markdownlint 0.28.2 → 0.29.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/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.29.0
4
+
5
+ - Update `micromark` parser dependencies for better performance
6
+ - Use `micromark` in MD049/MD050
7
+ - Improve MD034/MD037/MD044/MD049/MD050
8
+ - Support multiple parsers in demo page
9
+ - Remove support for end-of-life Node version 14
10
+ - Update dependencies
11
+
3
12
  ## 0.28.2
4
13
 
5
14
  - Update dependencies for CVE-2023-2251
@@ -13,7 +22,7 @@
13
22
  - Introduce `micromark` parser for better positional data (internal only)
14
23
  - Use `micromark` in MD013/MD033/MD034/MD035/MD038/MD044/MD052/MD053
15
24
  - Simplify file-based test cases
16
- - Unify browser script for demo
25
+ - Unify browser script for demo page
17
26
  - Update dependencies
18
27
 
19
28
  ## 0.27.0
package/CONTRIBUTING.md CHANGED
@@ -17,6 +17,11 @@ Do not add new [`dependencies` to `package.json`][dependencies]. The Markdown
17
17
  parsers [`markdown-it`][markdown-it] and [`micromark`][micromark] are the
18
18
  project's only dependencies.
19
19
 
20
+ Package versions for `dependencies` and `devDependencies` should be specified
21
+ exactly (also known as "pinning"). The short explanation is that doing otherwise
22
+ eventually leads to inconsistent behavior and broken functionality. (See [Pin
23
+ your npm/yarn dependencies][pin-dependencies] for a longer explanation.)
24
+
20
25
  If developing a new rule, start by creating a [custom rule][custom-rules] in its
21
26
  own project. Once written, published, and tested in real world scenarios, open
