fimo 0.9.0-experimental.1 → 0.9.0

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 (205) hide show
  1. package/assets/skills/fimo/SKILL.md +17 -54
  2. package/assets/skills/fimo-cli/SKILL.md +15 -15
  3. package/assets/skills/fimo-cli/references/agent-setup.md +36 -53
  4. package/assets/skills/fimo-cli/references/agents.md +4 -4
  5. package/assets/skills/fimo-cli/references/content.md +2 -2
  6. package/assets/skills/fimo-cli/references/deploy.md +1 -1
  7. package/assets/skills/fimo-cli/references/forms.md +1 -1
  8. package/assets/skills/fimo-cli/references/init.md +16 -24
  9. package/assets/skills/fimo-cli/references/project-vars-and-secrets.md +14 -11
  10. package/assets/skills/fimo-cli/references/projects.md +1 -1
  11. package/assets/skills/fimo-cli/references/support.md +11 -9
  12. package/assets/skills/fimo-cli/references/webhooks.md +3 -1
  13. package/assets/skills/fimo-code/SKILL.md +67 -0
  14. package/assets/skills/fimo-migration/SKILL.md +2 -22
  15. package/assets/skills/fimo-migration/references/content.md +0 -24
  16. package/assets/skills/fimo-migration/references/manifest.md +0 -35
  17. package/assets/skills/fimo-migration/references/qa.md +2 -24
  18. package/assets/skills/fimo-migration/references/workflow.md +1 -12
  19. package/assets/skills/fimo-studio/references/visual-editing.md +3 -5
  20. package/assets/skills/fimo-studio/references/webhooks.md +1 -1
  21. package/dist/build/vite/plugins/translations.d.ts +8 -2
  22. package/dist/build/vite/plugins/translations.js +121 -3
  23. package/dist/cli/bundle.json +2 -2
  24. package/dist/cli/index.js +311 -1209
  25. package/dist/runtime/app/FimoProviders.d.ts +11 -1
  26. package/dist/runtime/app/FimoProviders.js +23 -2
  27. package/dist/runtime/content/client/createContentClient.js +2 -1
  28. package/dist/runtime/i18n/FimoLocaleContext.js +0 -1
  29. package/dist/runtime/primitives/lib/useFimoLiveValue.d.ts +3 -5
  30. package/dist/runtime/primitives/lib/useFimoLiveValue.js +4 -11
  31. package/dist/runtime/primitives/translations.d.ts +27 -1
  32. package/dist/runtime/primitives/translations.js +85 -7
  33. package/dist/runtime/shared/fimo-config.server.js +0 -1
  34. package/dist/runtime/shared/fimo-config.types.d.ts +0 -2
  35. package/dist/scripts/extract-translations.js +11 -16
  36. package/dist/scripts/lib/validation-report.d.ts +0 -1
  37. package/dist/scripts/lib/validation-report.js +0 -3
  38. package/dist/scripts/validate-route-metadata.js +0 -11
  39. package/package.json +4 -84
  40. package/release.json +2 -2
  41. package/scripts/postinstall.mjs +11 -65
  42. package/templates/react-router/AGENTS.md +44 -0
  43. package/templates/react-router/CLAUDE.md +5 -0
  44. package/templates/react-router/package.json +1 -1
  45. package/assets/agents-starter/AGENTS.md +0 -66
  46. package/assets/skills/fimo-migration/references/wrap.md +0 -617
  47. package/dist/runtime/astro/index.d.ts +0 -2
  48. package/dist/runtime/astro/index.js +0 -3
  49. package/dist/runtime/astro/server.d.ts +0 -3
  50. package/dist/runtime/astro/server.js +0 -6
  51. package/dist/runtime/next/FimoNextProviders.d.ts +0 -24
  52. package/dist/runtime/next/FimoNextProviders.js +0 -20
  53. package/dist/runtime/next/FimoNextScripts.d.ts +0 -10
  54. package/dist/runtime/next/FimoNextScripts.js +0 -19
  55. package/dist/runtime/next/index.d.ts +0 -14
  56. package/dist/runtime/next/index.js +0 -14
  57. package/dist/runtime/next/server.d.ts +0 -2
  58. package/dist/runtime/next/server.js +0 -4
  59. package/dist/runtime/nuxt/composables.d.ts +0 -9
  60. package/dist/runtime/nuxt/composables.js +0 -57
  61. package/dist/runtime/nuxt/index.d.ts +0 -3
  62. package/dist/runtime/nuxt/index.js +0 -6
  63. package/dist/runtime/nuxt/server.d.ts +0 -3
  64. package/dist/runtime/nuxt/server.js +0 -6
  65. package/dist/runtime/primitives/labels-hook.d.ts +0 -33
  66. package/dist/runtime/primitives/labels-hook.js +0 -41
  67. package/dist/runtime/primitives/labels-store.d.ts +0 -12
  68. package/dist/runtime/primitives/labels-store.js +0 -60
  69. package/dist/runtime/react/FimoSpaProviders.d.ts +0 -36
  70. package/dist/runtime/react/FimoSpaProviders.js +0 -63
  71. package/dist/runtime/react/index.d.ts +0 -33
  72. package/dist/runtime/react/index.js +0 -39
  73. package/dist/runtime/remix/FimoRemixProviders.d.ts +0 -16
  74. package/dist/runtime/remix/FimoRemixProviders.js +0 -12
  75. package/dist/runtime/remix/FimoRemixScripts.d.ts +0 -10
  76. package/dist/runtime/remix/FimoRemixScripts.js +0 -19
  77. package/dist/runtime/remix/index.d.ts +0 -12
  78. package/dist/runtime/remix/index.js +0 -11
  79. package/dist/runtime/remix/server.d.ts +0 -2
  80. package/dist/runtime/remix/server.js +0 -2
  81. package/dist/runtime/shared/display-routes.d.ts +0 -14
  82. package/dist/runtime/shared/display-routes.js +0 -25
  83. package/dist/runtime/shared/i18n-messages.d.ts +0 -29
  84. package/dist/runtime/shared/i18n-messages.js +0 -79
  85. package/dist/runtime/shared/labels-fetch.pure.d.ts +0 -17
  86. package/dist/runtime/shared/labels-fetch.pure.js +0 -71
  87. package/dist/runtime/shared/labels-fetch.server.d.ts +0 -7
  88. package/dist/runtime/shared/labels-fetch.server.js +0 -97
  89. package/dist/runtime/shared/labels-t.pure.d.ts +0 -2
  90. package/dist/runtime/shared/labels-t.pure.js +0 -10
  91. package/dist/runtime/strapi/client.d.ts +0 -30
  92. package/dist/runtime/strapi/client.js +0 -89
  93. package/dist/runtime/strapi/index.d.ts +0 -5
  94. package/dist/runtime/strapi/index.js +0 -6
  95. package/dist/runtime/strapi/reshape.d.ts +0 -46
  96. package/dist/runtime/strapi/reshape.js +0 -114
  97. package/dist/runtime/svelte/index.d.ts +0 -3
  98. package/dist/runtime/svelte/index.js +0 -7
  99. package/dist/runtime/svelte/server.d.ts +0 -3
  100. package/dist/runtime/svelte/server.js +0 -6
  101. package/dist/runtime/vue/index.d.ts +0 -3
  102. package/dist/runtime/vue/index.js +0 -5
  103. package/dist/runtime/vue/server.d.ts +0 -3
  104. package/dist/runtime/vue/server.js +0 -6
  105. package/dist/runtime/wrapped/FimoFileLink.d.ts +0 -17
  106. package/dist/runtime/wrapped/FimoFileLink.js +0 -19
  107. package/dist/runtime/wrapped/FimoMediaImage.d.ts +0 -14
  108. package/dist/runtime/wrapped/FimoMediaImage.js +0 -20
  109. package/dist/runtime/wrapped/FimoMediaVideo.d.ts +0 -14
  110. package/dist/runtime/wrapped/FimoMediaVideo.js +0 -20
  111. package/dist/runtime/wrapped/FimoRichTextBlock.d.ts +0 -23
  112. package/dist/runtime/wrapped/FimoRichTextBlock.js +0 -22
  113. package/dist/runtime/wrapped/FimoText.d.ts +0 -22
  114. package/dist/runtime/wrapped/FimoText.js +0 -20
  115. package/dist/runtime/wrapped/WrappedContentContext.d.ts +0 -28
  116. package/dist/runtime/wrapped/WrappedContentContext.js +0 -30
  117. package/dist/runtime/wrapped/WrappedProviders.d.ts +0 -33
  118. package/dist/runtime/wrapped/WrappedProviders.js +0 -101
  119. package/dist/runtime/wrapped/dom.d.ts +0 -4
  120. package/dist/runtime/wrapped/dom.js +0 -23
  121. package/dist/runtime/wrapped/server.d.ts +0 -77
  122. package/dist/runtime/wrapped/server.js +0 -237
  123. package/dist/scripts/apply-wrap-templates.d.ts +0 -61
  124. package/dist/scripts/apply-wrap-templates.js +0 -132
  125. package/dist/scripts/apply-wrap.d.ts +0 -46
  126. package/dist/scripts/apply-wrap.js +0 -278
  127. package/dist/scripts/cms/discover.d.ts +0 -2
  128. package/dist/scripts/cms/discover.js +0 -17
  129. package/dist/scripts/cms/example-content.d.ts +0 -33
  130. package/dist/scripts/cms/example-content.js +0 -162
  131. package/dist/scripts/cms/strapi/detect.d.ts +0 -2
  132. package/dist/scripts/cms/strapi/detect.js +0 -186
  133. package/dist/scripts/cms/strapi/index.d.ts +0 -3
  134. package/dist/scripts/cms/strapi/index.js +0 -25
  135. package/dist/scripts/cms/strapi/list-source.d.ts +0 -17
  136. package/dist/scripts/cms/strapi/list-source.js +0 -90
  137. package/dist/scripts/cms/strapi/schema-map.d.ts +0 -9
  138. package/dist/scripts/cms/strapi/schema-map.js +0 -277
  139. package/dist/scripts/cms/strapi/shapes.d.ts +0 -23
  140. package/dist/scripts/cms/strapi/shapes.js +0 -38
  141. package/dist/scripts/cms/strapi/touchpoints.d.ts +0 -31
  142. package/dist/scripts/cms/strapi/touchpoints.js +0 -145
  143. package/dist/scripts/cms/strapi/wire-client.d.ts +0 -15
  144. package/dist/scripts/cms/strapi/wire-client.js +0 -107
  145. package/dist/scripts/cms/strapi/wiring.d.ts +0 -17
  146. package/dist/scripts/cms/strapi/wiring.js +0 -46
  147. package/dist/scripts/cms/types.d.ts +0 -145
  148. package/dist/scripts/cms/types.js +0 -11
  149. package/dist/scripts/detect-framework.d.ts +0 -39
  150. package/dist/scripts/detect-framework.js +0 -133
  151. package/dist/scripts/draft-rows.d.ts +0 -19
  152. package/dist/scripts/draft-rows.js +0 -135
  153. package/dist/scripts/draft-schemas.d.ts +0 -27
  154. package/dist/scripts/draft-schemas.js +0 -188
  155. package/dist/scripts/frameworks/astro/routes.d.ts +0 -3
  156. package/dist/scripts/frameworks/astro/routes.js +0 -55
  157. package/dist/scripts/frameworks/astro/template-style.d.ts +0 -7
  158. package/dist/scripts/frameworks/astro/template-style.js +0 -19
  159. package/dist/scripts/frameworks/discover.d.ts +0 -70
  160. package/dist/scripts/frameworks/discover.js +0 -178
  161. package/dist/scripts/frameworks/next/rewire.d.ts +0 -30
  162. package/dist/scripts/frameworks/next/rewire.js +0 -258
  163. package/dist/scripts/frameworks/next/routes.d.ts +0 -17
  164. package/dist/scripts/frameworks/next/routes.js +0 -134
  165. package/dist/scripts/frameworks/next/wiring.d.ts +0 -33
  166. package/dist/scripts/frameworks/next/wiring.js +0 -186
  167. package/dist/scripts/frameworks/nuxt/routes.d.ts +0 -3
  168. package/dist/scripts/frameworks/nuxt/routes.js +0 -54
  169. package/dist/scripts/frameworks/nuxt/template-style.d.ts +0 -9
  170. package/dist/scripts/frameworks/nuxt/template-style.js +0 -27
  171. package/dist/scripts/frameworks/remix/routes.d.ts +0 -3
  172. package/dist/scripts/frameworks/remix/routes.js +0 -50
  173. package/dist/scripts/frameworks/support.d.ts +0 -75
  174. package/dist/scripts/frameworks/support.js +0 -165
  175. package/dist/scripts/frameworks/sveltekit/routes.d.ts +0 -3
  176. package/dist/scripts/frameworks/sveltekit/routes.js +0 -50
  177. package/dist/scripts/frameworks/sveltekit/template-style.d.ts +0 -9
  178. package/dist/scripts/frameworks/sveltekit/template-style.js +0 -54
  179. package/dist/scripts/frameworks/vite/routes.d.ts +0 -15
  180. package/dist/scripts/frameworks/vite/routes.js +0 -93
  181. package/dist/scripts/frameworks/vite/wiring.d.ts +0 -10
  182. package/dist/scripts/frameworks/vite/wiring.js +0 -99
  183. package/dist/scripts/i18n-namespace.d.ts +0 -27
  184. package/dist/scripts/i18n-namespace.js +0 -155
  185. package/dist/scripts/render-parity/capture.d.ts +0 -56
  186. package/dist/scripts/render-parity/capture.js +0 -366
  187. package/dist/scripts/render-parity/compare.d.ts +0 -59
  188. package/dist/scripts/render-parity/compare.js +0 -0
  189. package/dist/scripts/render-parity/normalize-html.d.ts +0 -13
  190. package/dist/scripts/render-parity/normalize-html.js +0 -223
  191. package/dist/scripts/render-parity/types.d.ts +0 -41
  192. package/dist/scripts/render-parity/types.js +0 -1
  193. package/dist/scripts/scan-wrappable.d.ts +0 -196
  194. package/dist/scripts/scan-wrappable.js +0 -1232
  195. /package/assets/skills/{fimo → fimo-code}/assets/react-router-locales/navigation.tsx +0 -0
  196. /package/assets/skills/{fimo → fimo-code}/assets/react-router-locales/routes.ts +0 -0
  197. /package/assets/skills/{fimo → fimo-code}/references/assets.md +0 -0
  198. /package/assets/skills/{fimo → fimo-code}/references/content.md +0 -0
  199. /package/assets/skills/{fimo → fimo-code}/references/design.md +0 -0
  200. /package/assets/skills/{fimo → fimo-code}/references/forms.md +0 -0
  201. /package/assets/skills/{fimo → fimo-code}/references/labels.md +0 -0
  202. /package/assets/skills/{fimo → fimo-code}/references/locales.md +0 -0
  203. /package/assets/skills/{fimo → fimo-code}/references/setup-plain-vite.md +0 -0
  204. /package/assets/skills/{fimo → fimo-code}/references/setup-react-router.md +0 -0
  205. /package/assets/skills/{fimo → fimo-code}/references/ui.md +0 -0
