Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/codemods/array-at.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@ describe('array-at', () => {
const source = `
const lastItem = myArray[myArray.length - 1];
`;
expect(codemod.test({source})).toBe(true);
expect(codemod.test({source}).hasMatch).toBe(true);
});

it('should not detect when there is no array length - 1 access', () => {
const source = `
const firstItem = myArray[0];
`;
expect(codemod.test({source})).toBe(false);
expect(codemod.test({source}).hasMatch).toBe(false);
});
});
});
10 changes: 7 additions & 3 deletions src/codemods/array-at.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {parse, Lang, type Edit, type NapiConfig} from '@ast-grep/napi';
import type {Options, CodeMod} from '../shared.js';
import type {Options, CodeMod, TestResult} from '../shared.js';
import {getRangeForNode} from '../typescript-utils.js';

const arrayLengthLastIndexRule: NapiConfig = {
rule: {
Expand All @@ -8,11 +9,14 @@ const arrayLengthLastIndexRule: NapiConfig = {
};

export const codemod: CodeMod = {
test(options: Options): boolean {
test(options: Options): TestResult {
const ast = parse(Lang.TypeScript, options.source);
const root = ast.root();

return root.has(arrayLengthLastIndexRule);
const node = root.find(arrayLengthLastIndexRule);
return node
? {hasMatch: true, range: getRangeForNode(node)}
: {hasMatch: false};
},
apply(options: Options): string {
const ast = parse(Lang.TypeScript, options.source);
Expand Down
10 changes: 5 additions & 5 deletions src/codemods/array-fill.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,28 +123,28 @@ for (let i = 0; i < 5; i++) { arr.push(1); }`;
describe('test', () => {
it('should detect Array.from with constant callback', () => {
const source = `const arr = Array.from({length: 5}, () => 0);`;
expect(codemod.test({source})).toBe(true);
expect(codemod.test({source}).hasMatch).toBe(true);
});

it('should detect spread Array with map', () => {
const source = `const arr = [...Array(5)].map(() => 0);`;
expect(codemod.test({source})).toBe(true);
expect(codemod.test({source}).hasMatch).toBe(true);
});

it('should detect for loop array filling', () => {
const source = `const arr = new Array(5);
for (let i = 0; i < arr.length; i++) { arr[i] = 0; }`;
expect(codemod.test({source})).toBe(true);
expect(codemod.test({source}).hasMatch).toBe(true);
});

it('should not detect regular array creation', () => {
const source = `const arr = [1, 2, 3];`;
expect(codemod.test({source})).toBe(false);
expect(codemod.test({source}).hasMatch).toBe(false);
});

it('should not detect when there are no fill patterns', () => {
const source = `const arr = Array.from({length: 5}, (_, i) => i);`;
expect(codemod.test({source})).toBe(false);
expect(codemod.test({source}).hasMatch).toBe(false);
});
});
});
19 changes: 11 additions & 8 deletions src/codemods/array-fill.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import {
type SgNode,
type NapiConfig
} from '@ast-grep/napi';
import type {Options, CodeMod} from '../shared.js';
import type {Options, CodeMod, TestResult} from '../shared.js';
import {getRangeForNode} from '../typescript-utils.js';

const arrayFromRule: NapiConfig = {
rule: {
Expand Down Expand Up @@ -171,16 +172,18 @@ function transformEmptyArrayDeclarations(root: SgNode): Edit[] {
}

export const codemod: CodeMod = {
test(options: Options): boolean {
test(options: Options): TestResult {
const ast = parse(Lang.TypeScript, options.source);
const root = ast.root();

return (
root.has(arrayFromRule) ||
root.has(spreadMapRule) ||
root.has(arrayDeclarationRule) ||
root.has(emptyArrayDeclarationRule)
);
const node =
root.find(arrayFromRule) ??
root.find(spreadMapRule) ??
root.find(arrayDeclarationRule) ??
root.find(emptyArrayDeclarationRule);
return node
? {hasMatch: true, range: getRangeForNode(node)}
: {hasMatch: false};
},
apply(options: Options): string {
const ast = parse(Lang.TypeScript, options.source);
Expand Down
8 changes: 4 additions & 4 deletions src/codemods/array-includes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ describe('array-includes', () => {
console.log('found');
}
`;
expect(codemod.test({source})).toBe(true);
expect(codemod.test({source}).hasMatch).toBe(true);
});

it('should detect bitwise NOT patterns', () => {
Expand All @@ -168,7 +168,7 @@ describe('array-includes', () => {
console.log('found');
}
`;
expect(codemod.test({source})).toBe(true);
expect(codemod.test({source}).hasMatch).toBe(true);
});

it('should not detect when already using includes', () => {
Expand All @@ -177,14 +177,14 @@ describe('array-includes', () => {
console.log('found');
}
`;
expect(codemod.test({source})).toBe(false);
expect(codemod.test({source}).hasMatch).toBe(false);
});

it('should not detect plain indexOf calls', () => {
const source = `
const index = arr.indexOf(item);
`;
expect(codemod.test({source})).toBe(false);
expect(codemod.test({source}).hasMatch).toBe(false);
});
});
});
10 changes: 7 additions & 3 deletions src/codemods/array-includes.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {parse, Lang, type Edit, type NapiConfig} from '@ast-grep/napi';
import type {Options, CodeMod} from '../shared.js';
import type {Options, CodeMod, TestResult} from '../shared.js';
import {getRangeForNode} from '../typescript-utils.js';

