eslint-plugin-markdown-preferences 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/lib/index.d.ts +16 -3
- package/lib/index.js +146 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -92,6 +92,7 @@ The rules with the following star ⭐ are included in the configs.
|
|
|
92
92
|
|
|
93
93
|
| Rule ID | Description | Fixable | RECOMMENDED |
|
|
94
94
|
|:--------|:------------|:-------:|:-----------:|
|
|
95
|
+
| [markdown-preferences/canonical-code-block-language](https://ota-meshi.github.io/eslint-plugin-markdown-preferences/rules/canonical-code-block-language.html) | enforce canonical language names in code blocks | 🔧 | |
|
|
95
96
|
| [markdown-preferences/no-text-backslash-linebreak](https://ota-meshi.github.io/eslint-plugin-markdown-preferences/rules/no-text-backslash-linebreak.html) | disallow text backslash at the end of a line. | | ⭐ |
|
|
96
97
|
| [markdown-preferences/prefer-inline-code-words](https://ota-meshi.github.io/eslint-plugin-markdown-preferences/rules/prefer-inline-code-words.html) | enforce the use of inline code for specific words. | 🔧 | |
|
|
97
98
|
| [markdown-preferences/prefer-linked-words](https://ota-meshi.github.io/eslint-plugin-markdown-preferences/rules/prefer-linked-words.html) | enforce the specified word to be a link. | 🔧 | |
|
|
@@ -100,13 +101,14 @@ The rules with the following star ⭐ are included in the configs.
|
|
|
100
101
|
|
|
101
102
|
| Rule ID | Description | Fixable | RECOMMENDED |
|
|
102
103
|
|:--------|:------------|:-------:|:-----------:|
|
|
103
|
-
| [markdown-preferences/canonical-code-block-language](https://ota-meshi.github.io/eslint-plugin-markdown-preferences/rules/canonical-code-block-language.html) | enforce canonical language names in code blocks | 🔧 | |
|
|
104
104
|
| [markdown-preferences/definitions-last](https://ota-meshi.github.io/eslint-plugin-markdown-preferences/rules/definitions-last.html) | require link definitions and footnote definitions to be placed at the end of the document | 🔧 | |
|
|
105
105
|
| [markdown-preferences/hard-linebreak-style](https://ota-meshi.github.io/eslint-plugin-markdown-preferences/rules/hard-linebreak-style.html) | enforce consistent hard linebreak style. | 🔧 | ⭐ |
|
|
106
106
|
| [markdown-preferences/heading-casing](https://ota-meshi.github.io/eslint-plugin-markdown-preferences/rules/heading-casing.html) | enforce consistent casing in headings. | 🔧 | |
|
|
107
107
|
| [markdown-preferences/no-laziness-blockquotes](https://ota-meshi.github.io/eslint-plugin-markdown-preferences/rules/no-laziness-blockquotes.html) | disallow laziness in blockquotes | | ⭐ |
|
|
108
108
|
| [markdown-preferences/no-multiple-empty-lines](https://ota-meshi.github.io/eslint-plugin-markdown-preferences/rules/no-multiple-empty-lines.html) | disallow multiple empty lines in Markdown files. | 🔧 | |
|
|
109
109
|
| [markdown-preferences/no-trailing-spaces](https://ota-meshi.github.io/eslint-plugin-markdown-preferences/rules/no-trailing-spaces.html) | disallow trailing whitespace at the end of lines in Markdown files. | 🔧 | |
|
|
110
|
+
| [markdown-preferences/prefer-autolinks](https://ota-meshi.github.io/eslint-plugin-markdown-preferences/rules/prefer-autolinks.html) | enforce the use of autolinks for URLs | 🔧 | ⭐ |
|
|
111
|
+
| [markdown-preferences/prefer-fenced-code-blocks](https://ota-meshi.github.io/eslint-plugin-markdown-preferences/rules/prefer-fenced-code-blocks.html) | enforce the use of fenced code blocks over indented code blocks | 🔧 | ⭐ |
|
|
110
112
|
| [markdown-preferences/prefer-link-reference-definitions](https://ota-meshi.github.io/eslint-plugin-markdown-preferences/rules/prefer-link-reference-definitions.html) | enforce using link reference definitions instead of inline links | 🔧 | |
|
|
111
113
|
| [markdown-preferences/sort-definitions](https://ota-meshi.github.io/eslint-plugin-markdown-preferences/rules/sort-definitions.html) | enforce a specific order for link definitions and footnote definitions | 🔧 | |
|
|
112
114
|
|
|
@@ -129,7 +131,7 @@ Please use GitHub's Issues/PRs.
|
|
|
129
131
|
|
|
130
132
|
## 🔒 License
|
|
131
133
|
|
|
132
|
-
See the [LICENSE](LICENSE) file for license rights and limitations (MIT).
|
|
134
|
+
See the [LICENSE](./LICENSE) file for license rights and limitations (MIT).
|
|
133
135
|
|
|
134
136
|
[npm-package]: https://www.npmjs.com/package/eslint-plugin-markdown-preferences
|
|
135
137
|
[npmtrends]: http://www.npmtrends.com/eslint-plugin-markdown-preferences
|
package/lib/index.d.ts
CHANGED
|
@@ -50,6 +50,16 @@ interface RuleOptions {
|
|
|
50
50
|
* @see https://ota-meshi.github.io/eslint-plugin-markdown-preferences/rules/no-trailing-spaces.html
|
|
51
51
|
*/
|
|
52
52
|
'markdown-preferences/no-trailing-spaces'?: Linter.RuleEntry<MarkdownPreferencesNoTrailingSpaces>;
|
|
53
|
+
/**
|
|
54
|
+
* enforce the use of autolinks for URLs
|
|
55
|
+
* @see https://ota-meshi.github.io/eslint-plugin-markdown-preferences/rules/prefer-autolinks.html
|
|
56
|
+
*/
|
|
57
|
+
'markdown-preferences/prefer-autolinks'?: Linter.RuleEntry<[]>;
|
|
58
|
+
/**
|
|
59
|
+
* enforce the use of fenced code blocks over indented code blocks
|
|
60
|
+
* @see https://ota-meshi.github.io/eslint-plugin-markdown-preferences/rules/prefer-fenced-code-blocks.html
|
|
61
|
+
*/
|
|
62
|
+
'markdown-preferences/prefer-fenced-code-blocks'?: Linter.RuleEntry<[]>;
|
|
53
63
|
/**
|
|
54
64
|
* enforce the use of inline code for specific words.
|
|
55
65
|
* @see https://ota-meshi.github.io/eslint-plugin-markdown-preferences/rules/prefer-inline-code-words.html
|
|
@@ -129,11 +139,14 @@ type MarkdownPreferencesSortDefinitions = [] | [{
|
|
|
129
139
|
alphabetical?: boolean;
|
|
130
140
|
}];
|
|
131
141
|
declare namespace recommended_d_exports {
|
|
132
|
-
export { files, language, name$1 as name, plugins, rules$1 as rules };
|
|
142
|
+
export { files, language, languageOptions, name$1 as name, plugins, rules$1 as rules };
|
|
133
143
|
}
|
|
134
144
|
declare const name$1 = "markdown-preferences/recommended";
|
|
135
145
|
declare const files: string[];
|
|
136
|
-
declare const language = "markdown/
|
|
146
|
+
declare const language = "markdown/gfm";
|
|
147
|
+
declare const languageOptions: {
|
|
148
|
+
frontmatter: string;
|
|
149
|
+
};
|
|
137
150
|
declare const plugins: {
|
|
138
151
|
markdown: typeof markdown;
|
|
139
152
|
readonly "markdown-preferences": ESLint.Plugin;
|
|
@@ -143,7 +156,7 @@ declare namespace meta_d_exports {
|
|
|
143
156
|
export { name, version };
|
|
144
157
|
}
|
|
145
158
|
declare const name: "eslint-plugin-markdown-preferences";
|
|
146
|
-
declare const version: "0.
|
|
159
|
+
declare const version: "0.11.0";
|
|
147
160
|
//#endregion
|
|
148
161
|
//#region src/index.d.ts
|
|
149
162
|
declare const configs: {
|
package/lib/index.js
CHANGED
|
@@ -56,7 +56,7 @@ var canonical_code_block_language_default = createRule("canonical-code-block-lan
|
|
|
56
56
|
docs: {
|
|
57
57
|
description: "enforce canonical language names in code blocks",
|
|
58
58
|
categories: [],
|
|
59
|
-
listCategory: "
|
|
59
|
+
listCategory: "Preference"
|
|
60
60
|
},
|
|
61
61
|
fixable: "code",
|
|
62
62
|
hasSuggestions: false,
|
|
@@ -1464,6 +1464,142 @@ var no_trailing_spaces_default = createRule("no-trailing-spaces", {
|
|
|
1464
1464
|
}
|
|
1465
1465
|
});
|
|
1466
1466
|
|
|
1467
|
+
//#endregion
|
|
1468
|
+
//#region src/utils/ast.ts
|
|
1469
|
+
/**
|
|
1470
|
+
* Get the kind of code block.
|
|
1471
|
+
*/
|
|
1472
|
+
function getCodeBlockKind(sourceCode, node) {
|
|
1473
|
+
const text = sourceCode.getText(node);
|
|
1474
|
+
return text.startsWith("```") ? "backtick-fenced" : text.startsWith("~~~") ? "tilde-fenced" : "indented";
|
|
1475
|
+
}
|
|
1476
|
+
/**
|
|
1477
|
+
* Get the kind of link.
|
|
1478
|
+
*/
|
|
1479
|
+
function getLinkKind(sourceCode, node) {
|
|
1480
|
+
const text = sourceCode.getText(node);
|
|
1481
|
+
return text.startsWith("[") ? "inline" : text.startsWith("<") && text.endsWith(">") ? "autolink" : "gfm-autolink";
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1484
|
+
//#endregion
|
|
1485
|
+
//#region src/rules/prefer-autolinks.ts
|
|
1486
|
+
var prefer_autolinks_default = createRule("prefer-autolinks", {
|
|
1487
|
+
meta: {
|
|
1488
|
+
type: "layout",
|
|
1489
|
+
docs: {
|
|
1490
|
+
description: "enforce the use of autolinks for URLs",
|
|
1491
|
+
categories: ["recommended"],
|
|
1492
|
+
listCategory: "Stylistic"
|
|
1493
|
+
},
|
|
1494
|
+
fixable: "code",
|
|
1495
|
+
hasSuggestions: false,
|
|
1496
|
+
schema: [],
|
|
1497
|
+
messages: {
|
|
1498
|
+
useAutolinkInsteadGFMAutolink: "Use an autolink instead of a GFM autolink (bare url).",
|
|
1499
|
+
useAutolinkInsteadInlineLink: "Use an autolink instead of an inline link with the same URL."
|
|
1500
|
+
}
|
|
1501
|
+
},
|
|
1502
|
+
create(context) {
|
|
1503
|
+
const sourceCode = context.sourceCode;
|
|
1504
|
+
return { link(node) {
|
|
1505
|
+
const kind = getLinkKind(sourceCode, node);
|
|
1506
|
+
if (kind === "autolink") return;
|
|
1507
|
+
if (node.title) return;
|
|
1508
|
+
if (node.children.some((child) => child.type !== "text")) return;
|
|
1509
|
+
const label = node.children.map((child) => child.value).join("");
|
|
1510
|
+
if (node.url !== label) return;
|
|
1511
|
+
context.report({
|
|
1512
|
+
node,
|
|
1513
|
+
messageId: kind === "inline" ? "useAutolinkInsteadInlineLink" : "useAutolinkInsteadGFMAutolink",
|
|
1514
|
+
fix(fixer) {
|
|
1515
|
+
return fixer.replaceText(node, `<${node.url}>`);
|
|
1516
|
+
}
|
|
1517
|
+
});
|
|
1518
|
+
} };
|
|
1519
|
+
}
|
|
1520
|
+
});
|
|
1521
|
+
|
|
1522
|
+
//#endregion
|
|
1523
|
+
//#region src/rules/prefer-fenced-code-blocks.ts
|
|
1524
|
+
var prefer_fenced_code_blocks_default = createRule("prefer-fenced-code-blocks", {
|
|
1525
|
+
meta: {
|
|
1526
|
+
type: "layout",
|
|
1527
|
+
docs: {
|
|
1528
|
+
description: "enforce the use of fenced code blocks over indented code blocks",
|
|
1529
|
+
categories: ["recommended"],
|
|
1530
|
+
listCategory: "Stylistic"
|
|
1531
|
+
},
|
|
1532
|
+
fixable: "code",
|
|
1533
|
+
hasSuggestions: false,
|
|
1534
|
+
schema: [],
|
|
1535
|
+
messages: { useFencedCodeBlock: "Use a fenced code block instead of an indented code block." }
|
|
1536
|
+
},
|
|
1537
|
+
create(context) {
|
|
1538
|
+
const sourceCode = context.sourceCode;
|
|
1539
|
+
const lines = parseLines(sourceCode);
|
|
1540
|
+
return { code(node) {
|
|
1541
|
+
const kind = getCodeBlockKind(sourceCode, node);
|
|
1542
|
+
if (kind === "backtick-fenced" || kind === "tilde-fenced") return;
|
|
1543
|
+
const loc = sourceCode.getLoc(node);
|
|
1544
|
+
context.report({
|
|
1545
|
+
node,
|
|
1546
|
+
messageId: "useFencedCodeBlock",
|
|
1547
|
+
fix(fixer) {
|
|
1548
|
+
if (!isFixableIndentedCodeBlock(node)) return null;
|
|
1549
|
+
const startColumnOffset = loc.start.column - 1;
|
|
1550
|
+
const removeRanges = [];
|
|
1551
|
+
let prefixText = null;
|
|
1552
|
+
for (let line = loc.start.line; line <= loc.end.line; line++) {
|
|
1553
|
+
const parsedLine = lines.get(line);
|
|
1554
|
+
const currentPrefix = normalizePrefix(parsedLine.text.slice(0, startColumnOffset));
|
|
1555
|
+
if (!prefixText) prefixText = currentPrefix;
|
|
1556
|
+
else if (currentPrefix !== prefixText) return null;
|
|
1557
|
+
let removeRange = [parsedLine.range[0] + startColumnOffset, parsedLine.range[0] + startColumnOffset + 4];
|
|
1558
|
+
for (let index = removeRange[0]; index < removeRange[1]; index++) {
|
|
1559
|
+
const c = sourceCode.text[index];
|
|
1560
|
+
if (c === " ") continue;
|
|
1561
|
+
if (c === " ") {
|
|
1562
|
+
removeRange = [removeRange[0], index + 1];
|
|
1563
|
+
break;
|
|
1564
|
+
}
|
|
1565
|
+
return null;
|
|
1566
|
+
}
|
|
1567
|
+
removeRanges.push(removeRange);
|
|
1568
|
+
}
|
|
1569
|
+
const beginFenceInsertOffset = lines.get(loc.start.line).range[0];
|
|
1570
|
+
const endFenceInsertOffset = lines.get(loc.end.line).range[1];
|
|
1571
|
+
return [
|
|
1572
|
+
fixer.insertTextBeforeRange([beginFenceInsertOffset, beginFenceInsertOffset], `${prefixText}\`\`\`\n`),
|
|
1573
|
+
...removeRanges.map((removeRange) => fixer.removeRange(removeRange)),
|
|
1574
|
+
fixer.insertTextAfterRange([endFenceInsertOffset, endFenceInsertOffset], `${prefixText}\`\`\`\n`)
|
|
1575
|
+
];
|
|
1576
|
+
}
|
|
1577
|
+
});
|
|
1578
|
+
} };
|
|
1579
|
+
/**
|
|
1580
|
+
* Determines whether the given indented code block is fixable or not.
|
|
1581
|
+
*/
|
|
1582
|
+
function isFixableIndentedCodeBlock(node) {
|
|
1583
|
+
if (!node.value.startsWith(" ")) return true;
|
|
1584
|
+
const loc = sourceCode.getLoc(node);
|
|
1585
|
+
const firstLine = lines.get(loc.start.line);
|
|
1586
|
+
const codeBlockFirstLine = normalizePrefix(node.value.split(/\r?\n/u)[0]);
|
|
1587
|
+
const startColumnOffset = loc.start.column - 1;
|
|
1588
|
+
const normalizedFirstLine = normalizePrefix(firstLine.text.slice(startColumnOffset));
|
|
1589
|
+
return normalizedFirstLine.startsWith(codeBlockFirstLine);
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1592
|
+
});
|
|
1593
|
+
/**
|
|
1594
|
+
* Normalize the prefix by removing tabs and replacing them with spaces.
|
|
1595
|
+
*/
|
|
1596
|
+
function normalizePrefix(prefix) {
|
|
1597
|
+
let result = "";
|
|
1598
|
+
for (const c of prefix) if (c !== " ") result += c;
|
|
1599
|
+
else result += " ".repeat(4 - result.length % 4);
|
|
1600
|
+
return result;
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1467
1603
|
//#endregion
|
|
1468
1604
|
//#region src/utils/search-words.ts
|
|
1469
1605
|
const RE_BOUNDARY = /^[\s\p{Letter_Number}\p{Modifier_Letter}\p{Modifier_Symbol}\p{Nonspacing_Mark}\p{Other_Letter}\p{Other_Symbol}\p{Script=Han}!"#$%&'()*+,./:;<=>?\\{|}~\u{2ffc}-\u{303d}\u{30a0}-\u{30fb}\u{3192}-\u{32bf}\u{fe10}-\u{fe1f}\u{fe30}-\u{fe6f}\u{ff00}-\u{ffef}\u{2ebf0}-\u{2ee5d}]*$/u;
|
|
@@ -2201,6 +2337,8 @@ const rules$1 = [
|
|
|
2201
2337
|
no_multiple_empty_lines_default,
|
|
2202
2338
|
no_text_backslash_linebreak_default,
|
|
2203
2339
|
no_trailing_spaces_default,
|
|
2340
|
+
prefer_autolinks_default,
|
|
2341
|
+
prefer_fenced_code_blocks_default,
|
|
2204
2342
|
prefer_inline_code_words_default,
|
|
2205
2343
|
prefer_link_reference_definitions_default,
|
|
2206
2344
|
prefer_linked_words_default,
|
|
@@ -2213,13 +2351,15 @@ var recommended_exports = {};
|
|
|
2213
2351
|
__export(recommended_exports, {
|
|
2214
2352
|
files: () => files,
|
|
2215
2353
|
language: () => language,
|
|
2354
|
+
languageOptions: () => languageOptions,
|
|
2216
2355
|
name: () => name$1,
|
|
2217
2356
|
plugins: () => plugins,
|
|
2218
2357
|
rules: () => rules$2
|
|
2219
2358
|
});
|
|
2220
2359
|
const name$1 = "markdown-preferences/recommended";
|
|
2221
2360
|
const files = ["*.md", "**/*.md"];
|
|
2222
|
-
const language = "markdown/
|
|
2361
|
+
const language = "markdown/gfm";
|
|
2362
|
+
const languageOptions = { frontmatter: "yaml" };
|
|
2223
2363
|
const plugins = {
|
|
2224
2364
|
markdown,
|
|
2225
2365
|
get "markdown-preferences"() {
|
|
@@ -2229,7 +2369,9 @@ const plugins = {
|
|
|
2229
2369
|
const rules$2 = {
|
|
2230
2370
|
"markdown-preferences/hard-linebreak-style": "error",
|
|
2231
2371
|
"markdown-preferences/no-laziness-blockquotes": "error",
|
|
2232
|
-
"markdown-preferences/no-text-backslash-linebreak": "error"
|
|
2372
|
+
"markdown-preferences/no-text-backslash-linebreak": "error",
|
|
2373
|
+
"markdown-preferences/prefer-autolinks": "error",
|
|
2374
|
+
"markdown-preferences/prefer-fenced-code-blocks": "error"
|
|
2233
2375
|
};
|
|
2234
2376
|
|
|
2235
2377
|
//#endregion
|
|
@@ -2240,7 +2382,7 @@ __export(meta_exports, {
|
|
|
2240
2382
|
version: () => version
|
|
2241
2383
|
});
|
|
2242
2384
|
const name = "eslint-plugin-markdown-preferences";
|
|
2243
|
-
const version = "0.
|
|
2385
|
+
const version = "0.11.0";
|
|
2244
2386
|
|
|
2245
2387
|
//#endregion
|
|
2246
2388
|
//#region src/index.ts
|