From 1c2e4dc9b950f9529fb7f2cb2c1a23cc9a117bc3 Mon Sep 17 00:00:00 2001 From: James Garbutt <43081j@users.noreply.github.com> Date: Wed, 23 Sep 2026 21:59:14 +0100 Subject: [PATCH] fix: don't include source in messages Some rules emit messages containing source code. This can lead to poor DX if the source is pretty lengthy. Instead, this changes them to just report the pattern rather than the actual code. Fixes #160. --- src/rules/prefer-array-fill.test.ts | 101 ++++-------------------- src/rules/prefer-array-fill.ts | 12 +-- src/rules/prefer-array-from-map.test.ts | 81 +++---------------- src/rules/prefer-array-from-map.ts | 6 +- src/rules/prefer-regex-test.ts | 7 +- 5 files changed, 30 insertions(+), 177 deletions(-) diff --git a/src/rules/prefer-array-fill.test.ts b/src/rules/prefer-array-fill.test.ts index cbded7d..1bad625 100644 --- a/src/rules/prefer-array-fill.test.ts +++ b/src/rules/prefer-array-fill.test.ts @@ -62,84 +62,49 @@ ruleTester.run('prefer-array-fill', preferArrayFill, { { code: 'const arr = Array.from({length: 5}, () => 0)', output: 'const arr = Array.from({length: 5}).fill(0)', - errors: [ - { - messageId: 'preferFillArrayFrom', - data: {length: '5', value: '0'} - } - ] + errors: [{messageId: 'preferFillArrayFrom'}] }, // Array.from with string value { code: 'const arr = Array.from({length: 3}, () => "test")', output: 'const arr = Array.from({length: 3}).fill("test")', - errors: [ - { - messageId: 'preferFillArrayFrom', - data: {length: '3', value: '"test"'} - } - ] + errors: [{messageId: 'preferFillArrayFrom'}] }, // Array.from with expression in length { code: 'const arr = Array.from({length: 2 + 3}, () => 0)', output: 'const arr = Array.from({length: 2 + 3}).fill(0)', - errors: [ - { - messageId: 'preferFillArrayFrom', - data: {length: '2 + 3', value: '0'} - } - ] + errors: [{messageId: 'preferFillArrayFrom'}] }, // Array.from with regular function expression { code: 'const arr = Array.from({length: 5}, function() { return 0 })', output: 'const arr = Array.from({length: 5}).fill(0)', - errors: [ - { - messageId: 'preferFillArrayFrom', - data: {length: '5', value: '0'} - } - ] + errors: [{messageId: 'preferFillArrayFrom'}] }, // Spread Array with map and arrow function { code: 'const arr = [...Array(5)].map(() => 0)', output: 'const arr = Array(5).fill(0)', - errors: [ - { - messageId: 'preferFillSpreadMap', - data: {length: '5', value: '0'} - } - ] + errors: [{messageId: 'preferFillSpreadMap'}] }, // Spread Array with map and string value { code: 'const arr = [...Array(3)].map(() => "test")', output: 'const arr = Array(3).fill("test")', - errors: [ - { - messageId: 'preferFillSpreadMap', - data: {length: '3', value: '"test"'} - } - ] + errors: [{messageId: 'preferFillSpreadMap'}] }, // Spread Array with map and function expression { code: 'const arr = [...Array(5)].map(function() { return 1 })', output: 'const arr = Array(5).fill(1)', - errors: [ - { - messageId: 'preferFillSpreadMap', - data: {length: '5', value: '1'} - } - ] + errors: [{messageId: 'preferFillSpreadMap'}] }, // Multiple occurrences @@ -149,14 +114,8 @@ const arr2 = [...Array(3)].map(() => "test");`, output: `const arr1 = Array.from({length: 5}).fill(0); const arr2 = Array(3).fill("test");`, errors: [ - { - messageId: 'preferFillArrayFrom', - data: {length: '5', value: '0'} - }, - { - messageId: 'preferFillSpreadMap', - data: {length: '3', value: '"test"'} - } + {messageId: 'preferFillArrayFrom'}, + {messageId: 'preferFillSpreadMap'} ] }, @@ -164,72 +123,42 @@ const arr2 = Array(3).fill("test");`, { code: 'console.log(Array.from({length: 5}, () => 0))', output: 'console.log(Array.from({length: 5}).fill(0))', - errors: [ - { - messageId: 'preferFillArrayFrom', - data: {length: '5', value: '0'} - } - ] + errors: [{messageId: 'preferFillArrayFrom'}] }, // Used in return statements { code: 'function getArray() { return [...Array(5)].map(() => 0) }', output: 'function getArray() { return Array(5).fill(0) }', - errors: [ - { - messageId: 'preferFillSpreadMap', - data: {length: '5', value: '0'} - } - ] + errors: [{messageId: 'preferFillSpreadMap'}] }, // Variable length { code: 'const arr = Array.from({length: n}, () => 0)', output: 'const arr = Array.from({length: n}).fill(0)', - errors: [ - { - messageId: 'preferFillArrayFrom', - data: {length: 'n', value: '0'} - } - ] + errors: [{messageId: 'preferFillArrayFrom'}] }, // Complex expressions in value { code: 'const arr = [...Array(5)].map(() => 1 + 2)', output: 'const arr = Array(5).fill(1 + 2)', - errors: [ - { - messageId: 'preferFillSpreadMap', - data: {length: '5', value: '1 + 2'} - } - ] + errors: [{messageId: 'preferFillSpreadMap'}] }, // Logical expression with all-constant operands { code: 'const arr = Array.from({length: 5}, () => a ?? b)', output: 'const arr = Array.from({length: 5}).fill(a ?? b)', - errors: [ - { - messageId: 'preferFillArrayFrom', - data: {length: '5', value: 'a ?? b'} - } - ] + errors: [{messageId: 'preferFillArrayFrom'}] }, // Conditional expression with all-constant branches { code: 'const arr = [...Array(5)].map(() => a ? b : c)', output: 'const arr = Array(5).fill(a ? b : c)', - errors: [ - { - messageId: 'preferFillSpreadMap', - data: {length: '5', value: 'a ? b : c'} - } - ] + errors: [{messageId: 'preferFillSpreadMap'}] } ] }); diff --git a/src/rules/prefer-array-fill.ts b/src/rules/prefer-array-fill.ts index 6f305ec..0f79d75 100644 --- a/src/rules/prefer-array-fill.ts +++ b/src/rules/prefer-array-fill.ts @@ -91,9 +91,9 @@ export const preferArrayFill: Rule.RuleModule = { schema: [], messages: { preferFillArrayFrom: - 'Use Array.from({length: {{length}}}).fill({{value}}) instead of Array.from with a constant callback', + 'Use `Array.from({length: n}).fill(value)` instead of `Array.from` with a constant callback', preferFillSpreadMap: - 'Use Array({{length}}).fill({{value}}) instead of spread Array with map' + 'Use `Array(n).fill(value)` instead of spreading `Array(n)` and mapping' } }, create(context) { @@ -139,10 +139,6 @@ export const preferArrayFill: Rule.RuleModule = { context.report({ node, messageId: 'preferFillArrayFrom', - data: { - length: lengthText, - value: valueText - }, fix(fixer) { return fixer.replaceText( node, @@ -195,10 +191,6 @@ export const preferArrayFill: Rule.RuleModule = { context.report({ node, messageId: 'preferFillSpreadMap', - data: { - length: lengthText, - value: valueText - }, fix(fixer) { return fixer.replaceText( node, diff --git a/src/rules/prefer-array-from-map.test.ts b/src/rules/prefer-array-from-map.test.ts index 8164e6e..93c3f52 100644 --- a/src/rules/prefer-array-from-map.test.ts +++ b/src/rules/prefer-array-from-map.test.ts @@ -48,48 +48,28 @@ ruleTester.run('prefer-array-from-map', preferArrayFromMap, { { code: 'const result = [...arr].map(x => x * 2)', output: 'const result = Array.from(arr, x => x * 2)', - errors: [ - { - messageId: 'preferArrayFrom', - data: {iterable: 'arr', mapper: 'x => x * 2'} - } - ] + errors: [{messageId: 'preferArrayFrom'}] }, // With named function { code: 'const result = [...items].map(double)', output: 'const result = Array.from(items, double)', - errors: [ - { - messageId: 'preferArrayFrom', - data: {iterable: 'items', mapper: 'double'} - } - ] + errors: [{messageId: 'preferArrayFrom'}] }, // With function expression { code: 'const result = [...list].map(function(x) { return x * 2 })', output: 'const result = Array.from(list, function(x) { return x * 2 })', - errors: [ - { - messageId: 'preferArrayFrom', - data: {iterable: 'list', mapper: 'function(x) { return x * 2 }'} - } - ] + errors: [{messageId: 'preferArrayFrom'}] }, // With method call on iterable { code: 'const result = [...map.values()].map(process)', output: 'const result = Array.from(map.values(), process)', - errors: [ - { - messageId: 'preferArrayFrom', - data: {iterable: 'map.values()', mapper: 'process'} - } - ] + errors: [{messageId: 'preferArrayFrom'}] }, // Multiple occurrences @@ -98,16 +78,7 @@ ruleTester.run('prefer-array-from-map', preferArrayFromMap, { const b = [...arr2].map(y => y + 1)`, output: `const a = Array.from(arr1, x => x * 2) const b = Array.from(arr2, y => y + 1)`, - errors: [ - { - messageId: 'preferArrayFrom', - data: {iterable: 'arr1', mapper: 'x => x * 2'} - }, - { - messageId: 'preferArrayFrom', - data: {iterable: 'arr2', mapper: 'y => y + 1'} - } - ] + errors: [{messageId: 'preferArrayFrom'}, {messageId: 'preferArrayFrom'}] }, // Used in return statement @@ -115,48 +86,28 @@ const b = Array.from(arr2, y => y + 1)`, code: 'function transform(items) { return [...items].map(x => x * 2) }', output: 'function transform(items) { return Array.from(items, x => x * 2) }', - errors: [ - { - messageId: 'preferArrayFrom', - data: {iterable: 'items', mapper: 'x => x * 2'} - } - ] + errors: [{messageId: 'preferArrayFrom'}] }, // Used in expression { code: 'console.log([...data].map(format))', output: 'console.log(Array.from(data, format))', - errors: [ - { - messageId: 'preferArrayFrom', - data: {iterable: 'data', mapper: 'format'} - } - ] + errors: [{messageId: 'preferArrayFrom'}] }, // Complex iterable expression { code: 'const result = [...getItems()].map(x => x.id)', output: 'const result = Array.from(getItems(), x => x.id)', - errors: [ - { - messageId: 'preferArrayFrom', - data: {iterable: 'getItems()', mapper: 'x => x.id'} - } - ] + errors: [{messageId: 'preferArrayFrom'}] }, // With member expression { code: 'const result = [...this.items].map(process)', output: 'const result = Array.from(this.items, process)', - errors: [ - { - messageId: 'preferArrayFrom', - data: {iterable: 'this.items', mapper: 'process'} - } - ] + errors: [{messageId: 'preferArrayFrom'}] }, // Chained with other array methods @@ -164,24 +115,14 @@ const b = Array.from(arr2, y => y + 1)`, code: 'const doubled = [...numbers].map(n => n * 2).filter(n => n > 10)', output: 'const doubled = Array.from(numbers, n => n * 2).filter(n => n > 10)', - errors: [ - { - messageId: 'preferArrayFrom', - data: {iterable: 'numbers', mapper: 'n => n * 2'} - } - ] + errors: [{messageId: 'preferArrayFrom'}] }, // sequence expressions must stay parenthesised { code: 'const result = [...(a, items)].map(process)', output: 'const result = Array.from((a, items), process)', - errors: [ - { - messageId: 'preferArrayFrom', - data: {iterable: '(a, items)', mapper: 'process'} - } - ] + errors: [{messageId: 'preferArrayFrom'}] } ] }); diff --git a/src/rules/prefer-array-from-map.ts b/src/rules/prefer-array-from-map.ts index 375a30c..b05f166 100644 --- a/src/rules/prefer-array-from-map.ts +++ b/src/rules/prefer-array-from-map.ts @@ -14,7 +14,7 @@ export const preferArrayFromMap: Rule.RuleModule = { schema: [], messages: { preferArrayFrom: - 'Use Array.from({{iterable}}, {{mapper}}) instead of [...{{iterable}}].map({{mapper}}) to avoid creating an intermediate array' + 'Use `Array.from(iterable, fn)` instead of `[...iterable].map(fn)` to avoid creating an intermediate array.' } }, create(context) { @@ -81,10 +81,6 @@ export const preferArrayFromMap: Rule.RuleModule = { context.report({ node, messageId: 'preferArrayFrom', - data: { - iterable: iterableText, - mapper: mapperText - }, fix(fixer) { return fixer.replaceText( node, diff --git a/src/rules/prefer-regex-test.ts b/src/rules/prefer-regex-test.ts index c320b0e..1282764 100644 --- a/src/rules/prefer-regex-test.ts +++ b/src/rules/prefer-regex-test.ts @@ -127,7 +127,7 @@ export const preferRegexTest: TSESLint.RuleModule = { fixable: 'code', messages: { preferTest: - 'Prefer `{{regex}}.test({{string}})` over `{{original}}` for boolean checks' + 'Prefer `regex.test(str)` over `match`/`exec` for boolean checks' }, schema: [] }, @@ -178,11 +178,6 @@ export const preferRegexTest: TSESLint.RuleModule = { context.report({ node, messageId: 'preferTest', - data: { - regex: regexText, - string: stringText, - original: sourceCode.getText(node) - }, fix(fixer) { return fixer.replaceText(node, `${regexText}.test(${stringText})`); }