@reventlessdev/reventless-gwt 1.0.0-alpha.76 → 1.0.0-alpha.77
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 +8 -0
- package/package.json +6 -6
- package/src/Behavior_GWT.res +125 -159
- package/src/Behavior_GWT.res.mjs +156 -59
- package/src/BuildClassifier.res +15 -5
- package/src/BuildClassifier.res.mjs +3 -3
- package/src/Cli.res +157 -29
- package/src/Cli.res.mjs +138 -24
- package/src/Collector.res +2 -2
- package/src/Collector.res.mjs +2 -2
- package/src/ComponentMeta.res +16 -43
- package/src/ComponentMeta.res.mjs +12 -41
- package/src/Discovery.res +19 -19
- package/src/Discovery.res.mjs +5 -9
- package/src/DomainGraph.res +0 -0
- package/src/DomainGraph.res.mjs +0 -0
- package/src/FormatterHuman.res +14 -43
- package/src/FormatterHuman.res.mjs +21 -28
- package/src/FormatterJson.res +12 -5
- package/src/FormatterJson.res.mjs +8 -6
- package/src/FormatterTap.res +13 -52
- package/src/FormatterTap.res.mjs +25 -43
- package/src/FormatterVsCode.res +4 -19
- package/src/FormatterVsCode.res.mjs +4 -23
- package/src/LocalHost.res +11 -27
- package/src/LocalHost.res.mjs +6 -34
- package/src/MismatchRender.res +72 -0
- package/src/MismatchRender.res.mjs +127 -0
- package/src/Outcome.res +0 -64
- package/src/Outcome.res.mjs +0 -47
- package/src/PlatformScan.res +14 -10
- package/src/PlatformScan.res.mjs +14 -13
- package/tests/BuildClassifierTest.res +39 -0
- package/tests/BuildClassifierTest.res.mjs +44 -0
- package/tests/CliWatchScopeTest.res +62 -0
- package/tests/CliWatchScopeTest.res.mjs +95 -0
- package/tests/ComponentMetaTest.res +15 -0
- package/tests/ComponentMetaTest.res.mjs +14 -0
- package/tests/DomainGraphTest.res +2 -2
- package/tests/FlowAggregateGwtTest.res +2 -0
- package/tests/FlowAggregateGwtTest.res.mjs +4 -0
- package/tests/FormatterGoldenTest.res +125 -0
- package/tests/FormatterGoldenTest.res.mjs +162 -0
- package/tests/MappingGwtTest.res +2 -0
- package/tests/MappingGwtTest.res.mjs +4 -0
package/src/FormatterTap.res.mjs
CHANGED
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
4
4
|
import * as Hint$ReventlessGwt from "./Hint.res.mjs";
|
|
5
|
-
import * as
|
|
6
|
-
import * as RenderRescript$ReventlessGwt from "./RenderRescript.res.mjs";
|
|
5
|
+
import * as MismatchRender$ReventlessGwt from "./MismatchRender.res.mjs";
|
|
7
6
|
|
|
8
7
|
function write(s) {
|
|
9
8
|
process.stdout.write(s);
|
|
@@ -27,47 +26,30 @@ function yamlLine(indentOpt, key, value) {
|
|
|
27
26
|
}
|
|
28
27
|
|
|
29
28
|
function renderMismatchYaml(m) {
|
|
30
|
-
let
|
|
31
|
-
lines
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
lines.push(yamlLine(undefined, "actual", yamlString(RenderRescript$ReventlessGwt.render(undefined, m.actual))));
|
|
55
|
-
break;
|
|
56
|
-
case "TranslateError" :
|
|
57
|
-
lines.push(yamlLine(undefined, "expected", yamlString(m.expected)));
|
|
58
|
-
lines.push(yamlLine(undefined, "actual", yamlString(Stdlib_Option.getOr(m.actual, "(none)"))));
|
|
59
|
-
break;
|
|
60
|
-
case "EventsMismatch" :
|
|
61
|
-
case "QueryRowsMismatch" :
|
|
62
|
-
case "PublishedActionsMismatch" :
|
|
63
|
-
lines.push(yamlLine(undefined, "expected", yamlString(RenderRescript$ReventlessGwt.renderMany(m.expected))));
|
|
64
|
-
lines.push(yamlLine(undefined, "actual", yamlString(RenderRescript$ReventlessGwt.renderMany(m.actual))));
|
|
65
|
-
break;
|
|
66
|
-
case "Throw" :
|
|
67
|
-
lines.push(yamlLine(undefined, "error", yamlString(m.error)));
|
|
68
|
-
lines.push(yamlLine(undefined, "stack", yamlString(m.stack)));
|
|
69
|
-
break;
|
|
70
|
-
}
|
|
29
|
+
let n = MismatchRender$ReventlessGwt.normalize(m);
|
|
30
|
+
let lines = [yamlLine(undefined, "kind", yamlString(n.kind))];
|
|
31
|
+
n.fields.forEach(f => {
|
|
32
|
+
if (typeof f !== "object") {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
switch (f.TAG) {
|
|
36
|
+
case "Expected" :
|
|
37
|
+
lines.push(yamlLine(undefined, "expected", yamlString(f._0)));
|
|
38
|
+
return;
|
|
39
|
+
case "Actual" :
|
|
40
|
+
lines.push(yamlLine(undefined, "actual", yamlString(f._0)));
|
|
41
|
+
return;
|
|
42
|
+
case "Key" :
|
|
43
|
+
lines.push(yamlLine(undefined, "key", yamlString(f._0)));
|
|
44
|
+
return;
|
|
45
|
+
case "Error" :
|
|
46
|
+
lines.push(yamlLine(undefined, "error", yamlString(f._0)));
|
|
47
|
+
return;
|
|
48
|
+
case "Stack" :
|
|
49
|
+
lines.push(yamlLine(undefined, "stack", yamlString(f._0)));
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
});
|
|
71
53
|
return lines.join("\n");
|
|
72
54
|
}
|
|
73
55
|
|
package/src/FormatterVsCode.res
CHANGED
|
@@ -45,12 +45,6 @@ let relativeToCwd = (abs: string) => pathRelative(processCwd(), abs)
|
|
|
45
45
|
|
|
46
46
|
let sourceLineCache: Dict.t<option<array<string>>> = Dict.make()
|
|
47
47
|
|
|
48
|
-
let resetLocateCache = () => {
|
|
49
|
-
sourceLineCache
|
|
50
|
-
->Dict.keysToArray
|
|
51
|
-
->Array.forEach(k => Dict.delete(sourceLineCache, k))
|
|
52
|
-
}
|
|
53
|
-
|
|
54
48
|
let mjsToRes = (mjsPath: string): option<string> =>
|
|
55
49
|
if String.endsWith(mjsPath, ".res.mjs") {
|
|
56
50
|
Some(String.slice(mjsPath, ~start=0, ~end=String.length(mjsPath) - 4))
|
|
@@ -253,18 +247,9 @@ let deadCode = (findings: array<DomainDeadCode.finding>) =>
|
|
|
253
247
|
|
|
254
248
|
// Event-Modeling graph (Phase 6) — the node/edge model assembled from each plugin's
|
|
255
249
|
// `pluginStructure` + cross-plugin edges.
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
nodes: g.nodes->Array.map((n): P.graphNode => {
|
|
260
|
-
id: n.id,
|
|
261
|
-
kind: n.kind,
|
|
262
|
-
label: n.label,
|
|
263
|
-
plugin: n.plugin,
|
|
264
|
-
}),
|
|
265
|
-
edges: g.edges->Array.map((e): P.graphEdge => {from: e.from, to_: e.to, kind: e.kind, label: ?e.label}),
|
|
266
|
-
}),
|
|
267
|
-
)
|
|
250
|
+
// `DomainGraph` already builds `P.graphNode`/`P.graphEdge`, so the graph event
|
|
251
|
+
// forwards them directly — no field-by-field re-map to drift from the contract.
|
|
252
|
+
let graph = (g: DomainGraph.graph) => emit(Graph({nodes: g.nodes, edges: g.edges}))
|
|
268
253
|
|
|
269
254
|
// Component definitions (Phase 6.3) — one `encodePluginStructureEntry` JSON object
|
|
270
255
|
// per plugin (commands/events with field schemas, read-side state schemas), used by
|
|
@@ -292,7 +277,7 @@ let domainEvent = (payload: JSON.t) => writeLine(JSON.stringify(payload))
|
|
|
292
277
|
|
|
293
278
|
let platformLog = (~line: string) => emit(PlatformLog({line: line}))
|
|
294
279
|
|
|
295
|
-
let platformStop = (~code: option<int>) => emit(PlatformStop({code: code}))
|
|
280
|
+
let platformStop = (~code: option<int>) => emit(PlatformStop({code: ?code}))
|
|
296
281
|
|
|
297
282
|
let runStart = (~total: int, ~filter: array<string>) => emit(RunStart({total, filter}))
|
|
298
283
|
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
import * as Nodefs from "node:fs";
|
|
4
4
|
import * as Nodepath from "node:path";
|
|
5
|
-
import * as Stdlib_Dict from "@rescript/runtime/lib/es6/Stdlib_Dict.js";
|
|
6
5
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
7
6
|
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
8
7
|
import * as Hint$ReventlessGwt from "./Hint.res.mjs";
|
|
@@ -43,10 +42,6 @@ function relativeToCwd(abs) {
|
|
|
43
42
|
|
|
44
43
|
let sourceLineCache = {};
|
|
45
44
|
|
|
46
|
-
function resetLocateCache() {
|
|
47
|
-
Object.keys(sourceLineCache).forEach(k => Stdlib_Dict.$$delete(sourceLineCache, k));
|
|
48
|
-
}
|
|
49
|
-
|
|
50
45
|
function mjsToRes(mjsPath) {
|
|
51
46
|
if (mjsPath.endsWith(".res.mjs")) {
|
|
52
47
|
return mjsPath.slice(0, mjsPath.length - 4 | 0);
|
|
@@ -282,24 +277,11 @@ function deadCode(findings) {
|
|
|
282
277
|
}
|
|
283
278
|
|
|
284
279
|
function graph(g) {
|
|
285
|
-
let
|
|
286
|
-
id: n.id,
|
|
287
|
-
kind: n.kind,
|
|
288
|
-
label: n.label,
|
|
289
|
-
plugin: n.plugin
|
|
290
|
-
}));
|
|
291
|
-
let e_1 = g.edges.map(e => ({
|
|
292
|
-
from: e.from,
|
|
293
|
-
to: e.to,
|
|
294
|
-
kind: e.kind,
|
|
295
|
-
label: e.label
|
|
296
|
-
}));
|
|
297
|
-
let e = {
|
|
280
|
+
let s = Protocol$ReventlessVscodeProtocol.toJsonLine({
|
|
298
281
|
event: "graph",
|
|
299
|
-
nodes:
|
|
300
|
-
edges:
|
|
301
|
-
};
|
|
302
|
-
let s = Protocol$ReventlessVscodeProtocol.toJsonLine(e);
|
|
282
|
+
nodes: g.nodes,
|
|
283
|
+
edges: g.edges
|
|
284
|
+
});
|
|
303
285
|
process.stdout.write(s + "\n");
|
|
304
286
|
}
|
|
305
287
|
|
|
@@ -527,7 +509,6 @@ export {
|
|
|
527
509
|
fileLabelOf,
|
|
528
510
|
relativeToCwd,
|
|
529
511
|
sourceLineCache,
|
|
530
|
-
resetLocateCache,
|
|
531
512
|
mjsToRes,
|
|
532
513
|
readLinesCached,
|
|
533
514
|
escapeForDouble,
|
package/src/LocalHost.res
CHANGED
|
@@ -55,23 +55,11 @@ type pluginExports = {"Make": platform => builtPlugin}
|
|
|
55
55
|
// plugin keys match the names the framework itself bakes into Plugin.res. ──
|
|
56
56
|
|
|
57
57
|
// "@scope/my-catalog" → "MyCatalog", "online-shop" → "OnlineShop".
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
64
|
-
base
|
|
65
|
-
->String.split("-")
|
|
66
|
-
->Array.flatMap(part => part->String.split("_"))
|
|
67
|
-
->Array.map(word =>
|
|
68
|
-
word === ""
|
|
69
|
-
? ""
|
|
70
|
-
: word->String.slice(~start=0, ~end=1)->String.toUpperCase ++
|
|
71
|
-
word->String.slice(~start=1, ~end=word->String.length)
|
|
72
|
-
)
|
|
73
|
-
->Array.join("")
|
|
74
|
-
}
|
|
58
|
+
// Single-sourced with the plugin generator (spec's `Config`) via
|
|
59
|
+
// `Reventless.PluginName` so the two can't drift — a drift silently breaks
|
|
60
|
+
// graph plugin keys (see the module for the full rationale). Re-exported here
|
|
61
|
+
// under the historical name the tests already pin.
|
|
62
|
+
let packageNameToPluginName = Reventless.PluginName.fromPackageName
|
|
75
63
|
|
|
76
64
|
let strField = (json, key) =>
|
|
77
65
|
json->JSON.Decode.object->Option.flatMap(d => d->Dict.get(key))->Option.flatMap(JSON.Decode.string)
|
|
@@ -82,19 +70,15 @@ let readJson = path =>
|
|
|
82
70
|
}
|
|
83
71
|
|
|
84
72
|
// plugin.json `name` → else PascalCase(package.json `name`) → else "Plugin".
|
|
73
|
+
// The precedence itself lives in `Reventless.PluginName.resolve`; this only
|
|
74
|
+
// reads the two raw fields with the local node bindings.
|
|
85
75
|
let derivePluginName = (~pluginSrcDir: string): string => {
|
|
86
76
|
let pluginJson = join(pluginSrcDir, "plugin.json")
|
|
87
|
-
let
|
|
77
|
+
let pluginJsonName =
|
|
88
78
|
existsSync(pluginJson) ? readJson(pluginJson)->Option.flatMap(j => strField(j, "name")) : None
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
let pkgJson = join(dirname(pluginSrcDir), "package.json")
|
|
93
|
-
readJson(pkgJson)
|
|
94
|
-
->Option.flatMap(j => strField(j, "name"))
|
|
95
|
-
->Option.map(packageNameToPluginName)
|
|
96
|
-
->Option.getOr("Plugin")
|
|
97
|
-
}
|
|
79
|
+
let packageJsonName =
|
|
80
|
+
readJson(join(dirname(pluginSrcDir), "package.json"))->Option.flatMap(j => strField(j, "name"))
|
|
81
|
+
Reventless.PluginName.resolve(~pluginJsonName, ~packageJsonName)
|
|
98
82
|
}
|
|
99
83
|
|
|
100
84
|
// Given workspace package dirs (e.g. from PackageScan), keep those that carry a
|
package/src/LocalHost.res.mjs
CHANGED
|
@@ -7,6 +7,7 @@ import * as Stdlib_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
|
|
|
7
7
|
import * as Nodemodule from "node:module";
|
|
8
8
|
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
9
9
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
10
|
+
import * as PluginName$Reventless from "@reventlessdev/reventless-spec/src/components/PluginName.res.mjs";
|
|
10
11
|
|
|
11
12
|
let dynamicImport = ((u) => import(u));
|
|
12
13
|
|
|
@@ -19,34 +20,6 @@ function bustedUrl(absolutePath) {
|
|
|
19
20
|
return Nodeurl.pathToFileURL(absolutePath).href + "?t=" + counter.contents.toString();
|
|
20
21
|
}
|
|
21
22
|
|
|
22
|
-
function packageNameToPluginName(packageName) {
|
|
23
|
-
let parts = packageName.split("/");
|
|
24
|
-
let len = parts.length;
|
|
25
|
-
let base;
|
|
26
|
-
if (len >= 3) {
|
|
27
|
-
base = parts[parts.length - 1 | 0];
|
|
28
|
-
} else {
|
|
29
|
-
switch (len) {
|
|
30
|
-
case 0 :
|
|
31
|
-
base = parts[parts.length - 1 | 0];
|
|
32
|
-
break;
|
|
33
|
-
case 1 :
|
|
34
|
-
base = parts[0];
|
|
35
|
-
break;
|
|
36
|
-
case 2 :
|
|
37
|
-
base = parts[1];
|
|
38
|
-
break;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
return base.split("-").flatMap(part => part.split("_")).map(word => {
|
|
42
|
-
if (word === "") {
|
|
43
|
-
return "";
|
|
44
|
-
} else {
|
|
45
|
-
return word.slice(0, 1).toUpperCase() + word.slice(1, word.length);
|
|
46
|
-
}
|
|
47
|
-
}).join("");
|
|
48
|
-
}
|
|
49
|
-
|
|
50
23
|
function strField(json, key) {
|
|
51
24
|
return Stdlib_Option.flatMap(Stdlib_Option.flatMap(Stdlib_JSON.Decode.object(json), d => d[key]), Stdlib_JSON.Decode.string);
|
|
52
25
|
}
|
|
@@ -61,12 +34,9 @@ function readJson(path) {
|
|
|
61
34
|
|
|
62
35
|
function derivePluginName(pluginSrcDir) {
|
|
63
36
|
let pluginJson = Nodepath.join(pluginSrcDir, "plugin.json");
|
|
64
|
-
let
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
let pkgJson = Nodepath.join(Nodepath.dirname(pluginSrcDir), "package.json");
|
|
69
|
-
return Stdlib_Option.getOr(Stdlib_Option.map(Stdlib_Option.flatMap(readJson(pkgJson), j => strField(j, "name")), packageNameToPluginName), "Plugin");
|
|
37
|
+
let pluginJsonName = Nodefs.existsSync(pluginJson) ? Stdlib_Option.flatMap(readJson(pluginJson), j => strField(j, "name")) : undefined;
|
|
38
|
+
let packageJsonName = Stdlib_Option.flatMap(readJson(Nodepath.join(Nodepath.dirname(pluginSrcDir), "package.json")), j => strField(j, "name"));
|
|
39
|
+
return PluginName$Reventless.resolve(pluginJsonName, packageJsonName);
|
|
70
40
|
}
|
|
71
41
|
|
|
72
42
|
function discover(packageDirs) {
|
|
@@ -111,6 +81,8 @@ async function loadGraph(platformModulePath, plugins) {
|
|
|
111
81
|
};
|
|
112
82
|
}
|
|
113
83
|
|
|
84
|
+
let packageNameToPluginName = PluginName$Reventless.fromPackageName;
|
|
85
|
+
|
|
114
86
|
export {
|
|
115
87
|
dynamicImport,
|
|
116
88
|
counter,
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// Single source for rendering an `Outcome.mismatch`'s expected/actual/extras
|
|
2
|
+
// into RenderRescript strings. The Human and TAP formatters previously each held
|
|
3
|
+
// a full 10-arm switch over the mismatch that computed *identical* rendered
|
|
4
|
+
// values (`RenderRescript.render*`, the `Error()`/`Ok()` wrapping, the Todo
|
|
5
|
+
// `(id, value)` pairs) and differed only in framing — aligned `label: value`
|
|
6
|
+
// lines vs YAML `key: "escaped"` lines. This normalizes the value-rendering once;
|
|
7
|
+
// each formatter interprets the `field` list with its own framing.
|
|
8
|
+
//
|
|
9
|
+
// NOT used by JUnit (renders via the older JSON-based `Outcome.format`) nor
|
|
10
|
+
// FormatterJson/VsCode (they consume the raw JSON values to build a structured
|
|
11
|
+
// `{type, payload, rendered}` + `fieldDiff` payload).
|
|
12
|
+
|
|
13
|
+
// One rendered piece of a mismatch. The constructor carries the *already
|
|
14
|
+
// rendered* string (unescaped — Human uses it raw, TAP yaml-escapes it), except
|
|
15
|
+
// the structural markers `ExpectedNoEvents` (Human prints a literal line; TAP
|
|
16
|
+
// omits it) and `Stack` (Human appends it raw; TAP labels it as a yaml field).
|
|
17
|
+
type field =
|
|
18
|
+
| Expected(string)
|
|
19
|
+
| Actual(string)
|
|
20
|
+
| Key(string)
|
|
21
|
+
| ExpectedNoEvents
|
|
22
|
+
| Error(string)
|
|
23
|
+
| Stack(string)
|
|
24
|
+
|
|
25
|
+
type normalized = {
|
|
26
|
+
kind: string,
|
|
27
|
+
fields: array<field>,
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
let render = RenderRescript.render
|
|
31
|
+
let renderMany = RenderRescript.renderMany
|
|
32
|
+
let renderOption = RenderRescript.renderOption
|
|
33
|
+
|
|
34
|
+
let normalize = (m: Outcome.mismatch): normalized => {
|
|
35
|
+
let fields = switch m {
|
|
36
|
+
| EventsMismatch({expected, actual}) => [Expected(renderMany(expected)), Actual(renderMany(actual))]
|
|
37
|
+
| ErrorMismatch({expected, actual, actualEvents}) => [
|
|
38
|
+
Expected(`Error(${render(expected)})`),
|
|
39
|
+
Actual(
|
|
40
|
+
switch actual {
|
|
41
|
+
| Some(v) => `Error(${render(v)})`
|
|
42
|
+
| None => `Ok(${renderMany(actualEvents)})`
|
|
43
|
+
},
|
|
44
|
+
),
|
|
45
|
+
]
|
|
46
|
+
| StateMismatch({key, expected, actual}) => [
|
|
47
|
+
Key(key),
|
|
48
|
+
Expected(renderOption(expected)),
|
|
49
|
+
Actual(renderOption(actual)),
|
|
50
|
+
]
|
|
51
|
+
| NoEventExpected({actual}) => [ExpectedNoEvents, Actual(renderMany(actual))]
|
|
52
|
+
| TodoMismatch({expected, actual}) =>
|
|
53
|
+
let fmt = (arr: array<(string, JSON.t)>) =>
|
|
54
|
+
"[" ++ arr->Array.map(((id, v)) => `(${id}, ${render(v)})`)->Array.join(", ") ++ "]"
|
|
55
|
+
[Expected(fmt(expected)), Actual(fmt(actual))]
|
|
56
|
+
| AppendConditionMismatch({expected, actual}) => [
|
|
57
|
+
Expected(render(expected)),
|
|
58
|
+
Actual(render(actual)),
|
|
59
|
+
]
|
|
60
|
+
| TranslateError({expected, actual}) => [
|
|
61
|
+
Expected(expected),
|
|
62
|
+
Actual(actual->Option.getOr("(none)")),
|
|
63
|
+
]
|
|
64
|
+
| QueryRowsMismatch({expected, actual}) => [Expected(renderMany(expected)), Actual(renderMany(actual))]
|
|
65
|
+
| PublishedActionsMismatch({expected, actual}) => [
|
|
66
|
+
Expected(renderMany(expected)),
|
|
67
|
+
Actual(renderMany(actual)),
|
|
68
|
+
]
|
|
69
|
+
| Throw({error, stack}) => [Error(error), Stack(stack)]
|
|
70
|
+
}
|
|
71
|
+
{kind: Outcome.kindName(m), fields}
|
|
72
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
4
|
+
import * as Outcome$ReventlessGwt from "./Outcome.res.mjs";
|
|
5
|
+
import * as RenderRescript$ReventlessGwt from "./RenderRescript.res.mjs";
|
|
6
|
+
|
|
7
|
+
function normalize(m) {
|
|
8
|
+
let fields;
|
|
9
|
+
switch (m.TAG) {
|
|
10
|
+
case "ErrorMismatch" :
|
|
11
|
+
let actual = m.actual;
|
|
12
|
+
fields = [
|
|
13
|
+
{
|
|
14
|
+
TAG: "Expected",
|
|
15
|
+
_0: `Error(` + RenderRescript$ReventlessGwt.render(undefined, m.expected) + `)`
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
TAG: "Actual",
|
|
19
|
+
_0: actual !== undefined ? `Error(` + RenderRescript$ReventlessGwt.render(undefined, actual) + `)` : `Ok(` + RenderRescript$ReventlessGwt.renderMany(m.actualEvents) + `)`
|
|
20
|
+
}
|
|
21
|
+
];
|
|
22
|
+
break;
|
|
23
|
+
case "StateMismatch" :
|
|
24
|
+
fields = [
|
|
25
|
+
{
|
|
26
|
+
TAG: "Key",
|
|
27
|
+
_0: m.key
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
TAG: "Expected",
|
|
31
|
+
_0: RenderRescript$ReventlessGwt.renderOption(m.expected)
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
TAG: "Actual",
|
|
35
|
+
_0: RenderRescript$ReventlessGwt.renderOption(m.actual)
|
|
36
|
+
}
|
|
37
|
+
];
|
|
38
|
+
break;
|
|
39
|
+
case "NoEventExpected" :
|
|
40
|
+
fields = [
|
|
41
|
+
"ExpectedNoEvents",
|
|
42
|
+
{
|
|
43
|
+
TAG: "Actual",
|
|
44
|
+
_0: RenderRescript$ReventlessGwt.renderMany(m.actual)
|
|
45
|
+
}
|
|
46
|
+
];
|
|
47
|
+
break;
|
|
48
|
+
case "TodoMismatch" :
|
|
49
|
+
let fmt = arr => "[" + arr.map(param => `(` + param[0] + `, ` + RenderRescript$ReventlessGwt.render(undefined, param[1]) + `)`).join(", ") + "]";
|
|
50
|
+
fields = [
|
|
51
|
+
{
|
|
52
|
+
TAG: "Expected",
|
|
53
|
+
_0: fmt(m.expected)
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
TAG: "Actual",
|
|
57
|
+
_0: fmt(m.actual)
|
|
58
|
+
}
|
|
59
|
+
];
|
|
60
|
+
break;
|
|
61
|
+
case "AppendConditionMismatch" :
|
|
62
|
+
fields = [
|
|
63
|
+
{
|
|
64
|
+
TAG: "Expected",
|
|
65
|
+
_0: RenderRescript$ReventlessGwt.render(undefined, m.expected)
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
TAG: "Actual",
|
|
69
|
+
_0: RenderRescript$ReventlessGwt.render(undefined, m.actual)
|
|
70
|
+
}
|
|
71
|
+
];
|
|
72
|
+
break;
|
|
73
|
+
case "TranslateError" :
|
|
74
|
+
fields = [
|
|
75
|
+
{
|
|
76
|
+
TAG: "Expected",
|
|
77
|
+
_0: m.expected
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
TAG: "Actual",
|
|
81
|
+
_0: Stdlib_Option.getOr(m.actual, "(none)")
|
|
82
|
+
}
|
|
83
|
+
];
|
|
84
|
+
break;
|
|
85
|
+
case "Throw" :
|
|
86
|
+
fields = [
|
|
87
|
+
{
|
|
88
|
+
TAG: "Error",
|
|
89
|
+
_0: m.error
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
TAG: "Stack",
|
|
93
|
+
_0: m.stack
|
|
94
|
+
}
|
|
95
|
+
];
|
|
96
|
+
break;
|
|
97
|
+
default:
|
|
98
|
+
fields = [
|
|
99
|
+
{
|
|
100
|
+
TAG: "Expected",
|
|
101
|
+
_0: RenderRescript$ReventlessGwt.renderMany(m.expected)
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
TAG: "Actual",
|
|
105
|
+
_0: RenderRescript$ReventlessGwt.renderMany(m.actual)
|
|
106
|
+
}
|
|
107
|
+
];
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
kind: Outcome$ReventlessGwt.kindName(m),
|
|
111
|
+
fields: fields
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
let render = RenderRescript$ReventlessGwt.render;
|
|
116
|
+
|
|
117
|
+
let renderMany = RenderRescript$ReventlessGwt.renderMany;
|
|
118
|
+
|
|
119
|
+
let renderOption = RenderRescript$ReventlessGwt.renderOption;
|
|
120
|
+
|
|
121
|
+
export {
|
|
122
|
+
render,
|
|
123
|
+
renderMany,
|
|
124
|
+
renderOption,
|
|
125
|
+
normalize,
|
|
126
|
+
}
|
|
127
|
+
/* No side effect */
|
package/src/Outcome.res
CHANGED
|
@@ -95,67 +95,3 @@ let format = (m: mismatch) =>
|
|
|
95
95
|
)}`
|
|
96
96
|
| Throw({error, stack}) => `Throw: ${error}\n${stack}`
|
|
97
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
|
-
}
|
package/src/Outcome.res.mjs
CHANGED
|
@@ -76,52 +76,6 @@ function format(m) {
|
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
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
79
|
let pass = {
|
|
126
80
|
TAG: "Ok",
|
|
127
81
|
_0: undefined
|
|
@@ -135,6 +89,5 @@ export {
|
|
|
135
89
|
stringifyOptJson,
|
|
136
90
|
stringifyJsonArray,
|
|
137
91
|
format,
|
|
138
|
-
toJson,
|
|
139
92
|
}
|
|
140
93
|
/* No side effect */
|
package/src/PlatformScan.res
CHANGED
|
@@ -105,16 +105,20 @@ let inspectDir = (dir: string): option<platformPkg> => {
|
|
|
105
105
|
// declaration order preserved). Prunes node_modules/lib/.git like Discovery.
|
|
106
106
|
let rec walk = async (dir: string, acc: array<platformPkg>): array<platformPkg> => {
|
|
107
107
|
switch inspectDir(dir) {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
108
|
+
// A platform package — record it and stop: descending into its own subtree
|
|
109
|
+
// (src/, generated code, nested workspace copies) can only waste I/O or turn
|
|
110
|
+
// up spurious inner matches. This is what the "don't descend" comment always
|
|
111
|
+
// intended; the recursion below used to run regardless.
|
|
112
|
+
| Some(pkg) => acc->Array.push(pkg)
|
|
113
|
+
| None =>
|
|
114
|
+
let entries = try await _readdir(dir, {withFileTypes: true}) catch {
|
|
115
|
+
| _ => []
|
|
116
|
+
}
|
|
117
|
+
for i in 0 to entries->Array.length - 1 {
|
|
118
|
+
let entry = entries->Array.getUnsafe(i)
|
|
119
|
+
if entry._isDirectory() && !Array.includes(ignoreNames, entry.name) {
|
|
120
|
+
let _ = await walk(join(dir, entry.name), acc)
|
|
121
|
+
}
|
|
118
122
|
}
|
|
119
123
|
}
|
|
120
124
|
acc
|