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

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 (251) hide show
  1. package/ATOM-PIPELINE.md +144 -0
  2. package/README.md +88 -40
  3. package/dist/babel/index.js +113 -6
  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-5RKTOVR5.mjs +244 -0
  11. package/dist/chunk-5YDMOO4X.mjs +214 -0
  12. package/dist/chunk-64ZWEMLJ.mjs +148 -0
  13. package/dist/chunk-6XP4KSWQ.mjs +2190 -0
  14. package/dist/chunk-72QWL54I.mjs +175 -0
  15. package/dist/chunk-7B4TRI7C.mjs +4835 -0
  16. package/dist/chunk-7ZKGHTNB.mjs +4952 -0
  17. package/dist/chunk-CIESM3BP.mjs +33 -0
  18. package/dist/chunk-DE3ZGQAC.mjs +148 -0
  19. package/dist/chunk-DMCY3BBG.mjs +1933 -0
  20. package/dist/chunk-DPIK3PJS.mjs +244 -0
  21. package/dist/chunk-E5IVH4RE.mjs +186 -0
  22. package/dist/chunk-E6FZNUR5.mjs +4953 -0
  23. package/dist/chunk-EJRBDQDP.mjs +2607 -0
  24. package/dist/chunk-ELO4TXJL.mjs +186 -0
  25. package/dist/chunk-FKRO52XH.mjs +3446 -0
  26. package/dist/chunk-FL4YAKU6.mjs +4941 -0
  27. package/dist/chunk-FYT47UBU.mjs +5076 -0
  28. package/dist/chunk-GCLGPOJZ.mjs +148 -0
  29. package/dist/chunk-GXB4JOP7.mjs +5072 -0
  30. package/dist/chunk-HFXOUMTD.mjs +175 -0
  31. package/dist/chunk-HWIZ47US.mjs +214 -0
  32. package/dist/chunk-IB7MNPQL.mjs +4953 -0
  33. package/dist/chunk-ICSIHQCG.mjs +148 -0
  34. package/dist/chunk-JLA5VNQ3.mjs +186 -0
  35. package/dist/chunk-JQLWFCTM.mjs +214 -0
  36. package/dist/chunk-KFJJCQAL.mjs +148 -0
  37. package/dist/chunk-KJUIIEQE.mjs +186 -0
  38. package/dist/chunk-KNWTHRVQ.mjs +175 -0
  39. package/dist/chunk-KSG4XSZF.mjs +175 -0
  40. package/dist/chunk-LF5N6DOU.mjs +175 -0
  41. package/dist/chunk-LJQCM2IM.mjs +214 -0
  42. package/dist/chunk-NW6555WJ.mjs +186 -0
  43. package/dist/chunk-OMZE6VLQ.mjs +214 -0
  44. package/dist/chunk-P4BR7WVO.mjs +2190 -0
  45. package/dist/chunk-QQHVYH2X.mjs +244 -0
  46. package/dist/chunk-S5QLWLLT.mjs +186 -0
  47. package/dist/chunk-SCWGT2FY.mjs +2190 -0
  48. package/dist/chunk-SMKJUSB3.mjs +2190 -0
  49. package/dist/chunk-VCAY2KGM.mjs +175 -0
  50. package/dist/chunk-WECAV6QB.mjs +148 -0
  51. package/dist/chunk-WMKBXUCE.mjs +3228 -0
  52. package/dist/chunk-XAJ5BKKL.mjs +4947 -0
  53. package/dist/chunk-XG2X7AEA.mjs +175 -0
  54. package/dist/chunk-XG7Z23NQ.mjs +148 -0
  55. package/dist/chunk-XWZAOCQ7.mjs +2607 -0
  56. package/dist/chunk-Y6MA7ULW.mjs +148 -0
  57. package/dist/chunk-YMS7Q7LG.mjs +214 -0
  58. package/dist/chunk-ZA37XTGA.mjs +175 -0
  59. package/dist/cli/index.js +1616 -366
  60. package/dist/cli/index.mjs +8 -8
  61. package/dist/codemod/cli.mjs +1 -1
  62. package/dist/codemod/index.mjs +1 -1
  63. package/dist/dev-server-RmGHIntF.d.mts +113 -0
  64. package/dist/dev-server-RmGHIntF.d.ts +113 -0
  65. package/dist/dev-server.d.mts +1 -1
  66. package/dist/dev-server.d.ts +1 -1
  67. package/dist/dev-server.js +982 -53
  68. package/dist/dev-server.mjs +5 -5
  69. package/dist/envelope.js +113 -6
  70. package/dist/envelope.mjs +3 -3
  71. package/dist/index.d.mts +5 -1
  72. package/dist/index.d.ts +5 -1
  73. package/dist/index.js +992 -63
  74. package/dist/index.mjs +8 -8
  75. package/{src/cli/init.ts → dist/init-7JQMAAXS.mjs} +70 -95
  76. package/dist/init-EHO4VQ22.mjs +369 -0
  77. package/dist/init-UC3FWPIW.mjs +367 -0
  78. package/dist/init-UNSMVKIK.mjs +366 -0
  79. package/dist/init-UNV5XIDE.mjs +367 -0
  80. package/dist/project-compiler-2P4N4DR7.mjs +10 -0
  81. package/dist/project-compiler-D2LCC27O.mjs +10 -0
  82. package/dist/project-compiler-EJ3GANJE.mjs +10 -0
  83. package/dist/project-compiler-LOQKVRZJ.mjs +10 -0
  84. package/dist/project-compiler-RQ6OQKRM.mjs +10 -0
  85. package/dist/project-compiler-VWNNCHGO.mjs +10 -0
  86. package/dist/project-compiler-XVAAU4C5.mjs +10 -0
  87. package/dist/project-compiler-YES5FGMD.mjs +10 -0
  88. package/dist/project-compiler-ZKMQDLGU.mjs +10 -0
  89. package/dist/project-decompiler-FLXCEJHS.mjs +7 -0
  90. package/dist/project-decompiler-VLPR22QF.mjs +7 -0
  91. package/dist/pull-FUS5QYZS.mjs +109 -0
  92. package/dist/pull-LD5ENLGY.mjs +109 -0
  93. package/dist/testing/index.js +113 -6
  94. package/dist/testing/index.mjs +2 -2
  95. package/dist/vite/index.js +113 -6
  96. package/dist/vite/index.mjs +3 -3
  97. package/examples/uber-app/app/admin/fleet.tsx +19 -19
  98. package/package.json +4 -3
  99. package/compile-blueprint-chat.mjs +0 -99
  100. package/compile-blueprint-glass-console.mjs +0 -98
  101. package/compile-chat-defs.mjs +0 -92
  102. package/examples/uber-app/tests/payment.test.tsx +0 -129
  103. package/examples/uber-app/tests/ride-flow.test.tsx +0 -123
  104. package/package.json.backup +0 -86
  105. package/scripts/decompile.ts +0 -226
  106. package/scripts/seed-auth.ts +0 -267
  107. package/scripts/seed-uber.ts +0 -248
  108. package/scripts/validate-uber.ts +0 -119
  109. package/seed-blueprint-chat.mjs +0 -444
  110. package/seed-blueprint-glass-console.mjs +0 -445
  111. package/seed-compiled.mjs +0 -318
  112. package/src/RoundTripValidator.ts +0 -400
  113. package/src/__tests__/atom-rendering-coverage.test.ts +0 -680
  114. package/src/__tests__/auth-module-compilation.test.ts +0 -247
  115. package/src/__tests__/auth-template-compilation.test.ts +0 -589
  116. package/src/__tests__/change-extractor.test.ts +0 -142
  117. package/src/__tests__/cli-pull.test.ts +0 -73
  118. package/src/__tests__/cli-test.test.ts +0 -72
  119. package/src/__tests__/component-extractor.test.ts +0 -331
  120. package/src/__tests__/context-extractor.test.ts +0 -145
  121. package/src/__tests__/decompiler.test.ts +0 -718
  122. package/src/__tests__/define-blueprint.test.ts +0 -133
  123. package/src/__tests__/definition-validator.test.ts +0 -519
  124. package/src/__tests__/during-extractor.test.ts +0 -152
  125. package/src/__tests__/effect-extractor.test.ts +0 -107
  126. package/src/__tests__/event-emission.test.ts +0 -127
  127. package/src/__tests__/examples.test.ts +0 -236
  128. package/src/__tests__/full-blueprint-coverage.test.ts +0 -1221
  129. package/src/__tests__/golden-suite.test.ts +0 -403
  130. package/src/__tests__/grammar-island-extractor.test.ts +0 -289
  131. package/src/__tests__/instance-key.test.ts +0 -82
  132. package/src/__tests__/ir-migration.test.ts +0 -255
  133. package/src/__tests__/lock-file.test.ts +0 -117
  134. package/src/__tests__/model-extractor.test.ts +0 -195
  135. package/src/__tests__/model-field-acl.test.ts +0 -237
  136. package/src/__tests__/model-hooks.test.ts +0 -130
  137. package/src/__tests__/model-ref-resolution.test.ts +0 -268
  138. package/src/__tests__/model-roundtrip.test.ts +0 -502
  139. package/src/__tests__/model-runtime.test.ts +0 -112
  140. package/src/__tests__/model-transitions.test.ts +0 -183
  141. package/src/__tests__/nrt-action-trace.test.ts +0 -391
  142. package/src/__tests__/pipeline-hardening.test.ts +0 -413
  143. package/src/__tests__/project-compiler.test.ts +0 -546
  144. package/src/__tests__/project-decompiler.test.ts +0 -343
  145. package/src/__tests__/query-compilation.test.ts +0 -145
  146. package/src/__tests__/round-trip/PLAN.md +0 -158
  147. package/src/__tests__/round-trip/README.md +0 -52
  148. package/src/__tests__/round-trip/RESULTS.md +0 -86
  149. package/src/__tests__/round-trip/fixtures/data-heavy/main.workflow.tsx +0 -55
  150. package/src/__tests__/round-trip/fixtures/data-heavy/mm.config.ts +0 -11
  151. package/src/__tests__/round-trip/fixtures/data-heavy/models/contact.ts +0 -54
  152. package/src/__tests__/round-trip/fixtures/full-workflow/main.workflow.tsx +0 -79
  153. package/src/__tests__/round-trip/fixtures/full-workflow/mm.config.ts +0 -12
  154. package/src/__tests__/round-trip/fixtures/full-workflow/models/order.ts +0 -50
  155. package/src/__tests__/round-trip/fixtures/simple-crud/main.workflow.tsx +0 -25
  156. package/src/__tests__/round-trip/fixtures/simple-crud/mm.config.ts +0 -11
  157. package/src/__tests__/round-trip/fixtures/simple-crud/models/task.ts +0 -32
  158. package/src/__tests__/round-trip/fixtures/view-heavy/main.workflow.tsx +0 -79
  159. package/src/__tests__/round-trip/fixtures/view-heavy/mm.config.ts +0 -10
  160. package/src/__tests__/round-trip/round-trip.test.ts +0 -2598
  161. package/src/__tests__/round-trip-ir.test.ts +0 -300
  162. package/src/__tests__/round-trip.test.ts +0 -1212
  163. package/src/__tests__/route-merging.test.ts +0 -372
  164. package/src/__tests__/router-composition.test.ts +0 -489
  165. package/src/__tests__/router-extractor.test.ts +0 -176
  166. package/src/__tests__/server-action-extractor.test.ts +0 -128
  167. package/src/__tests__/smart-type-inference.test.ts +0 -365
  168. package/src/__tests__/source-envelope.test.ts +0 -284
  169. package/src/__tests__/source-fidelity.test.ts +0 -516
  170. package/src/__tests__/state-extractor.test.ts +0 -115
  171. package/src/__tests__/strict-mode.test.ts +0 -227
  172. package/src/__tests__/transition-effect-extractor.test.ts +0 -119
  173. package/src/__tests__/transition-extractor.test.ts +0 -68
  174. package/src/__tests__/ts-to-expression.test.ts +0 -462
  175. package/src/__tests__/type-generator.test.ts +0 -201
  176. package/src/__tests__/uber-validation.test.ts +0 -502
  177. package/src/action-compiler.ts +0 -361
  178. package/src/babel/emitters/experience-transform.ts +0 -199
  179. package/src/babel/emitters/ir-to-tsx-emitter.ts +0 -110
  180. package/src/babel/emitters/pure-form-emitter.ts +0 -1023
  181. package/src/babel/emitters/runtime-glue-emitter.ts +0 -39
  182. package/src/babel/extractors/change-extractor.ts +0 -199
  183. package/src/babel/extractors/component-extractor.ts +0 -907
  184. package/src/babel/extractors/computed-extractor.ts +0 -262
  185. package/src/babel/extractors/context-extractor.ts +0 -277
  186. package/src/babel/extractors/during-extractor.ts +0 -295
  187. package/src/babel/extractors/effect-extractor.ts +0 -340
  188. package/src/babel/extractors/event-extractor.ts +0 -235
  189. package/src/babel/extractors/grammar-island-extractor.ts +0 -302
  190. package/src/babel/extractors/model-extractor.ts +0 -1018
  191. package/src/babel/extractors/router-extractor.ts +0 -303
  192. package/src/babel/extractors/server-action-extractor.ts +0 -173
  193. package/src/babel/extractors/server-action-hook-extractor.ts +0 -72
  194. package/src/babel/extractors/server-state-extractor.ts +0 -88
  195. package/src/babel/extractors/state-extractor.ts +0 -214
  196. package/src/babel/extractors/transition-effect-extractor.ts +0 -176
  197. package/src/babel/extractors/transition-extractor.ts +0 -143
  198. package/src/babel/index.ts +0 -24
  199. package/src/babel/transpilers/ts-to-expression.ts +0 -674
  200. package/src/babel/visitor.ts +0 -807
  201. package/src/cli/auth.ts +0 -255
  202. package/src/cli/build.ts +0 -288
  203. package/src/cli/deploy.ts +0 -206
  204. package/src/cli/index.ts +0 -328
  205. package/src/cli/installer.ts +0 -261
  206. package/src/cli/lock-file.ts +0 -94
  207. package/src/cli/mmrc.ts +0 -22
  208. package/src/cli/pull.ts +0 -172
  209. package/src/cli/registry-client.ts +0 -175
  210. package/src/cli/test.ts +0 -397
  211. package/src/cli/type-generator.ts +0 -243
  212. package/src/codemod/__tests__/forward.test.ts +0 -239
  213. package/src/codemod/__tests__/reverse.test.ts +0 -145
  214. package/src/codemod/__tests__/round-trip.test.ts +0 -137
  215. package/src/codemod/annotation.ts +0 -97
  216. package/src/codemod/classify.ts +0 -197
  217. package/src/codemod/cli.ts +0 -207
  218. package/src/codemod/control-flow.ts +0 -409
  219. package/src/codemod/forward.ts +0 -244
  220. package/src/codemod/import-manager.ts +0 -171
  221. package/src/codemod/index.ts +0 -120
  222. package/src/codemod/reverse.ts +0 -197
  223. package/src/codemod/rules.ts +0 -174
  224. package/src/codemod/state-transform.ts +0 -126
  225. package/src/decompiler/ast-builder.ts +0 -538
  226. package/src/decompiler/config-generator.ts +0 -151
  227. package/src/decompiler/index.ts +0 -315
  228. package/src/decompiler/project-decompiler.ts +0 -1776
  229. package/src/decompiler/project.ts +0 -862
  230. package/src/decompiler/split-strategy.ts +0 -140
  231. package/src/decompiler/state-emitter.ts +0 -1053
  232. package/src/decompiler/sx-emitter.ts +0 -318
  233. package/src/decompiler/workspace-hydrator.ts +0 -189
  234. package/src/dev-server.ts +0 -238
  235. package/src/envelope/fs-tree.ts +0 -217
  236. package/src/envelope/source-envelope.ts +0 -264
  237. package/src/envelope.ts +0 -315
  238. package/src/incremental-compiler.ts +0 -401
  239. package/src/index.ts +0 -99
  240. package/src/model-compiler.ts +0 -277
  241. package/src/project-compiler.ts +0 -1629
  242. package/src/route-extractor.ts +0 -333
  243. package/src/testing/index.ts +0 -32
  244. package/src/testing/snapshot.ts +0 -252
  245. package/src/testing/test-utils.ts +0 -226
  246. package/src/types.ts +0 -68
  247. package/src/vite/index.ts +0 -288
  248. package/test-compile.mjs +0 -142
  249. package/tsconfig.json +0 -25
  250. package/tsup.config.ts +0 -23
  251. package/vitest.config.ts +0 -9
