Skip to content

Commit

Permalink
Merge pull request #94 from es-tooling/iterating-through-time
Browse files Browse the repository at this point in the history
feat: add iterate-value
  • Loading branch information
thepassle authored Aug 26, 2024
2 parents 38c83b0 + 6c0c4f8 commit 2d915ff
Show file tree
Hide file tree
Showing 9 changed files with 342 additions and 0 deletions.
125 changes: 125 additions & 0 deletions codemods/iterate-value/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { ts } from '@ast-grep/napi';

/**
* @typedef {import('../../types.js').Codemod} Codemod
* @typedef {import('../../types.js').CodemodOptions} CodemodOptions
*/

/**
* @param {CodemodOptions} [options]
* @returns {Codemod}
*/
export default function (options) {
return {
name: 'iterate-value',
transform: ({ file }) => {
const ast = ts.parse(file.source);
const root = ast.root();
const imports = root.findAll({
rule: {
any: [
{
pattern: {
context: "import $NAME from 'iterate-value'",
strictness: 'relaxed',
},
},
{
pattern: {
context: "const $NAME = require('iterate-value')",
strictness: 'relaxed',
},
},
],
},
});

const edits = [];
/** @type {string|null} */
let importedName = null;

if (imports.length === 0) {
return file.source;
}

for (const node of imports) {
if (!importedName) {
const name = node.getMatch('NAME')?.text();

if (name) {
importedName = name;
}
}

edits.push(node.replace(''));
}

const calls = root.findAll({
rule: {
any: [
{
pattern: `${importedName}($ITERABLE)`,
},
{
pattern: `${importedName}($ITERABLE, $CALLBACK)`,
},
],
},
});

for (const node of calls) {
const iter = node.getMatch('ITERABLE');
const callback = node.getMatch('CALLBACK');

if (!iter) {
continue;
}

if (!callback) {
edits.push(node.replace(`Array.from(${iter.text()})`));
} else {
const callbackKind = callback.kind();
const callbackBody = callback.field('body');

if (
(callbackKind === 'arrow_function' ||
callbackKind === 'function_expression') &&
callbackBody
) {
const params = callback.field('parameters');
let valueName = '_value';

if (params) {
for (const param of params.children()) {
const paramKind = param.kind();

if (paramKind === 'required_parameter') {
valueName = param.text();
break;
}
}
}

edits.push(
node.replace(
`for (const ${valueName} of (${iter.text()})) ${callbackBody.text()}`,
),
);
} else {
edits.push(
node.replace(
`for (const value of (${iter.text()})) { ${callback.text()}(value); }`,
),
);
}
}
}

if (edits.length === 0) {
return file.source;
}

return root.commitEdits(edits);
},
};
}
2 changes: 2 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ import isString from './codemods/is-string/index.js';
import isTravis from './codemods/is-travis/index.js';
import isWhitespace from './codemods/is-whitespace/index.js';
import isWindows from './codemods/is-windows/index.js';
import iterateValue from './codemods/iterate-value/index.js';
import lastIndexOf from './codemods/last-index-of/index.js';
import leftPad from './codemods/left-pad/index.js';
import mathAcosh from './codemods/math.acosh/index.js';
Expand Down Expand Up @@ -252,6 +253,7 @@ export const codemods = {
"is-travis": isTravis,
"is-whitespace": isWhitespace,
"is-windows": isWindows,
"iterate-value": iterateValue,
"last-index-of": lastIndexOf,
"left-pad": leftPad,
"math.acosh": mathAcosh,
Expand Down
34 changes: 34 additions & 0 deletions test/fixtures/iterate-value/simple-cjs/after.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@


// string, no callback
const collection0 = Array.from('foo');

// string, callback
for (const chr of ('foo')) {
console.log(chr);
};

// string, callback ref
const callback0 = (chr) => console.log(chr);
for (const value of ('foo')) { callback0(value); };

// array, no callback
const collection1 = Array.from([3, 0, 3]);

// array, callback
for (const num of ([3, 0, 3])) {
console.log(num);
};

// array, function callback
for (const num of ([3, 0, 3])) {
console.log(num);
};

// array, no value in callback
for (const _value of ([8, 0, 8])) {
console.log('bleep bloop');
};

// ignored because it has invalid usage
iterate([8, 0, 8], (num) => {}, 'unexpected-third-arg');
34 changes: 34 additions & 0 deletions test/fixtures/iterate-value/simple-cjs/before.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
const iterate = require('iterate-value');

// string, no callback
const collection0 = iterate('foo');

// string, callback
iterate('foo', (chr) => {
console.log(chr);
});

// string, callback ref
const callback0 = (chr) => console.log(chr);
iterate('foo', callback0);

// array, no callback
const collection1 = iterate([3, 0, 3]);

// array, callback
iterate([3, 0, 3], (num) => {
console.log(num);
});

// array, function callback
iterate([3, 0, 3], function (num) {
console.log(num);
});

// array, no value in callback
iterate([8, 0, 8], () => {
console.log('bleep bloop');
});

// ignored because it has invalid usage
iterate([8, 0, 8], (num) => {}, 'unexpected-third-arg');
34 changes: 34 additions & 0 deletions test/fixtures/iterate-value/simple-cjs/result.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@


// string, no callback
const collection0 = Array.from('foo');

// string, callback
for (const chr of ('foo')) {
console.log(chr);
};

// string, callback ref
const callback0 = (chr) => console.log(chr);
for (const value of ('foo')) { callback0(value); };

// array, no callback
const collection1 = Array.from([3, 0, 3]);

// array, callback
for (const num of ([3, 0, 3])) {
console.log(num);
};

// array, function callback
for (const num of ([3, 0, 3])) {
console.log(num);
};

// array, no value in callback
for (const _value of ([8, 0, 8])) {
console.log('bleep bloop');
};

// ignored because it has invalid usage
iterate([8, 0, 8], (num) => {}, 'unexpected-third-arg');
34 changes: 34 additions & 0 deletions test/fixtures/iterate-value/simple/after.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@


// string, no callback
const collection0 = Array.from('foo');

// string, callback
for (const chr of ('foo')) {
console.log(chr);
};

// string, callback ref
const callback0 = (chr) => console.log(chr);
for (const value of ('foo')) { callback0(value); };

// array, no callback
const collection1 = Array.from([3, 0, 3]);

// array, callback
for (const num of ([3, 0, 3])) {
console.log(num);
};

// array, function callback
for (const num of ([3, 0, 3])) {
console.log(num);
};

// array, no value in callback
for (const _value of ([8, 0, 8])) {
console.log('bleep bloop');
};

// ignored because it has invalid usage
iterate([8, 0, 8], (num) => {}, 'unexpected-third-arg');
34 changes: 34 additions & 0 deletions test/fixtures/iterate-value/simple/before.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import iterate from 'iterate-value';

// string, no callback
const collection0 = iterate('foo');

// string, callback
iterate('foo', (chr) => {
console.log(chr);
});

// string, callback ref
const callback0 = (chr) => console.log(chr);
iterate('foo', callback0);

// array, no callback
const collection1 = iterate([3, 0, 3]);

// array, callback
iterate([3, 0, 3], (num) => {
console.log(num);
});

// array, function callback
iterate([3, 0, 3], function (num) {
console.log(num);
});

// array, no value in callback
iterate([8, 0, 8], () => {
console.log('bleep bloop');
});

// ignored because it has invalid usage
iterate([8, 0, 8], (num) => {}, 'unexpected-third-arg');
34 changes: 34 additions & 0 deletions test/fixtures/iterate-value/simple/result.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@


// string, no callback
const collection0 = Array.from('foo');

// string, callback
for (const chr of ('foo')) {
console.log(chr);
};

// string, callback ref
const callback0 = (chr) => console.log(chr);
for (const value of ('foo')) { callback0(value); };

// array, no callback
const collection1 = Array.from([3, 0, 3]);

// array, callback
for (const num of ([3, 0, 3])) {
console.log(num);
};

// array, function callback
for (const num of ([3, 0, 3])) {
console.log(num);
};

// array, no value in callback
for (const _value of ([8, 0, 8])) {
console.log('bleep bloop');
};

// ignored because it has invalid usage
iterate([8, 0, 8], (num) => {}, 'unexpected-third-arg');
11 changes: 11 additions & 0 deletions types/codemods/iterate-value/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* @typedef {import('../../types.js').Codemod} Codemod
* @typedef {import('../../types.js').CodemodOptions} CodemodOptions
*/
/**
* @param {CodemodOptions} [options]
* @returns {Codemod}
*/
export default function _default(options?: import("../../types.js").CodemodOptions | undefined): Codemod;
export type Codemod = import("../../types.js").Codemod;
export type CodemodOptions = import("../../types.js").CodemodOptions;

0 comments on commit 2d915ff

Please sign in to comment.