@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.
- package/LICENSE +1 -1
- package/dist/analyze/intrinsics.cjs +13 -1
- package/dist/analyze/intrinsics.d.cts +14 -0
- package/dist/analyze/intrinsics.d.ts +14 -0
- package/dist/analyze/intrinsics.d.ts.map +1 -1
- package/dist/analyze/intrinsics.js +17 -0
- package/dist/analyze/intrinsics.mjs +13 -1
- package/dist/analyze/static-graph.cjs +1 -1
- package/dist/analyze/static-graph.mjs +1 -1
- package/dist/{babel-RJHJQVEM.mjs → babel-V33QLJBF.mjs} +4 -4
- package/dist/{chunk-56QSOVVL.mjs → chunk-62F2LLBM.mjs} +1 -1
- package/dist/{chunk-R7PPFBCL.mjs → chunk-7GNSGUHK.mjs} +4 -83
- package/dist/{chunk-U7HCFLZ2.mjs → chunk-B64LVPTU.mjs} +356 -24
- package/dist/{chunk-OD53TMER.mjs → chunk-C3AK5PBV.mjs} +13 -1
- package/dist/{chunk-TJIH7TLX.mjs → chunk-GLFUPZ27.mjs} +1 -1
- package/dist/chunk-HUABRVWB.mjs +92 -0
- package/dist/chunk-XCWP7WJG.mjs +584 -0
- package/dist/codegen/backends/imperative.cjs +1 -1
- package/dist/codegen/backends/imperative.d.ts.map +1 -1
- package/dist/codegen/backends/imperative.js +2 -1
- package/dist/codegen/backends/imperative.mjs +1 -1
- package/dist/frontend/babel/build-ir-lit.cjs +352 -22
- package/dist/frontend/babel/build-ir-lit.mjs +352 -22
- package/dist/frontend/babel/build-ir.cjs +352 -22
- package/dist/frontend/babel/build-ir.mjs +352 -22
- package/dist/frontend/babel/index.cjs +353 -23
- package/dist/frontend/babel/index.mjs +353 -23
- package/dist/frontend/babel/lower-template.cjs +352 -22
- package/dist/frontend/babel/lower-template.mjs +352 -22
- package/dist/frontend/babel/plugin.cjs +352 -22
- package/dist/frontend/babel/plugin.mjs +352 -22
- package/dist/index.cjs +321 -22
- package/dist/index.mjs +333 -22
- package/dist/integrations.cjs +1240 -56
- package/dist/integrations.d.ts.map +1 -1
- package/dist/integrations.js +62 -9
- package/dist/integrations.mjs +257 -26
- package/dist/lower/compile-template.cjs +315 -21
- package/dist/lower/compile-template.d.cts +13 -0
- package/dist/lower/compile-template.d.ts +13 -0
- package/dist/lower/compile-template.d.ts.map +1 -1
- package/dist/lower/compile-template.js +3 -0
- package/dist/lower/compile-template.mjs +327 -21
- package/dist/lower/entities.cjs +288 -0
- package/dist/lower/entities.d.cts +1 -0
- package/dist/lower/entities.d.ts +2 -0
- package/dist/lower/entities.d.ts.map +1 -0
- package/dist/lower/entities.js +54 -0
- package/dist/lower/entities.mjs +267 -0
- package/dist/lower/jsx.cjs +104 -47
- package/dist/lower/jsx.d.cts +8 -0
- package/dist/lower/jsx.d.ts +8 -0
- package/dist/lower/jsx.d.ts.map +1 -1
- package/dist/lower/jsx.js +92 -2
- package/dist/lower/jsx.mjs +104 -47
- package/dist/lower/template.cjs +293 -20
- package/dist/lower/template.d.ts.map +1 -1
- package/dist/lower/template.js +35 -19
- package/dist/lower/template.mjs +293 -20
- package/dist/resolve/builtins.cjs +1 -1
- package/dist/resolve/builtins.mjs +1 -1
- package/dist/resolve/component-globals.cjs +6 -1
- package/dist/resolve/component-globals.js +2 -2
- package/dist/resolve/component-globals.mjs +6 -1
- package/dist/resolve/write-globals.cjs +6 -1
- package/dist/resolve/write-globals.mjs +6 -1
- package/dist/{server-fns-ZFRDIQ2X.mjs → server-fns-N3SDJXA7.mjs} +5 -4
- package/dist/{server-functions-CTDXX67X.mjs → server-functions-LVS66Q4R.mjs} +3 -3
- package/dist/transform/index.cjs +973 -33
- package/dist/transform/index.mjs +991 -47
- package/dist/transform/props.mjs +19 -14
- package/dist/transform/server-fns.mjs +19 -14
- package/dist/transform/styles.cjs +606 -0
- package/dist/transform/styles.d.cts +237 -0
- package/dist/transform/styles.d.ts +238 -0
- package/dist/transform/styles.d.ts.map +1 -0
- package/dist/transform/styles.js +743 -0
- package/dist/transform/styles.mjs +671 -0
- package/dist/transform/templates.cjs +972 -32
- package/dist/transform/templates.d.cts +13 -0
- package/dist/transform/templates.d.ts +13 -0
- package/dist/transform/templates.d.ts.map +1 -1
- package/dist/transform/templates.js +49 -12
- package/dist/transform/templates.mjs +990 -46
- package/dist/{transform-QWWQDCXE.mjs → transform-P4AETYV4.mjs} +49 -16
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- package/dist/vite-styles.cjs +223 -0
- package/dist/vite-styles.d.cts +68 -0
- package/dist/vite-styles.d.ts +69 -0
- package/dist/vite-styles.d.ts.map +1 -0
- package/dist/vite-styles.js +241 -0
- package/dist/vite-styles.mjs +214 -0
- package/package.json +5 -4
package/dist/lower/jsx.js
CHANGED
|
@@ -4,6 +4,7 @@ import { shapeOf } from '../analyze/expr-shape.js';
|
|
|
4
4
|
import { analyzeStatic } from '../optimize/analyze-static.js';
|
|
5
5
|
import { cleanTemplateText } from './text.js';
|
|
6
6
|
import { paren } from '../analyze/paren.js';
|
|
7
|
+
import { markHole } from '../transform/source-locations.js';
|
|
7
8
|
import { imperativeBackend, inlineTemplates } from '../codegen/backends/imperative.js';
|
|
8
9
|
export const SVG_TAGS = new Set([
|
|
9
10
|
'svg', 'path', 'circle', 'rect', 'line', 'polygon', 'polyline',
|
|
@@ -132,9 +133,18 @@ function attrExprCode(attr, ctx) {
|
|
|
132
133
|
}
|
|
133
134
|
return null;
|
|
134
135
|
}
|
|
135
|
-
|
|
136
|
+
/**
|
|
137
|
+
* `element`: the tag is a DOM element. Only there are class:/style: and a style object taken
|
|
138
|
+
* apart; a component gets its props as written.
|
|
139
|
+
*/
|
|
140
|
+
function buildProps(attrs, ctx, element = false) {
|
|
136
141
|
const props = [];
|
|
137
142
|
const usePairs = []; // use:name directives collapse into one `use` prop
|
|
143
|
+
// class:x and style:x collapse into one classList / style object, as in templates; each
|
|
144
|
+
// value that moves is an accessor in it, so the runtime updates that one key.
|
|
145
|
+
const classEntries = [];
|
|
146
|
+
const styleEntries = [];
|
|
147
|
+
let styleAt;
|
|
138
148
|
for (const a of attrs) {
|
|
139
149
|
if (a.type === 'JSXSpreadAttribute') {
|
|
140
150
|
props.push({ name: '', kind: 'spread', expr: ctx.code(a.argument) });
|
|
@@ -155,6 +165,33 @@ function buildProps(attrs, ctx) {
|
|
|
155
165
|
usePairs.push(opts != null ? `[${dir}, () => ${paren(opts, 'arrowBody')}]` : `[${dir}]`);
|
|
156
166
|
continue;
|
|
157
167
|
}
|
|
168
|
+
if (element && (ns === 'class' || ns === 'style')) {
|
|
169
|
+
const key = JSON.stringify(a.name.name.name);
|
|
170
|
+
const v = a.value;
|
|
171
|
+
let value;
|
|
172
|
+
if (v == null)
|
|
173
|
+
value = 'true';
|
|
174
|
+
else if (isString(v))
|
|
175
|
+
value = JSON.stringify(literalOf(v));
|
|
176
|
+
else if (v.type === 'JSXExpressionContainer' && v.expression?.type !== 'JSXEmptyExpression') {
|
|
177
|
+
value = keyValue(v.expression, ctx);
|
|
178
|
+
if (ns === 'style')
|
|
179
|
+
styleAt ??= posOf(v.expression, ctx);
|
|
180
|
+
}
|
|
181
|
+
else
|
|
182
|
+
continue;
|
|
183
|
+
(ns === 'class' ? classEntries : styleEntries).push(`${key}: ${value}`);
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
// style={{ … }}: one entry per property, so `--gap` moving does not rewrite `margin`.
|
|
187
|
+
if (element && a.name.type === 'JSXIdentifier' && a.name.name === 'style' && a.value?.type === 'JSXExpressionContainer') {
|
|
188
|
+
const entries = objectEntries(a.value.expression, ctx);
|
|
189
|
+
if (entries) {
|
|
190
|
+
styleEntries.unshift(...entries);
|
|
191
|
+
styleAt = posOf(a.value.expression, ctx);
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
158
195
|
// oncapture:name -> native on:name with { capture: true }
|
|
159
196
|
if (ns === 'oncapture') {
|
|
160
197
|
const evt = a.name.name.name.toLowerCase();
|
|
@@ -164,10 +201,51 @@ function buildProps(attrs, ctx) {
|
|
|
164
201
|
}
|
|
165
202
|
props.push(buildAttr(a, ctx));
|
|
166
203
|
}
|
|
204
|
+
if (classEntries.length > 0)
|
|
205
|
+
props.push({ name: 'classList', kind: 'attr', expr: `{ ${classEntries.join(', ')} }`, reactive: false });
|
|
206
|
+
if (styleEntries.length > 0) {
|
|
207
|
+
const entries = `{ ${styleEntries.join(', ')} }`;
|
|
208
|
+
// A style the object form could not take apart (a string, a variable) goes first, and
|
|
209
|
+
// the keys after it: the runtime applies an array in order.
|
|
210
|
+
const base = props.findIndex((p) => p.name === 'style' && p.kind === 'attr');
|
|
211
|
+
if (base === -1)
|
|
212
|
+
props.push({ name: 'style', kind: 'attr', expr: entries, reactive: false, ...(styleAt ? { at: styleAt } : {}) });
|
|
213
|
+
else {
|
|
214
|
+
const prop = props[base];
|
|
215
|
+
const value = prop.literal !== undefined ? JSON.stringify(prop.literal) : prop.reactive ? `() => ${paren(prop.expr, 'arrowBody')}` : prop.expr;
|
|
216
|
+
props[base] = { name: 'style', kind: 'attr', expr: `[${value}, ${entries}]`, reactive: false, ...(prop.at ? { at: prop.at } : {}) };
|
|
217
|
+
}
|
|
218
|
+
}
|
|
167
219
|
if (usePairs.length > 0)
|
|
168
220
|
props.push({ name: 'use', kind: 'attr', expr: `[${usePairs.join(', ')}]` });
|
|
169
221
|
return props;
|
|
170
222
|
}
|
|
223
|
+
/** A value inside a classList / style object: an accessor when it moves. */
|
|
224
|
+
function keyValue(expr, ctx) {
|
|
225
|
+
const code = ctx.code(expr);
|
|
226
|
+
if (!isReactive(expr))
|
|
227
|
+
return code;
|
|
228
|
+
const accessor = `() => ${paren(code, 'arrowBody')}`;
|
|
229
|
+
const at = posOf(expr, ctx);
|
|
230
|
+
return at ? markHole(accessor, at.line, at.column) : accessor;
|
|
231
|
+
}
|
|
232
|
+
/** `{ a: x, '--b': y }` as object entries; null for anything with a spread or a method. */
|
|
233
|
+
function objectEntries(expr, ctx) {
|
|
234
|
+
if (expr?.type !== 'ObjectExpression')
|
|
235
|
+
return null;
|
|
236
|
+
const entries = [];
|
|
237
|
+
for (const p of expr.properties) {
|
|
238
|
+
if (p.type !== 'ObjectProperty')
|
|
239
|
+
return null;
|
|
240
|
+
const key = p.computed
|
|
241
|
+
? `[${ctx.code(p.key)}]`
|
|
242
|
+
: p.key.type === 'Identifier'
|
|
243
|
+
? JSON.stringify(p.key.name)
|
|
244
|
+
: JSON.stringify(String(p.key.value));
|
|
245
|
+
entries.push(`${key}: ${keyValue(p.value, ctx)}`);
|
|
246
|
+
}
|
|
247
|
+
return entries;
|
|
248
|
+
}
|
|
171
249
|
function buildChildren(children, ctx) {
|
|
172
250
|
const out = [];
|
|
173
251
|
for (let i = 0; i < children.length; i++) {
|
|
@@ -203,6 +281,9 @@ function buildChildren(children, ctx) {
|
|
|
203
281
|
}
|
|
204
282
|
}
|
|
205
283
|
else if (child.type === 'JSXElement' || child.type === 'JSXFragment') {
|
|
284
|
+
// A `<style>` the compiler took out leaves no child behind, not even an empty insert.
|
|
285
|
+
if (ctx.dropStyles?.has(child.start))
|
|
286
|
+
continue;
|
|
206
287
|
out.push(buildNode(child, ctx));
|
|
207
288
|
}
|
|
208
289
|
else if (child.type === 'JSXSpreadChild') {
|
|
@@ -295,7 +376,13 @@ function buildElement(node, ctx, handled) {
|
|
|
295
376
|
const at = ctx.sourceFile && node.loc?.start
|
|
296
377
|
? { file: ctx.sourceFile, line: node.loc.start.line, column: node.loc.start.column }
|
|
297
378
|
: undefined;
|
|
298
|
-
|
|
379
|
+
const props = buildProps(attributes, ctx, true);
|
|
380
|
+
// A scoped style's mark: a static attribute, so it is part of the template itself and
|
|
381
|
+
// every render carries it, on the client, from the server and through hydration.
|
|
382
|
+
const scope = ctx.scopes?.find((s) => node.start >= s.start && node.end <= s.end);
|
|
383
|
+
if (scope)
|
|
384
|
+
props.unshift({ name: 'data-fx-s', kind: 'attr', literal: scope.value });
|
|
385
|
+
return { kind: 'element', tag, svg: SVG_TAGS.has(tag), props, children, static: false, ...(at ? { at } : {}) };
|
|
299
386
|
}
|
|
300
387
|
function buildNode(node, ctx) {
|
|
301
388
|
if (node.type === 'JSXFragment') {
|
|
@@ -303,6 +390,9 @@ function buildNode(node, ctx) {
|
|
|
303
390
|
}
|
|
304
391
|
if (directive(node, 'if'))
|
|
305
392
|
return buildIf(node, null, ctx);
|
|
393
|
+
// Its CSS went to the host; nothing of the element is rendered.
|
|
394
|
+
if (ctx.dropStyles?.has(node.start))
|
|
395
|
+
return { kind: 'fragment', children: [] };
|
|
306
396
|
const { tag, component } = tagInfo(node.openingElement.name, ctx);
|
|
307
397
|
if (!component)
|
|
308
398
|
return buildElement(node, ctx, []);
|
package/dist/lower/jsx.mjs
CHANGED
|
@@ -305,6 +305,50 @@ function paren(code, position) {
|
|
|
305
305
|
return topLevelComma(src) === false ? code : `(${code})`;
|
|
306
306
|
}
|
|
307
307
|
|
|
308
|
+
// src/analyze/intrinsics.ts
|
|
309
|
+
var REACTIVE_MODULE = "@fluixi/reactive/signal";
|
|
310
|
+
var INTRINSICS = {
|
|
311
|
+
$signal: { export: "signal", module: REACTIVE_MODULE, returns: "signal-handle" },
|
|
312
|
+
$memo: { export: "memo", module: REACTIVE_MODULE, returns: "memo-handle" },
|
|
313
|
+
$effect: { export: "effect", module: REACTIVE_MODULE, returns: "effect" },
|
|
314
|
+
$store: { export: "store", module: "@fluixi/reactive/store", returns: "store-handle" },
|
|
315
|
+
$resource: { export: "resource", module: REACTIVE_MODULE, returns: "resource-handle" },
|
|
316
|
+
$cachedResource: { export: "cachedResource", module: "@fluixi/reactive/cached-resource", returns: "resource-handle" },
|
|
317
|
+
// No short runtime form for these yet, so the intrinsic stands for the `create*`
|
|
318
|
+
// name. Still worth having: no import to write, and when a shorter form is
|
|
319
|
+
// designed, the change is this line rather than a compiler pass.
|
|
320
|
+
$selector: { export: "createSelector", module: REACTIVE_MODULE, returns: "memo-accessor" },
|
|
321
|
+
$deferred: { export: "createDeferred", module: REACTIVE_MODULE, returns: "memo-accessor" },
|
|
322
|
+
// Not value constructors, but the compiler has to know them: they change what a read
|
|
323
|
+
// does. `untrack` suppresses dependency collection, which is exactly the kind of thing
|
|
324
|
+
// dependency analysis must not guess at.
|
|
325
|
+
$untrack: { export: "untrack", module: REACTIVE_MODULE, returns: "plain" },
|
|
326
|
+
$untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" },
|
|
327
|
+
// Scopes, scheduling and lifecycle: no value to classify, but the same authoring promise,
|
|
328
|
+
// no import to write. `$cleanup` registers a callback on the current owner (`onCleanup`).
|
|
329
|
+
$batch: { export: "batch", module: REACTIVE_MODULE, returns: "plain" },
|
|
330
|
+
$cleanup: { export: "onCleanup", module: REACTIVE_MODULE, returns: "plain" },
|
|
331
|
+
$root: { export: "root", module: REACTIVE_MODULE, returns: "plain" },
|
|
332
|
+
$context: { export: "context", module: REACTIVE_MODULE, returns: "plain" },
|
|
333
|
+
$renderEffect: { export: "renderEffect", module: REACTIVE_MODULE, returns: "effect" },
|
|
334
|
+
$computed: { export: "computed", module: REACTIVE_MODULE, returns: "effect" },
|
|
335
|
+
// Storage for where the code runs, and a signal kept in it. `$persisted` is a signal
|
|
336
|
+
// handle as far as reads go: the same accessor with `set` on it.
|
|
337
|
+
$storage: { export: "useStorage", module: "@fluixi/core/storage", returns: "plain" },
|
|
338
|
+
$asyncStorage: { export: "useAsyncStorage", module: "@fluixi/core/storage", returns: "plain" },
|
|
339
|
+
$persisted: { export: "persisted", module: "@fluixi/core/storage", returns: "signal-handle" },
|
|
340
|
+
// An environment variable, public or server-only; the browser build refuses a secret.
|
|
341
|
+
$env: { export: "env", module: "@fluixi/start/env", returns: "plain" }
|
|
342
|
+
};
|
|
343
|
+
var INTRINSIC_CALL = new RegExp(`\\$(?:${Object.keys(INTRINSICS).map((n) => n.slice(1)).join("|")})\\s*\\(`);
|
|
344
|
+
|
|
345
|
+
// src/transform/source-locations.ts
|
|
346
|
+
var SOURCE_MARKER = "__fx_source";
|
|
347
|
+
var HOLE_MARKER = "__fx_hole";
|
|
348
|
+
var markHole = (accessor, line, column, name) => `(globalThis.${HOLE_MARKER} ?? ((f) => f))(${accessor},${line},${column}${name === void 0 ? "" : `,${JSON.stringify(name)}`})`;
|
|
349
|
+
var PROPS_MARKER = "__fx_props";
|
|
350
|
+
var markProps = (object, at) => `(globalThis.${PROPS_MARKER} ?? ((p) => p))(${object},${JSON.stringify(at)})`;
|
|
351
|
+
|
|
308
352
|
// src/codegen/serialize-static.ts
|
|
309
353
|
var VOID_ELEMENTS = /* @__PURE__ */ new Set([
|
|
310
354
|
"area",
|
|
@@ -509,50 +553,6 @@ var RUNTIME_CONTRACT_V2 = {
|
|
|
509
553
|
symbols: [...RUNTIME_CONTRACT_V1.symbols, "template", "cloneTemplate", "walk"]
|
|
510
554
|
};
|
|
511
555
|
|
|
512
|
-
// src/analyze/intrinsics.ts
|
|
513
|
-
var REACTIVE_MODULE = "@fluixi/reactive/signal";
|
|
514
|
-
var INTRINSICS = {
|
|
515
|
-
$signal: { export: "signal", module: REACTIVE_MODULE, returns: "signal-handle" },
|
|
516
|
-
$memo: { export: "memo", module: REACTIVE_MODULE, returns: "memo-handle" },
|
|
517
|
-
$effect: { export: "effect", module: REACTIVE_MODULE, returns: "effect" },
|
|
518
|
-
$store: { export: "store", module: "@fluixi/reactive/store", returns: "store-handle" },
|
|
519
|
-
$resource: { export: "resource", module: REACTIVE_MODULE, returns: "resource-handle" },
|
|
520
|
-
$cachedResource: { export: "cachedResource", module: "@fluixi/reactive/cached-resource", returns: "resource-handle" },
|
|
521
|
-
// No short runtime form for these yet, so the intrinsic stands for the `create*`
|
|
522
|
-
// name. Still worth having: no import to write, and when a shorter form is
|
|
523
|
-
// designed, the change is this line rather than a compiler pass.
|
|
524
|
-
$selector: { export: "createSelector", module: REACTIVE_MODULE, returns: "memo-accessor" },
|
|
525
|
-
$deferred: { export: "createDeferred", module: REACTIVE_MODULE, returns: "memo-accessor" },
|
|
526
|
-
// Not value constructors, but the compiler has to know them: they change what a read
|
|
527
|
-
// does. `untrack` suppresses dependency collection, which is exactly the kind of thing
|
|
528
|
-
// dependency analysis must not guess at.
|
|
529
|
-
$untrack: { export: "untrack", module: REACTIVE_MODULE, returns: "plain" },
|
|
530
|
-
$untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" },
|
|
531
|
-
// Scopes, scheduling and lifecycle: no value to classify, but the same authoring promise,
|
|
532
|
-
// no import to write. `$cleanup` registers a callback on the current owner (`onCleanup`).
|
|
533
|
-
$batch: { export: "batch", module: REACTIVE_MODULE, returns: "plain" },
|
|
534
|
-
$cleanup: { export: "onCleanup", module: REACTIVE_MODULE, returns: "plain" },
|
|
535
|
-
$root: { export: "root", module: REACTIVE_MODULE, returns: "plain" },
|
|
536
|
-
$context: { export: "context", module: REACTIVE_MODULE, returns: "plain" },
|
|
537
|
-
$renderEffect: { export: "renderEffect", module: REACTIVE_MODULE, returns: "effect" },
|
|
538
|
-
$computed: { export: "computed", module: REACTIVE_MODULE, returns: "effect" },
|
|
539
|
-
// Storage for where the code runs, and a signal kept in it. `$persisted` is a signal
|
|
540
|
-
// handle as far as reads go: the same accessor with `set` on it.
|
|
541
|
-
$storage: { export: "useStorage", module: "@fluixi/core/storage", returns: "plain" },
|
|
542
|
-
$asyncStorage: { export: "useAsyncStorage", module: "@fluixi/core/storage", returns: "plain" },
|
|
543
|
-
$persisted: { export: "persisted", module: "@fluixi/core/storage", returns: "signal-handle" },
|
|
544
|
-
// An environment variable, public or server-only; the browser build refuses a secret.
|
|
545
|
-
$env: { export: "env", module: "@fluixi/start/env", returns: "plain" }
|
|
546
|
-
};
|
|
547
|
-
var INTRINSIC_CALL = new RegExp(`\\$(?:${Object.keys(INTRINSICS).map((n) => n.slice(1)).join("|")})\\s*\\(`);
|
|
548
|
-
|
|
549
|
-
// src/transform/source-locations.ts
|
|
550
|
-
var SOURCE_MARKER = "__fx_source";
|
|
551
|
-
var HOLE_MARKER = "__fx_hole";
|
|
552
|
-
var markHole = (accessor, line, column, name) => `(globalThis.${HOLE_MARKER} ?? ((f) => f))(${accessor},${line},${column}${name === void 0 ? "" : `,${JSON.stringify(name)}`})`;
|
|
553
|
-
var PROPS_MARKER = "__fx_props";
|
|
554
|
-
var markProps = (object, at) => `(globalThis.${PROPS_MARKER} ?? ((p) => p))(${object},${JSON.stringify(at)})`;
|
|
555
|
-
|
|
556
556
|
// src/codegen/backends/imperative.ts
|
|
557
557
|
var CONTROL_COMPONENT = {
|
|
558
558
|
show: "Show",
|
|
@@ -614,7 +614,7 @@ function emitComponent(name, props, children, used, templates, at) {
|
|
|
614
614
|
}
|
|
615
615
|
let obj = `{ ${bodies.map(([name2, body]) => `get ${propKey(name2)}() { return ${body}; }`).join(", ")} }`;
|
|
616
616
|
if (bodies.some(([, body]) => /\bthis\b/.test(body))) {
|
|
617
|
-
const thunks = bodies.map(([name2, body]) => `${JSON.stringify(name2)}: () => ${body}`);
|
|
617
|
+
const thunks = bodies.map(([name2, body]) => `${JSON.stringify(name2)}: () => (${body})`);
|
|
618
618
|
const getters = bodies.map(([name2]) => `get ${propKey(name2)}() { return _$t[${JSON.stringify(name2)}](); }`);
|
|
619
619
|
obj = `((_$t) => ({ ${getters.join(", ")} }))({ ${thunks.join(", ")} })`;
|
|
620
620
|
}
|
|
@@ -858,9 +858,12 @@ function attrExprCode(attr, ctx) {
|
|
|
858
858
|
}
|
|
859
859
|
return null;
|
|
860
860
|
}
|
|
861
|
-
function buildProps(attrs, ctx) {
|
|
861
|
+
function buildProps(attrs, ctx, element = false) {
|
|
862
862
|
const props = [];
|
|
863
863
|
const usePairs = [];
|
|
864
|
+
const classEntries = [];
|
|
865
|
+
const styleEntries = [];
|
|
866
|
+
let styleAt;
|
|
864
867
|
for (const a of attrs) {
|
|
865
868
|
if (a.type === "JSXSpreadAttribute") {
|
|
866
869
|
props.push({ name: "", kind: "spread", expr: ctx.code(a.argument) });
|
|
@@ -876,6 +879,27 @@ function buildProps(attrs, ctx) {
|
|
|
876
879
|
usePairs.push(opts != null ? `[${dir}, () => ${paren(opts, "arrowBody")}]` : `[${dir}]`);
|
|
877
880
|
continue;
|
|
878
881
|
}
|
|
882
|
+
if (element && (ns === "class" || ns === "style")) {
|
|
883
|
+
const key = JSON.stringify(a.name.name.name);
|
|
884
|
+
const v = a.value;
|
|
885
|
+
let value;
|
|
886
|
+
if (v == null) value = "true";
|
|
887
|
+
else if (isString(v)) value = JSON.stringify(literalOf(v));
|
|
888
|
+
else if (v.type === "JSXExpressionContainer" && v.expression?.type !== "JSXEmptyExpression") {
|
|
889
|
+
value = keyValue(v.expression, ctx);
|
|
890
|
+
if (ns === "style") styleAt ??= posOf(v.expression, ctx);
|
|
891
|
+
} else continue;
|
|
892
|
+
(ns === "class" ? classEntries : styleEntries).push(`${key}: ${value}`);
|
|
893
|
+
continue;
|
|
894
|
+
}
|
|
895
|
+
if (element && a.name.type === "JSXIdentifier" && a.name.name === "style" && a.value?.type === "JSXExpressionContainer") {
|
|
896
|
+
const entries = objectEntries(a.value.expression, ctx);
|
|
897
|
+
if (entries) {
|
|
898
|
+
styleEntries.unshift(...entries);
|
|
899
|
+
styleAt = posOf(a.value.expression, ctx);
|
|
900
|
+
continue;
|
|
901
|
+
}
|
|
902
|
+
}
|
|
879
903
|
if (ns === "oncapture") {
|
|
880
904
|
const evt = a.name.name.name.toLowerCase();
|
|
881
905
|
const h = attrExprCode(a, ctx) ?? "undefined";
|
|
@@ -884,9 +908,37 @@ function buildProps(attrs, ctx) {
|
|
|
884
908
|
}
|
|
885
909
|
props.push(buildAttr(a, ctx));
|
|
886
910
|
}
|
|
911
|
+
if (classEntries.length > 0) props.push({ name: "classList", kind: "attr", expr: `{ ${classEntries.join(", ")} }`, reactive: false });
|
|
912
|
+
if (styleEntries.length > 0) {
|
|
913
|
+
const entries = `{ ${styleEntries.join(", ")} }`;
|
|
914
|
+
const base = props.findIndex((p) => p.name === "style" && p.kind === "attr");
|
|
915
|
+
if (base === -1) props.push({ name: "style", kind: "attr", expr: entries, reactive: false, ...styleAt ? { at: styleAt } : {} });
|
|
916
|
+
else {
|
|
917
|
+
const prop = props[base];
|
|
918
|
+
const value = prop.literal !== void 0 ? JSON.stringify(prop.literal) : prop.reactive ? `() => ${paren(prop.expr, "arrowBody")}` : prop.expr;
|
|
919
|
+
props[base] = { name: "style", kind: "attr", expr: `[${value}, ${entries}]`, reactive: false, ...prop.at ? { at: prop.at } : {} };
|
|
920
|
+
}
|
|
921
|
+
}
|
|
887
922
|
if (usePairs.length > 0) props.push({ name: "use", kind: "attr", expr: `[${usePairs.join(", ")}]` });
|
|
888
923
|
return props;
|
|
889
924
|
}
|
|
925
|
+
function keyValue(expr, ctx) {
|
|
926
|
+
const code = ctx.code(expr);
|
|
927
|
+
if (!isReactive(expr)) return code;
|
|
928
|
+
const accessor = `() => ${paren(code, "arrowBody")}`;
|
|
929
|
+
const at = posOf(expr, ctx);
|
|
930
|
+
return at ? markHole(accessor, at.line, at.column) : accessor;
|
|
931
|
+
}
|
|
932
|
+
function objectEntries(expr, ctx) {
|
|
933
|
+
if (expr?.type !== "ObjectExpression") return null;
|
|
934
|
+
const entries = [];
|
|
935
|
+
for (const p of expr.properties) {
|
|
936
|
+
if (p.type !== "ObjectProperty") return null;
|
|
937
|
+
const key = p.computed ? `[${ctx.code(p.key)}]` : p.key.type === "Identifier" ? JSON.stringify(p.key.name) : JSON.stringify(String(p.key.value));
|
|
938
|
+
entries.push(`${key}: ${keyValue(p.value, ctx)}`);
|
|
939
|
+
}
|
|
940
|
+
return entries;
|
|
941
|
+
}
|
|
890
942
|
function buildChildren(children, ctx) {
|
|
891
943
|
const out = [];
|
|
892
944
|
for (let i = 0; i < children.length; i++) {
|
|
@@ -914,6 +966,7 @@ function buildChildren(children, ctx) {
|
|
|
914
966
|
});
|
|
915
967
|
}
|
|
916
968
|
} else if (child.type === "JSXElement" || child.type === "JSXFragment") {
|
|
969
|
+
if (ctx.dropStyles?.has(child.start)) continue;
|
|
917
970
|
out.push(buildNode(child, ctx));
|
|
918
971
|
} else if (child.type === "JSXSpreadChild") {
|
|
919
972
|
out.push({ kind: "expr", code: ctx.code(child.expression), reactive: false });
|
|
@@ -983,13 +1036,17 @@ function buildElement(node, ctx, handled) {
|
|
|
983
1036
|
const children = each ? [each] : buildChildren(node.children, ctx);
|
|
984
1037
|
if (tag === CONTAINER) return children.length === 1 ? children[0] : { kind: "fragment", children };
|
|
985
1038
|
const at = ctx.sourceFile && node.loc?.start ? { file: ctx.sourceFile, line: node.loc.start.line, column: node.loc.start.column } : void 0;
|
|
986
|
-
|
|
1039
|
+
const props = buildProps(attributes, ctx, true);
|
|
1040
|
+
const scope = ctx.scopes?.find((s) => node.start >= s.start && node.end <= s.end);
|
|
1041
|
+
if (scope) props.unshift({ name: "data-fx-s", kind: "attr", literal: scope.value });
|
|
1042
|
+
return { kind: "element", tag, svg: SVG_TAGS.has(tag), props, children, static: false, ...at ? { at } : {} };
|
|
987
1043
|
}
|
|
988
1044
|
function buildNode(node, ctx) {
|
|
989
1045
|
if (node.type === "JSXFragment") {
|
|
990
1046
|
return { kind: "fragment", children: buildChildren(node.children, ctx) };
|
|
991
1047
|
}
|
|
992
1048
|
if (directive(node, "if")) return buildIf(node, null, ctx);
|
|
1049
|
+
if (ctx.dropStyles?.has(node.start)) return { kind: "fragment", children: [] };
|
|
993
1050
|
const { tag, component } = tagInfo(node.openingElement.name, ctx);
|
|
994
1051
|
if (!component) return buildElement(node, ctx, []);
|
|
995
1052
|
const props = buildProps(node.openingElement.attributes, ctx);
|