@ui5/linter
Version:
A static code analysis tool for UI5
453 lines • 25.1 kB
JavaScript
import ts from "typescript";
import { getLogger } from "@ui5/logger";
const { SyntaxKind } = ts;
import { toPosStr, UnsupportedModuleError } from "./util.js";
const log = getLogger("linter:ui5Types:amdTranspiler:replaceNodeInParent");
/**
* Replaces a node in its parent with another node
*/
export default function (parent, replacement, nodeFactory) {
const { original, substitute } = replacement;
log.verbose(`Replacing child of ${ts.SyntaxKind[parent.kind]}\n` +
` Old: ${ts.SyntaxKind[original.kind]}\n` +
` New: ${ts.SyntaxKind[substitute.kind]}`);
switch (parent.kind) {
case SyntaxKind.ExpressionStatement:
return replaceInExpressionStatement(parent, replacement, nodeFactory);
case SyntaxKind.ParenthesizedExpression:
return replaceInParenthesizedExpression(parent, replacement, nodeFactory);
case SyntaxKind.CallExpression:
return replaceInCallExpression(parent, replacement, nodeFactory);
case SyntaxKind.NewExpression:
return replaceInNewExpression(parent, replacement, nodeFactory);
case SyntaxKind.BinaryExpression:
return replaceInBinaryExpression(parent, replacement, nodeFactory);
case SyntaxKind.ConditionalExpression:
return replaceInConditionalExpression(parent, replacement, nodeFactory);
case SyntaxKind.PrefixUnaryExpression:
return replaceInPrefixUnaryExpression(parent, replacement, nodeFactory);
case SyntaxKind.PostfixUnaryExpression:
return replaceInPostfixUnaryExpression(parent, replacement, nodeFactory);
case SyntaxKind.YieldExpression:
return replaceInYieldExpression(parent, replacement, nodeFactory);
case SyntaxKind.AwaitExpression:
return replaceInAwaitExpression(parent, replacement, nodeFactory);
case SyntaxKind.VariableStatement:
return replaceInVariableStatement(parent, replacement, nodeFactory);
case SyntaxKind.VariableDeclaration:
return replaceInVariableDeclaration(parent, replacement, nodeFactory);
case SyntaxKind.VariableDeclarationList:
return replaceInVariableDeclarationList(parent, replacement, nodeFactory);
case SyntaxKind.PropertyAssignment:
return replaceInPropertyAssignment(parent, replacement, nodeFactory);
case SyntaxKind.PropertyDeclaration:
return replaceInPropertyDeclaration(parent, replacement, nodeFactory);
case SyntaxKind.IfStatement:
return replaceInIfStatement(parent, replacement, nodeFactory);
case SyntaxKind.WhileStatement:
return replaceInWhileStatement(parent, replacement, nodeFactory);
case SyntaxKind.DoStatement:
return replaceInDoStatement(parent, replacement, nodeFactory);
case SyntaxKind.ForStatement:
return replaceInForStatement(parent, replacement, nodeFactory);
case SyntaxKind.ReturnStatement:
return replaceInReturnStatement(parent, replacement, nodeFactory);
case SyntaxKind.ArrayLiteralExpression:
return replaceInArrayLiteralExpression(parent, replacement, nodeFactory);
case SyntaxKind.ObjectLiteralExpression:
return replaceInObjectLiteralExpression(parent, replacement, nodeFactory);
case SyntaxKind.PropertyAccessExpression:
return replaceInPropertyAccessExpression(parent, replacement, nodeFactory);
case SyntaxKind.ElementAccessExpression:
return replaceInElementAccessExpression(parent, replacement, nodeFactory);
case SyntaxKind.Block:
return replaceInBlock(parent, replacement, nodeFactory);
case SyntaxKind.ArrowFunction:
return replaceInArrowFunction(parent, replacement, nodeFactory);
case SyntaxKind.FunctionExpression:
return replaceInFunctionExpression(parent, replacement, nodeFactory);
case SyntaxKind.FunctionDeclaration:
return replaceInFunctionDeclaration(parent, replacement, nodeFactory);
case SyntaxKind.MethodDeclaration:
return replaceInMethodDeclaration(parent, replacement, nodeFactory);
case SyntaxKind.ClassDeclaration:
return replaceInClassDeclaration(parent, replacement, nodeFactory);
case SyntaxKind.ComputedPropertyName:
return replaceInComputedPropertyName(parent, replacement, nodeFactory);
case SyntaxKind.Parameter:
return replaceInParameterDeclaration(parent, replacement, nodeFactory);
case SyntaxKind.SourceFile:
return replaceInSourceFile(parent, replacement, nodeFactory);
default:
throw new UnsupportedModuleError(`Unsupported parent node type for replacement operation: ${ts.SyntaxKind[parent.kind]} at ` +
`${toPosStr(parent)}`);
}
}
function replaceNodeInArray(original, substitute, array) {
// First create a flat copy of the array
const newArray = array.slice();
const index = array.indexOf(original);
if (index < 0) {
throw new Error(`Node not found in array`);
}
newArray[index] = substitute;
return newArray;
}
function replaceInExpressionStatement(node, { substitute }, nodeFactory) {
if (!ts.isExpression(substitute)) {
throw new UnsupportedModuleError(`Unexpected replacement type for ExpressionStatement (expected Expression): ` +
`${ts.SyntaxKind[substitute.kind]} at ${toPosStr(node)}`);
}
return nodeFactory.updateExpressionStatement(node, substitute);
}
function replaceInParenthesizedExpression(node, { substitute }, nodeFactory) {
if (!ts.isExpression(substitute)) {
throw new UnsupportedModuleError(`Unexpected replacement type for ParenthesizedExpression (expected Expression): ` +
`${ts.SyntaxKind[substitute.kind]} at ${toPosStr(node)}`);
}
return nodeFactory.updateParenthesizedExpression(node, substitute);
}
function replaceInCallExpression(node, { original, substitute }, nodeFactory) {
if (node.expression === original) {
// Replace expression
if (!ts.isExpression(substitute)) {
throw new UnsupportedModuleError(`Unexpected replacement type for CallExpression (expected Expression): ` +
`${ts.SyntaxKind[substitute.kind]} at ${toPosStr(node)}`);
}
return nodeFactory.updateCallExpression(node, substitute, node.typeArguments, node.arguments);
}
else if (node.arguments.includes(original)) {
// Replace argument
const args = replaceNodeInArray(original, substitute, node.arguments);
return nodeFactory.updateCallExpression(node, node.expression, node.typeArguments, args);
}
else {
throw new UnsupportedModuleError(`Unexpected child node for CallExpression replacement: ${ts.SyntaxKind[original.kind]} at ` +
`${toPosStr(original)}`);
}
}
function replaceInNewExpression(node, { original, substitute }, nodeFactory) {
if (node.expression === original) {
// Replace expression
if (!ts.isExpression(substitute)) {
throw new UnsupportedModuleError(`Unexpected replacement type for NewExpression (expected Expression): ` +
`${ts.SyntaxKind[substitute.kind]} at ${toPosStr(node)}`);
}
return nodeFactory.updateNewExpression(node, substitute, node.typeArguments, node.arguments);
}
else if (node.arguments?.includes(original)) {
// Replace argument
const args = replaceNodeInArray(original, substitute, node.arguments);
return nodeFactory.updateNewExpression(node, node.expression, node.typeArguments, args);
}
else {
throw new UnsupportedModuleError(`Unexpected child node for NewExpression replacement: ${ts.SyntaxKind[original.kind]} at ` +
`${toPosStr(original)}`);
}
}
function replaceInBinaryExpression(node, { original, substitute }, nodeFactory) {
if (!ts.isExpression(substitute)) {
throw new UnsupportedModuleError(`Unexpected replacement type for BinaryExpression (expected Expression): ` +
`${ts.SyntaxKind[substitute.kind]} at ${toPosStr(node)}`);
}
if (node.left === original) {
// Replace left
return nodeFactory.updateBinaryExpression(node, substitute, node.operatorToken, node.right);
}
else { // Must be right
// Replace right
return nodeFactory.updateBinaryExpression(node, node.left, node.operatorToken, substitute);
}
}
function replaceInConditionalExpression(node, { original, substitute }, nodeFactory) {
if (!ts.isExpression(substitute)) {
throw new UnsupportedModuleError(`Unexpected replacement type for ConditionalExpression (expected Expression): ` +
`${ts.SyntaxKind[substitute.kind]} at ${toPosStr(node)}`);
}
if (node.condition === original) {
// Replace condition
return nodeFactory.updateConditionalExpression(node, substitute, node.questionToken, node.whenTrue, node.colonToken, node.whenFalse);
}
else if (node.whenTrue === original) {
// Replace whenTrue
return nodeFactory.updateConditionalExpression(node, node.condition, node.questionToken, substitute, node.colonToken, node.whenFalse);
}
else { // Must be whenFalse
// Replace whenFalse
return nodeFactory.updateConditionalExpression(node, node.condition, node.questionToken, node.whenTrue, node.colonToken, substitute);
}
}
function replaceInPrefixUnaryExpression(node, { substitute }, nodeFactory) {
if (!ts.isExpression(substitute)) {
throw new UnsupportedModuleError(`Unexpected replacement type for PrefixUnaryExpression (expected Expression): ` +
`${ts.SyntaxKind[substitute.kind]} at ${toPosStr(node)}`);
}
return nodeFactory.updatePrefixUnaryExpression(node, substitute);
}
function replaceInPostfixUnaryExpression(node, { substitute }, nodeFactory) {
if (!ts.isExpression(substitute)) {
throw new UnsupportedModuleError(`Unexpected replacement type for PostfixUnaryExpression (expected Expression): ` +
`${ts.SyntaxKind[substitute.kind]} at ${toPosStr(node)}`);
}
return nodeFactory.updatePostfixUnaryExpression(node, substitute);
}
function replaceInYieldExpression(node, { substitute }, nodeFactory) {
if (!ts.isExpression(substitute)) {
throw new UnsupportedModuleError(`Unexpected replacement type for YieldExpression (expected Expression): ` +
`${ts.SyntaxKind[substitute.kind]} at ${toPosStr(node)}`);
}
return nodeFactory.updateYieldExpression(node, node.asteriskToken, substitute);
}
function replaceInAwaitExpression(node, { substitute }, nodeFactory) {
if (!ts.isExpression(substitute)) {
throw new UnsupportedModuleError(`Unexpected replacement type for AwaitExpression (expected Expression): ` +
`${ts.SyntaxKind[substitute.kind]} at ${toPosStr(node)}`);
}
return nodeFactory.updateAwaitExpression(node, substitute);
}
function replaceInVariableStatement(node, { original, substitute }, nodeFactory) {
const declarationList = replaceNodeInArray(original, substitute, node.declarationList.declarations);
return nodeFactory.updateVariableStatement(node, node.modifiers, nodeFactory.updateVariableDeclarationList(node.declarationList, declarationList));
}
function replaceInVariableDeclaration(node, { substitute }, nodeFactory) {
if (!ts.isExpression(substitute)) {
throw new UnsupportedModuleError(`Unexpected replacement type for VariableDeclaration (expected Expression): ` +
`${ts.SyntaxKind[substitute.kind]} at ${toPosStr(node)}`);
}
return nodeFactory.updateVariableDeclaration(node, node.name, node.exclamationToken, node.type, substitute);
}
function replaceInVariableDeclarationList(node, { original, substitute }, nodeFactory) {
const declarations = replaceNodeInArray(original, substitute, node.declarations);
return nodeFactory.updateVariableDeclarationList(node, declarations);
}
function replaceInPropertyAssignment(node, { substitute }, nodeFactory) {
if (!ts.isExpression(substitute)) {
throw new UnsupportedModuleError(`Unexpected replacement type for PropertyAssignment (expected Expression): ` +
`${ts.SyntaxKind[substitute.kind]} at ${toPosStr(node)}`);
}
return nodeFactory.updatePropertyAssignment(node, node.name, substitute);
}
function replaceInPropertyDeclaration(node, { substitute }, nodeFactory) {
if (!ts.isExpression(substitute)) {
throw new UnsupportedModuleError(`Unexpected replacement type for PropertyDeclaration (expected Expression): ` +
`${ts.SyntaxKind[substitute.kind]} at ${toPosStr(node)}`);
}
return nodeFactory.updatePropertyDeclaration(node, node.modifiers, node.name, node.questionToken ?? node.exclamationToken, node.type, substitute);
}
function replaceInIfStatement(node, { original, substitute }, nodeFactory) {
if (node.expression === original) {
// Replace expression
if (!ts.isExpression(substitute)) {
throw new UnsupportedModuleError(`Unexpected replacement type for IfStatement (expected Expression): ` +
`${ts.SyntaxKind[substitute.kind]} at ${toPosStr(node)}`);
}
return nodeFactory.updateIfStatement(node, substitute, node.thenStatement, node.elseStatement);
}
else if (node.thenStatement === original) {
// Replace statement
if (!ts.isStatement(substitute)) {
throw new UnsupportedModuleError(`Unexpected replacement type for IfStatement (expected Statement): ` +
`${ts.SyntaxKind[substitute.kind]} at ${toPosStr(node)}`);
}
return nodeFactory.updateIfStatement(node, node.expression, substitute, node.elseStatement);
}
else { // Must be elseStatement
// Replace statement
if (!ts.isStatement(substitute)) {
throw new UnsupportedModuleError(`Unexpected replacement type for IfStatement (expected Statement): ` +
`${ts.SyntaxKind[substitute.kind]} at ${toPosStr(node)}`);
}
return nodeFactory.updateIfStatement(node, node.expression, node.thenStatement, substitute);
}
}
function replaceInWhileStatement(node, { original, substitute }, nodeFactory) {
if (node.expression === original) {
// Replace expression
if (!ts.isExpression(substitute)) {
throw new UnsupportedModuleError(`Unexpected replacement type for WhileStatement (expected Expression): ` +
`${ts.SyntaxKind[substitute.kind]} at ${toPosStr(node)}`);
}
return nodeFactory.updateWhileStatement(node, substitute, node.statement);
}
else { // Must be statement
// Replace statement
if (!ts.isStatement(substitute)) {
throw new UnsupportedModuleError(`Unexpected replacement type for WhileStatement (expected Statement): ` +
`${ts.SyntaxKind[substitute.kind]} at ${toPosStr(node)}`);
}
return nodeFactory.updateWhileStatement(node, node.expression, substitute);
}
}
function replaceInDoStatement(node, { original, substitute }, nodeFactory) {
if (node.statement === original) {
// Replace statement
if (!ts.isStatement(substitute)) {
throw new UnsupportedModuleError(`Unexpected replacement type for DoStatement (expected Statement): ` +
`${ts.SyntaxKind[substitute.kind]} at ${toPosStr(node)}`);
}
return nodeFactory.updateDoStatement(node, substitute, node.expression);
}
else { // Must be expression
// Replace expression
if (!ts.isExpression(substitute)) {
throw new UnsupportedModuleError(`Unexpected replacement type for DoStatement (expected Expression): ` +
`${ts.SyntaxKind[substitute.kind]} at ${toPosStr(node)}`);
}
return nodeFactory.updateDoStatement(node, node.statement, substitute);
}
}
function replaceInForStatement(node, { original, substitute }, nodeFactory) {
if (node.initializer === original) {
// Replace initializer
if (!ts.isForInitializer(substitute)) {
throw new UnsupportedModuleError(`Unexpected replacement type for ForStatement (expected ForInitializer): ` +
`${ts.SyntaxKind[substitute.kind]} at ${toPosStr(node)}`);
}
return nodeFactory.updateForStatement(node, substitute, node.condition, node.incrementor, node.statement);
}
else if (node.condition === original) {
// Replace condition
if (!ts.isExpression(substitute)) {
throw new UnsupportedModuleError(`Unexpected replacement type for ForStatement (expected Expression): ` +
`${ts.SyntaxKind[substitute.kind]} at ${toPosStr(node)}`);
}
return nodeFactory.updateForStatement(node, node.initializer, substitute, node.incrementor, node.statement);
}
else if (node.incrementor === original) {
// Replace incrementor
if (!ts.isExpression(substitute)) {
throw new UnsupportedModuleError(`Unexpected replacement type for ForStatement (expected Expression): ` +
`${ts.SyntaxKind[substitute.kind]} at ${toPosStr(node)}`);
}
return nodeFactory.updateForStatement(node, node.initializer, node.condition, substitute, node.statement);
}
else { // Must be statement
// Replace statement
if (!ts.isStatement(substitute)) {
throw new UnsupportedModuleError(`Unexpected replacement type for ForStatement (expected Statement): ` +
`${ts.SyntaxKind[substitute.kind]} at ${toPosStr(node)}`);
}
return nodeFactory.updateForStatement(node, node.initializer, node.condition, node.incrementor, substitute);
}
}
function replaceInReturnStatement(node, { substitute }, nodeFactory) {
if (!ts.isExpression(substitute)) {
throw new UnsupportedModuleError(`Unexpected replacement type for ReturnStatement (expected Expression): ` +
`${ts.SyntaxKind[substitute.kind]} at ${toPosStr(node)}`);
}
return nodeFactory.updateReturnStatement(node, substitute);
}
function replaceInArrayLiteralExpression(node, { original, substitute }, nodeFactory) {
const elements = replaceNodeInArray(original, substitute, node.elements);
return nodeFactory.updateArrayLiteralExpression(node, elements);
}
function replaceInObjectLiteralExpression(node, { original, substitute }, nodeFactory) {
const properties = replaceNodeInArray(original, substitute, node.properties);
return nodeFactory.updateObjectLiteralExpression(node, properties);
}
function replaceInPropertyAccessExpression(node, { original, substitute }, nodeFactory) {
if (node.name === original) {
// Replace name
if (!ts.isIdentifier(substitute)) {
throw new UnsupportedModuleError(`Unexpected replacement type for PropertyAccessExpression (expected Identifier): ` +
`${ts.SyntaxKind[substitute.kind]} at ${toPosStr(node)}`);
}
return nodeFactory.updatePropertyAccessExpression(node, node.expression, substitute);
}
else {
if (!ts.isExpression(substitute)) {
throw new UnsupportedModuleError(`Unexpected replacement type for PropertyAccessExpression (expected Expression): ` +
`${ts.SyntaxKind[substitute.kind]} at ${toPosStr(node)}`);
}
return nodeFactory.updatePropertyAccessExpression(node, substitute, node.name);
}
}
function replaceInBlock(node, { original, substitute }, nodeFactory) {
const statements = replaceNodeInArray(original, substitute, node.statements);
return nodeFactory.updateBlock(node, statements);
}
function replaceInElementAccessExpression(node, { original, substitute }, nodeFactory) {
if (node.expression === original) {
if (!ts.isExpression(substitute)) {
throw new UnsupportedModuleError(`Unexpected replacement type for ElementAccessExpression (expected Expression): ` +
`${ts.SyntaxKind[substitute.kind]} at ${toPosStr(node)}`);
}
return nodeFactory.updateElementAccessExpression(node, substitute, node.argumentExpression);
}
else {
if (!ts.isExpression(substitute)) {
throw new UnsupportedModuleError(`Unexpected replacement type for ElementAccessExpression (expected Expression): ` +
`${ts.SyntaxKind[substitute.kind]} at ${toPosStr(node)}`);
}
return nodeFactory.updateElementAccessExpression(node, node.expression, substitute);
}
}
function replaceInArrowFunction(node, { substitute }, nodeFactory) {
if (!ts.isBlock(substitute) && !ts.isExpression(substitute)) {
throw new UnsupportedModuleError(`Unexpected replacement type for ArrowFunction (expected Block or Expression): ` +
`${ts.SyntaxKind[substitute.kind]} at ${toPosStr(node)}`);
}
return nodeFactory.updateArrowFunction(node, node.modifiers, node.typeParameters, node.parameters, node.type, node.equalsGreaterThanToken, substitute);
}
function replaceInFunctionExpression(node, { substitute }, nodeFactory) {
if (!ts.isBlock(substitute)) {
throw new UnsupportedModuleError(`Unexpected replacement type for FunctionExpression (expected Block): ` +
`${ts.SyntaxKind[substitute.kind]} at ${toPosStr(node)}`);
}
return nodeFactory.updateFunctionExpression(node, node.modifiers, node.asteriskToken, node.name, node.typeParameters, node.parameters, node.type, substitute);
}
function replaceInFunctionDeclaration(node, { substitute }, nodeFactory) {
if (!ts.isBlock(substitute)) {
throw new UnsupportedModuleError(`Unexpected replacement type for FunctionDeclaration (expected Block): ` +
`${ts.SyntaxKind[substitute.kind]} at ${toPosStr(node)}`);
}
return nodeFactory.updateFunctionDeclaration(node, node.modifiers, node.asteriskToken, node.name, node.typeParameters, node.parameters, node.type, substitute);
}
function replaceInMethodDeclaration(node, { substitute }, nodeFactory) {
if (!ts.isBlock(substitute)) {
throw new UnsupportedModuleError(`Unexpected replacement type for MethodDeclaration (expected Block): ` +
`${ts.SyntaxKind[substitute.kind]} at ${toPosStr(node)}`);
}
return nodeFactory.updateMethodDeclaration(node, node.modifiers, node.asteriskToken, node.name, node.questionToken, node.typeParameters, node.parameters, node.type, substitute);
}
function replaceInClassDeclaration(node, { original, substitute }, nodeFactory) {
if (node.heritageClauses?.includes(original)) {
if (!ts.isHeritageClause(substitute)) {
throw new UnsupportedModuleError(`Unexpected replacement type for ClassDeclaration (expected HeritageClause): ` +
`${ts.SyntaxKind[substitute.kind]} at ${toPosStr(node)}`);
}
const heritageClauses = replaceNodeInArray(original, substitute, node.heritageClauses);
return nodeFactory.updateClassDeclaration(node, node.modifiers, node.name, node.typeParameters, heritageClauses, node.members);
}
else if (node.members.includes(original)) {
if (!ts.isClassElement(substitute)) {
throw new UnsupportedModuleError(`Unexpected replacement type for ClassDeclaration (expected ClassElement): ` +
`${ts.SyntaxKind[substitute.kind]} at ${toPosStr(node)}`);
}
const members = replaceNodeInArray(original, substitute, node.members);
return nodeFactory.updateClassDeclaration(node, node.modifiers, node.name, node.typeParameters, node.heritageClauses, members);
}
else {
throw new UnsupportedModuleError(`Unexpected child node for ClassDeclaration replacement: ${ts.SyntaxKind[original.kind]} at ` +
`${toPosStr(original)}`);
}
}
function replaceInComputedPropertyName(node, { substitute }, nodeFactory) {
if (!ts.isExpression(substitute)) {
throw new UnsupportedModuleError(`Unexpected replacement type for ComputedPropertyName (expected Expression): ` +
`${ts.SyntaxKind[substitute.kind]} at ${toPosStr(node)}`);
}
return nodeFactory.updateComputedPropertyName(node, substitute);
}
function replaceInParameterDeclaration(node, { substitute }, nodeFactory) {
if (!ts.isExpression(substitute)) {
throw new UnsupportedModuleError(`Unexpected replacement type for ParameterDeclaration (expected Expression): ` +
`${ts.SyntaxKind[substitute.kind]} at ${toPosStr(node)}`);
}
return nodeFactory.updateParameterDeclaration(node, node.modifiers, node.dotDotDotToken, node.name, node.questionToken, node.type, substitute);
}
function replaceInSourceFile(node, { original, substitute }, nodeFactory) {
const statements = replaceNodeInArray(original, substitute, node.statements);
return nodeFactory.updateSourceFile(node, statements);
}
//# sourceMappingURL=replaceNodeInParent.js.map