22
27
  an issue to consider adding it to this project. For rule ideas, see [issues
@@ -83,4 +88,5 @@ Thank you!
83
88
  [micromark]: https://www.npmjs.com/package/micromark
84
89
  [new-rule]: https://github.com/DavidAnson/markdownlint/labels/new%20rule
85
90
  [npm-scripts]: https://docs.npmjs.com/misc/scripts
91
+ [pin-dependencies]: https://maxleiter.com/blog/pin-dependencies
86
92
  [rewriting-history]: https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History
package/README.md CHANGED
@@ -70,6 +70,13 @@ and test cases came directly from that project.
70
70
  [super-linter]: https://github.com/github/super-linter
71
71
  [vscode-markdownlint]: https://marketplace.visualstudio.com/items?itemName=DavidAnson.vscode-markdownlint
72
72
 
73
+ ### References
74
+
75
+ The following specifications are considered authoritative in cases of ambiguity:
76
+
77
+ - [CommonMark](https://spec.commonmark.org/current/)
78
+ - [GitHub Flavored Markdown Spec](https://github.github.com/gfm/)
79
+
73
80
  ## Demonstration
74
81
 
75
82
  [`markdownlint` demo](https://dlaa.me/markdownlint/), an interactive, in-browser
@@ -185,7 +192,7 @@ rules at once.
185
192
  ## Configuration
186
193
 
187
194
  Text passed to `markdownlint` is parsed as Markdown, analyzed, and any
188
- issues reported. Two kinds of text are ignored:
195
+ issues reported. Two kinds of text are ignored by most rules:
189
196
 
190
197
  - [HTML comments](https://www.w3.org/TR/html5/syntax.html#comments)
191
198
  - [Front matter](https://jekyllrb.com/docs/frontmatter/) (see
@@ -1,4 +1,4 @@
1
- /*! markdownlint 0.28.2 https://github.com/DavidAnson/markdownlint @license MIT */
1
+ /*! markdownlint 0.29.0 https://github.com/DavidAnson/markdownlint @license MIT */
2
2
  var markdownlint;
3
3
  /******/ (() => { // webpackBootstrap
4
4
  /******/ var __webpack_modules__ = ({
@@ -1165,61 +1165,6 @@ function applyFixes(input, errors) {
1165
1165
  }
1166
1166
  module.exports.applyFixes = applyFixes;
1167
1167
 
1168
- /**
1169
- * Gets the range and fixInfo values for reporting an error if the expected
1170
- * text is found on the specified line.
1171
- *
1172
- * @param {string[]} lines Lines of Markdown content.
1173
- * @param {number} lineIndex Line index to check.
1174
- * @param {string} search Text to search for.
1175
- * @param {string} replace Text to replace with.
1176
- * @param {number} [instance] Instance on the line (1-based).
1177
- * @returns {Object} Range and fixInfo wrapper.
1178
- */
1179
- module.exports.getRangeAndFixInfoIfFound = function (lines, lineIndex, search, replace) {
1180
- var instance = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
1181
- var range = null;
1182
- var fixInfo = null;
1183
- var searchIndex = -1;
1184
- while (instance > 0) {
1185
- searchIndex = lines[lineIndex].indexOf(search, searchIndex + 1);
1186
- instance--;
1187
- }
1188
- if (searchIndex !== -1) {
1189
- var column = searchIndex + 1;
1190
- var length = search.length;
1191
- range = [column, length];
1192
- fixInfo = {
1193
- "editColumn": column,
1194
- "deleteCount": length,
1195
- "insertText": replace
1196
- };
1197
- }
1198
- return {
1199
- range: range,
1200
- fixInfo: fixInfo
1201
- };
1202
- };
1203
-
1204
- /**
1205
- * Gets the next (subsequent) child token if it is of the expected type.
1206
- *
1207
- * @param {Object} parentToken Parent token.
1208
- * @param {Object} childToken Child token basis.
1209
- * @param {string} nextType Token type of next token.
1210
- * @param {string} nextNextType Token type of next-next token.
1211
- * @returns {Object} Next token.
1212
- */
1213
- function getNextChildToken(parentToken, childToken, nextType, nextNextType) {
1214
- var children = parentToken.children;
1215
- var index = children.indexOf(childToken);
1216
- if (index !== -1 && children.length > index + 2 && children[index + 1].type === nextType && children[index + 2].type === nextNextType) {
1217
- return children[index + 1];
1218
- }
1219
- return null;
1220
- }
1221
- module.exports.getNextChildToken = getNextChildToken;
1222
-
1223
1168
  /**
1224
1169
  * Expands a path with a tilde to an absolute path.
1225
1170
  *
@@ -1374,10 +1319,12 @@ var _require = __webpack_require__(/*! markdownlint-micromark */ "markdownlint-m
1374
1319
  *
1375
1320
  * @param {string} markdown Markdown document.
1376
1321
  * @param {Object} [options] Options for micromark.
1322
+ * @param {boolean} [refsDefined] Whether to treat references as defined.
1377
1323
  * @returns {Object[]} Micromark events.
1378
1324
  */
1379
1325
  function getMicromarkEvents(markdown) {
1380
1326
  var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
1327
+ var refsDefined = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
1381
1328
  // Customize options object to add useful extensions
1382
1329
  options.extensions = options.extensions || [];
1383
1330
  options.extensions.push(gfmAutolinkLiteral, gfmFootnote(), gfmTable);
@@ -1386,10 +1333,12 @@ function getMicromarkEvents(markdown) {
1386
1333
  var encoding = undefined;
1387
1334
  var eol = true;
1388
1335
  var parseContext = parse(options);
1389
- // Customize ParseContext to treat all references as defined
1390
- parseContext.defined.includes = function (searchElement) {
1391
- return searchElement.length > 0;
1392
- };
1336
+ if (refsDefined) {
1337
+ // Customize ParseContext to treat all references as defined
1338
+ parseContext.defined.includes = function (searchElement) {
1339
+ return searchElement.length > 0;
1340
+ };
1341
+ }
1393
1342
  var chunks = preprocess()(markdown, encoding, eol);
1394
1343
  var events = postprocess(parseContext.document().write(chunks));
1395
1344
  return events;
@@ -1400,12 +1349,14 @@ function getMicromarkEvents(markdown) {
1400
1349
  *
1401
1350
  * @param {string} markdown Markdown document.
1402
1351
  * @param {Object} [options] Options for micromark.
1352
+ * @param {boolean} [refsDefined] Whether to treat references as defined.
1403
1353
  * @returns {Token[]} Micromark tokens (frozen).
1404
1354
  */
1405
1355
  function micromarkParse(markdown) {
1406
1356
  var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
1357
+ var refsDefined = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
1407
1358
  // Use micromark to parse document into Events
1408
- var events = getMicromarkEvents(markdown, options);
1359
+ var events = getMicromarkEvents(markdown, options, refsDefined);
1409
1360
 
1410
1361
  // Create Token objects
1411
1362
  var document = [];
@@ -1429,12 +1380,7 @@ function micromarkParse(markdown) {
1429
1380
  startLine = start["line"];
1430
1381
  var endColumn = end["column"],
1431
1382
  endLine = end["line"];
1432
- var text = null;
1433
- try {
1434
- text = context.sliceSerialize(token);
1435
- } catch (_unused) {
1436
- // https://github.com/micromark/micromark/issues/131
1437
- }
1383
+ var text = context.sliceSerialize(token);
1438
1384
  if (kind === "enter") {
1439
1385
  var previous = current;
1440
1386
  history.push(previous);
@@ -1466,6 +1412,25 @@ function micromarkParse(markdown) {
1466
1412
  return document;
1467
1413
  }
1468
1414
 
1415
+ // /**
1416
+ // * Log the structure of a Micromark token list.
1417
+ // *
1418
+ // * @param {Token[]} tokens Micromark tokens.
1419
+ // * @param {number} depth Tree depth.
1420
+ // * @returns {void}
1421
+ // */
1422
+ // function consoleLogTokens(tokens, depth = 0) {
1423
+ // for (const token of tokens) {
1424
+ // const { children, text, type } = token;
1425
+ // console.log(
1426
+ // `${" ".repeat(depth * 2)}${type} ${text.replace(/\n/g, "\\n")}`
1427
+ // );
1428
+ // if (children.length > 0) {
1429
+ // consoleLogTokens(children, depth + 1);
1430
+ // }
1431
+ // }
1432
+ // }
1433
+
1469
1434
  /**
1470
1435
  * Filter a list of Micromark tokens by predicate.
1471
1436
  *
@@ -1563,6 +1528,17 @@ function matchAndGetTokensByType(tokens, matchTypes, resultTypes) {
1563
1528
  }
1564
1529
  return result;
1565
1530
  }
1531
+
1532
+ /**
1533
+ * Returns the specified token iff it is of the desired type.
1534
+ *
1535
+ * @param {Token} token Micromark token candidate.
1536
+ * @param {string} type Desired type.
1537
+ * @returns {Token | null} Token instance.
1538
+ */
1539
+ function tokenIfType(token, type) {
1540
+ return token && token.type === type ? token : null;
1541
+ }
1566
1542
  module.exports = {
1567
1543
  "parse": micromarkParse,
1568
1544
  filterByPredicate: filterByPredicate,
@@ -1570,7 +1546,8 @@ module.exports = {
1570
1546
  getHtmlTagInfo: getHtmlTagInfo,
1571
1547
  getMicromarkEvents: getMicromarkEvents,
1572
1548
  getTokenTextByType: getTokenTextByType,
1573
- matchAndGetTokensByType: matchAndGetTokensByType
1549
+ matchAndGetTokensByType: matchAndGetTokensByType,
1550
+ tokenIfType: tokenIfType
1574
1551
  };
1575
1552
 
1576
1553
  /***/ }),
@@ -1636,7 +1613,7 @@ module.exports.referenceLinkImageData = function () {
1636
1613
  module.exports.deprecatedRuleNames = ["MD002", "MD006"];
1637
1614
  module.exports.fixableRuleNames = ["MD004", "MD005", "MD006", "MD007", "MD009", "MD010", "MD011", "MD012", "MD014", "MD018", "MD019", "MD020", "MD021", "MD022", "MD023", "MD026", "MD027", "MD030", "MD031", "MD032", "MD034", "MD037", "MD038", "MD039", "MD044", "MD047", "MD049", "MD050", "MD051", "MD053"];
1638
1615
  module.exports.homepage = "https://github.com/DavidAnson/markdownlint";
1639
- module.exports.version = "0.28.2";
1616
+ module.exports.version = "0.29.0";
1640
1617
 
1641
1618
  /***/ }),
1642
1619
 
@@ -5008,60 +4985,68 @@ var _require = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js"),
5008
4985
  addErrorContext = _require.addErrorContext;
5009
4986
  var _require2 = __webpack_require__(/*! ../helpers/micromark.cjs */ "../helpers/micromark.cjs"),
5010
4987
  filterByPredicate = _require2.filterByPredicate,
5011
- getHtmlTagInfo = _require2.getHtmlTagInfo;
4988
+ getHtmlTagInfo = _require2.getHtmlTagInfo,
4989
+ parse = _require2.parse;
5012
4990
  module.exports = {
5013
4991
  "names": ["MD034", "no-bare-urls"],
5014
4992
  "description": "Bare URL used",
5015
4993
  "tags": ["links", "url"],
5016
4994
  "function": function MD034(params, onError) {
5017
- var literalAutolinks = filterByPredicate(params.parsers.micromark.tokens, function (token) {
5018
- return token.type === "literalAutolink";
5019
- }, function (token) {
5020
- var children = token.children;
5021
- var result = [];
5022
- for (var i = 0; i < children.length; i++) {
5023
- var openToken = children[i];
5024
- var openTagInfo = getHtmlTagInfo(openToken);
5025
- if (openTagInfo && !openTagInfo.close) {
5026
- var count = 1;
5027
- for (var j = i + 1; j < children.length; j++) {
5028
- var closeToken = children[j];
5029
- var closeTagInfo = getHtmlTagInfo(closeToken);
5030
- if (closeTagInfo && openTagInfo.name === closeTagInfo.name) {
5031
- if (closeTagInfo.close) {
5032
- count--;
5033
- if (count === 0) {
5034
- i = j;
5035
- break;
4995
+ var literalAutolinks = function literalAutolinks(tokens) {
4996
+ return filterByPredicate(tokens, function (token) {
4997
+ return token.type === "literalAutolink";
4998
+ }, function (token) {
4999
+ var children = token.children;
5000
+ var result = [];
5001
+ for (var i = 0; i < children.length; i++) {
5002
+ var openToken = children[i];
5003
+ var openTagInfo = getHtmlTagInfo(openToken);
5004
+ if (openTagInfo && !openTagInfo.close) {
5005
+ var count = 1;
5006
+ for (var j = i + 1; j < children.length; j++) {
5007
+ var closeToken = children[j];
5008
+ var closeTagInfo = getHtmlTagInfo(closeToken);
5009
+ if (closeTagInfo && openTagInfo.name === closeTagInfo.name) {
5010
+ if (closeTagInfo.close) {
5011
+ count--;
5012
+ if (count === 0) {
5013
+ i = j;
5014
+ break;
5015
+ }
5016
+ } else {
5017
+ count++;
5036
5018
  }
5037
- } else {
5038
- count++;
5039
5019
  }
5040
5020
  }
5021
+ } else {
5022
+ result.push(openToken);
5041
5023
  }
5042
- } else {
5043
- result.push(openToken);
5044
5024
  }
5025
+ return result;
5026
+ });
5027
+ };
5028
+ if (literalAutolinks(params.parsers.micromark.tokens).length > 0) {
5029
+ // Re-parse with correct link/image reference definition handling
5030
+ var document = params.lines.join("\n");
5031
+ var tokens = parse(document, undefined, false);
5032
+ var _iterator = _createForOfIteratorHelper(literalAutolinks(tokens)),
5033
+ _step;
5034
+ try {
5035
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
5036
+ var token = _step.value;
5037
+ var range = [token.startColumn, token.endColumn - token.startColumn];
5038
+ var fixInfo = {
5039
+ "editColumn": range[0],
5040
+ "deleteCount": range[1],
5041
+ "insertText": "<".concat(token.text, ">")
5042
+ };
5043
+ addErrorContext(onError, token.startLine, token.text, null, null, range, fixInfo);
5044
+ }
5045
+ } catch (err) {
5046
+ _iterator.e(err);
5047
+ } finally {
5048
+ _iterator.f();
5045
5049
  }
5046
- return result;
5047
- });
5048
- var _iterator = _createForOfIteratorHelper(literalAutolinks),
5049
- _step;
5050
- try {
5051
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
5052
- var token = _step.value;
5053
- var range = [token.startColumn, token.endColumn - token.startColumn];
5054
- var fixInfo = {
5055
- "editColumn": range[0],
5056
- "deleteCount": range[1],
5057
- "insertText": "<".concat(token.text, ">")
5058
- };
5059
- addErrorContext(onError, token.startLine, token.text, null, null, range, fixInfo);
5060
- }
5061
- } catch (err) {
5062
- _iterator.e(err);
5063
- } finally {
5064
- _iterator.f();
5065
5050
  }
5066
5051
  }
5067
5052
  };
@@ -5215,11 +5200,12 @@ var _require2 = __webpack_require__(/*! ./cache */ "../lib/cache.js"),
5215
5200
  htmlElementRanges = _require2.htmlElementRanges,
5216
5201
  lineMetadata = _require2.lineMetadata;
5217
5202
  var emphasisRe = /(^|[^\\]|\\\\)(?:(\*{1,3})|(_{1,3}))/g;
5218
- var embeddedUnderscoreRe = /([A-Za-z\d])_([A-Za-z\d])/g;
5203
+ var embeddedUnderscoreRe = /([A-Za-z\d])(_([A-Za-z\d]))+/g;
5219
5204
  var asteriskListItemMarkerRe = /^([\s>]*)\*(\s+)/;
5220
5205
  var leftSpaceRe = /^\s+/;
5221
5206
  var rightSpaceRe = /\s+$/;
5222
5207
  var tablePipeRe = /\|/;
5208
+ var allUnderscoresRe = /_/g;
5223
5209
  module.exports = {
5224
5210
  "names": ["MD037", "no-space-in-emphasis"],
5225
5211
  "description": "Spaces inside emphasis markers",
@@ -5285,7 +5271,9 @@ module.exports = {
5285
5271
  // Emphasis has no meaning here
5286
5272
  return;
5287
5273
  }
5288
- var patchedLine = line.replace(embeddedUnderscoreRe, "$1 $2");
5274
+ var patchedLine = line.replace(embeddedUnderscoreRe, function (match) {
5275
+ return match.replace(allUnderscoresRe, " ");
5276
+ });
5289
5277
  if (onItemStart) {
5290
5278
  // Trim overlapping '*' list item marker
5291
5279
  patchedLine = patchedLine.replace(asteriskListItemMarkerRe, "$1 $2");
@@ -5373,7 +5361,8 @@ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len
5373
5361
  var _require = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js"),
5374
5362
  addErrorContext = _require.addErrorContext;
5375
5363
  var _require2 = __webpack_require__(/*! ../helpers/micromark.cjs */ "../helpers/micromark.cjs"),
5376
- filterByTypes = _require2.filterByTypes;
5364
+ filterByTypes = _require2.filterByTypes,
5365
+ tokenIfType = _require2.tokenIfType;
5377
5366
  var leftSpaceRe = /^\s(?:[^`]|$)/;
5378
5367
  var rightSpaceRe = /[^`]\s$/;
5379
5368
  var trimCodeText = function trimCodeText(text, start, end) {
@@ -5386,9 +5375,6 @@ var trimCodeText = function trimCodeText(text, start, end) {
5386
5375
  }
5387
5376
  return text;
5388
5377
  };
5389
- var tokenIfType = function tokenIfType(token, type) {
5390
- return token && token.type === type && token;
5391
- };
5392
5378
  module.exports = {
5393
5379
  "names": ["MD038", "no-space-in-code"],
5394
5380
  "description": "Spaces inside code span elements",
@@ -5781,20 +5767,21 @@ module.exports = {
5781
5767
 
5782
5768
 
5783
5769
 
5784
- function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
5785
- function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
5786
- function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
5787
- function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
5788
5770
  function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
5789
5771
  function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
5790
5772
  function _iterableToArrayLimit(arr, i) { var _i = null == arr ? null : "undefined" != typeof Symbol && arr[Symbol.iterator] || arr["@@iterator"]; if (null != _i) { var _s, _e, _x, _r, _arr = [], _n = !0, _d = !1; try { if (_x = (_i = _i.call(arr)).next, 0 === i) { if (Object(_i) !== _i) return; _n = !1; } else for (; !(_n = (_s = _x.call(_i)).done) && (_arr.push(_s.value), _arr.length !== i); _n = !0); } catch (err) { _d = !0, _e = err; } finally { try { if (!_n && null != _i["return"] && (_r = _i["return"](), Object(_r) !== _r)) return; } finally { if (_d) throw _e; } } return _arr; } }
5791
5773
  function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
5792
5774
  function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e2) { throw _e2; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e3) { didErr = true; err = _e3; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
5775
+ function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
5776
+ function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
5793
5777
  function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
5778
+ function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
5779
+ function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
5794
5780
  function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
5795
5781
  var _require = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js"),
5796
5782
  addErrorDetailIf = _require.addErrorDetailIf,
5797
5783
  escapeForRegExp = _require.escapeForRegExp,
5784
+ newLineRe = _require.newLineRe,
5798
5785
  withinAnyRange = _require.withinAnyRange;
5799
5786
  var _require2 = __webpack_require__(/*! ../helpers/micromark.cjs */ "../helpers/micromark.cjs"),
5800
5787
  filterByPredicate = _require2.filterByPredicate,
@@ -5820,12 +5807,39 @@ module.exports = {
5820
5807
  scannedTypes.add("codeFlowValue");
5821
5808
  scannedTypes.add("codeTextData");
5822
5809
  }
5810
+ var tokenAdjustments = new Map();
5823
5811
  var contentTokens = filterByPredicate(params.parsers.micromark.tokens, function (token) {
5824
5812
  return scannedTypes.has(token.type);
5825
5813
  }, function (token) {
5826
5814
  var children = token.children;
5815
+ var startLine = token.startLine,
5816
+ text = token.text;
5827
5817
  if (!includeHtmlElements && token.type === "htmlFlow") {
5828
- children = children.slice(1, -1);
5818
+ if (text.startsWith("<!--")) {
5819
+ // Remove comment content
5820
+ children = [];
5821
+ } else {
5822
+ // Re-parse to get htmlText elements for detailed tokenization
5823
+ var htmlTextLines = "<md044>\n".concat(text, "\n</md044>").split(newLineRe);
5824
+ children = parse(htmlTextLines.join(""));
5825
+ var reTokens = _toConsumableArray(children);
5826
+ var _iterator = _createForOfIteratorHelper(reTokens),
5827
+ _step;
5828
+ try {
5829
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
5830
+ var reToken = _step.value;
5831
+ tokenAdjustments.set(reToken, {
5832
+ htmlTextLines: htmlTextLines,
5833
+ startLine: startLine
5834
+ });
5835
+ reTokens.push.apply(reTokens, _toConsumableArray(reToken.children));
5836
+ }
5837
+ } catch (err) {
5838
+ _iterator.e(err);
5839
+ } finally {
5840
+ _iterator.f();
5841
+ }
5842
+ }
5829
5843
  }
5830
5844
  return children.filter(function (t) {
5831
5845
  return !ignoredChildTypes.has(t.type);
@@ -5833,21 +5847,21 @@ module.exports = {
5833
5847
  });
5834
5848
  var exclusions = [];
5835
5849
  var autoLinked = new Set();
5836
- var _iterator = _createForOfIteratorHelper(names),
5837
- _step;
5850
+ var _iterator2 = _createForOfIteratorHelper(names),
5851
+ _step2;
5838
5852
  try {
5839
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
5840
- var name = _step.value;
5853
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
5854
+ var name = _step2.value;
5841
5855
  var escapedName = escapeForRegExp(name);
5842
5856
  var startNamePattern = /^\W/.test(name) ? "" : "\\b_*";
5843
5857
  var endNamePattern = /\W$/.test(name) ? "" : "_*\\b";
5844
5858
  var namePattern = "(".concat(startNamePattern, ")(").concat(escapedName, ")").concat(endNamePattern);
5845
5859
  var nameRe = new RegExp(namePattern, "gi");
5846
- var _iterator2 = _createForOfIteratorHelper(contentTokens),
5847
- _step2;
5860
+ var _iterator3 = _createForOfIteratorHelper(contentTokens),
5861
+ _step3;
5848
5862
  try {
5849
5863
  var _loop = function _loop() {
5850
- var token = _step2.value;
5864
+ var token = _step3.value;
5851
5865
  var match = null;
5852
5866
  var _loop2 = function _loop2() {
5853
5867
  var _match = match,
@@ -5867,8 +5881,21 @@ module.exports = {
5867
5881
  autoLinked.add(token);
5868
5882
  }
5869
5883
  if (!withinAnyRange(urlRanges, lineIndex, index, length)) {
5870
- var column = index + 1;
5871
- addErrorDetailIf(onError, token.startLine, name, nameMatch, null, null, [column, length], {
5884
+ var lineNumber = token.startLine;
5885
+ var column = index;
5886
+ if (tokenAdjustments.has(token)) {
5887
+ var _tokenAdjustments$get = tokenAdjustments.get(token),
5888
+ htmlTextLines = _tokenAdjustments$get.htmlTextLines,
5889
+ startLine = _tokenAdjustments$get.startLine;
5890
+ var lineDelta = 0;
5891
+ while (htmlTextLines[lineDelta].length <= column) {
5892
+ column -= htmlTextLines[lineDelta].length;
5893
+ lineDelta++;
5894
+ }
5895
+ lineNumber = startLine + lineDelta - 1;
5896
+ }
5897
+ column++;
5898
+ addErrorDetailIf(onError, lineNumber, name, nameMatch, null, null, [column, length], {
5872
5899
  "editColumn": column,
5873
5900
  "deleteCount": length,
5874
5901
  "insertText": name
@@ -5881,19 +5908,19 @@ module.exports = {
5881
5908
  _loop2();
5882
5909
  }
5883
5910
  };
5884
- for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
5911
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
5885
5912
  _loop();
5886
5913
  }
5887
5914
  } catch (err) {
5888
- _iterator2.e(err);
5915
+ _iterator3.e(err);
5889
5916
  } finally {
5890
- _iterator2.f();
5917
+ _iterator3.f();
5891
5918
  }
5892
5919
  }
5893
5920
  } catch (err) {
5894
- _iterator.e(err);
5921
+ _iterator2.e(err);
5895
5922
  } finally {
5896
- _iterator.f();
5923
+ _iterator2.f();
5897
5924
  }
5898
5925
  }
5899
5926
  };
@@ -6072,57 +6099,69 @@ module.exports = {
6072
6099
 
6073
6100
 
6074
6101
 
6102
+ function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
6103
+ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
6104
+ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
6075
6105
  var _require = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js"),
6076
6106
  addError = _require.addError,
6077
- emphasisOrStrongStyleFor = _require.emphasisOrStrongStyleFor,
6078
- forEachInlineChild = _require.forEachInlineChild,
6079
- getNextChildToken = _require.getNextChildToken,
6080
- getRangeAndFixInfoIfFound = _require.getRangeAndFixInfoIfFound;
6081
- var impl = function impl(params, onError, tagPrefix, asterisk, underline, style) {
6082
- var lastLineNumber = -1;
6083
- var instances = new Map();
6084
- forEachInlineChild(params, "".concat(tagPrefix, "_open"), function (token, parent) {
6085
- var lineNumber = token.lineNumber,
6086
- markup = token.markup;
6087
- var markupStyle = emphasisOrStrongStyleFor(markup);
6088
- if (style === "consistent") {
6089
- style = markupStyle;
6090
- }
6091
- if (style !== markupStyle) {
6092
- var rangeAndFixInfo = {};
6093
- var contentToken = getNextChildToken(parent, token, "text", "".concat(tagPrefix, "_close"));
6094
- if (contentToken) {
6095
- var content = contentToken.content;
6096
- var actual = "".concat(markup).concat(content).concat(markup);
6097
- var expectedMarkup = style === "asterisk" ? asterisk : underline;
6098
- var expected = "".concat(expectedMarkup).concat(content).concat(expectedMarkup);
6099
- if (lastLineNumber !== lineNumber) {
6100
- lastLineNumber = lineNumber;
6101
- instances.clear();
6107
+ emphasisOrStrongStyleFor = _require.emphasisOrStrongStyleFor;
6108
+ var _require2 = __webpack_require__(/*! ../helpers/micromark.cjs */ "../helpers/micromark.cjs"),
6109
+ filterByTypes = _require2.filterByTypes,
6110
+ tokenIfType = _require2.tokenIfType;
6111
+ var intrawordRe = /\w/;
6112
+ var impl = function impl(params, onError, type, asterisk, underline) {
6113
+ var style = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : "consistent";
6114
+ var lines = params.lines,
6115
+ parsers = params.parsers;
6116
+ var emphasisTokens = filterByTypes(parsers.micromark.tokens, [type]);
6117
+ var _iterator = _createForOfIteratorHelper(emphasisTokens),
6118
+ _step;
6119
+ try {
6120
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
6121
+ var token = _step.value;
6122
+ var children = token.children;
6123
+ var childType = "".concat(type, "Sequence");
6124
+ var startSequence = tokenIfType(children[0], childType);
6125
+ var endSequence = tokenIfType(children[children.length - 1], childType);
6126
+ if (startSequence && endSequence) {
6127
+ var markupStyle = emphasisOrStrongStyleFor(startSequence.text);
6128
+ if (style === "consistent") {
6129
+ style = markupStyle;
6130
+ }
6131
+ if (style !== markupStyle) {
6132
+ var underscoreIntraword = style === "underscore" && (intrawordRe.test(lines[startSequence.startLine - 1][startSequence.startColumn - 2]) || intrawordRe.test(lines[endSequence.endLine - 1][endSequence.endColumn - 1]));
6133
+ if (!underscoreIntraword) {
6134
+ for (var _i = 0, _arr = [startSequence, endSequence]; _i < _arr.length; _i++) {
6135
+ var sequence = _arr[_i];
6136
+ addError(onError, sequence.startLine, "Expected: ".concat(style, "; Actual: ").concat(markupStyle), undefined, [sequence.startColumn, sequence.text.length], {
6137
+ "editColumn": sequence.startColumn,
6138
+ "deleteCount": sequence.text.length,
6139
+ "insertText": style === "asterisk" ? asterisk : underline
6140
+ });
6141
+ }
6142
+ }
6102
6143
  }
6103
- var instance = (instances.get(expected) || 0) + 1;
6104
- instances.set(expected, instance);
6105
- rangeAndFixInfo = getRangeAndFixInfoIfFound(params.lines, lineNumber - 1, actual, expected, instance);
6106
6144
  }
6107
- addError(onError, lineNumber, "Expected: ".concat(style, "; Actual: ").concat(markupStyle), null, rangeAndFixInfo.range, rangeAndFixInfo.fixInfo);
6108
6145
  }
6109
- });
6146
+ } catch (err) {
6147
+ _iterator.e(err);
6148
+ } finally {
6149
+ _iterator.f();
6150
+ }
6110
6151
  };
6111
6152
  module.exports = [{
6112
6153
  "names": ["MD049", "emphasis-style"],
6113
6154
  "description": "Emphasis style should be consistent",
6114
6155
  "tags": ["emphasis"],
6115
6156
  "function": function MD049(params, onError) {
6116
- var style = String(params.config.style || "consistent");
6117
- return impl(params, onError, "em", "*", "_", style);
6157
+ return impl(params, onError, "emphasis", "*", "_", params.config.style || undefined);
6118
6158
  }
6119
6159
  }, {
6120
6160
  "names": ["MD050", "strong-style"],
6121
6161
  "description": "Strong style should be consistent",
6122
6162
  "tags": ["emphasis"],
6123
6163
  "function": function MD050(params, onError) {
6124
- var style = String(params.config.style || "consistent");
6125
- return impl(params, onError, "strong", "**", "__", style);
6164
+ return impl(params, onError, "strong", "**", "__", params.config.style || undefined);
6126
6165
  }
6127
6166
  }];
6128
6167
 
@@ -1080,66 +1080,6 @@ function applyFixes(input, errors) {
1080
1080
  }
1081
1081
  module.exports.applyFixes = applyFixes;
1082
1082
 
1083
- /**
1084
- * Gets the range and fixInfo values for reporting an error if the expected
1085
- * text is found on the specified line.
1086
- *
1087
- * @param {string[]} lines Lines of Markdown content.
1088
- * @param {number} lineIndex Line index to check.
1089
- * @param {string} search Text to search for.
1090
- * @param {string} replace Text to replace with.
1091
- * @param {number} [instance] Instance on the line (1-based).
1092
- * @returns {Object} Range and fixInfo wrapper.
1093
- */
1094
- module.exports.getRangeAndFixInfoIfFound =
1095
- (lines, lineIndex, search, replace, instance = 1) => {
1096
- let range = null;
1097
- let fixInfo = null;
1098
- let searchIndex = -1;
1099
- while (instance > 0) {
1100
- searchIndex = lines[lineIndex].indexOf(search, searchIndex + 1);
1101
- instance--;
1102
- }
1103
- if (searchIndex !== -1) {
1104
- const column = searchIndex + 1;
1105
- const length = search.length;
1106
- range = [ column, length ];
1107
- fixInfo = {
1108
- "editColumn": column,
1109
- "deleteCount": length,
1110
- "insertText": replace
1111
- };
1112
- }
1113
- return {
1114
- range,
1115
- fixInfo
1116
- };
1117
- };
1118
-
1119
- /**
1120
- * Gets the next (subsequent) child token if it is of the expected type.
1121
- *
1122
- * @param {Object} parentToken Parent token.
1123
- * @param {Object} childToken Child token basis.
1124
- * @param {string} nextType Token type of next token.
1125
- * @param {string} nextNextType Token type of next-next token.
1126
- * @returns {Object} Next token.
1127
- */
1128
- function getNextChildToken(parentToken, childToken, nextType, nextNextType) {
1129
- const { children } = parentToken;
1130
- const index = children.indexOf(childToken);
1131
- if (
1132
- (index !== -1) &&
1133
- (children.length > index + 2) &&
1134
- (children[index + 1].type === nextType) &&
1135
- (children[index + 2].type === nextNextType)
1136
- ) {
1137
- return children[index + 1];
1138
- }
1139
- return null;
1140
- }
1141
- module.exports.getNextChildToken = getNextChildToken;
1142
-
1143
1083
  /**
1144
1084
  * Expands a path with a tilde to an absolute path.
1145
1085
  *
@@ -26,9 +26,10 @@ const {
26
26
  *
27
27
  * @param {string} markdown Markdown document.
28
28
  * @param {Object} [options] Options for micromark.
29
+ * @param {boolean} [refsDefined] Whether to treat references as defined.
29
30
  * @returns {Object[]} Micromark events.
30
31
  */
31
- function getMicromarkEvents(markdown, options = {}) {
32
+ function getMicromarkEvents(markdown, options = {}, refsDefined = true) {
32
33
 
33
34
  // Customize options object to add useful extensions
34
35
  options.extensions = options.extensions || [];
@@ -38,8 +39,10 @@ function getMicromarkEvents(markdown, options = {}) {
38
39
  const encoding = undefined;
39
40
  const eol = true;
40
41
  const parseContext = parse(options);
41
- // Customize ParseContext to treat all references as defined
42
- parseContext.defined.includes = (searchElement) => searchElement.length > 0;
42
+ if (refsDefined) {
43
+ // Customize ParseContext to treat all references as defined
44
+ parseContext.defined.includes = (searchElement) => searchElement.length > 0;
45
+ }
43
46
  const chunks = preprocess()(markdown, encoding, eol);
44
47
  const events = postprocess(parseContext.document().write(chunks));
45
48
  return events;
@@ -50,12 +53,14 @@ function getMicromarkEvents(markdown, options = {}) {
50
53
  *
51
54
  * @param {string} markdown Markdown document.
52
55
  * @param {Object} [options] Options for micromark.
56
+ * @param {boolean} [refsDefined] Whether to treat references as defined.
53
57
  * @returns {Token[]} Micromark tokens (frozen).
54
58
  */
55
- function micromarkParse(markdown, options = {}) {
59
+ function micromarkParse(markdown, options = {}, refsDefined = true) {
56
60
 
57
61
  // Use micromark to parse document into Events
58
- const events = getMicromarkEvents(markdown, options);
62
+ const events =
63
+ getMicromarkEvents(markdown, options, refsDefined);
59
64
 
60
65
  // Create Token objects
61
66
  const document = [];
@@ -68,12 +73,7 @@ function micromarkParse(markdown, options = {}) {
68
73
  const { type, start, end } = token;
69
74
  const { "column": startColumn, "line": startLine } = start;
70
75
  const { "column": endColumn, "line": endLine } = end;
71
- let text = null;
72
- try {
73
- text = context.sliceSerialize(token);
74
- } catch {
75
- // https://github.com/micromark/micromark/issues/131
76
- }
76
+ const text = context.sliceSerialize(token);
77
77
  if (kind === "enter") {
78
78
  const previous = current;
79
79
  history.push(previous);
@@ -100,6 +100,25 @@ function micromarkParse(markdown, options = {}) {
100
100
  return document;
101
101
  }
102
102
 
103
+ // /**
104
+ // * Log the structure of a Micromark token list.
105
+ // *
106
+ // * @param {Token[]} tokens Micromark tokens.
107
+ // * @param {number} depth Tree depth.
108
+ // * @returns {void}
109
+ // */
110
+ // function consoleLogTokens(tokens, depth = 0) {
111
+ // for (const token of tokens) {
112
+ // const { children, text, type } = token;
113
+ // console.log(
114
+ // `${" ".repeat(depth * 2)}${type} ${text.replace(/\n/g, "\\n")}`
115
+ // );
116
+ // if (children.length > 0) {
117
+ // consoleLogTokens(children, depth + 1);
118
+ // }
119
+ // }
120
+ // }
121
+
103
122
  /**
104
123
  * Filter a list of Micromark tokens by predicate.
105
124
  *
@@ -198,6 +217,17 @@ function matchAndGetTokensByType(tokens, matchTypes, resultTypes) {
198
217
  return result;
199
218
  }
200
219
 
220
+ /**
221
+ * Returns the specified token iff it is of the desired type.
222
+ *
223
+ * @param {Token} token Micromark token candidate.
224
+ * @param {string} type Desired type.
225
+ * @returns {Token | null} Token instance.
226
+ */
227
+ function tokenIfType(token, type) {
228
+ return (token && (token.type === type)) ? token : null;
229
+ }
230
+
201
231
  module.exports = {
202
232
  "parse": micromarkParse,
203
233
  filterByPredicate,
@@ -205,5 +235,6 @@ module.exports = {
205
235
  getHtmlTagInfo,
206
236
  getMicromarkEvents,
207
237
  getTokenTextByType,
208
- matchAndGetTokensByType
238
+ matchAndGetTokensByType,
239
+ tokenIfType
209
240
  };
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "markdownlint-rule-helpers",
3
- "version": "0.19.0",
3
+ "version": "0.20.0",
4
4
  "description": "A collection of markdownlint helper functions for custom rules",
5
5
  "main": "./helpers.js",
6
6
  "exports": "./helpers.js",
package/lib/constants.js CHANGED
@@ -11,4 +11,4 @@ module.exports.fixableRuleNames = [
11
11
  "MD044", "MD047", "MD049", "MD050", "MD051", "MD053"
12
12
  ];
13
13
  module.exports.homepage = "https://github.com/DavidAnson/markdownlint";
14
- module.exports.version = "0.28.2";
14
+ module.exports.version = "0.29.0";
package/lib/md034.js CHANGED
@@ -3,7 +3,7 @@
3
3
  "use strict";
4
4
 
5
5
  const { addErrorContext } = require("../helpers");
6
- const { filterByPredicate, getHtmlTagInfo } =
6
+ const { filterByPredicate, getHtmlTagInfo, parse } =
7
7
  require("../helpers/micromark.cjs");
8
8
 
9
9
  module.exports = {
@@ -11,9 +11,9 @@ module.exports = {
11
11
  "description": "Bare URL used",
12
12
  "tags": [ "links", "url" ],
13
13
  "function": function MD034(params, onError) {
14
- const literalAutolinks =
14
+ const literalAutolinks = (tokens) => (
15
15
  filterByPredicate(
16
- params.parsers.micromark.tokens,
16
+ tokens,
17
17
  (token) => token.type === "literalAutolink",
18
18
  (token) => {
19
19
  const { children } = token;
@@ -43,26 +43,33 @@ module.exports = {
43
43
  }
44
44
  }
45
45
  return result;
46
- });
47
- for (const token of literalAutolinks) {
48
- const range = [
49
- token.startColumn,
50
- token.endColumn - token.startColumn
51
- ];
52
- const fixInfo = {
53
- "editColumn": range[0],
54
- "deleteCount": range[1],
55
- "insertText": `<${token.text}>`
56
- };
57
- addErrorContext(
58
- onError,
59
- token.startLine,
60
- token.text,
61
- null,
62
- null,
63
- range,
64
- fixInfo
65
- );
46
+ }
47
+ )
48
+ );
49
+ if (literalAutolinks(params.parsers.micromark.tokens).length > 0) {
50
+ // Re-parse with correct link/image reference definition handling
51
+ const document = params.lines.join("\n");
52
+ const tokens = parse(document, undefined, false);
53
+ for (const token of literalAutolinks(tokens)) {
54
+ const range = [
55
+ token.startColumn,
56
+ token.endColumn - token.startColumn
57
+ ];
58
+ const fixInfo = {
59
+ "editColumn": range[0],
60
+ "deleteCount": range[1],
61
+ "insertText": `<${token.text}>`
62
+ };
63
+ addErrorContext(
64
+ onError,
65
+ token.startLine,
66
+ token.text,
67
+ null,
68
+ null,
69
+ range,
70
+ fixInfo
71
+ );
72
+ }
66
73
  }
67
74
  }
68
75
  };
package/lib/md037.js CHANGED
@@ -7,11 +7,12 @@ const { addErrorContext, emphasisMarkersInContent, forEachLine, isBlankLine,
7
7
  const { htmlElementRanges, lineMetadata } = require("./cache");
8
8
 
9
9
  const emphasisRe = /(^|[^\\]|\\\\)(?:(\*{1,3})|(_{1,3}))/g;
10
- const embeddedUnderscoreRe = /([A-Za-z\d])_([A-Za-z\d])/g;
10
+ const embeddedUnderscoreRe = /([A-Za-z\d])(_([A-Za-z\d]))+/g;
11
11
  const asteriskListItemMarkerRe = /^([\s>]*)\*(\s+)/;
12
12
  const leftSpaceRe = /^\s+/;
13
13
  const rightSpaceRe = /\s+$/;
14
14
  const tablePipeRe = /\|/;
15
+ const allUnderscoresRe = /_/g;
15
16
 
16
17
  module.exports = {
17
18
  "names": [ "MD037", "no-space-in-emphasis" ],
@@ -102,7 +103,10 @@ module.exports = {
102
103
  // Emphasis has no meaning here
103
104
  return;
104
105
  }
105
- let patchedLine = line.replace(embeddedUnderscoreRe, "$1 $2");
106
+ let patchedLine = line.replace(
107
+ embeddedUnderscoreRe,
108
+ (match) => match.replace(allUnderscoresRe, " ")
109
+ );
106
110
  if (onItemStart) {
107
111
  // Trim overlapping '*' list item marker
108
112
  patchedLine = patchedLine.replace(asteriskListItemMarkerRe, "$1 $2");
package/lib/md038.js CHANGED
@@ -3,7 +3,7 @@
3
3
  "use strict";
4
4
 
5
5
  const { addErrorContext } = require("../helpers");
6
- const { filterByTypes } = require("../helpers/micromark.cjs");
6
+ const { filterByTypes, tokenIfType } = require("../helpers/micromark.cjs");
7
7
 
8
8
  const leftSpaceRe = /^\s(?:[^`]|$)/;
9
9
  const rightSpaceRe = /[^`]\s$/;
@@ -17,7 +17,6 @@ const trimCodeText = (text, start, end) => {
17
17
  }
18
18
  return text;
19
19
  };
20
- const tokenIfType = (token, type) => token && (token.type === type) && token;
21
20
 
22
21
  module.exports = {
23
22
  "names": [ "MD038", "no-space-in-code" ],
package/lib/md044.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const { addErrorDetailIf, escapeForRegExp, withinAnyRange } =
5
+ const { addErrorDetailIf, escapeForRegExp, newLineRe, withinAnyRange } =
6
6
  require("../helpers");
7
7
  const { filterByPredicate, filterByTypes, parse } =
8
8
  require("../helpers/micromark.cjs");
@@ -30,14 +30,32 @@ module.exports = {
30
30
  scannedTypes.add("codeFlowValue");
31
31
  scannedTypes.add("codeTextData");
32
32
  }
33
+ const tokenAdjustments = new Map();
33
34
  const contentTokens =
34
35
  filterByPredicate(
35
36
  params.parsers.micromark.tokens,
36
37
  (token) => scannedTypes.has(token.type),
37
38
  (token) => {
38
39
  let { children } = token;
40
+ const { startLine, text } = token;
39
41
  if (!includeHtmlElements && (token.type === "htmlFlow")) {
40
- children = children.slice(1, -1);
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
+ }
41
59
  }
42
60
  return children.filter((t) => !ignoredChildTypes.has(t.type));
43
61
  }
@@ -78,10 +96,22 @@ module.exports = {
78
96
  autoLinked.add(token);
79
97
  }
80
98
  if (!withinAnyRange(urlRanges, lineIndex, index, length)) {
81
- const column = index + 1;
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++;
82
112
  addErrorDetailIf(
83
113
  onError,
84
- token.startLine,
114
+ lineNumber,
85
115
  name,
86
116
  nameMatch,
87
117
  null,
@@ -2,54 +2,55 @@
2
2
 
3
3
  "use strict";
4
4
 
5
- const { addError, emphasisOrStrongStyleFor, forEachInlineChild,
6
- getNextChildToken, getRangeAndFixInfoIfFound } = require("../helpers");
5
+ const { addError, emphasisOrStrongStyleFor } = require("../helpers");
6
+ const { filterByTypes, tokenIfType } = require("../helpers/micromark.cjs");
7
7
 
8
- const impl = (params, onError, tagPrefix, asterisk, underline, style) => {
9
- let lastLineNumber = -1;
10
- const instances = new Map();
11
- forEachInlineChild(params, `${tagPrefix}_open`, (token, parent) => {
12
- const { lineNumber, markup } = token;
13
- const markupStyle = emphasisOrStrongStyleFor(markup);
14
- if (style === "consistent") {
15
- style = markupStyle;
16
- }
17
- if (style !== markupStyle) {
18
- let rangeAndFixInfo = {};
19
- const contentToken = getNextChildToken(
20
- parent, token, "text", `${tagPrefix}_close`
21
- );
22
- if (contentToken) {
23
- const { content } = contentToken;
24
- const actual = `${markup}${content}${markup}`;
25
- const expectedMarkup =
26
- (style === "asterisk") ? asterisk : underline;
27
- const expected = `${expectedMarkup}${content}${expectedMarkup}`;
28
- if (lastLineNumber !== lineNumber) {
29
- lastLineNumber = lineNumber;
30
- instances.clear();
8
+ const intrawordRe = /\w/;
9
+
10
+ const impl =
11
+ (params, onError, type, asterisk, underline, style = "consistent") => {
12
+ const { lines, parsers } = params;
13
+ const emphasisTokens =
14
+ filterByTypes(parsers.micromark.tokens, [ type ]);
15
+ for (const token of emphasisTokens) {
16
+ const { children } = token;
17
+ const childType = `${type}Sequence`;
18
+ const startSequence = tokenIfType(children[0], childType);
19
+ const endSequence = tokenIfType(children[children.length - 1], childType);
20
+ if (startSequence && endSequence) {
21
+ const markupStyle = emphasisOrStrongStyleFor(startSequence.text);
22
+ if (style === "consistent") {
23
+ style = markupStyle;
24
+ }
25
+ if (style !== markupStyle) {
26
+ const underscoreIntraword = (style === "underscore") && (
27
+ intrawordRe.test(
28
+ lines[startSequence.startLine - 1][startSequence.startColumn - 2]
29
+ ) ||
30
+ intrawordRe.test(
31
+ lines[endSequence.endLine - 1][endSequence.endColumn - 1]
32
+ )
33
+ );
34
+ if (!underscoreIntraword) {
35
+ for (const sequence of [ startSequence, endSequence ]) {
36
+ addError(
37
+ onError,
38
+ sequence.startLine,
39
+ `Expected: ${style}; Actual: ${markupStyle}`,
40
+ undefined,
41
+ [ sequence.startColumn, sequence.text.length ],
42
+ {
43
+ "editColumn": sequence.startColumn,
44
+ "deleteCount": sequence.text.length,
45
+ "insertText": (style === "asterisk") ? asterisk : underline
46
+ }
47
+ );
48
+ }
49
+ }
31
50
  }
32
- const instance = (instances.get(expected) || 0) + 1;
33
- instances.set(expected, instance);
34
- rangeAndFixInfo = getRangeAndFixInfoIfFound(
35
- params.lines,
36
- lineNumber - 1,
37
- actual,
38
- expected,
39
- instance
40
- );
41
51
  }
42
- addError(
43
- onError,
44
- lineNumber,
45
- `Expected: ${style}; Actual: ${markupStyle}`,
46
- null,
47
- rangeAndFixInfo.range,
48
- rangeAndFixInfo.fixInfo
49
- );
50
52
  }
51
- });
52
- };
53
+ };
53
54
 
54
55
  module.exports = [
55
56
  {
@@ -57,8 +58,14 @@ module.exports = [
57
58
  "description": "Emphasis style should be consistent",
58
59
  "tags": [ "emphasis" ],
59
60
  "function": function MD049(params, onError) {
60
- const style = String(params.config.style || "consistent");
61
- return impl(params, onError, "em", "*", "_", style);
61
+ return impl(
62
+ params,
63
+ onError,
64
+ "emphasis",
65
+ "*",
66
+ "_",
67
+ params.config.style || undefined
68
+ );
62
69
  }
63
70
  },
64
71
  {
@@ -66,8 +73,14 @@ module.exports = [
66
73
  "description": "Strong style should be consistent",
67
74
  "tags": [ "emphasis" ],
68
75
  "function": function MD050(params, onError) {
69
- const style = String(params.config.style || "consistent");
70
- return impl(params, onError, "strong", "**", "__", style);
76
+ return impl(
77
+ params,
78
+ onError,
79
+ "strong",
80
+ "**",
81
+ "__",
82
+ params.config.style || undefined
83
+ );
71
84
  }
72
85
  }
73
86
  ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "markdownlint",
3
- "version": "0.28.2",
3
+ "version": "0.29.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",
@@ -26,14 +26,14 @@
26
26
  "build-config-example": "node schema/build-config-example.js",
27
27
  "build-config-schema": "node schema/build-config-schema.js",
28
28
  "build-declaration": "tsc --allowJs --declaration --emitDeclarationOnly --module commonjs --resolveJsonModule --target es2015 lib/markdownlint.js && node scripts delete 'lib/{c,md,r}*.d.ts' 'micromark/*.d.cts' 'helpers/*.d.{cts,ts}'",
29
- "build-demo": "node scripts copy node_modules/markdown-it/dist/markdown-it.min.js demo/markdown-it.min.js && node scripts copy node_modules/markdownlint-micromark/micromark-browser.js demo/micromark-browser.js && cd demo && webpack --no-stats",
29
+ "build-demo": "node scripts copy node_modules/markdown-it/dist/markdown-it.min.js demo/markdown-it.min.js && node scripts copy node_modules/markdownlint-micromark/micromark-browser.js demo/micromark-browser.js && node scripts copy node_modules/markdownlint-micromark/micromark-html-browser.js demo/micromark-html-browser.js && cd demo && webpack --no-stats",
30
30
  "build-docs": "node doc-build/build-rules.mjs",
31
31
  "build-example": "npm install --no-save --ignore-scripts grunt grunt-cli gulp through2",
32
32
  "build-micromark": "cd micromark && npm run build",
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",
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",
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
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",
@@ -46,8 +46,9 @@
46
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",
47
47
  "declaration": "npm run build-declaration && npm run test-declaration",
48
48
  "example": "cd example && node standalone.js && grunt markdownlint --force && gulp markdownlint",
49
- "docker-npm-install": "docker run --rm --tty --name npm-install --volume $PWD:/home/workdir --workdir /home/workdir --user node node:16 npm install",
50
- "docker-npm-run-upgrade": "docker run --rm --tty --name npm-run-upgrade --volume $PWD:/home/workdir --workdir /home/workdir --user node node:16 npm run upgrade",
49
+ "docker-npm-install": "docker run --rm --tty --name npm-install --volume $PWD:/home/workdir --workdir /home/workdir --user node node:latest npm install",
50
+ "docker-npm-run-upgrade": "docker run --rm --tty --name npm-run-upgrade --volume $PWD:/home/workdir --workdir /home/workdir --user node node:latest npm run upgrade",
51
+ "install-micromark": "cd micromark && npm install --no-package-lock",
51
52
  "lint": "eslint --ext .js,.cjs,.mjs --max-warnings 0 .",
52
53
  "lint-test-repos": "ava --timeout=10m test/markdownlint-test-repos.js",
53
54
  "serial-config-docs": "npm run build-config && npm run build-docs",
@@ -60,24 +61,24 @@
60
61
  "upgrade": "npx --yes npm-check-updates --upgrade"
61
62
  },
62
63
  "engines": {
63
- "node": ">=14.18.0"
64
+ "node": ">=16"
64
65
  },
65
66
  "dependencies": {
66
67
  "markdown-it": "13.0.1",
67
- "markdownlint-micromark": "0.1.2"
68
+ "markdownlint-micromark": "0.1.5"
68
69
  },
69
70
  "devDependencies": {
70
- "ava": "5.2.0",
71
+ "@babel/core": "7.22.1",
72
+ "@babel/preset-env": "7.22.4",
73
+ "ava": "5.3.0",
71
74
  "babel-loader": "9.1.2",
72
- "@babel/core": "7.21.4",
73
- "@babel/preset-env": "7.21.4",
74
- "c8": "7.13.0",
75
- "eslint": "8.39.0",
75
+ "c8": "7.14.0",
76
+ "eslint": "8.41.0",
76
77
  "eslint-plugin-es": "4.1.0",
77
- "eslint-plugin-jsdoc": "43.0.7",
78
- "eslint-plugin-n": "15.7.0",
79
- "eslint-plugin-regexp": "1.14.0",
80
- "eslint-plugin-unicorn": "46.0.0",
78
+ "eslint-plugin-jsdoc": "46.1.0",
79
+ "eslint-plugin-n": "16.0.0",
80
+ "eslint-plugin-regexp": "1.15.0",
81
+ "eslint-plugin-unicorn": "47.0.0",
81
82
  "globby": "13.1.4",
82
83
  "js-yaml": "4.1.0",
83
84
  "markdown-it-for-inline": "0.1.1",
@@ -87,13 +88,13 @@
87
88
  "markdownlint-rule-helpers": "0.19.0",
88
89
  "npm-run-all": "4.1.5",
89
90
  "strip-json-comments": "5.0.0",
90
- "terser-webpack-plugin": "5.3.7",
91
+ "terser-webpack-plugin": "5.3.9",
91
92
  "toml": "3.0.0",
92
93
  "tv4": "1.3.0",
93
- "typescript": "5.0.4",
94
- "webpack": "5.81.0",
95
- "webpack-cli": "5.0.2",
96
- "yaml": "2.2.2"
94
+ "typescript": "5.1.3",
95
+ "webpack": "5.85.0",
96
+ "webpack-cli": "5.1.1",
97
+ "yaml": "2.3.1"
97
98
  },
98
99
  "keywords": [
99
100
  "markdown",