Refactor code-style

This commit is contained in:
Titus Wormer 2023-11-13 16:14:01 +01:00
parent 0e79b65cc7
commit 19251fc5ab
No known key found for this signature in database
GPG Key ID: E6E581152ED04E2E
148 changed files with 1361 additions and 864 deletions

View File

@ -40,7 +40,7 @@ npm install remark-lint remark-cli
We will also use some utilities:
```sh
npm install unified-lint-rule unist-util-generated unist-util-visit
npm install unified-lint-rule unist-util-visit
```
These will help us creating and managing our custom rules.

View File

@ -134,6 +134,7 @@
"type-coverage": "^2.0.0",
"type-fest": "^4.0.0",
"typescript": "^5.0.0",
"unified": "^11.0.0",
"unist-builder": "^4.0.0",
"unist-util-remove-position": "^5.0.0",
"vfile": "^6.0.0",

View File

@ -79,39 +79,42 @@
*/
/**
* @typedef {import('mdast').Blockquote} Blockquote
* @typedef {import('mdast').Root} Root
*/
/**
* @typedef {'consistent' | number} Options
* Options.
* @typedef {number | 'consistent'} Options
* Configuration.
*/
import pluralize from 'pluralize'
import {lintRule} from 'unified-lint-rule'
import plural from 'pluralize'
import {visit} from 'unist-util-visit'
import {pointStart} from 'unist-util-position'
import {generated} from 'unist-util-generated'
import {visit} from 'unist-util-visit'
const remarkLintBlockquoteIndentation = lintRule(
{
origin: 'remark-lint:blockquote-indentation',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-blockquote-indentation#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, Options>} */
(tree, file, option = 'consistent') => {
visit(tree, 'blockquote', (node) => {
if (generated(node) || node.children.length === 0) {
return
}
/**
* @param {Root} tree
* Tree.
* @param {Options | null | undefined} [options='consistent']
* Configuration (default: `'consistent'`).
* @returns {undefined}
* Nothing.
*/
function (tree, file, options) {
let option = options || 'consistent'
visit(tree, 'blockquote', function (node) {
const start = pointStart(node)
const head = pointStart(node.children[0])
/* c8 ignore next -- we get here if we have offsets. */
const count = head && start ? head.column - start.column : undefined
if (typeof count === 'number') {
if (head && start) {
const count = head.column - start.column
if (option === 'consistent') {
option = count
} else {
@ -125,9 +128,9 @@ const remarkLintBlockquoteIndentation = lintRule(
' ' +
abs +
' ' +
plural('space', abs) +
pluralize('space', abs) +
' between block quote and content',
pointStart(node.children[0])
head
)
}
}

View File

@ -38,9 +38,7 @@
"dependencies": {
"@types/mdast": "^4.0.0",
"pluralize": "^8.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0",
"unist-util-generated": "^3.0.0",
"unist-util-position": "^5.0.0",
"unist-util-visit": "^5.0.0"
},
@ -54,7 +52,8 @@
"xo": {
"prettier": true,
"rules": {
"capitalized-comments": "off"
"capitalized-comments": "off",
"unicorn/prefer-default-parameters": "off"
}
}
}

View File

@ -92,37 +92,44 @@
*/
/**
* @typedef {Styles | 'consistent'} Options
* Configuration.
*
* @typedef Styles
* Styles.
* @property {'x' | 'X' | 'consistent'} [checked='consistent']
* @property {'X' | 'x' | 'consistent' | null | undefined} [checked='consistent']
* Preferred style to use for checked checkboxes (default: `'consistent'`).
* @property {' ' | '\t' | 'consistent'} [unchecked='consistent']
* @property {'\t' | ' ' | 'consistent' | null | undefined} [unchecked='consistent']
* Preferred style to use for unchecked checkboxes (default: `'consistent'`).
*
* @typedef {'consistent' | Styles} Options
* Options.
*/
import {lintRule} from 'unified-lint-rule'
import {visit} from 'unist-util-visit'
import {pointStart} from 'unist-util-position'
import {visit} from 'unist-util-visit'
const remarkLintCheckboxCharacterStyle = lintRule(
{
origin: 'remark-lint:checkbox-character-style',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-checkbox-character-style#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, Options>} */
(tree, file, option = 'consistent') => {
/**
* @param {Root} tree
* Tree.
* @param {Options | null | undefined} [options]
* Configuration (optional).
* @returns {undefined}
* Nothing.
*/
function (tree, file, options) {
const value = String(file)
/** @type {'x' | 'X' | 'consistent'} */
/** @type {'X' | 'x' | 'consistent'} */
let checked = 'consistent'
/** @type {' ' | '\x09' | 'consistent'} */
/** @type {'\x09' | ' ' | 'consistent'} */
let unchecked = 'consistent'
if (typeof option === 'object') {
checked = option.checked || 'consistent'
unchecked = option.unchecked || 'consistent'
if (options && typeof options === 'object') {
checked = options.checked || 'consistent'
unchecked = options.unchecked || 'consistent'
}
if (unchecked !== 'consistent' && unchecked !== ' ' && unchecked !== '\t') {
@ -141,7 +148,7 @@ const remarkLintCheckboxCharacterStyle = lintRule(
)
}
visit(tree, 'listItem', (node) => {
visit(tree, 'listItem', function (node) {
const head = node.children[0]
const point = pointStart(head)
@ -149,8 +156,8 @@ const remarkLintCheckboxCharacterStyle = lintRule(
// A list item cannot be checked and empty, according to GFM.
if (
!point ||
typeof node.checked !== 'boolean' ||
!head ||
typeof node.checked !== 'boolean' ||
typeof point.offset !== 'number'
) {
return

View File

@ -38,7 +38,6 @@
],
"dependencies": {
"@types/mdast": "^4.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0",
"unist-util-position": "^5.0.0",
"unist-util-visit": "^5.0.0"

View File

@ -66,21 +66,26 @@
*/
import {lintRule} from 'unified-lint-rule'
import {location} from 'vfile-location'
import {visit} from 'unist-util-visit'
import {pointStart} from 'unist-util-position'
import {visit} from 'unist-util-visit'
import {location} from 'vfile-location'
const remarkLintCheckboxContentIndent = lintRule(
{
origin: 'remark-lint:checkbox-content-indent',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-checkbox-content-indent#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, void>} */
(tree, file) => {
/**
* @param {Root} tree
* Tree.
* @returns {undefined}
* Nothing.
*/
function (tree, file) {
const value = String(file)
const loc = location(file)
visit(tree, 'listItem', (node) => {
visit(tree, 'listItem', function (node) {
const head = node.children[0]
const point = pointStart(head)
@ -88,8 +93,8 @@ const remarkLintCheckboxContentIndent = lintRule(
// A list item cannot be checked and empty, according to GFM.
if (
!point ||
typeof node.checked !== 'boolean' ||
!head ||
typeof node.checked !== 'boolean' ||
typeof point.offset !== 'number'
) {
return
@ -100,8 +105,7 @@ const remarkLintCheckboxContentIndent = lintRule(
value.slice(point.offset - 4, point.offset + 1)
)
// Failsafe to make sure we dont crash if there actually isnt a checkbox.
/* c8 ignore next */
/* c8 ignore next -- make sure we dont crash if there actually isnt a checkbox. */
if (!match) return
// Move past checkbox.

View File

@ -38,7 +38,6 @@
],
"dependencies": {
"@types/mdast": "^4.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0",
"unist-util-position": "^5.0.0",
"unist-util-visit": "^5.0.0",

View File

@ -131,29 +131,38 @@
*/
/**
* @typedef {'fenced' | 'indented'} Style
* @typedef {Style | 'consistent'} Options
* Configuration.
*
* @typedef {'indented' | 'fenced'} Style
* Styles.
* @typedef {'consistent' | Style} Options
* Options.
*/
import {lintRule} from 'unified-lint-rule'
import {pointEnd, pointStart} from 'unist-util-position'
import {visit} from 'unist-util-visit'
import {pointStart, pointEnd} from 'unist-util-position'
const remarkLintCodeBlockStyle = lintRule(
{
origin: 'remark-lint:code-block-style',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-code-block-style#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, Options>} */
(tree, file, option = 'consistent') => {
/**
* @param {Root} tree
* Tree.
* @param {Options | null | undefined} [options='consistent']
* Configuration (default: `'consistent'`).
* @returns {undefined}
* Nothing.
*/
function (tree, file, options) {
let option = options || 'consistent'
const value = String(file)
if (
option !== 'consistent' &&
option !== 'fenced' &&
option !== 'indented'
option !== 'indented' &&
option !== 'fenced'
) {
file.fail(
'Incorrect code block style `' +
@ -162,22 +171,22 @@ const remarkLintCodeBlockStyle = lintRule(
)
}
visit(tree, 'code', (node) => {
const initial = pointStart(node)
const final = pointEnd(node)
visit(tree, 'code', function (node) {
const end = pointEnd(node)
const start = pointStart(node)
if (
!initial ||
!final ||
typeof initial.offset !== 'number' ||
typeof final.offset !== 'number'
!start ||
!end ||
typeof start.offset !== 'number' ||
typeof end.offset !== 'number'
) {
return
}
const current =
node.lang ||
/^\s*([~`])\1{2,}/.test(value.slice(initial.offset, final.offset))
/^\s*([~`])\1{2,}/.test(value.slice(start.offset, end.offset))
? 'fenced'
: 'indented'

View File

@ -36,7 +36,6 @@
],
"dependencies": {
"@types/mdast": "^4.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0",
"unist-util-position": "^5.0.0",
"unist-util-visit": "^5.0.0"
@ -51,7 +50,8 @@
"xo": {
"prettier": true,
"rules": {
"capitalized-comments": "off"
"capitalized-comments": "off",
"unicorn/prefer-default-parameters": "off"
}
}
}

View File

@ -42,8 +42,8 @@
*/
import {lintRule} from 'unified-lint-rule'
import {pointEnd, pointStart} from 'unist-util-position'
import {visit} from 'unist-util-visit'
import {pointStart, pointEnd} from 'unist-util-position'
const label = /^\s*\[((?:\\[\s\S]|[^[\]])+)]/
@ -52,20 +52,25 @@ const remarkLintDefinitionCase = lintRule(
origin: 'remark-lint:definition-case',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-definition-case#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, void>} */
(tree, file) => {
/**
* @param {Root} tree
* Tree.
* @returns {undefined}
* Nothing.
*/
function (tree, file) {
const value = String(file)
visit(tree, (node) => {
visit(tree, function (node) {
if (node.type === 'definition' || node.type === 'footnoteDefinition') {
const start = pointStart(node)
const end = pointEnd(node)
const start = pointStart(node)
if (
start &&
end &&
typeof start.offset === 'number' &&
typeof end.offset === 'number'
start &&
typeof end.offset === 'number' &&
typeof start.offset === 'number'
) {
const match = value.slice(start.offset, end.offset).match(label)

View File

@ -36,7 +36,6 @@
],
"dependencies": {
"@types/mdast": "^4.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0",
"unist-util-position": "^5.0.0",
"unist-util-visit": "^5.0.0"

View File

@ -44,8 +44,8 @@
*/
import {lintRule} from 'unified-lint-rule'
import {visit} from 'unist-util-visit'
import {pointStart, pointEnd} from 'unist-util-position'
import {visit} from 'unist-util-visit'
const label = /^\s*\[((?:\\[\s\S]|[^[\]])+)]/
@ -54,20 +54,25 @@ const remarkLintDefinitionSpacing = lintRule(
origin: 'remark-lint:definition-spacing',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-definition-spacing#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, void>} */
(tree, file) => {
/**
* @param {Root} tree
* Tree.
* @returns {undefined}
* Nothing.
*/
function (tree, file) {
const value = String(file)
visit(tree, (node) => {
visit(tree, function (node) {
if (node.type === 'definition' || node.type === 'footnoteDefinition') {
const start = pointStart(node)
const end = pointEnd(node)
const start = pointStart(node)
if (
start &&
end &&
typeof start.offset === 'number' &&
typeof end.offset === 'number'
start &&
typeof end.offset === 'number' &&
typeof start.offset === 'number'
) {
const match = value.slice(start.offset, end.offset).match(label)

View File

@ -36,7 +36,6 @@
],
"dependencies": {
"@types/mdast": "^4.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0",
"unist-util-position": "^5.0.0",
"unist-util-visit": "^5.0.0"

View File

@ -93,22 +93,31 @@
/**
* @typedef {'*' | '_'} Marker
* Styles.
* @typedef {'consistent' | Marker} Options
* Options.
*
* @typedef {Marker | 'consistent'} Options
* Configuration.
*/
import {lintRule} from 'unified-lint-rule'
import {visit} from 'unist-util-visit'
import {pointStart} from 'unist-util-position'
import {visit} from 'unist-util-visit'
const remarkLintEmphasisMarker = lintRule(
{
origin: 'remark-lint:emphasis-marker',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-emphasis-marker#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, Options>} */
(tree, file, option = 'consistent') => {
/**
* @param {Root} tree
* Tree.
* @param {Options | null | undefined} [options='consistent']
* Configuration (default: `'consistent`').
* @returns {undefined}
* Nothing.
*/
function (tree, file, options) {
const value = String(file)
let option = options || 'consistent'
if (option !== '*' && option !== '_' && option !== 'consistent') {
file.fail(
@ -118,7 +127,7 @@ const remarkLintEmphasisMarker = lintRule(
)
}
visit(tree, 'emphasis', (node) => {
visit(tree, 'emphasis', function (node) {
const start = pointStart(node)
if (start && typeof start.offset === 'number') {

View File

@ -36,7 +36,6 @@
],
"dependencies": {
"@types/mdast": "^4.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0",
"unist-util-position": "^5.0.0",
"unist-util-visit": "^5.0.0"
@ -51,7 +50,8 @@
"xo": {
"prettier": true,
"rules": {
"capitalized-comments": "off"
"capitalized-comments": "off",
"unicorn/prefer-default-parameters": "off"
}
}
}

View File

@ -100,23 +100,23 @@
*/
/**
* @typedef FlagMap
* Configuration.
* @property {boolean | null | undefined} [allowEmpty=false]
* Allow language flags to be omitted (default: `false`).
* @property {Flags | null | undefined} [flags]
* Language flags (optional).
*
* @typedef {Array<string>} Flags
* Language flags.
*
* @typedef FlagMap
* @typedef {FlagMap | Flags} Options
* Configuration.
* @property {Flags} [flags]
* Language flags.
* @property {boolean} [allowEmpty=false]
* Allow language flags to be omitted (default: `false`).
*
* @typedef {Flags | FlagMap} Options
* Options.
*/
import {lintRule} from 'unified-lint-rule'
import {pointEnd, pointStart} from 'unist-util-position'
import {visit} from 'unist-util-visit'
import {pointStart, pointEnd} from 'unist-util-position'
const fence = /^ {0,3}([~`])\1{2,}/
@ -125,34 +125,41 @@ const remarkLintFencedCodeFlag = lintRule(
origin: 'remark-lint:fenced-code-flag',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-fenced-code-flag#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, Options>} */
(tree, file, option) => {
/**
* @param {Root} tree
* Tree.
* @param {Options | null | undefined} [options]
* Configuration (optional).
* @returns {undefined}
* Nothing.
*/
function (tree, file, options) {
const value = String(file)
let allowEmpty = false
/** @type {Array<string>} */
let allowed = []
if (typeof option === 'object') {
if (Array.isArray(option)) {
allowed = option
if (options && typeof options === 'object') {
if (Array.isArray(options)) {
allowed = options
} else {
allowEmpty = Boolean(option.allowEmpty)
allowEmpty = Boolean(options.allowEmpty)
if (option.flags) {
allowed = option.flags
if (options.flags) {
allowed = options.flags
}
}
}
visit(tree, 'code', (node) => {
const start = pointStart(node)
visit(tree, 'code', function (node) {
const end = pointEnd(node)
const start = pointStart(node)
if (
start &&
end &&
typeof start.offset === 'number' &&
typeof end.offset === 'number'
start &&
typeof end.offset === 'number' &&
typeof start.offset === 'number'
) {
if (node.lang) {
if (allowed.length > 0 && !allowed.includes(node.lang)) {

View File

@ -38,7 +38,6 @@
],
"dependencies": {
"@types/mdast": "^4.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0",
"unist-util-position": "^5.0.0",
"unist-util-visit": "^5.0.0"

View File

@ -105,23 +105,32 @@
*/
/**
* @typedef {'~' | '`'} Marker
* @typedef {'`' | '~'} Marker
* Styles.
* @typedef {'consistent' | Marker} Options
* Options.
*
* @typedef {Marker | 'consistent'} Options
* Configuration.
*/
import {lintRule} from 'unified-lint-rule'
import {visit} from 'unist-util-visit'
import {pointStart} from 'unist-util-position'
import {visit} from 'unist-util-visit'
const remarkLintFencedCodeMarker = lintRule(
{
origin: 'remark-lint:fenced-code-marker',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-fenced-code-marker#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, Options>} */
(tree, file, option = 'consistent') => {
/**
* @param {Root} tree
* Tree.
* @param {Options | null | undefined} [options='consistent']
* Configuration (default: `'consistent'`).
* @returns {undefined}
* Nothing.
*/
function (tree, file, options) {
let option = options || 'consistent'
const contents = String(file)
if (option !== 'consistent' && option !== '~' && option !== '`') {
@ -132,7 +141,7 @@ const remarkLintFencedCodeMarker = lintRule(
)
}
visit(tree, 'code', (node) => {
visit(tree, 'code', function (node) {
const start = pointStart(node)
if (start && typeof start.offset === 'number') {
@ -142,7 +151,7 @@ const remarkLintFencedCodeMarker = lintRule(
.charAt(0)
// Ignore unfenced code blocks.
if (marker === '~' || marker === '`') {
if (marker === '`' || marker === '~') {
if (option === 'consistent') {
option = marker
} else if (marker !== option) {

View File

@ -37,7 +37,6 @@
],
"dependencies": {
"@types/mdast": "^4.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0",
"unist-util-position": "^5.0.0",
"unist-util-visit": "^5.0.0"
@ -52,7 +51,8 @@
"xo": {
"prettier": true,
"rules": {
"capitalized-comments": "off"
"capitalized-comments": "off",
"unicorn/prefer-default-parameters": "off"
}
}
}

View File

@ -47,7 +47,7 @@
/**
* @typedef {string} Options
* Options.
* Configuration.
*/
import {lintRule} from 'unified-lint-rule'
@ -57,8 +57,16 @@ const remarkLintFileExtension = lintRule(
origin: 'remark-lint:file-extension',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-file-extension#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, Options>} */
(_, file, option = 'md') => {
/**
* @param {Root} _
* Tree.
* @param {Options | null | undefined} [options]
* Configuration (default: `'md'`).
* @returns {undefined}
* Nothing.
*/
function (_, file, options) {
const option = options || 'md'
const ext = file.extname
if (ext && ext.slice(1) !== option) {

View File

@ -37,7 +37,6 @@
],
"dependencies": {
"@types/mdast": "^4.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0"
},
"scripts": {},
@ -50,7 +49,8 @@
"xo": {
"prettier": true,
"rules": {
"capitalized-comments": "off"
"capitalized-comments": "off",
"unicorn/prefer-default-parameters": "off"
}
}
}

View File

@ -59,27 +59,33 @@
*/
import {lintRule} from 'unified-lint-rule'
import {visit} from 'unist-util-visit'
import {pointStart} from 'unist-util-position'
import {visit} from 'unist-util-visit'
const remarkLintFinalDefinition = lintRule(
{
origin: 'remark-lint:final-definition',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-final-definition#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, void>} */
(tree, file) => {
/**
* @param {Root} tree
* Tree.
* @returns {undefined}
* Nothing.
*/
function (tree, file) {
let last = 0
visit(
tree,
(node) => {
function (node) {
const start = pointStart(node)
// To do: ignore MDX comments?
// Ignore generated and HTML comment nodes.
if (
node.type === 'root' ||
!start ||
node.type === 'root' ||
(node.type === 'html' && /^\s*<!--/.test(node.value))
) {
return

View File

@ -37,7 +37,6 @@
],
"dependencies": {
"@types/mdast": "^4.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0",
"unist-util-position": "^5.0.0",
"unist-util-visit": "^5.0.0"

View File

@ -69,12 +69,18 @@ const remarkLintFinalNewline = lintRule(
origin: 'remark-lint:final-newline',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-final-newline#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, void>} */
(_, file) => {
/**
* @param {Root} _
* Tree.
* @returns {undefined}
* Nothing.
*/
function (_, file) {
const value = String(file)
const last = value.length - 1
if (last > -1 && value.charAt(last) !== '\n') {
// To do: warn at last character.
file.message('Missing newline character at end of file')
}
}

View File

@ -37,7 +37,6 @@
],
"dependencies": {
"@types/mdast": "^4.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0"
},
"scripts": {},

View File

@ -108,20 +108,20 @@
/**
* @typedef {import('mdast').Heading} Heading
* @typedef {import('mdast').HTML} HTML
* @typedef {import('mdast').Root} Root
*/
/**
* @typedef {Heading['depth']} Depth
* Styles.
*
* @typedef {Depth} Options
* Options.
* Configuration.
*/
import {lintRule} from 'unified-lint-rule'
import {visit, EXIT} from 'unist-util-visit'
import {generated} from 'unist-util-generated'
import {position} from 'unist-util-position'
import {EXIT, visit} from 'unist-util-visit'
const re = /<h([1-6])/
@ -130,22 +130,38 @@ const remarkLintFirstHeadingLevel = lintRule(
origin: 'remark-lint:first-heading-level',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-first-heading-level#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, Options>} */
(tree, file, option = 1) => {
visit(tree, (node) => {
if (!generated(node)) {
/**
* @param {Root} tree
* Tree.
* @param {Options | null | undefined} [options=1]
* Configuration (default: `1`).
* @returns {undefined}
* Nothing.
*/
function (tree, file, options) {
const option = options || 1
visit(tree, function (node) {
const place = position(node)
if (place) {
/** @type {Depth | undefined} */
let rank
// To do: MDX?
if (node.type === 'heading') {
rank = node.depth
} else if (node.type === 'html') {
rank = infer(node)
const results = node.value.match(re)
rank = results ? /** @type {Depth} */ (Number(results[1])) : undefined
}
if (rank !== undefined) {
if (rank) {
if (rank !== option) {
file.message('First heading level should be `' + option + '`', node)
file.message(
'First heading level should be `' + option + '`',
place
)
}
return EXIT
@ -156,13 +172,3 @@ const remarkLintFirstHeadingLevel = lintRule(
)
export default remarkLintFirstHeadingLevel
/**
* @param {HTML} node
* @returns {Depth | undefined}
*/
function infer(node) {
const results = node.value.match(re)
// @ts-expect-error: can be casted fine.
return results ? Number(results[1]) : undefined
}

View File

@ -38,9 +38,8 @@
],
"dependencies": {
"@types/mdast": "^4.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0",
"unist-util-generated": "^3.0.0",
"unist-util-position": "^5.0.0",
"unist-util-visit": "^5.0.0"
},
"scripts": {},
@ -53,7 +52,8 @@
"xo": {
"prettier": true,
"rules": {
"capitalized-comments": "off"
"capitalized-comments": "off",
"unicorn/prefer-default-parameters": "off"
}
}
}

View File

@ -44,19 +44,24 @@
*/
import {lintRule} from 'unified-lint-rule'
import {pointEnd, pointStart} from 'unist-util-position'
import {visit} from 'unist-util-visit'
import {pointStart, pointEnd} from 'unist-util-position'
const remarkLintHardBreakSpaces = lintRule(
{
origin: 'remark-lint:hard-break-spaces',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-hard-break-spaces#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, void>} */
(tree, file) => {
/**
* @param {Root} tree
* Tree.
* @returns {undefined}
* Nothing.
*/
function (tree, file) {
const value = String(file)
visit(tree, 'break', (node) => {
visit(tree, 'break', function (node) {
const start = pointStart(node)
const end = pointEnd(node)

View File

@ -38,7 +38,6 @@
],
"dependencies": {
"@types/mdast": "^4.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0",
"unist-util-position": "^5.0.0",
"unist-util-visit": "^5.0.0"

View File

@ -55,25 +55,32 @@
*/
import {lintRule} from 'unified-lint-rule'
import {position} from 'unist-util-position'
import {visit} from 'unist-util-visit'
import {generated} from 'unist-util-generated'
const remarkLintHeadingIncrement = lintRule(
{
origin: 'remark-lint:heading-increment',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-heading-increment#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, void>} */
(tree, file) => {
/** @type {Depth} */
/**
* @param {Root} tree
* Tree.
* @returns {undefined}
* Nothing.
*/
function (tree, file) {
/** @type {Depth | undefined} */
let previous
visit(tree, 'heading', (node) => {
if (!generated(node)) {
visit(tree, 'heading', function (node) {
const place = position(node)
if (place) {
if (previous && node.depth > previous + 1) {
file.message(
'Heading levels should increment by one level at a time',
node
place
)
}

View File

@ -37,9 +37,8 @@
],
"dependencies": {
"@types/mdast": "^4.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0",
"unist-util-generated": "^3.0.0",
"unist-util-position": "^5.0.0",
"unist-util-visit": "^5.0.0"
},
"scripts": {},

View File

@ -117,28 +117,38 @@
*/
/**
* @typedef {Type | 'consistent'} Options
* Configuration.
*
* @typedef {'atx' | 'atx-closed' | 'setext'} Type
* Styles.
* @typedef {'consistent' | Type} Options
* Options.
*/
import {lintRule} from 'unified-lint-rule'
import {visit} from 'unist-util-visit'
import {headingStyle} from 'mdast-util-heading-style'
import {generated} from 'unist-util-generated'
import {lintRule} from 'unified-lint-rule'
import {position} from 'unist-util-position'
import {visit} from 'unist-util-visit'
const remarkLintHeadingStyle = lintRule(
{
origin: 'remark-lint:heading-style',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-heading-style#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, Options>} */
(tree, file, option = 'consistent') => {
/**
* @param {Root} tree
* Tree.
* @param {Options | null | undefined} [options='consistent']
* Configuration (default: `'consistent'`).
* @returns {undefined}
* Nothing.
*/
function (tree, file, options) {
let option = options || 'consistent'
if (
option !== 'consistent' &&
option !== 'atx' &&
option !== 'atx-closed' &&
option !== 'consistent' &&
option !== 'setext'
) {
file.fail(
@ -148,14 +158,15 @@ const remarkLintHeadingStyle = lintRule(
)
}
visit(tree, 'heading', (node) => {
if (!generated(node)) {
visit(tree, 'heading', function (node) {
const place = position(node)
if (place) {
if (option === 'consistent') {
// Funky nodes perhaps cannot be detected.
/* c8 ignore next */
/* c8 ignore next -- funky nodes perhaps cannot be detected. */
option = headingStyle(node) || 'consistent'
} else if (headingStyle(node, option) !== option) {
file.message('Headings should use ' + option, node)
file.message('Headings should use ' + option, place)
}
}
})

View File

@ -39,9 +39,8 @@
"dependencies": {
"@types/mdast": "^4.0.0",
"mdast-util-heading-style": "^3.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0",
"unist-util-generated": "^3.0.0",
"unist-util-position": "^5.0.0",
"unist-util-visit": "^5.0.0"
},
"scripts": {},
@ -54,7 +53,8 @@
"xo": {
"prettier": true,
"rules": {
"capitalized-comments": "off"
"capitalized-comments": "off",
"unicorn/prefer-default-parameters": "off"
}
}
}

View File

@ -72,7 +72,7 @@
/**
* @typedef {'unix' | 'windows'} Type
* Styles.
* @typedef {'consistent' | Type} Options
* @typedef {Type | 'consistent'} Options
* Options.
*/
@ -86,8 +86,16 @@ const remarkLintLinebreakStyle = lintRule(
origin: 'remark-lint:linebreak-style',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-linebreak-style#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, Options>} */
(_, file, option = 'consistent') => {
/**
* @param {Root} _
* Tree.
* @param {Options | null | undefined} [options='consistent']
* Configuration (default: `'consistent'`).
* @returns {undefined}
* Nothing.
*/
function (_, file, options) {
let option = options || 'consistent'
const value = String(file)
const toPoint = location(value).toPoint
let index = value.indexOf('\n')

View File

@ -41,7 +41,6 @@
],
"dependencies": {
"@types/mdast": "^4.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0",
"vfile-location": "^5.0.0"
},
@ -55,7 +54,8 @@
"xo": {
"prettier": true,
"rules": {
"capitalized-comments": "off"
"capitalized-comments": "off",
"unicorn/prefer-default-parameters": "off"
}
}
}

View File

@ -128,16 +128,15 @@
/**
* @typedef {'"' | '\'' | '()'} Marker
* Styles.
* @typedef {'consistent' | Marker} Options
* Options.
*
* @typedef {Marker | 'consistent'} Options
* Configuration.
*/
import {lintRule} from 'unified-lint-rule'
import {location} from 'vfile-location'
import {pointEnd, pointStart} from 'unist-util-position'
import {visit} from 'unist-util-visit'
import {pointStart, pointEnd} from 'unist-util-position'
const own = {}.hasOwnProperty
import {location} from 'vfile-location'
const markers = {
'"': '"',
@ -150,14 +149,22 @@ const remarkLintLinkTitleStyle = lintRule(
origin: 'remark-lint:link-title-style',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-link-title-style#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, Options>} */
(tree, file, option = 'consistent') => {
/**
* @param {Root} tree
* Tree.
* @param {Options | null | undefined} [options='consistent']
* Configuration (default: `'consistent'`).
* @returns {undefined}
* Nothing.
*/
function (tree, file, options) {
const value = String(file)
const loc = location(file)
// @ts-expect-error: allow other paren combos.
const option = options || 'consistent'
// @ts-expect-error: allow `(` too, even though untyped.
let look = option === '()' || option === '(' ? ')' : option
if (look !== 'consistent' && !own.call(markers, look)) {
if (look !== 'consistent' && !Object.hasOwn(markers, look)) {
file.fail(
'Incorrect link title style marker `' +
look +
@ -165,11 +172,11 @@ const remarkLintLinkTitleStyle = lintRule(
)
}
visit(tree, (node) => {
visit(tree, function (node) {
if (
node.type === 'link' ||
node.type === 'definition' ||
node.type === 'image' ||
node.type === 'definition'
node.type === 'link'
) {
const tail =
'children' in node
@ -216,13 +223,14 @@ const remarkLintLinkTitleStyle = lintRule(
} else if (look !== final) {
const start = loc.toPoint(first)
const end = loc.toPoint(last + 1)
/* c8 ignore next -- we get here if we have offsets. */
const place = start && end ? {start, end} : undefined
file.message(
'Titles should use `' +
(look === ')' ? '()' : look) +
'` as a quote',
/* c8 ignore next -- we get here if we have offsets. */
start && end ? {start, end} : undefined
place
)
}
}

View File

@ -38,7 +38,6 @@
],
"dependencies": {
"@types/mdast": "^4.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0",
"unist-util-position": "^5.0.0",
"unist-util-visit": "^5.0.0",

View File

@ -62,8 +62,9 @@
* @typedef {import('mdast').Root} Root
*/
import {lintRule} from 'unified-lint-rule'
import plural from 'pluralize'
import {lintRule} from 'unified-lint-rule'
import {pointStart} from 'unist-util-position'
import {visit} from 'unist-util-visit'
const remarkLintListItemBulletIndent = lintRule(
@ -71,24 +72,28 @@ const remarkLintListItemBulletIndent = lintRule(
origin: 'remark-lint:list-item-bullet-indent',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-list-item-bullet-indent#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, void>} */
(tree, file) => {
visit(tree, 'list', (list, _, grandparent) => {
/**
* @param {Root} tree
* Tree.
* @returns {undefined}
* Nothing.
*/
function (tree, file) {
visit(tree, 'list', function (list, _, grandparent) {
let index = -1
const pointStartGrandparent = pointStart(grandparent)
while (++index < list.children.length) {
const item = list.children[index]
const itemStart = pointStart(item)
if (
grandparent &&
grandparent.type === 'root' &&
grandparent.position &&
typeof grandparent.position.start.column === 'number' &&
item.position &&
typeof item.position.start.column === 'number'
pointStartGrandparent &&
itemStart &&
grandparent.type === 'root'
) {
const indent =
item.position.start.column - grandparent.position.start.column
const indent = itemStart.column - pointStartGrandparent.column
if (indent) {
file.message(
@ -96,7 +101,7 @@ const remarkLintListItemBulletIndent = lintRule(
indent +
' ' +
plural('space', indent),
item.position.start
itemStart
)
}
}

View File

@ -38,8 +38,8 @@
"dependencies": {
"@types/mdast": "^4.0.0",
"pluralize": "^8.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0",
"unist-util-position": "^5.0.0",
"unist-util-visit": "^5.0.0"
},
"scripts": {},

View File

@ -45,21 +45,26 @@
* @typedef {import('mdast').Root} Root
*/
import {lintRule} from 'unified-lint-rule'
import plural from 'pluralize'
import {visit} from 'unist-util-visit'
import {lintRule} from 'unified-lint-rule'
import {pointStart} from 'unist-util-position'
import {visit} from 'unist-util-visit'
const remarkLintListItemContentIndent = lintRule(
{
origin: 'remark-lint:list-item-content-indent',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-list-item-content-indent#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, void>} */
(tree, file) => {
/**
* @param {Root} tree
* Tree.
* @returns {undefined}
* Nothing.
*/
function (tree, file) {
const value = String(file)
visit(tree, 'listItem', (node) => {
visit(tree, 'listItem', function (node) {
let index = -1
/** @type {number | undefined} */
let style
@ -68,11 +73,7 @@ const remarkLintListItemContentIndent = lintRule(
const item = node.children[index]
const begin = pointStart(item)
if (
!begin ||
typeof begin.column !== 'number' ||
typeof begin.offset !== 'number'
) {
if (!begin || typeof begin.offset !== 'number') {
continue
}

View File

@ -39,7 +39,6 @@
"dependencies": {
"@types/mdast": "^4.0.0",
"pluralize": "^8.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0",
"unist-util-position": "^5.0.0",
"unist-util-visit": "^5.0.0"

View File

@ -155,26 +155,33 @@
*/
/**
* @typedef {'tab-size' | 'space' | 'mixed'} Options
* Options.
* @typedef {'mixed' | 'space' | 'tab-size'} Options
* Configuration.
*/
import {lintRule} from 'unified-lint-rule'
import plural from 'pluralize'
import {visit} from 'unist-util-visit'
import {lintRule} from 'unified-lint-rule'
import {pointStart} from 'unist-util-position'
import {generated} from 'unist-util-generated'
import {visit} from 'unist-util-visit'
const remarkLintListItemIndent = lintRule(
{
origin: 'remark-lint:list-item-indent',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-list-item-indent#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, Options>} */
(tree, file, option = 'tab-size') => {
/**
* @param {Root} tree
* Tree.
* @param {Options | null | undefined} [options='tab-size']
* Configuration (default: `'tab-size'`).
* @returns {undefined}
* Nothing.
*/
function (tree, file, options) {
const value = String(file)
const option = options || 'tab-size'
if (option !== 'tab-size' && option !== 'space' && option !== 'mixed') {
if (option !== 'mixed' && option !== 'space' && option !== 'tab-size') {
file.fail(
'Incorrect list-item indent style `' +
option +
@ -182,9 +189,7 @@ const remarkLintListItemIndent = lintRule(
)
}
visit(tree, 'list', (node) => {
if (generated(node)) return
visit(tree, 'list', function (node) {
const spread = node.spread
let index = -1

View File

@ -38,9 +38,7 @@
"dependencies": {
"@types/mdast": "^4.0.0",
"pluralize": "^8.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0",
"unist-util-generated": "^3.0.0",
"unist-util-position": "^5.0.0",
"unist-util-visit": "^5.0.0"
},

View File

@ -132,56 +132,68 @@
*/
/**
* @typedef {import('mdast').Root} Root
* @typedef {import('mdast').ListItem} ListItem
*
* @typedef {import('mdast').Root} Root
*/
/**
* @typedef Options
* Options.
* Configuration.
* @property {boolean | null | undefined} [checkBlanks=false]
* Adhere to CommonMark looseness instead of markdown-style-guide preference.
* Follow CommonMark looseness instead of markdown-style-guide preference
* (default: `false`).
*/
import {lintRule} from 'unified-lint-rule'
import {pointEnd, pointStart} from 'unist-util-position'
import {visit} from 'unist-util-visit'
import {pointStart, pointEnd} from 'unist-util-position'
import {generated} from 'unist-util-generated'
/** @type {Readonly<Options>} */
const emptyOptions = {}
const remarkLintListItemSpacing = lintRule(
{
origin: 'remark-lint:list-item-spacing',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-list-item-spacing#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, Options>} */
(tree, file, option = {}) => {
const {checkBlanks} = option
/**
* @param {Root} tree
* Tree.
* @param {Readonly<Options> | null | undefined} [options]
* Configuration (optional).
* @returns {undefined}
* Nothing.
*/
function (tree, file, options) {
// To do: change options? Follow CM by default?
const settings = options || emptyOptions
const checkBlanks = settings.checkBlanks || false
const infer = checkBlanks ? inferBlankLine : inferMultiline
visit(tree, 'list', (node) => {
if (!generated(node)) {
let tight = true
let index = -1
visit(tree, 'list', function (node) {
let tight = true
let index = -1
while (++index < node.children.length) {
if (infer(node.children[index])) {
tight = false
break
}
while (++index < node.children.length) {
if (infer(node.children[index])) {
tight = false
break
}
}
index = 0 // Skip over first.
index = 0 // Skip over first.
while (++index < node.children.length) {
const start = pointEnd(node.children[index - 1])
const end = pointStart(node.children[index])
while (++index < node.children.length) {
const start = pointEnd(node.children[index - 1])
const end = pointStart(node.children[index])
if (start && end && end.line - start.line < 2 !== tight) {
file.message(
tight
? 'Extraneous new line after list item'
: 'Missing new line after list item',
{start, end}
)
}
if (start && end && end.line - start.line < 2 !== tight) {
file.message(
tight
? 'Extraneous new line after list item'
: 'Missing new line after list item',
{start, end}
)
}
}
})
@ -192,7 +204,9 @@ export default remarkLintListItemSpacing
/**
* @param {ListItem} node
* Item.
* @returns {boolean}
* Whether theres a blank line between item children.
*/
function inferBlankLine(node) {
let index = 0
@ -212,7 +226,9 @@ function inferBlankLine(node) {
/**
* @param {ListItem} node
* Item.
* @returns {boolean}
* Whether `node` is multiline.
*/
function inferMultiline(node) {
const end = pointEnd(node.children[node.children.length - 1])

View File

@ -38,9 +38,7 @@
],
"dependencies": {
"@types/mdast": "^4.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0",
"unist-util-generated": "^3.0.0",
"unist-util-position": "^5.0.0",
"unist-util-visit": "^5.0.0"
},

View File

@ -48,26 +48,32 @@
* @typedef {import('mdast').Root} Root
*/
/**
* @typedef {number} Options
* Options.
*/
import {lintRule} from 'unified-lint-rule'
import {visit} from 'unist-util-visit'
import {generated} from 'unist-util-generated'
import {toString} from 'mdast-util-to-string'
import {lintRule} from 'unified-lint-rule'
import {position} from 'unist-util-position'
import {visit} from 'unist-util-visit'
const remarkLintMaximumHeadingLength = lintRule(
{
origin: 'remark-lint:maximum-heading-length',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-maximum-heading-length#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, Options>} */
(tree, file, option = 60) => {
visit(tree, 'heading', (node) => {
if (!generated(node) && toString(node).length > option) {
file.message('Use headings shorter than `' + option + '`', node)
/**
* @param {Root} tree
* Tree.
* @param {number | null | undefined} [options=60]
* Configuration (default: `60`).
* @returns {undefined}
* Nothing.
*/
function (tree, file, options) {
const option = options || 60
visit(tree, 'heading', function (node) {
const place = position(node)
if (place && toString(node).length > option) {
file.message('Use headings shorter than `' + option + '`', place)
}
})
}

View File

@ -37,9 +37,8 @@
"dependencies": {
"@types/mdast": "^4.0.0",
"mdast-util-to-string": "^4.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0",
"unist-util-generated": "^3.0.0",
"unist-util-position": "^5.0.0",
"unist-util-visit": "^5.0.0"
},
"scripts": {},
@ -52,7 +51,8 @@
"xo": {
"prettier": true,
"rules": {
"capitalized-comments": "off"
"capitalized-comments": "off",
"unicorn/prefer-default-parameters": "off"
}
}
}

View File

@ -111,32 +111,37 @@
* @typedef {import('mdast').Root} Root
*/
/**
* @typedef {number} Options
* Options.
*/
import {lintRule} from 'unified-lint-rule'
import {pointEnd, pointStart} from 'unist-util-position'
import {visit} from 'unist-util-visit'
import {pointStart, pointEnd} from 'unist-util-position'
const remarkLintMaximumLineLength = lintRule(
{
origin: 'remark-lint:maximum-line-length',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-maximum-line-length#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, Options>} */
(tree, file, option = 80) => {
/**
* @param {Root} tree
* Tree.
* @param {number | null | undefined} [options=80]
* Configuration (default: `80`).
* @returns {undefined}
* Nothing.
*/
function (tree, file, options) {
const value = String(file)
const lines = value.split(/\r?\n/)
const option = options || 80
visit(tree, (node) => {
visit(tree, function (node) {
// To do: add MDX types, etc.
// To do: remove MDX 1?
if (
node.type === 'heading' ||
node.type === 'table' ||
node.type === 'code' ||
node.type === 'definition' ||
node.type === 'heading' ||
node.type === 'html' ||
node.type === 'table' ||
// @ts-expect-error: These are from MDX@1 and MDX@2: <https://github.com/mdx-js/specification>.
node.type === 'jsx' ||
// @ts-expect-error: MDX
@ -149,14 +154,14 @@ const remarkLintMaximumLineLength = lintRule(
node.type === 'mdxTextExpression' ||
// @ts-expect-error: MDX
node.type === 'mdxjsEsm' ||
node.type === 'yaml' ||
// @ts-expect-error: YAML and TOML are from frontmatter.
node.type === 'toml'
// @ts-expect-error: TOML from frontmatter.
node.type === 'toml' ||
node.type === 'yaml'
) {
const start = pointStart(node)
const end = pointEnd(node)
const start = pointStart(node)
if (start && end) {
if (end && start) {
allowList(start.line - 1, end.line)
}
}
@ -166,14 +171,14 @@ const remarkLintMaximumLineLength = lintRule(
// the wrap.
// However, when they do, and theres whitespace after it, they are not
// allowed.
visit(tree, (node, pos, parent) => {
const initial = pointStart(node)
visit(tree, function (node, pos, parent) {
const final = pointEnd(node)
const initial = pointStart(node)
if (
(node.type === 'link' ||
node.type === 'image' ||
node.type === 'inlineCode') &&
(node.type === 'image' ||
node.type === 'inlineCode' ||
node.type === 'link') &&
initial &&
final &&
parent &&
@ -219,7 +224,11 @@ const remarkLintMaximumLineLength = lintRule(
* Allowlist from `initial` to `final`, zero-based.
*
* @param {number} initial
* Initial line.
* @param {number} final
* Final line.
* @returns {undefined}
* Nothing.
*/
function allowList(initial, final) {
while (initial < final) {

View File

@ -36,7 +36,6 @@
],
"dependencies": {
"@types/mdast": "^4.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0",
"unist-util-position": "^5.0.0",
"unist-util-visit": "^5.0.0"

View File

@ -35,10 +35,10 @@
* @typedef {import('mdast').Root} Root
*/
import {lintRule} from 'unified-lint-rule'
import {visit} from 'unist-util-visit'
import {pointStart, pointEnd} from 'unist-util-position'
import {toString} from 'mdast-util-to-string'
import {lintRule} from 'unified-lint-rule'
import {pointEnd, pointStart} from 'unist-util-position'
import {visit} from 'unist-util-visit'
// Protocol expression.
// See: <https://en.wikipedia.org/wiki/URI_scheme#Generic_syntax>.
@ -49,9 +49,14 @@ const remarkLintNoAutoLinkWithoutProtocol = lintRule(
origin: 'remark-lint:no-auto-link-without-protocol',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-no-auto-link-without-protocol#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, void>} */
(tree, file) => {
visit(tree, 'link', (node) => {
/**
* @param {Root} tree
* Tree.
* @returns {undefined}
* Nothing.
*/
function (tree, file) {
visit(tree, 'link', function (node) {
const end = pointEnd(node)
const headStart = pointStart(node.children[0])
const start = pointStart(node)
@ -62,8 +67,8 @@ const remarkLintNoAutoLinkWithoutProtocol = lintRule(
headStart &&
start &&
tailEnd &&
start.column === headStart.column - 1 &&
end.column === tailEnd.column + 1 &&
start.column === headStart.column - 1 &&
!protocol.test(toString(node))
) {
file.message('All automatic links must start with a protocol', node)

View File

@ -38,7 +38,6 @@
"dependencies": {
"@types/mdast": "^4.0.0",
"mdast-util-to-string": "^4.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0",
"unist-util-position": "^5.0.0",
"unist-util-visit": "^5.0.0"

View File

@ -68,21 +68,26 @@
*/
import {lintRule} from 'unified-lint-rule'
import {location} from 'vfile-location'
import {pointEnd, pointStart} from 'unist-util-position'
import {visit} from 'unist-util-visit'
import {pointStart, pointEnd} from 'unist-util-position'
import {location} from 'vfile-location'
const remarkLintNoBlockquoteWithoutMarker = lintRule(
{
origin: 'remark-lint:no-blockquote-without-marker',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-no-blockquote-without-marker#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, void>} */
(tree, file) => {
/**
* @param {Root} tree
* Tree.
* @returns {undefined}
* Nothing.
*/
function (tree, file) {
const value = String(file)
const loc = location(file)
visit(tree, 'blockquote', (node) => {
visit(tree, 'blockquote', function (node) {
let index = -1
while (++index < node.children.length) {

View File

@ -37,7 +37,6 @@
],
"dependencies": {
"@types/mdast": "^4.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0",
"unist-util-position": "^5.0.0",
"unist-util-visit": "^5.0.0",

View File

@ -56,10 +56,10 @@
* @typedef {import('unist').Point} Point
*/
import {lintRule} from 'unified-lint-rule'
import plural from 'pluralize'
import {lintRule} from 'unified-lint-rule'
import {pointEnd, pointStart} from 'unist-util-position'
import {visit} from 'unist-util-visit'
import {pointStart, pointEnd} from 'unist-util-position'
const unknownContainerSize = new Set(['mdxJsxFlowElement', 'mdxJsxTextElement'])
@ -68,15 +68,20 @@ const remarkLintNoConsecutiveBlankLines = lintRule(
origin: 'remark-lint:no-consecutive-blank-lines',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-no-consecutive-blank-lines#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, void>} */
(tree, file) => {
visit(tree, (node) => {
/**
* @param {Root} tree
* Tree.
* @returns {undefined}
* Nothing.
*/
function (tree, file) {
visit(tree, function (node) {
if ('children' in node) {
const head = node.children[0]
const start = pointStart(node)
const head = node.children[0]
const headStart = pointStart(head)
if (head && start && headStart) {
if (head && headStart && start) {
if (!unknownContainerSize.has(node.type)) {
// Compare parent and first child.
compare(start, headStart, 0)
@ -118,8 +123,13 @@ const remarkLintNoConsecutiveBlankLines = lintRule(
* difference exceeds `max`.
*
* @param {Point} start
* Start.
* @param {Point} end
* End.
* @param {0 | 1 | 2} max
* Max.
* @returns {undefined}
* Nothing.
*/
function compare(start, end, max) {
const diff = end.line - start.line

View File

@ -38,7 +38,6 @@
"@types/mdast": "^4.0.0",
"@types/unist": "^3.0.0",
"pluralize": "^8.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0",
"unist-util-position": "^5.0.0",
"unist-util-visit": "^5.0.0"

View File

@ -41,8 +41,7 @@
*/
import {lintRule} from 'unified-lint-rule'
import {pointStart} from 'unist-util-position'
import {generated} from 'unist-util-generated'
import {pointStart, position} from 'unist-util-position'
import {stringifyPosition} from 'unist-util-stringify-position'
import {visit} from 'unist-util-visit'
@ -51,26 +50,34 @@ const remarkLintNoDuplicateDefinedUrls = lintRule(
origin: 'remark-lint:no-duplicate-defined-urls',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-no-duplicate-defined-urls#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, void>} */
(tree, file) => {
/** @type {Record<string, string>} */
const map = Object.create(null)
/**
* @param {Root} tree
* Tree.
* @returns {undefined}
* Nothing.
*/
function (tree, file) {
/** @type {Map<string, string>} */
const map = new Map()
visit(tree, 'definition', (node) => {
if (!generated(node) && node.url) {
visit(tree, 'definition', function (node) {
const place = position(node)
const start = pointStart(node)
if (place && start && node.url) {
const url = String(node.url).toUpperCase()
const duplicate = map[url]
const duplicate = map.get(url)
if (duplicate) {
file.message(
'Do not use different definitions with the same URL (' +
duplicate +
')',
node
place
)
}
map[url] = stringifyPosition(pointStart(node))
map.set(url, stringifyPosition(start))
}
})
}

View File

@ -37,9 +37,7 @@
],
"dependencies": {
"@types/mdast": "^4.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0",
"unist-util-generated": "^3.0.0",
"unist-util-position": "^5.0.0",
"unist-util-stringify-position": "^4.0.0",
"unist-util-visit": "^5.0.0"

View File

@ -40,8 +40,7 @@
*/
import {lintRule} from 'unified-lint-rule'
import {pointStart} from 'unist-util-position'
import {generated} from 'unist-util-generated'
import {pointStart, position} from 'unist-util-position'
import {stringifyPosition} from 'unist-util-stringify-position'
import {visit} from 'unist-util-visit'
@ -50,29 +49,38 @@ const remarkLintNoDuplicateDefinitions = lintRule(
origin: 'remark-lint:no-duplicate-definitions',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-no-duplicate-definitions#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, void>} */
(tree, file) => {
/** @type {Record<string, string>} */
const map = Object.create(null)
/**
* @param {Root} tree
* Tree.
* @returns {undefined}
* Nothing.
*/
function (tree, file) {
/** @type {Map<string, string>} */
const map = new Map()
visit(tree, function (node) {
const place = position(node)
const start = pointStart(node)
visit(tree, (node) => {
if (
(node.type === 'definition' || node.type === 'footnoteDefinition') &&
!generated(node)
place &&
start
) {
const identifier = node.identifier
const duplicate = map[identifier]
const duplicate = map.get(identifier)
if (duplicate) {
file.message(
'Do not use definitions with the same identifier (' +
duplicate +
')',
node
place
)
}
map[identifier] = stringifyPosition(pointStart(node))
map.set(identifier, stringifyPosition(start))
}
})
}

View File

@ -36,9 +36,7 @@
],
"dependencies": {
"@types/mdast": "^4.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0",
"unist-util-generated": "^3.0.0",
"unist-util-position": "^5.0.0",
"unist-util-stringify-position": "^4.0.0",
"unist-util-visit": "^5.0.0"

View File

@ -77,41 +77,47 @@
* @typedef {import('mdast').Root} Root
*/
import {lintRule} from 'unified-lint-rule'
import {pointStart} from 'unist-util-position'
import {generated} from 'unist-util-generated'
import {visit} from 'unist-util-visit'
import {stringifyPosition} from 'unist-util-stringify-position'
import {toString} from 'mdast-util-to-string'
import {lintRule} from 'unified-lint-rule'
import {pointStart, position} from 'unist-util-position'
import {stringifyPosition} from 'unist-util-stringify-position'
import {visit} from 'unist-util-visit'
const remarkLintNoDuplicateHeadingsInSection = lintRule(
{
origin: 'remark-lint:no-duplicate-headings-in-section',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-no-duplicate-headings-in-section#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, void>} */
(tree, file) => {
/** @type {Array<Record<string, Heading>>} */
let stack = []
/**
* @param {Root} tree
* Tree.
* @returns {undefined}
* Nothing.
*/
function (tree, file) {
/** @type {Array<Map<string, string>>} */
const stack = []
visit(tree, 'heading', (node) => {
const depth = node.depth
visit(tree, 'heading', function (node) {
const value = toString(node).toUpperCase()
const index = depth - 1
const scope = stack[index] || (stack[index] = {})
const duplicate = scope[value]
const index = node.depth - 1
const scope = stack[index] || (stack[index] = new Map())
const duplicate = scope.get(value)
const place = position(node)
const start = pointStart(node)
if (!generated(node) && duplicate) {
if (place && duplicate) {
file.message(
'Do not use headings with similar content per section (' +
stringifyPosition(pointStart(duplicate)) +
duplicate +
')',
node
place
)
}
scope[value] = node
stack = stack.slice(0, depth)
scope.set(value, stringifyPosition(start))
// Drop things after it.
stack.length = node.depth
})
}
)

View File

@ -38,9 +38,7 @@
"dependencies": {
"@types/mdast": "^4.0.0",
"mdast-util-to-string": "^4.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0",
"unist-util-generated": "^3.0.0",
"unist-util-position": "^5.0.0",
"unist-util-stringify-position": "^4.0.0",
"unist-util-visit": "^5.0.0"

View File

@ -51,27 +51,34 @@
* @typedef {import('mdast').Root} Root
*/
import {lintRule} from 'unified-lint-rule'
import {pointStart} from 'unist-util-position'
import {generated} from 'unist-util-generated'
import {visit} from 'unist-util-visit'
import {stringifyPosition} from 'unist-util-stringify-position'
import {toString} from 'mdast-util-to-string'
import {lintRule} from 'unified-lint-rule'
import {pointStart, position} from 'unist-util-position'
import {stringifyPosition} from 'unist-util-stringify-position'
import {visit} from 'unist-util-visit'
const remarkLintNoDuplicateHeadings = lintRule(
{
origin: 'remark-lint:no-duplicate-headings',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-no-duplicate-headings#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, void>} */
(tree, file) => {
/** @type {Record<string, string>} */
const map = Object.create(null)
/**
* @param {Root} tree
* Tree.
* @returns {undefined}
* Nothing.
*/
function (tree, file) {
/** @type {Map<string, string>} */
const map = new Map()
visit(tree, 'heading', (node) => {
if (!generated(node)) {
visit(tree, 'heading', function (node) {
const place = position(node)
const start = pointStart(node)
if (place && start) {
const value = toString(node).toUpperCase()
const duplicate = map[value]
const duplicate = map.get(value)
if (duplicate) {
file.message(
@ -80,7 +87,7 @@ const remarkLintNoDuplicateHeadings = lintRule(
)
}
map[value] = stringifyPosition(pointStart(node))
map.set(value, stringifyPosition(start))
}
})
}

View File

@ -37,9 +37,7 @@
"dependencies": {
"@types/mdast": "^4.0.0",
"mdast-util-to-string": "^4.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0",
"unist-util-generated": "^3.0.0",
"unist-util-position": "^5.0.0",
"unist-util-stringify-position": "^4.0.0",
"unist-util-visit": "^5.0.0"

View File

@ -52,22 +52,28 @@
import {lintRule} from 'unified-lint-rule'
import {visit} from 'unist-util-visit'
import {generated} from 'unist-util-generated'
import {position} from 'unist-util-position'
const remarkLintNoEmphasisAsHeading = lintRule(
{
origin: 'remark-lint:no-emphasis-as-heading',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-no-emphasis-as-heading#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, void>} */
(tree, file) => {
visit(tree, 'paragraph', (node, index, parent) => {
/**
* @param {Root} tree
* Tree.
* @returns {undefined}
* Nothing.
*/
function (tree, file) {
visit(tree, 'paragraph', function (node, index, parent) {
const head = node.children[0]
const place = position(node)
if (
place &&
parent &&
typeof index === 'number' &&
!generated(node) &&
node.children.length === 1 &&
(head.type === 'emphasis' || head.type === 'strong')
) {
@ -81,7 +87,7 @@ const remarkLintNoEmphasisAsHeading = lintRule(
) {
file.message(
'Dont use emphasis to introduce a section, use a heading',
node
place
)
}
}

View File

@ -36,9 +36,8 @@
],
"dependencies": {
"@types/mdast": "^4.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0",
"unist-util-generated": "^3.0.0",
"unist-util-position": "^5.0.0",
"unist-util-visit": "^5.0.0"
},
"scripts": {},

View File

@ -54,25 +54,32 @@
*/
import {lintRule} from 'unified-lint-rule'
import {position} from 'unist-util-position'
import {visit} from 'unist-util-visit'
import {generated} from 'unist-util-generated'
const remarkLintNoEmptyUrl = lintRule(
{
origin: 'remark-lint:no-empty-url',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-no-empty-url#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, void>} */
(tree, file) => {
visit(tree, (node) => {
/**
* @param {Root} tree
* Tree.
* @returns {undefined}
* Nothing.
*/
function (tree, file) {
visit(tree, function (node) {
const place = position(node)
if (
(node.type === 'link' ||
(node.type === 'definition' ||
node.type === 'image' ||
node.type === 'definition') &&
!generated(node) &&
node.type === 'link') &&
place &&
!node.url
) {
file.message('Dont use ' + node.type + 's without URL', node)
file.message('Dont use ' + node.type + 's without URL', place)
}
})
}

View File

@ -38,9 +38,8 @@
],
"dependencies": {
"@types/mdast": "^4.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0",
"unist-util-generated": "^3.0.0",
"unist-util-position": "^5.0.0",
"unist-util-visit": "^5.0.0"
},
"scripts": {},

View File

@ -49,8 +49,13 @@ const remarkLintNoFileNameArticles = lintRule(
origin: 'remark-lint:no-file-name-articles',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-no-file-name-articles#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, void>} */
(_, file) => {
/**
* @param {Root} _
* Tree.
* @returns {undefined}
* Nothing.
*/
function (_, file) {
const match = file.stem && file.stem.match(/^(the|teh|an?)\b/i)
if (match) {

View File

@ -38,7 +38,6 @@
],
"dependencies": {
"@types/mdast": "^4.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0"
},
"scripts": {},

View File

@ -34,8 +34,13 @@ const remarkLintNoFileNameConsecutiveDashes = lintRule(
origin: 'remark-lint:no-file-name-consecutive-dashes',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-no-file-name-consecutive-dashes#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, void>} */
(_, file) => {
/**
* @param {Root} _
* Tree.
* @returns {undefined}
* Nothing.
*/
function (_, file) {
if (file.stem && /-{2,}/.test(file.stem)) {
file.message('Do not use consecutive dashes in a file name')
}

View File

@ -39,7 +39,6 @@
],
"dependencies": {
"@types/mdast": "^4.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0"
},
"scripts": {},

View File

@ -47,7 +47,7 @@
/**
* @typedef {RegExp | string} Options
* Options.
* Configuration.
*/
import {lintRule} from 'unified-lint-rule'
@ -59,9 +59,16 @@ const remarkLintNoFileNameIrregularCharacters = lintRule(
origin: 'remark-lint:no-file-name-irregular-characters',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-no-file-name-irregular-characters#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, Options>} */
(_, file, option) => {
let preferred = option || expression
/**
* @param {Root} _
* Tree.
* @param {Options | null | undefined} [options]
* Configuration (default: `/[^\\.a-zA-Z\d-]/`).
* @returns {undefined}
* Nothing.
*/
function (_, file, options) {
let preferred = options || expression
if (typeof preferred === 'string') {
preferred = new RegExp('[^' + preferred + ']')

View File

@ -38,7 +38,6 @@
],
"dependencies": {
"@types/mdast": "^4.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0"
},
"scripts": {},

View File

@ -37,8 +37,13 @@ const remarkLintNofileNameMixedCase = lintRule(
origin: 'remark-lint:no-file-name-mixed-case',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-no-file-name-mixed-case#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, void>} */
(_, file) => {
/**
* @param {Root} _
* Tree.
* @returns {undefined}
* Nothing.
*/
function (_, file) {
const name = file.stem
if (name && !(name === name.toLowerCase() || name === name.toUpperCase())) {

View File

@ -37,7 +37,6 @@
],
"dependencies": {
"@types/mdast": "^4.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0"
},
"scripts": {},

View File

@ -39,8 +39,13 @@ const remarkLintNofileNameOuterDashes = lintRule(
origin: 'remark-lint:no-file-name-outer-dashes',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-no-file-name-outer-dashes#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, void>} */
(_, file) => {
/**
* @param {Root} _
* Tree.
* @returns {undefined}
* Nothing.
*/
function (_, file) {
if (file.stem && /^-|-$/.test(file.stem)) {
file.message('Do not use initial or final dashes in a file name')
}

View File

@ -38,7 +38,6 @@
],
"dependencies": {
"@types/mdast": "^4.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0"
},
"scripts": {},

View File

@ -65,20 +65,25 @@
* @typedef {import('mdast').Root} Root
*/
import {lintRule} from 'unified-lint-rule'
import {visit} from 'unist-util-visit'
import {headingStyle} from 'mdast-util-heading-style'
import plural from 'pluralize'
import {pointStart, pointEnd} from 'unist-util-position'
import {lintRule} from 'unified-lint-rule'
import {pointEnd, pointStart} from 'unist-util-position'
import {visit} from 'unist-util-visit'
const remarkLintNoHeadingContentIndent = lintRule(
{
origin: 'remark-lint:no-heading-content-indent',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-no-heading-content-indent#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, void>} */
(tree, file) => {
visit(tree, 'heading', (node) => {
/**
* @param {Root} tree
* Tree.
* @returns {undefined}
* Nothing.
*/
function (tree, file) {
visit(tree, 'heading', function (node) {
const start = pointStart(node)
const type = headingStyle(node, 'atx')

View File

@ -39,7 +39,6 @@
"@types/mdast": "^4.0.0",
"mdast-util-heading-style": "^3.0.0",
"pluralize": "^8.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0",
"unist-util-position": "^5.0.0",
"unist-util-visit": "^5.0.0"

View File

@ -74,19 +74,24 @@
* @typedef {import('mdast').Root} Root
*/
import {lintRule} from 'unified-lint-rule'
import plural from 'pluralize'
import {visit} from 'unist-util-visit'
import {lintRule} from 'unified-lint-rule'
import {pointStart} from 'unist-util-position'
import {visit} from 'unist-util-visit'
const remarkLintNoHeadingIndent = lintRule(
{
origin: 'remark-lint:no-heading-indent',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-no-heading-indent#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, void>} */
(tree, file) => {
visit(tree, 'heading', (node, _, parent) => {
/**
* @param {Root} tree
* Tree.
* @returns {undefined}
* Nothing.
*/
function (tree, file) {
visit(tree, 'heading', function (node, _, parent) {
const start = pointStart(node)
// Note: its rather complex to detect what the expected indent is in block
@ -104,7 +109,7 @@ const remarkLintNoHeadingIndent = lintRule(
' ' +
plural('space', diff) +
' before this heading',
pointStart(node)
start
)
}
})

View File

@ -37,7 +37,6 @@
"dependencies": {
"@types/mdast": "^4.0.0",
"pluralize": "^8.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0",
"unist-util-position": "^5.0.0",
"unist-util-visit": "^5.0.0"

View File

@ -40,8 +40,8 @@
*/
import {lintRule} from 'unified-lint-rule'
import {position} from 'unist-util-position'
import {visit} from 'unist-util-visit'
import {generated} from 'unist-util-generated'
const fence = '#######'
@ -50,10 +50,17 @@ const remarkLintNoHeadingLikeParagraph = lintRule(
origin: 'remark-lint:no-heading-like-paragraph',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-no-heading-like-paragraph#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, void>} */
(tree, file) => {
visit(tree, 'paragraph', (node) => {
if (!generated(node)) {
/**
* @param {Root} tree
* Tree.
* @returns {undefined}
* Nothing.
*/
function (tree, file) {
visit(tree, 'paragraph', function (node) {
const place = position(node)
if (place) {
const head = node.children[0]
if (
@ -63,7 +70,7 @@ const remarkLintNoHeadingLikeParagraph = lintRule(
) {
file.message(
'This looks like a heading but has too many hashes',
node
place
)
}
}

View File

@ -36,9 +36,8 @@
],
"dependencies": {
"@types/mdast": "^4.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0",
"unist-util-generated": "^3.0.0",
"unist-util-position": "^5.0.0",
"unist-util-visit": "^5.0.0"
},
"scripts": {},

View File

@ -61,27 +61,36 @@
* Options.
*/
import {lintRule} from 'unified-lint-rule'
import {visit} from 'unist-util-visit'
import {generated} from 'unist-util-generated'
import {toString} from 'mdast-util-to-string'
import {lintRule} from 'unified-lint-rule'
import {position} from 'unist-util-position'
import {visit} from 'unist-util-visit'
const remarkLintNoHeadingPunctuation = lintRule(
{
origin: 'remark-lint:no-heading-punctuation',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-no-heading-punctuation#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, Options>} */
(tree, file, option = '\\.,;:!?') => {
const expression = new RegExp('[' + option + ']')
/**
* @param {Root} tree
* Tree.
* @param {Options | null | undefined} [options]
* Configuration (default: `'\\.,;:!?'`).
* @returns {undefined}
* Nothing.
*/
function (tree, file, options) {
const expression = new RegExp('[' + (options || '\\.,;:!?') + ']')
visit(tree, 'heading', (node) => {
if (!generated(node)) {
visit(tree, 'heading', function (node) {
const place = position(node)
if (place) {
const value = toString(node)
const tail = value.charAt(value.length - 1)
if (expression.test(tail)) {
file.message('Dont add a trailing `' + tail + '` to headings', node)
file.message('Dont add a trailing `' + tail + '` to headings', place)
}
}
})

View File

@ -37,9 +37,8 @@
"dependencies": {
"@types/mdast": "^4.0.0",
"mdast-util-to-string": "^4.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0",
"unist-util-generated": "^3.0.0",
"unist-util-position": "^5.0.0",
"unist-util-visit": "^5.0.0"
},
"scripts": {},

View File

@ -37,19 +37,25 @@
*/
import {lintRule} from 'unified-lint-rule'
import {position} from 'unist-util-position'
import {visit} from 'unist-util-visit'
import {generated} from 'unist-util-generated'
const remarkLintNoHtml = lintRule(
{
origin: 'remark-lint:no-html',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-no-html#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, void>} */
(tree, file) => {
visit(tree, 'html', (node) => {
if (!generated(node) && !/^\s*<!--/.test(node.value)) {
file.message('Do not use HTML in markdown', node)
/**
* @param {Root} tree
* Tree.
* @returns {undefined}
* Nothing.
*/
function (tree, file) {
visit(tree, 'html', function (node) {
const place = position(node)
if (place && !/^\s*<!--/.test(node.value)) {
file.message('Do not use HTML in markdown', place)
}
})
}

View File

@ -35,9 +35,8 @@
],
"dependencies": {
"@types/mdast": "^4.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0",
"unist-util-generated": "^3.0.0",
"unist-util-position": "^5.0.0",
"unist-util-visit": "^5.0.0"
},
"scripts": {},

View File

@ -36,29 +36,33 @@
* @typedef {import('mdast').Root} Root
*/
import {lintRule} from 'unified-lint-rule'
import {visit} from 'unist-util-visit'
import {generated} from 'unist-util-generated'
import {toString} from 'mdast-util-to-string'
import {lintRule} from 'unified-lint-rule'
import {position} from 'unist-util-position'
import {visit} from 'unist-util-visit'
const remarkLintNoInlinePadding = lintRule(
{
origin: 'remark-lint:no-inline-padding',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-no-inline-padding#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, void>} */
(tree, file) => {
/**
* @param {Root} tree
* Tree.
* @returns {undefined}
* Nothing.
*/
function (tree, file) {
// Note: `emphasis`, `strong`, `delete` (GFM) cant have padding anymore
// since CM.
visit(tree, (node) => {
if (
(node.type === 'link' || node.type === 'linkReference') &&
!generated(node)
) {
visit(tree, function (node) {
const place = position(node)
if ((node.type === 'link' || node.type === 'linkReference') && place) {
const value = toString(node)
if (value.charAt(0) === ' ' || value.charAt(value.length - 1) === ' ') {
file.message('Dont pad `' + node.type + '` with inner spaces', node)
file.message('Dont pad `' + node.type + '` with inner spaces', place)
}
}
})

View File

@ -37,9 +37,8 @@
"dependencies": {
"@types/mdast": "^4.0.0",
"mdast-util-to-string": "^4.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0",
"unist-util-generated": "^3.0.0",
"unist-util-position": "^5.0.0",
"unist-util-visit": "^5.0.0"
},
"scripts": {},

View File

@ -45,30 +45,37 @@
* @typedef {import('mdast').Root} Root
*/
import {lintRule} from 'unified-lint-rule'
import {visit} from 'unist-util-visit'
import {pointStart, pointEnd} from 'unist-util-position'
import {toString} from 'mdast-util-to-string'
import {lintRule} from 'unified-lint-rule'
import {pointEnd, pointStart} from 'unist-util-position'
import {visit} from 'unist-util-visit'
const remarkLintNoLiteralUrls = lintRule(
{
origin: 'remark-lint:no-literal-urls',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-no-literal-urls#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, void>} */
(tree, file) => {
visit(tree, 'link', (node) => {
/**
* @param {Root} tree
* Tree.
* @returns {undefined}
* Nothing.
*/
function (tree, file) {
visit(tree, 'link', function (node) {
const value = toString(node)
const start = pointStart(node)
const end = pointEnd(node)
const start = pointStart(node)
const headStart = pointStart(node.children[0])
const tailEnd = pointEnd(node.children[node.children.length - 1])
if (
start &&
end &&
start.column === headStart?.column &&
end.column === tailEnd?.column &&
start &&
headStart &&
tailEnd &&
end.column === tailEnd.column &&
start.column === headStart.column &&
(node.url === 'mailto:' + value || node.url === value)
) {
file.message('Dont use literal URLs without angle brackets', node)

View File

@ -37,7 +37,6 @@
"dependencies": {
"@types/mdast": "^4.0.0",
"mdast-util-to-string": "^4.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0",
"unist-util-position": "^5.0.0",
"unist-util-visit": "^5.0.0"

View File

@ -82,15 +82,14 @@
/**
* @typedef Options
* Options.
* Configuration.
* @property {boolean | null | undefined} [exceptTightLists=false]
* Allow tight list items.
* Allow tight list items (default: `false`).
*/
import {lintRule} from 'unified-lint-rule'
import {pointEnd, pointStart} from 'unist-util-position'
import {visit} from 'unist-util-visit'
import {pointStart, pointEnd} from 'unist-util-position'
import {generated} from 'unist-util-generated'
const types = new Set([
'paragraph',
@ -109,18 +108,24 @@ const remarkLintNoMissingBlankLines = lintRule(
origin: 'remark-lint:no-missing-blank-lines',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-no-missing-blank-lines#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, Options>} */
(tree, file, option = {}) => {
const {exceptTightLists} = option
/**
* @param {Root} tree
* Tree.
* @param {Options | null | undefined} [options]
* Configuration (optional).
* @returns {undefined}
* Nothing.
*/
function (tree, file, options) {
const exceptTightLists = options ? options.exceptTightLists : false
visit(tree, (node, index, parent) => {
visit(tree, function (node, index, parent) {
const end = pointEnd(node)
if (
end &&
parent &&
typeof index === 'number' &&
!generated(node) &&
end &&
(!exceptTightLists || parent.type !== 'listItem')
) {
const next = parent.children[index + 1]

View File

@ -36,9 +36,7 @@
],
"dependencies": {
"@types/mdast": "^4.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0",
"unist-util-generated": "^3.0.0",
"unist-util-position": "^5.0.0",
"unist-util-visit": "^5.0.0"
},

View File

@ -49,34 +49,44 @@
/**
* @typedef {Heading['depth']} Options
* Options.
* Configuration.
*/
import {lintRule} from 'unified-lint-rule'
import {visit} from 'unist-util-visit'
import {pointStart} from 'unist-util-position'
import {generated} from 'unist-util-generated'
import {pointStart, position} from 'unist-util-position'
import {stringifyPosition} from 'unist-util-stringify-position'
import {visit} from 'unist-util-visit'
const remarkLintNoMultipleToplevelHeadings = lintRule(
{
origin: 'remark-lint:no-multiple-toplevel-headings',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-no-multiple-toplevel-headings#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, Options>} */
(tree, file, option = 1) => {
/**
* @param {Root} tree
* Tree.
* @param {Options | null | undefined} [options=1]
* Configuration (default: `1`).
* @returns {undefined}
* Nothing.
*/
function (tree, file, options) {
const option = options || 1
/** @type {string | undefined} */
let duplicate
visit(tree, 'heading', (node) => {
if (!generated(node) && node.depth === option) {
visit(tree, 'heading', function (node) {
const start = pointStart(node)
const place = position(node)
if (start && place && node.depth === option) {
if (duplicate) {
file.message(
'Dont use multiple top level headings (' + duplicate + ')',
node
place
)
} else {
duplicate = stringifyPosition(pointStart(node))
duplicate = stringifyPosition(start)
}
}
})

View File

@ -36,9 +36,7 @@
],
"dependencies": {
"@types/mdast": "^4.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0",
"unist-util-generated": "^3.0.0",
"unist-util-position": "^5.0.0",
"unist-util-stringify-position": "^4.0.0",
"unist-util-visit": "^5.0.0"
@ -53,7 +51,8 @@
"xo": {
"prettier": true,
"rules": {
"capitalized-comments": "off"
"capitalized-comments": "off",
"unicorn/prefer-default-parameters": "off"
}
}
}

View File

@ -92,8 +92,8 @@
*/
import {lintRule} from 'unified-lint-rule'
import {visit, SKIP} from 'unist-util-visit'
import {pointStart, pointEnd} from 'unist-util-position'
import {pointEnd, pointStart} from 'unist-util-position'
import {SKIP, visit} from 'unist-util-visit'
import {location} from 'vfile-location'
const remarkLintNoParagraphContentIndent = lintRule(
@ -101,12 +101,17 @@ const remarkLintNoParagraphContentIndent = lintRule(
origin: 'remark-lint:no-paragraph-content-indent',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-no-paragraph-content-indent#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, void>} */
(tree, file) => {
/**
* @param {Root} tree
* Tree.
* @returns {undefined}
* Nothing.
*/
function (tree, file) {
const value = String(file)
const loc = location(value)
visit(tree, 'paragraph', (node, _, parent) => {
visit(tree, 'paragraph', function (node, _, parent) {
const end = pointEnd(node)?.line
let line = pointStart(node)?.line
/** @type {number | undefined} */

View File

@ -37,7 +37,6 @@
],
"dependencies": {
"@types/mdast": "^4.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0",
"unist-util-position": "^5.0.0",
"unist-util-visit": "^5.0.0",

View File

@ -47,7 +47,7 @@
*/
import {lintRule} from 'unified-lint-rule'
import {generated} from 'unist-util-generated'
import {position} from 'unist-util-position'
import {visit} from 'unist-util-visit'
const remarkLintNoReferenceLikeUrl = lintRule(
@ -55,21 +55,27 @@ const remarkLintNoReferenceLikeUrl = lintRule(
origin: 'remark-lint:no-reference-like-url',
url: 'https://github.com/remarkjs/remark-lint/tree/main/packages/remark-lint-no-reference-like-url#readme'
},
/** @type {import('unified-lint-rule').Rule<Root, void>} */
(tree, file) => {
/** @type {Array<string>} */
const identifiers = []
/**
* @param {Root} tree
* Tree.
* @returns {undefined}
* Nothing.
*/
function (tree, file) {
/** @type {Set<string>} */
const identifiers = new Set()
visit(tree, 'definition', (node) => {
if (!generated(node)) {
identifiers.push(node.identifier.toLowerCase())
}
visit(tree, 'definition', function (node) {
identifiers.add(node.identifier.toLowerCase())
})
visit(tree, (node) => {
visit(tree, function (node) {
const place = position(node)
if (
place &&
(node.type === 'image' || node.type === 'link') &&
identifiers.includes(node.url.toLowerCase())
identifiers.has(node.url.toLowerCase())
) {
file.message(
'Did you mean to use `[' +
@ -78,7 +84,7 @@ const remarkLintNoReferenceLikeUrl = lintRule(
'`(' +
node.url +
')`, a reference?',
node
place
)
}
})

View File

@ -37,9 +37,8 @@
],
"dependencies": {
"@types/mdast": "^4.0.0",
"unified": "^11.0.0",
"unified-lint-rule": "^2.0.0",
"unist-util-generated": "^3.0.0",
"unist-util-position": "^5.0.0",
"unist-util-visit": "^5.0.0"
},
"scripts": {},

Some files were not shown because too many files have changed in this diff Show More