@babel/types#JSXSpreadAttribute TypeScript Examples

The following examples show how to use @babel/types#JSXSpreadAttribute. 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: plasmic-parser.ts    From plasmic with MIT License 6 votes vote down vote up
tryGetNodeIdFromAttr = (attr: JSXAttribute | JSXSpreadAttribute) => {
  if (attr.type === "JSXAttribute") {
    if (isAttribute(attr, "className") && attr.value) {
      let nodeId: string | undefined = undefined;
      traverse(attr.value, {
        noScope: true,
        CallExpression: function (path) {
          const member = tryExtractPropertyNameOfMemberExpression(
            path.node.callee,
            helperObject
          );
          const m = member?.match(/^cls(.+)$/);
          if (m) {
            nodeId = m[1];
            path.stop();
          }
        },
      });
      return nodeId;
    }
  } else {
    // spread
    if (
      attr.argument.type === "CallExpression" &&
      attr.argument.callee.type === "MemberExpression"
    ) {
      const member = tryExtractPropertyNameOfMemberExpression(
        attr.argument.callee,
        helperObject
      );
      const m = member?.match(/^props(.+)$/);
      if (m) {
        return m[1];
      }
    }
  }
  return undefined;
}
Example #2
Source File: utils.ts    From plasmic with MIT License 6 votes vote down vote up
isAttribute = (
  attr: JSXAttribute | JSXSpreadAttribute,
  expectedName: string
) => {
  return attr.type === "JSXAttribute" && getAttrName(attr) === expectedName;
}
Example #3
Source File: index.ts    From plasmic with MIT License 4 votes vote down vote up
mergeAttributes = (
  newNode: PlasmicTagOrComponent,
  editedNode: PlasmicTagOrComponent,
  baseNode: PlasmicTagOrComponent,
  codeVersions: CodeVersions
) => {
  const { newVersion, editedVersion } = codeVersions;
  assert(editedNode.jsxElement.nameInId === newNode.jsxElement.nameInId);
  assert(editedNode.jsxElement.nameInId === baseNode.jsxElement.nameInId);

  const newNodePropsWithIdSpreador = newVersion.tryGetPropsIdSpreador(newNode);
  const editedHasPropsWithIdSpreador = editedVersion.hasPropsIdSpreador(
    editedNode
  );

  const newNamedAttrs = getRawNamedAttrs(newNode.jsxElement.rawNode);
  const editedNamedAttrs = getRawNamedAttrs(editedNode.jsxElement.rawNode);
  const baseNamedAttrs = getRawNamedAttrs(baseNode.jsxElement.rawNode);

  const conflictResolution = (
    name: string,
    baseAttr: JSXAttribute | undefined,
    editedAttr: JSXAttribute,
    newAttr: JSXAttribute
  ) => {
    // If attribute match, then emit either version is ok. Emitting it at the
    // place where the edited version emitted at is probably safer, and less
    // disturbing.
    if (nodesDeepEqualIgnoreComments(editedAttr, newAttr)) {
      return "emit-edited";
    }
    if (!baseAttr) {
      // We don't know how to handle the conflict. Merge them and let developer
      // handle it.
      return "emit-merged";
    }
    if (nodesDeepEqualIgnoreComments(baseAttr, editedAttr)) {
      // User didn't edit it. Emit the new version.
      return "emit-new";
    }
    if (
      name.startsWith("on") ||
      (name === "value" &&
        tagName(newNode.jsxElement.rawNode) === "PlasmicSlot") ||
      nodesDeepEqualIgnoreComments(baseAttr, newAttr)
    ) {
      // Plasmic doesn't change it. Emit the edited version then.
      return "emit-edited";
    }
    // Both Plasmic and developer edited it. Emit both.
    return "emit-merged";
  };

  const emitAttrInEditedNode = (attrName: string) => {
    const editedAttr = ensure(editedNamedAttrs.get(attrName));
    const newAttr = newNamedAttrs.get(attrName);
    const baseAttr = baseNamedAttrs.get(attrName);
    if (newAttr) {
      const res = conflictResolution(attrName, baseAttr, editedAttr, newAttr);
      if (res === "emit-new") {
        // We emit the newAttr in place to minimize diff.
        return newAttr;
      } else if (res === "emit-merged") {
        const value = mergeAttributeValue(
          attrName,
          newNode,
          editedNode,
          baseNode,
          codeVersions
        );
        return babel.types.jsxAttribute(newAttr.name, value);
      }
      assert(res === "emit-edited");
      return editedAttr;
    } else if (!baseAttr) {
      // user added attribute in edited version. Emit the edited attribute
      // without any transformation.
      return serializeNamedAttribute(
        editedAttr.name,
        findParsedNamedAttrs(editedNode, attrName),
        codeVersions
      );
    } else {
      // Attribute deleted in new version. However, user may have modified it.
      // Delete it only if there is no modification; otherwise, keep it for user
      // to fix the compilation failure.
      return nodesDeepEqualIgnoreComments(baseAttr, editedAttr)
        ? undefined
        : serializeNamedAttribute(
            editedAttr.name,
            findParsedNamedAttrs(editedNode, attrName),
            codeVersions
          );
    }
  };

  const mergedAttrs: Array<JSXAttribute | JSXSpreadAttribute> = [];

  newNamedAttrs.forEach((attr, name) => {
    const editedAttr = editedNamedAttrs.get(name);
    const baseAttr = baseNamedAttrs.get(name);
    if (!baseAttr && !editedAttr) {
      // newly added attribute in new version
      mergedAttrs.push(
        serializeNamedAttribute(
          attr.name,
          findParsedNamedAttrs(newNode, name),
          codeVersions
        )
      );
    }
  });

  for (const attrInEditedNode of editedNode.jsxElement.attrs) {
    if (L.isArray(attrInEditedNode)) {
      const toEmit = emitAttrInEditedNode(attrInEditedNode[0]);
      if (toEmit) {
        mergedAttrs.push(toEmit);
      }
    } else {
      const serializedSpreador = serializeJsxSpreadAttribute(
        attrInEditedNode,
        !!newNodePropsWithIdSpreador,
        newNode.jsxElement.nameInId,
        codeVersions
      );
      if (serializedSpreador) {
        mergedAttrs.push(serializedSpreador);
      }
    }
  }
  let classNameAt = mergedAttrs.findIndex((attr) =>
    isAttribute(attr, "className")
  );
  // insert className if missing in edited version, mostly to support old code.
  if (classNameAt === -1) {
    const newClassNameAttr = newNamedAttrs.get("className");
    if (newClassNameAttr) {
      mergedAttrs.splice(0, 0, newClassNameAttr);
      classNameAt = 0;
    }
  }
  if (newNodePropsWithIdSpreador && !editedHasPropsWithIdSpreador) {
    // insert the new spreador right after className if any, always
    const insertSpreadorAt = classNameAt === -1 ? 0 : classNameAt + 1;
    mergedAttrs.splice(insertSpreadorAt, 0, newNodePropsWithIdSpreador);
  }

  return mergedAttrs;
}