diff --git a/eslint.config.mjs b/eslint.config.mjs index 63bb8b9310e5..7d2c53baab40 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -332,6 +332,7 @@ export default tseslint.config( 'unicorn/prefer-export-from': 'error', 'unicorn/prefer-node-protocol': 'error', 'unicorn/prefer-regexp-test': 'error', + 'unicorn/prefer-spread': 'error', 'unicorn/prefer-string-replace-all': 'error', 'unicorn/prefer-structured-clone': 'error', }, diff --git a/packages/ast-spec/tests/fixtures.test.ts b/packages/ast-spec/tests/fixtures.test.ts index 87a42cffa6d3..d64fb8c007c5 100644 --- a/packages/ast-spec/tests/fixtures.test.ts +++ b/packages/ast-spec/tests/fixtures.test.ts @@ -339,16 +339,12 @@ describe('AST Fixtures', () => { // once we've run all the tests, snapshot the list of fixtures that have differences for easy reference it('List fixtures with AST differences', () => { - expect( - Array.from(fixturesWithASTDifferences).sort(), - ).toMatchSpecificSnapshot( + expect([...fixturesWithASTDifferences].sort()).toMatchSpecificSnapshot( path.resolve(__dirname, 'fixtures-with-differences-ast.shot'), ); }); it('List fixtures with Token differences', () => { - expect( - Array.from(fixturesWithTokenDifferences).sort(), - ).toMatchSpecificSnapshot( + expect([...fixturesWithTokenDifferences].sort()).toMatchSpecificSnapshot( path.resolve(__dirname, 'fixtures-with-differences-tokens.shot'), ); }); @@ -357,7 +353,7 @@ describe('AST Fixtures', () => { Object.fromEntries( Object.entries(fixturesWithErrorDifferences).map(([key, value]) => [ key, - Array.from(value).sort(), + [...value].sort(), ]), ), ).toMatchSpecificSnapshot( @@ -366,7 +362,7 @@ describe('AST Fixtures', () => { }); it('List fixtures we expect babel to not support', () => { expect( - Array.from(fixturesConfiguredToExpectBabelToNotSupport).sort(), + [...fixturesConfiguredToExpectBabelToNotSupport].sort(), ).toMatchSpecificSnapshot( path.resolve(__dirname, 'fixtures-without-babel-support.shot'), ); diff --git a/packages/ast-spec/tests/util/serializers/Node.ts b/packages/ast-spec/tests/util/serializers/Node.ts index 73d394b9ce3f..4b7f60f989da 100644 --- a/packages/ast-spec/tests/util/serializers/Node.ts +++ b/packages/ast-spec/tests/util/serializers/Node.ts @@ -22,7 +22,7 @@ function sortKeys( keySet.delete('interpreter'); } - return Array.from(keySet).sort((a, b) => + return [...keySet].sort((a, b) => a.localeCompare(b), ) as (keyof typeof node)[]; } diff --git a/packages/eslint-plugin/src/rules/consistent-type-exports.ts b/packages/eslint-plugin/src/rules/consistent-type-exports.ts index 7f9568533710..1118c257d00f 100644 --- a/packages/eslint-plugin/src/rules/consistent-type-exports.ts +++ b/packages/eslint-plugin/src/rules/consistent-type-exports.ts @@ -291,7 +291,7 @@ function* fixSeparateNamedExports( ): IterableIterator { const { node, typeBasedSpecifiers, inlineTypeSpecifiers, valueSpecifiers } = report; - const typeSpecifiers = typeBasedSpecifiers.concat(inlineTypeSpecifiers); + const typeSpecifiers = [...typeBasedSpecifiers, ...inlineTypeSpecifiers]; const source = getSourceFromExport(node); const specifierNames = typeSpecifiers.map(getSpecifierText).join(', '); diff --git a/packages/eslint-plugin/src/rules/member-ordering.ts b/packages/eslint-plugin/src/rules/member-ordering.ts index 979c398cf157..fcc711a3aaa1 100644 --- a/packages/eslint-plugin/src/rules/member-ordering.ts +++ b/packages/eslint-plugin/src/rules/member-ordering.ts @@ -509,7 +509,7 @@ function getRankOrder( orderConfig: MemberType[], ): number { let rank = -1; - const stack = memberGroups.slice(); // Get a copy of the member groups + const stack = [...memberGroups]; // Get a copy of the member groups while (stack.length > 0 && rank === -1) { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion diff --git a/packages/eslint-plugin/src/rules/no-shadow.ts b/packages/eslint-plugin/src/rules/no-shadow.ts index 2de2cbf0ff60..806f1829bf0d 100644 --- a/packages/eslint-plugin/src/rules/no-shadow.ts +++ b/packages/eslint-plugin/src/rules/no-shadow.ts @@ -645,7 +645,7 @@ export default createRule({ return { 'Program:exit'(node): void { const globalScope = context.sourceCode.getScope(node); - const stack = globalScope.childScopes.slice(); + const stack = [...globalScope.childScopes]; while (stack.length) { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion diff --git a/packages/eslint-plugin/src/rules/prefer-function-type.ts b/packages/eslint-plugin/src/rules/prefer-function-type.ts index c7372c067f0b..74ee9ac968b7 100644 --- a/packages/eslint-plugin/src/rules/prefer-function-type.ts +++ b/packages/eslint-plugin/src/rules/prefer-function-type.ts @@ -108,9 +108,10 @@ export default createRule({ const text = context.sourceCode .getText() .slice(start, member.range[1]); - const comments = context.sourceCode - .getCommentsBefore(member) - .concat(context.sourceCode.getCommentsAfter(member)); + const comments = [ + ...context.sourceCode.getCommentsBefore(member), + ...context.sourceCode.getCommentsAfter(member), + ]; let suggestion = `${text.slice(0, colonPos)} =>${text.slice( colonPos + 1, )}`; diff --git a/packages/eslint-plugin/src/rules/prefer-readonly.ts b/packages/eslint-plugin/src/rules/prefer-readonly.ts index df05668299a2..3dab8b7f82a2 100644 --- a/packages/eslint-plugin/src/rules/prefer-readonly.ts +++ b/packages/eslint-plugin/src/rules/prefer-readonly.ts @@ -460,8 +460,8 @@ class ClassScope { }); return [ - ...Array.from(this.privateModifiableMembers.values()), - ...Array.from(this.privateModifiableStatics.values()), + ...this.privateModifiableMembers.values(), + ...this.privateModifiableStatics.values(), ]; } } diff --git a/packages/eslint-plugin/src/rules/unified-signatures.ts b/packages/eslint-plugin/src/rules/unified-signatures.ts index 9a6705576ed4..ee012cceb0ed 100644 --- a/packages/eslint-plugin/src/rules/unified-signatures.ts +++ b/packages/eslint-plugin/src/rules/unified-signatures.ts @@ -515,7 +515,7 @@ export default createRule({ 'checkScope() called without a current scope', ); const failures = checkOverloads( - Array.from(scope.overloads.values()), + [...scope.overloads.values()], scope.typeParameters, ); addFailures(failures); diff --git a/packages/rule-schema-to-typescript-types/src/generateType.ts b/packages/rule-schema-to-typescript-types/src/generateType.ts index 68c39f114787..00d4e0d6e9c0 100644 --- a/packages/rule-schema-to-typescript-types/src/generateType.ts +++ b/packages/rule-schema-to-typescript-types/src/generateType.ts @@ -38,7 +38,7 @@ export function generateType(schema: JSONSchema4, refMap: RefMap): AST { throw new UnexpectedError( `Could not find definition for $ref ${ schema.$ref - }.\nAvailable refs:\n${Array.from(refMap.keys()).join('\n')})`, + }.\nAvailable refs:\n${[...refMap.keys()].join('\n')})`, schema, ); } diff --git a/packages/rule-schema-to-typescript-types/src/optimizeAST.ts b/packages/rule-schema-to-typescript-types/src/optimizeAST.ts index ba39aae909a3..14a0fd1c778a 100644 --- a/packages/rule-schema-to-typescript-types/src/optimizeAST.ts +++ b/packages/rule-schema-to-typescript-types/src/optimizeAST.ts @@ -44,7 +44,7 @@ export function optimizeAST(ast: AST | null): void { for (const element of elements) { uniqueElementsMap.set(JSON.stringify(element), element); } - const uniqueElements = Array.from(uniqueElementsMap.values()); + const uniqueElements = [...uniqueElementsMap.values()]; // @ts-expect-error -- purposely overwriting the property with a flattened list ast.elements = uniqueElements; diff --git a/packages/rule-schema-to-typescript-types/src/printAST.ts b/packages/rule-schema-to-typescript-types/src/printAST.ts index f2ff982fb3ab..746d0b850b0c 100644 --- a/packages/rule-schema-to-typescript-types/src/printAST.ts +++ b/packages/rule-schema-to-typescript-types/src/printAST.ts @@ -42,7 +42,7 @@ function printAST(ast: AST): CodeWithComments { const code = printAndMaybeParenthesise(ast.elementType); return { code: `${code.code}[]`, - commentLines: ast.commentLines.concat(code.commentLines), + commentLines: [...ast.commentLines, ...code.commentLines], }; } diff --git a/packages/rule-tester/src/utils/flat-config-schema.ts b/packages/rule-tester/src/utils/flat-config-schema.ts index 0f46b9ef549e..63ef8fcadf2d 100644 --- a/packages/rule-tester/src/utils/flat-config-schema.ts +++ b/packages/rule-tester/src/utils/flat-config-schema.ts @@ -122,7 +122,7 @@ function normalizeRuleOptions( ruleOptions: SharedConfig.RuleLevel | SharedConfig.RuleLevelAndOptions, ): SharedConfig.RuleLevelAndOptions { const finalOptions = Array.isArray(ruleOptions) - ? ruleOptions.slice(0) + ? [...ruleOptions] : [ruleOptions]; finalOptions[0] = ruleSeverities.get( diff --git a/packages/scope-manager/src/ScopeManager.ts b/packages/scope-manager/src/ScopeManager.ts index 5814b6a78034..3fe70f467809 100644 --- a/packages/scope-manager/src/ScopeManager.ts +++ b/packages/scope-manager/src/ScopeManager.ts @@ -56,7 +56,7 @@ class ScopeManager { scope.childScopes.forEach(recurse); } this.scopes.forEach(recurse); - return Array.from(variables).sort((a, b) => a.$id - b.$id); + return [...variables].sort((a, b) => a.$id - b.$id); } constructor(options: ScopeManagerOptions) { diff --git a/packages/scope-manager/tests/fixtures.test.ts b/packages/scope-manager/tests/fixtures.test.ts index 5ddf348764c7..7ccf64f08fbc 100644 --- a/packages/scope-manager/tests/fixtures.test.ts +++ b/packages/scope-manager/tests/fixtures.test.ts @@ -125,7 +125,7 @@ function nestDescribe( if (type[1] && !type[1].has(value)) { throw new Error( - `Expected value for ${key} to be one of (${Array.from(type[1]).join( + `Expected value for ${key} to be one of (${[...type[1]].join( ' | ', )}), but got ${value as string}`, ); diff --git a/packages/typescript-estree/src/convert.ts b/packages/typescript-estree/src/convert.ts index 9c966b71955e..26b22ad2aa74 100644 --- a/packages/typescript-estree/src/convert.ts +++ b/packages/typescript-estree/src/convert.ts @@ -1984,9 +1984,9 @@ export class Converter { ); break; case SyntaxKind.NamedImports: - result.specifiers = result.specifiers.concat( - node.importClause.namedBindings.elements.map(el => - this.convertChild(el), + result.specifiers.push( + ...node.importClause.namedBindings.elements.map( + el => this.convertChild(el) as TSESTree.ImportClause, ), ); break; @@ -2165,7 +2165,7 @@ export class Converter { left.type === AST_NODE_TYPES.SequenceExpression && node.left.kind !== SyntaxKind.ParenthesizedExpression ) { - result.expressions = result.expressions.concat(left.expressions); + result.expressions.push(...left.expressions); } else { result.expressions.push(left); } diff --git a/packages/typescript-estree/src/create-program/createProjectProgramError.ts b/packages/typescript-estree/src/create-program/createProjectProgramError.ts index 2af659b217f6..9bf5d67da280 100644 --- a/packages/typescript-estree/src/create-program/createProjectProgramError.ts +++ b/packages/typescript-estree/src/create-program/createProjectProgramError.ts @@ -35,7 +35,7 @@ function getErrorStart( describedFilePath: string, parseSettings: ParseSettings, ): string { - const relativeProjects = Array.from(parseSettings.projects.values()).map( + const relativeProjects = [...parseSettings.projects.values()].map( projectFile => describeFilePath(projectFile, parseSettings.tsconfigRootDir), ); diff --git a/packages/typescript-estree/src/create-program/getWatchProgramsForProjects.ts b/packages/typescript-estree/src/create-program/getWatchProgramsForProjects.ts index 16db33b6964e..473e73f2ae78 100644 --- a/packages/typescript-estree/src/create-program/getWatchProgramsForProjects.ts +++ b/packages/typescript-estree/src/create-program/getWatchProgramsForProjects.ts @@ -320,7 +320,7 @@ function createWatchProgram( path, !extensions ? undefined - : extensions.concat(parseSettings.extraFileExtensions), + : [...extensions, ...parseSettings.extraFileExtensions], exclude, include, depth, diff --git a/packages/typescript-estree/src/getModifiers.ts b/packages/typescript-estree/src/getModifiers.ts index 19043b12c831..f5abd47c51f3 100644 --- a/packages/typescript-estree/src/getModifiers.ts +++ b/packages/typescript-estree/src/getModifiers.ts @@ -17,7 +17,7 @@ export function getModifiers( if (includeIllegalModifiers || ts.canHaveModifiers(node)) { // eslint-disable-next-line @typescript-eslint/no-deprecated -- this is safe as it's guarded const modifiers = ts.getModifiers(node as ts.HasModifiers); - return modifiers ? Array.from(modifiers) : undefined; + return modifiers ? [...modifiers] : undefined; } return undefined; @@ -44,7 +44,7 @@ export function getDecorators( if (includeIllegalDecorators || ts.canHaveDecorators(node)) { // eslint-disable-next-line @typescript-eslint/no-deprecated -- this is safe as it's guarded const decorators = ts.getDecorators(node as ts.HasDecorators); - return decorators ? Array.from(decorators) : undefined; + return decorators ? [...decorators] : undefined; } return undefined; diff --git a/packages/typescript-estree/src/parseSettings/resolveProjectList.ts b/packages/typescript-estree/src/parseSettings/resolveProjectList.ts index ee0e58f76942..4a09b55775e6 100644 --- a/packages/typescript-estree/src/parseSettings/resolveProjectList.ts +++ b/packages/typescript-estree/src/parseSettings/resolveProjectList.ts @@ -103,14 +103,12 @@ export function resolveProjectList( } const uniqueCanonicalProjectPaths = new Map( - nonGlobProjects - .concat(globProjectPaths) - .map(project => [ - getCanonicalFileName( - ensureAbsolutePath(project, options.tsconfigRootDir), - ), + [...nonGlobProjects, ...globProjectPaths].map(project => [ + getCanonicalFileName( ensureAbsolutePath(project, options.tsconfigRootDir), - ]), + ), + ensureAbsolutePath(project, options.tsconfigRootDir), + ]), ); log( diff --git a/packages/typescript-estree/src/parseSettings/warnAboutTSVersion.ts b/packages/typescript-estree/src/parseSettings/warnAboutTSVersion.ts index 710d5c69d587..c338c538bfec 100644 --- a/packages/typescript-estree/src/parseSettings/warnAboutTSVersion.ts +++ b/packages/typescript-estree/src/parseSettings/warnAboutTSVersion.ts @@ -16,9 +16,7 @@ const SUPPORTED_PRERELEASE_RANGES: string[] = []; const ACTIVE_TYPESCRIPT_VERSION = ts.version; const isRunningSupportedTypeScriptVersion = semver.satisfies( ACTIVE_TYPESCRIPT_VERSION, - [SUPPORTED_TYPESCRIPT_VERSIONS] - .concat(SUPPORTED_PRERELEASE_RANGES) - .join(' || '), + [SUPPORTED_TYPESCRIPT_VERSIONS, ...SUPPORTED_PRERELEASE_RANGES].join(' || '), ); let warnedAboutTSVersion = false; diff --git a/packages/typescript-estree/src/useProgramFromProjectService.ts b/packages/typescript-estree/src/useProgramFromProjectService.ts index 6efa688d8dd4..103f21b3cdc8 100644 --- a/packages/typescript-estree/src/useProgramFromProjectService.ts +++ b/packages/typescript-estree/src/useProgramFromProjectService.ts @@ -87,7 +87,7 @@ function openClientFileFromProjectService( serviceSettings.maximumDefaultProjectFileMatchCount ) { const filePrintLimit = 20; - const filesToPrint = Array.from(defaultProjectMatchedFiles).slice( + const filesToPrint = [...defaultProjectMatchedFiles].slice( 0, filePrintLimit, ); diff --git a/packages/utils/src/eslint-utils/deepMerge.ts b/packages/utils/src/eslint-utils/deepMerge.ts index 777407efffa5..78cb3ebfcd42 100644 --- a/packages/utils/src/eslint-utils/deepMerge.ts +++ b/packages/utils/src/eslint-utils/deepMerge.ts @@ -20,10 +20,10 @@ export function deepMerge( second: ObjectLike = {}, ): Record { // get the unique set of keys across both objects - const keys = new Set(Object.keys(first).concat(Object.keys(second))); + const keys = new Set([...Object.keys(first), ...Object.keys(second)]); return Object.fromEntries( - Array.from(keys, key => { + [...keys].map(key => { const firstHasKey = key in first; const secondHasKey = key in second; const firstValue = first[key]; diff --git a/packages/website-eslint/src/mock/path.js b/packages/website-eslint/src/mock/path.js index 674595ce81a7..3737bc24f8f3 100644 --- a/packages/website-eslint/src/mock/path.js +++ b/packages/website-eslint/src/mock/path.js @@ -167,14 +167,10 @@ export function relative(from, to) { } } - let outputParts = []; - for (let i = samePartsLength; i < fromParts.length; i++) { - outputParts.push('..'); - } - - outputParts = outputParts.concat(toParts.slice(samePartsLength)); - - return outputParts.join('/'); + return [ + ...Array(fromParts.length - samePartsLength).fill('..'), + ...toParts.slice(samePartsLength), + ].join('/'); } export const sep = '/'; diff --git a/packages/website/src/components/config/ConfigTypeScript.tsx b/packages/website/src/components/config/ConfigTypeScript.tsx index 1f45569df9c8..9d9352aef689 100644 --- a/packages/website/src/components/config/ConfigTypeScript.tsx +++ b/packages/website/src/components/config/ConfigTypeScript.tsx @@ -50,7 +50,7 @@ function ConfigTypeScript(props: ConfigTypeScriptProps): React.JSX.Element { key: item.name, type: 'string', label: item.description.message, - enum: ['', ...Array.from(item.type.keys())], + enum: ['', ...item.type.keys()], }); } return group; diff --git a/packages/website/src/components/editor/LoadedEditor.tsx b/packages/website/src/components/editor/LoadedEditor.tsx index 6dab67a39278..954b0bc4439d 100644 --- a/packages/website/src/components/editor/LoadedEditor.tsx +++ b/packages/website/src/components/editor/LoadedEditor.tsx @@ -155,7 +155,7 @@ export const LoadedEditor: React.FC = ({ enableSchemaRequest: false, allowComments: true, schemas: [ - ...Array.from(webLinter.rules.values()).map(rule => ({ + ...[...webLinter.rules.values()].map(rule => ({ uri: createRuleUri(rule.name), schema: getRuleJsonSchemaWithErrorLevel(rule.name, rule.schema), })), diff --git a/packages/website/src/components/editor/useSandboxServices.ts b/packages/website/src/components/editor/useSandboxServices.ts index fac8e1838fa0..13d1779fb7ae 100644 --- a/packages/website/src/components/editor/useSandboxServices.ts +++ b/packages/website/src/components/editor/useSandboxServices.ts @@ -120,10 +120,13 @@ export const useSandboxServices = ( ); onLoaded( - Array.from(webLinter.rules.values()), - Array.from( - new Set([...sandboxInstance.supportedVersions, window.ts.version]), - ) + [...webLinter.rules.values()], + [ + ...new Set([ + ...sandboxInstance.supportedVersions, + window.ts.version, + ]), + ] .filter(item => semverSatisfies(item, rootPackageJson.devDependencies.typescript), ) diff --git a/packages/website/src/components/lib/jsonSchema.ts b/packages/website/src/components/lib/jsonSchema.ts index fb48d465aed6..e61678858a4b 100644 --- a/packages/website/src/components/lib/jsonSchema.ts +++ b/packages/website/src/components/lib/jsonSchema.ts @@ -189,7 +189,7 @@ export function getTypescriptJsonSchema(): JSONSchema4 { value = { description: item.description.message, items: { - enum: Array.from(item.element.type.keys()), + enum: [...item.element.type.keys()], type: 'string', }, type: 'array', @@ -197,7 +197,7 @@ export function getTypescriptJsonSchema(): JSONSchema4 { } else if (item.type instanceof Map) { value = { description: item.description.message, - enum: Array.from(item.type.keys()), + enum: [...item.type.keys()], type: 'string', }; } diff --git a/packages/website/src/components/linter/createLinter.ts b/packages/website/src/components/linter/createLinter.ts index 0d3eea31794d..78f001439d87 100644 --- a/packages/website/src/components/linter/createLinter.ts +++ b/packages/website/src/components/linter/createLinter.ts @@ -182,7 +182,7 @@ export function createLinter( applyTSConfig('/tsconfig.json'); return { - configs: Array.from(configs.keys()), + configs: [...configs.keys()], onLint: onLint.register, onParse: onParse.register, rules, diff --git a/packages/website/src/components/linter/createParser.ts b/packages/website/src/components/linter/createParser.ts index 8be91ed929c2..6af8e0af3b85 100644 --- a/packages/website/src/components/linter/createParser.ts +++ b/packages/website/src/components/linter/createParser.ts @@ -28,7 +28,7 @@ export function createParser( ): tsvfs.VirtualTypeScriptEnvironment => { return vfs.createVirtualTypeScriptEnvironment( system, - Array.from(registeredFiles), + [...registeredFiles], window.ts, compilerOptions, ); diff --git a/packages/website/src/theme/NotFound/Content/index.tsx b/packages/website/src/theme/NotFound/Content/index.tsx index 4bc63043527e..26990fa82a88 100644 --- a/packages/website/src/theme/NotFound/Content/index.tsx +++ b/packages/website/src/theme/NotFound/Content/index.tsx @@ -13,7 +13,7 @@ export default function NotFound(): React.JSX.Element {

$ npx eslint .
- {`'${location.pathname}'`.split('').map((letter, i) => ( + {[...`'${location.pathname}'`].map((letter, i) => ( {letter} diff --git a/tools/scripts/generate-lib.mts b/tools/scripts/generate-lib.mts index 18fbfdba1d6a..12ef2fabc8fe 100644 --- a/tools/scripts/generate-lib.mts +++ b/tools/scripts/generate-lib.mts @@ -237,7 +237,7 @@ async function main(): Promise { if (requiredBaseImports.size > 0) { imports.push( - `import {${Array.from(requiredBaseImports) + `import {${[...requiredBaseImports] .sort() .join(',')}} from './${BASE_CONFIG_MODULE_NAME}';`, ); @@ -288,9 +288,7 @@ async function main(): Promise { // generate a string union type for the lib names const libUnionCode = [ - `type Lib = ${Array.from(libMap.keys()) - .map(k => `'${k}'`) - .join(' | ')};`, + `type Lib = ${[...libMap.keys()].map(k => `'${k}'`).join(' | ')};`, '', 'export { Lib };', ];