@babel/types#JSXAttribute TypeScript Examples

The following examples show how to use @babel/types#JSXAttribute. 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: jsx.ts    From react-optimized-image with MIT License 6 votes vote down vote up
getAttribute = (path: NodePath<JSXElement>, attributeName: string): NodePath<JSXAttribute> | undefined => {
  if (path.node.openingElement.attributes) {
    let attribue;

    path.get('openingElement').traverse({
      JSXAttribute(attributePath) {
        if (attributePath.node.name.name === attributeName) {
          attribue = attributePath;
          attributePath.stop();
        }
      },
    });

    return attribue;
  }

  return undefined;
}
Example #2
Source File: traverse.ts    From react-optimized-image with MIT License 6 votes vote down vote up
getRequireArguments = (
  types: Babel['types'],
  path: NodePath<JSXAttribute>,
): CallExpression['arguments'] | undefined => {
  // check for inline-require statement
  if (
    path.node.value &&
    path.node.value.type === 'JSXExpressionContainer' &&
    path.node.value.expression.type === 'CallExpression' &&
    path.node.value.expression.callee.type === 'Identifier' &&
    path.node.value.expression.callee.name === 'require' &&
    path.node.value.expression.arguments.length > 0
  ) {
    return path.node.value.expression.arguments;
  }

  // check for import reference
  if (
    path.node.value &&
    path.node.value.type === 'JSXExpressionContainer' &&
    path.node.value.expression.type === 'Identifier'
  ) {
    const variableName = path.node.value.expression.name;
    const binding = path.scope.getBinding(variableName);

    if (
      binding &&
      binding.kind === 'module' &&
      isImport(binding.path) &&
      binding.path.parent.type === 'ImportDeclaration'
    ) {
      return [types.stringLiteral(binding.path.parent.source.value)];
    }
  }
}
Example #3
Source File: traverse.ts    From react-optimized-image with MIT License 6 votes vote down vote up
getRelevantRequireString = (types: Babel['types'], path: NodePath<JSXAttribute>): string | undefined => {
  const args = getRequireArguments(types, path);
  if (args && args.length > 0) {
    // stringle string
    if (args[0].type === 'StringLiteral') {
      return args[0].value;
    }

    // concatenated string
    if (args[0].type === 'BinaryExpression' && args[0].right.type === 'StringLiteral') {
      return args[0].right.value;
    }

    // template literal
    if (args[0].type === 'TemplateLiteral' && args[0].quasis.length > 0) {
      return args[0].quasis[args[0].quasis.length - 1].value.raw;
    }
  }
}
Example #4
Source File: index.ts    From plasmic with MIT License 6 votes vote down vote up
getRawNamedAttrs = (jsxElement: JSXElement) => {
  const attrs = new Map<string, JSXAttribute>();
  for (const attr of jsxElement.openingElement.attributes) {
    if (attr.type !== "JSXAttribute") {
      continue;
    }
    assert(L.isString(attr.name.name));
    attrs.set(attr.name.name, attr);
  }
  return attrs;
}
Example #5
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 #6
Source File: utils.ts    From plasmic with MIT License 6 votes vote down vote up
getAttrName = (attr: JSXAttribute) => {
  const name = attr.name;
  return name.type === "JSXIdentifier"
    ? name.name
    : `${name.namespace.name}.${name.name.name}`;
}
Example #7
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 #8
Source File: visitor.ts    From react-dev-inspector with MIT License 6 votes vote down vote up
doJSXOpeningElement: NodeHandler<
  JSXOpeningElement,
  { relativePath: string }
