amis-rpc-design/node_modules/jscodeshift/dist/template.js
2023-10-07 19:42:30 +08:00

174 lines
5.0 KiB
JavaScript

/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';
const recast = require('recast');
const builders = recast.types.builders;
const types = recast.types.namedTypes;
function splice(arr, element, replacement) {
arr.splice.apply(arr, [arr.indexOf(element), 1].concat(replacement));
}
function cleanLocation(node) {
delete node.start;
delete node.end;
delete node.loc;
return node;
}
function ensureStatement(node) {
return types.Statement.check(node) ?
// Removing the location information seems to ensure that the node is
// correctly reprinted with a trailing semicolon
cleanLocation(node) :
builders.expressionStatement(node);
}
function getVistor(varNames, nodes) {
return {
visitIdentifier: function(path) {
this.traverse(path);
const node = path.node;
const parent = path.parent.node;
// If this identifier is not one of our generated ones, do nothing
const varIndex = varNames.indexOf(node.name);
if (varIndex === -1) {
return;
}
let replacement = nodes[varIndex];
nodes[varIndex] = null;
// If the replacement is an array, we need to explode the nodes in context
if (Array.isArray(replacement)) {
if (types.Function.check(parent) &&
parent.params.indexOf(node) > -1) {
// Function parameters: function foo(${bar}) {}
splice(parent.params, node, replacement);
} else if (types.VariableDeclarator.check(parent)) {
// Variable declarations: var foo = ${bar}, baz = 42;
splice(
path.parent.parent.node.declarations,
parent,
replacement
);
} else if (types.ArrayExpression.check(parent)) {
// Arrays: var foo = [${bar}, baz];
splice(parent.elements, node, replacement);
} else if (types.Property.check(parent) && parent.shorthand) {
// Objects: var foo = {${bar}, baz: 42};
splice(
path.parent.parent.node.properties,
parent,
replacement
);
} else if (types.CallExpression.check(parent) &&
parent.arguments.indexOf(node) > -1) {
// Function call arguments: foo(${bar}, baz)
splice(parent.arguments, node, replacement);
} else if (types.ExpressionStatement.check(parent)) {
// Generic sequence of statements: { ${foo}; bar; }
path.parent.replace.apply(
path.parent,
replacement.map(ensureStatement)
);
} else {
// Every else, let recast take care of it
path.replace.apply(path, replacement);
}
} else if (types.ExpressionStatement.check(parent)) {
path.parent.replace(ensureStatement(replacement));
} else {
path.replace(replacement);
}
}
};
}
function replaceNodes(src, varNames, nodes, parser) {
const ast = recast.parse(src, {parser});
recast.visit(ast, getVistor(varNames, nodes));
return ast;
}
let varNameCounter = 0;
function getUniqueVarName() {
return `$jscodeshift${varNameCounter++}$`;
}
module.exports = function withParser(parser) {
function statements(template/*, ...nodes*/) {
template = Array.from(template);
const nodes = Array.from(arguments).slice(1);
const varNames = nodes.map(() => getUniqueVarName());
const src = template.reduce(
(result, elem, i) => result + varNames[i - 1] + elem
);
return replaceNodes(
src,
varNames,
nodes,
parser
).program.body;
}
function statement(/*template, ...nodes*/) {
return statements.apply(null, arguments)[0];
}
function expression(template/*, ...nodes*/) {
// wrap code in `(...)` to force evaluation as expression
template = Array.from(template);
if (template.length > 0) {
template[0] = '(' + template[0];
template[template.length - 1] += ')';
}
const expression = statement.apply(
null,
[template].concat(Array.from(arguments).slice(1))
).expression;
// Remove added parens
if (expression.extra) {
expression.extra.parenthesized = false;
}
return expression;
}
function asyncExpression(template/*, ...nodes*/) {
template = Array.from(template);
if (template.length > 0) {
template[0] = 'async () => (' + template[0];
template[template.length - 1] += ')';
}
const expression = statement.apply(
null,
[template].concat(Array.from(arguments).slice(1))
).expression.body;
// Remove added parens
if (expression.extra) {
expression.extra.parenthesized = false;
}
return expression;
}
return {statements, statement, expression, asyncExpression};
}