zyzz 0.0.20 → 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 (131) hide show
  1. package/dist/Style.d.ts +7 -0
  2. package/dist/Style.d.ts.map +1 -1
  3. package/dist/Style.js +1 -5
  4. package/dist/Style.js.map +1 -1
  5. package/dist/compiler/Graph.d.ts +3 -0
  6. package/dist/compiler/Graph.d.ts.map +1 -1
  7. package/dist/compiler/Graph.js +44 -37
  8. package/dist/compiler/Graph.js.map +1 -1
  9. package/dist/compiler/Source.d.ts +4 -0
  10. package/dist/compiler/Source.d.ts.map +1 -1
  11. package/dist/compiler/Source.js +63 -6
  12. package/dist/compiler/Source.js.map +1 -1
  13. package/dist/compiler/Transform.d.ts +4 -1
  14. package/dist/compiler/Transform.d.ts.map +1 -1
  15. package/dist/compiler/Transform.js +32 -46
  16. package/dist/compiler/Transform.js.map +1 -1
  17. package/dist/compiler/internal/Catalogs.d.ts.map +1 -1
  18. package/dist/compiler/internal/Catalogs.js +6 -1
  19. package/dist/compiler/internal/Catalogs.js.map +1 -1
  20. package/dist/compiler/internal/Compositions.d.ts.map +1 -1
  21. package/dist/compiler/internal/Compositions.js +5 -0
  22. package/dist/compiler/internal/Compositions.js.map +1 -1
  23. package/dist/compiler/internal/Configurations.d.ts.map +1 -1
  24. package/dist/compiler/internal/Configurations.js +2 -1
  25. package/dist/compiler/internal/Configurations.js.map +1 -1
  26. package/dist/compiler/internal/Contract.d.ts +4 -1
  27. package/dist/compiler/internal/Contract.d.ts.map +1 -1
  28. package/dist/compiler/internal/Contract.js +56 -147
  29. package/dist/compiler/internal/Contract.js.map +1 -1
  30. package/dist/compiler/internal/Contributions.d.ts.map +1 -1
  31. package/dist/compiler/internal/Contributions.js +1 -3
  32. package/dist/compiler/internal/Contributions.js.map +1 -1
  33. package/dist/compiler/internal/Dynamic.d.ts +1 -1
  34. package/dist/compiler/internal/Dynamic.d.ts.map +1 -1
  35. package/dist/compiler/internal/Dynamic.js +5 -5
  36. package/dist/compiler/internal/Dynamic.js.map +1 -1
  37. package/dist/compiler/internal/Names.d.ts +5 -0
  38. package/dist/compiler/internal/Names.d.ts.map +1 -0
  39. package/dist/compiler/internal/Names.js +37 -0
  40. package/dist/compiler/internal/Names.js.map +1 -0
  41. package/dist/compiler/internal/Selectors.d.ts +1 -1
  42. package/dist/compiler/internal/Selectors.d.ts.map +1 -1
  43. package/dist/compiler/internal/Selectors.js +5 -2
  44. package/dist/compiler/internal/Selectors.js.map +1 -1
  45. package/dist/compiler/internal/Stylesheets.js +2 -2
  46. package/dist/compiler/internal/Stylesheets.js.map +1 -1
  47. package/dist/compiler/internal/Themes.d.ts.map +1 -1
  48. package/dist/compiler/internal/Themes.js +2 -1
  49. package/dist/compiler/internal/Themes.js.map +1 -1
  50. package/dist/compiler/internal/Vars.d.ts +2 -0
  51. package/dist/compiler/internal/Vars.d.ts.map +1 -1
  52. package/dist/compiler/internal/Vars.js +7 -1
  53. package/dist/compiler/internal/Vars.js.map +1 -1
  54. package/dist/default.d.ts +4 -4
  55. package/dist/default.d.ts.map +1 -1
  56. package/dist/default.js +9 -9
  57. package/dist/default.js.map +2 -2
  58. package/dist/default.js.zyzz.json +1 -1
  59. package/dist/internal/Authoring.d.ts.map +1 -1
  60. package/dist/internal/Authoring.js +8 -3
  61. package/dist/internal/Authoring.js.map +1 -1
  62. package/dist/internal/Binding.d.ts +4 -0
  63. package/dist/internal/Binding.d.ts.map +1 -1
  64. package/dist/internal/Binding.js +2 -0
  65. package/dist/internal/Binding.js.map +1 -1
  66. package/dist/internal/Configuration.d.ts +2 -2
  67. package/dist/internal/Configuration.d.ts.map +1 -1
  68. package/dist/internal/Configuration.js +4 -2
  69. package/dist/internal/Configuration.js.map +1 -1
  70. package/dist/internal/Identity.d.ts +3 -3
  71. package/dist/internal/Identity.d.ts.map +1 -1
  72. package/dist/internal/Identity.js +11 -9
  73. package/dist/internal/Identity.js.map +1 -1
  74. package/dist/internal/Theme.js +2 -2
  75. package/dist/internal/Theme.js.map +1 -1
  76. package/dist/internal/Token.d.ts +5 -1
  77. package/dist/internal/Token.d.ts.map +1 -1
  78. package/dist/internal/Token.js +9 -2
  79. package/dist/internal/Token.js.map +1 -1
  80. package/dist/internal/VariableSets.js +1 -1
  81. package/dist/internal/VariableSets.js.map +1 -1
  82. package/dist/node/Host.d.ts.map +1 -1
  83. package/dist/node/Host.js +2 -0
  84. package/dist/node/Host.js.map +1 -1
  85. package/dist/variable.js +1 -1
  86. package/dist/variable.js.map +1 -1
  87. package/dist/vite/index.d.ts.map +1 -1
  88. package/dist/vite/index.js +36 -12
  89. package/dist/vite/index.js.map +1 -1
  90. package/dist/web/Css.d.ts +7 -2
  91. package/dist/web/Css.d.ts.map +1 -1
  92. package/dist/web/Css.js +46 -39
  93. package/dist/web/Css.js.map +1 -1
  94. package/dist/web/internal/ClassName.d.ts +13 -2
  95. package/dist/web/internal/ClassName.d.ts.map +1 -1
  96. package/dist/web/internal/ClassName.js +17 -30
  97. package/dist/web/internal/ClassName.js.map +1 -1
  98. package/dist/web/internal/Themes.d.ts +3 -0
  99. package/dist/web/internal/Themes.d.ts.map +1 -1
  100. package/dist/web/internal/Themes.js +48 -24
  101. package/dist/web/internal/Themes.js.map +1 -1
  102. package/package.json +1 -1
  103. package/src/Style.ts +4 -1
  104. package/src/compiler/Graph.ts +60 -46
  105. package/src/compiler/Source.ts +83 -5
  106. package/src/compiler/Transform.ts +42 -60
  107. package/src/compiler/internal/Catalogs.ts +9 -1
  108. package/src/compiler/internal/Compositions.ts +7 -0
  109. package/src/compiler/internal/Configurations.ts +2 -1
  110. package/src/compiler/internal/Contract.ts +75 -253
  111. package/src/compiler/internal/Contributions.ts +1 -5
  112. package/src/compiler/internal/Dynamic.ts +14 -9
  113. package/src/compiler/internal/Names.ts +48 -0
  114. package/src/compiler/internal/Selectors.ts +6 -1
  115. package/src/compiler/internal/Stylesheets.ts +2 -2
  116. package/src/compiler/internal/Themes.ts +6 -1
  117. package/src/compiler/internal/Vars.ts +9 -1
  118. package/src/default.ts +9 -10
  119. package/src/internal/Authoring.ts +8 -2
  120. package/src/internal/Binding.ts +5 -0
  121. package/src/internal/Configuration.ts +7 -4
  122. package/src/internal/Identity.ts +14 -12
  123. package/src/internal/Theme.ts +2 -2
  124. package/src/internal/Token.ts +13 -1
  125. package/src/internal/VariableSets.ts +1 -1
  126. package/src/node/Host.ts +3 -0
  127. package/src/variable.ts +1 -1
  128. package/src/vite/index.ts +43 -18
  129. package/src/web/Css.ts +83 -49
  130. package/src/web/internal/ClassName.ts +31 -36
  131. package/src/web/internal/Themes.ts +75 -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,
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)
@@ -92,13 +114,19 @@ export function read(
92
114
  if (Object.hasOwn(fields, '$variable')) {
93
115
  const reference = record(fields.$variable)
94
116
  const identity = string(reference.identity)
117
+ const naming = variableNaming(reference, identity)
95
118
  let contract = identities.get(identity)
96
119
  if (contract && !contract.variableSet)
97
120
  throw new Error(
98
121
  'Conflicting packed variable-set modes for one identity.',
99
122
  )
123
+ if (contract && contract.variableNaming !== naming)
124
+ throw new Error(
125
+ 'Conflicting packed variable naming schemes for one identity.',
126
+ )
100
127
  if (!contract) {
101
128
  contract = Object.freeze({
129
+ ...(naming ? { variableNaming: naming } : {}),
102
130
  variableSet: true,
103
131
  [Token.identity]: identity,
104
132
  })
@@ -122,6 +150,7 @@ export function read(
122
150
  for (const [name, value] of Object.entries(record(data.themes))) {
123
151
  const entry = record(value)
124
152
  const identity = string(entry.identity)
153
+ const naming = variableNaming(entry, identity)
125
154
  if (entry.variableSet === true && (data.version as number) < 28)
126
155
  throw new Error('Vars contracts require contract version 28 or later.')
127
156
  const mappings = VariableSets.mappings(entry.mappings)
@@ -180,8 +209,13 @@ export function read(
180
209
  'Conflicting packed default layers for one theme identity.',
181
210
  )
182
211
 
212
+ if (contract && contract.variableNaming !== naming)
213
+ throw new Error(
214
+ 'Conflicting packed variable naming schemes for one identity.',
215
+ )
183
216
  if (!contract) {
184
217
  contract = Object.freeze({
218
+ ...(naming ? { variableNaming: naming } : {}),
185
219
  ...(entry.variableSet === true
186
220
  ? {
187
221
  variableSet: true,
@@ -223,7 +257,11 @@ export function read(
223
257
  'Packed responsive typography and border widths require contract version 25 or later.',
224
258
  )
225
259
 
226
- themes[name] = Token.bind(definition, contract)
260
+ themes[name] = Token.bind(
261
+ definition,
262
+ contract,
263
+ entry.cssName === undefined ? undefined : string(entry.cssName),
264
+ )
227
265
  types[name] = type(input(definition))
228
266
  }
229
267
 
@@ -249,7 +287,7 @@ export function read(
249
287
  key === 'set' ||
250
288
  key === '__proto__' ||
251
289
  names.has(string(slot.name)) ||
252
- !/^--z-v[a-z0-9-]+$/.test(string(slot.name)) ||
290
+ !/^--z-[a-zA-Z0-9_-]+$/.test(string(slot.name)) ||
253
291
  ![
254
292
  '*',
255
293
  'color',
@@ -314,7 +352,7 @@ export function read(
314
352
  if (
315
353
  ![
316
354
  9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
317
- 27, 28, 29,
355
+ 27, 28, 29, 30, 31,
318
356
  ].includes(data.version as number) ||
319
357
  ![
320
358
  'cssFunction',
@@ -324,7 +362,7 @@ export function read(
324
362
  'fontPaletteValues',
325
363
  'positionTry',
326
364
  ].includes(reference) ||
327
- !/^(?:--)?z-[a-z0-9-]+$/.test(name) ||
365
+ !/^(?:--)?z-[a-zA-Z0-9_-]+$/.test(name) ||
328
366
  !name.startsWith(
329
367
  `${reference === 'counterStyle' ? '' : '--'}z-${reference.toLowerCase()}`,
330
368
  ) ||
@@ -350,7 +388,7 @@ export function read(
350
388
 
351
389
  if (entry.kind === 'animation') {
352
390
  const name = string(entry.name)
353
- if (!/^z-k[a-z0-9-]+$/.test(name))
391
+ if (!/^z-k[a-zA-Z0-9_-]+$/.test(name))
354
392
  throw new Error('Invalid animation identity.')
355
393
 
356
394
  return {
@@ -367,7 +405,7 @@ export function read(
367
405
  'Packed callable styles require contract version 16 or later.',
368
406
  )
369
407
  const binding = string(entry.binding)
370
- if (!/^z-style-[a-z0-9_-]+$/.test(binding))
408
+ if (!/^z-style-[a-zA-Z0-9_-]+$/.test(binding))
371
409
  throw new Error('Invalid style reference identity.')
372
410
  const members =
373
411
  entry.members === undefined
@@ -577,7 +615,22 @@ export function read(
577
615
  ]),
578
616
  )
579
617
 
580
- 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
+ }
581
634
  }
582
635
 
583
636
  function record(value: unknown): Record<string, unknown> {
@@ -627,6 +680,7 @@ export function write(
627
680
  stylesheets: readonly Stylesheets.Section[] = [],
628
681
  moduleId = '',
629
682
  configurations: readonly write.Configuration[] = [],
683
+ classRules: Readonly<Record<string, string>> = {},
630
684
  ): string {
631
685
  function entry(link: Themes.Link): Record<string, unknown> {
632
686
  if (link.kind === 'variables')
@@ -714,6 +768,7 @@ export function write(
714
768
  }
715
769
 
716
770
  return JSON.stringify({
771
+ ...(Object.keys(classRules).length ? { classRules } : {}),
717
772
  ...(stylesheets.length
718
773
  ? { stylesheets: Stylesheets.write(stylesheets) }
719
774
  : {}),
@@ -727,6 +782,9 @@ export function write(
727
782
  Object.entries(themes).map(([name, theme]) => [
728
783
  name,
729
784
  {
785
+ ...(theme[Token.definition].cssName !== undefined
786
+ ? { cssName: theme[Token.definition].cssName }
787
+ : {}),
730
788
  ...(theme[Token.definition].contract.shorthands
731
789
  ? { shorthands: theme[Token.definition].contract.shorthands }
732
790
  : {}),
@@ -742,247 +800,17 @@ export function write(
742
800
  mappings: theme[Token.definition].contract.mappings,
743
801
  }
744
802
  : {}),
803
+ ...(theme[Token.definition].contract.variableNaming
804
+ ? {
805
+ variableNaming: theme[Token.definition].contract.variableNaming,
806
+ }
807
+ : {}),
745
808
  identity: theme[Token.definition].contract[Token.identity],
746
809
  tokens: encode(input(theme)),
747
810
  },
748
811
  ]),
749
812
  ),
750
- version: (() => {
751
- function composed(value: unknown): boolean {
752
- if (Token.isExpression(value)) return true
753
- if (Token.is(value)) return composed(value.value)
754
- return (
755
- !!value &&
756
- typeof value === 'object' &&
757
- Object.values(value).some(composed)
758
- )
759
- }
760
- if (
761
- Object.values(themes).some((theme) =>
762
- composed(theme[Token.definition].values),
763
- )
764
- )
765
- return 29
766
-
767
- if (
768
- Object.values(themes).some(
769
- (theme) =>
770
- theme[Token.definition].contract.variableSet ||
771
- theme[Token.definition].queries,
772
- )
773
- )
774
- return 28
775
-
776
- if (
777
- Object.values(themes).some(
778
- (theme) =>
779
- theme[Token.definition].contract.defaultLayer !== undefined,
780
- )
781
- )
782
- return 27
783
- if (
784
- Object.values(themes).some(
785
- (theme) =>
786
- theme[Token.definition].paths ||
787
- Object.hasOwn(theme.tokens, 'borderWidth'),
788
- )
789
- )
790
- return 25
791
-
792
- if (
793
- Object.values(themes).some((theme) =>
794
- Object.hasOwn(theme.tokens, 'typography'),
795
- )
796
- )
797
- return 24
798
-
799
- function callable(link: Themes.Link): boolean {
800
- return !!link.style || Object.values(link.members ?? {}).some(callable)
801
- }
802
- function styled(link: Themes.Link): boolean {
803
- return (
804
- link.kind === 'style' ||
805
- Object.values(link.members ?? {}).some(styled)
806
- )
807
- }
808
- function branches(style: import('../../Style.js').NamedStyle): boolean {
809
- return (
810
- !!style.targets || !!style.rules?.some((rule) => branches(rule.style))
811
- )
812
- }
813
- function targeted(link: Themes.Link): boolean {
814
- return (
815
- (link.style && branches(link.style.style)) ||
816
- Object.values(link.members ?? {}).some(targeted)
817
- )
818
- }
819
- function staticRecipe(link: Themes.Link): boolean {
820
- return (
821
- !!link.style?.staticRecipe ||
822
- Object.values(link.members ?? {}).some(staticRecipe)
823
- )
824
- }
825
- function nested(link: Themes.Link): boolean {
826
- return Object.values(link.members ?? {}).some(
827
- (member) =>
828
- (link.kind === 'style-reference' && !!member.members) ||
829
- nested(member),
830
- )
831
- }
832
- function dynamic(link: Themes.Link): boolean {
833
- return (
834
- !!link.style?.dynamic ||
835
- Object.values(link.members ?? {}).some(dynamic)
836
- )
837
- }
838
- if (Object.values(links).some(dynamic)) return 23
839
- if (Object.values(links).some(nested)) return 22
840
- if (Object.values(links).some(staticRecipe)) return 21
841
- if (Object.values(links).some(targeted)) return 20
842
- // Style authoring exports serialize as `style`; older readers only know `css`.
843
- if (Object.values(links).some(styled)) return 19
844
- // Root controls call a runtime helper older releases lack, and older
845
- // readers reject the storageKey option, so both require readers to opt in.
846
- // Local configurations emit the same helper without an exported binding.
847
- if (
848
- configurations.length ||
849
- Object.values(links).some(
850
- (link) =>
851
- (link.call.appearance &&
852
- (link.kind === 'config' || link.call.root)) ||
853
- link.call.options?.storageKey !== undefined,
854
- )
855
- )
856
- return 18
857
- if (
858
- Object.values(links).some(callable) ||
859
- Object.values(themes).some(
860
- (theme) => theme[Token.definition].contract.cssOutput,
861
- )
862
- )
863
- return 17
864
- if (Object.values(links).some((link) => link.call.recipe)) return 15
865
- if (Object.values(links).some((link) => link.kind === 'variables'))
866
- return 14
867
- if (Object.values(links).some((link) => link.kind === 'style-reference'))
868
- return 13
869
-
870
- if (
871
- Object.values(links).some(
872
- (link) => link.call.function && extended(link.call.function),
873
- )
874
- )
875
- return 12
876
-
877
- if (
878
- stylesheets.some((section) => section.namespaces?.length) ||
879
- Object.values(links).some(
880
- (link) =>
881
- link.call.function &&
882
- [
883
- link.call.function.returns,
884
- ...link.call.function.parameters.map(
885
- (parameter) => parameter.syntax ?? '*',
886
- ),
887
- ].some(
888
- (syntax) =>
889
- // Version 10 readers accepted this fixed scalar subset.
890
- !(
891
- [
892
- '*',
893
- '<angle>',
894
- '<color>',
895
- '<integer>',
896
- '<length>',
897
- '<length-percentage>',
898
- '<number>',
899
- '<percentage>',
900
- '<time>',
901
- ] as readonly string[]
902
- ).includes(syntax),
903
- ),
904
- )
905
- )
906
- return 11
907
-
908
- if (
909
- Object.values(links).some(
910
- (link) =>
911
- link.call.reference === 'cssFunction' ||
912
- link.call.reference === 'customMedia',
913
- )
914
- )
915
- return 10
916
-
917
- if (Object.values(links).some((link) => link.kind === 'rule-reference'))
918
- return 9
919
-
920
- if (Object.values(links).some((link) => link.kind === 'variables'))
921
- return 8
922
-
923
- if (
924
- stylesheets.length ||
925
- Object.values(links).some((link) => link.kind === 'animation')
926
- )
927
- return 7
928
-
929
- if (
930
- Object.values(themes).some(
931
- (theme) =>
932
- theme[Token.definition].contract.shorthands ||
933
- Object.hasOwn(theme.tokens, 'margin') ||
934
- Object.hasOwn(theme.tokens, 'padding'),
935
- ) ||
936
- Object.values(links).some(
937
- (link) =>
938
- link.call.output === 'html' ||
939
- Object.values(link.members ?? {}).some(
940
- (member) => member.call.output === 'html',
941
- ),
942
- )
943
- )
944
- return 5
945
-
946
- if (
947
- stylesheets.length ||
948
- Object.values(links).some(
949
- (link) =>
950
- link.call.selection ||
951
- (link.kind === 'config' && !!link.call.options?.themes) ||
952
- link.call.initialization ||
953
- (link.kind === 'config' && link.call.script) ||
954
- link.kind === 'animation' ||
955
- link.kind === 'variables',
956
- )
957
- )
958
- return 4
959
-
960
- if (
961
- Object.values(themes).some(
962
- (theme) =>
963
- theme[Token.definition].queries ||
964
- Object.keys(theme.tokens).some((group) =>
965
- [
966
- 'fontFamily',
967
- 'fontSize',
968
- 'fontWeight',
969
- 'lineHeight',
970
- 'letterSpacing',
971
- ].includes(group),
972
- ),
973
- )
974
- )
975
- return 3
976
-
977
- if (
978
- Object.values(links).some(
979
- (link) => link.kind === 'config' || link.call.type,
980
- )
981
- )
982
- return 2
983
-
984
- return 1
985
- })(),
813
+ version: 31,
986
814
  })
987
815
  }
988
816
 
@@ -1058,15 +886,6 @@ function signature(
1058
886
  }
1059
887
  }
1060
888
 
1061
- function extended(signature: NonNullable<Themes.Call['function']>): boolean {
1062
- return (
1063
- /[\\\u0080-\uffff]/.test(signature.returns) ||
1064
- signature.parameters.some((parameter) =>
1065
- /[\\\u0080-\uffff]/.test(parameter.name + (parameter.syntax ?? '*')),
1066
- )
1067
- )
1068
- }
1069
-
1070
889
  function encode(value: unknown): unknown {
1071
890
  if (Token.isExpression(value) && 'group' in value)
1072
891
  return {
@@ -1075,6 +894,9 @@ function encode(value: unknown): unknown {
1075
894
  if (Token.is(value))
1076
895
  return {
1077
896
  $variable: {
897
+ ...(value.contract.variableNaming
898
+ ? { variableNaming: value.contract.variableNaming }
899
+ : {}),
1078
900
  identity: value.contract[Token.identity],
1079
901
  path: value.path,
1080
902
  value: encode(value.value),
@@ -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 })
@@ -941,7 +941,7 @@ export function collect(program: Ast.Program, options: collect.Options) {
941
941
  'id-',
942
942
  )
943
943
  )
944
- name = definition.className.slice('z_theme-'.length)
944
+ name = definition.className.slice('z-theme-'.length)
945
945
  tokenType = parent.tokenType
946
946
  output = parent.output
947
947
  }
@@ -977,6 +977,11 @@ export function collect(program: Ast.Program, options: collect.Options) {
977
977
  : {}),
978
978
  })
979
979
 
980
+ definition = Token.bind(
981
+ definition,
982
+ definition[Token.definition].contract,
983
+ binding,
984
+ )
980
985
  calls.push(call)
981
986
  definitions.set(variable.id.start, call)
982
987
  factories.add(expression.start)
@@ -6,6 +6,7 @@ import * as Theme from '../../internal/Theme.js'
6
6
  import type * as Css from '../../web/Css.js'
7
7
  import * as Identity from '../../internal/Identity.js'
8
8
  import * as Expression from './Expression.js'
9
+ import * as Names from './Names.js'
9
10
  import type * as Scope from './Scope.js'
10
11
  import type * as Themes from './Themes.js'
11
12
  import { InvalidError } from './Themes.js'
@@ -14,6 +15,8 @@ import { InvalidError } from './Themes.js'
14
15
  export type Call = {
15
16
  /** Exclusive source offset. */
16
17
  readonly end: number
18
+ /** Whether the consumer supplied a portable variable identity. */
19
+ readonly explicit?: boolean | undefined
17
20
  /** Fixed scalar reference retained in portable metadata. */
18
21
  readonly slots: Readonly<Record<string, Binding.Reference>>
19
22
  /** Inclusive source offset. */
@@ -28,6 +31,7 @@ export function collect(
28
31
  links: Readonly<Record<string, Themes.Link>> = {},
29
32
  moduleId = namespace,
30
33
  ) {
34
+ const authoredNames = Names.collect(program)
31
35
  const imports = new Set<number>()
32
36
  const external = new Map<number, Themes.Link>()
33
37
  for (const statement of program.body) {
@@ -187,6 +191,7 @@ export function collect(
187
191
  })
188
192
 
189
193
  const calls: Call[] = []
194
+ const explicit = new Set<number>()
190
195
  const definitions = new Map<number, Themes.Link>()
191
196
  const registrations: Css.Contribution[] = []
192
197
  const registrationStarts: number[] = []
@@ -275,8 +280,10 @@ export function collect(
275
280
  descriptor[key] = literal as string | number | boolean
276
281
  }
277
282
 
283
+ if (descriptor.id !== undefined) explicit.add(call.start)
284
+
278
285
  const name =
279
- `--z-v${descriptor.id === undefined ? `${namespace}-${call.start}` : Identity.requireId(typeof descriptor.id === 'string' ? descriptor.id : undefined, 'variable')}` as const
286
+ `--z-${descriptor.id === undefined ? authoredNames.get(call.start)! : Identity.requireId(typeof descriptor.id === 'string' ? descriptor.id : undefined, 'variable').slice(3)}` as const
280
287
  if (value && Object.keys(descriptor).some((key) => key !== 'id')) {
281
288
  const syntax =
282
289
  kind === 'signedLength'
@@ -325,6 +332,7 @@ export function collect(
325
332
  variable: true as const,
326
333
  })
327
334
  const entry = Object.freeze({
335
+ explicit: explicit.has(call.start),
328
336
  start: call.start,
329
337
  end: call.end,
330
338
  slots: Object.freeze({ value: slot }),