unplugin-jsx-string
Advanced tools
Comparing version 0.4.1 to 0.5.0
import * as magic_string from 'magic-string'; | ||
import { Primitive } from './utils.js'; | ||
import { OptionsResolved } from './options.js'; | ||
@@ -6,3 +7,6 @@ import '@babel/parser'; | ||
declare const convert: (code: string, { debug, plugins }: Pick<OptionsResolved, 'debug' | 'plugins'>) => { | ||
declare type EvaluatedValue = Exclude<Primitive, symbol> | RegExp | Record<any, any> | any[]; | ||
declare function transformJsxToString(code: string, { debug, plugins, id, }: Pick<OptionsResolved, 'debug' | 'plugins'> & { | ||
id?: string; | ||
}): { | ||
code: string; | ||
@@ -12,2 +16,2 @@ readonly map: magic_string.SourceMap; | ||
export { convert }; | ||
export { EvaluatedValue, transformJsxToString }; |
@@ -0,1 +1,2 @@ | ||
"use strict"; | ||
var __create = Object.create; | ||
@@ -25,3 +26,3 @@ var __defProp = Object.defineProperty; | ||
__export(convert_exports, { | ||
convert: () => convert | ||
transformJsxToString: () => transformJsxToString | ||
}); | ||
@@ -36,3 +37,2 @@ module.exports = __toCommonJS(convert_exports); | ||
// src/core/utils.ts | ||
var import_json5 = __toESM(require("json5")); | ||
var import_jsesc = __toESM(require("jsesc")); | ||
@@ -46,13 +46,22 @@ var KEBAB_REGEX = /[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g; | ||
var styleToString = (styles) => Object.entries(styles).map(([key, value]) => `${kebabCase(key)}:${value}`).join(";"); | ||
var parseObject = (text) => { | ||
try { | ||
return import_json5.default.parse(text); | ||
} catch (err) { | ||
throw new SyntaxError(`Invalid attribute value: ${text}, error: ${err.message}`); | ||
} | ||
var RAW_RE = /__RAW_(.*?)_RAW/g; | ||
var escapeString = (str) => { | ||
const text = (0, import_jsesc.default)(str, { | ||
quotes: "backtick", | ||
wrap: true, | ||
es6: true | ||
}); | ||
return text.replaceAll(RAW_RE, "${$1}"); | ||
}; | ||
var escapeString = (str) => `'${(0, import_jsesc.default)(str)}'`; | ||
var isPrimitive = (val) => { | ||
if (typeof val === "object") | ||
return val === null; | ||
return typeof val !== "function"; | ||
}; | ||
var isPlainObject = (obj) => { | ||
return Object.prototype.toString.call(obj) === "[object Object]"; | ||
}; | ||
// src/core/convert.ts | ||
var convert = (code, { debug, plugins }) => { | ||
function extractJsx(code, plugins) { | ||
const ast = (0, import_parser.parse)(code, { | ||
@@ -70,48 +79,22 @@ sourceType: "module", | ||
}); | ||
const s = new import_magic_string.default(code); | ||
for (const [node, expr] of nodes) { | ||
let str; | ||
if (!debug) { | ||
str = escapeString(jsxToString(node)); | ||
} else { | ||
try { | ||
str = escapeString(jsxToString(node)); | ||
} catch (err) { | ||
str = `(() => { throw new Error(${escapeString(err.toString())}) })()`; | ||
} | ||
} | ||
s.overwrite(expr.start, expr.end, str); | ||
return nodes; | ||
} | ||
function transformJsx(code, node) { | ||
return escapeString(toStringJsx(node)); | ||
function toStringJsx(node2) { | ||
return toStringExpression(resolveJsx(node2)); | ||
} | ||
return { | ||
code: s.toString(), | ||
get map() { | ||
return s.generateMap(); | ||
function toStringExpression(expr) { | ||
if (expr instanceof RegExp) { | ||
return expr.toString(); | ||
} else if (typeof expr === "object") { | ||
return JSON.stringify(expr); | ||
} | ||
}; | ||
function jsxToString(node) { | ||
var _a; | ||
switch (node.type) { | ||
case "JSXElement": | ||
return jsxElementToString(node); | ||
case "JSXFragment": | ||
return jsxChildrenToString(node.children); | ||
case "JSXText": | ||
return jsxTextToString(node); | ||
case "JSXEmptyExpression": | ||
return ((_a = node.innerComments) == null ? void 0 : _a.map((comment) => `<!--${comment.value}-->`).join("")) ?? ""; | ||
case "JSXExpressionContainer": { | ||
const expr = resolveExpression(node.expression); | ||
if (expr instanceof RegExp) { | ||
return expr.toString(); | ||
} else if (typeof expr === "object") { | ||
return JSON.stringify(expr); | ||
} | ||
return String(expr); | ||
} | ||
default: | ||
return notSupported(node); | ||
} | ||
return String(expr); | ||
} | ||
function jsxTextToString(node) { | ||
const texts = node.value.split("\n"); | ||
function toStringJsxChildren(nodes) { | ||
return nodes.map((child) => toStringJsx(child)).join(""); | ||
} | ||
function toStringJsxText(node2) { | ||
const texts = node2.value.split("\n"); | ||
return texts.map((text, idx) => idx > 0 ? text.trim() : text).filter((line) => { | ||
@@ -123,30 +106,27 @@ if (line.trim().length === 0) | ||
} | ||
function jsxElementToString(node) { | ||
if (node.openingElement.selfClosing) { | ||
return jsxOpeningElementToString(node.openingElement); | ||
function toStringJsxElement(node2) { | ||
if (node2.openingElement.selfClosing) { | ||
return toStringOpeningElement(node2.openingElement); | ||
} else { | ||
const children = jsxChildrenToString(node.children); | ||
return `${jsxOpeningElementToString(node.openingElement)}${children}</${jsxNameToString(node.closingElement.name)}>`; | ||
const children = toStringJsxChildren(node2.children); | ||
return `${toStringOpeningElement(node2.openingElement)}${children}</${toStringJsxName(node2.closingElement.name)}>`; | ||
} | ||
} | ||
function jsxChildrenToString(nodes2) { | ||
return nodes2.map((child) => jsxToString(child)).join(""); | ||
} | ||
function jsxOpeningElementToString(node) { | ||
let str = `<${jsxNameToString(node.name)}`; | ||
const props = node.attributes.map((attr) => { | ||
if (attr.type === "JSXAttribute") { | ||
return jsxAttributeToString(attr); | ||
} else { | ||
return notSupported(node); | ||
function toStringOpeningElement(node3) { | ||
let str = `<${toStringJsxName(node3.name)}`; | ||
const props = node3.attributes.map((attr) => { | ||
if (attr.type === "JSXAttribute") { | ||
return toStringJsxAttribute(attr); | ||
} else { | ||
return notSupported(node3); | ||
} | ||
}).filter((x) => x !== void 0); | ||
if (props.length > 0) { | ||
str += ` ${props.join(" ")}`; | ||
} | ||
}).filter((x) => x !== void 0); | ||
if (props.length > 0) { | ||
str += ` ${props.join(" ")}`; | ||
str += node3.selfClosing ? "/>" : ">"; | ||
return str; | ||
} | ||
str += node.selfClosing ? "/>" : ">"; | ||
return str; | ||
} | ||
function jsxAttributeToString(node) { | ||
let name = jsxNameToString(node.name); | ||
function toStringJsxAttribute(node2) { | ||
let name = toStringJsxName(node2.name); | ||
if (name === "className") | ||
@@ -157,4 +137,4 @@ name = "class"; | ||
let value; | ||
if (node.value) { | ||
const rawValue = jsxAttrValueToString(node.value, name); | ||
if (node2.value) { | ||
const rawValue = toStringJsxAttributeValue(node2.value, name); | ||
if (rawValue === null) { | ||
@@ -167,83 +147,245 @@ return void 0; | ||
} | ||
function jsxNameToString(node) { | ||
if (node.type === "JSXIdentifier") { | ||
return node.name; | ||
} else { | ||
return notSupported(node); | ||
function toStringJsxAttributeValue(node2, key) { | ||
let value; | ||
if ((0, import_types.isJSXExpressionContainer)(node2) && (0, import_types.isBooleanLiteral)(node2.expression)) { | ||
value = node2.expression.value ? void 0 : null; | ||
} else if ((0, import_types.isJSXExpressionContainer)(node2) && (0, import_types.isFunction)(node2.expression)) { | ||
value = getSource(node2.expression.body); | ||
} else if ((0, import_types.isJSX)(node2)) { | ||
value = resolveJsx(node2); | ||
if (key === "style" && isPlainObject(value)) { | ||
value = styleToString(value); | ||
} else if (key === "class" && Array.isArray(value) && value.every((e) => isPrimitive(e))) | ||
value = value.join(" "); | ||
} else if ((0, import_types.isStringLiteral)(node2)) { | ||
value = node2.value; | ||
} | ||
if (value === void 0 || value === null) | ||
return value; | ||
return toStringExpression(value); | ||
} | ||
function jsxAttrValueToString(node, key) { | ||
let value; | ||
if ((0, import_types.isJSXExpressionContainer)(node) && (0, import_types.isBooleanLiteral)(node.expression)) { | ||
value = node.expression.value ? void 0 : null; | ||
} else if ((0, import_types.isJSXExpressionContainer)(node) && (0, import_types.isFunction)(node.expression)) { | ||
value = getSource(node.expression.body); | ||
} else if ((0, import_types.isJSX)(node)) { | ||
value = jsxToString(node); | ||
if ((0, import_types.isJSXExpressionContainer)(node) && ((0, import_types.isObjectExpression)(node.expression) || (0, import_types.isArrayExpression)(node.expression))) { | ||
if (key === "style") { | ||
value = styleToString(JSON.parse(value)); | ||
} else if (key === "class") { | ||
const classes = JSON.parse(value); | ||
if (Array.isArray(classes)) | ||
value = classes.join(" "); | ||
} | ||
function toStringJsxName(node2) { | ||
if (node2.type === "JSXIdentifier") | ||
return node2.name; | ||
return notSupported(node2); | ||
} | ||
function resolveJsx(node2) { | ||
var _a; | ||
switch (node2.type) { | ||
case "JSXElement": | ||
return toStringJsxElement(node2); | ||
case "JSXFragment": | ||
return toStringJsxChildren(node2.children); | ||
case "JSXText": | ||
return toStringJsxText(node2); | ||
case "JSXEmptyExpression": | ||
return ((_a = node2.innerComments) == null ? void 0 : _a.map((comment) => `<!--${comment.value}-->`).join("")) ?? ""; | ||
case "JSXExpressionContainer": { | ||
return resolveExpression(node2.expression); | ||
} | ||
} else if ((0, import_types.isStringLiteral)(node)) { | ||
value = node.value; | ||
default: | ||
return notSupported(node2); | ||
} | ||
return value; | ||
} | ||
function resolveExpression(node) { | ||
if ((0, import_types.isLiteral)(node)) { | ||
return resolveLiteral(node); | ||
} else if ((0, import_types.isJSX)(node)) { | ||
return jsxToString(node); | ||
function resolveExpression(node2) { | ||
if ((0, import_types.isLiteral)(node2)) { | ||
return resolveLiteral(node2); | ||
} else if ((0, import_types.isJSX)(node2)) { | ||
return resolveJsx(node2); | ||
} | ||
switch (node.type) { | ||
switch (node2.type) { | ||
case "ArrayExpression": | ||
return resolveArrayExpression(node2); | ||
case "ObjectExpression": | ||
return parseObject(getSource(node)); | ||
return resolveObjectExpression(node2); | ||
case "BinaryExpression": | ||
return resolveExpression(node.left) + resolveExpression(node.right); | ||
case "LogicalExpression": | ||
return resolveBinary(node2); | ||
case "UnaryExpression": | ||
return resolveUnaryExpression(node2); | ||
case "ConditionalExpression": | ||
return resolveExpression(node2.test) ? resolveExpression(node2.consequent) : resolveExpression(node2.alternate); | ||
case "SequenceExpression": { | ||
const expressions = node2.expressions.map((expr) => resolveExpression(expr)); | ||
return expressions.slice(-1)[0]; | ||
} | ||
case "TSNonNullExpression": | ||
return resolveExpression(node2.expression); | ||
case "CallExpression": | ||
return resolveCallExpression(node2); | ||
default: | ||
return notSupported(node); | ||
return notSupported(node2); | ||
} | ||
} | ||
function resolveLiteral(node) { | ||
switch (node.type) { | ||
function resolveCallExpression(node2) { | ||
if (node2.callee.type === "Identifier" && node2.callee.name === "jsxRaw") { | ||
return `__RAW_${getSource(node2.arguments[0])}_RAW`; | ||
} | ||
return notSupported(node2); | ||
} | ||
function resolveBinary(node2) { | ||
const left = resolveExpression(node2.left); | ||
const right = resolveExpression(node2.right); | ||
switch (node2.operator) { | ||
case "+": | ||
return left + right; | ||
case "-": | ||
return left - right; | ||
case "*": | ||
return left * right; | ||
case "/": | ||
return left / right; | ||
case "&&": | ||
return left && right; | ||
case "||": | ||
return left || right; | ||
case "??": | ||
return left ?? right; | ||
case "==": | ||
return left == right; | ||
case "!=": | ||
return left != right; | ||
case "===": | ||
return left === right; | ||
case "!==": | ||
return left !== right; | ||
case ">": | ||
return left > right; | ||
case ">=": | ||
return left >= right; | ||
case "<": | ||
return left < right; | ||
case "<=": | ||
return left <= right; | ||
case "%": | ||
return left % right; | ||
case "**": | ||
return left ** right; | ||
case "&": | ||
return left & right; | ||
case "|": | ||
return left | right; | ||
case "^": | ||
return left ^ right; | ||
case "<<": | ||
return left << right; | ||
case ">>": | ||
return left >> right; | ||
case ">>>": | ||
return left >>> right; | ||
case "in": | ||
return left in right; | ||
case "instanceof": | ||
return left instanceof right; | ||
default: | ||
notSupported(node2); | ||
} | ||
} | ||
function resolveUnaryExpression(node2) { | ||
const value = resolveExpression(node2.argument); | ||
switch (node2.operator) { | ||
case "!": | ||
return !value; | ||
case "+": | ||
return +value; | ||
case "-": | ||
return -value; | ||
case "typeof": | ||
return typeof value; | ||
case "void": | ||
return void 0; | ||
case "~": | ||
return ~value; | ||
default: | ||
notSupported(node2); | ||
} | ||
} | ||
function resolveLiteral(node2) { | ||
switch (node2.type) { | ||
case "TemplateLiteral": | ||
return templateLiteralToString(node); | ||
return resolveTemplateLiteral(node2); | ||
case "NullLiteral": | ||
return null; | ||
case "BigIntLiteral": | ||
return BigInt(node.value); | ||
return BigInt(node2.value); | ||
case "RegExpLiteral": | ||
return new RegExp(node.pattern, node.flags); | ||
return new RegExp(node2.pattern, node2.flags); | ||
case "BooleanLiteral": | ||
case "NumericLiteral": | ||
case "StringLiteral": | ||
return node.value; | ||
return node2.value; | ||
default: | ||
return notSupported(node); | ||
return notSupported(node2); | ||
} | ||
} | ||
function templateLiteralToString(node) { | ||
return node.quasis.reduce((prev, curr, idx) => { | ||
if (node.expressions[idx]) { | ||
return prev + curr.value.cooked + resolveExpression(node.expressions[idx]); | ||
function resolveArrayExpression(node2) { | ||
const items = []; | ||
for (const [i, element] of node2.elements.entries()) { | ||
if (element) | ||
items[i] = resolveExpression(element); | ||
} | ||
return items; | ||
} | ||
function resolveObjectExpression(node2) { | ||
const obj = {}; | ||
for (const prop of node2.properties) { | ||
if (prop.type !== "ObjectProperty") | ||
return notSupported(prop); | ||
let key; | ||
if ((0, import_types.isIdentifier)(prop.key) && !prop.computed) { | ||
key = prop.key.name; | ||
} else { | ||
key = resolveExpression(prop.key); | ||
} | ||
obj[key] = resolveExpression(prop.value); | ||
} | ||
return obj; | ||
} | ||
function resolveTemplateLiteral(node2) { | ||
return node2.quasis.reduce((prev, curr, idx) => { | ||
if (node2.expressions[idx]) { | ||
return prev + curr.value.cooked + resolveExpression(node2.expressions[idx]); | ||
} | ||
return prev + curr.value.cooked; | ||
}, ""); | ||
} | ||
function getSource(node) { | ||
return code.slice(node.start, node.end); | ||
function getSource(node2) { | ||
return code.slice(node2.start, node2.end); | ||
} | ||
function notSupported(node) { | ||
throw new Error(`not supported ${node.type}: ${getSource(node)}`); | ||
function notSupported(node2) { | ||
throw new Error(`not supported ${node2.type}: ${getSource(node2)}`); | ||
} | ||
}; | ||
} | ||
function transformJsxToString(code, { | ||
debug, | ||
plugins, | ||
id = "" | ||
}) { | ||
const s = new import_magic_string.default(code); | ||
if (id.endsWith(".tsx")) | ||
plugins.push("typescript"); | ||
const nodes = extractJsx(code, plugins); | ||
for (const [node, expr] of nodes) { | ||
let str; | ||
if (!debug) { | ||
str = transformJsx(code, node); | ||
} else { | ||
try { | ||
str = transformJsx(code, node); | ||
} catch (err) { | ||
str = `(() => { throw new Error(${escapeString(err.toString())}) })()`; | ||
} | ||
} | ||
s.overwrite(expr.start, expr.end, str); | ||
} | ||
return { | ||
code: s.toString(), | ||
get map() { | ||
return s.generateMap(); | ||
} | ||
}; | ||
} | ||
// Annotate the CommonJS export names for ESM import in node: | ||
0 && (module.exports = { | ||
convert | ||
transformJsxToString | ||
}); |
@@ -10,3 +10,5 @@ import { ParserPlugin } from '@babel/parser'; | ||
* Plugins for `@babel/parser` | ||
* @default `['typescript', 'jsx']` | ||
* | ||
* If filename ends with `.tsx`, `typescript` will be automatically added to the default value. | ||
* @default `['jsx']` or `['jsx', 'typescript']`. | ||
*/ | ||
@@ -13,0 +15,0 @@ plugins?: ParserPlugin[]; |
@@ -0,1 +1,2 @@ | ||
"use strict"; | ||
var __defProp = Object.defineProperty; | ||
@@ -30,3 +31,3 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
debug: options.debug ?? false, | ||
plugins: ["typescript", "jsx"] | ||
plugins: ["jsx"] | ||
}; | ||
@@ -33,0 +34,0 @@ } |
@@ -0,6 +1,8 @@ | ||
declare type Primitive = null | undefined | string | number | boolean | symbol | bigint; | ||
declare function kebabCase(str: string): string; | ||
declare const styleToString: (styles: Record<string, string>) => string; | ||
declare const parseObject: (text: string) => any; | ||
declare const escapeString: (str: string) => string; | ||
declare const isPrimitive: (val: unknown) => val is Primitive; | ||
declare const isPlainObject: (obj: unknown) => obj is Record<any, any>; | ||
export { escapeString, kebabCase, parseObject, styleToString }; | ||
export { Primitive, escapeString, isPlainObject, isPrimitive, kebabCase, styleToString }; |
@@ -0,1 +1,2 @@ | ||
"use strict"; | ||
var __create = Object.create; | ||
@@ -26,8 +27,8 @@ var __defProp = Object.defineProperty; | ||
escapeString: () => escapeString, | ||
isPlainObject: () => isPlainObject, | ||
isPrimitive: () => isPrimitive, | ||
kebabCase: () => kebabCase, | ||
parseObject: () => parseObject, | ||
styleToString: () => styleToString | ||
}); | ||
module.exports = __toCommonJS(utils_exports); | ||
var import_json5 = __toESM(require("json5")); | ||
var import_jsesc = __toESM(require("jsesc")); | ||
@@ -41,16 +42,26 @@ var KEBAB_REGEX = /[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g; | ||
var styleToString = (styles) => Object.entries(styles).map(([key, value]) => `${kebabCase(key)}:${value}`).join(";"); | ||
var parseObject = (text) => { | ||
try { | ||
return import_json5.default.parse(text); | ||
} catch (err) { | ||
throw new SyntaxError(`Invalid attribute value: ${text}, error: ${err.message}`); | ||
} | ||
var RAW_RE = /__RAW_(.*?)_RAW/g; | ||
var escapeString = (str) => { | ||
const text = (0, import_jsesc.default)(str, { | ||
quotes: "backtick", | ||
wrap: true, | ||
es6: true | ||
}); | ||
return text.replaceAll(RAW_RE, "${$1}"); | ||
}; | ||
var escapeString = (str) => `'${(0, import_jsesc.default)(str)}'`; | ||
var isPrimitive = (val) => { | ||
if (typeof val === "object") | ||
return val === null; | ||
return typeof val !== "function"; | ||
}; | ||
var isPlainObject = (obj) => { | ||
return Object.prototype.toString.call(obj) === "[object Object]"; | ||
}; | ||
// Annotate the CommonJS export names for ESM import in node: | ||
0 && (module.exports = { | ||
escapeString, | ||
isPlainObject, | ||
isPrimitive, | ||
kebabCase, | ||
parseObject, | ||
styleToString | ||
}); |
@@ -1,5 +0,6 @@ | ||
export { convert } from './core/convert.js'; | ||
export { transformJsxToString } from './core/convert.js'; | ||
import 'magic-string'; | ||
import './core/utils.js'; | ||
import './core/options.js'; | ||
import '@babel/parser'; | ||
import '@rollup/pluginutils'; |
@@ -0,1 +1,2 @@ | ||
"use strict"; | ||
var __create = Object.create; | ||
@@ -25,3 +26,3 @@ var __defProp = Object.defineProperty; | ||
__export(cores_exports, { | ||
convert: () => convert | ||
transformJsxToString: () => transformJsxToString | ||
}); | ||
@@ -38,3 +39,2 @@ module.exports = __toCommonJS(cores_exports); | ||
// src/core/utils.ts | ||
var import_json5 = __toESM(require("json5")); | ||
var import_jsesc = __toESM(require("jsesc")); | ||
@@ -48,13 +48,22 @@ var KEBAB_REGEX = /[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g; | ||
var styleToString = (styles) => Object.entries(styles).map(([key, value]) => `${kebabCase(key)}:${value}`).join(";"); | ||
var parseObject = (text) => { | ||
try { | ||
return import_json5.default.parse(text); | ||
} catch (err) { | ||
throw new SyntaxError(`Invalid attribute value: ${text}, error: ${err.message}`); | ||
} | ||
var RAW_RE = /__RAW_(.*?)_RAW/g; | ||
var escapeString = (str) => { | ||
const text = (0, import_jsesc.default)(str, { | ||
quotes: "backtick", | ||
wrap: true, | ||
es6: true | ||
}); | ||
return text.replaceAll(RAW_RE, "${$1}"); | ||
}; | ||
var escapeString = (str) => `'${(0, import_jsesc.default)(str)}'`; | ||
var isPrimitive = (val) => { | ||
if (typeof val === "object") | ||
return val === null; | ||
return typeof val !== "function"; | ||
}; | ||
var isPlainObject = (obj) => { | ||
return Object.prototype.toString.call(obj) === "[object Object]"; | ||
}; | ||
// src/core/convert.ts | ||
var convert = (code, { debug, plugins }) => { | ||
function extractJsx(code, plugins) { | ||
const ast = (0, import_parser.parse)(code, { | ||
@@ -72,48 +81,22 @@ sourceType: "module", | ||
}); | ||
const s = new import_magic_string.default(code); | ||
for (const [node, expr] of nodes) { | ||
let str; | ||
if (!debug) { | ||
str = escapeString(jsxToString(node)); | ||
} else { | ||
try { | ||
str = escapeString(jsxToString(node)); | ||
} catch (err) { | ||
str = `(() => { throw new Error(${escapeString(err.toString())}) })()`; | ||
} | ||
} | ||
s.overwrite(expr.start, expr.end, str); | ||
return nodes; | ||
} | ||
function transformJsx(code, node) { | ||
return escapeString(toStringJsx(node)); | ||
function toStringJsx(node2) { | ||
return toStringExpression(resolveJsx(node2)); | ||
} | ||
return { | ||
code: s.toString(), | ||
get map() { | ||
return s.generateMap(); | ||
function toStringExpression(expr) { | ||
if (expr instanceof RegExp) { | ||
return expr.toString(); | ||
} else if (typeof expr === "object") { | ||
return JSON.stringify(expr); | ||
} | ||
}; | ||
function jsxToString(node) { | ||
var _a; | ||
switch (node.type) { | ||
case "JSXElement": | ||
return jsxElementToString(node); | ||
case "JSXFragment": | ||
return jsxChildrenToString(node.children); | ||
case "JSXText": | ||
return jsxTextToString(node); | ||
case "JSXEmptyExpression": | ||
return ((_a = node.innerComments) == null ? void 0 : _a.map((comment) => `<!--${comment.value}-->`).join("")) ?? ""; | ||
case "JSXExpressionContainer": { | ||
const expr = resolveExpression(node.expression); | ||
if (expr instanceof RegExp) { | ||
return expr.toString(); | ||
} else if (typeof expr === "object") { | ||
return JSON.stringify(expr); | ||
} | ||
return String(expr); | ||
} | ||
default: | ||
return notSupported(node); | ||
} | ||
return String(expr); | ||
} | ||
function jsxTextToString(node) { | ||
const texts = node.value.split("\n"); | ||
function toStringJsxChildren(nodes) { | ||
return nodes.map((child) => toStringJsx(child)).join(""); | ||
} | ||
function toStringJsxText(node2) { | ||
const texts = node2.value.split("\n"); | ||
return texts.map((text, idx) => idx > 0 ? text.trim() : text).filter((line) => { | ||
@@ -125,30 +108,27 @@ if (line.trim().length === 0) | ||
} | ||
function jsxElementToString(node) { | ||
if (node.openingElement.selfClosing) { | ||
return jsxOpeningElementToString(node.openingElement); | ||
function toStringJsxElement(node2) { | ||
if (node2.openingElement.selfClosing) { | ||
return toStringOpeningElement(node2.openingElement); | ||
} else { | ||
const children = jsxChildrenToString(node.children); | ||
return `${jsxOpeningElementToString(node.openingElement)}${children}</${jsxNameToString(node.closingElement.name)}>`; | ||
const children = toStringJsxChildren(node2.children); | ||
return `${toStringOpeningElement(node2.openingElement)}${children}</${toStringJsxName(node2.closingElement.name)}>`; | ||
} | ||
} | ||
function jsxChildrenToString(nodes2) { | ||
return nodes2.map((child) => jsxToString(child)).join(""); | ||
} | ||
function jsxOpeningElementToString(node) { | ||
let str = `<${jsxNameToString(node.name)}`; | ||
const props = node.attributes.map((attr) => { | ||
if (attr.type === "JSXAttribute") { | ||
return jsxAttributeToString(attr); | ||
} else { | ||
return notSupported(node); | ||
function toStringOpeningElement(node3) { | ||
let str = `<${toStringJsxName(node3.name)}`; | ||
const props = node3.attributes.map((attr) => { | ||
if (attr.type === "JSXAttribute") { | ||
return toStringJsxAttribute(attr); | ||
} else { | ||
return notSupported(node3); | ||
} | ||
}).filter((x) => x !== void 0); | ||
if (props.length > 0) { | ||
str += ` ${props.join(" ")}`; | ||
} | ||
}).filter((x) => x !== void 0); | ||
if (props.length > 0) { | ||
str += ` ${props.join(" ")}`; | ||
str += node3.selfClosing ? "/>" : ">"; | ||
return str; | ||
} | ||
str += node.selfClosing ? "/>" : ">"; | ||
return str; | ||
} | ||
function jsxAttributeToString(node) { | ||
let name = jsxNameToString(node.name); | ||
function toStringJsxAttribute(node2) { | ||
let name = toStringJsxName(node2.name); | ||
if (name === "className") | ||
@@ -159,4 +139,4 @@ name = "class"; | ||
let value; | ||
if (node.value) { | ||
const rawValue = jsxAttrValueToString(node.value, name); | ||
if (node2.value) { | ||
const rawValue = toStringJsxAttributeValue(node2.value, name); | ||
if (rawValue === null) { | ||
@@ -169,84 +149,246 @@ return void 0; | ||
} | ||
function jsxNameToString(node) { | ||
if (node.type === "JSXIdentifier") { | ||
return node.name; | ||
} else { | ||
return notSupported(node); | ||
function toStringJsxAttributeValue(node2, key) { | ||
let value; | ||
if ((0, import_types.isJSXExpressionContainer)(node2) && (0, import_types.isBooleanLiteral)(node2.expression)) { | ||
value = node2.expression.value ? void 0 : null; | ||
} else if ((0, import_types.isJSXExpressionContainer)(node2) && (0, import_types.isFunction)(node2.expression)) { | ||
value = getSource(node2.expression.body); | ||
} else if ((0, import_types.isJSX)(node2)) { | ||
value = resolveJsx(node2); | ||
if (key === "style" && isPlainObject(value)) { | ||
value = styleToString(value); | ||
} else if (key === "class" && Array.isArray(value) && value.every((e) => isPrimitive(e))) | ||
value = value.join(" "); | ||
} else if ((0, import_types.isStringLiteral)(node2)) { | ||
value = node2.value; | ||
} | ||
if (value === void 0 || value === null) | ||
return value; | ||
return toStringExpression(value); | ||
} | ||
function jsxAttrValueToString(node, key) { | ||
let value; | ||
if ((0, import_types.isJSXExpressionContainer)(node) && (0, import_types.isBooleanLiteral)(node.expression)) { | ||
value = node.expression.value ? void 0 : null; | ||
} else if ((0, import_types.isJSXExpressionContainer)(node) && (0, import_types.isFunction)(node.expression)) { | ||
value = getSource(node.expression.body); | ||
} else if ((0, import_types.isJSX)(node)) { | ||
value = jsxToString(node); | ||
if ((0, import_types.isJSXExpressionContainer)(node) && ((0, import_types.isObjectExpression)(node.expression) || (0, import_types.isArrayExpression)(node.expression))) { | ||
if (key === "style") { | ||
value = styleToString(JSON.parse(value)); | ||
} else if (key === "class") { | ||
const classes = JSON.parse(value); | ||
if (Array.isArray(classes)) | ||
value = classes.join(" "); | ||
} | ||
function toStringJsxName(node2) { | ||
if (node2.type === "JSXIdentifier") | ||
return node2.name; | ||
return notSupported(node2); | ||
} | ||
function resolveJsx(node2) { | ||
var _a; | ||
switch (node2.type) { | ||
case "JSXElement": | ||
return toStringJsxElement(node2); | ||
case "JSXFragment": | ||
return toStringJsxChildren(node2.children); | ||
case "JSXText": | ||
return toStringJsxText(node2); | ||
case "JSXEmptyExpression": | ||
return ((_a = node2.innerComments) == null ? void 0 : _a.map((comment) => `<!--${comment.value}-->`).join("")) ?? ""; | ||
case "JSXExpressionContainer": { | ||
return resolveExpression(node2.expression); | ||
} | ||
} else if ((0, import_types.isStringLiteral)(node)) { | ||
value = node.value; | ||
default: | ||
return notSupported(node2); | ||
} | ||
return value; | ||
} | ||
function resolveExpression(node) { | ||
if ((0, import_types.isLiteral)(node)) { | ||
return resolveLiteral(node); | ||
} else if ((0, import_types.isJSX)(node)) { | ||
return jsxToString(node); | ||
function resolveExpression(node2) { | ||
if ((0, import_types.isLiteral)(node2)) { | ||
return resolveLiteral(node2); | ||
} else if ((0, import_types.isJSX)(node2)) { | ||
return resolveJsx(node2); | ||
} | ||
switch (node.type) { | ||
switch (node2.type) { | ||
case "ArrayExpression": | ||
return resolveArrayExpression(node2); | ||
case "ObjectExpression": | ||
return parseObject(getSource(node)); | ||
return resolveObjectExpression(node2); | ||
case "BinaryExpression": | ||
return resolveExpression(node.left) + resolveExpression(node.right); | ||
case "LogicalExpression": | ||
return resolveBinary(node2); | ||
case "UnaryExpression": | ||
return resolveUnaryExpression(node2); | ||
case "ConditionalExpression": | ||
return resolveExpression(node2.test) ? resolveExpression(node2.consequent) : resolveExpression(node2.alternate); | ||
case "SequenceExpression": { | ||
const expressions = node2.expressions.map((expr) => resolveExpression(expr)); | ||
return expressions.slice(-1)[0]; | ||
} | ||
case "TSNonNullExpression": | ||
return resolveExpression(node2.expression); | ||
case "CallExpression": | ||
return resolveCallExpression(node2); | ||
default: | ||
return notSupported(node); | ||
return notSupported(node2); | ||
} | ||
} | ||
function resolveLiteral(node) { | ||
switch (node.type) { | ||
function resolveCallExpression(node2) { | ||
if (node2.callee.type === "Identifier" && node2.callee.name === "jsxRaw") { | ||
return `__RAW_${getSource(node2.arguments[0])}_RAW`; | ||
} | ||
return notSupported(node2); | ||
} | ||
function resolveBinary(node2) { | ||
const left = resolveExpression(node2.left); | ||
const right = resolveExpression(node2.right); | ||
switch (node2.operator) { | ||
case "+": | ||
return left + right; | ||
case "-": | ||
return left - right; | ||
case "*": | ||
return left * right; | ||
case "/": | ||
return left / right; | ||
case "&&": | ||
return left && right; | ||
case "||": | ||
return left || right; | ||
case "??": | ||
return left ?? right; | ||
case "==": | ||
return left == right; | ||
case "!=": | ||
return left != right; | ||
case "===": | ||
return left === right; | ||
case "!==": | ||
return left !== right; | ||
case ">": | ||
return left > right; | ||
case ">=": | ||
return left >= right; | ||
case "<": | ||
return left < right; | ||
case "<=": | ||
return left <= right; | ||
case "%": | ||
return left % right; | ||
case "**": | ||
return left ** right; | ||
case "&": | ||
return left & right; | ||
case "|": | ||
return left | right; | ||
case "^": | ||
return left ^ right; | ||
case "<<": | ||
return left << right; | ||
case ">>": | ||
return left >> right; | ||
case ">>>": | ||
return left >>> right; | ||
case "in": | ||
return left in right; | ||
case "instanceof": | ||
return left instanceof right; | ||
default: | ||
notSupported(node2); | ||
} | ||
} | ||
function resolveUnaryExpression(node2) { | ||
const value = resolveExpression(node2.argument); | ||
switch (node2.operator) { | ||
case "!": | ||
return !value; | ||
case "+": | ||
return +value; | ||
case "-": | ||
return -value; | ||
case "typeof": | ||
return typeof value; | ||
case "void": | ||
return void 0; | ||
case "~": | ||
return ~value; | ||
default: | ||
notSupported(node2); | ||
} | ||
} | ||
function resolveLiteral(node2) { | ||
switch (node2.type) { | ||
case "TemplateLiteral": | ||
return templateLiteralToString(node); | ||
return resolveTemplateLiteral(node2); | ||
case "NullLiteral": | ||
return null; | ||
case "BigIntLiteral": | ||
return BigInt(node.value); | ||
return BigInt(node2.value); | ||
case "RegExpLiteral": | ||
return new RegExp(node.pattern, node.flags); | ||
return new RegExp(node2.pattern, node2.flags); | ||
case "BooleanLiteral": | ||
case "NumericLiteral": | ||
case "StringLiteral": | ||
return node.value; | ||
return node2.value; | ||
default: | ||
return notSupported(node); | ||
return notSupported(node2); | ||
} | ||
} | ||
function templateLiteralToString(node) { | ||
return node.quasis.reduce((prev, curr, idx) => { | ||
if (node.expressions[idx]) { | ||
return prev + curr.value.cooked + resolveExpression(node.expressions[idx]); | ||
function resolveArrayExpression(node2) { | ||
const items = []; | ||
for (const [i, element] of node2.elements.entries()) { | ||
if (element) | ||
items[i] = resolveExpression(element); | ||
} | ||
return items; | ||
} | ||
function resolveObjectExpression(node2) { | ||
const obj = {}; | ||
for (const prop of node2.properties) { | ||
if (prop.type !== "ObjectProperty") | ||
return notSupported(prop); | ||
let key; | ||
if ((0, import_types.isIdentifier)(prop.key) && !prop.computed) { | ||
key = prop.key.name; | ||
} else { | ||
key = resolveExpression(prop.key); | ||
} | ||
obj[key] = resolveExpression(prop.value); | ||
} | ||
return obj; | ||
} | ||
function resolveTemplateLiteral(node2) { | ||
return node2.quasis.reduce((prev, curr, idx) => { | ||
if (node2.expressions[idx]) { | ||
return prev + curr.value.cooked + resolveExpression(node2.expressions[idx]); | ||
} | ||
return prev + curr.value.cooked; | ||
}, ""); | ||
} | ||
function getSource(node) { | ||
return code.slice(node.start, node.end); | ||
function getSource(node2) { | ||
return code.slice(node2.start, node2.end); | ||
} | ||
function notSupported(node) { | ||
throw new Error(`not supported ${node.type}: ${getSource(node)}`); | ||
function notSupported(node2) { | ||
throw new Error(`not supported ${node2.type}: ${getSource(node2)}`); | ||
} | ||
}; | ||
} | ||
function transformJsxToString(code, { | ||
debug, | ||
plugins, | ||
id = "" | ||
}) { | ||
const s = new import_magic_string.default(code); | ||
if (id.endsWith(".tsx")) | ||
plugins.push("typescript"); | ||
const nodes = extractJsx(code, plugins); | ||
for (const [node, expr] of nodes) { | ||
let str; | ||
if (!debug) { | ||
str = transformJsx(code, node); | ||
} else { | ||
try { | ||
str = transformJsx(code, node); | ||
} catch (err) { | ||
str = `(() => { throw new Error(${escapeString(err.toString())}) })()`; | ||
} | ||
} | ||
s.overwrite(expr.start, expr.end, str); | ||
} | ||
return { | ||
code: s.toString(), | ||
get map() { | ||
return s.generateMap(); | ||
} | ||
}; | ||
} | ||
// Annotate the CommonJS export names for ESM import in node: | ||
0 && (module.exports = { | ||
convert | ||
transformJsxToString | ||
}); | ||
exports.default = module.exports; |
@@ -0,7 +1,25 @@ | ||
"use strict"; | ||
var __create = Object.create; | ||
var __defProp = Object.defineProperty; | ||
var __defProps = Object.defineProperties; | ||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
var __getOwnPropDescs = Object.getOwnPropertyDescriptors; | ||
var __getOwnPropNames = Object.getOwnPropertyNames; | ||
var __getOwnPropSymbols = Object.getOwnPropertySymbols; | ||
var __getProtoOf = Object.getPrototypeOf; | ||
var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
var __propIsEnum = Object.prototype.propertyIsEnumerable; | ||
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; | ||
var __spreadValues = (a, b) => { | ||
for (var prop in b || (b = {})) | ||
if (__hasOwnProp.call(b, prop)) | ||
__defNormalProp(a, prop, b[prop]); | ||
if (__getOwnPropSymbols) | ||
for (var prop of __getOwnPropSymbols(b)) { | ||
if (__propIsEnum.call(b, prop)) | ||
__defNormalProp(a, prop, b[prop]); | ||
} | ||
return a; | ||
}; | ||
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); | ||
var __export = (target, all) => { | ||
@@ -41,3 +59,2 @@ for (var name in all) | ||
// src/core/utils.ts | ||
var import_json5 = __toESM(require("json5")); | ||
var import_jsesc = __toESM(require("jsesc")); | ||
@@ -51,13 +68,22 @@ var KEBAB_REGEX = /[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g; | ||
var styleToString = (styles) => Object.entries(styles).map(([key, value]) => `${kebabCase(key)}:${value}`).join(";"); | ||
var parseObject = (text) => { | ||
try { | ||
return import_json5.default.parse(text); | ||
} catch (err) { | ||
throw new SyntaxError(`Invalid attribute value: ${text}, error: ${err.message}`); | ||
} | ||
var RAW_RE = /__RAW_(.*?)_RAW/g; | ||
var escapeString = (str) => { | ||
const text = (0, import_jsesc.default)(str, { | ||
quotes: "backtick", | ||
wrap: true, | ||
es6: true | ||
}); | ||
return text.replaceAll(RAW_RE, "${$1}"); | ||
}; | ||
var escapeString = (str) => `'${(0, import_jsesc.default)(str)}'`; | ||
var isPrimitive = (val) => { | ||
if (typeof val === "object") | ||
return val === null; | ||
return typeof val !== "function"; | ||
}; | ||
var isPlainObject = (obj) => { | ||
return Object.prototype.toString.call(obj) === "[object Object]"; | ||
}; | ||
// src/core/convert.ts | ||
var convert = (code, { debug, plugins }) => { | ||
function extractJsx(code, plugins) { | ||
const ast = (0, import_parser.parse)(code, { | ||
@@ -75,48 +101,22 @@ sourceType: "module", | ||
}); | ||
const s = new import_magic_string.default(code); | ||
for (const [node, expr] of nodes) { | ||
let str; | ||
if (!debug) { | ||
str = escapeString(jsxToString(node)); | ||
} else { | ||
try { | ||
str = escapeString(jsxToString(node)); | ||
} catch (err) { | ||
str = `(() => { throw new Error(${escapeString(err.toString())}) })()`; | ||
} | ||
} | ||
s.overwrite(expr.start, expr.end, str); | ||
return nodes; | ||
} | ||
function transformJsx(code, node) { | ||
return escapeString(toStringJsx(node)); | ||
function toStringJsx(node2) { | ||
return toStringExpression(resolveJsx(node2)); | ||
} | ||
return { | ||
code: s.toString(), | ||
get map() { | ||
return s.generateMap(); | ||
function toStringExpression(expr) { | ||
if (expr instanceof RegExp) { | ||
return expr.toString(); | ||
} else if (typeof expr === "object") { | ||
return JSON.stringify(expr); | ||
} | ||
}; | ||
function jsxToString(node) { | ||
var _a; | ||
switch (node.type) { | ||
case "JSXElement": | ||
return jsxElementToString(node); | ||
case "JSXFragment": | ||
return jsxChildrenToString(node.children); | ||
case "JSXText": | ||
return jsxTextToString(node); | ||
case "JSXEmptyExpression": | ||
return ((_a = node.innerComments) == null ? void 0 : _a.map((comment) => `<!--${comment.value}-->`).join("")) ?? ""; | ||
case "JSXExpressionContainer": { | ||
const expr = resolveExpression(node.expression); | ||
if (expr instanceof RegExp) { | ||
return expr.toString(); | ||
} else if (typeof expr === "object") { | ||
return JSON.stringify(expr); | ||
} | ||
return String(expr); | ||
} | ||
default: | ||
return notSupported(node); | ||
} | ||
return String(expr); | ||
} | ||
function jsxTextToString(node) { | ||
const texts = node.value.split("\n"); | ||
function toStringJsxChildren(nodes) { | ||
return nodes.map((child) => toStringJsx(child)).join(""); | ||
} | ||
function toStringJsxText(node2) { | ||
const texts = node2.value.split("\n"); | ||
return texts.map((text, idx) => idx > 0 ? text.trim() : text).filter((line) => { | ||
@@ -128,30 +128,27 @@ if (line.trim().length === 0) | ||
} | ||
function jsxElementToString(node) { | ||
if (node.openingElement.selfClosing) { | ||
return jsxOpeningElementToString(node.openingElement); | ||
function toStringJsxElement(node2) { | ||
if (node2.openingElement.selfClosing) { | ||
return toStringOpeningElement(node2.openingElement); | ||
} else { | ||
const children = jsxChildrenToString(node.children); | ||
return `${jsxOpeningElementToString(node.openingElement)}${children}</${jsxNameToString(node.closingElement.name)}>`; | ||
const children = toStringJsxChildren(node2.children); | ||
return `${toStringOpeningElement(node2.openingElement)}${children}</${toStringJsxName(node2.closingElement.name)}>`; | ||
} | ||
} | ||
function jsxChildrenToString(nodes2) { | ||
return nodes2.map((child) => jsxToString(child)).join(""); | ||
} | ||
function jsxOpeningElementToString(node) { | ||
let str = `<${jsxNameToString(node.name)}`; | ||
const props = node.attributes.map((attr) => { | ||
if (attr.type === "JSXAttribute") { | ||
return jsxAttributeToString(attr); | ||
} else { | ||
return notSupported(node); | ||
function toStringOpeningElement(node3) { | ||
let str = `<${toStringJsxName(node3.name)}`; | ||
const props = node3.attributes.map((attr) => { | ||
if (attr.type === "JSXAttribute") { | ||
return toStringJsxAttribute(attr); | ||
} else { | ||
return notSupported(node3); | ||
} | ||
}).filter((x) => x !== void 0); | ||
if (props.length > 0) { | ||
str += ` ${props.join(" ")}`; | ||
} | ||
}).filter((x) => x !== void 0); | ||
if (props.length > 0) { | ||
str += ` ${props.join(" ")}`; | ||
str += node3.selfClosing ? "/>" : ">"; | ||
return str; | ||
} | ||
str += node.selfClosing ? "/>" : ">"; | ||
return str; | ||
} | ||
function jsxAttributeToString(node) { | ||
let name = jsxNameToString(node.name); | ||
function toStringJsxAttribute(node2) { | ||
let name = toStringJsxName(node2.name); | ||
if (name === "className") | ||
@@ -162,4 +159,4 @@ name = "class"; | ||
let value; | ||
if (node.value) { | ||
const rawValue = jsxAttrValueToString(node.value, name); | ||
if (node2.value) { | ||
const rawValue = toStringJsxAttributeValue(node2.value, name); | ||
if (rawValue === null) { | ||
@@ -172,80 +169,242 @@ return void 0; | ||
} | ||
function jsxNameToString(node) { | ||
if (node.type === "JSXIdentifier") { | ||
return node.name; | ||
} else { | ||
return notSupported(node); | ||
function toStringJsxAttributeValue(node2, key) { | ||
let value; | ||
if ((0, import_types.isJSXExpressionContainer)(node2) && (0, import_types.isBooleanLiteral)(node2.expression)) { | ||
value = node2.expression.value ? void 0 : null; | ||
} else if ((0, import_types.isJSXExpressionContainer)(node2) && (0, import_types.isFunction)(node2.expression)) { | ||
value = getSource(node2.expression.body); | ||
} else if ((0, import_types.isJSX)(node2)) { | ||
value = resolveJsx(node2); | ||
if (key === "style" && isPlainObject(value)) { | ||
value = styleToString(value); | ||
} else if (key === "class" && Array.isArray(value) && value.every((e) => isPrimitive(e))) | ||
value = value.join(" "); | ||
} else if ((0, import_types.isStringLiteral)(node2)) { | ||
value = node2.value; | ||
} | ||
if (value === void 0 || value === null) | ||
return value; | ||
return toStringExpression(value); | ||
} | ||
function jsxAttrValueToString(node, key) { | ||
let value; | ||
if ((0, import_types.isJSXExpressionContainer)(node) && (0, import_types.isBooleanLiteral)(node.expression)) { | ||
value = node.expression.value ? void 0 : null; | ||
} else if ((0, import_types.isJSXExpressionContainer)(node) && (0, import_types.isFunction)(node.expression)) { | ||
value = getSource(node.expression.body); | ||
} else if ((0, import_types.isJSX)(node)) { | ||
value = jsxToString(node); | ||
if ((0, import_types.isJSXExpressionContainer)(node) && ((0, import_types.isObjectExpression)(node.expression) || (0, import_types.isArrayExpression)(node.expression))) { | ||
if (key === "style") { | ||
value = styleToString(JSON.parse(value)); | ||
} else if (key === "class") { | ||
const classes = JSON.parse(value); | ||
if (Array.isArray(classes)) | ||
value = classes.join(" "); | ||
} | ||
function toStringJsxName(node2) { | ||
if (node2.type === "JSXIdentifier") | ||
return node2.name; | ||
return notSupported(node2); | ||
} | ||
function resolveJsx(node2) { | ||
var _a; | ||
switch (node2.type) { | ||
case "JSXElement": | ||
return toStringJsxElement(node2); | ||
case "JSXFragment": | ||
return toStringJsxChildren(node2.children); | ||
case "JSXText": | ||
return toStringJsxText(node2); | ||
case "JSXEmptyExpression": | ||
return ((_a = node2.innerComments) == null ? void 0 : _a.map((comment) => `<!--${comment.value}-->`).join("")) ?? ""; | ||
case "JSXExpressionContainer": { | ||
return resolveExpression(node2.expression); | ||
} | ||
} else if ((0, import_types.isStringLiteral)(node)) { | ||
value = node.value; | ||
default: | ||
return notSupported(node2); | ||
} | ||
return value; | ||
} | ||
function resolveExpression(node) { | ||
if ((0, import_types.isLiteral)(node)) { | ||
return resolveLiteral(node); | ||
} else if ((0, import_types.isJSX)(node)) { | ||
return jsxToString(node); | ||
function resolveExpression(node2) { | ||
if ((0, import_types.isLiteral)(node2)) { | ||
return resolveLiteral(node2); | ||
} else if ((0, import_types.isJSX)(node2)) { | ||
return resolveJsx(node2); | ||
} | ||
switch (node.type) { | ||
switch (node2.type) { | ||
case "ArrayExpression": | ||
return resolveArrayExpression(node2); | ||
case "ObjectExpression": | ||
return parseObject(getSource(node)); | ||
return resolveObjectExpression(node2); | ||
case "BinaryExpression": | ||
return resolveExpression(node.left) + resolveExpression(node.right); | ||
case "LogicalExpression": | ||
return resolveBinary(node2); | ||
case "UnaryExpression": | ||
return resolveUnaryExpression(node2); | ||
case "ConditionalExpression": | ||
return resolveExpression(node2.test) ? resolveExpression(node2.consequent) : resolveExpression(node2.alternate); | ||
case "SequenceExpression": { | ||
const expressions = node2.expressions.map((expr) => resolveExpression(expr)); | ||
return expressions.slice(-1)[0]; | ||
} | ||
case "TSNonNullExpression": | ||
return resolveExpression(node2.expression); | ||
case "CallExpression": | ||
return resolveCallExpression(node2); | ||
default: | ||
return notSupported(node); | ||
return notSupported(node2); | ||
} | ||
} | ||
function resolveLiteral(node) { | ||
switch (node.type) { | ||
function resolveCallExpression(node2) { | ||
if (node2.callee.type === "Identifier" && node2.callee.name === "jsxRaw") { | ||
return `__RAW_${getSource(node2.arguments[0])}_RAW`; | ||
} | ||
return notSupported(node2); | ||
} | ||
function resolveBinary(node2) { | ||
const left = resolveExpression(node2.left); | ||
const right = resolveExpression(node2.right); | ||
switch (node2.operator) { | ||
case "+": | ||
return left + right; | ||
case "-": | ||
return left - right; | ||
case "*": | ||
return left * right; | ||
case "/": | ||
return left / right; | ||
case "&&": | ||
return left && right; | ||
case "||": | ||
return left || right; | ||
case "??": | ||
return left ?? right; | ||
case "==": | ||
return left == right; | ||
case "!=": | ||
return left != right; | ||
case "===": | ||
return left === right; | ||
case "!==": | ||
return left !== right; | ||
case ">": | ||
return left > right; | ||
case ">=": | ||
return left >= right; | ||
case "<": | ||
return left < right; | ||
case "<=": | ||
return left <= right; | ||
case "%": | ||
return left % right; | ||
case "**": | ||
return left ** right; | ||
case "&": | ||
return left & right; | ||
case "|": | ||
return left | right; | ||
case "^": | ||
return left ^ right; | ||
case "<<": | ||
return left << right; | ||
case ">>": | ||
return left >> right; | ||
case ">>>": | ||
return left >>> right; | ||
case "in": | ||
return left in right; | ||
case "instanceof": | ||
return left instanceof right; | ||
default: | ||
notSupported(node2); | ||
} | ||
} | ||
function resolveUnaryExpression(node2) { | ||
const value = resolveExpression(node2.argument); | ||
switch (node2.operator) { | ||
case "!": | ||
return !value; | ||
case "+": | ||
return +value; | ||
case "-": | ||
return -value; | ||
case "typeof": | ||
return typeof value; | ||
case "void": | ||
return void 0; | ||
case "~": | ||
return ~value; | ||
default: | ||
notSupported(node2); | ||
} | ||
} | ||
function resolveLiteral(node2) { | ||
switch (node2.type) { | ||
case "TemplateLiteral": | ||
return templateLiteralToString(node); | ||
return resolveTemplateLiteral(node2); | ||
case "NullLiteral": | ||
return null; | ||
case "BigIntLiteral": | ||
return BigInt(node.value); | ||
return BigInt(node2.value); | ||
case "RegExpLiteral": | ||
return new RegExp(node.pattern, node.flags); | ||
return new RegExp(node2.pattern, node2.flags); | ||
case "BooleanLiteral": | ||
case "NumericLiteral": | ||
case "StringLiteral": | ||
return node.value; | ||
return node2.value; | ||
default: | ||
return notSupported(node); | ||
return notSupported(node2); | ||
} | ||
} | ||
function templateLiteralToString(node) { | ||
return node.quasis.reduce((prev, curr, idx) => { | ||
if (node.expressions[idx]) { | ||
return prev + curr.value.cooked + resolveExpression(node.expressions[idx]); | ||
function resolveArrayExpression(node2) { | ||
const items = []; | ||
for (const [i, element] of node2.elements.entries()) { | ||
if (element) | ||
items[i] = resolveExpression(element); | ||
} | ||
return items; | ||
} | ||
function resolveObjectExpression(node2) { | ||
const obj = {}; | ||
for (const prop of node2.properties) { | ||
if (prop.type !== "ObjectProperty") | ||
return notSupported(prop); | ||
let key; | ||
if ((0, import_types.isIdentifier)(prop.key) && !prop.computed) { | ||
key = prop.key.name; | ||
} else { | ||
key = resolveExpression(prop.key); | ||
} | ||
obj[key] = resolveExpression(prop.value); | ||
} | ||
return obj; | ||
} | ||
function resolveTemplateLiteral(node2) { | ||
return node2.quasis.reduce((prev, curr, idx) => { | ||
if (node2.expressions[idx]) { | ||
return prev + curr.value.cooked + resolveExpression(node2.expressions[idx]); | ||
} | ||
return prev + curr.value.cooked; | ||
}, ""); | ||
} | ||
function getSource(node) { | ||
return code.slice(node.start, node.end); | ||
function getSource(node2) { | ||
return code.slice(node2.start, node2.end); | ||
} | ||
function notSupported(node) { | ||
throw new Error(`not supported ${node.type}: ${getSource(node)}`); | ||
function notSupported(node2) { | ||
throw new Error(`not supported ${node2.type}: ${getSource(node2)}`); | ||
} | ||
}; | ||
} | ||
function transformJsxToString(code, { | ||
debug, | ||
plugins, | ||
id = "" | ||
}) { | ||
const s = new import_magic_string.default(code); | ||
if (id.endsWith(".tsx")) | ||
plugins.push("typescript"); | ||
const nodes = extractJsx(code, plugins); | ||
for (const [node, expr] of nodes) { | ||
let str; | ||
if (!debug) { | ||
str = transformJsx(code, node); | ||
} else { | ||
try { | ||
str = transformJsx(code, node); | ||
} catch (err) { | ||
str = `(() => { throw new Error(${escapeString(err.toString())}) })()`; | ||
} | ||
} | ||
s.overwrite(expr.start, expr.end, str); | ||
} | ||
return { | ||
code: s.toString(), | ||
get map() { | ||
return s.generateMap(); | ||
} | ||
}; | ||
} | ||
@@ -258,3 +417,3 @@ // src/core/options.ts | ||
debug: options.debug ?? false, | ||
plugins: ["typescript", "jsx"] | ||
plugins: ["jsx"] | ||
}; | ||
@@ -274,5 +433,7 @@ } | ||
}, | ||
transform(code) { | ||
transform(code, id) { | ||
try { | ||
return convert(code, opt); | ||
return transformJsxToString(code, __spreadProps(__spreadValues({}, opt), { | ||
id | ||
})); | ||
} catch (err) { | ||
@@ -279,0 +440,0 @@ this.error(`${name} ${err}`); |
@@ -8,2 +8,3 @@ import * as unplugin from 'unplugin'; | ||
const jsxToString: (element: JSX.Element) => string; | ||
const jsxRaw: (variable: any) => any; | ||
} | ||
@@ -10,0 +11,0 @@ declare const _default: unplugin.UnpluginInstance<Options>; |
@@ -0,7 +1,25 @@ | ||
"use strict"; | ||
var __create = Object.create; | ||
var __defProp = Object.defineProperty; | ||
var __defProps = Object.defineProperties; | ||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
var __getOwnPropDescs = Object.getOwnPropertyDescriptors; | ||
var __getOwnPropNames = Object.getOwnPropertyNames; | ||
var __getOwnPropSymbols = Object.getOwnPropertySymbols; | ||
var __getProtoOf = Object.getPrototypeOf; | ||
var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
var __propIsEnum = Object.prototype.propertyIsEnumerable; | ||
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; | ||
var __spreadValues = (a, b) => { | ||
for (var prop in b || (b = {})) | ||
if (__hasOwnProp.call(b, prop)) | ||
__defNormalProp(a, prop, b[prop]); | ||
if (__getOwnPropSymbols) | ||
for (var prop of __getOwnPropSymbols(b)) { | ||
if (__propIsEnum.call(b, prop)) | ||
__defNormalProp(a, prop, b[prop]); | ||
} | ||
return a; | ||
}; | ||
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); | ||
var __export = (target, all) => { | ||
@@ -39,3 +57,2 @@ for (var name in all) | ||
// src/core/utils.ts | ||
var import_json5 = __toESM(require("json5")); | ||
var import_jsesc = __toESM(require("jsesc")); | ||
@@ -49,13 +66,22 @@ var KEBAB_REGEX = /[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g; | ||
var styleToString = (styles) => Object.entries(styles).map(([key, value]) => `${kebabCase(key)}:${value}`).join(";"); | ||
var parseObject = (text) => { | ||
try { | ||
return import_json5.default.parse(text); | ||
} catch (err) { | ||
throw new SyntaxError(`Invalid attribute value: ${text}, error: ${err.message}`); | ||
} | ||
var RAW_RE = /__RAW_(.*?)_RAW/g; | ||
var escapeString = (str) => { | ||
const text = (0, import_jsesc.default)(str, { | ||
quotes: "backtick", | ||
wrap: true, | ||
es6: true | ||
}); | ||
return text.replaceAll(RAW_RE, "${$1}"); | ||
}; | ||
var escapeString = (str) => `'${(0, import_jsesc.default)(str)}'`; | ||
var isPrimitive = (val) => { | ||
if (typeof val === "object") | ||
return val === null; | ||
return typeof val !== "function"; | ||
}; | ||
var isPlainObject = (obj) => { | ||
return Object.prototype.toString.call(obj) === "[object Object]"; | ||
}; | ||
// src/core/convert.ts | ||
var convert = (code, { debug, plugins }) => { | ||
function extractJsx(code, plugins) { | ||
const ast = (0, import_parser.parse)(code, { | ||
@@ -73,48 +99,22 @@ sourceType: "module", | ||
}); | ||
const s = new import_magic_string.default(code); | ||
for (const [node, expr] of nodes) { | ||
let str; | ||
if (!debug) { | ||
str = escapeString(jsxToString(node)); | ||
} else { | ||
try { | ||
str = escapeString(jsxToString(node)); | ||
} catch (err) { | ||
str = `(() => { throw new Error(${escapeString(err.toString())}) })()`; | ||
} | ||
} | ||
s.overwrite(expr.start, expr.end, str); | ||
return nodes; | ||
} | ||
function transformJsx(code, node) { | ||
return escapeString(toStringJsx(node)); | ||
function toStringJsx(node2) { | ||
return toStringExpression(resolveJsx(node2)); | ||
} | ||
return { | ||
code: s.toString(), | ||
get map() { | ||
return s.generateMap(); | ||
function toStringExpression(expr) { | ||
if (expr instanceof RegExp) { | ||
return expr.toString(); | ||
} else if (typeof expr === "object") { | ||
return JSON.stringify(expr); | ||
} | ||
}; | ||
function jsxToString(node) { | ||
var _a; | ||
switch (node.type) { | ||
case "JSXElement": | ||
return jsxElementToString(node); | ||
case "JSXFragment": | ||
return jsxChildrenToString(node.children); | ||
case "JSXText": | ||
return jsxTextToString(node); | ||
case "JSXEmptyExpression": | ||
return ((_a = node.innerComments) == null ? void 0 : _a.map((comment) => `<!--${comment.value}-->`).join("")) ?? ""; | ||
case "JSXExpressionContainer": { | ||
const expr = resolveExpression(node.expression); | ||
if (expr instanceof RegExp) { | ||
return expr.toString(); | ||
} else if (typeof expr === "object") { | ||
return JSON.stringify(expr); | ||
} | ||
return String(expr); | ||
} | ||
default: | ||
return notSupported(node); | ||
} | ||
return String(expr); | ||
} | ||
function jsxTextToString(node) { | ||
const texts = node.value.split("\n"); | ||
function toStringJsxChildren(nodes) { | ||
return nodes.map((child) => toStringJsx(child)).join(""); | ||
} | ||
function toStringJsxText(node2) { | ||
const texts = node2.value.split("\n"); | ||
return texts.map((text, idx) => idx > 0 ? text.trim() : text).filter((line) => { | ||
@@ -126,30 +126,27 @@ if (line.trim().length === 0) | ||
} | ||
function jsxElementToString(node) { | ||
if (node.openingElement.selfClosing) { | ||
return jsxOpeningElementToString(node.openingElement); | ||
function toStringJsxElement(node2) { | ||
if (node2.openingElement.selfClosing) { | ||
return toStringOpeningElement(node2.openingElement); | ||
} else { | ||
const children = jsxChildrenToString(node.children); | ||
return `${jsxOpeningElementToString(node.openingElement)}${children}</${jsxNameToString(node.closingElement.name)}>`; | ||
const children = toStringJsxChildren(node2.children); | ||
return `${toStringOpeningElement(node2.openingElement)}${children}</${toStringJsxName(node2.closingElement.name)}>`; | ||
} | ||
} | ||
function jsxChildrenToString(nodes2) { | ||
return nodes2.map((child) => jsxToString(child)).join(""); | ||
} | ||
function jsxOpeningElementToString(node) { | ||
let str = `<${jsxNameToString(node.name)}`; | ||
const props = node.attributes.map((attr) => { | ||
if (attr.type === "JSXAttribute") { | ||
return jsxAttributeToString(attr); | ||
} else { | ||
return notSupported(node); | ||
function toStringOpeningElement(node3) { | ||
let str = `<${toStringJsxName(node3.name)}`; | ||
const props = node3.attributes.map((attr) => { | ||
if (attr.type === "JSXAttribute") { | ||
return toStringJsxAttribute(attr); | ||
} else { | ||
return notSupported(node3); | ||
} | ||
}).filter((x) => x !== void 0); | ||
if (props.length > 0) { | ||
str += ` ${props.join(" ")}`; | ||
} | ||
}).filter((x) => x !== void 0); | ||
if (props.length > 0) { | ||
str += ` ${props.join(" ")}`; | ||
str += node3.selfClosing ? "/>" : ">"; | ||
return str; | ||
} | ||
str += node.selfClosing ? "/>" : ">"; | ||
return str; | ||
} | ||
function jsxAttributeToString(node) { | ||
let name = jsxNameToString(node.name); | ||
function toStringJsxAttribute(node2) { | ||
let name = toStringJsxName(node2.name); | ||
if (name === "className") | ||
@@ -160,4 +157,4 @@ name = "class"; | ||
let value; | ||
if (node.value) { | ||
const rawValue = jsxAttrValueToString(node.value, name); | ||
if (node2.value) { | ||
const rawValue = toStringJsxAttributeValue(node2.value, name); | ||
if (rawValue === null) { | ||
@@ -170,80 +167,242 @@ return void 0; | ||
} | ||
function jsxNameToString(node) { | ||
if (node.type === "JSXIdentifier") { | ||
return node.name; | ||
} else { | ||
return notSupported(node); | ||
function toStringJsxAttributeValue(node2, key) { | ||
let value; | ||
if ((0, import_types.isJSXExpressionContainer)(node2) && (0, import_types.isBooleanLiteral)(node2.expression)) { | ||
value = node2.expression.value ? void 0 : null; | ||
} else if ((0, import_types.isJSXExpressionContainer)(node2) && (0, import_types.isFunction)(node2.expression)) { | ||
value = getSource(node2.expression.body); | ||
} else if ((0, import_types.isJSX)(node2)) { | ||
value = resolveJsx(node2); | ||
if (key === "style" && isPlainObject(value)) { | ||
value = styleToString(value); | ||
} else if (key === "class" && Array.isArray(value) && value.every((e) => isPrimitive(e))) | ||
value = value.join(" "); | ||
} else if ((0, import_types.isStringLiteral)(node2)) { | ||
value = node2.value; | ||
} | ||
if (value === void 0 || value === null) | ||
return value; | ||
return toStringExpression(value); | ||
} | ||
function jsxAttrValueToString(node, key) { | ||
let value; | ||
if ((0, import_types.isJSXExpressionContainer)(node) && (0, import_types.isBooleanLiteral)(node.expression)) { | ||
value = node.expression.value ? void 0 : null; | ||
} else if ((0, import_types.isJSXExpressionContainer)(node) && (0, import_types.isFunction)(node.expression)) { | ||
value = getSource(node.expression.body); | ||
} else if ((0, import_types.isJSX)(node)) { | ||
value = jsxToString(node); | ||
if ((0, import_types.isJSXExpressionContainer)(node) && ((0, import_types.isObjectExpression)(node.expression) || (0, import_types.isArrayExpression)(node.expression))) { | ||
if (key === "style") { | ||
value = styleToString(JSON.parse(value)); | ||
} else if (key === "class") { | ||
const classes = JSON.parse(value); | ||
if (Array.isArray(classes)) | ||
value = classes.join(" "); | ||
} | ||
function toStringJsxName(node2) { | ||
if (node2.type === "JSXIdentifier") | ||
return node2.name; | ||
return notSupported(node2); | ||
} | ||
function resolveJsx(node2) { | ||
var _a; | ||
switch (node2.type) { | ||
case "JSXElement": | ||
return toStringJsxElement(node2); | ||
case "JSXFragment": | ||
return toStringJsxChildren(node2.children); | ||
case "JSXText": | ||
return toStringJsxText(node2); | ||
case "JSXEmptyExpression": | ||
return ((_a = node2.innerComments) == null ? void 0 : _a.map((comment) => `<!--${comment.value}-->`).join("")) ?? ""; | ||
case "JSXExpressionContainer": { | ||
return resolveExpression(node2.expression); | ||
} | ||
} else if ((0, import_types.isStringLiteral)(node)) { | ||
value = node.value; | ||
default: | ||
return notSupported(node2); | ||
} | ||
return value; | ||
} | ||
function resolveExpression(node) { | ||
if ((0, import_types.isLiteral)(node)) { | ||
return resolveLiteral(node); | ||
} else if ((0, import_types.isJSX)(node)) { | ||
return jsxToString(node); | ||
function resolveExpression(node2) { | ||
if ((0, import_types.isLiteral)(node2)) { | ||
return resolveLiteral(node2); | ||
} else if ((0, import_types.isJSX)(node2)) { | ||
return resolveJsx(node2); | ||
} | ||
switch (node.type) { | ||
switch (node2.type) { | ||
case "ArrayExpression": | ||
return resolveArrayExpression(node2); | ||
case "ObjectExpression": | ||
return parseObject(getSource(node)); | ||
return resolveObjectExpression(node2); | ||
case "BinaryExpression": | ||
return resolveExpression(node.left) + resolveExpression(node.right); | ||
case "LogicalExpression": | ||
return resolveBinary(node2); | ||
case "UnaryExpression": | ||
return resolveUnaryExpression(node2); | ||
case "ConditionalExpression": | ||
return resolveExpression(node2.test) ? resolveExpression(node2.consequent) : resolveExpression(node2.alternate); | ||
case "SequenceExpression": { | ||
const expressions = node2.expressions.map((expr) => resolveExpression(expr)); | ||
return expressions.slice(-1)[0]; | ||
} | ||
case "TSNonNullExpression": | ||
return resolveExpression(node2.expression); | ||
case "CallExpression": | ||
return resolveCallExpression(node2); | ||
default: | ||
return notSupported(node); | ||
return notSupported(node2); | ||
} | ||
} | ||
function resolveLiteral(node) { | ||
switch (node.type) { | ||
function resolveCallExpression(node2) { | ||
if (node2.callee.type === "Identifier" && node2.callee.name === "jsxRaw") { | ||
return `__RAW_${getSource(node2.arguments[0])}_RAW`; | ||
} | ||
return notSupported(node2); | ||
} | ||
function resolveBinary(node2) { | ||
const left = resolveExpression(node2.left); | ||
const right = resolveExpression(node2.right); | ||
switch (node2.operator) { | ||
case "+": | ||
return left + right; | ||
case "-": | ||
return left - right; | ||
case "*": | ||
return left * right; | ||
case "/": | ||
return left / right; | ||
case "&&": | ||
return left && right; | ||
case "||": | ||
return left || right; | ||
case "??": | ||
return left ?? right; | ||
case "==": | ||
return left == right; | ||
case "!=": | ||
return left != right; | ||
case "===": | ||
return left === right; | ||
case "!==": | ||
return left !== right; | ||
case ">": | ||
return left > right; | ||
case ">=": | ||
return left >= right; | ||
case "<": | ||
return left < right; | ||
case "<=": | ||
return left <= right; | ||
case "%": | ||
return left % right; | ||
case "**": | ||
return left ** right; | ||
case "&": | ||
return left & right; | ||
case "|": | ||
return left | right; | ||
case "^": | ||
return left ^ right; | ||
case "<<": | ||
return left << right; | ||
case ">>": | ||
return left >> right; | ||
case ">>>": | ||
return left >>> right; | ||
case "in": | ||
return left in right; | ||
case "instanceof": | ||
return left instanceof right; | ||
default: | ||
notSupported(node2); | ||
} | ||
} | ||
function resolveUnaryExpression(node2) { | ||
const value = resolveExpression(node2.argument); | ||
switch (node2.operator) { | ||
case "!": | ||
return !value; | ||
case "+": | ||
return +value; | ||
case "-": | ||
return -value; | ||
case "typeof": | ||
return typeof value; | ||
case "void": | ||
return void 0; | ||
case "~": | ||
return ~value; | ||
default: | ||
notSupported(node2); | ||
} | ||
} | ||
function resolveLiteral(node2) { | ||
switch (node2.type) { | ||
case "TemplateLiteral": | ||
return templateLiteralToString(node); | ||
return resolveTemplateLiteral(node2); | ||
case "NullLiteral": | ||
return null; | ||
case "BigIntLiteral": | ||
return BigInt(node.value); | ||
return BigInt(node2.value); | ||
case "RegExpLiteral": | ||
return new RegExp(node.pattern, node.flags); | ||
return new RegExp(node2.pattern, node2.flags); | ||
case "BooleanLiteral": | ||
case "NumericLiteral": | ||
case "StringLiteral": | ||
return node.value; | ||
return node2.value; | ||
default: | ||
return notSupported(node); | ||
return notSupported(node2); | ||
} | ||
} | ||
function templateLiteralToString(node) { | ||
return node.quasis.reduce((prev, curr, idx) => { | ||
if (node.expressions[idx]) { | ||
return prev + curr.value.cooked + resolveExpression(node.expressions[idx]); | ||
function resolveArrayExpression(node2) { | ||
const items = []; | ||
for (const [i, element] of node2.elements.entries()) { | ||
if (element) | ||
items[i] = resolveExpression(element); | ||
} | ||
return items; | ||
} | ||
function resolveObjectExpression(node2) { | ||
const obj = {}; | ||
for (const prop of node2.properties) { | ||
if (prop.type !== "ObjectProperty") | ||
return notSupported(prop); | ||
let key; | ||
if ((0, import_types.isIdentifier)(prop.key) && !prop.computed) { | ||
key = prop.key.name; | ||
} else { | ||
key = resolveExpression(prop.key); | ||
} | ||
obj[key] = resolveExpression(prop.value); | ||
} | ||
return obj; | ||
} | ||
function resolveTemplateLiteral(node2) { | ||
return node2.quasis.reduce((prev, curr, idx) => { | ||
if (node2.expressions[idx]) { | ||
return prev + curr.value.cooked + resolveExpression(node2.expressions[idx]); | ||
} | ||
return prev + curr.value.cooked; | ||
}, ""); | ||
} | ||
function getSource(node) { | ||
return code.slice(node.start, node.end); | ||
function getSource(node2) { | ||
return code.slice(node2.start, node2.end); | ||
} | ||
function notSupported(node) { | ||
throw new Error(`not supported ${node.type}: ${getSource(node)}`); | ||
function notSupported(node2) { | ||
throw new Error(`not supported ${node2.type}: ${getSource(node2)}`); | ||
} | ||
}; | ||
} | ||
function transformJsxToString(code, { | ||
debug, | ||
plugins, | ||
id = "" | ||
}) { | ||
const s = new import_magic_string.default(code); | ||
if (id.endsWith(".tsx")) | ||
plugins.push("typescript"); | ||
const nodes = extractJsx(code, plugins); | ||
for (const [node, expr] of nodes) { | ||
let str; | ||
if (!debug) { | ||
str = transformJsx(code, node); | ||
} else { | ||
try { | ||
str = transformJsx(code, node); | ||
} catch (err) { | ||
str = `(() => { throw new Error(${escapeString(err.toString())}) })()`; | ||
} | ||
} | ||
s.overwrite(expr.start, expr.end, str); | ||
} | ||
return { | ||
code: s.toString(), | ||
get map() { | ||
return s.generateMap(); | ||
} | ||
}; | ||
} | ||
@@ -256,3 +415,3 @@ // src/core/options.ts | ||
debug: options.debug ?? false, | ||
plugins: ["typescript", "jsx"] | ||
plugins: ["jsx"] | ||
}; | ||
@@ -272,5 +431,7 @@ } | ||
}, | ||
transform(code) { | ||
transform(code, id) { | ||
try { | ||
return convert(code, opt); | ||
return transformJsxToString(code, __spreadProps(__spreadValues({}, opt), { | ||
id | ||
})); | ||
} catch (err) { | ||
@@ -277,0 +438,0 @@ this.error(`${name} ${err}`); |
@@ -0,7 +1,25 @@ | ||
"use strict"; | ||
var __create = Object.create; | ||
var __defProp = Object.defineProperty; | ||
var __defProps = Object.defineProperties; | ||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
var __getOwnPropDescs = Object.getOwnPropertyDescriptors; | ||
var __getOwnPropNames = Object.getOwnPropertyNames; | ||
var __getOwnPropSymbols = Object.getOwnPropertySymbols; | ||
var __getProtoOf = Object.getPrototypeOf; | ||
var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
var __propIsEnum = Object.prototype.propertyIsEnumerable; | ||
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; | ||
var __spreadValues = (a, b) => { | ||
for (var prop in b || (b = {})) | ||
if (__hasOwnProp.call(b, prop)) | ||
__defNormalProp(a, prop, b[prop]); | ||
if (__getOwnPropSymbols) | ||
for (var prop of __getOwnPropSymbols(b)) { | ||
if (__propIsEnum.call(b, prop)) | ||
__defNormalProp(a, prop, b[prop]); | ||
} | ||
return a; | ||
}; | ||
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); | ||
var __export = (target, all) => { | ||
@@ -41,3 +59,2 @@ for (var name in all) | ||
// src/core/utils.ts | ||
var import_json5 = __toESM(require("json5")); | ||
var import_jsesc = __toESM(require("jsesc")); | ||
@@ -51,13 +68,22 @@ var KEBAB_REGEX = /[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g; | ||
var styleToString = (styles) => Object.entries(styles).map(([key, value]) => `${kebabCase(key)}:${value}`).join(";"); | ||
var parseObject = (text) => { | ||
try { | ||
return import_json5.default.parse(text); | ||
} catch (err) { | ||
throw new SyntaxError(`Invalid attribute value: ${text}, error: ${err.message}`); | ||
} | ||
var RAW_RE = /__RAW_(.*?)_RAW/g; | ||
var escapeString = (str) => { | ||
const text = (0, import_jsesc.default)(str, { | ||
quotes: "backtick", | ||
wrap: true, | ||
es6: true | ||
}); | ||
return text.replaceAll(RAW_RE, "${$1}"); | ||
}; | ||
var escapeString = (str) => `'${(0, import_jsesc.default)(str)}'`; | ||
var isPrimitive = (val) => { | ||
if (typeof val === "object") | ||
return val === null; | ||
return typeof val !== "function"; | ||
}; | ||
var isPlainObject = (obj) => { | ||
return Object.prototype.toString.call(obj) === "[object Object]"; | ||
}; | ||
// src/core/convert.ts | ||
var convert = (code, { debug, plugins }) => { | ||
function extractJsx(code, plugins) { | ||
const ast = (0, import_parser.parse)(code, { | ||
@@ -75,48 +101,22 @@ sourceType: "module", | ||
}); | ||
const s = new import_magic_string.default(code); | ||
for (const [node, expr] of nodes) { | ||
let str; | ||
if (!debug) { | ||
str = escapeString(jsxToString(node)); | ||
} else { | ||
try { | ||
str = escapeString(jsxToString(node)); | ||
} catch (err) { | ||
str = `(() => { throw new Error(${escapeString(err.toString())}) })()`; | ||
} | ||
} | ||
s.overwrite(expr.start, expr.end, str); | ||
return nodes; | ||
} | ||
function transformJsx(code, node) { | ||
return escapeString(toStringJsx(node)); | ||
function toStringJsx(node2) { | ||
return toStringExpression(resolveJsx(node2)); | ||
} | ||
return { | ||
code: s.toString(), | ||
get map() { | ||
return s.generateMap(); | ||
function toStringExpression(expr) { | ||
if (expr instanceof RegExp) { | ||
return expr.toString(); | ||
} else if (typeof expr === "object") { | ||
return JSON.stringify(expr); | ||
} | ||
}; | ||
function jsxToString(node) { | ||
var _a; | ||
switch (node.type) { | ||
case "JSXElement": | ||
return jsxElementToString(node); | ||
case "JSXFragment": | ||
return jsxChildrenToString(node.children); | ||
case "JSXText": | ||
return jsxTextToString(node); | ||
case "JSXEmptyExpression": | ||
return ((_a = node.innerComments) == null ? void 0 : _a.map((comment) => `<!--${comment.value}-->`).join("")) ?? ""; | ||
case "JSXExpressionContainer": { | ||
const expr = resolveExpression(node.expression); | ||
if (expr instanceof RegExp) { | ||
return expr.toString(); | ||
} else if (typeof expr === "object") { | ||
return JSON.stringify(expr); | ||
} | ||
return String(expr); | ||
} | ||
default: | ||
return notSupported(node); | ||
} | ||
return String(expr); | ||
} | ||
function jsxTextToString(node) { | ||
const texts = node.value.split("\n"); | ||
function toStringJsxChildren(nodes) { | ||
return nodes.map((child) => toStringJsx(child)).join(""); | ||
} | ||
function toStringJsxText(node2) { | ||
const texts = node2.value.split("\n"); | ||
return texts.map((text, idx) => idx > 0 ? text.trim() : text).filter((line) => { | ||
@@ -128,30 +128,27 @@ if (line.trim().length === 0) | ||
} | ||
function jsxElementToString(node) { | ||
if (node.openingElement.selfClosing) { | ||
return jsxOpeningElementToString(node.openingElement); | ||
function toStringJsxElement(node2) { | ||
if (node2.openingElement.selfClosing) { | ||
return toStringOpeningElement(node2.openingElement); | ||
} else { | ||
const children = jsxChildrenToString(node.children); | ||
return `${jsxOpeningElementToString(node.openingElement)}${children}</${jsxNameToString(node.closingElement.name)}>`; | ||
const children = toStringJsxChildren(node2.children); | ||
return `${toStringOpeningElement(node2.openingElement)}${children}</${toStringJsxName(node2.closingElement.name)}>`; | ||
} | ||
} | ||
function jsxChildrenToString(nodes2) { | ||
return nodes2.map((child) => jsxToString(child)).join(""); | ||
} | ||
function jsxOpeningElementToString(node) { | ||
let str = `<${jsxNameToString(node.name)}`; | ||
const props = node.attributes.map((attr) => { | ||
if (attr.type === "JSXAttribute") { | ||
return jsxAttributeToString(attr); | ||
} else { | ||
return notSupported(node); | ||
function toStringOpeningElement(node3) { | ||
let str = `<${toStringJsxName(node3.name)}`; | ||
const props = node3.attributes.map((attr) => { | ||
if (attr.type === "JSXAttribute") { | ||
return toStringJsxAttribute(attr); | ||
} else { | ||
return notSupported(node3); | ||
} | ||
}).filter((x) => x !== void 0); | ||
if (props.length > 0) { | ||
str += ` ${props.join(" ")}`; | ||
} | ||
}).filter((x) => x !== void 0); | ||
if (props.length > 0) { | ||
str += ` ${props.join(" ")}`; | ||
str += node3.selfClosing ? "/>" : ">"; | ||
return str; | ||
} | ||
str += node.selfClosing ? "/>" : ">"; | ||
return str; | ||
} | ||
function jsxAttributeToString(node) { | ||
let name = jsxNameToString(node.name); | ||
function toStringJsxAttribute(node2) { | ||
let name = toStringJsxName(node2.name); | ||
if (name === "className") | ||
@@ -162,4 +159,4 @@ name = "class"; | ||
let value; | ||
if (node.value) { | ||
const rawValue = jsxAttrValueToString(node.value, name); | ||
if (node2.value) { | ||
const rawValue = toStringJsxAttributeValue(node2.value, name); | ||
if (rawValue === null) { | ||
@@ -172,80 +169,242 @@ return void 0; | ||
} | ||
function jsxNameToString(node) { | ||
if (node.type === "JSXIdentifier") { | ||
return node.name; | ||
} else { | ||
return notSupported(node); | ||
function toStringJsxAttributeValue(node2, key) { | ||
let value; | ||
if ((0, import_types.isJSXExpressionContainer)(node2) && (0, import_types.isBooleanLiteral)(node2.expression)) { | ||
value = node2.expression.value ? void 0 : null; | ||
} else if ((0, import_types.isJSXExpressionContainer)(node2) && (0, import_types.isFunction)(node2.expression)) { | ||
value = getSource(node2.expression.body); | ||
} else if ((0, import_types.isJSX)(node2)) { | ||
value = resolveJsx(node2); | ||
if (key === "style" && isPlainObject(value)) { | ||
value = styleToString(value); | ||
} else if (key === "class" && Array.isArray(value) && value.every((e) => isPrimitive(e))) | ||
value = value.join(" "); | ||
} else if ((0, import_types.isStringLiteral)(node2)) { | ||
value = node2.value; | ||
} | ||
if (value === void 0 || value === null) | ||
return value; | ||
return toStringExpression(value); | ||
} | ||
function jsxAttrValueToString(node, key) { | ||
let value; | ||
if ((0, import_types.isJSXExpressionContainer)(node) && (0, import_types.isBooleanLiteral)(node.expression)) { | ||
value = node.expression.value ? void 0 : null; | ||
} else if ((0, import_types.isJSXExpressionContainer)(node) && (0, import_types.isFunction)(node.expression)) { | ||
value = getSource(node.expression.body); | ||
} else if ((0, import_types.isJSX)(node)) { | ||
value = jsxToString(node); | ||
if ((0, import_types.isJSXExpressionContainer)(node) && ((0, import_types.isObjectExpression)(node.expression) || (0, import_types.isArrayExpression)(node.expression))) { | ||
if (key === "style") { | ||
value = styleToString(JSON.parse(value)); | ||
} else if (key === "class") { | ||
const classes = JSON.parse(value); | ||
if (Array.isArray(classes)) | ||
value = classes.join(" "); | ||
} | ||
function toStringJsxName(node2) { | ||
if (node2.type === "JSXIdentifier") | ||
return node2.name; | ||
return notSupported(node2); | ||
} | ||
function resolveJsx(node2) { | ||
var _a; | ||
switch (node2.type) { | ||
case "JSXElement": | ||
return toStringJsxElement(node2); | ||
case "JSXFragment": | ||
return toStringJsxChildren(node2.children); | ||
case "JSXText": | ||
return toStringJsxText(node2); | ||
case "JSXEmptyExpression": | ||
return ((_a = node2.innerComments) == null ? void 0 : _a.map((comment) => `<!--${comment.value}-->`).join("")) ?? ""; | ||
case "JSXExpressionContainer": { | ||
return resolveExpression(node2.expression); | ||
} | ||
} else if ((0, import_types.isStringLiteral)(node)) { | ||
value = node.value; | ||
default: | ||
return notSupported(node2); | ||
} | ||
return value; | ||
} | ||
function resolveExpression(node) { | ||
if ((0, import_types.isLiteral)(node)) { | ||
return resolveLiteral(node); | ||
} else if ((0, import_types.isJSX)(node)) { | ||
return jsxToString(node); | ||
function resolveExpression(node2) { | ||
if ((0, import_types.isLiteral)(node2)) { | ||
return resolveLiteral(node2); | ||
} else if ((0, import_types.isJSX)(node2)) { | ||
return resolveJsx(node2); | ||
} | ||
switch (node.type) { | ||
switch (node2.type) { | ||
case "ArrayExpression": | ||
return resolveArrayExpression(node2); | ||
case "ObjectExpression": | ||
return parseObject(getSource(node)); | ||
return resolveObjectExpression(node2); | ||
case "BinaryExpression": | ||
return resolveExpression(node.left) + resolveExpression(node.right); | ||
case "LogicalExpression": | ||
return resolveBinary(node2); | ||
case "UnaryExpression": | ||
return resolveUnaryExpression(node2); | ||
case "ConditionalExpression": | ||
return resolveExpression(node2.test) ? resolveExpression(node2.consequent) : resolveExpression(node2.alternate); | ||
case "SequenceExpression": { | ||
const expressions = node2.expressions.map((expr) => resolveExpression(expr)); | ||
return expressions.slice(-1)[0]; | ||
} | ||
case "TSNonNullExpression": | ||
return resolveExpression(node2.expression); | ||
case "CallExpression": | ||
return resolveCallExpression(node2); | ||
default: | ||
return notSupported(node); | ||
return notSupported(node2); | ||
} | ||
} | ||
function resolveLiteral(node) { | ||
switch (node.type) { | ||
function resolveCallExpression(node2) { | ||
if (node2.callee.type === "Identifier" && node2.callee.name === "jsxRaw") { | ||
return `__RAW_${getSource(node2.arguments[0])}_RAW`; | ||
} | ||
return notSupported(node2); | ||
} | ||
function resolveBinary(node2) { | ||
const left = resolveExpression(node2.left); | ||
const right = resolveExpression(node2.right); | ||
switch (node2.operator) { | ||
case "+": | ||
return left + right; | ||
case "-": | ||
return left - right; | ||
case "*": | ||
return left * right; | ||
case "/": | ||
return left / right; | ||
case "&&": | ||
return left && right; | ||
case "||": | ||
return left || right; | ||
case "??": | ||
return left ?? right; | ||
case "==": | ||
return left == right; | ||
case "!=": | ||
return left != right; | ||
case "===": | ||
return left === right; | ||
case "!==": | ||
return left !== right; | ||
case ">": | ||
return left > right; | ||
case ">=": | ||
return left >= right; | ||
case "<": | ||
return left < right; | ||
case "<=": | ||
return left <= right; | ||
case "%": | ||
return left % right; | ||
case "**": | ||
return left ** right; | ||
case "&": | ||
return left & right; | ||
case "|": | ||
return left | right; | ||
case "^": | ||
return left ^ right; | ||
case "<<": | ||
return left << right; | ||
case ">>": | ||
return left >> right; | ||
case ">>>": | ||
return left >>> right; | ||
case "in": | ||
return left in right; | ||
case "instanceof": | ||
return left instanceof right; | ||
default: | ||
notSupported(node2); | ||
} | ||
} | ||
function resolveUnaryExpression(node2) { | ||
const value = resolveExpression(node2.argument); | ||
switch (node2.operator) { | ||
case "!": | ||
return !value; | ||
case "+": | ||
return +value; | ||
case "-": | ||
return -value; | ||
case "typeof": | ||
return typeof value; | ||
case "void": | ||
return void 0; | ||
case "~": | ||
return ~value; | ||
default: | ||
notSupported(node2); | ||
} | ||
} | ||
function resolveLiteral(node2) { | ||
switch (node2.type) { | ||
case "TemplateLiteral": | ||
return templateLiteralToString(node); | ||
return resolveTemplateLiteral(node2); | ||
case "NullLiteral": | ||
return null; | ||
case "BigIntLiteral": | ||
return BigInt(node.value); | ||
return BigInt(node2.value); | ||
case "RegExpLiteral": | ||
return new RegExp(node.pattern, node.flags); | ||
return new RegExp(node2.pattern, node2.flags); | ||
case "BooleanLiteral": | ||
case "NumericLiteral": | ||
case "StringLiteral": | ||
return node.value; | ||
return node2.value; | ||
default: | ||
return notSupported(node); | ||
return notSupported(node2); | ||
} | ||
} | ||
function templateLiteralToString(node) { | ||
return node.quasis.reduce((prev, curr, idx) => { | ||
if (node.expressions[idx]) { | ||
return prev + curr.value.cooked + resolveExpression(node.expressions[idx]); | ||
function resolveArrayExpression(node2) { | ||
const items = []; | ||
for (const [i, element] of node2.elements.entries()) { | ||
if (element) | ||
items[i] = resolveExpression(element); | ||
} | ||
return items; | ||
} | ||
function resolveObjectExpression(node2) { | ||
const obj = {}; | ||
for (const prop of node2.properties) { | ||
if (prop.type !== "ObjectProperty") | ||
return notSupported(prop); | ||
let key; | ||
if ((0, import_types.isIdentifier)(prop.key) && !prop.computed) { | ||
key = prop.key.name; | ||
} else { | ||
key = resolveExpression(prop.key); | ||
} | ||
obj[key] = resolveExpression(prop.value); | ||
} | ||
return obj; | ||
} | ||
function resolveTemplateLiteral(node2) { | ||
return node2.quasis.reduce((prev, curr, idx) => { | ||
if (node2.expressions[idx]) { | ||
return prev + curr.value.cooked + resolveExpression(node2.expressions[idx]); | ||
} | ||
return prev + curr.value.cooked; | ||
}, ""); | ||
} | ||
function getSource(node) { | ||
return code.slice(node.start, node.end); | ||
function getSource(node2) { | ||
return code.slice(node2.start, node2.end); | ||
} | ||
function notSupported(node) { | ||
throw new Error(`not supported ${node.type}: ${getSource(node)}`); | ||
function notSupported(node2) { | ||
throw new Error(`not supported ${node2.type}: ${getSource(node2)}`); | ||
} | ||
}; | ||
} | ||
function transformJsxToString(code, { | ||
debug, | ||
plugins, | ||
id = "" | ||
}) { | ||
const s = new import_magic_string.default(code); | ||
if (id.endsWith(".tsx")) | ||
plugins.push("typescript"); | ||
const nodes = extractJsx(code, plugins); | ||
for (const [node, expr] of nodes) { | ||
let str; | ||
if (!debug) { | ||
str = transformJsx(code, node); | ||
} else { | ||
try { | ||
str = transformJsx(code, node); | ||
} catch (err) { | ||
str = `(() => { throw new Error(${escapeString(err.toString())}) })()`; | ||
} | ||
} | ||
s.overwrite(expr.start, expr.end, str); | ||
} | ||
return { | ||
code: s.toString(), | ||
get map() { | ||
return s.generateMap(); | ||
} | ||
}; | ||
} | ||
@@ -258,3 +417,3 @@ // src/core/options.ts | ||
debug: options.debug ?? false, | ||
plugins: ["typescript", "jsx"] | ||
plugins: ["jsx"] | ||
}; | ||
@@ -274,5 +433,7 @@ } | ||
}, | ||
transform(code) { | ||
transform(code, id) { | ||
try { | ||
return convert(code, opt); | ||
return transformJsxToString(code, __spreadProps(__spreadValues({}, opt), { | ||
id | ||
})); | ||
} catch (err) { | ||
@@ -279,0 +440,0 @@ this.error(`${name} ${err}`); |
419
dist/vite.js
@@ -0,7 +1,25 @@ | ||
"use strict"; | ||
var __create = Object.create; | ||
var __defProp = Object.defineProperty; | ||
var __defProps = Object.defineProperties; | ||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
var __getOwnPropDescs = Object.getOwnPropertyDescriptors; | ||
var __getOwnPropNames = Object.getOwnPropertyNames; | ||
var __getOwnPropSymbols = Object.getOwnPropertySymbols; | ||
var __getProtoOf = Object.getPrototypeOf; | ||
var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
var __propIsEnum = Object.prototype.propertyIsEnumerable; | ||
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; | ||
var __spreadValues = (a, b) => { | ||
for (var prop in b || (b = {})) | ||
if (__hasOwnProp.call(b, prop)) | ||
__defNormalProp(a, prop, b[prop]); | ||
if (__getOwnPropSymbols) | ||
for (var prop of __getOwnPropSymbols(b)) { | ||
if (__propIsEnum.call(b, prop)) | ||
__defNormalProp(a, prop, b[prop]); | ||
} | ||
return a; | ||
}; | ||
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); | ||
var __export = (target, all) => { | ||
@@ -41,3 +59,2 @@ for (var name in all) | ||
// src/core/utils.ts | ||
var import_json5 = __toESM(require("json5")); | ||
var import_jsesc = __toESM(require("jsesc")); | ||
@@ -51,13 +68,22 @@ var KEBAB_REGEX = /[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g; | ||
var styleToString = (styles) => Object.entries(styles).map(([key, value]) => `${kebabCase(key)}:${value}`).join(";"); | ||
var parseObject = (text) => { | ||
try { | ||
return import_json5.default.parse(text); | ||
} catch (err) { | ||
throw new SyntaxError(`Invalid attribute value: ${text}, error: ${err.message}`); | ||
} | ||
var RAW_RE = /__RAW_(.*?)_RAW/g; | ||
var escapeString = (str) => { | ||
const text = (0, import_jsesc.default)(str, { | ||
quotes: "backtick", | ||
wrap: true, | ||
es6: true | ||
}); | ||
return text.replaceAll(RAW_RE, "${$1}"); | ||
}; | ||
var escapeString = (str) => `'${(0, import_jsesc.default)(str)}'`; | ||
var isPrimitive = (val) => { | ||
if (typeof val === "object") | ||
return val === null; | ||
return typeof val !== "function"; | ||
}; | ||
var isPlainObject = (obj) => { | ||
return Object.prototype.toString.call(obj) === "[object Object]"; | ||
}; | ||
// src/core/convert.ts | ||
var convert = (code, { debug, plugins }) => { | ||
function extractJsx(code, plugins) { | ||
const ast = (0, import_parser.parse)(code, { | ||
@@ -75,48 +101,22 @@ sourceType: "module", | ||
}); | ||
const s = new import_magic_string.default(code); | ||
for (const [node, expr] of nodes) { | ||
let str; | ||
if (!debug) { | ||
str = escapeString(jsxToString(node)); | ||
} else { | ||
try { | ||
str = escapeString(jsxToString(node)); | ||
} catch (err) { | ||
str = `(() => { throw new Error(${escapeString(err.toString())}) })()`; | ||
} | ||
} | ||
s.overwrite(expr.start, expr.end, str); | ||
return nodes; | ||
} | ||
function transformJsx(code, node) { | ||
return escapeString(toStringJsx(node)); | ||
function toStringJsx(node2) { | ||
return toStringExpression(resolveJsx(node2)); | ||
} | ||
return { | ||
code: s.toString(), | ||
get map() { | ||
return s.generateMap(); | ||
function toStringExpression(expr) { | ||
if (expr instanceof RegExp) { | ||
return expr.toString(); | ||
} else if (typeof expr === "object") { | ||
return JSON.stringify(expr); | ||
} | ||
}; | ||
function jsxToString(node) { | ||
var _a; | ||
switch (node.type) { | ||
case "JSXElement": | ||
return jsxElementToString(node); | ||
case "JSXFragment": | ||
return jsxChildrenToString(node.children); | ||
case "JSXText": | ||
return jsxTextToString(node); | ||
case "JSXEmptyExpression": | ||
return ((_a = node.innerComments) == null ? void 0 : _a.map((comment) => `<!--${comment.value}-->`).join("")) ?? ""; | ||
case "JSXExpressionContainer": { | ||
const expr = resolveExpression(node.expression); | ||
if (expr instanceof RegExp) { | ||
return expr.toString(); | ||
} else if (typeof expr === "object") { | ||
return JSON.stringify(expr); | ||
} | ||
return String(expr); | ||
} | ||
default: | ||
return notSupported(node); | ||
} | ||
return String(expr); | ||
} | ||
function jsxTextToString(node) { | ||
const texts = node.value.split("\n"); | ||
function toStringJsxChildren(nodes) { | ||
return nodes.map((child) => toStringJsx(child)).join(""); | ||
} | ||
function toStringJsxText(node2) { | ||
const texts = node2.value.split("\n"); | ||
return texts.map((text, idx) => idx > 0 ? text.trim() : text).filter((line) => { | ||
@@ -128,30 +128,27 @@ if (line.trim().length === 0) | ||
} | ||
function jsxElementToString(node) { | ||
if (node.openingElement.selfClosing) { | ||
return jsxOpeningElementToString(node.openingElement); | ||
function toStringJsxElement(node2) { | ||
if (node2.openingElement.selfClosing) { | ||
return toStringOpeningElement(node2.openingElement); | ||
} else { | ||
const children = jsxChildrenToString(node.children); | ||
return `${jsxOpeningElementToString(node.openingElement)}${children}</${jsxNameToString(node.closingElement.name)}>`; | ||
const children = toStringJsxChildren(node2.children); | ||
return `${toStringOpeningElement(node2.openingElement)}${children}</${toStringJsxName(node2.closingElement.name)}>`; | ||
} | ||
} | ||
function jsxChildrenToString(nodes2) { | ||
return nodes2.map((child) => jsxToString(child)).join(""); | ||
} | ||
function jsxOpeningElementToString(node) { | ||
let str = `<${jsxNameToString(node.name)}`; | ||
const props = node.attributes.map((attr) => { | ||
if (attr.type === "JSXAttribute") { | ||
return jsxAttributeToString(attr); | ||
} else { | ||
return notSupported(node); | ||
function toStringOpeningElement(node3) { | ||
let str = `<${toStringJsxName(node3.name)}`; | ||
const props = node3.attributes.map((attr) => { | ||
if (attr.type === "JSXAttribute") { | ||
return toStringJsxAttribute(attr); | ||
} else { | ||
return notSupported(node3); | ||
} | ||
}).filter((x) => x !== void 0); | ||
if (props.length > 0) { | ||
str += ` ${props.join(" ")}`; | ||
} | ||
}).filter((x) => x !== void 0); | ||
if (props.length > 0) { | ||
str += ` ${props.join(" ")}`; | ||
str += node3.selfClosing ? "/>" : ">"; | ||
return str; | ||
} | ||
str += node.selfClosing ? "/>" : ">"; | ||
return str; | ||
} | ||
function jsxAttributeToString(node) { | ||
let name = jsxNameToString(node.name); | ||
function toStringJsxAttribute(node2) { | ||
let name = toStringJsxName(node2.name); | ||
if (name === "className") | ||
@@ -162,4 +159,4 @@ name = "class"; | ||
let value; | ||
if (node.value) { | ||
const rawValue = jsxAttrValueToString(node.value, name); | ||
if (node2.value) { | ||
const rawValue = toStringJsxAttributeValue(node2.value, name); | ||
if (rawValue === null) { | ||
@@ -172,80 +169,242 @@ return void 0; | ||
} | ||
function jsxNameToString(node) { | ||
if (node.type === "JSXIdentifier") { | ||
return node.name; | ||
} else { | ||
return notSupported(node); | ||
function toStringJsxAttributeValue(node2, key) { | ||
let value; | ||
if ((0, import_types.isJSXExpressionContainer)(node2) && (0, import_types.isBooleanLiteral)(node2.expression)) { | ||
value = node2.expression.value ? void 0 : null; | ||
} else if ((0, import_types.isJSXExpressionContainer)(node2) && (0, import_types.isFunction)(node2.expression)) { | ||
value = getSource(node2.expression.body); | ||
} else if ((0, import_types.isJSX)(node2)) { | ||
value = resolveJsx(node2); | ||
if (key === "style" && isPlainObject(value)) { | ||
value = styleToString(value); | ||
} else if (key === "class" && Array.isArray(value) && value.every((e) => isPrimitive(e))) | ||
value = value.join(" "); | ||
} else if ((0, import_types.isStringLiteral)(node2)) { | ||
value = node2.value; | ||
} | ||
if (value === void 0 || value === null) | ||
return value; | ||
return toStringExpression(value); | ||
} | ||
function jsxAttrValueToString(node, key) { | ||
let value; | ||
if ((0, import_types.isJSXExpressionContainer)(node) && (0, import_types.isBooleanLiteral)(node.expression)) { | ||
value = node.expression.value ? void 0 : null; | ||
} else if ((0, import_types.isJSXExpressionContainer)(node) && (0, import_types.isFunction)(node.expression)) { | ||
value = getSource(node.expression.body); | ||
} else if ((0, import_types.isJSX)(node)) { | ||
value = jsxToString(node); | ||
if ((0, import_types.isJSXExpressionContainer)(node) && ((0, import_types.isObjectExpression)(node.expression) || (0, import_types.isArrayExpression)(node.expression))) { | ||
if (key === "style") { | ||
value = styleToString(JSON.parse(value)); | ||
} else if (key === "class") { | ||
const classes = JSON.parse(value); | ||
if (Array.isArray(classes)) | ||
value = classes.join(" "); | ||
} | ||
function toStringJsxName(node2) { | ||
if (node2.type === "JSXIdentifier") | ||
return node2.name; | ||
return notSupported(node2); | ||
} | ||
function resolveJsx(node2) { | ||
var _a; | ||
switch (node2.type) { | ||
case "JSXElement": | ||
return toStringJsxElement(node2); | ||
case "JSXFragment": | ||
return toStringJsxChildren(node2.children); | ||
case "JSXText": | ||
return toStringJsxText(node2); | ||
case "JSXEmptyExpression": | ||
return ((_a = node2.innerComments) == null ? void 0 : _a.map((comment) => `<!--${comment.value}-->`).join("")) ?? ""; | ||
case "JSXExpressionContainer": { | ||
return resolveExpression(node2.expression); | ||
} | ||
} else if ((0, import_types.isStringLiteral)(node)) { | ||
value = node.value; | ||
default: | ||
return notSupported(node2); | ||
} | ||
return value; | ||
} | ||
function resolveExpression(node) { | ||
if ((0, import_types.isLiteral)(node)) { | ||
return resolveLiteral(node); | ||
} else if ((0, import_types.isJSX)(node)) { | ||
return jsxToString(node); | ||
function resolveExpression(node2) { | ||
if ((0, import_types.isLiteral)(node2)) { | ||
return resolveLiteral(node2); | ||
} else if ((0, import_types.isJSX)(node2)) { | ||
return resolveJsx(node2); | ||
} | ||
switch (node.type) { | ||
switch (node2.type) { | ||
case "ArrayExpression": | ||
return resolveArrayExpression(node2); | ||
case "ObjectExpression": | ||
return parseObject(getSource(node)); | ||
return resolveObjectExpression(node2); | ||
case "BinaryExpression": | ||
return resolveExpression(node.left) + resolveExpression(node.right); | ||
case "LogicalExpression": | ||
return resolveBinary(node2); | ||
case "UnaryExpression": | ||
return resolveUnaryExpression(node2); | ||
case "ConditionalExpression": | ||
return resolveExpression(node2.test) ? resolveExpression(node2.consequent) : resolveExpression(node2.alternate); | ||
case "SequenceExpression": { | ||
const expressions = node2.expressions.map((expr) => resolveExpression(expr)); | ||
return expressions.slice(-1)[0]; | ||
} | ||
case "TSNonNullExpression": | ||
return resolveExpression(node2.expression); | ||
case "CallExpression": | ||
return resolveCallExpression(node2); | ||
default: | ||
return notSupported(node); | ||
return notSupported(node2); | ||
} | ||
} | ||
function resolveLiteral(node) { | ||
switch (node.type) { | ||
function resolveCallExpression(node2) { | ||
if (node2.callee.type === "Identifier" && node2.callee.name === "jsxRaw") { | ||
return `__RAW_${getSource(node2.arguments[0])}_RAW`; | ||
} | ||
return notSupported(node2); | ||
} | ||
function resolveBinary(node2) { | ||
const left = resolveExpression(node2.left); | ||
const right = resolveExpression(node2.right); | ||
switch (node2.operator) { | ||
case "+": | ||
return left + right; | ||
case "-": | ||
return left - right; | ||
case "*": | ||
return left * right; | ||
case "/": | ||
return left / right; | ||
case "&&": | ||
return left && right; | ||
case "||": | ||
return left || right; | ||
case "??": | ||
return left ?? right; | ||
case "==": | ||
return left == right; | ||
case "!=": | ||
return left != right; | ||
case "===": | ||
return left === right; | ||
case "!==": | ||
return left !== right; | ||
case ">": | ||
return left > right; | ||
case ">=": | ||
return left >= right; | ||
case "<": | ||
return left < right; | ||
case "<=": | ||
return left <= right; | ||
case "%": | ||
return left % right; | ||
case "**": | ||
return left ** right; | ||
case "&": | ||
return left & right; | ||
case "|": | ||
return left | right; | ||
case "^": | ||
return left ^ right; | ||
case "<<": | ||
return left << right; | ||
case ">>": | ||
return left >> right; | ||
case ">>>": | ||
return left >>> right; | ||
case "in": | ||
return left in right; | ||
case "instanceof": | ||
return left instanceof right; | ||
default: | ||
notSupported(node2); | ||
} | ||
} | ||
function resolveUnaryExpression(node2) { | ||
const value = resolveExpression(node2.argument); | ||
switch (node2.operator) { | ||
case "!": | ||
return !value; | ||
case "+": | ||
return +value; | ||
case "-": | ||
return -value; | ||
case "typeof": | ||
return typeof value; | ||
case "void": | ||
return void 0; | ||
case "~": | ||
return ~value; | ||
default: | ||
notSupported(node2); | ||
} | ||
} | ||
function resolveLiteral(node2) { | ||
switch (node2.type) { | ||
case "TemplateLiteral": | ||
return templateLiteralToString(node); | ||
return resolveTemplateLiteral(node2); | ||
case "NullLiteral": | ||
return null; | ||
case "BigIntLiteral": | ||
return BigInt(node.value); | ||
return BigInt(node2.value); | ||
case "RegExpLiteral": | ||
return new RegExp(node.pattern, node.flags); | ||
return new RegExp(node2.pattern, node2.flags); | ||
case "BooleanLiteral": | ||
case "NumericLiteral": | ||
case "StringLiteral": | ||
return node.value; | ||
return node2.value; | ||
default: | ||
return notSupported(node); | ||
return notSupported(node2); | ||
} | ||
} | ||
function templateLiteralToString(node) { | ||
return node.quasis.reduce((prev, curr, idx) => { | ||
if (node.expressions[idx]) { | ||
return prev + curr.value.cooked + resolveExpression(node.expressions[idx]); | ||
function resolveArrayExpression(node2) { | ||
const items = []; | ||
for (const [i, element] of node2.elements.entries()) { | ||
if (element) | ||
items[i] = resolveExpression(element); | ||
} | ||
return items; | ||
} | ||
function resolveObjectExpression(node2) { | ||
const obj = {}; | ||
for (const prop of node2.properties) { | ||
if (prop.type !== "ObjectProperty") | ||
return notSupported(prop); | ||
let key; | ||
if ((0, import_types.isIdentifier)(prop.key) && !prop.computed) { | ||
key = prop.key.name; | ||
} else { | ||
key = resolveExpression(prop.key); | ||
} | ||
obj[key] = resolveExpression(prop.value); | ||
} | ||
return obj; | ||
} | ||
function resolveTemplateLiteral(node2) { | ||
return node2.quasis.reduce((prev, curr, idx) => { | ||
if (node2.expressions[idx]) { | ||
return prev + curr.value.cooked + resolveExpression(node2.expressions[idx]); | ||
} | ||
return prev + curr.value.cooked; | ||
}, ""); | ||
} | ||
function getSource(node) { | ||
return code.slice(node.start, node.end); | ||
function getSource(node2) { | ||
return code.slice(node2.start, node2.end); | ||
} | ||
function notSupported(node) { | ||
throw new Error(`not supported ${node.type}: ${getSource(node)}`); | ||
function notSupported(node2) { | ||
throw new Error(`not supported ${node2.type}: ${getSource(node2)}`); | ||
} | ||
}; | ||
} | ||
function transformJsxToString(code, { | ||
debug, | ||
plugins, | ||
id = "" | ||
}) { | ||
const s = new import_magic_string.default(code); | ||
if (id.endsWith(".tsx")) | ||
plugins.push("typescript"); | ||
const nodes = extractJsx(code, plugins); | ||
for (const [node, expr] of nodes) { | ||
let str; | ||
if (!debug) { | ||
str = transformJsx(code, node); | ||
} else { | ||
try { | ||
str = transformJsx(code, node); | ||
} catch (err) { | ||
str = `(() => { throw new Error(${escapeString(err.toString())}) })()`; | ||
} | ||
} | ||
s.overwrite(expr.start, expr.end, str); | ||
} | ||
return { | ||
code: s.toString(), | ||
get map() { | ||
return s.generateMap(); | ||
} | ||
}; | ||
} | ||
@@ -258,3 +417,3 @@ // src/core/options.ts | ||
debug: options.debug ?? false, | ||
plugins: ["typescript", "jsx"] | ||
plugins: ["jsx"] | ||
}; | ||
@@ -274,5 +433,7 @@ } | ||
}, | ||
transform(code) { | ||
transform(code, id) { | ||
try { | ||
return convert(code, opt); | ||
return transformJsxToString(code, __spreadProps(__spreadValues({}, opt), { | ||
id | ||
})); | ||
} catch (err) { | ||
@@ -279,0 +440,0 @@ this.error(`${name} ${err}`); |
@@ -0,7 +1,25 @@ | ||
"use strict"; | ||
var __create = Object.create; | ||
var __defProp = Object.defineProperty; | ||
var __defProps = Object.defineProperties; | ||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
var __getOwnPropDescs = Object.getOwnPropertyDescriptors; | ||
var __getOwnPropNames = Object.getOwnPropertyNames; | ||
var __getOwnPropSymbols = Object.getOwnPropertySymbols; | ||
var __getProtoOf = Object.getPrototypeOf; | ||
var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
var __propIsEnum = Object.prototype.propertyIsEnumerable; | ||
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; | ||
var __spreadValues = (a, b) => { | ||
for (var prop in b || (b = {})) | ||
if (__hasOwnProp.call(b, prop)) | ||
__defNormalProp(a, prop, b[prop]); | ||
if (__getOwnPropSymbols) | ||
for (var prop of __getOwnPropSymbols(b)) { | ||
if (__propIsEnum.call(b, prop)) | ||
__defNormalProp(a, prop, b[prop]); | ||
} | ||
return a; | ||
}; | ||
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); | ||
var __export = (target, all) => { | ||
@@ -41,3 +59,2 @@ for (var name in all) | ||
// src/core/utils.ts | ||
var import_json5 = __toESM(require("json5")); | ||
var import_jsesc = __toESM(require("jsesc")); | ||
@@ -51,13 +68,22 @@ var KEBAB_REGEX = /[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g; | ||
var styleToString = (styles) => Object.entries(styles).map(([key, value]) => `${kebabCase(key)}:${value}`).join(";"); | ||
var parseObject = (text) => { | ||
try { | ||
return import_json5.default.parse(text); | ||
} catch (err) { | ||
throw new SyntaxError(`Invalid attribute value: ${text}, error: ${err.message}`); | ||
} | ||
var RAW_RE = /__RAW_(.*?)_RAW/g; | ||
var escapeString = (str) => { | ||
const text = (0, import_jsesc.default)(str, { | ||
quotes: "backtick", | ||
wrap: true, | ||
es6: true | ||
}); | ||
return text.replaceAll(RAW_RE, "${$1}"); | ||
}; | ||
var escapeString = (str) => `'${(0, import_jsesc.default)(str)}'`; | ||
var isPrimitive = (val) => { | ||
if (typeof val === "object") | ||
return val === null; | ||
return typeof val !== "function"; | ||
}; | ||
var isPlainObject = (obj) => { | ||
return Object.prototype.toString.call(obj) === "[object Object]"; | ||
}; | ||
// src/core/convert.ts | ||
var convert = (code, { debug, plugins }) => { | ||
function extractJsx(code, plugins) { | ||
const ast = (0, import_parser.parse)(code, { | ||
@@ -75,48 +101,22 @@ sourceType: "module", | ||
}); | ||
const s = new import_magic_string.default(code); | ||
for (const [node, expr] of nodes) { | ||
let str; | ||
if (!debug) { | ||
str = escapeString(jsxToString(node)); | ||
} else { | ||
try { | ||
str = escapeString(jsxToString(node)); | ||
} catch (err) { | ||
str = `(() => { throw new Error(${escapeString(err.toString())}) })()`; | ||
} | ||
} | ||
s.overwrite(expr.start, expr.end, str); | ||
return nodes; | ||
} | ||
function transformJsx(code, node) { | ||
return escapeString(toStringJsx(node)); | ||
function toStringJsx(node2) { | ||
return toStringExpression(resolveJsx(node2)); | ||
} | ||
return { | ||
code: s.toString(), | ||
get map() { | ||
return s.generateMap(); | ||
function toStringExpression(expr) { | ||
if (expr instanceof RegExp) { | ||
return expr.toString(); | ||
} else if (typeof expr === "object") { | ||
return JSON.stringify(expr); | ||
} | ||
}; | ||
function jsxToString(node) { | ||
var _a; | ||
switch (node.type) { | ||
case "JSXElement": | ||
return jsxElementToString(node); | ||
case "JSXFragment": | ||
return jsxChildrenToString(node.children); | ||
case "JSXText": | ||
return jsxTextToString(node); | ||
case "JSXEmptyExpression": | ||
return ((_a = node.innerComments) == null ? void 0 : _a.map((comment) => `<!--${comment.value}-->`).join("")) ?? ""; | ||
case "JSXExpressionContainer": { | ||
const expr = resolveExpression(node.expression); | ||
if (expr instanceof RegExp) { | ||
return expr.toString(); | ||
} else if (typeof expr === "object") { | ||
return JSON.stringify(expr); | ||
} | ||
return String(expr); | ||
} | ||
default: | ||
return notSupported(node); | ||
} | ||
return String(expr); | ||
} | ||
function jsxTextToString(node) { | ||
const texts = node.value.split("\n"); | ||
function toStringJsxChildren(nodes) { | ||
return nodes.map((child) => toStringJsx(child)).join(""); | ||
} | ||
function toStringJsxText(node2) { | ||
const texts = node2.value.split("\n"); | ||
return texts.map((text, idx) => idx > 0 ? text.trim() : text).filter((line) => { | ||
@@ -128,30 +128,27 @@ if (line.trim().length === 0) | ||
} | ||
function jsxElementToString(node) { | ||
if (node.openingElement.selfClosing) { | ||
return jsxOpeningElementToString(node.openingElement); | ||
function toStringJsxElement(node2) { | ||
if (node2.openingElement.selfClosing) { | ||
return toStringOpeningElement(node2.openingElement); | ||
} else { | ||
const children = jsxChildrenToString(node.children); | ||
return `${jsxOpeningElementToString(node.openingElement)}${children}</${jsxNameToString(node.closingElement.name)}>`; | ||
const children = toStringJsxChildren(node2.children); | ||
return `${toStringOpeningElement(node2.openingElement)}${children}</${toStringJsxName(node2.closingElement.name)}>`; | ||
} | ||
} | ||
function jsxChildrenToString(nodes2) { | ||
return nodes2.map((child) => jsxToString(child)).join(""); | ||
} | ||
function jsxOpeningElementToString(node) { | ||
let str = `<${jsxNameToString(node.name)}`; | ||
const props = node.attributes.map((attr) => { | ||
if (attr.type === "JSXAttribute") { | ||
return jsxAttributeToString(attr); | ||
} else { | ||
return notSupported(node); | ||
function toStringOpeningElement(node3) { | ||
let str = `<${toStringJsxName(node3.name)}`; | ||
const props = node3.attributes.map((attr) => { | ||
if (attr.type === "JSXAttribute") { | ||
return toStringJsxAttribute(attr); | ||
} else { | ||
return notSupported(node3); | ||
} | ||
}).filter((x) => x !== void 0); | ||
if (props.length > 0) { | ||
str += ` ${props.join(" ")}`; | ||
} | ||
}).filter((x) => x !== void 0); | ||
if (props.length > 0) { | ||
str += ` ${props.join(" ")}`; | ||
str += node3.selfClosing ? "/>" : ">"; | ||
return str; | ||
} | ||
str += node.selfClosing ? "/>" : ">"; | ||
return str; | ||
} | ||
function jsxAttributeToString(node) { | ||
let name = jsxNameToString(node.name); | ||
function toStringJsxAttribute(node2) { | ||
let name = toStringJsxName(node2.name); | ||
if (name === "className") | ||
@@ -162,4 +159,4 @@ name = "class"; | ||
let value; | ||
if (node.value) { | ||
const rawValue = jsxAttrValueToString(node.value, name); | ||
if (node2.value) { | ||
const rawValue = toStringJsxAttributeValue(node2.value, name); | ||
if (rawValue === null) { | ||
@@ -172,80 +169,242 @@ return void 0; | ||
} | ||
function jsxNameToString(node) { | ||
if (node.type === "JSXIdentifier") { | ||
return node.name; | ||
} else { | ||
return notSupported(node); | ||
function toStringJsxAttributeValue(node2, key) { | ||
let value; | ||
if ((0, import_types.isJSXExpressionContainer)(node2) && (0, import_types.isBooleanLiteral)(node2.expression)) { | ||
value = node2.expression.value ? void 0 : null; | ||
} else if ((0, import_types.isJSXExpressionContainer)(node2) && (0, import_types.isFunction)(node2.expression)) { | ||
value = getSource(node2.expression.body); | ||
} else if ((0, import_types.isJSX)(node2)) { | ||
value = resolveJsx(node2); | ||
if (key === "style" && isPlainObject(value)) { | ||
value = styleToString(value); | ||
} else if (key === "class" && Array.isArray(value) && value.every((e) => isPrimitive(e))) | ||
value = value.join(" "); | ||
} else if ((0, import_types.isStringLiteral)(node2)) { | ||
value = node2.value; | ||
} | ||
if (value === void 0 || value === null) | ||
return value; | ||
return toStringExpression(value); | ||
} | ||
function jsxAttrValueToString(node, key) { | ||
let value; | ||
if ((0, import_types.isJSXExpressionContainer)(node) && (0, import_types.isBooleanLiteral)(node.expression)) { | ||
value = node.expression.value ? void 0 : null; | ||
} else if ((0, import_types.isJSXExpressionContainer)(node) && (0, import_types.isFunction)(node.expression)) { | ||
value = getSource(node.expression.body); | ||
} else if ((0, import_types.isJSX)(node)) { | ||
value = jsxToString(node); | ||
if ((0, import_types.isJSXExpressionContainer)(node) && ((0, import_types.isObjectExpression)(node.expression) || (0, import_types.isArrayExpression)(node.expression))) { | ||
if (key === "style") { | ||
value = styleToString(JSON.parse(value)); | ||
} else if (key === "class") { | ||
const classes = JSON.parse(value); | ||
if (Array.isArray(classes)) | ||
value = classes.join(" "); | ||
} | ||
function toStringJsxName(node2) { | ||
if (node2.type === "JSXIdentifier") | ||
return node2.name; | ||
return notSupported(node2); | ||
} | ||
function resolveJsx(node2) { | ||
var _a; | ||
switch (node2.type) { | ||
case "JSXElement": | ||
return toStringJsxElement(node2); | ||
case "JSXFragment": | ||
return toStringJsxChildren(node2.children); | ||
case "JSXText": | ||
return toStringJsxText(node2); | ||
case "JSXEmptyExpression": | ||
return ((_a = node2.innerComments) == null ? void 0 : _a.map((comment) => `<!--${comment.value}-->`).join("")) ?? ""; | ||
case "JSXExpressionContainer": { | ||
return resolveExpression(node2.expression); | ||
} | ||
} else if ((0, import_types.isStringLiteral)(node)) { | ||
value = node.value; | ||
default: | ||
return notSupported(node2); | ||
} | ||
return value; | ||
} | ||
function resolveExpression(node) { | ||
if ((0, import_types.isLiteral)(node)) { | ||
return resolveLiteral(node); | ||
} else if ((0, import_types.isJSX)(node)) { | ||
return jsxToString(node); | ||
function resolveExpression(node2) { | ||
if ((0, import_types.isLiteral)(node2)) { | ||
return resolveLiteral(node2); | ||
} else if ((0, import_types.isJSX)(node2)) { | ||
return resolveJsx(node2); | ||
} | ||
switch (node.type) { | ||
switch (node2.type) { | ||
case "ArrayExpression": | ||
return resolveArrayExpression(node2); | ||
case "ObjectExpression": | ||
return parseObject(getSource(node)); | ||
return resolveObjectExpression(node2); | ||
case "BinaryExpression": | ||
return resolveExpression(node.left) + resolveExpression(node.right); | ||
case "LogicalExpression": | ||
return resolveBinary(node2); | ||
case "UnaryExpression": | ||
return resolveUnaryExpression(node2); | ||
case "ConditionalExpression": | ||
return resolveExpression(node2.test) ? resolveExpression(node2.consequent) : resolveExpression(node2.alternate); | ||
case "SequenceExpression": { | ||
const expressions = node2.expressions.map((expr) => resolveExpression(expr)); | ||
return expressions.slice(-1)[0]; | ||
} | ||
case "TSNonNullExpression": | ||
return resolveExpression(node2.expression); | ||
case "CallExpression": | ||
return resolveCallExpression(node2); | ||
default: | ||
return notSupported(node); | ||
return notSupported(node2); | ||
} | ||
} | ||
function resolveLiteral(node) { | ||
switch (node.type) { | ||
function resolveCallExpression(node2) { | ||
if (node2.callee.type === "Identifier" && node2.callee.name === "jsxRaw") { | ||
return `__RAW_${getSource(node2.arguments[0])}_RAW`; | ||
} | ||
return notSupported(node2); | ||
} | ||
function resolveBinary(node2) { | ||
const left = resolveExpression(node2.left); | ||
const right = resolveExpression(node2.right); | ||
switch (node2.operator) { | ||
case "+": | ||
return left + right; | ||
case "-": | ||
return left - right; | ||
case "*": | ||
return left * right; | ||
case "/": | ||
return left / right; | ||
case "&&": | ||
return left && right; | ||
case "||": | ||
return left || right; | ||
case "??": | ||
return left ?? right; | ||
case "==": | ||
return left == right; | ||
case "!=": | ||
return left != right; | ||
case "===": | ||
return left === right; | ||
case "!==": | ||
return left !== right; | ||
case ">": | ||
return left > right; | ||
case ">=": | ||
return left >= right; | ||
case "<": | ||
return left < right; | ||
case "<=": | ||
return left <= right; | ||
case "%": | ||
return left % right; | ||
case "**": | ||
return left ** right; | ||
case "&": | ||
return left & right; | ||
case "|": | ||
return left | right; | ||
case "^": | ||
return left ^ right; | ||
case "<<": | ||
return left << right; | ||
case ">>": | ||
return left >> right; | ||
case ">>>": | ||
return left >>> right; | ||
case "in": | ||
return left in right; | ||
case "instanceof": | ||
return left instanceof right; | ||
default: | ||
notSupported(node2); | ||
} | ||
} | ||
function resolveUnaryExpression(node2) { | ||
const value = resolveExpression(node2.argument); | ||
switch (node2.operator) { | ||
case "!": | ||
return !value; | ||
case "+": | ||
return +value; | ||
case "-": | ||
return -value; | ||
case "typeof": | ||
return typeof value; | ||
case "void": | ||
return void 0; | ||
case "~": | ||
return ~value; | ||
default: | ||
notSupported(node2); | ||
} | ||
} | ||
function resolveLiteral(node2) { | ||
switch (node2.type) { | ||
case "TemplateLiteral": | ||
return templateLiteralToString(node); | ||
return resolveTemplateLiteral(node2); | ||
case "NullLiteral": | ||
return null; | ||
case "BigIntLiteral": | ||
return BigInt(node.value); | ||
return BigInt(node2.value); | ||
case "RegExpLiteral": | ||
return new RegExp(node.pattern, node.flags); | ||
return new RegExp(node2.pattern, node2.flags); | ||
case "BooleanLiteral": | ||
case "NumericLiteral": | ||
case "StringLiteral": | ||
return node.value; | ||
return node2.value; | ||
default: | ||
return notSupported(node); | ||
return notSupported(node2); | ||
} | ||
} | ||
function templateLiteralToString(node) { | ||
return node.quasis.reduce((prev, curr, idx) => { | ||
if (node.expressions[idx]) { | ||
return prev + curr.value.cooked + resolveExpression(node.expressions[idx]); | ||
function resolveArrayExpression(node2) { | ||
const items = []; | ||
for (const [i, element] of node2.elements.entries()) { | ||
if (element) | ||
items[i] = resolveExpression(element); | ||
} | ||
return items; | ||
} | ||
function resolveObjectExpression(node2) { | ||
const obj = {}; | ||
for (const prop of node2.properties) { | ||
if (prop.type !== "ObjectProperty") | ||
return notSupported(prop); | ||
let key; | ||
if ((0, import_types.isIdentifier)(prop.key) && !prop.computed) { | ||
key = prop.key.name; | ||
} else { | ||
key = resolveExpression(prop.key); | ||
} | ||
obj[key] = resolveExpression(prop.value); | ||
} | ||
return obj; | ||
} | ||
function resolveTemplateLiteral(node2) { | ||
return node2.quasis.reduce((prev, curr, idx) => { | ||
if (node2.expressions[idx]) { | ||
return prev + curr.value.cooked + resolveExpression(node2.expressions[idx]); | ||
} | ||
return prev + curr.value.cooked; | ||
}, ""); | ||
} | ||
function getSource(node) { | ||
return code.slice(node.start, node.end); | ||
function getSource(node2) { | ||
return code.slice(node2.start, node2.end); | ||
} | ||
function notSupported(node) { | ||
throw new Error(`not supported ${node.type}: ${getSource(node)}`); | ||
function notSupported(node2) { | ||
throw new Error(`not supported ${node2.type}: ${getSource(node2)}`); | ||
} | ||
}; | ||
} | ||
function transformJsxToString(code, { | ||
debug, | ||
plugins, | ||
id = "" | ||
}) { | ||
const s = new import_magic_string.default(code); | ||
if (id.endsWith(".tsx")) | ||
plugins.push("typescript"); | ||
const nodes = extractJsx(code, plugins); | ||
for (const [node, expr] of nodes) { | ||
let str; | ||
if (!debug) { | ||
str = transformJsx(code, node); | ||
} else { | ||
try { | ||
str = transformJsx(code, node); | ||
} catch (err) { | ||
str = `(() => { throw new Error(${escapeString(err.toString())}) })()`; | ||
} | ||
} | ||
s.overwrite(expr.start, expr.end, str); | ||
} | ||
return { | ||
code: s.toString(), | ||
get map() { | ||
return s.generateMap(); | ||
} | ||
}; | ||
} | ||
@@ -258,3 +417,3 @@ // src/core/options.ts | ||
debug: options.debug ?? false, | ||
plugins: ["typescript", "jsx"] | ||
plugins: ["jsx"] | ||
}; | ||
@@ -274,5 +433,7 @@ } | ||
}, | ||
transform(code) { | ||
transform(code, id) { | ||
try { | ||
return convert(code, opt); | ||
return transformJsxToString(code, __spreadProps(__spreadValues({}, opt), { | ||
id | ||
})); | ||
} catch (err) { | ||
@@ -279,0 +440,0 @@ this.error(`${name} ${err}`); |
{ | ||
"name": "unplugin-jsx-string", | ||
"version": "0.4.1", | ||
"version": "0.5.0", | ||
"packageManager": "pnpm@7.1.9", | ||
@@ -61,3 +61,4 @@ "description": "Converts JSX to HTML strings at compile time.", | ||
"*": [ | ||
"./dist/*" | ||
"./dist/*", | ||
"./*" | ||
] | ||
@@ -70,3 +71,3 @@ } | ||
"dependencies": { | ||
"@babel/parser": "^7.18.4", | ||
"@babel/parser": "^7.18.5", | ||
"@babel/types": "^7.18.4", | ||
@@ -77,3 +78,2 @@ "@rollup/pluginutils": "^4.2.1", | ||
"jsesc": "^3.0.2", | ||
"json5": "^2.2.1", | ||
"magic-string": "^0.26.2", | ||
@@ -87,14 +87,14 @@ "unplugin": "^0.7.0" | ||
"@types/node": "*", | ||
"@types/react": "^18.0.12", | ||
"@types/react": "^18.0.14", | ||
"benchmark": "^2.1.4", | ||
"bumpp": "^7.1.1", | ||
"eslint": "^8.17.0", | ||
"eslint-define-config": "^1.5.0", | ||
"bumpp": "^8.2.1", | ||
"eslint": "^8.18.0", | ||
"eslint-define-config": "^1.5.1", | ||
"fast-glob": "^3.2.11", | ||
"prettier": "^2.6.2", | ||
"tsup": "^6.1.0", | ||
"tsx": "^3.4.2", | ||
"typescript": "^4.7.3", | ||
"prettier": "^2.7.1", | ||
"tsup": "^6.1.2", | ||
"tsx": "^3.4.3", | ||
"typescript": "^4.7.4", | ||
"vite": "^2.9.12", | ||
"vitest": "^0.14.1" | ||
"vitest": "^0.15.1" | ||
}, | ||
@@ -108,2 +108,3 @@ "engines": { | ||
"build": "tsup && tsx scripts/postbuild.mts", | ||
"dev": "pnpm run -C playground dev", | ||
"test": "vitest", | ||
@@ -110,0 +111,0 @@ "release": "bumpp --commit --push --tag && pnpm publish", |
@@ -130,4 +130,4 @@ # unplugin-jsx-string [![npm](https://img.shields.io/npm/v/unplugin-jsx-string.svg)](https://npmjs.com/package/unplugin-jsx-string) | ||
``` | ||
<div>Hello World</div> x 73,893 ops/sec ±0.76% (91 runs sampled) | ||
<div><img src={'foo'} /><div></div></div> x 52,859 ops/sec ±0.77% (93 runs sampled) | ||
<div>Hello World</div> x 89,429 ops/sec ±0.88% (95 runs sampled) | ||
<div><img src={'foo'} /><div></div></div> x 62,522 ops/sec ±0.62% (93 runs sampled) | ||
``` | ||
@@ -134,0 +134,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
121201
8
35
3653
1
- Removedjson5@^2.2.1
- Removedjson5@2.2.3(transitive)
Updated@babel/parser@^7.18.5