UNPKG

@kuma-ui/compiler

Version:

🐻 Kuma UI is a utility-first, zero-runtime CSS-in-JS library that offers an outstanding developer experience and optimized performance.

407 lines (395 loc) 15 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/compile.ts var compile_exports = {}; __export(compile_exports, { compile: () => compile }); module.exports = __toCommonJS(compile_exports); var import_ts_morph8 = require("ts-morph"); // src/collector/collect.ts var import_ts_morph4 = require("ts-morph"); // src/collector/decode.ts var import_ts_morph = require("ts-morph"); var decode = (node) => { if (import_ts_morph.Node.isAsExpression(node)) { return decode(node.getExpression()); } if (import_ts_morph.Node.isParenthesizedExpression(node)) { return decode(node.getExpression()); } if (import_ts_morph.Node.isNonNullExpression(node)) { return decode(node.getExpression()); } if (import_ts_morph.Node.isTypeAssertion(node)) { return decode(node.getExpression()); } return node; }; // src/collector/expression.ts var import_ts_morph2 = require("ts-morph"); var handleJsxExpression = (node) => { if (import_ts_morph2.Node.isNumericLiteral(node)) { return node.getLiteralValue(); } if (import_ts_morph2.Node.isStringLiteral(node)) { return node.getLiteralValue().trim(); } if (import_ts_morph2.Node.isNoSubstitutionTemplateLiteral(node)) { return node.getLiteralValue().trim(); } if (import_ts_morph2.Node.isTrueLiteral(node)) { return node.getLiteralValue(); } if (import_ts_morph2.Node.isFalseLiteral(node)) { return node.getLiteralValue(); } if (import_ts_morph2.Node.isArrayLiteralExpression(node)) { const arrayExpression = node.getElements().map((elm) => { return handleJsxExpression(elm); }); return arrayExpression.includes(void 0) ? void 0 : arrayExpression; } if (import_ts_morph2.Node.isBinaryExpression(node)) { const leftOperand = handleJsxExpression(node.getLeft()); const rightOperand = handleJsxExpression(node.getRight()); const operator = node.getOperatorToken().getKind(); if (typeof leftOperand === "number" && typeof rightOperand === "number") { switch (operator) { case import_ts_morph2.SyntaxKind.PlusToken: return leftOperand + rightOperand; case import_ts_morph2.SyntaxKind.MinusToken: return leftOperand - rightOperand; case import_ts_morph2.SyntaxKind.AsteriskToken: return leftOperand * rightOperand; case import_ts_morph2.SyntaxKind.SlashToken: return leftOperand / rightOperand; default: return void 0; } } return void 0; } if (import_ts_morph2.Node.isObjectLiteralExpression(node)) { return void 0; } if (import_ts_morph2.Node.isCallExpression(node)) { return void 0; } return void 0; }; // src/collector/pseudo.ts var import_ts_morph3 = require("ts-morph"); var extractPseudoAttribute = (jsxAttribute) => { const initializer = jsxAttribute.getInitializer(); if (import_ts_morph3.Node.isJsxExpression(initializer)) { const expression = initializer.getExpression(); if (!expression) return; const decodedNode = decode(expression); return handlePseudoJsxExpression(decodedNode); } return void 0; }; var handlePseudoJsxExpression = (node) => { if (import_ts_morph3.Node.isObjectLiteralExpression(node)) { const objProps = {}; for (const prop of node.getProperties()) { if (import_ts_morph3.Node.isPropertyAssignment(prop)) { const initializer = prop.getInitializer(); if (initializer) { const decodedNode = decode(initializer); const propName = prop.getName(); objProps[propName] = handleJsxExpression(decodedNode); } } } return Object.values(objProps).includes(void 0) ? void 0 : objProps; } return handleJsxExpression(node); }; // src/collector/collect.ts var collectPropsFromJsx = (node) => { const jsxAttributes = node.getAttributes(); const extracted = {}; jsxAttributes.forEach((jsxAttribute) => { if (import_ts_morph4.Node.isJsxAttribute(jsxAttribute)) { const propName = jsxAttribute.getNameNode().getText(); let propValue; if (propName.trim().startsWith("_")) { propValue = extractPseudoAttribute(jsxAttribute); } else { propValue = extractAttribute(jsxAttribute); } if (propValue == void 0) return; extracted[propName] = propValue; } }); return extracted; }; var extractAttribute = (jsxAttribute) => { const initializer = jsxAttribute.getInitializer(); if (import_ts_morph4.Node.isStringLiteral(initializer)) { const value = initializer.getLiteralText(); return value; } if (import_ts_morph4.Node.isJsxExpression(initializer)) { const expression = initializer.getExpression(); if (!expression) return; const decodedNode = decode(expression); return handleJsxExpression(decodedNode); } if (initializer === void 0) { return true; } return void 0; }; // src/extractor/extract.ts var import_ts_morph5 = require("ts-morph"); var import_system = require("@kuma-ui/system"); var import_componentList = require("@kuma-ui/core/components/componentList"); var import_sheet = require("@kuma-ui/sheet"); var extractProps = (componentName, jsx, propsMap) => { const styledProps = {}; const pseudoProps = {}; const componentProps = {}; const variant = import_sheet.theme.getVariants(componentName); const baseStyleProps = { ...variant?.baseStyle }; const systemDefaultProps = (0, import_componentList.componentDefaultProps)(componentName); const userDefaultProps = variant?.defaultProps; let isDefault = false; for (const [propName, propValue] of Object.entries({ ...systemDefaultProps, ...userDefaultProps, ...propsMap })) { if ((0, import_system.isStyledProp)(propName)) { styledProps[propName] = propValue; } else if ((0, import_system.isPseudoProps)(propName)) { pseudoProps[propName] = propValue; } else if ((0, import_componentList.isComponentProps)(componentName)(propName)) { componentProps[propName] = propValue; } else if (propName === "variant") { Object.assign(baseStyleProps, variant?.variants?.[propValue]); jsx.getAttribute("variant")?.remove(); } else if (propName === "IS_KUMA_DEFAULT") { isDefault = true; } } if (!(!!Object.keys(styledProps).length || !!Object.keys(pseudoProps).length || !!Object.keys(componentProps))) { return; } const specificProps = (0, import_componentList.componentHandler)(componentName)(componentProps); if (componentName === "Box" && isDefault) { for (const prop in baseStyleProps) { if (Object.hasOwn(baseStyleProps, prop)) { delete baseStyleProps[prop]; } } } const combinedProps = { ...baseStyleProps, ...specificProps, ...styledProps, ...pseudoProps }; const { className: generatedClassName, css } = new import_system.StyleGenerator( combinedProps ).getStyle(); if (!generatedClassName) return { css }; const classNameAttr = jsx.getAttribute("className"); let newClassName = generatedClassName; let newClassNameInitializer = ""; if (classNameAttr && import_ts_morph5.Node.isJsxAttribute(classNameAttr)) { const initializer = classNameAttr.getInitializer(); if (import_ts_morph5.Node.isStringLiteral(initializer)) { const existingClassName = initializer.getLiteralText(); if (existingClassName) newClassName += " " + existingClassName; newClassNameInitializer = `"${newClassName}"`; } else if (import_ts_morph5.Node.isJsxExpression(initializer)) { const expression = initializer.getExpression(); if (expression) { newClassNameInitializer = `\`${newClassName} \${${expression.getText()}}\``; } } classNameAttr.remove(); } else { newClassNameInitializer = `"${newClassName}"`; } for (const styledPropKey of Object.keys(styledProps)) { jsx.getAttribute(styledPropKey)?.remove(); } for (const pseudoPropKey of Object.keys(pseudoProps)) { jsx.getAttribute(pseudoPropKey)?.remove(); } for (const componentPropsKey of Object.keys(componentProps)) { jsx.getAttribute(componentPropsKey)?.remove(); } jsx.addAttribute({ name: "className", initializer: `{${newClassNameInitializer}}` }); return { css }; }; // src/compile.ts var import_componentList3 = require("@kuma-ui/core/components/componentList"); // src/optimizer/optimize.ts var import_componentList2 = require("@kuma-ui/core/components/componentList"); var import_ts_morph6 = require("ts-morph"); var import_system2 = require("@kuma-ui/system"); var optimize = (componentName, jsxElement, as) => { const isOptimizable = jsxElement.getAttributes().every((attrLike) => { if (import_ts_morph6.Node.isJsxSpreadAttribute(attrLike)) return false; const attr = attrLike.asKindOrThrow(import_ts_morph6.SyntaxKind.JsxAttribute); if (hasDynamicProp(attr.getNameNode().getText().trim(), !!as)) return false; return true; }); if (!isOptimizable) return; const rawHTMLTag = (() => { const safeAs = typeof as === "string" ? as.replace(/['"`]/g, "") : as; const tag = import_componentList2.defaultComponentTag[componentName]; if (safeAs) { return safeAs; } else { if (typeof tag === "string") return tag; return "div"; } })(); safeReplaceTagName(jsxElement, rawHTMLTag); }; function hasDynamicProp(key, hasAs) { return (0, import_system2.isStyledProp)(key) || (0, import_system2.isPseudoProps)(key) || key === "variant" || !hasAs && key === "as"; } function safeReplaceTagName(jsxElement, newTagName) { const originalComponent = jsxElement.getTagNameNode().getText(); try { if (import_ts_morph6.Node.isJsxOpeningElement(jsxElement)) { const jsxElementParent = jsxElement.getParentIfKind( import_ts_morph6.SyntaxKind.JsxElement ); if (jsxElementParent) { jsxElementParent.getOpeningElement().getTagNameNode().replaceWithText(newTagName); jsxElementParent.getClosingElement().getTagNameNode().replaceWithText(newTagName); } } else if (import_ts_morph6.Node.isJsxSelfClosingElement(jsxElement)) { jsxElement.getTagNameNode().replaceWithText(newTagName); jsxElement.getFirstDescendantByKind(import_ts_morph6.SyntaxKind.Identifier)?.replaceWithText(newTagName); } jsxElement.getAttribute("as")?.remove(); jsxElement.getAttribute("IS_KUMA_DEFAULT")?.remove(); } catch { } } // src/processTaggedTemplateExpression.ts var import_ts_morph7 = require("ts-morph"); var import_sheet2 = require("@kuma-ui/sheet"); var extractClassName = (templateLiteral) => { if (import_ts_morph7.Node.isNoSubstitutionTemplateLiteral(templateLiteral)) { const cssString = templateLiteral.getLiteralText(); return cssString ? import_sheet2.sheet.parseCSS(cssString) : void 0; } return void 0; }; var processTaggedTemplateExpression = (node, bindings) => { const tag = node.getTag(); if (import_ts_morph7.Node.isIdentifier(tag) && tag.getText() === bindings["css"]) { const className = extractClassName(node.getTemplate()); if (className) { node.replaceWithText(JSON.stringify(className)); } } else if (import_ts_morph7.Node.isCallExpression(tag) && tag.getExpressionIfKind(import_ts_morph7.SyntaxKind.Identifier)?.getText() === bindings["styled"]) { const componentArg = tag.getArguments()[0]; if (import_ts_morph7.Node.isStringLiteral(componentArg)) { const componentName = componentArg.getLiteralText(); replaceTaggedTemplate(node, getBoxComponent(componentName, bindings)); } else { replaceTaggedTemplate(node, componentArg.getFullText()); } } else if (import_ts_morph7.Node.isPropertyAccessExpression(tag) && tag.getExpressionIfKind(import_ts_morph7.SyntaxKind.Identifier)?.getText() === bindings["styled"]) { replaceTaggedTemplate(node, getBoxComponent(tag.getName(), bindings)); } }; function getBoxComponent(intrinsicComponentName, bindings) { return `${bindings["Box"]} as="${intrinsicComponentName}"`; } function replaceTaggedTemplate(node, component) { const className = extractClassName(node.getTemplate()); if (className) { const replacement = `__KUMA_REACT__.forwardRef((props, ref) => { const combinedClassName = [props.className, "${className}"].filter(Boolean).join(" "); return <${component} {...props} ref={ref} className={combinedClassName} IS_KUMA_DEFAULT />; })`; node.replaceWithText(replacement); } } // src/compile.ts var project = new import_ts_morph8.Project({}); var compile = (code, id, bindings) => { const css = []; const source = project.createSourceFile(id, code, { overwrite: true }); source.forEachDescendant((node) => { if (node.getKind() === import_ts_morph8.SyntaxKind.JsxElement || node.getKind() === import_ts_morph8.SyntaxKind.JsxSelfClosingElement) { let openingElement; if (node.getKind() === import_ts_morph8.SyntaxKind.JsxElement) { const jsxElement = node.asKindOrThrow(import_ts_morph8.SyntaxKind.JsxElement); openingElement = jsxElement.getOpeningElement(); } else { openingElement = node.asKindOrThrow(import_ts_morph8.SyntaxKind.JsxSelfClosingElement); } const jsxTagName = openingElement.getTagNameNode().getText(); const originalComponentName = Object.keys(bindings).find( (key) => bindings[key] === jsxTagName && Object.values(import_componentList3.componentList).some((c) => c === key) ); if (!originalComponentName) return; const componentName = originalComponentName; const extractedPropsMap = collectPropsFromJsx(openingElement); const result = extractProps( componentName, openingElement, extractedPropsMap ); if (result) css.push(result.css); optimize( componentName, openingElement, extractedPropsMap["as"] ); } if (import_ts_morph8.Node.isTaggedTemplateExpression(node)) { processTaggedTemplateExpression(node, bindings); } }); return { code: source.getFullText(), id, css: css.join(" ") }; }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { compile });