testeranto 0.62.0 → 0.70.0
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/README.md +42 -21
- package/dist/cjs-shim.js +2 -2
- package/dist/common/Node.js +7 -24
- package/dist/common/NodeWriter.js +7 -9
- package/dist/common/Project.js +103 -266
- package/dist/common/SubPackages/puppeteer.js +1 -1
- package/dist/common/SubPackages/react-dom/component/web.js +1 -1
- package/dist/common/SubPackages/react-dom/jsx/web.js +15 -7
- package/dist/common/SubPackages/react-test-renderer/MemoExoticComponent/node.js +1 -1
- package/dist/common/SubPackages/react-test-renderer/component/index.js +0 -1
- package/dist/common/SubPackages/react-test-renderer/fc/web.js +1 -1
- package/dist/common/SubPackages/react-test-renderer/jsx/index.js +1 -2
- package/dist/common/SubPackages/react-test-renderer/jsx/web.js +1 -1
- package/dist/common/SubPackages/react-test-renderer/jsx-promised/index.js +1 -1
- package/dist/common/Types.js +2 -32
- package/dist/common/Web.js +25 -18
- package/dist/common/electron.js +177 -107
- package/dist/common/esbuildConfigs/index.js +5 -5
- package/dist/common/esbuildConfigs/node.js +17 -15
- package/dist/common/esbuildConfigs/report.js +12 -47
- package/dist/common/esbuildConfigs/tests.js +0 -1
- package/dist/common/esbuildConfigs/web.js +14 -11
- package/dist/common/lib/abstractBase.js +13 -6
- package/dist/common/lib/basebuilder.js +11 -11
- package/dist/common/lib/classBuilder.js +2 -3
- package/dist/common/lib/core.js +37 -8
- package/dist/common/lib/index.js +10 -8
- package/dist/common/lib/types.js +2 -0
- package/dist/common/preload.js +15 -25
- package/dist/common/puppeteerConfiger.js +24 -0
- package/dist/common/tsconfig.common.tsbuildinfo +1 -1
- package/dist/module/Node.js +7 -24
- package/dist/module/NodeWriter.js +7 -9
- package/dist/module/Project.js +104 -267
- package/dist/module/SubPackages/puppeteer.js +1 -1
- package/dist/module/SubPackages/react/jsx/web.js +1 -1
- package/dist/module/SubPackages/react-dom/component/node.js +2 -2
- package/dist/module/SubPackages/react-dom/component/web.js +1 -1
- package/dist/module/SubPackages/react-dom/jsx/web.js +17 -9
- package/dist/module/SubPackages/react-test-renderer/MemoExoticComponent/node.js +1 -1
- package/dist/module/SubPackages/react-test-renderer/component/index.js +0 -1
- package/dist/module/SubPackages/react-test-renderer/fc/web.js +1 -1
- package/dist/module/SubPackages/react-test-renderer/jsx/index.js +1 -2
- package/dist/module/SubPackages/react-test-renderer/jsx/web.js +1 -1
- package/dist/module/SubPackages/react-test-renderer/jsx-promised/index.js +1 -1
- package/dist/module/Types.js +3 -30
- package/dist/module/Web.js +26 -19
- package/dist/module/electron.js +179 -109
- package/dist/module/esbuildConfigs/index.js +5 -5
- package/dist/module/esbuildConfigs/node.js +17 -15
- package/dist/module/esbuildConfigs/report.js +11 -48
- package/dist/module/esbuildConfigs/tests.js +0 -1
- package/dist/module/esbuildConfigs/web.js +14 -11
- package/dist/module/lib/abstractBase.js +13 -6
- package/dist/module/lib/basebuilder.js +11 -11
- package/dist/module/lib/classBuilder.js +2 -3
- package/dist/module/lib/core.js +39 -10
- package/dist/module/lib/index.js +10 -8
- package/dist/module/lib/types.js +1 -0
- package/dist/module/preload.js +12 -25
- package/dist/module/puppeteerConfiger.js +19 -0
- package/dist/module/tsconfig.module.tsbuildinfo +1 -1
- package/dist/types/Node.d.ts +3 -2
- package/dist/types/Project.d.ts +1 -2
- package/dist/types/SubPackages/puppeteer.d.ts +3 -3
- package/dist/types/SubPackages/react/component/node.d.ts +1 -1
- package/dist/types/SubPackages/react/component/web.d.ts +1 -1
- package/dist/types/SubPackages/react/jsx/index.d.ts +1 -1
- package/dist/types/SubPackages/react/jsx/node.d.ts +1 -1
- package/dist/types/SubPackages/react/jsx/web.d.ts +2 -2
- package/dist/types/SubPackages/react-dom/component/node.d.ts +2 -2
- package/dist/types/SubPackages/react-dom/component/web.d.ts +1 -1
- package/dist/types/SubPackages/react-dom/jsx/node.d.ts +1 -1
- package/dist/types/SubPackages/react-dom/jsx/web.d.ts +1 -1
- package/dist/types/SubPackages/react-test-renderer/MemoExoticComponent/node.d.ts +1 -1
- package/dist/types/SubPackages/react-test-renderer/component/index.d.ts +1 -1
- package/dist/types/SubPackages/react-test-renderer/component/node.d.ts +1 -1
- package/dist/types/SubPackages/react-test-renderer/component/web.d.ts +1 -1
- package/dist/types/SubPackages/react-test-renderer/fc/node.d.ts +1 -1
- package/dist/types/SubPackages/react-test-renderer/fc/web.d.ts +1 -1
- package/dist/types/SubPackages/react-test-renderer/jsx/node.d.ts +1 -1
- package/dist/types/SubPackages/react-test-renderer/jsx/web.d.ts +3 -3
- package/dist/types/SubPackages/react-test-renderer/jsx-promised/index.d.ts +1 -1
- package/dist/types/SubPackages/react-test-renderer/jsx-promised/node.d.ts +1 -1
- package/dist/types/SubPackages/react-test-renderer/jsx-promised/web.d.ts +1 -1
- package/dist/types/Types.d.ts +19 -100
- package/dist/types/Web.d.ts +3 -2
- package/dist/types/esbuildConfigs/features.d.ts +1 -1
- package/dist/types/esbuildConfigs/index.d.ts +1 -1
- package/dist/types/esbuildConfigs/node.d.ts +1 -1
- package/dist/types/esbuildConfigs/report.d.ts +4 -0
- package/dist/types/esbuildConfigs/tests.d.ts +1 -1
- package/dist/types/esbuildConfigs/web.d.ts +1 -1
- package/dist/types/lib/abstractBase.d.ts +25 -24
- package/dist/types/lib/basebuilder.d.ts +8 -7
- package/dist/types/lib/classBuilder.d.ts +3 -2
- package/dist/types/lib/core.d.ts +3 -2
- package/dist/types/lib/index.d.ts +4 -3
- package/dist/types/lib/types.d.ts +70 -0
- package/dist/types/puppeteerConfiger.d.ts +4 -0
- package/dist/types/tsconfig.types.tsbuildinfo +1 -1
- package/package.json +4 -3
- package/src/Node.ts +24 -54
- package/src/NodeWriter.ts +21 -18
- package/src/Project.ts +165 -620
- package/src/Report.tsx +1 -1
- package/src/SubPackages/puppeteer.ts +19 -14
- package/src/SubPackages/react/component/node.ts +20 -32
- package/src/SubPackages/react/component/web.ts +20 -30
- package/src/SubPackages/react/jsx/index.ts +13 -24
- package/src/SubPackages/react/jsx/web.ts +10 -8
- package/src/SubPackages/react-dom/component/node.ts +17 -23
- package/src/SubPackages/react-dom/component/web.ts +30 -50
- package/src/SubPackages/react-dom/jsx/web.ts +41 -48
- package/src/SubPackages/react-test-renderer/MemoExoticComponent/node.ts +27 -37
- package/src/SubPackages/react-test-renderer/component/index.ts +16 -30
- package/src/SubPackages/react-test-renderer/component/node.ts +5 -11
- package/src/SubPackages/react-test-renderer/component/web.ts +5 -11
- package/src/SubPackages/react-test-renderer/fc/node.ts +36 -50
- package/src/SubPackages/react-test-renderer/fc/web.ts +37 -50
- package/src/SubPackages/react-test-renderer/jsx/index.ts +16 -21
- package/src/SubPackages/react-test-renderer/jsx/node.ts +6 -10
- package/src/SubPackages/react-test-renderer/jsx/web.ts +7 -7
- package/src/SubPackages/react-test-renderer/jsx-promised/index.ts +13 -16
- package/src/Types.ts +73 -307
- package/src/Web.ts +54 -53
- package/src/cjs-shim.js +2 -2
- package/src/electron.ts +258 -191
- package/src/esbuildConfigs/features.ts +3 -4
- package/src/esbuildConfigs/index.ts +8 -8
- package/src/esbuildConfigs/node.ts +21 -20
- package/src/esbuildConfigs/report.ts +15 -51
- package/src/esbuildConfigs/tests.ts +3 -9
- package/src/esbuildConfigs/web.ts +18 -18
- package/src/lib/abstractBase.ts +78 -125
- package/src/lib/basebuilder.ts +109 -134
- package/src/lib/classBuilder.ts +26 -45
- package/src/lib/core.ts +101 -69
- package/src/lib/index.ts +53 -52
- package/src/lib/types.ts +206 -0
- package/src/preload.ts +12 -28
- package/src/puppeteerConfiger.ts +26 -0
- package/src/web.html.ts +1 -1
- package/dist/common/lib/browser.js +0 -26
- package/dist/common/nodeWriterElectron.js +0 -55
- package/dist/module/lib/browser.js +0 -22
- package/dist/module/nodeWriterElectron.js +0 -52
- package/dist/types/lib/browser.d.ts +0 -6
- package/dist/types/nodeWriterElectron.d.ts +0 -2
- package/src/lib/browser.ts +0 -34
- package/src/nodeWriterElectron.ts +0 -71
package/src/Project.ts
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import esbuild from "esbuild";
|
|
2
2
|
import fs from "fs";
|
|
3
3
|
import path from "path";
|
|
4
|
-
import readline from
|
|
4
|
+
import readline from "readline";
|
|
5
5
|
import { glob } from "glob";
|
|
6
6
|
|
|
7
|
-
import { IBaseConfig, IRunTime, ITestTypes } from "./Types";
|
|
8
|
-
|
|
9
7
|
import esbuildNodeConfiger from "./esbuildConfigs/node.js";
|
|
10
8
|
import esbuildWebConfiger from "./esbuildConfigs/web.js";
|
|
11
9
|
import esbuildFeaturesConfiger from "./esbuildConfigs/features.js";
|
|
@@ -13,31 +11,62 @@ import esbuildFeaturesConfiger from "./esbuildConfigs/features.js";
|
|
|
13
11
|
import webHtmlFrame from "./web.html.js";
|
|
14
12
|
import reportHtmlFrame from "./report.html.js";
|
|
15
13
|
|
|
16
|
-
import
|
|
14
|
+
import { ITestTypes, IBaseConfig, IRunTime } from "./lib/types.js";
|
|
15
|
+
|
|
16
|
+
var mode: "DEV" | "PROD" = process.argv[2] === "-dev" ? "DEV" : "PROD";
|
|
17
17
|
|
|
18
18
|
readline.emitKeypressEvents(process.stdin);
|
|
19
19
|
if (process.stdin.isTTY) process.stdin.setRawMode(true);
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
21
|
+
process.stdin.on("keypress", (str, key) => {
|
|
22
|
+
if (key.name === "q") {
|
|
23
|
+
console.log("Testeranto-EsBuild is shutting down...");
|
|
24
|
+
mode = "PROD";
|
|
25
|
+
onDone();
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// setInterval(() => {
|
|
30
|
+
// const memoryUsage = process.memoryUsage();
|
|
31
|
+
// console.log("Memory usage:", memoryUsage);
|
|
32
|
+
// }, 10000); // Check every 10 seconds
|
|
33
|
+
|
|
34
|
+
let featuresDone,
|
|
35
|
+
nodeDone,
|
|
36
|
+
webDone = false;
|
|
37
|
+
const onFeaturesDone = () => {
|
|
38
|
+
featuresDone = true;
|
|
39
|
+
onDone();
|
|
40
|
+
};
|
|
41
|
+
const onNodeDone = () => {
|
|
42
|
+
nodeDone = true;
|
|
43
|
+
onDone();
|
|
44
|
+
};
|
|
45
|
+
const onWebDone = () => {
|
|
46
|
+
webDone = true;
|
|
47
|
+
onDone();
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const onDone = () => {
|
|
51
|
+
console.log(
|
|
52
|
+
JSON.stringify(
|
|
53
|
+
{
|
|
54
|
+
featuresDone,
|
|
55
|
+
nodeDone,
|
|
56
|
+
webDone,
|
|
57
|
+
mode,
|
|
58
|
+
},
|
|
59
|
+
null,
|
|
60
|
+
2
|
|
61
|
+
)
|
|
62
|
+
);
|
|
63
|
+
if (featuresDone && nodeDone && webDone && mode === "PROD") {
|
|
64
|
+
console.log("Testeranto-EsBuild is all done. Goodbye!");
|
|
65
|
+
process.exit();
|
|
66
|
+
} else {
|
|
67
|
+
console.log("Testeranto-EsBuild is still working...");
|
|
68
|
+
}
|
|
69
|
+
};
|
|
41
70
|
|
|
42
71
|
export class ITProject {
|
|
43
72
|
config: IBaseConfig;
|
|
@@ -46,107 +75,118 @@ export class ITProject {
|
|
|
46
75
|
constructor(config: IBaseConfig) {
|
|
47
76
|
this.config = config;
|
|
48
77
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
this.
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
return fs.promises.mkdir(path.dirname(htmlFilePath), { recursive: true }).then(x => fs.writeFileSync(htmlFilePath, webHtmlFrame(jsfilePath, htmlFilePath)
|
|
82
|
-
))
|
|
83
|
-
})
|
|
84
|
-
));
|
|
78
|
+
Promise.resolve(
|
|
79
|
+
Promise.all(
|
|
80
|
+
[...this.getSecondaryEndpointsPoints("web")].map(
|
|
81
|
+
async (sourceFilePath) => {
|
|
82
|
+
const sourceFileSplit = sourceFilePath.split("/");
|
|
83
|
+
const sourceDir = sourceFileSplit.slice(0, -1);
|
|
84
|
+
const sourceFileName = sourceFileSplit[sourceFileSplit.length - 1];
|
|
85
|
+
const sourceFileNameMinusJs = sourceFileName
|
|
86
|
+
.split(".")
|
|
87
|
+
.slice(0, -1)
|
|
88
|
+
.join(".");
|
|
89
|
+
|
|
90
|
+
const htmlFilePath = path.normalize(
|
|
91
|
+
`${process.cwd()}/${config.outdir}/web/${sourceDir.join(
|
|
92
|
+
"/"
|
|
93
|
+
)}/${sourceFileNameMinusJs}.html`
|
|
94
|
+
);
|
|
95
|
+
const jsfilePath = `./${sourceFileNameMinusJs}.mjs`;
|
|
96
|
+
|
|
97
|
+
return fs.promises
|
|
98
|
+
.mkdir(path.dirname(htmlFilePath), { recursive: true })
|
|
99
|
+
.then((x) =>
|
|
100
|
+
fs.writeFileSync(
|
|
101
|
+
htmlFilePath,
|
|
102
|
+
webHtmlFrame(jsfilePath, htmlFilePath)
|
|
103
|
+
)
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
)
|
|
107
|
+
)
|
|
108
|
+
);
|
|
85
109
|
|
|
86
110
|
const [nodeEntryPoints, webEntryPoints] = getRunnables(this.config.tests);
|
|
87
111
|
|
|
88
|
-
glob(`./${config.outdir}/chunk-*.mjs`, { ignore:
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
})
|
|
112
|
+
glob(`./${config.outdir}/chunk-*.mjs`, { ignore: "node_modules/**" }).then(
|
|
113
|
+
(chunks) => {
|
|
114
|
+
chunks.forEach((chunk) => {
|
|
115
|
+
fs.unlinkSync(chunk);
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
);
|
|
96
119
|
|
|
97
|
-
fs.copyFileSync(
|
|
98
|
-
|
|
120
|
+
fs.copyFileSync(
|
|
121
|
+
"./node_modules/testeranto/dist/prebuild/Report.js",
|
|
122
|
+
"./docs/Report.js"
|
|
123
|
+
);
|
|
124
|
+
fs.copyFileSync(
|
|
125
|
+
"./node_modules/testeranto/dist/prebuild/Report.css",
|
|
126
|
+
"./docs/Report.css"
|
|
127
|
+
);
|
|
99
128
|
|
|
100
129
|
fs.writeFileSync(`${config.outdir}/report.html`, reportHtmlFrame());
|
|
101
130
|
|
|
102
131
|
Promise.all([
|
|
103
|
-
|
|
132
|
+
fs.promises.writeFile(
|
|
133
|
+
`${config.outdir}/testeranto.json`,
|
|
134
|
+
JSON.stringify(
|
|
135
|
+
{
|
|
136
|
+
...config,
|
|
137
|
+
buildDir: process.cwd() + "/" + config.outdir,
|
|
138
|
+
},
|
|
139
|
+
null,
|
|
140
|
+
2
|
|
141
|
+
)
|
|
142
|
+
),
|
|
143
|
+
esbuild
|
|
144
|
+
.context(esbuildFeaturesConfiger(config))
|
|
104
145
|
.then(async (featuresContext) => {
|
|
105
|
-
|
|
106
|
-
|
|
146
|
+
if (mode == "DEV") {
|
|
147
|
+
await featuresContext.watch();
|
|
148
|
+
onFeaturesDone();
|
|
149
|
+
} else {
|
|
150
|
+
featuresContext.rebuild().then((v) => {
|
|
151
|
+
onFeaturesDone();
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
107
155
|
return featuresContext;
|
|
108
156
|
}),
|
|
109
|
-
esbuild
|
|
157
|
+
esbuild
|
|
158
|
+
.context(esbuildNodeConfiger(config, nodeEntryPoints))
|
|
110
159
|
.then(async (nodeContext) => {
|
|
111
|
-
|
|
112
|
-
|
|
160
|
+
if (mode == "DEV") {
|
|
161
|
+
await nodeContext.watch().then((v) => {
|
|
162
|
+
onNodeDone();
|
|
163
|
+
});
|
|
164
|
+
} else {
|
|
165
|
+
nodeContext.rebuild().then((v) => {
|
|
166
|
+
onNodeDone();
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
113
170
|
return nodeContext;
|
|
114
171
|
}),
|
|
115
|
-
esbuild
|
|
116
|
-
.
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
172
|
+
esbuild
|
|
173
|
+
.context(esbuildWebConfiger(config, webEntryPoints))
|
|
174
|
+
.then(async (webContext) => {
|
|
175
|
+
if (mode == "DEV") {
|
|
176
|
+
await webContext.watch().then((v) => {
|
|
177
|
+
onWebDone();
|
|
178
|
+
});
|
|
179
|
+
} else {
|
|
180
|
+
webContext.rebuild().then((v) => {
|
|
181
|
+
onWebDone();
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
return webContext;
|
|
120
185
|
}),
|
|
121
|
-
|
|
122
|
-
]).then(async (contexts) => {
|
|
123
|
-
Promise.all(
|
|
124
|
-
config.tests.map(async ([test, runtime]) => {
|
|
125
|
-
return {
|
|
126
|
-
test,
|
|
127
|
-
runtime
|
|
128
|
-
};
|
|
129
|
-
})
|
|
130
|
-
).then(async (modules) => {
|
|
131
|
-
fs.writeFileSync(`${config.outdir}/testeranto.json`, JSON.stringify(
|
|
132
|
-
{
|
|
133
|
-
modules,
|
|
134
|
-
buildDir: process.cwd() + "/" + config.outdir
|
|
135
|
-
}, null, 2));
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
if (config.devMode === false) {
|
|
139
|
-
console.log("Your tests were built but not run because devMode was false. Exiting gracefully");
|
|
140
|
-
process.exit(0);
|
|
141
|
-
|
|
142
|
-
} else {
|
|
143
|
-
// no-op
|
|
144
|
-
}
|
|
145
|
-
})
|
|
186
|
+
]);
|
|
146
187
|
}
|
|
147
188
|
|
|
148
189
|
public getSecondaryEndpointsPoints(runtime?: IRunTime): string[] {
|
|
149
|
-
|
|
150
190
|
const meta = (ts: ITestTypes[], st: Set<string>): Set<string> => {
|
|
151
191
|
ts.forEach((t) => {
|
|
152
192
|
if (t[1] === runtime) {
|
|
@@ -155,523 +195,28 @@ export class ITProject {
|
|
|
155
195
|
if (Array.isArray(t[2])) {
|
|
156
196
|
meta(t[2], st);
|
|
157
197
|
}
|
|
158
|
-
})
|
|
198
|
+
});
|
|
159
199
|
return st;
|
|
160
|
-
}
|
|
200
|
+
};
|
|
161
201
|
return Array.from(meta(this.config.tests, new Set()));
|
|
162
202
|
}
|
|
163
|
-
|
|
164
|
-
public initiateShutdown(reason: string) {
|
|
165
|
-
console.log("Shutdown initiated because", reason);
|
|
166
|
-
this.mode = "down";
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// private shutdown() {
|
|
170
|
-
// let i = 0;
|
|
171
|
-
// new Promise((res, reh) => {
|
|
172
|
-
// console.log("final results: ");
|
|
173
|
-
// const procsTable: any[] = [];
|
|
174
|
-
// // pm2.list((err, procs) => {
|
|
175
|
-
// // procs.forEach((proc, ndx) => {
|
|
176
|
-
// // const exitCode = this.exitCodes[proc.name as string]
|
|
177
|
-
// // if (exitCode !== 0) {
|
|
178
|
-
// // i++;
|
|
179
|
-
// // }
|
|
180
|
-
// // procsTable.push({
|
|
181
|
-
// // name: proc.name,
|
|
182
|
-
// // pm_id: proc.pm_id,
|
|
183
|
-
// // exitCode
|
|
184
|
-
// // })
|
|
185
|
-
|
|
186
|
-
// // if (ndx === procs.length - 1) {
|
|
187
|
-
// // console.table(procsTable);
|
|
188
|
-
// // res(i)
|
|
189
|
-
// // }
|
|
190
|
-
// // })
|
|
191
|
-
// // })
|
|
192
|
-
// }).then((failures: number) => {
|
|
193
|
-
// // pm2.stop("all", (e) => console.error(e));
|
|
194
|
-
// // pm2.disconnect();
|
|
195
|
-
// console.log(`gracefully exiting with ${failures} failures`)
|
|
196
|
-
// process.exit(failures);
|
|
197
|
-
// })
|
|
198
|
-
// }
|
|
199
|
-
|
|
200
|
-
// private spinner() {
|
|
201
|
-
// this.spinCycle = (this.spinCycle + 1) % this.spinAnimation.length;
|
|
202
|
-
// return this.spinAnimation[this.spinCycle];
|
|
203
|
-
// }
|
|
204
|
-
|
|
205
|
-
// private async releaseTestResourceWs(payload: any) {
|
|
206
|
-
// const name = payload.data.testResourceConfiguration.name;
|
|
207
|
-
// const failed = payload.data.failed;
|
|
208
|
-
|
|
209
|
-
// this.exitCodes[name] = failed;
|
|
210
|
-
|
|
211
|
-
// Object.keys(this.ports).forEach((port: string) => {
|
|
212
|
-
// if (this.ports[port] === name) {
|
|
213
|
-
// this.ports[port] = OPEN_PORT;
|
|
214
|
-
// }
|
|
215
|
-
// });
|
|
216
|
-
// }
|
|
217
|
-
|
|
218
|
-
// private async releaseTestResourcePm2(payload: IAdios) {
|
|
219
|
-
// const name = payload.testResourceConfiguration.name;
|
|
220
|
-
// const failed = payload.failed;
|
|
221
|
-
|
|
222
|
-
// this.exitCodes[name] = failed;
|
|
223
|
-
|
|
224
|
-
// // pm2.list((err, processes) => {
|
|
225
|
-
// // processes.forEach((proc: pm2.ProcessDescription) => {
|
|
226
|
-
// // if (proc.name === name) {
|
|
227
|
-
// // Object.keys(this.ports).forEach((port: string) => {
|
|
228
|
-
// // if (this.ports[port] === name) {
|
|
229
|
-
// // this.ports[port] = OPEN_PORT;
|
|
230
|
-
// // }
|
|
231
|
-
// // });
|
|
232
|
-
// // }
|
|
233
|
-
// // });
|
|
234
|
-
// // });
|
|
235
|
-
// }
|
|
236
|
-
|
|
237
|
-
// private allocateViaWs(resourceRequest: {
|
|
238
|
-
// requirement: ITTestResourceRequirement;
|
|
239
|
-
// protocol: ISchedulerProtocols;
|
|
240
|
-
// }) {
|
|
241
|
-
|
|
242
|
-
// const name = resourceRequest.requirement.name;
|
|
243
|
-
// const testResourceRequirement = resourceRequest.requirement;
|
|
244
|
-
|
|
245
|
-
// const websocket = this.websockets[name];
|
|
246
|
-
|
|
247
|
-
// if (testResourceRequirement?.ports === 0) {
|
|
248
|
-
// websocket.send(JSON.stringify({
|
|
249
|
-
// data: {
|
|
250
|
-
// testResourceConfiguration: {
|
|
251
|
-
// ports: [],
|
|
252
|
-
// },
|
|
253
|
-
// }
|
|
254
|
-
// }));
|
|
255
|
-
// } else if ((testResourceRequirement?.ports || 0) > 0) {
|
|
256
|
-
// // clear any port-slots associated with this job
|
|
257
|
-
// Object.values(this.ports).forEach((jobMaybe, portNumber) => {
|
|
258
|
-
// if (jobMaybe && jobMaybe === name) {
|
|
259
|
-
// this.ports[portNumber] = OPEN_PORT;
|
|
260
|
-
// }
|
|
261
|
-
// });
|
|
262
|
-
|
|
263
|
-
// // find a list of open ports
|
|
264
|
-
// const foundOpenPorts = Object.keys(this.ports).filter(
|
|
265
|
-
// (p) => this.ports[p] === OPEN_PORT
|
|
266
|
-
// );
|
|
267
|
-
|
|
268
|
-
// if (foundOpenPorts.length >= testResourceRequirement.ports) {
|
|
269
|
-
// const selectionOfPorts = foundOpenPorts.slice(
|
|
270
|
-
// 0,
|
|
271
|
-
// testResourceRequirement.ports
|
|
272
|
-
// );
|
|
273
|
-
|
|
274
|
-
// websocket.send(JSON.stringify({
|
|
275
|
-
// data: {
|
|
276
|
-
// testResourceConfiguration: {
|
|
277
|
-
// ports: selectionOfPorts,
|
|
278
|
-
// },
|
|
279
|
-
// }
|
|
280
|
-
// }));
|
|
281
|
-
|
|
282
|
-
// // mark the selected ports as occupied
|
|
283
|
-
// for (const foundOpenPort of selectionOfPorts) {
|
|
284
|
-
// this.ports[foundOpenPort] = name;
|
|
285
|
-
// }
|
|
286
|
-
// } else {
|
|
287
|
-
// console.log(
|
|
288
|
-
// `no port was open so send the ${name} job to the back of the resourceQueue`
|
|
289
|
-
// );
|
|
290
|
-
// this.resourceQueue.push(resourceRequest);
|
|
291
|
-
// }
|
|
292
|
-
// }
|
|
293
|
-
// }
|
|
294
|
-
|
|
295
|
-
// private allocateViaIpc(resourceRequest: {
|
|
296
|
-
// requirement: ITTestResourceRequirement;
|
|
297
|
-
// protocol: ISchedulerProtocols;
|
|
298
|
-
// }) {
|
|
299
|
-
// const pName = resourceRequest.requirement.name;
|
|
300
|
-
// const testResourceRequirement = resourceRequest.requirement;
|
|
301
|
-
|
|
302
|
-
// // pm2.list((err, processes) => {
|
|
303
|
-
// // console.error(err);
|
|
304
|
-
// // processes.forEach((p) => {
|
|
305
|
-
// // if (p.name === pName && p.pid) {
|
|
306
|
-
// // const message = {
|
|
307
|
-
// // // these fields must be present
|
|
308
|
-
// // id: p.pid,
|
|
309
|
-
// // topic: "some topic",
|
|
310
|
-
// // type: "process:msg",
|
|
311
|
-
|
|
312
|
-
// // // Data to be sent
|
|
313
|
-
// // data: {
|
|
314
|
-
// // testResourceConfiguration: {
|
|
315
|
-
// // ports: [],
|
|
316
|
-
// // // fs: fPath,
|
|
317
|
-
// // },
|
|
318
|
-
// // id: p.pm_id,
|
|
319
|
-
// // },
|
|
320
|
-
// // };
|
|
321
|
-
|
|
322
|
-
// // if (testResourceRequirement?.ports === 0) {
|
|
323
|
-
// // pm2.sendDataToProcessId(
|
|
324
|
-
// // p.pm_id as number,
|
|
325
|
-
// // message,
|
|
326
|
-
// // function (err, res) {
|
|
327
|
-
// // // console.log("sendDataToProcessId", err, res, message);
|
|
328
|
-
// // }
|
|
329
|
-
// // );
|
|
330
|
-
// // }
|
|
331
|
-
|
|
332
|
-
// // if ((testResourceRequirement?.ports || 0) > 0) {
|
|
333
|
-
// // // clear any port-slots associated with this job
|
|
334
|
-
// // Object.values(this.ports).forEach((jobMaybe, portNumber) => {
|
|
335
|
-
// // if (jobMaybe && jobMaybe === pName) {
|
|
336
|
-
// // this.ports[portNumber] = OPEN_PORT;
|
|
337
|
-
// // }
|
|
338
|
-
// // });
|
|
339
|
-
|
|
340
|
-
// // // find a list of open ports
|
|
341
|
-
// // const foundOpenPorts = Object.keys(this.ports).filter(
|
|
342
|
-
// // (p) => this.ports[p] === OPEN_PORT
|
|
343
|
-
// // );
|
|
344
|
-
// // // if there are enough open port-slots...
|
|
345
|
-
// // if (foundOpenPorts.length >= testResourceRequirement.ports) {
|
|
346
|
-
// // const selectionOfPorts = foundOpenPorts.slice(
|
|
347
|
-
// // 0,
|
|
348
|
-
// // testResourceRequirement.ports
|
|
349
|
-
// // );
|
|
350
|
-
|
|
351
|
-
// // const message = {
|
|
352
|
-
// // // these fields must be present
|
|
353
|
-
// // id: p.pid, // id of process from "pm2 list" command or from pm2.list(errback) method
|
|
354
|
-
// // topic: "some topic",
|
|
355
|
-
// // // process:msg will be send as 'message' on target process
|
|
356
|
-
// // type: "process:msg",
|
|
357
|
-
|
|
358
|
-
// // // Data to be sent
|
|
359
|
-
// // data: {
|
|
360
|
-
// // testResourceConfiguration: {
|
|
361
|
-
// // // fs: fPath,
|
|
362
|
-
// // ports: selectionOfPorts,
|
|
363
|
-
// // },
|
|
364
|
-
// // id: p.pid,
|
|
365
|
-
// // },
|
|
366
|
-
// // };
|
|
367
|
-
// // pm2.sendDataToProcessId(
|
|
368
|
-
// // p.pm_id as number,
|
|
369
|
-
// // message,
|
|
370
|
-
// // function (err, res) {
|
|
371
|
-
// // // no-op
|
|
372
|
-
// // }
|
|
373
|
-
// // );
|
|
374
|
-
// // // mark the selected ports as occupied
|
|
375
|
-
// // for (const foundOpenPort of selectionOfPorts) {
|
|
376
|
-
// // this.ports[foundOpenPort] = p.pid.toString();
|
|
377
|
-
// // }
|
|
378
|
-
// // } else {
|
|
379
|
-
// // console.log(
|
|
380
|
-
// // `no port was open so send the ${p.pid} job to the back of the resourceQueue`
|
|
381
|
-
// // );
|
|
382
|
-
// // this.resourceQueue.push(resourceRequest);
|
|
383
|
-
// // }
|
|
384
|
-
// // }
|
|
385
|
-
// // }
|
|
386
|
-
// // })
|
|
387
|
-
// // })
|
|
388
|
-
// }
|
|
389
|
-
|
|
390
|
-
// private mainLoop = async () => {
|
|
391
|
-
// if (this.clearScreen) {
|
|
392
|
-
// console.clear();
|
|
393
|
-
// }
|
|
394
|
-
|
|
395
|
-
// const procsTable: any[] = [];
|
|
396
|
-
// // pm2.list((err, procs) => {
|
|
397
|
-
// // procs.forEach((proc) => {
|
|
398
|
-
// // procsTable.push({
|
|
399
|
-
// // name: proc.name,
|
|
400
|
-
// // pid: proc.pid,
|
|
401
|
-
// // pm_id: proc.pm_id,
|
|
402
|
-
// // mem: proc.monit?.memory,
|
|
403
|
-
// // cpu: proc.monit?.cpu,
|
|
404
|
-
// // "exit code": this.exitCodes[proc.name as string]
|
|
405
|
-
// // })
|
|
406
|
-
// // })
|
|
407
|
-
// // console.table(procsTable);
|
|
408
|
-
|
|
409
|
-
// // console.table(this.resourceQueue);
|
|
410
|
-
// // console.log("webSocketServer.clients", Object.keys(this.websockets));
|
|
411
|
-
|
|
412
|
-
// // const resourceRequest = this.resourceQueue.pop();
|
|
413
|
-
|
|
414
|
-
// // if (!resourceRequest) {
|
|
415
|
-
// // if (!this.devMode && this.mode === "up") {
|
|
416
|
-
// // this.initiateShutdown("resource request queue is empty");
|
|
417
|
-
// // }
|
|
418
|
-
|
|
419
|
-
// // if (
|
|
420
|
-
// // this.mode === "down" &&
|
|
421
|
-
// // (
|
|
422
|
-
// // procsTable.every(
|
|
423
|
-
// // (p) => p.pid === 0 || p.pid === undefined
|
|
424
|
-
// // ) ||
|
|
425
|
-
// // procsTable.length === 0
|
|
426
|
-
// // )
|
|
427
|
-
// // ) {
|
|
428
|
-
// // this.shutdown();
|
|
429
|
-
// // }
|
|
430
|
-
// // } else {
|
|
431
|
-
// // if (resourceRequest.protocol === "ipc") {
|
|
432
|
-
// // this.allocateViaIpc(resourceRequest)
|
|
433
|
-
// // } else if (resourceRequest.protocol === "ws") {
|
|
434
|
-
// // this.allocateViaWs(resourceRequest)
|
|
435
|
-
// // }
|
|
436
|
-
// // }
|
|
437
|
-
|
|
438
|
-
// // const upMessage = `
|
|
439
|
-
// // Running tests while watching for changes.
|
|
440
|
-
// // Use 'q' to initiate shutdown and 'x' to kill.
|
|
441
|
-
// // esbuild web server - ${JSON.stringify(this.esWebServerDetails)}
|
|
442
|
-
// // `;
|
|
443
|
-
// // const downMessage = "Shutdown is in progress. Please wait.";
|
|
444
|
-
// // if (this.devMode) {
|
|
445
|
-
// // if (this.mode === "up") {
|
|
446
|
-
// // console.log(this.spinner(), upMessage);
|
|
447
|
-
// // } else {
|
|
448
|
-
// // console.log(this.spinner(), downMessage);
|
|
449
|
-
// // }
|
|
450
|
-
|
|
451
|
-
// // } else {
|
|
452
|
-
// // if (this.mode === "up") {
|
|
453
|
-
// // console.log(this.spinner(), upMessage);
|
|
454
|
-
// // } else {
|
|
455
|
-
// // console.log(this.spinner(), downMessage);
|
|
456
|
-
// // }
|
|
457
|
-
// // }
|
|
458
|
-
// // });
|
|
459
|
-
// };
|
|
460
203
|
}
|
|
461
204
|
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
// port: 8080,
|
|
473
|
-
// host: "localhost",
|
|
474
|
-
// });
|
|
475
|
-
|
|
476
|
-
// webSocketServer.on('open', () => {
|
|
477
|
-
// console.log('open');
|
|
478
|
-
// });
|
|
479
|
-
|
|
480
|
-
// webSocketServer.on('close', (data) => {
|
|
481
|
-
// console.log('webSocketServer close: %s', data);
|
|
482
|
-
// });
|
|
483
|
-
|
|
484
|
-
// webSocketServer.on('listening', () => {
|
|
485
|
-
// console.log("webSocketServer listening", webSocketServer.address());
|
|
486
|
-
// });
|
|
487
|
-
|
|
488
|
-
// webSocketServer.on('connection', (webSocket: WebSocket) => {
|
|
489
|
-
// webSocket.on('message', (webSocketData) => {
|
|
490
|
-
// const payload = JSON.parse(webSocketData.valueOf().toString() as any);
|
|
491
|
-
// const messageType = payload.type;
|
|
492
|
-
|
|
493
|
-
// if (messageType === "testeranto:hola") {
|
|
494
|
-
// const name = payload.data.requirement.name;
|
|
495
|
-
// const requestedResources = payload.data;
|
|
496
|
-
|
|
497
|
-
// this.websockets[name] = webSocket
|
|
498
|
-
// console.log('hola WS! connected: ' + name + ' in ' + Object.getOwnPropertyNames(this.websockets))
|
|
499
|
-
// this.requestResource(requestedResources.requirement, 'ws');
|
|
500
|
-
|
|
501
|
-
// } else if (messageType === "testeranto:adios") {
|
|
502
|
-
// console.log("adios WS", payload.data.testResourceConfiguration.name);
|
|
503
|
-
// this.releaseTestResourceWs(payload as any);
|
|
504
|
-
// }
|
|
505
|
-
|
|
506
|
-
// });
|
|
507
|
-
// });
|
|
508
|
-
|
|
509
|
-
// const makePath = (fPath: string, rt: IRunTime): string => {
|
|
510
|
-
// return path.resolve("./" + config.outdir + "/" +
|
|
511
|
-
// rt +
|
|
512
|
-
// // (rt === "electron" || rt === "chromium" ? "web" : "node") +
|
|
513
|
-
// "/" + fPath.replace(path.extname(fPath), "") + ".mjs");
|
|
514
|
-
// };
|
|
515
|
-
|
|
516
|
-
// const bootInterval = setInterval(async () => {
|
|
517
|
-
// const filesToLookup = this.tests
|
|
518
|
-
// .map(([p, rt]) => {
|
|
519
|
-
// const filepath = makePath(p, rt);
|
|
520
|
-
// return {
|
|
521
|
-
// filepath,
|
|
522
|
-
// exists: fsExists(filepath),
|
|
523
|
-
// };
|
|
524
|
-
// });
|
|
525
|
-
// const allFilesExist = (
|
|
526
|
-
// await Promise.all(filesToLookup.map((f) => f.exists))
|
|
527
|
-
// ).every((b) => b);
|
|
528
|
-
|
|
529
|
-
// if (!allFilesExist) {
|
|
530
|
-
// console.log(this.spinner(), "waiting for files to build...")
|
|
531
|
-
// filesToLookup.forEach((f) => {
|
|
532
|
-
// console.log(f.exists, "\t", f.filepath);
|
|
533
|
-
// })
|
|
534
|
-
|
|
535
|
-
// } else {
|
|
536
|
-
// clearInterval(bootInterval);
|
|
537
|
-
|
|
538
|
-
// pm2.launchBus((err, pm2_bus) => {
|
|
539
|
-
// pm2_bus.on("testeranto:hola", (packet: { data: { requirement: ITTestResourceRequirement } }) => {
|
|
540
|
-
// this.requestResource(
|
|
541
|
-
// packet.data.requirement,
|
|
542
|
-
// 'ipc'
|
|
543
|
-
// );
|
|
544
|
-
// });
|
|
545
|
-
|
|
546
|
-
// pm2_bus.on("testeranto:adios", (payload: IAdiosIPC) => {
|
|
547
|
-
// this.releaseTestResourcePm2(payload.data);
|
|
548
|
-
// });
|
|
549
|
-
// });
|
|
550
|
-
|
|
551
|
-
// this
|
|
552
|
-
// .tests
|
|
553
|
-
// .reduce((m, [inputFilePath, runtime]) => {
|
|
554
|
-
// const script = makePath(inputFilePath, runtime);
|
|
555
|
-
// const partialTestResourceByCommandLineArg = `${script} '${JSON.stringify(
|
|
556
|
-
// {
|
|
557
|
-
// name: inputFilePath,
|
|
558
|
-
// ports: [],
|
|
559
|
-
// fs: path.resolve(
|
|
560
|
-
// process.cwd(),
|
|
561
|
-
// config.outdir,
|
|
562
|
-
// inputFilePath
|
|
563
|
-
// ),
|
|
564
|
-
// }
|
|
565
|
-
// )}'`;
|
|
566
|
-
|
|
567
|
-
// if (runtime === "web") {
|
|
568
|
-
// pm2.start(electron_pm2_StartOptions(
|
|
569
|
-
// partialTestResourceByCommandLineArg,
|
|
570
|
-
// inputFilePath,
|
|
571
|
-
// config
|
|
572
|
-
// ),
|
|
573
|
-
// (err, proc) => {
|
|
574
|
-
// if (err) {
|
|
575
|
-
// console.error(err);
|
|
576
|
-
// return pm2.disconnect();
|
|
577
|
-
// }
|
|
578
|
-
// }
|
|
579
|
-
// );
|
|
580
|
-
|
|
581
|
-
// // } else if (runtime === "chromium") {
|
|
582
|
-
// // pm2.start(
|
|
583
|
-
// // chromium_pm2_StartOptions(
|
|
584
|
-
// // partialTestResourceByCommandLineArg,
|
|
585
|
-
// // inputFilePath,
|
|
586
|
-
// // config,
|
|
587
|
-
// // ),
|
|
588
|
-
// // (err, proc) => {
|
|
589
|
-
// // if (err) {
|
|
590
|
-
// // console.error(err);
|
|
591
|
-
// // return pm2.disconnect();
|
|
592
|
-
// // }
|
|
593
|
-
// // }
|
|
594
|
-
// // );
|
|
595
|
-
|
|
596
|
-
// } else if (runtime === "node") {
|
|
597
|
-
// const resolvedPath = path.resolve(script);
|
|
598
|
-
|
|
599
|
-
// console.log("watching", resolvedPath);
|
|
600
|
-
// pm2.start(node_pm2_StartOptions(
|
|
601
|
-
// partialTestResourceByCommandLineArg,
|
|
602
|
-
// inputFilePath,
|
|
603
|
-
// config,
|
|
604
|
-
// resolvedPath
|
|
605
|
-
// ), (err, proc) => {
|
|
606
|
-
// if (err) {
|
|
607
|
-
// console.error(err);
|
|
608
|
-
// return pm2.disconnect();
|
|
609
|
-
// }
|
|
610
|
-
// });
|
|
611
|
-
// }
|
|
612
|
-
|
|
613
|
-
// this.exitCodes[inputFilePath] = null;
|
|
614
|
-
// return [inputFilePath, ...m];
|
|
615
|
-
// }, []);
|
|
616
|
-
// setInterval(this.mainLoop, TIMEOUT).unref();
|
|
617
|
-
// }
|
|
618
|
-
// }, TIMEOUT).unref();
|
|
619
|
-
// });
|
|
620
|
-
// public requestResource(
|
|
621
|
-
// requirement: ITTestResourceRequirement,
|
|
622
|
-
// protocol: ISchedulerProtocols
|
|
623
|
-
// ) {
|
|
624
|
-
// this.resourceQueue.push({ requirement, protocol });
|
|
625
|
-
// }
|
|
626
|
-
// const OPEN_PORT = "";
|
|
627
|
-
|
|
628
|
-
// type ISchedulerProtocols = `ipc` | `ws`;
|
|
629
|
-
|
|
630
|
-
// type IAdios = {
|
|
631
|
-
// name: string;
|
|
632
|
-
// failed: any;
|
|
633
|
-
// testResourceConfiguration: {
|
|
634
|
-
// name: string;
|
|
635
|
-
// };
|
|
636
|
-
// results: {
|
|
637
|
-
// fails: any[];
|
|
638
|
-
// givens: any[];
|
|
639
|
-
// name: string;
|
|
640
|
-
// };
|
|
641
|
-
// };
|
|
642
|
-
|
|
643
|
-
// type IAdiosIPC = {
|
|
644
|
-
// process: {
|
|
645
|
-
// namespace: string;
|
|
646
|
-
// versioning: object;
|
|
647
|
-
// name: string;
|
|
648
|
-
// pm_id: number;
|
|
649
|
-
// };
|
|
650
|
-
// data: IAdios
|
|
651
|
-
// at: string;
|
|
652
|
-
// };
|
|
653
|
-
// clearScreen: boolean;
|
|
654
|
-
// devMode: boolean;
|
|
655
|
-
// exitCodes: Record<number, string> = {};
|
|
656
|
-
// features: TesterantoFeatures;
|
|
657
|
-
|
|
658
|
-
// ports: Record<string, string> = {};
|
|
659
|
-
// tests: ITestTypes[];
|
|
660
|
-
// websockets: Record<string, WebSocket> = {};
|
|
661
|
-
|
|
662
|
-
// resourceQueue: {
|
|
663
|
-
// requirement: ITTestResourceRequirement,
|
|
664
|
-
// protocol: ISchedulerProtocols,
|
|
665
|
-
// }[] = [];
|
|
205
|
+
const getRunnables = (
|
|
206
|
+
tests: ITestTypes[],
|
|
207
|
+
payload = [new Set<string>(), new Set<string>()]
|
|
208
|
+
): [Set<string>, Set<string>] => {
|
|
209
|
+
return tests.reduce((pt, cv, cndx, cry) => {
|
|
210
|
+
if (cv[1] === "node") {
|
|
211
|
+
pt[0].add(cv[0]);
|
|
212
|
+
} else if (cv[1] === "web") {
|
|
213
|
+
pt[1].add(cv[0]);
|
|
214
|
+
}
|
|
666
215
|
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
// childElectron.stdin.write(JSON.stringify(this.tests));
|
|
671
|
-
// not necessary
|
|
672
|
-
// this.esWebServerDetails = await eWeb.serve({
|
|
673
|
-
// servedir: jsonConfig.outdir,
|
|
674
|
-
// });
|
|
216
|
+
if (cv[2].length) {
|
|
217
|
+
getRunnables(cv[2], payload);
|
|
218
|
+
}
|
|
675
219
|
|
|
676
|
-
|
|
677
|
-
|
|
220
|
+
return pt;
|
|
221
|
+
}, payload as [Set<string>, Set<string>]);
|
|
222
|
+
};
|