@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/Cli.res.mjs
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
|
+
import * as Nodepath from "node:path";
|
|
4
|
+
import * as Nodecrypto from "node:crypto";
|
|
3
5
|
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
4
6
|
import * as Stdlib_JsExn from "@rescript/runtime/lib/es6/Stdlib_JsExn.js";
|
|
5
7
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
8
|
+
import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
|
|
9
|
+
import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
|
|
6
10
|
import * as Watch$ReventlessGwt from "./Watch.res.mjs";
|
|
11
|
+
import * as Nodeworker_threads from "node:worker_threads";
|
|
7
12
|
import * as Loader$ReventlessGwt from "./Loader.res.mjs";
|
|
8
13
|
import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
|
|
14
|
+
import * as Worker$ReventlessGwt from "./Worker.res.mjs";
|
|
9
15
|
import * as Outcome$ReventlessGwt from "./Outcome.res.mjs";
|
|
10
16
|
import * as Collector$ReventlessGwt from "./Collector.res.mjs";
|
|
11
17
|
import * as Discovery$ReventlessGwt from "./Discovery.res.mjs";
|
|
@@ -30,6 +36,14 @@ import * as Platform_ComponentDefinitionsApi$ReventlessCore from "@reventlessdev
|
|
|
30
36
|
|
|
31
37
|
let toolVersion = "0.1.0";
|
|
32
38
|
|
|
39
|
+
function sha256(s) {
|
|
40
|
+
return Nodecrypto.createHash("sha256").update(s).digest("hex");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
let lastDomainHash = {
|
|
44
|
+
contents: undefined
|
|
45
|
+
};
|
|
46
|
+
|
|
33
47
|
let dateNowIso = (() => new Date().toISOString());
|
|
34
48
|
|
|
35
49
|
function parseFormat(s) {
|
|
@@ -291,7 +305,8 @@ Exit code is 1 if any test failed, 0 otherwise.
|
|
|
291
305
|
backend: backend,
|
|
292
306
|
uiPorts: uiPorts,
|
|
293
307
|
listPlatforms: listPlatforms,
|
|
294
|
-
toolVersion: toolVersion
|
|
308
|
+
toolVersion: toolVersion,
|
|
309
|
+
paths: undefined
|
|
295
310
|
}
|
|
296
311
|
};
|
|
297
312
|
}
|
|
@@ -317,6 +332,29 @@ let exnMessage = (function(e) {
|
|
|
317
332
|
return "unknown error"
|
|
318
333
|
});
|
|
319
334
|
|
|
335
|
+
function raceWithTimeout(body, ms) {
|
|
336
|
+
let handleRef = {
|
|
337
|
+
contents: undefined
|
|
338
|
+
};
|
|
339
|
+
let timeout = new Promise((resolve, _reject) => {
|
|
340
|
+
handleRef.contents = Primitive_option.some(setTimeout(() => resolve(Outcome$ReventlessGwt.fail({
|
|
341
|
+
TAG: "Throw",
|
|
342
|
+
error: `timed out after ` + ms.toString() + `ms`,
|
|
343
|
+
stack: ""
|
|
344
|
+
})), ms));
|
|
345
|
+
});
|
|
346
|
+
return Promise.race([
|
|
347
|
+
body(),
|
|
348
|
+
timeout
|
|
349
|
+
]).then(o => {
|
|
350
|
+
let h = handleRef.contents;
|
|
351
|
+
if (h !== undefined) {
|
|
352
|
+
clearTimeout(Primitive_option.valFromOption(h));
|
|
353
|
+
}
|
|
354
|
+
return Promise.resolve(o);
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
|
|
320
358
|
async function runEntry(entry) {
|
|
321
359
|
let start = performance.now();
|
|
322
360
|
let status = "Pass";
|
|
@@ -334,7 +372,8 @@ async function runEntry(entry) {
|
|
|
334
372
|
}
|
|
335
373
|
if (exit === 1) {
|
|
336
374
|
try {
|
|
337
|
-
let
|
|
375
|
+
let deadline = Stdlib_Option.getOr(entry.timeout, 5000);
|
|
376
|
+
let outcome = await raceWithTimeout(entry.body, deadline);
|
|
338
377
|
if (outcome.TAG === "Ok") {
|
|
339
378
|
status = "Pass";
|
|
340
379
|
} else {
|
|
@@ -375,7 +414,7 @@ async function loadAndCollect(path) {
|
|
|
375
414
|
} catch (raw_exn) {
|
|
376
415
|
let exn = Primitive_exceptions.internalToException(raw_exn);
|
|
377
416
|
let msg = Stdlib_Option.getOr(Stdlib_Option.flatMap(Stdlib_JsExn.fromException(exn), Stdlib_JsExn.message), "import failed");
|
|
378
|
-
Collector$ReventlessGwt.push(undefined, undefined, `<file-load-error>`, () => Promise.resolve(Outcome$ReventlessGwt.fail({
|
|
417
|
+
Collector$ReventlessGwt.push(undefined, undefined, undefined, `<file-load-error>`, () => Promise.resolve(Outcome$ReventlessGwt.fail({
|
|
379
418
|
TAG: "Throw",
|
|
380
419
|
error: "Failed to load " + path + ": " + msg,
|
|
381
420
|
stack: ""
|
|
@@ -469,7 +508,7 @@ function emitResult(opts, r) {
|
|
|
469
508
|
if (opts.stream) {
|
|
470
509
|
return FormatterJson$ReventlessGwt.streamRunEnd(r);
|
|
471
510
|
} else {
|
|
472
|
-
return FormatterJson$ReventlessGwt.emit(r, opts.toolVersion);
|
|
511
|
+
return FormatterJson$ReventlessGwt.emit(r, opts.toolVersion, opts.schemaVersion);
|
|
473
512
|
}
|
|
474
513
|
case "Tap" :
|
|
475
514
|
return FormatterTap$ReventlessGwt.emit(r);
|
|
@@ -480,10 +519,48 @@ function emitResult(opts, r) {
|
|
|
480
519
|
}
|
|
481
520
|
}
|
|
482
521
|
|
|
522
|
+
function mergeScope(a, b) {
|
|
523
|
+
if (typeof a !== "object") {
|
|
524
|
+
return "RunAll";
|
|
525
|
+
}
|
|
526
|
+
if (typeof b !== "object") {
|
|
527
|
+
return "RunAll";
|
|
528
|
+
}
|
|
529
|
+
let seen = {};
|
|
530
|
+
let union = [];
|
|
531
|
+
a._0.concat(b._0).forEach(d => {
|
|
532
|
+
let match = seen[d];
|
|
533
|
+
if (match !== undefined) {
|
|
534
|
+
return;
|
|
535
|
+
} else {
|
|
536
|
+
seen[d] = true;
|
|
537
|
+
union.push(d);
|
|
538
|
+
return;
|
|
539
|
+
}
|
|
540
|
+
});
|
|
541
|
+
return {
|
|
542
|
+
TAG: "RunPackages",
|
|
543
|
+
_0: union
|
|
544
|
+
};
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
function pathUnderDir(path, dir) {
|
|
548
|
+
return path.startsWith(dir.endsWith("/") ? dir : dir + "/");
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
function scopeSubset(scope, allPaths) {
|
|
552
|
+
if (typeof scope !== "object") {
|
|
553
|
+
return allPaths;
|
|
554
|
+
}
|
|
555
|
+
let dirs = scope._0;
|
|
556
|
+
return allPaths.filter(p => dirs.some(d => pathUnderDir(p, d)));
|
|
557
|
+
}
|
|
558
|
+
|
|
483
559
|
async function runOnce(opts) {
|
|
484
|
-
let
|
|
560
|
+
let p = opts.paths;
|
|
561
|
+
let paths = p !== undefined ? p : await Discovery$ReventlessGwt.discover(opts.roots);
|
|
485
562
|
if (opts.format === "Json" && opts.stream) {
|
|
486
|
-
FormatterJson$ReventlessGwt.streamRunStart(opts.toolVersion, dateNowIso());
|
|
563
|
+
FormatterJson$ReventlessGwt.streamRunStart(opts.toolVersion, dateNowIso(), opts.schemaVersion);
|
|
487
564
|
}
|
|
488
565
|
let match = opts.format;
|
|
489
566
|
let match$1 = opts.stream;
|
|
@@ -530,9 +607,16 @@ async function emitDomainAnalysis(pkgs) {
|
|
|
530
607
|
}
|
|
531
608
|
try {
|
|
532
609
|
let loaded = await LocalHost$ReventlessGwt.loadGraph(platformModulePath, plugins);
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
610
|
+
let definitions = loaded.structures.map(param => Platform_ComponentDefinitionsApi$ReventlessCore.encodePluginStructureEntry(param[0], param[1]));
|
|
611
|
+
let fingerprint = sha256(JSON.stringify(definitions));
|
|
612
|
+
if (Primitive_object.notequal(lastDomainHash.contents, fingerprint)) {
|
|
613
|
+
lastDomainHash.contents = fingerprint;
|
|
614
|
+
FormatterVsCode$ReventlessGwt.deadCode(DomainDeadCode$ReventlessGwt.analyze(loaded.structures));
|
|
615
|
+
FormatterVsCode$ReventlessGwt.graph(DomainGraph$ReventlessGwt.build(loaded.structures));
|
|
616
|
+
return FormatterVsCode$ReventlessGwt.definitions(definitions);
|
|
617
|
+
} else {
|
|
618
|
+
return;
|
|
619
|
+
}
|
|
536
620
|
} catch (exn) {
|
|
537
621
|
return;
|
|
538
622
|
}
|
|
@@ -593,55 +677,160 @@ function startBuildWatchers(paths) {
|
|
|
593
677
|
|
|
594
678
|
async function runWatch(opts) {
|
|
595
679
|
let roots = opts.roots;
|
|
680
|
+
let discoveredPaths = {
|
|
681
|
+
contents: []
|
|
682
|
+
};
|
|
596
683
|
if (opts.format === "VsCode") {
|
|
597
684
|
let paths = await Discovery$ReventlessGwt.discover(roots);
|
|
685
|
+
discoveredPaths.contents = paths;
|
|
598
686
|
await emitDiscovery(paths);
|
|
599
687
|
startBuildWatchers(paths);
|
|
600
688
|
}
|
|
689
|
+
let currentWorker = {
|
|
690
|
+
contents: undefined
|
|
691
|
+
};
|
|
692
|
+
Cancellation$ReventlessGwt.onCancel(() => {
|
|
693
|
+
let w = currentWorker.contents;
|
|
694
|
+
if (w !== undefined) {
|
|
695
|
+
Primitive_option.valFromOption(w).terminate();
|
|
696
|
+
return;
|
|
697
|
+
}
|
|
698
|
+
});
|
|
699
|
+
let runInWorker = paths => new Promise((resolve, _reject) => {
|
|
700
|
+
let w = new Nodeworker_threads.Worker(Worker$ReventlessGwt.runWorkerUrl, {
|
|
701
|
+
workerData: {
|
|
702
|
+
subcommand: opts.subcommand,
|
|
703
|
+
format: opts.format,
|
|
704
|
+
stream: opts.stream,
|
|
705
|
+
watch: opts.watch,
|
|
706
|
+
filters: opts.filters,
|
|
707
|
+
schemaVersion: opts.schemaVersion,
|
|
708
|
+
roots: opts.roots,
|
|
709
|
+
backend: opts.backend,
|
|
710
|
+
uiPorts: opts.uiPorts,
|
|
711
|
+
listPlatforms: opts.listPlatforms,
|
|
712
|
+
toolVersion: opts.toolVersion,
|
|
713
|
+
paths: paths
|
|
714
|
+
}
|
|
715
|
+
});
|
|
716
|
+
currentWorker.contents = Primitive_option.some(w);
|
|
717
|
+
let settled = {
|
|
718
|
+
contents: false
|
|
719
|
+
};
|
|
720
|
+
let settle = () => {
|
|
721
|
+
if (!settled.contents) {
|
|
722
|
+
settled.contents = true;
|
|
723
|
+
currentWorker.contents = undefined;
|
|
724
|
+
return resolve();
|
|
725
|
+
}
|
|
726
|
+
};
|
|
727
|
+
w.on("exit", _code => settle());
|
|
728
|
+
w.on("error", e => {
|
|
729
|
+
console.error("gwt run worker error:", e);
|
|
730
|
+
settle();
|
|
731
|
+
});
|
|
732
|
+
});
|
|
733
|
+
let pathsForScope = scope => {
|
|
734
|
+
if (opts.format === "VsCode") {
|
|
735
|
+
return scopeSubset(scope, discoveredPaths.contents);
|
|
736
|
+
}
|
|
737
|
+
};
|
|
601
738
|
let runInProgress = {
|
|
602
739
|
contents: false
|
|
603
740
|
};
|
|
604
|
-
let
|
|
605
|
-
contents:
|
|
741
|
+
let pendingScope = {
|
|
742
|
+
contents: undefined
|
|
606
743
|
};
|
|
607
|
-
let
|
|
744
|
+
let requestRun = async scope => {
|
|
608
745
|
if (runInProgress.contents) {
|
|
609
|
-
|
|
746
|
+
let s = pendingScope.contents;
|
|
747
|
+
pendingScope.contents = s !== undefined ? mergeScope(s, scope) : scope;
|
|
610
748
|
return;
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
749
|
+
}
|
|
750
|
+
runInProgress.contents = true;
|
|
751
|
+
await runInWorker(pathsForScope(scope));
|
|
752
|
+
let drain = async () => {
|
|
753
|
+
let next = pendingScope.contents;
|
|
754
|
+
if (next !== undefined) {
|
|
755
|
+
pendingScope.contents = undefined;
|
|
756
|
+
await runInWorker(pathsForScope(next));
|
|
757
|
+
return await drain();
|
|
619
758
|
} else {
|
|
759
|
+
runInProgress.contents = false;
|
|
620
760
|
return;
|
|
621
761
|
}
|
|
762
|
+
};
|
|
763
|
+
return await drain();
|
|
764
|
+
};
|
|
765
|
+
await requestRun("RunAll");
|
|
766
|
+
let rediscoverAndRun = async () => {
|
|
767
|
+
if (opts.format === "VsCode") {
|
|
768
|
+
discoveredPaths.contents = await Discovery$ReventlessGwt.discover(roots);
|
|
769
|
+
}
|
|
770
|
+
await requestRun("RunAll");
|
|
771
|
+
};
|
|
772
|
+
let rebuilding = {};
|
|
773
|
+
let refreshDiscovery = async () => {
|
|
774
|
+
let paths = await Discovery$ReventlessGwt.discover(roots);
|
|
775
|
+
discoveredPaths.contents = paths;
|
|
776
|
+
await emitDiscovery(paths);
|
|
777
|
+
startBuildWatchers(paths);
|
|
778
|
+
await requestRun("RunAll");
|
|
779
|
+
};
|
|
780
|
+
let affectedScope = path => {
|
|
781
|
+
if (opts.format !== "VsCode") {
|
|
782
|
+
return "RunAll";
|
|
783
|
+
}
|
|
784
|
+
let abs = Nodepath.resolve(path);
|
|
785
|
+
let pkg = PackageScan$ReventlessGwt.findOwning(Nodepath.dirname(abs));
|
|
786
|
+
if (pkg !== undefined && discoveredPaths.contents.some(p => pathUnderDir(p, pkg.dir))) {
|
|
787
|
+
return {
|
|
788
|
+
TAG: "RunPackages",
|
|
789
|
+
_0: [pkg.dir]
|
|
790
|
+
};
|
|
791
|
+
} else {
|
|
792
|
+
return "RunAll";
|
|
622
793
|
}
|
|
623
794
|
};
|
|
624
|
-
await run();
|
|
625
795
|
Watch$ReventlessGwt.start(roots, (event, path) => {
|
|
626
796
|
if (opts.format === "VsCode" && Watch$ReventlessGwt.isStructuralSource(event, path)) {
|
|
627
797
|
let pkg = PackageScan$ReventlessGwt.findOwning(path);
|
|
628
798
|
if (pkg !== undefined) {
|
|
799
|
+
if (Stdlib_Option.getOr(rebuilding[pkg.dir], false)) {
|
|
800
|
+
return;
|
|
801
|
+
}
|
|
802
|
+
rebuilding[pkg.dir] = true;
|
|
629
803
|
let t0 = Date.now();
|
|
630
804
|
FormatterVsCode$ReventlessGwt.buildStart(pkg.dir);
|
|
805
|
+
let sawError = {
|
|
806
|
+
contents: false
|
|
807
|
+
};
|
|
631
808
|
let feed = BuildClassifier$ReventlessGwt.make(undefined, {
|
|
632
809
|
onStart: () => {},
|
|
633
810
|
onOk: _ms => {},
|
|
634
|
-
onFail: msg =>
|
|
811
|
+
onFail: msg => {
|
|
812
|
+
sawError.contents = true;
|
|
813
|
+
FormatterVsCode$ReventlessGwt.buildFail(pkg.dir, msg);
|
|
814
|
+
}
|
|
635
815
|
});
|
|
636
|
-
return ProcessManager$ReventlessGwt.cleanRebuild(pkg, (_dir, line) => feed(line),
|
|
637
|
-
|
|
638
|
-
|
|
816
|
+
return ProcessManager$ReventlessGwt.cleanRebuild(pkg, (_dir, line) => feed(line), ok => {
|
|
817
|
+
rebuilding[pkg.dir] = false;
|
|
818
|
+
if (ok) {
|
|
819
|
+
FormatterVsCode$ReventlessGwt.buildOk(pkg.dir, Date.now() - t0);
|
|
820
|
+
} else if (!sawError.contents) {
|
|
821
|
+
FormatterVsCode$ReventlessGwt.buildFail(pkg.dir, "clean rebuild failed");
|
|
822
|
+
}
|
|
823
|
+
rediscoverAndRun();
|
|
639
824
|
});
|
|
640
825
|
}
|
|
641
|
-
|
|
826
|
+
requestRun("RunAll");
|
|
642
827
|
return;
|
|
643
828
|
} else {
|
|
644
|
-
|
|
829
|
+
if (opts.format === "VsCode" && event === "Add" && path.endsWith(".res")) {
|
|
830
|
+
refreshDiscovery();
|
|
831
|
+
} else {
|
|
832
|
+
requestRun(affectedScope(path));
|
|
833
|
+
}
|
|
645
834
|
return;
|
|
646
835
|
}
|
|
647
836
|
});
|
|
@@ -728,8 +917,12 @@ async function main() {
|
|
|
728
917
|
}
|
|
729
918
|
}
|
|
730
919
|
|
|
920
|
+
let defaultTimeoutMs = 5000;
|
|
921
|
+
|
|
731
922
|
export {
|
|
732
923
|
toolVersion,
|
|
924
|
+
sha256,
|
|
925
|
+
lastDomainHash,
|
|
733
926
|
dateNowIso,
|
|
734
927
|
parseFormat,
|
|
735
928
|
defaultRoots,
|
|
@@ -737,10 +930,15 @@ export {
|
|
|
737
930
|
parseArgv,
|
|
738
931
|
passesFilter,
|
|
739
932
|
exnMessage,
|
|
933
|
+
defaultTimeoutMs,
|
|
934
|
+
raceWithTimeout,
|
|
740
935
|
runEntry,
|
|
741
936
|
loadAndCollect,
|
|
742
937
|
runFiles,
|
|
743
938
|
emitResult,
|
|
939
|
+
mergeScope,
|
|
940
|
+
pathUnderDir,
|
|
941
|
+
scopeSubset,
|
|
744
942
|
runOnce,
|
|
745
943
|
emitDomainAnalysis,
|
|
746
944
|
emitDiscovery,
|
|
@@ -751,4 +949,4 @@ export {
|
|
|
751
949
|
listPlatforms,
|
|
752
950
|
main,
|
|
753
951
|
}
|
|
754
|
-
/*
|
|
952
|
+
/* node:path Not a pure module */
|
package/src/Collector.res
CHANGED
|
@@ -25,6 +25,10 @@ type entry = {
|
|
|
25
25
|
body: unit => promise<Outcome.outcome>,
|
|
26
26
|
status: status,
|
|
27
27
|
location: option<location>,
|
|
28
|
+
// Per-test deadline in ms (from `~timeout` on `testPromise`). `None` = use the
|
|
29
|
+
// runner default. The CLI runner races the body against this; the Jest arm
|
|
30
|
+
// passes it to Jest's own timeout instead.
|
|
31
|
+
timeout: option<int>,
|
|
28
32
|
}
|
|
29
33
|
|
|
30
34
|
let active = ref(false)
|
|
@@ -43,6 +47,10 @@ let activate = () => {
|
|
|
43
47
|
hasOnly := false
|
|
44
48
|
skipNext := false
|
|
45
49
|
onlyNext := false
|
|
50
|
+
// Reset the skip nesting depth too: a throwing `xdescribe` body in a prior
|
|
51
|
+
// file could otherwise leave it > 0, silently skipping every test in every
|
|
52
|
+
// subsequently loaded file.
|
|
53
|
+
skipDepth := 0
|
|
46
54
|
currentFile := None
|
|
47
55
|
}
|
|
48
56
|
|
|
@@ -73,6 +81,7 @@ let buildId = (describePath, name) => {
|
|
|
73
81
|
let push = (
|
|
74
82
|
~slice=?,
|
|
75
83
|
~location=?,
|
|
84
|
+
~timeout=?,
|
|
76
85
|
name: string,
|
|
77
86
|
body: unit => promise<Outcome.outcome>,
|
|
78
87
|
) => {
|
|
@@ -97,8 +106,9 @@ let push = (
|
|
|
97
106
|
body,
|
|
98
107
|
status,
|
|
99
108
|
location,
|
|
109
|
+
timeout,
|
|
100
110
|
}
|
|
101
|
-
entries
|
|
111
|
+
entries.contents->Array.push(entry)
|
|
102
112
|
}
|
|
103
113
|
|
|
104
114
|
// A `todo` placeholder: a spec-less slice still ships a discoverable, compiling
|
|
@@ -115,8 +125,9 @@ let pushTodo = (name: string) => {
|
|
|
115
125
|
body: () => Promise.resolve(Outcome.pass),
|
|
116
126
|
status: Skipped,
|
|
117
127
|
location: None,
|
|
128
|
+
timeout: None,
|
|
118
129
|
}
|
|
119
|
-
entries
|
|
130
|
+
entries.contents->Array.push(entry)
|
|
120
131
|
}
|
|
121
132
|
|
|
122
133
|
let drain = () => {
|
package/src/Collector.res.mjs
CHANGED
|
@@ -42,6 +42,7 @@ function activate() {
|
|
|
42
42
|
hasOnly.contents = false;
|
|
43
43
|
skipNext.contents = false;
|
|
44
44
|
onlyNext.contents = false;
|
|
45
|
+
skipDepth.contents = 0;
|
|
45
46
|
currentFile.contents = undefined;
|
|
46
47
|
}
|
|
47
48
|
|
|
@@ -86,7 +87,7 @@ function buildId(describePath, name) {
|
|
|
86
87
|
}
|
|
87
88
|
}
|
|
88
89
|
|
|
89
|
-
function push(slice, location, name, body) {
|
|
90
|
+
function push(slice, location, timeout, name, body) {
|
|
90
91
|
let status = skipDepth.contents > 0 ? "Skipped" : (
|
|
91
92
|
skipNext.contents ? (skipNext.contents = false, "Skipped") : (
|
|
92
93
|
onlyNext.contents ? (onlyNext.contents = false, "Only") : "Runnable"
|
|
@@ -101,9 +102,10 @@ function push(slice, location, name, body) {
|
|
|
101
102
|
slice: slice,
|
|
102
103
|
body: body,
|
|
103
104
|
status: status,
|
|
104
|
-
location: location
|
|
105
|
+
location: location,
|
|
106
|
+
timeout: timeout
|
|
105
107
|
};
|
|
106
|
-
entries.contents
|
|
108
|
+
entries.contents.push(entry);
|
|
107
109
|
}
|
|
108
110
|
|
|
109
111
|
function pushTodo(name) {
|
|
@@ -117,9 +119,10 @@ function pushTodo(name) {
|
|
|
117
119
|
slice: undefined,
|
|
118
120
|
body: entry_body,
|
|
119
121
|
status: "Skipped",
|
|
120
|
-
location: undefined
|
|
122
|
+
location: undefined,
|
|
123
|
+
timeout: undefined
|
|
121
124
|
};
|
|
122
|
-
entries.contents
|
|
125
|
+
entries.contents.push(entry);
|
|
123
126
|
}
|
|
124
127
|
|
|
125
128
|
function drain() {
|
package/src/ComponentMeta.res
CHANGED
|
@@ -5,42 +5,16 @@
|
|
|
5
5
|
|
|
6
6
|
type component = {kind: string, name: string}
|
|
7
7
|
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
"StateViewSlice",
|
|
14
|
-
"StateViewSliceStream",
|
|
15
|
-
"ReadModel",
|
|
16
|
-
"ReadModelStream",
|
|
17
|
-
"AutomationSlice",
|
|
18
|
-
"InboundTranslationSlice",
|
|
19
|
-
"OutboundTranslationSlice",
|
|
20
|
-
"Extension",
|
|
21
|
-
"ExtensionPoint",
|
|
22
|
-
"Task",
|
|
23
|
-
]
|
|
24
|
-
|
|
25
|
-
let isKindFolder = (segment: string) => kindFolders->Array.includes(segment)
|
|
26
|
-
|
|
27
|
-
// Body-file suffixes stripped to recover the spec stem (longest first so
|
|
28
|
-
// `_ExtensionPointMapping` is removed before `_ExtensionPoint`). Spec and body
|
|
29
|
-
// files in one folder collapse to the same component name.
|
|
30
|
-
let bodySuffixes = [
|
|
31
|
-
"_ExtensionPointMapping",
|
|
32
|
-
"_ExtensionPoint",
|
|
33
|
-
"_Extension",
|
|
34
|
-
"_Projections",
|
|
35
|
-
"_Projection",
|
|
36
|
-
"_Mappings",
|
|
37
|
-
"_Behavior",
|
|
38
|
-
"_Automation",
|
|
39
|
-
"_Translation",
|
|
40
|
-
]
|
|
8
|
+
// The folder→kind vocabulary and body-file suffixes are the single source in
|
|
9
|
+
// `Reventless.ComponentKind` (shared with the plugin generator). Deriving from it
|
|
10
|
+
// means the gwt discovery recognises exactly the folder spellings the generator
|
|
11
|
+
// classifies — including the plural / short forms this file used to miss.
|
|
12
|
+
module Kind = Reventless.ComponentKind
|
|
41
13
|
|
|
14
|
+
// Strip a body-file suffix (longest first) to recover the spec stem, so spec and
|
|
15
|
+
// body files in one folder collapse to the same component name.
|
|
42
16
|
let stripBody = (stem: string) =>
|
|
43
|
-
switch bodySuffixes->Array.find(suf => String.endsWith(stem, suf)) {
|
|
17
|
+
switch Kind.bodySuffixes->Array.find(suf => String.endsWith(stem, suf)) {
|
|
44
18
|
| Some(suf) => String.slice(stem, ~start=0, ~end=String.length(stem) - String.length(suf))
|
|
45
19
|
| None => stem
|
|
46
20
|
}
|
|
@@ -87,18 +61,17 @@ let stem = (filename: string) =>
|
|
|
87
61
|
}
|
|
88
62
|
|
|
89
63
|
// {kind, name} for a discovered GWT test file, or None if it isn't inside a
|
|
90
|
-
// recognised kind folder.
|
|
64
|
+
// recognised kind folder. `kind` is the canonical folder name, so a plural
|
|
65
|
+
// folder (`Aggregates/`) reports the same kind as its singular form.
|
|
91
66
|
let componentOfTestFile = (path: string): option<component> =>
|
|
92
|
-
switch parentFolder(path) {
|
|
93
|
-
| Some(
|
|
94
|
-
|
|
95
|
-
| _ => None
|
|
67
|
+
switch parentFolder(path)->Option.flatMap(Kind.folderToKind) {
|
|
68
|
+
| Some(kind) => Some({kind: Kind.folderName(kind), name: path->basename->stem->stripGwt->stripBody})
|
|
69
|
+
| None => None
|
|
96
70
|
}
|
|
97
71
|
|
|
98
72
|
// {kind, name} for a src/ component file (spec or body), or None.
|
|
99
73
|
let componentOfSrcFile = (path: string): option<component> =>
|
|
100
|
-
switch parentFolder(path) {
|
|
101
|
-
| Some(
|
|
102
|
-
|
|
103
|
-
| _ => None
|
|
74
|
+
switch parentFolder(path)->Option.flatMap(Kind.folderToKind) {
|
|
75
|
+
| Some(kind) => Some({kind: Kind.folderName(kind), name: path->basename->stem->stripBody})
|
|
76
|
+
| None => None
|
|
104
77
|
}
|
|
@@ -1,40 +1,11 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
3
|
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
"Aggregate",
|
|
7
|
-
"StateChangeSlice",
|
|
8
|
-
"StateViewSlice",
|
|
9
|
-
"StateViewSliceStream",
|
|
10
|
-
"ReadModel",
|
|
11
|
-
"ReadModelStream",
|
|
12
|
-
"AutomationSlice",
|
|
13
|
-
"InboundTranslationSlice",
|
|
14
|
-
"OutboundTranslationSlice",
|
|
15
|
-
"Extension",
|
|
16
|
-
"ExtensionPoint",
|
|
17
|
-
"Task"
|
|
18
|
-
];
|
|
19
|
-
|
|
20
|
-
function isKindFolder(segment) {
|
|
21
|
-
return kindFolders.includes(segment);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
let bodySuffixes = [
|
|
25
|
-
"_ExtensionPointMapping",
|
|
26
|
-
"_ExtensionPoint",
|
|
27
|
-
"_Extension",
|
|
28
|
-
"_Projections",
|
|
29
|
-
"_Projection",
|
|
30
|
-
"_Mappings",
|
|
31
|
-
"_Behavior",
|
|
32
|
-
"_Automation",
|
|
33
|
-
"_Translation"
|
|
34
|
-
];
|
|
4
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
5
|
+
import * as ComponentKind$Reventless from "@reventlessdev/reventless-spec/src/components/ComponentKind.res.mjs";
|
|
35
6
|
|
|
36
7
|
function stripBody(stem) {
|
|
37
|
-
let suf = bodySuffixes.find(suf => stem.endsWith(suf));
|
|
8
|
+
let suf = ComponentKind$Reventless.bodySuffixes.find(suf => stem.endsWith(suf));
|
|
38
9
|
if (suf !== undefined) {
|
|
39
10
|
return stem.slice(0, stem.length - suf.length | 0);
|
|
40
11
|
} else {
|
|
@@ -86,29 +57,29 @@ function stem(filename) {
|
|
|
86
57
|
}
|
|
87
58
|
|
|
88
59
|
function componentOfTestFile(path) {
|
|
89
|
-
let
|
|
90
|
-
if (
|
|
60
|
+
let kind = Stdlib_Option.flatMap(parentFolder(path), ComponentKind$Reventless.folderToKind);
|
|
61
|
+
if (kind !== undefined) {
|
|
91
62
|
return {
|
|
92
|
-
kind:
|
|
63
|
+
kind: ComponentKind$Reventless.folderName(kind),
|
|
93
64
|
name: stripBody(stripGwt(stem(basename(path))))
|
|
94
65
|
};
|
|
95
66
|
}
|
|
96
67
|
}
|
|
97
68
|
|
|
98
69
|
function componentOfSrcFile(path) {
|
|
99
|
-
let
|
|
100
|
-
if (
|
|
70
|
+
let kind = Stdlib_Option.flatMap(parentFolder(path), ComponentKind$Reventless.folderToKind);
|
|
71
|
+
if (kind !== undefined) {
|
|
101
72
|
return {
|
|
102
|
-
kind:
|
|
73
|
+
kind: ComponentKind$Reventless.folderName(kind),
|
|
103
74
|
name: stripBody(stem(basename(path)))
|
|
104
75
|
};
|
|
105
76
|
}
|
|
106
77
|
}
|
|
107
78
|
|
|
79
|
+
let Kind;
|
|
80
|
+
|
|
108
81
|
export {
|
|
109
|
-
|
|
110
|
-
isKindFolder,
|
|
111
|
-
bodySuffixes,
|
|
82
|
+
Kind,
|
|
112
83
|
stripBody,
|
|
113
84
|
stripGwt,
|
|
114
85
|
basename,
|