executable-stories-formatters 0.7.10 → 0.7.11

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/index.cjs CHANGED
@@ -106,8 +106,8 @@ __export(src_exports, {
106
106
  validateCanonicalRun: () => validateCanonicalRun
107
107
  });
108
108
  module.exports = __toCommonJS(src_exports);
109
- var fs7 = require("fs");
110
- var path7 = __toESM(require("path"), 1);
109
+ var fs8 = require("fs");
110
+ var path8 = __toESM(require("path"), 1);
111
111
  var fsPromises = __toESM(require("fs/promises"), 1);
112
112
 
113
113
  // src/converters/acl/status.ts
@@ -760,6 +760,10 @@ ${doc.markdown}`,
760
760
  }
761
761
  };
762
762
 
763
+ // src/formatters/html/renderers/index.ts
764
+ var fs2 = __toESM(require("fs"), 1);
765
+ var path2 = __toESM(require("path"), 1);
766
+
763
767
  // src/formatters/html/template.ts
764
768
  var JS_THEME = `
765
769
  // Theme management
@@ -13070,7 +13074,9 @@ function renderDocMermaid(entry, deps) {
13070
13074
  }
13071
13075
  function renderDocScreenshot(entry, deps) {
13072
13076
  const alt = entry.alt ?? "Screenshot";
13073
- const src = entry.path;
13077
+ const embedEnabled = deps.embedScreenshots ?? true;
13078
+ const isRemote = /^(?:https?:|data:)/i.test(entry.path);
13079
+ const src = embedEnabled && !isRemote && deps.readScreenshot ? deps.readScreenshot(entry.path) ?? entry.path : entry.path;
13074
13080
  return `<div class="doc-screenshot">
13075
13081
  <img src="${deps.escapeHtml(src)}" alt="${deps.escapeHtml(alt)}" class="doc-screenshot-img" />
13076
13082
  ${entry.alt ? `<div class="doc-screenshot-caption">${deps.escapeHtml(entry.alt)}</div>` : ""}
@@ -13657,6 +13663,28 @@ function renderToc(args, deps) {
13657
13663
  }
13658
13664
 
13659
13665
  // src/formatters/html/renderers/index.ts
13666
+ var SCREENSHOT_MIME_BY_EXT = {
13667
+ png: "image/png",
13668
+ jpg: "image/jpeg",
13669
+ jpeg: "image/jpeg",
13670
+ gif: "image/gif",
13671
+ webp: "image/webp",
13672
+ svg: "image/svg+xml",
13673
+ avif: "image/avif",
13674
+ bmp: "image/bmp"
13675
+ };
13676
+ function readScreenshotAsDataUri(filePath) {
13677
+ try {
13678
+ const ext = path2.extname(filePath).slice(1).toLowerCase();
13679
+ const mime = SCREENSHOT_MIME_BY_EXT[ext];
13680
+ if (!mime) return void 0;
13681
+ if (!fs2.existsSync(filePath)) return void 0;
13682
+ const buf = fs2.readFileSync(filePath);
13683
+ return `data:${mime};base64,${buf.toString("base64")}`;
13684
+ } catch {
13685
+ return void 0;
13686
+ }
13687
+ }
13660
13688
  function normalizeOptions(options = {}) {
13661
13689
  return {
13662
13690
  title: options.title ?? "Test Results",
@@ -13680,7 +13708,9 @@ function createHtmlFormatter(options = {}) {
13680
13708
  escapeHtml,
13681
13709
  syntaxHighlighting: opts.syntaxHighlighting,
13682
13710
  markdownEnabled: opts.markdownEnabled,
13683
- mermaidEnabled: opts.mermaidEnabled
13711
+ mermaidEnabled: opts.mermaidEnabled,
13712
+ embedScreenshots: opts.embedScreenshots,
13713
+ readScreenshot: (filePath) => readScreenshotAsDataUri(filePath)
13684
13714
  };
13685
13715
  const renderDocs = (docs, containerClass) => {
13686
13716
  if (!docs || docs.length === 0) return "";
@@ -15109,8 +15139,8 @@ function extractDocAttachments(step) {
15109
15139
  }
15110
15140
  return attachments;
15111
15141
  }
15112
- function guessMediaType(path8) {
15113
- const lower = path8.toLowerCase();
15142
+ function guessMediaType(path9) {
15143
+ const lower = path9.toLowerCase();
15114
15144
  if (lower.endsWith(".png")) return "image/png";
15115
15145
  if (lower.endsWith(".jpg") || lower.endsWith(".jpeg")) return "image/jpeg";
15116
15146
  if (lower.endsWith(".gif")) return "image/gif";
@@ -16154,8 +16184,8 @@ function selectTestCases(args, deps) {
16154
16184
  }
16155
16185
 
16156
16186
  // src/bundler/bundle-assets.ts
16157
- var fs3 = __toESM(require("fs"), 1);
16158
- var path3 = __toESM(require("path"), 1);
16187
+ var fs4 = __toESM(require("fs"), 1);
16188
+ var path4 = __toESM(require("path"), 1);
16159
16189
 
16160
16190
  // src/bundler/scan-html-assets.ts
16161
16191
  function scanHtmlAssets(html) {
@@ -16185,21 +16215,21 @@ function isLocalAssetRef(ref) {
16185
16215
  }
16186
16216
 
16187
16217
  // src/bundler/copy-asset.ts
16188
- var fs2 = __toESM(require("fs"), 1);
16189
- var path2 = __toESM(require("path"), 1);
16218
+ var fs3 = __toESM(require("fs"), 1);
16219
+ var path3 = __toESM(require("path"), 1);
16190
16220
  var crypto = __toESM(require("crypto"), 1);
16191
16221
  function copyAsset(sourcePath, assetsDir) {
16192
- if (!fs2.existsSync(assetsDir)) {
16193
- fs2.mkdirSync(assetsDir, { recursive: true });
16222
+ if (!fs3.existsSync(assetsDir)) {
16223
+ fs3.mkdirSync(assetsDir, { recursive: true });
16194
16224
  }
16195
- const content = fs2.readFileSync(sourcePath);
16225
+ const content = fs3.readFileSync(sourcePath);
16196
16226
  const hash = crypto.createHash("sha256").update(content).digest("hex").slice(0, 8);
16197
- const ext = path2.extname(sourcePath);
16198
- const baseName = sanitize(path2.basename(sourcePath, ext));
16227
+ const ext = path3.extname(sourcePath);
16228
+ const baseName = sanitize(path3.basename(sourcePath, ext));
16199
16229
  const destName = `${baseName}-${hash}${ext}`;
16200
- const destPath = path2.join(assetsDir, destName);
16201
- if (!fs2.existsSync(destPath)) {
16202
- fs2.copyFileSync(sourcePath, destPath);
16230
+ const destPath = path3.join(assetsDir, destName);
16231
+ if (!fs3.existsSync(destPath)) {
16232
+ fs3.copyFileSync(sourcePath, destPath);
16203
16233
  }
16204
16234
  return `assets/${destName}`;
16205
16235
  }
@@ -16209,15 +16239,15 @@ function sanitize(name) {
16209
16239
 
16210
16240
  // src/bundler/bundle-assets.ts
16211
16241
  function bundleAssets(htmlPath, options = {}) {
16212
- const htmlDir = path3.dirname(htmlPath);
16213
- const assetsDir = path3.join(htmlDir, "assets");
16214
- let html = fs3.readFileSync(htmlPath, "utf8");
16242
+ const htmlDir = path4.dirname(htmlPath);
16243
+ const assetsDir = path4.join(htmlDir, "assets");
16244
+ let html = fs4.readFileSync(htmlPath, "utf8");
16215
16245
  const refs = scanHtmlAssets(html);
16216
16246
  let copiedCount = 0;
16217
16247
  const missing = [];
16218
16248
  for (const ref of refs) {
16219
- const absolutePath = path3.resolve(htmlDir, ref);
16220
- if (!fs3.existsSync(absolutePath)) {
16249
+ const absolutePath = path4.resolve(htmlDir, ref);
16250
+ if (!fs4.existsSync(absolutePath)) {
16221
16251
  missing.push(ref);
16222
16252
  continue;
16223
16253
  }
@@ -16230,7 +16260,7 @@ function bundleAssets(htmlPath, options = {}) {
16230
16260
  `Missing asset${missing.length > 1 ? "s" : ""}: ${missing.join(", ")}`
16231
16261
  );
16232
16262
  }
16233
- fs3.writeFileSync(htmlPath, html, "utf8");
16263
+ fs4.writeFileSync(htmlPath, html, "utf8");
16234
16264
  return {
16235
16265
  copiedCount,
16236
16266
  missingCount: missing.length,
@@ -16713,15 +16743,15 @@ function groupBy7(items, keyFn) {
16713
16743
  }
16714
16744
 
16715
16745
  // src/formatters/astro-assets.ts
16716
- var fs4 = __toESM(require("fs"), 1);
16717
- var path4 = __toESM(require("path"), 1);
16746
+ var fs5 = __toESM(require("fs"), 1);
16747
+ var path5 = __toESM(require("path"), 1);
16718
16748
  var SKIP_PREFIXES = ["http://", "https://", "data:", "#"];
16719
16749
  function isLocalPath(src) {
16720
16750
  const trimmed = src.trim();
16721
16751
  if (SKIP_PREFIXES.some((prefix) => trimmed.startsWith(prefix))) {
16722
16752
  return false;
16723
16753
  }
16724
- return !path4.posix.isAbsolute(trimmed) && !path4.win32.isAbsolute(trimmed);
16754
+ return !path5.posix.isAbsolute(trimmed) && !path5.win32.isAbsolute(trimmed);
16725
16755
  }
16726
16756
  function stripCodeContent(markdown) {
16727
16757
  let result = markdown.replace(/^[ \t]*(`{3,}|~{3,})[^\n]*\n[\s\S]*?^[ \t]*\1\s*$/gm, "");
