|
@@ -20,9 +20,9 @@ import { NodeUtils } from '../../node/NodeUtils';
|
|
@injectable()
|
|
@injectable()
|
|
export class ObjectExpressionKeysTransformer extends AbstractNodeTransformer {
|
|
export class ObjectExpressionKeysTransformer extends AbstractNodeTransformer {
|
|
/**
|
|
/**
|
|
- * @type {Map<Node, TNodeWithScope>}
|
|
|
|
|
|
+ * @type {Map<ESTree.ObjectExpression, TNodeWithScope>}
|
|
*/
|
|
*/
|
|
- private readonly cachedScopeNodesMap: Map <ESTree.Node, TNodeWithScope> = new Map();
|
|
|
|
|
|
+ private readonly cachedObjectExpressionScopesMap: Map <ESTree.ObjectExpression, TNodeWithScope> = new Map();
|
|
|
|
|
|
/**
|
|
/**
|
|
* @param {IRandomGenerator} randomGenerator
|
|
* @param {IRandomGenerator} randomGenerator
|
|
@@ -35,30 +35,6 @@ export class ObjectExpressionKeysTransformer extends AbstractNodeTransformer {
|
|
super(randomGenerator, options);
|
|
super(randomGenerator, options);
|
|
}
|
|
}
|
|
|
|
|
|
- /**
|
|
|
|
- * @param {TNodeWithScope} scopeNode
|
|
|
|
- * @param {Node} hostNode
|
|
|
|
- * @param {ExpressionStatement[]} expressionStatements
|
|
|
|
- */
|
|
|
|
- private static appendExpressionStatements (
|
|
|
|
- scopeNode: TNodeWithScope,
|
|
|
|
- hostNode: ESTree.Node,
|
|
|
|
- expressionStatements: ESTree.ExpressionStatement[]
|
|
|
|
- ): void {
|
|
|
|
- const hostNodeScope: ESTree.Node = ObjectExpressionKeysTransformer.getHostStatement(hostNode);
|
|
|
|
-
|
|
|
|
- NodeAppender.insertNodeAfter(scopeNode, expressionStatements, hostNodeScope);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * @param {Property[]} properties
|
|
|
|
- * @param {number[]} removablePropertyIds
|
|
|
|
- * @returns {Property[]}
|
|
|
|
- */
|
|
|
|
- private static filterObjectExpressionProperties (properties: ESTree.Property[], removablePropertyIds: number[]): ESTree.Property[] {
|
|
|
|
- return properties.filter((property: ESTree.Property, index: number) => !removablePropertyIds.includes(index));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
/**
|
|
/**
|
|
* Returns host statement of object expression node
|
|
* Returns host statement of object expression node
|
|
*
|
|
*
|
|
@@ -92,7 +68,9 @@ export class ObjectExpressionKeysTransformer extends AbstractNodeTransformer {
|
|
|
|
|
|
if (NodeGuards.isLiteralNode(propertyKeyNode) && typeof propertyKeyNode.value === 'string') {
|
|
if (NodeGuards.isLiteralNode(propertyKeyNode) && typeof propertyKeyNode.value === 'string') {
|
|
return propertyKeyNode.value;
|
|
return propertyKeyNode.value;
|
|
- } else if (NodeGuards.isIdentifierNode(propertyKeyNode)) {
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (NodeGuards.isIdentifierNode(propertyKeyNode)) {
|
|
return propertyKeyNode.name;
|
|
return propertyKeyNode.name;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -100,14 +78,14 @@ export class ObjectExpressionKeysTransformer extends AbstractNodeTransformer {
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
- * @param {Expression | Pattern} propertyValueNode
|
|
|
|
- * @returns {propertyValueNode is Expression}
|
|
|
|
|
|
+ * @param {Node} node
|
|
|
|
+ * @returns {propertyValueNode is Pattern}
|
|
*/
|
|
*/
|
|
- private static isValidExpressionNode (propertyValueNode: ESTree.Expression | ESTree.Pattern): propertyValueNode is ESTree.Expression {
|
|
|
|
- return !NodeGuards.isObjectPatternNode(propertyValueNode)
|
|
|
|
- && !NodeGuards.isArrayPatternNode(propertyValueNode)
|
|
|
|
- && !NodeGuards.isAssignmentPatternNode(propertyValueNode)
|
|
|
|
- && !NodeGuards.isRestElementNode(propertyValueNode);
|
|
|
|
|
|
+ private static isProhibitedPattern (node: ESTree.Node): node is ESTree.Pattern {
|
|
|
|
+ return NodeGuards.isObjectPatternNode(node)
|
|
|
|
+ || NodeGuards.isArrayPatternNode(node)
|
|
|
|
+ || NodeGuards.isAssignmentPatternNode(node)
|
|
|
|
+ || NodeGuards.isRestElementNode(node);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -115,23 +93,21 @@ export class ObjectExpressionKeysTransformer extends AbstractNodeTransformer {
|
|
* @returns {IVisitor | null}
|
|
* @returns {IVisitor | null}
|
|
*/
|
|
*/
|
|
public getVisitor (transformationStage: TransformationStage): IVisitor | null {
|
|
public getVisitor (transformationStage: TransformationStage): IVisitor | null {
|
|
- switch (transformationStage) {
|
|
|
|
- case TransformationStage.Converting:
|
|
|
|
- return {
|
|
|
|
- enter: (node: ESTree.Node, parentNode: ESTree.Node | null) => {
|
|
|
|
- if (
|
|
|
|
- this.options.transformObjectKeys
|
|
|
|
- && parentNode
|
|
|
|
- && NodeGuards.isObjectExpressionNode(node)
|
|
|
|
- ) {
|
|
|
|
- return this.transformNode(node, parentNode);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- default:
|
|
|
|
- return null;
|
|
|
|
|
|
+ if (transformationStage !== TransformationStage.Converting) {
|
|
|
|
+ return null;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ return {
|
|
|
|
+ enter: (node: ESTree.Node, parentNode: ESTree.Node | null) => {
|
|
|
|
+ if (
|
|
|
|
+ this.options.transformObjectKeys
|
|
|
|
+ && parentNode
|
|
|
|
+ && NodeGuards.isObjectExpressionNode(node)
|
|
|
|
+ ) {
|
|
|
|
+ return this.transformNode(node, parentNode);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ };
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -151,86 +127,29 @@ export class ObjectExpressionKeysTransformer extends AbstractNodeTransformer {
|
|
* @returns {NodeGuards}
|
|
* @returns {NodeGuards}
|
|
*/
|
|
*/
|
|
public transformNode (objectExpressionNode: ESTree.ObjectExpression, parentNode: ESTree.Node): ESTree.Node {
|
|
public transformNode (objectExpressionNode: ESTree.ObjectExpression, parentNode: ESTree.Node): ESTree.Node {
|
|
- if (NodeGuards.isVariableDeclaratorNode(parentNode)) {
|
|
|
|
- return this.transformVariableDeclaratorHostObjectExpression(objectExpressionNode, parentNode);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (NodeGuards.isAssignmentExpressionNode(parentNode)) {
|
|
|
|
- return this.transformAssignmentExpressionHostObjectExpression(objectExpressionNode, parentNode);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return objectExpressionNode;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * @param {ObjectExpression} objectExpressionNode
|
|
|
|
- * @param {VariableDeclarator} variableDeclaratorNode
|
|
|
|
- * @returns {Node}
|
|
|
|
- */
|
|
|
|
- private transformVariableDeclaratorHostObjectExpression(
|
|
|
|
- objectExpressionNode: ESTree.ObjectExpression,
|
|
|
|
- variableDeclaratorNode: ESTree.VariableDeclarator
|
|
|
|
- ): ESTree.Node {
|
|
|
|
- // should pass only Expression nodes as MemberExpression.object value
|
|
|
|
- if (!NodeGuards.isIdentifierNode(variableDeclaratorNode.id)) {
|
|
|
|
|
|
+ if (!objectExpressionNode.properties.length) {
|
|
return objectExpressionNode;
|
|
return objectExpressionNode;
|
|
}
|
|
}
|
|
|
|
|
|
- const scopeNode: TNodeWithScope | null = NodeUtils.getScopeOfNode(variableDeclaratorNode);
|
|
|
|
-
|
|
|
|
- if (!scopeNode || !NodeGuards.isNodeHasScope(scopeNode)) {
|
|
|
|
- return objectExpressionNode;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- this.cachedScopeNodesMap.set(variableDeclaratorNode, scopeNode);
|
|
|
|
-
|
|
|
|
- return this.transformObjectExpressionNode(
|
|
|
|
- objectExpressionNode,
|
|
|
|
- variableDeclaratorNode.id,
|
|
|
|
- variableDeclaratorNode
|
|
|
|
- );
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * @param {ObjectExpression} objectExpressionNode
|
|
|
|
- * @param {AssignmentExpression} assignmentExpressionNode
|
|
|
|
- * @returns {Node}
|
|
|
|
- */
|
|
|
|
- private transformAssignmentExpressionHostObjectExpression(
|
|
|
|
- objectExpressionNode: ESTree.ObjectExpression,
|
|
|
|
- assignmentExpressionNode: ESTree.AssignmentExpression
|
|
|
|
- ): ESTree.Node {
|
|
|
|
- const leftNode: ESTree.MemberExpression | ESTree.Pattern = assignmentExpressionNode.left;
|
|
|
|
-
|
|
|
|
- if (!ObjectExpressionKeysTransformer.isValidExpressionNode(leftNode)) {
|
|
|
|
- return objectExpressionNode;
|
|
|
|
|
|
+ if (NodeGuards.isVariableDeclaratorNode(parentNode)) {
|
|
|
|
+ return this.transformWithVariableDeclaratorHost(objectExpressionNode, parentNode);
|
|
}
|
|
}
|
|
|
|
|
|
- const scopeNode: TNodeWithScope | null = NodeUtils.getScopeOfNode(assignmentExpressionNode);
|
|
|
|
-
|
|
|
|
- if (!scopeNode || !NodeGuards.isNodeHasScope(scopeNode)) {
|
|
|
|
- return objectExpressionNode;
|
|
|
|
|
|
+ if (NodeGuards.isAssignmentExpressionNode(parentNode)) {
|
|
|
|
+ return this.transformWithAssignmentExpressionHost(objectExpressionNode, parentNode);
|
|
}
|
|
}
|
|
|
|
|
|
- this.cachedScopeNodesMap.set(assignmentExpressionNode, scopeNode);
|
|
|
|
-
|
|
|
|
- return this.transformObjectExpressionNode(
|
|
|
|
- objectExpressionNode,
|
|
|
|
- leftNode,
|
|
|
|
- assignmentExpressionNode
|
|
|
|
- );
|
|
|
|
|
|
+ return objectExpressionNode;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
* @param {Property[]} properties
|
|
* @param {Property[]} properties
|
|
- * @param {Expression} memberExpressionObject
|
|
|
|
- * @param {Node} hostNode
|
|
|
|
|
|
+ * @param {Expression} memberExpressionHostNode
|
|
* @returns {[ExpressionStatement[] , number[]]}
|
|
* @returns {[ExpressionStatement[] , number[]]}
|
|
*/
|
|
*/
|
|
private extractPropertiesToExpressionStatements (
|
|
private extractPropertiesToExpressionStatements (
|
|
properties: ESTree.Property[],
|
|
properties: ESTree.Property[],
|
|
- memberExpressionObject: ESTree.Expression,
|
|
|
|
- hostNode: ESTree.Node
|
|
|
|
|
|
+ memberExpressionHostNode: ESTree.Expression
|
|
): [ESTree.ExpressionStatement[], number[]] {
|
|
): [ESTree.ExpressionStatement[], number[]] {
|
|
const propertiesLength: number = properties.length;
|
|
const propertiesLength: number = properties.length;
|
|
const expressionStatements: ESTree.ExpressionStatement[] = [];
|
|
const expressionStatements: ESTree.ExpressionStatement[] = [];
|
|
@@ -241,7 +160,7 @@ export class ObjectExpressionKeysTransformer extends AbstractNodeTransformer {
|
|
const propertyValue: ESTree.Expression | ESTree.Pattern = property.value;
|
|
const propertyValue: ESTree.Expression | ESTree.Pattern = property.value;
|
|
|
|
|
|
// invalid property nodes
|
|
// invalid property nodes
|
|
- if (!ObjectExpressionKeysTransformer.isValidExpressionNode(propertyValue)) {
|
|
|
|
|
|
+ if (ObjectExpressionKeysTransformer.isProhibitedPattern(propertyValue)) {
|
|
continue;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -263,7 +182,7 @@ export class ObjectExpressionKeysTransformer extends AbstractNodeTransformer {
|
|
? NodeFactory.literalNode(propertyKeyName)
|
|
? NodeFactory.literalNode(propertyKeyName)
|
|
: NodeFactory.identifierNode(propertyKeyName);
|
|
: NodeFactory.identifierNode(propertyKeyName);
|
|
const memberExpressionNode: ESTree.MemberExpression = NodeFactory
|
|
const memberExpressionNode: ESTree.MemberExpression = NodeFactory
|
|
- .memberExpressionNode(memberExpressionObject, memberExpressionProperty, true);
|
|
|
|
|
|
+ .memberExpressionNode(memberExpressionHostNode, memberExpressionProperty, true);
|
|
const expressionStatementNode: ESTree.ExpressionStatement = NodeFactory.expressionStatementNode(
|
|
const expressionStatementNode: ESTree.ExpressionStatement = NodeFactory.expressionStatementNode(
|
|
NodeFactory.assignmentExpressionNode('=', memberExpressionNode, propertyValue)
|
|
NodeFactory.assignmentExpressionNode('=', memberExpressionNode, propertyValue)
|
|
);
|
|
);
|
|
@@ -272,7 +191,7 @@ export class ObjectExpressionKeysTransformer extends AbstractNodeTransformer {
|
|
* Stage 3: recursively processing nested object expressions
|
|
* Stage 3: recursively processing nested object expressions
|
|
*/
|
|
*/
|
|
if (NodeGuards.isObjectExpressionNode(property.value)) {
|
|
if (NodeGuards.isObjectExpressionNode(property.value)) {
|
|
- this.transformObjectExpressionNode(property.value, memberExpressionNode, hostNode);
|
|
|
|
|
|
+ this.transformObjectExpressionNode(property.value, memberExpressionNode);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -287,34 +206,81 @@ export class ObjectExpressionKeysTransformer extends AbstractNodeTransformer {
|
|
|
|
|
|
/**
|
|
/**
|
|
* @param {ObjectExpression} objectExpressionNode
|
|
* @param {ObjectExpression} objectExpressionNode
|
|
- * @param {Expression} memberExpressionObjectNode
|
|
|
|
- * @param {Node} hostNode
|
|
|
|
|
|
+ * @returns {TNodeWithScope}
|
|
|
|
+ */
|
|
|
|
+ private getScopeNode (objectExpressionNode: ESTree.ObjectExpression): TNodeWithScope {
|
|
|
|
+ if (this.cachedObjectExpressionScopesMap.has(objectExpressionNode)) {
|
|
|
|
+ return <TNodeWithScope>this.cachedObjectExpressionScopesMap.get(objectExpressionNode);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const scopeNode: TNodeWithScope = NodeUtils.getScopeOfNode(objectExpressionNode);
|
|
|
|
+
|
|
|
|
+ this.cachedObjectExpressionScopesMap.set(objectExpressionNode, scopeNode);
|
|
|
|
+
|
|
|
|
+ return scopeNode;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * @param {ObjectExpression} objectExpressionNode
|
|
|
|
+ * @param {VariableDeclarator} hostNode
|
|
* @returns {Node}
|
|
* @returns {Node}
|
|
*/
|
|
*/
|
|
- private transformObjectExpressionNode (
|
|
|
|
|
|
+ private transformWithVariableDeclaratorHost (
|
|
objectExpressionNode: ESTree.ObjectExpression,
|
|
objectExpressionNode: ESTree.ObjectExpression,
|
|
- memberExpressionObjectNode: ESTree.Expression,
|
|
|
|
- hostNode: ESTree.Node
|
|
|
|
|
|
+ hostNode: ESTree.VariableDeclarator
|
|
): ESTree.Node {
|
|
): ESTree.Node {
|
|
- const properties: ESTree.Property[] = objectExpressionNode.properties;
|
|
|
|
-
|
|
|
|
- if (!properties.length) {
|
|
|
|
|
|
+ // should pass only Expression nodes as MemberExpression.object value
|
|
|
|
+ if (!NodeGuards.isIdentifierNode(hostNode.id)) {
|
|
return objectExpressionNode;
|
|
return objectExpressionNode;
|
|
}
|
|
}
|
|
|
|
|
|
- const scopeNode: TNodeWithScope | undefined = this.cachedScopeNodesMap.get(hostNode);
|
|
|
|
|
|
+ return this.transformObjectExpressionNode(
|
|
|
|
+ objectExpressionNode,
|
|
|
|
+ hostNode.id
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * @param {ObjectExpression} objectExpressionNode
|
|
|
|
+ * @param {AssignmentExpression} hostNode
|
|
|
|
+ * @returns {Node}
|
|
|
|
+ */
|
|
|
|
+ private transformWithAssignmentExpressionHost (
|
|
|
|
+ objectExpressionNode: ESTree.ObjectExpression,
|
|
|
|
+ hostNode: ESTree.AssignmentExpression
|
|
|
|
+ ): ESTree.Node {
|
|
|
|
+ const leftNode: ESTree.MemberExpression | ESTree.Pattern = hostNode.left;
|
|
|
|
|
|
- if (!scopeNode) {
|
|
|
|
|
|
+ // left node shouldn't be as Pattern node
|
|
|
|
+ if (ObjectExpressionKeysTransformer.isProhibitedPattern(leftNode)) {
|
|
return objectExpressionNode;
|
|
return objectExpressionNode;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ return this.transformObjectExpressionNode(
|
|
|
|
+ objectExpressionNode,
|
|
|
|
+ leftNode
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * @param {ObjectExpression} objectExpressionNode
|
|
|
|
+ * @param {Expression} memberExpressionHostNode
|
|
|
|
+ * @returns {Node}
|
|
|
|
+ */
|
|
|
|
+ private transformObjectExpressionNode (
|
|
|
|
+ objectExpressionNode: ESTree.ObjectExpression,
|
|
|
|
+ memberExpressionHostNode: ESTree.Expression
|
|
|
|
+ ): ESTree.Node {
|
|
|
|
+ const properties: ESTree.Property[] = objectExpressionNode.properties;
|
|
const [expressionStatements, removablePropertyIds]: [ESTree.ExpressionStatement[], number[]] = this
|
|
const [expressionStatements, removablePropertyIds]: [ESTree.ExpressionStatement[], number[]] = this
|
|
- .extractPropertiesToExpressionStatements(properties, memberExpressionObjectNode, hostNode);
|
|
|
|
|
|
+ .extractPropertiesToExpressionStatements(properties, memberExpressionHostNode);
|
|
|
|
+ const hostStatement: ESTree.Statement = ObjectExpressionKeysTransformer.getHostStatement(objectExpressionNode);
|
|
|
|
+ const scopeNode: TNodeWithScope = this.getScopeNode(objectExpressionNode);
|
|
|
|
|
|
- objectExpressionNode.properties = ObjectExpressionKeysTransformer
|
|
|
|
- .filterObjectExpressionProperties(properties, removablePropertyIds);
|
|
|
|
- ObjectExpressionKeysTransformer
|
|
|
|
- .appendExpressionStatements(scopeNode, objectExpressionNode, expressionStatements);
|
|
|
|
|
|
+ objectExpressionNode.properties = properties.filter((property: ESTree.Property, index: number) =>
|
|
|
|
+ !removablePropertyIds.includes(index)
|
|
|
|
+ );
|
|
|
|
+ NodeAppender.insertAfter(scopeNode, expressionStatements, hostStatement);
|
|
|
|
|
|
return objectExpressionNode;
|
|
return objectExpressionNode;
|
|
}
|
|
}
|