@mmapp/react-compiler 0.1.0-alpha.1 → 0.1.0-alpha.5

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 (265) hide show
  1. package/ATOM-PIPELINE.md +144 -0
  2. package/README.md +88 -40
  3. package/dist/babel/index.js +2814 -277
  4. package/dist/babel/index.mjs +2 -2
  5. package/dist/chunk-3USIFFE4.mjs +2190 -0
  6. package/dist/chunk-45YMGEVT.mjs +186 -0
  7. package/dist/chunk-4FN2AISW.mjs +148 -0
  8. package/dist/chunk-4OPI5L7G.mjs +2593 -0
  9. package/dist/chunk-4RYTKOOJ.mjs +186 -0
  10. package/dist/chunk-52XHYD2V.mjs +214 -0
  11. package/dist/chunk-5GUFFFGL.mjs +148 -0
  12. package/dist/chunk-5RKTOVR5.mjs +244 -0
  13. package/dist/chunk-5YDMOO4X.mjs +214 -0
  14. package/dist/chunk-64ZWEMLJ.mjs +148 -0
  15. package/dist/chunk-6XP4KSWQ.mjs +2190 -0
  16. package/dist/chunk-72QWL54I.mjs +175 -0
  17. package/dist/chunk-7B4TRI7C.mjs +4835 -0
  18. package/dist/chunk-7ZKGHTNB.mjs +4952 -0
  19. package/dist/chunk-CIESM3BP.mjs +33 -0
  20. package/dist/chunk-DE3ZGQAC.mjs +148 -0
  21. package/dist/chunk-DMCY3BBG.mjs +1933 -0
  22. package/dist/chunk-DPIK3PJS.mjs +244 -0
  23. package/dist/chunk-E5IVH4RE.mjs +186 -0
  24. package/dist/chunk-E6FZNUR5.mjs +4953 -0
  25. package/dist/chunk-EJRBDQDP.mjs +2607 -0
  26. package/dist/chunk-ELO4TXJL.mjs +186 -0
  27. package/dist/chunk-EO6SYNCG.mjs +175 -0
  28. package/dist/chunk-FKRO52XH.mjs +3446 -0
  29. package/dist/chunk-FL4YAKU6.mjs +4941 -0
  30. package/dist/chunk-FYT47UBU.mjs +5076 -0
  31. package/dist/chunk-GCLGPOJZ.mjs +148 -0
  32. package/dist/chunk-GXB4JOP7.mjs +5072 -0
  33. package/dist/chunk-HFXOUMTD.mjs +175 -0
  34. package/dist/chunk-HWIZ47US.mjs +214 -0
  35. package/dist/chunk-IB7MNPQL.mjs +4953 -0
  36. package/dist/chunk-ICSIHQCG.mjs +148 -0
  37. package/dist/chunk-J7JUAHS4.mjs +186 -0
  38. package/dist/chunk-JLA5VNQ3.mjs +186 -0
  39. package/dist/chunk-JQLWFCTM.mjs +214 -0
  40. package/dist/chunk-KFJJCQAL.mjs +148 -0
  41. package/dist/chunk-KJUIIEQE.mjs +186 -0
  42. package/dist/chunk-KNWTHRVQ.mjs +175 -0
  43. package/dist/chunk-KSG4XSZF.mjs +175 -0
  44. package/dist/chunk-LF5N6DOU.mjs +175 -0
  45. package/dist/chunk-LJQCM2IM.mjs +214 -0
  46. package/dist/chunk-NTB7OEX2.mjs +2918 -0
  47. package/dist/chunk-NW6555WJ.mjs +186 -0
  48. package/dist/chunk-OMZE6VLQ.mjs +214 -0
  49. package/dist/chunk-OPJKP747.mjs +7506 -0
  50. package/dist/chunk-P4BR7WVO.mjs +2190 -0
  51. package/dist/chunk-QQHVYH2X.mjs +244 -0
  52. package/dist/chunk-S5QLWLLT.mjs +186 -0
  53. package/dist/chunk-SCWGT2FY.mjs +2190 -0
  54. package/dist/chunk-SMKJUSB3.mjs +2190 -0
  55. package/dist/chunk-THFYE5ZX.mjs +244 -0
  56. package/dist/chunk-VCAY2KGM.mjs +175 -0
  57. package/dist/chunk-WBYMW4NQ.mjs +3450 -0
  58. package/dist/chunk-WECAV6QB.mjs +148 -0
  59. package/dist/chunk-WMKBXUCE.mjs +3228 -0
  60. package/dist/chunk-XAJ5BKKL.mjs +4947 -0
  61. package/dist/chunk-XG2X7AEA.mjs +175 -0
  62. package/dist/chunk-XG7Z23NQ.mjs +148 -0
  63. package/dist/chunk-XWZAOCQ7.mjs +2607 -0
  64. package/dist/chunk-Y6MA7ULW.mjs +148 -0
  65. package/dist/chunk-YMS7Q7LG.mjs +214 -0
  66. package/dist/chunk-ZA37XTGA.mjs +175 -0
  67. package/dist/cli/index.js +13189 -6838
  68. package/dist/cli/index.mjs +140 -22
  69. package/dist/codemod/cli.mjs +1 -1
  70. package/dist/codemod/index.mjs +1 -1
  71. package/dist/config-PL24KEWL.mjs +219 -0
  72. package/dist/dev-server-RmGHIntF.d.mts +113 -0
  73. package/dist/dev-server-RmGHIntF.d.ts +113 -0
  74. package/dist/dev-server.d.mts +1 -1
  75. package/dist/dev-server.d.ts +1 -1
  76. package/dist/dev-server.js +4135 -440
  77. package/dist/dev-server.mjs +5 -5
  78. package/dist/envelope.js +2812 -275
  79. package/dist/envelope.mjs +3 -3
  80. package/dist/index.d.mts +161 -2
  81. package/dist/index.d.ts +161 -2
  82. package/dist/index.js +4429 -428
  83. package/dist/index.mjs +217 -9
  84. package/{src/cli/init.ts → dist/init-7JQMAAXS.mjs} +70 -95
  85. package/dist/init-DQDX3QK6.mjs +369 -0
  86. package/dist/init-EHO4VQ22.mjs +369 -0
  87. package/dist/init-UC3FWPIW.mjs +367 -0
  88. package/dist/init-UNSMVKIK.mjs +366 -0
  89. package/dist/init-UNV5XIDE.mjs +367 -0
  90. package/dist/project-compiler-2P4N4DR7.mjs +10 -0
  91. package/dist/project-compiler-D2LCC27O.mjs +10 -0
  92. package/dist/project-compiler-EJ3GANJE.mjs +10 -0
  93. package/dist/project-compiler-LOQKVRZJ.mjs +10 -0
  94. package/dist/project-compiler-OP2VVGJQ.mjs +10 -0
  95. package/dist/project-compiler-RQ6OQKRM.mjs +10 -0
  96. package/dist/project-compiler-VWNNCHGO.mjs +10 -0
  97. package/dist/project-compiler-XVAAU4C5.mjs +10 -0
  98. package/dist/project-compiler-YES5FGMD.mjs +10 -0
  99. package/dist/project-compiler-ZKMQDLGU.mjs +10 -0
  100. package/dist/project-decompiler-FLXCEJHS.mjs +7 -0
  101. package/dist/project-decompiler-US7GAVIC.mjs +7 -0
  102. package/dist/project-decompiler-VLPR22QF.mjs +7 -0
  103. package/dist/pull-FUS5QYZS.mjs +109 -0
  104. package/dist/pull-LD5ENLGY.mjs +109 -0
  105. package/dist/pull-P44LDRWB.mjs +109 -0
  106. package/dist/testing/index.js +2822 -285
  107. package/dist/testing/index.mjs +2 -2
  108. package/dist/verify-SEIXUGN4.mjs +1833 -0
  109. package/dist/vite/index.js +2815 -278
  110. package/dist/vite/index.mjs +3 -3
  111. package/examples/uber-app/app/admin/fleet.tsx +19 -19
  112. package/package.json +16 -6
  113. package/compile-blueprint-chat.mjs +0 -99
  114. package/compile-blueprint-glass-console.mjs +0 -98
  115. package/compile-chat-defs.mjs +0 -92
  116. package/examples/uber-app/tests/payment.test.tsx +0 -129
  117. package/examples/uber-app/tests/ride-flow.test.tsx +0 -123
  118. package/package.json.backup +0 -86
  119. package/scripts/decompile.ts +0 -226
  120. package/scripts/seed-auth.ts +0 -267
  121. package/scripts/seed-uber.ts +0 -248
  122. package/scripts/validate-uber.ts +0 -119
  123. package/seed-blueprint-chat.mjs +0 -444
  124. package/seed-blueprint-glass-console.mjs +0 -445
  125. package/seed-compiled.mjs +0 -318
  126. package/src/RoundTripValidator.ts +0 -400
  127. package/src/__tests__/atom-rendering-coverage.test.ts +0 -680
  128. package/src/__tests__/auth-module-compilation.test.ts +0 -247
  129. package/src/__tests__/auth-template-compilation.test.ts +0 -589
  130. package/src/__tests__/change-extractor.test.ts +0 -142
  131. package/src/__tests__/cli-pull.test.ts +0 -73
  132. package/src/__tests__/cli-test.test.ts +0 -72
  133. package/src/__tests__/component-extractor.test.ts +0 -331
  134. package/src/__tests__/context-extractor.test.ts +0 -145
  135. package/src/__tests__/decompiler.test.ts +0 -718
  136. package/src/__tests__/define-blueprint.test.ts +0 -133
  137. package/src/__tests__/definition-validator.test.ts +0 -519
  138. package/src/__tests__/during-extractor.test.ts +0 -152
  139. package/src/__tests__/effect-extractor.test.ts +0 -107
  140. package/src/__tests__/event-emission.test.ts +0 -127
  141. package/src/__tests__/examples.test.ts +0 -236
  142. package/src/__tests__/full-blueprint-coverage.test.ts +0 -1221
  143. package/src/__tests__/golden-suite.test.ts +0 -403
  144. package/src/__tests__/grammar-island-extractor.test.ts +0 -289
  145. package/src/__tests__/instance-key.test.ts +0 -82
  146. package/src/__tests__/ir-migration.test.ts +0 -255
  147. package/src/__tests__/lock-file.test.ts +0 -117
  148. package/src/__tests__/model-extractor.test.ts +0 -195
  149. package/src/__tests__/model-field-acl.test.ts +0 -237
  150. package/src/__tests__/model-hooks.test.ts +0 -130
  151. package/src/__tests__/model-ref-resolution.test.ts +0 -268
  152. package/src/__tests__/model-roundtrip.test.ts +0 -502
  153. package/src/__tests__/model-runtime.test.ts +0 -112
  154. package/src/__tests__/model-transitions.test.ts +0 -183
  155. package/src/__tests__/nrt-action-trace.test.ts +0 -391
  156. package/src/__tests__/pipeline-hardening.test.ts +0 -413
  157. package/src/__tests__/project-compiler.test.ts +0 -546
  158. package/src/__tests__/project-decompiler.test.ts +0 -343
  159. package/src/__tests__/query-compilation.test.ts +0 -145
  160. package/src/__tests__/round-trip/PLAN.md +0 -158
  161. package/src/__tests__/round-trip/README.md +0 -52
  162. package/src/__tests__/round-trip/RESULTS.md +0 -86
  163. package/src/__tests__/round-trip/fixtures/data-heavy/main.workflow.tsx +0 -55
  164. package/src/__tests__/round-trip/fixtures/data-heavy/mm.config.ts +0 -11
  165. package/src/__tests__/round-trip/fixtures/data-heavy/models/contact.ts +0 -54
  166. package/src/__tests__/round-trip/fixtures/full-workflow/main.workflow.tsx +0 -79
  167. package/src/__tests__/round-trip/fixtures/full-workflow/mm.config.ts +0 -12
  168. package/src/__tests__/round-trip/fixtures/full-workflow/models/order.ts +0 -50
  169. package/src/__tests__/round-trip/fixtures/simple-crud/main.workflow.tsx +0 -25
  170. package/src/__tests__/round-trip/fixtures/simple-crud/mm.config.ts +0 -11
  171. package/src/__tests__/round-trip/fixtures/simple-crud/models/task.ts +0 -32
  172. package/src/__tests__/round-trip/fixtures/view-heavy/main.workflow.tsx +0 -79
  173. package/src/__tests__/round-trip/fixtures/view-heavy/mm.config.ts +0 -10
  174. package/src/__tests__/round-trip/round-trip.test.ts +0 -2598
  175. package/src/__tests__/round-trip-ir.test.ts +0 -300
  176. package/src/__tests__/round-trip.test.ts +0 -1212
  177. package/src/__tests__/route-merging.test.ts +0 -372
  178. package/src/__tests__/router-composition.test.ts +0 -489
  179. package/src/__tests__/router-extractor.test.ts +0 -176
  180. package/src/__tests__/server-action-extractor.test.ts +0 -128
  181. package/src/__tests__/smart-type-inference.test.ts +0 -365
  182. package/src/__tests__/source-envelope.test.ts +0 -284
  183. package/src/__tests__/source-fidelity.test.ts +0 -516
  184. package/src/__tests__/state-extractor.test.ts +0 -115
  185. package/src/__tests__/strict-mode.test.ts +0 -227
  186. package/src/__tests__/transition-effect-extractor.test.ts +0 -119
  187. package/src/__tests__/transition-extractor.test.ts +0 -68
  188. package/src/__tests__/ts-to-expression.test.ts +0 -462
  189. package/src/__tests__/type-generator.test.ts +0 -201
  190. package/src/__tests__/uber-validation.test.ts +0 -502
  191. package/src/action-compiler.ts +0 -361
  192. package/src/babel/emitters/experience-transform.ts +0 -199
  193. package/src/babel/emitters/ir-to-tsx-emitter.ts +0 -110
  194. package/src/babel/emitters/pure-form-emitter.ts +0 -1023
  195. package/src/babel/emitters/runtime-glue-emitter.ts +0 -39
  196. package/src/babel/extractors/change-extractor.ts +0 -199
  197. package/src/babel/extractors/component-extractor.ts +0 -907
  198. package/src/babel/extractors/computed-extractor.ts +0 -262
  199. package/src/babel/extractors/context-extractor.ts +0 -277
  200. package/src/babel/extractors/during-extractor.ts +0 -295
  201. package/src/babel/extractors/effect-extractor.ts +0 -340
  202. package/src/babel/extractors/event-extractor.ts +0 -235
  203. package/src/babel/extractors/grammar-island-extractor.ts +0 -302
  204. package/src/babel/extractors/model-extractor.ts +0 -1018
  205. package/src/babel/extractors/router-extractor.ts +0 -303
  206. package/src/babel/extractors/server-action-extractor.ts +0 -173
  207. package/src/babel/extractors/server-action-hook-extractor.ts +0 -72
  208. package/src/babel/extractors/server-state-extractor.ts +0 -88
  209. package/src/babel/extractors/state-extractor.ts +0 -214
  210. package/src/babel/extractors/transition-effect-extractor.ts +0 -176
  211. package/src/babel/extractors/transition-extractor.ts +0 -143
  212. package/src/babel/index.ts +0 -24
  213. package/src/babel/transpilers/ts-to-expression.ts +0 -674
  214. package/src/babel/visitor.ts +0 -807
  215. package/src/cli/auth.ts +0 -255
  216. package/src/cli/build.ts +0 -288
  217. package/src/cli/deploy.ts +0 -206
  218. package/src/cli/index.ts +0 -328
  219. package/src/cli/installer.ts +0 -261
  220. package/src/cli/lock-file.ts +0 -94
  221. package/src/cli/mmrc.ts +0 -22
  222. package/src/cli/pull.ts +0 -172
  223. package/src/cli/registry-client.ts +0 -175
  224. package/src/cli/test.ts +0 -397
  225. package/src/cli/type-generator.ts +0 -243
  226. package/src/codemod/__tests__/forward.test.ts +0 -239
  227. package/src/codemod/__tests__/reverse.test.ts +0 -145
  228. package/src/codemod/__tests__/round-trip.test.ts +0 -137
  229. package/src/codemod/annotation.ts +0 -97
  230. package/src/codemod/classify.ts +0 -197
  231. package/src/codemod/cli.ts +0 -207
  232. package/src/codemod/control-flow.ts +0 -409
  233. package/src/codemod/forward.ts +0 -244
  234. package/src/codemod/import-manager.ts +0 -171
  235. package/src/codemod/index.ts +0 -120
  236. package/src/codemod/reverse.ts +0 -197
  237. package/src/codemod/rules.ts +0 -174
  238. package/src/codemod/state-transform.ts +0 -126
  239. package/src/decompiler/ast-builder.ts +0 -538
  240. package/src/decompiler/config-generator.ts +0 -151
  241. package/src/decompiler/index.ts +0 -315
  242. package/src/decompiler/project-decompiler.ts +0 -1776
  243. package/src/decompiler/project.ts +0 -862
  244. package/src/decompiler/split-strategy.ts +0 -140
  245. package/src/decompiler/state-emitter.ts +0 -1053
  246. package/src/decompiler/sx-emitter.ts +0 -318
  247. package/src/decompiler/workspace-hydrator.ts +0 -189
  248. package/src/dev-server.ts +0 -238
  249. package/src/envelope/fs-tree.ts +0 -217
  250. package/src/envelope/source-envelope.ts +0 -264
  251. package/src/envelope.ts +0 -315
  252. package/src/incremental-compiler.ts +0 -401
  253. package/src/index.ts +0 -99
  254. package/src/model-compiler.ts +0 -277
  255. package/src/project-compiler.ts +0 -1629
  256. package/src/route-extractor.ts +0 -333
  257. package/src/testing/index.ts +0 -32
  258. package/src/testing/snapshot.ts +0 -252
  259. package/src/testing/test-utils.ts +0 -226
  260. package/src/types.ts +0 -68
  261. package/src/vite/index.ts +0 -288
  262. package/test-compile.mjs +0 -142
  263. package/tsconfig.json +0 -25
  264. package/tsup.config.ts +0 -23
  265. package/vitest.config.ts +0 -9
