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

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 (90) hide show
  1. package/dist/analyze/intrinsics.cjs +13 -1
  2. package/dist/analyze/intrinsics.d.cts +14 -0
  3. package/dist/analyze/intrinsics.d.ts +14 -0
  4. package/dist/analyze/intrinsics.d.ts.map +1 -1
  5. package/dist/analyze/intrinsics.js +17 -0
  6. package/dist/analyze/intrinsics.mjs +13 -1
  7. package/dist/analyze/static-graph.cjs +1 -1
  8. package/dist/analyze/static-graph.mjs +1 -1
  9. package/dist/{babel-RJHJQVEM.mjs → babel-RJFQVFJW.mjs} +4 -4
  10. package/dist/{chunk-56QSOVVL.mjs → chunk-DP2QDWWH.mjs} +1 -1
  11. package/dist/{chunk-R7PPFBCL.mjs → chunk-E2RWTIYE.mjs} +21 -15
  12. package/dist/{chunk-OD53TMER.mjs → chunk-HCCBEJEZ.mjs} +13 -1
  13. package/dist/{chunk-TJIH7TLX.mjs → chunk-HIZU7WI2.mjs} +1 -1
  14. package/dist/{chunk-U7HCFLZ2.mjs → chunk-ZR2QHTEX.mjs} +356 -24
  15. package/dist/codegen/backends/imperative.cjs +1 -1
  16. package/dist/codegen/backends/imperative.d.ts.map +1 -1
  17. package/dist/codegen/backends/imperative.js +2 -1
  18. package/dist/codegen/backends/imperative.mjs +1 -1
  19. package/dist/frontend/babel/build-ir-lit.cjs +352 -22
  20. package/dist/frontend/babel/build-ir-lit.mjs +352 -22
  21. package/dist/frontend/babel/build-ir.cjs +352 -22
  22. package/dist/frontend/babel/build-ir.mjs +352 -22
  23. package/dist/frontend/babel/index.cjs +353 -23
  24. package/dist/frontend/babel/index.mjs +353 -23
  25. package/dist/frontend/babel/lower-template.cjs +352 -22
  26. package/dist/frontend/babel/lower-template.mjs +352 -22
  27. package/dist/frontend/babel/plugin.cjs +352 -22
  28. package/dist/frontend/babel/plugin.mjs +352 -22
  29. package/dist/index.cjs +321 -22
  30. package/dist/index.mjs +333 -22
  31. package/dist/integrations.cjs +1174 -49
  32. package/dist/integrations.d.ts.map +1 -1
  33. package/dist/integrations.js +44 -2
  34. package/dist/integrations.mjs +205 -19
  35. package/dist/lower/compile-template.cjs +315 -21
  36. package/dist/lower/compile-template.d.cts +13 -0
  37. package/dist/lower/compile-template.d.ts +13 -0
  38. package/dist/lower/compile-template.d.ts.map +1 -1
  39. package/dist/lower/compile-template.js +3 -0
  40. package/dist/lower/compile-template.mjs +327 -21
  41. package/dist/lower/entities.cjs +288 -0
  42. package/dist/lower/entities.d.cts +1 -0
  43. package/dist/lower/entities.d.ts +2 -0
  44. package/dist/lower/entities.d.ts.map +1 -0
  45. package/dist/lower/entities.js +54 -0
  46. package/dist/lower/entities.mjs +267 -0
  47. package/dist/lower/jsx.cjs +104 -47
  48. package/dist/lower/jsx.d.cts +8 -0
  49. package/dist/lower/jsx.d.ts +8 -0
  50. package/dist/lower/jsx.d.ts.map +1 -1
  51. package/dist/lower/jsx.js +92 -2
  52. package/dist/lower/jsx.mjs +104 -47
  53. package/dist/lower/template.cjs +293 -20
  54. package/dist/lower/template.d.ts.map +1 -1
  55. package/dist/lower/template.js +35 -19
  56. package/dist/lower/template.mjs +293 -20
  57. package/dist/resolve/builtins.cjs +1 -1
  58. package/dist/resolve/builtins.mjs +1 -1
  59. package/dist/resolve/component-globals.cjs +6 -1
  60. package/dist/resolve/component-globals.js +2 -2
  61. package/dist/resolve/component-globals.mjs +6 -1
  62. package/dist/resolve/write-globals.cjs +6 -1
  63. package/dist/resolve/write-globals.mjs +6 -1
  64. package/dist/{server-fns-ZFRDIQ2X.mjs → server-fns-JLSTKWPS.mjs} +4 -4
  65. package/dist/{server-functions-CTDXX67X.mjs → server-functions-BGY3RD4R.mjs} +3 -3
  66. package/dist/transform/index.cjs +956 -33
  67. package/dist/transform/index.mjs +974 -47
  68. package/dist/transform/props.mjs +19 -14
  69. package/dist/transform/server-fns.mjs +19 -14
  70. package/dist/transform/styles.cjs +588 -0
  71. package/dist/transform/styles.d.cts +211 -0
  72. package/dist/transform/styles.d.ts +212 -0
  73. package/dist/transform/styles.d.ts.map +1 -0
  74. package/dist/transform/styles.js +714 -0
  75. package/dist/transform/styles.mjs +653 -0
  76. package/dist/transform/templates.cjs +955 -32
  77. package/dist/transform/templates.d.cts +13 -0
  78. package/dist/transform/templates.d.ts +13 -0
  79. package/dist/transform/templates.d.ts.map +1 -1
  80. package/dist/transform/templates.js +49 -12
  81. package/dist/transform/templates.mjs +973 -46
  82. package/dist/{transform-QWWQDCXE.mjs → transform-GBP6Y4UI.mjs} +601 -17
  83. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  84. package/dist/vite-styles.cjs +180 -0
  85. package/dist/vite-styles.d.cts +59 -0
  86. package/dist/vite-styles.d.ts +60 -0
  87. package/dist/vite-styles.d.ts.map +1 -0
  88. package/dist/vite-styles.js +198 -0
  89. package/dist/vite-styles.mjs +159 -0
  90. package/package.json +4 -3
