@sverka/playground 0.2.20 → 0.2.22
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.d.mts +2 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +9 -12
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.d.mts
CHANGED
|
@@ -174,7 +174,8 @@ interface MountRunnerOptions {
|
|
|
174
174
|
* come from a share link or CMS, so mounting never executes it unless
|
|
175
175
|
* the embedder opts in or the user clicks Run. */
|
|
176
176
|
readonly autoRun?: boolean;
|
|
177
|
-
/** Called once per completed run
|
|
177
|
+
/** Called once per completed run — unless the runner was disposed
|
|
178
|
+
* first; teardown silences callbacks for runs still in flight. */
|
|
178
179
|
readonly onRun?: (result: PipelineResult) => void;
|
|
179
180
|
}
|
|
180
181
|
interface MountedRunner {
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/pipeline.ts","../src/runner.ts","../src/share.ts","../src/embed.ts","../src/engine.ts","../src/transpile.ts","../src/gallery.ts"],"mappings":";;KAGY;;UAGK;EACf;EACA;EACA;EACA;EACA;;;UAIe;EACf;EACA;EACA;EACA,UAAU;EACV;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,QAAQ;EACR;;;;UAKe;EACf;EACA;EACA;EACA,UAAU;EACV;EACA;EACA;;;UAIe;EACf;EACA;EACA,UAAU;EACV;EACA;;;UAIe;EACf,OAAO;EACP,UAAU;EACV;EACA;;;;;uBCrDoB;WACX;WACA,OAAO;EAEJ,YAAA,OAAO,kBAAkB;;MAMjC;;;qBASO,gBAAgB;WAClB,WAAW;EAER,YAAA;;EAKZ,YAAY,UAAU;;;qBAMX,iBAAiB;WACnB,OAAO;WACP,SAAS;EAEN,YAAA,SAAS,SAAS;;EAM9B,QAAQ,MAAM;;EAKd,SAAS,OAAO;;;uBAMI,aAAa;WACxB;EAEG,YAAA,UAAU,UAAU,YAAY;;WAOnC,WAAW,QAAQ,uBAAuB;;;qBAIxC,qBAAqB;WACvB,UAAU,QAAQ,uBAAuB;EAGhD,YAAA,UAAU,UACV,YACA;IACE,UAAU,QAAQ,uBAAuB;IACzC;;EAOJ,WAAW,QAAQ,uBAAuB;;;;;;;;qBAW/B,kBAAkB;WACpB;EAGP,YAAA,UAAU,UACV,YACA;IACE;IACA;IACA;IACA;IACA;;EAOJ,WAAW;;;qBAgBA;WACF,UAAU;WACV;WACA;IAAW;;WACX;EAGP,YAAA,UAAU,UACV,YACA;IAAW;MAAW;;IAAgB;;;;;;;;;;;;;wBC7DpB,YAAY,SAAS,UAAU,QAAQ;;;UC3E5C;WACN;WACA;WACA,oBAAoB;;KAGnB;qBAGC,wBAAwB;WAC1B,MAAM;EACH,YAAA,MAAM,qBAAqB;;;qBAQ5B;;;qBAIA;;;wBAkFG,gBAAgB,KAAK,cAAc;;;;wBAkCnC,gBAAgB,eAAe;;;UCnI9B;;WAEN;;WAEA;;;;WAIA
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/pipeline.ts","../src/runner.ts","../src/share.ts","../src/embed.ts","../src/engine.ts","../src/transpile.ts","../src/gallery.ts"],"mappings":";;KAGY;;UAGK;EACf;EACA;EACA;EACA;EACA;;;UAIe;EACf;EACA;EACA;EACA,UAAU;EACV;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,QAAQ;EACR;;;;UAKe;EACf;EACA;EACA;EACA,UAAU;EACV;EACA;EACA;;;UAIe;EACf;EACA;EACA,UAAU;EACV;EACA;;;UAIe;EACf,OAAO;EACP,UAAU;EACV;EACA;;;;;uBCrDoB;WACX;WACA,OAAO;EAEJ,YAAA,OAAO,kBAAkB;;MAMjC;;;qBASO,gBAAgB;WAClB,WAAW;EAER,YAAA;;EAKZ,YAAY,UAAU;;;qBAMX,iBAAiB;WACnB,OAAO;WACP,SAAS;EAEN,YAAA,SAAS,SAAS;;EAM9B,QAAQ,MAAM;;EAKd,SAAS,OAAO;;;uBAMI,aAAa;WACxB;EAEG,YAAA,UAAU,UAAU,YAAY;;WAOnC,WAAW,QAAQ,uBAAuB;;;qBAIxC,qBAAqB;WACvB,UAAU,QAAQ,uBAAuB;EAGhD,YAAA,UAAU,UACV,YACA;IACE,UAAU,QAAQ,uBAAuB;IACzC;;EAOJ,WAAW,QAAQ,uBAAuB;;;;;;;;qBAW/B,kBAAkB;WACpB;EAGP,YAAA,UAAU,UACV,YACA;IACE;IACA;IACA;IACA;IACA;;EAOJ,WAAW;;;qBAgBA;WACF,UAAU;WACV;WACA;IAAW;;WACX;EAGP,YAAA,UAAU,UACV,YACA;IAAW;MAAW;;IAAgB;;;;;;;;;;;;;wBC7DpB,YAAY,SAAS,UAAU,QAAQ;;;UC3E5C;WACN;WACA;WACA,oBAAoB;;KAGnB;qBAGC,wBAAwB;WAC1B,MAAM;EACH,YAAA,MAAM,qBAAqB;;;qBAQ5B;;;qBAIA;;;wBAkFG,gBAAgB,KAAK,cAAc;;;;wBAkCnC,gBAAgB,eAAe;;;UCnI9B;;WAEN;;WAEA;;;;WAIA;;;WAGA,SAAS,QAAQ;;UAGX;;EAEf;;;;;;;;wBAkKc,YACd,IAAI,aACJ,OAAM,qBACL;;;;qBCnJU;;;;;;;;;;;;wBAmWG,iBAAiB,eAAe;;;;;;wBA6C1B,uBACpB,SAAS,SACT,oBACC,QAAQ,QAAQ,kBAAkB;;;;;;;;;;;;;;;;wBCfrB,eAAe;;;UC/ad;;WAEN;;WAEA;;WAEA;;;;wBAYK,aACd,SAAS,kCACC"}
|
package/dist/index.mjs
CHANGED
|
@@ -433,8 +433,11 @@ function scanOpaqueEnd(code, i, depth = 0) {
|
|
|
433
433
|
isString: false
|
|
434
434
|
};
|
|
435
435
|
}
|
|
436
|
-
/**
|
|
437
|
-
*
|
|
436
|
+
/** Reserved words after which `/` opens a regex rather than divides —
|
|
437
|
+
* they can never end an operand. Contextual keywords (`of`, `as`,
|
|
438
|
+
* `from`, `get`, `set`, `type`, `async`, `declare`) are NOT listed:
|
|
439
|
+
* they act as ordinary identifiers in most positions, so a `/` after
|
|
440
|
+
* them divides. Everything else — plain identifiers plus literals such
|
|
438
441
|
* as `this`/`true` — ends an operand, making `/` a division. */
|
|
439
442
|
const NON_OPERAND_WORDS = /* @__PURE__ */ new Set([
|
|
440
443
|
"await",
|
|
@@ -477,15 +480,7 @@ const NON_OPERAND_WORDS = /* @__PURE__ */ new Set([
|
|
|
477
480
|
"void",
|
|
478
481
|
"while",
|
|
479
482
|
"with",
|
|
480
|
-
"yield"
|
|
481
|
-
"as",
|
|
482
|
-
"async",
|
|
483
|
-
"from",
|
|
484
|
-
"get",
|
|
485
|
-
"of",
|
|
486
|
-
"set",
|
|
487
|
-
"type",
|
|
488
|
-
"declare"
|
|
483
|
+
"yield"
|
|
489
484
|
]);
|
|
490
485
|
/** True when `word` ends an operand — a following `/` is division. */
|
|
491
486
|
function operandAfterWord(word) {
|
|
@@ -1107,6 +1102,7 @@ function mountRunner(el, opts = {}) {
|
|
|
1107
1102
|
root.append(header, codeEl, frame);
|
|
1108
1103
|
el.appendChild(root);
|
|
1109
1104
|
const getCode = () => opts.readonly === true ? code : codeEl.value;
|
|
1105
|
+
let disposed = false;
|
|
1110
1106
|
const run = async () => {
|
|
1111
1107
|
runBtn.disabled = true;
|
|
1112
1108
|
status.textContent = "Running...";
|
|
@@ -1124,7 +1120,7 @@ function mountRunner(el, opts = {}) {
|
|
|
1124
1120
|
return;
|
|
1125
1121
|
}
|
|
1126
1122
|
runBtn.disabled = false;
|
|
1127
|
-
opts.onRun?.(result);
|
|
1123
|
+
if (!disposed) opts.onRun?.(result);
|
|
1128
1124
|
};
|
|
1129
1125
|
const onClick = () => {
|
|
1130
1126
|
run();
|
|
@@ -1132,6 +1128,7 @@ function mountRunner(el, opts = {}) {
|
|
|
1132
1128
|
runBtn.addEventListener("click", onClick);
|
|
1133
1129
|
if (opts.autoRun === true) run();
|
|
1134
1130
|
return { dispose() {
|
|
1131
|
+
disposed = true;
|
|
1135
1132
|
runBtn.removeEventListener("click", onClick);
|
|
1136
1133
|
root.remove();
|
|
1137
1134
|
} };
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../src/pipeline.ts","../src/runner.ts","../src/share.ts","../src/scanner.ts","../src/engine.ts","../src/embed.ts","../src/transpile.ts","../src/gallery.ts"],"sourcesContent":["// @sverka/playground — minimal pipeline model. Browser-safe.\n// Mirrors @sverka/workflow Construct API but simplified for browser use.\n\nimport type { PlaygroundFinding } from \"./types.js\";\n\n/** Base class for all constructs. */\nexport abstract class Construct {\n readonly id: string;\n readonly scope: Construct | null;\n\n constructor(scope: Construct | null, id: string) {\n this.id = id;\n this.scope = scope;\n }\n\n /** Full path from root to this construct. */\n get path(): string {\n if (this.scope && this.scope.id !== \"root\") {\n return `${this.scope.path}/${this.id}`;\n }\n return this.id;\n }\n}\n\n/** Root construct representing a project. */\nexport class Project extends Construct {\n readonly pipelines: Pipeline[] = [];\n\n constructor(id: string) {\n super(null, id);\n }\n\n /** Add a pipeline to this project. */\n addPipeline(pipeline: Pipeline): void {\n this.pipelines.push(pipeline);\n }\n}\n\n/** A pipeline containing steps. */\nexport class Pipeline extends Construct {\n readonly steps: Step[] = [];\n readonly entries: Entry[] = [];\n\n constructor(project: Project, id: string) {\n super(project, id);\n project.addPipeline(this);\n }\n\n /** Add a step to this pipeline. */\n addStep(step: Step): void {\n this.steps.push(step);\n }\n\n /** Add an entry to this pipeline. */\n addEntry(entry: Entry): void {\n this.entries.push(entry);\n }\n}\n\n/** Base class for all step types. */\nexport abstract class Step extends Construct {\n readonly dependencies: string[];\n\n constructor(pipeline: Pipeline, id: string, dependencies: string[] = []) {\n super(pipeline, id);\n this.dependencies = dependencies;\n pipeline.addStep(this);\n }\n\n /** Execute this step and return findings. */\n abstract execute(): Promise<PlaygroundFinding[]> | PlaygroundFinding[];\n}\n\n/** A step that runs a JavaScript function in the browser. */\nexport class FunctionStep extends Step {\n readonly fn: () => Promise<PlaygroundFinding[]> | PlaygroundFinding[];\n\n constructor(\n pipeline: Pipeline,\n id: string,\n options: {\n fn: () => Promise<PlaygroundFinding[]> | PlaygroundFinding[];\n dependencies?: string[];\n },\n ) {\n super(pipeline, id, options.dependencies ?? []);\n this.fn = options.fn;\n }\n\n execute(): Promise<PlaygroundFinding[]> | PlaygroundFinding[] {\n return this.fn();\n }\n}\n\n/**\n * Browser stub of the real `@sverka/workflow` ShellStep. Real configs load\n * verbatim in the playground, but a shell command cannot execute in a\n * browser — execute() surfaces an info finding explaining the demo\n * boundary instead of pretending the command ran.\n */\nexport class ShellStep extends Step {\n readonly command: string;\n\n constructor(\n pipeline: Pipeline,\n id: string,\n options: {\n command: string;\n dependsOn?: string[];\n runtime?: unknown;\n outputs?: unknown;\n background?: boolean;\n },\n ) {\n super(pipeline, id, options.dependsOn ?? []);\n this.command = options.command;\n }\n\n execute(): PlaygroundFinding[] {\n return [\n {\n rule: \"playground/shell-step\",\n file: \"sverka.config.ts\",\n line: 1,\n severity: \"info\",\n // The command text is deliberately not echoed — a real command may\n // carry inline secrets, and findings end up in share links.\n message: `'${this.id}' is a shell step — the browser cannot run it. Run the exported config locally to execute it.`,\n },\n ];\n }\n}\n\n/** An entry point that triggers a pipeline. */\nexport class Entry {\n readonly pipeline: Pipeline;\n readonly id: string;\n readonly trigger: { kind: string };\n readonly roots: string[];\n\n constructor(\n pipeline: Pipeline,\n id: string,\n options: { trigger: { kind: string }; roots: string[] },\n ) {\n this.pipeline = pipeline;\n this.id = id;\n this.trigger = options.trigger;\n this.roots = options.roots;\n pipeline.addEntry(this);\n }\n}\n","// @sverka/playground — pipeline runner. Browser-safe.\n// Executes FunctionSteps and collects findings.\n\nimport type { Project } from \"./pipeline.js\";\nimport type { Pipeline } from \"./pipeline.js\";\nimport type { Step } from \"./pipeline.js\";\nimport type {\n Finding,\n PlaygroundFinding,\n PipelineResult,\n StepResult,\n} from \"./types.js\";\n\n/** Simple deterministic hash for fingerprint generation. Browser-safe. */\nfunction simpleHash(input: string): string {\n let hash = 5381;\n for (let i = 0; i < input.length; i++) {\n hash = ((hash << 5) + hash + input.charCodeAt(i)) | 0;\n }\n return (hash >>> 0).toString(16).padStart(8, \"0\");\n}\n\n/** Convert a PlaygroundFinding to a full Finding with fingerprint and id. */\nfunction toFinding(pf: PlaygroundFinding, stepId: string): Finding {\n // Include checkId (stepId) in fingerprint so identical findings from\n // different checks get distinct fingerprints.\n const fingerprintInput = `${stepId}:${pf.rule}:${pf.file}:${pf.line}`;\n const fingerprint = simpleHash(fingerprintInput);\n const id = `${stepId}:${fingerprint}`;\n return {\n id,\n fingerprint,\n checkId: stepId,\n severity: pf.severity,\n confidence: 0.8,\n message: pf.message,\n rule: pf.rule,\n file: pf.file,\n startLine: pf.line,\n endLine: pf.line,\n source: {\n tool: pf.tool ?? stepId,\n version: null,\n format: \"custom\",\n originalRuleId: pf.rule,\n originalSeverity: null,\n },\n ...(pf.snippet ? { snippet: pf.snippet } : {}),\n };\n}\n\n/** Execute a single step and return its result. */\nasync function executeStep(step: Step): Promise<StepResult> {\n const start = Date.now();\n try {\n const playgroundFindings = await step.execute();\n const findings = playgroundFindings.map((pf) => toFinding(pf, step.id));\n return {\n stepId: step.id,\n status: \"success\",\n findings,\n durationMs: Date.now() - start,\n };\n } catch (e) {\n return {\n stepId: step.id,\n status: \"failure\",\n findings: [],\n durationMs: Date.now() - start,\n error: e instanceof Error ? e.message : String(e),\n };\n }\n}\n\n/**\n * Run all FunctionSteps in a project's pipelines and collect findings.\n * Browser-safe — no Node.js APIs, no child_process, no fs.\n *\n * If a pipeline has entries with `roots`, only steps whose id matches a\n * root are executed. If no entries exist or all entries have empty roots,\n * all steps run.\n */\nexport async function runPipeline(project: Project): Promise<PipelineResult> {\n const start = Date.now();\n const stepResults: StepResult[] = [];\n const allFindings: Finding[] = [];\n\n for (const pipeline of project.pipelines) {\n // Determine which steps to run based on entry roots. A root's\n // dependency closure comes along — a step depending on another can't\n // sensibly run without it, and its demo findings belong in the report.\n let stepsToRun = pipeline.steps;\n const entriesWithRoots = pipeline.entries.filter((e) => e.roots.length > 0);\n if (entriesWithRoots.length > 0) {\n const byId = new Map(pipeline.steps.map((s) => [s.id, s]));\n const rootSet = new Set<string>();\n const addWithDeps = (id: string): void => {\n if (rootSet.has(id)) return;\n rootSet.add(id);\n for (const dep of byId.get(id)?.dependencies ?? []) addWithDeps(dep);\n };\n for (const entry of entriesWithRoots) {\n for (const root of entry.roots) addWithDeps(root);\n }\n stepsToRun = pipeline.steps.filter((s) => rootSet.has(s.id));\n }\n\n // Execute all selected steps in parallel — dependencies are for\n // ordering, not data flow in the playground.\n const results = await Promise.all(\n stepsToRun.map((step) => executeStep(step)),\n );\n\n for (const result of results) {\n stepResults.push(result);\n allFindings.push(...result.findings);\n }\n }\n\n return {\n steps: stepResults,\n findings: allFindings,\n totalDurationMs: Date.now() - start,\n success: stepResults.every((s) => s.status === \"success\"),\n };\n}\n","// Share links (Spec 53): a ShareableRun serializes into the URL fragment —\n// `#c=` keeps payloads out of server logs and needs zero backend.\n// Encoding: JSON → deflate-raw → base64url.\n\nimport { deflateSync, Inflate } from \"fflate\";\nimport type { Finding, Severity } from \"./types.js\";\n\nexport interface ShareableRun {\n readonly schema: \"sverka.playground/v1\";\n readonly code: string;\n readonly findings?: readonly Finding[];\n}\n\nexport type PlaygroundErrorCode =\n \"TRANSPILE_FAILED\" | \"DECODE_FAILED\" | \"PAYLOAD_TOO_LARGE\";\n\nexport class PlaygroundError extends Error {\n readonly code: PlaygroundErrorCode;\n constructor(code: PlaygroundErrorCode, message: string) {\n super(message);\n this.name = \"PlaygroundError\";\n this.code = code;\n }\n}\n\n/** Fragment lengths are browser-dependent; warn past 32 KB of payload. */\nexport const SHARE_PAYLOAD_WARN_BYTES = 32 * 1024;\n\n/** Encoded payloads past 64 KB sit outside the safe URL-fragment range —\n * a link that long may arrive truncated, so decoding refuses outright. */\nexport const SHARE_PAYLOAD_MAX_BYTES = 64 * 1024;\n\n/** Hard cap on inflated share payloads — a compressed fragment is cheap to\n * craft into a deflate bomb, so decoding refuses past 1 MB of JSON. */\nconst SHARE_MAX_INFLATED_BYTES = 1024 * 1024;\n\nconst SHARE_PREFIX = \"#c=\";\n\nfunction toBase64Url(bytes: Uint8Array): string {\n let bin = \"\";\n for (const b of bytes) bin += String.fromCharCode(b);\n return btoa(bin).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\");\n}\n\nfunction fromBase64Url(text: string): Uint8Array {\n const b64 = text.replace(/-/g, \"+\").replace(/_/g, \"/\");\n // Browser atob() is strict about padding — restore what the encoder\n // stripped. (Node's atob tolerates missing padding, which is why the\n // round-trip test alone did not catch this.)\n const padded = b64 + \"=\".repeat((4 - (b64.length % 4)) % 4);\n const bin = atob(padded);\n const bytes = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);\n return bytes;\n}\n\n/** Inflate with a hard output cap — bounded memory on hostile payloads. */\nfunction inflateBounded(bytes: Uint8Array): Uint8Array {\n const chunks: Uint8Array[] = [];\n let total = 0;\n let overflow = false;\n const inflate = new Inflate((chunk) => {\n total += chunk.length;\n if (total > SHARE_MAX_INFLATED_BYTES) {\n overflow = true;\n return;\n }\n chunks.push(chunk);\n });\n inflate.push(bytes, true);\n if (overflow) {\n throw new PlaygroundError(\n \"PAYLOAD_TOO_LARGE\",\n `share link inflates past ${SHARE_MAX_INFLATED_BYTES} bytes`,\n );\n }\n const out = new Uint8Array(total);\n let offset = 0;\n for (const chunk of chunks) {\n out.set(chunk, offset);\n offset += chunk.length;\n }\n return out;\n}\n\nconst SEVERITIES: readonly string[] = [\n \"info\",\n \"low\",\n \"medium\",\n \"high\",\n \"critical\",\n];\n\nconst FINDING_STRING_FIELDS = [\"rule\", \"file\", \"message\"] as const;\nconst FINDING_NUMBER_FIELDS = [\"startLine\", \"endLine\"] as const;\n\n/** Structural check — a shared finding reaches the HTML report, so every\n * field that gets rendered must be the expected scalar. */\nfunction isFindingShape(v: unknown): v is Finding {\n if (typeof v !== \"object\" || v === null) return false;\n const f = v as Record<string, unknown>;\n if (!FINDING_STRING_FIELDS.every((k) => typeof f[k] === \"string\")) {\n return false;\n }\n if (!SEVERITIES.includes(f.severity as Severity)) return false;\n return FINDING_NUMBER_FIELDS.every(\n (k) => typeof f[k] === \"number\" && Number.isFinite(f[k]),\n );\n}\n\n/** Encode a run into a share link. `base` is the page URL the link targets\n * (`location.origin + location.pathname` at runtime). */\nexport function encodeShareLink(run: ShareableRun, base = \"\"): string {\n const payload = toBase64Url(\n deflateSync(new TextEncoder().encode(JSON.stringify(run))),\n );\n return `${base}${SHARE_PREFIX}${payload}`;\n}\n\n/** Extract the payload tail from a `#c=` fragment or a bare payload. */\nfunction shareFragment(hash: string): string {\n const marker = hash.indexOf(SHARE_PREFIX);\n if (marker >= 0) return hash.slice(marker + SHARE_PREFIX.length);\n return hash.startsWith(\"#\") ? hash.slice(1) : hash;\n}\n\n/** Shape assertion — anything else is a corrupt or hostile payload. */\nfunction assertRunShape(parsed: unknown): asserts parsed is ShareableRun {\n if (\n typeof parsed !== \"object\" ||\n parsed === null ||\n (parsed as ShareableRun).schema !== \"sverka.playground/v1\" ||\n typeof (parsed as ShareableRun).code !== \"string\"\n ) {\n throw new Error(\"payload is not a sverka.playground/v1 run\");\n }\n const findings = (parsed as ShareableRun).findings;\n if (findings === undefined) return;\n if (!Array.isArray(findings) || !findings.every(isFindingShape)) {\n throw new Error(\"payload findings failed shape validation\");\n }\n}\n\n/** Decode a `#c=` fragment back into a ShareableRun. Corrupt, oversized, or\n * shape-invalid payloads throw PlaygroundError — callers fall back to the\n * default template. */\nexport function decodeShareLink(hash: string): ShareableRun {\n try {\n const payload = shareFragment(hash);\n if (payload.length > SHARE_PAYLOAD_MAX_BYTES) {\n throw new PlaygroundError(\n \"PAYLOAD_TOO_LARGE\",\n `share link payload ${payload.length} bytes exceeds ${SHARE_PAYLOAD_MAX_BYTES}`,\n );\n }\n const json = new TextDecoder().decode(\n inflateBounded(fromBase64Url(payload)),\n );\n const parsed: unknown = JSON.parse(json);\n assertRunShape(parsed);\n return parsed;\n } catch (e) {\n if (e instanceof PlaygroundError) throw e;\n throw new PlaygroundError(\n \"DECODE_FAILED\",\n `share link could not be decoded: ${e instanceof Error ? e.message : String(e)}`,\n );\n }\n}\n","// @sverka/playground — shared mini-scanner primitives.\n// Char-class checks instead of regexes (a pattern evaluated against user\n// source is ReDoS surface); every helper is string/comment/regex aware so\n// quoted or literal braces never count as syntax. All scans are linear.\n\n// --- char classes --------------------------------------------------------\n\n/** Non-ASCII whitespace code points beyond the Latin-1 range. */\nconst WS_POINTS = new Set([\n 0xa0, 0x1680, 0x2028, 0x2029, 0x202f, 0x205f, 0x3000, 0xfeff,\n]);\n\n/** Whitespace per the JS grammar: \\t \\n \\v \\f \\r space, NBSP, the unicode\n * space separators (0x2000–0x200a), and ZWNBSP. */\nexport function isWsChar(c: string | undefined): boolean {\n if (c === undefined) return false;\n const n = c.codePointAt(0) ?? 0;\n if ((n >= 9 && n <= 13) || n === 32) return true;\n return (n >= 0x2000 && n <= 0x200a) || WS_POINTS.has(n);\n}\n\n/** ASCII letter-or-digit — digits and both letter cases. */\nfunction isAsciiLetterOrDigit(n: number): boolean {\n return (n >= 48 && n <= 57) || (n >= 65 && n <= 90) || (n >= 97 && n <= 122);\n}\n\n/** Identifier-part chars, approximated: ASCII ident chars plus any\n * non-ASCII char that isn't JS whitespace — `export` + a non-ASCII\n * letter keeps its boundary. Over-approximation only ever suppresses\n * a false keyword match — it never corrupts code. */\nexport function isIdentChar(c: string | undefined): boolean {\n if (c === undefined) return false;\n const n = c.codePointAt(0) ?? 0;\n if (n >= 0x80) return !isWsChar(c);\n return isAsciiLetterOrDigit(n) || c === \"_\" || c === \"$\";\n}\n\nexport function isQuote(c: string | undefined): boolean {\n return c === '\"' || c === \"'\" || c === \"`\";\n}\n\n// --- skips ---------------------------------------------------------------\n\nexport function skipIdent(code: string, i: number): number {\n while (i < code.length && isIdentChar(code[i])) i++;\n return i;\n}\n\n/** Index of the `\\n` ending the `//` comment at `at` (code.length if none). */\nexport function lineCommentEnd(code: string, at: number): number {\n const end = code.indexOf(\"\\n\", at + 2);\n return end === -1 ? code.length : end;\n}\n\n/** Index just past the closing star-slash ending the block comment at\n * `at` — the literal marker is never written inside this doc comment\n * or it would terminate the comment itself. */\nexport function blockCommentEnd(code: string, at: number): number {\n const end = code.indexOf(\"*/\", at + 2);\n return end === -1 ? code.length : end + 2;\n}\n\n/** True when `at` starts a `//` or `/*` comment. */\nexport function commentAt(code: string, at: number): boolean {\n return code[at] === \"/\" && (code[at + 1] === \"/\" || code[at + 1] === \"*\");\n}\n\n/** True when `at` opens a string literal or a comment. */\nexport function isOpaqueStart(code: string, at: number): boolean {\n return isQuote(code[at]) || commentAt(code, at);\n}\n\n/** Bound on `${}`-in-template nesting. Each level costs a scanString ↔\n * scanTemplateExpr recursion hop, so a crafted source (e.g. a share-link\n * payload) with pathological nesting could exhaust the call stack. Past\n * the cap the template is treated as unterminated — the tail is opaque\n * and the scan degrades gracefully instead of crashing. */\nconst MAX_TEMPLATE_DEPTH = 200;\n\n/** End index of the string literal starting at `at` (quote char).\n * Template literals may nest `${}` expressions — tracked by brace depth\n * up to MAX_TEMPLATE_DEPTH, where the scan bails to code.length. */\nexport function scanString(code: string, at: number, depth = 0): number {\n const quote = code[at];\n let i = at + 1;\n while (i < code.length) {\n const c = code[i];\n if (c === \"\\\\\") {\n i += 2;\n continue;\n }\n if (c === quote) return i + 1;\n if (quote === \"`\" && c === \"$\" && code[i + 1] === \"{\") {\n if (depth >= MAX_TEMPLATE_DEPTH) return code.length;\n i = scanTemplateExpr(code, i + 1, depth + 1);\n continue;\n }\n i++;\n }\n return i;\n}\n\n/** End index of a regex literal starting at `at` (`/`): closes at the\n * first unescaped `/` outside a `[]` class, then consumes flags. Stops at\n * a newline or EOF when unterminated — the evaluator reports the syntax. */\nexport function scanRegex(code: string, at: number): number {\n let i = at + 1;\n let inClass = false;\n while (i < code.length) {\n const c = code[i];\n if (c === \"\\\\\") {\n i += 2;\n continue;\n }\n if (c === \"[\") inClass = true;\n else if (c === \"]\") inClass = false;\n else if (c === \"/\" && !inClass) return skipIdent(code, i + 1);\n else if (c === \"\\n\") return i;\n i++;\n }\n return i;\n}\n\n/** End index of the opaque region at `i`, or i+1 for ordinary chars —\n * plus whether the region was a string literal (an operand). */\nexport function scanOpaqueEnd(\n code: string,\n i: number,\n depth = 0,\n): { end: number; isString: boolean } {\n const c = code[i];\n if (isQuote(c)) return { end: scanString(code, i, depth), isString: true };\n if (c === \"/\" && code[i + 1] === \"/\")\n return { end: lineCommentEnd(code, i), isString: false };\n if (c === \"/\" && code[i + 1] === \"*\")\n return { end: blockCommentEnd(code, i), isString: false };\n return { end: i + 1, isString: false };\n}\n\n/** Keywords and contextual keywords after which `/` opens a regex rather\n * than divides. Everything else — plain identifiers plus literals such\n * as `this`/`true` — ends an operand, making `/` a division. */\nconst NON_OPERAND_WORDS = new Set([\n \"await\",\n \"break\",\n \"case\",\n \"catch\",\n \"class\",\n \"const\",\n \"continue\",\n \"debugger\",\n \"default\",\n \"delete\",\n \"do\",\n \"else\",\n \"enum\",\n \"export\",\n \"extends\",\n \"finally\",\n \"for\",\n \"function\",\n \"if\",\n \"implements\",\n \"import\",\n \"in\",\n \"instanceof\",\n \"interface\",\n \"let\",\n \"new\",\n \"package\",\n \"private\",\n \"protected\",\n \"public\",\n \"return\",\n \"static\",\n \"switch\",\n \"throw\",\n \"try\",\n \"typeof\",\n \"var\",\n \"void\",\n \"while\",\n \"with\",\n \"yield\",\n \"as\",\n \"async\",\n \"from\",\n \"get\",\n \"of\",\n \"set\",\n \"type\",\n \"declare\",\n]);\n\n/** True when `word` ends an operand — a following `/` is division. */\nexport function operandAfterWord(word: string): boolean {\n return !NON_OPERAND_WORDS.has(word);\n}\n\ninterface TokenStep {\n /** Index just past the consumed token. */\n end: number;\n /** Whether the token ends an operand — a following `/` divides. */\n operandEnd: boolean;\n /** +1 for `{`, −1 for `}`, 0 otherwise. */\n brace: -1 | 0 | 1;\n}\n\n/** Consume one token at `i` for the brace-matching scans: opaque regions\n * and regex literals advance wholesale, identifiers update operand\n * state from the keyword table, braces report a depth delta. */\nfunction scanToken(\n code: string,\n i: number,\n operandEnd: boolean,\n depth = 0,\n): TokenStep {\n const opaque = scanOpaqueEnd(code, i, depth);\n if (opaque.end > i + 1) {\n return {\n end: opaque.end,\n operandEnd: opaque.isString || operandEnd,\n brace: 0,\n };\n }\n const ch = code[i];\n if (ch === \"/\" && !operandEnd) {\n return { end: scanRegex(code, i), operandEnd: true, brace: 0 };\n }\n if (isWsChar(ch)) return { end: i + 1, operandEnd, brace: 0 };\n if (isIdentChar(ch)) {\n const wend = skipIdent(code, i);\n return {\n end: wend,\n operandEnd: operandAfterWord(code.slice(i, wend)),\n brace: 0,\n };\n }\n if (ch === \"{\") return { end: i + 1, operandEnd: false, brace: 1 };\n if (ch === \"}\") return { end: i + 1, operandEnd: true, brace: -1 };\n return { end: i + 1, operandEnd: false, brace: 0 };\n}\n\n/**\n * Scan one operand-context token — an opaque span, a regex-or-division,\n * or an identifier run — returning where it ends and whether it leaves\n * an operand behind. Comments are transparent (operand context passes\n * through unchanged). Returns null for punctuation/whitespace the\n * caller's own loop owns.\n */\nexport function scanOperand(\n code: string,\n i: number,\n operandEnd: boolean,\n): { end: number; operandEnd: boolean } | null {\n const opaque = scanOpaqueEnd(code, i);\n if (opaque.end > i + 1)\n return { end: opaque.end, operandEnd: operandEnd || opaque.isString };\n const c = code[i];\n if (c === \"/\")\n return operandEnd\n ? { end: i + 1, operandEnd: false }\n : { end: scanRegex(code, i), operandEnd: true };\n if (isIdentChar(c)) {\n const wend = skipIdent(code, i);\n return {\n end: wend,\n operandEnd: operandAfterWord(code.slice(i, wend)),\n };\n }\n return null;\n}\n\n/**\n * End index of the `${` expression whose `{` is at `at`. Strings,\n * comments, nested templates, and regex literals inside the expression\n * are all skipped correctly: `` `${ x[\"`\"] }` `` and `` `${ /\"/ }` ``\n * must not treat literal text as syntax.\n */\nexport function scanTemplateExpr(code: string, at: number, depth = 0): number {\n let braces = 1;\n let i = at + 1;\n let operandEnd = false;\n while (i < code.length && braces > 0) {\n const step = scanToken(code, i, operandEnd, depth);\n braces += step.brace;\n operandEnd = step.operandEnd;\n i = step.end;\n }\n return i;\n}\n\n/**\n * Index of the `}` matching the `{` at `open`; -1 when unbalanced.\n * Operand tracking decides whether a `/` divides or opens a regex —\n * braces inside `/[{]/` never reach the depth counter.\n */\nexport function matchBrace(code: string, open: number): number {\n let depth = 0;\n let i = open;\n let operandEnd = false;\n while (i < code.length) {\n const step = scanToken(code, i, operandEnd);\n depth += step.brace;\n operandEnd = step.operandEnd;\n i = step.end;\n if (step.brace === -1 && depth === 0) return i - 1;\n }\n return -1;\n}\n\n/** `word` starting at `at` with an identifier boundary on the right. */\nexport function keywordAt(code: string, at: number, word: string): boolean {\n return code.startsWith(word, at) && !isIdentChar(code[at + word.length]);\n}\n\n/** Skip whitespace and comments (including newlines). */\nexport function skipTrivia(code: string, at: number): number {\n let i = at;\n for (;;) {\n const c = code[i];\n if (isWsChar(c)) {\n i++;\n continue;\n }\n if (c === \"/\" && code[i + 1] === \"/\") {\n i = lineCommentEnd(code, i);\n continue;\n }\n if (c === \"/\" && code[i + 1] === \"*\") {\n i = blockCommentEnd(code, i);\n continue;\n }\n return i;\n }\n}\n","// @sverka/playground — shared engine plumbing. Browser-safe.\n// Code template, user-code evaluation, and a timeout-wrapped run used by\n// both the full playground app and the embeddable mountRunner.\n\nimport {\n Project,\n Pipeline,\n FunctionStep,\n ShellStep,\n Entry,\n} from \"./pipeline.js\";\nimport { runPipeline } from \"./runner.js\";\nimport {\n commentAt,\n isIdentChar,\n isWsChar,\n keywordAt,\n matchBrace,\n operandAfterWord,\n scanOpaqueEnd,\n scanRegex,\n scanString,\n skipIdent,\n skipTrivia,\n} from \"./scanner.js\";\n\n/** Trigger helpers mirroring @sverka/workflow — real configs use\n * `trigger: push()`/`manual()`/`schedule()`/`changeRequest()`. The\n * optional filter argument is preserved, not silently discarded —\n * `push({ branches: [\"main\"] })` keeps its restriction. */\nconst push = (filter?: Record<string, unknown>) => ({\n kind: \"push\",\n ...filter,\n});\nconst changeRequest = (filter?: Record<string, unknown>) => ({\n kind: \"changeRequest\",\n ...filter,\n});\nconst manual = (filter?: Record<string, unknown>) => ({\n kind: \"manual\",\n ...filter,\n});\nconst schedule = (cron: string, timezone?: string) => ({\n kind: \"schedule\",\n cron,\n ...(timezone ? { timezone } : {}),\n});\n\n/** Default template shown in the editor. */\nexport const DEFAULT_CODE = [\n 'import { Project, Pipeline, FunctionStep, Entry } from \"@sverka/playground\";',\n \"\",\n 'const proj = new Project(\"demo\");',\n 'const checks = new Pipeline(proj, \"checks\");',\n \"\",\n 'new FunctionStep(checks, \"lint\", {',\n \" fn: () => [\",\n ' { rule: \"no-unused-vars\", file: \"src/index.ts\", line: 5, severity: \"high\", message: \"Variable \\'x\\' is declared but never used\" },',\n ' { rule: \"no-console\", file: \"src/utils.ts\", line: 12, severity: \"medium\", message: \"Unexpected console.log statement\" },',\n \" ],\",\n \"});\",\n \"\",\n 'new FunctionStep(checks, \"typecheck\", {',\n \" fn: () => [\",\n ' { rule: \"ts2322\", file: \"src/types.ts\", line: 8, severity: \"critical\", message: \"Type \\'string\\' is not assignable to type \\'number\\'\" },',\n \" ],\",\n \"});\",\n \"\",\n 'new FunctionStep(checks, \"test\", {',\n \" fn: () => [\",\n ' { rule: \"assertion-failed\", file: \"test/index.test.ts\", line: 23, severity: \"high\", message: \"Expected 5 but got 3\" },',\n ' { rule: \"assertion-failed\", file: \"test/index.test.ts\", line: 45, severity: \"low\", message: \"Expected \\'hello\\' but got \\'world\\'\" },',\n \" ],\",\n \"});\",\n \"\",\n 'new Entry(checks, \"on-push\", { trigger: { kind: \"push\" }, roots: [\"test\"] });',\n \"\",\n \"export default proj;\",\n \"\",\n].join(\"\\n\");\n\n/** Escape HTML special characters to prevent XSS. */\nexport function escapeHtml(text: string): string {\n return text\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n}\n\n/** +1/−1 for bracket chars, 0 otherwise. */\nfunction bracketDelta(c: string | undefined): number {\n if (c === \"{\" || c === \"(\" || c === \"[\") return 1;\n if (c === \"}\" || c === \")\" || c === \"]\") return -1;\n return 0;\n}\n\n/** Chars that end an import statement at depth ≤0: `;` (consumed) or a\n * newline after the module-specifier string (left in place). */\nfunction stmtTerminator(\n c: string | undefined,\n depth: number,\n specSeen: boolean,\n): \"past\" | \"at\" | null {\n if (c === \";\" && depth <= 0) return \"past\";\n if (c === \"\\n\" && depth <= 0 && specSeen) return \"at\";\n return null;\n}\n\n/** End index of the statement starting at `at`: first top-level `;`, or\n * the first newline after the module-specifier string (covers multiline\n * `import {…}\\n from \"x\"` and `import \"x\"` without a semicolon). */\nfunction scanStatementEnd(code: string, at: number): number {\n let i = at;\n let depth = 0;\n let specSeen = false;\n while (i < code.length) {\n const opaque = scanOpaqueEnd(code, i);\n if (opaque.end > i + 1) {\n specSeen = specSeen || opaque.isString;\n i = opaque.end;\n continue;\n }\n const term = stmtTerminator(code[i], depth, specSeen);\n if (term === \"past\") return i + 1;\n if (term === \"at\") return i;\n depth += bracketDelta(code[i]);\n i++;\n }\n return i;\n}\n\n/** Same-line statement tail: horizontal whitespace then an optional `;`.\n * Never eats the newline — the following line is the next statement. */\nfunction scanStmtTail(code: string, at: number): number {\n let i = at;\n while (i < code.length && (code[i] === \" \" || code[i] === \"\\t\")) i++;\n if (code[i] === \";\") i++;\n return i;\n}\n\n/** End index of the `from \"…\"` clause starting after `from`, or `at` when\n * the clause is malformed — let the evaluator complain. */\nfunction scanFromClause(code: string, next: number): number {\n const specAt = skipTrivia(code, next + 4);\n const q = code[specAt];\n if (q === '\"' || q === \"'\") {\n return scanStmtTail(code, scanString(code, specAt));\n }\n return next;\n}\n\n/** End index of `export * [as ns] [from \"…\"]` — the `*` is at `at`. */\nfunction scanExportStar(code: string, at: number): number {\n let i = skipTrivia(code, at + 1);\n if (keywordAt(code, i, \"as\")) {\n i = skipTrivia(code, i + 2);\n i = skipIdent(code, i);\n }\n const next = skipTrivia(code, i);\n if (keywordAt(code, next, \"from\")) return scanFromClause(code, next);\n return scanStmtTail(code, i);\n}\n\n/**\n * End index of `export {…}` / `export * [as ns] [from \"…\"]` starting at\n * the `{` or `*`. A bare list ends at its `;` or newline — unlike an\n * import, a newline after the closing brace must end the statement or\n * the next line would be eaten with it.\n */\nfunction scanExportListEnd(code: string, at: number): number {\n if (code[at] === \"*\") return scanExportStar(code, at);\n const close = matchBrace(code, at);\n const i = close < 0 ? code.length : close + 1;\n const next = skipTrivia(code, i);\n if (keywordAt(code, next, \"from\")) return scanFromClause(code, next);\n return scanStmtTail(code, i);\n}\n\ninterface ScanState {\n i: number;\n stmtStart: boolean;\n exportDefaultDone: boolean;\n /** `block` vs `expr` — separates block braces from object literals, so\n * `{ export: 1 }` is a key, not a statement. */\n stack: (\"block\" | \"expr\")[];\n /** True when the previous token ended an operand — `/` then divides.\n * Regex literals never update the delimiter stack, so `/[{]/` can't\n * leave an unclosed `{` that keeps `export default` alive to eval. */\n operandEnd: boolean;\n}\n\nfunction atStmtLevel(st: ScanState): boolean {\n return st.stack.length === 0 || st.stack.at(-1) === \"block\";\n}\n\n/** Copy a string literal or comment verbatim into `out`. */\nfunction copyOpaque(code: string, st: ScanState, out: string[]): boolean {\n const opaque = scanOpaqueEnd(code, st.i);\n if (opaque.end <= st.i + 1) return false;\n out.push(code.slice(st.i, opaque.end));\n if (opaque.isString) {\n st.stmtStart = false;\n st.operandEnd = true;\n }\n st.i = opaque.end;\n return true;\n}\n\n/** Handle `{}`/`()`/`[]` — pushes onto the block/expr stack and sets the\n * operand context: `}` closing an object literal ends a value, `}`\n * closing a block ends a statement. */\nfunction applyBracket(code: string, st: ScanState, out: string[]): boolean {\n const c = code[st.i];\n if (c === \"{\") {\n // A `{` at statement position opens a block; anywhere else it's an\n // object literal. Inside a block the next token is a statement;\n // inside an object it's a key — `export:` there is not a keyword.\n st.stack.push(st.stmtStart ? \"block\" : \"expr\");\n st.operandEnd = false;\n } else if (c === \"}\") {\n const popped = st.stack.pop();\n st.stmtStart = popped === \"block\";\n st.operandEnd = popped === \"expr\";\n } else if (c === \"(\" || c === \"[\") {\n st.stack.push(\"expr\");\n st.stmtStart = false;\n st.operandEnd = false;\n } else if (c === \")\" || c === \"]\") {\n st.stack.pop();\n st.stmtStart = false;\n st.operandEnd = true;\n } else {\n return false;\n }\n out.push(c ?? \"\");\n st.i++;\n return true;\n}\n\n/** Handle `\\n`, `;`, and whitespace — statement boundaries at statement\n * level only (a `;` inside `for (;;)` doesn't count). A newline never\n * resets operand context: `foo\\n/bar/` divides, per ASI rules. */\nfunction applyTerminator(code: string, st: ScanState, out: string[]): boolean {\n const c = code[st.i];\n if (c !== \";\" && c !== \"\\n\" && !isWsChar(c)) return false;\n if (c === \";\") {\n if (atStmtLevel(st)) st.stmtStart = true;\n st.operandEnd = false;\n } else if (c === \"\\n\" && atStmtLevel(st)) {\n st.stmtStart = true;\n }\n out.push(c ?? \"\");\n st.i++;\n return true;\n}\n\n/** Handle `/` — a regex literal when an operand is expected, a division\n * operator when one just ended. Comments never reach here (copyOpaque\n * already consumed them). */\nfunction applySlash(code: string, st: ScanState, out: string[]): boolean {\n if (code[st.i] !== \"/\" || commentAt(code, st.i)) return false;\n if (st.operandEnd) {\n out.push(\"/\");\n st.i++;\n st.operandEnd = false;\n } else {\n const end = scanRegex(code, st.i);\n out.push(code.slice(st.i, end));\n st.i = end;\n st.operandEnd = true;\n }\n st.stmtStart = false;\n return true;\n}\n\n/** Handle an `import` keyword at statement start. Dynamic `import (…)`\n * and `import.meta` pass through verbatim — whitespace and comments may\n * sit between the keyword and the paren. */\nfunction tryImport(code: string, st: ScanState, out: string[]): boolean {\n if (!st.stmtStart || !keywordAt(code, st.i, \"import\")) return false;\n const nc = code[skipTrivia(code, st.i + 6)];\n if (nc === \"(\" || nc === \".\") {\n out.push(\"import\");\n st.i += 6;\n st.stmtStart = false;\n st.operandEnd = true;\n return true;\n }\n st.i = scanStatementEnd(code, st.i + 6);\n st.stmtStart = false;\n st.operandEnd = false;\n return true;\n}\n\n/** Handle `export default` (→ `return`), `export {…}`/`export *` (removed)\n * and `export <decl>` (keyword dropped — the eval context is a function\n * body, where `export const` would be a syntax error). */\nfunction tryExport(code: string, st: ScanState, out: string[]): boolean {\n if (!st.stmtStart || !keywordAt(code, st.i, \"export\")) return false;\n const j = skipTrivia(code, st.i + 6);\n if (\n !st.exportDefaultDone &&\n code.startsWith(\"default\", j) &&\n !isIdentChar(code[j + 7])\n ) {\n // `return` must touch the expression — a newline between `default`\n // and the value would trigger ASI and return undefined.\n out.push(\"return \");\n st.exportDefaultDone = true;\n st.i = skipTrivia(code, j + 7);\n st.stmtStart = false;\n st.operandEnd = false;\n return true;\n }\n if (code[j] === \"{\" || code[j] === \"*\") {\n st.i = scanExportListEnd(code, j);\n st.stmtStart = false;\n st.operandEnd = false;\n return true;\n }\n st.i = j;\n st.stmtStart = false;\n st.operandEnd = false;\n return true;\n}\n\n/** Emit an identifier run — keyword table decides whether `/` after it\n * divides (`foo /x/`) or opens a regex (`return /x/`). */\nfunction tryWord(code: string, st: ScanState, out: string[]): boolean {\n if (!isIdentChar(code[st.i])) return false;\n const wend = skipIdent(code, st.i);\n out.push(code.slice(st.i, wend));\n st.operandEnd = operandAfterWord(code.slice(st.i, wend));\n st.stmtStart = false;\n st.i = wend;\n return true;\n}\n\n/** Char handlers tried in order — first true wins. Any char left over is\n * copied verbatim as a non-operand punctuation token. */\nconst HANDLERS: ((code: string, st: ScanState, out: string[]) => boolean)[] = [\n copyOpaque,\n applyBracket,\n applyTerminator,\n applySlash,\n tryImport,\n tryExport,\n tryWord,\n];\n\nfunction advanceScan(code: string, st: ScanState, out: string[]): void {\n for (const handle of HANDLERS) {\n if (handle(code, st, out)) return;\n }\n st.stmtStart = false;\n st.operandEnd = false;\n out.push(code[st.i] ?? \"\");\n st.i++;\n}\n\n/**\n * Strip import/export statements from user code for eval — a linear\n * single-pass scan, so multiline imports and comments/strings are handled\n * and pathological spacing cannot cause quadratic backtracking.\n *\n * `import …` statements are removed whole. `export default` becomes\n * `return`, `export {…}`/`export *` are removed, and `export` before a\n * declaration is dropped (the eval context is a function body, where\n * `export const` would be a syntax error).\n *\n * Note: TypeScript-specific syntax (type annotations, interfaces, enums)\n * is not stripped — the playground uses Monaco's TypeScript language mode\n * for editing, but evaluation is plain JavaScript. Users should write\n * JS-compatible code or use the `as any` escape hatch sparingly.\n */\nexport function preprocessCode(code: string): string {\n const out: string[] = [];\n const st: ScanState = {\n i: 0,\n stmtStart: true,\n exportDefaultDone: false,\n stack: [],\n operandEnd: false,\n };\n while (st.i < code.length) {\n if (code[st.i] === undefined) break;\n advanceScan(code, st, out);\n }\n return out.join(\"\");\n}\n\n/**\n * Evaluate user code and return the Project.\n *\n * SECURITY: This uses `new Function()` to execute user-provided code.\n * This is intentional — the playground is a local development tool where\n * the user writes and runs their own pipeline code. The code runs in the\n * browser's main page context (not a sandboxed iframe or worker) because\n * the playground needs to support synchronous FunctionStep execution and\n * direct access to the pipeline constructs. This is the same trust model\n * as a local REPL or `node -e`.\n */\nexport function evaluateUserCode(code: string): Project {\n const processed = preprocessCode(code);\n // Dynamic code execution is intentional for the playground sandbox.\n // SonarCloud S1523: safe — user code runs in the browser sandbox with the\n // same trust model as a local REPL or `node -e` (see comment above).\n const params = [\n \"Project\",\n \"Pipeline\",\n \"FunctionStep\",\n \"ShellStep\",\n \"Entry\",\n \"push\",\n \"changeRequest\",\n \"manual\",\n \"schedule\",\n processed,\n ];\n // NOSONAR suppresses only issues on the marker's own line — it must\n // trail the `new Function` callee, not sit inside the argument list.\n const fn = new Function(...params); // NOSONAR — intentional dynamic evaluation in sandbox\n const fnArgs = [\n Project,\n Pipeline,\n FunctionStep,\n ShellStep,\n Entry,\n push,\n changeRequest,\n manual,\n schedule,\n ];\n // NOSONAR suppresses only issues on the marker's own line — it must\n // trail the `fn(...)` invocation, not sit inside an argument list.\n const result = fn(...fnArgs); // NOSONAR — intentional dynamic evaluation in sandbox\n if (!(result instanceof Project)) {\n throw new TypeError(\"Code must export a Project instance\");\n }\n return result as Project;\n}\n\n/**\n * Run a pipeline with a timeout. If a step returns a never-resolving\n * promise, the timeout ensures the UI recovers instead of staying\n * stuck in \"Running\" state forever.\n */\nexport async function runPipelineWithTimeout(\n project: Project,\n timeoutMs: number,\n): Promise<Awaited<ReturnType<typeof runPipeline>>> {\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n return await Promise.race([\n runPipeline(project),\n new Promise<never>((_, reject) => {\n timer = setTimeout(\n () => reject(new Error(`Pipeline timed out after ${timeoutMs}ms`)),\n timeoutMs,\n );\n }),\n ]);\n } finally {\n // Without this, every completed run leaves a live timer that rejects\n // into an unhandled rejection timeoutMs later.\n if (timer !== undefined) clearTimeout(timer);\n }\n}\n","// @sverka/playground — mountRunner embed API (Spec 53).\n// Docs pages mount a self-contained runner: code (editable or readonly),\n// a Run button, status line, and a findings iframe. Zero backend — the\n// runner evaluates pipeline code in-page under the same trust model as\n// the full playground (see engine.ts).\n\nimport { generateSarifHtml } from \"@sverka/sarif-viewer-web/html-generator\";\nimport type { PipelineResult } from \"./types.js\";\nimport {\n DEFAULT_CODE,\n escapeHtml,\n evaluateUserCode,\n runPipelineWithTimeout,\n} from \"./engine.js\";\n\nexport interface MountRunnerOptions {\n /** Initial editor source. Defaults to the playground template. */\n readonly code?: string;\n /** Render the source as a fixed listing instead of an editable field. */\n readonly readonly?: boolean;\n /** Run `code` immediately on mount. Defaults to false — embed code may\n * come from a share link or CMS, so mounting never executes it unless\n * the embedder opts in or the user clicks Run. */\n readonly autoRun?: boolean;\n /** Called once per completed run. */\n readonly onRun?: (result: PipelineResult) => void;\n}\n\nexport interface MountedRunner {\n /** Remove the runner's DOM and listeners. */\n dispose(): void;\n}\n\nconst STYLE = `\n font-family: monospace; font-size: 12px;\n background: #0d1117; color: #c9d1d9;\n border: 1px solid #30363d; border-radius: 6px;\n display: flex; flex-direction: column; overflow: hidden;\n`;\n\nfunction createHeader(doc: Document): {\n header: HTMLElement;\n runBtn: HTMLButtonElement;\n status: HTMLSpanElement;\n} {\n const header = doc.createElement(\"div\");\n header.setAttribute(\n \"style\",\n \"display:flex;align-items:center;gap:0.5rem;padding:0.4rem 0.6rem;background:#161b22;border-bottom:1px solid #30363d;\",\n );\n const runBtn = doc.createElement(\"button\");\n runBtn.textContent = \"Run\";\n runBtn.setAttribute(\n \"style\",\n \"padding:0.2rem 0.8rem;border:1px solid #30363d;border-radius:6px;background:#1f6feb;color:#fff;cursor:pointer;font-size:0.8rem;\",\n );\n const status = doc.createElement(\"span\");\n status.setAttribute(\"style\", \"font-size:0.75rem;color:#8b949e;\");\n status.textContent = \"Ready\";\n header.append(runBtn, status);\n return { header, runBtn, status };\n}\n\nfunction createCodeEl(\n doc: Document,\n code: string,\n readonly: boolean,\n): HTMLTextAreaElement | HTMLElement {\n if (readonly) {\n const pre = doc.createElement(\"pre\");\n pre.setAttribute(\n \"style\",\n \"margin:0;padding:0.75rem;overflow:auto;max-height:16rem;white-space:pre;\",\n );\n pre.textContent = code;\n return pre;\n }\n const textarea = doc.createElement(\"textarea\");\n textarea.value = code;\n textarea.setAttribute(\n \"style\",\n \"flex:0 0 12rem;width:100%;background:#0d1117;color:#c9d1d9;border:none;border-bottom:1px solid #30363d;padding:0.75rem;resize:vertical;outline:none;font:inherit;\",\n );\n return textarea;\n}\n\nfunction createFrame(doc: Document): HTMLIFrameElement {\n const frame = doc.createElement(\"iframe\");\n // Shared findings render via srcdoc — sandboxed onto an opaque origin so a\n // crafted payload can never touch the host page; allow-scripts keeps the\n // report's own viewer interactivity (search/filter/sort) working.\n frame.setAttribute(\"sandbox\", \"allow-scripts\");\n frame.setAttribute(\n \"style\",\n \"flex:1;min-height:10rem;width:100%;border:none;background:#0d1117;\",\n );\n return frame;\n}\n\nconst BODY_DARK =\n '<body style=\"background:#0d1117;font-family:monospace;padding:1rem;';\n\n/** Failure banner HTML — string concat keeps user data flowing through\n * escapeHtml explicitly, never through template interpolation. */\nfunction failureBanner(result: PipelineResult): string {\n const failed = result.steps.filter((s) => s.status === \"failure\");\n const lines =\n failed.map((s) => `${s.stepId}: ${s.error ?? \"failed\"}`).join(\"\\n\") ||\n `${result.steps.length} steps failed`;\n return [\n '<div style=\"background:#3d1d1f;color:#f85149;padding:0.6rem 1rem;font-family:monospace;border-bottom:1px solid #30363d;\">',\n \"<strong>Run failed</strong>\",\n '<pre style=\"margin:0.4rem 0 0;white-space:pre-wrap;\">',\n escapeHtml(lines),\n \"</pre></div>\",\n ].join(\"\");\n}\n\n/** Document shown when the run failed — partial findings still render\n * underneath the banner so finished steps aren't hidden by the error. */\nfunction failureDoc(result: PipelineResult, banner: string): string {\n if (result.findings.length === 0) {\n return (\n \"<!DOCTYPE html><html>\" +\n BODY_DARK +\n 'color:#f85149;\">' +\n banner +\n \"</body></html>\"\n );\n }\n const sarif = generateSarifHtml(result.findings);\n return sarif.includes(\"<body>\")\n ? sarif.replace(\"<body>\", \"<body>\" + banner)\n : banner + sarif;\n}\n\n/** Document shown for a clean run with zero findings. */\nfunction successDoc(result: PipelineResult): string {\n return [\n \"<!DOCTYPE html><html>\",\n BODY_DARK,\n 'color:#3fb950;\">',\n \"<h3>No findings — all checks passed</h3><p>\",\n escapeHtml(String(result.steps.length)),\n \" steps in \",\n escapeHtml(String(result.totalDurationMs)),\n \"ms</p></body></html>\",\n ].join(\"\");\n}\n\n/** Document shown when the runner itself threw (eval or pipeline error). */\nfunction errorDoc(e: unknown): string {\n const msg = e instanceof Error ? e.message : String(e);\n return [\n \"<!DOCTYPE html><html>\",\n BODY_DARK,\n 'color:#f85149;\">',\n \"<h3>Error</h3><pre>\",\n escapeHtml(msg),\n \"</pre></body></html>\",\n ].join(\"\");\n}\n\nfunction statusLine(result: PipelineResult): string {\n if (result.success)\n return `${result.findings.length} findings · ${result.totalDurationMs}ms`;\n const failures = result.steps.filter((s) => s.status === \"failure\").length;\n return `${failures} step(s) failed · ${result.findings.length} findings`;\n}\n\n/** Render a completed run into the findings frame. */\nfunction renderResult(\n result: PipelineResult,\n showFindings: (html: string) => void,\n): void {\n if (!result.success) {\n showFindings(failureDoc(result, failureBanner(result)));\n return;\n }\n if (result.findings.length === 0) {\n showFindings(successDoc(result));\n return;\n }\n showFindings(generateSarifHtml(result.findings));\n}\n\n/**\n * Mount a self-contained runner inside `el`. `dispose()` tears the mount\n * down. With `autoRun: true` the runner executes `code` once on mount;\n * otherwise it waits for the Run button — embeds never auto-execute code\n * the embedder didn't explicitly allow.\n */\nexport function mountRunner(\n el: HTMLElement,\n opts: MountRunnerOptions = {},\n): MountedRunner {\n const doc = el.ownerDocument;\n const code = opts.code ?? DEFAULT_CODE;\n\n const root = doc.createElement(\"div\");\n root.setAttribute(\"style\", STYLE);\n const { header, runBtn, status } = createHeader(doc);\n const codeEl = createCodeEl(doc, code, opts.readonly === true);\n const frame = createFrame(doc);\n root.append(header, codeEl, frame);\n el.appendChild(root);\n\n // Branch on the option, not instanceof — a container owned by another\n // window would produce a cross-realm textarea that fails the check.\n const getCode = (): string =>\n opts.readonly === true ? code : (codeEl as HTMLTextAreaElement).value;\n\n const run = async (): Promise<void> => {\n runBtn.disabled = true;\n status.textContent = \"Running...\";\n let result: PipelineResult;\n try {\n const project = evaluateUserCode(getCode());\n result = await runPipelineWithTimeout(project, 30_000);\n renderResult(result, (html) => {\n frame.srcdoc = html;\n });\n status.textContent = statusLine(result);\n } catch (e) {\n frame.srcdoc = errorDoc(e);\n status.textContent = \"Error\";\n runBtn.disabled = false;\n return;\n }\n runBtn.disabled = false;\n // Outside the try — a throwing callback must not corrupt the findings\n // view or get misreported as a runner failure.\n opts.onRun?.(result);\n };\n\n const onClick = (): void => {\n void run();\n };\n runBtn.addEventListener(\"click\", onClick);\n if (opts.autoRun === true) void run();\n\n return {\n dispose() {\n runBtn.removeEventListener(\"click\", onClick);\n root.remove();\n },\n };\n}\n","// @sverka/playground — toSverkaConfig (Spec 53): the \"take it home\" bridge.\n// Converts playground source into a real sverka.config.ts: the authoring\n// surface (Project/Pipeline/Entry/roots) transfers verbatim — only the step\n// kind differs. FunctionStep bodies cannot run as shell commands, so each\n// becomes a ShellStep carrying a placeholder echo the user replaces.\n\nimport { PlaygroundError } from \"./share.js\";\nimport {\n isIdentChar,\n isOpaqueStart,\n isWsChar,\n keywordAt,\n matchBrace,\n scanOpaqueEnd,\n scanOperand,\n scanString,\n skipIdent,\n} from \"./scanner.js\";\n\n// --- local char helpers (only transpile needs these) ----------------------\n\nfunction isOpenBracket(c: string | undefined): boolean {\n return c === \"{\" || c === \"[\" || c === \"(\";\n}\n\nfunction isCloseBracket(c: string | undefined): boolean {\n return c === \"}\" || c === \"]\" || c === \")\";\n}\n\nfunction skipWs(code: string, i: number): number {\n while (i < code.length && isWsChar(code[i])) i++;\n return i;\n}\n\n// ---------------------------------------------------------------------------\n// Every matcher below is string-, comment-, and regex-literal-aware via the\n// shared scanner — braces inside `/[{]/` or quotes never count as syntax,\n// and all scans are linear (no regexes over user source at all).\n// ---------------------------------------------------------------------------\n\n/** One token of an operand-tracking scan — identifiers (with `word`),\n * opaque spans, and regex-vs-division resolve through the shared\n * scanner; whitespace passes through. Null when `i` sits on\n * punctuation the caller's own depth/branch logic owns. */\nfunction propToken(\n s: string,\n i: number,\n operandEnd: boolean,\n): { end: number; operandEnd: boolean; word?: string } | null {\n if (isWsChar(s[i])) return { end: i + 1, operandEnd };\n const op = scanOperand(s, i, operandEnd);\n if (op === null) return null;\n if (isIdentChar(s[i])) return { ...op, word: s.slice(i, op.end) };\n return op;\n}\n\n/** Apply a bracket/other punctuation char to depth + operand state. */\nfunction applyPunctuation(\n c: string | undefined,\n st: { depth: number; operandEnd: boolean },\n): void {\n if (isOpenBracket(c)) {\n st.depth++;\n st.operandEnd = false;\n } else if (isCloseBracket(c)) {\n st.depth--;\n st.operandEnd = true;\n } else {\n st.operandEnd = false;\n }\n}\n\n/**\n * Index of the `:` following a depth-0 `key` in a props object body, or -1.\n * A `dependencies` declared inside `fn` never counts — only top-level keys.\n */\nfunction findPropKey(props: string, key: string): number {\n const st = { depth: 0, operandEnd: false };\n let i = 0;\n while (i < props.length) {\n const tok = propToken(props, i, st.operandEnd);\n if (tok === null) {\n applyPunctuation(props[i], st);\n i++;\n continue;\n }\n if (st.depth === 0 && tok.word === key) {\n const hit = skipWs(props, tok.end);\n if (props[hit] === \":\") return hit;\n }\n st.operandEnd = tok.operandEnd;\n i = tok.end;\n }\n return -1;\n}\n\n/** True when the comment at `k` is a top-level tail comment — `deps: [] //\n * note` — and therefore not part of the value. Emitting it would comment\n * out the generated `}` after `dependsOn: <value>`. */\nfunction isTailComment(props: string, k: number, after: number): boolean {\n const ahead = skipWs(props, after);\n return ahead >= props.length || props[ahead] === \",\";\n}\n\n/** End index of a prop value starting at `j` — the next top-level comma\n * or the end of the props body, with strings/comments/brackets balanced. */\nfunction propValueEnd(props: string, j: number): number {\n const st = { depth: 0, operandEnd: false };\n let k = j;\n while (k < props.length) {\n if (isOpaqueStart(props, k)) {\n const after = scanOpaqueEnd(props, k).end;\n if (st.depth === 0 && isTailComment(props, k, after)) return k;\n k = after;\n continue;\n }\n const tok = propToken(props, k, st.operandEnd);\n if (tok !== null) {\n st.operandEnd = tok.operandEnd;\n k = tok.end;\n continue;\n }\n if (props[k] === \",\" && st.depth === 0) return k;\n applyPunctuation(props[k], st);\n k++;\n }\n return k;\n}\n\n/**\n * Extract a top-level `key: <value>` span from a props object body.\n * Only depth-0 keys match — a `dependencies` declared inside `fn` never\n * counts. The value runs to the next top-level `,`, with strings,\n * comments, and nested brackets all balanced.\n */\nfunction extractProp(props: string, key: string): string | undefined {\n const colon = findPropKey(props, key);\n if (colon < 0) return undefined;\n const j = skipWs(props, colon + 1);\n return props.slice(j, propValueEnd(props, j)).trim();\n}\n\n/** Consume trailing spaces/tabs plus one optional `;` — never the newline.\n * Eating it would fuse the emitted import with the next line\n * (`from \"@sverka/workflow\"const x = …`). */\nfunction stmtEndPos(source: string, i: number): number {\n let end = i;\n while (source[end] === \" \" || source[end] === \"\\t\") end++;\n if (source[end] === \";\") end++;\n return end;\n}\n\n/** Parse one import specifier: `Name` or `Name as alias`. */\nfunction parseImportSpec(spec: string): { orig: string; local: string } {\n const a = skipWs(spec, 0);\n const wend = skipIdent(spec, a);\n const orig = spec.slice(a, wend);\n const asPos = skipWs(spec, wend);\n if (!spec.startsWith(\"as\", asPos) || isIdentChar(spec[asPos + 2])) {\n return { orig, local: orig };\n }\n const b = skipWs(spec, asPos + 2);\n const local = spec.slice(b, skipIdent(spec, b));\n return local === \"\" ? { orig, local: orig } : { orig, local };\n}\n\ninterface MappedImports {\n mapped: string;\n fnStepLocals: string[];\n}\n\n/** Map `{…}` import specifiers; FunctionStep becomes ShellStep (aliases\n * survive: `FunctionStep as Fn` → `ShellStep as Fn`). */\nfunction mapImportSpecifiers(inner: string): MappedImports {\n const mapped: string[] = [];\n const fnStepLocals: string[] = [];\n for (const spec of inner.split(\",\")) {\n const trimmed = spec.trim();\n if (trimmed === \"\") continue;\n const { orig, local } = parseImportSpec(trimmed);\n if (orig === \"FunctionStep\") {\n fnStepLocals.push(local);\n mapped.push(orig === local ? \"ShellStep\" : `ShellStep as ${local}`);\n } else {\n mapped.push(trimmed);\n }\n }\n return { mapped: mapped.join(\", \"), fnStepLocals };\n}\n\ninterface PlaygroundImport {\n stmtEnd: number;\n mapped: string;\n fnStepLocals: string[];\n}\n\n/** Parse `import {…} from \"@sverka/playground\"` at `i`, or null when the\n * statement has another shape/module. Caller guarantees \"import\" at `i`. */\nfunction parsePlaygroundImport(\n source: string,\n i: number,\n): PlaygroundImport | null {\n const j = skipWs(source, i + 6);\n if (source[j] !== \"{\") return null;\n const namesEnd = matchBrace(source, j);\n if (namesEnd < 0) return null;\n const fromKw = skipWs(source, namesEnd + 1);\n if (!keywordAt(source, fromKw, \"from\")) return null;\n const qPos = skipWs(source, fromKw + 4);\n const q = source[qPos];\n if (q !== '\"' && q !== \"'\") return null;\n const specEnd = scanString(source, qPos);\n if (source.slice(qPos + 1, specEnd - 1) !== \"@sverka/playground\") return null;\n const { mapped, fnStepLocals } = mapImportSpecifiers(\n source.slice(j + 1, namesEnd),\n );\n return { stmtEnd: stmtEndPos(source, specEnd), mapped, fnStepLocals };\n}\n\n/**\n * Rewrite `import {…} from \"@sverka/playground\"` statements linearly.\n *\n * Returns the rewritten source plus every local name bound to\n * FunctionStep, so constructor calls under an alias are transpiled too.\n */\nfunction rewritePlaygroundImports(source: string): {\n code: string;\n fnStepNames: string[];\n} {\n const fnStepNames: string[] = [];\n let out = \"\";\n let cursor = 0;\n let i = 0;\n while (i < source.length) {\n const end = scanOpaqueEnd(source, i).end;\n if (end > i + 1) {\n i = end;\n continue;\n }\n if (source.startsWith(\"import\", i) && !isIdentChar(source[i + 6])) {\n const stmt = parsePlaygroundImport(source, i);\n if (stmt !== null) {\n out += source.slice(cursor, i);\n out += `import { ${stmt.mapped} } from \"@sverka/workflow\"`;\n if (source[stmt.stmtEnd - 1] === \";\") out += \";\";\n fnStepNames.push(...stmt.fnStepLocals);\n cursor = stmt.stmtEnd;\n i = stmt.stmtEnd;\n continue;\n }\n }\n i++;\n }\n return { code: out + source.slice(cursor), fnStepNames };\n}\n\n/** Index of `(` after `new <name>` where <name> ∈ names, or null. */\nfunction stepCallParen(\n code: string,\n afterNew: number,\n names: readonly string[],\n): number | null {\n const j = skipWs(code, afterNew);\n for (const name of names) {\n const next = code[j + name.length];\n if (code.startsWith(name, j) && !isIdentChar(next)) {\n const paren = skipWs(code, j + name.length);\n if (code[paren] === \"(\") return paren;\n }\n }\n return null;\n}\n\n/** Operand context after punctuation — closers end a value, everything\n * else (openers, operators, separators) expects one. */\nfunction punctuationOperandEnd(c: string | undefined): boolean {\n return c === \")\" || c === \"]\" || c === \"}\";\n}\n\n/**\n * Locate the next `new <name>(` call where <name> ∈ names. Whole-word\n * scanning makes boundary checks free — `myNew` or `newer` never match.\n * Opaque regions and regex literals are skipped inline, so a\n * `new FunctionStep(` inside a comment, string, or `/new Fn(/` pattern\n * is documentation, not a call.\n */\nfunction findStepCall(\n code: string,\n names: readonly string[],\n from: number,\n): { start: number; paren: number } | null {\n let operandEnd = false;\n let i = from;\n while (i < code.length) {\n const tok = propToken(code, i, operandEnd);\n if (tok !== null) {\n if (tok.word === \"new\") {\n const paren = stepCallParen(code, tok.end, names);\n if (paren !== null) return { start: i, paren };\n }\n operandEnd = tok.operandEnd;\n i = tok.end;\n continue;\n }\n operandEnd = punctuationOperandEnd(code[i]);\n i++;\n }\n return null;\n}\n\n/** End of the scope expression — the first top-level comma after `from`,\n * or -1 when the argument list closes/ends first. */\nfunction scanScopeEnd(code: string, from: number): number {\n const st = { depth: 0, operandEnd: false };\n let k = from;\n while (k < code.length) {\n const tok = propToken(code, k, st.operandEnd);\n if (tok !== null) {\n st.operandEnd = tok.operandEnd;\n k = tok.end;\n continue;\n }\n const c = code[k];\n if (c === \",\" && st.depth === 0) return k;\n if (isCloseBracket(c) && st.depth === 0) return -1;\n applyPunctuation(c, st);\n k++;\n }\n return -1;\n}\n\ninterface StepArgs {\n scope: string;\n id: string;\n propsOpen: number;\n}\n\n/** Parse `(scope, \"id\", {` after the `(` at `paren`; null when the call\n * shape differs. A template id throws immediately — never half-converts. */\nfunction parseStepArgs(code: string, paren: number): StepArgs | null {\n const scopeStart = skipWs(code, paren + 1);\n const comma = scanScopeEnd(code, scopeStart);\n if (comma < 0) return null;\n const qPos = skipWs(code, comma + 1);\n const q = code[qPos];\n if (q === \"`\")\n throw new PlaygroundError(\n \"TRANSPILE_FAILED\",\n \"cannot parse FunctionStep — template-literal step id\",\n );\n if (q !== '\"' && q !== \"'\") return null;\n const idEnd = scanString(code, qPos);\n const afterId = skipWs(code, idEnd);\n if (code[afterId] !== \",\") return null;\n const propsOpen = skipWs(code, afterId + 1);\n if (code[propsOpen] !== \"{\") return null;\n return {\n scope: code.slice(scopeStart, comma).trim(),\n id: code.slice(qPos + 1, idEnd - 1),\n propsOpen,\n };\n}\n\n/** Emit the ShellStep placeholder replacing one FunctionStep call. */\nfunction shellStepCall(args: StepArgs, dependencies: string | undefined) {\n // The id lands inside shell single quotes — $()/backticks can never\n // expand. `'` is already impossible (the id is a plain string literal).\n return (\n `new ShellStep(${args.scope}, \"${args.id}\", ` +\n `{ command: \"echo 'TODO: port '${args.id}' — replace with the real shell command'\"` +\n (dependencies !== undefined ? \", dependsOn: \" + dependencies : \"\") +\n \" }\"\n );\n}\n\n/** Rewrite every `new Fn(scope, \"id\", {…})` call under the given local\n * names into ShellStep placeholders; `dependencies` → `dependsOn`. */\nfunction rewriteStepCalls(code: string, names: readonly string[]): string {\n let result = \"\";\n let cursor = 0;\n for (;;) {\n const call = findStepCall(code, names, cursor);\n if (call === null) break;\n const args = parseStepArgs(code, call.paren);\n if (args === null) {\n // A `new Fn(` whose shape we don't own — skip `new` and let the\n // leftover check name it, rather than silently dropping it.\n result += code.slice(cursor, call.start + 3);\n cursor = call.start + 3;\n continue;\n }\n const propsClose = matchBrace(code, args.propsOpen);\n if (propsClose < 0)\n throw new PlaygroundError(\n \"TRANSPILE_FAILED\",\n `cannot parse FunctionStep \"${args.id}\" — unbalanced props object`,\n );\n const dependencies = extractProp(\n code.slice(args.propsOpen + 1, propsClose),\n \"dependencies\",\n );\n result +=\n code.slice(cursor, call.start) + shellStepCall(args, dependencies);\n cursor = propsClose + 1;\n }\n return result + code.slice(cursor);\n}\n\n/** A surviving step call means a shape we could not convert — computed\n * scope/id or a malformed alias call. Fail loud rather than emit a\n * half-converted file. */\nfunction assertNoLeftoverSteps(code: string, names: readonly string[]): void {\n const call = findStepCall(code, names, 0);\n if (call === null) return;\n const scopeStart = skipWs(code, call.paren + 1);\n const scopeEnd = scanScopeEnd(code, scopeStart);\n const scope =\n scopeEnd < 0 ? \"?\" : code.slice(scopeStart, scopeEnd).trim() || \"?\";\n throw new PlaygroundError(\n \"TRANSPILE_FAILED\",\n `cannot parse FunctionStep with scope '${scope}' — unsupported expression`,\n );\n}\n\n/**\n * Transpile playground source into `sverka.config.ts`.\n *\n * Rewrites the `@sverka/playground` import to `@sverka/workflow` and each\n * `new FunctionStep(scope, \"id\", { fn, dependencies })` into a ShellStep\n * whose command echoes a placeholder — the function body has no shell\n * equivalent.\n * `dependencies` maps onto `dependsOn`. Aliased FunctionStep imports\n * (`FunctionStep as Fn`) are followed too.\n *\n * Throws `PlaygroundError(TRANSPILE_FAILED)` naming the offending step when\n * a FunctionStep cannot be parsed — a half-converted file is never emitted.\n */\nexport function toSverkaConfig(source: string): string {\n const { code, fnStepNames } = rewritePlaygroundImports(source);\n if (fnStepNames.length === 0) fnStepNames.push(\"FunctionStep\");\n const out = rewriteStepCalls(code, fnStepNames);\n assertNoLeftoverSteps(out, fnStepNames);\n return out;\n}\n","// @sverka/playground — examples gallery (Spec 53).\n// `examples/*/` mini-projects are bundled at build time by the vite entry\n// (app.ts collects them via import.meta.glob) — the picker needs no\n// network access. This module stays bundler-agnostic so the library\n// build (tsdown) never sees vite-only APIs.\n\nexport interface GalleryExample {\n /** Directory name, e.g. \"failing-checks\". */\n readonly id: string;\n /** Humanized label for the picker. */\n readonly title: string;\n /** sverka.config.ts source, bundled into the playground build. */\n readonly code: string;\n}\n\nfunction toTitle(id: string): string {\n return id\n .split(\"-\")\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1))\n .join(\" \");\n}\n\n/** Turn a `{ \"<path>/examples/<id>/sverka.config.ts\": source }` map into a\n * sorted picker list. */\nexport function listExamples(\n modules: Record<string, string>,\n): readonly GalleryExample[] {\n return Object.entries(modules)\n .map(([path, code]) => {\n const id =\n /examples\\/([^/]+)\\/sverka\\.config\\.ts$/.exec(path)?.[1] ?? path;\n return { id, title: toTitle(id), code };\n })\n .sort((a, b) => a.id.localeCompare(b.id));\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/pipeline.ts","../src/runner.ts","../src/share.ts","../src/scanner.ts","../src/engine.ts","../src/embed.ts","../src/transpile.ts","../src/gallery.ts"],"sourcesContent":["// @sverka/playground — minimal pipeline model. Browser-safe.\n// Mirrors @sverka/workflow Construct API but simplified for browser use.\n\nimport type { PlaygroundFinding } from \"./types.js\";\n\n/** Base class for all constructs. */\nexport abstract class Construct {\n readonly id: string;\n readonly scope: Construct | null;\n\n constructor(scope: Construct | null, id: string) {\n this.id = id;\n this.scope = scope;\n }\n\n /** Full path from root to this construct. */\n get path(): string {\n if (this.scope && this.scope.id !== \"root\") {\n return `${this.scope.path}/${this.id}`;\n }\n return this.id;\n }\n}\n\n/** Root construct representing a project. */\nexport class Project extends Construct {\n readonly pipelines: Pipeline[] = [];\n\n constructor(id: string) {\n super(null, id);\n }\n\n /** Add a pipeline to this project. */\n addPipeline(pipeline: Pipeline): void {\n this.pipelines.push(pipeline);\n }\n}\n\n/** A pipeline containing steps. */\nexport class Pipeline extends Construct {\n readonly steps: Step[] = [];\n readonly entries: Entry[] = [];\n\n constructor(project: Project, id: string) {\n super(project, id);\n project.addPipeline(this);\n }\n\n /** Add a step to this pipeline. */\n addStep(step: Step): void {\n this.steps.push(step);\n }\n\n /** Add an entry to this pipeline. */\n addEntry(entry: Entry): void {\n this.entries.push(entry);\n }\n}\n\n/** Base class for all step types. */\nexport abstract class Step extends Construct {\n readonly dependencies: string[];\n\n constructor(pipeline: Pipeline, id: string, dependencies: string[] = []) {\n super(pipeline, id);\n this.dependencies = dependencies;\n pipeline.addStep(this);\n }\n\n /** Execute this step and return findings. */\n abstract execute(): Promise<PlaygroundFinding[]> | PlaygroundFinding[];\n}\n\n/** A step that runs a JavaScript function in the browser. */\nexport class FunctionStep extends Step {\n readonly fn: () => Promise<PlaygroundFinding[]> | PlaygroundFinding[];\n\n constructor(\n pipeline: Pipeline,\n id: string,\n options: {\n fn: () => Promise<PlaygroundFinding[]> | PlaygroundFinding[];\n dependencies?: string[];\n },\n ) {\n super(pipeline, id, options.dependencies ?? []);\n this.fn = options.fn;\n }\n\n execute(): Promise<PlaygroundFinding[]> | PlaygroundFinding[] {\n return this.fn();\n }\n}\n\n/**\n * Browser stub of the real `@sverka/workflow` ShellStep. Real configs load\n * verbatim in the playground, but a shell command cannot execute in a\n * browser — execute() surfaces an info finding explaining the demo\n * boundary instead of pretending the command ran.\n */\nexport class ShellStep extends Step {\n readonly command: string;\n\n constructor(\n pipeline: Pipeline,\n id: string,\n options: {\n command: string;\n dependsOn?: string[];\n runtime?: unknown;\n outputs?: unknown;\n background?: boolean;\n },\n ) {\n super(pipeline, id, options.dependsOn ?? []);\n this.command = options.command;\n }\n\n execute(): PlaygroundFinding[] {\n return [\n {\n rule: \"playground/shell-step\",\n file: \"sverka.config.ts\",\n line: 1,\n severity: \"info\",\n // The command text is deliberately not echoed — a real command may\n // carry inline secrets, and findings end up in share links.\n message: `'${this.id}' is a shell step — the browser cannot run it. Run the exported config locally to execute it.`,\n },\n ];\n }\n}\n\n/** An entry point that triggers a pipeline. */\nexport class Entry {\n readonly pipeline: Pipeline;\n readonly id: string;\n readonly trigger: { kind: string };\n readonly roots: string[];\n\n constructor(\n pipeline: Pipeline,\n id: string,\n options: { trigger: { kind: string }; roots: string[] },\n ) {\n this.pipeline = pipeline;\n this.id = id;\n this.trigger = options.trigger;\n this.roots = options.roots;\n pipeline.addEntry(this);\n }\n}\n","// @sverka/playground — pipeline runner. Browser-safe.\n// Executes FunctionSteps and collects findings.\n\nimport type { Project } from \"./pipeline.js\";\nimport type { Pipeline } from \"./pipeline.js\";\nimport type { Step } from \"./pipeline.js\";\nimport type {\n Finding,\n PlaygroundFinding,\n PipelineResult,\n StepResult,\n} from \"./types.js\";\n\n/** Simple deterministic hash for fingerprint generation. Browser-safe. */\nfunction simpleHash(input: string): string {\n let hash = 5381;\n for (let i = 0; i < input.length; i++) {\n hash = ((hash << 5) + hash + input.charCodeAt(i)) | 0;\n }\n return (hash >>> 0).toString(16).padStart(8, \"0\");\n}\n\n/** Convert a PlaygroundFinding to a full Finding with fingerprint and id. */\nfunction toFinding(pf: PlaygroundFinding, stepId: string): Finding {\n // Include checkId (stepId) in fingerprint so identical findings from\n // different checks get distinct fingerprints.\n const fingerprintInput = `${stepId}:${pf.rule}:${pf.file}:${pf.line}`;\n const fingerprint = simpleHash(fingerprintInput);\n const id = `${stepId}:${fingerprint}`;\n return {\n id,\n fingerprint,\n checkId: stepId,\n severity: pf.severity,\n confidence: 0.8,\n message: pf.message,\n rule: pf.rule,\n file: pf.file,\n startLine: pf.line,\n endLine: pf.line,\n source: {\n tool: pf.tool ?? stepId,\n version: null,\n format: \"custom\",\n originalRuleId: pf.rule,\n originalSeverity: null,\n },\n ...(pf.snippet ? { snippet: pf.snippet } : {}),\n };\n}\n\n/** Execute a single step and return its result. */\nasync function executeStep(step: Step): Promise<StepResult> {\n const start = Date.now();\n try {\n const playgroundFindings = await step.execute();\n const findings = playgroundFindings.map((pf) => toFinding(pf, step.id));\n return {\n stepId: step.id,\n status: \"success\",\n findings,\n durationMs: Date.now() - start,\n };\n } catch (e) {\n return {\n stepId: step.id,\n status: \"failure\",\n findings: [],\n durationMs: Date.now() - start,\n error: e instanceof Error ? e.message : String(e),\n };\n }\n}\n\n/**\n * Run all FunctionSteps in a project's pipelines and collect findings.\n * Browser-safe — no Node.js APIs, no child_process, no fs.\n *\n * If a pipeline has entries with `roots`, only steps whose id matches a\n * root are executed. If no entries exist or all entries have empty roots,\n * all steps run.\n */\nexport async function runPipeline(project: Project): Promise<PipelineResult> {\n const start = Date.now();\n const stepResults: StepResult[] = [];\n const allFindings: Finding[] = [];\n\n for (const pipeline of project.pipelines) {\n // Determine which steps to run based on entry roots. A root's\n // dependency closure comes along — a step depending on another can't\n // sensibly run without it, and its demo findings belong in the report.\n let stepsToRun = pipeline.steps;\n const entriesWithRoots = pipeline.entries.filter((e) => e.roots.length > 0);\n if (entriesWithRoots.length > 0) {\n const byId = new Map(pipeline.steps.map((s) => [s.id, s]));\n const rootSet = new Set<string>();\n const addWithDeps = (id: string): void => {\n if (rootSet.has(id)) return;\n rootSet.add(id);\n for (const dep of byId.get(id)?.dependencies ?? []) addWithDeps(dep);\n };\n for (const entry of entriesWithRoots) {\n for (const root of entry.roots) addWithDeps(root);\n }\n stepsToRun = pipeline.steps.filter((s) => rootSet.has(s.id));\n }\n\n // Execute all selected steps in parallel — dependencies are for\n // ordering, not data flow in the playground.\n const results = await Promise.all(\n stepsToRun.map((step) => executeStep(step)),\n );\n\n for (const result of results) {\n stepResults.push(result);\n allFindings.push(...result.findings);\n }\n }\n\n return {\n steps: stepResults,\n findings: allFindings,\n totalDurationMs: Date.now() - start,\n success: stepResults.every((s) => s.status === \"success\"),\n };\n}\n","// Share links (Spec 53): a ShareableRun serializes into the URL fragment —\n// `#c=` keeps payloads out of server logs and needs zero backend.\n// Encoding: JSON → deflate-raw → base64url.\n\nimport { deflateSync, Inflate } from \"fflate\";\nimport type { Finding, Severity } from \"./types.js\";\n\nexport interface ShareableRun {\n readonly schema: \"sverka.playground/v1\";\n readonly code: string;\n readonly findings?: readonly Finding[];\n}\n\nexport type PlaygroundErrorCode =\n \"TRANSPILE_FAILED\" | \"DECODE_FAILED\" | \"PAYLOAD_TOO_LARGE\";\n\nexport class PlaygroundError extends Error {\n readonly code: PlaygroundErrorCode;\n constructor(code: PlaygroundErrorCode, message: string) {\n super(message);\n this.name = \"PlaygroundError\";\n this.code = code;\n }\n}\n\n/** Fragment lengths are browser-dependent; warn past 32 KB of payload. */\nexport const SHARE_PAYLOAD_WARN_BYTES = 32 * 1024;\n\n/** Encoded payloads past 64 KB sit outside the safe URL-fragment range —\n * a link that long may arrive truncated, so decoding refuses outright. */\nexport const SHARE_PAYLOAD_MAX_BYTES = 64 * 1024;\n\n/** Hard cap on inflated share payloads — a compressed fragment is cheap to\n * craft into a deflate bomb, so decoding refuses past 1 MB of JSON. */\nconst SHARE_MAX_INFLATED_BYTES = 1024 * 1024;\n\nconst SHARE_PREFIX = \"#c=\";\n\nfunction toBase64Url(bytes: Uint8Array): string {\n let bin = \"\";\n for (const b of bytes) bin += String.fromCharCode(b);\n return btoa(bin).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\");\n}\n\nfunction fromBase64Url(text: string): Uint8Array {\n const b64 = text.replace(/-/g, \"+\").replace(/_/g, \"/\");\n // Browser atob() is strict about padding — restore what the encoder\n // stripped. (Node's atob tolerates missing padding, which is why the\n // round-trip test alone did not catch this.)\n const padded = b64 + \"=\".repeat((4 - (b64.length % 4)) % 4);\n const bin = atob(padded);\n const bytes = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);\n return bytes;\n}\n\n/** Inflate with a hard output cap — bounded memory on hostile payloads. */\nfunction inflateBounded(bytes: Uint8Array): Uint8Array {\n const chunks: Uint8Array[] = [];\n let total = 0;\n let overflow = false;\n const inflate = new Inflate((chunk) => {\n total += chunk.length;\n if (total > SHARE_MAX_INFLATED_BYTES) {\n overflow = true;\n return;\n }\n chunks.push(chunk);\n });\n inflate.push(bytes, true);\n if (overflow) {\n throw new PlaygroundError(\n \"PAYLOAD_TOO_LARGE\",\n `share link inflates past ${SHARE_MAX_INFLATED_BYTES} bytes`,\n );\n }\n const out = new Uint8Array(total);\n let offset = 0;\n for (const chunk of chunks) {\n out.set(chunk, offset);\n offset += chunk.length;\n }\n return out;\n}\n\nconst SEVERITIES: readonly string[] = [\n \"info\",\n \"low\",\n \"medium\",\n \"high\",\n \"critical\",\n];\n\nconst FINDING_STRING_FIELDS = [\"rule\", \"file\", \"message\"] as const;\nconst FINDING_NUMBER_FIELDS = [\"startLine\", \"endLine\"] as const;\n\n/** Structural check — a shared finding reaches the HTML report, so every\n * field that gets rendered must be the expected scalar. */\nfunction isFindingShape(v: unknown): v is Finding {\n if (typeof v !== \"object\" || v === null) return false;\n const f = v as Record<string, unknown>;\n if (!FINDING_STRING_FIELDS.every((k) => typeof f[k] === \"string\")) {\n return false;\n }\n if (!SEVERITIES.includes(f.severity as Severity)) return false;\n return FINDING_NUMBER_FIELDS.every(\n (k) => typeof f[k] === \"number\" && Number.isFinite(f[k]),\n );\n}\n\n/** Encode a run into a share link. `base` is the page URL the link targets\n * (`location.origin + location.pathname` at runtime). */\nexport function encodeShareLink(run: ShareableRun, base = \"\"): string {\n const payload = toBase64Url(\n deflateSync(new TextEncoder().encode(JSON.stringify(run))),\n );\n return `${base}${SHARE_PREFIX}${payload}`;\n}\n\n/** Extract the payload tail from a `#c=` fragment or a bare payload. */\nfunction shareFragment(hash: string): string {\n const marker = hash.indexOf(SHARE_PREFIX);\n if (marker >= 0) return hash.slice(marker + SHARE_PREFIX.length);\n return hash.startsWith(\"#\") ? hash.slice(1) : hash;\n}\n\n/** Shape assertion — anything else is a corrupt or hostile payload. */\nfunction assertRunShape(parsed: unknown): asserts parsed is ShareableRun {\n if (\n typeof parsed !== \"object\" ||\n parsed === null ||\n (parsed as ShareableRun).schema !== \"sverka.playground/v1\" ||\n typeof (parsed as ShareableRun).code !== \"string\"\n ) {\n throw new Error(\"payload is not a sverka.playground/v1 run\");\n }\n const findings = (parsed as ShareableRun).findings;\n if (findings === undefined) return;\n if (!Array.isArray(findings) || !findings.every(isFindingShape)) {\n throw new Error(\"payload findings failed shape validation\");\n }\n}\n\n/** Decode a `#c=` fragment back into a ShareableRun. Corrupt, oversized, or\n * shape-invalid payloads throw PlaygroundError — callers fall back to the\n * default template. */\nexport function decodeShareLink(hash: string): ShareableRun {\n try {\n const payload = shareFragment(hash);\n if (payload.length > SHARE_PAYLOAD_MAX_BYTES) {\n throw new PlaygroundError(\n \"PAYLOAD_TOO_LARGE\",\n `share link payload ${payload.length} bytes exceeds ${SHARE_PAYLOAD_MAX_BYTES}`,\n );\n }\n const json = new TextDecoder().decode(\n inflateBounded(fromBase64Url(payload)),\n );\n const parsed: unknown = JSON.parse(json);\n assertRunShape(parsed);\n return parsed;\n } catch (e) {\n if (e instanceof PlaygroundError) throw e;\n throw new PlaygroundError(\n \"DECODE_FAILED\",\n `share link could not be decoded: ${e instanceof Error ? e.message : String(e)}`,\n );\n }\n}\n","// @sverka/playground — shared mini-scanner primitives.\n// Char-class checks instead of regexes (a pattern evaluated against user\n// source is ReDoS surface); every helper is string/comment/regex aware so\n// quoted or literal braces never count as syntax. All scans are linear.\n\n// --- char classes --------------------------------------------------------\n\n/** Non-ASCII whitespace code points beyond the Latin-1 range. */\nconst WS_POINTS = new Set([\n 0xa0, 0x1680, 0x2028, 0x2029, 0x202f, 0x205f, 0x3000, 0xfeff,\n]);\n\n/** Whitespace per the JS grammar: \\t \\n \\v \\f \\r space, NBSP, the unicode\n * space separators (0x2000–0x200a), and ZWNBSP. */\nexport function isWsChar(c: string | undefined): boolean {\n if (c === undefined) return false;\n const n = c.codePointAt(0) ?? 0;\n if ((n >= 9 && n <= 13) || n === 32) return true;\n return (n >= 0x2000 && n <= 0x200a) || WS_POINTS.has(n);\n}\n\n/** ASCII letter-or-digit — digits and both letter cases. */\nfunction isAsciiLetterOrDigit(n: number): boolean {\n return (n >= 48 && n <= 57) || (n >= 65 && n <= 90) || (n >= 97 && n <= 122);\n}\n\n/** Identifier-part chars, approximated: ASCII ident chars plus any\n * non-ASCII char that isn't JS whitespace — `export` + a non-ASCII\n * letter keeps its boundary. Over-approximation only ever suppresses\n * a false keyword match — it never corrupts code. */\nexport function isIdentChar(c: string | undefined): boolean {\n if (c === undefined) return false;\n const n = c.codePointAt(0) ?? 0;\n if (n >= 0x80) return !isWsChar(c);\n return isAsciiLetterOrDigit(n) || c === \"_\" || c === \"$\";\n}\n\nexport function isQuote(c: string | undefined): boolean {\n return c === '\"' || c === \"'\" || c === \"`\";\n}\n\n// --- skips ---------------------------------------------------------------\n\nexport function skipIdent(code: string, i: number): number {\n while (i < code.length && isIdentChar(code[i])) i++;\n return i;\n}\n\n/** Index of the `\\n` ending the `//` comment at `at` (code.length if none). */\nexport function lineCommentEnd(code: string, at: number): number {\n const end = code.indexOf(\"\\n\", at + 2);\n return end === -1 ? code.length : end;\n}\n\n/** Index just past the closing star-slash ending the block comment at\n * `at` — the literal marker is never written inside this doc comment\n * or it would terminate the comment itself. */\nexport function blockCommentEnd(code: string, at: number): number {\n const end = code.indexOf(\"*/\", at + 2);\n return end === -1 ? code.length : end + 2;\n}\n\n/** True when `at` starts a `//` or `/*` comment. */\nexport function commentAt(code: string, at: number): boolean {\n return code[at] === \"/\" && (code[at + 1] === \"/\" || code[at + 1] === \"*\");\n}\n\n/** True when `at` opens a string literal or a comment. */\nexport function isOpaqueStart(code: string, at: number): boolean {\n return isQuote(code[at]) || commentAt(code, at);\n}\n\n/** Bound on `${}`-in-template nesting. Each level costs a scanString ↔\n * scanTemplateExpr recursion hop, so a crafted source (e.g. a share-link\n * payload) with pathological nesting could exhaust the call stack. Past\n * the cap the template is treated as unterminated — the tail is opaque\n * and the scan degrades gracefully instead of crashing. */\nconst MAX_TEMPLATE_DEPTH = 200;\n\n/** End index of the string literal starting at `at` (quote char).\n * Template literals may nest `${}` expressions — tracked by brace depth\n * up to MAX_TEMPLATE_DEPTH, where the scan bails to code.length. */\nexport function scanString(code: string, at: number, depth = 0): number {\n const quote = code[at];\n let i = at + 1;\n while (i < code.length) {\n const c = code[i];\n if (c === \"\\\\\") {\n i += 2;\n continue;\n }\n if (c === quote) return i + 1;\n if (quote === \"`\" && c === \"$\" && code[i + 1] === \"{\") {\n if (depth >= MAX_TEMPLATE_DEPTH) return code.length;\n i = scanTemplateExpr(code, i + 1, depth + 1);\n continue;\n }\n i++;\n }\n return i;\n}\n\n/** End index of a regex literal starting at `at` (`/`): closes at the\n * first unescaped `/` outside a `[]` class, then consumes flags. Stops at\n * a newline or EOF when unterminated — the evaluator reports the syntax. */\nexport function scanRegex(code: string, at: number): number {\n let i = at + 1;\n let inClass = false;\n while (i < code.length) {\n const c = code[i];\n if (c === \"\\\\\") {\n i += 2;\n continue;\n }\n if (c === \"[\") inClass = true;\n else if (c === \"]\") inClass = false;\n else if (c === \"/\" && !inClass) return skipIdent(code, i + 1);\n else if (c === \"\\n\") return i;\n i++;\n }\n return i;\n}\n\n/** End index of the opaque region at `i`, or i+1 for ordinary chars —\n * plus whether the region was a string literal (an operand). */\nexport function scanOpaqueEnd(\n code: string,\n i: number,\n depth = 0,\n): { end: number; isString: boolean } {\n const c = code[i];\n if (isQuote(c)) return { end: scanString(code, i, depth), isString: true };\n if (c === \"/\" && code[i + 1] === \"/\")\n return { end: lineCommentEnd(code, i), isString: false };\n if (c === \"/\" && code[i + 1] === \"*\")\n return { end: blockCommentEnd(code, i), isString: false };\n return { end: i + 1, isString: false };\n}\n\n/** Reserved words after which `/` opens a regex rather than divides —\n * they can never end an operand. Contextual keywords (`of`, `as`,\n * `from`, `get`, `set`, `type`, `async`, `declare`) are NOT listed:\n * they act as ordinary identifiers in most positions, so a `/` after\n * them divides. Everything else — plain identifiers plus literals such\n * as `this`/`true` — ends an operand, making `/` a division. */\nconst NON_OPERAND_WORDS = new Set([\n \"await\",\n \"break\",\n \"case\",\n \"catch\",\n \"class\",\n \"const\",\n \"continue\",\n \"debugger\",\n \"default\",\n \"delete\",\n \"do\",\n \"else\",\n \"enum\",\n \"export\",\n \"extends\",\n \"finally\",\n \"for\",\n \"function\",\n \"if\",\n \"implements\",\n \"import\",\n \"in\",\n \"instanceof\",\n \"interface\",\n \"let\",\n \"new\",\n \"package\",\n \"private\",\n \"protected\",\n \"public\",\n \"return\",\n \"static\",\n \"switch\",\n \"throw\",\n \"try\",\n \"typeof\",\n \"var\",\n \"void\",\n \"while\",\n \"with\",\n \"yield\",\n]);\n\n/** True when `word` ends an operand — a following `/` is division. */\nexport function operandAfterWord(word: string): boolean {\n return !NON_OPERAND_WORDS.has(word);\n}\n\ninterface TokenStep {\n /** Index just past the consumed token. */\n end: number;\n /** Whether the token ends an operand — a following `/` divides. */\n operandEnd: boolean;\n /** +1 for `{`, −1 for `}`, 0 otherwise. */\n brace: -1 | 0 | 1;\n}\n\n/** Consume one token at `i` for the brace-matching scans: opaque regions\n * and regex literals advance wholesale, identifiers update operand\n * state from the keyword table, braces report a depth delta. */\nfunction scanToken(\n code: string,\n i: number,\n operandEnd: boolean,\n depth = 0,\n): TokenStep {\n const opaque = scanOpaqueEnd(code, i, depth);\n if (opaque.end > i + 1) {\n return {\n end: opaque.end,\n operandEnd: opaque.isString || operandEnd,\n brace: 0,\n };\n }\n const ch = code[i];\n if (ch === \"/\" && !operandEnd) {\n return { end: scanRegex(code, i), operandEnd: true, brace: 0 };\n }\n if (isWsChar(ch)) return { end: i + 1, operandEnd, brace: 0 };\n if (isIdentChar(ch)) {\n const wend = skipIdent(code, i);\n return {\n end: wend,\n operandEnd: operandAfterWord(code.slice(i, wend)),\n brace: 0,\n };\n }\n if (ch === \"{\") return { end: i + 1, operandEnd: false, brace: 1 };\n if (ch === \"}\") return { end: i + 1, operandEnd: true, brace: -1 };\n return { end: i + 1, operandEnd: false, brace: 0 };\n}\n\n/**\n * Scan one operand-context token — an opaque span, a regex-or-division,\n * or an identifier run — returning where it ends and whether it leaves\n * an operand behind. Comments are transparent (operand context passes\n * through unchanged). Returns null for punctuation/whitespace the\n * caller's own loop owns.\n */\nexport function scanOperand(\n code: string,\n i: number,\n operandEnd: boolean,\n): { end: number; operandEnd: boolean } | null {\n const opaque = scanOpaqueEnd(code, i);\n if (opaque.end > i + 1)\n return { end: opaque.end, operandEnd: operandEnd || opaque.isString };\n const c = code[i];\n if (c === \"/\")\n return operandEnd\n ? { end: i + 1, operandEnd: false }\n : { end: scanRegex(code, i), operandEnd: true };\n if (isIdentChar(c)) {\n const wend = skipIdent(code, i);\n return {\n end: wend,\n operandEnd: operandAfterWord(code.slice(i, wend)),\n };\n }\n return null;\n}\n\n/**\n * End index of the `${` expression whose `{` is at `at`. Strings,\n * comments, nested templates, and regex literals inside the expression\n * are all skipped correctly: `` `${ x[\"`\"] }` `` and `` `${ /\"/ }` ``\n * must not treat literal text as syntax.\n */\nexport function scanTemplateExpr(code: string, at: number, depth = 0): number {\n let braces = 1;\n let i = at + 1;\n let operandEnd = false;\n while (i < code.length && braces > 0) {\n const step = scanToken(code, i, operandEnd, depth);\n braces += step.brace;\n operandEnd = step.operandEnd;\n i = step.end;\n }\n return i;\n}\n\n/**\n * Index of the `}` matching the `{` at `open`; -1 when unbalanced.\n * Operand tracking decides whether a `/` divides or opens a regex —\n * braces inside `/[{]/` never reach the depth counter.\n */\nexport function matchBrace(code: string, open: number): number {\n let depth = 0;\n let i = open;\n let operandEnd = false;\n while (i < code.length) {\n const step = scanToken(code, i, operandEnd);\n depth += step.brace;\n operandEnd = step.operandEnd;\n i = step.end;\n if (step.brace === -1 && depth === 0) return i - 1;\n }\n return -1;\n}\n\n/** `word` starting at `at` with an identifier boundary on the right. */\nexport function keywordAt(code: string, at: number, word: string): boolean {\n return code.startsWith(word, at) && !isIdentChar(code[at + word.length]);\n}\n\n/** Skip whitespace and comments (including newlines). */\nexport function skipTrivia(code: string, at: number): number {\n let i = at;\n for (;;) {\n const c = code[i];\n if (isWsChar(c)) {\n i++;\n continue;\n }\n if (c === \"/\" && code[i + 1] === \"/\") {\n i = lineCommentEnd(code, i);\n continue;\n }\n if (c === \"/\" && code[i + 1] === \"*\") {\n i = blockCommentEnd(code, i);\n continue;\n }\n return i;\n }\n}\n","// @sverka/playground — shared engine plumbing. Browser-safe.\n// Code template, user-code evaluation, and a timeout-wrapped run used by\n// both the full playground app and the embeddable mountRunner.\n\nimport {\n Project,\n Pipeline,\n FunctionStep,\n ShellStep,\n Entry,\n} from \"./pipeline.js\";\nimport { runPipeline } from \"./runner.js\";\nimport {\n commentAt,\n isIdentChar,\n isWsChar,\n keywordAt,\n matchBrace,\n operandAfterWord,\n scanOpaqueEnd,\n scanRegex,\n scanString,\n skipIdent,\n skipTrivia,\n} from \"./scanner.js\";\n\n/** Trigger helpers mirroring @sverka/workflow — real configs use\n * `trigger: push()`/`manual()`/`schedule()`/`changeRequest()`. The\n * optional filter argument is preserved, not silently discarded —\n * `push({ branches: [\"main\"] })` keeps its restriction. */\nconst push = (filter?: Record<string, unknown>) => ({\n kind: \"push\",\n ...filter,\n});\nconst changeRequest = (filter?: Record<string, unknown>) => ({\n kind: \"changeRequest\",\n ...filter,\n});\nconst manual = (filter?: Record<string, unknown>) => ({\n kind: \"manual\",\n ...filter,\n});\nconst schedule = (cron: string, timezone?: string) => ({\n kind: \"schedule\",\n cron,\n ...(timezone ? { timezone } : {}),\n});\n\n/** Default template shown in the editor. */\nexport const DEFAULT_CODE = [\n 'import { Project, Pipeline, FunctionStep, Entry } from \"@sverka/playground\";',\n \"\",\n 'const proj = new Project(\"demo\");',\n 'const checks = new Pipeline(proj, \"checks\");',\n \"\",\n 'new FunctionStep(checks, \"lint\", {',\n \" fn: () => [\",\n ' { rule: \"no-unused-vars\", file: \"src/index.ts\", line: 5, severity: \"high\", message: \"Variable \\'x\\' is declared but never used\" },',\n ' { rule: \"no-console\", file: \"src/utils.ts\", line: 12, severity: \"medium\", message: \"Unexpected console.log statement\" },',\n \" ],\",\n \"});\",\n \"\",\n 'new FunctionStep(checks, \"typecheck\", {',\n \" fn: () => [\",\n ' { rule: \"ts2322\", file: \"src/types.ts\", line: 8, severity: \"critical\", message: \"Type \\'string\\' is not assignable to type \\'number\\'\" },',\n \" ],\",\n \"});\",\n \"\",\n 'new FunctionStep(checks, \"test\", {',\n \" fn: () => [\",\n ' { rule: \"assertion-failed\", file: \"test/index.test.ts\", line: 23, severity: \"high\", message: \"Expected 5 but got 3\" },',\n ' { rule: \"assertion-failed\", file: \"test/index.test.ts\", line: 45, severity: \"low\", message: \"Expected \\'hello\\' but got \\'world\\'\" },',\n \" ],\",\n \"});\",\n \"\",\n 'new Entry(checks, \"on-push\", { trigger: { kind: \"push\" }, roots: [\"test\"] });',\n \"\",\n \"export default proj;\",\n \"\",\n].join(\"\\n\");\n\n/** Escape HTML special characters to prevent XSS. */\nexport function escapeHtml(text: string): string {\n return text\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n}\n\n/** +1/−1 for bracket chars, 0 otherwise. */\nfunction bracketDelta(c: string | undefined): number {\n if (c === \"{\" || c === \"(\" || c === \"[\") return 1;\n if (c === \"}\" || c === \")\" || c === \"]\") return -1;\n return 0;\n}\n\n/** Chars that end an import statement at depth ≤0: `;` (consumed) or a\n * newline after the module-specifier string (left in place). */\nfunction stmtTerminator(\n c: string | undefined,\n depth: number,\n specSeen: boolean,\n): \"past\" | \"at\" | null {\n if (c === \";\" && depth <= 0) return \"past\";\n if (c === \"\\n\" && depth <= 0 && specSeen) return \"at\";\n return null;\n}\n\n/** End index of the statement starting at `at`: first top-level `;`, or\n * the first newline after the module-specifier string (covers multiline\n * `import {…}\\n from \"x\"` and `import \"x\"` without a semicolon). */\nfunction scanStatementEnd(code: string, at: number): number {\n let i = at;\n let depth = 0;\n let specSeen = false;\n while (i < code.length) {\n const opaque = scanOpaqueEnd(code, i);\n if (opaque.end > i + 1) {\n specSeen = specSeen || opaque.isString;\n i = opaque.end;\n continue;\n }\n const term = stmtTerminator(code[i], depth, specSeen);\n if (term === \"past\") return i + 1;\n if (term === \"at\") return i;\n depth += bracketDelta(code[i]);\n i++;\n }\n return i;\n}\n\n/** Same-line statement tail: horizontal whitespace then an optional `;`.\n * Never eats the newline — the following line is the next statement. */\nfunction scanStmtTail(code: string, at: number): number {\n let i = at;\n while (i < code.length && (code[i] === \" \" || code[i] === \"\\t\")) i++;\n if (code[i] === \";\") i++;\n return i;\n}\n\n/** End index of the `from \"…\"` clause starting after `from`, or `at` when\n * the clause is malformed — let the evaluator complain. */\nfunction scanFromClause(code: string, next: number): number {\n const specAt = skipTrivia(code, next + 4);\n const q = code[specAt];\n if (q === '\"' || q === \"'\") {\n return scanStmtTail(code, scanString(code, specAt));\n }\n return next;\n}\n\n/** End index of `export * [as ns] [from \"…\"]` — the `*` is at `at`. */\nfunction scanExportStar(code: string, at: number): number {\n let i = skipTrivia(code, at + 1);\n if (keywordAt(code, i, \"as\")) {\n i = skipTrivia(code, i + 2);\n i = skipIdent(code, i);\n }\n const next = skipTrivia(code, i);\n if (keywordAt(code, next, \"from\")) return scanFromClause(code, next);\n return scanStmtTail(code, i);\n}\n\n/**\n * End index of `export {…}` / `export * [as ns] [from \"…\"]` starting at\n * the `{` or `*`. A bare list ends at its `;` or newline — unlike an\n * import, a newline after the closing brace must end the statement or\n * the next line would be eaten with it.\n */\nfunction scanExportListEnd(code: string, at: number): number {\n if (code[at] === \"*\") return scanExportStar(code, at);\n const close = matchBrace(code, at);\n const i = close < 0 ? code.length : close + 1;\n const next = skipTrivia(code, i);\n if (keywordAt(code, next, \"from\")) return scanFromClause(code, next);\n return scanStmtTail(code, i);\n}\n\ninterface ScanState {\n i: number;\n stmtStart: boolean;\n exportDefaultDone: boolean;\n /** `block` vs `expr` — separates block braces from object literals, so\n * `{ export: 1 }` is a key, not a statement. */\n stack: (\"block\" | \"expr\")[];\n /** True when the previous token ended an operand — `/` then divides.\n * Regex literals never update the delimiter stack, so `/[{]/` can't\n * leave an unclosed `{` that keeps `export default` alive to eval. */\n operandEnd: boolean;\n}\n\nfunction atStmtLevel(st: ScanState): boolean {\n return st.stack.length === 0 || st.stack.at(-1) === \"block\";\n}\n\n/** Copy a string literal or comment verbatim into `out`. */\nfunction copyOpaque(code: string, st: ScanState, out: string[]): boolean {\n const opaque = scanOpaqueEnd(code, st.i);\n if (opaque.end <= st.i + 1) return false;\n out.push(code.slice(st.i, opaque.end));\n if (opaque.isString) {\n st.stmtStart = false;\n st.operandEnd = true;\n }\n st.i = opaque.end;\n return true;\n}\n\n/** Handle `{}`/`()`/`[]` — pushes onto the block/expr stack and sets the\n * operand context: `}` closing an object literal ends a value, `}`\n * closing a block ends a statement. */\nfunction applyBracket(code: string, st: ScanState, out: string[]): boolean {\n const c = code[st.i];\n if (c === \"{\") {\n // A `{` at statement position opens a block; anywhere else it's an\n // object literal. Inside a block the next token is a statement;\n // inside an object it's a key — `export:` there is not a keyword.\n st.stack.push(st.stmtStart ? \"block\" : \"expr\");\n st.operandEnd = false;\n } else if (c === \"}\") {\n const popped = st.stack.pop();\n st.stmtStart = popped === \"block\";\n st.operandEnd = popped === \"expr\";\n } else if (c === \"(\" || c === \"[\") {\n st.stack.push(\"expr\");\n st.stmtStart = false;\n st.operandEnd = false;\n } else if (c === \")\" || c === \"]\") {\n st.stack.pop();\n st.stmtStart = false;\n st.operandEnd = true;\n } else {\n return false;\n }\n out.push(c ?? \"\");\n st.i++;\n return true;\n}\n\n/** Handle `\\n`, `;`, and whitespace — statement boundaries at statement\n * level only (a `;` inside `for (;;)` doesn't count). A newline never\n * resets operand context: `foo\\n/bar/` divides, per ASI rules. */\nfunction applyTerminator(code: string, st: ScanState, out: string[]): boolean {\n const c = code[st.i];\n if (c !== \";\" && c !== \"\\n\" && !isWsChar(c)) return false;\n if (c === \";\") {\n if (atStmtLevel(st)) st.stmtStart = true;\n st.operandEnd = false;\n } else if (c === \"\\n\" && atStmtLevel(st)) {\n st.stmtStart = true;\n }\n out.push(c ?? \"\");\n st.i++;\n return true;\n}\n\n/** Handle `/` — a regex literal when an operand is expected, a division\n * operator when one just ended. Comments never reach here (copyOpaque\n * already consumed them). */\nfunction applySlash(code: string, st: ScanState, out: string[]): boolean {\n if (code[st.i] !== \"/\" || commentAt(code, st.i)) return false;\n if (st.operandEnd) {\n out.push(\"/\");\n st.i++;\n st.operandEnd = false;\n } else {\n const end = scanRegex(code, st.i);\n out.push(code.slice(st.i, end));\n st.i = end;\n st.operandEnd = true;\n }\n st.stmtStart = false;\n return true;\n}\n\n/** Handle an `import` keyword at statement start. Dynamic `import (…)`\n * and `import.meta` pass through verbatim — whitespace and comments may\n * sit between the keyword and the paren. */\nfunction tryImport(code: string, st: ScanState, out: string[]): boolean {\n if (!st.stmtStart || !keywordAt(code, st.i, \"import\")) return false;\n const nc = code[skipTrivia(code, st.i + 6)];\n if (nc === \"(\" || nc === \".\") {\n out.push(\"import\");\n st.i += 6;\n st.stmtStart = false;\n st.operandEnd = true;\n return true;\n }\n st.i = scanStatementEnd(code, st.i + 6);\n st.stmtStart = false;\n st.operandEnd = false;\n return true;\n}\n\n/** Handle `export default` (→ `return`), `export {…}`/`export *` (removed)\n * and `export <decl>` (keyword dropped — the eval context is a function\n * body, where `export const` would be a syntax error). */\nfunction tryExport(code: string, st: ScanState, out: string[]): boolean {\n if (!st.stmtStart || !keywordAt(code, st.i, \"export\")) return false;\n const j = skipTrivia(code, st.i + 6);\n if (\n !st.exportDefaultDone &&\n code.startsWith(\"default\", j) &&\n !isIdentChar(code[j + 7])\n ) {\n // `return` must touch the expression — a newline between `default`\n // and the value would trigger ASI and return undefined.\n out.push(\"return \");\n st.exportDefaultDone = true;\n st.i = skipTrivia(code, j + 7);\n st.stmtStart = false;\n st.operandEnd = false;\n return true;\n }\n if (code[j] === \"{\" || code[j] === \"*\") {\n st.i = scanExportListEnd(code, j);\n st.stmtStart = false;\n st.operandEnd = false;\n return true;\n }\n st.i = j;\n st.stmtStart = false;\n st.operandEnd = false;\n return true;\n}\n\n/** Emit an identifier run — keyword table decides whether `/` after it\n * divides (`foo /x/`) or opens a regex (`return /x/`). */\nfunction tryWord(code: string, st: ScanState, out: string[]): boolean {\n if (!isIdentChar(code[st.i])) return false;\n const wend = skipIdent(code, st.i);\n out.push(code.slice(st.i, wend));\n st.operandEnd = operandAfterWord(code.slice(st.i, wend));\n st.stmtStart = false;\n st.i = wend;\n return true;\n}\n\n/** Char handlers tried in order — first true wins. Any char left over is\n * copied verbatim as a non-operand punctuation token. */\nconst HANDLERS: ((code: string, st: ScanState, out: string[]) => boolean)[] = [\n copyOpaque,\n applyBracket,\n applyTerminator,\n applySlash,\n tryImport,\n tryExport,\n tryWord,\n];\n\nfunction advanceScan(code: string, st: ScanState, out: string[]): void {\n for (const handle of HANDLERS) {\n if (handle(code, st, out)) return;\n }\n st.stmtStart = false;\n st.operandEnd = false;\n out.push(code[st.i] ?? \"\");\n st.i++;\n}\n\n/**\n * Strip import/export statements from user code for eval — a linear\n * single-pass scan, so multiline imports and comments/strings are handled\n * and pathological spacing cannot cause quadratic backtracking.\n *\n * `import …` statements are removed whole. `export default` becomes\n * `return`, `export {…}`/`export *` are removed, and `export` before a\n * declaration is dropped (the eval context is a function body, where\n * `export const` would be a syntax error).\n *\n * Note: TypeScript-specific syntax (type annotations, interfaces, enums)\n * is not stripped — the playground uses Monaco's TypeScript language mode\n * for editing, but evaluation is plain JavaScript. Users should write\n * JS-compatible code or use the `as any` escape hatch sparingly.\n */\nexport function preprocessCode(code: string): string {\n const out: string[] = [];\n const st: ScanState = {\n i: 0,\n stmtStart: true,\n exportDefaultDone: false,\n stack: [],\n operandEnd: false,\n };\n while (st.i < code.length) {\n if (code[st.i] === undefined) break;\n advanceScan(code, st, out);\n }\n return out.join(\"\");\n}\n\n/**\n * Evaluate user code and return the Project.\n *\n * SECURITY: This uses `new Function()` to execute user-provided code.\n * This is intentional — the playground is a local development tool where\n * the user writes and runs their own pipeline code. The code runs in the\n * browser's main page context (not a sandboxed iframe or worker) because\n * the playground needs to support synchronous FunctionStep execution and\n * direct access to the pipeline constructs. This is the same trust model\n * as a local REPL or `node -e`.\n */\nexport function evaluateUserCode(code: string): Project {\n const processed = preprocessCode(code);\n // Dynamic code execution is intentional for the playground sandbox.\n // SonarCloud S1523: safe — user code runs in the browser sandbox with the\n // same trust model as a local REPL or `node -e` (see comment above).\n const params = [\n \"Project\",\n \"Pipeline\",\n \"FunctionStep\",\n \"ShellStep\",\n \"Entry\",\n \"push\",\n \"changeRequest\",\n \"manual\",\n \"schedule\",\n processed,\n ];\n // NOSONAR suppresses only issues on the marker's own line — it must\n // trail the `new Function` callee, not sit inside the argument list.\n const fn = new Function(...params); // NOSONAR — intentional dynamic evaluation in sandbox\n const fnArgs = [\n Project,\n Pipeline,\n FunctionStep,\n ShellStep,\n Entry,\n push,\n changeRequest,\n manual,\n schedule,\n ];\n // NOSONAR suppresses only issues on the marker's own line — it must\n // trail the `fn(...)` invocation, not sit inside an argument list.\n const result = fn(...fnArgs); // NOSONAR — intentional dynamic evaluation in sandbox\n if (!(result instanceof Project)) {\n throw new TypeError(\"Code must export a Project instance\");\n }\n return result as Project;\n}\n\n/**\n * Run a pipeline with a timeout. If a step returns a never-resolving\n * promise, the timeout ensures the UI recovers instead of staying\n * stuck in \"Running\" state forever.\n */\nexport async function runPipelineWithTimeout(\n project: Project,\n timeoutMs: number,\n): Promise<Awaited<ReturnType<typeof runPipeline>>> {\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n return await Promise.race([\n runPipeline(project),\n new Promise<never>((_, reject) => {\n timer = setTimeout(\n () => reject(new Error(`Pipeline timed out after ${timeoutMs}ms`)),\n timeoutMs,\n );\n }),\n ]);\n } finally {\n // Without this, every completed run leaves a live timer that rejects\n // into an unhandled rejection timeoutMs later.\n if (timer !== undefined) clearTimeout(timer);\n }\n}\n","// @sverka/playground — mountRunner embed API (Spec 53).\n// Docs pages mount a self-contained runner: code (editable or readonly),\n// a Run button, status line, and a findings iframe. Zero backend — the\n// runner evaluates pipeline code in-page under the same trust model as\n// the full playground (see engine.ts).\n\nimport { generateSarifHtml } from \"@sverka/sarif-viewer-web/html-generator\";\nimport type { PipelineResult } from \"./types.js\";\nimport {\n DEFAULT_CODE,\n escapeHtml,\n evaluateUserCode,\n runPipelineWithTimeout,\n} from \"./engine.js\";\n\nexport interface MountRunnerOptions {\n /** Initial editor source. Defaults to the playground template. */\n readonly code?: string;\n /** Render the source as a fixed listing instead of an editable field. */\n readonly readonly?: boolean;\n /** Run `code` immediately on mount. Defaults to false — embed code may\n * come from a share link or CMS, so mounting never executes it unless\n * the embedder opts in or the user clicks Run. */\n readonly autoRun?: boolean;\n /** Called once per completed run — unless the runner was disposed\n * first; teardown silences callbacks for runs still in flight. */\n readonly onRun?: (result: PipelineResult) => void;\n}\n\nexport interface MountedRunner {\n /** Remove the runner's DOM and listeners. */\n dispose(): void;\n}\n\nconst STYLE = `\n font-family: monospace; font-size: 12px;\n background: #0d1117; color: #c9d1d9;\n border: 1px solid #30363d; border-radius: 6px;\n display: flex; flex-direction: column; overflow: hidden;\n`;\n\nfunction createHeader(doc: Document): {\n header: HTMLElement;\n runBtn: HTMLButtonElement;\n status: HTMLSpanElement;\n} {\n const header = doc.createElement(\"div\");\n header.setAttribute(\n \"style\",\n \"display:flex;align-items:center;gap:0.5rem;padding:0.4rem 0.6rem;background:#161b22;border-bottom:1px solid #30363d;\",\n );\n const runBtn = doc.createElement(\"button\");\n runBtn.textContent = \"Run\";\n runBtn.setAttribute(\n \"style\",\n \"padding:0.2rem 0.8rem;border:1px solid #30363d;border-radius:6px;background:#1f6feb;color:#fff;cursor:pointer;font-size:0.8rem;\",\n );\n const status = doc.createElement(\"span\");\n status.setAttribute(\"style\", \"font-size:0.75rem;color:#8b949e;\");\n status.textContent = \"Ready\";\n header.append(runBtn, status);\n return { header, runBtn, status };\n}\n\nfunction createCodeEl(\n doc: Document,\n code: string,\n readonly: boolean,\n): HTMLTextAreaElement | HTMLElement {\n if (readonly) {\n const pre = doc.createElement(\"pre\");\n pre.setAttribute(\n \"style\",\n \"margin:0;padding:0.75rem;overflow:auto;max-height:16rem;white-space:pre;\",\n );\n pre.textContent = code;\n return pre;\n }\n const textarea = doc.createElement(\"textarea\");\n textarea.value = code;\n textarea.setAttribute(\n \"style\",\n \"flex:0 0 12rem;width:100%;background:#0d1117;color:#c9d1d9;border:none;border-bottom:1px solid #30363d;padding:0.75rem;resize:vertical;outline:none;font:inherit;\",\n );\n return textarea;\n}\n\nfunction createFrame(doc: Document): HTMLIFrameElement {\n const frame = doc.createElement(\"iframe\");\n // Shared findings render via srcdoc — sandboxed onto an opaque origin so a\n // crafted payload can never touch the host page; allow-scripts keeps the\n // report's own viewer interactivity (search/filter/sort) working.\n frame.setAttribute(\"sandbox\", \"allow-scripts\");\n frame.setAttribute(\n \"style\",\n \"flex:1;min-height:10rem;width:100%;border:none;background:#0d1117;\",\n );\n return frame;\n}\n\nconst BODY_DARK =\n '<body style=\"background:#0d1117;font-family:monospace;padding:1rem;';\n\n/** Failure banner HTML — string concat keeps user data flowing through\n * escapeHtml explicitly, never through template interpolation. */\nfunction failureBanner(result: PipelineResult): string {\n const failed = result.steps.filter((s) => s.status === \"failure\");\n const lines =\n failed.map((s) => `${s.stepId}: ${s.error ?? \"failed\"}`).join(\"\\n\") ||\n `${result.steps.length} steps failed`;\n return [\n '<div style=\"background:#3d1d1f;color:#f85149;padding:0.6rem 1rem;font-family:monospace;border-bottom:1px solid #30363d;\">',\n \"<strong>Run failed</strong>\",\n '<pre style=\"margin:0.4rem 0 0;white-space:pre-wrap;\">',\n escapeHtml(lines),\n \"</pre></div>\",\n ].join(\"\");\n}\n\n/** Document shown when the run failed — partial findings still render\n * underneath the banner so finished steps aren't hidden by the error. */\nfunction failureDoc(result: PipelineResult, banner: string): string {\n if (result.findings.length === 0) {\n return (\n \"<!DOCTYPE html><html>\" +\n BODY_DARK +\n 'color:#f85149;\">' +\n banner +\n \"</body></html>\"\n );\n }\n const sarif = generateSarifHtml(result.findings);\n return sarif.includes(\"<body>\")\n ? sarif.replace(\"<body>\", \"<body>\" + banner)\n : banner + sarif;\n}\n\n/** Document shown for a clean run with zero findings. */\nfunction successDoc(result: PipelineResult): string {\n return [\n \"<!DOCTYPE html><html>\",\n BODY_DARK,\n 'color:#3fb950;\">',\n \"<h3>No findings — all checks passed</h3><p>\",\n escapeHtml(String(result.steps.length)),\n \" steps in \",\n escapeHtml(String(result.totalDurationMs)),\n \"ms</p></body></html>\",\n ].join(\"\");\n}\n\n/** Document shown when the runner itself threw (eval or pipeline error). */\nfunction errorDoc(e: unknown): string {\n const msg = e instanceof Error ? e.message : String(e);\n return [\n \"<!DOCTYPE html><html>\",\n BODY_DARK,\n 'color:#f85149;\">',\n \"<h3>Error</h3><pre>\",\n escapeHtml(msg),\n \"</pre></body></html>\",\n ].join(\"\");\n}\n\nfunction statusLine(result: PipelineResult): string {\n if (result.success)\n return `${result.findings.length} findings · ${result.totalDurationMs}ms`;\n const failures = result.steps.filter((s) => s.status === \"failure\").length;\n return `${failures} step(s) failed · ${result.findings.length} findings`;\n}\n\n/** Render a completed run into the findings frame. */\nfunction renderResult(\n result: PipelineResult,\n showFindings: (html: string) => void,\n): void {\n if (!result.success) {\n showFindings(failureDoc(result, failureBanner(result)));\n return;\n }\n if (result.findings.length === 0) {\n showFindings(successDoc(result));\n return;\n }\n showFindings(generateSarifHtml(result.findings));\n}\n\n/**\n * Mount a self-contained runner inside `el`. `dispose()` tears the mount\n * down. With `autoRun: true` the runner executes `code` once on mount;\n * otherwise it waits for the Run button — embeds never auto-execute code\n * the embedder didn't explicitly allow.\n */\nexport function mountRunner(\n el: HTMLElement,\n opts: MountRunnerOptions = {},\n): MountedRunner {\n const doc = el.ownerDocument;\n const code = opts.code ?? DEFAULT_CODE;\n\n const root = doc.createElement(\"div\");\n root.setAttribute(\"style\", STYLE);\n const { header, runBtn, status } = createHeader(doc);\n const codeEl = createCodeEl(doc, code, opts.readonly === true);\n const frame = createFrame(doc);\n root.append(header, codeEl, frame);\n el.appendChild(root);\n\n // Branch on the option, not instanceof — a container owned by another\n // window would produce a cross-realm textarea that fails the check.\n const getCode = (): string =>\n opts.readonly === true ? code : (codeEl as HTMLTextAreaElement).value;\n\n // A run in flight outlives dispose() — the flag suppresses its callback.\n let disposed = false;\n\n const run = async (): Promise<void> => {\n runBtn.disabled = true;\n status.textContent = \"Running...\";\n let result: PipelineResult;\n try {\n const project = evaluateUserCode(getCode());\n result = await runPipelineWithTimeout(project, 30_000);\n renderResult(result, (html) => {\n frame.srcdoc = html;\n });\n status.textContent = statusLine(result);\n } catch (e) {\n frame.srcdoc = errorDoc(e);\n status.textContent = \"Error\";\n runBtn.disabled = false;\n return;\n }\n runBtn.disabled = false;\n // Outside the try — a throwing callback must not corrupt the findings\n // view or get misreported as a runner failure.\n if (!disposed) opts.onRun?.(result);\n };\n\n const onClick = (): void => {\n void run();\n };\n runBtn.addEventListener(\"click\", onClick);\n if (opts.autoRun === true) void run();\n\n return {\n dispose() {\n disposed = true;\n runBtn.removeEventListener(\"click\", onClick);\n root.remove();\n },\n };\n}\n","// @sverka/playground — toSverkaConfig (Spec 53): the \"take it home\" bridge.\n// Converts playground source into a real sverka.config.ts: the authoring\n// surface (Project/Pipeline/Entry/roots) transfers verbatim — only the step\n// kind differs. FunctionStep bodies cannot run as shell commands, so each\n// becomes a ShellStep carrying a placeholder echo the user replaces.\n\nimport { PlaygroundError } from \"./share.js\";\nimport {\n isIdentChar,\n isOpaqueStart,\n isWsChar,\n keywordAt,\n matchBrace,\n scanOpaqueEnd,\n scanOperand,\n scanString,\n skipIdent,\n} from \"./scanner.js\";\n\n// --- local char helpers (only transpile needs these) ----------------------\n\nfunction isOpenBracket(c: string | undefined): boolean {\n return c === \"{\" || c === \"[\" || c === \"(\";\n}\n\nfunction isCloseBracket(c: string | undefined): boolean {\n return c === \"}\" || c === \"]\" || c === \")\";\n}\n\nfunction skipWs(code: string, i: number): number {\n while (i < code.length && isWsChar(code[i])) i++;\n return i;\n}\n\n// ---------------------------------------------------------------------------\n// Every matcher below is string-, comment-, and regex-literal-aware via the\n// shared scanner — braces inside `/[{]/` or quotes never count as syntax,\n// and all scans are linear (no regexes over user source at all).\n// ---------------------------------------------------------------------------\n\n/** One token of an operand-tracking scan — identifiers (with `word`),\n * opaque spans, and regex-vs-division resolve through the shared\n * scanner; whitespace passes through. Null when `i` sits on\n * punctuation the caller's own depth/branch logic owns. */\nfunction propToken(\n s: string,\n i: number,\n operandEnd: boolean,\n): { end: number; operandEnd: boolean; word?: string } | null {\n if (isWsChar(s[i])) return { end: i + 1, operandEnd };\n const op = scanOperand(s, i, operandEnd);\n if (op === null) return null;\n if (isIdentChar(s[i])) return { ...op, word: s.slice(i, op.end) };\n return op;\n}\n\n/** Apply a bracket/other punctuation char to depth + operand state. */\nfunction applyPunctuation(\n c: string | undefined,\n st: { depth: number; operandEnd: boolean },\n): void {\n if (isOpenBracket(c)) {\n st.depth++;\n st.operandEnd = false;\n } else if (isCloseBracket(c)) {\n st.depth--;\n st.operandEnd = true;\n } else {\n st.operandEnd = false;\n }\n}\n\n/**\n * Index of the `:` following a depth-0 `key` in a props object body, or -1.\n * A `dependencies` declared inside `fn` never counts — only top-level keys.\n */\nfunction findPropKey(props: string, key: string): number {\n const st = { depth: 0, operandEnd: false };\n let i = 0;\n while (i < props.length) {\n const tok = propToken(props, i, st.operandEnd);\n if (tok === null) {\n applyPunctuation(props[i], st);\n i++;\n continue;\n }\n if (st.depth === 0 && tok.word === key) {\n const hit = skipWs(props, tok.end);\n if (props[hit] === \":\") return hit;\n }\n st.operandEnd = tok.operandEnd;\n i = tok.end;\n }\n return -1;\n}\n\n/** True when the comment at `k` is a top-level tail comment — `deps: [] //\n * note` — and therefore not part of the value. Emitting it would comment\n * out the generated `}` after `dependsOn: <value>`. */\nfunction isTailComment(props: string, k: number, after: number): boolean {\n const ahead = skipWs(props, after);\n return ahead >= props.length || props[ahead] === \",\";\n}\n\n/** End index of a prop value starting at `j` — the next top-level comma\n * or the end of the props body, with strings/comments/brackets balanced. */\nfunction propValueEnd(props: string, j: number): number {\n const st = { depth: 0, operandEnd: false };\n let k = j;\n while (k < props.length) {\n if (isOpaqueStart(props, k)) {\n const after = scanOpaqueEnd(props, k).end;\n if (st.depth === 0 && isTailComment(props, k, after)) return k;\n k = after;\n continue;\n }\n const tok = propToken(props, k, st.operandEnd);\n if (tok !== null) {\n st.operandEnd = tok.operandEnd;\n k = tok.end;\n continue;\n }\n if (props[k] === \",\" && st.depth === 0) return k;\n applyPunctuation(props[k], st);\n k++;\n }\n return k;\n}\n\n/**\n * Extract a top-level `key: <value>` span from a props object body.\n * Only depth-0 keys match — a `dependencies` declared inside `fn` never\n * counts. The value runs to the next top-level `,`, with strings,\n * comments, and nested brackets all balanced.\n */\nfunction extractProp(props: string, key: string): string | undefined {\n const colon = findPropKey(props, key);\n if (colon < 0) return undefined;\n const j = skipWs(props, colon + 1);\n return props.slice(j, propValueEnd(props, j)).trim();\n}\n\n/** Consume trailing spaces/tabs plus one optional `;` — never the newline.\n * Eating it would fuse the emitted import with the next line\n * (`from \"@sverka/workflow\"const x = …`). */\nfunction stmtEndPos(source: string, i: number): number {\n let end = i;\n while (source[end] === \" \" || source[end] === \"\\t\") end++;\n if (source[end] === \";\") end++;\n return end;\n}\n\n/** Parse one import specifier: `Name` or `Name as alias`. */\nfunction parseImportSpec(spec: string): { orig: string; local: string } {\n const a = skipWs(spec, 0);\n const wend = skipIdent(spec, a);\n const orig = spec.slice(a, wend);\n const asPos = skipWs(spec, wend);\n if (!spec.startsWith(\"as\", asPos) || isIdentChar(spec[asPos + 2])) {\n return { orig, local: orig };\n }\n const b = skipWs(spec, asPos + 2);\n const local = spec.slice(b, skipIdent(spec, b));\n return local === \"\" ? { orig, local: orig } : { orig, local };\n}\n\ninterface MappedImports {\n mapped: string;\n fnStepLocals: string[];\n}\n\n/** Map `{…}` import specifiers; FunctionStep becomes ShellStep (aliases\n * survive: `FunctionStep as Fn` → `ShellStep as Fn`). */\nfunction mapImportSpecifiers(inner: string): MappedImports {\n const mapped: string[] = [];\n const fnStepLocals: string[] = [];\n for (const spec of inner.split(\",\")) {\n const trimmed = spec.trim();\n if (trimmed === \"\") continue;\n const { orig, local } = parseImportSpec(trimmed);\n if (orig === \"FunctionStep\") {\n fnStepLocals.push(local);\n mapped.push(orig === local ? \"ShellStep\" : `ShellStep as ${local}`);\n } else {\n mapped.push(trimmed);\n }\n }\n return { mapped: mapped.join(\", \"), fnStepLocals };\n}\n\ninterface PlaygroundImport {\n stmtEnd: number;\n mapped: string;\n fnStepLocals: string[];\n}\n\n/** Parse `import {…} from \"@sverka/playground\"` at `i`, or null when the\n * statement has another shape/module. Caller guarantees \"import\" at `i`. */\nfunction parsePlaygroundImport(\n source: string,\n i: number,\n): PlaygroundImport | null {\n const j = skipWs(source, i + 6);\n if (source[j] !== \"{\") return null;\n const namesEnd = matchBrace(source, j);\n if (namesEnd < 0) return null;\n const fromKw = skipWs(source, namesEnd + 1);\n if (!keywordAt(source, fromKw, \"from\")) return null;\n const qPos = skipWs(source, fromKw + 4);\n const q = source[qPos];\n if (q !== '\"' && q !== \"'\") return null;\n const specEnd = scanString(source, qPos);\n if (source.slice(qPos + 1, specEnd - 1) !== \"@sverka/playground\") return null;\n const { mapped, fnStepLocals } = mapImportSpecifiers(\n source.slice(j + 1, namesEnd),\n );\n return { stmtEnd: stmtEndPos(source, specEnd), mapped, fnStepLocals };\n}\n\n/**\n * Rewrite `import {…} from \"@sverka/playground\"` statements linearly.\n *\n * Returns the rewritten source plus every local name bound to\n * FunctionStep, so constructor calls under an alias are transpiled too.\n */\nfunction rewritePlaygroundImports(source: string): {\n code: string;\n fnStepNames: string[];\n} {\n const fnStepNames: string[] = [];\n let out = \"\";\n let cursor = 0;\n let i = 0;\n while (i < source.length) {\n const end = scanOpaqueEnd(source, i).end;\n if (end > i + 1) {\n i = end;\n continue;\n }\n if (source.startsWith(\"import\", i) && !isIdentChar(source[i + 6])) {\n const stmt = parsePlaygroundImport(source, i);\n if (stmt !== null) {\n out += source.slice(cursor, i);\n out += `import { ${stmt.mapped} } from \"@sverka/workflow\"`;\n if (source[stmt.stmtEnd - 1] === \";\") out += \";\";\n fnStepNames.push(...stmt.fnStepLocals);\n cursor = stmt.stmtEnd;\n i = stmt.stmtEnd;\n continue;\n }\n }\n i++;\n }\n return { code: out + source.slice(cursor), fnStepNames };\n}\n\n/** Index of `(` after `new <name>` where <name> ∈ names, or null. */\nfunction stepCallParen(\n code: string,\n afterNew: number,\n names: readonly string[],\n): number | null {\n const j = skipWs(code, afterNew);\n for (const name of names) {\n const next = code[j + name.length];\n if (code.startsWith(name, j) && !isIdentChar(next)) {\n const paren = skipWs(code, j + name.length);\n if (code[paren] === \"(\") return paren;\n }\n }\n return null;\n}\n\n/** Operand context after punctuation — closers end a value, everything\n * else (openers, operators, separators) expects one. */\nfunction punctuationOperandEnd(c: string | undefined): boolean {\n return c === \")\" || c === \"]\" || c === \"}\";\n}\n\n/**\n * Locate the next `new <name>(` call where <name> ∈ names. Whole-word\n * scanning makes boundary checks free — `myNew` or `newer` never match.\n * Opaque regions and regex literals are skipped inline, so a\n * `new FunctionStep(` inside a comment, string, or `/new Fn(/` pattern\n * is documentation, not a call.\n */\nfunction findStepCall(\n code: string,\n names: readonly string[],\n from: number,\n): { start: number; paren: number } | null {\n let operandEnd = false;\n let i = from;\n while (i < code.length) {\n const tok = propToken(code, i, operandEnd);\n if (tok !== null) {\n if (tok.word === \"new\") {\n const paren = stepCallParen(code, tok.end, names);\n if (paren !== null) return { start: i, paren };\n }\n operandEnd = tok.operandEnd;\n i = tok.end;\n continue;\n }\n operandEnd = punctuationOperandEnd(code[i]);\n i++;\n }\n return null;\n}\n\n/** End of the scope expression — the first top-level comma after `from`,\n * or -1 when the argument list closes/ends first. */\nfunction scanScopeEnd(code: string, from: number): number {\n const st = { depth: 0, operandEnd: false };\n let k = from;\n while (k < code.length) {\n const tok = propToken(code, k, st.operandEnd);\n if (tok !== null) {\n st.operandEnd = tok.operandEnd;\n k = tok.end;\n continue;\n }\n const c = code[k];\n if (c === \",\" && st.depth === 0) return k;\n if (isCloseBracket(c) && st.depth === 0) return -1;\n applyPunctuation(c, st);\n k++;\n }\n return -1;\n}\n\ninterface StepArgs {\n scope: string;\n id: string;\n propsOpen: number;\n}\n\n/** Parse `(scope, \"id\", {` after the `(` at `paren`; null when the call\n * shape differs. A template id throws immediately — never half-converts. */\nfunction parseStepArgs(code: string, paren: number): StepArgs | null {\n const scopeStart = skipWs(code, paren + 1);\n const comma = scanScopeEnd(code, scopeStart);\n if (comma < 0) return null;\n const qPos = skipWs(code, comma + 1);\n const q = code[qPos];\n if (q === \"`\")\n throw new PlaygroundError(\n \"TRANSPILE_FAILED\",\n \"cannot parse FunctionStep — template-literal step id\",\n );\n if (q !== '\"' && q !== \"'\") return null;\n const idEnd = scanString(code, qPos);\n const afterId = skipWs(code, idEnd);\n if (code[afterId] !== \",\") return null;\n const propsOpen = skipWs(code, afterId + 1);\n if (code[propsOpen] !== \"{\") return null;\n return {\n scope: code.slice(scopeStart, comma).trim(),\n id: code.slice(qPos + 1, idEnd - 1),\n propsOpen,\n };\n}\n\n/** Emit the ShellStep placeholder replacing one FunctionStep call. */\nfunction shellStepCall(args: StepArgs, dependencies: string | undefined) {\n // The id lands inside shell single quotes — $()/backticks can never\n // expand. `'` is already impossible (the id is a plain string literal).\n return (\n `new ShellStep(${args.scope}, \"${args.id}\", ` +\n `{ command: \"echo 'TODO: port '${args.id}' — replace with the real shell command'\"` +\n (dependencies !== undefined ? \", dependsOn: \" + dependencies : \"\") +\n \" }\"\n );\n}\n\n/** Rewrite every `new Fn(scope, \"id\", {…})` call under the given local\n * names into ShellStep placeholders; `dependencies` → `dependsOn`. */\nfunction rewriteStepCalls(code: string, names: readonly string[]): string {\n let result = \"\";\n let cursor = 0;\n for (;;) {\n const call = findStepCall(code, names, cursor);\n if (call === null) break;\n const args = parseStepArgs(code, call.paren);\n if (args === null) {\n // A `new Fn(` whose shape we don't own — skip `new` and let the\n // leftover check name it, rather than silently dropping it.\n result += code.slice(cursor, call.start + 3);\n cursor = call.start + 3;\n continue;\n }\n const propsClose = matchBrace(code, args.propsOpen);\n if (propsClose < 0)\n throw new PlaygroundError(\n \"TRANSPILE_FAILED\",\n `cannot parse FunctionStep \"${args.id}\" — unbalanced props object`,\n );\n const dependencies = extractProp(\n code.slice(args.propsOpen + 1, propsClose),\n \"dependencies\",\n );\n result +=\n code.slice(cursor, call.start) + shellStepCall(args, dependencies);\n cursor = propsClose + 1;\n }\n return result + code.slice(cursor);\n}\n\n/** A surviving step call means a shape we could not convert — computed\n * scope/id or a malformed alias call. Fail loud rather than emit a\n * half-converted file. */\nfunction assertNoLeftoverSteps(code: string, names: readonly string[]): void {\n const call = findStepCall(code, names, 0);\n if (call === null) return;\n const scopeStart = skipWs(code, call.paren + 1);\n const scopeEnd = scanScopeEnd(code, scopeStart);\n const scope =\n scopeEnd < 0 ? \"?\" : code.slice(scopeStart, scopeEnd).trim() || \"?\";\n throw new PlaygroundError(\n \"TRANSPILE_FAILED\",\n `cannot parse FunctionStep with scope '${scope}' — unsupported expression`,\n );\n}\n\n/**\n * Transpile playground source into `sverka.config.ts`.\n *\n * Rewrites the `@sverka/playground` import to `@sverka/workflow` and each\n * `new FunctionStep(scope, \"id\", { fn, dependencies })` into a ShellStep\n * whose command echoes a placeholder — the function body has no shell\n * equivalent.\n * `dependencies` maps onto `dependsOn`. Aliased FunctionStep imports\n * (`FunctionStep as Fn`) are followed too.\n *\n * Throws `PlaygroundError(TRANSPILE_FAILED)` naming the offending step when\n * a FunctionStep cannot be parsed — a half-converted file is never emitted.\n */\nexport function toSverkaConfig(source: string): string {\n const { code, fnStepNames } = rewritePlaygroundImports(source);\n if (fnStepNames.length === 0) fnStepNames.push(\"FunctionStep\");\n const out = rewriteStepCalls(code, fnStepNames);\n assertNoLeftoverSteps(out, fnStepNames);\n return out;\n}\n","// @sverka/playground — examples gallery (Spec 53).\n// `examples/*/` mini-projects are bundled at build time by the vite entry\n// (app.ts collects them via import.meta.glob) — the picker needs no\n// network access. This module stays bundler-agnostic so the library\n// build (tsdown) never sees vite-only APIs.\n\nexport interface GalleryExample {\n /** Directory name, e.g. \"failing-checks\". */\n readonly id: string;\n /** Humanized label for the picker. */\n readonly title: string;\n /** sverka.config.ts source, bundled into the playground build. */\n readonly code: string;\n}\n\nfunction toTitle(id: string): string {\n return id\n .split(\"-\")\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1))\n .join(\" \");\n}\n\n/** Turn a `{ \"<path>/examples/<id>/sverka.config.ts\": source }` map into a\n * sorted picker list. */\nexport function listExamples(\n modules: Record<string, string>,\n): readonly GalleryExample[] {\n return Object.entries(modules)\n .map(([path, code]) => {\n const id =\n /examples\\/([^/]+)\\/sverka\\.config\\.ts$/.exec(path)?.[1] ?? path;\n return { id, title: toTitle(id), code };\n })\n .sort((a, b) => a.id.localeCompare(b.id));\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sverka/playground",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.22",
|
|
4
4
|
"description": "Sverka Playground — browser sandbox for building and running check pipelines",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"typecheck": "tsc --noEmit"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@sverka/sarif-viewer-web": "^0.2.
|
|
40
|
+
"@sverka/sarif-viewer-web": "^0.2.22",
|
|
41
41
|
"fflate": "0.8.3"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|