@ox-content/code-play 3.0.0-alpha.1

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.
@@ -0,0 +1,524 @@
1
+ import { c as DEV_TYPECHECK_PATH, i as escapeAttribute, n as encodePayload, o as DEFAULT_ENDPOINTS, p as resolveLanguage, r as decodeHtml, s as DEFAULT_VIEWERS, t as decodePayload, u as resolveCodePlayOptions } from "./payload.mjs";
2
+ import { readFile, writeFile } from "node:fs/promises";
3
+ import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
4
+ import path from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+ //#region src/payload-factory.ts
7
+ function payloadFromFence(fence, options) {
8
+ const definition = resolveLanguage(fence.language);
9
+ const enabled = definition ? options.languages.get(definition.id) : void 0;
10
+ return {
11
+ language: definition?.id ?? fence.language,
12
+ code: fence.code,
13
+ capabilities: {
14
+ execute: enabled?.execute ?? Boolean(definition?.capabilities.execute),
15
+ typecheck: payloadTypecheckEnabled(fence.typecheck, enabled?.typecheck, definition, options.endpoints)
16
+ },
17
+ config: {
18
+ ...definition?.defaultConfig,
19
+ ...enabled?.config
20
+ },
21
+ viewers: options.viewers,
22
+ ui: options.ui,
23
+ timeoutMs: options.timeoutMs,
24
+ endpoints: options.endpoints
25
+ };
26
+ }
27
+ /** TypeScript typecheck in the browser needs a reachable endpoint; hide the dead button otherwise. */
28
+ function payloadTypecheckEnabled(fenceTypecheck, enabledTypecheck, definition, endpoints) {
29
+ if (!(fenceTypecheck || enabledTypecheck)) return false;
30
+ if (definition?.id === "typescript") return Boolean(endpoints.typecheck);
31
+ return true;
32
+ }
33
+ //#endregion
34
+ //#region src/html.ts
35
+ const COMMENT_PATTERN = /<!--ox-code-play:([A-Za-z0-9+/=]+)-->\s*(<pre\b[\s\S]*?<\/pre>)/gi;
36
+ const CODEPLAY_TAG_PATTERN = /<CodePlay\b([^>]*)>([\s\S]*?)<\/CodePlay>/gi;
37
+ const PRE_PATTERN = /<pre\b[^>]*>\s*<code\b([^>]*)>([\s\S]*?)<\/code>\s*<\/pre>/gi;
38
+ function enhancePlayHtml(html, options) {
39
+ let next = wrapCommentedBlocks(html, options);
40
+ next = upgradeCodePlayTags(next, options);
41
+ if (options.matchFences?.length) next = wrapMatchingFences(next, options.matchFences);
42
+ if (options.scriptSrc && next.includes("data-ox-code-play") && !next.includes(options.scriptSrc)) next += `\n<script type="module" src="${escapeAttribute(options.scriptSrc)}"><\/script>\n`;
43
+ return next;
44
+ }
45
+ function enhanceGeneratedModule(source, options) {
46
+ const start = source.indexOf("export const html = ");
47
+ if (start === -1) return source;
48
+ const jsonStart = start + 20;
49
+ if (source[jsonStart] !== "\"") return source;
50
+ const parsed = readJsonString(source, jsonStart);
51
+ if (!parsed) return source;
52
+ const enhanced = enhancePlayHtml(parsed.value, options);
53
+ return source.slice(0, jsonStart) + JSON.stringify(enhanced) + source.slice(parsed.end);
54
+ }
55
+ function wrapCommentedBlocks(html, _options) {
56
+ return html.replace(COMMENT_PATTERN, (_all, payload, pre) => {
57
+ return wrapWidget(payload, pre);
58
+ });
59
+ }
60
+ function upgradeCodePlayTags(html, options) {
61
+ return html.replace(CODEPLAY_TAG_PATTERN, (all, attrs, body) => {
62
+ if (/\bdata-ox-code-play=/.test(all)) return all;
63
+ const language = readAttr$1(attrs, "lang") ?? readAttr$1(attrs, "language") ?? "text";
64
+ const code = decodeHtml(body).replace(/^\n/, "").replace(/\n$/, "");
65
+ const definition = resolveLanguage(language);
66
+ const endpoints = options.endpoints ?? DEFAULT_ENDPOINTS;
67
+ return wrapWidget(options.encodePayload({
68
+ language: definition?.id ?? language,
69
+ code,
70
+ capabilities: {
71
+ execute: true,
72
+ typecheck: payloadTypecheckEnabled(/\btypecheck\b/i.test(attrs), void 0, definition, endpoints)
73
+ },
74
+ config: {},
75
+ viewers: { ...DEFAULT_VIEWERS },
76
+ ui: "default",
77
+ timeoutMs: 1e4,
78
+ endpoints
79
+ }), `<pre><code class="language-${escapeAttribute(language)}">${body}</code></pre>`);
80
+ });
81
+ }
82
+ function wrapMatchingFences(html, matches) {
83
+ const unused = matches.map((item) => ({
84
+ ...item,
85
+ used: false
86
+ }));
87
+ return html.replace(PRE_PATTERN, (all, attrs, body) => {
88
+ const language = (readAttr$1(attrs, "class") ?? "").split(/\s+/).find((token) => token.startsWith("language-"))?.slice(9);
89
+ const code = normalizeCode(decodeHtml(stripTags(body)));
90
+ const match = unused.find((item) => !item.used && aliasesEqual(item.language, language) && normalizeCode(item.code) === code);
91
+ if (!match) return all;
92
+ match.used = true;
93
+ return wrapWidget(match.payload, all);
94
+ });
95
+ }
96
+ function wrapWidget(payload, inner) {
97
+ return `<ox-code-play data-ox-code-play="${escapeAttribute(payload)}">${inner}</ox-code-play>`;
98
+ }
99
+ function readJsonString(source, start) {
100
+ try {
101
+ const raw = sliceJsonString(source, start);
102
+ return {
103
+ value: JSON.parse(raw),
104
+ end: start + raw.length
105
+ };
106
+ } catch {
107
+ return;
108
+ }
109
+ }
110
+ function sliceJsonString(source, start) {
111
+ let end = start + 1;
112
+ let escaped = false;
113
+ while (end < source.length) {
114
+ const char = source[end];
115
+ if (escaped) escaped = false;
116
+ else if (char === "\\") escaped = true;
117
+ else if (char === "\"") return source.slice(start, end + 1);
118
+ end += 1;
119
+ }
120
+ throw new Error("Unterminated HTML JSON string.");
121
+ }
122
+ function readAttr$1(attrs, name) {
123
+ return new RegExp(`(?:^|\\s)${name}\\s*=\\s*"([^"]+)"`, "i").exec(attrs)?.[1];
124
+ }
125
+ function stripTags(value) {
126
+ return value.replace(/<[^>]+>/g, "");
127
+ }
128
+ function normalizeCode(value) {
129
+ return value.replace(/\r\n/g, "\n").replace(/\n$/, "");
130
+ }
131
+ function aliasesEqual(left, right) {
132
+ if (!left || !right) return false;
133
+ return left.toLowerCase() === right.toLowerCase();
134
+ }
135
+ //#endregion
136
+ //#region src/markdown.ts
137
+ const FENCE_OPEN = /^( {0,3})(`{3,}|~{3,})([^\n]*)$/;
138
+ function parseTopLevelFences(source) {
139
+ const lines = source.split("\n");
140
+ const fences = [];
141
+ let index = 0;
142
+ let offset = 0;
143
+ while (index < lines.length) {
144
+ const line = lines[index] ?? "";
145
+ const open = FENCE_OPEN.exec(line);
146
+ if (!open) {
147
+ offset += line.length + 1;
148
+ index += 1;
149
+ continue;
150
+ }
151
+ const indent = open[1] ?? "";
152
+ const marker = open[2] ?? "```";
153
+ const [language = "", ...metaParts] = splitInfo((open[3] ?? "").trim());
154
+ const start = offset;
155
+ index += 1;
156
+ offset += line.length + 1;
157
+ const body = [];
158
+ while (index < lines.length) {
159
+ const candidate = lines[index] ?? "";
160
+ if (new RegExp(`^ {0,3}${escapeRegExp(marker)}[ \t]*$`).exec(candidate)) {
161
+ const raw = `${line}\n${body.join("\n")}${body.length > 0 ? "\n" : ""}${candidate}`;
162
+ fences.push({
163
+ language,
164
+ meta: metaParts.join(" "),
165
+ code: body.join("\n"),
166
+ raw,
167
+ start,
168
+ end: start + raw.length,
169
+ indent,
170
+ marker
171
+ });
172
+ offset += candidate.length + 1;
173
+ index += 1;
174
+ break;
175
+ }
176
+ body.push(candidate);
177
+ offset += candidate.length + 1;
178
+ index += 1;
179
+ }
180
+ }
181
+ return fences;
182
+ }
183
+ function parsePlayFences(source) {
184
+ return parseTopLevelFences(source).filter((fence) => hasToken(fence.meta, "play")).map((fence) => ({
185
+ language: fence.language,
186
+ meta: fence.meta,
187
+ code: fence.code,
188
+ raw: fence.raw,
189
+ start: fence.start,
190
+ end: fence.end,
191
+ typecheck: hasToken(fence.meta, "typecheck")
192
+ }));
193
+ }
194
+ function stripPlayMeta(meta) {
195
+ return meta.split(/\s+/).filter((token) => token && token !== "play" && token !== "typecheck" && !token.startsWith("play-")).join(" ");
196
+ }
197
+ function rewritePlayFences(source, encode) {
198
+ const fences = parsePlayFences(source);
199
+ if (fences.length === 0) return source;
200
+ let cursor = 0;
201
+ let output = "";
202
+ for (const fence of fences) {
203
+ output += source.slice(cursor, fence.start);
204
+ const encoded = encode(fence);
205
+ if (encoded === null) output += source.slice(fence.start, fence.end);
206
+ else {
207
+ const cleanedMeta = stripPlayMeta(fence.meta);
208
+ const info = [fence.language, cleanedMeta].filter(Boolean).join(" ");
209
+ output += `<!--ox-code-play:${encoded}-->\n\`\`\`${info}\n${fence.code}\n\`\`\``;
210
+ }
211
+ cursor = fence.end;
212
+ }
213
+ output += source.slice(cursor);
214
+ return output;
215
+ }
216
+ function parseCodePlayTags(source) {
217
+ const tags = [];
218
+ for (const match of source.matchAll(/<CodePlay\b([^>]*)>([\s\S]*?)<\/CodePlay>/gi)) {
219
+ const attrs = match[1] ?? "";
220
+ const language = readAttr(attrs, "lang") ?? readAttr(attrs, "language") ?? "text";
221
+ tags.push({
222
+ language,
223
+ meta: "play",
224
+ code: stripIndent((match[2] ?? "").replace(/^\n/, "").replace(/\n$/, "")),
225
+ raw: match[0] ?? "",
226
+ start: match.index ?? 0,
227
+ end: (match.index ?? 0) + (match[0]?.length ?? 0),
228
+ typecheck: /\btypecheck\b/i.test(attrs)
229
+ });
230
+ }
231
+ return tags;
232
+ }
233
+ function splitInfo(info) {
234
+ return info.trim().split(/\s+/).filter(Boolean);
235
+ }
236
+ function hasToken(meta, token) {
237
+ return meta.split(/\s+/).includes(token);
238
+ }
239
+ function escapeRegExp(value) {
240
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
241
+ }
242
+ function readAttr(attrs, name) {
243
+ return new RegExp(`(?:^|\\s)${name}\\s*=\\s*"([^"]+)"`, "i").exec(attrs)?.[1];
244
+ }
245
+ function stripIndent(value) {
246
+ const lines = value.split("\n");
247
+ const indents = lines.filter((line) => line.trim()).map((line) => line.match(/^ */)?.[0].length ?? 0);
248
+ const indent = indents.length > 0 ? Math.min(...indents) : 0;
249
+ return lines.map((line) => line.slice(indent)).join("\n");
250
+ }
251
+ //#endregion
252
+ //#region src/plugin-client.ts
253
+ const CLIENT_FILE_CANDIDATES = [
254
+ "browser.mjs",
255
+ "browser.js",
256
+ "hydrate.mjs",
257
+ "hydrate.js"
258
+ ];
259
+ function resolveClientFile(baseUrl = import.meta.url) {
260
+ return CLIENT_FILE_CANDIDATES.map((name) => fileURLToPath(new URL(`./${name}`, baseUrl))).find((candidate) => existsSync(candidate));
261
+ }
262
+ function resolveHydrateSpecifier(baseUrl = import.meta.url) {
263
+ return resolveClientFile(baseUrl) ?? fileURLToPath(new URL("./hydrate.ts", baseUrl));
264
+ }
265
+ function isStandaloneBrowserClient(source) {
266
+ return !/\bfrom\s+["']\.\.?\/[^"']+["']/.test(source) && !/\bimport\s*\(\s*["']\.\.?\/[^"']+["']/.test(source);
267
+ }
268
+ function isAutoHydratingClient(source) {
269
+ return source.includes("bootCodePlay") && source.includes("DOMContentLoaded");
270
+ }
271
+ function assertBrowserClientSource(source) {
272
+ if (!isAutoHydratingClient(source) || !isStandaloneBrowserClient(source)) throw new Error("@ox-content/code-play must emit a standalone ox-code-play.js that calls bootCodePlay(). Run the package build.");
273
+ return source;
274
+ }
275
+ //#endregion
276
+ //#region src/plugin-proxy.ts
277
+ const PROXY_MAX_BODY_BYTES = 262144;
278
+ var ProxyRequestError = class extends Error {
279
+ statusCode;
280
+ constructor(statusCode, message) {
281
+ super(message);
282
+ this.name = "ProxyRequestError";
283
+ this.statusCode = statusCode;
284
+ }
285
+ };
286
+ function assertHttpUrl(url) {
287
+ let parsed;
288
+ try {
289
+ parsed = new URL(url);
290
+ } catch {
291
+ throw new ProxyRequestError(400, "Invalid Code Play proxy destination.");
292
+ }
293
+ if (parsed.protocol !== "https:" && parsed.protocol !== "http:") throw new ProxyRequestError(400, "Code Play proxy destination must be http(s).");
294
+ if (parsed.username || parsed.password) throw new ProxyRequestError(400, "Code Play proxy destination must not include credentials.");
295
+ return parsed;
296
+ }
297
+ async function readLimitedBody(req, limit = PROXY_MAX_BODY_BYTES) {
298
+ if (req.method !== "POST") throw new ProxyRequestError(405, "Code Play proxy only accepts POST.");
299
+ const chunks = [];
300
+ let size = 0;
301
+ for await (const chunk of req) {
302
+ const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
303
+ size += buffer.byteLength;
304
+ if (size > limit) throw new ProxyRequestError(413, "Code Play proxy request body is too large.");
305
+ chunks.push(buffer);
306
+ }
307
+ return Buffer.concat(chunks);
308
+ }
309
+ async function typecheckProxy(req, res) {
310
+ try {
311
+ const body = JSON.parse((await readLimitedBody(req)).toString("utf8"));
312
+ const { createCodePlay } = await import("./client.mjs").then((n) => n.t);
313
+ const language = body.language ?? "typescript";
314
+ writeJson(res, 200, await createCodePlay({ languages: { [language]: true } }).createSession({
315
+ language,
316
+ code: body.code ?? "",
317
+ config: body.config
318
+ }).typecheck());
319
+ } catch (error) {
320
+ writeProxyError(res, error, 400, "Typecheck failed.");
321
+ }
322
+ }
323
+ async function proxy(req, res, url, contentType) {
324
+ try {
325
+ assertHttpUrl(url);
326
+ const body = await readLimitedBody(req);
327
+ const response = await fetch(url, {
328
+ method: "POST",
329
+ headers: { "Content-Type": contentType },
330
+ body: Uint8Array.from(body)
331
+ });
332
+ res.statusCode = response.status;
333
+ res.setHeader("Content-Type", response.headers.get("content-type") ?? "application/json");
334
+ res.end(await response.text());
335
+ } catch (error) {
336
+ writeProxyError(res, error, 502, "Code Play proxy failed.");
337
+ }
338
+ }
339
+ function writeProxyError(res, error, fallbackStatus, fallbackMessage) {
340
+ if (error instanceof ProxyRequestError) {
341
+ writeJson(res, error.statusCode, { error: error.message });
342
+ return;
343
+ }
344
+ writeJson(res, fallbackStatus, { error: fallbackMessage });
345
+ }
346
+ function writeJson(res, status, body) {
347
+ res.statusCode = status;
348
+ res.setHeader("Content-Type", "application/json; charset=utf-8");
349
+ res.end(JSON.stringify(body));
350
+ }
351
+ //#endregion
352
+ //#region src/plugin.ts
353
+ const VIRTUAL_ID = "virtual:ox-content/code-play";
354
+ const RESOLVED_VIRTUAL = `\0${VIRTUAL_ID}`;
355
+ const MARKDOWN_RE = /\.(?:md|markdown|mdx)(?:$|\?)/i;
356
+ function codePlay(options = {}) {
357
+ const resolved = resolveCodePlayOptions(options);
358
+ const explicitTypecheck = options.endpoints?.typecheck;
359
+ let base = resolved.base;
360
+ let command = "serve";
361
+ let outDir = resolved.outDir;
362
+ let root = process.cwd();
363
+ const enhanceOptions = (matchFences) => ({
364
+ scriptSrc: `${base}ox-code-play.js`,
365
+ decodePayload,
366
+ encodePayload,
367
+ matchFences,
368
+ endpoints: resolved.endpoints
369
+ });
370
+ return {
371
+ name: "@ox-content/code-play",
372
+ configResolved(config) {
373
+ command = config.command;
374
+ root = config.root;
375
+ base = resolved.base === "/" ? normalizeBase(config.base) : resolved.base;
376
+ outDir = resolved.outDir ?? config.build.outDir;
377
+ if (explicitTypecheck === void 0) {
378
+ if (command === "serve" && resolved.proxy) resolved.endpoints.typecheck = DEV_TYPECHECK_PATH;
379
+ else delete resolved.endpoints.typecheck;
380
+ }
381
+ },
382
+ resolveId(id) {
383
+ return id === VIRTUAL_ID ? RESOLVED_VIRTUAL : null;
384
+ },
385
+ load(id) {
386
+ if (id !== RESOLVED_VIRTUAL) return null;
387
+ return `export { hydrateCodePlay, mountCodePlay } from ${JSON.stringify(resolveHydrateSpecifier())};`;
388
+ },
389
+ transform(code, id) {
390
+ if (!MARKDOWN_RE.test(id)) {
391
+ if (code.includes("export const html = ") && code.includes("ox-code-play:")) return enhanceGeneratedModule(code, enhanceOptions());
392
+ return null;
393
+ }
394
+ const rewritten = rewritePlayFences(code, (fence) => {
395
+ const definition = resolveLanguage(fence.language);
396
+ if (!definition || !resolved.languages.has(definition.id)) return null;
397
+ return encodePayload(payloadFromFence(fence, resolved));
398
+ });
399
+ return rewritten === code ? null : rewritten;
400
+ },
401
+ configureServer(server) {
402
+ if (resolved.proxy) mountProxies(server, resolved.endpoints.rust, resolved.endpoints.go);
403
+ server.middlewares.use(async (req, res, next) => {
404
+ const urlPath = req.url?.split("?")[0] ?? "";
405
+ if (urlPath === `${base}ox-code-play.js`.replace(/\/{2,}/g, "/")) {
406
+ const file = resolveClientFile();
407
+ if (!file) return next();
408
+ res.setHeader("Content-Type", "text/javascript; charset=utf-8");
409
+ res.end(assertBrowserClientSource(await readFile(file, "utf8")));
410
+ return;
411
+ }
412
+ interceptHtml(res, (html) => enhanceHtmlForUrl(urlPath, html, root, resolved, enhanceOptions));
413
+ next();
414
+ });
415
+ },
416
+ async generateBundle() {
417
+ const file = resolveClientFile();
418
+ if (!file || command !== "build") return;
419
+ this.emitFile({
420
+ type: "asset",
421
+ fileName: "ox-code-play.js",
422
+ source: assertBrowserClientSource(await readFile(file, "utf8"))
423
+ });
424
+ },
425
+ async closeBundle() {
426
+ if (command !== "build") return;
427
+ const srcDir = path.resolve(root, resolved.srcDir ?? "docs");
428
+ const destination = path.resolve(root, outDir ?? "dist");
429
+ if (!existsSync(srcDir) || !existsSync(destination)) return;
430
+ await enhanceWrittenPages(srcDir, destination, resolved, enhanceOptions);
431
+ }
432
+ };
433
+ }
434
+ function interceptHtml(res, enhance) {
435
+ const originalEnd = res.end.bind(res);
436
+ res.end = ((chunk, encoding, cb) => {
437
+ const html = typeof chunk === "string" ? chunk : Buffer.isBuffer(chunk) ? chunk.toString("utf8") : void 0;
438
+ const type = String(res.getHeader("content-type") ?? "");
439
+ if (html && (type.includes("html") || html.includes("<pre"))) {
440
+ const next = enhance(html);
441
+ if (next && next !== html) {
442
+ if (typeof encoding === "function") return originalEnd(next, encoding);
443
+ return originalEnd(next, encoding ?? "utf8", cb);
444
+ }
445
+ }
446
+ if (typeof encoding === "function") return originalEnd(chunk, encoding);
447
+ return originalEnd(chunk, encoding ?? "utf8", cb);
448
+ });
449
+ }
450
+ function enhanceHtmlForUrl(urlPath, html, root, resolved, enhance) {
451
+ const markdownPath = urlToMarkdown(urlPath, root, resolved.srcDir ?? "docs", resolved.base);
452
+ if (!markdownPath || !existsSync(markdownPath)) return;
453
+ const source = readFileSync(markdownPath, "utf8");
454
+ const fences = [...parsePlayFences(source), ...parseCodePlayTags(source)].filter((fence) => {
455
+ const definition = resolveLanguage(fence.language);
456
+ return Boolean(definition && resolved.languages.has(definition.id));
457
+ });
458
+ if (fences.length === 0) return;
459
+ return enhancePlayHtml(html, enhance(fences.map((fence) => ({
460
+ language: fence.language,
461
+ code: fence.code,
462
+ payload: encodePayload(payloadFromFence(fence, resolved))
463
+ }))));
464
+ }
465
+ function urlToMarkdown(urlPath, root, srcDir, base) {
466
+ let relative = urlPath;
467
+ if (base !== "/" && relative.startsWith(base)) relative = relative.slice(base.length);
468
+ relative = relative.replace(/^\//, "").replace(/\.html$/, "");
469
+ if (!relative || relative.includes("..")) return;
470
+ return [path.resolve(root, srcDir, `${relative}.md`), path.resolve(root, srcDir, relative, "index.md")].find((candidate) => existsSync(candidate));
471
+ }
472
+ function mountProxies(server, rustUrl, goUrl) {
473
+ server.middlewares.use("/__ox-code-play/rust", (req, res) => {
474
+ proxy(req, res, rustUrl, "application/json");
475
+ });
476
+ server.middlewares.use("/__ox-code-play/go", (req, res) => {
477
+ proxy(req, res, goUrl, "application/x-www-form-urlencoded");
478
+ });
479
+ server.middlewares.use(DEV_TYPECHECK_PATH, (req, res) => {
480
+ typecheckProxy(req, res);
481
+ });
482
+ }
483
+ async function enhanceWrittenPages(srcDir, outDir, resolved, enhance) {
484
+ for (const file of walkFiles(srcDir)) {
485
+ if (!MARKDOWN_RE.test(file)) continue;
486
+ const source = await readFile(file, "utf8");
487
+ const fences = [...parsePlayFences(source), ...parseCodePlayTags(source)].filter((fence) => {
488
+ const definition = resolveLanguage(fence.language);
489
+ return Boolean(definition && resolved.languages.has(definition.id));
490
+ });
491
+ if (fences.length === 0) continue;
492
+ const htmlPath = guessHtmlPath(file, srcDir, outDir);
493
+ if (!htmlPath || !existsSync(htmlPath)) continue;
494
+ const html = await readFile(htmlPath, "utf8");
495
+ const enhanced = enhancePlayHtml(html, enhance(fences.map((fence) => ({
496
+ language: fence.language,
497
+ code: fence.code,
498
+ payload: encodePayload(payloadFromFence(fence, resolved))
499
+ }))));
500
+ if (enhanced !== html) await writeFile(htmlPath, enhanced);
501
+ }
502
+ }
503
+ function guessHtmlPath(file, srcDir, outDir) {
504
+ const relative = path.relative(srcDir, file).replace(/\.(?:md|markdown|mdx)$/i, "");
505
+ return [path.join(outDir, `${relative}.html`), path.join(outDir, relative, "index.html")].find((candidate) => existsSync(candidate));
506
+ }
507
+ function walkFiles(dir) {
508
+ const entries = readdirSync(dir);
509
+ const files = [];
510
+ for (const entry of entries) {
511
+ const full = path.join(dir, entry);
512
+ if (statSync(full).isDirectory()) files.push(...walkFiles(full));
513
+ else files.push(full);
514
+ }
515
+ return files;
516
+ }
517
+ function normalizeBase(base) {
518
+ if (!base || base === "/") return "/";
519
+ return base.endsWith("/") ? base : `${base}/`;
520
+ }
521
+ //#endregion
522
+ export { stripPlayMeta as a, rewritePlayFences as i, parseCodePlayTags as n, enhanceGeneratedModule as o, parsePlayFences as r, enhancePlayHtml as s, codePlay as t };
523
+
524
+ //# sourceMappingURL=plugin2.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin2.mjs","names":["readAttr"],"sources":["../src/payload-factory.ts","../src/html.ts","../src/markdown.ts","../src/plugin-client.ts","../src/plugin-proxy.ts","../src/plugin.ts"],"sourcesContent":["import { resolveLanguage } from \"./catalog\";\nimport type { ResolvedCodePlayOptions } from \"./config\";\nimport type { PlayFence } from \"./markdown\";\nimport type { LanguageDefinition, PlayPayload, PlaygroundEndpoints } from \"./types\";\n\nexport function payloadFromFence(fence: PlayFence, options: ResolvedCodePlayOptions): PlayPayload {\n const definition = resolveLanguage(fence.language);\n const enabled = definition ? options.languages.get(definition.id) : undefined;\n return {\n language: definition?.id ?? fence.language,\n code: fence.code,\n capabilities: {\n execute: enabled?.execute ?? Boolean(definition?.capabilities.execute),\n typecheck: payloadTypecheckEnabled(\n fence.typecheck,\n enabled?.typecheck,\n definition,\n options.endpoints,\n ),\n },\n config: { ...definition?.defaultConfig, ...enabled?.config },\n viewers: options.viewers,\n ui: options.ui,\n timeoutMs: options.timeoutMs,\n endpoints: options.endpoints,\n };\n}\n\n/** TypeScript typecheck in the browser needs a reachable endpoint; hide the dead button otherwise. */\nexport function payloadTypecheckEnabled(\n fenceTypecheck: boolean,\n enabledTypecheck: boolean | undefined,\n definition: LanguageDefinition | undefined,\n endpoints: PlaygroundEndpoints,\n): boolean {\n if (!(fenceTypecheck || enabledTypecheck)) {\n return false;\n }\n if (definition?.id === \"typescript\") {\n return Boolean(endpoints.typecheck);\n }\n return true;\n}\n","import { resolveLanguage } from \"./catalog\";\nimport { DEFAULT_ENDPOINTS, DEFAULT_VIEWERS } from \"./config\";\nimport { decodeHtml, escapeAttribute } from \"./escape\";\nimport { payloadTypecheckEnabled } from \"./payload-factory\";\nimport type { PlaygroundEndpoints, PlayPayload } from \"./types\";\n\nconst COMMENT_PATTERN = /<!--ox-code-play:([A-Za-z0-9+/=]+)-->\\s*(<pre\\b[\\s\\S]*?<\\/pre>)/gi;\nconst CODEPLAY_TAG_PATTERN = /<CodePlay\\b([^>]*)>([\\s\\S]*?)<\\/CodePlay>/gi;\nconst PRE_PATTERN = /<pre\\b[^>]*>\\s*<code\\b([^>]*)>([\\s\\S]*?)<\\/code>\\s*<\\/pre>/gi;\n\nexport interface HtmlEnhanceOptions {\n scriptSrc?: string;\n decodePayload: (value: string) => PlayPayload;\n encodePayload: (payload: PlayPayload) => string;\n matchFences?: Array<{ language: string; code: string; payload: string }>;\n endpoints?: PlaygroundEndpoints;\n}\n\nexport function enhancePlayHtml(html: string, options: HtmlEnhanceOptions): string {\n let next = wrapCommentedBlocks(html, options);\n next = upgradeCodePlayTags(next, options);\n if (options.matchFences?.length) {\n next = wrapMatchingFences(next, options.matchFences);\n }\n if (\n options.scriptSrc &&\n next.includes(\"data-ox-code-play\") &&\n !next.includes(options.scriptSrc)\n ) {\n next += `\\n<script type=\"module\" src=\"${escapeAttribute(options.scriptSrc)}\"></script>\\n`;\n }\n return next;\n}\n\nexport function enhanceGeneratedModule(source: string, options: HtmlEnhanceOptions): string {\n const marker = \"export const html = \";\n const start = source.indexOf(marker);\n if (start === -1) {\n return source;\n }\n const jsonStart = start + marker.length;\n if (source[jsonStart] !== '\"') {\n return source;\n }\n const parsed = readJsonString(source, jsonStart);\n if (!parsed) {\n return source;\n }\n const enhanced = enhancePlayHtml(parsed.value, options);\n return source.slice(0, jsonStart) + JSON.stringify(enhanced) + source.slice(parsed.end);\n}\n\nfunction wrapCommentedBlocks(html: string, _options: HtmlEnhanceOptions): string {\n return html.replace(COMMENT_PATTERN, (_all, payload: string, pre: string) => {\n return wrapWidget(payload, pre);\n });\n}\n\nfunction upgradeCodePlayTags(html: string, options: HtmlEnhanceOptions): string {\n return html.replace(CODEPLAY_TAG_PATTERN, (all, attrs: string, body: string) => {\n if (/\\bdata-ox-code-play=/.test(all)) {\n return all;\n }\n const language = readAttr(attrs, \"lang\") ?? readAttr(attrs, \"language\") ?? \"text\";\n const code = decodeHtml(body).replace(/^\\n/, \"\").replace(/\\n$/, \"\");\n const definition = resolveLanguage(language);\n const endpoints = options.endpoints ?? DEFAULT_ENDPOINTS;\n const payload = options.encodePayload({\n language: definition?.id ?? language,\n code,\n capabilities: {\n execute: true,\n typecheck: payloadTypecheckEnabled(\n /\\btypecheck\\b/i.test(attrs),\n undefined,\n definition,\n endpoints,\n ),\n },\n config: {},\n viewers: { ...DEFAULT_VIEWERS },\n ui: \"default\",\n timeoutMs: 10_000,\n endpoints,\n });\n return wrapWidget(\n payload,\n `<pre><code class=\"language-${escapeAttribute(language)}\">${body}</code></pre>`,\n );\n });\n}\n\nfunction wrapMatchingFences(\n html: string,\n matches: Array<{ language: string; code: string; payload: string }>,\n): string {\n const unused = matches.map((item) => ({ ...item, used: false }));\n return html.replace(PRE_PATTERN, (all, attrs: string, body: string) => {\n const className = readAttr(attrs, \"class\") ?? \"\";\n const language = className\n .split(/\\s+/)\n .find((token) => token.startsWith(\"language-\"))\n ?.slice(\"language-\".length);\n const code = normalizeCode(decodeHtml(stripTags(body)));\n const match = unused.find(\n (item) =>\n !item.used && aliasesEqual(item.language, language) && normalizeCode(item.code) === code,\n );\n if (!match) {\n return all;\n }\n match.used = true;\n return wrapWidget(match.payload, all);\n });\n}\n\nfunction wrapWidget(payload: string, inner: string): string {\n return `<ox-code-play data-ox-code-play=\"${escapeAttribute(payload)}\">${inner}</ox-code-play>`;\n}\n\nfunction readJsonString(source: string, start: number): { value: string; end: number } | undefined {\n try {\n const raw = sliceJsonString(source, start);\n return { value: JSON.parse(raw) as string, end: start + raw.length };\n } catch {\n return undefined;\n }\n}\n\nfunction sliceJsonString(source: string, start: number): string {\n let end = start + 1;\n let escaped = false;\n while (end < source.length) {\n const char = source[end];\n if (escaped) {\n escaped = false;\n } else if (char === \"\\\\\") {\n escaped = true;\n } else if (char === '\"') {\n return source.slice(start, end + 1);\n }\n end += 1;\n }\n throw new Error(\"Unterminated HTML JSON string.\");\n}\n\nfunction readAttr(attrs: string, name: string): string | undefined {\n const match = new RegExp(`(?:^|\\\\s)${name}\\\\s*=\\\\s*\"([^\"]+)\"`, \"i\").exec(attrs);\n return match?.[1];\n}\n\nfunction stripTags(value: string): string {\n return value.replace(/<[^>]+>/g, \"\");\n}\n\nfunction normalizeCode(value: string): string {\n return value.replace(/\\r\\n/g, \"\\n\").replace(/\\n$/, \"\");\n}\n\nfunction aliasesEqual(left: string | undefined, right: string | undefined): boolean {\n if (!left || !right) {\n return false;\n }\n return left.toLowerCase() === right.toLowerCase();\n}\n","export interface PlayFence {\n language: string;\n meta: string;\n code: string;\n raw: string;\n start: number;\n end: number;\n typecheck: boolean;\n}\n\nexport interface ParsedFence {\n language: string;\n meta: string;\n code: string;\n raw: string;\n start: number;\n end: number;\n indent: string;\n marker: string;\n}\n\nconst FENCE_OPEN = /^( {0,3})(`{3,}|~{3,})([^\\n]*)$/;\n\nexport function parseTopLevelFences(source: string): ParsedFence[] {\n const lines = source.split(\"\\n\");\n const fences: ParsedFence[] = [];\n let index = 0;\n let offset = 0;\n\n while (index < lines.length) {\n const line = lines[index] ?? \"\";\n const open = FENCE_OPEN.exec(line);\n if (!open) {\n offset += line.length + 1;\n index += 1;\n continue;\n }\n\n const indent = open[1] ?? \"\";\n const marker = open[2] ?? \"```\";\n const info = (open[3] ?? \"\").trim();\n const [language = \"\", ...metaParts] = splitInfo(info);\n const start = offset;\n index += 1;\n offset += line.length + 1;\n const body: string[] = [];\n\n while (index < lines.length) {\n const candidate = lines[index] ?? \"\";\n const close = new RegExp(`^ {0,3}${escapeRegExp(marker)}[ \\t]*$`).exec(candidate);\n if (close) {\n const raw = `${line}\\n${body.join(\"\\n\")}${body.length > 0 ? \"\\n\" : \"\"}${candidate}`;\n fences.push({\n language,\n meta: metaParts.join(\" \"),\n code: body.join(\"\\n\"),\n raw,\n start,\n end: start + raw.length,\n indent,\n marker,\n });\n offset += candidate.length + 1;\n index += 1;\n break;\n }\n body.push(candidate);\n offset += candidate.length + 1;\n index += 1;\n }\n }\n\n return fences;\n}\n\nexport function parsePlayFences(source: string): PlayFence[] {\n return parseTopLevelFences(source)\n .filter((fence) => hasToken(fence.meta, \"play\"))\n .map((fence) => ({\n language: fence.language,\n meta: fence.meta,\n code: fence.code,\n raw: fence.raw,\n start: fence.start,\n end: fence.end,\n typecheck: hasToken(fence.meta, \"typecheck\"),\n }));\n}\n\nexport function stripPlayMeta(meta: string): string {\n return meta\n .split(/\\s+/)\n .filter(\n (token) => token && token !== \"play\" && token !== \"typecheck\" && !token.startsWith(\"play-\"),\n )\n .join(\" \");\n}\n\nexport function rewritePlayFences(\n source: string,\n encode: (fence: PlayFence) => string | null,\n): string {\n const fences = parsePlayFences(source);\n if (fences.length === 0) {\n return source;\n }\n\n let cursor = 0;\n let output = \"\";\n for (const fence of fences) {\n output += source.slice(cursor, fence.start);\n const encoded = encode(fence);\n if (encoded === null) {\n output += source.slice(fence.start, fence.end);\n } else {\n const cleanedMeta = stripPlayMeta(fence.meta);\n const info = [fence.language, cleanedMeta].filter(Boolean).join(\" \");\n output += `<!--ox-code-play:${encoded}-->\\n\\`\\`\\`${info}\\n${fence.code}\\n\\`\\`\\``;\n }\n cursor = fence.end;\n }\n output += source.slice(cursor);\n return output;\n}\n\nexport function parseCodePlayTags(source: string): PlayFence[] {\n const tags: PlayFence[] = [];\n const pattern = /<CodePlay\\b([^>]*)>([\\s\\S]*?)<\\/CodePlay>/gi;\n for (const match of source.matchAll(pattern)) {\n const attrs = match[1] ?? \"\";\n const language = readAttr(attrs, \"lang\") ?? readAttr(attrs, \"language\") ?? \"text\";\n tags.push({\n language,\n meta: \"play\",\n code: stripIndent((match[2] ?? \"\").replace(/^\\n/, \"\").replace(/\\n$/, \"\")),\n raw: match[0] ?? \"\",\n start: match.index ?? 0,\n end: (match.index ?? 0) + (match[0]?.length ?? 0),\n typecheck: /\\btypecheck\\b/i.test(attrs),\n });\n }\n return tags;\n}\n\nfunction splitInfo(info: string): string[] {\n return info.trim().split(/\\s+/).filter(Boolean);\n}\n\nfunction hasToken(meta: string, token: string): boolean {\n return meta.split(/\\s+/).includes(token);\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nfunction readAttr(attrs: string, name: string): string | undefined {\n const match = new RegExp(`(?:^|\\\\s)${name}\\\\s*=\\\\s*\"([^\"]+)\"`, \"i\").exec(attrs);\n return match?.[1];\n}\n\nfunction stripIndent(value: string): string {\n const lines = value.split(\"\\n\");\n const indents = lines\n .filter((line) => line.trim())\n .map((line) => line.match(/^ */)?.[0].length ?? 0);\n const indent = indents.length > 0 ? Math.min(...indents) : 0;\n return lines.map((line) => line.slice(indent)).join(\"\\n\");\n}\n","import { existsSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\n\nexport const CLIENT_FILE_CANDIDATES = [\n \"browser.mjs\",\n \"browser.js\",\n \"hydrate.mjs\",\n \"hydrate.js\",\n] as const;\n\nexport function resolveClientFile(baseUrl = import.meta.url): string | undefined {\n return CLIENT_FILE_CANDIDATES.map((name) => fileURLToPath(new URL(`./${name}`, baseUrl))).find(\n (candidate) => existsSync(candidate),\n );\n}\n\nexport function resolveHydrateSpecifier(baseUrl = import.meta.url): string {\n return resolveClientFile(baseUrl) ?? fileURLToPath(new URL(\"./hydrate.ts\", baseUrl));\n}\n\nexport function isStandaloneBrowserClient(source: string): boolean {\n return (\n !/\\bfrom\\s+[\"']\\.\\.?\\/[^\"']+[\"']/.test(source) &&\n !/\\bimport\\s*\\(\\s*[\"']\\.\\.?\\/[^\"']+[\"']/.test(source)\n );\n}\n\nexport function isAutoHydratingClient(source: string): boolean {\n return source.includes(\"bootCodePlay\") && source.includes(\"DOMContentLoaded\");\n}\n\nexport function assertBrowserClientSource(source: string): string {\n if (!isAutoHydratingClient(source) || !isStandaloneBrowserClient(source)) {\n throw new Error(\n \"@ox-content/code-play must emit a standalone ox-code-play.js that calls bootCodePlay(). Run the package build.\",\n );\n }\n return source;\n}\n","import type { IncomingMessage, ServerResponse } from \"node:http\";\n\nexport const PROXY_MAX_BODY_BYTES = 256 * 1024;\n\nexport class ProxyRequestError extends Error {\n readonly statusCode: number;\n\n constructor(statusCode: number, message: string) {\n super(message);\n this.name = \"ProxyRequestError\";\n this.statusCode = statusCode;\n }\n}\n\nexport function assertHttpUrl(url: string): URL {\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n throw new ProxyRequestError(400, \"Invalid Code Play proxy destination.\");\n }\n if (parsed.protocol !== \"https:\" && parsed.protocol !== \"http:\") {\n throw new ProxyRequestError(400, \"Code Play proxy destination must be http(s).\");\n }\n if (parsed.username || parsed.password) {\n throw new ProxyRequestError(400, \"Code Play proxy destination must not include credentials.\");\n }\n return parsed;\n}\n\nexport async function readLimitedBody(\n req: IncomingMessage,\n limit = PROXY_MAX_BODY_BYTES,\n): Promise<Buffer> {\n if (req.method !== \"POST\") {\n throw new ProxyRequestError(405, \"Code Play proxy only accepts POST.\");\n }\n const chunks: Buffer[] = [];\n let size = 0;\n for await (const chunk of req) {\n const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);\n size += buffer.byteLength;\n if (size > limit) {\n throw new ProxyRequestError(413, \"Code Play proxy request body is too large.\");\n }\n chunks.push(buffer);\n }\n return Buffer.concat(chunks);\n}\n\nexport async function typecheckProxy(req: IncomingMessage, res: ServerResponse): Promise<void> {\n try {\n const body = JSON.parse((await readLimitedBody(req)).toString(\"utf8\")) as {\n language?: string;\n code?: string;\n config?: Record<string, unknown>;\n };\n const { createCodePlay } = await import(\"./client\");\n const language = body.language ?? \"typescript\";\n const play = createCodePlay({ languages: { [language]: true } });\n const result = await play\n .createSession({ language, code: body.code ?? \"\", config: body.config })\n .typecheck();\n writeJson(res, 200, result);\n } catch (error) {\n writeProxyError(res, error, 400, \"Typecheck failed.\");\n }\n}\n\nexport async function proxy(\n req: IncomingMessage,\n res: ServerResponse,\n url: string,\n contentType: string,\n): Promise<void> {\n try {\n assertHttpUrl(url);\n const body = await readLimitedBody(req);\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": contentType },\n body: Uint8Array.from(body),\n });\n res.statusCode = response.status;\n res.setHeader(\"Content-Type\", response.headers.get(\"content-type\") ?? \"application/json\");\n res.end(await response.text());\n } catch (error) {\n writeProxyError(res, error, 502, \"Code Play proxy failed.\");\n }\n}\n\nexport function writeProxyError(\n res: ServerResponse,\n error: unknown,\n fallbackStatus: number,\n fallbackMessage: string,\n): void {\n if (error instanceof ProxyRequestError) {\n writeJson(res, error.statusCode, { error: error.message });\n return;\n }\n writeJson(res, fallbackStatus, { error: fallbackMessage });\n}\n\nfunction writeJson(res: ServerResponse, status: number, body: unknown): void {\n res.statusCode = status;\n res.setHeader(\"Content-Type\", \"application/json; charset=utf-8\");\n res.end(JSON.stringify(body));\n}\n","import { readFile, writeFile } from \"node:fs/promises\";\nimport { existsSync, readFileSync, readdirSync, statSync } from \"node:fs\";\nimport path from \"node:path\";\nimport type { Plugin, ViteDevServer } from \"vite\";\nimport { resolveLanguage } from \"./catalog\";\nimport {\n DEV_TYPECHECK_PATH,\n resolveCodePlayOptions,\n type RawCodePlayOptions,\n type ResolvedCodePlayOptions,\n} from \"./config\";\nimport { enhanceGeneratedModule, enhancePlayHtml, type HtmlEnhanceOptions } from \"./html\";\nimport { parseCodePlayTags, parsePlayFences, rewritePlayFences } from \"./markdown\";\nimport { decodePayload, encodePayload } from \"./payload\";\nimport { payloadFromFence } from \"./payload-factory\";\nimport {\n assertBrowserClientSource,\n resolveClientFile,\n resolveHydrateSpecifier,\n} from \"./plugin-client\";\nimport { proxy, typecheckProxy } from \"./plugin-proxy\";\n\nexport type CodePlayPluginOptions = RawCodePlayOptions;\n\nconst VIRTUAL_ID = \"virtual:ox-content/code-play\";\nconst RESOLVED_VIRTUAL = `\\0${VIRTUAL_ID}`;\nconst MARKDOWN_RE = /\\.(?:md|markdown|mdx)(?:$|\\?)/i;\n\nexport function codePlay(options: CodePlayPluginOptions = {}): Plugin {\n const resolved = resolveCodePlayOptions(options);\n const explicitTypecheck = options.endpoints?.typecheck;\n let base = resolved.base;\n let command: \"build\" | \"serve\" = \"serve\";\n let outDir = resolved.outDir;\n let root = process.cwd();\n\n const enhanceOptions = (\n matchFences?: Array<{ language: string; code: string; payload: string }>,\n ) => ({\n scriptSrc: `${base}ox-code-play.js`,\n decodePayload,\n encodePayload,\n matchFences,\n endpoints: resolved.endpoints,\n });\n\n return {\n name: \"@ox-content/code-play\",\n\n configResolved(config) {\n command = config.command;\n root = config.root;\n base = resolved.base === \"/\" ? normalizeBase(config.base) : resolved.base;\n outDir = resolved.outDir ?? config.build.outDir;\n if (explicitTypecheck === undefined) {\n if (command === \"serve\" && resolved.proxy) {\n resolved.endpoints.typecheck = DEV_TYPECHECK_PATH;\n } else {\n delete resolved.endpoints.typecheck;\n }\n }\n },\n\n resolveId(id) {\n return id === VIRTUAL_ID ? RESOLVED_VIRTUAL : null;\n },\n\n load(id) {\n if (id !== RESOLVED_VIRTUAL) {\n return null;\n }\n return `export { hydrateCodePlay, mountCodePlay } from ${JSON.stringify(resolveHydrateSpecifier())};`;\n },\n\n transform(code, id) {\n if (!MARKDOWN_RE.test(id)) {\n if (code.includes(\"export const html = \") && code.includes(\"ox-code-play:\")) {\n return enhanceGeneratedModule(code, enhanceOptions());\n }\n return null;\n }\n const rewritten = rewritePlayFences(code, (fence) => {\n const definition = resolveLanguage(fence.language);\n if (!definition || !resolved.languages.has(definition.id)) {\n return null;\n }\n return encodePayload(payloadFromFence(fence, resolved));\n });\n return rewritten === code ? null : rewritten;\n },\n\n configureServer(server) {\n if (resolved.proxy) {\n mountProxies(server, resolved.endpoints.rust, resolved.endpoints.go);\n }\n server.middlewares.use(async (req, res, next) => {\n const urlPath = req.url?.split(\"?\")[0] ?? \"\";\n if (urlPath === `${base}ox-code-play.js`.replace(/\\/{2,}/g, \"/\")) {\n const file = resolveClientFile();\n if (!file) {\n return next();\n }\n res.setHeader(\"Content-Type\", \"text/javascript; charset=utf-8\");\n res.end(assertBrowserClientSource(await readFile(file, \"utf8\")));\n return;\n }\n interceptHtml(res, (html) =>\n enhanceHtmlForUrl(urlPath, html, root, resolved, enhanceOptions),\n );\n next();\n });\n },\n\n async generateBundle() {\n const file = resolveClientFile();\n if (!file || command !== \"build\") {\n return;\n }\n this.emitFile({\n type: \"asset\",\n fileName: \"ox-code-play.js\",\n source: assertBrowserClientSource(await readFile(file, \"utf8\")),\n });\n },\n\n async closeBundle() {\n if (command !== \"build\") {\n return;\n }\n const srcDir = path.resolve(root, resolved.srcDir ?? \"docs\");\n const destination = path.resolve(root, outDir ?? \"dist\");\n if (!existsSync(srcDir) || !existsSync(destination)) {\n return;\n }\n await enhanceWrittenPages(srcDir, destination, resolved, enhanceOptions);\n },\n };\n}\n\nfunction interceptHtml(\n res: import(\"node:http\").ServerResponse,\n enhance: (html: string) => string | undefined,\n): void {\n const originalEnd = res.end.bind(res);\n res.end = ((chunk?: unknown, encoding?: BufferEncoding | (() => void), cb?: () => void) => {\n const html =\n typeof chunk === \"string\"\n ? chunk\n : Buffer.isBuffer(chunk)\n ? chunk.toString(\"utf8\")\n : undefined;\n const type = String(res.getHeader(\"content-type\") ?? \"\");\n if (html && (type.includes(\"html\") || html.includes(\"<pre\"))) {\n const next = enhance(html);\n if (next && next !== html) {\n if (typeof encoding === \"function\") {\n return originalEnd(next, encoding);\n }\n return originalEnd(next, encoding ?? \"utf8\", cb);\n }\n }\n if (typeof encoding === \"function\") {\n return originalEnd(chunk as never, encoding);\n }\n return originalEnd(chunk as never, encoding ?? \"utf8\", cb);\n }) as typeof res.end;\n}\n\nfunction enhanceHtmlForUrl(\n urlPath: string,\n html: string,\n root: string,\n resolved: ResolvedCodePlayOptions,\n enhance: (\n matchFences?: Array<{ language: string; code: string; payload: string }>,\n ) => HtmlEnhanceOptions,\n): string | undefined {\n const markdownPath = urlToMarkdown(urlPath, root, resolved.srcDir ?? \"docs\", resolved.base);\n if (!markdownPath || !existsSync(markdownPath)) {\n return undefined;\n }\n const source = readFileSync(markdownPath, \"utf8\");\n const fences = [...parsePlayFences(source), ...parseCodePlayTags(source)].filter((fence) => {\n const definition = resolveLanguage(fence.language);\n return Boolean(definition && resolved.languages.has(definition.id));\n });\n if (fences.length === 0) {\n return undefined;\n }\n return enhancePlayHtml(\n html,\n enhance(\n fences.map((fence) => ({\n language: fence.language,\n code: fence.code,\n payload: encodePayload(payloadFromFence(fence, resolved)),\n })),\n ),\n );\n}\n\nfunction urlToMarkdown(\n urlPath: string,\n root: string,\n srcDir: string,\n base: string,\n): string | undefined {\n let relative = urlPath;\n if (base !== \"/\" && relative.startsWith(base)) {\n relative = relative.slice(base.length);\n }\n relative = relative.replace(/^\\//, \"\").replace(/\\.html$/, \"\");\n if (!relative || relative.includes(\"..\")) {\n return undefined;\n }\n const candidates = [\n path.resolve(root, srcDir, `${relative}.md`),\n path.resolve(root, srcDir, relative, \"index.md\"),\n ];\n return candidates.find((candidate) => existsSync(candidate));\n}\n\nfunction mountProxies(server: ViteDevServer, rustUrl: string, goUrl: string): void {\n server.middlewares.use(\"/__ox-code-play/rust\", (req, res) => {\n void proxy(req, res, rustUrl, \"application/json\");\n });\n server.middlewares.use(\"/__ox-code-play/go\", (req, res) => {\n void proxy(req, res, goUrl, \"application/x-www-form-urlencoded\");\n });\n server.middlewares.use(DEV_TYPECHECK_PATH, (req, res) => {\n void typecheckProxy(req, res);\n });\n}\n\nasync function enhanceWrittenPages(\n srcDir: string,\n outDir: string,\n resolved: ResolvedCodePlayOptions,\n enhance: (\n matchFences?: Array<{ language: string; code: string; payload: string }>,\n ) => HtmlEnhanceOptions,\n): Promise<void> {\n for (const file of walkFiles(srcDir)) {\n if (!MARKDOWN_RE.test(file)) {\n continue;\n }\n const source = await readFile(file, \"utf8\");\n const fences = [...parsePlayFences(source), ...parseCodePlayTags(source)].filter((fence) => {\n const definition = resolveLanguage(fence.language);\n return Boolean(definition && resolved.languages.has(definition.id));\n });\n if (fences.length === 0) {\n continue;\n }\n const htmlPath = guessHtmlPath(file, srcDir, outDir);\n if (!htmlPath || !existsSync(htmlPath)) {\n continue;\n }\n const html = await readFile(htmlPath, \"utf8\");\n const enhanced = enhancePlayHtml(\n html,\n enhance(\n fences.map((fence) => ({\n language: fence.language,\n code: fence.code,\n payload: encodePayload(payloadFromFence(fence, resolved)),\n })),\n ),\n );\n if (enhanced !== html) {\n await writeFile(htmlPath, enhanced);\n }\n }\n}\n\nfunction guessHtmlPath(file: string, srcDir: string, outDir: string): string | undefined {\n const relative = path.relative(srcDir, file).replace(/\\.(?:md|markdown|mdx)$/i, \"\");\n const candidates = [\n path.join(outDir, `${relative}.html`),\n path.join(outDir, relative, \"index.html\"),\n ];\n return candidates.find((candidate) => existsSync(candidate));\n}\n\nfunction walkFiles(dir: string): string[] {\n const entries = readdirSync(dir);\n const files: string[] = [];\n for (const entry of entries) {\n const full = path.join(dir, entry);\n const stat = statSync(full);\n if (stat.isDirectory()) {\n files.push(...walkFiles(full));\n } else {\n files.push(full);\n }\n }\n return files;\n}\n\nfunction normalizeBase(base: string): string {\n if (!base || base === \"/\") {\n return \"/\";\n }\n return base.endsWith(\"/\") ? base : `${base}/`;\n}\n\nexport type { CodePlayPluginOptions as CodePlayOptions };\n"],"mappings":"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"}