@@ -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.94 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
  import {
3
3
  analyzeStatic,
4
4
  buildJsxIR,
@@ -14,7 +14,7 @@ import {
14
14
  resolveComponentSources,
15
15
  resolveReactiveBindings,
16
16
  shapeOf
17
- } from "./chunk-U7HCFLZ2.mjs";
17
+ } from "./chunk-ZR2QHTEX.mjs";
18
18
  import {
19
19
  CORE_CONTROL_FLOW,
20
20
  DOM_CONTROL_FLOW,
@@ -22,16 +22,574 @@ import {
22
22
  ROUTER_COMPONENTS,
23
23
  createComponentResolver,
24
24
  isIntrinsicName,
25
- mayHaveIntrinsic
26
- } from "./chunk-OD53TMER.mjs";
25
+ mayHaveIntrinsic,
26
+ tagIntrinsics
27
+ } from "./chunk-HCCBEJEZ.mjs";
27
28
  import {
28
- MagicString
29
- } from "./chunk-R7PPFBCL.mjs";
30
- import "./chunk-TJIH7TLX.mjs";
29
+ MagicString,
30
+ encode
31
+ } from "./chunk-E2RWTIYE.mjs";
32
+ import "./chunk-HIZU7WI2.mjs";
31
33
 
32
34
  // src/transform/templates.ts
33
35
  import { parse as parse2 } from "@babel/parser";
34
36
 
