zyzz 0.0.19 → 0.0.21

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 (167) hide show
  1. package/README.md +9 -9
  2. package/dist/Config.d.ts +1 -0
  3. package/dist/Config.d.ts.map +1 -1
  4. package/dist/Config.js.map +1 -1
  5. package/dist/Style.d.ts +7 -0
  6. package/dist/Style.d.ts.map +1 -1
  7. package/dist/Style.js +1 -5
  8. package/dist/Style.js.map +1 -1
  9. package/dist/Vars.d.ts +22 -15
  10. package/dist/Vars.d.ts.map +1 -1
  11. package/dist/Vars.js +26 -0
  12. package/dist/Vars.js.map +1 -1
  13. package/dist/cli/index.js +5 -0
  14. package/dist/cli/index.js.map +1 -1
  15. package/dist/compiler/Graph.d.ts +3 -0
  16. package/dist/compiler/Graph.d.ts.map +1 -1
  17. package/dist/compiler/Graph.js +44 -37
  18. package/dist/compiler/Graph.js.map +1 -1
  19. package/dist/compiler/Source.d.ts +4 -0
  20. package/dist/compiler/Source.d.ts.map +1 -1
  21. package/dist/compiler/Source.js +66 -6
  22. package/dist/compiler/Source.js.map +1 -1
  23. package/dist/compiler/Transform.d.ts +4 -1
  24. package/dist/compiler/Transform.d.ts.map +1 -1
  25. package/dist/compiler/Transform.js +32 -46
  26. package/dist/compiler/Transform.js.map +1 -1
  27. package/dist/compiler/internal/Catalogs.d.ts.map +1 -1
  28. package/dist/compiler/internal/Catalogs.js +6 -1
  29. package/dist/compiler/internal/Catalogs.js.map +1 -1
  30. package/dist/compiler/internal/Compositions.d.ts.map +1 -1
  31. package/dist/compiler/internal/Compositions.js +5 -0
  32. package/dist/compiler/internal/Compositions.js.map +1 -1
  33. package/dist/compiler/internal/Configurations.d.ts.map +1 -1
  34. package/dist/compiler/internal/Configurations.js +5 -1
  35. package/dist/compiler/internal/Configurations.js.map +1 -1
  36. package/dist/compiler/internal/Contract.d.ts +4 -1
  37. package/dist/compiler/internal/Contract.d.ts.map +1 -1
  38. package/dist/compiler/internal/Contract.js +73 -138
  39. package/dist/compiler/internal/Contract.js.map +1 -1
  40. package/dist/compiler/internal/Contributions.d.ts.map +1 -1
  41. package/dist/compiler/internal/Contributions.js +1 -3
  42. package/dist/compiler/internal/Contributions.js.map +1 -1
  43. package/dist/compiler/internal/Dynamic.d.ts +1 -1
  44. package/dist/compiler/internal/Dynamic.d.ts.map +1 -1
  45. package/dist/compiler/internal/Dynamic.js +5 -5
  46. package/dist/compiler/internal/Dynamic.js.map +1 -1
  47. package/dist/compiler/internal/Names.d.ts +5 -0
  48. package/dist/compiler/internal/Names.d.ts.map +1 -0
  49. package/dist/compiler/internal/Names.js +37 -0
  50. package/dist/compiler/internal/Names.js.map +1 -0
  51. package/dist/compiler/internal/Selectors.d.ts +1 -1
  52. package/dist/compiler/internal/Selectors.d.ts.map +1 -1
  53. package/dist/compiler/internal/Selectors.js +5 -2
  54. package/dist/compiler/internal/Selectors.js.map +1 -1
  55. package/dist/compiler/internal/Stylesheets.js +2 -2
  56. package/dist/compiler/internal/Stylesheets.js.map +1 -1
  57. package/dist/compiler/internal/Themes.d.ts.map +1 -1
  58. package/dist/compiler/internal/Themes.js +85 -24
  59. package/dist/compiler/internal/Themes.js.map +1 -1
  60. package/dist/compiler/internal/Vars.d.ts +2 -0
  61. package/dist/compiler/internal/Vars.d.ts.map +1 -1
  62. package/dist/compiler/internal/Vars.js +7 -1
  63. package/dist/compiler/internal/Vars.js.map +1 -1
  64. package/dist/default.d.ts +11 -15
  65. package/dist/default.d.ts.map +1 -1
  66. package/dist/default.js +13 -14
  67. package/dist/default.js.map +2 -2
  68. package/dist/default.js.zyzz.json +1 -1
  69. package/dist/index.d.ts +15 -0
  70. package/dist/index.d.ts.map +1 -1
  71. package/dist/index.js +15 -0
  72. package/dist/index.js.map +1 -1
  73. package/dist/internal/Authoring.d.ts.map +1 -1
  74. package/dist/internal/Authoring.js +8 -3
  75. package/dist/internal/Authoring.js.map +1 -1
  76. package/dist/internal/Binding.d.ts +4 -0
  77. package/dist/internal/Binding.d.ts.map +1 -1
  78. package/dist/internal/Binding.js +2 -0
  79. package/dist/internal/Binding.js.map +1 -1
  80. package/dist/internal/Configuration.d.ts +2 -2
  81. package/dist/internal/Configuration.d.ts.map +1 -1
  82. package/dist/internal/Configuration.js +4 -2
  83. package/dist/internal/Configuration.js.map +1 -1
  84. package/dist/internal/Identity.d.ts +3 -3
  85. package/dist/internal/Identity.d.ts.map +1 -1
  86. package/dist/internal/Identity.js +11 -9
  87. package/dist/internal/Identity.js.map +1 -1
  88. package/dist/internal/Theme.js +2 -2
  89. package/dist/internal/Theme.js.map +1 -1
  90. package/dist/internal/Token.d.ts +16 -3
  91. package/dist/internal/Token.d.ts.map +1 -1
  92. package/dist/internal/Token.js +11 -2
  93. package/dist/internal/Token.js.map +1 -1
  94. package/dist/internal/VariableSets.d.ts.map +1 -1
  95. package/dist/internal/VariableSets.js +19 -2
  96. package/dist/internal/VariableSets.js.map +1 -1
  97. package/dist/node/Host.d.ts +2 -0
  98. package/dist/node/Host.d.ts.map +1 -1
  99. package/dist/node/Host.js +9 -0
  100. package/dist/node/Host.js.map +1 -1
  101. package/dist/react-native/StyleSheet.js +2 -0
  102. package/dist/react-native/StyleSheet.js.map +1 -1
  103. package/dist/runtime/Composition.d.ts +1 -1
  104. package/dist/runtime/ConditionalRecipe.d.ts +1 -1
  105. package/dist/runtime/PayloadRecipe.d.ts +1 -1
  106. package/dist/runtime/Recipe.d.ts +1 -1
  107. package/dist/styleFunction.d.ts +1 -1
  108. package/dist/styleFunction.d.ts.map +1 -1
  109. package/dist/styleFunction.js.map +1 -1
  110. package/dist/variable.js +1 -1
  111. package/dist/variable.js.map +1 -1
  112. package/dist/variants.d.ts +14 -6
  113. package/dist/variants.d.ts.map +1 -1
  114. package/dist/variants.js.map +1 -1
  115. package/dist/vite/index.d.ts +2 -0
  116. package/dist/vite/index.d.ts.map +1 -1
  117. package/dist/vite/index.js +111 -42
  118. package/dist/vite/index.js.map +1 -1
  119. package/dist/web/Css.d.ts +7 -2
  120. package/dist/web/Css.d.ts.map +1 -1
  121. package/dist/web/Css.js +46 -39
  122. package/dist/web/Css.js.map +1 -1
  123. package/dist/web/internal/ClassName.d.ts +13 -2
  124. package/dist/web/internal/ClassName.d.ts.map +1 -1
  125. package/dist/web/internal/ClassName.js +17 -30
  126. package/dist/web/internal/ClassName.js.map +1 -1
  127. package/dist/web/internal/Themes.d.ts +3 -0
  128. package/dist/web/internal/Themes.d.ts.map +1 -1
  129. package/dist/web/internal/Themes.js +52 -24
  130. package/dist/web/internal/Themes.js.map +1 -1
  131. package/package.json +1 -1
  132. package/src/Config.ts +5 -0
  133. package/src/Style.ts +4 -1
  134. package/src/Vars.ts +88 -29
  135. package/src/cli/index.ts +5 -0
  136. package/src/compiler/Graph.ts +60 -46
  137. package/src/compiler/Source.ts +86 -5
  138. package/src/compiler/Transform.ts +42 -60
  139. package/src/compiler/internal/Catalogs.ts +9 -1
  140. package/src/compiler/internal/Compositions.ts +7 -0
  141. package/src/compiler/internal/Configurations.ts +5 -1
  142. package/src/compiler/internal/Contract.ts +104 -239
  143. package/src/compiler/internal/Contributions.ts +1 -5
  144. package/src/compiler/internal/Dynamic.ts +14 -9
  145. package/src/compiler/internal/Names.ts +48 -0
  146. package/src/compiler/internal/Selectors.ts +6 -1
  147. package/src/compiler/internal/Stylesheets.ts +2 -2
  148. package/src/compiler/internal/Themes.ts +115 -35
  149. package/src/compiler/internal/Vars.ts +9 -1
  150. package/src/default.ts +17 -20
  151. package/src/index.ts +15 -0
  152. package/src/internal/Authoring.ts +9 -3
  153. package/src/internal/Binding.ts +5 -0
  154. package/src/internal/Configuration.ts +7 -4
  155. package/src/internal/Identity.ts +14 -12
  156. package/src/internal/Theme.ts +2 -2
  157. package/src/internal/Token.ts +52 -12
  158. package/src/internal/VariableSets.ts +26 -2
  159. package/src/node/Host.ts +22 -0
  160. package/src/react-native/StyleSheet.ts +6 -0
  161. package/src/styleFunction.ts +1 -3
  162. package/src/variable.ts +1 -1
  163. package/src/variants.ts +38 -16
  164. package/src/vite/index.ts +137 -51
  165. package/src/web/Css.ts +83 -49
  166. package/src/web/internal/ClassName.ts +31 -36
  167. package/src/web/internal/Themes.ts +79 -29