> = (node, option) => {
  const { stop } = doJSXPathName(node.name)
  if (stop) return { stop }

  const { relativePath } = option
  const line = node.loc?.start.line
  const column = node.loc?.start.column

  const lineAttr: JSXAttribute | null = isNil(line)
    ? null
    : jsxAttribute(
      jsxIdentifier('data-inspector-line'),
      stringLiteral(line.toString()),
    )

  const columnAttr: JSXAttribute | null = isNil(column)
    ? null
    : jsxAttribute(
      jsxIdentifier('data-inspector-column'),
      stringLiteral(column.toString()),
    )

  const relativePathAttr: JSXAttribute = jsxAttribute(
    jsxIdentifier('data-inspector-relative-path'),
    stringLiteral(relativePath),
  )

  const attributes = [lineAttr, columnAttr, relativePathAttr] as JSXAttribute[]

  // Make sure that there are exist together
  if (attributes.every(Boolean)) {
    node.attributes.unshift(...attributes)
  }

  return { result: node }
}
Example #9
Source File: jsxConverter.ts    From react-native-decompiler with GNU Affero General Public License v3.0 5 votes vote down vote up
private parseJsx(node: Expression): JSXText | JSXExpressionContainer | JSXSpreadChild | JSXElement | JSXFragment {
    if (isStringLiteral(node)) {
      return jsxText(node.value);
    }
    if (isCallExpression(node)) {
      const args = node.arguments;

      let name: JSXIdentifier | JSXMemberExpression | undefined;
      if (isIdentifier(args[0]) || isStringLiteral(args[0])) {
        name = jsxIdentifier(isIdentifier(args[0]) ? args[0].name : args[0].value);
      } else if (isMemberExpression(args[0]) && isIdentifier(args[0].object) && isIdentifier(args[0].property)) {
        name = jsxMemberExpression(jsxIdentifier(args[0].object.name), jsxIdentifier(args[0].property.name));
      } else {
        this.debugLog(`fail to parse component ${args[0].type} inside callExpression`);
        return jsxExpressionContainer(node);
      }

      let props: JSXAttribute[] = [];
      if (isObjectExpression(args[1])) {
        props = args[1].properties.map((prop) => {
          if (!isObjectProperty(prop) || !isIdentifier(prop.key)) return null;
          if (isStringLiteral(prop.value)) {
            return jsxAttribute(jsxIdentifier(prop.key.name), prop.value);
          }
          if (isBooleanLiteral(prop.value) && prop.value.value) {
            return jsxAttribute(jsxIdentifier(prop.key.name), null);
          }
          if (isExpression(prop.value)) {
            return jsxAttribute(jsxIdentifier(prop.key.name), jsxExpressionContainer(prop.value));
          }
          return null;
        }).filter((e): e is JSXAttribute => e != null);
      }

      const children = args.slice(2).map((e) => (isExpression(e) ? this.parseJsx(e) : null)).filter((e): e is JSXElement => e != null);

      if (children.length) {
        return jsxElement(jsxOpeningElement(name, props), jsxClosingElement(name), children);
      }

      return jsxElement(jsxOpeningElement(name, props, true), null, []);
    }

    this.debugLog(`fail to parse component ${node.type}`);
    return jsxExpressionContainer(node);
  }
Example #10
Source File: img.ts    From react-optimized-image with MIT License 5 votes vote down vote up
buildRawSrcAttribute = (
  types: Babel['types'],
  requireArgs: CallExpression['arguments'],
  config: ImageConfig,
  globalQuery: Record<string, string>,
): JSXAttribute => {
  const properties: ObjectProperty[] = [];

  ['fallback', ...(config.webp ? ['webp'] : [])].forEach((type) => {
    const typeProperties: ObjectProperty[] = [];
    const query: Record<string, string> = type === 'webp' ? { ...globalQuery, webp: '' } : { ...globalQuery };

    (config.sizes && config.sizes.length > 0 ? config.sizes : ['original']).forEach(
      (size: number | string, index: number, allSizes: Array<number | string>) => {
        const sizeProperties: ObjectProperty[] = [];

        // only inline image if there is 1 size and no fallback
        if (
          typeof query.url === 'undefined' &&
          typeof query.inline === 'undefined' &&
          ((type === 'fallback' && config.webp) || allSizes.length > 1 || (config.densities || [1]).length > 1)
        ) {
          query.url = '';
        }

        (config.densities || [1]).forEach((density) => {
          const sizeQuery: Record<string, string> = {
            ...query,
            ...(typeof size === 'number' ? { width: `${size * density}` } : {}),
          };

          sizeProperties.push(
            types.objectProperty(
              types.numericLiteral(density),
              buildRequireStatement(types, clone(requireArgs), sizeQuery),
            ),
          );
        });

        typeProperties.push(
          types.objectProperty(
            typeof size === 'string' ? types.identifier(size) : types.numericLiteral(size),
            types.objectExpression(sizeProperties),
          ),
        );
      },
    );

    properties.push(types.objectProperty(types.identifier(type), types.objectExpression(typeProperties)));
  });

  return types.jsxAttribute(
    types.jsxIdentifier('rawSrc'),
    types.jsxExpressionContainer(types.objectExpression(properties)),
  );
}
Example #11
Source File: jsxConverter.ts    From react-native-decompiler with GNU Affero General Public License v3.0 5 votes vote down vote up
private parseJsx(node: Expression): JSXText | JSXExpressionContainer | JSXSpreadChild | JSXElement | JSXFragment {
    if (isStringLiteral(node)) {
      return jsxText(node.value);
    }
    if (isCallExpression(node)) {
      const args = node.arguments;

      let name: JSXIdentifier | JSXMemberExpression | undefined;
      if (isIdentifier(args[0]) || isStringLiteral(args[0])) {
        name = jsxIdentifier(isIdentifier(args[0]) ? args[0].name : args[0].value);
      } else if (isMemberExpression(args[0]) && isIdentifier(args[0].object) && isIdentifier(args[0].property)) {
        name = jsxMemberExpression(jsxIdentifier(args[0].object.name), jsxIdentifier(args[0].property.name));
      } else {
        this.debugLog(`fail to parse component ${args[0].type} inside callExpression`);
        return jsxExpressionContainer(node);
      }

      let props: JSXAttribute[] = [];
      if (isObjectExpression(args[1])) {
        props = args[1].properties.map((prop) => {
          if (!isObjectProperty(prop) || !isIdentifier(prop.key)) return null;
          if (isStringLiteral(prop.value)) {
            return jsxAttribute(jsxIdentifier(prop.key.name), prop.value);
          }
          if (isBooleanLiteral(prop.value) && prop.value.value) {
            return jsxAttribute(jsxIdentifier(prop.key.name), null);
          }
          if (isExpression(prop.value)) {
            return jsxAttribute(jsxIdentifier(prop.key.name), jsxExpressionContainer(prop.value));
          }
          return null;
        }).filter((e): e is JSXAttribute => e != null);
      }

      const children = args.slice(2).map((e) => (isExpression(e) ? this.parseJsx(e) : null)).filter((e): e is JSXElement => e != null);

      if (children.length) {
        return jsxElement(jsxOpeningElement(name, props), jsxClosingElement(name), children);
      }

      return jsxElement(jsxOpeningElement(name, props, true), null, []);
    }

    this.debugLog(`fail to parse component ${node.type}`);
    return jsxExpressionContainer(node);
  }
