eslint-plugin-yml 1.18.0 → 1.19.1

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/lib/meta.d.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  export declare const name: "eslint-plugin-yml";
2
- export declare const version: "1.18.0";
2
+ export declare const version: "1.19.1";
package/lib/meta.js CHANGED
@@ -2,4 +2,4 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.version = exports.name = void 0;
4
4
  exports.name = "eslint-plugin-yml";
5
- exports.version = "1.18.0";
5
+ exports.version = "1.19.1";
@@ -7,6 +7,7 @@ const natural_compare_1 = __importDefault(require("natural-compare"));
7
7
  const index_1 = require("../utils/index");
8
8
  const ast_utils_1 = require("../utils/ast-utils");
9
9
  const compat_1 = require("../utils/compat");
10
+ const calc_shortest_edit_script_1 = require("../utils/calc-shortest-edit-script");
10
11
  function isNewLine(char) {
11
12
  return (char === "\n" || char === "\r" || char === "\u2028" || char === "\u2029");
12
13
  }
@@ -306,7 +307,8 @@ exports.default = (0, index_1.createRule)("sort-keys", {
306
307
  ],
307
308
  },
308
309
  messages: {
309
- sortKeys: "Expected mapping keys to be in {{orderText}} order. '{{thisName}}' should be before '{{prevName}}'.",
310
+ shouldBeBefore: "Expected mapping keys to be in {{orderText}} order. '{{thisName}}' should be before '{{targetName}}'.",
311
+ shouldBeAfter: "Expected mapping keys to be in {{orderText}} order. '{{thisName}}' should be after '{{targetName}}'.",
310
312
  },
311
313
  type: "suggestion",
312
314
  },
