mirror of
https://github.com/remarkjs/remark-lint.git
synced 2024-08-18 00:00:26 +03:00
Refactor code style in scripts
This commit is contained in:
parent
db4810d891
commit
0e79b65cc7
@ -58,9 +58,14 @@ touch .remarkrc.js
|
||||
|
||||
```js
|
||||
// .remarkrc.js
|
||||
module.exports = {
|
||||
plugins: []
|
||||
}
|
||||
/**
|
||||
* @typedef {import('unified').Preset} Preset
|
||||
*/
|
||||
|
||||
/** @type {Preset} */
|
||||
const preset = {plugins: []}
|
||||
|
||||
export default preset
|
||||
```
|
||||
|
||||
Then, in our `package.json`, add the following script to process all the
|
||||
@ -142,7 +147,7 @@ import {lintRule} from 'unified-lint-rule'
|
||||
|
||||
const remarkLintNoGifAllowed = lintRule(
|
||||
'remark-lint:no-gif-allowed',
|
||||
(tree, file, options) => {
|
||||
function (tree, file, options) {
|
||||
// Rule implementation
|
||||
}
|
||||
)
|
||||
@ -155,9 +160,16 @@ namespace.
|
||||
If your project was named `my-project`, then you can export your rule as:
|
||||
|
||||
```js
|
||||
const remarkLintNoGifAllowed = lintRule('my-project-name:no-gif-allowed', () => {})
|
||||
const remarkLintNoGifAllowed = lintRule(
|
||||
'my-project-name:no-gif-allowed',
|
||||
function () {}
|
||||
)
|
||||
|
||||
// Or:
|
||||
const remarkLintNoGifAllowed = lintRule('my-npm-published-package:no-gif-allowed', () => {})
|
||||
const remarkLintNoGifAllowed = lintRule(
|
||||
'my-npm-published-package:no-gif-allowed',
|
||||
function () {}
|
||||
)
|
||||
```
|
||||
|
||||
This can help you when wanting to create a group of rules under the same
|
||||
@ -168,7 +180,7 @@ This can help you when wanting to create a group of rules under the same
|
||||
Your rule function will receive three arguments:
|
||||
|
||||
```js
|
||||
(tree, file, options) => {}
|
||||
function rule(tree, file, options) {}
|
||||
```
|
||||
|
||||
* `tree` (*required*): [mdast][]
|
||||
@ -187,38 +199,36 @@ recursively inspect all the image nodes, and
|
||||
nodes that we have generated ourselves and do not belong to the `doc.md`.
|
||||
|
||||
```js
|
||||
import {lintRule} from 'unified-lint-rule'
|
||||
import {visit} from 'unist-visit-util'
|
||||
import {generated} from 'unist-util-generated'
|
||||
/**
|
||||
* @typedef {import('mdast').Root} Root
|
||||
*/
|
||||
|
||||
function isValidNode(node) {
|
||||
// Here we check whether the given node violates our rule.
|
||||
// Implementation details are not relevant to the scope of this example.
|
||||
// This is an overly simplified solution for demonstration purposes
|
||||
if (node.url && typeof node.url === 'string') {
|
||||
return !node.url.endsWith('.gif')
|
||||
}
|
||||
}
|
||||
import {lintRule} from 'unified-lint-rule'
|
||||
import {visit} from 'unist-util-visit'
|
||||
|
||||
const remarkLintNoGifAllowed = lintRule(
|
||||
'remark-lint:no-gif-allowed',
|
||||
(tree, file, options) => {
|
||||
visit(tree, 'image', (node) => {
|
||||
if (!generated(node)) {
|
||||
// This is an extremely simplified example of how to structure
|
||||
// the logic to check whether a node violates your rule.
|
||||
// You have complete freedom over how to visit/inspect the tree,
|
||||
// and on how to implement the validation logic for your node.
|
||||
const isValid = isValidNode(node)
|
||||
/**
|
||||
* @param {Root} tree
|
||||
* Tree.
|
||||
* @returns {undefined}
|
||||
* Nothing.
|
||||
*/
|
||||
function (tree, file, options) {
|
||||
visit(tree, 'image', function (node) {
|
||||
// This is an extremely simplified example of how to structure
|
||||
// the logic to check whether a node violates your rule.
|
||||
// You have complete freedom over how to visit/inspect the tree,
|
||||
// and on how to implement the validation logic for your node.
|
||||
const isValid = !node.url.endsWith('.gif')
|
||||
|
||||
if (!isValid) {
|
||||
// Remember to provide the node as second argument to the message,
|
||||
// in order to obtain the position and column where the violation occurred.
|
||||
file.message(
|
||||
'Invalid image file extensions. Please do not use gifs',
|
||||
node
|
||||
)
|
||||
}
|
||||
if (!isValid) {
|
||||
// Remember to provide the node as second argument to the message,
|
||||
// in order to obtain the position and column where the violation occurred.
|
||||
file.message(
|
||||
'Invalid image file extensions. Please do not use gifs',
|
||||
node
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -236,13 +246,14 @@ You can do that by importing your rule and adding it in `plugins` array:
|
||||
|
||||
```js
|
||||
// .remarkrc.js
|
||||
/**
|
||||
* @typedef {import('unified').Preset} Preset
|
||||
*/
|
||||
|
||||
import remarkLintNoGifAllowed from './rules/no-gif-allowed.js'
|
||||
|
||||
const plugins = {
|
||||
plugins: [remarkLintNoGifAllowed]
|
||||
}
|
||||
|
||||
const preset = {plugins}
|
||||
/** @type {Preset} */
|
||||
const preset = {plugins: [remarkLintNoGifAllowed]}
|
||||
|
||||
export default preset
|
||||
```
|
||||
|
15
package.json
15
package.json
@ -116,7 +116,11 @@
|
||||
"c8": "^8.0.0",
|
||||
"comment-parser": "^1.0.0",
|
||||
"github-slugger": "^2.0.0",
|
||||
"mdast-util-from-markdown": "^2.0.0",
|
||||
"mdast-util-gfm": "^3.0.0",
|
||||
"mdast-util-to-markdown": "^2.0.0",
|
||||
"mdast-zone": "^6.0.0",
|
||||
"micromark-extension-gfm": "^3.0.0",
|
||||
"parse-author": "^2.0.0",
|
||||
"prettier": "^3.0.0",
|
||||
"remark": "^15.0.0",
|
||||
@ -127,16 +131,16 @@
|
||||
"remark-toc": "^9.0.0",
|
||||
"remark-validate-links": "^13.0.0",
|
||||
"strip-indent": "^4.0.0",
|
||||
"to-vfile": "^8.0.0",
|
||||
"type-coverage": "^2.0.0",
|
||||
"type-fest": "^4.0.0",
|
||||
"typescript": "^5.0.0",
|
||||
"unist-builder": "^4.0.0",
|
||||
"unist-util-remove-position": "^5.0.0",
|
||||
"vfile": "^6.0.0",
|
||||
"xo": "^0.56.0"
|
||||
},
|
||||
"scripts": {
|
||||
"generate": "node --conditions development script/build-presets.js && node --conditions development script/build-rules.js",
|
||||
"generate": "node --conditions development script/build-plugins.js && node --conditions development script/build-presets.js",
|
||||
"build": "tsc --build --clean && tsc --build && type-coverage",
|
||||
"format": "remark . --frail --output --quiet && prettier . --log-level warn --write && xo --fix",
|
||||
"test": "npm run build && npm run generate && npm run format && npm run test-coverage",
|
||||
@ -174,8 +178,8 @@
|
||||
"remark-lint-list-item-indent",
|
||||
"space"
|
||||
],
|
||||
"./script/plugin/list-of-presets.js",
|
||||
"./script/plugin/list-of-rules.js"
|
||||
"./script/plugin/list-of-plugins.js",
|
||||
"./script/plugin/list-of-presets.js"
|
||||
]
|
||||
},
|
||||
"typeCoverage": {
|
||||
@ -193,7 +197,8 @@
|
||||
],
|
||||
"rules": {
|
||||
"max-depth": "off",
|
||||
"no-await-in-loop": "off"
|
||||
"no-await-in-loop": "off",
|
||||
"unicorn/no-array-callback-reference": "off"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
@ -77,22 +77,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintBlockquoteIndentation from 'remark-lint-blockquote-indentation'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintBlockquoteIndentation)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintBlockquoteIndentation)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -76,22 +76,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintCheckboxCharacterStyle from 'remark-lint-checkbox-character-style'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintCheckboxCharacterStyle)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintCheckboxCharacterStyle)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -72,22 +72,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintCheckboxContentIndent from 'remark-lint-checkbox-content-indent'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintCheckboxContentIndent)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintCheckboxContentIndent)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -75,22 +75,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintCodeBlockStyle from 'remark-lint-code-block-style'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintCodeBlockStyle)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintCodeBlockStyle)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -74,22 +74,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintDefinitionCase from 'remark-lint-definition-case'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintDefinitionCase)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintDefinitionCase)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -75,22 +75,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintDefinitionSpacing from 'remark-lint-definition-spacing'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintDefinitionSpacing)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintDefinitionSpacing)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -75,22 +75,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintEmphasisMarker from 'remark-lint-emphasis-marker'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintEmphasisMarker)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintEmphasisMarker)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -74,22 +74,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintFencedCodeFlag from 'remark-lint-fenced-code-flag'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintFencedCodeFlag)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintFencedCodeFlag)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -75,22 +75,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintFencedCodeMarker from 'remark-lint-fenced-code-marker'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintFencedCodeMarker)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintFencedCodeMarker)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
@ -162,46 +160,6 @@ Indented code blocks are not affected by this rule:
|
||||
|
||||
No messages.
|
||||
|
||||
##### `not-ok-consistent-tick.md`
|
||||
|
||||
###### In
|
||||
|
||||
````markdown
|
||||
```alpha
|
||||
bravo()
|
||||
```
|
||||
|
||||
~~~
|
||||
charlie()
|
||||
~~~
|
||||
````
|
||||
|
||||
###### Out
|
||||
|
||||
```text
|
||||
5:1-7:4: Fenced code should use `` ` `` as a marker
|
||||
```
|
||||
|
||||
##### `not-ok-consistent-tilde.md`
|
||||
|
||||
###### In
|
||||
|
||||
````markdown
|
||||
~~~alpha
|
||||
bravo()
|
||||
~~~
|
||||
|
||||
```
|
||||
charlie()
|
||||
```
|
||||
````
|
||||
|
||||
###### Out
|
||||
|
||||
```text
|
||||
5:1-7:4: Fenced code should use `~` as a marker
|
||||
```
|
||||
|
||||
##### `ok.md`
|
||||
|
||||
When configured with ``'`'``.
|
||||
@ -242,6 +200,46 @@ charlie()
|
||||
|
||||
No messages.
|
||||
|
||||
##### `not-ok-consistent-tick.md`
|
||||
|
||||
###### In
|
||||
|
||||
````markdown
|
||||
```alpha
|
||||
bravo()
|
||||
```
|
||||
|
||||
~~~
|
||||
charlie()
|
||||
~~~
|
||||
````
|
||||
|
||||
###### Out
|
||||
|
||||
```text
|
||||
5:1-7:4: Fenced code should use `` ` `` as a marker
|
||||
```
|
||||
|
||||
##### `not-ok-consistent-tilde.md`
|
||||
|
||||
###### In
|
||||
|
||||
````markdown
|
||||
~~~alpha
|
||||
bravo()
|
||||
~~~
|
||||
|
||||
```
|
||||
charlie()
|
||||
```
|
||||
````
|
||||
|
||||
###### Out
|
||||
|
||||
```text
|
||||
5:1-7:4: Fenced code should use `~` as a marker
|
||||
```
|
||||
|
||||
##### `not-ok-incorrect.md`
|
||||
|
||||
When configured with `'💩'`.
|
||||
|
@ -73,22 +73,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintFileExtension from 'remark-lint-file-extension'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintFileExtension)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintFileExtension)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -75,22 +75,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintFinalDefinition from 'remark-lint-final-definition'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintFinalDefinition)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintFinalDefinition)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -74,22 +74,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintFinalNewline from 'remark-lint-final-newline'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintFinalNewline)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintFinalNewline)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -69,22 +69,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintFirstHeadingLevel from 'remark-lint-first-heading-level'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintFirstHeadingLevel)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintFirstHeadingLevel)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -76,22 +76,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintHardBreakSpaces from 'remark-lint-hard-break-spaces'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintHardBreakSpaces)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintHardBreakSpaces)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -75,22 +75,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintHeadingIncrement from 'remark-lint-heading-increment'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintHeadingIncrement)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintHeadingIncrement)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -75,22 +75,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintHeadingStyle from 'remark-lint-heading-style'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintHeadingStyle)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintHeadingStyle)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -70,22 +70,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintLinebreakStyle from 'remark-lint-linebreak-style'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintLinebreakStyle)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintLinebreakStyle)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -75,22 +75,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintLinkTitleStyle from 'remark-lint-link-title-style'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintLinkTitleStyle)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintLinkTitleStyle)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -74,22 +74,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintListItemBulletIndent from 'remark-lint-list-item-bullet-indent'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintListItemBulletIndent)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintListItemBulletIndent)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -75,22 +75,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintListItemContentIndent from 'remark-lint-list-item-content-indent'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintListItemContentIndent)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintListItemContentIndent)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -77,22 +77,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintListItemIndent from 'remark-lint-list-item-indent'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintListItemIndent)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintListItemIndent)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
@ -230,24 +228,6 @@ Paragraph.
|
||||
|
||||
No messages.
|
||||
|
||||
##### `not-ok.md`
|
||||
|
||||
When configured with `'mixed'`.
|
||||
|
||||
###### In
|
||||
|
||||
> 👉 **Note**: `·` represents a space.
|
||||
|
||||
```markdown
|
||||
*···List item.
|
||||
```
|
||||
|
||||
###### Out
|
||||
|
||||
```text
|
||||
1:5: Incorrect list-item indent: remove 2 spaces
|
||||
```
|
||||
|
||||
##### `ok.md`
|
||||
|
||||
When configured with `'space'`.
|
||||
@ -316,6 +296,24 @@ When configured with `'tab-size'`.
|
||||
|
||||
##### `not-ok.md`
|
||||
|
||||
When configured with `'mixed'`.
|
||||
|
||||
###### In
|
||||
|
||||
> 👉 **Note**: `·` represents a space.
|
||||
|
||||
```markdown
|
||||
*···List item.
|
||||
```
|
||||
|
||||
###### Out
|
||||
|
||||
```text
|
||||
1:5: Incorrect list-item indent: remove 2 spaces
|
||||
```
|
||||
|
||||
##### `not-ok.md`
|
||||
|
||||
When configured with `'💩'`.
|
||||
|
||||
###### Out
|
||||
|
@ -75,22 +75,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintListItemSpacing from 'remark-lint-list-item-spacing'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintListItemSpacing)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintListItemSpacing)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -73,22 +73,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintMaximumHeadingLength from 'remark-lint-maximum-heading-length'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintMaximumHeadingLength)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintMaximumHeadingLength)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -73,22 +73,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintMaximumLineLength from 'remark-lint-maximum-line-length'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintMaximumLineLength)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintMaximumLineLength)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -75,22 +75,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintNoBlockquoteWithoutMarker from 'remark-lint-no-blockquote-without-marker'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoBlockquoteWithoutMarker)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoBlockquoteWithoutMarker)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -76,22 +76,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintNoConsecutiveBlankLines from 'remark-lint-no-consecutive-blank-lines'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoConsecutiveBlankLines)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoConsecutiveBlankLines)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -69,22 +69,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintNoDuplicateDefinedUrls from 'remark-lint-no-duplicate-defined-urls'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoDuplicateDefinedUrls)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoDuplicateDefinedUrls)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -73,22 +73,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintNoDuplicateDefinitions from 'remark-lint-no-duplicate-definitions'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoDuplicateDefinitions)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoDuplicateDefinitions)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -71,22 +71,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintNoDuplicateHeadingsInSection from 'remark-lint-no-duplicate-headings-in-section'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoDuplicateHeadingsInSection)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoDuplicateHeadingsInSection)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -74,22 +74,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintNoDuplicateHeadings from 'remark-lint-no-duplicate-headings'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoDuplicateHeadings)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoDuplicateHeadings)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -75,22 +75,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintNoEmphasisAsHeading from 'remark-lint-no-emphasis-as-heading'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoEmphasisAsHeading)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoEmphasisAsHeading)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -69,22 +69,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintNoEmptyUrl from 'remark-lint-no-empty-url'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoEmptyUrl)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoEmptyUrl)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -73,22 +73,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintNoFileNameArticles from 'remark-lint-no-file-name-articles'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoFileNameArticles)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoFileNameArticles)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -73,22 +73,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintNoFileNameConsecutiveDashes from 'remark-lint-no-file-name-consecutive-dashes'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoFileNameConsecutiveDashes)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoFileNameConsecutiveDashes)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -72,22 +72,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintNoFileNameIrregularCharacters from 'remark-lint-no-file-name-irregular-characters'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoFileNameIrregularCharacters)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoFileNameIrregularCharacters)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
@ -151,14 +149,6 @@ No messages.
|
||||
1:1: Do not use `_` in a file name
|
||||
```
|
||||
|
||||
##### `plug ins.md`
|
||||
|
||||
###### Out
|
||||
|
||||
```text
|
||||
1:1: Do not use ` ` in a file name
|
||||
```
|
||||
|
||||
##### `README.md`
|
||||
|
||||
When configured with `'\\.a-z0-9'`.
|
||||
@ -169,6 +159,14 @@ When configured with `'\\.a-z0-9'`.
|
||||
1:1: Do not use `R` in a file name
|
||||
```
|
||||
|
||||
##### `plug ins.md`
|
||||
|
||||
###### Out
|
||||
|
||||
```text
|
||||
1:1: Do not use ` ` in a file name
|
||||
```
|
||||
|
||||
## Compatibility
|
||||
|
||||
Projects maintained by the unified collective are compatible with all maintained
|
||||
|
@ -73,22 +73,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintNoFileNameMixedCase from 'remark-lint-no-file-name-mixed-case'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoFileNameMixedCase)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoFileNameMixedCase)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -73,22 +73,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintNoFileNameOuterDashes from 'remark-lint-no-file-name-outer-dashes'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoFileNameOuterDashes)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoFileNameOuterDashes)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -76,22 +76,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintNoHeadingContentIndent from 'remark-lint-no-heading-content-indent'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoHeadingContentIndent)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoHeadingContentIndent)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -70,22 +70,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintNoHeadingIndent from 'remark-lint-no-heading-indent'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoHeadingIndent)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoHeadingIndent)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -70,22 +70,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintNoHeadingLikeParagraph from 'remark-lint-no-heading-like-paragraph'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoHeadingLikeParagraph)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoHeadingLikeParagraph)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -72,22 +72,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintNoHeadingPunctuation from 'remark-lint-no-heading-punctuation'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoHeadingPunctuation)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoHeadingPunctuation)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
@ -143,6 +141,20 @@ The following options (default: `'\\.,;:!?'`) are accepted:
|
||||
|
||||
No messages.
|
||||
|
||||
##### `ok.md`
|
||||
|
||||
When configured with `',;:!?'`.
|
||||
|
||||
###### In
|
||||
|
||||
```markdown
|
||||
# Hello…
|
||||
```
|
||||
|
||||
###### Out
|
||||
|
||||
No messages.
|
||||
|
||||
##### `not-ok.md`
|
||||
|
||||
###### In
|
||||
@ -169,20 +181,6 @@ No messages.
|
||||
9:1-9:9: Don’t add a trailing `;` to headings
|
||||
```
|
||||
|
||||
##### `ok.md`
|
||||
|
||||
When configured with `',;:!?'`.
|
||||
|
||||
###### In
|
||||
|
||||
```markdown
|
||||
# Hello…
|
||||
```
|
||||
|
||||
###### Out
|
||||
|
||||
No messages.
|
||||
|
||||
## Compatibility
|
||||
|
||||
Projects maintained by the unified collective are compatible with all maintained
|
||||
|
@ -68,22 +68,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintNoHtml from 'remark-lint-no-html'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoHtml)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoHtml)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -76,22 +76,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintNoInlinePadding from 'remark-lint-no-inline-padding'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoInlinePadding)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoInlinePadding)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -75,22 +75,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintNoLiteralUrls from 'remark-lint-no-literal-urls'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoLiteralUrls)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoLiteralUrls)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -70,22 +70,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintNoMissingBlankLines from 'remark-lint-no-missing-blank-lines'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoMissingBlankLines)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoMissingBlankLines)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -74,22 +74,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintNoMultipleToplevelHeadings from 'remark-lint-no-multiple-toplevel-headings'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoMultipleToplevelHeadings)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoMultipleToplevelHeadings)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -106,7 +106,6 @@ const remarkLintNoParagraphContentIndent = lintRule(
|
||||
const value = String(file)
|
||||
const loc = location(value)
|
||||
|
||||
// eslint-disable-next-line complexity
|
||||
visit(tree, 'paragraph', (node, _, parent) => {
|
||||
const end = pointEnd(node)?.line
|
||||
let line = pointStart(node)?.line
|
||||
|
@ -53,7 +53,8 @@
|
||||
"xo": {
|
||||
"prettier": true,
|
||||
"rules": {
|
||||
"capitalized-comments": "off"
|
||||
"capitalized-comments": "off",
|
||||
"complexity": "off"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -70,22 +70,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintNoParagraphContentIndent from 'remark-lint-no-paragraph-content-indent'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoParagraphContentIndent)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoParagraphContentIndent)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -70,22 +70,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintNoReferenceLikeUrl from 'remark-lint-no-reference-like-url'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoReferenceLikeUrl)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoReferenceLikeUrl)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -74,22 +74,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintNoShellDollars from 'remark-lint-no-shell-dollars'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoShellDollars)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoShellDollars)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -75,22 +75,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintNoShortcutReferenceImage from 'remark-lint-no-shortcut-reference-image'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoShortcutReferenceImage)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoShortcutReferenceImage)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -75,22 +75,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintNoShortcutReferenceLink from 'remark-lint-no-shortcut-reference-link'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoShortcutReferenceLink)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoShortcutReferenceLink)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -76,22 +76,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintNoTableIndentation from 'remark-lint-no-table-indentation'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoTableIndentation)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoTableIndentation)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -70,22 +70,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintNoTabs from 'remark-lint-no-tabs'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoTabs)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoTabs)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -213,7 +213,6 @@ const remarkLintNoUndefinedReferences = lintRule(
|
||||
/** @type {Array<Range>} */
|
||||
let ranges = []
|
||||
|
||||
// eslint-disable-next-line complexity
|
||||
visit(node, (child) => {
|
||||
// Ignore the node itself.
|
||||
if (child === node) return
|
||||
@ -292,12 +291,10 @@ const remarkLintNoUndefinedReferences = lintRule(
|
||||
let range = ranges.pop()
|
||||
|
||||
// Range should always exist.
|
||||
// eslint-disable-next-line max-depth
|
||||
if (range) {
|
||||
range.push(lines[lineIndex][0] + index)
|
||||
|
||||
// This is the end of a reference already.
|
||||
// eslint-disable-next-line max-depth
|
||||
if (range.length === 4) {
|
||||
handleRange(range)
|
||||
range = []
|
||||
@ -314,7 +311,6 @@ const remarkLintNoUndefinedReferences = lintRule(
|
||||
const range = ranges.pop()
|
||||
|
||||
// Range should always exist.
|
||||
// eslint-disable-next-line max-depth
|
||||
if (range) {
|
||||
range.push(lines[lineIndex][0] + index)
|
||||
handleRange(range)
|
||||
|
@ -55,6 +55,8 @@
|
||||
"prettier": true,
|
||||
"rules": {
|
||||
"capitalized-comments": "off",
|
||||
"complexity": "off",
|
||||
"max-depth": "off",
|
||||
"unicorn/prefer-at": "off",
|
||||
"unicorn/prefer-code-point": "off",
|
||||
"unicorn/prefer-string-replace-all": "off",
|
||||
|
@ -73,22 +73,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintNoUndefinedReferences from 'remark-lint-no-undefined-references'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoUndefinedReferences)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoUndefinedReferences)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
@ -178,6 +176,38 @@ Just two braces can’t link: [].
|
||||
|
||||
No messages.
|
||||
|
||||
##### `ok-allow.md`
|
||||
|
||||
When configured with `{ allow: [ '...', '…' ] }`.
|
||||
|
||||
###### In
|
||||
|
||||
```markdown
|
||||
> Eliding a portion of a quoted passage […] is acceptable.
|
||||
```
|
||||
|
||||
###### Out
|
||||
|
||||
No messages.
|
||||
|
||||
##### `ok-allow.md`
|
||||
|
||||
When configured with `{ allow: [ 'a', { source: '^b\\.' } ] }`.
|
||||
|
||||
###### In
|
||||
|
||||
```markdown
|
||||
[foo][b.c]
|
||||
|
||||
[bar][a]
|
||||
|
||||
Matching is case-insensitive: [bar][B.C]
|
||||
```
|
||||
|
||||
###### Out
|
||||
|
||||
No messages.
|
||||
|
||||
##### `not-ok.md`
|
||||
|
||||
###### In
|
||||
@ -216,38 +246,6 @@ Multiple pairs: [a][b][c].
|
||||
17:23-17:26: Found reference to undefined definition
|
||||
```
|
||||
|
||||
##### `ok-allow.md`
|
||||
|
||||
When configured with `{ allow: [ '...', '…' ] }`.
|
||||
|
||||
###### In
|
||||
|
||||
```markdown
|
||||
> Eliding a portion of a quoted passage […] is acceptable.
|
||||
```
|
||||
|
||||
###### Out
|
||||
|
||||
No messages.
|
||||
|
||||
##### `ok-allow.md`
|
||||
|
||||
When configured with `{ allow: [ 'a', { source: '^b\\.' } ] }`.
|
||||
|
||||
###### In
|
||||
|
||||
```markdown
|
||||
[foo][b.c]
|
||||
|
||||
[bar][a]
|
||||
|
||||
Matching is case-insensitive: [bar][B.C]
|
||||
```
|
||||
|
||||
###### Out
|
||||
|
||||
No messages.
|
||||
|
||||
##### `not-ok.md`
|
||||
|
||||
When configured with `{ allow: [ 'a', { source: '^b\\.' } ] }`.
|
||||
|
@ -71,22 +71,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintNoUnneededFullReferenceImage from 'remark-lint-no-unneeded-full-reference-image'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoUnneededFullReferenceImage)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoUnneededFullReferenceImage)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -71,22 +71,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintNoUnneededFullReferenceLink from 'remark-lint-no-unneeded-full-reference-link'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoUnneededFullReferenceLink)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoUnneededFullReferenceLink)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -73,22 +73,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintNoUnusedDefinitions from 'remark-lint-no-unused-definitions'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoUnusedDefinitions)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoUnusedDefinitions)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -76,22 +76,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintOrderedListMarkerStyle from 'remark-lint-ordered-list-marker-style'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintOrderedListMarkerStyle)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintOrderedListMarkerStyle)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
@ -170,22 +168,6 @@ Unordered lists are not affected by this rule.
|
||||
|
||||
No messages.
|
||||
|
||||
##### `not-ok.md`
|
||||
|
||||
###### In
|
||||
|
||||
```markdown
|
||||
1. Foo
|
||||
|
||||
2) Bar
|
||||
```
|
||||
|
||||
###### Out
|
||||
|
||||
```text
|
||||
3:1-3:8: Marker style should be `.`
|
||||
```
|
||||
|
||||
##### `ok.md`
|
||||
|
||||
When configured with `'.'`.
|
||||
@ -220,6 +202,22 @@ No messages.
|
||||
|
||||
##### `not-ok.md`
|
||||
|
||||
###### In
|
||||
|
||||
```markdown
|
||||
1. Foo
|
||||
|
||||
2) Bar
|
||||
```
|
||||
|
||||
###### Out
|
||||
|
||||
```text
|
||||
3:1-3:8: Marker style should be `.`
|
||||
```
|
||||
|
||||
##### `not-ok.md`
|
||||
|
||||
When configured with `'💩'`.
|
||||
|
||||
###### Out
|
||||
|
@ -74,22 +74,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintOrderedListMarkerValue from 'remark-lint-ordered-list-marker-value'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintOrderedListMarkerValue)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintOrderedListMarkerValue)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
@ -202,40 +200,6 @@ Paragraph.
|
||||
|
||||
No messages.
|
||||
|
||||
##### `not-ok.md`
|
||||
|
||||
When configured with `'one'`.
|
||||
|
||||
###### In
|
||||
|
||||
```markdown
|
||||
1. Foo
|
||||
2. Bar
|
||||
```
|
||||
|
||||
###### Out
|
||||
|
||||
```text
|
||||
2:1-2:8: Marker should be `1`, was `2`
|
||||
```
|
||||
|
||||
##### `also-not-ok.md`
|
||||
|
||||
When configured with `'one'`.
|
||||
|
||||
###### In
|
||||
|
||||
```markdown
|
||||
2. Foo
|
||||
1. Bar
|
||||
```
|
||||
|
||||
###### Out
|
||||
|
||||
```text
|
||||
1:1-1:8: Marker should be `1`, was `2`
|
||||
```
|
||||
|
||||
##### `ok.md`
|
||||
|
||||
When configured with `'single'`.
|
||||
@ -294,6 +258,40 @@ No messages.
|
||||
|
||||
##### `not-ok.md`
|
||||
|
||||
When configured with `'one'`.
|
||||
|
||||
###### In
|
||||
|
||||
```markdown
|
||||
1. Foo
|
||||
2. Bar
|
||||
```
|
||||
|
||||
###### Out
|
||||
|
||||
```text
|
||||
2:1-2:8: Marker should be `1`, was `2`
|
||||
```
|
||||
|
||||
##### `also-not-ok.md`
|
||||
|
||||
When configured with `'one'`.
|
||||
|
||||
###### In
|
||||
|
||||
```markdown
|
||||
2. Foo
|
||||
1. Bar
|
||||
```
|
||||
|
||||
###### Out
|
||||
|
||||
```text
|
||||
1:1-1:8: Marker should be `1`, was `2`
|
||||
```
|
||||
|
||||
##### `not-ok.md`
|
||||
|
||||
When configured with `'ordered'`.
|
||||
|
||||
###### In
|
||||
|
@ -76,22 +76,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintRuleStyle from 'remark-lint-rule-style'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintRuleStyle)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintRuleStyle)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -74,22 +74,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintStrikethroughMarker from 'remark-lint-strikethrough-marker'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintStrikethroughMarker)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintStrikethroughMarker)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -75,22 +75,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintStrongMarker from 'remark-lint-strong-marker'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintStrongMarker)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintStrongMarker)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
@ -178,20 +176,6 @@ __foo__ and __bar__.
|
||||
|
||||
No messages.
|
||||
|
||||
##### `not-ok.md`
|
||||
|
||||
###### In
|
||||
|
||||
```markdown
|
||||
**foo** and __bar__.
|
||||
```
|
||||
|
||||
###### Out
|
||||
|
||||
```text
|
||||
1:13-1:20: Strong should use `*` as a marker
|
||||
```
|
||||
|
||||
##### `ok.md`
|
||||
|
||||
When configured with `'*'`.
|
||||
@ -222,6 +206,20 @@ No messages.
|
||||
|
||||
##### `not-ok.md`
|
||||
|
||||
###### In
|
||||
|
||||
```markdown
|
||||
**foo** and __bar__.
|
||||
```
|
||||
|
||||
###### Out
|
||||
|
||||
```text
|
||||
1:13-1:20: Strong should use `*` as a marker
|
||||
```
|
||||
|
||||
##### `not-ok.md`
|
||||
|
||||
When configured with `'💩'`.
|
||||
|
||||
###### Out
|
||||
|
@ -77,22 +77,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintTableCellPadding from 'remark-lint-table-cell-padding'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintTableCellPadding)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintTableCellPadding)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
@ -206,51 +204,6 @@ Too much padding isn’t good either:
|
||||
13:32: Cell should be padded with 1 space, not 2
|
||||
```
|
||||
|
||||
##### `empty.md`
|
||||
|
||||
When configured with `'padded'`.
|
||||
|
||||
###### In
|
||||
|
||||
> 👉 **Note**: this example uses GFM ([`remark-gfm`][gfm]).
|
||||
|
||||
```markdown
|
||||
<!-- Empty cells are OK, but those surrounding them may not be. -->
|
||||
|
||||
| | Alpha | Bravo|
|
||||
| ------ | ----- | ---: |
|
||||
| Charlie| | Echo|
|
||||
```
|
||||
|
||||
###### Out
|
||||
|
||||
```text
|
||||
3:25: Cell should be padded
|
||||
5:10: Cell should be padded
|
||||
5:25: Cell should be padded
|
||||
```
|
||||
|
||||
##### `missing-body.md`
|
||||
|
||||
When configured with `'padded'`.
|
||||
|
||||
###### In
|
||||
|
||||
> 👉 **Note**: this example uses GFM ([`remark-gfm`][gfm]).
|
||||
|
||||
```markdown
|
||||
<!-- Missing cells are fine as well. -->
|
||||
|
||||
| Alpha | Bravo | Charlie |
|
||||
| ----- | ------- | ------- |
|
||||
| Delta |
|
||||
| Echo | Foxtrot |
|
||||
```
|
||||
|
||||
###### Out
|
||||
|
||||
No messages.
|
||||
|
||||
##### `ok.md`
|
||||
|
||||
When configured with `'compact'`.
|
||||
@ -397,6 +350,51 @@ When configured with `'💩'`.
|
||||
1:1: Incorrect table cell padding style `💩`, expected `'padded'`, `'compact'`, or `'consistent'`
|
||||
```
|
||||
|
||||
##### `empty.md`
|
||||
|
||||
When configured with `'padded'`.
|
||||
|
||||
###### In
|
||||
|
||||
> 👉 **Note**: this example uses GFM ([`remark-gfm`][gfm]).
|
||||
|
||||
```markdown
|
||||
<!-- Empty cells are OK, but those surrounding them may not be. -->
|
||||
|
||||
| | Alpha | Bravo|
|
||||
| ------ | ----- | ---: |
|
||||
| Charlie| | Echo|
|
||||
```
|
||||
|
||||
###### Out
|
||||
|
||||
```text
|
||||
3:25: Cell should be padded
|
||||
5:10: Cell should be padded
|
||||
5:25: Cell should be padded
|
||||
```
|
||||
|
||||
##### `missing-body.md`
|
||||
|
||||
When configured with `'padded'`.
|
||||
|
||||
###### In
|
||||
|
||||
> 👉 **Note**: this example uses GFM ([`remark-gfm`][gfm]).
|
||||
|
||||
```markdown
|
||||
<!-- Missing cells are fine as well. -->
|
||||
|
||||
| Alpha | Bravo | Charlie |
|
||||
| ----- | ------- | ------- |
|
||||
| Delta |
|
||||
| Echo | Foxtrot |
|
||||
```
|
||||
|
||||
###### Out
|
||||
|
||||
No messages.
|
||||
|
||||
## Compatibility
|
||||
|
||||
Projects maintained by the unified collective are compatible with all maintained
|
||||
|
@ -76,22 +76,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintTablePipeAlignment from 'remark-lint-table-pipe-alignment'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintTablePipeAlignment)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintTablePipeAlignment)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -78,22 +78,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintTablePipes from 'remark-lint-table-pipes'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintTablePipes)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintTablePipes)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -75,22 +75,20 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLint from 'remark-lint'
|
||||
import remarkLintUnorderedListMarkerStyle from 'remark-lint-unordered-list-marker-style'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintUnorderedListMarkerStyle)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintUnorderedListMarkerStyle)
|
||||
.process(file)
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
@ -174,23 +172,6 @@ Ordered lists are not affected.
|
||||
|
||||
No messages.
|
||||
|
||||
##### `not-ok.md`
|
||||
|
||||
###### In
|
||||
|
||||
```markdown
|
||||
* Foo
|
||||
- Bar
|
||||
+ Baz
|
||||
```
|
||||
|
||||
###### Out
|
||||
|
||||
```text
|
||||
2:1-2:6: Marker style should be `*`
|
||||
3:1-3:6: Marker style should be `*`
|
||||
```
|
||||
|
||||
##### `ok.md`
|
||||
|
||||
When configured with `'*'`.
|
||||
@ -235,6 +216,23 @@ No messages.
|
||||
|
||||
##### `not-ok.md`
|
||||
|
||||
###### In
|
||||
|
||||
```markdown
|
||||
* Foo
|
||||
- Bar
|
||||
+ Baz
|
||||
```
|
||||
|
||||
###### Out
|
||||
|
||||
```text
|
||||
2:1-2:6: Marker style should be `*`
|
||||
3:1-3:6: Marker style should be `*`
|
||||
```
|
||||
|
||||
##### `not-ok.md`
|
||||
|
||||
When configured with `'💩'`.
|
||||
|
||||
###### Out
|
||||
|
@ -82,20 +82,18 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkPresetLintConsistent from 'remark-preset-lint-consistent'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkPresetLintConsistent)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkPresetLintConsistent)
|
||||
.process(await read('example.md'))
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -203,20 +203,18 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkPresetLintMarkdownStyleGuide from 'remark-preset-lint-markdown-style-guide'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkPresetLintMarkdownStyleGuide)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkPresetLintMarkdownStyleGuide)
|
||||
.process(await read('example.md'))
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
@ -84,20 +84,18 @@ In browsers with [`esm.sh`][esmsh]:
|
||||
On the API:
|
||||
|
||||
```js
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkPresetLintRecommended from 'remark-preset-lint-recommended'
|
||||
import {read} from 'to-vfile'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await read('example.md')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkPresetLintRecommended)
|
||||
.process(await read('example.md'))
|
||||
await remark()
|
||||
.use(remarkPresetLintRecommended)
|
||||
.process(await read('example.md'))
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
On the CLI:
|
||||
|
54
readme.md
54
readme.md
@ -369,28 +369,24 @@ npm install vfile-reporter remark remark-preset-lint-consistent remark-preset-li
|
||||
Then create a module `example.js` that contains:
|
||||
|
||||
```js
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLintListItemIndent from 'remark-lint-list-item-indent'
|
||||
import remarkPresetLintConsistent from 'remark-preset-lint-consistent'
|
||||
import remarkPresetLintRecommended from 'remark-preset-lint-recommended'
|
||||
import remarkLintListItemIndent from 'remark-lint-list-item-indent'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await remark()
|
||||
// Check that markdown is consistent.
|
||||
.use(remarkPresetLintConsistent)
|
||||
// Few recommended rules.
|
||||
.use(remarkPresetLintRecommended)
|
||||
// `remark-lint-list-item-indent` is configured with `tab-size` in the
|
||||
// recommended preset, but if we’d prefer something else, it can be
|
||||
// reconfigured:
|
||||
.use(remarkLintListItemIndent, 'space')
|
||||
.process('1) Hello, _Jupiter_ and *Neptune*!')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
// Check that markdown is consistent.
|
||||
.use(remarkPresetLintConsistent)
|
||||
// Few recommended rules.
|
||||
.use(remarkPresetLintRecommended)
|
||||
// `remark-lint-list-item-indent` is configured with `tab-size` in the
|
||||
// recommended preset, but if we’d prefer something else, it can be
|
||||
// reconfigured:
|
||||
.use(remarkLintListItemIndent, 'space')
|
||||
.process('1) Hello, _Jupiter_ and *Neptune*!')
|
||||
|
||||
console.error(reporter(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
```
|
||||
|
||||
Running that with `node example.js` yields:
|
||||
@ -411,25 +407,21 @@ When you configure lint rules and use remark to format markdown, you must
|
||||
manually synchronize their configuration:
|
||||
|
||||
```js
|
||||
import {reporter} from 'vfile-reporter'
|
||||
import {remark} from 'remark'
|
||||
import remarkLintEmphasisMarker from 'remark-lint-emphasis-marker'
|
||||
import remarkLintStrongMarker from 'remark-lint-strong-marker'
|
||||
import {reporter} from 'vfile-reporter'
|
||||
|
||||
main()
|
||||
const file = await remark()
|
||||
.use(remarkLintEmphasisMarker, '*')
|
||||
.use(remarkLintStrongMarker, '*')
|
||||
.use({
|
||||
settings: {emphasis: '*', strong: '*'} // `remark-stringify` settings.
|
||||
})
|
||||
.process('_Hello_, __world__!')
|
||||
|
||||
async function main() {
|
||||
const file = await remark()
|
||||
.use(remarkLintEmphasisMarker, '*')
|
||||
.use(remarkLintStrongMarker, '*')
|
||||
.use({
|
||||
settings: {emphasis: '*', strong: '*'} // `remark-stringify` settings.
|
||||
})
|
||||
.process('_Hello_, __world__!')
|
||||
|
||||
console.error(reporter(file))
|
||||
console.log(String(file))
|
||||
}
|
||||
console.error(reporter(file))
|
||||
console.log(String(file))
|
||||
```
|
||||
|
||||
Yields:
|
||||
|
919
script/build-plugins.js
Normal file
919
script/build-plugins.js
Normal file
@ -0,0 +1,919 @@
|
||||
/**
|
||||
* @typedef {import('mdast').TableContent} TableContent
|
||||
* @typedef {import('mdast').TopLevelContent} TopLevelContent
|
||||
*
|
||||
* @typedef {import('type-fest').PackageJson} PackageJson
|
||||
*/
|
||||
|
||||
import assert from 'node:assert/strict'
|
||||
import fs from 'node:fs/promises'
|
||||
import {inspect} from 'node:util'
|
||||
import {slug as githubSlug} from 'github-slugger'
|
||||
import {findAndReplace} from 'mdast-util-find-and-replace'
|
||||
import {fromMarkdown} from 'mdast-util-from-markdown'
|
||||
import {gfmToMarkdown} from 'mdast-util-gfm'
|
||||
import {toMarkdown} from 'mdast-util-to-markdown'
|
||||
import {toString} from 'mdast-util-to-string'
|
||||
import parseAuthor from 'parse-author'
|
||||
import {packagesUrl, plugins, presets} from './info.js'
|
||||
import {characters} from './characters.js'
|
||||
|
||||
/** @type {PackageJson} */
|
||||
const pack = JSON.parse(await fs.readFile('package.json', 'utf8'))
|
||||
assert(pack.repository && typeof pack.repository === 'object')
|
||||
const remote = pack.repository.url
|
||||
|
||||
let index = -1
|
||||
|
||||
while (++index < plugins.length) {
|
||||
const info = plugins[index]
|
||||
const packageUrl = new URL(info.name + '/', packagesUrl)
|
||||
/** @type {PackageJson} */
|
||||
const pack = JSON.parse(
|
||||
await fs.readFile(new URL('package.json', packageUrl), 'utf8')
|
||||
)
|
||||
const version = (pack.version || '0').split('.')[0]
|
||||
const author =
|
||||
typeof pack.author === 'string' ? parseAuthor(pack.author) : pack.author
|
||||
const camelcased = info.name.replace(
|
||||
/-(\w)/g,
|
||||
function (_, /** @type {string} */ $1) {
|
||||
return $1.toUpperCase()
|
||||
}
|
||||
)
|
||||
const org = remote.split('/').slice(0, -1).join('/')
|
||||
const main = remote + '/blob/main'
|
||||
const health = org + '/.github'
|
||||
const hMain = health + '/blob/main'
|
||||
const slug = remote.split('/').slice(-2).join('/')
|
||||
let hasGfm = false
|
||||
const descriptionTree = fromMarkdown(info.description)
|
||||
const summaryTree = fromMarkdown(info.summary || '')
|
||||
|
||||
// Autolink `remark-lint`
|
||||
findAndReplace(summaryTree, [
|
||||
/remark-lint/g,
|
||||
function () {
|
||||
return {
|
||||
type: 'linkReference',
|
||||
identifier: 'mono',
|
||||
referenceType: 'full',
|
||||
children: [{type: 'inlineCode', value: 'remark-lint'}]
|
||||
}
|
||||
}
|
||||
])
|
||||
|
||||
const descriptionContent = /** @type {Array<TopLevelContent>} */ (
|
||||
descriptionTree.children
|
||||
)
|
||||
const summaryContent = /** @type {Array<TopLevelContent>} */ (
|
||||
summaryTree.children
|
||||
)
|
||||
|
||||
assert.equal(info.name, pack.name, 'expected correct package name')
|
||||
|
||||
/** @type {Record<string, Array<TopLevelContent>>} */
|
||||
const categories = {}
|
||||
let category = 'Intro'
|
||||
let contentIndex = -1
|
||||
|
||||
while (++contentIndex < descriptionContent.length) {
|
||||
const node = descriptionContent[contentIndex]
|
||||
|
||||
if (node.type === 'heading' && node.depth === 2) {
|
||||
category = githubSlug(toString(node))
|
||||
}
|
||||
|
||||
if (!(category in categories)) {
|
||||
categories[category] = []
|
||||
}
|
||||
|
||||
categories[category].push(node)
|
||||
}
|
||||
|
||||
const includes = presets.filter(function (preset) {
|
||||
return preset.plugins.find(function (d) {
|
||||
return d[0] === info.name
|
||||
})
|
||||
})
|
||||
|
||||
/** @type {Array<TopLevelContent>} */
|
||||
const children = [
|
||||
{type: 'html', value: '<!--This file is generated-->'},
|
||||
{
|
||||
type: 'heading',
|
||||
depth: 1,
|
||||
children: [{type: 'text', value: info.name}]
|
||||
}
|
||||
]
|
||||
|
||||
if (info.deprecated) {
|
||||
children.push(...descriptionContent)
|
||||
} else {
|
||||
children.push(
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
type: 'linkReference',
|
||||
identifier: 'build',
|
||||
referenceType: 'full',
|
||||
children: [
|
||||
{
|
||||
type: 'imageReference',
|
||||
identifier: 'build-badge',
|
||||
referenceType: 'full',
|
||||
alt: 'Build'
|
||||
}
|
||||
]
|
||||
},
|
||||
{type: 'text', value: '\n'},
|
||||
{
|
||||
type: 'linkReference',
|
||||
identifier: 'coverage',
|
||||
referenceType: 'full',
|
||||
children: [
|
||||
{
|
||||
type: 'imageReference',
|
||||
identifier: 'coverage-badge',
|
||||
referenceType: 'full',
|
||||
alt: 'Coverage'
|
||||
}
|
||||
]
|
||||
},
|
||||
{type: 'text', value: '\n'},
|
||||
{
|
||||
type: 'linkReference',
|
||||
identifier: 'downloads',
|
||||
referenceType: 'full',
|
||||
children: [
|
||||
{
|
||||
type: 'imageReference',
|
||||
identifier: 'downloads-badge',
|
||||
referenceType: 'full',
|
||||
alt: 'Downloads'
|
||||
}
|
||||
]
|
||||
},
|
||||
{type: 'text', value: '\n'},
|
||||
{
|
||||
type: 'linkReference',
|
||||
identifier: 'size',
|
||||
referenceType: 'full',
|
||||
children: [
|
||||
{
|
||||
type: 'imageReference',
|
||||
identifier: 'size-badge',
|
||||
referenceType: 'full',
|
||||
alt: 'Size'
|
||||
}
|
||||
]
|
||||
},
|
||||
{type: 'text', value: '\n'},
|
||||
{
|
||||
type: 'linkReference',
|
||||
identifier: 'collective',
|
||||
referenceType: 'full',
|
||||
children: [
|
||||
{
|
||||
type: 'imageReference',
|
||||
identifier: 'sponsors-badge',
|
||||
referenceType: 'full',
|
||||
alt: 'Sponsors'
|
||||
}
|
||||
]
|
||||
},
|
||||
{type: 'text', value: '\n'},
|
||||
{
|
||||
type: 'linkReference',
|
||||
identifier: 'collective',
|
||||
referenceType: 'full',
|
||||
children: [
|
||||
{
|
||||
type: 'imageReference',
|
||||
identifier: 'backers-badge',
|
||||
referenceType: 'full',
|
||||
alt: 'Backers'
|
||||
}
|
||||
]
|
||||
},
|
||||
{type: 'text', value: '\n'},
|
||||
{
|
||||
type: 'linkReference',
|
||||
identifier: 'chat',
|
||||
referenceType: 'full',
|
||||
children: [
|
||||
{
|
||||
type: 'imageReference',
|
||||
identifier: 'chat-badge',
|
||||
referenceType: 'full',
|
||||
alt: 'Chat'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
...summaryContent,
|
||||
{
|
||||
type: 'heading',
|
||||
depth: 2,
|
||||
children: [{type: 'text', value: 'Contents'}]
|
||||
},
|
||||
{
|
||||
type: 'heading',
|
||||
depth: 2,
|
||||
children: [{type: 'text', value: 'What is this?'}]
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{type: 'text', value: 'This package is a '},
|
||||
{
|
||||
type: 'linkReference',
|
||||
identifier: 'unified',
|
||||
referenceType: 'collapsed',
|
||||
children: [{type: 'text', value: 'unified'}]
|
||||
},
|
||||
{type: 'text', value: ' ('},
|
||||
{
|
||||
type: 'linkReference',
|
||||
identifier: 'remark',
|
||||
referenceType: 'collapsed',
|
||||
children: [{type: 'text', value: 'remark'}]
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
value: ') plugin, specifically a '
|
||||
},
|
||||
{
|
||||
type: 'inlineCode',
|
||||
value: 'remark-lint'
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
value: '\nrule.\nLint rules check markdown code style.'
|
||||
}
|
||||
]
|
||||
},
|
||||
...(categories['when-should-i-use-this'] || []),
|
||||
{
|
||||
type: 'heading',
|
||||
depth: 2,
|
||||
children: [{type: 'text', value: 'Presets'}]
|
||||
}
|
||||
)
|
||||
|
||||
if (includes.length === 0) {
|
||||
children.push({
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
type: 'text',
|
||||
value: 'This rule is not included in a preset maintained here.'
|
||||
}
|
||||
]
|
||||
})
|
||||
} else {
|
||||
children.push(
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
type: 'text',
|
||||
value: 'This rule is included in the following presets:'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'table',
|
||||
align: [],
|
||||
children: [
|
||||
{
|
||||
type: 'tableRow',
|
||||
children: [
|
||||
{
|
||||
type: 'tableCell',
|
||||
children: [{type: 'text', value: 'Preset'}]
|
||||
},
|
||||
{
|
||||
type: 'tableCell',
|
||||
children: [{type: 'text', value: 'Setting'}]
|
||||
}
|
||||
]
|
||||
},
|
||||
...includes.map(function (preset) {
|
||||
const tuple = preset.plugins.find(function (d) {
|
||||
return d[0] === info.name
|
||||
})
|
||||
assert(tuple)
|
||||
const option = tuple[1]
|
||||
|
||||
/** @type {TableContent} */
|
||||
const row = {
|
||||
type: 'tableRow',
|
||||
children: [
|
||||
{
|
||||
type: 'tableCell',
|
||||
children: [
|
||||
{
|
||||
type: 'link',
|
||||
url: remote + '/tree/main/packages/' + preset.name,
|
||||
children: [{type: 'inlineCode', value: preset.name}]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'tableCell',
|
||||
children: option
|
||||
? [{type: 'inlineCode', value: inspect(option)}]
|
||||
: []
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
return row
|
||||
})
|
||||
]
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
children.push(
|
||||
{
|
||||
type: 'heading',
|
||||
depth: 2,
|
||||
children: [{type: 'text', value: 'Install'}]
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{type: 'text', value: 'This package is '},
|
||||
{
|
||||
type: 'linkReference',
|
||||
identifier: 'esm',
|
||||
referenceType: 'full',
|
||||
children: [{type: 'text', value: 'ESM only'}]
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
value:
|
||||
'.\nIn Node.js (version 12.20+, 14.14+, or 16.0+), ' +
|
||||
'install with '
|
||||
},
|
||||
{
|
||||
type: 'linkReference',
|
||||
identifier: 'npm',
|
||||
referenceType: 'collapsed',
|
||||
children: [{type: 'text', value: 'npm'}]
|
||||
},
|
||||
{type: 'text', value: ':'}
|
||||
]
|
||||
},
|
||||
{type: 'code', lang: 'sh', value: 'npm install ' + info.name},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{type: 'text', value: 'In Deno with '},
|
||||
{
|
||||
type: 'linkReference',
|
||||
identifier: 'esmsh',
|
||||
label: 'esmsh',
|
||||
referenceType: 'full',
|
||||
children: [{type: 'inlineCode', value: 'esm.sh'}]
|
||||
},
|
||||
{type: 'text', value: ':'}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'code',
|
||||
lang: 'js',
|
||||
value:
|
||||
'import ' +
|
||||
camelcased +
|
||||
" from 'https://esm.sh/" +
|
||||
info.name +
|
||||
'@' +
|
||||
version +
|
||||
"'"
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{type: 'text', value: 'In browsers with '},
|
||||
{
|
||||
type: 'linkReference',
|
||||
identifier: 'esmsh',
|
||||
label: 'esmsh',
|
||||
referenceType: 'full',
|
||||
children: [{type: 'inlineCode', value: 'esm.sh'}]
|
||||
},
|
||||
{type: 'text', value: ':'}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'code',
|
||||
lang: 'html',
|
||||
value:
|
||||
'<script type="module">\n import ' +
|
||||
camelcased +
|
||||
" from 'https://esm.sh/" +
|
||||
info.name +
|
||||
'@' +
|
||||
version +
|
||||
"?bundle'\n</script>"
|
||||
},
|
||||
{
|
||||
type: 'heading',
|
||||
depth: 2,
|
||||
children: [{type: 'text', value: 'Use'}]
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{type: 'text', value: 'On the API:'}]
|
||||
},
|
||||
{
|
||||
type: 'code',
|
||||
lang: 'js',
|
||||
value: [
|
||||
"import {remark} from 'remark'",
|
||||
"import remarkLint from 'remark-lint'",
|
||||
'import ' + camelcased + " from '" + info.name + "'",
|
||||
"import {read} from 'to-vfile'",
|
||||
"import {reporter} from 'vfile-reporter'",
|
||||
'',
|
||||
"const file = await read('example.md')",
|
||||
'',
|
||||
'await remark()',
|
||||
' .use(remarkLint)',
|
||||
' .use(' + camelcased + ')',
|
||||
' .process(file)',
|
||||
'',
|
||||
'console.error(reporter(file))'
|
||||
].join('\n')
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{type: 'text', value: 'On the CLI:'}]
|
||||
},
|
||||
{
|
||||
type: 'code',
|
||||
lang: 'sh',
|
||||
value: 'remark --use remark-lint --use ' + info.name + ' example.md'
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
type: 'text',
|
||||
value: 'On the CLI in a config file (here a '
|
||||
},
|
||||
{
|
||||
type: 'inlineCode',
|
||||
value: 'package.json'
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
value: '):'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'code',
|
||||
lang: 'diff',
|
||||
value: [
|
||||
' …',
|
||||
' "remarkConfig": {',
|
||||
' "plugins": [',
|
||||
' …',
|
||||
' "remark-lint",',
|
||||
'+ "' + info.name + '",',
|
||||
' …',
|
||||
' ]',
|
||||
' }',
|
||||
' …'
|
||||
].join('\n')
|
||||
}
|
||||
)
|
||||
|
||||
if ('api' in categories) {
|
||||
const [apiHeading, ...apiBody] = categories.api
|
||||
|
||||
children.push(
|
||||
apiHeading,
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
type: 'text',
|
||||
value:
|
||||
'This package exports no identifiers.\nThe default export is '
|
||||
},
|
||||
{type: 'inlineCode', value: camelcased},
|
||||
{type: 'text', value: '.'}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'heading',
|
||||
depth: 3,
|
||||
children: [
|
||||
{
|
||||
type: 'inlineCode',
|
||||
value: 'unified().use(' + camelcased + '[, config])'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
type: 'text',
|
||||
value:
|
||||
'This rule supports standard configuration that all remark lint rules accept\n(such as '
|
||||
},
|
||||
{type: 'inlineCode', value: 'false'},
|
||||
{type: 'text', value: ' to turn it off or '},
|
||||
{type: 'inlineCode', value: '[1, options]'},
|
||||
{type: 'text', value: ' to configure it).'}
|
||||
]
|
||||
},
|
||||
...apiBody
|
||||
)
|
||||
}
|
||||
|
||||
children.push(
|
||||
...(categories.recommendation || []),
|
||||
...(categories.fix || []),
|
||||
...(categories.example || [])
|
||||
)
|
||||
|
||||
let first = true
|
||||
|
||||
for (const check of info.checks) {
|
||||
if (first) {
|
||||
children.push({
|
||||
type: 'heading',
|
||||
depth: 2,
|
||||
children: [{type: 'text', value: 'Examples'}]
|
||||
})
|
||||
first = false
|
||||
}
|
||||
|
||||
/** @type {{config: unknown}} */
|
||||
const {config} = JSON.parse(check.configuration)
|
||||
let clean = check.input
|
||||
|
||||
children.push({
|
||||
type: 'heading',
|
||||
depth: 5,
|
||||
children: [{type: 'inlineCode', value: check.name}]
|
||||
})
|
||||
|
||||
if (config !== true) {
|
||||
children.push({
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{type: 'text', value: 'When configured with '},
|
||||
{type: 'inlineCode', value: inspect(config)},
|
||||
{type: 'text', value: '.'}
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
if (check.input.trim() !== '') {
|
||||
children.push({
|
||||
type: 'heading',
|
||||
depth: 6,
|
||||
children: [{type: 'text', value: 'In'}]
|
||||
})
|
||||
|
||||
if (check.gfm) {
|
||||
hasGfm = true
|
||||
children.push({
|
||||
type: 'blockquote',
|
||||
children: [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{type: 'text', value: '👉 '},
|
||||
{
|
||||
type: 'strong',
|
||||
children: [{type: 'text', value: 'Note'}]
|
||||
},
|
||||
{type: 'text', value: ': this example uses GFM ('},
|
||||
{
|
||||
type: 'linkReference',
|
||||
identifier: 'gfm',
|
||||
referenceType: 'full',
|
||||
children: [{type: 'inlineCode', value: 'remark-gfm'}]
|
||||
},
|
||||
{type: 'text', value: ').'}
|
||||
]
|
||||
}
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
let index = -1
|
||||
while (++index < characters.length) {
|
||||
const char = characters[index]
|
||||
const next = clean.replace(char.in, char.out)
|
||||
|
||||
if (clean !== next) {
|
||||
children.push({
|
||||
type: 'blockquote',
|
||||
children: [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{type: 'text', value: '👉 '},
|
||||
{
|
||||
type: 'strong',
|
||||
children: [{type: 'text', value: 'Note'}]
|
||||
},
|
||||
{type: 'text', value: ': '},
|
||||
{type: 'inlineCode', value: char.char},
|
||||
{
|
||||
type: 'text',
|
||||
value: ' represents ' + char.name + '.'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
clean = next
|
||||
}
|
||||
}
|
||||
|
||||
children.push({
|
||||
type: 'code',
|
||||
lang: 'markdown',
|
||||
value: check.input
|
||||
})
|
||||
}
|
||||
|
||||
children.push({
|
||||
type: 'heading',
|
||||
depth: 6,
|
||||
children: [{type: 'text', value: 'Out'}]
|
||||
})
|
||||
|
||||
if (check.output.length === 0) {
|
||||
children.push({
|
||||
type: 'paragraph',
|
||||
children: [{type: 'text', value: 'No messages.'}]
|
||||
})
|
||||
} else {
|
||||
children.push({
|
||||
type: 'code',
|
||||
lang: 'text',
|
||||
value: check.output.join('\n')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
children.push(
|
||||
{
|
||||
type: 'heading',
|
||||
depth: 2,
|
||||
children: [{type: 'text', value: 'Compatibility'}]
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
type: 'text',
|
||||
value:
|
||||
'Projects maintained by the unified collective are compatible with all maintained\nversions of Node.js.\nAs of now, that is Node.js 12.20+, 14.14+, and 16.0+.\nOur projects sometimes work with older versions, but this is not guaranteed.'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'heading',
|
||||
depth: 2,
|
||||
children: [{type: 'text', value: 'Contribute'}]
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{type: 'text', value: 'See '},
|
||||
{
|
||||
type: 'linkReference',
|
||||
referenceType: 'collapsed',
|
||||
identifier: 'contributing',
|
||||
children: [{type: 'inlineCode', value: 'contributing.md'}]
|
||||
},
|
||||
{type: 'text', value: ' in '},
|
||||
{
|
||||
type: 'linkReference',
|
||||
referenceType: 'collapsed',
|
||||
identifier: 'health',
|
||||
children: [
|
||||
{
|
||||
type: 'inlineCode',
|
||||
value: health.split('/').slice(-2).join('/')
|
||||
}
|
||||
]
|
||||
},
|
||||
{type: 'text', value: ' for ways\nto get started.\nSee '},
|
||||
{
|
||||
type: 'linkReference',
|
||||
referenceType: 'collapsed',
|
||||
identifier: 'support',
|
||||
children: [{type: 'inlineCode', value: 'support.md'}]
|
||||
},
|
||||
{type: 'text', value: ' for ways to get help.'}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{type: 'text', value: 'This project has a '},
|
||||
{
|
||||
type: 'linkReference',
|
||||
referenceType: 'collapsed',
|
||||
identifier: 'coc',
|
||||
children: [{type: 'text', value: 'code of conduct'}]
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
value:
|
||||
'.\nBy interacting with this repository, organization, or community you agree to\nabide by its terms.'
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
children.push(
|
||||
{type: 'heading', depth: 2, children: [{type: 'text', value: 'License'}]},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
type: 'linkReference',
|
||||
referenceType: 'collapsed',
|
||||
identifier: 'license',
|
||||
children: [{type: 'text', value: String(pack.license || '')}]
|
||||
},
|
||||
{type: 'text', value: ' © '},
|
||||
{
|
||||
type: 'linkReference',
|
||||
referenceType: 'collapsed',
|
||||
identifier: 'author',
|
||||
children: [
|
||||
{type: 'text', value: String((author && author.name) || '')}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
|
||||
if (!info.deprecated) {
|
||||
children.push(
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'build-badge',
|
||||
url: 'https://github.com/' + slug + '/workflows/main/badge.svg'
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'build',
|
||||
url: 'https://github.com/' + slug + '/actions'
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'coverage-badge',
|
||||
url: 'https://img.shields.io/codecov/c/github/' + slug + '.svg'
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'coverage',
|
||||
url: 'https://codecov.io/github/' + slug
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'downloads-badge',
|
||||
url: 'https://img.shields.io/npm/dm/' + info.name + '.svg'
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'downloads',
|
||||
url: 'https://www.npmjs.com/package/' + info.name
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'size-badge',
|
||||
url: 'https://img.shields.io/bundlephobia/minzip/' + info.name + '.svg'
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'size',
|
||||
url: 'https://bundlephobia.com/result?p=' + info.name
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'sponsors-badge',
|
||||
url: 'https://opencollective.com/unified/sponsors/badge.svg'
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'backers-badge',
|
||||
url: 'https://opencollective.com/unified/backers/badge.svg'
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'collective',
|
||||
url: 'https://opencollective.com/unified'
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'chat-badge',
|
||||
url: 'https://img.shields.io/badge/chat-discussions-success.svg'
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'chat',
|
||||
url: 'https://github.com/remarkjs/remark/discussions'
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'unified',
|
||||
url: 'https://github.com/unifiedjs/unified'
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'remark',
|
||||
url: 'https://github.com/remarkjs/remark'
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'mono',
|
||||
url: 'https://github.com/' + slug
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'esm',
|
||||
url: 'https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c'
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'esmsh',
|
||||
url: 'https://esm.sh'
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'npm',
|
||||
url: 'https://docs.npmjs.com/cli/install'
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'health',
|
||||
url: health
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'contributing',
|
||||
url: hMain + '/contributing.md'
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'support',
|
||||
url: hMain + '/support.md'
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'coc',
|
||||
url: hMain + '/code-of-conduct.md'
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
children.push(
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'license',
|
||||
url: main + '/license'
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'author',
|
||||
url: String((author && author.url) || '')
|
||||
}
|
||||
)
|
||||
|
||||
if (hasGfm) {
|
||||
children.push({
|
||||
type: 'definition',
|
||||
identifier: 'gfm',
|
||||
url: 'https://github.com/remarkjs/remark-gfm'
|
||||
})
|
||||
}
|
||||
|
||||
await fs.writeFile(
|
||||
new URL('readme.md', packageUrl),
|
||||
toMarkdown({type: 'root', children}, {extensions: [gfmToMarkdown()]})
|
||||
)
|
||||
|
||||
console.log('✓ wrote `readme.md` in `' + info.name + '`')
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,967 +0,0 @@
|
||||
/**
|
||||
* @typedef {import('mdast').BlockContent} BlockContent
|
||||
* @typedef {import('mdast').DefinitionContent} DefinitionContent
|
||||
* @typedef {import('mdast').TableContent} TableContent
|
||||
* @typedef {import('type-fest').PackageJson} PackageJson
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {BlockContent | DefinitionContent} BlockAndDefinitionContent
|
||||
*/
|
||||
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import process from 'node:process'
|
||||
import {inspect} from 'node:util'
|
||||
import {unified} from 'unified'
|
||||
import {remark} from 'remark'
|
||||
import remarkParse from 'remark-parse'
|
||||
import remarkGfm from 'remark-gfm'
|
||||
import {findAndReplace} from 'mdast-util-find-and-replace'
|
||||
import {toString} from 'mdast-util-to-string'
|
||||
import {slug as githubSlug} from 'github-slugger'
|
||||
import parseAuthor from 'parse-author'
|
||||
import {rules} from './util/rules.js'
|
||||
import {rule} from './util/rule.js'
|
||||
import {presets} from './util/presets.js'
|
||||
import {repoUrl} from './util/repo-url.js'
|
||||
import {characters} from './characters.js'
|
||||
|
||||
const own = {}.hasOwnProperty
|
||||
|
||||
const remote = repoUrl('package.json')
|
||||
|
||||
const root = path.join(process.cwd(), 'packages')
|
||||
|
||||
// eslint-disable-next-line complexity, unicorn/prefer-top-level-await
|
||||
presets(root).then((presetObjects) => {
|
||||
const allRules = rules(root)
|
||||
let index = -1
|
||||
|
||||
while (++index < allRules.length) {
|
||||
const basename = allRules[index]
|
||||
const base = path.resolve(root, basename)
|
||||
/** @type {PackageJson} */
|
||||
const pack = JSON.parse(
|
||||
String(fs.readFileSync(path.join(base, 'package.json')))
|
||||
)
|
||||
const version = (pack.version || '0').split('.')[0]
|
||||
const info = rule(base)
|
||||
const tests = info.tests
|
||||
const author =
|
||||
typeof pack.author === 'string' ? parseAuthor(pack.author) : pack.author
|
||||
const camelcased = basename.replace(
|
||||
/-(\w)/g,
|
||||
(_, /** @type {string} */ $1) => $1.toUpperCase()
|
||||
)
|
||||
const org = remote.split('/').slice(0, -1).join('/')
|
||||
const main = remote + '/blob/main'
|
||||
const health = org + '/.github'
|
||||
const hMain = health + '/blob/main'
|
||||
const slug = remote.split('/').slice(-2).join('/')
|
||||
let hasGfm = false
|
||||
|
||||
const descriptionTree = unified().use(remarkParse).parse(info.description)
|
||||
const summaryTree = unified()
|
||||
.use(remarkParse)
|
||||
.parse(info.summary || '')
|
||||
|
||||
// Autolink `remark-lint`
|
||||
unified()
|
||||
.use(
|
||||
/** @type {import('unified').Plugin<Array<void>, import('mdast').Root>} */
|
||||
() => (tree) => {
|
||||
findAndReplace(tree, [
|
||||
/remark-lint/g,
|
||||
() => {
|
||||
return {
|
||||
type: 'linkReference',
|
||||
identifier: 'mono',
|
||||
referenceType: 'full',
|
||||
children: [{type: 'inlineCode', value: 'remark-lint'}]
|
||||
}
|
||||
}
|
||||
])
|
||||
}
|
||||
)
|
||||
.runSync(summaryTree)
|
||||
|
||||
const descriptionContent = /** @type {Array<BlockAndDefinitionContent>} */ (
|
||||
descriptionTree.children
|
||||
)
|
||||
const summaryContent = /** @type {Array<BlockAndDefinitionContent>} */ (
|
||||
summaryTree.children
|
||||
)
|
||||
|
||||
if (basename !== pack.name) {
|
||||
throw new Error(
|
||||
'Expected package name (`' +
|
||||
pack.name +
|
||||
'`) to be the same as directory name (`' +
|
||||
basename +
|
||||
'`)'
|
||||
)
|
||||
}
|
||||
|
||||
/** @type {Record<string, Array<BlockAndDefinitionContent>>} */
|
||||
const categories = {}
|
||||
let category = 'Intro'
|
||||
let contentIndex = -1
|
||||
|
||||
while (++contentIndex < descriptionContent.length) {
|
||||
const node = descriptionContent[contentIndex]
|
||||
if (node.type === 'heading' && node.depth === 2) {
|
||||
category = githubSlug(toString(node))
|
||||
}
|
||||
|
||||
if (!(category in categories)) {
|
||||
categories[category] = []
|
||||
}
|
||||
|
||||
categories[category].push(node)
|
||||
}
|
||||
|
||||
const includes = presetObjects.filter(
|
||||
(preset) => basename in preset.packages
|
||||
)
|
||||
|
||||
/** @type {Array<BlockAndDefinitionContent>} */
|
||||
const children = [
|
||||
{type: 'html', value: '<!--This file is generated-->'},
|
||||
{
|
||||
type: 'heading',
|
||||
depth: 1,
|
||||
children: [{type: 'text', value: basename}]
|
||||
}
|
||||
]
|
||||
|
||||
if (info.deprecated) {
|
||||
children.push(...descriptionContent)
|
||||
} else {
|
||||
children.push(
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
type: 'linkReference',
|
||||
identifier: 'build',
|
||||
referenceType: 'full',
|
||||
children: [
|
||||
{
|
||||
type: 'imageReference',
|
||||
identifier: 'build-badge',
|
||||
referenceType: 'full',
|
||||
alt: 'Build'
|
||||
}
|
||||
]
|
||||
},
|
||||
{type: 'text', value: '\n'},
|
||||
{
|
||||
type: 'linkReference',
|
||||
identifier: 'coverage',
|
||||
referenceType: 'full',
|
||||
children: [
|
||||
{
|
||||
type: 'imageReference',
|
||||
identifier: 'coverage-badge',
|
||||
referenceType: 'full',
|
||||
alt: 'Coverage'
|
||||
}
|
||||
]
|
||||
},
|
||||
{type: 'text', value: '\n'},
|
||||
{
|
||||
type: 'linkReference',
|
||||
identifier: 'downloads',
|
||||
referenceType: 'full',
|
||||
children: [
|
||||
{
|
||||
type: 'imageReference',
|
||||
identifier: 'downloads-badge',
|
||||
referenceType: 'full',
|
||||
alt: 'Downloads'
|
||||
}
|
||||
]
|
||||
},
|
||||
{type: 'text', value: '\n'},
|
||||
{
|
||||
type: 'linkReference',
|
||||
identifier: 'size',
|
||||
referenceType: 'full',
|
||||
children: [
|
||||
{
|
||||
type: 'imageReference',
|
||||
identifier: 'size-badge',
|
||||
referenceType: 'full',
|
||||
alt: 'Size'
|
||||
}
|
||||
]
|
||||
},
|
||||
{type: 'text', value: '\n'},
|
||||
{
|
||||
type: 'linkReference',
|
||||
identifier: 'collective',
|
||||
referenceType: 'full',
|
||||
children: [
|
||||
{
|
||||
type: 'imageReference',
|
||||
identifier: 'sponsors-badge',
|
||||
referenceType: 'full',
|
||||
alt: 'Sponsors'
|
||||
}
|
||||
]
|
||||
},
|
||||
{type: 'text', value: '\n'},
|
||||
{
|
||||
type: 'linkReference',
|
||||
identifier: 'collective',
|
||||
referenceType: 'full',
|
||||
children: [
|
||||
{
|
||||
type: 'imageReference',
|
||||
identifier: 'backers-badge',
|
||||
referenceType: 'full',
|
||||
alt: 'Backers'
|
||||
}
|
||||
]
|
||||
},
|
||||
{type: 'text', value: '\n'},
|
||||
{
|
||||
type: 'linkReference',
|
||||
identifier: 'chat',
|
||||
referenceType: 'full',
|
||||
children: [
|
||||
{
|
||||
type: 'imageReference',
|
||||
identifier: 'chat-badge',
|
||||
referenceType: 'full',
|
||||
alt: 'Chat'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
...summaryContent,
|
||||
{
|
||||
type: 'heading',
|
||||
depth: 2,
|
||||
children: [{type: 'text', value: 'Contents'}]
|
||||
},
|
||||
{
|
||||
type: 'heading',
|
||||
depth: 2,
|
||||
children: [{type: 'text', value: 'What is this?'}]
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{type: 'text', value: 'This package is a '},
|
||||
{
|
||||
type: 'linkReference',
|
||||
identifier: 'unified',
|
||||
referenceType: 'collapsed',
|
||||
children: [{type: 'text', value: 'unified'}]
|
||||
},
|
||||
{type: 'text', value: ' ('},
|
||||
{
|
||||
type: 'linkReference',
|
||||
identifier: 'remark',
|
||||
referenceType: 'collapsed',
|
||||
children: [{type: 'text', value: 'remark'}]
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
value: ') plugin, specifically a '
|
||||
},
|
||||
{
|
||||
type: 'inlineCode',
|
||||
value: 'remark-lint'
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
value: '\nrule.\nLint rules check markdown code style.'
|
||||
}
|
||||
]
|
||||
},
|
||||
...(categories['when-should-i-use-this'] || []),
|
||||
{
|
||||
type: 'heading',
|
||||
depth: 2,
|
||||
children: [{type: 'text', value: 'Presets'}]
|
||||
}
|
||||
)
|
||||
|
||||
if (includes.length === 0) {
|
||||
children.push({
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
type: 'text',
|
||||
value: 'This rule is not included in a preset maintained here.'
|
||||
}
|
||||
]
|
||||
})
|
||||
} else {
|
||||
children.push(
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
type: 'text',
|
||||
value: 'This rule is included in the following presets:'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'table',
|
||||
align: [],
|
||||
children: [
|
||||
{
|
||||
type: 'tableRow',
|
||||
children: [
|
||||
{
|
||||
type: 'tableCell',
|
||||
children: [{type: 'text', value: 'Preset'}]
|
||||
},
|
||||
{
|
||||
type: 'tableCell',
|
||||
children: [{type: 'text', value: 'Setting'}]
|
||||
}
|
||||
]
|
||||
},
|
||||
...includes.map((preset) => {
|
||||
const option = preset.packages[basename]
|
||||
|
||||
/** @type {TableContent} */
|
||||
const row = {
|
||||
type: 'tableRow',
|
||||
children: [
|
||||
{
|
||||
type: 'tableCell',
|
||||
children: [
|
||||
{
|
||||
type: 'link',
|
||||
url: remote + '/tree/main/packages/' + preset.name,
|
||||
title: null,
|
||||
children: [{type: 'inlineCode', value: preset.name}]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'tableCell',
|
||||
children: option
|
||||
? [{type: 'inlineCode', value: inspect(option)}]
|
||||
: []
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
return row
|
||||
})
|
||||
]
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
children.push(
|
||||
{
|
||||
type: 'heading',
|
||||
depth: 2,
|
||||
children: [{type: 'text', value: 'Install'}]
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{type: 'text', value: 'This package is '},
|
||||
{
|
||||
type: 'linkReference',
|
||||
identifier: 'esm',
|
||||
referenceType: 'full',
|
||||
children: [{type: 'text', value: 'ESM only'}]
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
value:
|
||||
'.\nIn Node.js (version 12.20+, 14.14+, or 16.0+), ' +
|
||||
'install with '
|
||||
},
|
||||
{
|
||||
type: 'linkReference',
|
||||
identifier: 'npm',
|
||||
referenceType: 'collapsed',
|
||||
children: [{type: 'text', value: 'npm'}]
|
||||
},
|
||||
{type: 'text', value: ':'}
|
||||
]
|
||||
},
|
||||
{type: 'code', lang: 'sh', value: 'npm install ' + basename},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{type: 'text', value: 'In Deno with '},
|
||||
{
|
||||
type: 'linkReference',
|
||||
identifier: 'esmsh',
|
||||
label: 'esmsh',
|
||||
referenceType: 'full',
|
||||
children: [{type: 'inlineCode', value: 'esm.sh'}]
|
||||
},
|
||||
{type: 'text', value: ':'}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'code',
|
||||
lang: 'js',
|
||||
value:
|
||||
'import ' +
|
||||
camelcased +
|
||||
" from 'https://esm.sh/" +
|
||||
basename +
|
||||
'@' +
|
||||
version +
|
||||
"'"
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{type: 'text', value: 'In browsers with '},
|
||||
{
|
||||
type: 'linkReference',
|
||||
identifier: 'esmsh',
|
||||
label: 'esmsh',
|
||||
referenceType: 'full',
|
||||
children: [{type: 'inlineCode', value: 'esm.sh'}]
|
||||
},
|
||||
{type: 'text', value: ':'}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'code',
|
||||
lang: 'html',
|
||||
value:
|
||||
'<script type="module">\n import ' +
|
||||
camelcased +
|
||||
" from 'https://esm.sh/" +
|
||||
basename +
|
||||
'@' +
|
||||
version +
|
||||
"?bundle'\n</script>"
|
||||
},
|
||||
{
|
||||
type: 'heading',
|
||||
depth: 2,
|
||||
children: [{type: 'text', value: 'Use'}]
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{type: 'text', value: 'On the API:'}]
|
||||
},
|
||||
{
|
||||
type: 'code',
|
||||
lang: 'js',
|
||||
value: [
|
||||
"import {read} from 'to-vfile'",
|
||||
"import {reporter} from 'vfile-reporter'",
|
||||
"import {remark} from 'remark'",
|
||||
"import remarkLint from 'remark-lint'",
|
||||
'import ' + camelcased + " from '" + basename + "'",
|
||||
'',
|
||||
'main()',
|
||||
'',
|
||||
'async function main() {',
|
||||
' const file = await remark()',
|
||||
' .use(remarkLint)',
|
||||
' .use(' + camelcased + ')',
|
||||
" .process(await read('example.md'))",
|
||||
'',
|
||||
' console.error(reporter(file))',
|
||||
'}'
|
||||
].join('\n')
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{type: 'text', value: 'On the CLI:'}]
|
||||
},
|
||||
{
|
||||
type: 'code',
|
||||
lang: 'sh',
|
||||
value: 'remark --use remark-lint --use ' + basename + ' example.md'
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
type: 'text',
|
||||
value: 'On the CLI in a config file (here a '
|
||||
},
|
||||
{
|
||||
type: 'inlineCode',
|
||||
value: 'package.json'
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
value: '):'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'code',
|
||||
lang: 'diff',
|
||||
value: [
|
||||
' …',
|
||||
' "remarkConfig": {',
|
||||
' "plugins": [',
|
||||
' …',
|
||||
' "remark-lint",',
|
||||
'+ "' + basename + '",',
|
||||
' …',
|
||||
' ]',
|
||||
' }',
|
||||
' …'
|
||||
].join('\n')
|
||||
}
|
||||
)
|
||||
|
||||
if ('api' in categories) {
|
||||
const [apiHeading, ...apiBody] = categories.api
|
||||
|
||||
children.push(
|
||||
apiHeading,
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
type: 'text',
|
||||
value:
|
||||
'This package exports no identifiers.\nThe default export is '
|
||||
},
|
||||
{type: 'inlineCode', value: camelcased},
|
||||
{type: 'text', value: '.'}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'heading',
|
||||
depth: 3,
|
||||
children: [
|
||||
{
|
||||
type: 'inlineCode',
|
||||
value: 'unified().use(' + camelcased + '[, config])'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
type: 'text',
|
||||
value:
|
||||
'This rule supports standard configuration that all remark lint rules accept\n(such as '
|
||||
},
|
||||
{type: 'inlineCode', value: 'false'},
|
||||
{type: 'text', value: ' to turn it off or '},
|
||||
{type: 'inlineCode', value: '[1, options]'},
|
||||
{type: 'text', value: ' to configure it).'}
|
||||
]
|
||||
},
|
||||
...apiBody
|
||||
)
|
||||
}
|
||||
|
||||
children.push(
|
||||
...(categories.recommendation || []),
|
||||
...(categories.fix || []),
|
||||
...(categories.example || [])
|
||||
)
|
||||
|
||||
let first = true
|
||||
/** @type {string} */
|
||||
let configuration
|
||||
|
||||
for (configuration in tests) {
|
||||
if (own.call(tests, configuration)) {
|
||||
const fixtures = tests[configuration]
|
||||
|
||||
if (first) {
|
||||
children.push({
|
||||
type: 'heading',
|
||||
depth: 2,
|
||||
children: [{type: 'text', value: 'Examples'}]
|
||||
})
|
||||
first = false
|
||||
}
|
||||
|
||||
/** @type {string} */
|
||||
let fileName
|
||||
|
||||
for (fileName in fixtures) {
|
||||
if (own.call(fixtures, fileName)) {
|
||||
const fixture = fixtures[fileName]
|
||||
/** @type {{config: unknown}} */
|
||||
const {config} = JSON.parse(configuration)
|
||||
let clean = fixture.input
|
||||
|
||||
children.push({
|
||||
type: 'heading',
|
||||
depth: 5,
|
||||
children: [{type: 'inlineCode', value: fileName}]
|
||||
})
|
||||
|
||||
if (config !== true) {
|
||||
children.push({
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{type: 'text', value: 'When configured with '},
|
||||
{type: 'inlineCode', value: inspect(config)},
|
||||
{type: 'text', value: '.'}
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
if (
|
||||
fixture.input !== null &&
|
||||
fixture.input !== undefined &&
|
||||
fixture.input.trim() !== ''
|
||||
) {
|
||||
children.push({
|
||||
type: 'heading',
|
||||
depth: 6,
|
||||
children: [{type: 'text', value: 'In'}]
|
||||
})
|
||||
|
||||
if (fixture.gfm) {
|
||||
hasGfm = true
|
||||
children.push({
|
||||
type: 'blockquote',
|
||||
children: [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{type: 'text', value: '👉 '},
|
||||
{
|
||||
type: 'strong',
|
||||
children: [{type: 'text', value: 'Note'}]
|
||||
},
|
||||
{type: 'text', value: ': this example uses GFM ('},
|
||||
{
|
||||
type: 'linkReference',
|
||||
identifier: 'gfm',
|
||||
referenceType: 'full',
|
||||
children: [
|
||||
{type: 'inlineCode', value: 'remark-gfm'}
|
||||
]
|
||||
},
|
||||
{type: 'text', value: ').'}
|
||||
]
|
||||
}
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
let index = -1
|
||||
while (++index < characters.length) {
|
||||
const char = characters[index]
|
||||
const next = clean.replace(char.in, char.out)
|
||||
|
||||
if (clean !== next) {
|
||||
children.push({
|
||||
type: 'blockquote',
|
||||
children: [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{type: 'text', value: '👉 '},
|
||||
{
|
||||
type: 'strong',
|
||||
children: [{type: 'text', value: 'Note'}]
|
||||
},
|
||||
{type: 'text', value: ': '},
|
||||
{type: 'inlineCode', value: char.char},
|
||||
{
|
||||
type: 'text',
|
||||
value: ' represents ' + char.name + '.'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
clean = next
|
||||
}
|
||||
}
|
||||
|
||||
children.push({
|
||||
type: 'code',
|
||||
lang: 'markdown',
|
||||
value: fixture.input
|
||||
})
|
||||
}
|
||||
|
||||
children.push({
|
||||
type: 'heading',
|
||||
depth: 6,
|
||||
children: [{type: 'text', value: 'Out'}]
|
||||
})
|
||||
|
||||
if (fixture.output.length === 0) {
|
||||
children.push({
|
||||
type: 'paragraph',
|
||||
children: [{type: 'text', value: 'No messages.'}]
|
||||
})
|
||||
} else {
|
||||
children.push({
|
||||
type: 'code',
|
||||
lang: 'text',
|
||||
value: fixture.output.join('\n')
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
children.push(
|
||||
{
|
||||
type: 'heading',
|
||||
depth: 2,
|
||||
children: [{type: 'text', value: 'Compatibility'}]
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
type: 'text',
|
||||
value:
|
||||
'Projects maintained by the unified collective are compatible with all maintained\nversions of Node.js.\nAs of now, that is Node.js 12.20+, 14.14+, and 16.0+.\nOur projects sometimes work with older versions, but this is not guaranteed.'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'heading',
|
||||
depth: 2,
|
||||
children: [{type: 'text', value: 'Contribute'}]
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{type: 'text', value: 'See '},
|
||||
{
|
||||
type: 'linkReference',
|
||||
referenceType: 'collapsed',
|
||||
identifier: 'contributing',
|
||||
children: [{type: 'inlineCode', value: 'contributing.md'}]
|
||||
},
|
||||
{type: 'text', value: ' in '},
|
||||
{
|
||||
type: 'linkReference',
|
||||
referenceType: 'collapsed',
|
||||
identifier: 'health',
|
||||
children: [
|
||||
{
|
||||
type: 'inlineCode',
|
||||
value: health.split('/').slice(-2).join('/')
|
||||
}
|
||||
]
|
||||
},
|
||||
{type: 'text', value: ' for ways\nto get started.\nSee '},
|
||||
{
|
||||
type: 'linkReference',
|
||||
referenceType: 'collapsed',
|
||||
identifier: 'support',
|
||||
children: [{type: 'inlineCode', value: 'support.md'}]
|
||||
},
|
||||
{type: 'text', value: ' for ways to get help.'}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{type: 'text', value: 'This project has a '},
|
||||
{
|
||||
type: 'linkReference',
|
||||
referenceType: 'collapsed',
|
||||
identifier: 'coc',
|
||||
children: [{type: 'text', value: 'code of conduct'}]
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
value:
|
||||
'.\nBy interacting with this repository, organization, or community you agree to\nabide by its terms.'
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
children.push(
|
||||
{type: 'heading', depth: 2, children: [{type: 'text', value: 'License'}]},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
type: 'linkReference',
|
||||
referenceType: 'collapsed',
|
||||
identifier: 'license',
|
||||
children: [{type: 'text', value: String(pack.license || '')}]
|
||||
},
|
||||
{type: 'text', value: ' © '},
|
||||
{
|
||||
type: 'linkReference',
|
||||
referenceType: 'collapsed',
|
||||
identifier: 'author',
|
||||
children: [
|
||||
{type: 'text', value: String((author && author.name) || '')}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
|
||||
if (!info.deprecated) {
|
||||
children.push(
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'build-badge',
|
||||
url: 'https://github.com/' + slug + '/workflows/main/badge.svg'
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'build',
|
||||
url: 'https://github.com/' + slug + '/actions'
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'coverage-badge',
|
||||
url: 'https://img.shields.io/codecov/c/github/' + slug + '.svg'
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'coverage',
|
||||
url: 'https://codecov.io/github/' + slug
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'downloads-badge',
|
||||
url: 'https://img.shields.io/npm/dm/' + basename + '.svg'
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'downloads',
|
||||
url: 'https://www.npmjs.com/package/' + basename
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'size-badge',
|
||||
url: 'https://img.shields.io/bundlephobia/minzip/' + basename + '.svg'
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'size',
|
||||
url: 'https://bundlephobia.com/result?p=' + basename
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'sponsors-badge',
|
||||
url: 'https://opencollective.com/unified/sponsors/badge.svg'
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'backers-badge',
|
||||
url: 'https://opencollective.com/unified/backers/badge.svg'
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'collective',
|
||||
url: 'https://opencollective.com/unified'
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'chat-badge',
|
||||
url: 'https://img.shields.io/badge/chat-discussions-success.svg'
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'chat',
|
||||
url: 'https://github.com/remarkjs/remark/discussions'
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'unified',
|
||||
url: 'https://github.com/unifiedjs/unified'
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'remark',
|
||||
url: 'https://github.com/remarkjs/remark'
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'mono',
|
||||
url: 'https://github.com/' + slug
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'esm',
|
||||
url: 'https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c'
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'esmsh',
|
||||
url: 'https://esm.sh'
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'npm',
|
||||
url: 'https://docs.npmjs.com/cli/install'
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'health',
|
||||
url: health
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'contributing',
|
||||
url: hMain + '/contributing.md'
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'support',
|
||||
url: hMain + '/support.md'
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'coc',
|
||||
url: hMain + '/code-of-conduct.md'
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
children.push(
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'license',
|
||||
url: main + '/license'
|
||||
},
|
||||
{
|
||||
type: 'definition',
|
||||
identifier: 'author',
|
||||
url: String((author && author.url) || '')
|
||||
}
|
||||
)
|
||||
|
||||
if (hasGfm) {
|
||||
children.push({
|
||||
type: 'definition',
|
||||
identifier: 'gfm',
|
||||
url: 'https://github.com/remarkjs/remark-gfm'
|
||||
})
|
||||
}
|
||||
|
||||
fs.writeFileSync(
|
||||
path.join(base, 'readme.md'),
|
||||
remark().use(remarkGfm).stringify({type: 'root', children})
|
||||
)
|
||||
|
||||
console.log('✓ wrote `readme.md` in `' + basename + '`')
|
||||
}
|
||||
})
|
253
script/info.js
Normal file
253
script/info.js
Normal file
@ -0,0 +1,253 @@
|
||||
/**
|
||||
* @typedef {import('unified').Preset} Preset
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef Check
|
||||
* Check.
|
||||
* @property {string} configuration
|
||||
* Configuration.
|
||||
* @property {boolean} gfm
|
||||
* Whether to use GFM.
|
||||
* @property {string} input
|
||||
* Input.
|
||||
* @property {string} name
|
||||
* Name.
|
||||
* @property {Array<string>} output
|
||||
* Output.
|
||||
* @property {boolean} positionless
|
||||
* Whether this check also applies without positions.
|
||||
*
|
||||
* @typedef ExampleInfo
|
||||
* Example.
|
||||
* @property {unknown} [config]
|
||||
* Configuration.
|
||||
* @property {boolean} [gfm]
|
||||
* Whether to use GFM.
|
||||
* @property {'input' | 'output'} [label]
|
||||
* Label.
|
||||
* @property {boolean} [positionless]
|
||||
* Whether this check also applies without positions.
|
||||
* @property {string} name
|
||||
* Name.
|
||||
*
|
||||
* @typedef PluginInfo
|
||||
* Plugin.
|
||||
* @property {boolean} deprecated
|
||||
* Whether the plugin is deprecated.
|
||||
* @property {string} description
|
||||
* Description.
|
||||
* @property {string} name
|
||||
* Name.
|
||||
* @property {string} ruleId
|
||||
* Rule ID.
|
||||
* @property {string | undefined} summary
|
||||
* Summary.
|
||||
* @property {Array<Check>} checks
|
||||
* Checks.
|
||||
*
|
||||
* @typedef PresetInfo
|
||||
* Preset.
|
||||
* @property {string} name
|
||||
* Name.
|
||||
* @property {Array<[string, unknown]>} plugins
|
||||
* Plugins and their configuration.
|
||||
*/
|
||||
|
||||
import assert from 'node:assert/strict'
|
||||
import fs from 'node:fs/promises'
|
||||
import {parse} from 'comment-parser'
|
||||
import strip from 'strip-indent'
|
||||
|
||||
export const packagesUrl = new URL('../packages/', import.meta.url)
|
||||
|
||||
/**
|
||||
* @type {Array<PluginInfo>}
|
||||
* Plugins.
|
||||
*/
|
||||
export const plugins = []
|
||||
|
||||
/**
|
||||
* @type {Array<PresetInfo>}
|
||||
* Presets.
|
||||
*/
|
||||
export const presets = []
|
||||
|
||||
const names = await fs.readdir(packagesUrl)
|
||||
|
||||
for (const name of names) {
|
||||
if (name.startsWith('remark-lint-')) {
|
||||
await addPlugin(name)
|
||||
}
|
||||
|
||||
if (name.startsWith('remark-preset-lint-')) {
|
||||
await addPreset(name)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* Plugin name.
|
||||
* @returns {Promise<undefined>}
|
||||
* Nothing.
|
||||
*/
|
||||
async function addPlugin(name) {
|
||||
const ruleId = name.slice('remark-lint-'.length)
|
||||
const code = await fs.readFile(
|
||||
new URL(name + '/index.js', packagesUrl),
|
||||
'utf8'
|
||||
)
|
||||
const fileInfo = parse(code, {spacing: 'preserve'})[0]
|
||||
const tags = fileInfo.tags
|
||||
const deprecatedTag = tags.find(function (d) {
|
||||
return d.tag === 'deprecated'
|
||||
})
|
||||
const moduleTag = tags.find(function (d) {
|
||||
return d.tag === 'module'
|
||||
})
|
||||
const summaryTag = tags.find(function (d) {
|
||||
return d.tag === 'summary'
|
||||
})
|
||||
|
||||
assert(moduleTag, 'expected `@module` in JSDoc')
|
||||
|
||||
assert.equal(moduleTag.name, ruleId, 'expected correct `@module`')
|
||||
|
||||
let description = deprecatedTag
|
||||
? deprecatedTag.description
|
||||
: fileInfo.description
|
||||
|
||||
assert(description, 'expected description (or `@deprecated`)')
|
||||
|
||||
description = strip(description)
|
||||
|
||||
/** @type {PluginInfo} */
|
||||
const result = {
|
||||
deprecated: Boolean(deprecatedTag),
|
||||
description: description.trim(),
|
||||
name,
|
||||
ruleId,
|
||||
summary: summaryTag ? strip(summaryTag.description).trim() : undefined,
|
||||
checks: []
|
||||
}
|
||||
|
||||
const examples = tags
|
||||
.filter(function (d) {
|
||||
return d.tag === 'example'
|
||||
})
|
||||
.map(function (d) {
|
||||
return d.description.replace(/^\r?\n|\r?\n$/g, '')
|
||||
})
|
||||
|
||||
let index = -1
|
||||
|
||||
while (++index < examples.length) {
|
||||
const lines = examples[index].split('\n')
|
||||
/** @type {ExampleInfo} */
|
||||
let info
|
||||
|
||||
try {
|
||||
info = JSON.parse(lines[0])
|
||||
lines.splice(0, 1)
|
||||
/* c8 ignore next 4 */
|
||||
} catch (error) {
|
||||
const cause = /** @type {Error} */ (error)
|
||||
throw new Error('Could not parse example in `' + ruleId + '`', {cause})
|
||||
}
|
||||
|
||||
const exampleValue = strip(lines.join('\n').replace(/^\r?\n/g, ''))
|
||||
const configuration = JSON.stringify({config: info.config || true})
|
||||
const name = info.name
|
||||
|
||||
if (!info.label) {
|
||||
result.checks.push({
|
||||
configuration,
|
||||
name,
|
||||
positionless: info.positionless || false,
|
||||
gfm: info.gfm || false,
|
||||
input: exampleValue,
|
||||
output: []
|
||||
})
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
assert(info.label === 'input' || info.label === 'output')
|
||||
|
||||
let found = result.checks.find(function (d) {
|
||||
return d.configuration === configuration && d.name === name
|
||||
})
|
||||
|
||||
if (!found) {
|
||||
found = {
|
||||
configuration,
|
||||
name,
|
||||
positionless: info.positionless || false,
|
||||
gfm: info.gfm || false,
|
||||
input: '',
|
||||
output: []
|
||||
}
|
||||
result.checks.push(found)
|
||||
}
|
||||
|
||||
if (info.label === 'input') {
|
||||
found.input = exampleValue
|
||||
} else {
|
||||
found.output = exampleValue.split('\n')
|
||||
}
|
||||
}
|
||||
|
||||
plugins.push(result)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* Preset name.
|
||||
* @returns {Promise<undefined>}
|
||||
* Nothing.
|
||||
*/
|
||||
async function addPreset(name) {
|
||||
/** @type {{default: Preset}} */
|
||||
const mod = await import(new URL(name + '/index.js', packagesUrl).href)
|
||||
const plugins = mod.default.plugins
|
||||
assert(plugins, 'expected plugins in preset')
|
||||
/** @type {PresetInfo} */
|
||||
const presetInfo = {name, plugins: []}
|
||||
|
||||
let index = -1
|
||||
|
||||
while (++index < plugins.length) {
|
||||
const plugin = plugins[index]
|
||||
/** @type {import('unified').Plugin<[unknown]>} */
|
||||
let fn
|
||||
/** @type {unknown} */
|
||||
let option
|
||||
|
||||
if (Array.isArray(plugin)) {
|
||||
;[fn, option] = /** @type {import('unified').PluginTuple<[unknown]>} */ (
|
||||
plugin
|
||||
)
|
||||
} else {
|
||||
assert(typeof plugin === 'function')
|
||||
fn = plugin
|
||||
}
|
||||
|
||||
// @ts-expect-error: `displayName`s are fine.
|
||||
const name = /** @type {string} */ (fn.displayName || fn.name)
|
||||
|
||||
const pluginName = name
|
||||
.replace(
|
||||
/[:-](\w)/g,
|
||||
function (/** @type {string} */ _, /** @type {string} */ $1) {
|
||||
return $1.toUpperCase()
|
||||
}
|
||||
)
|
||||
.replace(/[A-Z]/g, function (/** @type {string} */ $0) {
|
||||
return '-' + $0.toLowerCase()
|
||||
})
|
||||
|
||||
presetInfo.plugins.push([pluginName, option])
|
||||
}
|
||||
|
||||
presets.push(presetInfo)
|
||||
}
|
85
script/plugin/list-of-plugins.js
Normal file
85
script/plugin/list-of-plugins.js
Normal file
@ -0,0 +1,85 @@
|
||||
/**
|
||||
* @typedef {import('mdast').List} List
|
||||
* @typedef {import('mdast').ListItem} ListItem
|
||||
* @typedef {import('mdast').Root} Root
|
||||
*
|
||||
* @typedef {import('type-fest').PackageJson} PackageJson
|
||||
*/
|
||||
|
||||
import assert from 'node:assert/strict'
|
||||
import fs from 'node:fs/promises'
|
||||
import {zone} from 'mdast-zone'
|
||||
import {packagesUrl, plugins} from '../info.js'
|
||||
|
||||
/**
|
||||
* @type {Array<ListItem | undefined>}
|
||||
* List items.
|
||||
*/
|
||||
const items = await Promise.all(
|
||||
plugins.map(async function (info) {
|
||||
const packageUrl = new URL(info.name + '/', packagesUrl)
|
||||
/** @type {PackageJson} */
|
||||
const pack = JSON.parse(
|
||||
String(await fs.readFile(new URL('package.json', packageUrl)))
|
||||
)
|
||||
const description = String(pack.description || '').replace(
|
||||
/^remark-lint rule to ?/i,
|
||||
''
|
||||
)
|
||||
|
||||
if (/^deprecated/i.test(description)) return
|
||||
|
||||
assert(pack.repository && typeof pack.repository === 'object')
|
||||
assert(pack.repository.directory)
|
||||
|
||||
return {
|
||||
type: 'listItem',
|
||||
spread: false,
|
||||
children: [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
type: 'link',
|
||||
url:
|
||||
pack.repository.url + '/tree/main/' + pack.repository.directory,
|
||||
children: [{type: 'inlineCode', value: info.name}]
|
||||
},
|
||||
{type: 'text', value: ' — ' + description}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
/** @type {List} */
|
||||
const list = {
|
||||
type: 'list',
|
||||
ordered: false,
|
||||
spread: false,
|
||||
// @ts-expect-error: filter is correct.
|
||||
children: items.filter(Boolean)
|
||||
}
|
||||
|
||||
/**
|
||||
* List rules.
|
||||
*
|
||||
* @returns
|
||||
* Transform.
|
||||
*/
|
||||
export default function remarkListOfRules() {
|
||||
/**
|
||||
* Transform.
|
||||
*
|
||||
* @param {Root} tree
|
||||
* Tree.
|
||||
* @returns {undefined}
|
||||
* Nothing.
|
||||
*/
|
||||
return function (tree) {
|
||||
zone(tree, 'rules', function (start, _, end) {
|
||||
return [start, structuredClone(list), end]
|
||||
})
|
||||
}
|
||||
}
|
@ -2,65 +2,77 @@
|
||||
* @typedef {import('mdast').List} List
|
||||
* @typedef {import('mdast').ListItem} ListItem
|
||||
* @typedef {import('mdast').Root} Root
|
||||
*
|
||||
* @typedef {import('type-fest').PackageJson} PackageJson
|
||||
*/
|
||||
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import process from 'node:process'
|
||||
import assert from 'node:assert/strict'
|
||||
import fs from 'node:fs/promises'
|
||||
import {zone} from 'mdast-zone'
|
||||
import {presets} from '../util/presets.js'
|
||||
import {repoUrl} from '../util/repo-url.js'
|
||||
import {packagesUrl, presets} from '../info.js'
|
||||
|
||||
const root = path.join(process.cwd(), 'packages')
|
||||
/**
|
||||
* @type {Array<ListItem>}
|
||||
* List items.
|
||||
*/
|
||||
const items = await Promise.all(
|
||||
presets.map(async function (info) {
|
||||
const packageUrl = new URL(info.name + '/', packagesUrl)
|
||||
/** @type {PackageJson} */
|
||||
const pack = JSON.parse(
|
||||
await fs.readFile(new URL('package.json', packageUrl), 'utf8')
|
||||
)
|
||||
|
||||
/** @type {import('unified').Plugin<Array<void>, Root>} */
|
||||
export default function listOfPresets() {
|
||||
const presetPromise = presets(root)
|
||||
const description = String(pack.description || '').replace(
|
||||
/^remark preset to configure remark-lint with ?/i,
|
||||
''
|
||||
)
|
||||
|
||||
return async (tree) => {
|
||||
const presetObjects = await presetPromise
|
||||
assert(pack.repository && typeof pack.repository === 'object')
|
||||
assert(pack.repository.directory)
|
||||
|
||||
zone(tree, 'presets', (start, _, end) => {
|
||||
/** @type {List} */
|
||||
const list = {
|
||||
type: 'list',
|
||||
ordered: false,
|
||||
spread: false,
|
||||
children: presetObjects.map(({name}) => {
|
||||
/** @type {PackageJson} */
|
||||
const pack = JSON.parse(
|
||||
String(fs.readFileSync(path.join(root, name, 'package.json')))
|
||||
)
|
||||
const description = String(pack.description || '').replace(
|
||||
/^remark preset to configure remark-lint with ?/i,
|
||||
''
|
||||
)
|
||||
return {
|
||||
type: 'listItem',
|
||||
spread: false,
|
||||
children: [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
type: 'link',
|
||||
url:
|
||||
pack.repository.url + '/tree/main/' + pack.repository.directory,
|
||||
children: [{type: 'inlineCode', value: info.name}]
|
||||
},
|
||||
{type: 'text', value: ' — ' + description}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
/** @type {ListItem} */
|
||||
const item = {
|
||||
type: 'listItem',
|
||||
spread: false,
|
||||
children: [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
type: 'link',
|
||||
url: repoUrl(pack),
|
||||
children: [{type: 'inlineCode', value: name}]
|
||||
},
|
||||
{type: 'text', value: ' — ' + description}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
/** @type {List} */
|
||||
const list = {type: 'list', ordered: false, spread: false, children: items}
|
||||
|
||||
return item
|
||||
})
|
||||
}
|
||||
|
||||
return [start, list, end]
|
||||
/**
|
||||
* List presets.
|
||||
*
|
||||
* @returns
|
||||
* Transform.
|
||||
*/
|
||||
export default function remarkListOfPresets() {
|
||||
/**
|
||||
* Transform.
|
||||
*
|
||||
* @param {Root} tree
|
||||
* Tree.
|
||||
* @returns {undefined}
|
||||
* Nothing.
|
||||
*/
|
||||
return function (tree) {
|
||||
zone(tree, 'presets', function (start, _, end) {
|
||||
return [start, structuredClone(list), end]
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,67 +0,0 @@
|
||||
/**
|
||||
* @typedef {import('type-fest').PackageJson} PackageJson
|
||||
* @typedef {import('mdast').ListItem} ListItem
|
||||
* @typedef {import('mdast').List} List
|
||||
* @typedef {import('mdast').Root} Root
|
||||
*/
|
||||
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import process from 'node:process'
|
||||
import {zone} from 'mdast-zone'
|
||||
import {rules} from '../util/rules.js'
|
||||
import {repoUrl} from '../util/repo-url.js'
|
||||
|
||||
const root = path.join(process.cwd(), 'packages')
|
||||
|
||||
/** @type {import('unified').Plugin<Array<void>, Root>} */
|
||||
export default function listOfRules() {
|
||||
return (tree) => {
|
||||
zone(tree, 'rules', (start, _, end) => {
|
||||
/** @type {List} */
|
||||
const list = {
|
||||
type: 'list',
|
||||
ordered: false,
|
||||
spread: false,
|
||||
children: rules(root)
|
||||
.map((basename) => {
|
||||
/** @type {PackageJson} */
|
||||
const pack = JSON.parse(
|
||||
String(fs.readFileSync(path.join(root, basename, 'package.json')))
|
||||
)
|
||||
const description = String(pack.description || '').replace(
|
||||
/^remark-lint rule to ?/i,
|
||||
''
|
||||
)
|
||||
const deprecated = /^deprecated/i.test(description)
|
||||
|
||||
/** @type {ListItem} */
|
||||
const item = {
|
||||
type: 'listItem',
|
||||
spread: false,
|
||||
children: deprecated
|
||||
? []
|
||||
: [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
type: 'link',
|
||||
url: repoUrl(pack),
|
||||
children: [{type: 'inlineCode', value: basename}]
|
||||
},
|
||||
{type: 'text', value: ' — ' + description}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
return item
|
||||
})
|
||||
.filter((d) => d.children.length > 0)
|
||||
}
|
||||
|
||||
return [start, list, end]
|
||||
})
|
||||
}
|
||||
}
|
@ -1,76 +0,0 @@
|
||||
/**
|
||||
* @typedef {import('unified').Plugin} Plugin
|
||||
* @typedef {import('unified').Preset} Preset
|
||||
*/
|
||||
|
||||
import {promises as fs} from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import url from 'node:url'
|
||||
|
||||
/**
|
||||
* @param {string} base
|
||||
* @returns {Promise<Array<{name: string, packages: Record<string, unknown>}>>}
|
||||
*/
|
||||
export async function presets(base) {
|
||||
const allFiles = await fs.readdir(base)
|
||||
const files = allFiles.filter((basename) =>
|
||||
/remark-preset-lint/.test(basename)
|
||||
)
|
||||
|
||||
return Promise.all(
|
||||
files.map(async (name) => {
|
||||
const href = url.pathToFileURL(path.join(base, name, 'index.js')).href
|
||||
// type-coverage:ignore-next-line
|
||||
const presetMod = await import(href)
|
||||
/** @type {Preset} */
|
||||
// type-coverage:ignore-next-line
|
||||
const preset = presetMod.default
|
||||
const plugins = preset.plugins || []
|
||||
/** @type {Record<string, unknown>} */
|
||||
const packages = {}
|
||||
|
||||
let index = -1
|
||||
while (++index < plugins.length) {
|
||||
const plugin = plugins[index]
|
||||
/** @type {Plugin} */
|
||||
let fn
|
||||
/** @type {unknown} */
|
||||
let option
|
||||
|
||||
if (typeof plugin === 'function') {
|
||||
fn = plugin
|
||||
} else if (Array.isArray(plugin)) {
|
||||
// Fine:
|
||||
// type-coverage:ignore-next-line
|
||||
fn = plugin[0]
|
||||
// Fine:
|
||||
// type-coverage:ignore-next-line
|
||||
option = plugin[1]
|
||||
} else {
|
||||
throw new TypeError(
|
||||
'Expected plugin, plugin tuple, not `' + plugin + '`'
|
||||
)
|
||||
}
|
||||
|
||||
/** @type {string} */
|
||||
// @ts-expect-error: `displayName`s are fine.
|
||||
const name = fn.displayName || fn.name
|
||||
|
||||
packages[
|
||||
name
|
||||
.replace(
|
||||
/[:-](\w)/g,
|
||||
(/** @type {string} */ _, /** @type {string} */ $1) =>
|
||||
$1.toUpperCase()
|
||||
)
|
||||
.replace(
|
||||
/[A-Z]/g,
|
||||
(/** @type {string} */ $0) => '-' + $0.toLowerCase()
|
||||
)
|
||||
] = option
|
||||
}
|
||||
|
||||
return {name, packages}
|
||||
})
|
||||
)
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
import fs from 'node:fs'
|
||||
|
||||
/**
|
||||
* @typedef {import('type-fest').PackageJson} PackageJson
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {string | PackageJson} pathOrJson
|
||||
* @returns {string}
|
||||
*/
|
||||
export function repoUrl(pathOrJson) {
|
||||
const pkg =
|
||||
typeof pathOrJson === 'string' ? readPackageJson(pathOrJson) : pathOrJson
|
||||
|
||||
if (
|
||||
pkg.repository === undefined ||
|
||||
typeof pkg.repository !== 'object' ||
|
||||
typeof pkg.repository.url !== 'string'
|
||||
) {
|
||||
throw new TypeError(
|
||||
`Expected \`string\` for \`repository.url\` in \`${pathOrJson}\``
|
||||
)
|
||||
}
|
||||
|
||||
if (pkg.repository.directory) {
|
||||
return pkg.repository.url + `/tree/main/${pkg.repository.directory}`
|
||||
}
|
||||
|
||||
return pkg.repository.url
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} filePath
|
||||
* @returns {PackageJson}
|
||||
*/
|
||||
function readPackageJson(filePath) {
|
||||
return JSON.parse(String(fs.readFileSync(filePath)))
|
||||
}
|
@ -1,140 +0,0 @@
|
||||
/**
|
||||
* @typedef Rule
|
||||
* @property {string} ruleId
|
||||
* @property {string} description
|
||||
* @property {string | undefined} summary
|
||||
* @property {boolean} deprecated
|
||||
* @property {Record<string, Checks>} tests
|
||||
* @property {string} filePath
|
||||
*
|
||||
* @typedef {Record<string, Check>} Checks
|
||||
*
|
||||
* @typedef Check
|
||||
* @property {string} input
|
||||
* @property {Array<string>} output
|
||||
* @property {boolean} gfm
|
||||
* @property {boolean} positionless
|
||||
*/
|
||||
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import {parse} from 'comment-parser'
|
||||
import strip from 'strip-indent'
|
||||
|
||||
/**
|
||||
* Get information for a rule at `filePath`.
|
||||
*
|
||||
* @param {string} filePath
|
||||
* @returns {Rule}
|
||||
*/
|
||||
export function rule(filePath) {
|
||||
const ruleId = path.basename(filePath).slice('remark-lint-'.length)
|
||||
/** @type {Record<string, Checks>} */
|
||||
const tests = {}
|
||||
const code = fs.readFileSync(path.join(filePath, 'index.js'), 'utf8')
|
||||
// Note: To do: `comment-parser` types are wrong.
|
||||
/** @type {import('comment-parser/primitives').Block} */
|
||||
const fileInfo = parse(code, {spacing: 'preserve'})[0]
|
||||
const tags = fileInfo.tags
|
||||
const moduleTag = tags.find((d) => d.tag === 'module')
|
||||
const summaryTag = tags.find((d) => d.tag === 'summary')
|
||||
const deprecatedTag = tags.find((d) => d.tag === 'deprecated')
|
||||
|
||||
/* c8 ignore next 3 */
|
||||
if (!moduleTag) {
|
||||
throw new Error('Expected `@module` in JSDoc')
|
||||
}
|
||||
|
||||
const name = moduleTag.name
|
||||
let description =
|
||||
(deprecatedTag && deprecatedTag.description) || fileInfo.description
|
||||
|
||||
/* c8 ignore next 3 */
|
||||
if (name !== ruleId) {
|
||||
throw new Error(ruleId + ' has an incorrect `@module`: ' + name)
|
||||
}
|
||||
|
||||
/* c8 ignore next 3 */
|
||||
if (!description) {
|
||||
throw new Error(ruleId + ' is missing a description or `@deprecated`')
|
||||
}
|
||||
|
||||
description = strip(description)
|
||||
|
||||
/** @type {Rule} */
|
||||
const result = {
|
||||
ruleId,
|
||||
description: description.trim(),
|
||||
summary: summaryTag ? strip(summaryTag.description).trim() : undefined,
|
||||
deprecated: Boolean(deprecatedTag),
|
||||
tests,
|
||||
filePath
|
||||
}
|
||||
|
||||
const examples = tags
|
||||
.filter((d) => d.tag === 'example')
|
||||
.map((d) => d.description.replace(/^\r?\n|\r?\n$/g, ''))
|
||||
let index = -1
|
||||
|
||||
while (++index < examples.length) {
|
||||
const lines = examples[index].split('\n')
|
||||
/** @type {{name: string, label?: 'input' | 'output', config?: unknown, positionless?: boolean, gfm?: boolean}} */
|
||||
let info
|
||||
|
||||
try {
|
||||
info = JSON.parse(lines[0])
|
||||
lines.splice(0, 1)
|
||||
/* c8 ignore next 6 */
|
||||
} catch (error) {
|
||||
const exception = /** @type Error */ (error)
|
||||
throw new Error(
|
||||
'Could not parse example in ' + ruleId + ':\n' + exception.stack
|
||||
)
|
||||
}
|
||||
|
||||
const exampleValue = strip(lines.join('\n').replace(/^\r?\n/g, ''))
|
||||
const configuration = JSON.stringify({config: info.config || true})
|
||||
const name = info.name
|
||||
const context =
|
||||
configuration in tests
|
||||
? tests[configuration]
|
||||
: (tests[configuration] = {})
|
||||
|
||||
if (!info.label) {
|
||||
context[name] = {
|
||||
positionless: info.positionless || false,
|
||||
gfm: info.gfm || false,
|
||||
input: exampleValue,
|
||||
output: []
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
/* c8 ignore next 9 */
|
||||
if (info.label !== 'input' && info.label !== 'output') {
|
||||
throw new Error(
|
||||
'Expected `input` or `ouput` for `label` in ' +
|
||||
ruleId +
|
||||
', not `' +
|
||||
info.label +
|
||||
'`'
|
||||
)
|
||||
}
|
||||
|
||||
if (!context[name]) {
|
||||
context[name] = {
|
||||
positionless: info.positionless || false,
|
||||
gfm: info.gfm || false,
|
||||
input: '',
|
||||
output: []
|
||||
}
|
||||
}
|
||||
|
||||
// @ts-expect-error: fine: array for output, string for rest.
|
||||
context[name][info.label] =
|
||||
info.label === 'output' ? exampleValue.split('\n') : exampleValue
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
import fs from 'node:fs'
|
||||
|
||||
/**
|
||||
* @param {string} filePath
|
||||
* @returns {Array<string>}
|
||||
*/
|
||||
export function rules(filePath) {
|
||||
return fs
|
||||
.readdirSync(filePath)
|
||||
.filter(
|
||||
(basename) => /remark-lint/.test(basename) && basename !== 'remark-lint'
|
||||
)
|
||||
}
|
590
test.js
590
test.js
@ -1,32 +1,33 @@
|
||||
/**
|
||||
* @typedef {import('unified').Plugin} Plugin
|
||||
* @typedef {import('vfile-message').VFileMessage} VFileMessage
|
||||
* @typedef {import('./script/util/rule.js').Check} Check
|
||||
* @typedef {import('./script/util/rule.js').Rule} Rule
|
||||
* @typedef {import('unified').PluggableList} PluggableList
|
||||
* @typedef {import('unified').Plugin<[unknown]>} Plugin
|
||||
*
|
||||
* @typedef {import('./script/info.js').Check} Check
|
||||
* @typedef {import('./script/info.js').PluginInfo} PluginInfo
|
||||
*/
|
||||
|
||||
import assert from 'node:assert/strict'
|
||||
import path from 'node:path'
|
||||
import process from 'node:process'
|
||||
import test from 'node:test'
|
||||
import url from 'node:url'
|
||||
import {toVFile} from 'to-vfile'
|
||||
import {removePosition} from 'unist-util-remove-position'
|
||||
import {remark} from 'remark'
|
||||
import remarkGfm from 'remark-gfm'
|
||||
import remarkLint from 'remark-lint'
|
||||
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 {lintRule} from 'unified-lint-rule'
|
||||
import {rules} from './script/util/rules.js'
|
||||
import {rule} from './script/util/rule.js'
|
||||
import {removePosition} from 'unist-util-remove-position'
|
||||
import {VFile} from 'vfile'
|
||||
import {characters} from './script/characters.js'
|
||||
import lint from './packages/remark-lint/index.js'
|
||||
import noHeadingPunctuation from './packages/remark-lint-no-heading-punctuation/index.js'
|
||||
import noMultipleToplevelHeadings from './packages/remark-lint-no-multiple-toplevel-headings/index.js'
|
||||
import noUndefinedReferences from './packages/remark-lint-no-undefined-references/index.js'
|
||||
import finalNewline from './packages/remark-lint-final-newline/index.js'
|
||||
import {plugins} from './script/info.js'
|
||||
|
||||
const own = {}.hasOwnProperty
|
||||
test('remark-lint', async function (t) {
|
||||
await t.test('should expose the public api', async function () {
|
||||
assert.deepEqual(Object.keys(await import('remark-lint')).sort(), [
|
||||
'default'
|
||||
])
|
||||
})
|
||||
|
||||
test('core', async () => {
|
||||
const doc = [
|
||||
'# A heading',
|
||||
'',
|
||||
@ -37,53 +38,48 @@ test('core', async () => {
|
||||
'# Another main heading.'
|
||||
].join('\n')
|
||||
|
||||
let file = await remark()
|
||||
.use(noHeadingPunctuation)
|
||||
.use(noMultipleToplevelHeadings)
|
||||
.use(lint)
|
||||
.process(toVFile({path: 'virtual.md', value: doc}))
|
||||
await t.test('should support `remark-lint` last', async function () {
|
||||
const file = await remark()
|
||||
.use(remarkLintNoHeadingPunctuation)
|
||||
.use(remarkLintNoMultipleToplevelHeadings)
|
||||
.use(remarkLint)
|
||||
.process({path: 'virtual.md', value: doc})
|
||||
|
||||
assert.deepEqual(
|
||||
asStrings(file.messages),
|
||||
[
|
||||
assert.deepEqual(file.messages.map(String), [
|
||||
'virtual.md:3:1-3:24: Don’t add a trailing `.` to headings',
|
||||
'virtual.md:3:1-3:24: Don’t use multiple top level headings (1:1)'
|
||||
],
|
||||
'should support `remark-lint` last'
|
||||
)
|
||||
])
|
||||
})
|
||||
|
||||
file = await remark()
|
||||
.use(lint)
|
||||
.use(noHeadingPunctuation)
|
||||
.use(noMultipleToplevelHeadings)
|
||||
.process(toVFile({path: 'virtual.md', value: doc}))
|
||||
await t.test('should support `remark-lint` first', async function () {
|
||||
const file = await remark()
|
||||
.use(remarkLint)
|
||||
.use(remarkLintNoHeadingPunctuation)
|
||||
.use(remarkLintNoMultipleToplevelHeadings)
|
||||
.process({path: 'virtual.md', value: doc})
|
||||
|
||||
assert.deepEqual(
|
||||
asStrings(file.messages),
|
||||
[
|
||||
assert.deepEqual(file.messages.map(String), [
|
||||
'virtual.md:3:1-3:24: Don’t add a trailing `.` to headings',
|
||||
'virtual.md:3:1-3:24: Don’t use multiple top level headings (1:1)'
|
||||
],
|
||||
'should support `remark-lint` first'
|
||||
)
|
||||
])
|
||||
})
|
||||
|
||||
file = await remark().use(lint).process('.')
|
||||
await t.test('should support no rules', async function () {
|
||||
const file = await remark().use(remarkLint).process('.')
|
||||
|
||||
assert.deepEqual(asStrings(file.messages), [], 'should support no rules')
|
||||
assert.deepEqual(file.messages, [])
|
||||
})
|
||||
|
||||
file = await remark().use(finalNewline).process('')
|
||||
await t.test('should support successful rules', async function () {
|
||||
const file = await remark().use(remarkLintFinalNewline).process('')
|
||||
|
||||
assert.deepEqual(
|
||||
asStrings(file.messages),
|
||||
[],
|
||||
'should support successful rules'
|
||||
)
|
||||
assert.deepEqual(file.messages, [])
|
||||
})
|
||||
|
||||
file = await remark().use(finalNewline, [2]).process('.')
|
||||
await t.test('should support a list with a severity', async function () {
|
||||
const file = await remark().use(remarkLintFinalNewline, [2]).process('.')
|
||||
|
||||
assert.deepEqual(
|
||||
file.messages.map((d) => JSON.parse(JSON.stringify(d))),
|
||||
[
|
||||
assert.deepEqual(file.messages.map(jsonClone), [
|
||||
{
|
||||
fatal: true,
|
||||
message: 'Missing newline character at end of file',
|
||||
@ -93,315 +89,269 @@ test('core', async () => {
|
||||
source: 'remark-lint',
|
||||
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-final-newline#readme'
|
||||
}
|
||||
],
|
||||
'should support a list with a severity'
|
||||
])
|
||||
})
|
||||
|
||||
await t.test('should support a boolean (`true`)', async function () {
|
||||
const file = await remark().use(remarkLintFinalNewline, true).process('.')
|
||||
|
||||
assert.deepEqual(file.messages.map(String), [
|
||||
'1:1: Missing newline character at end of file'
|
||||
])
|
||||
})
|
||||
|
||||
await t.test('should support a boolean (`false`)', async function () {
|
||||
const file = await remark().use(remarkLintFinalNewline, false).process('.')
|
||||
|
||||
assert.deepEqual(file.messages, [])
|
||||
})
|
||||
|
||||
await t.test(
|
||||
'should support a list with a boolean severity (true, for on)',
|
||||
async function () {
|
||||
const file = await remark()
|
||||
.use(remarkLintFinalNewline, [true])
|
||||
.process('.')
|
||||
|
||||
assert.deepEqual(file.messages.map(String), [
|
||||
'1:1: Missing newline character at end of file'
|
||||
])
|
||||
}
|
||||
)
|
||||
|
||||
file = await remark().use(finalNewline, true).process('.')
|
||||
await t.test(
|
||||
'should support a list with boolean severity (false, for off)',
|
||||
async function () {
|
||||
const file = await remark()
|
||||
.use(remarkLintFinalNewline, [false])
|
||||
.process('.')
|
||||
|
||||
assert.deepEqual(
|
||||
asStrings(file.messages),
|
||||
['1:1: Missing newline character at end of file'],
|
||||
'should support a boolean (`true`)'
|
||||
assert.deepEqual(file.messages, [])
|
||||
}
|
||||
)
|
||||
|
||||
file = await remark().use(finalNewline, false).process('.')
|
||||
await t.test(
|
||||
'should support a list with string severity (`error`)',
|
||||
async function () {
|
||||
const file = await remark()
|
||||
.use(remarkLintFinalNewline, ['error'])
|
||||
.process('.')
|
||||
|
||||
assert.deepEqual(
|
||||
asStrings(file.messages),
|
||||
[],
|
||||
'should support a boolean (`false`)'
|
||||
assert.deepEqual(file.messages.map(jsonClone), [
|
||||
{
|
||||
fatal: true,
|
||||
message: 'Missing newline character at end of file',
|
||||
name: '1:1',
|
||||
reason: 'Missing newline character at end of file',
|
||||
ruleId: 'final-newline',
|
||||
source: 'remark-lint',
|
||||
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-final-newline#readme'
|
||||
}
|
||||
])
|
||||
}
|
||||
)
|
||||
|
||||
file = await remark().use(finalNewline, [true]).process('.')
|
||||
await t.test(
|
||||
'should support a list with string severity (`on`)',
|
||||
async function () {
|
||||
const file = await remark()
|
||||
.use(remarkLintFinalNewline, ['on'])
|
||||
.process('.')
|
||||
|
||||
assert.deepEqual(
|
||||
asStrings(file.messages),
|
||||
['1:1: Missing newline character at end of file'],
|
||||
'should support a list with a boolean severity (true, for on)'
|
||||
assert.deepEqual(file.messages.map(jsonClone), [
|
||||
{
|
||||
fatal: false,
|
||||
message: 'Missing newline character at end of file',
|
||||
name: '1:1',
|
||||
reason: 'Missing newline character at end of file',
|
||||
ruleId: 'final-newline',
|
||||
source: 'remark-lint',
|
||||
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-final-newline#readme'
|
||||
}
|
||||
])
|
||||
}
|
||||
)
|
||||
|
||||
file = await remark().use(finalNewline, [false]).process('.')
|
||||
await t.test(
|
||||
'should support a list with string severity (`warn`)',
|
||||
async function () {
|
||||
const file = await remark()
|
||||
.use(remarkLintFinalNewline, ['warn'])
|
||||
.process('.')
|
||||
|
||||
assert.deepEqual(
|
||||
asStrings(file.messages),
|
||||
[],
|
||||
'should support a list with boolean severity (false, for off)'
|
||||
assert.deepEqual(file.messages.map(jsonClone), [
|
||||
{
|
||||
fatal: false,
|
||||
message: 'Missing newline character at end of file',
|
||||
name: '1:1',
|
||||
reason: 'Missing newline character at end of file',
|
||||
ruleId: 'final-newline',
|
||||
source: 'remark-lint',
|
||||
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-final-newline#readme'
|
||||
}
|
||||
])
|
||||
}
|
||||
)
|
||||
|
||||
file = await remark().use(finalNewline, ['error']).process('.')
|
||||
await t.test(
|
||||
'should support a list with string severity (`off`)',
|
||||
async function () {
|
||||
const file = await remark()
|
||||
.use(remarkLintFinalNewline, ['off'])
|
||||
.process('.')
|
||||
|
||||
assert.deepEqual(
|
||||
file.messages.map((d) => JSON.parse(JSON.stringify(d))),
|
||||
[
|
||||
{
|
||||
fatal: true,
|
||||
message: 'Missing newline character at end of file',
|
||||
name: '1:1',
|
||||
reason: 'Missing newline character at end of file',
|
||||
ruleId: 'final-newline',
|
||||
source: 'remark-lint',
|
||||
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-final-newline#readme'
|
||||
}
|
||||
],
|
||||
'should support a list with string severity (`error`)'
|
||||
assert.deepEqual(file.messages, [])
|
||||
}
|
||||
)
|
||||
|
||||
file = await remark().use(finalNewline, ['on']).process('.')
|
||||
|
||||
assert.deepEqual(
|
||||
file.messages.map((d) => JSON.parse(JSON.stringify(d))),
|
||||
[
|
||||
{
|
||||
fatal: false,
|
||||
message: 'Missing newline character at end of file',
|
||||
name: '1:1',
|
||||
reason: 'Missing newline character at end of file',
|
||||
ruleId: 'final-newline',
|
||||
source: 'remark-lint',
|
||||
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-final-newline#readme'
|
||||
}
|
||||
],
|
||||
'should support a list with string severity (`on`)'
|
||||
await t.test(
|
||||
'should fail on incorrect severities (too high)',
|
||||
async function () {
|
||||
assert.throws(function () {
|
||||
remark().use(remarkLintFinalNewline, [3]).freeze()
|
||||
}, /^Error: Incorrect severity `3` for `final-newline`, expected 0, 1, or 2$/)
|
||||
}
|
||||
)
|
||||
|
||||
file = await remark().use(finalNewline, ['warn']).process('.')
|
||||
|
||||
assert.deepEqual(
|
||||
file.messages.map((d) => JSON.parse(JSON.stringify(d))),
|
||||
[
|
||||
{
|
||||
fatal: false,
|
||||
message: 'Missing newline character at end of file',
|
||||
name: '1:1',
|
||||
reason: 'Missing newline character at end of file',
|
||||
ruleId: 'final-newline',
|
||||
source: 'remark-lint',
|
||||
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-final-newline#readme'
|
||||
}
|
||||
],
|
||||
'should support a list with string severity (`warn`)'
|
||||
await t.test(
|
||||
'should fail on incorrect severities (too low)',
|
||||
async function () {
|
||||
assert.throws(function () {
|
||||
remark().use(remarkLintFinalNewline, [-1]).freeze()
|
||||
}, /^Error: Incorrect severity `-1` for `final-newline`, expected 0, 1, or 2$/)
|
||||
}
|
||||
)
|
||||
|
||||
file = await remark().use(finalNewline, ['off']).process('.')
|
||||
await t.test(
|
||||
'should support regex as options (remark-lint-no-undefined-references)',
|
||||
async function () {
|
||||
const file = await remark()
|
||||
.use(remarkLintNoUndefinedReferences, {allow: [/^b\./i]})
|
||||
.process({
|
||||
path: 'virtual.md',
|
||||
value: ['[foo][b.c]', '', '[bar][b]'].join('\n')
|
||||
})
|
||||
|
||||
assert.deepEqual(
|
||||
asStrings(file.messages),
|
||||
[],
|
||||
'should support a list with string severity (`off`)'
|
||||
assert.deepEqual(file.messages.map(String), [
|
||||
'virtual.md:3:1-3:9: Found reference to undefined definition'
|
||||
])
|
||||
}
|
||||
)
|
||||
|
||||
assert.throws(
|
||||
() => {
|
||||
remark().use(finalNewline, [3]).freeze()
|
||||
},
|
||||
/^Error: Incorrect severity `3` for `final-newline`, expected 0, 1, or 2$/,
|
||||
'should fail on incorrect severities (too high)'
|
||||
)
|
||||
await t.test(
|
||||
'should support meta as a string (unified-lint-rule)',
|
||||
async function () {
|
||||
const file = await remark()
|
||||
.use(
|
||||
lintRule('test:rule', function (_, file) {
|
||||
file.message('Test message')
|
||||
}),
|
||||
['warn']
|
||||
)
|
||||
.process('.')
|
||||
|
||||
assert.throws(
|
||||
() => {
|
||||
remark().use(finalNewline, [-1]).freeze()
|
||||
},
|
||||
/^Error: Incorrect severity `-1` for `final-newline`, expected 0, 1, or 2$/,
|
||||
'should fail on incorrect severities (too low)'
|
||||
)
|
||||
|
||||
file = await remark()
|
||||
.use(noUndefinedReferences, {allow: [/^b\./i]})
|
||||
.process(
|
||||
toVFile({
|
||||
path: 'virtual.md',
|
||||
value: ['[foo][b.c]', '', '[bar][b]'].join('\n')
|
||||
})
|
||||
)
|
||||
|
||||
assert.deepEqual(
|
||||
asStrings(file.messages),
|
||||
['virtual.md:3:1-3:9: Found reference to undefined definition'],
|
||||
'no-undefined-references allow option should work with native regex'
|
||||
)
|
||||
|
||||
file = await remark()
|
||||
.use(
|
||||
lintRule('test:rule', (tree, file) => {
|
||||
file.message('Test message')
|
||||
}),
|
||||
['warn']
|
||||
)
|
||||
.process('.')
|
||||
|
||||
assert.deepEqual(
|
||||
file.messages.map((d) => JSON.parse(JSON.stringify(d))),
|
||||
[
|
||||
{
|
||||
fatal: false,
|
||||
message: 'Test message',
|
||||
name: '1:1',
|
||||
reason: 'Test message',
|
||||
ruleId: 'rule',
|
||||
source: 'test'
|
||||
}
|
||||
],
|
||||
'should support string meta'
|
||||
assert.deepEqual(file.messages.map(jsonClone), [
|
||||
{
|
||||
fatal: false,
|
||||
message: 'Test message',
|
||||
name: '1:1',
|
||||
reason: 'Test message',
|
||||
ruleId: 'rule',
|
||||
source: 'test'
|
||||
}
|
||||
])
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
test('rules', async (t) => {
|
||||
const root = path.join(process.cwd(), 'packages')
|
||||
const all = rules(root)
|
||||
let index = -1
|
||||
test('plugins', async function (t) {
|
||||
for (const plugin of plugins) {
|
||||
await t.test(plugin.name, async function () {
|
||||
await assertPlugin(plugin)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
while (++index < all.length) {
|
||||
const basename = all[index]
|
||||
const base = path.resolve(root, basename)
|
||||
const info = rule(base)
|
||||
const href = url.pathToFileURL(base).href + '/index.js'
|
||||
/**
|
||||
* @param {PluginInfo} info
|
||||
* Info.
|
||||
* @returns {Promise<undefined>}
|
||||
* Nothing.
|
||||
*/
|
||||
async function assertPlugin(info) {
|
||||
/** @type {{default: Plugin}} */
|
||||
const pluginMod = await import(info.name)
|
||||
const plugin = pluginMod.default
|
||||
|
||||
/** @type {{default: Plugin}} */
|
||||
const pluginMod = await import(href)
|
||||
const fn = pluginMod.default
|
||||
for (const check of info.checks) {
|
||||
await assertCheck(plugin, info, check)
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.keys(info.tests).length === 0) {
|
||||
assert.ok(true, info.ruleId + ': no tests')
|
||||
} else {
|
||||
await t.test(info.ruleId, async () => {
|
||||
const tests = info.tests
|
||||
/** @type {string} */
|
||||
let configuration
|
||||
/**
|
||||
* @param {Plugin} plugin
|
||||
* Plugin.
|
||||
* @param {PluginInfo} info
|
||||
* info.
|
||||
* @param {Check} check
|
||||
* Check.
|
||||
* @returns {Promise<undefined>}
|
||||
* Nothing.
|
||||
*/
|
||||
async function assertCheck(plugin, info, check) {
|
||||
/** @type {{config: unknown}} */
|
||||
const {config} = JSON.parse(check.configuration)
|
||||
/** @type {PluggableList} */
|
||||
const extras = check.gfm ? [remarkGfm] : []
|
||||
let value = check.input
|
||||
|
||||
for (configuration in tests) {
|
||||
if (own.call(tests, configuration)) {
|
||||
const checks = tests[configuration]
|
||||
/** @type {{config: unknown}} */
|
||||
const {config} = JSON.parse(configuration)
|
||||
for (const character of characters) {
|
||||
value = value.replace(character.in, character.out)
|
||||
}
|
||||
|
||||
/** @type {string} */
|
||||
let name
|
||||
const file = await remark()
|
||||
.use(plugin, config)
|
||||
.use(extras)
|
||||
.process(new VFile({path: check.name, value}))
|
||||
|
||||
for (name in checks) {
|
||||
if (own.call(checks, name)) {
|
||||
const basename = name
|
||||
const check = checks[name]
|
||||
for (const message of file.messages) {
|
||||
assert.equal(message.ruleId, info.ruleId)
|
||||
assert.equal(
|
||||
message.url,
|
||||
'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-' +
|
||||
info.ruleId +
|
||||
'#readme'
|
||||
)
|
||||
}
|
||||
|
||||
await assertFixture(fn, info, check, basename, config)
|
||||
}
|
||||
}
|
||||
}
|
||||
assert.deepEqual(
|
||||
file.messages.map(String).map(function (value) {
|
||||
return value.slice(value.indexOf(':') + 1)
|
||||
}),
|
||||
check.output
|
||||
)
|
||||
|
||||
if (!check.positionless) {
|
||||
const file = await remark()
|
||||
.use(function () {
|
||||
return function (tree) {
|
||||
removePosition(tree)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
.use(plugin, config)
|
||||
.use(extras)
|
||||
.process(new VFile({path: check.name, value}))
|
||||
|
||||
/**
|
||||
* @param {Plugin} rule
|
||||
* @param {Rule} info
|
||||
* @param {Check} fixture
|
||||
* @param {string} basename
|
||||
* @param {unknown} config
|
||||
*/
|
||||
/* eslint-disable-next-line max-params */
|
||||
function assertFixture(rule, info, fixture, basename, config) {
|
||||
const ruleId = info.ruleId
|
||||
const file = toVFile(basename)
|
||||
const expected = fixture.output
|
||||
const positionless = fixture.positionless
|
||||
// @ts-expect-error: to do: fix types.
|
||||
let proc = remark().use(rule, config)
|
||||
|
||||
if (fixture.gfm) proc.use(remarkGfm)
|
||||
|
||||
file.value = preprocess(fixture.input || '')
|
||||
|
||||
try {
|
||||
proc.runSync(proc.parse(file), file)
|
||||
} catch (error) {
|
||||
const exception = /** @type VFileMessage */ (error)
|
||||
if (exception && exception.source !== 'remark-lint') {
|
||||
throw exception
|
||||
}
|
||||
}
|
||||
|
||||
let index = -1
|
||||
while (++index < file.messages.length) {
|
||||
const message = file.messages[index]
|
||||
if (message.ruleId !== ruleId) {
|
||||
throw new Error(
|
||||
'Expected `' +
|
||||
ruleId +
|
||||
'`, not `' +
|
||||
message.ruleId +
|
||||
'` as `ruleId` for ' +
|
||||
message
|
||||
)
|
||||
}
|
||||
|
||||
const expectedUrl =
|
||||
'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-' +
|
||||
ruleId +
|
||||
'#readme'
|
||||
if (message.url !== expectedUrl) {
|
||||
throw new Error(
|
||||
'Expected `' +
|
||||
expectedUrl +
|
||||
'`, not `' +
|
||||
message.url +
|
||||
'` as `ruleId` for ' +
|
||||
message
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
assert.deepEqual(
|
||||
normalize(file.messages),
|
||||
expected,
|
||||
'should equal with position'
|
||||
)
|
||||
|
||||
if (!positionless) {
|
||||
file.messages = []
|
||||
proc = remark()
|
||||
.use(() => (tree) => removePosition(tree))
|
||||
// @ts-expect-error: to do: fix types.
|
||||
.use(rule, config)
|
||||
if (fixture.gfm) proc.use(remarkGfm)
|
||||
proc.processSync(file)
|
||||
|
||||
assert.deepEqual(
|
||||
normalize(file.messages),
|
||||
[],
|
||||
'should equal without position'
|
||||
)
|
||||
assert.deepEqual(file.messages, [])
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Array<VFileMessage>} messages
|
||||
* @returns {Array<string>}
|
||||
* @param {unknown} d
|
||||
* Value.
|
||||
* @returns {unknown}
|
||||
* Cloned value.
|
||||
*/
|
||||
function normalize(messages) {
|
||||
return asStrings(messages).map((value) => value.slice(value.indexOf(':') + 1))
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Array<VFileMessage>} messages
|
||||
* @returns {Array<string>}
|
||||
*/
|
||||
function asStrings(messages) {
|
||||
return messages.map(String)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @returns {string}
|
||||
*/
|
||||
function preprocess(value) {
|
||||
let index = -1
|
||||
|
||||
while (++index < characters.length) {
|
||||
value = value.replace(characters[index].in, characters[index].out)
|
||||
}
|
||||
|
||||
return value
|
||||
function jsonClone(d) {
|
||||
return JSON.parse(JSON.stringify(d))
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
"declarationMap": true,
|
||||
"emitDeclarationOnly": true,
|
||||
"exactOptionalPropertyTypes": true,
|
||||
"lib": ["es2020"],
|
||||
"lib": ["es2022"],
|
||||
"module": "node16",
|
||||
"strict": true,
|
||||
"target": "es2020"
|
||||
|
Loading…
Reference in New Issue
Block a user