executable-stories-formatters 0.16.0 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +473 -247
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +315 -103
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +100 -5
- package/dist/index.d.ts +100 -5
- package/dist/index.js +308 -102
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -59,6 +59,7 @@ __export(src_exports, {
|
|
|
59
59
|
adaptJestRun: () => adaptJestRun,
|
|
60
60
|
adaptPlaywrightRun: () => adaptPlaywrightRun,
|
|
61
61
|
adaptVitestRun: () => adaptVitestRun,
|
|
62
|
+
advanceState: () => advanceState,
|
|
62
63
|
assertValidRun: () => assertValidRun,
|
|
63
64
|
buildCheck: () => buildCheck,
|
|
64
65
|
buildGoal: () => buildGoal,
|
|
@@ -71,6 +72,7 @@ __export(src_exports, {
|
|
|
71
72
|
canonicalizeRun: () => canonicalizeRun,
|
|
72
73
|
classifyStatusChange: () => classifyStatusChange,
|
|
73
74
|
clearVersionCache: () => clearVersionCache,
|
|
75
|
+
computeDeltas: () => computeDeltas,
|
|
74
76
|
computeTestMetrics: () => computeTestMetrics,
|
|
75
77
|
copyMarkdownAssets: () => copyMarkdownAssets,
|
|
76
78
|
createPrCommentSummary: () => createPrCommentSummary,
|
|
@@ -93,6 +95,7 @@ __export(src_exports, {
|
|
|
93
95
|
getEnvironmentDrift: () => getEnvironmentDrift,
|
|
94
96
|
gradeEvidence: () => gradeEvidence,
|
|
95
97
|
hasSufficientHistory: () => hasSufficientHistory,
|
|
98
|
+
injectLiveBits: () => injectLiveBits,
|
|
96
99
|
isReviewableSource: () => isReviewableSource,
|
|
97
100
|
isTestFile: () => isTestFile,
|
|
98
101
|
joinNameAndExt: () => joinNameAndExt,
|
|
@@ -114,7 +117,9 @@ __export(src_exports, {
|
|
|
114
117
|
readPackageVersion: () => readPackageVersion,
|
|
115
118
|
recordDeployment: () => recordDeployment,
|
|
116
119
|
regenerateArtifacts: () => regenerateArtifacts,
|
|
120
|
+
regenerateRun: () => regenerateRun,
|
|
117
121
|
renderCheck: () => renderCheck,
|
|
122
|
+
renderDeltaStrip: () => renderDeltaStrip,
|
|
118
123
|
renderGoal: () => renderGoal,
|
|
119
124
|
renderTriage: () => renderTriage,
|
|
120
125
|
resolveAttachment: () => resolveAttachment,
|
|
@@ -130,6 +135,7 @@ __export(src_exports, {
|
|
|
130
135
|
sendWebhookNotification: () => sendWebhookNotification,
|
|
131
136
|
signBody: () => signBody,
|
|
132
137
|
slugify: () => slugify,
|
|
138
|
+
startServe: () => startServe,
|
|
133
139
|
startWatch: () => startWatch,
|
|
134
140
|
stripAnsi: () => stripAnsi,
|
|
135
141
|
toBehaviorManifest: () => toBehaviorManifest,
|
|
@@ -144,8 +150,8 @@ __export(src_exports, {
|
|
|
144
150
|
validateCanonicalRun: () => validateCanonicalRun
|
|
145
151
|
});
|
|
146
152
|
module.exports = __toCommonJS(src_exports);
|
|
147
|
-
var
|
|
148
|
-
var
|
|
153
|
+
var fs11 = require("fs");
|
|
154
|
+
var path12 = __toESM(require("path"), 1);
|
|
149
155
|
var fsPromises = __toESM(require("fs/promises"), 1);
|
|
150
156
|
|
|
151
157
|
// src/converters/acl/status.ts
|
|
@@ -196,7 +202,7 @@ function tokenize(text2) {
|
|
|
196
202
|
}
|
|
197
203
|
function behaviourFingerprint(input) {
|
|
198
204
|
const steps = input.steps.map((step) => `${step.keyword.toLowerCase()}:${normalizeText(step.text)}`).join("\n");
|
|
199
|
-
const covers = [...input.covers ?? []].map((
|
|
205
|
+
const covers = [...input.covers ?? []].map((path13) => path13.trim()).filter(Boolean).sort().join(",");
|
|
200
206
|
if (steps.length === 0 && covers.length === 0) return "";
|
|
201
207
|
return (0, import_node_crypto.createHash)("sha1").update(`${steps}\0${covers}`).digest("hex").slice(0, 16);
|
|
202
208
|
}
|
|
@@ -14419,12 +14425,12 @@ function hasSufficientHistory(entries, min) {
|
|
|
14419
14425
|
}
|
|
14420
14426
|
|
|
14421
14427
|
// src/formatters/html/renderers/scenario.ts
|
|
14422
|
-
function renderTicket(ticket, template,
|
|
14428
|
+
function renderTicket(ticket, template, escapeHtml5) {
|
|
14423
14429
|
const url = ticket.url ?? (template ? template.replace("{ticket}", ticket.id) : void 0);
|
|
14424
14430
|
if (url) {
|
|
14425
|
-
return `<a class="tag ticket-tag" href="${
|
|
14431
|
+
return `<a class="tag ticket-tag" href="${escapeHtml5(url)}" target="_blank" rel="noopener noreferrer">${escapeHtml5(ticket.id)}</a>`;
|
|
14426
14432
|
}
|
|
14427
|
-
return `<span class="tag ticket-tag">${
|
|
14433
|
+
return `<span class="tag ticket-tag">${escapeHtml5(ticket.id)}</span>`;
|
|
14428
14434
|
}
|
|
14429
14435
|
function renderScenario(args, deps) {
|
|
14430
14436
|
const { tc } = args;
|
|
@@ -14624,7 +14630,7 @@ function flattenTree(roots) {
|
|
|
14624
14630
|
}
|
|
14625
14631
|
return result;
|
|
14626
14632
|
}
|
|
14627
|
-
function buildTooltip(span,
|
|
14633
|
+
function buildTooltip(span, escapeHtml5) {
|
|
14628
14634
|
const parts = [];
|
|
14629
14635
|
parts.push(`${span.name} (${formatDuration(span.durationMs)})`);
|
|
14630
14636
|
if (span.statusMessage) {
|
|
@@ -14642,7 +14648,7 @@ function buildTooltip(span, escapeHtml4) {
|
|
|
14642
14648
|
if (text2.length > TOOLTIP_MAX_LENGTH) {
|
|
14643
14649
|
text2 = text2.slice(0, TOOLTIP_MAX_LENGTH - 3) + "...";
|
|
14644
14650
|
}
|
|
14645
|
-
return
|
|
14651
|
+
return escapeHtml5(text2);
|
|
14646
14652
|
}
|
|
14647
14653
|
function renderTraceView(args, deps) {
|
|
14648
14654
|
if (!args.spans || args.spans.length === 0) return "";
|
|
@@ -15937,14 +15943,14 @@ var TraceabilityMatrixFormatter = class {
|
|
|
15937
15943
|
lines.push("");
|
|
15938
15944
|
lines.push(`Status: ${renderRequirementStatus(req.status)}`);
|
|
15939
15945
|
if (req.covers.length > 0) {
|
|
15940
|
-
lines.push(`Covers: ${req.covers.map((
|
|
15946
|
+
lines.push(`Covers: ${req.covers.map((path13) => `\`${path13}\``).join(", ")}`);
|
|
15941
15947
|
}
|
|
15942
15948
|
lines.push("");
|
|
15943
15949
|
lines.push("| Status | Scenario | Source | Covers |");
|
|
15944
15950
|
lines.push("| --- | --- | --- | --- |");
|
|
15945
15951
|
for (const scenario of req.scenarios) {
|
|
15946
15952
|
const source = `${scenario.sourceFile}:${scenario.sourceLine}`;
|
|
15947
|
-
const covers = scenario.covers.length > 0 ? scenario.covers.map((
|
|
15953
|
+
const covers = scenario.covers.length > 0 ? scenario.covers.map((path13) => `\`${path13}\``).join(", ") : "";
|
|
15948
15954
|
lines.push(`| ${scenario.status} | ${escapePipe2(scenario.title)} | \`${source}\` | ${covers} |`);
|
|
15949
15955
|
}
|
|
15950
15956
|
lines.push("");
|
|
@@ -16046,8 +16052,8 @@ function extractFeatureName(testCases, uri) {
|
|
|
16046
16052
|
return tc.titlePath[0];
|
|
16047
16053
|
}
|
|
16048
16054
|
}
|
|
16049
|
-
const
|
|
16050
|
-
return
|
|
16055
|
+
const basename4 = uri.replace(/^.*[\\/]/, "").replace(/\.[^.]+$/, "");
|
|
16056
|
+
return basename4.replace(/[-_]+/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
16051
16057
|
}
|
|
16052
16058
|
function synthesizeFeature(uri, testCases) {
|
|
16053
16059
|
const featureName = extractFeatureName(testCases, uri);
|
|
@@ -16659,8 +16665,8 @@ function extractDocAttachments(step) {
|
|
|
16659
16665
|
}
|
|
16660
16666
|
return attachments;
|
|
16661
16667
|
}
|
|
16662
|
-
function guessMediaType(
|
|
16663
|
-
const lower =
|
|
16668
|
+
function guessMediaType(path13) {
|
|
16669
|
+
const lower = path13.toLowerCase();
|
|
16664
16670
|
if (lower.endsWith(".png")) return "image/png";
|
|
16665
16671
|
if (lower.endsWith(".jpg") || lower.endsWith(".jpeg")) return "image/jpeg";
|
|
16666
16672
|
if (lower.endsWith(".gif")) return "image/gif";
|
|
@@ -16801,11 +16807,11 @@ var CucumberHtmlFormatter = class {
|
|
|
16801
16807
|
for (const envelope of envelopes) {
|
|
16802
16808
|
const accepted = htmlStream.write(envelope);
|
|
16803
16809
|
if (!accepted) {
|
|
16804
|
-
await new Promise((
|
|
16810
|
+
await new Promise((resolve10) => htmlStream.once("drain", resolve10));
|
|
16805
16811
|
}
|
|
16806
16812
|
}
|
|
16807
|
-
await new Promise((
|
|
16808
|
-
collector.on("finish",
|
|
16813
|
+
await new Promise((resolve10, reject) => {
|
|
16814
|
+
collector.on("finish", resolve10);
|
|
16809
16815
|
collector.on("error", reject);
|
|
16810
16816
|
htmlStream.end();
|
|
16811
16817
|
});
|
|
@@ -18969,14 +18975,14 @@ ${result.errors.join("\n")}`);
|
|
|
18969
18975
|
}
|
|
18970
18976
|
|
|
18971
18977
|
// src/coverage-index.ts
|
|
18972
|
-
function normalizePath(
|
|
18973
|
-
return
|
|
18978
|
+
function normalizePath(path13) {
|
|
18979
|
+
return path13.replace(/^\.\//, "");
|
|
18974
18980
|
}
|
|
18975
18981
|
function scenariosCoveringPaths(index, paths) {
|
|
18976
18982
|
const queries = paths.map(normalizePath);
|
|
18977
18983
|
return index.scenarios.filter(
|
|
18978
18984
|
(scenario) => scenario.covers.some(
|
|
18979
|
-
(glob) => queries.some((
|
|
18985
|
+
(glob) => queries.some((path13) => matchesPattern(normalizePath(glob), path13))
|
|
18980
18986
|
)
|
|
18981
18987
|
);
|
|
18982
18988
|
}
|
|
@@ -19052,7 +19058,7 @@ function toRun(data, inputType, synthesize) {
|
|
|
19052
19058
|
if (synthesize) raw = synthesizeStories(raw);
|
|
19053
19059
|
return canonicalizeRun(raw);
|
|
19054
19060
|
}
|
|
19055
|
-
async function
|
|
19061
|
+
async function regenerateRun(options, deps = {}) {
|
|
19056
19062
|
const read = deps.readFile ?? ((filePath) => fs6.readFileSync(filePath, "utf8"));
|
|
19057
19063
|
const data = JSON.parse(read(path7.resolve(options.input)));
|
|
19058
19064
|
const run = toRun(data, options.inputType ?? "raw", options.synthesize !== false);
|
|
@@ -19062,7 +19068,10 @@ async function regenerateArtifacts(options, deps = {}) {
|
|
|
19062
19068
|
outputName: options.outputName
|
|
19063
19069
|
});
|
|
19064
19070
|
const result = await generator.generate(run);
|
|
19065
|
-
return [...result.values()].flat();
|
|
19071
|
+
return { files: [...result.values()].flat(), run };
|
|
19072
|
+
}
|
|
19073
|
+
async function regenerateArtifacts(options, deps = {}) {
|
|
19074
|
+
return (await regenerateRun(options, deps)).files;
|
|
19066
19075
|
}
|
|
19067
19076
|
function startWatch(options, deps = {}) {
|
|
19068
19077
|
const log = deps.log ?? ((message) => console.log(message));
|
|
@@ -19105,6 +19114,203 @@ function startWatch(options, deps = {}) {
|
|
|
19105
19114
|
};
|
|
19106
19115
|
}
|
|
19107
19116
|
|
|
19117
|
+
// src/serve.ts
|
|
19118
|
+
var fs7 = __toESM(require("fs"), 1);
|
|
19119
|
+
var http = __toESM(require("http"), 1);
|
|
19120
|
+
var path8 = __toESM(require("path"), 1);
|
|
19121
|
+
function advanceState(prev, run) {
|
|
19122
|
+
if (prev.sessionBaseline === null) {
|
|
19123
|
+
return { sessionBaseline: run, previous: null, current: run, runCount: 1 };
|
|
19124
|
+
}
|
|
19125
|
+
return {
|
|
19126
|
+
sessionBaseline: prev.sessionBaseline,
|
|
19127
|
+
previous: prev.current,
|
|
19128
|
+
current: run,
|
|
19129
|
+
runCount: prev.runCount + 1
|
|
19130
|
+
};
|
|
19131
|
+
}
|
|
19132
|
+
function computeDeltas(state) {
|
|
19133
|
+
if (state.current === null || state.sessionBaseline === null || state.runCount <= 1) {
|
|
19134
|
+
return { session: null, iteration: null };
|
|
19135
|
+
}
|
|
19136
|
+
return {
|
|
19137
|
+
session: diffRuns(state.sessionBaseline, state.current),
|
|
19138
|
+
iteration: state.previous ? diffRuns(state.previous, state.current) : null
|
|
19139
|
+
};
|
|
19140
|
+
}
|
|
19141
|
+
function pluralize(n, word) {
|
|
19142
|
+
return `${n} ${word}${n === 1 ? "" : "s"}`;
|
|
19143
|
+
}
|
|
19144
|
+
function summarizeDiff(diff) {
|
|
19145
|
+
const s = diff.summary;
|
|
19146
|
+
const parts = [];
|
|
19147
|
+
if (s.fixed > 0) parts.push(`+${pluralize(s.fixed, "passing")}`);
|
|
19148
|
+
if (s.regressed > 0) parts.push(`${pluralize(s.regressed, "regressed")}`);
|
|
19149
|
+
if (s.added > 0) parts.push(`${pluralize(s.added, "new behaviour")}`);
|
|
19150
|
+
if (s.removed > 0) parts.push(`${pluralize(s.removed, "removed")}`);
|
|
19151
|
+
const moved = s.renamed + s.moved;
|
|
19152
|
+
if (moved > 0) parts.push(`${pluralize(moved, "renamed")}`);
|
|
19153
|
+
if (s.changed > 0) parts.push(`${pluralize(s.changed, "changed")}`);
|
|
19154
|
+
return parts.length > 0 ? parts.join(", ") : null;
|
|
19155
|
+
}
|
|
19156
|
+
function escapeHtml3(text2) {
|
|
19157
|
+
return text2.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
19158
|
+
}
|
|
19159
|
+
function renderDeltaStrip(state) {
|
|
19160
|
+
if (state.current === null) return "";
|
|
19161
|
+
const { session, iteration } = computeDeltas(state);
|
|
19162
|
+
if (session === null) {
|
|
19163
|
+
const label = `Run #${state.runCount} captured \u2014 baseline pinned. Watching for changes\u2026`;
|
|
19164
|
+
return `<div data-es-live="strip"><strong>Live</strong> \xB7 ${escapeHtml3(label)}</div>`;
|
|
19165
|
+
}
|
|
19166
|
+
const sessionLine = summarizeDiff(session) ?? "no change yet";
|
|
19167
|
+
let detail = "";
|
|
19168
|
+
if (iteration) {
|
|
19169
|
+
const iterationLine = summarizeDiff(iteration);
|
|
19170
|
+
if (iterationLine) detail = ` \xB7 <span data-es-live="iteration">this iteration: ${escapeHtml3(iterationLine)}</span>`;
|
|
19171
|
+
}
|
|
19172
|
+
return [
|
|
19173
|
+
`<div data-es-live="strip">`,
|
|
19174
|
+
`<strong>Live</strong> \xB7 run #${state.runCount} \xB7 `,
|
|
19175
|
+
`<span data-es-live="session">since you started: ${escapeHtml3(sessionLine)}</span>`,
|
|
19176
|
+
detail,
|
|
19177
|
+
`</div>`
|
|
19178
|
+
].join("");
|
|
19179
|
+
}
|
|
19180
|
+
var RELOAD_CLIENT = `<script data-es-live="client">
|
|
19181
|
+
(function () {
|
|
19182
|
+
try {
|
|
19183
|
+
var es = new EventSource("/__es_reload");
|
|
19184
|
+
es.onmessage = function (e) { if (e.data === "reload") location.reload(); };
|
|
19185
|
+
} catch (err) { /* SSE unavailable: stay static */ }
|
|
19186
|
+
})();
|
|
19187
|
+
</script>`;
|
|
19188
|
+
var STRIP_STYLE = `<style data-es-live="style">
|
|
19189
|
+
[data-es-live="strip"]{position:sticky;top:0;z-index:9999;font:14px/1.5 system-ui,sans-serif;
|
|
19190
|
+
padding:8px 16px;background:#0b1021;color:#e6e9f5;border-bottom:1px solid #2a3052}
|
|
19191
|
+
[data-es-live="strip"] strong{color:#7dd3fc}
|
|
19192
|
+
</style>`;
|
|
19193
|
+
function injectLiveBits(html, stripHtml) {
|
|
19194
|
+
let out = html;
|
|
19195
|
+
const bodyOpen = out.match(/<body[^>]*>/i);
|
|
19196
|
+
if (bodyOpen) {
|
|
19197
|
+
const at = bodyOpen.index + bodyOpen[0].length;
|
|
19198
|
+
out = out.slice(0, at) + stripHtml + out.slice(at);
|
|
19199
|
+
} else {
|
|
19200
|
+
out = stripHtml + out;
|
|
19201
|
+
}
|
|
19202
|
+
const tail = STRIP_STYLE + RELOAD_CLIENT;
|
|
19203
|
+
if (/<\/body>/i.test(out)) {
|
|
19204
|
+
out = out.replace(/<\/body>/i, tail + "</body>");
|
|
19205
|
+
} else {
|
|
19206
|
+
out += tail;
|
|
19207
|
+
}
|
|
19208
|
+
return out;
|
|
19209
|
+
}
|
|
19210
|
+
var CONTENT_TYPES = {
|
|
19211
|
+
".html": "text/html; charset=utf-8",
|
|
19212
|
+
".css": "text/css; charset=utf-8",
|
|
19213
|
+
".js": "text/javascript; charset=utf-8",
|
|
19214
|
+
".json": "application/json; charset=utf-8",
|
|
19215
|
+
".svg": "image/svg+xml",
|
|
19216
|
+
".png": "image/png"
|
|
19217
|
+
};
|
|
19218
|
+
function watchInputDir(filePath, listener) {
|
|
19219
|
+
const dir = path8.dirname(filePath);
|
|
19220
|
+
const base = path8.basename(filePath);
|
|
19221
|
+
fs7.mkdirSync(dir, { recursive: true });
|
|
19222
|
+
const watcher = fs7.watch(dir, (_event, changed) => {
|
|
19223
|
+
if (!changed || changed === base) listener();
|
|
19224
|
+
});
|
|
19225
|
+
return { close: () => watcher.close() };
|
|
19226
|
+
}
|
|
19227
|
+
function plainText(html) {
|
|
19228
|
+
return html.replace(/<[^>]+>/g, "").trim();
|
|
19229
|
+
}
|
|
19230
|
+
function startServe(options, deps = {}) {
|
|
19231
|
+
const log = deps.log ?? ((message) => console.log(message));
|
|
19232
|
+
const read = deps.readFile ?? ((filePath) => fs7.readFileSync(filePath, "utf8"));
|
|
19233
|
+
const port = options.port ?? 4321;
|
|
19234
|
+
const host = options.host ?? "127.0.0.1";
|
|
19235
|
+
let state = { sessionBaseline: null, previous: null, current: null, runCount: 0 };
|
|
19236
|
+
let htmlPath = null;
|
|
19237
|
+
let stripHtml = renderDeltaStrip(state);
|
|
19238
|
+
const clients = /* @__PURE__ */ new Set();
|
|
19239
|
+
const pushReload = () => {
|
|
19240
|
+
for (const res of clients) res.write("data: reload\n\n");
|
|
19241
|
+
};
|
|
19242
|
+
const handler = (req, res) => {
|
|
19243
|
+
const url = (req.url ?? "/").split("?")[0];
|
|
19244
|
+
if (url === "/__es_reload") {
|
|
19245
|
+
res.writeHead(200, {
|
|
19246
|
+
"Content-Type": "text/event-stream",
|
|
19247
|
+
"Cache-Control": "no-cache",
|
|
19248
|
+
Connection: "keep-alive"
|
|
19249
|
+
});
|
|
19250
|
+
res.write("retry: 1000\n\n");
|
|
19251
|
+
clients.add(res);
|
|
19252
|
+
req.on("close", () => clients.delete(res));
|
|
19253
|
+
return;
|
|
19254
|
+
}
|
|
19255
|
+
if (url === "/" || url === "/index.html") {
|
|
19256
|
+
const html = htmlPath ? read(htmlPath) : "<!doctype html><html><body><h1>executable-stories</h1></body></html>";
|
|
19257
|
+
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
19258
|
+
res.end(injectLiveBits(html, stripHtml));
|
|
19259
|
+
return;
|
|
19260
|
+
}
|
|
19261
|
+
const safe = path8.normalize(url).replace(/^(\.\.[/\\])+/, "");
|
|
19262
|
+
const filePath = path8.join(path8.resolve(options.outputDir), safe);
|
|
19263
|
+
if (filePath.startsWith(path8.resolve(options.outputDir)) && fs7.existsSync(filePath)) {
|
|
19264
|
+
const ext = path8.extname(filePath).toLowerCase();
|
|
19265
|
+
res.writeHead(200, { "Content-Type": CONTENT_TYPES[ext] ?? "application/octet-stream" });
|
|
19266
|
+
res.end(read(filePath));
|
|
19267
|
+
return;
|
|
19268
|
+
}
|
|
19269
|
+
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
19270
|
+
res.end("Not found");
|
|
19271
|
+
};
|
|
19272
|
+
const server = deps.createServer ? deps.createServer(handler) : http.createServer(handler);
|
|
19273
|
+
const watchOptions = {
|
|
19274
|
+
input: options.input,
|
|
19275
|
+
outputDir: options.outputDir,
|
|
19276
|
+
outputName: options.outputName,
|
|
19277
|
+
formats: options.formats,
|
|
19278
|
+
inputType: options.inputType ?? "raw",
|
|
19279
|
+
synthesize: options.synthesize !== false,
|
|
19280
|
+
debounceMs: options.debounceMs
|
|
19281
|
+
};
|
|
19282
|
+
const watchHandle = startWatch(watchOptions, {
|
|
19283
|
+
readFile: read,
|
|
19284
|
+
watch: deps.watch ?? watchInputDir,
|
|
19285
|
+
log: () => {
|
|
19286
|
+
},
|
|
19287
|
+
// serve emits its own per-run line below
|
|
19288
|
+
regenerate: async (input) => {
|
|
19289
|
+
if (!fs7.existsSync(path8.resolve(input))) return [];
|
|
19290
|
+
const { files, run } = await regenerateRun({ ...watchOptions, input }, { readFile: read });
|
|
19291
|
+
htmlPath = files.find((f) => f.endsWith(".html")) ?? htmlPath;
|
|
19292
|
+
state = advanceState(state, run);
|
|
19293
|
+
stripHtml = renderDeltaStrip(state);
|
|
19294
|
+
log(`Run #${state.runCount}: ${plainText(stripHtml)}`);
|
|
19295
|
+
pushReload();
|
|
19296
|
+
return files;
|
|
19297
|
+
}
|
|
19298
|
+
});
|
|
19299
|
+
server.listen(port, host);
|
|
19300
|
+
const address = server.address();
|
|
19301
|
+
const boundPort = typeof address === "object" && address ? address.port : port;
|
|
19302
|
+
log(`Live docs: http://${host}:${boundPort} (Ctrl+C to stop)`);
|
|
19303
|
+
return {
|
|
19304
|
+
port: boundPort,
|
|
19305
|
+
close: () => {
|
|
19306
|
+
watchHandle.close();
|
|
19307
|
+
for (const res of clients) res.end();
|
|
19308
|
+
clients.clear();
|
|
19309
|
+
server.close();
|
|
19310
|
+
}
|
|
19311
|
+
};
|
|
19312
|
+
}
|
|
19313
|
+
|
|
19108
19314
|
// src/behavior-diff.ts
|
|
19109
19315
|
function classifyStatusChange(baseline, current) {
|
|
19110
19316
|
if (baseline === void 0) return "added";
|
|
@@ -19744,27 +19950,27 @@ function pickleStepArgumentToDocs(ps) {
|
|
|
19744
19950
|
}
|
|
19745
19951
|
|
|
19746
19952
|
// src/utils/git-info.ts
|
|
19747
|
-
var
|
|
19748
|
-
var
|
|
19953
|
+
var fs8 = __toESM(require("fs"), 1);
|
|
19954
|
+
var path9 = __toESM(require("path"), 1);
|
|
19749
19955
|
function readGitSha(cwd = process.cwd()) {
|
|
19750
19956
|
const envSha = process.env.GITHUB_SHA || process.env.GIT_COMMIT || process.env.CI_COMMIT_SHA;
|
|
19751
19957
|
if (envSha) return envSha;
|
|
19752
19958
|
const gitDir = findGitDir(cwd);
|
|
19753
19959
|
if (!gitDir) return void 0;
|
|
19754
19960
|
try {
|
|
19755
|
-
const headPath =
|
|
19756
|
-
const head =
|
|
19961
|
+
const headPath = path9.join(gitDir, "HEAD");
|
|
19962
|
+
const head = fs8.readFileSync(headPath, "utf8").trim();
|
|
19757
19963
|
if (!head.startsWith("ref:")) {
|
|
19758
19964
|
return head;
|
|
19759
19965
|
}
|
|
19760
19966
|
const refPath = head.replace("ref:", "").trim();
|
|
19761
|
-
const refFile =
|
|
19762
|
-
if (
|
|
19763
|
-
return
|
|
19967
|
+
const refFile = path9.join(gitDir, refPath);
|
|
19968
|
+
if (fs8.existsSync(refFile)) {
|
|
19969
|
+
return fs8.readFileSync(refFile, "utf8").trim();
|
|
19764
19970
|
}
|
|
19765
|
-
const packedRefs =
|
|
19766
|
-
if (
|
|
19767
|
-
const content =
|
|
19971
|
+
const packedRefs = path9.join(gitDir, "packed-refs");
|
|
19972
|
+
if (fs8.existsSync(packedRefs)) {
|
|
19973
|
+
const content = fs8.readFileSync(packedRefs, "utf8");
|
|
19768
19974
|
for (const line of content.split("\n")) {
|
|
19769
19975
|
if (!line || line.startsWith("#") || line.startsWith("^")) continue;
|
|
19770
19976
|
const [sha, ref] = line.split(" ");
|
|
@@ -19779,19 +19985,19 @@ function readGitSha(cwd = process.cwd()) {
|
|
|
19779
19985
|
function findGitDir(start) {
|
|
19780
19986
|
let current = start;
|
|
19781
19987
|
while (true) {
|
|
19782
|
-
const candidate =
|
|
19783
|
-
if (
|
|
19784
|
-
const stat =
|
|
19988
|
+
const candidate = path9.join(current, ".git");
|
|
19989
|
+
if (fs8.existsSync(candidate)) {
|
|
19990
|
+
const stat = fs8.statSync(candidate);
|
|
19785
19991
|
if (stat.isFile()) {
|
|
19786
|
-
const content =
|
|
19992
|
+
const content = fs8.readFileSync(candidate, "utf8").trim();
|
|
19787
19993
|
const match = content.match(/^gitdir: (.+)$/);
|
|
19788
19994
|
if (match) {
|
|
19789
|
-
return
|
|
19995
|
+
return path9.resolve(current, match[1]);
|
|
19790
19996
|
}
|
|
19791
19997
|
}
|
|
19792
19998
|
return candidate;
|
|
19793
19999
|
}
|
|
19794
|
-
const parent =
|
|
20000
|
+
const parent = path9.dirname(current);
|
|
19795
20001
|
if (parent === current) return void 0;
|
|
19796
20002
|
current = parent;
|
|
19797
20003
|
}
|
|
@@ -19802,8 +20008,8 @@ function readBranchName(cwd = process.cwd()) {
|
|
|
19802
20008
|
const gitDir = findGitDir(cwd);
|
|
19803
20009
|
if (!gitDir) return void 0;
|
|
19804
20010
|
try {
|
|
19805
|
-
const headPath =
|
|
19806
|
-
const head =
|
|
20011
|
+
const headPath = path9.join(gitDir, "HEAD");
|
|
20012
|
+
const head = fs8.readFileSync(headPath, "utf8").trim();
|
|
19807
20013
|
if (head.startsWith("ref:")) {
|
|
19808
20014
|
const refPath = head.replace("ref:", "").trim();
|
|
19809
20015
|
const match = refPath.match(/^refs\/heads\/(.+)$/);
|
|
@@ -19840,8 +20046,8 @@ function nanosecondsToMs(ns) {
|
|
|
19840
20046
|
}
|
|
19841
20047
|
|
|
19842
20048
|
// src/utils/metadata.ts
|
|
19843
|
-
var
|
|
19844
|
-
var
|
|
20049
|
+
var fs9 = __toESM(require("fs"), 1);
|
|
20050
|
+
var path10 = __toESM(require("path"), 1);
|
|
19845
20051
|
var versionCache = /* @__PURE__ */ new Map();
|
|
19846
20052
|
function readPackageVersion(root) {
|
|
19847
20053
|
if (versionCache.has(root)) {
|
|
@@ -19852,18 +20058,18 @@ function readPackageVersion(root) {
|
|
|
19852
20058
|
return version;
|
|
19853
20059
|
}
|
|
19854
20060
|
function findPackageVersion(startDir) {
|
|
19855
|
-
let current =
|
|
20061
|
+
let current = path10.resolve(startDir);
|
|
19856
20062
|
while (true) {
|
|
19857
|
-
const pkgPath =
|
|
20063
|
+
const pkgPath = path10.join(current, "package.json");
|
|
19858
20064
|
try {
|
|
19859
|
-
if (
|
|
19860
|
-
const raw =
|
|
20065
|
+
if (fs9.existsSync(pkgPath)) {
|
|
20066
|
+
const raw = fs9.readFileSync(pkgPath, "utf8");
|
|
19861
20067
|
const parsed = JSON.parse(raw);
|
|
19862
20068
|
return parsed.version;
|
|
19863
20069
|
}
|
|
19864
20070
|
} catch {
|
|
19865
20071
|
}
|
|
19866
|
-
const parent =
|
|
20072
|
+
const parent = path10.dirname(current);
|
|
19867
20073
|
if (parent === current) {
|
|
19868
20074
|
return void 0;
|
|
19869
20075
|
}
|
|
@@ -21192,18 +21398,18 @@ function deriveChangeType(tags) {
|
|
|
21192
21398
|
}
|
|
21193
21399
|
return "unknown";
|
|
21194
21400
|
}
|
|
21195
|
-
function extensionOf(
|
|
21196
|
-
const base =
|
|
21401
|
+
function extensionOf(path13) {
|
|
21402
|
+
const base = path13.split("/").pop() ?? path13;
|
|
21197
21403
|
const dot = base.lastIndexOf(".");
|
|
21198
21404
|
return dot === -1 ? "" : base.slice(dot + 1).toLowerCase();
|
|
21199
21405
|
}
|
|
21200
|
-
function isTestFile(
|
|
21201
|
-
return TEST_INFIX.test(
|
|
21406
|
+
function isTestFile(path13) {
|
|
21407
|
+
return TEST_INFIX.test(path13);
|
|
21202
21408
|
}
|
|
21203
|
-
function isReviewableSource(
|
|
21204
|
-
if (isTestFile(
|
|
21205
|
-
if (
|
|
21206
|
-
return CODE_EXTENSIONS.has(extensionOf(
|
|
21409
|
+
function isReviewableSource(path13) {
|
|
21410
|
+
if (isTestFile(path13)) return false;
|
|
21411
|
+
if (path13.endsWith(".d.ts")) return false;
|
|
21412
|
+
return CODE_EXTENSIONS.has(extensionOf(path13));
|
|
21207
21413
|
}
|
|
21208
21414
|
function testBaseKey(testFile) {
|
|
21209
21415
|
return testFile.replace(TEST_INFIX, "");
|
|
@@ -21307,7 +21513,7 @@ function toClaim(testCase, changedSourcePaths) {
|
|
|
21307
21513
|
const { strength, reasons } = gradeEvidence(testCase, audience);
|
|
21308
21514
|
const key = testBaseKey(testCase.sourceFile);
|
|
21309
21515
|
const coversFiles = changedSourcePaths.filter(
|
|
21310
|
-
(
|
|
21516
|
+
(path13) => sourceBaseKey(path13) === key
|
|
21311
21517
|
);
|
|
21312
21518
|
return {
|
|
21313
21519
|
id: testCase.id,
|
|
@@ -21556,7 +21762,7 @@ var ReviewMarkdownFormatter = class {
|
|
|
21556
21762
|
};
|
|
21557
21763
|
|
|
21558
21764
|
// src/formatters/review-html.ts
|
|
21559
|
-
function
|
|
21765
|
+
function escapeHtml4(value) {
|
|
21560
21766
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
21561
21767
|
}
|
|
21562
21768
|
var STRENGTH_LABEL = {
|
|
@@ -21578,22 +21784,22 @@ function statusIcon3(status) {
|
|
|
21578
21784
|
}
|
|
21579
21785
|
}
|
|
21580
21786
|
function formatStep3(step) {
|
|
21581
|
-
return `<li><strong>${
|
|
21787
|
+
return `<li><strong>${escapeHtml4(step.keyword)}</strong> ${escapeHtml4(step.text)}</li>`;
|
|
21582
21788
|
}
|
|
21583
21789
|
function inlineDoc(doc) {
|
|
21584
21790
|
switch (doc.kind) {
|
|
21585
21791
|
case "note":
|
|
21586
|
-
return
|
|
21792
|
+
return escapeHtml4(doc.text);
|
|
21587
21793
|
case "section":
|
|
21588
|
-
return `<strong>${
|
|
21794
|
+
return `<strong>${escapeHtml4(doc.title)}</strong>: ${escapeHtml4(doc.markdown)}`;
|
|
21589
21795
|
case "kv":
|
|
21590
|
-
return `${
|
|
21796
|
+
return `${escapeHtml4(doc.label)}: ${escapeHtml4(String(doc.value))}`;
|
|
21591
21797
|
case "code":
|
|
21592
|
-
return `${
|
|
21798
|
+
return `${escapeHtml4(doc.label)}: <code>${escapeHtml4(doc.content)}</code>`;
|
|
21593
21799
|
case "link":
|
|
21594
|
-
return `${
|
|
21800
|
+
return `${escapeHtml4(doc.label)}: ${escapeHtml4(doc.url)}`;
|
|
21595
21801
|
default:
|
|
21596
|
-
return
|
|
21802
|
+
return escapeHtml4(doc.kind);
|
|
21597
21803
|
}
|
|
21598
21804
|
}
|
|
21599
21805
|
function renderEvidenceArtifacts(testCase) {
|
|
@@ -21601,7 +21807,7 @@ function renderEvidenceArtifacts(testCase) {
|
|
|
21601
21807
|
for (const att of testCase.attachments) {
|
|
21602
21808
|
if (att.mediaType.startsWith("image/") && att.contentEncoding === "BASE64") {
|
|
21603
21809
|
parts.push(
|
|
21604
|
-
`<img class="shot" alt="${
|
|
21810
|
+
`<img class="shot" alt="${escapeHtml4(att.name)}" src="data:${escapeHtml4(att.mediaType)};base64,${att.body}" />`
|
|
21605
21811
|
);
|
|
21606
21812
|
}
|
|
21607
21813
|
}
|
|
@@ -21616,22 +21822,22 @@ function renderTicketPills(claim) {
|
|
|
21616
21822
|
const tickets = claim.testCase.story.tickets ?? [];
|
|
21617
21823
|
if (tickets.length === 0) return "";
|
|
21618
21824
|
return `<div class="ticket-row">${tickets.map((ticket) => {
|
|
21619
|
-
const label =
|
|
21825
|
+
const label = escapeHtml4(ticket.id);
|
|
21620
21826
|
if (ticket.url) {
|
|
21621
|
-
return `<a class="ticket-pill" href="${
|
|
21827
|
+
return `<a class="ticket-pill" href="${escapeHtml4(ticket.url)}" target="_blank" rel="noopener noreferrer">${label}</a>`;
|
|
21622
21828
|
}
|
|
21623
21829
|
return `<span class="ticket-pill">${label}</span>`;
|
|
21624
21830
|
}).join("")}</div>`;
|
|
21625
21831
|
}
|
|
21626
21832
|
function renderClaimCard(claim) {
|
|
21627
21833
|
const ticketSearch = (claim.testCase.story.tickets ?? []).map((ticket) => ticket.id).join(" ");
|
|
21628
|
-
const search =
|
|
21834
|
+
const search = escapeHtml4(
|
|
21629
21835
|
`${claim.scenario} ${claim.sourceFile} ${claim.changeType} ${claim.audience} ${claim.strength} ${ticketSearch}`
|
|
21630
21836
|
).toLowerCase();
|
|
21631
21837
|
const steps = claim.testCase.story.steps.length > 0 ? `<ul class="step-list">${claim.testCase.story.steps.map(formatStep3).join("")}</ul>` : "";
|
|
21632
|
-
const reasons = `<ul class="reasons">${claim.strengthReasons.map((r) => `<li>${
|
|
21633
|
-
const intent = claim.intent !== void 0 ? `<div class="intent"><span class="intent-label">Why</span> ${
|
|
21634
|
-
const covers = claim.coversFiles.length > 0 ? `<p class="covers">Covers ${claim.coversFiles.map((f) => `<code>${
|
|
21838
|
+
const reasons = `<ul class="reasons">${claim.strengthReasons.map((r) => `<li>${escapeHtml4(r)}</li>`).join("")}</ul>`;
|
|
21839
|
+
const intent = claim.intent !== void 0 ? `<div class="intent"><span class="intent-label">Why</span> ${escapeHtml4(claim.intent)}</div>` : "";
|
|
21840
|
+
const covers = claim.coversFiles.length > 0 ? `<p class="covers">Covers ${claim.coversFiles.map((f) => `<code>${escapeHtml4(f)}</code>`).join(", ")}</p>` : "";
|
|
21635
21841
|
const docs = (claim.testCase.story.docs ?? []).filter(
|
|
21636
21842
|
(d) => d.kind === "section" || d.kind === "note"
|
|
21637
21843
|
);
|
|
@@ -21641,9 +21847,9 @@ function renderClaimCard(claim) {
|
|
|
21641
21847
|
<header class="claim-header">
|
|
21642
21848
|
<div>
|
|
21643
21849
|
<span class="strength-badge strength-${claim.strength}">${STRENGTH_LABEL[claim.strength]}</span>
|
|
21644
|
-
${claim.changeType !== "unknown" ? `<span class="change-pill">${
|
|
21645
|
-
<h3>${statusIcon3(claim.status)} ${
|
|
21646
|
-
<p class="source">${
|
|
21850
|
+
${claim.changeType !== "unknown" ? `<span class="change-pill">${escapeHtml4(claim.changeType)}</span>` : ""}
|
|
21851
|
+
<h3>${statusIcon3(claim.status)} ${escapeHtml4(claim.scenario)}</h3>
|
|
21852
|
+
<p class="source">${escapeHtml4(`${claim.sourceFile}:${claim.sourceLine}`)}</p>
|
|
21647
21853
|
${renderTicketPills(claim)}
|
|
21648
21854
|
</div>
|
|
21649
21855
|
</header>
|
|
@@ -21658,18 +21864,18 @@ function renderClaimCard(claim) {
|
|
|
21658
21864
|
</article>`;
|
|
21659
21865
|
}
|
|
21660
21866
|
function renderChangedFileRow(file) {
|
|
21661
|
-
const claims = file.claims.length > 0 ? file.claims.map((c) => `${
|
|
21867
|
+
const claims = file.claims.length > 0 ? file.claims.map((c) => `${escapeHtml4(c.scenario)} <em>(${c.strength})</em>`).join(", ") : "\u2014";
|
|
21662
21868
|
return `<tr data-band="${file.band}">
|
|
21663
21869
|
<td><span class="band-dot band-${file.band}"></span></td>
|
|
21664
|
-
<td><code>${
|
|
21665
|
-
<td>${
|
|
21870
|
+
<td><code>${escapeHtml4(file.path)}</code></td>
|
|
21871
|
+
<td>${escapeHtml4(file.changeKind)}</td>
|
|
21666
21872
|
<td>${claims}</td>
|
|
21667
21873
|
</tr>`;
|
|
21668
21874
|
}
|
|
21669
21875
|
function renderAudienceSection2(title, claims) {
|
|
21670
21876
|
if (claims.length === 0) return "";
|
|
21671
21877
|
return `<section class="audience-section">
|
|
21672
|
-
<h2>${
|
|
21878
|
+
<h2>${escapeHtml4(title)} <span class="count">${claims.length}</span></h2>
|
|
21673
21879
|
<div class="claim-list">${claims.map(renderClaimCard).join("\n")}</div>
|
|
21674
21880
|
</section>`;
|
|
21675
21881
|
}
|
|
@@ -21759,13 +21965,13 @@ var ReviewHtmlFormatter = class {
|
|
|
21759
21965
|
const themeInitJs = this.darkMode ? `${JS_THEME_TOGGLE2}
|
|
21760
21966
|
applyTheme(getEffectiveTheme());` : "";
|
|
21761
21967
|
const themeAttr = this.darkMode ? ' data-theme="light"' : "";
|
|
21762
|
-
const refsLine = context.baseRef || context.headRef ? `<p class="subtle">Comparing ${
|
|
21968
|
+
const refsLine = context.baseRef || context.headRef ? `<p class="subtle">Comparing ${escapeHtml4(context.baseRef ?? "base")} \u2192 ${escapeHtml4(context.headRef ?? "head")}</p>` : "";
|
|
21763
21969
|
return `<!doctype html>
|
|
21764
21970
|
<html lang="en"${themeAttr}>
|
|
21765
21971
|
<head>
|
|
21766
21972
|
<meta charset="utf-8" />
|
|
21767
21973
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
21768
|
-
<title>${
|
|
21974
|
+
<title>${escapeHtml4(this.title)}</title>
|
|
21769
21975
|
<style>
|
|
21770
21976
|
${this.theme.css}
|
|
21771
21977
|
${REVIEW_CSS}
|
|
@@ -21775,7 +21981,7 @@ applyTheme(getEffectiveTheme());` : "";
|
|
|
21775
21981
|
<main>
|
|
21776
21982
|
<div class="hero-card card">
|
|
21777
21983
|
<div class="review-header">
|
|
21778
|
-
<h1>${
|
|
21984
|
+
<h1>${escapeHtml4(this.title)}</h1>
|
|
21779
21985
|
${themeToggleHtml}
|
|
21780
21986
|
</div>
|
|
21781
21987
|
${refsLine}
|
|
@@ -21790,7 +21996,7 @@ applyTheme(getEffectiveTheme());` : "";
|
|
|
21790
21996
|
</section>
|
|
21791
21997
|
<section class="card priority-banner">
|
|
21792
21998
|
<h2>Review priority</h2>
|
|
21793
|
-
<p class="subtle">${
|
|
21999
|
+
<p class="subtle">${escapeHtml4(priority)}</p>
|
|
21794
22000
|
</section>
|
|
21795
22001
|
${changedFilesPanel}
|
|
21796
22002
|
<section class="toolbar">
|
|
@@ -21838,8 +22044,8 @@ applyTheme(getEffectiveTheme());` : "";
|
|
|
21838
22044
|
};
|
|
21839
22045
|
|
|
21840
22046
|
// src/deploy/ledger.ts
|
|
21841
|
-
var
|
|
21842
|
-
var
|
|
22047
|
+
var fs10 = __toESM(require("fs"), 1);
|
|
22048
|
+
var path11 = __toESM(require("path"), 1);
|
|
21843
22049
|
function createEmptyLedger() {
|
|
21844
22050
|
return {
|
|
21845
22051
|
deployments: [],
|
|
@@ -21847,12 +22053,12 @@ function createEmptyLedger() {
|
|
|
21847
22053
|
};
|
|
21848
22054
|
}
|
|
21849
22055
|
function loadLedger(ledgerPath) {
|
|
21850
|
-
const resolved =
|
|
21851
|
-
if (!
|
|
22056
|
+
const resolved = path11.resolve(ledgerPath);
|
|
22057
|
+
if (!fs10.existsSync(resolved)) {
|
|
21852
22058
|
return createEmptyLedger();
|
|
21853
22059
|
}
|
|
21854
22060
|
try {
|
|
21855
|
-
const raw = JSON.parse(
|
|
22061
|
+
const raw = JSON.parse(fs10.readFileSync(resolved, "utf8"));
|
|
21856
22062
|
if (raw.schemaVersion !== 1) {
|
|
21857
22063
|
throw new Error(`Unsupported ledger schemaVersion: ${raw.schemaVersion}`);
|
|
21858
22064
|
}
|
|
@@ -21863,10 +22069,10 @@ function loadLedger(ledgerPath) {
|
|
|
21863
22069
|
}
|
|
21864
22070
|
}
|
|
21865
22071
|
function saveLedger(ledger, ledgerPath) {
|
|
21866
|
-
const resolved =
|
|
21867
|
-
const dir =
|
|
21868
|
-
|
|
21869
|
-
|
|
22072
|
+
const resolved = path11.resolve(ledgerPath);
|
|
22073
|
+
const dir = path11.dirname(resolved);
|
|
22074
|
+
fs10.mkdirSync(dir, { recursive: true });
|
|
22075
|
+
fs10.writeFileSync(resolved, JSON.stringify(ledger, null, 2), "utf8");
|
|
21870
22076
|
}
|
|
21871
22077
|
function getLatestDeployment(ledger, environment) {
|
|
21872
22078
|
return [...ledger.deployments].reverse().find((d) => d.environment === environment);
|
|
@@ -21986,11 +22192,11 @@ function computeOutputPath(sourceFile, format, mode, colocatedStyle, baseOutputD
|
|
|
21986
22192
|
const ext = FORMAT_EXTENSIONS[format];
|
|
21987
22193
|
const effectiveName = outputName + (outputNameSuffix ?? "");
|
|
21988
22194
|
if (mode === "aggregated") {
|
|
21989
|
-
return toPosix(
|
|
22195
|
+
return toPosix(path12.join(baseOutputDir, joinNameAndExt(effectiveName, ext)));
|
|
21990
22196
|
}
|
|
21991
22197
|
const normalizedSource = toPosix(sourceFile);
|
|
21992
|
-
const dirOfSource =
|
|
21993
|
-
let baseName =
|
|
22198
|
+
const dirOfSource = path12.posix.dirname(normalizedSource);
|
|
22199
|
+
let baseName = path12.posix.basename(normalizedSource);
|
|
21994
22200
|
for (const testExt of TEST_EXTENSIONS) {
|
|
21995
22201
|
if (baseName.endsWith(testExt)) {
|
|
21996
22202
|
baseName = baseName.slice(0, -testExt.length);
|
|
@@ -21999,12 +22205,12 @@ function computeOutputPath(sourceFile, format, mode, colocatedStyle, baseOutputD
|
|
|
21999
22205
|
}
|
|
22000
22206
|
const fileName = `${baseName}.${effectiveName}${ext}`;
|
|
22001
22207
|
if (colocatedStyle === "adjacent") {
|
|
22002
|
-
return toPosix(
|
|
22208
|
+
return toPosix(path12.posix.join(dirOfSource, fileName));
|
|
22003
22209
|
}
|
|
22004
22210
|
if (colocatedStyle === "flat") {
|
|
22005
|
-
return toPosix(
|
|
22211
|
+
return toPosix(path12.posix.join(baseOutputDir, `${cleanTestStem(normalizedSource)}${ext}`));
|
|
22006
22212
|
}
|
|
22007
|
-
return toPosix(
|
|
22213
|
+
return toPosix(path12.posix.join(baseOutputDir, dirOfSource, fileName));
|
|
22008
22214
|
}
|
|
22009
22215
|
function groupTestCasesByOutput(testCases, format, options, logger, outputNameSuffix) {
|
|
22010
22216
|
const groups = /* @__PURE__ */ new Map();
|
|
@@ -22217,8 +22423,8 @@ var ReportGenerator = class {
|
|
|
22217
22423
|
if (astroPaths) {
|
|
22218
22424
|
for (const mdPath of astroPaths) {
|
|
22219
22425
|
const content = await fsPromises.readFile(mdPath, "utf8");
|
|
22220
|
-
const mdDir =
|
|
22221
|
-
const assetsDir =
|
|
22426
|
+
const mdDir = path12.dirname(mdPath);
|
|
22427
|
+
const assetsDir = path12.resolve(this.options.astro.assetsDir);
|
|
22222
22428
|
const result = copyMarkdownAssets({
|
|
22223
22429
|
markdown: content,
|
|
22224
22430
|
markdownDir: mdDir,
|
|
@@ -22249,9 +22455,9 @@ var ReportGenerator = class {
|
|
|
22249
22455
|
if (groups.size === 0 && this.options.output.mode === "aggregated") {
|
|
22250
22456
|
const ext = FORMAT_EXTENSIONS[format];
|
|
22251
22457
|
const effectiveName = this.options.outputName + (outputNameSuffix ?? "");
|
|
22252
|
-
const outputPath = toPosix(
|
|
22458
|
+
const outputPath = toPosix(path12.join(this.options.outputDir, joinNameAndExt(effectiveName, ext)));
|
|
22253
22459
|
const content = await this.formatContent(run, format);
|
|
22254
|
-
const dir =
|
|
22460
|
+
const dir = path12.dirname(outputPath);
|
|
22255
22461
|
await fsPromises.mkdir(dir, { recursive: true });
|
|
22256
22462
|
await this.deps.writeFile(outputPath, content);
|
|
22257
22463
|
return [outputPath];
|
|
@@ -22263,7 +22469,7 @@ var ReportGenerator = class {
|
|
|
22263
22469
|
testCases
|
|
22264
22470
|
};
|
|
22265
22471
|
const content = await this.formatContent(groupRun, format);
|
|
22266
|
-
const dir =
|
|
22472
|
+
const dir = path12.dirname(outputPath);
|
|
22267
22473
|
await fsPromises.mkdir(dir, { recursive: true });
|
|
22268
22474
|
await this.deps.writeFile(outputPath, content);
|
|
22269
22475
|
writtenPaths.push(outputPath);
|
|
@@ -22415,7 +22621,7 @@ async function generateRunComparison(args) {
|
|
|
22415
22621
|
await fsPromises.mkdir(outputDir, { recursive: true });
|
|
22416
22622
|
for (const format of args.formats) {
|
|
22417
22623
|
const ext = format === "html" ? ".html" : ".md";
|
|
22418
|
-
const outputPath = toPosix(
|
|
22624
|
+
const outputPath = toPosix(path12.join(outputDir, `${outputName}${ext}`));
|
|
22419
22625
|
const content = format === "html" ? new RunDiffHtmlFormatter({ title: args.title }).format(diff) : new RunDiffMarkdownFormatter({ title: args.title }).format(diff);
|
|
22420
22626
|
await fsPromises.writeFile(outputPath, content, "utf8");
|
|
22421
22627
|
files.push(outputPath);
|
|
@@ -22465,6 +22671,7 @@ function normalizePlaywrightResults(testResults, adapterOptions, canonicalizeOpt
|
|
|
22465
22671
|
adaptJestRun,
|
|
22466
22672
|
adaptPlaywrightRun,
|
|
22467
22673
|
adaptVitestRun,
|
|
22674
|
+
advanceState,
|
|
22468
22675
|
assertValidRun,
|
|
22469
22676
|
buildCheck,
|
|
22470
22677
|
buildGoal,
|
|
@@ -22477,6 +22684,7 @@ function normalizePlaywrightResults(testResults, adapterOptions, canonicalizeOpt
|
|
|
22477
22684
|
canonicalizeRun,
|
|
22478
22685
|
classifyStatusChange,
|
|
22479
22686
|
clearVersionCache,
|
|
22687
|
+
computeDeltas,
|
|
22480
22688
|
computeTestMetrics,
|
|
22481
22689
|
copyMarkdownAssets,
|
|
22482
22690
|
createPrCommentSummary,
|
|
@@ -22499,6 +22707,7 @@ function normalizePlaywrightResults(testResults, adapterOptions, canonicalizeOpt
|
|
|
22499
22707
|
getEnvironmentDrift,
|
|
22500
22708
|
gradeEvidence,
|
|
22501
22709
|
hasSufficientHistory,
|
|
22710
|
+
injectLiveBits,
|
|
22502
22711
|
isReviewableSource,
|
|
22503
22712
|
isTestFile,
|
|
22504
22713
|
joinNameAndExt,
|
|
@@ -22520,7 +22729,9 @@ function normalizePlaywrightResults(testResults, adapterOptions, canonicalizeOpt
|
|
|
22520
22729
|
readPackageVersion,
|
|
22521
22730
|
recordDeployment,
|
|
22522
22731
|
regenerateArtifacts,
|
|
22732
|
+
regenerateRun,
|
|
22523
22733
|
renderCheck,
|
|
22734
|
+
renderDeltaStrip,
|
|
22524
22735
|
renderGoal,
|
|
22525
22736
|
renderTriage,
|
|
22526
22737
|
resolveAttachment,
|
|
@@ -22536,6 +22747,7 @@ function normalizePlaywrightResults(testResults, adapterOptions, canonicalizeOpt
|
|
|
22536
22747
|
sendWebhookNotification,
|
|
22537
22748
|
signBody,
|
|
22538
22749
|
slugify,
|
|
22750
|
+
startServe,
|
|
22539
22751
|
startWatch,
|
|
22540
22752
|
stripAnsi,
|
|
22541
22753
|
toBehaviorManifest,
|