@@ -317,16 +319,18 @@ exports.default = (0, index_1.createRule)("sort-keys", {
317
319
  return {};
318
320
  }
319
321
  const parsedOptions = parseOptions(context.options, sourceCode);
320
- function isValidOrder(prevData, thisData, option) {
321
- if (option.isValidOrder(prevData, thisData)) {
322
- return true;
323
- }
324
- for (const aliasName of thisData.anchorAlias.aliases) {
322
+ function shouldKeepOrder(prevData, nextData) {
323
+ if ((prevData.anchorAlias.aliases.size === 0 &&
324
+ prevData.anchorAlias.anchors.size === 0) ||
325
+ (nextData.anchorAlias.aliases.size === 0 &&
326
+ nextData.anchorAlias.anchors.size === 0))
327
+ return false;
328
+ for (const aliasName of nextData.anchorAlias.aliases) {
325
329
  if (prevData.anchorAlias.anchors.has(aliasName)) {
326
330
  return true;
327
331
  }
328
332
  }
329
- for (const anchorName of thisData.anchorAlias.anchors) {
333
+ for (const anchorName of nextData.anchorAlias.anchors) {
330
334
  if (prevData.anchorAlias.aliases.has(anchorName)) {
331
335
  return true;
332
336
  }
@@ -339,55 +343,176 @@ exports.default = (0, index_1.createRule)("sort-keys", {
339
343
  }
340
344
  return option.ignore(data);
341
345
  }
342
- function verifyPair(data, option) {
343
- if (ignore(data, option)) {
344
- return;
345
- }
346
- const prevList = [];
347
- let currTarget = data;
348
- let prevTarget;
349
- while ((prevTarget = currTarget.getPrev())) {
350
- if (option.allowLineSeparatedGroups) {
351
- if (hasBlankLine(prevTarget, currTarget)) {
352
- break;
353
- }
346
+ function groupingPairs(pairs, option) {
347
+ const groups = [];
348
+ let group = [];
349
+ let prev = null;
350
+ for (const pair of pairs) {
351
+ if (ignore(pair, option)) {
352
+ prev = pair;
353
+ continue;
354
354
  }
355
- if (!ignore(prevTarget, option)) {
356
- prevList.push(prevTarget);
355
+ if (prev &&
356
+ option.allowLineSeparatedGroups &&
357
+ hasBlankLine(prev, pair)) {
358
+ if (group.length > 0) {
359
+ groups.push(group);
360
+ group = [];
361
+ }
357
362
  }
358
- currTarget = prevTarget;
363
+ group.push(pair);
364
+ prev = pair;
359
365
  }
360
- if (prevList.length === 0) {
361
- return;
366
+ if (group.length > 0) {
367
+ groups.push(group);
362
368
  }
363
- const prev = prevList[0];
364
- if (!isValidOrder(prev, data, option)) {
365
- context.report({
366
- loc: data.reportLoc,
367
- messageId: "sortKeys",
368
- data: {
369
- thisName: data.name,
370
- prevName: prev.name,
371
- orderText: option.orderText,
372
- },
373
- *fix(fixer) {
374
- let moveTarget = prevList[0];
375
- for (const prev of prevList) {
376
- if (isValidOrder(prev, data, option)) {
377
- break;
369
+ return groups;
370
+ }
371
+ function bubbleSort(pairs, option) {
372
+ const l = pairs.length;
373
+ const result = [...pairs];
374
+ let swapped;
375
+ do {
376
+ swapped = false;
377
+ for (let nextIndex = 1; nextIndex < l; nextIndex++) {
378
+ const prevIndex = nextIndex - 1;
379
+ if (option.isValidOrder(result[prevIndex], result[nextIndex]) ||
380
+ shouldKeepOrder(result[prevIndex], result[nextIndex]))
381
+ continue;
382
+ [result[prevIndex], result[nextIndex]] = [
383
+ result[nextIndex],
384
+ result[prevIndex],
385
+ ];
386
+ swapped = true;
387
+ }
388
+ } while (swapped);
389
+ return result;
390
+ }
391
+ function verifyPairs(pairs, option) {
392
+ const sorted = bubbleSort(pairs, option);
393
+ const editScript = (0, calc_shortest_edit_script_1.calcShortestEditScript)(pairs, sorted);
394
+ for (let index = 0; index < editScript.length; index++) {
395
+ const edit = editScript[index];
396
+ if (edit.type !== "delete")
397
+ continue;
398
+ const insertEditIndex = editScript.findIndex((e) => e.type === "insert" && e.b === edit.a);
399
+ if (insertEditIndex === -1) {
400
+ continue;
401
+ }
402
+ if (index < insertEditIndex) {
403
+ const target = findInsertAfterTarget(edit.a, insertEditIndex);
404
+ if (!target) {
405
+ continue;
406
+ }
407
+ context.report({
408
+ loc: edit.a.reportLoc,
409
+ messageId: "shouldBeAfter",
410
+ data: {
411
+ thisName: edit.a.name,
412
+ targetName: target.name,
413
+ orderText: option.orderText,
414
+ },
415
+ *fix(fixer) {
416
+ if (edit.a.mapping.node.style === "flow") {
417
+ yield* fixToMoveDownForFlow(fixer, edit.a, target);
378
418
  }
379
419
  else {
380
- moveTarget = prev;
420
+ yield* fixToMoveDownForBlock(fixer, edit.a, target);
381
421
  }
422
+ },
423
+ });
424
+ }
425
+ else {
426
+ const target = findInsertBeforeTarget(edit.a, insertEditIndex);
427
+ if (!target) {
428
+ continue;
429
+ }
430
+ context.report({
431
+ loc: edit.a.reportLoc,
432
+ messageId: "shouldBeBefore",
433
+ data: {
434
+ thisName: edit.a.name,
435
+ targetName: target.name,
436
+ orderText: option.orderText,
437
+ },
438
+ *fix(fixer) {
439
+ if (edit.a.mapping.node.style === "flow") {
440
+ yield* fixToMoveUpForFlow(fixer, edit.a, target);
441
+ }
442
+ else {
443
+ yield* fixToMoveUpForBlock(fixer, edit.a, target);
444
+ }
445
+ },
446
+ });
447
+ }
448
+ }
449
+ function findInsertAfterTarget(pair, insertEditIndex) {
450
+ let candidate = null;
451
+ for (let index = insertEditIndex - 1; index >= 0; index--) {
452
+ const edit = editScript[index];
453
+ if (edit.type === "delete" && edit.a === pair)
454
+ break;
455
+ if (edit.type !== "common")
456
+ continue;
457
+ candidate = edit.a;
458
+ break;
459
+ }
460
+ const pairIndex = pairs.indexOf(pair);
461
+ if (candidate) {
462
+ for (let index = pairIndex + 1; index < pairs.length; index++) {
463
+ const element = pairs[index];
464
+ if (element === candidate)
465
+ return candidate;
466
+ if (shouldKeepOrder(pair, element)) {
467
+ break;
382
468
  }
383
- if (data.mapping.node.style === "flow") {
384
- yield* fixForFlow(fixer, data, moveTarget);
385
- }
386
- else {
387
- yield* fixForBlock(fixer, data, moveTarget);
469
+ }
470
+ }
471
+ let lastTarget = null;
472
+ for (let index = pairIndex + 1; index < pairs.length; index++) {
473
+ const element = pairs[index];
474
+ if (option.isValidOrder(element, pair) &&
475
+ !shouldKeepOrder(pair, element)) {
476
+ lastTarget = element;
477
+ continue;
478
+ }
479
+ return lastTarget;
480
+ }
481
+ return lastTarget;
482
+ }
483
+ function findInsertBeforeTarget(pair, insertEditIndex) {
484
+ let candidate = null;
485
+ for (let index = insertEditIndex + 1; index < editScript.length; index++) {
486
+ const edit = editScript[index];
487
+ if (edit.type === "delete" && edit.a === pair)
488
+ break;
489
+ if (edit.type !== "common")
490
+ continue;
491
+ candidate = edit.a;
492
+ break;
493
+ }
494
+ const pairIndex = pairs.indexOf(pair);
495
+ if (candidate) {
496
+ for (let index = pairIndex - 1; index >= 0; index--) {
497
+ const element = pairs[index];
498
+ if (element === candidate)
499
+ return candidate;
500
+ if (shouldKeepOrder(element, pair)) {
501
+ break;
388
502
  }
389
- },
390
- });
503
+ }
504
+ }
505
+ let lastTarget = null;
506
+ for (let index = pairIndex - 1; index >= 0; index--) {
507
+ const element = pairs[index];
508
+ if (option.isValidOrder(pair, element) &&
509
+ !shouldKeepOrder(element, pair)) {
510
+ lastTarget = element;
511
+ continue;
512
+ }
513
+ return lastTarget;
514
+ }
515
+ return lastTarget;
391
516
  }
392
517
  }
393
518
  function hasBlankLine(prev, next) {
@@ -444,12 +569,44 @@ exports.default = (0, index_1.createRule)("sort-keys", {
444
569
  if (!option) {
445
570
  return;
446
571
  }
447
- for (const pair of data.pairs) {
448
- verifyPair(pair, option);
572
+ for (const pairs of groupingPairs(data.pairs, option)) {
573
+ verifyPairs(pairs, option);
449
574
  }
450
575
  },
451
576
  };
452
- function* fixForFlow(fixer, data, moveTarget) {
577
+ function* fixToMoveDownForFlow(fixer, data, moveTarget) {
578
+ const beforeToken = sourceCode.getTokenBefore(data.node);
579
+ let insertCode, removeRange, insertTargetToken;
580
+ const afterCommaToken = sourceCode.getTokenAfter(data.node);
581
+ if ((0, ast_utils_1.isComma)(afterCommaToken)) {
582
+ removeRange = [beforeToken.range[1], afterCommaToken.range[1]];
583
+ const moveTargetAfterToken = sourceCode.getTokenAfter(moveTarget.node);
584
+ if ((0, ast_utils_1.isComma)(moveTargetAfterToken)) {
585
+ insertTargetToken = moveTargetAfterToken;
586
+ insertCode = sourceCode.text.slice(...removeRange);
587
+ }
588
+ else {
589
+ insertTargetToken = sourceCode.getLastToken(moveTarget.node);
590
+ insertCode = sourceCode.text.slice(beforeToken.range[1], afterCommaToken.range[0]);
591
+ insertCode = `,${insertCode}`;
592
+ }
593
+ }
594
+ else {
595
+ if ((0, ast_utils_1.isComma)(beforeToken)) {
596
+ removeRange = [beforeToken.range[0], data.node.range[1]];
597
+ insertCode = sourceCode.text.slice(...removeRange);
598
+ insertTargetToken = sourceCode.getLastToken(moveTarget.node);
599
+ }
600
+ else {
601
+ removeRange = [beforeToken.range[1], data.node.range[1]];
602
+ insertCode = `,${sourceCode.text.slice(...removeRange)}`;
603
+ insertTargetToken = sourceCode.getLastToken(moveTarget.node);
604
+ }
605
+ }
606
+ yield fixer.removeRange(removeRange);
607
+ yield fixer.insertTextAfterRange(insertTargetToken.range, insertCode);
608
+ }
609
+ function* fixToMoveUpForFlow(fixer, data, moveTarget) {
453
610
  const beforeCommaToken = sourceCode.getTokenBefore(data.node);
454
611
  let insertCode, removeRange, insertTargetToken;
455
612
  const afterCommaToken = sourceCode.getTokenAfter(data.node);
@@ -473,7 +630,57 @@ exports.default = (0, index_1.createRule)("sort-keys", {
473
630
  yield fixer.insertTextAfterRange(insertTargetToken.range, insertCode);
474
631
  yield fixer.removeRange(removeRange);
475
632
  }
476
- function* fixForBlock(fixer, data, moveTarget) {
633
+ function* fixToMoveDownForBlock(fixer, data, moveTarget) {
634
+ const nodeLocs = getPairRangeForBlock(data.node);
635
+ const moveTargetLocs = getPairRangeForBlock(moveTarget.node);
636
+ if (nodeLocs.loc.start.column === 0) {
637
+ const removeRange = [
638
+ getNewlineStartIndex(nodeLocs.range[0]),
639
+ nodeLocs.range[1],
640
+ ];
641
+ const moveTargetRange = [
642
+ getNewlineStartIndex(moveTargetLocs.range[0]),
643
+ moveTargetLocs.range[1],
644
+ ];
645
+ const insertCode = sourceCode.text.slice(...removeRange);
646
+ const isAtFileStart = nodeLocs.loc.start.line === 1;
647
+ if (isAtFileStart) {
648
+ const removeRangeEnd = nodeLocs.range[1];
649
+ const len = sourceCode.text.length;
650
+ if (removeRangeEnd < len) {
651
+ const ch = sourceCode.text[removeRangeEnd];
652
+ if (isNewLine(ch)) {
653
+ if (ch === "\r" &&
654
+ removeRangeEnd + 1 < len &&
655
+ sourceCode.text[removeRangeEnd + 1] === "\n") {
656
+ removeRange[1] += 2;
657
+ }
658
+ else {
659
+ removeRange[1] += 1;
660
+ }
661
+ }
662
+ }
663
+ }
664
+ yield fixer.removeRange(removeRange);
665
+ yield fixer.insertTextAfterRange(moveTargetRange, `${isAtFileStart ? "\n" : ""}${insertCode}`);
666
+ }
667
+ else {
668
+ const nextToken = sourceCode.getTokenAfter(data.node, {
669
+ includeComments: true,
670
+ });
671
+ const removeRange = [data.node.range[0], nextToken.range[0]];
672
+ yield fixer.removeRange(removeRange);
673
+ const indentCode = sourceCode.text
674
+ .slice(sourceCode.getIndexFromLoc({
675
+ line: nodeLocs.loc.start.line,
676
+ column: 0,
677
+ }), data.node.range[0])
678
+ .replace(/\S/g, " ");
679
+ const insertCode = `\n${indentCode}${sourceCode.text.slice(data.node.range[0], nodeLocs.range[1])}`;
680
+ yield fixer.insertTextAfterRange(moveTargetLocs.range, insertCode);
681
+ }
682
+ }
683
+ function* fixToMoveUpForBlock(fixer, data, moveTarget) {
477
684
  const nodeLocs = getPairRangeForBlock(data.node);
478
685
  const moveTargetLocs = getPairRangeForBlock(moveTarget.node);
479
686
  if (moveTargetLocs.loc.start.column === 0) {
@@ -514,7 +721,7 @@ exports.default = (0, index_1.createRule)("sort-keys", {
514
721
  return 0;
515
722
  }
516
723
  function getPairRangeForBlock(node) {
517
- let endOfRange, end;
724
+ let end;
518
725
  const afterToken = sourceCode.getTokenAfter(node, {
519
726
  includeComments: true,
520
727
  filter: (t) => !(0, ast_utils_1.isCommentToken)(t) || node.loc.end.line < t.loc.start.line,
@@ -525,14 +732,17 @@ exports.default = (0, index_1.createRule)("sort-keys", {
525
732
  : node.loc.end.line;
526
733
  const lineText = sourceCode.lines[line - 1];
527
734
  end = {
528
- line,
529
- column: lineText.length,
735
+ loc: { line, column: lineText.length },
736
+ get index() {
737
+ return sourceCode.getIndexFromLoc(this.loc);
738
+ },
530
739
  };
531
- endOfRange = sourceCode.getIndexFromLoc(end);
532
740
  }
533
741
  else {
534
- endOfRange = node.range[1];
535
- end = node.loc.end;
742
+ end = {
743
+ index: node.range[1],
744
+ loc: node.loc.end,
745
+ };
536
746
  }
537
747
  const beforeToken = sourceCode.getTokenBefore(node);
538
748
  if (beforeToken) {
@@ -547,18 +757,15 @@ exports.default = (0, index_1.createRule)("sort-keys", {
547
757
  : node.loc.start.line,
548
758
  column: 0,
549
759
  };
550
- const startOfRange = sourceCode.getIndexFromLoc(start);
551
760
  return {
552
- range: [startOfRange, endOfRange],
553
- loc: { start, end },
761
+ range: [sourceCode.getIndexFromLoc(start), end.index],
762
+ loc: { start, end: end.loc },
554
763
  indentColumn: next.loc.start.column,
555
764
  };
556
765
  }
557
- const start = beforeToken.loc.end;
558
- const startOfRange = beforeToken.range[1];
559
766
  return {
560
- range: [startOfRange, endOfRange],
561
- loc: { start, end },
767
+ range: [beforeToken.range[1], end.index],
768
+ loc: { start: beforeToken.loc.end, end: end.loc },
562
769
  indentColumn: node.range[0] - beforeToken.range[1],
563
770
  };
564
771
  }
@@ -575,8 +782,8 @@ exports.default = (0, index_1.createRule)("sort-keys", {
575
782
  };
576
783
  const startOfRange = sourceCode.getIndexFromLoc(start);
577
784
  return {
578
- range: [startOfRange, endOfRange],
579
- loc: { start, end },
785
+ range: [startOfRange, end.index],
786
+ loc: { start, end: end.loc },
580
787
  indentColumn: next.loc.start.column,
581
788
  };
582
789
  }
@@ -588,8 +795,8 @@ exports.default = (0, index_1.createRule)("sort-keys", {
588
795
  };
589
796
  const startOfRange = sourceCode.getIndexFromLoc(start);
590
797
  return {
591
- range: [startOfRange, endOfRange],
592
- loc: { start, end },
798
+ range: [startOfRange, end.index],
799
+ loc: { start, end: end.loc },
593
800
  indentColumn: node.loc.start.column,
594
801
  };
595
802
  }
@@ -8,6 +8,7 @@ const index_1 = require("../utils/index");
8
8
  const ast_utils_1 = require("../utils/ast-utils");
9
9
  const yaml_eslint_parser_1 = require("yaml-eslint-parser");
10
10
  const compat_1 = require("../utils/compat");
11
+ const calc_shortest_edit_script_1 = require("../utils/calc-shortest-edit-script");
11
12
  class YAMLEntryData {
12
13
  get reportLoc() {
13
14
  if (this.node) {
@@ -298,7 +299,8 @@ exports.default = (0, index_1.createRule)("sort-sequence-values", {
298
299
  minItems: 1,
299
300
  },
300
301
  messages: {
301
- sortValues: "Expected sequence values to be in {{orderText}} order. '{{thisValue}}' should be before '{{prevValue}}'.",
302
+ shouldBeBefore: "Expected sequence values to be in {{orderText}} order. '{{thisValue}}' should be before '{{targetValue}}'.",
303
+ shouldBeAfter: "Expected sequence values to be in {{orderText}} order. '{{thisValue}}' should be after '{{targetValue}}'.",
302
304
  },
303
305
  type: "suggestion",
304
306
  },
@@ -309,62 +311,169 @@ exports.default = (0, index_1.createRule)("sort-sequence-values", {
309
311
  return {};
310
312
  }
311
313
  const parsedOptions = parseOptions(context.options, sourceCode);
312
- function isValidOrder(prevData, thisData, option) {
313
- if (option.isValidOrder(prevData, thisData)) {
314
- return true;
315
- }
316
- for (const aliasName of thisData.anchorAlias.aliases) {
314
+ function shouldKeepOrder(prevData, nextData) {
315
+ if ((prevData.anchorAlias.aliases.size === 0 &&
316
+ prevData.anchorAlias.anchors.size === 0) ||
317
+ (nextData.anchorAlias.aliases.size === 0 &&
318
+ nextData.anchorAlias.anchors.size === 0))
319
+ return false;
320
+ for (const aliasName of nextData.anchorAlias.aliases) {
317
321
  if (prevData.anchorAlias.anchors.has(aliasName)) {
318
322
  return true;
319
323
  }
320
324
  }
321
- for (const anchorName of thisData.anchorAlias.anchors) {
325
+ for (const anchorName of nextData.anchorAlias.anchors) {
322
326
  if (prevData.anchorAlias.aliases.has(anchorName)) {
323
327
  return true;
324
328
  }
325
329
  }
326
330
  return false;
327
331
  }
328
- function verifyArrayElement(data, option) {
329
- if (option.ignore(data)) {
330
- return;
331
- }
332
- const prevList = data.sequence.entries
333
- .slice(0, data.index)
334
- .reverse()
335
- .filter((d) => !option.ignore(d));
336
- if (prevList.length === 0) {
337
- return;
338
- }
339
- const prev = prevList[0];
340
- if (!isValidOrder(prev, data, option)) {
341
- const reportLoc = data.reportLoc;
342
- context.report({
343
- loc: reportLoc,
344
- messageId: "sortValues",
345
- data: {
346
- thisValue: toText(data),
347
- prevValue: toText(prev),
348
- orderText: option.orderText(data),
349
- },
350
- *fix(fixer) {
351
- let moveTarget = prevList[0];
352
- for (const prev of prevList) {
353
- if (isValidOrder(prev, data, option)) {
354
- break;
332
+ function bubbleSort(entries, option) {
333
+ const l = entries.length;
334
+ const result = [...entries];
335
+ let swapped;
336
+ do {
337
+ swapped = false;
338
+ for (let nextIndex = 1; nextIndex < l; nextIndex++) {
339
+ const prevIndex = nextIndex - 1;
340
+ if (option.isValidOrder(result[prevIndex], result[nextIndex]) ||
341
+ shouldKeepOrder(result[prevIndex], result[nextIndex]))
342
+ continue;
343
+ [result[prevIndex], result[nextIndex]] = [
344
+ result[nextIndex],
345
+ result[prevIndex],
346
+ ];
347
+ swapped = true;
348
+ }
349
+ } while (swapped);
350
+ return result;
351
+ }
352
+ function verifyArrayElements(entries, option) {
353
+ const sorted = bubbleSort(entries, option);
354
+ const editScript = (0, calc_shortest_edit_script_1.calcShortestEditScript)(entries, sorted);
355
+ for (let index = 0; index < editScript.length; index++) {
356
+ const edit = editScript[index];
357
+ if (edit.type !== "delete")
358
+ continue;
359
+ const insertEditIndex = editScript.findIndex((e) => e.type === "insert" && e.b === edit.a);
360
+ if (insertEditIndex === -1) {
361
+ continue;
362
+ }
363
+ if (index < insertEditIndex) {
364
+ const target = findInsertAfterTarget(edit.a, insertEditIndex);
365
+ if (!target) {
366
+ continue;
367
+ }
368
+ context.report({
369
+ loc: edit.a.reportLoc,
370
+ messageId: "shouldBeAfter",
371
+ data: {
372
+ thisValue: toText(edit.a),
373
+ targetValue: toText(target),
374
+ orderText: option.orderText(edit.a),
375
+ },
376
+ *fix(fixer) {
377
+ if (edit.a.sequence.node.style === "flow") {
378
+ yield* fixToMoveDownForFlow(fixer, edit.a, target);
355
379
  }
356
380
  else {
357
- moveTarget = prev;
381
+ yield* fixToMoveDownForBlock(fixer, edit.a, target);
358
382
  }
383
+ },
384
+ });
385
+ }
386
+ else {
387
+ const target = findInsertBeforeTarget(edit.a, insertEditIndex);
388
+ if (!target) {
389
+ continue;
390
+ }
391
+ context.report({
392
+ loc: edit.a.reportLoc,
393
+ messageId: "shouldBeBefore",
394
+ data: {
395
+ thisValue: toText(edit.a),
396
+ targetValue: toText(target),
397
+ orderText: option.orderText(edit.a),
398
+ },
399
+ *fix(fixer) {
400
+ if (edit.a.sequence.node.style === "flow") {
401
+ yield* fixToMoveUpForFlow(fixer, edit.a, target);
402
+ }
403
+ else {
404
+ yield* fixToMoveUpForBlock(fixer, edit.a, target);
405
+ }
406
+ },
407
+ });
408
+ }
409
+ }
410
+ function findInsertAfterTarget(entry, insertEditIndex) {
411
+ let candidate = null;
412
+ for (let index = insertEditIndex - 1; index >= 0; index--) {
413
+ const edit = editScript[index];
414
+ if (edit.type === "delete" && edit.a === entry)
415
+ break;
416
+ if (edit.type !== "common")
417
+ continue;
418
+ candidate = edit.a;
419
+ break;
420
+ }
421
+ const entryIndex = entries.indexOf(entry);
422
+ if (candidate) {
423
+ for (let index = entryIndex + 1; index < entries.length; index++) {
424
+ const element = entries[index];
425
+ if (element === candidate)
426
+ return candidate;
427
+ if (shouldKeepOrder(entry, element)) {
428
+ break;
359
429
  }
360
- if (data.sequence.node.style === "flow") {
361
- yield* fixForFlow(fixer, data, moveTarget);
362
- }
363
- else {
364
- yield* fixForBlock(fixer, data, moveTarget);
430
+ }
431
+ }
432
+ let lastTarget = null;
433
+ for (let index = entryIndex + 1; index < entries.length; index++) {
434
+ const element = entries[index];
435
+ if (option.isValidOrder(element, entry) &&
436
+ !shouldKeepOrder(entry, element)) {
437
+ lastTarget = element;
438
+ continue;
439
+ }
440
+ return lastTarget;
441
+ }
442
+ return lastTarget;
443
+ }
444
+ function findInsertBeforeTarget(entry, insertEditIndex) {
445
+ let candidate = null;
446
+ for (let index = insertEditIndex + 1; index < editScript.length; index++) {
447
+ const edit = editScript[index];
448
+ if (edit.type === "delete" && edit.a === entry)
449
+ break;
450
+ if (edit.type !== "common")
451
+ continue;
452
+ candidate = edit.a;
453
+ break;
454
+ }
455
+ const entryIndex = entries.indexOf(entry);
456
+ if (candidate) {
457
+ for (let index = entryIndex - 1; index >= 0; index--) {
458
+ const element = entries[index];
459
+ if (element === candidate)
460
+ return candidate;
461
+ if (shouldKeepOrder(element, entry)) {
462
+ break;
365
463
  }
366
- },
367
- });
464
+ }
465
+ }
466
+ let lastTarget = null;
467
+ for (let index = entryIndex - 1; index >= 0; index--) {
468
+ const element = entries[index];
469
+ if (option.isValidOrder(entry, element) &&
470
+ !shouldKeepOrder(element, entry)) {
471
+ lastTarget = element;
472
+ continue;
473
+ }
474
+ return lastTarget;
475
+ }
476
+ return lastTarget;
368
477
  }
369
478
  }
370
479
  function toText(data) {
@@ -419,12 +528,48 @@ exports.default = (0, index_1.createRule)("sort-sequence-values", {
419
528
  if (!option) {
420
529
  return;
421
530
  }
422
- for (const element of data.entries) {
423
- verifyArrayElement(element, option);
424
- }
531
+ verifyArrayElements(data.entries.filter((d) => !option.ignore(d)), option);
425
532
  },
426
533
  };
427
- function* fixForFlow(fixer, data, moveTarget) {
534
+ function* fixToMoveDownForFlow(fixer, data, moveTarget) {
535
+ const beforeToken = data.aroundTokens.before;
536
+ const afterToken = data.aroundTokens.after;
537
+ let insertCode, removeRange, insertTargetToken;
538
+ if ((0, ast_utils_1.isComma)(afterToken)) {
539
+ removeRange = [beforeToken.range[1], afterToken.range[1]];
540
+ const moveTargetAfterToken = moveTarget.aroundTokens.after;
541
+ if ((0, ast_utils_1.isComma)(moveTargetAfterToken)) {
542
+ insertTargetToken = moveTargetAfterToken;
543
+ insertCode = sourceCode.text.slice(...removeRange);
544
+ }
545
+ else {
546
+ insertTargetToken = moveTarget.node
547
+ ? sourceCode.getLastToken(moveTarget.node)
548
+ : moveTarget.aroundTokens.before;
549
+ insertCode = sourceCode.text.slice(beforeToken.range[1], afterToken.range[0]);
550
+ insertCode = `,${insertCode}`;
551
+ }
552
+ }
553
+ else {
554
+ if ((0, ast_utils_1.isComma)(beforeToken)) {
555
+ removeRange = [beforeToken.range[0], data.range[1]];
556
+ insertCode = sourceCode.text.slice(...removeRange);
557
+ insertTargetToken = moveTarget.node
558
+ ? sourceCode.getLastToken(moveTarget.node)
559
+ : moveTarget.aroundTokens.before;
560
+ }
561
+ else {
562
+ removeRange = [beforeToken.range[1], data.range[1]];
563
+ insertCode = `,${sourceCode.text.slice(...removeRange)}`;
564
+ insertTargetToken = moveTarget.node
565
+ ? sourceCode.getLastToken(moveTarget.node)
566
+ : moveTarget.aroundTokens.before;
567
+ }
568
+ }
569
+ yield fixer.removeRange(removeRange);
570
+ yield fixer.insertTextAfterRange(insertTargetToken.range, insertCode);
571
+ }
572
+ function* fixToMoveUpForFlow(fixer, data, moveTarget) {
428
573
  const beforeToken = data.aroundTokens.before;
429
574
  const afterToken = data.aroundTokens.after;
430
575
  let insertCode, removeRange, insertTargetToken;
@@ -447,7 +592,16 @@ exports.default = (0, index_1.createRule)("sort-sequence-values", {
447
592
  yield fixer.insertTextAfterRange(insertTargetToken.range, insertCode);
448
593
  yield fixer.removeRange(removeRange);
449
594
  }
450
- function* fixForBlock(fixer, data, moveTarget) {
595
+ function* fixToMoveDownForBlock(fixer, data, moveTarget) {
596
+ const moveDataList = data.sequence.entries.slice(data.index, moveTarget.index + 1);
597
+ let replacementCodeRange = getBlockEntryRange(data);
598
+ for (const target of moveDataList.reverse()) {
599
+ const range = getBlockEntryRange(target);
600
+ yield fixer.replaceTextRange(range, sourceCode.text.slice(...replacementCodeRange));
601
+ replacementCodeRange = range;
602
+ }
603
+ }
604
+ function* fixToMoveUpForBlock(fixer, data, moveTarget) {
451
605
  const moveDataList = data.sequence.entries.slice(moveTarget.index, data.index + 1);
452
606
  let replacementCodeRange = getBlockEntryRange(data);
453
607
  for (const target of moveDataList) {
@@ -4,7 +4,10 @@ export declare function isTokenOnSameLine(left: YAMLToken, right: YAMLToken): bo
4
4
  export declare function isQuestion(token: YAMLToken | null): token is YAMLToken;
5
5
  export declare function isHyphen(token: YAMLToken | null): token is YAMLToken;
6
6
  export declare function isColon(token: YAMLToken | null): token is YAMLToken;
7
- export declare function isComma(token: YAMLToken | null): token is YAMLToken;
7
+ export declare function isComma(token: YAMLToken | null): token is YAMLToken & {
8
+ type: "Punctuator";
9
+ value: ",";
10
+ };
8
11
  export declare function isOpeningBracketToken(token: YAMLToken | null): token is YAMLToken;
9
12
  export declare function isClosingBracketToken(token: YAMLToken | null): token is YAMLToken;
10
13
  export declare function isOpeningBraceToken(token: YAMLToken | null): token is YAMLToken;
@@ -0,0 +1,15 @@
1
+ export type DeleteEntry<E> = {
2
+ type: "delete";
3
+ a: E;
4
+ };
5
+ export type InsertEntry<E> = {
6
+ type: "insert";
7
+ b: E;
8
+ };
9
+ export type CommonEntry<E> = {
10
+ type: "common";
11
+ a: E;
12
+ b: E;
13
+ };
14
+ export type DiffEntry<E> = DeleteEntry<E> | InsertEntry<E> | CommonEntry<E>;
15
+ export declare function calcShortestEditScript<E>(a: E[], b: E[]): DiffEntry<E>[];
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.calcShortestEditScript = calcShortestEditScript;
7
+ const diff_sequences_1 = __importDefault(require("diff-sequences"));
8
+ function calcShortestEditScript(a, b) {
9
+ let aIndex = 0;
10
+ let bIndex = 0;
11
+ const result = [];
12
+ (0, diff_sequences_1.default)(a.length, b.length, (aIndex, bIndex) => a[aIndex] === b[bIndex], (nCommon, aCommon, bCommon) => {
13
+ pushDelIns(aIndex, aCommon, bIndex, bCommon);
14
+ aIndex = aCommon + nCommon;
15
+ bIndex = bCommon + nCommon;
16
+ if (nCommon > 0) {
17
+ for (let index = 0; index < nCommon; index++) {
18
+ const elementA = a[aCommon + index];
19
+ const elementB = b[bCommon + index];
20
+ result.push({
21
+ type: "common",
22
+ a: elementA,
23
+ b: elementB,
24
+ });
25
+ }
26
+ }
27
+ });
28
+ pushDelIns(aIndex, a.length, bIndex, b.length);
29
+ return result;
30
+ function pushDelIns(aStart, aEnd, bStart, bEnd) {
31
+ for (const element of a.slice(aStart, aEnd)) {
32
+ result.push({
33
+ type: "delete",
34
+ a: element,
35
+ });
36
+ }
37
+ for (const element of b.slice(bStart, bEnd)) {
38
+ result.push({
39
+ type: "insert",
40
+ b: element,
41
+ });
42
+ }
43
+ }
44
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-yml",
3
- "version": "1.18.0",
3
+ "version": "1.19.1",
4
4
  "description": "This ESLint plugin provides linting rules for YAML.",
5
5
  "main": "lib/index.js",
6
6
  "files": [
@@ -29,8 +29,8 @@
29
29
  "docs:watch": "vitepress dev docs",
30
30
  "docs:build": "npm run build:ts && vitepress build docs",
31
31
  "preversion": "npm test && git add .",
32
- "version": "env-cmd -e version npm run update && git add .",
33
- "version:ci": "env-cmd -e version-ci npm run update && changeset version",
32
+ "version": "env-cmd -e version -- npm run update && git add .",
33
+ "version:ci": "env-cmd -e version-ci -- npm run update && changeset version",
34
34
  "prerelease": "npm run build",
35
35
  "release": "changeset publish",
36
36
  "update-fixtures": "npm run ts -- ./tools/update-fixtures.ts && npm run eslint-fix",
@@ -58,6 +58,7 @@
58
58
  "homepage": "https://ota-meshi.github.io/eslint-plugin-yml/",
59
59
  "dependencies": {
60
60
  "debug": "^4.3.2",
61
+ "diff-sequences": "^27.5.1",
61
62
  "escape-string-regexp": "4.0.0",
62
63
  "eslint-compat-utils": "^0.6.0",
63
64
  "natural-compare": "^1.4.0",
@@ -72,53 +73,53 @@
72
73
  "@eslint-community/eslint-plugin-eslint-comments": "^4.3.0",
73
74
  "@eslint/eslintrc": "^3.1.0",
74
75
  "@eslint/js": "^9.5.0",
75
- "@eslint/json": "^0.12.0",
76
- "@ota-meshi/eslint-plugin": "^0.17.3",
76
+ "@eslint/json": "^0.14.0",
77
+ "@ota-meshi/eslint-plugin": "^0.18.0",
77
78
  "@ota-meshi/site-kit-eslint-editor-vue": "^0.2.0",
78
79
  "@types/debug": "^4.1.5",
79
80
  "@types/eslint": "^9.0.0",
80
- "@types/eslint-scope": "^3.7.0",
81
+ "@types/eslint-scope": "^8.0.0",
81
82
  "@types/eslint-visitor-keys": "^3.0.0",
82
83
  "@types/estree": "^1.0.0",
83
84
  "@types/mocha": "^10.0.0",
84
85
  "@types/natural-compare": "^1.4.0",
85
- "@types/node": "^22.0.0",
86
+ "@types/node": "^24.0.0",
86
87
  "@types/semver": "^7.3.1",
87
- "@typescript-eslint/eslint-plugin": "~8.31.0",
88
- "@typescript-eslint/parser": "~8.31.0",
89
- "cross-env": "^7.0.2",
90
- "env-cmd": "^10.1.0",
91
- "esbuild": "^0.25.0",
88
+ "@typescript-eslint/eslint-plugin": "~8.49.0",
89
+ "@typescript-eslint/parser": "~8.49.0",
90
+ "cross-env": "^10.0.0",
91
+ "env-cmd": "^11.0.0",
92
+ "esbuild": "^0.27.0",
92
93
  "esbuild-register": "^3.2.0",
93
94
  "eslint": "^9.16.0",
94
95
  "eslint-config-prettier": "^10.0.0",
95
- "eslint-plugin-eslint-plugin": "^6.0.0",
96
+ "eslint-plugin-eslint-plugin": "^7.0.0",
96
97
  "eslint-plugin-eslint-rule-tester": "^0.6.0",
97
- "eslint-plugin-jsdoc": "^50.0.0",
98
+ "eslint-plugin-jsdoc": "^61.0.0",
98
99
  "eslint-plugin-json-schema-validator": "^5.0.0",
99
100
  "eslint-plugin-jsonc": "^2.0.0",
100
101
  "eslint-plugin-markdown": "^5.0.0",
101
102
  "eslint-plugin-n": "^17.0.0",
102
- "eslint-plugin-node-dependencies": "^0.12.0",
103
+ "eslint-plugin-node-dependencies": "^1.0.0",
103
104
  "eslint-plugin-prettier": "^5.0.0",
104
105
  "eslint-plugin-regexp": "^2.0.0",
105
- "eslint-plugin-vue": "^9.0.0",
106
+ "eslint-plugin-vue": "^10.0.0",
106
107
  "eslint-plugin-yml": "^1.0.0",
107
108
  "events": "^3.3.0",
108
109
  "mocha": "^11.0.0",
109
- "monaco-editor": "^0.52.0",
110
+ "monaco-editor": "^0.55.0",
110
111
  "nyc": "^17.0.0",
111
112
  "pako": "^2.1.0",
112
113
  "prettier": "^3.0.3",
113
114
  "semver": "^7.3.2",
114
115
  "stylelint": "^16.0.0",
115
116
  "stylelint-config-recommended-vue": "^1.0.0",
116
- "stylelint-config-standard": "^38.0.0",
117
+ "stylelint-config-standard": "^39.0.0",
117
118
  "stylelint-config-standard-vue": "^1.0.0",
118
119
  "stylelint-stylus": "^1.0.0",
119
- "typescript": "~5.8.0",
120
+ "typescript": "~5.9.0",
120
121
  "typescript-eslint": "^8.0.0",
121
- "vite-plugin-eslint4b": "^0.5.0",
122
+ "vite-plugin-eslint4b": "^0.6.0",
122
123
  "vitepress": "^1.0.0-rc.17",
123
124
  "vue-eslint-parser": "^10.0.0",
124
125
  "yaml": "^2.1.1"
@@ -126,5 +127,5 @@
126
127
  "publishConfig": {
127
128
  "access": "public"
128
129
  },
129
- "packageManager": "npm@11.3.0"
130
+ "packageManager": "npm@11.7.0"
130
131
  }