markdownlint 0.29.0 → 0.31.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/lib/md043.js CHANGED
@@ -11,52 +11,54 @@ module.exports = {
11
11
  "tags": [ "headings", "headers" ],
12
12
  "function": function MD043(params, onError) {
13
13
  const requiredHeadings = params.config.headings || params.config.headers;
14
+ if (!Array.isArray(requiredHeadings)) {
15
+ // Nothing to check; avoid doing any work
16
+ return;
17
+ }
14
18
  const matchCase = params.config.match_case || false;
15
- if (Array.isArray(requiredHeadings)) {
16
- const levels = {};
17
- for (const level of [ 1, 2, 3, 4, 5, 6 ]) {
18
- levels["h" + level] = "######".substr(-level);
19
- }
20
- let i = 0;
21
- let matchAny = false;
22
- let hasError = false;
23
- let anyHeadings = false;
24
- const getExpected = () => requiredHeadings[i++] || "[None]";
25
- const handleCase = (str) => (matchCase ? str : str.toLowerCase());
26
- forEachHeading(params, (heading, content) => {
27
- if (!hasError) {
28
- anyHeadings = true;
29
- const actual = levels[heading.tag] + " " + content;
30
- const expected = getExpected();
31
- if (expected === "*") {
32
- const nextExpected = getExpected();
33
- if (handleCase(nextExpected) !== handleCase(actual)) {
34
- matchAny = true;
35
- i--;
36
- }
37
- } else if (expected === "+") {
19
+ const levels = {};
20
+ for (const level of [ 1, 2, 3, 4, 5, 6 ]) {
21
+ levels["h" + level] = "######".substr(-level);
22
+ }
23
+ let i = 0;
24
+ let matchAny = false;
25
+ let hasError = false;
26
+ let anyHeadings = false;
27
+ const getExpected = () => requiredHeadings[i++] || "[None]";
28
+ const handleCase = (str) => (matchCase ? str : str.toLowerCase());
29
+ forEachHeading(params, (heading, content) => {
30
+ if (!hasError) {
31
+ anyHeadings = true;
32
+ const actual = levels[heading.tag] + " " + content;
33
+ const expected = getExpected();
34
+ if (expected === "*") {
35
+ const nextExpected = getExpected();
36
+ if (handleCase(nextExpected) !== handleCase(actual)) {
38
37
  matchAny = true;
39
- } else if (handleCase(expected) === handleCase(actual)) {
40
- matchAny = false;
41
- } else if (matchAny) {
42
38
  i--;
43
- } else {
44
- addErrorDetailIf(onError, heading.lineNumber,
45
- expected, actual);
46
- hasError = true;
47
39
  }
40
+ } else if (expected === "+") {
41
+ matchAny = true;
42
+ } else if (handleCase(expected) === handleCase(actual)) {
43
+ matchAny = false;
44
+ } else if (matchAny) {
45
+ i--;
46
+ } else {
47
+ addErrorDetailIf(onError, heading.lineNumber,
48
+ expected, actual);
49
+ hasError = true;
48
50
  }
49
- });
50
- const extraHeadings = requiredHeadings.length - i;
51
- if (
52
- !hasError &&
53
- ((extraHeadings > 1) ||
54
- ((extraHeadings === 1) && (requiredHeadings[i] !== "*"))) &&
55
- (anyHeadings || !requiredHeadings.every((heading) => heading === "*"))
56
- ) {
57
- addErrorContext(onError, params.lines.length,
58
- requiredHeadings[i]);
59
51
  }
52
+ });
53
+ const extraHeadings = requiredHeadings.length - i;
54
+ if (
55
+ !hasError &&
56
+ ((extraHeadings > 1) ||
57
+ ((extraHeadings === 1) && (requiredHeadings[i] !== "*"))) &&
58
+ (anyHeadings || !requiredHeadings.every((heading) => heading === "*"))
59
+ ) {
60
+ addErrorContext(onError, params.lines.length,
61
+ requiredHeadings[i]);
60
62
  }
61
63
  }
62
64
  };
package/lib/md044.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const { addErrorDetailIf, escapeForRegExp, newLineRe, withinAnyRange } =
5
+ const { addErrorDetailIf, escapeForRegExp, withinAnyRange } =
6
6
  require("../helpers");
7
7
  const { filterByPredicate, filterByTypes, parse } =
8
8
  require("../helpers/micromark.cjs");
@@ -19,46 +19,32 @@ module.exports = {
19
19
  let names = params.config.names;
20
20
  names = Array.isArray(names) ? names : [];
21
21
  names.sort((a, b) => (b.length - a.length) || a.localeCompare(b));
22
+ if (names.length === 0) {
23
+ // Nothing to check; avoid doing any work
24
+ return;
25
+ }
22
26
  const codeBlocks = params.config.code_blocks;
23
27
  const includeCodeBlocks =
24
28
  (codeBlocks === undefined) ? true : !!codeBlocks;
25
29
  const htmlElements = params.config.html_elements;
26
30
  const includeHtmlElements =
27
31
  (htmlElements === undefined) ? true : !!htmlElements;
28
- const scannedTypes = new Set([ "data", "htmlFlowData" ]);
32
+ const scannedTypes = new Set([ "data" ]);
29
33
  if (includeCodeBlocks) {
30
34
  scannedTypes.add("codeFlowValue");
31
35
  scannedTypes.add("codeTextData");
32
36
  }
33
- const tokenAdjustments = new Map();
37
+ if (includeHtmlElements) {
38
+ scannedTypes.add("htmlFlowData");
39
+ scannedTypes.add("htmlTextData");
40
+ }
34
41
  const contentTokens =
35
42
  filterByPredicate(
36
43
  params.parsers.micromark.tokens,
37
44
  (token) => scannedTypes.has(token.type),
38
- (token) => {
39
- let { children } = token;
40
- const { startLine, text } = token;
41
- if (!includeHtmlElements && (token.type === "htmlFlow")) {
42
- if (text.startsWith("<!--")) {
43
- // Remove comment content
44
- children = [];
45
- } else {
46
- // Re-parse to get htmlText elements for detailed tokenization
47
- const htmlTextLines =
48
- `<md044>\n${text}\n</md044>`.split(newLineRe);
49
- children = parse(htmlTextLines.join(""));
50
- const reTokens = [ ...children ];
51
- for (const reToken of reTokens) {
52
- tokenAdjustments.set(reToken, {
53
- htmlTextLines,
54
- startLine
55
- });
56
- reTokens.push(...reToken.children);
57
- }
58
- }
59
- }
60
- return children.filter((t) => !ignoredChildTypes.has(t.type));
61
- }
45
+ (token) => (
46
+ token.children.filter((t) => !ignoredChildTypes.has(t.type))
47
+ )
62
48
  );
63
49
  const exclusions = [];
64
50
  const autoLinked = new Set();
@@ -96,22 +82,10 @@ module.exports = {
96
82
  autoLinked.add(token);
97
83
  }
98
84
  if (!withinAnyRange(urlRanges, lineIndex, index, length)) {
99
- let lineNumber = token.startLine;
100
- let column = index;
101
- if (tokenAdjustments.has(token)) {
102
- const { htmlTextLines, startLine } =
103
- tokenAdjustments.get(token);
104
- let lineDelta = 0;
105
- while (htmlTextLines[lineDelta].length <= column) {
106
- column -= htmlTextLines[lineDelta].length;
107
- lineDelta++;
108
- }
109
- lineNumber = startLine + lineDelta - 1;
110
- }
111
- column++;
85
+ const column = index + 1;
112
86
  addErrorDetailIf(
113
87
  onError,
114
- lineNumber,
88
+ token.startLine,
115
89
  name,
116
90
  nameMatch,
117
91
  null,
package/lib/md045.js CHANGED
@@ -2,17 +2,29 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const { addError, forEachInlineChild } = require("../helpers");
5
+ const { addError } = require("../helpers");
6
+ const { filterByTypes } = require("../helpers/micromark.cjs");
6
7
 
7
8
  module.exports = {
8
9
  "names": [ "MD045", "no-alt-text" ],
9
10
  "description": "Images should have alternate text (alt text)",
10
11
  "tags": [ "accessibility", "images" ],
11
12
  "function": function MD045(params, onError) {
12
- forEachInlineChild(params, "image", function forToken(token) {
13
- if (token.content === "") {
14
- addError(onError, token.lineNumber);
13
+ const images = filterByTypes(params.parsers.micromark.tokens, [ "image" ]);
14
+ for (const image of images) {
15
+ const labelTexts = filterByTypes(image.children, [ "labelText" ]);
16
+ if (labelTexts.some((labelText) => labelText.text.length === 0)) {
17
+ const range = (image.startLine === image.endLine) ?
18
+ [ image.startColumn, image.endColumn - image.startColumn ] :
19
+ undefined;
20
+ addError(
21
+ onError,
22
+ image.startLine,
23
+ undefined,
24
+ undefined,
25
+ range
26
+ );
15
27
  }
16
- });
28
+ }
17
29
  }
18
30
  };
@@ -3,15 +3,18 @@
3
3
  "use strict";
4
4
 
5
5
  const { addError, emphasisOrStrongStyleFor } = require("../helpers");
6
- const { filterByTypes, tokenIfType } = require("../helpers/micromark.cjs");
6
+ const { filterByPredicate, tokenIfType } = require("../helpers/micromark.cjs");
7
7
 
8
8
  const intrawordRe = /\w/;
9
9
 
10
10
  const impl =
11
11
  (params, onError, type, asterisk, underline, style = "consistent") => {
12
12
  const { lines, parsers } = params;
13
- const emphasisTokens =
14
- filterByTypes(parsers.micromark.tokens, [ type ]);
13
+ const emphasisTokens = filterByPredicate(
14
+ parsers.micromark.tokens,
15
+ (token) => token.type === type,
16
+ (token) => ((token.type === "htmlFlow") ? [] : token.children)
17
+ );
15
18
  for (const token of emphasisTokens) {
16
19
  const { children } = token;
17
20
  const childType = `${type}Sequence`;
package/lib/md051.js CHANGED
@@ -2,25 +2,39 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const { addError, addErrorDetailIf, escapeForRegExp, filterTokens,
6
- forEachInlineChild, forEachHeading, htmlElementRe } = require("../helpers");
5
+ const { addError, addErrorDetailIf } = require("../helpers");
6
+ const { filterByPredicate, filterByTypes, getHtmlTagInfo } =
7
+ require("../helpers/micromark.cjs");
7
8
 
8
9
  // Regular expression for identifying HTML anchor names
9
10
  const idRe = /\sid\s*=\s*['"]?([^'"\s>]+)/iu;
10
11
  const nameRe = /\sname\s*=\s*['"]?([^'"\s>]+)/iu;
12
+ const anchorRe = /\{(#[a-z\d]+(?:[-_][a-z\d]+)*)\}/gu;
13
+
14
+ // Sets for filtering heading tokens during conversion
15
+ const childrenExclude = new Set([ "image", "reference", "resource" ]);
16
+ const tokensInclude = new Set([ "codeTextData", "data" ]);
17
+
18
+ /**
19
+ * @typedef {import("../helpers/micromark.cjs").Token} Token
20
+ */
11
21
 
12
22
  /**
13
23
  * Converts a Markdown heading into an HTML fragment according to the rules
14
24
  * used by GitHub.
15
25
  *
16
- * @param {Object} inline Inline token for heading.
26
+ * @param {Token} headingText Heading text token.
17
27
  * @returns {string} Fragment string for heading.
18
28
  */
19
- function convertHeadingToHTMLFragment(inline) {
20
- const inlineText = inline.children
21
- .filter((token) => token.type !== "html_inline")
22
- .map((token) => token.content)
23
- .join("");
29
+ function convertHeadingToHTMLFragment(headingText) {
30
+ const inlineText =
31
+ filterByPredicate(
32
+ headingText.children,
33
+ (token) => tokensInclude.has(token.type),
34
+ (token) => (childrenExclude.has(token.type) ? [] : token.children)
35
+ )
36
+ .map((token) => token.text)
37
+ .join("");
24
38
  return "#" + encodeURIComponent(
25
39
  inlineText
26
40
  .toLowerCase()
@@ -36,84 +50,121 @@ function convertHeadingToHTMLFragment(inline) {
36
50
  );
37
51
  }
38
52
 
53
+ /**
54
+ * Unescapes the text of a String-type micromark Token.
55
+ *
56
+ * @param {Token} token String-type micromark Token.
57
+ * @returns {string} Unescaped token text.
58
+ */
59
+ function unescapeStringTokenText(token) {
60
+ return filterByTypes(token.children, [ "characterEscapeValue", "data" ])
61
+ .map((child) => child.text)
62
+ .join("");
63
+ }
64
+
39
65
  module.exports = {
40
66
  "names": [ "MD051", "link-fragments" ],
41
67
  "description": "Link fragments should be valid",
42
68
  "tags": [ "links" ],
43
69
  "function": function MD051(params, onError) {
70
+ const { tokens } = params.parsers.micromark;
44
71
  const fragments = new Map();
72
+
45
73
  // Process headings
46
- forEachHeading(params, (heading, content, inline) => {
47
- const fragment = convertHeadingToHTMLFragment(inline);
48
- const count = fragments.get(fragment) || 0;
49
- if (count) {
50
- fragments.set(`${fragment}-${count}`, 0);
74
+ const headingTexts = filterByTypes(
75
+ tokens,
76
+ [ "atxHeadingText", "setextHeadingText" ]
77
+ );
78
+ for (const headingText of headingTexts) {
79
+ const fragment = convertHeadingToHTMLFragment(headingText);
80
+ if (fragment !== "#") {
81
+ const count = fragments.get(fragment) || 0;
82
+ if (count) {
83
+ fragments.set(`${fragment}-${count}`, 0);
84
+ }
85
+ fragments.set(fragment, count + 1);
86
+ let match = null;
87
+ while ((match = anchorRe.exec(headingText.text)) !== null) {
88
+ const [ , anchor ] = match;
89
+ if (!fragments.has(anchor)) {
90
+ fragments.set(anchor, 1);
91
+ }
92
+ }
51
93
  }
52
- fragments.set(fragment, count + 1);
53
- });
94
+ }
95
+
54
96
  // Process HTML anchors
55
- const processHtmlToken = (token) => {
56
- let match = null;
57
- while ((match = htmlElementRe.exec(token.content)) !== null) {
58
- const [ tag, , element ] = match;
59
- const anchorMatch = idRe.exec(tag) ||
60
- (element.toLowerCase() === "a" && nameRe.exec(tag));
97
+ for (const token of filterByTypes(tokens, [ "htmlText" ])) {
98
+ const htmlTagInfo = getHtmlTagInfo(token);
99
+ if (htmlTagInfo && !htmlTagInfo.close) {
100
+ const anchorMatch = idRe.exec(token.text) ||
101
+ (htmlTagInfo.name.toLowerCase() === "a" && nameRe.exec(token.text));
61
102
  if (anchorMatch) {
62
103
  fragments.set(`#${anchorMatch[1]}`, 0);
63
104
  }
64
105
  }
65
- };
66
- filterTokens(params, "html_block", processHtmlToken);
67
- forEachInlineChild(params, "html_inline", processHtmlToken);
68
- // Process link fragments
69
- forEachInlineChild(params, "link_open", (token) => {
70
- const { attrs, lineNumber, line } = token;
71
- const href = attrs.find((attr) => attr[0] === "href");
72
- const id = href && href[1];
73
- if (id && (id.length > 1) && (id[0] === "#") && !fragments.has(id)) {
74
- let context = id;
75
- let range = null;
76
- let fixInfo = null;
77
- const match = line.match(
78
- new RegExp(`\\[.*?\\]\\(${escapeForRegExp(context)}\\)`)
79
- );
80
- if (match) {
81
- [ context ] = match;
82
- const index = match.index;
83
- const length = context.length;
84
- range = [ index + 1, length ];
85
- fixInfo = {
86
- "editColumn": index + (length - id.length),
87
- "deleteCount": id.length,
88
- "insertText": null
89
- };
90
- }
91
- const idLower = id.toLowerCase();
92
- const mixedCaseKey = [ ...fragments.keys() ]
93
- .find((key) => idLower === key.toLowerCase());
94
- if (mixedCaseKey) {
95
- (fixInfo || {}).insertText = mixedCaseKey;
96
- addErrorDetailIf(
97
- onError,
98
- lineNumber,
99
- mixedCaseKey,
100
- id,
101
- undefined,
102
- context,
103
- range,
104
- fixInfo
105
- );
106
- } else {
107
- addError(
108
- onError,
109
- lineNumber,
110
- undefined,
111
- context,
112
- // @ts-ignore
113
- range
114
- );
106
+ }
107
+
108
+ // Process link and definition fragments
109
+ const parentChilds = [
110
+ [ "link", "resourceDestinationString" ],
111
+ [ "definition", "definitionDestinationString" ]
112
+ ];
113
+ for (const [ parentType, definitionType ] of parentChilds) {
114
+ const links = filterByTypes(tokens, [ parentType ]);
115
+ for (const link of links) {
116
+ const definitions = filterByTypes(link.children, [ definitionType ]);
117
+ for (const definition of definitions) {
118
+ const { endColumn, startColumn } = definition;
119
+ const text = unescapeStringTokenText(definition);
120
+ if (
121
+ (text.length > 1) &&
122
+ text.startsWith("#") &&
123
+ !fragments.has(text) &&
124
+ !fragments.has(`#${encodeURIComponent(text.slice(1))}`)
125
+ ) {
126
+ // eslint-disable-next-line no-undef-init
127
+ let context = undefined;
128
+ // eslint-disable-next-line no-undef-init
129
+ let range = undefined;
130
+ // eslint-disable-next-line no-undef-init
131
+ let fixInfo = undefined;
132
+ if (link.startLine === link.endLine) {
133
+ context = link.text;
134
+ range = [ link.startColumn, link.endColumn - link.startColumn ];
135
+ fixInfo = {
136
+ "editColumn": startColumn,
137
+ "deleteCount": endColumn - startColumn
138
+ };
139
+ }
140
+ const textLower = text.toLowerCase();
141
+ const mixedCaseKey = [ ...fragments.keys() ]
142
+ .find((key) => textLower === key.toLowerCase());
143
+ if (mixedCaseKey) {
144
+ // @ts-ignore
145
+ (fixInfo || {}).insertText = mixedCaseKey;
146
+ addErrorDetailIf(
147
+ onError,
148
+ link.startLine,
149
+ mixedCaseKey,
150
+ text,
151
+ undefined,
152
+ context,
153
+ range,
154
+ fixInfo
155
+ );
156
+ } else {
157
+ addError(
158
+ onError,
159
+ link.startLine,
160
+ undefined,
161
+ context,
162
+ range
163
+ );
164
+ }
165
+ }
115
166
  }
116
167
  }
117
- });
168
+ }
118
169
  }
119
170
  };
package/lib/md052.js CHANGED
@@ -11,10 +11,14 @@ module.exports = {
11
11
  "Reference links and images should use a label that is defined",
12
12
  "tags": [ "images", "links" ],
13
13
  "function": function MD052(params, onError) {
14
- const { lines } = params;
15
- const { references, definitions } = referenceLinkImageData();
14
+ const { config, lines } = params;
15
+ const shortcutSyntax = config.shortcut_syntax || false;
16
+ const { definitions, references, shortcuts } = referenceLinkImageData();
17
+ const entries = shortcutSyntax ?
18
+ [ ...references.entries(), ...shortcuts.entries() ] :
19
+ references.entries();
16
20
  // Look for links/images that use an undefined link reference
17
- for (const reference of references.entries()) {
21
+ for (const reference of entries) {
18
22
  const [ label, datas ] = reference;
19
23
  if (!definitions.has(label)) {
20
24
  for (const data of datas) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "markdownlint",
3
- "version": "0.29.0",
3
+ "version": "0.31.0",
4
4
  "description": "A Node.js style checker and lint tool for Markdown/CommonMark files.",
5
5
  "type": "commonjs",
6
6
  "main": "./lib/markdownlint.js",
@@ -33,17 +33,16 @@
33
33
  "ci": "npm-run-all --continue-on-error --parallel lint serial-config-docs serial-declaration-demo test-cover && git diff --exit-code",
34
34
  "clone-test-repos-apache-airflow": "cd test-repos && git clone https://github.com/apache/airflow apache-airflow --depth 1 --no-tags --quiet",
35
35
  "clone-test-repos-dotnet-docs": "cd test-repos && git clone https://github.com/dotnet/docs dotnet-docs --depth 1 --no-tags --quiet",
36
- "clone-test-repos-electron-electron": "cd test-repos && git clone https://github.com/electron/electron electron-electron --depth 1 --no-tags --quiet && cd electron-electron && npm install --ignore-scripts @electron/lint-roller",
36
+ "clone-test-repos-electron-electron": "cd test-repos && git clone https://github.com/electron/electron electron-electron --depth 1 --no-tags --quiet && cd electron-electron && npm install --ignore-scripts @electron/lint-roller typescript@4",
37
37
  "clone-test-repos-eslint-eslint": "cd test-repos && git clone https://github.com/eslint/eslint eslint-eslint --depth 1 --no-tags --quiet",
38
38
  "clone-test-repos-mdn-content": "cd test-repos && git clone https://github.com/mdn/content mdn-content --depth 1 --no-tags --quiet",
39
- "clone-test-repos-mdn-translated-content": "cd test-repos && git clone https://github.com/mdn/translated-content mdn-translated-content --depth 1 --no-tags --quiet",
40
39
  "clone-test-repos-mkdocs-mkdocs": "cd test-repos && git clone https://github.com/mkdocs/mkdocs mkdocs-mkdocs --depth 1 --no-tags --quiet",
41
40
  "clone-test-repos-mochajs-mocha": "cd test-repos && git clone https://github.com/mochajs/mocha mochajs-mocha --depth 1 --no-tags --quiet",
42
41
  "clone-test-repos-pi-hole-docs": "cd test-repos && git clone https://github.com/pi-hole/docs pi-hole-docs --depth 1 --no-tags --quiet",
43
42
  "clone-test-repos-v8-v8-dev": "cd test-repos && git clone https://github.com/v8/v8.dev v8-v8-dev --depth 1 --no-tags --quiet",
44
43
  "clone-test-repos-webhintio-hint": "cd test-repos && git clone https://github.com/webhintio/hint webhintio-hint --depth 1 --no-tags --quiet",
45
44
  "clone-test-repos-webpack-webpack-js-org": "cd test-repos && git clone https://github.com/webpack/webpack.js.org webpack-webpack-js-org --depth 1 --no-tags --quiet",
46
- "clone-test-repos": "mkdir test-repos && cd test-repos && npm run clone-test-repos-apache-airflow && npm run clone-test-repos-dotnet-docs && npm run clone-test-repos-electron-electron && npm run clone-test-repos-eslint-eslint && npm run clone-test-repos-mdn-content && npm run clone-test-repos-mdn-translated-content && npm run clone-test-repos-mkdocs-mkdocs && npm run clone-test-repos-mochajs-mocha && npm run clone-test-repos-pi-hole-docs && npm run clone-test-repos-v8-v8-dev && npm run clone-test-repos-webhintio-hint && npm run clone-test-repos-webpack-webpack-js-org",
45
+ "clone-test-repos": "mkdir test-repos && cd test-repos && npm run clone-test-repos-apache-airflow && npm run clone-test-repos-dotnet-docs && npm run clone-test-repos-electron-electron && npm run clone-test-repos-eslint-eslint && npm run clone-test-repos-mdn-content && npm run clone-test-repos-mkdocs-mkdocs && npm run clone-test-repos-mochajs-mocha && npm run clone-test-repos-pi-hole-docs && npm run clone-test-repos-v8-v8-dev && npm run clone-test-repos-webhintio-hint && npm run clone-test-repos-webpack-webpack-js-org",
47
46
  "declaration": "npm run build-declaration && npm run test-declaration",
48
47
  "example": "cd example && node standalone.js && grunt markdownlint --force && gulp markdownlint",
49
48
  "docker-npm-install": "docker run --rm --tty --name npm-install --volume $PWD:/home/workdir --workdir /home/workdir --user node node:latest npm install",
@@ -53,11 +52,12 @@
53
52
  "lint-test-repos": "ava --timeout=10m test/markdownlint-test-repos.js",
54
53
  "serial-config-docs": "npm run build-config && npm run build-docs",
55
54
  "serial-declaration-demo": "npm run build-declaration && npm-run-all --continue-on-error --parallel build-demo test-declaration",
56
- "test": "ava test/markdownlint-test.js test/markdownlint-test-config.js test/markdownlint-test-custom-rules.js test/markdownlint-test-helpers.js test/markdownlint-test-micromark.mjs test/markdownlint-test-result-object.js test/markdownlint-test-scenarios.js",
57
- "test-cover": "c8 --check-coverage --branches 100 --functions 100 --lines 100 --statements 100 --exclude 'test/**' --exclude 'micromark/**' npm test",
55
+ "test": "ava --timeout=30s test/markdownlint-test.js test/markdownlint-test-config.js test/markdownlint-test-custom-rules.js test/markdownlint-test-helpers.js test/markdownlint-test-micromark.mjs test/markdownlint-test-result-object.js test/markdownlint-test-scenarios.js",
56
+ "test-cover": "c8 --100 npm test",
58
57
  "test-declaration": "cd example/typescript && tsc && node type-check.js",
59
58
  "test-extra": "ava --timeout=5m test/markdownlint-test-extra-parse.js test/markdownlint-test-extra-type.js",
60
59
  "update-snapshots": "ava --update-snapshots test/markdownlint-test-micromark.mjs test/markdownlint-test-scenarios.js",
60
+ "update-snapshots-test-repos": "ava --timeout=10m --update-snapshots test/markdownlint-test-repos.js",
61
61
  "upgrade": "npx --yes npm-check-updates --upgrade"
62
62
  },
63
63
  "engines": {
@@ -65,36 +65,37 @@
65
65
  },
66
66
  "dependencies": {
67
67
  "markdown-it": "13.0.1",
68
- "markdownlint-micromark": "0.1.5"
68
+ "markdownlint-micromark": "0.1.7"
69
69
  },
70
70
  "devDependencies": {
71
- "@babel/core": "7.22.1",
72
- "@babel/preset-env": "7.22.4",
73
- "ava": "5.3.0",
74
- "babel-loader": "9.1.2",
75
- "c8": "7.14.0",
76
- "eslint": "8.41.0",
71
+ "@babel/core": "7.22.15",
72
+ "@babel/preset-env": "7.22.15",
73
+ "ava": "5.3.1",
74
+ "babel-loader": "9.1.3",
75
+ "c8": "8.0.1",
76
+ "character-entities": "2.0.2",
77
+ "eslint": "8.48.0",
77
78
  "eslint-plugin-es": "4.1.0",
78
- "eslint-plugin-jsdoc": "46.1.0",
79
- "eslint-plugin-n": "16.0.0",
79
+ "eslint-plugin-jsdoc": "46.5.1",
80
+ "eslint-plugin-n": "16.0.2",
80
81
  "eslint-plugin-regexp": "1.15.0",
81
- "eslint-plugin-unicorn": "47.0.0",
82
- "globby": "13.1.4",
82
+ "eslint-plugin-unicorn": "48.0.1",
83
+ "gemoji": "8.1.0",
84
+ "globby": "13.2.2",
83
85
  "js-yaml": "4.1.0",
84
86
  "markdown-it-for-inline": "0.1.1",
85
87
  "markdown-it-sub": "1.0.0",
86
88
  "markdown-it-sup": "1.0.0",
87
- "markdown-it-texmath": "1.0.0",
88
- "markdownlint-rule-helpers": "0.19.0",
89
+ "markdownlint-rule-helpers": "0.21.0",
89
90
  "npm-run-all": "4.1.5",
90
- "strip-json-comments": "5.0.0",
91
+ "strip-json-comments": "5.0.1",
91
92
  "terser-webpack-plugin": "5.3.9",
92
93
  "toml": "3.0.0",
93
94
  "tv4": "1.3.0",
94
- "typescript": "5.1.3",
95
- "webpack": "5.85.0",
96
- "webpack-cli": "5.1.1",
97
- "yaml": "2.3.1"
95
+ "typescript": "5.2.2",
96
+ "webpack": "5.88.2",
97
+ "webpack-cli": "5.1.4",
98
+ "yaml": "2.3.2"
98
99
  },
99
100
  "keywords": [
100
101
  "markdown",
@@ -139,7 +139,7 @@
139
139
 
140
140
  // MD026/no-trailing-punctuation - Trailing punctuation in heading
141
141
  "MD026": {
142
- // Punctuation characters not allowed at end of headings
142
+ // Punctuation characters
143
143
  "punctuation": ".,;:!。,;:!"
144
144
  },
145
145
 
@@ -265,13 +265,13 @@
265
265
 
266
266
  // MD049/emphasis-style - Emphasis style should be consistent
267
267
  "MD049": {
268
- // Emphasis style should be consistent
268
+ // Emphasis style
269
269
  "style": "consistent"
270
270
  },
271
271
 
272
272
  // MD050/strong-style - Strong style should be consistent
273
273
  "MD050": {
274
- // Strong style should be consistent
274
+ // Strong style
275
275
  "style": "consistent"
276
276
  },
277
277
 
@@ -279,7 +279,10 @@
279
279
  "MD051": true,
280
280
 
281
281
  // MD052/reference-links-images - Reference links and images should use a label that is defined
282
- "MD052": true,
282
+ "MD052": {
283
+ // Include shortcut syntax
284
+ "shortcut_syntax": false
285
+ },
283
286
 
284
287
  // MD053/link-image-reference-definitions - Link and image reference definitions should be needed
285
288
  "MD053": {