Update MD009/no-trailing-spaces with code_blocks parameter to allow reporting/fixing trailing spaces in indented/fenced code blocks (fixes #1181).
Some checks are pending
Checkers / linkcheck (push) Waiting to run
Checkers / spellcheck (push) Waiting to run
CI / build (20, macos-latest) (push) Waiting to run
CI / build (20, ubuntu-latest) (push) Waiting to run
CI / build (20, windows-latest) (push) Waiting to run
CI / build (22, macos-latest) (push) Waiting to run
CI / build (22, ubuntu-latest) (push) Waiting to run
CI / build (22, windows-latest) (push) Waiting to run
CI / build (24, macos-latest) (push) Waiting to run
CI / build (24, ubuntu-latest) (push) Waiting to run
CI / build (24, windows-latest) (push) Waiting to run
CI / pnpm (push) Waiting to run
CodeQL / Analyze (push) Waiting to run
TestRepos / build (latest, ubuntu-latest) (push) Waiting to run
UpdateTestRepos / update (push) Waiting to run

This commit is contained in:
David Anson 2025-10-11 17:28:04 -07:00
parent 7beb9fc9d0
commit a55d5499e2
16 changed files with 590 additions and 34 deletions

View file

@ -1,21 +1,19 @@
This rule is triggered on any lines that end with unexpected whitespace. To fix
this, remove the trailing space from the end of the line.
Note: Trailing space is allowed in indented and fenced code blocks because some
languages require it.
The `br_spaces` parameter allows an exception to this rule for a specific number
of trailing spaces, typically used to insert an explicit line break. The default
value allows 2 spaces to indicate a hard break (\<br> element).
value allows 2 spaces to indicate a hard break (\<br> element). (You must set
`br_spaces` to a value >= 2 for this parameter to take effect. Setting
`br_spaces` to 1 behaves the same as 0, disallowing any trailing spaces.)
Note: You must set `br_spaces` to a value >= 2 for this parameter to take
effect. Setting `br_spaces` to 1 behaves the same as 0, disallowing any trailing
spaces.
By default, trailing space is allowed in indented and fenced code blocks because
some programming languages require that. To report such instances, set the
`code_blocks` parameter to `true`.
By default, this rule will not trigger when the allowed number of spaces is
used, even when it doesn't create a hard break (for example, at the end of a
paragraph). To report such instances as well, set the `strict` parameter to
`true`.
paragraph). To report such instances, set the `strict` parameter to `true`.
```markdown
Text text text

View file

@ -295,6 +295,7 @@ Aliases: `no-trailing-spaces`
Parameters:
- `br_spaces`: Spaces for line break (`integer`, default `2`)
- `code_blocks`: Include code blocks (`boolean`, default `false`)
- `list_item_empty_lines`: Allow spaces for empty lines in list items
(`boolean`, default `false`)
- `strict`: Include unnecessary breaks (`boolean`, default `false`)
@ -304,21 +305,19 @@ Fixable: Some violations can be fixed by tooling
This rule is triggered on any lines that end with unexpected whitespace. To fix
this, remove the trailing space from the end of the line.
Note: Trailing space is allowed in indented and fenced code blocks because some
languages require it.
The `br_spaces` parameter allows an exception to this rule for a specific number
of trailing spaces, typically used to insert an explicit line break. The default
value allows 2 spaces to indicate a hard break (\<br> element).
value allows 2 spaces to indicate a hard break (\<br> element). (You must set
`br_spaces` to a value >= 2 for this parameter to take effect. Setting
`br_spaces` to 1 behaves the same as 0, disallowing any trailing spaces.)
Note: You must set `br_spaces` to a value >= 2 for this parameter to take
effect. Setting `br_spaces` to 1 behaves the same as 0, disallowing any trailing
spaces.
By default, trailing space is allowed in indented and fenced code blocks because
some programming languages require that. To report such instances, set the
`code_blocks` parameter to `true`.
By default, this rule will not trigger when the allowed number of spaces is
used, even when it doesn't create a hard break (for example, at the end of a
paragraph). To report such instances as well, set the `strict` parameter to
`true`.
paragraph). To report such instances, set the `strict` parameter to `true`.
```markdown
Text text text

View file

