Skip to content

Commit

Permalink
CHORE: Remove cyclic dependencies within expression evaluation (#1144)
Browse files Browse the repository at this point in the history
  • Loading branch information
at-nathan authored Mar 16, 2022
1 parent 2ad385c commit 5a5ab2e
Show file tree
Hide file tree
Showing 18 changed files with 96 additions and 93 deletions.
6 changes: 3 additions & 3 deletions packages/babel-plugin/src/utils/css-builders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ const extractConditionalExpression = (node: t.ConditionalExpression, meta: Metad
) {
cssOutput = buildCss(pathNode, meta);
} else if (t.isIdentifier(pathNode)) {
const resolved = resolveBinding(pathNode.name, meta);
const resolved = resolveBinding(pathNode.name, meta, evaluateExpression);

if (
resolved &&
Expand Down Expand Up @@ -522,7 +522,7 @@ const extractObjectExpression = (node: t.ObjectExpression, meta: Metadata): CSSO
let resolvedBinding = undefined;

if (t.isIdentifier(prop.argument)) {
resolvedBinding = resolveBinding(prop.argument.name, meta);
resolvedBinding = resolveBinding(prop.argument.name, meta, evaluateExpression);

if (!resolvedBinding) {
throw buildCodeFrameError('Variable could not be found', prop.argument, meta.parentPath);
Expand Down Expand Up @@ -708,7 +708,7 @@ export const buildCss = (node: t.Expression | t.Expression[], meta: Metadata): C
}

if (t.isIdentifier(node)) {
const resolvedBinding = resolveBinding(node.name, meta);
const resolvedBinding = resolveBinding(node.name, meta, evaluateExpression);

if (!resolvedBinding) {
throw buildCodeFrameError('Variable could not be found', node, meta.parentPath);
Expand Down
20 changes: 16 additions & 4 deletions packages/babel-plugin/src/utils/evaluate-expression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,13 +134,25 @@ export const evaluateExpression = (
// --------------

if (t.isIdentifier(expression)) {
({ value, meta: updatedMeta } = traverseIdentifier(expression, updatedMeta));
({ value, meta: updatedMeta } = traverseIdentifier(
expression,
updatedMeta,
evaluateExpression
));
} else if (t.isMemberExpression(expression)) {
({ value, meta: updatedMeta } = traverseMemberExpression(expression, updatedMeta));
({ value, meta: updatedMeta } = traverseMemberExpression(
expression,
updatedMeta,
evaluateExpression
));
} else if (t.isFunction(expression)) {
({ value, meta: updatedMeta } = traverseFunction(expression, updatedMeta));
({ value, meta: updatedMeta } = traverseFunction(expression, updatedMeta, evaluateExpression));
} else if (t.isCallExpression(expression)) {
({ value, meta: updatedMeta } = traverseCallExpression(expression, updatedMeta));
({ value, meta: updatedMeta } = traverseCallExpression(
expression,
updatedMeta,
evaluateExpression
));
} else if (t.isBinaryExpression(expression)) {
({ value, meta: updatedMeta } = traverseBinaryExpression(
expression,
Expand Down
26 changes: 17 additions & 9 deletions packages/babel-plugin/src/utils/resolve-binding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@ import resolve from 'resolve';
import { DEFAULT_CODE_EXTENSIONS } from '../constants';
import type { Metadata } from '../types';

import { traverseMemberExpression } from './traverse-expression';
import { getDefaultExport, getNamedExport } from './traversers';
import type { PartialBindingWithMeta } from './types';
import type { PartialBindingWithMeta, EvaluateExpression } from './types';

/**
* Will recursively checks if identifier name is coming from destructuring. If yes,
Expand Down Expand Up @@ -80,7 +79,8 @@ export const resolveIdentifierComingFromDestructuring = ({
const resolveObjectPatternValueNode = (
expression: t.Expression,
meta: Metadata,
referenceName: string
referenceName: string,
evaluateExpression: EvaluateExpression
): t.Node | undefined => {
let objectPatternValueNode: t.Node | undefined = undefined;

Expand All @@ -98,9 +98,14 @@ const resolveObjectPatternValueNode = (
},
});
} else if (t.isMemberExpression(expression) && t.isMemberExpression(expression.object)) {
const { value: node, meta: updatedMeta } = traverseMemberExpression(expression, meta);
const { value: node, meta: updatedMeta } = evaluateExpression(expression, meta);

objectPatternValueNode = resolveObjectPatternValueNode(node, updatedMeta, referenceName);
objectPatternValueNode = resolveObjectPatternValueNode(
node,
updatedMeta,
referenceName,
evaluateExpression
);
} else if (
t.isIdentifier(expression) ||
(t.isMemberExpression(expression) && t.isIdentifier(expression.object))
Expand All @@ -109,7 +114,7 @@ const resolveObjectPatternValueNode = (
? expression.name
: (expression.object as t.Identifier).name;

const resolvedBinding = resolveBinding(name, meta);
const resolvedBinding = resolveBinding(name, meta, evaluateExpression);

if (resolvedBinding) {
const isResolvedToSameNode = resolvedBinding.path.node === expression;
Expand All @@ -122,7 +127,8 @@ const resolveObjectPatternValueNode = (
objectPatternValueNode = resolveObjectPatternValueNode(
resolvedBinding.node,
meta,
referenceName
referenceName,
evaluateExpression
);
}
}
Expand Down Expand Up @@ -240,7 +246,8 @@ const getModuleImportSource = (path: Binding['path']): string => {
*/
export const resolveBinding = (
referenceName: string,
meta: Metadata
meta: Metadata,
evaluateExpression: EvaluateExpression
): PartialBindingWithMeta | undefined => {
const binding = getBinding(referenceName, meta);

Expand All @@ -257,7 +264,8 @@ export const resolveBinding = (
node = resolveObjectPatternValueNode(
node,
meta,
getDestructuredObjectPatternKey(binding.path.node.id, referenceName)
getDestructuredObjectPatternKey(binding.path.node.id, referenceName),
evaluateExpression
) as t.Node;
}

Expand Down
17 changes: 0 additions & 17 deletions packages/babel-plugin/src/utils/traverse-access-path/types.ts

This file was deleted.

8 changes: 4 additions & 4 deletions packages/babel-plugin/src/utils/traverse-expression/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export { traverseBinaryExpression } from './traverse-binary-expression';
export * from './traverse-function';
export * from './traverse-call-expression';
export * from './traverse-identifier';
export * from './traverse-member-expression';
export { traverseFunction } from './traverse-function';
export { traverseCallExpression } from './traverse-call-expression';
export { traverseIdentifier } from './traverse-identifier';
export { traverseMemberExpression } from './traverse-member-expression';
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,7 @@ import * as t from '@babel/types';

import type { Metadata } from '../../types';
import { createResultPair } from '../create-result-pair';

type EvaluateExpression = (
expression: t.Expression,
meta: Metadata
) => ReturnType<typeof createResultPair>;
import type { EvaluateExpression } from '../types';

const hasNumericValue = (expression: t.Expression): boolean =>
t.isNumericLiteral(expression) ||
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@ import * as t from '@babel/types';
import type { Metadata } from '../../types';
import { getPathOfNode, wrapNodeInIIFE } from '../ast';
import { createResultPair } from '../create-result-pair';
import { evaluateExpression } from '../evaluate-expression';
import { resolveBinding } from '../resolve-binding';

import { traverseMemberExpression } from './traverse-member-expression';
import type { EvaluateExpression } from '../types';

/**
* Will find the function node for the call expression and wrap an IIFE around it (to avoid name collision)
Expand All @@ -19,7 +17,8 @@ import { traverseMemberExpression } from './traverse-member-expression';
*/
export const traverseCallExpression = (
expression: t.CallExpression,
meta: Metadata
meta: Metadata,
evaluateExpression: EvaluateExpression
): ReturnType<typeof createResultPair> => {
const callee = expression.callee;
let value: t.Node | undefined | null = undefined;
Expand Down Expand Up @@ -51,7 +50,7 @@ export const traverseCallExpression = (
// Right now we are only supported these 2 flavors. If we have complex case like `func('arg').fn().variable`,
// it will not get evaluated.
if (t.isIdentifier(callee)) {
const resolvedBinding = resolveBinding(callee.name, updatedMeta);
const resolvedBinding = resolveBinding(callee.name, updatedMeta, evaluateExpression);

if (resolvedBinding && resolvedBinding.constant) {
functionNode = resolvedBinding.node;
Expand All @@ -61,7 +60,7 @@ export const traverseCallExpression = (
// the functions arguments
callee.property = t.callExpression(callee.property, expression.arguments);

return traverseMemberExpression(callee, updatedMeta);
return evaluateExpression(callee, updatedMeta);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as t from '@babel/types';

import type { Metadata } from '../../types';
import { createResultPair } from '../create-result-pair';
import { evaluateExpression } from '../evaluate-expression';
import type { EvaluateExpression } from '../types';

/**
* Will look in an expression and return the actual value along with updated metadata.
Expand All @@ -17,7 +17,8 @@ import { evaluateExpression } from '../evaluate-expression';
*/
export const traverseFunction = (
expression: t.Function,
meta: Metadata
meta: Metadata,
evaluateExpression: EvaluateExpression
): ReturnType<typeof createResultPair> => {
let value: t.Node | undefined | null = undefined;
let updatedMeta: Metadata = meta;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import type * as t from '@babel/types';

import type { Metadata } from '../../types';
import { createResultPair } from '../create-result-pair';
import { evaluateExpression } from '../evaluate-expression';
import { resolveBinding } from '../resolve-binding';
import type { EvaluateExpression } from '../types';

/**
* Will look in an expression and return the actual value along with updated metadata.
Expand All @@ -16,12 +16,13 @@ import { resolveBinding } from '../resolve-binding';
*/
export const traverseIdentifier = (
expression: t.Identifier,
meta: Metadata
meta: Metadata,
evaluateExpression: EvaluateExpression
): ReturnType<typeof createResultPair> => {
let value: t.Node | undefined | null = undefined;
let updatedMeta: Metadata = meta;

const resolvedBinding = resolveBinding(expression.name, updatedMeta);
const resolvedBinding = resolveBinding(expression.name, updatedMeta, evaluateExpression);

if (resolvedBinding && resolvedBinding.constant && resolvedBinding.node) {
// We recursively call get interpolation until it not longer returns an identifier or member expression
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import traverse from '@babel/traverse';
import * as t from '@babel/types';

import type { Metadata } from '../../types';
import { createResultPair } from '../create-result-pair';
import { traverseMemberAccessPath } from '../traverse-access-path';
import type { Metadata } from '../../../types';
import { createResultPair } from '../../create-result-pair';
import type { EvaluateExpression } from '../../types';

import { traverseMemberAccessPath } from './traverse-access-path';

/**
* Returns the binding identifier for a member expression.
Expand Down Expand Up @@ -77,7 +79,8 @@ const getMemberExpressionMeta = (
*/
export const traverseMemberExpression = (
expression: t.MemberExpression,
meta: Metadata
meta: Metadata,
evaluateExpression: EvaluateExpression
): ReturnType<typeof createResultPair> => {
const { accessPath, bindingIdentifier } = getMemberExpressionMeta(expression);

Expand All @@ -88,7 +91,7 @@ export const traverseMemberExpression = (
bindingIdentifier.name,
accessPath,
expression,
traverseMemberExpression
evaluateExpression
);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as t from '@babel/types';

import type { Metadata } from '../../../types';
import { createResultPair } from '../../create-result-pair';
import type { Metadata } from '../../../../../types';
import { createResultPair } from '../../../../create-result-pair';

import { evaluateNamespaceImportPath } from './namespace-import';
import { evaluateObjectPath } from './object';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import * as t from '@babel/types';

import type { Metadata } from '../../../types';
import { createResultPair } from '../../create-result-pair';
import { getDefaultExport, getNamedExport } from '../../traversers';
import type { Metadata } from '../../../../../types';
import { createResultPair } from '../../../../create-result-pair';
import { getDefaultExport, getNamedExport } from '../../../../traversers';

export const evaluateNamespaceImportPath = (
expression: t.Expression,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type * as t from '@babel/types';

import type { Metadata } from '../../../types';
import { createResultPair } from '../../create-result-pair';
import { getObjectPropertyValue } from '../../traversers';
import type { Metadata } from '../../../../../types';
import { createResultPair } from '../../../../create-result-pair';
import { getObjectPropertyValue } from '../../../../traversers';

export const evaluateObjectPath = (
expression: t.ObjectExpression,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,26 @@
import type * as t from '@babel/types';

import type { Metadata } from '../../types';
import { createResultPair } from '../create-result-pair';
import { traverseCallExpression } from '../traverse-expression';
import type { Metadata } from '../../../../types';
import { createResultPair } from '../../../create-result-pair';
import type { EvaluateExpression } from '../../../types';

import { evaluatePath } from './evaluate-path';
import { resolveExpressionInMember } from './resolve-expression';
import type { TraverseHandlers, traverseMemberExpressionHandler } from './types';

export const traverseMemberAccessPath = (
expression: t.Expression,
meta: Metadata,
expressionName: string,
accessPath: t.Identifier[],
memberExpression: t.MemberExpression,
traverseMemberExpression: traverseMemberExpressionHandler
evaluateExpression: EvaluateExpression
): ReturnType<typeof createResultPair> => {
const traversers: TraverseHandlers = {
callExpression: traverseCallExpression,
memberExpression: traverseMemberExpression,
};
const { value: resolvedExpression, meta: updatedMeta } = resolveExpressionInMember(
expression,
meta,
expressionName,
memberExpression,
traversers
evaluateExpression
);

if (accessPath.length) {
Expand All @@ -38,7 +33,7 @@ export const traverseMemberAccessPath = (
pathName,
accessPath.slice(1),
memberExpression,
traverseMemberExpression
evaluateExpression
);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import type * as t from '@babel/types';

import type { Metadata } from '../../../types';
import { createResultPair } from '../../create-result-pair';
import { resolveBinding } from '../../resolve-binding';
import type { Metadata } from '../../../../../types';
import { createResultPair } from '../../../../create-result-pair';
import { resolveBinding } from '../../../../resolve-binding';
import type { EvaluateExpression } from '../../../../types';

export const evaluateIdentifier = (
expression: t.Identifier,
meta: Metadata
meta: Metadata,
evaluateExpression: EvaluateExpression
): ReturnType<typeof createResultPair> => {
const { name } = expression;
const resolvedBinding = resolveBinding(name, meta);
const resolvedBinding = resolveBinding(name, meta, evaluateExpression);

if (resolvedBinding) {
const { constant, node, meta: updatedMeta } = resolvedBinding;
Expand Down
Loading

0 comments on commit 5a5ab2e

Please sign in to comment.