diff --git a/package.json b/package.json index af61f95..ed39613 100644 --- a/package.json +++ b/package.json @@ -32,17 +32,25 @@ "David Clark ", "Tucker Whitehouse ", "kthjm ", - "Artem Sapegin " + "Artem Sapegin ", + "Christian Murphy " ], "files": [ - "index.js" + "index.js", + "types/index.d.ts" ], + "types": "types/index.d.ts", "dependencies": { "@mapbox/hast-util-table-cell-style": "^0.1.3", - "hast-to-hyperscript": "^8.0.0" + "hast-to-hyperscript": "^9.0.0" }, "devDependencies": { + "@types/hyperscript": "0.0.4", + "@types/react": "^16.9.35", + "@types/virtual-dom": "^2.1.0", + "dtslint": "^3.6.3", "hastscript": "^5.0.0", + "hyperscript": "^2.0.2", "nyc": "^15.0.0", "prettier": "^2.0.0", "react": "^16.0.0", @@ -53,13 +61,15 @@ "tape": "^4.0.0", "unified": "^9.0.0", "unist-builder": "^2.0.0", + "vue": "^2.6.11", "xo": "^0.28.0" }, "scripts": { "format": "remark . -qfo && prettier --write \"**/*.js\" && xo --fix", "test-api": "node test", "test-coverage": "nyc --reporter lcov tape test.js", - "test": "npm run format && npm run test-coverage" + "test-types": "dtslint types", + "test": "npm run format && npm run test-coverage && npm run test-types" }, "nyc": { "check-coverage": true, diff --git a/types/index.d.ts b/types/index.d.ts new file mode 100644 index 0000000..aaf5bb3 --- /dev/null +++ b/types/index.d.ts @@ -0,0 +1,47 @@ +// Minimum TypeScript Version: 3.4 + +import {Transformer} from 'unified' +import {Prefix, CreateElementLike} from 'hast-to-hyperscript' + +declare namespace rehypeReact { + type FragmentLike = (props: any) => T | null + + type ComponentLike = (props: {[prop: string]: unknown}) => T | null + + interface Options { + /** + * How to create elements or components. + * You should typically pass `React.createElement` + */ + createElement: H + + /** + * Create fragments instead of an outer `
` if available + * You should typically pass `React.Fragment` + */ + Fragment?: FragmentLike> + + /** + * Override default elements (such as ``, `

`, etcetera) by passing an object mapping tag names to components + */ + components?: { + [element: string]: ComponentLike> + } + + /** + * React key prefix + * + * @defaultValue 'h-' + */ + prefix?: Prefix + } +} + +/** + * Rehype plugin to transform to React + */ +declare function rehypeReact( + options: rehypeReact.Options +): Transformer + +export = rehypeReact diff --git a/types/rehype-react-test.tsx b/types/rehype-react-test.tsx new file mode 100644 index 0000000..7e6fcd8 --- /dev/null +++ b/types/rehype-react-test.tsx @@ -0,0 +1,55 @@ +import * as unified from 'unified' +import * as rehypeToReact from 'rehype-react' +import * as React from 'react' +import {h as virtualDomCreateElement} from 'virtual-dom' +import * as hyperscriptCreateElement from 'hyperscript' +import Vue from 'vue' + +// Create element must be provided +unified().use(rehypeToReact) // $ExpectError +unified().use(rehypeToReact, {}) // $ExpectError + +// multiple frameworks providing createElement can be used +unified().use(rehypeToReact, {createElement: React.createElement}) +unified().use(rehypeToReact, {createElement: virtualDomCreateElement}) +unified().use(rehypeToReact, {createElement: hyperscriptCreateElement}) +unified().use(rehypeToReact, {createElement: new Vue().$createElement}) +unified().use(rehypeToReact, { + createElement: (name: number) => name // $ExpectError +}) + +// Prefix, fragment, and components are optional +unified().use(rehypeToReact, { + createElement: React.createElement, + prefix: 'h' +}) + +unified().use(rehypeToReact, { + createElement: React.createElement, + Fragment: React.Fragment +}) + +unified().use(rehypeToReact, { + createElement: React.createElement, + components: { + a: () => example + } +}) + +unified().use(rehypeToReact, { + createElement: React.createElement, + components: { + div: () => <>example + } +}) + +// Mismatch between framework of createElement and components or Fragment should fail +unified().use(rehypeToReact, { + createElement: virtualDomCreateElement, + // prettier-ignore typescript versions can disagree where error happens, squish statement so they agree + components: {a: () => example} // $ExpectError +}) +unified().use(rehypeToReact, { + createElement: virtualDomCreateElement, + Fragment: () => example // $ExpectError +}) diff --git a/types/tsconfig.json b/types/tsconfig.json new file mode 100644 index 0000000..0dba0d6 --- /dev/null +++ b/types/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "lib": ["es2015", "DOM"], + "strict": true, + "baseUrl": ".", + "paths": { + "rehype-react": ["index.d.ts"] + }, + "jsx": "react" + } +} diff --git a/types/tslint.json b/types/tslint.json new file mode 100644 index 0000000..e339e79 --- /dev/null +++ b/types/tslint.json @@ -0,0 +1,8 @@ +{ + "extends": "dtslint/dtslint.json", + "rules": { + "semicolon": false, + "whitespace": false, + "no-unnecessary-generics": false + } +}