@fluixi/compiler 1.0.0-alpha.69 → 1.0.0-alpha.71
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/babel-DFIRSRWC.mjs +2 -0
- package/dist/chunk-EF6V4GTD.mjs +1 -0
- package/dist/codegen/backend.cjs +1 -1
- package/dist/codegen/backend.d.ts +14 -0
- package/dist/codegen/backend.d.ts.map +1 -1
- package/dist/codegen/backends/imperative.cjs +1 -1
- package/dist/codegen/backends/imperative.d.ts +10 -1
- package/dist/codegen/backends/imperative.d.ts.map +1 -1
- package/dist/codegen/backends/imperative.js +127 -16
- package/dist/codegen/backends/imperative.mjs +1 -1
- package/dist/codegen/partial-template.cjs +1 -0
- package/dist/codegen/partial-template.d.ts +62 -0
- package/dist/codegen/partial-template.d.ts.map +1 -0
- package/dist/codegen/partial-template.js +0 -0
- package/dist/codegen/partial-template.mjs +1 -0
- package/dist/codegen/serialize-static.cjs +1 -0
- package/dist/codegen/serialize-static.d.ts +23 -0
- package/dist/codegen/serialize-static.d.ts.map +1 -0
- package/dist/codegen/serialize-static.js +140 -0
- package/dist/codegen/serialize-static.mjs +1 -0
- package/dist/frontend/babel/build-ir-lit.cjs +1 -1
- package/dist/frontend/babel/build-ir-lit.d.ts.map +1 -1
- package/dist/frontend/babel/build-ir-lit.js +5 -1
- package/dist/frontend/babel/build-ir-lit.mjs +1 -1
- package/dist/frontend/babel/build-ir.cjs +1 -1
- package/dist/frontend/babel/build-ir.d.ts.map +1 -1
- package/dist/frontend/babel/build-ir.js +36 -8
- package/dist/frontend/babel/build-ir.mjs +1 -1
- package/dist/frontend/babel/index.cjs +2 -2
- package/dist/frontend/babel/index.mjs +2 -2
- package/dist/frontend/babel/lower-template.cjs +1 -1
- package/dist/frontend/babel/lower-template.d.ts.map +1 -1
- package/dist/frontend/babel/lower-template.js +34 -5
- package/dist/frontend/babel/lower-template.mjs +1 -1
- package/dist/frontend/babel/plugin.cjs +2 -2
- package/dist/frontend/babel/plugin.d.ts +4 -0
- package/dist/frontend/babel/plugin.d.ts.map +1 -1
- package/dist/frontend/babel/plugin.js +276 -50
- package/dist/frontend/babel/plugin.mjs +2 -2
- package/dist/index.cjs +22 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.mjs +22 -1
- package/dist/integrations.cjs +29 -8
- package/dist/integrations.d.ts +22 -0
- package/dist/integrations.d.ts.map +1 -1
- package/dist/integrations.js +14 -0
- package/dist/integrations.mjs +26 -5
- package/dist/ir/nodes.cjs +1 -1
- package/dist/ir/nodes.d.ts +43 -0
- package/dist/ir/nodes.d.ts.map +1 -1
- package/dist/optimize/analyze-static.cjs +1 -0
- package/dist/optimize/analyze-static.d.ts +40 -0
- package/dist/optimize/analyze-static.d.ts.map +1 -0
- package/dist/optimize/analyze-static.js +131 -0
- package/dist/optimize/analyze-static.mjs +1 -0
- package/dist/optimize/collapse-strategies.cjs +1 -0
- package/dist/optimize/collapse-strategies.d.ts +31 -0
- package/dist/optimize/collapse-strategies.d.ts.map +1 -0
- package/dist/optimize/collapse-strategies.js +33 -0
- package/dist/optimize/collapse-strategies.mjs +1 -0
- package/dist/options.cjs +1 -1
- package/dist/options.d.ts +18 -0
- package/dist/options.d.ts.map +1 -1
- package/dist/resolve/builtins.cjs +1 -0
- package/dist/resolve/builtins.d.ts +69 -0
- package/dist/resolve/builtins.d.ts.map +1 -0
- package/dist/resolve/builtins.js +64 -0
- package/dist/resolve/builtins.mjs +1 -0
- package/dist/resolve/component-globals.cjs +22 -0
- package/dist/resolve/component-globals.d.ts +73 -0
- package/dist/resolve/component-globals.d.ts.map +1 -0
- package/dist/resolve/component-globals.js +137 -0
- package/dist/resolve/component-globals.mjs +22 -0
- package/dist/resolve/load-directive.cjs +1 -0
- package/dist/resolve/load-directive.d.ts +54 -0
- package/dist/resolve/load-directive.d.ts.map +1 -0
- package/dist/resolve/load-directive.js +93 -0
- package/dist/resolve/load-directive.mjs +1 -0
- package/dist/resolve/resolve-ir.cjs +1 -0
- package/dist/resolve/resolve-ir.d.ts +54 -0
- package/dist/resolve/resolve-ir.d.ts.map +1 -0
- package/dist/resolve/resolve-ir.js +58 -0
- package/dist/resolve/resolve-ir.mjs +1 -0
- package/dist/resolve/write-globals.cjs +22 -0
- package/dist/resolve/write-globals.d.ts +31 -0
- package/dist/resolve/write-globals.d.ts.map +1 -0
- package/dist/resolve/write-globals.js +136 -0
- package/dist/resolve/write-globals.mjs +22 -0
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/dist/babel-UKVEBBZL.mjs +0 -2
- package/dist/chunk-3SAEGOMQ.mjs +0 -1
package/dist/ir/nodes.d.ts
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
* between parsing and code generation — the layer your own improvements
|
|
5
5
|
* (hoisting, islands, resumability hints) transform.
|
|
6
6
|
*/
|
|
7
|
+
import type { IRLoadStrategy } from '../resolve/load-directive.js';
|
|
8
|
+
export type { IRLoadStrategy };
|
|
7
9
|
export interface SourceSpan {
|
|
8
10
|
start: number;
|
|
9
11
|
end: number;
|
|
@@ -46,11 +48,52 @@ export interface IRElement {
|
|
|
46
48
|
static: boolean;
|
|
47
49
|
loc?: SourceSpan;
|
|
48
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* Where a component reference comes from, attached to the reference itself.
|
|
53
|
+
*
|
|
54
|
+
* A capitalised tag with no binding in the file is supplied by the compiler — from a
|
|
55
|
+
* `resolve` rule, or from the built-in control-flow/router sets. That decision used to
|
|
56
|
+
* live only in the Babel plugin's state, which meant the IR could not see which
|
|
57
|
+
* components a template referenced: no pass could vary a decision per usage, group
|
|
58
|
+
* references into chunks, or drop a subtree it knows is server-only. Recording it on
|
|
59
|
+
* the node is what turns resolution from a convenience into something later passes can
|
|
60
|
+
* read.
|
|
61
|
+
*
|
|
62
|
+
* `origin` distinguishes the two suppliers because they behave differently: a `rule`
|
|
63
|
+
* is configuration and may be overridden or re-targeted, while a `builtin` control-flow
|
|
64
|
+
* name also selects codegen and cannot be re-pointed at another module.
|
|
65
|
+
*/
|
|
66
|
+
export interface IRComponentSource {
|
|
67
|
+
module: string;
|
|
68
|
+
/** The export to import, or `default`. */
|
|
69
|
+
export: string;
|
|
70
|
+
origin: 'rule' | 'builtin';
|
|
71
|
+
/**
|
|
72
|
+
* When the module is fetched. Set from a `load:` directive at the usage site, and
|
|
73
|
+
* `eager` otherwise — resolution decides where a component comes from, this decides
|
|
74
|
+
* when, and the two vary independently.
|
|
75
|
+
*/
|
|
76
|
+
loading: IRLoadStrategy;
|
|
77
|
+
/** Assigned by the optimizer once references are grouped. */
|
|
78
|
+
chunk?: string;
|
|
79
|
+
}
|
|
49
80
|
export interface IRComponent {
|
|
50
81
|
kind: 'component';
|
|
51
82
|
name: string;
|
|
52
83
|
props: IRProp[];
|
|
53
84
|
children: IRNode[];
|
|
85
|
+
/**
|
|
86
|
+
* Set by the resolve pass when the compiler supplies this reference. Absent when the
|
|
87
|
+
* name is bound in the file — an ordinary import the author wrote — or when nothing
|
|
88
|
+
* claims it, which is a diagnostic rather than a resolution.
|
|
89
|
+
*/
|
|
90
|
+
source?: IRComponentSource;
|
|
91
|
+
/**
|
|
92
|
+
* A `load:` strategy read off the tag by the frontend. The resolve pass folds it into
|
|
93
|
+
* `source.loading`; it lives here first because the frontend knows the directive and
|
|
94
|
+
* the resolve pass knows whether the name is deferrable at all.
|
|
95
|
+
*/
|
|
96
|
+
load?: IRLoadStrategy;
|
|
54
97
|
loc?: SourceSpan;
|
|
55
98
|
}
|
|
56
99
|
export interface IRText {
|
package/dist/ir/nodes.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nodes.d.ts","sourceRoot":"","sources":["../../src/ir/nodes.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IAAG,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;CAAE;AAE3D,MAAM,MAAM,MAAM,GACd,SAAS,GACT,WAAW,GACX,MAAM,GACN,YAAY,GACZ,SAAS,GACT,UAAU,CAAC;AAEf,MAAM,MAAM,UAAU,GAClB,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,CAAC;AAErE,MAAM,WAAW,MAAM;IACrB,4FAA4F;IAC5F,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,UAAU,CAAC;IACjB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;IAC3C,iEAAiE;IACjE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oFAAoF;IACpF,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,sEAAsE;IACtE,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC;CAC9C;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,SAAS,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,OAAO,CAAC;IACb,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,iFAAiF;IACjF,MAAM,EAAE,OAAO,CAAC;IAChB,GAAG,CAAC,EAAE,UAAU,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,GAAG,CAAC,EAAE,UAAU,CAAC;CAClB;AAED,MAAM,WAAW,MAAM;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,UAAU,CAAC;CAAE;AAE1E,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,GAAG,CAAC,EAAE,UAAU,CAAC;CAClB;AAED,MAAM,WAAW,UAAU;IAAG,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAC;IAAC,GAAG,CAAC,EAAE,UAAU,CAAC;CAAE;AAEvF,MAAM,MAAM,WAAW,GACnB,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,GAC7C,SAAS,GAAG,eAAe,GAAG,UAAU,CAAC;AAE7C,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,WAAW,CAAC;IACrB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,GAAG,CAAC,EAAE,UAAU,CAAC;CAClB"}
|
|
1
|
+
{"version":3,"file":"nodes.d.ts","sourceRoot":"","sources":["../../src/ir/nodes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var a=Object.defineProperty;var l=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var p=Object.prototype.hasOwnProperty;var d=(r,e)=>{for(var s in e)a(r,s,{get:e[s],enumerable:!0})},u=(r,e,s,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let t of f(e))!p.call(r,t)&&t!==s&&a(r,t,{get:()=>e[t],enumerable:!(n=l(e,t))||n.enumerable});return r};var R=r=>u(a({},"__esModule",{value:!0}),r);var y={};d(y,{analyzeStatic:()=>m,staticRoots:()=>x});module.exports=R(y);function h(r){switch(r.kind){case"event":return"event";case"ref":return"ref";case"spread":return"spread";case"class":case"style":return"class-or-style-directive";case"attr":case"prop":return r.reactive?"reactive-prop":r.expr!==void 0?"expression-prop":void 0;default:return"expression-prop"}}function m(r){let e=[],s=new Map,n=t=>{switch(t.kind){case"text":return!0;case"expr":return!1;case"component":case"control":for(let i of t.children)n(i);return!1;case"fragment":for(let i of t.children)n(i);return!1;case"element":{let i=!0;for(let o of t.children)n(o)||(i=!1);let c;for(let o of t.props)if(c=h(o),c)break;return!c&&!i&&(c=I(t)),t.static=!c,c?s.set(t,c):e.push(t),t.static}default:return!1}};for(let t of Array.isArray(r)?r:[r])n(t);return{staticElements:e,reasons:s}}function I(r){for(let e of r.children){if(e.kind==="expr")return"expression-child";if(e.kind==="component")return"component-child";if(e.kind==="control")return"control-child";if(e.kind==="element"&&!e.static||e.kind==="fragment")return"expression-child"}return"expression-child"}function x(r){let e=[],s=n=>{if(n.kind==="element"&&n.static){e.push(n);return}let t=n.children;if(t)for(let i of t)s(i)};for(let n of Array.isArray(r)?r:[r])s(n);return e}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Static analysis: mark the element subtrees that never change after creation.
|
|
3
|
+
*
|
|
4
|
+
* A static subtree can be built once as an HTML string and cloned per instance, instead
|
|
5
|
+
* of constructed an element at a time. That is the difference between one `cloneNode`
|
|
6
|
+
* and N `createElement` + N `spread` calls — measured at 2.1x faster for a three-element
|
|
7
|
+
* row and 2.4x for a nine-element card, with the gap widening as components grow.
|
|
8
|
+
*
|
|
9
|
+
* `IRElement.static` has existed since the IR was written, documented as
|
|
10
|
+
* "subtree has no dynamic parts → hoistable (template-clone)", but was hardcoded `false`
|
|
11
|
+
* with no producer. This is the producer.
|
|
12
|
+
*
|
|
13
|
+
* The analysis is deliberately conservative: marking something static that is not is a
|
|
14
|
+
* correctness bug (a shared DOM node across renders), while missing one is only a lost
|
|
15
|
+
* optimisation. Anything not positively known to be inert makes its whole ancestry
|
|
16
|
+
* dynamic.
|
|
17
|
+
*/
|
|
18
|
+
import type { IRNode, IRElement } from '../ir/nodes.js';
|
|
19
|
+
/** Why a subtree could not be treated as static. Useful for diagnostics and tests. */
|
|
20
|
+
export type DynamicReason = 'reactive-prop' | 'expression-prop' | 'event' | 'ref' | 'spread' | 'class-or-style-directive' | 'expression-child' | 'component-child' | 'control-child';
|
|
21
|
+
export interface StaticReport {
|
|
22
|
+
/** Elements marked static, in visit order. */
|
|
23
|
+
staticElements: IRElement[];
|
|
24
|
+
/** Why each non-static element was rejected, keyed by the element node. */
|
|
25
|
+
reasons: Map<IRElement, DynamicReason>;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Mark every static element in the tree, returning what was decided.
|
|
29
|
+
*
|
|
30
|
+
* Mutates `IRElement.static` in place, since that field is the contract codegen reads.
|
|
31
|
+
*/
|
|
32
|
+
export declare function analyzeStatic(root: IRNode | IRNode[]): StaticReport;
|
|
33
|
+
/**
|
|
34
|
+
* The outermost static elements — the roots worth turning into templates.
|
|
35
|
+
*
|
|
36
|
+
* Cloning a static child of a static parent is wasted: the parent's template already
|
|
37
|
+
* contains it.
|
|
38
|
+
*/
|
|
39
|
+
export declare function staticRoots(root: IRNode | IRNode[]): IRElement[];
|
|
40
|
+
//# sourceMappingURL=analyze-static.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyze-static.d.ts","sourceRoot":"","sources":["../../src/optimize/analyze-static.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,SAAS,EAAU,MAAM,gBAAgB,CAAC;AAEhE,sFAAsF;AACtF,MAAM,MAAM,aAAa,GACrB,eAAe,GACf,iBAAiB,GACjB,OAAO,GACP,KAAK,GACL,QAAQ,GACR,0BAA0B,GAC1B,kBAAkB,GAClB,iBAAiB,GACjB,eAAe,CAAC;AAEpB,MAAM,WAAW,YAAY;IAC3B,8CAA8C;IAC9C,cAAc,EAAE,SAAS,EAAE,CAAC;IAC5B,2EAA2E;IAC3E,OAAO,EAAE,GAAG,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;CACxC;AA+BD;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,YAAY,CA2DnE;AAeD;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,EAAE,CAchE"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A prop is inert only when it is a plain attribute or property with a literal value.
|
|
3
|
+
*
|
|
4
|
+
* `expr` means arbitrary JS, which may read a signal or allocate, so it is dynamic even
|
|
5
|
+
* when `reactive` is false — a non-reactive expression still has to run per instance.
|
|
6
|
+
*/
|
|
7
|
+
function propReason(prop) {
|
|
8
|
+
switch (prop.kind) {
|
|
9
|
+
case 'event':
|
|
10
|
+
return 'event';
|
|
11
|
+
case 'ref':
|
|
12
|
+
return 'ref';
|
|
13
|
+
case 'spread':
|
|
14
|
+
return 'spread';
|
|
15
|
+
case 'class':
|
|
16
|
+
case 'style':
|
|
17
|
+
// classList/style objects are built from expressions even when they look literal.
|
|
18
|
+
return 'class-or-style-directive';
|
|
19
|
+
case 'attr':
|
|
20
|
+
case 'prop':
|
|
21
|
+
if (prop.reactive)
|
|
22
|
+
return 'reactive-prop';
|
|
23
|
+
if (prop.expr !== undefined)
|
|
24
|
+
return 'expression-prop';
|
|
25
|
+
return undefined;
|
|
26
|
+
/* c8 ignore next 2 */
|
|
27
|
+
default:
|
|
28
|
+
return 'expression-prop';
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Mark every static element in the tree, returning what was decided.
|
|
33
|
+
*
|
|
34
|
+
* Mutates `IRElement.static` in place, since that field is the contract codegen reads.
|
|
35
|
+
*/
|
|
36
|
+
export function analyzeStatic(root) {
|
|
37
|
+
const staticElements = [];
|
|
38
|
+
const reasons = new Map();
|
|
39
|
+
/** Returns whether `node` is static, marking elements bottom-up. */
|
|
40
|
+
const visit = (node) => {
|
|
41
|
+
switch (node.kind) {
|
|
42
|
+
case 'text':
|
|
43
|
+
return true;
|
|
44
|
+
case 'expr':
|
|
45
|
+
// A hole is dynamic even when it is not reactive: its value is computed.
|
|
46
|
+
return false;
|
|
47
|
+
case 'component':
|
|
48
|
+
case 'control':
|
|
49
|
+
// Both produce their own subtree at runtime, so an ancestor cannot be cloned
|
|
50
|
+
// wholesale. Still walk in, so nested elements are marked for their own sake.
|
|
51
|
+
for (const child of node.children)
|
|
52
|
+
visit(child);
|
|
53
|
+
return false;
|
|
54
|
+
case 'fragment':
|
|
55
|
+
// A fragment is not an element and cannot itself be cloned, but its children
|
|
56
|
+
// can be considered independently.
|
|
57
|
+
for (const child of node.children)
|
|
58
|
+
visit(child);
|
|
59
|
+
return false;
|
|
60
|
+
case 'element': {
|
|
61
|
+
// Children are visited first and unconditionally, so a static subtree nested
|
|
62
|
+
// under a dynamic parent is still marked and can be cloned on its own.
|
|
63
|
+
let childrenStatic = true;
|
|
64
|
+
for (const child of node.children) {
|
|
65
|
+
if (!visit(child))
|
|
66
|
+
childrenStatic = false;
|
|
67
|
+
}
|
|
68
|
+
let reason;
|
|
69
|
+
for (const prop of node.props) {
|
|
70
|
+
reason = propReason(prop);
|
|
71
|
+
if (reason)
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
if (!reason && !childrenStatic) {
|
|
75
|
+
reason = childReason(node);
|
|
76
|
+
}
|
|
77
|
+
node.static = !reason;
|
|
78
|
+
if (reason)
|
|
79
|
+
reasons.set(node, reason);
|
|
80
|
+
else
|
|
81
|
+
staticElements.push(node);
|
|
82
|
+
return node.static;
|
|
83
|
+
}
|
|
84
|
+
/* c8 ignore next 2 */
|
|
85
|
+
default:
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
for (const node of Array.isArray(root) ? root : [root])
|
|
90
|
+
visit(node);
|
|
91
|
+
return { staticElements, reasons };
|
|
92
|
+
}
|
|
93
|
+
/** The most specific reason a child made its parent dynamic. */
|
|
94
|
+
function childReason(node) {
|
|
95
|
+
for (const child of node.children) {
|
|
96
|
+
if (child.kind === 'expr')
|
|
97
|
+
return 'expression-child';
|
|
98
|
+
if (child.kind === 'component')
|
|
99
|
+
return 'component-child';
|
|
100
|
+
if (child.kind === 'control')
|
|
101
|
+
return 'control-child';
|
|
102
|
+
if (child.kind === 'element' && !child.static)
|
|
103
|
+
return 'expression-child';
|
|
104
|
+
if (child.kind === 'fragment')
|
|
105
|
+
return 'expression-child';
|
|
106
|
+
}
|
|
107
|
+
/* c8 ignore next */
|
|
108
|
+
return 'expression-child';
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* The outermost static elements — the roots worth turning into templates.
|
|
112
|
+
*
|
|
113
|
+
* Cloning a static child of a static parent is wasted: the parent's template already
|
|
114
|
+
* contains it.
|
|
115
|
+
*/
|
|
116
|
+
export function staticRoots(root) {
|
|
117
|
+
const roots = [];
|
|
118
|
+
const visit = (node) => {
|
|
119
|
+
if (node.kind === 'element' && node.static) {
|
|
120
|
+
roots.push(node);
|
|
121
|
+
return; // its subtree is inside this template
|
|
122
|
+
}
|
|
123
|
+
const children = node.children;
|
|
124
|
+
if (children)
|
|
125
|
+
for (const child of children)
|
|
126
|
+
visit(child);
|
|
127
|
+
};
|
|
128
|
+
for (const node of Array.isArray(root) ? root : [root])
|
|
129
|
+
visit(node);
|
|
130
|
+
return roots;
|
|
131
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function a(r){switch(r.kind){case"event":return"event";case"ref":return"ref";case"spread":return"spread";case"class":case"style":return"class-or-style-directive";case"attr":case"prop":return r.reactive?"reactive-prop":r.expr!==void 0?"expression-prop":void 0;default:return"expression-prop"}}function f(r){let t=[],c=new Map,n=e=>{switch(e.kind){case"text":return!0;case"expr":return!1;case"component":case"control":for(let s of e.children)n(s);return!1;case"fragment":for(let s of e.children)n(s);return!1;case"element":{let s=!0;for(let o of e.children)n(o)||(s=!1);let i;for(let o of e.props)if(i=a(o),i)break;return!i&&!s&&(i=l(e)),e.static=!i,i?c.set(e,i):t.push(e),e.static}default:return!1}};for(let e of Array.isArray(r)?r:[r])n(e);return{staticElements:t,reasons:c}}function l(r){for(let t of r.children){if(t.kind==="expr")return"expression-child";if(t.kind==="component")return"component-child";if(t.kind==="control")return"control-child";if(t.kind==="element"&&!t.static||t.kind==="fragment")return"expression-child"}return"expression-child"}function p(r){let t=[],c=n=>{if(n.kind==="element"&&n.static){t.push(n);return}let e=n.children;if(e)for(let s of e)c(s)};for(let n of Array.isArray(r)?r:[r])c(n);return t}export{f as analyzeStatic,p as staticRoots};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var d=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var R=Object.prototype.hasOwnProperty;var x=(e,o)=>{for(var t in o)d(e,t,{get:o[t],enumerable:!0})},v=(e,o,t,i)=>{if(o&&typeof o=="object"||typeof o=="function")for(let n of g(o))!R.call(e,n)&&n!==t&&d(e,n,{get:()=>o[n],enumerable:!(i=f(o,n))||i.enumerable});return e};var S=e=>v(d({},"__esModule",{value:!0}),e);var E={};x(E,{collapseStrategies:()=>I});module.exports=S(E);function l(e){return e.kind!=="eager"&&e.kind!=="never"}var u=["Show","For","Index","Switch","Match","Portal","Dynamic","ErrorBoundary"],p=["Suspense","SuspenseList","Await"],m=["Router","Outlet","Redirect","Link"],O=[...u,...p,...m],C=new Set([...u,...p]);function c(e,o){let t=Array.isArray(e)?e:[e];for(let i of t){o(i);let n=i.children;n&&c(n,o)}}function I(e){let o=[];c(e,r=>{r.kind==="component"&&r.source&&o.push(r)});let t=new Set,i=new Set;for(let r of o){let{module:s,loading:a}=r.source;a.kind==="eager"&&t.add(s),a.kind==="never"&&i.add(s)}let n=new Map;for(let r of o){let s=r.source;l(s.loading)&&t.has(s.module)&&(s.loading={kind:"eager"},n.set(s.module,(n.get(s.module)??0)+1))}return{collapsed:n,conflicted:[...i].filter(r=>t.has(r))}}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Strategy collapsing — demote a deferred reference whose module is already present.
|
|
3
|
+
*
|
|
4
|
+
* This is not a nice-to-have. Without it the naive feature is a regression: if a module
|
|
5
|
+
* is referenced eagerly anywhere in the compilation unit, it is in the parent chunk
|
|
6
|
+
* already, so a `load:visible` boundary elsewhere adds a wrapper, a promise and a
|
|
7
|
+
* re-render in order to fetch nothing. The bytes are paid twice — once in the chunk,
|
|
8
|
+
* once in the deferral machinery — and the component renders later than it needs to.
|
|
9
|
+
*
|
|
10
|
+
* Collapsing runs per module, not per component name, because a chunk is a module:
|
|
11
|
+
* `<Button>` eager and `<ButtonGroup load:visible>` from the same package means the
|
|
12
|
+
* package is already loaded, so deferring the second buys nothing.
|
|
13
|
+
*
|
|
14
|
+
* `never` is not collapsed. It means "no client code at all", which is a statement about
|
|
15
|
+
* what should exist rather than about when to fetch it; an eager sibling does not make a
|
|
16
|
+
* server-only component suddenly belong in the client bundle. That combination is
|
|
17
|
+
* contradictory and reported instead.
|
|
18
|
+
*/
|
|
19
|
+
import type { IRNode } from '../ir/nodes.js';
|
|
20
|
+
export interface CollapseReport {
|
|
21
|
+
/** Modules demoted to eager, with the reference count that was demoted. */
|
|
22
|
+
collapsed: Map<string, number>;
|
|
23
|
+
/**
|
|
24
|
+
* Modules referenced both as `load:never` and in a way that needs client code.
|
|
25
|
+
* Contradictory rather than optimisable, so it is reported and left alone.
|
|
26
|
+
*/
|
|
27
|
+
conflicted: string[];
|
|
28
|
+
}
|
|
29
|
+
/** Demote deferred references to modules that are already in the chunk. */
|
|
30
|
+
export declare function collapseStrategies(root: IRNode | IRNode[]): CollapseReport;
|
|
31
|
+
//# sourceMappingURL=collapse-strategies.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collapse-strategies.d.ts","sourceRoot":"","sources":["../../src/optimize/collapse-strategies.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,KAAK,EAAE,MAAM,EAAe,MAAM,gBAAgB,CAAC;AAI1D,MAAM,WAAW,cAAc;IAC7B,2EAA2E;IAC3E,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B;;;OAGG;IACH,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,2EAA2E;AAC3E,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,cAAc,CA2B1E"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { isDeferred } from '../resolve/load-directive.js';
|
|
2
|
+
import { walk } from '../resolve/resolve-ir.js';
|
|
3
|
+
/** Demote deferred references to modules that are already in the chunk. */
|
|
4
|
+
export function collapseStrategies(root) {
|
|
5
|
+
const components = [];
|
|
6
|
+
walk(root, (node) => {
|
|
7
|
+
if (node.kind === 'component' && node.source)
|
|
8
|
+
components.push(node);
|
|
9
|
+
});
|
|
10
|
+
const eager = new Set();
|
|
11
|
+
const never = new Set();
|
|
12
|
+
for (const node of components) {
|
|
13
|
+
const { module, loading } = node.source;
|
|
14
|
+
if (loading.kind === 'eager')
|
|
15
|
+
eager.add(module);
|
|
16
|
+
if (loading.kind === 'never')
|
|
17
|
+
never.add(module);
|
|
18
|
+
}
|
|
19
|
+
const collapsed = new Map();
|
|
20
|
+
for (const node of components) {
|
|
21
|
+
const source = node.source;
|
|
22
|
+
if (!isDeferred(source.loading))
|
|
23
|
+
continue;
|
|
24
|
+
if (!eager.has(source.module))
|
|
25
|
+
continue;
|
|
26
|
+
source.loading = { kind: 'eager' };
|
|
27
|
+
collapsed.set(source.module, (collapsed.get(source.module) ?? 0) + 1);
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
collapsed,
|
|
31
|
+
conflicted: [...never].filter((m) => eager.has(m)),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function a(o){return o.kind!=="eager"&&o.kind!=="never"}var l=["Show","For","Index","Switch","Match","Portal","Dynamic","ErrorBoundary"],u=["Suspense","SuspenseList","Await"],p=["Router","Outlet","Redirect","Link"],g=[...l,...u,...p],m=new Set([...l,...u]);function d(o,t){let i=Array.isArray(o)?o:[o];for(let s of i){t(s);let r=s.children;r&&d(r,t)}}function w(o){let t=[];d(o,e=>{e.kind==="component"&&e.source&&t.push(e)});let i=new Set,s=new Set;for(let e of t){let{module:n,loading:c}=e.source;c.kind==="eager"&&i.add(n),c.kind==="never"&&s.add(n)}let r=new Map;for(let e of t){let n=e.source;a(n.loading)&&i.has(n.module)&&(n.loading={kind:"eager"},r.set(n.module,(r.get(n.module)??0)+1))}return{collapsed:r,conflicted:[...s].filter(e=>i.has(e))}}export{w as collapseStrategies};
|
package/dist/options.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var l=Object.defineProperty;var n=Object.getOwnPropertyDescriptor;var s=Object.getOwnPropertyNames;var p=Object.prototype.hasOwnProperty;var m=(o,e)=>{for(var t in e)l(o,t,{get:e[t],enumerable:!0})},d=(o,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of s(e))!p.call(o,a)&&a!==t&&l(o,a,{get:()=>e[a],enumerable:!(r=n(e,a))||r.enumerable});return o};var i=o=>d(l({},"__esModule",{value:!0}),o);var b={};m(b,{defaultOptions:()=>v});module.exports=i(b);var v={backend:"imperative",generate:"dom",moduleName:"@fluixi/dom",delegateEvents:!0,hydratable:!1,sourceMaps:!0,dev:!1};
|
package/dist/options.d.ts
CHANGED
|
@@ -4,6 +4,24 @@ import type { ComponentResolverRule } from './resolve/component-resolver.js';
|
|
|
4
4
|
* as backends change. Switching DOM strategy is `backend`, not a rewrite.
|
|
5
5
|
*/
|
|
6
6
|
export interface CompilerOptions {
|
|
7
|
+
/**
|
|
8
|
+
* Clone static subtrees from a `<template>` instead of building them element by
|
|
9
|
+
* element. Roughly 2x faster to instantiate, but **client-only**: `createTemplate`
|
|
10
|
+
* produces real DOM nodes, which the SSR renderer's ServerElement tree rejects, and a
|
|
11
|
+
* clone creates a fresh node where hydration must adopt the existing one. Opt in for
|
|
12
|
+
* a client-rendered app; leave off wherever SSR or hydration is involved.
|
|
13
|
+
*/
|
|
14
|
+
templateClone?: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Also clone subtrees whose *structure* is static but which contain dynamic holes —
|
|
17
|
+
* the common shape. Roughly halves the emitted code for such a subtree and replaces
|
|
18
|
+
* per-element construction with one clone.
|
|
19
|
+
*
|
|
20
|
+
* Works under SSR and hydration: each hole is bracketed by `<!--fx-->` markers, so its
|
|
21
|
+
* content is exactly the nodes between them and the server's markup has the same shape
|
|
22
|
+
* as the client's template. Hydration adopts those nodes rather than rebuilding them.
|
|
23
|
+
*/
|
|
24
|
+
partialTemplates?: boolean;
|
|
7
25
|
/** which codegen backend to use */
|
|
8
26
|
backend?: 'imperative' | 'template-clone';
|
|
9
27
|
/** output target */
|
package/dist/options.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAE7E;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,mCAAmC;IACnC,OAAO,CAAC,EAAE,YAAY,GAAG,gBAAgB,CAAC;IAC1C,oBAAoB;IACpB,QAAQ,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,SAAS,CAAC;IACrC,uDAAuD;IACvD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd;;;OAGG;IACH,OAAO,CAAC,EAAE,SAAS,qBAAqB,EAAE,CAAC;CAC5C;AAED,eAAO,MAAM,cAAc,EAAE,eAQ5B,CAAC"}
|
|
1
|
+
{"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAE7E;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;;;;;;OAQG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAE3B,mCAAmC;IACnC,OAAO,CAAC,EAAE,YAAY,GAAG,gBAAgB,CAAC;IAC1C,oBAAoB;IACpB,QAAQ,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,SAAS,CAAC;IACrC,uDAAuD;IACvD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd;;;OAGG;IACH,OAAO,CAAC,EAAE,SAAS,qBAAqB,EAAE,CAAC;CAC5C;AAED,eAAO,MAAM,cAAc,EAAE,eAQ5B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var l=Object.defineProperty;var a=Object.getOwnPropertyDescriptor;var m=Object.getOwnPropertyNames;var d=Object.prototype.hasOwnProperty;var M=(o,t)=>{for(var e in t)l(o,e,{get:t[e],enumerable:!0})},O=(o,t,e,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of m(t))!d.call(o,n)&&n!==e&&l(o,n,{get:()=>t[n],enumerable:!(s=a(t,n))||s.enumerable});return o};var f=o=>O(l({},"__esModule",{value:!0}),o);var E={};M(E,{BUILTIN_COMPONENTS:()=>x,CORE_CONTROL_FLOW:()=>u,DOM_CONTROL_FLOW:()=>i,RESERVED_COMPONENTS:()=>R,ROUTER_COMPONENTS:()=>c,builtinComponentMap:()=>p,builtinComponents:()=>C,routerComponents:()=>g});module.exports=f(E);var i=["Show","For","Index","Switch","Match","Portal","Dynamic","ErrorBoundary"],u=["Suspense","SuspenseList","Await"],c=["Router","Outlet","Redirect","Link"],x=[...i,...u,...c],R=new Set([...i,...u]);function p(o={}){let{controlFlowModule:t="@fluixi/dom",coreModule:e="@fluixi/core",routerModule:s="@fluixi/core/router-next"}=o,n={};for(let r of i)n[r]=t;for(let r of u)n[r]=e;for(let r of c)n[r]=s;return n}function C(o={}){return{components:p(o)}}function g(o){let t=o??"@fluixi/core/router-next";return{components:Object.fromEntries(c.map(e=>[e,t]))}}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The components the compiler supplies without an import, as data.
|
|
3
|
+
*
|
|
4
|
+
* Two different things have always been bundled into one hardcoded `Set` per group:
|
|
5
|
+
* *which module a name comes from*, and *whether the name has special lowering*. Only
|
|
6
|
+
* the first is interesting outside the compiler, and every tool needs it — the TS
|
|
7
|
+
* plugin, to resolve `<Show>` for hover and go-to-definition; the language server, to
|
|
8
|
+
* complete and validate tags inside `` html`…` ``; a codemod, to materialise imports.
|
|
9
|
+
* Having no published source, `@fluixi/ts-plugin` duplicated the list and pinned it
|
|
10
|
+
* with a test that fails when the two drift.
|
|
11
|
+
*
|
|
12
|
+
* So the names live here, shaped as {@link ComponentMapRule} so they compose with
|
|
13
|
+
* user-configured `resolve` rules, and the compiler keeps its own sets for the parts
|
|
14
|
+
* that are genuinely about codegen.
|
|
15
|
+
*
|
|
16
|
+
* The split matters: control-flow names cannot become ordinary rules. `Show`, `For`,
|
|
17
|
+
* `Index` and `Match` read a reactive *value* prop inside their own tracking scope, so
|
|
18
|
+
* the compiler emits that prop as a getter — without it `each={items()}` snapshots once
|
|
19
|
+
* and never updates. They are also exempted from `createMemo` wrapping and may be
|
|
20
|
+
* replaced outright by `optimizeControlFlowComponent`. A rule only injects an import,
|
|
21
|
+
* so converting them would keep the import and silently drop the reactivity.
|
|
22
|
+
*
|
|
23
|
+
* Router components have no such behaviour — every reference to them in the plugin is
|
|
24
|
+
* import plumbing — so they are a plain rule.
|
|
25
|
+
*/
|
|
26
|
+
import type { ComponentMapRule } from './component-resolver.js';
|
|
27
|
+
/** Where the built-in groups come from when the host does not override the module. */
|
|
28
|
+
export interface BuiltinModules {
|
|
29
|
+
/** Control flow that lives in the DOM package. Default `@fluixi/dom`. */
|
|
30
|
+
controlFlowModule?: string;
|
|
31
|
+
/** Control flow that only exists in core. Default `@fluixi/core`. */
|
|
32
|
+
coreModule?: string;
|
|
33
|
+
/** Router components. Default `@fluixi/core/router-next`. */
|
|
34
|
+
routerModule?: string;
|
|
35
|
+
}
|
|
36
|
+
/** Control flow lowered against the DOM runtime. */
|
|
37
|
+
export declare const DOM_CONTROL_FLOW: readonly ["Show", "For", "Index", "Switch", "Match", "Portal", "Dynamic", "ErrorBoundary"];
|
|
38
|
+
/** Control flow that only `@fluixi/core` exports — importing it from dom resolves to nothing. */
|
|
39
|
+
export declare const CORE_CONTROL_FLOW: readonly ["Suspense", "SuspenseList", "Await"];
|
|
40
|
+
/**
|
|
41
|
+
* Router components.
|
|
42
|
+
*
|
|
43
|
+
* `Routes` is not a component (routing is `<Router routes={…}>`) and `lazy` is a call
|
|
44
|
+
* rather than a tag, so neither can be supplied this way.
|
|
45
|
+
*/
|
|
46
|
+
export declare const ROUTER_COMPONENTS: readonly ["Router", "Outlet", "Redirect", "Link"];
|
|
47
|
+
/** Every name the compiler supplies without an import. */
|
|
48
|
+
export declare const BUILTIN_COMPONENTS: readonly string[];
|
|
49
|
+
/**
|
|
50
|
+
* Names whose meaning is fixed by the compiler and cannot be reassigned by a rule.
|
|
51
|
+
*
|
|
52
|
+
* A rule naming one of these is a silent no-op — the compiler matches the built-in
|
|
53
|
+
* first and the tag renders control flow instead of the intended component, with no
|
|
54
|
+
* error. Rule authors should check against this set and report rather than emit.
|
|
55
|
+
*/
|
|
56
|
+
export declare const RESERVED_COMPONENTS: ReadonlySet<string>;
|
|
57
|
+
/** Name → module for every built-in, honouring host module overrides. */
|
|
58
|
+
export declare function builtinComponentMap(modules?: BuiltinModules): Record<string, string>;
|
|
59
|
+
/**
|
|
60
|
+
* The built-ins as a resolver rule, for tools that want one uniform lookup.
|
|
61
|
+
*
|
|
62
|
+
* Note this is the *naming* half only. Feeding it to the compiler would not make
|
|
63
|
+
* control flow work through resolution — the compiler still recognises those names
|
|
64
|
+
* itself, for the codegen reasons above.
|
|
65
|
+
*/
|
|
66
|
+
export declare function builtinComponents(modules?: BuiltinModules): ComponentMapRule;
|
|
67
|
+
/** Just the router group as a rule — the one group that is purely an import. */
|
|
68
|
+
export declare function routerComponents(routerModule?: string): ComponentMapRule;
|
|
69
|
+
//# sourceMappingURL=builtins.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"builtins.d.ts","sourceRoot":"","sources":["../../src/resolve/builtins.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,sFAAsF;AACtF,MAAM,WAAW,cAAc;IAC7B,yEAAyE;IACzE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,qEAAqE;IACrE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6DAA6D;IAC7D,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,oDAAoD;AACpD,eAAO,MAAM,gBAAgB,4FASnB,CAAC;AAEX,iGAAiG;AACjG,eAAO,MAAM,iBAAiB,gDAAiD,CAAC;AAEhF;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,mDAAoD,CAAC;AAEnF,0DAA0D;AAC1D,eAAO,MAAM,kBAAkB,EAAE,SAAS,MAAM,EAI/C,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,EAAE,WAAW,CAAC,MAAM,CAGlD,CAAC;AAEH,yEAAyE;AACzE,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,cAAmB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAYxF;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,cAAmB,GAAG,gBAAgB,CAEhF;AAED,gFAAgF;AAChF,wBAAgB,gBAAgB,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAGxE"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/** Control flow lowered against the DOM runtime. */
|
|
2
|
+
export const DOM_CONTROL_FLOW = [
|
|
3
|
+
'Show',
|
|
4
|
+
'For',
|
|
5
|
+
'Index',
|
|
6
|
+
'Switch',
|
|
7
|
+
'Match',
|
|
8
|
+
'Portal',
|
|
9
|
+
'Dynamic',
|
|
10
|
+
'ErrorBoundary',
|
|
11
|
+
];
|
|
12
|
+
/** Control flow that only `@fluixi/core` exports — importing it from dom resolves to nothing. */
|
|
13
|
+
export const CORE_CONTROL_FLOW = ['Suspense', 'SuspenseList', 'Await'];
|
|
14
|
+
/**
|
|
15
|
+
* Router components.
|
|
16
|
+
*
|
|
17
|
+
* `Routes` is not a component (routing is `<Router routes={…}>`) and `lazy` is a call
|
|
18
|
+
* rather than a tag, so neither can be supplied this way.
|
|
19
|
+
*/
|
|
20
|
+
export const ROUTER_COMPONENTS = ['Router', 'Outlet', 'Redirect', 'Link'];
|
|
21
|
+
/** Every name the compiler supplies without an import. */
|
|
22
|
+
export const BUILTIN_COMPONENTS = [
|
|
23
|
+
...DOM_CONTROL_FLOW,
|
|
24
|
+
...CORE_CONTROL_FLOW,
|
|
25
|
+
...ROUTER_COMPONENTS,
|
|
26
|
+
];
|
|
27
|
+
/**
|
|
28
|
+
* Names whose meaning is fixed by the compiler and cannot be reassigned by a rule.
|
|
29
|
+
*
|
|
30
|
+
* A rule naming one of these is a silent no-op — the compiler matches the built-in
|
|
31
|
+
* first and the tag renders control flow instead of the intended component, with no
|
|
32
|
+
* error. Rule authors should check against this set and report rather than emit.
|
|
33
|
+
*/
|
|
34
|
+
export const RESERVED_COMPONENTS = new Set([
|
|
35
|
+
...DOM_CONTROL_FLOW,
|
|
36
|
+
...CORE_CONTROL_FLOW,
|
|
37
|
+
]);
|
|
38
|
+
/** Name → module for every built-in, honouring host module overrides. */
|
|
39
|
+
export function builtinComponentMap(modules = {}) {
|
|
40
|
+
const { controlFlowModule = '@fluixi/dom', coreModule = '@fluixi/core', routerModule = '@fluixi/core/router-next', } = modules;
|
|
41
|
+
const map = {};
|
|
42
|
+
for (const name of DOM_CONTROL_FLOW)
|
|
43
|
+
map[name] = controlFlowModule;
|
|
44
|
+
for (const name of CORE_CONTROL_FLOW)
|
|
45
|
+
map[name] = coreModule;
|
|
46
|
+
for (const name of ROUTER_COMPONENTS)
|
|
47
|
+
map[name] = routerModule;
|
|
48
|
+
return map;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The built-ins as a resolver rule, for tools that want one uniform lookup.
|
|
52
|
+
*
|
|
53
|
+
* Note this is the *naming* half only. Feeding it to the compiler would not make
|
|
54
|
+
* control flow work through resolution — the compiler still recognises those names
|
|
55
|
+
* itself, for the codegen reasons above.
|
|
56
|
+
*/
|
|
57
|
+
export function builtinComponents(modules = {}) {
|
|
58
|
+
return { components: builtinComponentMap(modules) };
|
|
59
|
+
}
|
|
60
|
+
/** Just the router group as a rule — the one group that is purely an import. */
|
|
61
|
+
export function routerComponents(routerModule) {
|
|
62
|
+
const module = routerModule ?? '@fluixi/core/router-next';
|
|
63
|
+
return { components: Object.fromEntries(ROUTER_COMPONENTS.map((n) => [n, module])) };
|
|
64
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var s=["Show","For","Index","Switch","Match","Portal","Dynamic","ErrorBoundary"],i=["Suspense","SuspenseList","Await"],u=["Router","Outlet","Redirect","Link"],p=[...s,...i,...u],a=new Set([...s,...i]);function l(o={}){let{controlFlowModule:e="@fluixi/dom",coreModule:r="@fluixi/core",routerModule:c="@fluixi/core/router-next"}=o,n={};for(let t of s)n[t]=e;for(let t of i)n[t]=r;for(let t of u)n[t]=c;return n}function m(o={}){return{components:l(o)}}function d(o){let e=o??"@fluixi/core/router-next";return{components:Object.fromEntries(u.map(r=>[r,e]))}}export{p as BUILTIN_COMPONENTS,i as CORE_CONTROL_FLOW,s as DOM_CONTROL_FLOW,a as RESERVED_COMPONENTS,u as ROUTER_COMPONENTS,l as builtinComponentMap,m as builtinComponents,d as routerComponents};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";var C=Object.defineProperty;var N=Object.getOwnPropertyDescriptor;var T=Object.getOwnPropertyNames;var L=Object.prototype.hasOwnProperty;var _=(e,t)=>{for(var r in t)C(e,r,{get:t[r],enumerable:!0})},B=(e,t,r,a)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of T(t))!L.call(e,n)&&n!==r&&C(e,n,{get:()=>t[n],enumerable:!(a=N(t,n))||a.enumerable});return e};var D=e=>B(C({},"__esModule",{value:!0}),e);var W={};_(W,{componentGlobals:()=>I});module.exports=D(W);var j=e=>"components"in e;function b(e,t){return e.replace(/\$(\d+)/g,(r,a)=>t[Number(a)]??r)}function A(e,t){return typeof t=="string"?{module:t,export:e}:t}function M(e=[]){let t=new Map,r=[],a=[];for(let i of e){if(!j(i)){a.push(i);continue}for(let[s,c]of Object.entries(i.components)){let l=A(s,c),m=t.get(s);if(m&&m.module!==l.module){let d=r.find(f=>f.name===s);d?d.modules.push(l.module):r.push({name:s,modules:[m.module,l.module]});continue}t.set(s,l)}}let n=new Map;return{resolve:i=>{if(n.has(i))return n.get(i);let s=t.get(i);if(!s)for(let c of a){let l=i.match(new RegExp(c.match.source,c.match.flags.replace("g","")));if(l){s={module:b(c.module,l),export:c.export?b(c.export,l):i};break}}return n.set(i,s),s},names:()=>[...t.keys()],conflicts:()=>r}}var h=["Show","For","Index","Switch","Match","Portal","Dynamic","ErrorBoundary"],x=["Suspense","SuspenseList","Await"],O=["Router","Outlet","Redirect","Link"],q=[...h,...x,...O],z=new Set([...h,...x]);function y(e={}){let{controlFlowModule:t="@fluixi/dom",coreModule:r="@fluixi/core",routerModule:a="@fluixi/core/router-next"}=e,n={};for(let p of h)n[p]=t;for(let p of x)n[p]=r;for(let p of O)n[p]=a;return n}var G=new Set(["Text","Image","Option","Audio","Comment","Range","Selection","Notification","Event","Document","Element","Node","Screen","Window","Location","History","Storage","Response","Request","Headers"]);function P(e){if(e.startsWith(".")||e.startsWith("/")||/^[~@]\//.test(e))return;let t=e.split("/");return e.startsWith("@")?t.slice(0,2).join("/"):t[0]}function w(e){return`_${e.replace(/[^A-Za-z0-9]/g,"_")}`}function I(e,t={}){let{available:r,builtins:a=!0,generator:n="@fluixi/compiler",specifier:p=o=>o}=t,i=[...e];a&&i.push({components:y()});let s=M(i),c=r?new Set(r):void 0,l=[],m=[],d=[],f=new Map;for(let o of[...s.names()].sort()){let u=s.resolve(o);if(!u)continue;let g=P(u.module);G.has(o)?m.push(o):c&&g&&!c.has(g)?d.push(o):(l.push(o),f.set(o,u))}let v=[...new Set(l.map(o=>f.get(o).module))].sort().map(o=>`import * as ${w(o)} from '${p(o)}';`),E=l.map(o=>{let u=f.get(o),g=w(u.module);return u.export==="default"?` const ${o}: typeof ${g}.default;`:` export import ${o} = ${g}.${u.export};`}),S=m.length>0?`//
|
|
2
|
+
// Import these explicitly — lib.dom already declares the name, so an ambient
|
|
3
|
+
// declaration cannot win:
|
|
4
|
+
`+m.map(o=>{let u=s.resolve(o)?.module;return`// import { ${o} } from '${u?p(u):""}';
|
|
5
|
+
`}).join(""):"",R=e.filter(o=>"match"in o).length,$=R>0?`//
|
|
6
|
+
// ${R} pattern rule${R===1?"":"s"} cannot be declared:
|
|
7
|
+
// a pattern matches unboundedly many names, so there is no list to emit. Those
|
|
8
|
+
// tags still resolve at build time; declare them by hand if the editor needs them.
|
|
9
|
+
`:"";return{source:`// GENERATED by ${n} — do not edit.
|
|
10
|
+
//
|
|
11
|
+
// The components \`resolve\` supplies without an import. This describes what the
|
|
12
|
+
// compiler already does; it does not enable it.
|
|
13
|
+
`+S+$+(v.length>0?`
|
|
14
|
+
${v.join(`
|
|
15
|
+
`)}
|
|
16
|
+
`:`
|
|
17
|
+
`)+`
|
|
18
|
+
declare global {
|
|
19
|
+
${E.join(`
|
|
20
|
+
`)}
|
|
21
|
+
}
|
|
22
|
+
`,declared:l,shadowedByDom:m,unavailable:d,patternRules:R}}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ambient declarations for the components `resolve` supplies without an import.
|
|
3
|
+
*
|
|
4
|
+
* The compiler injects the import, so nothing in the source imports these — which leaves
|
|
5
|
+
* TypeScript reporting `TS2304: Cannot find name`. The code compiles and runs; the editor
|
|
6
|
+
* is unusable and `tsc` fails. These declarations describe what the compiler already
|
|
7
|
+
* does. They do not enable it.
|
|
8
|
+
*
|
|
9
|
+
* This lives next to the resolver, and takes rules rather than a flat map, because the
|
|
10
|
+
* resolver is the only thing that knows the whole picture: a UI library's components, the
|
|
11
|
+
* project's own, and the framework builtins all arrive through the same config. A
|
|
12
|
+
* component library cannot generate this on its own — it does not know what else the
|
|
13
|
+
* project resolves — which is why the generator belongs here and the library-specific CLI
|
|
14
|
+
* that predates it does not.
|
|
15
|
+
*
|
|
16
|
+
* Pure, like the resolver: rules in, source out, no filesystem. Writing the file is the
|
|
17
|
+
* caller's job (the Vite plugin does it on config resolve; a CLI can do it in CI).
|
|
18
|
+
*/
|
|
19
|
+
import { type ComponentResolverRule } from './component-resolver.js';
|
|
20
|
+
export interface ComponentGlobalsOptions {
|
|
21
|
+
/**
|
|
22
|
+
* Packages the project can actually resolve — normally its declared dependencies.
|
|
23
|
+
*
|
|
24
|
+
* Declaring a component from a package the project does not depend on produces an
|
|
25
|
+
* unresolvable `import(...)`, and under the usual `skipLibCheck: true` that failure is
|
|
26
|
+
* silent: the component degrades to `any` and every prop typo type-checks, which is
|
|
27
|
+
* worse than the error it replaced. Omit to declare everything, which is only correct
|
|
28
|
+
* when every package is present.
|
|
29
|
+
*
|
|
30
|
+
* Relative and alias specifiers are never filtered — there is no package to check.
|
|
31
|
+
*/
|
|
32
|
+
available?: Iterable<string>;
|
|
33
|
+
/**
|
|
34
|
+
* Declare the framework builtins (`Show`, `For`, `Portal`, `Router`, …) too.
|
|
35
|
+
*
|
|
36
|
+
* On by default because the compiler resolves them whether or not a rule mentions
|
|
37
|
+
* them, so declaring them is what matches reality. A real import shadows the ambient
|
|
38
|
+
* declaration, so this stays safe for code that imports them explicitly.
|
|
39
|
+
*/
|
|
40
|
+
builtins?: boolean;
|
|
41
|
+
/** Attribution written into the header. */
|
|
42
|
+
generator?: string;
|
|
43
|
+
/**
|
|
44
|
+
* Rewrite a module specifier for the file being generated.
|
|
45
|
+
*
|
|
46
|
+
* A bundler and TypeScript do not agree on every specifier: Vite resolves a
|
|
47
|
+
* root-absolute `/src/x.tsx` that TypeScript cannot see at all. The caller knows where
|
|
48
|
+
* the file will land and so is the only one able to fix that up; the generator stays
|
|
49
|
+
* pure and just asks.
|
|
50
|
+
*/
|
|
51
|
+
specifier?: (module: string) => string;
|
|
52
|
+
}
|
|
53
|
+
export interface ComponentGlobalsResult {
|
|
54
|
+
/** The `.d.ts` source to write. */
|
|
55
|
+
source: string;
|
|
56
|
+
/** Components declared. */
|
|
57
|
+
declared: string[];
|
|
58
|
+
/** Left out because `lib.dom` already claims the name. */
|
|
59
|
+
shadowedByDom: string[];
|
|
60
|
+
/** Left out because the project does not depend on their package. */
|
|
61
|
+
unavailable: string[];
|
|
62
|
+
/**
|
|
63
|
+
* Pattern rules, which have no finite name list and so cannot be declared.
|
|
64
|
+
*
|
|
65
|
+
* `Icon(.+) -> @/icons/$1` matches unboundedly many names; the resolver answers them on
|
|
66
|
+
* demand but cannot enumerate them. Those tags stay manual, and the caller is told how
|
|
67
|
+
* many rules are in that position rather than left to wonder why nothing appeared.
|
|
68
|
+
*/
|
|
69
|
+
patternRules: number;
|
|
70
|
+
}
|
|
71
|
+
/** Build the ambient `.d.ts` for the components a project's `resolve` config supplies. */
|
|
72
|
+
export declare function componentGlobals(rules: readonly ComponentResolverRule[], options?: ComponentGlobalsOptions): ComponentGlobalsResult;
|
|
73
|
+
//# sourceMappingURL=component-globals.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"component-globals.d.ts","sourceRoot":"","sources":["../../src/resolve/component-globals.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAEL,KAAK,qBAAqB,EAE3B,MAAM,yBAAyB,CAAC;AAkCjC,MAAM,WAAW,uBAAuB;IACtC;;;;;;;;;;OAUG;IACH,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC7B;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,2CAA2C;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC;CACxC;AAED,MAAM,WAAW,sBAAsB;IACrC,mCAAmC;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,2BAA2B;IAC3B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,0DAA0D;IAC1D,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,qEAAqE;IACrE,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB;;;;;;OAMG;IACH,YAAY,EAAE,MAAM,CAAC;CACtB;AAgBD,0FAA0F;AAC1F,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,SAAS,qBAAqB,EAAE,EACvC,OAAO,GAAE,uBAA4B,GACpC,sBAAsB,CAyFxB"}
|