@tamagui/static 2.7.7 → 3.0.0-beta.643.1

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 (329) hide show
  1. package/dist/cjs/check-dep-versions.cjs +355 -0
  2. package/dist/cjs/checkDeps.cjs +302 -0
  3. package/dist/cjs/compiler.cjs +286 -0
  4. package/dist/cjs/compilerHost.cjs +1695 -0
  5. package/dist/cjs/constants.cjs +33 -0
  6. package/dist/cjs/domStructuralPass.cjs +112 -0
  7. package/dist/cjs/exports.cjs +42 -0
  8. package/dist/cjs/extractor/addLocalExports.cjs +64 -0
  9. package/dist/cjs/extractor/bundle.cjs +203 -0
  10. package/dist/cjs/extractor/bundleConfig.cjs +747 -0
  11. package/dist/cjs/extractor/concatClassName.cjs +117 -0
  12. package/dist/cjs/extractor/detectModuleFormat.cjs +54 -0
  13. package/dist/cjs/extractor/esbuildAliasPlugin.cjs +47 -0
  14. package/dist/cjs/extractor/esbuildTsconfigPaths.cjs +92 -0
  15. package/dist/cjs/extractor/getTamaguiConfigPathFromOptionsConfig.cjs +38 -0
  16. package/dist/cjs/extractor/loadTamagui.cjs +344 -0
  17. package/dist/cjs/extractor/regenerateConfig.cjs +161 -0
  18. package/dist/cjs/extractor/watchTamaguiConfig.cjs +64 -0
  19. package/dist/cjs/getPragmaOptions.cjs +67 -0
  20. package/dist/cjs/helpers/memoize.cjs +42 -0
  21. package/dist/cjs/helpers/requireTamaguiCore.cjs +40 -0
  22. package/dist/cjs/index.cjs +34 -0
  23. package/dist/cjs/registerRequire.cjs +220 -0
  24. package/dist/cjs/server.cjs +66 -0
  25. package/dist/cjs/staticEvaluationIgnoredModules.cjs +86 -0
  26. package/dist/cjs/types.cjs +17 -0
  27. package/dist/cjs/zero/artifact.cjs +145 -0
  28. package/dist/cjs/zero/graph.cjs +209 -0
  29. package/dist/cjs/zero/identity.cjs +61 -0
  30. package/dist/cjs/zero/index.cjs +26 -0
  31. package/dist/cjs/zero/islands.cjs +232 -0
  32. package/dist/cjs/zero/options.cjs +163 -0
  33. package/dist/cjs/zero/ownership.cjs +79 -0
  34. package/dist/cjs/zero/theme.cjs +328 -0
  35. package/dist/cjs/zero/transform.cjs +203 -0
  36. package/dist/esm/check-dep-versions.mjs +329 -0
  37. package/dist/esm/check-dep-versions.mjs.map +1 -0
  38. package/dist/esm/checkDeps.mjs +279 -0
  39. package/dist/esm/checkDeps.mjs.map +1 -0
  40. package/dist/esm/compiler.mjs +255 -0
  41. package/dist/esm/compiler.mjs.map +1 -0
  42. package/dist/esm/compilerHost.mjs +1675 -0
  43. package/dist/esm/compilerHost.mjs.map +1 -0
  44. package/dist/esm/constants.mjs +7 -0
  45. package/dist/esm/constants.mjs.map +1 -0
  46. package/dist/esm/domStructuralPass.mjs +92 -0
  47. package/dist/esm/domStructuralPass.mjs.map +1 -0
  48. package/dist/esm/exports.mjs +26 -0
  49. package/dist/esm/extractor/addLocalExports.mjs +44 -0
  50. package/dist/esm/extractor/addLocalExports.mjs.map +1 -0
  51. package/dist/esm/extractor/bundle.mjs +173 -0
  52. package/dist/esm/extractor/bundle.mjs.map +1 -0
  53. package/dist/esm/extractor/bundleConfig.mjs +706 -0
  54. package/dist/esm/extractor/bundleConfig.mjs.map +1 -0
  55. package/dist/esm/extractor/concatClassName.mjs +96 -0
  56. package/dist/esm/extractor/concatClassName.mjs.map +1 -0
  57. package/dist/esm/extractor/detectModuleFormat.mjs +31 -0
  58. package/dist/esm/extractor/detectModuleFormat.mjs.map +1 -0
  59. package/dist/esm/extractor/esbuildAliasPlugin.mjs +26 -0
  60. package/dist/esm/extractor/esbuildAliasPlugin.mjs.map +1 -0
  61. package/dist/esm/extractor/esbuildTsconfigPaths.mjs +63 -0
  62. package/dist/esm/extractor/esbuildTsconfigPaths.mjs.map +1 -0
  63. package/dist/esm/extractor/getTamaguiConfigPathFromOptionsConfig.mjs +18 -0
  64. package/dist/esm/extractor/getTamaguiConfigPathFromOptionsConfig.mjs.map +1 -0
  65. package/dist/esm/extractor/loadTamagui.mjs +306 -0
  66. package/dist/esm/extractor/loadTamagui.mjs.map +1 -0
  67. package/dist/esm/extractor/regenerateConfig.mjs +131 -0
  68. package/dist/esm/extractor/regenerateConfig.mjs.map +1 -0
  69. package/dist/esm/extractor/watchTamaguiConfig.mjs +43 -0
  70. package/dist/esm/extractor/watchTamaguiConfig.mjs.map +1 -0
  71. package/dist/esm/getPragmaOptions.mjs +46 -0
  72. package/dist/esm/getPragmaOptions.mjs.map +1 -0
  73. package/dist/esm/helpers/memoize.mjs +21 -0
  74. package/dist/esm/helpers/memoize.mjs.map +1 -0
  75. package/dist/esm/helpers/requireTamaguiCore.mjs +19 -0
  76. package/dist/esm/helpers/requireTamaguiCore.mjs.map +1 -0
  77. package/dist/esm/index.mjs +8 -0
  78. package/dist/esm/index.mjs.map +1 -0
  79. package/dist/esm/registerRequire.mjs +195 -0
  80. package/dist/esm/registerRequire.mjs.map +1 -0
  81. package/dist/esm/server.mjs +40 -0
  82. package/dist/esm/server.mjs.map +1 -0
  83. package/dist/esm/setup.mjs +0 -0
  84. package/dist/esm/staticEvaluationIgnoredModules.mjs +61 -0
  85. package/dist/esm/staticEvaluationIgnoredModules.mjs.map +1 -0
  86. package/dist/esm/types.mjs +0 -0
  87. package/dist/esm/zero/artifact.mjs +119 -0
  88. package/dist/esm/zero/artifact.mjs.map +1 -0
  89. package/dist/esm/zero/graph.mjs +170 -0
  90. package/dist/esm/zero/graph.mjs.map +1 -0
  91. package/dist/esm/zero/identity.mjs +36 -0
  92. package/dist/esm/zero/identity.mjs.map +1 -0
  93. package/dist/esm/zero/index.mjs +15 -0
  94. package/dist/esm/zero/islands.mjs +197 -0
  95. package/dist/esm/zero/islands.mjs.map +1 -0
  96. package/dist/esm/zero/options.mjs +129 -0
  97. package/dist/esm/zero/options.mjs.map +1 -0
  98. package/dist/esm/zero/ownership.mjs +48 -0
  99. package/dist/esm/zero/ownership.mjs.map +1 -0
  100. package/dist/esm/zero/theme.mjs +303 -0
  101. package/dist/esm/zero/theme.mjs.map +1 -0
  102. package/dist/esm/zero/transform.mjs +177 -0
  103. package/dist/esm/zero/transform.mjs.map +1 -0
  104. package/package.json +33 -43
  105. package/src/check-dep-versions.ts +2 -2
  106. package/src/checkDeps.ts +3 -2
  107. package/src/compiler.ts +425 -0
  108. package/src/compilerHost.ts +3125 -0
  109. package/src/constants.ts +0 -5
  110. package/src/domStructuralPass.ts +170 -0
  111. package/src/exports.ts +3 -6
  112. package/src/extractor/addLocalExports.ts +49 -0
  113. package/src/extractor/bundle.ts +20 -35
  114. package/src/extractor/bundleConfig.ts +334 -187
  115. package/src/extractor/concatClassName.ts +13 -20
  116. package/src/extractor/getTamaguiConfigPathFromOptionsConfig.ts +5 -4
  117. package/src/extractor/loadTamagui.ts +196 -143
  118. package/src/extractor/regenerateConfig.ts +65 -13
  119. package/src/extractor/watchTamaguiConfig.ts +6 -1
  120. package/src/helpers/requireTamaguiCore.ts +6 -1
  121. package/src/registerRequire.ts +94 -132
  122. package/src/staticEvaluationIgnoredModules.ts +74 -0
  123. package/src/types.ts +2 -107
  124. package/src/zero/artifact.ts +142 -0
  125. package/src/zero/graph.ts +359 -0
  126. package/src/zero/identity.ts +73 -0
  127. package/src/zero/index.ts +8 -0
  128. package/src/zero/islands.ts +262 -0
  129. package/src/zero/options.ts +239 -0
  130. package/src/zero/ownership.ts +113 -0
  131. package/src/zero/theme.ts +478 -0
  132. package/src/zero/transform.ts +320 -0
  133. package/types/check-dep-versions.d.ts.map +1 -1
  134. package/types/checkDeps.d.ts.map +1 -1
  135. package/types/compiler.d.ts +117 -0
  136. package/types/compiler.d.ts.map +1 -0
  137. package/types/compilerHost.d.ts +25 -0
  138. package/types/compilerHost.d.ts.map +1 -0
  139. package/types/constants.d.ts +0 -1
  140. package/types/constants.d.ts.map +1 -1
  141. package/types/domStructuralPass.d.ts +3 -0
  142. package/types/domStructuralPass.d.ts.map +1 -0
  143. package/types/exports.d.ts +3 -6
  144. package/types/exports.d.ts.map +1 -1
  145. package/types/extractor/addLocalExports.d.ts +3 -0
  146. package/types/extractor/addLocalExports.d.ts.map +1 -0
  147. package/types/extractor/bundle.d.ts +66 -65
  148. package/types/extractor/bundle.d.ts.map +1 -1
  149. package/types/extractor/bundleConfig.d.ts +19 -4
  150. package/types/extractor/bundleConfig.d.ts.map +1 -1
  151. package/types/extractor/esbuildAliasPlugin.d.ts.map +1 -1
  152. package/types/extractor/getTamaguiConfigPathFromOptionsConfig.d.ts +1 -1
  153. package/types/extractor/getTamaguiConfigPathFromOptionsConfig.d.ts.map +1 -1
  154. package/types/extractor/loadTamagui.d.ts +26 -3
  155. package/types/extractor/loadTamagui.d.ts.map +1 -1
  156. package/types/extractor/regenerateConfig.d.ts +1 -1
  157. package/types/extractor/regenerateConfig.d.ts.map +1 -1
  158. package/types/extractor/watchTamaguiConfig.d.ts.map +1 -1
  159. package/types/getPragmaOptions.d.ts +1 -1
  160. package/types/helpers/memoize.d.ts +1 -1
  161. package/types/helpers/memoize.d.ts.map +1 -1
  162. package/types/helpers/requireTamaguiCore.d.ts.map +1 -1
  163. package/types/index.d.ts.map +1 -1
  164. package/types/registerRequire.d.ts +2 -2
  165. package/types/registerRequire.d.ts.map +1 -1
  166. package/types/staticEvaluationIgnoredModules.d.ts +9 -0
  167. package/types/staticEvaluationIgnoredModules.d.ts.map +1 -0
  168. package/types/types.d.ts +2 -90
  169. package/types/types.d.ts.map +1 -1
  170. package/types/zero/artifact.d.ts +44 -0
  171. package/types/zero/artifact.d.ts.map +1 -0
  172. package/types/zero/graph.d.ts +139 -0
  173. package/types/zero/graph.d.ts.map +1 -0
  174. package/types/zero/identity.d.ts +33 -0
  175. package/types/zero/identity.d.ts.map +1 -0
  176. package/types/zero/index.d.ts +9 -0
  177. package/types/zero/index.d.ts.map +1 -0
  178. package/types/zero/islands.d.ts +56 -0
  179. package/types/zero/islands.d.ts.map +1 -0
  180. package/types/zero/options.d.ts +58 -0
  181. package/types/zero/options.d.ts.map +1 -0
  182. package/types/zero/ownership.d.ts +51 -0
  183. package/types/zero/ownership.d.ts.map +1 -0
  184. package/types/zero/theme.d.ts +83 -0
  185. package/types/zero/theme.d.ts.map +1 -0
  186. package/types/zero/transform.d.ts +53 -0
  187. package/types/zero/transform.d.ts.map +1 -0
  188. package/dist/check-dep-versions.cjs +0 -372
  189. package/dist/checkDeps.cjs +0 -271
  190. package/dist/constants.cjs +0 -51
  191. package/dist/exports.cjs +0 -48
  192. package/dist/extractor/accessSafe.cjs +0 -48
  193. package/dist/extractor/babelParse.cjs +0 -56
  194. package/dist/extractor/buildClassName.cjs +0 -86
  195. package/dist/extractor/bundle.cjs +0 -234
  196. package/dist/extractor/bundleConfig.cjs +0 -729
  197. package/dist/extractor/concatClassName.cjs +0 -129
  198. package/dist/extractor/createEvaluator.cjs +0 -88
  199. package/dist/extractor/createExtractor.cjs +0 -1968
  200. package/dist/extractor/createLogger.cjs +0 -50
  201. package/dist/extractor/detectModuleFormat.cjs +0 -55
  202. package/dist/extractor/ensureImportingConcat.cjs +0 -54
  203. package/dist/extractor/errors.cjs +0 -28
  204. package/dist/extractor/esbuildAliasPlugin.cjs +0 -56
  205. package/dist/extractor/esbuildTsconfigPaths.cjs +0 -108
  206. package/dist/extractor/evaluateAstNode.cjs +0 -128
  207. package/dist/extractor/extractHelpers.cjs +0 -182
  208. package/dist/extractor/extractMediaStyle.cjs +0 -169
  209. package/dist/extractor/extractToClassNames.cjs +0 -475
  210. package/dist/extractor/extractToNative.cjs +0 -369
  211. package/dist/extractor/findTopmostFunction.cjs +0 -43
  212. package/dist/extractor/generatedUid.cjs +0 -58
  213. package/dist/extractor/getPrefixLogs.cjs +0 -31
  214. package/dist/extractor/getPropValueFromAttributes.cjs +0 -85
  215. package/dist/extractor/getSourceModule.cjs +0 -100
  216. package/dist/extractor/getStaticBindingsForScope.cjs +0 -213
  217. package/dist/extractor/getTamaguiConfigPathFromOptionsConfig.cjs +0 -41
  218. package/dist/extractor/hasTopLevelAwait.cjs +0 -62
  219. package/dist/extractor/hoistClassNames.cjs +0 -76
  220. package/dist/extractor/literalToAst.cjs +0 -109
  221. package/dist/extractor/loadFile.cjs +0 -17
  222. package/dist/extractor/loadTamagui.cjs +0 -373
  223. package/dist/extractor/logLines.cjs +0 -43
  224. package/dist/extractor/normalizeTernaries.cjs +0 -100
  225. package/dist/extractor/propsToFontFamilyCache.cjs +0 -42
  226. package/dist/extractor/regenerateConfig.cjs +0 -178
  227. package/dist/extractor/removeUnusedHooks.cjs +0 -108
  228. package/dist/extractor/timer.cjs +0 -52
  229. package/dist/extractor/validHTMLAttributes.cjs +0 -79
  230. package/dist/extractor/watchTamaguiConfig.cjs +0 -70
  231. package/dist/getPragmaOptions.cjs +0 -73
  232. package/dist/helpers/memoize.cjs +0 -45
  233. package/dist/helpers/requireTamaguiCore.cjs +0 -40
  234. package/dist/index.cjs +0 -42
  235. package/dist/registerRequire.cjs +0 -209
  236. package/dist/server.cjs +0 -82
  237. package/dist/types.cjs +0 -18
  238. package/dist/worker.cjs +0 -111
  239. package/src/extractor/accessSafe.ts +0 -22
  240. package/src/extractor/babelParse.ts +0 -38
  241. package/src/extractor/buildClassName.ts +0 -76
  242. package/src/extractor/createEvaluator.ts +0 -82
  243. package/src/extractor/createExtractor.ts +0 -2970
  244. package/src/extractor/createLogger.ts +0 -41
  245. package/src/extractor/ensureImportingConcat.ts +0 -36
  246. package/src/extractor/errors.ts +0 -1
  247. package/src/extractor/evaluateAstNode.ts +0 -136
  248. package/src/extractor/extractHelpers.ts +0 -211
  249. package/src/extractor/extractMediaStyle.ts +0 -194
  250. package/src/extractor/extractToClassNames.ts +0 -733
  251. package/src/extractor/extractToNative.ts +0 -506
  252. package/src/extractor/findTopmostFunction.ts +0 -24
  253. package/src/extractor/generatedUid.ts +0 -41
  254. package/src/extractor/getPrefixLogs.ts +0 -9
  255. package/src/extractor/getPropValueFromAttributes.ts +0 -95
  256. package/src/extractor/getSourceModule.ts +0 -96
  257. package/src/extractor/getStaticBindingsForScope.ts +0 -237
  258. package/src/extractor/hasTopLevelAwait.ts +0 -28
  259. package/src/extractor/hoistClassNames.ts +0 -52
  260. package/src/extractor/literalToAst.ts +0 -85
  261. package/src/extractor/loadFile.ts +0 -17
  262. package/src/extractor/logLines.ts +0 -16
  263. package/src/extractor/normalizeTernaries.ts +0 -89
  264. package/src/extractor/propsToFontFamilyCache.ts +0 -18
  265. package/src/extractor/removeUnusedHooks.ts +0 -83
  266. package/src/extractor/timer.ts +0 -25
  267. package/src/extractor/validHTMLAttributes.ts +0 -52
  268. package/src/worker.ts +0 -142
  269. package/types/extractor/accessSafe.d.ts +0 -3
  270. package/types/extractor/accessSafe.d.ts.map +0 -1
  271. package/types/extractor/babelParse.d.ts +0 -5
  272. package/types/extractor/babelParse.d.ts.map +0 -1
  273. package/types/extractor/buildClassName.d.ts +0 -7
  274. package/types/extractor/buildClassName.d.ts.map +0 -1
  275. package/types/extractor/createEvaluator.d.ts +0 -12
  276. package/types/extractor/createEvaluator.d.ts.map +0 -1
  277. package/types/extractor/createExtractor.d.ts +0 -32
  278. package/types/extractor/createExtractor.d.ts.map +0 -1
  279. package/types/extractor/createLogger.d.ts +0 -3
  280. package/types/extractor/createLogger.d.ts.map +0 -1
  281. package/types/extractor/ensureImportingConcat.d.ts +0 -4
  282. package/types/extractor/ensureImportingConcat.d.ts.map +0 -1
  283. package/types/extractor/errors.d.ts +0 -3
  284. package/types/extractor/errors.d.ts.map +0 -1
  285. package/types/extractor/evaluateAstNode.d.ts +0 -3
  286. package/types/extractor/evaluateAstNode.d.ts.map +0 -1
  287. package/types/extractor/extractHelpers.d.ts +0 -28
  288. package/types/extractor/extractHelpers.d.ts.map +0 -1
  289. package/types/extractor/extractMediaStyle.d.ts +0 -11
  290. package/types/extractor/extractMediaStyle.d.ts.map +0 -1
  291. package/types/extractor/extractToClassNames.d.ts +0 -25
  292. package/types/extractor/extractToClassNames.d.ts.map +0 -1
  293. package/types/extractor/extractToNative.d.ts +0 -13
  294. package/types/extractor/extractToNative.d.ts.map +0 -1
  295. package/types/extractor/findTopmostFunction.d.ts +0 -4
  296. package/types/extractor/findTopmostFunction.d.ts.map +0 -1
  297. package/types/extractor/generatedUid.d.ts +0 -5
  298. package/types/extractor/generatedUid.d.ts.map +0 -1
  299. package/types/extractor/getPrefixLogs.d.ts +0 -3
  300. package/types/extractor/getPrefixLogs.d.ts.map +0 -1
  301. package/types/extractor/getPropValueFromAttributes.d.ts +0 -19
  302. package/types/extractor/getPropValueFromAttributes.d.ts.map +0 -1
  303. package/types/extractor/getSourceModule.d.ts +0 -16
  304. package/types/extractor/getSourceModule.d.ts.map +0 -1
  305. package/types/extractor/getStaticBindingsForScope.d.ts +0 -5
  306. package/types/extractor/getStaticBindingsForScope.d.ts.map +0 -1
  307. package/types/extractor/hasTopLevelAwait.d.ts +0 -2
  308. package/types/extractor/hasTopLevelAwait.d.ts.map +0 -1
  309. package/types/extractor/hoistClassNames.d.ts +0 -6
  310. package/types/extractor/hoistClassNames.d.ts.map +0 -1
  311. package/types/extractor/literalToAst.d.ts +0 -4
  312. package/types/extractor/literalToAst.d.ts.map +0 -1
  313. package/types/extractor/loadFile.d.ts +0 -1
  314. package/types/extractor/loadFile.d.ts.map +0 -1
  315. package/types/extractor/logLines.d.ts +0 -2
  316. package/types/extractor/logLines.d.ts.map +0 -1
  317. package/types/extractor/normalizeTernaries.d.ts +0 -5
  318. package/types/extractor/normalizeTernaries.d.ts.map +0 -1
  319. package/types/extractor/propsToFontFamilyCache.d.ts +0 -4
  320. package/types/extractor/propsToFontFamilyCache.d.ts.map +0 -1
  321. package/types/extractor/removeUnusedHooks.d.ts +0 -3
  322. package/types/extractor/removeUnusedHooks.d.ts.map +0 -1
  323. package/types/extractor/timer.d.ts +0 -5
  324. package/types/extractor/timer.d.ts.map +0 -1
  325. package/types/extractor/validHTMLAttributes.d.ts +0 -52
  326. package/types/extractor/validHTMLAttributes.d.ts.map +0 -1
  327. package/types/worker.d.ts +0 -46
  328. package/types/worker.d.ts.map +0 -1
  329. /package/dist/{setup.cjs → cjs/setup.cjs} +0 -0