@@ -445,25 +445,25 @@ function inferTransitionStates(transitions, states) {
445
445
  const stateArray = Array.from(states.values());
446
446
  const startStates = stateArray.filter((s) => s.type === "START");
447
447
  const regularStates = stateArray.filter((s) => s.type === "REGULAR");
448
- const needsInference = transitions.filter((t18) => t18.from.length === 0 || !t18.to);
448
+ const needsInference = transitions.filter((t19) => t19.from.length === 0 || !t19.to);
449
449
  if (needsInference.length === 0) return;
450
450
  if (startStates.length === 1 && regularStates.length > 0) {
451
- needsInference.forEach((t18, idx) => {
452
- if (t18.from.length === 0) {
453
- t18.from = [startStates[0].name];
451
+ needsInference.forEach((t19, idx) => {
452
+ if (t19.from.length === 0) {
453
+ t19.from = [startStates[0].name];
454
454
  }
455
- if (!t18.to) {
456
- t18.to = regularStates[idx % regularStates.length]?.name || startStates[0].name;
455
+ if (!t19.to) {
456
+ t19.to = regularStates[idx % regularStates.length]?.name || startStates[0].name;
457
457
  }
458
458
  });
459
459
  } else {
460
460
  const allStateNames = stateArray.map((s) => s.name);
461
- needsInference.forEach((t18, idx) => {
462
- if (t18.from.length === 0 && allStateNames.length > 0) {
463
- t18.from = [allStateNames[0]];
461
+ needsInference.forEach((t19, idx) => {
462
+ if (t19.from.length === 0 && allStateNames.length > 0) {
463
+ t19.from = [allStateNames[0]];
464
464
  }
465
- if (!t18.to && allStateNames.length > 1) {
466
- t18.to = allStateNames[Math.min(idx + 1, allStateNames.length - 1)];
465
+ if (!t19.to && allStateNames.length > 1) {
466
+ t19.to = allStateNames[Math.min(idx + 1, allStateNames.length - 1)];
467
467
  }
468
468
  });
469
469
  }
@@ -651,11 +651,128 @@ var init_event_extractor = __esm({
651
651
  });
652
652
 
653
653
  // src/babel/transpilers/ts-to-expression.ts
654
+ var ts_to_expression_exports = {};
655
+ __export(ts_to_expression_exports, {
656
+ transpile: () => transpile,
657
+ transpileBlock: () => transpileBlock,
658
+ transpileExpression: () => transpileExpression
659
+ });
654
660
  function transpileExpression(node, options = {}) {
655
661
  const ctx = new TranspileContext(options);
656
662
  const expr = ctx.visit(node);
657
663
  return { expression: expr, pure: ctx.isPure };
658
664
  }
665
+ function transpile(node, options = {}) {
666
+ return transpileExpression(node, options).expression;
667
+ }
668
+ function transpileBlock(node, options = {}) {
669
+ const ctx = new TranspileContext(options);
670
+ const lines = visitStatements(node.body, ctx);
671
+ return { expression: lines, pure: ctx.isPure };
672
+ }
673
+ function visitStatements(stmts, ctx) {
674
+ return stmts.map((s) => visitStatement(s, ctx)).join("\n");
675
+ }
676
+ function visitStatement(stmt, ctx) {
677
+ if (t5.isVariableDeclaration(stmt)) {
678
+ const keyword = ctx.allMutable || stmt.kind !== "const" ? "let" : "const";
679
+ const decls = stmt.declarations.map((d) => {
680
+ const init = d.init ? ctx.visit(d.init) : "null";
681
+ const lhs = declaratorPattern(d.id);
682
+ return `${keyword} ${lhs} = ${init}`;
683
+ });
684
+ return decls.join(";\n") + ";";
685
+ }
686
+ if (t5.isIfStatement(stmt)) {
687
+ const test = ctx.visit(stmt.test);
688
+ const consequent = visitBranchBody(stmt.consequent, ctx);
689
+ if (stmt.alternate) {
690
+ const alternate = visitBranchBody(stmt.alternate, ctx);
691
+ return `if (${test}) ${consequent} else ${alternate}`;
692
+ }
693
+ return `if (${test}) ${consequent}`;
694
+ }
695
+ if (t5.isForOfStatement(stmt)) {
696
+ const right = ctx.visit(stmt.right);
697
+ const varName = forOfPattern(stmt.left);
698
+ const body = visitBranchBody(stmt.body, ctx);
699
+ return `for (const ${varName} of ${right}) ${body}`;
700
+ }
701
+ if (t5.isWhileStatement(stmt)) {
702
+ const test = ctx.visit(stmt.test);
703
+ const body = visitBranchBody(stmt.body, ctx);
704
+ return `while (${test}) ${body}`;
705
+ }
706
+ if (t5.isReturnStatement(stmt)) {
707
+ if (!stmt.argument) return "return;";
708
+ return `return ${ctx.visit(stmt.argument)};`;
709
+ }
710
+ if (t5.isExpressionStatement(stmt)) {
711
+ return ctx.visit(stmt.expression) + ";";
712
+ }
713
+ if (t5.isBlockStatement(stmt)) {
714
+ const inner = visitStatements(stmt.body, ctx);
715
+ return `{
716
+ ${indent(inner)}
717
+ }`;
718
+ }
719
+ if (t5.isFunctionDeclaration(stmt) && stmt.id) {
720
+ const name = stmt.id.name;
721
+ const params = stmt.params.map((p) => t5.isIdentifier(p) ? p.name : "_").join(", ");
722
+ const body = visitStatements(stmt.body.body, ctx);
723
+ return `function ${name}(${params}) {
724
+ ${indent(body)}
725
+ }`;
726
+ }
727
+ return ctx.opaque(`[${stmt.type}]`) + ";";
728
+ }
729
+ function visitBranchBody(node, ctx) {
730
+ if (t5.isBlockStatement(node)) {
731
+ const inner2 = visitStatements(node.body, ctx);
732
+ return `{
733
+ ${indent(inner2)}
734
+ }`;
735
+ }
736
+ const inner = visitStatement(node, ctx);
737
+ return `{
738
+ ${indent(inner)}
739
+ }`;
740
+ }
741
+ function declaratorPattern(node) {
742
+ if (t5.isIdentifier(node)) return node.name;
743
+ if (t5.isObjectPattern(node)) {
744
+ const props = node.properties.map((p) => {
745
+ if (t5.isRestElement(p)) {
746
+ return `...${t5.isIdentifier(p.argument) ? p.argument.name : "_"}`;
747
+ }
748
+ if (t5.isObjectProperty(p)) {
749
+ const key = t5.isIdentifier(p.key) ? p.key.name : "_";
750
+ const val = t5.isIdentifier(p.value) ? p.value.name : t5.isAssignmentPattern(p.value) && t5.isIdentifier(p.value.left) ? p.value.left.name : "_";
751
+ return key === val ? key : `${key}: ${val}`;
752
+ }
753
+ return "_";
754
+ });
755
+ return `{ ${props.join(", ")} }`;
756
+ }
757
+ if (t5.isArrayPattern(node)) {
758
+ const elems = node.elements.map(
759
+ (e) => e === null ? "" : t5.isIdentifier(e) ? e.name : "_"
760
+ );
761
+ return `[${elems.join(", ")}]`;
762
+ }
763
+ return "_";
764
+ }
765
+ function forOfPattern(left) {
766
+ if (t5.isVariableDeclaration(left)) {
767
+ const d = left.declarations[0];
768
+ if (d) return declaratorPattern(d.id);
769
+ }
770
+ if (t5.isIdentifier(left)) return left.name;
771
+ return "_";
772
+ }
773
+ function indent(code) {
774
+ return code.split("\n").map((l) => " " + l).join("\n");
775
+ }
659
776
  function fallbackGenerate(node) {
660
777
  if (t5.isIdentifier(node)) return node.name;
661
778
  if (t5.isStringLiteral(node)) return `"${node.value.replace(/"/g, '\\"')}"`;
@@ -675,6 +792,8 @@ var init_ts_to_expression = __esm({
675
792
  this.localFieldMap = options.localFieldMap ?? /* @__PURE__ */ new Map();
676
793
  this.derivedVarMap = options.derivedVarMap ?? /* @__PURE__ */ new Map();
677
794
  this.setterToFieldMap = options.setterToFieldMap ?? /* @__PURE__ */ new Map();
795
+ this.parameterMap = options.parameterMap ?? /* @__PURE__ */ new Map();
796
+ this.allMutable = options.allMutable ?? false;
678
797
  }
679
798
  /**
680
799
  * Emit an opaque JS fallback, marking the result as impure.
@@ -696,6 +815,8 @@ var init_ts_to_expression = __esm({
696
815
  if (snakeName) return `$local.${snakeName}`;
697
816
  const derivedInit = this.derivedVarMap.get(node.name);
698
817
  if (derivedInit) return `(${this.visit(derivedInit)})`;
818
+ const paramField = this.parameterMap.get(node.name);
819
+ if (paramField) return paramField;
699
820
  if (node.name === "undefined") return "null";
700
821
  if (node.name === "NaN") return "null";
701
822
  if (node.name === "Infinity") return "null";
@@ -743,6 +864,9 @@ var init_ts_to_expression = __esm({
743
864
  if (t5.isNewExpression(node)) {
744
865
  return this.visitNew(node);
745
866
  }
867
+ if (t5.isAssignmentExpression(node) && node.operator === "=" && t5.isIdentifier(node.left)) {
868
+ return `${node.left.name} = ${this.visit(node.right)}`;
869
+ }
746
870
  return this.opaque(fallbackGenerate(node));
747
871
  }
748
872
  // ---------------------------------------------------------------------------
@@ -943,6 +1067,11 @@ var init_ts_to_expression = __esm({
943
1067
  return this.visitArrayHigherOrder("some", obj, args);
944
1068
  case "every":
945
1069
  return this.visitArrayHigherOrder("every", obj, args);
1070
+ // --- Array push: arr.push(item) → arr = push(arr, item) ---
1071
+ case "push": {
1072
+ const [item] = this.visitArgsList(args);
1073
+ return `${obj} = push(${obj}, ${item})`;
1074
+ }
946
1075
  // --- Array mutation-free methods ---
947
1076
  case "reverse":
948
1077
  return `reverse(${obj})`;
@@ -2796,6 +2925,71 @@ function modelStateTypeToIR(type) {
2796
2925
  if (type === "final") return "END";
2797
2926
  return "REGULAR";
2798
2927
  }
2928
+ function parseActionArray(raw, actionCounter) {
2929
+ if (!Array.isArray(raw)) return [];
2930
+ const actions = [];
2931
+ for (const item of raw) {
2932
+ if (typeof item !== "object" || item === null) continue;
2933
+ const a = item;
2934
+ actions.push({
2935
+ id: a.id ? String(a.id) : `auto_${++actionCounter.value}`,
2936
+ type: String(a.type || a.action_type || "unknown"),
2937
+ mode: a.mode || "auto",
2938
+ config: a.config && typeof a.config === "object" ? a.config : {},
2939
+ ...a.condition ? { condition: String(a.condition) } : {}
2940
+ });
2941
+ }
2942
+ return actions;
2943
+ }
2944
+ function parseDuringArray(raw, actionCounter) {
2945
+ if (!Array.isArray(raw)) return [];
2946
+ const result = [];
2947
+ for (const item of raw) {
2948
+ if (typeof item !== "object" || item === null) continue;
2949
+ const d = item;
2950
+ result.push({
2951
+ id: d.id ? String(d.id) : `during_${++actionCounter.value}`,
2952
+ type: d.type || "interval",
2953
+ ...d.interval_ms != null ? { interval_ms: Number(d.interval_ms) } : {},
2954
+ ...d.cron ? { cron: String(d.cron) } : {},
2955
+ ...d.delay_ms != null ? { delay_ms: Number(d.delay_ms) } : {},
2956
+ ...d.condition ? { condition: String(d.condition) } : {},
2957
+ actions: parseActionArray(d.actions, actionCounter)
2958
+ });
2959
+ }
2960
+ return result;
2961
+ }
2962
+ function parseOnEventArray(raw, actionCounter) {
2963
+ if (!Array.isArray(raw)) return [];
2964
+ const result = [];
2965
+ for (const item of raw) {
2966
+ if (typeof item !== "object" || item === null) continue;
2967
+ const e = item;
2968
+ const actions = [];
2969
+ if (Array.isArray(e.actions)) {
2970
+ for (const a of e.actions) {
2971
+ if (typeof a !== "object" || a === null) continue;
2972
+ const act = a;
2973
+ actions.push({
2974
+ type: act.type || "set_field",
2975
+ ...act.field ? { field: String(act.field) } : {},
2976
+ ...act.expression ? { expression: String(act.expression) } : {},
2977
+ ...act.key ? { key: String(act.key) } : {},
2978
+ ...act.message ? { message: String(act.message) } : {},
2979
+ ...act.config && typeof act.config === "object" ? { config: act.config } : {},
2980
+ ...act.conditions && Array.isArray(act.conditions) ? { conditions: act.conditions.map(String) } : {}
2981
+ });
2982
+ }
2983
+ }
2984
+ result.push({
2985
+ match: String(e.match || ""),
2986
+ ...e.description ? { description: String(e.description) } : {},
2987
+ ...e.conditions && Array.isArray(e.conditions) ? { conditions: e.conditions.map(String) } : {},
2988
+ actions
2989
+ });
2990
+ }
2991
+ return result;
2992
+ }
2799
2993
  function extractDefineModelCall(programPath, compilerState, actionCounter) {
2800
2994
  for (const node of programPath.node.body) {
2801
2995
  if (!t11.isExportDefaultDeclaration(node)) continue;
@@ -2835,17 +3029,27 @@ function extractDefineModelCall(programPath, compilerState, actionCounter) {
2835
3029
  const statesObj = config.states;
2836
3030
  for (const [name, stateConfig] of Object.entries(statesObj)) {
2837
3031
  const stateType = modelStateTypeToIR(stateConfig.type);
3032
+ const on_enter = parseActionArray(stateConfig.on_enter, actionCounter);
3033
+ const on_exit = parseActionArray(stateConfig.on_exit, actionCounter);
3034
+ const during = parseDuringArray(stateConfig.during, actionCounter);
3035
+ const on_event = parseOnEventArray(stateConfig.on_event, actionCounter);
2838
3036
  if (!compilerState.states.has(name)) {
2839
3037
  compilerState.states.set(name, {
2840
3038
  name,
2841
3039
  type: stateType,
2842
3040
  description: stateConfig.description,
2843
- on_enter: [],
2844
- during: [],
2845
- on_exit: []
3041
+ on_enter,
3042
+ during,
3043
+ on_exit,
3044
+ ...on_event.length > 0 ? { on_event } : {}
2846
3045
  });
2847
3046
  } else {
2848
- compilerState.states.get(name).type = stateType;
3047
+ const existing = compilerState.states.get(name);
3048
+ existing.type = stateType;
3049
+ if (on_enter.length > 0) existing.on_enter = on_enter;
3050
+ if (on_exit.length > 0) existing.on_exit = on_exit;
3051
+ if (during.length > 0) existing.during = during;
3052
+ if (on_event.length > 0) existing.on_event = on_event;
2849
3053
  }
2850
3054
  }
2851
3055
  }
@@ -2883,13 +3087,21 @@ function extractDefineModelCall(programPath, compilerState, actionCounter) {
2883
3087
  if (transConfig.guard) {
2884
3088
  conditions.push(parseGuardExpression(String(transConfig.guard)));
2885
3089
  }
3090
+ if (transConfig.conditions && Array.isArray(transConfig.conditions)) {
3091
+ for (const cond of transConfig.conditions) {
3092
+ if (typeof cond === "object" && cond !== null) {
3093
+ conditions.push(cond);
3094
+ }
3095
+ }
3096
+ }
3097
+ const actions = parseActionArray(transConfig.actions, actionCounter);
2886
3098
  compilerState.transitions.push({
2887
3099
  name,
2888
3100
  from,
2889
3101
  to,
2890
3102
  description: transConfig.description,
2891
3103
  conditions: conditions.length > 0 ? conditions : void 0,
2892
- actions: [],
3104
+ actions,
2893
3105
  roles: transConfig.roles,
2894
3106
  auto: transConfig.auto,
2895
3107
  required_fields: transConfig.required_fields
@@ -3569,7 +3781,7 @@ var init_context_extractor = __esm({
3569
3781
 
3570
3782
  // ../player-core/dist/index.mjs
3571
3783
  function normalizeCategory(primary, ...tags) {
3572
- const uniqueTags = [...new Set(tags.filter((t18) => t18 !== primary))];
3784
+ const uniqueTags = [...new Set(tags.filter((t19) => t19 !== primary))];
3573
3785
  uniqueTags.sort();
3574
3786
  return [primary, ...uniqueTags];
3575
3787
  }
@@ -3849,6 +4061,18 @@ function emitIR(extracted) {
3849
4061
  });
3850
4062
  stateNames.add(transition.to);
3851
4063
  }
4064
+ for (const from of transition.from) {
4065
+ if (from && !stateNames.has(from)) {
4066
+ stateArray.push({
4067
+ name: from,
4068
+ type: "REGULAR",
4069
+ on_enter: [],
4070
+ during: [],
4071
+ on_exit: []
4072
+ });
4073
+ stateNames.add(from);
4074
+ }
4075
+ }
3852
4076
  }
3853
4077
  const fieldNames = new Set(fields.map((f) => f.name));
3854
4078
  let normalizedView;
@@ -4278,16 +4502,16 @@ function emitWorkflowDefinition(extracted) {
4278
4502
  ...f.editable_when && { editable_when: f.editable_when },
4279
4503
  ...f.state_home && { state_home: f.state_home }
4280
4504
  }));
4281
- const transitions = ir.transitions.map((t18) => ({
4282
- name: t18.name,
4283
- from: t18.from,
4284
- to: t18.to,
4285
- description: t18.description || "",
4286
- roles: t18.roles || [],
4287
- auto: t18.auto || false,
4288
- conditions: t18.conditions || [],
4289
- actions: (t18.actions || []).map(convertAction),
4290
- required_fields: t18.required_fields || [],
4505
+ const transitions = ir.transitions.map((t19) => ({
4506
+ name: t19.name,
4507
+ from: t19.from,
4508
+ to: t19.to,
4509
+ description: t19.description || "",
4510
+ roles: t19.roles || [],
4511
+ auto: t19.auto || false,
4512
+ conditions: t19.conditions || [],
4513
+ actions: (t19.actions || []).map(convertAction),
4514
+ required_fields: t19.required_fields || [],
4291
4515
  priority: 0
4292
4516
  }));
4293
4517
  const state_data = {};
@@ -4823,7 +5047,7 @@ function createVisitor(options = {}) {
4823
5047
  }
4824
5048
  }
4825
5049
  if (mode !== "strict") return;
4826
- if (source.startsWith("@mindmatrix/") || source === "react" || source.startsWith("react/") || source.startsWith(".") || source.startsWith("/")) {
5050
+ if (source.startsWith("@mindmatrix/") || source.startsWith("@mmapp/") || source === "react" || source.startsWith("react/") || source.startsWith(".") || source.startsWith("/")) {
4827
5051
  return;
4828
5052
  }
4829
5053
  const error = {
@@ -5237,7 +5461,7 @@ function compileModel(filename, source, options = {}) {
5237
5461
  ir,
5238
5462
  interfaceName,
5239
5463
  fieldNames: ir.fields.map((f) => f.name),
5240
- transitionNames: ir.transitions.map((t18) => t18.name),
5464
+ transitionNames: ir.transitions.map((t19) => t19.name),
5241
5465
  stateNames: ir.states.map((s) => s.name),
5242
5466
  hasFieldOptions: Object.keys(rawFieldOptions).length > 0,
5243
5467
  fieldOptions: rawFieldOptions
@@ -5637,6 +5861,520 @@ var init_action_compiler = __esm({
5637
5861
  }
5638
5862
  });
5639
5863
 
5864
+ // src/babel/extractors/action-extractor.ts
5865
+ function extractAction(source, filename) {
5866
+ let ast;
5867
+ try {
5868
+ ast = (0, import_parser.parse)(source, {
5869
+ sourceType: "module",
5870
+ plugins: ["typescript"],
5871
+ strictMode: false
5872
+ });
5873
+ } catch {
5874
+ return null;
5875
+ }
5876
+ const result = findDefaultExportedFunction(ast);
5877
+ if (!result) return null;
5878
+ const { name, params, body, returnTypeAnnotation, isAsync } = result;
5879
+ const slug = toKebabCase(name);
5880
+ const warnings = [];
5881
+ const fields = params.map((p) => paramToField(p));
5882
+ const parameterMap = /* @__PURE__ */ new Map();
5883
+ for (const p of params) {
5884
+ const snakeName = toSnakeCase3(p.name);
5885
+ if (snakeName !== p.name) {
5886
+ parameterMap.set(p.name, snakeName);
5887
+ }
5888
+ }
5889
+ const humanName = name.replace(/([A-Z])/g, " $1").replace(/^./, (s) => s.toUpperCase()).trim();
5890
+ const metadata = {
5891
+ source_file: filename,
5892
+ source_function: name,
5893
+ provenance: {
5894
+ frontend: "react-compiler",
5895
+ source: "action-extractor",
5896
+ compiler_version: "2.0.0"
5897
+ }
5898
+ };
5899
+ if (returnTypeAnnotation) {
5900
+ metadata.return_type = returnTypeAnnotation;
5901
+ }
5902
+ if (isAsync) {
5903
+ const segments = splitAtAwaits(body.body);
5904
+ const hasAwaits = segments.some((s) => s.kind === "await");
5905
+ if (hasAwaits) {
5906
+ const rewritten = rewriteAwaitReferences(segments);
5907
+ const { states: states2, transitions: transitions2, bodyIsPure } = generateMultiStateIR(rewritten, warnings, parameterMap);
5908
+ if (!bodyIsPure) {
5909
+ warnings.push(`Async action '${name}' body contains untranslatable JS \u2014 wrapped in $expr() markers`);
5910
+ }
5911
+ const ir2 = {
5912
+ slug,
5913
+ name: humanName,
5914
+ version: "0.1.0",
5915
+ category: "action",
5916
+ fields,
5917
+ states: states2,
5918
+ transitions: transitions2,
5919
+ roles: [],
5920
+ metadata: { ...metadata, async: true }
5921
+ };
5922
+ return { ir: ir2, bodyIsPure, warnings };
5923
+ }
5924
+ }
5925
+ const transpileResult = transpileBlock(body, { allMutable: true, parameterMap });
5926
+ const bodyExpr = transpileResult.expression;
5927
+ if (!transpileResult.pure) {
5928
+ warnings.push(`Action '${name}' body contains untranslatable JS \u2014 wrapped in $expr() markers`);
5929
+ }
5930
+ const states = [
5931
+ {
5932
+ name: "ready",
5933
+ type: "START",
5934
+ on_enter: [],
5935
+ during: [],
5936
+ on_exit: []
5937
+ },
5938
+ {
5939
+ name: "done",
5940
+ type: "END",
5941
+ on_enter: [],
5942
+ during: [],
5943
+ on_exit: []
5944
+ }
5945
+ ];
5946
+ const transitions = [
5947
+ {
5948
+ name: "execute",
5949
+ from: ["ready"],
5950
+ to: "done",
5951
+ actions: [
5952
+ {
5953
+ id: "body",
5954
+ type: "eval",
5955
+ mode: "auto",
5956
+ config: {
5957
+ expression: bodyExpr
5958
+ }
5959
+ }
5960
+ ]
5961
+ }
5962
+ ];
5963
+ const ir = {
5964
+ slug,
5965
+ name: humanName,
5966
+ version: "0.1.0",
5967
+ category: "action",
5968
+ fields,
5969
+ states,
5970
+ transitions,
5971
+ roles: [],
5972
+ metadata
5973
+ };
5974
+ return { ir, bodyIsPure: transpileResult.pure, warnings };
5975
+ }
5976
+ function findDefaultExportedFunction(ast) {
5977
+ const topLevelVars = /* @__PURE__ */ new Map();
5978
+ for (const node of ast.program.body) {
5979
+ if (t18.isVariableDeclaration(node)) {
5980
+ for (const decl of node.declarations) {
5981
+ if (t18.isIdentifier(decl.id) && decl.init) {
5982
+ if (t18.isArrowFunctionExpression(decl.init) || t18.isFunctionExpression(decl.init)) {
5983
+ topLevelVars.set(decl.id.name, decl.init);
5984
+ }
5985
+ }
5986
+ }
5987
+ }
5988
+ }
5989
+ for (const node of ast.program.body) {
5990
+ if (t18.isExportDefaultDeclaration(node)) {
5991
+ const decl = node.declaration;
5992
+ if (t18.isFunctionDeclaration(decl) && decl.body) {
5993
+ const name = decl.id?.name ?? inferNameFromFile(decl) ?? "action";
5994
+ return extractFromFunction(name, decl.params, decl.body, decl.returnType, decl.async);
5995
+ }
5996
+ if (t18.isArrowFunctionExpression(decl) || t18.isFunctionExpression(decl)) {
5997
+ const name = t18.isFunctionExpression(decl) && decl.id ? decl.id.name : "action";
5998
+ const body = ensureBlock(decl.body);
5999
+ if (!body) return null;
6000
+ return extractFromFunction(name, decl.params, body, decl.returnType, decl.async);
6001
+ }
6002
+ if (t18.isIdentifier(decl)) {
6003
+ const fn = topLevelVars.get(decl.name);
6004
+ if (fn) {
6005
+ const body = ensureBlock(fn.body);
6006
+ if (!body) return null;
6007
+ return extractFromFunction(decl.name, fn.params, body, fn.returnType, fn.async);
6008
+ }
6009
+ }
6010
+ }
6011
+ }
6012
+ return null;
6013
+ }
6014
+ function extractFromFunction(name, params, body, returnType, isAsync = false) {
6015
+ const extracted = params.map((p) => extractParam(p));
6016
+ const returnTypeAnnotation = returnType && t18.isTSTypeAnnotation(returnType) ? serializeTSType(returnType.typeAnnotation) : void 0;
6017
+ return { name, params: extracted, body, returnTypeAnnotation, isAsync };
6018
+ }
6019
+ function ensureBlock(body) {
6020
+ if (t18.isBlockStatement(body)) return body;
6021
+ const ret = t18.returnStatement(body);
6022
+ return t18.blockStatement([ret]);
6023
+ }
6024
+ function inferNameFromFile(_node) {
6025
+ return null;
6026
+ }
6027
+ function extractParam(param) {
6028
+ if (t18.isIdentifier(param)) {
6029
+ return {
6030
+ name: param.name,
6031
+ typeAnnotation: param.typeAnnotation ? param.typeAnnotation.typeAnnotation : null,
6032
+ optional: param.optional ?? false
6033
+ };
6034
+ }
6035
+ if (t18.isAssignmentPattern(param)) {
6036
+ const inner = param.left;
6037
+ if (t18.isIdentifier(inner)) {
6038
+ return {
6039
+ name: inner.name,
6040
+ typeAnnotation: inner.typeAnnotation ? inner.typeAnnotation.typeAnnotation : null,
6041
+ optional: true,
6042
+ defaultValue: param.right
6043
+ };
6044
+ }
6045
+ }
6046
+ if (t18.isRestElement(param)) {
6047
+ const arg = param.argument;
6048
+ return {
6049
+ name: t18.isIdentifier(arg) ? arg.name : "rest",
6050
+ typeAnnotation: null,
6051
+ optional: true
6052
+ };
6053
+ }
6054
+ return { name: "params", typeAnnotation: null, optional: false };
6055
+ }
6056
+ function paramToField(param) {
6057
+ const fieldType = param.typeAnnotation ? tsTypeToFieldType2(param.typeAnnotation) : "text";
6058
+ const field = {
6059
+ name: toSnakeCase3(param.name),
6060
+ type: fieldType,
6061
+ required: !param.optional
6062
+ };
6063
+ if (param.defaultValue !== void 0) {
6064
+ field.default_value = extractLiteralDefault(param.defaultValue);
6065
+ }
6066
+ return field;
6067
+ }
6068
+ function extractLiteralDefault(expr) {
6069
+ if (!expr) return void 0;
6070
+ if (t18.isStringLiteral(expr)) return expr.value;
6071
+ if (t18.isNumericLiteral(expr)) return expr.value;
6072
+ if (t18.isBooleanLiteral(expr)) return expr.value;
6073
+ if (t18.isNullLiteral(expr)) return null;
6074
+ if (t18.isArrayExpression(expr) && expr.elements.length === 0) return [];
6075
+ if (t18.isObjectExpression(expr) && expr.properties.length === 0) return {};
6076
+ return void 0;
6077
+ }
6078
+ function tsTypeToFieldType2(tsType) {
6079
+ if (t18.isTSStringKeyword(tsType)) return "text";
6080
+ if (t18.isTSNumberKeyword(tsType)) return "number";
6081
+ if (t18.isTSBooleanKeyword(tsType)) return "boolean";
6082
+ if (t18.isTSObjectKeyword(tsType)) return "json";
6083
+ if (t18.isTSAnyKeyword(tsType) || t18.isTSUnknownKeyword(tsType)) return "json";
6084
+ if (t18.isTSArrayType(tsType)) return "json";
6085
+ if (t18.isTSUnionType(tsType)) {
6086
+ const nonNullable = tsType.types.filter(
6087
+ (t22) => !t18.isTSNullKeyword(t22) && !t18.isTSUndefinedKeyword(t22)
6088
+ );
6089
+ if (nonNullable.length === 1) {
6090
+ return tsTypeToFieldType2(nonNullable[0]);
6091
+ }
6092
+ if (nonNullable.every((t22) => t18.isTSLiteralType(t22) && t18.isStringLiteral(t22.literal))) {
6093
+ return "select";
6094
+ }
6095
+ return "text";
6096
+ }
6097
+ if (t18.isTSTypeReference(tsType) && t18.isIdentifier(tsType.typeName)) {
6098
+ const name = tsType.typeName.name;
6099
+ if (name === "Date") return "datetime";
6100
+ if (name === "string") return "text";
6101
+ if (name === "number") return "number";
6102
+ if (name === "boolean") return "boolean";
6103
+ }
6104
+ return "text";
6105
+ }
6106
+ function serializeTSType(tsType) {
6107
+ if (t18.isTSStringKeyword(tsType)) return "string";
6108
+ if (t18.isTSNumberKeyword(tsType)) return "number";
6109
+ if (t18.isTSBooleanKeyword(tsType)) return "boolean";
6110
+ if (t18.isTSVoidKeyword(tsType)) return "void";
6111
+ if (t18.isTSAnyKeyword(tsType)) return "any";
6112
+ if (t18.isTSTypeReference(tsType) && t18.isIdentifier(tsType.typeName)) {
6113
+ return tsType.typeName.name;
6114
+ }
6115
+ if (t18.isTSArrayType(tsType)) return `${serializeTSType(tsType.elementType)}[]`;
6116
+ if (t18.isTSPromiseType(tsType)) {
6117
+ return `Promise<${tsType.typeParameter ? serializeTSType(tsType.typeParameter.params[0]) : "unknown"}>`;
6118
+ }
6119
+ return "unknown";
6120
+ }
6121
+ function splitAtAwaits(body) {
6122
+ const segments = [];
6123
+ let current = [];
6124
+ let index = 0;
6125
+ for (const stmt of body) {
6126
+ const awaitInfo = extractAwait(stmt);
6127
+ if (!awaitInfo) {
6128
+ current.push(stmt);
6129
+ continue;
6130
+ }
6131
+ if (current.length > 0) {
6132
+ segments.push({ index: index++, kind: "sync", statements: current });
6133
+ current = [];
6134
+ }
6135
+ segments.push({
6136
+ index: index++,
6137
+ kind: "await",
6138
+ statements: [stmt],
6139
+ awaitTarget: awaitInfo.callee,
6140
+ awaitArgs: awaitInfo.args,
6141
+ resultBinding: awaitInfo.binding
6142
+ });
6143
+ }
6144
+ if (current.length > 0) {
6145
+ segments.push({ index: index++, kind: "sync", statements: current });
6146
+ }
6147
+ return segments;
6148
+ }
6149
+ function extractAwait(stmt) {
6150
+ if (t18.isVariableDeclaration(stmt)) {
6151
+ const decl = stmt.declarations[0];
6152
+ if (decl?.init && t18.isAwaitExpression(decl.init)) {
6153
+ const arg = decl.init.argument;
6154
+ if (t18.isCallExpression(arg)) {
6155
+ return {
6156
+ callee: getCalleeName(arg.callee),
6157
+ args: arg.arguments,
6158
+ binding: t18.isIdentifier(decl.id) ? decl.id.name : void 0
6159
+ };
6160
+ }
6161
+ }
6162
+ }
6163
+ if (t18.isExpressionStatement(stmt) && t18.isAwaitExpression(stmt.expression)) {
6164
+ const arg = stmt.expression.argument;
6165
+ if (t18.isCallExpression(arg)) {
6166
+ return {
6167
+ callee: getCalleeName(arg.callee),
6168
+ args: arg.arguments,
6169
+ binding: void 0
6170
+ };
6171
+ }
6172
+ }
6173
+ if (t18.isReturnStatement(stmt) && stmt.argument && t18.isAwaitExpression(stmt.argument)) {
6174
+ const arg = stmt.argument.argument;
6175
+ if (t18.isCallExpression(arg)) {
6176
+ return {
6177
+ callee: getCalleeName(arg.callee),
6178
+ args: arg.arguments,
6179
+ binding: void 0
6180
+ };
6181
+ }
6182
+ }
6183
+ return null;
6184
+ }
6185
+ function getCalleeName(callee) {
6186
+ if (t18.isIdentifier(callee)) return callee.name;
6187
+ if (t18.isMemberExpression(callee) && t18.isIdentifier(callee.object) && t18.isIdentifier(callee.property)) {
6188
+ return `${callee.object.name}_${callee.property.name}`;
6189
+ }
6190
+ return "unknown_action";
6191
+ }
6192
+ function rewriteAwaitReferences(segments) {
6193
+ const bindings = /* @__PURE__ */ new Map();
6194
+ const slugCounts = /* @__PURE__ */ new Map();
6195
+ return segments.map((seg) => {
6196
+ if (seg.kind === "await" && seg.resultBinding) {
6197
+ const slug = toSnakeCase3(seg.awaitTarget ?? "unknown");
6198
+ const count = (slugCounts.get(slug) ?? 0) + 1;
6199
+ slugCounts.set(slug, count);
6200
+ const key = count > 1 ? `${slug}_${count}` : slug;
6201
+ bindings.set(seg.resultBinding, `action_results.${key}`);
6202
+ }
6203
+ if (seg.kind === "sync" && bindings.size > 0) {
6204
+ return {
6205
+ ...seg,
6206
+ statements: seg.statements.map(
6207
+ (stmt) => rewriteIdentifiersInStatement(stmt, bindings)
6208
+ )
6209
+ };
6210
+ }
6211
+ return seg;
6212
+ });
6213
+ }
6214
+ function rewriteIdentifiersInStatement(stmt, _bindings) {
6215
+ return stmt;
6216
+ }
6217
+ function generateMultiStateIR(segments, _warnings, parameterMap) {
6218
+ const states = [];
6219
+ const transitions = [];
6220
+ let bodyIsPure = true;
6221
+ const awaitBindings = /* @__PURE__ */ new Map();
6222
+ const slugCounts = /* @__PURE__ */ new Map();
6223
+ for (const seg of segments) {
6224
+ if (seg.kind === "await" && seg.resultBinding) {
6225
+ const slug = toSnakeCase3(seg.awaitTarget ?? "unknown");
6226
+ const count = (slugCounts.get(slug) ?? 0) + 1;
6227
+ slugCounts.set(slug, count);
6228
+ const key = count > 1 ? `${slug}_${count}` : slug;
6229
+ awaitBindings.set(seg.resultBinding, `action_results.${key}`);
6230
+ }
6231
+ }
6232
+ states.push({ name: "ready", type: "START", on_enter: [], during: [], on_exit: [] });
6233
+ const usedStateNames = /* @__PURE__ */ new Set();
6234
+ let prevState = "ready";
6235
+ let transitionCount = 0;
6236
+ let pendingSyncStmts = [];
6237
+ for (const seg of segments) {
6238
+ if (seg.kind === "sync") {
6239
+ pendingSyncStmts.push(...seg.statements);
6240
+ continue;
6241
+ }
6242
+ const targetSlug = toSnakeCase3(seg.awaitTarget ?? "unknown");
6243
+ let stateName = `awaiting_${targetSlug}`;
6244
+ if (usedStateNames.has(stateName)) {
6245
+ let suffix = 2;
6246
+ while (usedStateNames.has(`${stateName}_${suffix}`)) suffix++;
6247
+ stateName = `${stateName}_${suffix}`;
6248
+ }
6249
+ usedStateNames.add(stateName);
6250
+ states.push({ name: stateName, type: "REGULAR", on_enter: [], during: [], on_exit: [] });
6251
+ const actions = [];
6252
+ if (pendingSyncStmts.length > 0) {
6253
+ const block = t18.blockStatement(pendingSyncStmts);
6254
+ const transpiled = transpileBlock(block, {
6255
+ allMutable: true,
6256
+ derivedVarMap: buildDerivedVarMap(awaitBindings),
6257
+ parameterMap
6258
+ });
6259
+ if (!transpiled.pure) bodyIsPure = false;
6260
+ actions.push({
6261
+ id: `pre_${transitionCount}`,
6262
+ type: "eval",
6263
+ mode: "auto",
6264
+ config: { expression: transpiled.expression }
6265
+ });
6266
+ pendingSyncStmts = [];
6267
+ }
6268
+ const callConfig = {
6269
+ definition_slug: seg.awaitTarget,
6270
+ result_key: targetSlug
6271
+ };
6272
+ if (seg.awaitArgs && seg.awaitArgs.length > 0) {
6273
+ const params = {};
6274
+ for (let i = 0; i < seg.awaitArgs.length; i++) {
6275
+ const arg = seg.awaitArgs[i];
6276
+ if (t18.isObjectExpression(arg)) {
6277
+ for (const prop of arg.properties) {
6278
+ if (t18.isObjectProperty(prop) && t18.isIdentifier(prop.key)) {
6279
+ const { expression: valExpr } = transpileArgExpression(prop.value, awaitBindings);
6280
+ params[prop.key.name] = valExpr;
6281
+ }
6282
+ }
6283
+ } else {
6284
+ const { expression: valExpr } = transpileArgExpression(arg, awaitBindings);
6285
+ params[`arg${i}`] = valExpr;
6286
+ }
6287
+ }
6288
+ if (Object.keys(params).length > 0) {
6289
+ callConfig.params = params;
6290
+ }
6291
+ }
6292
+ actions.push({
6293
+ id: `call_${targetSlug}`,
6294
+ type: "call_workflow",
6295
+ mode: "auto",
6296
+ config: callConfig
6297
+ });
6298
+ const transName = transitionCount === 0 ? "execute" : `on_${getStateSuffix(prevState)}_complete`;
6299
+ transitions.push({
6300
+ name: transName,
6301
+ from: [prevState],
6302
+ to: stateName,
6303
+ actions
6304
+ });
6305
+ prevState = stateName;
6306
+ transitionCount++;
6307
+ }
6308
+ states.push({ name: "done", type: "END", on_enter: [], during: [], on_exit: [] });
6309
+ const finalActions = [];
6310
+ if (pendingSyncStmts.length > 0) {
6311
+ const block = t18.blockStatement(pendingSyncStmts);
6312
+ const transpiled = transpileBlock(block, {
6313
+ allMutable: true,
6314
+ derivedVarMap: buildDerivedVarMap(awaitBindings),
6315
+ parameterMap
6316
+ });
6317
+ if (!transpiled.pure) bodyIsPure = false;
6318
+ finalActions.push({
6319
+ id: "post_final",
6320
+ type: "eval",
6321
+ mode: "auto",
6322
+ config: { expression: transpiled.expression }
6323
+ });
6324
+ }
6325
+ const finalTransName = transitionCount === 0 ? "execute" : `on_${getStateSuffix(prevState)}_complete`;
6326
+ transitions.push({
6327
+ name: finalTransName,
6328
+ from: [prevState],
6329
+ to: "done",
6330
+ actions: finalActions
6331
+ });
6332
+ return { states, transitions, bodyIsPure };
6333
+ }
6334
+ function getStateSuffix(stateName) {
6335
+ return stateName.replace(/^awaiting_/, "");
6336
+ }
6337
+ function transpileArgExpression(expr, bindings) {
6338
+ if (t18.isIdentifier(expr)) {
6339
+ const replacement = bindings.get(expr.name);
6340
+ if (replacement) return { expression: replacement };
6341
+ return { expression: `state_data.${toSnakeCase3(expr.name)}` };
6342
+ }
6343
+ if (t18.isMemberExpression(expr) && t18.isIdentifier(expr.object)) {
6344
+ const replacement = bindings.get(expr.object.name);
6345
+ if (replacement && t18.isIdentifier(expr.property)) {
6346
+ return { expression: `${replacement}.${expr.property.name}` };
6347
+ }
6348
+ }
6349
+ if (t18.isStringLiteral(expr)) return { expression: `'${expr.value}'` };
6350
+ if (t18.isNumericLiteral(expr)) return { expression: String(expr.value) };
6351
+ if (t18.isBooleanLiteral(expr)) return { expression: String(expr.value) };
6352
+ const { transpile: transpile2 } = (init_ts_to_expression(), __toCommonJS(ts_to_expression_exports));
6353
+ return { expression: transpile2(expr, { derivedVarMap: buildDerivedVarMap(bindings) }) };
6354
+ }
6355
+ function buildDerivedVarMap(bindings) {
6356
+ const map = /* @__PURE__ */ new Map();
6357
+ for (const [varName, path] of bindings) {
6358
+ map.set(varName, t18.identifier(path));
6359
+ }
6360
+ return map;
6361
+ }
6362
+ function toKebabCase(name) {
6363
+ return name.replace(/([A-Z])/g, "-$1").toLowerCase().replace(/^-/, "");
6364
+ }
6365
+ function toSnakeCase3(name) {
6366
+ return name.replace(/([A-Z])/g, "_$1").toLowerCase().replace(/^_/, "");
6367
+ }
6368
+ var import_parser, t18;
6369
+ var init_action_extractor = __esm({
6370
+ "src/babel/extractors/action-extractor.ts"() {
6371
+ "use strict";
6372
+ import_parser = require("@babel/parser");
6373
+ t18 = __toESM(require("@babel/types"));
6374
+ init_ts_to_expression();
6375
+ }
6376
+ });
6377
+
5640
6378
  // src/incremental-compiler.ts
5641
6379
  function hashContent(content) {
5642
6380
  let hash = 5381;
@@ -5990,24 +6728,56 @@ function parseModuleManifest(source) {
5990
6728
  }
5991
6729
  if (contributions.length > 0) manifest.contributions = contributions;
5992
6730
  }
6731
+ const configSchemaBlock = extractObjectBlock(source, "configSchema");
6732
+ if (configSchemaBlock) {
6733
+ const configSchema = {};
6734
+ const modelSlugMatch = configSchemaBlock.match(/modelSlug:\s*['"]([^'"]+)['"]/);
6735
+ if (modelSlugMatch) configSchema.modelSlug = modelSlugMatch[1];
6736
+ const defaultsBlock = extractObjectBlock(configSchemaBlock, "defaults");
6737
+ if (defaultsBlock) {
6738
+ const defaults = {};
6739
+ const kvRegex = /(\w+):\s*(?:'([^']*)'|"([^"]*)"|(\d+(?:\.\d+)?)|(\btrue\b|\bfalse\b))/g;
6740
+ let kv;
6741
+ while ((kv = kvRegex.exec(defaultsBlock)) !== null) {
6742
+ const key = kv[1];
6743
+ const val = kv[2] ?? kv[3] ?? (kv[4] !== void 0 ? Number(kv[4]) : kv[5] === "true");
6744
+ defaults[key] = val;
6745
+ }
6746
+ configSchema.defaults = defaults;
6747
+ }
6748
+ manifest.configSchema = configSchema;
6749
+ }
5993
6750
  const depsBlock = extractArrayBlock(source, "dependencies");
5994
6751
  if (depsBlock) {
5995
6752
  const dependencies = [];
5996
- const depRegex = /\{\s*slug:\s*['"]([^'"]+)['"][^}]*\}/g;
5997
- let dm;
5998
- while ((dm = depRegex.exec(depsBlock)) !== null) {
5999
- const entry = { slug: dm[1] };
6000
- const verMatch = dm[0].match(/version:\s*['"]([^'"]+)['"]/);
6753
+ const depBlocks = extractNestedObjects(depsBlock);
6754
+ for (const block of depBlocks) {
6755
+ const slugMatch = block.match(/slug:\s*['"]([^'"]+)['"]/);
6756
+ if (!slugMatch) continue;
6757
+ const entry = { slug: slugMatch[1] };
6758
+ const verMatch = block.match(/version:\s*['"]([^'"]+)['"]/);
6001
6759
  if (verMatch) entry.version = verMatch[1];
6002
- const reqMatch = dm[0].match(/required:\s*(true|false)/);
6760
+ const reqMatch = block.match(/required:\s*(true|false)/);
6003
6761
  if (reqMatch) entry.required = reqMatch[1] === "true";
6004
- const prefixMatch = dm[0].match(/prefix:\s*['"]([^'"]+)['"]/);
6762
+ const prefixMatch = block.match(/prefix:\s*['"]([^'"]+)['"]/);
6005
6763
  if (prefixMatch) entry.routeConfig = { prefix: prefixMatch[1] };
6764
+ const configBlock = extractObjectBlock(block, "config");
6765
+ if (configBlock) {
6766
+ const config = {};
6767
+ const kvRegex = /(\w+):\s*(?:'([^']*)'|"([^"]*)"|(\d+(?:\.\d+)?)|(\btrue\b|\bfalse\b))/g;
6768
+ let kv;
6769
+ while ((kv = kvRegex.exec(configBlock)) !== null) {
6770
+ const key = kv[1];
6771
+ const val = kv[2] ?? kv[3] ?? (kv[4] !== void 0 ? Number(kv[4]) : kv[5] === "true");
6772
+ config[key] = val;
6773
+ }
6774
+ if (Object.keys(config).length > 0) entry.config = config;
6775
+ }
6006
6776
  dependencies.push(entry);
6007
6777
  }
6008
6778
  if (dependencies.length > 0) manifest.dependencies = dependencies;
6009
6779
  }
6010
- const hasRichFields = manifest.routes || manifest.actions || manifest.contributions || manifest.capabilities || manifest.dependencies;
6780
+ const hasRichFields = manifest.routes || manifest.actions || manifest.contributions || manifest.capabilities || manifest.dependencies || manifest.configSchema;
6011
6781
  return hasRichFields ? manifest : null;
6012
6782
  }
6013
6783
  function parseDependencyRouteConfigs(files) {
@@ -6103,6 +6873,9 @@ function isModelFile2(filename) {
6103
6873
  function isServerActionFile2(filename) {
6104
6874
  return /\.server\.(ts|tsx)$/.test(filename);
6105
6875
  }
6876
+ function isActionFile(filename) {
6877
+ return /^actions\/.*\.(ts|tsx)$/.test(filename) && !filename.endsWith(".server.ts") && !filename.endsWith(".test.ts") && !filename.endsWith(".test.tsx");
6878
+ }
6106
6879
  function isComponentFile(filename) {
6107
6880
  return /components\/.*\.(tsx?|jsx?)$/.test(filename) && !filename.endsWith(".test.ts") && !filename.endsWith(".test.tsx");
6108
6881
  }
@@ -6119,7 +6892,7 @@ function isModuleManifestFile(filename) {
6119
6892
  return /mm\.module\.(ts|tsx|js)$/.test(filename);
6120
6893
  }
6121
6894
  function isCompilableFile(filename) {
6122
- return isWorkflowFile(filename) || isModelFile2(filename) || isServerActionFile2(filename) || isPageFile2(filename) || isComponentFile(filename);
6895
+ return isWorkflowFile(filename) || isModelFile2(filename) || isServerActionFile2(filename) || isActionFile(filename) || isPageFile2(filename) || isComponentFile(filename);
6123
6896
  }
6124
6897
  function compileFile(filename, source, mode) {
6125
6898
  const errors = [];
@@ -6401,10 +7174,87 @@ function extractComponentProps(source) {
6401
7174
  if (!match) return [];
6402
7175
  return match[1].split(",").map((p) => p.trim().split(/[\s=:]/)[0].replace(/^\.{3}/, "").trim()).filter(Boolean);
6403
7176
  }
7177
+ function generateModuleTypeStubs(childDefinitions, _modelResults) {
7178
+ const stubs = {};
7179
+ for (const child of childDefinitions) {
7180
+ if (!child.slug) continue;
7181
+ const category = child.category;
7182
+ const isModel = category === "data" || Array.isArray(category) && category.includes("model") || Array.isArray(category) && category.includes("data");
7183
+ if (!isModel || !child.fields || child.fields.length === 0) continue;
7184
+ const interfaceName = slugToInterfaceName(child.slug) + "Fields";
7185
+ const lines = [
7186
+ `// Auto-generated type stub for model: ${child.slug}`,
7187
+ `// Do not edit \u2014 regenerated on each build.`,
7188
+ ``,
7189
+ `export interface ${interfaceName} {`
7190
+ ];
7191
+ for (const field of child.fields) {
7192
+ const tsType = irFieldTypeToTs(field.type || "string");
7193
+ const optional = field.required ? "" : "?";
7194
+ const desc = field.description;
7195
+ if (desc) {
7196
+ lines.push(` /** ${desc} */`);
7197
+ }
7198
+ lines.push(` ${field.name}${optional}: ${tsType};`);
7199
+ }
7200
+ lines.push(`}`);
7201
+ lines.push(``);
7202
+ lines.push(`export declare const ${slugToCamelCase(child.slug)}Slug: '${child.slug}';`);
7203
+ lines.push(``);
7204
+ stubs[`types/modules/${child.slug}.d.ts`] = lines.join("\n");
7205
+ }
7206
+ return stubs;
7207
+ }
7208
+ function slugToInterfaceName(slug) {
7209
+ return slug.split("-").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join("");
7210
+ }
7211
+ function slugToCamelCase(slug) {
7212
+ const parts = slug.split("-");
7213
+ return parts[0] + parts.slice(1).map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join("");
7214
+ }
7215
+ function irFieldTypeToTs(type) {
7216
+ switch (type) {
7217
+ case "string":
7218
+ case "text":
7219
+ case "email":
7220
+ case "url":
7221
+ case "phone":
7222
+ case "slug":
7223
+ case "color":
7224
+ case "password":
7225
+ return "string";
7226
+ case "number":
7227
+ case "integer":
7228
+ case "float":
7229
+ case "currency":
7230
+ case "percent":
7231
+ return "number";
7232
+ case "boolean":
7233
+ case "toggle":
7234
+ return "boolean";
7235
+ case "date":
7236
+ case "datetime":
7237
+ case "timestamp":
7238
+ return "string";
7239
+ case "json":
7240
+ case "object":
7241
+ return "Record<string, unknown>";
7242
+ case "array":
7243
+ return "unknown[]";
7244
+ case "enum":
7245
+ return "string";
7246
+ case "file":
7247
+ case "image":
7248
+ return "string";
7249
+ default:
7250
+ return "unknown";
7251
+ }
7252
+ }
6404
7253
  function buildComposedResult(files, fileIRs, config, errors, warnings, options = {}) {
6405
7254
  const usePhase2 = options.usePhase2Modules !== false;
6406
7255
  const workflowIRs = [];
6407
7256
  const modelIRs = [];
7257
+ const actionDefinitionIRs = [];
6408
7258
  const serverActionEntries = [];
6409
7259
  let modelResults;
6410
7260
  let actionResult;
@@ -6443,6 +7293,17 @@ function buildComposedResult(files, fileIRs, config, errors, warnings, options =
6443
7293
  }
6444
7294
  }
6445
7295
  }
7296
+ for (const [filename, source] of Object.entries(files)) {
7297
+ if (isActionFile(filename)) {
7298
+ const result = extractAction(source, filename);
7299
+ if (result) {
7300
+ actionDefinitionIRs.push(result.ir);
7301
+ for (const w of result.warnings) {
7302
+ warnings.push({ file: filename, message: w, severity: "warning" });
7303
+ }
7304
+ }
7305
+ }
7306
+ }
6446
7307
  if (usePhase2) {
6447
7308
  const modelFiles = {};
6448
7309
  for (const [filename, source] of Object.entries(files)) {
@@ -6493,7 +7354,11 @@ function buildComposedResult(files, fileIRs, config, errors, warnings, options =
6493
7354
  });
6494
7355
  }
6495
7356
  }
6496
- const childDefinitions = [...workflowIRs, ...modelIRs];
7357
+ const childDefinitions = [
7358
+ ...workflowIRs,
7359
+ ...modelIRs,
7360
+ ...actionDefinitionIRs
7361
+ ];
6497
7362
  let routeTable = [];
6498
7363
  if (routeResult) {
6499
7364
  routeTable = routeResult.routes.map((r) => ({
@@ -6569,6 +7434,22 @@ function buildComposedResult(files, fileIRs, config, errors, warnings, options =
6569
7434
  }
6570
7435
  }
6571
7436
  }
7437
+ if (options.resolvedModules && options.resolvedModules.length > 0) {
7438
+ for (const mod of options.resolvedModules) {
7439
+ if (mod.serverActions && mod.serverActions.length > 0) {
7440
+ for (const action of mod.serverActions) {
7441
+ const namespacedName = `${mod.slug}:${action.name}`;
7442
+ if (!serverActionEntries.some((a) => a.name === namespacedName)) {
7443
+ serverActionEntries.push({
7444
+ ...action,
7445
+ name: namespacedName,
7446
+ sourceFile: `${mod.slug}/${action.sourceFile}`
7447
+ });
7448
+ }
7449
+ }
7450
+ }
7451
+ }
7452
+ }
6572
7453
  const allIRs = Object.values(fileIRs);
6573
7454
  const parentIR = mergeIRs(allIRs, config);
6574
7455
  if (!parentIR.metadata) parentIR.metadata = {};
@@ -6581,6 +7462,7 @@ function buildComposedResult(files, fileIRs, config, errors, warnings, options =
6581
7462
  parentMeta.composition = {
6582
7463
  workflowCount: workflowIRs.length,
6583
7464
  modelCount: modelIRs.length,
7465
+ actionCount: actionDefinitionIRs.length,
6584
7466
  serverActionCount: serverActionEntries.length,
6585
7467
  routeCount: routeTable.length,
6586
7468
  componentCount: Object.keys(componentDefinitions).length,
@@ -6612,6 +7494,20 @@ function buildComposedResult(files, fileIRs, config, errors, warnings, options =
6612
7494
  if (manifest?.contributions) {
6613
7495
  parentMeta.slot_contributions = manifest.contributions;
6614
7496
  }
7497
+ if (manifest?.configSchema) {
7498
+ parentMeta.configSchema = manifest.configSchema;
7499
+ }
7500
+ if (manifest?.dependencies) {
7501
+ const depConfigs = {};
7502
+ for (const dep of manifest.dependencies) {
7503
+ if (dep.config) {
7504
+ depConfigs[dep.slug] = dep.config;
7505
+ }
7506
+ }
7507
+ if (Object.keys(depConfigs).length > 0) {
7508
+ parentMeta.module_configs = depConfigs;
7509
+ }
7510
+ }
6615
7511
  const compilableFiles = Object.keys(files).filter(isCompilableFile);
6616
7512
  const importLinks = resolveImportLinks(files, compilableFiles);
6617
7513
  const pageExperiences = {};
@@ -6726,6 +7622,7 @@ function buildComposedResult(files, fileIRs, config, errors, warnings, options =
6726
7622
  }
6727
7623
  }
6728
7624
  }
7625
+ const typeStubs = generateModuleTypeStubs(childDefinitions, modelResults);
6729
7626
  return {
6730
7627
  ir: parentIR,
6731
7628
  childDefinitions,
@@ -6739,7 +7636,8 @@ function buildComposedResult(files, fileIRs, config, errors, warnings, options =
6739
7636
  importLinks,
6740
7637
  modelResults,
6741
7638
  actionResult,
6742
- routeResult
7639
+ routeResult,
7640
+ typeStubs
6743
7641
  };
6744
7642
  }
6745
7643
  function compileProject(files, options = {}) {
@@ -6783,6 +7681,7 @@ var init_project_compiler = __esm({
6783
7681
  init_model_compiler();
6784
7682
  init_route_extractor();
6785
7683
  init_action_compiler();
7684
+ init_action_extractor();
6786
7685
  init_incremental_compiler();
6787
7686
  IncrementalProjectCompiler = class {
6788
7687
  constructor() {
@@ -7339,10 +8238,10 @@ ${output}`);
7339
8238
  fileMap[rel] = (0, import_fs3.readFileSync)(f, "utf-8");
7340
8239
  }
7341
8240
  (0, import_fs3.mkdirSync)(outDir, { recursive: true });
7342
- const result = compileProject2(fileMap, { mode });
7343
- const errors = result.errors.filter((e) => e.severity === "error");
7344
- const warnings = result.errors.filter((e) => e.severity === "warning");
7345
- const definitions2 = [result.ir];
8241
+ const result2 = compileProject2(fileMap, { mode });
8242
+ const errors = result2.errors.filter((e) => e.severity === "error");
8243
+ const warnings = result2.errors.filter((e) => e.severity === "warning");
8244
+ const definitions2 = [result2.ir];
7346
8245
  const errorDetails2 = [];
7347
8246
  for (const err of errors) {
7348
8247
  errorDetails2.push({ file: err.file, message: err.message, line: err.line });
@@ -7351,11 +8250,11 @@ ${output}`);
7351
8250
  for (const warn of warnings) {
7352
8251
  console.warn(` ! ${warn.file}${warn.line ? `:${warn.line}` : ""} ${warn.message}`);
7353
8252
  }
7354
- const irPath = (0, import_path2.join)(outDir, `${result.ir.slug}.workflow.json`);
7355
- (0, import_fs3.writeFileSync)(irPath, JSON.stringify(result.ir, null, 2), "utf-8");
8253
+ const irPath = (0, import_path2.join)(outDir, `${result2.ir.slug}.workflow.json`);
8254
+ (0, import_fs3.writeFileSync)(irPath, JSON.stringify(result2.ir, null, 2), "utf-8");
7356
8255
  console.log(` + ${(0, import_path2.basename)(irPath)}`);
7357
- const seenSlugs = /* @__PURE__ */ new Set([result.ir.slug]);
7358
- for (const child of result.childDefinitions) {
8256
+ const seenSlugs = /* @__PURE__ */ new Set([result2.ir.slug]);
8257
+ for (const child of result2.childDefinitions) {
7359
8258
  if (seenSlugs.has(child.slug)) continue;
7360
8259
  seenSlugs.add(child.slug);
7361
8260
  definitions2.push(child);
@@ -7385,14 +8284,14 @@ ${output}`);
7385
8284
  for (const file of allFiles) {
7386
8285
  try {
7387
8286
  const code = (0, import_fs3.readFileSync)(file, "utf-8");
7388
- const result = (0, import_core5.transformSync)(code, {
8287
+ const result2 = (0, import_core5.transformSync)(code, {
7389
8288
  filename: file,
7390
8289
  plugins: [[babelPlugin, { mode }]],
7391
8290
  parserOpts: { plugins: ["jsx", "typescript"], attachComment: true }
7392
8291
  });
7393
- const ir = result?.metadata?.mindmatrixIR;
7394
- const definition = result?.metadata?.mindmatrixDefinition;
7395
- const canonical = result?.metadata?.mindmatrixCanonical;
8292
+ const ir = result2?.metadata?.mindmatrixIR;
8293
+ const definition = result2?.metadata?.mindmatrixDefinition;
8294
+ const canonical = result2?.metadata?.mindmatrixCanonical;
7396
8295
  if (ir) {
7397
8296
  definitions.push(ir);
7398
8297
  const irErrors = ir.metadata?.errors;
@@ -7457,7 +8356,37 @@ ${output}`);
7457
8356
  }
7458
8357
  console.log(`
7459
8358
  [mindmatrix-react] Compiled ${compiled} workflows, ${errorCount} errors, ${warningCount} warnings`);
7460
- return { compiled, errors: errorCount, warnings: warningCount, definitions, errorDetails };
8359
+ const result = { compiled, errors: errorCount, warnings: warningCount, definitions, errorDetails };
8360
+ if (options.watch) {
8361
+ await startWatchMode(options);
8362
+ }
8363
+ return result;
8364
+ }
8365
+ async function startWatchMode(options) {
8366
+ const { watch: fsWatch } = await import("fs");
8367
+ const srcDir = options.src ?? "src/workflows";
8368
+ let debounce = null;
8369
+ console.log(`
8370
+ [mindmatrix-react] Watching ${srcDir} for changes... (Ctrl+C to stop)
8371
+ `);
8372
+ fsWatch(srcDir, { recursive: true }, (_event, filename) => {
8373
+ if (!filename) return;
8374
+ if (!filename.match(/\.(tsx?|jsx?)$/)) return;
8375
+ if (filename.includes("node_modules") || filename.includes("dist")) return;
8376
+ if (debounce) clearTimeout(debounce);
8377
+ debounce = setTimeout(async () => {
8378
+ const ts = (/* @__PURE__ */ new Date()).toLocaleTimeString();
8379
+ console.log(`
8380
+ [${ts}] Change detected: ${filename} \u2014 recompiling...`);
8381
+ try {
8382
+ await build({ ...options, watch: false, skipTypeCheck: true });
8383
+ } catch (e) {
8384
+ console.error(`[mindmatrix-react] Rebuild failed:`, e.message);
8385
+ }
8386
+ }, 300);
8387
+ });
8388
+ return new Promise(() => {
8389
+ });
7461
8390
  }
7462
8391
 
7463
8392
  // src/dev-server.ts