executable-stories-formatters 0.7.6 → 0.7.8

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.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // src/index.ts
2
2
  import "fs";
3
- import * as path6 from "path";
3
+ import * as path7 from "path";
4
4
  import * as fsPromises from "fs/promises";
5
5
 
6
6
  // src/converters/acl/status.ts
@@ -15002,8 +15002,8 @@ function extractDocAttachments(step) {
15002
15002
  }
15003
15003
  return attachments;
15004
15004
  }
15005
- function guessMediaType(path7) {
15006
- const lower = path7.toLowerCase();
15005
+ function guessMediaType(path8) {
15006
+ const lower = path8.toLowerCase();
15007
15007
  if (lower.endsWith(".png")) return "image/png";
15008
15008
  if (lower.endsWith(".jpg") || lower.endsWith(".jpeg")) return "image/jpeg";
15009
15009
  if (lower.endsWith(".gif")) return "image/gif";
@@ -15144,11 +15144,11 @@ var CucumberHtmlFormatter = class {
15144
15144
  for (const envelope of envelopes) {
15145
15145
  const accepted = htmlStream.write(envelope);
15146
15146
  if (!accepted) {
15147
- await new Promise((resolve5) => htmlStream.once("drain", resolve5));
15147
+ await new Promise((resolve7) => htmlStream.once("drain", resolve7));
15148
15148
  }
15149
15149
  }
15150
- await new Promise((resolve5, reject) => {
15151
- collector.on("finish", resolve5);
15150
+ await new Promise((resolve7, reject) => {
15151
+ collector.on("finish", resolve7);
15152
15152
  collector.on("error", reject);
15153
15153
  htmlStream.end();
15154
15154
  });
@@ -16150,6 +16150,177 @@ function replaceAssetRef(html, original, replacement) {
16150
16150
  return html;
16151
16151
  }
16152
16152
 
16153
+ // src/formatters/astro.ts
16154
+ var AstroFormatter = class _AstroFormatter {
16155
+ markdownFormatter;
16156
+ title;
16157
+ constructor(options = {}) {
16158
+ this.title = options.markdown?.title ?? "User Stories";
16159
+ this.markdownFormatter = new MarkdownFormatter({
16160
+ ...options.markdown,
16161
+ title: this.title,
16162
+ stepStyle: "gherkin",
16163
+ includeFrontMatter: false,
16164
+ includeSummaryTable: false,
16165
+ includeMetadata: false
16166
+ });
16167
+ }
16168
+ format(run) {
16169
+ const markdown = this.markdownFormatter.format(run);
16170
+ const body = markdown.replace(/^# .+\n\n?/, "");
16171
+ const frontmatter = this.buildFrontmatter(run);
16172
+ return `${frontmatter}
16173
+ ${body}`;
16174
+ }
16175
+ buildFrontmatter(run) {
16176
+ const badge = _AstroFormatter.computeBadge(run.testCases);
16177
+ const count = run.testCases.length;
16178
+ const description = `${count} scenario${count !== 1 ? "s" : ""} \u2014 ${badge.text.toLowerCase()}`;
16179
+ const lines = [
16180
+ "---",
16181
+ `title: ${this.title}`,
16182
+ `description: ${description}`,
16183
+ "sidebar:",
16184
+ " badge:",
16185
+ ` text: ${badge.text}`,
16186
+ ` variant: ${badge.variant}`,
16187
+ "---"
16188
+ ];
16189
+ return lines.join("\n");
16190
+ }
16191
+ static computeBadge(testCases) {
16192
+ const statuses = new Set(testCases.map((tc) => tc.status));
16193
+ if (statuses.has("failed")) return { text: "Failed", variant: "danger" };
16194
+ if (statuses.has("pending")) return { text: "Pending", variant: "caution" };
16195
+ if (statuses.has("skipped") && !statuses.has("passed")) return { text: "Skipped", variant: "caution" };
16196
+ return { text: "Passed", variant: "success" };
16197
+ }
16198
+ };
16199
+
16200
+ // src/formatters/astro-assets.ts
16201
+ import * as fs4 from "fs";
16202
+ import * as path4 from "path";
16203
+ var SKIP_PREFIXES = ["http://", "https://", "data:", "#"];
16204
+ function isLocalPath(src) {
16205
+ const trimmed = src.trim();
16206
+ if (SKIP_PREFIXES.some((prefix) => trimmed.startsWith(prefix))) {
16207
+ return false;
16208
+ }
16209
+ return !path4.posix.isAbsolute(trimmed) && !path4.win32.isAbsolute(trimmed);
16210
+ }
16211
+ function stripCodeContent(markdown) {
16212
+ let result = markdown.replace(/^[ \t]*(`{3,}|~{3,})[^\n]*\n[\s\S]*?^[ \t]*\1\s*$/gm, "");
16213
+ result = result.replace(/(`+)(?:(?!\1).)+\1/g, "");
16214
+ result = result.replace(/<pre\b[^>]*>[\s\S]*?<\/pre>/gi, "");
16215
+ result = result.replace(/<code\b[^>]*>[\s\S]*?<\/code>/gi, "");
16216
+ return result;
16217
+ }
16218
+ function scanMarkdownAssets(markdown) {
16219
+ const found = /* @__PURE__ */ new Set();
16220
+ const stripped = stripCodeContent(markdown);
16221
+ const mdImageRe = /!\[[^\]]*\]\(([^)"'\s]+)(?:\s+["'][^"']*["'])?\s*\)/g;
16222
+ let match;
16223
+ while ((match = mdImageRe.exec(stripped)) !== null) {
16224
+ const src = match[1].trim();
16225
+ if (isLocalPath(src)) {
16226
+ found.add(src);
16227
+ }
16228
+ }
16229
+ const htmlSrcRe = /<(?:img|source|video)[^>]+\bsrc=["']([^"']+)["'][^>]*>/gi;
16230
+ while ((match = htmlSrcRe.exec(stripped)) !== null) {
16231
+ const src = match[1].trim();
16232
+ if (isLocalPath(src)) {
16233
+ found.add(src);
16234
+ }
16235
+ }
16236
+ return Array.from(found);
16237
+ }
16238
+ function splitByCode(markdown) {
16239
+ const codeRe = /^[ \t]*(`{3,}|~{3,})[^\n]*\n[\s\S]*?^[ \t]*\1\s*$|<pre\b[^>]*>[\s\S]*?<\/pre>|<code\b[^>]*>[\s\S]*?<\/code>|(`+)(?:(?!\2).)+\2/gim;
16240
+ const segments = [];
16241
+ let lastIndex = 0;
16242
+ for (const match of markdown.matchAll(codeRe)) {
16243
+ if (match.index > lastIndex) {
16244
+ segments.push(markdown.slice(lastIndex, match.index));
16245
+ }
16246
+ segments.push(match[0]);
16247
+ lastIndex = match.index + match[0].length;
16248
+ }
16249
+ if (lastIndex < markdown.length) {
16250
+ segments.push(markdown.slice(lastIndex));
16251
+ }
16252
+ return segments;
16253
+ }
16254
+ function isCode(segment) {
16255
+ const trimmed = segment.trimStart();
16256
+ return trimmed.startsWith("`") || trimmed.startsWith("~") || trimmed.startsWith("<pre") || trimmed.startsWith("<code");
16257
+ }
16258
+ function rewriteProseSegment(prose, assetsBaseUrl, pathMap) {
16259
+ let result = prose;
16260
+ result = result.replace(
16261
+ /(!\[[^\]]*\]\()([^)"'\s]+)((?:\s+["'][^"']*["'])?\s*\))/g,
16262
+ (full, pre, src, post) => {
16263
+ const trimmed = src.trim();
16264
+ if (!isLocalPath(trimmed)) return full;
16265
+ if (pathMap) {
16266
+ const mapped = pathMap.get(trimmed);
16267
+ if (mapped === void 0) return full;
16268
+ return `${pre}${assetsBaseUrl}/${mapped}${post}`;
16269
+ }
16270
+ return `${pre}${assetsBaseUrl}/${trimmed}${post}`;
16271
+ }
16272
+ );
16273
+ result = result.replace(
16274
+ /(<(?:img|source|video)[^>]+\bsrc=["'])([^"']+)(["'][^>]*>)/gi,
16275
+ (full, pre, src, post) => {
16276
+ const trimmed = src.trim();
16277
+ if (!isLocalPath(trimmed)) return full;
16278
+ if (pathMap) {
16279
+ const mapped = pathMap.get(trimmed);
16280
+ if (mapped === void 0) return full;
16281
+ return `${pre}${assetsBaseUrl}/${mapped}${post}`;
16282
+ }
16283
+ return `${pre}${assetsBaseUrl}/${trimmed}${post}`;
16284
+ }
16285
+ );
16286
+ return result;
16287
+ }
16288
+ function rewriteAssetPaths(markdown, assetsBaseUrl, pathMap) {
16289
+ return splitByCode(markdown).map((seg) => isCode(seg) ? seg : rewriteProseSegment(seg, assetsBaseUrl, pathMap)).join("");
16290
+ }
16291
+ function copyMarkdownAssets(options) {
16292
+ const {
16293
+ markdown,
16294
+ markdownDir,
16295
+ assetsDir,
16296
+ assetsBaseUrl,
16297
+ allowMissing = false
16298
+ } = options;
16299
+ const refs = scanMarkdownAssets(markdown);
16300
+ const pathMap = /* @__PURE__ */ new Map();
16301
+ const missing = [];
16302
+ for (const ref of refs) {
16303
+ const absPath = path4.resolve(markdownDir, ref);
16304
+ if (!fs4.existsSync(absPath)) {
16305
+ if (!allowMissing) {
16306
+ throw new Error(`Asset not found: ${absPath}`);
16307
+ }
16308
+ missing.push(ref);
16309
+ continue;
16310
+ }
16311
+ const relativeCopied = copyAsset(absPath, assetsDir);
16312
+ const fileName = relativeCopied.replace(/^assets\//, "");
16313
+ pathMap.set(ref, fileName);
16314
+ }
16315
+ const rewritten = rewriteAssetPaths(markdown, assetsBaseUrl, pathMap);
16316
+ return {
16317
+ markdown: rewritten,
16318
+ copiedCount: pathMap.size,
16319
+ missingCount: missing.length,
16320
+ missing
16321
+ };
16322
+ }
16323
+
16153
16324
  // src/converters/adapters/jest.ts
16154
16325
  function mapJestStatus(status) {
16155
16326
  switch (status) {
@@ -16917,27 +17088,27 @@ function pickleStepArgumentToDocs(ps) {
16917
17088
  }
16918
17089
 
16919
17090
  // src/utils/git-info.ts
16920
- import * as fs4 from "fs";
16921
- import * as path4 from "path";
17091
+ import * as fs5 from "fs";
17092
+ import * as path5 from "path";
16922
17093
  function readGitSha(cwd = process.cwd()) {
16923
17094
  const envSha = process.env.GITHUB_SHA || process.env.GIT_COMMIT || process.env.CI_COMMIT_SHA;
16924
17095
  if (envSha) return envSha;
16925
17096
  const gitDir = findGitDir(cwd);
16926
17097
  if (!gitDir) return void 0;
16927
17098
  try {
16928
- const headPath = path4.join(gitDir, "HEAD");
16929
- const head = fs4.readFileSync(headPath, "utf8").trim();
17099
+ const headPath = path5.join(gitDir, "HEAD");
17100
+ const head = fs5.readFileSync(headPath, "utf8").trim();
16930
17101
  if (!head.startsWith("ref:")) {
16931
17102
  return head;
16932
17103
  }
16933
17104
  const refPath = head.replace("ref:", "").trim();
16934
- const refFile = path4.join(gitDir, refPath);
16935
- if (fs4.existsSync(refFile)) {
16936
- return fs4.readFileSync(refFile, "utf8").trim();
17105
+ const refFile = path5.join(gitDir, refPath);
17106
+ if (fs5.existsSync(refFile)) {
17107
+ return fs5.readFileSync(refFile, "utf8").trim();
16937
17108
  }
16938
- const packedRefs = path4.join(gitDir, "packed-refs");
16939
- if (fs4.existsSync(packedRefs)) {
16940
- const content = fs4.readFileSync(packedRefs, "utf8");
17109
+ const packedRefs = path5.join(gitDir, "packed-refs");
17110
+ if (fs5.existsSync(packedRefs)) {
17111
+ const content = fs5.readFileSync(packedRefs, "utf8");
16941
17112
  for (const line of content.split("\n")) {
16942
17113
  if (!line || line.startsWith("#") || line.startsWith("^")) continue;
16943
17114
  const [sha, ref] = line.split(" ");
@@ -16952,19 +17123,19 @@ function readGitSha(cwd = process.cwd()) {
16952
17123
  function findGitDir(start) {
16953
17124
  let current = start;
16954
17125
  while (true) {
16955
- const candidate = path4.join(current, ".git");
16956
- if (fs4.existsSync(candidate)) {
16957
- const stat = fs4.statSync(candidate);
17126
+ const candidate = path5.join(current, ".git");
17127
+ if (fs5.existsSync(candidate)) {
17128
+ const stat = fs5.statSync(candidate);
16958
17129
  if (stat.isFile()) {
16959
- const content = fs4.readFileSync(candidate, "utf8").trim();
17130
+ const content = fs5.readFileSync(candidate, "utf8").trim();
16960
17131
  const match = content.match(/^gitdir: (.+)$/);
16961
17132
  if (match) {
16962
- return path4.resolve(current, match[1]);
17133
+ return path5.resolve(current, match[1]);
16963
17134
  }
16964
17135
  }
16965
17136
  return candidate;
16966
17137
  }
16967
- const parent = path4.dirname(current);
17138
+ const parent = path5.dirname(current);
16968
17139
  if (parent === current) return void 0;
16969
17140
  current = parent;
16970
17141
  }
@@ -16975,8 +17146,8 @@ function readBranchName(cwd = process.cwd()) {
16975
17146
  const gitDir = findGitDir(cwd);
16976
17147
  if (!gitDir) return void 0;
16977
17148
  try {
16978
- const headPath = path4.join(gitDir, "HEAD");
16979
- const head = fs4.readFileSync(headPath, "utf8").trim();
17149
+ const headPath = path5.join(gitDir, "HEAD");
17150
+ const head = fs5.readFileSync(headPath, "utf8").trim();
16980
17151
  if (head.startsWith("ref:")) {
16981
17152
  const refPath = head.replace("ref:", "").trim();
16982
17153
  const match = refPath.match(/^refs\/heads\/(.+)$/);
@@ -17013,8 +17184,8 @@ function nanosecondsToMs(ns) {
17013
17184
  }
17014
17185
 
17015
17186
  // src/utils/metadata.ts
17016
- import * as fs5 from "fs";
17017
- import * as path5 from "path";
17187
+ import * as fs6 from "fs";
17188
+ import * as path6 from "path";
17018
17189
  var versionCache = /* @__PURE__ */ new Map();
17019
17190
  function readPackageVersion(root) {
17020
17191
  if (versionCache.has(root)) {
@@ -17025,18 +17196,18 @@ function readPackageVersion(root) {
17025
17196
  return version;
17026
17197
  }
17027
17198
  function findPackageVersion(startDir) {
17028
- let current = path5.resolve(startDir);
17199
+ let current = path6.resolve(startDir);
17029
17200
  while (true) {
17030
- const pkgPath = path5.join(current, "package.json");
17201
+ const pkgPath = path6.join(current, "package.json");
17031
17202
  try {
17032
- if (fs5.existsSync(pkgPath)) {
17033
- const raw = fs5.readFileSync(pkgPath, "utf8");
17203
+ if (fs6.existsSync(pkgPath)) {
17204
+ const raw = fs6.readFileSync(pkgPath, "utf8");
17034
17205
  const parsed = JSON.parse(raw);
17035
17206
  return parsed.version;
17036
17207
  }
17037
17208
  } catch {
17038
17209
  }
17039
- const parent = path5.dirname(current);
17210
+ const parent = path6.dirname(current);
17040
17211
  if (parent === current) {
17041
17212
  return void 0;
17042
17213
  }
@@ -17920,6 +18091,37 @@ function listScenarios(args, _deps) {
17920
18091
  }));
17921
18092
  return JSON.stringify(items, null, 2);
17922
18093
  }
18094
+ if (format === "csv") {
18095
+ const header = "id,scenario,status,sourceFile,sourceLine,tags";
18096
+ const rows = testCases.map((tc) => {
18097
+ const fields = [
18098
+ tc.id,
18099
+ tc.story.scenario,
18100
+ tc.status,
18101
+ tc.sourceFile,
18102
+ String(tc.sourceLine),
18103
+ tc.tags.join(" ")
18104
+ ];
18105
+ return fields.map((f) => {
18106
+ if (f.includes(",") || f.includes('"') || f.includes("\n")) {
18107
+ return `"${f.replace(/"/g, '""')}"`;
18108
+ }
18109
+ return f;
18110
+ }).join(",");
18111
+ });
18112
+ return [header, ...rows].join("\n");
18113
+ }
18114
+ if (format === "markdown-table") {
18115
+ const header = "| Status | Scenario | Location | Tags |";
18116
+ const divider = "|--------|----------|----------|------|";
18117
+ const rows = testCases.map((tc) => {
18118
+ const icon = STATUS_ICONS[tc.status] ?? "?";
18119
+ const location = `${tc.sourceFile}:${tc.sourceLine}`;
18120
+ const tags = tc.tags.map((t) => `@${t}`).join(" ");
18121
+ return `| ${icon} | ${tc.story.scenario} | ${location} | ${tags} |`;
18122
+ });
18123
+ return [header, divider, ...rows].join("\n");
18124
+ }
17923
18125
  if (testCases.length === 0) {
17924
18126
  return "No scenarios found.";
17925
18127
  }
@@ -17961,6 +18163,7 @@ function listScenarios(args, _deps) {
17961
18163
 
17962
18164
  // src/index.ts
17963
18165
  var FORMAT_EXTENSIONS = {
18166
+ astro: ".md",
17964
18167
  markdown: ".md",
17965
18168
  html: ".html",
17966
18169
  "cucumber-html": ".cucumber.html",
@@ -17993,11 +18196,11 @@ function computeOutputPath(sourceFile, format, mode, colocatedStyle, baseOutputD
17993
18196
  const ext = FORMAT_EXTENSIONS[format];
17994
18197
  const effectiveName = outputName + (outputNameSuffix ?? "");
17995
18198
  if (mode === "aggregated") {
17996
- return toPosix(path6.join(baseOutputDir, `${effectiveName}${ext}`));
18199
+ return toPosix(path7.join(baseOutputDir, `${effectiveName}${ext}`));
17997
18200
  }
17998
18201
  const normalizedSource = toPosix(sourceFile);
17999
- const dirOfSource = path6.posix.dirname(normalizedSource);
18000
- let baseName = path6.posix.basename(normalizedSource);
18202
+ const dirOfSource = path7.posix.dirname(normalizedSource);
18203
+ let baseName = path7.posix.basename(normalizedSource);
18001
18204
  for (const testExt of TEST_EXTENSIONS) {
18002
18205
  if (baseName.endsWith(testExt)) {
18003
18206
  baseName = baseName.slice(0, -testExt.length);
@@ -18006,9 +18209,9 @@ function computeOutputPath(sourceFile, format, mode, colocatedStyle, baseOutputD
18006
18209
  }
18007
18210
  const fileName = `${baseName}.${effectiveName}${ext}`;
18008
18211
  if (colocatedStyle === "adjacent") {
18009
- return toPosix(path6.posix.join(dirOfSource, fileName));
18212
+ return toPosix(path7.posix.join(dirOfSource, fileName));
18010
18213
  }
18011
- return toPosix(path6.posix.join(baseOutputDir, dirOfSource, fileName));
18214
+ return toPosix(path7.posix.join(baseOutputDir, dirOfSource, fileName));
18012
18215
  }
18013
18216
  function groupTestCasesByOutput(testCases, format, options, logger, outputNameSuffix) {
18014
18217
  const groups = /* @__PURE__ */ new Map();
@@ -18134,6 +18337,24 @@ var ReportGenerator = class {
18134
18337
  includeSourceLinks: options.markdown?.includeSourceLinks ?? true,
18135
18338
  customRenderers: options.markdown?.customRenderers
18136
18339
  },
18340
+ astro: {
18341
+ assetsDir: options.astro?.assetsDir ?? "public/stories/assets",
18342
+ assetsBaseUrl: options.astro?.assetsBaseUrl ?? "/stories/assets",
18343
+ markdown: {
18344
+ title: options.astro?.markdown?.title ?? "User Stories",
18345
+ includeStatusIcons: options.astro?.markdown?.includeStatusIcons ?? true,
18346
+ includeErrors: options.astro?.markdown?.includeErrors ?? true,
18347
+ scenarioHeadingLevel: options.astro?.markdown?.scenarioHeadingLevel ?? 3,
18348
+ groupBy: options.astro?.markdown?.groupBy ?? "file",
18349
+ sortScenarios: options.astro?.markdown?.sortScenarios ?? "source",
18350
+ suiteSeparator: options.astro?.markdown?.suiteSeparator ?? " - ",
18351
+ includeSourceLinks: options.astro?.markdown?.includeSourceLinks ?? true,
18352
+ permalinkBaseUrl: options.astro?.markdown?.permalinkBaseUrl,
18353
+ ticketUrlTemplate: options.astro?.markdown?.ticketUrlTemplate,
18354
+ traceUrlTemplate: options.astro?.markdown?.traceUrlTemplate,
18355
+ customRenderers: options.astro?.markdown?.customRenderers
18356
+ }
18357
+ },
18137
18358
  assetMode: options.assetMode ?? "none",
18138
18359
  allowMissingAssets: options.allowMissingAssets ?? false
18139
18360
  };
@@ -18171,6 +18392,24 @@ var ReportGenerator = class {
18171
18392
  });
18172
18393
  }
18173
18394
  }
18395
+ const astroPaths = results.get("astro");
18396
+ if (astroPaths) {
18397
+ for (const mdPath of astroPaths) {
18398
+ const content = await fsPromises.readFile(mdPath, "utf8");
18399
+ const mdDir = path7.dirname(mdPath);
18400
+ const assetsDir = path7.resolve(this.options.astro.assetsDir);
18401
+ const result = copyMarkdownAssets({
18402
+ markdown: content,
18403
+ markdownDir: mdDir,
18404
+ assetsDir,
18405
+ assetsBaseUrl: this.options.astro.assetsBaseUrl,
18406
+ allowMissing: this.options.allowMissingAssets
18407
+ });
18408
+ if (result.copiedCount > 0 || result.missingCount > 0) {
18409
+ await this.deps.writeFile(mdPath, result.markdown);
18410
+ }
18411
+ }
18412
+ }
18174
18413
  }
18175
18414
  return results;
18176
18415
  }
@@ -18189,9 +18428,9 @@ var ReportGenerator = class {
18189
18428
  if (groups.size === 0 && this.options.output.mode === "aggregated") {
18190
18429
  const ext = FORMAT_EXTENSIONS[format];
18191
18430
  const effectiveName = this.options.outputName + (outputNameSuffix ?? "");
18192
- const outputPath = toPosix(path6.join(this.options.outputDir, `${effectiveName}${ext}`));
18431
+ const outputPath = toPosix(path7.join(this.options.outputDir, `${effectiveName}${ext}`));
18193
18432
  const content = await this.formatContent(run, format);
18194
- const dir = path6.dirname(outputPath);
18433
+ const dir = path7.dirname(outputPath);
18195
18434
  await fsPromises.mkdir(dir, { recursive: true });
18196
18435
  await this.deps.writeFile(outputPath, content);
18197
18436
  return [outputPath];
@@ -18203,7 +18442,7 @@ var ReportGenerator = class {
18203
18442
  testCases
18204
18443
  };
18205
18444
  const content = await this.formatContent(groupRun, format);
18206
- const dir = path6.dirname(outputPath);
18445
+ const dir = path7.dirname(outputPath);
18207
18446
  await fsPromises.mkdir(dir, { recursive: true });
18208
18447
  await this.deps.writeFile(outputPath, content);
18209
18448
  writtenPaths.push(outputPath);
@@ -18266,6 +18505,13 @@ var ReportGenerator = class {
18266
18505
  });
18267
18506
  return formatter.formatToString(run);
18268
18507
  }
18508
+ case "astro": {
18509
+ const formatter = new AstroFormatter({
18510
+ assetsBaseUrl: this.options.astro.assetsBaseUrl,
18511
+ markdown: this.options.astro.markdown
18512
+ });
18513
+ return formatter.format(run);
18514
+ }
18269
18515
  case "markdown": {
18270
18516
  const formatter = new MarkdownFormatter({
18271
18517
  title: this.options.markdown.title,
@@ -18303,7 +18549,7 @@ async function generateRunComparison(args) {
18303
18549
  await fsPromises.mkdir(outputDir, { recursive: true });
18304
18550
  for (const format of args.formats) {
18305
18551
  const ext = format === "html" ? ".html" : ".md";
18306
- const outputPath = toPosix(path6.join(outputDir, `${outputName}${ext}`));
18552
+ const outputPath = toPosix(path7.join(outputDir, `${outputName}${ext}`));
18307
18553
  const content = format === "html" ? new RunDiffHtmlFormatter({ title: args.title }).format(diff) : new RunDiffMarkdownFormatter({ title: args.title }).format(diff);
18308
18554
  await fsPromises.writeFile(outputPath, content, "utf8");
18309
18555
  files.push(outputPath);
@@ -18323,6 +18569,7 @@ function normalizePlaywrightResults(testResults, adapterOptions, canonicalizeOpt
18323
18569
  return canonicalizeRun(raw, canonicalizeOptions);
18324
18570
  }
18325
18571
  export {
18572
+ AstroFormatter,
18326
18573
  CucumberHtmlFormatter,
18327
18574
  CucumberJsonFormatter,
18328
18575
  CucumberMessagesFormatter,
@@ -18346,6 +18593,7 @@ export {
18346
18593
  canonicalizeRun,
18347
18594
  clearVersionCache,
18348
18595
  computeTestMetrics,
18596
+ copyMarkdownAssets,
18349
18597
  createPrCommentSummary,
18350
18598
  createReportGenerator,
18351
18599
  deriveStepResults,
@@ -18378,6 +18626,7 @@ export {
18378
18626
  resolveAttachments,
18379
18627
  resolveTheme,
18380
18628
  resolveTraceUrl,
18629
+ rewriteAssetPaths,
18381
18630
  saveHistory,
18382
18631
  sendNotifications,
18383
18632
  sendSlackNotification,