Example #12
Source File: index.ts    From tailchat with GNU General Public License v3.0 5 votes vote down vote up
async function loader(this: LoaderContext<any>, source: string): Promise<void> {
  const done = this.async();

  const { available } = this.getOptions();
  if (!available) {
    // skip if not
    done(null, source);
    return;
  }

  const ast = parse(source, {
    sourceType: 'module',
    plugins: ['jsx', 'typescript'],
  });
  const filepath = this.resourcePath;
  if (filepath.includes('node_modules')) {
    done(null, source);
    return;
  }

  traverse(ast, {
    JSXOpeningElement(path) {
      const location = path.node.loc;
      if (!location) {
        return;
      }

      if (Array.isArray(location)) {
        return;
      }

      const name = path.node.name;
      if (isJSXIdentifier(name) && name.name === 'Fragment') {
        return;
      }
      if (isJSXMemberExpression(name) && name.property.name === 'Fragment') {
        return;
      }

      const line = location.start.line;
      const col = location.start.column;

      const attrs = path.node.attributes;
      for (let i = 0; i < attrs.length; i++) {
        const attr = attrs[i];
        if (attr.type === 'JSXAttribute' && attr.name.name === TRACE_ID) {
          // existed
          return;
        }
      }

      const traceId = `${filepath}:${line}:${col}`;

      attrs.push(jsxAttribute(jsxIdentifier(TRACE_ID), stringLiteral(traceId)));
    },
  });

  const code = generate(ast).code;

  done(null, code);
}
Example #13
Source File: index.ts    From tailchat with GNU General Public License v3.0 5 votes vote down vote up
export default function sourceRef(): Plugin {
  return {
    name: 'source-ref',
    transform(code, id) {
      const filepath = id;

      const ast = parse(code, {
        sourceType: 'module',
        plugins: ['jsx', 'typescript'],
      });

      traverse(ast, {
        JSXOpeningElement(path) {
          const location = path.node.loc;
          if (!location) {
            return;
          }

          if (Array.isArray(location)) {
            return;
          }

          const name = path.node.name;
          if (isJSXIdentifier(name) && name.name === 'Fragment') {
            return;
          }
          if (
            isJSXMemberExpression(name) &&
            name.property.name === 'Fragment'
          ) {
            return;
          }

          const line = location.start.line;
          const col = location.start.column;

          const attrs = path.node.attributes;
          for (let i = 0; i < attrs.length; i++) {
            const attr = attrs[i];
            if (attr.type === 'JSXAttribute' && attr.name.name === TRACE_ID) {
              // existed
              return;
            }
          }

          const traceId = `${filepath}:${line}:${col}`;

          attrs.push(
            jsxAttribute(jsxIdentifier(TRACE_ID), stringLiteral(traceId))
          );
        },
      });

      const res = generate(ast);

      return { code: res.code, map: res.map };
    },
  };
}
Example #14
Source File: jsxConverter.ts    From react-native-decompiler with GNU Affero General Public License v3.0 5 votes vote down vote up
private parseJsx(node: Expression): JSXText | JSXExpressionContainer | JSXSpreadChild | JSXElement | JSXFragment {
    if (isStringLiteral(node)) {
      return jsxText(node.value);
    }
    if (isCallExpression(node)) {
      const args = node.arguments;

      let name: JSXIdentifier | JSXMemberExpression | undefined;
      if (isIdentifier(args[0]) || isStringLiteral(args[0])) {
        name = jsxIdentifier(isIdentifier(args[0]) ? args[0].name : args[0].value);
      } else if (isMemberExpression(args[0]) && isIdentifier(args[0].object) && isIdentifier(args[0].property)) {
        name = jsxMemberExpression(jsxIdentifier(args[0].object.name), jsxIdentifier(args[0].property.name));
      } else {
        this.debugLog(`fail to parse component ${args[0].type} inside callExpression`);
        return jsxExpressionContainer(node);
      }

      let props: JSXAttribute[] = [];
      if (isObjectExpression(args[1])) {
        props = args[1].properties.map((prop) => {
          if (!isObjectProperty(prop) || !isIdentifier(prop.key)) return null;
          if (isStringLiteral(prop.value)) {
            return jsxAttribute(jsxIdentifier(prop.key.name), prop.value);
          }
          if (isBooleanLiteral(prop.value) && prop.value.value) {
            return jsxAttribute(jsxIdentifier(prop.key.name), null);
          }
          if (isExpression(prop.value)) {
            return jsxAttribute(jsxIdentifier(prop.key.name), jsxExpressionContainer(prop.value));
          }
          return null;
        }).filter((e): e is JSXAttribute => e != null);
      }

      const children = args.slice(2).map((e) => (isExpression(e) ? this.parseJsx(e) : null)).filter((e): e is JSXElement => e != null);

      if (children.length) {
        return jsxElement(jsxOpeningElement(name, props), jsxClosingElement(name), children);
      }

      return jsxElement(jsxOpeningElement(name, props, true), null, []);
    }

    this.debugLog(`fail to parse component ${node.type}`);
    return jsxExpressionContainer(node);
  }
