zyzz 0.0.28 → 0.0.30
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/binding/wasi/wasi-worker.mjs +186 -0
- package/binding/wasi/zyzz.wasi.cjs +2302 -0
- package/binding/wasi/zyzz.wasm32-wasi.wasm +0 -0
- package/binding/zyzz.linux-x64-gnu.node +0 -0
- package/dist/babel/index.d.ts.map +1 -1
- package/dist/babel/index.js +2 -4
- package/dist/babel/index.js.map +1 -1
- package/dist/babel/internal/Compilation.d.ts +0 -1
- package/dist/babel/internal/Compilation.d.ts.map +1 -1
- package/dist/compiler/Graph.d.ts +14 -11
- package/dist/compiler/Graph.d.ts.map +1 -1
- package/dist/compiler/Graph.js +57 -1442
- package/dist/compiler/Graph.js.map +1 -1
- package/dist/compiler/Native.d.ts +7 -9
- package/dist/compiler/Native.d.ts.map +1 -1
- package/dist/compiler/Native.js +12 -716
- package/dist/compiler/Native.js.map +1 -1
- package/dist/compiler/Source.d.ts +122 -24
- package/dist/compiler/Source.d.ts.map +1 -1
- package/dist/compiler/Source.js +10 -1267
- package/dist/compiler/Source.js.map +1 -1
- package/dist/compiler/Transform.d.ts +4 -3
- package/dist/compiler/Transform.d.ts.map +1 -1
- package/dist/compiler/Transform.js +13 -961
- package/dist/compiler/Transform.js.map +1 -1
- package/dist/compiler/internal/AtRules.d.ts +5 -1
- package/dist/compiler/internal/AtRules.d.ts.map +1 -1
- package/dist/compiler/internal/AtRules.js +12 -106
- package/dist/compiler/internal/AtRules.js.map +1 -1
- package/dist/compiler/internal/Context.d.ts +11 -0
- package/dist/compiler/internal/Context.d.ts.map +1 -0
- package/dist/compiler/internal/Context.js +11 -0
- package/dist/compiler/internal/Context.js.map +1 -0
- package/dist/compiler/internal/Results.d.ts +148 -0
- package/dist/compiler/internal/Results.d.ts.map +1 -0
- package/dist/compiler/internal/Results.js +259 -0
- package/dist/compiler/internal/Results.js.map +1 -0
- package/dist/compiler/internal/Syntax.d.ts +0 -2
- package/dist/compiler/internal/Syntax.d.ts.map +1 -1
- package/dist/compiler/internal/Syntax.js +0 -2
- package/dist/compiler/internal/Syntax.js.map +1 -1
- package/dist/compiler/internal/Wire.d.ts +17 -0
- package/dist/compiler/internal/Wire.d.ts.map +1 -0
- package/dist/compiler/internal/Wire.js +795 -0
- package/dist/compiler/internal/Wire.js.map +1 -0
- package/dist/internal/Addon.d.ts +28 -0
- package/dist/internal/Addon.d.ts.map +1 -0
- package/dist/internal/Addon.js +87 -0
- package/dist/internal/Addon.js.map +1 -0
- package/dist/internal/Literal.d.ts +4 -1
- package/dist/internal/Literal.d.ts.map +1 -1
- package/dist/internal/Literal.js +4 -2
- package/dist/internal/Literal.js.map +1 -1
- package/dist/internal/Token.d.ts +2 -1
- package/dist/internal/Token.d.ts.map +1 -1
- package/dist/internal/Token.js +2 -2
- package/dist/internal/Token.js.map +1 -1
- package/dist/internal/Vlq.d.ts +14 -0
- package/dist/internal/Vlq.d.ts.map +1 -0
- package/dist/internal/Vlq.js +47 -0
- package/dist/internal/Vlq.js.map +1 -0
- package/dist/internal/Wasm.d.ts +22 -0
- package/dist/internal/Wasm.d.ts.map +1 -0
- package/dist/internal/Wasm.js +83 -0
- package/dist/internal/Wasm.js.map +1 -0
- package/dist/metro/Graph.d.ts +0 -1
- package/dist/metro/Graph.d.ts.map +1 -1
- package/dist/metro/transformer.d.ts.map +1 -1
- package/dist/metro/transformer.js +0 -1
- package/dist/metro/transformer.js.map +1 -1
- package/dist/next/internal/Project.d.ts.map +1 -1
- package/dist/next/internal/Project.js +2 -5
- package/dist/next/internal/Project.js.map +1 -1
- package/dist/node/Host.d.ts.map +1 -1
- package/dist/node/Host.js +0 -2
- package/dist/node/Host.js.map +1 -1
- package/dist/node/internal/Contracts.d.ts.map +1 -1
- package/dist/node/internal/Contracts.js +3 -7
- package/dist/node/internal/Contracts.js.map +1 -1
- package/dist/node/internal/Snapshot.d.ts +0 -1
- package/dist/node/internal/Snapshot.d.ts.map +1 -1
- package/dist/node/internal/Snapshot.js +0 -6
- package/dist/node/internal/Snapshot.js.map +1 -1
- package/dist/runtime/Composition.d.ts +2 -3
- package/dist/runtime/Composition.d.ts.map +1 -1
- package/dist/runtime/Composition.js +51 -30
- package/dist/runtime/Composition.js.map +1 -1
- package/dist/runtime/Recipe.d.ts.map +1 -1
- package/dist/runtime/Recipe.js +16 -12
- package/dist/runtime/Recipe.js.map +1 -1
- package/dist/unplugin/index.d.ts.map +1 -1
- package/dist/unplugin/index.js +3 -6
- package/dist/unplugin/index.js.map +1 -1
- package/dist/vite/index.d.ts.map +1 -1
- package/dist/vite/index.js +696 -201
- package/dist/vite/index.js.map +1 -1
- package/dist/web/Css.d.ts +8 -3
- package/dist/web/Css.d.ts.map +1 -1
- package/dist/web/Css.js +5 -721
- package/dist/web/Css.js.map +1 -1
- package/dist/web/internal/Block.d.ts +0 -2
- package/dist/web/internal/Block.d.ts.map +1 -1
- package/dist/web/internal/Block.js +1 -12
- package/dist/web/internal/Block.js.map +1 -1
- package/dist/web/internal/ClassName.d.ts +23 -18
- package/dist/web/internal/ClassName.d.ts.map +1 -1
- package/dist/web/internal/ClassName.js +26 -55
- package/dist/web/internal/ClassName.js.map +1 -1
- package/dist/web/internal/Contributions.d.ts +3 -5
- package/dist/web/internal/Contributions.d.ts.map +1 -1
- package/dist/web/internal/Contributions.js +0 -45
- package/dist/web/internal/Contributions.js.map +1 -1
- package/dist/web/internal/Engine.browser.d.ts +8 -0
- package/dist/web/internal/Engine.browser.d.ts.map +1 -0
- package/dist/web/internal/Engine.browser.js +42 -0
- package/dist/web/internal/Engine.browser.js.map +1 -0
- package/dist/web/internal/Engine.d.ts +9 -0
- package/dist/web/internal/Engine.d.ts.map +1 -0
- package/dist/web/internal/Engine.js +14 -0
- package/dist/web/internal/Engine.js.map +1 -0
- package/dist/web/internal/Themes.d.ts +1 -9
- package/dist/web/internal/Themes.d.ts.map +1 -1
- package/dist/web/internal/Themes.js +3 -221
- package/dist/web/internal/Themes.js.map +1 -1
- package/dist/web/internal/Wasm.generated.d.ts +4 -0
- package/dist/web/internal/Wasm.generated.d.ts.map +1 -0
- package/dist/web/internal/Wasm.generated.js +4 -0
- package/dist/web/internal/Wasm.generated.js.map +1 -0
- package/dist/web/internal/Wire.d.ts +19 -0
- package/dist/web/internal/Wire.d.ts.map +1 -0
- package/dist/web/internal/Wire.js +387 -0
- package/dist/web/internal/Wire.js.map +1 -0
- package/package.json +20 -1
- package/src/babel/index.ts +2 -5
- package/src/babel/internal/Compilation.ts +0 -1
- package/src/compiler/Graph.ts +89 -1930
- package/src/compiler/Native.ts +18 -871
- package/src/compiler/Source.ts +144 -1803
- package/src/compiler/Transform.ts +16 -1315
- package/src/compiler/internal/AtRules.ts +27 -115
- package/src/compiler/internal/Context.ts +11 -0
- package/src/compiler/internal/Results.ts +406 -0
- package/src/compiler/internal/Syntax.ts +0 -3
- package/src/compiler/internal/Wire.ts +1045 -0
- package/src/internal/Addon.ts +118 -0
- package/src/internal/Literal.ts +4 -2
- package/src/internal/Token.ts +2 -2
- package/src/internal/Vlq.ts +59 -0
- package/src/internal/Wasm.ts +111 -0
- package/src/metro/transformer.ts +0 -1
- package/src/next/internal/Project.ts +2 -9
- package/src/node/Host.ts +0 -2
- package/src/node/internal/Contracts.ts +3 -7
- package/src/node/internal/Snapshot.ts +0 -8
- package/src/runtime/Composition.ts +48 -25
- package/src/runtime/Recipe.ts +21 -14
- package/src/unplugin/index.ts +6 -6
- package/src/vite/index.ts +922 -221
- package/src/web/Css.ts +12 -908
- package/src/web/internal/Block.ts +0 -14
- package/src/web/internal/ClassName.ts +52 -85
- package/src/web/internal/Contributions.ts +3 -59
- package/src/web/internal/Engine.browser.ts +51 -0
- package/src/web/internal/Engine.ts +17 -0
- package/src/web/internal/Themes.ts +3 -279
- package/src/web/internal/Wasm.generated.ts +3 -0
- package/src/web/internal/Wire.ts +466 -0
- package/src/web/internal/wasm.d.ts +9 -0
- package/dist/compiler/internal/Applications.d.ts +0 -55
- package/dist/compiler/internal/Applications.d.ts.map +0 -1
- package/dist/compiler/internal/Applications.js +0 -393
- package/dist/compiler/internal/Applications.js.map +0 -1
- package/dist/compiler/internal/ColorProfiles.d.ts +0 -3
- package/dist/compiler/internal/ColorProfiles.d.ts.map +0 -1
- package/dist/compiler/internal/ColorProfiles.js +0 -84
- package/dist/compiler/internal/ColorProfiles.js.map +0 -1
- package/dist/compiler/internal/CompositionBindings.d.ts +0 -16
- package/dist/compiler/internal/CompositionBindings.d.ts.map +0 -1
- package/dist/compiler/internal/CompositionBindings.js +0 -89
- package/dist/compiler/internal/CompositionBindings.js.map +0 -1
- package/dist/compiler/internal/Compositions.d.ts +0 -37
- package/dist/compiler/internal/Compositions.d.ts.map +0 -1
- package/dist/compiler/internal/Compositions.js +0 -494
- package/dist/compiler/internal/Compositions.js.map +0 -1
- package/dist/compiler/internal/Configurations.d.ts +0 -26
- package/dist/compiler/internal/Configurations.d.ts.map +0 -1
- package/dist/compiler/internal/Configurations.js +0 -259
- package/dist/compiler/internal/Configurations.js.map +0 -1
- package/dist/compiler/internal/Contract.d.ts +0 -30
- package/dist/compiler/internal/Contract.d.ts.map +0 -1
- package/dist/compiler/internal/Contract.js +0 -753
- package/dist/compiler/internal/Contract.js.map +0 -1
- package/dist/compiler/internal/Contributions.d.ts +0 -54
- package/dist/compiler/internal/Contributions.d.ts.map +0 -1
- package/dist/compiler/internal/Contributions.js +0 -1151
- package/dist/compiler/internal/Contributions.js.map +0 -1
- package/dist/compiler/internal/Descriptors.d.ts +0 -15
- package/dist/compiler/internal/Descriptors.d.ts.map +0 -1
- package/dist/compiler/internal/Descriptors.js +0 -192
- package/dist/compiler/internal/Descriptors.js.map +0 -1
- package/dist/compiler/internal/Dynamic.d.ts +0 -14
- package/dist/compiler/internal/Dynamic.d.ts.map +0 -1
- package/dist/compiler/internal/Dynamic.js +0 -175
- package/dist/compiler/internal/Dynamic.js.map +0 -1
- package/dist/compiler/internal/Expression.d.ts +0 -19
- package/dist/compiler/internal/Expression.d.ts.map +0 -1
- package/dist/compiler/internal/Expression.js +0 -164
- package/dist/compiler/internal/Expression.js.map +0 -1
- package/dist/compiler/internal/Functions.d.ts +0 -5
- package/dist/compiler/internal/Functions.d.ts.map +0 -1
- package/dist/compiler/internal/Functions.js +0 -191
- package/dist/compiler/internal/Functions.js.map +0 -1
- package/dist/compiler/internal/Keyframes.d.ts +0 -5
- package/dist/compiler/internal/Keyframes.d.ts.map +0 -1
- package/dist/compiler/internal/Keyframes.js +0 -51
- package/dist/compiler/internal/Keyframes.js.map +0 -1
- package/dist/compiler/internal/Names.d.ts +0 -5
- package/dist/compiler/internal/Names.d.ts.map +0 -1
- package/dist/compiler/internal/Names.js +0 -37
- package/dist/compiler/internal/Names.js.map +0 -1
- package/dist/compiler/internal/NativeBindings.d.ts +0 -72
- package/dist/compiler/internal/NativeBindings.d.ts.map +0 -1
- package/dist/compiler/internal/NativeBindings.js +0 -171
- package/dist/compiler/internal/NativeBindings.js.map +0 -1
- package/dist/compiler/internal/NativeMedia.d.ts +0 -14
- package/dist/compiler/internal/NativeMedia.d.ts.map +0 -1
- package/dist/compiler/internal/NativeMedia.js +0 -287
- package/dist/compiler/internal/NativeMedia.js.map +0 -1
- package/dist/compiler/internal/NativeVars.d.ts +0 -28
- package/dist/compiler/internal/NativeVars.d.ts.map +0 -1
- package/dist/compiler/internal/NativeVars.js +0 -160
- package/dist/compiler/internal/NativeVars.js.map +0 -1
- package/dist/compiler/internal/PackedStyles.d.ts +0 -37
- package/dist/compiler/internal/PackedStyles.d.ts.map +0 -1
- package/dist/compiler/internal/PackedStyles.js +0 -344
- package/dist/compiler/internal/PackedStyles.js.map +0 -1
- package/dist/compiler/internal/Properties.d.ts +0 -5
- package/dist/compiler/internal/Properties.d.ts.map +0 -1
- package/dist/compiler/internal/Properties.js +0 -82
- package/dist/compiler/internal/Properties.js.map +0 -1
- package/dist/compiler/internal/RecipeConditions.d.ts +0 -41
- package/dist/compiler/internal/RecipeConditions.d.ts.map +0 -1
- package/dist/compiler/internal/RecipeConditions.js +0 -82
- package/dist/compiler/internal/RecipeConditions.js.map +0 -1
- package/dist/compiler/internal/RecipePayloads.d.ts +0 -31
- package/dist/compiler/internal/RecipePayloads.d.ts.map +0 -1
- package/dist/compiler/internal/RecipePayloads.js +0 -99
- package/dist/compiler/internal/RecipePayloads.js.map +0 -1
- package/dist/compiler/internal/Recipes.d.ts +0 -32
- package/dist/compiler/internal/Recipes.d.ts.map +0 -1
- package/dist/compiler/internal/Recipes.js +0 -339
- package/dist/compiler/internal/Recipes.js.map +0 -1
- package/dist/compiler/internal/Selectors.d.ts +0 -13
- package/dist/compiler/internal/Selectors.d.ts.map +0 -1
- package/dist/compiler/internal/Selectors.js +0 -280
- package/dist/compiler/internal/Selectors.js.map +0 -1
- package/dist/compiler/internal/Static.d.ts +0 -39
- package/dist/compiler/internal/Static.d.ts.map +0 -1
- package/dist/compiler/internal/Static.js +0 -534
- package/dist/compiler/internal/Static.js.map +0 -1
- package/dist/compiler/internal/Themes.d.ts +0 -190
- package/dist/compiler/internal/Themes.d.ts.map +0 -1
- package/dist/compiler/internal/Themes.js +0 -1577
- package/dist/compiler/internal/Themes.js.map +0 -1
- package/dist/compiler/internal/Vars.d.ts +0 -33
- package/dist/compiler/internal/Vars.d.ts.map +0 -1
- package/dist/compiler/internal/Vars.js +0 -387
- package/dist/compiler/internal/Vars.js.map +0 -1
- package/dist/compiler/internal/ViewTransitions.d.ts +0 -3
- package/dist/compiler/internal/ViewTransitions.d.ts.map +0 -1
- package/dist/compiler/internal/ViewTransitions.js +0 -68
- package/dist/compiler/internal/ViewTransitions.js.map +0 -1
- package/dist/internal/Cascade.d.ts +0 -74
- package/dist/internal/Cascade.d.ts.map +0 -1
- package/dist/internal/Cascade.js +0 -210
- package/dist/internal/Cascade.js.map +0 -1
- package/src/compiler/internal/Applications.ts +0 -610
- package/src/compiler/internal/ColorProfiles.ts +0 -93
- package/src/compiler/internal/CompositionBindings.ts +0 -120
- package/src/compiler/internal/Compositions.ts +0 -678
- package/src/compiler/internal/Configurations.ts +0 -349
- package/src/compiler/internal/Contract.ts +0 -1028
- package/src/compiler/internal/Contributions.ts +0 -1561
- package/src/compiler/internal/Descriptors.ts +0 -242
- package/src/compiler/internal/Dynamic.ts +0 -275
- package/src/compiler/internal/Expression.ts +0 -218
- package/src/compiler/internal/Functions.ts +0 -206
- package/src/compiler/internal/Keyframes.ts +0 -62
- package/src/compiler/internal/Names.ts +0 -48
- package/src/compiler/internal/NativeBindings.ts +0 -235
- package/src/compiler/internal/NativeMedia.ts +0 -342
- package/src/compiler/internal/NativeVars.ts +0 -231
- package/src/compiler/internal/PackedStyles.ts +0 -473
- package/src/compiler/internal/Properties.ts +0 -121
- package/src/compiler/internal/RecipeConditions.ts +0 -139
- package/src/compiler/internal/RecipePayloads.ts +0 -132
- package/src/compiler/internal/Recipes.ts +0 -531
- package/src/compiler/internal/Selectors.ts +0 -353
- package/src/compiler/internal/Static.ts +0 -784
- package/src/compiler/internal/Themes.ts +0 -2398
- package/src/compiler/internal/Vars.ts +0 -516
- package/src/compiler/internal/ViewTransitions.ts +0 -82
package/src/compiler/Graph.ts
CHANGED
|
@@ -2,34 +2,60 @@
|
|
|
2
2
|
* Links a closed graph of source modules without executing code or reading files.
|
|
3
3
|
* @module
|
|
4
4
|
*/
|
|
5
|
-
import * as Contributions from './internal/Contributions.js'
|
|
6
|
-
import * as Stylesheets from './internal/Stylesheets.js'
|
|
7
5
|
import type * as Mapping from '@jridgewell/gen-mapping'
|
|
8
|
-
import * as
|
|
6
|
+
import * as Addon from '../internal/Addon.js'
|
|
7
|
+
import type * as Css from '../web/Css.js'
|
|
9
8
|
import * as ClassName from '../web/internal/ClassName.js'
|
|
10
|
-
import * as Native from './Native.js'
|
|
11
|
-
import * as NativeVars from './internal/NativeVars.js'
|
|
12
|
-
import * as NativeStyleSheet from '../react-native/StyleSheet.js'
|
|
13
|
-
import * as Edits from './internal/Edits.js'
|
|
14
|
-
import * as Identity from '../internal/Identity.js'
|
|
15
|
-
import type * as Ast from '@oxc-project/types'
|
|
16
|
-
import * as Parser from 'oxc-parser'
|
|
17
|
-
import * as Syntax from './internal/Syntax.js'
|
|
18
|
-
import * as Walker from 'oxc-walker'
|
|
19
|
-
import type * as Theme from '../internal/Theme.js'
|
|
20
|
-
import * as Token from '../internal/Token.js'
|
|
21
|
-
import * as Contract from './internal/Contract.js'
|
|
22
|
-
import * as Relative from './internal/Relative.js'
|
|
23
9
|
import * as ThemeRules from '../web/internal/Themes.js'
|
|
24
|
-
import * as
|
|
25
|
-
import * as Source from './Source.js'
|
|
26
|
-
import * as
|
|
27
|
-
import * as
|
|
28
|
-
import * as
|
|
10
|
+
import type * as Native from './Native.js'
|
|
11
|
+
import type * as Source from './Source.js'
|
|
12
|
+
import type * as Transform from './Transform.js'
|
|
13
|
+
import type * as Context from './internal/Context.js'
|
|
14
|
+
import * as Results from './internal/Results.js'
|
|
15
|
+
import * as Stylesheets from './internal/Stylesheets.js'
|
|
29
16
|
|
|
30
17
|
/** Compiles supplied modules with shared theme contracts and dependency metadata. */
|
|
31
18
|
export function compile(options: compile.Options): compile.ReturnType {
|
|
32
|
-
return
|
|
19
|
+
return Results.graph(
|
|
20
|
+
Results.call<Results.Output>('graph.compile', encode(options)),
|
|
21
|
+
)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** The engine's answer when a snapshot names a source it no longer holds. */
|
|
25
|
+
const stale = '{"stale":true}'
|
|
26
|
+
|
|
27
|
+
/** Names each source equal to the one `previous` held as `0`. */
|
|
28
|
+
function unchanged(
|
|
29
|
+
sources: Readonly<Record<string, string>> | undefined,
|
|
30
|
+
previous: Readonly<Record<string, string>> | undefined,
|
|
31
|
+
) {
|
|
32
|
+
if (!sources || !previous) return sources
|
|
33
|
+
|
|
34
|
+
const output: Record<string, string | 0> = {}
|
|
35
|
+
|
|
36
|
+
for (const [id, source] of Object.entries(sources))
|
|
37
|
+
output[id] = previous[id] === source ? 0 : source
|
|
38
|
+
|
|
39
|
+
return output
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** The engine's graph input. */
|
|
43
|
+
function encode(options: compile.Options) {
|
|
44
|
+
return {
|
|
45
|
+
complete: options[ClassName.complete],
|
|
46
|
+
compiler: options.compiler,
|
|
47
|
+
composition: options.composition,
|
|
48
|
+
contracts: options.contracts,
|
|
49
|
+
cssOutput: options.cssOutput,
|
|
50
|
+
development: options.development,
|
|
51
|
+
entry: options[Stylesheets.entry],
|
|
52
|
+
imports: options.imports,
|
|
53
|
+
lean: options[Results.lean],
|
|
54
|
+
modules: options.modules,
|
|
55
|
+
native: options.native && Results.native(options.native),
|
|
56
|
+
reset: options.reset,
|
|
57
|
+
shared: options[ThemeRules.shared],
|
|
58
|
+
}
|
|
33
59
|
}
|
|
34
60
|
|
|
35
61
|
/** Input and output of graph compilation. */
|
|
@@ -48,10 +74,8 @@ export declare namespace compile {
|
|
|
48
74
|
readonly [Stylesheets.entry]?: string | undefined
|
|
49
75
|
/** Lets modules reuse shared rule names from unrelated modules of this one graph. */
|
|
50
76
|
readonly [ClassName.complete]?: boolean | undefined
|
|
51
|
-
/**
|
|
52
|
-
readonly [
|
|
53
|
-
| ReadonlyMap<string, Parser.ParseResult>
|
|
54
|
-
| undefined
|
|
77
|
+
/** Leaves out per-module records and publishes only configuration catalogs as contracts. */
|
|
78
|
+
readonly [Results.lean]?: boolean | undefined
|
|
55
79
|
/** Rewrite authoring calls. False emits CSS for unchanged source. */
|
|
56
80
|
readonly compiler?: boolean | undefined
|
|
57
81
|
/** Whether compiled applications can be combined with one another. */
|
|
@@ -68,10 +92,7 @@ export declare namespace compile {
|
|
|
68
92
|
| undefined
|
|
69
93
|
/** Native output context. Omit to compile web modules and CSS. */
|
|
70
94
|
readonly native?:
|
|
71
|
-
| Omit<
|
|
72
|
-
Native.compile.Options,
|
|
73
|
-
'moduleId' | 'source' | typeof Themes.context
|
|
74
|
-
>
|
|
95
|
+
| Omit<Native.compile.Options, 'moduleId' | 'source' | typeof Context.key>
|
|
75
96
|
| undefined
|
|
76
97
|
/** Complete source graph keyed by stable package-relative module identities. */
|
|
77
98
|
readonly modules: Readonly<Record<string, string>>
|
|
@@ -104,1920 +125,58 @@ export declare namespace compile {
|
|
|
104
125
|
|
|
105
126
|
/** Creates an isolated compiler with bounded extraction reuse across source graphs. */
|
|
106
127
|
export function create(): create.ReturnType {
|
|
107
|
-
|
|
128
|
+
const decoded = new Map<string, Transform.compile.ReturnType>()
|
|
129
|
+
// The engine compiler owns the caches, and collecting this object releases them.
|
|
130
|
+
let engine: InstanceType<Addon.Exports['Graph']> | undefined
|
|
131
|
+
let result: compile.ReturnType | undefined
|
|
132
|
+
// The engine holds the sources of its last decoded snapshot, so a source equal to the one sent
|
|
133
|
+
// last crosses the boundary as `0`. A failed call leaves nothing sent, which resends every source.
|
|
134
|
+
let sent: Pick<ReturnType<typeof encode>, 'contracts' | 'modules'> | undefined
|
|
108
135
|
|
|
109
136
|
return Object.freeze({
|
|
110
137
|
compile(options: compile.Options): compile.ReturnType {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
previous = next
|
|
114
|
-
|
|
115
|
-
return next.result
|
|
116
|
-
},
|
|
117
|
-
})
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/** Incremental graph compiler contracts. */
|
|
121
|
-
export declare namespace create {
|
|
122
|
-
/** Explicitly owned compilation state; dropping the compiler releases its cache. */
|
|
123
|
-
type ReturnType = {
|
|
124
|
-
/** Compiles a complete source snapshot, reusing unaffected work across calls. */
|
|
125
|
-
readonly compile: typeof compile
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
type Extraction = {
|
|
130
|
-
dependencies: readonly string[]
|
|
131
|
-
extracted: Source.extract.ReturnType
|
|
132
|
-
inputs: ReadonlyMap<
|
|
133
|
-
string,
|
|
134
|
-
Source.extract.ReturnType | ReturnType<typeof Contract.read>
|
|
135
|
-
>
|
|
136
|
-
resolution: string
|
|
137
|
-
source: string
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
type Transformed = {
|
|
141
|
-
classes: Readonly<Record<string, string | undefined>>
|
|
142
|
-
extracted: Source.extract.ReturnType
|
|
143
|
-
owners: string
|
|
144
|
-
output: Transform.compile.ReturnType
|
|
145
|
-
schemes: boolean
|
|
146
|
-
themes: Readonly<Record<string, Theme.Definition>>
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
type Cache = {
|
|
150
|
-
compiler: boolean
|
|
151
|
-
composition: Css.compile.Options['composition']
|
|
152
|
-
cssOutput: Css.compile.Options['cssOutput']
|
|
153
|
-
|
|
154
|
-
contracts: string
|
|
155
|
-
development: boolean
|
|
156
|
-
entry: string | undefined
|
|
157
|
-
extracted: ReadonlyMap<string, Source.extract.ReturnType>
|
|
158
|
-
libraries: Readonly<Record<string, ReturnType<typeof Contract.read>>>
|
|
159
|
-
reset: string | undefined
|
|
160
|
-
retained: ReadonlyMap<string, Extraction>
|
|
161
|
-
transformed: ReadonlyMap<string, Transformed>
|
|
162
|
-
resolutions: Readonly<Record<string, string>>
|
|
163
|
-
native: compile.Options['native']
|
|
164
|
-
result: compile.ReturnType
|
|
165
|
-
schemes: boolean
|
|
166
|
-
shared?: 'all' | 'defaults' | undefined
|
|
167
|
-
sources: Readonly<Record<string, string>>
|
|
168
|
-
themes: Readonly<Record<string, Theme.Definition>>
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
function build(options: compile.Options, cache?: Cache): Cache {
|
|
172
|
-
if (
|
|
173
|
-
!!cache?.native !== !!options.native ||
|
|
174
|
-
cache?.native?.[Edits.runtime] !== options.native?.[Edits.runtime] ||
|
|
175
|
-
Object.keys(cache?.native ?? {}).length !==
|
|
176
|
-
Object.keys(options.native ?? {}).length ||
|
|
177
|
-
Object.entries(cache?.native ?? {}).some(([key, value]) => {
|
|
178
|
-
const next = Reflect.get(options.native ?? {}, key)
|
|
179
|
-
if (key !== 'fonts' && key !== 'vars' && key !== 'units')
|
|
180
|
-
return value !== next
|
|
181
|
-
|
|
182
|
-
return (
|
|
183
|
-
!!value !== !!next ||
|
|
184
|
-
Object.keys(value ?? {}).length !== Object.keys(next ?? {}).length ||
|
|
185
|
-
Object.entries(value ?? {}).some(
|
|
186
|
-
([name, entry]) => Reflect.get(next ?? {}, name) !== entry,
|
|
187
|
-
)
|
|
188
|
-
)
|
|
189
|
-
})
|
|
190
|
-
)
|
|
191
|
-
cache = undefined
|
|
192
|
-
if (options.native && options.reset !== undefined)
|
|
193
|
-
throw new Native.CompileError(
|
|
194
|
-
'The CSS reset is only supported by web builds.',
|
|
195
|
-
)
|
|
196
|
-
if (options.native && options.compiler === false)
|
|
197
|
-
throw new Native.CompileError(
|
|
198
|
-
'Native graph compilation requires source rewriting.',
|
|
199
|
-
)
|
|
200
|
-
if (cache?.compiler !== (options.compiler !== false)) cache = undefined
|
|
201
|
-
if (cache?.reset !== options.reset) cache = undefined
|
|
202
|
-
if (cache?.cssOutput !== options.cssOutput) cache = undefined
|
|
203
|
-
if (cache?.composition !== options.composition) cache = undefined
|
|
204
|
-
if (cache?.shared !== options[ThemeRules.shared]) cache = undefined
|
|
205
|
-
if (
|
|
206
|
-
(cache?.entry === undefined) !==
|
|
207
|
-
(options[Stylesheets.entry] === undefined)
|
|
208
|
-
)
|
|
209
|
-
cache = undefined
|
|
210
|
-
const ids = Object.keys(options.modules).sort()
|
|
211
|
-
const programs = new Map<string, ReturnType<typeof Syntax.parse>>()
|
|
212
|
-
function parse(input: Syntax.parse.Options) {
|
|
213
|
-
const cached =
|
|
214
|
-
programs.get(input.moduleId) ?? options[Syntax.cache]?.get(input.moduleId)
|
|
215
|
-
if (cached) return cached
|
|
216
|
-
const parsed = Syntax.parse(input)
|
|
217
|
-
programs.set(input.moduleId, parsed)
|
|
218
|
-
return parsed
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
const contracts = JSON.stringify(
|
|
222
|
-
Object.entries(options.contracts ?? {}).sort(([a], [b]) =>
|
|
223
|
-
a.localeCompare(b),
|
|
224
|
-
),
|
|
225
|
-
)
|
|
226
|
-
|
|
227
|
-
const resolutions = Object.fromEntries(
|
|
228
|
-
[...new Set([...ids, ...Object.keys(options.imports ?? {})])]
|
|
229
|
-
.sort()
|
|
230
|
-
.map((id) => [
|
|
231
|
-
id,
|
|
232
|
-
options.imports === undefined
|
|
233
|
-
? 'relative'
|
|
234
|
-
: JSON.stringify(
|
|
235
|
-
Object.entries(options.imports[id] ?? {}).sort(([a], [b]) =>
|
|
236
|
-
a.localeCompare(b),
|
|
237
|
-
),
|
|
238
|
-
),
|
|
239
|
-
]),
|
|
240
|
-
)
|
|
241
|
-
|
|
242
|
-
// Host resolutions remain explicit when generated modules enter or leave the graph.
|
|
243
|
-
const previous = (() => {
|
|
244
|
-
if (
|
|
245
|
-
cache &&
|
|
246
|
-
cache.contracts === contracts &&
|
|
247
|
-
cache.development === !!options.development &&
|
|
248
|
-
(options.imports !== undefined ||
|
|
249
|
-
(ids.length === Object.keys(cache.sources).length &&
|
|
250
|
-
ids.every((id) => Object.hasOwn(cache.sources, id))))
|
|
251
|
-
) {
|
|
252
|
-
return cache
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
return undefined
|
|
256
|
-
})()
|
|
257
|
-
if (
|
|
258
|
-
previous &&
|
|
259
|
-
previous.entry === options[Stylesheets.entry] &&
|
|
260
|
-
ids.length === Object.keys(previous.sources).length &&
|
|
261
|
-
Object.keys(resolutions).length ===
|
|
262
|
-
Object.keys(previous.resolutions).length &&
|
|
263
|
-
Object.entries(resolutions).every(
|
|
264
|
-
([id, value]) => value === previous.resolutions[id],
|
|
265
|
-
) &&
|
|
266
|
-
ids.every(
|
|
267
|
-
(id) =>
|
|
268
|
-
options.modules[id] === previous.sources[id] &&
|
|
269
|
-
resolutions[id] === previous.resolutions[id],
|
|
270
|
-
)
|
|
271
|
-
)
|
|
272
|
-
return previous
|
|
273
|
-
|
|
274
|
-
const retained = new Map(previous?.retained)
|
|
275
|
-
const transformed = new Map(previous?.transformed)
|
|
276
|
-
const dependencies: Record<string, readonly string[]> = Object.create(null)
|
|
277
|
-
const extracted = new Map<string, Source.extract.ReturnType>()
|
|
278
|
-
const identifiers = new Map<string, Set<string>>()
|
|
279
|
-
const owners: Record<string, NonNullable<Themes.Context['owners']>[string]> =
|
|
280
|
-
Object.create(null)
|
|
281
|
-
const themes: Record<string, Theme.Definition> = Object.create(null)
|
|
282
|
-
const visiting = new Set<string>()
|
|
283
|
-
const libraries: Record<
|
|
284
|
-
string,
|
|
285
|
-
ReturnType<typeof Contract.read>
|
|
286
|
-
> = Object.create(null)
|
|
287
|
-
const identities = new Map<string, Token.Contract>()
|
|
288
|
-
const variableSlots = new Map<
|
|
289
|
-
string,
|
|
290
|
-
{ owner: string; binding: string; type: string }
|
|
291
|
-
>()
|
|
292
|
-
|
|
293
|
-
function validateLibraryLink(link: Themes.Link, owner: string) {
|
|
294
|
-
const variableOwner = owner.includes('/')
|
|
295
|
-
? (link.call.variableOwner ?? owner)
|
|
296
|
-
: owner
|
|
297
|
-
|
|
298
|
-
for (const slot of Object.values(link.call.variables ?? {})) {
|
|
299
|
-
const previous = variableSlots.get(slot.name)
|
|
300
|
-
if (
|
|
301
|
-
previous &&
|
|
302
|
-
(previous.owner !== variableOwner ||
|
|
303
|
-
previous.binding !== link.binding ||
|
|
304
|
-
previous.type !== slot.type)
|
|
305
|
-
)
|
|
306
|
-
throw new Error(
|
|
307
|
-
`Conflicting packed variable identity: ${slot.name}; supply distinct declaration ids.`,
|
|
308
|
-
)
|
|
309
|
-
|
|
310
|
-
variableSlots.set(slot.name, {
|
|
311
|
-
owner: variableOwner,
|
|
312
|
-
binding: link.binding,
|
|
313
|
-
type: slot.type,
|
|
314
|
-
})
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
for (const member of Object.values(link.members ?? {}))
|
|
318
|
-
validateLibraryLink(member, owner)
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
for (const [id, source] of Object.entries(options.contracts ?? {})) {
|
|
322
|
-
if (Object.hasOwn(options.modules, id))
|
|
323
|
-
fail(id, 'A module cannot supply both source and a library contract.')
|
|
324
|
-
|
|
325
|
-
try {
|
|
326
|
-
const library =
|
|
327
|
-
previous?.libraries[id] ?? Contract.read(source, identities, id)
|
|
328
|
-
|
|
329
|
-
for (const link of Object.values(library.links))
|
|
330
|
-
validateLibraryLink(link, id)
|
|
331
|
-
|
|
332
|
-
for (const [name, theme] of Object.entries(library.themes)) {
|
|
333
|
-
if (
|
|
334
|
-
themes[name] &&
|
|
335
|
-
Contract.write({}, { [name]: themes[name]! }) !==
|
|
336
|
-
Contract.write({}, { [name]: theme })
|
|
337
|
-
)
|
|
338
|
-
throw new Error(`Conflicting library theme identity: ${name}`)
|
|
339
|
-
|
|
340
|
-
themes[name] = theme
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
libraries[id] = library
|
|
344
|
-
} catch (error) {
|
|
345
|
-
fail(id, `Invalid library contract: ${(error as Error).message}`)
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
function fail(
|
|
350
|
-
moduleId: string,
|
|
351
|
-
message: string,
|
|
352
|
-
node?: Pick<Ast.Node, 'start' | 'end'>,
|
|
353
|
-
): never {
|
|
354
|
-
throw new Source.ExtractError([
|
|
355
|
-
{
|
|
356
|
-
code: 'unsupported_syntax',
|
|
357
|
-
end: node?.end ?? 0,
|
|
358
|
-
message,
|
|
359
|
-
source: moduleId,
|
|
360
|
-
start: node?.start ?? 0,
|
|
361
|
-
},
|
|
362
|
-
])
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
function resolve(
|
|
366
|
-
moduleId: string,
|
|
367
|
-
specifier: string,
|
|
368
|
-
node: Pick<Ast.Node, 'start' | 'end'> = { start: 0, end: 0 },
|
|
369
|
-
): string | undefined {
|
|
370
|
-
if (options.imports !== undefined) {
|
|
371
|
-
const imports = options.imports[moduleId]
|
|
372
|
-
|
|
373
|
-
if (!imports || !Object.hasOwn(imports, specifier))
|
|
374
|
-
fail(moduleId, `Missing host resolution: ${specifier}`, node)
|
|
375
|
-
|
|
376
|
-
const target = imports[specifier]
|
|
377
|
-
if (target === null) return undefined
|
|
378
|
-
|
|
379
|
-
if (
|
|
380
|
-
target === undefined ||
|
|
381
|
-
(!Object.hasOwn(options.modules, target) &&
|
|
382
|
-
!Object.hasOwn(libraries, target))
|
|
383
|
-
)
|
|
384
|
-
fail(moduleId, `Missing host source module: ${specifier}`, node)
|
|
385
|
-
|
|
386
|
-
return target
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
try {
|
|
390
|
-
return Relative.resolve({ moduleId, modules: options.modules, specifier })
|
|
391
|
-
} catch (error) {
|
|
392
|
-
fail(moduleId, (error as Error).message, node)
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
const constants = new Map<string, Ast.Node | undefined>()
|
|
397
|
-
function constant(
|
|
398
|
-
moduleId: string,
|
|
399
|
-
name: string,
|
|
400
|
-
active = new Set<string>(),
|
|
401
|
-
): Ast.Node | undefined {
|
|
402
|
-
const key = JSON.stringify([moduleId, name])
|
|
403
|
-
if (constants.has(key)) return constants.get(key)
|
|
404
|
-
if (active.has(key) || !Object.hasOwn(options.modules, moduleId))
|
|
405
|
-
return undefined
|
|
406
|
-
const next = new Set(active).add(key)
|
|
407
|
-
const program = parse({
|
|
408
|
-
moduleId,
|
|
409
|
-
source: options.modules[moduleId]!,
|
|
410
|
-
}).program
|
|
411
|
-
const imports: Record<string, Ast.Node> = Object.create(null)
|
|
412
|
-
let local = name
|
|
413
|
-
let exported = false
|
|
414
|
-
let direct: Ast.Node | undefined
|
|
415
|
-
const stars: string[] = []
|
|
416
|
-
for (const statement of program.body) {
|
|
417
|
-
if (statement.type === 'ExportDefaultDeclaration' && name === 'default') {
|
|
418
|
-
direct = statement.declaration
|
|
419
|
-
exported = true
|
|
420
|
-
}
|
|
421
|
-
if (
|
|
422
|
-
statement.type === 'ExportAllDeclaration' &&
|
|
423
|
-
statement.exportKind !== 'type' &&
|
|
424
|
-
!statement.exported &&
|
|
425
|
-
name !== 'default'
|
|
426
|
-
) {
|
|
427
|
-
const target = resolve(moduleId, statement.source.value, statement)
|
|
428
|
-
if (target) stars.push(target)
|
|
429
|
-
}
|
|
430
|
-
if (
|
|
431
|
-
statement.type !== 'ExportNamedDeclaration' ||
|
|
432
|
-
statement.exportKind === 'type'
|
|
433
|
-
)
|
|
434
|
-
continue
|
|
435
|
-
if (statement.declaration?.type === 'VariableDeclaration')
|
|
436
|
-
exported ||= statement.declaration.declarations.some(
|
|
437
|
-
(value) => value.id.type === 'Identifier' && value.id.name === name,
|
|
438
|
-
)
|
|
439
|
-
for (const specifier of statement.specifiers) {
|
|
440
|
-
if (specifier.exportKind === 'type') continue
|
|
441
|
-
const alias =
|
|
442
|
-
specifier.exported.type === 'Identifier'
|
|
443
|
-
? specifier.exported.name
|
|
444
|
-
: specifier.exported.value
|
|
445
|
-
if (alias !== name) continue
|
|
446
|
-
local =
|
|
447
|
-
specifier.local.type === 'Identifier'
|
|
448
|
-
? specifier.local.name
|
|
449
|
-
: specifier.local.value
|
|
450
|
-
if (statement.source) {
|
|
451
|
-
const target = resolve(moduleId, statement.source.value, statement)
|
|
452
|
-
return target ? constant(target, local, next) : undefined
|
|
453
|
-
}
|
|
454
|
-
exported = true
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
if (!exported) {
|
|
458
|
-
const candidates = [
|
|
459
|
-
...new Set(
|
|
460
|
-
stars
|
|
461
|
-
.map((target) => constant(target, name, next))
|
|
462
|
-
.filter((value) => value !== undefined),
|
|
463
|
-
),
|
|
464
|
-
]
|
|
465
|
-
const value = candidates.length === 1 ? candidates[0] : undefined
|
|
466
|
-
if (value || !stars.length) constants.set(key, value)
|
|
467
|
-
return value
|
|
468
|
-
}
|
|
469
|
-
if (
|
|
470
|
-
direct &&
|
|
471
|
-
[
|
|
472
|
-
'FunctionDeclaration',
|
|
473
|
-
'FunctionExpression',
|
|
474
|
-
'ArrowFunctionExpression',
|
|
475
|
-
'ClassDeclaration',
|
|
476
|
-
'ClassExpression',
|
|
477
|
-
].includes(direct.type)
|
|
478
|
-
) {
|
|
479
|
-
constants.set(key, undefined)
|
|
480
|
-
return undefined
|
|
481
|
-
}
|
|
482
|
-
for (const statement of program.body) {
|
|
483
|
-
if (
|
|
484
|
-
statement.type === 'ImportDeclaration' &&
|
|
485
|
-
statement.importKind !== 'type'
|
|
486
|
-
) {
|
|
487
|
-
const target = resolve(moduleId, statement.source.value, statement)
|
|
488
|
-
if (!target) continue
|
|
489
|
-
for (const specifier of statement.specifiers) {
|
|
490
|
-
if (
|
|
491
|
-
specifier.type === 'ImportNamespaceSpecifier' ||
|
|
492
|
-
(specifier.type === 'ImportSpecifier' &&
|
|
493
|
-
specifier.importKind === 'type')
|
|
494
|
-
)
|
|
495
|
-
continue
|
|
496
|
-
const imported =
|
|
497
|
-
specifier.type === 'ImportDefaultSpecifier'
|
|
498
|
-
? 'default'
|
|
499
|
-
: specifier.imported.type === 'Identifier'
|
|
500
|
-
? specifier.imported.name
|
|
501
|
-
: specifier.imported.value
|
|
502
|
-
const value = constant(target, imported, next)
|
|
503
|
-
if (value) imports[specifier.local.name] = relocate(value, specifier)
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
const scope = new Scope.Tracker({ preserveExitedScopes: true })
|
|
508
|
-
Walker.walk(program, { scopeTracker: scope })
|
|
509
|
-
scope.freeze()
|
|
510
|
-
let value: Ast.Node | undefined
|
|
511
|
-
try {
|
|
512
|
-
const data = Static.collect(program, scope, imports)
|
|
513
|
-
value = direct
|
|
514
|
-
? data.normalize(direct, new Set(), new Set(), true)
|
|
515
|
-
: data.exported(local)
|
|
516
|
-
} catch {
|
|
517
|
-
return undefined
|
|
518
|
-
}
|
|
519
|
-
if (value && !literal(value)) value = undefined
|
|
520
|
-
constants.set(key, value)
|
|
521
|
-
return value
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
function literal(node: Ast.Node, depth = 0): boolean {
|
|
525
|
-
if (depth > 64) return false
|
|
526
|
-
if (node.type === 'Literal')
|
|
527
|
-
return (
|
|
528
|
-
node.value === null ||
|
|
529
|
-
['string', 'number', 'boolean'].includes(typeof node.value)
|
|
530
|
-
)
|
|
531
|
-
if (node.type === 'UnaryExpression')
|
|
532
|
-
return (
|
|
533
|
-
['+', '-'].includes(node.operator) &&
|
|
534
|
-
node.argument.type === 'Literal' &&
|
|
535
|
-
typeof node.argument.value === 'number'
|
|
536
|
-
)
|
|
537
|
-
if (node.type === 'TemplateLiteral') return !node.expressions.length
|
|
538
|
-
if (node.type === 'ArrayExpression')
|
|
539
|
-
return node.elements.every((value) => value && literal(value, depth + 1))
|
|
540
|
-
return (
|
|
541
|
-
node.type === 'ObjectExpression' &&
|
|
542
|
-
node.properties.every(
|
|
543
|
-
(property) =>
|
|
544
|
-
property.type === 'Property' &&
|
|
545
|
-
!property.method &&
|
|
546
|
-
property.kind === 'init' &&
|
|
547
|
-
(!property.computed || property.key.type === 'Literal') &&
|
|
548
|
-
literal(property.value, depth + 1),
|
|
549
|
-
)
|
|
550
|
-
)
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
function relocate(
|
|
554
|
-
node: Ast.Node,
|
|
555
|
-
span: Pick<Ast.Node, 'start' | 'end'>,
|
|
556
|
-
): Ast.Node {
|
|
557
|
-
const copy = structuredClone(node)
|
|
558
|
-
Walker.walk(copy, {
|
|
559
|
-
enter(node) {
|
|
560
|
-
node.start = span.start
|
|
561
|
-
node.end = span.end
|
|
562
|
-
},
|
|
563
|
-
})
|
|
564
|
-
return copy
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
const factoryPrograms = new Map<string, Ast.Program>()
|
|
568
|
-
function factory(
|
|
569
|
-
moduleId: string,
|
|
570
|
-
name: string,
|
|
571
|
-
seen = new Set<string>(),
|
|
572
|
-
): string | undefined {
|
|
573
|
-
if (moduleId === 'zyzz/web')
|
|
574
|
-
return Contributions.factories.includes(name) ? name : undefined
|
|
575
|
-
const key = `${moduleId}#${name}`
|
|
576
|
-
if (seen.has(key) || !Object.hasOwn(options.modules, moduleId))
|
|
577
|
-
return undefined
|
|
578
|
-
const next = new Set(seen).add(key)
|
|
579
|
-
const program =
|
|
580
|
-
factoryPrograms.get(moduleId) ??
|
|
581
|
-
Parser.parseSync('barrel.ts', options.modules[moduleId]!, {
|
|
582
|
-
sourceType: 'module',
|
|
583
|
-
}).program
|
|
584
|
-
factoryPrograms.set(moduleId, program)
|
|
585
|
-
const target = (specifier: string, node: Ast.Node) =>
|
|
586
|
-
specifier === 'zyzz/web' ? specifier : resolve(moduleId, specifier, node)
|
|
587
|
-
for (const node of program.body) {
|
|
588
|
-
if (node.type !== 'ExportNamedDeclaration' || node.exportKind === 'type')
|
|
589
|
-
continue
|
|
590
|
-
const declaration = node.declaration
|
|
591
|
-
if (
|
|
592
|
-
declaration?.type === 'VariableDeclaration' &&
|
|
593
|
-
declaration.declarations.some(
|
|
594
|
-
(item) => item.id.type === 'Identifier' && item.id.name === name,
|
|
595
|
-
)
|
|
596
|
-
)
|
|
597
|
-
return undefined
|
|
598
|
-
if (
|
|
599
|
-
(declaration?.type === 'FunctionDeclaration' ||
|
|
600
|
-
declaration?.type === 'ClassDeclaration') &&
|
|
601
|
-
declaration.id?.name === name
|
|
602
|
-
)
|
|
603
|
-
return undefined
|
|
604
|
-
for (const specifier of node.specifiers) {
|
|
605
|
-
if (specifier.exportKind === 'type') continue
|
|
606
|
-
const exported =
|
|
607
|
-
specifier.exported.type === 'Identifier'
|
|
608
|
-
? specifier.exported.name
|
|
609
|
-
: specifier.exported.value
|
|
610
|
-
if (exported !== name) continue
|
|
611
|
-
const local =
|
|
612
|
-
specifier.local.type === 'Identifier'
|
|
613
|
-
? specifier.local.name
|
|
614
|
-
: specifier.local.value
|
|
615
|
-
if (node.source) {
|
|
616
|
-
const id = target(node.source.value, node)
|
|
617
|
-
return id ? factory(id, local, next) : undefined
|
|
618
|
-
}
|
|
619
|
-
for (const declaration of program.body) {
|
|
620
|
-
if (
|
|
621
|
-
declaration.type !== 'ImportDeclaration' ||
|
|
622
|
-
declaration.importKind === 'type'
|
|
623
|
-
)
|
|
624
|
-
continue
|
|
625
|
-
for (const imported of declaration.specifiers) {
|
|
626
|
-
if (
|
|
627
|
-
imported.type !== 'ImportSpecifier' ||
|
|
628
|
-
imported.importKind === 'type' ||
|
|
629
|
-
imported.local.name !== local
|
|
630
|
-
)
|
|
631
|
-
continue
|
|
632
|
-
const id = target(declaration.source.value, declaration)
|
|
633
|
-
return id
|
|
634
|
-
? factory(
|
|
635
|
-
id,
|
|
636
|
-
imported.imported.type === 'Identifier'
|
|
637
|
-
? imported.imported.name
|
|
638
|
-
: imported.imported.value,
|
|
639
|
-
next,
|
|
640
|
-
)
|
|
641
|
-
: undefined
|
|
642
|
-
}
|
|
643
|
-
}
|
|
644
|
-
return undefined
|
|
645
|
-
}
|
|
646
|
-
}
|
|
647
|
-
for (const node of program.body) {
|
|
648
|
-
if (
|
|
649
|
-
node.type === 'ExportAllDeclaration' &&
|
|
650
|
-
node.exportKind !== 'type' &&
|
|
651
|
-
!node.exported
|
|
652
|
-
) {
|
|
653
|
-
const id = target(node.source.value, node)
|
|
654
|
-
const found = id ? factory(id, name, next) : undefined
|
|
655
|
-
if (found) return found
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
return undefined
|
|
659
|
-
}
|
|
660
|
-
function visit(moduleId: string): Source.extract.ReturnType {
|
|
661
|
-
const cached = extracted.get(moduleId)
|
|
662
|
-
if (cached) return cached
|
|
663
|
-
|
|
664
|
-
if (visiting.has(moduleId))
|
|
665
|
-
fail(moduleId, 'Circular source dependencies are not supported yet.')
|
|
666
|
-
|
|
667
|
-
visiting.add(moduleId)
|
|
668
|
-
|
|
669
|
-
const source = options.modules[moduleId]!
|
|
670
|
-
|
|
671
|
-
const snapshot =
|
|
672
|
-
previous?.retained.get(moduleId) ??
|
|
673
|
-
(previous && Object.hasOwn(previous.sources, moduleId)
|
|
674
|
-
? {
|
|
675
|
-
dependencies: previous.result.dependencies[moduleId]!,
|
|
676
|
-
extracted: previous.extracted.get(moduleId)!,
|
|
677
|
-
inputs: new Map(
|
|
678
|
-
previous.result.dependencies[moduleId]!.map((target) => [
|
|
679
|
-
target,
|
|
680
|
-
previous.libraries[target] ?? previous.extracted.get(target)!,
|
|
681
|
-
]),
|
|
682
|
-
),
|
|
683
|
-
resolution: previous.resolutions[moduleId]!,
|
|
684
|
-
source: previous.sources[moduleId]!,
|
|
685
|
-
}
|
|
686
|
-
: undefined)
|
|
687
|
-
if (
|
|
688
|
-
snapshot &&
|
|
689
|
-
source === snapshot.source &&
|
|
690
|
-
resolutions[moduleId] === snapshot.resolution &&
|
|
691
|
-
snapshot.dependencies.every((target) =>
|
|
692
|
-
Object.hasOwn(libraries, target)
|
|
693
|
-
? libraries[target] === snapshot.inputs.get(target)
|
|
694
|
-
: Object.hasOwn(options.modules, target) &&
|
|
695
|
-
visit(target) === snapshot.inputs.get(target),
|
|
696
|
-
)
|
|
697
|
-
) {
|
|
698
|
-
return retain(moduleId, snapshot.extracted, snapshot.dependencies)
|
|
699
|
-
}
|
|
700
|
-
|
|
701
|
-
// Validate identity and syntax through the public source boundary before linking.
|
|
702
|
-
Source.extract({ moduleId, source: '' })
|
|
703
|
-
|
|
704
|
-
const parsed = parse({ moduleId, source })
|
|
705
|
-
|
|
706
|
-
if (parsed.errors.length) Source.extract({ moduleId, source })
|
|
707
|
-
factoryPrograms.set(moduleId, parsed.program)
|
|
708
|
-
|
|
709
|
-
const names = new Set<string>()
|
|
710
|
-
identifiers.set(moduleId, names)
|
|
711
|
-
Walker.walk(parsed.program, {
|
|
712
|
-
enter(node) {
|
|
713
|
-
if (node.type === 'Identifier') names.add(node.name)
|
|
714
|
-
if (
|
|
715
|
-
options.imports === undefined &&
|
|
716
|
-
node.type === 'ImportExpression' &&
|
|
717
|
-
(node.source.type !== 'Literal' ||
|
|
718
|
-
typeof node.source.value !== 'string' ||
|
|
719
|
-
node.source.value.startsWith('.'))
|
|
720
|
-
)
|
|
721
|
-
fail(
|
|
722
|
-
moduleId,
|
|
723
|
-
'Source graph dependencies require static imports.',
|
|
724
|
-
node,
|
|
725
|
-
)
|
|
726
|
-
},
|
|
727
|
-
})
|
|
728
|
-
|
|
729
|
-
const values: Record<string, Ast.Node> = Object.create(null)
|
|
730
|
-
const links: Record<string, Themes.Link> = Object.create(null)
|
|
731
|
-
const forwarded: Record<string, Themes.Link> = Object.create(null)
|
|
732
|
-
const explicit = new Set<string>()
|
|
733
|
-
const stars: Readonly<Record<string, Themes.Link>>[] = []
|
|
734
|
-
const imports = new Set<string>()
|
|
735
|
-
|
|
736
|
-
function exportedBindings(node: Ast.Node) {
|
|
737
|
-
if (node.type === 'Identifier') explicit.add(node.name)
|
|
738
|
-
else if (node.type === 'ObjectPattern')
|
|
739
|
-
for (const property of node.properties)
|
|
740
|
-
exportedBindings(
|
|
741
|
-
property.type === 'Property' ? property.value : property.argument,
|
|
742
|
-
)
|
|
743
|
-
else if (node.type === 'ArrayPattern')
|
|
744
|
-
for (const element of node.elements) {
|
|
745
|
-
if (element) exportedBindings(element)
|
|
746
|
-
}
|
|
747
|
-
else if (node.type === 'AssignmentPattern') exportedBindings(node.left)
|
|
748
|
-
else if (node.type === 'RestElement') exportedBindings(node.argument)
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
for (const node of parsed.program.body) {
|
|
752
|
-
if (
|
|
753
|
-
node.type === 'ExportNamedDeclaration' &&
|
|
754
|
-
!node.source &&
|
|
755
|
-
node.exportKind !== 'type'
|
|
756
|
-
) {
|
|
757
|
-
for (const specifier of node.specifiers)
|
|
758
|
-
if (specifier.exportKind !== 'type')
|
|
759
|
-
explicit.add(
|
|
760
|
-
specifier.exported.type === 'Identifier'
|
|
761
|
-
? specifier.exported.name
|
|
762
|
-
: specifier.exported.value,
|
|
763
|
-
)
|
|
764
|
-
|
|
765
|
-
if (node.declaration?.type === 'VariableDeclaration')
|
|
766
|
-
for (const declaration of node.declaration.declarations)
|
|
767
|
-
exportedBindings(declaration.id)
|
|
768
|
-
else if (
|
|
769
|
-
(node.declaration?.type === 'FunctionDeclaration' ||
|
|
770
|
-
node.declaration?.type === 'ClassDeclaration') &&
|
|
771
|
-
node.declaration.id
|
|
772
|
-
)
|
|
773
|
-
explicit.add(node.declaration.id.name)
|
|
774
|
-
}
|
|
775
|
-
|
|
776
|
-
if (
|
|
777
|
-
(node.type !== 'ImportDeclaration' &&
|
|
778
|
-
node.type !== 'ExportNamedDeclaration' &&
|
|
779
|
-
node.type !== 'ExportAllDeclaration') ||
|
|
780
|
-
!node.source
|
|
781
|
-
)
|
|
782
|
-
continue
|
|
783
|
-
|
|
784
|
-
if (
|
|
785
|
-
node.type === 'ImportDeclaration'
|
|
786
|
-
? node.importKind === 'type'
|
|
787
|
-
: node.exportKind === 'type'
|
|
788
|
-
)
|
|
789
|
-
continue
|
|
790
|
-
|
|
791
|
-
if (
|
|
792
|
-
'specifiers' in node &&
|
|
793
|
-
node.specifiers.length &&
|
|
794
|
-
node.specifiers.every((specifier) =>
|
|
795
|
-
specifier.type === 'ImportSpecifier'
|
|
796
|
-
? specifier.importKind === 'type'
|
|
797
|
-
: specifier.type === 'ExportSpecifier' &&
|
|
798
|
-
specifier.exportKind === 'type',
|
|
799
|
-
)
|
|
800
|
-
)
|
|
801
|
-
continue
|
|
802
|
-
|
|
803
|
-
const target = resolve(moduleId, node.source.value, node)
|
|
804
|
-
if (!target) continue
|
|
805
|
-
|
|
806
|
-
imports.add(target)
|
|
807
|
-
|
|
808
|
-
const contracts =
|
|
809
|
-
libraries[target]?.links ?? visit(target).themeExports ?? {}
|
|
810
|
-
|
|
811
|
-
function namespace(name: string): Themes.Link | undefined {
|
|
812
|
-
const first = Object.values(contracts)[0]
|
|
813
|
-
if (!first) return undefined
|
|
814
|
-
return {
|
|
815
|
-
binding: `z-style-${Identity.hash(JSON.stringify([moduleId, name]))}-namespace`,
|
|
816
|
-
call: { start: -1, end: -1, name: '', tokenType: '{}' },
|
|
817
|
-
definition: first.definition,
|
|
818
|
-
kind: 'style-reference',
|
|
819
|
-
members: contracts,
|
|
820
|
-
}
|
|
821
|
-
}
|
|
822
|
-
|
|
823
|
-
if (node.type === 'ImportDeclaration') {
|
|
824
|
-
for (const specifier of node.specifiers) {
|
|
825
|
-
if (specifier.type === 'ImportNamespaceSpecifier') {
|
|
826
|
-
if (
|
|
827
|
-
Object.values(contracts).some(
|
|
828
|
-
(link) => link.kind !== 'style-reference',
|
|
829
|
-
)
|
|
830
|
-
)
|
|
831
|
-
fail(
|
|
832
|
-
moduleId,
|
|
833
|
-
'Import theme contracts by name; namespace imports are not supported.',
|
|
834
|
-
specifier,
|
|
835
|
-
)
|
|
836
|
-
|
|
837
|
-
const link = namespace(specifier.local.name)
|
|
838
|
-
if (link) links[specifier.local.name] = link
|
|
839
|
-
continue
|
|
840
|
-
}
|
|
841
|
-
|
|
842
|
-
if (
|
|
843
|
-
specifier.type === 'ImportSpecifier' &&
|
|
844
|
-
specifier.importKind === 'type'
|
|
845
|
-
)
|
|
846
|
-
continue
|
|
847
|
-
|
|
848
|
-
const name = (() => {
|
|
849
|
-
if (specifier.type === 'ImportDefaultSpecifier') {
|
|
850
|
-
return 'default'
|
|
851
|
-
}
|
|
852
|
-
|
|
853
|
-
if (specifier.imported.type === 'Identifier') {
|
|
854
|
-
return specifier.imported.name
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
return specifier.imported.value
|
|
858
|
-
})()
|
|
859
|
-
|
|
860
|
-
if (Object.hasOwn(contracts, name))
|
|
861
|
-
links[specifier.local.name] = contracts[name]!
|
|
862
|
-
else {
|
|
863
|
-
const value = constant(target, name)
|
|
864
|
-
if (value) values[specifier.local.name] = relocate(value, specifier)
|
|
865
|
-
}
|
|
866
|
-
}
|
|
867
|
-
} else if (node.type === 'ExportAllDeclaration') {
|
|
868
|
-
if (node.exported) {
|
|
869
|
-
if (
|
|
870
|
-
Object.values(contracts).some(
|
|
871
|
-
(link) => link.kind !== 'style-reference',
|
|
872
|
-
)
|
|
873
|
-
)
|
|
874
|
-
fail(
|
|
875
|
-
moduleId,
|
|
876
|
-
'Namespace theme re-exports are not supported.',
|
|
877
|
-
node,
|
|
878
|
-
)
|
|
879
|
-
const name =
|
|
880
|
-
node.exported.type === 'Identifier'
|
|
881
|
-
? node.exported.name
|
|
882
|
-
: node.exported.value
|
|
883
|
-
explicit.add(name)
|
|
884
|
-
const link = namespace(name)
|
|
885
|
-
if (link) forwarded[name] = link
|
|
886
|
-
} else stars.push(contracts)
|
|
887
|
-
} else {
|
|
888
|
-
for (const specifier of node.specifiers) {
|
|
889
|
-
if (specifier.exportKind === 'type') continue
|
|
890
|
-
|
|
891
|
-
const name =
|
|
892
|
-
specifier.local.type === 'Identifier'
|
|
893
|
-
? specifier.local.name
|
|
894
|
-
: specifier.local.value
|
|
895
|
-
const exported =
|
|
896
|
-
specifier.exported.type === 'Identifier'
|
|
897
|
-
? specifier.exported.name
|
|
898
|
-
: specifier.exported.value
|
|
899
|
-
|
|
900
|
-
explicit.add(exported)
|
|
901
|
-
|
|
902
|
-
if (Object.hasOwn(contracts, name))
|
|
903
|
-
forwarded[exported] = contracts[name]!
|
|
904
|
-
}
|
|
905
|
-
}
|
|
906
|
-
}
|
|
907
|
-
const factories: Record<string, string> = Object.create(null)
|
|
908
|
-
for (const node of parsed.program.body) {
|
|
909
|
-
if (
|
|
910
|
-
node.type !== 'ImportDeclaration' ||
|
|
911
|
-
node.importKind === 'type' ||
|
|
912
|
-
node.specifiers.every(
|
|
913
|
-
(specifier) =>
|
|
914
|
-
specifier.type === 'ImportSpecifier' &&
|
|
915
|
-
specifier.importKind === 'type',
|
|
916
|
-
) ||
|
|
917
|
-
['zyzz', 'zyzz/web'].includes(node.source.value)
|
|
918
|
-
)
|
|
919
|
-
continue
|
|
920
|
-
const target = resolve(moduleId, node.source.value, node)
|
|
921
|
-
if (!target) continue
|
|
922
|
-
for (const specifier of node.specifiers) {
|
|
923
|
-
if (
|
|
924
|
-
specifier.type !== 'ImportSpecifier' ||
|
|
925
|
-
specifier.importKind === 'type'
|
|
926
|
-
)
|
|
927
|
-
continue
|
|
928
|
-
const name =
|
|
929
|
-
specifier.imported.type === 'Identifier'
|
|
930
|
-
? specifier.imported.name
|
|
931
|
-
: specifier.imported.value
|
|
932
|
-
const found = factory(target, name)
|
|
933
|
-
if (found) factories[specifier.local.name] = found
|
|
934
|
-
}
|
|
935
|
-
}
|
|
936
|
-
|
|
937
|
-
const result = Source.extract({
|
|
938
|
-
target: options.native ? 'native' : 'web',
|
|
939
|
-
compiler: options.compiler,
|
|
940
|
-
moduleId,
|
|
941
|
-
source,
|
|
942
|
-
[Themes.context]: { constants: values, factories, links, parsed },
|
|
943
|
-
})
|
|
944
|
-
|
|
945
|
-
function outputLink(link: Themes.Link): Themes.Link {
|
|
946
|
-
return {
|
|
947
|
-
...link,
|
|
948
|
-
...(link.style
|
|
949
|
-
? {
|
|
950
|
-
style: {
|
|
951
|
-
...link.style,
|
|
952
|
-
style: {
|
|
953
|
-
...link.style.style,
|
|
954
|
-
cssOutput:
|
|
955
|
-
link.style.style.cssOutput ?? options.cssOutput ?? 'atomic',
|
|
956
|
-
},
|
|
957
|
-
},
|
|
958
|
-
}
|
|
959
|
-
: {}),
|
|
960
|
-
...(link.members
|
|
961
|
-
? {
|
|
962
|
-
members: Object.fromEntries(
|
|
963
|
-
Object.entries(link.members).map(([name, member]) => [
|
|
964
|
-
name,
|
|
965
|
-
outputLink(member),
|
|
966
|
-
]),
|
|
967
|
-
),
|
|
968
|
-
}
|
|
969
|
-
: {}),
|
|
970
|
-
}
|
|
971
|
-
}
|
|
972
|
-
|
|
973
|
-
const exports: Record<string, Themes.Link> = Object.assign(
|
|
974
|
-
Object.create(null),
|
|
975
|
-
forwarded,
|
|
976
|
-
Object.fromEntries(
|
|
977
|
-
Object.entries(result.themeExports ?? {}).map(([name, link]) => [
|
|
978
|
-
name,
|
|
979
|
-
outputLink(link),
|
|
980
|
-
]),
|
|
981
|
-
),
|
|
982
|
-
)
|
|
983
|
-
|
|
984
|
-
for (const name of Object.keys(result.themeExports ?? {}))
|
|
985
|
-
explicit.add(name)
|
|
986
|
-
|
|
987
|
-
for (const contracts of stars)
|
|
988
|
-
for (const [name, link] of Object.entries(contracts)) {
|
|
989
|
-
if (name === 'default' || explicit.has(name)) continue
|
|
990
|
-
|
|
991
|
-
const previous = exports[name]
|
|
992
|
-
|
|
993
|
-
if (
|
|
994
|
-
previous &&
|
|
995
|
-
(previous.binding !== link.binding || previous.kind !== link.kind)
|
|
996
|
-
)
|
|
997
|
-
fail(moduleId, `Ambiguous theme re-export: ${name}`)
|
|
998
|
-
|
|
999
|
-
exports[name] = link
|
|
1000
|
-
}
|
|
1001
|
-
|
|
1002
|
-
const linked = Object.freeze({
|
|
1003
|
-
...result,
|
|
1004
|
-
themeExports: Object.freeze(exports),
|
|
1005
|
-
})
|
|
1006
|
-
|
|
1007
|
-
return retain(moduleId, linked, Object.freeze([...imports]))
|
|
1008
|
-
}
|
|
138
|
+
engine ??= new (Addon.load().Graph)()
|
|
1009
139
|
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
result: Source.extract.ReturnType,
|
|
1013
|
-
imports: readonly string[],
|
|
1014
|
-
): Source.extract.ReturnType {
|
|
1015
|
-
for (const call of result.variableCalls ?? [])
|
|
1016
|
-
for (const slot of Object.values(call.slots)) {
|
|
1017
|
-
const owner = moduleId.replace(/\.[cm]?[jt]sx?$/, '')
|
|
1018
|
-
const previous = variableSlots.get(slot.name)
|
|
140
|
+
const input = encode(options)
|
|
141
|
+
const previous = sent
|
|
1019
142
|
|
|
1020
|
-
|
|
1021
|
-
previous &&
|
|
1022
|
-
(previous.owner !== owner || previous.type !== slot.type)
|
|
1023
|
-
)
|
|
1024
|
-
fail(
|
|
1025
|
-
moduleId,
|
|
1026
|
-
`Conflicting variable identity: ${slot.name}; supply distinct declaration ids.`,
|
|
1027
|
-
call,
|
|
1028
|
-
)
|
|
1029
|
-
|
|
1030
|
-
variableSlots.set(slot.name, {
|
|
1031
|
-
owner,
|
|
1032
|
-
binding: `source:${call.start}`,
|
|
1033
|
-
type: slot.type,
|
|
1034
|
-
})
|
|
1035
|
-
}
|
|
1036
|
-
|
|
1037
|
-
extracted.set(moduleId, result)
|
|
1038
|
-
dependencies[moduleId] = imports
|
|
1039
|
-
retained.delete(moduleId)
|
|
1040
|
-
retained.set(moduleId, {
|
|
1041
|
-
dependencies: imports,
|
|
1042
|
-
extracted: result,
|
|
1043
|
-
inputs: new Map(
|
|
1044
|
-
imports.map((target) => [
|
|
1045
|
-
target,
|
|
1046
|
-
libraries[target] ?? extracted.get(target)!,
|
|
1047
|
-
]),
|
|
1048
|
-
),
|
|
1049
|
-
resolution: resolutions[moduleId]!,
|
|
1050
|
-
source: options.modules[moduleId]!,
|
|
1051
|
-
})
|
|
1052
|
-
if (retained.size > 256) retained.delete(retained.keys().next().value!)
|
|
1053
|
-
|
|
1054
|
-
for (const call of result.themeCalls)
|
|
1055
|
-
for (const name of new Set([
|
|
1056
|
-
call.name,
|
|
1057
|
-
...Object.values(call.members ?? {}),
|
|
1058
|
-
]))
|
|
1059
|
-
owners[name] = {
|
|
1060
|
-
call: { ...call, name },
|
|
1061
|
-
moduleId,
|
|
1062
|
-
source: options.modules[moduleId]!,
|
|
1063
|
-
}
|
|
1064
|
-
|
|
1065
|
-
Object.assign(themes, result.vars)
|
|
1066
|
-
visiting.delete(moduleId)
|
|
1067
|
-
|
|
1068
|
-
return result
|
|
1069
|
-
}
|
|
1070
|
-
|
|
1071
|
-
for (const moduleId of ids) visit(moduleId)
|
|
143
|
+
sent = undefined
|
|
1072
144
|
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
function packedLink(link: Themes.Link): Themes.Link {
|
|
1076
|
-
return {
|
|
1077
|
-
...link,
|
|
1078
|
-
...(link.style
|
|
1079
|
-
? { style: { ...link.style, className: link.style.className ?? '' } }
|
|
1080
|
-
: {}),
|
|
1081
|
-
...(link.members
|
|
1082
|
-
? {
|
|
1083
|
-
members: Object.fromEntries(
|
|
1084
|
-
Object.entries(link.members).map(([name, link]) => [
|
|
1085
|
-
name,
|
|
1086
|
-
packedLink(link),
|
|
1087
|
-
]),
|
|
1088
|
-
),
|
|
1089
|
-
}
|
|
1090
|
-
: {}),
|
|
1091
|
-
}
|
|
1092
|
-
}
|
|
1093
|
-
const profiles = new Map<
|
|
1094
|
-
string,
|
|
1095
|
-
{
|
|
1096
|
-
definitions: Map<string, string>
|
|
1097
|
-
reads: Map<number, { name: string; source?: string }>
|
|
1098
|
-
}
|
|
1099
|
-
>()
|
|
1100
|
-
const reserved = new Set(
|
|
1101
|
-
[...identifiers.values()].flatMap((names) => [...names]),
|
|
1102
|
-
)
|
|
1103
|
-
function profile(moduleId: string) {
|
|
1104
|
-
let value = profiles.get(moduleId)
|
|
1105
|
-
if (!value) {
|
|
1106
|
-
value = { definitions: new Map(), reads: new Map() }
|
|
1107
|
-
profiles.set(moduleId, value)
|
|
1108
|
-
}
|
|
1109
|
-
return value
|
|
1110
|
-
}
|
|
145
|
+
const text = (() => {
|
|
146
|
+
if (!previous) return engine.compile(JSON.stringify(input))
|
|
1111
147
|
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
fonts: native.fonts,
|
|
1118
|
-
units: native.units,
|
|
148
|
+
const output = engine.compile(
|
|
149
|
+
JSON.stringify({
|
|
150
|
+
...input,
|
|
151
|
+
contracts: unchanged(input.contracts, previous.contracts),
|
|
152
|
+
modules: unchanged(input.modules, previous.modules),
|
|
1119
153
|
}),
|
|
1120
154
|
)
|
|
1121
|
-
} catch (error) {
|
|
1122
|
-
throw new Native.CompileError((error as Error).message)
|
|
1123
|
-
}
|
|
1124
|
-
}
|
|
1125
|
-
|
|
1126
|
-
function define(owner: string, value: string) {
|
|
1127
|
-
const definitions = profile(owner).definitions
|
|
1128
|
-
let name = definitions.get(value)
|
|
1129
|
-
if (!name) {
|
|
1130
|
-
// Hashing the owner keeps names independent of which modules share the graph.
|
|
1131
|
-
name = `__zyzzProfile${Identity.hash(owner + value)}`
|
|
1132
|
-
while (reserved.has(name)) name += '_'
|
|
1133
|
-
reserved.add(name)
|
|
1134
|
-
definitions.set(value, name)
|
|
1135
|
-
}
|
|
1136
|
-
return name
|
|
1137
|
-
}
|
|
1138
|
-
|
|
1139
|
-
if (ids.some((id) => extracted.get(id)!.nativeVars?.length))
|
|
1140
|
-
NativeStyleSheet.compile({
|
|
1141
|
-
fonts: native.fonts,
|
|
1142
|
-
platform: native.platform,
|
|
1143
|
-
units: native.units,
|
|
1144
|
-
styles: { styles: [] },
|
|
1145
|
-
})
|
|
1146
|
-
|
|
1147
|
-
// Single-file adapters compile each owner without its consumers, so owners publish every exported profile.
|
|
1148
|
-
if (native[Edits.runtime])
|
|
1149
|
-
for (const moduleId of ids)
|
|
1150
|
-
for (const link of Object.values(
|
|
1151
|
-
extracted.get(moduleId)!.themeExports ?? {},
|
|
1152
|
-
)) {
|
|
1153
|
-
if (
|
|
1154
|
-
owners[link.call.name]?.moduleId !== moduleId ||
|
|
1155
|
-
!(
|
|
1156
|
-
link.call.variableSet ||
|
|
1157
|
-
(link.kind === 'config' &&
|
|
1158
|
-
link.call.variableConfig &&
|
|
1159
|
-
!link.call.initialization &&
|
|
1160
|
-
!link.call.root)
|
|
1161
|
-
)
|
|
1162
|
-
)
|
|
1163
|
-
continue
|
|
1164
|
-
const value = (() => {
|
|
1165
|
-
try {
|
|
1166
|
-
return encode(Themes.varsRead(link))
|
|
1167
|
-
} catch {
|
|
1168
|
-
// Consumers that read this profile report the same error.
|
|
1169
|
-
return undefined
|
|
1170
|
-
}
|
|
1171
|
-
})()
|
|
1172
|
-
if (value !== undefined) define(moduleId, value)
|
|
1173
|
-
}
|
|
1174
|
-
|
|
1175
|
-
for (const moduleId of ids) {
|
|
1176
|
-
for (const read of extracted.get(moduleId)!.nativeVars ?? []) {
|
|
1177
|
-
const owner = owners[read.owner]?.moduleId
|
|
1178
|
-
// Packed catalogs without source retain their local fallback.
|
|
1179
|
-
if (!owner || !Object.hasOwn(options.modules, owner)) continue
|
|
1180
155
|
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
? profiles.get(owner)?.definitions.get(value)
|
|
1184
|
-
: define(owner, value)
|
|
1185
|
-
if (!name) continue
|
|
156
|
+
return output === stale ? engine.compile(JSON.stringify(input)) : output
|
|
157
|
+
})()
|
|
1186
158
|
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
if (native[Edits.runtime] && options.imports) {
|
|
1192
|
-
const imports = options.imports[moduleId] ?? {}
|
|
1193
|
-
return Object.keys(imports).find((key) => imports[key] === owner)
|
|
1194
|
-
}
|
|
1195
|
-
|
|
1196
|
-
const from = moduleId.split('/').slice(0, -1)
|
|
1197
|
-
const to = owner.split('/')
|
|
1198
|
-
while (from.length && from[0] === to[0]) {
|
|
1199
|
-
from.shift()
|
|
1200
|
-
to.shift()
|
|
1201
|
-
}
|
|
1202
|
-
return (
|
|
1203
|
-
(from.length ? '../'.repeat(from.length) : './') +
|
|
1204
|
-
to.join('/').replace(/\.([cm]?)tsx?$/, '.$1js')
|
|
1205
|
-
)
|
|
1206
|
-
})()
|
|
1207
|
-
if (owner !== moduleId && !source) continue
|
|
1208
|
-
profile(moduleId).reads.set(read.start, {
|
|
1209
|
-
name,
|
|
1210
|
-
...(source ? { source } : {}),
|
|
1211
|
-
})
|
|
1212
|
-
}
|
|
1213
|
-
}
|
|
1214
|
-
const modules = Object.fromEntries(
|
|
1215
|
-
ids.map((moduleId) => {
|
|
1216
|
-
// Single-file profiles derive only from this module's extraction and its dependencies.
|
|
1217
|
-
if (
|
|
1218
|
-
previous &&
|
|
1219
|
-
(native[Edits.runtime] || !profiles.size) &&
|
|
1220
|
-
extracted.get(moduleId) === previous.extracted.get(moduleId)
|
|
1221
|
-
)
|
|
1222
|
-
return [moduleId, previous.result.modules[moduleId]!]
|
|
1223
|
-
|
|
1224
|
-
const imported: Record<
|
|
1225
|
-
string,
|
|
1226
|
-
Readonly<Record<string, Themes.Link>>
|
|
1227
|
-
> = Object.create(null)
|
|
1228
|
-
for (const statement of parse({
|
|
1229
|
-
moduleId,
|
|
1230
|
-
source: options.modules[moduleId]!,
|
|
1231
|
-
}).program.body) {
|
|
1232
|
-
if (
|
|
1233
|
-
(statement.type !== 'ImportDeclaration' &&
|
|
1234
|
-
statement.type !== 'ExportNamedDeclaration' &&
|
|
1235
|
-
statement.type !== 'ExportAllDeclaration') ||
|
|
1236
|
-
!statement.source
|
|
1237
|
-
)
|
|
1238
|
-
continue
|
|
1239
|
-
if (
|
|
1240
|
-
(statement.type === 'ImportDeclaration' &&
|
|
1241
|
-
statement.importKind === 'type') ||
|
|
1242
|
-
(statement.type !== 'ImportDeclaration' &&
|
|
1243
|
-
statement.exportKind === 'type')
|
|
1244
|
-
)
|
|
1245
|
-
continue
|
|
1246
|
-
if (
|
|
1247
|
-
'specifiers' in statement &&
|
|
1248
|
-
statement.specifiers.length &&
|
|
1249
|
-
statement.specifiers.every((specifier) =>
|
|
1250
|
-
specifier.type === 'ImportSpecifier'
|
|
1251
|
-
? specifier.importKind === 'type'
|
|
1252
|
-
: specifier.type === 'ExportSpecifier' &&
|
|
1253
|
-
specifier.exportKind === 'type',
|
|
1254
|
-
)
|
|
1255
|
-
)
|
|
1256
|
-
continue
|
|
1257
|
-
const target = resolve(moduleId, statement.source.value, statement)
|
|
1258
|
-
if (target && libraries[target])
|
|
1259
|
-
imported[statement.source.value] = libraries[target].links
|
|
1260
|
-
}
|
|
1261
|
-
const output = Native.compile({
|
|
1262
|
-
...native,
|
|
1263
|
-
[NativeVars.shared]: profiles.get(moduleId),
|
|
1264
|
-
moduleId,
|
|
1265
|
-
source: options.modules[moduleId]!,
|
|
1266
|
-
[Themes.context]: {
|
|
1267
|
-
parsed: parse({ moduleId, source: options.modules[moduleId]! }),
|
|
1268
|
-
identifiers: identifiers.get(moduleId),
|
|
1269
|
-
extracted: extracted.get(moduleId)!,
|
|
1270
|
-
libraries: imported,
|
|
1271
|
-
links: {},
|
|
1272
|
-
},
|
|
1273
|
-
})
|
|
1274
|
-
return [moduleId, nativeOutput(output)]
|
|
1275
|
-
}),
|
|
1276
|
-
)
|
|
1277
|
-
return {
|
|
1278
|
-
compiler: true,
|
|
1279
|
-
composition: options.composition,
|
|
1280
|
-
contracts,
|
|
1281
|
-
cssOutput: options.cssOutput,
|
|
1282
|
-
development: !!options.development,
|
|
1283
|
-
extracted,
|
|
1284
|
-
libraries: Object.freeze(libraries),
|
|
1285
|
-
native: {
|
|
1286
|
-
...options.native,
|
|
1287
|
-
...(options.native.fonts && { fonts: { ...options.native.fonts } }),
|
|
1288
|
-
...(options.native.vars && { vars: { ...options.native.vars } }),
|
|
1289
|
-
...(options.native.units && { units: { ...options.native.units } }),
|
|
1290
|
-
},
|
|
1291
|
-
reset: options.reset,
|
|
1292
|
-
entry: options[Stylesheets.entry],
|
|
1293
|
-
retained,
|
|
1294
|
-
transformed,
|
|
1295
|
-
resolutions: Object.freeze(resolutions),
|
|
1296
|
-
result: Object.freeze({
|
|
1297
|
-
contracts: Object.freeze(
|
|
1298
|
-
Object.fromEntries(
|
|
1299
|
-
ids
|
|
1300
|
-
.filter(
|
|
1301
|
-
(id) =>
|
|
1302
|
-
Object.keys(extracted.get(id)!.themeExports ?? {}).length,
|
|
1303
|
-
)
|
|
1304
|
-
.map((id) => [
|
|
1305
|
-
id,
|
|
1306
|
-
Contract.write(
|
|
1307
|
-
Object.fromEntries(
|
|
1308
|
-
Object.entries(extracted.get(id)!.themeExports ?? {}).map(
|
|
1309
|
-
([name, link]) => [name, packedLink(link)],
|
|
1310
|
-
),
|
|
1311
|
-
),
|
|
1312
|
-
themes,
|
|
1313
|
-
[],
|
|
1314
|
-
id,
|
|
1315
|
-
),
|
|
1316
|
-
]),
|
|
1317
|
-
),
|
|
1318
|
-
),
|
|
1319
|
-
dependencies: Object.freeze(dependencies),
|
|
1320
|
-
modules: Object.freeze(modules),
|
|
1321
|
-
}),
|
|
1322
|
-
schemes: false,
|
|
1323
|
-
sources: Object.freeze({ ...options.modules }),
|
|
1324
|
-
themes: Object.freeze(themes),
|
|
1325
|
-
}
|
|
1326
|
-
}
|
|
1327
|
-
|
|
1328
|
-
const modules: Record<string, Transform.compile.ReturnType> =
|
|
1329
|
-
Object.create(null)
|
|
1330
|
-
const sharedThemes = Object.freeze(themes)
|
|
1331
|
-
const sections = new Map<string, readonly Stylesheets.Section[]>()
|
|
1332
|
-
|
|
1333
|
-
for (const id of ids) {
|
|
1334
|
-
const extractedModule = extracted.get(id)!
|
|
1335
|
-
const contributions = extractedModule.contributions ?? []
|
|
1336
|
-
|
|
1337
|
-
if (!contributions.length) {
|
|
1338
|
-
sections.set(id, [])
|
|
1339
|
-
continue
|
|
1340
|
-
}
|
|
1341
|
-
|
|
1342
|
-
sections.set(
|
|
1343
|
-
id,
|
|
1344
|
-
contributions.map((contribution, index) => ({
|
|
1345
|
-
source: id,
|
|
1346
|
-
namespaces: extractedModule.namespaces,
|
|
1347
|
-
key: String(index),
|
|
1348
|
-
css:
|
|
1349
|
-
contribution.kind === 'layers'
|
|
1350
|
-
? ''
|
|
1351
|
-
: (Css.compile({
|
|
1352
|
-
styles: { styles: [] },
|
|
1353
|
-
vars: sharedThemes,
|
|
1354
|
-
contributions: [contribution],
|
|
1355
|
-
}).contributionCss ?? ''),
|
|
1356
|
-
layers: contribution.kind === 'layers' ? [contribution.names] : [],
|
|
1357
|
-
content: options.modules[id]!,
|
|
1358
|
-
start: extractedModule.contributionStarts?.[index] ?? 0,
|
|
1359
|
-
})),
|
|
1360
|
-
)
|
|
1361
|
-
}
|
|
1362
|
-
|
|
1363
|
-
for (const [id, library] of Object.entries(libraries))
|
|
1364
|
-
sections.set(
|
|
1365
|
-
id,
|
|
1366
|
-
library.stylesheets.map((section) => {
|
|
1367
|
-
let owner = id
|
|
1368
|
-
|
|
1369
|
-
for (const specifier of section.dependency ?? []) {
|
|
1370
|
-
const target = resolve(owner, specifier)
|
|
1371
|
-
|
|
1372
|
-
if (!target || !Object.hasOwn(libraries, target))
|
|
1373
|
-
fail(
|
|
1374
|
-
id,
|
|
1375
|
-
'Repacked stylesheet dependencies require supplied library contracts.',
|
|
1376
|
-
)
|
|
1377
|
-
|
|
1378
|
-
owner = target
|
|
1379
|
-
}
|
|
1380
|
-
|
|
1381
|
-
return {
|
|
1382
|
-
...section,
|
|
1383
|
-
owner,
|
|
1384
|
-
source: Stylesheets.resolve(owner, section.source),
|
|
1385
|
-
}
|
|
1386
|
-
}),
|
|
1387
|
-
)
|
|
1388
|
-
|
|
1389
|
-
const resetOwners = ids.filter(
|
|
1390
|
-
(id) =>
|
|
1391
|
-
options.modules[id]!.includes('zyzz/reset.css') &&
|
|
1392
|
-
parse({
|
|
1393
|
-
moduleId: id,
|
|
1394
|
-
source: options.modules[id]!,
|
|
1395
|
-
}).program.body.some(
|
|
1396
|
-
(node) =>
|
|
1397
|
-
node.type === 'ImportDeclaration' &&
|
|
1398
|
-
node.source.value === 'zyzz/reset.css',
|
|
1399
|
-
),
|
|
1400
|
-
)
|
|
1401
|
-
|
|
1402
|
-
const layerNames = [
|
|
1403
|
-
...new Set(
|
|
1404
|
-
ids.flatMap((id) =>
|
|
1405
|
-
reachable(id).flatMap((section) => section.layers.flat()),
|
|
1406
|
-
),
|
|
1407
|
-
),
|
|
1408
|
-
].filter((name) => name !== 'reset')
|
|
1409
|
-
|
|
1410
|
-
for (const resetOwner of resetOwners) {
|
|
1411
|
-
const entryLayers = [
|
|
1412
|
-
...new Set(
|
|
1413
|
-
reachable(resetOwner).flatMap((section) => section.layers.flat()),
|
|
1414
|
-
),
|
|
1415
|
-
].filter((name) => name !== 'reset')
|
|
1416
|
-
|
|
1417
|
-
sections.set(resetOwner, [
|
|
1418
|
-
{
|
|
1419
|
-
source: resetOwner,
|
|
1420
|
-
key: 'optional-reset-order',
|
|
1421
|
-
css: '',
|
|
1422
|
-
layers: entryLayers.length
|
|
1423
|
-
? entryLayers.map((name) => ['reset', name])
|
|
1424
|
-
: [['reset']],
|
|
1425
|
-
},
|
|
1426
|
-
...(sections.get(resetOwner) ?? []),
|
|
1427
|
-
])
|
|
1428
|
-
}
|
|
1429
|
-
|
|
1430
|
-
function dependencyPath(from: string, to: string): readonly string[] {
|
|
1431
|
-
const queue = [{ id: from, path: [] as string[] }]
|
|
1432
|
-
const seen = new Set<string>()
|
|
1433
|
-
|
|
1434
|
-
while (queue.length) {
|
|
1435
|
-
const current = queue.shift()!
|
|
1436
|
-
if (current.id === to) return current.path
|
|
1437
|
-
if (seen.has(current.id)) continue
|
|
1438
|
-
|
|
1439
|
-
seen.add(current.id)
|
|
1440
|
-
|
|
1441
|
-
for (const [specifier, target] of Object.entries(
|
|
1442
|
-
options.imports?.[current.id] ?? {},
|
|
1443
|
-
))
|
|
1444
|
-
if (target)
|
|
1445
|
-
queue.push({ id: target, path: [...current.path, specifier] })
|
|
1446
|
-
}
|
|
1447
|
-
|
|
1448
|
-
fail(
|
|
1449
|
-
from,
|
|
1450
|
-
'Repacked stylesheet ownership requires a resolved dependency path.',
|
|
1451
|
-
)
|
|
1452
|
-
}
|
|
1453
|
-
|
|
1454
|
-
function reachable(
|
|
1455
|
-
id: string,
|
|
1456
|
-
visited = new Set<string>(),
|
|
1457
|
-
): readonly Stylesheets.Section[] {
|
|
1458
|
-
if (visited.has(id)) return []
|
|
1459
|
-
|
|
1460
|
-
visited.add(id)
|
|
1461
|
-
|
|
1462
|
-
return [
|
|
1463
|
-
...(dependencies[id] ?? []).flatMap((dependency) =>
|
|
1464
|
-
reachable(dependency, visited),
|
|
1465
|
-
),
|
|
1466
|
-
...(sections.get(id) ?? []),
|
|
1467
|
-
]
|
|
1468
|
-
}
|
|
1469
|
-
|
|
1470
|
-
const sharedVisited = new Set<string>()
|
|
1471
|
-
const packed: Stylesheets.Resource[] = []
|
|
1472
|
-
|
|
1473
|
-
const sharedSections = (() => {
|
|
1474
|
-
try {
|
|
1475
|
-
const entry = options[Stylesheets.entry]
|
|
1476
|
-
const packedSections =
|
|
1477
|
-
entry === undefined
|
|
1478
|
-
? []
|
|
1479
|
-
: (dependencies[entry] ?? [])
|
|
1480
|
-
.filter((id) => Object.hasOwn(libraries, id))
|
|
1481
|
-
.flatMap((id) => reachable(id, sharedVisited))
|
|
1482
|
-
const sharedSections =
|
|
1483
|
-
entry === undefined
|
|
1484
|
-
? ids.flatMap((id) => reachable(id, sharedVisited))
|
|
1485
|
-
: (sections.get(entry) ?? [])
|
|
1486
|
-
if (packedSections.length) {
|
|
1487
|
-
// Validate combined ownership and ordering before splitting independently loaded resources.
|
|
1488
|
-
Stylesheets.render([...packedSections, ...sharedSections])
|
|
1489
|
-
for (const section of packedSections) {
|
|
1490
|
-
packed.push({
|
|
1491
|
-
id: JSON.stringify([section.owner, section.source, section.key]),
|
|
1492
|
-
...Stylesheets.render([section]),
|
|
1493
|
-
})
|
|
1494
|
-
}
|
|
1495
|
-
}
|
|
1496
|
-
const resetSource =
|
|
1497
|
-
(options.reset === undefined ? undefined : 'zyzz/reset.css') ??
|
|
1498
|
-
resetOwners[0] ??
|
|
1499
|
-
sharedSections.find((section) => section.key === 'optional-reset-order')
|
|
1500
|
-
?.source
|
|
1501
|
-
|
|
1502
|
-
if (packed.length) {
|
|
1503
|
-
const order = Stylesheets.render([
|
|
1504
|
-
...(resetSource === undefined
|
|
1505
|
-
? []
|
|
1506
|
-
: [
|
|
1507
|
-
{
|
|
1508
|
-
source: resetSource,
|
|
1509
|
-
css: '',
|
|
1510
|
-
layers: layerNames.length
|
|
1511
|
-
? layerNames.map((name) => ['reset', name])
|
|
1512
|
-
: [['reset']],
|
|
1513
|
-
},
|
|
1514
|
-
]),
|
|
1515
|
-
...[...packedSections, ...sharedSections].map((section) => ({
|
|
1516
|
-
...section,
|
|
1517
|
-
css: '',
|
|
1518
|
-
})),
|
|
1519
|
-
])
|
|
1520
|
-
if (order.css) packed.unshift({ ...order, id: order.css })
|
|
1521
|
-
}
|
|
1522
|
-
|
|
1523
|
-
return [
|
|
1524
|
-
...(resetSource === undefined
|
|
1525
|
-
? []
|
|
1526
|
-
: [
|
|
1527
|
-
{
|
|
1528
|
-
source: resetSource,
|
|
1529
|
-
key: 'optional-reset-graph-order',
|
|
1530
|
-
css: '',
|
|
1531
|
-
layers: layerNames.length
|
|
1532
|
-
? layerNames.map((name) => ['reset', name])
|
|
1533
|
-
: [['reset']],
|
|
1534
|
-
},
|
|
1535
|
-
]),
|
|
1536
|
-
...sharedSections,
|
|
1537
|
-
...(options.reset === undefined || entry !== undefined
|
|
1538
|
-
? []
|
|
1539
|
-
: [
|
|
1540
|
-
{
|
|
1541
|
-
source: 'zyzz/reset.css',
|
|
1542
|
-
key: 'optional-reset',
|
|
1543
|
-
css: options.reset,
|
|
1544
|
-
content: options.reset,
|
|
1545
|
-
layers: [['reset']],
|
|
1546
|
-
},
|
|
1547
|
-
]),
|
|
1548
|
-
] satisfies Stylesheets.Section[]
|
|
1549
|
-
} catch (error) {
|
|
1550
|
-
return fail(
|
|
1551
|
-
error instanceof Stylesheets.ConflictError ? error.source : ids[0]!,
|
|
1552
|
-
(error as Error).message,
|
|
1553
|
-
)
|
|
1554
|
-
}
|
|
1555
|
-
})()
|
|
1556
|
-
|
|
1557
|
-
function renderShared(sections: readonly Stylesheets.Section[]) {
|
|
1558
|
-
try {
|
|
1559
|
-
return Stylesheets.render(sections)
|
|
1560
|
-
} catch (error) {
|
|
1561
|
-
return fail(
|
|
1562
|
-
error instanceof Stylesheets.ConflictError ? error.source : ids[0]!,
|
|
1563
|
-
(error as Error).message,
|
|
1564
|
-
)
|
|
1565
|
-
}
|
|
1566
|
-
}
|
|
1567
|
-
|
|
1568
|
-
const contributions = renderShared(sharedSections)
|
|
1569
|
-
|
|
1570
|
-
// Every stylesheet includes all graph scopes, including unimported alternatives.
|
|
1571
|
-
const names = Object.keys(themes)
|
|
1572
|
-
const previousNames = Object.keys(previous?.themes ?? {})
|
|
1573
|
-
|
|
1574
|
-
const sameThemes =
|
|
1575
|
-
previous &&
|
|
1576
|
-
names.length === previousNames.length &&
|
|
1577
|
-
names.every(
|
|
1578
|
-
(name, index) =>
|
|
1579
|
-
name === previousNames[index] && previous.themes[name] === themes[name],
|
|
1580
|
-
)
|
|
1581
|
-
|
|
1582
|
-
const styleClasses: Record<string, string> = Object.create(null)
|
|
1583
|
-
function published(link: Themes.Link) {
|
|
1584
|
-
if (link.style?.className !== undefined)
|
|
1585
|
-
styleClasses[link.binding] = link.style.className
|
|
1586
|
-
for (const member of Object.values(link.members ?? {})) published(member)
|
|
1587
|
-
}
|
|
1588
|
-
for (const library of Object.values(libraries))
|
|
1589
|
-
for (const link of Object.values(library.links)) published(link)
|
|
1590
|
-
|
|
1591
|
-
const emittedRules = new Map<string, { body: string; moduleId: string }>()
|
|
1592
|
-
function registerRules(
|
|
1593
|
-
classRules: Readonly<Record<string, string>>,
|
|
1594
|
-
moduleId: string,
|
|
1595
|
-
) {
|
|
1596
|
-
for (const [name, body] of Object.entries(classRules)) {
|
|
1597
|
-
const previous = emittedRules.get(name)
|
|
1598
|
-
if (previous && previous.body !== body)
|
|
1599
|
-
throw new Css.CompileError([
|
|
1600
|
-
{
|
|
1601
|
-
code: 'identity_collision',
|
|
1602
|
-
message: `Generated ${name.startsWith('@scope:') ? `scope ${name.split(':')[1]}` : `class ${name}`} conflicts with module ${previous.moduleId}. Supply distinct config or style ids.`,
|
|
1603
|
-
path: [moduleId],
|
|
1604
|
-
},
|
|
1605
|
-
])
|
|
1606
|
-
emittedRules.set(name, { body, moduleId })
|
|
1607
|
-
}
|
|
1608
|
-
}
|
|
1609
|
-
for (const [moduleId, library] of Object.entries(libraries))
|
|
1610
|
-
registerRules(library.classRules, moduleId)
|
|
1611
|
-
if (options.compiler === false) {
|
|
1612
|
-
const identities = new Map<string, string>()
|
|
1613
|
-
for (const [moduleId, library] of Object.entries(libraries)) {
|
|
1614
|
-
function register(name: string, signature: string) {
|
|
1615
|
-
const previous = identities.get(name)
|
|
1616
|
-
if (previous !== undefined && previous !== signature)
|
|
1617
|
-
fail(
|
|
1618
|
-
moduleId,
|
|
1619
|
-
'The same explicit identity is used for different definitions.',
|
|
1620
|
-
)
|
|
1621
|
-
identities.set(name, signature)
|
|
1622
|
-
}
|
|
1623
|
-
for (const [name, theme] of Object.entries(library.themes)) {
|
|
1624
|
-
const data = theme[Token.definition]
|
|
1625
|
-
if (data.contract[Token.identity]?.startsWith('id-'))
|
|
1626
|
-
register(`theme:${name}`, JSON.stringify(data.values))
|
|
1627
|
-
}
|
|
1628
|
-
function styles(link: Themes.Link) {
|
|
1629
|
-
for (const name of link.style?.className?.split(' ') ?? [])
|
|
1630
|
-
if (name.startsWith('z-style-id-'))
|
|
1631
|
-
register(name, Identity.style(link.style!.style))
|
|
1632
|
-
for (const member of Object.values(link.members ?? {})) styles(member)
|
|
1633
|
-
}
|
|
1634
|
-
for (const link of Object.values(library.links)) styles(link)
|
|
1635
|
-
}
|
|
1636
|
-
for (const [moduleId, module] of extracted) {
|
|
1637
|
-
function register(name: string, signature: string) {
|
|
1638
|
-
const previous = identities.get(name)
|
|
1639
|
-
if (previous !== undefined && previous !== signature)
|
|
1640
|
-
return fail(
|
|
1641
|
-
moduleId,
|
|
1642
|
-
'The same explicit identity is used for different definitions.',
|
|
1643
|
-
)
|
|
1644
|
-
identities.set(name, signature)
|
|
1645
|
-
}
|
|
1646
|
-
for (const [name, theme] of Object.entries(module.vars)) {
|
|
1647
|
-
const data = theme[Token.definition]
|
|
1648
|
-
if (data.contract[Token.identity]?.startsWith('id-'))
|
|
1649
|
-
register(`theme:${name}`, JSON.stringify(data.values))
|
|
1650
|
-
}
|
|
1651
|
-
for (const contribution of module.contributions ?? [])
|
|
1652
|
-
if ('name' in contribution)
|
|
1653
|
-
register(
|
|
1654
|
-
`${contribution.kind}:${contribution.name}`,
|
|
1655
|
-
Css.compile({
|
|
1656
|
-
styles: { styles: [] },
|
|
1657
|
-
contributions: [contribution],
|
|
1658
|
-
}).css,
|
|
1659
|
-
)
|
|
1660
|
-
for (const call of module.calls) {
|
|
1661
|
-
if (!call.portable?.startsWith('z-style-id-')) continue
|
|
1662
|
-
const signature = Identity.style(
|
|
1663
|
-
module.styles.styles.find((style) => style.name === call.name)!,
|
|
1664
|
-
)
|
|
1665
|
-
const previous = identities.get(call.portable)
|
|
1666
|
-
if (previous !== undefined && previous !== signature)
|
|
1667
|
-
return fail(
|
|
1668
|
-
moduleId,
|
|
1669
|
-
'The same explicit style id is used for different declarations.',
|
|
1670
|
-
)
|
|
1671
|
-
identities.set(call.portable, signature)
|
|
1672
|
-
}
|
|
1673
|
-
}
|
|
1674
|
-
}
|
|
1675
|
-
|
|
1676
|
-
// Selection anywhere in the graph applies scheme classes beside scopes every
|
|
1677
|
-
// stylesheet carries, so each stylesheet declares the matching color-scheme.
|
|
1678
|
-
const schemes = [...extracted.values()].some((module) =>
|
|
1679
|
-
Boolean(
|
|
1680
|
-
module.themeAppearances?.length ||
|
|
1681
|
-
module.themeScripts?.length ||
|
|
1682
|
-
module.themeSelections?.length,
|
|
1683
|
-
),
|
|
1684
|
-
)
|
|
1685
|
-
|
|
1686
|
-
const ownerSignature = JSON.stringify(owners)
|
|
1687
|
-
const units = ClassName.registry()
|
|
1688
|
-
const closures = new Map<string, ReadonlySet<string>>()
|
|
1689
|
-
|
|
1690
|
-
function closure(moduleId: string): ReadonlySet<string> {
|
|
1691
|
-
const cached = closures.get(moduleId)
|
|
1692
|
-
if (cached) return cached
|
|
1693
|
-
|
|
1694
|
-
const result = new Set<string>()
|
|
1695
|
-
closures.set(moduleId, result)
|
|
1696
|
-
for (const dependency of dependencies[moduleId] ?? []) {
|
|
1697
|
-
result.add(dependency)
|
|
1698
|
-
for (const nested of closure(dependency)) result.add(nested)
|
|
1699
|
-
}
|
|
1700
|
-
|
|
1701
|
-
return result
|
|
1702
|
-
}
|
|
1703
|
-
|
|
1704
|
-
// Hosts that compile a module within several graphs must name it the same in
|
|
1705
|
-
// each, so it may reuse only names its dependencies introduce.
|
|
1706
|
-
function visible(moduleId: string) {
|
|
1707
|
-
if (options[ClassName.complete]) return undefined
|
|
1708
|
-
return (owner: string) => closure(moduleId).has(owner)
|
|
1709
|
-
}
|
|
1710
|
-
|
|
1711
|
-
function restore(moduleId: string, output: Transform.compile.ReturnType) {
|
|
1712
|
-
return units.restore({
|
|
1713
|
-
owner: moduleId,
|
|
1714
|
-
used: output[ClassName.units] ?? new Map(),
|
|
1715
|
-
visible: visible(moduleId),
|
|
1716
|
-
})
|
|
1717
|
-
}
|
|
1718
|
-
|
|
1719
|
-
// Extraction visits dependencies first; their emitted classes must precede consumers.
|
|
1720
|
-
for (const moduleId of extracted.keys()) {
|
|
1721
|
-
const cached = transformed.get(moduleId)
|
|
1722
|
-
const reusable =
|
|
1723
|
-
cached &&
|
|
1724
|
-
cached.extracted === extracted.get(moduleId) &&
|
|
1725
|
-
cached.schemes === schemes &&
|
|
1726
|
-
Object.keys(cached.themes).length === names.length &&
|
|
1727
|
-
names.every((name) => cached.themes[name] === themes[name]) &&
|
|
1728
|
-
Object.entries(cached.classes).every(
|
|
1729
|
-
([name, value]) => styleClasses[name] === value,
|
|
1730
|
-
) &&
|
|
1731
|
-
cached.owners === ownerSignature &&
|
|
1732
|
-
restore(moduleId, cached.output)
|
|
1733
|
-
modules[moduleId] = reusable
|
|
1734
|
-
? cached.output
|
|
1735
|
-
: sameThemes &&
|
|
1736
|
-
previous!.schemes === schemes &&
|
|
1737
|
-
extracted.get(moduleId) === previous!.extracted.get(moduleId) &&
|
|
1738
|
-
restore(moduleId, previous!.result.modules[moduleId]!)
|
|
1739
|
-
? previous!.result.modules[moduleId]!
|
|
1740
|
-
: Transform.compile({
|
|
1741
|
-
[ClassName.units]: units.scope({
|
|
1742
|
-
owner: moduleId,
|
|
1743
|
-
qualifier: Identity.compact(moduleId).slice(-6),
|
|
1744
|
-
visible: visible(moduleId),
|
|
1745
|
-
}),
|
|
1746
|
-
[ThemeRules.shared]:
|
|
1747
|
-
options[Stylesheets.entry] === undefined
|
|
1748
|
-
? (options[ThemeRules.shared] ?? 'defaults')
|
|
1749
|
-
: 'all',
|
|
1750
|
-
compiler: options.compiler,
|
|
1751
|
-
development: options.development,
|
|
1752
|
-
composition: options.composition,
|
|
1753
|
-
cssOutput: options.cssOutput,
|
|
1754
|
-
moduleId,
|
|
1755
|
-
schemes,
|
|
1756
|
-
source: options.modules[moduleId]!,
|
|
1757
|
-
[Themes.context]: {
|
|
1758
|
-
parsed: parse({ moduleId, source: options.modules[moduleId]! }),
|
|
1759
|
-
extracted: Object.freeze({
|
|
1760
|
-
...extracted.get(moduleId)!,
|
|
1761
|
-
vars: sharedThemes,
|
|
1762
|
-
contributions: undefined,
|
|
1763
|
-
}),
|
|
1764
|
-
links: {},
|
|
1765
|
-
owners,
|
|
1766
|
-
styleClasses,
|
|
1767
|
-
},
|
|
1768
|
-
})
|
|
1769
|
-
transformed.delete(moduleId)
|
|
1770
|
-
transformed.set(moduleId, {
|
|
1771
|
-
classes: Object.fromEntries(
|
|
1772
|
-
extracted
|
|
1773
|
-
.get(moduleId)!
|
|
1774
|
-
.calls.flatMap((call) =>
|
|
1775
|
-
(call.runtimeComposition ?? []).map((input) => [
|
|
1776
|
-
input.name,
|
|
1777
|
-
styleClasses[input.name],
|
|
1778
|
-
]),
|
|
1779
|
-
),
|
|
1780
|
-
),
|
|
1781
|
-
extracted: extracted.get(moduleId)!,
|
|
1782
|
-
owners: ownerSignature,
|
|
1783
|
-
output: modules[moduleId]!,
|
|
1784
|
-
schemes,
|
|
1785
|
-
themes: sharedThemes,
|
|
1786
|
-
})
|
|
1787
|
-
if (transformed.size > 256)
|
|
1788
|
-
transformed.delete(transformed.keys().next().value!)
|
|
1789
|
-
registerRules(modules[moduleId]![ClassName.rules], moduleId)
|
|
1790
|
-
|
|
1791
|
-
for (const call of extracted.get(moduleId)!.calls)
|
|
1792
|
-
if (
|
|
1793
|
-
call.identity &&
|
|
1794
|
-
!call.composition &&
|
|
1795
|
-
!call.runtimeComposition &&
|
|
1796
|
-
!call.compositionCase
|
|
159
|
+
result = Results.graph(
|
|
160
|
+
Results.decode<Results.Output>(text),
|
|
161
|
+
result,
|
|
162
|
+
decoded,
|
|
1797
163
|
)
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
const defaultRules = new Map<string, ThemeRules.Rule[]>()
|
|
1803
|
-
const defaultSections: Stylesheets.Section[] = []
|
|
1804
|
-
if (options[Stylesheets.entry] === undefined)
|
|
1805
|
-
for (const [source, output] of Object.entries(modules))
|
|
1806
|
-
for (const resource of output[ThemeRules.shared] ?? []) {
|
|
1807
|
-
if (defaults.has(resource.id)) continue
|
|
1808
|
-
defaults.add(resource.id)
|
|
1809
|
-
|
|
1810
|
-
if (!resource.rules) {
|
|
1811
|
-
defaultSections.push({
|
|
1812
|
-
css: resource.css,
|
|
1813
|
-
key: resource.id,
|
|
1814
|
-
layers: [],
|
|
1815
|
-
source,
|
|
1816
|
-
})
|
|
1817
|
-
continue
|
|
1818
|
-
}
|
|
1819
|
-
|
|
1820
|
-
const rules = defaultRules.get(source) ?? []
|
|
1821
|
-
rules.push(...resource.rules)
|
|
1822
|
-
defaultRules.set(source, rules)
|
|
164
|
+
// Hosts may update their records in place, so the sent text is copied.
|
|
165
|
+
sent = {
|
|
166
|
+
contracts: input.contracts && { ...input.contracts },
|
|
167
|
+
modules: { ...input.modules },
|
|
1823
168
|
}
|
|
1824
169
|
|
|
1825
|
-
|
|
1826
|
-
? renderShared([
|
|
1827
|
-
...sharedSections,
|
|
1828
|
-
...defaultSections,
|
|
1829
|
-
...[...defaultRules].map(([source, rules]) => ({
|
|
1830
|
-
css: ThemeRules.render(rules),
|
|
1831
|
-
key: 'theme-defaults',
|
|
1832
|
-
layers: [],
|
|
1833
|
-
source,
|
|
1834
|
-
})),
|
|
1835
|
-
])
|
|
1836
|
-
: contributions
|
|
1837
|
-
const sharedCss = shared.css
|
|
1838
|
-
|
|
1839
|
-
function publishedRules(
|
|
1840
|
-
id: string,
|
|
1841
|
-
visited = new Set<string>(),
|
|
1842
|
-
): Readonly<Record<string, string>> {
|
|
1843
|
-
if (visited.has(id)) return {}
|
|
1844
|
-
visited.add(id)
|
|
1845
|
-
return Object.assign(
|
|
1846
|
-
{},
|
|
1847
|
-
...(dependencies[id] ?? []).map((dependency) =>
|
|
1848
|
-
publishedRules(dependency, visited),
|
|
1849
|
-
),
|
|
1850
|
-
libraries[id]?.classRules,
|
|
1851
|
-
modules[id]?.[ClassName.rules],
|
|
1852
|
-
)
|
|
1853
|
-
}
|
|
1854
|
-
|
|
1855
|
-
function publishedStyle(link: Themes.Link): Themes.Link {
|
|
1856
|
-
return {
|
|
1857
|
-
...link,
|
|
1858
|
-
...(link.style
|
|
1859
|
-
? {
|
|
1860
|
-
style: {
|
|
1861
|
-
...link.style,
|
|
1862
|
-
className: styleClasses[link.binding] ?? link.style.className,
|
|
1863
|
-
},
|
|
1864
|
-
}
|
|
1865
|
-
: {}),
|
|
1866
|
-
...(link.members
|
|
1867
|
-
? {
|
|
1868
|
-
members: Object.fromEntries(
|
|
1869
|
-
Object.entries(link.members).map(([name, member]) => [
|
|
1870
|
-
name,
|
|
1871
|
-
publishedStyle(member),
|
|
1872
|
-
]),
|
|
1873
|
-
),
|
|
1874
|
-
}
|
|
1875
|
-
: {}),
|
|
1876
|
-
}
|
|
1877
|
-
}
|
|
1878
|
-
|
|
1879
|
-
// A configuration whose module uses root controls or the script publishes its
|
|
1880
|
-
// catalog, exported or not, so initialization restores selections it persists.
|
|
1881
|
-
function configurations(id: string): readonly Contract.write.Configuration[] {
|
|
1882
|
-
const module = extracted.get(id)!
|
|
1883
|
-
|
|
1884
|
-
return module.themeCalls
|
|
1885
|
-
.filter(
|
|
1886
|
-
(call) =>
|
|
1887
|
-
call.appearance &&
|
|
1888
|
-
call.options &&
|
|
1889
|
-
(module.themeAppearances?.includes(call.name) ||
|
|
1890
|
-
module.themeScripts?.includes(call.name)),
|
|
1891
|
-
)
|
|
1892
|
-
.map((call) => {
|
|
1893
|
-
const themeNames = call.options?.themes
|
|
1894
|
-
|
|
1895
|
-
return {
|
|
1896
|
-
identity:
|
|
1897
|
-
sharedThemes[call.name]?.[Token.definition].contract[
|
|
1898
|
-
Token.identity
|
|
1899
|
-
] ?? call.name,
|
|
1900
|
-
...(typeof call.options?.storageKey === 'string'
|
|
1901
|
-
? { storageKey: call.options.storageKey }
|
|
1902
|
-
: {}),
|
|
1903
|
-
themes:
|
|
1904
|
-
themeNames && typeof themeNames === 'object'
|
|
1905
|
-
? Object.keys(themeNames)
|
|
1906
|
-
: [],
|
|
1907
|
-
}
|
|
1908
|
-
})
|
|
1909
|
-
}
|
|
1910
|
-
|
|
1911
|
-
return {
|
|
1912
|
-
compiler: options.compiler !== false,
|
|
1913
|
-
shared: options[ThemeRules.shared],
|
|
1914
|
-
composition: options.composition,
|
|
1915
|
-
cssOutput: options.cssOutput,
|
|
1916
|
-
contracts,
|
|
1917
|
-
development: !!options.development,
|
|
1918
|
-
extracted,
|
|
1919
|
-
libraries: Object.freeze(libraries),
|
|
1920
|
-
native: undefined,
|
|
1921
|
-
reset: options.reset,
|
|
1922
|
-
entry: options[Stylesheets.entry],
|
|
1923
|
-
retained,
|
|
1924
|
-
transformed,
|
|
1925
|
-
resolutions: Object.freeze(resolutions),
|
|
1926
|
-
result: Object.freeze({
|
|
1927
|
-
...(options[Stylesheets.entry] !== undefined &&
|
|
1928
|
-
options.reset !== undefined
|
|
1929
|
-
? {
|
|
1930
|
-
[Stylesheets.reset]: {
|
|
1931
|
-
id: 'zyzz/reset.css',
|
|
1932
|
-
...Stylesheets.render([
|
|
1933
|
-
{
|
|
1934
|
-
content: options.reset,
|
|
1935
|
-
css: options.reset,
|
|
1936
|
-
layers: [['reset']],
|
|
1937
|
-
source: 'zyzz/reset.css',
|
|
1938
|
-
},
|
|
1939
|
-
]),
|
|
1940
|
-
},
|
|
1941
|
-
}
|
|
1942
|
-
: {}),
|
|
1943
|
-
...(packed.length ? { [Stylesheets.packed]: packed } : {}),
|
|
1944
|
-
...(sharedCss
|
|
1945
|
-
? {
|
|
1946
|
-
sharedCss,
|
|
1947
|
-
sharedCssMap: shared.map,
|
|
1948
|
-
sharedAssets: shared.assets,
|
|
1949
|
-
sharedAssetOwners: shared.owners,
|
|
1950
|
-
}
|
|
1951
|
-
: {}),
|
|
1952
|
-
contracts: Object.freeze(
|
|
1953
|
-
Object.fromEntries(
|
|
1954
|
-
(options[Stylesheets.entry] === undefined ? ids : [])
|
|
1955
|
-
.filter(
|
|
1956
|
-
(id) =>
|
|
1957
|
-
Object.keys(extracted.get(id)!.themeExports ?? {}).length ||
|
|
1958
|
-
reachable(id).length ||
|
|
1959
|
-
configurations(id).length,
|
|
1960
|
-
)
|
|
1961
|
-
.map((id) => [
|
|
1962
|
-
id,
|
|
1963
|
-
Contract.write(
|
|
1964
|
-
Object.fromEntries(
|
|
1965
|
-
Object.entries(extracted.get(id)!.themeExports ?? {}).map(
|
|
1966
|
-
([name, link]) => [name, publishedStyle(link)],
|
|
1967
|
-
),
|
|
1968
|
-
),
|
|
1969
|
-
sharedThemes,
|
|
1970
|
-
reachable(id).map((section) => ({
|
|
1971
|
-
...section,
|
|
1972
|
-
owner: undefined,
|
|
1973
|
-
dependency:
|
|
1974
|
-
section.owner && section.owner !== id
|
|
1975
|
-
? dependencyPath(id, section.owner)
|
|
1976
|
-
: undefined,
|
|
1977
|
-
source: Stylesheets.relative(
|
|
1978
|
-
section.owner ?? id,
|
|
1979
|
-
section.source,
|
|
1980
|
-
),
|
|
1981
|
-
})),
|
|
1982
|
-
id,
|
|
1983
|
-
configurations(id),
|
|
1984
|
-
publishedRules(id),
|
|
1985
|
-
),
|
|
1986
|
-
]),
|
|
1987
|
-
),
|
|
1988
|
-
),
|
|
1989
|
-
dependencies: Object.freeze(dependencies),
|
|
1990
|
-
modules: Object.freeze(
|
|
1991
|
-
Object.fromEntries(ids.map((id) => [id, modules[id]!])),
|
|
1992
|
-
),
|
|
1993
|
-
}),
|
|
1994
|
-
schemes,
|
|
1995
|
-
sources: Object.freeze({ ...options.modules }),
|
|
1996
|
-
themes: sharedThemes,
|
|
1997
|
-
}
|
|
1998
|
-
}
|
|
1999
|
-
|
|
2000
|
-
// A returned lazy map must not retain the graph compilation context.
|
|
2001
|
-
function nativeOutput(
|
|
2002
|
-
output: Native.compile.ReturnType,
|
|
2003
|
-
): Transform.compile.ReturnType {
|
|
2004
|
-
let sourceMap: Mapping.EncodedSourceMap | undefined
|
|
2005
|
-
|
|
2006
|
-
return Object.freeze({
|
|
2007
|
-
[ClassName.rules]: Object.freeze({}),
|
|
2008
|
-
classes: Object.freeze({}),
|
|
2009
|
-
[Edits.key]: output[Edits.key],
|
|
2010
|
-
code: output.code,
|
|
2011
|
-
css: '',
|
|
2012
|
-
cssMap: {
|
|
2013
|
-
version: 3 as const,
|
|
2014
|
-
names: [],
|
|
2015
|
-
sources: [],
|
|
2016
|
-
mappings: '',
|
|
170
|
+
return result
|
|
2017
171
|
},
|
|
2018
|
-
get map() {
|
|
2019
|
-
return (sourceMap ??= JSON.parse(output.map) as Mapping.EncodedSourceMap)
|
|
2020
|
-
},
|
|
2021
|
-
vars: Object.freeze({}),
|
|
2022
172
|
})
|
|
2023
173
|
}
|
|
174
|
+
|
|
175
|
+
/** Incremental graph compiler contracts. */
|
|
176
|
+
export declare namespace create {
|
|
177
|
+
/** Explicitly owned compilation state; dropping the compiler releases its cache. */
|
|
178
|
+
type ReturnType = {
|
|
179
|
+
/** Compiles a complete source snapshot, reusing unaffected work across calls. */
|
|
180
|
+
readonly compile: typeof compile
|
|
181
|
+
}
|
|
182
|
+
}
|