zyzz 0.0.28 → 0.0.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (302) hide show
  1. package/binding/wasi/wasi-worker.mjs +186 -0
  2. package/binding/wasi/zyzz.wasi.cjs +2302 -0
  3. package/binding/wasi/zyzz.wasm32-wasi.wasm +0 -0
  4. package/binding/zyzz.linux-x64-gnu.node +0 -0
  5. package/dist/babel/index.d.ts.map +1 -1
  6. package/dist/babel/index.js +2 -4
  7. package/dist/babel/index.js.map +1 -1
  8. package/dist/babel/internal/Compilation.d.ts +0 -1
  9. package/dist/babel/internal/Compilation.d.ts.map +1 -1
  10. package/dist/compiler/Graph.d.ts +14 -11
  11. package/dist/compiler/Graph.d.ts.map +1 -1
  12. package/dist/compiler/Graph.js +57 -1442
  13. package/dist/compiler/Graph.js.map +1 -1
  14. package/dist/compiler/Native.d.ts +7 -9
  15. package/dist/compiler/Native.d.ts.map +1 -1
  16. package/dist/compiler/Native.js +12 -716
  17. package/dist/compiler/Native.js.map +1 -1
  18. package/dist/compiler/Source.d.ts +122 -24
  19. package/dist/compiler/Source.d.ts.map +1 -1
  20. package/dist/compiler/Source.js +10 -1267
  21. package/dist/compiler/Source.js.map +1 -1
  22. package/dist/compiler/Transform.d.ts +4 -3
  23. package/dist/compiler/Transform.d.ts.map +1 -1
  24. package/dist/compiler/Transform.js +13 -961
  25. package/dist/compiler/Transform.js.map +1 -1
  26. package/dist/compiler/internal/AtRules.d.ts +5 -1
  27. package/dist/compiler/internal/AtRules.d.ts.map +1 -1
  28. package/dist/compiler/internal/AtRules.js +12 -106
  29. package/dist/compiler/internal/AtRules.js.map +1 -1
  30. package/dist/compiler/internal/Context.d.ts +11 -0
  31. package/dist/compiler/internal/Context.d.ts.map +1 -0
  32. package/dist/compiler/internal/Context.js +11 -0
  33. package/dist/compiler/internal/Context.js.map +1 -0
  34. package/dist/compiler/internal/Results.d.ts +148 -0
  35. package/dist/compiler/internal/Results.d.ts.map +1 -0
  36. package/dist/compiler/internal/Results.js +259 -0
  37. package/dist/compiler/internal/Results.js.map +1 -0
  38. package/dist/compiler/internal/Syntax.d.ts +0 -2
  39. package/dist/compiler/internal/Syntax.d.ts.map +1 -1
  40. package/dist/compiler/internal/Syntax.js +0 -2
  41. package/dist/compiler/internal/Syntax.js.map +1 -1
  42. package/dist/compiler/internal/Wire.d.ts +17 -0
  43. package/dist/compiler/internal/Wire.d.ts.map +1 -0
  44. package/dist/compiler/internal/Wire.js +795 -0
  45. package/dist/compiler/internal/Wire.js.map +1 -0
  46. package/dist/internal/Addon.d.ts +28 -0
  47. package/dist/internal/Addon.d.ts.map +1 -0
  48. package/dist/internal/Addon.js +87 -0
  49. package/dist/internal/Addon.js.map +1 -0
  50. package/dist/internal/Literal.d.ts +4 -1
  51. package/dist/internal/Literal.d.ts.map +1 -1
  52. package/dist/internal/Literal.js +4 -2
  53. package/dist/internal/Literal.js.map +1 -1
  54. package/dist/internal/Token.d.ts +2 -1
  55. package/dist/internal/Token.d.ts.map +1 -1
  56. package/dist/internal/Token.js +2 -2
  57. package/dist/internal/Token.js.map +1 -1
  58. package/dist/internal/Vlq.d.ts +14 -0
  59. package/dist/internal/Vlq.d.ts.map +1 -0
  60. package/dist/internal/Vlq.js +47 -0
  61. package/dist/internal/Vlq.js.map +1 -0
  62. package/dist/internal/Wasm.d.ts +22 -0
  63. package/dist/internal/Wasm.d.ts.map +1 -0
  64. package/dist/internal/Wasm.js +83 -0
  65. package/dist/internal/Wasm.js.map +1 -0
  66. package/dist/metro/Graph.d.ts +0 -1
  67. package/dist/metro/Graph.d.ts.map +1 -1
  68. package/dist/metro/transformer.d.ts.map +1 -1
  69. package/dist/metro/transformer.js +0 -1
  70. package/dist/metro/transformer.js.map +1 -1
  71. package/dist/next/internal/Project.d.ts.map +1 -1
  72. package/dist/next/internal/Project.js +2 -5
  73. package/dist/next/internal/Project.js.map +1 -1
  74. package/dist/node/Host.d.ts.map +1 -1
  75. package/dist/node/Host.js +0 -2
  76. package/dist/node/Host.js.map +1 -1
  77. package/dist/node/internal/Contracts.d.ts.map +1 -1
  78. package/dist/node/internal/Contracts.js +3 -7
  79. package/dist/node/internal/Contracts.js.map +1 -1
  80. package/dist/node/internal/Snapshot.d.ts +0 -1
  81. package/dist/node/internal/Snapshot.d.ts.map +1 -1
  82. package/dist/node/internal/Snapshot.js +0 -6
  83. package/dist/node/internal/Snapshot.js.map +1 -1
  84. package/dist/runtime/Composition.d.ts +2 -3
  85. package/dist/runtime/Composition.d.ts.map +1 -1
  86. package/dist/runtime/Composition.js +51 -30
  87. package/dist/runtime/Composition.js.map +1 -1
  88. package/dist/runtime/Recipe.d.ts.map +1 -1
  89. package/dist/runtime/Recipe.js +16 -12
  90. package/dist/runtime/Recipe.js.map +1 -1
  91. package/dist/unplugin/index.d.ts.map +1 -1
  92. package/dist/unplugin/index.js +3 -6
  93. package/dist/unplugin/index.js.map +1 -1
  94. package/dist/vite/index.d.ts.map +1 -1
  95. package/dist/vite/index.js +696 -201
  96. package/dist/vite/index.js.map +1 -1
  97. package/dist/web/Css.d.ts +8 -3
  98. package/dist/web/Css.d.ts.map +1 -1
  99. package/dist/web/Css.js +5 -721
  100. package/dist/web/Css.js.map +1 -1
  101. package/dist/web/internal/Block.d.ts +0 -2
  102. package/dist/web/internal/Block.d.ts.map +1 -1
  103. package/dist/web/internal/Block.js +1 -12
  104. package/dist/web/internal/Block.js.map +1 -1
  105. package/dist/web/internal/ClassName.d.ts +23 -18
  106. package/dist/web/internal/ClassName.d.ts.map +1 -1
  107. package/dist/web/internal/ClassName.js +26 -55
  108. package/dist/web/internal/ClassName.js.map +1 -1
  109. package/dist/web/internal/Contributions.d.ts +3 -5
  110. package/dist/web/internal/Contributions.d.ts.map +1 -1
  111. package/dist/web/internal/Contributions.js +0 -45
  112. package/dist/web/internal/Contributions.js.map +1 -1
  113. package/dist/web/internal/Engine.browser.d.ts +8 -0
  114. package/dist/web/internal/Engine.browser.d.ts.map +1 -0
  115. package/dist/web/internal/Engine.browser.js +42 -0
  116. package/dist/web/internal/Engine.browser.js.map +1 -0
  117. package/dist/web/internal/Engine.d.ts +9 -0
  118. package/dist/web/internal/Engine.d.ts.map +1 -0
  119. package/dist/web/internal/Engine.js +14 -0
  120. package/dist/web/internal/Engine.js.map +1 -0
  121. package/dist/web/internal/Themes.d.ts +1 -9
  122. package/dist/web/internal/Themes.d.ts.map +1 -1
  123. package/dist/web/internal/Themes.js +3 -221
  124. package/dist/web/internal/Themes.js.map +1 -1
  125. package/dist/web/internal/Wasm.generated.d.ts +4 -0
  126. package/dist/web/internal/Wasm.generated.d.ts.map +1 -0
  127. package/dist/web/internal/Wasm.generated.js +4 -0
  128. package/dist/web/internal/Wasm.generated.js.map +1 -0
  129. package/dist/web/internal/Wire.d.ts +19 -0
  130. package/dist/web/internal/Wire.d.ts.map +1 -0
  131. package/dist/web/internal/Wire.js +387 -0
  132. package/dist/web/internal/Wire.js.map +1 -0
  133. package/package.json +20 -1
  134. package/src/babel/index.ts +2 -5
  135. package/src/babel/internal/Compilation.ts +0 -1
  136. package/src/compiler/Graph.ts +89 -1930
  137. package/src/compiler/Native.ts +18 -871
  138. package/src/compiler/Source.ts +144 -1803
  139. package/src/compiler/Transform.ts +16 -1315
  140. package/src/compiler/internal/AtRules.ts +27 -115
  141. package/src/compiler/internal/Context.ts +11 -0
  142. package/src/compiler/internal/Results.ts +406 -0
  143. package/src/compiler/internal/Syntax.ts +0 -3
  144. package/src/compiler/internal/Wire.ts +1045 -0
  145. package/src/internal/Addon.ts +118 -0
  146. package/src/internal/Literal.ts +4 -2
  147. package/src/internal/Token.ts +2 -2
  148. package/src/internal/Vlq.ts +59 -0
  149. package/src/internal/Wasm.ts +111 -0
  150. package/src/metro/transformer.ts +0 -1
  151. package/src/next/internal/Project.ts +2 -9
  152. package/src/node/Host.ts +0 -2
  153. package/src/node/internal/Contracts.ts +3 -7
  154. package/src/node/internal/Snapshot.ts +0 -8
  155. package/src/runtime/Composition.ts +48 -25
  156. package/src/runtime/Recipe.ts +21 -14
  157. package/src/unplugin/index.ts +6 -6
  158. package/src/vite/index.ts +922 -221
  159. package/src/web/Css.ts +12 -908
  160. package/src/web/internal/Block.ts +0 -14
  161. package/src/web/internal/ClassName.ts +52 -85
  162. package/src/web/internal/Contributions.ts +3 -59
  163. package/src/web/internal/Engine.browser.ts +51 -0
  164. package/src/web/internal/Engine.ts +17 -0
  165. package/src/web/internal/Themes.ts +3 -279
  166. package/src/web/internal/Wasm.generated.ts +3 -0
  167. package/src/web/internal/Wire.ts +466 -0
  168. package/src/web/internal/wasm.d.ts +9 -0
  169. package/dist/compiler/internal/Applications.d.ts +0 -55
  170. package/dist/compiler/internal/Applications.d.ts.map +0 -1
  171. package/dist/compiler/internal/Applications.js +0 -393
  172. package/dist/compiler/internal/Applications.js.map +0 -1
  173. package/dist/compiler/internal/ColorProfiles.d.ts +0 -3
  174. package/dist/compiler/internal/ColorProfiles.d.ts.map +0 -1
  175. package/dist/compiler/internal/ColorProfiles.js +0 -84
  176. package/dist/compiler/internal/ColorProfiles.js.map +0 -1
  177. package/dist/compiler/internal/CompositionBindings.d.ts +0 -16
  178. package/dist/compiler/internal/CompositionBindings.d.ts.map +0 -1
  179. package/dist/compiler/internal/CompositionBindings.js +0 -89
  180. package/dist/compiler/internal/CompositionBindings.js.map +0 -1
  181. package/dist/compiler/internal/Compositions.d.ts +0 -37
  182. package/dist/compiler/internal/Compositions.d.ts.map +0 -1
  183. package/dist/compiler/internal/Compositions.js +0 -494
  184. package/dist/compiler/internal/Compositions.js.map +0 -1
  185. package/dist/compiler/internal/Configurations.d.ts +0 -26
  186. package/dist/compiler/internal/Configurations.d.ts.map +0 -1
  187. package/dist/compiler/internal/Configurations.js +0 -259
  188. package/dist/compiler/internal/Configurations.js.map +0 -1
  189. package/dist/compiler/internal/Contract.d.ts +0 -30
  190. package/dist/compiler/internal/Contract.d.ts.map +0 -1
  191. package/dist/compiler/internal/Contract.js +0 -753
  192. package/dist/compiler/internal/Contract.js.map +0 -1
  193. package/dist/compiler/internal/Contributions.d.ts +0 -54
  194. package/dist/compiler/internal/Contributions.d.ts.map +0 -1
  195. package/dist/compiler/internal/Contributions.js +0 -1151
  196. package/dist/compiler/internal/Contributions.js.map +0 -1
  197. package/dist/compiler/internal/Descriptors.d.ts +0 -15
  198. package/dist/compiler/internal/Descriptors.d.ts.map +0 -1
  199. package/dist/compiler/internal/Descriptors.js +0 -192
  200. package/dist/compiler/internal/Descriptors.js.map +0 -1
  201. package/dist/compiler/internal/Dynamic.d.ts +0 -14
  202. package/dist/compiler/internal/Dynamic.d.ts.map +0 -1
  203. package/dist/compiler/internal/Dynamic.js +0 -175
  204. package/dist/compiler/internal/Dynamic.js.map +0 -1
  205. package/dist/compiler/internal/Expression.d.ts +0 -19
  206. package/dist/compiler/internal/Expression.d.ts.map +0 -1
  207. package/dist/compiler/internal/Expression.js +0 -164
  208. package/dist/compiler/internal/Expression.js.map +0 -1
  209. package/dist/compiler/internal/Functions.d.ts +0 -5
  210. package/dist/compiler/internal/Functions.d.ts.map +0 -1
  211. package/dist/compiler/internal/Functions.js +0 -191
  212. package/dist/compiler/internal/Functions.js.map +0 -1
  213. package/dist/compiler/internal/Keyframes.d.ts +0 -5
  214. package/dist/compiler/internal/Keyframes.d.ts.map +0 -1
  215. package/dist/compiler/internal/Keyframes.js +0 -51
  216. package/dist/compiler/internal/Keyframes.js.map +0 -1
  217. package/dist/compiler/internal/Names.d.ts +0 -5
  218. package/dist/compiler/internal/Names.d.ts.map +0 -1
  219. package/dist/compiler/internal/Names.js +0 -37
  220. package/dist/compiler/internal/Names.js.map +0 -1
  221. package/dist/compiler/internal/NativeBindings.d.ts +0 -72
  222. package/dist/compiler/internal/NativeBindings.d.ts.map +0 -1
  223. package/dist/compiler/internal/NativeBindings.js +0 -171
  224. package/dist/compiler/internal/NativeBindings.js.map +0 -1
  225. package/dist/compiler/internal/NativeMedia.d.ts +0 -14
  226. package/dist/compiler/internal/NativeMedia.d.ts.map +0 -1
  227. package/dist/compiler/internal/NativeMedia.js +0 -287
  228. package/dist/compiler/internal/NativeMedia.js.map +0 -1
  229. package/dist/compiler/internal/NativeVars.d.ts +0 -28
  230. package/dist/compiler/internal/NativeVars.d.ts.map +0 -1
  231. package/dist/compiler/internal/NativeVars.js +0 -160
  232. package/dist/compiler/internal/NativeVars.js.map +0 -1
  233. package/dist/compiler/internal/PackedStyles.d.ts +0 -37
  234. package/dist/compiler/internal/PackedStyles.d.ts.map +0 -1
  235. package/dist/compiler/internal/PackedStyles.js +0 -344
  236. package/dist/compiler/internal/PackedStyles.js.map +0 -1
  237. package/dist/compiler/internal/Properties.d.ts +0 -5
  238. package/dist/compiler/internal/Properties.d.ts.map +0 -1
  239. package/dist/compiler/internal/Properties.js +0 -82
  240. package/dist/compiler/internal/Properties.js.map +0 -1
  241. package/dist/compiler/internal/RecipeConditions.d.ts +0 -41
  242. package/dist/compiler/internal/RecipeConditions.d.ts.map +0 -1
  243. package/dist/compiler/internal/RecipeConditions.js +0 -82
  244. package/dist/compiler/internal/RecipeConditions.js.map +0 -1
  245. package/dist/compiler/internal/RecipePayloads.d.ts +0 -31
  246. package/dist/compiler/internal/RecipePayloads.d.ts.map +0 -1
  247. package/dist/compiler/internal/RecipePayloads.js +0 -99
  248. package/dist/compiler/internal/RecipePayloads.js.map +0 -1
  249. package/dist/compiler/internal/Recipes.d.ts +0 -32
  250. package/dist/compiler/internal/Recipes.d.ts.map +0 -1
  251. package/dist/compiler/internal/Recipes.js +0 -339
  252. package/dist/compiler/internal/Recipes.js.map +0 -1
  253. package/dist/compiler/internal/Selectors.d.ts +0 -13
  254. package/dist/compiler/internal/Selectors.d.ts.map +0 -1
  255. package/dist/compiler/internal/Selectors.js +0 -280
  256. package/dist/compiler/internal/Selectors.js.map +0 -1
  257. package/dist/compiler/internal/Static.d.ts +0 -39
  258. package/dist/compiler/internal/Static.d.ts.map +0 -1
  259. package/dist/compiler/internal/Static.js +0 -534
  260. package/dist/compiler/internal/Static.js.map +0 -1
  261. package/dist/compiler/internal/Themes.d.ts +0 -190
  262. package/dist/compiler/internal/Themes.d.ts.map +0 -1
  263. package/dist/compiler/internal/Themes.js +0 -1577
  264. package/dist/compiler/internal/Themes.js.map +0 -1
  265. package/dist/compiler/internal/Vars.d.ts +0 -33
  266. package/dist/compiler/internal/Vars.d.ts.map +0 -1
  267. package/dist/compiler/internal/Vars.js +0 -387
  268. package/dist/compiler/internal/Vars.js.map +0 -1
  269. package/dist/compiler/internal/ViewTransitions.d.ts +0 -3
  270. package/dist/compiler/internal/ViewTransitions.d.ts.map +0 -1
  271. package/dist/compiler/internal/ViewTransitions.js +0 -68
  272. package/dist/compiler/internal/ViewTransitions.js.map +0 -1
  273. package/dist/internal/Cascade.d.ts +0 -74
  274. package/dist/internal/Cascade.d.ts.map +0 -1
  275. package/dist/internal/Cascade.js +0 -210
  276. package/dist/internal/Cascade.js.map +0 -1
  277. package/src/compiler/internal/Applications.ts +0 -610
  278. package/src/compiler/internal/ColorProfiles.ts +0 -93
  279. package/src/compiler/internal/CompositionBindings.ts +0 -120
  280. package/src/compiler/internal/Compositions.ts +0 -678
  281. package/src/compiler/internal/Configurations.ts +0 -349
  282. package/src/compiler/internal/Contract.ts +0 -1028
  283. package/src/compiler/internal/Contributions.ts +0 -1561
  284. package/src/compiler/internal/Descriptors.ts +0 -242
  285. package/src/compiler/internal/Dynamic.ts +0 -275
  286. package/src/compiler/internal/Expression.ts +0 -218
  287. package/src/compiler/internal/Functions.ts +0 -206
  288. package/src/compiler/internal/Keyframes.ts +0 -62
  289. package/src/compiler/internal/Names.ts +0 -48
  290. package/src/compiler/internal/NativeBindings.ts +0 -235
  291. package/src/compiler/internal/NativeMedia.ts +0 -342
  292. package/src/compiler/internal/NativeVars.ts +0 -231
  293. package/src/compiler/internal/PackedStyles.ts +0 -473
  294. package/src/compiler/internal/Properties.ts +0 -121
  295. package/src/compiler/internal/RecipeConditions.ts +0 -139
  296. package/src/compiler/internal/RecipePayloads.ts +0 -132
  297. package/src/compiler/internal/Recipes.ts +0 -531
  298. package/src/compiler/internal/Selectors.ts +0 -353
  299. package/src/compiler/internal/Static.ts +0 -784
  300. package/src/compiler/internal/Themes.ts +0 -2398
  301. package/src/compiler/internal/Vars.ts +0 -516
  302. package/src/compiler/internal/ViewTransitions.ts +0 -82
@@ -0,0 +1,1045 @@
1
+ /**
2
+ * Decodes Rust `source.extract` results into the frozen data `Source.extract` returns.
3
+ * The format is documented in `crates/compiler/src/compiler/internal/wire.rs`.
4
+ * @module
5
+ */
6
+ import * as Authoring from '../../internal/Authoring.js'
7
+ import * as Binding from '../../internal/Binding.js'
8
+ import type * as Block from '../../web/internal/Block.js'
9
+ import * as ClassName from '../../web/internal/ClassName.js'
10
+ import * as Configuration from '../../internal/Configuration.js'
11
+ import type * as Css from '../../web/Css.js'
12
+ import * as Identity from '../../internal/Identity.js'
13
+ import { MissingTransformError } from '../../styleFunction.js'
14
+ import type * as Query from '../../internal/Query.js'
15
+ import * as Source from '../Source.js'
16
+ import * as Style from '../../Style.js'
17
+ import * as Theme from '../../internal/Theme.js'
18
+ import * as Token from '../../internal/Token.js'
19
+ import * as Vars from '../../Vars.js'
20
+
21
+ type Json =
22
+ | null
23
+ | boolean
24
+ | number
25
+ | string
26
+ | readonly Json[]
27
+ | { readonly [key: string]: Json }
28
+ type Pairs = readonly (readonly [string, Json])[]
29
+ type Fields = { readonly [key: string]: Json }
30
+
31
+ /** A failure encoded by the Rust compiler. */
32
+ type Failure = {
33
+ readonly diagnostics?: readonly Fields[]
34
+ readonly message: string
35
+ readonly name: string
36
+ readonly path?: readonly string[]
37
+ readonly reason?: string
38
+ }
39
+
40
+ /**
41
+ * Decodes one extraction result, or throws the error the extraction failed with.
42
+ * @param text - JSON text returned by the `source.extract` operation.
43
+ * @returns Frozen calls, styles, theme data, and contributions.
44
+ * @throws {Source.ExtractError} With every source diagnostic of a failed extraction.
45
+ */
46
+ export function decode(
47
+ text: string,
48
+ options: decode.Options = {},
49
+ ): Source.extract.ReturnType {
50
+ const output = JSON.parse(text) as {
51
+ readonly contracts?: readonly Fields[]
52
+ readonly error?: Failure
53
+ readonly result?: Fields
54
+ }
55
+
56
+ if (output.error) throw failure(output.error)
57
+
58
+ const contracts = (output.contracts ?? []).map(contract)
59
+ const decoder = create(contracts, options)
60
+
61
+ return decoder.result(output.result ?? {})
62
+ }
63
+
64
+ /** Extraction options that shape the decoded result. */
65
+ export declare namespace decode {
66
+ /** The options passed to the extraction. */
67
+ type Options = {
68
+ /** `false` when the extraction collected portable identities without source rewriting. */
69
+ readonly compiler?: boolean | undefined
70
+ }
71
+ }
72
+
73
+ /** Reconstructs the error class a TypeScript extraction throws. */
74
+ function failure(error: Failure): Error {
75
+ switch (error.name) {
76
+ case 'Source.ExtractError':
77
+ return new Source.ExtractError(
78
+ (error.diagnostics ?? []).map((diagnostic) =>
79
+ Object.freeze({
80
+ code: diagnostic.code as Source.Diagnostic['code'],
81
+ end: diagnostic.end as number,
82
+ message: diagnostic.message as string,
83
+ source: diagnostic.source as string,
84
+ start: diagnostic.start as number,
85
+ }),
86
+ ),
87
+ )
88
+ case 'Config.InvalidError':
89
+ return new Configuration.InvalidError(error.message)
90
+ case 'Theme.InvalidError':
91
+ return new Theme.InvalidError(
92
+ error.path ?? [],
93
+ error.reason ?? error.message,
94
+ )
95
+ case 'Vars.InvalidError':
96
+ return new Vars.InvalidError(
97
+ error.path ?? [],
98
+ error.reason ?? error.message,
99
+ )
100
+ case 'Style.InvalidError':
101
+ return new Style.InvalidError(
102
+ (error.diagnostics ?? []).map((diagnostic) => {
103
+ const location = diagnostic.location as Fields | undefined
104
+
105
+ return Object.freeze({
106
+ code: diagnostic.code as 'invalid_structure' | 'invalid_value',
107
+ ...(location
108
+ ? {
109
+ location: Object.freeze({
110
+ end: location.end as number,
111
+ path: Object.freeze([...(location.path as string[])]),
112
+ source: location.source as string,
113
+ start: location.start as number,
114
+ }),
115
+ }
116
+ : {}),
117
+ message: diagnostic.message as string,
118
+ path: Object.freeze([...(diagnostic.path as string[])]),
119
+ }) as Style.Diagnostic
120
+ }),
121
+ )
122
+ case 'MissingTransformError':
123
+ return new MissingTransformError()
124
+ default:
125
+ return new Error(error.message)
126
+ }
127
+ }
128
+
129
+ /** Rebuilds a contract with its enumerable properties in creation order. */
130
+ function contract(input: Fields): Token.Contract {
131
+ const value: Record<string | symbol, unknown> = {}
132
+
133
+ for (const key of input.keys as string[]) {
134
+ if (key === 'variableSet') value.variableSet = true
135
+ else if (key === 'mappings')
136
+ value.mappings = (() => {
137
+ if (input.mappings === undefined) return undefined
138
+ if (input.mappings === false) return false
139
+ return properties(input.mappings as Pairs)
140
+ })()
141
+ else if (key === 'shorthands')
142
+ value.shorthands = shorthands(input.shorthands)
143
+ else value[key] = input[key]
144
+ }
145
+
146
+ if (input.identity !== null) value[Token.identity] = input.identity
147
+ if (input.complete) value[Token.complete] = true
148
+
149
+ return Object.freeze(value) as Token.Contract
150
+ }
151
+
152
+ /** Shorthand mappings are frozen null-prototype records, as `Shorthands.read` returns them. */
153
+ function shorthands(
154
+ input: Json | undefined,
155
+ ): Readonly<Record<string, readonly string[]>> {
156
+ return Object.freeze(lookup(input, strings))
157
+ }
158
+
159
+ /** A frozen record of frozen string lists. */
160
+ function properties(input: Pairs): Readonly<Record<string, readonly string[]>> {
161
+ return Object.freeze(
162
+ Object.fromEntries(
163
+ input.map(([key, value]) => [
164
+ key,
165
+ Object.freeze([...(value as string[])]),
166
+ ]),
167
+ ),
168
+ )
169
+ }
170
+
171
+ function number(input: Json | undefined): number {
172
+ if (typeof input === 'number') return input
173
+ const tag = (input as Fields).n
174
+ if (tag === 'NaN') return Number.NaN
175
+ if (tag === 'Infinity') return Number.POSITIVE_INFINITY
176
+ if (tag === '-Infinity') return Number.NEGATIVE_INFINITY
177
+ return -0
178
+ }
179
+
180
+ function isNumber(input: Json | undefined): boolean {
181
+ return (
182
+ typeof input === 'number' ||
183
+ (typeof input === 'object' &&
184
+ input !== null &&
185
+ !Array.isArray(input) &&
186
+ 'n' in input)
187
+ )
188
+ }
189
+
190
+ function strings(input: Json | undefined): readonly string[] {
191
+ return Object.freeze([...(input as string[])])
192
+ }
193
+
194
+ function record<value>(
195
+ input: Json | undefined,
196
+ decode: (value: Json) => value,
197
+ ): Readonly<Record<string, value>> {
198
+ return Object.freeze(
199
+ Object.fromEntries(
200
+ (input as Pairs).map(([key, value]) => [key, decode(value)]),
201
+ ),
202
+ )
203
+ }
204
+
205
+ /** Authored container names are frozen copies, and an omitted list is a fresh array. */
206
+ function containerNames(input: Json | undefined): readonly string[] {
207
+ const names = input as string[]
208
+ return names.length ? Object.freeze([...names]) : []
209
+ }
210
+
211
+ /** A mutable null-prototype record. */
212
+ function lookup<value>(
213
+ input: Json | undefined,
214
+ decode: (value: Json) => value,
215
+ ): Record<string, value> {
216
+ return Object.assign(
217
+ Object.create(null) as Record<string, value>,
218
+ Object.fromEntries(
219
+ (input as Pairs).map(([key, value]) => [key, decode(value)]),
220
+ ),
221
+ )
222
+ }
223
+
224
+ /** Creates a decoder that shares one contract table. */
225
+ function create(contracts: readonly Token.Contract[], options: decode.Options) {
226
+ function binding(input: Fields): Binding.Reference {
227
+ const value = {
228
+ name: input.name as `--${string}`,
229
+ type: input.type as Binding.Domain,
230
+ ...(input.zero ? { zero: true } : {}),
231
+ variable: true as const,
232
+ }
233
+
234
+ return Object.freeze(
235
+ input.dynamic
236
+ ? Object.defineProperty(value, Binding.dynamic, { value: true })
237
+ : value,
238
+ ) as Binding.Reference
239
+ }
240
+
241
+ function reference(input: Fields): Token.Reference {
242
+ const value = Token.create({
243
+ contract: contracts[input.c as number]!,
244
+ group: input.g as Token.Group,
245
+ path: input.p as string,
246
+ value: tokenValue(input.v) as Token.Value,
247
+ })
248
+
249
+ return input.w
250
+ ? (Object.freeze({
251
+ ...value,
252
+ [Token.web]: true as const,
253
+ }) as Token.Reference)
254
+ : value
255
+ }
256
+
257
+ function expression(input: Fields): Token.Expression {
258
+ const parts = Object.freeze(
259
+ (input.parts as Json[]).map((part) => {
260
+ if (typeof part === 'string') return part
261
+ const fields = part as Fields
262
+ if ('binding' in fields) return binding(fields.binding as Fields)
263
+ return reference(fields.ref as Fields)
264
+ }),
265
+ )
266
+
267
+ return Object.freeze(
268
+ input.group === null
269
+ ? { [Token.expression]: true as const, parts }
270
+ : { [Token.expression]: true as const, group: input.group, parts },
271
+ ) as Token.Expression
272
+ }
273
+
274
+ function tokenValue(input: Json | undefined): unknown {
275
+ if (typeof input === 'string') return input
276
+ if (isNumber(input)) return number(input)
277
+ const fields = input as Fields
278
+ if ('ref' in fields) return reference(fields.ref as Fields)
279
+ if ('expr' in fields) return expression(fields.expr as Fields)
280
+ return record(fields.obj!, tokenValue)
281
+ }
282
+
283
+ function data(input: Json | undefined): unknown {
284
+ if (input === undefined) return undefined
285
+ if (
286
+ input === null ||
287
+ typeof input === 'string' ||
288
+ typeof input === 'boolean'
289
+ )
290
+ return input
291
+ if (typeof input === 'number') return input
292
+ if (Array.isArray(input)) return Object.freeze(input.map(data))
293
+ const fields = input as Fields
294
+ if ('n' in fields) return number(fields)
295
+ if ('$' in fields) return undefined
296
+ if ('ref' in fields) return reference(fields.ref as Fields)
297
+ if ('expr' in fields) return expression(fields.expr as Fields)
298
+ if ('binding' in fields) return binding(fields.binding as Fields)
299
+ if ('theme' in fields) return definition(fields.theme as Fields)
300
+ return record(fields.obj!, data)
301
+ }
302
+
303
+ // Authored configuration literals are mutable, and their objects have no prototype.
304
+ function authored(input: Json | undefined): unknown {
305
+ if (Array.isArray(input)) return input.map(authored)
306
+ if (input === null || typeof input !== 'object') return data(input)
307
+ const fields = input as Fields
308
+ if (!('obj' in fields)) return data(input)
309
+ return lookup(fields.obj, authored)
310
+ }
311
+
312
+ // Theme values flatten token groups into mutable records around the frozen token values.
313
+ // A group is never a value, so an object with scheme or condition keys is one.
314
+ function tree(input: Json | undefined): unknown {
315
+ const fields = input as Fields | null
316
+ const entries =
317
+ fields !== null && typeof fields === 'object'
318
+ ? (fields.obj as Pairs)
319
+ : undefined
320
+ if (
321
+ !entries ||
322
+ entries.some(
323
+ ([key]) => key === 'default' || key === 'light' || key === 'dark',
324
+ )
325
+ )
326
+ return data(input)
327
+ return Object.fromEntries(entries.map(([key, value]) => [key, tree(value)]))
328
+ }
329
+
330
+ // Query metadata spreads over the token values of each configured theme.
331
+ function themeValues(input: Json | undefined) {
332
+ return Object.fromEntries(
333
+ ((input as Fields).obj as Pairs).map(([key, value]) => {
334
+ if (key === 'breakpoint' || key === 'container')
335
+ return [key, Object.freeze(lookup((value as Fields).obj, String))]
336
+ if (key === 'containerNames') return [key, containerNames(value)]
337
+ return [key, tree(value)]
338
+ }),
339
+ )
340
+ }
341
+
342
+ // Normalized configuration options keep authored literals beside the flattened themes.
343
+ function configOptions(input: Json | undefined): Record<string, unknown> {
344
+ return Object.fromEntries(
345
+ ((input as Fields).obj as Pairs).map(([key, value]) => {
346
+ if (key === 'theme') return [key, themeValues(value)]
347
+ if (key === 'themes')
348
+ return [
349
+ key,
350
+ Object.fromEntries(
351
+ ((value as Fields).obj as Pairs).map(([name, theme]) => [
352
+ name,
353
+ themeValues(theme),
354
+ ]),
355
+ ),
356
+ ]
357
+ return [key, authored(value)]
358
+ }),
359
+ )
360
+ }
361
+
362
+ function definition(input: Fields): Theme.Definition {
363
+ const contract = contracts[input.contract as number]!
364
+ const queries = input.queries as Fields | null
365
+ const metadata = Object.freeze({
366
+ contract,
367
+ ...(input.cssName !== null ? { cssName: input.cssName as string } : {}),
368
+ ...(input.paths !== null
369
+ ? { paths: properties(input.paths as Pairs) }
370
+ : {}),
371
+ values: record(input.values, tokenValue) as Token.Metadata['values'],
372
+ // Variable sets always record their query metadata, even when it is empty.
373
+ ...(contract.variableSet && !queries ? { queries: undefined } : {}),
374
+ ...(queries
375
+ ? {
376
+ queries: Object.freeze({
377
+ breakpoint: Object.freeze(lookup(queries.breakpoint, String)),
378
+ containerNames: containerNames(queries.containerNames),
379
+ container: Object.freeze(lookup(queries.container, String)),
380
+ }) as Query.Metadata,
381
+ }
382
+ : {}),
383
+ })
384
+ const className = input.className as Fields
385
+ const value: Theme.Definition = Object.freeze(
386
+ Object.defineProperty(
387
+ {
388
+ get className(): string {
389
+ if ('ok' in className) return className.ok as string
390
+ if (className.error === new MissingTransformError().message)
391
+ throw new MissingTransformError()
392
+ throw new Error(className.error as string)
393
+ },
394
+ style: (styles?: unknown, options: Record<string, unknown> = {}) => {
395
+ if (!contract[Token.identity])
396
+ Identity.requireId(undefined, 'Theme.define')
397
+ return Authoring.create(styles, {
398
+ ...options,
399
+ theme: value,
400
+ } as never)
401
+ },
402
+ tokens: data(input.tokens),
403
+ variants: (
404
+ styles: Record<string, unknown>,
405
+ options: Record<string, unknown> = {},
406
+ ) => Authoring.variants(styles, options as never),
407
+ vars: data(input.vars),
408
+ },
409
+ Token.definition,
410
+ { value: metadata },
411
+ ),
412
+ ) as unknown as Theme.Definition
413
+
414
+ return value
415
+ }
416
+
417
+ function declarationValue(input: Json): Style.Declaration['value'] {
418
+ return data(input) as Style.Declaration['value']
419
+ }
420
+
421
+ function style(input: Fields): Style.NamedStyle {
422
+ const declarations = Object.freeze(
423
+ (input.declarations as Json[][]).map(([property, value, important]) =>
424
+ Object.freeze({
425
+ ...(important ? { important: true } : {}),
426
+ property: property as Style.Declaration['property'],
427
+ value: declarationValue(value!),
428
+ }),
429
+ ),
430
+ )
431
+ const rules = input.rules as Json[][] | undefined
432
+ const targets = input.targets as Fields | undefined
433
+ const body = rules
434
+ ? {
435
+ name: input.name as string,
436
+ declarations,
437
+ rules: Object.freeze(
438
+ rules.map(([condition, child]) =>
439
+ Object.freeze({
440
+ ...(condition !== null
441
+ ? { condition: condition as string }
442
+ : {}),
443
+ style: style(child as Fields),
444
+ }),
445
+ ),
446
+ ),
447
+ }
448
+ : { declarations, name: input.name as string }
449
+
450
+ return Object.freeze({
451
+ ...body,
452
+ ...(targets
453
+ ? {
454
+ targets: Object.freeze({
455
+ ...(targets.native !== undefined
456
+ ? { native: target(targets.native) }
457
+ : {}),
458
+ ...(targets.ios !== undefined
459
+ ? { ios: target(targets.ios) }
460
+ : {}),
461
+ ...(targets.android !== undefined
462
+ ? { android: target(targets.android) }
463
+ : {}),
464
+ ...(targets.web !== undefined
465
+ ? { web: style(targets.web as Fields) }
466
+ : {}),
467
+ }),
468
+ }
469
+ : {}),
470
+ ...(input.composition !== undefined
471
+ ? { composition: input.composition }
472
+ : {}),
473
+ ...(input.cssOutput !== undefined ? { cssOutput: input.cssOutput } : {}),
474
+ }) as Style.NamedStyle
475
+ }
476
+
477
+ // Native target data is copied into frozen null-prototype records, as `Targets.copy` does.
478
+ function target(input: Json | undefined): unknown {
479
+ if (Array.isArray(input)) return Object.freeze(input.map(target))
480
+ if (input === null || typeof input !== 'object' || !('obj' in input))
481
+ return data(input)
482
+ return Object.freeze(lookup((input as Fields).obj, target))
483
+ }
484
+
485
+ function styles(input: Fields): Style.Definition {
486
+ return Object.freeze({
487
+ styles: Object.freeze((input.styles as Fields[]).map(style)),
488
+ })
489
+ }
490
+
491
+ // Compositions copy the styles they combine, and a copy differs from its source in content.
492
+ function composed(
493
+ input: Fields,
494
+ sources: ReadonlyMap<string, string>,
495
+ ): Style.NamedStyle {
496
+ const decoded = style(input)
497
+ const rules = input.rules as Json[][] | undefined
498
+ const name = input.name as string
499
+
500
+ if (!rules || !decoded.rules) return decoded
501
+
502
+ const copied = (child: Fields) =>
503
+ sources.get(child.name as string) !== JSON.stringify(child)
504
+
505
+ // Runtime compositions copy each conditional rule with the output mode of its source.
506
+ if (name.startsWith('composition-'))
507
+ return Object.freeze({
508
+ ...decoded,
509
+ rules: Object.freeze(
510
+ decoded.rules.map((rule, index) => {
511
+ const child = rules[index]![1] as Fields
512
+ return copied(child) && !('cssOutput' in rule.style)
513
+ ? Object.freeze({
514
+ ...rule,
515
+ style: Object.freeze({ ...rule.style, cssOutput: undefined }),
516
+ })
517
+ : rule
518
+ }),
519
+ ),
520
+ })
521
+
522
+ // Static compositions copy referenced styles mutably beside their inline parts.
523
+ if (
524
+ decoded.declarations.length ||
525
+ rules.some(([condition]) => condition !== null)
526
+ )
527
+ return decoded
528
+
529
+ return Object.freeze({
530
+ ...decoded,
531
+ rules: Object.freeze(
532
+ decoded.rules.map((rule) =>
533
+ rule.style.name === name
534
+ ? rule
535
+ : Object.freeze({ ...rule, style: { ...rule.style } }),
536
+ ),
537
+ ),
538
+ })
539
+ }
540
+
541
+ function labelled(input: Fields): Style.Definition {
542
+ const inputs = input.styles as Fields[]
543
+ const sources = new Map(
544
+ inputs.map((entry) => [entry.name as string, JSON.stringify(entry)]),
545
+ )
546
+ const definition: Record<string | symbol, unknown> = {
547
+ styles: Object.freeze(inputs.map((entry) => composed(entry, sources))),
548
+ }
549
+ const labels = input.labels as Json[][] | undefined
550
+
551
+ if (labels)
552
+ Object.defineProperty(definition, ClassName.labels, {
553
+ value: Object.freeze(
554
+ Object.fromEntries(
555
+ labels.map(([name, label, namespace]) => [
556
+ name,
557
+ { name: label, namespace: namespace ?? undefined },
558
+ ]),
559
+ ),
560
+ ),
561
+ })
562
+
563
+ return Object.freeze(definition) as Style.Definition
564
+ }
565
+
566
+ // A call's lowered recipe shares the axes and defaults of its recipe metadata.
567
+ function staticRecipe(
568
+ input: Fields,
569
+ shared: ReturnType<typeof recipe> | undefined,
570
+ ) {
571
+ return {
572
+ axes:
573
+ shared?.axes ??
574
+ lookup(input.axes, (choices) => [...(choices as string[])]),
575
+ defaults: shared?.defaults ?? lookup(input.defaults, (value) => value),
576
+ rules: (input.rules as Fields[]).map((rule) => ({
577
+ matches: (rule.matches as Pairs).map(([axis, choices]) => [
578
+ axis,
579
+ [...(choices as string[])],
580
+ ]),
581
+ value: styles(rule.value as Fields),
582
+ })),
583
+ }
584
+ }
585
+
586
+ // Recipe metadata is mutable and keyed by null-prototype records, as `Recipes.expand` builds it.
587
+ function recipe(input: Fields) {
588
+ return {
589
+ axes: lookup(input.axes, (choices) => [...(choices as string[])]),
590
+ defaults: lookup(input.defaults, (value) => value),
591
+ ...(input.payloads !== undefined
592
+ ? {
593
+ payloads: (input.payloads as Fields[]).map((payload) => ({
594
+ axis: payload.axis as string,
595
+ choice: payload.choice as string,
596
+ slots: (payload.slots as Pairs[]).map((slots) =>
597
+ Object.fromEntries(slots),
598
+ ),
599
+ })),
600
+ defaultPayloads: lookup(input.defaultPayloads, (fields) =>
601
+ lookup(fields, (value) =>
602
+ isNumber(value) ? number(value) : value,
603
+ ),
604
+ ),
605
+ }
606
+ : {}),
607
+ ...(input.conditions !== undefined
608
+ ? { conditions: [...(input.conditions as string[])] }
609
+ : {}),
610
+ }
611
+ }
612
+
613
+ function slots(input: Json | undefined) {
614
+ return record(input, (value) => binding(value as Fields))
615
+ }
616
+
617
+ // Callback slots are null-prototype records, so field names never meet inherited keys.
618
+ function fields(input: Json | undefined) {
619
+ return Object.freeze(
620
+ Object.assign(
621
+ Object.create(null) as Record<string, Binding.Reference>,
622
+ Object.fromEntries(
623
+ (input as Pairs).map(([key, value]) => [
624
+ key,
625
+ binding(value as Fields),
626
+ ]),
627
+ ),
628
+ ),
629
+ )
630
+ }
631
+
632
+ function nativeContext(input: Fields) {
633
+ return Object.freeze({
634
+ defaultVars: input.defaultVars as string,
635
+ vars: record(input.vars, (value) => definition(value as Fields)),
636
+ })
637
+ }
638
+
639
+ function owner(input: Fields) {
640
+ return Object.freeze({
641
+ attributes: strings(input.attributes),
642
+ identity: input.identity as string,
643
+ slots: strings(input.slots),
644
+ })
645
+ }
646
+
647
+ function counts(input: Json | undefined): ReadonlyMap<number, number> {
648
+ return new Map(
649
+ (input as [number, number][]).map(([start, count]) => [start, count]),
650
+ )
651
+ }
652
+
653
+ function call(input: Fields): Source.Call {
654
+ const value: Record<string, unknown> = {}
655
+ const shared =
656
+ input.recipe !== undefined ? recipe(input.recipe as Fields) : undefined
657
+
658
+ // Without source rewriting, every definition call records its portable identity, if any.
659
+ if (
660
+ options.compiler === false &&
661
+ input.composition === undefined &&
662
+ input.runtimeComposition === undefined &&
663
+ input.compositionCase === undefined
664
+ )
665
+ value.portable = undefined
666
+
667
+ for (const [key, entry] of Object.entries(input)) {
668
+ switch (key) {
669
+ case 'nativeContext':
670
+ value[key] = nativeContext(entry as Fields)
671
+ break
672
+ case 'cssNamespace':
673
+ value[key] = entry ?? undefined
674
+ break
675
+ case 'portable':
676
+ value[key] = entry ?? undefined
677
+ break
678
+ // Composition metadata is assembled as mutable lists.
679
+ case 'portableInputs':
680
+ case 'compositionCases':
681
+ case 'composition':
682
+ value[key] = [...(entry as string[])]
683
+ break
684
+ case 'ownership':
685
+ value[key] = owner(entry as Fields)
686
+ break
687
+ case 'runtimeComposition':
688
+ value[key] = (entry as Fields[]).map((input) => ({
689
+ ...(input.applicationStart !== undefined
690
+ ? { applicationStart: input.applicationStart as number }
691
+ : {}),
692
+ ...(input.condition !== undefined
693
+ ? { condition: input.condition as number }
694
+ : {}),
695
+ end: input.end as number,
696
+ name: input.name as string,
697
+ owners: (input.owners as Fields[]).map((owner) => ({
698
+ attributes: [...(owner.attributes as string[])],
699
+ identity: owner.identity as string,
700
+ slots: [...(owner.slots as string[])],
701
+ })),
702
+ start: input.start as number,
703
+ }))
704
+ break
705
+ case 'recipe':
706
+ value[key] = shared
707
+ break
708
+ case 'dynamicRecipe':
709
+ case 'staticRecipe':
710
+ value[key] = staticRecipe(entry as Fields, shared)
711
+ break
712
+ case 'recipeTypes':
713
+ value[key] = lookup(entry, (choices) => lookup(choices, String))
714
+ break
715
+ case 'shorthands':
716
+ value[key] = shorthands(entry)
717
+ break
718
+ case 'typography':
719
+ case 'typographyQueries':
720
+ value[key] = counts(entry)
721
+ break
722
+ case 'slots':
723
+ value[key] = fields(entry)
724
+ break
725
+ default:
726
+ value[key] = entry
727
+ }
728
+ }
729
+
730
+ return Object.freeze(value) as Source.Call
731
+ }
732
+
733
+ function signature(input: Fields) {
734
+ return {
735
+ // Parameters are the evaluated literal records, which have no prototype.
736
+ parameters: (input.parameters as Fields[]).map((parameter) =>
737
+ Object.assign(Object.create(null) as Record<string, unknown>, {
738
+ ...(parameter.default !== undefined
739
+ ? {
740
+ default: isNumber(parameter.default)
741
+ ? number(parameter.default)
742
+ : parameter.default,
743
+ }
744
+ : {}),
745
+ name: parameter.name,
746
+ ...(parameter.syntax !== undefined
747
+ ? { syntax: parameter.syntax }
748
+ : {}),
749
+ }),
750
+ ),
751
+ returns: input.returns,
752
+ }
753
+ }
754
+
755
+ // Authored variable mappings stay the mutable null-prototype literal the configuration read.
756
+ function mappings(
757
+ input: Json | undefined,
758
+ ): Source.extract.ReturnType['themeCalls'][number]['variableMappings'] {
759
+ if (input === null || input === undefined) return undefined
760
+ if (input === false) return false
761
+ return lookup(input, (properties) => [
762
+ ...(properties as string[]),
763
+ ]) as NonNullable<
764
+ Source.extract.ReturnType['themeCalls'][number]['variableMappings']
765
+ >
766
+ }
767
+
768
+ // Configuration calls carry `appearance` and stay mutable. Factory calls are frozen.
769
+ function themeCall(
770
+ input: Fields,
771
+ ): Source.extract.ReturnType['themeCalls'][number] {
772
+ const value: Record<string, unknown> = {}
773
+
774
+ for (const [key, entry] of Object.entries(input)) {
775
+ // Variable configurations always record their mappings, even when none were authored.
776
+ if (
777
+ key === 'variableMappings' &&
778
+ (input.variableConfig || entry === false)
779
+ ) {
780
+ value[key] = mappings(entry)
781
+ continue
782
+ }
783
+
784
+ if (entry === null || entry === false) continue
785
+
786
+ switch (key) {
787
+ case 'function':
788
+ value[key] = signature(entry as Fields)
789
+ break
790
+ case 'members':
791
+ value[key] = input.appearance
792
+ ? Object.fromEntries(entry as Pairs)
793
+ : record(entry, String)
794
+ break
795
+ case 'options':
796
+ value[key] = configOptions(entry)
797
+ break
798
+ case 'variables':
799
+ value[key] = slots(entry)
800
+ break
801
+ default:
802
+ value[key] = entry
803
+ }
804
+ }
805
+
806
+ return (
807
+ input.appearance ? value : Object.freeze(value)
808
+ ) as Source.extract.ReturnType['themeCalls'][number]
809
+ }
810
+
811
+ function alias(
812
+ input: Fields,
813
+ ): Source.extract.ReturnType['themeAliases'][number] {
814
+ const call = input.call as Fields
815
+
816
+ // A style alias copies a fixed set of the theme call's fields, defined or not.
817
+ if (input.bindings !== null)
818
+ return {
819
+ recipe: call.recipe as boolean,
820
+ destructured: input.destructured as boolean,
821
+ end: call.end as number,
822
+ name: call.name as string,
823
+ start: call.start as number,
824
+ tokenType: call.tokenType as string,
825
+ type: (call.type ?? undefined) as string | undefined,
826
+ options:
827
+ call.options === null ? undefined : configOptions(call.options),
828
+ variableConfig: call.variableConfig ? true : undefined,
829
+ variableMappings: mappings(call.variableMappings),
830
+ output: (call.output ?? undefined) as 'html' | undefined,
831
+ bindings: [...(input.bindings as ('style' | 'variants')[])],
832
+ }
833
+
834
+ return {
835
+ ...themeCall(call),
836
+ destructured: input.destructured as boolean,
837
+ ...(input.retained ? { retained: true } : {}),
838
+ } as Source.extract.ReturnType['themeAliases'][number]
839
+ }
840
+
841
+ function varsRead(
842
+ input: Fields,
843
+ ): NonNullable<Source.extract.ReturnType['nativeVars']>[number] {
844
+ return {
845
+ defaultVars: input.defaultVars as string,
846
+ end: input.end as number,
847
+ owner: input.owner as string,
848
+ start: input.start as number,
849
+ unnamed: input.unnamed as boolean,
850
+ vars: Object.fromEntries(
851
+ (input.vars as Pairs).map(([key, value]) => [
852
+ key,
853
+ definition(value as Fields),
854
+ ]),
855
+ ),
856
+ }
857
+ }
858
+
859
+ // Contribution data is mutable. Only the styles `Style.define` produces inside it are frozen.
860
+ function entry(input: Fields): Block.Entry {
861
+ if (input.kind === 'block')
862
+ return {
863
+ kind: 'block',
864
+ header: input.header as string,
865
+ entries: (input.entries as Fields[]).map(entry),
866
+ }
867
+ if (input.kind === 'descriptor')
868
+ return {
869
+ kind: 'descriptor',
870
+ name: input.name as string,
871
+ value: (isNumber(input.value!) ? number(input.value!) : input.value) as
872
+ | string
873
+ | number,
874
+ }
875
+ return { kind: 'style', style: style(input.style as Fields) }
876
+ }
877
+
878
+ function scalarRecord(input: Json | undefined) {
879
+ return Object.fromEntries(
880
+ (input as Pairs).map(([key, value]) => [
881
+ key,
882
+ isNumber(value) ? number(value) : value,
883
+ ]),
884
+ ) as Record<string, string | number>
885
+ }
886
+
887
+ // Grouping rules nest plain `global` styles around the defined styles of their selectors.
888
+ function ruleStyle(input: Fields): Style.NamedStyle {
889
+ if (input.name !== 'global') return style(input)
890
+
891
+ return {
892
+ name: 'global',
893
+ declarations: [],
894
+ rules: ((input.rules as Json[][] | undefined) ?? []).map(
895
+ ([condition, child]) => ({
896
+ condition: condition as string,
897
+ style: ruleStyle(child as Fields),
898
+ }),
899
+ ),
900
+ }
901
+ }
902
+
903
+ function contribution(input: Fields): Css.Contribution {
904
+ const value = ((): Record<string, unknown> => {
905
+ switch (input.kind) {
906
+ case 'block':
907
+ return {
908
+ kind: 'block',
909
+ header: input.header,
910
+ entries: (input.entries as Fields[]).map(entry),
911
+ }
912
+ case 'descriptor':
913
+ return {
914
+ kind: 'descriptor',
915
+ rule: input.rule,
916
+ name: input.name,
917
+ declarations: scalarRecord(input.declarations),
918
+ }
919
+ case 'font-face':
920
+ return {
921
+ kind: 'font-face',
922
+ declarations: scalarRecord(input.declarations),
923
+ }
924
+ case 'keyframes':
925
+ return {
926
+ kind: 'keyframes',
927
+ name: input.name,
928
+ frames: (input.frames as Fields[]).map((frame) => ({
929
+ stop: frame.stop as string,
930
+ style: style(frame.style as Fields),
931
+ })),
932
+ }
933
+ case 'layers':
934
+ return { kind: 'layers', names: [...(input.names as string[])] }
935
+ case 'rule':
936
+ return {
937
+ kind: 'rule',
938
+ selector: input.selector,
939
+ style: ruleStyle(input.style as Fields),
940
+ }
941
+ default:
942
+ return Object.fromEntries(
943
+ Object.entries(input).filter(([key]) => key !== 'within'),
944
+ )
945
+ }
946
+ })()
947
+
948
+ return (
949
+ input.within !== undefined
950
+ ? { ...value, within: [...(input.within as string[])] }
951
+ : value
952
+ ) as Css.Contribution
953
+ }
954
+
955
+ function contributionCall(
956
+ input: Fields,
957
+ ): NonNullable<Source.extract.ReturnType['contributionCalls']>[number] {
958
+ return {
959
+ kind: input.kind,
960
+ start: input.start,
961
+ end: input.end,
962
+ ...(input.function !== undefined
963
+ ? { function: signature(input.function as Fields) }
964
+ : {}),
965
+ ...(input.name !== undefined ? { name: input.name } : {}),
966
+ ...(input.binding !== undefined ? { binding: input.binding } : {}),
967
+ ...(input.exported !== undefined ? { exported: input.exported } : {}),
968
+ } as NonNullable<Source.extract.ReturnType['contributionCalls']>[number]
969
+ }
970
+
971
+ function result(input: Fields): Source.extract.ReturnType {
972
+ const contributions = (
973
+ (input.contributions as Fields[] | undefined) ?? []
974
+ ).map(contribution)
975
+ // Namespaces are the namespace contributions themselves, as a filtered list.
976
+ const value: Record<string, unknown> = {
977
+ namespaces: contributions.filter((entry) => entry.kind === 'namespace'),
978
+ }
979
+
980
+ if (input.contributions !== undefined) {
981
+ value.contributions = contributions
982
+ value.contributionStarts = [...(input.contributionStarts as number[])]
983
+ }
984
+
985
+ if (input.contributionCalls !== undefined)
986
+ value.contributionCalls = (input.contributionCalls as Fields[]).map(
987
+ contributionCall,
988
+ )
989
+
990
+ value.calls = Object.freeze((input.calls as Fields[]).map(call))
991
+ value.styles = labelled(input.styles as Fields)
992
+
993
+ if (input.variableCalls !== undefined)
994
+ value.variableCalls = Object.freeze(
995
+ (input.variableCalls as Fields[]).map((entry) =>
996
+ Object.freeze({
997
+ explicit: entry.explicit as boolean,
998
+ start: entry.start as number,
999
+ end: entry.end as number,
1000
+ slots: slots(entry.slots),
1001
+ }),
1002
+ ),
1003
+ )
1004
+
1005
+ value.themeAliases = Object.freeze(
1006
+ (input.themeAliases as Fields[]).map(alias),
1007
+ )
1008
+
1009
+ for (const key of ['themeAppearances', 'themeScripts', 'themeSelections'])
1010
+ if (input[key] !== undefined) value[key] = strings(input[key]!)
1011
+
1012
+ value.themeCalls = Object.freeze(
1013
+ (input.themeCalls as Fields[]).map(themeCall),
1014
+ )
1015
+
1016
+ if (input.staticThemeReferences !== undefined)
1017
+ value.staticThemeReferences = Object.freeze(
1018
+ (input.staticThemeReferences as Fields[]).map((entry) => ({
1019
+ ...entry,
1020
+ })),
1021
+ )
1022
+
1023
+ value.themeReferences = Object.freeze(
1024
+ (input.themeReferences as Fields[]).map((entry) =>
1025
+ Object.freeze({ ...entry }),
1026
+ ),
1027
+ )
1028
+ // Collected themes are keyed by a null-prototype record. A module without theme
1029
+ // imports collects none and returns an ordinary empty record.
1030
+ value.vars = Object.freeze(
1031
+ input.collectedThemes
1032
+ ? lookup(input.vars, (entry) => definition(entry as Fields))
1033
+ : {},
1034
+ )
1035
+
1036
+ if (input.nativeVars !== undefined)
1037
+ value.nativeVars = Object.freeze(
1038
+ (input.nativeVars as Fields[]).map(varsRead),
1039
+ )
1040
+
1041
+ return Object.freeze(value) as unknown as Source.extract.ReturnType
1042
+ }
1043
+
1044
+ return { result }
1045
+ }