const positiveChecksRule: NapiConfig = {
rule: {
Expand Down Expand Up @@ -32,11 +33,14 @@ const negativeChecksRule: NapiConfig = {
};

export const codemod: CodeMod = {
test(options: Options): boolean {
test(options: Options): TestResult {
const ast = parse(Lang.TypeScript, options.source);
const root = ast.root();

return root.has(positiveChecksRule) || root.has(negativeChecksRule);
const node = root.find(positiveChecksRule) ?? root.find(negativeChecksRule);
return node
? {hasMatch: true, range: getRangeForNode(node)}
: {hasMatch: false};
},
apply(options: Options): string {
const ast = parse(Lang.TypeScript, options.source);
Expand Down
8 changes: 4 additions & 4 deletions src/codemods/array-to-reversed.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,22 +43,22 @@ describe('array-to-reversed', () => {
describe('test', () => {
it('should detect slice().reverse() pattern', () => {
const source = 'const reversed = arr.slice().reverse();';
expect(codemod.test({source})).toBe(true);
expect(codemod.test({source}).hasMatch).toBe(true);
});

it('should detect [...array].reverse() pattern', () => {
const source = 'const reversed = [...arr].reverse();';
expect(codemod.test({source})).toBe(true);
expect(codemod.test({source}).hasMatch).toBe(true);
});

it('should not detect direct reverse() calls', () => {
const source = 'const reversed = arr.reverse();';
expect(codemod.test({source})).toBe(false);
expect(codemod.test({source}).hasMatch).toBe(false);
});

it('should not detect when there is no reverse pattern', () => {
const source = 'const arr = [1, 2, 3];';
expect(codemod.test({source})).toBe(false);
expect(codemod.test({source}).hasMatch).toBe(false);
});
});
});
10 changes: 7 additions & 3 deletions src/codemods/array-to-reversed.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {parse, Lang, type Edit, type NapiConfig} from '@ast-grep/napi';
import type {Options, CodeMod} from '../shared.js';
import type {Options, CodeMod, TestResult} from '../shared.js';
import {getRangeForNode} from '../typescript-utils.js';

const arrayToReversedRule: NapiConfig = {
rule: {
Expand All @@ -21,11 +22,14 @@ const arrayToReversedRule: NapiConfig = {
};

export const codemod: CodeMod = {
test(options: Options): boolean {
test(options: Options): TestResult {
const ast = parse(Lang.TypeScript, options.source);
const root = ast.root();

return root.has(arrayToReversedRule);
const node = root.find(arrayToReversedRule);
return node
? {hasMatch: true, range: getRangeForNode(node)}
: {hasMatch: false};
},
apply(options: Options): string {
const ast = parse(Lang.TypeScript, options.source);
Expand Down
8 changes: 4 additions & 4 deletions src/codemods/array-to-sorted.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,22 +49,22 @@ describe('array-to-sorted', () => {
describe('test', () => {
it('should detect slice().sort() pattern', () => {
const source = 'const sorted = arr.slice().sort();';
expect(codemod.test({source})).toBe(true);
expect(codemod.test({source}).hasMatch).toBe(true);
});

it('should detect [...arr].sort() pattern', () => {
const source = 'const sorted = [...arr].sort();';
expect(codemod.test({source})).toBe(true);
expect(codemod.test({source}).hasMatch).toBe(true);
});

it('should not detect direct sort() calls', () => {
const source = 'const sorted = arr.sort();';
expect(codemod.test({source})).toBe(false);
expect(codemod.test({source}).hasMatch).toBe(false);
});

it('should not detect when there is no sort pattern', () => {
const source = 'const arr = [1, 2, 3];';
expect(codemod.test({source})).toBe(false);
expect(codemod.test({source}).hasMatch).toBe(false);
});
});
});
11 changes: 7 additions & 4 deletions src/codemods/array-to-sorted.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {parse, Lang, type Edit, type NapiConfig} from '@ast-grep/napi';
import type {Options, CodeMod} from '../shared.js';
import {getNodesSourceText} from '../typescript-utils.js';
import type {Options, CodeMod, TestResult} from '../shared.js';
import {getNodesSourceText, getRangeForNode} from '../typescript-utils.js';

const arrayToSortedRule: NapiConfig = {
rule: {
Expand All @@ -22,11 +22,14 @@ const arrayToSortedRule: NapiConfig = {
};

export const codemod: CodeMod = {
test(options: Options): boolean {
test(options: Options): TestResult {
const ast = parse(Lang.TypeScript, options.source);
const root = ast.root();

return root.has(arrayToSortedRule);
const node = root.find(arrayToSortedRule);
return node
? {hasMatch: true, range: getRangeForNode(node)}
: {hasMatch: false};
},
apply(options: Options): string {
const ast = parse(Lang.TypeScript, options.source);
Expand Down
10 changes: 5 additions & 5 deletions src/codemods/array-to-spliced.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,27 +57,27 @@ describe('array-to-spliced', () => {
describe('test', () => {
it('should detect slice() followed by splice() pattern', () => {
const source = `const copy = arr.slice();\ncopy.splice(0, 1);`;
expect(codemod.test({source})).toBe(true);
expect(codemod.test({source}).hasMatch).toBe(true);
});

it('should detect spread followed by splice() pattern', () => {
const source = `const copy = [...arr];\ncopy.splice(0, 1);`;
expect(codemod.test({source})).toBe(true);
expect(codemod.test({source}).hasMatch).toBe(true);
});

it('should not detect direct splice() calls', () => {
const source = `arr.splice(0, 1);`;
expect(codemod.test({source})).toBe(false);
expect(codemod.test({source}).hasMatch).toBe(false);
});

it('should not detect when variable names do not match', () => {
const source = `const copy = arr.slice();\nother.splice(0, 1);`;
expect(codemod.test({source})).toBe(false);
expect(codemod.test({source}).hasMatch).toBe(false);
});

it('should not detect when there is no splice pattern', () => {
const source = `const arr = [1, 2, 3];`;
expect(codemod.test({source})).toBe(false);
expect(codemod.test({source}).hasMatch).toBe(false);
});
});
});
10 changes: 5 additions & 5 deletions src/codemods/array-to-spliced.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {parse, Lang, type Edit, type NapiConfig} from '@ast-grep/napi';
import type {Options, CodeMod} from '../shared.js';
import {getNodesSourceText} from '../typescript-utils.js';
import type {Options, CodeMod, TestResult} from '../shared.js';
import {getNodesSourceText, getRangeForNode} from '../typescript-utils.js';

const arrayClonePatterns = [
{pattern: 'const $NAME = $ARRAY.concat();'},
Expand Down Expand Up @@ -42,7 +42,7 @@ const createSpliceStatementRule = (name: string): NapiConfig => ({
});

export const codemod: CodeMod = {
test(options: Options): boolean {
test(options: Options): TestResult {
const ast = parse(Lang.TypeScript, options.source);
const root = ast.root();

Expand All @@ -53,11 +53,11 @@ export const codemod: CodeMod = {
const arraySplice = node.getMatch('ARRSPLICE');

if (name && arraySplice && name.text() === arraySplice.text()) {
return true;
return {hasMatch: true, range: getRangeForNode(node)};
}
}

return false;
return {hasMatch: false};
},
apply(options: Options): string {
const ast = parse(Lang.TypeScript, options.source);
Expand Down
4 changes: 2 additions & 2 deletions src/codemods/exponentiation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,14 @@ describe('exponentiation', () => {
const source = `
const result = Math.pow(2, 3);
`;
expect(codemod.test({source})).toBe(true);
expect(codemod.test({source}).hasMatch).toBe(true);
});

it('should not detect when there is no Math.pow', () => {
const source = `
const result = x ** y;
`;
expect(codemod.test({source})).toBe(false);
expect(codemod.test({source}).hasMatch).toBe(false);
});
});
});
10 changes: 7 additions & 3 deletions src/codemods/exponentiation.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {parse, Lang, type Edit, type NapiConfig} from '@ast-grep/napi';
import type {Options, CodeMod} from '../shared.js';
import type {Options, CodeMod, TestResult} from '../shared.js';
import {getRangeForNode} from '../typescript-utils.js';

const mathPowRule: NapiConfig = {
rule: {
Expand All @@ -8,11 +9,14 @@ const mathPowRule: NapiConfig = {
};

export const codemod: CodeMod = {
test(options: Options): boolean {
test(options: Options): TestResult {
const ast = parse(Lang.TypeScript, options.source);
const root = ast.root();

return root.has(mathPowRule);
const node = root.find(mathPowRule);
return node
? {hasMatch: true, range: getRangeForNode(node)}
: {hasMatch: false};
},
apply(options: Options): string {
let source = options.source;
Expand Down
Loading