The convention I want to use in the codebase is:
const a = 1;
const b = 2;
However, there are many areas in the code that are written like this:
let a = 1,
b = 2;
I want to write a codemod, probably using JSCodeshift that can change the second style of variable declaration to the first. I have been doing some research on ASTs and have been using AST explorer. However, I am having trouble accessing the variable declarator "kind" in the abstract syntax tree.
An example of something I've tried is this:
module.exports = function(file, api) {
const j = api.jscodeshift;
const root = j(file.source);
// Step 1: Find all instances of the code to change
const instances = root.find(VariableDeclarator.value.kind = 'let');
// Step 2: Apply a code transformation and replace the code
instances.forEach(instance => {
j(path).replaceWith(VariableDeclarator.value.kind = 'const');
});
return root.toSource();
}
}
Any help or direction would be appreciated! Thank you!
You can use ๐Putout
code transformer, Iโm working on, with @putout/plugin-split-variable-declarations
this way:
import putout from 'putout';
const {code} = putout('let a = 1, b = 2;', {
plugins: [
'split-variable-declarations',
['let-to-const', {
report: () => 'convert let to const',
replace: () => ({
'let __a = __b': 'const __a = __b',
}),
}]
]
});
console.log(code);
// output
const a = 1;
const b = 2;
Here is example from ๐Putout Editor
:
It looks like the main problem you're experiencing is using the correct syntax when using the find method. For example, changing your
const instances = root.find(VariableDeclarator.value.kind = 'let');
to
const instances = root.find(j.VariableDeclaration, {kind: 'let'});
You must use the type definition from api.jscodeshift
.
A complete example that does what you ask looks like:
export default function transformer(file, api) {
const j = api.jscodeshift;
const root = j(file.source);
const letDeclarations = root.find(j.VariableDeclaration, {kind: 'let'});
letDeclarations.replaceWith(({value: {declarations}}) => {
return declarations.map(dec =>
j.variableDeclaration(dec.init ? 'const' : 'let', [dec])
);
});
return root.toSource();
}
This will make the following transformation from:
let a = 1,
b = 2,
c;
const d = 3;
let e = 4;
var f = 4;
c = 3;
to:
const a = 1;
const b = 2;
let c;
const d = 3;
const e = 4;
var f = 4;
c = 3;
This codemod will only transform let declarations that include an initializer since that's required for const
declarations.
See the full example on AST Explorer to play around with it.