@@ -1,807 +0,0 @@
1
- /**
2
- * Babel Visitor — main AST traversal logic for extracting workflow definitions.
3
- *
4
- * Handles all @mindmatrix/react hooks:
5
- * - useState → fields
6
- * - useOnEnter / useOnExit → state enter/exit actions
7
- * - useTransition → transitions
8
- * - useOnEvent → event subscriptions
9
- * - useWhileIn → during actions (interval while in state)
10
- * - useOnChange → field watchers
11
- * - useOnTransition → transition effects
12
- *
13
- * Supports strict/infer mode enforcement.
14
- */
15
-
16
- import type { Visitor } from '@babel/traverse';
17
- import * as t from '@babel/types';
18
- import type { CompilerState, CompilerOptions, ReactCompilerError } from '../types';
19
- import { extractStates } from './extractors/state-extractor';
20
- import { extractEffects } from './extractors/effect-extractor';
21
- import { extractTransitions } from './extractors/transition-extractor';
22
- import { extractEvents } from './extractors/event-extractor';
23
- import { extractComponents, resetNodeIdCounter, registerDerivedVar } from './extractors/component-extractor';
24
- import { extractDuring, resetDuringIdCounter } from './extractors/during-extractor';
25
- import { extractChangeWatcher, resetWatcherIdCounter } from './extractors/change-extractor';
26
- import { extractComputed } from './extractors/computed-extractor';
27
- import { extractTransitionEffect, resetTransitionEffectIdCounter } from './extractors/transition-effect-extractor';
28
- import { isModelFile, extractModelFile } from './extractors/model-extractor';
29
- import { isServerActionFile, extractServerActions } from './extractors/server-action-extractor';
30
- import { extractServerActionHook } from './extractors/server-action-hook-extractor';
31
- import { extractServerState } from './extractors/server-state-extractor';
32
- import { extractGrammarIslands } from './extractors/grammar-island-extractor';
33
- import { hasContextCreation, extractContextWorkflows } from './extractors/context-extractor';
34
- import { emitIR, emitCanonical, emitWorkflowDefinition, compilerStateToWorkflow } from './emitters/pure-form-emitter';
35
- import type { IRDataSource, IRWorkflowDataSource } from '@mindmatrix/player-core';
36
- import type { NodePath } from '@babel/traverse';
37
-
38
- /**
39
- * Extracts useQuery() calls into IRDataSource declarations.
40
- * useQuery('channel', { state: 'active' }) → IRDataSource with type 'workflow'
41
- */
42
- /**
43
- * Resolves a useQuery/useMutation slug argument.
44
- * Supports string literals ('channel') and identifier references to imported defineModel results.
45
- *
46
- * When the argument is an identifier (e.g. `useQuery(ChannelModel)`), we:
47
- * 1. Look up the import source in __modelImports
48
- * 2. Derive the slug from the import path (e.g. '../models/channel' → 'channel')
49
- * 3. Also check __modelImportSlugs for slugs resolved from actual file contents
50
- */
51
- function resolveSlugArg(args: t.Node[], state: any): string | null {
52
- if (args.length < 1) return null;
53
- const slugArg = args[0];
54
-
55
- // Direct string literal: useQuery('channel')
56
- if (t.isStringLiteral(slugArg)) return slugArg.value;
57
-
58
- // Identifier reference: useQuery(ChannelModel)
59
- // Resolve via tracked model imports
60
- if (t.isIdentifier(slugArg)) {
61
- const compilerState = state as CompilerState;
62
- const meta = compilerState.metadata as Record<string, unknown>;
63
-
64
- // Check pre-resolved slugs first (from file content analysis)
65
- const resolvedSlugs = meta.__modelImportSlugs as Record<string, string> | undefined;
66
- if (resolvedSlugs?.[slugArg.name]) return resolvedSlugs[slugArg.name];
67
-
68
- // Fall back to slug derived from import path
69
- const importSources = meta.__modelImports as Record<string, string> | undefined;
70
- if (importSources?.[slugArg.name]) {
71
- const importPath = importSources[slugArg.name];
72
- // Derive slug from the import path's filename
73
- // e.g. '../models/channel' → 'channel'
74
- // e.g. '../models/user-profile' → 'user-profile'
75
- // e.g. './models/OrderItem' → 'order-item'
76
- const filename = importPath.split('/').pop() || '';
77
- return filename
78
- .replace(/\.(ts|tsx|js|jsx)$/, '')
79
- .replace(/\.model$/, '')
80
- .replace(/([A-Z])/g, '-$1')
81
- .toLowerCase()
82
- .replace(/^-/, '');
83
- }
84
- }
85
-
86
- return null;
87
- }
88
-
89
- function extractQueryDataSource(path: NodePath<t.CallExpression>, state: any): void {
90
- const args = path.node.arguments;
91
- if (args.length < 1) return;
92
-
93
- const slug = resolveSlugArg(args, state);
94
- if (!slug) return;
95
- const compilerState = state as CompilerState;
96
-
97
- // Build data source from useQuery params
98
- const dataSource: IRWorkflowDataSource = {
99
- type: 'workflow',
100
- name: slug,
101
- slug,
102
- query: 'list',
103
- };
104
-
105
- // Extract options if provided — maps QueryParams → IRWorkflowDataSource fields
106
- if (args.length > 1 && t.isObjectExpression(args[1])) {
107
- for (const prop of args[1].properties) {
108
- if (!t.isObjectProperty(prop) || !t.isIdentifier(prop.key)) continue;
109
- const key = prop.key.name;
110
- const val = prop.value;
111
-
112
- switch (key) {
113
- case 'limit':
114
- if (t.isNumericLiteral(val)) {
115
- dataSource.pageSize = val.value;
116
- dataSource.paginated = true;
117
- }
118
- break;
119
- case 'orderBy':
120
- if (t.isStringLiteral(val)) {
121
- dataSource.sort = val.value;
122
- }
123
- break;
124
- case 'order':
125
- if (t.isStringLiteral(val) && dataSource.sort) {
126
- dataSource.sort = `${dataSource.sort}:${val.value}`;
127
- }
128
- break;
129
- case 'search':
130
- if (t.isStringLiteral(val)) {
131
- dataSource.search = val.value;
132
- }
133
- break;
134
- case 'searchFields':
135
- if (t.isArrayExpression(val)) {
136
- dataSource.searchFields = val.elements
137
- .filter((el): el is t.StringLiteral => t.isStringLiteral(el))
138
- .map(el => el.value);
139
- }
140
- break;
141
- case 'filter':
142
- if (t.isObjectExpression(val)) {
143
- const filter: Record<string, string> = {};
144
- for (const fp of val.properties) {
145
- if (t.isObjectProperty(fp) && t.isIdentifier(fp.key) && t.isStringLiteral(fp.value)) {
146
- filter[fp.key.name] = fp.value.value;
147
- }
148
- }
149
- if (Object.keys(filter).length > 0) {
150
- dataSource.filter = filter;
151
- }
152
- }
153
- break;
154
- case 'state':
155
- // Shorthand: filter by workflow state
156
- if (t.isStringLiteral(val)) {
157
- if (!dataSource.filter) dataSource.filter = {};
158
- dataSource.filter.current_state = val.value;
159
- }
160
- break;
161
- case 'groupBy':
162
- if (t.isStringLiteral(val)) {
163
- dataSource.groupBy = val.value;
164
- }
165
- break;
166
- case 'facets':
167
- if (t.isArrayExpression(val)) {
168
- dataSource.facets = val.elements
169
- .filter((el): el is t.StringLiteral => t.isStringLiteral(el))
170
- .map(el => el.value);
171
- }
172
- break;
173
- }
174
- }
175
- }
176
-
177
- // Store data sources on the metadata for later emission
178
- if (!compilerState.metadata) compilerState.metadata = {};
179
- const meta = compilerState.metadata as Record<string, unknown>;
180
- if (!meta.dataSources) meta.dataSources = [];
181
- (meta.dataSources as IRDataSource[]).push(dataSource);
182
- }
183
-
184
- /**
185
- * Extracts useMutation() calls into mutation action stubs.
186
- * useMutation('channel') → records the slug for transition/create capability
187
- */
188
- function extractMutationDataSource(path: NodePath<t.CallExpression>, state: any): void {
189
- const args = path.node.arguments;
190
- if (args.length < 1) return;
191
-
192
- const slug = resolveSlugArg(args, state);
193
- if (!slug) return;
194
- const compilerState = state as CompilerState;
195
-
196
- // Store mutation targets on metadata
197
- if (!compilerState.metadata) compilerState.metadata = {};
198
- const meta = compilerState.metadata as Record<string, unknown>;
199
- if (!meta.mutationTargets) meta.mutationTargets = [];
200
- (meta.mutationTargets as string[]).push(slug);
201
- }
202
-
203
- /**
204
- * Extracts useDuringAction({ state, action, intervalMs }) into during actions.
205
- * Alternate API for useWhileIn — config object instead of positional args.
206
- */
207
- function extractDuringAction(path: NodePath<t.CallExpression>, state: any): void {
208
- const args = path.node.arguments;
209
- if (args.length < 1 || !t.isObjectExpression(args[0])) return;
210
-
211
- const compilerState = state as CompilerState;
212
- const config = args[0];
213
-
214
- let stateName: string | undefined;
215
- let intervalMs = 1000;
216
-
217
- for (const prop of config.properties) {
218
- if (!t.isObjectProperty(prop) || !t.isIdentifier(prop.key)) continue;
219
- if (prop.key.name === 'state' && t.isStringLiteral(prop.value)) {
220
- stateName = prop.value.value;
221
- }
222
- if (prop.key.name === 'intervalMs' && t.isNumericLiteral(prop.value)) {
223
- intervalMs = prop.value.value;
224
- }
225
- }
226
-
227
- if (!stateName) return;
228
-
229
- // Ensure state exists
230
- if (!compilerState.states.has(stateName)) {
231
- compilerState.states.set(stateName, {
232
- name: stateName,
233
- type: 'REGULAR',
234
- on_enter: [],
235
- during: [],
236
- on_exit: [],
237
- });
238
- }
239
-
240
- const stateEntry = compilerState.states.get(stateName)!;
241
- if (!stateEntry.during) stateEntry.during = [];
242
-
243
- compilerState.actionCounter++;
244
- stateEntry.during.push({
245
- id: `during_${compilerState.actionCounter}`,
246
- type: 'interval',
247
- interval_ms: intervalMs,
248
- actions: [],
249
- });
250
- }
251
-
252
- /**
253
- * Extracts useRole('roleName') into metadata.roleDependencies.
254
- */
255
- function extractRoleDependency(path: NodePath<t.CallExpression>, state: any): void {
256
- const args = path.node.arguments;
257
- if (args.length < 1 || !t.isStringLiteral(args[0])) return;
258
-
259
- const compilerState = state as CompilerState;
260
- if (!compilerState.metadata) compilerState.metadata = {};
261
- const meta = compilerState.metadata as Record<string, unknown>;
262
- if (!meta.roleDependencies) meta.roleDependencies = [];
263
- const roles = meta.roleDependencies as string[];
264
- const role = args[0].value;
265
- if (!roles.includes(role)) roles.push(role);
266
- }
267
-
268
- /**
269
- * Extracts useView('slug') into metadata.viewDependencies.
270
- */
271
- function extractViewDependency(path: NodePath<t.CallExpression>, state: any): void {
272
- const args = path.node.arguments;
273
- if (args.length < 1 || !t.isStringLiteral(args[0])) return;
274
-
275
- const compilerState = state as CompilerState;
276
- if (!compilerState.metadata) compilerState.metadata = {};
277
- const meta = compilerState.metadata as Record<string, unknown>;
278
- if (!meta.viewDependencies) meta.viewDependencies = [];
279
- const views = meta.viewDependencies as string[];
280
- const slug = args[0].value;
281
- if (!views.includes(slug)) views.push(slug);
282
- }
283
-
284
- /**
285
- * Extracts useParams() into metadata.acceptsParams = true.
286
- */
287
- function extractParamsUsage(_path: NodePath<t.CallExpression>, state: any): void {
288
- const compilerState = state as CompilerState;
289
- if (!compilerState.metadata) compilerState.metadata = {};
290
- const meta = compilerState.metadata as Record<string, unknown>;
291
- meta.acceptsParams = true;
292
- }
293
-
294
- /**
295
- * Extracts useExpressionLibrary('slug') into metadata.libraryDependencies.
296
- */
297
- function extractLibraryDependency(path: NodePath<t.CallExpression>, state: any): void {
298
- const args = path.node.arguments;
299
- if (args.length < 1 || !t.isStringLiteral(args[0])) return;
300
-
301
- const compilerState = state as CompilerState;
302
- if (!compilerState.metadata) compilerState.metadata = {};
303
- const meta = compilerState.metadata as Record<string, unknown>;
304
- if (!meta.libraryDependencies) meta.libraryDependencies = [];
305
- const libs = meta.libraryDependencies as string[];
306
- const slug = args[0].value;
307
- if (!libs.includes(slug)) libs.push(slug);
308
- }
309
-
310
- /** Hooks banned in strict mode */
311
- const STRICT_BANNED_HOOKS: Record<string, string> = {
312
- useEffect: 'STRICT_USE_EFFECT',
313
- useLayoutEffect: 'STRICT_USE_LAYOUT_EFFECT',
314
- useRef: 'STRICT_USE_REF',
315
- useMemo: 'STRICT_USE_MEMO',
316
- useCallback: 'STRICT_USE_CALLBACK',
317
- };
318
-
319
- /**
320
- * Extracts metadata from JSDoc comments.
321
- * Shared between Program.enter and FunctionDeclaration.
322
- */
323
- function extractMetadataFromComments(comments: any[], metadata: CompilerState['metadata']): void {
324
- for (const comment of comments) {
325
- if (comment.type !== 'CommentBlock') continue;
326
- const lines = comment.value.split('\n');
327
- for (const line of lines) {
328
- // Match @workflow with inline key=value pairs:
329
- // @workflow slug="mm-chat-app" version="1.0.0" category="blueprint"
330
- const workflowMatch = line.match(/@workflow\s+(.+)/);
331
- if (workflowMatch) {
332
- const rest = workflowMatch[1].trim();
333
- const kvRegex = /(\w+)="([^"]+)"/g;
334
- let kvMatch;
335
- let hasKV = false;
336
- while ((kvMatch = kvRegex.exec(rest)) !== null) {
337
- hasKV = true;
338
- const [, key, val] = kvMatch;
339
- if (key === 'slug') metadata.slug = val;
340
- else if (key === 'version') metadata.version = val;
341
- else if (key === 'category') metadata.category = val;
342
- else if (key === 'description') metadata.description = val;
343
- }
344
- // Fallback: if no key=value pairs, treat whole value as slug
345
- if (!hasKV) {
346
- metadata.slug = rest;
347
- }
348
- continue;
349
- }
350
- // Match standalone @version, @category, @description tags
351
- const match = line.match(/@(\w+)\s+(.+)/);
352
- if (match) {
353
- const [, tag, value] = match;
354
- if (tag === 'version') metadata.version = value.trim();
355
- if (tag === 'category') metadata.category = value.trim();
356
- if (tag === 'description') metadata.description = value.trim();
357
- }
358
- }
359
- }
360
- }
361
-
362
- /**
363
- * Creates the Babel visitor for the plugin.
364
- */
365
- export function createVisitor(options: CompilerOptions = {}): Visitor {
366
- const mode = options.mode;
367
-
368
- return {
369
- Program: {
370
- // Initialize compiler state at program entry
371
- enter(_path, state: any) {
372
- // Reset per-file counters to prevent ID leaks across compilations
373
- resetNodeIdCounter();
374
- resetDuringIdCounter();
375
- resetWatcherIdCounter();
376
- resetTransitionEffectIdCounter();
377
-
378
- const compilerState: CompilerState = {
379
- fields: [],
380
- states: new Map(),
381
- transitions: [],
382
- events: [],
383
- actionCounter: 0,
384
- metadata: {},
385
- errors: [],
386
- warnings: [],
387
- };
388
-
389
- // Extract metadata from JSDoc comments
390
- const program = _path.node;
391
- const leadingComments = program.leadingComments || [];
392
- extractMetadataFromComments(leadingComments, compilerState.metadata);
393
-
394
- // Also check leadingComments on first body statement (Babel attaches
395
- // top-of-file comments to the first statement, not the program node)
396
- if (program.body.length > 0) {
397
- const firstStmt = program.body[0];
398
- if (firstStmt.leadingComments) {
399
- extractMetadataFromComments(firstStmt.leadingComments, compilerState.metadata);
400
- }
401
- }
402
-
403
- // Extract component name from export and check for JSDoc on function
404
- const exportDeclaration = program.body.find((node) =>
405
- t.isExportNamedDeclaration(node) || t.isExportDefaultDeclaration(node)
406
- );
407
-
408
- if (exportDeclaration) {
409
- // Check the export statement's own leading comments (JSDoc may be on the export)
410
- if (exportDeclaration.leadingComments) {
411
- extractMetadataFromComments(exportDeclaration.leadingComments, compilerState.metadata);
412
- }
413
-
414
- if (t.isExportNamedDeclaration(exportDeclaration)) {
415
- const declaration = exportDeclaration.declaration;
416
- if (t.isFunctionDeclaration(declaration)) {
417
- if (declaration.id) {
418
- compilerState.metadata.name = declaration.id.name;
419
- }
420
- if (declaration.leadingComments) {
421
- extractMetadataFromComments(declaration.leadingComments, compilerState.metadata);
422
- }
423
- }
424
- } else if (t.isExportDefaultDeclaration(exportDeclaration)) {
425
- const declaration = exportDeclaration.declaration;
426
- if (t.isFunctionDeclaration(declaration)) {
427
- if (declaration.id) {
428
- compilerState.metadata.name = declaration.id.name;
429
- }
430
- if (declaration.leadingComments) {
431
- extractMetadataFromComments(declaration.leadingComments, compilerState.metadata);
432
- }
433
- } else if (t.isIdentifier(declaration)) {
434
- compilerState.metadata.name = declaration.name;
435
- }
436
- }
437
- }
438
-
439
- // Infer slug from file name if not set by JSDoc
440
- if (!compilerState.metadata.slug && state.filename) {
441
- const fileName = state.filename.split('/').pop() || '';
442
- compilerState.metadata.slug = fileName
443
- .replace(/\.workflow\.(tsx?|jsx?)$/, '')
444
- .replace(/\.(tsx?|jsx?)$/, '')
445
- .replace(/([A-Z])/g, '-$1')
446
- .toLowerCase()
447
- .replace(/^-/, '');
448
- // Track that this was auto-derived (model extractor may override)
449
- (compilerState.metadata as any).__slugAutoFallback = true;
450
- }
451
-
452
- // Store in state for later phases
453
- Object.assign(state, compilerState);
454
-
455
- // Model file detection — extract immediately since all declarations are top-level
456
- if (isModelFile(_path, state.filename)) {
457
- extractModelFile(_path, state);
458
- // Mark as model file so CallExpression/ReturnStatement visitors can skip
459
- (state as any).__isModelFile = true;
460
- // Model files default to category 'data' (creates a data workflow definition)
461
- if (!compilerState.metadata.category) {
462
- compilerState.metadata.category = 'data';
463
- }
464
- }
465
-
466
- // Grammar island extraction — detect tagged templates (cedar, sql, cron, etc.)
467
- // Works in both model files and regular workflow files
468
- extractGrammarIslands(_path, state);
469
-
470
- // Context workflow extraction — detect createContext() calls
471
- if (hasContextCreation(_path)) {
472
- extractContextWorkflows(_path, state);
473
- }
474
-
475
- // Server action file detection — extract exported functions
476
- if (isServerActionFile(state.filename)) {
477
- extractServerActions(_path, state);
478
- (state as any).__isServerActionFile = true;
479
- }
480
- },
481
-
482
- // After all extraction, emit Pure Form JSON
483
- exit(_path, state: any) {
484
- const compilerState = state as CompilerState;
485
-
486
- // Convert to ExtractedWorkflow and emit IR, engine definition, and canonical tree
487
- const extracted = compilerStateToWorkflow(compilerState, compilerState.metadata);
488
- const ir = emitIR(extracted);
489
- const definition = emitWorkflowDefinition(extracted);
490
- const canonical = emitCanonical(extracted, state.filename);
491
-
492
- // Attach errors/warnings to IR
493
- if (compilerState.errors && compilerState.errors.length > 0) {
494
- if (!ir.metadata) ir.metadata = {};
495
- (ir.metadata as any).errors = compilerState.errors;
496
- }
497
- if (compilerState.warnings && compilerState.warnings.length > 0) {
498
- if (!ir.metadata) ir.metadata = {};
499
- (ir.metadata as any).warnings = compilerState.warnings;
500
- }
501
-
502
- // Attach all outputs to file metadata for compile script to consume
503
- if (!state.file.metadata) state.file.metadata = {};
504
- state.file.metadata.mindmatrixIR = ir;
505
- state.file.metadata.mindmatrixDefinition = definition;
506
- state.file.metadata.mindmatrixCanonical = canonical;
507
- },
508
- },
509
-
510
- // Extract metadata from function declarations with JSDoc
511
- FunctionDeclaration(path, state: any) {
512
- const comments = path.node.leadingComments || [];
513
- const compilerState = state as CompilerState;
514
- extractMetadataFromComments(comments, compilerState.metadata);
515
- },
516
-
517
- // Main hook extraction dispatcher
518
- CallExpression(path, state) {
519
- const callee = path.node.callee;
520
- if (!t.isIdentifier(callee)) return;
521
-
522
- const compilerState = state as CompilerState;
523
- const hookName = callee.name;
524
-
525
- // Strict mode enforcement — ban forbidden hooks
526
- if (mode === 'strict' && STRICT_BANNED_HOOKS[hookName]) {
527
- const error: ReactCompilerError = {
528
- code: STRICT_BANNED_HOOKS[hookName] as any,
529
- message: `${hookName}() is not allowed in strict mode. Use @mindmatrix/react effect hooks instead.`,
530
- line: path.node.loc?.start.line,
531
- column: path.node.loc?.start.column,
532
- severity: 'error',
533
- };
534
- if (!compilerState.errors) compilerState.errors = [];
535
- compilerState.errors.push(error);
536
- return;
537
- }
538
-
539
- // Infer mode: warn about useEffect (component becomes opaque)
540
- if (mode === 'infer' && hookName === 'useEffect') {
541
- const warning: ReactCompilerError = {
542
- code: 'INFER_RAW_JSX',
543
- message: `useEffect() found in infer mode — component will be treated as an opaque [raw jsx] grammar island.`,
544
- line: path.node.loc?.start.line,
545
- column: path.node.loc?.start.column,
546
- severity: 'warning',
547
- };
548
- if (!compilerState.warnings) compilerState.warnings = [];
549
- compilerState.warnings.push(warning);
550
- return;
551
- }
552
-
553
- switch (hookName) {
554
- case 'useState':
555
- extractStates(path, state);
556
- break;
557
- case 'useOnEnter':
558
- case 'useOnExit':
559
- extractEffects(path, state);
560
- break;
561
- case 'useTransition':
562
- extractTransitions(path, state);
563
- break;
564
- case 'useOnEvent':
565
- extractEvents(path, state);
566
- break;
567
- case 'useWhileIn':
568
- extractDuring(path, state);
569
- break;
570
- case 'useOnChange':
571
- extractChangeWatcher(path, state);
572
- break;
573
- case 'useComputed':
574
- extractComputed(path, state);
575
- break;
576
- case 'useOnTransition':
577
- extractTransitionEffect(path, state);
578
- break;
579
- case 'useQuery':
580
- extractQueryDataSource(path, state);
581
- break;
582
- case 'useMutation':
583
- extractMutationDataSource(path, state);
584
- break;
585
- case 'useDuringAction':
586
- // useDuringAction({ state, action, intervalMs }) → during action (alias for useWhileIn)
587
- extractDuringAction(path, state);
588
- break;
589
- case 'useRole':
590
- // useRole('admin') → records role dependency in metadata
591
- extractRoleDependency(path, state);
592
- break;
593
- case 'useView':
594
- // useView('my-view') → records view dependency in metadata
595
- extractViewDependency(path, state);
596
- break;
597
- case 'useParams':
598
- // useParams() → records that the workflow accepts invocation params
599
- extractParamsUsage(path, state);
600
- break;
601
- case 'useExpressionLibrary':
602
- // useExpressionLibrary('tax-calc') → records library dependency
603
- extractLibraryDependency(path, state);
604
- break;
605
- case 'useServerAction':
606
- // useServerAction('approve', { instanceId }) → records server action dependency
607
- extractServerActionHook(path, state);
608
- break;
609
- case 'useServerState':
610
- // useServerState(instanceId) → records SSE state subscription
611
- extractServerState(path, state);
612
- break;
613
- }
614
- },
615
-
616
- // Track imports: model imports for useQuery(modelRef) resolution + strict mode validation
617
- ImportDeclaration(path, state) {
618
- const compilerState = state as CompilerState;
619
- const source = path.node.source.value;
620
-
621
- // Track model imports: imports from paths containing /models/ or ending with .model
622
- // e.g. import ChannelModel from '../models/channel'
623
- // e.g. import { Channel } from './models/channel.model'
624
- if (source.match(/\/models\/|\.model(?:\.[tj]sx?)?$/)) {
625
- if (!compilerState.metadata) compilerState.metadata = {};
626
- const meta = compilerState.metadata as Record<string, unknown>;
627
- if (!meta.__modelImports) meta.__modelImports = {};
628
- const imports = meta.__modelImports as Record<string, string>;
629
-
630
- for (const specifier of path.node.specifiers) {
631
- if (t.isImportDefaultSpecifier(specifier) || t.isImportSpecifier(specifier)) {
632
- imports[specifier.local.name] = source;
633
- }
634
- }
635
- }
636
-
637
- // Strict mode: validate imports
638
- if (mode !== 'strict') return;
639
-
640
- // Allow @mindmatrix/* imports and react itself (for types)
641
- if (
642
- source.startsWith('@mindmatrix/') ||
643
- source === 'react' ||
644
- source.startsWith('react/') ||
645
- source.startsWith('.') ||
646
- source.startsWith('/')
647
- ) {
648
- return;
649
- }
650
-
651
- const error: ReactCompilerError = {
652
- code: 'STRICT_FORBIDDEN_IMPORT',
653
- message: `Import from '${source}' is not allowed in strict mode. Only @mindmatrix/* and relative imports are permitted.`,
654
- line: path.node.loc?.start.line,
655
- column: path.node.loc?.start.column,
656
- severity: 'error',
657
- };
658
- if (!compilerState.errors) compilerState.errors = [];
659
- compilerState.errors.push(error);
660
- },
661
-
662
- // Track derived/computed variable declarations for expression inlining.
663
- //
664
- // Three cases:
665
- // 1. `const hasContent = expr` → registerDerivedVar (inline the expression)
666
- // 2. `const users = useQuery(...)` → registerDerivedVar as $instance.{slug}
667
- // (data source results are available on $instance by their slug)
668
- // 3. `const sendMsg = useMutation(...)` → registerDerivedVar as $action.transition
669
- // (mutation results are action callbacks)
670
- // 4. `const memo = useMemo(() => expr, [])` → registerDerivedVar with body expr
671
- VariableDeclarator(path, state) {
672
- const compilerState = state as CompilerState;
673
- if (!compilerState.metadata) return;
674
-
675
- const id = path.node.id;
676
- const init = path.node.init;
677
-
678
- // Skip array destructuring (useState pattern: const [x, setX] = useState(...))
679
- if (t.isArrayPattern(id)) return;
680
- if (!t.isIdentifier(id) || !init || !t.isExpression(init)) return;
681
-
682
- // Only track declarations inside the exported component function body
683
- const parentFn = path.getFunctionParent();
684
- if (!parentFn) return;
685
- const parentNode = parentFn.parentPath;
686
- const isExportedDirectly =
687
- parentNode?.isExportDefaultDeclaration() ||
688
- parentNode?.isExportNamedDeclaration();
689
- let isExportedByName = false;
690
- if (!isExportedDirectly && parentNode?.isVariableDeclarator()) {
691
- const varId = parentNode.node.id;
692
- if (t.isIdentifier(varId)) {
693
- isExportedByName = varId.name === compilerState.metadata?.name;
694
- }
695
- }
696
- if (!isExportedDirectly && !isExportedByName) return;
697
-
698
- // Handle hook call results
699
- if (t.isCallExpression(init) && t.isIdentifier(init.callee)) {
700
- const callee = init.callee.name;
701
-
702
- // useQuery result → reference as $instance.{varName}
703
- // The data source is already extracted by extractQueryDataSource.
704
- // At runtime, the CTR makes query results available on $instance.
705
- if (callee === 'useQuery') {
706
- // Use optional member expression: $instance?.{varName}
707
- // Data sources may not be loaded yet on initial render.
708
- registerDerivedVar(id.name, t.optionalMemberExpression(
709
- t.identifier('$instance'),
710
- t.identifier(id.name),
711
- false, // computed
712
- true, // optional
713
- ));
714
- return;
715
- }
716
-
717
- // useMutation result → reference as $action.transition
718
- if (callee === 'useMutation') {
719
- registerDerivedVar(id.name, t.memberExpression(
720
- t.identifier('$action'),
721
- t.identifier('transition'),
722
- ));
723
- return;
724
- }
725
-
726
- // useServerAction result → reference as $action.serverAction
727
- if (callee === 'useServerAction') {
728
- registerDerivedVar(id.name, t.memberExpression(
729
- t.identifier('$action'),
730
- t.identifier('serverAction'),
731
- ));
732
- return;
733
- }
734
-
735
- // useServerState result → reference as $instance.serverState
736
- if (callee === 'useServerState') {
737
- registerDerivedVar(id.name, t.optionalMemberExpression(
738
- t.identifier('$instance'),
739
- t.identifier('serverState'),
740
- false,
741
- true,
742
- ));
743
- return;
744
- }
745
-
746
- // useMemo → extract the callback body expression
747
- if (callee === 'useMemo' && init.arguments.length >= 1) {
748
- const callback = init.arguments[0];
749
- if (t.isArrowFunctionExpression(callback)) {
750
- if (t.isExpression(callback.body)) {
751
- // () => expression
752
- registerDerivedVar(id.name, callback.body);
753
- } else if (t.isBlockStatement(callback.body)) {
754
- // () => { return expression; }
755
- const retStmt = callback.body.body.find(s => t.isReturnStatement(s)) as t.ReturnStatement | undefined;
756
- if (retStmt?.argument && t.isExpression(retStmt.argument)) {
757
- registerDerivedVar(id.name, retStmt.argument);
758
- }
759
- }
760
- }
761
- return;
762
- }
763
-
764
- // Skip other hooks (useState handled by extractStates, etc.)
765
- if (callee.startsWith('use')) return;
766
- }
767
-
768
- // Regular const declaration: inline the expression
769
- registerDerivedVar(id.name, init);
770
- },
771
-
772
- // Extract JSX from function component return.
773
- // Only extract from the exported component function's direct return,
774
- // not from nested callbacks (Each render functions, helper components, etc.).
775
- ReturnStatement(path, state) {
776
- if (!t.isJSXElement(path.node.argument) && !t.isJSXFragment(path.node.argument)) return;
777
-
778
- // Walk up to find the nearest enclosing function
779
- const parentFn = path.getFunctionParent();
780
- if (!parentFn) return;
781
-
782
- // Check if this function is the exported component:
783
- // export default function Foo() { ... }
784
- // export function Foo() { ... }
785
- // export default Foo (where Foo is defined as function above)
786
- const parentNode = parentFn.parentPath;
787
- const isExportedDirectly =
788
- parentNode?.isExportDefaultDeclaration() ||
789
- parentNode?.isExportNamedDeclaration();
790
-
791
- // Also handle: const Foo = () => { return <JSX/> }; export default Foo;
792
- // In this case parentFn is the arrow/function expression assigned to a variable.
793
- // We check if the variable name matches the exported identifier.
794
- let isExportedByName = false;
795
- if (!isExportedDirectly && parentNode?.isVariableDeclarator()) {
796
- const varId = parentNode.node.id;
797
- if (t.isIdentifier(varId)) {
798
- isExportedByName = varId.name === (state as CompilerState).metadata?.name;
799
- }
800
- }
801
-
802
- if (isExportedDirectly || isExportedByName) {
803
- extractComponents(path, state);
804
- }
805
- },
806
- };
807
- }