export function parseCode()

in src/ast.ts [177:279]


export function parseCode(
  code: string,
  elementName: string,
  parseProvider?: (ast: any) => void,
) {
  const propValues: { [key: string]: string } = {};
  const stateValues: { [key: string]: string } = {};
  let parsedProvider: any = undefined;
  try {
    const ast = parse(code) as any;
    traverse(ast, {
      JSXElement(path) {
        if (
          Object.keys(propValues).length === 0 && // process just the first element
          path.node.openingElement.type === "JSXOpeningElement" &&
          //@ts-ignore
          path.node.openingElement.name.name === elementName
        ) {
          path.node.openingElement.attributes.forEach((attr: any) => {
            const name = attr.name.name;
            let value = null;
            if (attr.value === null) {
              //boolean prop without value
              value = true;
            } else {
              if (attr.value.type === "StringLiteral") {
                value = attr.value.value;
              } else if (attr.value.type === "JSXExpressionContainer") {
                if (attr.value.expression.type === "BooleanLiteral") {
                  value = attr.value.expression.value;
                } else {
                  value = formatAstAndPrint(
                    //@ts-ignore
                    t.program([t.expressionStatement(attr.value.expression)]),
                    30,
                  );
                  if (attr.value.expression.type === "ObjectExpression") {
                    // the generated code is ({ .... }), this removes the brackets to
                    // keep the input more readable
                    value = value.slice(1, -1);
                  }
                  if (
                    attr.value.expression.type === "MemberExpression" &&
                    attr.value.expression.computed
                  ) {
                    // turn a['hello-world'] into a.hello-world so we don't have to deal with two
                    // variants in the enum knob UI
                    value = `${attr.value.expression.object.name}.${attr.value.expression.property.value}`;
                  }
                }
              }
            }
            propValues[name] = value;
          });
          propValues["children"] = formatAstAndPrint(
            getAstJsxElement("ViewRoot", [], path.node.children as any) as any,
            30,
          )
            .replace(/\n  /g, "\n")
            .replace(/^<ViewRoot>\n?/, "")
            .replace(/<\/ViewRoot>$/, "")
            .replace(/\s*<ViewRoot \/>\s*/, "");
        }
      },
      VariableDeclarator(path) {
        // looking for React.useState()
        const node = path.node as any;
        if (
          node.id.type === "ArrayPattern" &&
          node.init.type === "CallExpression" &&
          node.init.callee.property.name === "useState"
        ) {
          const name = node.id.elements[0].name;
          const valueNode = node.init.arguments[0];
          if (
            valueNode.type === "StringLiteral" ||
            valueNode.type === "BooleanLiteral"
          ) {
            stateValues[name] = valueNode.value;
          } else {
            stateValues[name] = generate(valueNode).code;
          }
        }
      },
    });
    if (parseProvider) {
      parsedProvider = parseProvider(ast);
    }
  } catch (e) {
    throw new Error("Code is not valid and can't be parsed.");
  }

  // override props by local state (React hooks)
  Object.keys(stateValues).forEach((stateValueKey) => {
    Object.keys(propValues).forEach((propValueKey) => {
      if (propValues[propValueKey] === stateValueKey) {
        propValues[propValueKey] = stateValues[stateValueKey];
      }
    });
  });

  return { parsedProps: propValues, parsedProvider };
}