@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
@@ -0,0 +1,3446 @@
1
+ // src/decompiler/index.ts
2
+ import * as t4 from "@babel/types";
3
+ import generate from "@babel/generator";
4
+
5
+ // src/decompiler/ast-builder.ts
6
+ import * as t2 from "@babel/types";
7
+ import { parseExpression } from "@babel/parser";
8
+
9
+ // src/decompiler/sx-emitter.ts
10
+ import * as t from "@babel/types";
11
+ function isTRBL(v) {
12
+ if (typeof v !== "object" || v === null) return false;
13
+ const obj = v;
14
+ return typeof obj.top === "number" && typeof obj.right === "number" && typeof obj.bottom === "number" && typeof obj.left === "number";
15
+ }
16
+ function isFourCorners(v) {
17
+ if (typeof v !== "object" || v === null) return false;
18
+ const obj = v;
19
+ return typeof obj.topLeft === "number" && typeof obj.topRight === "number" && typeof obj.bottomRight === "number" && typeof obj.bottomLeft === "number";
20
+ }
21
+ function isTokenRef(v) {
22
+ if (typeof v !== "object" || v === null) return false;
23
+ return v.kind === "token-ref";
24
+ }
25
+ function emitSpacingShorthand(prefix, trbl) {
26
+ const { top, right, bottom, left } = trbl;
27
+ if (top === right && right === bottom && bottom === left) {
28
+ return [prop(prefix, top)];
29
+ }
30
+ if (top === bottom && left === right) {
31
+ return [
32
+ prop(`${prefix}y`, top),
33
+ prop(`${prefix}x`, left)
34
+ ];
35
+ }
36
+ return [
37
+ prop(`${prefix}t`, top),
38
+ prop(`${prefix}r`, right),
39
+ prop(`${prefix}b`, bottom),
40
+ prop(`${prefix}l`, left)
41
+ ];
42
+ }
43
+ function emitRadiusShorthand(corners) {
44
+ const { topLeft, topRight, bottomRight, bottomLeft } = corners;
45
+ if (topLeft === topRight && topRight === bottomRight && bottomRight === bottomLeft) {
46
+ return [prop("rounded", topLeft)];
47
+ }
48
+ return [
49
+ prop("roundedTL", topLeft),
50
+ prop("roundedTR", topRight),
51
+ prop("roundedBR", bottomRight),
52
+ prop("roundedBL", bottomLeft)
53
+ ];
54
+ }
55
+ function emitColorValue(color) {
56
+ if (isTokenRef(color)) {
57
+ return t.stringLiteral(`token:${color.name}`);
58
+ }
59
+ if (typeof color === "string") {
60
+ return t.stringLiteral(color);
61
+ }
62
+ if (typeof color === "object" && color !== null) {
63
+ const c = color;
64
+ if (typeof c.r === "number" && typeof c.g === "number" && typeof c.b === "number") {
65
+ const a = typeof c.a === "number" ? c.a : 1;
66
+ if (a === 1) {
67
+ const hex = `#${hexByte(c.r)}${hexByte(c.g)}${hexByte(c.b)}`;
68
+ return t.stringLiteral(hex);
69
+ }
70
+ return t.stringLiteral(`rgba(${c.r}, ${c.g}, ${c.b}, ${a})`);
71
+ }
72
+ }
73
+ return t.stringLiteral("inherit");
74
+ }
75
+ function hexByte(n) {
76
+ return Math.round(n).toString(16).padStart(2, "0");
77
+ }
78
+ function prop(key, value) {
79
+ return t.objectProperty(t.identifier(key), valueToExpression(value));
80
+ }
81
+ function valueToExpression(value) {
82
+ if (typeof value === "string") return t.stringLiteral(value);
83
+ if (typeof value === "number") return t.numericLiteral(value);
84
+ if (typeof value === "boolean") return t.booleanLiteral(value);
85
+ if (value === null) return t.nullLiteral();
86
+ if (value === void 0) return t.identifier("undefined");
87
+ if (Array.isArray(value)) {
88
+ return t.arrayExpression(value.map((v) => valueToExpression(v)));
89
+ }
90
+ if (typeof value === "object") {
91
+ const entries = Object.entries(value);
92
+ return t.objectExpression(
93
+ entries.map(
94
+ ([k, v]) => t.objectProperty(t.identifier(k), valueToExpression(v))
95
+ )
96
+ );
97
+ }
98
+ return t.identifier("undefined");
99
+ }
100
+ var STATE_TO_SX_KEY = {
101
+ hovered: "hover",
102
+ pressed: "pressed",
103
+ focused: "focus",
104
+ selected: "selected",
105
+ disabled: "disabled"
106
+ };
107
+ function emitSxProp(style) {
108
+ if (!style || typeof style !== "object") return null;
109
+ const props = [];
110
+ if (style.padding && isTRBL(style.padding)) {
111
+ props.push(...emitSpacingShorthand("p", style.padding));
112
+ }
113
+ if (style.margin && isTRBL(style.margin)) {
114
+ props.push(...emitSpacingShorthand("m", style.margin));
115
+ }
116
+ if (style.backgroundColor) {
117
+ props.push(t.objectProperty(
118
+ t.identifier("bg"),
119
+ emitColorValue(style.backgroundColor)
120
+ ));
121
+ }
122
+ if (style.borderRadius && isFourCorners(style.borderRadius)) {
123
+ props.push(...emitRadiusShorthand(style.borderRadius));
124
+ }
125
+ if (typeof style.gap === "number") {
126
+ props.push(prop("gap", style.gap));
127
+ }
128
+ if (typeof style.flexDirection === "string") {
129
+ props.push(prop("direction", style.flexDirection));
130
+ }
131
+ if (typeof style.justifyContent === "string") {
132
+ props.push(prop("justify", style.justifyContent));
133
+ }
134
+ if (typeof style.alignItems === "string") {
135
+ props.push(prop("align", style.alignItems));
136
+ }
137
+ if (style.width !== void 0) props.push(prop("w", style.width));
138
+ if (style.height !== void 0) props.push(prop("h", style.height));
139
+ if (style.minWidth !== void 0) props.push(prop("minW", style.minWidth));
140
+ if (style.minHeight !== void 0) props.push(prop("minH", style.minHeight));
141
+ if (style.maxWidth !== void 0) props.push(prop("maxW", style.maxWidth));
142
+ if (style.maxHeight !== void 0) props.push(prop("maxH", style.maxHeight));
143
+ if (typeof style.opacity === "number") {
144
+ props.push(prop("opacity", style.opacity));
145
+ }
146
+ if (style.color) {
147
+ props.push(t.objectProperty(
148
+ t.identifier("color"),
149
+ emitColorValue(style.color)
150
+ ));
151
+ }
152
+ if (typeof style.overflow === "string") {
153
+ props.push(prop("overflow", style.overflow));
154
+ }
155
+ if (typeof style.position === "string") {
156
+ props.push(prop("position", style.position));
157
+ }
158
+ if (typeof style.states === "object" && style.states !== null) {
159
+ for (const [state, override] of Object.entries(style.states)) {
160
+ const sxKey = STATE_TO_SX_KEY[state] || state;
161
+ if (typeof override === "object" && override !== null) {
162
+ const subProp = emitSxProp(override);
163
+ if (subProp && t.isJSXExpressionContainer(subProp.value) && t.isObjectExpression(subProp.value.expression)) {
164
+ props.push(t.objectProperty(
165
+ t.identifier(sxKey),
166
+ subProp.value.expression
167
+ ));
168
+ }
169
+ }
170
+ }
171
+ }
172
+ if (props.length === 0) return null;
173
+ return t.jsxAttribute(
174
+ t.jsxIdentifier("sx"),
175
+ t.jsxExpressionContainer(t.objectExpression(props))
176
+ );
177
+ }
178
+
179
+ // src/decompiler/ast-builder.ts
180
+ function buildSymbolTable(fields, metadata, transitions, experience) {
181
+ const locals = /* @__PURE__ */ new Map();
182
+ const setters = /* @__PURE__ */ new Map();
183
+ const queries = /* @__PURE__ */ new Map();
184
+ const transMap = /* @__PURE__ */ new Map();
185
+ for (const field of fields) {
186
+ if (field.computed) continue;
187
+ const camel = toCamelCase(field.name);
188
+ locals.set(field.name, camel);
189
+ setters.set(field.name, setterName(field.name));
190
+ }
191
+ const dataSources = metadata?.dataSources;
192
+ if (dataSources) {
193
+ for (const ds of dataSources) {
194
+ if (ds.type !== "workflow") continue;
195
+ const varName = toCamelCase(ds.name.replace(/-/g, "_"));
196
+ queries.set(ds.name, varName);
197
+ queries.set(ds.name.replace(/-/g, "_"), varName);
198
+ }
199
+ }
200
+ for (const trans of transitions) {
201
+ transMap.set(trans.name, toCamelCase(trans.name));
202
+ }
203
+ if (experience) {
204
+ collectLocalDefaults(experience, locals, setters);
205
+ }
206
+ return { locals, setters, queries, transitions: transMap };
207
+ }
208
+ function collectLocalDefaults(node, locals, setters) {
209
+ if (node.config?.localDefaults && typeof node.config.localDefaults === "object") {
210
+ for (const key of Object.keys(node.config.localDefaults)) {
211
+ if (key.includes(".")) continue;
212
+ if (!locals.has(key)) {
213
+ const camel = toCamelCase(key);
214
+ locals.set(key, camel);
215
+ setters.set(key, setterName(key));
216
+ }
217
+ }
218
+ }
219
+ if (node.children) {
220
+ for (const child of node.children) {
221
+ collectLocalDefaults(child, locals, setters);
222
+ }
223
+ }
224
+ }
225
+ var REACT_ATOMS = /* @__PURE__ */ new Set([
226
+ "Stack",
227
+ "Row",
228
+ "Column",
229
+ "Grid",
230
+ "Divider",
231
+ "Spacer",
232
+ "Text",
233
+ "Heading",
234
+ "Field",
235
+ "Image",
236
+ "Badge",
237
+ "Icon",
238
+ "Button",
239
+ "Link",
240
+ "Show",
241
+ "Each",
242
+ "Card",
243
+ "Tabs",
244
+ "Accordion",
245
+ "Section",
246
+ "Modal",
247
+ "TextInput",
248
+ "Select",
249
+ "Markdown",
250
+ "ScrollArea",
251
+ "Canvas3D",
252
+ "DataGrid",
253
+ "AnimatedBox",
254
+ "ServerGrid",
255
+ "Chart",
256
+ "MetricCard",
257
+ "Slot"
258
+ ]);
259
+ function resolveIRTokens(expr, symbols) {
260
+ let result = expr;
261
+ const exprMatch = result.match(/^\$expr\((.+)\)$/s);
262
+ if (exprMatch) {
263
+ return resolveIRTokens(exprMatch[1], symbols);
264
+ }
265
+ const seqMatch = result.match(/^\$action\.seq\((.+)\)$/);
266
+ if (seqMatch) {
267
+ const actions = splitTopLevelArgs(seqMatch[1]);
268
+ const resolved = actions.map((a) => resolveIRTokens(a.trim(), symbols));
269
+ return `() => { ${resolved.join("; ")}; }`;
270
+ }
271
+ while (result.includes("$action.setLocal(")) {
272
+ const updated = resolveOneSetLocal(result, symbols);
273
+ if (updated === result) break;
274
+ result = updated;
275
+ }
276
+ result = result.replace(/\$action\.transition\("([^"]+)"\)/g, (_, name) => {
277
+ const varName = symbols.transitions.get(name) || toCamelCase(name);
278
+ return `${varName}()`;
279
+ });
280
+ result = result.replace(/\$instance\.\[/g, "[");
281
+ result = result.replace(/\$instance\??\.(?:state_data\.)?(\w+)/g, (_, field) => {
282
+ return symbols.queries.get(field) || toCamelCase(field);
283
+ });
284
+ result = result.replace(/\$local\.(\w+)/g, (_, field) => {
285
+ return symbols.locals.get(field) || toCamelCase(field);
286
+ });
287
+ const concatMatch = result.match(/^\$fn\.concat\((.+)\)$/);
288
+ if (concatMatch) {
289
+ const parts = splitTopLevelArgs(concatMatch[1]);
290
+ return "`" + parts.map((p) => `\${${p.trim()}}`).join("") + "`";
291
+ }
292
+ const notMatch = result.match(/^not\((.+)\)$/);
293
+ if (notMatch) {
294
+ return `!(${resolveIRTokens(notMatch[1], symbols)})`;
295
+ }
296
+ return result;
297
+ }
298
+ function resolveOneSetLocal(expr, symbols) {
299
+ const prefix = "$action.setLocal(";
300
+ const idx = expr.indexOf(prefix);
301
+ if (idx === -1) return expr;
302
+ let depth = 0;
303
+ let end = -1;
304
+ for (let i = idx + prefix.length - 1; i < expr.length; i++) {
305
+ if (expr[i] === "(") depth++;
306
+ else if (expr[i] === ")") {
307
+ depth--;
308
+ if (depth === 0) {
309
+ end = i;
310
+ break;
311
+ }
312
+ }
313
+ }
314
+ if (end === -1) return expr;
315
+ const inner = expr.substring(idx + prefix.length, end);
316
+ const fieldMatch = inner.match(/^"([^"]+)",\s*/);
317
+ if (!fieldMatch) return expr;
318
+ const field = fieldMatch[1];
319
+ const value = inner.substring(fieldMatch[0].length);
320
+ const setter = symbols.setters.get(field) || setterName(field);
321
+ const resolvedValue = resolveIRTokens(value.trim(), symbols);
322
+ return expr.substring(0, idx) + `${setter}(${resolvedValue})` + expr.substring(end + 1);
323
+ }
324
+ function splitTopLevelArgs(input) {
325
+ const result = [];
326
+ let depth = 0;
327
+ let inStr = null;
328
+ let current = "";
329
+ for (let i = 0; i < input.length; i++) {
330
+ const ch = input[i];
331
+ if ((ch === '"' || ch === "'" || ch === "`") && (i === 0 || input[i - 1] !== "\\")) {
332
+ if (inStr === ch) inStr = null;
333
+ else if (!inStr) inStr = ch;
334
+ }
335
+ if (!inStr) {
336
+ if (ch === "(" || ch === "[" || ch === "{") depth++;
337
+ else if (ch === ")" || ch === "]" || ch === "}") depth--;
338
+ else if (ch === "," && depth === 0) {
339
+ result.push(current);
340
+ current = "";
341
+ continue;
342
+ }
343
+ }
344
+ current += ch;
345
+ }
346
+ if (current.trim()) result.push(current);
347
+ return result;
348
+ }
349
+ function emitBindingExpression(expr, symbols) {
350
+ if (expr === "[Expression]" || expr === '"[Expression]"') {
351
+ return t2.nullLiteral();
352
+ }
353
+ const resolved = resolveIRTokens(expr, symbols);
354
+ const fieldsMatch = resolved.match(/^fields\.(\w+)$/);
355
+ if (fieldsMatch) {
356
+ return t2.identifier(toCamelCase(fieldsMatch[1]));
357
+ }
358
+ const setFieldMatch = resolved.match(/^set_field\((\w+),\s*(.+)\)$/);
359
+ if (setFieldMatch) {
360
+ const setter = setterName(setFieldMatch[1]);
361
+ return t2.callExpression(
362
+ t2.identifier(setter),
363
+ [emitBindingExpression(setFieldMatch[2].trim(), symbols)]
364
+ );
365
+ }
366
+ if (/^\w+$/.test(resolved)) {
367
+ return t2.identifier(toCamelCase(resolved));
368
+ }
369
+ if (/^[\w$]+(?:\??\.[\w$]+)+$/.test(resolved)) {
370
+ const parts = resolved.split(/(\??\.)/).filter(Boolean);
371
+ let node = t2.identifier(parts[0]);
372
+ for (let i = 1; i < parts.length; i += 2) {
373
+ const isOptional = parts[i] === "?.";
374
+ const prop2 = parts[i + 1];
375
+ if (!prop2) break;
376
+ node = t2.optionalMemberExpression(
377
+ node,
378
+ t2.identifier(prop2),
379
+ false,
380
+ isOptional
381
+ );
382
+ }
383
+ return node;
384
+ }
385
+ if (/[=<>!+\-*/%&|^~?:,()[\]{}]/.test(resolved)) {
386
+ try {
387
+ return parseExpression(resolved, {
388
+ plugins: ["typescript", "jsx"]
389
+ });
390
+ } catch {
391
+ return t2.stringLiteral(resolved);
392
+ }
393
+ }
394
+ return t2.stringLiteral(resolved);
395
+ }
396
+ function emitConfigAttribute(key, value) {
397
+ if (typeof value === "string") {
398
+ if (value.includes('"') || value.includes("\\") || value.includes("\n")) {
399
+ return t2.jsxAttribute(
400
+ t2.jsxIdentifier(key),
401
+ t2.jsxExpressionContainer(t2.stringLiteral(value))
402
+ );
403
+ }
404
+ return t2.jsxAttribute(
405
+ t2.jsxIdentifier(key),
406
+ t2.stringLiteral(value)
407
+ );
408
+ }
409
+ if (typeof value === "boolean" && value === true) {
410
+ return t2.jsxAttribute(t2.jsxIdentifier(key), null);
411
+ }
412
+ return t2.jsxAttribute(
413
+ t2.jsxIdentifier(key),
414
+ t2.jsxExpressionContainer(valueToExpression(value))
415
+ );
416
+ }
417
+ function toCamelCase(str) {
418
+ return str.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
419
+ }
420
+ function setterName(snakeName) {
421
+ const camel = toCamelCase(snakeName);
422
+ return `set${camel.charAt(0).toUpperCase()}${camel.slice(1)}`;
423
+ }
424
+ function buildJSXTree(node, imports, symbols) {
425
+ if (!node.component) {
426
+ const fragmentChildren = (node.children || []).map(
427
+ (child) => buildJSXTree(child, imports, symbols)
428
+ );
429
+ return t2.jsxFragment(
430
+ t2.jsxOpeningFragment(),
431
+ t2.jsxClosingFragment(),
432
+ fragmentChildren
433
+ );
434
+ }
435
+ const componentName = node.component;
436
+ if (REACT_ATOMS.has(componentName)) {
437
+ addImport(imports, "@mindmatrix/react", componentName);
438
+ }
439
+ const attributes = [];
440
+ if (node.config) {
441
+ for (const [key, value] of Object.entries(node.config)) {
442
+ if (key === "localDefaults") continue;
443
+ attributes.push(emitConfigAttribute(key, value));
444
+ }
445
+ }
446
+ if (node.bindings) {
447
+ for (const [key, expr] of Object.entries(node.bindings)) {
448
+ let emitted = emitBindingExpression(expr, symbols);
449
+ if (isEventHandlerKey(key) && !t2.isArrowFunctionExpression(emitted) && !t2.isFunctionExpression(emitted)) {
450
+ emitted = t2.arrowFunctionExpression([], emitted);
451
+ }
452
+ attributes.push(
453
+ t2.jsxAttribute(
454
+ t2.jsxIdentifier(key),
455
+ t2.jsxExpressionContainer(emitted)
456
+ )
457
+ );
458
+ }
459
+ }
460
+ if (node.style && typeof node.style === "object" && Object.keys(node.style).length > 0) {
461
+ const sxAttr = emitSxProp(node.style);
462
+ if (sxAttr) attributes.push(sxAttr);
463
+ }
464
+ const jsxChildren = [];
465
+ if (node.children) {
466
+ for (const child of node.children) {
467
+ jsxChildren.push(buildJSXTree(child, imports, symbols));
468
+ }
469
+ }
470
+ const isSelfClosing = jsxChildren.length === 0;
471
+ const element = t2.jsxElement(
472
+ t2.jsxOpeningElement(
473
+ t2.jsxIdentifier(componentName),
474
+ attributes,
475
+ isSelfClosing
476
+ ),
477
+ isSelfClosing ? null : t2.jsxClosingElement(t2.jsxIdentifier(componentName)),
478
+ jsxChildren,
479
+ isSelfClosing
480
+ );
481
+ if (node.visible_when) {
482
+ addImport(imports, "@mindmatrix/react", "Show");
483
+ return t2.jsxElement(
484
+ t2.jsxOpeningElement(
485
+ t2.jsxIdentifier("Show"),
486
+ [
487
+ t2.jsxAttribute(
488
+ t2.jsxIdentifier("when"),
489
+ t2.jsxExpressionContainer(emitBindingExpression(node.visible_when, symbols))
490
+ )
491
+ ],
492
+ false
493
+ ),
494
+ t2.jsxClosingElement(t2.jsxIdentifier("Show")),
495
+ [element],
496
+ false
497
+ );
498
+ }
499
+ return element;
500
+ }
501
+ function isEventHandlerKey(key) {
502
+ return /^on[A-Z]/.test(key);
503
+ }
504
+ function addImport(tracker, source, name) {
505
+ if (!tracker.has(source)) tracker.set(source, /* @__PURE__ */ new Set());
506
+ tracker.get(source).add(name);
507
+ }
508
+
509
+ // src/decompiler/state-emitter.ts
510
+ import * as t3 from "@babel/types";
511
+ function toCamelCase2(str) {
512
+ return str.replace(/[-_]([a-z])/g, (_, c) => c.toUpperCase());
513
+ }
514
+ function toPascalCase(str) {
515
+ const camel = toCamelCase2(str);
516
+ return camel.charAt(0).toUpperCase() + camel.slice(1);
517
+ }
518
+ function fieldTypeAnnotation(field) {
519
+ const f = field;
520
+ const validation = f.validation;
521
+ const options = validation?.options || f.metadata?.options || f.options;
522
+ if (options && Array.isArray(options) && options.length > 0 && (field.type === "select" || field.type === "text")) {
523
+ return t3.tsUnionType(
524
+ options.map((o) => t3.tsLiteralType(t3.stringLiteral(String(o))))
525
+ );
526
+ }
527
+ switch (field.type) {
528
+ case "text":
529
+ case "rich_text":
530
+ case "email":
531
+ case "url":
532
+ case "phone":
533
+ case "color":
534
+ return t3.tsStringKeyword();
535
+ case "number":
536
+ case "currency":
537
+ case "percentage":
538
+ case "rating":
539
+ case "duration":
540
+ case "auto_number":
541
+ return t3.tsNumberKeyword();
542
+ case "boolean":
543
+ return t3.tsBooleanKeyword();
544
+ case "date":
545
+ case "datetime":
546
+ case "created_at":
547
+ case "updated_at":
548
+ return t3.tsTypeReference(t3.identifier("Date"));
549
+ case "select":
550
+ return t3.tsStringKeyword();
551
+ case "multi_select":
552
+ return t3.tsArrayType(t3.tsStringKeyword());
553
+ // string[]
554
+ case "json":
555
+ return null;
556
+ // Inferred from default
557
+ default:
558
+ return null;
559
+ }
560
+ }
561
+ function emitFieldDeclarations(fields, imports) {
562
+ if (fields.length === 0) return [];
563
+ addImport2(imports, "@mindmatrix/react", "useState");
564
+ const statements = [];
565
+ for (const field of fields) {
566
+ if (field.computed) continue;
567
+ const camelName = toCamelCase2(field.name);
568
+ const setter = `set${toPascalCase(field.name)}`;
569
+ const defaultExpr = field.default_value !== void 0 ? valueToExpression(field.default_value) : inferDefaultFromType(field.type);
570
+ const args = [defaultExpr];
571
+ if (field.state_home?.scope === "ephemeral") {
572
+ args.push(t3.objectExpression([
573
+ t3.objectProperty(t3.identifier("ephemeral"), t3.booleanLiteral(true))
574
+ ]));
575
+ }
576
+ const declaration = t3.variableDeclaration("const", [
577
+ t3.variableDeclarator(
578
+ t3.arrayPattern([
579
+ t3.identifier(camelName),
580
+ t3.identifier(setter)
581
+ ]),
582
+ t3.callExpression(t3.identifier("useState"), args)
583
+ )
584
+ ]);
585
+ if (field.default_value !== null) {
586
+ const tsType = fieldTypeAnnotation(field);
587
+ if (tsType) {
588
+ const callExpr = declaration.declarations[0].init;
589
+ callExpr.typeParameters = t3.tsTypeParameterInstantiation([tsType]);
590
+ }
591
+ }
592
+ statements.push(declaration);
593
+ }
594
+ return statements;
595
+ }
596
+ function inferDefaultFromType(fieldType) {
597
+ switch (fieldType) {
598
+ case "text":
599
+ case "rich_text":
600
+ case "email":
601
+ case "url":
602
+ case "phone":
603
+ case "color":
604
+ case "select":
605
+ return t3.stringLiteral("");
606
+ case "number":
607
+ case "currency":
608
+ case "percentage":
609
+ case "rating":
610
+ case "duration":
611
+ case "auto_number":
612
+ return t3.numericLiteral(0);
613
+ case "boolean":
614
+ return t3.booleanLiteral(false);
615
+ case "multi_select":
616
+ return t3.arrayExpression([]);
617
+ case "json":
618
+ return t3.objectExpression([]);
619
+ default:
620
+ return t3.nullLiteral();
621
+ }
622
+ }
623
+ function emitStateEffects(states, imports) {
624
+ const statements = [];
625
+ for (const state of states) {
626
+ if (state.on_enter.length > 0) {
627
+ addImport2(imports, "@mindmatrix/react", "useOnEnter");
628
+ statements.push(
629
+ t3.expressionStatement(
630
+ t3.callExpression(t3.identifier("useOnEnter"), [
631
+ t3.stringLiteral(state.name),
632
+ emitActionCallback(state.on_enter)
633
+ ])
634
+ )
635
+ );
636
+ }
637
+ if (state.on_exit.length > 0) {
638
+ addImport2(imports, "@mindmatrix/react", "useOnExit");
639
+ statements.push(
640
+ t3.expressionStatement(
641
+ t3.callExpression(t3.identifier("useOnExit"), [
642
+ t3.stringLiteral(state.name),
643
+ emitActionCallback(state.on_exit)
644
+ ])
645
+ )
646
+ );
647
+ }
648
+ if (state.during.length > 0) {
649
+ addImport2(imports, "@mindmatrix/react", "useWhileIn");
650
+ for (const during of state.during) {
651
+ const args = [
652
+ t3.stringLiteral(state.name)
653
+ ];
654
+ if (during.interval_ms) {
655
+ args.push(t3.numericLiteral(during.interval_ms));
656
+ }
657
+ args.push(emitActionCallback(during.actions));
658
+ statements.push(
659
+ t3.expressionStatement(
660
+ t3.callExpression(t3.identifier("useWhileIn"), args)
661
+ )
662
+ );
663
+ }
664
+ }
665
+ }
666
+ return statements;
667
+ }
668
+ function emitTransitionDeclarations(transitions, imports) {
669
+ if (transitions.length === 0) return [];
670
+ addImport2(imports, "@mindmatrix/react", "useTransition");
671
+ const correctedTransitions = correctFromFields(transitions);
672
+ const statements = [];
673
+ for (const transition of correctedTransitions) {
674
+ const varName = toCamelCase2(transition.name);
675
+ const configProps = [];
676
+ const fromArr = normalizeFrom(transition.from);
677
+ if (fromArr.length === 1) {
678
+ configProps.push(
679
+ t3.objectProperty(t3.identifier("from"), t3.stringLiteral(fromArr[0]))
680
+ );
681
+ } else if (fromArr.length > 1) {
682
+ configProps.push(
683
+ t3.objectProperty(
684
+ t3.identifier("from"),
685
+ t3.arrayExpression(fromArr.map((s) => t3.stringLiteral(s)))
686
+ )
687
+ );
688
+ }
689
+ configProps.push(
690
+ t3.objectProperty(t3.identifier("to"), t3.stringLiteral(transition.to))
691
+ );
692
+ if (transition.conditions && transition.conditions.length > 0) {
693
+ configProps.push(
694
+ t3.objectProperty(
695
+ t3.identifier("when"),
696
+ emitConditionExpression(transition.conditions)
697
+ )
698
+ );
699
+ }
700
+ if (transition.roles && transition.roles.length > 0) {
701
+ configProps.push(
702
+ t3.objectProperty(
703
+ t3.identifier("roles"),
704
+ t3.arrayExpression(transition.roles.map((r) => t3.stringLiteral(r)))
705
+ )
706
+ );
707
+ }
708
+ if (transition.auto) {
709
+ configProps.push(
710
+ t3.objectProperty(t3.identifier("auto"), t3.booleanLiteral(true))
711
+ );
712
+ }
713
+ if (transition.required_fields && transition.required_fields.length > 0) {
714
+ configProps.push(
715
+ t3.objectProperty(
716
+ t3.identifier("requiredFields"),
717
+ t3.arrayExpression(transition.required_fields.map((f) => t3.stringLiteral(f)))
718
+ )
719
+ );
720
+ }
721
+ statements.push(
722
+ t3.variableDeclaration("const", [
723
+ t3.variableDeclarator(
724
+ t3.identifier(varName),
725
+ t3.callExpression(t3.identifier("useTransition"), [
726
+ t3.stringLiteral(transition.name),
727
+ t3.objectExpression(configProps)
728
+ ])
729
+ )
730
+ ])
731
+ );
732
+ }
733
+ return statements;
734
+ }
735
+ function emitActionCallback(actions) {
736
+ const body = [];
737
+ for (const action of actions) {
738
+ const stmt = emitSingleAction(action);
739
+ if (stmt) body.push(stmt);
740
+ }
741
+ if (body.length === 0) {
742
+ body.push(t3.emptyStatement());
743
+ }
744
+ return t3.arrowFunctionExpression([], t3.blockStatement(body));
745
+ }
746
+ function emitSingleAction(action) {
747
+ switch (action.type) {
748
+ case "set_field": {
749
+ if (!action.config.field) return null;
750
+ const setter = `set${toPascalCase(String(action.config.field))}`;
751
+ const expr = action.config.expression ? t3.identifier(String(action.config.expression)) : valueToExpression(action.config.value ?? null);
752
+ return t3.expressionStatement(
753
+ t3.callExpression(t3.identifier(setter), [expr])
754
+ );
755
+ }
756
+ case "log_event":
757
+ case "log": {
758
+ const msg = action.config.message ?? action.config.event ?? action.type;
759
+ return t3.expressionStatement(
760
+ t3.callExpression(
761
+ t3.memberExpression(t3.identifier("console"), t3.identifier("log")),
762
+ [t3.stringLiteral(String(msg))]
763
+ )
764
+ );
765
+ }
766
+ case "emit_event": {
767
+ const eventName = String(action.config.event ?? action.config.name ?? "unknown");
768
+ const args = [t3.stringLiteral(eventName)];
769
+ if (action.config.payload) {
770
+ args.push(valueToExpression(action.config.payload));
771
+ }
772
+ return t3.expressionStatement(
773
+ t3.callExpression(t3.identifier("emitEvent"), args)
774
+ );
775
+ }
776
+ case "call_workflow": {
777
+ const slug = String(action.config.slug ?? action.config.workflow ?? "unknown");
778
+ const args = [t3.stringLiteral(slug)];
779
+ if (action.config.params) {
780
+ args.push(valueToExpression(action.config.params));
781
+ }
782
+ return t3.expressionStatement(
783
+ t3.callExpression(t3.identifier("callWorkflow"), args)
784
+ );
785
+ }
786
+ case "spawn_instance":
787
+ case "spawn_subworkflow": {
788
+ const slug = String(action.config.slug ?? action.config.workflow ?? "unknown");
789
+ const args = [t3.stringLiteral(slug)];
790
+ if (action.config.params || action.config.input) {
791
+ args.push(valueToExpression(action.config.params ?? action.config.input));
792
+ }
793
+ return t3.expressionStatement(
794
+ t3.callExpression(t3.identifier("spawnInstance"), args)
795
+ );
796
+ }
797
+ case "http_request":
798
+ case "webhook":
799
+ case "call_webhook": {
800
+ const url = String(action.config.url ?? "");
801
+ const method = String(action.config.method ?? "POST");
802
+ return t3.expressionStatement(
803
+ t3.callExpression(t3.identifier("fetch"), [
804
+ t3.stringLiteral(url),
805
+ t3.objectExpression([
806
+ t3.objectProperty(t3.identifier("method"), t3.stringLiteral(method))
807
+ ])
808
+ ])
809
+ );
810
+ }
811
+ case "delay": {
812
+ const ms = Number(action.config.duration_ms ?? action.config.delay_ms ?? 1e3);
813
+ return t3.expressionStatement(
814
+ t3.awaitExpression(
815
+ t3.callExpression(
816
+ t3.identifier("delay"),
817
+ [t3.numericLiteral(ms)]
818
+ )
819
+ )
820
+ );
821
+ }
822
+ case "notify":
823
+ case "send_notification": {
824
+ const msg = String(action.config.message ?? action.config.body ?? "");
825
+ return t3.expressionStatement(
826
+ t3.callExpression(t3.identifier("notify"), [t3.stringLiteral(msg)])
827
+ );
828
+ }
829
+ case "noop":
830
+ return null;
831
+ default: {
832
+ const comment = ` ${action.type}(${JSON.stringify(action.config)}) `;
833
+ const voidExpr = t3.unaryExpression("void", t3.numericLiteral(0));
834
+ t3.addComment(voidExpr, "leading", comment, false);
835
+ return t3.expressionStatement(voidExpr);
836
+ }
837
+ }
838
+ }
839
+ function emitConditionExpression(conditions) {
840
+ if (conditions.length === 1) {
841
+ return emitSingleCondition(conditions[0]);
842
+ }
843
+ let result = emitSingleCondition(conditions[0]);
844
+ for (let i = 1; i < conditions.length; i++) {
845
+ result = t3.logicalExpression("&&", result, emitSingleCondition(conditions[i]));
846
+ }
847
+ return result;
848
+ }
849
+ function emitSingleCondition(cond) {
850
+ if (cond.expression) {
851
+ return t3.identifier(cond.expression);
852
+ }
853
+ if (cond.field && cond.operator) {
854
+ const fieldExpr = t3.identifier(toCamelCase2(cond.field));
855
+ const valueExpr = valueToExpression(cond.value);
856
+ const opMap = {
857
+ eq: "===",
858
+ ne: "!==",
859
+ gt: ">",
860
+ gte: ">=",
861
+ lt: "<",
862
+ lte: "<="
863
+ };
864
+ const jsOp = opMap[cond.operator];
865
+ if (jsOp) {
866
+ return t3.binaryExpression(jsOp, fieldExpr, valueExpr);
867
+ }
868
+ if (cond.operator === "is_set") {
869
+ return t3.binaryExpression("!==", fieldExpr, t3.nullLiteral());
870
+ }
871
+ if (cond.operator === "is_empty") {
872
+ return t3.binaryExpression("===", fieldExpr, t3.nullLiteral());
873
+ }
874
+ if (cond.operator === "contains" && typeof cond.value === "string") {
875
+ return t3.callExpression(
876
+ t3.memberExpression(fieldExpr, t3.identifier("includes")),
877
+ [t3.stringLiteral(cond.value)]
878
+ );
879
+ }
880
+ if (cond.operator === "in" && Array.isArray(cond.value)) {
881
+ return t3.callExpression(
882
+ t3.memberExpression(
883
+ t3.arrayExpression(cond.value.map((v) => valueToExpression(v))),
884
+ t3.identifier("includes")
885
+ ),
886
+ [fieldExpr]
887
+ );
888
+ }
889
+ }
890
+ if (cond.OR && cond.OR.length > 0) {
891
+ let result = emitSingleCondition(cond.OR[0]);
892
+ for (let i = 1; i < cond.OR.length; i++) {
893
+ result = t3.logicalExpression("||", result, emitSingleCondition(cond.OR[i]));
894
+ }
895
+ return result;
896
+ }
897
+ if (cond.AND && cond.AND.length > 0) {
898
+ return emitConditionExpression(cond.AND);
899
+ }
900
+ return t3.booleanLiteral(true);
901
+ }
902
+ function emitRoleDeclarations(metadata, imports) {
903
+ const roleDeps = metadata?.roleDependencies;
904
+ if (!roleDeps || roleDeps.length === 0) return [];
905
+ addImport2(imports, "@mindmatrix/react", "useRole");
906
+ const statements = [];
907
+ for (const role of roleDeps) {
908
+ const varName = `is${toPascalCase(role)}`;
909
+ statements.push(
910
+ t3.variableDeclaration("const", [
911
+ t3.variableDeclarator(
912
+ t3.identifier(varName),
913
+ t3.callExpression(t3.identifier("useRole"), [t3.stringLiteral(role)])
914
+ )
915
+ ])
916
+ );
917
+ }
918
+ return statements;
919
+ }
920
+ function emitQueryDeclarations(metadata, imports) {
921
+ const statements = [];
922
+ const dataSources = metadata?.dataSources;
923
+ const modelImports = metadata?.modelImports;
924
+ const addedModelImports = /* @__PURE__ */ new Set();
925
+ if (dataSources && dataSources.length > 0) {
926
+ addImport2(imports, "@mindmatrix/react", "useQuery");
927
+ const usedVarNames = /* @__PURE__ */ new Set();
928
+ for (const ds of dataSources) {
929
+ if (ds.type !== "workflow") continue;
930
+ const slug = ds.slug || ds.name;
931
+ const baseName = ds.name.includes(".") ? ds.name.split(".").pop() : ds.name;
932
+ let varName = toCamelCase2(baseName.replace(/-/g, "_"));
933
+ if (usedVarNames.has(varName)) {
934
+ let suffix = 2;
935
+ while (usedVarNames.has(`${varName}${suffix}`)) suffix++;
936
+ varName = `${varName}${suffix}`;
937
+ }
938
+ usedVarNames.add(varName);
939
+ const modelPath = modelImports?.[slug];
940
+ const modelVarName = modelPath ? `${toCamelCase2(slug.replace(/-/g, "_"))}Model` : void 0;
941
+ if (modelPath && modelVarName && !addedModelImports.has(slug)) {
942
+ addImport2(imports, modelPath, `default as ${modelVarName}`);
943
+ addedModelImports.add(slug);
944
+ }
945
+ const optionProps = [];
946
+ if (ds.pageSize) {
947
+ optionProps.push(
948
+ t3.objectProperty(t3.identifier("limit"), t3.numericLiteral(ds.pageSize))
949
+ );
950
+ }
951
+ if (ds.sort) {
952
+ optionProps.push(
953
+ t3.objectProperty(t3.identifier("orderBy"), t3.stringLiteral(ds.sort))
954
+ );
955
+ }
956
+ if (ds.filter && Object.keys(ds.filter).length > 0) {
957
+ optionProps.push(
958
+ t3.objectProperty(t3.identifier("filter"), valueToExpression(ds.filter))
959
+ );
960
+ }
961
+ if (ds.search) {
962
+ optionProps.push(
963
+ t3.objectProperty(t3.identifier("search"), t3.stringLiteral(ds.search))
964
+ );
965
+ }
966
+ if (ds.groupBy) {
967
+ optionProps.push(
968
+ t3.objectProperty(t3.identifier("groupBy"), t3.stringLiteral(ds.groupBy))
969
+ );
970
+ }
971
+ const queryTarget = modelVarName ? t3.identifier(modelVarName) : t3.stringLiteral(slug);
972
+ const args = [queryTarget];
973
+ if (optionProps.length > 0) {
974
+ args.push(t3.objectExpression(optionProps));
975
+ }
976
+ statements.push(
977
+ t3.variableDeclaration("const", [
978
+ t3.variableDeclarator(
979
+ t3.objectPattern([
980
+ t3.objectProperty(
981
+ t3.identifier("data"),
982
+ t3.identifier(varName)
983
+ )
984
+ ]),
985
+ t3.callExpression(t3.identifier("useQuery"), args)
986
+ )
987
+ ])
988
+ );
989
+ }
990
+ }
991
+ const mutationTargets = metadata?.mutationTargets;
992
+ if (mutationTargets && mutationTargets.length > 0) {
993
+ addImport2(imports, "@mindmatrix/react", "useMutation");
994
+ for (const slug of mutationTargets) {
995
+ const modelPath = modelImports?.[slug];
996
+ const modelVarName2 = modelPath ? `${toCamelCase2(slug.replace(/-/g, "_"))}Model` : void 0;
997
+ if (modelPath && modelVarName2 && !addedModelImports?.has(slug)) {
998
+ addImport2(imports, modelPath, `default as ${modelVarName2}`);
999
+ addedModelImports?.add(slug);
1000
+ }
1001
+ const mutTarget = modelVarName2 ? t3.identifier(modelVarName2) : t3.stringLiteral(slug);
1002
+ const varName = `${toCamelCase2(slug.replace(/-/g, "_"))}Mutation`;
1003
+ statements.push(
1004
+ t3.variableDeclaration("const", [
1005
+ t3.variableDeclarator(
1006
+ t3.identifier(varName),
1007
+ t3.callExpression(t3.identifier("useMutation"), [mutTarget])
1008
+ )
1009
+ ])
1010
+ );
1011
+ }
1012
+ }
1013
+ return statements;
1014
+ }
1015
+ function emitChangeWatchers(metadata, imports) {
1016
+ const watchers = metadata?.fieldWatchers;
1017
+ if (!watchers || watchers.length === 0) return [];
1018
+ addImport2(imports, "@mindmatrix/react", "useOnChange");
1019
+ const statements = [];
1020
+ for (const watcher of watchers) {
1021
+ statements.push(
1022
+ t3.expressionStatement(
1023
+ t3.callExpression(t3.identifier("useOnChange"), [
1024
+ t3.stringLiteral(watcher.field),
1025
+ emitActionCallback(watcher.actions)
1026
+ ])
1027
+ )
1028
+ );
1029
+ }
1030
+ return statements;
1031
+ }
1032
+ function emitEventSubscriptions(onEvent, imports) {
1033
+ if (!onEvent || onEvent.length === 0) return [];
1034
+ addImport2(imports, "@mindmatrix/react", "useOnEvent");
1035
+ const statements = [];
1036
+ for (const sub of onEvent) {
1037
+ const actions = sub.actions.map((a, i) => ({
1038
+ id: `event_${i}`,
1039
+ type: a.type,
1040
+ mode: "auto",
1041
+ config: {
1042
+ ...a.field && { field: a.field },
1043
+ ...a.expression && { expression: a.expression },
1044
+ ...a.message && { message: a.message }
1045
+ }
1046
+ }));
1047
+ statements.push(
1048
+ t3.expressionStatement(
1049
+ t3.callExpression(t3.identifier("useOnEvent"), [
1050
+ t3.stringLiteral(sub.match),
1051
+ emitActionCallback(actions)
1052
+ ])
1053
+ )
1054
+ );
1055
+ }
1056
+ return statements;
1057
+ }
1058
+ function emitTransitionEffects(metadata, imports) {
1059
+ const effects = metadata?.transitionEffects;
1060
+ if (!effects || effects.length === 0) return [];
1061
+ addImport2(imports, "@mindmatrix/react", "useOnTransition");
1062
+ const statements = [];
1063
+ for (const effect of effects) {
1064
+ statements.push(
1065
+ t3.expressionStatement(
1066
+ t3.callExpression(t3.identifier("useOnTransition"), [
1067
+ t3.stringLiteral(effect.transition),
1068
+ emitActionCallback(effect.actions)
1069
+ ])
1070
+ )
1071
+ );
1072
+ }
1073
+ return statements;
1074
+ }
1075
+ function emitLocalDefaultDeclarations(experience, existingFields, imports) {
1076
+ const allDefaults = /* @__PURE__ */ new Map();
1077
+ collectAllLocalDefaults(experience, allDefaults);
1078
+ const existingNames = /* @__PURE__ */ new Set();
1079
+ for (const f of existingFields) {
1080
+ if (f.computed) continue;
1081
+ existingNames.add(f.name);
1082
+ existingNames.add(toCamelCase2(f.name));
1083
+ }
1084
+ const emittedCamelNames = /* @__PURE__ */ new Set();
1085
+ const statements = [];
1086
+ for (const [key, value] of allDefaults) {
1087
+ if (key.includes(".")) continue;
1088
+ if (existingNames.has(key) || existingNames.has(toCamelCase2(key))) continue;
1089
+ const camelName = toCamelCase2(key);
1090
+ if (emittedCamelNames.has(camelName)) continue;
1091
+ emittedCamelNames.add(camelName);
1092
+ addImport2(imports, "@mindmatrix/react", "useState");
1093
+ const setter = `set${toPascalCase(key)}`;
1094
+ let defaultExpr;
1095
+ if (value === void 0 || value === null) {
1096
+ defaultExpr = t3.identifier("undefined");
1097
+ } else if (typeof value === "string" && /^[a-zA-Z]\w*$/.test(value) && value !== key) {
1098
+ defaultExpr = t3.identifier("undefined");
1099
+ } else {
1100
+ defaultExpr = valueToExpression(value);
1101
+ }
1102
+ statements.push(
1103
+ t3.variableDeclaration("const", [
1104
+ t3.variableDeclarator(
1105
+ t3.arrayPattern([
1106
+ t3.identifier(camelName),
1107
+ t3.identifier(setter)
1108
+ ]),
1109
+ t3.callExpression(t3.identifier("useState"), [defaultExpr])
1110
+ )
1111
+ ])
1112
+ );
1113
+ }
1114
+ return statements;
1115
+ }
1116
+ function collectAllLocalDefaults(node, out) {
1117
+ if (node.config?.localDefaults && typeof node.config.localDefaults === "object") {
1118
+ const ld = node.config.localDefaults;
1119
+ for (const [key, value] of Object.entries(ld)) {
1120
+ if (!out.has(key)) out.set(key, value);
1121
+ }
1122
+ }
1123
+ if (node.children) {
1124
+ for (const child of node.children) {
1125
+ collectAllLocalDefaults(child, out);
1126
+ }
1127
+ }
1128
+ }
1129
+ function normalizeFrom(from) {
1130
+ if (Array.isArray(from)) return from;
1131
+ if (typeof from === "string") return [from];
1132
+ return [];
1133
+ }
1134
+ function correctFromFields(transitions) {
1135
+ if (transitions.length <= 1) return transitions;
1136
+ const fromValues = /* @__PURE__ */ new Set();
1137
+ for (const t5 of transitions) {
1138
+ const arr = normalizeFrom(t5.from);
1139
+ for (const f of arr) fromValues.add(f);
1140
+ }
1141
+ if (fromValues.size !== 1) return transitions;
1142
+ const stateNames = /* @__PURE__ */ new Set([...fromValues]);
1143
+ for (const t5 of transitions) {
1144
+ stateNames.add(t5.to);
1145
+ }
1146
+ const allNamesAreStates = transitions.every((t5) => stateNames.has(t5.name));
1147
+ if (!allNamesAreStates) return transitions;
1148
+ return transitions.map((t5) => ({
1149
+ ...t5,
1150
+ from: [t5.name]
1151
+ }));
1152
+ }
1153
+ function addImport2(tracker, source, name) {
1154
+ if (!tracker.has(source)) tracker.set(source, /* @__PURE__ */ new Set());
1155
+ tracker.get(source).add(name);
1156
+ }
1157
+
1158
+ // src/decompiler/project.ts
1159
+ function pascalCase(slug) {
1160
+ return slug.split(/[-_]/).map((part) => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase()).join("");
1161
+ }
1162
+ function camelCase(str) {
1163
+ return str.replace(/[-_]([a-z])/g, (_, c) => c.toUpperCase());
1164
+ }
1165
+ function fieldTypeToTS(fieldType, field) {
1166
+ const options = getFieldOptions(field);
1167
+ if (options && options.length > 0 && (fieldType === "select" || fieldType === "text")) {
1168
+ return options.map((o) => `'${o.replace(/'/g, "\\'")}'`).join(" | ");
1169
+ }
1170
+ switch (fieldType) {
1171
+ case "text":
1172
+ case "rich_text":
1173
+ case "email":
1174
+ case "url":
1175
+ case "phone":
1176
+ case "color":
1177
+ case "select":
1178
+ return "string";
1179
+ case "number":
1180
+ case "currency":
1181
+ case "percentage":
1182
+ case "rating":
1183
+ case "duration":
1184
+ case "auto_number":
1185
+ return "number";
1186
+ case "boolean":
1187
+ return "boolean";
1188
+ case "date":
1189
+ case "datetime":
1190
+ case "created_at":
1191
+ case "updated_at":
1192
+ return "Date";
1193
+ case "multi_select":
1194
+ return "string[]";
1195
+ case "json":
1196
+ return "Record<string, unknown>";
1197
+ case "file":
1198
+ case "image":
1199
+ return "string";
1200
+ // URL
1201
+ case "relation":
1202
+ case "lookup":
1203
+ return "string";
1204
+ // ID reference
1205
+ default:
1206
+ return "unknown";
1207
+ }
1208
+ }
1209
+ function getFieldOptions(field) {
1210
+ if (!field) return null;
1211
+ const f = field;
1212
+ const validation = f.validation;
1213
+ if (validation?.options && Array.isArray(validation.options)) return validation.options;
1214
+ const meta = f.metadata;
1215
+ if (meta?.options && Array.isArray(meta.options)) return meta.options;
1216
+ if (f.options && Array.isArray(f.options)) return f.options;
1217
+ return null;
1218
+ }
1219
+ function generateModelFile(slug, fields) {
1220
+ const typeName = pascalCase(slug);
1221
+ const lines = [
1222
+ `/**`,
1223
+ ` * ${typeName} \u2014 data model interface.`,
1224
+ ` *`,
1225
+ ` * Auto-generated from workflow definition "${slug}".`,
1226
+ ` * Fields: ${fields.length}`,
1227
+ ` */`,
1228
+ ``,
1229
+ `export interface ${typeName} {`
1230
+ ];
1231
+ for (const field of fields) {
1232
+ const tsType = fieldTypeToTS(field.type, field);
1233
+ const optional = field.required ? "" : "?";
1234
+ const comment = field.label ? ` /** ${field.label} */` : "";
1235
+ if (comment) lines.push(` ${comment}`);
1236
+ lines.push(` ${camelCase(field.name)}${optional}: ${tsType};`);
1237
+ }
1238
+ lines.push(`}`);
1239
+ lines.push(``);
1240
+ return lines.join("\n");
1241
+ }
1242
+ function generateStateEnum(slug, states) {
1243
+ if (states.length === 0) return "";
1244
+ const enumName = `${pascalCase(slug)}State`;
1245
+ const lines = [
1246
+ ``,
1247
+ `export enum ${enumName} {`
1248
+ ];
1249
+ for (const state of states) {
1250
+ const enumKey = pascalCase(state.name);
1251
+ lines.push(` ${enumKey} = '${state.name}',`);
1252
+ }
1253
+ lines.push(`}`);
1254
+ lines.push(``);
1255
+ return lines.join("\n");
1256
+ }
1257
+ function extractServerActions(states, transitions) {
1258
+ const seen = /* @__PURE__ */ new Set();
1259
+ const actions = [];
1260
+ const SERVER_ACTION_TYPES2 = /* @__PURE__ */ new Set([
1261
+ "http_request",
1262
+ "webhook",
1263
+ "call_webhook",
1264
+ "notify",
1265
+ "send_notification",
1266
+ "call_workflow",
1267
+ "spawn_instance",
1268
+ "spawn_subworkflow",
1269
+ "emit_event"
1270
+ ]);
1271
+ function collectFromActions(defs) {
1272
+ for (const action of defs) {
1273
+ if (SERVER_ACTION_TYPES2.has(action.type) && !seen.has(action.id)) {
1274
+ seen.add(action.id);
1275
+ const name = actionToFunctionName(action);
1276
+ actions.push({ name, type: action.type, config: action.config });
1277
+ }
1278
+ }
1279
+ }
1280
+ for (const state of states) {
1281
+ collectFromActions(state.on_enter);
1282
+ collectFromActions(state.on_exit);
1283
+ for (const during of state.during) {
1284
+ collectFromActions(during.actions);
1285
+ }
1286
+ }
1287
+ for (const trans of transitions) {
1288
+ collectFromActions(trans.actions);
1289
+ }
1290
+ return actions;
1291
+ }
1292
+ function actionToFunctionName(action) {
1293
+ const slug = action.config.name ?? action.config.event ?? action.config.slug ?? action.type;
1294
+ return camelCase(String(slug).replace(/[^a-zA-Z0-9_-]/g, "-"));
1295
+ }
1296
+ function generateServerActionFile(actions) {
1297
+ const lines = [
1298
+ `/**`,
1299
+ ` * Server actions \u2014 backend handlers for workflow transitions.`,
1300
+ ` *`,
1301
+ ` * These functions run server-side during state transitions.`,
1302
+ ` * Each receives a TransitionContext with instance data and utilities.`,
1303
+ ` */`,
1304
+ ``,
1305
+ `import type { TransitionContext } from '@mindmatrix/react';`,
1306
+ ``
1307
+ ];
1308
+ for (const action of actions) {
1309
+ const comment = actionComment(action.type, action.config);
1310
+ lines.push(`/** ${comment} */`);
1311
+ lines.push(`export async function ${action.name}(ctx: TransitionContext): Promise<void> {`);
1312
+ lines.push(` const { instance, env } = ctx;`);
1313
+ switch (action.type) {
1314
+ case "http_request":
1315
+ case "webhook":
1316
+ case "call_webhook": {
1317
+ const url = String(action.config.url ?? "https://api.example.com/webhook");
1318
+ const method = String(action.config.method ?? "POST");
1319
+ lines.push(` await fetch('${url}', {`);
1320
+ lines.push(` method: '${method}',`);
1321
+ lines.push(` headers: { 'Content-Type': 'application/json' },`);
1322
+ lines.push(` body: JSON.stringify({ instanceId: instance.id }),`);
1323
+ lines.push(` });`);
1324
+ break;
1325
+ }
1326
+ case "notify":
1327
+ case "send_notification": {
1328
+ const msg = String(action.config.message ?? action.config.body ?? "Notification");
1329
+ lines.push(` // Send notification: "${msg}"`);
1330
+ lines.push(` await env.notify({ message: '${msg}', instanceId: instance.id });`);
1331
+ break;
1332
+ }
1333
+ case "call_workflow":
1334
+ case "spawn_instance":
1335
+ case "spawn_subworkflow": {
1336
+ const slug = String(action.config.slug ?? action.config.workflow ?? "child-workflow");
1337
+ lines.push(` await env.spawn('${slug}', { parentId: instance.id });`);
1338
+ break;
1339
+ }
1340
+ case "emit_event": {
1341
+ const event = String(action.config.event ?? action.config.name ?? "custom-event");
1342
+ lines.push(` await env.emit('${event}', { instanceId: instance.id });`);
1343
+ break;
1344
+ }
1345
+ default:
1346
+ lines.push(` // TODO: Implement ${action.type} logic`);
1347
+ }
1348
+ lines.push(`}`);
1349
+ lines.push(``);
1350
+ }
1351
+ return lines.join("\n");
1352
+ }
1353
+ function actionComment(type, config) {
1354
+ switch (type) {
1355
+ case "http_request":
1356
+ case "webhook":
1357
+ case "call_webhook":
1358
+ return `HTTP ${config.method ?? "POST"} to ${config.url ?? "webhook endpoint"}`;
1359
+ case "notify":
1360
+ case "send_notification":
1361
+ return `Send notification: ${config.message ?? config.body ?? ""}`;
1362
+ case "call_workflow":
1363
+ case "spawn_instance":
1364
+ case "spawn_subworkflow":
1365
+ return `Spawn child workflow: ${config.slug ?? config.workflow ?? ""}`;
1366
+ case "emit_event":
1367
+ return `Emit event: ${config.event ?? config.name ?? ""}`;
1368
+ default:
1369
+ return `Server action: ${type}`;
1370
+ }
1371
+ }
1372
+ function generateConfigFile(def) {
1373
+ const lines = [
1374
+ `/**`,
1375
+ ` * Blueprint configuration for "${def.name || pascalCase(def.slug)}".`,
1376
+ ` */`,
1377
+ ``,
1378
+ `import { defineBlueprint } from '@mindmatrix/react';`,
1379
+ ``,
1380
+ `export default defineBlueprint({`,
1381
+ ` slug: '${def.slug}',`,
1382
+ ` name: '${(def.name || pascalCase(def.slug)).replace(/'/g, "\\'")}',`,
1383
+ ` version: '${def.version}',`,
1384
+ ` category: '${def.category}',`
1385
+ ];
1386
+ if (def.description) {
1387
+ lines.push(` description: '${def.description.replace(/'/g, "\\'")}',`);
1388
+ }
1389
+ if (def.roles && def.roles.length > 0) {
1390
+ lines.push(` roles: [`);
1391
+ for (const role of def.roles) {
1392
+ const perms = role.permissions.map((p) => `'${p}'`).join(", ");
1393
+ lines.push(` { name: '${role.name}', permissions: [${perms}] },`);
1394
+ }
1395
+ lines.push(` ],`);
1396
+ }
1397
+ lines.push(`});`);
1398
+ lines.push(``);
1399
+ return lines.join("\n");
1400
+ }
1401
+ function extractPages(experience, slug) {
1402
+ if (!experience || !experience.children) return [];
1403
+ const pages = [];
1404
+ const rootChildren = experience.children;
1405
+ for (const child of rootChildren) {
1406
+ const isRoutePage = child.visible_when && /activeRoute|route|isOn/i.test(child.visible_when);
1407
+ const isPageId = child.id && /page|route|view/i.test(child.id);
1408
+ const isShowRoute = child.component === "Show" && child.config?.when && /activeRoute|route/i.test(String(child.config.when));
1409
+ if (isRoutePage || isPageId || isShowRoute) {
1410
+ const routeName = extractRouteName(child) || child.id || `page-${pages.length}`;
1411
+ const componentName = pascalCase(routeName.replace(/^\//, "").replace(/\//g, "-") || `${slug}-page`);
1412
+ pages.push({
1413
+ route: routeName,
1414
+ componentName,
1415
+ tree: child,
1416
+ filePath: `pages/${componentName}.tsx`
1417
+ });
1418
+ }
1419
+ }
1420
+ return pages;
1421
+ }
1422
+ function extractRouteName(node) {
1423
+ if (node.visible_when) {
1424
+ const match = node.visible_when.match(/['"]\/([^'"]+)['"]/);
1425
+ if (match) return match[1];
1426
+ const boolMatch = node.visible_when.match(/isOn([A-Z]\w+)/);
1427
+ if (boolMatch) return boolMatch[1].toLowerCase();
1428
+ }
1429
+ if (node.config?.when) {
1430
+ const match = String(node.config.when).match(/['"]\/([^'"]+)['"]/);
1431
+ if (match) return match[1];
1432
+ }
1433
+ return "";
1434
+ }
1435
+ function generatePageFile(page, _slug) {
1436
+ const pageInput = {
1437
+ slug: page.route || "page",
1438
+ name: page.componentName,
1439
+ version: "1.0.0",
1440
+ category: "page",
1441
+ states: [],
1442
+ transitions: [],
1443
+ fields: [],
1444
+ roles: [],
1445
+ experience: page.tree
1446
+ };
1447
+ const result = decompile(pageInput, {
1448
+ componentName: page.componentName,
1449
+ includeAnnotation: false
1450
+ });
1451
+ return result.code;
1452
+ }
1453
+ function generateMainFile(def, pages, hasModel, serverActionNames, options) {
1454
+ if (pages.length === 0) {
1455
+ const result = decompile(def, options);
1456
+ return result.code;
1457
+ }
1458
+ const slug = def.slug;
1459
+ const componentName = options?.componentName ?? pascalCase(slug);
1460
+ const importLines = [];
1461
+ const reactImports = /* @__PURE__ */ new Set();
1462
+ const nonComputed = def.fields.filter((f) => !f.computed);
1463
+ if (nonComputed.length > 0) reactImports.add("useState");
1464
+ for (const state of def.states) {
1465
+ if (state.on_enter.length > 0) reactImports.add("useOnEnter");
1466
+ if (state.on_exit.length > 0) reactImports.add("useOnExit");
1467
+ if (state.during.length > 0) reactImports.add("useWhileIn");
1468
+ }
1469
+ if (def.transitions.length > 0) reactImports.add("useTransition");
1470
+ reactImports.add("Stack");
1471
+ if (reactImports.size > 0) {
1472
+ const sorted = [...reactImports].sort();
1473
+ importLines.push(`import { ${sorted.join(", ")} } from '@mindmatrix/react';`);
1474
+ }
1475
+ if (hasModel) {
1476
+ const typeName = pascalCase(slug);
1477
+ importLines.push(`import type { ${typeName} } from './models/${slug}';`);
1478
+ }
1479
+ if (serverActionNames.length > 0) {
1480
+ const names = serverActionNames.join(", ");
1481
+ importLines.push(`import { ${names} } from './actions/${slug}.server';`);
1482
+ }
1483
+ for (const page of pages) {
1484
+ importLines.push(`import { ${page.componentName} } from './${page.filePath.replace(/\.tsx$/, "")}';`);
1485
+ }
1486
+ const bodyLines = [];
1487
+ for (const field of nonComputed) {
1488
+ const name = camelCase(field.name);
1489
+ const setter = `set${pascalCase(field.name)}`;
1490
+ const defaultVal = fieldDefaultLiteral(field);
1491
+ bodyLines.push(` const [${name}, ${setter}] = useState(${defaultVal});`);
1492
+ }
1493
+ if (nonComputed.length > 0) bodyLines.push(``);
1494
+ for (const state of def.states) {
1495
+ if (state.on_enter.length > 0) {
1496
+ const actions = state.on_enter.map((a) => actionToInlineCode(a)).filter(Boolean);
1497
+ bodyLines.push(` useOnEnter('${state.name}', () => {`);
1498
+ for (const a of actions) bodyLines.push(` ${a}`);
1499
+ bodyLines.push(` });`);
1500
+ }
1501
+ if (state.on_exit.length > 0) {
1502
+ const actions = state.on_exit.map((a) => actionToInlineCode(a)).filter(Boolean);
1503
+ bodyLines.push(` useOnExit('${state.name}', () => {`);
1504
+ for (const a of actions) bodyLines.push(` ${a}`);
1505
+ bodyLines.push(` });`);
1506
+ }
1507
+ }
1508
+ for (const trans of def.transitions) {
1509
+ const varName = camelCase(trans.name);
1510
+ const from = trans.from.length === 1 ? `'${trans.from[0]}'` : `[${trans.from.map((f) => `'${f}'`).join(", ")}]`;
1511
+ bodyLines.push(` const ${varName} = useTransition('${trans.name}', { from: ${from}, to: '${trans.to}' });`);
1512
+ }
1513
+ if (def.transitions.length > 0) bodyLines.push(``);
1514
+ bodyLines.push(` return (`);
1515
+ bodyLines.push(` <Stack sx={{ minHeight: '100vh' }}>`);
1516
+ for (const page of pages) {
1517
+ bodyLines.push(` <${page.componentName} />`);
1518
+ }
1519
+ bodyLines.push(` </Stack>`);
1520
+ bodyLines.push(` );`);
1521
+ const lines = [
1522
+ ...importLines,
1523
+ ``,
1524
+ `/**`,
1525
+ ` * @workflow slug="${slug}" version="${def.version}" category="${def.category}"`,
1526
+ ...def.description ? [` * @description ${def.description}`] : [],
1527
+ ` */`,
1528
+ `export default function ${componentName}() {`,
1529
+ ...bodyLines,
1530
+ `}`,
1531
+ ``
1532
+ ];
1533
+ return lines.join("\n");
1534
+ }
1535
+ function fieldDefaultLiteral(field) {
1536
+ if (field.default_value !== void 0) {
1537
+ if (typeof field.default_value === "string") return `'${field.default_value}'`;
1538
+ return JSON.stringify(field.default_value);
1539
+ }
1540
+ switch (field.type) {
1541
+ case "text":
1542
+ case "rich_text":
1543
+ case "email":
1544
+ case "url":
1545
+ case "phone":
1546
+ case "color":
1547
+ case "select":
1548
+ return "''";
1549
+ case "number":
1550
+ case "currency":
1551
+ case "percentage":
1552
+ case "rating":
1553
+ case "duration":
1554
+ case "auto_number":
1555
+ return "0";
1556
+ case "boolean":
1557
+ return "false";
1558
+ case "date":
1559
+ case "datetime":
1560
+ return "null";
1561
+ case "multi_select":
1562
+ case "json":
1563
+ return "[]";
1564
+ default:
1565
+ return "null";
1566
+ }
1567
+ }
1568
+ function actionToInlineCode(action) {
1569
+ switch (action.type) {
1570
+ case "set_field": {
1571
+ const field = String(action.config.field ?? "");
1572
+ const setter = `set${pascalCase(field)}`;
1573
+ const val = action.config.expression ? String(action.config.expression) : JSON.stringify(action.config.value ?? null);
1574
+ return `${setter}(${val});`;
1575
+ }
1576
+ case "log_event":
1577
+ case "log":
1578
+ return `console.log('${action.config.message ?? action.config.event ?? action.type}');`;
1579
+ case "noop":
1580
+ return "";
1581
+ default:
1582
+ return `// ${action.type}: ${JSON.stringify(action.config)}`;
1583
+ }
1584
+ }
1585
+ function decompileProject(definition, options) {
1586
+ const files = [];
1587
+ const slug = definition.slug;
1588
+ const pages = options?.skipPages ? [] : extractPages(definition.experience, slug);
1589
+ const serverActions = options?.skipActions ? [] : extractServerActions(definition.states, definition.transitions);
1590
+ const hasFields = definition.fields.length > 0;
1591
+ if (hasFields && !options?.skipModels) {
1592
+ let modelContent = generateModelFile(slug, definition.fields);
1593
+ if (definition.states.length > 0) {
1594
+ modelContent += generateStateEnum(slug, definition.states);
1595
+ }
1596
+ files.push({
1597
+ path: `models/${slug}.ts`,
1598
+ role: "model",
1599
+ content: modelContent
1600
+ });
1601
+ }
1602
+ if (serverActions.length > 0) {
1603
+ files.push({
1604
+ path: `actions/${slug}.server.ts`,
1605
+ role: "server-action",
1606
+ content: generateServerActionFile(serverActions)
1607
+ });
1608
+ }
1609
+ for (const page of pages) {
1610
+ files.push({
1611
+ path: page.filePath,
1612
+ role: "page",
1613
+ content: generatePageFile(page, slug)
1614
+ });
1615
+ }
1616
+ if (!options?.skipConfig) {
1617
+ files.push({
1618
+ path: "mm.config.ts",
1619
+ role: "config",
1620
+ content: generateConfigFile(definition)
1621
+ });
1622
+ }
1623
+ if (definition.childDefinitions && definition.childDefinitions.length > 0) {
1624
+ for (const child of definition.childDefinitions) {
1625
+ const childSlug = child.slug;
1626
+ const childFileName = `${childSlug}.workflow.tsx`;
1627
+ const childInput = {
1628
+ ...child,
1629
+ experience: child.views?.default
1630
+ };
1631
+ if (child.category === "data" && child.fields.length > 0 && !options?.skipModels) {
1632
+ let childModelContent = generateModelFile(childSlug, child.fields);
1633
+ if (child.states.length > 0) {
1634
+ childModelContent += generateStateEnum(childSlug, child.states);
1635
+ }
1636
+ files.push({
1637
+ path: `models/${childSlug}.ts`,
1638
+ role: "model",
1639
+ content: childModelContent
1640
+ });
1641
+ }
1642
+ if (!options?.skipActions) {
1643
+ const childServerActions = extractServerActions(child.states, child.transitions);
1644
+ if (childServerActions.length > 0) {
1645
+ files.push({
1646
+ path: `actions/${childSlug}.server.ts`,
1647
+ role: "server-action",
1648
+ content: generateServerActionFile(childServerActions)
1649
+ });
1650
+ }
1651
+ }
1652
+ const childResult = decompile(childInput, {
1653
+ componentName: pascalCase(childSlug),
1654
+ includeAnnotation: true
1655
+ });
1656
+ files.push({
1657
+ path: childFileName,
1658
+ role: "view-entry",
1659
+ content: childResult.code
1660
+ });
1661
+ }
1662
+ }
1663
+ const mainContent = generateMainFile(
1664
+ definition,
1665
+ pages,
1666
+ hasFields && !options?.skipModels,
1667
+ serverActions.map((a) => a.name),
1668
+ options
1669
+ );
1670
+ files.push({
1671
+ path: "main.workflow.tsx",
1672
+ role: "view-entry",
1673
+ content: mainContent
1674
+ });
1675
+ return {
1676
+ files,
1677
+ entryFile: "main.workflow.tsx",
1678
+ slug
1679
+ };
1680
+ }
1681
+ function shouldDecompileAsProject(def) {
1682
+ const meta = def.metadata;
1683
+ const childSlugs = meta?.childSlugs;
1684
+ const hasChildren = Array.isArray(childSlugs) && childSlugs.length > 0;
1685
+ return hasChildren || def.states.length > 1 && def.transitions.length > 0 && (def.fields.length > 0 || def.category === "blueprint");
1686
+ }
1687
+
1688
+ // src/decompiler/split-strategy.ts
1689
+ var SMALL_FIELD_LIMIT = 5;
1690
+ var SMALL_STATE_LIMIT = 1;
1691
+ var MEDIUM_FIELD_LIMIT = 15;
1692
+ var MEDIUM_STATE_LIMIT = 5;
1693
+ function determineSplitStrategy(def) {
1694
+ const fieldCount = def.fields.length;
1695
+ const stateCount = def.states.length;
1696
+ const hasExperience = !!def.experience || !!def.views?.default;
1697
+ const hasChildren = Array.isArray(def.metadata?.childSlugs) && def.metadata.childSlugs.length > 0;
1698
+ if (def.category === "blueprint" || hasChildren) {
1699
+ return {
1700
+ tier: "large",
1701
+ emitModels: fieldCount > 0,
1702
+ emitPages: hasExperience,
1703
+ emitActions: true,
1704
+ emitConfig: true,
1705
+ reason: "blueprint or has children \u2014 always full project"
1706
+ };
1707
+ }
1708
+ if (fieldCount > MEDIUM_FIELD_LIMIT || stateCount > MEDIUM_STATE_LIMIT) {
1709
+ return {
1710
+ tier: "large",
1711
+ emitModels: true,
1712
+ emitPages: hasExperience,
1713
+ emitActions: true,
1714
+ emitConfig: true,
1715
+ reason: "large definition (>15 fields or >5 states)"
1716
+ };
1717
+ }
1718
+ if (fieldCount > SMALL_FIELD_LIMIT || stateCount > SMALL_STATE_LIMIT) {
1719
+ const hasRoutes = hasExperience && hasRouteStructure(def);
1720
+ return {
1721
+ tier: "medium",
1722
+ emitModels: fieldCount > 0,
1723
+ emitPages: hasRoutes,
1724
+ emitActions: false,
1725
+ emitConfig: true,
1726
+ reason: "medium definition (>5 fields or >1 state)"
1727
+ };
1728
+ }
1729
+ return {
1730
+ tier: "single",
1731
+ emitModels: false,
1732
+ emitPages: false,
1733
+ emitActions: false,
1734
+ emitConfig: false,
1735
+ reason: "small definition \u2014 single file sufficient"
1736
+ };
1737
+ }
1738
+ function hasRouteStructure(def) {
1739
+ const exp = def.experience;
1740
+ if (!exp) return false;
1741
+ function walk(node) {
1742
+ const comp = node.component || node.layout || "";
1743
+ if (comp === "Router" || comp === "Route") return true;
1744
+ if (node.children) {
1745
+ for (const c of node.children) {
1746
+ if (walk(c)) return true;
1747
+ }
1748
+ }
1749
+ return false;
1750
+ }
1751
+ return walk(exp);
1752
+ }
1753
+
1754
+ // src/decompiler/config-generator.ts
1755
+ function extractConfigData(def, modelPaths, entryPaths, actionPaths) {
1756
+ const meta = def.metadata;
1757
+ return {
1758
+ slug: def.slug,
1759
+ name: def.name || pascalCase2(def.slug),
1760
+ version: def.version,
1761
+ category: def.category,
1762
+ description: def.description || void 0,
1763
+ mode: meta?.mode || void 0,
1764
+ defaultRuntime: meta?.defaultRuntime || void 0,
1765
+ models: modelPaths,
1766
+ entries: entryPaths,
1767
+ actions: actionPaths,
1768
+ roles: (def.roles || []).map((r) => r.name)
1769
+ };
1770
+ }
1771
+ function generateMmConfig(config) {
1772
+ const isBlueprint = config.category === "blueprint";
1773
+ const fnName = isBlueprint ? "defineBlueprint" : "defineWorkspace";
1774
+ const label = isBlueprint ? "Blueprint" : "Workspace";
1775
+ const lines = [
1776
+ `/**`,
1777
+ ` * MindMatrix ${label.toLowerCase()} configuration.`,
1778
+ ` *`,
1779
+ ` * Auto-generated from workflow definition "${config.slug}".`,
1780
+ ` */`,
1781
+ ``,
1782
+ `import { ${fnName} } from '@mindmatrix/react';`,
1783
+ ``,
1784
+ `export default ${fnName}({`,
1785
+ ` slug: '${esc(config.slug)}',`,
1786
+ ` name: '${esc(config.name)}',`,
1787
+ ` version: '${esc(config.version)}',`,
1788
+ ` category: ${Array.isArray(config.category) ? `[${config.category.map((c) => `'${esc(c)}'`).join(", ")}]` : `'${esc(config.category)}'`},`
1789
+ ];
1790
+ if (config.description) {
1791
+ lines.push(` description: '${esc(config.description)}',`);
1792
+ }
1793
+ if (isBlueprint) {
1794
+ if (config.mode) {
1795
+ lines.push(` mode: '${esc(config.mode)}',`);
1796
+ }
1797
+ if (config.defaultRuntime) {
1798
+ lines.push(` defaultRuntime: '${esc(config.defaultRuntime)}',`);
1799
+ }
1800
+ }
1801
+ if (config.models.length > 0) {
1802
+ lines.push(` models: [`);
1803
+ for (const m of config.models) {
1804
+ lines.push(` '${esc(m)}',`);
1805
+ }
1806
+ lines.push(` ],`);
1807
+ }
1808
+ if (config.entries.length > 0) {
1809
+ lines.push(` entries: [`);
1810
+ for (const e of config.entries) {
1811
+ lines.push(` '${esc(e)}',`);
1812
+ }
1813
+ lines.push(` ],`);
1814
+ }
1815
+ if (config.actions.length > 0) {
1816
+ lines.push(` actions: [`);
1817
+ for (const a of config.actions) {
1818
+ lines.push(` '${esc(a)}',`);
1819
+ }
1820
+ lines.push(` ],`);
1821
+ }
1822
+ if (config.roles.length > 0) {
1823
+ lines.push(` roles: [${config.roles.map((r) => `'${esc(r)}'`).join(", ")}],`);
1824
+ }
1825
+ lines.push(`});`);
1826
+ lines.push(``);
1827
+ return lines.join("\n");
1828
+ }
1829
+ function esc(s) {
1830
+ return s.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
1831
+ }
1832
+ function pascalCase2(slug) {
1833
+ return slug.split(/[-_]/).map((part) => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase()).join("");
1834
+ }
1835
+
1836
+ // src/decompiler/index.ts
1837
+ function pascalCase3(slug) {
1838
+ return slug.split(/[-_]/).map((part) => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase()).join("");
1839
+ }
1840
+ function emitImportStatements(tracker) {
1841
+ const result = [];
1842
+ const sources = [...tracker.keys()].sort();
1843
+ for (const source of sources) {
1844
+ const names = [...tracker.get(source)].sort();
1845
+ const specifiers = [];
1846
+ for (const name of names) {
1847
+ if (name.startsWith("default as ")) {
1848
+ const localName = name.slice("default as ".length);
1849
+ specifiers.push(t4.importDefaultSpecifier(t4.identifier(localName)));
1850
+ } else {
1851
+ specifiers.push(t4.importSpecifier(t4.identifier(name), t4.identifier(name)));
1852
+ }
1853
+ }
1854
+ result.push(t4.importDeclaration(specifiers, t4.stringLiteral(source)));
1855
+ }
1856
+ return result;
1857
+ }
1858
+ function buildWorkflowAnnotation(def) {
1859
+ const parts = [
1860
+ `@workflow slug="${def.slug}" version="${def.version}" category="${def.category}"`
1861
+ ];
1862
+ if (def.description) {
1863
+ parts.push(`@description ${def.description}`);
1864
+ }
1865
+ return `*
1866
+ * ${parts.join("\n * ")}
1867
+ `;
1868
+ }
1869
+ function decompile(definition, options) {
1870
+ const imports = /* @__PURE__ */ new Map();
1871
+ const includeAnnotation = options?.includeAnnotation ?? true;
1872
+ const componentName = options?.componentName ?? definition.metadata?.displayName ?? pascalCase3(definition.slug);
1873
+ const symbols = buildSymbolTable(
1874
+ definition.fields,
1875
+ definition.metadata,
1876
+ definition.transitions,
1877
+ definition.experience
1878
+ );
1879
+ const componentBody = [];
1880
+ const sortedFields = [...definition.fields].sort((a, b) => a.name.localeCompare(b.name));
1881
+ const fieldStmts = emitFieldDeclarations(sortedFields, imports);
1882
+ componentBody.push(...fieldStmts);
1883
+ if (definition.experience) {
1884
+ const localDefaultStmts = emitLocalDefaultDeclarations(
1885
+ definition.experience,
1886
+ definition.fields,
1887
+ imports
1888
+ );
1889
+ componentBody.push(...localDefaultStmts);
1890
+ }
1891
+ const queryStmts = emitQueryDeclarations(definition.metadata, imports);
1892
+ componentBody.push(...queryStmts);
1893
+ const roleStmts = emitRoleDeclarations(definition.metadata, imports);
1894
+ componentBody.push(...roleStmts);
1895
+ const sortedStates = [...definition.states].sort((a, b) => a.name.localeCompare(b.name));
1896
+ const effectStmts = emitStateEffects(sortedStates, imports);
1897
+ componentBody.push(...effectStmts);
1898
+ const watcherStmts = emitChangeWatchers(definition.metadata, imports);
1899
+ componentBody.push(...watcherStmts);
1900
+ const eventStmts = emitEventSubscriptions(definition.on_event, imports);
1901
+ componentBody.push(...eventStmts);
1902
+ const sortedTransitions = [...definition.transitions].sort((a, b) => a.name.localeCompare(b.name));
1903
+ const transStmts = emitTransitionDeclarations(sortedTransitions, imports);
1904
+ componentBody.push(...transStmts);
1905
+ const effectHookStmts = emitTransitionEffects(definition.metadata, imports);
1906
+ componentBody.push(...effectHookStmts);
1907
+ if (definition.experience) {
1908
+ const jsxTree = buildJSXTree(definition.experience, imports, symbols);
1909
+ componentBody.push(t4.returnStatement(jsxTree));
1910
+ } else {
1911
+ componentBody.push(t4.returnStatement(t4.nullLiteral()));
1912
+ }
1913
+ const func = t4.functionDeclaration(
1914
+ t4.identifier(componentName),
1915
+ [],
1916
+ t4.blockStatement(componentBody)
1917
+ );
1918
+ const programBody = [];
1919
+ programBody.push(...emitImportStatements(imports));
1920
+ const exportDecl = t4.exportDefaultDeclaration(func);
1921
+ if (includeAnnotation) {
1922
+ t4.addComment(exportDecl, "leading", buildWorkflowAnnotation(definition), false);
1923
+ }
1924
+ programBody.push(exportDecl);
1925
+ const program2 = t4.program(programBody);
1926
+ const file2 = t4.file(program2);
1927
+ const { code } = generate(file2, {
1928
+ retainLines: false,
1929
+ compact: false,
1930
+ jsescOption: { minimal: true }
1931
+ });
1932
+ return {
1933
+ code,
1934
+ imports: [...imports.keys()],
1935
+ componentName
1936
+ };
1937
+ }
1938
+
1939
+ // src/decompiler/project-decompiler.ts
1940
+ function pascalCase4(slug) {
1941
+ return slug.split(/[-_]/).map((part) => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase()).join("");
1942
+ }
1943
+ function camelCase2(str) {
1944
+ return str.replace(/[-_]([a-z])/g, (_, c) => c.toUpperCase());
1945
+ }
1946
+ function correctTransitionFromFields(transitions) {
1947
+ if (transitions.length <= 1) return transitions;
1948
+ const fromValues = /* @__PURE__ */ new Set();
1949
+ for (const t5 of transitions) {
1950
+ const arr = Array.isArray(t5.from) ? t5.from : [t5.from];
1951
+ for (const f of arr) fromValues.add(f);
1952
+ }
1953
+ if (fromValues.size !== 1) return transitions;
1954
+ const stateNames = /* @__PURE__ */ new Set([...fromValues]);
1955
+ for (const t5 of transitions) {
1956
+ stateNames.add(t5.to);
1957
+ }
1958
+ const allNamesAreStates = transitions.every((t5) => stateNames.has(t5.name));
1959
+ if (!allNamesAreStates) return transitions;
1960
+ return transitions.map((t5) => ({ ...t5, from: [t5.name] }));
1961
+ }
1962
+ function fieldTypeToTS2(fieldType, field) {
1963
+ const options = getFieldOptions2(field);
1964
+ if (options && options.length > 0 && (fieldType === "select" || fieldType === "text")) {
1965
+ return options.map((o) => `'${esc2(String(o))}'`).join(" | ");
1966
+ }
1967
+ switch (fieldType) {
1968
+ case "text":
1969
+ case "rich_text":
1970
+ case "email":
1971
+ case "url":
1972
+ case "phone":
1973
+ case "color":
1974
+ case "select":
1975
+ return "string";
1976
+ case "number":
1977
+ case "currency":
1978
+ case "percentage":
1979
+ case "rating":
1980
+ case "duration":
1981
+ case "auto_number":
1982
+ return "number";
1983
+ case "boolean":
1984
+ return "boolean";
1985
+ case "date":
1986
+ case "datetime":
1987
+ case "created_at":
1988
+ case "updated_at":
1989
+ return "Date";
1990
+ case "multi_select":
1991
+ return "string[]";
1992
+ case "json":
1993
+ case "object":
1994
+ return "Record<string, unknown>";
1995
+ case "array":
1996
+ return "string[]";
1997
+ case "file":
1998
+ case "image":
1999
+ return "string";
2000
+ case "relation":
2001
+ case "lookup":
2002
+ return "string";
2003
+ default:
2004
+ return "unknown";
2005
+ }
2006
+ }
2007
+ function getFieldOptions2(field) {
2008
+ if (!field) return null;
2009
+ const f = field;
2010
+ const validation = f.validation;
2011
+ if (validation?.options && Array.isArray(validation.options)) {
2012
+ return validation.options;
2013
+ }
2014
+ const meta = f.metadata;
2015
+ if (meta?.options && Array.isArray(meta.options)) {
2016
+ return meta.options;
2017
+ }
2018
+ if (f.options && Array.isArray(f.options)) {
2019
+ return f.options;
2020
+ }
2021
+ return null;
2022
+ }
2023
+ function safeKey(name) {
2024
+ return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name) ? name : `'${esc2(name)}'`;
2025
+ }
2026
+ function fieldTypeToModelType(fieldType) {
2027
+ switch (fieldType) {
2028
+ case "text":
2029
+ case "rich_text":
2030
+ case "select":
2031
+ return "string";
2032
+ case "email":
2033
+ return "email";
2034
+ case "url":
2035
+ return "url";
2036
+ case "phone":
2037
+ return "phone";
2038
+ case "color":
2039
+ return "color";
2040
+ case "number":
2041
+ case "currency":
2042
+ case "percentage":
2043
+ case "rating":
2044
+ case "duration":
2045
+ case "auto_number":
2046
+ return "number";
2047
+ case "boolean":
2048
+ return "boolean";
2049
+ case "date":
2050
+ case "datetime":
2051
+ case "created_at":
2052
+ case "updated_at":
2053
+ return "date";
2054
+ case "multi_select":
2055
+ return "array";
2056
+ case "json":
2057
+ case "object":
2058
+ return "json";
2059
+ case "array":
2060
+ return "array";
2061
+ case "file":
2062
+ case "image":
2063
+ return "file";
2064
+ case "relation":
2065
+ case "lookup":
2066
+ return "relation";
2067
+ default:
2068
+ return fieldType;
2069
+ }
2070
+ }
2071
+ function serializeDefault(value) {
2072
+ if (value === void 0 || value === null) return "null";
2073
+ if (typeof value === "string") return `'${esc2(value)}'`;
2074
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
2075
+ if (Array.isArray(value)) {
2076
+ if (value.length === 0) return "[]";
2077
+ return `[${value.map((v) => serializeDefault(v)).join(", ")}]`;
2078
+ }
2079
+ return JSON.stringify(value);
2080
+ }
2081
+ function serializeValue(value, indent) {
2082
+ const pad = " ".repeat(indent);
2083
+ if (value === void 0 || value === null) return "null";
2084
+ if (typeof value === "string") return `'${esc2(value)}'`;
2085
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
2086
+ if (Array.isArray(value)) {
2087
+ if (value.length === 0) return "[]";
2088
+ if (value.every((v) => typeof v === "string" || typeof v === "number" || typeof v === "boolean")) {
2089
+ return `[${value.map((v) => serializeValue(v, 0)).join(", ")}]`;
2090
+ }
2091
+ const items = value.map((v) => `${pad} ${serializeValue(v, indent + 2)},`);
2092
+ return `[
2093
+ ${items.join("\n")}
2094
+ ${pad}]`;
2095
+ }
2096
+ if (typeof value === "object") {
2097
+ return serializeObject(value, indent);
2098
+ }
2099
+ return JSON.stringify(value);
2100
+ }
2101
+ function serializeObject(obj, indent) {
2102
+ const pad = " ".repeat(indent);
2103
+ const entries = Object.entries(obj).filter(([, v]) => v !== void 0);
2104
+ if (entries.length === 0) return "{}";
2105
+ const simple = entries.every(([, v]) => typeof v === "string" || typeof v === "number" || typeof v === "boolean" || v === null);
2106
+ if (simple && entries.length <= 3) {
2107
+ const parts = entries.map(([k, v]) => `${safeKey(k)}: ${serializeValue(v, 0)}`);
2108
+ return `{ ${parts.join(", ")} }`;
2109
+ }
2110
+ const lines = entries.map(([k, v]) => `${pad} ${safeKey(k)}: ${serializeValue(v, indent + 2)},`);
2111
+ return `{
2112
+ ${lines.join("\n")}
2113
+ ${pad}}`;
2114
+ }
2115
+ function serializeActions(actions, indent) {
2116
+ const pad = " ".repeat(indent);
2117
+ if (!actions || actions.length === 0) return [];
2118
+ const lines = [];
2119
+ lines.push(`${pad}[`);
2120
+ for (const action of actions) {
2121
+ const inner = indent + 2;
2122
+ const ip = " ".repeat(inner);
2123
+ lines.push(`${ip}{`);
2124
+ if (action.id) lines.push(`${ip} id: '${esc2(String(action.id))}',`);
2125
+ if (action.type) lines.push(`${ip} type: '${esc2(String(action.type))}',`);
2126
+ if (action.mode) lines.push(`${ip} mode: '${esc2(String(action.mode))}',`);
2127
+ if (action.condition) lines.push(`${ip} condition: '${esc2(String(action.condition))}',`);
2128
+ if (action.config && typeof action.config === "object" && Object.keys(action.config).length > 0) {
2129
+ lines.push(`${ip} config: ${serializeValue(action.config, inner + 2)},`);
2130
+ }
2131
+ lines.push(`${ip}},`);
2132
+ }
2133
+ lines.push(`${pad}]`);
2134
+ return lines;
2135
+ }
2136
+ function serializeConditions(conditions, indent) {
2137
+ const pad = " ".repeat(indent);
2138
+ if (!conditions || conditions.length === 0) return [];
2139
+ const lines = [];
2140
+ lines.push(`${pad}[`);
2141
+ for (const cond of conditions) {
2142
+ lines.push(`${" ".repeat(indent + 2)}${serializeObject(cond, indent + 2)},`);
2143
+ }
2144
+ lines.push(`${pad}]`);
2145
+ return lines;
2146
+ }
2147
+ function serializeDuring(during, indent) {
2148
+ const pad = " ".repeat(indent);
2149
+ if (!during || during.length === 0) return [];
2150
+ const lines = [];
2151
+ lines.push(`${pad}[`);
2152
+ for (const d of during) {
2153
+ const inner = indent + 2;
2154
+ const ip = " ".repeat(inner);
2155
+ lines.push(`${ip}{`);
2156
+ if (d.id) lines.push(`${ip} id: '${esc2(String(d.id))}',`);
2157
+ if (d.type) lines.push(`${ip} type: '${esc2(String(d.type))}',`);
2158
+ if (d.schedule && typeof d.schedule === "object") {
2159
+ lines.push(`${ip} schedule: ${serializeValue(d.schedule, inner + 2)},`);
2160
+ }
2161
+ if (d.interval_ms != null) lines.push(`${ip} interval_ms: ${d.interval_ms},`);
2162
+ if (d.cron) lines.push(`${ip} cron: '${esc2(String(d.cron))}',`);
2163
+ if (d.delay_ms != null) lines.push(`${ip} delay_ms: ${d.delay_ms},`);
2164
+ if (d.condition) lines.push(`${ip} condition: '${esc2(String(d.condition))}',`);
2165
+ if (d.actions && Array.isArray(d.actions) && d.actions.length > 0) {
2166
+ const actLines = serializeActions(d.actions, inner + 2);
2167
+ lines.push(`${ip} actions: ${actLines[0]?.trim()}`);
2168
+ for (let i = 1; i < actLines.length; i++) lines.push(actLines[i]);
2169
+ const lastIdx = lines.length - 1;
2170
+ if (!lines[lastIdx].trimEnd().endsWith(",")) lines[lastIdx] += ",";
2171
+ }
2172
+ lines.push(`${ip}},`);
2173
+ }
2174
+ lines.push(`${pad}]`);
2175
+ return lines;
2176
+ }
2177
+ function serializeOnEvent(events, indent) {
2178
+ const pad = " ".repeat(indent);
2179
+ if (!events || events.length === 0) return [];
2180
+ const lines = [];
2181
+ lines.push(`${pad}[`);
2182
+ for (const evt of events) {
2183
+ const inner = indent + 2;
2184
+ const ip = " ".repeat(inner);
2185
+ lines.push(`${ip}{`);
2186
+ if (evt.match) lines.push(`${ip} match: '${esc2(String(evt.match))}',`);
2187
+ if (evt.description) lines.push(`${ip} description: '${esc2(String(evt.description))}',`);
2188
+ if (evt.conditions && Array.isArray(evt.conditions) && evt.conditions.length > 0) {
2189
+ const conds = evt.conditions.map((c) => `'${esc2(c)}'`);
2190
+ if (conds.length === 1) {
2191
+ lines.push(`${ip} conditions: [${conds[0]}],`);
2192
+ } else {
2193
+ lines.push(`${ip} conditions: [`);
2194
+ for (const c of conds) lines.push(`${ip} ${c},`);
2195
+ lines.push(`${ip} ],`);
2196
+ }
2197
+ }
2198
+ if (evt.actions && Array.isArray(evt.actions) && evt.actions.length > 0) {
2199
+ const actLines = serializeActions(evt.actions, inner + 2);
2200
+ lines.push(`${ip} actions: ${actLines[0]?.trim()}`);
2201
+ for (let i = 1; i < actLines.length; i++) lines.push(actLines[i]);
2202
+ if (!lines[lines.length - 1].trimEnd().endsWith(",")) lines[lines.length - 1] += ",";
2203
+ }
2204
+ lines.push(`${ip}},`);
2205
+ }
2206
+ lines.push(`${pad}]`);
2207
+ return lines;
2208
+ }
2209
+ function generateModelFile2(slug, fields, states, transitions, meta) {
2210
+ const typeName = pascalCase4(slug);
2211
+ const interfaceName = `${typeName}Fields`;
2212
+ const version = meta?.version || "0.1.0";
2213
+ const category = meta?.category || "data";
2214
+ const lines = [];
2215
+ lines.push(`import { defineModel } from '@mindmatrix/react';`);
2216
+ lines.push(``);
2217
+ const sortedFields = [...fields].sort((a, b) => a.name.localeCompare(b.name));
2218
+ if (sortedFields.length > 0) {
2219
+ lines.push(`export interface ${interfaceName} {`);
2220
+ for (const field of sortedFields) {
2221
+ const tsType = fieldTypeToTS2(field.type, field);
2222
+ const optional = field.required ? "" : "?";
2223
+ lines.push(` ${camelCase2(field.name)}${optional}: ${tsType};`);
2224
+ }
2225
+ lines.push(`}`);
2226
+ lines.push(``);
2227
+ }
2228
+ lines.push(`export default defineModel({`);
2229
+ lines.push(` slug: '${esc2(slug)}',`);
2230
+ lines.push(` version: '${esc2(version)}',`);
2231
+ lines.push(` category: '${esc2(category)}',`);
2232
+ if (meta?.description) {
2233
+ lines.push(` description: '${esc2(meta.description)}',`);
2234
+ }
2235
+ if (sortedFields.length > 0) {
2236
+ lines.push(` fields: {`);
2237
+ for (const field of sortedFields) {
2238
+ const props = [];
2239
+ props.push(`type: '${fieldTypeToModelType(field.type)}'`);
2240
+ if (field.required) {
2241
+ props.push(`required: true`);
2242
+ }
2243
+ if (field.default_value === null) {
2244
+ props.push(`default: null`);
2245
+ } else if (field.default_value !== void 0 && field.default_value !== "" && field.default_value !== 0 && field.default_value !== false) {
2246
+ props.push(`default: ${serializeDefault(field.default_value)}`);
2247
+ }
2248
+ const options = getFieldOptions2(field);
2249
+ if (options && options.length > 0) {
2250
+ const enumStr = options.map((o) => `'${esc2(String(o))}'`).join(", ");
2251
+ props.push(`enum: [${enumStr}]`);
2252
+ }
2253
+ lines.push(` ${camelCase2(field.name)}: { ${props.join(", ")} },`);
2254
+ }
2255
+ lines.push(` },`);
2256
+ }
2257
+ const validStates = states.filter((s) => s.name !== "");
2258
+ if (validStates.length > 0) {
2259
+ const sortedStates = [...validStates].sort((a, b) => a.name.localeCompare(b.name));
2260
+ lines.push(` states: {`);
2261
+ for (const state of sortedStates) {
2262
+ const hasOnEnter = state.on_enter && state.on_enter.length > 0;
2263
+ const hasOnExit = state.on_exit && state.on_exit.length > 0;
2264
+ const hasDuring = state.during && state.during.length > 0;
2265
+ const hasOnEvent = state.on_event && state.on_event.length > 0;
2266
+ const hasLifecycle = hasOnEnter || hasOnExit || hasDuring || hasOnEvent;
2267
+ if (!hasLifecycle) {
2268
+ const props = [];
2269
+ if (state.type === "START") props.push(`type: 'initial'`);
2270
+ else if (state.type === "END") props.push(`type: 'final'`);
2271
+ if (state.description) props.push(`description: '${esc2(state.description)}'`);
2272
+ const body = props.length > 0 ? ` ${props.join(", ")} ` : "";
2273
+ lines.push(` ${safeKey(state.name)}: {${body}},`);
2274
+ continue;
2275
+ }
2276
+ lines.push(` ${safeKey(state.name)}: {`);
2277
+ if (state.type === "START") lines.push(` type: 'initial',`);
2278
+ else if (state.type === "END") lines.push(` type: 'final',`);
2279
+ if (state.description) lines.push(` description: '${esc2(state.description)}',`);
2280
+ if (hasOnEnter) {
2281
+ const actLines = serializeActions(state.on_enter, 8);
2282
+ lines.push(` on_enter: ${actLines[0]?.trim()}`);
2283
+ for (let i = 1; i < actLines.length; i++) lines.push(actLines[i]);
2284
+ if (!lines[lines.length - 1].trimEnd().endsWith(",")) lines[lines.length - 1] += ",";
2285
+ }
2286
+ if (hasOnExit) {
2287
+ const actLines = serializeActions(state.on_exit, 8);
2288
+ lines.push(` on_exit: ${actLines[0]?.trim()}`);
2289
+ for (let i = 1; i < actLines.length; i++) lines.push(actLines[i]);
2290
+ if (!lines[lines.length - 1].trimEnd().endsWith(",")) lines[lines.length - 1] += ",";
2291
+ }
2292
+ if (hasDuring) {
2293
+ const durLines = serializeDuring(state.during, 8);
2294
+ lines.push(` during: ${durLines[0]?.trim()}`);
2295
+ for (let i = 1; i < durLines.length; i++) lines.push(durLines[i]);
2296
+ if (!lines[lines.length - 1].trimEnd().endsWith(",")) lines[lines.length - 1] += ",";
2297
+ }
2298
+ if (hasOnEvent) {
2299
+ const evtLines = serializeOnEvent(state.on_event, 8);
2300
+ lines.push(` on_event: ${evtLines[0]?.trim()}`);
2301
+ for (let i = 1; i < evtLines.length; i++) lines.push(evtLines[i]);
2302
+ if (!lines[lines.length - 1].trimEnd().endsWith(",")) lines[lines.length - 1] += ",";
2303
+ }
2304
+ lines.push(` },`);
2305
+ }
2306
+ lines.push(` },`);
2307
+ }
2308
+ if (transitions.length > 0) {
2309
+ const correctedTrans = correctTransitionFromFields(transitions);
2310
+ const sortedTrans = [...correctedTrans].sort((a, b) => a.name.localeCompare(b.name));
2311
+ lines.push(` transitions: {`);
2312
+ for (const trans of sortedTrans) {
2313
+ const fromArr = Array.isArray(trans.from) ? trans.from : [trans.from];
2314
+ const hasConditions = trans.conditions && trans.conditions.length > 0;
2315
+ const hasActions = trans.actions && trans.actions.length > 0;
2316
+ const hasRichContent = hasConditions || hasActions;
2317
+ if (!hasRichContent) {
2318
+ const parts = [];
2319
+ if (fromArr.length === 1) parts.push(`from: '${esc2(fromArr[0])}'`);
2320
+ else parts.push(`from: [${fromArr.map((f) => `'${esc2(f)}'`).join(", ")}]`);
2321
+ parts.push(`to: '${esc2(trans.to)}'`);
2322
+ if (trans.roles && trans.roles.length > 0) {
2323
+ parts.push(`roles: [${trans.roles.map((r) => `'${esc2(r)}'`).join(", ")}]`);
2324
+ }
2325
+ if (trans.auto) parts.push(`auto: true`);
2326
+ if (trans.required_fields && trans.required_fields.length > 0) {
2327
+ parts.push(`required_fields: [${trans.required_fields.map((f) => `'${esc2(f)}'`).join(", ")}]`);
2328
+ }
2329
+ lines.push(` ${safeKey(trans.name)}: { ${parts.join(", ")} },`);
2330
+ continue;
2331
+ }
2332
+ lines.push(` ${safeKey(trans.name)}: {`);
2333
+ if (fromArr.length === 1) {
2334
+ lines.push(` from: '${esc2(fromArr[0])}',`);
2335
+ } else {
2336
+ lines.push(` from: [${fromArr.map((f) => `'${esc2(f)}'`).join(", ")}],`);
2337
+ }
2338
+ lines.push(` to: '${esc2(trans.to)}',`);
2339
+ if (trans.roles && trans.roles.length > 0) {
2340
+ lines.push(` roles: [${trans.roles.map((r) => `'${esc2(r)}'`).join(", ")}],`);
2341
+ }
2342
+ if (trans.auto) lines.push(` auto: true,`);
2343
+ if (trans.required_fields && trans.required_fields.length > 0) {
2344
+ lines.push(` required_fields: [${trans.required_fields.map((f) => `'${esc2(f)}'`).join(", ")}],`);
2345
+ }
2346
+ if (hasConditions) {
2347
+ const condLines = serializeConditions(trans.conditions, 8);
2348
+ lines.push(` conditions: ${condLines[0]?.trim()}`);
2349
+ for (let i = 1; i < condLines.length; i++) lines.push(condLines[i]);
2350
+ if (!lines[lines.length - 1].trimEnd().endsWith(",")) lines[lines.length - 1] += ",";
2351
+ }
2352
+ if (hasActions) {
2353
+ const actLines = serializeActions(trans.actions, 8);
2354
+ lines.push(` actions: ${actLines[0]?.trim()}`);
2355
+ for (let i = 1; i < actLines.length; i++) lines.push(actLines[i]);
2356
+ if (!lines[lines.length - 1].trimEnd().endsWith(",")) lines[lines.length - 1] += ",";
2357
+ }
2358
+ lines.push(` },`);
2359
+ }
2360
+ lines.push(` },`);
2361
+ }
2362
+ lines.push(`});`);
2363
+ lines.push(``);
2364
+ return lines.join("\n");
2365
+ }
2366
+ function generateLayoutFile(slug, roles) {
2367
+ const componentName = `${pascalCase4(slug)}Layout`;
2368
+ const lines = [
2369
+ `/**`,
2370
+ ` * ${componentName} \u2014 root layout with auth guards.`,
2371
+ ` */`,
2372
+ ``,
2373
+ `import { useRole, Stack } from '@mindmatrix/react';`,
2374
+ ``,
2375
+ `interface LayoutProps {`,
2376
+ ` children: React.ReactNode;`,
2377
+ `}`,
2378
+ ``,
2379
+ `export default function ${componentName}({ children }: LayoutProps) {`
2380
+ ];
2381
+ for (const role of roles) {
2382
+ const varName = `is${pascalCase4(role.name)}`;
2383
+ lines.push(` const ${varName} = useRole('${esc2(role.name)}');`);
2384
+ }
2385
+ if (roles.length > 0) {
2386
+ lines.push(``);
2387
+ const roleChecks = roles.map((r) => `is${pascalCase4(r.name)}`).join(" || ");
2388
+ lines.push(` const isAuthorized = ${roleChecks};`);
2389
+ lines.push(``);
2390
+ lines.push(` if (!isAuthorized) {`);
2391
+ lines.push(` return <Stack sx={{ p: 32, align: 'center' }}>Access denied</Stack>;`);
2392
+ lines.push(` }`);
2393
+ }
2394
+ lines.push(``);
2395
+ lines.push(` return (`);
2396
+ lines.push(` <Stack sx={{ minH: '100vh' }}>`);
2397
+ lines.push(` {children}`);
2398
+ lines.push(` </Stack>`);
2399
+ lines.push(` );`);
2400
+ lines.push(`}`);
2401
+ lines.push(``);
2402
+ return lines.join("\n");
2403
+ }
2404
+ function extractRouteTable(childDefinitions) {
2405
+ if (!childDefinitions) return [];
2406
+ const router = childDefinitions.find(
2407
+ (c) => c.slug.endsWith("-router") || c.category === "router"
2408
+ );
2409
+ if (!router?.states) return [];
2410
+ return router.states.filter((s) => s.description?.startsWith("Route:")).map((s) => {
2411
+ const route = s.description.replace(/^Route:\s*/, "").replace(/^\//, "");
2412
+ const parts = route.split("/");
2413
+ return {
2414
+ stateName: s.name,
2415
+ role: parts[0] || "shared",
2416
+ page: parts.slice(1).join("/") || parts[0],
2417
+ path: route
2418
+ };
2419
+ });
2420
+ }
2421
+ function findPageTitle(node, maxDepth = 5) {
2422
+ const queue = [{ n: node, d: 0 }];
2423
+ while (queue.length > 0) {
2424
+ const { n, d } = queue.shift();
2425
+ if (d > maxDepth) continue;
2426
+ if ((n.component === "Text" || n.component === "Heading") && (n.config?.level === 2 || n.config?.variant === "h2")) {
2427
+ if (n.config?.text) return n.config.text;
2428
+ if (n.children?.length) {
2429
+ const parts = n.children.filter((c) => c.config?.value).map((c) => c.config.value);
2430
+ if (parts.length > 0) return parts.join("");
2431
+ }
2432
+ }
2433
+ if (n.children) {
2434
+ for (const child of n.children) {
2435
+ queue.push({ n: child, d: d + 1 });
2436
+ }
2437
+ }
2438
+ }
2439
+ return null;
2440
+ }
2441
+ function detectPageRole(node) {
2442
+ const when = node.bindings?.when || "";
2443
+ if (/isAdmin|is_admin/i.test(when)) return "admin";
2444
+ if (/isDriver|is_driver/i.test(when)) return "driver";
2445
+ if (/isRider|is_rider/i.test(when)) return "rider";
2446
+ const ld = node.config?.localDefaults || {};
2447
+ const keys = Object.keys(ld);
2448
+ if (keys.some((k) => k.startsWith("driver.") || k === "is_online")) return "driver";
2449
+ if (keys.some((k) => k.startsWith("earnings.") || k.startsWith("matching."))) return "driver";
2450
+ if (keys.some((k) => k.startsWith("rider."))) return "rider";
2451
+ if (keys.includes("ride.current_fare") || keys.includes("time_left")) return "driver";
2452
+ if (keys.includes("selected_vehicle") || keys.includes("driver_location")) return "rider";
2453
+ if (keys.includes("date_from") || keys.includes("date_to")) return "rider";
2454
+ if (keys.includes("cvv") || keys.includes("card_number")) return "rider";
2455
+ const title = findPageTitle(node);
2456
+ if (title) {
2457
+ const lower = title.toLowerCase();
2458
+ if (lower.includes("driver") || lower.includes("earning") || lower.includes("navigation")) return "driver";
2459
+ if (lower.includes("ride request") || lower.includes("ride acceptance")) return "driver";
2460
+ if (lower.includes("payment method") || lower.includes("ride history")) return "rider";
2461
+ if (lower.includes("your ride") || lower.includes("where to") || lower.includes("ride tracking")) return "rider";
2462
+ if (lower.includes("analytics") || lower.includes("surge") || lower.includes("fleet")) return "admin";
2463
+ }
2464
+ return "shared";
2465
+ }
2466
+ function isChildWorkflowView(node, childSlugs) {
2467
+ const title = findPageTitle(node);
2468
+ if (!title) return false;
2469
+ if (title.includes("#")) return true;
2470
+ const titleSlug = title.toLowerCase().replace(/[^a-z0-9\s]/g, "").trim().replace(/\s+/g, "-");
2471
+ return childSlugs.has(titleSlug);
2472
+ }
2473
+ function titleToSlug(title) {
2474
+ const MAP = {
2475
+ "where to?": "home",
2476
+ "where to": "home",
2477
+ "your ride": "ride-tracking",
2478
+ "incoming ride request": "ride-acceptance"
2479
+ };
2480
+ const lower = title.toLowerCase();
2481
+ if (MAP[lower]) return MAP[lower];
2482
+ return lower.replace(/[^a-z0-9\s]/g, "").trim().replace(/\s+/g, "-");
2483
+ }
2484
+ function scoreRouteMatch(title, route) {
2485
+ const titleSlug = title.toLowerCase().replace(/[^a-z0-9\s]/g, "").trim().replace(/\s+/g, "-");
2486
+ const titleWords = new Set(titleSlug.split("-").filter((w) => w.length > 2));
2487
+ let score = 0;
2488
+ for (const word of route.page.split("-")) {
2489
+ if (titleWords.has(word)) score += 2;
2490
+ }
2491
+ if (titleSlug.includes(route.page) || route.page.includes(titleSlug)) {
2492
+ score += 3;
2493
+ }
2494
+ return score;
2495
+ }
2496
+ function extractRoleGuard(node) {
2497
+ const when = node.bindings?.when || "";
2498
+ const match = when.match(/\$instance\.(is\w+)/);
2499
+ return match ? match[1] : void 0;
2500
+ }
2501
+ function collectDataSources(node) {
2502
+ const sources = [];
2503
+ const nodeDS = node.dataSources;
2504
+ if (Array.isArray(nodeDS)) sources.push(...nodeDS);
2505
+ if (node.children) {
2506
+ for (const child of node.children) {
2507
+ const childDS = child.dataSources;
2508
+ if (Array.isArray(childDS)) sources.push(...childDS);
2509
+ }
2510
+ }
2511
+ return sources;
2512
+ }
2513
+ function stripLocalDefaults(node) {
2514
+ if (!node.config?.localDefaults) return node;
2515
+ const { localDefaults, ...rest } = node.config;
2516
+ return { ...node, config: Object.keys(rest).length > 0 ? rest : void 0 };
2517
+ }
2518
+ function getPageContentTree(node) {
2519
+ if (node.component === "Show" && node.children?.length === 1) {
2520
+ return stripLocalDefaults(node.children[0]);
2521
+ }
2522
+ return stripLocalDefaults(node);
2523
+ }
2524
+ function inferFieldType(value) {
2525
+ if (typeof value === "boolean") return "boolean";
2526
+ if (typeof value === "number") return "number";
2527
+ return "text";
2528
+ }
2529
+ function extractPageSections(experience, childDefinitions) {
2530
+ if (!experience?.children) return { pages: [], childViews: [] };
2531
+ const routerExtracted = extractFromRouterExperience(experience);
2532
+ if (routerExtracted) return routerExtracted;
2533
+ const routeTable = extractRouteTable(childDefinitions);
2534
+ const childSlugs = new Set(
2535
+ (childDefinitions || []).filter((c) => !c.slug.endsWith("-router") && c.category !== "router").map((c) => c.slug)
2536
+ );
2537
+ const pages = [];
2538
+ const childViews = [];
2539
+ const candidates = [];
2540
+ for (let i = 0; i < experience.children.length; i++) {
2541
+ const child = experience.children[i];
2542
+ if (isChildWorkflowView(child, childSlugs)) {
2543
+ childViews.push(child);
2544
+ continue;
2545
+ }
2546
+ const title = findPageTitle(child);
2547
+ const role = detectPageRole(child);
2548
+ const localDefaults = child.config?.localDefaults || {};
2549
+ const roleGuard = extractRoleGuard(child);
2550
+ const dataSources = collectDataSources(child);
2551
+ candidates.push({
2552
+ title,
2553
+ role,
2554
+ index: i,
2555
+ node: child,
2556
+ localDefaults,
2557
+ roleGuard,
2558
+ dataSources: dataSources.length > 0 ? dataSources : void 0
2559
+ });
2560
+ }
2561
+ const assignments = /* @__PURE__ */ new Map();
2562
+ const usedRoutes = /* @__PURE__ */ new Set();
2563
+ for (const cand of candidates) {
2564
+ if (!cand.title) continue;
2565
+ const roleRoutes = routeTable.filter(
2566
+ (r) => r.role === cand.role && !usedRoutes.has(r.stateName)
2567
+ );
2568
+ let bestRoute = null;
2569
+ let bestScore = 0;
2570
+ for (const route of roleRoutes) {
2571
+ const score = scoreRouteMatch(cand.title, route);
2572
+ if (score > bestScore) {
2573
+ bestScore = score;
2574
+ bestRoute = route;
2575
+ }
2576
+ }
2577
+ if (bestRoute && bestScore >= 3) {
2578
+ assignments.set(cand.index, bestRoute);
2579
+ usedRoutes.add(bestRoute.stateName);
2580
+ }
2581
+ }
2582
+ let changed = true;
2583
+ while (changed) {
2584
+ changed = false;
2585
+ for (const cand of candidates) {
2586
+ if (assignments.has(cand.index)) continue;
2587
+ const remaining = routeTable.filter(
2588
+ (r) => r.role === cand.role && !usedRoutes.has(r.stateName)
2589
+ );
2590
+ if (remaining.length === 1) {
2591
+ assignments.set(cand.index, remaining[0]);
2592
+ usedRoutes.add(remaining[0].stateName);
2593
+ changed = true;
2594
+ } else if (remaining.length > 1 && cand.title) {
2595
+ let bestRoute = null;
2596
+ let bestScore = 0;
2597
+ for (const route of remaining) {
2598
+ const score = scoreRouteMatch(cand.title, route);
2599
+ if (score > bestScore) {
2600
+ bestScore = score;
2601
+ bestRoute = route;
2602
+ }
2603
+ }
2604
+ if (bestRoute && bestScore > 0) {
2605
+ assignments.set(cand.index, bestRoute);
2606
+ usedRoutes.add(bestRoute.stateName);
2607
+ changed = true;
2608
+ }
2609
+ }
2610
+ }
2611
+ }
2612
+ for (const cand of candidates) {
2613
+ const route = assignments.get(cand.index);
2614
+ const slug = route?.page || titleToSlug(cand.title || `page-${cand.index}`);
2615
+ const filePath = `app/${cand.role}/${slug}.tsx`;
2616
+ const componentName = pascalCase4(slug) + "Page";
2617
+ pages.push({
2618
+ route: route?.path || `${cand.role}/${slug}`,
2619
+ role: cand.role,
2620
+ slug,
2621
+ title: cand.title || slug,
2622
+ componentName,
2623
+ tree: cand.node,
2624
+ filePath,
2625
+ localDefaults: cand.localDefaults,
2626
+ roleGuard: cand.roleGuard,
2627
+ dataSources: cand.dataSources
2628
+ });
2629
+ }
2630
+ return { pages, childViews };
2631
+ }
2632
+ function extractFromRouterExperience(experience) {
2633
+ if (!experience.children) return null;
2634
+ const routerNode = experience.children.find((c) => c.component === "Router");
2635
+ if (!routerNode?.children) return null;
2636
+ const routes = routerNode.children.filter((c) => c.component === "Route");
2637
+ if (routes.length === 0) return null;
2638
+ const pages = [];
2639
+ const seenPaths = /* @__PURE__ */ new Set();
2640
+ for (const route of routes) {
2641
+ const routePath = route.config?.path || "";
2642
+ if (route.config?.exact && routePath === "/") continue;
2643
+ if (seenPaths.has(routePath)) continue;
2644
+ seenPaths.add(routePath);
2645
+ const segments = routePath.replace(/^\//, "").split("/").filter(Boolean);
2646
+ const role = segments.length > 1 ? segments[0] : void 0;
2647
+ const slug = segments.length > 1 ? segments.slice(1).join("-") : segments[0] || "page0";
2648
+ const filePath = role ? `app/${role}/${slug}.tsx` : `app/${slug}.tsx`;
2649
+ const componentName = pascalCase4(slug) + "Page";
2650
+ const rawPageTree = route.children?.[0] || route;
2651
+ const pageTree = { ...rawPageTree };
2652
+ if (pageTree.config) {
2653
+ const { gap, padding, ...restConfig } = pageTree.config;
2654
+ pageTree.config = Object.keys(restConfig).length > 0 ? restConfig : void 0;
2655
+ }
2656
+ const localDefaults = pageTree.config?.localDefaults || {};
2657
+ pages.push({
2658
+ route: routePath,
2659
+ role: role || "",
2660
+ slug,
2661
+ title: findPageTitle(pageTree) || slug,
2662
+ componentName,
2663
+ tree: pageTree,
2664
+ filePath,
2665
+ localDefaults
2666
+ });
2667
+ }
2668
+ return pages.length > 0 ? { pages, childViews: [] } : null;
2669
+ }
2670
+ function generatePageFileFromSection(page, modelSlugToPath) {
2671
+ const fields = Object.entries(page.localDefaults).filter(([key]) => !key.includes(".")).map(([key, value]) => ({
2672
+ name: key,
2673
+ type: inferFieldType(value),
2674
+ required: false,
2675
+ default_value: value ?? void 0
2676
+ }));
2677
+ const contentTree = getPageContentTree(page.tree);
2678
+ const metadata = {};
2679
+ if (page.dataSources && page.dataSources.length > 0) {
2680
+ metadata.dataSources = page.dataSources;
2681
+ if (modelSlugToPath) {
2682
+ const modelImports = {};
2683
+ for (const ds of page.dataSources) {
2684
+ const dsObj = ds;
2685
+ if (dsObj.type !== "workflow") continue;
2686
+ const slug = dsObj.slug || dsObj.name;
2687
+ if (!slug) continue;
2688
+ const modelPath = modelSlugToPath.get(slug);
2689
+ if (modelPath) {
2690
+ const pageDir = page.filePath.split("/").slice(0, -1).join("/");
2691
+ const rel = computeRelativeImport(pageDir, modelPath);
2692
+ modelImports[slug] = rel;
2693
+ }
2694
+ }
2695
+ if (Object.keys(modelImports).length > 0) {
2696
+ metadata.modelImports = modelImports;
2697
+ }
2698
+ }
2699
+ }
2700
+ const pageInput = {
2701
+ slug: page.slug,
2702
+ name: page.componentName,
2703
+ version: "1.0.0",
2704
+ category: "page",
2705
+ states: [],
2706
+ transitions: [],
2707
+ fields,
2708
+ roles: [],
2709
+ experience: contentTree,
2710
+ metadata: Object.keys(metadata).length > 0 ? metadata : void 0
2711
+ };
2712
+ return decompile(pageInput, {
2713
+ componentName: page.componentName,
2714
+ includeAnnotation: false
2715
+ }).code;
2716
+ }
2717
+ function computeRelativeImport(fromDir, toFile) {
2718
+ const fromParts = fromDir.split("/").filter(Boolean);
2719
+ const toParts = toFile.replace(/\.(ts|tsx)$/, "").split("/").filter(Boolean);
2720
+ let common = 0;
2721
+ while (common < fromParts.length && common < toParts.length && fromParts[common] === toParts[common]) {
2722
+ common++;
2723
+ }
2724
+ const ups = fromParts.length - common;
2725
+ const downs = toParts.slice(common);
2726
+ if (ups === 0 && downs.length === 0) return "./index";
2727
+ const prefix = ups > 0 ? "../".repeat(ups) : "./";
2728
+ return prefix + downs.join("/");
2729
+ }
2730
+ function generateMainWithPages(definition, pages, childViews) {
2731
+ const mainChildren = [];
2732
+ for (const page of pages) {
2733
+ if (page.roleGuard) {
2734
+ mainChildren.push({
2735
+ id: `page-${page.slug}`,
2736
+ component: "Show",
2737
+ bindings: { when: `$instance.${page.roleGuard}` },
2738
+ children: [{ id: `${page.slug}-ref`, component: page.componentName }]
2739
+ });
2740
+ } else {
2741
+ mainChildren.push({
2742
+ id: `page-${page.slug}`,
2743
+ component: page.componentName
2744
+ });
2745
+ }
2746
+ }
2747
+ for (const cv of childViews) {
2748
+ mainChildren.push(cv);
2749
+ }
2750
+ const mainTree = {
2751
+ id: "root",
2752
+ component: "Stack",
2753
+ children: mainChildren
2754
+ };
2755
+ const strippedMeta = { ...definition.metadata || {} };
2756
+ delete strippedMeta.dataSources;
2757
+ delete strippedMeta.queries;
2758
+ delete strippedMeta.mutations;
2759
+ delete strippedMeta.mutationTargets;
2760
+ const strippedStates = definition.states.map((s) => ({
2761
+ ...s,
2762
+ on_enter: [],
2763
+ on_exit: [],
2764
+ during: [],
2765
+ on_event: void 0
2766
+ }));
2767
+ const strippedTransitions = definition.transitions.map((t5) => ({
2768
+ ...t5,
2769
+ actions: [],
2770
+ conditions: void 0
2771
+ }));
2772
+ const modifiedDef = {
2773
+ ...definition,
2774
+ states: strippedStates,
2775
+ transitions: strippedTransitions,
2776
+ experience: mainTree,
2777
+ metadata: strippedMeta
2778
+ };
2779
+ const result = decompile(modifiedDef, { includeAnnotation: true });
2780
+ const pageImports = pages.map((p) => `import ${p.componentName} from './${p.filePath.replace(/\.tsx$/, "")}';`).join("\n");
2781
+ const code = result.code;
2782
+ const importRegex = /^import .+$/gm;
2783
+ let lastImportEnd = -1;
2784
+ let m;
2785
+ while ((m = importRegex.exec(code)) !== null) {
2786
+ lastImportEnd = m.index + m[0].length;
2787
+ }
2788
+ if (lastImportEnd > 0) {
2789
+ return code.slice(0, lastImportEnd) + "\n" + pageImports + code.slice(lastImportEnd);
2790
+ }
2791
+ return pageImports + "\n" + code;
2792
+ }
2793
+ var SERVER_ACTION_TYPES = /* @__PURE__ */ new Set([
2794
+ "http_request",
2795
+ "webhook",
2796
+ "call_webhook",
2797
+ "notify",
2798
+ "send_notification",
2799
+ "call_workflow",
2800
+ "spawn_instance",
2801
+ "spawn_subworkflow",
2802
+ "emit_event",
2803
+ "custom"
2804
+ ]);
2805
+ function extractServerActions2(states, transitions) {
2806
+ const seen = /* @__PURE__ */ new Set();
2807
+ const actions = [];
2808
+ function collect(defs) {
2809
+ for (const action of defs) {
2810
+ if (SERVER_ACTION_TYPES.has(action.type) && !seen.has(action.id)) {
2811
+ seen.add(action.id);
2812
+ const slug = String(action.config.name || action.config.event || action.config.slug || action.type);
2813
+ const name = camelCase2(slug.replace(/[^a-zA-Z0-9_-]/g, "-"));
2814
+ actions.push({ name, type: action.type, config: action.config });
2815
+ }
2816
+ }
2817
+ }
2818
+ for (const state of states) {
2819
+ collect(state.on_enter);
2820
+ collect(state.on_exit);
2821
+ for (const during of state.during) {
2822
+ collect(during.actions);
2823
+ }
2824
+ }
2825
+ for (const trans of transitions) {
2826
+ collect(trans.actions);
2827
+ }
2828
+ return actions;
2829
+ }
2830
+ function generateServerActionFile2(slug, actions) {
2831
+ const lines = [
2832
+ `/**`,
2833
+ ` * Server actions for "${slug}".`,
2834
+ ` *`,
2835
+ ` * These run server-side during state transitions.`,
2836
+ ` */`,
2837
+ ``,
2838
+ `import type { TransitionContext } from '@mindmatrix/react';`,
2839
+ ``
2840
+ ];
2841
+ for (const action of actions) {
2842
+ lines.push(`/** ${actionComment2(action)} */`);
2843
+ lines.push(`export async function ${action.name}(ctx: TransitionContext): Promise<void> {`);
2844
+ lines.push(` const { instance, env } = ctx;`);
2845
+ switch (action.type) {
2846
+ case "http_request":
2847
+ case "webhook":
2848
+ case "call_webhook": {
2849
+ const url = String(action.config.url || "https://api.example.com/webhook");
2850
+ const method = String(action.config.method || "POST");
2851
+ lines.push(` await fetch('${esc2(url)}', {`);
2852
+ lines.push(` method: '${method}',`);
2853
+ lines.push(` headers: { 'Content-Type': 'application/json' },`);
2854
+ lines.push(` body: JSON.stringify({ instanceId: instance.id }),`);
2855
+ lines.push(` });`);
2856
+ break;
2857
+ }
2858
+ case "notify":
2859
+ case "send_notification": {
2860
+ const msg = String(action.config.message || action.config.body || "Notification");
2861
+ lines.push(` await env.notify({ message: '${esc2(msg)}', instanceId: instance.id });`);
2862
+ break;
2863
+ }
2864
+ case "call_workflow":
2865
+ case "spawn_instance":
2866
+ case "spawn_subworkflow": {
2867
+ const target = String(action.config.slug || action.config.workflow || "child-workflow");
2868
+ lines.push(` await env.spawn('${esc2(target)}', { parentId: instance.id });`);
2869
+ break;
2870
+ }
2871
+ case "emit_event": {
2872
+ const event = String(action.config.event || action.config.name || "custom-event");
2873
+ lines.push(` await env.emit('${esc2(event)}', { instanceId: instance.id });`);
2874
+ break;
2875
+ }
2876
+ case "custom": {
2877
+ const expr = action.config.expression || action.config.body;
2878
+ if (expr) {
2879
+ lines.push(` // Original expression: ${String(expr).replace(/\n/g, "\\n").slice(0, 200)}`);
2880
+ }
2881
+ lines.push(` // TODO: Implement custom action logic`);
2882
+ lines.push(` throw new Error('Not implemented \u2014 decompiled stub');`);
2883
+ break;
2884
+ }
2885
+ default:
2886
+ lines.push(` // TODO: Implement ${action.type} logic`);
2887
+ }
2888
+ lines.push(`}`);
2889
+ lines.push(``);
2890
+ }
2891
+ return lines.join("\n");
2892
+ }
2893
+ function actionComment2(action) {
2894
+ switch (action.type) {
2895
+ case "http_request":
2896
+ case "webhook":
2897
+ case "call_webhook":
2898
+ return `HTTP ${action.config.method || "POST"} to ${action.config.url || "webhook"}`;
2899
+ case "notify":
2900
+ case "send_notification":
2901
+ return `Send notification: ${action.config.message || ""}`;
2902
+ case "call_workflow":
2903
+ case "spawn_instance":
2904
+ case "spawn_subworkflow":
2905
+ return `Spawn workflow: ${action.config.slug || action.config.workflow || ""}`;
2906
+ case "emit_event":
2907
+ return `Emit event: ${action.config.event || action.config.name || ""}`;
2908
+ case "custom":
2909
+ return `Custom action: ${action.name}`;
2910
+ default:
2911
+ return `Server action: ${action.type}`;
2912
+ }
2913
+ }
2914
+ function emitComponentDefinitions(definition, files) {
2915
+ const meta = definition.metadata;
2916
+ const componentDefs = meta?.componentDefinitions;
2917
+ if (!componentDefs) return;
2918
+ for (const [name, def] of Object.entries(componentDefs)) {
2919
+ const content = generateComponentFromDefinition(name, def.experience, def.props);
2920
+ files.push({
2921
+ path: `components/${name}.tsx`,
2922
+ role: "component",
2923
+ content
2924
+ });
2925
+ }
2926
+ }
2927
+ function inferPropType(propName, experience) {
2928
+ const usages = [];
2929
+ collectPropUsages(propName, experience, usages);
2930
+ if (propName.startsWith("on") && propName.length > 2 && propName[2] === propName[2].toUpperCase()) {
2931
+ return "(() => void)";
2932
+ }
2933
+ const boolNames = ["show", "is", "has", "enable", "disable", "compact", "track", "follow"];
2934
+ if (boolNames.some((b) => propName.toLowerCase().startsWith(b))) return "boolean";
2935
+ for (const usage of usages) {
2936
+ if (usage.includes(".address") || usage.includes("Address")) return "{ address: string; latitude: number; longitude: number }";
2937
+ if (usage.includes(".toFixed")) return "number";
2938
+ if (usage.includes(".toLocaleString")) return "number";
2939
+ if (usage.includes(".heading")) return "{ latitude: number; longitude: number; heading: number }";
2940
+ if (usage.includes(".length")) return "unknown[]";
2941
+ }
2942
+ if (/url|src|image|avatar|icon/i.test(propName)) return "string";
2943
+ if (/count|amount|total|rating|eta|minutes|radius|zoom/i.test(propName)) return "number";
2944
+ if (/style|sx/i.test(propName)) return "React.CSSProperties";
2945
+ if (/items|list|zones|options/i.test(propName)) return "unknown[]";
2946
+ if (/location|position|point/i.test(propName)) return "{ latitude: number; longitude: number }";
2947
+ return "unknown";
2948
+ }
2949
+ function collectPropUsages(propName, node, out) {
2950
+ if (node.bindings) {
2951
+ for (const expr of Object.values(node.bindings)) {
2952
+ if (typeof expr === "string" && expr.includes(propName)) {
2953
+ out.push(expr);
2954
+ }
2955
+ }
2956
+ }
2957
+ if (node.visible_when && typeof node.visible_when === "string" && node.visible_when.includes(propName)) {
2958
+ out.push(node.visible_when);
2959
+ }
2960
+ if (node.children) {
2961
+ for (const child of node.children) {
2962
+ collectPropUsages(propName, child, out);
2963
+ }
2964
+ }
2965
+ }
2966
+ function generateComponentFromDefinition(name, experience, props) {
2967
+ const pageInput = {
2968
+ slug: name.toLowerCase(),
2969
+ name,
2970
+ version: "1.0.0",
2971
+ category: "component",
2972
+ states: [],
2973
+ transitions: [],
2974
+ fields: [],
2975
+ roles: [],
2976
+ experience
2977
+ };
2978
+ const result = decompile(pageInput, {
2979
+ componentName: name,
2980
+ includeAnnotation: false
2981
+ });
2982
+ if (props.length > 0) {
2983
+ const typedProps = props.map((p) => {
2984
+ const type = inferPropType(p, experience);
2985
+ const isCallback = p.startsWith("on") && p.length > 2 && p[2] === p[2].toUpperCase();
2986
+ const optional = isCallback ? "?" : "";
2987
+ return ` ${p}${optional}: ${type};`;
2988
+ });
2989
+ const propsInterface = `interface ${name}Props {
2990
+ ${typedProps.join("\n")}
2991
+ }
2992
+
2993
+ `;
2994
+ const code = result.code.replace(
2995
+ `export default function ${name}()`,
2996
+ `${propsInterface}export default function ${name}({ ${props.join(", ")} }: ${name}Props)`
2997
+ );
2998
+ return code;
2999
+ }
3000
+ return result.code;
3001
+ }
3002
+ function generateActionFile(child) {
3003
+ const isSimple = isSimpleActionDefinition(child);
3004
+ if (isSimple) {
3005
+ return generateSimpleActionFile(child);
3006
+ }
3007
+ return generateModelFile2(
3008
+ child.slug,
3009
+ child.fields,
3010
+ child.states,
3011
+ child.transitions,
3012
+ {
3013
+ version: child.version,
3014
+ category: "action",
3015
+ description: child.description
3016
+ }
3017
+ );
3018
+ }
3019
+ function isSimpleActionDefinition(child) {
3020
+ const stateNames = child.states.map((s) => s.name);
3021
+ const hasReady = stateNames.includes("ready");
3022
+ const hasDone = stateNames.includes("done");
3023
+ if (!hasReady || !hasDone || stateNames.length !== 2) return false;
3024
+ if (child.transitions.length !== 1) return false;
3025
+ const exec = child.transitions[0];
3026
+ if (exec.name !== "execute") return false;
3027
+ if (exec.actions.length !== 1) return false;
3028
+ const action = exec.actions[0];
3029
+ if (action.type !== "eval") return false;
3030
+ const config = action.config;
3031
+ return typeof config.expression === "string";
3032
+ }
3033
+ function generateSimpleActionFile(child) {
3034
+ const exec = child.transitions[0];
3035
+ const evalAction = exec.actions[0];
3036
+ const expression = String(evalAction.config.expression || "");
3037
+ const params = child.fields.map((f) => {
3038
+ const paramName = camelCase2(f.name);
3039
+ const tsType = fieldTypeToTS2(f.type, f);
3040
+ const optional = f.required === false ? "?" : "";
3041
+ return `${paramName}${optional}: ${tsType}`;
3042
+ });
3043
+ const funcName = camelCase2(child.slug);
3044
+ const meta = child.metadata;
3045
+ const sourceFn = typeof meta?.source_function === "string" ? meta.source_function : funcName;
3046
+ const returnType = typeof meta?.return_type === "string" ? meta.return_type : "void";
3047
+ const lines = [];
3048
+ const bodyLines = expression.split("\n").map((l) => ` ${l}`).join("\n");
3049
+ lines.push(`/**`);
3050
+ if (child.description) {
3051
+ lines.push(` * ${child.description}`);
3052
+ } else {
3053
+ lines.push(` * ${child.name || sourceFn}`);
3054
+ }
3055
+ lines.push(` */`);
3056
+ lines.push(`export default function ${sourceFn}(${params.join(", ")}): ${returnType} {`);
3057
+ if (bodyLines.trim()) {
3058
+ lines.push(bodyLines);
3059
+ } else {
3060
+ lines.push(` // TODO: implement`);
3061
+ }
3062
+ lines.push(`}`);
3063
+ lines.push(``);
3064
+ return lines.join("\n");
3065
+ }
3066
+ function emitServerActionsFromMetadata(definition, files) {
3067
+ const meta = definition.metadata;
3068
+ const serverActions = meta?.serverActions;
3069
+ if (!serverActions || serverActions.length === 0) return [];
3070
+ const actionsWithBodies = serverActions.filter((a) => a.body);
3071
+ if (actionsWithBodies.length === 0) return [];
3072
+ const byFile = /* @__PURE__ */ new Map();
3073
+ for (const action of actionsWithBodies) {
3074
+ const file2 = action.sourceFile || `actions/${action.name}.server.ts`;
3075
+ if (!byFile.has(file2)) byFile.set(file2, []);
3076
+ byFile.get(file2).push(action);
3077
+ }
3078
+ const emittedPaths = [];
3079
+ for (const [filePath, actions] of byFile) {
3080
+ const content = generateServerActionFileFromBodies(filePath, actions);
3081
+ const existing = files.findIndex((f) => f.path === filePath);
3082
+ if (existing !== -1) {
3083
+ files[existing].content = content;
3084
+ } else {
3085
+ files.push({ path: filePath, role: "server-action", content });
3086
+ }
3087
+ emittedPaths.push(filePath);
3088
+ }
3089
+ return emittedPaths;
3090
+ }
3091
+ function generateServerActionFileFromBodies(filePath, actions) {
3092
+ const lines = [
3093
+ `/**`,
3094
+ ` * Server actions \u2014 ${filePath}`,
3095
+ ` *`,
3096
+ ` * Auto-generated from preserved function bodies.`,
3097
+ ` */`,
3098
+ ``,
3099
+ `import type { TransitionContext, ActionResult } from '@mindmatrix/react';`,
3100
+ ``
3101
+ ];
3102
+ for (const action of actions) {
3103
+ if (action.body) {
3104
+ lines.push(action.body);
3105
+ lines.push(``);
3106
+ }
3107
+ }
3108
+ return lines.join("\n");
3109
+ }
3110
+ function reduceRouterTransitions(transitions, states) {
3111
+ if (transitions.length === 0) return transitions;
3112
+ const stateNames = new Set(states.map((s) => s.name));
3113
+ const roleGroups = /* @__PURE__ */ new Map();
3114
+ for (const state of states) {
3115
+ const parts = state.name.split("_");
3116
+ const role = parts[0];
3117
+ if (!roleGroups.has(role)) roleGroups.set(role, []);
3118
+ roleGroups.get(role).push(state.name);
3119
+ }
3120
+ const homeStates = /* @__PURE__ */ new Set();
3121
+ for (const [, group] of roleGroups) {
3122
+ const home = group.find(
3123
+ (s) => s.includes("HOME") || s.includes("DASHBOARD") || s.includes("ANALYTICS")
3124
+ ) || group[0];
3125
+ homeStates.add(home);
3126
+ }
3127
+ const kept = [];
3128
+ const seenKeys = /* @__PURE__ */ new Set();
3129
+ for (const t5 of transitions) {
3130
+ const fromArr = Array.isArray(t5.from) ? t5.from : [t5.from];
3131
+ const fromState = fromArr[0];
3132
+ const toState = t5.to;
3133
+ if (!fromState || !stateNames.has(fromState) || !stateNames.has(toState)) continue;
3134
+ const fromRole = fromState.split("_")[0];
3135
+ const toRole = toState.split("_")[0];
3136
+ const key = `${fromState}\u2192${toState}`;
3137
+ if (seenKeys.has(key)) continue;
3138
+ const sameRole = fromRole === toRole;
3139
+ const crossRoleHome = homeStates.has(fromState) && homeStates.has(toState);
3140
+ if (sameRole || crossRoleHome) {
3141
+ seenKeys.add(key);
3142
+ kept.push(t5);
3143
+ }
3144
+ }
3145
+ return kept;
3146
+ }
3147
+ function decompileProjectEnhanced(definition) {
3148
+ const slug = definition.slug;
3149
+ const decision = determineSplitStrategy(definition);
3150
+ const files = [];
3151
+ const modelPaths = [];
3152
+ const entryPaths = [];
3153
+ const actionPaths = [];
3154
+ if (decision.tier === "single") {
3155
+ const result = decompile(definition);
3156
+ files.push({
3157
+ path: "main.workflow.tsx",
3158
+ role: "view-entry",
3159
+ content: result.code
3160
+ });
3161
+ emitComponentDefinitions(definition, files);
3162
+ emitServerActionsFromMetadata(definition, files);
3163
+ return { files, entryFile: "main.workflow.tsx", slug, splitDecision: decision };
3164
+ }
3165
+ if (decision.emitModels && definition.fields.length > 0) {
3166
+ const modelPath = `models/${slug}.ts`;
3167
+ const modelContent = generateModelFile2(
3168
+ slug,
3169
+ definition.fields,
3170
+ definition.states,
3171
+ definition.transitions,
3172
+ { version: definition.version, category: Array.isArray(definition.category) ? definition.category[0] : definition.category, description: definition.description }
3173
+ );
3174
+ files.push({ path: modelPath, role: "model", content: modelContent });
3175
+ modelPaths.push(modelPath);
3176
+ }
3177
+ if (decision.emitActions) {
3178
+ const serverActions = extractServerActions2(definition.states, definition.transitions);
3179
+ if (serverActions.length > 0) {
3180
+ const actionPath = `actions/${slug}.server.ts`;
3181
+ const actionContent = generateServerActionFile2(slug, serverActions);
3182
+ files.push({ path: actionPath, role: "server-action", content: actionContent });
3183
+ actionPaths.push(actionPath);
3184
+ }
3185
+ }
3186
+ let pagesExtracted = false;
3187
+ let extractedPages = [];
3188
+ let extractedChildViews = [];
3189
+ let routerIsCompilerGenerated = false;
3190
+ if (decision.emitPages && definition.experience) {
3191
+ const routerNode = definition.experience.children?.find(
3192
+ (c) => c.component === "Router"
3193
+ );
3194
+ routerIsCompilerGenerated = !!routerNode;
3195
+ const { pages, childViews } = extractPageSections(
3196
+ definition.experience,
3197
+ definition.childDefinitions
3198
+ );
3199
+ if (pages.length > 0) {
3200
+ pagesExtracted = true;
3201
+ extractedPages = pages;
3202
+ extractedChildViews = childViews;
3203
+ const modelSlugToPath = /* @__PURE__ */ new Map();
3204
+ modelSlugToPath.set(slug, `models/${slug}.ts`);
3205
+ if (definition.childDefinitions) {
3206
+ for (const child of definition.childDefinitions) {
3207
+ const cs = child.slug;
3208
+ if (!cs.endsWith("-router") && child.category !== "router") {
3209
+ modelSlugToPath.set(cs, `models/${cs}.ts`);
3210
+ }
3211
+ }
3212
+ }
3213
+ for (const page of pages) {
3214
+ const pageContent = generatePageFileFromSection(page, modelSlugToPath);
3215
+ files.push({ path: page.filePath, role: "page", content: pageContent });
3216
+ }
3217
+ }
3218
+ }
3219
+ if (definition.roles && definition.roles.length > 0 && decision.tier === "large") {
3220
+ const layoutContent = generateLayoutFile(slug, definition.roles);
3221
+ files.push({ path: "app/layout.tsx", role: "layout", content: layoutContent });
3222
+ }
3223
+ const emittedModelSlugs = new Set(modelPaths.map((p) => p.replace("models/", "").replace(".ts", "")));
3224
+ const mergedChildren = /* @__PURE__ */ new Map();
3225
+ if (definition.childDefinitions && definition.childDefinitions.length > 0) {
3226
+ for (const child of definition.childDefinitions) {
3227
+ const childSlug = child.slug;
3228
+ if (childSlug === slug) continue;
3229
+ const isRouter = childSlug.endsWith("-router") || child.category === "router";
3230
+ if (isRouter && routerIsCompilerGenerated) continue;
3231
+ if (!mergedChildren.has(childSlug)) {
3232
+ mergedChildren.set(childSlug, { ...child });
3233
+ } else {
3234
+ const existing = mergedChildren.get(childSlug);
3235
+ const fieldMap = new Map(existing.fields.map((f) => [f.name, f]));
3236
+ for (const f of child.fields) {
3237
+ if (fieldMap.has(f.name)) {
3238
+ const ef = fieldMap.get(f.name);
3239
+ if (f.required && !ef.required) ef.required = true;
3240
+ if (f.default_value != null && (ef.default_value == null || ef.default_value === "" || ef.default_value === 0 || ef.default_value === false)) {
3241
+ ef.default_value = f.default_value;
3242
+ }
3243
+ } else {
3244
+ existing.fields.push(f);
3245
+ fieldMap.set(f.name, f);
3246
+ }
3247
+ }
3248
+ if (child.states.length > existing.states.length) {
3249
+ const existingByName = new Map(existing.states.map((s) => [s.name, s]));
3250
+ existing.states = child.states.map((s) => {
3251
+ const ex = existingByName.get(s.name);
3252
+ if (ex && (ex.on_enter.length || ex.on_exit.length || ex.during.length)) {
3253
+ return { ...s, on_enter: ex.on_enter, on_exit: ex.on_exit, during: ex.during };
3254
+ }
3255
+ return s;
3256
+ });
3257
+ const childNames = new Set(child.states.map((s) => s.name));
3258
+ const hasStart = child.states.some((s) => s.type === "START");
3259
+ for (const s of existingByName.values()) {
3260
+ if (!childNames.has(s.name)) {
3261
+ if (s.name === "draft" && s.type === "START" && hasStart) continue;
3262
+ existing.states.push(s);
3263
+ }
3264
+ }
3265
+ } else {
3266
+ const stateNames = new Set(existing.states.map((s) => s.name));
3267
+ for (const s of child.states) {
3268
+ if (!stateNames.has(s.name)) {
3269
+ existing.states.push(s);
3270
+ stateNames.add(s.name);
3271
+ }
3272
+ }
3273
+ }
3274
+ const transNames = new Set(existing.transitions.map((t5) => t5.name));
3275
+ for (const t5 of child.transitions) {
3276
+ if (!transNames.has(t5.name)) {
3277
+ existing.transitions.push(t5);
3278
+ transNames.add(t5.name);
3279
+ }
3280
+ }
3281
+ if (child.version && child.version !== "0.1.0" && (!existing.version || existing.version === "0.1.0")) {
3282
+ existing.version = child.version;
3283
+ }
3284
+ if (child.category && child.category !== "data" && (!existing.category || existing.category === "data")) {
3285
+ existing.category = child.category;
3286
+ }
3287
+ if (child.description && !existing.description) {
3288
+ existing.description = child.description;
3289
+ }
3290
+ }
3291
+ }
3292
+ }
3293
+ for (const [childSlug, child] of mergedChildren) {
3294
+ const isRouter = childSlug.endsWith("-router") || child.category === "router";
3295
+ const isAction = child.category === "action";
3296
+ const childTransitions = isRouter ? reduceRouterTransitions(child.transitions, child.states) : child.transitions;
3297
+ if (isAction) {
3298
+ const actionFilePath = `actions/${childSlug}.ts`;
3299
+ files.push({
3300
+ path: actionFilePath,
3301
+ role: "model",
3302
+ content: generateActionFile({ ...child, transitions: childTransitions })
3303
+ });
3304
+ actionPaths.push(actionFilePath);
3305
+ continue;
3306
+ }
3307
+ if (child.fields.length > 0 && !emittedModelSlugs.has(childSlug)) {
3308
+ const childModelPath = `models/${childSlug}.ts`;
3309
+ files.push({
3310
+ path: childModelPath,
3311
+ role: "model",
3312
+ content: generateModelFile2(
3313
+ childSlug,
3314
+ child.fields,
3315
+ child.states,
3316
+ childTransitions,
3317
+ { version: child.version, category: Array.isArray(child.category) ? child.category[0] : child.category, description: child.description }
3318
+ )
3319
+ });
3320
+ modelPaths.push(childModelPath);
3321
+ emittedModelSlugs.add(childSlug);
3322
+ }
3323
+ const childInput = {
3324
+ ...child,
3325
+ version: child.version || definition.version,
3326
+ category: child.category || definition.category,
3327
+ transitions: childTransitions,
3328
+ experience: child.views?.default
3329
+ };
3330
+ const childResult = decompile(childInput, {
3331
+ componentName: pascalCase4(childSlug),
3332
+ includeAnnotation: true
3333
+ });
3334
+ const childPath = `${childSlug}.workflow.tsx`;
3335
+ files.push({ path: childPath, role: "view-entry", content: childResult.code });
3336
+ entryPaths.push(childPath);
3337
+ }
3338
+ emitComponentDefinitions(definition, files);
3339
+ const emittedActionPaths = emitServerActionsFromMetadata(definition, files);
3340
+ actionPaths.push(...emittedActionPaths);
3341
+ const mainPath = "main.workflow.tsx";
3342
+ if (pagesExtracted) {
3343
+ const mainContent = generateMainWithPages(definition, extractedPages, extractedChildViews);
3344
+ files.push({ path: mainPath, role: "view-entry", content: mainContent });
3345
+ } else {
3346
+ const mainDef = decision.emitModels ? {
3347
+ ...definition,
3348
+ states: definition.states.map((s) => ({
3349
+ ...s,
3350
+ on_enter: [],
3351
+ on_exit: [],
3352
+ during: [],
3353
+ on_event: void 0
3354
+ })),
3355
+ // Also strip transition actions — model file has them
3356
+ transitions: definition.transitions.map((t5) => ({
3357
+ ...t5,
3358
+ actions: [],
3359
+ conditions: void 0
3360
+ }))
3361
+ } : definition;
3362
+ const mainResult = decompile(mainDef);
3363
+ files.push({ path: mainPath, role: "view-entry", content: mainResult.code });
3364
+ }
3365
+ entryPaths.push(mainPath);
3366
+ if (decision.emitConfig) {
3367
+ const configData = extractConfigData(
3368
+ definition,
3369
+ [...new Set(modelPaths)],
3370
+ [...new Set(entryPaths)],
3371
+ [...new Set(actionPaths)]
3372
+ );
3373
+ const configContent = generateMmConfig(configData);
3374
+ files.push({ path: "mm.config.ts", role: "config", content: configContent });
3375
+ }
3376
+ files.push({
3377
+ path: "package.json",
3378
+ role: "config",
3379
+ content: generatePackageJson(definition)
3380
+ });
3381
+ files.push({
3382
+ path: "tsconfig.json",
3383
+ role: "config",
3384
+ content: TSCONFIG_TEMPLATE
3385
+ });
3386
+ return {
3387
+ files,
3388
+ entryFile: mainPath,
3389
+ slug,
3390
+ splitDecision: decision
3391
+ };
3392
+ }
3393
+ var TSCONFIG_TEMPLATE = JSON.stringify({
3394
+ compilerOptions: {
3395
+ target: "ES2022",
3396
+ module: "ESNext",
3397
+ moduleResolution: "bundler",
3398
+ jsx: "react-jsx",
3399
+ strict: true,
3400
+ esModuleInterop: true,
3401
+ skipLibCheck: true,
3402
+ forceConsistentCasingInFileNames: true,
3403
+ declaration: true,
3404
+ sourceMap: true,
3405
+ outDir: "dist",
3406
+ rootDir: ".",
3407
+ baseUrl: ".",
3408
+ paths: { "@/*": ["./*"] }
3409
+ },
3410
+ include: ["**/*.ts", "**/*.tsx"],
3411
+ exclude: ["node_modules", "dist"]
3412
+ }, null, 2) + "\n";
3413
+ function generatePackageJson(def) {
3414
+ const pkg = {
3415
+ name: `@mindmatrix/blueprint-${def.slug}`,
3416
+ version: def.version || "1.0.0",
3417
+ description: def.description || "",
3418
+ type: "module",
3419
+ main: "main.workflow.tsx",
3420
+ scripts: {
3421
+ "type-check": "tsc --noEmit",
3422
+ build: "mmrc build --src .",
3423
+ deploy: "mmrc deploy --build --src ."
3424
+ },
3425
+ peerDependencies: {
3426
+ react: ">=18.0.0",
3427
+ "@mindmatrix/react": "workspace:*"
3428
+ },
3429
+ devDependencies: {
3430
+ "@mindmatrix/react-compiler": "workspace:*",
3431
+ "@types/react": "^19.0.0",
3432
+ typescript: "^5.4.0"
3433
+ }
3434
+ };
3435
+ return JSON.stringify(pkg, null, 2) + "\n";
3436
+ }
3437
+ function esc2(s) {
3438
+ return s.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
3439
+ }
3440
+
3441
+ export {
3442
+ decompileProject,
3443
+ shouldDecompileAsProject,
3444
+ decompileProjectEnhanced,
3445
+ decompile
3446
+ };