eslint-plugin-markdown-preferences 0.22.0 → 0.23.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/README.md +2 -0
- package/lib/index.d.ts +18 -1
- package/lib/index.js +348 -68
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -130,6 +130,8 @@ The rules with the following 💄 are included in the `standard` config.
|
|
|
130
130
|
| [markdown-preferences/link-bracket-newline](https://ota-meshi.github.io/eslint-plugin-markdown-preferences/rules/link-bracket-newline.html) | enforce linebreaks after opening and before closing link brackets | 🔧 | 💄 |
|
|
131
131
|
| [markdown-preferences/link-bracket-spacing](https://ota-meshi.github.io/eslint-plugin-markdown-preferences/rules/link-bracket-spacing.html) | enforce consistent spacing inside link brackets | 🔧 | 💄 |
|
|
132
132
|
| [markdown-preferences/link-destination-style](https://ota-meshi.github.io/eslint-plugin-markdown-preferences/rules/link-destination-style.html) | enforce a consistent style for link destinations | 🔧 | 💄 |
|
|
133
|
+
| [markdown-preferences/link-paren-newline](https://ota-meshi.github.io/eslint-plugin-markdown-preferences/rules/link-paren-newline.html) | enforce linebreaks after opening and before closing link parentheses | 🔧 | 💄 |
|
|
134
|
+
| [markdown-preferences/link-paren-spacing](https://ota-meshi.github.io/eslint-plugin-markdown-preferences/rules/link-paren-spacing.html) | enforce consistent spacing inside link parentheses | 🔧 | 💄 |
|
|
133
135
|
| [markdown-preferences/link-title-style](https://ota-meshi.github.io/eslint-plugin-markdown-preferences/rules/link-title-style.html) | enforce a consistent style for link titles | 🔧 | 💄 |
|
|
134
136
|
| [markdown-preferences/list-marker-alignment](https://ota-meshi.github.io/eslint-plugin-markdown-preferences/rules/list-marker-alignment.html) | enforce consistent alignment of list markers | 🔧 | ⭐💄 |
|
|
135
137
|
| [markdown-preferences/no-laziness-blockquotes](https://ota-meshi.github.io/eslint-plugin-markdown-preferences/rules/no-laziness-blockquotes.html) | disallow laziness in blockquotes | | ⭐💄 |
|
package/lib/index.d.ts
CHANGED
|
@@ -95,6 +95,16 @@ interface RuleOptions {
|
|
|
95
95
|
* @see https://ota-meshi.github.io/eslint-plugin-markdown-preferences/rules/link-destination-style.html
|
|
96
96
|
*/
|
|
97
97
|
'markdown-preferences/link-destination-style'?: Linter.RuleEntry<MarkdownPreferencesLinkDestinationStyle>;
|
|
98
|
+
/**
|
|
99
|
+
* enforce linebreaks after opening and before closing link parentheses
|
|
100
|
+
* @see https://ota-meshi.github.io/eslint-plugin-markdown-preferences/rules/link-paren-newline.html
|
|
101
|
+
*/
|
|
102
|
+
'markdown-preferences/link-paren-newline'?: Linter.RuleEntry<MarkdownPreferencesLinkParenNewline>;
|
|
103
|
+
/**
|
|
104
|
+
* enforce consistent spacing inside link parentheses
|
|
105
|
+
* @see https://ota-meshi.github.io/eslint-plugin-markdown-preferences/rules/link-paren-spacing.html
|
|
106
|
+
*/
|
|
107
|
+
'markdown-preferences/link-paren-spacing'?: Linter.RuleEntry<MarkdownPreferencesLinkParenSpacing>;
|
|
98
108
|
/**
|
|
99
109
|
* enforce a consistent style for link titles
|
|
100
110
|
* @see https://ota-meshi.github.io/eslint-plugin-markdown-preferences/rules/link-title-style.html
|
|
@@ -297,6 +307,13 @@ type MarkdownPreferencesLinkDestinationStyle = [] | [{
|
|
|
297
307
|
avoidEscape?: boolean;
|
|
298
308
|
[k: string]: unknown | undefined;
|
|
299
309
|
}];
|
|
310
|
+
type MarkdownPreferencesLinkParenNewline = [] | [{
|
|
311
|
+
newline?: ("always" | "never" | "consistent");
|
|
312
|
+
multiline?: boolean;
|
|
313
|
+
}];
|
|
314
|
+
type MarkdownPreferencesLinkParenSpacing = [] | [{
|
|
315
|
+
space?: ("always" | "never");
|
|
316
|
+
}];
|
|
300
317
|
type MarkdownPreferencesLinkTitleStyle = [] | [{
|
|
301
318
|
style?: ("double" | "single" | "parentheses");
|
|
302
319
|
avoidEscape?: boolean;
|
|
@@ -425,7 +442,7 @@ declare namespace meta_d_exports {
|
|
|
425
442
|
export { name, version };
|
|
426
443
|
}
|
|
427
444
|
declare const name: "eslint-plugin-markdown-preferences";
|
|
428
|
-
declare const version: "0.
|
|
445
|
+
declare const version: "0.23.0";
|
|
429
446
|
//#endregion
|
|
430
447
|
//#region src/index.d.ts
|
|
431
448
|
declare const configs: {
|
package/lib/index.js
CHANGED
|
@@ -186,47 +186,48 @@ function parseATXHeading(sourceCode, node) {
|
|
|
186
186
|
}
|
|
187
187
|
}
|
|
188
188
|
};
|
|
189
|
-
const
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
loc: {
|
|
193
|
-
start: openingSequence.loc.end,
|
|
194
|
-
end: {
|
|
195
|
-
line: openingSequence.loc.end.line,
|
|
196
|
-
column: openingSequence.loc.end.column + parsedOpening.rawAfter.length
|
|
197
|
-
}
|
|
198
|
-
}
|
|
189
|
+
const contentLocStart = {
|
|
190
|
+
line: openingSequence.loc.end.line,
|
|
191
|
+
column: openingSequence.loc.end.column + parsedOpening.after.length
|
|
199
192
|
};
|
|
200
193
|
const parsedClosing = parseATXHeadingClosingSequenceFromText(text);
|
|
201
194
|
if (parsedClosing == null) {
|
|
202
|
-
const textAfterOpening = sourceCode.text.slice(
|
|
195
|
+
const textAfterOpening = sourceCode.text.slice(openingSequence.range[1] + parsedOpening.after.length, range[1]);
|
|
203
196
|
const contentText$1 = textAfterOpening.trimEnd();
|
|
197
|
+
const contentRange$1 = [openingSequence.range[1] + parsedOpening.after.length, openingSequence.range[1] + parsedOpening.after.length + contentText$1.length];
|
|
198
|
+
const contentLocEnd = {
|
|
199
|
+
line: loc.end.line,
|
|
200
|
+
column: loc.end.column - (textAfterOpening.length - contentText$1.length)
|
|
201
|
+
};
|
|
202
|
+
const after = contentText$1 === textAfterOpening ? null : {
|
|
203
|
+
text: textAfterOpening.slice(contentText$1.length),
|
|
204
|
+
range: [contentRange$1[1], range[1]],
|
|
205
|
+
loc: {
|
|
206
|
+
start: contentLocEnd,
|
|
207
|
+
end: loc.end
|
|
208
|
+
}
|
|
209
|
+
};
|
|
204
210
|
return {
|
|
205
|
-
openingSequence
|
|
206
|
-
...openingSequence,
|
|
207
|
-
raws: { spaceAfter: spaceAfterOpening }
|
|
208
|
-
},
|
|
211
|
+
openingSequence,
|
|
209
212
|
content: {
|
|
210
213
|
text: contentText$1,
|
|
211
|
-
range:
|
|
214
|
+
range: contentRange$1,
|
|
212
215
|
loc: {
|
|
213
|
-
start:
|
|
214
|
-
end:
|
|
215
|
-
line: loc.end.line,
|
|
216
|
-
column: loc.end.column - (textAfterOpening.length - contentText$1.length)
|
|
217
|
-
}
|
|
216
|
+
start: contentLocStart,
|
|
217
|
+
end: contentLocEnd
|
|
218
218
|
}
|
|
219
219
|
},
|
|
220
|
-
closingSequence: null
|
|
220
|
+
closingSequence: null,
|
|
221
|
+
after
|
|
221
222
|
};
|
|
222
223
|
}
|
|
223
224
|
const spaceAfterClosing = {
|
|
224
|
-
text: parsedClosing.
|
|
225
|
-
range: [range[1] - parsedClosing.
|
|
225
|
+
text: parsedClosing.after,
|
|
226
|
+
range: [range[1] - parsedClosing.after.length, range[1]],
|
|
226
227
|
loc: {
|
|
227
228
|
start: {
|
|
228
229
|
line: loc.end.line,
|
|
229
|
-
column: loc.end.column - parsedClosing.
|
|
230
|
+
column: loc.end.column - parsedClosing.after.length
|
|
230
231
|
},
|
|
231
232
|
end: loc.end
|
|
232
233
|
}
|
|
@@ -242,38 +243,23 @@ function parseATXHeading(sourceCode, node) {
|
|
|
242
243
|
end: spaceAfterClosing.loc.start
|
|
243
244
|
}
|
|
244
245
|
};
|
|
245
|
-
const
|
|
246
|
-
|
|
247
|
-
range: [closingSequence.range[0] - parsedClosing.rawBefore.length, closingSequence.range[0]],
|
|
248
|
-
loc: {
|
|
249
|
-
start: {
|
|
250
|
-
line: closingSequence.loc.start.line,
|
|
251
|
-
column: closingSequence.loc.start.column - parsedClosing.rawBefore.length
|
|
252
|
-
},
|
|
253
|
-
end: closingSequence.loc.start
|
|
254
|
-
}
|
|
255
|
-
};
|
|
256
|
-
const contentText = sourceCode.text.slice(spaceAfterOpening.range[1], spaceBeforeClosing.range[0]);
|
|
246
|
+
const contentRange = [openingSequence.range[1] + parsedOpening.after.length, closingSequence.range[0] - parsedClosing.before.length];
|
|
247
|
+
const contentText = sourceCode.text.slice(...contentRange);
|
|
257
248
|
return {
|
|
258
|
-
openingSequence
|
|
259
|
-
...openingSequence,
|
|
260
|
-
raws: { spaceAfter: spaceAfterOpening }
|
|
261
|
-
},
|
|
249
|
+
openingSequence,
|
|
262
250
|
content: {
|
|
263
251
|
text: contentText,
|
|
264
|
-
range:
|
|
252
|
+
range: contentRange,
|
|
265
253
|
loc: {
|
|
266
|
-
start:
|
|
267
|
-
end:
|
|
254
|
+
start: contentLocStart,
|
|
255
|
+
end: {
|
|
256
|
+
line: closingSequence.loc.start.line,
|
|
257
|
+
column: closingSequence.loc.start.column - parsedClosing.before.length
|
|
258
|
+
}
|
|
268
259
|
}
|
|
269
260
|
},
|
|
270
|
-
closingSequence
|
|
271
|
-
|
|
272
|
-
raws: {
|
|
273
|
-
spaceBefore: spaceBeforeClosing,
|
|
274
|
-
spaceAfter: spaceAfterClosing
|
|
275
|
-
}
|
|
276
|
-
}
|
|
261
|
+
closingSequence,
|
|
262
|
+
after: spaceAfterClosing.range[0] < spaceAfterClosing.range[1] ? spaceAfterClosing : null
|
|
277
263
|
};
|
|
278
264
|
}
|
|
279
265
|
/**
|
|
@@ -287,7 +273,7 @@ function parseATXHeadingOpeningSequenceFromText(text) {
|
|
|
287
273
|
if (afterOffset === openingSequenceAfterOffset || afterOffset >= text.length) return null;
|
|
288
274
|
return {
|
|
289
275
|
openingSequence: text.slice(0, openingSequenceAfterOffset),
|
|
290
|
-
|
|
276
|
+
after: text.slice(openingSequenceAfterOffset, afterOffset)
|
|
291
277
|
};
|
|
292
278
|
/**
|
|
293
279
|
* Skip whitespace characters at the start of the text.
|
|
@@ -310,9 +296,9 @@ function parseATXHeadingClosingSequenceFromText(text) {
|
|
|
310
296
|
const beforeOffset = skipEndWhitespace(closingSequenceBeforeOffset);
|
|
311
297
|
if (beforeOffset === closingSequenceBeforeOffset || beforeOffset < 0) return null;
|
|
312
298
|
return {
|
|
313
|
-
|
|
299
|
+
before: text.slice(beforeOffset + 1, closingSequenceBeforeOffset + 1),
|
|
314
300
|
closingSequence: text.slice(closingSequenceBeforeOffset + 1, trimmedEndOffset),
|
|
315
|
-
|
|
301
|
+
after: text.slice(trimmedEndOffset)
|
|
316
302
|
};
|
|
317
303
|
/**
|
|
318
304
|
* Skip whitespace characters at the end of the text.
|
|
@@ -577,16 +563,16 @@ var atx_heading_closing_sequence_default = createRule("atx-heading-closing-seque
|
|
|
577
563
|
context.report({
|
|
578
564
|
node,
|
|
579
565
|
loc: {
|
|
580
|
-
start: parsed.
|
|
566
|
+
start: parsed.content.loc.end,
|
|
581
567
|
end: parsed.closingSequence.loc.end
|
|
582
568
|
},
|
|
583
569
|
messageId: "forbidClosing",
|
|
584
570
|
*fix(fixer) {
|
|
585
|
-
const removeRange = [parsed.
|
|
571
|
+
const removeRange = [parsed.content.range[1], parsed.closingSequence.range[1]];
|
|
586
572
|
const newHeadingText = sourceCode.text.slice(sourceCode.getRange(node)[0], removeRange[0]);
|
|
587
573
|
const newHeadingParsed = parseATXHeadingClosingSequenceFromText(newHeadingText);
|
|
588
574
|
if (newHeadingParsed) {
|
|
589
|
-
const escapeIndex = removeRange[0] - newHeadingParsed.
|
|
575
|
+
const escapeIndex = removeRange[0] - newHeadingParsed.after.length - 1;
|
|
590
576
|
yield fixer.insertTextBeforeRange([escapeIndex, escapeIndex], "\\");
|
|
591
577
|
}
|
|
592
578
|
yield fixer.removeRange(removeRange);
|
|
@@ -4527,8 +4513,8 @@ var level1_heading_style_default = createRule("level1-heading-style", {
|
|
|
4527
4513
|
*fix(fixer) {
|
|
4528
4514
|
const parsed = parseATXHeading(sourceCode, node);
|
|
4529
4515
|
if (!parsed) return;
|
|
4530
|
-
yield fixer.removeRange([parsed.openingSequence.range[0], parsed.
|
|
4531
|
-
if (parsed.closingSequence) yield fixer.removeRange([parsed.
|
|
4516
|
+
yield fixer.removeRange([parsed.openingSequence.range[0], parsed.content.range[0]]);
|
|
4517
|
+
if (parsed.closingSequence) yield fixer.removeRange([parsed.content.range[1], parsed.after?.range[1] ?? parsed.closingSequence.range[1]]);
|
|
4532
4518
|
const lines = getParsedLines(sourceCode);
|
|
4533
4519
|
const underline = "=".repeat(Math.max(getTextWidth(parsed.content.text), 3));
|
|
4534
4520
|
const appendingText = `\n${lines.get(parsed.openingSequence.loc.start.line).text.slice(0, parsed.openingSequence.loc.start.column - 1)}${underline}`;
|
|
@@ -4604,8 +4590,8 @@ var level2_heading_style_default = createRule("level2-heading-style", {
|
|
|
4604
4590
|
*fix(fixer) {
|
|
4605
4591
|
const parsed = parseATXHeading(sourceCode, node);
|
|
4606
4592
|
if (!parsed) return;
|
|
4607
|
-
yield fixer.removeRange([parsed.openingSequence.range[0], parsed.
|
|
4608
|
-
if (parsed.closingSequence) yield fixer.removeRange([parsed.
|
|
4593
|
+
yield fixer.removeRange([parsed.openingSequence.range[0], parsed.content.range[0]]);
|
|
4594
|
+
if (parsed.closingSequence) yield fixer.removeRange([parsed.content.range[1], parsed.after?.range[1] ?? parsed.closingSequence.range[1]]);
|
|
4609
4595
|
const lines = getParsedLines(sourceCode);
|
|
4610
4596
|
const underline = "-".repeat(Math.max(getTextWidth(parsed.content.text), 3));
|
|
4611
4597
|
const appendingText = `\n${lines.get(parsed.openingSequence.loc.start.line).text.slice(0, parsed.openingSequence.loc.start.column - 1)}${underline}`;
|
|
@@ -4633,12 +4619,18 @@ function parseInlineLink(sourceCode, node) {
|
|
|
4633
4619
|
}
|
|
4634
4620
|
const parsed = parseInlineLinkDestAndTitleFromText(sourceCode.text.slice(textRange[1], nodeRange[1]));
|
|
4635
4621
|
if (!parsed) return null;
|
|
4622
|
+
const openingParenRange = [textRange[1] + parsed.openingParen.range[0], textRange[1] + parsed.openingParen.range[1]];
|
|
4636
4623
|
const destinationRange = [textRange[1] + parsed.destination.range[0], textRange[1] + parsed.destination.range[1]];
|
|
4624
|
+
const closingParenRange = [textRange[1] + parsed.closingParen.range[0], textRange[1] + parsed.closingParen.range[1]];
|
|
4637
4625
|
return {
|
|
4638
4626
|
text: {
|
|
4639
4627
|
range: textRange,
|
|
4640
4628
|
loc: getSourceLocationFromRange(sourceCode, node, textRange)
|
|
4641
4629
|
},
|
|
4630
|
+
openingParen: {
|
|
4631
|
+
range: openingParenRange,
|
|
4632
|
+
loc: getSourceLocationFromRange(sourceCode, node, openingParenRange)
|
|
4633
|
+
},
|
|
4642
4634
|
destination: {
|
|
4643
4635
|
type: parsed.destination.type,
|
|
4644
4636
|
text: parsed.destination.text,
|
|
@@ -4650,7 +4642,11 @@ function parseInlineLink(sourceCode, node) {
|
|
|
4650
4642
|
text: parsed.title.text,
|
|
4651
4643
|
range: [textRange[1] + parsed.title.range[0], textRange[1] + parsed.title.range[1]],
|
|
4652
4644
|
loc: getSourceLocationFromRange(sourceCode, node, [textRange[1] + parsed.title.range[0], textRange[1] + parsed.title.range[1]])
|
|
4653
|
-
} : null
|
|
4645
|
+
} : null,
|
|
4646
|
+
closingParen: {
|
|
4647
|
+
range: closingParenRange,
|
|
4648
|
+
loc: getSourceLocationFromRange(sourceCode, node, closingParenRange)
|
|
4649
|
+
}
|
|
4654
4650
|
};
|
|
4655
4651
|
}
|
|
4656
4652
|
/**
|
|
@@ -4685,12 +4681,15 @@ function parseInlineLinkDestAndTitleFromText(text) {
|
|
|
4685
4681
|
}
|
|
4686
4682
|
skipSpaces();
|
|
4687
4683
|
if (text[index] === ")") {
|
|
4684
|
+
const closingParenStartIndex$1 = index;
|
|
4688
4685
|
index++;
|
|
4689
4686
|
skipSpaces();
|
|
4690
4687
|
if (index < text.length) return null;
|
|
4691
4688
|
return {
|
|
4689
|
+
openingParen: { range: [0, 1] },
|
|
4692
4690
|
destination,
|
|
4693
|
-
title: null
|
|
4691
|
+
title: null,
|
|
4692
|
+
closingParen: { range: [closingParenStartIndex$1, index] }
|
|
4694
4693
|
};
|
|
4695
4694
|
}
|
|
4696
4695
|
if (text.length <= index) return null;
|
|
@@ -4711,12 +4710,15 @@ function parseInlineLinkDestAndTitleFromText(text) {
|
|
|
4711
4710
|
} else return null;
|
|
4712
4711
|
skipSpaces();
|
|
4713
4712
|
if (text[index] !== ")") return null;
|
|
4713
|
+
const closingParenStartIndex = index;
|
|
4714
4714
|
index++;
|
|
4715
4715
|
skipSpaces();
|
|
4716
4716
|
if (index < text.length) return null;
|
|
4717
4717
|
return {
|
|
4718
|
+
openingParen: { range: [0, 1] },
|
|
4718
4719
|
destination,
|
|
4719
|
-
title
|
|
4720
|
+
title,
|
|
4721
|
+
closingParen: { range: [closingParenStartIndex, index] }
|
|
4720
4722
|
};
|
|
4721
4723
|
/**
|
|
4722
4724
|
* Skip spaces
|
|
@@ -4808,12 +4810,18 @@ function parseImage(sourceCode, node) {
|
|
|
4808
4810
|
if (!parsed) return null;
|
|
4809
4811
|
const nodeRange = sourceCode.getRange(node);
|
|
4810
4812
|
const textRange = [nodeRange[0] + parsed.text.range[0], nodeRange[0] + parsed.text.range[1]];
|
|
4813
|
+
const openingParenRange = [nodeRange[0] + parsed.openingParen.range[0], nodeRange[0] + parsed.openingParen.range[1]];
|
|
4811
4814
|
const destinationRange = [nodeRange[0] + parsed.destination.range[0], nodeRange[0] + parsed.destination.range[1]];
|
|
4815
|
+
const closingParenRange = [nodeRange[0] + parsed.closingParen.range[0], nodeRange[0] + parsed.closingParen.range[1]];
|
|
4812
4816
|
return {
|
|
4813
4817
|
text: {
|
|
4814
4818
|
range: textRange,
|
|
4815
4819
|
loc: getSourceLocationFromRange(sourceCode, node, textRange)
|
|
4816
4820
|
},
|
|
4821
|
+
openingParen: {
|
|
4822
|
+
range: openingParenRange,
|
|
4823
|
+
loc: getSourceLocationFromRange(sourceCode, node, openingParenRange)
|
|
4824
|
+
},
|
|
4817
4825
|
destination: {
|
|
4818
4826
|
type: parsed.destination.type,
|
|
4819
4827
|
text: parsed.destination.text,
|
|
@@ -4825,7 +4833,11 @@ function parseImage(sourceCode, node) {
|
|
|
4825
4833
|
text: parsed.title.text,
|
|
4826
4834
|
range: [nodeRange[0] + parsed.title.range[0], nodeRange[0] + parsed.title.range[1]],
|
|
4827
4835
|
loc: getSourceLocationFromRange(sourceCode, node, [nodeRange[0] + parsed.title.range[0], nodeRange[0] + parsed.title.range[1]])
|
|
4828
|
-
} : null
|
|
4836
|
+
} : null,
|
|
4837
|
+
closingParen: {
|
|
4838
|
+
range: closingParenRange,
|
|
4839
|
+
loc: getSourceLocationFromRange(sourceCode, node, closingParenRange)
|
|
4840
|
+
}
|
|
4829
4841
|
};
|
|
4830
4842
|
}
|
|
4831
4843
|
/**
|
|
@@ -4836,6 +4848,7 @@ function parseImageFromText(text) {
|
|
|
4836
4848
|
let index = text.length - 1;
|
|
4837
4849
|
skipSpaces();
|
|
4838
4850
|
if (text[index] !== ")") return null;
|
|
4851
|
+
const closingParenStartIndex = index;
|
|
4839
4852
|
index--;
|
|
4840
4853
|
skipSpaces();
|
|
4841
4854
|
let title = null;
|
|
@@ -4880,12 +4893,16 @@ function parseImageFromText(text) {
|
|
|
4880
4893
|
}
|
|
4881
4894
|
skipSpaces();
|
|
4882
4895
|
if (text[index] !== "(") return null;
|
|
4896
|
+
const openingParenStartIndex = index;
|
|
4883
4897
|
index--;
|
|
4884
4898
|
if (text[index] !== "]") return null;
|
|
4899
|
+
const textRange = [1, index + 1];
|
|
4885
4900
|
return {
|
|
4886
|
-
|
|
4901
|
+
openingParen: { range: [openingParenStartIndex, openingParenStartIndex + 1] },
|
|
4902
|
+
text: { range: textRange },
|
|
4887
4903
|
destination,
|
|
4888
|
-
title
|
|
4904
|
+
title,
|
|
4905
|
+
closingParen: { range: [closingParenStartIndex, closingParenStartIndex + 1] }
|
|
4889
4906
|
};
|
|
4890
4907
|
/**
|
|
4891
4908
|
* Skip spaces
|
|
@@ -5624,6 +5641,265 @@ function hasLoneLastBackslash(text) {
|
|
|
5624
5641
|
return escapeText.length % 2 === 1;
|
|
5625
5642
|
}
|
|
5626
5643
|
|
|
5644
|
+
//#endregion
|
|
5645
|
+
//#region src/rules/link-paren-newline.ts
|
|
5646
|
+
var link_paren_newline_default = createRule("link-paren-newline", {
|
|
5647
|
+
meta: {
|
|
5648
|
+
type: "layout",
|
|
5649
|
+
docs: {
|
|
5650
|
+
description: "enforce linebreaks after opening and before closing link parentheses",
|
|
5651
|
+
categories: ["standard"],
|
|
5652
|
+
listCategory: "Stylistic"
|
|
5653
|
+
},
|
|
5654
|
+
fixable: "whitespace",
|
|
5655
|
+
hasSuggestions: false,
|
|
5656
|
+
schema: [{
|
|
5657
|
+
type: "object",
|
|
5658
|
+
properties: {
|
|
5659
|
+
newline: { enum: [
|
|
5660
|
+
"always",
|
|
5661
|
+
"never",
|
|
5662
|
+
"consistent"
|
|
5663
|
+
] },
|
|
5664
|
+
multiline: { type: "boolean" }
|
|
5665
|
+
},
|
|
5666
|
+
additionalProperties: false
|
|
5667
|
+
}],
|
|
5668
|
+
messages: {
|
|
5669
|
+
expectedNewlineAfterOpeningParen: "Expected a linebreak after this opening parenthesis.",
|
|
5670
|
+
unexpectedNewlineAfterOpeningParen: "Unexpected linebreak after this opening parenthesis.",
|
|
5671
|
+
expectedNewlineBeforeClosingParen: "Expected a linebreak before this closing parenthesis.",
|
|
5672
|
+
unexpectedNewlineBeforeClosingParen: "Unexpected linebreak before this closing parenthesis."
|
|
5673
|
+
}
|
|
5674
|
+
},
|
|
5675
|
+
create(context) {
|
|
5676
|
+
const sourceCode = context.sourceCode;
|
|
5677
|
+
const optionProvider = parseOptions$3(context.options[0]);
|
|
5678
|
+
/**
|
|
5679
|
+
* Parse the options.
|
|
5680
|
+
*/
|
|
5681
|
+
function parseOptions$3(option) {
|
|
5682
|
+
const newline = option?.newline ?? "never";
|
|
5683
|
+
const multiline = option?.multiline ?? false;
|
|
5684
|
+
return (openingParenIndex, closingParenIndex) => {
|
|
5685
|
+
if (multiline) {
|
|
5686
|
+
if (sourceCode.text.slice(openingParenIndex + 1, closingParenIndex).trim().includes("\n")) return "always";
|
|
5687
|
+
}
|
|
5688
|
+
return newline;
|
|
5689
|
+
};
|
|
5690
|
+
}
|
|
5691
|
+
/**
|
|
5692
|
+
* Verify the newline around the parentheses.
|
|
5693
|
+
*/
|
|
5694
|
+
function verifyNewlineAroundParens(node, openingParenIndex, closingParenIndex) {
|
|
5695
|
+
const newline = optionProvider(openingParenIndex, closingParenIndex);
|
|
5696
|
+
const spaceAfterOpeningParen = getSpaceAfterOpeningParen(openingParenIndex);
|
|
5697
|
+
verifyNewlineAfterOpeningParen(node, spaceAfterOpeningParen, openingParenIndex, newline);
|
|
5698
|
+
const newlineOptionBeforeClosingParen = newline === "consistent" ? getSpaceAfterOpeningParen(openingParenIndex).includes("\n") ? "always" : "never" : newline;
|
|
5699
|
+
verifyNewlineBeforeClosingParen(node, getSpaceBeforeClosingParen(closingParenIndex), openingParenIndex, closingParenIndex, newlineOptionBeforeClosingParen);
|
|
5700
|
+
}
|
|
5701
|
+
/**
|
|
5702
|
+
* Verify the newline after the opening parenthesis and before the closing parenthesis.
|
|
5703
|
+
*/
|
|
5704
|
+
function verifyNewlineAfterOpeningParen(node, spaceAfterOpeningParen, openingParenIndex, newline) {
|
|
5705
|
+
if (newline === "always") {
|
|
5706
|
+
if (spaceAfterOpeningParen.includes("\n")) return;
|
|
5707
|
+
const loc = getSourceLocationFromRange(sourceCode, node, [openingParenIndex, openingParenIndex + 1]);
|
|
5708
|
+
context.report({
|
|
5709
|
+
node,
|
|
5710
|
+
loc,
|
|
5711
|
+
messageId: "expectedNewlineAfterOpeningParen",
|
|
5712
|
+
fix: (fixer) => fixer.insertTextAfterRange([openingParenIndex, openingParenIndex + 1], `\n${" ".repeat(loc.start.column)}${spaceAfterOpeningParen}`)
|
|
5713
|
+
});
|
|
5714
|
+
} else if (newline === "never") {
|
|
5715
|
+
if (!spaceAfterOpeningParen.includes("\n")) return;
|
|
5716
|
+
context.report({
|
|
5717
|
+
node,
|
|
5718
|
+
loc: getSourceLocationFromRange(sourceCode, node, [openingParenIndex + 1, openingParenIndex + 1 + spaceAfterOpeningParen.length]),
|
|
5719
|
+
messageId: "unexpectedNewlineAfterOpeningParen",
|
|
5720
|
+
fix: (fixer) => fixer.replaceTextRange([openingParenIndex + 1, openingParenIndex + 1 + spaceAfterOpeningParen.length], " ")
|
|
5721
|
+
});
|
|
5722
|
+
}
|
|
5723
|
+
}
|
|
5724
|
+
/**
|
|
5725
|
+
* Verify the newline before the closing parenthesis.
|
|
5726
|
+
*/
|
|
5727
|
+
function verifyNewlineBeforeClosingParen(node, spaceBeforeClosingParen, openingParenIndex, closingParenIndex, newline) {
|
|
5728
|
+
if (openingParenIndex + 1 === closingParenIndex - spaceBeforeClosingParen.length) return;
|
|
5729
|
+
if (newline === "always") {
|
|
5730
|
+
if (spaceBeforeClosingParen.includes("\n")) return;
|
|
5731
|
+
context.report({
|
|
5732
|
+
node,
|
|
5733
|
+
loc: getSourceLocationFromRange(sourceCode, node, [closingParenIndex, closingParenIndex + 1]),
|
|
5734
|
+
messageId: "expectedNewlineBeforeClosingParen",
|
|
5735
|
+
fix: (fixer) => {
|
|
5736
|
+
const openingParenLoc = getSourceLocationFromRange(sourceCode, node, [openingParenIndex, openingParenIndex + 1]);
|
|
5737
|
+
return fixer.insertTextBeforeRange([closingParenIndex, closingParenIndex + 1], `\n${" ".repeat(openingParenLoc.start.column)}`);
|
|
5738
|
+
}
|
|
5739
|
+
});
|
|
5740
|
+
} else if (newline === "never") {
|
|
5741
|
+
if (!spaceBeforeClosingParen.includes("\n")) return;
|
|
5742
|
+
context.report({
|
|
5743
|
+
node,
|
|
5744
|
+
loc: getSourceLocationFromRange(sourceCode, node, [closingParenIndex - spaceBeforeClosingParen.length, closingParenIndex]),
|
|
5745
|
+
messageId: "unexpectedNewlineBeforeClosingParen",
|
|
5746
|
+
fix: (fixer) => fixer.replaceTextRange([closingParenIndex - spaceBeforeClosingParen.length, closingParenIndex], " ")
|
|
5747
|
+
});
|
|
5748
|
+
}
|
|
5749
|
+
}
|
|
5750
|
+
return {
|
|
5751
|
+
link(node) {
|
|
5752
|
+
if (getLinkKind(sourceCode, node) !== "inline") return;
|
|
5753
|
+
const parsed = parseInlineLink(sourceCode, node);
|
|
5754
|
+
if (!parsed) return;
|
|
5755
|
+
verifyNewlineAroundParens(node, parsed.openingParen.range[0], parsed.closingParen.range[0]);
|
|
5756
|
+
},
|
|
5757
|
+
image(node) {
|
|
5758
|
+
const parsed = parseImage(sourceCode, node);
|
|
5759
|
+
if (!parsed) return;
|
|
5760
|
+
verifyNewlineAroundParens(node, parsed.openingParen.range[0], parsed.closingParen.range[0]);
|
|
5761
|
+
}
|
|
5762
|
+
};
|
|
5763
|
+
/**
|
|
5764
|
+
* Get the spaces after the opening parenthesis.
|
|
5765
|
+
*/
|
|
5766
|
+
function getSpaceAfterOpeningParen(openingParenIndex) {
|
|
5767
|
+
for (let i = openingParenIndex + 1; i < sourceCode.text.length; i++) {
|
|
5768
|
+
const char = sourceCode.text[i];
|
|
5769
|
+
if (isWhitespace(char)) continue;
|
|
5770
|
+
return sourceCode.text.slice(openingParenIndex + 1, i);
|
|
5771
|
+
}
|
|
5772
|
+
return sourceCode.text.slice(openingParenIndex + 1);
|
|
5773
|
+
}
|
|
5774
|
+
/**
|
|
5775
|
+
* Get the spaces before the closing parenthesis.
|
|
5776
|
+
*/
|
|
5777
|
+
function getSpaceBeforeClosingParen(closingParenIndex) {
|
|
5778
|
+
for (let i = closingParenIndex - 1; i >= 0; i--) {
|
|
5779
|
+
const char = sourceCode.text[i];
|
|
5780
|
+
if (isWhitespace(char)) continue;
|
|
5781
|
+
return sourceCode.text.slice(i + 1, closingParenIndex);
|
|
5782
|
+
}
|
|
5783
|
+
return sourceCode.text.slice(0, closingParenIndex);
|
|
5784
|
+
}
|
|
5785
|
+
}
|
|
5786
|
+
});
|
|
5787
|
+
|
|
5788
|
+
//#endregion
|
|
5789
|
+
//#region src/rules/link-paren-spacing.ts
|
|
5790
|
+
var link_paren_spacing_default = createRule("link-paren-spacing", {
|
|
5791
|
+
meta: {
|
|
5792
|
+
type: "layout",
|
|
5793
|
+
docs: {
|
|
5794
|
+
description: "enforce consistent spacing inside link parentheses",
|
|
5795
|
+
categories: ["standard"],
|
|
5796
|
+
listCategory: "Stylistic"
|
|
5797
|
+
},
|
|
5798
|
+
fixable: "whitespace",
|
|
5799
|
+
hasSuggestions: false,
|
|
5800
|
+
schema: [{
|
|
5801
|
+
type: "object",
|
|
5802
|
+
properties: { space: { enum: ["always", "never"] } },
|
|
5803
|
+
additionalProperties: false
|
|
5804
|
+
}],
|
|
5805
|
+
messages: {
|
|
5806
|
+
unexpectedSpaceAfterOpeningParen: "Unexpected space after opening parenthesis.",
|
|
5807
|
+
expectedSpaceAfterOpeningParen: "Expected space after opening parenthesis.",
|
|
5808
|
+
unexpectedSpaceBeforeClosingParen: "Unexpected space before closing parenthesis.",
|
|
5809
|
+
expectedSpaceBeforeClosingParen: "Expected space before closing parenthesis."
|
|
5810
|
+
}
|
|
5811
|
+
},
|
|
5812
|
+
create(context) {
|
|
5813
|
+
const sourceCode = context.sourceCode;
|
|
5814
|
+
const spaceOption = context.options[0]?.space || "never";
|
|
5815
|
+
/**
|
|
5816
|
+
* Verify the space after the opening paren and before the closing paren.
|
|
5817
|
+
*/
|
|
5818
|
+
function verifySpaceAfterOpeningParen(node, openingParen) {
|
|
5819
|
+
const space = getSpaceAfterOpeningParen(openingParen);
|
|
5820
|
+
if (space.includes("\n")) return;
|
|
5821
|
+
if (spaceOption === "always") {
|
|
5822
|
+
if (space.length > 0) return;
|
|
5823
|
+
context.report({
|
|
5824
|
+
node,
|
|
5825
|
+
loc: openingParen.loc,
|
|
5826
|
+
messageId: "expectedSpaceAfterOpeningParen",
|
|
5827
|
+
fix: (fixer) => fixer.insertTextAfterRange(openingParen.range, " ")
|
|
5828
|
+
});
|
|
5829
|
+
} else if (spaceOption === "never") {
|
|
5830
|
+
if (space.length === 0) return;
|
|
5831
|
+
context.report({
|
|
5832
|
+
node,
|
|
5833
|
+
loc: getSourceLocationFromRange(sourceCode, node, [openingParen.range[1], openingParen.range[1] + space.length]),
|
|
5834
|
+
messageId: "unexpectedSpaceAfterOpeningParen",
|
|
5835
|
+
fix: (fixer) => fixer.removeRange([openingParen.range[1], openingParen.range[1] + space.length])
|
|
5836
|
+
});
|
|
5837
|
+
}
|
|
5838
|
+
}
|
|
5839
|
+
/**
|
|
5840
|
+
* Verify the space before the closing paren.
|
|
5841
|
+
*/
|
|
5842
|
+
function verifySpaceBeforeClosingParen(node, closingParen) {
|
|
5843
|
+
const space = getSpaceBeforeClosingParen(closingParen);
|
|
5844
|
+
if (space.includes("\n")) return;
|
|
5845
|
+
if (spaceOption === "always") {
|
|
5846
|
+
if (space.length > 0) return;
|
|
5847
|
+
context.report({
|
|
5848
|
+
node,
|
|
5849
|
+
loc: closingParen.loc,
|
|
5850
|
+
messageId: "expectedSpaceBeforeClosingParen",
|
|
5851
|
+
fix: (fixer) => fixer.insertTextBeforeRange(closingParen.range, " ")
|
|
5852
|
+
});
|
|
5853
|
+
} else if (spaceOption === "never") {
|
|
5854
|
+
if (space.length === 0) return;
|
|
5855
|
+
context.report({
|
|
5856
|
+
node,
|
|
5857
|
+
loc: getSourceLocationFromRange(sourceCode, node, [closingParen.range[0] - space.length, closingParen.range[0]]),
|
|
5858
|
+
messageId: "unexpectedSpaceBeforeClosingParen",
|
|
5859
|
+
fix: (fixer) => fixer.removeRange([closingParen.range[0] - space.length, closingParen.range[0]])
|
|
5860
|
+
});
|
|
5861
|
+
}
|
|
5862
|
+
}
|
|
5863
|
+
return {
|
|
5864
|
+
link(node) {
|
|
5865
|
+
if (getLinkKind(sourceCode, node) !== "inline") return;
|
|
5866
|
+
const parsed = parseInlineLink(sourceCode, node);
|
|
5867
|
+
if (!parsed) return;
|
|
5868
|
+
verifySpaceAfterOpeningParen(node, parsed.openingParen);
|
|
5869
|
+
verifySpaceBeforeClosingParen(node, parsed.closingParen);
|
|
5870
|
+
},
|
|
5871
|
+
image(node) {
|
|
5872
|
+
const parsed = parseImage(sourceCode, node);
|
|
5873
|
+
if (!parsed) return;
|
|
5874
|
+
verifySpaceAfterOpeningParen(node, parsed.openingParen);
|
|
5875
|
+
verifySpaceBeforeClosingParen(node, parsed.closingParen);
|
|
5876
|
+
}
|
|
5877
|
+
};
|
|
5878
|
+
/**
|
|
5879
|
+
* Get the spaces after the opening paren.
|
|
5880
|
+
*/
|
|
5881
|
+
function getSpaceAfterOpeningParen(openingParen) {
|
|
5882
|
+
for (let i = openingParen.range[1]; i < sourceCode.text.length; i++) {
|
|
5883
|
+
const char = sourceCode.text[i];
|
|
5884
|
+
if (isWhitespace(char)) continue;
|
|
5885
|
+
return sourceCode.text.slice(openingParen.range[1], i);
|
|
5886
|
+
}
|
|
5887
|
+
return sourceCode.text.slice(openingParen.range[1]);
|
|
5888
|
+
}
|
|
5889
|
+
/**
|
|
5890
|
+
* Get the spaces before the closing paren.
|
|
5891
|
+
*/
|
|
5892
|
+
function getSpaceBeforeClosingParen(closingParen) {
|
|
5893
|
+
for (let i = closingParen.range[0] - 1; i >= 0; i--) {
|
|
5894
|
+
const char = sourceCode.text[i];
|
|
5895
|
+
if (isWhitespace(char)) continue;
|
|
5896
|
+
return sourceCode.text.slice(i + 1, closingParen.range[0]);
|
|
5897
|
+
}
|
|
5898
|
+
return sourceCode.text.slice(0, closingParen.range[0]);
|
|
5899
|
+
}
|
|
5900
|
+
}
|
|
5901
|
+
});
|
|
5902
|
+
|
|
5627
5903
|
//#endregion
|
|
5628
5904
|
//#region src/rules/link-title-style.ts
|
|
5629
5905
|
const STYLES = {
|
|
@@ -8543,6 +8819,8 @@ const rules$1 = [
|
|
|
8543
8819
|
link_bracket_newline_default,
|
|
8544
8820
|
link_bracket_spacing_default,
|
|
8545
8821
|
link_destination_style_default,
|
|
8822
|
+
link_paren_newline_default,
|
|
8823
|
+
link_paren_spacing_default,
|
|
8546
8824
|
link_title_style_default,
|
|
8547
8825
|
list_marker_alignment_default,
|
|
8548
8826
|
no_laziness_blockquotes_default,
|
|
@@ -8634,6 +8912,8 @@ const rules$2 = {
|
|
|
8634
8912
|
"markdown-preferences/link-bracket-newline": "error",
|
|
8635
8913
|
"markdown-preferences/link-bracket-spacing": "error",
|
|
8636
8914
|
"markdown-preferences/link-destination-style": "error",
|
|
8915
|
+
"markdown-preferences/link-paren-newline": "error",
|
|
8916
|
+
"markdown-preferences/link-paren-spacing": "error",
|
|
8637
8917
|
"markdown-preferences/link-title-style": "error",
|
|
8638
8918
|
"markdown-preferences/list-marker-alignment": "error",
|
|
8639
8919
|
"markdown-preferences/no-laziness-blockquotes": "error",
|
|
@@ -8663,7 +8943,7 @@ __export(meta_exports, {
|
|
|
8663
8943
|
version: () => version
|
|
8664
8944
|
});
|
|
8665
8945
|
const name = "eslint-plugin-markdown-preferences";
|
|
8666
|
-
const version = "0.
|
|
8946
|
+
const version = "0.23.0";
|
|
8667
8947
|
|
|
8668
8948
|
//#endregion
|
|
8669
8949
|
//#region src/index.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-markdown-preferences",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.23.0",
|
|
4
4
|
"description": "ESLint plugin that enforces our markdown preferences",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -94,7 +94,7 @@
|
|
|
94
94
|
"eslint-plugin-json-schema-validator": "^5.3.1",
|
|
95
95
|
"eslint-plugin-jsonc": "^2.19.1",
|
|
96
96
|
"eslint-plugin-markdown": "^5.1.0",
|
|
97
|
-
"eslint-plugin-markdown-links": "^0.
|
|
97
|
+
"eslint-plugin-markdown-links": "^0.5.0",
|
|
98
98
|
"eslint-plugin-n": "^17.16.2",
|
|
99
99
|
"eslint-plugin-node-dependencies": "^1.0.0",
|
|
100
100
|
"eslint-plugin-prettier": "^5.2.3",
|
|
@@ -115,7 +115,7 @@
|
|
|
115
115
|
"stylelint-config-recommended-vue": "^1.6.0",
|
|
116
116
|
"stylelint-config-standard": "^39.0.0",
|
|
117
117
|
"stylelint-config-standard-vue": "^1.0.0",
|
|
118
|
-
"tsdown": "^0.
|
|
118
|
+
"tsdown": "^0.15.0",
|
|
119
119
|
"tsx": "^4.19.3",
|
|
120
120
|
"twoslash-eslint": "^0.3.1",
|
|
121
121
|
"type-fest": "^4.37.0",
|