zyzz 0.0.21 → 0.0.23

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 (233) hide show
  1. package/Zyzz.podspec +16 -0
  2. package/dist/Style.d.ts +3 -1
  3. package/dist/Style.d.ts.map +1 -1
  4. package/dist/Style.js.map +1 -1
  5. package/dist/babel/NativeJsx.d.ts.map +1 -1
  6. package/dist/babel/NativeJsx.js +217 -15
  7. package/dist/babel/NativeJsx.js.map +1 -1
  8. package/dist/babel/index.d.ts +6 -2
  9. package/dist/babel/index.d.ts.map +1 -1
  10. package/dist/babel/index.js +10 -1
  11. package/dist/babel/index.js.map +1 -1
  12. package/dist/compiler/Graph.d.ts.map +1 -1
  13. package/dist/compiler/Graph.js +107 -0
  14. package/dist/compiler/Graph.js.map +1 -1
  15. package/dist/compiler/Native.d.ts +6 -3
  16. package/dist/compiler/Native.d.ts.map +1 -1
  17. package/dist/compiler/Native.js +142 -24
  18. package/dist/compiler/Native.js.map +1 -1
  19. package/dist/compiler/Source.d.ts +2 -0
  20. package/dist/compiler/Source.d.ts.map +1 -1
  21. package/dist/compiler/Source.js +17 -5
  22. package/dist/compiler/Source.js.map +1 -1
  23. package/dist/compiler/internal/Configurations.d.ts +2 -0
  24. package/dist/compiler/internal/Configurations.d.ts.map +1 -1
  25. package/dist/compiler/internal/Configurations.js +21 -3
  26. package/dist/compiler/internal/Configurations.js.map +1 -1
  27. package/dist/compiler/internal/Contract.d.ts.map +1 -1
  28. package/dist/compiler/internal/Contract.js +75 -38
  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 +7 -1
  32. package/dist/compiler/internal/Contributions.js.map +1 -1
  33. package/dist/compiler/internal/Descriptors.d.ts.map +1 -1
  34. package/dist/compiler/internal/Descriptors.js +11 -2
  35. package/dist/compiler/internal/Descriptors.js.map +1 -1
  36. package/dist/compiler/internal/Dynamic.d.ts.map +1 -1
  37. package/dist/compiler/internal/Dynamic.js +3 -0
  38. package/dist/compiler/internal/Dynamic.js.map +1 -1
  39. package/dist/compiler/internal/Expression.js +2 -2
  40. package/dist/compiler/internal/Expression.js.map +1 -1
  41. package/dist/compiler/internal/NativeBindings.d.ts +24 -26
  42. package/dist/compiler/internal/NativeBindings.d.ts.map +1 -1
  43. package/dist/compiler/internal/NativeBindings.js +62 -8
  44. package/dist/compiler/internal/NativeBindings.js.map +1 -1
  45. package/dist/compiler/internal/NativeMedia.d.ts +14 -0
  46. package/dist/compiler/internal/NativeMedia.d.ts.map +1 -0
  47. package/dist/compiler/internal/NativeMedia.js +287 -0
  48. package/dist/compiler/internal/NativeMedia.js.map +1 -0
  49. package/dist/compiler/internal/NativeVars.d.ts +28 -0
  50. package/dist/compiler/internal/NativeVars.d.ts.map +1 -0
  51. package/dist/compiler/internal/NativeVars.js +160 -0
  52. package/dist/compiler/internal/NativeVars.js.map +1 -0
  53. package/dist/compiler/internal/PackedStyles.d.ts +2 -0
  54. package/dist/compiler/internal/PackedStyles.d.ts.map +1 -1
  55. package/dist/compiler/internal/PackedStyles.js +2 -0
  56. package/dist/compiler/internal/PackedStyles.js.map +1 -1
  57. package/dist/compiler/internal/Themes.d.ts +24 -1
  58. package/dist/compiler/internal/Themes.d.ts.map +1 -1
  59. package/dist/compiler/internal/Themes.js +120 -3
  60. package/dist/compiler/internal/Themes.js.map +1 -1
  61. package/dist/compiler/internal/Vars.d.ts +1 -1
  62. package/dist/compiler/internal/Vars.d.ts.map +1 -1
  63. package/dist/compiler/internal/Vars.js +7 -2
  64. package/dist/compiler/internal/Vars.js.map +1 -1
  65. package/dist/default.js.zyzz.json +1 -1
  66. package/dist/internal/Completion.d.ts +1 -1
  67. package/dist/internal/Completion.d.ts.map +1 -1
  68. package/dist/internal/Targets.d.ts.map +1 -1
  69. package/dist/internal/Targets.js +2 -0
  70. package/dist/internal/Targets.js.map +1 -1
  71. package/dist/internal/Token.d.ts +0 -2
  72. package/dist/internal/Token.d.ts.map +1 -1
  73. package/dist/internal/Token.js.map +1 -1
  74. package/dist/internal/Value.d.ts +7 -0
  75. package/dist/internal/Value.d.ts.map +1 -1
  76. package/dist/internal/Value.js.map +1 -1
  77. package/dist/metro/Graph.d.ts +22 -7
  78. package/dist/metro/Graph.d.ts.map +1 -1
  79. package/dist/metro/Graph.js +188 -42
  80. package/dist/metro/Graph.js.map +1 -1
  81. package/dist/metro/Watch.d.ts +28 -4
  82. package/dist/metro/Watch.d.ts.map +1 -1
  83. package/dist/metro/Watch.js +39 -7
  84. package/dist/metro/Watch.js.map +1 -1
  85. package/dist/metro/index.d.ts +15 -4
  86. package/dist/metro/index.d.ts.map +1 -1
  87. package/dist/metro/index.js +27 -0
  88. package/dist/metro/index.js.map +1 -1
  89. package/dist/metro/transformer.d.ts +5 -1
  90. package/dist/metro/transformer.d.ts.map +1 -1
  91. package/dist/metro/transformer.js +5 -3
  92. package/dist/metro/transformer.js.map +1 -1
  93. package/dist/react-native/StyleSheet.d.ts +8 -3
  94. package/dist/react-native/StyleSheet.d.ts.map +1 -1
  95. package/dist/react-native/StyleSheet.js +25 -34
  96. package/dist/react-native/StyleSheet.js.map +1 -1
  97. package/dist/react-native/index.d.ts +1 -1
  98. package/dist/react-native/index.d.ts.map +1 -1
  99. package/dist/react-native/index.js +1 -1
  100. package/dist/react-native/index.js.map +1 -1
  101. package/dist/react-native/index.native.d.ts +5 -0
  102. package/dist/react-native/index.native.js +20 -0
  103. package/dist/react-native/index.native.js.map +7 -0
  104. package/dist/react-native/internal/Calculation.d.ts +7 -0
  105. package/dist/react-native/internal/Calculation.d.ts.map +1 -0
  106. package/dist/react-native/internal/Calculation.js +134 -0
  107. package/dist/react-native/internal/Calculation.js.map +1 -0
  108. package/dist/react-native/internal/Device.js +218 -0
  109. package/dist/react-native/internal/Device.js.map +7 -0
  110. package/dist/react-native/internal/NativeZyzz.js +7 -0
  111. package/dist/react-native/internal/NativeZyzz.js.map +7 -0
  112. package/dist/react-native/internal/Scalar.d.ts +16 -0
  113. package/dist/react-native/internal/Scalar.d.ts.map +1 -1
  114. package/dist/react-native/internal/Scalar.js +62 -4
  115. package/dist/react-native/internal/Scalar.js.map +1 -1
  116. package/dist/react-native/internal/Store.d.ts +32 -0
  117. package/dist/react-native/internal/Store.d.ts.map +1 -0
  118. package/dist/react-native/internal/Store.js +57 -0
  119. package/dist/react-native/internal/Store.js.map +1 -0
  120. package/dist/react-native/internal/Styles.d.ts +19 -0
  121. package/dist/react-native/internal/Styles.d.ts.map +1 -0
  122. package/dist/react-native/internal/Styles.js +35 -0
  123. package/dist/react-native/internal/Styles.js.map +1 -0
  124. package/dist/react-native/internal/Tokens.d.ts +21 -0
  125. package/dist/react-native/internal/Tokens.d.ts.map +1 -0
  126. package/dist/react-native/internal/Tokens.js +58 -0
  127. package/dist/react-native/internal/Tokens.js.map +1 -0
  128. package/dist/react-native/internal/Viewport.d.ts +6 -0
  129. package/dist/react-native/internal/Viewport.d.ts.map +1 -0
  130. package/dist/react-native/internal/Viewport.js +4 -0
  131. package/dist/react-native/internal/Viewport.js.map +1 -0
  132. package/dist/react-native/react.d.ts +102 -14
  133. package/dist/react-native/react.d.ts.map +1 -1
  134. package/dist/react-native/react.js +86 -18
  135. package/dist/react-native/react.js.map +1 -1
  136. package/dist/react-native/reanimated.d.ts +39 -0
  137. package/dist/react-native/reanimated.d.ts.map +1 -0
  138. package/dist/react-native/reanimated.js +76 -0
  139. package/dist/react-native/reanimated.js.map +1 -0
  140. package/dist/runtime/NativeContext.d.ts +10 -1
  141. package/dist/runtime/NativeContext.d.ts.map +1 -1
  142. package/dist/runtime/NativeContext.js +67 -14
  143. package/dist/runtime/NativeContext.js.map +1 -1
  144. package/dist/runtime/NativeDynamic.d.ts +3 -2
  145. package/dist/runtime/NativeDynamic.d.ts.map +1 -1
  146. package/dist/runtime/NativeDynamic.js +37 -7
  147. package/dist/runtime/NativeDynamic.js.map +1 -1
  148. package/dist/runtime/NativeStatic.d.ts +23 -0
  149. package/dist/runtime/NativeStatic.d.ts.map +1 -0
  150. package/dist/runtime/NativeStatic.js +106 -0
  151. package/dist/runtime/NativeStatic.js.map +1 -0
  152. package/dist/runtime/NativeVars.d.ts +53 -0
  153. package/dist/runtime/NativeVars.d.ts.map +1 -0
  154. package/dist/runtime/NativeVars.js +77 -0
  155. package/dist/runtime/NativeVars.js.map +1 -0
  156. package/dist/runtime/index.d.ts +4 -0
  157. package/dist/runtime/index.d.ts.map +1 -1
  158. package/dist/runtime/index.js +4 -0
  159. package/dist/runtime/index.js.map +1 -1
  160. package/dist/runtime/internal/NativeMedia.d.ts +25 -0
  161. package/dist/runtime/internal/NativeMedia.d.ts.map +1 -0
  162. package/dist/runtime/internal/NativeMedia.js +36 -0
  163. package/dist/runtime/internal/NativeMedia.js.map +1 -0
  164. package/dist/vite/index.d.ts.map +1 -1
  165. package/dist/vite/index.js +7 -35
  166. package/dist/vite/index.js.map +1 -1
  167. package/dist/web/Css.d.ts.map +1 -1
  168. package/dist/web/Css.js +31 -19
  169. package/dist/web/Css.js.map +1 -1
  170. package/dist/web/internal/Themes.d.ts +0 -2
  171. package/dist/web/internal/Themes.d.ts.map +1 -1
  172. package/dist/web/internal/Themes.js +30 -28
  173. package/dist/web/internal/Themes.js.map +1 -1
  174. package/dist/web/page.d.ts +2 -0
  175. package/dist/web/page.d.ts.map +1 -1
  176. package/native/NativeZyzz.cpp +215 -0
  177. package/native/NativeZyzz.h +52 -0
  178. package/native/ZyzzSpecJSI.h +65 -0
  179. package/native/android/CMakeLists.txt +8 -0
  180. package/native/android/ZyzzSpec-generated.cpp +50 -0
  181. package/native/android/ZyzzSpec.h +31 -0
  182. package/native/ios/ZyzzModuleProvider.mm +13 -0
  183. package/package.json +39 -1
  184. package/react-native.config.ts +14 -0
  185. package/src/Style.ts +11 -8
  186. package/src/babel/NativeJsx.ts +319 -33
  187. package/src/babel/index.ts +21 -3
  188. package/src/compiler/Graph.ts +126 -0
  189. package/src/compiler/Native.ts +158 -26
  190. package/src/compiler/Source.ts +32 -5
  191. package/src/compiler/internal/Configurations.ts +25 -3
  192. package/src/compiler/internal/Contract.ts +98 -50
  193. package/src/compiler/internal/Contributions.ts +7 -1
  194. package/src/compiler/internal/Descriptors.ts +12 -8
  195. package/src/compiler/internal/Dynamic.ts +4 -0
  196. package/src/compiler/internal/Expression.ts +2 -2
  197. package/src/compiler/internal/NativeBindings.ts +99 -15
  198. package/src/compiler/internal/NativeMedia.ts +342 -0
  199. package/src/compiler/internal/NativeVars.ts +231 -0
  200. package/src/compiler/internal/PackedStyles.ts +4 -0
  201. package/src/compiler/internal/Themes.ts +193 -2
  202. package/src/compiler/internal/Vars.ts +12 -1
  203. package/src/internal/Completion.ts +6 -3
  204. package/src/internal/Targets.ts +2 -0
  205. package/src/internal/Token.ts +0 -2
  206. package/src/internal/Value.ts +20 -0
  207. package/src/metro/Graph.ts +250 -50
  208. package/src/metro/Watch.ts +95 -10
  209. package/src/metro/index.ts +62 -4
  210. package/src/metro/transformer.ts +21 -11
  211. package/src/react-native/StyleSheet.ts +56 -49
  212. package/src/react-native/index.native.ts +10 -0
  213. package/src/react-native/index.ts +1 -1
  214. package/src/react-native/internal/Calculation.ts +159 -0
  215. package/src/react-native/internal/Device.ts +297 -0
  216. package/src/react-native/internal/NativeZyzz.ts +20 -0
  217. package/src/react-native/internal/Scalar.ts +86 -4
  218. package/src/react-native/internal/Store.ts +78 -0
  219. package/src/react-native/internal/Styles.ts +77 -0
  220. package/src/react-native/internal/Tokens.ts +85 -0
  221. package/src/react-native/internal/Viewport.ts +8 -0
  222. package/src/react-native/react.ts +218 -26
  223. package/src/react-native/reanimated.ts +162 -0
  224. package/src/runtime/NativeContext.ts +88 -17
  225. package/src/runtime/NativeDynamic.ts +42 -10
  226. package/src/runtime/NativeStatic.ts +145 -0
  227. package/src/runtime/NativeVars.ts +189 -0
  228. package/src/runtime/index.ts +6 -0
  229. package/src/runtime/internal/NativeMedia.ts +63 -0
  230. package/src/vite/index.ts +9 -42
  231. package/src/web/Css.ts +42 -27
  232. package/src/web/internal/Themes.ts +34 -57
  233. package/src/web/page.ts +2 -0
