@timber-js/app 0.2.0-alpha.147 → 0.2.0-alpha.148

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 (274) hide show
  1. package/dist/_chunks/{actions-OIZ8siQu.js → actions-a0RczDnB.js} +8 -34
  2. package/dist/_chunks/{actions-OIZ8siQu.js.map → actions-a0RczDnB.js.map} +1 -1
  3. package/dist/_chunks/cache-api-Co-yI-gP.js +424 -0
  4. package/dist/_chunks/cache-api-Co-yI-gP.js.map +1 -0
  5. package/dist/_chunks/{metadata-routes-BjepjefT.js → canonicalize-P41GR6tY.js} +65 -2
  6. package/dist/_chunks/canonicalize-P41GR6tY.js.map +1 -0
  7. package/dist/_chunks/{cli-schema-sync-CQaxupHv.js → cli-schema-sync-DJDdyEae.js} +111 -260
  8. package/dist/_chunks/cli-schema-sync-DJDdyEae.js.map +1 -0
  9. package/dist/_chunks/cli-schema-sync-D_IhHEUW.js +2 -0
  10. package/dist/_chunks/{define-DMVhsipD.js → define-Bssfp6ot.js} +3 -33
  11. package/dist/_chunks/define-Bssfp6ot.js.map +1 -0
  12. package/dist/_chunks/{define-C3RvHQPK.js → define-CFmvb4Bt.js} +15 -7
  13. package/dist/_chunks/define-CFmvb4Bt.js.map +1 -0
  14. package/dist/_chunks/{href-validation-DyZIzfMJ.js → href-validation-FiA_rToW.js} +2 -1
  15. package/dist/_chunks/{href-validation-DyZIzfMJ.js.map → href-validation-FiA_rToW.js.map} +1 -1
  16. package/dist/_chunks/{tracing-M_zKubhk.js → logger-CM0clugc.js} +394 -107
  17. package/dist/_chunks/logger-CM0clugc.js.map +1 -0
  18. package/dist/_chunks/navigation-root-bUDZLw74.js.map +1 -1
  19. package/dist/_chunks/plugin-context-DurqFBuY.js +2 -0
  20. package/dist/_chunks/plugin-context-GfDWsdd2.js +268 -0
  21. package/dist/_chunks/plugin-context-GfDWsdd2.js.map +1 -0
  22. package/dist/_chunks/{resolve-schema-Dj8tQloi.js → resolve-schema-3iUvBV5T.js} +3 -30
  23. package/dist/_chunks/resolve-schema-3iUvBV5T.js.map +1 -0
  24. package/dist/_chunks/{schema-bridge-DK_89h8O.js → schema-bridge-BY3QLBL7.js} +35 -2
  25. package/dist/_chunks/schema-bridge-BY3QLBL7.js.map +1 -0
  26. package/dist/_chunks/tree-match-D2l830j2.js +102 -0
  27. package/dist/_chunks/tree-match-D2l830j2.js.map +1 -0
  28. package/dist/_chunks/use-segment-params-D1CzlgBo.js.map +1 -1
  29. package/dist/_chunks/{walkers-Ck4Y45XN.js → walkers-DvWDj453.js} +107 -82
  30. package/dist/_chunks/walkers-DvWDj453.js.map +1 -0
  31. package/dist/adapters/cloudflare-kv-cache.d.ts.map +1 -1
  32. package/dist/adapters/cloudflare-kv-cache.js +36 -14
  33. package/dist/adapters/cloudflare-kv-cache.js.map +1 -1
  34. package/dist/adapters/compress-module.d.ts +5 -4
  35. package/dist/adapters/compress-module.d.ts.map +1 -1
  36. package/dist/adapters/nitro.d.ts +1 -3
  37. package/dist/adapters/nitro.d.ts.map +1 -1
  38. package/dist/adapters/nitro.js +14 -134
  39. package/dist/adapters/nitro.js.map +1 -1
  40. package/dist/cache/cache-api.d.ts.map +1 -1
  41. package/dist/cache/index.d.ts +3 -1
  42. package/dist/cache/index.d.ts.map +1 -1
  43. package/dist/cache/index.js +20 -235
  44. package/dist/cache/index.js.map +1 -1
  45. package/dist/cache/invalidation-epoch.d.ts +43 -0
  46. package/dist/cache/invalidation-epoch.d.ts.map +1 -0
  47. package/dist/cache/redis-handler.d.ts +13 -0
  48. package/dist/cache/redis-handler.d.ts.map +1 -1
  49. package/dist/cache/timber-cache.d.ts +17 -9
  50. package/dist/cache/timber-cache.d.ts.map +1 -1
  51. package/dist/cli-schema-sync.d.ts +21 -1
  52. package/dist/cli-schema-sync.d.ts.map +1 -1
  53. package/dist/cli.d.ts +12 -0
  54. package/dist/cli.d.ts.map +1 -1
  55. package/dist/cli.js +26 -31
  56. package/dist/cli.js.map +1 -1
  57. package/dist/client/browser-entry/hmr.d.ts.map +1 -1
  58. package/dist/client/browser-entry/hydrate.d.ts.map +1 -1
  59. package/dist/client/browser-entry/post-hydration.d.ts.map +1 -1
  60. package/dist/client/browser-entry/router-init.d.ts.map +1 -1
  61. package/dist/client/history.d.ts +10 -17
  62. package/dist/client/history.d.ts.map +1 -1
  63. package/dist/client/index.js +1 -1
  64. package/dist/client/index.js.map +1 -1
  65. package/dist/client/internal.js +30 -33
  66. package/dist/client/internal.js.map +1 -1
  67. package/dist/client/navigation-api.d.ts +9 -2
  68. package/dist/client/navigation-api.d.ts.map +1 -1
  69. package/dist/client/navigation-context.d.ts +0 -11
  70. package/dist/client/navigation-context.d.ts.map +1 -1
  71. package/dist/client/navigation-root.d.ts +0 -5
  72. package/dist/client/navigation-root.d.ts.map +1 -1
  73. package/dist/client/router.d.ts.map +1 -1
  74. package/dist/client/rsc-fetch.d.ts.map +1 -1
  75. package/dist/client/use-search-params.d.ts +10 -5
  76. package/dist/client/use-search-params.d.ts.map +1 -1
  77. package/dist/codec.js +1 -1
  78. package/dist/config-validation.d.ts.map +1 -1
  79. package/dist/cookies/define-cookie.d.ts.map +1 -1
  80. package/dist/cookies/index.js +2 -4
  81. package/dist/cookies/index.js.map +1 -1
  82. package/dist/dev-tools/dev-page-shell.d.ts +1 -0
  83. package/dist/dev-tools/dev-page-shell.d.ts.map +1 -1
  84. package/dist/dev-tools/hydration-overlay.d.ts +11 -0
  85. package/dist/dev-tools/hydration-overlay.d.ts.map +1 -0
  86. package/dist/dev-tools/index.d.ts +1 -2
  87. package/dist/dev-tools/index.d.ts.map +1 -1
  88. package/dist/fonts/ast-walk.d.ts +68 -0
  89. package/dist/fonts/ast-walk.d.ts.map +1 -0
  90. package/dist/fonts/ast.d.ts +23 -11
  91. package/dist/fonts/ast.d.ts.map +1 -1
  92. package/dist/fonts/bundle.d.ts +3 -1
  93. package/dist/fonts/bundle.d.ts.map +1 -1
  94. package/dist/fonts/dev-middleware.d.ts +1 -1
  95. package/dist/fonts/dev-middleware.d.ts.map +1 -1
  96. package/dist/fonts/fallbacks.d.ts +0 -7
  97. package/dist/fonts/fallbacks.d.ts.map +1 -1
  98. package/dist/fonts/google.d.ts +4 -2
  99. package/dist/fonts/google.d.ts.map +1 -1
  100. package/dist/fonts/local.d.ts +3 -3
  101. package/dist/fonts/local.d.ts.map +1 -1
  102. package/dist/fonts/paths.d.ts +43 -0
  103. package/dist/fonts/paths.d.ts.map +1 -0
  104. package/dist/fonts/pipeline.d.ts +7 -21
  105. package/dist/fonts/pipeline.d.ts.map +1 -1
  106. package/dist/fonts/transform.d.ts.map +1 -1
  107. package/dist/fonts/virtual-modules.d.ts +1 -18
  108. package/dist/fonts/virtual-modules.d.ts.map +1 -1
  109. package/dist/index.d.ts.map +1 -1
  110. package/dist/index.js +609 -406
  111. package/dist/index.js.map +1 -1
  112. package/dist/params/index.js +1 -1
  113. package/dist/params/resolve-schema.d.ts.map +1 -1
  114. package/dist/plugin-context.d.ts +28 -5
  115. package/dist/plugin-context.d.ts.map +1 -1
  116. package/dist/plugins/cache.d.ts +13 -5
  117. package/dist/plugins/cache.d.ts.map +1 -1
  118. package/dist/plugins/dev-server.d.ts.map +1 -1
  119. package/dist/plugins/fonts.d.ts +1 -2
  120. package/dist/plugins/fonts.d.ts.map +1 -1
  121. package/dist/plugins/routing.d.ts.map +1 -1
  122. package/dist/routing/codegen.d.ts.map +1 -1
  123. package/dist/routing/convention-lint.d.ts.map +1 -1
  124. package/dist/routing/file-cache.d.ts +8 -0
  125. package/dist/routing/file-cache.d.ts.map +1 -0
  126. package/dist/routing/index.js +2 -2
  127. package/dist/routing/interception.d.ts +0 -5
  128. package/dist/routing/interception.d.ts.map +1 -1
  129. package/dist/routing/manifest-codegen.d.ts +32 -0
  130. package/dist/routing/manifest-codegen.d.ts.map +1 -0
  131. package/dist/routing/scanner.d.ts.map +1 -1
  132. package/dist/schema-bridge.d.ts +15 -0
  133. package/dist/schema-bridge.d.ts.map +1 -1
  134. package/dist/search-params/define.d.ts.map +1 -1
  135. package/dist/search-params/index.js +7 -3
  136. package/dist/search-params/index.js.map +1 -1
  137. package/dist/search-params/wrappers.d.ts.map +1 -1
  138. package/dist/segment-params/define.d.ts.map +1 -1
  139. package/dist/segment-params/index.js +1 -1
  140. package/dist/server/access-gate.d.ts.map +1 -1
  141. package/dist/server/actions.d.ts +0 -14
  142. package/dist/server/actions.d.ts.map +1 -1
  143. package/dist/server/build-manifest.d.ts +0 -29
  144. package/dist/server/build-manifest.d.ts.map +1 -1
  145. package/dist/server/canonicalize.d.ts +10 -0
  146. package/dist/server/canonicalize.d.ts.map +1 -1
  147. package/dist/server/deny-renderer.d.ts +1 -1
  148. package/dist/server/deny-renderer.d.ts.map +1 -1
  149. package/dist/server/html-injector-core.d.ts +8 -0
  150. package/dist/server/html-injector-core.d.ts.map +1 -1
  151. package/dist/server/html-injectors.d.ts.map +1 -1
  152. package/dist/server/index.js +2 -2
  153. package/dist/server/internal.d.ts +1 -5
  154. package/dist/server/internal.d.ts.map +1 -1
  155. package/dist/server/internal.js +12 -171
  156. package/dist/server/internal.js.map +1 -1
  157. package/dist/server/node-stream-transforms.d.ts +0 -11
  158. package/dist/server/node-stream-transforms.d.ts.map +1 -1
  159. package/dist/server/render-utils.d.ts +25 -0
  160. package/dist/server/render-utils.d.ts.map +1 -0
  161. package/dist/server/route-element-builder.d.ts +11 -25
  162. package/dist/server/route-element-builder.d.ts.map +1 -1
  163. package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
  164. package/dist/server/rsc-entry/helpers.d.ts +2 -18
  165. package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
  166. package/dist/server/rsc-entry/index.d.ts.map +1 -1
  167. package/dist/server/rsc-entry/render-route.d.ts.map +1 -1
  168. package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
  169. package/dist/server/ssr-render.d.ts.map +1 -1
  170. package/dist/shared/href-validation.d.ts.map +1 -1
  171. package/dist/shims/image.d.ts +15 -15
  172. package/package.json +2 -2
  173. package/src/adapters/cloudflare-kv-cache.ts +56 -19
  174. package/src/adapters/compress-module.ts +27 -118
  175. package/src/adapters/nitro.ts +3 -41
  176. package/src/adapters/raw-imports.d.ts +5 -0
  177. package/src/cache/cache-api.ts +9 -1
  178. package/src/cache/index.ts +5 -2
  179. package/src/cache/invalidation-epoch.ts +93 -0
  180. package/src/cache/redis-handler.ts +33 -2
  181. package/src/cache/timber-cache.ts +109 -53
  182. package/src/cli-schema-sync.ts +123 -30
  183. package/src/cli.ts +33 -37
  184. package/src/client/browser-entry/hmr.ts +0 -11
  185. package/src/client/browser-entry/hydrate.ts +39 -5
  186. package/src/client/browser-entry/post-hydration.ts +6 -15
  187. package/src/client/browser-entry/router-init.ts +98 -3
  188. package/src/client/history.ts +10 -24
  189. package/src/client/navigation-api.ts +14 -9
  190. package/src/client/navigation-context.ts +1 -21
  191. package/src/client/navigation-root.tsx +0 -8
  192. package/src/client/router.ts +18 -8
  193. package/src/client/rsc-fetch.ts +7 -2
  194. package/src/client/use-search-params.ts +10 -5
  195. package/src/config-validation.ts +33 -25
  196. package/src/cookies/define-cookie.ts +2 -18
  197. package/src/dev-tools/dev-page-shell.ts +6 -2
  198. package/src/dev-tools/hydration-overlay.ts +158 -0
  199. package/src/dev-tools/index.ts +3 -16
  200. package/src/fonts/ast-walk.ts +235 -0
  201. package/src/fonts/ast.ts +91 -249
  202. package/src/fonts/bundle.ts +16 -9
  203. package/src/fonts/dev-middleware.ts +16 -5
  204. package/src/fonts/fallbacks.ts +0 -23
  205. package/src/fonts/google.ts +7 -3
  206. package/src/fonts/local.ts +7 -6
  207. package/src/fonts/paths.ts +58 -0
  208. package/src/fonts/pipeline.ts +27 -48
  209. package/src/fonts/transform.ts +27 -0
  210. package/src/fonts/virtual-modules.ts +1 -57
  211. package/src/index.ts +5 -11
  212. package/src/params/resolve-schema.ts +2 -34
  213. package/src/plugin-context.ts +95 -17
  214. package/src/plugins/cache.ts +64 -17
  215. package/src/plugins/dev-server.ts +61 -9
  216. package/src/plugins/fonts.ts +21 -6
  217. package/src/plugins/routing.ts +5 -348
  218. package/src/routing/codegen.ts +3 -2
  219. package/src/routing/convention-lint.ts +4 -3
  220. package/src/routing/file-cache.ts +23 -0
  221. package/src/routing/interception.ts +2 -21
  222. package/src/routing/manifest-codegen.ts +290 -0
  223. package/src/routing/scanner.ts +5 -17
  224. package/src/routing/schema-validation.ts +2 -2
  225. package/src/schema-bridge.ts +63 -2
  226. package/src/search-params/define.ts +34 -2
  227. package/src/search-params/wrappers.ts +21 -3
  228. package/src/segment-params/define.ts +2 -62
  229. package/src/server/access-gate.tsx +8 -0
  230. package/src/server/actions.ts +8 -31
  231. package/src/server/build-manifest.ts +0 -56
  232. package/src/server/canonicalize.ts +6 -3
  233. package/src/server/deny-renderer.ts +6 -0
  234. package/src/server/html-injector-core.ts +19 -0
  235. package/src/server/html-injectors.ts +14 -4
  236. package/src/server/internal.ts +1 -18
  237. package/src/server/node-stream-transforms.ts +5 -72
  238. package/src/server/render-utils.ts +31 -0
  239. package/src/server/route-element-builder.ts +77 -47
  240. package/src/server/rsc-entry/error-renderer.ts +1 -0
  241. package/src/server/rsc-entry/helpers.ts +6 -34
  242. package/src/server/rsc-entry/index.ts +11 -0
  243. package/src/server/rsc-entry/render-route.ts +7 -9
  244. package/src/server/rsc-entry/rsc-payload.ts +2 -1
  245. package/src/server/rsc-entry/ssr-renderer.ts +2 -2
  246. package/src/server/ssr-render.ts +1 -11
  247. package/src/shared/href-validation.ts +8 -0
  248. package/dist/_chunks/cli-schema-sync-CBiMEtqa.js +0 -2
  249. package/dist/_chunks/cli-schema-sync-CQaxupHv.js.map +0 -1
  250. package/dist/_chunks/define-C3RvHQPK.js.map +0 -1
  251. package/dist/_chunks/define-DMVhsipD.js.map +0 -1
  252. package/dist/_chunks/handler-store-BVDgyTh7.js +0 -78
  253. package/dist/_chunks/handler-store-BVDgyTh7.js.map +0 -1
  254. package/dist/_chunks/logger-Dt-jQaBO.js +0 -291
  255. package/dist/_chunks/logger-Dt-jQaBO.js.map +0 -1
  256. package/dist/_chunks/metadata-routes-BjepjefT.js.map +0 -1
  257. package/dist/_chunks/resolve-schema-Dj8tQloi.js.map +0 -1
  258. package/dist/_chunks/schema-bridge-DK_89h8O.js.map +0 -1
  259. package/dist/_chunks/tracing-M_zKubhk.js.map +0 -1
  260. package/dist/_chunks/walkers-Ck4Y45XN.js.map +0 -1
  261. package/dist/_chunks/warnings-CNPXaypM.js +0 -125
  262. package/dist/_chunks/warnings-CNPXaypM.js.map +0 -1
  263. package/dist/client/link-pending-store.d.ts +0 -65
  264. package/dist/client/link-pending-store.d.ts.map +0 -1
  265. package/dist/client/nav-link-store.d.ts +0 -27
  266. package/dist/client/nav-link-store.d.ts.map +0 -1
  267. package/dist/dev-tools/warnings.d.ts +0 -109
  268. package/dist/dev-tools/warnings.d.ts.map +0 -1
  269. package/dist/server/flush.d.ts +0 -74
  270. package/dist/server/flush.d.ts.map +0 -1
  271. package/src/client/link-pending-store.ts +0 -116
  272. package/src/client/nav-link-store.ts +0 -37
  273. package/src/dev-tools/warnings.ts +0 -238
  274. package/src/server/flush.ts +0 -183
