@fluixi/compiler 1.0.0-alpha.82 → 1.0.0-alpha.84
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/dist/analyze/expr-shape.cjs +62 -1
- package/dist/analyze/expr-shape.d.cts +14 -0
- package/dist/analyze/expr-shape.mjs +41 -1
- package/dist/analyze/intrinsics.cjs +80 -1
- package/dist/analyze/intrinsics.d.cts +66 -0
- package/dist/analyze/intrinsics.mjs +59 -1
- package/dist/analyze/paren.cjs +134 -0
- package/dist/analyze/paren.d.cts +23 -0
- package/dist/analyze/paren.d.ts +24 -0
- package/dist/analyze/paren.d.ts.map +1 -0
- package/dist/analyze/paren.js +168 -0
- package/dist/analyze/paren.mjs +113 -0
- package/dist/analyze/props-destructure.cjs +226 -1
- package/dist/analyze/props-destructure.d.cts +83 -0
- package/dist/analyze/props-destructure.mjs +205 -1
- package/dist/analyze/reactive-bindings.cjs +190 -1
- package/dist/analyze/reactive-bindings.d.cts +42 -0
- package/dist/analyze/reactive-bindings.mjs +167 -1
- package/dist/analyze/reactive-expr.cjs +38 -1
- package/dist/analyze/reactive-expr.d.cts +38 -0
- package/dist/analyze/reactive-expr.mjs +17 -1
- package/dist/analyze/static-graph.cjs +811 -0
- package/dist/analyze/static-graph.d.cts +102 -0
- package/dist/analyze/static-graph.d.ts +103 -0
- package/dist/analyze/static-graph.d.ts.map +1 -0
- package/dist/analyze/static-graph.js +869 -0
- package/dist/analyze/static-graph.mjs +793 -0
- package/dist/babel-NRW4EFTG.mjs +636 -0
- package/dist/chunk-3YKZ4GNH.mjs +11 -0
- package/dist/chunk-EZR7NZOY.mjs +1718 -0
- package/dist/chunk-FSSWUXUR.mjs +16 -0
- package/dist/chunk-MJV3UXIL.mjs +158 -0
- package/dist/chunk-R2VHAZAX.mjs +1078 -0
- package/dist/codegen/backend.cjs +18 -1
- package/dist/codegen/backend.d.cts +35 -0
- package/dist/codegen/backends/imperative.cjs +542 -1
- package/dist/codegen/backends/imperative.d.cts +11 -0
- package/dist/codegen/backends/imperative.d.ts.map +1 -1
- package/dist/codegen/backends/imperative.js +68 -13
- package/dist/codegen/backends/imperative.mjs +519 -1
- package/dist/codegen/contract.cjs +52 -1
- package/dist/codegen/contract.d.cts +24 -0
- package/dist/codegen/contract.mjs +31 -1
- package/dist/codegen/partial-template.cjs +176 -1
- package/dist/codegen/partial-template.d.cts +61 -0
- package/dist/codegen/partial-template.mjs +153 -1
- package/dist/codegen/serialize-static.cjs +125 -1
- package/dist/codegen/serialize-static.d.cts +38 -0
- package/dist/codegen/serialize-static.d.ts +16 -0
- package/dist/codegen/serialize-static.d.ts.map +1 -1
- package/dist/codegen/serialize-static.js +25 -0
- package/dist/codegen/serialize-static.mjs +104 -1
- package/dist/frontend/babel/build-ir-lit.cjs +1509 -1
- package/dist/frontend/babel/build-ir-lit.d.cts +26 -0
- package/dist/frontend/babel/build-ir-lit.mjs +1478 -1
- package/dist/frontend/babel/build-ir.cjs +1524 -1
- package/dist/frontend/babel/build-ir.d.cts +35 -0
- package/dist/frontend/babel/build-ir.mjs +1495 -1
- package/dist/frontend/babel/index.cjs +2186 -1
- package/dist/frontend/babel/index.d.cts +33 -0
- package/dist/frontend/babel/index.mjs +2156 -1
- package/dist/frontend/babel/lower-template.cjs +1507 -1
- package/dist/frontend/babel/lower-template.d.cts +23 -0
- package/dist/frontend/babel/lower-template.mjs +1478 -1
- package/dist/frontend/babel/plugin.cjs +2132 -1
- package/dist/frontend/babel/plugin.d.cts +95 -0
- package/dist/frontend/babel/plugin.mjs +2103 -1
- package/dist/frontend/babel/server-functions.cjs +110 -1
- package/dist/frontend/babel/server-functions.d.cts +10 -0
- package/dist/frontend/babel/server-functions.mjs +89 -1
- package/dist/frontend/babel/types.cjs +18 -1
- package/dist/frontend/babel/types.d.cts +33 -0
- package/dist/frontend/types.cjs +18 -1
- package/dist/frontend/types.d.cts +25 -0
- package/dist/frontend/vocabulary.cjs +98 -0
- package/dist/frontend/vocabulary.d.cts +79 -0
- package/dist/frontend/vocabulary.d.ts +80 -0
- package/dist/frontend/vocabulary.d.ts.map +1 -0
- package/dist/frontend/vocabulary.js +124 -0
- package/dist/frontend/vocabulary.mjs +77 -0
- package/dist/index.cjs +1594 -13
- package/dist/index.d.cts +27 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.mjs +1574 -13
- package/dist/integrations.cjs +4307 -25
- package/dist/integrations.d.cts +215 -0
- package/dist/integrations.d.ts +16 -0
- package/dist/integrations.d.ts.map +1 -1
- package/dist/integrations.js +21 -2
- package/dist/integrations.mjs +531 -17
- package/dist/ir/nodes.cjs +18 -1
- package/dist/ir/nodes.d.cts +168 -0
- package/dist/ir/nodes.d.ts +46 -0
- package/dist/ir/nodes.d.ts.map +1 -1
- package/dist/lower/compile-template.cjs +1356 -1
- package/dist/lower/compile-template.d.cts +69 -0
- package/dist/lower/compile-template.d.ts +12 -0
- package/dist/lower/compile-template.d.ts.map +1 -1
- package/dist/lower/compile-template.js +5 -1
- package/dist/lower/compile-template.mjs +1336 -1
- package/dist/lower/jsx.cjs +529 -1
- package/dist/lower/jsx.d.cts +25 -0
- package/dist/lower/jsx.d.ts +2 -0
- package/dist/lower/jsx.d.ts.map +1 -1
- package/dist/lower/jsx.js +27 -4
- package/dist/lower/jsx.mjs +506 -1
- package/dist/lower/template.cjs +1061 -1
- package/dist/lower/template.d.cts +53 -0
- package/dist/lower/template.d.ts +14 -1
- package/dist/lower/template.d.ts.map +1 -1
- package/dist/lower/template.js +106 -19
- package/dist/lower/template.mjs +1042 -1
- package/dist/lower/text.cjs +42 -1
- package/dist/lower/text.d.cts +10 -0
- package/dist/lower/text.mjs +21 -1
- package/dist/optimize/analyze-static.cjs +112 -1
- package/dist/optimize/analyze-static.d.cts +39 -0
- package/dist/optimize/analyze-static.mjs +91 -1
- package/dist/optimize/collapse-strategies.cjs +90 -1
- package/dist/optimize/collapse-strategies.d.cts +30 -0
- package/dist/optimize/collapse-strategies.mjs +67 -1
- package/dist/options.cjs +33 -1
- package/dist/options.d.cts +39 -0
- package/dist/options.mjs +12 -1
- package/dist/resolve/builtins.cjs +73 -1
- package/dist/resolve/builtins.d.cts +68 -0
- package/dist/resolve/builtins.mjs +53 -1
- package/dist/resolve/component-globals.cjs +233 -13
- package/dist/resolve/component-globals.d.cts +80 -0
- package/dist/resolve/component-globals.mjs +210 -13
- package/dist/resolve/component-resolver.cjs +80 -1
- package/dist/resolve/component-resolver.d.cts +68 -0
- package/dist/resolve/component-resolver.mjs +59 -1
- package/dist/resolve/load-directive.cjs +93 -1
- package/dist/resolve/load-directive.d.cts +53 -0
- package/dist/resolve/load-directive.mjs +72 -1
- package/dist/resolve/resolve-ir.cjs +108 -1
- package/dist/resolve/resolve-ir.d.cts +53 -0
- package/dist/resolve/resolve-ir.mjs +85 -1
- package/dist/resolve/write-globals.cjs +318 -13
- package/dist/resolve/write-globals.d.cts +30 -0
- package/dist/resolve/write-globals.mjs +297 -13
- package/dist/server-fns-4ZXN6DYU.mjs +78 -0
- package/dist/server-functions-V6D6DRIA.mjs +82 -0
- package/dist/transform/bindings.cjs +71 -1
- package/dist/transform/bindings.d.cts +16 -0
- package/dist/transform/bindings.mjs +50 -1
- package/dist/transform/index.cjs +2732 -8
- package/dist/transform/index.d.cts +15 -0
- package/dist/transform/index.mjs +3773 -17
- package/dist/transform/intrinsics.cjs +216 -3
- package/dist/transform/intrinsics.d.cts +21 -0
- package/dist/transform/intrinsics.mjs +193 -3
- package/dist/transform/props.cjs +441 -3
- package/dist/transform/props.d.cts +45 -0
- package/dist/transform/props.mjs +1482 -12
- package/dist/transform/server-fn-id.cjs +35 -1
- package/dist/transform/server-fn-id.d.cts +9 -0
- package/dist/transform/server-fn-id.mjs +14 -1
- package/dist/transform/server-fns.cjs +114 -2
- package/dist/transform/server-fns.d.cts +12 -0
- package/dist/transform/server-fns.mjs +1155 -11
- package/dist/transform/source-locations.cjs +330 -0
- package/dist/transform/source-locations.d.cts +43 -0
- package/dist/transform/source-locations.d.ts +44 -0
- package/dist/transform/source-locations.d.ts.map +1 -0
- package/dist/transform/source-locations.js +238 -0
- package/dist/transform/source-locations.mjs +307 -0
- package/dist/transform/templates.cjs +2701 -7
- package/dist/transform/templates.d.cts +69 -0
- package/dist/transform/templates.d.ts +12 -4
- package/dist/transform/templates.d.ts.map +1 -1
- package/dist/transform/templates.js +72 -7
- package/dist/transform/templates.mjs +3743 -16
- package/dist/transform-BT4MMASR.mjs +893 -0
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- package/package.json +6 -5
- package/dist/babel-4JUDAR2G.mjs +0 -1
- package/dist/chunk-3SAEGOMQ.mjs +0 -1
- package/dist/chunk-IBRM4W7I.mjs +0 -10
- package/dist/chunk-OHHZCYIQ.mjs +0 -1
- package/dist/chunk-PVR2SN3B.mjs +0 -1
- package/dist/chunk-QUIYULS2.mjs +0 -1
- package/dist/chunk-YR3SAEO7.mjs +0 -1
- package/dist/server-fns-6QM243HC.mjs +0 -2
- package/dist/server-functions-E3LKCZ4R.mjs +0 -1
- package/dist/transform-5WC4FWJE.mjs +0 -8
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lower a parsed Template AST (`@fluixi/template-parser`) into the host-agnostic IR.
|
|
3
|
+
*
|
|
4
|
+
* No parser in here: the `${…}` holes arrive already described as `TemplateHole`,
|
|
5
|
+
* since reading them means reading JavaScript and that belongs to a front-end.
|
|
6
|
+
*
|
|
7
|
+
* Pipeline: pieces → parseTemplate → Template AST → lowerTemplate → IRNode
|
|
8
|
+
*/
|
|
9
|
+
import { type Piece } from '@fluixi/template-parser';
|
|
10
|
+
import type { HolePosition, IRNode } from '../ir/nodes.cjs';
|
|
11
|
+
/**
|
|
12
|
+
* One `${…}` slot, as the front-end describes it. Conclusions about the
|
|
13
|
+
* expression only — never a syntax tree, or the parser dependency creeps back.
|
|
14
|
+
*/
|
|
15
|
+
export interface TemplateHole {
|
|
16
|
+
/** The expression source, verbatim. Anything nested inside it is already compiled. */
|
|
17
|
+
code: string;
|
|
18
|
+
/** Whether it must be wired reactively (see analyze/reactive-expr.ts). */
|
|
19
|
+
reactive: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Set when the hole is a single-expression arrow — `${item => …}`. `each` turns
|
|
22
|
+
* that into `For`'s render function, so it needs the parameters and the body
|
|
23
|
+
* separately rather than the arrow as written.
|
|
24
|
+
*/
|
|
25
|
+
arrow?: {
|
|
26
|
+
params: string[];
|
|
27
|
+
body: string;
|
|
28
|
+
bodyReactive: boolean;
|
|
29
|
+
};
|
|
30
|
+
/** Whether the hole is an object literal — `class=${{…}}` lowers to classList. */
|
|
31
|
+
object?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Where the `${…}` was written. Only kept when the host asked for source locations.
|
|
34
|
+
*
|
|
35
|
+
* A template is emitted as one overwrite, so every hole in it traces back through the
|
|
36
|
+
* source map to the line the template opens at. Without this, every node a template makes
|
|
37
|
+
* reports that one position.
|
|
38
|
+
*/
|
|
39
|
+
at?: HolePosition;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Lower a parsed template to IR. `pieces` are the static runs and hole slots as
|
|
43
|
+
* the parser wants them; `holes` describes each `${…}` in the same order. `used`
|
|
44
|
+
* collects the runtime symbols the emitted code imports.
|
|
45
|
+
*/
|
|
46
|
+
export declare function lowerTemplate(pieces: Piece[], holes: TemplateHole[], used: Set<string>, opts?: {
|
|
47
|
+
svg?: boolean;
|
|
48
|
+
sourceFile?: string;
|
|
49
|
+
positionAt?: (offset: number) => {
|
|
50
|
+
line: number;
|
|
51
|
+
column: number;
|
|
52
|
+
};
|
|
53
|
+
}): IRNode;
|
package/dist/lower/template.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* Pipeline: pieces → parseTemplate → Template AST → lowerTemplate → IRNode
|
|
8
8
|
*/
|
|
9
9
|
import { type Piece } from '@fluixi/template-parser';
|
|
10
|
-
import type { IRNode } from '../ir/nodes.js';
|
|
10
|
+
import type { HolePosition, IRNode } from '../ir/nodes.js';
|
|
11
11
|
/**
|
|
12
12
|
* One `${…}` slot, as the front-end describes it. Conclusions about the
|
|
13
13
|
* expression only — never a syntax tree, or the parser dependency creeps back.
|
|
@@ -29,6 +29,14 @@ export interface TemplateHole {
|
|
|
29
29
|
};
|
|
30
30
|
/** Whether the hole is an object literal — `class=${{…}}` lowers to classList. */
|
|
31
31
|
object?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Where the `${…}` was written. Only kept when the host asked for source locations.
|
|
34
|
+
*
|
|
35
|
+
* A template is emitted as one overwrite, so every hole in it traces back through the
|
|
36
|
+
* source map to the line the template opens at. Without this, every node a template makes
|
|
37
|
+
* reports that one position.
|
|
38
|
+
*/
|
|
39
|
+
at?: HolePosition;
|
|
32
40
|
}
|
|
33
41
|
/**
|
|
34
42
|
* Lower a parsed template to IR. `pieces` are the static runs and hole slots as
|
|
@@ -37,5 +45,10 @@ export interface TemplateHole {
|
|
|
37
45
|
*/
|
|
38
46
|
export declare function lowerTemplate(pieces: Piece[], holes: TemplateHole[], used: Set<string>, opts?: {
|
|
39
47
|
svg?: boolean;
|
|
48
|
+
sourceFile?: string;
|
|
49
|
+
positionAt?: (offset: number) => {
|
|
50
|
+
line: number;
|
|
51
|
+
column: number;
|
|
52
|
+
};
|
|
40
53
|
}): IRNode;
|
|
41
54
|
//# sourceMappingURL=template.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"template.d.ts","sourceRoot":"","sources":["../../src/lower/template.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAML,KAAK,KAAK,EAGX,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,MAAM,EAAsB,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"template.d.ts","sourceRoot":"","sources":["../../src/lower/template.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAML,KAAK,KAAK,EAGX,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,EAAsB,MAAM,gBAAgB,CAAC;AAM/E;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,sFAAsF;IACtF,IAAI,EAAE,MAAM,CAAC;IACb,0EAA0E;IAC1E,QAAQ,EAAE,OAAO,CAAC;IAClB;;;;OAIG;IACH,KAAK,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,EAAE,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,OAAO,CAAA;KAAE,CAAC;IAClE,kFAAkF;IAClF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;;;;OAMG;IACH,EAAE,CAAC,EAAE,YAAY,CAAC;CACnB;AAmhBD;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,KAAK,EAAE,EACf,KAAK,EAAE,YAAY,EAAE,EACrB,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,EACjB,IAAI,GAAE;IAAE,GAAG,CAAC,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;CAAO,GACnH,MAAM,CAGR"}
|
package/dist/lower/template.js
CHANGED
|
@@ -10,6 +10,7 @@ import { parseTemplate, } from '@fluixi/template-parser';
|
|
|
10
10
|
import { parseLoadDirective } from '../resolve/load-directive.js';
|
|
11
11
|
import { imperativeBackend, inlineTemplates } from '../codegen/backends/imperative.js';
|
|
12
12
|
import { cleanTemplateText } from './text.js';
|
|
13
|
+
import { paren } from '../analyze/paren.js';
|
|
13
14
|
const DELEGATED = new Set([
|
|
14
15
|
'click', 'dblclick', 'input', 'change', 'submit', 'focus', 'blur',
|
|
15
16
|
'keydown', 'keyup', 'keypress', 'mousedown', 'mouseup',
|
|
@@ -24,9 +25,27 @@ function capitalize(s) {
|
|
|
24
25
|
class Lowerer {
|
|
25
26
|
holes;
|
|
26
27
|
used;
|
|
27
|
-
|
|
28
|
+
sourceFile;
|
|
29
|
+
positionAt;
|
|
30
|
+
constructor(holes, used, sourceFile, positionAt) {
|
|
28
31
|
this.holes = holes;
|
|
29
32
|
this.used = used;
|
|
33
|
+
this.sourceFile = sourceFile;
|
|
34
|
+
this.positionAt = positionAt;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Where a tag is written, for the mark a component node carries.
|
|
38
|
+
*
|
|
39
|
+
* The parser reports offsets, and they are offsets into the file: the pieces it was given
|
|
40
|
+
* carry the positions the front-end recorded. Only built when the host asked for source
|
|
41
|
+
* locations, which is the only time either of these is set.
|
|
42
|
+
*/
|
|
43
|
+
tagAt(node) {
|
|
44
|
+
const start = node.loc?.start;
|
|
45
|
+
if (!this.sourceFile || !this.positionAt || start == null)
|
|
46
|
+
return undefined;
|
|
47
|
+
const { line, column } = this.positionAt(start);
|
|
48
|
+
return { file: this.sourceFile, line, column };
|
|
30
49
|
}
|
|
31
50
|
hole(i) {
|
|
32
51
|
// -1 marks a recovered-from missing binding; emit a harmless undefined.
|
|
@@ -95,7 +114,7 @@ class Lowerer {
|
|
|
95
114
|
return null; // dropped, like JSX comments
|
|
96
115
|
case 'Expression': {
|
|
97
116
|
const h = this.hole(node.hole);
|
|
98
|
-
return { kind: 'expr', code: h.code, reactive: h.reactive };
|
|
117
|
+
return { kind: 'expr', code: h.code, reactive: h.reactive, ...(h.at ? { at: h.at } : {}) };
|
|
99
118
|
}
|
|
100
119
|
case 'Fragment':
|
|
101
120
|
return { kind: 'fragment', children: this.lowerChildren(node.children) };
|
|
@@ -115,9 +134,10 @@ class Lowerer {
|
|
|
115
134
|
if (el.tag === 'component' && isAttr && isAttr.value && isAttr.value.kind === 'hole') {
|
|
116
135
|
const rest = el.attributes.filter((a) => a !== isAttr);
|
|
117
136
|
const node = this.lowerComponent({ ...el, kind: 'Component', tag: 'Dynamic', tagHole: null, attributes: rest });
|
|
118
|
-
node.props.unshift({ name: 'component', kind: 'attr', expr: `() =>
|
|
137
|
+
node.props.unshift({ name: 'component', kind: 'attr', expr: `() => ${paren(this.hole(isAttr.value.hole).code, 'arrowBody')}` });
|
|
119
138
|
return node;
|
|
120
139
|
}
|
|
140
|
+
const at = this.tagAt(el);
|
|
121
141
|
return {
|
|
122
142
|
kind: 'element',
|
|
123
143
|
tag: el.tag,
|
|
@@ -125,6 +145,7 @@ class Lowerer {
|
|
|
125
145
|
props: this.lowerAttributes(el.attributes),
|
|
126
146
|
children: this.lowerChildren(el.children),
|
|
127
147
|
static: false,
|
|
148
|
+
...(at ? { at } : {}),
|
|
128
149
|
};
|
|
129
150
|
}
|
|
130
151
|
lowerComponent(el) {
|
|
@@ -160,11 +181,20 @@ class Lowerer {
|
|
|
160
181
|
const load = loadAttr
|
|
161
182
|
? parseLoadDirective(`load:${loadAttr.strategy}`, loadAttr.modifier)
|
|
162
183
|
: undefined;
|
|
184
|
+
// The parser's positions are relative to the template string, not the file, so the
|
|
185
|
+
// tag itself has none to give. The first hole is the closest thing that does, and for
|
|
186
|
+
// the control-flow components — `<Show when=${…}>`, `<For each=${…}>` — it is the
|
|
187
|
+
// expression driving the subtree anyway.
|
|
188
|
+
// A reactive one: a literal carries a position too now, and it drives nothing.
|
|
189
|
+
const bindAt = props.find((p) => p.at && p.reactive)?.at;
|
|
190
|
+
const at = this.tagAt(el);
|
|
163
191
|
return {
|
|
164
192
|
kind: 'component',
|
|
165
193
|
name,
|
|
166
194
|
props,
|
|
167
195
|
children: this.lowerChildren(rest),
|
|
196
|
+
...(at ? { at } : {}),
|
|
197
|
+
...(bindAt ? { bindAt } : {}),
|
|
168
198
|
...(load ? { load } : {}),
|
|
169
199
|
};
|
|
170
200
|
}
|
|
@@ -193,14 +223,15 @@ class Lowerer {
|
|
|
193
223
|
lowerIf(el, condHole, elseEl) {
|
|
194
224
|
const cond = this.hole(condHole);
|
|
195
225
|
const props = [
|
|
196
|
-
{ name: 'when', kind: 'attr', expr: cond.code, reactive: cond.reactive },
|
|
226
|
+
{ name: 'when', kind: 'attr', expr: cond.code, reactive: cond.reactive, ...(cond.at ? { at: cond.at } : {}) },
|
|
197
227
|
];
|
|
198
228
|
if (elseEl) {
|
|
199
229
|
const elseIR = this.stripAndLower(elseEl, (a) => a.kind === 'ElseDirective');
|
|
200
230
|
props.push({ name: 'fallback', kind: 'attr', expr: this.emit(elseIR), jsxElement: true });
|
|
201
231
|
}
|
|
202
232
|
const child = this.stripAndLower(el, (a) => a.kind === 'IfDirective');
|
|
203
|
-
|
|
233
|
+
const at = this.tagAt(el);
|
|
234
|
+
return { kind: 'component', name: 'Show', props, children: [child], ...(at ? { at } : {}), ...(cond.at ? { bindAt: cond.at } : {}) };
|
|
204
235
|
}
|
|
205
236
|
/** `<el each=${items} key?>${item => …}</el>` → `<For each>{item => <el>…</el>}</For>`. */
|
|
206
237
|
lowerEach(el) {
|
|
@@ -208,7 +239,7 @@ class Lowerer {
|
|
|
208
239
|
if (!eachDir || eachDir.kind !== 'EachDirective')
|
|
209
240
|
return this.lowerNode(el);
|
|
210
241
|
const each = this.hole(eachDir.hole);
|
|
211
|
-
const props = [{ name: 'each', kind: 'attr', expr: each.code, reactive: each.reactive }];
|
|
242
|
+
const props = [{ name: 'each', kind: 'attr', expr: each.code, reactive: each.reactive, ...(each.at ? { at: each.at } : {}) }];
|
|
212
243
|
if (eachDir.key) {
|
|
213
244
|
// `<For by>` wants a KEY FUNCTION, not a string. `key="id"` selects the
|
|
214
245
|
// `id` field: `(item) => item["id"]`; `key=${fn}` passes the function.
|
|
@@ -223,14 +254,15 @@ class Lowerer {
|
|
|
223
254
|
if (arrow) {
|
|
224
255
|
const bodyIR = { kind: 'expr', code: arrow.body, reactive: arrow.bodyReactive };
|
|
225
256
|
const repeated = this.rebuildWithChildren(el, [bodyIR]);
|
|
226
|
-
childrenCode = `(${arrow.params.join(', ')}) =>
|
|
257
|
+
childrenCode = `(${arrow.params.join(', ')}) => ${paren(this.emit(repeated), 'arrowBody')}`;
|
|
227
258
|
}
|
|
228
259
|
else {
|
|
229
260
|
const repeated = this.stripAndLower(el, (a) => a.kind === 'EachDirective');
|
|
230
|
-
childrenCode = `() =>
|
|
261
|
+
childrenCode = `() => ${paren(this.emit(repeated), 'arrowBody')}`;
|
|
231
262
|
}
|
|
232
263
|
const children = [{ kind: 'expr', code: childrenCode, reactive: false }];
|
|
233
|
-
|
|
264
|
+
const at = this.tagAt(el);
|
|
265
|
+
return { kind: 'component', name: 'For', props, children, ...(at ? { at } : {}), ...(each.at ? { bindAt: each.at } : {}) };
|
|
234
266
|
}
|
|
235
267
|
/** The single `${item => expr}` child arrow, if that's the element's content. */
|
|
236
268
|
itemArrow(el) {
|
|
@@ -248,7 +280,16 @@ class Lowerer {
|
|
|
248
280
|
rebuildWithChildren(el, children) {
|
|
249
281
|
const props = this.lowerAttributes(el.attributes.filter((a) => a.kind !== 'EachDirective'));
|
|
250
282
|
if (el.kind === 'Element') {
|
|
251
|
-
|
|
283
|
+
const at = this.tagAt(el);
|
|
284
|
+
return {
|
|
285
|
+
kind: 'element',
|
|
286
|
+
tag: el.tag,
|
|
287
|
+
svg: el.namespace === 'svg',
|
|
288
|
+
props,
|
|
289
|
+
children,
|
|
290
|
+
static: false,
|
|
291
|
+
...(at ? { at } : {}),
|
|
292
|
+
};
|
|
252
293
|
}
|
|
253
294
|
return { kind: 'component', name: el.tag, props, children };
|
|
254
295
|
}
|
|
@@ -257,8 +298,10 @@ class Lowerer {
|
|
|
257
298
|
const props = [];
|
|
258
299
|
const classEntries = [];
|
|
259
300
|
let classReactive = false;
|
|
301
|
+
let classAt;
|
|
260
302
|
const styleEntries = [];
|
|
261
303
|
let styleReactive = false;
|
|
304
|
+
let styleAt;
|
|
262
305
|
const usePairs = [];
|
|
263
306
|
for (const a of attrs) {
|
|
264
307
|
switch (a.kind) {
|
|
@@ -270,13 +313,26 @@ class Lowerer {
|
|
|
270
313
|
props.push(this.plainAttr(a));
|
|
271
314
|
break;
|
|
272
315
|
case 'PropertyBinding':
|
|
273
|
-
props.push({
|
|
316
|
+
props.push({
|
|
317
|
+
name: a.name,
|
|
318
|
+
kind: 'prop',
|
|
319
|
+
expr: this.hole(a.hole).code,
|
|
320
|
+
reactive: this.hole(a.hole).reactive,
|
|
321
|
+
...(this.hole(a.hole).at ? { at: this.hole(a.hole).at } : {}),
|
|
322
|
+
});
|
|
274
323
|
break;
|
|
275
324
|
case 'EventBinding':
|
|
276
325
|
props.push(this.eventProp(a));
|
|
277
326
|
break;
|
|
278
327
|
case 'RefBinding':
|
|
279
|
-
props.push({
|
|
328
|
+
props.push({
|
|
329
|
+
name: 'ref',
|
|
330
|
+
kind: 'ref',
|
|
331
|
+
expr: this.hole(a.hole).code,
|
|
332
|
+
reactive: this.hole(a.hole).reactive,
|
|
333
|
+
// Which variable ends up holding the element, and where it was written.
|
|
334
|
+
...(this.hole(a.hole).at ? { at: this.hole(a.hole).at } : {}),
|
|
335
|
+
});
|
|
280
336
|
break;
|
|
281
337
|
case 'Spread':
|
|
282
338
|
props.push({ name: '', kind: 'spread', expr: this.hole(a.hole).code });
|
|
@@ -285,16 +341,18 @@ class Lowerer {
|
|
|
285
341
|
const h = this.hole(a.hole);
|
|
286
342
|
classEntries.push(`${JSON.stringify(a.name)}: ${h.code}`);
|
|
287
343
|
classReactive = classReactive || h.reactive;
|
|
344
|
+
classAt ??= h.at;
|
|
288
345
|
break;
|
|
289
346
|
}
|
|
290
347
|
case 'StyleDirective': {
|
|
291
348
|
const h = this.hole(a.hole);
|
|
292
349
|
styleEntries.push(`${JSON.stringify(a.name)}: ${h.code}`);
|
|
293
350
|
styleReactive = styleReactive || h.reactive;
|
|
351
|
+
styleAt ??= h.at;
|
|
294
352
|
break;
|
|
295
353
|
}
|
|
296
354
|
case 'BindDirective':
|
|
297
|
-
props.push(...this.bindProps(a.name, this.hole(a.hole)
|
|
355
|
+
props.push(...this.bindProps(a.name, this.hole(a.hole)));
|
|
298
356
|
break;
|
|
299
357
|
case 'UseDirective': {
|
|
300
358
|
// `use=${dir}` → [dir]; `use:name` → [name]; `use:name=${opts}` →
|
|
@@ -303,18 +361,33 @@ class Lowerer {
|
|
|
303
361
|
if (!dir)
|
|
304
362
|
break;
|
|
305
363
|
// parens so an object literal opts isn't read as a block body
|
|
306
|
-
usePairs.push(a.name != null && a.hole != null ? `[${dir}, () =>
|
|
364
|
+
usePairs.push(a.name != null && a.hole != null ? `[${dir}, () => ${paren(this.hole(a.hole).code, 'arrowBody')}]` : `[${dir}]`);
|
|
307
365
|
break;
|
|
308
366
|
}
|
|
309
367
|
}
|
|
310
368
|
}
|
|
311
369
|
// Merge all class:/style: directives into one classList/style prop so they
|
|
312
370
|
// don't collide as duplicate keys in the emitted props object.
|
|
371
|
+
// One prop covers every directive of its kind, so it carries the first hole's
|
|
372
|
+
// position — a real source line beats the stack fallback, which lands in the
|
|
373
|
+
// compiled file.
|
|
313
374
|
if (classEntries.length > 0) {
|
|
314
|
-
props.push({
|
|
375
|
+
props.push({
|
|
376
|
+
name: 'classList',
|
|
377
|
+
kind: 'attr',
|
|
378
|
+
expr: `{ ${classEntries.join(', ')} }`,
|
|
379
|
+
reactive: classReactive,
|
|
380
|
+
...(classAt ? { at: classAt } : {}),
|
|
381
|
+
});
|
|
315
382
|
}
|
|
316
383
|
if (styleEntries.length > 0) {
|
|
317
|
-
props.push({
|
|
384
|
+
props.push({
|
|
385
|
+
name: 'style',
|
|
386
|
+
kind: 'attr',
|
|
387
|
+
expr: `{ ${styleEntries.join(', ')} }`,
|
|
388
|
+
reactive: styleReactive,
|
|
389
|
+
...(styleAt ? { at: styleAt } : {}),
|
|
390
|
+
});
|
|
318
391
|
}
|
|
319
392
|
// All use: directives normalize to one `use` prop = an array of [dir, accessor?] pairs.
|
|
320
393
|
if (usePairs.length > 0) {
|
|
@@ -369,7 +442,8 @@ class Lowerer {
|
|
|
369
442
|
return opts.length ? `{ ${opts.join(', ')} }` : null;
|
|
370
443
|
}
|
|
371
444
|
/** `bind:value=${sig}` → `value={read()}` + `onInput={e => write(e…value)}`. */
|
|
372
|
-
bindProps(prop,
|
|
445
|
+
bindProps(prop, h) {
|
|
446
|
+
const sigCode = h.code;
|
|
373
447
|
const checked = prop === 'checked';
|
|
374
448
|
const evt = checked ? 'change' : 'input';
|
|
375
449
|
const accessor = checked ? 'checked' : 'value';
|
|
@@ -380,7 +454,14 @@ class Lowerer {
|
|
|
380
454
|
this.used.add('bindPair');
|
|
381
455
|
const sig = `bindPair(${sigCode})`;
|
|
382
456
|
return [
|
|
383
|
-
{
|
|
457
|
+
{
|
|
458
|
+
name: prop,
|
|
459
|
+
kind: 'attr',
|
|
460
|
+
expr: `${sig}[0]()`,
|
|
461
|
+
reactive: true,
|
|
462
|
+
directive: `bind:${prop}`,
|
|
463
|
+
...(h.at ? { at: h.at } : {}),
|
|
464
|
+
},
|
|
384
465
|
{
|
|
385
466
|
name: 'on' + capitalize(evt),
|
|
386
467
|
kind: 'event',
|
|
@@ -418,21 +499,27 @@ class Lowerer {
|
|
|
418
499
|
const h = this.hole(v.hole);
|
|
419
500
|
base.expr = h.code;
|
|
420
501
|
base.reactive = h.reactive;
|
|
502
|
+
if (h.at)
|
|
503
|
+
base.at = h.at;
|
|
421
504
|
return base;
|
|
422
505
|
}
|
|
423
506
|
// mixed: template literal, reactive if any hole is
|
|
424
507
|
let reactive = false;
|
|
508
|
+
let at;
|
|
425
509
|
const body = v.parts
|
|
426
510
|
.map((p) => {
|
|
427
511
|
if ('text' in p)
|
|
428
512
|
return escapeTemplate(p.text);
|
|
429
513
|
const h = this.hole(p.hole);
|
|
430
514
|
reactive = reactive || h.reactive;
|
|
515
|
+
at ??= h.at;
|
|
431
516
|
return '${' + h.code + '}';
|
|
432
517
|
})
|
|
433
518
|
.join('');
|
|
434
519
|
base.expr = '`' + body + '`';
|
|
435
520
|
base.reactive = reactive;
|
|
521
|
+
if (at)
|
|
522
|
+
base.at = at;
|
|
436
523
|
return base;
|
|
437
524
|
}
|
|
438
525
|
}
|
|
@@ -443,5 +530,5 @@ class Lowerer {
|
|
|
443
530
|
*/
|
|
444
531
|
export function lowerTemplate(pieces, holes, used, opts = {}) {
|
|
445
532
|
const { root } = parseTemplate(pieces, { svg: opts.svg });
|
|
446
|
-
return new Lowerer(holes, used).lowerRoot(root.children);
|
|
533
|
+
return new Lowerer(holes, used, opts.sourceFile, opts.positionAt).lowerRoot(root.children);
|
|
447
534
|
}
|