37
+ // src/transform/styles.ts
38
+ var SCOPE_ATTR = "data-fx-s";
39
+ var FUNCTIONS = /* @__PURE__ */ new Set(["FunctionDeclaration", "FunctionExpression", "ArrowFunctionExpression", "ObjectMethod", "ClassMethod"]);
40
+ function collectStyles(program, sourceName, options, tags = { html: /* @__PURE__ */ new Map([["html", "html"]]) }, module) {
41
+ const plan = {
42
+ scopes: [],
43
+ templateOwners: /* @__PURE__ */ new Map(),
44
+ drop: /* @__PURE__ */ new Set(),
45
+ styles: [],
46
+ diagnostics: [],
47
+ edits: [],
48
+ literals: [],
49
+ references: [],
50
+ shadowClasses: /* @__PURE__ */ new Map()
51
+ };
52
+ if (!options) return plan;
53
+ const literalsOf = findLiterals(program, options.cssModules ?? ["@fluixi/core", "@fluixi/dom"], plan, tags.css ?? []);
54
+ plan.names = literalsOf;
55
+ const classOf = /* @__PURE__ */ new Map();
56
+ const shadowOf = (owner) => {
57
+ const cls = classOf.get(owner);
58
+ return cls ? plan.shadowClasses.get(cls) : void 0;
59
+ };
60
+ const resolved = /* @__PURE__ */ new Map();
61
+ const piecesToNodes = (quasis, expressions, at, stack) => {
62
+ const out = [];
63
+ for (let i = 0; i < quasis.length; i++) {
64
+ const text = quasis[i].value.cooked ?? quasis[i].value.raw;
65
+ if (text.trim()) {
66
+ try {
67
+ const start = quasis[i].loc?.start;
68
+ out.push(...options.process(text, sourceName).map((n) => start ? shiftLoc(n, sourceName, start) : n));
69
+ } catch (error) {
70
+ plan.diagnostics.push({ ...at, message: `CSS could not be processed: ${error.message}` });
71
+ return null;
72
+ }
73
+ }
74
+ const expr = expressions[i];
75
+ if (!expr) continue;
76
+ const value = expr.type === "Identifier" ? resolveLiteral(expr.name, at, stack) : void 0;
77
+ if (value === void 0) {
78
+ plan.diagnostics.push({
79
+ ...at,
80
+ 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))."
81
+ });
82
+ return null;
83
+ }
84
+ if (value === null) return null;
85
+ out.push(...value);
86
+ }
87
+ return out;
88
+ };
89
+ function resolveLiteral(name, at, stack) {
90
+ const imported = literalsOf.imports.get(name);
91
+ if (imported) {
92
+ const nodes = options?.imported?.get(`${imported.source}#${imported.name}`);
93
+ if (nodes) return nodes.map(dropLoc);
94
+ plan.references.push({ name: imported.name, source: imported.source, ...at });
95
+ plan.diagnostics.push({
96
+ ...at,
97
+ 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.`
98
+ });
99
+ return null;
100
+ }
101
+ const literal = literalsOf.literals.get(name);
102
+ if (!literal) return void 0;
103
+ if (stack.includes(name)) {
104
+ plan.diagnostics.push({ ...at, message: `css\`\` values include each other: ${[...stack, name].join(" → ")}.` });
105
+ return null;
106
+ }
107
+ if (!resolved.has(name)) {
108
+ resolved.set(name, piecesToNodes(literal.quasi.quasis, literal.quasi.expressions, at, [...stack, name]));
109
+ }
110
+ return resolved.get(name);
111
+ }
112
+ for (const [name, literal] of literalsOf.literals) {
113
+ const at = { line: literal.loc?.start.line ?? 0, column: literal.loc?.start.column ?? 0 };
114
+ const nodes = resolveLiteral(name, at, []);
115
+ const id = hash(`${sourceName}:css:${name}`);
116
+ plan.edits.push({ start: literal.start, end: literal.end, code: `({ $fxStyle: ${JSON.stringify(id)} })` });
117
+ if (nodes) plan.literals.push({ id, name, css: printStyle(nodes, options.minify) });
118
+ }
119
+ const scopeOf = /* @__PURE__ */ new Map();
120
+ const names = /* @__PURE__ */ new Map();
121
+ const named = /* @__PURE__ */ new Map();
122
+ const visit = (node, owners) => {
123
+ if (!node || typeof node !== "object") return;
124
+ if (node.type === "VariableDeclarator" && node.id.type === "Identifier" && node.init && FUNCTIONS.has(node.init.type)) {
125
+ named.set(node.init, node.id.name);
126
+ }
127
+ if ((node.type === "ClassDeclaration" || node.type === "ClassExpression") && node.id) {
128
+ for (const member of node.body.body) if (member.type === "ClassMethod") named.set(member, node.id.name);
129
+ }
130
+ if (node.type === "ClassDeclaration" || node.type === "ClassExpression") {
131
+ for (const member of node.body.body) if (member.type === "ClassMethod") classOf.set(member, node);
132
+ const shadow = staticMember(node, "shadow");
133
+ if (shadow?.value && !(shadow.value.type === "BooleanLiteral" && shadow.value.value === false)) {
134
+ plan.shadowClasses.set(node, { node, styles: staticMember(node, "styles"), indexes: [] });
135
+ }
136
+ }
137
+ if (node.type === "TaggedTemplateExpression" && node.tag.type === "Identifier" && tags.html.get(node.tag.name) === "html") {
138
+ const text = node.quasi.quasis.map((q) => q.value.raw).join("");
139
+ if (/<style[\s>]/.test(text)) {
140
+ const at = { line: node.loc?.start.line ?? 0, column: node.loc?.start.column ?? 0 };
141
+ const owner = owners[0];
142
+ if (!owner) plan.diagnostics.push({ ...at, message: "<style> has to be written inside a component." });
143
+ else {
144
+ const id = idFor(owner);
145
+ const shadow = shadowOf(owner);
146
+ plan.templateOwners.set(node.start, { id, component: functionName(owner, named) });
147
+ for (const block of templateBlocks(node.quasi)) compileBlock(block, block.scoped, owner, at);
148
+ }
149
+ }
150
+ }
151
+ const inner = FUNCTIONS.has(node.type) ? [...owners, node] : owners;
152
+ if (node.type === "JSXElement" && isStyle(node)) {
153
+ handle(node, owners);
154
+ return;
155
+ }
156
+ for (const key of Object.keys(node)) {
157
+ if (key === "loc" || key === "leadingComments" || key === "trailingComments" || key === "innerComments") continue;
158
+ const value = node[key];
159
+ if (Array.isArray(value)) for (const v of value) visit(v, inner);
160
+ else if (value && typeof value === "object" && "type" in value) visit(value, inner);
161
+ }
162
+ };
163
+ const handle = (node, owners) => {
164
+ const at = { line: node.loc?.start.line ?? 0, column: node.loc?.start.column ?? 0 };
165
+ const pieces = blockPieces(node);
166
+ if (pieces === null) {
167
+ plan.diagnostics.push({
168
+ ...at,
169
+ message: "<style> needs its CSS as one template literal, <style>{`...`}</style>: JSX reads a bare `{` as an expression."
170
+ });
171
+ return;
172
+ }
173
+ const owner = owners[0];
174
+ if (!owner) {
175
+ plan.diagnostics.push({ ...at, message: "<style> has to be written inside a component." });
176
+ return;
177
+ }
178
+ compileBlock(pieces, isScoped(node), owner, at);
179
+ plan.drop.add(node.start);
180
+ };
181
+ const compileBlock = (pieces, scoped, owner, at) => {
182
+ const component = functionName(owner, named);
183
+ const id = idFor(owner);
184
+ const processed = piecesToNodes(pieces.quasis, pieces.expressions, at, []);
185
+ if (!processed) return;
186
+ let nodes = processed;
187
+ const shadow = shadowOf(owner);
188
+ if (scoped && !shadow) {
189
+ if (!plan.scopes.some((s) => s.value === id)) plan.scopes.push({ start: owner.start, end: owner.end, value: id });
190
+ nodes = scopeNodes(nodes, id, (message) => plan.diagnostics.push({ ...at, message }));
191
+ }
192
+ const printed = module ? printStyleWithMap(nodes, options.minify, sourceName, module) : { css: printStyle(nodes, options.minify) };
193
+ plan.styles.push({ id, scoped: scoped && !shadow, component, ...printed, ...shadow ? { shadow: true } : {}, ...at });
194
+ if (shadow) shadow.indexes.push(plan.styles.length - 1);
195
+ };
196
+ function idFor(owner) {
197
+ let id = scopeOf.get(owner);
198
+ if (!id) {
199
+ const component = functionName(owner, named);
200
+ const seen = names.get(component) ?? 0;
201
+ names.set(component, seen + 1);
202
+ id = hash(`${sourceName}:${component}${seen ? ":" + seen : ""}`);
203
+ scopeOf.set(owner, id);
204
+ }
205
+ return id;
206
+ }
207
+ visit(program, []);
208
+ return plan;
209
+ }
210
+ function applyTemplateStyles(ir, t) {
211
+ const walk5 = (node) => {
212
+ const children = node.children;
213
+ if (children) {
214
+ for (let i = children.length - 1; i >= 0; i--) {
215
+ const child = children[i];
216
+ if (child.kind === "element" && child.tag === "style" && t.owner) children.splice(i, 1);
217
+ else walk5(child);
218
+ }
219
+ }
220
+ if (t.scope && node.kind === "element" && node.tag !== "style" && node.props && !node.props.some((p) => p.name === SCOPE_ATTR)) {
221
+ node.props.unshift({ name: SCOPE_ATTR, kind: "attr", literal: t.scope });
222
+ }
223
+ };
224
+ walk5(ir);
225
+ }
226
+ function staticMember(cls, name) {
227
+ return cls.body.body.find(
228
+ (m) => m.type === "ClassProperty" && m.static && (m.key.type === "Identifier" && m.key.name === name || m.key.type === "StringLiteral" && m.key.value === name)
229
+ );
230
+ }
231
+ function finishShadowStyles(plan, code, moduleId) {
232
+ const edits = [];
233
+ const imports = [];
234
+ let next = 0;
235
+ const importOf = (specifier) => {
236
+ const local = `__fxShadow${next++}`;
237
+ imports.push(`import ${local} from ${JSON.stringify(specifier)};
238
+ `);
239
+ return local;
240
+ };
241
+ for (const shadow of plan.shadowClasses.values()) {
242
+ const blocks = shadow.indexes.map((i) => importOf(`${moduleId}?fx-style&index=${i}&inline&lang.css`));
243
+ let value;
244
+ const prop = shadow.styles;
245
+ if (prop?.value) {
246
+ const start = prop.value.start;
247
+ let text = code.slice(start, prop.value.end);
248
+ const replacements = [];
249
+ walkIdentifiers(prop.value, (id) => {
250
+ const local = plan.names?.literals.has(id.name) ? importOf(`${moduleId}?fx-literal=${id.name}&inline&lang.css`) : plan.names?.imports.has(id.name) && !/\.css(\?|$)/.test(plan.names.imports.get(id.name).source) ? importOf(`${plan.names.imports.get(id.name).source}?fx-literal=${plan.names.imports.get(id.name).name}&inline&lang.css`) : void 0;
251
+ if (local) replacements.push({ at: id.start - start, length: id.name.length, with: local });
252
+ });
253
+ 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);
254
+ value = text;
255
+ }
256
+ if (!blocks.length && value === void 0) continue;
257
+ if (prop?.value) {
258
+ const merged = blocks.length ? `[${value}, ${blocks.join(", ")}]` : value;
259
+ edits.push({ start: prop.value.start, end: prop.value.end, code: merged });
260
+ } else if (blocks.length) {
261
+ const open = shadow.node.body.start + 1;
262
+ edits.push({ start: open, end: open, code: ` static styles = [${blocks.join(", ")}];` });
263
+ }
264
+ }
265
+ if (imports.length) edits.push({ start: 0, end: 0, code: imports.join("") });
266
+ return edits;
267
+ }
268
+ function walkIdentifiers(node, visit) {
269
+ if (!node || typeof node !== "object") return;
270
+ if (node.type === "Identifier") return visit(node);
271
+ if (node.type === "MemberExpression") return walkIdentifiers(node.object, visit);
272
+ if (node.type === "ObjectProperty") return walkIdentifiers(node.value, visit);
273
+ for (const key of Object.keys(node)) {
274
+ if (key === "loc") continue;
275
+ const value = node[key];
276
+ if (Array.isArray(value)) for (const v of value) walkIdentifiers(v, visit);
277
+ else if (value && typeof value === "object" && "type" in value) walkIdentifiers(value, visit);
278
+ }
279
+ }
280
+ function isStyle(node) {
281
+ const name = node.openingElement.name;
282
+ return name.type === "JSXIdentifier" && name.name === "style";
283
+ }
284
+ function isScoped(node) {
285
+ return node.openingElement.attributes.some((a) => a.type === "JSXAttribute" && a.name.type === "JSXIdentifier" && a.name.name === "scoped");
286
+ }
287
+ function templateBlocks(quasi) {
288
+ const blocks = [];
289
+ let open = null;
290
+ quasi.quasis.forEach((q, i) => {
291
+ const raw = q.value.raw;
292
+ let from = 0;
293
+ while (from <= raw.length) {
294
+ if (!open) {
295
+ const tag = /<style\b([^>]*)>/g;
296
+ tag.lastIndex = from;
297
+ const m = tag.exec(raw);
298
+ if (!m) break;
299
+ open = { quasis: [], expressions: [], scoped: /\bscoped\b/.test(m[1]) };
300
+ from = m.index + m[0].length;
301
+ }
302
+ const close = raw.indexOf("</style", from);
303
+ open.quasis.push(slicePiece(q, raw, from, close === -1 ? raw.length : close));
304
+ if (close === -1) break;
305
+ blocks.push(open);
306
+ open = null;
307
+ from = close;
308
+ }
309
+ const expr = quasi.expressions[i];
310
+ if (open && expr) open.expressions.push(expr);
311
+ });
312
+ return blocks;
313
+ }
314
+ function slicePiece(q, raw, from, to) {
315
+ const text = raw.slice(from, to);
316
+ const start = q.loc?.start;
317
+ if (!start) return { type: "TemplateElement", value: { raw: text, cooked: text } };
318
+ const before = raw.slice(0, from).split("\n");
319
+ const line = start.line + before.length - 1;
320
+ const column = before.length > 1 ? before[before.length - 1].length : start.column + from;
321
+ return { type: "TemplateElement", value: { raw: text, cooked: text }, loc: { start: { line, column } } };
322
+ }
323
+ function blockPieces(node) {
324
+ const meaningful = node.children.filter((c) => !(c.type === "JSXText" && !c.value.trim()));
325
+ if (meaningful.length === 0) return { quasis: [], expressions: [] };
326
+ if (meaningful.length !== 1) return null;
327
+ const only = meaningful[0];
328
+ if (only.type !== "JSXExpressionContainer") return null;
329
+ const expr = only.expression;
330
+ if (expr.type === "StringLiteral") return { quasis: [{ type: "TemplateElement", value: { raw: expr.value, cooked: expr.value } }], expressions: [] };
331
+ if (expr.type === "TemplateLiteral") return { quasis: expr.quasis, expressions: expr.expressions };
332
+ return null;
333
+ }
334
+ function findLiterals(program, modules, plan, intrinsic) {
335
+ const literals = /* @__PURE__ */ new Map();
336
+ const imports = /* @__PURE__ */ new Map();
337
+ const tags = new Set(intrinsic);
338
+ for (const statement of program.body ?? []) {
339
+ if (statement.type !== "ImportDeclaration") continue;
340
+ const source = statement.source.value;
341
+ const specifiers = statement.specifiers;
342
+ for (const sp of specifiers) {
343
+ if (sp.type === "ImportSpecifier") imports.set(sp.local.name, { source, name: sp.imported.name ?? sp.imported.value });
344
+ }
345
+ if (!modules.includes(source)) continue;
346
+ const css = specifiers.find((sp) => sp.type === "ImportSpecifier" && (sp.imported.name ?? sp.imported.value) === "css");
347
+ if (!css) continue;
348
+ const local = css.local.name;
349
+ tags.add(local);
350
+ imports.delete(local);
351
+ plan.edits.push({ start: statement.start, end: statement.end, code: importWithout(statement, css) });
352
+ }
353
+ if (tags.size === 0) return { literals, imports };
354
+ const visit = (node) => {
355
+ if (!node || typeof node !== "object") return;
356
+ if (node.type === "VariableDeclarator" && node.id.type === "Identifier" && node.init?.type === "TaggedTemplateExpression" && node.init.tag.type === "Identifier" && tags.has(node.init.tag.name)) {
357
+ literals.set(node.id.name, node.init);
358
+ }
359
+ for (const key of Object.keys(node)) {
360
+ if (key === "loc") continue;
361
+ const value = node[key];
362
+ if (Array.isArray(value)) for (const v of value) visit(v);
363
+ else if (value && typeof value === "object" && "type" in value) visit(value);
364
+ }
365
+ };
366
+ visit(program);
367
+ return { literals, imports };
368
+ }
369
+ function importWithout(statement, removed) {
370
+ const rest = statement.specifiers.filter((sp) => sp !== removed);
371
+ const source = JSON.stringify(statement.source.value);
372
+ if (rest.length === 0) return "";
373
+ const def = rest.find((sp) => sp.type === "ImportDefaultSpecifier");
374
+ const ns = rest.find((sp) => sp.type === "ImportNamespaceSpecifier");
375
+ const named = rest.filter((sp) => sp.type === "ImportSpecifier").map((sp) => {
376
+ const imported = sp.imported.name ?? JSON.stringify(sp.imported.value);
377
+ return imported === sp.local.name ? imported : `${imported} as ${sp.local.name}`;
378
+ });
379
+ const parts = [def?.local.name, ns ? `* as ${ns.local.name}` : void 0, named.length ? `{ ${named.join(", ")} }` : void 0].filter(Boolean);
380
+ return `import ${parts.join(", ")} from ${source};`;
381
+ }
382
+ function functionName(fn, named) {
383
+ if ((fn.type === "FunctionDeclaration" || fn.type === "FunctionExpression") && fn.id) return fn.id.name;
384
+ return named.get(fn) ?? "anonymous";
385
+ }
386
+ function hash(text) {
387
+ let h = 2166136261;
388
+ for (let i = 0; i < text.length; i++) {
389
+ h ^= text.charCodeAt(i);
390
+ h = Math.imul(h, 16777619);
391
+ }
392
+ return (h >>> 0).toString(36);
393
+ }
394
+ var OPAQUE = /(^|-)keyframes$|^font-face$|^property$|^counter-style$|^page$|^font-feature-values$/;
395
+ function scopeNodes(nodes, id, warn = () => {
396
+ }) {
397
+ return nodes.map((node) => {
398
+ if (node.kind === "rule") return { ...node, selector: scopeSelector(node.selector, id, warn) };
399
+ if (node.kind === "at-rule" && !OPAQUE.test(node.name)) return { ...node, nodes: scopeNodes(node.nodes, id, warn) };
400
+ return node;
401
+ });
402
+ }
403
+ function scopeSelector(selector, id, warn = () => {
404
+ }) {
405
+ return splitTop(selector, ",").map((complex) => scopeComplex(complex.trim(), `[${SCOPE_ATTR}="${id}"]`, warn)).join(", ");
406
+ }
407
+ function scopeComplex(selector, attr, warn) {
408
+ if (/:host\b|::slotted\(/.test(selector)) {
409
+ warn(`\`${selector}\` only means something in a shadow root; in a light-DOM component it is left as written.`);
410
+ return selector;
411
+ }
412
+ const parts = compounds(selector);
413
+ const deep = parts.findIndex((p) => p.text.startsWith(":deep("));
414
+ if (deep !== -1) {
415
+ const inner = unwrap(parts[deep].text, ":deep(");
416
+ const before = parts.slice(0, deep);
417
+ if (before.length === 0) return `${attr} ${inner}`;
418
+ const scopedBefore = scopeAt(before, before.length - 1, attr);
419
+ return `${join(scopedBefore)} ${inner}`;
420
+ }
421
+ let target = -1;
422
+ for (let i = parts.length - 1; i >= 0; i--) {
423
+ if (!parts[i].text.startsWith(":global(")) {
424
+ target = i;
425
+ break;
426
+ }
427
+ }
428
+ const out = target === -1 ? parts : scopeAt(parts, target, attr);
429
+ return join(out.map((p) => p.text.startsWith(":global(") ? { ...p, text: unwrap(p.text, ":global(") } : p));
430
+ }
431
+ function scopeAt(parts, index, attr) {
432
+ return parts.map((p, i) => i === index ? { ...p, text: insertAttr(p.text, attr) } : p);
433
+ }
434
+ function insertAttr(compound, attr) {
435
+ let depth = 0;
436
+ let quote = "";
437
+ for (let i = 0; i < compound.length; i++) {
438
+ const c = compound[i];
439
+ if (quote) {
440
+ if (c === "\\") i++;
441
+ else if (c === quote) quote = "";
442
+ continue;
443
+ }
444
+ if (c === "\\") {
445
+ i++;
446
+ continue;
447
+ }
448
+ if (c === '"' || c === "'") quote = c;
449
+ else if (c === "(" || c === "[") depth++;
450
+ else if (c === ")" || c === "]") depth--;
451
+ else if (c === ":" && depth === 0 && i > 0) return compound.slice(0, i) + attr + compound.slice(i);
452
+ }
453
+ return compound + attr;
454
+ }
455
+ function compounds(selector) {
456
+ const out = [];
457
+ let depth = 0;
458
+ let quote = "";
459
+ let current = "";
460
+ let combinator = "";
461
+ const push = () => {
462
+ if (current.trim()) out.push({ combinator: out.length ? combinator || " " : "", text: current.trim() });
463
+ current = "";
464
+ combinator = "";
465
+ };
466
+ for (let i = 0; i < selector.length; i++) {
467
+ const c = selector[i];
468
+ if (quote) {
469
+ current += c;
470
+ if (c === "\\") current += selector[++i] ?? "";
471
+ else if (c === quote) quote = "";
472
+ continue;
473
+ }
474
+ if (c === "\\") {
475
+ current += c + (selector[++i] ?? "");
476
+ continue;
477
+ }
478
+ if (c === '"' || c === "'") quote = c;
479
+ if (c === "(" || c === "[") depth++;
480
+ if (c === ")" || c === "]") depth--;
481
+ if (depth === 0 && (c === ">" || c === "+" || c === "~")) {
482
+ push();
483
+ combinator = c;
484
+ continue;
485
+ }
486
+ if (depth === 0 && /\s/.test(c)) {
487
+ if (current.trim()) {
488
+ const keep = combinator;
489
+ push();
490
+ combinator = keep;
491
+ }
492
+ continue;
493
+ }
494
+ current += c;
495
+ }
496
+ push();
497
+ return out;
498
+ }
499
+ function join(parts) {
500
+ return parts.map((p, i) => i === 0 ? p.text : p.combinator === " " ? ` ${p.text}` : ` ${p.combinator} ${p.text}`).join("");
501
+ }
502
+ function unwrap(text, prefix) {
503
+ return text.slice(prefix.length, text.lastIndexOf(")")).trim() + text.slice(text.lastIndexOf(")") + 1);
504
+ }
505
+ function splitTop(selector, separator) {
506
+ const parts = [];
507
+ let depth = 0;
508
+ let quote = "";
509
+ let start = 0;
510
+ for (let i = 0; i < selector.length; i++) {
511
+ const c = selector[i];
512
+ if (quote) {
513
+ if (c === "\\") i++;
514
+ else if (c === quote) quote = "";
515
+ } else if (c === '"' || c === "'") quote = c;
516
+ else if (c === "\\") i++;
517
+ else if (c === "(" || c === "[") depth++;
518
+ else if (c === ")" || c === "]") depth--;
519
+ else if (c === separator && depth === 0) {
520
+ parts.push(selector.slice(start, i));
521
+ start = i + 1;
522
+ }
523
+ }
524
+ parts.push(selector.slice(start));
525
+ return parts.filter((p) => p.trim());
526
+ }
527
+ function shiftLoc(node, source, start) {
528
+ 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;
529
+ if (node.kind === "rule" || node.kind === "at-rule") return { ...node, loc, nodes: node.nodes.map((n) => shiftLoc(n, source, start)) };
530
+ return { ...node, loc };
531
+ }
532
+ function dropLoc(node) {
533
+ const { loc: _loc, ...rest } = node;
534
+ if (rest.kind === "rule" || rest.kind === "at-rule") return { ...rest, nodes: rest.nodes.map(dropLoc) };
535
+ return rest;
536
+ }
537
+ function printStyleWithMap(nodes, minify, sourceName, module) {
538
+ const lines = [[]];
539
+ let css = "";
540
+ let column = 0;
541
+ const emit = (text) => {
542
+ for (const ch of text) {
543
+ css += ch;
544
+ if (ch === "\n") {
545
+ lines.push([]);
546
+ column = 0;
547
+ } else column++;
548
+ }
549
+ };
550
+ const mark = (loc) => {
551
+ if (loc && loc.source === sourceName) lines[lines.length - 1].push([column, 0, loc.line - 1, loc.column]);
552
+ };
553
+ const write = (node, depth) => {
554
+ const pad = minify ? "" : " ".repeat(depth);
555
+ const nl = minify ? "" : "\n";
556
+ const sp = minify ? "" : " ";
557
+ emit(pad);
558
+ mark(node.loc);
559
+ if (node.kind === "declaration") {
560
+ emit(`${node.property}:${sp}${node.value}${node.important ? `${sp}!important` : ""};${nl}`);
561
+ } else if (node.kind === "raw") {
562
+ emit(`${node.text}${nl}`);
563
+ } else {
564
+ emit(`${node.kind === "rule" ? node.selector : `@${node.name}${node.params ? " " + node.params : ""}`}${sp}{${nl}`);
565
+ for (const child of node.nodes) write(child, depth + 1);
566
+ emit(`${pad}}${nl}`);
567
+ }
568
+ };
569
+ for (const node of nodes) write(node, 0);
570
+ return { css, map: { version: 3, sources: [module.id], sourcesContent: [module.code], names: [], mappings: encode(lines) } };
571
+ }
572
+ function printStyle(nodes, minify = false) {
573
+ const out = [];
574
+ const write = (node, depth) => {
575
+ const pad = minify ? "" : " ".repeat(depth);
576
+ const nl = minify ? "" : "\n";
577
+ const sp = minify ? "" : " ";
578
+ if (node.kind === "declaration") {
579
+ out.push(`${pad}${node.property}:${sp}${node.value}${node.important ? `${sp}!important` : ""};${nl}`);
580
+ } else if (node.kind === "raw") {
581
+ out.push(`${pad}${node.text}${nl}`);
582
+ } else {
583
+ const header = node.kind === "rule" ? node.selector : `@${node.name}${node.params ? " " + node.params : ""}`;
584
+ out.push(`${pad}${header}${sp}{${nl}`);
585
+ for (const child of node.nodes) write(child, depth + 1);
586
+ out.push(`${pad}}${nl}`);
587
+ }
588
+ };
589
+ for (const node of nodes) write(node, 0);
590
+ return out.join("");
591
+ }
592
+
35
593
  // src/lower/compile-template.ts
36
594
  function compilePieces(pieces, holes, options = {}) {
37
595
  const used = /* @__PURE__ */ new Set();
@@ -40,6 +598,7 @@ function compilePieces(pieces, holes, options = {}) {
40
598
  ...options.sourceFile ? { sourceFile: options.sourceFile } : {},
41
599
  ...options.positionAt ? { positionAt: options.positionAt } : {}
42
600
  });
601
+ if (options.templateStyles) applyTemplateStyles(ir, options.templateStyles);
43
602
  analyzeStatic(ir);
44
603
  resolveComponentSources(ir, {
45
604
  resolver: createComponentResolver(options.resolve ?? []),
@@ -573,8 +1132,8 @@ function isJsxRoot(node, parent, key) {
573
1132
  if (!isJsx(node)) return false;
574
1133
  return !(parent && isJsx(parent) && key === "children");
575
1134
  }
576
- function isTemplateTag(node, litTag) {
577
- return node.type === "TaggedTemplateExpression" && node.tag?.type === "Identifier" && (node.tag.name === litTag || node.tag.name === "svg");
1135
+ function isTemplateTag(node, tags) {
1136
+ return node.type === "TaggedTemplateExpression" && node.tag?.type === "Identifier" && tags.has(node.tag.name);
578
1137
  }
579
1138
  function outermost(list) {
580
1139
  return list.filter(
@@ -722,22 +1281,28 @@ function transformTemplates(code, id, options = {}) {
722
1281
  const wantsIntrinsics = options.intrinsics !== false && mayHaveIntrinsic(code);
723
1282
  const wantsSources = options.sourceLocations === true && mayHaveSourceMarks(code);
724
1283
  const sourceName = relativeToRoot(id, options.sourceRoot);
725
- if (!mayHaveTemplate && !(wantsJsx && code.includes("<")) && !wantsIntrinsics && !wantsSources) return null;
1284
+ const wantsStyles = options.styles !== void 0 && (code.includes("<style") || code.includes("css`"));
1285
+ if (!mayHaveTemplate && !(wantsJsx && code.includes("<")) && !wantsIntrinsics && !wantsSources && !wantsStyles) return null;
726
1286
  const ast = parse2(code, {
727
1287
  sourceType: "module",
728
1288
  plugins: ["jsx", "typescript"],
729
1289
  errorRecovery: true
730
1290
  });
1291
+ const intrinsicTags = options.intrinsics === false ? /* @__PURE__ */ new Map() : tagIntrinsics(moduleBindings(ast.program));
1292
+ const templateTags = /* @__PURE__ */ new Map([[litTag, "html"], ["svg", "svg"]]);
1293
+ for (const [name, tag] of intrinsicTags) if (tag !== "css") templateTags.set(name, tag);
1294
+ const cssTags = [...intrinsicTags].filter(([, tag]) => tag === "css").map(([name]) => name);
731
1295
  const found = [];
732
1296
  walk4(ast.program, (n, parent, key) => {
733
- if (wantsLit && isTemplateTag(n, litTag)) found.push(n);
1297
+ if (wantsLit && isTemplateTag(n, templateTags)) found.push(n);
734
1298
  else if (wantsJsx && isJsxRoot(n, parent, key)) found.push(n);
735
1299
  });
736
1300
  const props = options.propsDestructure === false ? { edits: [], diagnostics: [], used: /* @__PURE__ */ new Set() } : collectPropsEdits(ast.program, code, { runtimeModule: options.runtimeModule });
737
1301
  const intrinsics = options.intrinsics === false ? { edits: [], diagnostics: [], imports: /* @__PURE__ */ new Map() } : collectIntrinsicEdits(ast.program);
738
1302
  if (intrinsics.edits.length) avoidBindingClashes(ast.program, intrinsics, moduleBindings(ast.program));
739
1303
  const sources = options.sourceLocations === true ? collectSourceEdits(ast.program, sourceName) : { edits: [], marked: 0 };
740
- 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;
1304
+ const styles = wantsStyles ? collectStyles(ast.program, sourceName, options.styles, { html: templateTags, css: cssTags }, { id, code }) : void 0;
1305
+ 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;
741
1306
  if (silent) return null;
742
1307
  found.sort((a, b) => b.start - a.start || a.end - b.end);
743
1308
  const used = new Set(props.used);
@@ -751,20 +1316,32 @@ function transformTemplates(code, id, options = {}) {
751
1316
  declared: declaredNames(ast.program)
752
1317
  };
753
1318
  const hoisted = /* @__PURE__ */ new Map();
754
- const edits = [...props.edits, ...intrinsics.edits, ...sources.edits];
1319
+ const edits = [...props.edits, ...intrinsics.edits, ...sources.edits, ...styles?.edits ?? []];
755
1320
  for (const node of found) {
756
1321
  const nested = found.some(
757
1322
  (o) => o !== node && o.start <= node.start && o.end >= node.end && o.end - o.start > node.end - node.start
758
1323
  );
759
1324
  if (isJsx(node)) {
760
- edits.push({ start: node.start, end: node.end, code: compileJsx(code, node, edits, nested, used, needs, hoisted, options, sourceName) });
1325
+ edits.push({ start: node.start, end: node.end, code: compileJsx(code, node, edits, nested, used, needs, hoisted, options, sourceName, styles) });
761
1326
  continue;
762
1327
  }
763
1328
  const holes = node.quasi.expressions.map(
764
1329
  (e) => bindHole(code, e, edits, options.sourceLocations === true)
765
1330
  );
1331
+ const scope = styles?.scopes.find((s) => node.start >= s.start && node.end <= s.end)?.value;
1332
+ const owner = styles?.templateOwners.get(node.start);
1333
+ const templateStyles = options.styles && styles && (scope || owner) ? {
1334
+ options: options.styles,
1335
+ ...scope ? { scope } : {},
1336
+ ...owner ? { owner } : {},
1337
+ line: node.loc?.start.line ?? 0,
1338
+ column: node.loc?.start.column ?? 0,
1339
+ styles: styles.styles,
1340
+ diagnostics: styles.diagnostics
1341
+ } : void 0;
766
1342
  const result = compilePieces(toPieces(node), holes, {
767
1343
  ...options,
1344
+ ...templateStyles ? { templateStyles } : {},
768
1345
  hoistTemplates: true,
769
1346
  // A tag inside a template gets the same mark a JSX tag does. Without one, the nodes it
770
1347
  // makes are the only ones in the module carrying no mark, and they take whichever was
@@ -773,12 +1350,13 @@ function transformTemplates(code, id, options = {}) {
773
1350
  // Same defaults as the plugin, so moving a build over is not a rendering change.
774
1351
  templateClone: options.templateClone ?? true,
775
1352
  partialTemplates: nested ? false : options.partialTemplates ?? true,
776
- svg: node.tag.name === "svg"
1353
+ svg: templateTags.get(node.tag.name) === "svg"
777
1354
  });
778
1355
  for (const symbol of result.imports) used.add(symbol);
779
1356
  collectNeeds(result.ir, needs);
780
1357
  edits.push({ start: node.start, end: node.end, code: adoptTemplates(result.code, result.templates, hoisted) });
781
1358
  }
1359
+ if (styles && options.styles) edits.push(...finishShadowStyles(styles, code, id));
782
1360
  const out = new MagicString(code);
783
1361
  for (const e of outermost(edits)) {
784
1362
  if (e.start === e.end) out.appendLeft(e.start, e.code);
@@ -836,13 +1414,19 @@ function transformTemplates(code, id, options = {}) {
836
1414
  ...loadDiagnostics.length ? { loadDiagnostics } : {},
837
1415
  ...unresolvedDiagnostics.length ? { unresolvedDiagnostics } : {},
838
1416
  ...props.diagnostics.length ? { propsDiagnostics: props.diagnostics } : {},
839
- ...intrinsics.diagnostics.length ? { intrinsicDiagnostics: intrinsics.diagnostics } : {}
1417
+ ...intrinsics.diagnostics.length ? { intrinsicDiagnostics: intrinsics.diagnostics } : {},
1418
+ ...styles?.styles.length ? { styles: styles.styles } : {},
1419
+ ...styles?.diagnostics.length ? { styleDiagnostics: styles.diagnostics } : {},
1420
+ ...styles?.literals.length ? { styleLiterals: styles.literals } : {},
1421
+ ...styles?.references.length ? { styleReferences: styles.references } : {}
840
1422
  };
841
1423
  }
842
- function compileJsx(code, node, edits, nested, used, needs, hoisted, options, sourceFile) {
1424
+ function compileJsx(code, node, edits, nested, used, needs, hoisted, options, sourceFile, styles) {
843
1425
  const ir = buildJsxIR(node, {
844
1426
  code: (n) => slice(code, n.start, n.end, edits),
845
1427
  used,
1428
+ ...styles?.scopes.length ? { scopes: styles.scopes } : {},
1429
+ ...styles?.drop.size ? { dropStyles: styles.drop } : {},
846
1430
  ...options.sourceLocations === true && sourceFile ? { sourceFile } : {}
847
1431
  });
848
1432
  analyzeStatic(ir);