diff --git a/packages/eslint-plugin/src/rules/member-ordering.ts b/packages/eslint-plugin/src/rules/member-ordering.ts index 93e5f45adcdc..979c398cf157 100644 --- a/packages/eslint-plugin/src/rules/member-ordering.ts +++ b/packages/eslint-plugin/src/rules/member-ordering.ts @@ -299,38 +299,36 @@ export const defaultOrder: MemberType[] = [ 'method', ]; -const allMemberTypes = Array.from( - ( - [ - 'readonly-signature', - 'signature', - 'readonly-field', - 'field', - 'method', - 'call-signature', - 'constructor', - 'accessor', - 'get', - 'set', - 'static-initialization', - ] as const - ).reduce>((all, type) => { - all.add(type); - - (['public', 'protected', 'private', '#private'] as const).forEach( - accessibility => { - if ( +const allMemberTypes = [ + ...new Set( + ( + [ + 'readonly-signature', + 'signature', + 'readonly-field', + 'field', + 'method', + 'call-signature', + 'constructor', + 'accessor', + 'get', + 'set', + 'static-initialization', + ] as const + ).flatMap(type => [ + type, + + ...(['public', 'protected', 'private', '#private'] as const) + .flatMap(accessibility => [ type !== 'readonly-signature' && type !== 'signature' && type !== 'static-initialization' && type !== 'call-signature' && !(type === 'constructor' && accessibility === '#private') - ) { - all.add(`${accessibility}-${type}`); // e.g. `public-field` - } + ? `${accessibility}-${type}` // e.g. `public-field` + : [], - // Only class instance fields, methods, accessors, get and set can have decorators attached to them - if ( + // Only class instance fields, methods, accessors, get and set can have decorators attached to them accessibility !== '#private' && (type === 'readonly-field' || type === 'field' || @@ -338,36 +336,36 @@ const allMemberTypes = Array.from( type === 'accessor' || type === 'get' || type === 'set') - ) { - all.add(`${accessibility}-decorated-${type}`); - all.add(`decorated-${type}`); - } + ? [`${accessibility}-decorated-${type}`, `decorated-${type}`] + : [], - if ( type !== 'constructor' && type !== 'readonly-signature' && type !== 'signature' && type !== 'call-signature' - ) { - // There is no `static-constructor` or `instance-constructor` or `abstract-constructor` - if (accessibility === '#private' || accessibility === 'private') { - (['static', 'instance'] as const).forEach(scope => { - all.add(`${scope}-${type}`); - all.add(`${accessibility}-${scope}-${type}`); - }); - } else { - (['static', 'instance', 'abstract'] as const).forEach(scope => { - all.add(`${scope}-${type}`); - all.add(`${accessibility}-${scope}-${type}`); - }); - } - } - }, - ); - - return all; - }, new Set()), -); + ? ( + [ + 'static', + 'instance', + // There is no `static-constructor` or `instance-constructor` or `abstract-constructor` + ...(accessibility === '#private' || + accessibility === 'private' + ? [] + : (['abstract'] as const)), + ] as const + ).flatMap( + scope => + [ + `${scope}-${type}`, + `${accessibility}-${scope}-${type}`, + ] as const, + ) + : [], + ]) + .flat(), + ]), + ), +]; const functionExpressions = [ AST_NODE_TYPES.FunctionExpression, diff --git a/packages/eslint-plugin/src/rules/naming-convention-utils/parse-options.ts b/packages/eslint-plugin/src/rules/naming-convention-utils/parse-options.ts index 08ac8d41c8b0..e66cdaaebda7 100644 --- a/packages/eslint-plugin/src/rules/naming-convention-utils/parse-options.ts +++ b/packages/eslint-plugin/src/rules/naming-convention-utils/parse-options.ts @@ -82,13 +82,12 @@ function normalizeOption(option: Selector): NormalizedSelector[] { function parseOptions(context: Context): ParsedOptions { const normalizedOptions = context.options.flatMap(normalizeOption); - const result = getEnumNames(Selectors).reduce((acc, k) => { - acc[k] = createValidator(k, context, normalizedOptions); - return acc; - // eslint-disable-next-line @typescript-eslint/prefer-reduce-type-parameter - }, {} as ParsedOptions); - - return result; + return Object.fromEntries( + getEnumNames(Selectors).map(k => [ + k, + createValidator(k, context, normalizedOptions), + ]), + ) as ParsedOptions; } export { parseOptions }; diff --git a/packages/eslint-plugin/src/rules/no-type-alias.ts b/packages/eslint-plugin/src/rules/no-type-alias.ts index 50c6197da76a..6459579060f4 100644 --- a/packages/eslint-plugin/src/rules/no-type-alias.ts +++ b/packages/eslint-plugin/src/rules/no-type-alias.ts @@ -324,10 +324,7 @@ export default createRule({ node.type === AST_NODE_TYPES.TSUnionType || node.type === AST_NODE_TYPES.TSIntersectionType ) { - return node.types.reduce((acc, type) => { - acc.push(...getTypes(type, node.type)); - return acc; - }, []); + return node.types.flatMap(type => getTypes(type, node.type)); } return [{ node, compositionType }]; } diff --git a/packages/eslint-plugin/tests/configs.test.ts b/packages/eslint-plugin/tests/configs.test.ts index 22da970a907d..7aa30ab5ddff 100644 --- a/packages/eslint-plugin/tests/configs.test.ts +++ b/packages/eslint-plugin/tests/configs.test.ts @@ -16,13 +16,6 @@ const EXTENSION_RULES = Object.entries(rules) ] as const, ); -function entriesToObject(value: [string, T][]): Record { - return value.reduce>((accum, [k, v]) => { - accum[k] = v; - return accum; - }, {}); -} - function filterRules( values: Record, ): [string, string | unknown[]][] { @@ -118,7 +111,9 @@ describe('all.ts', () => { excludeDeprecated: true, }); - expect(entriesToObject(ruleConfigs)).toEqual(entriesToObject(configRules)); + expect(Object.fromEntries(ruleConfigs)).toEqual( + Object.fromEntries(configRules), + ); }); itHasBaseRulesOverriden(unfilteredConfigRules); @@ -135,7 +130,9 @@ describe('disable-type-checked.ts', () => { .filter(([, rule]) => rule.meta.docs?.requiresTypeChecking) .map(([name]) => [`${RULE_NAME_PREFIX}${name}`, 'off']); - expect(entriesToObject(ruleConfigs)).toEqual(entriesToObject(configRules)); + expect(Object.fromEntries(ruleConfigs)).toEqual( + Object.fromEntries(configRules), + ); }); }); @@ -151,7 +148,9 @@ describe('recommended.ts', () => { recommendations: ['recommended'], }); - expect(entriesToObject(ruleConfigs)).toEqual(entriesToObject(configRules)); + expect(Object.fromEntries(ruleConfigs)).toEqual( + Object.fromEntries(configRules), + ); }); itHasBaseRulesOverriden(unfilteredConfigRules); @@ -168,7 +167,9 @@ describe('recommended-type-checked.ts', () => { recommendations: ['recommended'], }); - expect(entriesToObject(ruleConfigs)).toEqual(entriesToObject(configRules)); + expect(Object.fromEntries(ruleConfigs)).toEqual( + Object.fromEntries(configRules), + ); }); itHasBaseRulesOverriden(unfilteredConfigRules); @@ -186,7 +187,9 @@ describe('recommended-type-checked-only.ts', () => { recommendations: ['recommended'], }).filter(([ruleName]) => ruleName); - expect(entriesToObject(ruleConfigs)).toEqual(entriesToObject(configRules)); + expect(Object.fromEntries(ruleConfigs)).toEqual( + Object.fromEntries(configRules), + ); }); itHasBaseRulesOverriden(unfilteredConfigRules); @@ -205,7 +208,9 @@ describe('strict.ts', () => { recommendations: ['recommended', 'strict'], }); - expect(entriesToObject(ruleConfigs)).toEqual(entriesToObject(configRules)); + expect(Object.fromEntries(ruleConfigs)).toEqual( + Object.fromEntries(configRules), + ); }); itHasBaseRulesOverriden(unfilteredConfigRules); @@ -222,7 +227,9 @@ describe('strict-type-checked.ts', () => { excludeDeprecated: true, recommendations: ['recommended', 'strict'], }); - expect(entriesToObject(ruleConfigs)).toEqual(entriesToObject(configRules)); + expect(Object.fromEntries(ruleConfigs)).toEqual( + Object.fromEntries(configRules), + ); }); itHasBaseRulesOverriden(unfilteredConfigRules); @@ -241,7 +248,9 @@ describe('strict-type-checked-only.ts', () => { recommendations: ['recommended', 'strict'], }).filter(([ruleName]) => ruleName); - expect(entriesToObject(ruleConfigs)).toEqual(entriesToObject(configRules)); + expect(Object.fromEntries(ruleConfigs)).toEqual( + Object.fromEntries(configRules), + ); }); itHasBaseRulesOverriden(unfilteredConfigRules); @@ -259,7 +268,9 @@ describe('stylistic.ts', () => { recommendations: ['stylistic'], }); - expect(entriesToObject(ruleConfigs)).toEqual(entriesToObject(configRules)); + expect(Object.fromEntries(ruleConfigs)).toEqual( + Object.fromEntries(configRules), + ); }); itHasBaseRulesOverriden(unfilteredConfigRules); @@ -275,7 +286,9 @@ describe('stylistic-type-checked.ts', () => { }); it('contains all stylistic rules, excluding deprecated ones', () => { - expect(entriesToObject(ruleConfigs)).toEqual(entriesToObject(configRules)); + expect(Object.fromEntries(ruleConfigs)).toEqual( + Object.fromEntries(configRules), + ); }); itHasBaseRulesOverriden(unfilteredConfigRules); @@ -293,7 +306,9 @@ describe('stylistic-type-checked-only.ts', () => { recommendations: ['stylistic'], }).filter(([ruleName]) => ruleName); - expect(entriesToObject(ruleConfigs)).toEqual(entriesToObject(configRules)); + expect(Object.fromEntries(ruleConfigs)).toEqual( + Object.fromEntries(configRules), + ); }); itHasBaseRulesOverriden(unfilteredConfigRules); diff --git a/packages/eslint-plugin/tests/rules/no-base-to-string.test.ts b/packages/eslint-plugin/tests/rules/no-base-to-string.test.ts index 67c2a7ebddaa..59def86e4bfb 100644 --- a/packages/eslint-plugin/tests/rules/no-base-to-string.test.ts +++ b/packages/eslint-plugin/tests/rules/no-base-to-string.test.ts @@ -44,9 +44,9 @@ ruleTester.run('no-base-to-string', rule, { ...literalList.map(i => `\`\${${i}}\`;`), // operator + += - ...literalListWrapped - .map(l => literalListWrapped.map(r => `${l} + ${r};`)) - .reduce((pre, cur) => [...pre, ...cur]), + ...literalListWrapped.flatMap(l => + literalListWrapped.map(r => `${l} + ${r};`), + ), // toString() ...literalListWrapped.map(i => `${i === '1' ? `(${i})` : i}.toString();`), diff --git a/packages/eslint-plugin/tests/rules/no-explicit-any.test.ts b/packages/eslint-plugin/tests/rules/no-explicit-any.test.ts index ce4011290353..4652dd0ae069 100644 --- a/packages/eslint-plugin/tests/rules/no-explicit-any.test.ts +++ b/packages/eslint-plugin/tests/rules/no-explicit-any.test.ts @@ -1198,7 +1198,7 @@ const test = >() => {}; ], }, ] as RuleInvalidTestCase[] - ).reduce((acc, testCase) => { + ).flatMap(testCase => { const suggestions = (code: string): RuleSuggestionOutput[] => [ { messageId: 'suggestUnknown', @@ -1209,38 +1209,37 @@ const test = >() => {}; output: code.replace(/any/, 'never'), }, ]; - acc.push({ - ...testCase, - errors: testCase.errors.map(e => ({ - ...e, - suggestions: e.suggestions ?? suggestions(testCase.code), - })), - }); - const options = testCase.options ?? []; const code = `// fixToUnknown: true\n${testCase.code}`; - acc.push({ - code, - output: code.replaceAll('any', 'unknown'), - options: [{ ...options[0], fixToUnknown: true }], - errors: testCase.errors.map(err => { - if (err.line === undefined) { - return err; - } - - return { - ...err, - line: err.line + 1, - suggestions: - err.suggestions?.map( - (s): RuleSuggestionOutput => ({ - ...s, - output: `// fixToUnknown: true\n${s.output}`, - }), - ) ?? suggestions(code), - }; - }), - }); + return [ + { + ...testCase, + errors: testCase.errors.map(e => ({ + ...e, + suggestions: e.suggestions ?? suggestions(testCase.code), + })), + }, + { + code, + output: code.replaceAll('any', 'unknown'), + options: [{ ...testCase.options?.[0], fixToUnknown: true }], + errors: testCase.errors.map(err => { + if (err.line === undefined) { + return err; + } - return acc; - }, []), + return { + ...err, + line: err.line + 1, + suggestions: + err.suggestions?.map( + (s): RuleSuggestionOutput => ({ + ...s, + output: `// fixToUnknown: true\n${s.output}`, + }), + ) ?? suggestions(code), + }; + }), + }, + ]; + }), }); diff --git a/packages/eslint-plugin/tests/rules/no-inferrable-types.test.ts b/packages/eslint-plugin/tests/rules/no-inferrable-types.test.ts index fa1b7f4ffa37..6d9ad9cce982 100644 --- a/packages/eslint-plugin/tests/rules/no-inferrable-types.test.ts +++ b/packages/eslint-plugin/tests/rules/no-inferrable-types.test.ts @@ -10,9 +10,6 @@ import type { type MessageIds = InferMessageIdsTypeFromRule; type Options = InferOptionsTypeFromRule; -function flatten(arr: T[][]): T[] { - return arr.reduce((acc, a) => acc.concat(a), []); -} const testCases = [ { type: 'bigint', @@ -70,11 +67,11 @@ const testCases = [ code: ['undefined', 'void someValue'], }, ]; -const validTestCases = flatten( - testCases.map(c => c.code.map(code => `const a = ${code}`)), +const validTestCases = testCases.flatMap(c => + c.code.map(code => `const a = ${code}`), ); -const invalidTestCases: InvalidTestCase[] = flatten( - testCases.map(cas => +const invalidTestCases: InvalidTestCase[] = + testCases.flatMap(cas => cas.code.map(code => ({ code: `const a: ${cas.type} = ${code}`, output: `const a = ${code}`, @@ -89,8 +86,7 @@ const invalidTestCases: InvalidTestCase[] = flatten( }, ], })), - ), -); + ); const ruleTester = new RuleTester(); diff --git a/packages/eslint-plugin/tests/rules/no-unsafe-assignment.test.ts b/packages/eslint-plugin/tests/rules/no-unsafe-assignment.test.ts index 19357a7adf11..e637c14896c0 100644 --- a/packages/eslint-plugin/tests/rules/no-unsafe-assignment.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unsafe-assignment.test.ts @@ -12,55 +12,51 @@ type Options = InferOptionsTypeFromRule; type MessageIds = InferMessageIdsTypeFromRule; type InvalidTest = InvalidTestCase; -function assignmentTest( +const assignmentTest = ( tests: [string, number, number, boolean?][], -): InvalidTest[] { - return tests.reduce( - (acc, [assignment, column, endColumn, skipAssignmentExpression]) => { - // VariableDeclaration - acc.push({ - code: `const ${assignment}`, - errors: [ - { - messageId: 'unsafeArrayPatternFromTuple', - line: 1, - column: column + 6, - endColumn: endColumn + 6, - }, - ], - }); - // AssignmentPattern - acc.push({ - code: `function foo(${assignment}) {}`, - errors: [ +): InvalidTest[] => + tests.flatMap(([assignment, column, endColumn, skipAssignmentExpression]) => [ + // VariableDeclaration + { + code: `const ${assignment}`, + errors: [ + { + messageId: 'unsafeArrayPatternFromTuple', + line: 1, + column: column + 6, + endColumn: endColumn + 6, + }, + ], + }, + // AssignmentPattern + { + code: `function foo(${assignment}) {}`, + errors: [ + { + messageId: 'unsafeArrayPatternFromTuple', + line: 1, + column: column + 13, + endColumn: endColumn + 13, + }, + ], + }, + // AssignmentExpression + ...(skipAssignmentExpression + ? [] + : [ { - messageId: 'unsafeArrayPatternFromTuple', - line: 1, - column: column + 13, - endColumn: endColumn + 13, + code: `(${assignment})`, + errors: [ + { + messageId: 'unsafeArrayPatternFromTuple' as const, + line: 1, + column: column + 1, + endColumn: endColumn + 1, + }, + ], }, - ], - }); - // AssignmentExpression - if (skipAssignmentExpression !== true) { - acc.push({ - code: `(${assignment})`, - errors: [ - { - messageId: 'unsafeArrayPatternFromTuple', - line: 1, - column: column + 1, - endColumn: endColumn + 1, - }, - ], - }); - } - - return acc; - }, - [], - ); -} + ]), + ]); const ruleTester = new RuleTester({ languageOptions: { diff --git a/packages/eslint-plugin/tests/rules/prefer-nullish-coalescing.test.ts b/packages/eslint-plugin/tests/rules/prefer-nullish-coalescing.test.ts index da54f2881104..c61384b6f24e 100644 --- a/packages/eslint-plugin/tests/rules/prefer-nullish-coalescing.test.ts +++ b/packages/eslint-plugin/tests/rules/prefer-nullish-coalescing.test.ts @@ -33,31 +33,13 @@ function typeValidTest( ): (ValidTestCase | string)[] { return types.map(type => cb(type)); } -function nullishTypeValidTest( - cb: (nullish: string, type: string) => ValidTestCase | string, -): (ValidTestCase | string)[] { - return nullishTypes.reduce<(ValidTestCase | string)[]>( - (acc, nullish) => { - types.forEach(type => { - acc.push(cb(nullish, type)); - }); - return acc; - }, - [], - ); -} -function nullishTypeInvalidTest( - cb: (nullish: string, type: string) => InvalidTestCase, -): InvalidTestCase[] { - return nullishTypes.reduce[]>( - (acc, nullish) => { - types.forEach(type => { - acc.push(cb(nullish, type)); - }); - return acc; - }, - [], - ); +function nullishTypeTest< + T extends + | ValidTestCase + | InvalidTestCase + | string, +>(cb: (nullish: string, type: string) => T): T[] { + return nullishTypes.flatMap(nullish => types.map(type => cb(nullish, type))); } ruleTester.run('prefer-nullish-coalescing', rule, { @@ -68,7 +50,7 @@ declare const x: ${type}; x || 'foo'; `, ), - ...nullishTypeValidTest( + ...nullishTypeTest( (nullish, type) => ` declare const x: ${type} | ${nullish}; x ?? 'foo'; @@ -137,31 +119,31 @@ x === null ? x : y; })), // ignoreConditionalTests - ...nullishTypeValidTest((nullish, type) => ({ + ...nullishTypeTest((nullish, type) => ({ code: ` declare const x: ${type} | ${nullish}; x || 'foo' ? null : null; `, })), - ...nullishTypeValidTest((nullish, type) => ({ + ...nullishTypeTest((nullish, type) => ({ code: ` declare const x: ${type} | ${nullish}; if (x || 'foo') {} `, })), - ...nullishTypeValidTest((nullish, type) => ({ + ...nullishTypeTest((nullish, type) => ({ code: ` declare const x: ${type} | ${nullish}; do {} while (x || 'foo') `, })), - ...nullishTypeValidTest((nullish, type) => ({ + ...nullishTypeTest((nullish, type) => ({ code: ` declare const x: ${type} | ${nullish}; for (;x || 'foo';) {} `, })), - ...nullishTypeValidTest((nullish, type) => ({ + ...nullishTypeTest((nullish, type) => ({ code: ` declare const x: ${type} | ${nullish}; while (x || 'foo') {} @@ -169,7 +151,7 @@ while (x || 'foo') {} })), // ignoreMixedLogicalExpressions - ...nullishTypeValidTest((nullish, type) => ({ + ...nullishTypeTest((nullish, type) => ({ code: ` declare const a: ${type} | ${nullish}; declare const b: ${type} | ${nullish}; @@ -178,7 +160,7 @@ a || b && c; `, options: [{ ignoreMixedLogicalExpressions: true }], })), - ...nullishTypeValidTest((nullish, type) => ({ + ...nullishTypeTest((nullish, type) => ({ code: ` declare const a: ${type} | ${nullish}; declare const b: ${type} | ${nullish}; @@ -188,7 +170,7 @@ a || b || c && d; `, options: [{ ignoreMixedLogicalExpressions: true }], })), - ...nullishTypeValidTest((nullish, type) => ({ + ...nullishTypeTest((nullish, type) => ({ code: ` declare const a: ${type} | ${nullish}; declare const b: ${type} | ${nullish}; @@ -375,7 +357,7 @@ x || y; }, ], invalid: [ - ...nullishTypeInvalidTest((nullish, type) => ({ + ...nullishTypeTest((nullish, type) => ({ code: ` declare const x: ${type} | ${nullish}; x || 'foo'; @@ -596,7 +578,7 @@ if (x) { }, // ignoreConditionalTests - ...nullishTypeInvalidTest((nullish, type) => ({ + ...nullishTypeTest((nullish, type) => ({ code: ` declare const x: ${type} | ${nullish}; x || 'foo' ? null : null; @@ -622,7 +604,7 @@ x ?? 'foo' ? null : null; }, ], })), - ...nullishTypeInvalidTest((nullish, type) => ({ + ...nullishTypeTest((nullish, type) => ({ code: ` declare const x: ${type} | ${nullish}; if (x || 'foo') {} @@ -648,7 +630,7 @@ if (x ?? 'foo') {} }, ], })), - ...nullishTypeInvalidTest((nullish, type) => ({ + ...nullishTypeTest((nullish, type) => ({ code: ` declare const x: ${type} | ${nullish}; do {} while (x || 'foo') @@ -674,7 +656,7 @@ do {} while (x ?? 'foo') }, ], })), - ...nullishTypeInvalidTest((nullish, type) => ({ + ...nullishTypeTest((nullish, type) => ({ code: ` declare const x: ${type} | ${nullish}; for (;x || 'foo';) {} @@ -700,7 +682,7 @@ for (;x ?? 'foo';) {} }, ], })), - ...nullishTypeInvalidTest((nullish, type) => ({ + ...nullishTypeTest((nullish, type) => ({ code: ` declare const x: ${type} | ${nullish}; while (x || 'foo') {} @@ -728,7 +710,7 @@ while (x ?? 'foo') {} })), // ignoreMixedLogicalExpressions - ...nullishTypeInvalidTest((nullish, type) => ({ + ...nullishTypeTest((nullish, type) => ({ code: ` declare const a: ${type} | ${nullish}; declare const b: ${type} | ${nullish}; @@ -757,7 +739,7 @@ a ?? b && c; }, ], })), - ...nullishTypeInvalidTest((nullish, type) => ({ + ...nullishTypeTest((nullish, type) => ({ code: ` declare const a: ${type} | ${nullish}; declare const b: ${type} | ${nullish}; @@ -807,7 +789,7 @@ a || b ?? c && d; }, ], })), - ...nullishTypeInvalidTest((nullish, type) => ({ + ...nullishTypeTest((nullish, type) => ({ code: ` declare const a: ${type} | ${nullish}; declare const b: ${type} | ${nullish}; @@ -859,7 +841,7 @@ a && b || c ?? d; })), // should not false positive for functions inside conditional tests - ...nullishTypeInvalidTest((nullish, type) => ({ + ...nullishTypeTest((nullish, type) => ({ code: ` declare const x: ${type} | ${nullish}; if (() => x || 'foo') {} @@ -884,7 +866,7 @@ if (() => x ?? 'foo') {} }, ], })), - ...nullishTypeInvalidTest((nullish, type) => ({ + ...nullishTypeTest((nullish, type) => ({ code: ` declare const x: ${type} | ${nullish}; if (function werid() { return x || 'foo' }) {} @@ -910,7 +892,7 @@ if (function werid() { return x ?? 'foo' }) {} ], })), // https://github.com/typescript-eslint/typescript-eslint/issues/1290 - ...nullishTypeInvalidTest((nullish, type) => ({ + ...nullishTypeTest((nullish, type) => ({ code: ` declare const a: ${type} | ${nullish}; declare const b: ${type}; diff --git a/packages/parser/src/parser.ts b/packages/parser/src/parser.ts index 584d5727e12c..7393e64d8525 100644 --- a/packages/parser/src/parser.ts +++ b/packages/parser/src/parser.ts @@ -46,14 +46,9 @@ function validateBoolean( const LIB_FILENAME_REGEX = /lib\.(.+)\.d\.[cm]?ts$/; function getLib(compilerOptions: ts.CompilerOptions): Lib[] { if (compilerOptions.lib) { - return compilerOptions.lib.reduce((acc, lib) => { - const match = LIB_FILENAME_REGEX.exec(lib.toLowerCase()); - if (match) { - acc.push(match[1] as Lib); - } - - return acc; - }, []); + return compilerOptions.lib + .map(lib => LIB_FILENAME_REGEX.exec(lib.toLowerCase())?.[1]) + .filter((lib): lib is Lib => !!lib); } const target = compilerOptions.target ?? ScriptTarget.ES5; diff --git a/packages/typescript-eslint/tests/configs.test.ts b/packages/typescript-eslint/tests/configs.test.ts index 47293f819bf0..61f4f2a92dc9 100644 --- a/packages/typescript-eslint/tests/configs.test.ts +++ b/packages/typescript-eslint/tests/configs.test.ts @@ -20,13 +20,6 @@ const EXTENSION_RULES = Object.entries(rules) ] as const, ); -function entriesToObject(value: [string, T][]): Record { - return value.reduce>((accum, [k, v]) => { - accum[k] = v; - return accum; - }, {}); -} - function filterRules( values: FlatConfig.Rules | undefined, ): [string, FlatConfig.RuleEntry][] { @@ -123,7 +116,9 @@ describe('all.ts', () => { excludeDeprecated: true, }); - expect(entriesToObject(ruleConfigs)).toEqual(entriesToObject(configRules)); + expect(Object.fromEntries(ruleConfigs)).toEqual( + Object.fromEntries(configRules), + ); }); itHasBaseRulesOverriden(unfilteredConfigRules); @@ -139,7 +134,9 @@ describe('disable-type-checked.ts', () => { .filter(([, rule]) => rule.meta.docs.requiresTypeChecking) .map(([name]) => [`${RULE_NAME_PREFIX}${name}`, 'off']); - expect(entriesToObject(ruleConfigs)).toEqual(entriesToObject(configRules)); + expect(Object.fromEntries(ruleConfigs)).toEqual( + Object.fromEntries(configRules), + ); }); }); @@ -154,7 +151,9 @@ describe('recommended.ts', () => { typeChecked: 'exclude', }); - expect(entriesToObject(ruleConfigs)).toEqual(entriesToObject(configRules)); + expect(Object.fromEntries(ruleConfigs)).toEqual( + Object.fromEntries(configRules), + ); }); itHasBaseRulesOverriden(unfilteredConfigRules); @@ -170,7 +169,9 @@ describe('recommended-type-checked.ts', () => { recommendations: ['recommended'], }); - expect(entriesToObject(ruleConfigs)).toEqual(entriesToObject(configRules)); + expect(Object.fromEntries(ruleConfigs)).toEqual( + Object.fromEntries(configRules), + ); }); itHasBaseRulesOverriden(unfilteredConfigRules); @@ -188,7 +189,9 @@ describe('recommended-type-checked-only.ts', () => { typeChecked: 'include-only', }).filter(([ruleName]) => ruleName); - expect(entriesToObject(ruleConfigs)).toEqual(entriesToObject(configRules)); + expect(Object.fromEntries(ruleConfigs)).toEqual( + Object.fromEntries(configRules), + ); }); itHasBaseRulesOverriden(unfilteredConfigRules); @@ -206,7 +209,9 @@ describe('strict.ts', () => { typeChecked: 'exclude', }); - expect(entriesToObject(ruleConfigs)).toEqual(entriesToObject(configRules)); + expect(Object.fromEntries(ruleConfigs)).toEqual( + Object.fromEntries(configRules), + ); }); itHasBaseRulesOverriden(unfilteredConfigRules); @@ -222,7 +227,9 @@ describe('strict-type-checked.ts', () => { excludeDeprecated: true, recommendations: ['recommended', 'strict'], }); - expect(entriesToObject(ruleConfigs)).toEqual(entriesToObject(configRules)); + expect(Object.fromEntries(ruleConfigs)).toEqual( + Object.fromEntries(configRules), + ); }); itHasBaseRulesOverriden(unfilteredConfigRules); @@ -240,7 +247,9 @@ describe('strict-type-checked-only.ts', () => { typeChecked: 'include-only', }).filter(([ruleName]) => ruleName); - expect(entriesToObject(ruleConfigs)).toEqual(entriesToObject(configRules)); + expect(Object.fromEntries(ruleConfigs)).toEqual( + Object.fromEntries(configRules), + ); }); itHasBaseRulesOverriden(unfilteredConfigRules); @@ -257,7 +266,9 @@ describe('stylistic.ts', () => { typeChecked: 'exclude', }); - expect(entriesToObject(ruleConfigs)).toEqual(entriesToObject(configRules)); + expect(Object.fromEntries(ruleConfigs)).toEqual( + Object.fromEntries(configRules), + ); }); itHasBaseRulesOverriden(unfilteredConfigRules); @@ -272,7 +283,9 @@ describe('stylistic-type-checked.ts', () => { }); it('contains all stylistic rules, excluding deprecated ones', () => { - expect(entriesToObject(ruleConfigs)).toEqual(entriesToObject(configRules)); + expect(Object.fromEntries(ruleConfigs)).toEqual( + Object.fromEntries(configRules), + ); }); itHasBaseRulesOverriden(unfilteredConfigRules); @@ -290,7 +303,9 @@ describe('stylistic-type-checked-only.ts', () => { typeChecked: 'include-only', }).filter(([ruleName]) => ruleName); - expect(entriesToObject(ruleConfigs)).toEqual(entriesToObject(configRules)); + expect(Object.fromEntries(ruleConfigs)).toEqual( + Object.fromEntries(configRules), + ); }); itHasBaseRulesOverriden(unfilteredConfigRules); diff --git a/packages/typescript-estree/src/parseSettings/resolveProjectList.ts b/packages/typescript-estree/src/parseSettings/resolveProjectList.ts index c625914f3fa5..ee0e58f76942 100644 --- a/packages/typescript-estree/src/parseSettings/resolveProjectList.ts +++ b/packages/typescript-estree/src/parseSettings/resolveProjectList.ts @@ -56,15 +56,10 @@ export function resolveProjectList( const projectFolderIgnoreList = ( options.projectFolderIgnoreList ?? ['**/node_modules/**'] - ).reduce((acc, folder) => { - if (typeof folder === 'string') { - acc.push( - // prefix with a ! for not match glob - folder.startsWith('!') ? folder : `!${folder}`, - ); - } - return acc; - }, []); + ) + .filter(folder => typeof folder === 'string') + // prefix with a ! for not match glob + .map(folder => (folder.startsWith('!') ? folder : `!${folder}`)); const cacheKey = getHash({ project: sanitizedProjects, diff --git a/packages/utils/src/eslint-utils/deepMerge.ts b/packages/utils/src/eslint-utils/deepMerge.ts index b764e2294653..777407efffa5 100644 --- a/packages/utils/src/eslint-utils/deepMerge.ts +++ b/packages/utils/src/eslint-utils/deepMerge.ts @@ -22,28 +22,30 @@ export function deepMerge( // get the unique set of keys across both objects const keys = new Set(Object.keys(first).concat(Object.keys(second))); - return Array.from(keys).reduce((acc, key) => { - const firstHasKey = key in first; - const secondHasKey = key in second; - const firstValue = first[key]; - const secondValue = second[key]; + return Object.fromEntries( + Array.from(keys, key => { + const firstHasKey = key in first; + const secondHasKey = key in second; + const firstValue = first[key]; + const secondValue = second[key]; - if (firstHasKey && secondHasKey) { - if (isObjectNotArray(firstValue) && isObjectNotArray(secondValue)) { - // object type - acc[key] = deepMerge(firstValue, secondValue); + let value; + if (firstHasKey && secondHasKey) { + if (isObjectNotArray(firstValue) && isObjectNotArray(secondValue)) { + // object type + value = deepMerge(firstValue, secondValue); + } else { + // value type + value = secondValue; + } + } else if (firstHasKey) { + value = firstValue; } else { - // value type - acc[key] = secondValue; + value = secondValue; } - } else if (firstHasKey) { - acc[key] = firstValue; - } else { - acc[key] = secondValue; - } - - return acc; - }, {}); + return [key, value]; + }), + ); } export { isObjectNotArray }; diff --git a/packages/website/src/components/lib/jsonSchema.ts b/packages/website/src/components/lib/jsonSchema.ts index 7b63eec715bd..fb48d465aed6 100644 --- a/packages/website/src/components/lib/jsonSchema.ts +++ b/packages/website/src/components/lib/jsonSchema.ts @@ -176,30 +176,35 @@ export function getTypescriptOptions(): DescribedOptionDeclaration[] { * Get the JSON schema for the typescript config */ export function getTypescriptJsonSchema(): JSONSchema4 { - const properties = getTypescriptOptions().reduce((options, item) => { - if (item.type === 'boolean') { - options[item.name] = { - description: item.description.message, - type: 'boolean', - }; - } else if (item.type === 'list' && item.element?.type instanceof Map) { - options[item.name] = { - description: item.description.message, - items: { - enum: Array.from(item.element.type.keys()), - type: 'string', - }, - type: 'array', - }; - } else if (item.type instanceof Map) { - options[item.name] = { - description: item.description.message, - enum: Array.from(item.type.keys()), - type: 'string', - }; - } - return options; - }, {}); + const properties = Object.fromEntries( + getTypescriptOptions() + .map(item => { + let value; + if (item.type === 'boolean') { + value = { + description: item.description.message, + type: 'boolean', + }; + } else if (item.type === 'list' && item.element?.type instanceof Map) { + value = { + description: item.description.message, + items: { + enum: Array.from(item.element.type.keys()), + type: 'string', + }, + type: 'array', + }; + } else if (item.type instanceof Map) { + value = { + description: item.description.message, + enum: Array.from(item.type.keys()), + type: 'string', + }; + } + return [item.name, value] as const; + }) + .filter(([, value]) => value), + ); return { properties: { diff --git a/tools/scripts/generate-configs.mts b/tools/scripts/generate-configs.mts index cc105624be3b..ecd9b1ca2adc 100644 --- a/tools/scripts/generate-configs.mts +++ b/tools/scripts/generate-configs.mts @@ -72,9 +72,8 @@ async function main(): Promise { } const RULE_NAME_PREFIX = '@typescript-eslint/'; - const MAX_RULE_NAME_LENGTH = Object.keys(eslintPlugin.rules).reduce( - (acc, name) => Math.max(acc, name.length), - 0, + const MAX_RULE_NAME_LENGTH = Math.max( + ...Object.keys(eslintPlugin.rules).map(name => name.length), ); const BASE_RULES_TO_BE_OVERRIDDEN = new Map( Object.entries(eslintPlugin.rules)