Skip to content

Commit c118c11

Browse files
committed
Update MD052/reference-links-images to add a shortcut_syntax parameter for opting into shortcut scanning (fixes #915).
1 parent a736588 commit c118c11

13 files changed

+433
-29
lines changed

demo/markdownlint-browser.js

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6315,7 +6315,11 @@ function _nonIterableRest() { throw new TypeError("Invalid attempt to destructur
63156315
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; } }
63166316
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
63176317
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; } } }; }
6318+
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
6319+
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."); }
63186320
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); }
6321+
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
6322+
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
63196323
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; }
63206324
var _require = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js"),
63216325
addError = _require.addError;
@@ -6326,12 +6330,16 @@ module.exports = {
63266330
"description": "Reference links and images should use a label that is defined",
63276331
"tags": ["images", "links"],
63286332
"function": function MD052(params, onError) {
6329-
var lines = params.lines;
6333+
var config = params.config,
6334+
lines = params.lines;
6335+
var shortcutSyntax = config.shortcut_syntax || false;
63306336
var _referenceLinkImageDa = referenceLinkImageData(),
6337+
definitions = _referenceLinkImageDa.definitions,
63316338
references = _referenceLinkImageDa.references,
6332-
definitions = _referenceLinkImageDa.definitions;
6339+
shortcuts = _referenceLinkImageDa.shortcuts;
6340+
var entries = shortcutSyntax ? [].concat(_toConsumableArray(references.entries()), _toConsumableArray(shortcuts.entries())) : references.entries();
63336341
// Look for links/images that use an undefined link reference
6334-
var _iterator = _createForOfIteratorHelper(references.entries()),
6342+
var _iterator = _createForOfIteratorHelper(entries),
63356343
_step;
63366344
try {
63376345
for (_iterator.s(); !(_step = _iterator.n()).done;) {

doc-build/md052.md

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,13 @@ Shortcut: ![image]
1818
[image]: https://example.com/image
1919
```
2020

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

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

doc/Rules.md

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2216,6 +2216,10 @@ Tags: `images`, `links`
22162216

22172217
Aliases: `reference-links-images`
22182218

2219+
Parameters:
2220+
2221+
- `shortcut_syntax`: Include shortcut syntax (`boolean`, default `false`)
2222+
22192223
Links and images in Markdown can provide the link destination or image source
22202224
at the time of use or can define it elsewhere and use a label for reference.
22212225
The reference format is convenient for keeping paragraph text clutter-free
@@ -2236,13 +2240,16 @@ Shortcut: ![image]
22362240
[image]: https://example.com/image
22372241
```
22382242

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

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

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

doc/md052.md

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ Tags: `images`, `links`
44

55
Aliases: `reference-links-images`
66

7+
Parameters:
8+
9+
- `shortcut_syntax`: Include shortcut syntax (`boolean`, default `false`)
10+
711
Links and images in Markdown can provide the link destination or image source
812
at the time of use or can define it elsewhere and use a label for reference.
913
The reference format is convenient for keeping paragraph text clutter-free
@@ -24,10 +28,13 @@ Shortcut: ![image]
2428
[image]: https://example.com/image
2529
```
2630

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

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

lib/md052.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,14 @@ module.exports = {
1111
"Reference links and images should use a label that is defined",
1212
"tags": [ "images", "links" ],
1313
"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();
1620
// Look for links/images that use an undefined link reference
17-
for (const reference of references.entries()) {
21+
for (const reference of entries) {
1822
const [ label, datas ] = reference;
1923
if (!definitions.has(label)) {
2024
for (const data of datas) {

schema/.markdownlint.jsonc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,10 @@
279279
"MD051": true,
280280

281281
// 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+
},
283286

284287
// MD053/link-image-reference-definitions - Link and image reference definitions should be needed
285288
"MD053": {

schema/.markdownlint.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,9 @@ MD050:
252252
MD051: true
253253

254254
# MD052/reference-links-images - Reference links and images should use a label that is defined
255-
MD052: true
255+
MD052:
256+
# Include shortcut syntax
257+
shortcut_syntax: false
256258

257259
# MD053/link-image-reference-definitions - Link and image reference definitions should be needed
258260
MD053:

schema/build-config-schema.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,15 @@ for (const rule of rules) {
497497
}
498498
};
499499
break;
500+
case "MD052":
501+
scheme.properties = {
502+
"shortcut_syntax": {
503+
"description": "Include shortcut syntax",
504+
"type": "boolean",
505+
"default": false
506+
}
507+
};
508+
break;
500509
case "MD053":
501510
scheme.properties = {
502511
"ignored_definitions": {

schema/markdownlint-config-schema.json

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -937,8 +937,19 @@
937937
},
938938
"MD052": {
939939
"description": "MD052/reference-links-images - Reference links and images should use a label that is defined",
940-
"type": "boolean",
941-
"default": true
940+
"type": [
941+
"boolean",
942+
"object"
943+
],
944+
"default": true,
945+
"properties": {
946+
"shortcut_syntax": {
947+
"description": "Include shortcut syntax",
948+
"type": "boolean",
949+
"default": false
950+
}
951+
},
952+
"additionalProperties": false
942953
},
943954
"reference-links-images": {
944955
"$ref": "#/properties/MD052"

test/markdownlint-test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -912,7 +912,7 @@ test("readme", async(t) => {
912912
});
913913

914914
test("validateJsonUsingConfigSchemaStrict", (t) => {
915-
t.plan(160);
915+
t.plan(161);
916916
const configRe =
917917
/^[\s\S]*<!-- markdownlint-configure-file ([\s\S]*) -->[\s\S]*$/;
918918
const ignoreFiles = new Set([
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
# Reference Links and Images (Shortcuts)
2+
3+
## Shortcut Handling
4+
5+
Validates the shortcut: [shortcut]
6+
7+
[shortcut]: https://example.com/shortcut
8+
9+
Missing reference: [missing] {MD052}
10+
11+
## Valid Links
12+
13+
Full reference link: [text][label]
14+
15+
Collapsed reference link: [label][]
16+
17+
Shortcut reference link: [label]
18+
19+
Same line: [text][label] [label][] [label]
20+
21+
Mixed case: [TEXT][LABEL] [LABEL][] [LABEL]
22+
23+
With nested brackets: [t\[ex\]t][label]
24+
25+
Shortcut inline code span: [`code`]
26+
27+
Shortcut ending in colon: [colon]:
28+
29+
## Invalid Links
30+
31+
Missing: [missing] {MD052}
32+
33+
> Missing in blockquote: [missing] {MD052}
34+
35+
## Non-Links
36+
37+
Code span: `[code]`
38+
39+
Escaped left: \[escaped]
40+
41+
Escaped right: [escaped\]
42+
43+
Escaped both: \[escaped\]
44+
45+
Unmatched [ in text
46+
47+
Unmatched ] in text
48+
49+
## Valid Images
50+
51+
Full style: ![text][image0]
52+
53+
Collapsed style: ![image1][]
54+
55+
Shortcut style: ![image2]
56+
57+
Image in link: [![text][image3]](link) [![image4][]](link) [![image5]](link)
58+
59+
Image in shortcut link: [![text][image6]][unique6] [![image7][]][unique7] [![image8]][unique8]
60+
61+
Wrapped in brackets: \[![text][unique9]\]
62+
63+
Embedded \[in ![text][unique10] brackets\]
64+
65+
## Invalid Images
66+
67+
Missing: ![missing] {MD052}
68+
69+
> Missing in blockquote: ![missing] {MD052}
70+
71+
## Non-Images
72+
73+
Escaped left: !\[escaped]
74+
75+
Escaped right: ![escaped\]
76+
77+
Escaped both: !\[escaped\]
78+
79+
## Valid Footnotes
80+
81+
Footnote[^1]
82+
83+
## Invalid Footnotes
84+
85+
Missing[^2] {MD052}
86+
87+
## Valid Labels
88+
89+
[label]: https://example.com/label
90+
[image0]: https://example.com/image0
91+
[image1]: https://example.com/image1
92+
[image2]: https://example.com/image2
93+
[image3]: https://example.com/image3
94+
[image4]: https://example.com/image4
95+
[image5]: https://example.com/image5
96+
[image6]: https://example.com/image6
97+
[image7]: https://example.com/image7
98+
[image8]: https://example.com/image8
99+
[`code`]: https://example.com/code
100+
[colon]: https://example.com/colon
101+
[unique6]: https://example.com/unique6
102+
[unique7]: https://example.com/unique7
103+
[unique8]: https://example.com/unique8
104+
[unique9]: https://example.com/unique9
105+
[unique10]: https://example.com/unique10
106+
[^1]: https://example.com/footnote {MD034}
107+
108+
<!-- markdownlint-configure-file {
109+
"reference-links-images": {
110+
"shortcut_syntax": true
111+
}
112+
} -->

0 commit comments

Comments
 (0)