@@ -26,7 +26,7 @@ export function read(
26
26
  if (
27
27
  ![
28
28
  1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
29
- 22, 23, 24, 25, 26, 27, 28,
29
+ 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
30
30
  ].includes(data.version as number)
31
31
  )
32
32
  throw new Error('Unsupported Zyzz contract version.')
@@ -58,6 +58,28 @@ export function read(
58
58
  for (const entry of Object.values(record(data.exports))) collect(entry)
59
59
  }
60
60
 
61
+ function variableNaming(
62
+ entry: Record<string, unknown>,
63
+ identity: string,
64
+ ): 'legacy' | 'hashed' | undefined {
65
+ if (entry.variableNaming !== undefined) {
66
+ if ((data.version as number) >= 30 && entry.variableNaming === 'legacy')
67
+ return 'legacy'
68
+ if ((data.version as number) >= 31 && entry.variableNaming === 'hashed')
69
+ return 'hashed'
70
+ throw new Error('Invalid packed variable naming scheme.')
71
+ }
72
+ if ((data.version as number) <= 30) {
73
+ if (
74
+ identity.startsWith('src-') ||
75
+ (data.version === 30 && identity.startsWith('id-'))
76
+ )
77
+ return 'hashed'
78
+ return 'legacy'
79
+ }
80
+ return undefined
81
+ }
82
+
61
83
  function decode(value: unknown): unknown {
62
84
  if (!value || typeof value !== 'object') return value
63
85
  if (Array.isArray(value)) return value.map(decode)
@@ -69,16 +91,42 @@ export function read(
69
91
  decode(value),
70
92
  ]),
71
93
  )
