diff --git a/package.json b/package.json index c6adf6b..c78a6d5 100644 --- a/package.json +++ b/package.json @@ -136,6 +136,7 @@ "remark-comment-config": "^8.0.0", "remark-gfm": "^4.0.0", "remark-github": "^12.0.0", + "remark-mdx": "^3.0.0", "remark-toc": "^9.0.0", "remark-validate-links": "^13.0.0", "strip-indent": "^4.0.0", diff --git a/packages/remark-lint-checkbox-character-style/index.js b/packages/remark-lint-checkbox-character-style/index.js index 62bfa98..7cc101a 100644 --- a/packages/remark-lint-checkbox-character-style/index.js +++ b/packages/remark-lint-checkbox-character-style/index.js @@ -206,8 +206,8 @@ const remarkLintCheckboxCharacterStyle = lintRule( value.slice(point.offset - 2, point.offset + 1) ) - // Failsafe to make sure we donβ€˜t crash if there actually isn’t a checkbox. - /* c8 ignore next */ + /* c8 ignore next 2 -- failsafe so we don’t crash if there actually isn’t + * a checkbox. */ if (!match) return const style = node.checked ? checked : unchecked diff --git a/packages/remark-lint-checkbox-character-style/readme.md b/packages/remark-lint-checkbox-character-style/readme.md index 5be4c79..35b519c 100644 --- a/packages/remark-lint-checkbox-character-style/readme.md +++ b/packages/remark-lint-checkbox-character-style/readme.md @@ -182,7 +182,8 @@ When configured with `{ checked: 'x' }`. ###### In -> πŸ‘‰ **Note**: this example uses GFM ([`remark-gfm`][github-remark-gfm]). +> πŸ‘‰ **Note**: this example uses +> GFM ([`remark-gfm`][github-remark-gfm]). ```markdown - [x] List item @@ -199,7 +200,8 @@ When configured with `{ checked: 'X' }`. ###### In -> πŸ‘‰ **Note**: this example uses GFM ([`remark-gfm`][github-remark-gfm]). +> πŸ‘‰ **Note**: this example uses +> GFM ([`remark-gfm`][github-remark-gfm]). ```markdown - [X] List item @@ -216,7 +218,8 @@ When configured with `{ unchecked: ' ' }`. ###### In -> πŸ‘‰ **Note**: this example uses GFM ([`remark-gfm`][github-remark-gfm]). +> πŸ‘‰ **Note**: this example uses +> GFM ([`remark-gfm`][github-remark-gfm]). ```markdown - [ ] List item @@ -235,7 +238,8 @@ When configured with `{ unchecked: '\t' }`. ###### In -> πŸ‘‰ **Note**: this example uses GFM ([`remark-gfm`][github-remark-gfm]). +> πŸ‘‰ **Note**: this example uses +> GFM ([`remark-gfm`][github-remark-gfm]). ```markdown - [␉] List item @@ -250,7 +254,8 @@ No messages. ###### In -> πŸ‘‰ **Note**: this example uses GFM ([`remark-gfm`][github-remark-gfm]). +> πŸ‘‰ **Note**: this example uses +> GFM ([`remark-gfm`][github-remark-gfm]). ```markdown - [x] List item diff --git a/packages/remark-lint-checkbox-content-indent/readme.md b/packages/remark-lint-checkbox-content-indent/readme.md index a597fd2..b21309e 100644 --- a/packages/remark-lint-checkbox-content-indent/readme.md +++ b/packages/remark-lint-checkbox-content-indent/readme.md @@ -159,7 +159,8 @@ content after them with a single space between. ###### In -> πŸ‘‰ **Note**: this example uses GFM ([`remark-gfm`][github-remark-gfm]). +> πŸ‘‰ **Note**: this example uses +> GFM ([`remark-gfm`][github-remark-gfm]). ```markdown - [ ] List item @@ -176,7 +177,8 @@ No messages. ###### In -> πŸ‘‰ **Note**: this example uses GFM ([`remark-gfm`][github-remark-gfm]). +> πŸ‘‰ **Note**: this example uses +> GFM ([`remark-gfm`][github-remark-gfm]). ```markdown - [ ] List item diff --git a/packages/remark-lint-final-definition/index.js b/packages/remark-lint-final-definition/index.js index bbefd95..c4812b2 100644 --- a/packages/remark-lint-final-definition/index.js +++ b/packages/remark-lint-final-definition/index.js @@ -57,26 +57,44 @@ * @example * {"name": "not-ok.md", "label": "output"} * - * 3:1-3:47: Move definitions to the end of the file (after the node at line `5`) + * 3:1-3:47: Move definitions to the end of the file (after `5:19`) * * @example - * {"name": "ok-comments.md"} + * {"name": "ok-html-comments.md"} * * Paragraph. * * [example-1]: http://example.com/one/ * - * + * + * + * [example-2]: http://example.com/two/ + * + * @example + * {"name": "ok-mdx-comments.mdx", "mdx": true} + * + * Paragraph. + * + * [example-1]: http://example.com/one/ + * + * {/* Comments are fine in MDX. *␀/} * * [example-2]: http://example.com/two/ */ /** + * @typedef {import('mdast').Definition} Definition + * @typedef {import('mdast').FootnoteDefinition} FootnoteDefinition * @typedef {import('mdast').Root} Root + * + * @typedef {import('unist').Point} Point */ +/// + import {lintRule} from 'unified-lint-rule' -import {pointStart} from 'unist-util-position' +import {pointEnd, pointStart} from 'unist-util-position' +import {stringifyPosition} from 'unist-util-stringify-position' import {visit} from 'unist-util-visit' const remarkLintFinalDefinition = lintRule( @@ -91,40 +109,47 @@ const remarkLintFinalDefinition = lintRule( * Nothing. */ function (tree, file) { - let last = 0 + /** @type {Array} */ + const definitions = [] + /** @type {Point | undefined} */ + let last - visit( - tree, - function (node) { - const start = pointStart(node) + visit(tree, function (node) { + if (node.type === 'definition' || node.type === 'footnoteDefinition') { + definitions.push(node) + } else if ( + node.type === 'root' || + node.type === 'blockquote' || + node.type === 'listItem' || + // Ignore HTML comments. + (node.type === 'html' && /^[\t ]* + + +[example-2]: http://example.com/two/ +``` + +###### Out + +No messages. + +##### `ok-mdx-comments.mdx` + +###### In + +> πŸ‘‰ **Note**: this example uses +> MDX ([`remark-mdx`][github-remark-mdx]). + +```mdx +Paragraph. + +[example-1]: http://example.com/one/ + +{/* Comments are fine in MDX. */} [example-2]: http://example.com/two/ ``` @@ -263,6 +284,8 @@ abide by its terms. [github-remark-lint]: https://github.com/remarkjs/remark-lint +[github-remark-mdx]: https://mdxjs.com/packages/remark-mdx/ + [github-unified-transformer]: https://github.com/unifiedjs/unified#transformer [npm-install]: https://docs.npmjs.com/cli/install diff --git a/packages/remark-lint-final-newline/index.js b/packages/remark-lint-final-newline/index.js index 60343ce..bad9635 100644 --- a/packages/remark-lint-final-newline/index.js +++ b/packages/remark-lint-final-newline/index.js @@ -81,6 +81,7 @@ */ import {lintRule} from 'unified-lint-rule' +import {location} from 'vfile-location' const remarkLintFinalNewline = lintRule( { @@ -95,11 +96,11 @@ const remarkLintFinalNewline = lintRule( */ function (_, file) { const value = String(file) + const end = location(file).toPoint(value.length) const last = value.length - 1 - if (last > -1 && value.charAt(last) !== '\n') { - // To do: warn at last character. - file.message('Missing newline character at end of file') + if (end && last > -1 && value.charAt(last) !== '\n') { + file.message('Missing newline character at end of file', end) } } ) diff --git a/packages/remark-lint-final-newline/package.json b/packages/remark-lint-final-newline/package.json index dd316fc..52f26dc 100644 --- a/packages/remark-lint-final-newline/package.json +++ b/packages/remark-lint-final-newline/package.json @@ -33,7 +33,8 @@ ], "dependencies": { "@types/mdast": "^4.0.0", - "unified-lint-rule": "^2.0.0" + "unified-lint-rule": "^2.0.0", + "vfile-location": "^5.0.0" }, "scripts": {}, "typeCoverage": { diff --git a/packages/remark-lint-first-heading-level/index.js b/packages/remark-lint-first-heading-level/index.js index f37338b..86835d3 100644 --- a/packages/remark-lint-first-heading-level/index.js +++ b/packages/remark-lint-first-heading-level/index.js @@ -143,6 +143,13 @@ * {"name": "not-ok-html.md", "config": 2, "label": "output"} * * 1:1-1:14: First heading level should be `2` + * + * @example + * {"name": "ok.mdx", "mdx": true} + * + * In MDX, JSX is supported. + * + *