@@ -8,6 +8,8 @@ import type * as Mapping from '@jridgewell/gen-mapping'
8
8
  import * as Css from '../web/Css.js'
9
9
  import * as ClassName from '../web/internal/ClassName.js'
10
10
  import * as Native from './Native.js'
11
+ import * as NativeVars from './internal/NativeVars.js'
12
+ import * as NativeStyleSheet from '../react-native/StyleSheet.js'
11
13
  import * as Edits from './internal/Edits.js'
12
14
  import * as Identity from '../internal/Identity.js'
13
15
  import type * as Ast from '@oxc-project/types'
@@ -1086,10 +1088,133 @@ function build(options: compile.Options, cache?: Cache): Cache {
1086
1088
  : {}),
1087
1089
  }
1088
1090
  }
1091
+ const profiles = new Map<
1092
+ string,
1093
+ {
1094
+ definitions: Map<string, string>
1095
+ reads: Map<number, { name: string; source?: string }>
1096
+ }
1097
+ >()
1098
+ const reserved = new Set(
1099
+ [...identifiers.values()].flatMap((names) => [...names]),
1100
+ )
1101
+ function profile(moduleId: string) {
1102
+ let value = profiles.get(moduleId)
1103
+ if (!value) {
1104
+ value = { definitions: new Map(), reads: new Map() }
1105
+ profiles.set(moduleId, value)
1106
+ }
1107
+ return value
1108
+ }
1109
+
1110
+ function encode(read: Omit<Themes.VarsRead, 'end' | 'start'>) {
1111
+ try {
1112
+ return JSON.stringify(
1113
+ NativeVars.compile({
1114
+ ...read,
1115
+ fonts: native.fonts,
1116
+ units: native.units,
1117
+ }),
1118
+ )
1119
+ } catch (error) {
1120
+ throw new Native.CompileError((error as Error).message)
1121
+ }
1122
+ }
1123
+
1124
+ function define(owner: string, value: string) {
1125
+ const definitions = profile(owner).definitions
1126
+ let name = definitions.get(value)
1127
+ if (!name) {
1128
+ // Hashing the owner keeps names independent of which modules share the graph.
1129
+ name = `__zyzzProfile${Identity.hash(owner + value)}`
1130
+ while (reserved.has(name)) name += '_'
1131
+ reserved.add(name)
1132
+ definitions.set(value, name)
1133
+ }
1134
+ return name
1135
+ }
1136
+
1137
+ if (ids.some((id) => extracted.get(id)!.nativeVars?.length))
1138
+ NativeStyleSheet.compile({
1139
+ fonts: native.fonts,
1140
+ platform: native.platform,
1141
+ units: native.units,
1142
+ styles: { styles: [] },
1143
+ })
1144
+
1145
+ // Single-file adapters compile each owner without its consumers, so owners publish every exported profile.
1146
+ if (native[Edits.runtime])
1147
+ for (const moduleId of ids)
1148
+ for (const link of Object.values(
1149
+ extracted.get(moduleId)!.themeExports ?? {},
1150
+ )) {
1151
+ if (
1152
+ owners[link.call.name]?.moduleId !== moduleId ||
1153
+ !(
1154
+ link.call.variableSet ||
1155
+ (link.kind === 'config' &&
1156
+ link.call.variableConfig &&
1157
+ !link.call.initialization &&
1158
+ !link.call.root)
1159
+ )
1160
+ )
1161
+ continue
1162
+ const value = (() => {
1163
+ try {
1164
+ return encode(Themes.varsRead(link))
1165
+ } catch {
1166
+ // Consumers that read this profile report the same error.
1167
+ return undefined
1168
+ }
1169
+ })()
1170
+ if (value !== undefined) define(moduleId, value)
1171
+ }
1172
+
1173
+ for (const moduleId of ids) {
1174
+ for (const read of extracted.get(moduleId)!.nativeVars ?? []) {
1175
+ const owner = owners[read.owner]?.moduleId
1176
+ // Packed catalogs without source retain their local fallback.
1177
+ if (!owner || !Object.hasOwn(options.modules, owner)) continue
1178
+
1179
+ const value = encode(read)
1180
+ const name = native[Edits.runtime]
1181
+ ? profiles.get(owner)?.definitions.get(value)
1182
+ : define(owner, value)
1183
+ if (!name) continue
1184
+
1185
+ const source = (() => {
1186
+ if (owner === moduleId) return undefined
1187
+
1188
+ // Host identities are opaque, so reuse the consumer's own resolved specifier.
1189
+ if (native[Edits.runtime] && options.imports) {
1190
+ const imports = options.imports[moduleId] ?? {}
1191
+ return Object.keys(imports).find((key) => imports[key] === owner)
1192
+ }
1193
+
1194
+ const from = moduleId.split('/').slice(0, -1)
1195
+ const to = owner.split('/')
1196
+ while (from.length && from[0] === to[0]) {
1197
+ from.shift()
1198
+ to.shift()
1199
+ }
1200
+ return (
1201
+ (from.length ? '../'.repeat(from.length) : './') +
1202
+ to.join('/').replace(/\.([cm]?)tsx?$/, '.$1js')
1203
+ )
1204
+ })()
1205
+ if (owner !== moduleId && !source) continue
1206
+ profile(moduleId).reads.set(read.start, {
1207
+ name,
1208
+ ...(source ? { source } : {}),
1209
+ })
1210
+ }
1211
+ }
1089
1212
  const modules = Object.fromEntries(
1090
1213
  ids.map((moduleId) => {
1214
+ // Single-file profiles derive only from this module's extraction and its dependencies.
1091
1215
  if (
1092
1216
  previous &&
1217
+ (native[Edits.runtime] || !profiles.size) &&
1093
1218
  extracted.get(moduleId) === previous.extracted.get(moduleId)
1094
1219
  )
1095
1220
  return [moduleId, previous.result.modules[moduleId]!]
@@ -1133,6 +1258,7 @@ function build(options: compile.Options, cache?: Cache): Cache {
1133
1258
  }
1134
1259
  const output = Native.compile({
1135
1260
  ...native,
1261
+ [NativeVars.shared]: profiles.get(moduleId),
1136
1262
  moduleId,
1137
1263
  source: options.modules[moduleId]!,
1138
1264
  [Themes.context]: {
@@ -5,6 +5,8 @@ import type * as Recipe from '../internal/Recipe.js'
5
5
  import * as Source from './Source.js'
6
6
  import * as Edits from './internal/Edits.js'
7
7
  import * as NativeBindings from './internal/NativeBindings.js'
8
+ import * as NativeMedia from './internal/NativeMedia.js'
9
+ import * as NativeVars from './internal/NativeVars.js'
8
10
  import * as Themes from './internal/Themes.js'
9
11
  import * as StyleSheet from '../react-native/StyleSheet.js'
10
12
  import * as Syntax from './internal/Syntax.js'
@@ -12,7 +14,7 @@ import * as Variants from '../react-native/Variants.js'
12
14
  import * as Walker from 'oxc-walker'
13
15
 
14
16
  /**
15
- * Compiles local style and variants calls for an explicit native context.
17
+ * Compiles local styles, variants, and variable reads for an explicit native target.
16
18
  * @param options - Shared source, destination mappings, and selected set/scheme.
17
19
  * @returns Native callables, source map, and static recipe tables.
18
20
  * @throws {Source.ExtractError} For invalid source authoring.
@@ -50,9 +52,13 @@ export function compile(options: compile.Options): compile.ReturnType {
50
52
  })
51
53
  let helper = '__zyzzNative'
52
54
  while (
53
- [helper, `${helper}Context`, `${helper}Dynamic`].some((name) =>
54
- names.has(name),
55
- )
55
+ [
56
+ helper,
57
+ `${helper}Context`,
58
+ `${helper}Dynamic`,
59
+ `${helper}Static`,
60
+ `${helper}Vars`,
61
+ ].some((name) => names.has(name))
56
62
  )
57
63
  helper += '_'
58
64
  let dynamicHelper = `${helper}Dynamic`
@@ -70,6 +76,7 @@ export function compile(options: compile.Options): compile.ReturnType {
70
76
  }
71
77
  const recipes: Record<string, Variants.Definition> = Object.create(null)
72
78
  let dynamic = false
79
+ let finite = false
73
80
  const contexts = new Map<string, string>()
74
81
  const compiledCalls = new WeakMap<
75
82
  Variants.Definition,
@@ -92,6 +99,54 @@ export function compile(options: compile.Options): compile.ReturnType {
92
99
  }
93
100
 
94
101
  const staticTables = new Map<Source.Call, Variants.Definition>()
102
+ if (extracted.nativeVars?.length)
103
+ StyleSheet.compile({
104
+ fonts: options.fonts,
105
+ platform: options.platform,
106
+ styles: { styles: [] },
107
+ units: options.units,
108
+ })
109
+
110
+ const shared = options[NativeVars.shared]
111
+ const variables = new Map(shared?.definitions)
112
+ const imports = new Set<string>()
113
+ for (const read of extracted.nativeVars ?? []) {
114
+ const imported = shared?.reads.get(read.start)
115
+ if (imported) {
116
+ if (imported.source)
117
+ imports.add(
118
+ `import {${imported.name}} from ${JSON.stringify(imported.source)};`,
119
+ )
120
+ const type = typed
121
+ ? ` as typeof ${options.source.slice(read.start, read.end)}`
122
+ : ''
123
+ overwrite(read.start, read.end, `(${imported.name}${type})`, true)
124
+ continue
125
+ }
126
+ const definition = (() => {
127
+ try {
128
+ return NativeVars.compile({
129
+ ...read,
130
+ fonts: options.fonts,
131
+ units: options.units,
132
+ })
133
+ } catch (error) {
134
+ throw new CompileError((error as Error).message)
135
+ }
136
+ })()
137
+ const key = JSON.stringify(definition)
138
+ let name = variables.get(key)
139
+ if (!name) {
140
+ name = `${helper}Vars${variables.size}`
141
+ while (names.has(name)) name += '_'
142
+ names.add(name)
143
+ variables.set(key, name)
144
+ }
145
+ const type = typed
146
+ ? ` as typeof ${options.source.slice(read.start, read.end)}`
147
+ : ''
148
+ overwrite(read.start, read.end, `(${name}${type})`, true)
149
+ }
95
150
  if (options.contextual) {
96
151
  const groups = new Map<StyleSheet.compile.Options['vars'], Source.Call[]>()
97
152
  for (const call of extracted.calls) {
@@ -104,6 +159,15 @@ export function compile(options: compile.Options): compile.ReturnType {
104
159
  )
105
160
  continue
106
161
  const vars = call.nativeContext?.vars ?? options.vars
162
+ try {
163
+ if (
164
+ NativeMedia.prepare(stylesByName.get(call.name) ?? [], vars, options)
165
+ )
166
+ continue
167
+ } catch (error) {
168
+ throw new CompileError((error as Error).message)
169
+ }
170
+
107
171
  const group = groups.get(vars)
108
172
  if (group) group.push(call)
109
173
  else groups.set(vars, [call])
@@ -233,9 +297,58 @@ export function compile(options: compile.Options): compile.ReturnType {
233
297
  compiled?: Variants.Definition,
234
298
  bindings?: ReturnType<typeof NativeBindings.prepare>,
235
299
  ): string {
300
+ const program =
301
+ Object.keys(recipe.axes).length > 0 ||
302
+ call?.slots ||
303
+ call?.recipe?.payloads?.length
304
+
236
305
  if (contextOptions.contextual) {
237
306
  const vars = call?.nativeContext?.vars ?? contextOptions.vars
238
- if (!call?.slots && !call?.recipe?.payloads?.length)
307
+ const media = (() => {
308
+ try {
309
+ return NativeMedia.prepare(
310
+ recipe.rules.flatMap((rule) => rule.value.styles),
311
+ vars,
312
+ contextOptions,
313
+ )
314
+ } catch (error) {
315
+ throw new CompileError((error as Error).message)
316
+ }
317
+ })()
318
+ if (media) {
319
+ const profiles = media.selections.map((selection) => {
320
+ const selected = media.select(selection)
321
+ const next = {
322
+ ...recipe,
323
+ rules: recipe.rules.map((rule) => ({
324
+ ...rule,
325
+ value: {
326
+ ...rule.value,
327
+ styles: rule.value.styles.map(selected.style),
328
+ },
329
+ })),
330
+ }
331
+ const source = call?.nativeContext
332
+ ? {
333
+ ...call,
334
+ nativeContext: {
335
+ ...call.nativeContext,
336
+ vars: selected.vars as typeof call.nativeContext.vars,
337
+ },
338
+ }
339
+ : call
340
+ const value = callable(next, name, source, {
341
+ ...contextOptions,
342
+ vars: selected.vars,
343
+ })
344
+ return `${JSON.stringify(selection)}:${value}`
345
+ })
346
+ // A single static table cannot represent the responsive callable.
347
+ delete recipes[name]
348
+
349
+ return `${helper}Context.responsive(${JSON.stringify(media.queries)},{${profiles.join(',')}})`
350
+ }
351
+ if (!program)
239
352
  compiled ??= Variants.compile({
240
353
  recipe,
241
354
  fonts: contextOptions.fonts,
@@ -245,7 +358,7 @@ export function compile(options: compile.Options): compile.ReturnType {
245
358
  })
246
359
  else {
247
360
  try {
248
- bindings = NativeBindings.prepare(recipe, call!, {
361
+ bindings = NativeBindings.prepare(recipe, call ?? {}, {
249
362
  ...contextOptions,
250
363
  vars,
251
364
  })
@@ -315,18 +428,36 @@ export function compile(options: compile.Options): compile.ReturnType {
315
428
  }
316
429
  return `${context}(${[...tables.keys()].join(',')})`
317
430
  }
318
- if (call?.slots || call?.recipe?.payloads?.length) {
319
- dynamic = true
431
+ const axes = Object.entries(recipe.axes)
432
+ .map(
433
+ ([axis, choices]) =>
434
+ `${JSON.stringify(axis)}:readonly ${JSON.stringify(choices)}`,
435
+ )
436
+ .join(';')
437
+
438
+ if (program) {
439
+ const scalar = !!(call?.slots || call?.recipe?.payloads?.length)
440
+ dynamic ||= scalar
441
+ finite ||= !scalar
320
442
  const compiled = (() => {
321
443
  try {
322
- return NativeBindings.compile(recipe, call, contextOptions, bindings)
444
+ const compiled = NativeBindings.compile(
445
+ recipe,
446
+ call ?? {},
447
+ contextOptions,
448
+ bindings,
449
+ )
450
+ return scalar ? compiled : NativeBindings.finite(compiled)
323
451
  } catch (error) {
324
452
  if (error instanceof StyleSheet.CompileError) throw error
325
453
  throw new CompileError((error as Error).message)
326
454
  }
327
455
  })()
328
- const value = create(dynamicHelper, compiled)
456
+ const value = create(scalar ? dynamicHelper : `${helper}Static`, compiled)
329
457
  if (!typed) return value
458
+ if (!call?.slots && !call?.recipe?.payloads?.length)
459
+ return `(${value} as import('zyzz/runtime').Native.Callable<{${axes}}>)`
460
+
330
461
  let input = call.valuesType ?? '{}'
331
462
  if (call.recipe) {
332
463
  input = `{${Object.entries(recipe.axes)
@@ -371,12 +502,6 @@ export function compile(options: compile.Options): compile.ReturnType {
371
502
  })
372
503
  if (options.contextual) compiledCalls.set(compiled, { styles, value })
373
504
  if (!typed) return value
374
- const axes = Object.entries(compiled.axes)
375
- .map(
376
- ([axis, choices]) =>
377
- `${JSON.stringify(axis)}:readonly ${JSON.stringify(choices)}`,
378
- )
379
- .join(';')
380
505
  return `(${value} as import('zyzz/runtime').Native.Callable<{${axes}}>)`
381
506
  }
382
507
 
@@ -483,10 +608,9 @@ export function compile(options: compile.Options): compile.ReturnType {
483
608
  throw new CompileError(
484
609
  `Packed native callable ${name} requires a static recipe contract.`,
485
610
  )
486
- const expression = callable(
487
- recipe,
488
- `${specifier}:${name}`,
489
- link.style?.dynamic
611
+ const expression = callable(recipe, `${specifier}:${name}`, {
612
+ nativeContext: link.style?.nativeContext,
613
+ ...(link.style?.dynamic
490
614
  ? {
491
615
  slots: link.style.dynamic.slots,
492
616
  recipe: {
@@ -496,8 +620,8 @@ export function compile(options: compile.Options): compile.ReturnType {
496
620
  defaultPayloads: link.style.dynamic.defaultPayloads,
497
621
  },
498
622
  }
499
- : undefined,
500
- )
623
+ : {}),
624
+ })
501
625
  if (!link.style?.dynamic || !typed) return expression
502
626
  const type = `typeof import(${JSON.stringify(specifier)})${path
503
627
  .map((part) => `[${JSON.stringify(part)}]`)
@@ -698,7 +822,13 @@ export function compile(options: compile.Options): compile.ReturnType {
698
822
  imports.length ? `import ${imports.join(',')} from 'zyzz';` : '',
699
823
  )
700
824
  }
701
- if (extracted.calls.length || compositions.length || packed.length) {
825
+ if (
826
+ extracted.calls.length ||
827
+ compositions.length ||
828
+ packed.length ||
829
+ variables.size ||
830
+ imports.size
831
+ ) {
702
832
  let offset = 0
703
833
  if (options.source.startsWith('#!')) {
704
834
  const newline = /\r\n|[\n\r\u2028\u2029]/.exec(options.source)
@@ -713,7 +843,7 @@ export function compile(options: compile.Options): compile.ReturnType {
713
843
  offset = node.end
714
844
  }
715
845
 
716
- const prelude = `\nimport {Native as ${helper}${dynamic ? `,NativeDynamic as ${dynamicHelper}` : ''}${options.contextual ? `,NativeContext as ${helper}Context` : ''}} from 'zyzz/runtime';\n${[...factories].map(([expression, factory]) => `const ${factory.name}=(${factory.parameters.join(',')})=>${expression};`).join('\n')}\n${[...contexts].map(([expression, name]) => `const ${name}=${expression};`).join('\n')}\n${[...compositions, ...packed].join('\n')}\n`
846
+ const prelude = `\nimport {Native as ${helper}${dynamic ? `,NativeDynamic as ${dynamicHelper}` : ''}${finite ? `,NativeStatic as ${helper}Static` : ''}${options.contextual ? `,NativeContext as ${helper}Context` : ''}${variables.size ? `,NativeVars as ${helper}Vars` : ''}} from 'zyzz/runtime';\n${[...factories].map(([expression, factory]) => `const ${factory.name}=(${factory.parameters.join(',')})=>${expression};`).join('\n')}\n${[...contexts].map(([expression, name]) => `const ${name}=${expression};`).join('\n')}\n${[...variables].map(([value, name]) => `${shared?.definitions.has(value) ? 'export ' : ''}const ${name}=${helper}Vars.create(JSON.parse(${JSON.stringify(value)}));`).join('\n')}\n${[...imports, ...compositions, ...packed].join('\n')}\n`
717
847
  module.appendLeft(offset, prelude)
718
848
  edits.push({ start: offset, end: offset, code: prelude, expression: false })
719
849
  }
@@ -738,6 +868,8 @@ export declare namespace compile {
738
868
  type Options = Omit<StyleSheet.compile.Options, 'styles'> & {
739
869
  /** Internal Babel emission mode; authoring types are still validated. */
740
870
  readonly [Edits.runtime]?: boolean | undefined
871
+ /** Compiler-owned shared native variable profiles. */
872
+ readonly [NativeVars.shared]?: NativeVars.Shared | undefined
741
873
  /** Compiler-owned graph context. */
742
874
  readonly [Themes.context]?: Themes.Context | undefined
743
875
  /** Retain every set and scheme for render-local selection. */
@@ -751,7 +883,7 @@ export declare namespace compile {
751
883
  /** Label selected from supplied vars. Defaults to the token-fallback default table. */
752
884
  readonly set?: string | undefined
753
885
  }
754
- /** Executable source with immutable recipe tables and authored source mappings. */
886
+ /** Executable source with immutable native data and authored source mappings. */
755
887
  type ReturnType = {
756
888
  /** Internal node replacements for syntax-tree adapters. */
757
889
  readonly [Edits.key]: readonly Edits.Edit[]
@@ -759,7 +891,7 @@ export declare namespace compile {
759
891
  readonly code: string
760
892
  /** Version-three source map encoded as JSON. */
761
893
  readonly map: string
762
- /** All set/scheme tables for each extracted definition. */
894
+ /** Set/scheme tables for definitions without variant or scalar programs. */
763
895
  readonly recipes: Readonly<Record<string, Variants.Definition>>
764
896
  }
765
897
  }
@@ -269,6 +269,7 @@ export function extract(options: extract.Options): extract.ReturnType {
269
269
  const themes = (() => {
270
270
  try {
271
271
  return Themes.collect(program, {
272
+ native: options.target === 'native',
272
273
  staticBindings: staticData.bindings,
273
274
  namespace: `src-${Identity.label(
274
275
  options.moduleId
@@ -336,7 +337,7 @@ export function extract(options: extract.Options): extract.ReturnType {
336
337
  contributions.read(node, parent, binding)
337
338
 
338
339
  try {
339
- if (variables.reference(node, parent, binding)) return
340
+ if (variables.reference(node, parent, ancestors, binding)) return
340
341
  } catch (error) {
341
342
  if (!(error instanceof Themes.InvalidError)) throw error
342
343
 
@@ -347,7 +348,16 @@ export function extract(options: extract.Options): extract.ReturnType {
347
348
 
348
349
  if (themes)
349
350
  try {
350
- if (themes.reference(node, parent, ancestors, binding)) return
351
+ if (
352
+ themes.reference(
353
+ node,
354
+ parent,
355
+ ancestors,
356
+ binding,
357
+ (name) => scopeTracker.getDeclaration(name) ?? null,
358
+ )
359
+ )
360
+ return
351
361
  } catch (error) {
352
362
  if (!(error instanceof Themes.InvalidError)) throw error
353
363
 
@@ -1520,7 +1530,17 @@ export function extract(options: extract.Options): extract.ReturnType {
1520
1530
  const style = call && styles.find((style) => style.name === call.name)
1521
1531
  return {
1522
1532
  ...link,
1523
- ...(call && style ? { style: PackedStyles.create(call, style) } : {}),
1533
+ ...(call && style
1534
+ ? {
1535
+ style: PackedStyles.create(
1536
+ {
1537
+ ...call,
1538
+ nativeContext: themes?.nativeContext(call.start, call.end),
1539
+ },
1540
+ style,
1541
+ ),
1542
+ }
1543
+ : {}),
1524
1544
  ...(link.members
1525
1545
  ? {
1526
1546
  members: Object.fromEntries(
@@ -1560,6 +1580,8 @@ export function extract(options: extract.Options): extract.ReturnType {
1560
1580
  ),
1561
1581
  }
1562
1582
  Object.defineProperty(definition, ClassName.labels, { enumerable: false })
1583
+ const selections =
1584
+ options.target === 'native' ? themes?.selectionUses : themes?.selections
1563
1585
 
1564
1586
  return Object.freeze({
1565
1587
  namespaces: contributionData.filter(
@@ -1611,8 +1633,8 @@ export function extract(options: extract.Options): extract.ReturnType {
1611
1633
  ...(themes?.scripts.size
1612
1634
  ? { themeScripts: Object.freeze([...themes.scripts]) }
1613
1635
  : {}),
1614
- ...(themes?.selections.size
1615
- ? { themeSelections: Object.freeze([...themes.selections]) }
1636
+ ...(selections?.size
1637
+ ? { themeSelections: Object.freeze([...selections]) }
1616
1638
  : {}),
1617
1639
  themeCalls: Object.freeze(themes?.calls ?? []),
1618
1640
  ...(themes?.staticTokens.length
@@ -1630,6 +1652,9 @@ export function extract(options: extract.Options): extract.ReturnType {
1630
1652
  : {}),
1631
1653
  themeReferences: Object.freeze(themes?.references ?? []),
1632
1654
  vars: themes?.themes ?? Object.freeze({}),
1655
+ ...(themes?.varsReads.length
1656
+ ? { nativeVars: Object.freeze(themes.varsReads) }
1657
+ : {}),
1633
1658
  })
1634
1659
  }
1635
1660
 
@@ -1654,6 +1679,8 @@ export declare namespace extract {
1654
1679
 
1655
1680
  /** Ordered public compiler input and spans for later rewriting. */
1656
1681
  type ReturnType = {
1682
+ /** Readonly native variable arguments and their complete catalogs. */
1683
+ readonly nativeVars?: readonly Themes.VarsRead[] | undefined
1657
1684
  /** Module-owned namespace bindings retained when contributions are shared. */
1658
1685
  readonly namespaces?: readonly Namespace.Definition[] | undefined
1659
1686
  /** Static stylesheet effects and their source replacements. */
@@ -252,10 +252,28 @@ export function collect(options: collect.Options): Themes.Link {
252
252
  ...(input.layers ? { layers: input.layers } : {}),
253
253
  ...(input.storageKey ? { storageKey: input.storageKey } : {}),
254
254
  }
255
+ const authoredType = type(
256
+ variableMode
257
+ ? {
258
+ ...normalized,
259
+ theme: undefined,
260
+ themes: undefined,
261
+ defaultTheme: undefined,
262
+ vars: 'themes' in normalized ? normalized.themes : normalized.theme,
263
+ ...('themes' in normalized
264
+ ? { defaultVars: normalized.defaultTheme }
265
+ : {}),
266
+ ...(authored.mappings !== undefined
267
+ ? { mappings: VariableSets.mappings(authored.mappings) }
268
+ : {}),
269
+ }
270
+ : normalized,
271
+ )
255
272
 
256
273
  return {
257
274
  binding: options.name,
258
275
  call: {
276
+ ...(options.nativeProvider ? { nativeProvider: true } : {}),
259
277
  ...(variableMode
260
278
  ? { variableConfig: true, variableMappings: authored.mappings }
261
279
  : {}),
@@ -269,9 +287,11 @@ export function collect(options: collect.Options): Themes.Link {
269
287
  options: normalized,
270
288
  start: options.expression.start,
271
289
  tokenType: selected?.call.tokenType ?? '{}',
272
- type: variableMode
273
- ? `import('zyzz').Config.VariableConfig<${type({ ...normalized, theme: undefined, themes: undefined, defaultTheme: undefined, vars: 'themes' in normalized ? normalized.themes : normalized.theme, ...('themes' in normalized ? { defaultVars: normalized.defaultTheme } : {}), ...(authored.mappings !== undefined ? { mappings: VariableSets.mappings(authored.mappings) } : {}) })}>`
274
- : `import('zyzz').Config.create.ReturnType<${type(normalized)}>`,
290
+ type: options.nativeProvider
291
+ ? `import('zyzz/react-native').defineConfig.ReturnType<${authoredType}>`
292
+ : variableMode
293
+ ? `import('zyzz').Config.VariableConfig<${authoredType}>`
294
+ : `import('zyzz').Config.create.ReturnType<${authoredType}>`,
275
295
  },
276
296
  definition,
277
297
  kind: 'config',
@@ -289,6 +309,8 @@ export declare namespace collect {
289
309
  readonly expression: Ast.CallExpression
290
310
  /** Stable module/binding identity. */
291
311
  readonly name: string
312
+ /** Native factory supplies an ordinary React Provider export. */
313
+ readonly nativeProvider?: boolean | undefined
292
314
  /** Looks up preceding immutable theme definitions. */
293
315
  readonly resolve: (node: Ast.Node) => Themes.Link | undefined
294
316
  }