@@ -1,99 +0,0 @@
1
- import fs from 'node:fs';
2
- import path from 'node:path';
3
- import { parseSync } from 'oxc-parser';
4
- /**
5
- * Vite React SPA root wiring: wrap the root render argument with
6
- * `FimoSpaProviders` (client-side label fetch; inline fallbacks until it
7
- * resolves) and import the project's fimo-config.json. Only the mainstream
8
- * entry shape is touched — a `createRoot(…).render(<JSX/>)` (or legacy
9
- * `ReactDOM.render(<JSX/>, …)`) call whose first argument is a JSX element.
10
- * Anything else bails with the reason and stays agent work via the recipe.
11
- */
12
- export function ensureSpaEntryWiring(cwd) {
13
- const entryFile = ['src/main.tsx', 'src/main.jsx', 'src/index.tsx', 'src/index.jsx']
14
- .map((candidate) => path.join(cwd, candidate))
15
- .find((candidate) => fs.existsSync(candidate));
16
- const bail = (reason, rel = 'src/main.tsx') => ({
17
- changes: [],
18
- warnings: [`Root wiring not applied: ${reason} — follow the SPA recipe in the agent prompt (${rel}).`],
19
- wired: false,
20
- });
21
- if (!entryFile) {
22
- return bail('no src/main or src/index entry file found');
23
- }
24
- const rel = path.relative(cwd, entryFile);
25
- const code = fs.readFileSync(entryFile, 'utf8');
26
- if (code.includes('FimoSpaProviders')) {
27
- return { changes: [], warnings: [], wired: true };
28
- }
29
- let program;
30
- try {
31
- program = parseSync(entryFile, code).program;
32
- }
33
- catch {
34
- return bail('entry file could not be parsed', rel);
35
- }
36
- // The JSX argument of the root render call, found structurally: a call
37
- // whose callee property is `render` with a JSX element first argument
38
- // (covers `createRoot(…).render(<X/>)` and `ReactDOM.render(<X/>, node)`).
39
- const renderArg = (function find(node) {
40
- if (!node || typeof node !== 'object') {
41
- return null;
42
- }
43
- const candidate = node;
44
- if (candidate.type === 'CallExpression' &&
45
- candidate.callee?.type === 'MemberExpression' &&
46
- candidate.callee?.property?.name === 'render' &&
47
- (candidate.arguments?.[0]?.type === 'JSXElement' || candidate.arguments?.[0]?.type === 'JSXFragment')) {
48
- return candidate.arguments[0];
49
- }
50
- for (const value of Object.values(candidate)) {
51
- if (Array.isArray(value)) {
52
- for (const entry of value) {
53
- const found = find(entry);
54
- if (found) {
55
- return found;
56
- }
57
- }
58
- }
59
- else if (value && typeof value === 'object') {
60
- const found = find(value);
61
- if (found) {
62
- return found;
63
- }
64
- }
65
- }
66
- return null;
67
- })(program);
68
- if (!renderArg) {
69
- return bail('no root render call with a JSX argument found', rel);
70
- }
71
- const configImportPath = path
72
- .relative(path.dirname(entryFile), path.join(cwd, 'fimo-config.json'))
73
- .split(path.sep)
74
- .join('/');
75
- const jsx = code.slice(renderArg.start, renderArg.end);
76
- const open = '<FimoSpaProviders\n' +
77
- ' config={fimoConfig}\n' +
78
- ' apiUrl={import.meta.env.VITE_API_URL}\n' +
79
- ' previewScriptUrl={import.meta.env.DEV ? import.meta.env.VITE_FIMO_PREVIEW_SCRIPT_URL : undefined}\n' +
80
- ' >';
81
- let next = code.slice(0, renderArg.start) + `${open}\n ${jsx}\n </FimoSpaProviders>` + code.slice(renderArg.end);
82
- // AST-positioned like ensureFimoImport: a multiline import's first line is
83
- // not the end of the imports.
84
- const importBlock = `import { FimoSpaProviders } from 'fimo/react';\nimport fimoConfig from '${configImportPath.startsWith('.') ? configImportPath : `./${configImportPath}`}';`;
85
- let lastImportEnd = -1;
86
- for (const node of program.body ?? []) {
87
- if (node.type === 'ImportDeclaration') {
88
- lastImportEnd = node.end;
89
- }
90
- }
91
- // The wrap edit above only touched positions at/after renderArg.start,
92
- // which is always beyond the import block, so import spans still hold.
93
- next =
94
- lastImportEnd >= 0
95
- ? `${next.slice(0, lastImportEnd)}\n${importBlock}${next.slice(lastImportEnd)}`
96
- : `${importBlock}\n${next}`;
97
- fs.writeFileSync(entryFile, next);
98
- return { changes: [`wired FimoSpaProviders into ${rel}`], warnings: [], wired: true };
99
- }
@@ -1,27 +0,0 @@
1
- /**
2
- * Shared next-intl namespace resolution for the two independent label-key
3
- * scanners (`extract-translations` for `fimo validate`, `scan-wrappable` for
4
- * `migrate wrap --check`). Both must record the SAME key form the i18n
5
- * ingestion stores, or the seeding gate can never go green.
6
- *
7
- * `const t = useTranslations("plans.checkout")` scopes every `t("buyNow")` in
8
- * that component to `plans.checkout.buyNow`. Root-scoped `useTranslations()`
9
- * (namespace `""`) and server `getTranslations` are handled; a bare `t(...)`
10
- * with no binding (Fimo's own label call) keeps its key unchanged.
11
- */
12
- export declare const isFunctionLike: (node: any) => boolean;
13
- export declare function collectScopedBindings(fnNode: any): Map<string, string | null>;
14
- /**
15
- * Resolve a `<name>("leaf")` call to its full key given the scope stack
16
- * (innermost first).
17
- * - `scoped`: the callee is a resolved `useTranslations` binding — namespace
18
- * prepended (unless root `""`).
19
- * - `unresolvable`: the callee is a passed-in parameter — its namespace lives in
20
- * the caller and cannot be known here, so the caller should count the call as
21
- * covered but NOT demand the (bare) key.
22
- */
23
- export declare function resolveScopedKey(calleeName: string, leafKey: string, scopes: Array<Map<string, string | null>>): {
24
- key: string;
25
- scoped: boolean;
26
- unresolvable: boolean;
27
- };
@@ -1,155 +0,0 @@
1
- /**
2
- * Shared next-intl namespace resolution for the two independent label-key
3
- * scanners (`extract-translations` for `fimo validate`, `scan-wrappable` for
4
- * `migrate wrap --check`). Both must record the SAME key form the i18n
5
- * ingestion stores, or the seeding gate can never go green.
6
- *
7
- * `const t = useTranslations("plans.checkout")` scopes every `t("buyNow")` in
8
- * that component to `plans.checkout.buyNow`. Root-scoped `useTranslations()`
9
- * (namespace `""`) and server `getTranslations` are handled; a bare `t(...)`
10
- * with no binding (Fimo's own label call) keeps its key unchanged.
11
- */
12
- export const isFunctionLike = (node) => node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression';
13
- /** Collect `useTranslations`/`getTranslations` bindings declared in a function's
14
- * direct body: variable name → namespace (`""` for root scope). */
15
- const unwrapAwait = (node) => (node?.type === 'AwaitExpression' ? node.argument : node);
16
- /**
17
- * The namespace of a `useTranslations`/`getTranslations` call, or null if the
18
- * node is not such a call. Handles the string arg (`getTranslations("seo")`),
19
- * the object arg (`getTranslations({ locale, namespace: "seo" })`), and no arg
20
- * (root scope → `""`). A dynamic namespace resolves to `""` (best effort).
21
- */
22
- function translationCallNamespace(node) {
23
- if (node?.type !== 'CallExpression' || node.callee?.type !== 'Identifier') {
24
- return null;
25
- }
26
- if (node.callee.name !== 'useTranslations' && node.callee.name !== 'getTranslations') {
27
- return null;
28
- }
29
- const arg = node.arguments?.[0];
30
- if (!arg) {
31
- return '';
32
- }
33
- if (arg.type === 'Literal' && typeof arg.value === 'string') {
34
- return arg.value;
35
- }
36
- if (arg.type === 'ObjectExpression') {
37
- for (const prop of arg.properties ?? []) {
38
- const keyName = prop?.key?.name ?? prop?.key?.value;
39
- if (keyName === 'namespace' && prop.value?.type === 'Literal' && typeof prop.value.value === 'string') {
40
- return prop.value.value;
41
- }
42
- }
43
- }
44
- return '';
45
- }
46
- /** Mark every identifier bound by a parameter pattern (plain, defaulted, or
47
- * destructured — `t`, `t = x`, `{ t }`, `[t]`) as unresolvable (null). */
48
- function markParamBindings(node, bindings) {
49
- if (!node) {
50
- return;
51
- }
52
- switch (node.type) {
53
- case 'Identifier':
54
- if (!bindings.has(node.name)) {
55
- bindings.set(node.name, null);
56
- }
57
- break;
58
- case 'AssignmentPattern':
59
- markParamBindings(node.left, bindings);
60
- break;
61
- case 'RestElement':
62
- markParamBindings(node.argument, bindings);
63
- break;
64
- case 'ArrayPattern':
65
- for (const element of node.elements ?? []) {
66
- markParamBindings(element, bindings);
67
- }
68
- break;
69
- case 'ObjectPattern':
70
- for (const prop of node.properties ?? []) {
71
- markParamBindings(prop.type === 'RestElement' ? prop.argument : prop.value, bindings);
72
- }
73
- break;
74
- default:
75
- break;
76
- }
77
- }
78
- export function collectScopedBindings(fnNode) {
79
- const bindings = new Map();
80
- const body = fnNode.body;
81
- const statements = body && Array.isArray(body.body) ? body.body : [];
82
- for (const stmt of statements) {
83
- if (stmt?.type !== 'VariableDeclaration') {
84
- continue;
85
- }
86
- for (const decl of stmt.declarations ?? []) {
87
- const init = unwrapAwait(decl?.init);
88
- // `const t = [await] useTranslations/getTranslations(...)`
89
- if (decl?.id?.type === 'Identifier') {
90
- const namespace = translationCallNamespace(init);
91
- if (namespace !== null) {
92
- bindings.set(decl.id.name, namespace);
93
- }
94
- continue;
95
- }
96
- // `const [a, t] = await Promise.all([...])` or `= use(Promise.all([...]))`
97
- if (decl?.id?.type === 'ArrayPattern') {
98
- // Unwrap React's `use()` wrapper around the promise.
99
- const source = init?.type === 'CallExpression' && init.callee?.type === 'Identifier' && init.callee.name === 'use'
100
- ? unwrapAwait(init.arguments?.[0])
101
- : init;
102
- const promiseAll = source?.type === 'CallExpression' &&
103
- source.callee?.type === 'MemberExpression' &&
104
- source.callee.object?.name === 'Promise' &&
105
- source.callee.property?.name === 'all';
106
- const elements = promiseAll
107
- ? source.arguments?.[0]?.type === 'ArrayExpression'
108
- ? source.arguments[0].elements
109
- : null
110
- : source?.type === 'ArrayExpression'
111
- ? source.elements
112
- : null;
113
- if (elements) {
114
- decl.id.elements?.forEach((el, index) => {
115
- if (el?.type !== 'Identifier') {
116
- return;
117
- }
118
- const namespace = translationCallNamespace(unwrapAwait(elements[index]));
119
- if (namespace !== null) {
120
- bindings.set(el.name, namespace);
121
- }
122
- });
123
- }
124
- }
125
- }
126
- }
127
- // Function parameters are bound by the CALLER: a `t` passed in carries the
128
- // caller's namespace, unknowable here. Mark them null so their t() calls are
129
- // counted as covered but never demanded by the seeding gate as a bare leaf.
130
- for (const param of fnNode.params ?? []) {
131
- markParamBindings(param, bindings);
132
- }
133
- return bindings;
134
- }
135
- /**
136
- * Resolve a `<name>("leaf")` call to its full key given the scope stack
137
- * (innermost first).
138
- * - `scoped`: the callee is a resolved `useTranslations` binding — namespace
139
- * prepended (unless root `""`).
140
- * - `unresolvable`: the callee is a passed-in parameter — its namespace lives in
141
- * the caller and cannot be known here, so the caller should count the call as
142
- * covered but NOT demand the (bare) key.
143
- */
144
- export function resolveScopedKey(calleeName, leafKey, scopes) {
145
- for (let i = scopes.length - 1; i >= 0; i -= 1) {
146
- if (scopes[i].has(calleeName)) {
147
- const namespace = scopes[i].get(calleeName);
148
- if (namespace === null || namespace === undefined) {
149
- return { key: leafKey, scoped: false, unresolvable: true };
150
- }
151
- return { key: namespace ? `${namespace}.${leafKey}` : leafKey, scoped: true, unresolvable: false };
152
- }
153
- }
154
- return { key: leafKey, scoped: false, unresolvable: false };
155
- }
@@ -1,56 +0,0 @@
1
- import { type ParityBaseline } from './types.js';
2
- export interface CaptureOptions {
3
- cwd: string;
4
- packageManager: string;
5
- routes: Array<{
6
- path: string;
7
- }>;
8
- framework: string | null;
9
- bootTimeoutMs?: number;
10
- routeTimeoutMs?: number;
11
- /** Reuse an already-running dev server instead of booting one: the warm
12
- * server recompiles incrementally, so repeated checks cost seconds. The
13
- * server is probed once and never stopped. */
14
- serverOrigin?: string;
15
- /** Concrete values for dynamic route params so `[locale]`-style routes are
16
- * actually captured instead of skipped. A route resolves (and is captured)
17
- * only when EVERY `:param` in it has a value here; both baseline and check
18
- * read the same values, so the comparison stays symmetric. */
19
- paramValues?: Record<string, string>;
20
- onProgress?: (message: string) => void;
21
- }
22
- /** Substitute known params into a `:param` route path; returns the concrete
23
- * path, or null when a param has no value (still unresolvable → skip). */
24
- export declare function resolveRoutePath(routePath: string, paramValues: Record<string, string>): string | null;
25
- export declare class CaptureError extends Error {
26
- readonly stderrTail: string;
27
- constructor(message: string, stderrTail?: string);
28
- }
29
- export declare function findFreePort(): Promise<number>;
30
- /**
31
- * Build workspace packages the app needs BEFORE booting its dev server. Fimo
32
- * runs the app's bare `next dev`, but in a Turborepo/pnpm monorepo the
33
- * internal deps (`@repo/*`) aren't built by that — `turbo dev` would build
34
- * them first. This detects unbuilt internal deps and runs the monorepo's
35
- * build once (the root `build` script, else `turbo run build`); turbo's cache
36
- * makes an already-built repo near-instant. A build failure is surfaced with
37
- * an actionable message instead of a cryptic `Cannot find module` at boot.
38
- */
39
- export declare function ensureWorkspaceDepsBuilt(cwd: string, packageManager: string, onProgress?: (message: string) => void): void;
40
- interface DevServer {
41
- origin: string;
42
- stderrTail: () => string;
43
- stop: () => Promise<void>;
44
- }
45
- export declare function startDevServer(opts: {
46
- cwd: string;
47
- packageManager: string;
48
- bootTimeoutMs: number;
49
- }): Promise<DevServer>;
50
- /**
51
- * Boot the project's own dev server, capture every static route's normalized
52
- * signature, and tear the server down. Baseline and check both run through
53
- * this identical pipeline — that symmetry is the gate's correctness property.
54
- */
55
- export declare function captureParityBaseline(opts: CaptureOptions): Promise<ParityBaseline>;
56
- export {};