First heading

*/ /** @@ -158,11 +165,14 @@ * Configuration. */ +/// + import {lintRule} from 'unified-lint-rule' import {position} from 'unist-util-position' import {EXIT, visit} from 'unist-util-visit' -const re = / πŸ‘‰ **Note**: this example uses +> MDX ([`remark-mdx`][github-remark-mdx]). + +```mdx +In MDX, JSX is supported. + +

First heading

+``` + +###### Out + +No messages. + ## Compatibility Projects maintained by the unified collective are compatible with maintained @@ -380,6 +397,8 @@ abide by its terms. [github-remark-lint]: https://github.com/remarkjs/remark-lint +[github-remark-mdx]: https://mdxjs.com/packages/remark-mdx/ + [github-unified-transformer]: https://github.com/unifiedjs/unified#transformer [npm-install]: https://docs.npmjs.com/cli/install diff --git a/packages/remark-lint-list-item-content-indent/index.js b/packages/remark-lint-list-item-content-indent/index.js index 4d7c2b2..2eacaa0 100644 --- a/packages/remark-lint-list-item-content-indent/index.js +++ b/packages/remark-lint-list-item-content-indent/index.js @@ -126,8 +126,7 @@ const remarkLintListItemContentIndent = lintRule( file.message( 'Don’t use mixed indentation for children, ' + - // Hard to test, I couldn’t find it at least. - /* c8 ignore next */ + /* c8 ignore next -- hard to test, I couldn’t find it at least. */ (diff > 0 ? 'add' : 'remove') + ' ' + abs + diff --git a/packages/remark-lint-list-item-content-indent/readme.md b/packages/remark-lint-list-item-content-indent/readme.md index cbc9a48..7df9258 100644 --- a/packages/remark-lint-list-item-content-indent/readme.md +++ b/packages/remark-lint-list-item-content-indent/readme.md @@ -151,7 +151,8 @@ Further children should align with it. ###### In -> πŸ‘‰ **Note**: this example uses GFM ([`remark-gfm`][github-remark-gfm]). +> πŸ‘‰ **Note**: this example uses +> GFM ([`remark-gfm`][github-remark-gfm]). ```markdown 1.␠[x] Alpha @@ -166,7 +167,8 @@ No messages. ###### In -> πŸ‘‰ **Note**: this example uses GFM ([`remark-gfm`][github-remark-gfm]). +> πŸ‘‰ **Note**: this example uses +> GFM ([`remark-gfm`][github-remark-gfm]). ```markdown 1.␠[x] Charlie diff --git a/packages/remark-lint-maximum-line-length/index.js b/packages/remark-lint-maximum-line-length/index.js index 9432d6f..18e14fb 100644 --- a/packages/remark-lint-maximum-line-length/index.js +++ b/packages/remark-lint-maximum-line-length/index.js @@ -119,6 +119,8 @@ * 4:12: Line must be at most 10 characters */ +/// + /** * @typedef {import('mdast').Root} Root */ @@ -146,26 +148,14 @@ const remarkLintMaximumLineLength = lintRule( const option = options || 80 visit(tree, function (node) { - // To do: add MDX types, etc. - // To do: remove MDX 1? if ( node.type === 'code' || node.type === 'definition' || node.type === 'heading' || node.type === 'html' || - node.type === 'table' || - // @ts-expect-error: These are from MDX@1 and MDX@2: . - node.type === 'jsx' || - // @ts-expect-error: MDX - node.type === 'mdxFlowExpression' || - // @ts-expect-error: MDX - node.type === 'mdxJsxFlowElement' || - // @ts-expect-error: MDX node.type === 'mdxJsxTextElement' || - // @ts-expect-error: MDX node.type === 'mdxTextExpression' || - // @ts-expect-error: MDX - node.type === 'mdxjsEsm' || + node.type === 'table' || // @ts-expect-error: TOML from frontmatter. node.type === 'toml' || node.type === 'yaml' diff --git a/packages/remark-lint-maximum-line-length/package.json b/packages/remark-lint-maximum-line-length/package.json index 9fa6008..cf95306 100644 --- a/packages/remark-lint-maximum-line-length/package.json +++ b/packages/remark-lint-maximum-line-length/package.json @@ -32,6 +32,7 @@ ], "dependencies": { "@types/mdast": "^4.0.0", + "mdast-util-mdx": "^3.0.0", "unified-lint-rule": "^2.0.0", "unist-util-position": "^5.0.0", "unist-util-visit": "^5.0.0" diff --git a/packages/remark-lint-maximum-line-length/readme.md b/packages/remark-lint-maximum-line-length/readme.md index a6b2907..f04ec3b 100644 --- a/packages/remark-lint-maximum-line-length/readme.md +++ b/packages/remark-lint-maximum-line-length/readme.md @@ -151,7 +151,8 @@ Whether to wrap prose or not is a stylistic choice. ###### In -> πŸ‘‰ **Note**: this example uses GFM ([`remark-gfm`][github-remark-gfm]). +> πŸ‘‰ **Note**: this example uses +> GFM ([`remark-gfm`][github-remark-gfm]). ```markdown This line is simply not toooooooooooooooooooooooooooooooooooooooooooo diff --git a/packages/remark-lint-no-literal-urls/readme.md b/packages/remark-lint-no-literal-urls/readme.md index fa06a25..c42aaa9 100644 --- a/packages/remark-lint-no-literal-urls/readme.md +++ b/packages/remark-lint-no-literal-urls/readme.md @@ -166,7 +166,8 @@ No messages. ###### In -> πŸ‘‰ **Note**: this example uses GFM ([`remark-gfm`][github-remark-gfm]). +> πŸ‘‰ **Note**: this example uses +> GFM ([`remark-gfm`][github-remark-gfm]). ```markdown http://foo.bar/baz diff --git a/packages/remark-lint-no-shell-dollars/index.js b/packages/remark-lint-no-shell-dollars/index.js index 50a7a12..4dcc3ab 100644 --- a/packages/remark-lint-no-shell-dollars/index.js +++ b/packages/remark-lint-no-shell-dollars/index.js @@ -90,6 +90,7 @@ * @typedef {import('mdast').Root} Root */ +import {collapseWhiteSpace} from 'collapse-white-space' import {lintRule} from 'unified-lint-rule' import {position} from 'unist-util-position' import {visit} from 'unist-util-visit' @@ -140,23 +141,27 @@ const remarkLintNoShellDollars = lintRule( // Check known shell code. if (place && node.lang && flags.has(node.lang)) { - const lines = node.value.split('\n').filter(function (line) { - return line.trim().length > 0 - }) + const lines = node.value.split('\n') let index = -1 - if (lines.length === 0) { - return - } + let hasLines = false while (++index < lines.length) { - const line = lines[index].trim() + const line = collapseWhiteSpace(lines[index], {style: 'html'}) + + if (!line) continue + + hasLines = true if (!/^\$/.test(line)) { return } } + if (!hasLines) { + return + } + file.message('Do not use dollar signs before shell commands', place) } }) diff --git a/packages/remark-lint-no-shell-dollars/package.json b/packages/remark-lint-no-shell-dollars/package.json index cc3557f..616b17b 100644 --- a/packages/remark-lint-no-shell-dollars/package.json +++ b/packages/remark-lint-no-shell-dollars/package.json @@ -32,6 +32,7 @@ ], "dependencies": { "@types/mdast": "^4.0.0", + "collapse-white-space": "^2.0.0", "unified-lint-rule": "^2.0.0", "unist-util-position": "^5.0.0", "unist-util-visit": "^5.0.0" diff --git a/packages/remark-lint-no-table-indentation/index.js b/packages/remark-lint-no-table-indentation/index.js index 24e0fd5..603cab0 100644 --- a/packages/remark-lint-no-table-indentation/index.js +++ b/packages/remark-lint-no-table-indentation/index.js @@ -138,8 +138,8 @@ const remarkLintNoTableIndentation = lintRule( const head = parent.children[0] column = pointStart(head)?.column - // Skip past the first line if we’re the first child of a list item. - /* c8 ignore next 3 */ + /* c8 ignore next 4 -- skip past the first line if we’re the first + * child of a list item. */ if (typeof line === 'number' && head === node) { line++ } diff --git a/packages/remark-lint-no-table-indentation/readme.md b/packages/remark-lint-no-table-indentation/readme.md index f4fe7fe..4d38992 100644 --- a/packages/remark-lint-no-table-indentation/readme.md +++ b/packages/remark-lint-no-table-indentation/readme.md @@ -152,7 +152,8 @@ So it’s recommended to not indent tables and to turn this rule on. ###### In -> πŸ‘‰ **Note**: this example uses GFM ([`remark-gfm`][github-remark-gfm]). +> πŸ‘‰ **Note**: this example uses +> GFM ([`remark-gfm`][github-remark-gfm]). ```markdown Paragraph. @@ -170,7 +171,8 @@ No messages. ###### In -> πŸ‘‰ **Note**: this example uses GFM ([`remark-gfm`][github-remark-gfm]). +> πŸ‘‰ **Note**: this example uses +> GFM ([`remark-gfm`][github-remark-gfm]). ```markdown Paragraph. @@ -192,7 +194,8 @@ Paragraph. ###### In -> πŸ‘‰ **Note**: this example uses GFM ([`remark-gfm`][github-remark-gfm]). +> πŸ‘‰ **Note**: this example uses +> GFM ([`remark-gfm`][github-remark-gfm]). ```markdown >␠␠| A | @@ -209,7 +212,8 @@ Paragraph. ###### In -> πŸ‘‰ **Note**: this example uses GFM ([`remark-gfm`][github-remark-gfm]). +> πŸ‘‰ **Note**: this example uses +> GFM ([`remark-gfm`][github-remark-gfm]). ```markdown -␠␠␠paragraph diff --git a/packages/remark-lint-no-undefined-references/index.js b/packages/remark-lint-no-undefined-references/index.js index d49ab6d..2c8e54d 100644 --- a/packages/remark-lint-no-undefined-references/index.js +++ b/packages/remark-lint-no-undefined-references/index.js @@ -213,9 +213,9 @@ const remarkLintNoUndefinedReferences = lintRule( visit(tree, function (node) { const place = position(node) - // CM specifiers that references only form when defined. - // Still, they could be added by plugins, so let’s keep it. - /* c8 ignore next 10 */ + /* c8 ignore next 12 -- CM specifies that references only form when + * defined. + * Still, they could be added by plugins, so let’s keep it. */ if ( (node.type === 'imageReference' || node.type === 'linkReference' || diff --git a/packages/remark-lint-no-unneeded-full-reference-image/index.js b/packages/remark-lint-no-unneeded-full-reference-image/index.js index 2801ee4..a12815b 100644 --- a/packages/remark-lint-no-unneeded-full-reference-image/index.js +++ b/packages/remark-lint-no-unneeded-full-reference-image/index.js @@ -92,7 +92,7 @@ const remarkLintNoUnneededFullReferenceImage = lintRule( if ( !place || node.referenceType !== 'full' || - /* c8 ignore next */ + /* c8 ignore next -- generated AST can omit `alt`. */ normalizeIdentifier(node.alt || '') !== node.identifier.toUpperCase() ) { return diff --git a/packages/remark-lint-no-unused-definitions/index.js b/packages/remark-lint-no-unused-definitions/index.js index 83c13ef..3884e47 100644 --- a/packages/remark-lint-no-unused-definitions/index.js +++ b/packages/remark-lint-no-unused-definitions/index.js @@ -62,11 +62,12 @@ * @example * {"name": "footnote.md", "gfm": true, "label": "output"} * - * 4:1-4:13: Found unused definition + * 4:1-4:13: Found unused footnote definition */ /** - * @typedef {import('mdast').DefinitionContent} DefinitionContent + * @typedef {import('mdast').Definition} Definition + * @typedef {import('mdast').FootnoteDefinition} FootnoteDefinition * @typedef {import('mdast').Root} Root */ @@ -86,13 +87,19 @@ const remarkLintNoUnusedDefinitions = lintRule( * Nothing. */ function (tree, file) { - /** @type {Map} */ - const map = new Map() + /** @type {Map} */ + const footnoteDefinitions = new Map() + /** @type {Map} */ + const definitions = new Map() - // To do: separate maps for footnotes/definitions. visit(tree, function (node) { if ('identifier' in node) { const id = node.identifier.toLowerCase() + const map = + node.type === 'footnoteDefinition' || + node.type === 'footnoteReference' + ? footnoteDefinitions + : definitions let entry = map.get(id) if (!entry) { @@ -112,7 +119,15 @@ const remarkLintNoUnusedDefinitions = lintRule( } }) - for (const entry of map.values()) { + for (const entry of footnoteDefinitions.values()) { + const place = position(entry.node) + + if (place && !entry.used) { + file.message('Found unused footnote definition', place) + } + } + + for (const entry of definitions.values()) { const place = position(entry.node) if (place && !entry.used) { diff --git a/packages/remark-lint-no-unused-definitions/readme.md b/packages/remark-lint-no-unused-definitions/readme.md index fe3d88c..ba56b3a 100644 --- a/packages/remark-lint-no-unused-definitions/readme.md +++ b/packages/remark-lint-no-unused-definitions/readme.md @@ -170,7 +170,8 @@ No messages. ###### In -> πŸ‘‰ **Note**: this example uses GFM ([`remark-gfm`][github-remark-gfm]). +> πŸ‘‰ **Note**: this example uses +> GFM ([`remark-gfm`][github-remark-gfm]). ```markdown a[^x]. @@ -182,7 +183,7 @@ a[^x]. ###### Out ```text -4:1-4:13: Found unused definition +4:1-4:13: Found unused footnote definition ``` ## Compatibility diff --git a/packages/remark-lint-strikethrough-marker/readme.md b/packages/remark-lint-strikethrough-marker/readme.md index a0451bd..f07af21 100644 --- a/packages/remark-lint-strikethrough-marker/readme.md +++ b/packages/remark-lint-strikethrough-marker/readme.md @@ -177,7 +177,8 @@ When configured with `'~'`. ###### In -> πŸ‘‰ **Note**: this example uses GFM ([`remark-gfm`][github-remark-gfm]). +> πŸ‘‰ **Note**: this example uses +> GFM ([`remark-gfm`][github-remark-gfm]). ```markdown ~foo~ @@ -193,7 +194,8 @@ When configured with `'~'`. ###### In -> πŸ‘‰ **Note**: this example uses GFM ([`remark-gfm`][github-remark-gfm]). +> πŸ‘‰ **Note**: this example uses +> GFM ([`remark-gfm`][github-remark-gfm]). ```markdown ~~foo~~ @@ -211,7 +213,8 @@ When configured with `'~~'`. ###### In -> πŸ‘‰ **Note**: this example uses GFM ([`remark-gfm`][github-remark-gfm]). +> πŸ‘‰ **Note**: this example uses +> GFM ([`remark-gfm`][github-remark-gfm]). ```markdown ~~foo~~ @@ -227,7 +230,8 @@ When configured with `'~~'`. ###### In -> πŸ‘‰ **Note**: this example uses GFM ([`remark-gfm`][github-remark-gfm]). +> πŸ‘‰ **Note**: this example uses +> GFM ([`remark-gfm`][github-remark-gfm]). ```markdown ~foo~ @@ -243,7 +247,8 @@ When configured with `'~~'`. ###### In -> πŸ‘‰ **Note**: this example uses GFM ([`remark-gfm`][github-remark-gfm]). +> πŸ‘‰ **Note**: this example uses +> GFM ([`remark-gfm`][github-remark-gfm]). ```markdown ~~foo~~ diff --git a/packages/remark-lint-table-cell-padding/index.js b/packages/remark-lint-table-cell-padding/index.js index 4d3e74f..8afbeef 100644 --- a/packages/remark-lint-table-cell-padding/index.js +++ b/packages/remark-lint-table-cell-padding/index.js @@ -271,7 +271,7 @@ const remarkLintTableCellPadding = lintRule( visit(tree, 'table', function (node) { const rows = node.children - /* c8 ignore next -- to do: fix types to always have `align` defined. */ + /* c8 ignore next -- generated AST can omit `align`. */ const align = node.align || [] /** @type {Array} */ const sizes = [] @@ -414,7 +414,6 @@ export default remarkLintTableCellPadding function size(node) { const head = pointStart(node.children[0])?.offset const tail = pointEnd(node.children[node.children.length - 1])?.offset - // Only called when we’re sure offsets exist. - /* c8 ignore next */ + /* c8 ignore next -- Only called when we’re sure offsets exist. */ return typeof head === 'number' && typeof tail === 'number' ? tail - head : 0 } diff --git a/packages/remark-lint-table-cell-padding/readme.md b/packages/remark-lint-table-cell-padding/readme.md index ba4e21e..354d219 100644 --- a/packages/remark-lint-table-cell-padding/readme.md +++ b/packages/remark-lint-table-cell-padding/readme.md @@ -186,7 +186,8 @@ When configured with `'padded'`. ###### In -> πŸ‘‰ **Note**: this example uses GFM ([`remark-gfm`][github-remark-gfm]). +> πŸ‘‰ **Note**: this example uses +> GFM ([`remark-gfm`][github-remark-gfm]). ```markdown | A | B | @@ -204,7 +205,8 @@ When configured with `'padded'`. ###### In -> πŸ‘‰ **Note**: this example uses GFM ([`remark-gfm`][github-remark-gfm]). +> πŸ‘‰ **Note**: this example uses +> GFM ([`remark-gfm`][github-remark-gfm]). ```markdown | A | B | @@ -242,7 +244,8 @@ When configured with `'compact'`. ###### In -> πŸ‘‰ **Note**: this example uses GFM ([`remark-gfm`][github-remark-gfm]). +> πŸ‘‰ **Note**: this example uses +> GFM ([`remark-gfm`][github-remark-gfm]). ```markdown |A |B | @@ -260,7 +263,8 @@ When configured with `'compact'`. ###### In -> πŸ‘‰ **Note**: this example uses GFM ([`remark-gfm`][github-remark-gfm]). +> πŸ‘‰ **Note**: this example uses +> GFM ([`remark-gfm`][github-remark-gfm]). ```markdown | A | B | @@ -284,7 +288,8 @@ When configured with `'compact'`. ###### In -> πŸ‘‰ **Note**: this example uses GFM ([`remark-gfm`][github-remark-gfm]). +> πŸ‘‰ **Note**: this example uses +> GFM ([`remark-gfm`][github-remark-gfm]). ```markdown The default is `'consistent'`. @@ -308,7 +313,8 @@ When configured with `'consistent'`. ###### In -> πŸ‘‰ **Note**: this example uses GFM ([`remark-gfm`][github-remark-gfm]). +> πŸ‘‰ **Note**: this example uses +> GFM ([`remark-gfm`][github-remark-gfm]). ```markdown | A | B | @@ -332,7 +338,8 @@ When configured with `'consistent'`. ###### In -> πŸ‘‰ **Note**: this example uses GFM ([`remark-gfm`][github-remark-gfm]). +> πŸ‘‰ **Note**: this example uses +> GFM ([`remark-gfm`][github-remark-gfm]). ```markdown |A |B | @@ -354,7 +361,8 @@ When configured with `'consistent'`. ###### In -> πŸ‘‰ **Note**: this example uses GFM ([`remark-gfm`][github-remark-gfm]). +> πŸ‘‰ **Note**: this example uses +> GFM ([`remark-gfm`][github-remark-gfm]). ```markdown |A |B | @@ -388,7 +396,8 @@ When configured with `'padded'`. ###### In -> πŸ‘‰ **Note**: this example uses GFM ([`remark-gfm`][github-remark-gfm]). +> πŸ‘‰ **Note**: this example uses +> GFM ([`remark-gfm`][github-remark-gfm]). ```markdown @@ -412,7 +421,8 @@ When configured with `'padded'`. ###### In -> πŸ‘‰ **Note**: this example uses GFM ([`remark-gfm`][github-remark-gfm]). +> πŸ‘‰ **Note**: this example uses +> GFM ([`remark-gfm`][github-remark-gfm]). ```markdown diff --git a/packages/remark-lint-table-pipe-alignment/readme.md b/packages/remark-lint-table-pipe-alignment/readme.md index caf9e7e..31c8dc3 100644 --- a/packages/remark-lint-table-pipe-alignment/readme.md +++ b/packages/remark-lint-table-pipe-alignment/readme.md @@ -160,7 +160,8 @@ in which case this rule must be turned off. ###### In -> πŸ‘‰ **Note**: this example uses GFM ([`remark-gfm`][github-remark-gfm]). +> πŸ‘‰ **Note**: this example uses +> GFM ([`remark-gfm`][github-remark-gfm]). ```markdown | A | B | @@ -176,7 +177,8 @@ No messages. ###### In -> πŸ‘‰ **Note**: this example uses GFM ([`remark-gfm`][github-remark-gfm]). +> πŸ‘‰ **Note**: this example uses +> GFM ([`remark-gfm`][github-remark-gfm]). ```markdown | A | B | @@ -195,7 +197,8 @@ No messages. ###### In -> πŸ‘‰ **Note**: this example uses GFM ([`remark-gfm`][github-remark-gfm]). +> πŸ‘‰ **Note**: this example uses +> GFM ([`remark-gfm`][github-remark-gfm]). ```markdown | | B | | @@ -211,7 +214,8 @@ No messages. ###### In -> πŸ‘‰ **Note**: this example uses GFM ([`remark-gfm`][github-remark-gfm]). +> πŸ‘‰ **Note**: this example uses +> GFM ([`remark-gfm`][github-remark-gfm]). ```markdown | | | | diff --git a/packages/remark-lint-table-pipes/readme.md b/packages/remark-lint-table-pipes/readme.md index c45048f..2bf9e48 100644 --- a/packages/remark-lint-table-pipes/readme.md +++ b/packages/remark-lint-table-pipes/readme.md @@ -153,7 +153,8 @@ delimiters. ###### In -> πŸ‘‰ **Note**: this example uses GFM ([`remark-gfm`][github-remark-gfm]). +> πŸ‘‰ **Note**: this example uses +> GFM ([`remark-gfm`][github-remark-gfm]). ```markdown | A | B | @@ -169,7 +170,8 @@ No messages. ###### In -> πŸ‘‰ **Note**: this example uses GFM ([`remark-gfm`][github-remark-gfm]). +> πŸ‘‰ **Note**: this example uses +> GFM ([`remark-gfm`][github-remark-gfm]). ```markdown A | B diff --git a/packages/unified-lint-rule/lib/index.js b/packages/unified-lint-rule/lib/index.js index 5f3c6d3..3a74422 100644 --- a/packages/unified-lint-rule/lib/index.js +++ b/packages/unified-lint-rule/lib/index.js @@ -56,8 +56,7 @@ export function lintRule(meta, rule) { const id = typeof meta === 'string' ? meta : meta.origin const url = typeof meta === 'string' ? undefined : meta.url const parts = id.split(':') - // Possibly useful if externalised later. - /* c8 ignore next */ + /* c8 ignore next -- Possibly useful if externalised later. */ const source = parts[1] ? parts[0] : undefined const ruleId = parts[1] @@ -94,9 +93,9 @@ export function lintRule(meta, rule) { wrap(rule, function (error) { const messages = file.messages - // Add the error, if not already properly added. - // Only happens for incorrect plugins. - /* c8 ignore next 6 */ + /* c8 ignore next 8 -- add the error, + * if not already properly added. + * Only happens for incorrect plugins. */ // @ts-expect-error: errors could be `messages`. if (error && !messages.includes(error)) { try { diff --git a/script/info.js b/script/info.js index 6167eb4..c16a85c 100644 --- a/script/info.js +++ b/script/info.js @@ -12,6 +12,8 @@ * Whether to use GFM. * @property {string} input * Input. + * @property {boolean} mdx + * Whether to use MDX. * @property {string} name * Name. * @property {Array} output @@ -27,6 +29,8 @@ * Whether to use GFM (optional). * @property {'input' | 'output'} [label] * Label (optional). + * @property {boolean} [mdx] + * Whether to use MDX (optional). * @property {boolean} [positionless] * Whether this check also applies without positions (optional). * @property {string} name @@ -168,7 +172,14 @@ async function addPlugin(name) { throw new Error('Could not parse example in `' + ruleId + '`', {cause}) } - const exampleValue = strip(lines.join('\n').replace(/^\r?\n/g, '')) + const exampleValue = strip( + lines + .join('\n') + // Remove head. + .replace(/^\r?\n/g, '') + // Remove magic handling of `nul` control picture. + .replace(/␀/g, '') + ) const configuration = JSON.stringify({config: info.config || true}) const name = info.name @@ -179,6 +190,7 @@ async function addPlugin(name) { positionless: info.positionless || false, gfm: info.gfm || false, input: exampleValue, + mdx: info.mdx || false, output: [] }) @@ -198,6 +210,7 @@ async function addPlugin(name) { positionless: info.positionless || false, gfm: info.gfm || false, input: '', + mdx: info.mdx || false, output: [] } result.checks.push(found) diff --git a/script/pipeline-package.js b/script/pipeline-package.js index 27f32f2..f347e52 100644 --- a/script/pipeline-package.js +++ b/script/pipeline-package.js @@ -1255,6 +1255,10 @@ function generateReadmeExample(state) { 'github-remark-gfm', 'https://github.com/remarkjs/remark-gfm' ) + state.urls.set( + 'github-remark-mdx', + 'https://mdxjs.com/packages/remark-mdx/' + ) if (!empty) { children.push({ @@ -1263,8 +1267,40 @@ function generateReadmeExample(state) { children: [{type: 'text', value: 'In'}] }) - // To do: other plugins. + /** @type {Array} */ + const phrasing = [] + if (check.gfm) { + phrasing.push( + {type: 'text', value: 'GFM ('}, + { + type: 'linkReference', + identifier: 'github-remark-gfm', + referenceType: 'full', + children: [{type: 'inlineCode', value: 'remark-gfm'}] + }, + {type: 'text', value: ')'} + ) + } + + if (check.mdx) { + if (phrasing.length > 0) { + phrasing.push({type: 'text', value: ',\n'}) + } + + phrasing.push( + {type: 'text', value: 'MDX ('}, + { + type: 'linkReference', + identifier: 'github-remark-mdx', + referenceType: 'full', + children: [{type: 'inlineCode', value: 'remark-mdx'}] + }, + {type: 'text', value: ')'} + ) + } + + if (phrasing.length > 0) { children.push({ type: 'blockquote', children: [ @@ -1276,14 +1312,9 @@ function generateReadmeExample(state) { type: 'strong', children: [{type: 'text', value: 'Note'}] }, - {type: 'text', value: ': this example uses GFM ('}, - { - type: 'linkReference', - identifier: 'github-remark-gfm', - referenceType: 'full', - children: [{type: 'inlineCode', value: 'remark-gfm'}] - }, - {type: 'text', value: ').'} + {type: 'text', value: ': this example uses\n'}, + ...phrasing, + {type: 'text', value: '.'} ] } ] @@ -1292,7 +1323,7 @@ function generateReadmeExample(state) { children.push({ type: 'code', - lang: 'markdown', + lang: check.mdx ? 'mdx' : 'markdown', value: check.input }) } diff --git a/test.js b/test.js index 1ac29a7..6c8c40e 100644 --- a/test.js +++ b/test.js @@ -16,6 +16,7 @@ import remarkLintFinalNewline from 'remark-lint-final-newline' import remarkLintNoHeadingPunctuation from 'remark-lint-no-heading-punctuation' import remarkLintNoMultipleToplevelHeadings from 'remark-lint-no-multiple-toplevel-headings' import remarkLintNoUndefinedReferences from 'remark-lint-no-undefined-references' +import remarkMdx from 'remark-mdx' import {lintRule} from 'unified-lint-rule' import {removePosition} from 'unist-util-remove-position' import {VFile} from 'vfile' @@ -81,9 +82,12 @@ test('remark-lint', async function (t) { assert.deepEqual(file.messages.map(jsonClone), [ { + column: 2, fatal: true, + line: 1, message: 'Missing newline character at end of file', - name: '1:1', + name: '1:2', + place: {column: 2, line: 1, offset: 1}, reason: 'Missing newline character at end of file', ruleId: 'final-newline', source: 'remark-lint', @@ -96,7 +100,7 @@ test('remark-lint', async function (t) { const file = await remark().use(remarkLintFinalNewline, true).process('.') assert.deepEqual(file.messages.map(String), [ - '1:1: Missing newline character at end of file' + '1:2: Missing newline character at end of file' ]) }) @@ -114,7 +118,7 @@ test('remark-lint', async function (t) { .process('.') assert.deepEqual(file.messages.map(String), [ - '1:1: Missing newline character at end of file' + '1:2: Missing newline character at end of file' ]) } ) @@ -139,9 +143,12 @@ test('remark-lint', async function (t) { assert.deepEqual(file.messages.map(jsonClone), [ { + column: 2, fatal: true, + line: 1, message: 'Missing newline character at end of file', - name: '1:1', + name: '1:2', + place: {column: 2, line: 1, offset: 1}, reason: 'Missing newline character at end of file', ruleId: 'final-newline', source: 'remark-lint', @@ -160,9 +167,12 @@ test('remark-lint', async function (t) { assert.deepEqual(file.messages.map(jsonClone), [ { + column: 2, fatal: false, + line: 1, message: 'Missing newline character at end of file', - name: '1:1', + name: '1:2', + place: {column: 2, line: 1, offset: 1}, reason: 'Missing newline character at end of file', ruleId: 'final-newline', source: 'remark-lint', @@ -181,9 +191,12 @@ test('remark-lint', async function (t) { assert.deepEqual(file.messages.map(jsonClone), [ { + column: 2, fatal: false, + line: 1, message: 'Missing newline character at end of file', - name: '1:1', + name: '1:2', + place: {column: 2, line: 1, offset: 1}, reason: 'Missing newline character at end of file', ruleId: 'final-newline', source: 'remark-lint', @@ -302,9 +315,17 @@ async function assertCheck(plugin, info, check) { /** @type {{config: unknown}} */ const {config} = JSON.parse(check.configuration) /** @type {PluggableList} */ - const extras = check.gfm ? [remarkGfm] : [] + const extras = [] const value = controlPictures(check.input) + if (check.gfm) { + extras.push(remarkGfm) + } + + if (check.mdx) { + extras.push(remarkMdx) + } + const file = await remark() .use(plugin, config) .use(extras)