eslint-plugin-markdown-preferences 0.23.0 → 0.24.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 +1 -0
- package/lib/{chunk-Cl8Af3a2.js → chunk-CTAAG5j7.js} +3 -1
- package/lib/index.d.ts +13 -1
- package/lib/index.js +1620 -558
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { __export } from "./chunk-
|
|
1
|
+
import { __export } from "./chunk-CTAAG5j7.js";
|
|
2
2
|
import stringWidth from "string-width";
|
|
3
3
|
import emojiRegex from "emoji-regex-xs";
|
|
4
4
|
import path from "node:path";
|
|
@@ -600,12 +600,28 @@ function getBlockquoteLevelFromLine(sourceCode, lineNumber) {
|
|
|
600
600
|
const lineText = sourceCode.lines[lineNumber - 1];
|
|
601
601
|
let prefix = "";
|
|
602
602
|
let level = 0;
|
|
603
|
+
let width = 0;
|
|
604
|
+
let leadingMarkerOffset = 0;
|
|
603
605
|
const blockquoteMarkers = /* @__PURE__ */ new Map();
|
|
604
606
|
for (const c of lineText) {
|
|
605
607
|
if (c === ">") {
|
|
608
|
+
if (width - leadingMarkerOffset > 3) break;
|
|
609
|
+
leadingMarkerOffset = width + 1;
|
|
606
610
|
level++;
|
|
607
|
-
blockquoteMarkers.set(level, {
|
|
608
|
-
|
|
611
|
+
blockquoteMarkers.set(level, { loc: {
|
|
612
|
+
start: {
|
|
613
|
+
line: lineNumber,
|
|
614
|
+
column: prefix.length + 1
|
|
615
|
+
},
|
|
616
|
+
end: {
|
|
617
|
+
line: lineNumber,
|
|
618
|
+
column: prefix.length + 2
|
|
619
|
+
}
|
|
620
|
+
} });
|
|
621
|
+
} else if (!isSpaceOrTab(c)) break;
|
|
622
|
+
if (c === " ") width += 4 - width % 4;
|
|
623
|
+
else width++;
|
|
624
|
+
if (c !== ">" && prefix.at(-1) === ">") leadingMarkerOffset++;
|
|
609
625
|
prefix += c;
|
|
610
626
|
}
|
|
611
627
|
const result = {
|
|
@@ -618,6 +634,64 @@ function getBlockquoteLevelFromLine(sourceCode, lineNumber) {
|
|
|
618
634
|
return result;
|
|
619
635
|
}
|
|
620
636
|
|
|
637
|
+
//#endregion
|
|
638
|
+
//#region src/utils/width.ts
|
|
639
|
+
/**
|
|
640
|
+
* Get the visual width of the string.
|
|
641
|
+
*/
|
|
642
|
+
function getWidth(str) {
|
|
643
|
+
let width = 0;
|
|
644
|
+
for (const c of str) if (c === " ") width += 4 - width % 4;
|
|
645
|
+
else width++;
|
|
646
|
+
return width;
|
|
647
|
+
}
|
|
648
|
+
/**
|
|
649
|
+
* Get a slice of the string by visual width.
|
|
650
|
+
*/
|
|
651
|
+
function sliceWidth(str, start, end) {
|
|
652
|
+
const buffer = [...str];
|
|
653
|
+
let width = 0;
|
|
654
|
+
let c;
|
|
655
|
+
while (c = buffer.shift()) {
|
|
656
|
+
if (start <= width) {
|
|
657
|
+
buffer.unshift(c);
|
|
658
|
+
break;
|
|
659
|
+
}
|
|
660
|
+
if (c === " ") width += 4 - width % 4;
|
|
661
|
+
else width++;
|
|
662
|
+
}
|
|
663
|
+
if (buffer.length === 0) return "";
|
|
664
|
+
let result = " ".repeat(width - start);
|
|
665
|
+
if (end == null) return `${result}${buffer.join("")}`;
|
|
666
|
+
while (c = buffer.shift()) {
|
|
667
|
+
let newWidth;
|
|
668
|
+
if (c === " ") newWidth = width + 4 - width % 4;
|
|
669
|
+
else newWidth = width + 1;
|
|
670
|
+
if (end < newWidth) {
|
|
671
|
+
buffer.unshift(c);
|
|
672
|
+
break;
|
|
673
|
+
}
|
|
674
|
+
result += c;
|
|
675
|
+
width = newWidth;
|
|
676
|
+
}
|
|
677
|
+
if (buffer.length === 0) return result;
|
|
678
|
+
result += " ".repeat(end - width);
|
|
679
|
+
return result;
|
|
680
|
+
}
|
|
681
|
+
/**
|
|
682
|
+
* Get the character at the visual width.
|
|
683
|
+
*/
|
|
684
|
+
function atWidth(str, target) {
|
|
685
|
+
let width = 0;
|
|
686
|
+
for (const c of str) {
|
|
687
|
+
if (target === width) return c;
|
|
688
|
+
if (target < width) return " ";
|
|
689
|
+
if (c === " ") width += 4 - width % 4;
|
|
690
|
+
else width++;
|
|
691
|
+
}
|
|
692
|
+
return null;
|
|
693
|
+
}
|
|
694
|
+
|
|
621
695
|
//#endregion
|
|
622
696
|
//#region src/rules/blockquote-marker-alignment.ts
|
|
623
697
|
var blockquote_marker_alignment_default = createRule("blockquote-marker-alignment", {
|
|
@@ -655,38 +729,33 @@ var blockquote_marker_alignment_default = createRule("blockquote-marker-alignmen
|
|
|
655
729
|
const endLine = loc.end.line;
|
|
656
730
|
const base = getBlockquoteLevelFromLine(sourceCode, startLine).blockquoteMarkers.get(blockquoteLevel);
|
|
657
731
|
if (!base) return;
|
|
732
|
+
const baseBeforeMarker = sourceCode.lines[startLine - 1].slice(0, base.loc.start.column - 1);
|
|
733
|
+
const baseIndentWidth = getWidth(baseBeforeMarker);
|
|
658
734
|
for (let lineNumber = startLine + 1; lineNumber <= endLine; lineNumber++) {
|
|
659
735
|
const marker = getBlockquoteLevelFromLine(sourceCode, lineNumber).blockquoteMarkers.get(blockquoteLevel);
|
|
660
736
|
if (!marker) continue;
|
|
661
|
-
|
|
737
|
+
const indentWidth = getWidth(sourceCode.lines[lineNumber - 1].slice(0, marker.loc.start.column - 1));
|
|
738
|
+
if (baseIndentWidth === indentWidth) continue;
|
|
662
739
|
blockquoteStack.reported = true;
|
|
663
740
|
context.report({
|
|
664
741
|
node,
|
|
665
|
-
loc:
|
|
666
|
-
start: {
|
|
667
|
-
line: lineNumber,
|
|
668
|
-
column: marker.index + 1
|
|
669
|
-
},
|
|
670
|
-
end: {
|
|
671
|
-
line: lineNumber,
|
|
672
|
-
column: marker.index + 2
|
|
673
|
-
}
|
|
674
|
-
},
|
|
742
|
+
loc: marker.loc,
|
|
675
743
|
messageId: "inconsistentAlignment",
|
|
676
744
|
fix(fixer) {
|
|
677
745
|
const line = getParsedLines(sourceCode).get(lineNumber);
|
|
678
|
-
if (
|
|
679
|
-
const addSpaces = " ".repeat(
|
|
680
|
-
return fixer.insertTextBeforeRange([line.range[0] + marker.
|
|
746
|
+
if (indentWidth < baseIndentWidth) {
|
|
747
|
+
const addSpaces = " ".repeat(baseIndentWidth - indentWidth);
|
|
748
|
+
return fixer.insertTextBeforeRange([line.range[0] + marker.loc.start.column - 1, line.range[0] + marker.loc.start.column - 1], addSpaces);
|
|
681
749
|
}
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
750
|
+
let newBeforeMarker = line.text.slice(0, marker.loc.start.column - 1);
|
|
751
|
+
while (getWidth(newBeforeMarker) > baseIndentWidth) {
|
|
752
|
+
const last = newBeforeMarker.at(-1);
|
|
753
|
+
if (last && isWhitespace(last)) newBeforeMarker = newBeforeMarker.slice(0, -1);
|
|
754
|
+
else return null;
|
|
685
755
|
}
|
|
686
|
-
if (
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
return fixer.removeRange([line.range[0] + removeStartIndex, line.range[0] + marker.index]);
|
|
756
|
+
if (getWidth(newBeforeMarker) < baseIndentWidth) newBeforeMarker += " ".repeat(baseIndentWidth - getWidth(newBeforeMarker));
|
|
757
|
+
if (!baseBeforeMarker.includes(">") || baseBeforeMarker === newBeforeMarker) return fixer.replaceTextRange([line.range[0], line.range[0] + marker.loc.start.column - 1], newBeforeMarker);
|
|
758
|
+
return null;
|
|
690
759
|
}
|
|
691
760
|
});
|
|
692
761
|
}
|
|
@@ -714,7 +783,7 @@ function getOtherMarker(unavailableMarker) {
|
|
|
714
783
|
/**
|
|
715
784
|
* Parse rule options.
|
|
716
785
|
*/
|
|
717
|
-
function parseOptions$
|
|
786
|
+
function parseOptions$3(options) {
|
|
718
787
|
const primary = options.primary || "-";
|
|
719
788
|
const secondary = options.secondary || getOtherMarker(primary);
|
|
720
789
|
if (primary === secondary) throw new Error(`\`primary\` and \`secondary\` cannot be the same (primary: "${primary}", secondary: "${secondary}").`);
|
|
@@ -782,7 +851,7 @@ var bullet_list_marker_style_default = createRule("bullet-list-marker-style", {
|
|
|
782
851
|
},
|
|
783
852
|
create(context) {
|
|
784
853
|
const sourceCode = context.sourceCode;
|
|
785
|
-
const options = parseOptions$
|
|
854
|
+
const options = parseOptions$3(context.options[0] || {});
|
|
786
855
|
let containerStack = {
|
|
787
856
|
node: sourceCode.ast,
|
|
788
857
|
level: 1,
|
|
@@ -4334,275 +4403,224 @@ var heading_casing_default = createRule("heading-casing", {
|
|
|
4334
4403
|
});
|
|
4335
4404
|
|
|
4336
4405
|
//#endregion
|
|
4337
|
-
//#region src/utils/
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
if (getHeadingKind(sourceCode, node) !== "setext") return null;
|
|
4343
|
-
const lines = getParsedLines(sourceCode);
|
|
4344
|
-
const contentLines = [];
|
|
4345
|
-
const nodeLoc = sourceCode.getLoc(node);
|
|
4346
|
-
for (let lineNumber = nodeLoc.start.line; lineNumber < nodeLoc.end.line; lineNumber++) {
|
|
4347
|
-
const content = parseContent(lines.get(lineNumber));
|
|
4348
|
-
contentLines.push(content);
|
|
4406
|
+
//#region src/utils/character-cursor.ts
|
|
4407
|
+
var CharacterCursor = class {
|
|
4408
|
+
text;
|
|
4409
|
+
constructor(text) {
|
|
4410
|
+
this.text = text;
|
|
4349
4411
|
}
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
}
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
|
|
4412
|
+
curr() {
|
|
4413
|
+
return this.text[this.index];
|
|
4414
|
+
}
|
|
4415
|
+
currIndex() {
|
|
4416
|
+
return this.index;
|
|
4417
|
+
}
|
|
4418
|
+
setCurrIndex(index) {
|
|
4419
|
+
this.index = index;
|
|
4420
|
+
}
|
|
4421
|
+
isWhitespace(index) {
|
|
4422
|
+
if (index >= this.text.length) return false;
|
|
4423
|
+
const ch = this.text[index];
|
|
4424
|
+
if (isWhitespace(ch)) return true;
|
|
4425
|
+
if (ch !== ">") return false;
|
|
4426
|
+
const prefix = [ch];
|
|
4427
|
+
for (let prev = index - 1; prev >= 0; prev--) {
|
|
4428
|
+
const prevCh$1 = this.text[prev];
|
|
4429
|
+
if (prevCh$1 === "\n") break;
|
|
4430
|
+
if (isSpaceOrTab(prevCh$1) || prevCh$1 === ">") {
|
|
4431
|
+
prefix.unshift(prevCh$1);
|
|
4432
|
+
continue;
|
|
4433
|
+
}
|
|
4434
|
+
return false;
|
|
4369
4435
|
}
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4436
|
+
let width = 0;
|
|
4437
|
+
let leadingMarkerOffset = 0;
|
|
4438
|
+
let prevCh;
|
|
4439
|
+
for (const currCh of prefix) {
|
|
4440
|
+
if (currCh === ">") {
|
|
4441
|
+
if (width - leadingMarkerOffset > 3) return false;
|
|
4442
|
+
leadingMarkerOffset = width + 1;
|
|
4443
|
+
}
|
|
4444
|
+
if (currCh === " ") width += 4 - width % 4;
|
|
4445
|
+
else width++;
|
|
4446
|
+
if (prevCh === ">" && isSpaceOrTab(currCh)) leadingMarkerOffset++;
|
|
4447
|
+
prevCh = currCh;
|
|
4374
4448
|
}
|
|
4375
|
-
|
|
4376
|
-
break;
|
|
4449
|
+
return true;
|
|
4377
4450
|
}
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
|
|
4451
|
+
};
|
|
4452
|
+
var ForwardCharacterCursor = class extends CharacterCursor {
|
|
4453
|
+
index;
|
|
4454
|
+
constructor(text) {
|
|
4455
|
+
super(text);
|
|
4456
|
+
this.index = 0;
|
|
4457
|
+
}
|
|
4458
|
+
next() {
|
|
4459
|
+
this.index++;
|
|
4460
|
+
return this.text[this.index];
|
|
4461
|
+
}
|
|
4462
|
+
finished() {
|
|
4463
|
+
return this.index >= this.text.length;
|
|
4464
|
+
}
|
|
4465
|
+
skipSpaces() {
|
|
4466
|
+
while (this.index < this.text.length && this.isWhitespace(this.index)) this.index++;
|
|
4467
|
+
}
|
|
4468
|
+
/**
|
|
4469
|
+
* Skip until the end by the given condition
|
|
4470
|
+
*/
|
|
4471
|
+
skipUntilEnd(checkEnd) {
|
|
4472
|
+
while (this.index < this.text.length) {
|
|
4473
|
+
const c = this.text[this.index];
|
|
4474
|
+
if (checkEnd(c, this.index)) return true;
|
|
4475
|
+
this.index++;
|
|
4476
|
+
if (c !== "\\") continue;
|
|
4477
|
+
if (this.index < this.text.length && (this.text[this.index] === "\\" || checkEnd(this.text[this.index], this.index)) && !isWhitespace(this.text[this.index])) this.index++;
|
|
4478
|
+
}
|
|
4479
|
+
return false;
|
|
4480
|
+
}
|
|
4481
|
+
};
|
|
4482
|
+
var BackwardCharacterCursor = class extends CharacterCursor {
|
|
4483
|
+
index;
|
|
4484
|
+
constructor(text) {
|
|
4485
|
+
super(text);
|
|
4486
|
+
this.index = text.length - 1;
|
|
4487
|
+
}
|
|
4488
|
+
prev() {
|
|
4489
|
+
this.index--;
|
|
4490
|
+
return this.text[this.index];
|
|
4491
|
+
}
|
|
4492
|
+
finished() {
|
|
4493
|
+
return this.index < 0;
|
|
4494
|
+
}
|
|
4495
|
+
skipSpaces() {
|
|
4496
|
+
while (this.index >= 0 && this.isWhitespace(this.index)) this.index--;
|
|
4497
|
+
}
|
|
4498
|
+
/**
|
|
4499
|
+
* Skip until the start by the given condition
|
|
4500
|
+
*/
|
|
4501
|
+
skipUntilStart(checkStart) {
|
|
4502
|
+
while (this.index >= 0) {
|
|
4503
|
+
const c = this.text[this.index];
|
|
4504
|
+
if (checkStart(c, this.index)) {
|
|
4505
|
+
if (this.index > 1 && !isWhitespace(c)) {
|
|
4506
|
+
let escapeText = "";
|
|
4507
|
+
while (this.text.endsWith(`${escapeText}\\`, this.index)) escapeText += "\\";
|
|
4508
|
+
if (escapeText.length % 2 === 1) {
|
|
4509
|
+
this.index -= escapeText.length + 1;
|
|
4510
|
+
continue;
|
|
4511
|
+
}
|
|
4512
|
+
}
|
|
4513
|
+
return true;
|
|
4391
4514
|
}
|
|
4392
|
-
|
|
4393
|
-
raws: {
|
|
4394
|
-
prefix,
|
|
4395
|
-
spaceBefore,
|
|
4396
|
-
spaceAfter
|
|
4515
|
+
this.index--;
|
|
4397
4516
|
}
|
|
4517
|
+
return false;
|
|
4518
|
+
}
|
|
4519
|
+
};
|
|
4520
|
+
|
|
4521
|
+
//#endregion
|
|
4522
|
+
//#region src/utils/link-definition.ts
|
|
4523
|
+
/**
|
|
4524
|
+
* Parse the link definition.
|
|
4525
|
+
*/
|
|
4526
|
+
function parseLinkDefinition(sourceCode, node) {
|
|
4527
|
+
const text = sourceCode.getText(node);
|
|
4528
|
+
const parsed = parseLinkDefinitionFromText(text);
|
|
4529
|
+
if (!parsed) return null;
|
|
4530
|
+
const nodeRange = sourceCode.getRange(node);
|
|
4531
|
+
const labelRange = [nodeRange[0] + parsed.label.range[0], nodeRange[0] + parsed.label.range[1]];
|
|
4532
|
+
const destinationRange = [nodeRange[0] + parsed.destination.range[0], nodeRange[0] + parsed.destination.range[1]];
|
|
4533
|
+
return {
|
|
4534
|
+
label: {
|
|
4535
|
+
text: parsed.label.text,
|
|
4536
|
+
range: labelRange,
|
|
4537
|
+
loc: getSourceLocationFromRange(sourceCode, node, labelRange)
|
|
4538
|
+
},
|
|
4539
|
+
destination: {
|
|
4540
|
+
type: parsed.destination.type,
|
|
4541
|
+
text: parsed.destination.text,
|
|
4542
|
+
range: destinationRange,
|
|
4543
|
+
loc: getSourceLocationFromRange(sourceCode, node, destinationRange)
|
|
4544
|
+
},
|
|
4545
|
+
title: parsed.title ? {
|
|
4546
|
+
type: parsed.title.type,
|
|
4547
|
+
text: parsed.title.text,
|
|
4548
|
+
range: [nodeRange[0] + parsed.title.range[0], nodeRange[0] + parsed.title.range[1]],
|
|
4549
|
+
loc: getSourceLocationFromRange(sourceCode, node, [nodeRange[0] + parsed.title.range[0], nodeRange[0] + parsed.title.range[1]])
|
|
4550
|
+
} : null
|
|
4398
4551
|
};
|
|
4399
4552
|
}
|
|
4400
4553
|
/**
|
|
4401
|
-
* Parse the
|
|
4554
|
+
* Parse the link definition from the given text.
|
|
4402
4555
|
*/
|
|
4403
|
-
function
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
|
|
4422
|
-
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
4426
|
-
|
|
4556
|
+
function parseLinkDefinitionFromText(text) {
|
|
4557
|
+
if (!text.startsWith("[")) return null;
|
|
4558
|
+
const cursor = new ForwardCharacterCursor(text);
|
|
4559
|
+
const labelStartIndex = 0;
|
|
4560
|
+
cursor.next();
|
|
4561
|
+
if (!cursor.skipUntilEnd((c) => c === "]")) return null;
|
|
4562
|
+
cursor.next();
|
|
4563
|
+
const labelRange = [labelStartIndex, cursor.currIndex()];
|
|
4564
|
+
if (!text.slice(labelRange[0] + 1, labelRange[1] - 1).trim()) return null;
|
|
4565
|
+
if (cursor.curr() !== ":") return null;
|
|
4566
|
+
const label = {
|
|
4567
|
+
text: text.slice(...labelRange),
|
|
4568
|
+
range: labelRange
|
|
4569
|
+
};
|
|
4570
|
+
cursor.next();
|
|
4571
|
+
cursor.skipSpaces();
|
|
4572
|
+
let destination;
|
|
4573
|
+
const destinationStartIndex = cursor.currIndex();
|
|
4574
|
+
if (cursor.curr() === "<") {
|
|
4575
|
+
cursor.next();
|
|
4576
|
+
if (!cursor.skipUntilEnd((c) => c === ">")) return null;
|
|
4577
|
+
cursor.next();
|
|
4578
|
+
const destinationRange = [destinationStartIndex, cursor.currIndex()];
|
|
4579
|
+
destination = {
|
|
4580
|
+
type: "pointy-bracketed",
|
|
4581
|
+
text: text.slice(...destinationRange),
|
|
4582
|
+
range: destinationRange
|
|
4583
|
+
};
|
|
4584
|
+
} else {
|
|
4585
|
+
if (cursor.finished()) return null;
|
|
4586
|
+
cursor.skipUntilEnd((c, i) => cursor.isWhitespace(i) || isAsciiControlCharacter(c));
|
|
4587
|
+
const destinationRange = [destinationStartIndex, cursor.currIndex()];
|
|
4588
|
+
destination = {
|
|
4589
|
+
type: "bare",
|
|
4590
|
+
text: text.slice(...destinationRange),
|
|
4591
|
+
range: destinationRange
|
|
4592
|
+
};
|
|
4427
4593
|
}
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
},
|
|
4434
|
-
end: {
|
|
4435
|
-
line: line.line,
|
|
4436
|
-
column: prefix.length + spaceBefore.length + underlineText.length + 1
|
|
4437
|
-
}
|
|
4594
|
+
cursor.skipSpaces();
|
|
4595
|
+
if (cursor.finished()) return {
|
|
4596
|
+
label,
|
|
4597
|
+
destination,
|
|
4598
|
+
title: null
|
|
4438
4599
|
};
|
|
4600
|
+
let title;
|
|
4601
|
+
const titleStartIndex = cursor.currIndex();
|
|
4602
|
+
const startChar = cursor.curr();
|
|
4603
|
+
if (startChar === "'" || startChar === "\"" || startChar === "(") {
|
|
4604
|
+
cursor.next();
|
|
4605
|
+
const endChar = startChar === "(" ? ")" : startChar;
|
|
4606
|
+
if (!cursor.skipUntilEnd((c) => c === endChar)) return null;
|
|
4607
|
+
cursor.next();
|
|
4608
|
+
const titleRange = [titleStartIndex, cursor.currIndex()];
|
|
4609
|
+
title = {
|
|
4610
|
+
type: startChar === "'" ? "single-quoted" : startChar === "\"" ? "double-quoted" : "parenthesized",
|
|
4611
|
+
text: text.slice(...titleRange),
|
|
4612
|
+
range: titleRange
|
|
4613
|
+
};
|
|
4614
|
+
} else return null;
|
|
4615
|
+
cursor.skipSpaces();
|
|
4616
|
+
if (!cursor.finished()) return null;
|
|
4439
4617
|
return {
|
|
4440
|
-
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
marker,
|
|
4444
|
-
raws: {
|
|
4445
|
-
prefix,
|
|
4446
|
-
spaceBefore,
|
|
4447
|
-
spaceAfter
|
|
4448
|
-
}
|
|
4618
|
+
label,
|
|
4619
|
+
destination,
|
|
4620
|
+
title
|
|
4449
4621
|
};
|
|
4450
4622
|
}
|
|
4451
4623
|
|
|
4452
|
-
//#endregion
|
|
4453
|
-
//#region src/rules/level1-heading-style.ts
|
|
4454
|
-
var level1_heading_style_default = createRule("level1-heading-style", {
|
|
4455
|
-
meta: {
|
|
4456
|
-
type: "layout",
|
|
4457
|
-
docs: {
|
|
4458
|
-
description: "enforce consistent style for level 1 headings",
|
|
4459
|
-
categories: ["standard"],
|
|
4460
|
-
listCategory: "Stylistic"
|
|
4461
|
-
},
|
|
4462
|
-
fixable: "code",
|
|
4463
|
-
hasSuggestions: false,
|
|
4464
|
-
schema: [{
|
|
4465
|
-
type: "object",
|
|
4466
|
-
properties: {
|
|
4467
|
-
style: { enum: ["atx", "setext"] },
|
|
4468
|
-
allowMultilineSetext: { type: "boolean" }
|
|
4469
|
-
},
|
|
4470
|
-
additionalProperties: false
|
|
4471
|
-
}],
|
|
4472
|
-
messages: {
|
|
4473
|
-
expectedAtx: "Expected ATX style heading (# Heading).",
|
|
4474
|
-
expectedSetext: "Expected Setext style heading (Heading\\n======).",
|
|
4475
|
-
multilineSetextNotAllowed: "Multiline Setext headings are not allowed."
|
|
4476
|
-
}
|
|
4477
|
-
},
|
|
4478
|
-
create(context) {
|
|
4479
|
-
const sourceCode = context.sourceCode;
|
|
4480
|
-
const opt = context.options[0] || {};
|
|
4481
|
-
const style = opt.style ?? "atx";
|
|
4482
|
-
const allowMultilineSetext = opt.allowMultilineSetext;
|
|
4483
|
-
return { heading(node) {
|
|
4484
|
-
if (node.depth !== 1) return;
|
|
4485
|
-
const headingKind = getHeadingKind(sourceCode, node);
|
|
4486
|
-
if (style === "atx") {
|
|
4487
|
-
if (headingKind !== "setext") return;
|
|
4488
|
-
const parsed = parseSetextHeading(sourceCode, node);
|
|
4489
|
-
if (!parsed) return;
|
|
4490
|
-
if (parsed.contentLines.length > 1) {
|
|
4491
|
-
if (allowMultilineSetext) return;
|
|
4492
|
-
context.report({
|
|
4493
|
-
node,
|
|
4494
|
-
messageId: "multilineSetextNotAllowed"
|
|
4495
|
-
});
|
|
4496
|
-
return;
|
|
4497
|
-
}
|
|
4498
|
-
context.report({
|
|
4499
|
-
node,
|
|
4500
|
-
messageId: "expectedAtx",
|
|
4501
|
-
*fix(fixer) {
|
|
4502
|
-
const heading = parsed.contentLines[0];
|
|
4503
|
-
yield fixer.insertTextBeforeRange(heading.range, "# ");
|
|
4504
|
-
const lines = getParsedLines(sourceCode);
|
|
4505
|
-
yield fixer.removeRange(lines.get(parsed.underline.loc.start.line).range);
|
|
4506
|
-
}
|
|
4507
|
-
});
|
|
4508
|
-
} else if (style === "setext") {
|
|
4509
|
-
if (headingKind !== "atx" || node.children.length === 0) return;
|
|
4510
|
-
context.report({
|
|
4511
|
-
node,
|
|
4512
|
-
messageId: "expectedSetext",
|
|
4513
|
-
*fix(fixer) {
|
|
4514
|
-
const parsed = parseATXHeading(sourceCode, node);
|
|
4515
|
-
if (!parsed) return;
|
|
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]]);
|
|
4518
|
-
const lines = getParsedLines(sourceCode);
|
|
4519
|
-
const underline = "=".repeat(Math.max(getTextWidth(parsed.content.text), 3));
|
|
4520
|
-
const appendingText = `\n${lines.get(parsed.openingSequence.loc.start.line).text.slice(0, parsed.openingSequence.loc.start.column - 1)}${underline}`;
|
|
4521
|
-
yield fixer.insertTextAfter(node, appendingText);
|
|
4522
|
-
}
|
|
4523
|
-
});
|
|
4524
|
-
}
|
|
4525
|
-
} };
|
|
4526
|
-
}
|
|
4527
|
-
});
|
|
4528
|
-
|
|
4529
|
-
//#endregion
|
|
4530
|
-
//#region src/rules/level2-heading-style.ts
|
|
4531
|
-
var level2_heading_style_default = createRule("level2-heading-style", {
|
|
4532
|
-
meta: {
|
|
4533
|
-
type: "layout",
|
|
4534
|
-
docs: {
|
|
4535
|
-
description: "enforce consistent style for level 2 headings",
|
|
4536
|
-
categories: ["standard"],
|
|
4537
|
-
listCategory: "Stylistic"
|
|
4538
|
-
},
|
|
4539
|
-
fixable: "code",
|
|
4540
|
-
hasSuggestions: false,
|
|
4541
|
-
schema: [{
|
|
4542
|
-
type: "object",
|
|
4543
|
-
properties: {
|
|
4544
|
-
style: { enum: ["atx", "setext"] },
|
|
4545
|
-
allowMultilineSetext: { type: "boolean" }
|
|
4546
|
-
},
|
|
4547
|
-
additionalProperties: false
|
|
4548
|
-
}],
|
|
4549
|
-
messages: {
|
|
4550
|
-
expectedAtx: "Expected ATX style heading (## Heading).",
|
|
4551
|
-
expectedSetext: "Expected Setext style heading (Heading\\n------).",
|
|
4552
|
-
multilineSetextNotAllowed: "Multiline Setext headings are not allowed."
|
|
4553
|
-
}
|
|
4554
|
-
},
|
|
4555
|
-
create(context) {
|
|
4556
|
-
const sourceCode = context.sourceCode;
|
|
4557
|
-
const opt = context.options[0] || {};
|
|
4558
|
-
const style = opt.style ?? "atx";
|
|
4559
|
-
const allowMultilineSetext = opt.allowMultilineSetext;
|
|
4560
|
-
return { heading(node) {
|
|
4561
|
-
if (node.depth !== 2) return;
|
|
4562
|
-
const headingKind = getHeadingKind(sourceCode, node);
|
|
4563
|
-
if (style === "atx") {
|
|
4564
|
-
if (headingKind !== "setext") return;
|
|
4565
|
-
const parsed = parseSetextHeading(sourceCode, node);
|
|
4566
|
-
if (!parsed) return;
|
|
4567
|
-
if (parsed.contentLines.length > 1) {
|
|
4568
|
-
if (allowMultilineSetext) return;
|
|
4569
|
-
context.report({
|
|
4570
|
-
node,
|
|
4571
|
-
messageId: "multilineSetextNotAllowed"
|
|
4572
|
-
});
|
|
4573
|
-
return;
|
|
4574
|
-
}
|
|
4575
|
-
context.report({
|
|
4576
|
-
node,
|
|
4577
|
-
messageId: "expectedAtx",
|
|
4578
|
-
*fix(fixer) {
|
|
4579
|
-
const heading = parsed.contentLines[0];
|
|
4580
|
-
yield fixer.insertTextBeforeRange(heading.range, "## ");
|
|
4581
|
-
const lines = getParsedLines(sourceCode);
|
|
4582
|
-
yield fixer.removeRange(lines.get(parsed.underline.loc.start.line).range);
|
|
4583
|
-
}
|
|
4584
|
-
});
|
|
4585
|
-
} else if (style === "setext") {
|
|
4586
|
-
if (headingKind !== "atx" || node.children.length === 0) return;
|
|
4587
|
-
context.report({
|
|
4588
|
-
node,
|
|
4589
|
-
messageId: "expectedSetext",
|
|
4590
|
-
*fix(fixer) {
|
|
4591
|
-
const parsed = parseATXHeading(sourceCode, node);
|
|
4592
|
-
if (!parsed) return;
|
|
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]]);
|
|
4595
|
-
const lines = getParsedLines(sourceCode);
|
|
4596
|
-
const underline = "-".repeat(Math.max(getTextWidth(parsed.content.text), 3));
|
|
4597
|
-
const appendingText = `\n${lines.get(parsed.openingSequence.loc.start.line).text.slice(0, parsed.openingSequence.loc.start.column - 1)}${underline}`;
|
|
4598
|
-
yield fixer.insertTextAfter(node, appendingText);
|
|
4599
|
-
}
|
|
4600
|
-
});
|
|
4601
|
-
}
|
|
4602
|
-
} };
|
|
4603
|
-
}
|
|
4604
|
-
});
|
|
4605
|
-
|
|
4606
4624
|
//#endregion
|
|
4607
4625
|
//#region src/utils/link.ts
|
|
4608
4626
|
/**
|
|
@@ -4653,92 +4671,73 @@ function parseInlineLink(sourceCode, node) {
|
|
|
4653
4671
|
* Parse the inline link destination and link title from the given text.
|
|
4654
4672
|
*/
|
|
4655
4673
|
function parseInlineLinkDestAndTitleFromText(text) {
|
|
4656
|
-
|
|
4657
|
-
|
|
4658
|
-
|
|
4659
|
-
skipSpaces();
|
|
4674
|
+
if (!text.startsWith("(")) return null;
|
|
4675
|
+
const cursor = new ForwardCharacterCursor(text);
|
|
4676
|
+
cursor.next();
|
|
4677
|
+
cursor.skipSpaces();
|
|
4660
4678
|
let destination;
|
|
4661
|
-
const destinationStartIndex =
|
|
4662
|
-
if (
|
|
4663
|
-
|
|
4664
|
-
if (!skipUntilEnd((c) => c === ">")) return null;
|
|
4665
|
-
|
|
4666
|
-
const destinationRange = [destinationStartIndex,
|
|
4679
|
+
const destinationStartIndex = cursor.currIndex();
|
|
4680
|
+
if (cursor.curr() === "<") {
|
|
4681
|
+
cursor.next();
|
|
4682
|
+
if (!cursor.skipUntilEnd((c) => c === ">")) return null;
|
|
4683
|
+
cursor.next();
|
|
4684
|
+
const destinationRange = [destinationStartIndex, cursor.currIndex()];
|
|
4667
4685
|
destination = {
|
|
4668
4686
|
type: "pointy-bracketed",
|
|
4669
4687
|
text: text.slice(...destinationRange),
|
|
4670
4688
|
range: destinationRange
|
|
4671
4689
|
};
|
|
4672
4690
|
} else {
|
|
4673
|
-
if (
|
|
4674
|
-
skipUntilEnd((c) => isWhitespace(
|
|
4675
|
-
const destinationRange = [destinationStartIndex,
|
|
4691
|
+
if (cursor.finished()) return null;
|
|
4692
|
+
cursor.skipUntilEnd((c, i) => cursor.isWhitespace(i) || isAsciiControlCharacter(c) || c === ")");
|
|
4693
|
+
const destinationRange = [destinationStartIndex, cursor.currIndex()];
|
|
4676
4694
|
destination = {
|
|
4677
4695
|
type: "bare",
|
|
4678
4696
|
text: text.slice(...destinationRange),
|
|
4679
4697
|
range: destinationRange
|
|
4680
4698
|
};
|
|
4681
4699
|
}
|
|
4682
|
-
skipSpaces();
|
|
4683
|
-
if (
|
|
4684
|
-
const closingParenStartIndex$1 =
|
|
4685
|
-
|
|
4686
|
-
skipSpaces();
|
|
4687
|
-
if (
|
|
4700
|
+
cursor.skipSpaces();
|
|
4701
|
+
if (cursor.curr() === ")") {
|
|
4702
|
+
const closingParenStartIndex$1 = cursor.currIndex();
|
|
4703
|
+
cursor.next();
|
|
4704
|
+
cursor.skipSpaces();
|
|
4705
|
+
if (!cursor.finished()) return null;
|
|
4688
4706
|
return {
|
|
4689
4707
|
openingParen: { range: [0, 1] },
|
|
4690
4708
|
destination,
|
|
4691
4709
|
title: null,
|
|
4692
|
-
closingParen: { range: [closingParenStartIndex$1,
|
|
4710
|
+
closingParen: { range: [closingParenStartIndex$1, closingParenStartIndex$1 + 1] }
|
|
4693
4711
|
};
|
|
4694
4712
|
}
|
|
4695
|
-
if (
|
|
4713
|
+
if (cursor.finished()) return null;
|
|
4696
4714
|
let title;
|
|
4697
|
-
const titleStartIndex =
|
|
4698
|
-
const startChar =
|
|
4715
|
+
const titleStartIndex = cursor.currIndex();
|
|
4716
|
+
const startChar = cursor.curr();
|
|
4699
4717
|
if (startChar === "'" || startChar === "\"" || startChar === "(") {
|
|
4700
|
-
|
|
4718
|
+
cursor.next();
|
|
4701
4719
|
const endChar = startChar === "(" ? ")" : startChar;
|
|
4702
|
-
if (!skipUntilEnd((c) => c === endChar)) return null;
|
|
4703
|
-
|
|
4704
|
-
const titleRange = [titleStartIndex,
|
|
4720
|
+
if (!cursor.skipUntilEnd((c) => c === endChar)) return null;
|
|
4721
|
+
cursor.next();
|
|
4722
|
+
const titleRange = [titleStartIndex, cursor.currIndex()];
|
|
4705
4723
|
title = {
|
|
4706
4724
|
type: startChar === "'" ? "single-quoted" : startChar === "\"" ? "double-quoted" : "parenthesized",
|
|
4707
4725
|
text: text.slice(...titleRange),
|
|
4708
4726
|
range: titleRange
|
|
4709
4727
|
};
|
|
4710
4728
|
} else return null;
|
|
4711
|
-
skipSpaces();
|
|
4712
|
-
if (
|
|
4713
|
-
const closingParenStartIndex =
|
|
4714
|
-
|
|
4715
|
-
skipSpaces();
|
|
4716
|
-
if (
|
|
4729
|
+
cursor.skipSpaces();
|
|
4730
|
+
if (cursor.curr() !== ")") return null;
|
|
4731
|
+
const closingParenStartIndex = cursor.currIndex();
|
|
4732
|
+
cursor.next();
|
|
4733
|
+
cursor.skipSpaces();
|
|
4734
|
+
if (!cursor.finished()) return null;
|
|
4717
4735
|
return {
|
|
4718
4736
|
openingParen: { range: [0, 1] },
|
|
4719
4737
|
destination,
|
|
4720
4738
|
title,
|
|
4721
|
-
closingParen: { range: [closingParenStartIndex,
|
|
4739
|
+
closingParen: { range: [closingParenStartIndex, closingParenStartIndex + 1] }
|
|
4722
4740
|
};
|
|
4723
|
-
/**
|
|
4724
|
-
* Skip spaces
|
|
4725
|
-
*/
|
|
4726
|
-
function skipSpaces() {
|
|
4727
|
-
while (index < text.length && isWhitespace(text[index])) index++;
|
|
4728
|
-
}
|
|
4729
|
-
/**
|
|
4730
|
-
* Skip until the end by the given condition
|
|
4731
|
-
*/
|
|
4732
|
-
function skipUntilEnd(checkEnd) {
|
|
4733
|
-
while (index < text.length) {
|
|
4734
|
-
const c = text[index];
|
|
4735
|
-
if (checkEnd(c)) return true;
|
|
4736
|
-
index++;
|
|
4737
|
-
if (c !== "\\") continue;
|
|
4738
|
-
if (index < text.length && (text[index] === "\\" || checkEnd(text[index])) && !isWhitespace(text[index])) index++;
|
|
4739
|
-
}
|
|
4740
|
-
return false;
|
|
4741
|
-
}
|
|
4742
4741
|
}
|
|
4743
4742
|
|
|
4744
4743
|
//#endregion
|
|
@@ -4845,58 +4844,57 @@ function parseImage(sourceCode, node) {
|
|
|
4845
4844
|
*/
|
|
4846
4845
|
function parseImageFromText(text) {
|
|
4847
4846
|
if (!text.startsWith("![")) return null;
|
|
4848
|
-
|
|
4849
|
-
skipSpaces();
|
|
4850
|
-
if (
|
|
4851
|
-
const closingParenStartIndex =
|
|
4852
|
-
|
|
4853
|
-
skipSpaces();
|
|
4847
|
+
const cursor = new BackwardCharacterCursor(text);
|
|
4848
|
+
cursor.skipSpaces();
|
|
4849
|
+
if (cursor.curr() !== ")") return null;
|
|
4850
|
+
const closingParenStartIndex = cursor.currIndex();
|
|
4851
|
+
cursor.prev();
|
|
4852
|
+
cursor.skipSpaces();
|
|
4854
4853
|
let title = null;
|
|
4855
|
-
const titleEndIndex =
|
|
4856
|
-
const endChar =
|
|
4854
|
+
const titleEndIndex = cursor.currIndex() + 1;
|
|
4855
|
+
const endChar = cursor.curr();
|
|
4857
4856
|
if (endChar === "'" || endChar === "\"" || endChar === ")") {
|
|
4858
|
-
|
|
4857
|
+
cursor.prev();
|
|
4859
4858
|
const startChar = endChar === ")" ? "(" : endChar;
|
|
4860
|
-
if (skipUntilStart((c) => c === startChar)) {
|
|
4861
|
-
const titleRange = [
|
|
4862
|
-
|
|
4859
|
+
if (cursor.skipUntilStart((c) => c === startChar)) {
|
|
4860
|
+
const titleRange = [cursor.currIndex(), titleEndIndex];
|
|
4861
|
+
cursor.prev();
|
|
4863
4862
|
title = {
|
|
4864
4863
|
type: startChar === "'" ? "single-quoted" : startChar === "\"" ? "double-quoted" : "parenthesized",
|
|
4865
4864
|
text: text.slice(...titleRange),
|
|
4866
4865
|
range: titleRange
|
|
4867
4866
|
};
|
|
4868
|
-
skipSpaces();
|
|
4867
|
+
cursor.skipSpaces();
|
|
4869
4868
|
}
|
|
4870
4869
|
}
|
|
4871
|
-
if (title == null)
|
|
4870
|
+
if (title == null) cursor.setCurrIndex(titleEndIndex - 1);
|
|
4872
4871
|
let destination;
|
|
4873
|
-
const destinationEndIndex =
|
|
4874
|
-
if (
|
|
4875
|
-
|
|
4876
|
-
if (!skipUntilStart((c) => c === "<")) return null;
|
|
4877
|
-
const destinationRange = [
|
|
4878
|
-
|
|
4872
|
+
const destinationEndIndex = cursor.currIndex() + 1;
|
|
4873
|
+
if (cursor.curr() === ">") {
|
|
4874
|
+
cursor.prev();
|
|
4875
|
+
if (!cursor.skipUntilStart((c) => c === "<")) return null;
|
|
4876
|
+
const destinationRange = [cursor.currIndex(), destinationEndIndex];
|
|
4877
|
+
cursor.prev();
|
|
4879
4878
|
destination = {
|
|
4880
4879
|
type: "pointy-bracketed",
|
|
4881
4880
|
text: text.slice(...destinationRange),
|
|
4882
4881
|
range: destinationRange
|
|
4883
4882
|
};
|
|
4884
4883
|
} else {
|
|
4885
|
-
if (
|
|
4886
|
-
skipUntilStart((c) => isWhitespace(
|
|
4887
|
-
const destinationRange = [
|
|
4884
|
+
if (cursor.finished()) return null;
|
|
4885
|
+
cursor.skipUntilStart((c, i) => cursor.isWhitespace(i) || isAsciiControlCharacter(c) || c === "(");
|
|
4886
|
+
const destinationRange = [cursor.currIndex() + 1, destinationEndIndex];
|
|
4888
4887
|
destination = {
|
|
4889
4888
|
type: "bare",
|
|
4890
4889
|
text: text.slice(...destinationRange),
|
|
4891
4890
|
range: destinationRange
|
|
4892
4891
|
};
|
|
4893
4892
|
}
|
|
4894
|
-
skipSpaces();
|
|
4895
|
-
if (
|
|
4896
|
-
const openingParenStartIndex =
|
|
4897
|
-
|
|
4898
|
-
|
|
4899
|
-
const textRange = [1, index + 1];
|
|
4893
|
+
cursor.skipSpaces();
|
|
4894
|
+
if (cursor.curr() !== "(") return null;
|
|
4895
|
+
const openingParenStartIndex = cursor.currIndex();
|
|
4896
|
+
if (cursor.prev() !== "]") return null;
|
|
4897
|
+
const textRange = [1, cursor.currIndex() + 1];
|
|
4900
4898
|
return {
|
|
4901
4899
|
openingParen: { range: [openingParenStartIndex, openingParenStartIndex + 1] },
|
|
4902
4900
|
text: { range: textRange },
|
|
@@ -4904,33 +4902,6 @@ function parseImageFromText(text) {
|
|
|
4904
4902
|
title,
|
|
4905
4903
|
closingParen: { range: [closingParenStartIndex, closingParenStartIndex + 1] }
|
|
4906
4904
|
};
|
|
4907
|
-
/**
|
|
4908
|
-
* Skip spaces
|
|
4909
|
-
*/
|
|
4910
|
-
function skipSpaces() {
|
|
4911
|
-
while (index >= 0 && isWhitespace(text[index])) index--;
|
|
4912
|
-
}
|
|
4913
|
-
/**
|
|
4914
|
-
* Skip until the start by the given condition
|
|
4915
|
-
*/
|
|
4916
|
-
function skipUntilStart(checkStart) {
|
|
4917
|
-
while (index >= 0) {
|
|
4918
|
-
const c = text[index];
|
|
4919
|
-
if (checkStart(c)) {
|
|
4920
|
-
if (index > 1 && !isWhitespace(c)) {
|
|
4921
|
-
let escapeText = "";
|
|
4922
|
-
while (text.endsWith(`${escapeText}\\`, index)) escapeText += "\\";
|
|
4923
|
-
if (escapeText.length % 2 === 1) {
|
|
4924
|
-
index -= escapeText.length + 1;
|
|
4925
|
-
continue;
|
|
4926
|
-
}
|
|
4927
|
-
}
|
|
4928
|
-
return true;
|
|
4929
|
-
}
|
|
4930
|
-
index--;
|
|
4931
|
-
}
|
|
4932
|
-
return false;
|
|
4933
|
-
}
|
|
4934
4905
|
}
|
|
4935
4906
|
|
|
4936
4907
|
//#endregion
|
|
@@ -4990,21 +4961,20 @@ function parseImageReference(sourceCode, node) {
|
|
|
4990
4961
|
*/
|
|
4991
4962
|
function parseFullImageReferenceFromText(text) {
|
|
4992
4963
|
if (!text.startsWith("![")) return null;
|
|
4993
|
-
|
|
4994
|
-
skipSpaces();
|
|
4995
|
-
if (
|
|
4996
|
-
const labelEndIndex =
|
|
4997
|
-
|
|
4998
|
-
skipSpaces();
|
|
4999
|
-
if (!skipUntilStart((c) => c === "[")) return null;
|
|
5000
|
-
const labelRange = [
|
|
5001
|
-
index--;
|
|
4964
|
+
const cursor = new BackwardCharacterCursor(text);
|
|
4965
|
+
cursor.skipSpaces();
|
|
4966
|
+
if (cursor.curr() !== "]") return null;
|
|
4967
|
+
const labelEndIndex = cursor.currIndex() + 1;
|
|
4968
|
+
cursor.prev();
|
|
4969
|
+
cursor.skipSpaces();
|
|
4970
|
+
if (!cursor.skipUntilStart((c) => c === "[")) return null;
|
|
4971
|
+
const labelRange = [cursor.currIndex(), labelEndIndex];
|
|
5002
4972
|
const label = {
|
|
5003
4973
|
text: text.slice(...labelRange),
|
|
5004
4974
|
range: labelRange
|
|
5005
4975
|
};
|
|
5006
|
-
if (
|
|
5007
|
-
const textRange = [1,
|
|
4976
|
+
if (cursor.prev() !== "]") return null;
|
|
4977
|
+
const textRange = [1, cursor.currIndex() + 1];
|
|
5008
4978
|
return {
|
|
5009
4979
|
text: {
|
|
5010
4980
|
text: text.slice(...textRange),
|
|
@@ -5012,156 +4982,1208 @@ function parseFullImageReferenceFromText(text) {
|
|
|
5012
4982
|
},
|
|
5013
4983
|
label
|
|
5014
4984
|
};
|
|
5015
|
-
/**
|
|
5016
|
-
* Skip spaces
|
|
5017
|
-
*/
|
|
5018
|
-
function skipSpaces() {
|
|
5019
|
-
while (index >= 0 && isWhitespace(text[index])) index--;
|
|
5020
|
-
}
|
|
5021
|
-
/**
|
|
5022
|
-
* Skip until the start by the given condition
|
|
5023
|
-
*/
|
|
5024
|
-
function skipUntilStart(checkStart) {
|
|
5025
|
-
while (index >= 0) {
|
|
5026
|
-
const c = text[index];
|
|
5027
|
-
if (checkStart(c)) {
|
|
5028
|
-
if (index > 1) {
|
|
5029
|
-
let escapeText = "";
|
|
5030
|
-
while (text.endsWith(`${escapeText}\\`, index)) escapeText += "\\";
|
|
5031
|
-
if (escapeText.length % 2 === 1) {
|
|
5032
|
-
index -= escapeText.length + 1;
|
|
5033
|
-
continue;
|
|
5034
|
-
}
|
|
5035
|
-
}
|
|
5036
|
-
return true;
|
|
5037
|
-
}
|
|
5038
|
-
index--;
|
|
5039
|
-
}
|
|
5040
|
-
return false;
|
|
5041
|
-
}
|
|
5042
4985
|
}
|
|
5043
4986
|
|
|
5044
4987
|
//#endregion
|
|
5045
|
-
//#region src/utils/
|
|
4988
|
+
//#region src/utils/list-item.ts
|
|
5046
4989
|
/**
|
|
5047
|
-
* Parse the
|
|
4990
|
+
* Parse the list item.
|
|
5048
4991
|
*/
|
|
5049
|
-
function
|
|
5050
|
-
const
|
|
5051
|
-
const parsed = parseLinkDefinitionFromText(text);
|
|
5052
|
-
if (!parsed) return null;
|
|
4992
|
+
function parseListItem(sourceCode, node) {
|
|
4993
|
+
const marker = getListItemMarker(sourceCode, node);
|
|
5053
4994
|
const nodeRange = sourceCode.getRange(node);
|
|
5054
|
-
const
|
|
5055
|
-
const
|
|
4995
|
+
const markerRange = [nodeRange[0], nodeRange[0] + marker.raw.length];
|
|
4996
|
+
const parsedMarker = marker.kind === "." || marker.kind === ")" ? {
|
|
4997
|
+
kind: marker.kind,
|
|
4998
|
+
text: marker.raw,
|
|
4999
|
+
value: marker.sequence.value,
|
|
5000
|
+
range: markerRange,
|
|
5001
|
+
loc: getSourceLocationFromRange(sourceCode, node, markerRange)
|
|
5002
|
+
} : {
|
|
5003
|
+
kind: marker.kind,
|
|
5004
|
+
text: marker.raw,
|
|
5005
|
+
range: markerRange,
|
|
5006
|
+
loc: getSourceLocationFromRange(sourceCode, node, markerRange)
|
|
5007
|
+
};
|
|
5008
|
+
if (node.checked == null) return {
|
|
5009
|
+
marker: parsedMarker,
|
|
5010
|
+
taskListItemMarker: null
|
|
5011
|
+
};
|
|
5012
|
+
for (let index = nodeRange[0] + marker.raw.length; index < nodeRange[1]; index++) {
|
|
5013
|
+
const c = sourceCode.text[index];
|
|
5014
|
+
if (isSpaceOrTab(c)) continue;
|
|
5015
|
+
if (c !== "[") break;
|
|
5016
|
+
const middle = sourceCode.text[index + 1];
|
|
5017
|
+
if (middle !== "x" && middle !== " ") break;
|
|
5018
|
+
if (sourceCode.text[index + 2] !== "]") break;
|
|
5019
|
+
const taskListItemMarkerRange = [index, index + 3];
|
|
5020
|
+
return {
|
|
5021
|
+
marker: parsedMarker,
|
|
5022
|
+
taskListItemMarker: {
|
|
5023
|
+
text: sourceCode.text.slice(...taskListItemMarkerRange),
|
|
5024
|
+
range: taskListItemMarkerRange,
|
|
5025
|
+
loc: getSourceLocationFromRange(sourceCode, node, taskListItemMarkerRange)
|
|
5026
|
+
}
|
|
5027
|
+
};
|
|
5028
|
+
}
|
|
5056
5029
|
return {
|
|
5057
|
-
|
|
5058
|
-
|
|
5059
|
-
|
|
5060
|
-
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
|
|
5064
|
-
|
|
5065
|
-
|
|
5066
|
-
|
|
5030
|
+
marker: parsedMarker,
|
|
5031
|
+
taskListItemMarker: null
|
|
5032
|
+
};
|
|
5033
|
+
}
|
|
5034
|
+
|
|
5035
|
+
//#endregion
|
|
5036
|
+
//#region src/rules/indent.ts
|
|
5037
|
+
/**
|
|
5038
|
+
* Parse options.
|
|
5039
|
+
*/
|
|
5040
|
+
function parseOptions$2(options) {
|
|
5041
|
+
const listItems = options?.listItems;
|
|
5042
|
+
return { listItems: {
|
|
5043
|
+
first: listItems?.first ?? 1,
|
|
5044
|
+
other: listItems?.other ?? "first",
|
|
5045
|
+
relativeTo: listItems?.relativeTo ?? "taskListMarkerEnd"
|
|
5046
|
+
} };
|
|
5047
|
+
}
|
|
5048
|
+
var indent_default = createRule("indent", {
|
|
5049
|
+
meta: {
|
|
5050
|
+
type: "layout",
|
|
5051
|
+
docs: {
|
|
5052
|
+
description: "enforce consistent indentation in Markdown files",
|
|
5053
|
+
categories: ["standard"],
|
|
5054
|
+
listCategory: "Stylistic"
|
|
5067
5055
|
},
|
|
5068
|
-
|
|
5069
|
-
|
|
5070
|
-
|
|
5071
|
-
|
|
5072
|
-
|
|
5073
|
-
|
|
5056
|
+
fixable: "whitespace",
|
|
5057
|
+
hasSuggestions: false,
|
|
5058
|
+
schema: [{
|
|
5059
|
+
type: "object",
|
|
5060
|
+
properties: { listItems: {
|
|
5061
|
+
type: "object",
|
|
5062
|
+
properties: {
|
|
5063
|
+
first: { anyOf: [{ const: "ignore" }, {
|
|
5064
|
+
type: "number",
|
|
5065
|
+
minimum: 1
|
|
5066
|
+
}] },
|
|
5067
|
+
other: { anyOf: [{ enum: ["first", "minimum"] }, {
|
|
5068
|
+
type: "number",
|
|
5069
|
+
minimum: 1
|
|
5070
|
+
}] },
|
|
5071
|
+
relativeTo: { enum: [
|
|
5072
|
+
"markerStart",
|
|
5073
|
+
"markerEnd",
|
|
5074
|
+
"taskListMarkerStart",
|
|
5075
|
+
"taskListMarkerEnd"
|
|
5076
|
+
] }
|
|
5077
|
+
},
|
|
5078
|
+
additionalProperties: false
|
|
5079
|
+
} },
|
|
5080
|
+
additionalProperties: false
|
|
5081
|
+
}],
|
|
5082
|
+
messages: {
|
|
5083
|
+
wrongIndentation: "Expected indentation of {{expected}} but found {{actual}}.",
|
|
5084
|
+
wrongIndentationFromBlockquoteMarker: "Expected indentation of {{expected}} from the blockquote marker but found {{actual}}.",
|
|
5085
|
+
wrongIndentationFromListMarker: "Expected indentation of {{expected}} from the list marker but found {{actual}}.",
|
|
5086
|
+
wrongIndentationWithTab: "Expected indentation of {{expected}} but found {{actual}} (tab width is 4).",
|
|
5087
|
+
wrongIndentationFromBlockquoteMarkerWithTab: "Expected indentation of {{expected}} from the blockquote marker but found {{actual}} (tab width is 4).",
|
|
5088
|
+
wrongIndentationFromListMarkerWithTab: "Expected indentation of {{expected}} from the list marker but found {{actual}} (tab width is 4)."
|
|
5089
|
+
}
|
|
5090
|
+
},
|
|
5091
|
+
create(context) {
|
|
5092
|
+
const sourceCode = context.sourceCode;
|
|
5093
|
+
const options = parseOptions$2(context.options[0]);
|
|
5094
|
+
class AbsBlockStack {
|
|
5095
|
+
violations = [];
|
|
5096
|
+
getCurrentBlockquote() {
|
|
5097
|
+
let block = this;
|
|
5098
|
+
while (block) {
|
|
5099
|
+
if (block.type === "blockquote") return block;
|
|
5100
|
+
block = block.upper;
|
|
5101
|
+
}
|
|
5102
|
+
return null;
|
|
5103
|
+
}
|
|
5104
|
+
getCurrentListItemAtLine(lineNumber) {
|
|
5105
|
+
let block = this;
|
|
5106
|
+
while (block) {
|
|
5107
|
+
if (block.type === "blockquote") return null;
|
|
5108
|
+
if (block.type === "listItem") {
|
|
5109
|
+
if (sourceCode.getLoc(block.node).start.line === lineNumber) return block;
|
|
5110
|
+
}
|
|
5111
|
+
block = block.upper;
|
|
5112
|
+
}
|
|
5113
|
+
return null;
|
|
5114
|
+
}
|
|
5115
|
+
}
|
|
5116
|
+
class RootStack extends AbsBlockStack {
|
|
5117
|
+
type = "root";
|
|
5118
|
+
node;
|
|
5119
|
+
upper = null;
|
|
5120
|
+
constructor(node) {
|
|
5121
|
+
super();
|
|
5122
|
+
this.node = node;
|
|
5123
|
+
}
|
|
5124
|
+
getExpectedIndent() {
|
|
5125
|
+
return 0;
|
|
5126
|
+
}
|
|
5127
|
+
}
|
|
5128
|
+
class BlockquoteStack extends AbsBlockStack {
|
|
5129
|
+
type = "blockquote";
|
|
5130
|
+
node;
|
|
5131
|
+
upper;
|
|
5132
|
+
_expectedIndent;
|
|
5133
|
+
_markerIndent;
|
|
5134
|
+
constructor(node) {
|
|
5135
|
+
super();
|
|
5136
|
+
this.node = node;
|
|
5137
|
+
this.upper = blockStack;
|
|
5138
|
+
}
|
|
5139
|
+
getExpectedIndent() {
|
|
5140
|
+
if (this._expectedIndent == null) this._expectedIndent = this.getMarkerIndent() + 1 + 1;
|
|
5141
|
+
return this._expectedIndent;
|
|
5142
|
+
}
|
|
5143
|
+
getMarkerIndent() {
|
|
5144
|
+
if (this._markerIndent == null) {
|
|
5145
|
+
const loc = sourceCode.getLoc(this.node);
|
|
5146
|
+
this._markerIndent = getWidth(sourceCode.lines[loc.start.line - 1].slice(0, loc.start.column - 1));
|
|
5147
|
+
}
|
|
5148
|
+
return this._markerIndent;
|
|
5149
|
+
}
|
|
5150
|
+
}
|
|
5151
|
+
class ListItemStack extends AbsBlockStack {
|
|
5152
|
+
type = "listItem";
|
|
5153
|
+
node;
|
|
5154
|
+
upper;
|
|
5155
|
+
_expectedIndentForFirstLine;
|
|
5156
|
+
_expectedIndentForOtherLines;
|
|
5157
|
+
_parsed;
|
|
5158
|
+
nodeLoc;
|
|
5159
|
+
constructor(node) {
|
|
5160
|
+
super();
|
|
5161
|
+
this.node = node;
|
|
5162
|
+
this.upper = blockStack;
|
|
5163
|
+
this.nodeLoc = sourceCode.getLoc(this.node);
|
|
5164
|
+
}
|
|
5165
|
+
getParsedListItem() {
|
|
5166
|
+
return this._parsed ??= parseListItem(sourceCode, this.node);
|
|
5167
|
+
}
|
|
5168
|
+
getExpectedIndent({ lineNumber, block }) {
|
|
5169
|
+
const loc = this.nodeLoc;
|
|
5170
|
+
if (lineNumber === loc.start.line) return this.getExpectedIndentForFirstLine();
|
|
5171
|
+
const expected = this.getExpectedIndentAfterFirstLine();
|
|
5172
|
+
if (expected === "ignore") return "ignore";
|
|
5173
|
+
if (!block) return expected;
|
|
5174
|
+
const actualFirstLineIndent = this.getActualFirstLineIndent({ withoutTaskListMarker: true });
|
|
5175
|
+
if (actualFirstLineIndent != null) return Math.min(expected, actualFirstLineIndent + 3);
|
|
5176
|
+
return expected;
|
|
5177
|
+
}
|
|
5178
|
+
getExpectedIndentForFirstLine() {
|
|
5179
|
+
if (options.listItems.first === "ignore") return "ignore";
|
|
5180
|
+
if (this._expectedIndentForFirstLine != null) return this._expectedIndentForFirstLine;
|
|
5181
|
+
const loc = this.nodeLoc;
|
|
5182
|
+
const parsed = this.getParsedListItem();
|
|
5183
|
+
const lineText = sourceCode.lines[loc.start.line - 1];
|
|
5184
|
+
if (options.listItems.relativeTo === "markerStart") {
|
|
5185
|
+
const baseIndent = getWidth(lineText.slice(0, loc.start.column - 1));
|
|
5186
|
+
return this._expectedIndentForFirstLine = Math.max(baseIndent + options.listItems.first, baseIndent + parsed.marker.text.length + 1);
|
|
5187
|
+
}
|
|
5188
|
+
if (options.listItems.relativeTo === "taskListMarkerEnd" && parsed.taskListItemMarker) return this._expectedIndentForFirstLine = getWidth(lineText.slice(0, parsed.taskListItemMarker.loc.end.column - 1)) + options.listItems.first;
|
|
5189
|
+
return this._expectedIndentForFirstLine = getWidth(lineText.slice(0, parsed.marker.loc.end.column - 1)) + options.listItems.first;
|
|
5190
|
+
}
|
|
5191
|
+
getExpectedIndentAfterFirstLine() {
|
|
5192
|
+
if (this._expectedIndentForOtherLines != null) return this._expectedIndentForOtherLines;
|
|
5193
|
+
const loc = this.nodeLoc;
|
|
5194
|
+
if (options.listItems.other === "first") {
|
|
5195
|
+
const firstLineIndent = this.getExpectedIndentForFirstLine();
|
|
5196
|
+
if (firstLineIndent === "ignore") {
|
|
5197
|
+
const actualFirstLineIndent = this.getActualFirstLineIndent();
|
|
5198
|
+
if (actualFirstLineIndent != null) return this._expectedIndentForOtherLines = actualFirstLineIndent;
|
|
5199
|
+
for (const child of this.node.children) {
|
|
5200
|
+
const childLoc = sourceCode.getLoc(child);
|
|
5201
|
+
if (loc.start.line < childLoc.start.line) return this._expectedIndentForOtherLines = getWidth(sourceCode.lines[childLoc.start.line - 1].slice(0, childLoc.start.column - 1));
|
|
5202
|
+
}
|
|
5203
|
+
}
|
|
5204
|
+
return this._expectedIndentForOtherLines = firstLineIndent;
|
|
5205
|
+
}
|
|
5206
|
+
if (options.listItems.other === "minimum") return this._expectedIndentForOtherLines = this.getMinimumLineIndent();
|
|
5207
|
+
const lineText = sourceCode.lines[loc.start.line - 1];
|
|
5208
|
+
if (options.listItems.relativeTo === "markerStart") {
|
|
5209
|
+
const baseIndent = getWidth(lineText.slice(0, loc.start.column - 1));
|
|
5210
|
+
const minimumLineIndent = this.getMinimumLineIndent();
|
|
5211
|
+
return this._expectedIndentForOtherLines = Math.max(baseIndent + options.listItems.other, minimumLineIndent);
|
|
5212
|
+
}
|
|
5213
|
+
const parsed = this.getParsedListItem();
|
|
5214
|
+
if (options.listItems.relativeTo === "taskListMarkerEnd" && parsed.taskListItemMarker) return this._expectedIndentForOtherLines = getWidth(lineText.slice(0, parsed.taskListItemMarker.loc.end.column - 1)) + options.listItems.other;
|
|
5215
|
+
return this._expectedIndentForOtherLines = getWidth(lineText.slice(0, parsed.marker.loc.end.column - 1)) + options.listItems.other;
|
|
5216
|
+
}
|
|
5217
|
+
getMinimumLineIndent() {
|
|
5218
|
+
const actualFirstLineIndent = this.getActualFirstLineIndent({ withoutTaskListMarker: true });
|
|
5219
|
+
if (actualFirstLineIndent != null) return this._expectedIndentForOtherLines = actualFirstLineIndent;
|
|
5220
|
+
const parsed = this.getParsedListItem();
|
|
5221
|
+
const lineText = sourceCode.lines[parsed.marker.loc.end.line - 1];
|
|
5222
|
+
return getWidth(lineText.slice(0, parsed.marker.loc.end.column - 1)) + 1;
|
|
5223
|
+
}
|
|
5224
|
+
getActualFirstLineIndent({ withoutTaskListMarker = false } = {}) {
|
|
5225
|
+
const parsed = this.getParsedListItem();
|
|
5226
|
+
const markerEndPos = withoutTaskListMarker ? parsed.marker.loc.end : parsed.taskListItemMarker?.loc.end ?? parsed.marker.loc.end;
|
|
5227
|
+
const lineText = sourceCode.lines[markerEndPos.line - 1];
|
|
5228
|
+
const afterMarkerText = lineText.slice(markerEndPos.column - 1);
|
|
5229
|
+
const trimmedAfterMarkerText = afterMarkerText.trimStart();
|
|
5230
|
+
if (trimmedAfterMarkerText) {
|
|
5231
|
+
const afterMarkerSpacesLength = afterMarkerText.length - trimmedAfterMarkerText.length;
|
|
5232
|
+
return getWidth(lineText.slice(0, markerEndPos.column - 1 + afterMarkerSpacesLength));
|
|
5233
|
+
}
|
|
5234
|
+
return null;
|
|
5235
|
+
}
|
|
5236
|
+
}
|
|
5237
|
+
class FootnoteDefinitionStack extends AbsBlockStack {
|
|
5238
|
+
type = "footnoteDefinition";
|
|
5239
|
+
node;
|
|
5240
|
+
upper;
|
|
5241
|
+
_expectedIndent;
|
|
5242
|
+
constructor(node) {
|
|
5243
|
+
super();
|
|
5244
|
+
this.node = node;
|
|
5245
|
+
this.upper = blockStack;
|
|
5246
|
+
}
|
|
5247
|
+
getExpectedIndent() {
|
|
5248
|
+
if (this._expectedIndent == null) {
|
|
5249
|
+
const loc = sourceCode.getLoc(this.node);
|
|
5250
|
+
this._expectedIndent = getWidth(sourceCode.lines[loc.start.line - 1].slice(0, loc.start.column - 1)) + 4;
|
|
5251
|
+
}
|
|
5252
|
+
return this._expectedIndent;
|
|
5253
|
+
}
|
|
5254
|
+
}
|
|
5255
|
+
class LinkStack extends AbsBlockStack {
|
|
5256
|
+
type = "link";
|
|
5257
|
+
node;
|
|
5258
|
+
upper;
|
|
5259
|
+
nodeLoc;
|
|
5260
|
+
constructor(node) {
|
|
5261
|
+
super();
|
|
5262
|
+
this.node = node;
|
|
5263
|
+
this.upper = blockStack;
|
|
5264
|
+
this.nodeLoc = sourceCode.getLoc(this.node);
|
|
5265
|
+
}
|
|
5266
|
+
getExpectedIndent(ctx) {
|
|
5267
|
+
const loc = this.nodeLoc;
|
|
5268
|
+
if (ctx.lineNumber === loc.start.line) return this.upper.getExpectedIndent(ctx);
|
|
5269
|
+
const base = this.upper.getExpectedIndent({
|
|
5270
|
+
lineNumber: loc.start.line,
|
|
5271
|
+
block: ctx.block
|
|
5272
|
+
});
|
|
5273
|
+
if (base === "ignore") return "ignore";
|
|
5274
|
+
return base + 2;
|
|
5275
|
+
}
|
|
5276
|
+
}
|
|
5277
|
+
let blockStack = new RootStack(sourceCode.ast);
|
|
5278
|
+
const reportedLocations = Object.create(null);
|
|
5279
|
+
/**
|
|
5280
|
+
* Reported locations (line and column) to avoid duplicate reports.
|
|
5281
|
+
*/
|
|
5282
|
+
function reportIncorrectIndent(violation) {
|
|
5283
|
+
const reportedColumns = reportedLocations[violation.loc.start.line] ??= /* @__PURE__ */ new Set();
|
|
5284
|
+
if (reportedColumns.has(violation.loc.start.column)) return;
|
|
5285
|
+
reportedColumns.add(violation.loc.start.column);
|
|
5286
|
+
blockStack.violations.push(violation);
|
|
5287
|
+
}
|
|
5288
|
+
/**
|
|
5289
|
+
* Flush violations to the context.
|
|
5290
|
+
*/
|
|
5291
|
+
function flushViolations({ violations }) {
|
|
5292
|
+
for (const violation of violations) context.report({
|
|
5293
|
+
loc: violation.loc,
|
|
5294
|
+
messageId: violation.messageId,
|
|
5295
|
+
data: {
|
|
5296
|
+
expected: String(violation.data.expected),
|
|
5297
|
+
actual: String(violation.data.actual)
|
|
5298
|
+
},
|
|
5299
|
+
fix(fixer) {
|
|
5300
|
+
const result = [];
|
|
5301
|
+
for (const { fix } of violations) result.push(...fix(fixer));
|
|
5302
|
+
return result;
|
|
5303
|
+
}
|
|
5304
|
+
});
|
|
5305
|
+
}
|
|
5306
|
+
return {
|
|
5307
|
+
thematicBreak: verifyThematicBreak,
|
|
5308
|
+
heading: verifyHeading,
|
|
5309
|
+
code: verifyCodeBlock,
|
|
5310
|
+
html: verifyHtml,
|
|
5311
|
+
definition: verifyLinkDefinition,
|
|
5312
|
+
table: verifyTable,
|
|
5313
|
+
list: verifyList,
|
|
5314
|
+
inlineCode: verifyInlineCode,
|
|
5315
|
+
emphasis: verifyEmphasisOrStrongOrDelete,
|
|
5316
|
+
strong: verifyEmphasisOrStrongOrDelete,
|
|
5317
|
+
delete: verifyEmphasisOrStrongOrDelete,
|
|
5318
|
+
image: verifyImage,
|
|
5319
|
+
imageReference: verifyImageReference,
|
|
5320
|
+
footnoteReference: verifyInline,
|
|
5321
|
+
break: verifyInline,
|
|
5322
|
+
text: verifyText,
|
|
5323
|
+
blockquote(node) {
|
|
5324
|
+
verifyBlockquote(node);
|
|
5325
|
+
blockStack = new BlockquoteStack(node);
|
|
5326
|
+
},
|
|
5327
|
+
listItem(node) {
|
|
5328
|
+
blockStack = new ListItemStack(node);
|
|
5329
|
+
},
|
|
5330
|
+
footnoteDefinition(node) {
|
|
5331
|
+
verifyFootnoteDefinition(node);
|
|
5332
|
+
blockStack = new FootnoteDefinitionStack(node);
|
|
5333
|
+
},
|
|
5334
|
+
link(node) {
|
|
5335
|
+
verifyLink(node);
|
|
5336
|
+
blockStack = new LinkStack(node);
|
|
5337
|
+
},
|
|
5338
|
+
linkReference(node) {
|
|
5339
|
+
verifyLinkReference(node);
|
|
5340
|
+
blockStack = new LinkStack(node);
|
|
5341
|
+
},
|
|
5342
|
+
"blockquote, listItem, footnoteDefinition, link, linkReference:exit"() {
|
|
5343
|
+
flushViolations(blockStack);
|
|
5344
|
+
blockStack = blockStack.upper;
|
|
5345
|
+
},
|
|
5346
|
+
"root:exit"() {
|
|
5347
|
+
flushViolations(blockStack);
|
|
5348
|
+
}
|
|
5349
|
+
};
|
|
5350
|
+
/**
|
|
5351
|
+
* Verify a thematic break node.
|
|
5352
|
+
*/
|
|
5353
|
+
function verifyThematicBreak(node) {
|
|
5354
|
+
const loc = sourceCode.getLoc(node);
|
|
5355
|
+
verifyLinesIndent(lineNumbersFromRange(loc.start.line, loc.end.line), (lineNumber) => blockStack.getExpectedIndent({
|
|
5356
|
+
lineNumber,
|
|
5357
|
+
block: true
|
|
5358
|
+
}));
|
|
5359
|
+
}
|
|
5360
|
+
/**
|
|
5361
|
+
* Verify a heading node.
|
|
5362
|
+
*/
|
|
5363
|
+
function verifyHeading(node) {
|
|
5364
|
+
const loc = sourceCode.getLoc(node);
|
|
5365
|
+
verifyLinesIndent(lineNumbersFromRange(loc.start.line, loc.end.line), (lineNumber) => blockStack.getExpectedIndent({
|
|
5366
|
+
lineNumber,
|
|
5367
|
+
block: true
|
|
5368
|
+
}));
|
|
5369
|
+
}
|
|
5370
|
+
/**
|
|
5371
|
+
* Verify a code block node.
|
|
5372
|
+
*/
|
|
5373
|
+
function verifyCodeBlock(node) {
|
|
5374
|
+
if (getCodeBlockKind(sourceCode, node) === "indented") return;
|
|
5375
|
+
const loc = sourceCode.getLoc(node);
|
|
5376
|
+
verifyLinesIndent([loc.start.line, loc.end.line], (lineNumber) => blockStack.getExpectedIndent({
|
|
5377
|
+
lineNumber,
|
|
5378
|
+
block: true
|
|
5379
|
+
}), additionalFixes);
|
|
5380
|
+
/**
|
|
5381
|
+
* Additional fixes for code block content lines.
|
|
5382
|
+
*/
|
|
5383
|
+
function* additionalFixes(fixer, info) {
|
|
5384
|
+
if (info.loc.start.line !== loc.start.line) return;
|
|
5385
|
+
for (let lineNumber = loc.start.line + 1; lineNumber < loc.end.line; lineNumber++) {
|
|
5386
|
+
const line = getParsedLines(sourceCode).get(lineNumber);
|
|
5387
|
+
if (!line) continue;
|
|
5388
|
+
if (info.expectedIndentWidth > info.actualIndentWidth) {
|
|
5389
|
+
const before = sliceWidth(line.text, 0, info.actualIndentWidth);
|
|
5390
|
+
const after = sliceWidth(line.text, info.actualIndentWidth);
|
|
5391
|
+
const diffWidth = info.expectedIndentWidth - info.actualIndentWidth;
|
|
5392
|
+
yield fixer.replaceTextRange([line.range[0], line.range[0] + line.text.length], before + " ".repeat(diffWidth) + after);
|
|
5393
|
+
} else {
|
|
5394
|
+
let before = sliceWidth(line.text, 0, info.expectedIndentWidth);
|
|
5395
|
+
let between = sliceWidth(line.text, info.expectedIndentWidth, info.actualIndentWidth);
|
|
5396
|
+
const after = sliceWidth(line.text, info.actualIndentWidth);
|
|
5397
|
+
while (between && !isSpaceOrTab(between)) {
|
|
5398
|
+
before += between[0];
|
|
5399
|
+
between = between.slice(1);
|
|
5400
|
+
}
|
|
5401
|
+
yield fixer.replaceTextRange([line.range[0], line.range[0] + line.text.length], before + after);
|
|
5402
|
+
}
|
|
5403
|
+
}
|
|
5404
|
+
}
|
|
5405
|
+
}
|
|
5406
|
+
/**
|
|
5407
|
+
* Verify an HTML node.
|
|
5408
|
+
*/
|
|
5409
|
+
function verifyHtml(node) {
|
|
5410
|
+
const loc = sourceCode.getLoc(node);
|
|
5411
|
+
if (!inlineToBeChecked(loc.start)) return;
|
|
5412
|
+
verifyLinesIndent([loc.start.line], (lineNumber) => blockStack.getExpectedIndent({
|
|
5413
|
+
lineNumber,
|
|
5414
|
+
block: true
|
|
5415
|
+
}));
|
|
5416
|
+
}
|
|
5417
|
+
/**
|
|
5418
|
+
* Verify a link definition node.
|
|
5419
|
+
*/
|
|
5420
|
+
function verifyLinkDefinition(node) {
|
|
5421
|
+
const parsed = parseLinkDefinition(sourceCode, node);
|
|
5422
|
+
if (!parsed) return;
|
|
5423
|
+
const loc = sourceCode.getLoc(node);
|
|
5424
|
+
verifyLinesIndent(lineNumbersFromRange(loc.start.line, loc.end.line), (lineNumber, column) => {
|
|
5425
|
+
const baseIndent = blockStack.getExpectedIndent({
|
|
5426
|
+
lineNumber,
|
|
5427
|
+
block: true
|
|
5428
|
+
});
|
|
5429
|
+
if (baseIndent === "ignore") return "ignore";
|
|
5430
|
+
if (lineNumber <= loc.start.line) return baseIndent;
|
|
5431
|
+
if (lineNumber < parsed.label.loc.end.line) return baseIndent + 2;
|
|
5432
|
+
if (lineNumber === parsed.label.loc.end.line) {
|
|
5433
|
+
const line = getParsedLines(sourceCode).get(lineNumber);
|
|
5434
|
+
if (!line) return baseIndent;
|
|
5435
|
+
const between = line.text.slice(column - 1, parsed.label.loc.end.column - 2);
|
|
5436
|
+
return !between || isWhitespace(between) ? baseIndent : baseIndent + 2;
|
|
5437
|
+
}
|
|
5438
|
+
if (lineNumber <= parsed.destination.loc.end.line) return baseIndent + 4;
|
|
5439
|
+
if (!parsed.title) return baseIndent;
|
|
5440
|
+
if (lineNumber <= parsed.title.loc.start.line) return baseIndent + 4;
|
|
5441
|
+
if (lineNumber < parsed.title.loc.end.line) return baseIndent + 6;
|
|
5442
|
+
if (lineNumber === parsed.title.loc.end.line) {
|
|
5443
|
+
const line = getParsedLines(sourceCode).get(lineNumber);
|
|
5444
|
+
if (!line) return baseIndent;
|
|
5445
|
+
const between = line.text.slice(column - 1, parsed.title.loc.end.column - 2);
|
|
5446
|
+
return !between || isWhitespace(between) ? baseIndent + 4 : baseIndent + 6;
|
|
5447
|
+
}
|
|
5448
|
+
return baseIndent;
|
|
5449
|
+
});
|
|
5450
|
+
}
|
|
5451
|
+
/**
|
|
5452
|
+
* Verify a blockquote node.
|
|
5453
|
+
*/
|
|
5454
|
+
function verifyBlockquote(node) {
|
|
5455
|
+
const loc = sourceCode.getLoc(node);
|
|
5456
|
+
verifyLinesIndent(lineNumbersFromRange(loc.start.line, loc.end.line), (lineNumber) => blockStack.getExpectedIndent({
|
|
5457
|
+
lineNumber,
|
|
5458
|
+
block: true
|
|
5459
|
+
}));
|
|
5460
|
+
}
|
|
5461
|
+
/**
|
|
5462
|
+
* Verify a table node.
|
|
5463
|
+
*/
|
|
5464
|
+
function verifyTable(node) {
|
|
5465
|
+
const loc = sourceCode.getLoc(node);
|
|
5466
|
+
verifyLinesIndent(lineNumbersFromRange(loc.start.line, loc.end.line), (lineNumber) => blockStack.getExpectedIndent({
|
|
5467
|
+
lineNumber,
|
|
5468
|
+
block: true
|
|
5469
|
+
}));
|
|
5470
|
+
}
|
|
5471
|
+
/**
|
|
5472
|
+
* Verify a list node.
|
|
5473
|
+
*/
|
|
5474
|
+
function verifyList(node) {
|
|
5475
|
+
const loc = sourceCode.getLoc(node);
|
|
5476
|
+
verifyLinesIndent([loc.start.line], (lineNumber) => blockStack.getExpectedIndent({
|
|
5477
|
+
lineNumber,
|
|
5478
|
+
block: true
|
|
5479
|
+
}), additionalFixes);
|
|
5480
|
+
/**
|
|
5481
|
+
* Additional fixes for list item lines.
|
|
5482
|
+
*/
|
|
5483
|
+
function* additionalFixes(fixer, info) {
|
|
5484
|
+
const [firstItem, ...otherItems] = node.children;
|
|
5485
|
+
yield* fixAfterFirstLine(firstItem, info.actualIndentWidth);
|
|
5486
|
+
for (const listItem of otherItems) {
|
|
5487
|
+
const listItemLoc = sourceCode.getLoc(listItem);
|
|
5488
|
+
const listItemIndentWidth = getWidth(sourceCode.lines[listItemLoc.start.line - 1].slice(0, listItemLoc.start.column - 1));
|
|
5489
|
+
if (listItemIndentWidth === info.expectedIndentWidth) continue;
|
|
5490
|
+
yield getFixForLine(listItemLoc.start.line, listItemIndentWidth);
|
|
5491
|
+
yield* fixAfterFirstLine(listItem, listItemIndentWidth);
|
|
5492
|
+
}
|
|
5493
|
+
/**
|
|
5494
|
+
* Get fixes for lines after the first line of the list item.
|
|
5495
|
+
*/
|
|
5496
|
+
function* fixAfterFirstLine(item, actualIndentWidth) {
|
|
5497
|
+
const itemLoc = sourceCode.getLoc(item);
|
|
5498
|
+
for (let lineNumber = itemLoc.start.line + 1; lineNumber <= itemLoc.end.line; lineNumber++) yield getFixForLine(lineNumber, actualIndentWidth);
|
|
5499
|
+
}
|
|
5500
|
+
/**
|
|
5501
|
+
* Get a fix for a line.
|
|
5502
|
+
*/
|
|
5503
|
+
function getFixForLine(lineNumber, actualIndentWidth) {
|
|
5504
|
+
const line = getParsedLines(sourceCode).get(lineNumber);
|
|
5505
|
+
if (info.expectedIndentWidth > actualIndentWidth) {
|
|
5506
|
+
const before$1 = sliceWidth(line.text, 0, actualIndentWidth);
|
|
5507
|
+
const diffWidth = info.expectedIndentWidth - actualIndentWidth;
|
|
5508
|
+
return fixer.insertTextAfterRange([line.range[0], line.range[0] + before$1.length], " ".repeat(diffWidth));
|
|
5509
|
+
}
|
|
5510
|
+
let before = sliceWidth(line.text, 0, info.expectedIndentWidth);
|
|
5511
|
+
let between = sliceWidth(line.text, info.expectedIndentWidth, actualIndentWidth);
|
|
5512
|
+
while (between && !isSpaceOrTab(between)) {
|
|
5513
|
+
before += between[0];
|
|
5514
|
+
between = between.slice(1);
|
|
5515
|
+
}
|
|
5516
|
+
return fixer.replaceTextRange([line.range[0], line.range[0] + before.length + between.length], before);
|
|
5517
|
+
}
|
|
5518
|
+
}
|
|
5519
|
+
}
|
|
5520
|
+
/**
|
|
5521
|
+
* Verify a footnote definition node.
|
|
5522
|
+
*/
|
|
5523
|
+
function verifyFootnoteDefinition(node) {
|
|
5524
|
+
const loc = sourceCode.getLoc(node);
|
|
5525
|
+
verifyLinesIndent([loc.start.line], (lineNumber) => blockStack.getExpectedIndent({
|
|
5526
|
+
lineNumber,
|
|
5527
|
+
block: true
|
|
5528
|
+
}));
|
|
5529
|
+
}
|
|
5530
|
+
/**
|
|
5531
|
+
* Verify an inline code node.
|
|
5532
|
+
*/
|
|
5533
|
+
function verifyInlineCode(node) {
|
|
5534
|
+
const loc = sourceCode.getLoc(node);
|
|
5535
|
+
if (!inlineToBeChecked(loc.start)) return;
|
|
5536
|
+
verifyLinesIndent([loc.start.line], (lineNumber) => blockStack.getExpectedIndent({
|
|
5537
|
+
lineNumber,
|
|
5538
|
+
block: false
|
|
5539
|
+
}));
|
|
5540
|
+
}
|
|
5541
|
+
/**
|
|
5542
|
+
* Verify an emphasis, strong, or delete node.
|
|
5543
|
+
*/
|
|
5544
|
+
function verifyEmphasisOrStrongOrDelete(node) {
|
|
5545
|
+
const loc = sourceCode.getLoc(node);
|
|
5546
|
+
if (!inlineToBeChecked(loc.start)) return;
|
|
5547
|
+
verifyLinesIndent([loc.start.line], (lineNumber) => blockStack.getExpectedIndent({
|
|
5548
|
+
lineNumber,
|
|
5549
|
+
block: false
|
|
5550
|
+
}));
|
|
5551
|
+
}
|
|
5552
|
+
/**
|
|
5553
|
+
* Verify a link node.
|
|
5554
|
+
*/
|
|
5555
|
+
function verifyLink(node) {
|
|
5556
|
+
const loc = sourceCode.getLoc(node);
|
|
5557
|
+
let lines = lineNumbersFromRange(loc.start.line, loc.end.line);
|
|
5558
|
+
if (!inlineToBeChecked(loc.start)) lines = lines.slice(1);
|
|
5559
|
+
const kind = getLinkKind(sourceCode, node);
|
|
5560
|
+
if (kind === "autolink" || kind === "gfm-autolink") verifyLinesIndent(lines, (lineNumber) => blockStack.getExpectedIndent({
|
|
5561
|
+
lineNumber,
|
|
5562
|
+
block: false
|
|
5563
|
+
}));
|
|
5564
|
+
else if (kind === "inline") {
|
|
5565
|
+
const parsed = parseInlineLink(sourceCode, node);
|
|
5566
|
+
if (!parsed) return;
|
|
5567
|
+
const lastChild = node.children.at(-1);
|
|
5568
|
+
if (lastChild && parsed.text.loc.start.line < parsed.text.loc.end.line) {
|
|
5569
|
+
const lastChildLoc = sourceCode.getLoc(lastChild);
|
|
5570
|
+
const lastChildEndLine = lastChild.type === "text" && lastChild.value.endsWith("\n") ? lastChildLoc.end.line - 1 : lastChildLoc.end.line;
|
|
5571
|
+
lines = lines.filter((lineNumber) => lineNumber <= parsed.text.loc.start.line || lastChildEndLine < lineNumber);
|
|
5572
|
+
}
|
|
5573
|
+
verifyLinesIndent(lines, (lineNumber, column) => {
|
|
5574
|
+
const baseIndent = blockStack.getExpectedIndent({
|
|
5575
|
+
lineNumber,
|
|
5576
|
+
block: false
|
|
5577
|
+
});
|
|
5578
|
+
if (baseIndent === "ignore") return "ignore";
|
|
5579
|
+
if (lineNumber <= loc.start.line) return baseIndent;
|
|
5580
|
+
if (lineNumber < parsed.text.loc.end.line) return baseIndent + 2;
|
|
5581
|
+
if (lineNumber <= parsed.openingParen.loc.end.line) return baseIndent;
|
|
5582
|
+
if (lineNumber <= parsed.destination.loc.end.line) return baseIndent + 2;
|
|
5583
|
+
if (!parsed.title) return baseIndent;
|
|
5584
|
+
if (lineNumber <= parsed.title.loc.start.line) return baseIndent + 2;
|
|
5585
|
+
if (lineNumber < parsed.title.loc.end.line) return baseIndent + 4;
|
|
5586
|
+
if (lineNumber === parsed.title.loc.end.line) {
|
|
5587
|
+
const line = getParsedLines(sourceCode).get(lineNumber);
|
|
5588
|
+
if (!line) return baseIndent;
|
|
5589
|
+
const between = line.text.slice(column - 1, parsed.title.loc.end.column - 2);
|
|
5590
|
+
return !between || isWhitespace(between) ? baseIndent + 2 : baseIndent + 4;
|
|
5591
|
+
}
|
|
5592
|
+
return baseIndent;
|
|
5593
|
+
});
|
|
5594
|
+
}
|
|
5595
|
+
}
|
|
5596
|
+
/**
|
|
5597
|
+
* Verify a link reference node.
|
|
5598
|
+
*/
|
|
5599
|
+
function verifyLinkReference(node) {
|
|
5600
|
+
const loc = sourceCode.getLoc(node);
|
|
5601
|
+
const parsed = parseLinkReference(sourceCode, node);
|
|
5602
|
+
if (!parsed) return;
|
|
5603
|
+
let lines = lineNumbersFromRange(loc.start.line, loc.end.line);
|
|
5604
|
+
if (!inlineToBeChecked(loc.start)) lines = lines.slice(1);
|
|
5605
|
+
const lastChild = node.children.at(-1);
|
|
5606
|
+
if (lastChild && parsed.text.loc.start.line < parsed.text.loc.end.line) {
|
|
5607
|
+
const lastChildLoc = sourceCode.getLoc(lastChild);
|
|
5608
|
+
const lastChildEndLine = lastChild.type === "text" && lastChild.value.endsWith("\n") ? lastChildLoc.end.line - 1 : lastChildLoc.end.line;
|
|
5609
|
+
lines = lines.filter((lineNumber) => lineNumber <= parsed.text.loc.start.line || lastChildEndLine < lineNumber);
|
|
5610
|
+
}
|
|
5611
|
+
verifyLinesIndent(lines, (lineNumber, column) => {
|
|
5612
|
+
const baseIndent = blockStack.getExpectedIndent({
|
|
5613
|
+
lineNumber,
|
|
5614
|
+
block: false
|
|
5615
|
+
});
|
|
5616
|
+
if (baseIndent === "ignore") return "ignore";
|
|
5617
|
+
if (lineNumber <= loc.start.line) return baseIndent;
|
|
5618
|
+
if (lineNumber < parsed.text.loc.end.line) return baseIndent + 2;
|
|
5619
|
+
if (!parsed.label) return baseIndent;
|
|
5620
|
+
if (lineNumber <= parsed.label.loc.start.line) return baseIndent;
|
|
5621
|
+
if (lineNumber < parsed.label.loc.end.line) return baseIndent + 2;
|
|
5622
|
+
if (lineNumber === parsed.label.loc.end.line) {
|
|
5623
|
+
const line = getParsedLines(sourceCode).get(lineNumber);
|
|
5624
|
+
if (!line) return baseIndent;
|
|
5625
|
+
const between = line.text.slice(column - 1, parsed.label.loc.end.column - 2);
|
|
5626
|
+
return !between || isWhitespace(between) ? baseIndent : baseIndent + 2;
|
|
5627
|
+
}
|
|
5628
|
+
return baseIndent;
|
|
5629
|
+
});
|
|
5630
|
+
}
|
|
5631
|
+
/**
|
|
5632
|
+
* Verify an image node.
|
|
5633
|
+
*/
|
|
5634
|
+
function verifyImage(node) {
|
|
5635
|
+
const loc = sourceCode.getLoc(node);
|
|
5636
|
+
let lines = lineNumbersFromRange(loc.start.line, loc.end.line);
|
|
5637
|
+
if (!inlineToBeChecked(loc.start)) lines = lines.slice(1);
|
|
5638
|
+
const parsed = parseImage(sourceCode, node);
|
|
5639
|
+
if (!parsed) return;
|
|
5640
|
+
verifyLinesIndent(lines, (lineNumber, column) => {
|
|
5641
|
+
const baseIndent = blockStack.getExpectedIndent({
|
|
5642
|
+
lineNumber,
|
|
5643
|
+
block: false
|
|
5644
|
+
});
|
|
5645
|
+
if (baseIndent === "ignore") return "ignore";
|
|
5646
|
+
if (lineNumber <= loc.start.line) return baseIndent;
|
|
5647
|
+
if (lineNumber < parsed.text.loc.end.line) return baseIndent + 2;
|
|
5648
|
+
if (lineNumber === parsed.text.loc.end.line) {
|
|
5649
|
+
const line = getParsedLines(sourceCode).get(lineNumber);
|
|
5650
|
+
if (!line) return baseIndent;
|
|
5651
|
+
const between = line.text.slice(column - 1, parsed.text.loc.end.column - 2);
|
|
5652
|
+
return !between || isWhitespace(between) ? baseIndent : baseIndent + 2;
|
|
5653
|
+
}
|
|
5654
|
+
if (lineNumber <= parsed.openingParen.loc.end.line) return baseIndent;
|
|
5655
|
+
if (lineNumber <= parsed.destination.loc.end.line) return baseIndent + 2;
|
|
5656
|
+
if (!parsed.title) return baseIndent;
|
|
5657
|
+
if (lineNumber <= parsed.title.loc.start.line) return baseIndent + 2;
|
|
5658
|
+
if (lineNumber < parsed.title.loc.end.line) return baseIndent + 4;
|
|
5659
|
+
if (lineNumber === parsed.title.loc.end.line) {
|
|
5660
|
+
const line = getParsedLines(sourceCode).get(lineNumber);
|
|
5661
|
+
if (!line) return baseIndent;
|
|
5662
|
+
const between = line.text.slice(column - 1, parsed.title.loc.end.column - 2);
|
|
5663
|
+
return !between || isWhitespace(between) ? baseIndent + 2 : baseIndent + 4;
|
|
5664
|
+
}
|
|
5665
|
+
return baseIndent;
|
|
5666
|
+
});
|
|
5667
|
+
}
|
|
5668
|
+
/**
|
|
5669
|
+
* Verify an image reference node.
|
|
5670
|
+
*/
|
|
5671
|
+
function verifyImageReference(node) {
|
|
5672
|
+
const loc = sourceCode.getLoc(node);
|
|
5673
|
+
const parsed = parseImageReference(sourceCode, node);
|
|
5674
|
+
if (!parsed) return;
|
|
5675
|
+
let lines = lineNumbersFromRange(loc.start.line, loc.end.line);
|
|
5676
|
+
if (!inlineToBeChecked(loc.start)) lines = lines.slice(1);
|
|
5677
|
+
verifyLinesIndent(lines, (lineNumber, column) => {
|
|
5678
|
+
const baseIndent = blockStack.getExpectedIndent({
|
|
5679
|
+
lineNumber,
|
|
5680
|
+
block: false
|
|
5681
|
+
});
|
|
5682
|
+
if (baseIndent === "ignore") return "ignore";
|
|
5683
|
+
if (lineNumber <= loc.start.line) return baseIndent;
|
|
5684
|
+
if (lineNumber < parsed.text.loc.end.line) return baseIndent + 2;
|
|
5685
|
+
if (lineNumber === parsed.text.loc.end.line) {
|
|
5686
|
+
const line = getParsedLines(sourceCode).get(lineNumber);
|
|
5687
|
+
if (!line) return baseIndent;
|
|
5688
|
+
const between = line.text.slice(column - 1, parsed.text.loc.end.column - 2);
|
|
5689
|
+
return !between || isWhitespace(between) ? baseIndent : baseIndent + 2;
|
|
5690
|
+
}
|
|
5691
|
+
if (!parsed.label) return baseIndent;
|
|
5692
|
+
if (lineNumber <= parsed.label.loc.start.line) return baseIndent;
|
|
5693
|
+
if (lineNumber < parsed.label.loc.end.line) return baseIndent + 2;
|
|
5694
|
+
if (lineNumber === parsed.label.loc.end.line) {
|
|
5695
|
+
const line = getParsedLines(sourceCode).get(lineNumber);
|
|
5696
|
+
if (!line) return baseIndent;
|
|
5697
|
+
const between = line.text.slice(column - 1, parsed.label.loc.end.column - 2);
|
|
5698
|
+
return !between || isWhitespace(between) ? baseIndent : baseIndent + 2;
|
|
5699
|
+
}
|
|
5700
|
+
return baseIndent;
|
|
5701
|
+
});
|
|
5702
|
+
}
|
|
5703
|
+
/**
|
|
5704
|
+
* Verify a text node.
|
|
5705
|
+
*/
|
|
5706
|
+
function verifyText(node) {
|
|
5707
|
+
const loc = sourceCode.getLoc(node);
|
|
5708
|
+
let lines = lineNumbersFromRange(loc.start.line, loc.end.line);
|
|
5709
|
+
if (!inlineToBeChecked(loc.start)) lines = lines.slice(1);
|
|
5710
|
+
if (node.value.endsWith("\n")) lines = lines.slice(0, -1);
|
|
5711
|
+
verifyLinesIndent(lines, (lineNumber) => blockStack.getExpectedIndent({
|
|
5712
|
+
lineNumber,
|
|
5713
|
+
block: false
|
|
5714
|
+
}));
|
|
5715
|
+
}
|
|
5716
|
+
/**
|
|
5717
|
+
* Verify an inline node.
|
|
5718
|
+
*/
|
|
5719
|
+
function verifyInline(node) {
|
|
5720
|
+
const loc = sourceCode.getLoc(node);
|
|
5721
|
+
let lines = lineNumbersFromRange(loc.start.line, loc.end.line);
|
|
5722
|
+
if (!inlineToBeChecked(loc.start)) lines = lines.slice(1);
|
|
5723
|
+
verifyLinesIndent(lines, (lineNumber) => blockStack.getExpectedIndent({
|
|
5724
|
+
lineNumber,
|
|
5725
|
+
block: false
|
|
5726
|
+
}));
|
|
5727
|
+
}
|
|
5728
|
+
/**
|
|
5729
|
+
* Check whether the inline node should be checked.
|
|
5730
|
+
*/
|
|
5731
|
+
function inlineToBeChecked(position) {
|
|
5732
|
+
const blockquote = blockStack.getCurrentBlockquote();
|
|
5733
|
+
const listItem = blockStack.getCurrentListItemAtLine(position.line);
|
|
5734
|
+
const lineText = sourceCode.lines[position.line - 1];
|
|
5735
|
+
if (listItem) {
|
|
5736
|
+
const parsed = listItem.getParsedListItem();
|
|
5737
|
+
const indentText = lineText.slice((parsed.taskListItemMarker?.loc ?? parsed.marker.loc).end.column - 1, position.column - 1);
|
|
5738
|
+
if (indentText && !isSpaceOrTab(indentText)) return false;
|
|
5739
|
+
} else if (blockquote) {
|
|
5740
|
+
if (atWidth(lineText, blockquote.getMarkerIndent()) !== ">") return false;
|
|
5741
|
+
const indentText = sliceWidth(lineText.slice(0, position.column - 1), blockquote.getMarkerIndent() + 1);
|
|
5742
|
+
if (indentText && !isSpaceOrTab(indentText)) return false;
|
|
5743
|
+
} else {
|
|
5744
|
+
const indentText = lineText.slice(0, position.column - 1);
|
|
5745
|
+
if (indentText && !isSpaceOrTab(indentText)) return false;
|
|
5746
|
+
}
|
|
5747
|
+
return true;
|
|
5748
|
+
}
|
|
5749
|
+
/**
|
|
5750
|
+
* Get line numbers from the range.
|
|
5751
|
+
*/
|
|
5752
|
+
function lineNumbersFromRange(lineNumberFrom, lineNumberTo) {
|
|
5753
|
+
const lines = [];
|
|
5754
|
+
for (let lineNumber = lineNumberFrom; lineNumber <= lineNumberTo; lineNumber++) lines.push(lineNumber);
|
|
5755
|
+
return lines;
|
|
5756
|
+
}
|
|
5757
|
+
/**
|
|
5758
|
+
* Verify the indentation of the lines.
|
|
5759
|
+
*/
|
|
5760
|
+
function verifyLinesIndent(lineNumbers, expectedIndentWidthProvider, additionalFixes) {
|
|
5761
|
+
const blockquote = blockStack.getCurrentBlockquote();
|
|
5762
|
+
if (!blockquote) {
|
|
5763
|
+
verifyLinesIndentFromRoot(lineNumbers, expectedIndentWidthProvider, additionalFixes);
|
|
5764
|
+
return;
|
|
5765
|
+
}
|
|
5766
|
+
verifyLinesIndentFromBlockquoteMarker(lineNumbers, blockquote, expectedIndentWidthProvider, additionalFixes);
|
|
5767
|
+
}
|
|
5768
|
+
/**
|
|
5769
|
+
* Verify the indentation of the lines from the root.
|
|
5770
|
+
*/
|
|
5771
|
+
function verifyLinesIndentFromRoot(lineNumbers, expectedIndentWidthProvider, additionalFixes) {
|
|
5772
|
+
const reports = [];
|
|
5773
|
+
for (const lineNumber of lineNumbers) {
|
|
5774
|
+
const line = getParsedLines(sourceCode).get(lineNumber);
|
|
5775
|
+
if (!line) return;
|
|
5776
|
+
const listItem = blockStack.getCurrentListItemAtLine(lineNumber);
|
|
5777
|
+
if (!listItem) {
|
|
5778
|
+
const indentText = /^\s*/u.exec(line.text)[0];
|
|
5779
|
+
const actualIndentWidth = getWidth(indentText);
|
|
5780
|
+
const expectedIndentWidth = expectedIndentWidthProvider(lineNumber, 1);
|
|
5781
|
+
if (expectedIndentWidth === "ignore") continue;
|
|
5782
|
+
if (actualIndentWidth === expectedIndentWidth) continue;
|
|
5783
|
+
reports.push({
|
|
5784
|
+
loc: {
|
|
5785
|
+
start: {
|
|
5786
|
+
line: line.line,
|
|
5787
|
+
column: 1
|
|
5788
|
+
},
|
|
5789
|
+
end: {
|
|
5790
|
+
line: line.line,
|
|
5791
|
+
column: indentText.length + 1
|
|
5792
|
+
}
|
|
5793
|
+
},
|
|
5794
|
+
messageId: indentText.includes(" ") ? "wrongIndentationWithTab" : "wrongIndentation",
|
|
5795
|
+
data: {
|
|
5796
|
+
expected: expectedIndentWidth,
|
|
5797
|
+
actual: actualIndentWidth
|
|
5798
|
+
},
|
|
5799
|
+
fix(fixer) {
|
|
5800
|
+
return fixer.replaceTextRange([line.range[0], line.range[0] + indentText.length], " ".repeat(expectedIndentWidth));
|
|
5801
|
+
},
|
|
5802
|
+
expectedIndentWidth,
|
|
5803
|
+
actualIndentWidth
|
|
5804
|
+
});
|
|
5805
|
+
continue;
|
|
5806
|
+
}
|
|
5807
|
+
const report = verifyLineIndentFromListItemMarker(line, listItem, expectedIndentWidthProvider);
|
|
5808
|
+
if (!report) continue;
|
|
5809
|
+
reports.push(report);
|
|
5810
|
+
}
|
|
5811
|
+
if (!reports.length) return;
|
|
5812
|
+
for (const report of reports) reportIncorrectIndent({
|
|
5813
|
+
loc: report.loc,
|
|
5814
|
+
messageId: report.messageId,
|
|
5815
|
+
data: report.data,
|
|
5816
|
+
*fix(fixer) {
|
|
5817
|
+
yield report.fix(fixer);
|
|
5818
|
+
if (additionalFixes) yield* additionalFixes(fixer, report) ?? [];
|
|
5819
|
+
}
|
|
5820
|
+
});
|
|
5821
|
+
}
|
|
5822
|
+
/**
|
|
5823
|
+
* Verify the indentation of the lines from the blockquote marker.
|
|
5824
|
+
*/
|
|
5825
|
+
function verifyLinesIndentFromBlockquoteMarker(lineNumbers, blockquote, expectedIndentWidthProvider, additionalFixes) {
|
|
5826
|
+
const blockquoteLoc = sourceCode.getLoc(blockquote.node);
|
|
5827
|
+
const reports = [];
|
|
5828
|
+
let cannotFix = false;
|
|
5829
|
+
for (const lineNumber of lineNumbers) {
|
|
5830
|
+
const line = getParsedLines(sourceCode).get(lineNumber);
|
|
5831
|
+
if (!line) return;
|
|
5832
|
+
if (atWidth(line.text, blockquote.getMarkerIndent()) !== ">") {
|
|
5833
|
+
cannotFix = true;
|
|
5834
|
+
continue;
|
|
5835
|
+
}
|
|
5836
|
+
const listItem = blockStack.getCurrentListItemAtLine(lineNumber);
|
|
5837
|
+
if (!listItem) {
|
|
5838
|
+
const before = line.text.slice(0, blockquoteLoc.start.column);
|
|
5839
|
+
const after = line.text.slice(blockquoteLoc.start.column);
|
|
5840
|
+
const indentText = /^\s*/u.exec(after)[0];
|
|
5841
|
+
const actualIndentWidth = getWidth(before + indentText);
|
|
5842
|
+
const expectedIndentWidth = expectedIndentWidthProvider(lineNumber, blockquoteLoc.start.column + 1);
|
|
5843
|
+
if (expectedIndentWidth === "ignore") continue;
|
|
5844
|
+
if (actualIndentWidth === expectedIndentWidth) continue;
|
|
5845
|
+
const linePrefixWidth = getWidth(before);
|
|
5846
|
+
reports.push({
|
|
5847
|
+
loc: {
|
|
5848
|
+
start: {
|
|
5849
|
+
line: line.line,
|
|
5850
|
+
column: blockquoteLoc.start.column + 1
|
|
5851
|
+
},
|
|
5852
|
+
end: {
|
|
5853
|
+
line: line.line,
|
|
5854
|
+
column: blockquoteLoc.start.column + 1 + indentText.length
|
|
5855
|
+
}
|
|
5856
|
+
},
|
|
5857
|
+
messageId: indentText.includes(" ") ? "wrongIndentationFromBlockquoteMarkerWithTab" : "wrongIndentationFromBlockquoteMarker",
|
|
5858
|
+
data: {
|
|
5859
|
+
expected: expectedIndentWidth - linePrefixWidth,
|
|
5860
|
+
actual: actualIndentWidth - linePrefixWidth
|
|
5861
|
+
},
|
|
5862
|
+
fix(fixer) {
|
|
5863
|
+
return fixer.replaceTextRange([line.range[0] + blockquoteLoc.start.column, line.range[0] + blockquoteLoc.start.column + indentText.length], " ".repeat(expectedIndentWidth - linePrefixWidth));
|
|
5864
|
+
},
|
|
5865
|
+
expectedIndentWidth,
|
|
5866
|
+
actualIndentWidth
|
|
5867
|
+
});
|
|
5868
|
+
continue;
|
|
5869
|
+
}
|
|
5870
|
+
const report = verifyLineIndentFromListItemMarker(line, listItem, expectedIndentWidthProvider);
|
|
5871
|
+
if (!report) continue;
|
|
5872
|
+
reports.push(report);
|
|
5873
|
+
}
|
|
5874
|
+
if (!reports.length) return;
|
|
5875
|
+
for (const report of reports) reportIncorrectIndent({
|
|
5876
|
+
loc: report.loc,
|
|
5877
|
+
messageId: report.messageId,
|
|
5878
|
+
data: report.data,
|
|
5879
|
+
*fix(fixer) {
|
|
5880
|
+
if (cannotFix) return;
|
|
5881
|
+
yield report.fix(fixer);
|
|
5882
|
+
if (additionalFixes) yield* additionalFixes(fixer, report) ?? [];
|
|
5883
|
+
}
|
|
5884
|
+
});
|
|
5885
|
+
}
|
|
5886
|
+
/**
|
|
5887
|
+
* Verify the indentation of the line from the list item marker.
|
|
5888
|
+
*/
|
|
5889
|
+
function verifyLineIndentFromListItemMarker(line, listItem, expectedIndentWidthProvider) {
|
|
5890
|
+
const parsed = listItem.getParsedListItem();
|
|
5891
|
+
const markerAfterColumn = (parsed.taskListItemMarker?.loc ?? parsed.marker.loc).end.column;
|
|
5892
|
+
const before = line.text.slice(0, markerAfterColumn - 1);
|
|
5893
|
+
const after = line.text.slice(markerAfterColumn - 1);
|
|
5894
|
+
const indentText = /^\s*/u.exec(after)[0];
|
|
5895
|
+
const actualIndentWidth = getWidth(before + indentText);
|
|
5896
|
+
const expectedIndentWidth = expectedIndentWidthProvider(line.line, markerAfterColumn);
|
|
5897
|
+
if (expectedIndentWidth === "ignore") return null;
|
|
5898
|
+
if (actualIndentWidth === expectedIndentWidth) return null;
|
|
5899
|
+
const linePrefixWidth = getWidth(before);
|
|
5900
|
+
const range = [line.range[0] + before.length, line.range[0] + before.length + indentText.length];
|
|
5901
|
+
return {
|
|
5902
|
+
loc: getSourceLocationFromRange(sourceCode, listItem.node, range),
|
|
5903
|
+
messageId: indentText.includes(" ") ? "wrongIndentationFromListMarkerWithTab" : "wrongIndentationFromListMarker",
|
|
5904
|
+
data: {
|
|
5905
|
+
expected: expectedIndentWidth - linePrefixWidth,
|
|
5906
|
+
actual: actualIndentWidth - linePrefixWidth
|
|
5907
|
+
},
|
|
5908
|
+
fix(fixer) {
|
|
5909
|
+
return fixer.replaceTextRange(range, " ".repeat(expectedIndentWidth - linePrefixWidth));
|
|
5910
|
+
},
|
|
5911
|
+
expectedIndentWidth,
|
|
5912
|
+
actualIndentWidth
|
|
5913
|
+
};
|
|
5914
|
+
}
|
|
5915
|
+
}
|
|
5916
|
+
});
|
|
5917
|
+
|
|
5918
|
+
//#endregion
|
|
5919
|
+
//#region src/utils/setext-heading.ts
|
|
5920
|
+
/**
|
|
5921
|
+
* Parse the setext heading.
|
|
5922
|
+
*/
|
|
5923
|
+
function parseSetextHeading(sourceCode, node) {
|
|
5924
|
+
if (getHeadingKind(sourceCode, node) !== "setext") return null;
|
|
5925
|
+
const lines = getParsedLines(sourceCode);
|
|
5926
|
+
const contentLines = [];
|
|
5927
|
+
const nodeLoc = sourceCode.getLoc(node);
|
|
5928
|
+
for (let lineNumber = nodeLoc.start.line; lineNumber < nodeLoc.end.line; lineNumber++) {
|
|
5929
|
+
const content = parseContent(lines.get(lineNumber));
|
|
5930
|
+
contentLines.push(content);
|
|
5931
|
+
}
|
|
5932
|
+
const underline = parseUnderline(lines.get(nodeLoc.end.line));
|
|
5933
|
+
if (!underline) return null;
|
|
5934
|
+
return {
|
|
5935
|
+
contentLines,
|
|
5936
|
+
underline
|
|
5937
|
+
};
|
|
5938
|
+
}
|
|
5939
|
+
/**
|
|
5940
|
+
* Parse the content line of a setext heading.
|
|
5941
|
+
*/
|
|
5942
|
+
function parseContent(line) {
|
|
5943
|
+
let prefix = "";
|
|
5944
|
+
let spaceBefore = "";
|
|
5945
|
+
let suffix = "";
|
|
5946
|
+
for (let index = 0; index < line.text.length; index++) {
|
|
5947
|
+
const c = line.text[index];
|
|
5948
|
+
if (!c.trim()) {
|
|
5949
|
+
spaceBefore += c;
|
|
5950
|
+
continue;
|
|
5951
|
+
}
|
|
5952
|
+
if (c === ">" && spaceBefore.length < 4) {
|
|
5953
|
+
prefix += spaceBefore + c;
|
|
5954
|
+
spaceBefore = "";
|
|
5955
|
+
continue;
|
|
5956
|
+
}
|
|
5957
|
+
suffix = line.text.slice(index);
|
|
5958
|
+
break;
|
|
5959
|
+
}
|
|
5960
|
+
const content = suffix.trimEnd();
|
|
5961
|
+
const spaceAfter = suffix.slice(content.length);
|
|
5962
|
+
return {
|
|
5963
|
+
text: content,
|
|
5964
|
+
range: [line.range[0] + prefix.length + spaceBefore.length, line.range[1] - line.linebreak.length - spaceAfter.length],
|
|
5965
|
+
loc: {
|
|
5966
|
+
start: {
|
|
5967
|
+
line: line.line,
|
|
5968
|
+
column: prefix.length + spaceBefore.length + 1
|
|
5969
|
+
},
|
|
5970
|
+
end: {
|
|
5971
|
+
line: line.line,
|
|
5972
|
+
column: prefix.length + spaceBefore.length + content.length + 1
|
|
5973
|
+
}
|
|
5974
|
+
},
|
|
5975
|
+
raws: {
|
|
5976
|
+
prefix,
|
|
5977
|
+
spaceBefore,
|
|
5978
|
+
spaceAfter
|
|
5979
|
+
}
|
|
5074
5980
|
};
|
|
5075
5981
|
}
|
|
5076
5982
|
/**
|
|
5077
|
-
* Parse the
|
|
5983
|
+
* Parse the underline of a setext heading.
|
|
5078
5984
|
*/
|
|
5079
|
-
function
|
|
5080
|
-
let
|
|
5081
|
-
|
|
5082
|
-
|
|
5083
|
-
|
|
5084
|
-
|
|
5085
|
-
index
|
|
5086
|
-
|
|
5087
|
-
|
|
5088
|
-
|
|
5089
|
-
|
|
5090
|
-
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
|
|
5095
|
-
|
|
5096
|
-
|
|
5097
|
-
|
|
5098
|
-
|
|
5099
|
-
|
|
5100
|
-
|
|
5101
|
-
|
|
5102
|
-
|
|
5103
|
-
type: "pointy-bracketed",
|
|
5104
|
-
text: text.slice(...destinationRange),
|
|
5105
|
-
range: destinationRange
|
|
5106
|
-
};
|
|
5107
|
-
} else {
|
|
5108
|
-
if (text.length <= index) return null;
|
|
5109
|
-
skipUntilEnd((c) => isWhitespace(c) || isAsciiControlCharacter(c));
|
|
5110
|
-
const destinationRange = [destinationStartIndex, index];
|
|
5111
|
-
destination = {
|
|
5112
|
-
type: "bare",
|
|
5113
|
-
text: text.slice(...destinationRange),
|
|
5114
|
-
range: destinationRange
|
|
5115
|
-
};
|
|
5985
|
+
function parseUnderline(line) {
|
|
5986
|
+
let marker = null;
|
|
5987
|
+
let underlineText = "";
|
|
5988
|
+
let prefix = "";
|
|
5989
|
+
let spaceBefore = "";
|
|
5990
|
+
let spaceAfter = "";
|
|
5991
|
+
for (let index = line.text.length - 1; index >= 0; index--) {
|
|
5992
|
+
const c = line.text[index];
|
|
5993
|
+
if (!marker) {
|
|
5994
|
+
if (c === "=" || c === "-") {
|
|
5995
|
+
underlineText = c + underlineText;
|
|
5996
|
+
marker = c;
|
|
5997
|
+
} else if (!c.trim()) spaceAfter = c + spaceAfter;
|
|
5998
|
+
else return null;
|
|
5999
|
+
continue;
|
|
6000
|
+
}
|
|
6001
|
+
if (c === marker) {
|
|
6002
|
+
underlineText = c + spaceBefore + underlineText;
|
|
6003
|
+
spaceBefore = "";
|
|
6004
|
+
} else if (!c.trim()) spaceBefore = c + spaceBefore;
|
|
6005
|
+
else {
|
|
6006
|
+
prefix = line.text.slice(0, index + 1);
|
|
6007
|
+
break;
|
|
6008
|
+
}
|
|
5116
6009
|
}
|
|
5117
|
-
|
|
5118
|
-
|
|
5119
|
-
|
|
5120
|
-
|
|
5121
|
-
|
|
6010
|
+
if (!marker) return null;
|
|
6011
|
+
const underlineLoc = {
|
|
6012
|
+
start: {
|
|
6013
|
+
line: line.line,
|
|
6014
|
+
column: prefix.length + spaceBefore.length + 1
|
|
6015
|
+
},
|
|
6016
|
+
end: {
|
|
6017
|
+
line: line.line,
|
|
6018
|
+
column: prefix.length + spaceBefore.length + underlineText.length + 1
|
|
6019
|
+
}
|
|
5122
6020
|
};
|
|
5123
|
-
let title;
|
|
5124
|
-
const titleStartIndex = index;
|
|
5125
|
-
const startChar = text[index];
|
|
5126
|
-
if (startChar === "'" || startChar === "\"" || startChar === "(") {
|
|
5127
|
-
index++;
|
|
5128
|
-
const endChar = startChar === "(" ? ")" : startChar;
|
|
5129
|
-
if (!skipUntilEnd((c) => c === endChar)) return null;
|
|
5130
|
-
index++;
|
|
5131
|
-
const titleRange = [titleStartIndex, index];
|
|
5132
|
-
title = {
|
|
5133
|
-
type: startChar === "'" ? "single-quoted" : startChar === "\"" ? "double-quoted" : "parenthesized",
|
|
5134
|
-
text: text.slice(...titleRange),
|
|
5135
|
-
range: titleRange
|
|
5136
|
-
};
|
|
5137
|
-
} else return null;
|
|
5138
|
-
skipSpaces();
|
|
5139
|
-
if (index < text.length) return null;
|
|
5140
6021
|
return {
|
|
5141
|
-
|
|
5142
|
-
|
|
5143
|
-
|
|
6022
|
+
text: underlineText,
|
|
6023
|
+
range: [line.range[0] + prefix.length + spaceBefore.length, line.range[1] - line.linebreak.length - spaceAfter.length],
|
|
6024
|
+
loc: underlineLoc,
|
|
6025
|
+
marker,
|
|
6026
|
+
raws: {
|
|
6027
|
+
prefix,
|
|
6028
|
+
spaceBefore,
|
|
6029
|
+
spaceAfter
|
|
6030
|
+
}
|
|
5144
6031
|
};
|
|
5145
|
-
|
|
5146
|
-
|
|
5147
|
-
|
|
5148
|
-
|
|
5149
|
-
|
|
6032
|
+
}
|
|
6033
|
+
|
|
6034
|
+
//#endregion
|
|
6035
|
+
//#region src/rules/level1-heading-style.ts
|
|
6036
|
+
var level1_heading_style_default = createRule("level1-heading-style", {
|
|
6037
|
+
meta: {
|
|
6038
|
+
type: "layout",
|
|
6039
|
+
docs: {
|
|
6040
|
+
description: "enforce consistent style for level 1 headings",
|
|
6041
|
+
categories: ["standard"],
|
|
6042
|
+
listCategory: "Stylistic"
|
|
6043
|
+
},
|
|
6044
|
+
fixable: "code",
|
|
6045
|
+
hasSuggestions: false,
|
|
6046
|
+
schema: [{
|
|
6047
|
+
type: "object",
|
|
6048
|
+
properties: {
|
|
6049
|
+
style: { enum: ["atx", "setext"] },
|
|
6050
|
+
allowMultilineSetext: { type: "boolean" }
|
|
6051
|
+
},
|
|
6052
|
+
additionalProperties: false
|
|
6053
|
+
}],
|
|
6054
|
+
messages: {
|
|
6055
|
+
expectedAtx: "Expected ATX style heading (# Heading).",
|
|
6056
|
+
expectedSetext: "Expected Setext style heading (Heading\\n======).",
|
|
6057
|
+
multilineSetextNotAllowed: "Multiline Setext headings are not allowed."
|
|
6058
|
+
}
|
|
6059
|
+
},
|
|
6060
|
+
create(context) {
|
|
6061
|
+
const sourceCode = context.sourceCode;
|
|
6062
|
+
const opt = context.options[0] || {};
|
|
6063
|
+
const style = opt.style ?? "atx";
|
|
6064
|
+
const allowMultilineSetext = opt.allowMultilineSetext;
|
|
6065
|
+
return { heading(node) {
|
|
6066
|
+
if (node.depth !== 1) return;
|
|
6067
|
+
const headingKind = getHeadingKind(sourceCode, node);
|
|
6068
|
+
if (style === "atx") {
|
|
6069
|
+
if (headingKind !== "setext") return;
|
|
6070
|
+
const parsed = parseSetextHeading(sourceCode, node);
|
|
6071
|
+
if (!parsed) return;
|
|
6072
|
+
if (parsed.contentLines.length > 1) {
|
|
6073
|
+
if (allowMultilineSetext) return;
|
|
6074
|
+
context.report({
|
|
6075
|
+
node,
|
|
6076
|
+
messageId: "multilineSetextNotAllowed"
|
|
6077
|
+
});
|
|
6078
|
+
return;
|
|
6079
|
+
}
|
|
6080
|
+
context.report({
|
|
6081
|
+
node,
|
|
6082
|
+
messageId: "expectedAtx",
|
|
6083
|
+
*fix(fixer) {
|
|
6084
|
+
const heading = parsed.contentLines[0];
|
|
6085
|
+
yield fixer.insertTextBeforeRange(heading.range, "# ");
|
|
6086
|
+
const lines = getParsedLines(sourceCode);
|
|
6087
|
+
yield fixer.removeRange(lines.get(parsed.underline.loc.start.line).range);
|
|
6088
|
+
}
|
|
6089
|
+
});
|
|
6090
|
+
} else if (style === "setext") {
|
|
6091
|
+
if (headingKind !== "atx" || node.children.length === 0) return;
|
|
6092
|
+
context.report({
|
|
6093
|
+
node,
|
|
6094
|
+
messageId: "expectedSetext",
|
|
6095
|
+
*fix(fixer) {
|
|
6096
|
+
const parsed = parseATXHeading(sourceCode, node);
|
|
6097
|
+
if (!parsed) return;
|
|
6098
|
+
yield fixer.removeRange([parsed.openingSequence.range[0], parsed.content.range[0]]);
|
|
6099
|
+
if (parsed.closingSequence) yield fixer.removeRange([parsed.content.range[1], parsed.after?.range[1] ?? parsed.closingSequence.range[1]]);
|
|
6100
|
+
const lines = getParsedLines(sourceCode);
|
|
6101
|
+
const underline = "=".repeat(Math.max(getTextWidth(parsed.content.text), 3));
|
|
6102
|
+
const appendingText = `\n${lines.get(parsed.openingSequence.loc.start.line).text.slice(0, parsed.openingSequence.loc.start.column - 1)}${underline}`;
|
|
6103
|
+
yield fixer.insertTextAfter(node, appendingText);
|
|
6104
|
+
}
|
|
6105
|
+
});
|
|
6106
|
+
}
|
|
6107
|
+
} };
|
|
5150
6108
|
}
|
|
5151
|
-
|
|
5152
|
-
|
|
5153
|
-
|
|
5154
|
-
|
|
5155
|
-
|
|
5156
|
-
|
|
5157
|
-
|
|
5158
|
-
|
|
5159
|
-
|
|
5160
|
-
|
|
6109
|
+
});
|
|
6110
|
+
|
|
6111
|
+
//#endregion
|
|
6112
|
+
//#region src/rules/level2-heading-style.ts
|
|
6113
|
+
var level2_heading_style_default = createRule("level2-heading-style", {
|
|
6114
|
+
meta: {
|
|
6115
|
+
type: "layout",
|
|
6116
|
+
docs: {
|
|
6117
|
+
description: "enforce consistent style for level 2 headings",
|
|
6118
|
+
categories: ["standard"],
|
|
6119
|
+
listCategory: "Stylistic"
|
|
6120
|
+
},
|
|
6121
|
+
fixable: "code",
|
|
6122
|
+
hasSuggestions: false,
|
|
6123
|
+
schema: [{
|
|
6124
|
+
type: "object",
|
|
6125
|
+
properties: {
|
|
6126
|
+
style: { enum: ["atx", "setext"] },
|
|
6127
|
+
allowMultilineSetext: { type: "boolean" }
|
|
6128
|
+
},
|
|
6129
|
+
additionalProperties: false
|
|
6130
|
+
}],
|
|
6131
|
+
messages: {
|
|
6132
|
+
expectedAtx: "Expected ATX style heading (## Heading).",
|
|
6133
|
+
expectedSetext: "Expected Setext style heading (Heading\\n------).",
|
|
6134
|
+
multilineSetextNotAllowed: "Multiline Setext headings are not allowed."
|
|
5161
6135
|
}
|
|
5162
|
-
|
|
6136
|
+
},
|
|
6137
|
+
create(context) {
|
|
6138
|
+
const sourceCode = context.sourceCode;
|
|
6139
|
+
const opt = context.options[0] || {};
|
|
6140
|
+
const style = opt.style ?? "atx";
|
|
6141
|
+
const allowMultilineSetext = opt.allowMultilineSetext;
|
|
6142
|
+
return { heading(node) {
|
|
6143
|
+
if (node.depth !== 2) return;
|
|
6144
|
+
const headingKind = getHeadingKind(sourceCode, node);
|
|
6145
|
+
if (style === "atx") {
|
|
6146
|
+
if (headingKind !== "setext") return;
|
|
6147
|
+
const parsed = parseSetextHeading(sourceCode, node);
|
|
6148
|
+
if (!parsed) return;
|
|
6149
|
+
if (parsed.contentLines.length > 1) {
|
|
6150
|
+
if (allowMultilineSetext) return;
|
|
6151
|
+
context.report({
|
|
6152
|
+
node,
|
|
6153
|
+
messageId: "multilineSetextNotAllowed"
|
|
6154
|
+
});
|
|
6155
|
+
return;
|
|
6156
|
+
}
|
|
6157
|
+
context.report({
|
|
6158
|
+
node,
|
|
6159
|
+
messageId: "expectedAtx",
|
|
6160
|
+
*fix(fixer) {
|
|
6161
|
+
const heading = parsed.contentLines[0];
|
|
6162
|
+
yield fixer.insertTextBeforeRange(heading.range, "## ");
|
|
6163
|
+
const lines = getParsedLines(sourceCode);
|
|
6164
|
+
yield fixer.removeRange(lines.get(parsed.underline.loc.start.line).range);
|
|
6165
|
+
}
|
|
6166
|
+
});
|
|
6167
|
+
} else if (style === "setext") {
|
|
6168
|
+
if (headingKind !== "atx" || node.children.length === 0) return;
|
|
6169
|
+
context.report({
|
|
6170
|
+
node,
|
|
6171
|
+
messageId: "expectedSetext",
|
|
6172
|
+
*fix(fixer) {
|
|
6173
|
+
const parsed = parseATXHeading(sourceCode, node);
|
|
6174
|
+
if (!parsed) return;
|
|
6175
|
+
yield fixer.removeRange([parsed.openingSequence.range[0], parsed.content.range[0]]);
|
|
6176
|
+
if (parsed.closingSequence) yield fixer.removeRange([parsed.content.range[1], parsed.after?.range[1] ?? parsed.closingSequence.range[1]]);
|
|
6177
|
+
const lines = getParsedLines(sourceCode);
|
|
6178
|
+
const underline = "-".repeat(Math.max(getTextWidth(parsed.content.text), 3));
|
|
6179
|
+
const appendingText = `\n${lines.get(parsed.openingSequence.loc.start.line).text.slice(0, parsed.openingSequence.loc.start.column - 1)}${underline}`;
|
|
6180
|
+
yield fixer.insertTextAfter(node, appendingText);
|
|
6181
|
+
}
|
|
6182
|
+
});
|
|
6183
|
+
}
|
|
6184
|
+
} };
|
|
5163
6185
|
}
|
|
5164
|
-
}
|
|
6186
|
+
});
|
|
5165
6187
|
|
|
5166
6188
|
//#endregion
|
|
5167
6189
|
//#region src/rules/link-bracket-newline.ts
|
|
@@ -5196,11 +6218,11 @@ var link_bracket_newline_default = createRule("link-bracket-newline", {
|
|
|
5196
6218
|
},
|
|
5197
6219
|
create(context) {
|
|
5198
6220
|
const sourceCode = context.sourceCode;
|
|
5199
|
-
const optionProvider = parseOptions$
|
|
6221
|
+
const optionProvider = parseOptions$4(context.options[0]);
|
|
5200
6222
|
/**
|
|
5201
6223
|
* Parse the options.
|
|
5202
6224
|
*/
|
|
5203
|
-
function parseOptions$
|
|
6225
|
+
function parseOptions$4(option) {
|
|
5204
6226
|
const newline = option?.newline ?? "never";
|
|
5205
6227
|
const multiline = option?.multiline ?? false;
|
|
5206
6228
|
return (bracketsRange) => {
|
|
@@ -5674,11 +6696,11 @@ var link_paren_newline_default = createRule("link-paren-newline", {
|
|
|
5674
6696
|
},
|
|
5675
6697
|
create(context) {
|
|
5676
6698
|
const sourceCode = context.sourceCode;
|
|
5677
|
-
const optionProvider = parseOptions$
|
|
6699
|
+
const optionProvider = parseOptions$4(context.options[0]);
|
|
5678
6700
|
/**
|
|
5679
6701
|
* Parse the options.
|
|
5680
6702
|
*/
|
|
5681
|
-
function parseOptions$
|
|
6703
|
+
function parseOptions$4(option) {
|
|
5682
6704
|
const newline = option?.newline ?? "never";
|
|
5683
6705
|
const multiline = option?.multiline ?? false;
|
|
5684
6706
|
return (openingParenIndex, closingParenIndex) => {
|
|
@@ -6044,10 +7066,22 @@ var list_marker_alignment_default = createRule("list-marker-alignment", {
|
|
|
6044
7066
|
const items = listNode.children;
|
|
6045
7067
|
if (items.length <= 1) return;
|
|
6046
7068
|
const referenceMarkerLocation = getMarkerLocation(items[0]);
|
|
7069
|
+
const expectedWidth = getWidth(sourceCode.lines[referenceMarkerLocation.line - 1].slice(0, referenceMarkerLocation[alignPositionName]));
|
|
6047
7070
|
for (const item of items.slice(1)) {
|
|
6048
7071
|
const markerLocation = getMarkerLocation(item);
|
|
6049
|
-
const
|
|
7072
|
+
const actualWidth = getWidth(sourceCode.lines[markerLocation.line - 1].slice(0, markerLocation[alignPositionName]));
|
|
7073
|
+
const diff = actualWidth - expectedWidth;
|
|
6050
7074
|
if (diff === 0) continue;
|
|
7075
|
+
const messageData = alignPositionName === "start" ? {
|
|
7076
|
+
expected: String(expectedWidth),
|
|
7077
|
+
actual: String(actualWidth)
|
|
7078
|
+
} : (() => {
|
|
7079
|
+
const start = getWidth(sourceCode.lines[markerLocation.line - 1].slice(0, markerLocation.start));
|
|
7080
|
+
return {
|
|
7081
|
+
expected: String(start - diff),
|
|
7082
|
+
actual: String(start)
|
|
7083
|
+
};
|
|
7084
|
+
})();
|
|
6051
7085
|
context.report({
|
|
6052
7086
|
node: item,
|
|
6053
7087
|
loc: {
|
|
@@ -6061,10 +7095,7 @@ var list_marker_alignment_default = createRule("list-marker-alignment", {
|
|
|
6061
7095
|
}
|
|
6062
7096
|
},
|
|
6063
7097
|
messageId: "incorrectAlignment",
|
|
6064
|
-
data:
|
|
6065
|
-
expected: String(markerLocation.start - diff),
|
|
6066
|
-
actual: String(markerLocation.start)
|
|
6067
|
-
},
|
|
7098
|
+
data: messageData,
|
|
6068
7099
|
fix(fixer) {
|
|
6069
7100
|
const lines = getParsedLines(sourceCode);
|
|
6070
7101
|
const line = lines.get(markerLocation.line);
|
|
@@ -6072,13 +7103,17 @@ var list_marker_alignment_default = createRule("list-marker-alignment", {
|
|
|
6072
7103
|
const addSpaces = " ".repeat(-diff);
|
|
6073
7104
|
return fixer.insertTextBeforeRange([line.range[0] + markerLocation.start, line.range[0] + markerLocation.start], addSpaces);
|
|
6074
7105
|
}
|
|
6075
|
-
const
|
|
6076
|
-
|
|
6077
|
-
|
|
6078
|
-
|
|
6079
|
-
const
|
|
6080
|
-
|
|
7106
|
+
const beforeItemMarker = line.text.slice(0, markerLocation.start);
|
|
7107
|
+
const newWidth = getWidth(beforeItemMarker) - diff;
|
|
7108
|
+
let newBeforeItemMarker = beforeItemMarker;
|
|
7109
|
+
while (getWidth(newBeforeItemMarker) > newWidth) {
|
|
7110
|
+
const last = newBeforeItemMarker.at(-1);
|
|
7111
|
+
if (last && isWhitespace(last)) newBeforeItemMarker = newBeforeItemMarker.slice(0, -1);
|
|
7112
|
+
else return null;
|
|
6081
7113
|
}
|
|
7114
|
+
if (getWidth(newBeforeItemMarker) < newWidth) newBeforeItemMarker += " ".repeat(newWidth - getWidth(newBeforeItemMarker));
|
|
7115
|
+
const referenceBeforeItemMarker = lines.get(referenceMarkerLocation.line).text.slice(0, referenceMarkerLocation.start);
|
|
7116
|
+
if (!referenceBeforeItemMarker.includes(">") || referenceBeforeItemMarker === newBeforeItemMarker) return fixer.replaceTextRange([line.range[0], line.range[0] + markerLocation.start], newBeforeItemMarker);
|
|
6082
7117
|
return null;
|
|
6083
7118
|
}
|
|
6084
7119
|
});
|
|
@@ -6212,6 +7247,7 @@ var no_multi_spaces_default = createRule("no-multi-spaces", {
|
|
|
6212
7247
|
},
|
|
6213
7248
|
create(context) {
|
|
6214
7249
|
const sourceCode = context.sourceCode;
|
|
7250
|
+
let codeText = sourceCode.text;
|
|
6215
7251
|
return {
|
|
6216
7252
|
definition: verifyLinkDefinition,
|
|
6217
7253
|
footnoteDefinition: verifyFootnoteDefinition,
|
|
@@ -6221,6 +7257,7 @@ var no_multi_spaces_default = createRule("no-multi-spaces", {
|
|
|
6221
7257
|
link: verifyLink,
|
|
6222
7258
|
linkReference: verifyLinkReference,
|
|
6223
7259
|
listItem: verifyListItem,
|
|
7260
|
+
blockquote: processBlockquote,
|
|
6224
7261
|
text: verifyText
|
|
6225
7262
|
};
|
|
6226
7263
|
/**
|
|
@@ -6294,7 +7331,13 @@ var no_multi_spaces_default = createRule("no-multi-spaces", {
|
|
|
6294
7331
|
* Verify a list item node
|
|
6295
7332
|
*/
|
|
6296
7333
|
function verifyListItem(node) {
|
|
6297
|
-
|
|
7334
|
+
const nodeRange = sourceCode.getRange(node);
|
|
7335
|
+
const parsed = parseListItem(sourceCode, node);
|
|
7336
|
+
if (parsed.taskListItemMarker) verifyTextInRange(node, [nodeRange[0], parsed.taskListItemMarker.range[0]]);
|
|
7337
|
+
let newCodeText = codeText.slice(0, parsed.marker.range[0]) + " ".repeat(parsed.marker.range[1] - parsed.marker.range[0]);
|
|
7338
|
+
if (parsed.taskListItemMarker) newCodeText += codeText.slice(parsed.marker.range[1], parsed.taskListItemMarker.range[0]) + " ".repeat(parsed.taskListItemMarker.range[1] - parsed.taskListItemMarker.range[0]) + codeText.slice(parsed.taskListItemMarker.range[1]);
|
|
7339
|
+
else newCodeText += codeText.slice(parsed.marker.range[1]);
|
|
7340
|
+
codeText = newCodeText;
|
|
6298
7341
|
}
|
|
6299
7342
|
/**
|
|
6300
7343
|
* Verify spaces in a node
|
|
@@ -6304,6 +7347,26 @@ var no_multi_spaces_default = createRule("no-multi-spaces", {
|
|
|
6304
7347
|
verifyTextInRange(node, nodeRange);
|
|
6305
7348
|
}
|
|
6306
7349
|
/**
|
|
7350
|
+
* Process a blockquote node
|
|
7351
|
+
*/
|
|
7352
|
+
function processBlockquote(node) {
|
|
7353
|
+
const nodeRange = sourceCode.getRange(node);
|
|
7354
|
+
let newCodeText = "";
|
|
7355
|
+
let inIndent = true;
|
|
7356
|
+
for (let index = nodeRange[0]; index < nodeRange[1]; index++) {
|
|
7357
|
+
const c = codeText[index];
|
|
7358
|
+
if (c === "\n") {
|
|
7359
|
+
inIndent = true;
|
|
7360
|
+
continue;
|
|
7361
|
+
}
|
|
7362
|
+
if (isWhitespace(c)) continue;
|
|
7363
|
+
if (c === ">" && inIndent) newCodeText += `${codeText.slice(newCodeText.length, index)} `;
|
|
7364
|
+
inIndent = false;
|
|
7365
|
+
}
|
|
7366
|
+
newCodeText += codeText.slice(newCodeText.length);
|
|
7367
|
+
codeText = newCodeText;
|
|
7368
|
+
}
|
|
7369
|
+
/**
|
|
6307
7370
|
* Verify spaces in a node excluding children
|
|
6308
7371
|
*/
|
|
6309
7372
|
function verifyTextOutsideChildren(node) {
|
|
@@ -6322,14 +7385,14 @@ var no_multi_spaces_default = createRule("no-multi-spaces", {
|
|
|
6322
7385
|
*/
|
|
6323
7386
|
function verifyTextInRange(node, textRange) {
|
|
6324
7387
|
const nodeRange = sourceCode.getRange(node);
|
|
6325
|
-
const text =
|
|
7388
|
+
const text = codeText.slice(...textRange);
|
|
6326
7389
|
const reSpaces = /\s{2,}|\n/gu;
|
|
6327
7390
|
let match;
|
|
6328
7391
|
while ((match = reSpaces.exec(text)) !== null) {
|
|
6329
7392
|
const spaces = match[0];
|
|
6330
7393
|
if (spaces.includes("\n")) {
|
|
6331
7394
|
let c = "";
|
|
6332
|
-
while ((c = text[reSpaces.lastIndex]) && (c
|
|
7395
|
+
while ((c = text[reSpaces.lastIndex]) && isWhitespace(c)) reSpaces.lastIndex++;
|
|
6333
7396
|
continue;
|
|
6334
7397
|
}
|
|
6335
7398
|
if (spaces.length < 2) continue;
|
|
@@ -6339,7 +7402,7 @@ var no_multi_spaces_default = createRule("no-multi-spaces", {
|
|
|
6339
7402
|
if (nodeRange[0] === range[0]) {
|
|
6340
7403
|
let isIndentation = true;
|
|
6341
7404
|
for (let index = nodeRange[0] - 1; index >= 0; index--) {
|
|
6342
|
-
const c =
|
|
7405
|
+
const c = codeText[index];
|
|
6343
7406
|
if (c === "\n") break;
|
|
6344
7407
|
if (isWhitespace(c)) continue;
|
|
6345
7408
|
isIndentation = false;
|
|
@@ -6349,8 +7412,8 @@ var no_multi_spaces_default = createRule("no-multi-spaces", {
|
|
|
6349
7412
|
}
|
|
6350
7413
|
if (nodeRange[1] === range[1]) {
|
|
6351
7414
|
let isTrailingSpaces = true;
|
|
6352
|
-
for (let index = nodeRange[1]; index <
|
|
6353
|
-
const c =
|
|
7415
|
+
for (let index = nodeRange[1]; index < codeText.length; index++) {
|
|
7416
|
+
const c = codeText[index];
|
|
6354
7417
|
if (c === "\n") break;
|
|
6355
7418
|
if (isWhitespace(c)) continue;
|
|
6356
7419
|
isTrailingSpaces = false;
|
|
@@ -8814,6 +9877,7 @@ const rules$1 = [
|
|
|
8814
9877
|
emphasis_delimiters_style_default,
|
|
8815
9878
|
hard_linebreak_style_default,
|
|
8816
9879
|
heading_casing_default,
|
|
9880
|
+
indent_default,
|
|
8817
9881
|
level1_heading_style_default,
|
|
8818
9882
|
level2_heading_style_default,
|
|
8819
9883
|
link_bracket_newline_default,
|
|
@@ -8848,8 +9912,7 @@ const rules$1 = [
|
|
|
8848
9912
|
|
|
8849
9913
|
//#endregion
|
|
8850
9914
|
//#region src/configs/recommended.ts
|
|
8851
|
-
var recommended_exports = {
|
|
8852
|
-
__export(recommended_exports, {
|
|
9915
|
+
var recommended_exports = __export({
|
|
8853
9916
|
files: () => files$1,
|
|
8854
9917
|
language: () => language$1,
|
|
8855
9918
|
languageOptions: () => languageOptions$1,
|
|
@@ -8879,8 +9942,7 @@ const rules$3 = {
|
|
|
8879
9942
|
|
|
8880
9943
|
//#endregion
|
|
8881
9944
|
//#region src/configs/standard.ts
|
|
8882
|
-
var standard_exports = {
|
|
8883
|
-
__export(standard_exports, {
|
|
9945
|
+
var standard_exports = __export({
|
|
8884
9946
|
files: () => files,
|
|
8885
9947
|
language: () => language,
|
|
8886
9948
|
languageOptions: () => languageOptions,
|
|
@@ -8907,6 +9969,7 @@ const rules$2 = {
|
|
|
8907
9969
|
"markdown-preferences/code-fence-style": "error",
|
|
8908
9970
|
"markdown-preferences/emphasis-delimiters-style": "error",
|
|
8909
9971
|
"markdown-preferences/hard-linebreak-style": "error",
|
|
9972
|
+
"markdown-preferences/indent": "error",
|
|
8910
9973
|
"markdown-preferences/level1-heading-style": "error",
|
|
8911
9974
|
"markdown-preferences/level2-heading-style": "error",
|
|
8912
9975
|
"markdown-preferences/link-bracket-newline": "error",
|
|
@@ -8937,13 +10000,12 @@ const rules$2 = {
|
|
|
8937
10000
|
|
|
8938
10001
|
//#endregion
|
|
8939
10002
|
//#region src/meta.ts
|
|
8940
|
-
var meta_exports = {
|
|
8941
|
-
__export(meta_exports, {
|
|
10003
|
+
var meta_exports = __export({
|
|
8942
10004
|
name: () => name,
|
|
8943
10005
|
version: () => version
|
|
8944
10006
|
});
|
|
8945
10007
|
const name = "eslint-plugin-markdown-preferences";
|
|
8946
|
-
const version = "0.
|
|
10008
|
+
const version = "0.24.0";
|
|
8947
10009
|
|
|
8948
10010
|
//#endregion
|
|
8949
10011
|
//#region src/index.ts
|