Example #15
Source File: jsxConverter.ts    From react-native-decompiler with GNU Affero General Public License v3.0 5 votes vote down vote up
private parseJsx(node: Expression): JSXText | JSXExpressionContainer | JSXSpreadChild | JSXElement | JSXFragment {
    if (isStringLiteral(node)) {
      return jsxText(node.value);
    }
    if (isCallExpression(node)) {
      const args = node.arguments;

      let name: JSXIdentifier | JSXMemberExpression | undefined;
      if (isIdentifier(args[0]) || isStringLiteral(args[0])) {
        name = jsxIdentifier(isIdentifier(args[0]) ? args[0].name : args[0].value);
      } else if (isMemberExpression(args[0]) && isIdentifier(args[0].object) && isIdentifier(args[0].property)) {
        name = jsxMemberExpression(jsxIdentifier(args[0].object.name), jsxIdentifier(args[0].property.name));
      } else {
        this.debugLog(`fail to parse component ${args[0].type} inside callExpression`);
        return jsxExpressionContainer(node);
      }

      let props: JSXAttribute[] = [];
      if (isObjectExpression(args[1])) {
        props = args[1].properties.map((prop) => {
          if (!isObjectProperty(prop) || !isIdentifier(prop.key)) return null;
          if (isStringLiteral(prop.value)) {
            return jsxAttribute(jsxIdentifier(prop.key.name), prop.value);
          }
          if (isBooleanLiteral(prop.value) && prop.value.value) {
            return jsxAttribute(jsxIdentifier(prop.key.name), null);
          }
          if (isExpression(prop.value)) {
            return jsxAttribute(jsxIdentifier(prop.key.name), jsxExpressionContainer(prop.value));
          }
          return null;
        }).filter((e): e is JSXAttribute => e != null);
      }

      const children = args.slice(2).map((e) => (isExpression(e) ? this.parseJsx(e) : null)).filter((e): e is JSXElement => e != null);

      if (children.length) {
        return jsxElement(jsxOpeningElement(name, props), jsxClosingElement(name), children);
      }

      return jsxElement(jsxOpeningElement(name, props, true), null, []);
    }

    this.debugLog(`fail to parse component ${node.type}`);
    return jsxExpressionContainer(node);
  }
Example #16
Source File: svg.ts    From react-optimized-image with MIT License 5 votes vote down vote up
buildRawSrcAttribute = (types: Babel['types'], requireArgs: CallExpression['arguments']): JSXAttribute => {
  return types.jsxAttribute(
    types.jsxIdentifier('rawSrc'),
    types.jsxExpressionContainer(buildRequireStatement(types, clone(requireArgs), { include: '' })),
  );
}
Example #17
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;
}