@babel/traverse#Scope TypeScript Examples

The following examples show how to use @babel/traverse#Scope. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: extractMachines.ts    From xstate-codegen with MIT License 6 votes vote down vote up
getReferencePathsByImportName = (
  scope: Scope,
  imports: UsedImport[],
): ReferencePathsByImportName | undefined => {
  let shouldExit = false;
  let hasReferences = false;
  const referencePathsByImportName = imports.reduce(
    (byName, { importedName, localName }) => {
      let binding = scope.getBinding(localName);
      if (!binding) {
        shouldExit = true;
        return byName;
      }
      byName[importedName] = binding.referencePaths;
      hasReferences = hasReferences || Boolean(byName[importedName].length);
      return byName;
    },
    {} as ReferencePathsByImportName,
  );

  if (!hasReferences || shouldExit) {
    return;
  }

  return referencePathsByImportName;
}
Example #2
Source File: createStatementUpdater.ts    From vidact with MIT License 6 votes vote down vote up
export function createStatementUpdater(
  statement: NodePath | t.Statement,
  scope: Scope | t.Identifier,
  name = STATEMENT_EXECUTER_VAR
): [t.VariableDeclaration, t.ExpressionStatement, t.Identifier] {
  const uid = t.isIdentifier(scope) ? scope : scope.generateUidIdentifier(name);
  const node = "node" in statement ? statement.node : statement;
  const block = t.isBlockStatement(node)
    ? node
    : t.blockStatement([node as t.Statement]);

  const nodeToReplace = t.variableDeclaration("const", [
    t.variableDeclarator(uid, t.arrowFunctionExpression([], block))
  ]);
  const callExpression = t.expressionStatement(t.callExpression(uid, []));

  return [nodeToReplace, callExpression, uid];
}
Example #3
Source File: getImpactfulIdentifiers.ts    From vidact with MIT License 5 votes vote down vote up
export function getImpactfulIdentifiers(
  node: t.Node,
  scope: Scope,
  parentPath: NodePath
) {
  const impactfulIdentifiers: [DependencyType, string][] = [];
  if (t.isIdentifier(node) && !isElementVar(node.name)) {
    impactfulIdentifiers.push(["local", node.name]);
  }

  traverse(
    node,
    {
      Identifier(p) {
        if (t.isMemberExpression(p.container)) {
          const parentNode = p.container as t.MemberExpression;
          if (t.isIdentifier(parentNode.object)) {
            if (p.node.name !== PROP_VAR) {
              if (parentNode.object.name === PROP_VAR) {
                impactfulIdentifiers.push(["prop", parentNode.property.name]);
              } else if (
                parentNode.object.name === p.node.name &&
                p.node.name !== "Object" &&
                !isElementVar(p.node.name)
              ) {
                impactfulIdentifiers.push(["local", p.node.name]);
              }
            }
          }
        } else {
          if (t.isCallExpression(p.container)) {
            const parentNode = p.container as t.CallExpression;
            if (
              t.isIdentifier(parentNode.callee) &&
              parentNode.callee.name === "addPropTransaction"
            ) {
              return;
            }
          }

          if (
            t.isObjectProperty(p.container) ||
            (parentPath.scope !== p.scope &&
              !parentPath.scope.hasBinding(p.node.name))
          ) {
            p.skip();
          } else if (!isElementVar(p.node.name)) {
            impactfulIdentifiers.push(["local", p.node.name]);
          }
        }
      }
    },
    scope,
    {},
    parentPath
  );

  return impactfulIdentifiers;
}
Example #4
Source File: visitJSXElement.ts    From vidact with MIT License 4 votes vote down vote up
export function shallowTraverseJSXElement(
  element:
    | t.JSXText
    | t.JSXExpressionContainer
    | t.JSXSpreadChild
    | t.JSXElement
    | t.JSXFragment
    | t.JSXEmptyExpression,
  state: JSXState,
  scope: Scope,
  namePrefix = ELEMENT_VAR,
  shouldTrim: 0 | typeof LEFT | typeof RIGHT = 0
) {
  const identifier = scope.generateUidIdentifier(namePrefix);

  switch (element.type) {
    case "JSXElement":
      const tagIdentifier = element.openingElement.name as t.JSXIdentifier;
      let children = element.children
        .map((child, i) => {
          const shouldTrimNext =
            (i === 0 && LEFT) || (i === element.children.length - 1 && RIGHT);

          return shallowTraverseJSXElement(
            child,
            state,
            scope,
            identifier.name,
            shouldTrimNext
          );
        })
        .filter(value => value);
      const isNative = isNativeTag(tagIdentifier.name);
      let { attributes } = element.openingElement;
      if (!isNative) {
        if (children && children.length > 0) {
          attributes.push(
            t.jsxAttribute(
              t.jsxIdentifier("children"),
              t.jsxExpressionContainer(
                children.length === 1
                  ? children[0]
                  : t.arrayExpression(children)
              )
            )
          );
          children = [];
        }
      }

      state.elements.push({
        type: "node",
        tag: tagIdentifier.name,
        attributes: element.openingElement.attributes,
        isNative,
        identifier,
        children
      });
      break;
    case "JSXText":
      let value = element.value.replace(multiSpaceRegex, " ");
      if (shouldTrim) {
        if (value.trim() === "") {
          return undefined;
        } else if (shouldTrim === LEFT) {
          value = value.trimLeft();
        } else if (shouldTrim === RIGHT) {
          value = value.trimRight();
        }
      }

      state.elements.push({
        type: "text",
        identifier,
        value
      });
      break;
    case "JSXExpressionContainer":
      state.elements.push({
        type: "expr",
        expression: element.expression,
        identifier
      });
      break;
    default:
      console.warn("Unsupported JSX child", element);
  }

  return identifier;
}
Example #5
Source File: scanUpdatableValues.ts    From vidact with MIT License 4 votes vote down vote up
export function scanUpdatableValues(fnPath: NodePath, state: ComponentState) {
  const { variableStatementDependencyManager } = state;

  fnPath.traverse(
    {
      MemberExpression(objectReferencePath) {
        const { node } = objectReferencePath;
        const { object, property } = node;

        if (!t.isIdentifier(object) || object.name !== PROP_VAR) {
          return;
        }

        const immediateStatement = objectReferencePath.findParent(
          findImmediateStatement
        );

        if (isStatementLocked(immediateStatement)) {
          return;
        }

        if (immediateStatement.isVariableDeclaration()) {
          // TODO: Check for object and array destruct
          const { id } = immediateStatement.node.declarations[0];

          if (!t.isIdentifier(id)) {
            return;
          }

          variableStatementDependencyManager.push(
            { type: "prop", name: property.name },
            { type: "local", name: id.name }
          );

          scanDependees(objectReferencePath.scope, id.name);
        } else if (
          !immediateStatement.isReturnStatement() &&
          (!immediateStatement.isExpressionStatement() ||
            !immediateStatement.get("expression").isAssignmentExpression())
        ) {
          variableStatementDependencyManager.push(
            { type: "prop", name: property.name },
            { type: "node", value: immediateStatement }
          );

          immediateStatement.traverse({
            AssignmentExpression(assignPath) {
              const leftPath = assignPath.get("left");
              if (leftPath.isIdentifier()) {
                variableStatementDependencyManager.push(
                  { type: "prop", name: property.name },
                  { type: "local", name: leftPath.node.name }
                );
                scanDependees(objectReferencePath.scope, leftPath.node.name);
              }
            },
          });
        }
      },
      CallExpression(callExpressionPath, state) {
        const callee = callExpressionPath.get("callee");
        if (!callee.isIdentifier() || callee.node.name !== USE_STATE) {
          return callExpressionPath.skip();
        }

        const statement = callExpressionPath.getStatementParent();

        if (!statement.isVariableDeclaration()) {
          return callExpressionPath.skip();
        }

        const tupleId = fnPath.scope.generateUidIdentifier("s");

        const declarations = statement.get("declarations");
        const declarator = declarations.find((declarator) => {
          const init = declarator.get("init");
          return init.node === callExpressionPath.node;
        });
        statement.node.kind = "let";
        const left = declarator.get("id");
        const initialValue = callExpressionPath.node
          .arguments[0] as t.Expression;

        const valueNode = t.memberExpression(t.identifier(STATE_VAR), tupleId);
        const setterNode = t.arrowFunctionExpression(
          [t.identifier("value")],
          t.blockStatement([
            t.expressionStatement(
              t.callExpression(t.identifier(KEY_STATE_UPDATER), [
                t.objectExpression([
                  t.objectProperty(tupleId, t.identifier("value")),
                ]),
              ])
            ),
          ])
        );

        if (left.isArrayPattern()) {
          const [valueName, setterName] = left
            .get("elements")
            .map(({ node }) => (node as t.Identifier).name);
          left.replaceWith(tupleId);
          state.variablesWithDependencies.add(valueName);
          const assignValue = t.expressionStatement(
            t.assignmentExpression("=", t.identifier(valueName), valueNode)
          );
          const assignValuePath = callExpressionPath
            .getStatementParent()
            .insertAfter(assignValue)[0];
          callExpressionPath
            .getStatementParent()
            .insertAfter(
              t.variableDeclaration("const", [
                t.variableDeclarator(t.identifier(setterName), setterNode),
              ])
            );

          variableStatementDependencyManager.push(
            { type: "state", name: tupleId.name },
            { type: "local", name: valueName }
          );
          variableStatementDependencyManager.push(
            { type: "local", name: valueName },
            { type: "node", value: assignValuePath }
          );

          scanDependees(callExpressionPath.scope, valueName, true);
          state.state.push({
            originalName: valueName,
            name: tupleId,
            initialValue,
          });
          statement.remove();
        }
      },
    },
    state
  );

  function findImmediateStatement(s: NodePath) {
    return (
      s.parentPath.isBlockStatement() &&
      s.parentPath.parentPath.node === fnPath.node
    );
  }

  function scanDependees(scope: Scope, name: string, skipDefinition = false) {
    if (!scope.hasBinding(name)) {
      return;
    }

    const binding = scope.getBinding(name);

    Object.values(binding.referencePaths).forEach((n) => {
      const container = n.getStatementParent();

      const expression = container.isExpressionStatement()
        ? container.get("expression")
        : container;

      const statement = n.findParent(findImmediateStatement);

      if (isStatementLocked(statement)) {
        return;
      }

      let lVal: NodePath<t.LVal>;
      if (expression.isVariableDeclaration()) {
        lVal = expression.get("declarations")[0].get("id");
      } else if (expression.isAssignmentExpression()) {
        lVal = expression.get("left");
      }

      if (statement.isVariableDeclaration()) {
        declarationToAssignment(statement).forEach((name) =>
          state.variablesWithDependencies.add(name)
        );
      }

      if (lVal) {
        const id = lVal as NodePath<t.Identifier>;
        const { name: idName } = id.node;

        if (idName !== name) {
          scanDependees(scope, idName);

          variableStatementDependencyManager.push(
            { type: "local", name },
            { type: "local", name: idName }
          );
        }
      }

      if (!statement.isReturnStatement()) {
        statement.traverse({
          AssignmentExpression(assignPath) {
            const leftPath = assignPath.get("left");
            if (leftPath.isIdentifier()) {
              variableStatementDependencyManager.push(
                { type: "local", name },
                { type: "local", name: leftPath.node.name }
              );
              scanDependees(scope, leftPath.node.name);
            }
          },
        });

        variableStatementDependencyManager.push(
          { type: "local", name },
          { type: "node", value: statement }
        );
      }
    });

    if (!skipDefinition) {
      const declaration = binding.path.findParent(findImmediateStatement);

      if (isStatementLocked(declaration)) {
        return;
      }

      state.variablesWithDependencies.add(name);
      variableStatementDependencyManager.push(
        { type: "local", name },
        { type: "node", value: declaration }
      );

      // declaration.replaceWith(
      //   t.assignmentExpression("=", declarator.node.id, declarator.node.init)
      // );
      if (declaration.isVariableDeclaration()) {
        state.looseAssignments.add(declaration);
      }
    }
  }
}