eslint-plugin-markdown-preferences 0.24.0 → 0.26.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 +88 -56
- package/lib/index.d.ts +46 -2
- package/lib/index.js +1295 -81
- package/package.json +2 -2
package/lib/index.js
CHANGED
|
@@ -36,6 +36,26 @@ function getParent(sourceCode, node) {
|
|
|
36
36
|
return sourceCode.getParent(node);
|
|
37
37
|
}
|
|
38
38
|
/**
|
|
39
|
+
* Get the previous sibling of a node.
|
|
40
|
+
*/
|
|
41
|
+
function getPrevSibling(sourceCode, node) {
|
|
42
|
+
const parent = getParent(sourceCode, node);
|
|
43
|
+
if (!parent) return null;
|
|
44
|
+
const index = parent.children.indexOf(node);
|
|
45
|
+
if (index <= 0) return null;
|
|
46
|
+
return parent.children[index - 1];
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Get the next sibling of a node.
|
|
50
|
+
*/
|
|
51
|
+
function getNextSibling(sourceCode, node) {
|
|
52
|
+
const parent = getParent(sourceCode, node);
|
|
53
|
+
if (!parent) return null;
|
|
54
|
+
const index = parent.children.indexOf(node);
|
|
55
|
+
if (index < 0 || index >= parent.children.length - 1) return null;
|
|
56
|
+
return parent.children[index + 1];
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
39
59
|
* Get the kind of heading.
|
|
40
60
|
*/
|
|
41
61
|
function getHeadingKind(sourceCode, node) {
|
|
@@ -109,13 +129,20 @@ function getThematicBreakMarker(sourceCode, node) {
|
|
|
109
129
|
* Get the source location from a range in a node.
|
|
110
130
|
*/
|
|
111
131
|
function getSourceLocationFromRange(sourceCode, node, range) {
|
|
112
|
-
const
|
|
132
|
+
const nodeRange = sourceCode.getRange(node);
|
|
133
|
+
const loc = sourceCode.getLoc(node);
|
|
134
|
+
if (nodeRange[1] <= range[0]) return getSourceLocationFromRangeAndSourcePosition(sourceCode, nodeRange[1], loc.end, range);
|
|
135
|
+
return getSourceLocationFromRangeAndSourcePosition(sourceCode, nodeRange[0], loc.start, range);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Get the source location from a range
|
|
139
|
+
*/
|
|
140
|
+
function getSourceLocationFromRangeAndSourcePosition(sourceCode, startIndex, startLoc, range) {
|
|
113
141
|
let startLine, startColumn;
|
|
114
|
-
if (
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
startColumn = (beforeLines.length === 1 ? loc.start.column : 1) + (beforeLines.at(-1) || "").length;
|
|
142
|
+
if (startIndex <= range[0]) {
|
|
143
|
+
const beforeLines = sourceCode.text.slice(startIndex, range[0]).split(/\n/u);
|
|
144
|
+
startLine = startLoc.line + beforeLines.length - 1;
|
|
145
|
+
startColumn = (beforeLines.length === 1 ? startLoc.column : 1) + (beforeLines.at(-1) || "").length;
|
|
119
146
|
} else {
|
|
120
147
|
const beforeLines = sourceCode.text.slice(0, range[0]).split(/\n/u);
|
|
121
148
|
startLine = beforeLines.length;
|
|
@@ -364,15 +391,23 @@ function getParsedLines(sourceCode) {
|
|
|
364
391
|
}
|
|
365
392
|
|
|
366
393
|
//#endregion
|
|
367
|
-
//#region src/utils/
|
|
394
|
+
//#region src/utils/text-width.ts
|
|
368
395
|
let segmenter;
|
|
369
396
|
/**
|
|
370
397
|
* Get the width of a text string.
|
|
371
398
|
*/
|
|
372
|
-
function getTextWidth(text) {
|
|
373
|
-
if (!text.includes(" ")) return stringWidth(text);
|
|
399
|
+
function getTextWidth(text, start = 0, end = text.length) {
|
|
400
|
+
if (!text.includes(" ")) return stringWidth(text.slice(start, end));
|
|
374
401
|
if (!segmenter) segmenter = new Intl.Segmenter("en");
|
|
375
|
-
|
|
402
|
+
const prefixWidth = getTextWidthBySegment(text.slice(0, start), 0);
|
|
403
|
+
return getTextWidthBySegment(text.slice(start, end), prefixWidth);
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Get the width of a text string by segmenter.
|
|
407
|
+
*/
|
|
408
|
+
function getTextWidthBySegment(text, startWidth) {
|
|
409
|
+
if (!segmenter) segmenter = new Intl.Segmenter("en");
|
|
410
|
+
let width = startWidth;
|
|
376
411
|
for (const { segment: c } of segmenter.segment(text)) if (c === " ") width += 4 - width % 4;
|
|
377
412
|
else width += stringWidth(c);
|
|
378
413
|
return width;
|
|
@@ -386,7 +421,7 @@ var atx_heading_closing_sequence_length_default = createRule("atx-heading-closin
|
|
|
386
421
|
docs: {
|
|
387
422
|
description: "enforce consistent length for the closing sequence (trailing #s) in ATX headings.",
|
|
388
423
|
categories: ["standard"],
|
|
389
|
-
listCategory: "
|
|
424
|
+
listCategory: "Decorative"
|
|
390
425
|
},
|
|
391
426
|
fixable: "code",
|
|
392
427
|
hasSuggestions: false,
|
|
@@ -524,7 +559,7 @@ var atx_heading_closing_sequence_default = createRule("atx-heading-closing-seque
|
|
|
524
559
|
docs: {
|
|
525
560
|
description: "enforce consistent use of closing sequence in ATX headings.",
|
|
526
561
|
categories: ["standard"],
|
|
527
|
-
listCategory: "
|
|
562
|
+
listCategory: "Decorative"
|
|
528
563
|
},
|
|
529
564
|
fixable: "code",
|
|
530
565
|
hasSuggestions: false,
|
|
@@ -700,7 +735,7 @@ var blockquote_marker_alignment_default = createRule("blockquote-marker-alignmen
|
|
|
700
735
|
docs: {
|
|
701
736
|
description: "enforce consistent alignment of blockquote markers",
|
|
702
737
|
categories: ["recommended", "standard"],
|
|
703
|
-
listCategory: "
|
|
738
|
+
listCategory: "Whitespace"
|
|
704
739
|
},
|
|
705
740
|
fixable: "whitespace",
|
|
706
741
|
hasSuggestions: false,
|
|
@@ -783,7 +818,7 @@ function getOtherMarker(unavailableMarker) {
|
|
|
783
818
|
/**
|
|
784
819
|
* Parse rule options.
|
|
785
820
|
*/
|
|
786
|
-
function parseOptions$
|
|
821
|
+
function parseOptions$5(options) {
|
|
787
822
|
const primary = options.primary || "-";
|
|
788
823
|
const secondary = options.secondary || getOtherMarker(primary);
|
|
789
824
|
if (primary === secondary) throw new Error(`\`primary\` and \`secondary\` cannot be the same (primary: "${primary}", secondary: "${secondary}").`);
|
|
@@ -815,7 +850,7 @@ var bullet_list_marker_style_default = createRule("bullet-list-marker-style", {
|
|
|
815
850
|
docs: {
|
|
816
851
|
description: "enforce consistent bullet list (unordered list) marker style",
|
|
817
852
|
categories: ["standard"],
|
|
818
|
-
listCategory: "
|
|
853
|
+
listCategory: "Notation"
|
|
819
854
|
},
|
|
820
855
|
fixable: "code",
|
|
821
856
|
hasSuggestions: false,
|
|
@@ -851,7 +886,7 @@ var bullet_list_marker_style_default = createRule("bullet-list-marker-style", {
|
|
|
851
886
|
},
|
|
852
887
|
create(context) {
|
|
853
888
|
const sourceCode = context.sourceCode;
|
|
854
|
-
const options = parseOptions$
|
|
889
|
+
const options = parseOptions$5(context.options[0] || {});
|
|
855
890
|
let containerStack = {
|
|
856
891
|
node: sourceCode.ast,
|
|
857
892
|
level: 1,
|
|
@@ -1114,7 +1149,7 @@ var code_fence_length_default = createRule("code-fence-length", {
|
|
|
1114
1149
|
docs: {
|
|
1115
1150
|
description: "enforce consistent code fence length in fenced code blocks.",
|
|
1116
1151
|
categories: ["standard"],
|
|
1117
|
-
listCategory: "
|
|
1152
|
+
listCategory: "Decorative"
|
|
1118
1153
|
},
|
|
1119
1154
|
fixable: "code",
|
|
1120
1155
|
hasSuggestions: false,
|
|
@@ -1251,7 +1286,7 @@ var code_fence_style_default = createRule("code-fence-style", {
|
|
|
1251
1286
|
docs: {
|
|
1252
1287
|
description: "enforce a consistent code fence style (backtick or tilde) in Markdown fenced code blocks.",
|
|
1253
1288
|
categories: ["standard"],
|
|
1254
|
-
listCategory: "
|
|
1289
|
+
listCategory: "Notation"
|
|
1255
1290
|
},
|
|
1256
1291
|
fixable: "code",
|
|
1257
1292
|
hasSuggestions: false,
|
|
@@ -1292,41 +1327,265 @@ var code_fence_style_default = createRule("code-fence-style", {
|
|
|
1292
1327
|
|
|
1293
1328
|
//#endregion
|
|
1294
1329
|
//#region src/rules/definitions-last.ts
|
|
1330
|
+
/**
|
|
1331
|
+
* Parse options with defaults.
|
|
1332
|
+
*/
|
|
1333
|
+
function parseOptions$4(options) {
|
|
1334
|
+
const linkDefinitionPlacement = {
|
|
1335
|
+
referencedFromSingleSection: options?.linkDefinitionPlacement?.referencedFromSingleSection || "document-last",
|
|
1336
|
+
referencedFromMultipleSections: options?.linkDefinitionPlacement?.referencedFromMultipleSections || "document-last"
|
|
1337
|
+
};
|
|
1338
|
+
const footnoteDefinitionPlacement = {
|
|
1339
|
+
referencedFromSingleSection: options?.footnoteDefinitionPlacement?.referencedFromSingleSection || "document-last",
|
|
1340
|
+
referencedFromMultipleSections: options?.footnoteDefinitionPlacement?.referencedFromMultipleSections || "document-last"
|
|
1341
|
+
};
|
|
1342
|
+
return {
|
|
1343
|
+
linkDefinitionPlacement,
|
|
1344
|
+
footnoteDefinitionPlacement
|
|
1345
|
+
};
|
|
1346
|
+
}
|
|
1295
1347
|
var definitions_last_default = createRule("definitions-last", {
|
|
1296
1348
|
meta: {
|
|
1297
1349
|
type: "layout",
|
|
1298
1350
|
docs: {
|
|
1299
1351
|
description: "require link definitions and footnote definitions to be placed at the end of the document",
|
|
1300
1352
|
categories: [],
|
|
1301
|
-
listCategory: "
|
|
1353
|
+
listCategory: "Notation"
|
|
1302
1354
|
},
|
|
1303
1355
|
fixable: "code",
|
|
1304
1356
|
hasSuggestions: false,
|
|
1305
|
-
schema: [
|
|
1306
|
-
|
|
1357
|
+
schema: [{
|
|
1358
|
+
type: "object",
|
|
1359
|
+
properties: {
|
|
1360
|
+
linkDefinitionPlacement: {
|
|
1361
|
+
type: "object",
|
|
1362
|
+
properties: {
|
|
1363
|
+
referencedFromSingleSection: {
|
|
1364
|
+
type: "string",
|
|
1365
|
+
enum: ["document-last", "section-last"]
|
|
1366
|
+
},
|
|
1367
|
+
referencedFromMultipleSections: {
|
|
1368
|
+
type: "string",
|
|
1369
|
+
enum: [
|
|
1370
|
+
"document-last",
|
|
1371
|
+
"first-reference-section-last",
|
|
1372
|
+
"last-reference-section-last"
|
|
1373
|
+
]
|
|
1374
|
+
}
|
|
1375
|
+
},
|
|
1376
|
+
additionalProperties: false
|
|
1377
|
+
},
|
|
1378
|
+
footnoteDefinitionPlacement: {
|
|
1379
|
+
type: "object",
|
|
1380
|
+
properties: {
|
|
1381
|
+
referencedFromSingleSection: {
|
|
1382
|
+
type: "string",
|
|
1383
|
+
enum: ["document-last", "section-last"]
|
|
1384
|
+
},
|
|
1385
|
+
referencedFromMultipleSections: {
|
|
1386
|
+
type: "string",
|
|
1387
|
+
enum: [
|
|
1388
|
+
"document-last",
|
|
1389
|
+
"first-reference-section-last",
|
|
1390
|
+
"last-reference-section-last"
|
|
1391
|
+
]
|
|
1392
|
+
}
|
|
1393
|
+
},
|
|
1394
|
+
additionalProperties: false
|
|
1395
|
+
}
|
|
1396
|
+
},
|
|
1397
|
+
additionalProperties: false
|
|
1398
|
+
}],
|
|
1399
|
+
messages: {
|
|
1400
|
+
definitionsDocumentLast: "Definition or footnote definition should be placed at the end of the document.",
|
|
1401
|
+
definitionsSectionLast: "Definition or footnote definition should be placed at the end of the section ({{at}}).",
|
|
1402
|
+
definitionsLastSectionLast: "Definition or footnote definition should be placed at the end of the last section (the end of the document)."
|
|
1403
|
+
}
|
|
1307
1404
|
},
|
|
1308
1405
|
create(context) {
|
|
1309
1406
|
const sourceCode = context.sourceCode;
|
|
1310
|
-
const
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1407
|
+
const options = parseOptions$4(context.options[0]);
|
|
1408
|
+
/**
|
|
1409
|
+
* Determine whether a node can be placed as the last node of the document or a section.
|
|
1410
|
+
*/
|
|
1411
|
+
function canBePlacedLastNode(node) {
|
|
1412
|
+
return node.type === "definition" || node.type === "footnoteDefinition" || node.type === "html" && (node.value.startsWith("<!--") || node.value.startsWith("<script") || node.value.startsWith("<style"));
|
|
1413
|
+
}
|
|
1414
|
+
const beforeLastNode = sourceCode.ast.children.findLast((node) => !canBePlacedLastNode(node));
|
|
1415
|
+
if (!beforeLastNode) return {};
|
|
1416
|
+
let lastSection = {
|
|
1417
|
+
heading: null,
|
|
1418
|
+
linkReferenceIds: /* @__PURE__ */ new Set(),
|
|
1419
|
+
footnoteReferenceIds: /* @__PURE__ */ new Set(),
|
|
1420
|
+
nextHeading: null
|
|
1421
|
+
};
|
|
1422
|
+
const sections = [lastSection];
|
|
1423
|
+
const definitions = [];
|
|
1424
|
+
/**
|
|
1425
|
+
* Get the expected placement of a definition or footnote definition node.
|
|
1426
|
+
*/
|
|
1427
|
+
function getExpectedPlacement(node) {
|
|
1428
|
+
let referencedFromSingleSection;
|
|
1429
|
+
let referencedFromMultipleSections;
|
|
1430
|
+
let referenceIdsNs;
|
|
1431
|
+
if (node.type === "definition") {
|
|
1432
|
+
({referencedFromSingleSection, referencedFromMultipleSections} = options.linkDefinitionPlacement);
|
|
1433
|
+
referenceIdsNs = "linkReferenceIds";
|
|
1434
|
+
} else if (node.type === "footnoteDefinition") {
|
|
1435
|
+
({referencedFromSingleSection, referencedFromMultipleSections} = options.footnoteDefinitionPlacement);
|
|
1436
|
+
referenceIdsNs = "footnoteReferenceIds";
|
|
1437
|
+
} else return { type: "document-last" };
|
|
1438
|
+
if (referencedFromSingleSection === "document-last" && referencedFromSingleSection === referencedFromMultipleSections) return { type: "document-last" };
|
|
1439
|
+
const referencedSections = [];
|
|
1440
|
+
for (const section of sections) {
|
|
1441
|
+
if (!section[referenceIdsNs].has(node.identifier)) continue;
|
|
1442
|
+
referencedSections.push(section);
|
|
1443
|
+
if (referencedSections.length > 1 && referencedFromMultipleSections !== "last-reference-section-last") return {
|
|
1444
|
+
type: referencedFromMultipleSections,
|
|
1445
|
+
section: referencedSections[0]
|
|
1446
|
+
};
|
|
1447
|
+
}
|
|
1448
|
+
if (referencedSections.length === 0) return { type: "document-last" };
|
|
1449
|
+
if (referencedSections.length === 1) return {
|
|
1450
|
+
type: referencedFromSingleSection,
|
|
1451
|
+
section: referencedSections[0]
|
|
1452
|
+
};
|
|
1453
|
+
return {
|
|
1454
|
+
type: referencedFromMultipleSections,
|
|
1455
|
+
section: referencedSections[referencedSections.length - 1]
|
|
1456
|
+
};
|
|
1457
|
+
}
|
|
1458
|
+
/**
|
|
1459
|
+
* Verify the position of a definition or footnote definition node.
|
|
1460
|
+
*/
|
|
1461
|
+
function verifyDefinitionPosition(node) {
|
|
1462
|
+
const expectedPlacement = getExpectedPlacement(node);
|
|
1463
|
+
if (expectedPlacement.type === "document-last") verifyDefinitionOnDocumentLast(node, "definitionsDocumentLast");
|
|
1464
|
+
else if (expectedPlacement.type === "section-last" || expectedPlacement.type === "first-reference-section-last" || expectedPlacement.type === "last-reference-section-last") if (!expectedPlacement.section.nextHeading) verifyDefinitionOnDocumentLast(node, "definitionsLastSectionLast");
|
|
1465
|
+
else verifyDefinitionOnSectionLast(node, expectedPlacement.section.nextHeading);
|
|
1466
|
+
}
|
|
1467
|
+
/**
|
|
1468
|
+
* Verify that a definition or footnote definition node is at the end of the document.
|
|
1469
|
+
*/
|
|
1470
|
+
function verifyDefinitionOnDocumentLast(node, messageId) {
|
|
1471
|
+
if (!beforeLastNode) return;
|
|
1314
1472
|
const range = sourceCode.getRange(node);
|
|
1315
|
-
if (
|
|
1473
|
+
if (sourceCode.getRange(beforeLastNode)[1] <= range[0]) return;
|
|
1316
1474
|
context.report({
|
|
1317
1475
|
node,
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
for (let index = range[0] - 1; index >= 0; index--) {
|
|
1322
|
-
if (sourceCode.text[index].trim()) break;
|
|
1323
|
-
rangeStart = index;
|
|
1324
|
-
}
|
|
1325
|
-
yield fixer.removeRange([rangeStart, range[1]]);
|
|
1326
|
-
yield fixer.insertTextAfterRange(lastNonDefinitionRange, sourceCode.text.slice(rangeStart, range[1]));
|
|
1476
|
+
messageId,
|
|
1477
|
+
fix(fixer) {
|
|
1478
|
+
return fixToMoveFromBeforeLastOfSectionToLastOfSection(fixer, beforeLastNode, node);
|
|
1327
1479
|
}
|
|
1328
1480
|
});
|
|
1329
|
-
}
|
|
1481
|
+
}
|
|
1482
|
+
/**
|
|
1483
|
+
* Verify that a definition or footnote definition node is at the end of its section.
|
|
1484
|
+
*/
|
|
1485
|
+
function verifyDefinitionOnSectionLast(node, nextSectionHeading) {
|
|
1486
|
+
const beforeLastOfSectionNode = getSectionBeforeLastNode(nextSectionHeading);
|
|
1487
|
+
if (!beforeLastOfSectionNode) return;
|
|
1488
|
+
const range = sourceCode.getRange(node);
|
|
1489
|
+
const beforeLastOfSectionRange = sourceCode.getRange(beforeLastOfSectionNode);
|
|
1490
|
+
const nextSectionHeadingRange = sourceCode.getRange(nextSectionHeading);
|
|
1491
|
+
if (beforeLastOfSectionRange[1] <= range[0] && range[1] <= nextSectionHeadingRange[0]) return;
|
|
1492
|
+
const expectedStartLine = sourceCode.getLoc(beforeLastOfSectionNode).end.line + 1;
|
|
1493
|
+
const expectedEndLine = sourceCode.getLoc(nextSectionHeading).start.line - 1;
|
|
1494
|
+
context.report({
|
|
1495
|
+
node,
|
|
1496
|
+
messageId: "definitionsSectionLast",
|
|
1497
|
+
data: { at: expectedStartLine === expectedEndLine ? `L${expectedStartLine}` : `between L${expectedStartLine} and L${expectedEndLine}` },
|
|
1498
|
+
fix(fixer) {
|
|
1499
|
+
if (range[0] < beforeLastOfSectionRange[1]) return fixToMoveFromBeforeLastOfSectionToLastOfSection(fixer, beforeLastOfSectionNode, node);
|
|
1500
|
+
return fixToMoveFromAfterLastOfSectionToLastOfSection(fixer, nextSectionHeading, node);
|
|
1501
|
+
}
|
|
1502
|
+
});
|
|
1503
|
+
}
|
|
1504
|
+
/**
|
|
1505
|
+
* Get the node before the last node of a section.
|
|
1506
|
+
*/
|
|
1507
|
+
function getSectionBeforeLastNode(nextSectionHeading) {
|
|
1508
|
+
let candidate = getPrevSibling(sourceCode, nextSectionHeading);
|
|
1509
|
+
while (candidate && canBePlacedLastNode(candidate)) candidate = getPrevSibling(sourceCode, candidate);
|
|
1510
|
+
return candidate;
|
|
1511
|
+
}
|
|
1512
|
+
/**
|
|
1513
|
+
* Fixer to move a definition or footnote definition node from before the last of the document/section
|
|
1514
|
+
* to the last of the document/section.
|
|
1515
|
+
*/
|
|
1516
|
+
function fixToMoveFromBeforeLastOfSectionToLastOfSection(fixer, prev, node) {
|
|
1517
|
+
const next = getNextSibling(sourceCode, prev);
|
|
1518
|
+
return fixToMove(fixer, prev, next, node);
|
|
1519
|
+
}
|
|
1520
|
+
/**
|
|
1521
|
+
* Fixer to move a definition or footnote definition node from after the last of the document/section
|
|
1522
|
+
* to the last of the document/section.
|
|
1523
|
+
*/
|
|
1524
|
+
function fixToMoveFromAfterLastOfSectionToLastOfSection(fixer, next, node) {
|
|
1525
|
+
const prev = getPrevSibling(sourceCode, next);
|
|
1526
|
+
if (!prev) return null;
|
|
1527
|
+
return fixToMove(fixer, prev, next, node);
|
|
1528
|
+
}
|
|
1529
|
+
/**
|
|
1530
|
+
* Fixer to move a definition or footnote definition node to after the prev node.
|
|
1531
|
+
*/
|
|
1532
|
+
function* fixToMove(fixer, prev, next, node) {
|
|
1533
|
+
const range = sourceCode.getRange(node);
|
|
1534
|
+
const loc = sourceCode.getLoc(node);
|
|
1535
|
+
const lineStart = range[0] - loc.start.column + 1;
|
|
1536
|
+
let rangeStart = lineStart;
|
|
1537
|
+
let lineFeeds = 0;
|
|
1538
|
+
for (let index = rangeStart - 1; index >= 0; index--) {
|
|
1539
|
+
const c = sourceCode.text[index];
|
|
1540
|
+
if (c.trim()) break;
|
|
1541
|
+
rangeStart = index;
|
|
1542
|
+
if (c === "\n") lineFeeds++;
|
|
1543
|
+
}
|
|
1544
|
+
yield fixer.removeRange([rangeStart, range[1]]);
|
|
1545
|
+
let insertText = sourceCode.text.slice(rangeStart, lineStart) + sourceCode.text.slice(...range);
|
|
1546
|
+
if (prev.type === "footnoteDefinition" && node.type !== "footnoteDefinition" && lineFeeds <= 1) insertText = `\n${insertText}`;
|
|
1547
|
+
if (next && node.type === "footnoteDefinition" && next.type !== "footnoteDefinition") {
|
|
1548
|
+
const prevLoc = sourceCode.getLoc(prev);
|
|
1549
|
+
const nextLoc = sourceCode.getLoc(next);
|
|
1550
|
+
if (!(prevLoc.end.line + 1 < nextLoc.start.line)) insertText = `${insertText}\n`;
|
|
1551
|
+
}
|
|
1552
|
+
yield fixer.insertTextAfter(prev, insertText);
|
|
1553
|
+
}
|
|
1554
|
+
const containerStack = [];
|
|
1555
|
+
return {
|
|
1556
|
+
"blockquote, listItem, footnoteDefinition"(node) {
|
|
1557
|
+
containerStack.push(node);
|
|
1558
|
+
},
|
|
1559
|
+
"blockquote, listItem, footnoteDefinition:exit"() {
|
|
1560
|
+
containerStack.pop();
|
|
1561
|
+
},
|
|
1562
|
+
heading(node) {
|
|
1563
|
+
if (containerStack.length > 0) return;
|
|
1564
|
+
lastSection.nextHeading = node;
|
|
1565
|
+
lastSection = {
|
|
1566
|
+
heading: node,
|
|
1567
|
+
linkReferenceIds: /* @__PURE__ */ new Set(),
|
|
1568
|
+
footnoteReferenceIds: /* @__PURE__ */ new Set(),
|
|
1569
|
+
nextHeading: null
|
|
1570
|
+
};
|
|
1571
|
+
sections.push(lastSection);
|
|
1572
|
+
},
|
|
1573
|
+
linkReference(node) {
|
|
1574
|
+
lastSection.linkReferenceIds.add(node.identifier);
|
|
1575
|
+
},
|
|
1576
|
+
imageReference(node) {
|
|
1577
|
+
lastSection.linkReferenceIds.add(node.identifier);
|
|
1578
|
+
},
|
|
1579
|
+
footnoteReference(node) {
|
|
1580
|
+
lastSection.footnoteReferenceIds.add(node.identifier);
|
|
1581
|
+
},
|
|
1582
|
+
"definition, footnoteDefinition"(node) {
|
|
1583
|
+
definitions.push(node);
|
|
1584
|
+
},
|
|
1585
|
+
"root:exit"() {
|
|
1586
|
+
for (const node of definitions) verifyDefinitionPosition(node);
|
|
1587
|
+
}
|
|
1588
|
+
};
|
|
1330
1589
|
}
|
|
1331
1590
|
});
|
|
1332
1591
|
|
|
@@ -3422,7 +3681,7 @@ var emphasis_delimiters_style_default = createRule("emphasis-delimiters-style",
|
|
|
3422
3681
|
docs: {
|
|
3423
3682
|
description: "enforce a consistent delimiter style for emphasis and strong emphasis",
|
|
3424
3683
|
categories: ["standard"],
|
|
3425
|
-
listCategory: "
|
|
3684
|
+
listCategory: "Notation"
|
|
3426
3685
|
},
|
|
3427
3686
|
fixable: "code",
|
|
3428
3687
|
hasSuggestions: false,
|
|
@@ -3604,7 +3863,7 @@ var hard_linebreak_style_default = createRule("hard-linebreak-style", {
|
|
|
3604
3863
|
docs: {
|
|
3605
3864
|
description: "enforce consistent hard linebreak style.",
|
|
3606
3865
|
categories: ["recommended", "standard"],
|
|
3607
|
-
listCategory: "
|
|
3866
|
+
listCategory: "Notation"
|
|
3608
3867
|
},
|
|
3609
3868
|
fixable: "code",
|
|
3610
3869
|
hasSuggestions: false,
|
|
@@ -5037,7 +5296,7 @@ function parseListItem(sourceCode, node) {
|
|
|
5037
5296
|
/**
|
|
5038
5297
|
* Parse options.
|
|
5039
5298
|
*/
|
|
5040
|
-
function parseOptions$
|
|
5299
|
+
function parseOptions$3(options) {
|
|
5041
5300
|
const listItems = options?.listItems;
|
|
5042
5301
|
return { listItems: {
|
|
5043
5302
|
first: listItems?.first ?? 1,
|
|
@@ -5051,7 +5310,7 @@ var indent_default = createRule("indent", {
|
|
|
5051
5310
|
docs: {
|
|
5052
5311
|
description: "enforce consistent indentation in Markdown files",
|
|
5053
5312
|
categories: ["standard"],
|
|
5054
|
-
listCategory: "
|
|
5313
|
+
listCategory: "Whitespace"
|
|
5055
5314
|
},
|
|
5056
5315
|
fixable: "whitespace",
|
|
5057
5316
|
hasSuggestions: false,
|
|
@@ -5090,7 +5349,7 @@ var indent_default = createRule("indent", {
|
|
|
5090
5349
|
},
|
|
5091
5350
|
create(context) {
|
|
5092
5351
|
const sourceCode = context.sourceCode;
|
|
5093
|
-
const options = parseOptions$
|
|
5352
|
+
const options = parseOptions$3(context.options[0]);
|
|
5094
5353
|
class AbsBlockStack {
|
|
5095
5354
|
violations = [];
|
|
5096
5355
|
getCurrentBlockquote() {
|
|
@@ -6039,7 +6298,7 @@ var level1_heading_style_default = createRule("level1-heading-style", {
|
|
|
6039
6298
|
docs: {
|
|
6040
6299
|
description: "enforce consistent style for level 1 headings",
|
|
6041
6300
|
categories: ["standard"],
|
|
6042
|
-
listCategory: "
|
|
6301
|
+
listCategory: "Notation"
|
|
6043
6302
|
},
|
|
6044
6303
|
fixable: "code",
|
|
6045
6304
|
hasSuggestions: false,
|
|
@@ -6116,7 +6375,7 @@ var level2_heading_style_default = createRule("level2-heading-style", {
|
|
|
6116
6375
|
docs: {
|
|
6117
6376
|
description: "enforce consistent style for level 2 headings",
|
|
6118
6377
|
categories: ["standard"],
|
|
6119
|
-
listCategory: "
|
|
6378
|
+
listCategory: "Notation"
|
|
6120
6379
|
},
|
|
6121
6380
|
fixable: "code",
|
|
6122
6381
|
hasSuggestions: false,
|
|
@@ -6193,7 +6452,7 @@ var link_bracket_newline_default = createRule("link-bracket-newline", {
|
|
|
6193
6452
|
docs: {
|
|
6194
6453
|
description: "enforce linebreaks after opening and before closing link brackets",
|
|
6195
6454
|
categories: ["standard"],
|
|
6196
|
-
listCategory: "
|
|
6455
|
+
listCategory: "Whitespace"
|
|
6197
6456
|
},
|
|
6198
6457
|
fixable: "whitespace",
|
|
6199
6458
|
hasSuggestions: false,
|
|
@@ -6218,11 +6477,11 @@ var link_bracket_newline_default = createRule("link-bracket-newline", {
|
|
|
6218
6477
|
},
|
|
6219
6478
|
create(context) {
|
|
6220
6479
|
const sourceCode = context.sourceCode;
|
|
6221
|
-
const optionProvider = parseOptions$
|
|
6480
|
+
const optionProvider = parseOptions$6(context.options[0]);
|
|
6222
6481
|
/**
|
|
6223
6482
|
* Parse the options.
|
|
6224
6483
|
*/
|
|
6225
|
-
function parseOptions$
|
|
6484
|
+
function parseOptions$6(option) {
|
|
6226
6485
|
const newline = option?.newline ?? "never";
|
|
6227
6486
|
const multiline = option?.multiline ?? false;
|
|
6228
6487
|
return (bracketsRange) => {
|
|
@@ -6353,7 +6612,7 @@ var link_bracket_newline_default = createRule("link-bracket-newline", {
|
|
|
6353
6612
|
/**
|
|
6354
6613
|
* The basic option for links and images.
|
|
6355
6614
|
*/
|
|
6356
|
-
function parseOptions$
|
|
6615
|
+
function parseOptions$2(option) {
|
|
6357
6616
|
const space = option?.space ?? "never";
|
|
6358
6617
|
const imagesInLinks = option?.imagesInLinks;
|
|
6359
6618
|
return {
|
|
@@ -6382,7 +6641,7 @@ var link_bracket_spacing_default = createRule("link-bracket-spacing", {
|
|
|
6382
6641
|
docs: {
|
|
6383
6642
|
description: "enforce consistent spacing inside link brackets",
|
|
6384
6643
|
categories: ["standard"],
|
|
6385
|
-
listCategory: "
|
|
6644
|
+
listCategory: "Whitespace"
|
|
6386
6645
|
},
|
|
6387
6646
|
fixable: "whitespace",
|
|
6388
6647
|
hasSuggestions: false,
|
|
@@ -6403,7 +6662,7 @@ var link_bracket_spacing_default = createRule("link-bracket-spacing", {
|
|
|
6403
6662
|
},
|
|
6404
6663
|
create(context) {
|
|
6405
6664
|
const sourceCode = context.sourceCode;
|
|
6406
|
-
const options = parseOptions$
|
|
6665
|
+
const options = parseOptions$2(context.options[0]);
|
|
6407
6666
|
/**
|
|
6408
6667
|
* Verify the space after the opening bracket and before the closing bracket.
|
|
6409
6668
|
*/
|
|
@@ -6546,7 +6805,7 @@ var link_destination_style_default = createRule("link-destination-style", {
|
|
|
6546
6805
|
docs: {
|
|
6547
6806
|
description: "enforce a consistent style for link destinations",
|
|
6548
6807
|
categories: ["standard"],
|
|
6549
|
-
listCategory: "
|
|
6808
|
+
listCategory: "Notation"
|
|
6550
6809
|
},
|
|
6551
6810
|
fixable: "code",
|
|
6552
6811
|
hasSuggestions: false,
|
|
@@ -6671,7 +6930,7 @@ var link_paren_newline_default = createRule("link-paren-newline", {
|
|
|
6671
6930
|
docs: {
|
|
6672
6931
|
description: "enforce linebreaks after opening and before closing link parentheses",
|
|
6673
6932
|
categories: ["standard"],
|
|
6674
|
-
listCategory: "
|
|
6933
|
+
listCategory: "Whitespace"
|
|
6675
6934
|
},
|
|
6676
6935
|
fixable: "whitespace",
|
|
6677
6936
|
hasSuggestions: false,
|
|
@@ -6696,11 +6955,11 @@ var link_paren_newline_default = createRule("link-paren-newline", {
|
|
|
6696
6955
|
},
|
|
6697
6956
|
create(context) {
|
|
6698
6957
|
const sourceCode = context.sourceCode;
|
|
6699
|
-
const optionProvider = parseOptions$
|
|
6958
|
+
const optionProvider = parseOptions$6(context.options[0]);
|
|
6700
6959
|
/**
|
|
6701
6960
|
* Parse the options.
|
|
6702
6961
|
*/
|
|
6703
|
-
function parseOptions$
|
|
6962
|
+
function parseOptions$6(option) {
|
|
6704
6963
|
const newline = option?.newline ?? "never";
|
|
6705
6964
|
const multiline = option?.multiline ?? false;
|
|
6706
6965
|
return (openingParenIndex, closingParenIndex) => {
|
|
@@ -6815,7 +7074,7 @@ var link_paren_spacing_default = createRule("link-paren-spacing", {
|
|
|
6815
7074
|
docs: {
|
|
6816
7075
|
description: "enforce consistent spacing inside link parentheses",
|
|
6817
7076
|
categories: ["standard"],
|
|
6818
|
-
listCategory: "
|
|
7077
|
+
listCategory: "Whitespace"
|
|
6819
7078
|
},
|
|
6820
7079
|
fixable: "whitespace",
|
|
6821
7080
|
hasSuggestions: false,
|
|
@@ -6950,7 +7209,7 @@ var link_title_style_default = createRule("link-title-style", {
|
|
|
6950
7209
|
docs: {
|
|
6951
7210
|
description: "enforce a consistent style for link titles",
|
|
6952
7211
|
categories: ["standard"],
|
|
6953
|
-
listCategory: "
|
|
7212
|
+
listCategory: "Notation"
|
|
6954
7213
|
},
|
|
6955
7214
|
fixable: "code",
|
|
6956
7215
|
hasSuggestions: false,
|
|
@@ -7032,7 +7291,7 @@ var list_marker_alignment_default = createRule("list-marker-alignment", {
|
|
|
7032
7291
|
docs: {
|
|
7033
7292
|
description: "enforce consistent alignment of list markers",
|
|
7034
7293
|
categories: ["recommended", "standard"],
|
|
7035
|
-
listCategory: "
|
|
7294
|
+
listCategory: "Whitespace"
|
|
7036
7295
|
},
|
|
7037
7296
|
fixable: "whitespace",
|
|
7038
7297
|
hasSuggestions: false,
|
|
@@ -7131,7 +7390,7 @@ var no_laziness_blockquotes_default = createRule("no-laziness-blockquotes", {
|
|
|
7131
7390
|
docs: {
|
|
7132
7391
|
description: "disallow laziness in blockquotes",
|
|
7133
7392
|
categories: ["recommended", "standard"],
|
|
7134
|
-
listCategory: "
|
|
7393
|
+
listCategory: "Decorative"
|
|
7135
7394
|
},
|
|
7136
7395
|
fixable: void 0,
|
|
7137
7396
|
hasSuggestions: true,
|
|
@@ -7230,6 +7489,193 @@ var no_laziness_blockquotes_default = createRule("no-laziness-blockquotes", {
|
|
|
7230
7489
|
}
|
|
7231
7490
|
});
|
|
7232
7491
|
|
|
7492
|
+
//#endregion
|
|
7493
|
+
//#region src/utils/table.ts
|
|
7494
|
+
/**
|
|
7495
|
+
* Parse the table.
|
|
7496
|
+
*/
|
|
7497
|
+
function parseTable(sourceCode, node) {
|
|
7498
|
+
const headerRow = parseTableRow(sourceCode, node.children[0]);
|
|
7499
|
+
if (!headerRow) return null;
|
|
7500
|
+
const delimiterRow = parseTableDelimiterRow(sourceCode, node);
|
|
7501
|
+
if (!delimiterRow) return null;
|
|
7502
|
+
const bodyRows = [];
|
|
7503
|
+
for (const child of node.children.slice(1)) {
|
|
7504
|
+
const bodyRow = parseTableRow(sourceCode, child);
|
|
7505
|
+
if (!bodyRow) return null;
|
|
7506
|
+
bodyRows.push(bodyRow);
|
|
7507
|
+
}
|
|
7508
|
+
return {
|
|
7509
|
+
headerRow,
|
|
7510
|
+
delimiterRow,
|
|
7511
|
+
bodyRows
|
|
7512
|
+
};
|
|
7513
|
+
}
|
|
7514
|
+
/**
|
|
7515
|
+
* Parse the table delimiter row.
|
|
7516
|
+
*/
|
|
7517
|
+
function parseTableDelimiterRow(sourceCode, node) {
|
|
7518
|
+
const headerRow = node.children[0];
|
|
7519
|
+
const headerRange = sourceCode.getRange(headerRow);
|
|
7520
|
+
const delimiterEndIndex = node.children.length > 1 ? sourceCode.getRange(node.children[1])[0] : sourceCode.getRange(node)[1];
|
|
7521
|
+
const delimiterText = sourceCode.text.slice(headerRange[1], delimiterEndIndex);
|
|
7522
|
+
const parsed = parseTableDelimiterRowFromText(delimiterText);
|
|
7523
|
+
if (!parsed) return null;
|
|
7524
|
+
const delimiters = parsed.delimiters.map((d) => {
|
|
7525
|
+
let leadingPipe = null;
|
|
7526
|
+
if (d.leadingPipe) {
|
|
7527
|
+
const leadingPipeRange = [headerRange[1] + d.leadingPipe.range[0], headerRange[1] + d.leadingPipe.range[1]];
|
|
7528
|
+
leadingPipe = {
|
|
7529
|
+
text: d.leadingPipe.text,
|
|
7530
|
+
range: leadingPipeRange,
|
|
7531
|
+
loc: getSourceLocationFromRange(sourceCode, headerRow, leadingPipeRange)
|
|
7532
|
+
};
|
|
7533
|
+
}
|
|
7534
|
+
const delimiterRange = [headerRange[1] + d.delimiter.range[0], headerRange[1] + d.delimiter.range[1]];
|
|
7535
|
+
return {
|
|
7536
|
+
leadingPipe,
|
|
7537
|
+
delimiter: {
|
|
7538
|
+
text: d.delimiter.text,
|
|
7539
|
+
align: d.delimiter.text.startsWith(":") ? d.delimiter.text.endsWith(":") ? "center" : "left" : d.delimiter.text.endsWith(":") ? "right" : "none",
|
|
7540
|
+
range: delimiterRange,
|
|
7541
|
+
loc: getSourceLocationFromRange(sourceCode, headerRow, delimiterRange)
|
|
7542
|
+
}
|
|
7543
|
+
};
|
|
7544
|
+
});
|
|
7545
|
+
let trailingPipe = null;
|
|
7546
|
+
if (parsed.trailingPipe) {
|
|
7547
|
+
const trailingPipeRange = [headerRange[1] + parsed.trailingPipe.range[0], headerRange[1] + parsed.trailingPipe.range[1]];
|
|
7548
|
+
trailingPipe = {
|
|
7549
|
+
text: parsed.trailingPipe.text,
|
|
7550
|
+
range: trailingPipeRange,
|
|
7551
|
+
loc: getSourceLocationFromRange(sourceCode, headerRow, trailingPipeRange)
|
|
7552
|
+
};
|
|
7553
|
+
}
|
|
7554
|
+
const firstToken = delimiters[0].leadingPipe ?? delimiters[0].delimiter;
|
|
7555
|
+
const lastToken = trailingPipe ?? delimiters[delimiters.length - 1].delimiter;
|
|
7556
|
+
return {
|
|
7557
|
+
delimiters,
|
|
7558
|
+
trailingPipe,
|
|
7559
|
+
range: [firstToken.range[0], lastToken.range[1]],
|
|
7560
|
+
loc: {
|
|
7561
|
+
start: firstToken.loc.start,
|
|
7562
|
+
end: lastToken.loc.end
|
|
7563
|
+
}
|
|
7564
|
+
};
|
|
7565
|
+
}
|
|
7566
|
+
/**
|
|
7567
|
+
* Parse the table row.
|
|
7568
|
+
*/
|
|
7569
|
+
function parseTableRow(sourceCode, node) {
|
|
7570
|
+
const cells = [];
|
|
7571
|
+
let trailingPipe = null;
|
|
7572
|
+
for (const cell of node.children) {
|
|
7573
|
+
const cellRange = sourceCode.getRange(cell);
|
|
7574
|
+
const cellLoc = sourceCode.getLoc(cell);
|
|
7575
|
+
const leadingPipe = sourceCode.text[cellRange[0]] === "|" ? {
|
|
7576
|
+
text: "|",
|
|
7577
|
+
range: [cellRange[0], cellRange[0] + 1],
|
|
7578
|
+
loc: {
|
|
7579
|
+
start: cellLoc.start,
|
|
7580
|
+
end: {
|
|
7581
|
+
line: cellLoc.start.line,
|
|
7582
|
+
column: cellLoc.start.column + 1
|
|
7583
|
+
}
|
|
7584
|
+
}
|
|
7585
|
+
} : null;
|
|
7586
|
+
if (trailingPipe && leadingPipe) return null;
|
|
7587
|
+
let parsedCell = null;
|
|
7588
|
+
if (cell.children.length > 0) {
|
|
7589
|
+
const firstChild = cell.children[0];
|
|
7590
|
+
const lastChild = cell.children[cell.children.length - 1];
|
|
7591
|
+
parsedCell = {
|
|
7592
|
+
range: [sourceCode.getRange(firstChild)[0], sourceCode.getRange(lastChild)[1]],
|
|
7593
|
+
loc: {
|
|
7594
|
+
start: sourceCode.getLoc(firstChild).start,
|
|
7595
|
+
end: sourceCode.getLoc(lastChild).end
|
|
7596
|
+
}
|
|
7597
|
+
};
|
|
7598
|
+
}
|
|
7599
|
+
cells.push({
|
|
7600
|
+
leadingPipe,
|
|
7601
|
+
cell: parsedCell
|
|
7602
|
+
});
|
|
7603
|
+
trailingPipe = sourceCode.text[cellRange[1] - 1] === "|" ? {
|
|
7604
|
+
text: "|",
|
|
7605
|
+
range: [cellRange[1] - 1, cellRange[1]],
|
|
7606
|
+
loc: {
|
|
7607
|
+
start: {
|
|
7608
|
+
line: cellLoc.end.line,
|
|
7609
|
+
column: cellLoc.end.column - 1
|
|
7610
|
+
},
|
|
7611
|
+
end: cellLoc.end
|
|
7612
|
+
}
|
|
7613
|
+
} : null;
|
|
7614
|
+
}
|
|
7615
|
+
const firstToken = cells[0].leadingPipe ?? cells[0].cell;
|
|
7616
|
+
const lastToken = trailingPipe ?? cells[cells.length - 1].cell ?? cells[cells.length - 1].leadingPipe;
|
|
7617
|
+
return {
|
|
7618
|
+
cells,
|
|
7619
|
+
trailingPipe,
|
|
7620
|
+
range: [firstToken.range[0], lastToken.range[1]],
|
|
7621
|
+
loc: {
|
|
7622
|
+
start: firstToken.loc.start,
|
|
7623
|
+
end: lastToken.loc.end
|
|
7624
|
+
}
|
|
7625
|
+
};
|
|
7626
|
+
}
|
|
7627
|
+
/**
|
|
7628
|
+
* Parse the table delimiter row from the text.
|
|
7629
|
+
*/
|
|
7630
|
+
function parseTableDelimiterRowFromText(text) {
|
|
7631
|
+
const cursor = new ForwardCharacterCursor(text);
|
|
7632
|
+
cursor.skipSpaces();
|
|
7633
|
+
while (cursor.curr() === ">") {
|
|
7634
|
+
cursor.next();
|
|
7635
|
+
cursor.skipSpaces();
|
|
7636
|
+
}
|
|
7637
|
+
const delimiters = [];
|
|
7638
|
+
let pipe = consumePipe();
|
|
7639
|
+
while (!cursor.finished()) {
|
|
7640
|
+
const delimiterStart = cursor.currIndex();
|
|
7641
|
+
cursor.skipUntilEnd((c) => c === "|" || isSpaceOrTab(c) || c === "\n" || c === "\r");
|
|
7642
|
+
const delimiterRange = [delimiterStart, cursor.currIndex()];
|
|
7643
|
+
const delimiterText = text.slice(...delimiterRange);
|
|
7644
|
+
if (!/^:?-+:?$/u.test(delimiterText)) return null;
|
|
7645
|
+
if (delimiters.length > 0 && pipe == null) return null;
|
|
7646
|
+
delimiters.push({
|
|
7647
|
+
leadingPipe: pipe,
|
|
7648
|
+
delimiter: {
|
|
7649
|
+
text: delimiterText,
|
|
7650
|
+
range: delimiterRange
|
|
7651
|
+
}
|
|
7652
|
+
});
|
|
7653
|
+
pipe = consumePipe();
|
|
7654
|
+
}
|
|
7655
|
+
return {
|
|
7656
|
+
delimiters,
|
|
7657
|
+
trailingPipe: pipe
|
|
7658
|
+
};
|
|
7659
|
+
/**
|
|
7660
|
+
* Consume a pipe if exists.
|
|
7661
|
+
*/
|
|
7662
|
+
function consumePipe() {
|
|
7663
|
+
cursor.skipSpaces();
|
|
7664
|
+
if (cursor.curr() === "|") {
|
|
7665
|
+
const pipeStart = cursor.currIndex();
|
|
7666
|
+
cursor.next();
|
|
7667
|
+
const pipeRange = [pipeStart, cursor.currIndex()];
|
|
7668
|
+
const result = {
|
|
7669
|
+
text: text.slice(...pipeRange),
|
|
7670
|
+
range: pipeRange
|
|
7671
|
+
};
|
|
7672
|
+
cursor.skipSpaces();
|
|
7673
|
+
return result;
|
|
7674
|
+
}
|
|
7675
|
+
return null;
|
|
7676
|
+
}
|
|
7677
|
+
}
|
|
7678
|
+
|
|
7233
7679
|
//#endregion
|
|
7234
7680
|
//#region src/rules/no-multi-spaces.ts
|
|
7235
7681
|
var no_multi_spaces_default = createRule("no-multi-spaces", {
|
|
@@ -7238,7 +7684,7 @@ var no_multi_spaces_default = createRule("no-multi-spaces", {
|
|
|
7238
7684
|
docs: {
|
|
7239
7685
|
description: "disallow multiple spaces",
|
|
7240
7686
|
categories: ["standard"],
|
|
7241
|
-
listCategory: "
|
|
7687
|
+
listCategory: "Whitespace"
|
|
7242
7688
|
},
|
|
7243
7689
|
fixable: "whitespace",
|
|
7244
7690
|
hasSuggestions: false,
|
|
@@ -7258,7 +7704,8 @@ var no_multi_spaces_default = createRule("no-multi-spaces", {
|
|
|
7258
7704
|
linkReference: verifyLinkReference,
|
|
7259
7705
|
listItem: verifyListItem,
|
|
7260
7706
|
blockquote: processBlockquote,
|
|
7261
|
-
text: verifyText
|
|
7707
|
+
text: verifyText,
|
|
7708
|
+
table: verifyTable
|
|
7262
7709
|
};
|
|
7263
7710
|
/**
|
|
7264
7711
|
* Verify a text node.
|
|
@@ -7267,6 +7714,14 @@ var no_multi_spaces_default = createRule("no-multi-spaces", {
|
|
|
7267
7714
|
verifyTextInNode(node);
|
|
7268
7715
|
}
|
|
7269
7716
|
/**
|
|
7717
|
+
* Verify a table node.
|
|
7718
|
+
*/
|
|
7719
|
+
function verifyTable(node) {
|
|
7720
|
+
const parsedDelimiterRow = parseTableDelimiterRow(sourceCode, node);
|
|
7721
|
+
if (!parsedDelimiterRow) return;
|
|
7722
|
+
verifyTextInRange(node, parsedDelimiterRow.range);
|
|
7723
|
+
}
|
|
7724
|
+
/**
|
|
7270
7725
|
* Verify a definition node.
|
|
7271
7726
|
*/
|
|
7272
7727
|
function verifyLinkDefinition(node) {
|
|
@@ -7442,7 +7897,7 @@ var no_multiple_empty_lines_default = createRule("no-multiple-empty-lines", {
|
|
|
7442
7897
|
docs: {
|
|
7443
7898
|
description: "disallow multiple empty lines in Markdown files.",
|
|
7444
7899
|
categories: ["standard"],
|
|
7445
|
-
listCategory: "
|
|
7900
|
+
listCategory: "Whitespace"
|
|
7446
7901
|
},
|
|
7447
7902
|
fixable: "whitespace",
|
|
7448
7903
|
hasSuggestions: false,
|
|
@@ -7601,7 +8056,7 @@ var no_text_backslash_linebreak_default = createRule("no-text-backslash-linebrea
|
|
|
7601
8056
|
docs: {
|
|
7602
8057
|
description: "disallow text backslash at the end of a line.",
|
|
7603
8058
|
categories: ["recommended", "standard"],
|
|
7604
|
-
listCategory: "
|
|
8059
|
+
listCategory: "Notation"
|
|
7605
8060
|
},
|
|
7606
8061
|
fixable: void 0,
|
|
7607
8062
|
hasSuggestions: true,
|
|
@@ -7646,7 +8101,7 @@ var no_trailing_spaces_default = createRule("no-trailing-spaces", {
|
|
|
7646
8101
|
docs: {
|
|
7647
8102
|
description: "disallow trailing whitespace at the end of lines in Markdown files.",
|
|
7648
8103
|
categories: ["standard"],
|
|
7649
|
-
listCategory: "
|
|
8104
|
+
listCategory: "Whitespace"
|
|
7650
8105
|
},
|
|
7651
8106
|
fixable: "whitespace",
|
|
7652
8107
|
hasSuggestions: false,
|
|
@@ -7772,7 +8227,7 @@ var ordered_list_marker_sequence_default = createRule("ordered-list-marker-seque
|
|
|
7772
8227
|
docs: {
|
|
7773
8228
|
description: "enforce that ordered list markers use sequential numbers",
|
|
7774
8229
|
categories: ["standard"],
|
|
7775
|
-
listCategory: "
|
|
8230
|
+
listCategory: "Decorative"
|
|
7776
8231
|
},
|
|
7777
8232
|
fixable: "code",
|
|
7778
8233
|
hasSuggestions: true,
|
|
@@ -7986,7 +8441,7 @@ function markerToKind(marker) {
|
|
|
7986
8441
|
/**
|
|
7987
8442
|
* Parse rule options.
|
|
7988
8443
|
*/
|
|
7989
|
-
function parseOptions(options) {
|
|
8444
|
+
function parseOptions$1(options) {
|
|
7990
8445
|
const prefer = markerToKind(options.prefer) || ".";
|
|
7991
8446
|
const overrides = (options.overrides ?? []).map((override) => {
|
|
7992
8447
|
const preferForOverride = markerToKind(override.prefer) || ".";
|
|
@@ -8013,7 +8468,7 @@ var ordered_list_marker_style_default = createRule("ordered-list-marker-style",
|
|
|
8013
8468
|
docs: {
|
|
8014
8469
|
description: "enforce consistent ordered list marker style",
|
|
8015
8470
|
categories: ["standard"],
|
|
8016
|
-
listCategory: "
|
|
8471
|
+
listCategory: "Notation"
|
|
8017
8472
|
},
|
|
8018
8473
|
fixable: "code",
|
|
8019
8474
|
hasSuggestions: false,
|
|
@@ -8047,7 +8502,7 @@ var ordered_list_marker_style_default = createRule("ordered-list-marker-style",
|
|
|
8047
8502
|
},
|
|
8048
8503
|
create(context) {
|
|
8049
8504
|
const sourceCode = context.sourceCode;
|
|
8050
|
-
const options = parseOptions(context.options[0] || {});
|
|
8505
|
+
const options = parseOptions$1(context.options[0] || {});
|
|
8051
8506
|
let containerStack = {
|
|
8052
8507
|
node: sourceCode.ast,
|
|
8053
8508
|
level: 1,
|
|
@@ -8232,7 +8687,7 @@ var padding_line_between_blocks_default = createRule("padding-line-between-block
|
|
|
8232
8687
|
docs: {
|
|
8233
8688
|
description: "require or disallow padding lines between blocks",
|
|
8234
8689
|
categories: ["standard"],
|
|
8235
|
-
listCategory: "
|
|
8690
|
+
listCategory: "Whitespace"
|
|
8236
8691
|
},
|
|
8237
8692
|
fixable: "whitespace",
|
|
8238
8693
|
hasSuggestions: false,
|
|
@@ -8430,7 +8885,7 @@ var prefer_autolinks_default = createRule("prefer-autolinks", {
|
|
|
8430
8885
|
docs: {
|
|
8431
8886
|
description: "enforce the use of autolinks for URLs",
|
|
8432
8887
|
categories: ["recommended", "standard"],
|
|
8433
|
-
listCategory: "
|
|
8888
|
+
listCategory: "Notation"
|
|
8434
8889
|
},
|
|
8435
8890
|
fixable: "code",
|
|
8436
8891
|
hasSuggestions: false,
|
|
@@ -8468,7 +8923,7 @@ var prefer_fenced_code_blocks_default = createRule("prefer-fenced-code-blocks",
|
|
|
8468
8923
|
docs: {
|
|
8469
8924
|
description: "enforce the use of fenced code blocks over indented code blocks",
|
|
8470
8925
|
categories: ["recommended", "standard"],
|
|
8471
|
-
listCategory: "
|
|
8926
|
+
listCategory: "Notation"
|
|
8472
8927
|
},
|
|
8473
8928
|
fixable: "code",
|
|
8474
8929
|
hasSuggestions: false,
|
|
@@ -8698,7 +9153,7 @@ var prefer_link_reference_definitions_default = createRule("prefer-link-referenc
|
|
|
8698
9153
|
docs: {
|
|
8699
9154
|
description: "enforce using link reference definitions instead of inline links",
|
|
8700
9155
|
categories: [],
|
|
8701
|
-
listCategory: "
|
|
9156
|
+
listCategory: "Notation"
|
|
8702
9157
|
},
|
|
8703
9158
|
fixable: "code",
|
|
8704
9159
|
hasSuggestions: false,
|
|
@@ -8977,9 +9432,9 @@ var setext_heading_underline_length_default = createRule("setext-heading-underli
|
|
|
8977
9432
|
docs: {
|
|
8978
9433
|
description: "enforce setext heading underline length",
|
|
8979
9434
|
categories: ["standard"],
|
|
8980
|
-
listCategory: "
|
|
9435
|
+
listCategory: "Decorative"
|
|
8981
9436
|
},
|
|
8982
|
-
fixable: "
|
|
9437
|
+
fixable: "code",
|
|
8983
9438
|
schema: [{
|
|
8984
9439
|
type: "object",
|
|
8985
9440
|
properties: {
|
|
@@ -9215,7 +9670,7 @@ var sort_definitions_default = createRule("sort-definitions", {
|
|
|
9215
9670
|
docs: {
|
|
9216
9671
|
description: "enforce a specific order for link definitions and footnote definitions",
|
|
9217
9672
|
categories: ["standard"],
|
|
9218
|
-
listCategory: "
|
|
9673
|
+
listCategory: "Decorative"
|
|
9219
9674
|
},
|
|
9220
9675
|
fixable: "code",
|
|
9221
9676
|
hasSuggestions: false,
|
|
@@ -9488,7 +9943,7 @@ var strikethrough_delimiters_style_default = createRule("strikethrough-delimiter
|
|
|
9488
9943
|
docs: {
|
|
9489
9944
|
description: "enforce a consistent delimiter style for strikethrough",
|
|
9490
9945
|
categories: ["standard"],
|
|
9491
|
-
listCategory: "
|
|
9946
|
+
listCategory: "Notation"
|
|
9492
9947
|
},
|
|
9493
9948
|
fixable: "code",
|
|
9494
9949
|
hasSuggestions: false,
|
|
@@ -9655,6 +10110,759 @@ var table_header_casing_default = createRule("table-header-casing", {
|
|
|
9655
10110
|
}
|
|
9656
10111
|
});
|
|
9657
10112
|
|
|
10113
|
+
//#endregion
|
|
10114
|
+
//#region src/rules/table-leading-trailing-pipes.ts
|
|
10115
|
+
var table_leading_trailing_pipes_default = createRule("table-leading-trailing-pipes", {
|
|
10116
|
+
meta: {
|
|
10117
|
+
type: "layout",
|
|
10118
|
+
docs: {
|
|
10119
|
+
description: "enforce consistent use of leading and trailing pipes in tables.",
|
|
10120
|
+
categories: ["standard"],
|
|
10121
|
+
listCategory: "Decorative"
|
|
10122
|
+
},
|
|
10123
|
+
fixable: "code",
|
|
10124
|
+
hasSuggestions: false,
|
|
10125
|
+
schema: [{ anyOf: [{ enum: ["always", "never"] }, {
|
|
10126
|
+
type: "object",
|
|
10127
|
+
properties: {
|
|
10128
|
+
leading: { enum: ["always", "never"] },
|
|
10129
|
+
trailing: { enum: ["always", "never"] }
|
|
10130
|
+
},
|
|
10131
|
+
additionalProperties: false
|
|
10132
|
+
}] }],
|
|
10133
|
+
messages: {
|
|
10134
|
+
missingLeadingPipe: "Table line should start with a leading pipe.",
|
|
10135
|
+
unexpectedLeadingPipe: "Table line should not start with a leading pipe.",
|
|
10136
|
+
missingTrailingPipe: "Table line should end with a trailing pipe.",
|
|
10137
|
+
unexpectedTrailingPipe: "Table line should not end with a trailing pipe."
|
|
10138
|
+
}
|
|
10139
|
+
},
|
|
10140
|
+
create(context) {
|
|
10141
|
+
const sourceCode = context.sourceCode;
|
|
10142
|
+
const preferOption = context.options[0] ?? "always";
|
|
10143
|
+
const leadingOption = typeof preferOption === "string" ? preferOption : preferOption.leading ?? "always";
|
|
10144
|
+
const trailingOption = typeof preferOption === "string" ? preferOption : preferOption.trailing ?? "always";
|
|
10145
|
+
/**
|
|
10146
|
+
* Verify the table pipes
|
|
10147
|
+
*/
|
|
10148
|
+
function verifyTablePipes(node) {
|
|
10149
|
+
for (const row of node.children) verifyTableRowPipes(row);
|
|
10150
|
+
const parsedDelimiterRow = parseTableDelimiterRow(sourceCode, node);
|
|
10151
|
+
if (parsedDelimiterRow) verifyTableLinePipes(parsedDelimiterRow.range, parsedDelimiterRow.loc, parsedDelimiterRow.delimiters.length);
|
|
10152
|
+
}
|
|
10153
|
+
/**
|
|
10154
|
+
* Verify the table row pipes
|
|
10155
|
+
*/
|
|
10156
|
+
function verifyTableRowPipes(node) {
|
|
10157
|
+
const loc = sourceCode.getLoc(node);
|
|
10158
|
+
const range = sourceCode.getRange(node);
|
|
10159
|
+
verifyTableLinePipes(range, loc, node.children.length);
|
|
10160
|
+
}
|
|
10161
|
+
/**
|
|
10162
|
+
* Verify the table line pipes
|
|
10163
|
+
*/
|
|
10164
|
+
function verifyTableLinePipes(lineContentRange, lineLocation, columnCount) {
|
|
10165
|
+
verifyTableLeadingPipe(lineContentRange, lineLocation, columnCount);
|
|
10166
|
+
verifyTableTrailingPipe(lineContentRange, lineLocation, columnCount);
|
|
10167
|
+
}
|
|
10168
|
+
/**
|
|
10169
|
+
* Verify the table leading pipe
|
|
10170
|
+
*/
|
|
10171
|
+
function verifyTableLeadingPipe(lineContentRange, lineLocation, columnCount) {
|
|
10172
|
+
if (leadingOption === "always") {
|
|
10173
|
+
if (sourceCode.text.startsWith("|", lineContentRange[0])) return;
|
|
10174
|
+
context.report({
|
|
10175
|
+
messageId: "missingLeadingPipe",
|
|
10176
|
+
loc: lineLocation.start,
|
|
10177
|
+
fix(fixer) {
|
|
10178
|
+
return fixer.insertTextBeforeRange(lineContentRange, "| ");
|
|
10179
|
+
}
|
|
10180
|
+
});
|
|
10181
|
+
} else if (leadingOption === "never") {
|
|
10182
|
+
if (columnCount < 2) {
|
|
10183
|
+
if (!(trailingOption === "always" && sourceCode.text.endsWith("|", lineContentRange[1]))) return;
|
|
10184
|
+
}
|
|
10185
|
+
if (!sourceCode.text.startsWith("|", lineContentRange[0])) return;
|
|
10186
|
+
let endIndex = lineContentRange[0] + 1;
|
|
10187
|
+
while (endIndex < lineContentRange[1] && isSpaceOrTab(sourceCode.text[endIndex])) endIndex++;
|
|
10188
|
+
context.report({
|
|
10189
|
+
messageId: "unexpectedLeadingPipe",
|
|
10190
|
+
loc: {
|
|
10191
|
+
start: lineLocation.start,
|
|
10192
|
+
end: {
|
|
10193
|
+
line: lineLocation.start.line,
|
|
10194
|
+
column: lineLocation.start.column + (endIndex - lineContentRange[0])
|
|
10195
|
+
}
|
|
10196
|
+
},
|
|
10197
|
+
fix(fixer) {
|
|
10198
|
+
return fixer.removeRange([lineContentRange[0], endIndex]);
|
|
10199
|
+
}
|
|
10200
|
+
});
|
|
10201
|
+
}
|
|
10202
|
+
}
|
|
10203
|
+
/**
|
|
10204
|
+
* Verify the table trailing pipe
|
|
10205
|
+
*/
|
|
10206
|
+
function verifyTableTrailingPipe(lineContentRange, lineLocation, columnCount) {
|
|
10207
|
+
if (trailingOption === "always") {
|
|
10208
|
+
if (sourceCode.text.endsWith("|", lineContentRange[1])) return;
|
|
10209
|
+
context.report({
|
|
10210
|
+
messageId: "missingTrailingPipe",
|
|
10211
|
+
loc: lineLocation.end,
|
|
10212
|
+
fix(fixer) {
|
|
10213
|
+
return fixer.insertTextAfterRange(lineContentRange, " |");
|
|
10214
|
+
}
|
|
10215
|
+
});
|
|
10216
|
+
} else if (trailingOption === "never") {
|
|
10217
|
+
if (columnCount < 2) {
|
|
10218
|
+
if (!(leadingOption === "always" && sourceCode.text.startsWith("|", lineContentRange[0]))) return;
|
|
10219
|
+
}
|
|
10220
|
+
if (!sourceCode.text.endsWith("|", lineContentRange[1])) return;
|
|
10221
|
+
let startIndex = lineContentRange[1] - 1;
|
|
10222
|
+
while (startIndex - 1 > lineContentRange[0] && isSpaceOrTab(sourceCode.text[startIndex - 1])) startIndex--;
|
|
10223
|
+
context.report({
|
|
10224
|
+
messageId: "unexpectedTrailingPipe",
|
|
10225
|
+
loc: {
|
|
10226
|
+
start: {
|
|
10227
|
+
line: lineLocation.end.line,
|
|
10228
|
+
column: lineLocation.end.column - (lineContentRange[1] - startIndex)
|
|
10229
|
+
},
|
|
10230
|
+
end: lineLocation.end
|
|
10231
|
+
},
|
|
10232
|
+
fix(fixer) {
|
|
10233
|
+
return fixer.removeRange([startIndex, lineContentRange[1]]);
|
|
10234
|
+
}
|
|
10235
|
+
});
|
|
10236
|
+
}
|
|
10237
|
+
}
|
|
10238
|
+
return { table(node) {
|
|
10239
|
+
verifyTablePipes(node);
|
|
10240
|
+
} };
|
|
10241
|
+
}
|
|
10242
|
+
});
|
|
10243
|
+
|
|
10244
|
+
//#endregion
|
|
10245
|
+
//#region src/rules/table-pipe-alignment.ts
|
|
10246
|
+
var table_pipe_alignment_default = createRule("table-pipe-alignment", {
|
|
10247
|
+
meta: {
|
|
10248
|
+
type: "layout",
|
|
10249
|
+
docs: {
|
|
10250
|
+
description: "enforce consistent alignment of table pipes",
|
|
10251
|
+
categories: ["standard"],
|
|
10252
|
+
listCategory: "Decorative"
|
|
10253
|
+
},
|
|
10254
|
+
fixable: "code",
|
|
10255
|
+
hasSuggestions: false,
|
|
10256
|
+
schema: [{
|
|
10257
|
+
type: "object",
|
|
10258
|
+
properties: { column: { enum: ["minimum", "consistent"] } },
|
|
10259
|
+
additionalProperties: false
|
|
10260
|
+
}],
|
|
10261
|
+
messages: {
|
|
10262
|
+
addSpaces: "Table pipe should be aligned at column {{expected}} (add {{count}} character{{plural}}).",
|
|
10263
|
+
removeSpaces: "Table pipe should be aligned at column {{expected}} (remove {{count}} character{{plural}})."
|
|
10264
|
+
}
|
|
10265
|
+
},
|
|
10266
|
+
create(context) {
|
|
10267
|
+
const sourceCode = context.sourceCode;
|
|
10268
|
+
const columnOption = (context.options[0] || {}).column || "minimum";
|
|
10269
|
+
class TableContext {
|
|
10270
|
+
rows;
|
|
10271
|
+
columnCount;
|
|
10272
|
+
_cacheHasSpaceBetweenContentAndTrailingPipe = /* @__PURE__ */ new Map();
|
|
10273
|
+
_cacheExpectedPipePosition = /* @__PURE__ */ new Map();
|
|
10274
|
+
constructor(parsed) {
|
|
10275
|
+
const rows = [parsedTableRowToRowData(parsed.headerRow), parsedTableDelimiterRowToRowData(parsed.delimiterRow)];
|
|
10276
|
+
for (const bodyRow of parsed.bodyRows) rows.push(parsedTableRowToRowData(bodyRow));
|
|
10277
|
+
this.rows = rows;
|
|
10278
|
+
let columnCount = 0;
|
|
10279
|
+
for (const row of rows) columnCount = Math.max(columnCount, row.cells.length);
|
|
10280
|
+
this.columnCount = columnCount;
|
|
10281
|
+
}
|
|
10282
|
+
/**
|
|
10283
|
+
* Get the expected pipe position for the index
|
|
10284
|
+
*/
|
|
10285
|
+
getExpectedPipePosition(pipeIndex) {
|
|
10286
|
+
let v = this._cacheExpectedPipePosition.get(pipeIndex);
|
|
10287
|
+
if (v !== void 0) return v;
|
|
10288
|
+
v = this._computeExpectedPipePositionWithoutCache(pipeIndex);
|
|
10289
|
+
this._cacheExpectedPipePosition.set(pipeIndex, v);
|
|
10290
|
+
return v;
|
|
10291
|
+
}
|
|
10292
|
+
/**
|
|
10293
|
+
* Check if there is at least one space between content and trailing pipe
|
|
10294
|
+
* for the index
|
|
10295
|
+
*
|
|
10296
|
+
* This is used to determine if the pipe should be aligned with a space before it.
|
|
10297
|
+
*/
|
|
10298
|
+
hasSpaceBetweenContentAndTrailingPipe(pipeIndex) {
|
|
10299
|
+
if (pipeIndex === 0) return false;
|
|
10300
|
+
let v = this._cacheHasSpaceBetweenContentAndTrailingPipe.get(pipeIndex);
|
|
10301
|
+
if (v != null) return v;
|
|
10302
|
+
v = this._hasSpaceBetweenContentAndTrailingPipeWithoutCache(pipeIndex);
|
|
10303
|
+
this._cacheHasSpaceBetweenContentAndTrailingPipe.set(pipeIndex, v);
|
|
10304
|
+
return v;
|
|
10305
|
+
}
|
|
10306
|
+
/**
|
|
10307
|
+
* Get the expected pipe position for the index
|
|
10308
|
+
*/
|
|
10309
|
+
_computeExpectedPipePositionWithoutCache(pipeIndex) {
|
|
10310
|
+
if (pipeIndex === 0) {
|
|
10311
|
+
const firstCell = this.rows[0].cells[0];
|
|
10312
|
+
const firstToken = firstCell.leadingPipe ?? firstCell.content;
|
|
10313
|
+
if (!firstToken) return null;
|
|
10314
|
+
return getTextWidth(sourceCode.lines[firstToken.loc.start.line - 1].slice(0, firstToken.loc.start.column - 1));
|
|
10315
|
+
}
|
|
10316
|
+
if (columnOption === "minimum") return this.getMinimumPipePosition(pipeIndex);
|
|
10317
|
+
else if (columnOption === "consistent") {
|
|
10318
|
+
const columnIndex = pipeIndex - 1;
|
|
10319
|
+
for (const row of this.rows) {
|
|
10320
|
+
if (row.cells.length <= columnIndex) continue;
|
|
10321
|
+
const cell = row.cells[columnIndex];
|
|
10322
|
+
if (cell.type === "delimiter" || !cell.trailingPipe) continue;
|
|
10323
|
+
const width = getTextWidth(sourceCode.lines[cell.trailingPipe.loc.start.line - 1].slice(0, cell.trailingPipe.loc.start.column - 1));
|
|
10324
|
+
return Math.max(width, this.getMinimumPipePosition(pipeIndex) || 0);
|
|
10325
|
+
}
|
|
10326
|
+
}
|
|
10327
|
+
return null;
|
|
10328
|
+
}
|
|
10329
|
+
/**
|
|
10330
|
+
* Get the minimum pipe position for the index
|
|
10331
|
+
*/
|
|
10332
|
+
getMinimumPipePosition(pipeIndex) {
|
|
10333
|
+
const needSpaceBeforePipe = this.hasSpaceBetweenContentAndTrailingPipe(pipeIndex);
|
|
10334
|
+
let maxWidth = 0;
|
|
10335
|
+
const columnIndex = pipeIndex - 1;
|
|
10336
|
+
for (const row of this.rows) {
|
|
10337
|
+
if (row.cells.length <= columnIndex) continue;
|
|
10338
|
+
const cell = row.cells[columnIndex];
|
|
10339
|
+
let width;
|
|
10340
|
+
if (cell.type === "delimiter") {
|
|
10341
|
+
const minimumDelimiterLength = getMinimumDelimiterLength(cell.align);
|
|
10342
|
+
width = getTextWidth(sourceCode.lines[cell.delimiter.loc.start.line - 1].slice(0, cell.delimiter.loc.start.column - 1)) + minimumDelimiterLength;
|
|
10343
|
+
} else {
|
|
10344
|
+
if (!cell.content) continue;
|
|
10345
|
+
width = getTextWidth(sourceCode.lines[cell.content.loc.end.line - 1].slice(0, cell.content.loc.end.column - 1));
|
|
10346
|
+
}
|
|
10347
|
+
if (needSpaceBeforePipe) width += 1;
|
|
10348
|
+
maxWidth = Math.max(maxWidth, width);
|
|
10349
|
+
}
|
|
10350
|
+
return maxWidth;
|
|
10351
|
+
}
|
|
10352
|
+
/**
|
|
10353
|
+
* Check if there is at least one space between content and trailing pipe
|
|
10354
|
+
*/
|
|
10355
|
+
_hasSpaceBetweenContentAndTrailingPipeWithoutCache(pipeIndex) {
|
|
10356
|
+
const columnIndex = pipeIndex - 1;
|
|
10357
|
+
for (const row of this.rows) {
|
|
10358
|
+
if (row.cells.length <= columnIndex) continue;
|
|
10359
|
+
const cell = row.cells[columnIndex];
|
|
10360
|
+
if (!cell.trailingPipe) continue;
|
|
10361
|
+
let content;
|
|
10362
|
+
if (cell.type === "delimiter") content = cell.delimiter;
|
|
10363
|
+
else {
|
|
10364
|
+
if (!cell.content) continue;
|
|
10365
|
+
content = cell.content;
|
|
10366
|
+
}
|
|
10367
|
+
if (content.range[1] < cell.trailingPipe.range[0]) continue;
|
|
10368
|
+
return false;
|
|
10369
|
+
}
|
|
10370
|
+
return true;
|
|
10371
|
+
}
|
|
10372
|
+
}
|
|
10373
|
+
/**
|
|
10374
|
+
* Verify the table pipes
|
|
10375
|
+
*/
|
|
10376
|
+
function verifyTablePipes(table) {
|
|
10377
|
+
const targetRows = [...table.rows];
|
|
10378
|
+
for (const row of targetRows) for (let pipeIndex = 0; pipeIndex <= table.columnCount; pipeIndex++) if (!verifyRowPipe(row, pipeIndex, table)) break;
|
|
10379
|
+
}
|
|
10380
|
+
/**
|
|
10381
|
+
* Verify the pipe in the row
|
|
10382
|
+
*/
|
|
10383
|
+
function verifyRowPipe(row, pipeIndex, table) {
|
|
10384
|
+
let cellIndex;
|
|
10385
|
+
let pipe;
|
|
10386
|
+
if (pipeIndex === 0) {
|
|
10387
|
+
cellIndex = 0;
|
|
10388
|
+
pipe = "leadingPipe";
|
|
10389
|
+
} else {
|
|
10390
|
+
cellIndex = pipeIndex - 1;
|
|
10391
|
+
pipe = "trailingPipe";
|
|
10392
|
+
}
|
|
10393
|
+
if (row.cells.length <= cellIndex) return true;
|
|
10394
|
+
const cell = row.cells[cellIndex];
|
|
10395
|
+
const pipeToken = cell[pipe];
|
|
10396
|
+
if (!pipeToken) return true;
|
|
10397
|
+
return verifyPipe(pipeToken, pipeIndex, table, cell);
|
|
10398
|
+
}
|
|
10399
|
+
/**
|
|
10400
|
+
* Verify the pipe position
|
|
10401
|
+
*/
|
|
10402
|
+
function verifyPipe(pipe, pipeIndex, table, cell) {
|
|
10403
|
+
const expected = table.getExpectedPipePosition(pipeIndex);
|
|
10404
|
+
if (expected == null) return true;
|
|
10405
|
+
const actual = getTextWidth(sourceCode.lines[pipe.loc.start.line - 1].slice(0, pipe.loc.start.column - 1));
|
|
10406
|
+
const diff = expected - actual;
|
|
10407
|
+
if (diff === 0) return true;
|
|
10408
|
+
context.report({
|
|
10409
|
+
loc: pipe.loc,
|
|
10410
|
+
messageId: diff > 0 ? "addSpaces" : "removeSpaces",
|
|
10411
|
+
data: {
|
|
10412
|
+
expected: String(expected),
|
|
10413
|
+
count: String(Math.abs(diff)),
|
|
10414
|
+
plural: Math.abs(diff) === 1 ? "" : "s"
|
|
10415
|
+
},
|
|
10416
|
+
fix(fixer) {
|
|
10417
|
+
if (diff > 0) {
|
|
10418
|
+
if (pipeIndex === 0 || cell.type === "cell") return fixer.insertTextBeforeRange(pipe.range, " ".repeat(diff));
|
|
10419
|
+
return fixer.insertTextAfterRange([cell.delimiter.range[0], cell.delimiter.range[0] + 1], "-".repeat(diff));
|
|
10420
|
+
}
|
|
10421
|
+
const baseEdit = fixRemoveSpaces();
|
|
10422
|
+
if (baseEdit) return baseEdit;
|
|
10423
|
+
if (pipeIndex === 0 || cell.type === "cell") return null;
|
|
10424
|
+
const beforeDelimiter = sourceCode.lines[cell.delimiter.loc.start.line - 1].slice(0, cell.delimiter.loc.start.column - 1);
|
|
10425
|
+
const widthBeforeDelimiter = getTextWidth(beforeDelimiter);
|
|
10426
|
+
const newLength = expected - widthBeforeDelimiter;
|
|
10427
|
+
const minimumDelimiterLength = getMinimumDelimiterLength(cell.align);
|
|
10428
|
+
const spaceAfter = table.hasSpaceBetweenContentAndTrailingPipe(pipeIndex) ? " " : "";
|
|
10429
|
+
if (newLength < minimumDelimiterLength + spaceAfter.length) return null;
|
|
10430
|
+
const delimiterPrefix = cell.align === "left" || cell.align === "center" ? ":" : "";
|
|
10431
|
+
const delimiterSuffix = (cell.align === "right" || cell.align === "center" ? ":" : "") + spaceAfter;
|
|
10432
|
+
const newDelimiter = "-".repeat(newLength - delimiterPrefix.length - delimiterSuffix.length);
|
|
10433
|
+
return fixer.replaceTextRange([cell.delimiter.range[0], pipe.range[0]], delimiterPrefix + newDelimiter + delimiterSuffix);
|
|
10434
|
+
/**
|
|
10435
|
+
* Fixer to remove spaces before the pipe
|
|
10436
|
+
*/
|
|
10437
|
+
function fixRemoveSpaces() {
|
|
10438
|
+
const beforePipe = sourceCode.lines[pipe.loc.start.line - 1].slice(0, pipe.loc.start.column - 1);
|
|
10439
|
+
const trimmedBeforePipe = beforePipe.trimEnd();
|
|
10440
|
+
const spacesBeforePipeLength = beforePipe.length - trimmedBeforePipe.length;
|
|
10441
|
+
const widthBeforePipe = getTextWidth(trimmedBeforePipe);
|
|
10442
|
+
const newSpacesLength = expected - widthBeforePipe;
|
|
10443
|
+
if (newSpacesLength < (table.hasSpaceBetweenContentAndTrailingPipe(pipeIndex) ? 1 : 0)) return null;
|
|
10444
|
+
return fixer.replaceTextRange([pipe.range[0] - spacesBeforePipeLength, pipe.range[0]], " ".repeat(newSpacesLength));
|
|
10445
|
+
}
|
|
10446
|
+
}
|
|
10447
|
+
});
|
|
10448
|
+
return false;
|
|
10449
|
+
}
|
|
10450
|
+
/**
|
|
10451
|
+
* Get the minimum delimiter length based on alignment
|
|
10452
|
+
*/
|
|
10453
|
+
function getMinimumDelimiterLength(align) {
|
|
10454
|
+
return align === "none" ? 1 : align === "center" ? 3 : 2;
|
|
10455
|
+
}
|
|
10456
|
+
return { table(node) {
|
|
10457
|
+
const parsed = parseTable(sourceCode, node);
|
|
10458
|
+
if (!parsed) return;
|
|
10459
|
+
verifyTablePipes(new TableContext(parsed));
|
|
10460
|
+
} };
|
|
10461
|
+
}
|
|
10462
|
+
});
|
|
10463
|
+
/**
|
|
10464
|
+
* Convert a parsed table row to row data
|
|
10465
|
+
*/
|
|
10466
|
+
function parsedTableRowToRowData(parsedRow) {
|
|
10467
|
+
return { cells: parsedRow.cells.map((cell, index) => {
|
|
10468
|
+
const nextCell = index + 1 < parsedRow.cells.length ? parsedRow.cells[index + 1] : null;
|
|
10469
|
+
return {
|
|
10470
|
+
type: "cell",
|
|
10471
|
+
leadingPipe: cell.leadingPipe,
|
|
10472
|
+
content: cell.cell,
|
|
10473
|
+
trailingPipe: nextCell ? nextCell.leadingPipe : parsedRow.trailingPipe
|
|
10474
|
+
};
|
|
10475
|
+
}) };
|
|
10476
|
+
}
|
|
10477
|
+
/**
|
|
10478
|
+
* Convert a parsed table delimiter row to row data
|
|
10479
|
+
*/
|
|
10480
|
+
function parsedTableDelimiterRowToRowData(parsedDelimiterRow) {
|
|
10481
|
+
return { cells: parsedDelimiterRow.delimiters.map((cell, index) => {
|
|
10482
|
+
const nextCell = index + 1 < parsedDelimiterRow.delimiters.length ? parsedDelimiterRow.delimiters[index + 1] : null;
|
|
10483
|
+
return {
|
|
10484
|
+
type: "delimiter",
|
|
10485
|
+
leadingPipe: cell.leadingPipe,
|
|
10486
|
+
delimiter: cell.delimiter,
|
|
10487
|
+
align: cell.delimiter.align,
|
|
10488
|
+
trailingPipe: nextCell ? nextCell.leadingPipe : parsedDelimiterRow.trailingPipe
|
|
10489
|
+
};
|
|
10490
|
+
}) };
|
|
10491
|
+
}
|
|
10492
|
+
|
|
10493
|
+
//#endregion
|
|
10494
|
+
//#region src/rules/table-pipe-spacing.ts
|
|
10495
|
+
/**
|
|
10496
|
+
* Parsed options
|
|
10497
|
+
*/
|
|
10498
|
+
function parseOptions(options) {
|
|
10499
|
+
const spaceOption = options?.space;
|
|
10500
|
+
const leadingSpace = (typeof spaceOption === "object" ? spaceOption.leading : spaceOption) || "always";
|
|
10501
|
+
const trailingSpace = (typeof spaceOption === "object" ? spaceOption.trailing : spaceOption) || "always";
|
|
10502
|
+
const cellAlignOption = options?.cellAlign;
|
|
10503
|
+
const defaultDelimiterCellAlign = (typeof cellAlignOption === "object" ? cellAlignOption.defaultDelimiter : cellAlignOption) || "left";
|
|
10504
|
+
const leftAlignmentDelimiterCellAlign = (typeof cellAlignOption === "object" ? cellAlignOption.leftAlignmentDelimiter : cellAlignOption) || "left";
|
|
10505
|
+
const centerAlignmentDelimiterCellAlign = (typeof cellAlignOption === "object" ? cellAlignOption.centerAlignmentDelimiter : cellAlignOption) || "center";
|
|
10506
|
+
const rightAlignmentDelimiterCellAlign = (typeof cellAlignOption === "object" ? cellAlignOption.rightAlignmentDelimiter : cellAlignOption) || "right";
|
|
10507
|
+
return {
|
|
10508
|
+
leadingSpace,
|
|
10509
|
+
trailingSpace,
|
|
10510
|
+
cellAlignByDelimiter: {
|
|
10511
|
+
none: adjustAlign(defaultDelimiterCellAlign),
|
|
10512
|
+
left: adjustAlign(leftAlignmentDelimiterCellAlign),
|
|
10513
|
+
center: adjustAlign(centerAlignmentDelimiterCellAlign),
|
|
10514
|
+
right: adjustAlign(rightAlignmentDelimiterCellAlign)
|
|
10515
|
+
}
|
|
10516
|
+
};
|
|
10517
|
+
/**
|
|
10518
|
+
* Adjust the alignment option based on the spacing options.
|
|
10519
|
+
*/
|
|
10520
|
+
function adjustAlign(align) {
|
|
10521
|
+
if (align === "left") {
|
|
10522
|
+
if (trailingSpace === "always") return "left";
|
|
10523
|
+
return "ignore";
|
|
10524
|
+
}
|
|
10525
|
+
if (align === "center") {
|
|
10526
|
+
if (leadingSpace === "always" && trailingSpace === "always") return "center";
|
|
10527
|
+
return "ignore";
|
|
10528
|
+
}
|
|
10529
|
+
if (align === "right") {
|
|
10530
|
+
if (leadingSpace === "always") return "right";
|
|
10531
|
+
return "ignore";
|
|
10532
|
+
}
|
|
10533
|
+
return align;
|
|
10534
|
+
}
|
|
10535
|
+
}
|
|
10536
|
+
var table_pipe_spacing_default = createRule("table-pipe-spacing", {
|
|
10537
|
+
meta: {
|
|
10538
|
+
type: "layout",
|
|
10539
|
+
docs: {
|
|
10540
|
+
description: "enforce consistent spacing around table pipes",
|
|
10541
|
+
categories: ["standard"],
|
|
10542
|
+
listCategory: "Whitespace"
|
|
10543
|
+
},
|
|
10544
|
+
fixable: "whitespace",
|
|
10545
|
+
hasSuggestions: false,
|
|
10546
|
+
schema: [{
|
|
10547
|
+
type: "object",
|
|
10548
|
+
properties: {
|
|
10549
|
+
space: { anyOf: [{ enum: ["always", "never"] }, {
|
|
10550
|
+
type: "object",
|
|
10551
|
+
properties: {
|
|
10552
|
+
leading: { enum: ["always", "never"] },
|
|
10553
|
+
trailing: { enum: ["always", "never"] }
|
|
10554
|
+
},
|
|
10555
|
+
additionalProperties: false
|
|
10556
|
+
}] },
|
|
10557
|
+
cellAlign: { anyOf: [{ enum: [
|
|
10558
|
+
"left",
|
|
10559
|
+
"center",
|
|
10560
|
+
"right"
|
|
10561
|
+
] }, {
|
|
10562
|
+
type: "object",
|
|
10563
|
+
properties: {
|
|
10564
|
+
defaultDelimiter: { enum: [
|
|
10565
|
+
"left",
|
|
10566
|
+
"center",
|
|
10567
|
+
"right",
|
|
10568
|
+
"ignore"
|
|
10569
|
+
] },
|
|
10570
|
+
leftAlignmentDelimiter: { enum: [
|
|
10571
|
+
"left",
|
|
10572
|
+
"center",
|
|
10573
|
+
"right",
|
|
10574
|
+
"ignore"
|
|
10575
|
+
] },
|
|
10576
|
+
centerAlignmentDelimiter: { enum: [
|
|
10577
|
+
"left",
|
|
10578
|
+
"center",
|
|
10579
|
+
"right",
|
|
10580
|
+
"ignore"
|
|
10581
|
+
] },
|
|
10582
|
+
rightAlignmentDelimiter: { enum: [
|
|
10583
|
+
"left",
|
|
10584
|
+
"center",
|
|
10585
|
+
"right",
|
|
10586
|
+
"ignore"
|
|
10587
|
+
] }
|
|
10588
|
+
},
|
|
10589
|
+
additionalProperties: false
|
|
10590
|
+
}] }
|
|
10591
|
+
},
|
|
10592
|
+
additionalProperties: false
|
|
10593
|
+
}],
|
|
10594
|
+
messages: {
|
|
10595
|
+
expectedSpaceBefore: "Expected 1 space before \"|\".",
|
|
10596
|
+
expectedNoSpaceBefore: "Expected no space before \"|\".",
|
|
10597
|
+
expectedSpaceAfter: "Expected 1 space after \"|\".",
|
|
10598
|
+
expectedNoSpaceAfter: "Expected no space after \"|\".",
|
|
10599
|
+
expectedAlignLeft: "Expected 1 space after \"|\" for left-aligned column.",
|
|
10600
|
+
expectedNoSpaceAlignLeft: "Expected no space after \"|\" for left-aligned column.",
|
|
10601
|
+
expectedAlignRight: "Expected 1 space before \"|\" for right-aligned column.",
|
|
10602
|
+
expectedNoSpaceAlignRight: "Expected no space before \"|\" for right-aligned column.",
|
|
10603
|
+
expectedAlignCenter: "Expected the number of spaces before and after the content to be the same or differ by 1 at most for center-aligned column."
|
|
10604
|
+
}
|
|
10605
|
+
},
|
|
10606
|
+
create(context) {
|
|
10607
|
+
const sourceCode = context.sourceCode;
|
|
10608
|
+
const options = parseOptions(context.options[0]);
|
|
10609
|
+
/**
|
|
10610
|
+
* Verify for the leading pipe.
|
|
10611
|
+
*/
|
|
10612
|
+
function verifyLeadingPipe(pipe, nextToken) {
|
|
10613
|
+
if (options.leadingSpace === "always") {
|
|
10614
|
+
if (pipe.range[1] < nextToken.range[0]) return true;
|
|
10615
|
+
context.report({
|
|
10616
|
+
loc: pipe.loc,
|
|
10617
|
+
messageId: "expectedSpaceAfter",
|
|
10618
|
+
fix(fixer) {
|
|
10619
|
+
return fixer.insertTextAfterRange(pipe.range, " ");
|
|
10620
|
+
}
|
|
10621
|
+
});
|
|
10622
|
+
return false;
|
|
10623
|
+
} else if (options.leadingSpace === "never") {
|
|
10624
|
+
if (pipe.range[1] === nextToken.range[0]) return true;
|
|
10625
|
+
context.report({
|
|
10626
|
+
loc: {
|
|
10627
|
+
start: pipe.loc.end,
|
|
10628
|
+
end: nextToken.loc.start
|
|
10629
|
+
},
|
|
10630
|
+
messageId: "expectedNoSpaceAfter",
|
|
10631
|
+
fix(fixer) {
|
|
10632
|
+
return fixer.removeRange([pipe.range[1], nextToken.range[0]]);
|
|
10633
|
+
}
|
|
10634
|
+
});
|
|
10635
|
+
return false;
|
|
10636
|
+
}
|
|
10637
|
+
return true;
|
|
10638
|
+
}
|
|
10639
|
+
/**
|
|
10640
|
+
* Verify for the trailing pipe.
|
|
10641
|
+
*/
|
|
10642
|
+
function verifyTrailingPipe(prevToken, pipe) {
|
|
10643
|
+
if (options.trailingSpace === "always") {
|
|
10644
|
+
if (prevToken.range[1] < pipe.range[0]) return true;
|
|
10645
|
+
context.report({
|
|
10646
|
+
loc: pipe.loc,
|
|
10647
|
+
messageId: "expectedSpaceBefore",
|
|
10648
|
+
fix(fixer) {
|
|
10649
|
+
return fixer.insertTextBeforeRange(pipe.range, " ");
|
|
10650
|
+
}
|
|
10651
|
+
});
|
|
10652
|
+
return false;
|
|
10653
|
+
} else if (options.trailingSpace === "never") {
|
|
10654
|
+
if (prevToken.range[1] === pipe.range[0]) return true;
|
|
10655
|
+
context.report({
|
|
10656
|
+
loc: {
|
|
10657
|
+
start: prevToken.loc.end,
|
|
10658
|
+
end: pipe.loc.start
|
|
10659
|
+
},
|
|
10660
|
+
messageId: "expectedNoSpaceBefore",
|
|
10661
|
+
fix(fixer) {
|
|
10662
|
+
return fixer.removeRange([prevToken.range[1], pipe.range[0]]);
|
|
10663
|
+
}
|
|
10664
|
+
});
|
|
10665
|
+
return false;
|
|
10666
|
+
}
|
|
10667
|
+
return true;
|
|
10668
|
+
}
|
|
10669
|
+
/**
|
|
10670
|
+
* Verify for the alignment of the pipe according to the delimiter alignment.
|
|
10671
|
+
* Return "leading" if the leading pipe is reported, "trailing" if the trailing pipe is reported, "both" if both are reported, or null if nothing is reported.
|
|
10672
|
+
*/
|
|
10673
|
+
function verifyAlignPipe({ leadingPipe, content, trailingPipe }, cellAlign) {
|
|
10674
|
+
if (!leadingPipe || !trailingPipe || !content) return null;
|
|
10675
|
+
const lineText = sourceCode.lines[leadingPipe.loc.start.line - 1];
|
|
10676
|
+
if (cellAlign === "left") {
|
|
10677
|
+
const expectedWidth = options.leadingSpace === "always" ? 1 : 0;
|
|
10678
|
+
if (getLeadingSpacesWidth() === expectedWidth) return null;
|
|
10679
|
+
context.report({
|
|
10680
|
+
loc: leadingPipe.range[1] < content.range[0] ? {
|
|
10681
|
+
start: leadingPipe.loc.end,
|
|
10682
|
+
end: content.loc.start
|
|
10683
|
+
} : leadingPipe.loc,
|
|
10684
|
+
messageId: expectedWidth >= 1 ? "expectedAlignLeft" : "expectedNoSpaceAlignLeft",
|
|
10685
|
+
*fix(fixer) {
|
|
10686
|
+
const cellWidth = getCellWidth();
|
|
10687
|
+
const contentTextWidth = getContentTextWidth();
|
|
10688
|
+
const newLeadingSpaces = " ".repeat(expectedWidth);
|
|
10689
|
+
const newTrailingSpaces = " ".repeat(Math.max(cellWidth - contentTextWidth - expectedWidth, 0));
|
|
10690
|
+
const contentText = getNormalizedContentText();
|
|
10691
|
+
yield fixer.replaceTextRange([leadingPipe.range[1], trailingPipe.range[0]], `${newLeadingSpaces}${contentText}${newTrailingSpaces}`);
|
|
10692
|
+
}
|
|
10693
|
+
});
|
|
10694
|
+
return "leading";
|
|
10695
|
+
} else if (cellAlign === "right") {
|
|
10696
|
+
const expectedWidth = options.trailingSpace === "always" ? 1 : 0;
|
|
10697
|
+
if (getTrailingSpacesWidth() === expectedWidth) return null;
|
|
10698
|
+
context.report({
|
|
10699
|
+
loc: content.range[1] < trailingPipe.range[0] ? {
|
|
10700
|
+
start: content.loc.end,
|
|
10701
|
+
end: trailingPipe.loc.start
|
|
10702
|
+
} : trailingPipe.loc,
|
|
10703
|
+
messageId: expectedWidth >= 1 ? "expectedAlignRight" : "expectedNoSpaceAlignRight",
|
|
10704
|
+
*fix(fixer) {
|
|
10705
|
+
const cellWidth = getCellWidth();
|
|
10706
|
+
const contentTextWidth = getContentTextWidth();
|
|
10707
|
+
const newLeadingSpaces = " ".repeat(Math.max(cellWidth - contentTextWidth - expectedWidth, 0));
|
|
10708
|
+
const newTrailingSpaces = " ".repeat(expectedWidth);
|
|
10709
|
+
const contentText = getNormalizedContentText();
|
|
10710
|
+
yield fixer.replaceTextRange([leadingPipe.range[1], trailingPipe.range[0]], `${newLeadingSpaces}${contentText}${newTrailingSpaces}`);
|
|
10711
|
+
}
|
|
10712
|
+
});
|
|
10713
|
+
return "trailing";
|
|
10714
|
+
} else if (cellAlign === "center") {
|
|
10715
|
+
const leadingSpacesWidth = getLeadingSpacesWidth();
|
|
10716
|
+
const trailingSpacesWidth = getTrailingSpacesWidth();
|
|
10717
|
+
if (leadingSpacesWidth === trailingSpacesWidth || leadingSpacesWidth + 1 === trailingSpacesWidth) return null;
|
|
10718
|
+
const leadingReportLoc = leadingPipe.range[1] < content.range[0] ? {
|
|
10719
|
+
start: leadingPipe.loc.end,
|
|
10720
|
+
end: content.loc.start
|
|
10721
|
+
} : leadingPipe.loc;
|
|
10722
|
+
const trailingReportLoc = content.range[1] < trailingPipe.range[0] ? {
|
|
10723
|
+
start: content.loc.end,
|
|
10724
|
+
end: trailingPipe.loc.start
|
|
10725
|
+
} : trailingPipe.loc;
|
|
10726
|
+
for (const reportLoc of [leadingReportLoc, trailingReportLoc]) context.report({
|
|
10727
|
+
loc: reportLoc,
|
|
10728
|
+
messageId: "expectedAlignCenter",
|
|
10729
|
+
*fix(fixer) {
|
|
10730
|
+
const cellWidth = getCellWidth();
|
|
10731
|
+
const contentTextWidth = getContentTextWidth();
|
|
10732
|
+
const spacesLength = cellWidth - contentTextWidth;
|
|
10733
|
+
const leadingSpacesLength = Math.floor(spacesLength / 2);
|
|
10734
|
+
const trailingSpacesLength = spacesLength - leadingSpacesLength;
|
|
10735
|
+
const newLeadingSpaces = " ".repeat(leadingSpacesLength);
|
|
10736
|
+
const newTrailingSpaces = " ".repeat(trailingSpacesLength);
|
|
10737
|
+
const contentText = getNormalizedContentText();
|
|
10738
|
+
yield fixer.replaceTextRange([leadingPipe.range[1], trailingPipe.range[0]], `${newLeadingSpaces}${contentText}${newTrailingSpaces}`);
|
|
10739
|
+
}
|
|
10740
|
+
});
|
|
10741
|
+
return "both";
|
|
10742
|
+
}
|
|
10743
|
+
return null;
|
|
10744
|
+
/**
|
|
10745
|
+
* Get the width of the leading spaces in the cell.
|
|
10746
|
+
*/
|
|
10747
|
+
function getLeadingSpacesWidth() {
|
|
10748
|
+
return getTextWidth(lineText, leadingPipe.loc.end.column - 1, content.loc.start.column - 1);
|
|
10749
|
+
}
|
|
10750
|
+
/**
|
|
10751
|
+
* Get the width of the trailing spaces in the cell.
|
|
10752
|
+
*/
|
|
10753
|
+
function getTrailingSpacesWidth() {
|
|
10754
|
+
return getTextWidth(lineText, content.loc.end.column - 1, trailingPipe.loc.start.column - 1);
|
|
10755
|
+
}
|
|
10756
|
+
/**
|
|
10757
|
+
* Get the width of the whole cell (including leading and trailing spaces)
|
|
10758
|
+
*/
|
|
10759
|
+
function getCellWidth() {
|
|
10760
|
+
return getTextWidth(lineText, leadingPipe.loc.end.column - 1, trailingPipe.loc.start.column - 1);
|
|
10761
|
+
}
|
|
10762
|
+
/**
|
|
10763
|
+
* Get the width of the content text (excluding leading and trailing spaces)
|
|
10764
|
+
*/
|
|
10765
|
+
function getContentTextWidth() {
|
|
10766
|
+
return getTextWidth(lineText, content.loc.start.column - 1, content.loc.end.column - 1);
|
|
10767
|
+
}
|
|
10768
|
+
/**
|
|
10769
|
+
* Get the normalized content text (with normalized spaces)
|
|
10770
|
+
*/
|
|
10771
|
+
function getNormalizedContentText() {
|
|
10772
|
+
const prefixWidth = getWidth(lineText.slice(0, content.loc.start.column - 1));
|
|
10773
|
+
let result = "";
|
|
10774
|
+
for (const c of lineText.slice(content.loc.start.column - 1, content.loc.end.column - 1)) if (c === " ") result += " ".repeat(4 - (prefixWidth + result.length) % 4);
|
|
10775
|
+
else result += c;
|
|
10776
|
+
return result;
|
|
10777
|
+
}
|
|
10778
|
+
}
|
|
10779
|
+
/**
|
|
10780
|
+
* Convert a parsed table row to cell data list
|
|
10781
|
+
*/
|
|
10782
|
+
function parsedTableRowToCellDataList(parsedRow) {
|
|
10783
|
+
return parsedRow.cells.map((cell, index) => {
|
|
10784
|
+
const nextCell = index + 1 < parsedRow.cells.length ? parsedRow.cells[index + 1] : null;
|
|
10785
|
+
return {
|
|
10786
|
+
type: "cell",
|
|
10787
|
+
leadingPipe: cell.leadingPipe,
|
|
10788
|
+
content: cell.cell,
|
|
10789
|
+
trailingPipe: nextCell ? nextCell.leadingPipe : parsedRow.trailingPipe
|
|
10790
|
+
};
|
|
10791
|
+
});
|
|
10792
|
+
}
|
|
10793
|
+
/**
|
|
10794
|
+
* Convert a parsed table delimiter row to delimiter data list
|
|
10795
|
+
*/
|
|
10796
|
+
function parsedTableDelimiterRowToDelimiterDataList(parsedDelimiterRow) {
|
|
10797
|
+
return parsedDelimiterRow.delimiters.map((cell, index) => {
|
|
10798
|
+
const nextCell = index + 1 < parsedDelimiterRow.delimiters.length ? parsedDelimiterRow.delimiters[index + 1] : null;
|
|
10799
|
+
return {
|
|
10800
|
+
type: "delimiter",
|
|
10801
|
+
leadingPipe: cell.leadingPipe,
|
|
10802
|
+
content: cell.delimiter,
|
|
10803
|
+
align: cell.delimiter.align,
|
|
10804
|
+
trailingPipe: nextCell ? nextCell.leadingPipe : parsedDelimiterRow.trailingPipe
|
|
10805
|
+
};
|
|
10806
|
+
});
|
|
10807
|
+
}
|
|
10808
|
+
return { table(node) {
|
|
10809
|
+
const parsedDelimiterRow = parseTableDelimiterRow(sourceCode, node);
|
|
10810
|
+
const delimiters = parsedDelimiterRow && parsedTableDelimiterRowToDelimiterDataList(parsedDelimiterRow);
|
|
10811
|
+
for (const row of node.children) {
|
|
10812
|
+
const parsedRow = parseTableRow(sourceCode, row);
|
|
10813
|
+
if (!parsedRow) continue;
|
|
10814
|
+
const cells = parsedTableRowToCellDataList(parsedRow);
|
|
10815
|
+
for (let columnIndex = 0; columnIndex < cells.length; columnIndex++) {
|
|
10816
|
+
const cell = cells[columnIndex];
|
|
10817
|
+
const delimiter = delimiters && columnIndex < delimiters.length ? delimiters[columnIndex] : null;
|
|
10818
|
+
const alignReportedPoint = delimiter ? verifyAlignPipe(cell, options.cellAlignByDelimiter[delimiter.align]) : null;
|
|
10819
|
+
if (alignReportedPoint === "both") continue;
|
|
10820
|
+
if (cell.leadingPipe && alignReportedPoint !== "leading") {
|
|
10821
|
+
if (options.leadingSpace !== "never" || cell.content) {
|
|
10822
|
+
const nextToken = getNextToken(cells, columnIndex);
|
|
10823
|
+
if (nextToken) verifyLeadingPipe(cell.leadingPipe, nextToken);
|
|
10824
|
+
}
|
|
10825
|
+
}
|
|
10826
|
+
if (cell.trailingPipe && options.trailingSpace !== "never" && alignReportedPoint !== "trailing") {
|
|
10827
|
+
const prevToken = getPrevToken(cells, columnIndex);
|
|
10828
|
+
if (prevToken) verifyTrailingPipe(prevToken, cell.trailingPipe);
|
|
10829
|
+
}
|
|
10830
|
+
}
|
|
10831
|
+
}
|
|
10832
|
+
if (!delimiters) return;
|
|
10833
|
+
for (let columnIndex = 0; columnIndex < delimiters.length; columnIndex++) {
|
|
10834
|
+
const delimiter = delimiters[columnIndex];
|
|
10835
|
+
const alignReportedPoint = verifyAlignPipe(delimiter, options.cellAlignByDelimiter[delimiter.align]);
|
|
10836
|
+
if (alignReportedPoint === "both") continue;
|
|
10837
|
+
if (delimiter.leadingPipe && alignReportedPoint !== "leading") verifyLeadingPipe(delimiter.leadingPipe, delimiter.content);
|
|
10838
|
+
if (delimiter.trailingPipe && alignReportedPoint !== "trailing") verifyTrailingPipe(delimiter.content, delimiter.trailingPipe);
|
|
10839
|
+
}
|
|
10840
|
+
} };
|
|
10841
|
+
/**
|
|
10842
|
+
* Get the next token (pipe or cell) after the given column index.
|
|
10843
|
+
*/
|
|
10844
|
+
function getNextToken(cells, columnIndex) {
|
|
10845
|
+
for (let i = columnIndex; i < cells.length; i++) {
|
|
10846
|
+
const cell = cells[i];
|
|
10847
|
+
const token = cell.content ?? cell.trailingPipe;
|
|
10848
|
+
if (token) return token;
|
|
10849
|
+
}
|
|
10850
|
+
return null;
|
|
10851
|
+
}
|
|
10852
|
+
/**
|
|
10853
|
+
* Get the prev token (pipe or cell) after the given column index.
|
|
10854
|
+
*/
|
|
10855
|
+
function getPrevToken(cells, columnIndex) {
|
|
10856
|
+
for (let i = columnIndex; i >= 0; i--) {
|
|
10857
|
+
const cell = cells[i];
|
|
10858
|
+
const token = cell.content ?? cell.leadingPipe;
|
|
10859
|
+
if (token) return token;
|
|
10860
|
+
}
|
|
10861
|
+
return null;
|
|
10862
|
+
}
|
|
10863
|
+
}
|
|
10864
|
+
});
|
|
10865
|
+
|
|
9658
10866
|
//#endregion
|
|
9659
10867
|
//#region src/rules/thematic-break-character-style.ts
|
|
9660
10868
|
var thematic_break_character_style_default = createRule("thematic-break-character-style", {
|
|
@@ -9663,7 +10871,7 @@ var thematic_break_character_style_default = createRule("thematic-break-characte
|
|
|
9663
10871
|
docs: {
|
|
9664
10872
|
description: "enforce consistent character style for thematic breaks (horizontal rules) in Markdown.",
|
|
9665
10873
|
categories: ["standard"],
|
|
9666
|
-
listCategory: "
|
|
10874
|
+
listCategory: "Notation"
|
|
9667
10875
|
},
|
|
9668
10876
|
fixable: "code",
|
|
9669
10877
|
hasSuggestions: false,
|
|
@@ -9742,7 +10950,7 @@ var thematic_break_length_default = createRule("thematic-break-length", {
|
|
|
9742
10950
|
docs: {
|
|
9743
10951
|
description: "enforce consistent length for thematic breaks (horizontal rules) in Markdown.",
|
|
9744
10952
|
categories: ["standard"],
|
|
9745
|
-
listCategory: "
|
|
10953
|
+
listCategory: "Decorative"
|
|
9746
10954
|
},
|
|
9747
10955
|
fixable: "code",
|
|
9748
10956
|
hasSuggestions: false,
|
|
@@ -9808,7 +11016,7 @@ var thematic_break_sequence_pattern_default = createRule("thematic-break-sequenc
|
|
|
9808
11016
|
docs: {
|
|
9809
11017
|
description: "enforce consistent repeating patterns for thematic breaks (horizontal rules) in Markdown.",
|
|
9810
11018
|
categories: ["standard"],
|
|
9811
|
-
listCategory: "
|
|
11019
|
+
listCategory: "Decorative"
|
|
9812
11020
|
},
|
|
9813
11021
|
fixable: "code",
|
|
9814
11022
|
hasSuggestions: false,
|
|
@@ -9905,6 +11113,9 @@ const rules$1 = [
|
|
|
9905
11113
|
sort_definitions_default,
|
|
9906
11114
|
strikethrough_delimiters_style_default,
|
|
9907
11115
|
table_header_casing_default,
|
|
11116
|
+
table_leading_trailing_pipes_default,
|
|
11117
|
+
table_pipe_alignment_default,
|
|
11118
|
+
table_pipe_spacing_default,
|
|
9908
11119
|
thematic_break_character_style_default,
|
|
9909
11120
|
thematic_break_length_default,
|
|
9910
11121
|
thematic_break_sequence_pattern_default
|
|
@@ -9912,7 +11123,7 @@ const rules$1 = [
|
|
|
9912
11123
|
|
|
9913
11124
|
//#endregion
|
|
9914
11125
|
//#region src/configs/recommended.ts
|
|
9915
|
-
var recommended_exports = __export({
|
|
11126
|
+
var recommended_exports = /* @__PURE__ */ __export({
|
|
9916
11127
|
files: () => files$1,
|
|
9917
11128
|
language: () => language$1,
|
|
9918
11129
|
languageOptions: () => languageOptions$1,
|
|
@@ -9942,7 +11153,7 @@ const rules$3 = {
|
|
|
9942
11153
|
|
|
9943
11154
|
//#endregion
|
|
9944
11155
|
//#region src/configs/standard.ts
|
|
9945
|
-
var standard_exports = __export({
|
|
11156
|
+
var standard_exports = /* @__PURE__ */ __export({
|
|
9946
11157
|
files: () => files,
|
|
9947
11158
|
language: () => language,
|
|
9948
11159
|
languageOptions: () => languageOptions,
|
|
@@ -9993,6 +11204,9 @@ const rules$2 = {
|
|
|
9993
11204
|
"markdown-preferences/setext-heading-underline-length": "error",
|
|
9994
11205
|
"markdown-preferences/sort-definitions": "error",
|
|
9995
11206
|
"markdown-preferences/strikethrough-delimiters-style": "error",
|
|
11207
|
+
"markdown-preferences/table-leading-trailing-pipes": "error",
|
|
11208
|
+
"markdown-preferences/table-pipe-alignment": "error",
|
|
11209
|
+
"markdown-preferences/table-pipe-spacing": "error",
|
|
9996
11210
|
"markdown-preferences/thematic-break-character-style": "error",
|
|
9997
11211
|
"markdown-preferences/thematic-break-length": "error",
|
|
9998
11212
|
"markdown-preferences/thematic-break-sequence-pattern": "error"
|
|
@@ -10000,12 +11214,12 @@ const rules$2 = {
|
|
|
10000
11214
|
|
|
10001
11215
|
//#endregion
|
|
10002
11216
|
//#region src/meta.ts
|
|
10003
|
-
var meta_exports = __export({
|
|
11217
|
+
var meta_exports = /* @__PURE__ */ __export({
|
|
10004
11218
|
name: () => name,
|
|
10005
11219
|
version: () => version
|
|
10006
11220
|
});
|
|
10007
11221
|
const name = "eslint-plugin-markdown-preferences";
|
|
10008
|
-
const version = "0.
|
|
11222
|
+
const version = "0.26.0";
|
|
10009
11223
|
|
|
10010
11224
|
//#endregion
|
|
10011
11225
|
//#region src/index.ts
|