@@ -0,0 +1,142 @@
1
+ import { createHash } from 'node:crypto'
2
+ import { mkdirSync, readFileSync, writeFileSync } from 'node:fs'
3
+ import path from 'node:path'
4
+
5
+ /**
6
+ * The cross-build CSS coordinator.
7
+ *
8
+ * A zero-runtime build owns exactly one CSS artifact. It holds the config CSS,
9
+ * the zero entry's compiler atomic CSS, every island child build's atomic CSS,
10
+ * and every theme-bridge class. `TAMAGUI_DID_OUTPUT_CSS` is derived from this
11
+ * object's completeness, never set by an author, so the JavaScript stripping
12
+ * fact and its replacement asset cannot diverge.
13
+ */
14
+ export class ZeroCSSArtifact {
15
+ #config: string | null = null
16
+ #zero = new Map<string, string>()
17
+ #islands = new Map<string, Map<string, string>>()
18
+ #bridges = new Map<string, string>()
19
+ #expectedIslands: readonly string[] = []
20
+ #cssPath: string
21
+
22
+ constructor(cssPath: string) {
23
+ this.#cssPath = cssPath
24
+ }
25
+
26
+ get cssPath() {
27
+ return this.#cssPath
28
+ }
29
+
30
+ expectIslands(ids: readonly string[]) {
31
+ this.#expectedIslands = [...ids].sort()
32
+ }
33
+
34
+ setConfigCSS(css: string) {
35
+ this.#config = css
36
+ }
37
+
38
+ setZeroModuleCSS(moduleId: string, css: string) {
39
+ if (css) this.#zero.set(moduleId, css)
40
+ else this.#zero.delete(moduleId)
41
+ }
42
+
43
+ setIslandModuleCSS(islandId: string, moduleId: string, css: string) {
44
+ let bucket = this.#islands.get(islandId)
45
+ if (!bucket) {
46
+ bucket = new Map()
47
+ this.#islands.set(islandId, bucket)
48
+ }
49
+ if (css) bucket.set(moduleId, css)
50
+ else bucket.delete(moduleId)
51
+ }
52
+
53
+ /** This island's collected rules, in deterministic module order. */
54
+ islandCSS(islandId: string): string[] {
55
+ const bucket = this.#islands.get(islandId)
56
+ if (!bucket) return []
57
+ return [...bucket.keys()].sort().map((moduleId) => bucket.get(moduleId)!)
58
+ }
59
+
60
+ /** Marks an island as compiled even when it contributed no atomic rules. */
61
+ markIslandComplete(islandId: string) {
62
+ if (!this.#islands.has(islandId)) this.#islands.set(islandId, new Map())
63
+ }
64
+
65
+ /** Collected zero-graph module CSS, for an integration that persists it. */
66
+ zeroModuleEntries(): [string, string][] {
67
+ return [...this.#zero.entries()].sort(([left], [right]) => (left < right ? -1 : 1))
68
+ }
69
+
70
+ bridgeEntries(): [string, string][] {
71
+ return [...this.#bridges.entries()].sort(([left], [right]) => (left < right ? -1 : 1))
72
+ }
73
+
74
+ setBridgeRules(bridgeId: string, css: string) {
75
+ if (css) this.#bridges.set(bridgeId, css)
76
+ else this.#bridges.delete(bridgeId)
77
+ }
78
+
79
+ clearGraphs() {
80
+ this.#zero.clear()
81
+ this.#islands.clear()
82
+ this.#bridges.clear()
83
+ }
84
+
85
+ /** The missing pieces that block deriving TAMAGUI_DID_OUTPUT_CSS. */
86
+ missing(): string[] {
87
+ const missing: string[] = []
88
+ if (this.#config === null) missing.push('config CSS')
89
+ for (const id of this.#expectedIslands) {
90
+ if (!this.#islands.has(id)) missing.push(`island ${id}`)
91
+ }
92
+ return missing
93
+ }
94
+
95
+ isComplete() {
96
+ return this.missing().length === 0
97
+ }
98
+
99
+ /** Deterministic order: config, zero atomic, island atomic, bridge classes. */
100
+ css(): string {
101
+ const parts: string[] = []
102
+ if (this.#config) parts.push(this.#config)
103
+ for (const moduleId of [...this.#zero.keys()].sort()) {
104
+ parts.push(this.#zero.get(moduleId)!)
105
+ }
106
+ for (const islandId of [...this.#islands.keys()].sort()) {
107
+ const bucket = this.#islands.get(islandId)!
108
+ for (const moduleId of [...bucket.keys()].sort()) parts.push(bucket.get(moduleId)!)
109
+ }
110
+ for (const bridgeId of [...this.#bridges.keys()].sort()) {
111
+ parts.push(this.#bridges.get(bridgeId)!)
112
+ }
113
+ return parts.join('\n')
114
+ }
115
+
116
+ hash(): string {
117
+ return createHash('sha256').update(this.css()).digest('hex').slice(0, 16)
118
+ }
119
+
120
+ /**
121
+ * Writes the artifact and returns whether the derived
122
+ * `TAMAGUI_DID_OUTPUT_CSS='1'` claim is now legal.
123
+ */
124
+ write(): { path: string; hash: string; complete: boolean; missing: string[] } {
125
+ const missing = this.missing()
126
+ const css = this.css()
127
+ mkdirSync(path.dirname(this.#cssPath), { recursive: true })
128
+ let existing: string | null = null
129
+ try {
130
+ existing = readFileSync(this.#cssPath, 'utf8')
131
+ } catch {
132
+ existing = null
133
+ }
134
+ if (existing !== css) writeFileSync(this.#cssPath, css)
135
+ return {
136
+ path: this.#cssPath,
137
+ hash: this.hash(),
138
+ complete: missing.length === 0,
139
+ missing,
140
+ }
141
+ }
142
+ }
@@ -0,0 +1,359 @@
1
+ import { ZERO_FAILURE_FOOTER, type ZeroRule } from '@tamagui/compiler-core'
2
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
3
+ import path from 'node:path'
4
+
5
+ /**
6
+ * The zero-runtime bundle gate.
7
+ *
8
+ * Reference erasure is what removes the modules; this is what proves it. A green
9
+ * build is not evidence, so every integration hands its own resolved module ids
10
+ * and importer chains to this one check and writes a machine-readable receipt.
11
+ */
12
+
13
+ export interface ZeroGraphModule {
14
+ id: string
15
+ /** Direct importers of this module inside the same graph. */
16
+ importers?: readonly string[]
17
+ }
18
+
19
+ export interface ZeroForbiddenModule {
20
+ id: string
21
+ /** Shortest importer chain from an entry to the forbidden module. */
22
+ chain: string[]
23
+ /** The package that owns the module, which is what the gate matched on. */
24
+ owner: string
25
+ }
26
+
27
+ export interface ZeroGraphReceipt {
28
+ integration: string
29
+ graph: 'zero' | 'island' | 'negative-control'
30
+ entries: string[]
31
+ moduleCount: number
32
+ tamaguiModules: string[]
33
+ forbidden: ZeroForbiddenModule[]
34
+ cssArtifact: { path: string; hash: string } | null
35
+ identity: string
36
+ gzip?: Record<string, number>
37
+ /**
38
+ * Whether this build restored its artifact from a persisted plan cache
39
+ * instead of rescanning. Only integrations that cache plans set it.
40
+ */
41
+ plansRestoredFromCache?: boolean
42
+ }
43
+
44
+ /**
45
+ * The one allowlisted Tamagui client module. Everything else owned by `tamagui`
46
+ * or an `@tamagui/*` package is forbidden in a zero entry graph.
47
+ */
48
+ const ALLOWED_ZERO_MODULE = /animated-number/
49
+
50
+ /** A module's owning package: the nearest package.json and the name in it. */
51
+ export interface OwningPackage {
52
+ name: string | null
53
+ manifest: string
54
+ }
55
+
56
+ const owningPackageCache = new Map<string, OwningPackage | null>()
57
+
58
+ /**
59
+ * The package that owns a module, read from the nearest package.json.
60
+ *
61
+ * Path matching is not enough: in this monorepo `@tamagui/web` resolves to
62
+ * `code/core/web/dist/...`, which contains no `@tamagui` path segment at all. A
63
+ * gate that greps ids would report a clean graph on a bundle that ships the
64
+ * whole runtime.
65
+ */
66
+ export function owningPackageOf(id: string): OwningPackage | null {
67
+ const clean = id.split(/[?#]/, 1)[0]!
68
+ if (!clean || clean.startsWith('\0') || !path.isAbsolute(clean)) return null
69
+ return owningPackageOfDir(path.dirname(clean))
70
+ }
71
+
72
+ /** The same walk from a directory, for the project root itself. */
73
+ export function owningPackageOfDir(from: string): OwningPackage | null {
74
+ if (!from || !path.isAbsolute(from)) return null
75
+ let dir = from
76
+ const visited: string[] = []
77
+ while (true) {
78
+ const cached = owningPackageCache.get(dir)
79
+ if (cached !== undefined) {
80
+ for (const seen of visited) owningPackageCache.set(seen, cached)
81
+ return cached
82
+ }
83
+ visited.push(dir)
84
+ const manifest = path.join(dir, 'package.json')
85
+ if (existsSync(manifest)) {
86
+ let owner: OwningPackage | null = null
87
+ try {
88
+ owner = {
89
+ name: JSON.parse(readFileSync(manifest, 'utf8')).name ?? null,
90
+ manifest,
91
+ }
92
+ } catch {
93
+ owner = { name: null, manifest }
94
+ }
95
+ for (const seen of visited) owningPackageCache.set(seen, owner)
96
+ return owner
97
+ }
98
+ const parent = path.dirname(dir)
99
+ if (parent === dir) {
100
+ for (const seen of visited) owningPackageCache.set(seen, null)
101
+ return null
102
+ }
103
+ dir = parent
104
+ }
105
+ }
106
+
107
+ /**
108
+ * `ownManifest` is the building project's own package.json.
109
+ *
110
+ * A project may legitimately name itself `tamagui` or `@tamagui/something` —
111
+ * this repo's own site and examples do — and then every one of its modules
112
+ * answers this question the same way Tamagui's do. The distinction that
113
+ * actually holds is ownership, not spelling: Tamagui reaches a build as a
114
+ * resolved dependency, so its modules are owned by a different package.json
115
+ * than the one being built. Excluding the project's own manifest keeps the gate
116
+ * a name-free rule rather than a list of names to carve out.
117
+ */
118
+ export function isTamaguiModuleId(id: string, ownManifest?: string | null): boolean {
119
+ const owner = owningPackageOf(id)
120
+ if (!owner?.name) return false
121
+ if (ownManifest && owner.manifest === ownManifest) return false
122
+ return owner.name === 'tamagui' || owner.name.startsWith('@tamagui/')
123
+ }
124
+
125
+ export function isForbiddenZeroModuleId(
126
+ id: string,
127
+ ownManifest?: string | null
128
+ ): boolean {
129
+ if (!isTamaguiModuleId(id, ownManifest)) return false
130
+ return !ALLOWED_ZERO_MODULE.test(id)
131
+ }
132
+
133
+ function shortestChain(
134
+ target: string,
135
+ entries: readonly string[],
136
+ importersOf: ReadonlyMap<string, readonly string[]>
137
+ ): string[] {
138
+ const entrySet = new Set(entries)
139
+ const seen = new Set([target])
140
+ const queue: string[][] = [[target]]
141
+ // an adapter may not expose its entry modules by the same id it uses for the
142
+ // rest of the graph, so fall back to the longest ancestor chain we can walk
143
+ let longest: string[] = [target]
144
+ while (queue.length) {
145
+ const chain = queue.shift()!
146
+ const head = chain[0]!
147
+ if (entrySet.has(head)) return chain
148
+ if (chain.length > longest.length) longest = chain
149
+ for (const importer of importersOf.get(head) ?? []) {
150
+ if (seen.has(importer)) continue
151
+ seen.add(importer)
152
+ queue.push([importer, ...chain])
153
+ }
154
+ }
155
+ return longest
156
+ }
157
+
158
+ export function checkZeroGraph(input: {
159
+ entries: readonly string[]
160
+ /** The modules that actually shipped in the emitted chunks. */
161
+ modules: readonly ZeroGraphModule[]
162
+ /**
163
+ * Importer edges for the whole resolved graph. A forbidden module's chain
164
+ * usually runs through modules that were merged into another chunk, so the
165
+ * shipped set alone cannot reconstruct it.
166
+ */
167
+ importerEdges?: ReadonlyMap<string, readonly string[]>
168
+ /**
169
+ * The project being built. Its own package.json is what
170
+ * `isTamaguiModuleId` excludes, so a project named `@tamagui/something` does
171
+ * not report every one of its own modules as a forbidden Tamagui module.
172
+ *
173
+ * It cannot be derived from the entries: webpack's entry for a Next app is
174
+ * `node_modules/next/dist/client/next.js`, which belongs to `next`.
175
+ */
176
+ root: string
177
+ }): { tamaguiModules: string[]; forbidden: ZeroForbiddenModule[] } {
178
+ const importersOf = new Map<string, readonly string[]>(input.importerEdges)
179
+ for (const module of input.modules) {
180
+ if (!importersOf.has(module.id)) importersOf.set(module.id, module.importers ?? [])
181
+ }
182
+ const ownManifest = input.root
183
+ ? (owningPackageOfDir(input.root)?.manifest ?? null)
184
+ : null
185
+ const tamaguiModules = input.modules
186
+ .map((module) => module.id)
187
+ .filter((id) => isTamaguiModuleId(id, ownManifest))
188
+ .sort()
189
+ const forbidden = tamaguiModules
190
+ .filter((id) => isForbiddenZeroModuleId(id, ownManifest))
191
+ .map((id) => ({
192
+ id,
193
+ chain: shortestChain(id, input.entries, importersOf),
194
+ owner: owningPackageOf(id)?.name ?? '',
195
+ }))
196
+ return { tamaguiModules, forbidden }
197
+ }
198
+
199
+ export function formatZeroGraphFailure(receipt: ZeroGraphReceipt): string {
200
+ const lines = [
201
+ `[tamagui zero-runtime] ${receipt.integration} zero entry graph contains ${receipt.forbidden.length} forbidden Tamagui module(s)`,
202
+ '',
203
+ ]
204
+ for (const entry of receipt.forbidden) {
205
+ // the package name is what the gate matched on, and the path often does not
206
+ // show it: `@tamagui/web` resolves to `code/core/web/dist/...` here
207
+ lines.push(entry.owner ? `${entry.id} (package ${entry.owner})` : entry.id)
208
+ lines.push(
209
+ entry.chain.length > 1
210
+ ? ` ${entry.chain.join('\n -> ')}`
211
+ : ` (this bundler exposed no importer edges for that module)`
212
+ )
213
+ }
214
+ lines.push('')
215
+ lines.push(ZERO_FAILURE_FOOTER)
216
+ return lines.join('\n')
217
+ }
218
+
219
+ export function writeZeroGraphReceipt(
220
+ outDir: string,
221
+ name: string,
222
+ receipt: ZeroGraphReceipt
223
+ ): string {
224
+ mkdirSync(outDir, { recursive: true })
225
+ const file = path.join(outDir, `${name}.graph.json`)
226
+ writeFileSync(file, `${JSON.stringify(receipt, null, 2)}\n`)
227
+ return file
228
+ }
229
+
230
+ export interface ZeroViolationSite {
231
+ file: string
232
+ line: number
233
+ column: number
234
+ rule: ZeroRule
235
+ code: string
236
+ component?: string
237
+ message: string
238
+ }
239
+
240
+ /**
241
+ * One deterministic order for every integration: normalized file path, source
242
+ * offset, rule, then message. A build that reports its violations in a
243
+ * different order on a different machine is not a receipt anyone can diff.
244
+ */
245
+ export function sortZeroViolations(
246
+ sites: readonly ZeroViolationSite[]
247
+ ): ZeroViolationSite[] {
248
+ return [...sites].sort(
249
+ (left, right) =>
250
+ (left.file < right.file ? -1 : left.file > right.file ? 1 : 0) ||
251
+ left.line - right.line ||
252
+ left.column - right.column ||
253
+ left.rule - right.rule ||
254
+ (left.message < right.message ? -1 : left.message > right.message ? 1 : 0)
255
+ )
256
+ }
257
+
258
+ /** The compiler collects every violation before failing. */
259
+ export function formatZeroViolations(sites: readonly ZeroViolationSite[]): string {
260
+ const sorted = sortZeroViolations(sites)
261
+ const lines = [
262
+ `[tamagui zero-runtime] build failed with ${sorted.length} violations`,
263
+ '',
264
+ ]
265
+ for (const site of sorted) {
266
+ lines.push(`Rule ${site.rule} ${site.code}`)
267
+ lines.push(
268
+ `${site.file}:${site.line}:${site.column}${site.component ? ` ${site.component}` : ''}`
269
+ )
270
+ lines.push(` ${site.message}`)
271
+ lines.push('')
272
+ }
273
+ lines.push(ZERO_FAILURE_FOOTER)
274
+ return lines.join('\n')
275
+ }
276
+
277
+ /**
278
+ * The machine-readable half of the same list. `report` mode writes it and exits
279
+ * successfully; `enforce` writes it and then fails, so the two are comparable.
280
+ */
281
+ export function writeZeroViolationReport(
282
+ outDir: string,
283
+ name: string,
284
+ report: {
285
+ integration: string
286
+ mode: 'report' | 'enforce'
287
+ violations: readonly ZeroViolationSite[]
288
+ }
289
+ ): string {
290
+ mkdirSync(outDir, { recursive: true })
291
+ const file = path.join(outDir, `${name}.violations.json`)
292
+ writeFileSync(
293
+ file,
294
+ `${JSON.stringify(
295
+ {
296
+ integration: report.integration,
297
+ mode: report.mode,
298
+ count: report.violations.length,
299
+ violations: sortZeroViolations(report.violations),
300
+ },
301
+ null,
302
+ 2
303
+ )}\n`
304
+ )
305
+ return file
306
+ }
307
+
308
+ /**
309
+ * An exported `styled()` declarator is only erasable because every importer in
310
+ * this entry graph was itself transformed, and therefore lowered its uses. That
311
+ * is a build-wide fact, so it is checked once here rather than guessed per
312
+ * module.
313
+ */
314
+ export function erasedExportEscape(input: {
315
+ integration: string
316
+ /** Module ids the zero transform actually ran on. */
317
+ transformed: ReadonlySet<string>
318
+ /** Erased exported binding names, by the module that declared them. */
319
+ erasedExports: ReadonlyMap<string, readonly string[]>
320
+ importersOf: ReadonlyMap<string, readonly string[]>
321
+ }): string | null {
322
+ for (const [moduleId, names] of input.erasedExports) {
323
+ if (names.length === 0) continue
324
+ // An empty importer set here would mean the graph query saw nothing, which
325
+ // is not the same as seeing no importers: this module is in the graph, so
326
+ // its own entry must be there too.
327
+ if (!input.importersOf.has(moduleId)) {
328
+ return `[tamagui zero-runtime] ${input.integration} erased the exported definition(s) ${names.join(
329
+ ', '
330
+ )} from ${moduleId}, and then could not find that module in its own graph, so nothing proved the erasure was safe.\n\n${ZERO_FAILURE_FOOTER}`
331
+ }
332
+ const untransformed = (input.importersOf.get(moduleId) ?? []).filter(
333
+ (importer) => !input.transformed.has(importer)
334
+ )
335
+ if (untransformed.length === 0) continue
336
+ return `[tamagui zero-runtime] ${input.integration} erased the exported definition(s) ${names.join(
337
+ ', '
338
+ )} from ${moduleId}, but ${untransformed.length} importer(s) in this entry graph were never zero-transformed and may still reference them:\n ${untransformed.join(
339
+ '\n '
340
+ )}\n\n${ZERO_FAILURE_FOOTER}`
341
+ }
342
+ return null
343
+ }
344
+
345
+ /** UTF-16 offset to 1-based line/column, for diagnostic sites. */
346
+ export function offsetToLineColumn(
347
+ source: string,
348
+ offset: number
349
+ ): { line: number; column: number } {
350
+ let line = 1
351
+ let lineStart = 0
352
+ for (let index = 0; index < offset && index < source.length; index++) {
353
+ if (source.charCodeAt(index) === 10) {
354
+ line++
355
+ lineStart = index + 1
356
+ }
357
+ }
358
+ return { line, column: offset - lineStart + 1 }
359
+ }
@@ -0,0 +1,73 @@
1
+ import { LOWERED_MODULE_PLAN_VERSION } from '@tamagui/compiler-core'
2
+ import { createHash } from 'node:crypto'
3
+
4
+ import type { TamaguiRuntimeLiteral } from './options'
5
+
6
+ /**
7
+ * Bumped whenever the zero transform's emitted output changes shape. It rides
8
+ * the lowering plan version so a compiler change also invalidates zero caches.
9
+ */
10
+ export const ZERO_COMPILER_VERSION = `zero-1/plan-${LOWERED_MODULE_PLAN_VERSION}`
11
+
12
+ /**
13
+ * Every integration records this tuple in its cache and build identity. The CSS
14
+ * path alone is insufficient because the artifact's content can change in place.
15
+ */
16
+ export interface ZeroArtifactIdentity {
17
+ runtimeLiteral: TamaguiRuntimeLiteral
18
+ target: 'web' | 'native'
19
+ configGeneration: string
20
+ cssHash: string
21
+ compilerVersion: string
22
+ islandEntries: string[]
23
+ bridgeManifestHash: string
24
+ islandOutputHashes: Record<string, string>
25
+ }
26
+
27
+ export function hashZeroIdentity(identity: ZeroArtifactIdentity): string {
28
+ const canonical = {
29
+ runtimeLiteral: identity.runtimeLiteral,
30
+ target: identity.target,
31
+ configGeneration: identity.configGeneration,
32
+ cssHash: identity.cssHash,
33
+ compilerVersion: identity.compilerVersion,
34
+ islandEntries: [...identity.islandEntries].sort(),
35
+ bridgeManifestHash: identity.bridgeManifestHash,
36
+ islandOutputHashes: Object.fromEntries(
37
+ Object.entries(identity.islandOutputHashes).sort(([left], [right]) =>
38
+ left < right ? -1 : left > right ? 1 : 0
39
+ )
40
+ ),
41
+ }
42
+ return createHash('sha256').update(JSON.stringify(canonical)).digest('hex').slice(0, 24)
43
+ }
44
+
45
+ /**
46
+ * A key-sorted deep copy.
47
+ *
48
+ * The bridge manifest is compared and hashed across processes and across a
49
+ * persisted cache, and a round trip through JSON reorders object keys. Hashing
50
+ * insertion order makes the same manifest produce two identities depending on
51
+ * whether the build scanned or restored, which is a cache miss that looks like
52
+ * a real change.
53
+ */
54
+ export function canonicalizeBridgeManifest<T>(manifest: T): T {
55
+ if (Array.isArray(manifest)) {
56
+ return manifest.map((entry) => canonicalizeBridgeManifest(entry)) as T
57
+ }
58
+ if (manifest && typeof manifest === 'object') {
59
+ const sorted: Record<string, unknown> = {}
60
+ for (const key of Object.keys(manifest as Record<string, unknown>).sort()) {
61
+ sorted[key] = canonicalizeBridgeManifest((manifest as Record<string, unknown>)[key])
62
+ }
63
+ return sorted as T
64
+ }
65
+ return manifest
66
+ }
67
+
68
+ export function hashBridgeManifest(manifest: unknown): string {
69
+ return createHash('sha256')
70
+ .update(JSON.stringify(canonicalizeBridgeManifest(manifest)))
71
+ .digest('hex')
72
+ .slice(0, 16)
73
+ }
@@ -0,0 +1,8 @@
1
+ export * from './artifact'
2
+ export * from './graph'
3
+ export * from './identity'
4
+ export * from './islands'
5
+ export * from './options'
6
+ export * from './ownership'
7
+ export * from './theme'
8
+ export * from './transform'