Last active
January 9, 2024 20:22
-
-
Save rosston/9d5319b54ea695826dfc12f13c7e7cb4 to your computer and use it in GitHub Desktop.
jscodeshift "transform" to find uses of any lodash method
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
// | |
// Usage: | |
// jscodeshift -t find-lodash-method.js /path/to/dir/or/file --method-name=<lodash_method> [--min-args=<min_num_args>] [--chain-only=1] | |
// | |
// Prints all locations of matching uses of the lodash method (e.g., `map`). | |
// | |
// Function copied from https://github.com/jfmengels/lodash-codemods/blob/v1.0.1/lib/method-calls-conditional-name-changes.js#L163-L179 | |
function isLodashChain(node) { | |
if (node.type === 'CallExpression') { | |
if (node.callee.type !== 'Identifier') { | |
return isLodashChain(node.callee); | |
} | |
return node.callee.name === '_'; | |
} | |
if (node.type === 'MemberExpression') { | |
if (node.object.type !== 'Identifier') { | |
return isLodashChain(node.object); | |
} | |
return node.object.name === '_' && | |
node.property.type === 'Identifier' && | |
node.property.name === 'chain'; | |
} | |
return false; | |
} | |
// Function copied from https://github.com/jfmengels/lodash-codemods/blob/v1.0.1/lib/method-calls-conditional-name-changes.js#L6-L8 | |
const hasMinArgs = (n, p, isInChain) => { | |
return p.arguments.length >= n - (isInChain ? 1 : 0); | |
}; | |
module.exports = function transformer(file, api, options) { | |
const chainOnly = options['chain-only']; | |
const methodName = options['method-name']; | |
const minArgs = options['min-args']; | |
const j = api.jscodeshift; | |
const ast = j(file.source); | |
const selector = { | |
type: j.CallExpression, | |
properties: { | |
callee: { | |
object: {name: '_'}, | |
property: {name: methodName} | |
} | |
} | |
}; | |
const matchHandler = (p) => { | |
const position = [ | |
file.path, | |
p.value.loc.start.line, | |
p.value.loc.start.column | |
].join(':'); | |
console.log(`\`_.${methodName}\` found at ${position}`); | |
}; | |
if (!chainOnly) { | |
// Find unchained uses, e.g., `_.forEach` | |
ast.find(selector.type, selector.properties) | |
.filter((p) => (!minArgs || hasMinArgs(minArgs, p.value, false))) | |
.forEach(matchHandler); | |
} | |
// Find chained uses, e.g., `_(foo).forEach` | |
ast.find(selector.type, {callee: {property: {name: methodName}}}) | |
.filter((p) => isLodashChain(p.value.callee.object)) | |
.filter((p) => (!minArgs || hasMinArgs(minArgs, p.value, true))) | |
.forEach(matchHandler); | |
return file.source; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment