zyzz 0.0.3 → 0.0.5

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 (247) hide show
  1. package/README.md +34 -19
  2. package/dist/Config.d.ts +16 -167
  3. package/dist/Config.d.ts.map +1 -1
  4. package/dist/Config.js +7 -246
  5. package/dist/Config.js.map +1 -1
  6. package/dist/Style.d.ts +15 -12
  7. package/dist/Style.d.ts.map +1 -1
  8. package/dist/Style.js +51 -26
  9. package/dist/Style.js.map +1 -1
  10. package/dist/Vars.d.ts +114 -0
  11. package/dist/Vars.d.ts.map +1 -0
  12. package/dist/Vars.js +42 -0
  13. package/dist/Vars.js.map +1 -0
  14. package/dist/compiler/Graph.js +11 -8
  15. package/dist/compiler/Graph.js.map +1 -1
  16. package/dist/compiler/Native.d.ts +5 -5
  17. package/dist/compiler/Native.d.ts.map +1 -1
  18. package/dist/compiler/Native.js +21 -21
  19. package/dist/compiler/Native.js.map +1 -1
  20. package/dist/compiler/Source.d.ts +8 -6
  21. package/dist/compiler/Source.d.ts.map +1 -1
  22. package/dist/compiler/Source.js +47 -14
  23. package/dist/compiler/Source.js.map +1 -1
  24. package/dist/compiler/Transform.d.ts +1 -1
  25. package/dist/compiler/Transform.d.ts.map +1 -1
  26. package/dist/compiler/Transform.js +58 -22
  27. package/dist/compiler/Transform.js.map +1 -1
  28. package/dist/compiler/internal/Compositions.d.ts +5 -0
  29. package/dist/compiler/internal/Compositions.d.ts.map +1 -1
  30. package/dist/compiler/internal/Compositions.js +22 -3
  31. package/dist/compiler/internal/Compositions.js.map +1 -1
  32. package/dist/compiler/internal/Configurations.d.ts.map +1 -1
  33. package/dist/compiler/internal/Configurations.js +73 -12
  34. package/dist/compiler/internal/Configurations.js.map +1 -1
  35. package/dist/compiler/internal/Contract.d.ts +1 -1
  36. package/dist/compiler/internal/Contract.d.ts.map +1 -1
  37. package/dist/compiler/internal/Contract.js +155 -13
  38. package/dist/compiler/internal/Contract.js.map +1 -1
  39. package/dist/compiler/internal/Contributions.js +1 -1
  40. package/dist/compiler/internal/Contributions.js.map +1 -1
  41. package/dist/compiler/internal/Dynamic.js +1 -1
  42. package/dist/compiler/internal/Dynamic.js.map +1 -1
  43. package/dist/compiler/internal/Expression.d.ts +3 -0
  44. package/dist/compiler/internal/Expression.d.ts.map +1 -1
  45. package/dist/compiler/internal/Expression.js +21 -0
  46. package/dist/compiler/internal/Expression.js.map +1 -1
  47. package/dist/compiler/internal/Identifiers.d.ts +1 -1
  48. package/dist/compiler/internal/Identifiers.d.ts.map +1 -1
  49. package/dist/compiler/internal/Identifiers.js +2 -2
  50. package/dist/compiler/internal/Identifiers.js.map +1 -1
  51. package/dist/compiler/internal/NativeBindings.d.ts +1 -1
  52. package/dist/compiler/internal/NativeBindings.d.ts.map +1 -1
  53. package/dist/compiler/internal/NativeBindings.js +3 -3
  54. package/dist/compiler/internal/NativeBindings.js.map +1 -1
  55. package/dist/compiler/internal/PackedStyles.d.ts +1 -1
  56. package/dist/compiler/internal/PackedStyles.d.ts.map +1 -1
  57. package/dist/compiler/internal/PackedStyles.js +15 -25
  58. package/dist/compiler/internal/PackedStyles.js.map +1 -1
  59. package/dist/compiler/internal/Recipes.js +1 -1
  60. package/dist/compiler/internal/Recipes.js.map +1 -1
  61. package/dist/compiler/internal/Selectors.js +1 -1
  62. package/dist/compiler/internal/Selectors.js.map +1 -1
  63. package/dist/compiler/internal/Themes.d.ts +12 -3
  64. package/dist/compiler/internal/Themes.d.ts.map +1 -1
  65. package/dist/compiler/internal/Themes.js +192 -52
  66. package/dist/compiler/internal/Themes.js.map +1 -1
  67. package/dist/compiler/internal/{Variables.d.ts → Vars.d.ts} +1 -1
  68. package/dist/compiler/internal/Vars.d.ts.map +1 -0
  69. package/dist/compiler/internal/{Variables.js → Vars.js} +3 -3
  70. package/dist/compiler/internal/Vars.js.map +1 -0
  71. package/dist/default.d.ts +147 -2562
  72. package/dist/default.d.ts.map +1 -1
  73. package/dist/default.js +85 -80
  74. package/dist/default.js.map +2 -2
  75. package/dist/default.js.zyzz.json +1 -1
  76. package/dist/esbuild/index.d.ts +3 -0
  77. package/dist/esbuild/index.d.ts.map +1 -0
  78. package/dist/esbuild/index.js +5 -0
  79. package/dist/esbuild/index.js.map +1 -0
  80. package/dist/index.d.ts +4 -4
  81. package/dist/index.d.ts.map +1 -1
  82. package/dist/index.js +4 -4
  83. package/dist/index.js.map +1 -1
  84. package/dist/internal/Authoring.d.ts +1 -1
  85. package/dist/internal/Authoring.d.ts.map +1 -1
  86. package/dist/internal/Authoring.js +4 -4
  87. package/dist/internal/Authoring.js.map +1 -1
  88. package/dist/internal/Binding.d.ts +1 -1
  89. package/dist/internal/Binding.d.ts.map +1 -1
  90. package/dist/internal/Completion.d.ts +19 -0
  91. package/dist/internal/Completion.d.ts.map +1 -0
  92. package/dist/internal/Completion.js +2 -0
  93. package/dist/internal/Completion.js.map +1 -0
  94. package/dist/internal/Condition.d.ts +3 -1
  95. package/dist/internal/Condition.d.ts.map +1 -1
  96. package/dist/internal/Condition.js.map +1 -1
  97. package/dist/internal/Configuration.d.ts +248 -0
  98. package/dist/internal/Configuration.d.ts.map +1 -0
  99. package/dist/internal/Configuration.js +343 -0
  100. package/dist/internal/Configuration.js.map +1 -0
  101. package/dist/{Theme.d.ts → internal/Theme.d.ts} +15 -13
  102. package/dist/internal/Theme.d.ts.map +1 -0
  103. package/dist/{Theme.js → internal/Theme.js} +39 -12
  104. package/dist/internal/Theme.js.map +1 -0
  105. package/dist/internal/Token.d.ts +46 -16
  106. package/dist/internal/Token.d.ts.map +1 -1
  107. package/dist/internal/Token.js +89 -5
  108. package/dist/internal/Token.js.map +1 -1
  109. package/dist/internal/Typography.d.ts +13 -5
  110. package/dist/internal/Typography.d.ts.map +1 -1
  111. package/dist/internal/Typography.js +42 -6
  112. package/dist/internal/Typography.js.map +1 -1
  113. package/dist/internal/Value.d.ts +6 -1
  114. package/dist/internal/Value.d.ts.map +1 -1
  115. package/dist/internal/Value.js.map +1 -1
  116. package/dist/internal/VariableSets.d.ts +20 -0
  117. package/dist/internal/VariableSets.d.ts.map +1 -0
  118. package/dist/internal/VariableSets.js +317 -0
  119. package/dist/internal/VariableSets.js.map +1 -0
  120. package/dist/next/loader.js +15 -5
  121. package/dist/next/loader.js.map +1 -1
  122. package/dist/node/Host.d.ts.map +1 -1
  123. package/dist/node/Host.js +1 -1
  124. package/dist/node/Host.js.map +1 -1
  125. package/dist/react-native/Host.d.ts +2 -2
  126. package/dist/react-native/Host.d.ts.map +1 -1
  127. package/dist/react-native/Host.js +4 -4
  128. package/dist/react-native/Host.js.map +1 -1
  129. package/dist/react-native/StyleSheet.d.ts +9 -8
  130. package/dist/react-native/StyleSheet.d.ts.map +1 -1
  131. package/dist/react-native/StyleSheet.js +29 -23
  132. package/dist/react-native/StyleSheet.js.map +1 -1
  133. package/dist/react-native/Variants.d.ts +3 -3
  134. package/dist/react-native/Variants.d.ts.map +1 -1
  135. package/dist/react-native/Variants.js +2 -2
  136. package/dist/react-native/react.d.ts +1 -1
  137. package/dist/react-native/react.d.ts.map +1 -1
  138. package/dist/react-native/react.js +5 -5
  139. package/dist/react-native/react.js.map +1 -1
  140. package/dist/rollup/index.d.ts +3 -0
  141. package/dist/rollup/index.d.ts.map +1 -0
  142. package/dist/rollup/index.js +5 -0
  143. package/dist/rollup/index.js.map +1 -0
  144. package/dist/runtime/Appearance.d.ts +7 -7
  145. package/dist/runtime/Appearance.d.ts.map +1 -1
  146. package/dist/runtime/Appearance.js +15 -15
  147. package/dist/runtime/Appearance.js.map +1 -1
  148. package/dist/runtime/Dynamic.d.ts.map +1 -1
  149. package/dist/runtime/Dynamic.js +4 -1
  150. package/dist/runtime/Dynamic.js.map +1 -1
  151. package/dist/runtime/NativeContext.d.ts +4 -4
  152. package/dist/runtime/NativeContext.d.ts.map +1 -1
  153. package/dist/runtime/NativeContext.js +5 -5
  154. package/dist/runtime/NativeContext.js.map +1 -1
  155. package/dist/runtime/NativeDynamic.d.ts +1 -1
  156. package/dist/runtime/NativeDynamic.d.ts.map +1 -1
  157. package/dist/runtime/NativeDynamic.js.map +1 -1
  158. package/dist/runtime/Props.d.ts +1 -1
  159. package/dist/runtime/Props.js +3 -3
  160. package/dist/runtime/Props.js.map +1 -1
  161. package/dist/runtime/Selection.d.ts +14 -10
  162. package/dist/runtime/Selection.d.ts.map +1 -1
  163. package/dist/runtime/Selection.js +19 -18
  164. package/dist/runtime/Selection.js.map +1 -1
  165. package/dist/styleFunction.d.ts +14 -14
  166. package/dist/styleFunction.d.ts.map +1 -1
  167. package/dist/styleFunction.js.map +1 -1
  168. package/dist/unplugin/index.d.ts +20 -0
  169. package/dist/unplugin/index.d.ts.map +1 -0
  170. package/dist/unplugin/index.js +498 -0
  171. package/dist/unplugin/index.js.map +1 -0
  172. package/dist/variants.d.ts +3 -3
  173. package/dist/variants.d.ts.map +1 -1
  174. package/dist/variants.js.map +1 -1
  175. package/dist/vite/index.d.ts.map +1 -1
  176. package/dist/vite/index.js +6 -3
  177. package/dist/vite/index.js.map +1 -1
  178. package/dist/web/Css.d.ts +4 -3
  179. package/dist/web/Css.d.ts.map +1 -1
  180. package/dist/web/Css.js +4 -4
  181. package/dist/web/Css.js.map +1 -1
  182. package/dist/web/internal/Themes.d.ts +3 -2
  183. package/dist/web/internal/Themes.d.ts.map +1 -1
  184. package/dist/web/internal/Themes.js +42 -6
  185. package/dist/web/internal/Themes.js.map +1 -1
  186. package/dist/webpack/index.d.ts +3 -0
  187. package/dist/webpack/index.d.ts.map +1 -0
  188. package/dist/webpack/index.js +5 -0
  189. package/dist/webpack/index.js.map +1 -0
  190. package/package.json +23 -2
  191. package/src/Config.ts +43 -685
  192. package/src/Style.ts +97 -34
  193. package/src/Vars.ts +299 -0
  194. package/src/compiler/Graph.ts +14 -9
  195. package/src/compiler/Native.ts +29 -32
  196. package/src/compiler/Source.ts +59 -21
  197. package/src/compiler/Transform.ts +73 -23
  198. package/src/compiler/internal/Compositions.ts +36 -3
  199. package/src/compiler/internal/Configurations.ts +83 -11
  200. package/src/compiler/internal/Contract.ts +207 -15
  201. package/src/compiler/internal/Contributions.ts +1 -1
  202. package/src/compiler/internal/Dynamic.ts +1 -1
  203. package/src/compiler/internal/Expression.ts +26 -0
  204. package/src/compiler/internal/Identifiers.ts +2 -1
  205. package/src/compiler/internal/NativeBindings.ts +3 -3
  206. package/src/compiler/internal/PackedStyles.ts +22 -26
  207. package/src/compiler/internal/Recipes.ts +1 -1
  208. package/src/compiler/internal/Selectors.ts +1 -1
  209. package/src/compiler/internal/Themes.ts +266 -57
  210. package/src/compiler/internal/{Variables.ts → Vars.ts} +2 -2
  211. package/src/default.ts +173 -154
  212. package/src/esbuild/index.ts +5 -0
  213. package/src/index.ts +4 -4
  214. package/src/internal/Authoring.ts +5 -7
  215. package/src/internal/Binding.ts +1 -1
  216. package/src/internal/Completion.ts +42 -0
  217. package/src/internal/Condition.ts +31 -1
  218. package/src/internal/Configuration.ts +970 -0
  219. package/src/{Theme.ts → internal/Theme.ts} +75 -20
  220. package/src/internal/Token.ts +258 -85
  221. package/src/internal/Typography.ts +71 -16
  222. package/src/internal/Value.ts +45 -26
  223. package/src/internal/VariableSets.ts +458 -0
  224. package/src/next/loader.ts +19 -5
  225. package/src/node/Host.ts +1 -2
  226. package/src/react-native/Host.ts +6 -6
  227. package/src/react-native/StyleSheet.ts +49 -42
  228. package/src/react-native/Variants.ts +3 -3
  229. package/src/react-native/react.ts +6 -6
  230. package/src/rollup/index.ts +5 -0
  231. package/src/runtime/Appearance.ts +20 -20
  232. package/src/runtime/Dynamic.ts +4 -1
  233. package/src/runtime/NativeContext.ts +8 -8
  234. package/src/runtime/NativeDynamic.ts +2 -4
  235. package/src/runtime/Props.ts +3 -3
  236. package/src/runtime/Selection.ts +44 -33
  237. package/src/styleFunction.ts +22 -19
  238. package/src/unplugin/index.ts +600 -0
  239. package/src/variants.ts +7 -5
  240. package/src/vite/index.ts +5 -4
  241. package/src/web/Css.ts +10 -7
  242. package/src/web/internal/Themes.ts +52 -9
  243. package/src/webpack/index.ts +5 -0
  244. package/dist/Theme.d.ts.map +0 -1
  245. package/dist/Theme.js.map +0 -1
  246. package/dist/compiler/internal/Variables.d.ts.map +0 -1
  247. package/dist/compiler/internal/Variables.js.map +0 -1
@@ -1,10 +1,12 @@
1
1
  import * as Identity from '../../internal/Identity.js';
2
2
  import * as Identifiers from './Identifiers.js';
3
- import * as Config from '../../Config.js';
3
+ import * as Config from '../../internal/Configuration.js';
4
4
  import * as Expression from './Expression.js';
5
5
  import * as Configurations from './Configurations.js';
6
6
  import * as Token from '../../internal/Token.js';
7
- import * as Theme from '../../Theme.js';
7
+ import * as Theme from '../../internal/Theme.js';
8
+ import * as VariableSets from '../../internal/VariableSets.js';
9
+ import * as Vars from '../../Vars.js';
8
10
  /** Internal context passed between graph extraction and module rewriting. */
9
11
  export const context = Symbol('zyzz.source.graph');
10
12
  /** Collects immutable module-level themes without evaluating source. */
@@ -14,12 +16,14 @@ export function collect(program, options) {
14
16
  const aliasBindings = new Map();
15
17
  const aliasReferences = new Set();
16
18
  const appearances = new Set();
19
+ const scopeApplications = new Map();
17
20
  const selections = new Set();
18
21
  const calls = [];
19
22
  const scripts = new Set();
20
23
  const definitions = new Map();
21
24
  const factories = new Set();
22
25
  const imports = new Set();
26
+ const variableImports = new Set();
23
27
  const configImports = new Set();
24
28
  const configs = new Map();
25
29
  const configBindings = new Map();
@@ -38,8 +42,10 @@ export function collect(program, options) {
38
42
  specifier.importKind !== 'type' &&
39
43
  (specifier.imported.type === 'Identifier'
40
44
  ? specifier.imported.name
41
- : specifier.imported.value) === 'Theme')
45
+ : specifier.imported.value) === 'Vars') {
42
46
  imports.add(specifier.start);
47
+ variableImports.add(specifier.start);
48
+ }
43
49
  else if (specifier.type === 'ImportSpecifier' &&
44
50
  specifier.importKind !== 'type' &&
45
51
  (specifier.imported.type === 'Identifier'
@@ -94,6 +100,12 @@ export function collect(program, options) {
94
100
  }
95
101
  const namespaces = new Set();
96
102
  const configNamespaces = new Set();
103
+ const variableNamespaces = new Set();
104
+ for (const node of program.body)
105
+ if (node.type === 'ImportDeclaration')
106
+ for (const specifier of node.specifiers)
107
+ if (variableImports.has(specifier.start))
108
+ variableNamespaces.add(specifier.local.name);
97
109
  for (const node of program.body)
98
110
  if (node.type === 'ImportDeclaration')
99
111
  for (const specifier of node.specifiers)
@@ -144,15 +156,17 @@ export function collect(program, options) {
144
156
  !config.call.initialization &&
145
157
  !config.call.root &&
146
158
  path.length === 1 &&
147
- ['themes', 'script', 'appearance'].includes(path[0])) {
159
+ ['themes', 'vars', 'script', 'appearance'].includes(path[0])) {
148
160
  const key = path[0];
161
+ if (config.call.variableConfig && key === 'themes')
162
+ return undefined;
149
163
  if (key === 'script')
150
164
  scripts.add(config.call.name);
151
165
  if (key === 'appearance')
152
166
  appearances.add(config.call.name);
153
167
  if (key === 'themes' && !config.call.options?.themes)
154
168
  return undefined;
155
- if (key === 'themes')
169
+ if (key === 'themes' || key === 'vars')
156
170
  selections.add(config.call.name);
157
171
  if (key === 'script' && !config.call.script)
158
172
  fail('This packed configuration does not provide script(); rebuild its library with initialization support.', node);
@@ -160,7 +174,7 @@ export function collect(program, options) {
160
174
  fail('This packed configuration does not provide appearance; rebuild its library with root control support.', node);
161
175
  const members = Object.fromEntries(Object.entries(config.members ?? {}).flatMap(([name, member]) => {
162
176
  const parts = JSON.parse(name);
163
- return key === 'themes' && parts[0] === 'themes'
177
+ return (key === 'themes' || key === 'vars') && parts[0] === 'themes'
164
178
  ? [[JSON.stringify(parts.slice(1)), member]]
165
179
  : [];
166
180
  }));
@@ -189,9 +203,48 @@ export function collect(program, options) {
189
203
  return { root: true };
190
204
  return { selection: true };
191
205
  }
192
- function data(node) {
206
+ function readReference(node, derived) {
207
+ if (node.type !== 'MemberExpression')
208
+ return undefined;
209
+ const path = [];
210
+ let root = node;
211
+ while (root.type === 'MemberExpression' && !root.optional) {
212
+ const key = !root.computed && root.property.type === 'Identifier'
213
+ ? root.property.name
214
+ : root.property.type === 'Literal'
215
+ ? String(root.property.value)
216
+ : undefined;
217
+ if (key === undefined)
218
+ return undefined;
219
+ path.unshift(key);
220
+ root = root.object;
221
+ }
222
+ if (root.type !== 'Identifier')
223
+ return undefined;
224
+ const local = derived?.name === root.name;
225
+ const call = names.get(root.name);
226
+ if (!local && !call)
227
+ return undefined;
228
+ let value = local ? derived.vars : themes[call.name]?.tokens;
229
+ if (!local && !call.variableSet && !call.directVariables) {
230
+ if (!['vars', 'tokens'].includes(path.shift()))
231
+ return undefined;
232
+ }
233
+ for (const key of path)
234
+ value =
235
+ value && typeof value === 'object'
236
+ ? Object.getOwnPropertyDescriptor(value, key)?.value
237
+ : undefined;
238
+ return Token.is(value) ? value : undefined;
239
+ }
240
+ function data(node, derived) {
241
+ const reference = readReference(node, derived);
242
+ if (reference) {
243
+ factoryReferences.add(node.start);
244
+ return reference;
245
+ }
193
246
  if (node.type === 'TSAsExpression' || node.type === 'TSSatisfiesExpression')
194
- return data(node.expression);
247
+ return data(node.expression, derived);
195
248
  if (node.type === 'Literal' &&
196
249
  (typeof node.value === 'string' || typeof node.value === 'number'))
197
250
  return node.value;
@@ -204,7 +257,7 @@ export function collect(program, options) {
204
257
  return node.elements.map((element) => {
205
258
  if (!element || element.type === 'SpreadElement')
206
259
  return fail('Theme arrays require dense literal elements.', node);
207
- return data(element);
260
+ return data(element, derived);
208
261
  });
209
262
  if (node.type !== 'ObjectExpression')
210
263
  return fail('Theme values must be literal data; expressions are not evaluated.', node);
@@ -229,7 +282,7 @@ export function collect(program, options) {
229
282
  })();
230
283
  if (key === undefined || Object.hasOwn(result, key))
231
284
  return fail('Theme data requires unique literal keys.', property);
232
- result[key] = data(property.value);
285
+ result[key] = data(property.value, derived);
233
286
  }
234
287
  return result;
235
288
  }
@@ -240,7 +293,7 @@ export function collect(program, options) {
240
293
  if (node.type === 'TSAsExpression' || node.type === 'TSSatisfiesExpression')
241
294
  return type(node.expression);
242
295
  if (node.type !== 'ObjectExpression')
243
- return JSON.stringify(data(node));
296
+ return Configurations.type(data(node));
244
297
  return `{${node.properties
245
298
  .map((property) => {
246
299
  if (property.type !== 'Property')
@@ -308,9 +361,14 @@ export function collect(program, options) {
308
361
  let name = `${options.namespace}-${binding}`;
309
362
  if (!configNamespaces.has(expression.callee.object.name) &&
310
363
  member.property.name === 'define') {
311
- const id = Identifiers.explicit(expression);
364
+ const argument = expression.arguments[1];
365
+ const callback = argument && Expression.unwrap(argument);
366
+ const id = Identifiers.explicit(expression, callback?.type === 'ArrowFunctionExpression' ||
367
+ callback?.type === 'FunctionExpression'
368
+ ? 2
369
+ : 1);
312
370
  if (id !== undefined)
313
- name = Identity.requireId(id, 'Theme.define');
371
+ name = Identity.requireId(id, 'Vars.define');
314
372
  }
315
373
  if (configNamespaces.has(expression.callee.object.name)) {
316
374
  try {
@@ -361,7 +419,8 @@ export function collect(program, options) {
361
419
  !link.call.root &&
362
420
  (key === 'script' ||
363
421
  key === 'appearance' ||
364
- (key === 'themes' && link.call.options?.themes))) {
422
+ (key === 'themes' && link.call.options?.themes) ||
423
+ (key === 'vars' && link.call.variableConfig))) {
365
424
  if ((key === 'script' && !link.call.script) ||
366
425
  (key === 'appearance' && !link.call.appearance) ||
367
426
  link.call.selection ||
@@ -371,11 +430,12 @@ export function collect(program, options) {
371
430
  scripts.add(link.call.name);
372
431
  if (key === 'appearance')
373
432
  appearances.add(link.call.name);
374
- if (key === 'themes')
433
+ if (key === 'themes' || key === 'vars')
375
434
  selections.add(link.call.name);
376
435
  const members = Object.fromEntries(Object.entries(link.members ?? {}).flatMap(([pathKey, member]) => {
377
436
  const path = JSON.parse(pathKey);
378
- return key === 'themes' && path[0] === 'themes'
437
+ return (key === 'themes' || key === 'vars') &&
438
+ (path[0] === 'themes' || path[0] === 'vars')
379
439
  ? [[JSON.stringify(path.slice(1)), member]]
380
440
  : [];
381
441
  }));
@@ -398,6 +458,8 @@ export function collect(program, options) {
398
458
  exports[id.name] = selection;
399
459
  continue;
400
460
  }
461
+ if (link.call.variableConfig && ['theme', 'themes'].includes(key))
462
+ fail('Use vars for references and scope selection.', id);
401
463
  const member = link.members?.[JSON.stringify([key])];
402
464
  if (!member)
403
465
  fail('Destructure only style and the configured single theme; other helpers remain unsupported.', id);
@@ -408,7 +470,8 @@ export function collect(program, options) {
408
470
  }
409
471
  }
410
472
  catch (error) {
411
- if (!(error instanceof Config.InvalidError))
473
+ if (!(error instanceof Config.InvalidError) &&
474
+ !(error instanceof Vars.InvalidError))
412
475
  throw error;
413
476
  fail(error.message, expression);
414
477
  }
@@ -420,20 +483,54 @@ export function collect(program, options) {
420
483
  try {
421
484
  if (member.property.name === 'define') {
422
485
  if (expression.arguments.length < 1 ||
423
- expression.arguments.length > 2)
424
- fail('Theme.define requires one literal token object.', expression);
425
- const input = data(expression.arguments[0]);
486
+ expression.arguments.length > 3)
487
+ fail('Vars.define requires one literal variable object.', expression);
488
+ let input = data(expression.arguments[0]);
426
489
  tokenType = type(expression.arguments[0]);
427
- const original = Theme.define(input);
428
- definition = Token.bind(original, Object.freeze({ [Token.identity]: name }));
490
+ const variableSet = variableNamespaces.has(expression.callee.object.name);
491
+ const argument = expression.arguments[1];
492
+ const callback = argument && Expression.unwrap(argument);
493
+ if (variableSet &&
494
+ (callback?.type === 'ArrowFunctionExpression' ||
495
+ callback?.type === 'FunctionExpression')) {
496
+ const parameter = callback.params[0];
497
+ const body = (() => {
498
+ if (callback.body?.type !== 'BlockStatement')
499
+ return callback.body;
500
+ if (callback.body.body.length === 1 &&
501
+ callback.body.body[0]?.type === 'ReturnStatement')
502
+ return callback.body.body[0].argument;
503
+ return undefined;
504
+ })();
505
+ if (callback.async ||
506
+ callback.generator ||
507
+ callback.params.length !== 1 ||
508
+ parameter?.type !== 'Identifier' ||
509
+ !body)
510
+ fail('Derived variables require one named parameter and a literal return value.', callback);
511
+ const base = VariableSets.build(input, Object.freeze({ variableSet: true, [Token.identity]: name }));
512
+ input = VariableSets.merge(input, data(body, { name: parameter.name, vars: base }));
513
+ tokenType = Configurations.type(input);
514
+ }
515
+ else if (expression.arguments.length > 2)
516
+ fail('Vars.define accepts a third argument only with a derived callback.', expression);
517
+ const original = variableSet
518
+ ? VariableSets.theme(VariableSets.build(input, Object.freeze({ variableSet: true, [Token.identity]: name })))
519
+ : Theme.define(input);
520
+ definition = Token.bind(original, Object.freeze({
521
+ ...original[Token.definition].contract,
522
+ [Token.identity]: name,
523
+ }));
429
524
  }
430
525
  else {
431
526
  const base = expression.arguments[0];
432
527
  const parent = base ? resolve(base)?.call : undefined;
433
528
  if (expression.arguments.length !== 2 || !parent)
434
- fail('Theme.extend requires a preceding local theme and literal overrides.', expression);
529
+ fail('Vars.extend requires a preceding variable set and literal overrides.', expression);
435
530
  factoryReferences.add(base.start);
436
- definition = Theme.extend(themes[parent.name], data(expression.arguments[1]));
531
+ definition = variableNamespaces.has(expression.callee.object.name)
532
+ ? VariableSets.theme(Vars.extend(VariableSets.from(themes[parent.name][Token.definition]), data(expression.arguments[1])))
533
+ : Theme.extend(themes[parent.name], data(expression.arguments[1]));
437
534
  if (definition[Token.definition].contract[Token.identity]?.startsWith('id-'))
438
535
  name = definition.className.slice('z_theme-'.length);
439
536
  tokenType = parent.tokenType;
@@ -443,11 +540,19 @@ export function collect(program, options) {
443
540
  catch (error) {
444
541
  if (error instanceof InvalidError)
445
542
  throw error;
446
- if (!(error instanceof Theme.InvalidError))
543
+ if (!(error instanceof Theme.InvalidError) &&
544
+ !(error instanceof Vars.InvalidError))
447
545
  throw error;
448
546
  fail(error.message, expression);
449
547
  }
450
548
  const call = Object.freeze({
549
+ ...(variableNamespaces.has(expression.callee.object.name)
550
+ ? {
551
+ variableSet: true,
552
+ directVariables: true,
553
+ type: `import('zyzz').Vars.Definition<${tokenType}>`,
554
+ }
555
+ : {}),
451
556
  ...(output ? { output } : {}),
452
557
  end: expression.end,
453
558
  name,
@@ -527,7 +632,8 @@ export function collect(program, options) {
527
632
  !link.call.root &&
528
633
  (key === 'script' ||
529
634
  key === 'appearance' ||
530
- (key === 'themes' && link.call.options?.themes))) {
635
+ (key === 'themes' && link.call.options?.themes) ||
636
+ (key === 'vars' && link.call.variableConfig))) {
531
637
  if ((key === 'script' && !link.call.script) ||
532
638
  (key === 'appearance' && !link.call.appearance) ||
533
639
  link.call.selection ||
@@ -537,11 +643,12 @@ export function collect(program, options) {
537
643
  scripts.add(link.call.name);
538
644
  if (key === 'appearance')
539
645
  appearances.add(link.call.name);
540
- if (key === 'themes')
646
+ if (key === 'themes' || key === 'vars')
541
647
  selections.add(link.call.name);
542
648
  const members = Object.fromEntries(Object.entries(link.members ?? {}).flatMap(([pathKey, member]) => {
543
649
  const path = JSON.parse(pathKey);
544
- return key === 'themes' && path[0] === 'themes'
650
+ return (key === 'themes' || key === 'vars') &&
651
+ (path[0] === 'themes' || path[0] === 'vars')
545
652
  ? [[JSON.stringify(path.slice(1)), member]]
546
653
  : [];
547
654
  }));
@@ -564,6 +671,8 @@ export function collect(program, options) {
564
671
  exports[id.name] = selection;
565
672
  continue;
566
673
  }
674
+ if (link.call.variableConfig && ['theme', 'themes'].includes(key))
675
+ fail('Use vars for references and scope selection.', id);
567
676
  const member = link.members?.[JSON.stringify([key])];
568
677
  if (!member)
569
678
  fail('Destructure only style and the configured single theme; other helpers remain unsupported.', id);
@@ -775,8 +884,13 @@ export function collect(program, options) {
775
884
  !parent.optional) {
776
885
  if (config.call.selection && config.call.catalogOnly)
777
886
  fail('This legacy catalog is not callable; rebuild its library.', node);
778
- if (config.call.selection)
887
+ if (config.call.selection) {
779
888
  selections.add(config.call.name);
889
+ scopeApplications.set(parent.start, {
890
+ end: parent.end,
891
+ output: config.call.options?.output === 'html' ? 'html' : undefined,
892
+ });
893
+ }
780
894
  if (config.call.initialization)
781
895
  scripts.add(config.call.name);
782
896
  return true;
@@ -820,21 +934,30 @@ export function collect(program, options) {
820
934
  if (path.length === 1 &&
821
935
  !config.call.selection &&
822
936
  !config.call.initialization &&
823
- ['script', 'themes'].includes(path[0]) &&
937
+ ['script', 'themes', 'vars'].includes(path[0]) &&
824
938
  ancestors[index - 1]?.type === 'CallExpression' &&
825
939
  ancestors[index - 1].callee === target &&
826
940
  !ancestors[index - 1].optional) {
941
+ if (path[0] === 'vars' && !config.call.variableConfig)
942
+ fail('This configuration has no vars.', target);
827
943
  if (path[0] === 'themes' && !config.call.options?.themes)
828
944
  fail('Theme selection requires a named catalog.', target);
829
- if (path[0] === 'themes' && config.call.catalogOnly)
945
+ if ((path[0] === 'themes' || path[0] === 'vars') &&
946
+ config.call.catalogOnly)
830
947
  fail('This legacy catalog is not callable; rebuild its library.', target);
831
948
  if (path[0] === 'script') {
832
949
  if (!config.call.script)
833
950
  fail('This packed configuration does not provide script(); rebuild its library with initialization support.', target);
834
951
  scripts.add(config.call.name);
835
952
  }
836
- if (path[0] === 'themes')
953
+ if (path[0] === 'themes' || path[0] === 'vars') {
837
954
  selections.add(config.call.name);
955
+ const application = ancestors[index - 1];
956
+ scopeApplications.set(application.start, {
957
+ end: application.end,
958
+ output: config.call.options?.output === 'html' ? 'html' : undefined,
959
+ });
960
+ }
838
961
  return true;
839
962
  }
840
963
  if (path.length === 1 &&
@@ -852,10 +975,20 @@ export function collect(program, options) {
852
975
  });
853
976
  return true;
854
977
  }
855
- const linked = config.members?.[JSON.stringify(path)];
978
+ if (config.call.variableConfig &&
979
+ ['theme', 'themes'].includes(path[0]))
980
+ fail('Use vars for references and scope selection.', target);
981
+ const linked = config.call.variableConfig && config.call.selection
982
+ ? undefined
983
+ : config.members?.[JSON.stringify(path)];
856
984
  if (linked)
857
985
  return themeReference(target, ancestors[index - 1], ancestors.slice(0, index + 1), linked.call);
858
986
  }
987
+ if (config.call.selection && config.call.variableConfig && path.length)
988
+ return themeReference(node, parent, ancestors, {
989
+ ...config.call,
990
+ directVariables: true,
991
+ });
859
992
  // A compiled selector is an ordinary runtime function, so passing or storing it is safe.
860
993
  if (config.call.selection && !config.call.catalogOnly && !path.length) {
861
994
  selections.add(config.call.name);
@@ -874,7 +1007,8 @@ export function collect(program, options) {
874
1007
  }
875
1008
  function themeReference(node, parent, ancestors, theme) {
876
1009
  const grandparent = ancestors.at(-3);
877
- if (factoryReferences.has(node.start))
1010
+ if (factoryReferences.has(node.start) ||
1011
+ ancestors.some((ancestor) => factoryReferences.has(ancestor.start)))
878
1012
  return true;
879
1013
  if (exportReferences.has(node.start))
880
1014
  return true;
@@ -888,23 +1022,25 @@ export function collect(program, options) {
888
1022
  return true;
889
1023
  if (parent.type === 'MemberExpression' &&
890
1024
  parent.object === node &&
891
- ((parent.property.type === 'Identifier' &&
892
- !parent.computed &&
893
- ['tokens', 'vars'].includes(parent.property.name)) ||
1025
+ (theme.directVariables ||
1026
+ (parent.property.type === 'Identifier' &&
1027
+ !parent.computed &&
1028
+ ['tokens', 'vars'].includes(parent.property.name)) ||
894
1029
  (parent.property.type === 'Literal' &&
895
1030
  parent.computed &&
896
1031
  ['tokens', 'vars'].includes(String(parent.property.value))))) {
897
1032
  if (parent.optional)
898
1033
  fail('Token references cannot use optional access.', parent);
899
- const variable = parent.property.type === 'Identifier'
900
- ? parent.property.name === 'vars'
901
- : parent.property.type === 'Literal' &&
902
- parent.property.value === 'vars';
903
- let value = variable
1034
+ const variable = theme.directVariables ||
1035
+ (parent.property.type === 'Identifier'
1036
+ ? parent.property.name === 'vars'
1037
+ : parent.property.type === 'Literal' &&
1038
+ parent.property.value === 'vars');
1039
+ let value = variable && !theme.directVariables
904
1040
  ? themes[theme.name].vars
905
1041
  : themes[theme.name].tokens;
906
- let target = parent;
907
- let index = ancestors.length - 3;
1042
+ let target = theme.directVariables ? node : parent;
1043
+ let index = ancestors.length - (theme.directVariables ? 2 : 3);
908
1044
  for (; index >= 0; index--) {
909
1045
  const ancestor = ancestors[index];
910
1046
  if (ancestor.type !== 'MemberExpression' || ancestor.object !== target)
@@ -1040,7 +1176,7 @@ export function collect(program, options) {
1040
1176
  parent.computed ||
1041
1177
  parent.optional ||
1042
1178
  parent.property.type !== 'Identifier')
1043
- fail('Use local theme.style calls, theme.className reads, or Theme.extend; other theme references require source linking.', node);
1179
+ fail('Use Config.create or Vars.extend with variable definitions; other references require source linking.', node);
1044
1180
  if (['style', 'variants'].includes(parent.property.name) &&
1045
1181
  grandparent?.type === 'CallExpression' &&
1046
1182
  grandparent.callee === parent &&
@@ -1114,25 +1250,28 @@ export function collect(program, options) {
1114
1250
  if (!alias?.options?.themes)
1115
1251
  return undefined;
1116
1252
  const context = {
1117
- defaultTheme: String(alias.options.defaultTheme),
1118
- themes: Object.fromEntries(Object.entries(alias.options.themes).map(([name, values]) => [
1253
+ defaultVars: String(alias.options.defaultTheme),
1254
+ vars: Object.fromEntries(Object.entries(alias.options.themes).map(([name, values]) => [
1119
1255
  name,
1120
- Token.bind(Theme.define(values), contract),
1256
+ Token.bind(contract.variableSet
1257
+ ? VariableSets.theme(Vars.define(values))
1258
+ : Theme.define(values), contract),
1121
1259
  ])),
1122
1260
  };
1123
- Object.freeze(context.themes);
1261
+ Object.freeze(context.vars);
1124
1262
  nativeContexts.set(contract, Object.freeze(context));
1125
1263
  return context;
1126
1264
  }
1127
1265
  const entries = Object.entries(config.members ?? {}).flatMap(([key, value]) => {
1128
1266
  const path = JSON.parse(key);
1129
- return path[0] === 'themes' && path.length === 2
1267
+ return (path[0] === 'themes' || path[0] === 'vars') &&
1268
+ path.length === 2
1130
1269
  ? [[path[1], value.definition]]
1131
1270
  : [];
1132
1271
  });
1133
1272
  const context = Object.freeze({
1134
- defaultTheme: String(config.call.options.defaultTheme),
1135
- themes: Object.freeze(Object.fromEntries(entries)),
1273
+ defaultVars: String(config.call.options.defaultTheme),
1274
+ vars: Object.freeze(Object.fromEntries(entries)),
1136
1275
  });
1137
1276
  nativeContexts.set(contract, context);
1138
1277
  return context;
@@ -1143,6 +1282,7 @@ export function collect(program, options) {
1143
1282
  exports: Object.freeze(exports),
1144
1283
  reference,
1145
1284
  references,
1285
+ scopeApplications,
1146
1286
  scripts,
1147
1287
  selections,
1148
1288
  staticTokens,