@reventlessdev/reventless-gwt 1.0.0-alpha.74
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/CHANGELOG.md +698 -0
- package/LICENSE +202 -0
- package/bin/reventless-dev.mjs +21 -0
- package/package.json +54 -0
- package/rescript.json +36 -0
- package/src/.gwtignore +10 -0
- package/src/Automation_GWT.res +207 -0
- package/src/Automation_GWT.res.mjs +160 -0
- package/src/Behavior_GWT.res +603 -0
- package/src/Behavior_GWT.res.mjs +426 -0
- package/src/Bind.res +29 -0
- package/src/Bind.res.mjs +22 -0
- package/src/BuildClassifier.res +137 -0
- package/src/BuildClassifier.res.mjs +136 -0
- package/src/Cancellation.res +31 -0
- package/src/Cancellation.res.mjs +45 -0
- package/src/ChildProcess.res +84 -0
- package/src/ChildProcess.res.mjs +92 -0
- package/src/Cli.res +671 -0
- package/src/Cli.res.mjs +754 -0
- package/src/Collector.res +201 -0
- package/src/Collector.res.mjs +215 -0
- package/src/ComponentMeta.res +104 -0
- package/src/ComponentMeta.res.mjs +120 -0
- package/src/ComponentScan.res +103 -0
- package/src/ComponentScan.res.mjs +105 -0
- package/src/Delegate_GWT.res +303 -0
- package/src/Delegate_GWT.res.mjs +372 -0
- package/src/Diff.res +91 -0
- package/src/Diff.res.mjs +98 -0
- package/src/Discovery.res +105 -0
- package/src/Discovery.res.mjs +103 -0
- package/src/DomainDeadCode.res +93 -0
- package/src/DomainDeadCode.res.mjs +69 -0
- package/src/DomainGraph.res +0 -0
- package/src/DomainGraph.res.mjs +0 -0
- package/src/EventMapping_GWT.res +29 -0
- package/src/EventMapping_GWT.res.mjs +44 -0
- package/src/Filter.res +36 -0
- package/src/Filter.res.mjs +40 -0
- package/src/Flow_GWT.res +664 -0
- package/src/Flow_GWT.res.mjs +604 -0
- package/src/FormatterHuman.res +138 -0
- package/src/FormatterHuman.res.mjs +122 -0
- package/src/FormatterJson.res +257 -0
- package/src/FormatterJson.res.mjs +320 -0
- package/src/FormatterJunit.res +93 -0
- package/src/FormatterJunit.res.mjs +90 -0
- package/src/FormatterTap.res +139 -0
- package/src/FormatterTap.res.mjs +149 -0
- package/src/FormatterVsCode.res +362 -0
- package/src/FormatterVsCode.res.mjs +564 -0
- package/src/Hint.res +119 -0
- package/src/Hint.res.mjs +124 -0
- package/src/InboundTranslation_GWT.res +83 -0
- package/src/InboundTranslation_GWT.res.mjs +94 -0
- package/src/JestBind.res +70 -0
- package/src/JestBind.res.mjs +63 -0
- package/src/Loader.res +24 -0
- package/src/Loader.res.mjs +23 -0
- package/src/LocalHost.res +135 -0
- package/src/LocalHost.res.mjs +127 -0
- package/src/Mapping_GWT.res +474 -0
- package/src/Mapping_GWT.res.mjs +322 -0
- package/src/MultiSourceProjection_GWT.res +316 -0
- package/src/MultiSourceProjection_GWT.res.mjs +354 -0
- package/src/OutboundTranslation_GWT.res +238 -0
- package/src/OutboundTranslation_GWT.res.mjs +186 -0
- package/src/Outcome.res +161 -0
- package/src/Outcome.res.mjs +140 -0
- package/src/PackageScan.res +80 -0
- package/src/PackageScan.res.mjs +81 -0
- package/src/PlatformRunner.res +160 -0
- package/src/PlatformRunner.res.mjs +155 -0
- package/src/PlatformScan.res +138 -0
- package/src/PlatformScan.res.mjs +131 -0
- package/src/ProcessManager.res +91 -0
- package/src/ProcessManager.res.mjs +80 -0
- package/src/Projection_GWT.res +312 -0
- package/src/Projection_GWT.res.mjs +332 -0
- package/src/Query_GWT.res +379 -0
- package/src/Query_GWT.res.mjs +367 -0
- package/src/RenderRescript.res +125 -0
- package/src/RenderRescript.res.mjs +141 -0
- package/src/RunnerTypes.res +68 -0
- package/src/RunnerTypes.res.mjs +60 -0
- package/src/SideEffect_GWT.res +157 -0
- package/src/SideEffect_GWT.res.mjs +113 -0
- package/src/StateChange/ExternalAddCategorySlice.res +25 -0
- package/src/StateChange/ExternalAddCategorySlice.res.mjs +34 -0
- package/src/StateChange/ExternalAddCategorySlice_Behavior.res +19 -0
- package/src/StateChange/ExternalAddCategorySlice_Behavior.res.mjs +46 -0
- package/src/StateChange/WithFixtures.res +22 -0
- package/src/StateChange/WithFixtures.res.mjs +31 -0
- package/src/StateChange/WithFixtures_Behavior.res +17 -0
- package/src/StateChange/WithFixtures_Behavior.res.mjs +37 -0
- package/src/StateChange/WithManualOpen.res +23 -0
- package/src/StateChange/WithManualOpen.res.mjs +31 -0
- package/src/StateChange/WithManualOpen_Behavior.res +17 -0
- package/src/StateChange/WithManualOpen_Behavior.res.mjs +37 -0
- package/src/StubRuntime.res +53 -0
- package/src/StubRuntime.res.mjs +54 -0
- package/src/TestFixtures.res +16 -0
- package/src/TestFixtures.res.mjs +34 -0
- package/src/Watch.res +92 -0
- package/src/Watch.res.mjs +83 -0
- package/src/WatcherProbe.res +48 -0
- package/src/WatcherProbe.res.mjs +46 -0
- package/tests/AutomationGwtTest.res +71 -0
- package/tests/AutomationGwtTest.res.mjs +189 -0
- package/tests/BuildClassifierTest.res +94 -0
- package/tests/BuildClassifierTest.res.mjs +132 -0
- package/tests/ComponentMetaTest.res +52 -0
- package/tests/ComponentMetaTest.res.mjs +57 -0
- package/tests/DelegateGwtTest.res +487 -0
- package/tests/DelegateGwtTest.res.mjs +891 -0
- package/tests/DiscoveryTest.res +42 -0
- package/tests/DiscoveryTest.res.mjs +43 -0
- package/tests/DomainDeadCodeTest.res +116 -0
- package/tests/DomainDeadCodeTest.res.mjs +155 -0
- package/tests/DomainGraphTest.res +365 -0
- package/tests/DomainGraphTest.res.mjs +413 -0
- package/tests/FlowAggregateGwtTest.res +169 -0
- package/tests/FlowAggregateGwtTest.res.mjs +269 -0
- package/tests/FlowCrossPluginGwtTest.res +340 -0
- package/tests/FlowCrossPluginGwtTest.res.mjs +798 -0
- package/tests/FlowGwtTest.res +222 -0
- package/tests/FlowGwtTest.res.mjs +432 -0
- package/tests/FormatterVsCodeMessageTest.res +41 -0
- package/tests/FormatterVsCodeMessageTest.res.mjs +42 -0
- package/tests/InboundTranslationGwtTest.res +34 -0
- package/tests/InboundTranslationGwtTest.res.mjs +98 -0
- package/tests/LocalHostIntegration.res +70 -0
- package/tests/LocalHostIntegration.res.mjs +64 -0
- package/tests/LocalHostTest.res +71 -0
- package/tests/LocalHostTest.res.mjs +63 -0
- package/tests/MappingGwtTest.res +348 -0
- package/tests/MappingGwtTest.res.mjs +592 -0
- package/tests/OutboundTranslationGwtTest.res +59 -0
- package/tests/OutboundTranslationGwtTest.res.mjs +138 -0
- package/tests/PlatformRunnerTest.res +66 -0
- package/tests/PlatformRunnerTest.res.mjs +85 -0
- package/tests/PlatformScanTest.res +61 -0
- package/tests/PlatformScanTest.res.mjs +56 -0
- package/tests/QueryGwtTest.res +161 -0
- package/tests/QueryGwtTest.res.mjs +314 -0
- package/tests/QueryResolverGwtTest.res +71 -0
- package/tests/QueryResolverGwtTest.res.mjs +136 -0
- package/tests/RunnerUnitTest.res +219 -0
- package/tests/RunnerUnitTest.res.mjs +244 -0
- package/tests/SideEffect/FakeOrderNotification.res +23 -0
- package/tests/SideEffect/FakeOrderNotification.res.mjs +36 -0
- package/tests/SideEffect/FakeOrderNotificationGwtTest.res +35 -0
- package/tests/SideEffect/FakeOrderNotificationGwtTest.res.mjs +73 -0
- package/tests/SideEffect/MockEmail.res +18 -0
- package/tests/SideEffect/MockEmail.res.mjs +47 -0
- package/tests/StateChange/ExternalAddCategorySlice_GWT.res +27 -0
- package/tests/StateChange/ExternalAddCategorySlice_GWT.res.mjs +70 -0
- package/tests/StateChange/WithFixtures_Fixtures.res +9 -0
- package/tests/StateChange/WithFixtures_Fixtures.res.mjs +20 -0
- package/tests/StateChange/WithFixtures_GWT.res +23 -0
- package/tests/StateChange/WithFixtures_GWT.res.mjs +56 -0
- package/tests/StateChange/WithManualOpen_Fixtures.res +7 -0
- package/tests/StateChange/WithManualOpen_Fixtures.res.mjs +20 -0
- package/tests/StateChange/WithManualOpen_GWT.res +17 -0
- package/tests/StateChange/WithManualOpen_GWT.res.mjs +56 -0
- package/tests/StateChangeSliceGwtTest.res +160 -0
- package/tests/StateChangeSliceGwtTest.res.mjs +280 -0
- package/tests/StateViewSliceGwtTest.res +64 -0
- package/tests/StateViewSliceGwtTest.res.mjs +161 -0
- package/tests/WatchDebounceTest.res +78 -0
- package/tests/WatchDebounceTest.res.mjs +97 -0
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as S from "sury/src/S.res.mjs";
|
|
4
|
+
import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
|
|
5
|
+
import * as Outcome$ReventlessGwt from "./Outcome.res.mjs";
|
|
6
|
+
import * as JestBind$ReventlessGwt from "./JestBind.res.mjs";
|
|
7
|
+
import * as Message$ReventlessCore from "@reventlessdev/reventless-core/src/Message.res.mjs";
|
|
8
|
+
|
|
9
|
+
function Make(Spec) {
|
|
10
|
+
S.enableJson();
|
|
11
|
+
let test = (name, timeout, body) => JestBind$ReventlessGwt.testPromise(Spec.name, name, timeout, body);
|
|
12
|
+
let testSync = (name, body) => JestBind$ReventlessGwt.test(Spec.name, name, body);
|
|
13
|
+
let encItems = arr => arr.map(param => [
|
|
14
|
+
param[0],
|
|
15
|
+
Message$ReventlessCore.encode(param[1], Spec.outboundItemSchema)
|
|
16
|
+
]);
|
|
17
|
+
let givenEvent = e => e;
|
|
18
|
+
let whenCollect = e => Spec.collect(e);
|
|
19
|
+
let thenTodos = (actual, expected) => {
|
|
20
|
+
if (Primitive_object.equal(actual, expected)) {
|
|
21
|
+
return Outcome$ReventlessGwt.pass;
|
|
22
|
+
} else {
|
|
23
|
+
return Outcome$ReventlessGwt.fail({
|
|
24
|
+
TAG: "TodoMismatch",
|
|
25
|
+
expected: encItems(expected),
|
|
26
|
+
actual: encItems(actual)
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
let givenTodo = (id, item) => [
|
|
31
|
+
id,
|
|
32
|
+
item
|
|
33
|
+
];
|
|
34
|
+
let whenTranslateMocked = async (param, mock) => {
|
|
35
|
+
let item = param[1];
|
|
36
|
+
let id = param[0];
|
|
37
|
+
let result = await mock(id, item);
|
|
38
|
+
return {
|
|
39
|
+
id: id,
|
|
40
|
+
item: item,
|
|
41
|
+
result: result,
|
|
42
|
+
retries: 0
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
let whenTranslateRetrying = async (param, maxRetries, mock) => {
|
|
46
|
+
let item = param[1];
|
|
47
|
+
let id = param[0];
|
|
48
|
+
let result = {
|
|
49
|
+
contents: await mock(id, item)
|
|
50
|
+
};
|
|
51
|
+
let retries = 0;
|
|
52
|
+
let failed = () => {
|
|
53
|
+
let match = result.contents;
|
|
54
|
+
return match.TAG !== "Ok";
|
|
55
|
+
};
|
|
56
|
+
while (failed() && retries < maxRetries) {
|
|
57
|
+
retries = retries + 1 | 0;
|
|
58
|
+
result.contents = await mock(id, item);
|
|
59
|
+
};
|
|
60
|
+
return {
|
|
61
|
+
id: id,
|
|
62
|
+
item: item,
|
|
63
|
+
result: result.contents,
|
|
64
|
+
retries: retries
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
let commandPairJson = (id, cmd) => {
|
|
68
|
+
let d = {};
|
|
69
|
+
d["id"] = id;
|
|
70
|
+
d["command"] = Message$ReventlessCore.encode(cmd, Spec.inboundCommandSchema);
|
|
71
|
+
return d;
|
|
72
|
+
};
|
|
73
|
+
let thenCommand = async (pending, expectedId, expectedCmd) => {
|
|
74
|
+
let match = await pending;
|
|
75
|
+
let result = match.result;
|
|
76
|
+
if (result.TAG !== "Ok") {
|
|
77
|
+
return Outcome$ReventlessGwt.fail({
|
|
78
|
+
TAG: "TranslateError",
|
|
79
|
+
expected: "(command)",
|
|
80
|
+
actual: result._0
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
let match$1 = result._0;
|
|
84
|
+
if (match$1 === undefined) {
|
|
85
|
+
return Outcome$ReventlessGwt.fail({
|
|
86
|
+
TAG: "EventsMismatch",
|
|
87
|
+
expected: [commandPairJson(expectedId, expectedCmd)],
|
|
88
|
+
actual: []
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
let cmd = match$1[1];
|
|
92
|
+
let id = match$1[0];
|
|
93
|
+
if (id === expectedId && Primitive_object.equal(cmd, expectedCmd)) {
|
|
94
|
+
return Outcome$ReventlessGwt.pass;
|
|
95
|
+
} else {
|
|
96
|
+
return Outcome$ReventlessGwt.fail({
|
|
97
|
+
TAG: "EventsMismatch",
|
|
98
|
+
expected: [commandPairJson(expectedId, expectedCmd)],
|
|
99
|
+
actual: [commandPairJson(id, cmd)]
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
let thenNoCommand = async pending => {
|
|
104
|
+
let match = await pending;
|
|
105
|
+
let result = match.result;
|
|
106
|
+
if (result.TAG !== "Ok") {
|
|
107
|
+
return Outcome$ReventlessGwt.fail({
|
|
108
|
+
TAG: "TranslateError",
|
|
109
|
+
expected: "(no command)",
|
|
110
|
+
actual: result._0
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
let match$1 = result._0;
|
|
114
|
+
if (match$1 !== undefined) {
|
|
115
|
+
return Outcome$ReventlessGwt.fail({
|
|
116
|
+
TAG: "NoEventExpected",
|
|
117
|
+
actual: [commandPairJson(match$1[0], match$1[1])]
|
|
118
|
+
});
|
|
119
|
+
} else {
|
|
120
|
+
return Outcome$ReventlessGwt.pass;
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
let thenRetryRecorded = async (pending, expectedRetries) => {
|
|
124
|
+
let match = await pending;
|
|
125
|
+
let retries = match.retries;
|
|
126
|
+
if (retries === expectedRetries) {
|
|
127
|
+
return Outcome$ReventlessGwt.pass;
|
|
128
|
+
} else {
|
|
129
|
+
return Outcome$ReventlessGwt.fail({
|
|
130
|
+
TAG: "StateMismatch",
|
|
131
|
+
key: "retries",
|
|
132
|
+
expected: expectedRetries,
|
|
133
|
+
actual: retries
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
let statusToString = s => {
|
|
138
|
+
if (s === "Pending") {
|
|
139
|
+
return "#Pending";
|
|
140
|
+
} else {
|
|
141
|
+
return "#Completed";
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
let thenTodoStatus = async (pending, expectedId, expectedStatus) => {
|
|
145
|
+
let match = await pending;
|
|
146
|
+
let id = match.id;
|
|
147
|
+
let actualStatus;
|
|
148
|
+
actualStatus = match.result.TAG === "Ok" ? "Completed" : "Pending";
|
|
149
|
+
if (id === expectedId && actualStatus === expectedStatus) {
|
|
150
|
+
return Outcome$ReventlessGwt.pass;
|
|
151
|
+
}
|
|
152
|
+
let encOne = (rid, rstatus) => {
|
|
153
|
+
let d = {};
|
|
154
|
+
d["id"] = rid;
|
|
155
|
+
d["status"] = statusToString(rstatus);
|
|
156
|
+
return d;
|
|
157
|
+
};
|
|
158
|
+
return Outcome$ReventlessGwt.fail({
|
|
159
|
+
TAG: "StateMismatch",
|
|
160
|
+
key: id,
|
|
161
|
+
expected: encOne(expectedId, expectedStatus),
|
|
162
|
+
actual: encOne(id, actualStatus)
|
|
163
|
+
});
|
|
164
|
+
};
|
|
165
|
+
return {
|
|
166
|
+
Spec: Spec,
|
|
167
|
+
describe: JestBind$ReventlessGwt.describe,
|
|
168
|
+
test: test,
|
|
169
|
+
testSync: testSync,
|
|
170
|
+
givenEvent: givenEvent,
|
|
171
|
+
whenCollect: whenCollect,
|
|
172
|
+
thenTodos: thenTodos,
|
|
173
|
+
givenTodo: givenTodo,
|
|
174
|
+
whenTranslateMocked: whenTranslateMocked,
|
|
175
|
+
whenTranslateRetrying: whenTranslateRetrying,
|
|
176
|
+
thenCommand: thenCommand,
|
|
177
|
+
thenNoCommand: thenNoCommand,
|
|
178
|
+
thenRetryRecorded: thenRetryRecorded,
|
|
179
|
+
thenTodoStatus: thenTodoStatus
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export {
|
|
184
|
+
Make,
|
|
185
|
+
}
|
|
186
|
+
/* S Not a pure module */
|
package/src/Outcome.res
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
// The `Outcome` algebra — Stage 2 of the reventless-gwt plan.
|
|
2
|
+
//
|
|
3
|
+
// Every `then*` combinator in every GWT DSL returns `Outcome.outcome`
|
|
4
|
+
// (`result<unit, mismatch>`). The runner, the human formatter, the AI loop,
|
|
5
|
+
// and the IDE all consume the same `Outcome` value, just rendered differently.
|
|
6
|
+
//
|
|
7
|
+
// See `docs/analysis/given-when-then-specifications.md` §3.2 for the canonical
|
|
8
|
+
// shape and §3.3 for the JSON rendering. Stage 7 adds sury-aware rendering and
|
|
9
|
+
// structural `fieldDiff`. Stage 4 added `AppendConditionMismatch`.
|
|
10
|
+
|
|
11
|
+
type mismatch =
|
|
12
|
+
| EventsMismatch({expected: array<JSON.t>, actual: array<JSON.t>})
|
|
13
|
+
| ErrorMismatch({
|
|
14
|
+
expected: JSON.t,
|
|
15
|
+
actual: option<JSON.t>,
|
|
16
|
+
actualEvents: array<JSON.t>,
|
|
17
|
+
})
|
|
18
|
+
| StateMismatch({key: string, expected: option<JSON.t>, actual: option<JSON.t>})
|
|
19
|
+
| NoEventExpected({actual: array<JSON.t>})
|
|
20
|
+
| TodoMismatch({expected: array<(string, JSON.t)>, actual: array<(string, JSON.t)>})
|
|
21
|
+
| AppendConditionMismatch({expected: JSON.t, actual: JSON.t})
|
|
22
|
+
| TranslateError({expected: string, actual: option<string>})
|
|
23
|
+
| QueryRowsMismatch({expected: array<JSON.t>, actual: array<JSON.t>})
|
|
24
|
+
// The set of published actions (events/commands) emitted by an ExtensionPoint
|
|
25
|
+
// mapping or an Extension delegate diverged from the expectation. Supports
|
|
26
|
+
// one-to-many fan-out (one inbound message → N published actions). Used by
|
|
27
|
+
// `Delegate_GWT` and the cross-plugin `Flow_GWT` boundary steps.
|
|
28
|
+
| PublishedActionsMismatch({expected: array<JSON.t>, actual: array<JSON.t>})
|
|
29
|
+
| Throw({error: string, stack: string})
|
|
30
|
+
|
|
31
|
+
type outcome = result<unit, mismatch>
|
|
32
|
+
|
|
33
|
+
let pass: outcome = Ok()
|
|
34
|
+
let fail = (m): outcome => Error(m)
|
|
35
|
+
|
|
36
|
+
let kindName = (m: mismatch) =>
|
|
37
|
+
switch m {
|
|
38
|
+
| EventsMismatch(_) => "EventsMismatch"
|
|
39
|
+
| ErrorMismatch(_) => "ErrorMismatch"
|
|
40
|
+
| StateMismatch(_) => "StateMismatch"
|
|
41
|
+
| NoEventExpected(_) => "NoEventExpected"
|
|
42
|
+
| TodoMismatch(_) => "TodoMismatch"
|
|
43
|
+
| AppendConditionMismatch(_) => "AppendConditionMismatch"
|
|
44
|
+
| TranslateError(_) => "TranslateError"
|
|
45
|
+
| QueryRowsMismatch(_) => "QueryRowsMismatch"
|
|
46
|
+
| PublishedActionsMismatch(_) => "PublishedActionsMismatch"
|
|
47
|
+
| Throw(_) => "Throw"
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
let stringifyJson = (j: JSON.t) => JSON.stringify(j, ~space=2)
|
|
51
|
+
let stringifyOptJson = (j: option<JSON.t>) =>
|
|
52
|
+
switch j {
|
|
53
|
+
| Some(v) => stringifyJson(v)
|
|
54
|
+
| None => "(none)"
|
|
55
|
+
}
|
|
56
|
+
let stringifyJsonArray = (arr: array<JSON.t>) =>
|
|
57
|
+
"[" ++ arr->Array.map(stringifyJson)->Array.join(", ") ++ "]"
|
|
58
|
+
|
|
59
|
+
let format = (m: mismatch) =>
|
|
60
|
+
switch m {
|
|
61
|
+
| EventsMismatch({expected, actual}) =>
|
|
62
|
+
`EventsMismatch:\n expected: ${stringifyJsonArray(expected)}\n actual: ${stringifyJsonArray(
|
|
63
|
+
actual,
|
|
64
|
+
)}`
|
|
65
|
+
| ErrorMismatch({expected, actual, actualEvents}) =>
|
|
66
|
+
`ErrorMismatch:\n expected error: ${stringifyJson(expected)}\n actual error: ${stringifyOptJson(
|
|
67
|
+
actual,
|
|
68
|
+
)}\n actual events: ${stringifyJsonArray(actualEvents)}`
|
|
69
|
+
| StateMismatch({key, expected, actual}) =>
|
|
70
|
+
`StateMismatch (key: ${key}):\n expected: ${stringifyOptJson(
|
|
71
|
+
expected,
|
|
72
|
+
)}\n actual: ${stringifyOptJson(actual)}`
|
|
73
|
+
| NoEventExpected({actual}) =>
|
|
74
|
+
`NoEventExpected: expected no events, got:\n ${stringifyJsonArray(actual)}`
|
|
75
|
+
| TodoMismatch({expected, actual}) => {
|
|
76
|
+
let fmt = arr =>
|
|
77
|
+
arr
|
|
78
|
+
->Array.map(((id, j)) => `(${id}, ${stringifyJson(j)})`)
|
|
79
|
+
->Array.join(", ")
|
|
80
|
+
`TodoMismatch:\n expected: [${fmt(expected)}]\n actual: [${fmt(actual)}]`
|
|
81
|
+
}
|
|
82
|
+
| AppendConditionMismatch({expected, actual}) =>
|
|
83
|
+
`AppendConditionMismatch:\n expected: ${stringifyJson(expected)}\n actual: ${stringifyJson(
|
|
84
|
+
actual,
|
|
85
|
+
)}`
|
|
86
|
+
| TranslateError({expected, actual}) =>
|
|
87
|
+
`TranslateError:\n expected: ${expected}\n actual: ${actual->Option.getOr("(none)")}`
|
|
88
|
+
| QueryRowsMismatch({expected, actual}) =>
|
|
89
|
+
`QueryRowsMismatch:\n expected: ${stringifyJsonArray(expected)}\n actual: ${stringifyJsonArray(
|
|
90
|
+
actual,
|
|
91
|
+
)}`
|
|
92
|
+
| PublishedActionsMismatch({expected, actual}) =>
|
|
93
|
+
`PublishedActionsMismatch:\n expected: ${stringifyJsonArray(expected)}\n actual: ${stringifyJsonArray(
|
|
94
|
+
actual,
|
|
95
|
+
)}`
|
|
96
|
+
| Throw({error, stack}) => `Throw: ${error}\n${stack}`
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Structured JSON payload per §3.3 of the analysis.
|
|
100
|
+
// Closed schema — consumers switch on the `kind` discriminator.
|
|
101
|
+
// Stage 7 enriches with `rendered` strings and `fieldDiff`.
|
|
102
|
+
let toJson = (m: mismatch): JSON.t => {
|
|
103
|
+
let obj = Dict.make()
|
|
104
|
+
obj->Dict.set("kind", JSON.Encode.string(kindName(m)))
|
|
105
|
+
let jsonArr = arr => JSON.Encode.array(arr)
|
|
106
|
+
let optJson = o => o->Option.getOr(JSON.Encode.null)
|
|
107
|
+
switch m {
|
|
108
|
+
| EventsMismatch({expected, actual}) => {
|
|
109
|
+
obj->Dict.set("expected", jsonArr(expected))
|
|
110
|
+
obj->Dict.set("actual", jsonArr(actual))
|
|
111
|
+
}
|
|
112
|
+
| ErrorMismatch({expected, actual, actualEvents}) => {
|
|
113
|
+
obj->Dict.set("expected", expected)
|
|
114
|
+
obj->Dict.set("actual", optJson(actual))
|
|
115
|
+
obj->Dict.set("actualEvents", jsonArr(actualEvents))
|
|
116
|
+
}
|
|
117
|
+
| StateMismatch({key, expected, actual}) => {
|
|
118
|
+
obj->Dict.set("key", JSON.Encode.string(key))
|
|
119
|
+
obj->Dict.set("expected", optJson(expected))
|
|
120
|
+
obj->Dict.set("actual", optJson(actual))
|
|
121
|
+
}
|
|
122
|
+
| NoEventExpected({actual}) => obj->Dict.set("actual", jsonArr(actual))
|
|
123
|
+
| TodoMismatch({expected, actual}) => {
|
|
124
|
+
let pairArr = pairs =>
|
|
125
|
+
pairs
|
|
126
|
+
->Array.map(((id, v)) => {
|
|
127
|
+
let d = Dict.make()
|
|
128
|
+
d->Dict.set("id", JSON.Encode.string(id))
|
|
129
|
+
d->Dict.set("value", v)
|
|
130
|
+
JSON.Encode.object(d)
|
|
131
|
+
})
|
|
132
|
+
->jsonArr
|
|
133
|
+
obj->Dict.set("expected", pairArr(expected))
|
|
134
|
+
obj->Dict.set("actual", pairArr(actual))
|
|
135
|
+
}
|
|
136
|
+
| AppendConditionMismatch({expected, actual}) => {
|
|
137
|
+
obj->Dict.set("expected", expected)
|
|
138
|
+
obj->Dict.set("actual", actual)
|
|
139
|
+
}
|
|
140
|
+
| TranslateError({expected, actual}) => {
|
|
141
|
+
obj->Dict.set("expected", JSON.Encode.string(expected))
|
|
142
|
+
obj->Dict.set(
|
|
143
|
+
"actual",
|
|
144
|
+
actual->Option.mapOr(JSON.Encode.null, JSON.Encode.string),
|
|
145
|
+
)
|
|
146
|
+
}
|
|
147
|
+
| QueryRowsMismatch({expected, actual}) => {
|
|
148
|
+
obj->Dict.set("expected", jsonArr(expected))
|
|
149
|
+
obj->Dict.set("actual", jsonArr(actual))
|
|
150
|
+
}
|
|
151
|
+
| PublishedActionsMismatch({expected, actual}) => {
|
|
152
|
+
obj->Dict.set("expected", jsonArr(expected))
|
|
153
|
+
obj->Dict.set("actual", jsonArr(actual))
|
|
154
|
+
}
|
|
155
|
+
| Throw({error, stack}) => {
|
|
156
|
+
obj->Dict.set("error", JSON.Encode.string(error))
|
|
157
|
+
obj->Dict.set("stack", JSON.Encode.string(stack))
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
JSON.Encode.object(obj)
|
|
161
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
4
|
+
|
|
5
|
+
function fail(m) {
|
|
6
|
+
return {
|
|
7
|
+
TAG: "Error",
|
|
8
|
+
_0: m
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function kindName(m) {
|
|
13
|
+
switch (m.TAG) {
|
|
14
|
+
case "EventsMismatch" :
|
|
15
|
+
return "EventsMismatch";
|
|
16
|
+
case "ErrorMismatch" :
|
|
17
|
+
return "ErrorMismatch";
|
|
18
|
+
case "StateMismatch" :
|
|
19
|
+
return "StateMismatch";
|
|
20
|
+
case "NoEventExpected" :
|
|
21
|
+
return "NoEventExpected";
|
|
22
|
+
case "TodoMismatch" :
|
|
23
|
+
return "TodoMismatch";
|
|
24
|
+
case "AppendConditionMismatch" :
|
|
25
|
+
return "AppendConditionMismatch";
|
|
26
|
+
case "TranslateError" :
|
|
27
|
+
return "TranslateError";
|
|
28
|
+
case "QueryRowsMismatch" :
|
|
29
|
+
return "QueryRowsMismatch";
|
|
30
|
+
case "PublishedActionsMismatch" :
|
|
31
|
+
return "PublishedActionsMismatch";
|
|
32
|
+
case "Throw" :
|
|
33
|
+
return "Throw";
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function stringifyJson(j) {
|
|
38
|
+
return JSON.stringify(j, undefined, 2);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function stringifyOptJson(j) {
|
|
42
|
+
if (j !== undefined) {
|
|
43
|
+
return JSON.stringify(j, undefined, 2);
|
|
44
|
+
} else {
|
|
45
|
+
return "(none)";
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function stringifyJsonArray(arr) {
|
|
50
|
+
return "[" + arr.map(stringifyJson).join(", ") + "]";
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function format(m) {
|
|
54
|
+
switch (m.TAG) {
|
|
55
|
+
case "EventsMismatch" :
|
|
56
|
+
return `EventsMismatch:\n expected: ` + stringifyJsonArray(m.expected) + `\n actual: ` + stringifyJsonArray(m.actual);
|
|
57
|
+
case "ErrorMismatch" :
|
|
58
|
+
return `ErrorMismatch:\n expected error: ` + JSON.stringify(m.expected, undefined, 2) + `\n actual error: ` + stringifyOptJson(m.actual) + `\n actual events: ` + stringifyJsonArray(m.actualEvents);
|
|
59
|
+
case "StateMismatch" :
|
|
60
|
+
return `StateMismatch (key: ` + m.key + `):\n expected: ` + stringifyOptJson(m.expected) + `\n actual: ` + stringifyOptJson(m.actual);
|
|
61
|
+
case "NoEventExpected" :
|
|
62
|
+
return `NoEventExpected: expected no events, got:\n ` + stringifyJsonArray(m.actual);
|
|
63
|
+
case "TodoMismatch" :
|
|
64
|
+
let fmt = arr => arr.map(param => `(` + param[0] + `, ` + JSON.stringify(param[1], undefined, 2) + `)`).join(", ");
|
|
65
|
+
return `TodoMismatch:\n expected: [` + fmt(m.expected) + `]\n actual: [` + fmt(m.actual) + `]`;
|
|
66
|
+
case "AppendConditionMismatch" :
|
|
67
|
+
return `AppendConditionMismatch:\n expected: ` + JSON.stringify(m.expected, undefined, 2) + `\n actual: ` + JSON.stringify(m.actual, undefined, 2);
|
|
68
|
+
case "TranslateError" :
|
|
69
|
+
return `TranslateError:\n expected: ` + m.expected + `\n actual: ` + Stdlib_Option.getOr(m.actual, "(none)");
|
|
70
|
+
case "QueryRowsMismatch" :
|
|
71
|
+
return `QueryRowsMismatch:\n expected: ` + stringifyJsonArray(m.expected) + `\n actual: ` + stringifyJsonArray(m.actual);
|
|
72
|
+
case "PublishedActionsMismatch" :
|
|
73
|
+
return `PublishedActionsMismatch:\n expected: ` + stringifyJsonArray(m.expected) + `\n actual: ` + stringifyJsonArray(m.actual);
|
|
74
|
+
case "Throw" :
|
|
75
|
+
return `Throw: ` + m.error + `\n` + m.stack;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function toJson(m) {
|
|
80
|
+
let obj = {};
|
|
81
|
+
obj["kind"] = kindName(m);
|
|
82
|
+
switch (m.TAG) {
|
|
83
|
+
case "ErrorMismatch" :
|
|
84
|
+
obj["expected"] = m.expected;
|
|
85
|
+
obj["actual"] = Stdlib_Option.getOr(m.actual, null);
|
|
86
|
+
obj["actualEvents"] = m.actualEvents;
|
|
87
|
+
break;
|
|
88
|
+
case "StateMismatch" :
|
|
89
|
+
obj["key"] = m.key;
|
|
90
|
+
obj["expected"] = Stdlib_Option.getOr(m.expected, null);
|
|
91
|
+
obj["actual"] = Stdlib_Option.getOr(m.actual, null);
|
|
92
|
+
break;
|
|
93
|
+
case "NoEventExpected" :
|
|
94
|
+
obj["actual"] = m.actual;
|
|
95
|
+
break;
|
|
96
|
+
case "TodoMismatch" :
|
|
97
|
+
let pairArr = pairs => pairs.map(param => {
|
|
98
|
+
let d = {};
|
|
99
|
+
d["id"] = param[0];
|
|
100
|
+
d["value"] = param[1];
|
|
101
|
+
return d;
|
|
102
|
+
});
|
|
103
|
+
obj["expected"] = pairArr(m.expected);
|
|
104
|
+
obj["actual"] = pairArr(m.actual);
|
|
105
|
+
break;
|
|
106
|
+
case "TranslateError" :
|
|
107
|
+
obj["expected"] = m.expected;
|
|
108
|
+
obj["actual"] = Stdlib_Option.mapOr(m.actual, null, prim => prim);
|
|
109
|
+
break;
|
|
110
|
+
case "EventsMismatch" :
|
|
111
|
+
case "AppendConditionMismatch" :
|
|
112
|
+
case "QueryRowsMismatch" :
|
|
113
|
+
case "PublishedActionsMismatch" :
|
|
114
|
+
obj["expected"] = m.expected;
|
|
115
|
+
obj["actual"] = m.actual;
|
|
116
|
+
break;
|
|
117
|
+
case "Throw" :
|
|
118
|
+
obj["error"] = m.error;
|
|
119
|
+
obj["stack"] = m.stack;
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
return obj;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
let pass = {
|
|
126
|
+
TAG: "Ok",
|
|
127
|
+
_0: undefined
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
export {
|
|
131
|
+
pass,
|
|
132
|
+
fail,
|
|
133
|
+
kindName,
|
|
134
|
+
stringifyJson,
|
|
135
|
+
stringifyOptJson,
|
|
136
|
+
stringifyJsonArray,
|
|
137
|
+
format,
|
|
138
|
+
toJson,
|
|
139
|
+
}
|
|
140
|
+
/* No side effect */
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// Derives the set of workspace packages that own GWT test files, so a watch
|
|
2
|
+
// session knows which packages to keep compiling (`pnpm run start` →
|
|
3
|
+
// `rescript build -w`). Given the absolute test-file paths from `Discovery`,
|
|
4
|
+
// each is mapped to its nearest ancestor `package.json` that declares a
|
|
5
|
+
// `start` script; results are deduplicated by directory.
|
|
6
|
+
//
|
|
7
|
+
// This is the input both the `packages` NDJSON event (FormatterVsCode) and the
|
|
8
|
+
// watch-mode build manager (ProcessManager) consume — computed fresh per run so
|
|
9
|
+
// it never drifts when a plugin is added or removed.
|
|
10
|
+
|
|
11
|
+
type pkg = {
|
|
12
|
+
// Package name from package.json (may be "" if absent).
|
|
13
|
+
name: string,
|
|
14
|
+
// Absolute directory containing the owning package.json.
|
|
15
|
+
dir: string,
|
|
16
|
+
// The `start` script's command (the ReScript watch command), informational.
|
|
17
|
+
build: string,
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@module("node:fs") external _existsSync: string => bool = "existsSync"
|
|
21
|
+
@module("node:fs") external _readFileSync: (string, string) => string = "readFileSync"
|
|
22
|
+
@module("node:path") external dirname: string => string = "dirname"
|
|
23
|
+
@module("node:path") external join: (string, string) => string = "join"
|
|
24
|
+
|
|
25
|
+
// Reads name + `start` command from a package.json, if it declares one.
|
|
26
|
+
let readPackage = (pkgJsonPath: string): option<(string, string)> =>
|
|
27
|
+
try {
|
|
28
|
+
let json = JSON.parseOrThrow(_readFileSync(pkgJsonPath, "utf8"))
|
|
29
|
+
switch json {
|
|
30
|
+
| Object(obj) =>
|
|
31
|
+
let name = switch obj->Dict.get("name") {
|
|
32
|
+
| Some(String(n)) => n
|
|
33
|
+
| _ => ""
|
|
34
|
+
}
|
|
35
|
+
switch obj->Dict.get("scripts") {
|
|
36
|
+
| Some(Object(scripts)) =>
|
|
37
|
+
switch scripts->Dict.get("start") {
|
|
38
|
+
| Some(String(cmd)) => Some((name, cmd))
|
|
39
|
+
| _ => None
|
|
40
|
+
}
|
|
41
|
+
| _ => None
|
|
42
|
+
}
|
|
43
|
+
| _ => None
|
|
44
|
+
}
|
|
45
|
+
} catch {
|
|
46
|
+
| _ => None
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Walks up from `dir` to the nearest package.json declaring a `start` script.
|
|
50
|
+
let rec findOwning = (dir: string): option<pkg> => {
|
|
51
|
+
let pkgJson = join(dir, "package.json")
|
|
52
|
+
let here = _existsSync(pkgJson) ? readPackage(pkgJson) : None
|
|
53
|
+
switch here {
|
|
54
|
+
| Some((name, build)) => Some({name, dir, build})
|
|
55
|
+
| None => {
|
|
56
|
+
let parent = dirname(dir)
|
|
57
|
+
parent == dir ? None : findOwning(parent)
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Maps test files → deduplicated owning packages (declaration order preserved).
|
|
63
|
+
let scan = (testFiles: array<string>): array<pkg> => {
|
|
64
|
+
let seen = Dict.make()
|
|
65
|
+
let out = []
|
|
66
|
+
testFiles->Array.forEach(file =>
|
|
67
|
+
switch findOwning(dirname(file)) {
|
|
68
|
+
| Some(pkg) =>
|
|
69
|
+
switch seen->Dict.get(pkg.dir) {
|
|
70
|
+
| Some(_) => ()
|
|
71
|
+
| None => {
|
|
72
|
+
seen->Dict.set(pkg.dir, true)
|
|
73
|
+
out->Array.push(pkg)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
| None => ()
|
|
77
|
+
}
|
|
78
|
+
)
|
|
79
|
+
out
|
|
80
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Nodefs from "node:fs";
|
|
4
|
+
import * as Nodepath from "node:path";
|
|
5
|
+
|
|
6
|
+
function readPackage(pkgJsonPath) {
|
|
7
|
+
try {
|
|
8
|
+
let json = JSON.parse(Nodefs.readFileSync(pkgJsonPath, "utf8"));
|
|
9
|
+
if (typeof json !== "object" || json === null || Array.isArray(json)) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
let match = json["name"];
|
|
13
|
+
let name = typeof match === "string" ? match : "";
|
|
14
|
+
let match$1 = json["scripts"];
|
|
15
|
+
if (match$1 === undefined) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
if (typeof match$1 !== "object" || match$1 === null || Array.isArray(match$1)) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
let match$2 = match$1["start"];
|
|
22
|
+
if (typeof match$2 === "string") {
|
|
23
|
+
return [
|
|
24
|
+
name,
|
|
25
|
+
match$2
|
|
26
|
+
];
|
|
27
|
+
} else {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
} catch (exn) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function findOwning(_dir) {
|
|
36
|
+
while (true) {
|
|
37
|
+
let dir = _dir;
|
|
38
|
+
let pkgJson = Nodepath.join(dir, "package.json");
|
|
39
|
+
let here = Nodefs.existsSync(pkgJson) ? readPackage(pkgJson) : undefined;
|
|
40
|
+
if (here !== undefined) {
|
|
41
|
+
return {
|
|
42
|
+
name: here[0],
|
|
43
|
+
dir: dir,
|
|
44
|
+
build: here[1]
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
let parent = Nodepath.dirname(dir);
|
|
48
|
+
if (parent === dir) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
_dir = parent;
|
|
52
|
+
continue;
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function scan(testFiles) {
|
|
57
|
+
let seen = {};
|
|
58
|
+
let out = [];
|
|
59
|
+
testFiles.forEach(file => {
|
|
60
|
+
let pkg = findOwning(Nodepath.dirname(file));
|
|
61
|
+
if (pkg === undefined) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
let match = seen[pkg.dir];
|
|
65
|
+
if (match !== undefined) {
|
|
66
|
+
return;
|
|
67
|
+
} else {
|
|
68
|
+
seen[pkg.dir] = true;
|
|
69
|
+
out.push(pkg);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
return out;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export {
|
|
77
|
+
readPackage,
|
|
78
|
+
findOwning,
|
|
79
|
+
scan,
|
|
80
|
+
}
|
|
81
|
+
/* node:fs Not a pure module */
|