import parser from '@typescript-eslint/parser'; import { RuleTester } from '@typescript-eslint/rule-tester'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import dedent from 'dedent'; import { noPartialArrayReduce } from './no-partial-array-reduce.mjs'; const ruleTester = new RuleTester({ languageOptions: { parserOptions: { sourceType: 'module', project: './tsconfig.tests.json', }, parser, }, }); ruleTester.run('no-partial-array-reduce', noPartialArrayReduce, { valid: [ // non-empty array literal, reduce { filename: 'file.ts', code: dedent` ["a"].reduce(() => "a"); `, }, // non-empty array literal, reduceRight { filename: 'file.ts', code: dedent` ["a"].reduceRight(() => "a"); `, }, // empty array literal, initial value provided { filename: 'file.ts', code: dedent` [].reduce(() => "b", "a"); `, }, // non-empty tuple { filename: 'file.ts', code: dedent` const arr = ["a"] as const; arr.reduce(() => "b"); `, }, // non-empty tuple with rest { filename: 'file.ts', code: dedent` const arr: [string, ...string[]] = ["a"]; arr.reduce(() => "b"); `, }, // initial value provided { filename: 'file.ts', code: dedent` const arr = ["string"]; arr.reduce(() => "b", "a"); `, }, // initial value provided, readonly array { filename: 'file.ts', code: dedent` const arr: readonly string[] = ["string"]; arr.reduce(() => "b", "a"); `, }, // non-array type { filename: 'file.ts', code: dedent` type Foo = { reduce: (func: () => void) => void; }; declare const foo: Foo; foo.reduce(() => "a"); `, }, // method other than reduce { filename: 'file.ts', code: dedent` [].filter(() => true); `, }, // union of array types, initial value provided { filename: 'file.ts', code: dedent` const arr: readonly string[] | readonly number[] = ["string"]; arr.reduce(() => "b", "a"); `, }, // literal with first element undefined (doesn't throw) { filename: 'file.ts', code: dedent` [undefined].reduce(() => "a"); `, }, // computed form, literal { filename: 'file.ts', code: dedent` ["a"]["reduce"](() => "a"); `, }, // computed form, value { filename: 'file.ts', code: dedent` const n = "reduce"; ["a"][n](() => "a"); `, }, // computed form, union { filename: 'file.ts', code: dedent` let n: "reduce" | "reduceRight" = "reduce"; if (Date.now > 0) { n = "reduceRight"; } ["a"][n](() => "a"); `, }, // other function named reduce { filename: 'file.ts', code: dedent` const reduce = () => "a"; reduce(); `, }, ], invalid: [ // array of unknown length, reduce { filename: 'file.ts', code: dedent` const arr: readonly string[] = ["string"]; arr.reduce(() => "b"); `, errors: [ { messageId: 'errorStringGeneric', type: AST_NODE_TYPES.CallExpression, }, ], }, // array of unknown length, reduceRight { filename: 'file.ts', code: dedent` const arr: readonly string[] = ["string"]; arr.reduceRight(() => "b"); `, errors: [ { messageId: 'errorStringGeneric', type: AST_NODE_TYPES.CallExpression, }, ], }, // empty literal { filename: 'file.ts', code: dedent` [].reduce(() => "b"); `, errors: [ { messageId: 'errorStringGeneric', type: AST_NODE_TYPES.CallExpression, }, ], }, // empty tuple { filename: 'file.ts', code: dedent` const arr = [] as const; arr.reduce(() => "b"); `, errors: [ { messageId: 'errorStringGeneric', type: AST_NODE_TYPES.CallExpression, }, ], }, // union of array types, initial value not provided { filename: 'file.ts', code: dedent` const arr: readonly string[] | readonly number[] = ["string"]; arr.reduce(() => "b"); `, errors: [ { messageId: 'errorStringGeneric', type: AST_NODE_TYPES.CallExpression, }, ], }, // literal with spread { filename: 'file.ts', code: dedent` [...[]].reduce(() => "a"); `, errors: [ { messageId: 'errorStringGeneric', type: AST_NODE_TYPES.CallExpression, }, ], }, // computed form, literal { filename: 'file.ts', code: dedent` const arr: string[] = []; arr["reduce"](() => "a"); `, errors: [ { messageId: 'errorStringGeneric', type: AST_NODE_TYPES.CallExpression, }, ], }, // computed form, value { filename: 'file.ts', code: dedent` const arr: string[] = []; const n = "reduce"; arr[n](() => "a"); `, errors: [ { messageId: 'errorStringGeneric', type: AST_NODE_TYPES.CallExpression, }, ], }, // computed form, union { filename: 'file.ts', code: dedent` const arr: string[] = []; let n: "reduce" | "reduceRight" = "reduce"; if (Date.now > 0) { n = "reduceRight"; } arr[n](() => "a"); `, errors: [ { messageId: 'errorStringGeneric', type: AST_NODE_TYPES.CallExpression, }, ], }, ], } as const);