in tools/hermes-parser/js/hermes-transform/src/transform/mutations/RemoveNode.js [77:259]
function getRemovalParent(node: RemoveNodeMutation['node']): $ReadOnly<{
type: 'array',
parent: ESNode,
key: string,
targetIndex: number,
}> {
const key = ((): string => {
function getErrorMessage(expectedParents: $ReadOnlyArray<string>): string {
return `Tried to remove ${node.type} from parent of type ${
node.parent.type
}.\nHowever ${
node.type
} can only be safely removed from parent of type ${expectedParents.join(
' | ',
)}.`;
}
function assertParent(expectedParents_: string | $ReadOnlyArray<string>) {
const expectedParents =
typeof expectedParents_ === 'string'
? [expectedParents_]
: expectedParents_;
if (!expectedParents.includes(node.parent.type)) {
return new InvalidRemovalError(getErrorMessage(expectedParents));
}
}
switch (node.type) {
// ClassMember
case 'ClassProperty':
case 'ClassPrivateProperty':
case 'MethodDefinition':
assertParent('ClassBody');
return 'body';
case 'EnumBooleanMember':
case 'EnumDefaultedMember':
case 'EnumNumberMember':
case 'EnumStringMember':
assertParent(VALID_ENUM_MEMBER_PARENTS);
return 'members';
// FunctionParameter
case 'AssignmentPattern':
case 'ArrayPattern':
case 'ObjectPattern':
assertParent(VALID_FUNCTION_PARAMETER_PARENTS);
return 'params';
case 'FunctionTypeParam':
assertParent('FunctionTypeAnnotation');
return 'params';
case 'ObjectTypeCallProperty':
assertParent('ObjectTypeAnnotation');
return 'callProperties';
case 'ObjectTypeIndexer':
assertParent('ObjectTypeAnnotation');
return 'indexers';
case 'ObjectTypeInternalSlot':
assertParent('ObjectTypeAnnotation');
return 'internalSlots';
case 'ObjectTypeProperty':
case 'ObjectTypeSpreadProperty':
assertParent('ObjectTypeAnnotation');
return 'properties';
case 'Property':
assertParent(VALID_PROPERTY_PARENTS);
return 'properties';
// Identifier can be the child of a number of usecases
case 'Identifier':
switch (node.parent.type) {
case 'ArrowFunctionExpression':
case 'FunctionDeclaration':
case 'FunctionExpression':
return 'params';
case 'ArrayExpression':
case 'ArrayPattern':
return 'elements';
default:
throw new InvalidRemovalError(
getErrorMessage([
'ArrowFunctionExpression',
'FunctionDeclaration',
'FunctionExpression',
'ArrayExpression',
'ArrayPattern',
]),
);
}
// RestElement can be the child of a number of usecases
case 'RestElement':
switch (node.parent.type) {
case 'ArrowFunctionExpression':
case 'FunctionDeclaration':
case 'FunctionExpression':
return 'params';
case 'ArrayPattern':
return 'elements';
case 'ObjectPattern':
return 'properties';
case 'CallExpression':
case 'OptionalCallExpression':
case 'NewExpression':
return 'arguments';
default:
throw new InvalidRemovalError(
getErrorMessage([
'ArrowFunctionExpression',
'FunctionDeclaration',
'FunctionExpression',
'ArrayPattern',
'ObjectPattern',
'CallExpression',
'OptionalCallExpression',
'NewExpression',
]),
);
}
// SpreadElement can be the child of a number of usecases
case 'SpreadElement':
switch (node.parent.type) {
case 'ArrayExpression':
return 'elements';
case 'ObjectExpression':
return 'properties';
case 'CallExpression':
case 'OptionalCallExpression':
case 'NewExpression':
return 'arguments';
default:
throw new InvalidRemovalError(
getErrorMessage([
'ArrayExpression',
'ObjectExpression',
'CallExpression',
'OptionalCallExpression',
'NewExpression',
]),
);
}
default:
throw new InvalidRemovalError(
`Cannot perform a remove mutation on node of type ${node.type}`,
);
}
})();
const targetIndex = (() => {
// $FlowExpectedError[prop-missing]
const arr = node.parent[key];
const idx = arr.indexOf(node);
if (idx === -1) {
throw new InvalidRemovalError(
`Could not find target in array of \`${parent.type}.${key}\`.`,
);
}
return idx;
})();
return {
type: 'array',
parent: node.parent,
key,
targetIndex,
};
}