@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
JavaScript
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
});
;