diff --git a/package.json b/package.json index f7c962925..c66c9af5f 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "bundle-collapser": "^1.3.0", "camelcase": "^5.0.0", "clone": "^2.0.0", + "dtslint": "^0.4.2", "lerna": "^3.0.0", "mdast-util-assert": "^2.0.0", "mdast-util-compact": "^1.0.0", @@ -20,20 +21,22 @@ "remark-preset-wooorm": "^5.0.0", "tape": "^4.5.1", "tinyify": "^2.4.3", + "typescript": "^3.2.4", "unist-builder": "^1.0.2", "unist-util-remove-position": "^1.1.0", "xo": "^0.24.0" }, "scripts": { "postinstall": "lerna bootstrap --no-ci", - "format": "packages/remark-cli/cli.js . -qfo && prettier --write \"**/*.js\" && xo --fix", + "format": "packages/remark-cli/cli.js . -qfo && prettier --write \"**/*.{js,ts}\" && xo --fix", "build-bundle": "browserify packages/remark -s remark > remark.js", "build-mangle": "browserify packages/remark -s remark -p tinyify > remark.min.js", "build": "npm run build-bundle && npm run build-mangle", "test-api": "tape packages/*/test.js test/index.js", "test-api-extensive": "TEST_EXTENDED=true npm run test-api", "test-coverage": "nyc --reporter lcov tape \"test/index.js\" \"packages/*/test.js\"", - "test": "npm run format && npm run build && npm run test-coverage" + "test-types": "dtslint packages/remark-parse/types && dtslint packages/remark-stringify/types && dtslint packages/remark/types", + "test": "npm run format && npm run build && npm run test-coverage && npm run test-types" }, "nyc": { "check-coverage": true, diff --git a/packages/remark-parse/package.json b/packages/remark-parse/package.json index 631128d99..6d4553ff3 100644 --- a/packages/remark-parse/package.json +++ b/packages/remark-parse/package.json @@ -15,6 +15,7 @@ "ast", "parse" ], + "types": "types/index.d.ts", "homepage": "https://remark.js.org", "repository": "https://github.com/remarkjs/remark/tree/master/packages/remark-parse", "bugs": "https://github.com/remarkjs/remark/issues", @@ -28,7 +29,8 @@ ], "files": [ "index.js", - "lib" + "lib", + "types/index.d.ts" ], "dependencies": { "collapse-white-space": "^1.0.2", @@ -49,7 +51,7 @@ }, "devDependencies": { "tape": "^4.9.1", - "unified": "^8.0.0", + "unified": "^8.2.0", "vfile": "^4.0.0" }, "scripts": { diff --git a/packages/remark-parse/types/index.d.ts b/packages/remark-parse/types/index.d.ts new file mode 100644 index 000000000..c8eff9ff0 --- /dev/null +++ b/packages/remark-parse/types/index.d.ts @@ -0,0 +1,53 @@ +// TypeScript Version: 3.0 + +import {Node, Parent, Position} from 'unist' +import {Parser, Attacher} from 'unified' + +declare class RemarkParser implements Parser { + parse(): Node + blockMethods: string[] + inlineTokenizers: { + [key: string]: remarkParse.Tokenizer + } + inlineMethods: string[] +} + +declare namespace remarkParse { + interface Parse extends Attacher<[Partial]> { + (options: Partial): void + Parser: typeof RemarkParser + } + + type Parser = RemarkParser + + interface RemarkParseOptions { + gfm: boolean + commonmark: boolean + footnotes: boolean + blocks: string[] + pedantic: boolean + } + + interface Add { + (node: Node, parent?: Parent): Node + test(): Position + reset(node: Node, parent?: Node): Node + } + + type Eat = (value: string) => Add + + type Locator = (value: string, fromIndex: number) => number + + interface Tokenizer { + (eat: Eat, value: string, silent: true): boolean | void + (eat: Eat, value: string): Node | void + locator?: Locator + onlyAtStart?: boolean + notInBlock?: boolean + notInList?: boolean + notInLink?: boolean + } +} +declare const remarkParse: remarkParse.Parse + +export = remarkParse diff --git a/packages/remark-parse/types/test.ts b/packages/remark-parse/types/test.ts new file mode 100644 index 000000000..99a6a8315 --- /dev/null +++ b/packages/remark-parse/types/test.ts @@ -0,0 +1,17 @@ +import unified = require('unified') +import * as Unist from 'unist' +import remarkParse = require('remark-parse') + +const parseOptions = { + gfm: true, + pedantic: true +} + +unified().use(remarkParse, parseOptions) + +const badParseOptions = { + gfm: 'true' +} + +// $ExpectError +unified().use(remarkParse, badParseOptions) diff --git a/packages/remark-parse/types/tsconfig.json b/packages/remark-parse/types/tsconfig.json new file mode 100644 index 000000000..9680afacc --- /dev/null +++ b/packages/remark-parse/types/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "lib": ["es2015"], + "strict": true, + "noImplicitAny": true, + "noImplicitThis": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "baseUrl": ".", + "paths": { + "remark-parse": ["index.d.ts"] + } + } +} diff --git a/packages/remark-parse/types/tslint.json b/packages/remark-parse/types/tslint.json new file mode 100644 index 000000000..22174ee66 --- /dev/null +++ b/packages/remark-parse/types/tslint.json @@ -0,0 +1,14 @@ +{ + "extends": "dtslint/dtslint.json", + "rules": { + "callable-types": false, + "max-line-length": false, + "no-redundant-jsdoc": false, + "no-void-expression": false, + "only-arrow-functions": false, + "semicolon": false, + "unified-signatures": false, + "whitespace": false, + "interface-over-type-literal": false + } +} diff --git a/packages/remark-stringify/package.json b/packages/remark-stringify/package.json index b31af4e40..410053a8d 100644 --- a/packages/remark-stringify/package.json +++ b/packages/remark-stringify/package.json @@ -26,8 +26,10 @@ ], "files": [ "index.js", - "lib" + "lib", + "types/index.d.ts" ], + "types": "types/index.d.ts", "dependencies": { "ccount": "^1.0.0", "is-alphanumeric": "^1.0.0", @@ -46,7 +48,7 @@ }, "devDependencies": { "tape": "^4.9.1", - "unified": "^8.0.0", + "unified": "^8.2.0", "unist-builder": "^1.0.3", "unist-util-visit": "^1.4.0", "wcwidth": "^1.0.1" diff --git a/packages/remark-stringify/types/index.d.ts b/packages/remark-stringify/types/index.d.ts new file mode 100644 index 000000000..1f1fa6891 --- /dev/null +++ b/packages/remark-stringify/types/index.d.ts @@ -0,0 +1,48 @@ +// TypeScript Version: 3.0 + +import {Attacher, Compiler, Processor} from 'unified' +import {Node, Parent} from 'unist' + +declare class RemarkCompiler implements Compiler { + compile(): string + visitors: { + [key: string]: remarkStringify.Visitor + } +} + +declare namespace remarkStringify { + interface Stringify extends Attacher<[Partial]> { + Compiler: typeof RemarkCompiler + (this: Processor, options?: Partial): void + } + + type Compiler = RemarkCompiler + + interface RemarkStringifyOptions { + gfm: boolean + commonmark: boolean + entities: boolean | 'numbers' | 'escape' + setext: boolean + closeAtx: boolean + looseTable: boolean + spacedTable: boolean + paddedTable: boolean + stringLength: (s: string) => number + fence: '~' | '`' + fences: boolean + bullet: '-' | '*' | '+' + listItemIndent: 'tab' | '1' | 'mixed' + incrementListMarker: boolean + rule: '-' | '_' | '*' + ruleRepetition: number + ruleSpaces: boolean + strong: '_' | '*' + emphasis: '_' | '*' + } + + type Visitor = (node: Node, parent?: Parent) => string +} + +declare const remarkStringify: remarkStringify.Stringify + +export = remarkStringify diff --git a/packages/remark-stringify/types/test.ts b/packages/remark-stringify/types/test.ts new file mode 100644 index 000000000..4e9befbae --- /dev/null +++ b/packages/remark-stringify/types/test.ts @@ -0,0 +1,51 @@ +import remarkStringify = require('remark-stringify') +import unified = require('unified') +import {Node, Parent} from 'unist' + +const inferredStringifyOptions = { + gfm: true, + fences: true, + incrementListMarker: false +} + +unified().use(remarkStringify, inferredStringifyOptions) + +// These cannot be automatically inferred by TypeScript +const nonInferredStringifyOptions: Partial< + remarkStringify.RemarkStringifyOptions +> = { + fence: '~', + bullet: '+', + listItemIndent: 'tab', + rule: '-', + strong: '_', + emphasis: '*' +} + +unified().use(remarkStringify, nonInferredStringifyOptions) + +const badStringifyOptions = { + gfm: 'true' +} + +// $ExpectError +unified().use(remarkStringify, badStringifyOptions) + +function gap(this: unified.Processor) { + const Compiler = this.Compiler as typeof remarkStringify.Compiler + const visitors = Compiler.prototype.visitors + const original = visitors.heading + + visitors.heading = heading + + function heading(this: unified.Processor, node: Node, parent?: Parent) { + // FIXME: remove need for explicit 'as' casting + const headingNode = node as (Node & {depth: number}) + return ( + (headingNode.depth === 2 ? '\n' : '') + + original.apply(this, [node, parent]) + ) + } +} + +const plugin: unified.Attacher = gap diff --git a/packages/remark-stringify/types/tsconfig.json b/packages/remark-stringify/types/tsconfig.json new file mode 100644 index 000000000..91a76bf11 --- /dev/null +++ b/packages/remark-stringify/types/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "lib": ["es2015"], + "strict": true, + "noImplicitAny": true, + "noImplicitThis": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "baseUrl": ".", + "paths": { + "remark-stringify": ["index.d.ts"] + } + } +} diff --git a/packages/remark-stringify/types/tslint.json b/packages/remark-stringify/types/tslint.json new file mode 100644 index 000000000..22174ee66 --- /dev/null +++ b/packages/remark-stringify/types/tslint.json @@ -0,0 +1,14 @@ +{ + "extends": "dtslint/dtslint.json", + "rules": { + "callable-types": false, + "max-line-length": false, + "no-redundant-jsdoc": false, + "no-void-expression": false, + "only-arrow-functions": false, + "semicolon": false, + "unified-signatures": false, + "whitespace": false, + "interface-over-type-literal": false + } +} diff --git a/packages/remark/package.json b/packages/remark/package.json index cd3b60280..522a6423b 100644 --- a/packages/remark/package.json +++ b/packages/remark/package.json @@ -24,12 +24,14 @@ "Titus Wormer (https://wooorm.com)" ], "files": [ - "index.js" + "index.js", + "types/index.d.ts" ], + "types": "types/index.d.ts", "dependencies": { "remark-parse": "^6.0.0", "remark-stringify": "^6.0.0", - "unified": "^8.0.0" + "unified": "^8.2.0" }, "devDependencies": { "tape": "^4.9.1" diff --git a/packages/remark/types/index.d.ts b/packages/remark/types/index.d.ts new file mode 100644 index 000000000..10f33a901 --- /dev/null +++ b/packages/remark/types/index.d.ts @@ -0,0 +1,14 @@ +// TypeScript Version: 3.0 + +import unified = require('unified') +import remarkParse = require('remark-parse') +import remarkStringify = require('remark-stringify') + +type RemarkOptions = remarkParse.RemarkParseOptions & + remarkStringify.RemarkStringifyOptions + +declare function remark< + P extends Partial = Partial +>(): unified.Processor

+ +export = remark diff --git a/packages/remark/types/test.ts b/packages/remark/types/test.ts new file mode 100644 index 000000000..e4ef0e845 --- /dev/null +++ b/packages/remark/types/test.ts @@ -0,0 +1,15 @@ +import remark = require('remark') + +interface PluginOptions { + example: boolean +} + +const plugin = (options?: PluginOptions) => {} + +remark().use(plugin) +remark().use(plugin, {example: true}) +remark().use({settings: {commonmark: true}}) +// $ExpectError +remark().use({settings: {doesNotExist: true}}) +// $ExpectError +remark().use(plugin, {doesNotExist: 'true'}) diff --git a/packages/remark/types/tsconfig.json b/packages/remark/types/tsconfig.json new file mode 100644 index 000000000..c688cea16 --- /dev/null +++ b/packages/remark/types/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "lib": ["es2015"], + "strict": true, + "noImplicitAny": true, + "noImplicitThis": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "baseUrl": ".", + "paths": { + "remark": ["index.d.ts"] + } + } +} diff --git a/packages/remark/types/tslint.json b/packages/remark/types/tslint.json new file mode 100644 index 000000000..aa595811d --- /dev/null +++ b/packages/remark/types/tslint.json @@ -0,0 +1,15 @@ +{ + "extends": "dtslint/dtslint.json", + "rules": { + "callable-types": false, + "max-line-length": false, + "no-redundant-jsdoc": false, + "no-void-expression": false, + "only-arrow-functions": false, + "semicolon": false, + "unified-signatures": false, + "whitespace": false, + "interface-over-type-literal": false, + "no-unnecessary-generics": false + } +}