@fluixi/compiler 1.0.0-alpha.93 → 1.0.0-alpha.95

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/LICENSE +1 -1
  2. package/dist/analyze/intrinsics.cjs +13 -1
  3. package/dist/analyze/intrinsics.d.cts +14 -0
  4. package/dist/analyze/intrinsics.d.ts +14 -0
  5. package/dist/analyze/intrinsics.d.ts.map +1 -1
  6. package/dist/analyze/intrinsics.js +17 -0
  7. package/dist/analyze/intrinsics.mjs +13 -1
  8. package/dist/analyze/static-graph.cjs +1 -1
  9. package/dist/analyze/static-graph.mjs +1 -1
  10. package/dist/{babel-RJHJQVEM.mjs → babel-V33QLJBF.mjs} +4 -4
  11. package/dist/{chunk-56QSOVVL.mjs → chunk-62F2LLBM.mjs} +1 -1
  12. package/dist/{chunk-R7PPFBCL.mjs → chunk-7GNSGUHK.mjs} +4 -83
  13. package/dist/{chunk-U7HCFLZ2.mjs → chunk-B64LVPTU.mjs} +356 -24
  14. package/dist/{chunk-OD53TMER.mjs → chunk-C3AK5PBV.mjs} +13 -1
  15. package/dist/{chunk-TJIH7TLX.mjs → chunk-GLFUPZ27.mjs} +1 -1
  16. package/dist/chunk-HUABRVWB.mjs +92 -0
  17. package/dist/chunk-XCWP7WJG.mjs +584 -0
  18. package/dist/codegen/backends/imperative.cjs +1 -1
  19. package/dist/codegen/backends/imperative.d.ts.map +1 -1
  20. package/dist/codegen/backends/imperative.js +2 -1
  21. package/dist/codegen/backends/imperative.mjs +1 -1
  22. package/dist/frontend/babel/build-ir-lit.cjs +352 -22
  23. package/dist/frontend/babel/build-ir-lit.mjs +352 -22
  24. package/dist/frontend/babel/build-ir.cjs +352 -22
  25. package/dist/frontend/babel/build-ir.mjs +352 -22
  26. package/dist/frontend/babel/index.cjs +353 -23
  27. package/dist/frontend/babel/index.mjs +353 -23
  28. package/dist/frontend/babel/lower-template.cjs +352 -22
  29. package/dist/frontend/babel/lower-template.mjs +352 -22
  30. package/dist/frontend/babel/plugin.cjs +352 -22
  31. package/dist/frontend/babel/plugin.mjs +352 -22
  32. package/dist/index.cjs +321 -22
  33. package/dist/index.mjs +333 -22
  34. package/dist/integrations.cjs +1240 -56
  35. package/dist/integrations.d.ts.map +1 -1
  36. package/dist/integrations.js +62 -9
  37. package/dist/integrations.mjs +257 -26
  38. package/dist/lower/compile-template.cjs +315 -21
  39. package/dist/lower/compile-template.d.cts +13 -0
  40. package/dist/lower/compile-template.d.ts +13 -0
  41. package/dist/lower/compile-template.d.ts.map +1 -1
  42. package/dist/lower/compile-template.js +3 -0
  43. package/dist/lower/compile-template.mjs +327 -21
  44. package/dist/lower/entities.cjs +288 -0
  45. package/dist/lower/entities.d.cts +1 -0
  46. package/dist/lower/entities.d.ts +2 -0
  47. package/dist/lower/entities.d.ts.map +1 -0
  48. package/dist/lower/entities.js +54 -0
  49. package/dist/lower/entities.mjs +267 -0
  50. package/dist/lower/jsx.cjs +104 -47
  51. package/dist/lower/jsx.d.cts +8 -0
  52. package/dist/lower/jsx.d.ts +8 -0
  53. package/dist/lower/jsx.d.ts.map +1 -1
  54. package/dist/lower/jsx.js +92 -2
  55. package/dist/lower/jsx.mjs +104 -47
  56. package/dist/lower/template.cjs +293 -20
  57. package/dist/lower/template.d.ts.map +1 -1
  58. package/dist/lower/template.js +35 -19
  59. package/dist/lower/template.mjs +293 -20
  60. package/dist/resolve/builtins.cjs +1 -1
  61. package/dist/resolve/builtins.mjs +1 -1
  62. package/dist/resolve/component-globals.cjs +6 -1
  63. package/dist/resolve/component-globals.js +2 -2
  64. package/dist/resolve/component-globals.mjs +6 -1
  65. package/dist/resolve/write-globals.cjs +6 -1
  66. package/dist/resolve/write-globals.mjs +6 -1
  67. package/dist/{server-fns-ZFRDIQ2X.mjs → server-fns-N3SDJXA7.mjs} +5 -4
  68. package/dist/{server-functions-CTDXX67X.mjs → server-functions-LVS66Q4R.mjs} +3 -3
  69. package/dist/transform/index.cjs +973 -33
  70. package/dist/transform/index.mjs +991 -47
  71. package/dist/transform/props.mjs +19 -14
  72. package/dist/transform/server-fns.mjs +19 -14
  73. package/dist/transform/styles.cjs +606 -0
  74. package/dist/transform/styles.d.cts +237 -0
  75. package/dist/transform/styles.d.ts +238 -0
  76. package/dist/transform/styles.d.ts.map +1 -0
  77. package/dist/transform/styles.js +743 -0
  78. package/dist/transform/styles.mjs +671 -0
  79. package/dist/transform/templates.cjs +972 -32
  80. package/dist/transform/templates.d.cts +13 -0
  81. package/dist/transform/templates.d.ts +13 -0
  82. package/dist/transform/templates.d.ts.map +1 -1
  83. package/dist/transform/templates.js +49 -12
  84. package/dist/transform/templates.mjs +990 -46
  85. package/dist/{transform-QWWQDCXE.mjs → transform-P4AETYV4.mjs} +49 -16
  86. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  87. package/dist/vite-styles.cjs +223 -0
  88. package/dist/vite-styles.d.cts +68 -0
  89. package/dist/vite-styles.d.ts +69 -0
  90. package/dist/vite-styles.d.ts.map +1 -0
  91. package/dist/vite-styles.js +241 -0
  92. package/dist/vite-styles.mjs +214 -0
  93. package/package.json +5 -4
