@expressjs/codemod
Version:
Codemods for updating express servers.
121 lines (120 loc) • 4.49 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = transformer;
const jscodeshift_1 = require("jscodeshift");
const recastOptions_1 = require("../utils/recastOptions");
const recursiveParent_1 = require("../utils/recursiveParent");
const separateStatusAndBody = (path, calleePropertyName) => {
const pathArguments = path.node.arguments;
const statusParamIndex = pathArguments.findIndex((arg) => arg.type === 'NumericLiteral');
const bodyParamIndex = pathArguments.findIndex((arg) => arg.type !== 'NumericLiteral');
path.replace((0, jscodeshift_1.callExpression)((0, jscodeshift_1.memberExpression)((0, jscodeshift_1.callExpression)((0, jscodeshift_1.memberExpression)((0, jscodeshift_1.identifier)((0, recursiveParent_1.recursiveParent)(path.parentPath, 1) || 'res'), (0, jscodeshift_1.identifier)('status')), [pathArguments[statusParamIndex]]), (0, jscodeshift_1.identifier)(calleePropertyName)), [pathArguments[bodyParamIndex]]));
};
function transformer(file, _api) {
const parser = (0, jscodeshift_1.withParser)('ts');
const parsedFile = parser(file.source);
parsedFile
.find(jscodeshift_1.CallExpression, {
callee: {
property: {
name: 'send',
},
},
})
.map((path) => {
// from v3: https://expressjs.com/en/3x/api.html#res.send
const pathArguments = path.node.arguments;
if (pathArguments.length === 2) {
separateStatusAndBody(path, 'send');
}
else if (pathArguments.length === 1) {
const statusValue = pathArguments[0].type === 'NumericLiteral' ? pathArguments[0].value : false;
if (statusValue) {
path.replace((0, jscodeshift_1.callExpression)((0, jscodeshift_1.memberExpression)((0, jscodeshift_1.identifier)((0, recursiveParent_1.recursiveParent)(path.parentPath, 1) || 'res'), (0, jscodeshift_1.identifier)('sendStatus')), [pathArguments[0]]));
}
}
return path;
});
parsedFile
.find(jscodeshift_1.CallExpression, {
callee: {
property: {
name: 'json',
},
},
})
.map((path) => {
// from v3: https://expressjs.com/en/3x/api.html#res.json
const pathArguments = path.node.arguments;
if (pathArguments.length === 2) {
separateStatusAndBody(path, 'json');
}
return path;
});
parsedFile
.find(jscodeshift_1.CallExpression, {
callee: {
property: {
name: 'jsonp',
},
},
})
.map((path) => {
// from v3: https://expressjs.com/en/3x/api.html#res.jsonp
const pathArguments = path.node.arguments;
if (pathArguments.length === 2) {
separateStatusAndBody(path, 'jsonp');
}
return path;
});
parsedFile
.find(jscodeshift_1.CallExpression, {
callee: {
property: {
name: 'del',
},
},
})
.map((path) => {
const pathArguments = path.node.arguments;
if (pathArguments[0].type !== 'RegExpLiteral' &&
pathArguments[0].type !== 'StringLiteral' &&
pathArguments[0].type !== 'ArrayExpression')
return path;
if (path.node.callee.type === 'MemberExpression' && path.node.callee.property.type === 'Identifier') {
path.node.callee.property.name = 'delete';
}
return path;
});
parsedFile
.find(jscodeshift_1.CallExpression, {
callee: {
property: {
name: 'sendfile',
},
},
})
.map((path) => {
if (path.node.callee.type === 'MemberExpression' && path.node.callee.property.type === 'Identifier') {
path.node.callee.property.name = 'sendFile';
}
return path;
});
parsedFile
.find(jscodeshift_1.CallExpression, {
callee: {
property: {
name: 'redirect',
},
},
})
.map((path) => {
const args = path.value.arguments;
// if its already in the correct order, dont reverse
if (args.length === 2 && args[0]?.type !== 'NumericLiteral') {
args.reverse();
}
return path;
});
return parsedFile.toSource((0, recastOptions_1.getOptions)(file.source));
}