Refactor more code, improve small things

This commit is contained in:
Titus Wormer 2023-12-15 12:57:49 +01:00
parent 547188ec6f
commit 627363b2a2
No known key found for this signature in database
GPG Key ID: E6E581152ED04E2E
35 changed files with 344 additions and 143 deletions

View File

@ -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",

View File

@ -206,8 +206,8 @@ const remarkLintCheckboxCharacterStyle = lintRule(
value.slice(point.offset - 2, point.offset + 1)
)
// Failsafe to make sure we dont crash if there actually isnt a checkbox.
/* c8 ignore next */
/* c8 ignore next 2 -- failsafe so we dont crash if there actually isnt
* a checkbox. */
if (!match) return
const style = node.checked ? checked : unchecked

View File

@ -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

View File

@ -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

View File

@ -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/
*
* <!-- Comments are fine between and after definitions -->
* <!-- Comments are fine between and after definitions. -->
*
* [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
*/
/// <reference types="mdast-util-mdx" />
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<Definition | FootnoteDefinition>} */
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 ]*<!--/.test(node.value)) ||
// Ignore MDX comments.
((node.type === 'mdxFlowExpression' ||
node.type === 'mdxTextExpression') &&
/^\s*\/\*/.test(node.value))
) {
// Empty.
} else {
const place = pointEnd(node)
// To do: ignore MDX comments?
// Ignore generated and HTML comment nodes.
if (
!start ||
node.type === 'root' ||
(node.type === 'html' && /^\s*<!--/.test(node.value))
) {
return
if (place) {
last = place
}
}
})
const line = start.line
for (const node of definitions) {
const point = pointStart(node)
if (node.type === 'definition') {
if (last && last > line) {
file.message(
'Move definitions to the end of the file (after the node at line `' +
last +
'`)',
node
)
}
} else if (last === 0) {
last = line
}
},
true
)
if (point && last && point.line < last.line) {
file.message(
'Move definitions to the end of the file (after `' +
stringifyPosition(last) +
'`)',
node
)
}
}
}
)

View File

@ -33,8 +33,11 @@
],
"dependencies": {
"@types/mdast": "^4.0.0",
"@types/unist": "^3.0.0",
"mdast-util-mdx": "^3.0.0",
"unified-lint-rule": "^2.0.0",
"unist-util-position": "^5.0.0",
"unist-util-stringify-position": "^4.0.0",
"unist-util-visit": "^5.0.0"
},
"scripts": {},

View File

@ -171,10 +171,10 @@ Another paragraph.
###### Out
```text
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`)
```
##### `ok-comments.md`
##### `ok-html-comments.md`
###### In
@ -183,7 +183,28 @@ Paragraph.
[example-1]: http://example.com/one/
<!-- Comments are fine between and after definitions -->
<!-- Comments are fine between and after definitions. -->
[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

View File

@ -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)
}
}
)

View File

@ -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": {

View File

@ -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 <b>MDX</b>, JSX is supported.
*
* <h1>First heading</h1>
*/
/**
@ -158,11 +165,14 @@
* Configuration.
*/
/// <reference types="mdast-util-mdx" />
import {lintRule} from 'unified-lint-rule'
import {position} from 'unist-util-position'
import {EXIT, visit} from 'unist-util-visit'
const re = /<h([1-6])/
const htmlRe = /<h([1-6])/
const jsxNameRe = /h([1-6])/
const remarkLintFirstHeadingLevel = lintRule(
{
@ -187,11 +197,17 @@ const remarkLintFirstHeadingLevel = lintRule(
/** @type {Depth | undefined} */
let rank
// To do: MDX?
if (node.type === 'heading') {
rank = node.depth
} else if (node.type === 'html') {
const results = node.value.match(re)
const results = node.value.match(htmlRe)
rank = results ? /** @type {Depth} */ (Number(results[1])) : undefined
} else if (
(node.type === 'mdxJsxFlowElement' ||
node.type === 'mdxJsxTextElement') &&
node.name
) {
const results = node.name.match(jsxNameRe)
rank = results ? /** @type {Depth} */ (Number(results[1])) : undefined
}

View File

@ -34,6 +34,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"

View File

@ -305,6 +305,23 @@ Paragraph.
1:1-1:14: First heading level should be `2`
```
##### `ok.mdx`
###### In
> 👉 **Note**: this example uses
> MDX ([`remark-mdx`][github-remark-mdx]).
```mdx
In <b>MDX</b>, JSX is supported.
<h1>First heading</h1>
```
###### 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

View File

@ -126,8 +126,7 @@ const remarkLintListItemContentIndent = lintRule(
file.message(
'Dont use mixed indentation for children, ' +
// Hard to test, I couldnt find it at least.
/* c8 ignore next */
/* c8 ignore next -- hard to test, I couldnt find it at least. */
(diff > 0 ? 'add' : 'remove') +
' ' +
abs +

View File

@ -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

View File

@ -119,6 +119,8 @@
* 4:12: Line must be at most 10 characters
*/
/// <reference types="mdast-util-mdx" />
/**
* @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: <https://github.com/mdx-js/specification>.
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'

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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)
}
})

View File

@ -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"

View File

@ -138,8 +138,8 @@ const remarkLintNoTableIndentation = lintRule(
const head = parent.children[0]
column = pointStart(head)?.column
// Skip past the first line if were the first child of a list item.
/* c8 ignore next 3 */
/* c8 ignore next 4 -- skip past the first line if were the first
* child of a list item. */
if (typeof line === 'number' && head === node) {
line++
}

View File

@ -152,7 +152,8 @@ So its 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

View File

@ -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 lets 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 lets keep it. */
if (
(node.type === 'imageReference' ||
node.type === 'linkReference' ||

View File

@ -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

View File

@ -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<string, {node: DefinitionContent | undefined, used: boolean}>} */
const map = new Map()
/** @type {Map<string, {node: Definition | FootnoteDefinition | undefined, used: boolean}>} */
const footnoteDefinitions = new Map()
/** @type {Map<string, {node: Definition | FootnoteDefinition | undefined, used: boolean}>} */
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) {

View File

@ -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

View File

@ -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~~

View File

@ -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<number>} */
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 were sure offsets exist.
/* c8 ignore next */
/* c8 ignore next -- Only called when were sure offsets exist. */
return typeof head === 'number' && typeof tail === 'number' ? tail - head : 0
}

View File

@ -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
<!-- Empty cells are OK, but those surrounding them may not be. -->
@ -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
<!-- Missing cells are fine as well. -->

View File

@ -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
| | | |

View File

@ -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

View File

@ -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 {

View File

@ -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<string>} 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)

View File

@ -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<PhrasingContent>} */
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
})
}

35
test.js
View File

@ -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)