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 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
- import stringWidth from 'fast-string-width';
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$7 = createEslintRule({
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$6 = createEslintRule({
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$5 = createEslintRule({
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.test.ts'
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
- 'root > paragraph > text': function(node) {
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$7,
1112
- 'jsonc-inline-spacing': rule$6,
1113
- 'jsx-attribute-spacing': rule$5,
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.13.2",
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",