@reventlessdev/reventless-gwt 1.0.0-alpha.75 → 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 +16 -0
- package/package.json +8 -8
- package/src/Behavior_GWT.res +125 -159
- package/src/Behavior_GWT.res.mjs +156 -59
- package/src/Bind.res.mjs +2 -2
- package/src/BuildClassifier.res +15 -5
- package/src/BuildClassifier.res.mjs +3 -3
- package/src/Cancellation.res +6 -0
- package/src/Cancellation.res.mjs +3 -2
- package/src/ChildProcess.res +19 -1
- package/src/ChildProcess.res.mjs +16 -1
- package/src/Cli.res +260 -26
- package/src/Cli.res.mjs +227 -29
- package/src/Collector.res +13 -2
- package/src/Collector.res.mjs +8 -5
- 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/Filter.res +11 -2
- package/src/Filter.res.mjs +10 -3
- 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/JestBind.res +1 -1
- package/src/JestBind.res.mjs +2 -2
- 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/PlatformRunner.res +27 -6
- package/src/PlatformRunner.res.mjs +27 -6
- package/src/PlatformScan.res +14 -10
- package/src/PlatformScan.res.mjs +14 -13
- package/src/ProcessManager.res +51 -7
- package/src/ProcessManager.res.mjs +43 -4
- package/src/RunWorker.res +24 -0
- package/src/RunWorker.res.mjs +16 -0
- package/src/Watch.res +46 -30
- package/src/Watch.res.mjs +34 -32
- package/src/WatcherProbe.res +11 -3
- package/src/WatcherProbe.res.mjs +15 -2
- package/src/Worker.res +24 -0
- package/src/Worker.res.mjs +9 -0
- package/tests/BuildClassifierTest.res +39 -0
- package/tests/BuildClassifierTest.res.mjs +44 -0
- package/tests/CliRunEntryTest.res +57 -0
- package/tests/CliRunEntryTest.res.mjs +65 -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/tests/WatchDebounceTest.res +35 -7
- package/tests/WatchDebounceTest.res.mjs +37 -6
package/src/Discovery.res
CHANGED
|
@@ -43,36 +43,37 @@ let isGwtTestFile = (name: string) =>
|
|
|
43
43
|
String.endsWith(name, "GwtTest.res.mjs") ||
|
|
44
44
|
String.endsWith(name, "Gwt.res.mjs")
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
// Depth-first, pushing into a shared accumulator instead of rebuilding it with
|
|
47
|
+
// `Array.concat` per entry (which was O(n²) over a large tree). The traversal
|
|
48
|
+
// order is unchanged: files and nested subtree results still land in on-disk
|
|
49
|
+
// entry order.
|
|
50
|
+
let rec walk = async (dir: string, acc: array<string>): unit => {
|
|
47
51
|
let entries = try {
|
|
48
52
|
await _readdir(dir, {withFileTypes: true})
|
|
49
53
|
} catch {
|
|
50
54
|
| _ => []
|
|
51
55
|
}
|
|
52
56
|
if isPruned(entries) {
|
|
53
|
-
|
|
57
|
+
()
|
|
54
58
|
} else {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
found := Array.concat(found.contents, [full])
|
|
59
|
+
for i in 0 to entries->Array.length - 1 {
|
|
60
|
+
let entry = entries->Array.getUnsafe(i)
|
|
61
|
+
if !shouldIgnore(entry.name) {
|
|
62
|
+
let full = join(dir, entry.name)
|
|
63
|
+
if entry._isDirectory() {
|
|
64
|
+
await walk(full, acc)
|
|
65
|
+
} else if entry._isFile() && isGwtTestFile(entry.name) {
|
|
66
|
+
acc->Array.push(full)
|
|
67
|
+
}
|
|
65
68
|
}
|
|
66
69
|
}
|
|
67
70
|
}
|
|
68
|
-
found.contents
|
|
69
|
-
}
|
|
70
71
|
}
|
|
71
72
|
|
|
72
73
|
// Returns absolute paths of `*GWT*.res.mjs` test files reachable from the
|
|
73
74
|
// supplied roots. A root may be a directory or a single file.
|
|
74
75
|
let discover = async (roots: array<string>): array<string> => {
|
|
75
|
-
let found =
|
|
76
|
+
let found = []
|
|
76
77
|
for i in 0 to roots->Array.length - 1 {
|
|
77
78
|
let root = roots->Array.getUnsafe(i)
|
|
78
79
|
let absolute = isAbsolute(root) ? root : resolve(root)
|
|
@@ -83,16 +84,15 @@ let discover = async (roots: array<string>): array<string> => {
|
|
|
83
84
|
| _ => false
|
|
84
85
|
}
|
|
85
86
|
if isDir {
|
|
86
|
-
|
|
87
|
-
found := Array.concat(found.contents, collected)
|
|
87
|
+
await walk(absolute, found)
|
|
88
88
|
} else if isGwtTestFile(absolute) {
|
|
89
|
-
found
|
|
89
|
+
found->Array.push(absolute)
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
// Deduplicate (if roots overlap).
|
|
93
93
|
let seen = Dict.make()
|
|
94
94
|
let unique = []
|
|
95
|
-
found
|
|
95
|
+
found->Array.forEach(path =>
|
|
96
96
|
switch seen->Dict.get(path) {
|
|
97
97
|
| Some(_) => ()
|
|
98
98
|
| None => {
|
package/src/Discovery.res.mjs
CHANGED
|
@@ -39,22 +39,19 @@ async function walk(dir, acc) {
|
|
|
39
39
|
entries = [];
|
|
40
40
|
}
|
|
41
41
|
if (isPruned(entries)) {
|
|
42
|
-
return
|
|
42
|
+
return;
|
|
43
43
|
}
|
|
44
|
-
let found = acc;
|
|
45
44
|
for (let i = 0, i_finish = entries.length; i < i_finish; ++i) {
|
|
46
45
|
let entry = entries[i];
|
|
47
46
|
if (!ignoreNames.includes(entry.name)) {
|
|
48
47
|
let full = Nodepath.join(dir, entry.name);
|
|
49
48
|
if (entry.isDirectory()) {
|
|
50
|
-
|
|
51
|
-
found = found.concat(nested);
|
|
49
|
+
await walk(full, acc);
|
|
52
50
|
} else if (entry.isFile() && isGwtTestFile(entry.name)) {
|
|
53
|
-
|
|
51
|
+
acc.push(full);
|
|
54
52
|
}
|
|
55
53
|
}
|
|
56
54
|
}
|
|
57
|
-
return found;
|
|
58
55
|
}
|
|
59
56
|
|
|
60
57
|
async function discover(roots) {
|
|
@@ -70,10 +67,9 @@ async function discover(roots) {
|
|
|
70
67
|
isDir = false;
|
|
71
68
|
}
|
|
72
69
|
if (isDir) {
|
|
73
|
-
|
|
74
|
-
found = found.concat(collected);
|
|
70
|
+
await walk(absolute, found);
|
|
75
71
|
} else if (isGwtTestFile(absolute)) {
|
|
76
|
-
found
|
|
72
|
+
found.push(absolute);
|
|
77
73
|
}
|
|
78
74
|
}
|
|
79
75
|
let seen = {};
|
package/src/DomainGraph.res
CHANGED
|
Binary file
|
package/src/DomainGraph.res.mjs
CHANGED
|
Binary file
|
package/src/Filter.res
CHANGED
|
@@ -29,8 +29,17 @@ let xtest = (~slice as _: option<string>=?, name: string, _body: unit => Outcome
|
|
|
29
29
|
let xdescribe = (label: string, body: unit => unit) =>
|
|
30
30
|
if Collector.isActive() {
|
|
31
31
|
Collector.skipDepth := Collector.skipDepth.contents + 1
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
// Decrement on both the normal and the throwing path (ReScript has no
|
|
33
|
+
// `finally`): a body that raises must not leak the incremented depth and
|
|
34
|
+
// skip every following sibling/file.
|
|
35
|
+
try {
|
|
36
|
+
Collector.pushDescribe(label, body)
|
|
37
|
+
Collector.skipDepth := Collector.skipDepth.contents - 1
|
|
38
|
+
} catch {
|
|
39
|
+
| e =>
|
|
40
|
+
Collector.skipDepth := Collector.skipDepth.contents - 1
|
|
41
|
+
throw(e)
|
|
42
|
+
}
|
|
34
43
|
} else {
|
|
35
44
|
jestXDescribe(label, body)
|
|
36
45
|
}
|
package/src/Filter.res.mjs
CHANGED
|
@@ -14,7 +14,7 @@ function only() {
|
|
|
14
14
|
function xtest(param, name, _body) {
|
|
15
15
|
if (Collector$ReventlessGwt.isActive()) {
|
|
16
16
|
Collector$ReventlessGwt.markSkipNext();
|
|
17
|
-
return Collector$ReventlessGwt.push(undefined, undefined, name, () => Promise.resolve(Outcome$ReventlessGwt.pass));
|
|
17
|
+
return Collector$ReventlessGwt.push(undefined, undefined, undefined, name, () => Promise.resolve(Outcome$ReventlessGwt.pass));
|
|
18
18
|
} else {
|
|
19
19
|
globalThis.xtest(name, () => {});
|
|
20
20
|
return;
|
|
@@ -24,10 +24,17 @@ function xtest(param, name, _body) {
|
|
|
24
24
|
function xdescribe(label, body) {
|
|
25
25
|
if (Collector$ReventlessGwt.isActive()) {
|
|
26
26
|
Collector$ReventlessGwt.skipDepth.contents = Collector$ReventlessGwt.skipDepth.contents + 1 | 0;
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
try {
|
|
28
|
+
Collector$ReventlessGwt.pushDescribe(label, body);
|
|
29
|
+
Collector$ReventlessGwt.skipDepth.contents = Collector$ReventlessGwt.skipDepth.contents - 1 | 0;
|
|
30
|
+
return;
|
|
31
|
+
} catch (e) {
|
|
32
|
+
Collector$ReventlessGwt.skipDepth.contents = Collector$ReventlessGwt.skipDepth.contents - 1 | 0;
|
|
33
|
+
throw e;
|
|
34
|
+
}
|
|
29
35
|
} else {
|
|
30
36
|
globalThis.xdescribe(label, body);
|
|
37
|
+
return;
|
|
31
38
|
}
|
|
32
39
|
}
|
|
33
40
|
|
package/src/FormatterHuman.res
CHANGED
|
@@ -41,51 +41,22 @@ let formatLocation = (loc: option<Collector.location>) =>
|
|
|
41
41
|
| Some(l) => `${l.file}:${Int.toString(l.line)}`
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
| None => `Ok(${RenderRescript.renderMany(actualEvents)})`
|
|
56
|
-
}
|
|
57
|
-
` expected: ${exp}\n actual: ${act}`
|
|
58
|
-
}
|
|
59
|
-
| StateMismatch({key, expected, actual}) =>
|
|
60
|
-
` key: "${key}"\n expected: ${RenderRescript.renderOption(
|
|
61
|
-
expected,
|
|
62
|
-
)}\n actual: ${RenderRescript.renderOption(actual)}`
|
|
63
|
-
| NoEventExpected({actual}) =>
|
|
64
|
-
` expected no events\n actual: ${RenderRescript.renderMany(actual)}`
|
|
65
|
-
| TodoMismatch({expected, actual}) => {
|
|
66
|
-
let fmt = (arr: array<(string, JSON.t)>) =>
|
|
67
|
-
arr
|
|
68
|
-
->Array.map(((id, v)) => `(${id}, ${RenderRescript.render(v)})`)
|
|
69
|
-
->Array.join(", ")
|
|
70
|
-
` expected: [${fmt(expected)}]\n actual: [${fmt(actual)}]`
|
|
71
|
-
}
|
|
72
|
-
| AppendConditionMismatch({expected, actual}) =>
|
|
73
|
-
` expected: ${RenderRescript.render(expected)}\n actual: ${RenderRescript.render(
|
|
74
|
-
actual,
|
|
75
|
-
)}`
|
|
76
|
-
| TranslateError({expected, actual}) =>
|
|
77
|
-
` expected: ${expected}\n actual: ${actual->Option.getOr("(none)")}`
|
|
78
|
-
| QueryRowsMismatch({expected, actual}) =>
|
|
79
|
-
` expected: ${RenderRescript.renderMany(expected)}\n actual: ${RenderRescript.renderMany(
|
|
80
|
-
actual,
|
|
81
|
-
)}`
|
|
82
|
-
| PublishedActionsMismatch({expected, actual}) =>
|
|
83
|
-
` expected: ${RenderRescript.renderMany(expected)}\n actual: ${RenderRescript.renderMany(
|
|
84
|
-
actual,
|
|
85
|
-
)}`
|
|
86
|
-
| Throw({error, stack}) => ` error: ${error}\n${stack}`
|
|
44
|
+
// Frames one normalized field as a terminal line. Labels are padded so values
|
|
45
|
+
// align at column 12 (`key:`, `expected:`, `actual:`); `error:` is its own
|
|
46
|
+
// shorter form and the `Throw` stack is dumped raw beneath it.
|
|
47
|
+
let renderField = (f: MismatchRender.field) =>
|
|
48
|
+
switch f {
|
|
49
|
+
| Expected(v) => ` expected: ${v}`
|
|
50
|
+
| Actual(v) => ` actual: ${v}`
|
|
51
|
+
| Key(k) => ` key: "${k}"`
|
|
52
|
+
| ExpectedNoEvents => " expected no events"
|
|
53
|
+
| Error(e) => ` error: ${e}`
|
|
54
|
+
| Stack(s) => s
|
|
87
55
|
}
|
|
88
56
|
|
|
57
|
+
let renderMismatch = (m: Outcome.mismatch) =>
|
|
58
|
+
MismatchRender.normalize(m).fields->Array.map(renderField)->Array.join("\n")
|
|
59
|
+
|
|
89
60
|
let emitTest = (t: RunnerTypes.testResult) => {
|
|
90
61
|
let path = t.describePath->Array.join(" > ")
|
|
91
62
|
let full = path == "" ? t.name : `${path} > ${t.name}`
|
|
@@ -4,7 +4,7 @@ import * as Nodepath from "node:path";
|
|
|
4
4
|
import Picocolors from "picocolors";
|
|
5
5
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
6
6
|
import * as Hint$ReventlessGwt from "./Hint.res.mjs";
|
|
7
|
-
import * as
|
|
7
|
+
import * as MismatchRender$ReventlessGwt from "./MismatchRender.res.mjs";
|
|
8
8
|
|
|
9
9
|
function write(s) {
|
|
10
10
|
process.stdout.write(s);
|
|
@@ -29,36 +29,28 @@ function formatLocation(loc) {
|
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
function
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
return `
|
|
43
|
-
case "
|
|
44
|
-
return `
|
|
45
|
-
case "
|
|
46
|
-
return
|
|
47
|
-
case "TodoMismatch" :
|
|
48
|
-
let fmt = arr => arr.map(param => `(` + param[0] + `, ` + RenderRescript$ReventlessGwt.render(undefined, param[1]) + `)`).join(", ");
|
|
49
|
-
return ` expected: [` + fmt(m.expected) + `]\n actual: [` + fmt(m.actual) + `]`;
|
|
50
|
-
case "AppendConditionMismatch" :
|
|
51
|
-
return ` expected: ` + RenderRescript$ReventlessGwt.render(undefined, m.expected) + `\n actual: ` + RenderRescript$ReventlessGwt.render(undefined, m.actual);
|
|
52
|
-
case "TranslateError" :
|
|
53
|
-
return ` expected: ` + m.expected + `\n actual: ` + Stdlib_Option.getOr(m.actual, "(none)");
|
|
54
|
-
case "QueryRowsMismatch" :
|
|
55
|
-
case "PublishedActionsMismatch" :
|
|
56
|
-
return ` expected: ` + RenderRescript$ReventlessGwt.renderMany(m.expected) + `\n actual: ` + RenderRescript$ReventlessGwt.renderMany(m.actual);
|
|
57
|
-
case "Throw" :
|
|
58
|
-
return ` error: ` + m.error + `\n` + m.stack;
|
|
32
|
+
function renderField(f) {
|
|
33
|
+
if (typeof f !== "object") {
|
|
34
|
+
return " expected no events";
|
|
35
|
+
}
|
|
36
|
+
switch (f.TAG) {
|
|
37
|
+
case "Expected" :
|
|
38
|
+
return ` expected: ` + f._0;
|
|
39
|
+
case "Actual" :
|
|
40
|
+
return ` actual: ` + f._0;
|
|
41
|
+
case "Key" :
|
|
42
|
+
return ` key: "` + f._0 + `"`;
|
|
43
|
+
case "Error" :
|
|
44
|
+
return ` error: ` + f._0;
|
|
45
|
+
case "Stack" :
|
|
46
|
+
return f._0;
|
|
59
47
|
}
|
|
60
48
|
}
|
|
61
49
|
|
|
50
|
+
function renderMismatch(m) {
|
|
51
|
+
return MismatchRender$ReventlessGwt.normalize(m).fields.map(renderField).join("\n");
|
|
52
|
+
}
|
|
53
|
+
|
|
62
54
|
function emitTest(t) {
|
|
63
55
|
let path = t.describePath.join(" > ");
|
|
64
56
|
let full = path === "" ? t.name : path + ` > ` + t.name;
|
|
@@ -113,6 +105,7 @@ export {
|
|
|
113
105
|
writeLine,
|
|
114
106
|
formatFilePath,
|
|
115
107
|
formatLocation,
|
|
108
|
+
renderField,
|
|
116
109
|
renderMismatch,
|
|
117
110
|
emitTest,
|
|
118
111
|
emitFile,
|
package/src/FormatterJson.res
CHANGED
|
@@ -5,7 +5,10 @@
|
|
|
5
5
|
|
|
6
6
|
// 1.1.0 — additive: `PublishedActionsMismatch` mismatch kind for the
|
|
7
7
|
// Delegate_GWT / cross-plugin Flow_GWT boundary steps.
|
|
8
|
-
|
|
8
|
+
// The default the emitted envelope carries; the `--schema-version` CLI flag
|
|
9
|
+
// overrides it (threaded through `emit` / `streamRunStart`) so a consumer can
|
|
10
|
+
// pin the schema version its AI prompt was built against.
|
|
11
|
+
let defaultSchemaVersion = "1.1.0"
|
|
9
12
|
|
|
10
13
|
@val external processStdout: {"write": string => unit} = "process.stdout"
|
|
11
14
|
let write = (s: string) => processStdout["write"](s)
|
|
@@ -184,7 +187,11 @@ let summaryJson = (s: RunnerTypes.summary): JSON.t => {
|
|
|
184
187
|
JSON.Encode.object(d)
|
|
185
188
|
}
|
|
186
189
|
|
|
187
|
-
let envelope = (
|
|
190
|
+
let envelope = (
|
|
191
|
+
r: RunnerTypes.runResult,
|
|
192
|
+
~toolVersion: string,
|
|
193
|
+
~schemaVersion: string,
|
|
194
|
+
): JSON.t => {
|
|
188
195
|
let d = Dict.make()
|
|
189
196
|
d->Dict.set("schemaVersion", JSON.Encode.string(schemaVersion))
|
|
190
197
|
d->Dict.set("tool", JSON.Encode.string("reventless-gwt"))
|
|
@@ -196,11 +203,11 @@ let envelope = (r: RunnerTypes.runResult, ~toolVersion: string): JSON.t => {
|
|
|
196
203
|
JSON.Encode.object(d)
|
|
197
204
|
}
|
|
198
205
|
|
|
199
|
-
let emit = (r: RunnerTypes.runResult, ~toolVersion: string) =>
|
|
200
|
-
write(JSON.stringify(envelope(r, ~toolVersion), ~space=2) ++ "\n")
|
|
206
|
+
let emit = (r: RunnerTypes.runResult, ~toolVersion: string, ~schemaVersion=defaultSchemaVersion) =>
|
|
207
|
+
write(JSON.stringify(envelope(r, ~toolVersion, ~schemaVersion), ~space=2) ++ "\n")
|
|
201
208
|
|
|
202
209
|
// Streaming variant — NDJSON events.
|
|
203
|
-
let streamRunStart = (~toolVersion: string, ~startedAt: string) => {
|
|
210
|
+
let streamRunStart = (~toolVersion: string, ~startedAt: string, ~schemaVersion=defaultSchemaVersion) => {
|
|
204
211
|
let d = Dict.make()
|
|
205
212
|
d->Dict.set("type", JSON.Encode.string("runStarted"))
|
|
206
213
|
d->Dict.set("schemaVersion", JSON.Encode.string(schemaVersion))
|
|
@@ -7,7 +7,7 @@ import * as Outcome$ReventlessGwt from "./Outcome.res.mjs";
|
|
|
7
7
|
import * as RunnerTypes$ReventlessGwt from "./RunnerTypes.res.mjs";
|
|
8
8
|
import * as RenderRescript$ReventlessGwt from "./RenderRescript.res.mjs";
|
|
9
9
|
|
|
10
|
-
let
|
|
10
|
+
let defaultSchemaVersion = "1.1.0";
|
|
11
11
|
|
|
12
12
|
function write(s) {
|
|
13
13
|
process.stdout.write(s);
|
|
@@ -214,7 +214,7 @@ function summaryJson(s) {
|
|
|
214
214
|
return d;
|
|
215
215
|
}
|
|
216
216
|
|
|
217
|
-
function envelope(r, toolVersion) {
|
|
217
|
+
function envelope(r, toolVersion, schemaVersion) {
|
|
218
218
|
let d = {};
|
|
219
219
|
d["schemaVersion"] = schemaVersion;
|
|
220
220
|
d["tool"] = "reventless-gwt";
|
|
@@ -226,11 +226,13 @@ function envelope(r, toolVersion) {
|
|
|
226
226
|
return d;
|
|
227
227
|
}
|
|
228
228
|
|
|
229
|
-
function emit(r, toolVersion) {
|
|
230
|
-
|
|
229
|
+
function emit(r, toolVersion, schemaVersionOpt) {
|
|
230
|
+
let schemaVersion = schemaVersionOpt !== undefined ? schemaVersionOpt : defaultSchemaVersion;
|
|
231
|
+
process.stdout.write(JSON.stringify(envelope(r, toolVersion, schemaVersion), undefined, 2) + "\n");
|
|
231
232
|
}
|
|
232
233
|
|
|
233
|
-
function streamRunStart(toolVersion, startedAt) {
|
|
234
|
+
function streamRunStart(toolVersion, startedAt, schemaVersionOpt) {
|
|
235
|
+
let schemaVersion = schemaVersionOpt !== undefined ? schemaVersionOpt : defaultSchemaVersion;
|
|
234
236
|
let d = {};
|
|
235
237
|
d["type"] = "runStarted";
|
|
236
238
|
d["schemaVersion"] = schemaVersion;
|
|
@@ -299,7 +301,7 @@ function streamRunEnd(r) {
|
|
|
299
301
|
}
|
|
300
302
|
|
|
301
303
|
export {
|
|
302
|
-
|
|
304
|
+
defaultSchemaVersion,
|
|
303
305
|
write,
|
|
304
306
|
writeLine,
|
|
305
307
|
renderValue,
|
package/src/FormatterTap.res
CHANGED
|
@@ -18,59 +18,20 @@ let yamlLine = (~indent=2, key: string, value: string) =>
|
|
|
18
18
|
String.repeat(" ", indent) ++ key ++ ": " ++ value
|
|
19
19
|
|
|
20
20
|
let renderMismatchYaml = (m: Outcome.mismatch) => {
|
|
21
|
-
let
|
|
22
|
-
lines
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
21
|
+
let n = MismatchRender.normalize(m)
|
|
22
|
+
let lines = [yamlLine("kind", yamlString(n.kind))]
|
|
23
|
+
// `ExpectedNoEvents` is a Human-only literal (TAP simply omits `expected`);
|
|
24
|
+
// every other field maps to one yaml `key: "escaped-value"` line.
|
|
25
|
+
n.fields->Array.forEach(f =>
|
|
26
|
+
switch f {
|
|
27
|
+
| Expected(v) => lines->Array.push(yamlLine("expected", yamlString(v)))
|
|
28
|
+
| Actual(v) => lines->Array.push(yamlLine("actual", yamlString(v)))
|
|
29
|
+
| Key(k) => lines->Array.push(yamlLine("key", yamlString(k)))
|
|
30
|
+
| Error(e) => lines->Array.push(yamlLine("error", yamlString(e)))
|
|
31
|
+
| Stack(s) => lines->Array.push(yamlLine("stack", yamlString(s)))
|
|
32
|
+
| ExpectedNoEvents => ()
|
|
27
33
|
}
|
|
28
|
-
|
|
29
|
-
lines->Array.push(
|
|
30
|
-
yamlLine("expected", yamlString("Error(" ++ RenderRescript.render(expected) ++ ")")),
|
|
31
|
-
)
|
|
32
|
-
let actualStr = switch actual {
|
|
33
|
-
| Some(v) => "Error(" ++ RenderRescript.render(v) ++ ")"
|
|
34
|
-
| None => "Ok(" ++ RenderRescript.renderMany(actualEvents) ++ ")"
|
|
35
|
-
}
|
|
36
|
-
lines->Array.push(yamlLine("actual", yamlString(actualStr)))
|
|
37
|
-
}
|
|
38
|
-
| StateMismatch({key, expected, actual}) => {
|
|
39
|
-
lines->Array.push(yamlLine("key", yamlString(key)))
|
|
40
|
-
lines->Array.push(yamlLine("expected", yamlString(RenderRescript.renderOption(expected))))
|
|
41
|
-
lines->Array.push(yamlLine("actual", yamlString(RenderRescript.renderOption(actual))))
|
|
42
|
-
}
|
|
43
|
-
| NoEventExpected({actual}) =>
|
|
44
|
-
lines->Array.push(yamlLine("actual", yamlString(RenderRescript.renderMany(actual))))
|
|
45
|
-
| TodoMismatch({expected, actual}) => {
|
|
46
|
-
let fmt = arr =>
|
|
47
|
-
arr
|
|
48
|
-
->Array.map(((id, v)) => "(" ++ id ++ ", " ++ RenderRescript.render(v) ++ ")")
|
|
49
|
-
->Array.join(", ")
|
|
50
|
-
lines->Array.push(yamlLine("expected", yamlString("[" ++ fmt(expected) ++ "]")))
|
|
51
|
-
lines->Array.push(yamlLine("actual", yamlString("[" ++ fmt(actual) ++ "]")))
|
|
52
|
-
}
|
|
53
|
-
| AppendConditionMismatch({expected, actual}) => {
|
|
54
|
-
lines->Array.push(yamlLine("expected", yamlString(RenderRescript.render(expected))))
|
|
55
|
-
lines->Array.push(yamlLine("actual", yamlString(RenderRescript.render(actual))))
|
|
56
|
-
}
|
|
57
|
-
| TranslateError({expected, actual}) => {
|
|
58
|
-
lines->Array.push(yamlLine("expected", yamlString(expected)))
|
|
59
|
-
lines->Array.push(yamlLine("actual", yamlString(actual->Option.getOr("(none)"))))
|
|
60
|
-
}
|
|
61
|
-
| QueryRowsMismatch({expected, actual}) => {
|
|
62
|
-
lines->Array.push(yamlLine("expected", yamlString(RenderRescript.renderMany(expected))))
|
|
63
|
-
lines->Array.push(yamlLine("actual", yamlString(RenderRescript.renderMany(actual))))
|
|
64
|
-
}
|
|
65
|
-
| PublishedActionsMismatch({expected, actual}) => {
|
|
66
|
-
lines->Array.push(yamlLine("expected", yamlString(RenderRescript.renderMany(expected))))
|
|
67
|
-
lines->Array.push(yamlLine("actual", yamlString(RenderRescript.renderMany(actual))))
|
|
68
|
-
}
|
|
69
|
-
| Throw({error, stack}) => {
|
|
70
|
-
lines->Array.push(yamlLine("error", yamlString(error)))
|
|
71
|
-
lines->Array.push(yamlLine("stack", yamlString(stack)))
|
|
72
|
-
}
|
|
73
|
-
}
|
|
34
|
+
)
|
|
74
35
|
lines->Array.join("\n")
|
|
75
36
|
}
|
|
76
37
|
|
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,
|