executable-stories-react 0.15.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/index.cjs +147 -65
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +136 -54
- package/dist/index.js.map +1 -1
- package/dist/interactive.cjs +439 -332
- package/dist/interactive.cjs.map +1 -1
- package/dist/interactive.d.cts +6 -0
- package/dist/interactive.d.ts +6 -0
- package/dist/interactive.js +397 -290
- package/dist/interactive.js.map +1 -1
- package/dist/report-island.global.js +55 -54
- package/dist/ssr.cjs +111 -28
- package/dist/ssr.cjs.map +1 -1
- package/dist/ssr.d.cts +2 -0
- package/dist/ssr.d.ts +2 -0
- package/dist/ssr.js +99 -16
- package/dist/ssr.js.map +1 -1
- package/dist/tailwind.css +1 -1
- package/package.json +3 -3
package/dist/ssr.d.cts
CHANGED
|
@@ -91,6 +91,8 @@ interface RenderReportToHtmlOptions {
|
|
|
91
91
|
share?: boolean;
|
|
92
92
|
/** Command the share dialog hands over, e.g. `npx executable-stories share reports/`. */
|
|
93
93
|
shareCommand?: string;
|
|
94
|
+
/** Draw the "Architecture, as it ran" span section (default false). `--html-architecture`. */
|
|
95
|
+
architecture?: boolean;
|
|
94
96
|
}
|
|
95
97
|
/**
|
|
96
98
|
* Render a StoryReport (or a parse Result) to a complete, self-contained HTML
|
package/dist/ssr.d.ts
CHANGED
|
@@ -91,6 +91,8 @@ interface RenderReportToHtmlOptions {
|
|
|
91
91
|
share?: boolean;
|
|
92
92
|
/** Command the share dialog hands over, e.g. `npx executable-stories share reports/`. */
|
|
93
93
|
shareCommand?: string;
|
|
94
|
+
/** Draw the "Architecture, as it ran" span section (default false). `--html-architecture`. */
|
|
95
|
+
architecture?: boolean;
|
|
94
96
|
}
|
|
95
97
|
/**
|
|
96
98
|
* Render a StoryReport (or a parse Result) to a complete, self-contained HTML
|
package/dist/ssr.js
CHANGED
|
@@ -523,12 +523,29 @@ function DocVideo({ entry }) {
|
|
|
523
523
|
}
|
|
524
524
|
|
|
525
525
|
// src/components/doc/DocHtml.tsx
|
|
526
|
+
import { useEffect, useRef, useState } from "react";
|
|
526
527
|
import { jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
528
|
+
var MEASURE_SCRIPT = "<script>(function(){if(parent===window)return;var last=0,queued=false;var measure=function(){var kids=document.body.children,h=0;for(var i=0;i<kids.length;i++)h=Math.max(h,kids[i].getBoundingClientRect().bottom);return Math.ceil(h||document.body.getBoundingClientRect().bottom)};var post=function(){queued=false;var h=measure();if(h===last)return;last=h;parent.postMessage({__esHtmlHeight:h},'*')};var schedule=function(){if(queued)return;queued=true;requestAnimationFrame(post)};var start=function(){new ResizeObserver(schedule).observe(document.body);new MutationObserver(schedule).observe(document.body,{subtree:true,childList:true,attributes:true,characterData:true});addEventListener('load',schedule);post()};if(document.body)start();else addEventListener('DOMContentLoaded',start)})();</script>";
|
|
529
|
+
var MAX_MEASURED_HEIGHT = 5e3;
|
|
527
530
|
function DocHtml({ entry }) {
|
|
528
|
-
const
|
|
531
|
+
const declaredHeight = typeof entry.height === "number" ? `${entry.height}px` : entry.height ?? "400px";
|
|
529
532
|
const title = entry.title ?? "Embedded HTML";
|
|
530
533
|
const safeHref = safeUrl(entry.url ?? entry.path);
|
|
531
|
-
const
|
|
534
|
+
const frameRef = useRef(null);
|
|
535
|
+
const [measuredHeight, setMeasuredHeight] = useState();
|
|
536
|
+
useEffect(() => {
|
|
537
|
+
if (entry.content === void 0) return;
|
|
538
|
+
const onMessage = (event) => {
|
|
539
|
+
if (event.source !== frameRef.current?.contentWindow) return;
|
|
540
|
+
const reported = event.data?.__esHtmlHeight;
|
|
541
|
+
if (typeof reported !== "number" || !Number.isFinite(reported) || reported <= 0) return;
|
|
542
|
+
setMeasuredHeight(Math.min(reported, MAX_MEASURED_HEIGHT));
|
|
543
|
+
};
|
|
544
|
+
window.addEventListener("message", onMessage);
|
|
545
|
+
return () => window.removeEventListener("message", onMessage);
|
|
546
|
+
}, [entry.content]);
|
|
547
|
+
const height = measuredHeight === void 0 ? declaredHeight : `${measuredHeight}px`;
|
|
548
|
+
const frameProps = entry.content !== void 0 ? { srcDoc: entry.content + MEASURE_SCRIPT } : { src: safeHref ?? "" };
|
|
532
549
|
return /* @__PURE__ */ jsxs9("figure", { className: "my-3 overflow-hidden rounded-md border border-border", children: [
|
|
533
550
|
/* @__PURE__ */ jsxs9("figcaption", { className: "flex items-center justify-between border-b border-border bg-muted/40 px-3 py-1.5 text-xs font-medium text-muted-foreground", children: [
|
|
534
551
|
/* @__PURE__ */ jsx14("span", { children: entry.title ?? "HTML" }),
|
|
@@ -548,6 +565,7 @@ function DocHtml({ entry }) {
|
|
|
548
565
|
/* @__PURE__ */ jsx14(
|
|
549
566
|
"iframe",
|
|
550
567
|
{
|
|
568
|
+
ref: frameRef,
|
|
551
569
|
...frameProps,
|
|
552
570
|
sandbox: "allow-scripts",
|
|
553
571
|
loading: "lazy",
|
|
@@ -1096,7 +1114,7 @@ function ScenarioRunHistory({ scenarioId }) {
|
|
|
1096
1114
|
}
|
|
1097
1115
|
|
|
1098
1116
|
// src/components/ScenarioStaleness.tsx
|
|
1099
|
-
import { useEffect, useState } from "react";
|
|
1117
|
+
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
1100
1118
|
|
|
1101
1119
|
// src/lib/provenance.ts
|
|
1102
1120
|
function formatRelativeAge(thenMs, nowMs) {
|
|
@@ -1155,8 +1173,8 @@ import { jsxs as jsxs16 } from "react/jsx-runtime";
|
|
|
1155
1173
|
function ScenarioStaleness({ scenario }) {
|
|
1156
1174
|
const freshness = useScenarioFreshness();
|
|
1157
1175
|
const fixedNow = freshness?.nowMs;
|
|
1158
|
-
const [now, setNow] =
|
|
1159
|
-
|
|
1176
|
+
const [now, setNow] = useState2(fixedNow);
|
|
1177
|
+
useEffect2(() => {
|
|
1160
1178
|
if (fixedNow === void 0) setNow(Date.now());
|
|
1161
1179
|
}, [fixedNow]);
|
|
1162
1180
|
if (!freshness || now === void 0) return null;
|
|
@@ -1170,7 +1188,7 @@ function ScenarioStaleness({ scenario }) {
|
|
|
1170
1188
|
}
|
|
1171
1189
|
|
|
1172
1190
|
// src/interactive/collapse-context.ts
|
|
1173
|
-
import { createContext as createContext4, useCallback, useContext as useContext5, useState as
|
|
1191
|
+
import { createContext as createContext4, useCallback, useContext as useContext5, useState as useState3 } from "react";
|
|
1174
1192
|
var CollapseContext = createContext4(null);
|
|
1175
1193
|
var CollapseProvider = CollapseContext.Provider;
|
|
1176
1194
|
function useCollapse() {
|
|
@@ -1744,23 +1762,85 @@ function ReportErrorShell({
|
|
|
1744
1762
|
return /* @__PURE__ */ jsx36("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: /* @__PURE__ */ jsx36(ReportSchemaError, { error }) });
|
|
1745
1763
|
}
|
|
1746
1764
|
|
|
1747
|
-
// src/components/
|
|
1765
|
+
// src/components/ReportSpanGraph.tsx
|
|
1766
|
+
import { deriveSpanGraph, spanGraphNodeMark, spanGraphToMermaid } from "executable-stories-core/span-graph";
|
|
1767
|
+
import { useMemo as useMemo2 } from "react";
|
|
1748
1768
|
import { jsx as jsx37, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
1769
|
+
var LANE_LABEL = {
|
|
1770
|
+
edge: "Edge",
|
|
1771
|
+
service: "Service",
|
|
1772
|
+
queue: "Queue",
|
|
1773
|
+
datastore: "Data"
|
|
1774
|
+
};
|
|
1775
|
+
var MARK_LABEL = {
|
|
1776
|
+
failing: "Failing",
|
|
1777
|
+
added: "New",
|
|
1778
|
+
changed: "Changed"
|
|
1779
|
+
};
|
|
1780
|
+
var MARK_CLASS = {
|
|
1781
|
+
failing: "text-fail",
|
|
1782
|
+
added: "text-pass",
|
|
1783
|
+
changed: "text-pend"
|
|
1784
|
+
};
|
|
1785
|
+
function MarkBadge({ node }) {
|
|
1786
|
+
const mark = spanGraphNodeMark(node);
|
|
1787
|
+
if (!mark) return null;
|
|
1788
|
+
return /* @__PURE__ */ jsx37("span", { className: cn("ml-2 text-xs font-medium", MARK_CLASS[mark]), children: MARK_LABEL[mark] });
|
|
1789
|
+
}
|
|
1790
|
+
function ReportSpanGraph() {
|
|
1791
|
+
const report = useReport();
|
|
1792
|
+
const { code, graph, titleById } = useMemo2(() => {
|
|
1793
|
+
const scenarios = report.features.flatMap((feature) => feature.scenarios);
|
|
1794
|
+
const derived = deriveSpanGraph(scenarios);
|
|
1795
|
+
return {
|
|
1796
|
+
graph: derived,
|
|
1797
|
+
code: spanGraphToMermaid(derived),
|
|
1798
|
+
titleById: new Map(scenarios.map((scenario) => [scenario.id, scenario.title]))
|
|
1799
|
+
};
|
|
1800
|
+
}, [report]);
|
|
1801
|
+
if (code === "") return null;
|
|
1802
|
+
return /* @__PURE__ */ jsxs25("section", { className: "es-span-graph mt-6", "aria-labelledby": "es-span-graph-heading", children: [
|
|
1803
|
+
/* @__PURE__ */ jsx37("h2", { id: "es-span-graph-heading", className: "text-base font-semibold text-foreground", children: "Architecture, as it ran" }),
|
|
1804
|
+
/* @__PURE__ */ jsx37("p", { className: "mt-1 text-sm text-muted-foreground", children: "Derived from this run\u2019s traces. Every component was named by a span while a scenario ran, so nothing here is inferred from the code. Instrumented, exercised paths only: a component no scenario reaches does not appear." }),
|
|
1805
|
+
/* @__PURE__ */ jsx37(DocMermaid, { entry: { kind: "mermaid", phase: "static", code } }),
|
|
1806
|
+
/* @__PURE__ */ jsxs25("table", { className: "mt-2 w-full border-collapse text-left text-sm", children: [
|
|
1807
|
+
/* @__PURE__ */ jsx37("caption", { className: "sr-only", children: "Each component and the scenarios that exercised it" }),
|
|
1808
|
+
/* @__PURE__ */ jsx37("thead", { children: /* @__PURE__ */ jsxs25("tr", { className: "text-xs text-muted-foreground", children: [
|
|
1809
|
+
/* @__PURE__ */ jsx37("th", { scope: "col", className: "py-1 pr-4 font-medium", children: "Component" }),
|
|
1810
|
+
/* @__PURE__ */ jsx37("th", { scope: "col", className: "py-1 pr-4 font-medium", children: "Lane" }),
|
|
1811
|
+
/* @__PURE__ */ jsx37("th", { scope: "col", className: "py-1 font-medium", children: "Covered by" })
|
|
1812
|
+
] }) }),
|
|
1813
|
+
/* @__PURE__ */ jsx37("tbody", { children: graph.nodes.map((node) => /* @__PURE__ */ jsxs25("tr", { className: "border-t border-border align-top", children: [
|
|
1814
|
+
/* @__PURE__ */ jsxs25("th", { scope: "row", className: "py-1.5 pr-4 font-mono text-xs font-normal", children: [
|
|
1815
|
+
node.id,
|
|
1816
|
+
/* @__PURE__ */ jsx37(MarkBadge, { node })
|
|
1817
|
+
] }),
|
|
1818
|
+
/* @__PURE__ */ jsx37("td", { className: "py-1.5 pr-4 text-xs text-muted-foreground", children: LANE_LABEL[node.kind] }),
|
|
1819
|
+
/* @__PURE__ */ jsx37("td", { className: "py-1.5", children: /* @__PURE__ */ jsx37("ul", { className: "flex flex-col gap-0.5", children: node.scenarioIds.map((id) => /* @__PURE__ */ jsx37("li", { children: /* @__PURE__ */ jsx37("a", { href: `#${id}`, className: "text-xs text-link underline underline-offset-2 hover:text-foreground", children: titleById.get(id) ?? id }) }, id)) }) })
|
|
1820
|
+
] }, node.id)) })
|
|
1821
|
+
] })
|
|
1822
|
+
] });
|
|
1823
|
+
}
|
|
1824
|
+
|
|
1825
|
+
// src/components/Report.tsx
|
|
1826
|
+
import { jsx as jsx38, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
1749
1827
|
function Report(props) {
|
|
1750
|
-
const { report, customRenderers, renderers, className, title, dataTheme } = props;
|
|
1828
|
+
const { report, customRenderers, renderers, className, title, dataTheme, architecture = false } = props;
|
|
1751
1829
|
const result = unwrapReport(report);
|
|
1752
1830
|
if (!result.ok) {
|
|
1753
|
-
return /* @__PURE__ */
|
|
1831
|
+
return /* @__PURE__ */ jsx38(ReportErrorShell, { error: result.error, className, title, dataTheme });
|
|
1754
1832
|
}
|
|
1755
1833
|
const data = result.data;
|
|
1756
1834
|
const hasContent = data.features.length > 0;
|
|
1757
|
-
return /* @__PURE__ */
|
|
1758
|
-
/* @__PURE__ */
|
|
1759
|
-
|
|
1835
|
+
return /* @__PURE__ */ jsx38(ReportRoot, { report: data, customRenderers, renderers, children: /* @__PURE__ */ jsxs26("main", { className: cn("es-report", className), "aria-label": title ?? "Test report", "data-theme": dataTheme, children: [
|
|
1836
|
+
/* @__PURE__ */ jsx38("header", { className: "es-report-header", children: /* @__PURE__ */ jsx38(ReportTitleBlock, { title }) }),
|
|
1837
|
+
architecture ? /* @__PURE__ */ jsx38(ReportSpanGraph, {}) : null,
|
|
1838
|
+
hasContent ? /* @__PURE__ */ jsx38(ReportFeatureList, {}) : /* @__PURE__ */ jsx38(ReportEmpty, {})
|
|
1760
1839
|
] }) });
|
|
1761
1840
|
}
|
|
1762
1841
|
|
|
1763
1842
|
// src/ssr-entry.ts
|
|
1843
|
+
import { REPORT_FAVICON_LINK } from "executable-stories-core/utils/report-favicon";
|
|
1764
1844
|
var ROOT_ID = "es-report-root";
|
|
1765
1845
|
var DATA_ID = "es-report-data";
|
|
1766
1846
|
var HISTORY_ID = "es-report-history";
|
|
@@ -1770,7 +1850,7 @@ function escapeJsonForScript(json) {
|
|
|
1770
1850
|
var HLJS_URL = "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/es/highlight.min.js";
|
|
1771
1851
|
var HLJS_CSS_LIGHT = "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github.min.css";
|
|
1772
1852
|
var HLJS_CSS_DARK = "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css";
|
|
1773
|
-
var MERMAID_URL = "https://cdn.jsdelivr.net/npm/mermaid@
|
|
1853
|
+
var MERMAID_URL = "https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs";
|
|
1774
1854
|
function cdnAssets(syntaxHighlighting, mermaid) {
|
|
1775
1855
|
const headParts = [];
|
|
1776
1856
|
const imports = [];
|
|
@@ -1816,10 +1896,11 @@ function renderReportToHtml(report, options = {}) {
|
|
|
1816
1896
|
staleAfterDays = 7,
|
|
1817
1897
|
scenarioHistory,
|
|
1818
1898
|
share = false,
|
|
1819
|
-
shareCommand = ""
|
|
1899
|
+
shareCommand = "",
|
|
1900
|
+
architecture = false
|
|
1820
1901
|
} = options;
|
|
1821
1902
|
const markup = renderToStaticMarkup(
|
|
1822
|
-
createElement(Report, { report, title })
|
|
1903
|
+
createElement(Report, { report, title, architecture })
|
|
1823
1904
|
);
|
|
1824
1905
|
const cdn = cdnAssets(syntaxHighlighting, mermaid);
|
|
1825
1906
|
const parsed = unwrapReport(report);
|
|
@@ -1829,8 +1910,9 @@ function renderReportToHtml(report, options = {}) {
|
|
|
1829
1910
|
const historyScript = interactive && scenarioHistory && Object.keys(scenarioHistory).length > 0 ? `<script type="application/json" id="${HISTORY_ID}">${escapeJsonForScript(JSON.stringify(scenarioHistory))}</script>` : "";
|
|
1830
1911
|
const islandTag = interactive ? `<script>${islandScript}</script>` : "";
|
|
1831
1912
|
const cdnBody = interactive ? "" : cdn.body;
|
|
1913
|
+
const architectureAttr = architecture ? ` data-es-architecture="true"` : "";
|
|
1832
1914
|
const shareAttrs = share ? ` data-es-share="true"${shareCommand ? ` data-es-share-cmd="${escapeHtml(shareCommand)}"` : ""}` : "";
|
|
1833
|
-
const islandConfigAttrs = interactive ? ` data-es-syntax="${syntaxHighlighting ? "true" : "false"}" data-es-mermaid="${mermaid ? "true" : "false"}" data-es-stale-days="${Number.isFinite(staleAfterDays) && staleAfterDays >= 0 ? staleAfterDays : 7}"${shareAttrs}` : "";
|
|
1915
|
+
const islandConfigAttrs = interactive ? ` data-es-syntax="${syntaxHighlighting ? "true" : "false"}" data-es-mermaid="${mermaid ? "true" : "false"}" data-es-stale-days="${Number.isFinite(staleAfterDays) && staleAfterDays >= 0 ? staleAfterDays : 7}"${shareAttrs}${architectureAttr}` : "";
|
|
1834
1916
|
const rootAttrs = interactive ? ` id="${ROOT_ID}" data-title="${escapeHtml(title)}"${islandConfigAttrs}` : "";
|
|
1835
1917
|
return `<!DOCTYPE html>
|
|
1836
1918
|
<html lang="${escapeHtml(lang)}" data-theme="${theme === "dark" ? "dark" : "light"}">
|
|
@@ -1838,6 +1920,7 @@ function renderReportToHtml(report, options = {}) {
|
|
|
1838
1920
|
<meta charset="UTF-8">
|
|
1839
1921
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
1840
1922
|
<meta name="color-scheme" content="light dark">
|
|
1923
|
+
${REPORT_FAVICON_LINK}
|
|
1841
1924
|
<title>${escapeHtml(title)}</title>
|
|
1842
1925
|
${cdn.head}
|
|
1843
1926
|
${headExtra}
|