testeranto 0.200.0 → 0.200.1

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.
@@ -0,0 +1,3249 @@
1
+ import { createRequire } from 'module';const require = createRequire(import.meta.url);
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __esm = (fn, res) => function __init() {
5
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
6
+ };
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+
12
+ // src/utils.ts
13
+ import path from "path";
14
+ var tscPather, lintPather, promptPather, getRunnables;
15
+ var init_utils = __esm({
16
+ "src/utils.ts"() {
17
+ "use strict";
18
+ tscPather = (entryPoint, platform, projectName) => {
19
+ return path.join(
20
+ "testeranto",
21
+ "reports",
22
+ projectName,
23
+ entryPoint.split(".").slice(0, -1).join("."),
24
+ platform,
25
+ `type_errors.txt`
26
+ );
27
+ };
28
+ lintPather = (entryPoint, platform, projectName) => {
29
+ return path.join(
30
+ "testeranto",
31
+ "reports",
32
+ projectName,
33
+ entryPoint.split(".").slice(0, -1).join("."),
34
+ platform,
35
+ `lint_errors.txt`
36
+ );
37
+ };
38
+ promptPather = (entryPoint, platform, projectName) => {
39
+ return path.join(
40
+ "testeranto",
41
+ "reports",
42
+ projectName,
43
+ entryPoint.split(".").slice(0, -1).join("."),
44
+ platform,
45
+ `prompt.txt`
46
+ );
47
+ };
48
+ getRunnables = (tests, projectName, payload = {
49
+ pythonEntryPoints: {},
50
+ nodeEntryPoints: {},
51
+ nodeEntryPointSidecars: {},
52
+ webEntryPoints: {},
53
+ webEntryPointSidecars: {},
54
+ pureEntryPoints: {},
55
+ pureEntryPointSidecars: {},
56
+ golangEntryPoints: {},
57
+ golangEntryPointSidecars: {},
58
+ pitonoEntryPoints: {},
59
+ pitonoEntryPointSidecars: {}
60
+ }) => {
61
+ const initializedPayload = {
62
+ pythonEntryPoints: payload.pythonEntryPoints || {},
63
+ nodeEntryPoints: payload.nodeEntryPoints || {},
64
+ nodeEntryPointSidecars: payload.nodeEntryPointSidecars || {},
65
+ webEntryPoints: payload.webEntryPoints || {},
66
+ webEntryPointSidecars: payload.webEntryPointSidecars || {},
67
+ pureEntryPoints: payload.pureEntryPoints || {},
68
+ pureEntryPointSidecars: payload.pureEntryPointSidecars || {},
69
+ golangEntryPoints: payload.golangEntryPoints || {},
70
+ golangEntryPointSidecars: payload.golangEntryPointSidecars || {},
71
+ pitonoEntryPoints: payload.pitonoEntryPoints || {},
72
+ pitonoEntryPointSidecars: payload.pitonoEntryPointSidecars || {}
73
+ };
74
+ return tests.reduce((pt, cv, cndx, cry) => {
75
+ if (cv[1] === "node") {
76
+ pt.nodeEntryPoints[cv[0]] = path.resolve(
77
+ `./testeranto/bundles/node/${projectName}/${cv[0].split(".").slice(0, -1).concat("mjs").join(".")}`
78
+ );
79
+ } else if (cv[1] === "web") {
80
+ pt.webEntryPoints[cv[0]] = path.resolve(
81
+ `./testeranto/bundles/web/${projectName}/${cv[0].split(".").slice(0, -1).concat("mjs").join(".")}`
82
+ );
83
+ } else if (cv[1] === "pure") {
84
+ pt.pureEntryPoints[cv[0]] = path.resolve(
85
+ `./testeranto/bundles/pure/${projectName}/${cv[0].split(".").slice(0, -1).concat("mjs").join(".")}`
86
+ );
87
+ } else if (cv[1] === "golang") {
88
+ pt.golangEntryPoints[cv[0]] = path.resolve(cv[0]);
89
+ } else if (cv[1] === "pitono") {
90
+ pt.pitonoEntryPoints[cv[0]] = path.resolve(cv[0]);
91
+ }
92
+ cv[3].filter((t) => t[1] === "node").forEach((t) => {
93
+ pt.nodeEntryPointSidecars[`${t[0]}`] = path.resolve(
94
+ `./testeranto/bundles/node/${projectName}/${cv[0].split(".").slice(0, -1).concat("mjs").join(".")}`
95
+ );
96
+ });
97
+ cv[3].filter((t) => t[1] === "web").forEach((t) => {
98
+ pt.webEntryPointSidecars[`${t[0]}`] = path.resolve(
99
+ `./testeranto/bundles/web/${projectName}/${cv[0].split(".").slice(0, -1).concat("mjs").join(".")}`
100
+ );
101
+ });
102
+ cv[3].filter((t) => t[1] === "pure").forEach((t) => {
103
+ pt.pureEntryPointSidecars[`${t[0]}`] = path.resolve(
104
+ `./testeranto/bundles/pure/${projectName}/${cv[0].split(".").slice(0, -1).concat("mjs").join(".")}`
105
+ );
106
+ });
107
+ cv[3].filter((t) => t[1] === "golang").forEach((t) => {
108
+ pt.golangEntryPointSidecars[`${t[0]}`] = path.resolve(t[0]);
109
+ });
110
+ cv[3].filter((t) => t[1] === "pitono").forEach((t) => {
111
+ pt.pitonoEntryPointSidecars[`${t[0]}`] = path.resolve(t[0]);
112
+ });
113
+ return pt;
114
+ }, initializedPayload);
115
+ };
116
+ }
117
+ });
118
+
119
+ // src/utils/queue.ts
120
+ var Queue;
121
+ var init_queue = __esm({
122
+ "src/utils/queue.ts"() {
123
+ "use strict";
124
+ Queue = class {
125
+ constructor() {
126
+ this.items = [];
127
+ }
128
+ enqueue(element) {
129
+ this.items.push(element);
130
+ }
131
+ dequeue() {
132
+ if (this.isEmpty()) {
133
+ return "Queue is empty";
134
+ }
135
+ return this.items.shift();
136
+ }
137
+ peek() {
138
+ if (this.isEmpty()) {
139
+ return "Queue is empty";
140
+ }
141
+ return this.items[0];
142
+ }
143
+ isEmpty() {
144
+ return this.items.length === 0;
145
+ }
146
+ size() {
147
+ return this.items.length;
148
+ }
149
+ clear() {
150
+ this.items = [];
151
+ }
152
+ print() {
153
+ console.log(this.items.join(" -> "));
154
+ }
155
+ };
156
+ }
157
+ });
158
+
159
+ // src/PM/base.ts
160
+ import fs4 from "fs";
161
+ import path4 from "path";
162
+ var fileStreams3, fPaths, files, recorders, screenshots, PM_Base;
163
+ var init_base = __esm({
164
+ "src/PM/base.ts"() {
165
+ "use strict";
166
+ fileStreams3 = [];
167
+ fPaths = [];
168
+ files = {};
169
+ recorders = {};
170
+ screenshots = {};
171
+ PM_Base = class {
172
+ constructor(configs) {
173
+ this.configs = configs;
174
+ }
175
+ customclose() {
176
+ throw new Error("customclose not implemented.");
177
+ }
178
+ waitForSelector(p, s) {
179
+ return new Promise((res) => {
180
+ this.doInPage(p, async (page) => {
181
+ const x = page.$(s);
182
+ const y = await x;
183
+ res(y !== null);
184
+ });
185
+ });
186
+ }
187
+ closePage(p) {
188
+ return new Promise((res) => {
189
+ this.doInPage(p, async (page) => {
190
+ page.close();
191
+ res({});
192
+ });
193
+ });
194
+ }
195
+ async newPage() {
196
+ return (await this.browser.newPage()).mainFrame()._id;
197
+ }
198
+ goto(p, url2) {
199
+ return new Promise((res) => {
200
+ this.doInPage(p, async (page) => {
201
+ await page?.goto(url2);
202
+ res({});
203
+ });
204
+ });
205
+ }
206
+ $(selector, p) {
207
+ return new Promise((res) => {
208
+ this.doInPage(p, async (page) => {
209
+ const x = await page.$(selector);
210
+ const y = await x?.jsonValue();
211
+ res(y);
212
+ });
213
+ });
214
+ }
215
+ async pages() {
216
+ return (await this.browser.pages()).map((p) => {
217
+ return p.mainFrame()._id;
218
+ });
219
+ }
220
+ async screencast(ssOpts, testName2, page) {
221
+ const p = ssOpts.path;
222
+ const dir = path4.dirname(p);
223
+ fs4.mkdirSync(dir, {
224
+ recursive: true
225
+ });
226
+ if (!files[testName2]) {
227
+ files[testName2] = /* @__PURE__ */ new Set();
228
+ }
229
+ files[testName2].add(ssOpts.path);
230
+ const sPromise = page.screenshot({
231
+ ...ssOpts,
232
+ path: p
233
+ });
234
+ if (!screenshots[testName2]) {
235
+ screenshots[testName2] = [];
236
+ }
237
+ screenshots[testName2].push(sPromise);
238
+ await sPromise;
239
+ return sPromise;
240
+ }
241
+ async customScreenShot(ssOpts, testName2, pageUid) {
242
+ const p = ssOpts.path;
243
+ const dir = path4.dirname(p);
244
+ fs4.mkdirSync(dir, {
245
+ recursive: true
246
+ });
247
+ if (!files[testName2]) {
248
+ files[testName2] = /* @__PURE__ */ new Set();
249
+ }
250
+ files[testName2].add(ssOpts.path);
251
+ const page = (await this.browser.pages()).find(
252
+ (p2) => p2.mainFrame()._id === pageUid
253
+ );
254
+ const sPromise = page.screenshot({
255
+ ...ssOpts,
256
+ path: p
257
+ });
258
+ if (!screenshots[testName2]) {
259
+ screenshots[testName2] = [];
260
+ }
261
+ screenshots[testName2].push(sPromise);
262
+ await sPromise;
263
+ return sPromise;
264
+ }
265
+ async end(uid) {
266
+ await fileStreams3[uid].end();
267
+ return true;
268
+ }
269
+ existsSync(destFolder) {
270
+ return fs4.existsSync(destFolder);
271
+ }
272
+ async mkdirSync(fp) {
273
+ if (!fs4.existsSync(fp)) {
274
+ return fs4.mkdirSync(fp, {
275
+ recursive: true
276
+ });
277
+ }
278
+ return false;
279
+ }
280
+ async writeFileSync(...x) {
281
+ const filepath = x[0];
282
+ const contents = x[1];
283
+ const testName2 = x[2];
284
+ return new Promise(async (res) => {
285
+ fs4.mkdirSync(path4.dirname(filepath), {
286
+ recursive: true
287
+ });
288
+ if (!files[testName2]) {
289
+ files[testName2] = /* @__PURE__ */ new Set();
290
+ }
291
+ files[testName2].add(filepath);
292
+ await fs4.writeFileSync(filepath, contents);
293
+ res(true);
294
+ });
295
+ }
296
+ async createWriteStream(filepath, testName2) {
297
+ const folder = filepath.split("/").slice(0, -1).join("/");
298
+ return new Promise((res) => {
299
+ if (!fs4.existsSync(folder)) {
300
+ return fs4.mkdirSync(folder, {
301
+ recursive: true
302
+ });
303
+ }
304
+ const f2 = fs4.createWriteStream(filepath);
305
+ fileStreams3.push(f2);
306
+ if (!files[testName2]) {
307
+ files[testName2] = /* @__PURE__ */ new Set();
308
+ }
309
+ files[testName2].add(filepath);
310
+ res(fileStreams3.length - 1);
311
+ });
312
+ }
313
+ testArtiFactoryfileWriter(tLog, callback) {
314
+ return (fPath, value) => {
315
+ callback(
316
+ new Promise((res, rej) => {
317
+ tLog("testArtiFactory =>", fPath);
318
+ const cleanPath = path4.resolve(fPath);
319
+ fPaths.push(cleanPath.replace(process.cwd(), ``));
320
+ const targetDir = cleanPath.split("/").slice(0, -1).join("/");
321
+ fs4.mkdir(targetDir, { recursive: true }, async (error) => {
322
+ if (error) {
323
+ console.error(`\u2757\uFE0FtestArtiFactory failed`, targetDir, error);
324
+ }
325
+ fs4.writeFileSync(
326
+ path4.resolve(
327
+ targetDir.split("/").slice(0, -1).join("/"),
328
+ "manifest"
329
+ ),
330
+ fPaths.join(`
331
+ `),
332
+ {
333
+ encoding: "utf-8"
334
+ }
335
+ );
336
+ if (Buffer.isBuffer(value)) {
337
+ fs4.writeFileSync(fPath, value, "binary");
338
+ res();
339
+ } else if (`string` === typeof value) {
340
+ fs4.writeFileSync(fPath, value.toString(), {
341
+ encoding: "utf-8"
342
+ });
343
+ res();
344
+ } else {
345
+ const pipeStream = value;
346
+ const myFile = fs4.createWriteStream(fPath);
347
+ pipeStream.pipe(myFile);
348
+ pipeStream.on("close", () => {
349
+ myFile.close();
350
+ res();
351
+ });
352
+ }
353
+ });
354
+ })
355
+ );
356
+ };
357
+ }
358
+ async write(uid, contents) {
359
+ return new Promise((res) => {
360
+ const x = fileStreams3[uid].write(contents);
361
+ res(x);
362
+ });
363
+ }
364
+ page(p) {
365
+ return p;
366
+ }
367
+ click(selector, page) {
368
+ return page.click(selector);
369
+ }
370
+ async focusOn(selector, p) {
371
+ this.doInPage(p, (page) => {
372
+ return page.focus(selector);
373
+ });
374
+ }
375
+ async typeInto(value, p) {
376
+ this.doInPage(p, (page) => {
377
+ return page.keyboard.type(value);
378
+ });
379
+ }
380
+ // setValue(value: string, p: string) {
381
+ // this.doInPage(p, (page) => {
382
+ // return page.keyboard.type(value);
383
+ // });
384
+ // }
385
+ getAttribute(selector, attribute, p) {
386
+ this.doInPage(p, (page) => {
387
+ return page.$eval(selector, (input) => input.getAttribute(attribute));
388
+ });
389
+ }
390
+ async getInnerHtml(selector, p) {
391
+ return new Promise((res, rej) => {
392
+ this.doInPage(p, async (page) => {
393
+ const e = await page.$(selector);
394
+ if (!e) {
395
+ rej();
396
+ } else {
397
+ const text = await (await e.getProperty("textContent")).jsonValue();
398
+ res(text);
399
+ }
400
+ });
401
+ });
402
+ }
403
+ isDisabled(selector, p) {
404
+ this.doInPage(p, async (page) => {
405
+ return await page.$eval(selector, (input) => {
406
+ return input.disabled;
407
+ });
408
+ });
409
+ }
410
+ screencastStop(s) {
411
+ return recorders[s].stop();
412
+ }
413
+ async doInPage(p, cb) {
414
+ (await this.browser.pages()).forEach((page) => {
415
+ const frame = page.mainFrame();
416
+ if (frame._id === p) {
417
+ return cb(page);
418
+ }
419
+ });
420
+ }
421
+ };
422
+ }
423
+ });
424
+
425
+ // src/utils/logFiles.ts
426
+ function getLogFilesForRuntime(runtime) {
427
+ const { standard, runtimeSpecific } = getRuntimeLogs(runtime);
428
+ return [...standard, ...runtimeSpecific];
429
+ }
430
+ var LOG_FILES, STANDARD_LOGS, RUNTIME_SPECIFIC_LOGS, ALL_LOGS, getRuntimeLogs;
431
+ var init_logFiles = __esm({
432
+ "src/utils/logFiles.ts"() {
433
+ "use strict";
434
+ LOG_FILES = {
435
+ TESTS: "tests.json",
436
+ TYPE_ERRORS: "type_errors.txt",
437
+ LINT_ERRORS: "lint_errors.txt",
438
+ EXIT: "exit.log",
439
+ MESSAGE: "message.txt",
440
+ PROMPT: "prompt.txt",
441
+ STDOUT: "stdout.log",
442
+ STDERR: "stderr.log",
443
+ INFO: "info.log",
444
+ ERROR: "error.log",
445
+ WARN: "warn.log",
446
+ DEBUG: "debug.log"
447
+ };
448
+ STANDARD_LOGS = {
449
+ TESTS: "tests.json",
450
+ TYPE_ERRORS: "type_errors.txt",
451
+ LINT_ERRORS: "lint_errors.txt",
452
+ EXIT: "exit.log",
453
+ MESSAGE: "message.txt",
454
+ PROMPT: "prompt.txt",
455
+ BUILD: "build.json"
456
+ };
457
+ RUNTIME_SPECIFIC_LOGS = {
458
+ node: {
459
+ STDOUT: "stdout.log",
460
+ STDERR: "stderr.log"
461
+ },
462
+ web: {
463
+ INFO: "info.log",
464
+ ERROR: "error.log",
465
+ WARN: "warn.log",
466
+ DEBUG: "debug.log"
467
+ },
468
+ pure: {}
469
+ // No runtime-specific logs for pure
470
+ };
471
+ ALL_LOGS = {
472
+ ...STANDARD_LOGS,
473
+ ...Object.values(RUNTIME_SPECIFIC_LOGS).reduce((acc, logs) => ({ ...acc, ...logs }), {})
474
+ };
475
+ getRuntimeLogs = (runtime) => {
476
+ return {
477
+ standard: Object.values(STANDARD_LOGS),
478
+ runtimeSpecific: Object.values(RUNTIME_SPECIFIC_LOGS[runtime])
479
+ };
480
+ };
481
+ }
482
+ });
483
+
484
+ // src/utils/makePrompt.ts
485
+ import fs5 from "fs";
486
+ import path5 from "path";
487
+ var makePrompt, makePromptInternal;
488
+ var init_makePrompt = __esm({
489
+ "src/utils/makePrompt.ts"() {
490
+ "use strict";
491
+ init_utils();
492
+ init_logFiles();
493
+ init_logFiles();
494
+ makePrompt = async (summary, name, entryPoint, addableFiles, runtime) => {
495
+ summary[entryPoint].prompt = "?";
496
+ const promptPath = promptPather(entryPoint, runtime, name);
497
+ const testDir = path5.join(
498
+ "testeranto",
499
+ "reports",
500
+ name,
501
+ entryPoint.split(".").slice(0, -1).join("."),
502
+ runtime
503
+ );
504
+ if (!fs5.existsSync(testDir)) {
505
+ fs5.mkdirSync(testDir, { recursive: true });
506
+ }
507
+ const testPaths = path5.join(testDir, LOG_FILES.TESTS);
508
+ const lintPath = path5.join(testDir, LOG_FILES.LINT_ERRORS);
509
+ const typePath = path5.join(testDir, LOG_FILES.TYPE_ERRORS);
510
+ const messagePath = path5.join(testDir, LOG_FILES.MESSAGE);
511
+ try {
512
+ await Promise.all([
513
+ fs5.promises.writeFile(
514
+ promptPath,
515
+ `
516
+ ${addableFiles.map((x) => {
517
+ return `/add ${x}`;
518
+ }).join("\n")}
519
+
520
+ /read node_modules/testeranto/docs/index.md
521
+ /read node_modules/testeranto/docs/style.md
522
+ /read node_modules/testeranto/docs/testing.ai.txt
523
+ /read node_modules/testeranto/src/CoreTypes.ts
524
+
525
+ /read ${testPaths}
526
+ /read ${typePath}
527
+ /read ${lintPath}
528
+
529
+ /read ${getLogFilesForRuntime(runtime).map((p) => `${testDir}/${p}`).join(" ")}
530
+ `
531
+ ),
532
+ fs5.promises.writeFile(
533
+ messagePath,
534
+ `
535
+ There are 3 types of test reports.
536
+ 1) bdd (highest priority)
537
+ 2) type checker
538
+ 3) static analysis (lowest priority)
539
+
540
+ "tests.json" is the detailed result of the bdd tests.
541
+ if these files do not exist, then something has gone badly wrong and needs to be addressed.
542
+
543
+ "type_errors.txt" is the result of the type checker.
544
+ if this file does not exist, then type check passed without errors;
545
+
546
+ "lint_errors.txt" is the result of the static analysis.
547
+ if this file does not exist, then static analysis passed without errors;
548
+
549
+ BDD failures are the highest priority. Focus on passing BDD tests before addressing other concerns.
550
+ Do not add error throwing/catching to the tests themselves.
551
+ `
552
+ )
553
+ ]);
554
+ } catch (e) {
555
+ console.error(`Failed to write prompt files at ${testDir}`);
556
+ console.error(e);
557
+ throw e;
558
+ }
559
+ summary[entryPoint].prompt = `aider --model deepseek/deepseek-chat --load testeranto/${name}/reports/${runtime}/${entryPoint.split(".").slice(0, -1).join(".")}/prompt.txt`;
560
+ };
561
+ makePromptInternal = (summary, name, entryPoint, addableFiles, runTime) => {
562
+ if (runTime === "node") {
563
+ return makePrompt(summary, name, entryPoint, addableFiles, "node");
564
+ }
565
+ if (runTime === "web") {
566
+ return makePrompt(summary, name, entryPoint, addableFiles, "web");
567
+ }
568
+ if (runTime === "pure") {
569
+ return makePrompt(summary, name, entryPoint, addableFiles, "pure");
570
+ }
571
+ };
572
+ }
573
+ });
574
+
575
+ // src/PM/PM_WithEslintAndTsc.ts
576
+ import ts from "typescript";
577
+ import fs6 from "fs";
578
+ import ansiC from "ansi-colors";
579
+ import { ESLint } from "eslint";
580
+ import tsc from "tsc-prog";
581
+ var eslint, formatter, PM_WithEslintAndTsc;
582
+ var init_PM_WithEslintAndTsc = __esm({
583
+ async "src/PM/PM_WithEslintAndTsc.ts"() {
584
+ "use strict";
585
+ init_utils();
586
+ init_base();
587
+ init_makePrompt();
588
+ eslint = new ESLint();
589
+ formatter = await eslint.loadFormatter(
590
+ "./node_modules/testeranto/dist/prebuild/esbuildConfigs/eslint-formatter-testeranto.mjs"
591
+ );
592
+ PM_WithEslintAndTsc = class extends PM_Base {
593
+ constructor(configs, name, mode2) {
594
+ super(configs);
595
+ this.summary = {};
596
+ this.tscCheck = async ({
597
+ entrypoint,
598
+ addableFiles,
599
+ platform
600
+ }) => {
601
+ console.log(ansiC.green(ansiC.inverse(`tsc < ${entrypoint}`)));
602
+ try {
603
+ this.typeCheckIsRunning(entrypoint);
604
+ } catch (e) {
605
+ console.error("error in tscCheck");
606
+ console.error(e);
607
+ console.error(entrypoint);
608
+ console.error(JSON.stringify(this.summary, null, 2));
609
+ process.exit(-1);
610
+ }
611
+ const program = tsc.createProgramFromConfig({
612
+ basePath: process.cwd(),
613
+ // always required, used for relative paths
614
+ configFilePath: "tsconfig.json",
615
+ // config to inherit from (optional)
616
+ compilerOptions: {
617
+ outDir: tscPather(entrypoint, platform, this.name),
618
+ // declaration: true,
619
+ // skipLibCheck: true,
620
+ noEmit: true
621
+ },
622
+ include: addableFiles
623
+ //["src/**/*"],
624
+ // exclude: ["node_modules", "../testeranto"],
625
+ // exclude: ["**/*.test.ts", "**/*.spec.ts"],
626
+ });
627
+ const tscPath = tscPather(entrypoint, platform, this.name);
628
+ const allDiagnostics = program.getSemanticDiagnostics();
629
+ const results = [];
630
+ allDiagnostics.forEach((diagnostic) => {
631
+ if (diagnostic.file) {
632
+ const { line, character } = ts.getLineAndCharacterOfPosition(
633
+ diagnostic.file,
634
+ diagnostic.start
635
+ );
636
+ const message = ts.flattenDiagnosticMessageText(
637
+ diagnostic.messageText,
638
+ "\n"
639
+ );
640
+ results.push(
641
+ `${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`
642
+ );
643
+ } else {
644
+ results.push(
645
+ ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n")
646
+ );
647
+ }
648
+ });
649
+ fs6.writeFileSync(tscPath, results.join("\n"));
650
+ this.typeCheckIsNowDone(entrypoint, results.length);
651
+ };
652
+ this.eslintCheck = async (entrypoint, platform, addableFiles) => {
653
+ console.log(ansiC.green(ansiC.inverse(`eslint < ${entrypoint}`)));
654
+ try {
655
+ this.lintIsRunning(entrypoint);
656
+ } catch (e) {
657
+ console.error("error in eslintCheck");
658
+ console.error(e);
659
+ console.error(entrypoint);
660
+ console.error(JSON.stringify(this.summary, null, 2));
661
+ process.exit(-1);
662
+ }
663
+ const filepath = lintPather(entrypoint, platform, this.name);
664
+ if (fs6.existsSync(filepath))
665
+ fs6.rmSync(filepath);
666
+ const results = (await eslint.lintFiles(addableFiles)).filter((r) => r.messages.length).filter((r) => {
667
+ return r.messages[0].ruleId !== null;
668
+ }).map((r) => {
669
+ delete r.source;
670
+ return r;
671
+ });
672
+ fs6.writeFileSync(filepath, await formatter.format(results));
673
+ this.lintIsNowDone(entrypoint, results.length);
674
+ };
675
+ this.makePrompt = async (entryPoint, addableFiles, platform) => {
676
+ await makePromptInternal(
677
+ this.summary,
678
+ this.name,
679
+ entryPoint,
680
+ addableFiles,
681
+ platform
682
+ );
683
+ this.checkForShutdown();
684
+ };
685
+ this.typeCheckIsRunning = (src) => {
686
+ if (!this.summary[src]) {
687
+ throw `this.summary[${src}] is undefined`;
688
+ }
689
+ this.summary[src].typeErrors = "?";
690
+ };
691
+ this.typeCheckIsNowDone = (src, failures) => {
692
+ if (!this.summary[src]) {
693
+ throw `this.summary[${src}] is undefined`;
694
+ }
695
+ if (failures === 0) {
696
+ console.log(ansiC.green(ansiC.inverse(`tsc > ${src}`)));
697
+ } else {
698
+ console.log(
699
+ ansiC.red(ansiC.inverse(`tsc > ${src} failed ${failures} times`))
700
+ );
701
+ }
702
+ this.summary[src].typeErrors = failures;
703
+ this.writeBigBoard();
704
+ this.checkForShutdown();
705
+ };
706
+ this.lintIsRunning = (src) => {
707
+ if (!this.summary[src]) {
708
+ throw `this.summary[${src}] is undefined`;
709
+ }
710
+ this.summary[src].staticErrors = "?";
711
+ this.writeBigBoard();
712
+ };
713
+ this.lintIsNowDone = (src, failures) => {
714
+ if (!this.summary[src]) {
715
+ throw `this.summary[${src}] is undefined`;
716
+ }
717
+ if (failures === 0) {
718
+ console.log(ansiC.green(ansiC.inverse(`eslint > ${src}`)));
719
+ } else {
720
+ console.log(
721
+ ansiC.red(ansiC.inverse(`eslint > ${src} failed ${failures} times`))
722
+ );
723
+ }
724
+ this.summary[src].staticErrors = failures;
725
+ this.writeBigBoard();
726
+ this.checkForShutdown();
727
+ };
728
+ this.bddTestIsRunning = (src) => {
729
+ if (!this.summary[src]) {
730
+ throw `this.summary[${src}] is undefined`;
731
+ }
732
+ this.summary[src].runTimeErrors = "?";
733
+ this.writeBigBoard();
734
+ };
735
+ this.bddTestIsNowDone = (src, failures) => {
736
+ if (!this.summary[src]) {
737
+ throw `this.summary[${src}] is undefined`;
738
+ }
739
+ this.summary[src].runTimeErrors = failures;
740
+ this.writeBigBoard();
741
+ this.checkForShutdown();
742
+ };
743
+ this.writeBigBoard = () => {
744
+ const summaryPath = `./testeranto/reports/${this.name}/summary.json`;
745
+ const summaryData = JSON.stringify(this.summary, null, 2);
746
+ fs6.writeFileSync(summaryPath, summaryData);
747
+ this.broadcast({
748
+ type: "summaryUpdate",
749
+ data: this.summary
750
+ });
751
+ };
752
+ this.name = name;
753
+ this.mode = mode2;
754
+ this.summary = {};
755
+ this.configs.tests.forEach(([t, rt, tr, sidecars]) => {
756
+ this.ensureSummaryEntry(t);
757
+ sidecars.forEach(([sidecarName]) => {
758
+ this.ensureSummaryEntry(sidecarName, true);
759
+ });
760
+ });
761
+ }
762
+ ensureSummaryEntry(src, isSidecar = false) {
763
+ if (!this.summary[src]) {
764
+ this.summary[src] = {
765
+ typeErrors: void 0,
766
+ staticErrors: void 0,
767
+ runTimeErrors: void 0,
768
+ prompt: void 0,
769
+ failingFeatures: {}
770
+ };
771
+ if (isSidecar) {
772
+ }
773
+ }
774
+ return this.summary[src];
775
+ }
776
+ };
777
+ }
778
+ });
779
+
780
+ // src/PM/pitonoRunner.ts
781
+ var pitonoRunner_exports = {};
782
+ __export(pitonoRunner_exports, {
783
+ PitonoRunner: () => PitonoRunner
784
+ });
785
+ import { execSync } from "child_process";
786
+ import path6 from "path";
787
+ import fs7 from "fs";
788
+ var PitonoRunner;
789
+ var init_pitonoRunner = __esm({
790
+ "src/PM/pitonoRunner.ts"() {
791
+ "use strict";
792
+ PitonoRunner = class {
793
+ constructor(config, testName2) {
794
+ this.config = config;
795
+ this.testName = testName2;
796
+ }
797
+ async run() {
798
+ const coreJsonPath = path6.join(process.cwd(), "testeranto", "pitono", this.testName, "core.json");
799
+ const maxWaitTime = 1e4;
800
+ const startTime = Date.now();
801
+ while (!fs7.existsSync(coreJsonPath) && Date.now() - startTime < maxWaitTime) {
802
+ await new Promise((resolve) => setTimeout(resolve, 100));
803
+ }
804
+ if (!fs7.existsSync(coreJsonPath)) {
805
+ console.error(`Pitono core.json not found at: ${coreJsonPath} after waiting ${maxWaitTime}ms`);
806
+ return;
807
+ }
808
+ try {
809
+ const coreData = JSON.parse(fs7.readFileSync(coreJsonPath, "utf-8"));
810
+ const entryPoints = coreData.entryPoints;
811
+ for (const entryPoint of entryPoints) {
812
+ try {
813
+ console.log(`Running pitono test: ${entryPoint}`);
814
+ const absolutePath = path6.resolve(entryPoint);
815
+ if (!fs7.existsSync(absolutePath)) {
816
+ console.error(`Pitono test file not found: ${absolutePath}`);
817
+ continue;
818
+ }
819
+ execSync(`python "${absolutePath}"`, { stdio: "inherit" });
820
+ console.log(`Pitono test completed: ${entryPoint}`);
821
+ } catch (error) {
822
+ console.error(`Pitono test failed: ${entryPoint}`, error);
823
+ throw error;
824
+ }
825
+ }
826
+ } catch (error) {
827
+ console.error(`Error reading or parsing core.json: ${error}`);
828
+ }
829
+ }
830
+ };
831
+ }
832
+ });
833
+
834
+ // src/PM/main.ts
835
+ var main_exports = {};
836
+ __export(main_exports, {
837
+ PM_Main: () => PM_Main
838
+ });
839
+ import { spawn } from "node:child_process";
840
+ import ansiColors from "ansi-colors";
841
+ import net from "net";
842
+ import fs8, { watch } from "fs";
843
+ import path7 from "path";
844
+ import puppeteer from "puppeteer-core";
845
+ import ansiC2 from "ansi-colors";
846
+ import crypto from "node:crypto";
847
+ import { WebSocketServer } from "ws";
848
+ import http from "http";
849
+ import url from "url";
850
+ import mime from "mime-types";
851
+ function runtimeLogs(runtime, reportDest) {
852
+ const safeDest = reportDest || `testeranto/reports/default_${Date.now()}`;
853
+ try {
854
+ if (!fs8.existsSync(safeDest)) {
855
+ fs8.mkdirSync(safeDest, { recursive: true });
856
+ }
857
+ if (runtime === "node") {
858
+ return {
859
+ stdout: fs8.createWriteStream(`${safeDest}/stdout.log`),
860
+ stderr: fs8.createWriteStream(`${safeDest}/stderr.log`),
861
+ exit: fs8.createWriteStream(`${safeDest}/exit.log`)
862
+ };
863
+ } else if (runtime === "web") {
864
+ return {
865
+ info: fs8.createWriteStream(`${safeDest}/info.log`),
866
+ warn: fs8.createWriteStream(`${safeDest}/warn.log`),
867
+ error: fs8.createWriteStream(`${safeDest}/error.log`),
868
+ debug: fs8.createWriteStream(`${safeDest}/debug.log`),
869
+ exit: fs8.createWriteStream(`${safeDest}/exit.log`)
870
+ };
871
+ } else if (runtime === "pure") {
872
+ return {
873
+ exit: fs8.createWriteStream(`${safeDest}/exit.log`)
874
+ };
875
+ } else if (runtime === "pitono") {
876
+ return {
877
+ stdout: fs8.createWriteStream(`${safeDest}/stdout.log`),
878
+ stderr: fs8.createWriteStream(`${safeDest}/stderr.log`),
879
+ exit: fs8.createWriteStream(`${safeDest}/exit.log`)
880
+ };
881
+ } else {
882
+ throw `unknown runtime: ${runtime}`;
883
+ }
884
+ } catch (e) {
885
+ console.error(`Failed to create log streams in ${safeDest}:`, e);
886
+ throw e;
887
+ }
888
+ }
889
+ function createLogStreams(reportDest, runtime) {
890
+ if (!fs8.existsSync(reportDest)) {
891
+ fs8.mkdirSync(reportDest, { recursive: true });
892
+ }
893
+ const streams = runtimeLogs(runtime, reportDest);
894
+ const safeDest = reportDest || `testeranto/reports/default_${Date.now()}`;
895
+ try {
896
+ if (!fs8.existsSync(safeDest)) {
897
+ fs8.mkdirSync(safeDest, { recursive: true });
898
+ }
899
+ const streams2 = runtimeLogs(runtime, safeDest);
900
+ return {
901
+ ...streams2,
902
+ closeAll: () => {
903
+ Object.values(streams2).forEach(
904
+ (stream) => !stream.closed && stream.close()
905
+ );
906
+ },
907
+ writeExitCode: (code, error) => {
908
+ if (error) {
909
+ streams2.exit.write(`Error: ${error.message}
910
+ `);
911
+ if (error.stack) {
912
+ streams2.exit.write(`Stack Trace:
913
+ ${error.stack}
914
+ `);
915
+ }
916
+ }
917
+ streams2.exit.write(`${code}
918
+ `);
919
+ },
920
+ exit: streams2.exit
921
+ };
922
+ } catch (e) {
923
+ console.error(`Failed to create log streams in ${safeDest}:`, e);
924
+ throw e;
925
+ }
926
+ }
927
+ async function fileHash(filePath, algorithm = "md5") {
928
+ return new Promise((resolve, reject) => {
929
+ const hash = crypto.createHash(algorithm);
930
+ const fileStream = fs8.createReadStream(filePath);
931
+ fileStream.on("data", (data) => {
932
+ hash.update(data);
933
+ });
934
+ fileStream.on("end", () => {
935
+ const fileHash2 = hash.digest("hex");
936
+ resolve(fileHash2);
937
+ });
938
+ fileStream.on("error", (error) => {
939
+ reject(`Error reading file: ${error.message}`);
940
+ });
941
+ });
942
+ }
943
+ async function writeFileAndCreateDir(filePath, data) {
944
+ const dirPath = path7.dirname(filePath);
945
+ try {
946
+ await fs8.promises.mkdir(dirPath, { recursive: true });
947
+ await fs8.writeFileSync(filePath, data);
948
+ } catch (error) {
949
+ console.error(`Error writing file: ${error}`);
950
+ }
951
+ }
952
+ function isValidUrl(string) {
953
+ try {
954
+ new URL(string);
955
+ return true;
956
+ } catch (err) {
957
+ return false;
958
+ }
959
+ }
960
+ async function pollForFile(path11, timeout = 2e3) {
961
+ const intervalObj = setInterval(function() {
962
+ const file = path11;
963
+ const fileExists = fs8.existsSync(file);
964
+ if (fileExists) {
965
+ clearInterval(intervalObj);
966
+ }
967
+ }, timeout);
968
+ }
969
+ var changes, fileHashes, files2, screenshots2, statusMessagePretty, filesHash, PM_Main;
970
+ var init_main = __esm({
971
+ async "src/PM/main.ts"() {
972
+ "use strict";
973
+ init_utils();
974
+ init_queue();
975
+ await init_PM_WithEslintAndTsc();
976
+ changes = {};
977
+ fileHashes = {};
978
+ files2 = {};
979
+ screenshots2 = {};
980
+ statusMessagePretty = (failures, test, runtime) => {
981
+ if (failures === 0) {
982
+ console.log(ansiC2.green(ansiC2.inverse(`${runtime} > ${test}`)));
983
+ } else if (failures > 0) {
984
+ console.log(
985
+ ansiC2.red(
986
+ ansiC2.inverse(
987
+ `${runtime} > ${test} failed ${failures} times (exit code: ${failures})`
988
+ )
989
+ )
990
+ );
991
+ } else {
992
+ console.log(
993
+ ansiC2.red(ansiC2.inverse(`${runtime} > ${test} crashed (exit code: -1)`))
994
+ );
995
+ }
996
+ };
997
+ filesHash = async (files3, algorithm = "md5") => {
998
+ return new Promise((resolve, reject) => {
999
+ resolve(
1000
+ files3.reduce(async (mm, f2) => {
1001
+ return await mm + await fileHash(f2);
1002
+ }, Promise.resolve(""))
1003
+ );
1004
+ });
1005
+ };
1006
+ PM_Main = class extends PM_WithEslintAndTsc {
1007
+ constructor(configs, name, mode2) {
1008
+ super(configs, name, mode2);
1009
+ this.logStreams = {};
1010
+ this.sidecars = {};
1011
+ this.clients = /* @__PURE__ */ new Set();
1012
+ this.runningProcesses = /* @__PURE__ */ new Map();
1013
+ this.allProcesses = /* @__PURE__ */ new Map();
1014
+ this.processLogs = /* @__PURE__ */ new Map();
1015
+ this.getRunnables = (tests, testName2, payload = {
1016
+ nodeEntryPoints: {},
1017
+ nodeEntryPointSidecars: {},
1018
+ webEntryPoints: {},
1019
+ webEntryPointSidecars: {},
1020
+ pureEntryPoints: {},
1021
+ pureEntryPointSidecars: {}
1022
+ }) => {
1023
+ return getRunnables(tests, testName2, payload);
1024
+ };
1025
+ this.launchPure = async (src, dest) => {
1026
+ console.log(ansiC2.green(ansiC2.inverse(`pure < ${src}`)));
1027
+ this.bddTestIsRunning(src);
1028
+ const reportDest = `testeranto/reports/${this.name}/${src.split(".").slice(0, -1).join(".")}/pure`;
1029
+ if (!fs8.existsSync(reportDest)) {
1030
+ fs8.mkdirSync(reportDest, { recursive: true });
1031
+ }
1032
+ const destFolder = dest.replace(".mjs", "");
1033
+ let argz2 = "";
1034
+ const testConfig = this.configs.tests.find((t) => {
1035
+ return t[0] === src;
1036
+ });
1037
+ if (!testConfig) {
1038
+ console.log(ansiC2.inverse("missing test config! Exiting ungracefully!"));
1039
+ process.exit(-1);
1040
+ }
1041
+ const testConfigResource = testConfig[2];
1042
+ const portsToUse = [];
1043
+ if (testConfigResource.ports === 0) {
1044
+ argz2 = JSON.stringify({
1045
+ scheduled: true,
1046
+ name: src,
1047
+ ports: portsToUse,
1048
+ fs: reportDest,
1049
+ browserWSEndpoint: this.browser.wsEndpoint()
1050
+ });
1051
+ } else if (testConfigResource.ports > 0) {
1052
+ const openPorts = Object.entries(this.ports).filter(
1053
+ ([portnumber, status]) => status === ""
1054
+ );
1055
+ if (openPorts.length >= testConfigResource.ports) {
1056
+ for (let i = 0; i < testConfigResource.ports; i++) {
1057
+ portsToUse.push(openPorts[i][0]);
1058
+ this.ports[openPorts[i][0]] = src;
1059
+ }
1060
+ argz2 = JSON.stringify({
1061
+ scheduled: true,
1062
+ name: src,
1063
+ ports: portsToUse,
1064
+ fs: destFolder,
1065
+ browserWSEndpoint: this.browser.wsEndpoint()
1066
+ });
1067
+ } else {
1068
+ this.queue.push(src);
1069
+ return [Math.random(), argz2];
1070
+ }
1071
+ } else {
1072
+ console.error("negative port makes no sense", src);
1073
+ process.exit(-1);
1074
+ }
1075
+ const builtfile = dest;
1076
+ const logs = createLogStreams(reportDest, "pure");
1077
+ try {
1078
+ await import(`${builtfile}?cacheBust=${Date.now()}`).then((module) => {
1079
+ const originalConsole = { ...console };
1080
+ return module.default.then((defaultModule) => {
1081
+ defaultModule.receiveTestResourceConfig(argz2).then(async (results) => {
1082
+ statusMessagePretty(results.fails, src, "pure");
1083
+ this.bddTestIsNowDone(src, results.fails);
1084
+ }).catch((e1) => {
1085
+ console.log(
1086
+ ansiC2.red(`launchPure - ${src} errored with: ${e1.stack}`)
1087
+ );
1088
+ this.bddTestIsNowDone(src, -1);
1089
+ statusMessagePretty(-1, src, "pure");
1090
+ });
1091
+ }).catch((e2) => {
1092
+ console.log(
1093
+ ansiColors.red(
1094
+ `pure ! ${src} failed to execute. No "tests.json" file was generated. Check the logs for more info`
1095
+ )
1096
+ );
1097
+ logs.exit.write(e2.stack);
1098
+ logs.exit.write(-1);
1099
+ this.bddTestIsNowDone(src, -1);
1100
+ statusMessagePretty(-1, src, "pure");
1101
+ }).finally((x) => {
1102
+ });
1103
+ });
1104
+ } catch (e3) {
1105
+ logs.writeExitCode(-1, e3);
1106
+ console.log(
1107
+ ansiC2.red(
1108
+ ansiC2.inverse(
1109
+ `${src} 1 errored with: ${e3}. Check logs for more info`
1110
+ )
1111
+ )
1112
+ );
1113
+ logs.exit.write(e3.stack);
1114
+ logs.exit.write("-1");
1115
+ this.bddTestIsNowDone(src, -1);
1116
+ statusMessagePretty(-1, src, "pure");
1117
+ }
1118
+ for (let i = 0; i <= portsToUse.length; i++) {
1119
+ if (portsToUse[i]) {
1120
+ this.ports[portsToUse[i]] = "";
1121
+ }
1122
+ }
1123
+ };
1124
+ this.launchNode = async (src, dest) => {
1125
+ console.log(ansiC2.green(ansiC2.inverse(`node < ${src}`)));
1126
+ this.bddTestIsRunning(src);
1127
+ const reportDest = `testeranto/reports/${this.name}/${src.split(".").slice(0, -1).join(".")}/node`;
1128
+ if (!fs8.existsSync(reportDest)) {
1129
+ fs8.mkdirSync(reportDest, { recursive: true });
1130
+ }
1131
+ let testResources = "";
1132
+ const testConfig = this.configs.tests.find((t) => {
1133
+ return t[0] === src;
1134
+ });
1135
+ if (!testConfig) {
1136
+ console.log(
1137
+ ansiC2.inverse(`missing test config! Exiting ungracefully for '${src}'`)
1138
+ );
1139
+ process.exit(-1);
1140
+ }
1141
+ const testConfigResource = testConfig[2];
1142
+ const portsToUse = [];
1143
+ if (testConfigResource.ports === 0) {
1144
+ const t = {
1145
+ name: src,
1146
+ // ports: portsToUse.map((v) => Number(v)),
1147
+ ports: [],
1148
+ fs: reportDest,
1149
+ browserWSEndpoint: this.browser.wsEndpoint()
1150
+ };
1151
+ testResources = JSON.stringify(t);
1152
+ } else if (testConfigResource.ports > 0) {
1153
+ const openPorts = Object.entries(this.ports).filter(
1154
+ ([portnumber, portopen]) => portopen === ""
1155
+ );
1156
+ if (openPorts.length >= testConfigResource.ports) {
1157
+ for (let i = 0; i < testConfigResource.ports; i++) {
1158
+ portsToUse.push(openPorts[i][0]);
1159
+ this.ports[openPorts[i][0]] = src;
1160
+ }
1161
+ testResources = JSON.stringify({
1162
+ scheduled: true,
1163
+ name: src,
1164
+ ports: portsToUse,
1165
+ fs: reportDest,
1166
+ browserWSEndpoint: this.browser.wsEndpoint()
1167
+ });
1168
+ } else {
1169
+ console.log(
1170
+ ansiC2.red(
1171
+ `node: cannot run ${src} because there are no open ports ATM. This job will be enqueued and run again run a port is available`
1172
+ )
1173
+ );
1174
+ this.queue.push(src);
1175
+ return [Math.random(), argz];
1176
+ }
1177
+ } else {
1178
+ console.error("negative port makes no sense", src);
1179
+ process.exit(-1);
1180
+ }
1181
+ const builtfile = dest;
1182
+ let haltReturns = false;
1183
+ const ipcfile = "/tmp/tpipe_" + Math.random();
1184
+ const child = spawn(
1185
+ "node",
1186
+ // "node",
1187
+ [
1188
+ // "--inspect-brk",
1189
+ builtfile,
1190
+ testResources,
1191
+ ipcfile
1192
+ ],
1193
+ {
1194
+ stdio: ["pipe", "pipe", "pipe", "ipc"]
1195
+ }
1196
+ );
1197
+ let buffer = new Buffer("");
1198
+ const server = net.createServer((socket) => {
1199
+ const queue = new Queue();
1200
+ socket.on("data", (data) => {
1201
+ buffer = Buffer.concat([buffer, data]);
1202
+ for (let b = 0; b < buffer.length + 1; b++) {
1203
+ const c = buffer.slice(0, b);
1204
+ let d;
1205
+ try {
1206
+ d = JSON.parse(c.toString());
1207
+ queue.enqueue(d);
1208
+ buffer = buffer.slice(b, buffer.length + 1);
1209
+ b = 0;
1210
+ } catch (e) {
1211
+ }
1212
+ }
1213
+ while (queue.size() > 0) {
1214
+ const message = queue.dequeue();
1215
+ if (message) {
1216
+ this.mapping().forEach(async ([command, func]) => {
1217
+ if (message[0] === command) {
1218
+ const x = message.slice(1, -1);
1219
+ const r = await this[command](...x);
1220
+ if (!haltReturns) {
1221
+ child.send(
1222
+ JSON.stringify({
1223
+ payload: r,
1224
+ key: message[message.length - 1]
1225
+ })
1226
+ );
1227
+ }
1228
+ }
1229
+ });
1230
+ }
1231
+ }
1232
+ });
1233
+ });
1234
+ const logs = createLogStreams(reportDest, "node");
1235
+ server.listen(ipcfile, () => {
1236
+ child.stdout?.on("data", (data) => {
1237
+ logs.stdout?.write(data);
1238
+ });
1239
+ child.stderr?.on("data", (data) => {
1240
+ logs.stderr?.write(data);
1241
+ });
1242
+ child.on("error", (err) => {
1243
+ });
1244
+ child.on("close", (code) => {
1245
+ const exitCode = code === null ? -1 : code;
1246
+ if (exitCode < 0) {
1247
+ logs.writeExitCode(
1248
+ exitCode,
1249
+ new Error("Process crashed or was terminated")
1250
+ );
1251
+ } else {
1252
+ logs.writeExitCode(exitCode);
1253
+ }
1254
+ logs.closeAll();
1255
+ server.close();
1256
+ if (!files2[src]) {
1257
+ files2[src] = /* @__PURE__ */ new Set();
1258
+ }
1259
+ if (exitCode === 255) {
1260
+ console.log(
1261
+ ansiColors.red(
1262
+ `node ! ${src} failed to execute. No "tests.json" file was generated. Check ${reportDest}/stderr.log for more info`
1263
+ )
1264
+ );
1265
+ this.bddTestIsNowDone(src, -1);
1266
+ statusMessagePretty(-1, src, "node");
1267
+ return;
1268
+ } else if (exitCode === 0) {
1269
+ this.bddTestIsNowDone(src, 0);
1270
+ statusMessagePretty(0, src, "node");
1271
+ } else {
1272
+ this.bddTestIsNowDone(src, exitCode);
1273
+ statusMessagePretty(exitCode, src, "node");
1274
+ }
1275
+ haltReturns = true;
1276
+ });
1277
+ child.on("exit", (code) => {
1278
+ haltReturns = true;
1279
+ for (let i = 0; i <= portsToUse.length; i++) {
1280
+ if (portsToUse[i]) {
1281
+ this.ports[portsToUse[i]] = "";
1282
+ }
1283
+ }
1284
+ });
1285
+ child.on("error", (e) => {
1286
+ console.log("error");
1287
+ haltReturns = true;
1288
+ console.log(
1289
+ ansiC2.red(
1290
+ ansiC2.inverse(
1291
+ `${src} errored with: ${e.name}. Check error logs for more info`
1292
+ )
1293
+ )
1294
+ );
1295
+ this.bddTestIsNowDone(src, -1);
1296
+ statusMessagePretty(-1, src, "node");
1297
+ });
1298
+ });
1299
+ };
1300
+ this.launchWebSideCar = async (testConfig) => {
1301
+ const src = testConfig[0];
1302
+ const dest = src.split(".").slice(0, -1).join(".");
1303
+ const destFolder = dest.replace(".mjs", "");
1304
+ console.log(ansiC2.green(ansiC2.inverse(`launchWebSideCar ${src}`)));
1305
+ const logs = createLogStreams(dest, "web");
1306
+ return new Promise((res, rej) => {
1307
+ this.browser.newPage().then(async (page) => {
1308
+ this.mapping().forEach(async ([command, func]) => {
1309
+ page.exposeFunction(command, func);
1310
+ });
1311
+ const close = () => {
1312
+ if (!files2[src]) {
1313
+ files2[src] = /* @__PURE__ */ new Set();
1314
+ }
1315
+ delete files2[src];
1316
+ Promise.all(screenshots2[src] || []).then(() => {
1317
+ delete screenshots2[src];
1318
+ page.close();
1319
+ });
1320
+ };
1321
+ page.on("pageerror", (err) => {
1322
+ console.debug(`Error from ${src}: [${err.name}] `);
1323
+ console.debug(`Error from ${src}: [${err.name}] `);
1324
+ if (err.cause) {
1325
+ console.debug(`Error from ${src} cause: [${err.cause}] `);
1326
+ }
1327
+ if (err.stack) {
1328
+ console.debug(`Error from stack ${src}: [${err.stack}] `);
1329
+ }
1330
+ console.debug(`Error from message ${src}: [${err.message}] `);
1331
+ this.bddTestIsNowDone(src, -1);
1332
+ close();
1333
+ });
1334
+ page.on("console", (log) => {
1335
+ const msg = `${log.text()}
1336
+ ${JSON.stringify(
1337
+ log.location()
1338
+ )}
1339
+ ${JSON.stringify(log.stackTrace())}
1340
+ `;
1341
+ switch (log.type()) {
1342
+ case "info":
1343
+ logs.info?.write(msg);
1344
+ break;
1345
+ case "warn":
1346
+ logs.warn?.write(msg);
1347
+ break;
1348
+ case "error":
1349
+ logs.error?.write(msg);
1350
+ break;
1351
+ case "debug":
1352
+ logs.debug?.write(msg);
1353
+ break;
1354
+ default:
1355
+ break;
1356
+ }
1357
+ });
1358
+ await page.goto(`file://${`${destFolder}.html`}`, {});
1359
+ const webArgz = JSON.stringify({
1360
+ name: dest,
1361
+ ports: [].toString(),
1362
+ fs: dest,
1363
+ browserWSEndpoint: this.browser.wsEndpoint()
1364
+ });
1365
+ const d = `${dest}?cacheBust=${Date.now()}`;
1366
+ const evaluation = `
1367
+ import('${d}').then(async (x) => {
1368
+
1369
+ try {
1370
+ return await (await x.default).receiveTestResourceConfig(${webArgz})
1371
+ } catch (e) {
1372
+ console.log("fail", e.toString())
1373
+ }
1374
+ })`;
1375
+ await page.evaluate(evaluation).then(async ({ fails, failed, features }) => {
1376
+ statusMessagePretty(fails, src, "web");
1377
+ this.bddTestIsNowDone(src, fails);
1378
+ }).catch((e) => {
1379
+ console.log(
1380
+ ansiC2.red(
1381
+ ansiC2.inverse(`launchWebSidecar - ${src} errored with: ${e}`)
1382
+ )
1383
+ );
1384
+ }).finally(() => {
1385
+ this.bddTestIsNowDone(src, -1);
1386
+ close();
1387
+ });
1388
+ return page;
1389
+ }).then(async (page) => {
1390
+ await page.goto(`file://${`${dest}.html`}`, {});
1391
+ res([Math.random(), page]);
1392
+ });
1393
+ });
1394
+ };
1395
+ this.launchNodeSideCar = async (sidecar) => {
1396
+ const src = sidecar[0];
1397
+ const dest = process.cwd() + `/testeranto/bundles/node/${this.name}/${sidecar[0]}`;
1398
+ const d = dest + ".mjs";
1399
+ console.log(ansiC2.green(ansiC2.inverse(`launchNodeSideCar ${sidecar[0]}`)));
1400
+ const destFolder = dest.replace(".ts", "");
1401
+ const reportDest = `testeranto/reports/${this.name}/${src.split(".").slice(0, -1).join(".")}/node`;
1402
+ const argz2 = {
1403
+ name: sidecar[0],
1404
+ ports: [],
1405
+ fs: destFolder,
1406
+ browserWSEndpoint: this.browser.wsEndpoint()
1407
+ };
1408
+ const testReq = sidecar[2];
1409
+ const logs = createLogStreams(dest, "node");
1410
+ const portsToUse = [];
1411
+ if (testReq.ports === 0) {
1412
+ } else if (testReq.ports > 0) {
1413
+ const openPorts = Object.entries(this.ports).filter(
1414
+ ([portnumber, portopen]) => portopen === ""
1415
+ );
1416
+ if (openPorts.length >= testReq.ports) {
1417
+ for (let i = 0; i < testReq.ports; i++) {
1418
+ portsToUse.push(Number(openPorts[i][0]));
1419
+ this.ports[openPorts[i][0]] = src;
1420
+ }
1421
+ argz2.ports = portsToUse;
1422
+ const builtfile = destFolder + ".mjs";
1423
+ let haltReturns = false;
1424
+ let buffer = new Buffer("");
1425
+ const server = net.createServer((socket) => {
1426
+ socket.on("data", (data) => {
1427
+ buffer = Buffer.concat([buffer, data]);
1428
+ const messages = [];
1429
+ for (let b = 0; b < buffer.length + 1; b++) {
1430
+ const c = buffer.slice(0, b);
1431
+ let d2;
1432
+ try {
1433
+ d2 = JSON.parse(c.toString());
1434
+ messages.push(d2);
1435
+ buffer = buffer.slice(b, buffer.length + 1);
1436
+ b = 0;
1437
+ } catch (e) {
1438
+ }
1439
+ }
1440
+ messages.forEach(async (payload) => {
1441
+ this.mapping().forEach(async ([command, func]) => {
1442
+ if (payload[0] === command) {
1443
+ const x = payload.slice(1, -1);
1444
+ const r2 = await this[command](...x);
1445
+ if (!haltReturns) {
1446
+ child.send(
1447
+ JSON.stringify({
1448
+ payload: r2,
1449
+ key: payload[payload.length - 1]
1450
+ })
1451
+ );
1452
+ }
1453
+ }
1454
+ });
1455
+ });
1456
+ });
1457
+ });
1458
+ const child = spawn("node", [builtfile, JSON.stringify(argz2)], {
1459
+ stdio: ["pipe", "pipe", "pipe", "ipc"]
1460
+ // silent: true
1461
+ });
1462
+ const p = "/tmp/tpipe" + Math.random();
1463
+ server.listen(p, () => {
1464
+ child.on("close", (code) => {
1465
+ server.close();
1466
+ haltReturns = true;
1467
+ });
1468
+ child.on("exit", (code) => {
1469
+ haltReturns = true;
1470
+ for (let i = 0; i <= portsToUse.length; i++) {
1471
+ if (portsToUse[i]) {
1472
+ this.ports[portsToUse[i]] = "";
1473
+ }
1474
+ }
1475
+ });
1476
+ child.on("error", (e) => {
1477
+ if (fs8.existsSync(p)) {
1478
+ fs8.rmSync(p);
1479
+ }
1480
+ haltReturns = true;
1481
+ console.log(
1482
+ ansiC2.red(
1483
+ ansiC2.inverse(
1484
+ `launchNodeSideCar - ${src} errored with: ${e.name}. Check logs for more info`
1485
+ )
1486
+ )
1487
+ );
1488
+ logs.error?.write(e.toString() + "\n");
1489
+ });
1490
+ });
1491
+ child.send({ path: p });
1492
+ const r = Math.random();
1493
+ this.nodeSidecars[r] = child;
1494
+ return [r, argz2];
1495
+ } else {
1496
+ console.log(
1497
+ ansiC2.red(
1498
+ `cannot ${src} because there are no open ports. the job will be unqueued`
1499
+ )
1500
+ );
1501
+ this.queue.push(sidecar[0]);
1502
+ return [Math.random(), argz2];
1503
+ }
1504
+ } else {
1505
+ console.error("negative port makes no sense", sidecar[0]);
1506
+ process.exit(-1);
1507
+ }
1508
+ };
1509
+ this.stopPureSideCar = async (uid) => {
1510
+ console.log(ansiC2.green(ansiC2.inverse(`stopPureSideCar ${uid}`)));
1511
+ await this.sidecars[uid].shutdown();
1512
+ return;
1513
+ };
1514
+ this.launchPureSideCar = async (sidecar) => {
1515
+ console.log(ansiC2.green(ansiC2.inverse(`launchPureSideCar ${sidecar[0]}`)));
1516
+ const r = Math.random();
1517
+ const dest = process.cwd() + `/testeranto/bundles/pure/${this.name}/${sidecar[0]}`;
1518
+ const builtfile = dest.split(".").slice(0, -1).concat("mjs").join(".");
1519
+ const destFolder = dest.replace(".mjs", "");
1520
+ let argz2;
1521
+ const z = sidecar[2];
1522
+ const testConfigResource = sidecar[2];
1523
+ const src = sidecar[0];
1524
+ const portsToUse = [];
1525
+ if (testConfigResource.ports === 0) {
1526
+ argz2 = {
1527
+ // scheduled: true,
1528
+ name: src,
1529
+ ports: portsToUse,
1530
+ fs: destFolder,
1531
+ browserWSEndpoint: this.browser.wsEndpoint()
1532
+ };
1533
+ } else if (testConfigResource.ports > 0) {
1534
+ const openPorts = Object.entries(this.ports).filter(
1535
+ ([portnumber, portopen]) => portopen === ""
1536
+ );
1537
+ if (openPorts.length >= testConfigResource.ports) {
1538
+ for (let i = 0; i < testConfigResource.ports; i++) {
1539
+ portsToUse.push(Number(openPorts[i][0]));
1540
+ this.ports[openPorts[i][0]] = src;
1541
+ }
1542
+ argz2 = {
1543
+ // scheduled: true,
1544
+ name: src,
1545
+ // ports: [3333],
1546
+ ports: portsToUse,
1547
+ fs: ".",
1548
+ browserWSEndpoint: this.browser.wsEndpoint()
1549
+ };
1550
+ } else {
1551
+ this.queue.push(src);
1552
+ }
1553
+ } else {
1554
+ console.error("negative port makes no sense", src);
1555
+ process.exit(-1);
1556
+ }
1557
+ await import(`${builtfile}?cacheBust=${Date.now()}`).then((module) => {
1558
+ if (!this.pureSidecars)
1559
+ this.pureSidecars = {};
1560
+ this.pureSidecars[r] = module.default;
1561
+ this.pureSidecars[r].start(argz2);
1562
+ });
1563
+ return [r, argz2];
1564
+ };
1565
+ this.launchPitono = async (src, dest) => {
1566
+ console.log(ansiC2.green(ansiC2.inverse(`pitono < ${src}`)));
1567
+ this.bddTestIsRunning(src);
1568
+ const reportDest = `testeranto/reports/${this.name}/${src.split(".").slice(0, -1).join(".")}/pitono`;
1569
+ if (!fs8.existsSync(reportDest)) {
1570
+ fs8.mkdirSync(reportDest, { recursive: true });
1571
+ }
1572
+ const logs = createLogStreams(reportDest, "node");
1573
+ try {
1574
+ const { PitonoRunner: PitonoRunner2 } = await Promise.resolve().then(() => (init_pitonoRunner(), pitonoRunner_exports));
1575
+ const runner = new PitonoRunner2(this.configs, this.name);
1576
+ await runner.run();
1577
+ this.bddTestIsNowDone(src, 0);
1578
+ statusMessagePretty(0, src, "pitono");
1579
+ } catch (error) {
1580
+ logs.writeExitCode(-1, error);
1581
+ console.log(
1582
+ ansiC2.red(
1583
+ ansiC2.inverse(
1584
+ `${src} errored with: ${error}. Check logs for more info`
1585
+ )
1586
+ )
1587
+ );
1588
+ this.bddTestIsNowDone(src, -1);
1589
+ statusMessagePretty(-1, src, "pitono");
1590
+ }
1591
+ };
1592
+ this.launchWeb = async (src, dest) => {
1593
+ console.log(ansiC2.green(ansiC2.inverse(`web < ${src}`)));
1594
+ this.bddTestIsRunning(src);
1595
+ const reportDest = `testeranto/reports/${this.name}/${src.split(".").slice(0, -1).join(".")}/web`;
1596
+ if (!fs8.existsSync(reportDest)) {
1597
+ fs8.mkdirSync(reportDest, { recursive: true });
1598
+ }
1599
+ const destFolder = dest.replace(".mjs", "");
1600
+ const webArgz = JSON.stringify({
1601
+ name: src,
1602
+ ports: [].toString(),
1603
+ fs: reportDest,
1604
+ browserWSEndpoint: this.browser.wsEndpoint()
1605
+ });
1606
+ const d = `${dest}?cacheBust=${Date.now()}`;
1607
+ const logs = createLogStreams(reportDest, "web");
1608
+ this.browser.newPage().then((page) => {
1609
+ page.on("console", (log) => {
1610
+ const msg = `${log.text()}
1611
+ `;
1612
+ switch (log.type()) {
1613
+ case "info":
1614
+ logs.info?.write(msg);
1615
+ break;
1616
+ case "warn":
1617
+ logs.warn?.write(msg);
1618
+ break;
1619
+ case "error":
1620
+ logs.error?.write(msg);
1621
+ break;
1622
+ case "debug":
1623
+ logs.debug?.write(msg);
1624
+ break;
1625
+ default:
1626
+ break;
1627
+ }
1628
+ });
1629
+ page.on("close", () => {
1630
+ logs.writeExitCode(0);
1631
+ logs.closeAll();
1632
+ logs.closeAll();
1633
+ });
1634
+ this.mapping().forEach(async ([command, func]) => {
1635
+ if (command === "page") {
1636
+ page.exposeFunction(command, (x) => {
1637
+ if (x) {
1638
+ return func(x);
1639
+ } else {
1640
+ return func(page.mainFrame()._id);
1641
+ }
1642
+ });
1643
+ } else {
1644
+ return page.exposeFunction(command, func);
1645
+ }
1646
+ });
1647
+ return page;
1648
+ }).then(async (page) => {
1649
+ const close = () => {
1650
+ if (!files2[src]) {
1651
+ files2[src] = /* @__PURE__ */ new Set();
1652
+ }
1653
+ delete files2[src];
1654
+ Promise.all(screenshots2[src] || []).then(() => {
1655
+ delete screenshots2[src];
1656
+ page.close();
1657
+ });
1658
+ return;
1659
+ };
1660
+ page.on("pageerror", (err) => {
1661
+ logs.writeExitCode(-1, err);
1662
+ console.log(
1663
+ ansiColors.red(
1664
+ `web ! ${src} failed to execute No "tests.json" file was generated. Check ${reportDest}/error.log for more info`
1665
+ )
1666
+ );
1667
+ this.bddTestIsNowDone(src, -1);
1668
+ close();
1669
+ });
1670
+ await page.goto(`file://${`${destFolder}.html`}`, {});
1671
+ await page.evaluate(
1672
+ `
1673
+ import('${d}').then(async (x) => {
1674
+ try {
1675
+ return await (await x.default).receiveTestResourceConfig(${webArgz})
1676
+ } catch (e) {
1677
+ console.log("web run failure", e.toString())
1678
+ }
1679
+ })
1680
+ `
1681
+ ).then(async ({ fails, failed, features }) => {
1682
+ statusMessagePretty(fails, src, "web");
1683
+ this.bddTestIsNowDone(src, fails);
1684
+ }).catch((e) => {
1685
+ console.log(ansiC2.red(ansiC2.inverse(e.stack)));
1686
+ console.log(
1687
+ ansiC2.red(
1688
+ ansiC2.inverse(
1689
+ `web ! ${src} failed to execute. No "tests.json" file was generated. Check logs for more info`
1690
+ )
1691
+ )
1692
+ );
1693
+ this.bddTestIsNowDone(src, -1);
1694
+ }).finally(() => {
1695
+ close();
1696
+ });
1697
+ return page;
1698
+ });
1699
+ };
1700
+ this.receiveFeaturesV2 = (reportDest, srcTest, platform) => {
1701
+ const featureDestination = path7.resolve(
1702
+ process.cwd(),
1703
+ "reports",
1704
+ "features",
1705
+ "strings",
1706
+ srcTest.split(".").slice(0, -1).join(".") + ".features.txt"
1707
+ );
1708
+ const testReportPath = `${reportDest}/tests.json`;
1709
+ if (!fs8.existsSync(testReportPath)) {
1710
+ console.error(`tests.json not found at: ${testReportPath}`);
1711
+ return;
1712
+ }
1713
+ const testReport = JSON.parse(fs8.readFileSync(testReportPath, "utf8"));
1714
+ if (testReport.tests) {
1715
+ testReport.tests.forEach((test) => {
1716
+ test.fullPath = path7.resolve(process.cwd(), srcTest);
1717
+ });
1718
+ }
1719
+ testReport.fullPath = path7.resolve(process.cwd(), srcTest);
1720
+ fs8.writeFileSync(testReportPath, JSON.stringify(testReport, null, 2));
1721
+ testReport.features.reduce(async (mm, featureStringKey) => {
1722
+ const accum = await mm;
1723
+ const isUrl = isValidUrl(featureStringKey);
1724
+ if (isUrl) {
1725
+ const u = new URL(featureStringKey);
1726
+ if (u.protocol === "file:") {
1727
+ const newPath = `${process.cwd()}/testeranto/features/internal/${path7.relative(
1728
+ process.cwd(),
1729
+ u.pathname
1730
+ )}`;
1731
+ accum.files.push(u.pathname);
1732
+ } else if (u.protocol === "http:" || u.protocol === "https:") {
1733
+ const newPath = `${process.cwd()}/testeranto/features/external/${u.hostname}${u.pathname}`;
1734
+ const body = await this.configs.featureIngestor(featureStringKey);
1735
+ writeFileAndCreateDir(newPath, body);
1736
+ accum.files.push(newPath);
1737
+ }
1738
+ } else {
1739
+ await fs8.promises.mkdir(path7.dirname(featureDestination), {
1740
+ recursive: true
1741
+ });
1742
+ accum.strings.push(featureStringKey);
1743
+ }
1744
+ return accum;
1745
+ }, Promise.resolve({ files: [], strings: [] })).then(({ files: files3, strings }) => {
1746
+ fs8.writeFileSync(
1747
+ `testeranto/reports/${this.name}/${srcTest.split(".").slice(0, -1).join(".")}/${platform}/featurePrompt.txt`,
1748
+ files3.map((f2) => {
1749
+ return `/read ${f2}`;
1750
+ }).join("\n")
1751
+ );
1752
+ });
1753
+ testReport.givens.forEach((g) => {
1754
+ if (g.failed === true) {
1755
+ this.summary[srcTest].failingFeatures[g.key] = g.features;
1756
+ }
1757
+ });
1758
+ this.writeBigBoard();
1759
+ };
1760
+ this.checkForShutdown = () => {
1761
+ this.checkQueue();
1762
+ console.log(
1763
+ ansiC2.inverse(
1764
+ `The following jobs are awaiting resources: ${JSON.stringify(
1765
+ this.queue
1766
+ )}`
1767
+ )
1768
+ );
1769
+ console.log(
1770
+ ansiC2.inverse(`The status of ports: ${JSON.stringify(this.ports)}`)
1771
+ );
1772
+ this.writeBigBoard();
1773
+ if (this.mode === "dev")
1774
+ return;
1775
+ let inflight = false;
1776
+ Object.keys(this.summary).forEach((k) => {
1777
+ if (this.summary[k].prompt === "?") {
1778
+ console.log(ansiC2.blue(ansiC2.inverse(`\u{1F555} prompt ${k}`)));
1779
+ inflight = true;
1780
+ }
1781
+ });
1782
+ Object.keys(this.summary).forEach((k) => {
1783
+ if (this.summary[k].runTimeErrors === "?") {
1784
+ console.log(ansiC2.blue(ansiC2.inverse(`\u{1F555} runTimeError ${k}`)));
1785
+ inflight = true;
1786
+ }
1787
+ });
1788
+ Object.keys(this.summary).forEach((k) => {
1789
+ if (this.summary[k].staticErrors === "?") {
1790
+ console.log(ansiC2.blue(ansiC2.inverse(`\u{1F555} staticErrors ${k}`)));
1791
+ inflight = true;
1792
+ }
1793
+ });
1794
+ Object.keys(this.summary).forEach((k) => {
1795
+ if (this.summary[k].typeErrors === "?") {
1796
+ console.log(ansiC2.blue(ansiC2.inverse(`\u{1F555} typeErrors ${k}`)));
1797
+ inflight = true;
1798
+ }
1799
+ });
1800
+ this.writeBigBoard();
1801
+ if (!inflight) {
1802
+ if (this.browser) {
1803
+ if (this.browser) {
1804
+ this.browser.disconnect().then(() => {
1805
+ console.log(
1806
+ ansiC2.inverse(`${this.name} has been tested. Goodbye.`)
1807
+ );
1808
+ process.exit();
1809
+ });
1810
+ }
1811
+ }
1812
+ }
1813
+ };
1814
+ this.launchers = {};
1815
+ this.ports = {};
1816
+ this.queue = [];
1817
+ this.nodeSidecars = {};
1818
+ this.webSidecars = {};
1819
+ this.pureSidecars = {};
1820
+ this.configs.ports.forEach((element) => {
1821
+ this.ports[element] = "";
1822
+ });
1823
+ this.httpServer = http.createServer(this.requestHandler.bind(this));
1824
+ this.wss = new WebSocketServer({ server: this.httpServer });
1825
+ this.wss.on("connection", (ws) => {
1826
+ this.clients.add(ws);
1827
+ console.log("Client connected");
1828
+ ws.on("message", (data) => {
1829
+ try {
1830
+ const message = JSON.parse(data.toString());
1831
+ if (message.type === "executeCommand") {
1832
+ if (message.command && message.command.trim().startsWith("aider")) {
1833
+ console.log(`Executing command: ${message.command}`);
1834
+ const processId = Date.now().toString();
1835
+ const child = spawn(message.command, {
1836
+ shell: true,
1837
+ cwd: process.cwd()
1838
+ });
1839
+ this.runningProcesses.set(processId, child);
1840
+ this.allProcesses.set(processId, {
1841
+ child,
1842
+ status: "running",
1843
+ command: message.command,
1844
+ pid: child.pid,
1845
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1846
+ });
1847
+ this.processLogs.set(processId, []);
1848
+ this.broadcast({
1849
+ type: "processStarted",
1850
+ processId,
1851
+ command: message.command,
1852
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1853
+ logs: []
1854
+ });
1855
+ child.stdout?.on("data", (data2) => {
1856
+ const logData = data2.toString();
1857
+ const logs = this.processLogs.get(processId) || [];
1858
+ logs.push(logData);
1859
+ this.processLogs.set(processId, logs);
1860
+ this.broadcast({
1861
+ type: "processStdout",
1862
+ processId,
1863
+ data: logData,
1864
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1865
+ });
1866
+ });
1867
+ child.stderr?.on("data", (data2) => {
1868
+ const logData = data2.toString();
1869
+ const logs = this.processLogs.get(processId) || [];
1870
+ logs.push(logData);
1871
+ this.processLogs.set(processId, logs);
1872
+ this.broadcast({
1873
+ type: "processStderr",
1874
+ processId,
1875
+ data: logData,
1876
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1877
+ });
1878
+ });
1879
+ child.on("error", (error) => {
1880
+ console.error(`Failed to execute command: ${error}`);
1881
+ this.runningProcesses.delete(processId);
1882
+ const processInfo = this.allProcesses.get(processId);
1883
+ if (processInfo) {
1884
+ this.allProcesses.set(processId, {
1885
+ ...processInfo,
1886
+ status: "error",
1887
+ error: error.message
1888
+ });
1889
+ }
1890
+ this.broadcast({
1891
+ type: "processError",
1892
+ processId,
1893
+ error: error.message,
1894
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1895
+ });
1896
+ });
1897
+ child.on("exit", (code) => {
1898
+ console.log(`Command exited with code ${code}`);
1899
+ this.runningProcesses.delete(processId);
1900
+ const processInfo = this.allProcesses.get(processId);
1901
+ if (processInfo) {
1902
+ this.allProcesses.set(processId, {
1903
+ ...processInfo,
1904
+ status: "exited",
1905
+ exitCode: code
1906
+ });
1907
+ }
1908
+ this.broadcast({
1909
+ type: "processExited",
1910
+ processId,
1911
+ exitCode: code,
1912
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1913
+ });
1914
+ });
1915
+ } else {
1916
+ console.error('Invalid command: must start with "aider"');
1917
+ }
1918
+ } else if (message.type === "getRunningProcesses") {
1919
+ const processes = Array.from(this.allProcesses.entries()).map(
1920
+ ([id, procInfo]) => ({
1921
+ processId: id,
1922
+ command: procInfo.command,
1923
+ pid: procInfo.pid,
1924
+ status: procInfo.status,
1925
+ exitCode: procInfo.exitCode,
1926
+ error: procInfo.error,
1927
+ timestamp: procInfo.timestamp,
1928
+ logs: this.processLogs.get(id) || []
1929
+ })
1930
+ );
1931
+ ws.send(
1932
+ JSON.stringify({
1933
+ type: "runningProcesses",
1934
+ processes
1935
+ })
1936
+ );
1937
+ } else if (message.type === "getProcess") {
1938
+ const processId = message.processId;
1939
+ const procInfo = this.allProcesses.get(processId);
1940
+ if (procInfo) {
1941
+ ws.send(
1942
+ JSON.stringify({
1943
+ type: "processData",
1944
+ processId,
1945
+ command: procInfo.command,
1946
+ pid: procInfo.pid,
1947
+ status: procInfo.status,
1948
+ exitCode: procInfo.exitCode,
1949
+ error: procInfo.error,
1950
+ timestamp: procInfo.timestamp,
1951
+ logs: this.processLogs.get(processId) || []
1952
+ })
1953
+ );
1954
+ }
1955
+ } else if (message.type === "stdin") {
1956
+ const processId = message.processId;
1957
+ const data2 = message.data;
1958
+ console.log("Received stdin for process", processId, ":", data2);
1959
+ const childProcess = this.runningProcesses.get(processId);
1960
+ if (childProcess && childProcess.stdin) {
1961
+ console.log("Writing to process stdin");
1962
+ childProcess.stdin.write(data2);
1963
+ } else {
1964
+ console.log(
1965
+ "Cannot write to stdin - process not found or no stdin:",
1966
+ {
1967
+ processExists: !!childProcess,
1968
+ stdinExists: childProcess?.stdin ? true : false
1969
+ }
1970
+ );
1971
+ }
1972
+ } else if (message.type === "killProcess") {
1973
+ const processId = message.processId;
1974
+ console.log("Received killProcess for process", processId);
1975
+ const childProcess = this.runningProcesses.get(processId);
1976
+ if (childProcess) {
1977
+ console.log("Killing process");
1978
+ childProcess.kill("SIGTERM");
1979
+ } else {
1980
+ console.log("Cannot kill process - process not found:", {
1981
+ processExists: !!childProcess
1982
+ });
1983
+ }
1984
+ }
1985
+ } catch (error) {
1986
+ console.error("Error handling WebSocket message:", error);
1987
+ }
1988
+ });
1989
+ ws.on("close", () => {
1990
+ this.clients.delete(ws);
1991
+ console.log("Client disconnected");
1992
+ });
1993
+ ws.on("error", (error) => {
1994
+ console.error("WebSocket error:", error);
1995
+ this.clients.delete(ws);
1996
+ });
1997
+ });
1998
+ const httpPort = Number(process.env.HTTP_PORT) || 3e3;
1999
+ this.httpServer.listen(httpPort, () => {
2000
+ console.log(`HTTP server running on http://localhost:${httpPort}`);
2001
+ });
2002
+ }
2003
+ async stopSideCar(uid) {
2004
+ console.log(ansiC2.green(ansiC2.inverse(`stopSideCar ${uid}`)));
2005
+ Object.entries(this.pureSidecars).forEach(async ([k, v]) => {
2006
+ if (Number(k) === uid) {
2007
+ await this.pureSidecars[Number(k)].stop();
2008
+ delete this.pureSidecars[Number(k)];
2009
+ }
2010
+ });
2011
+ Object.entries(this.nodeSidecars).forEach(async ([k, v]) => {
2012
+ if (Number(k) === uid) {
2013
+ await this.nodeSidecars[Number(k)].send("stop");
2014
+ delete this.nodeSidecars[Number(k)];
2015
+ }
2016
+ });
2017
+ Object.entries(this.webSidecars).forEach(async ([k, v]) => {
2018
+ if (Number(k) === uid) {
2019
+ (await this.browser.pages()).forEach(async (p) => {
2020
+ if (p.mainFrame()._id === k) {
2021
+ await this.webSidecars[Number(k)].close();
2022
+ delete this.webSidecars[Number(k)];
2023
+ }
2024
+ });
2025
+ }
2026
+ });
2027
+ return;
2028
+ }
2029
+ async launchSideCar(n, name) {
2030
+ const c = this.configs.tests.find(([v, r2]) => {
2031
+ return v === name;
2032
+ });
2033
+ const s = c[3][n];
2034
+ const r = s[1];
2035
+ if (r === "node") {
2036
+ return this.launchNodeSideCar(s);
2037
+ } else if (r === "web") {
2038
+ return this.launchWebSideCar(s);
2039
+ } else if (r === "pure") {
2040
+ return this.launchPureSideCar(s);
2041
+ } else {
2042
+ throw `unknown runtime ${r}`;
2043
+ }
2044
+ }
2045
+ mapping() {
2046
+ return [
2047
+ ["$", this.$],
2048
+ ["click", this.click],
2049
+ ["closePage", this.closePage],
2050
+ ["createWriteStream", this.createWriteStream],
2051
+ ["customclose", this.customclose],
2052
+ ["customScreenShot", this.customScreenShot.bind(this)],
2053
+ ["end", this.end],
2054
+ ["existsSync", this.existsSync],
2055
+ ["focusOn", this.focusOn],
2056
+ ["getAttribute", this.getAttribute],
2057
+ ["getInnerHtml", this.getInnerHtml],
2058
+ // ["setValue", this.setValue],
2059
+ ["goto", this.goto.bind(this)],
2060
+ ["isDisabled", this.isDisabled],
2061
+ ["launchSideCar", this.launchSideCar.bind(this)],
2062
+ ["mkdirSync", this.mkdirSync],
2063
+ ["newPage", this.newPage],
2064
+ ["page", this.page],
2065
+ ["pages", this.pages],
2066
+ ["screencast", this.screencast],
2067
+ ["screencastStop", this.screencastStop],
2068
+ ["stopSideCar", this.stopSideCar.bind(this)],
2069
+ ["typeInto", this.typeInto],
2070
+ ["waitForSelector", this.waitForSelector],
2071
+ ["write", this.write],
2072
+ ["writeFileSync", this.writeFileSync]
2073
+ ];
2074
+ }
2075
+ async start() {
2076
+ this.mapping().forEach(async ([command, func]) => {
2077
+ globalThis[command] = func;
2078
+ });
2079
+ if (!fs8.existsSync(`testeranto/reports/${this.name}`)) {
2080
+ fs8.mkdirSync(`testeranto/reports/${this.name}`);
2081
+ }
2082
+ const executablePath = "/opt/homebrew/bin/chromium";
2083
+ try {
2084
+ this.browser = await puppeteer.launch({
2085
+ slowMo: 1,
2086
+ waitForInitialPage: false,
2087
+ executablePath,
2088
+ headless: true,
2089
+ defaultViewport: null,
2090
+ // Disable default 800x600 viewport
2091
+ dumpio: false,
2092
+ devtools: false,
2093
+ args: [
2094
+ "--allow-file-access-from-files",
2095
+ "--allow-insecure-localhost",
2096
+ "--allow-running-insecure-content",
2097
+ "--auto-open-devtools-for-tabs",
2098
+ "--disable-dev-shm-usage",
2099
+ "--disable-extensions",
2100
+ "--disable-features=site-per-process",
2101
+ "--disable-gpu",
2102
+ "--disable-setuid-sandbox",
2103
+ "--disable-site-isolation-trials",
2104
+ "--disable-web-security",
2105
+ "--no-first-run",
2106
+ "--no-sandbox",
2107
+ "--no-startup-window",
2108
+ "--reduce-security-for-testing",
2109
+ "--remote-allow-origins=*",
2110
+ "--start-maximized",
2111
+ "--unsafely-treat-insecure-origin-as-secure=*",
2112
+ `--remote-debugging-port=3234`
2113
+ // "--disable-features=IsolateOrigins,site-per-process",
2114
+ // "--disable-features=IsolateOrigins",
2115
+ // "--disk-cache-dir=/dev/null",
2116
+ // "--disk-cache-size=1",
2117
+ // "--no-zygote",
2118
+ // "--remote-allow-origins=ws://localhost:3234",
2119
+ // "--single-process",
2120
+ // "--start-maximized",
2121
+ // "--unsafely-treat-insecure-origin-as-secure",
2122
+ // "--unsafely-treat-insecure-origin-as-secure=ws://192.168.0.101:3234",
2123
+ ]
2124
+ });
2125
+ } catch (e) {
2126
+ console.error(e);
2127
+ console.error(
2128
+ "could not start chrome via puppeter. Check this path: ",
2129
+ executablePath
2130
+ );
2131
+ }
2132
+ const { nodeEntryPoints, webEntryPoints, pureEntryPoints, pitonoEntryPoints } = this.getRunnables(this.configs.tests, this.name);
2133
+ [
2134
+ [
2135
+ nodeEntryPoints,
2136
+ this.launchNode,
2137
+ "node",
2138
+ (w) => {
2139
+ this.nodeMetafileWatcher = w;
2140
+ }
2141
+ ],
2142
+ [
2143
+ webEntryPoints,
2144
+ this.launchWeb,
2145
+ "web",
2146
+ (w) => {
2147
+ this.webMetafileWatcher = w;
2148
+ }
2149
+ ],
2150
+ [
2151
+ pureEntryPoints,
2152
+ this.launchPure,
2153
+ "pure",
2154
+ (w) => {
2155
+ this.importMetafileWatcher = w;
2156
+ }
2157
+ ],
2158
+ [
2159
+ pitonoEntryPoints,
2160
+ this.launchPitono,
2161
+ "pitono",
2162
+ (w) => {
2163
+ this.pitonoMetafileWatcher = w;
2164
+ }
2165
+ ]
2166
+ ].forEach(
2167
+ async ([eps, launcher, runtime, watcher]) => {
2168
+ let metafile;
2169
+ if (runtime === "pitono") {
2170
+ metafile = `./testeranto/metafiles/python/core.json`;
2171
+ const metafileDir = path7.dirname(metafile);
2172
+ if (!fs8.existsSync(metafileDir)) {
2173
+ fs8.mkdirSync(metafileDir, { recursive: true });
2174
+ }
2175
+ } else {
2176
+ metafile = `./testeranto/metafiles/${runtime}/${this.name}.json`;
2177
+ }
2178
+ if (runtime !== "pitono") {
2179
+ await pollForFile(metafile);
2180
+ }
2181
+ Object.entries(eps).forEach(
2182
+ async ([inputFile, outputFile]) => {
2183
+ this.launchers[inputFile] = () => launcher(inputFile, outputFile);
2184
+ this.launchers[inputFile]();
2185
+ try {
2186
+ watch(outputFile, async (e, filename) => {
2187
+ const hash = await fileHash(outputFile);
2188
+ if (fileHashes[inputFile] !== hash) {
2189
+ fileHashes[inputFile] = hash;
2190
+ console.log(
2191
+ ansiC2.yellow(ansiC2.inverse(`< ${e} ${filename}`))
2192
+ );
2193
+ this.launchers[inputFile]();
2194
+ }
2195
+ });
2196
+ } catch (e) {
2197
+ console.error(e);
2198
+ }
2199
+ }
2200
+ );
2201
+ this.metafileOutputs(runtime);
2202
+ if (runtime === "pitono") {
2203
+ const checkFileExists = () => {
2204
+ if (fs8.existsSync(metafile)) {
2205
+ console.log(
2206
+ ansiC2.green(ansiC2.inverse(`Pitono metafile found: ${metafile}`))
2207
+ );
2208
+ watcher(
2209
+ watch(metafile, async (e, filename) => {
2210
+ console.log(
2211
+ ansiC2.yellow(ansiC2.inverse(`< ${e} ${filename} (${runtime})`))
2212
+ );
2213
+ this.metafileOutputs(runtime);
2214
+ })
2215
+ );
2216
+ this.metafileOutputs(runtime);
2217
+ } else {
2218
+ setTimeout(checkFileExists, 1e3);
2219
+ }
2220
+ };
2221
+ checkFileExists();
2222
+ } else {
2223
+ if (fs8.existsSync(metafile)) {
2224
+ watcher(
2225
+ watch(metafile, async (e, filename) => {
2226
+ console.log(
2227
+ ansiC2.yellow(ansiC2.inverse(`< ${e} ${filename} (${runtime})`))
2228
+ );
2229
+ this.metafileOutputs(runtime);
2230
+ })
2231
+ );
2232
+ }
2233
+ }
2234
+ }
2235
+ );
2236
+ }
2237
+ // async launchExternalTest(
2238
+ // externalTestName: string,
2239
+ // externalTest: {
2240
+ // watch: string[];
2241
+ // exec: string;
2242
+ // }
2243
+ // ) {
2244
+ // // fs.mkdirSync(`testeranto/externalTests/${externalTestName}`);
2245
+ // // exec(externalTest.exec, (error, stdout, stderr) => {
2246
+ // // if (error) {
2247
+ // // fs.writeFileSync(
2248
+ // // `testeranto/externalTests/${externalTestName}/exitcode.txt`,
2249
+ // // `${error.name}\n${error.message}\n${error.code}\n`
2250
+ // // );
2251
+ // // } else {
2252
+ // // fs.writeFileSync(
2253
+ // // `testeranto/externalTests/${externalTestName}/exitcode.txt`,
2254
+ // // `0`
2255
+ // // );
2256
+ // // }
2257
+ // // fs.writeFileSync(
2258
+ // // `testeranto/externalTests/${externalTestName}/stdout.txt`,
2259
+ // // stdout
2260
+ // // );
2261
+ // // fs.writeFileSync(
2262
+ // // `testeranto/externalTests/${externalTestName}/stderr.txt`,
2263
+ // // stderr
2264
+ // // );
2265
+ // // });
2266
+ // }
2267
+ async stop() {
2268
+ console.log(ansiC2.inverse("Testeranto-Run is shutting down gracefully..."));
2269
+ this.mode = "once";
2270
+ this.nodeMetafileWatcher.close();
2271
+ this.webMetafileWatcher.close();
2272
+ this.importMetafileWatcher.close();
2273
+ if (this.pitonoMetafileWatcher) {
2274
+ this.pitonoMetafileWatcher.close();
2275
+ }
2276
+ Object.values(this.logStreams || {}).forEach((logs) => logs.closeAll());
2277
+ this.wss.close(() => {
2278
+ console.log("WebSocket server closed");
2279
+ });
2280
+ this.clients.forEach((client) => {
2281
+ client.terminate();
2282
+ });
2283
+ this.clients.clear();
2284
+ this.httpServer.close(() => {
2285
+ console.log("HTTP server closed");
2286
+ });
2287
+ this.checkForShutdown();
2288
+ }
2289
+ async metafileOutputs(platform) {
2290
+ let metafilePath;
2291
+ if (platform === "pitono") {
2292
+ metafilePath = `./testeranto/metafiles/python/core.json`;
2293
+ } else {
2294
+ metafilePath = `./testeranto/metafiles/${platform}/${this.name}.json`;
2295
+ }
2296
+ if (!fs8.existsSync(metafilePath)) {
2297
+ if (platform === "pitono") {
2298
+ console.log(
2299
+ ansiC2.yellow(ansiC2.inverse(`Pitono metafile not found yet: ${metafilePath}`))
2300
+ );
2301
+ }
2302
+ return;
2303
+ }
2304
+ let metafile;
2305
+ try {
2306
+ const fileContent = fs8.readFileSync(metafilePath).toString();
2307
+ const parsedData = JSON.parse(fileContent);
2308
+ if (platform === "pitono") {
2309
+ metafile = parsedData.metafile || parsedData;
2310
+ } else {
2311
+ metafile = parsedData.metafile;
2312
+ }
2313
+ if (!metafile) {
2314
+ console.log(
2315
+ ansiC2.yellow(ansiC2.inverse(`No metafile found in ${metafilePath}`))
2316
+ );
2317
+ return;
2318
+ }
2319
+ } catch (error) {
2320
+ console.error(`Error reading metafile at ${metafilePath}:`, error);
2321
+ return;
2322
+ }
2323
+ const outputs = metafile.outputs;
2324
+ Object.keys(outputs).forEach(async (k) => {
2325
+ const pattern = `testeranto/bundles/${platform}/${this.name}/${this.configs.src}`;
2326
+ if (!k.startsWith(pattern)) {
2327
+ return false;
2328
+ }
2329
+ const addableFiles = Object.keys(outputs[k].inputs).filter((i) => {
2330
+ if (!fs8.existsSync(i))
2331
+ return false;
2332
+ if (i.startsWith("node_modules"))
2333
+ return false;
2334
+ if (i.startsWith("./node_modules"))
2335
+ return false;
2336
+ return true;
2337
+ });
2338
+ const f2 = `${k.split(".").slice(0, -1).join(".")}/`;
2339
+ if (!fs8.existsSync(f2)) {
2340
+ fs8.mkdirSync(f2);
2341
+ }
2342
+ const entrypoint = outputs[k].entryPoint;
2343
+ if (entrypoint) {
2344
+ const changeDigest = await filesHash(addableFiles);
2345
+ if (changeDigest === changes[entrypoint]) {
2346
+ } else {
2347
+ changes[entrypoint] = changeDigest;
2348
+ this.tscCheck({
2349
+ platform,
2350
+ addableFiles,
2351
+ entrypoint
2352
+ });
2353
+ this.eslintCheck(entrypoint, platform, addableFiles);
2354
+ this.makePrompt(entrypoint, addableFiles, platform);
2355
+ }
2356
+ }
2357
+ });
2358
+ }
2359
+ requestHandler(req, res) {
2360
+ const parsedUrl = url.parse(req.url || "/");
2361
+ let pathname = parsedUrl.pathname || "/";
2362
+ if (pathname === "/") {
2363
+ pathname = "/index.html";
2364
+ }
2365
+ let filePath = pathname.substring(1);
2366
+ if (filePath.startsWith("reports/")) {
2367
+ filePath = `testeranto/${filePath}`;
2368
+ } else if (filePath.startsWith("metafiles/")) {
2369
+ filePath = `testeranto/${filePath}`;
2370
+ } else if (filePath === "projects.json") {
2371
+ filePath = `testeranto/${filePath}`;
2372
+ } else {
2373
+ const possiblePaths = [
2374
+ `dist/${filePath}`,
2375
+ `testeranto/dist/${filePath}`,
2376
+ `../dist/${filePath}`,
2377
+ `./${filePath}`
2378
+ ];
2379
+ let foundPath = null;
2380
+ for (const possiblePath of possiblePaths) {
2381
+ if (fs8.existsSync(possiblePath)) {
2382
+ foundPath = possiblePath;
2383
+ break;
2384
+ }
2385
+ }
2386
+ if (foundPath) {
2387
+ filePath = foundPath;
2388
+ } else {
2389
+ const indexPath = this.findIndexHtml();
2390
+ if (indexPath) {
2391
+ fs8.readFile(indexPath, (err, data) => {
2392
+ if (err) {
2393
+ res.writeHead(404, { "Content-Type": "text/plain" });
2394
+ res.end("404 Not Found");
2395
+ return;
2396
+ }
2397
+ res.writeHead(200, { "Content-Type": "text/html" });
2398
+ res.end(data);
2399
+ });
2400
+ return;
2401
+ } else {
2402
+ res.writeHead(404, { "Content-Type": "text/plain" });
2403
+ res.end("404 Not Found");
2404
+ return;
2405
+ }
2406
+ }
2407
+ }
2408
+ fs8.exists(filePath, (exists) => {
2409
+ if (!exists) {
2410
+ if (!pathname.includes(".") && pathname !== "/") {
2411
+ const indexPath = this.findIndexHtml();
2412
+ if (indexPath) {
2413
+ fs8.readFile(indexPath, (err, data) => {
2414
+ if (err) {
2415
+ res.writeHead(404, { "Content-Type": "text/plain" });
2416
+ res.end("404 Not Found");
2417
+ return;
2418
+ }
2419
+ res.writeHead(200, { "Content-Type": "text/html" });
2420
+ res.end(data);
2421
+ });
2422
+ return;
2423
+ } else {
2424
+ res.writeHead(200, { "Content-Type": "text/html" });
2425
+ res.end(`
2426
+ <html>
2427
+ <body>
2428
+ <h1>Testeranto is running</h1>
2429
+ <p>Frontend files are not built yet. Run 'npm run build' to build the frontend.</p>
2430
+ </body>
2431
+ </html>
2432
+ `);
2433
+ return;
2434
+ }
2435
+ }
2436
+ res.writeHead(404, { "Content-Type": "text/plain" });
2437
+ res.end("404 Not Found");
2438
+ return;
2439
+ }
2440
+ fs8.readFile(filePath, (err, data) => {
2441
+ if (err) {
2442
+ res.writeHead(500, { "Content-Type": "text/plain" });
2443
+ res.end("500 Internal Server Error");
2444
+ return;
2445
+ }
2446
+ const mimeType = mime.lookup(filePath) || "application/octet-stream";
2447
+ res.writeHead(200, { "Content-Type": mimeType });
2448
+ res.end(data);
2449
+ });
2450
+ });
2451
+ }
2452
+ findIndexHtml() {
2453
+ const possiblePaths = [
2454
+ "dist/index.html",
2455
+ "testeranto/dist/index.html",
2456
+ "../dist/index.html",
2457
+ "./index.html"
2458
+ ];
2459
+ for (const path11 of possiblePaths) {
2460
+ if (fs8.existsSync(path11)) {
2461
+ return path11;
2462
+ }
2463
+ }
2464
+ return null;
2465
+ }
2466
+ broadcast(message) {
2467
+ const data = typeof message === "string" ? message : JSON.stringify(message);
2468
+ this.clients.forEach((client) => {
2469
+ if (client.readyState === 1) {
2470
+ client.send(data);
2471
+ }
2472
+ });
2473
+ }
2474
+ checkQueue() {
2475
+ const x = this.queue.pop();
2476
+ if (!x) {
2477
+ ansiC2.inverse(`The following queue is empty`);
2478
+ return;
2479
+ }
2480
+ const test = this.configs.tests.find((t) => t[0] === x);
2481
+ if (!test)
2482
+ throw `test is undefined ${x}`;
2483
+ this.launchers[test[0]]();
2484
+ }
2485
+ };
2486
+ }
2487
+ });
2488
+
2489
+ // src/utils/golingvuMetafile.ts
2490
+ var golingvuMetafile_exports = {};
2491
+ __export(golingvuMetafile_exports, {
2492
+ generateGolangMetafile: () => generateGolangMetafile,
2493
+ writeGolangMetafile: () => writeGolangMetafile
2494
+ });
2495
+ import fs9 from "fs";
2496
+ import path8 from "path";
2497
+ async function generateGolangMetafile(testName2, entryPoints) {
2498
+ const outputs = {};
2499
+ for (const entryPoint of entryPoints) {
2500
+ try {
2501
+ const entryDir = path8.dirname(entryPoint);
2502
+ const goFiles = fs9.readdirSync(entryDir).filter((file) => file.endsWith(".go")).map((file) => path8.join(entryDir, file));
2503
+ const inputs = {};
2504
+ let totalBytes = 0;
2505
+ for (const file of goFiles) {
2506
+ try {
2507
+ const stats = fs9.statSync(file);
2508
+ inputs[file] = { bytesInOutput: stats.size };
2509
+ totalBytes += stats.size;
2510
+ } catch {
2511
+ inputs[file] = { bytesInOutput: 0 };
2512
+ }
2513
+ }
2514
+ if (!inputs[entryPoint]) {
2515
+ try {
2516
+ const entryStats = fs9.statSync(entryPoint);
2517
+ inputs[entryPoint] = { bytesInOutput: entryStats.size };
2518
+ totalBytes += entryStats.size;
2519
+ } catch {
2520
+ inputs[entryPoint] = { bytesInOutput: 0 };
2521
+ }
2522
+ }
2523
+ const outputPath = `testeranto/bundles/golang/${testName2}/${entryPoint}`;
2524
+ outputs[outputPath] = {
2525
+ entryPoint,
2526
+ // Use the source file path, not the bundle path
2527
+ inputs,
2528
+ bytes: totalBytes
2529
+ };
2530
+ } catch (error) {
2531
+ console.error(`Error processing Go entry point ${entryPoint}:`, error);
2532
+ }
2533
+ }
2534
+ const allInputs = {};
2535
+ const allGoFiles = /* @__PURE__ */ new Set();
2536
+ for (const entryPoint of entryPoints) {
2537
+ try {
2538
+ const entryDir = path8.dirname(entryPoint);
2539
+ const goFiles = fs9.readdirSync(entryDir).filter((file) => file.endsWith(".go")).map((file) => path8.join(entryDir, file));
2540
+ goFiles.forEach((file) => allGoFiles.add(file));
2541
+ allGoFiles.add(entryPoint);
2542
+ } catch (error) {
2543
+ console.error(`Error processing Go entry point ${entryPoint} for source files:`, error);
2544
+ }
2545
+ }
2546
+ for (const filePath of Array.from(allGoFiles)) {
2547
+ try {
2548
+ const stats = fs9.statSync(filePath);
2549
+ allInputs[filePath] = {
2550
+ bytes: stats.size,
2551
+ imports: []
2552
+ // Go files don't have imports like JS
2553
+ };
2554
+ } catch {
2555
+ allInputs[filePath] = {
2556
+ bytes: 0,
2557
+ imports: []
2558
+ };
2559
+ }
2560
+ }
2561
+ const esbuildOutputs = {};
2562
+ for (const [outputPath, output] of Object.entries(outputs)) {
2563
+ esbuildOutputs[outputPath] = {
2564
+ bytes: output.bytes,
2565
+ inputs: output.inputs,
2566
+ entryPoint: output.entryPoint
2567
+ };
2568
+ }
2569
+ return {
2570
+ errors: [],
2571
+ warnings: [],
2572
+ metafile: {
2573
+ inputs: allInputs,
2574
+ outputs: esbuildOutputs
2575
+ }
2576
+ };
2577
+ }
2578
+ function writeGolangMetafile(testName2, metafile) {
2579
+ const metafileDir = path8.join(
2580
+ process.cwd(),
2581
+ "testeranto",
2582
+ "metafiles",
2583
+ "golang"
2584
+ );
2585
+ fs9.mkdirSync(metafileDir, { recursive: true });
2586
+ const metafilePath = path8.join(metafileDir, `${testName2}.json`);
2587
+ fs9.writeFileSync(metafilePath, JSON.stringify(metafile, null, 2));
2588
+ }
2589
+ var init_golingvuMetafile = __esm({
2590
+ "src/utils/golingvuMetafile.ts"() {
2591
+ "use strict";
2592
+ }
2593
+ });
2594
+
2595
+ // src/utils/pitonoMetafile.ts
2596
+ var pitonoMetafile_exports = {};
2597
+ __export(pitonoMetafile_exports, {
2598
+ generatePitonoMetafile: () => generatePitonoMetafile,
2599
+ writePitonoMetafile: () => writePitonoMetafile
2600
+ });
2601
+ import fs10 from "fs";
2602
+ import path9 from "path";
2603
+ import { execSync as execSync2 } from "child_process";
2604
+ async function generatePitonoMetafile(testName2, entryPoints) {
2605
+ return {
2606
+ testName: testName2,
2607
+ entryPoints,
2608
+ timestamp: Date.now()
2609
+ };
2610
+ }
2611
+ function writePitonoMetafile(testName2, metafile) {
2612
+ const metafilePath = path9.join(process.cwd(), "testeranto", "pitono", testName2, "metafile.json");
2613
+ const metafileDir = path9.dirname(metafilePath);
2614
+ if (!fs10.existsSync(metafileDir)) {
2615
+ fs10.mkdirSync(metafileDir, { recursive: true });
2616
+ }
2617
+ fs10.writeFileSync(metafilePath, JSON.stringify(metafile, null, 2));
2618
+ console.log(`Pitono metafile written to: ${metafilePath}`);
2619
+ try {
2620
+ const command = `pitono-core-generator ${testName2} ${metafile.entryPoints.join(" ")}`;
2621
+ execSync2(command, { stdio: "inherit" });
2622
+ console.log(`Pitono core.json generated successfully for ${testName2}`);
2623
+ } catch (error) {
2624
+ console.error(`Failed to generate Pitono core.json with installed command: ${error}`);
2625
+ try {
2626
+ const pythonCommand = `python ${process.cwd()}/pitono/core_generator.py ${testName2} ${metafile.entryPoints.join(" ")}`;
2627
+ execSync2(pythonCommand, { stdio: "inherit" });
2628
+ console.log(`Pitono core.json generated successfully using direct Python execution`);
2629
+ } catch (fallbackError) {
2630
+ console.error(`Direct Python execution also failed: ${fallbackError}`);
2631
+ try {
2632
+ const coreData = {
2633
+ testName: testName2,
2634
+ entryPoints: metafile.entryPoints,
2635
+ outputs: {},
2636
+ metafile: {
2637
+ inputs: {},
2638
+ outputs: {}
2639
+ },
2640
+ timestamp: Date.now(),
2641
+ runtime: "pitono"
2642
+ };
2643
+ const coreFilePath = path9.join(process.cwd(), "testeranto", "pitono", testName2, "core.json");
2644
+ fs10.writeFileSync(coreFilePath, JSON.stringify(coreData, null, 2));
2645
+ console.log(`Pitono core.json created manually as fallback`);
2646
+ } catch (manualError) {
2647
+ console.error(`Even manual creation failed: ${manualError}`);
2648
+ }
2649
+ }
2650
+ }
2651
+ }
2652
+ var init_pitonoMetafile = __esm({
2653
+ "src/utils/pitonoMetafile.ts"() {
2654
+ "use strict";
2655
+ }
2656
+ });
2657
+
2658
+ // src/testeranto.ts
2659
+ init_utils();
2660
+ import ansiC3 from "ansi-colors";
2661
+ import fs11 from "fs";
2662
+ import path10 from "path";
2663
+ import readline from "readline";
2664
+ import esbuild from "esbuild";
2665
+
2666
+ // src/utils/buildTemplates.ts
2667
+ var getBaseHtml = (title) => `
2668
+ <!DOCTYPE html>
2669
+ <html lang="en">
2670
+ <head>
2671
+ <meta name="description" content="Webpage description goes here" />
2672
+ <meta charset="utf-8" />
2673
+ <title>${title} - testeranto</title>
2674
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
2675
+ <meta name="author" content="" />
2676
+
2677
+ <script>
2678
+ function initApp() {
2679
+ if (window.React && window.ReactDOM && window.App) {
2680
+ const root = ReactDOM.createRoot(document.getElementById('root'));
2681
+ root.render(React.createElement(App));
2682
+ } else {
2683
+ setTimeout(initApp, 100);
2684
+ }
2685
+ }
2686
+ window.addEventListener('DOMContentLoaded', initApp);
2687
+ </script>
2688
+ `;
2689
+ var AppHtml = () => `
2690
+ ${getBaseHtml("Testeranto")}
2691
+
2692
+ <link rel="stylesheet" href="App.css" />
2693
+ <script src="App.js"></script>
2694
+ </head>
2695
+ <body>
2696
+ <div id="root"></div>
2697
+ </body>
2698
+ </html>
2699
+ `;
2700
+
2701
+ // src/esbuildConfigs/index.ts
2702
+ var esbuildConfigs_default = (config) => {
2703
+ return {
2704
+ // packages: "external",
2705
+ target: "esnext",
2706
+ format: "esm",
2707
+ splitting: true,
2708
+ outExtension: { ".js": ".mjs" },
2709
+ outbase: ".",
2710
+ jsx: "transform",
2711
+ bundle: true,
2712
+ minify: config.minify === true,
2713
+ write: true,
2714
+ loader: {
2715
+ ".js": "jsx",
2716
+ ".png": "binary",
2717
+ ".jpg": "binary"
2718
+ }
2719
+ };
2720
+ };
2721
+
2722
+ // src/esbuildConfigs/inputFilesPlugin.ts
2723
+ import fs from "fs";
2724
+ var otherInputs = {};
2725
+ var register = (entrypoint, sources) => {
2726
+ if (!otherInputs[entrypoint]) {
2727
+ otherInputs[entrypoint] = /* @__PURE__ */ new Set();
2728
+ }
2729
+ sources.forEach((s) => otherInputs[entrypoint].add(s));
2730
+ };
2731
+ var inputFilesPlugin_default = (platform, testName2) => {
2732
+ const f2 = `testeranto/metafiles/${platform}/${testName2}.json`;
2733
+ if (!fs.existsSync(`testeranto/metafiles/${platform}`)) {
2734
+ fs.mkdirSync(`testeranto/metafiles/${platform}`, { recursive: true });
2735
+ }
2736
+ return {
2737
+ register,
2738
+ inputFilesPluginFactory: {
2739
+ name: "metafileWriter",
2740
+ setup(build) {
2741
+ build.onEnd((result) => {
2742
+ fs.writeFileSync(f2, JSON.stringify(result, null, 2));
2743
+ });
2744
+ }
2745
+ }
2746
+ };
2747
+ };
2748
+
2749
+ // src/esbuildConfigs/featuresPlugin.ts
2750
+ import path2 from "path";
2751
+ var featuresPlugin_default = {
2752
+ name: "feature-markdown",
2753
+ setup(build) {
2754
+ build.onResolve({ filter: /\.md$/ }, (args) => {
2755
+ if (args.resolveDir === "")
2756
+ return;
2757
+ return {
2758
+ path: path2.isAbsolute(args.path) ? args.path : path2.join(args.resolveDir, args.path),
2759
+ namespace: "feature-markdown"
2760
+ };
2761
+ });
2762
+ build.onLoad(
2763
+ { filter: /.*/, namespace: "feature-markdown" },
2764
+ async (args) => {
2765
+ return {
2766
+ contents: `file://${args.path}`,
2767
+ loader: "text"
2768
+ // contents: JSON.stringify({ path: args.path }),
2769
+ // loader: "json",
2770
+ // contents: JSON.stringify({
2771
+ // // html: markdownHTML,
2772
+ // raw: markdownContent,
2773
+ // filename: args.path, //path.basename(args.path),
2774
+ // }),
2775
+ // loader: "json",
2776
+ };
2777
+ }
2778
+ );
2779
+ }
2780
+ };
2781
+
2782
+ // src/esbuildConfigs/rebuildPlugin.ts
2783
+ import fs2 from "fs";
2784
+ var rebuildPlugin_default = (r) => {
2785
+ return {
2786
+ name: "rebuild-notify",
2787
+ setup: (build) => {
2788
+ build.onEnd((result) => {
2789
+ console.log(`${r} > build ended with ${result.errors.length} errors`);
2790
+ if (result.errors.length > 0) {
2791
+ fs2.writeFileSync(
2792
+ `./testeranto/reports${r}_build_errors`,
2793
+ JSON.stringify(result, null, 2)
2794
+ );
2795
+ }
2796
+ });
2797
+ }
2798
+ };
2799
+ };
2800
+
2801
+ // src/esbuildConfigs/node.ts
2802
+ var node_default = (config, entryPoints, testName2) => {
2803
+ const { inputFilesPluginFactory, register: register2 } = inputFilesPlugin_default(
2804
+ "node",
2805
+ testName2
2806
+ );
2807
+ return {
2808
+ ...esbuildConfigs_default(config),
2809
+ splitting: true,
2810
+ outdir: `testeranto/bundles/node/${testName2}/`,
2811
+ inject: [`./node_modules/testeranto/dist/cjs-shim.js`],
2812
+ metafile: true,
2813
+ supported: {
2814
+ "dynamic-import": true
2815
+ },
2816
+ define: {
2817
+ "process.env.FLUENTFFMPEG_COV": "0"
2818
+ },
2819
+ absWorkingDir: process.cwd(),
2820
+ banner: {
2821
+ js: `import { createRequire } from 'module';const require = createRequire(import.meta.url);`
2822
+ },
2823
+ platform: "node",
2824
+ external: ["react", ...config.externals],
2825
+ entryPoints: [...entryPoints],
2826
+ plugins: [
2827
+ featuresPlugin_default,
2828
+ inputFilesPluginFactory,
2829
+ rebuildPlugin_default("node"),
2830
+ ...config.nodePlugins.map((p) => p(register2, entryPoints)) || []
2831
+ ]
2832
+ };
2833
+ };
2834
+
2835
+ // src/esbuildConfigs/web.ts
2836
+ import { polyfillNode } from "esbuild-plugin-polyfill-node";
2837
+ import path3 from "path";
2838
+ var web_default = (config, entryPoints, testName2) => {
2839
+ const { inputFilesPluginFactory, register: register2 } = inputFilesPlugin_default(
2840
+ "web",
2841
+ testName2
2842
+ );
2843
+ return {
2844
+ ...esbuildConfigs_default(config),
2845
+ treeShaking: true,
2846
+ outdir: `testeranto/bundles/web/${testName2}`,
2847
+ alias: {
2848
+ react: path3.resolve("./node_modules/react")
2849
+ },
2850
+ metafile: true,
2851
+ external: [
2852
+ "path",
2853
+ "fs",
2854
+ "stream",
2855
+ "http",
2856
+ "constants",
2857
+ "net",
2858
+ "assert",
2859
+ "tls",
2860
+ "os",
2861
+ "child_process",
2862
+ "readline",
2863
+ "zlib",
2864
+ "crypto",
2865
+ "https",
2866
+ "util",
2867
+ "process",
2868
+ "dns"
2869
+ ],
2870
+ platform: "browser",
2871
+ entryPoints: [...entryPoints],
2872
+ loader: config.webLoaders,
2873
+ plugins: [
2874
+ featuresPlugin_default,
2875
+ inputFilesPluginFactory,
2876
+ polyfillNode({
2877
+ // You might need to configure specific Node.js modules you want to polyfill
2878
+ // Example:
2879
+ // modules: {
2880
+ // 'util': true,
2881
+ // 'fs': false,
2882
+ // }
2883
+ }),
2884
+ rebuildPlugin_default("web"),
2885
+ ...(config.webPlugins || []).map((p) => p(register2, entryPoints)) || []
2886
+ ]
2887
+ };
2888
+ };
2889
+
2890
+ // src/esbuildConfigs/pure.ts
2891
+ import { isBuiltin } from "node:module";
2892
+
2893
+ // src/esbuildConfigs/consoleDetectorPlugin.ts
2894
+ import fs3 from "fs";
2895
+ var consoleDetectorPlugin = {
2896
+ name: "console-detector",
2897
+ setup(build) {
2898
+ build.onLoad({ filter: /\.(js|ts)$/ }, async (args) => {
2899
+ const contents = await fs3.promises.readFile(args.path, "utf8");
2900
+ const consolePattern = /console\.(log|error|warn|info|debug|trace|dir|dirxml|table|group|groupEnd|clear|count|countReset|assert|profile|profileEnd|time|timeLog|timeEnd|timeStamp|context|memory)/g;
2901
+ const matches = contents.match(consolePattern);
2902
+ if (matches) {
2903
+ const uniqueMethods = [...new Set(matches)];
2904
+ return {
2905
+ warnings: uniqueMethods.map((method) => ({
2906
+ text: `call of "${method}" was detected, which is not supported in the pure runtime.`
2907
+ // location: {
2908
+ // file: args.path,
2909
+ // line:
2910
+ // contents
2911
+ // .split("\n")
2912
+ // .findIndex((line) => line.includes(method)) + 1,
2913
+ // column: 0,
2914
+ // },
2915
+ }))
2916
+ };
2917
+ }
2918
+ return null;
2919
+ });
2920
+ build.onEnd((buildResult) => {
2921
+ if (buildResult.warnings.find((br) => br.pluginName === "console-detector"))
2922
+ console.warn(
2923
+ `Warning: An unsupported method call was detected in a source file used to build for the pure runtime. It is possible that this method call is in a comment block. If you really want to use this function, change this test to the "node" runtime.`
2924
+ );
2925
+ });
2926
+ }
2927
+ };
2928
+
2929
+ // src/esbuildConfigs/pure.ts
2930
+ var pure_default = (config, entryPoints, testName2) => {
2931
+ const { inputFilesPluginFactory, register: register2 } = inputFilesPlugin_default(
2932
+ "pure",
2933
+ testName2
2934
+ );
2935
+ return {
2936
+ ...esbuildConfigs_default(config),
2937
+ drop: [],
2938
+ splitting: true,
2939
+ outdir: `testeranto/bundles/pure/${testName2}/`,
2940
+ // inject: [`./node_modules/testeranto/dist/cjs-shim.js`],
2941
+ metafile: true,
2942
+ supported: {
2943
+ "dynamic-import": true
2944
+ },
2945
+ define: {
2946
+ "process.env.FLUENTFFMPEG_COV": "0"
2947
+ },
2948
+ absWorkingDir: process.cwd(),
2949
+ banner: {
2950
+ js: `import { createRequire } from 'module';const require = createRequire(import.meta.url);`
2951
+ },
2952
+ platform: "node",
2953
+ external: ["react", ...config.externals],
2954
+ entryPoints: [...entryPoints],
2955
+ plugins: [
2956
+ featuresPlugin_default,
2957
+ inputFilesPluginFactory,
2958
+ consoleDetectorPlugin,
2959
+ // nativeImportDetectorPlugin,
2960
+ {
2961
+ name: "native-node-import-filter",
2962
+ setup(build) {
2963
+ build.onResolve({ filter: /fs/ }, (args) => {
2964
+ if (isBuiltin(args.path)) {
2965
+ throw new Error(
2966
+ `You attempted to import a node module "${args.path}" into a "pure" test, which is not allowed. If you really want to use this package, convert this test from "pure" to "node"`
2967
+ );
2968
+ }
2969
+ return { path: args.path };
2970
+ });
2971
+ }
2972
+ },
2973
+ rebuildPlugin_default("pure"),
2974
+ ...(config.nodePlugins || []).map((p) => p(register2, entryPoints)) || []
2975
+ ]
2976
+ };
2977
+ };
2978
+
2979
+ // src/web.html.ts
2980
+ var web_html_default = (jsfilePath, htmlFilePath, cssfilePath) => `
2981
+ <!DOCTYPE html>
2982
+ <html lang="en">
2983
+
2984
+ <head>
2985
+ <script type="module" src="${jsfilePath}"></script>
2986
+ <link rel="stylesheet" href="${cssfilePath}">
2987
+ </head>
2988
+
2989
+ <body>
2990
+ <div id="root">
2991
+ </div>
2992
+ </body>
2993
+
2994
+ </html>
2995
+ `;
2996
+
2997
+ // src/testeranto.ts
2998
+ readline.emitKeypressEvents(process.stdin);
2999
+ if (process.stdin.isTTY)
3000
+ process.stdin.setRawMode(true);
3001
+ var testName = process.argv[2];
3002
+ var mode = process.argv[3];
3003
+ if (mode !== "once" && mode !== "dev") {
3004
+ console.error(`The 3rd argument should be 'dev' or 'once', not '${mode}'.`);
3005
+ process.exit(-1);
3006
+ }
3007
+ var f = process.cwd() + "/testeranto.config.ts";
3008
+ console.log("config file:", f);
3009
+ import(f).then(async (module) => {
3010
+ const pckge = (await import(`${process.cwd()}/package.json`)).default;
3011
+ const bigConfig = module.default;
3012
+ const project = bigConfig.projects[testName];
3013
+ if (!project) {
3014
+ console.error("no project found for", testName, "in testeranto.config.ts");
3015
+ process.exit(-1);
3016
+ }
3017
+ fs11.writeFileSync(
3018
+ `${process.cwd()}/testeranto/projects.json`,
3019
+ JSON.stringify(Object.keys(bigConfig.projects), null, 2)
3020
+ );
3021
+ const rawConfig = bigConfig.projects[testName];
3022
+ if (!rawConfig) {
3023
+ console.error(`Project "${testName}" does not exist in the configuration.`);
3024
+ console.error("Available projects:", Object.keys(bigConfig.projects));
3025
+ process.exit(-1);
3026
+ }
3027
+ if (!rawConfig.tests) {
3028
+ console.error(testName, "appears to have no tests: ", f);
3029
+ console.error(`here is the config:`);
3030
+ console.log(JSON.stringify(rawConfig));
3031
+ process.exit(-1);
3032
+ }
3033
+ const config = {
3034
+ ...rawConfig,
3035
+ buildDir: process.cwd() + "/testeranto/bundles/" + testName
3036
+ };
3037
+ console.log(ansiC3.inverse("Press 'q' to initiate a graceful shutdown."));
3038
+ console.log(ansiC3.inverse("Press 'x' to quit forcefully."));
3039
+ process.stdin.on("keypress", (str, key) => {
3040
+ if (key.name === "x") {
3041
+ console.log(ansiC3.inverse("Shutting down forcefully..."));
3042
+ process.exit(-1);
3043
+ }
3044
+ });
3045
+ let nodeDone = false;
3046
+ let webDone = false;
3047
+ let importDone = false;
3048
+ let golangDone = false;
3049
+ let pitonoDone = false;
3050
+ let status = "build";
3051
+ const {
3052
+ nodeEntryPoints,
3053
+ nodeEntryPointSidecars,
3054
+ webEntryPoints,
3055
+ webEntryPointSidecars,
3056
+ pureEntryPoints,
3057
+ pureEntryPointSidecars
3058
+ } = getRunnables(config.tests, testName);
3059
+ const onNodeDone = () => {
3060
+ nodeDone = true;
3061
+ onDone();
3062
+ };
3063
+ const onWebDone = () => {
3064
+ webDone = true;
3065
+ onDone();
3066
+ };
3067
+ const onImportDone = () => {
3068
+ importDone = true;
3069
+ onDone();
3070
+ };
3071
+ const onGolangDone = () => {
3072
+ golangDone = true;
3073
+ onDone();
3074
+ };
3075
+ const onPitonoDone = () => {
3076
+ pitonoDone = true;
3077
+ onDone();
3078
+ };
3079
+ let pm = null;
3080
+ const onDone = async () => {
3081
+ const hasGolangTests2 = config.tests.some((test) => test[1] === "golang");
3082
+ const hasPitonoTests2 = config.tests.some((test) => test[1] === "pitono");
3083
+ const allDone = nodeDone && webDone && importDone && (!hasGolangTests2 || golangDone) && (!hasPitonoTests2 || pitonoDone);
3084
+ if (allDone) {
3085
+ status = "built";
3086
+ if (!pm) {
3087
+ const { PM_Main: PM_Main2 } = await init_main().then(() => main_exports);
3088
+ pm = new PM_Main2(config, testName, mode);
3089
+ await pm.start();
3090
+ }
3091
+ }
3092
+ if (allDone && mode === "once") {
3093
+ console.log(
3094
+ ansiC3.inverse(
3095
+ `${testName} was built and the builder exited successfully.`
3096
+ )
3097
+ );
3098
+ }
3099
+ };
3100
+ fs11.writeFileSync(`${process.cwd()}/testeranto/projects.html`, AppHtml());
3101
+ Object.keys(bigConfig.projects).forEach((projectName) => {
3102
+ console.log(`testeranto/reports/${projectName}`);
3103
+ if (!fs11.existsSync(`testeranto/reports/${projectName}`)) {
3104
+ fs11.mkdirSync(`testeranto/reports/${projectName}`);
3105
+ }
3106
+ fs11.writeFileSync(
3107
+ `testeranto/reports/${projectName}/config.json`,
3108
+ JSON.stringify(config, null, 2)
3109
+ );
3110
+ });
3111
+ const getSecondaryEndpointsPoints = (runtime) => {
3112
+ const meta = (ts2, st) => {
3113
+ ts2.forEach((t) => {
3114
+ if (t[1] === runtime) {
3115
+ st.add(t[0]);
3116
+ }
3117
+ if (Array.isArray(t[3])) {
3118
+ meta(t[3], st);
3119
+ }
3120
+ });
3121
+ return st;
3122
+ };
3123
+ return Array.from(meta(config.tests, /* @__PURE__ */ new Set()));
3124
+ };
3125
+ [...getSecondaryEndpointsPoints("pitono")].forEach(async (sourceFilePath) => {
3126
+ console.log(`Pitono test found: ${sourceFilePath}`);
3127
+ });
3128
+ const golangTests = config.tests.filter((test) => test[1] === "golang");
3129
+ const hasGolangTests = golangTests.length > 0;
3130
+ if (hasGolangTests) {
3131
+ const { generateGolangMetafile: generateGolangMetafile2, writeGolangMetafile: writeGolangMetafile2 } = await Promise.resolve().then(() => (init_golingvuMetafile(), golingvuMetafile_exports));
3132
+ const golangEntryPoints = golangTests.map((test) => test[0]);
3133
+ const metafile = await generateGolangMetafile2(testName, golangEntryPoints);
3134
+ writeGolangMetafile2(testName, metafile);
3135
+ onGolangDone();
3136
+ }
3137
+ const pitonoTests = config.tests.filter((test) => test[1] === "pitono");
3138
+ const hasPitonoTests = pitonoTests.length > 0;
3139
+ if (hasPitonoTests) {
3140
+ const { generatePitonoMetafile: generatePitonoMetafile2 } = await Promise.resolve().then(() => (init_pitonoMetafile(), pitonoMetafile_exports));
3141
+ const pitonoEntryPoints = pitonoTests.map((test) => test[0]);
3142
+ const metafile = await generatePitonoMetafile2(testName, pitonoEntryPoints);
3143
+ const pitonoMetafilePath = `${process.cwd()}/testeranto/metafiles/python`;
3144
+ await fs11.promises.mkdir(pitonoMetafilePath, { recursive: true });
3145
+ fs11.writeFileSync(
3146
+ `${pitonoMetafilePath}/core.json`,
3147
+ JSON.stringify(metafile, null, 2)
3148
+ );
3149
+ onPitonoDone();
3150
+ }
3151
+ Promise.resolve(
3152
+ Promise.all(
3153
+ [...getSecondaryEndpointsPoints("web")].map(async (sourceFilePath) => {
3154
+ const sourceFileSplit = sourceFilePath.split("/");
3155
+ const sourceDir = sourceFileSplit.slice(0, -1);
3156
+ const sourceFileName = sourceFileSplit[sourceFileSplit.length - 1];
3157
+ const sourceFileNameMinusJs = sourceFileName.split(".").slice(0, -1).join(".");
3158
+ const htmlFilePath = path10.normalize(
3159
+ `${process.cwd()}/testeranto/bundles/web/${testName}/${sourceDir.join(
3160
+ "/"
3161
+ )}/${sourceFileNameMinusJs}.html`
3162
+ );
3163
+ const jsfilePath = `./${sourceFileNameMinusJs}.mjs`;
3164
+ const cssFilePath = `./${sourceFileNameMinusJs}.css`;
3165
+ return fs11.promises.mkdir(path10.dirname(htmlFilePath), { recursive: true }).then(
3166
+ (x2) => fs11.writeFileSync(
3167
+ htmlFilePath,
3168
+ web_html_default(jsfilePath, htmlFilePath, cssFilePath)
3169
+ )
3170
+ );
3171
+ })
3172
+ )
3173
+ );
3174
+ const x = [
3175
+ ["pure", Object.keys(pureEntryPoints)],
3176
+ ["node", Object.keys(nodeEntryPoints)],
3177
+ ["web", Object.keys(webEntryPoints)]
3178
+ ];
3179
+ x.forEach(async ([runtime, keys]) => {
3180
+ keys.forEach(async (k) => {
3181
+ const folder = `testeranto/reports/${testName}/${k.split(".").slice(0, -1).join(".")}/${runtime}`;
3182
+ await fs11.mkdirSync(folder, { recursive: true });
3183
+ });
3184
+ });
3185
+ [
3186
+ [pureEntryPoints, pureEntryPointSidecars, "pure"],
3187
+ [webEntryPoints, webEntryPointSidecars, "web"],
3188
+ [nodeEntryPoints, nodeEntryPointSidecars, "node"]
3189
+ ].forEach(
3190
+ ([eps, eps2, runtime]) => {
3191
+ [...Object.keys(eps), ...Object.keys(eps2)].forEach((ep) => {
3192
+ const fp = path10.resolve(
3193
+ `testeranto`,
3194
+ `reports`,
3195
+ testName,
3196
+ ep.split(".").slice(0, -1).join("."),
3197
+ runtime
3198
+ );
3199
+ fs11.mkdirSync(fp, { recursive: true });
3200
+ });
3201
+ }
3202
+ );
3203
+ await Promise.all([
3204
+ ...[
3205
+ [
3206
+ pure_default,
3207
+ pureEntryPoints,
3208
+ pureEntryPointSidecars,
3209
+ onImportDone
3210
+ ],
3211
+ [
3212
+ node_default,
3213
+ nodeEntryPoints,
3214
+ nodeEntryPointSidecars,
3215
+ onNodeDone
3216
+ ],
3217
+ [web_default, webEntryPoints, webEntryPointSidecars, onWebDone]
3218
+ ].map(([configer, entryPoints, sidecars, done]) => {
3219
+ esbuild.context(
3220
+ configer(
3221
+ config,
3222
+ [...Object.keys(entryPoints), ...Object.keys(sidecars)],
3223
+ testName
3224
+ )
3225
+ ).then(async (ctx) => {
3226
+ if (mode === "dev") {
3227
+ await ctx.watch().then((v) => {
3228
+ done();
3229
+ });
3230
+ } else {
3231
+ ctx.rebuild().then((v) => {
3232
+ done();
3233
+ });
3234
+ }
3235
+ return ctx;
3236
+ });
3237
+ })
3238
+ ]);
3239
+ process.stdin.on("keypress", (str, key) => {
3240
+ if (key.name === "q") {
3241
+ console.log("Testeranto is shutting down gracefully...");
3242
+ if (pm) {
3243
+ pm.stop();
3244
+ } else {
3245
+ process.exit();
3246
+ }
3247
+ }
3248
+ });
3249
+ });