@ -7,6 +7,7 @@ Aliases: `no-trailing-spaces`
Parameters:
- `br_spaces`: Spaces for line break (`integer`, default `2`)
- `code_blocks`: Include code blocks (`boolean`, default `false`)
- `list_item_empty_lines`: Allow spaces for empty lines in list items
(`boolean`, default `false`)
- `strict`: Include unnecessary breaks (`boolean`, default `false`)
@ -16,21 +17,19 @@ Fixable: Some violations can be fixed by tooling
This rule is triggered on any lines that end with unexpected whitespace. To fix
this, remove the trailing space from the end of the line.
Note: Trailing space is allowed in indented and fenced code blocks because some
languages require it.
The `br_spaces` parameter allows an exception to this rule for a specific number
of trailing spaces, typically used to insert an explicit line break. The default
value allows 2 spaces to indicate a hard break (\<br> element).
value allows 2 spaces to indicate a hard break (\<br> element). (You must set
`br_spaces` to a value >= 2 for this parameter to take effect. Setting
`br_spaces` to 1 behaves the same as 0, disallowing any trailing spaces.)
Note: You must set `br_spaces` to a value >= 2 for this parameter to take
effect. Setting `br_spaces` to 1 behaves the same as 0, disallowing any trailing
spaces.
By default, trailing space is allowed in indented and fenced code blocks because
some programming languages require that. To report such instances, set the
`code_blocks` parameter to `true`.
By default, this rule will not trigger when the allowed number of spaces is
used, even when it doesn't create a hard break (for example, at the end of a
paragraph). To report such instances as well, set the `strict` parameter to
`true`.
paragraph). To report such instances, set the `strict` parameter to `true`.
```markdown
Text text text

View file

@ -245,6 +245,10 @@ export interface ConfigurationStrict {
* Spaces for line break
*/
br_spaces?: number;
/**
* Include code blocks
*/
code_blocks?: boolean;
/**
* Allow spaces for empty lines in list items
*/
@ -273,6 +277,10 @@ export interface ConfigurationStrict {
* Spaces for line break
*/
br_spaces?: number;
/**
* Include code blocks
*/
code_blocks?: boolean;
/**
* Allow spaces for empty lines in list items
*/

View file

@ -13,14 +13,18 @@ export default {
"function": function MD009(params, onError) {
let brSpaces = params.config.br_spaces;
brSpaces = Number((brSpaces === undefined) ? 2 : brSpaces);
const codeBlocks = params.config.code_blocks;
const includeCode = (codeBlocks === undefined) ? false : !!codeBlocks;
const listItemEmptyLines = !!params.config.list_item_empty_lines;
const strict = !!params.config.strict;
const codeBlockLineNumbers = new Set();
for (const codeBlock of filterByTypesCached([ "codeFenced" ])) {
addRangeToSet(codeBlockLineNumbers, codeBlock.startLine + 1, codeBlock.endLine - 1);
}
for (const codeBlock of filterByTypesCached([ "codeIndented" ])) {
addRangeToSet(codeBlockLineNumbers, codeBlock.startLine, codeBlock.endLine);
if (!includeCode) {
for (const codeBlock of filterByTypesCached([ "codeFenced" ])) {
addRangeToSet(codeBlockLineNumbers, codeBlock.startLine + 1, codeBlock.endLine - 1);
}
for (const codeBlock of filterByTypesCached([ "codeIndented" ])) {
addRangeToSet(codeBlockLineNumbers, codeBlock.startLine, codeBlock.endLine);
}
}
const listItemLineNumbers = new Set();
if (listItemEmptyLines) {

View file

@ -42,6 +42,8 @@
"MD009": {
// Spaces for line break
"br_spaces": 2,
// Include code blocks
"code_blocks": false,
// Allow spaces for empty lines in list items
"list_item_empty_lines": false,
// Include unnecessary breaks

View file

@ -37,6 +37,8 @@ MD007:
MD009:
# Spaces for line break
br_spaces: 2
# Include code blocks
code_blocks: false
# Allow spaces for empty lines in list items
list_item_empty_lines: false
# Include unnecessary breaks

View file

@ -161,6 +161,12 @@ for (const rule of rules) {
"default": 2
};
// @ts-ignore
subscheme.properties.code_blocks = {
"description": "Include code blocks",
"type": "boolean",
"default": false
};
// @ts-ignore
subscheme.properties.list_item_empty_lines = {
"description": "Allow spaces for empty lines in list items",
"type": "boolean",

View file

@ -512,6 +512,11 @@
"minimum": 0,
"default": 2
},
"code_blocks": {
"description": "Include code blocks",
"type": "boolean",
"default": false
},
"list_item_empty_lines": {
"description": "Allow spaces for empty lines in list items",
"type": "boolean",
@ -563,6 +568,11 @@
"minimum": 0,
"default": 2
},
"code_blocks": {
"description": "Include code blocks",
"type": "boolean",
"default": false
},
"list_item_empty_lines": {
"description": "Allow spaces for empty lines in list items",
"type": "boolean",

View file

@ -512,6 +512,11 @@
"minimum": 0,
"default": 2
},
"code_blocks": {
"description": "Include code blocks",
"type": "boolean",
"default": false
},
"list_item_empty_lines": {
"description": "Allow spaces for empty lines in list items",
"type": "boolean",
@ -563,6 +568,11 @@
"minimum": 0,
"default": 2
},
"code_blocks": {
"description": "Include code blocks",
"type": "boolean",
"default": false
},
"list_item_empty_lines": {
"description": "Allow spaces for empty lines in list items",
"type": "boolean",

View file

@ -984,6 +984,9 @@ test("customFileSystemSync", (t) => {
t.plan(2);
const file = "/dir/file.md";
const fsApi = {
"access": () => { throw new Error("access"); },
"accessSync": () => { throw new Error("accessSync"); },
"readFile": () => { throw new Error("readFile"); },
// @ts-ignore
"readFileSync": (p) => {
t.is(p, file);
@ -1001,11 +1004,14 @@ test("customFileSystemAsync", (t) => new Promise((resolve) => {
t.plan(3);
const file = "/dir/file.md";
const fsApi = {
"access": () => { throw new Error("access"); },
"accessSync": () => { throw new Error("accessSync"); },
// @ts-ignore
"readFile": (p, o, cb) => {
t.is(p, file);
cb(null, "# Heading");
}
},
"readFileSync": () => { throw new Error("readFileSync"); }
};
lintAsync({
"files": file,
@ -1095,7 +1101,7 @@ test("readme", async(t) => {
});
test("validateJsonUsingConfigSchemaStrict", async(t) => {
t.plan(215);
t.plan(218);
// @ts-ignore
const ajv = new Ajv(ajvOptions);
const validateSchemaStrict = ajv.compile(configSchemaStrict);

View file

@ -75772,6 +75772,427 @@ Generated by [AVA](https://avajs.dev).
`,
}
## trailing-spaces-in-code-default.md
> Snapshot 1
{
errors: [
{
errorContext: null,
errorDetail: 'Expected: 0 or 2; Actual: 1',
errorRange: [
14,
1,
],
fixInfo: {
deleteCount: 1,
editColumn: 14,
},
lineNumber: 4,
ruleDescription: 'Trailing spaces',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md009.md',
ruleNames: [
'MD009',
'no-trailing-spaces',
],
severity: 'error',
},
{
errorContext: null,
errorDetail: 'Expected: 0 or 2; Actual: 3',
errorRange: [
14,
3,
],
fixInfo: {
deleteCount: 3,
editColumn: 14,
},
lineNumber: 6,
ruleDescription: 'Trailing spaces',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md009.md',
ruleNames: [
'MD009',
'no-trailing-spaces',
],
severity: 'error',
},
{
errorContext: null,
errorDetail: 'Expected: 0 or 2; Actual: 4',
errorRange: [
14,
4,
],
fixInfo: {
deleteCount: 4,
editColumn: 14,
},
lineNumber: 7,
ruleDescription: 'Trailing spaces',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md009.md',
ruleNames: [
'MD009',
'no-trailing-spaces',
],
severity: 'error',
},
],
fixed: `# Trailing Spaces in Code - Default␊
const a = 10;␊
const b = 10;␊
const c = 10; ␊
const d = 10;␊
const e = 10;␊
{MD009:-5} {MD009:-3} {MD009:-2}␊
const a = 10;␊
const b = 10; ␊
const c = 10; ␊
const d = 10; ␊
const e = 10; ␊
\`\`\`js␊
const a = 10;␊
const b = 10; ␊
const c = 10; ␊
const d = 10; ␊
const e = 10; ␊
\`\`\`␊
<!-- markdownlint-configure-file {␊
"code-block-style": false␊
} -->␊
`,
}
## trailing-spaces-in-code-false.md
> Snapshot 1
{
errors: [
{
errorContext: null,
errorDetail: 'Expected: 0 or 2; Actual: 1',
errorRange: [
14,
1,
],
fixInfo: {
deleteCount: 1,
editColumn: 14,
},
lineNumber: 4,
ruleDescription: 'Trailing spaces',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md009.md',
ruleNames: [
'MD009',
'no-trailing-spaces',
],
severity: 'error',
},
{
errorContext: null,
errorDetail: 'Expected: 0 or 2; Actual: 3',
errorRange: [
14,
3,
],
fixInfo: {
deleteCount: 3,
editColumn: 14,
},
lineNumber: 6,
ruleDescription: 'Trailing spaces',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md009.md',
ruleNames: [
'MD009',
'no-trailing-spaces',
],
severity: 'error',
},
{
errorContext: null,
errorDetail: 'Expected: 0 or 2; Actual: 4',
errorRange: [
14,
4,
],
fixInfo: {
deleteCount: 4,
editColumn: 14,
},
lineNumber: 7,
ruleDescription: 'Trailing spaces',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md009.md',
ruleNames: [
'MD009',
'no-trailing-spaces',
],
severity: 'error',
},
],
fixed: `# Trailing Spaces in Code - False␊
const a = 10;␊
const b = 10;␊
const c = 10; ␊
const d = 10;␊
const e = 10;␊
{MD009:-5} {MD009:-3} {MD009:-2}␊
const a = 10;␊
const b = 10; ␊
const c = 10; ␊
const d = 10; ␊
const e = 10; ␊
\`\`\`js␊
const a = 10;␊
const b = 10; ␊
const c = 10; ␊
const d = 10; ␊
const e = 10; ␊
\`\`\`␊
<!-- markdownlint-configure-file {␊
"code-block-style": false,␊
"no-trailing-spaces": {␊
"code_blocks": false␊
}␊
} -->␊
`,
}
## trailing-spaces-in-code-true.md
> Snapshot 1
{
errors: [
{
errorContext: null,
errorDetail: 'Expected: 0 or 2; Actual: 1',
errorRange: [
14,
1,
],
fixInfo: {
deleteCount: 1,
editColumn: 14,
},
lineNumber: 4,
ruleDescription: 'Trailing spaces',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md009.md',
ruleNames: [
'MD009',
'no-trailing-spaces',
],
severity: 'error',
},
{
errorContext: null,
errorDetail: 'Expected: 0 or 2; Actual: 3',
errorRange: [
14,
3,
],
fixInfo: {
deleteCount: 3,
editColumn: 14,
},
lineNumber: 6,
ruleDescription: 'Trailing spaces',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md009.md',
ruleNames: [
'MD009',
'no-trailing-spaces',
],
severity: 'error',
},
{
errorContext: null,
errorDetail: 'Expected: 0 or 2; Actual: 4',
errorRange: [
14,
4,
],
fixInfo: {
deleteCount: 4,
editColumn: 14,
},
lineNumber: 7,
ruleDescription: 'Trailing spaces',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md009.md',
ruleNames: [
'MD009',
'no-trailing-spaces',
],
severity: 'error',
},
{
errorContext: null,
errorDetail: 'Expected: 0 or 2; Actual: 1',
errorRange: [
18,
1,
],
fixInfo: {
deleteCount: 1,
editColumn: 18,
},
lineNumber: 12,
ruleDescription: 'Trailing spaces',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md009.md',
ruleNames: [
'MD009',
'no-trailing-spaces',
],
severity: 'error',
},
{
errorContext: null,
errorDetail: 'Expected: 0 or 2; Actual: 3',
errorRange: [
18,
3,
],
fixInfo: {
deleteCount: 3,
editColumn: 18,
},
lineNumber: 14,
ruleDescription: 'Trailing spaces',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md009.md',
ruleNames: [
'MD009',
'no-trailing-spaces',
],
severity: 'error',
},
{
errorContext: null,
errorDetail: 'Expected: 0 or 2; Actual: 4',
errorRange: [
18,
4,
],
fixInfo: {
deleteCount: 4,
editColumn: 18,
},
lineNumber: 15,
ruleDescription: 'Trailing spaces',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md009.md',
ruleNames: [
'MD009',
'no-trailing-spaces',
],
severity: 'error',
},
{
errorContext: null,
errorDetail: 'Expected: 0 or 2; Actual: 1',
errorRange: [
14,
1,
],
fixInfo: {
deleteCount: 1,
editColumn: 14,
},
lineNumber: 21,
ruleDescription: 'Trailing spaces',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md009.md',
ruleNames: [
'MD009',
'no-trailing-spaces',
],
severity: 'error',
},
{
errorContext: null,
errorDetail: 'Expected: 0 or 2; Actual: 3',
errorRange: [
14,
3,
],
fixInfo: {
deleteCount: 3,
editColumn: 14,
},
lineNumber: 23,
ruleDescription: 'Trailing spaces',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md009.md',
ruleNames: [
'MD009',
'no-trailing-spaces',
],
severity: 'error',
},
{
errorContext: null,
errorDetail: 'Expected: 0 or 2; Actual: 4',
errorRange: [
14,
4,
],
fixInfo: {
deleteCount: 4,
editColumn: 14,
},
lineNumber: 24,
ruleDescription: 'Trailing spaces',
ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md009.md',
ruleNames: [
'MD009',
'no-trailing-spaces',
],
severity: 'error',
},
],
fixed: `# Trailing Spaces in Code - True␊
const a = 10;␊
const b = 10;␊
const c = 10; ␊
const d = 10;␊
const e = 10;␊
{MD009:-5} {MD009:-3} {MD009:-2}␊
const a = 10;␊
const b = 10;␊
const c = 10; ␊
const d = 10;␊
const e = 10;␊
{MD009:-5} {MD009:-3} {MD009:-2}␊
\`\`\`js␊
const a = 10;␊
const b = 10;␊
const c = 10; ␊
const d = 10;␊
const e = 10;␊
\`\`\`␊
{MD009:-6} {MD009:-4} {MD009:-3}␊
<!-- markdownlint-configure-file {␊
"code-block-style": false,␊
"no-trailing-spaces": {␊
"code_blocks": true␊
}␊
} -->␊
`,
}
## trailing-spaces-in-lists-allowed-strict.md
> Snapshot 1