@@ -16815,8 +16845,8 @@ function copyMarkdownAssets(options) {
16815
16845
  const pathMap = /* @__PURE__ */ new Map();
16816
16846
  const missing = [];
16817
16847
  for (const ref of refs) {
16818
- const absPath = path4.resolve(markdownDir, ref);
16819
- if (!fs4.existsSync(absPath)) {
16848
+ const absPath = path5.resolve(markdownDir, ref);
16849
+ if (!fs5.existsSync(absPath)) {
16820
16850
  if (!allowMissing) {
16821
16851
  throw new Error(`Asset not found: ${absPath}`);
16822
16852
  }
@@ -17832,27 +17862,27 @@ function pickleStepArgumentToDocs(ps) {
17832
17862
  }
17833
17863
 
17834
17864
  // src/utils/git-info.ts
17835
- var fs5 = __toESM(require("fs"), 1);
17836
- var path5 = __toESM(require("path"), 1);
17865
+ var fs6 = __toESM(require("fs"), 1);
17866
+ var path6 = __toESM(require("path"), 1);
17837
17867
  function readGitSha(cwd = process.cwd()) {
17838
17868
  const envSha = process.env.GITHUB_SHA || process.env.GIT_COMMIT || process.env.CI_COMMIT_SHA;
17839
17869
  if (envSha) return envSha;
17840
17870
  const gitDir = findGitDir(cwd);
17841
17871
  if (!gitDir) return void 0;
17842
17872
  try {
17843
- const headPath = path5.join(gitDir, "HEAD");
17844
- const head = fs5.readFileSync(headPath, "utf8").trim();
17873
+ const headPath = path6.join(gitDir, "HEAD");
17874
+ const head = fs6.readFileSync(headPath, "utf8").trim();
17845
17875
  if (!head.startsWith("ref:")) {
17846
17876
  return head;
17847
17877
  }
17848
17878
  const refPath = head.replace("ref:", "").trim();
17849
- const refFile = path5.join(gitDir, refPath);
17850
- if (fs5.existsSync(refFile)) {
17851
- return fs5.readFileSync(refFile, "utf8").trim();
17879
+ const refFile = path6.join(gitDir, refPath);
17880
+ if (fs6.existsSync(refFile)) {
17881
+ return fs6.readFileSync(refFile, "utf8").trim();
17852
17882
  }
17853
- const packedRefs = path5.join(gitDir, "packed-refs");
17854
- if (fs5.existsSync(packedRefs)) {
17855
- const content = fs5.readFileSync(packedRefs, "utf8");
17883
+ const packedRefs = path6.join(gitDir, "packed-refs");
17884
+ if (fs6.existsSync(packedRefs)) {
17885
+ const content = fs6.readFileSync(packedRefs, "utf8");
17856
17886
  for (const line of content.split("\n")) {
17857
17887
  if (!line || line.startsWith("#") || line.startsWith("^")) continue;
17858
17888
  const [sha, ref] = line.split(" ");
@@ -17867,19 +17897,19 @@ function readGitSha(cwd = process.cwd()) {
17867
17897
  function findGitDir(start) {
17868
17898
  let current = start;
17869
17899
  while (true) {
17870
- const candidate = path5.join(current, ".git");
17871
- if (fs5.existsSync(candidate)) {
17872
- const stat = fs5.statSync(candidate);
17900
+ const candidate = path6.join(current, ".git");
17901
+ if (fs6.existsSync(candidate)) {
17902
+ const stat = fs6.statSync(candidate);
17873
17903
  if (stat.isFile()) {
17874
- const content = fs5.readFileSync(candidate, "utf8").trim();
17904
+ const content = fs6.readFileSync(candidate, "utf8").trim();
17875
17905
  const match = content.match(/^gitdir: (.+)$/);
17876
17906
  if (match) {
17877
- return path5.resolve(current, match[1]);
17907
+ return path6.resolve(current, match[1]);
17878
17908
  }
17879
17909
  }
17880
17910
  return candidate;
17881
17911
  }
17882
- const parent = path5.dirname(current);
17912
+ const parent = path6.dirname(current);
17883
17913
  if (parent === current) return void 0;
17884
17914
  current = parent;
17885
17915
  }
@@ -17890,8 +17920,8 @@ function readBranchName(cwd = process.cwd()) {
17890
17920
  const gitDir = findGitDir(cwd);
17891
17921
  if (!gitDir) return void 0;
17892
17922
  try {
17893
- const headPath = path5.join(gitDir, "HEAD");
17894
- const head = fs5.readFileSync(headPath, "utf8").trim();
17923
+ const headPath = path6.join(gitDir, "HEAD");
17924
+ const head = fs6.readFileSync(headPath, "utf8").trim();
17895
17925
  if (head.startsWith("ref:")) {
17896
17926
  const refPath = head.replace("ref:", "").trim();
17897
17927
  const match = refPath.match(/^refs\/heads\/(.+)$/);
@@ -17928,8 +17958,8 @@ function nanosecondsToMs(ns) {
17928
17958
  }
17929
17959
 
17930
17960
  // src/utils/metadata.ts
17931
- var fs6 = __toESM(require("fs"), 1);
17932
- var path6 = __toESM(require("path"), 1);
17961
+ var fs7 = __toESM(require("fs"), 1);
17962
+ var path7 = __toESM(require("path"), 1);
17933
17963
  var versionCache = /* @__PURE__ */ new Map();
17934
17964
  function readPackageVersion(root) {
17935
17965
  if (versionCache.has(root)) {
@@ -17940,18 +17970,18 @@ function readPackageVersion(root) {
17940
17970
  return version;
17941
17971
  }
17942
17972
  function findPackageVersion(startDir) {
17943
- let current = path6.resolve(startDir);
17973
+ let current = path7.resolve(startDir);
17944
17974
  while (true) {
17945
- const pkgPath = path6.join(current, "package.json");
17975
+ const pkgPath = path7.join(current, "package.json");
17946
17976
  try {
17947
- if (fs6.existsSync(pkgPath)) {
17948
- const raw = fs6.readFileSync(pkgPath, "utf8");
17977
+ if (fs7.existsSync(pkgPath)) {
17978
+ const raw = fs7.readFileSync(pkgPath, "utf8");
17949
17979
  const parsed = JSON.parse(raw);
17950
17980
  return parsed.version;
17951
17981
  }
17952
17982
  } catch {
17953
17983
  }
17954
- const parent = path6.dirname(current);
17984
+ const parent = path7.dirname(current);
17955
17985
  if (parent === current) {
17956
17986
  return void 0;
17957
17987
  }
@@ -18942,11 +18972,11 @@ function computeOutputPath(sourceFile, format, mode, colocatedStyle, baseOutputD
18942
18972
  const ext = FORMAT_EXTENSIONS[format];
18943
18973
  const effectiveName = outputName + (outputNameSuffix ?? "");
18944
18974
  if (mode === "aggregated") {
18945
- return toPosix(path7.join(baseOutputDir, `${effectiveName}${ext}`));
18975
+ return toPosix(path8.join(baseOutputDir, `${effectiveName}${ext}`));
18946
18976
  }
18947
18977
  const normalizedSource = toPosix(sourceFile);
18948
- const dirOfSource = path7.posix.dirname(normalizedSource);
18949
- let baseName = path7.posix.basename(normalizedSource);
18978
+ const dirOfSource = path8.posix.dirname(normalizedSource);
18979
+ let baseName = path8.posix.basename(normalizedSource);
18950
18980
  for (const testExt of TEST_EXTENSIONS) {
18951
18981
  if (baseName.endsWith(testExt)) {
18952
18982
  baseName = baseName.slice(0, -testExt.length);
@@ -18955,9 +18985,9 @@ function computeOutputPath(sourceFile, format, mode, colocatedStyle, baseOutputD
18955
18985
  }
18956
18986
  const fileName = `${baseName}.${effectiveName}${ext}`;
18957
18987
  if (colocatedStyle === "adjacent") {
18958
- return toPosix(path7.posix.join(dirOfSource, fileName));
18988
+ return toPosix(path8.posix.join(dirOfSource, fileName));
18959
18989
  }
18960
- return toPosix(path7.posix.join(baseOutputDir, dirOfSource, fileName));
18990
+ return toPosix(path8.posix.join(baseOutputDir, dirOfSource, fileName));
18961
18991
  }
18962
18992
  function groupTestCasesByOutput(testCases, format, options, logger, outputNameSuffix) {
18963
18993
  const groups = /* @__PURE__ */ new Map();
@@ -19155,8 +19185,8 @@ var ReportGenerator = class {
19155
19185
  if (astroPaths) {
19156
19186
  for (const mdPath of astroPaths) {
19157
19187
  const content = await fsPromises.readFile(mdPath, "utf8");
19158
- const mdDir = path7.dirname(mdPath);
19159
- const assetsDir = path7.resolve(this.options.astro.assetsDir);
19188
+ const mdDir = path8.dirname(mdPath);
19189
+ const assetsDir = path8.resolve(this.options.astro.assetsDir);
19160
19190
  const result = copyMarkdownAssets({
19161
19191
  markdown: content,
19162
19192
  markdownDir: mdDir,
@@ -19187,9 +19217,9 @@ var ReportGenerator = class {
19187
19217
  if (groups.size === 0 && this.options.output.mode === "aggregated") {
19188
19218
  const ext = FORMAT_EXTENSIONS[format];
19189
19219
  const effectiveName = this.options.outputName + (outputNameSuffix ?? "");
19190
- const outputPath = toPosix(path7.join(this.options.outputDir, `${effectiveName}${ext}`));
19220
+ const outputPath = toPosix(path8.join(this.options.outputDir, `${effectiveName}${ext}`));
19191
19221
  const content = await this.formatContent(run, format);
19192
- const dir = path7.dirname(outputPath);
19222
+ const dir = path8.dirname(outputPath);
19193
19223
  await fsPromises.mkdir(dir, { recursive: true });
19194
19224
  await this.deps.writeFile(outputPath, content);
19195
19225
  return [outputPath];
@@ -19201,7 +19231,7 @@ var ReportGenerator = class {
19201
19231
  testCases
19202
19232
  };
19203
19233
  const content = await this.formatContent(groupRun, format);
19204
- const dir = path7.dirname(outputPath);
19234
+ const dir = path8.dirname(outputPath);
19205
19235
  await fsPromises.mkdir(dir, { recursive: true });
19206
19236
  await this.deps.writeFile(outputPath, content);
19207
19237
  writtenPaths.push(outputPath);
@@ -19324,7 +19354,7 @@ async function generateRunComparison(args) {
19324
19354
  await fsPromises.mkdir(outputDir, { recursive: true });
19325
19355
  for (const format of args.formats) {
19326
19356
  const ext = format === "html" ? ".html" : ".md";
19327
- const outputPath = toPosix(path7.join(outputDir, `${outputName}${ext}`));
19357
+ const outputPath = toPosix(path8.join(outputDir, `${outputName}${ext}`));
19328
19358
  const content = format === "html" ? new RunDiffHtmlFormatter({ title: args.title }).format(diff) : new RunDiffMarkdownFormatter({ title: args.title }).format(diff);
19329
19359
  await fsPromises.writeFile(outputPath, content, "utf8");
19330
19360
  files.push(outputPath);