eslint-plugin-hyoban 0.13.2 → 0.14.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/dist/index.d.mts +0 -3
- package/dist/index.mjs +9 -299
- package/package.json +1 -4
package/dist/index.d.mts
CHANGED
|
@@ -32,9 +32,6 @@ declare const _default: {
|
|
|
32
32
|
'i18n-flat-key': RuleModule<[]>;
|
|
33
33
|
'jsonc-inline-spacing': RuleModule<[]>;
|
|
34
34
|
'jsx-attribute-spacing': RuleModule<[]>;
|
|
35
|
-
'md-consistent-table-width': _eslint_markdown.MarkdownRuleDefinition<{
|
|
36
|
-
MessageIds: "formatCell";
|
|
37
|
-
}>;
|
|
38
35
|
'md-one-sentence-per-line': _eslint_markdown.MarkdownRuleDefinition<{
|
|
39
36
|
MessageIds: "wrapParagraph";
|
|
40
37
|
}>;
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
var version = "0.13.2";
|
|
1
|
+
var version = "0.14.0";
|
|
4
2
|
|
|
5
3
|
const hasDocs = new Set([
|
|
6
4
|
'prefer-tailwind-icons'
|
|
@@ -67,7 +65,7 @@ function getReportNode(sourceCode, targetNode) {
|
|
|
67
65
|
if (reportNode) return reportNode;
|
|
68
66
|
return sourceCode.ast;
|
|
69
67
|
}
|
|
70
|
-
const rule$
|
|
68
|
+
const rule$6 = createEslintRule({
|
|
71
69
|
name: 'i18n-flat-key',
|
|
72
70
|
meta: {
|
|
73
71
|
type: 'problem',
|
|
@@ -150,7 +148,7 @@ function getCorrectedSource(value) {
|
|
|
150
148
|
return `{ ${value.properties.filter((property)=>property.key.type !== 'JSONIdentifier').map((property)=>`${property.key.raw}: ${getCorrectedSource(property.value)}`).join(', ')} }`;
|
|
151
149
|
}
|
|
152
150
|
}
|
|
153
|
-
const rule$
|
|
151
|
+
const rule$5 = createEslintRule({
|
|
154
152
|
name: 'jsonc-inline-spacing',
|
|
155
153
|
meta: {
|
|
156
154
|
type: 'layout',
|
|
@@ -212,7 +210,7 @@ const expressionTypesNoCheck = new Set([
|
|
|
212
210
|
'JSXElement',
|
|
213
211
|
'TSAsExpression'
|
|
214
212
|
]);
|
|
215
|
-
const rule$
|
|
213
|
+
const rule$4 = createEslintRule({
|
|
216
214
|
name: 'jsx-attribute-spacing',
|
|
217
215
|
meta: {
|
|
218
216
|
type: 'layout',
|
|
@@ -285,293 +283,6 @@ const rule$5 = createEslintRule({
|
|
|
285
283
|
}
|
|
286
284
|
});
|
|
287
285
|
|
|
288
|
-
function getCellText(cell, sourceCode) {
|
|
289
|
-
if (cell.children.length === 0) return '';
|
|
290
|
-
const firstChild = cell.children[0];
|
|
291
|
-
const lastChild = cell.children.at(-1);
|
|
292
|
-
const [start] = sourceCode.getRange(firstChild);
|
|
293
|
-
const [, end] = sourceCode.getRange(lastChild);
|
|
294
|
-
return sourceCode.getText().slice(start, end).trim();
|
|
295
|
-
}
|
|
296
|
-
function getDelimiterCell(width, alignment) {
|
|
297
|
-
if (alignment === 'left') return `:${'-'.repeat(width - 1)}`;
|
|
298
|
-
if (alignment === 'right') return `${'-'.repeat(width - 1)}:`;
|
|
299
|
-
if (alignment === 'center') return `:${'-'.repeat(width - 2)}:`;
|
|
300
|
-
return '-'.repeat(width);
|
|
301
|
-
}
|
|
302
|
-
function getAlignedCellContent(cellText, width, alignment) {
|
|
303
|
-
const paddingLength = Math.max(0, width - stringWidth(cellText));
|
|
304
|
-
if (alignment === 'right') return `${' '.repeat(paddingLength)}${cellText}`;
|
|
305
|
-
if (alignment === 'center') {
|
|
306
|
-
const leftPaddingLength = Math.floor(paddingLength / 2);
|
|
307
|
-
const rightPaddingLength = paddingLength - leftPaddingLength;
|
|
308
|
-
return `${' '.repeat(leftPaddingLength)}${cellText}${' '.repeat(rightPaddingLength)}`;
|
|
309
|
-
}
|
|
310
|
-
return `${cellText}${' '.repeat(paddingLength)}`;
|
|
311
|
-
}
|
|
312
|
-
function normalizeAlignments(alignments, columnCount) {
|
|
313
|
-
return Array.from({
|
|
314
|
-
length: columnCount
|
|
315
|
-
}, (_, index)=>alignments?.[index] ?? null);
|
|
316
|
-
}
|
|
317
|
-
function buildTableState(tableNode) {
|
|
318
|
-
if (tableNode.children.length === 0) return null;
|
|
319
|
-
const columnCount = Math.max(tableNode.align?.length ?? 0, ...tableNode.children.map((row)=>row.children.length));
|
|
320
|
-
if (columnCount === 0) return null;
|
|
321
|
-
const rowValues = tableNode.children.map(()=>Array.from({
|
|
322
|
-
length: columnCount
|
|
323
|
-
}, ()=>''));
|
|
324
|
-
const widths = Array.from({
|
|
325
|
-
length: columnCount
|
|
326
|
-
}, ()=>3);
|
|
327
|
-
const rowIndexByNode = new WeakMap();
|
|
328
|
-
for (const [index, rowNode] of tableNode.children.entries())rowIndexByNode.set(rowNode, index);
|
|
329
|
-
return {
|
|
330
|
-
tableNode,
|
|
331
|
-
columnCount,
|
|
332
|
-
rowNodes: tableNode.children,
|
|
333
|
-
rowValues,
|
|
334
|
-
widths,
|
|
335
|
-
alignments: normalizeAlignments(tableNode.align, columnCount),
|
|
336
|
-
rowIndexByNode,
|
|
337
|
-
visitedCells: []
|
|
338
|
-
};
|
|
339
|
-
}
|
|
340
|
-
function formatTableCellSegment(content, columnIndex, columnCount) {
|
|
341
|
-
const suffix = columnIndex === columnCount - 1 ? ' |' : ' ';
|
|
342
|
-
return `| ${content}${suffix}`;
|
|
343
|
-
}
|
|
344
|
-
function getExpectedCellSegment(cellText, width, alignment, columnIndex, columnCount) {
|
|
345
|
-
return formatTableCellSegment(getAlignedCellContent(cellText, width, alignment), columnIndex, columnCount);
|
|
346
|
-
}
|
|
347
|
-
function getExpectedDelimiterSegment(width, alignment, columnIndex, columnCount) {
|
|
348
|
-
return formatTableCellSegment(getDelimiterCell(width, alignment), columnIndex, columnCount);
|
|
349
|
-
}
|
|
350
|
-
function getExpectedBodyTail(state, rowIndex, startColumnIndex) {
|
|
351
|
-
if (startColumnIndex >= state.columnCount) return '';
|
|
352
|
-
return Array.from({
|
|
353
|
-
length: state.columnCount - startColumnIndex
|
|
354
|
-
}, (_, index)=>{
|
|
355
|
-
const columnIndex = startColumnIndex + index;
|
|
356
|
-
return getExpectedCellSegment(state.rowValues[rowIndex]?.[columnIndex] ?? '', state.widths[columnIndex] ?? 3, state.alignments[columnIndex] ?? null, columnIndex, state.columnCount);
|
|
357
|
-
}).join('');
|
|
358
|
-
}
|
|
359
|
-
function getExpectedDelimiterTail(state, startColumnIndex) {
|
|
360
|
-
if (startColumnIndex >= state.columnCount) return '';
|
|
361
|
-
return Array.from({
|
|
362
|
-
length: state.columnCount - startColumnIndex
|
|
363
|
-
}, (_, index)=>{
|
|
364
|
-
const columnIndex = startColumnIndex + index;
|
|
365
|
-
return getExpectedDelimiterSegment(state.widths[columnIndex] ?? 3, state.alignments[columnIndex] ?? null, columnIndex, state.columnCount);
|
|
366
|
-
}).join('');
|
|
367
|
-
}
|
|
368
|
-
function getBodyCellLabel(rowIndex, columnIndex, existingCellCount, columnCount, hasTail) {
|
|
369
|
-
if (!hasTail || existingCellCount === columnCount) return `R${rowIndex + 1}C${columnIndex + 1}`;
|
|
370
|
-
return `R${rowIndex + 1}C${columnIndex + 1}-C${columnCount}`;
|
|
371
|
-
}
|
|
372
|
-
function getMissingBodyCellLabel(rowIndex, startColumnIndex, columnCount) {
|
|
373
|
-
return `R${rowIndex + 1}C${startColumnIndex + 1}-C${columnCount}`;
|
|
374
|
-
}
|
|
375
|
-
function getDelimiterCellLabel(columnIndex, columnCount, hasTail) {
|
|
376
|
-
if (!hasTail) return `D${columnIndex + 1}`;
|
|
377
|
-
return `D${columnIndex + 1}-D${columnCount}`;
|
|
378
|
-
}
|
|
379
|
-
function toMessageValue(text) {
|
|
380
|
-
return JSON.stringify(text);
|
|
381
|
-
}
|
|
382
|
-
function toEditableChange(range, actualSegment, expectedSegment) {
|
|
383
|
-
const hasLeadingPipe = actualSegment.startsWith('|');
|
|
384
|
-
return {
|
|
385
|
-
range: [
|
|
386
|
-
range[0] + (hasLeadingPipe ? 1 : 0),
|
|
387
|
-
range[1]
|
|
388
|
-
],
|
|
389
|
-
actual: hasLeadingPipe ? actualSegment.slice(1) : actualSegment,
|
|
390
|
-
expected: hasLeadingPipe ? expectedSegment.slice(1) : expectedSegment
|
|
391
|
-
};
|
|
392
|
-
}
|
|
393
|
-
function isTableRow(node) {
|
|
394
|
-
return !!node && typeof node === 'object' && node.type === 'tableRow';
|
|
395
|
-
}
|
|
396
|
-
function parseRowSegments(rowText, rowStartOffset) {
|
|
397
|
-
if (rowText.length === 0) return [];
|
|
398
|
-
const separators = [];
|
|
399
|
-
for(let index = 1; index < rowText.length - 1; index++){
|
|
400
|
-
if (rowText[index] === '|') separators.push(index);
|
|
401
|
-
}
|
|
402
|
-
const segments = [];
|
|
403
|
-
let start = 0;
|
|
404
|
-
for (const separator of separators){
|
|
405
|
-
segments.push({
|
|
406
|
-
range: [
|
|
407
|
-
rowStartOffset + start,
|
|
408
|
-
rowStartOffset + separator
|
|
409
|
-
],
|
|
410
|
-
text: rowText.slice(start, separator)
|
|
411
|
-
});
|
|
412
|
-
start = separator;
|
|
413
|
-
}
|
|
414
|
-
segments.push({
|
|
415
|
-
range: [
|
|
416
|
-
rowStartOffset + start,
|
|
417
|
-
rowStartOffset + rowText.length
|
|
418
|
-
],
|
|
419
|
-
text: rowText.slice(start)
|
|
420
|
-
});
|
|
421
|
-
return segments;
|
|
422
|
-
}
|
|
423
|
-
function getDelimiterRowSegments(tableNode, sourceCode) {
|
|
424
|
-
const headerRow = tableNode.children[0];
|
|
425
|
-
if (!headerRow) return null;
|
|
426
|
-
const delimiterLine = headerRow.position?.end.line ? headerRow.position.end.line + 1 : null;
|
|
427
|
-
if (delimiterLine == null) return null;
|
|
428
|
-
const [tableStartOffset] = sourceCode.getRange(tableNode);
|
|
429
|
-
const tableStartLoc = sourceCode.getLocFromIndex(tableStartOffset);
|
|
430
|
-
const originLoc = sourceCode.getLocFromIndex(0);
|
|
431
|
-
const lineBase = originLoc.line === 0 ? 0 : 1;
|
|
432
|
-
const columnBase = originLoc.column === 0 ? 0 : 1;
|
|
433
|
-
const delimiterLineIndex = delimiterLine - lineBase;
|
|
434
|
-
const fullDelimiterLine = sourceCode.lines[delimiterLineIndex];
|
|
435
|
-
if (fullDelimiterLine == null) return null;
|
|
436
|
-
const prefixLength = Math.max(0, tableStartLoc.column - columnBase);
|
|
437
|
-
const delimiterRowText = fullDelimiterLine.slice(prefixLength);
|
|
438
|
-
const rowStartOffset = sourceCode.getIndexFromLoc({
|
|
439
|
-
line: delimiterLine,
|
|
440
|
-
column: tableStartLoc.column
|
|
441
|
-
});
|
|
442
|
-
return {
|
|
443
|
-
segments: parseRowSegments(delimiterRowText, rowStartOffset),
|
|
444
|
-
rowEndOffset: rowStartOffset + delimiterRowText.length
|
|
445
|
-
};
|
|
446
|
-
}
|
|
447
|
-
const rule$4 = {
|
|
448
|
-
meta: {
|
|
449
|
-
type: 'layout',
|
|
450
|
-
docs: {
|
|
451
|
-
description: 'Format GFM markdown tables to aligned columns',
|
|
452
|
-
url: 'https://github.com/hyoban/eslint-plugin-hyoban/blob/main/src/md-consistent-table-width.test.ts'
|
|
453
|
-
},
|
|
454
|
-
fixable: 'whitespace',
|
|
455
|
-
schema: [],
|
|
456
|
-
defaultOptions: [],
|
|
457
|
-
messages: {
|
|
458
|
-
formatCell: 'Expected {{cell}} to be {{expected}}, but found {{actual}}.'
|
|
459
|
-
},
|
|
460
|
-
language: 'markdown',
|
|
461
|
-
dialects: [
|
|
462
|
-
'gfm'
|
|
463
|
-
]
|
|
464
|
-
},
|
|
465
|
-
create (context) {
|
|
466
|
-
const { sourceCode } = context;
|
|
467
|
-
const tableStack = [];
|
|
468
|
-
function reportFormatCell(range, cell, actual, expected) {
|
|
469
|
-
if (actual === expected) return;
|
|
470
|
-
context.report({
|
|
471
|
-
loc: {
|
|
472
|
-
start: sourceCode.getLocFromIndex(range[0]),
|
|
473
|
-
end: sourceCode.getLocFromIndex(range[1])
|
|
474
|
-
},
|
|
475
|
-
messageId: 'formatCell',
|
|
476
|
-
data: {
|
|
477
|
-
cell,
|
|
478
|
-
expected: toMessageValue(expected),
|
|
479
|
-
actual: toMessageValue(actual)
|
|
480
|
-
},
|
|
481
|
-
fix (fixer) {
|
|
482
|
-
return fixer.replaceTextRange(range, expected);
|
|
483
|
-
}
|
|
484
|
-
});
|
|
485
|
-
}
|
|
486
|
-
return {
|
|
487
|
-
table (tableNode) {
|
|
488
|
-
tableStack.push({
|
|
489
|
-
tableNode,
|
|
490
|
-
state: buildTableState(tableNode)
|
|
491
|
-
});
|
|
492
|
-
},
|
|
493
|
-
tableCell (cellNode) {
|
|
494
|
-
const current = tableStack.at(-1);
|
|
495
|
-
const state = current?.state;
|
|
496
|
-
if (!state) return;
|
|
497
|
-
const rowNode = sourceCode.getParent(cellNode);
|
|
498
|
-
if (!isTableRow(rowNode)) return;
|
|
499
|
-
const rowIndex = state.rowIndexByNode.get(rowNode);
|
|
500
|
-
if (rowIndex == null) return;
|
|
501
|
-
const columnIndex = rowNode.children.indexOf(cellNode);
|
|
502
|
-
if (columnIndex < 0 || columnIndex >= state.columnCount) return;
|
|
503
|
-
const cellText = getCellText(cellNode, sourceCode);
|
|
504
|
-
state.rowValues[rowIndex][columnIndex] = cellText;
|
|
505
|
-
state.widths[columnIndex] = Math.max(state.widths[columnIndex] ?? 3, stringWidth(cellText), 3);
|
|
506
|
-
state.visitedCells.push({
|
|
507
|
-
range: sourceCode.getRange(cellNode),
|
|
508
|
-
rowIndex,
|
|
509
|
-
columnIndex,
|
|
510
|
-
actual: sourceCode.getText(cellNode)
|
|
511
|
-
});
|
|
512
|
-
},
|
|
513
|
-
'table:exit': function(tableNode) {
|
|
514
|
-
const current = tableStack.pop();
|
|
515
|
-
if (!current || current.tableNode !== tableNode || !current.state) return;
|
|
516
|
-
const state = current.state;
|
|
517
|
-
state.visitedCells.sort((left, right)=>left.range[0] - right.range[0]);
|
|
518
|
-
const rowTailByRowIndex = new Map();
|
|
519
|
-
for (const [rowIndex, rowNode] of state.rowNodes.entries()){
|
|
520
|
-
const existingCellCount = rowNode.children.length;
|
|
521
|
-
if (existingCellCount >= state.columnCount) continue;
|
|
522
|
-
const expectedTail = getExpectedBodyTail(state, rowIndex, existingCellCount);
|
|
523
|
-
if (expectedTail.length === 0) continue;
|
|
524
|
-
if (existingCellCount > 0) {
|
|
525
|
-
rowTailByRowIndex.set(rowIndex, expectedTail);
|
|
526
|
-
continue;
|
|
527
|
-
}
|
|
528
|
-
const [, rowEndOffset] = sourceCode.getRange(rowNode);
|
|
529
|
-
const missingCellLabel = getMissingBodyCellLabel(rowIndex, existingCellCount, state.columnCount);
|
|
530
|
-
reportFormatCell([
|
|
531
|
-
rowEndOffset,
|
|
532
|
-
rowEndOffset
|
|
533
|
-
], missingCellLabel, '', expectedTail);
|
|
534
|
-
}
|
|
535
|
-
for (const cell of state.visitedCells){
|
|
536
|
-
const rowNode = state.rowNodes[cell.rowIndex];
|
|
537
|
-
const existingCellCount = rowNode?.children.length ?? 0;
|
|
538
|
-
const isLastExistingCell = existingCellCount > 0 && cell.columnIndex === existingCellCount - 1;
|
|
539
|
-
const rowTail = isLastExistingCell ? rowTailByRowIndex.get(cell.rowIndex) ?? '' : '';
|
|
540
|
-
let expected = getExpectedCellSegment(state.rowValues[cell.rowIndex]?.[cell.columnIndex] ?? '', state.widths[cell.columnIndex] ?? 3, state.alignments[cell.columnIndex] ?? null, cell.columnIndex, state.columnCount);
|
|
541
|
-
if (rowTail) expected += rowTail;
|
|
542
|
-
const change = toEditableChange(cell.range, cell.actual, expected);
|
|
543
|
-
if (change.actual === change.expected) continue;
|
|
544
|
-
const cellLabel = getBodyCellLabel(cell.rowIndex, cell.columnIndex, existingCellCount, state.columnCount, !!rowTail);
|
|
545
|
-
reportFormatCell(change.range, cellLabel, change.actual, change.expected);
|
|
546
|
-
}
|
|
547
|
-
const delimiterRow = getDelimiterRowSegments(state.tableNode, sourceCode);
|
|
548
|
-
if (!delimiterRow) return;
|
|
549
|
-
const delimiterTail = getExpectedDelimiterTail(state, delimiterRow.segments.length);
|
|
550
|
-
if (delimiterRow.segments.length === 0) {
|
|
551
|
-
if (!delimiterTail) return;
|
|
552
|
-
reportFormatCell([
|
|
553
|
-
delimiterRow.rowEndOffset,
|
|
554
|
-
delimiterRow.rowEndOffset
|
|
555
|
-
], `D1-D${state.columnCount}`, '', delimiterTail);
|
|
556
|
-
return;
|
|
557
|
-
}
|
|
558
|
-
const delimiterColumnCount = Math.min(state.columnCount, delimiterRow.segments.length);
|
|
559
|
-
for(let columnIndex = 0; columnIndex < delimiterColumnCount; columnIndex++){
|
|
560
|
-
const segment = delimiterRow.segments[columnIndex];
|
|
561
|
-
if (!segment) continue;
|
|
562
|
-
const isLastExistingDelimiterCell = columnIndex === delimiterRow.segments.length - 1;
|
|
563
|
-
let expected = getExpectedDelimiterSegment(state.widths[columnIndex] ?? 3, state.alignments[columnIndex] ?? null, columnIndex, state.columnCount);
|
|
564
|
-
if (isLastExistingDelimiterCell && delimiterTail) expected += delimiterTail;
|
|
565
|
-
const change = toEditableChange(segment.range, segment.text, expected);
|
|
566
|
-
if (change.actual === change.expected) continue;
|
|
567
|
-
const cellLabel = getDelimiterCellLabel(columnIndex, state.columnCount, isLastExistingDelimiterCell && !!delimiterTail);
|
|
568
|
-
reportFormatCell(change.range, cellLabel, change.actual, change.expected);
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
};
|
|
572
|
-
}
|
|
573
|
-
};
|
|
574
|
-
|
|
575
286
|
function lastNonWhitespaceChar(segment, segmentStart) {
|
|
576
287
|
for(let i = segment.length - 1; i >= 0; i--){
|
|
577
288
|
const char = segment[i];
|
|
@@ -589,7 +300,7 @@ const rule$3 = {
|
|
|
589
300
|
type: 'layout',
|
|
590
301
|
docs: {
|
|
591
302
|
description: 'Wrap markdown paragraphs so each sentence is on its own line',
|
|
592
|
-
url: 'https://github.com/hyoban/eslint-plugin-hyoban/blob/main/src/md-one-sentence-per-line.
|
|
303
|
+
url: 'https://github.com/hyoban/eslint-plugin-hyoban/blob/main/src/md-one-sentence-per-line.md'
|
|
593
304
|
},
|
|
594
305
|
fixable: 'whitespace',
|
|
595
306
|
schema: [],
|
|
@@ -608,7 +319,7 @@ const rule$3 = {
|
|
|
608
319
|
granularity: 'sentence'
|
|
609
320
|
});
|
|
610
321
|
return {
|
|
611
|
-
'
|
|
322
|
+
'paragraph > text': function(node) {
|
|
612
323
|
const range = sourceCode.getRange(node);
|
|
613
324
|
const originalText = sourceCode.getText(node);
|
|
614
325
|
const matches = [];
|
|
@@ -1108,10 +819,9 @@ var index = {
|
|
|
1108
819
|
},
|
|
1109
820
|
/// keep-sorted
|
|
1110
821
|
rules: {
|
|
1111
|
-
'i18n-flat-key': rule$
|
|
1112
|
-
'jsonc-inline-spacing': rule$
|
|
1113
|
-
'jsx-attribute-spacing': rule$
|
|
1114
|
-
'md-consistent-table-width': rule$4,
|
|
822
|
+
'i18n-flat-key': rule$6,
|
|
823
|
+
'jsonc-inline-spacing': rule$5,
|
|
824
|
+
'jsx-attribute-spacing': rule$4,
|
|
1115
825
|
'md-one-sentence-per-line': rule$3,
|
|
1116
826
|
'no-dependency-version-prefix': rule$2,
|
|
1117
827
|
'prefer-early-return': rule$1,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-hyoban",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.14.0",
|
|
5
5
|
"description": "Hyoban extended ESLint rules.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "hyoban",
|
|
@@ -28,9 +28,6 @@
|
|
|
28
28
|
"peerDependencies": {
|
|
29
29
|
"eslint": "*"
|
|
30
30
|
},
|
|
31
|
-
"dependencies": {
|
|
32
|
-
"fast-string-width": "^3.0.2"
|
|
33
|
-
},
|
|
34
31
|
"devDependencies": {
|
|
35
32
|
"@eslint/markdown": "^7.5.1",
|
|
36
33
|
"@types/mdast": "^4.0.4",
|