Skip to content

Commit

Permalink
Update MD052/reference-links-images to add a shortcut_syntax paramete…
Browse files Browse the repository at this point in the history
…r for opting into shortcut scanning (fixes DavidAnson#915).
  • Loading branch information
DavidAnson committed Sep 4, 2023
1 parent a736588 commit c118c11
Show file tree
Hide file tree
Showing 13 changed files with 433 additions and 29 deletions.
14 changes: 11 additions & 3 deletions demo/markdownlint-browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -6315,7 +6315,11 @@ function _nonIterableRest() { throw new TypeError("Invalid attempt to destructur
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
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; } } }; }
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
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."); }
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); }
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
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; }
var _require = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js"),
addError = _require.addError;
Expand All @@ -6326,12 +6330,16 @@ module.exports = {
"description": "Reference links and images should use a label that is defined",
"tags": ["images", "links"],
"function": function MD052(params, onError) {
var lines = params.lines;
var config = params.config,
lines = params.lines;
var shortcutSyntax = config.shortcut_syntax || false;
var _referenceLinkImageDa = referenceLinkImageData(),
definitions = _referenceLinkImageDa.definitions,
references = _referenceLinkImageDa.references,
definitions = _referenceLinkImageDa.definitions;
shortcuts = _referenceLinkImageDa.shortcuts;
var entries = shortcutSyntax ? [].concat(_toConsumableArray(references.entries()), _toConsumableArray(shortcuts.entries())) : references.entries();
// Look for links/images that use an undefined link reference
var _iterator = _createForOfIteratorHelper(references.entries()),
var _iterator = _createForOfIteratorHelper(entries),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
Expand Down
15 changes: 9 additions & 6 deletions doc-build/md052.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,13 @@ Shortcut: ![image]
[image]: https://example.com/image
```

A link or image renders correctly when a corresponding label is defined, but
the text displays with brackets if the label is not present. This rule warns
of undefined labels for "full" and "collapsed" reference syntax.
A link or image renders correctly when the corresponding label is defined, but
displays as text with brackets when the label is not present. By default, this
rule warns of undefined labels for "full" and "collapsed" reference syntax but
not for "shortcut" syntax because it is ambiguous.

> "Shortcut" syntax is ambiguous and a missing label will not generate an
error. For example, `[shortcut]` could be a shortcut link or the text
"shortcut" in brackets.
The text `[example]` could be a shortcut link or the text "example" in brackets,
so "shortcut" syntax is ignored by default. To include "shortcut" syntax, set
the `include_shortcut` parameter to `true`. Note that doing so produces warnings
for *all* text in the document that *could* be a shortcut. If bracketed text is
intentional, brackets can be escaped with the `\` character: `\[example\]`.
19 changes: 13 additions & 6 deletions doc/Rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -2216,6 +2216,10 @@ Tags: `images`, `links`

Aliases: `reference-links-images`

Parameters:

- `shortcut_syntax`: Include shortcut syntax (`boolean`, default `false`)

Links and images in Markdown can provide the link destination or image source
at the time of use or can define it elsewhere and use a label for reference.
The reference format is convenient for keeping paragraph text clutter-free
Expand All @@ -2236,13 +2240,16 @@ Shortcut: ![image]
[image]: https://example.com/image
```

A link or image renders correctly when a corresponding label is defined, but
the text displays with brackets if the label is not present. This rule warns
of undefined labels for "full" and "collapsed" reference syntax.
A link or image renders correctly when the corresponding label is defined, but
displays as text with brackets when the label is not present. By default, this
rule warns of undefined labels for "full" and "collapsed" reference syntax but
not for "shortcut" syntax because it is ambiguous.

> "Shortcut" syntax is ambiguous and a missing label will not generate an
error. For example, `[shortcut]` could be a shortcut link or the text
"shortcut" in brackets.
The text `[example]` could be a shortcut link or the text "example" in brackets,
so "shortcut" syntax is ignored by default. To include "shortcut" syntax, set
the `include_shortcut` parameter to `true`. Note that doing so produces warnings
for *all* text in the document that *could* be a shortcut. If bracketed text is
intentional, brackets can be escaped with the `\` character: `\[example\]`.

<a name="md053"></a>

Expand Down
19 changes: 13 additions & 6 deletions doc/md052.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ Tags: `images`, `links`

Aliases: `reference-links-images`

Parameters:

- `shortcut_syntax`: Include shortcut syntax (`boolean`, default `false`)

Links and images in Markdown can provide the link destination or image source
at the time of use or can define it elsewhere and use a label for reference.
The reference format is convenient for keeping paragraph text clutter-free
Expand All @@ -24,10 +28,13 @@ Shortcut: ![image]
[image]: https://example.com/image
```

A link or image renders correctly when a corresponding label is defined, but
the text displays with brackets if the label is not present. This rule warns
of undefined labels for "full" and "collapsed" reference syntax.
A link or image renders correctly when the corresponding label is defined, but
displays as text with brackets when the label is not present. By default, this
rule warns of undefined labels for "full" and "collapsed" reference syntax but
not for "shortcut" syntax because it is ambiguous.

> "Shortcut" syntax is ambiguous and a missing label will not generate an
error. For example, `[shortcut]` could be a shortcut link or the text
"shortcut" in brackets.
The text `[example]` could be a shortcut link or the text "example" in brackets,
so "shortcut" syntax is ignored by default. To include "shortcut" syntax, set
the `include_shortcut` parameter to `true`. Note that doing so produces warnings
for *all* text in the document that *could* be a shortcut. If bracketed text is
intentional, brackets can be escaped with the `\` character: `\[example\]`.
10 changes: 7 additions & 3 deletions lib/md052.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,14 @@ module.exports = {
"Reference links and images should use a label that is defined",
"tags": [ "images", "links" ],
"function": function MD052(params, onError) {
const { lines } = params;
const { references, definitions } = referenceLinkImageData();
const { config, lines } = params;
const shortcutSyntax = config.shortcut_syntax || false;
const { definitions, references, shortcuts } = referenceLinkImageData();
const entries = shortcutSyntax ?
[ ...references.entries(), ...shortcuts.entries() ] :
references.entries();
// Look for links/images that use an undefined link reference
for (const reference of references.entries()) {
for (const reference of entries) {
const [ label, datas ] = reference;
if (!definitions.has(label)) {
for (const data of datas) {
Expand Down
5 changes: 4 additions & 1 deletion schema/.markdownlint.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,10 @@
"MD051": true,

// MD052/reference-links-images - Reference links and images should use a label that is defined
"MD052": true,
"MD052": {
// Include shortcut syntax
"shortcut_syntax": false
},

// MD053/link-image-reference-definitions - Link and image reference definitions should be needed
"MD053": {
Expand Down
4 changes: 3 additions & 1 deletion schema/.markdownlint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,9 @@ MD050:
MD051: true

# MD052/reference-links-images - Reference links and images should use a label that is defined
MD052: true
MD052:
# Include shortcut syntax
shortcut_syntax: false

# MD053/link-image-reference-definitions - Link and image reference definitions should be needed
MD053:
Expand Down
9 changes: 9 additions & 0 deletions schema/build-config-schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,15 @@ for (const rule of rules) {
}
};
break;
case "MD052":
scheme.properties = {
"shortcut_syntax": {
"description": "Include shortcut syntax",
"type": "boolean",
"default": false
}
};
break;
case "MD053":
scheme.properties = {
"ignored_definitions": {
Expand Down
15 changes: 13 additions & 2 deletions schema/markdownlint-config-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -937,8 +937,19 @@
},
"MD052": {
"description": "MD052/reference-links-images - Reference links and images should use a label that is defined",
"type": "boolean",
"default": true
"type": [
"boolean",
"object"
],
"default": true,
"properties": {
"shortcut_syntax": {
"description": "Include shortcut syntax",
"type": "boolean",
"default": false
}
},
"additionalProperties": false
},
"reference-links-images": {
"$ref": "#/properties/MD052"
Expand Down
2 changes: 1 addition & 1 deletion test/markdownlint-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -912,7 +912,7 @@ test("readme", async(t) => {
});

test("validateJsonUsingConfigSchemaStrict", (t) => {
t.plan(160);
t.plan(161);
const configRe =
/^[\s\S]*<!-- markdownlint-configure-file ([\s\S]*) -->[\s\S]*$/;
const ignoreFiles = new Set([
Expand Down
112 changes: 112 additions & 0 deletions test/reference-links-and-images-shortcuts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# Reference Links and Images (Shortcuts)

## Shortcut Handling

Validates the shortcut: [shortcut]

[shortcut]: https://example.com/shortcut

Missing reference: [missing] {MD052}

## Valid Links

Full reference link: [text][label]

Collapsed reference link: [label][]

Shortcut reference link: [label]

Same line: [text][label] [label][] [label]

Mixed case: [TEXT][LABEL] [LABEL][] [LABEL]

With nested brackets: [t\[ex\]t][label]

Shortcut inline code span: [`code`]

Shortcut ending in colon: [colon]:

## Invalid Links

Missing: [missing] {MD052}

> Missing in blockquote: [missing] {MD052}
## Non-Links

Code span: `[code]`

Escaped left: \[escaped]

Escaped right: [escaped\]

Escaped both: \[escaped\]

Unmatched [ in text

Unmatched ] in text

## Valid Images

Full style: ![text][image0]

Collapsed style: ![image1][]

Shortcut style: ![image2]

Image in link: [![text][image3]](link) [![image4][]](link) [![image5]](link)

Image in shortcut link: [![text][image6]][unique6] [![image7][]][unique7] [![image8]][unique8]

Wrapped in brackets: \[![text][unique9]\]

Embedded \[in ![text][unique10] brackets\]

## Invalid Images

Missing: ![missing] {MD052}

> Missing in blockquote: ![missing] {MD052}
## Non-Images

Escaped left: !\[escaped]

Escaped right: ![escaped\]

Escaped both: !\[escaped\]

## Valid Footnotes

Footnote[^1]

## Invalid Footnotes

Missing[^2] {MD052}

## Valid Labels

[label]: https://example.com/label
[image0]: https://example.com/image0
[image1]: https://example.com/image1
[image2]: https://example.com/image2
[image3]: https://example.com/image3
[image4]: https://example.com/image4
[image5]: https://example.com/image5
[image6]: https://example.com/image6
[image7]: https://example.com/image7
[image8]: https://example.com/image8
[`code`]: https://example.com/code
[colon]: https://example.com/colon
[unique6]: https://example.com/unique6
[unique7]: https://example.com/unique7
[unique8]: https://example.com/unique8
[unique9]: https://example.com/unique9
[unique10]: https://example.com/unique10
[^1]: https://example.com/footnote {MD034}

<!-- markdownlint-configure-file {
"reference-links-images": {
"shortcut_syntax": true
}
} -->
Loading

0 comments on commit c118c11

Please sign in to comment.