@@ -0,0 +1,235 @@
1
+ /**
2
+ * Generic AST node types and recursive walkers for font static analysis.
3
+ *
4
+ * `ast.ts` owns parsing, config extraction, and call-site discovery; this
5
+ * module owns the recursive walks that police where font bindings may be
6
+ * used (dynamic configs, nested scopes, unconsumed references). Split out
7
+ * to keep `ast.ts` under the 500-code-line limit (design/18-build-system.md).
8
+ *
9
+ * Design doc: 24-fonts.md §"Step 1: Static Analysis"
10
+ */
11
+
12
+ // ── AST node types (minimal subset of estree) ────────────────────────────────
13
+
14
+ export interface AstNode {
15
+ type: string;
16
+ [key: string]: unknown;
17
+ }
18
+
19
+ export interface IdentifierNode extends AstNode {
20
+ type: 'Identifier';
21
+ name: string;
22
+ }
23
+
24
+ export interface PositionedNode extends AstNode {
25
+ start: number;
26
+ end: number;
27
+ }
28
+
29
+ /** A flagged reference/usage for build-error reporting. */
30
+ export interface FlaggedUsage {
31
+ name: string;
32
+ line: number;
33
+ column: number;
34
+ }
35
+
36
+ // ── Offset → line/column helper ──────────────────────────────────────────────
37
+
38
+ /** Convert a 0-based byte offset into a 1-based line and 0-based column. */
39
+ export function offsetToLineColumn(
40
+ source: string,
41
+ offset: number
42
+ ): { line: number; column: number } {
43
+ let line = 1;
44
+ let lastNewline = -1;
45
+ for (let i = 0; i < offset; i++) {
46
+ if (source[i] === '\n') {
47
+ line++;
48
+ lastNewline = i;
49
+ }
50
+ }
51
+ return { line, column: offset - lastNewline - 1 };
52
+ }
53
+
54
+ // ── Shared recursion plumbing ────────────────────────────────────────────────
55
+
56
+ /**
57
+ * Invoke `visit` on every direct child AST node of `node` (array elements
58
+ * and object-valued properties with a `type` field).
59
+ */
60
+ export function walkChildNodes(node: AstNode, visit: (child: AstNode) => void): void {
61
+ for (const key of Object.keys(node)) {
62
+ if (key === 'type') continue;
63
+ const child = node[key];
64
+ if (Array.isArray(child)) {
65
+ for (const item of child) {
66
+ if (item && typeof item === 'object' && (item as AstNode).type) {
67
+ visit(item as AstNode);
68
+ }
69
+ }
70
+ } else if (child && typeof child === 'object' && (child as AstNode).type) {
71
+ visit(child as AstNode);
72
+ }
73
+ }
74
+ }
75
+
76
+ // ── Walkers ──────────────────────────────────────────────────────────────────
77
+
78
+ /**
79
+ * Recursively walk the AST looking for CallExpression nodes where
80
+ * the callee is one of the imported font names and the first argument
81
+ * is not an ObjectExpression (i.e. it's dynamic).
82
+ */
83
+ export function walkForDynamicCalls(
84
+ node: AstNode,
85
+ names: ReadonlySet<string>,
86
+ source: string
87
+ ): string | null {
88
+ if (!node || typeof node !== 'object') return null;
89
+
90
+ if (node.type === 'CallExpression') {
91
+ const callee = node.callee as AstNode;
92
+ if (callee.type === 'Identifier' && names.has((callee as IdentifierNode).name)) {
93
+ const args = node.arguments as AstNode[];
94
+ if (args.length > 0 && args[0].type !== 'ObjectExpression') {
95
+ // Extract the argument source text
96
+ const argStart = (args[0] as PositionedNode).start;
97
+ const argEnd = (args[0] as PositionedNode).end;
98
+ const argText = source.slice(argStart, argEnd);
99
+ const calleeName = (callee as IdentifierNode).name;
100
+ return `${calleeName}(${argText})`;
101
+ }
102
+ }
103
+ }
104
+
105
+ let result: string | null = null;
106
+ walkChildNodes(node, (child) => {
107
+ if (!result) result = walkForDynamicCalls(child, names, source);
108
+ });
109
+ return result;
110
+ }
111
+
112
+ /**
113
+ * Node types that introduce a nested scope — any font call inside is an
114
+ * error (font calls must be module-level, same constraint as Next.js).
115
+ * Module scope so it isn't rebuilt on every recursive walk call.
116
+ */
117
+ const NESTED_SCOPE_TYPES = new Set([
118
+ 'FunctionDeclaration',
119
+ 'FunctionExpression',
120
+ 'ArrowFunctionExpression',
121
+ 'IfStatement',
122
+ 'ForStatement',
123
+ 'ForInStatement',
124
+ 'ForOfStatement',
125
+ 'WhileStatement',
126
+ 'DoWhileStatement',
127
+ 'SwitchStatement',
128
+ 'TryStatement',
129
+ 'BlockStatement',
130
+ 'ClassDeclaration',
131
+ 'ClassExpression',
132
+ ]);
133
+
134
+ /**
135
+ * Recursively walk an AST node looking for font CallExpressions in nested
136
+ * scopes (function bodies, if-blocks, loops, etc.). Font calls must be
137
+ * module-level; nested calls are collected as errors.
138
+ *
139
+ * `isNested` tracks whether we've descended past the top-level statement.
140
+ * Top-level VariableDeclarations and ExpressionStatements are already
141
+ * handled by the main loop in `findFontCallSites`, so we only flag calls
142
+ * found deeper.
143
+ */
144
+ export function walkForNestedFontCalls(
145
+ node: AstNode,
146
+ bindingNames: ReadonlyMap<string, unknown>,
147
+ source: string,
148
+ out: FlaggedUsage[],
149
+ isNested: boolean
150
+ ): void {
151
+ if (!node || typeof node !== 'object') return;
152
+
153
+ if (node.type === 'CallExpression') {
154
+ const callee = node.callee as AstNode;
155
+ if (
156
+ isNested &&
157
+ callee.type === 'Identifier' &&
158
+ bindingNames.has((callee as IdentifierNode).name)
159
+ ) {
160
+ const pos = offsetToLineColumn(source, (node as PositionedNode).start);
161
+ out.push({ name: (callee as IdentifierNode).name, line: pos.line, column: pos.column });
162
+ return; // Don't recurse into this call's children
163
+ }
164
+ }
165
+
166
+ const enterNested = isNested || NESTED_SCOPE_TYPES.has(node.type);
167
+ walkChildNodes(node, (child) =>
168
+ walkForNestedFontCalls(child, bindingNames, source, out, enterNested)
169
+ );
170
+ }
171
+
172
+ /**
173
+ * Recursively walk an AST node looking for references to font bindings
174
+ * that were not consumed by a recognized call site.
175
+ *
176
+ * Skips:
177
+ * - recognized CallExpressions (the transform rewrites them wholesale)
178
+ * - TS type-position nodes (erased at runtime)
179
+ * - non-computed member properties (`obj.Inter` doesn't reference the binding)
180
+ * - non-computed object keys (`{ Inter: 1 }` doesn't reference the binding)
181
+ * - export aliases (`export { inter as Inter }` — only `local` is a reference)
182
+ */
183
+ export function walkForUnconsumedReferences(
184
+ node: AstNode,
185
+ bindingNames: ReadonlyMap<string, unknown>,
186
+ consumedCallStarts: ReadonlySet<number>,
187
+ source: string,
188
+ out: FlaggedUsage[]
189
+ ): void {
190
+ if (!node || typeof node !== 'object') return;
191
+ if (node.type === 'ImportDeclaration' || node.type.startsWith('TS')) return;
192
+
193
+ if (node.type === 'Identifier') {
194
+ const name = (node as IdentifierNode).name;
195
+ if (bindingNames.has(name)) {
196
+ const pos = offsetToLineColumn(source, (node as PositionedNode).start);
197
+ out.push({ name, line: pos.line, column: pos.column });
198
+ }
199
+ return;
200
+ }
201
+
202
+ if (node.type === 'CallExpression' && consumedCallStarts.has((node as PositionedNode).start)) {
203
+ return; // The whole call (callee + config object) is rewritten.
204
+ }
205
+
206
+ if (node.type === 'MemberExpression' && !(node as { computed?: boolean }).computed) {
207
+ const object = (node as { object?: AstNode }).object;
208
+ if (object) {
209
+ walkForUnconsumedReferences(object, bindingNames, consumedCallStarts, source, out);
210
+ }
211
+ return;
212
+ }
213
+
214
+ if (node.type === 'Property' && !(node as { computed?: boolean }).computed) {
215
+ const value = (node as { value?: AstNode }).value;
216
+ if (value) {
217
+ walkForUnconsumedReferences(value, bindingNames, consumedCallStarts, source, out);
218
+ }
219
+ return;
220
+ }
221
+
222
+ if (node.type === 'ExportSpecifier') {
223
+ // Only `local` references a module binding. `exported` is just the
224
+ // public name — `export { inter as Inter }` must not flag `Inter`.
225
+ const local = (node as { local?: AstNode }).local;
226
+ if (local) {
227
+ walkForUnconsumedReferences(local, bindingNames, consumedCallStarts, source, out);
228
+ }
229
+ return;
230
+ }
231
+
232
+ walkChildNodes(node, (child) =>
233
+ walkForUnconsumedReferences(child, bindingNames, consumedCallStarts, source, out)
234
+ );
235
+ }