94
+ if (Object.hasOwn(fields, '$composition')) {
95
+ if ((data.version as number) < 29)
96
+ throw new Error(
97
+ 'Composed variables require contract version 29 or later.',
98
+ )
99
+ const composition = record(fields.$composition)
100
+ if (
101
+ (composition.group !== 'color' && composition.group !== 'spacing') ||
102
+ !Array.isArray(composition.parts)
103
+ )
104
+ throw new Error('Invalid packed variable composition.')
105
+ return Vars.compose(
106
+ composition.group,
107
+ composition.parts.map(decode) as readonly (
108
+ | string
109
+ | number
110
+ | Vars.Reference
111
+ )[],
112
+ )
113
+ }
72
114
  if (Object.hasOwn(fields, '$variable')) {
73
115
  const reference = record(fields.$variable)
74
116
  const identity = string(reference.identity)
117
+ const naming = variableNaming(reference, identity)
75
118
  let contract = identities.get(identity)
76
119
  if (contract && !contract.variableSet)
77
120
  throw new Error(
78
121
  'Conflicting packed variable-set modes for one identity.',
79
122
  )
123
+ if (contract && contract.variableNaming !== naming)
124
+ throw new Error(
125
+ 'Conflicting packed variable naming schemes for one identity.',
126
+ )
80
127
  if (!contract) {
81
128
  contract = Object.freeze({
129
+ ...(naming ? { variableNaming: naming } : {}),
82
130
  variableSet: true,
83
131
  [Token.identity]: identity,
84
132
  })
@@ -102,6 +150,7 @@ export function read(
102
150
  for (const [name, value] of Object.entries(record(data.themes))) {
103
151
  const entry = record(value)
104
152
  const identity = string(entry.identity)
153
+ const naming = variableNaming(entry, identity)
105
154
  if (entry.variableSet === true && (data.version as number) < 28)
106
155
  throw new Error('Vars contracts require contract version 28 or later.')
107
156
  const mappings = VariableSets.mappings(entry.mappings)
@@ -160,8 +209,13 @@ export function read(
160
209
  'Conflicting packed default layers for one theme identity.',
161
210
  )
162
211
 
212
+ if (contract && contract.variableNaming !== naming)
213
+ throw new Error(
214
+ 'Conflicting packed variable naming schemes for one identity.',
215
+ )
163
216
  if (!contract) {
164
217
  contract = Object.freeze({
218
+ ...(naming ? { variableNaming: naming } : {}),
165
219
  ...(entry.variableSet === true
166
220
  ? {
167
221
  variableSet: true,
@@ -203,7 +257,11 @@ export function read(
203
257
  'Packed responsive typography and border widths require contract version 25 or later.',
204
258
  )
205
259
 
206
- themes[name] = Token.bind(definition, contract)
260
+ themes[name] = Token.bind(
261
+ definition,
262
+ contract,
263
+ entry.cssName === undefined ? undefined : string(entry.cssName),
264
+ )
207
265
  types[name] = type(input(definition))
208
266
  }
209
267
 
@@ -229,7 +287,7 @@ export function read(
229
287
  key === 'set' ||
230
288
  key === '__proto__' ||
231
289
  names.has(string(slot.name)) ||
232
- !/^--z-v[a-z0-9-]+$/.test(string(slot.name)) ||
290
+ !/^--z-[a-zA-Z0-9_-]+$/.test(string(slot.name)) ||
233
291
  ![
234
292
  '*',
235
293
  'color',
@@ -294,7 +352,7 @@ export function read(
294
352
  if (
295
353
  ![
296
354
  9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
297
- 27, 28,
355
+ 27, 28, 29, 30, 31,
298
356
  ].includes(data.version as number) ||
299
357
  ![
300
358
  'cssFunction',
@@ -304,7 +362,7 @@ export function read(
304
362
  'fontPaletteValues',
305
363
  'positionTry',
306
364
  ].includes(reference) ||
307
- !/^(?:--)?z-[a-z0-9-]+$/.test(name) ||
365
+ !/^(?:--)?z-[a-zA-Z0-9_-]+$/.test(name) ||
308
366
  !name.startsWith(
309
367
  `${reference === 'counterStyle' ? '' : '--'}z-${reference.toLowerCase()}`,
310
368
  ) ||
@@ -330,7 +388,7 @@ export function read(
330
388
 
331
389
  if (entry.kind === 'animation') {
332
390
  const name = string(entry.name)
333
- if (!/^z-k[a-z0-9-]+$/.test(name))
391
+ if (!/^z-k[a-zA-Z0-9_-]+$/.test(name))
334
392
  throw new Error('Invalid animation identity.')
335
393
 
336
394
  return {
@@ -347,7 +405,7 @@ export function read(
347
405
  'Packed callable styles require contract version 16 or later.',
348
406
  )
349
407
  const binding = string(entry.binding)
350
- if (!/^z-style-[a-z0-9_-]+$/.test(binding))
408
+ if (!/^z-style-[a-zA-Z0-9_-]+$/.test(binding))
351
409
  throw new Error('Invalid style reference identity.')
352
410
  const members =
353
411
  entry.members === undefined
@@ -557,7 +615,22 @@ export function read(
557
615
  ]),
558
616
  )
559
617
 
560
- return { links, themes, stylesheets: Stylesheets.read(data.stylesheets) }
618
+ const classRules = Object.fromEntries(
619
+ Object.entries(
620
+ data.classRules === undefined ? {} : record(data.classRules),
621
+ ).map(([name, body]) => {
622
+ if (!name || /\s/.test(name))
623
+ throw new Error('Invalid packed class name.')
624
+ return [name, string(body)]
625
+ }),
626
+ )
627
+
628
+ return {
629
+ classRules,
630
+ links,
631
+ themes,
632
+ stylesheets: Stylesheets.read(data.stylesheets),
633
+ }
561
634
  }
562
635
 
563
636
  function record(value: unknown): Record<string, unknown> {
@@ -590,7 +663,8 @@ function tokens(tree: Theme.References<Theme.Tokens>): Record<string, unknown> {
590
663
  }
591
664
 
592
665
  function type(value: unknown): string {
593
- if (Token.is(value)) return Configurations.type(value)
666
+ if (Token.is(value) || Token.isExpression(value))
667
+ return Configurations.type(value)
594
668
  if (Array.isArray(value)) return `readonly [${value.map(type).join(',')}]`
595
669
  if (!value || typeof value !== 'object') return JSON.stringify(value)
596
670
 
@@ -606,6 +680,7 @@ export function write(
606
680
  stylesheets: readonly Stylesheets.Section[] = [],
607
681
  moduleId = '',
608
682
  configurations: readonly write.Configuration[] = [],
683
+ classRules: Readonly<Record<string, string>> = {},
609
684
  ): string {
610
685
  function entry(link: Themes.Link): Record<string, unknown> {
611
686
  if (link.kind === 'variables')
@@ -693,6 +768,7 @@ export function write(
693
768
  }
694
769
 
695
770
  return JSON.stringify({
771
+ ...(Object.keys(classRules).length ? { classRules } : {}),
696
772
  ...(stylesheets.length
697
773
  ? { stylesheets: Stylesheets.write(stylesheets) }
698
774
  : {}),
@@ -706,6 +782,9 @@ export function write(
706
782
  Object.entries(themes).map(([name, theme]) => [
707
783
  name,
708
784
  {
785
+ ...(theme[Token.definition].cssName !== undefined
786
+ ? { cssName: theme[Token.definition].cssName }
787
+ : {}),
709
788
  ...(theme[Token.definition].contract.shorthands
710
789
  ? { shorthands: theme[Token.definition].contract.shorthands }
711
790
  : {}),
@@ -721,231 +800,17 @@ export function write(
721
800
  mappings: theme[Token.definition].contract.mappings,
722
801
  }
723
802
  : {}),
803
+ ...(theme[Token.definition].contract.variableNaming
804
+ ? {
805
+ variableNaming: theme[Token.definition].contract.variableNaming,
806
+ }
807
+ : {}),
724
808
  identity: theme[Token.definition].contract[Token.identity],
725
809
  tokens: encode(input(theme)),
726
810
  },
727
811
  ]),
728
812
  ),
729
- version: (() => {
730
- if (
731
- Object.values(themes).some(
732
- (theme) =>
733
- theme[Token.definition].contract.variableSet ||
734
- theme[Token.definition].queries,
735
- )
736
- )
737
- return 28
738
-
739
- if (
740
- Object.values(themes).some(
741
- (theme) =>
742
- theme[Token.definition].contract.defaultLayer !== undefined,
743
- )
744
- )
745
- return 27
746
- if (
747
- Object.values(themes).some(
748
- (theme) =>
749
- theme[Token.definition].paths ||
750
- Object.hasOwn(theme.tokens, 'borderWidth'),
751
- )
752
- )
753
- return 25
754
-
755
- if (
756
- Object.values(themes).some((theme) =>
757
- Object.hasOwn(theme.tokens, 'typography'),
758
- )
759
- )
760
- return 24
761
-
762
- function callable(link: Themes.Link): boolean {
763
- return !!link.style || Object.values(link.members ?? {}).some(callable)
764
- }
765
- function styled(link: Themes.Link): boolean {
766
- return (
767
- link.kind === 'style' ||
768
- Object.values(link.members ?? {}).some(styled)
769
- )
770
- }
771
- function branches(style: import('../../Style.js').NamedStyle): boolean {
772
- return (
773
- !!style.targets || !!style.rules?.some((rule) => branches(rule.style))
774
- )
775
- }
776
- function targeted(link: Themes.Link): boolean {
777
- return (
778
- (link.style && branches(link.style.style)) ||
779
- Object.values(link.members ?? {}).some(targeted)
780
- )
781
- }
782
- function staticRecipe(link: Themes.Link): boolean {
783
- return (
784
- !!link.style?.staticRecipe ||
785
- Object.values(link.members ?? {}).some(staticRecipe)
786
- )
787
- }
788
- function nested(link: Themes.Link): boolean {
789
- return Object.values(link.members ?? {}).some(
790
- (member) =>
791
- (link.kind === 'style-reference' && !!member.members) ||
792
- nested(member),
793
- )
794
- }
795
- function dynamic(link: Themes.Link): boolean {
796
- return (
797
- !!link.style?.dynamic ||
798
- Object.values(link.members ?? {}).some(dynamic)
799
- )
800
- }
801
- if (Object.values(links).some(dynamic)) return 23
802
- if (Object.values(links).some(nested)) return 22
803
- if (Object.values(links).some(staticRecipe)) return 21
804
- if (Object.values(links).some(targeted)) return 20
805
- // Style authoring exports serialize as `style`; older readers only know `css`.
806
- if (Object.values(links).some(styled)) return 19
807
- // Root controls call a runtime helper older releases lack, and older
808
- // readers reject the storageKey option, so both require readers to opt in.
809
- // Local configurations emit the same helper without an exported binding.
810
- if (
811
- configurations.length ||
812
- Object.values(links).some(
813
- (link) =>
814
- (link.call.appearance &&
815
- (link.kind === 'config' || link.call.root)) ||
816
- link.call.options?.storageKey !== undefined,
817
- )
818
- )
819
- return 18
820
- if (
821
- Object.values(links).some(callable) ||
822
- Object.values(themes).some(
823
- (theme) => theme[Token.definition].contract.cssOutput,
824
- )
825
- )
826
- return 17
827
- if (Object.values(links).some((link) => link.call.recipe)) return 15
828
- if (Object.values(links).some((link) => link.kind === 'variables'))
829
- return 14
830
- if (Object.values(links).some((link) => link.kind === 'style-reference'))
831
- return 13
832
-
833
- if (
834
- Object.values(links).some(
835
- (link) => link.call.function && extended(link.call.function),
836
- )
837
- )
838
- return 12
839
-
840
- if (
841
- stylesheets.some((section) => section.namespaces?.length) ||
842
- Object.values(links).some(
843
- (link) =>
844
- link.call.function &&
845
- [
846
- link.call.function.returns,
847
- ...link.call.function.parameters.map(
848
- (parameter) => parameter.syntax ?? '*',
849
- ),
850
- ].some(
851
- (syntax) =>
852
- // Version 10 readers accepted this fixed scalar subset.
853
- !(
854
- [
855
- '*',
856
- '<angle>',
857
- '<color>',
858
- '<integer>',
859
- '<length>',
860
- '<length-percentage>',
861
- '<number>',
862
- '<percentage>',
863
- '<time>',
864
- ] as readonly string[]
865
- ).includes(syntax),
866
- ),
867
- )
868
- )
869
- return 11
870
-
871
- if (
872
- Object.values(links).some(
873
- (link) =>
874
- link.call.reference === 'cssFunction' ||
875
- link.call.reference === 'customMedia',
876
- )
877
- )
878
- return 10
879
-
880
- if (Object.values(links).some((link) => link.kind === 'rule-reference'))
881
- return 9
882
-
883
- if (Object.values(links).some((link) => link.kind === 'variables'))
884
- return 8
885
-
886
- if (
887
- stylesheets.length ||
888
- Object.values(links).some((link) => link.kind === 'animation')
889
- )
890
- return 7
891
-
892
- if (
893
- Object.values(themes).some(
894
- (theme) =>
895
- theme[Token.definition].contract.shorthands ||
896
- Object.hasOwn(theme.tokens, 'margin') ||
897
- Object.hasOwn(theme.tokens, 'padding'),
898
- ) ||
899
- Object.values(links).some(
900
- (link) =>
901
- link.call.output === 'html' ||
902
- Object.values(link.members ?? {}).some(
903
- (member) => member.call.output === 'html',
904
- ),
905
- )
906
- )
907
- return 5
908
-
909
- if (
910
- stylesheets.length ||
911
- Object.values(links).some(
912
- (link) =>
913
- link.call.selection ||
914
- (link.kind === 'config' && !!link.call.options?.themes) ||
915
- link.call.initialization ||
916
- (link.kind === 'config' && link.call.script) ||
917
- link.kind === 'animation' ||
918
- link.kind === 'variables',
919
- )
920
- )
921
- return 4
922
-
923
- if (
924
- Object.values(themes).some(
925
- (theme) =>
926
- theme[Token.definition].queries ||
927
- Object.keys(theme.tokens).some((group) =>
928
- [
929
- 'fontFamily',
930
- 'fontSize',
931
- 'fontWeight',
932
- 'lineHeight',
933
- 'letterSpacing',
934
- ].includes(group),
935
- ),
936
- )
937
- )
938
- return 3
939
-
940
- if (
941
- Object.values(links).some(
942
- (link) => link.kind === 'config' || link.call.type,
943
- )
944
- )
945
- return 2
946
-
947
- return 1
948
- })(),
813
+ version: 31,
949
814
  })
950
815
  }
951
816
 
@@ -1021,19 +886,17 @@ function signature(
1021
886
  }
1022
887
  }
1023
888
 
1024
- function extended(signature: NonNullable<Themes.Call['function']>): boolean {
1025
- return (
1026
- /[\\\u0080-\uffff]/.test(signature.returns) ||
1027
- signature.parameters.some((parameter) =>
1028
- /[\\\u0080-\uffff]/.test(parameter.name + (parameter.syntax ?? '*')),
1029
- )
1030
- )
1031
- }
1032
-
1033
889
  function encode(value: unknown): unknown {
890
+ if (Token.isExpression(value) && 'group' in value)
891
+ return {
892
+ $composition: { group: value.group, parts: value.parts.map(encode) },
893
+ }
1034
894
  if (Token.is(value))
1035
895
  return {
1036
896
  $variable: {
897
+ ...(value.contract.variableNaming
898
+ ? { variableNaming: value.contract.variableNaming }
899
+ : {}),
1037
900
  identity: value.contract[Token.identity],
1038
901
  path: value.path,
1039
902
  value: encode(value.value),
@@ -1044,7 +907,9 @@ function encode(value: unknown): unknown {
1044
907
  const fields = Object.fromEntries(
1045
908
  Object.entries(value).map(([key, value]) => [key, encode(value)]),
1046
909
  )
1047
- return Object.hasOwn(fields, '$variable') || Object.hasOwn(fields, '$object')
910
+ return Object.hasOwn(fields, '$composition') ||
911
+ Object.hasOwn(fields, '$variable') ||
912
+ Object.hasOwn(fields, '$object')
1048
913
  ? { $object: fields }
1049
914
  : fields
1050
915
  }
@@ -286,11 +286,7 @@ export function scan(
286
286
  explicit !== undefined
287
287
  ? Identity.contribution(type, explicit)
288
288
  : variable?.id.type === 'Identifier'
289
- ? `${type === 'keyframes' ? 'z-k' : `${type === 'counterStyle' ? '' : '--'}z-${type.toLowerCase()}`}${namespace}-${Array.from(
290
- variable.id.name,
291
- )
292
- .map((value) => value.codePointAt(0)!.toString(16))
293
- .join('-')}`
289
+ ? `${type === 'keyframes' ? 'z-k-' : `${type === 'counterStyle' ? '' : '--'}z-${type.toLowerCase()}-`}${Identity.name(variable.id.name)}`
294
290
  : undefined
295
291
 
296
292
  const call: Call = {
@@ -1,6 +1,7 @@
1
1
  /** Extracts typed callback slots and static object bodies without invoking callbacks. @module */
2
2
  import type * as Ast from '@oxc-project/types'
3
- import type * as Binding from '../../internal/Binding.js'
3
+ import * as Binding from '../../internal/Binding.js'
4
+ import * as Identity from '../../internal/Identity.js'
4
5
  import * as Expression from './Expression.js'
5
6
  import * as Literal from '../../internal/Literal.js'
6
7
  import * as Themes from './Themes.js'
@@ -82,14 +83,18 @@ export function read(
82
83
  member,
83
84
  )
84
85
 
85
- const slot = (slots[key] = Object.freeze({
86
- name: `--z-d${identity}-${Array.from(key)
87
- .map((character) => character.codePointAt(0)!.toString(16))
88
- .join('-')}`,
89
- type: kind === 'number' ? 'number' : 'length',
90
- ...(kind === 'zero-string' ? { zero: true } : {}),
91
- variable: true,
92
- }))
86
+ const slot = (slots[key] = Object.freeze(
87
+ Object.defineProperty(
88
+ {
89
+ name: Identity.slot(identity, key),
90
+ type: kind === 'number' ? ('number' as const) : ('length' as const),
91
+ ...(kind === 'zero-string' ? { zero: true } : {}),
92
+ variable: true as const,
93
+ },
94
+ Binding.dynamic,
95
+ { value: true },
96
+ ),
97
+ ))
93
98
 
94
99
  const values = numbers(type)
95
100
 
@@ -0,0 +1,48 @@
1
+ /** Derives emitted names from authored bindings rather than source locations. @module */
2
+ import type * as Ast from '@oxc-project/types'
3
+ import * as Walker from 'oxc-walker'
4
+ import * as Identity from '../../internal/Identity.js'
5
+
6
+ /** Collects readable declaration paths for calls in constants and namespaces. */
7
+ export function collect(program: Ast.Program): ReadonlyMap<number, string> {
8
+ const names = new Map<number, string>()
9
+ const ancestors: Ast.Node[] = []
10
+
11
+ Walker.walk(program, {
12
+ enter(node) {
13
+ if (node.type === 'CallExpression') {
14
+ const parts: string[] = []
15
+ for (const ancestor of ancestors) {
16
+ if (
17
+ ancestor.type === 'TSModuleDeclaration' &&
18
+ ancestor.id.type === 'Identifier'
19
+ )
20
+ parts.push(ancestor.id.name)
21
+ if (
22
+ ancestor.type === 'VariableDeclarator' &&
23
+ ancestor.id.type === 'Identifier'
24
+ )
25
+ parts.push(ancestor.id.name)
26
+ if (ancestor.type === 'Property' && !ancestor.computed) {
27
+ if (ancestor.key.type === 'Identifier')
28
+ parts.push(ancestor.key.name)
29
+ else if (ancestor.key.type === 'Literal')
30
+ parts.push(String(ancestor.key.value))
31
+ }
32
+ if (ancestor.type === 'FunctionDeclaration' && ancestor.id)
33
+ parts.push(ancestor.id.name)
34
+ }
35
+ names.set(
36
+ node.start,
37
+ parts.length ? parts.map(Identity.name).join('-') : 'style',
38
+ )
39
+ }
40
+ ancestors.push(node)
41
+ },
42
+ leave() {
43
+ ancestors.pop()
44
+ },
45
+ })
46
+
47
+ return names
48
+ }
@@ -6,6 +6,7 @@ import * as Theme from '../../internal/Theme.js'
6
6
  import * as AtRules from './AtRules.js'
7
7
  import * as Identity from '../../internal/Identity.js'
8
8
  import * as Identifiers from './Identifiers.js'
9
+ import * as Names from './Names.js'
9
10
  import * as Expression from './Expression.js'
10
11
  import type * as Scope from './Scope.js'
11
12
  import * as Themes from './Themes.js'
@@ -18,7 +19,10 @@ export function scan(
18
19
  calls: readonly Ast.CallExpression[],
19
20
  links: Readonly<Record<string, Themes.Link>> = {},
20
21
  selectorKeys: ReadonlySet<number> = new Set(),
22
+ cssNamespaces: ReadonlyMap<number, string> = new Map(),
23
+ moduleId = namespace,
21
24
  ) {
25
+ const authoredNames = Names.collect(program)
22
26
  const conditions = new Map<number, string>()
23
27
  const localConditions = new Set<string>()
24
28
  const identities = new Map<number, string>()
@@ -163,7 +167,8 @@ export function scan(
163
167
 
164
168
  function link(call: Ast.CallExpression): Themes.Link {
165
169
  const id = Identifiers.explicit(call)
166
- const name = `z-style-${id === undefined ? `${namespace}-${call.start}` : Identity.requireId(id, 'style')}`
170
+ const prefix = cssNamespaces.get(call.start)
171
+ const name = `z-style-${id === undefined ? `${prefix ? `${prefix}-` : ''}${Identity.compact(moduleId).slice(-6)}-${authoredNames.get(call.start)!}` : `id-${prefix ? `${prefix}-` : ''}${Identity.requireId(id, 'style').slice(3)}`}`
167
172
  identities.set(call.start, name)
168
173
 
169
174
  return {
@@ -214,7 +214,7 @@ export function render(sections: readonly Section[]) {
214
214
  )
215
215
  throw new ConflictError(
216
216
  section.owner ?? section.source,
217
- `Conflicting stylesheet identity: ${identity.name}; compile libraries with package-qualified module IDs.`,
217
+ `Conflicting stylesheet identity: ${identity.name}; supply distinct declaration ids.`,
218
218
  )
219
219
  identities.set(key, { source: section.source, signature })
220
220
  return
@@ -230,7 +230,7 @@ export function render(sections: readonly Section[]) {
230
230
  )
231
231
  throw new ConflictError(
232
232
  section.owner ?? section.source,
233
- `Conflicting animation identity: ${name}; compile libraries with package-qualified module IDs.`,
233
+ `Conflicting animation identity: ${name}; supply distinct declaration ids.`,
234
234
  )
235
235
 
236
236
  animations.set(name, { source: section.source, signature })