markdownlint 0.26.1 → 0.26.2
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 +2 -0
- package/demo/markdownlint-browser.js +74 -69
- package/doc/Rules.md +13 -2
- package/helpers/helpers.js +31 -29
- package/helpers/package.json +1 -1
- package/lib/constants.js +1 -1
- package/lib/markdownlint.js +0 -5
- package/lib/md032.js +4 -5
- package/lib/md033.js +1 -1
- package/lib/md037.js +23 -20
- package/lib/md051.js +6 -6
- package/lib/md053.js +18 -11
- package/package.json +1 -1
- package/schema/.markdownlint.jsonc +6 -1
- package/schema/.markdownlint.yaml +5 -1
- package/schema/markdownlint-config-schema.json +18 -2
package/README.md
CHANGED
|
@@ -48,6 +48,7 @@ and test cases came directly from that project.
|
|
|
48
48
|
* [eslint-plugin-markdownlint for the ESLint analyzer](https://github.com/paweldrozd/eslint-plugin-markdownlint)
|
|
49
49
|
* [grunt-markdownlint for the Grunt task runner](https://github.com/sagiegurari/grunt-markdownlint)
|
|
50
50
|
* [Cake.Markdownlint addin for Cake build automation system](https://github.com/cake-contrib/Cake.Markdownlint)
|
|
51
|
+
* [Lombiq Node.js Extensions for MSBuild (.NET builds)](https://github.com/Lombiq/NodeJs-Extensions)
|
|
51
52
|
* Ruby
|
|
52
53
|
* [markdownlint/mdl gem for Ruby](https://rubygems.org/gems/mdl)
|
|
53
54
|
|
|
@@ -1020,6 +1021,7 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for more information.
|
|
|
1020
1021
|
browser script to use ES2015, simplify JSON schema, address remaining CodeQL issues,
|
|
1021
1022
|
improve performance, update dependencies.
|
|
1022
1023
|
* 0.26.1 - Improve MD051.
|
|
1024
|
+
* 0.26.2 - Improve MD037/MD051/MD053.
|
|
1023
1025
|
|
|
1024
1026
|
[npm-image]: https://img.shields.io/npm/v/markdownlint.svg
|
|
1025
1027
|
[npm-url]: https://www.npmjs.com/package/markdownlint
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! markdownlint 0.26.
|
|
1
|
+
/*! markdownlint 0.26.2 https://github.com/DavidAnson/markdownlint @license MIT */
|
|
2
2
|
var markdownlint;
|
|
3
3
|
/******/ (() => { // webpackBootstrap
|
|
4
4
|
/******/ var __webpack_modules__ = ({
|
|
@@ -52,8 +52,11 @@ module.exports.listItemMarkerRe = /^([\s>]*)(?:[*+-]|\d+[.)])\s+/;
|
|
|
52
52
|
module.exports.orderedListItemMarkerRe = /^[\s>]*0*(\d+)[.)]/;
|
|
53
53
|
// Regular expression for all instances of emphasis markers
|
|
54
54
|
const emphasisMarkersRe = /[_*]/g;
|
|
55
|
-
// Regular expression for
|
|
56
|
-
const
|
|
55
|
+
// Regular expression for blockquote prefixes
|
|
56
|
+
const blockquotePrefixRe = /^[>\s]*/;
|
|
57
|
+
module.exports.blockquotePrefixRe = blockquotePrefixRe;
|
|
58
|
+
// Regular expression for reference links (full, collapsed, and shortcut)
|
|
59
|
+
const referenceLinkRe = /!?\\?\[((?:\[[^\]\0]*]|[^\]\0])*)](?:(?:\[([^\]\0]*)\])|([^(])|$)/g;
|
|
57
60
|
// Regular expression for link reference definitions
|
|
58
61
|
const linkReferenceDefinitionRe = /^ {0,3}\[([^\]]*[^\\])]:/;
|
|
59
62
|
module.exports.linkReferenceDefinitionRe = linkReferenceDefinitionRe;
|
|
@@ -755,7 +758,7 @@ function getReferenceLinkImageData(lineMetadata) {
|
|
|
755
758
|
// Define helper functions
|
|
756
759
|
const normalizeLabel = (s) => s.toLowerCase().trim().replace(/\s+/g, " ");
|
|
757
760
|
const exclusions = [];
|
|
758
|
-
const excluded = (match) => withinAnyRange(exclusions, 0, match.index, match[0].length);
|
|
761
|
+
const excluded = (match) => withinAnyRange(exclusions, 0, match.index, match[0].length - (match[3] || "").length);
|
|
759
762
|
// Convert input to single-line so multi-line links/images are easier
|
|
760
763
|
const lineOffsets = [];
|
|
761
764
|
let currentOffset = 0;
|
|
@@ -763,6 +766,7 @@ function getReferenceLinkImageData(lineMetadata) {
|
|
|
763
766
|
forEachLine(lineMetadata, (line, lineIndex, inCode) => {
|
|
764
767
|
lineOffsets[lineIndex] = currentOffset;
|
|
765
768
|
if (!inCode) {
|
|
769
|
+
line = line.replace(blockquotePrefixRe, "");
|
|
766
770
|
if (line.trim().length === 0) {
|
|
767
771
|
// Allow RegExp to detect the end of a block
|
|
768
772
|
line = "\0";
|
|
@@ -813,30 +817,29 @@ function getReferenceLinkImageData(lineMetadata) {
|
|
|
813
817
|
!matchString.startsWith("!\\") &&
|
|
814
818
|
!matchText.endsWith("\\") &&
|
|
815
819
|
!(matchLabel || "").endsWith("\\") &&
|
|
816
|
-
(topLevel
|
|
817
|
-
!excluded(referenceLinkMatch)) {
|
|
820
|
+
!(topLevel && excluded(referenceLinkMatch))) {
|
|
818
821
|
const shortcutLink = (matchLabel === undefined);
|
|
819
822
|
const collapsedLink = (!shortcutLink && (matchLabel.length === 0));
|
|
820
823
|
const label = normalizeLabel((shortcutLink || collapsedLink) ? matchText : matchLabel);
|
|
821
824
|
if (label.length > 0) {
|
|
825
|
+
const referenceindex = referenceLinkMatch.index;
|
|
826
|
+
if (topLevel) {
|
|
827
|
+
// Calculate line index
|
|
828
|
+
while (lineOffsets[lineIndex + 1] <= referenceindex) {
|
|
829
|
+
lineIndex++;
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
else {
|
|
833
|
+
// Use provided line index
|
|
834
|
+
lineIndex = contentLineIndex;
|
|
835
|
+
}
|
|
836
|
+
const referenceIndex = referenceindex +
|
|
837
|
+
(topLevel ? -lineOffsets[lineIndex] : contentIndex);
|
|
822
838
|
if (shortcutLink) {
|
|
823
|
-
// Track
|
|
839
|
+
// Track separately due to ambiguity in "text [text] text"
|
|
824
840
|
shortcuts.add(label);
|
|
825
841
|
}
|
|
826
842
|
else {
|
|
827
|
-
const referenceindex = referenceLinkMatch.index;
|
|
828
|
-
if (topLevel) {
|
|
829
|
-
// Calculate line index
|
|
830
|
-
while (lineOffsets[lineIndex + 1] <= referenceindex) {
|
|
831
|
-
lineIndex++;
|
|
832
|
-
}
|
|
833
|
-
}
|
|
834
|
-
else {
|
|
835
|
-
// Use provided line index
|
|
836
|
-
lineIndex = contentLineIndex;
|
|
837
|
-
}
|
|
838
|
-
const referenceIndex = referenceindex +
|
|
839
|
-
(topLevel ? -lineOffsets[lineIndex] : contentIndex);
|
|
840
843
|
// Track reference and location
|
|
841
844
|
const referenceData = references.get(label) || [];
|
|
842
845
|
referenceData.push([
|
|
@@ -845,15 +848,15 @@ function getReferenceLinkImageData(lineMetadata) {
|
|
|
845
848
|
matchString.length
|
|
846
849
|
]);
|
|
847
850
|
references.set(label, referenceData);
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
}
|
|
851
|
+
}
|
|
852
|
+
// Check for links embedded in brackets
|
|
853
|
+
if (!matchString.startsWith("!")) {
|
|
854
|
+
pendingContents.push({
|
|
855
|
+
"content": matchText,
|
|
856
|
+
"contentLineIndex": lineIndex,
|
|
857
|
+
"contentIndex": referenceIndex + 1,
|
|
858
|
+
"topLevel": false
|
|
859
|
+
});
|
|
857
860
|
}
|
|
858
861
|
}
|
|
859
862
|
}
|
|
@@ -1187,7 +1190,7 @@ module.exports.referenceLinkImageData =
|
|
|
1187
1190
|
|
|
1188
1191
|
module.exports.deprecatedRuleNames = ["MD002", "MD006"];
|
|
1189
1192
|
module.exports.homepage = "https://github.com/DavidAnson/markdownlint";
|
|
1190
|
-
module.exports.version = "0.26.
|
|
1193
|
+
module.exports.version = "0.26.2";
|
|
1191
1194
|
|
|
1192
1195
|
|
|
1193
1196
|
/***/ }),
|
|
@@ -1419,11 +1422,6 @@ function annotateAndFreezeTokens(tokens, lines) {
|
|
|
1419
1422
|
if (!token.map && trMap) {
|
|
1420
1423
|
token.map = [...trMap];
|
|
1421
1424
|
}
|
|
1422
|
-
// Adjust maps for math blocks
|
|
1423
|
-
if (helpers.isMathBlock(token) && token.map[1]) {
|
|
1424
|
-
// markdown-it-texmath plugin does not account for math_block_end
|
|
1425
|
-
token.map[1]++;
|
|
1426
|
-
}
|
|
1427
1425
|
// Update token metadata
|
|
1428
1426
|
if (token.map) {
|
|
1429
1427
|
token.line = lines[token.map[0]];
|
|
@@ -3588,9 +3586,8 @@ module.exports = {
|
|
|
3588
3586
|
"use strict";
|
|
3589
3587
|
// @ts-check
|
|
3590
3588
|
|
|
3591
|
-
const { addErrorContext, isBlankLine } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
3589
|
+
const { addErrorContext, blockquotePrefixRe, isBlankLine } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
3592
3590
|
const { flattenedLists } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
|
|
3593
|
-
const quotePrefixRe = /^[>\s]*/;
|
|
3594
3591
|
module.exports = {
|
|
3595
3592
|
"names": ["MD032", "blanks-around-lists"],
|
|
3596
3593
|
"description": "Lists should be surrounded by blank lines",
|
|
@@ -3602,7 +3599,7 @@ module.exports = {
|
|
|
3602
3599
|
const firstIndex = list.open.map[0];
|
|
3603
3600
|
if (!isBlankLine(lines[firstIndex - 1])) {
|
|
3604
3601
|
const line = lines[firstIndex];
|
|
3605
|
-
const quotePrefix = line.match(
|
|
3602
|
+
const quotePrefix = line.match(blockquotePrefixRe)[0].trimEnd();
|
|
3606
3603
|
addErrorContext(onError, firstIndex + 1, line.trim(), null, null, null, {
|
|
3607
3604
|
"insertText": `${quotePrefix}\n`
|
|
3608
3605
|
});
|
|
@@ -3610,7 +3607,7 @@ module.exports = {
|
|
|
3610
3607
|
const lastIndex = list.lastLineIndex - 1;
|
|
3611
3608
|
if (!isBlankLine(lines[lastIndex + 1])) {
|
|
3612
3609
|
const line = lines[lastIndex];
|
|
3613
|
-
const quotePrefix = line.match(
|
|
3610
|
+
const quotePrefix = line.match(blockquotePrefixRe)[0].trimEnd();
|
|
3614
3611
|
addErrorContext(onError, lastIndex + 1, line.trim(), null, null, null, {
|
|
3615
3612
|
"lineNumber": lastIndex + 2,
|
|
3616
3613
|
"insertText": `${quotePrefix}\n`
|
|
@@ -3661,7 +3658,7 @@ module.exports = {
|
|
|
3661
3658
|
if (!linkDestinationRe.test(prefix)) {
|
|
3662
3659
|
const unescaped = unescapeMarkdown(prefix + "<", "_");
|
|
3663
3660
|
if (!unescaped.endsWith("_")) {
|
|
3664
|
-
addError(onError, lineIndex + 1, "Element: " + element,
|
|
3661
|
+
addError(onError, lineIndex + 1, "Element: " + element, undefined, [match.index + 1, tag.length]);
|
|
3665
3662
|
}
|
|
3666
3663
|
}
|
|
3667
3664
|
}
|
|
@@ -3842,8 +3839,8 @@ module.exports = {
|
|
|
3842
3839
|
"use strict";
|
|
3843
3840
|
// @ts-check
|
|
3844
3841
|
|
|
3845
|
-
const { addErrorContext, emphasisMarkersInContent, forEachLine, isBlankLine } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
3846
|
-
const { lineMetadata } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
|
|
3842
|
+
const { addErrorContext, emphasisMarkersInContent, forEachLine, isBlankLine, withinAnyRange } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
3843
|
+
const { htmlElementRanges, lineMetadata } = __webpack_require__(/*! ./cache */ "../lib/cache.js");
|
|
3847
3844
|
const emphasisRe = /(^|[^\\]|\\\\)(?:(\*\*?\*?)|(__?_?))/g;
|
|
3848
3845
|
const embeddedUnderscoreRe = /([A-Za-z0-9])_([A-Za-z0-9])/g;
|
|
3849
3846
|
const asteriskListItemMarkerRe = /^([\s>]*)\*(\s+)/;
|
|
@@ -3855,6 +3852,7 @@ module.exports = {
|
|
|
3855
3852
|
"description": "Spaces inside emphasis markers",
|
|
3856
3853
|
"tags": ["whitespace", "emphasis"],
|
|
3857
3854
|
"function": function MD037(params, onError) {
|
|
3855
|
+
const exclusions = htmlElementRanges();
|
|
3858
3856
|
// eslint-disable-next-line init-declarations
|
|
3859
3857
|
let effectiveEmphasisLength, emphasisIndex, emphasisKind, emphasisLength, pendingError = null;
|
|
3860
3858
|
// eslint-disable-next-line jsdoc/require-jsdoc
|
|
@@ -3882,25 +3880,27 @@ module.exports = {
|
|
|
3882
3880
|
// Report the violation
|
|
3883
3881
|
const contextStart = emphasisIndex - emphasisLength;
|
|
3884
3882
|
const contextEnd = matchIndex + contextLength;
|
|
3885
|
-
const context = line.substring(contextStart, contextEnd);
|
|
3886
3883
|
const column = contextStart + 1;
|
|
3887
3884
|
const length = contextEnd - contextStart;
|
|
3888
|
-
|
|
3889
|
-
|
|
3890
|
-
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
|
|
3902
|
-
|
|
3903
|
-
|
|
3885
|
+
if (!withinAnyRange(exclusions, lineIndex, column, length)) {
|
|
3886
|
+
const context = line.substring(contextStart, contextEnd);
|
|
3887
|
+
const leftMarker = line.substring(contextStart, emphasisIndex);
|
|
3888
|
+
const rightMarker = match ? (match[2] || match[3]) : "";
|
|
3889
|
+
const fixedText = `${leftMarker}${content.trim()}${rightMarker}`;
|
|
3890
|
+
return [
|
|
3891
|
+
onError,
|
|
3892
|
+
lineIndex + 1,
|
|
3893
|
+
context,
|
|
3894
|
+
leftSpace,
|
|
3895
|
+
rightSpace,
|
|
3896
|
+
[column, length],
|
|
3897
|
+
{
|
|
3898
|
+
"editColumn": column,
|
|
3899
|
+
"deleteCount": length,
|
|
3900
|
+
"insertText": fixedText
|
|
3901
|
+
}
|
|
3902
|
+
];
|
|
3903
|
+
}
|
|
3904
3904
|
}
|
|
3905
3905
|
return null;
|
|
3906
3906
|
}
|
|
@@ -4601,7 +4601,8 @@ module.exports = [
|
|
|
4601
4601
|
|
|
4602
4602
|
const { addError, escapeForRegExp, filterTokens, forEachInlineChild, forEachHeading, htmlElementRe } = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js");
|
|
4603
4603
|
// Regular expression for identifying HTML anchor names
|
|
4604
|
-
const
|
|
4604
|
+
const idRe = /\sid\s*=\s*['"]?([^'"\s>]+)/iu;
|
|
4605
|
+
const nameRe = /\sname\s*=\s*['"]?([^'"\s>]+)/iu;
|
|
4605
4606
|
/**
|
|
4606
4607
|
* Converts a Markdown heading into an HTML fragment according to the rules
|
|
4607
4608
|
* used by GitHub.
|
|
@@ -4643,11 +4644,10 @@ module.exports = {
|
|
|
4643
4644
|
let match = null;
|
|
4644
4645
|
while ((match = htmlElementRe.exec(token.content)) !== null) {
|
|
4645
4646
|
const [tag, , element] = match;
|
|
4646
|
-
|
|
4647
|
-
|
|
4648
|
-
|
|
4649
|
-
|
|
4650
|
-
}
|
|
4647
|
+
const anchorMatch = idRe.exec(tag) ||
|
|
4648
|
+
(element.toLowerCase() === "a" && nameRe.exec(tag));
|
|
4649
|
+
if (anchorMatch) {
|
|
4650
|
+
fragments.set(`#${anchorMatch[1]}`, 0);
|
|
4651
4651
|
}
|
|
4652
4652
|
}
|
|
4653
4653
|
};
|
|
@@ -4727,7 +4727,8 @@ module.exports = {
|
|
|
4727
4727
|
"description": "Link and image reference definitions should be needed",
|
|
4728
4728
|
"tags": ["images", "links"],
|
|
4729
4729
|
"function": function MD053(params, onError) {
|
|
4730
|
-
const
|
|
4730
|
+
const ignored = new Set(params.config.ignored_definitions || ["//"]);
|
|
4731
|
+
const lines = params.lines;
|
|
4731
4732
|
const { references, shortcuts, definitions, duplicateDefinitions } = referenceLinkImageData();
|
|
4732
4733
|
const singleLineDefinition = (line) => (line.replace(linkReferenceDefinitionRe, "").trim().length > 0);
|
|
4733
4734
|
const deleteFixInfo = {
|
|
@@ -4736,7 +4737,9 @@ module.exports = {
|
|
|
4736
4737
|
// Look for unused link references (unreferenced by any link/image)
|
|
4737
4738
|
for (const definition of definitions.entries()) {
|
|
4738
4739
|
const [label, lineIndex] = definition;
|
|
4739
|
-
if (!
|
|
4740
|
+
if (!ignored.has(label) &&
|
|
4741
|
+
!references.has(label) &&
|
|
4742
|
+
!shortcuts.has(label)) {
|
|
4740
4743
|
const line = lines[lineIndex];
|
|
4741
4744
|
addError(onError, lineIndex + 1, `Unused link or image reference definition: "${label}"`, ellipsify(line), [1, line.length], singleLineDefinition(line) ? deleteFixInfo : 0);
|
|
4742
4745
|
}
|
|
@@ -4744,8 +4747,10 @@ module.exports = {
|
|
|
4744
4747
|
// Look for duplicate link references (defined more than once)
|
|
4745
4748
|
for (const duplicateDefinition of duplicateDefinitions) {
|
|
4746
4749
|
const [label, lineIndex] = duplicateDefinition;
|
|
4747
|
-
|
|
4748
|
-
|
|
4750
|
+
if (!ignored.has(label)) {
|
|
4751
|
+
const line = lines[lineIndex];
|
|
4752
|
+
addError(onError, lineIndex + 1, `Duplicate link or image reference definition: "${label}"`, ellipsify(line), [1, line.length], singleLineDefinition(line) ? deleteFixInfo : 0);
|
|
4753
|
+
}
|
|
4749
4754
|
}
|
|
4750
4755
|
}
|
|
4751
4756
|
};
|
package/doc/Rules.md
CHANGED
|
@@ -1315,7 +1315,7 @@ To fix this, use 'pure' Markdown instead of including raw HTML:
|
|
|
1315
1315
|
# Markdown heading
|
|
1316
1316
|
```
|
|
1317
1317
|
|
|
1318
|
-
Note: To allow specific HTML elements, use the
|
|
1318
|
+
Note: To allow specific HTML elements, use the `allowed_elements` parameter.
|
|
1319
1319
|
|
|
1320
1320
|
Rationale: Raw HTML is allowed in Markdown, but this rule is included for
|
|
1321
1321
|
those who want their documents to only include "pure" Markdown, or for those
|
|
@@ -2075,6 +2075,8 @@ Tags: images, links
|
|
|
2075
2075
|
|
|
2076
2076
|
Aliases: link-image-reference-definitions
|
|
2077
2077
|
|
|
2078
|
+
Parameters: ignored_definitions (array of string; default [ "//" ])
|
|
2079
|
+
|
|
2078
2080
|
Fixable: Most violations can be fixed by tooling
|
|
2079
2081
|
|
|
2080
2082
|
Links and images in Markdown can provide the link destination or image source
|
|
@@ -2092,9 +2094,18 @@ unnecessary:
|
|
|
2092
2094
|
used and the others can be deleted.
|
|
2093
2095
|
|
|
2094
2096
|
This rule considers a reference definition to be used if any link or image
|
|
2095
|
-
reference has the corresponding label. "
|
|
2097
|
+
reference has the corresponding label. The "full", "collapsed", and "shortcut"
|
|
2096
2098
|
formats are all supported.
|
|
2097
2099
|
|
|
2100
|
+
If there are reference definitions that are deliberately unreferenced, they can
|
|
2101
|
+
be ignored by setting the `ignored_definitions` parameter. The default value of
|
|
2102
|
+
this parameter ignores the following convention for adding non-HTML comments to
|
|
2103
|
+
Markdown:
|
|
2104
|
+
|
|
2105
|
+
```md
|
|
2106
|
+
[//]: # (This behaves like a comment)
|
|
2107
|
+
```
|
|
2108
|
+
|
|
2098
2109
|
<!-- markdownlint-configure-file {
|
|
2099
2110
|
"no-inline-html": {
|
|
2100
2111
|
"allowed_elements": [
|
package/helpers/helpers.js
CHANGED
|
@@ -30,9 +30,13 @@ module.exports.orderedListItemMarkerRe = /^[\s>]*0*(\d+)[.)]/;
|
|
|
30
30
|
// Regular expression for all instances of emphasis markers
|
|
31
31
|
const emphasisMarkersRe = /[_*]/g;
|
|
32
32
|
|
|
33
|
-
// Regular expression for
|
|
33
|
+
// Regular expression for blockquote prefixes
|
|
34
|
+
const blockquotePrefixRe = /^[>\s]*/;
|
|
35
|
+
module.exports.blockquotePrefixRe = blockquotePrefixRe;
|
|
36
|
+
|
|
37
|
+
// Regular expression for reference links (full, collapsed, and shortcut)
|
|
34
38
|
const referenceLinkRe =
|
|
35
|
-
/!?\\?\[((?:\[[^\]\0]*]|[^\]\0])*)](?:(?:\[([^\]\0]*)\])|[^(]|$)/g;
|
|
39
|
+
/!?\\?\[((?:\[[^\]\0]*]|[^\]\0])*)](?:(?:\[([^\]\0]*)\])|([^(])|$)/g;
|
|
36
40
|
|
|
37
41
|
// Regular expression for link reference definitions
|
|
38
42
|
const linkReferenceDefinitionRe = /^ {0,3}\[([^\]]*[^\\])]:/;
|
|
@@ -785,7 +789,7 @@ function getReferenceLinkImageData(lineMetadata) {
|
|
|
785
789
|
const normalizeLabel = (s) => s.toLowerCase().trim().replace(/\s+/g, " ");
|
|
786
790
|
const exclusions = [];
|
|
787
791
|
const excluded = (match) => withinAnyRange(
|
|
788
|
-
exclusions, 0, match.index, match[0].length
|
|
792
|
+
exclusions, 0, match.index, match[0].length - (match[3] || "").length
|
|
789
793
|
);
|
|
790
794
|
// Convert input to single-line so multi-line links/images are easier
|
|
791
795
|
const lineOffsets = [];
|
|
@@ -794,6 +798,7 @@ function getReferenceLinkImageData(lineMetadata) {
|
|
|
794
798
|
forEachLine(lineMetadata, (line, lineIndex, inCode) => {
|
|
795
799
|
lineOffsets[lineIndex] = currentOffset;
|
|
796
800
|
if (!inCode) {
|
|
801
|
+
line = line.replace(blockquotePrefixRe, "");
|
|
797
802
|
if (line.trim().length === 0) {
|
|
798
803
|
// Allow RegExp to detect the end of a block
|
|
799
804
|
line = "\0";
|
|
@@ -845,8 +850,7 @@ function getReferenceLinkImageData(lineMetadata) {
|
|
|
845
850
|
!matchString.startsWith("!\\") &&
|
|
846
851
|
!matchText.endsWith("\\") &&
|
|
847
852
|
!(matchLabel || "").endsWith("\\") &&
|
|
848
|
-
(topLevel
|
|
849
|
-
!excluded(referenceLinkMatch)
|
|
853
|
+
!(topLevel && excluded(referenceLinkMatch))
|
|
850
854
|
) {
|
|
851
855
|
const shortcutLink = (matchLabel === undefined);
|
|
852
856
|
const collapsedLink =
|
|
@@ -855,22 +859,22 @@ function getReferenceLinkImageData(lineMetadata) {
|
|
|
855
859
|
(shortcutLink || collapsedLink) ? matchText : matchLabel
|
|
856
860
|
);
|
|
857
861
|
if (label.length > 0) {
|
|
862
|
+
const referenceindex = referenceLinkMatch.index;
|
|
863
|
+
if (topLevel) {
|
|
864
|
+
// Calculate line index
|
|
865
|
+
while (lineOffsets[lineIndex + 1] <= referenceindex) {
|
|
866
|
+
lineIndex++;
|
|
867
|
+
}
|
|
868
|
+
} else {
|
|
869
|
+
// Use provided line index
|
|
870
|
+
lineIndex = contentLineIndex;
|
|
871
|
+
}
|
|
872
|
+
const referenceIndex = referenceindex +
|
|
873
|
+
(topLevel ? -lineOffsets[lineIndex] : contentIndex);
|
|
858
874
|
if (shortcutLink) {
|
|
859
|
-
// Track
|
|
875
|
+
// Track separately due to ambiguity in "text [text] text"
|
|
860
876
|
shortcuts.add(label);
|
|
861
877
|
} else {
|
|
862
|
-
const referenceindex = referenceLinkMatch.index;
|
|
863
|
-
if (topLevel) {
|
|
864
|
-
// Calculate line index
|
|
865
|
-
while (lineOffsets[lineIndex + 1] <= referenceindex) {
|
|
866
|
-
lineIndex++;
|
|
867
|
-
}
|
|
868
|
-
} else {
|
|
869
|
-
// Use provided line index
|
|
870
|
-
lineIndex = contentLineIndex;
|
|
871
|
-
}
|
|
872
|
-
const referenceIndex = referenceindex +
|
|
873
|
-
(topLevel ? -lineOffsets[lineIndex] : contentIndex);
|
|
874
878
|
// Track reference and location
|
|
875
879
|
const referenceData = references.get(label) || [];
|
|
876
880
|
referenceData.push([
|
|
@@ -879,17 +883,15 @@ function getReferenceLinkImageData(lineMetadata) {
|
|
|
879
883
|
matchString.length
|
|
880
884
|
]);
|
|
881
885
|
references.set(label, referenceData);
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
);
|
|
892
|
-
}
|
|
886
|
+
}
|
|
887
|
+
// Check for links embedded in brackets
|
|
888
|
+
if (!matchString.startsWith("!")) {
|
|
889
|
+
pendingContents.push({
|
|
890
|
+
"content": matchText,
|
|
891
|
+
"contentLineIndex": lineIndex,
|
|
892
|
+
"contentIndex": referenceIndex + 1,
|
|
893
|
+
"topLevel": false
|
|
894
|
+
});
|
|
893
895
|
}
|
|
894
896
|
}
|
|
895
897
|
}
|
package/helpers/package.json
CHANGED
package/lib/constants.js
CHANGED
package/lib/markdownlint.js
CHANGED
|
@@ -233,11 +233,6 @@ function annotateAndFreezeTokens(tokens, lines) {
|
|
|
233
233
|
if (!token.map && trMap) {
|
|
234
234
|
token.map = [ ...trMap ];
|
|
235
235
|
}
|
|
236
|
-
// Adjust maps for math blocks
|
|
237
|
-
if (helpers.isMathBlock(token) && token.map[1]) {
|
|
238
|
-
// markdown-it-texmath plugin does not account for math_block_end
|
|
239
|
-
token.map[1]++;
|
|
240
|
-
}
|
|
241
236
|
// Update token metadata
|
|
242
237
|
if (token.map) {
|
|
243
238
|
token.line = lines[token.map[0]];
|
package/lib/md032.js
CHANGED
|
@@ -2,11 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
const { addErrorContext, isBlankLine } =
|
|
5
|
+
const { addErrorContext, blockquotePrefixRe, isBlankLine } =
|
|
6
|
+
require("../helpers");
|
|
6
7
|
const { flattenedLists } = require("./cache");
|
|
7
8
|
|
|
8
|
-
const quotePrefixRe = /^[>\s]*/;
|
|
9
|
-
|
|
10
9
|
module.exports = {
|
|
11
10
|
"names": [ "MD032", "blanks-around-lists" ],
|
|
12
11
|
"description": "Lists should be surrounded by blank lines",
|
|
@@ -18,7 +17,7 @@ module.exports = {
|
|
|
18
17
|
const firstIndex = list.open.map[0];
|
|
19
18
|
if (!isBlankLine(lines[firstIndex - 1])) {
|
|
20
19
|
const line = lines[firstIndex];
|
|
21
|
-
const quotePrefix = line.match(
|
|
20
|
+
const quotePrefix = line.match(blockquotePrefixRe)[0].trimEnd();
|
|
22
21
|
addErrorContext(
|
|
23
22
|
onError,
|
|
24
23
|
firstIndex + 1,
|
|
@@ -33,7 +32,7 @@ module.exports = {
|
|
|
33
32
|
const lastIndex = list.lastLineIndex - 1;
|
|
34
33
|
if (!isBlankLine(lines[lastIndex + 1])) {
|
|
35
34
|
const line = lines[lastIndex];
|
|
36
|
-
const quotePrefix = line.match(
|
|
35
|
+
const quotePrefix = line.match(blockquotePrefixRe)[0].trimEnd();
|
|
37
36
|
addErrorContext(
|
|
38
37
|
onError,
|
|
39
38
|
lastIndex + 1,
|
package/lib/md033.js
CHANGED
|
@@ -38,7 +38,7 @@ module.exports = {
|
|
|
38
38
|
const unescaped = unescapeMarkdown(prefix + "<", "_");
|
|
39
39
|
if (!unescaped.endsWith("_")) {
|
|
40
40
|
addError(onError, lineIndex + 1, "Element: " + element,
|
|
41
|
-
|
|
41
|
+
undefined, [ match.index + 1, tag.length ]);
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
}
|
package/lib/md037.js
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
const { addErrorContext, emphasisMarkersInContent, forEachLine, isBlankLine
|
|
6
|
-
require("../helpers");
|
|
7
|
-
const { lineMetadata } = require("./cache");
|
|
5
|
+
const { addErrorContext, emphasisMarkersInContent, forEachLine, isBlankLine,
|
|
6
|
+
withinAnyRange } = require("../helpers");
|
|
7
|
+
const { htmlElementRanges, lineMetadata } = require("./cache");
|
|
8
8
|
|
|
9
9
|
const emphasisRe = /(^|[^\\]|\\\\)(?:(\*\*?\*?)|(__?_?))/g;
|
|
10
10
|
const embeddedUnderscoreRe = /([A-Za-z0-9])_([A-Za-z0-9])/g;
|
|
@@ -18,6 +18,7 @@ module.exports = {
|
|
|
18
18
|
"description": "Spaces inside emphasis markers",
|
|
19
19
|
"tags": [ "whitespace", "emphasis" ],
|
|
20
20
|
"function": function MD037(params, onError) {
|
|
21
|
+
const exclusions = htmlElementRanges();
|
|
21
22
|
// eslint-disable-next-line init-declarations
|
|
22
23
|
let effectiveEmphasisLength, emphasisIndex, emphasisKind, emphasisLength,
|
|
23
24
|
pendingError = null;
|
|
@@ -50,25 +51,27 @@ module.exports = {
|
|
|
50
51
|
// Report the violation
|
|
51
52
|
const contextStart = emphasisIndex - emphasisLength;
|
|
52
53
|
const contextEnd = matchIndex + contextLength;
|
|
53
|
-
const context = line.substring(contextStart, contextEnd);
|
|
54
54
|
const column = contextStart + 1;
|
|
55
55
|
const length = contextEnd - contextStart;
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
56
|
+
if (!withinAnyRange(exclusions, lineIndex, column, length)) {
|
|
57
|
+
const context = line.substring(contextStart, contextEnd);
|
|
58
|
+
const leftMarker = line.substring(contextStart, emphasisIndex);
|
|
59
|
+
const rightMarker = match ? (match[2] || match[3]) : "";
|
|
60
|
+
const fixedText = `${leftMarker}${content.trim()}${rightMarker}`;
|
|
61
|
+
return [
|
|
62
|
+
onError,
|
|
63
|
+
lineIndex + 1,
|
|
64
|
+
context,
|
|
65
|
+
leftSpace,
|
|
66
|
+
rightSpace,
|
|
67
|
+
[ column, length ],
|
|
68
|
+
{
|
|
69
|
+
"editColumn": column,
|
|
70
|
+
"deleteCount": length,
|
|
71
|
+
"insertText": fixedText
|
|
72
|
+
}
|
|
73
|
+
];
|
|
74
|
+
}
|
|
72
75
|
}
|
|
73
76
|
return null;
|
|
74
77
|
}
|
package/lib/md051.js
CHANGED
|
@@ -6,7 +6,8 @@ const { addError, escapeForRegExp, filterTokens, forEachInlineChild,
|
|
|
6
6
|
forEachHeading, htmlElementRe } = require("../helpers");
|
|
7
7
|
|
|
8
8
|
// Regular expression for identifying HTML anchor names
|
|
9
|
-
const
|
|
9
|
+
const idRe = /\sid\s*=\s*['"]?([^'"\s>]+)/iu;
|
|
10
|
+
const nameRe = /\sname\s*=\s*['"]?([^'"\s>]+)/iu;
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Converts a Markdown heading into an HTML fragment according to the rules
|
|
@@ -55,11 +56,10 @@ module.exports = {
|
|
|
55
56
|
let match = null;
|
|
56
57
|
while ((match = htmlElementRe.exec(token.content)) !== null) {
|
|
57
58
|
const [ tag, , element ] = match;
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
59
|
+
const anchorMatch = idRe.exec(tag) ||
|
|
60
|
+
(element.toLowerCase() === "a" && nameRe.exec(tag));
|
|
61
|
+
if (anchorMatch) {
|
|
62
|
+
fragments.set(`#${anchorMatch[1]}`, 0);
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
};
|
package/lib/md053.js
CHANGED
|
@@ -11,7 +11,8 @@ module.exports = {
|
|
|
11
11
|
"description": "Link and image reference definitions should be needed",
|
|
12
12
|
"tags": [ "images", "links" ],
|
|
13
13
|
"function": function MD053(params, onError) {
|
|
14
|
-
const
|
|
14
|
+
const ignored = new Set(params.config.ignored_definitions || [ "//" ]);
|
|
15
|
+
const lines = params.lines;
|
|
15
16
|
const { references, shortcuts, definitions, duplicateDefinitions } =
|
|
16
17
|
referenceLinkImageData();
|
|
17
18
|
const singleLineDefinition = (line) => (
|
|
@@ -23,7 +24,11 @@ module.exports = {
|
|
|
23
24
|
// Look for unused link references (unreferenced by any link/image)
|
|
24
25
|
for (const definition of definitions.entries()) {
|
|
25
26
|
const [ label, lineIndex ] = definition;
|
|
26
|
-
if (
|
|
27
|
+
if (
|
|
28
|
+
!ignored.has(label) &&
|
|
29
|
+
!references.has(label) &&
|
|
30
|
+
!shortcuts.has(label)
|
|
31
|
+
) {
|
|
27
32
|
const line = lines[lineIndex];
|
|
28
33
|
addError(
|
|
29
34
|
onError,
|
|
@@ -38,15 +43,17 @@ module.exports = {
|
|
|
38
43
|
// Look for duplicate link references (defined more than once)
|
|
39
44
|
for (const duplicateDefinition of duplicateDefinitions) {
|
|
40
45
|
const [ label, lineIndex ] = duplicateDefinition;
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
if (!ignored.has(label)) {
|
|
47
|
+
const line = lines[lineIndex];
|
|
48
|
+
addError(
|
|
49
|
+
onError,
|
|
50
|
+
lineIndex + 1,
|
|
51
|
+
`Duplicate link or image reference definition: "${label}"`,
|
|
52
|
+
ellipsify(line),
|
|
53
|
+
[ 1, line.length ],
|
|
54
|
+
singleLineDefinition(line) ? deleteFixInfo : 0
|
|
55
|
+
);
|
|
56
|
+
}
|
|
50
57
|
}
|
|
51
58
|
}
|
|
52
59
|
};
|
package/package.json
CHANGED
|
@@ -909,8 +909,24 @@
|
|
|
909
909
|
},
|
|
910
910
|
"MD053": {
|
|
911
911
|
"description": "MD053/link-image-reference-definitions - Link and image reference definitions should be needed",
|
|
912
|
-
"type":
|
|
913
|
-
|
|
912
|
+
"type": [
|
|
913
|
+
"boolean",
|
|
914
|
+
"object"
|
|
915
|
+
],
|
|
916
|
+
"default": true,
|
|
917
|
+
"properties": {
|
|
918
|
+
"ignored_definitions": {
|
|
919
|
+
"description": "Ignored definitions",
|
|
920
|
+
"type": "array",
|
|
921
|
+
"items": {
|
|
922
|
+
"type": "string"
|
|
923
|
+
},
|
|
924
|
+
"default": [
|
|
925
|
+
"//"
|
|
926
|
+
]
|
|
927
|
+
}
|
|
928
|
+
},
|
|
929
|
+
"additionalProperties": false
|
|
914
930
|
},
|
|
915
931
|
"link-image-reference-definitions": {
|
|
916
932
|
"$ref": "#/properties/MD053"
|