executable-stories-formatters 0.7.10 → 0.7.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +197 -104
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +166 -73
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +165 -72
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
// src/cli.ts
|
|
4
4
|
import { parseArgs } from "util";
|
|
5
|
-
import * as
|
|
6
|
-
import * as
|
|
5
|
+
import * as fs8 from "fs";
|
|
6
|
+
import * as path8 from "path";
|
|
7
7
|
|
|
8
8
|
// src/validation/schema-validator.ts
|
|
9
9
|
import Ajv from "ajv/dist/2020.js";
|
|
@@ -492,17 +492,17 @@ function validateRawRun(data) {
|
|
|
492
492
|
return { valid: true, errors: [] };
|
|
493
493
|
}
|
|
494
494
|
const errors = (validate.errors ?? []).map((err) => {
|
|
495
|
-
const
|
|
495
|
+
const path9 = err.instancePath || "/";
|
|
496
496
|
const message = err.message ?? "unknown error";
|
|
497
497
|
if (err.keyword === "additionalProperties") {
|
|
498
498
|
const extra = err.params.additionalProperty;
|
|
499
|
-
return `${
|
|
499
|
+
return `${path9}: ${message} \u2014 '${extra}'`;
|
|
500
500
|
}
|
|
501
501
|
if (err.keyword === "enum") {
|
|
502
502
|
const allowed = err.params.allowedValues;
|
|
503
|
-
return `${
|
|
503
|
+
return `${path9}: ${message} \u2014 allowed: ${JSON.stringify(allowed)}`;
|
|
504
504
|
}
|
|
505
|
-
return `${
|
|
505
|
+
return `${path9}: ${message}`;
|
|
506
506
|
});
|
|
507
507
|
return { valid: false, errors };
|
|
508
508
|
}
|
|
@@ -966,7 +966,7 @@ ${result.errors.join("\n")}`);
|
|
|
966
966
|
|
|
967
967
|
// src/index.ts
|
|
968
968
|
import "fs";
|
|
969
|
-
import * as
|
|
969
|
+
import * as path6 from "path";
|
|
970
970
|
import * as fsPromises from "fs/promises";
|
|
971
971
|
|
|
972
972
|
// src/converters/acl/lines.ts
|
|
@@ -1330,6 +1330,10 @@ ${doc.markdown}`,
|
|
|
1330
1330
|
}
|
|
1331
1331
|
};
|
|
1332
1332
|
|
|
1333
|
+
// src/formatters/html/renderers/index.ts
|
|
1334
|
+
import * as fs2 from "fs";
|
|
1335
|
+
import * as path2 from "path";
|
|
1336
|
+
|
|
1333
1337
|
// src/formatters/html/template.ts
|
|
1334
1338
|
var JS_THEME = `
|
|
1335
1339
|
// Theme management
|
|
@@ -2988,6 +2992,27 @@ body {
|
|
|
2988
2992
|
border: 1px solid var(--border);
|
|
2989
2993
|
}
|
|
2990
2994
|
|
|
2995
|
+
.attachment-unavailable {
|
|
2996
|
+
padding: 0.75rem 1rem;
|
|
2997
|
+
border: 1px dashed var(--border);
|
|
2998
|
+
border-radius: calc(var(--radius) - 2px);
|
|
2999
|
+
background: var(--muted, transparent);
|
|
3000
|
+
color: var(--muted-foreground);
|
|
3001
|
+
font-size: 0.8125rem;
|
|
3002
|
+
}
|
|
3003
|
+
|
|
3004
|
+
.attachment-unavailable-label {
|
|
3005
|
+
font-weight: 600;
|
|
3006
|
+
margin-bottom: 0.25rem;
|
|
3007
|
+
}
|
|
3008
|
+
|
|
3009
|
+
.attachment-unavailable-path {
|
|
3010
|
+
font-family: var(--font-mono, ui-monospace, monospace);
|
|
3011
|
+
font-size: 0.75rem;
|
|
3012
|
+
word-break: break-all;
|
|
3013
|
+
opacity: 0.8;
|
|
3014
|
+
}
|
|
3015
|
+
|
|
2991
3016
|
/* ============================================================================
|
|
2992
3017
|
Chevron Icon - smooth rotation
|
|
2993
3018
|
============================================================================ */
|
|
@@ -3553,6 +3578,27 @@ body {
|
|
|
3553
3578
|
font-style: italic;
|
|
3554
3579
|
}
|
|
3555
3580
|
|
|
3581
|
+
.doc-screenshot-missing {
|
|
3582
|
+
padding: 0.75rem 1rem;
|
|
3583
|
+
border: 1px dashed var(--border);
|
|
3584
|
+
border-radius: calc(var(--radius) - 2px);
|
|
3585
|
+
background: var(--muted, transparent);
|
|
3586
|
+
color: var(--muted-foreground);
|
|
3587
|
+
font-size: 0.8125rem;
|
|
3588
|
+
}
|
|
3589
|
+
|
|
3590
|
+
.doc-screenshot-missing-label {
|
|
3591
|
+
font-weight: 600;
|
|
3592
|
+
margin-bottom: 0.25rem;
|
|
3593
|
+
}
|
|
3594
|
+
|
|
3595
|
+
.doc-screenshot-missing-path {
|
|
3596
|
+
font-family: var(--font-mono, ui-monospace, monospace);
|
|
3597
|
+
font-size: 0.75rem;
|
|
3598
|
+
word-break: break-all;
|
|
3599
|
+
opacity: 0.8;
|
|
3600
|
+
}
|
|
3601
|
+
|
|
3556
3602
|
/* ============================================================================
|
|
3557
3603
|
Documentation Entries - Custom
|
|
3558
3604
|
============================================================================ */
|
|
@@ -13527,11 +13573,18 @@ function renderTagBar(args, deps) {
|
|
|
13527
13573
|
</div>`;
|
|
13528
13574
|
}
|
|
13529
13575
|
|
|
13576
|
+
// src/notifiers/ansi-strip.ts
|
|
13577
|
+
function stripAnsi(text2) {
|
|
13578
|
+
return text2.replace(/\x1B\[[0-?]*[ -/]*[@-~]/g, "");
|
|
13579
|
+
}
|
|
13580
|
+
|
|
13530
13581
|
// src/formatters/html/renderers/error-box.ts
|
|
13531
13582
|
function renderErrorBox(args, deps) {
|
|
13532
|
-
const
|
|
13583
|
+
const message = stripAnsi(args.message);
|
|
13584
|
+
const stack = args.stack != null ? stripAnsi(args.stack) : void 0;
|
|
13585
|
+
const body = stack != null ? `${deps.escapeHtml(message)}
|
|
13533
13586
|
|
|
13534
|
-
${deps.escapeHtml(
|
|
13587
|
+
${deps.escapeHtml(stack)}` : deps.escapeHtml(message);
|
|
13535
13588
|
return `<div class="error-box">${body}</div>`;
|
|
13536
13589
|
}
|
|
13537
13590
|
|
|
@@ -13544,6 +13597,7 @@ function renderAttachments(args, deps) {
|
|
|
13544
13597
|
const isImage = att.mediaType.startsWith("image/");
|
|
13545
13598
|
const isVideo = att.mediaType.startsWith("video/");
|
|
13546
13599
|
const isBase64 = att.contentEncoding === "BASE64";
|
|
13600
|
+
const isUnreachableFsPath = deps.embedScreenshots && !isBase64 && typeof att.body === "string" && /^(?:[/\\]|[A-Za-z]:[/\\])/.test(att.body);
|
|
13547
13601
|
if (isImage && deps.embedScreenshots && isBase64) {
|
|
13548
13602
|
return `
|
|
13549
13603
|
<div class="attachment">
|
|
@@ -13551,12 +13605,19 @@ function renderAttachments(args, deps) {
|
|
|
13551
13605
|
<img class="attachment-image" src="data:${att.mediaType};base64,${att.body}" alt="${deps.escapeHtml(att.name)}" />
|
|
13552
13606
|
</div>`;
|
|
13553
13607
|
}
|
|
13554
|
-
if (isVideo && deps.embedScreenshots) {
|
|
13608
|
+
if (isVideo && deps.embedScreenshots && !isUnreachableFsPath) {
|
|
13555
13609
|
const src = isBase64 ? `data:${att.mediaType};base64,${att.body}` : att.body;
|
|
13556
13610
|
return `
|
|
13557
13611
|
<div class="attachment">
|
|
13558
13612
|
${deps.escapeHtml(att.name)}
|
|
13559
13613
|
<video class="attachment-video" controls src="${deps.escapeHtml(src)}"></video>
|
|
13614
|
+
</div>`;
|
|
13615
|
+
}
|
|
13616
|
+
if (isUnreachableFsPath) {
|
|
13617
|
+
return `
|
|
13618
|
+
<div class="attachment attachment-unavailable">
|
|
13619
|
+
<div class="attachment-unavailable-label">${deps.escapeHtml(att.name)} unavailable</div>
|
|
13620
|
+
<div class="attachment-unavailable-path">${deps.escapeHtml(att.body)}</div>
|
|
13560
13621
|
</div>`;
|
|
13561
13622
|
}
|
|
13562
13623
|
const href = isBase64 ? `data:${att.mediaType};base64,${att.body}` : att.body;
|
|
@@ -13637,7 +13698,20 @@ function renderDocMermaid(entry, deps) {
|
|
|
13637
13698
|
}
|
|
13638
13699
|
function renderDocScreenshot(entry, deps) {
|
|
13639
13700
|
const alt = entry.alt ?? "Screenshot";
|
|
13640
|
-
const
|
|
13701
|
+
const embedEnabled = deps.embedScreenshots ?? true;
|
|
13702
|
+
const isRemote = /^(?:https?:|data:)/i.test(entry.path);
|
|
13703
|
+
const embedAttempted = !isRemote && embedEnabled && !!deps.readScreenshot;
|
|
13704
|
+
const inlined = embedAttempted ? deps.readScreenshot(entry.path) : void 0;
|
|
13705
|
+
const isAbsoluteFsPath = !isRemote && /^(?:[/\\]|[A-Za-z]:[/\\])/.test(entry.path);
|
|
13706
|
+
if (embedAttempted && inlined === void 0 && isAbsoluteFsPath) {
|
|
13707
|
+
const captionHtml = entry.alt ? `<div class="doc-screenshot-caption">${deps.escapeHtml(entry.alt)}</div>` : "";
|
|
13708
|
+
return `<div class="doc-screenshot doc-screenshot-missing">
|
|
13709
|
+
<div class="doc-screenshot-missing-label">Screenshot unavailable</div>
|
|
13710
|
+
<div class="doc-screenshot-missing-path">${deps.escapeHtml(entry.path)}</div>
|
|
13711
|
+
${captionHtml}
|
|
13712
|
+
</div>`;
|
|
13713
|
+
}
|
|
13714
|
+
const src = inlined ?? entry.path;
|
|
13641
13715
|
return `<div class="doc-screenshot">
|
|
13642
13716
|
<img src="${deps.escapeHtml(src)}" alt="${deps.escapeHtml(alt)}" class="doc-screenshot-img" />
|
|
13643
13717
|
${entry.alt ? `<div class="doc-screenshot-caption">${deps.escapeHtml(entry.alt)}</div>` : ""}
|
|
@@ -14219,6 +14293,28 @@ function renderToc(args, deps) {
|
|
|
14219
14293
|
}
|
|
14220
14294
|
|
|
14221
14295
|
// src/formatters/html/renderers/index.ts
|
|
14296
|
+
var SCREENSHOT_MIME_BY_EXT = {
|
|
14297
|
+
png: "image/png",
|
|
14298
|
+
jpg: "image/jpeg",
|
|
14299
|
+
jpeg: "image/jpeg",
|
|
14300
|
+
gif: "image/gif",
|
|
14301
|
+
webp: "image/webp",
|
|
14302
|
+
svg: "image/svg+xml",
|
|
14303
|
+
avif: "image/avif",
|
|
14304
|
+
bmp: "image/bmp"
|
|
14305
|
+
};
|
|
14306
|
+
function readScreenshotAsDataUri(filePath) {
|
|
14307
|
+
try {
|
|
14308
|
+
const ext = path2.extname(filePath).slice(1).toLowerCase();
|
|
14309
|
+
const mime = SCREENSHOT_MIME_BY_EXT[ext];
|
|
14310
|
+
if (!mime) return void 0;
|
|
14311
|
+
if (!fs2.existsSync(filePath)) return void 0;
|
|
14312
|
+
const buf = fs2.readFileSync(filePath);
|
|
14313
|
+
return `data:${mime};base64,${buf.toString("base64")}`;
|
|
14314
|
+
} catch {
|
|
14315
|
+
return void 0;
|
|
14316
|
+
}
|
|
14317
|
+
}
|
|
14222
14318
|
function normalizeOptions(options = {}) {
|
|
14223
14319
|
return {
|
|
14224
14320
|
title: options.title ?? "Test Results",
|
|
@@ -14242,7 +14338,9 @@ function createHtmlFormatter(options = {}) {
|
|
|
14242
14338
|
escapeHtml,
|
|
14243
14339
|
syntaxHighlighting: opts.syntaxHighlighting,
|
|
14244
14340
|
markdownEnabled: opts.markdownEnabled,
|
|
14245
|
-
mermaidEnabled: opts.mermaidEnabled
|
|
14341
|
+
mermaidEnabled: opts.mermaidEnabled,
|
|
14342
|
+
embedScreenshots: opts.embedScreenshots,
|
|
14343
|
+
readScreenshot: (filePath) => readScreenshotAsDataUri(filePath)
|
|
14246
14344
|
};
|
|
14247
14345
|
const renderDocs = (docs, containerClass) => {
|
|
14248
14346
|
if (!docs || docs.length === 0) return "";
|
|
@@ -15671,8 +15769,8 @@ function extractDocAttachments(step) {
|
|
|
15671
15769
|
}
|
|
15672
15770
|
return attachments;
|
|
15673
15771
|
}
|
|
15674
|
-
function guessMediaType(
|
|
15675
|
-
const lower =
|
|
15772
|
+
function guessMediaType(path9) {
|
|
15773
|
+
const lower = path9.toLowerCase();
|
|
15676
15774
|
if (lower.endsWith(".png")) return "image/png";
|
|
15677
15775
|
if (lower.endsWith(".jpg") || lower.endsWith(".jpeg")) return "image/jpeg";
|
|
15678
15776
|
if (lower.endsWith(".gif")) return "image/gif";
|
|
@@ -16746,8 +16844,8 @@ function selectTestCases(args, deps) {
|
|
|
16746
16844
|
}
|
|
16747
16845
|
|
|
16748
16846
|
// src/bundler/bundle-assets.ts
|
|
16749
|
-
import * as
|
|
16750
|
-
import * as
|
|
16847
|
+
import * as fs4 from "fs";
|
|
16848
|
+
import * as path4 from "path";
|
|
16751
16849
|
|
|
16752
16850
|
// src/bundler/scan-html-assets.ts
|
|
16753
16851
|
function scanHtmlAssets(html) {
|
|
@@ -16777,21 +16875,21 @@ function isLocalAssetRef(ref) {
|
|
|
16777
16875
|
}
|
|
16778
16876
|
|
|
16779
16877
|
// src/bundler/copy-asset.ts
|
|
16780
|
-
import * as
|
|
16781
|
-
import * as
|
|
16878
|
+
import * as fs3 from "fs";
|
|
16879
|
+
import * as path3 from "path";
|
|
16782
16880
|
import * as crypto from "crypto";
|
|
16783
16881
|
function copyAsset(sourcePath, assetsDir) {
|
|
16784
|
-
if (!
|
|
16785
|
-
|
|
16882
|
+
if (!fs3.existsSync(assetsDir)) {
|
|
16883
|
+
fs3.mkdirSync(assetsDir, { recursive: true });
|
|
16786
16884
|
}
|
|
16787
|
-
const content =
|
|
16885
|
+
const content = fs3.readFileSync(sourcePath);
|
|
16788
16886
|
const hash = crypto.createHash("sha256").update(content).digest("hex").slice(0, 8);
|
|
16789
|
-
const ext =
|
|
16790
|
-
const baseName = sanitize(
|
|
16887
|
+
const ext = path3.extname(sourcePath);
|
|
16888
|
+
const baseName = sanitize(path3.basename(sourcePath, ext));
|
|
16791
16889
|
const destName = `${baseName}-${hash}${ext}`;
|
|
16792
|
-
const destPath =
|
|
16793
|
-
if (!
|
|
16794
|
-
|
|
16890
|
+
const destPath = path3.join(assetsDir, destName);
|
|
16891
|
+
if (!fs3.existsSync(destPath)) {
|
|
16892
|
+
fs3.copyFileSync(sourcePath, destPath);
|
|
16795
16893
|
}
|
|
16796
16894
|
return `assets/${destName}`;
|
|
16797
16895
|
}
|
|
@@ -16801,15 +16899,15 @@ function sanitize(name) {
|
|
|
16801
16899
|
|
|
16802
16900
|
// src/bundler/bundle-assets.ts
|
|
16803
16901
|
function bundleAssets(htmlPath, options = {}) {
|
|
16804
|
-
const htmlDir =
|
|
16805
|
-
const assetsDir =
|
|
16806
|
-
let html =
|
|
16902
|
+
const htmlDir = path4.dirname(htmlPath);
|
|
16903
|
+
const assetsDir = path4.join(htmlDir, "assets");
|
|
16904
|
+
let html = fs4.readFileSync(htmlPath, "utf8");
|
|
16807
16905
|
const refs = scanHtmlAssets(html);
|
|
16808
16906
|
let copiedCount = 0;
|
|
16809
16907
|
const missing = [];
|
|
16810
16908
|
for (const ref of refs) {
|
|
16811
|
-
const absolutePath =
|
|
16812
|
-
if (!
|
|
16909
|
+
const absolutePath = path4.resolve(htmlDir, ref);
|
|
16910
|
+
if (!fs4.existsSync(absolutePath)) {
|
|
16813
16911
|
missing.push(ref);
|
|
16814
16912
|
continue;
|
|
16815
16913
|
}
|
|
@@ -16822,7 +16920,7 @@ function bundleAssets(htmlPath, options = {}) {
|
|
|
16822
16920
|
`Missing asset${missing.length > 1 ? "s" : ""}: ${missing.join(", ")}`
|
|
16823
16921
|
);
|
|
16824
16922
|
}
|
|
16825
|
-
|
|
16923
|
+
fs4.writeFileSync(htmlPath, html, "utf8");
|
|
16826
16924
|
return {
|
|
16827
16925
|
copiedCount,
|
|
16828
16926
|
missingCount: missing.length,
|
|
@@ -17305,15 +17403,15 @@ function groupBy7(items, keyFn) {
|
|
|
17305
17403
|
}
|
|
17306
17404
|
|
|
17307
17405
|
// src/formatters/astro-assets.ts
|
|
17308
|
-
import * as
|
|
17309
|
-
import * as
|
|
17406
|
+
import * as fs5 from "fs";
|
|
17407
|
+
import * as path5 from "path";
|
|
17310
17408
|
var SKIP_PREFIXES = ["http://", "https://", "data:", "#"];
|
|
17311
17409
|
function isLocalPath(src) {
|
|
17312
17410
|
const trimmed = src.trim();
|
|
17313
17411
|
if (SKIP_PREFIXES.some((prefix) => trimmed.startsWith(prefix))) {
|
|
17314
17412
|
return false;
|
|
17315
17413
|
}
|
|
17316
|
-
return !
|
|
17414
|
+
return !path5.posix.isAbsolute(trimmed) && !path5.win32.isAbsolute(trimmed);
|
|
17317
17415
|
}
|
|
17318
17416
|
function stripCodeContent(markdown) {
|
|
17319
17417
|
let result = markdown.replace(/^[ \t]*(`{3,}|~{3,})[^\n]*\n[\s\S]*?^[ \t]*\1\s*$/gm, "");
|
|
@@ -17407,8 +17505,8 @@ function copyMarkdownAssets(options) {
|
|
|
17407
17505
|
const pathMap = /* @__PURE__ */ new Map();
|
|
17408
17506
|
const missing = [];
|
|
17409
17507
|
for (const ref of refs) {
|
|
17410
|
-
const absPath =
|
|
17411
|
-
if (!
|
|
17508
|
+
const absPath = path5.resolve(markdownDir, ref);
|
|
17509
|
+
if (!fs5.existsSync(absPath)) {
|
|
17412
17510
|
if (!allowMissing) {
|
|
17413
17511
|
throw new Error(`Asset not found: ${absPath}`);
|
|
17414
17512
|
}
|
|
@@ -18022,11 +18120,6 @@ function pickleStepArgumentToDocs(ps) {
|
|
|
18022
18120
|
return docs;
|
|
18023
18121
|
}
|
|
18024
18122
|
|
|
18025
|
-
// src/notifiers/ansi-strip.ts
|
|
18026
|
-
function stripAnsi(text2) {
|
|
18027
|
-
return text2.replace(/\x1B\[[0-?]*[ -/]*[@-~]/g, "");
|
|
18028
|
-
}
|
|
18029
|
-
|
|
18030
18123
|
// src/notifiers/slack.ts
|
|
18031
18124
|
function truncate(text2, maxLen) {
|
|
18032
18125
|
if (text2.length <= maxLen) return text2;
|
|
@@ -18716,11 +18809,11 @@ function computeOutputPath(sourceFile, format, mode, colocatedStyle, baseOutputD
|
|
|
18716
18809
|
const ext = FORMAT_EXTENSIONS[format];
|
|
18717
18810
|
const effectiveName = outputName + (outputNameSuffix ?? "");
|
|
18718
18811
|
if (mode === "aggregated") {
|
|
18719
|
-
return toPosix(
|
|
18812
|
+
return toPosix(path6.join(baseOutputDir, `${effectiveName}${ext}`));
|
|
18720
18813
|
}
|
|
18721
18814
|
const normalizedSource = toPosix(sourceFile);
|
|
18722
|
-
const dirOfSource =
|
|
18723
|
-
let baseName =
|
|
18815
|
+
const dirOfSource = path6.posix.dirname(normalizedSource);
|
|
18816
|
+
let baseName = path6.posix.basename(normalizedSource);
|
|
18724
18817
|
for (const testExt of TEST_EXTENSIONS) {
|
|
18725
18818
|
if (baseName.endsWith(testExt)) {
|
|
18726
18819
|
baseName = baseName.slice(0, -testExt.length);
|
|
@@ -18729,9 +18822,9 @@ function computeOutputPath(sourceFile, format, mode, colocatedStyle, baseOutputD
|
|
|
18729
18822
|
}
|
|
18730
18823
|
const fileName = `${baseName}.${effectiveName}${ext}`;
|
|
18731
18824
|
if (colocatedStyle === "adjacent") {
|
|
18732
|
-
return toPosix(
|
|
18825
|
+
return toPosix(path6.posix.join(dirOfSource, fileName));
|
|
18733
18826
|
}
|
|
18734
|
-
return toPosix(
|
|
18827
|
+
return toPosix(path6.posix.join(baseOutputDir, dirOfSource, fileName));
|
|
18735
18828
|
}
|
|
18736
18829
|
function groupTestCasesByOutput(testCases, format, options, logger, outputNameSuffix) {
|
|
18737
18830
|
const groups = /* @__PURE__ */ new Map();
|
|
@@ -18929,8 +19022,8 @@ var ReportGenerator = class {
|
|
|
18929
19022
|
if (astroPaths) {
|
|
18930
19023
|
for (const mdPath of astroPaths) {
|
|
18931
19024
|
const content = await fsPromises.readFile(mdPath, "utf8");
|
|
18932
|
-
const mdDir =
|
|
18933
|
-
const assetsDir =
|
|
19025
|
+
const mdDir = path6.dirname(mdPath);
|
|
19026
|
+
const assetsDir = path6.resolve(this.options.astro.assetsDir);
|
|
18934
19027
|
const result = copyMarkdownAssets({
|
|
18935
19028
|
markdown: content,
|
|
18936
19029
|
markdownDir: mdDir,
|
|
@@ -18961,9 +19054,9 @@ var ReportGenerator = class {
|
|
|
18961
19054
|
if (groups.size === 0 && this.options.output.mode === "aggregated") {
|
|
18962
19055
|
const ext = FORMAT_EXTENSIONS[format];
|
|
18963
19056
|
const effectiveName = this.options.outputName + (outputNameSuffix ?? "");
|
|
18964
|
-
const outputPath = toPosix(
|
|
19057
|
+
const outputPath = toPosix(path6.join(this.options.outputDir, `${effectiveName}${ext}`));
|
|
18965
19058
|
const content = await this.formatContent(run, format);
|
|
18966
|
-
const dir =
|
|
19059
|
+
const dir = path6.dirname(outputPath);
|
|
18967
19060
|
await fsPromises.mkdir(dir, { recursive: true });
|
|
18968
19061
|
await this.deps.writeFile(outputPath, content);
|
|
18969
19062
|
return [outputPath];
|
|
@@ -18975,7 +19068,7 @@ var ReportGenerator = class {
|
|
|
18975
19068
|
testCases
|
|
18976
19069
|
};
|
|
18977
19070
|
const content = await this.formatContent(groupRun, format);
|
|
18978
|
-
const dir =
|
|
19071
|
+
const dir = path6.dirname(outputPath);
|
|
18979
19072
|
await fsPromises.mkdir(dir, { recursive: true });
|
|
18980
19073
|
await this.deps.writeFile(outputPath, content);
|
|
18981
19074
|
writtenPaths.push(outputPath);
|
|
@@ -19095,7 +19188,7 @@ async function generateRunComparison(args) {
|
|
|
19095
19188
|
await fsPromises.mkdir(outputDir, { recursive: true });
|
|
19096
19189
|
for (const format of args.formats) {
|
|
19097
19190
|
const ext = format === "html" ? ".html" : ".md";
|
|
19098
|
-
const outputPath = toPosix(
|
|
19191
|
+
const outputPath = toPosix(path6.join(outputDir, `${outputName}${ext}`));
|
|
19099
19192
|
const content = format === "html" ? new RunDiffHtmlFormatter({ title: args.title }).format(diff) : new RunDiffMarkdownFormatter({ title: args.title }).format(diff);
|
|
19100
19193
|
await fsPromises.writeFile(outputPath, content, "utf8");
|
|
19101
19194
|
files.push(outputPath);
|
|
@@ -19104,23 +19197,23 @@ async function generateRunComparison(args) {
|
|
|
19104
19197
|
}
|
|
19105
19198
|
|
|
19106
19199
|
// src/init-astro.ts
|
|
19107
|
-
import * as
|
|
19108
|
-
import * as
|
|
19200
|
+
import * as fs7 from "fs";
|
|
19201
|
+
import * as path7 from "path";
|
|
19109
19202
|
import { fileURLToPath } from "url";
|
|
19110
|
-
var __dirname =
|
|
19203
|
+
var __dirname = path7.dirname(fileURLToPath(import.meta.url));
|
|
19111
19204
|
function initAstro(options = {}) {
|
|
19112
19205
|
const targetDir = options.targetDir ?? "./story-docs";
|
|
19113
19206
|
const force = options.force ?? false;
|
|
19114
|
-
if (
|
|
19115
|
-
const entries =
|
|
19207
|
+
if (fs7.existsSync(targetDir)) {
|
|
19208
|
+
const entries = fs7.readdirSync(targetDir);
|
|
19116
19209
|
if (entries.length > 0 && !force) {
|
|
19117
19210
|
throw new Error(
|
|
19118
19211
|
`Directory "${targetDir}" already exists and is not empty. Use --force to overwrite.`
|
|
19119
19212
|
);
|
|
19120
19213
|
}
|
|
19121
19214
|
}
|
|
19122
|
-
const templateDir =
|
|
19123
|
-
if (!
|
|
19215
|
+
const templateDir = path7.resolve(__dirname, "..", "templates", "astro-starlight");
|
|
19216
|
+
if (!fs7.existsSync(templateDir)) {
|
|
19124
19217
|
throw new Error(
|
|
19125
19218
|
`Template directory not found at ${templateDir}. Ensure the package is installed correctly.`
|
|
19126
19219
|
);
|
|
@@ -19129,25 +19222,25 @@ function initAstro(options = {}) {
|
|
|
19129
19222
|
return { targetDir };
|
|
19130
19223
|
}
|
|
19131
19224
|
function copyDirRecursive(src, dest) {
|
|
19132
|
-
|
|
19133
|
-
const entries =
|
|
19225
|
+
fs7.mkdirSync(dest, { recursive: true });
|
|
19226
|
+
const entries = fs7.readdirSync(src, { withFileTypes: true });
|
|
19134
19227
|
for (const entry of entries) {
|
|
19135
|
-
const srcPath =
|
|
19136
|
-
const destPath =
|
|
19228
|
+
const srcPath = path7.join(src, entry.name);
|
|
19229
|
+
const destPath = path7.join(dest, entry.name);
|
|
19137
19230
|
if (entry.isDirectory()) {
|
|
19138
19231
|
copyDirRecursive(srcPath, destPath);
|
|
19139
19232
|
} else {
|
|
19140
|
-
|
|
19233
|
+
fs7.copyFileSync(srcPath, destPath);
|
|
19141
19234
|
}
|
|
19142
19235
|
}
|
|
19143
19236
|
}
|
|
19144
19237
|
|
|
19145
19238
|
// src/config.ts
|
|
19146
|
-
import { existsSync as
|
|
19239
|
+
import { existsSync as existsSync7 } from "fs";
|
|
19147
19240
|
import { resolve as resolve6 } from "path";
|
|
19148
19241
|
async function loadConfig(configPath) {
|
|
19149
19242
|
const resolved = configPath ? resolve6(configPath) : resolve6(process.cwd(), "executable-stories.config.js");
|
|
19150
|
-
if (!
|
|
19243
|
+
if (!existsSync7(resolved)) return {};
|
|
19151
19244
|
const mod = await import(resolved);
|
|
19152
19245
|
const config = mod.default;
|
|
19153
19246
|
if (!config || typeof config !== "object" || Array.isArray(config)) {
|
|
@@ -19566,20 +19659,20 @@ async function readInput(args) {
|
|
|
19566
19659
|
if (args.stdin) {
|
|
19567
19660
|
return readStdin();
|
|
19568
19661
|
}
|
|
19569
|
-
const filePath =
|
|
19570
|
-
if (!
|
|
19662
|
+
const filePath = path8.resolve(args.inputFile);
|
|
19663
|
+
if (!fs8.existsSync(filePath)) {
|
|
19571
19664
|
console.error(`Error: File not found: ${filePath}`);
|
|
19572
19665
|
process.exit(EXIT_USAGE);
|
|
19573
19666
|
}
|
|
19574
|
-
return
|
|
19667
|
+
return fs8.readFileSync(filePath, "utf8");
|
|
19575
19668
|
}
|
|
19576
19669
|
function readFileInput(filePath) {
|
|
19577
|
-
const resolved =
|
|
19578
|
-
if (!
|
|
19670
|
+
const resolved = path8.resolve(filePath);
|
|
19671
|
+
if (!fs8.existsSync(resolved)) {
|
|
19579
19672
|
console.error(`Error: File not found: ${resolved}`);
|
|
19580
19673
|
process.exit(EXIT_USAGE);
|
|
19581
19674
|
}
|
|
19582
|
-
return
|
|
19675
|
+
return fs8.readFileSync(resolved, "utf8");
|
|
19583
19676
|
}
|
|
19584
19677
|
function readStdin() {
|
|
19585
19678
|
return new Promise((resolve8, reject) => {
|
|
@@ -19712,14 +19805,14 @@ function tryNormalizeRunFromText(text2, args) {
|
|
|
19712
19805
|
}
|
|
19713
19806
|
}
|
|
19714
19807
|
function listBaselineCandidates(currentFile, args) {
|
|
19715
|
-
const baselineDir =
|
|
19716
|
-
const currentResolved =
|
|
19717
|
-
if (!
|
|
19808
|
+
const baselineDir = path8.resolve(args.baselineDir ?? path8.dirname(currentFile));
|
|
19809
|
+
const currentResolved = path8.resolve(currentFile);
|
|
19810
|
+
if (!fs8.existsSync(baselineDir)) {
|
|
19718
19811
|
console.error(`Error: baseline directory not found: ${baselineDir}`);
|
|
19719
19812
|
process.exit(EXIT_USAGE);
|
|
19720
19813
|
}
|
|
19721
|
-
const entries =
|
|
19722
|
-
return entries.filter((entry) => entry.isFile()).map((entry) =>
|
|
19814
|
+
const entries = fs8.readdirSync(baselineDir, { withFileTypes: true });
|
|
19815
|
+
return entries.filter((entry) => entry.isFile()).map((entry) => path8.join(baselineDir, entry.name)).filter((candidate) => path8.resolve(candidate) !== currentResolved).filter(
|
|
19723
19816
|
(candidate) => args.inputType === "ndjson" ? candidate.endsWith(".ndjson") : candidate.endsWith(".json")
|
|
19724
19817
|
);
|
|
19725
19818
|
}
|
|
@@ -19727,14 +19820,14 @@ function resolveBaselineAuto(currentFile, currentRun, args) {
|
|
|
19727
19820
|
const candidates = listBaselineCandidates(currentFile, args);
|
|
19728
19821
|
const comparable = [];
|
|
19729
19822
|
for (const candidate of candidates) {
|
|
19730
|
-
const run = tryNormalizeRunFromText(
|
|
19823
|
+
const run = tryNormalizeRunFromText(fs8.readFileSync(candidate, "utf8"), args);
|
|
19731
19824
|
if (run) {
|
|
19732
19825
|
comparable.push({ file: candidate, run });
|
|
19733
19826
|
}
|
|
19734
19827
|
}
|
|
19735
19828
|
if (comparable.length === 0) {
|
|
19736
19829
|
console.error(
|
|
19737
|
-
`Error: no compatible baseline files found in ${
|
|
19830
|
+
`Error: no compatible baseline files found in ${path8.resolve(args.baselineDir ?? path8.dirname(currentFile))}.`
|
|
19738
19831
|
);
|
|
19739
19832
|
process.exit(EXIT_USAGE);
|
|
19740
19833
|
}
|
|
@@ -19823,9 +19916,9 @@ async function main() {
|
|
|
19823
19916
|
process.exit(EXIT_SCHEMA_VALIDATION);
|
|
19824
19917
|
}
|
|
19825
19918
|
if (args.emitCanonical) {
|
|
19826
|
-
const outPath =
|
|
19827
|
-
|
|
19828
|
-
|
|
19919
|
+
const outPath = path8.resolve(args.emitCanonical);
|
|
19920
|
+
fs8.mkdirSync(path8.dirname(outPath), { recursive: true });
|
|
19921
|
+
fs8.writeFileSync(outPath, JSON.stringify(run, null, 2), "utf8");
|
|
19829
19922
|
}
|
|
19830
19923
|
try {
|
|
19831
19924
|
const result = await generateReports(run, args);
|
|
@@ -19882,9 +19975,9 @@ ${msg}`);
|
|
|
19882
19975
|
}
|
|
19883
19976
|
const run = data;
|
|
19884
19977
|
if (args.emitCanonical) {
|
|
19885
|
-
const outPath =
|
|
19886
|
-
|
|
19887
|
-
|
|
19978
|
+
const outPath = path8.resolve(args.emitCanonical);
|
|
19979
|
+
fs8.mkdirSync(path8.dirname(outPath), { recursive: true });
|
|
19980
|
+
fs8.writeFileSync(outPath, JSON.stringify(run, null, 2), "utf8");
|
|
19888
19981
|
}
|
|
19889
19982
|
try {
|
|
19890
19983
|
const result = await generateReports(run, args);
|
|
@@ -19940,9 +20033,9 @@ ${msg}`);
|
|
|
19940
20033
|
process.exit(EXIT_CANONICAL_VALIDATION);
|
|
19941
20034
|
}
|
|
19942
20035
|
if (args.emitCanonical) {
|
|
19943
|
-
const outPath =
|
|
19944
|
-
|
|
19945
|
-
|
|
20036
|
+
const outPath = path8.resolve(args.emitCanonical);
|
|
20037
|
+
fs8.mkdirSync(path8.dirname(outPath), { recursive: true });
|
|
20038
|
+
fs8.writeFileSync(outPath, JSON.stringify(canonical, null, 2), "utf8");
|
|
19946
20039
|
}
|
|
19947
20040
|
try {
|
|
19948
20041
|
const result = await generateReports(canonical, args, droppedMissingStory);
|
|
@@ -19967,9 +20060,9 @@ function runCustomFormatters(run, customRequested, formatters, args) {
|
|
|
19967
20060
|
const ext = formatter.fileExtension ?? formatName;
|
|
19968
20061
|
const baseName = args.outputName ?? "report";
|
|
19969
20062
|
const filename = args.outputNameTimestamp ? `${baseName}-${Math.floor(run.startedAtMs / 1e3)}.${ext}` : `${baseName}.${ext}`;
|
|
19970
|
-
const filepath =
|
|
19971
|
-
|
|
19972
|
-
|
|
20063
|
+
const filepath = path8.join(outputDir, filename);
|
|
20064
|
+
fs8.mkdirSync(outputDir, { recursive: true });
|
|
20065
|
+
fs8.writeFileSync(filepath, content, "utf8");
|
|
19973
20066
|
console.log(`Generated: ${filepath}`);
|
|
19974
20067
|
} catch (err) {
|
|
19975
20068
|
console.error(`Error running custom formatter "${formatName}": ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -20019,13 +20112,13 @@ async function dispatchNotifications(run, args) {
|
|
|
20019
20112
|
}
|
|
20020
20113
|
function runHistoryPipeline(run, args) {
|
|
20021
20114
|
if (!args.historyFile) return;
|
|
20022
|
-
const historyPath =
|
|
20115
|
+
const historyPath = path8.resolve(args.historyFile);
|
|
20023
20116
|
const store = loadHistory(
|
|
20024
20117
|
{ filePath: historyPath },
|
|
20025
20118
|
{
|
|
20026
20119
|
readFile: (p) => {
|
|
20027
20120
|
try {
|
|
20028
|
-
return
|
|
20121
|
+
return fs8.readFileSync(p, "utf8");
|
|
20029
20122
|
} catch {
|
|
20030
20123
|
return void 0;
|
|
20031
20124
|
}
|
|
@@ -20038,11 +20131,11 @@ function runHistoryPipeline(run, args) {
|
|
|
20038
20131
|
run,
|
|
20039
20132
|
maxRuns: args.maxHistoryRuns
|
|
20040
20133
|
});
|
|
20041
|
-
const dir =
|
|
20042
|
-
|
|
20134
|
+
const dir = path8.dirname(historyPath);
|
|
20135
|
+
fs8.mkdirSync(dir, { recursive: true });
|
|
20043
20136
|
saveHistory(
|
|
20044
20137
|
{ filePath: historyPath, store: updated },
|
|
20045
|
-
{ writeFile: (p, content) =>
|
|
20138
|
+
{ writeFile: (p, content) => fs8.writeFileSync(p, content, "utf8") }
|
|
20046
20139
|
);
|
|
20047
20140
|
let metricsCount = 0;
|
|
20048
20141
|
for (const testId of Object.keys(updated.tests)) {
|
|
@@ -20140,9 +20233,9 @@ function printResult(result, args, startMs, droppedMissingStory = 0) {
|
|
|
20140
20233
|
function printCompareResult(result, args, startMs) {
|
|
20141
20234
|
const durationMs = Date.now() - startMs;
|
|
20142
20235
|
if (result.prSummary && args.prSummaryFile) {
|
|
20143
|
-
const outputPath =
|
|
20144
|
-
|
|
20145
|
-
|
|
20236
|
+
const outputPath = path8.resolve(args.prSummaryFile);
|
|
20237
|
+
fs8.mkdirSync(path8.dirname(outputPath), { recursive: true });
|
|
20238
|
+
fs8.writeFileSync(outputPath, result.prSummary, "utf8");
|
|
20146
20239
|
}
|
|
20147
20240
|
if (args.jsonSummary) {
|
|
20148
20241
|
console.log(
|
|
@@ -20213,7 +20306,7 @@ Generate an API token at https://id.atlassian.com/manage-profile/security/api-to
|
|
|
20213
20306
|
console.error("Error: missing ADF file argument. Run with --help for usage.");
|
|
20214
20307
|
process.exit(EXIT_USAGE);
|
|
20215
20308
|
}
|
|
20216
|
-
if (!
|
|
20309
|
+
if (!fs8.existsSync(inputFile)) {
|
|
20217
20310
|
console.error(`Error: file not found: ${inputFile}`);
|
|
20218
20311
|
process.exit(EXIT_USAGE);
|
|
20219
20312
|
}
|
|
@@ -20241,7 +20334,7 @@ Generate an API token at https://id.atlassian.com/manage-profile/security/api-to
|
|
|
20241
20334
|
console.error("Error: --title is required when creating a new page");
|
|
20242
20335
|
process.exit(EXIT_USAGE);
|
|
20243
20336
|
}
|
|
20244
|
-
const adf =
|
|
20337
|
+
const adf = fs8.readFileSync(path8.resolve(inputFile), "utf8");
|
|
20245
20338
|
if (dryRun) {
|
|
20246
20339
|
console.log(
|
|
20247
20340
|
JSON.stringify(
|
|
@@ -20320,7 +20413,7 @@ Generate an API token at https://id.atlassian.com/manage-profile/security/api-to
|
|
|
20320
20413
|
console.error("Error: missing ADF file argument. Run with --help for usage.");
|
|
20321
20414
|
process.exit(EXIT_USAGE);
|
|
20322
20415
|
}
|
|
20323
|
-
if (!
|
|
20416
|
+
if (!fs8.existsSync(inputFile)) {
|
|
20324
20417
|
console.error(`Error: file not found: ${inputFile}`);
|
|
20325
20418
|
process.exit(EXIT_USAGE);
|
|
20326
20419
|
}
|
|
@@ -20347,7 +20440,7 @@ Generate an API token at https://id.atlassian.com/manage-profile/security/api-to
|
|
|
20347
20440
|
process.exit(EXIT_USAGE);
|
|
20348
20441
|
}
|
|
20349
20442
|
const mode = modeRaw;
|
|
20350
|
-
const adf =
|
|
20443
|
+
const adf = fs8.readFileSync(path8.resolve(inputFile), "utf8");
|
|
20351
20444
|
if (dryRun) {
|
|
20352
20445
|
console.log(
|
|
20353
20446
|
JSON.stringify(
|