@reventlessdev/reventless-gwt 1.0.0-alpha.115 → 1.0.0-alpha.116
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 +11 -0
- package/package.json +5 -12
- package/rescript.json +0 -1
- package/bin/reventless-dev.mjs +0 -21
- package/src/Bind.res +0 -29
- package/src/Bind.res.mjs +0 -22
- package/src/BuildClassifier.res +0 -147
- package/src/BuildClassifier.res.mjs +0 -136
- package/src/Cancellation.res +0 -37
- package/src/Cancellation.res.mjs +0 -46
- package/src/ChildProcess.res +0 -102
- package/src/ChildProcess.res.mjs +0 -107
- package/src/Cli.res +0 -889
- package/src/Cli.res.mjs +0 -944
- package/src/Collector.res +0 -222
- package/src/Collector.res.mjs +0 -228
- package/src/ComponentMeta.res +0 -77
- package/src/ComponentMeta.res.mjs +0 -91
- package/src/ComponentScan.res +0 -101
- package/src/ComponentScan.res.mjs +0 -92
- package/src/Discovery.res +0 -102
- package/src/Discovery.res.mjs +0 -86
- package/src/DomainDeadCode.res +0 -98
- package/src/DomainDeadCode.res.mjs +0 -72
- package/src/DomainGraph.res +0 -0
- package/src/DomainGraph.res.mjs +0 -0
- package/src/ExnMessage.res +0 -14
- package/src/ExnMessage.res.mjs +0 -17
- package/src/ExnReflect.mjs +0 -24
- package/src/Filter.res +0 -45
- package/src/Filter.res.mjs +0 -47
- package/src/FormatterHuman.res +0 -109
- package/src/FormatterHuman.res.mjs +0 -115
- package/src/FormatterJson.res +0 -264
- package/src/FormatterJson.res.mjs +0 -322
- package/src/FormatterJunit.res +0 -93
- package/src/FormatterJunit.res.mjs +0 -90
- package/src/FormatterTap.res +0 -100
- package/src/FormatterTap.res.mjs +0 -131
- package/src/FormatterVsCode.res +0 -352
- package/src/FormatterVsCode.res.mjs +0 -546
- package/src/Loader.res +0 -24
- package/src/Loader.res.mjs +0 -23
- package/src/PackageScan.res +0 -80
- package/src/PackageScan.res.mjs +0 -81
- package/src/PlatformRunner.res +0 -191
- package/src/PlatformRunner.res.mjs +0 -178
- package/src/PlatformScan.res +0 -141
- package/src/PlatformScan.res.mjs +0 -124
- package/src/ProcessManager.res +0 -135
- package/src/ProcessManager.res.mjs +0 -119
- package/src/RunWorker.res +0 -24
- package/src/RunWorker.res.mjs +0 -16
- package/src/RunnerTypes.res +0 -68
- package/src/RunnerTypes.res.mjs +0 -60
- package/src/ScanIgnore.res +0 -11
- package/src/ScanIgnore.res.mjs +0 -23
- package/src/Watch.res +0 -102
- package/src/Watch.res.mjs +0 -80
- package/src/WatcherProbe.res +0 -56
- package/src/WatcherProbe.res.mjs +0 -59
- package/src/Worker.res +0 -24
- package/src/Worker.res.mjs +0 -9
- package/tests/BuildClassifierTest.res +0 -133
- package/tests/BuildClassifierTest.res.mjs +0 -176
- package/tests/CliRunEntryTest.res +0 -57
- package/tests/CliRunEntryTest.res.mjs +0 -65
- package/tests/CliWatchScopeTest.res +0 -62
- package/tests/CliWatchScopeTest.res.mjs +0 -95
- package/tests/ComponentMetaTest.res +0 -67
- package/tests/ComponentMetaTest.res.mjs +0 -71
- package/tests/DiscoveryTest.res +0 -42
- package/tests/DiscoveryTest.res.mjs +0 -43
- package/tests/DomainDeadCodeTest.res +0 -119
- package/tests/DomainDeadCodeTest.res.mjs +0 -158
- package/tests/DomainGraphTest.res +0 -448
- package/tests/DomainGraphTest.res.mjs +0 -505
- package/tests/ExnMessageTest.res +0 -42
- package/tests/ExnMessageTest.res.mjs +0 -64
- package/tests/FormatterGoldenTest.res +0 -125
- package/tests/FormatterGoldenTest.res.mjs +0 -162
- package/tests/FormatterVsCodeMessageTest.res +0 -41
- package/tests/FormatterVsCodeMessageTest.res.mjs +0 -42
- package/tests/PlatformRunnerTest.res +0 -66
- package/tests/PlatformRunnerTest.res.mjs +0 -85
- package/tests/PlatformScanTest.res +0 -61
- package/tests/PlatformScanTest.res.mjs +0 -56
- package/tests/RunnerUnitTest.res +0 -219
- package/tests/RunnerUnitTest.res.mjs +0 -244
- package/tests/WatchDebounceTest.res +0 -106
- package/tests/WatchDebounceTest.res.mjs +0 -128
package/src/Filter.res.mjs
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
-
|
|
3
|
-
import * as Outcome$ReventlessGwt from "./Outcome.res.mjs";
|
|
4
|
-
import * as Collector$ReventlessGwt from "./Collector.res.mjs";
|
|
5
|
-
|
|
6
|
-
function skip() {
|
|
7
|
-
Collector$ReventlessGwt.markSkipNext();
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
function only() {
|
|
11
|
-
Collector$ReventlessGwt.markOnlyNext();
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function xtest(param, name, _body) {
|
|
15
|
-
if (Collector$ReventlessGwt.isActive()) {
|
|
16
|
-
Collector$ReventlessGwt.markSkipNext();
|
|
17
|
-
return Collector$ReventlessGwt.push(undefined, undefined, undefined, name, () => Promise.resolve(Outcome$ReventlessGwt.pass));
|
|
18
|
-
} else {
|
|
19
|
-
globalThis.xtest(name, () => {});
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function xdescribe(label, body) {
|
|
25
|
-
if (Collector$ReventlessGwt.isActive()) {
|
|
26
|
-
Collector$ReventlessGwt.skipDepth.contents = Collector$ReventlessGwt.skipDepth.contents + 1 | 0;
|
|
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
|
-
}
|
|
35
|
-
} else {
|
|
36
|
-
globalThis.xdescribe(label, body);
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export {
|
|
42
|
-
skip,
|
|
43
|
-
only,
|
|
44
|
-
xtest,
|
|
45
|
-
xdescribe,
|
|
46
|
-
}
|
|
47
|
-
/* No side effect */
|
package/src/FormatterHuman.res
DELETED
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
// Terminal-coloured human formatter. Shipped as the default output for
|
|
2
|
-
// `reventless-gwt run`. Uses picocolors for ANSI colours — it is a tiny
|
|
3
|
-
// zero-dependency helper that transparently disables colour when stdout
|
|
4
|
-
// is not a TTY.
|
|
5
|
-
|
|
6
|
-
type colour = string => string
|
|
7
|
-
type picocolors = {
|
|
8
|
-
red: colour,
|
|
9
|
-
green: colour,
|
|
10
|
-
yellow: colour,
|
|
11
|
-
cyan: colour,
|
|
12
|
-
gray: colour,
|
|
13
|
-
bold: colour,
|
|
14
|
-
dim: colour,
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
@module("picocolors") external pc: picocolors = "default"
|
|
18
|
-
|
|
19
|
-
@val external processStdout: {"write": string => unit} = "process.stdout"
|
|
20
|
-
@val external processCwd: unit => string = "process.cwd"
|
|
21
|
-
@module("node:path") external pathBasename: string => string = "basename"
|
|
22
|
-
@module("node:path") external pathRelative: (string, string) => string = "relative"
|
|
23
|
-
|
|
24
|
-
let write = (s: string) => processStdout["write"](s)
|
|
25
|
-
let writeLine = (s: string) => write(s ++ "\n")
|
|
26
|
-
|
|
27
|
-
let formatFilePath = (abs: string) => {
|
|
28
|
-
let base = pathBasename(abs)
|
|
29
|
-
let name = if String.endsWith(base, ".res.mjs") {
|
|
30
|
-
String.slice(base, ~start=0, ~end=String.length(base) - 8)
|
|
31
|
-
} else {
|
|
32
|
-
base
|
|
33
|
-
}
|
|
34
|
-
let rel = pathRelative(processCwd(), abs)
|
|
35
|
-
`${name} - ${rel}`
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
let formatLocation = (loc: option<Collector.location>) =>
|
|
39
|
-
switch loc {
|
|
40
|
-
| None => ""
|
|
41
|
-
| Some(l) => `${l.file}:${Int.toString(l.line)}`
|
|
42
|
-
}
|
|
43
|
-
|
|
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
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
let renderMismatch = (m: Outcome.mismatch) =>
|
|
58
|
-
MismatchRender.normalize(m).fields->Array.map(renderField)->Array.join("\n")
|
|
59
|
-
|
|
60
|
-
let emitTest = (t: RunnerTypes.testResult) => {
|
|
61
|
-
let path = t.describePath->Array.join(" > ")
|
|
62
|
-
let full = path == "" ? t.name : `${path} > ${t.name}`
|
|
63
|
-
let loc = formatLocation(t.location)
|
|
64
|
-
let locStr = loc == "" ? "" : ` ${pc.dim(loc)}`
|
|
65
|
-
switch t.status {
|
|
66
|
-
| Pass => writeLine(` ${pc.green("✓")} ${full}${locStr}`)
|
|
67
|
-
| Skip =>
|
|
68
|
-
writeLine(
|
|
69
|
-
` ${pc.yellow("○")} ${full}${locStr} ${pc.dim(
|
|
70
|
-
t.skipReason->Option.getOr("skipped"),
|
|
71
|
-
)}`,
|
|
72
|
-
)
|
|
73
|
-
| Fail => {
|
|
74
|
-
writeLine(` ${pc.red("✗")} ${pc.bold(full)}${locStr}`)
|
|
75
|
-
switch t.mismatch {
|
|
76
|
-
| Some(m) => {
|
|
77
|
-
writeLine("")
|
|
78
|
-
writeLine(renderMismatch(m))
|
|
79
|
-
let hint = Hint.forMismatch(~slice=?t.slice, m)
|
|
80
|
-
writeLine("")
|
|
81
|
-
writeLine(` ${pc.cyan(Hint.format(hint))}`)
|
|
82
|
-
writeLine("")
|
|
83
|
-
}
|
|
84
|
-
| None => ()
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
let emitFile = (f: RunnerTypes.fileResult) => {
|
|
91
|
-
writeLine("")
|
|
92
|
-
writeLine(pc.bold(formatFilePath(f.path)))
|
|
93
|
-
f.tests->Array.forEach(emitTest)
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
let emitSummary = (s: RunnerTypes.summary) => {
|
|
97
|
-
writeLine("")
|
|
98
|
-
let line = `Tests: ${Int.toString(s.total)} ${pc.green(
|
|
99
|
-
Int.toString(s.passed) ++ " passed",
|
|
100
|
-
)} ${pc.red(Int.toString(s.failed) ++ " failed")} ${pc.yellow(
|
|
101
|
-
Int.toString(s.skipped) ++ " skipped",
|
|
102
|
-
)} (${Float.toString(s.durationMs)} ms)`
|
|
103
|
-
writeLine(line)
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
let emit = (r: RunnerTypes.runResult) => {
|
|
107
|
-
r.files->Array.forEach(emitFile)
|
|
108
|
-
emitSummary(r.summary)
|
|
109
|
-
}
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
-
|
|
3
|
-
import * as Nodepath from "node:path";
|
|
4
|
-
import Picocolors from "picocolors";
|
|
5
|
-
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
6
|
-
import * as Hint$ReventlessGwt from "./Hint.res.mjs";
|
|
7
|
-
import * as MismatchRender$ReventlessGwt from "./MismatchRender.res.mjs";
|
|
8
|
-
|
|
9
|
-
function write(s) {
|
|
10
|
-
process.stdout.write(s);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function writeLine(s) {
|
|
14
|
-
process.stdout.write(s + "\n");
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function formatFilePath(abs) {
|
|
18
|
-
let base = Nodepath.basename(abs);
|
|
19
|
-
let name = base.endsWith(".res.mjs") ? base.slice(0, base.length - 8 | 0) : base;
|
|
20
|
-
let rel = Nodepath.relative(process.cwd(), abs);
|
|
21
|
-
return name + ` - ` + rel;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function formatLocation(loc) {
|
|
25
|
-
if (loc !== undefined) {
|
|
26
|
-
return loc.file + `:` + loc.line.toString();
|
|
27
|
-
} else {
|
|
28
|
-
return "";
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
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;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function renderMismatch(m) {
|
|
51
|
-
return MismatchRender$ReventlessGwt.normalize(m).fields.map(renderField).join("\n");
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function emitTest(t) {
|
|
55
|
-
let path = t.describePath.join(" > ");
|
|
56
|
-
let full = path === "" ? t.name : path + ` > ` + t.name;
|
|
57
|
-
let loc = formatLocation(t.location);
|
|
58
|
-
let locStr = loc === "" ? "" : ` ` + Picocolors.dim(loc);
|
|
59
|
-
let match = t.status;
|
|
60
|
-
switch (match) {
|
|
61
|
-
case "Pass" :
|
|
62
|
-
let s = ` ` + Picocolors.green("✓") + ` ` + full + locStr;
|
|
63
|
-
return process.stdout.write(s + "\n");
|
|
64
|
-
case "Fail" :
|
|
65
|
-
let s$1 = ` ` + Picocolors.red("✗") + ` ` + Picocolors.bold(full) + locStr;
|
|
66
|
-
process.stdout.write(s$1 + "\n");
|
|
67
|
-
let m = t.mismatch;
|
|
68
|
-
if (m === undefined) {
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
process.stdout.write("\n");
|
|
72
|
-
let s$2 = renderMismatch(m);
|
|
73
|
-
process.stdout.write(s$2 + "\n");
|
|
74
|
-
let hint = Hint$ReventlessGwt.forMismatch(t.slice, m);
|
|
75
|
-
process.stdout.write("\n");
|
|
76
|
-
let s$3 = ` ` + Picocolors.cyan(Hint$ReventlessGwt.format(hint));
|
|
77
|
-
process.stdout.write(s$3 + "\n");
|
|
78
|
-
return process.stdout.write("\n");
|
|
79
|
-
case "Skip" :
|
|
80
|
-
let s$4 = ` ` + Picocolors.yellow("○") + ` ` + full + locStr + ` ` + Picocolors.dim(Stdlib_Option.getOr(t.skipReason, "skipped"));
|
|
81
|
-
return process.stdout.write(s$4 + "\n");
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function emitFile(f) {
|
|
86
|
-
process.stdout.write("\n");
|
|
87
|
-
let s = Picocolors.bold(formatFilePath(f.path));
|
|
88
|
-
process.stdout.write(s + "\n");
|
|
89
|
-
f.tests.forEach(emitTest);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function emitSummary(s) {
|
|
93
|
-
process.stdout.write("\n");
|
|
94
|
-
let s$1 = `Tests: ` + s.total.toString() + ` ` + Picocolors.green(s.passed.toString() + " passed") + ` ` + Picocolors.red(s.failed.toString() + " failed") + ` ` + Picocolors.yellow(s.skipped.toString() + " skipped") + ` (` + s.durationMs.toString() + ` ms)`;
|
|
95
|
-
process.stdout.write(s$1 + "\n");
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
function emit(r) {
|
|
99
|
-
r.files.forEach(emitFile);
|
|
100
|
-
emitSummary(r.summary);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
export {
|
|
104
|
-
write,
|
|
105
|
-
writeLine,
|
|
106
|
-
formatFilePath,
|
|
107
|
-
formatLocation,
|
|
108
|
-
renderField,
|
|
109
|
-
renderMismatch,
|
|
110
|
-
emitTest,
|
|
111
|
-
emitFile,
|
|
112
|
-
emitSummary,
|
|
113
|
-
emit,
|
|
114
|
-
}
|
|
115
|
-
/* node:path Not a pure module */
|
package/src/FormatterJson.res
DELETED
|
@@ -1,264 +0,0 @@
|
|
|
1
|
-
// Structured JSON formatter — the AI loop's primary input and the substrate
|
|
2
|
-
// for any programmatic consumer. Ships both a single-envelope mode and an
|
|
3
|
-
// NDJSON streaming mode (`--stream`). Shape matches §3.3 of
|
|
4
|
-
// `docs/analysis/given-when-then-specifications.md`.
|
|
5
|
-
|
|
6
|
-
// 1.1.0 — additive: `PublishedActionsMismatch` mismatch kind for the
|
|
7
|
-
// Delegate_GWT / cross-plugin Flow_GWT boundary steps.
|
|
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"
|
|
12
|
-
|
|
13
|
-
@val external processStdout: {"write": string => unit} = "process.stdout"
|
|
14
|
-
let write = (s: string) => processStdout["write"](s)
|
|
15
|
-
let writeLine = (s: string) => write(s ++ "\n")
|
|
16
|
-
|
|
17
|
-
// Re-render a JSON value as a dual-rendered `{type, payload, rendered}` entry.
|
|
18
|
-
let renderValue = (j: JSON.t): JSON.t => {
|
|
19
|
-
let obj = Dict.make()
|
|
20
|
-
switch j {
|
|
21
|
-
| Object(dict) =>
|
|
22
|
-
switch dict->Dict.get("TAG") {
|
|
23
|
-
| Some(String(tag)) => {
|
|
24
|
-
obj->Dict.set("type", JSON.Encode.string(tag))
|
|
25
|
-
let payloadKeys =
|
|
26
|
-
dict
|
|
27
|
-
->Dict.keysToArray
|
|
28
|
-
->Array.filter(k => k != "TAG" && String.startsWith(k, "_"))
|
|
29
|
-
let payload = switch payloadKeys {
|
|
30
|
-
| [] => JSON.Encode.null
|
|
31
|
-
| ["_0"] =>
|
|
32
|
-
dict->Dict.get("_0")->Option.getOr(JSON.Encode.null)
|
|
33
|
-
| _ => {
|
|
34
|
-
let payloadDict = Dict.make()
|
|
35
|
-
payloadKeys->Array.forEach(k =>
|
|
36
|
-
payloadDict->Dict.set(
|
|
37
|
-
k,
|
|
38
|
-
dict->Dict.get(k)->Option.getOr(JSON.Encode.null),
|
|
39
|
-
)
|
|
40
|
-
)
|
|
41
|
-
JSON.Encode.object(payloadDict)
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
obj->Dict.set("payload", payload)
|
|
45
|
-
}
|
|
46
|
-
| _ => {
|
|
47
|
-
obj->Dict.set("type", JSON.Encode.null)
|
|
48
|
-
obj->Dict.set("payload", j)
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
| String(s) => {
|
|
52
|
-
obj->Dict.set("type", JSON.Encode.string(s))
|
|
53
|
-
obj->Dict.set("payload", JSON.Encode.null)
|
|
54
|
-
}
|
|
55
|
-
| _ => {
|
|
56
|
-
obj->Dict.set("type", JSON.Encode.null)
|
|
57
|
-
obj->Dict.set("payload", j)
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
obj->Dict.set("rendered", JSON.Encode.string(RenderRescript.render(j)))
|
|
61
|
-
JSON.Encode.object(obj)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
let renderValues = (arr: array<JSON.t>): JSON.t =>
|
|
65
|
-
arr->Array.map(renderValue)->JSON.Encode.array
|
|
66
|
-
|
|
67
|
-
let mismatchJson = (m: Outcome.mismatch, slice: option<string>): JSON.t => {
|
|
68
|
-
let obj = Dict.make()
|
|
69
|
-
obj->Dict.set("kind", JSON.Encode.string(Outcome.kindName(m)))
|
|
70
|
-
let optVal = o =>
|
|
71
|
-
switch o {
|
|
72
|
-
| Some(v) => renderValue(v)
|
|
73
|
-
| None => JSON.Encode.null
|
|
74
|
-
}
|
|
75
|
-
switch m {
|
|
76
|
-
| EventsMismatch({expected, actual}) => {
|
|
77
|
-
obj->Dict.set("expected", renderValues(expected))
|
|
78
|
-
obj->Dict.set("actual", renderValues(actual))
|
|
79
|
-
obj->Dict.set("fieldDiff", Diff.toJsonArray(Diff.diffArrays(expected, actual)))
|
|
80
|
-
}
|
|
81
|
-
| ErrorMismatch({expected, actual, actualEvents}) => {
|
|
82
|
-
obj->Dict.set("expected", renderValue(expected))
|
|
83
|
-
obj->Dict.set("actual", optVal(actual))
|
|
84
|
-
obj->Dict.set("actualEvents", renderValues(actualEvents))
|
|
85
|
-
}
|
|
86
|
-
| StateMismatch({key, expected, actual}) => {
|
|
87
|
-
obj->Dict.set("key", JSON.Encode.string(key))
|
|
88
|
-
obj->Dict.set("expected", optVal(expected))
|
|
89
|
-
obj->Dict.set("actual", optVal(actual))
|
|
90
|
-
let eJson = expected->Option.getOr(JSON.Encode.null)
|
|
91
|
-
let aJson = actual->Option.getOr(JSON.Encode.null)
|
|
92
|
-
obj->Dict.set("fieldDiff", Diff.toJsonArray(Diff.diff(eJson, aJson)))
|
|
93
|
-
}
|
|
94
|
-
| NoEventExpected({actual}) => obj->Dict.set("actual", renderValues(actual))
|
|
95
|
-
| TodoMismatch({expected, actual}) => {
|
|
96
|
-
let pairArr = pairs =>
|
|
97
|
-
pairs
|
|
98
|
-
->Array.map(((id, v)) => {
|
|
99
|
-
let d = Dict.make()
|
|
100
|
-
d->Dict.set("id", JSON.Encode.string(id))
|
|
101
|
-
d->Dict.set("value", renderValue(v))
|
|
102
|
-
JSON.Encode.object(d)
|
|
103
|
-
})
|
|
104
|
-
->JSON.Encode.array
|
|
105
|
-
obj->Dict.set("expected", pairArr(expected))
|
|
106
|
-
obj->Dict.set("actual", pairArr(actual))
|
|
107
|
-
}
|
|
108
|
-
| AppendConditionMismatch({expected, actual}) => {
|
|
109
|
-
obj->Dict.set("expected", expected)
|
|
110
|
-
obj->Dict.set("actual", actual)
|
|
111
|
-
}
|
|
112
|
-
| TranslateError({expected, actual}) => {
|
|
113
|
-
obj->Dict.set("expected", JSON.Encode.string(expected))
|
|
114
|
-
obj->Dict.set(
|
|
115
|
-
"actual",
|
|
116
|
-
actual->Option.mapOr(JSON.Encode.null, JSON.Encode.string),
|
|
117
|
-
)
|
|
118
|
-
}
|
|
119
|
-
| QueryRowsMismatch({expected, actual}) => {
|
|
120
|
-
obj->Dict.set("expected", renderValues(expected))
|
|
121
|
-
obj->Dict.set("actual", renderValues(actual))
|
|
122
|
-
obj->Dict.set("fieldDiff", Diff.toJsonArray(Diff.diffArrays(expected, actual)))
|
|
123
|
-
}
|
|
124
|
-
| PublishedActionsMismatch({expected, actual}) => {
|
|
125
|
-
obj->Dict.set("expected", renderValues(expected))
|
|
126
|
-
obj->Dict.set("actual", renderValues(actual))
|
|
127
|
-
obj->Dict.set("fieldDiff", Diff.toJsonArray(Diff.diffArrays(expected, actual)))
|
|
128
|
-
}
|
|
129
|
-
| Throw({error, stack}) => {
|
|
130
|
-
obj->Dict.set("error", JSON.Encode.string(error))
|
|
131
|
-
obj->Dict.set("stack", JSON.Encode.string(stack))
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
let hint = Hint.forMismatch(~slice?, m)
|
|
135
|
-
obj->Dict.set("hint", Hint.toJson(hint))
|
|
136
|
-
JSON.Encode.object(obj)
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
let locationJson = (loc: option<Collector.location>): JSON.t =>
|
|
140
|
-
switch loc {
|
|
141
|
-
| None => JSON.Encode.null
|
|
142
|
-
| Some(l) => {
|
|
143
|
-
let d = Dict.make()
|
|
144
|
-
d->Dict.set("file", JSON.Encode.string(l.file))
|
|
145
|
-
d->Dict.set("line", JSON.Encode.int(l.line))
|
|
146
|
-
d->Dict.set("column", JSON.Encode.int(l.column))
|
|
147
|
-
JSON.Encode.object(d)
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
let testJson = (t: RunnerTypes.testResult): JSON.t => {
|
|
152
|
-
let d = Dict.make()
|
|
153
|
-
d->Dict.set("id", JSON.Encode.string(t.id))
|
|
154
|
-
d->Dict.set("name", JSON.Encode.string(t.name))
|
|
155
|
-
d->Dict.set(
|
|
156
|
-
"describePath",
|
|
157
|
-
t.describePath->Array.map(JSON.Encode.string)->JSON.Encode.array,
|
|
158
|
-
)
|
|
159
|
-
d->Dict.set("status", JSON.Encode.string(RunnerTypes.statusString(t.status)))
|
|
160
|
-
d->Dict.set("durationMs", JSON.Encode.float(t.durationMs))
|
|
161
|
-
d->Dict.set("location", locationJson(t.location))
|
|
162
|
-
switch t.mismatch {
|
|
163
|
-
| Some(m) => d->Dict.set("mismatch", mismatchJson(m, t.slice))
|
|
164
|
-
| None => ()
|
|
165
|
-
}
|
|
166
|
-
switch t.skipReason {
|
|
167
|
-
| Some(r) => d->Dict.set("skipReason", JSON.Encode.string(r))
|
|
168
|
-
| None => ()
|
|
169
|
-
}
|
|
170
|
-
JSON.Encode.object(d)
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
let fileJson = (f: RunnerTypes.fileResult): JSON.t => {
|
|
174
|
-
let d = Dict.make()
|
|
175
|
-
d->Dict.set("path", JSON.Encode.string(f.path))
|
|
176
|
-
d->Dict.set("tests", f.tests->Array.map(testJson)->JSON.Encode.array)
|
|
177
|
-
JSON.Encode.object(d)
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
let summaryJson = (s: RunnerTypes.summary): JSON.t => {
|
|
181
|
-
let d = Dict.make()
|
|
182
|
-
d->Dict.set("total", JSON.Encode.int(s.total))
|
|
183
|
-
d->Dict.set("passed", JSON.Encode.int(s.passed))
|
|
184
|
-
d->Dict.set("failed", JSON.Encode.int(s.failed))
|
|
185
|
-
d->Dict.set("skipped", JSON.Encode.int(s.skipped))
|
|
186
|
-
d->Dict.set("files", JSON.Encode.int(s.files))
|
|
187
|
-
JSON.Encode.object(d)
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
let envelope = (
|
|
191
|
-
r: RunnerTypes.runResult,
|
|
192
|
-
~toolVersion: string,
|
|
193
|
-
~schemaVersion: string,
|
|
194
|
-
): JSON.t => {
|
|
195
|
-
let d = Dict.make()
|
|
196
|
-
d->Dict.set("schemaVersion", JSON.Encode.string(schemaVersion))
|
|
197
|
-
d->Dict.set("tool", JSON.Encode.string("reventless-gwt"))
|
|
198
|
-
d->Dict.set("toolVersion", JSON.Encode.string(toolVersion))
|
|
199
|
-
d->Dict.set("startedAt", JSON.Encode.string(r.summary.startedAt))
|
|
200
|
-
d->Dict.set("durationMs", JSON.Encode.float(r.summary.durationMs))
|
|
201
|
-
d->Dict.set("summary", summaryJson(r.summary))
|
|
202
|
-
d->Dict.set("files", r.files->Array.map(fileJson)->JSON.Encode.array)
|
|
203
|
-
JSON.Encode.object(d)
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
let emit = (r: RunnerTypes.runResult, ~toolVersion: string, ~schemaVersion=defaultSchemaVersion) =>
|
|
207
|
-
write(JSON.stringify(envelope(r, ~toolVersion, ~schemaVersion), ~space=2) ++ "\n")
|
|
208
|
-
|
|
209
|
-
// Streaming variant — NDJSON events.
|
|
210
|
-
let streamRunStart = (~toolVersion: string, ~startedAt: string, ~schemaVersion=defaultSchemaVersion) => {
|
|
211
|
-
let d = Dict.make()
|
|
212
|
-
d->Dict.set("type", JSON.Encode.string("runStarted"))
|
|
213
|
-
d->Dict.set("schemaVersion", JSON.Encode.string(schemaVersion))
|
|
214
|
-
d->Dict.set("toolVersion", JSON.Encode.string(toolVersion))
|
|
215
|
-
d->Dict.set("at", JSON.Encode.string(startedAt))
|
|
216
|
-
writeLine(JSON.stringify(JSON.Encode.object(d)))
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
let streamFileStart = (path: string) => {
|
|
220
|
-
let d = Dict.make()
|
|
221
|
-
d->Dict.set("type", JSON.Encode.string("fileStarted"))
|
|
222
|
-
d->Dict.set("path", JSON.Encode.string(path))
|
|
223
|
-
writeLine(JSON.stringify(JSON.Encode.object(d)))
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
let streamTest = (t: RunnerTypes.testResult) => {
|
|
227
|
-
let d = Dict.make()
|
|
228
|
-
d->Dict.set("type", JSON.Encode.string("testResult"))
|
|
229
|
-
let tj = testJson(t)
|
|
230
|
-
// Fold testJson's object keys into the envelope.
|
|
231
|
-
switch tj {
|
|
232
|
-
| Object(inner) =>
|
|
233
|
-
inner->Dict.keysToArray->Array.forEach(k =>
|
|
234
|
-
d->Dict.set(k, inner->Dict.getUnsafe(k))
|
|
235
|
-
)
|
|
236
|
-
| _ => ()
|
|
237
|
-
}
|
|
238
|
-
writeLine(JSON.stringify(JSON.Encode.object(d)))
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
let streamFileFinished = (f: RunnerTypes.fileResult) => {
|
|
242
|
-
let passed = ref(0)
|
|
243
|
-
let failed = ref(0)
|
|
244
|
-
f.tests->Array.forEach(t =>
|
|
245
|
-
switch t.status {
|
|
246
|
-
| Pass => passed := passed.contents + 1
|
|
247
|
-
| Fail => failed := failed.contents + 1
|
|
248
|
-
| Skip => ()
|
|
249
|
-
}
|
|
250
|
-
)
|
|
251
|
-
let d = Dict.make()
|
|
252
|
-
d->Dict.set("type", JSON.Encode.string("fileFinished"))
|
|
253
|
-
d->Dict.set("path", JSON.Encode.string(f.path))
|
|
254
|
-
d->Dict.set("passed", JSON.Encode.int(passed.contents))
|
|
255
|
-
d->Dict.set("failed", JSON.Encode.int(failed.contents))
|
|
256
|
-
writeLine(JSON.stringify(JSON.Encode.object(d)))
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
let streamRunEnd = (r: RunnerTypes.runResult) => {
|
|
260
|
-
let d = Dict.make()
|
|
261
|
-
d->Dict.set("type", JSON.Encode.string("runFinished"))
|
|
262
|
-
d->Dict.set("summary", summaryJson(r.summary))
|
|
263
|
-
writeLine(JSON.stringify(JSON.Encode.object(d)))
|
|
264
|
-
}
|