@mmapp/react-compiler 0.1.0-alpha.1 → 0.1.0-alpha.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ATOM-PIPELINE.md +144 -0
- package/README.md +88 -40
- package/dist/babel/index.js +2814 -277
- package/dist/babel/index.mjs +2 -2
- package/dist/chunk-3USIFFE4.mjs +2190 -0
- package/dist/chunk-45YMGEVT.mjs +186 -0
- package/dist/chunk-4FN2AISW.mjs +148 -0
- package/dist/chunk-4OPI5L7G.mjs +2593 -0
- package/dist/chunk-4RYTKOOJ.mjs +186 -0
- package/dist/chunk-52XHYD2V.mjs +214 -0
- package/dist/chunk-5GUFFFGL.mjs +148 -0
- package/dist/chunk-5RKTOVR5.mjs +244 -0
- package/dist/chunk-5YDMOO4X.mjs +214 -0
- package/dist/chunk-64ZWEMLJ.mjs +148 -0
- package/dist/chunk-6XP4KSWQ.mjs +2190 -0
- package/dist/chunk-72QWL54I.mjs +175 -0
- package/dist/chunk-7B4TRI7C.mjs +4835 -0
- package/dist/chunk-7ZKGHTNB.mjs +4952 -0
- package/dist/chunk-CIESM3BP.mjs +33 -0
- package/dist/chunk-DE3ZGQAC.mjs +148 -0
- package/dist/chunk-DMCY3BBG.mjs +1933 -0
- package/dist/chunk-DPIK3PJS.mjs +244 -0
- package/dist/chunk-E5IVH4RE.mjs +186 -0
- package/dist/chunk-E6FZNUR5.mjs +4953 -0
- package/dist/chunk-EJRBDQDP.mjs +2607 -0
- package/dist/chunk-ELO4TXJL.mjs +186 -0
- package/dist/chunk-EO6SYNCG.mjs +175 -0
- package/dist/chunk-FKRO52XH.mjs +3446 -0
- package/dist/chunk-FL4YAKU6.mjs +4941 -0
- package/dist/chunk-FYT47UBU.mjs +5076 -0
- package/dist/chunk-GCLGPOJZ.mjs +148 -0
- package/dist/chunk-GXB4JOP7.mjs +5072 -0
- package/dist/chunk-HFXOUMTD.mjs +175 -0
- package/dist/chunk-HWIZ47US.mjs +214 -0
- package/dist/chunk-IB7MNPQL.mjs +4953 -0
- package/dist/chunk-ICSIHQCG.mjs +148 -0
- package/dist/chunk-J7JUAHS4.mjs +186 -0
- package/dist/chunk-JLA5VNQ3.mjs +186 -0
- package/dist/chunk-JQLWFCTM.mjs +214 -0
- package/dist/chunk-KFJJCQAL.mjs +148 -0
- package/dist/chunk-KJUIIEQE.mjs +186 -0
- package/dist/chunk-KNWTHRVQ.mjs +175 -0
- package/dist/chunk-KSG4XSZF.mjs +175 -0
- package/dist/chunk-LF5N6DOU.mjs +175 -0
- package/dist/chunk-LJQCM2IM.mjs +214 -0
- package/dist/chunk-NTB7OEX2.mjs +2918 -0
- package/dist/chunk-NW6555WJ.mjs +186 -0
- package/dist/chunk-OMZE6VLQ.mjs +214 -0
- package/dist/chunk-OPJKP747.mjs +7506 -0
- package/dist/chunk-P4BR7WVO.mjs +2190 -0
- package/dist/chunk-QQHVYH2X.mjs +244 -0
- package/dist/chunk-S5QLWLLT.mjs +186 -0
- package/dist/chunk-SCWGT2FY.mjs +2190 -0
- package/dist/chunk-SMKJUSB3.mjs +2190 -0
- package/dist/chunk-THFYE5ZX.mjs +244 -0
- package/dist/chunk-VCAY2KGM.mjs +175 -0
- package/dist/chunk-WBYMW4NQ.mjs +3450 -0
- package/dist/chunk-WECAV6QB.mjs +148 -0
- package/dist/chunk-WMKBXUCE.mjs +3228 -0
- package/dist/chunk-XAJ5BKKL.mjs +4947 -0
- package/dist/chunk-XG2X7AEA.mjs +175 -0
- package/dist/chunk-XG7Z23NQ.mjs +148 -0
- package/dist/chunk-XWZAOCQ7.mjs +2607 -0
- package/dist/chunk-Y6MA7ULW.mjs +148 -0
- package/dist/chunk-YMS7Q7LG.mjs +214 -0
- package/dist/chunk-ZA37XTGA.mjs +175 -0
- package/dist/cli/index.js +13189 -6838
- package/dist/cli/index.mjs +140 -22
- package/dist/codemod/cli.mjs +1 -1
- package/dist/codemod/index.mjs +1 -1
- package/dist/config-PL24KEWL.mjs +219 -0
- package/dist/dev-server-RmGHIntF.d.mts +113 -0
- package/dist/dev-server-RmGHIntF.d.ts +113 -0
- package/dist/dev-server.d.mts +1 -1
- package/dist/dev-server.d.ts +1 -1
- package/dist/dev-server.js +4135 -440
- package/dist/dev-server.mjs +5 -5
- package/dist/envelope.js +2812 -275
- package/dist/envelope.mjs +3 -3
- package/dist/index.d.mts +161 -2
- package/dist/index.d.ts +161 -2
- package/dist/index.js +4429 -428
- package/dist/index.mjs +217 -9
- package/{src/cli/init.ts → dist/init-7JQMAAXS.mjs} +70 -95
- package/dist/init-DQDX3QK6.mjs +369 -0
- package/dist/init-EHO4VQ22.mjs +369 -0
- package/dist/init-UC3FWPIW.mjs +367 -0
- package/dist/init-UNSMVKIK.mjs +366 -0
- package/dist/init-UNV5XIDE.mjs +367 -0
- package/dist/project-compiler-2P4N4DR7.mjs +10 -0
- package/dist/project-compiler-D2LCC27O.mjs +10 -0
- package/dist/project-compiler-EJ3GANJE.mjs +10 -0
- package/dist/project-compiler-LOQKVRZJ.mjs +10 -0
- package/dist/project-compiler-OP2VVGJQ.mjs +10 -0
- package/dist/project-compiler-RQ6OQKRM.mjs +10 -0
- package/dist/project-compiler-VWNNCHGO.mjs +10 -0
- package/dist/project-compiler-XVAAU4C5.mjs +10 -0
- package/dist/project-compiler-YES5FGMD.mjs +10 -0
- package/dist/project-compiler-ZKMQDLGU.mjs +10 -0
- package/dist/project-decompiler-FLXCEJHS.mjs +7 -0
- package/dist/project-decompiler-US7GAVIC.mjs +7 -0
- package/dist/project-decompiler-VLPR22QF.mjs +7 -0
- package/dist/pull-FUS5QYZS.mjs +109 -0
- package/dist/pull-LD5ENLGY.mjs +109 -0
- package/dist/pull-P44LDRWB.mjs +109 -0
- package/dist/testing/index.js +2822 -285
- package/dist/testing/index.mjs +2 -2
- package/dist/verify-SEIXUGN4.mjs +1833 -0
- package/dist/vite/index.js +2815 -278
- package/dist/vite/index.mjs +3 -3
- package/examples/uber-app/app/admin/fleet.tsx +19 -19
- package/package.json +16 -6
- package/compile-blueprint-chat.mjs +0 -99
- package/compile-blueprint-glass-console.mjs +0 -98
- package/compile-chat-defs.mjs +0 -92
- package/examples/uber-app/tests/payment.test.tsx +0 -129
- package/examples/uber-app/tests/ride-flow.test.tsx +0 -123
- package/package.json.backup +0 -86
- package/scripts/decompile.ts +0 -226
- package/scripts/seed-auth.ts +0 -267
- package/scripts/seed-uber.ts +0 -248
- package/scripts/validate-uber.ts +0 -119
- package/seed-blueprint-chat.mjs +0 -444
- package/seed-blueprint-glass-console.mjs +0 -445
- package/seed-compiled.mjs +0 -318
- package/src/RoundTripValidator.ts +0 -400
- package/src/__tests__/atom-rendering-coverage.test.ts +0 -680
- package/src/__tests__/auth-module-compilation.test.ts +0 -247
- package/src/__tests__/auth-template-compilation.test.ts +0 -589
- package/src/__tests__/change-extractor.test.ts +0 -142
- package/src/__tests__/cli-pull.test.ts +0 -73
- package/src/__tests__/cli-test.test.ts +0 -72
- package/src/__tests__/component-extractor.test.ts +0 -331
- package/src/__tests__/context-extractor.test.ts +0 -145
- package/src/__tests__/decompiler.test.ts +0 -718
- package/src/__tests__/define-blueprint.test.ts +0 -133
- package/src/__tests__/definition-validator.test.ts +0 -519
- package/src/__tests__/during-extractor.test.ts +0 -152
- package/src/__tests__/effect-extractor.test.ts +0 -107
- package/src/__tests__/event-emission.test.ts +0 -127
- package/src/__tests__/examples.test.ts +0 -236
- package/src/__tests__/full-blueprint-coverage.test.ts +0 -1221
- package/src/__tests__/golden-suite.test.ts +0 -403
- package/src/__tests__/grammar-island-extractor.test.ts +0 -289
- package/src/__tests__/instance-key.test.ts +0 -82
- package/src/__tests__/ir-migration.test.ts +0 -255
- package/src/__tests__/lock-file.test.ts +0 -117
- package/src/__tests__/model-extractor.test.ts +0 -195
- package/src/__tests__/model-field-acl.test.ts +0 -237
- package/src/__tests__/model-hooks.test.ts +0 -130
- package/src/__tests__/model-ref-resolution.test.ts +0 -268
- package/src/__tests__/model-roundtrip.test.ts +0 -502
- package/src/__tests__/model-runtime.test.ts +0 -112
- package/src/__tests__/model-transitions.test.ts +0 -183
- package/src/__tests__/nrt-action-trace.test.ts +0 -391
- package/src/__tests__/pipeline-hardening.test.ts +0 -413
- package/src/__tests__/project-compiler.test.ts +0 -546
- package/src/__tests__/project-decompiler.test.ts +0 -343
- package/src/__tests__/query-compilation.test.ts +0 -145
- package/src/__tests__/round-trip/PLAN.md +0 -158
- package/src/__tests__/round-trip/README.md +0 -52
- package/src/__tests__/round-trip/RESULTS.md +0 -86
- package/src/__tests__/round-trip/fixtures/data-heavy/main.workflow.tsx +0 -55
- package/src/__tests__/round-trip/fixtures/data-heavy/mm.config.ts +0 -11
- package/src/__tests__/round-trip/fixtures/data-heavy/models/contact.ts +0 -54
- package/src/__tests__/round-trip/fixtures/full-workflow/main.workflow.tsx +0 -79
- package/src/__tests__/round-trip/fixtures/full-workflow/mm.config.ts +0 -12
- package/src/__tests__/round-trip/fixtures/full-workflow/models/order.ts +0 -50
- package/src/__tests__/round-trip/fixtures/simple-crud/main.workflow.tsx +0 -25
- package/src/__tests__/round-trip/fixtures/simple-crud/mm.config.ts +0 -11
- package/src/__tests__/round-trip/fixtures/simple-crud/models/task.ts +0 -32
- package/src/__tests__/round-trip/fixtures/view-heavy/main.workflow.tsx +0 -79
- package/src/__tests__/round-trip/fixtures/view-heavy/mm.config.ts +0 -10
- package/src/__tests__/round-trip/round-trip.test.ts +0 -2598
- package/src/__tests__/round-trip-ir.test.ts +0 -300
- package/src/__tests__/round-trip.test.ts +0 -1212
- package/src/__tests__/route-merging.test.ts +0 -372
- package/src/__tests__/router-composition.test.ts +0 -489
- package/src/__tests__/router-extractor.test.ts +0 -176
- package/src/__tests__/server-action-extractor.test.ts +0 -128
- package/src/__tests__/smart-type-inference.test.ts +0 -365
- package/src/__tests__/source-envelope.test.ts +0 -284
- package/src/__tests__/source-fidelity.test.ts +0 -516
- package/src/__tests__/state-extractor.test.ts +0 -115
- package/src/__tests__/strict-mode.test.ts +0 -227
- package/src/__tests__/transition-effect-extractor.test.ts +0 -119
- package/src/__tests__/transition-extractor.test.ts +0 -68
- package/src/__tests__/ts-to-expression.test.ts +0 -462
- package/src/__tests__/type-generator.test.ts +0 -201
- package/src/__tests__/uber-validation.test.ts +0 -502
- package/src/action-compiler.ts +0 -361
- package/src/babel/emitters/experience-transform.ts +0 -199
- package/src/babel/emitters/ir-to-tsx-emitter.ts +0 -110
- package/src/babel/emitters/pure-form-emitter.ts +0 -1023
- package/src/babel/emitters/runtime-glue-emitter.ts +0 -39
- package/src/babel/extractors/change-extractor.ts +0 -199
- package/src/babel/extractors/component-extractor.ts +0 -907
- package/src/babel/extractors/computed-extractor.ts +0 -262
- package/src/babel/extractors/context-extractor.ts +0 -277
- package/src/babel/extractors/during-extractor.ts +0 -295
- package/src/babel/extractors/effect-extractor.ts +0 -340
- package/src/babel/extractors/event-extractor.ts +0 -235
- package/src/babel/extractors/grammar-island-extractor.ts +0 -302
- package/src/babel/extractors/model-extractor.ts +0 -1018
- package/src/babel/extractors/router-extractor.ts +0 -303
- package/src/babel/extractors/server-action-extractor.ts +0 -173
- package/src/babel/extractors/server-action-hook-extractor.ts +0 -72
- package/src/babel/extractors/server-state-extractor.ts +0 -88
- package/src/babel/extractors/state-extractor.ts +0 -214
- package/src/babel/extractors/transition-effect-extractor.ts +0 -176
- package/src/babel/extractors/transition-extractor.ts +0 -143
- package/src/babel/index.ts +0 -24
- package/src/babel/transpilers/ts-to-expression.ts +0 -674
- package/src/babel/visitor.ts +0 -807
- package/src/cli/auth.ts +0 -255
- package/src/cli/build.ts +0 -288
- package/src/cli/deploy.ts +0 -206
- package/src/cli/index.ts +0 -328
- package/src/cli/installer.ts +0 -261
- package/src/cli/lock-file.ts +0 -94
- package/src/cli/mmrc.ts +0 -22
- package/src/cli/pull.ts +0 -172
- package/src/cli/registry-client.ts +0 -175
- package/src/cli/test.ts +0 -397
- package/src/cli/type-generator.ts +0 -243
- package/src/codemod/__tests__/forward.test.ts +0 -239
- package/src/codemod/__tests__/reverse.test.ts +0 -145
- package/src/codemod/__tests__/round-trip.test.ts +0 -137
- package/src/codemod/annotation.ts +0 -97
- package/src/codemod/classify.ts +0 -197
- package/src/codemod/cli.ts +0 -207
- package/src/codemod/control-flow.ts +0 -409
- package/src/codemod/forward.ts +0 -244
- package/src/codemod/import-manager.ts +0 -171
- package/src/codemod/index.ts +0 -120
- package/src/codemod/reverse.ts +0 -197
- package/src/codemod/rules.ts +0 -174
- package/src/codemod/state-transform.ts +0 -126
- package/src/decompiler/ast-builder.ts +0 -538
- package/src/decompiler/config-generator.ts +0 -151
- package/src/decompiler/index.ts +0 -315
- package/src/decompiler/project-decompiler.ts +0 -1776
- package/src/decompiler/project.ts +0 -862
- package/src/decompiler/split-strategy.ts +0 -140
- package/src/decompiler/state-emitter.ts +0 -1053
- package/src/decompiler/sx-emitter.ts +0 -318
- package/src/decompiler/workspace-hydrator.ts +0 -189
- package/src/dev-server.ts +0 -238
- package/src/envelope/fs-tree.ts +0 -217
- package/src/envelope/source-envelope.ts +0 -264
- package/src/envelope.ts +0 -315
- package/src/incremental-compiler.ts +0 -401
- package/src/index.ts +0 -99
- package/src/model-compiler.ts +0 -277
- package/src/project-compiler.ts +0 -1629
- package/src/route-extractor.ts +0 -333
- package/src/testing/index.ts +0 -32
- package/src/testing/snapshot.ts +0 -252
- package/src/testing/test-utils.ts +0 -226
- package/src/types.ts +0 -68
- package/src/vite/index.ts +0 -288
- package/test-compile.mjs +0 -142
- package/tsconfig.json +0 -25
- package/tsup.config.ts +0 -23
- package/vitest.config.ts +0 -9
package/dist/vite/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
mindmatrixReact
|
|
3
|
-
} from "../chunk-
|
|
4
|
-
import "../chunk-
|
|
5
|
-
import "../chunk-
|
|
3
|
+
} from "../chunk-EO6SYNCG.mjs";
|
|
4
|
+
import "../chunk-OPJKP747.mjs";
|
|
5
|
+
import "../chunk-CIESM3BP.mjs";
|
|
6
6
|
export {
|
|
7
7
|
mindmatrixReact
|
|
8
8
|
};
|
|
@@ -40,19 +40,19 @@ export default function FleetManagement() {
|
|
|
40
40
|
|
|
41
41
|
return (
|
|
42
42
|
<Show when={isAdmin} fallback={<Text>Access denied. Admin role required.</Text>}>
|
|
43
|
-
<Stack gap=lg>
|
|
44
|
-
<Row justify=between align=center>
|
|
43
|
+
<Stack gap="lg">
|
|
44
|
+
<Row justify="between" align="center">
|
|
45
45
|
<Heading level={2}>Fleet Management</Heading>
|
|
46
46
|
<Button onClick={() => setShowAddForm(true)}>Add Vehicle</Button>
|
|
47
47
|
</Row>
|
|
48
48
|
|
|
49
|
-
<Row gap=md>
|
|
50
|
-
<Badge color=green>Active: {statusCounts.active}</Badge>
|
|
51
|
-
<Badge color=yellow>Maintenance: {statusCounts.maintenance}</Badge>
|
|
52
|
-
<Badge color=gray>Retired: {statusCounts.retired}</Badge>
|
|
49
|
+
<Row gap="md">
|
|
50
|
+
<Badge color="green">Active: {statusCounts.active}</Badge>
|
|
51
|
+
<Badge color="yellow">Maintenance: {statusCounts.maintenance}</Badge>
|
|
52
|
+
<Badge color="gray">Retired: {statusCounts.retired}</Badge>
|
|
53
53
|
</Row>
|
|
54
54
|
|
|
55
|
-
<Row gap=sm>
|
|
55
|
+
<Row gap="sm">
|
|
56
56
|
{(['all', 'sedan', 'suv', 'van', 'luxury'] as const).map((t) => (
|
|
57
57
|
<Button key={t} variant={filterType === t ? 'primary' : 'ghost'} onClick={() => setFilterType(t)}>
|
|
58
58
|
{t.charAt(0).toUpperCase() + t.slice(1)}
|
|
@@ -62,16 +62,16 @@ export default function FleetManagement() {
|
|
|
62
62
|
|
|
63
63
|
<Show when={showAddForm}>
|
|
64
64
|
<Card>
|
|
65
|
-
<Stack gap=sm>
|
|
66
|
-
<Input label=License Plate value={newPlate} onChange={setNewPlate} />
|
|
67
|
-
<Row gap=sm>
|
|
65
|
+
<Stack gap="sm">
|
|
66
|
+
<Input label="License Plate" value={newPlate} onChange={setNewPlate} />
|
|
67
|
+
<Row gap="sm">
|
|
68
68
|
{(['sedan', 'suv', 'van', 'luxury'] as const).map((t) => (
|
|
69
69
|
<Button key={t} variant={newType === t ? 'primary' : 'ghost'} onClick={() => setNewType(t)}>{t}</Button>
|
|
70
70
|
))}
|
|
71
71
|
</Row>
|
|
72
|
-
<Row gap=sm>
|
|
72
|
+
<Row gap="sm">
|
|
73
73
|
<Button onClick={handleAddVehicle}>Save</Button>
|
|
74
|
-
<Button variant=ghost onClick={() => setShowAddForm(false)}>Cancel</Button>
|
|
74
|
+
<Button variant="ghost" onClick={() => setShowAddForm(false)}>Cancel</Button>
|
|
75
75
|
</Row>
|
|
76
76
|
</Stack>
|
|
77
77
|
</Card>
|
|
@@ -80,15 +80,15 @@ export default function FleetManagement() {
|
|
|
80
80
|
<Each items={filteredVehicles}>
|
|
81
81
|
{(vehicle: Vehicle) => (
|
|
82
82
|
<Card key={vehicle.id}>
|
|
83
|
-
<Row justify=between align=center>
|
|
84
|
-
<Stack gap=xs>
|
|
85
|
-
<Text weight=bold>{vehicle.plate} — {vehicle.type}</Text>
|
|
86
|
-
<Text size=sm color=muted>{vehicle.assignedDriver?.name ?? 'Unassigned'}</Text>
|
|
83
|
+
<Row justify="between" align="center">
|
|
84
|
+
<Stack gap="xs">
|
|
85
|
+
<Text weight="bold">{vehicle.plate} — {vehicle.type}</Text>
|
|
86
|
+
<Text size="sm" color="muted">{vehicle.assignedDriver?.name ?? 'Unassigned'}</Text>
|
|
87
87
|
</Stack>
|
|
88
|
-
<Row gap=sm align=center>
|
|
88
|
+
<Row gap="sm" align="center">
|
|
89
89
|
<Badge color={statusColor(vehicle.status)}>{vehicle.status}</Badge>
|
|
90
|
-
<Button size=sm onClick={() => assignDriver({ vehicleId: vehicle.id })}>Assign</Button>
|
|
91
|
-
<Button size=sm variant=ghost onClick={() => updateStatus({ vehicleId: vehicle.id, status: 'maintenance' })}>
|
|
90
|
+
<Button size="sm" onClick={() => assignDriver({ vehicleId: vehicle.id })}>Assign</Button>
|
|
91
|
+
<Button size="sm" variant="ghost" onClick={() => updateStatus({ vehicleId: vehicle.id, status: 'maintenance' })}>
|
|
92
92
|
Service
|
|
93
93
|
</Button>
|
|
94
94
|
</Row>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mmapp/react-compiler",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.5",
|
|
4
4
|
"description": "Babel plugin + Vite integration for compiling React workflows to Pure Form IR",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -55,7 +55,8 @@
|
|
|
55
55
|
"seed:chat:compile": "node seed-blueprint-chat.mjs --compile-only",
|
|
56
56
|
"seed:chat:seed": "node seed-blueprint-chat.mjs --seed-only",
|
|
57
57
|
"test": "vitest run",
|
|
58
|
-
"test:watch": "vitest"
|
|
58
|
+
"test:watch": "vitest",
|
|
59
|
+
"publish:alpha": "cd ../.. && ./scripts/publish-npm.sh"
|
|
59
60
|
},
|
|
60
61
|
"dependencies": {
|
|
61
62
|
"@babel/core": "^7.24.0",
|
|
@@ -65,13 +66,22 @@
|
|
|
65
66
|
"@babel/plugin-syntax-typescript": "^7.24.0",
|
|
66
67
|
"@babel/traverse": "^7.24.0",
|
|
67
68
|
"@babel/types": "^7.24.0",
|
|
68
|
-
"
|
|
69
|
-
"
|
|
69
|
+
"@mindmatrix/player-core": "workspace:*",
|
|
70
|
+
"glob": "^10.3.10"
|
|
70
71
|
},
|
|
71
72
|
"peerDependencies": {
|
|
72
73
|
"vite": ">=5.0.0"
|
|
73
74
|
},
|
|
74
|
-
"
|
|
75
|
-
"
|
|
75
|
+
"devDependencies": {
|
|
76
|
+
"@types/babel__core": "^7.20.5",
|
|
77
|
+
"@types/babel__generator": "^7.27.0",
|
|
78
|
+
"@types/babel__traverse": "^7.20.5",
|
|
79
|
+
"@types/node": "^20.0.0",
|
|
80
|
+
"@types/pg": "^8.18.0",
|
|
81
|
+
"pg": "^8.20.0",
|
|
82
|
+
"prettier": "^3.8.1",
|
|
83
|
+
"tsup": "^8.0.0",
|
|
84
|
+
"typescript": "^5.0.0",
|
|
85
|
+
"vitest": "^2.0.0"
|
|
76
86
|
}
|
|
77
87
|
}
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Compiles blueprint-chat app/ views through the same Babel plugin
|
|
3
|
-
* that handles .workflow.tsx files.
|
|
4
|
-
*
|
|
5
|
-
* Each app/ file has @workflow JSDoc + default export function →
|
|
6
|
-
* compiled to { canonical, ir } with view tree.
|
|
7
|
-
*
|
|
8
|
-
* Run from repo root: node packages/react-compiler/compile-blueprint-chat.mjs
|
|
9
|
-
*/
|
|
10
|
-
import { transformSync } from '@babel/core';
|
|
11
|
-
import { readFileSync, readdirSync, writeFileSync, mkdirSync, statSync } from 'fs';
|
|
12
|
-
import { join, dirname, relative } from 'path';
|
|
13
|
-
import { fileURLToPath } from 'url';
|
|
14
|
-
|
|
15
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
16
|
-
const __dirname = dirname(__filename);
|
|
17
|
-
|
|
18
|
-
const plugin = await import('./dist/babel/index.mjs');
|
|
19
|
-
const babelPlugin = plugin.default;
|
|
20
|
-
|
|
21
|
-
const blueprintDir = join(__dirname, '../blueprint-chat/app');
|
|
22
|
-
const outDir = join(__dirname, '../frontend/src/workflows/compiled/blueprint-chat');
|
|
23
|
-
|
|
24
|
-
mkdirSync(outDir, { recursive: true });
|
|
25
|
-
|
|
26
|
-
// Recursively find all .tsx files in app/
|
|
27
|
-
function findTsxFiles(dir, base = '') {
|
|
28
|
-
const entries = readdirSync(dir, { withFileTypes: true });
|
|
29
|
-
const files = [];
|
|
30
|
-
for (const entry of entries) {
|
|
31
|
-
const relPath = base ? `${base}/${entry.name}` : entry.name;
|
|
32
|
-
if (entry.isDirectory()) {
|
|
33
|
-
files.push(...findTsxFiles(join(dir, entry.name), relPath));
|
|
34
|
-
} else if (entry.name.endsWith('.tsx')) {
|
|
35
|
-
files.push({ fullPath: join(dir, entry.name), relPath });
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
return files;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const files = findTsxFiles(blueprintDir);
|
|
42
|
-
console.log(`Found ${files.length} .tsx files in blueprint-chat/app/\n`);
|
|
43
|
-
|
|
44
|
-
let compiled = 0;
|
|
45
|
-
let failed = 0;
|
|
46
|
-
const results = [];
|
|
47
|
-
|
|
48
|
-
for (const { fullPath, relPath } of files) {
|
|
49
|
-
const code = readFileSync(fullPath, 'utf-8');
|
|
50
|
-
|
|
51
|
-
try {
|
|
52
|
-
const result = transformSync(code, {
|
|
53
|
-
filename: fullPath,
|
|
54
|
-
plugins: [[babelPlugin, { mode: 'infer' }]],
|
|
55
|
-
parserOpts: { plugins: ['jsx', 'typescript'] },
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
const def = result?.metadata?.mindmatrixDefinition;
|
|
59
|
-
const canonical = result?.metadata?.mindmatrixCanonical;
|
|
60
|
-
const ir = result?.metadata?.mindmatrixIR;
|
|
61
|
-
|
|
62
|
-
if (def) {
|
|
63
|
-
const combinedOutput = {
|
|
64
|
-
canonical: canonical || null,
|
|
65
|
-
ir: def,
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
// Use the slug from the workflow annotation
|
|
69
|
-
const outFile = join(outDir, `${def.slug}.json`);
|
|
70
|
-
writeFileSync(outFile, JSON.stringify(combinedOutput, null, 2), 'utf-8');
|
|
71
|
-
console.log(` ✓ ${relPath} → ${def.slug}.json`);
|
|
72
|
-
|
|
73
|
-
// Check if view tree was extracted
|
|
74
|
-
const viewTree = def.views?.default || def.metadata?.experience;
|
|
75
|
-
if (viewTree) {
|
|
76
|
-
console.log(` view tree: ${viewTree.children?.length || 0} top-level children`);
|
|
77
|
-
} else {
|
|
78
|
-
console.log(` ⚠ no view tree extracted`);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
results.push({ slug: def.slug, relPath, hasView: !!viewTree });
|
|
82
|
-
compiled++;
|
|
83
|
-
} else {
|
|
84
|
-
console.log(` ⚠ ${relPath}: no @workflow annotation or no definition generated`);
|
|
85
|
-
failed++;
|
|
86
|
-
}
|
|
87
|
-
} catch (err) {
|
|
88
|
-
console.error(` ✗ ${relPath}: ${err.message}`);
|
|
89
|
-
failed++;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
console.log(`\nCompiled: ${compiled}, Failed/Skipped: ${failed}`);
|
|
94
|
-
|
|
95
|
-
// Summary of view trees
|
|
96
|
-
console.log('\n--- View tree summary ---');
|
|
97
|
-
for (const r of results) {
|
|
98
|
-
console.log(` ${r.slug}: view=${r.hasView ? '✓' : '✗'} (${r.relPath})`);
|
|
99
|
-
}
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Compiles blueprint-glass-console app/ views through the same Babel plugin
|
|
3
|
-
* that handles .workflow.tsx files.
|
|
4
|
-
*
|
|
5
|
-
* Each app/ file has @workflow JSDoc + default export function →
|
|
6
|
-
* compiled to { canonical, ir } with view tree.
|
|
7
|
-
*
|
|
8
|
-
* Run from repo root: node packages/react-compiler/compile-blueprint-glass-console.mjs
|
|
9
|
-
*/
|
|
10
|
-
import { transformSync } from '@babel/core';
|
|
11
|
-
import { readFileSync, readdirSync, writeFileSync, mkdirSync } from 'fs';
|
|
12
|
-
import { join, dirname } from 'path';
|
|
13
|
-
import { fileURLToPath } from 'url';
|
|
14
|
-
|
|
15
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
16
|
-
const __dirname = dirname(__filename);
|
|
17
|
-
|
|
18
|
-
const plugin = await import('./dist/babel/index.mjs');
|
|
19
|
-
const babelPlugin = plugin.default;
|
|
20
|
-
|
|
21
|
-
const blueprintDir = join(__dirname, '../blueprint-glass-console/app');
|
|
22
|
-
const outDir = join(__dirname, '../frontend/src/workflows/compiled/blueprint-glass-console');
|
|
23
|
-
|
|
24
|
-
mkdirSync(outDir, { recursive: true });
|
|
25
|
-
|
|
26
|
-
// Recursively find all .tsx files in app/
|
|
27
|
-
function findTsxFiles(dir, base = '') {
|
|
28
|
-
const entries = readdirSync(dir, { withFileTypes: true });
|
|
29
|
-
const files = [];
|
|
30
|
-
for (const entry of entries) {
|
|
31
|
-
const relPath = base ? `${base}/${entry.name}` : entry.name;
|
|
32
|
-
if (entry.isDirectory()) {
|
|
33
|
-
files.push(...findTsxFiles(join(dir, entry.name), relPath));
|
|
34
|
-
} else if (entry.name.endsWith('.tsx')) {
|
|
35
|
-
files.push({ fullPath: join(dir, entry.name), relPath });
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
return files;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const files = findTsxFiles(blueprintDir);
|
|
42
|
-
console.log(`Found ${files.length} .tsx files in blueprint-glass-console/app/\n`);
|
|
43
|
-
|
|
44
|
-
let compiled = 0;
|
|
45
|
-
let failed = 0;
|
|
46
|
-
const results = [];
|
|
47
|
-
|
|
48
|
-
for (const { fullPath, relPath } of files) {
|
|
49
|
-
const code = readFileSync(fullPath, 'utf-8');
|
|
50
|
-
|
|
51
|
-
try {
|
|
52
|
-
const result = transformSync(code, {
|
|
53
|
-
filename: fullPath,
|
|
54
|
-
plugins: [[babelPlugin, { mode: 'infer' }]],
|
|
55
|
-
parserOpts: { plugins: ['jsx', 'typescript'] },
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
const def = result?.metadata?.mindmatrixDefinition;
|
|
59
|
-
const canonical = result?.metadata?.mindmatrixCanonical;
|
|
60
|
-
|
|
61
|
-
if (def) {
|
|
62
|
-
const combinedOutput = {
|
|
63
|
-
canonical: canonical || null,
|
|
64
|
-
ir: def,
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
// Use the slug from the workflow annotation
|
|
68
|
-
const outFile = join(outDir, `${def.slug}.json`);
|
|
69
|
-
writeFileSync(outFile, JSON.stringify(combinedOutput, null, 2), 'utf-8');
|
|
70
|
-
console.log(` ✓ ${relPath} → ${def.slug}.json`);
|
|
71
|
-
|
|
72
|
-
// Check if view tree was extracted
|
|
73
|
-
const viewTree = def.views?.default || def.metadata?.experience;
|
|
74
|
-
if (viewTree) {
|
|
75
|
-
console.log(` view tree: ${viewTree.children?.length || 0} top-level children`);
|
|
76
|
-
} else {
|
|
77
|
-
console.log(` ⚠ no view tree extracted`);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
results.push({ slug: def.slug, relPath, hasView: !!viewTree });
|
|
81
|
-
compiled++;
|
|
82
|
-
} else {
|
|
83
|
-
console.log(` ⚠ ${relPath}: no @workflow annotation or no definition generated`);
|
|
84
|
-
failed++;
|
|
85
|
-
}
|
|
86
|
-
} catch (err) {
|
|
87
|
-
console.error(` ✗ ${relPath}: ${err.message}`);
|
|
88
|
-
failed++;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
console.log(`\nCompiled: ${compiled}, Failed/Skipped: ${failed}`);
|
|
93
|
-
|
|
94
|
-
// Summary of view trees
|
|
95
|
-
console.log('\n--- View tree summary ---');
|
|
96
|
-
for (const r of results) {
|
|
97
|
-
console.log(` ${r.slug}: view=${r.hasView ? '✓' : '✗'} (${r.relPath})`);
|
|
98
|
-
}
|
package/compile-chat-defs.mjs
DELETED
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Compiles all .workflow.tsx files into engine-compatible JSON definitions.
|
|
3
|
-
* Outputs to packages/frontend/src/workflows/compiled/
|
|
4
|
-
*
|
|
5
|
-
* Each compiled output contains both:
|
|
6
|
-
* - canonical: Pure form tree per 041 protocol (THE TRUTH)
|
|
7
|
-
* - ir: Lowered IR with normalized view tree (derivable cache)
|
|
8
|
-
*
|
|
9
|
-
* Run from repo root: node packages/react-compiler/compile-chat-defs.mjs
|
|
10
|
-
*/
|
|
11
|
-
import { transformSync } from '@babel/core';
|
|
12
|
-
import { readFileSync, readdirSync, writeFileSync, mkdirSync } from 'fs';
|
|
13
|
-
import { join, dirname } from 'path';
|
|
14
|
-
import { fileURLToPath } from 'url';
|
|
15
|
-
|
|
16
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
17
|
-
const __dirname = dirname(__filename);
|
|
18
|
-
|
|
19
|
-
const plugin = await import('./dist/babel/index.mjs');
|
|
20
|
-
const babelPlugin = plugin.default;
|
|
21
|
-
|
|
22
|
-
const workflowDir = join(__dirname, '../frontend/src/workflows');
|
|
23
|
-
const outDir = join(__dirname, '../frontend/src/workflows/compiled');
|
|
24
|
-
|
|
25
|
-
const files = readdirSync(workflowDir).filter(f => f.endsWith('.workflow.tsx'));
|
|
26
|
-
|
|
27
|
-
mkdirSync(outDir, { recursive: true });
|
|
28
|
-
|
|
29
|
-
let compiled = 0;
|
|
30
|
-
const slugs = [];
|
|
31
|
-
|
|
32
|
-
for (const file of files) {
|
|
33
|
-
const filePath = join(workflowDir, file);
|
|
34
|
-
const code = readFileSync(filePath, 'utf-8');
|
|
35
|
-
|
|
36
|
-
try {
|
|
37
|
-
const result = transformSync(code, {
|
|
38
|
-
filename: filePath,
|
|
39
|
-
plugins: [[babelPlugin, { mode: 'infer' }]],
|
|
40
|
-
parserOpts: { plugins: ['jsx', 'typescript'] },
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
const def = result?.metadata?.mindmatrixDefinition;
|
|
44
|
-
const canonical = result?.metadata?.mindmatrixCanonical;
|
|
45
|
-
|
|
46
|
-
if (def) {
|
|
47
|
-
// Output combined format: { canonical, ir }
|
|
48
|
-
const combinedOutput = {
|
|
49
|
-
canonical: canonical || null,
|
|
50
|
-
ir: def,
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
const outFile = join(outDir, `${def.slug}.json`);
|
|
54
|
-
writeFileSync(outFile, JSON.stringify(combinedOutput, null, 2), 'utf-8');
|
|
55
|
-
console.log(` ✓ ${file} → ${def.slug}.json (canonical + ir)`);
|
|
56
|
-
slugs.push(def.slug);
|
|
57
|
-
compiled++;
|
|
58
|
-
} else {
|
|
59
|
-
console.error(` ✗ ${file}: no definition generated`);
|
|
60
|
-
}
|
|
61
|
-
} catch (err) {
|
|
62
|
-
console.error(` ✗ ${file}: ${err.message}`);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Generate index.ts that re-exports all definitions
|
|
67
|
-
const indexContent = [
|
|
68
|
-
'// Auto-generated by compile-chat-defs.mjs — do not edit manually',
|
|
69
|
-
`// Compiled from ${files.length} .workflow.tsx files`,
|
|
70
|
-
'',
|
|
71
|
-
...slugs.map(slug => {
|
|
72
|
-
const varName = slug.replace(/-/g, '_').replace(/^mm_/, 'mm');
|
|
73
|
-
return `import ${varName}Def from './${slug}.json';`;
|
|
74
|
-
}),
|
|
75
|
-
'',
|
|
76
|
-
'export const compiledDefinitions: Record<string, unknown> = {',
|
|
77
|
-
...slugs.map(slug => {
|
|
78
|
-
const varName = slug.replace(/-/g, '_').replace(/^mm_/, 'mm');
|
|
79
|
-
return ` '${slug}': ${varName}Def,`;
|
|
80
|
-
}),
|
|
81
|
-
'};',
|
|
82
|
-
'',
|
|
83
|
-
...slugs.map(slug => {
|
|
84
|
-
const varName = slug.replace(/-/g, '_').replace(/^mm_/, 'mm');
|
|
85
|
-
return `export { default as ${varName}Def } from './${slug}.json';`;
|
|
86
|
-
}),
|
|
87
|
-
'',
|
|
88
|
-
].join('\n');
|
|
89
|
-
|
|
90
|
-
writeFileSync(join(outDir, 'index.ts'), indexContent);
|
|
91
|
-
console.log(`\n ✓ index.ts generated (${slugs.length} definitions)`);
|
|
92
|
-
console.log(`\nCompiled ${compiled} workflow definitions`);
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
-
import { renderWorkflow, act, waitFor } from '@mindmatrix/react/testing';
|
|
3
|
-
import { PaymentProcessingWorkflow } from '../components/PaymentProcessingWorkflow';
|
|
4
|
-
|
|
5
|
-
describe('Payment Processing', () => {
|
|
6
|
-
let workflow: ReturnType<typeof renderWorkflow>;
|
|
7
|
-
|
|
8
|
-
beforeEach(() => {
|
|
9
|
-
workflow = renderWorkflow(PaymentProcessingWorkflow, {
|
|
10
|
-
initialFields: {
|
|
11
|
-
rideId: 'ride-100',
|
|
12
|
-
riderId: 'rider-001',
|
|
13
|
-
driverId: 'driver-042',
|
|
14
|
-
amount: 25.00,
|
|
15
|
-
paymentMethod: 'card_visa_4242',
|
|
16
|
-
currency: 'USD',
|
|
17
|
-
},
|
|
18
|
-
});
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it('starts in pending state', () => {
|
|
22
|
-
expect(workflow.currentState()).toBe('pending');
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('authorizes payment and captures on ride completion', async () => {
|
|
26
|
-
// Authorize hold
|
|
27
|
-
await act(() => workflow.transition('authorize', { holdId: 'hold-abc' }));
|
|
28
|
-
await waitFor(() => expect(workflow.currentState()).toBe('authorized'));
|
|
29
|
-
expect(workflow.field('holdId')).toBe('hold-abc');
|
|
30
|
-
|
|
31
|
-
// Capture on completion (final amount may differ from hold)
|
|
32
|
-
await act(() => workflow.transition('capture', {
|
|
33
|
-
finalAmount: 27.50,
|
|
34
|
-
tip: 5.00,
|
|
35
|
-
surgeMultiplier: 1.0,
|
|
36
|
-
}));
|
|
37
|
-
await waitFor(() => expect(workflow.currentState()).toBe('captured'));
|
|
38
|
-
expect(workflow.field('finalAmount')).toBe(27.50);
|
|
39
|
-
expect(workflow.field('tip')).toBe(5.00);
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it('processes full refund on cancellation before ride start', async () => {
|
|
43
|
-
await act(() => workflow.transition('authorize', { holdId: 'hold-abc' }));
|
|
44
|
-
await waitFor(() => expect(workflow.currentState()).toBe('authorized'));
|
|
45
|
-
|
|
46
|
-
await act(() => workflow.transition('refund', {
|
|
47
|
-
refundAmount: 25.00,
|
|
48
|
-
refundType: 'full',
|
|
49
|
-
reason: 'ride_cancelled_before_pickup',
|
|
50
|
-
}));
|
|
51
|
-
await waitFor(() => expect(workflow.currentState()).toBe('refunded'));
|
|
52
|
-
expect(workflow.field('refundAmount')).toBe(25.00);
|
|
53
|
-
expect(workflow.field('refundType')).toBe('full');
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it('processes partial refund for poor service', async () => {
|
|
57
|
-
await act(() => workflow.transition('authorize', { holdId: 'hold-abc' }));
|
|
58
|
-
await act(() => workflow.transition('capture', { finalAmount: 25.00, tip: 0, surgeMultiplier: 1.0 }));
|
|
59
|
-
await waitFor(() => expect(workflow.currentState()).toBe('captured'));
|
|
60
|
-
|
|
61
|
-
await act(() => workflow.transition('refund', {
|
|
62
|
-
refundAmount: 10.00,
|
|
63
|
-
refundType: 'partial',
|
|
64
|
-
reason: 'driver_took_wrong_route',
|
|
65
|
-
}));
|
|
66
|
-
await waitFor(() => expect(workflow.currentState()).toBe('partially_refunded'));
|
|
67
|
-
expect(workflow.field('refundAmount')).toBe(10.00);
|
|
68
|
-
expect(workflow.field('refundType')).toBe('partial');
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
it('voids authorization when ride is cancelled before capture', async () => {
|
|
72
|
-
await act(() => workflow.transition('authorize', { holdId: 'hold-abc' }));
|
|
73
|
-
await waitFor(() => expect(workflow.currentState()).toBe('authorized'));
|
|
74
|
-
|
|
75
|
-
await act(() => workflow.transition('void_authorization', { reason: 'no_driver_found' }));
|
|
76
|
-
await waitFor(() => expect(workflow.currentState()).toBe('voided'));
|
|
77
|
-
expect(workflow.field('holdId')).toBeDefined();
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
it('handles dispute flow: captured → disputed → resolved', async () => {
|
|
81
|
-
await act(() => workflow.transition('authorize', { holdId: 'hold-abc' }));
|
|
82
|
-
await act(() => workflow.transition('capture', { finalAmount: 25.00, tip: 0, surgeMultiplier: 1.5 }));
|
|
83
|
-
await waitFor(() => expect(workflow.currentState()).toBe('captured'));
|
|
84
|
-
|
|
85
|
-
// Rider opens dispute
|
|
86
|
-
await act(() => workflow.transition('open_dispute', {
|
|
87
|
-
disputeReason: 'incorrect_fare',
|
|
88
|
-
description: 'Surge pricing was applied incorrectly',
|
|
89
|
-
}));
|
|
90
|
-
await waitFor(() => expect(workflow.currentState()).toBe('disputed'));
|
|
91
|
-
expect(workflow.field('disputeReason')).toBe('incorrect_fare');
|
|
92
|
-
|
|
93
|
-
// Admin resolves dispute with partial refund
|
|
94
|
-
await act(() => workflow.transition('resolve_dispute', {
|
|
95
|
-
resolution: 'partial_refund',
|
|
96
|
-
adjustedAmount: 18.00,
|
|
97
|
-
refundAmount: 7.00,
|
|
98
|
-
adminNote: 'Surge was incorrectly applied to this zone',
|
|
99
|
-
}));
|
|
100
|
-
await waitFor(() => expect(workflow.currentState()).toBe('dispute_resolved'));
|
|
101
|
-
expect(workflow.field('adjustedAmount')).toBe(18.00);
|
|
102
|
-
expect(workflow.field('refundAmount')).toBe(7.00);
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
it('handles dispute resolved with no action', async () => {
|
|
106
|
-
await act(() => workflow.transition('authorize', { holdId: 'hold-abc' }));
|
|
107
|
-
await act(() => workflow.transition('capture', { finalAmount: 25.00, tip: 0, surgeMultiplier: 1.0 }));
|
|
108
|
-
await act(() => workflow.transition('open_dispute', {
|
|
109
|
-
disputeReason: 'overcharged',
|
|
110
|
-
description: 'I think the fare was too high',
|
|
111
|
-
}));
|
|
112
|
-
await waitFor(() => expect(workflow.currentState()).toBe('disputed'));
|
|
113
|
-
|
|
114
|
-
await act(() => workflow.transition('resolve_dispute', {
|
|
115
|
-
resolution: 'no_action',
|
|
116
|
-
adjustedAmount: 25.00,
|
|
117
|
-
refundAmount: 0,
|
|
118
|
-
adminNote: 'Fare calculation verified as correct',
|
|
119
|
-
}));
|
|
120
|
-
await waitFor(() => expect(workflow.currentState()).toBe('dispute_resolved'));
|
|
121
|
-
expect(workflow.field('refundAmount')).toBe(0);
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
it('rejects capture without prior authorization', async () => {
|
|
125
|
-
await expect(
|
|
126
|
-
act(() => workflow.transition('capture', { finalAmount: 25.00, tip: 0, surgeMultiplier: 1.0 }))
|
|
127
|
-
).rejects.toThrow(/invalid transition/i);
|
|
128
|
-
});
|
|
129
|
-
});
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
-
import { renderWorkflow, act, waitFor } from '@mindmatrix/react/testing';
|
|
3
|
-
import { RideRequestWorkflow } from '../components/RideRequestWorkflow';
|
|
4
|
-
|
|
5
|
-
describe('Ride Flow — Full Lifecycle', () => {
|
|
6
|
-
let workflow: ReturnType<typeof renderWorkflow>;
|
|
7
|
-
|
|
8
|
-
beforeEach(() => {
|
|
9
|
-
workflow = renderWorkflow(RideRequestWorkflow, {
|
|
10
|
-
initialFields: {
|
|
11
|
-
pickup: { lat: 40.7128, lng: -74.006, address: '350 5th Ave, New York' },
|
|
12
|
-
dropoff: { lat: 40.758, lng: -73.9855, address: 'Times Square, New York' },
|
|
13
|
-
rideType: 'standard',
|
|
14
|
-
riderId: 'rider-001',
|
|
15
|
-
},
|
|
16
|
-
});
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
it('starts in the requesting state', () => {
|
|
20
|
-
expect(workflow.currentState()).toBe('requesting');
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('completes full ride lifecycle: request → match → en_route → arrived → in_progress → completed → rated', async () => {
|
|
24
|
-
// Request ride
|
|
25
|
-
await act(() => workflow.transition('request_ride'));
|
|
26
|
-
await waitFor(() => expect(workflow.currentState()).toBe('matching'));
|
|
27
|
-
|
|
28
|
-
// Match driver
|
|
29
|
-
await act(() => workflow.transition('match_driver', {
|
|
30
|
-
driverId: 'driver-042',
|
|
31
|
-
vehiclePlate: 'ABC-1234',
|
|
32
|
-
estimatedArrival: 5,
|
|
33
|
-
}));
|
|
34
|
-
await waitFor(() => expect(workflow.currentState()).toBe('driver_en_route'));
|
|
35
|
-
expect(workflow.field('driverId')).toBe('driver-042');
|
|
36
|
-
|
|
37
|
-
// Driver arrives at pickup
|
|
38
|
-
await act(() => workflow.transition('driver_arrived'));
|
|
39
|
-
await waitFor(() => expect(workflow.currentState()).toBe('driver_arrived'));
|
|
40
|
-
|
|
41
|
-
// Start ride
|
|
42
|
-
await act(() => workflow.transition('start_ride'));
|
|
43
|
-
await waitFor(() => expect(workflow.currentState()).toBe('in_progress'));
|
|
44
|
-
expect(workflow.field('rideStartedAt')).toBeDefined();
|
|
45
|
-
|
|
46
|
-
// Complete ride
|
|
47
|
-
await act(() => workflow.transition('complete_ride', {
|
|
48
|
-
distanceMiles: 3.2,
|
|
49
|
-
durationMinutes: 14,
|
|
50
|
-
fare: 18.50,
|
|
51
|
-
}));
|
|
52
|
-
await waitFor(() => expect(workflow.currentState()).toBe('completed'));
|
|
53
|
-
expect(workflow.field('fare')).toBe(18.50);
|
|
54
|
-
|
|
55
|
-
// Rate the ride
|
|
56
|
-
await act(() => workflow.transition('submit_rating', {
|
|
57
|
-
rating: 5,
|
|
58
|
-
comment: 'Great ride!',
|
|
59
|
-
}));
|
|
60
|
-
await waitFor(() => expect(workflow.currentState()).toBe('rated'));
|
|
61
|
-
expect(workflow.field('rating')).toBe(5);
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
it('handles rider cancellation before driver match', async () => {
|
|
65
|
-
await act(() => workflow.transition('request_ride'));
|
|
66
|
-
await waitFor(() => expect(workflow.currentState()).toBe('matching'));
|
|
67
|
-
|
|
68
|
-
await act(() => workflow.transition('cancel_ride', { reason: 'changed_mind' }));
|
|
69
|
-
await waitFor(() => expect(workflow.currentState()).toBe('cancelled'));
|
|
70
|
-
expect(workflow.field('cancellationReason')).toBe('changed_mind');
|
|
71
|
-
expect(workflow.field('cancellationFee')).toBe(0);
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
it('handles rider cancellation after driver match with fee', async () => {
|
|
75
|
-
await act(() => workflow.transition('request_ride'));
|
|
76
|
-
await waitFor(() => expect(workflow.currentState()).toBe('matching'));
|
|
77
|
-
|
|
78
|
-
await act(() => workflow.transition('match_driver', {
|
|
79
|
-
driverId: 'driver-042',
|
|
80
|
-
vehiclePlate: 'ABC-1234',
|
|
81
|
-
estimatedArrival: 5,
|
|
82
|
-
}));
|
|
83
|
-
await waitFor(() => expect(workflow.currentState()).toBe('driver_en_route'));
|
|
84
|
-
|
|
85
|
-
await act(() => workflow.transition('cancel_ride', { reason: 'too_long' }));
|
|
86
|
-
await waitFor(() => expect(workflow.currentState()).toBe('cancelled'));
|
|
87
|
-
expect(workflow.field('cancellationFee')).toBeGreaterThan(0);
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
it('handles driver cancellation and re-matching', async () => {
|
|
91
|
-
await act(() => workflow.transition('request_ride'));
|
|
92
|
-
await waitFor(() => expect(workflow.currentState()).toBe('matching'));
|
|
93
|
-
|
|
94
|
-
await act(() => workflow.transition('match_driver', {
|
|
95
|
-
driverId: 'driver-042',
|
|
96
|
-
vehiclePlate: 'ABC-1234',
|
|
97
|
-
estimatedArrival: 5,
|
|
98
|
-
}));
|
|
99
|
-
await waitFor(() => expect(workflow.currentState()).toBe('driver_en_route'));
|
|
100
|
-
|
|
101
|
-
// Driver cancels — goes back to matching
|
|
102
|
-
await act(() => workflow.transition('driver_cancel', { reason: 'emergency' }));
|
|
103
|
-
await waitFor(() => expect(workflow.currentState()).toBe('matching'));
|
|
104
|
-
expect(workflow.field('driverId')).toBeNull();
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
it('rejects invalid transitions', async () => {
|
|
108
|
-
// Cannot start ride from requesting state
|
|
109
|
-
await expect(
|
|
110
|
-
act(() => workflow.transition('start_ride'))
|
|
111
|
-
).rejects.toThrow(/invalid transition/i);
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
it('tracks ride duration when in progress', async () => {
|
|
115
|
-
await act(() => workflow.transition('request_ride'));
|
|
116
|
-
await act(() => workflow.transition('match_driver', { driverId: 'd1', vehiclePlate: 'X', estimatedArrival: 3 }));
|
|
117
|
-
await act(() => workflow.transition('driver_arrived'));
|
|
118
|
-
await act(() => workflow.transition('start_ride'));
|
|
119
|
-
|
|
120
|
-
await waitFor(() => expect(workflow.currentState()).toBe('in_progress'));
|
|
121
|
-
expect(workflow.field('rideStartedAt')).toBeDefined();
|
|
122
|
-
});
|
|
123
|
-
});
|