View file

@ -0,0 +1,27 @@
# Trailing Spaces in Code - Default
const a = 10;
const b = 10;
const c = 10;
const d = 10;
const e = 10;
{MD009:-5} {MD009:-3} {MD009:-2}
const a = 10;
const b = 10;
const c = 10;
const d = 10;
const e = 10;
```js
const a = 10;
const b = 10;
const c = 10;
const d = 10;
const e = 10;
```
<!-- markdownlint-configure-file {
"code-block-style": false
} -->

View file

@ -0,0 +1,30 @@
# Trailing Spaces in Code - False
const a = 10;
const b = 10;
const c = 10;
const d = 10;
const e = 10;
{MD009:-5} {MD009:-3} {MD009:-2}
const a = 10;
const b = 10;
const c = 10;
const d = 10;
const e = 10;
```js
const a = 10;
const b = 10;
const c = 10;
const d = 10;
const e = 10;
```
<!-- markdownlint-configure-file {
"code-block-style": false,
"no-trailing-spaces": {
"code_blocks": false
}
} -->

View file

@ -0,0 +1,34 @@
# Trailing Spaces in Code - True
const a = 10;
const b = 10;
const c = 10;
const d = 10;
const e = 10;
{MD009:-5} {MD009:-3} {MD009:-2}
const a = 10;
const b = 10;
const c = 10;
const d = 10;
const e = 10;
{MD009:-5} {MD009:-3} {MD009:-2}
```js
const a = 10;
const b = 10;
const c = 10;
const d = 10;
const e = 10;
```
{MD009:-6} {MD009:-4} {MD009:-3}
<!-- markdownlint-configure-file {
"code-block-style": false,
"no-trailing-spaces": {
"code_blocks": true
}
} -->