@@ -1,4 +1,4 @@
1
- /*! @fluixi/compiler v1.0.0-alpha.93 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/compiler v1.0.0-alpha.95 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
  "use strict";
3
3
  var __create = Object.create;
4
4
  var __defProp = Object.defineProperty;
@@ -44,6 +44,580 @@ module.exports = __toCommonJS(index_exports);
44
44
  var import_parser2 = require("@babel/parser");
45
45
  var import_magic_string2 = __toESM(require("magic-string"), 1);
46
46
 
47
+ // src/transform/styles.ts
48
+ var import_sourcemap_codec = require("@jridgewell/sourcemap-codec");
49
+ var SCOPE_ATTR = "data-fx-s";
50
+ var FUNCTIONS = /* @__PURE__ */ new Set(["FunctionDeclaration", "FunctionExpression", "ArrowFunctionExpression", "ObjectMethod", "ClassMethod"]);
51
+ function collectStyles(program, sourceName, options, tags = { html: /* @__PURE__ */ new Map([["html", "html"]]) }, module2) {
52
+ const plan = {
53
+ scopes: [],
54
+ templateOwners: /* @__PURE__ */ new Map(),
55
+ drop: /* @__PURE__ */ new Set(),
56
+ styles: [],
57
+ diagnostics: [],
58
+ edits: [],
59
+ literals: [],
60
+ references: [],
61
+ shadowClasses: /* @__PURE__ */ new Map()
62
+ };
63
+ if (!options) return plan;
64
+ const literalsOf = findLiterals(program, options.cssModules ?? ["@fluixi/core", "@fluixi/dom"], plan, tags.css ?? []);
65
+ plan.names = literalsOf;
66
+ const classOf = /* @__PURE__ */ new Map();
67
+ const shadowOf = (owner) => {
68
+ const cls = classOf.get(owner);
69
+ return cls ? plan.shadowClasses.get(cls) : void 0;
70
+ };
71
+ const resolved = /* @__PURE__ */ new Map();
72
+ const piecesToNodes = (quasis, expressions, at, stack) => {
73
+ const out = [];
74
+ for (let i = 0; i < quasis.length; i++) {
75
+ const text = quasis[i].value.cooked ?? quasis[i].value.raw;
76
+ if (text.trim()) {
77
+ try {
78
+ const start = quasis[i].loc?.start;
79
+ out.push(...options.process(text, sourceName).map((n) => start ? shiftLoc(n, sourceName, start) : n));
80
+ } catch (error) {
81
+ plan.diagnostics.push({ ...at, message: `CSS could not be processed: ${error.message}` });
82
+ return null;
83
+ }
84
+ }
85
+ const expr = expressions[i];
86
+ if (!expr) continue;
87
+ const value = expr.type === "Identifier" ? resolveLiteral(expr.name, at, stack) : void 0;
88
+ if (value === void 0) {
89
+ plan.diagnostics.push({
90
+ ...at,
91
+ message: "Only css`` values can be interpolated into styles, and only by name: ${base}. Dynamic values go through custom properties (style:--x={...} and var(--x))."
92
+ });
93
+ return null;
94
+ }
95
+ if (value === null) return null;
96
+ out.push(...value);
97
+ }
98
+ return out;
99
+ };
100
+ function resolveLiteral(name, at, stack) {
101
+ const imported = literalsOf.imports.get(name);
102
+ if (imported) {
103
+ const nodes = options?.imported?.get(`${imported.source}#${imported.name}`);
104
+ if (nodes) return nodes.map((n) => keepLocIn(n, options?.importedModules));
105
+ plan.references.push({ name: imported.name, source: imported.source, ...at });
106
+ plan.diagnostics.push({
107
+ ...at,
108
+ message: options?.imported ? `${name} from ${imported.source} is not a css\`\` value the build could find.` : `${name} comes from ${imported.source}: style values from another module are resolved by the build.`
109
+ });
110
+ return null;
111
+ }
112
+ const literal = literalsOf.literals.get(name);
113
+ if (!literal) return void 0;
114
+ if (stack.includes(name)) {
115
+ plan.diagnostics.push({ ...at, message: `css\`\` values include each other: ${[...stack, name].join(" → ")}.` });
116
+ return null;
117
+ }
118
+ if (!resolved.has(name)) {
119
+ resolved.set(name, piecesToNodes(literal.quasi.quasis, literal.quasi.expressions, at, [...stack, name]));
120
+ }
121
+ return resolved.get(name);
122
+ }
123
+ for (const [name, literal] of literalsOf.literals) {
124
+ const at = { line: literal.loc?.start.line ?? 0, column: literal.loc?.start.column ?? 0 };
125
+ const nodes = resolveLiteral(name, at, []);
126
+ const id = hash(`${sourceName}:css:${name}`);
127
+ plan.edits.push({ start: literal.start, end: literal.end, code: `({ $fxStyle: ${JSON.stringify(id)} })` });
128
+ if (nodes) plan.literals.push({ id, name, css: printStyle(nodes, options.minify), nodes });
129
+ }
130
+ const scopeOf = /* @__PURE__ */ new Map();
131
+ const names = /* @__PURE__ */ new Map();
132
+ const named = /* @__PURE__ */ new Map();
133
+ const visit = (node, owners) => {
134
+ if (!node || typeof node !== "object") return;
135
+ if (node.type === "VariableDeclarator" && node.id.type === "Identifier" && node.init && FUNCTIONS.has(node.init.type)) {
136
+ named.set(node.init, node.id.name);
137
+ }
138
+ if ((node.type === "ClassDeclaration" || node.type === "ClassExpression") && node.id) {
139
+ for (const member of node.body.body) if (member.type === "ClassMethod") named.set(member, node.id.name);
140
+ }
141
+ if (node.type === "ClassDeclaration" || node.type === "ClassExpression") {
142
+ for (const member of node.body.body) if (member.type === "ClassMethod") classOf.set(member, node);
143
+ const shadow = staticMember(node, "shadow");
144
+ if (shadow?.value && !(shadow.value.type === "BooleanLiteral" && shadow.value.value === false)) {
145
+ plan.shadowClasses.set(node, { node, styles: staticMember(node, "styles"), indexes: [] });
146
+ }
147
+ }
148
+ if (node.type === "TaggedTemplateExpression" && node.tag.type === "Identifier" && tags.html.get(node.tag.name) === "html") {
149
+ const text = node.quasi.quasis.map((q) => q.value.raw).join("");
150
+ if (/<style[\s>]/.test(text)) {
151
+ const at = { line: node.loc?.start.line ?? 0, column: node.loc?.start.column ?? 0 };
152
+ const owner = owners[0];
153
+ if (!owner) plan.diagnostics.push({ ...at, message: "<style> has to be written inside a component." });
154
+ else {
155
+ const id = idFor(owner);
156
+ const shadow = shadowOf(owner);
157
+ plan.templateOwners.set(node.start, { id, component: functionName(owner, named) });
158
+ for (const block of templateBlocks(node.quasi)) compileBlock(block, block.scoped, owner, at);
159
+ }
160
+ }
161
+ }
162
+ const inner = FUNCTIONS.has(node.type) ? [...owners, node] : owners;
163
+ if (node.type === "JSXElement" && isStyle(node)) {
164
+ handle(node, owners);
165
+ return;
166
+ }
167
+ for (const key of Object.keys(node)) {
168
+ if (key === "loc" || key === "leadingComments" || key === "trailingComments" || key === "innerComments") continue;
169
+ const value = node[key];
170
+ if (Array.isArray(value)) for (const v of value) visit(v, inner);
171
+ else if (value && typeof value === "object" && "type" in value) visit(value, inner);
172
+ }
173
+ };
174
+ const handle = (node, owners) => {
175
+ const at = { line: node.loc?.start.line ?? 0, column: node.loc?.start.column ?? 0 };
176
+ const pieces = blockPieces(node);
177
+ if (pieces === null) {
178
+ plan.diagnostics.push({
179
+ ...at,
180
+ message: "<style> needs its CSS as one template literal, <style>{`...`}</style>: JSX reads a bare `{` as an expression."
181
+ });
182
+ return;
183
+ }
184
+ const owner = owners[0];
185
+ if (!owner) {
186
+ plan.diagnostics.push({ ...at, message: "<style> has to be written inside a component." });
187
+ return;
188
+ }
189
+ compileBlock(pieces, isScoped(node), owner, at);
190
+ plan.drop.add(node.start);
191
+ };
192
+ const compileBlock = (pieces, scoped, owner, at) => {
193
+ const component = functionName(owner, named);
194
+ const id = idFor(owner);
195
+ const processed = piecesToNodes(pieces.quasis, pieces.expressions, at, []);
196
+ if (!processed) return;
197
+ let nodes = processed;
198
+ const shadow = shadowOf(owner);
199
+ if (scoped && !shadow) {
200
+ if (!plan.scopes.some((s) => s.value === id)) plan.scopes.push({ start: owner.start, end: owner.end, value: id });
201
+ nodes = scopeNodes(nodes, id, (message) => plan.diagnostics.push({ ...at, message }));
202
+ }
203
+ const printed = module2 ? printStyleWithMap(nodes, options.minify, sourceName, module2, options.importedModules) : { css: printStyle(nodes, options.minify) };
204
+ plan.styles.push({ id, scoped: scoped && !shadow, component, ...printed, ...shadow ? { shadow: true } : {}, ...at });
205
+ if (shadow) shadow.indexes.push(plan.styles.length - 1);
206
+ };
207
+ function idFor(owner) {
208
+ let id = scopeOf.get(owner);
209
+ if (!id) {
210
+ const component = functionName(owner, named);
211
+ const seen = names.get(component) ?? 0;
212
+ names.set(component, seen + 1);
213
+ id = hash(`${sourceName}:${component}${seen ? ":" + seen : ""}`);
214
+ scopeOf.set(owner, id);
215
+ }
216
+ return id;
217
+ }
218
+ visit(program, []);
219
+ return plan;
220
+ }
221
+ function applyTemplateStyles(ir, t) {
222
+ const walk8 = (node) => {
223
+ const children = node.children;
224
+ if (children) {
225
+ for (let i = children.length - 1; i >= 0; i--) {
226
+ const child = children[i];
227
+ if (child.kind === "element" && child.tag === "style" && t.owner) children.splice(i, 1);
228
+ else walk8(child);
229
+ }
230
+ }
231
+ if (t.scope && node.kind === "element" && node.tag !== "style" && node.props && !node.props.some((p) => p.name === SCOPE_ATTR)) {
232
+ node.props.unshift({ name: SCOPE_ATTR, kind: "attr", literal: t.scope });
233
+ }
234
+ };
235
+ walk8(ir);
236
+ }
237
+ function staticMember(cls, name) {
238
+ return cls.body.body.find(
239
+ (m) => m.type === "ClassProperty" && m.static && (m.key.type === "Identifier" && m.key.name === name || m.key.type === "StringLiteral" && m.key.value === name)
240
+ );
241
+ }
242
+ var styleIds = {
243
+ block: (owner, index) => `${owner}.fx-${index}.css`,
244
+ inline: (owner, index) => `${owner}.fx-${index}.css?inline`,
245
+ literal: (owner, name) => `${owner}.fx-literal-${name}.css?inline`
246
+ };
247
+ function finishShadowStyles(plan, code, moduleId) {
248
+ const edits = [];
249
+ const imports = [];
250
+ let next = 0;
251
+ const importOf = (specifier) => {
252
+ const local = `__fxShadow${next++}`;
253
+ imports.push(`import ${local} from ${JSON.stringify(specifier)};
254
+ `);
255
+ return local;
256
+ };
257
+ for (const shadow of plan.shadowClasses.values()) {
258
+ const blocks = shadow.indexes.map((i) => importOf(styleIds.inline(moduleId, i)));
259
+ let value;
260
+ const prop = shadow.styles;
261
+ if (prop?.value) {
262
+ const start = prop.value.start;
263
+ let text = code.slice(start, prop.value.end);
264
+ const replacements = [];
265
+ walkIdentifiers(prop.value, (id) => {
266
+ const local = plan.names?.literals.has(id.name) ? importOf(styleIds.literal(moduleId, id.name)) : plan.names?.imports.has(id.name) && !/\.css(\?|$)/.test(plan.names.imports.get(id.name).source) ? importOf(styleIds.literal(plan.names.imports.get(id.name).source, plan.names.imports.get(id.name).name)) : void 0;
267
+ if (local) replacements.push({ at: id.start - start, length: id.name.length, with: local });
268
+ });
269
+ for (const r of replacements.sort((a, b) => b.at - a.at)) text = text.slice(0, r.at) + r.with + text.slice(r.at + r.length);
270
+ value = text;
271
+ }
272
+ if (!blocks.length && value === void 0) continue;
273
+ if (prop?.value) {
274
+ const merged = blocks.length ? `[${value}, ${blocks.join(", ")}]` : value;
275
+ edits.push({ start: prop.value.start, end: prop.value.end, code: merged });
276
+ } else if (blocks.length) {
277
+ const open = shadow.node.body.start + 1;
278
+ edits.push({ start: open, end: open, code: ` static styles = [${blocks.join(", ")}];` });
279
+ }
280
+ }
281
+ if (imports.length) edits.push({ start: 0, end: 0, code: imports.join("") });
282
+ return edits;
283
+ }
284
+ function walkIdentifiers(node, visit) {
285
+ if (!node || typeof node !== "object") return;
286
+ if (node.type === "Identifier") return visit(node);
287
+ if (node.type === "MemberExpression") return walkIdentifiers(node.object, visit);
288
+ if (node.type === "ObjectProperty") return walkIdentifiers(node.value, visit);
289
+ for (const key of Object.keys(node)) {
290
+ if (key === "loc") continue;
291
+ const value = node[key];
292
+ if (Array.isArray(value)) for (const v of value) walkIdentifiers(v, visit);
293
+ else if (value && typeof value === "object" && "type" in value) walkIdentifiers(value, visit);
294
+ }
295
+ }
296
+ function isStyle(node) {
297
+ const name = node.openingElement.name;
298
+ return name.type === "JSXIdentifier" && name.name === "style";
299
+ }
300
+ function isScoped(node) {
301
+ return node.openingElement.attributes.some((a) => a.type === "JSXAttribute" && a.name.type === "JSXIdentifier" && a.name.name === "scoped");
302
+ }
303
+ function templateBlocks(quasi) {
304
+ const blocks = [];
305
+ let open = null;
306
+ quasi.quasis.forEach((q, i) => {
307
+ const raw = q.value.raw;
308
+ let from = 0;
309
+ while (from <= raw.length) {
310
+ if (!open) {
311
+ const tag = /<style\b([^>]*)>/g;
312
+ tag.lastIndex = from;
313
+ const m = tag.exec(raw);
314
+ if (!m) break;
315
+ open = { quasis: [], expressions: [], scoped: /\bscoped\b/.test(m[1]) };
316
+ from = m.index + m[0].length;
317
+ }
318
+ const close = raw.indexOf("</style", from);
319
+ open.quasis.push(slicePiece(q, raw, from, close === -1 ? raw.length : close));
320
+ if (close === -1) break;
321
+ blocks.push(open);
322
+ open = null;
323
+ from = close;
324
+ }
325
+ const expr = quasi.expressions[i];
326
+ if (open && expr) open.expressions.push(expr);
327
+ });
328
+ return blocks;
329
+ }
330
+ function slicePiece(q, raw, from, to) {
331
+ const text = raw.slice(from, to);
332
+ const start = q.loc?.start;
333
+ if (!start) return { type: "TemplateElement", value: { raw: text, cooked: text } };
334
+ const before = raw.slice(0, from).split("\n");
335
+ const line = start.line + before.length - 1;
336
+ const column = before.length > 1 ? before[before.length - 1].length : start.column + from;
337
+ return { type: "TemplateElement", value: { raw: text, cooked: text }, loc: { start: { line, column } } };
338
+ }
339
+ function blockPieces(node) {
340
+ const meaningful = node.children.filter((c) => !(c.type === "JSXText" && !c.value.trim()));
341
+ if (meaningful.length === 0) return { quasis: [], expressions: [] };
342
+ if (meaningful.length !== 1) return null;
343
+ const only = meaningful[0];
344
+ if (only.type !== "JSXExpressionContainer") return null;
345
+ const expr = only.expression;
346
+ if (expr.type === "StringLiteral") return { quasis: [{ type: "TemplateElement", value: { raw: expr.value, cooked: expr.value } }], expressions: [] };
347
+ if (expr.type === "TemplateLiteral") return { quasis: expr.quasis, expressions: expr.expressions };
348
+ return null;
349
+ }
350
+ function findLiterals(program, modules, plan, intrinsic) {
351
+ const literals = /* @__PURE__ */ new Map();
352
+ const imports = /* @__PURE__ */ new Map();
353
+ const tags = new Set(intrinsic);
354
+ for (const statement of program.body ?? []) {
355
+ if (statement.type !== "ImportDeclaration") continue;
356
+ const source = statement.source.value;
357
+ const specifiers = statement.specifiers;
358
+ for (const sp of specifiers) {
359
+ if (sp.type === "ImportSpecifier") imports.set(sp.local.name, { source, name: sp.imported.name ?? sp.imported.value });
360
+ }
361
+ if (!modules.includes(source)) continue;
362
+ const css = specifiers.find((sp) => sp.type === "ImportSpecifier" && (sp.imported.name ?? sp.imported.value) === "css");
363
+ if (!css) continue;
364
+ const local = css.local.name;
365
+ tags.add(local);
366
+ imports.delete(local);
367
+ plan.edits.push({ start: statement.start, end: statement.end, code: importWithout(statement, css) });
368
+ }
369
+ if (tags.size === 0) return { literals, imports };
370
+ const visit = (node) => {
371
+ if (!node || typeof node !== "object") return;
372
+ if (node.type === "VariableDeclarator" && node.id.type === "Identifier" && node.init?.type === "TaggedTemplateExpression" && node.init.tag.type === "Identifier" && tags.has(node.init.tag.name)) {
373
+ literals.set(node.id.name, node.init);
374
+ }
375
+ for (const key of Object.keys(node)) {
376
+ if (key === "loc") continue;
377
+ const value = node[key];
378
+ if (Array.isArray(value)) for (const v of value) visit(v);
379
+ else if (value && typeof value === "object" && "type" in value) visit(value);
380
+ }
381
+ };
382
+ visit(program);
383
+ return { literals, imports };
384
+ }
385
+ function importWithout(statement, removed) {
386
+ const rest = statement.specifiers.filter((sp) => sp !== removed);
387
+ const source = JSON.stringify(statement.source.value);
388
+ if (rest.length === 0) return "";
389
+ const def = rest.find((sp) => sp.type === "ImportDefaultSpecifier");
390
+ const ns = rest.find((sp) => sp.type === "ImportNamespaceSpecifier");
391
+ const named = rest.filter((sp) => sp.type === "ImportSpecifier").map((sp) => {
392
+ const imported = sp.imported.name ?? JSON.stringify(sp.imported.value);
393
+ return imported === sp.local.name ? imported : `${imported} as ${sp.local.name}`;
394
+ });
395
+ const parts = [def?.local.name, ns ? `* as ${ns.local.name}` : void 0, named.length ? `{ ${named.join(", ")} }` : void 0].filter(Boolean);
396
+ return `import ${parts.join(", ")} from ${source};`;
397
+ }
398
+ function functionName(fn, named) {
399
+ if ((fn.type === "FunctionDeclaration" || fn.type === "FunctionExpression") && fn.id) return fn.id.name;
400
+ return named.get(fn) ?? "anonymous";
401
+ }
402
+ function hash(text) {
403
+ let h = 2166136261;
404
+ for (let i = 0; i < text.length; i++) {
405
+ h ^= text.charCodeAt(i);
406
+ h = Math.imul(h, 16777619);
407
+ }
408
+ return (h >>> 0).toString(36);
409
+ }
410
+ var OPAQUE = /(^|-)keyframes$|^font-face$|^property$|^counter-style$|^page$|^font-feature-values$/;
411
+ function scopeNodes(nodes, id, warn = () => {
412
+ }) {
413
+ return nodes.map((node) => {
414
+ if (node.kind === "rule") return { ...node, selector: scopeSelector(node.selector, id, warn) };
415
+ if (node.kind === "at-rule" && !OPAQUE.test(node.name)) return { ...node, nodes: scopeNodes(node.nodes, id, warn) };
416
+ return node;
417
+ });
418
+ }
419
+ function scopeSelector(selector, id, warn = () => {
420
+ }) {
421
+ return splitTop(selector, ",").map((complex) => scopeComplex(complex.trim(), `[${SCOPE_ATTR}="${id}"]`, warn)).join(", ");
422
+ }
423
+ function scopeComplex(selector, attr, warn) {
424
+ if (/:host\b|::slotted\(/.test(selector)) {
425
+ warn(`\`${selector}\` only means something in a shadow root; in a light-DOM component it is left as written.`);
426
+ return selector;
427
+ }
428
+ const parts = compounds(selector);
429
+ const deep = parts.findIndex((p) => p.text.startsWith(":deep("));
430
+ if (deep !== -1) {
431
+ const inner = unwrap(parts[deep].text, ":deep(");
432
+ const before = parts.slice(0, deep);
433
+ if (before.length === 0) return `${attr} ${inner}`;
434
+ const scopedBefore = scopeAt(before, before.length - 1, attr);
435
+ return `${join(scopedBefore)} ${inner}`;
436
+ }
437
+ let target = -1;
438
+ for (let i = parts.length - 1; i >= 0; i--) {
439
+ if (!parts[i].text.startsWith(":global(")) {
440
+ target = i;
441
+ break;
442
+ }
443
+ }
444
+ const out = target === -1 ? parts : scopeAt(parts, target, attr);
445
+ return join(out.map((p) => p.text.startsWith(":global(") ? { ...p, text: unwrap(p.text, ":global(") } : p));
446
+ }
447
+ function scopeAt(parts, index, attr) {
448
+ return parts.map((p, i) => i === index ? { ...p, text: insertAttr(p.text, attr) } : p);
449
+ }
450
+ function insertAttr(compound, attr) {
451
+ let depth = 0;
452
+ let quote = "";
453
+ for (let i = 0; i < compound.length; i++) {
454
+ const c = compound[i];
455
+ if (quote) {
456
+ if (c === "\\") i++;
457
+ else if (c === quote) quote = "";
458
+ continue;
459
+ }
460
+ if (c === "\\") {
461
+ i++;
462
+ continue;
463
+ }
464
+ if (c === '"' || c === "'") quote = c;
465
+ else if (c === "(" || c === "[") depth++;
466
+ else if (c === ")" || c === "]") depth--;
467
+ else if (c === ":" && depth === 0 && i > 0) return compound.slice(0, i) + attr + compound.slice(i);
468
+ }
469
+ return compound + attr;
470
+ }
471
+ function compounds(selector) {
472
+ const out = [];
473
+ let depth = 0;
474
+ let quote = "";
475
+ let current = "";
476
+ let combinator = "";
477
+ const push = () => {
478
+ if (current.trim()) out.push({ combinator: out.length ? combinator || " " : "", text: current.trim() });
479
+ current = "";
480
+ combinator = "";
481
+ };
482
+ for (let i = 0; i < selector.length; i++) {
483
+ const c = selector[i];
484
+ if (quote) {
485
+ current += c;
486
+ if (c === "\\") current += selector[++i] ?? "";
487
+ else if (c === quote) quote = "";
488
+ continue;
489
+ }
490
+ if (c === "\\") {
491
+ current += c + (selector[++i] ?? "");
492
+ continue;
493
+ }
494
+ if (c === '"' || c === "'") quote = c;
495
+ if (c === "(" || c === "[") depth++;
496
+ if (c === ")" || c === "]") depth--;
497
+ if (depth === 0 && (c === ">" || c === "+" || c === "~")) {
498
+ push();
499
+ combinator = c;
500
+ continue;
501
+ }
502
+ if (depth === 0 && /\s/.test(c)) {
503
+ if (current.trim()) {
504
+ const keep = combinator;
505
+ push();
506
+ combinator = keep;
507
+ }
508
+ continue;
509
+ }
510
+ current += c;
511
+ }
512
+ push();
513
+ return out;
514
+ }
515
+ function join(parts) {
516
+ return parts.map((p, i) => i === 0 ? p.text : p.combinator === " " ? ` ${p.text}` : ` ${p.combinator} ${p.text}`).join("");
517
+ }
518
+ function unwrap(text, prefix) {
519
+ return text.slice(prefix.length, text.lastIndexOf(")")).trim() + text.slice(text.lastIndexOf(")") + 1);
520
+ }
521
+ function splitTop(selector, separator) {
522
+ const parts = [];
523
+ let depth = 0;
524
+ let quote = "";
525
+ let start = 0;
526
+ for (let i = 0; i < selector.length; i++) {
527
+ const c = selector[i];
528
+ if (quote) {
529
+ if (c === "\\") i++;
530
+ else if (c === quote) quote = "";
531
+ } else if (c === '"' || c === "'") quote = c;
532
+ else if (c === "\\") i++;
533
+ else if (c === "(" || c === "[") depth++;
534
+ else if (c === ")" || c === "]") depth--;
535
+ else if (c === separator && depth === 0) {
536
+ parts.push(selector.slice(start, i));
537
+ start = i + 1;
538
+ }
539
+ }
540
+ parts.push(selector.slice(start));
541
+ return parts.filter((p) => p.trim());
542
+ }
543
+ function shiftLoc(node, source, start) {
544
+ const loc = node.loc && node.loc.source === source ? { source, line: start.line + node.loc.line - 1, column: node.loc.line === 1 ? start.column + node.loc.column : node.loc.column } : node.loc;
545
+ if (node.kind === "rule" || node.kind === "at-rule") return { ...node, loc, nodes: node.nodes.map((n) => shiftLoc(n, source, start)) };
546
+ return { ...node, loc };
547
+ }
548
+ function keepLocIn(node, modules) {
549
+ const keep = node.loc !== void 0 && modules?.has(node.loc.source) === true;
550
+ const { loc, ...rest } = node;
551
+ const kept = keep ? { ...rest, loc } : rest;
552
+ if (kept.kind === "rule" || kept.kind === "at-rule") return { ...kept, nodes: kept.nodes.map((n) => keepLocIn(n, modules)) };
553
+ return kept;
554
+ }
555
+ function printStyleWithMap(nodes, minify, sourceName, module2, others) {
556
+ const sources = [module2];
557
+ const index = /* @__PURE__ */ new Map([[sourceName, 0]]);
558
+ const sourceOf = (name) => {
559
+ if (index.has(name)) return index.get(name);
560
+ const other = others?.get(name);
561
+ if (!other) return void 0;
562
+ index.set(name, sources.push(other) - 1);
563
+ return index.get(name);
564
+ };
565
+ const lines = [[]];
566
+ let css = "";
567
+ let column = 0;
568
+ const emit = (text) => {
569
+ for (const ch of text) {
570
+ css += ch;
571
+ if (ch === "\n") {
572
+ lines.push([]);
573
+ column = 0;
574
+ } else column++;
575
+ }
576
+ };
577
+ const mark = (loc) => {
578
+ const at = loc ? sourceOf(loc.source) : void 0;
579
+ if (loc && at !== void 0) lines[lines.length - 1].push([column, at, loc.line - 1, loc.column]);
580
+ };
581
+ const write = (node, depth) => {
582
+ const pad = minify ? "" : " ".repeat(depth);
583
+ const nl = minify ? "" : "\n";
584
+ const sp = minify ? "" : " ";
585
+ emit(pad);
586
+ mark(node.loc);
587
+ if (node.kind === "declaration") {
588
+ emit(`${node.property}:${sp}${node.value}${node.important ? `${sp}!important` : ""};${nl}`);
589
+ } else if (node.kind === "raw") {
590
+ emit(`${node.text}${nl}`);
591
+ } else {
592
+ emit(`${node.kind === "rule" ? node.selector : `@${node.name}${node.params ? " " + node.params : ""}`}${sp}{${nl}`);
593
+ for (const child of node.nodes) write(child, depth + 1);
594
+ emit(`${pad}}${nl}`);
595
+ }
596
+ };
597
+ for (const node of nodes) write(node, 0);
598
+ return { css, map: { version: 3, sources: sources.map((s) => s.id), sourcesContent: sources.map((s) => s.code), names: [], mappings: (0, import_sourcemap_codec.encode)(lines) } };
599
+ }
600
+ function printStyle(nodes, minify = false) {
601
+ const out = [];
602
+ const write = (node, depth) => {
603
+ const pad = minify ? "" : " ".repeat(depth);
604
+ const nl = minify ? "" : "\n";
605
+ const sp = minify ? "" : " ";
606
+ if (node.kind === "declaration") {
607
+ out.push(`${pad}${node.property}:${sp}${node.value}${node.important ? `${sp}!important` : ""};${nl}`);
608
+ } else if (node.kind === "raw") {
609
+ out.push(`${pad}${node.text}${nl}`);
610
+ } else {
611
+ const header = node.kind === "rule" ? node.selector : `@${node.name}${node.params ? " " + node.params : ""}`;
612
+ out.push(`${pad}${header}${sp}{${nl}`);
613
+ for (const child of node.nodes) write(child, depth + 1);
614
+ out.push(`${pad}}${nl}`);
615
+ }
616
+ };
617
+ for (const node of nodes) write(node, 0);
618
+ return out.join("");
619
+ }
620
+
47
621
  // src/optimize/analyze-static.ts
48
622
  function propReason(prop) {
49
623
  switch (prop.kind) {
@@ -541,6 +1115,16 @@ var PRIMITIVE_MODULES = [
541
1115
  "@fluixi/reactive/cached-resource",
542
1116
  "@fluixi/core"
543
1117
  ];
1118
+ var TAG_INTRINSICS = {
1119
+ $html: { export: "html", module: "@fluixi/core" },
1120
+ $svg: { export: "svg", module: "@fluixi/core" },
1121
+ $css: { export: "css", module: "@fluixi/core" }
1122
+ };
1123
+ function tagIntrinsics(bound) {
1124
+ const tags = /* @__PURE__ */ new Map();
1125
+ for (const [name, tag] of Object.entries(TAG_INTRINSICS)) if (!bound.has(name)) tags.set(name, tag.export);
1126
+ return tags;
1127
+ }
544
1128
  var INTRINSIC_CALL = new RegExp(`\\$(?:${Object.keys(INTRINSICS).map((n) => n.slice(1)).join("|")})\\s*\\(`);
545
1129
  function mayHaveIntrinsic(code) {
546
1130
  return INTRINSIC_CALL.test(code);
@@ -1044,7 +1628,7 @@ function emitComponent(name, props, children, used, templates, at) {
1044
1628
  }
1045
1629
  let obj = `{ ${bodies.map(([name2, body]) => `get ${propKey(name2)}() { return ${body}; }`).join(", ")} }`;
1046
1630
  if (bodies.some(([, body]) => /\bthis\b/.test(body))) {
1047
- const thunks = bodies.map(([name2, body]) => `${JSON.stringify(name2)}: () => ${body}`);
1631
+ const thunks = bodies.map(([name2, body]) => `${JSON.stringify(name2)}: () => (${body})`);
1048
1632
  const getters = bodies.map(([name2]) => `get ${propKey(name2)}() { return _$t[${JSON.stringify(name2)}](); }`);
1049
1633
  obj = `((_$t) => ({ ${getters.join(", ")} }))({ ${thunks.join(", ")} })`;
1050
1634
  }
@@ -1243,6 +1827,271 @@ function cleanTemplateText(value) {
1243
1827
  return out;
1244
1828
  }
1245
1829
 
1830
+ // src/lower/entities.ts
1831
+ var NAMED = {
1832
+ quot: 34,
1833
+ amp: 38,
1834
+ apos: 39,
1835
+ lt: 60,
1836
+ gt: 62,
1837
+ nbsp: 160,
1838
+ iexcl: 161,
1839
+ cent: 162,
1840
+ pound: 163,
1841
+ curren: 164,
1842
+ yen: 165,
1843
+ brvbar: 166,
1844
+ sect: 167,
1845
+ uml: 168,
1846
+ copy: 169,
1847
+ ordf: 170,
1848
+ laquo: 171,
1849
+ not: 172,
1850
+ shy: 173,
1851
+ reg: 174,
1852
+ macr: 175,
1853
+ deg: 176,
1854
+ plusmn: 177,
1855
+ sup2: 178,
1856
+ sup3: 179,
1857
+ acute: 180,
1858
+ micro: 181,
1859
+ para: 182,
1860
+ middot: 183,
1861
+ cedil: 184,
1862
+ sup1: 185,
1863
+ ordm: 186,
1864
+ raquo: 187,
1865
+ frac14: 188,
1866
+ frac12: 189,
1867
+ frac34: 190,
1868
+ iquest: 191,
1869
+ Agrave: 192,
1870
+ Aacute: 193,
1871
+ Acirc: 194,
1872
+ Atilde: 195,
1873
+ Auml: 196,
1874
+ Aring: 197,
1875
+ AElig: 198,
1876
+ Ccedil: 199,
1877
+ Egrave: 200,
1878
+ Eacute: 201,
1879
+ Ecirc: 202,
1880
+ Euml: 203,
1881
+ Igrave: 204,
1882
+ Iacute: 205,
1883
+ Icirc: 206,
1884
+ Iuml: 207,
1885
+ ETH: 208,
1886
+ Ntilde: 209,
1887
+ Ograve: 210,
1888
+ Oacute: 211,
1889
+ Ocirc: 212,
1890
+ Otilde: 213,
1891
+ Ouml: 214,
1892
+ times: 215,
1893
+ Oslash: 216,
1894
+ Ugrave: 217,
1895
+ Uacute: 218,
1896
+ Ucirc: 219,
1897
+ Uuml: 220,
1898
+ Yacute: 221,
1899
+ THORN: 222,
1900
+ szlig: 223,
1901
+ agrave: 224,
1902
+ aacute: 225,
1903
+ acirc: 226,
1904
+ atilde: 227,
1905
+ auml: 228,
1906
+ aring: 229,
1907
+ aelig: 230,
1908
+ ccedil: 231,
1909
+ egrave: 232,
1910
+ eacute: 233,
1911
+ ecirc: 234,
1912
+ euml: 235,
1913
+ igrave: 236,
1914
+ iacute: 237,
1915
+ icirc: 238,
1916
+ iuml: 239,
1917
+ eth: 240,
1918
+ ntilde: 241,
1919
+ ograve: 242,
1920
+ oacute: 243,
1921
+ ocirc: 244,
1922
+ otilde: 245,
1923
+ ouml: 246,
1924
+ divide: 247,
1925
+ oslash: 248,
1926
+ ugrave: 249,
1927
+ uacute: 250,
1928
+ ucirc: 251,
1929
+ uuml: 252,
1930
+ yacute: 253,
1931
+ thorn: 254,
1932
+ yuml: 255,
1933
+ OElig: 338,
1934
+ oelig: 339,
1935
+ Scaron: 352,
1936
+ scaron: 353,
1937
+ Yuml: 376,
1938
+ fnof: 402,
1939
+ circ: 710,
1940
+ tilde: 732,
1941
+ Alpha: 913,
1942
+ Beta: 914,
1943
+ Gamma: 915,
1944
+ Delta: 916,
1945
+ Epsilon: 917,
1946
+ Zeta: 918,
1947
+ Eta: 919,
1948
+ Theta: 920,
1949
+ Iota: 921,
1950
+ Kappa: 922,
1951
+ Lambda: 923,
1952
+ Mu: 924,
1953
+ Nu: 925,
1954
+ Xi: 926,
1955
+ Omicron: 927,
1956
+ Pi: 928,
1957
+ Rho: 929,
1958
+ Sigma: 931,
1959
+ Tau: 932,
1960
+ Upsilon: 933,
1961
+ Phi: 934,
1962
+ Chi: 935,
1963
+ Psi: 936,
1964
+ Omega: 937,
1965
+ alpha: 945,
1966
+ beta: 946,
1967
+ gamma: 947,
1968
+ delta: 948,
1969
+ epsilon: 949,
1970
+ zeta: 950,
1971
+ eta: 951,
1972
+ theta: 952,
1973
+ iota: 953,
1974
+ kappa: 954,
1975
+ lambda: 955,
1976
+ mu: 956,
1977
+ nu: 957,
1978
+ xi: 958,
1979
+ omicron: 959,
1980
+ pi: 960,
1981
+ rho: 961,
1982
+ sigmaf: 962,
1983
+ sigma: 963,
1984
+ tau: 964,
1985
+ upsilon: 965,
1986
+ phi: 966,
1987
+ chi: 967,
1988
+ psi: 968,
1989
+ omega: 969,
1990
+ thetasym: 977,
1991
+ upsih: 978,
1992
+ piv: 982,
1993
+ ensp: 8194,
1994
+ emsp: 8195,
1995
+ thinsp: 8201,
1996
+ zwnj: 8204,
1997
+ zwj: 8205,
1998
+ lrm: 8206,
1999
+ rlm: 8207,
2000
+ ndash: 8211,
2001
+ mdash: 8212,
2002
+ lsquo: 8216,
2003
+ rsquo: 8217,
2004
+ sbquo: 8218,
2005
+ ldquo: 8220,
2006
+ rdquo: 8221,
2007
+ bdquo: 8222,
2008
+ dagger: 8224,
2009
+ Dagger: 8225,
2010
+ bull: 8226,
2011
+ hellip: 8230,
2012
+ permil: 8240,
2013
+ prime: 8242,
2014
+ Prime: 8243,
2015
+ lsaquo: 8249,
2016
+ rsaquo: 8250,
2017
+ oline: 8254,
2018
+ frasl: 8260,
2019
+ euro: 8364,
2020
+ image: 8465,
2021
+ weierp: 8472,
2022
+ real: 8476,
2023
+ trade: 8482,
2024
+ alefsym: 8501,
2025
+ larr: 8592,
2026
+ uarr: 8593,
2027
+ rarr: 8594,
2028
+ darr: 8595,
2029
+ harr: 8596,
2030
+ crarr: 8629,
2031
+ lArr: 8656,
2032
+ uArr: 8657,
2033
+ rArr: 8658,
2034
+ dArr: 8659,
2035
+ hArr: 8660,
2036
+ forall: 8704,
2037
+ part: 8706,
2038
+ exist: 8707,
2039
+ empty: 8709,
2040
+ nabla: 8711,
2041
+ isin: 8712,
2042
+ notin: 8713,
2043
+ ni: 8715,
2044
+ prod: 8719,
2045
+ sum: 8721,
2046
+ minus: 8722,
2047
+ lowast: 8727,
2048
+ radic: 8730,
2049
+ prop: 8733,
2050
+ infin: 8734,
2051
+ ang: 8736,
2052
+ and: 8743,
2053
+ or: 8744,
2054
+ cap: 8745,
2055
+ cup: 8746,
2056
+ int: 8747,
2057
+ there4: 8756,
2058
+ sim: 8764,
2059
+ cong: 8773,
2060
+ asymp: 8776,
2061
+ ne: 8800,
2062
+ equiv: 8801,
2063
+ le: 8804,
2064
+ ge: 8805,
2065
+ sub: 8834,
2066
+ sup: 8835,
2067
+ nsub: 8836,
2068
+ sube: 8838,
2069
+ supe: 8839,
2070
+ oplus: 8853,
2071
+ otimes: 8855,
2072
+ perp: 8869,
2073
+ sdot: 8901,
2074
+ lceil: 8968,
2075
+ rceil: 8969,
2076
+ lfloor: 8970,
2077
+ rfloor: 8971,
2078
+ lang: 9001,
2079
+ rang: 9002,
2080
+ loz: 9674,
2081
+ spades: 9824,
2082
+ clubs: 9827,
2083
+ hearts: 9829,
2084
+ diams: 9830
2085
+ };
2086
+ var REFERENCE = /&(?:#[xX]([0-9a-fA-F]{1,6})|#([0-9]{1,7})|([a-zA-Z][a-zA-Z0-9]{1,31}));/g;
2087
+ function decodeEntities(value) {
2088
+ if (!value.includes("&")) return value;
2089
+ return value.replace(REFERENCE, (match, hex, dec, name) => {
2090
+ const code = hex ? parseInt(hex, 16) : dec ? parseInt(dec, 10) : Object.prototype.hasOwnProperty.call(NAMED, name) ? NAMED[name] : void 0;
2091
+ return code !== void 0 && code <= 1114111 ? String.fromCodePoint(code) : match;
2092
+ });
2093
+ }
2094
+
1246
2095
  // src/lower/template.ts
1247
2096
  var DELEGATED = /* @__PURE__ */ new Set([
1248
2097
  "click",
@@ -1329,7 +2178,7 @@ var Lowerer = class {
1329
2178
  switch (node.kind) {
1330
2179
  case "Text": {
1331
2180
  if (node.raw) return { kind: "text", value: node.value };
1332
- const cleaned = cleanTemplateText(node.value);
2181
+ const cleaned = decodeEntities(cleanTemplateText(node.value));
1333
2182
  return cleaned ? { kind: "text", value: cleaned } : null;
1334
2183
  }
1335
2184
  case "Comment":
@@ -1365,7 +2214,7 @@ var Lowerer = class {
1365
2214
  kind: "element",
1366
2215
  tag: el.tag,
1367
2216
  svg: el.namespace === "svg",
1368
- props: this.lowerAttributes(el.attributes),
2217
+ props: this.lowerAttributes(el.attributes, true),
1369
2218
  children,
1370
2219
  static: false,
1371
2220
  ...at ? { at } : {}
@@ -1478,13 +2327,22 @@ var Lowerer = class {
1478
2327
  return clone.kind === "Element" ? this.lowerElement(clone) : this.lowerComponent(clone);
1479
2328
  }
1480
2329
  // --- attributes ---------------------------------------------------------
1481
- lowerAttributes(attrs) {
2330
+ /**
2331
+ * `element`: a DOM element, where each class:/style: value that moves is its own accessor.
2332
+ * A component gets the object as before, rebuilt whole when any value moves.
2333
+ */
2334
+ lowerAttributes(attrs, element = false) {
2335
+ let anyReactive = false;
2336
+ const entry = (name, h) => {
2337
+ anyReactive ||= h.reactive;
2338
+ if (!element || !h.reactive) return `${JSON.stringify(name)}: ${h.code}`;
2339
+ const accessor = `() => ${paren(h.code, "arrowBody")}`;
2340
+ return `${JSON.stringify(name)}: ${h.at ? markHole(accessor, h.at.line, h.at.column) : accessor}`;
2341
+ };
1482
2342
  const props = [];
1483
2343
  const classEntries = [];
1484
- let classReactive = false;
1485
2344
  let classAt;
1486
2345
  const styleEntries = [];
1487
- let styleReactive = false;
1488
2346
  let styleAt;
1489
2347
  const usePairs = [];
1490
2348
  for (const a of attrs) {
@@ -1524,15 +2382,13 @@ var Lowerer = class {
1524
2382
  break;
1525
2383
  case "ClassDirective": {
1526
2384
  const h = this.hole(a.hole);
1527
- classEntries.push(`${JSON.stringify(a.name)}: ${h.code}`);
1528
- classReactive = classReactive || h.reactive;
2385
+ classEntries.push(entry(a.name, h));
1529
2386
  classAt ??= h.at;
1530
2387
  break;
1531
2388
  }
1532
2389
  case "StyleDirective": {
1533
2390
  const h = this.hole(a.hole);
1534
- styleEntries.push(`${JSON.stringify(a.name)}: ${h.code}`);
1535
- styleReactive = styleReactive || h.reactive;
2391
+ styleEntries.push(entry(a.name, h));
1536
2392
  styleAt ??= h.at;
1537
2393
  break;
1538
2394
  }
@@ -1552,18 +2408,19 @@ var Lowerer = class {
1552
2408
  name: "classList",
1553
2409
  kind: "attr",
1554
2410
  expr: `{ ${classEntries.join(", ")} }`,
1555
- reactive: classReactive,
2411
+ reactive: !element && anyReactive,
1556
2412
  ...classAt ? { at: classAt } : {}
1557
2413
  });
1558
2414
  }
1559
2415
  if (styleEntries.length > 0) {
1560
- props.push({
1561
- name: "style",
1562
- kind: "attr",
1563
- expr: `{ ${styleEntries.join(", ")} }`,
1564
- reactive: styleReactive,
1565
- ...styleAt ? { at: styleAt } : {}
1566
- });
2416
+ const entries = `{ ${styleEntries.join(", ")} }`;
2417
+ const base = props.findIndex((p) => p.name === "style");
2418
+ if (base === -1) props.push({ name: "style", kind: "attr", expr: entries, reactive: !element && anyReactive, ...styleAt ? { at: styleAt } : {} });
2419
+ else {
2420
+ const prop = props[base];
2421
+ const value = prop.expr === void 0 ? JSON.stringify(prop.literal) : prop.reactive ? `() => ${paren(prop.expr, "arrowBody")}` : prop.expr;
2422
+ props[base] = { name: "style", kind: "attr", expr: `[${value}, ${entries}]`, reactive: false, ...prop.at ? { at: prop.at } : {} };
2423
+ }
1567
2424
  }
1568
2425
  if (usePairs.length > 0) {
1569
2426
  props.push({ name: "use", kind: "attr", expr: `[${usePairs.join(", ")}]` });
@@ -1652,7 +2509,7 @@ var Lowerer = class {
1652
2509
  return base;
1653
2510
  }
1654
2511
  if (v.kind === "static") {
1655
- base.literal = v.value;
2512
+ base.literal = decodeEntities(v.value);
1656
2513
  return base;
1657
2514
  }
1658
2515
  if (v.kind === "hole") {
@@ -1665,7 +2522,7 @@ var Lowerer = class {
1665
2522
  let reactive = false;
1666
2523
  let at;
1667
2524
  const body = v.parts.map((p) => {
1668
- if ("text" in p) return escapeTemplate(p.text);
2525
+ if ("text" in p) return escapeTemplate(decodeEntities(p.text));
1669
2526
  const h = this.hole(p.hole);
1670
2527
  reactive = reactive || h.reactive;
1671
2528
  at ??= h.at;
@@ -1690,6 +2547,7 @@ function compilePieces(pieces, holes, options = {}) {
1690
2547
  ...options.sourceFile ? { sourceFile: options.sourceFile } : {},
1691
2548
  ...options.positionAt ? { positionAt: options.positionAt } : {}
1692
2549
  });
2550
+ if (options.templateStyles) applyTemplateStyles(ir, options.templateStyles);
1693
2551
  analyzeStatic(ir);
1694
2552
  resolveComponentSources(ir, {
1695
2553
  resolver: createComponentResolver(options.resolve ?? []),
@@ -1888,9 +2746,12 @@ function attrExprCode(attr, ctx) {
1888
2746
  }
1889
2747
  return null;
1890
2748
  }
1891
- function buildProps(attrs, ctx) {
2749
+ function buildProps(attrs, ctx, element = false) {
1892
2750
  const props = [];
1893
2751
  const usePairs = [];
2752
+ const classEntries = [];
2753
+ const styleEntries = [];
2754
+ let styleAt;
1894
2755
  for (const a of attrs) {
1895
2756
  if (a.type === "JSXSpreadAttribute") {
1896
2757
  props.push({ name: "", kind: "spread", expr: ctx.code(a.argument) });
@@ -1906,6 +2767,27 @@ function buildProps(attrs, ctx) {
1906
2767
  usePairs.push(opts != null ? `[${dir}, () => ${paren(opts, "arrowBody")}]` : `[${dir}]`);
1907
2768
  continue;
1908
2769
  }
2770
+ if (element && (ns === "class" || ns === "style")) {
2771
+ const key = JSON.stringify(a.name.name.name);
2772
+ const v = a.value;
2773
+ let value;
2774
+ if (v == null) value = "true";
2775
+ else if (isString(v)) value = JSON.stringify(literalOf(v));
2776
+ else if (v.type === "JSXExpressionContainer" && v.expression?.type !== "JSXEmptyExpression") {
2777
+ value = keyValue(v.expression, ctx);
2778
+ if (ns === "style") styleAt ??= posOf(v.expression, ctx);
2779
+ } else continue;
2780
+ (ns === "class" ? classEntries : styleEntries).push(`${key}: ${value}`);
2781
+ continue;
2782
+ }
2783
+ if (element && a.name.type === "JSXIdentifier" && a.name.name === "style" && a.value?.type === "JSXExpressionContainer") {
2784
+ const entries = objectEntries(a.value.expression, ctx);
2785
+ if (entries) {
2786
+ styleEntries.unshift(...entries);
2787
+ styleAt = posOf(a.value.expression, ctx);
2788
+ continue;
2789
+ }
2790
+ }
1909
2791
  if (ns === "oncapture") {
1910
2792
  const evt = a.name.name.name.toLowerCase();
1911
2793
  const h = attrExprCode(a, ctx) ?? "undefined";
@@ -1914,9 +2796,37 @@ function buildProps(attrs, ctx) {
1914
2796
  }
1915
2797
  props.push(buildAttr(a, ctx));
1916
2798
  }
2799
+ if (classEntries.length > 0) props.push({ name: "classList", kind: "attr", expr: `{ ${classEntries.join(", ")} }`, reactive: false });
2800
+ if (styleEntries.length > 0) {
2801
+ const entries = `{ ${styleEntries.join(", ")} }`;
2802
+ const base = props.findIndex((p) => p.name === "style" && p.kind === "attr");
2803
+ if (base === -1) props.push({ name: "style", kind: "attr", expr: entries, reactive: false, ...styleAt ? { at: styleAt } : {} });
2804
+ else {
2805
+ const prop = props[base];
2806
+ const value = prop.literal !== void 0 ? JSON.stringify(prop.literal) : prop.reactive ? `() => ${paren(prop.expr, "arrowBody")}` : prop.expr;
2807
+ props[base] = { name: "style", kind: "attr", expr: `[${value}, ${entries}]`, reactive: false, ...prop.at ? { at: prop.at } : {} };
2808
+ }
2809
+ }
1917
2810
  if (usePairs.length > 0) props.push({ name: "use", kind: "attr", expr: `[${usePairs.join(", ")}]` });
1918
2811
  return props;
1919
2812
  }
2813
+ function keyValue(expr, ctx) {
2814
+ const code = ctx.code(expr);
2815
+ if (!isReactive(expr)) return code;
2816
+ const accessor = `() => ${paren(code, "arrowBody")}`;
2817
+ const at = posOf(expr, ctx);
2818
+ return at ? markHole(accessor, at.line, at.column) : accessor;
2819
+ }
2820
+ function objectEntries(expr, ctx) {
2821
+ if (expr?.type !== "ObjectExpression") return null;
2822
+ const entries = [];
2823
+ for (const p of expr.properties) {
2824
+ if (p.type !== "ObjectProperty") return null;
2825
+ const key = p.computed ? `[${ctx.code(p.key)}]` : p.key.type === "Identifier" ? JSON.stringify(p.key.name) : JSON.stringify(String(p.key.value));
2826
+ entries.push(`${key}: ${keyValue(p.value, ctx)}`);
2827
+ }
2828
+ return entries;
2829
+ }
1920
2830
  function buildChildren(children, ctx) {
1921
2831
  const out = [];
1922
2832
  for (let i = 0; i < children.length; i++) {
@@ -1944,6 +2854,7 @@ function buildChildren(children, ctx) {
1944
2854
  });
1945
2855
  }
1946
2856
  } else if (child.type === "JSXElement" || child.type === "JSXFragment") {
2857
+ if (ctx.dropStyles?.has(child.start)) continue;
1947
2858
  out.push(buildNode(child, ctx));
1948
2859
  } else if (child.type === "JSXSpreadChild") {
1949
2860
  out.push({ kind: "expr", code: ctx.code(child.expression), reactive: false });
@@ -2013,13 +2924,17 @@ function buildElement(node, ctx, handled) {
2013
2924
  const children = each ? [each] : buildChildren(node.children, ctx);
2014
2925
  if (tag === CONTAINER2) return children.length === 1 ? children[0] : { kind: "fragment", children };
2015
2926
  const at = ctx.sourceFile && node.loc?.start ? { file: ctx.sourceFile, line: node.loc.start.line, column: node.loc.start.column } : void 0;
2016
- return { kind: "element", tag, svg: SVG_TAGS.has(tag), props: buildProps(attributes, ctx), children, static: false, ...at ? { at } : {} };
2927
+ const props = buildProps(attributes, ctx, true);
2928
+ const scope = ctx.scopes?.find((s) => node.start >= s.start && node.end <= s.end);
2929
+ if (scope) props.unshift({ name: "data-fx-s", kind: "attr", literal: scope.value });
2930
+ return { kind: "element", tag, svg: SVG_TAGS.has(tag), props, children, static: false, ...at ? { at } : {} };
2017
2931
  }
2018
2932
  function buildNode(node, ctx) {
2019
2933
  if (node.type === "JSXFragment") {
2020
2934
  return { kind: "fragment", children: buildChildren(node.children, ctx) };
2021
2935
  }
2022
2936
  if (directive(node, "if")) return buildIf(node, null, ctx);
2937
+ if (ctx.dropStyles?.has(node.start)) return { kind: "fragment", children: [] };
2023
2938
  const { tag, component } = tagInfo(node.openingElement.name, ctx);
2024
2939
  if (!component) return buildElement(node, ctx, []);
2025
2940
  const props = buildProps(node.openingElement.attributes, ctx);
@@ -2548,8 +3463,8 @@ function isJsxRoot(node, parent, key) {
2548
3463
  if (!isJsx(node)) return false;
2549
3464
  return !(parent && isJsx(parent) && key === "children");
2550
3465
  }
2551
- function isTemplateTag(node, litTag) {
2552
- return node.type === "TaggedTemplateExpression" && node.tag?.type === "Identifier" && (node.tag.name === litTag || node.tag.name === "svg");
3466
+ function isTemplateTag(node, tags) {
3467
+ return node.type === "TaggedTemplateExpression" && node.tag?.type === "Identifier" && tags.has(node.tag.name);
2553
3468
  }
2554
3469
  function outermost(list) {
2555
3470
  return list.filter(
@@ -2697,22 +3612,28 @@ function transformTemplates(code, id, options = {}) {
2697
3612
  const wantsIntrinsics = options.intrinsics !== false && mayHaveIntrinsic(code);
2698
3613
  const wantsSources = options.sourceLocations === true && mayHaveSourceMarks(code);
2699
3614
  const sourceName = relativeToRoot(id, options.sourceRoot);
2700
- if (!mayHaveTemplate && !(wantsJsx && code.includes("<")) && !wantsIntrinsics && !wantsSources) return null;
3615
+ const wantsStyles = options.styles !== void 0 && (code.includes("<style") || code.includes("css`"));
3616
+ if (!mayHaveTemplate && !(wantsJsx && code.includes("<")) && !wantsIntrinsics && !wantsSources && !wantsStyles) return null;
2701
3617
  const ast = (0, import_parser2.parse)(code, {
2702
3618
  sourceType: "module",
2703
3619
  plugins: ["jsx", "typescript"],
2704
3620
  errorRecovery: true
2705
3621
  });
3622
+ const intrinsicTags = options.intrinsics === false ? /* @__PURE__ */ new Map() : tagIntrinsics(moduleBindings(ast.program));
3623
+ const templateTags = /* @__PURE__ */ new Map([[litTag, "html"], ["svg", "svg"]]);
3624
+ for (const [name, tag] of intrinsicTags) if (tag !== "css") templateTags.set(name, tag);
3625
+ const cssTags = [...intrinsicTags].filter(([, tag]) => tag === "css").map(([name]) => name);
2706
3626
  const found = [];
2707
3627
  walk7(ast.program, (n, parent, key) => {
2708
- if (wantsLit && isTemplateTag(n, litTag)) found.push(n);
3628
+ if (wantsLit && isTemplateTag(n, templateTags)) found.push(n);
2709
3629
  else if (wantsJsx && isJsxRoot(n, parent, key)) found.push(n);
2710
3630
  });
2711
3631
  const props = options.propsDestructure === false ? { edits: [], diagnostics: [], used: /* @__PURE__ */ new Set() } : collectPropsEdits(ast.program, code, { runtimeModule: options.runtimeModule });
2712
3632
  const intrinsics = options.intrinsics === false ? { edits: [], diagnostics: [], imports: /* @__PURE__ */ new Map() } : collectIntrinsicEdits(ast.program);
2713
3633
  if (intrinsics.edits.length) avoidBindingClashes(ast.program, intrinsics, moduleBindings(ast.program));
2714
3634
  const sources = options.sourceLocations === true ? collectSourceEdits(ast.program, sourceName) : { edits: [], marked: 0 };
2715
- const silent = found.length === 0 && props.edits.length === 0 && sources.edits.length === 0 && intrinsics.edits.length === 0 && intrinsics.diagnostics.length === 0 && props.diagnostics.length === 0;
3635
+ const styles = wantsStyles ? collectStyles(ast.program, sourceName, options.styles, { html: templateTags, css: cssTags }, { id, code }) : void 0;
3636
+ const silent = found.length === 0 && props.edits.length === 0 && sources.edits.length === 0 && intrinsics.edits.length === 0 && intrinsics.diagnostics.length === 0 && props.diagnostics.length === 0 && !styles?.edits.length && !styles?.diagnostics.length;
2716
3637
  if (silent) return null;
2717
3638
  found.sort((a, b) => b.start - a.start || a.end - b.end);
2718
3639
  const used = new Set(props.used);
@@ -2726,20 +3647,32 @@ function transformTemplates(code, id, options = {}) {
2726
3647
  declared: declaredNames(ast.program)
2727
3648
  };
2728
3649
  const hoisted = /* @__PURE__ */ new Map();
2729
- const edits = [...props.edits, ...intrinsics.edits, ...sources.edits];
3650
+ const edits = [...props.edits, ...intrinsics.edits, ...sources.edits, ...styles?.edits ?? []];
2730
3651
  for (const node of found) {
2731
3652
  const nested = found.some(
2732
3653
  (o) => o !== node && o.start <= node.start && o.end >= node.end && o.end - o.start > node.end - node.start
2733
3654
  );
2734
3655
  if (isJsx(node)) {
2735
- edits.push({ start: node.start, end: node.end, code: compileJsx(code, node, edits, nested, used, needs, hoisted, options, sourceName) });
3656
+ edits.push({ start: node.start, end: node.end, code: compileJsx(code, node, edits, nested, used, needs, hoisted, options, sourceName, styles) });
2736
3657
  continue;
2737
3658
  }
2738
3659
  const holes = node.quasi.expressions.map(
2739
3660
  (e) => bindHole(code, e, edits, options.sourceLocations === true)
2740
3661
  );
3662
+ const scope = styles?.scopes.find((s) => node.start >= s.start && node.end <= s.end)?.value;
3663
+ const owner = styles?.templateOwners.get(node.start);
3664
+ const templateStyles = options.styles && styles && (scope || owner) ? {
3665
+ options: options.styles,
3666
+ ...scope ? { scope } : {},
3667
+ ...owner ? { owner } : {},
3668
+ line: node.loc?.start.line ?? 0,
3669
+ column: node.loc?.start.column ?? 0,
3670
+ styles: styles.styles,
3671
+ diagnostics: styles.diagnostics
3672
+ } : void 0;
2741
3673
  const result = compilePieces(toPieces(node), holes, {
2742
3674
  ...options,
3675
+ ...templateStyles ? { templateStyles } : {},
2743
3676
  hoistTemplates: true,
2744
3677
  // A tag inside a template gets the same mark a JSX tag does. Without one, the nodes it
2745
3678
  // makes are the only ones in the module carrying no mark, and they take whichever was
@@ -2748,12 +3681,13 @@ function transformTemplates(code, id, options = {}) {
2748
3681
  // Same defaults as the plugin, so moving a build over is not a rendering change.
2749
3682
  templateClone: options.templateClone ?? true,
2750
3683
  partialTemplates: nested ? false : options.partialTemplates ?? true,
2751
- svg: node.tag.name === "svg"
3684
+ svg: templateTags.get(node.tag.name) === "svg"
2752
3685
  });
2753
3686
  for (const symbol of result.imports) used.add(symbol);
2754
3687
  collectNeeds(result.ir, needs);
2755
3688
  edits.push({ start: node.start, end: node.end, code: adoptTemplates(result.code, result.templates, hoisted) });
2756
3689
  }
3690
+ if (styles && options.styles) edits.push(...finishShadowStyles(styles, code, id));
2757
3691
  const out = new import_magic_string2.default(code);
2758
3692
  for (const e of outermost(edits)) {
2759
3693
  if (e.start === e.end) out.appendLeft(e.start, e.code);
@@ -2811,13 +3745,19 @@ function transformTemplates(code, id, options = {}) {
2811
3745
  ...loadDiagnostics.length ? { loadDiagnostics } : {},
2812
3746
  ...unresolvedDiagnostics.length ? { unresolvedDiagnostics } : {},
2813
3747
  ...props.diagnostics.length ? { propsDiagnostics: props.diagnostics } : {},
2814
- ...intrinsics.diagnostics.length ? { intrinsicDiagnostics: intrinsics.diagnostics } : {}
3748
+ ...intrinsics.diagnostics.length ? { intrinsicDiagnostics: intrinsics.diagnostics } : {},
3749
+ ...styles?.styles.length ? { styles: styles.styles } : {},
3750
+ ...styles?.diagnostics.length ? { styleDiagnostics: styles.diagnostics } : {},
3751
+ ...styles?.literals.length ? { styleLiterals: styles.literals } : {},
3752
+ ...styles?.references.length ? { styleReferences: styles.references } : {}
2815
3753
  };
2816
3754
  }
2817
- function compileJsx(code, node, edits, nested, used, needs, hoisted, options, sourceFile) {
3755
+ function compileJsx(code, node, edits, nested, used, needs, hoisted, options, sourceFile, styles) {
2818
3756
  const ir = buildJsxIR(node, {
2819
3757
  code: (n) => slice(code, n.start, n.end, edits),
2820
3758
  used,
3759
+ ...styles?.scopes.length ? { scopes: styles.scopes } : {},
3760
+ ...styles?.drop.size ? { dropStyles: styles.drop } : {},
2821
3761
  ...options.sourceLocations === true && sourceFile ? { sourceFile } : {}
2822
3762
  });
2823
3763
  analyzeStatic(ir);