hono-decks 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ja.md +35 -1
- package/README.md +46 -2
- package/dist/adapters/hono-markdown.d.ts +39 -0
- package/dist/adapters/hono-markdown.js +47 -0
- package/dist/advanced.d.ts +5 -2
- package/dist/bin.js +77 -29
- package/dist/cli.js +77 -29
- package/dist/{init-vite-mLg3XlcN.js → init-vite-EA_L4k2H.js} +35 -27
- package/dist/mod.d.ts +5 -2
- package/dist/node.d.ts +115 -112
- package/dist/node.js +76 -28
- package/dist/vite.js +76 -28
- package/package.json +5 -1
package/dist/vite.js
CHANGED
|
@@ -7,10 +7,10 @@ import { unified } from "unified";
|
|
|
7
7
|
import remarkGfm from "remark-gfm";
|
|
8
8
|
import remarkMdx from "remark-mdx";
|
|
9
9
|
import remarkParse from "remark-parse";
|
|
10
|
-
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
11
10
|
import { compile } from "@mdx-js/mdx";
|
|
12
11
|
import remarkDirective from "remark-directive";
|
|
13
12
|
import { codeToHtml } from "shiki";
|
|
13
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
14
14
|
import { existsSync } from "node:fs";
|
|
15
15
|
import { lookup } from "node:dns/promises";
|
|
16
16
|
import { isIP } from "node:net";
|
|
@@ -1505,29 +1505,20 @@ function extractDeckPrelude(source) {
|
|
|
1505
1505
|
};
|
|
1506
1506
|
}
|
|
1507
1507
|
//#endregion
|
|
1508
|
-
//#region src/node/
|
|
1509
|
-
|
|
1510
|
-
async function compileVoidMarkdownDecks(input) {
|
|
1508
|
+
//#region src/node/markdown-decks.ts
|
|
1509
|
+
async function compileMarkdownDecks(input, adapter) {
|
|
1511
1510
|
const markdownEntries = input.decks.filter((entry) => entry.sourcePath.endsWith(".md"));
|
|
1512
1511
|
const mdx = await compileMdxModuleDecks({
|
|
1513
1512
|
...input,
|
|
1514
1513
|
decks: input.decks.filter((entry) => !entry.sourcePath.endsWith(".md"))
|
|
1515
1514
|
});
|
|
1516
1515
|
if (!markdownEntries.length) return mdx;
|
|
1517
|
-
let compiler;
|
|
1518
|
-
try {
|
|
1519
|
-
compiler = await import(pathToFileURL(createRequire(resolve(input.cwd ?? process.cwd(), "package.json")).resolve("void-plugin-hono-jsx/markdown/compiler")).href);
|
|
1520
|
-
if (typeof (compiler.compileMarkdownModule ?? compiler.compileStaticMarkdown) !== "function" || typeof (compiler.readMarkdownModule ?? compiler.readStaticMarkdown) !== "function") throw new Error("Missing standalone compiler API");
|
|
1521
|
-
} catch (error) {
|
|
1522
|
-
throw new Error("Void Markdown requires void-plugin-hono-jsx with the public /markdown/compiler API and its Markdown peers installed in the app.", { cause: error });
|
|
1523
|
-
}
|
|
1524
|
-
const readModule = compiler.readMarkdownModule ?? compiler.readStaticMarkdown;
|
|
1525
|
-
const compileModule = compiler.compileMarkdownModule ?? compiler.compileStaticMarkdown;
|
|
1526
1516
|
const decks = [...mdx.decks];
|
|
1527
1517
|
const clients = /* @__PURE__ */ new Set();
|
|
1528
1518
|
const markdownIslands = /* @__PURE__ */ new Map();
|
|
1529
1519
|
for (const entry of markdownEntries) try {
|
|
1530
|
-
const
|
|
1520
|
+
const source = await input.readText(entry.sourcePath);
|
|
1521
|
+
const parsed = adapter.read(source);
|
|
1531
1522
|
if (input.clientComponentIds?.[entry.slug] && Object.keys(input.clientComponentIds[entry.slug]).length) throw new Error("Void Markdown slides support static components only; use MDX for hono-decks client components.");
|
|
1532
1523
|
const warnings = [];
|
|
1533
1524
|
const meta = toDeckFrontmatter(parsed.frontmatter, warnings);
|
|
@@ -1548,12 +1539,13 @@ async function compileVoidMarkdownDecks(input) {
|
|
|
1548
1539
|
const slides = [];
|
|
1549
1540
|
for (const [index, slideSource] of splitMarkdownSlides(parsed.content).entries()) {
|
|
1550
1541
|
const prelude = parsed.script ? `<script>\n${parsed.script}\n<\/script>\n` : "";
|
|
1551
|
-
const slide =
|
|
1542
|
+
const slide = adapter.read(prelude + slideSource);
|
|
1552
1543
|
const path = `${input.outDir}/decks/${entry.slug}/slide-${index}.ts`;
|
|
1553
|
-
const
|
|
1544
|
+
const rewritten = rewriteAssetUrls(`${prelude}---\n${JSON.stringify({
|
|
1554
1545
|
...parsed.frontmatter,
|
|
1555
1546
|
...slide.frontmatter
|
|
1556
|
-
})}\n---\n${slide.content}`, assets)
|
|
1547
|
+
})}\n---\n${slide.content}`, assets);
|
|
1548
|
+
const result = await adapter.compile(rewritten, { sourcePath: resolve(input.cwd ?? process.cwd(), entry.sourcePath) });
|
|
1557
1549
|
clientEntryRequired ||= Boolean(result.clientCode || result.islands?.length);
|
|
1558
1550
|
if (result.clientCode) clients.add(result.clientCode);
|
|
1559
1551
|
for (const island of result.islands ?? []) markdownIslands.set(island.id, island);
|
|
@@ -1603,6 +1595,7 @@ async function compileVoidMarkdownDecks(input) {
|
|
|
1603
1595
|
decks,
|
|
1604
1596
|
routerModule: emitModuleDecksRouter({ decks }),
|
|
1605
1597
|
clientCode: [...clients].join("\n"),
|
|
1598
|
+
clientModules: [adapter.client([...markdownIslands.values()])].filter(Boolean),
|
|
1606
1599
|
markdownIslands: [...markdownIslands.values()]
|
|
1607
1600
|
};
|
|
1608
1601
|
}
|
|
@@ -1639,6 +1632,64 @@ function splitMarkdownSlides(source) {
|
|
|
1639
1632
|
return splitSlideSources(protectedLines.join("\n")).map((slide) => slide.replace(new RegExp(`${prefix}(\\d+)_END`, "g"), (_, id) => fences[Number(id)]));
|
|
1640
1633
|
}
|
|
1641
1634
|
//#endregion
|
|
1635
|
+
//#region src/adapters/hono-markdown.ts
|
|
1636
|
+
/** Node-only bridge. Existing Void configs retain their original compiler/runtime pair. */
|
|
1637
|
+
async function createHonoMarkdownAdapter(cwd, legacy = false, options) {
|
|
1638
|
+
const require = createRequire(resolve(cwd, "package.json"));
|
|
1639
|
+
const entry = legacy ? "void-plugin-hono-jsx/markdown/compiler" : "@ts-76/hono-markdown/compiler";
|
|
1640
|
+
let compiler;
|
|
1641
|
+
try {
|
|
1642
|
+
compiler = await import(pathToFileURL(require.resolve(entry)).href);
|
|
1643
|
+
} catch (cause) {
|
|
1644
|
+
throw new Error(`Hono Markdown requires ${legacy ? "its public /markdown/compiler API" : "@ts-76/hono-markdown/compiler"} and Markdown peers installed in the app.`, { cause });
|
|
1645
|
+
}
|
|
1646
|
+
const read = compiler.readMarkdownModule ?? compiler.readStaticMarkdown;
|
|
1647
|
+
const compile = compiler.compileMarkdownModule ?? compiler.compileStaticMarkdown;
|
|
1648
|
+
if (typeof read !== "function" || typeof compile !== "function") throw new Error("Missing standalone compiler API");
|
|
1649
|
+
const runtime = entry.startsWith("void-plugin") ? "void-plugin-hono-jsx/markdown/client" : "@ts-76/hono-markdown/client";
|
|
1650
|
+
return {
|
|
1651
|
+
read,
|
|
1652
|
+
compile: (source, input) => compile(source, {
|
|
1653
|
+
...input,
|
|
1654
|
+
options
|
|
1655
|
+
}),
|
|
1656
|
+
client: (islands) => emitMarkdownClient(islands, runtime)
|
|
1657
|
+
};
|
|
1658
|
+
}
|
|
1659
|
+
function emitMarkdownClient(islands, runtime) {
|
|
1660
|
+
if (!islands.length) return "";
|
|
1661
|
+
const literal = (value) => JSON.stringify(value).replace(/</g, "\\u003c");
|
|
1662
|
+
return `import { hydrateMarkdownIslands } from ${literal(runtime)};
|
|
1663
|
+
hydrateMarkdownIslands({ ${islands.map((island) => `${literal(island.id)}: () => import(${literal(island.modulePath)})`).join(",")} }, {
|
|
1664
|
+
ready(element, start) {
|
|
1665
|
+
const slide = element.closest('section[data-slide-state]');
|
|
1666
|
+
if (!slide || slide.dataset.slideState === 'active') { start(); return; }
|
|
1667
|
+
const observer = new MutationObserver(() => {
|
|
1668
|
+
if (slide.dataset.slideState === 'active') { observer.disconnect(); start(); }
|
|
1669
|
+
});
|
|
1670
|
+
observer.observe(slide, { attributes: true, attributeFilter: ['data-slide-state'] });
|
|
1671
|
+
}
|
|
1672
|
+
});`;
|
|
1673
|
+
}
|
|
1674
|
+
//#endregion
|
|
1675
|
+
//#region src/node/markdown-adapter.ts
|
|
1676
|
+
async function loadMarkdownAdapter(selection, cwd) {
|
|
1677
|
+
if (selection === "void") return createHonoMarkdownAdapter(cwd, true);
|
|
1678
|
+
if (selection.adapter === "hono-decks/adapters/hono-markdown") return createHonoMarkdownAdapter(cwd, false, selection.options);
|
|
1679
|
+
const module = await import(pathToFileURL(createRequire(resolve(cwd, "package.json")).resolve(selection.adapter)).href);
|
|
1680
|
+
if (typeof module.createMarkdownAdapter !== "function") throw new Error("Markdown adapter must export createMarkdownAdapter.");
|
|
1681
|
+
const adapter = await module.createMarkdownAdapter({
|
|
1682
|
+
cwd,
|
|
1683
|
+
options: selection.options
|
|
1684
|
+
});
|
|
1685
|
+
if (![
|
|
1686
|
+
adapter?.read,
|
|
1687
|
+
adapter?.compile,
|
|
1688
|
+
adapter?.client
|
|
1689
|
+
].every((value) => typeof value === "function")) throw new Error("Markdown adapter must provide read, compile and client functions.");
|
|
1690
|
+
return adapter;
|
|
1691
|
+
}
|
|
1692
|
+
//#endregion
|
|
1642
1693
|
//#region src/node/client-entry.ts
|
|
1643
1694
|
async function discoverClientComponentIds(input) {
|
|
1644
1695
|
const result = {};
|
|
@@ -1659,12 +1710,11 @@ async function emitClientEntryModule(input) {
|
|
|
1659
1710
|
registrations.push(`${JSON.stringify(clientId)}: ${localName}`);
|
|
1660
1711
|
}
|
|
1661
1712
|
}
|
|
1662
|
-
const
|
|
1663
|
-
if (registrations.length === 0 &&
|
|
1713
|
+
const clientModules = input.clientModules ?? [];
|
|
1714
|
+
if (registrations.length === 0 && clientModules.length === 0) return `export const decksClientEntry = ${JSON.stringify(input.extraCode ?? "")};\n`;
|
|
1664
1715
|
const result = await build({
|
|
1665
1716
|
stdin: {
|
|
1666
|
-
contents: `${
|
|
1667
|
-
hydrateMarkdownIslands({ ${markdown.map((entry) => `${javascriptString(entry.id)}: () => import(${javascriptString(entry.modulePath)})`).join(",")} });` : ""}
|
|
1717
|
+
contents: `${clientModules.join("\n")}
|
|
1668
1718
|
import { hydrateSlideIslands } from "hono-decks/client";
|
|
1669
1719
|
${imports.join("\n")}
|
|
1670
1720
|
|
|
@@ -1741,9 +1791,6 @@ function hashString(value) {
|
|
|
1741
1791
|
function safeIdentifier(value) {
|
|
1742
1792
|
return value.replace(/[^A-Za-z0-9_$]+/g, "_").replace(/^[^A-Za-z_$]+/, "_") || "_";
|
|
1743
1793
|
}
|
|
1744
|
-
function javascriptString(value) {
|
|
1745
|
-
return JSON.stringify(value).replace(/</g, "\\u003c").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
1746
|
-
}
|
|
1747
1794
|
//#endregion
|
|
1748
1795
|
//#region src/node/path-utils.ts
|
|
1749
1796
|
function dirname(path) {
|
|
@@ -2023,7 +2070,7 @@ async function compileDeckModules(input) {
|
|
|
2023
2070
|
const out = normalizeRelativePath(input.out, "Output directory");
|
|
2024
2071
|
const root = normalizeDeckRoot(input.root);
|
|
2025
2072
|
const paths = await listFiles(input.cwd, join(input.cwd, root));
|
|
2026
|
-
const resolved = resolveDeckFiles(paths, root, { markdown: input.markdown
|
|
2073
|
+
const resolved = resolveDeckFiles(paths, root, { markdown: Boolean(input.markdown) });
|
|
2027
2074
|
const componentModulePaths = Object.fromEntries(resolved.flatMap((deck) => {
|
|
2028
2075
|
const path = deck.kind === "directory" ? findComponentModule(paths, root, deck.slug) : void 0;
|
|
2029
2076
|
return path ? [[deck.slug, path]] : [];
|
|
@@ -2051,7 +2098,8 @@ async function compileDeckModules(input) {
|
|
|
2051
2098
|
refresh: input.refreshOgp,
|
|
2052
2099
|
resolveOgp: input.resolveOgp ?? resolveOgpMetadata
|
|
2053
2100
|
});
|
|
2054
|
-
const
|
|
2101
|
+
const adapter = input.markdown && resolved.some((entry) => entry.sourcePath.endsWith(".md")) ? await loadMarkdownAdapter(input.markdown, input.cwd) : void 0;
|
|
2102
|
+
const generated = await (adapter ? (value) => compileMarkdownDecks(value, adapter) : compileMdxModuleDecks)({
|
|
2055
2103
|
cwd: input.cwd,
|
|
2056
2104
|
root,
|
|
2057
2105
|
outDir: out,
|
|
@@ -2070,7 +2118,7 @@ async function compileDeckModules(input) {
|
|
|
2070
2118
|
clientEntries: clientEntryPaths,
|
|
2071
2119
|
clientComponentIds,
|
|
2072
2120
|
extraCode: generated.clientCode,
|
|
2073
|
-
|
|
2121
|
+
clientModules: generated.clientModules,
|
|
2074
2122
|
onCss: (css) => {
|
|
2075
2123
|
clientCss = css;
|
|
2076
2124
|
}
|
|
@@ -2220,7 +2268,7 @@ async function loadDecksConfig(input) {
|
|
|
2220
2268
|
const config = (await import(`data:text/javascript;charset=utf-8,${encodeURIComponent(source)}#${Date.now()}`)).default;
|
|
2221
2269
|
if (!config || typeof config !== "object") throw new Error(`Config must have a default export: ${path}`);
|
|
2222
2270
|
if (typeof config.mountPath !== "string") throw new Error(`Config mountPath must be a string: ${path}`);
|
|
2223
|
-
if (config.build?.markdown !== void 0 && config.build.markdown !== "void") throw new Error("Config build.markdown must be \"void\".");
|
|
2271
|
+
if (config.build?.markdown !== void 0 && config.build.markdown !== "void" && (typeof config.build.markdown !== "object" || !config.build.markdown || typeof config.build.markdown.adapter !== "string" || !config.build.markdown.adapter.trim())) throw new Error("Config build.markdown must be \"void\" or an adapter reference.");
|
|
2224
2272
|
return {
|
|
2225
2273
|
path,
|
|
2226
2274
|
config,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hono-decks",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Slide decks for Hono and Cloudflare Workers",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cloudflare-workers",
|
|
@@ -63,6 +63,10 @@
|
|
|
63
63
|
},
|
|
64
64
|
"./vite-env": {
|
|
65
65
|
"types": "./vite-env.d.ts"
|
|
66
|
+
},
|
|
67
|
+
"./adapters/hono-markdown": {
|
|
68
|
+
"types": "./dist/adapters/hono-markdown.d.ts",
|
|
69
|
+
"import": "./dist/adapters/hono-markdown.js"
|
|
66
70
|
}
|
|
67
71
|
},
|
|
68
72
|
"publishConfig": {
|