semajsx 0.1.1 → 0.1.2
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/{computed-BpjqvQu1.mjs → computed-BidG06Lt.mjs} +2 -2
- package/dist/{computed-BpjqvQu1.mjs.map → computed-BidG06Lt.mjs.map} +1 -1
- package/dist/{document-OGuk9jhK.mjs → document-BOJDaiBc.mjs} +19 -4
- package/dist/document-BOJDaiBc.mjs.map +1 -0
- package/dist/{document-DFsOtfef.mjs → document-CwHVG_PJ.mjs} +2 -2
- package/dist/dom/index.d.mts +68 -3
- package/dist/dom/index.d.mts.map +1 -1
- package/dist/dom/index.mjs +4 -4
- package/dist/dom/jsx-dev-runtime.d.mts +4 -4
- package/dist/dom/jsx-dev-runtime.mjs +1 -1
- package/dist/dom/jsx-runtime.d.mts +4 -4
- package/dist/dom/jsx-runtime.mjs +2 -2
- package/dist/{helpers-DrifjCXb.d.mts → helpers-CfRDJgcP.d.mts} +3 -3
- package/dist/{helpers-DrifjCXb.d.mts.map → helpers-CfRDJgcP.d.mts.map} +1 -1
- package/dist/{index-DS5X3Pvb.d.mts → index-B1pjI-Su.d.mts} +2 -2
- package/dist/{index-DS5X3Pvb.d.mts.map → index-B1pjI-Su.d.mts.map} +1 -1
- package/dist/index-DC3tthWf.d.mts +81 -0
- package/dist/index-DC3tthWf.d.mts.map +1 -0
- package/dist/index.d.mts +7 -7
- package/dist/index.mjs +5 -5
- package/dist/{island-marker-hZdmHMvx.d.mts → island-marker-BJIO07Vj.d.mts} +1 -1
- package/dist/island-marker-BJIO07Vj.d.mts.map +1 -0
- package/dist/{jsx-CGW4OyqA.d.mts → jsx-fNlLjLou.d.mts} +2 -2
- package/dist/{jsx-CGW4OyqA.d.mts.map → jsx-fNlLjLou.d.mts.map} +1 -1
- package/dist/{jsx-runtime-DU8DRISG.d.mts → jsx-runtime-BFuFPDzn.d.mts} +3 -3
- package/dist/{jsx-runtime-DU8DRISG.d.mts.map → jsx-runtime-BFuFPDzn.d.mts.map} +1 -1
- package/dist/jsx-runtime-D9ZNjMJ2.mjs.map +1 -1
- package/dist/{jsx-runtime-mBpL8czJ.d.mts → jsx-runtime-DZx2Yv-t.d.mts} +28 -6
- package/dist/{jsx-runtime-mBpL8czJ.d.mts.map → jsx-runtime-DZx2Yv-t.d.mts.map} +1 -1
- package/dist/lucide-CVtHepGM.mjs +126 -0
- package/dist/lucide-CVtHepGM.mjs.map +1 -0
- package/dist/{resource-B1IudM8_.d.mts → resource-BQI6AeJ0.d.mts} +23 -3
- package/dist/resource-BQI6AeJ0.d.mts.map +1 -0
- package/dist/{resource-BjsDAkbG.mjs → resource-DSlXDZZi.mjs} +2 -2
- package/dist/{resource-BjsDAkbG.mjs.map → resource-DSlXDZZi.mjs.map} +1 -1
- package/dist/signal/index.d.mts +2 -2
- package/dist/signal/index.mjs +3 -3
- package/dist/{signal-4PgGfydw.mjs → signal-BN8vHXDb.mjs} +1 -1
- package/dist/{signal-4PgGfydw.mjs.map → signal-BN8vHXDb.mjs.map} +1 -1
- package/dist/{signal-CLsaPA7c.d.mts → signal-BwxUlXKs.d.mts} +1 -1
- package/dist/{signal-CLsaPA7c.d.mts.map → signal-BwxUlXKs.d.mts.map} +1 -1
- package/dist/{src-CRi0xsNK.mjs → src-BqX3sryB.mjs} +68 -5
- package/dist/src-BqX3sryB.mjs.map +1 -0
- package/dist/src-DR-EWgVP.mjs +868 -0
- package/dist/src-DR-EWgVP.mjs.map +1 -0
- package/dist/{src-DEoBG1zB.mjs → src-DUpFNNM_.mjs} +4 -4
- package/dist/{src-DEoBG1zB.mjs.map → src-DUpFNNM_.mjs.map} +1 -1
- package/dist/{src-BlS3Hc-L.mjs → src-DW3tIczg.mjs} +75 -5
- package/dist/src-DW3tIczg.mjs.map +1 -0
- package/dist/{src-Jbt_w0hc.mjs → src-Ds9vl42d.mjs} +37 -35
- package/dist/src-Ds9vl42d.mjs.map +1 -0
- package/dist/{src-iC-NFwTy.mjs → src-DuSN6go_.mjs} +79 -22
- package/dist/src-DuSN6go_.mjs.map +1 -0
- package/dist/ssg/index.d.mts +4 -182
- package/dist/ssg/index.d.mts.map +1 -1
- package/dist/ssg/index.mjs +7 -756
- package/dist/ssg/index.mjs.map +1 -1
- package/dist/ssg/plugins/docs-theme.d.mts +180 -0
- package/dist/ssg/plugins/docs-theme.d.mts.map +1 -0
- package/dist/ssg/plugins/docs-theme.mjs +2042 -0
- package/dist/ssg/plugins/docs-theme.mjs.map +1 -0
- package/dist/ssg/plugins/lucide.d.mts +3 -0
- package/dist/ssg/plugins/lucide.mjs +7 -0
- package/dist/ssr/client.d.mts +3 -3
- package/dist/ssr/client.mjs +5 -5
- package/dist/ssr/index.d.mts +3 -3
- package/dist/ssr/index.d.mts.map +1 -1
- package/dist/ssr/index.mjs +6 -5
- package/dist/style/index.d.mts +2 -2
- package/dist/style/index.d.mts.map +1 -1
- package/dist/style/index.mjs +1 -1
- package/dist/style/react.d.mts +2 -2
- package/dist/style/react.mjs +2 -2
- package/dist/style/vue.d.mts +2 -2
- package/dist/style/vue.mjs +2 -2
- package/dist/terminal/index.d.mts +4 -4
- package/dist/terminal/index.mjs +2 -2
- package/dist/terminal/jsx-dev-runtime.d.mts +4 -4
- package/dist/terminal/jsx-dev-runtime.mjs +1 -1
- package/dist/terminal/jsx-runtime.d.mts +4 -4
- package/dist/terminal/jsx-runtime.mjs +1 -1
- package/dist/{types-DlNR9ZaJ.d.mts → types-BlaUrkq0.d.mts} +2 -2
- package/dist/{types-DlNR9ZaJ.d.mts.map → types-BlaUrkq0.d.mts.map} +1 -1
- package/dist/types-CGkRxnQB.d.mts +220 -0
- package/dist/types-CGkRxnQB.d.mts.map +1 -0
- package/dist/{types-Dgj6n-EE.d.mts → types-CZMcXQTW.d.mts} +9 -4
- package/dist/types-CZMcXQTW.d.mts.map +1 -0
- package/dist/{types-Bjx1Pp14.d.mts → types-D0jRO840.d.mts} +1 -1
- package/dist/{types-Bjx1Pp14.d.mts.map → types-D0jRO840.d.mts.map} +1 -1
- package/dist/{types-DEi0apQO.d.mts → types-DucvOZQ2.d.mts} +2 -2
- package/dist/{types-DEi0apQO.d.mts.map → types-DucvOZQ2.d.mts.map} +1 -1
- package/dist/{utils-BrGmTgfG.mjs → utils-DbTAs943.mjs} +1 -1
- package/dist/{utils-BrGmTgfG.mjs.map → utils-DbTAs943.mjs.map} +1 -1
- package/package.json +30 -2
- package/dist/document-OGuk9jhK.mjs.map +0 -1
- package/dist/island-marker-hZdmHMvx.d.mts.map +0 -1
- package/dist/jsx-runtime-D2B2BK8X.mjs +0 -4
- package/dist/resource-B1IudM8_.d.mts.map +0 -1
- package/dist/src-BlS3Hc-L.mjs.map +0 -1
- package/dist/src-CRi0xsNK.mjs.map +0 -1
- package/dist/src-Jbt_w0hc.mjs.map +0 -1
- package/dist/src-iC-NFwTy.mjs.map +0 -1
- package/dist/types-Dgj6n-EE.d.mts.map +0 -1
package/dist/ssg/index.mjs
CHANGED
|
@@ -1,762 +1,13 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { _ as DefaultDocument, a as remoteSource, c as FileSource, d as defineCollection, f as SSG, g as RawHTML, h as createMDXProcessor, i as RemoteSource, l as fileSource, m as MDXProcessor, n as CustomSource, o as GitSource, p as createSSG, r as createSource, s as gitSource, t as z, u as BaseSource, y as __require } from "../src-DR-EWgVP.mjs";
|
|
2
|
+
import "../src-DW3tIczg.mjs";
|
|
3
|
+
import "../src-Ds9vl42d.mjs";
|
|
2
4
|
import "../jsx-runtime-D9ZNjMJ2.mjs";
|
|
3
|
-
import "../src-
|
|
5
|
+
import "../src-DUpFNNM_.mjs";
|
|
4
6
|
import "../jsx-runtime-BjCGsceN.mjs";
|
|
5
|
-
import "../resource-
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import { createRequire } from "node:module";
|
|
9
|
-
import { dirname, join, relative, resolve } from "path";
|
|
10
|
-
import { mkdir, readFile, rm, watch, writeFile } from "fs/promises";
|
|
11
|
-
import { compile } from "@mdx-js/mdx";
|
|
12
|
-
import { glob } from "glob";
|
|
13
|
-
import matter from "gray-matter";
|
|
14
|
-
import { exec } from "child_process";
|
|
15
|
-
import { promisify } from "util";
|
|
16
|
-
import { z } from "zod";
|
|
7
|
+
import "../resource-DSlXDZZi.mjs";
|
|
8
|
+
import "../src-DuSN6go_.mjs";
|
|
9
|
+
import "../document-BOJDaiBc.mjs";
|
|
17
10
|
|
|
18
|
-
//#region rolldown:runtime
|
|
19
|
-
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
20
|
-
|
|
21
|
-
//#endregion
|
|
22
|
-
//#region ../ssg/src/document.tsx
|
|
23
|
-
/**
|
|
24
|
-
* Default HTML document template for SSG
|
|
25
|
-
*/
|
|
26
|
-
const DefaultDocument = ({ children, title = "SSG Page", scripts, css }) => /* @__PURE__ */ jsxs("html", {
|
|
27
|
-
lang: "en",
|
|
28
|
-
children: [/* @__PURE__ */ jsxs("head", { children: [
|
|
29
|
-
/* @__PURE__ */ jsx("meta", { charSet: "UTF-8" }),
|
|
30
|
-
/* @__PURE__ */ jsx("meta", {
|
|
31
|
-
name: "viewport",
|
|
32
|
-
content: "width=device-width, initial-scale=1.0"
|
|
33
|
-
}),
|
|
34
|
-
/* @__PURE__ */ jsx("title", { children: title }),
|
|
35
|
-
css?.map((href) => /* @__PURE__ */ jsx("link", {
|
|
36
|
-
rel: "stylesheet",
|
|
37
|
-
href
|
|
38
|
-
}))
|
|
39
|
-
] }), /* @__PURE__ */ jsxs("body", { children: [children, scripts] })]
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
//#endregion
|
|
43
|
-
//#region ../ssg/src/types.ts
|
|
44
|
-
/**
|
|
45
|
-
* Raw HTML VNode that can be used directly in JSX or converted to string
|
|
46
|
-
*/
|
|
47
|
-
var RawHTML = class {
|
|
48
|
-
constructor(html) {
|
|
49
|
-
this.html = html;
|
|
50
|
-
this.type = "div";
|
|
51
|
-
this.children = [];
|
|
52
|
-
this.props = { dangerouslySetInnerHTML: { __html: html } };
|
|
53
|
-
}
|
|
54
|
-
toString() {
|
|
55
|
-
return this.html;
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
//#endregion
|
|
60
|
-
//#region ../ssg/src/mdx/processor.ts
|
|
61
|
-
/**
|
|
62
|
-
* MDX Processor for compiling MDX content to JSX components
|
|
63
|
-
*/
|
|
64
|
-
var MDXProcessor = class {
|
|
65
|
-
constructor(config = {}) {
|
|
66
|
-
this.config = config;
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Compile MDX content to a JSX component
|
|
70
|
-
*/
|
|
71
|
-
async compile(content, frontmatter = {}) {
|
|
72
|
-
const headings = this.extractHeadings(content);
|
|
73
|
-
const compiled = await compile(content, {
|
|
74
|
-
outputFormat: "function-body",
|
|
75
|
-
development: false,
|
|
76
|
-
remarkPlugins: this.config.remarkPlugins ?? [],
|
|
77
|
-
rehypePlugins: this.config.rehypePlugins ?? [],
|
|
78
|
-
jsxImportSource: "@semajsx/dom"
|
|
79
|
-
});
|
|
80
|
-
const jsxRuntime = await import("../jsx-runtime-D2B2BK8X.mjs");
|
|
81
|
-
return {
|
|
82
|
-
Content: this.createComponent(String(compiled), this.config.components ?? {}, jsxRuntime),
|
|
83
|
-
frontmatter,
|
|
84
|
-
headings
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Create a component from compiled MDX code
|
|
89
|
-
*/
|
|
90
|
-
createComponent(code, components, jsxRuntime) {
|
|
91
|
-
return (props = {}) => {
|
|
92
|
-
try {
|
|
93
|
-
return new Function(code + "\nreturn MDXContent;").call(null, jsxRuntime).default({
|
|
94
|
-
...props,
|
|
95
|
-
components
|
|
96
|
-
});
|
|
97
|
-
} catch (e) {
|
|
98
|
-
throw new Error(`MDX rendering failed: ${e.message}`);
|
|
99
|
-
}
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
/**
|
|
103
|
-
* Extract headings from markdown content
|
|
104
|
-
*/
|
|
105
|
-
extractHeadings(content) {
|
|
106
|
-
const headings = [];
|
|
107
|
-
const headingRegex = /^(#{1,6})\s+(.+)$/gm;
|
|
108
|
-
let match;
|
|
109
|
-
while ((match = headingRegex.exec(content)) !== null) {
|
|
110
|
-
const hashes = match[1];
|
|
111
|
-
const rawText = match[2];
|
|
112
|
-
if (!hashes || !rawText) continue;
|
|
113
|
-
const depth = hashes.length;
|
|
114
|
-
const text = rawText.trim();
|
|
115
|
-
const slug = this.slugify(text);
|
|
116
|
-
headings.push({
|
|
117
|
-
depth,
|
|
118
|
-
text,
|
|
119
|
-
slug
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
return headings;
|
|
123
|
-
}
|
|
124
|
-
/**
|
|
125
|
-
* Convert text to URL-friendly slug
|
|
126
|
-
*/
|
|
127
|
-
slugify(text) {
|
|
128
|
-
return text.toLowerCase().replace(/[^\w\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").trim();
|
|
129
|
-
}
|
|
130
|
-
};
|
|
131
|
-
/**
|
|
132
|
-
* Create an MDX processor instance
|
|
133
|
-
*/
|
|
134
|
-
function createMDXProcessor(config) {
|
|
135
|
-
return new MDXProcessor(config);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
//#endregion
|
|
139
|
-
//#region ../ssg/src/mdx/vite-plugin.ts
|
|
140
|
-
/**
|
|
141
|
-
* Vite plugin for MDX support
|
|
142
|
-
* Transforms .mdx files to JSX modules
|
|
143
|
-
*/
|
|
144
|
-
function viteMDXPlugin(options = {}) {
|
|
145
|
-
return {
|
|
146
|
-
name: "semajsx-mdx",
|
|
147
|
-
async transform(code, id) {
|
|
148
|
-
if (!id.endsWith(".mdx")) return null;
|
|
149
|
-
try {
|
|
150
|
-
const compiled = await compile(code, {
|
|
151
|
-
jsxImportSource: "@semajsx/dom",
|
|
152
|
-
outputFormat: "program",
|
|
153
|
-
development: false,
|
|
154
|
-
remarkPlugins: options.remarkPlugins ?? [],
|
|
155
|
-
rehypePlugins: options.rehypePlugins ?? []
|
|
156
|
-
});
|
|
157
|
-
return {
|
|
158
|
-
code: String(compiled),
|
|
159
|
-
map: null
|
|
160
|
-
};
|
|
161
|
-
} catch (error) {
|
|
162
|
-
const err = error;
|
|
163
|
-
throw new Error(`MDX compilation failed for ${id}: ${err.message}`);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
//#endregion
|
|
170
|
-
//#region ../ssg/src/ssg.ts
|
|
171
|
-
/**
|
|
172
|
-
* SSG (Static Site Generator) core class
|
|
173
|
-
* Built on top of server's createApp
|
|
174
|
-
*/
|
|
175
|
-
var SSG = class {
|
|
176
|
-
constructor(config) {
|
|
177
|
-
this.mdxModules = /* @__PURE__ */ new Map();
|
|
178
|
-
this.rootDir = config.rootDir ?? process.cwd();
|
|
179
|
-
this.config = {
|
|
180
|
-
base: "/",
|
|
181
|
-
...config,
|
|
182
|
-
outDir: resolve(this.rootDir, config.outDir)
|
|
183
|
-
};
|
|
184
|
-
this.collections = /* @__PURE__ */ new Map();
|
|
185
|
-
this.entriesCache = /* @__PURE__ */ new Map();
|
|
186
|
-
this.app = createApp({
|
|
187
|
-
root: this.rootDir,
|
|
188
|
-
vite: { plugins: [{
|
|
189
|
-
name: "ssg-virtual-mdx",
|
|
190
|
-
resolveId: (id) => {
|
|
191
|
-
if (id.startsWith("virtual:mdx:")) return "\0" + id;
|
|
192
|
-
},
|
|
193
|
-
load: (id) => {
|
|
194
|
-
if (id.startsWith("\0virtual:mdx:")) {
|
|
195
|
-
const mdxId = id.replace("\0virtual:mdx:", "");
|
|
196
|
-
return this.mdxModules.get(mdxId);
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
}, viteMDXPlugin(config.mdx ?? {})] }
|
|
200
|
-
});
|
|
201
|
-
for (const collection of config.collections ?? []) this.collections.set(collection.name, collection);
|
|
202
|
-
}
|
|
203
|
-
getRootDir() {
|
|
204
|
-
return this.rootDir;
|
|
205
|
-
}
|
|
206
|
-
async getCollection(name) {
|
|
207
|
-
const collection = this.collections.get(name);
|
|
208
|
-
if (!collection) throw new Error(`Collection "${name}" not found`);
|
|
209
|
-
if (this.entriesCache.has(name)) return this.entriesCache.get(name);
|
|
210
|
-
const validatedEntries = (await collection.source.getEntries()).map((entry) => {
|
|
211
|
-
const result = collection.schema.safeParse(entry.data);
|
|
212
|
-
if (!result.success) throw new Error(`Validation error in ${name}/${entry.id}: ${result.error.message}`);
|
|
213
|
-
return {
|
|
214
|
-
...entry,
|
|
215
|
-
data: result.data,
|
|
216
|
-
render: async () => {
|
|
217
|
-
const vite = this.app.getViteServer();
|
|
218
|
-
if (!vite) throw new Error("Vite server not initialized");
|
|
219
|
-
const mdxId = `${name}/${entry.id}.mdx`;
|
|
220
|
-
this.mdxModules.set(mdxId, entry.body);
|
|
221
|
-
try {
|
|
222
|
-
const moduleExports = await vite.ssrLoadModule(`virtual:mdx:${mdxId}`);
|
|
223
|
-
const Content = (props = {}) => moduleExports.default({
|
|
224
|
-
...props,
|
|
225
|
-
components: this.config.mdx?.components ?? {}
|
|
226
|
-
});
|
|
227
|
-
return {
|
|
228
|
-
Content,
|
|
229
|
-
headings: this.extractHeadings(entry.body)
|
|
230
|
-
};
|
|
231
|
-
} finally {
|
|
232
|
-
this.mdxModules.delete(mdxId);
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
};
|
|
236
|
-
});
|
|
237
|
-
this.entriesCache.set(name, validatedEntries);
|
|
238
|
-
return validatedEntries;
|
|
239
|
-
}
|
|
240
|
-
async getEntry(name, id) {
|
|
241
|
-
return (await this.getCollection(name)).find((e) => e.id === id || e.slug === id) ?? null;
|
|
242
|
-
}
|
|
243
|
-
async build(options = {}) {
|
|
244
|
-
const { incremental = false, state: prevState } = options;
|
|
245
|
-
const outDir = this.config.outDir;
|
|
246
|
-
await this.app.prepare();
|
|
247
|
-
try {
|
|
248
|
-
await this.registerRoutes();
|
|
249
|
-
const result = await this.buildPages(incremental, prevState, outDir);
|
|
250
|
-
await this.app.build({
|
|
251
|
-
outDir,
|
|
252
|
-
mode: "full",
|
|
253
|
-
minify: true,
|
|
254
|
-
vite: { build: { rollupOptions: { external: [] } } }
|
|
255
|
-
});
|
|
256
|
-
return result;
|
|
257
|
-
} finally {
|
|
258
|
-
await this.app.close();
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
async registerRoutes() {
|
|
262
|
-
const routes = this.config.routes ?? [];
|
|
263
|
-
for (const route of routes) if (route.getStaticPaths) {
|
|
264
|
-
const staticPaths = await route.getStaticPaths(this);
|
|
265
|
-
for (const sp of staticPaths) {
|
|
266
|
-
const path = this.applyParams(route.path, sp.params);
|
|
267
|
-
const props = {
|
|
268
|
-
...sp.props,
|
|
269
|
-
params: sp.params
|
|
270
|
-
};
|
|
271
|
-
this.app.route(path, (_context) => {
|
|
272
|
-
return route.component(props);
|
|
273
|
-
}, { title: props.title });
|
|
274
|
-
}
|
|
275
|
-
} else {
|
|
276
|
-
let props = {};
|
|
277
|
-
if (typeof route.props === "function") props = await route.props(this);
|
|
278
|
-
else if (route.props) props = route.props;
|
|
279
|
-
this.app.route(route.path, (_context) => {
|
|
280
|
-
return route.component(props);
|
|
281
|
-
}, { title: props.title });
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
async buildPages(incremental, prevState, outDir) {
|
|
285
|
-
const state = {
|
|
286
|
-
cursors: {},
|
|
287
|
-
pageHashes: {},
|
|
288
|
-
timestamp: Date.now()
|
|
289
|
-
};
|
|
290
|
-
const stats = {
|
|
291
|
-
added: 0,
|
|
292
|
-
updated: 0,
|
|
293
|
-
deleted: 0,
|
|
294
|
-
unchanged: 0
|
|
295
|
-
};
|
|
296
|
-
const builtPaths = [];
|
|
297
|
-
if (!incremental) await rm(outDir, {
|
|
298
|
-
recursive: true,
|
|
299
|
-
force: true
|
|
300
|
-
});
|
|
301
|
-
await mkdir(outDir, { recursive: true });
|
|
302
|
-
this.entriesCache.clear();
|
|
303
|
-
const allPaths = await this.generateAllPaths();
|
|
304
|
-
const currentPaths = new Set(allPaths.map((p) => p.path));
|
|
305
|
-
if (incremental && prevState) {
|
|
306
|
-
for (const oldPath of Object.keys(prevState.pageHashes)) if (!currentPaths.has(oldPath)) {
|
|
307
|
-
const filePath = this.pathToFilePath(oldPath);
|
|
308
|
-
try {
|
|
309
|
-
await rm(join(outDir, filePath));
|
|
310
|
-
stats.deleted++;
|
|
311
|
-
} catch {}
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
for (const { path, props } of allPaths) {
|
|
315
|
-
const html = await this.renderPage(path, props);
|
|
316
|
-
const hash = this.hashContent(html);
|
|
317
|
-
const prevHash = prevState?.pageHashes[path];
|
|
318
|
-
if (!incremental || !prevHash || prevHash !== hash) {
|
|
319
|
-
const fullPath = join(outDir, this.pathToFilePath(path));
|
|
320
|
-
await mkdir(dirname(fullPath), { recursive: true });
|
|
321
|
-
await writeFile(fullPath, html);
|
|
322
|
-
builtPaths.push(path);
|
|
323
|
-
if (!prevHash) stats.added++;
|
|
324
|
-
else stats.updated++;
|
|
325
|
-
} else stats.unchanged++;
|
|
326
|
-
state.pageHashes[path] = hash;
|
|
327
|
-
}
|
|
328
|
-
for (const [name, collection] of this.collections) if (collection.source.getChanges) state.cursors[name] = Date.now().toString();
|
|
329
|
-
return {
|
|
330
|
-
state,
|
|
331
|
-
paths: builtPaths,
|
|
332
|
-
stats
|
|
333
|
-
};
|
|
334
|
-
}
|
|
335
|
-
async renderPage(path, props) {
|
|
336
|
-
const result = await this.app.render(path);
|
|
337
|
-
const documentProps = {
|
|
338
|
-
children: new RawHTML(result.html),
|
|
339
|
-
title: props.title,
|
|
340
|
-
base: this.config.base ?? "/",
|
|
341
|
-
path,
|
|
342
|
-
props,
|
|
343
|
-
scripts: result.scripts ? new RawHTML(result.scripts) : void 0,
|
|
344
|
-
css: result.css.length > 0 ? result.css : void 0
|
|
345
|
-
};
|
|
346
|
-
return renderDocument((this.config.document ?? DefaultDocument)(documentProps));
|
|
347
|
-
}
|
|
348
|
-
async generateAllPaths() {
|
|
349
|
-
const paths = [];
|
|
350
|
-
const routes = this.config.routes ?? [];
|
|
351
|
-
for (const route of routes) if (route.getStaticPaths) {
|
|
352
|
-
const staticPaths = await route.getStaticPaths(this);
|
|
353
|
-
for (const sp of staticPaths) {
|
|
354
|
-
const path = this.applyParams(route.path, sp.params);
|
|
355
|
-
paths.push({
|
|
356
|
-
path,
|
|
357
|
-
props: {
|
|
358
|
-
...sp.props,
|
|
359
|
-
params: sp.params
|
|
360
|
-
}
|
|
361
|
-
});
|
|
362
|
-
}
|
|
363
|
-
} else {
|
|
364
|
-
let props = {};
|
|
365
|
-
if (typeof route.props === "function") props = await route.props(this);
|
|
366
|
-
else if (route.props) props = route.props;
|
|
367
|
-
paths.push({
|
|
368
|
-
path: route.path,
|
|
369
|
-
props
|
|
370
|
-
});
|
|
371
|
-
}
|
|
372
|
-
return paths;
|
|
373
|
-
}
|
|
374
|
-
watch(options = {}) {
|
|
375
|
-
const unsubscribers = [];
|
|
376
|
-
for (const [name, collection] of this.collections) if (collection.source.watch) {
|
|
377
|
-
const unsubscribe = collection.source.watch(async () => {
|
|
378
|
-
try {
|
|
379
|
-
this.entriesCache.delete(name);
|
|
380
|
-
const result = await this.build({ incremental: true });
|
|
381
|
-
options.onRebuild?.(result);
|
|
382
|
-
} catch (error) {
|
|
383
|
-
options.onError?.(error);
|
|
384
|
-
}
|
|
385
|
-
});
|
|
386
|
-
unsubscribers.push(unsubscribe);
|
|
387
|
-
}
|
|
388
|
-
return { close: () => unsubscribers.forEach((fn) => fn()) };
|
|
389
|
-
}
|
|
390
|
-
pathToFilePath(urlPath) {
|
|
391
|
-
if (urlPath === "/") return "index.html";
|
|
392
|
-
return `${urlPath.slice(1)}/index.html`;
|
|
393
|
-
}
|
|
394
|
-
applyParams(pattern, params) {
|
|
395
|
-
let path = pattern;
|
|
396
|
-
for (const [key, value] of Object.entries(params)) path = path.replace(`:${key}`, value);
|
|
397
|
-
return path;
|
|
398
|
-
}
|
|
399
|
-
hashContent(content) {
|
|
400
|
-
let hash = 0;
|
|
401
|
-
for (let i = 0; i < content.length; i++) {
|
|
402
|
-
const char = content.charCodeAt(i);
|
|
403
|
-
hash = (hash << 5) - hash + char;
|
|
404
|
-
hash = hash & hash;
|
|
405
|
-
}
|
|
406
|
-
return hash.toString(16);
|
|
407
|
-
}
|
|
408
|
-
extractHeadings(content) {
|
|
409
|
-
const headings = [];
|
|
410
|
-
const regex = /^(#{1,6})\s+(.+)$/gm;
|
|
411
|
-
let match;
|
|
412
|
-
while ((match = regex.exec(content)) !== null) {
|
|
413
|
-
if (!match[1] || !match[2]) continue;
|
|
414
|
-
const depth = match[1].length;
|
|
415
|
-
const text = match[2].trim();
|
|
416
|
-
const slug = text.toLowerCase().replace(/[^\w\s-]/g, "").replace(/\s+/g, "-");
|
|
417
|
-
headings.push({
|
|
418
|
-
depth,
|
|
419
|
-
text,
|
|
420
|
-
slug
|
|
421
|
-
});
|
|
422
|
-
}
|
|
423
|
-
return headings;
|
|
424
|
-
}
|
|
425
|
-
};
|
|
426
|
-
function createSSG(config) {
|
|
427
|
-
return new SSG(config);
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
//#endregion
|
|
431
|
-
//#region ../ssg/src/collection/index.ts
|
|
432
|
-
/**
|
|
433
|
-
* Define a collection with schema validation
|
|
434
|
-
*/
|
|
435
|
-
function defineCollection(config) {
|
|
436
|
-
return {
|
|
437
|
-
name: config.name,
|
|
438
|
-
source: config.source,
|
|
439
|
-
schema: config.schema
|
|
440
|
-
};
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
//#endregion
|
|
444
|
-
//#region ../ssg/src/sources/base.ts
|
|
445
|
-
/**
|
|
446
|
-
* Base class for collection sources
|
|
447
|
-
*/
|
|
448
|
-
var BaseSource = class {
|
|
449
|
-
async getEntry(id) {
|
|
450
|
-
return (await this.getEntries()).find((e) => e.id === id) ?? null;
|
|
451
|
-
}
|
|
452
|
-
};
|
|
453
|
-
|
|
454
|
-
//#endregion
|
|
455
|
-
//#region ../ssg/src/sources/file.ts
|
|
456
|
-
/**
|
|
457
|
-
* File system source for collections
|
|
458
|
-
*/
|
|
459
|
-
var FileSource = class extends BaseSource {
|
|
460
|
-
constructor(options, contentRoot = process.cwd()) {
|
|
461
|
-
super();
|
|
462
|
-
this.directory = options.directory;
|
|
463
|
-
this.include = options.include ?? "**/*.{md,mdx}";
|
|
464
|
-
this.shouldWatch = options.watch ?? false;
|
|
465
|
-
this.contentRoot = contentRoot;
|
|
466
|
-
this.id = `file:${this.directory}`;
|
|
467
|
-
}
|
|
468
|
-
async getEntries() {
|
|
469
|
-
const dir = join(this.contentRoot, this.directory);
|
|
470
|
-
const files = await glob(join(dir, this.include));
|
|
471
|
-
return await Promise.all(files.map(async (filePath) => {
|
|
472
|
-
const { data, content: body } = matter(await readFile(filePath, "utf-8"));
|
|
473
|
-
const id = relative(dir, filePath).replace(/\.(md|mdx)$/, "");
|
|
474
|
-
return {
|
|
475
|
-
id,
|
|
476
|
-
slug: id.replace(/\\/g, "/"),
|
|
477
|
-
data,
|
|
478
|
-
body,
|
|
479
|
-
render: async () => {
|
|
480
|
-
return { Content: () => {
|
|
481
|
-
throw new Error("MDX rendering not yet implemented");
|
|
482
|
-
} };
|
|
483
|
-
}
|
|
484
|
-
};
|
|
485
|
-
}));
|
|
486
|
-
}
|
|
487
|
-
watch(callback) {
|
|
488
|
-
if (!this.shouldWatch) return () => {};
|
|
489
|
-
const dir = join(this.contentRoot, this.directory);
|
|
490
|
-
const abortController = new AbortController();
|
|
491
|
-
const startWatching = async () => {
|
|
492
|
-
try {
|
|
493
|
-
const watcher = watch(dir, {
|
|
494
|
-
recursive: true,
|
|
495
|
-
signal: abortController.signal
|
|
496
|
-
});
|
|
497
|
-
for await (const _event of watcher) {
|
|
498
|
-
const entries = await this.getEntries();
|
|
499
|
-
callback({
|
|
500
|
-
cursor: Date.now().toString(),
|
|
501
|
-
added: [],
|
|
502
|
-
updated: entries,
|
|
503
|
-
deleted: []
|
|
504
|
-
});
|
|
505
|
-
}
|
|
506
|
-
} catch (err) {
|
|
507
|
-
if (err.name !== "AbortError") throw err;
|
|
508
|
-
}
|
|
509
|
-
};
|
|
510
|
-
startWatching();
|
|
511
|
-
return () => {
|
|
512
|
-
abortController.abort();
|
|
513
|
-
};
|
|
514
|
-
}
|
|
515
|
-
async getChanges(_since) {
|
|
516
|
-
const entries = await this.getEntries();
|
|
517
|
-
return {
|
|
518
|
-
cursor: Date.now().toString(),
|
|
519
|
-
added: [],
|
|
520
|
-
updated: entries,
|
|
521
|
-
deleted: []
|
|
522
|
-
};
|
|
523
|
-
}
|
|
524
|
-
};
|
|
525
|
-
/**
|
|
526
|
-
* Create a file system source
|
|
527
|
-
*/
|
|
528
|
-
function fileSource(options, contentRoot) {
|
|
529
|
-
return new FileSource(options, contentRoot);
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
//#endregion
|
|
533
|
-
//#region ../ssg/src/sources/git.ts
|
|
534
|
-
const execAsync = promisify(exec);
|
|
535
|
-
/**
|
|
536
|
-
* Git source for collections
|
|
537
|
-
*/
|
|
538
|
-
var GitSource = class extends BaseSource {
|
|
539
|
-
constructor(options, cwd = process.cwd()) {
|
|
540
|
-
super();
|
|
541
|
-
this.options = options;
|
|
542
|
-
this.cwd = cwd;
|
|
543
|
-
this.id = `git:${options.type}`;
|
|
544
|
-
}
|
|
545
|
-
async getEntries() {
|
|
546
|
-
if (this.options.type === "commits") return this.getCommits(this.options);
|
|
547
|
-
else return this.getTags(this.options);
|
|
548
|
-
}
|
|
549
|
-
async getCommits(options) {
|
|
550
|
-
const args = ["log", "--format=%H|%s|%an|%ae|%aI"];
|
|
551
|
-
if (options.filter?.since) args.push(`--since=${options.filter.since}`);
|
|
552
|
-
if (options.filter?.until) args.push(`--until=${options.filter.until}`);
|
|
553
|
-
if (options.filter?.author) args.push(`--author=${options.filter.author}`);
|
|
554
|
-
if (options.limit) args.push(`-n`, options.limit.toString());
|
|
555
|
-
if (options.filter?.paths?.length) args.push("--", ...options.filter.paths);
|
|
556
|
-
const { stdout } = await execAsync(`git ${args.join(" ")}`, { cwd: this.cwd });
|
|
557
|
-
return stdout.trim().split("\n").filter(Boolean).map((line) => {
|
|
558
|
-
const parts = line.split("|");
|
|
559
|
-
const hash = parts[0] ?? "";
|
|
560
|
-
const message = parts[1] ?? "";
|
|
561
|
-
const author = parts[2] ?? "";
|
|
562
|
-
const email = parts[3] ?? "";
|
|
563
|
-
const dateStr = parts[4] ?? "";
|
|
564
|
-
const data = {
|
|
565
|
-
hash,
|
|
566
|
-
message,
|
|
567
|
-
author,
|
|
568
|
-
email,
|
|
569
|
-
date: new Date(dateStr)
|
|
570
|
-
};
|
|
571
|
-
return {
|
|
572
|
-
id: hash,
|
|
573
|
-
slug: hash.slice(0, 7),
|
|
574
|
-
data,
|
|
575
|
-
body: message,
|
|
576
|
-
render: async () => ({ Content: () => {
|
|
577
|
-
throw new Error("Git commits cannot be rendered as content");
|
|
578
|
-
} })
|
|
579
|
-
};
|
|
580
|
-
});
|
|
581
|
-
}
|
|
582
|
-
async getTags(options) {
|
|
583
|
-
const { stdout } = await execAsync(`git tag -l "${options.pattern ?? "*"}" --format="%(refname:short)|%(objectname:short)|%(creatordate:iso)|%(contents:subject)"`, { cwd: this.cwd });
|
|
584
|
-
return stdout.trim().split("\n").filter(Boolean).map((line) => {
|
|
585
|
-
const parts = line.split("|");
|
|
586
|
-
const tag = parts[0] ?? "";
|
|
587
|
-
const hash = parts[1] ?? "";
|
|
588
|
-
const dateStr = parts[2] ?? "";
|
|
589
|
-
const message = parts[3] ?? "";
|
|
590
|
-
return {
|
|
591
|
-
id: tag,
|
|
592
|
-
slug: tag,
|
|
593
|
-
data: {
|
|
594
|
-
tag,
|
|
595
|
-
hash,
|
|
596
|
-
date: new Date(dateStr),
|
|
597
|
-
message: message || void 0
|
|
598
|
-
},
|
|
599
|
-
body: message,
|
|
600
|
-
render: async () => ({ Content: () => {
|
|
601
|
-
throw new Error("Git tags cannot be rendered as content");
|
|
602
|
-
} })
|
|
603
|
-
};
|
|
604
|
-
});
|
|
605
|
-
}
|
|
606
|
-
};
|
|
607
|
-
/**
|
|
608
|
-
* Create a Git source
|
|
609
|
-
*/
|
|
610
|
-
function gitSource(options, cwd) {
|
|
611
|
-
return new GitSource(options, cwd);
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
//#endregion
|
|
615
|
-
//#region ../ssg/src/sources/remote.ts
|
|
616
|
-
/**
|
|
617
|
-
* Remote API source for collections
|
|
618
|
-
*/
|
|
619
|
-
var RemoteSource = class extends BaseSource {
|
|
620
|
-
constructor(options, id = "remote") {
|
|
621
|
-
super();
|
|
622
|
-
this.options = options;
|
|
623
|
-
this.id = `remote:${id}`;
|
|
624
|
-
}
|
|
625
|
-
async getEntries() {
|
|
626
|
-
return (await this.options.fetch()).map((item, index) => {
|
|
627
|
-
const id = item.id?.toString() ?? index.toString();
|
|
628
|
-
return {
|
|
629
|
-
id,
|
|
630
|
-
slug: item.slug?.toString() ?? id,
|
|
631
|
-
data: item,
|
|
632
|
-
body: item.content?.toString() ?? "",
|
|
633
|
-
render: async () => ({ Content: () => {
|
|
634
|
-
throw new Error("Remote content rendering not yet implemented");
|
|
635
|
-
} })
|
|
636
|
-
};
|
|
637
|
-
});
|
|
638
|
-
}
|
|
639
|
-
async getEntry(id) {
|
|
640
|
-
if (this.options.fetchOne) {
|
|
641
|
-
const item = await this.options.fetchOne(id);
|
|
642
|
-
if (!item) return null;
|
|
643
|
-
return {
|
|
644
|
-
id,
|
|
645
|
-
slug: item.slug?.toString() ?? id,
|
|
646
|
-
data: item,
|
|
647
|
-
body: item.content?.toString() ?? "",
|
|
648
|
-
render: async () => ({ Content: () => {
|
|
649
|
-
throw new Error("Remote content rendering not yet implemented");
|
|
650
|
-
} })
|
|
651
|
-
};
|
|
652
|
-
}
|
|
653
|
-
return super.getEntry(id);
|
|
654
|
-
}
|
|
655
|
-
watch(callback) {
|
|
656
|
-
if (this.options.pollInterval) {
|
|
657
|
-
this.pollTimer = setInterval(async () => {
|
|
658
|
-
const entries = await this.getEntries();
|
|
659
|
-
callback({
|
|
660
|
-
cursor: Date.now().toString(),
|
|
661
|
-
added: [],
|
|
662
|
-
updated: entries,
|
|
663
|
-
deleted: []
|
|
664
|
-
});
|
|
665
|
-
}, this.options.pollInterval);
|
|
666
|
-
return () => {
|
|
667
|
-
if (this.pollTimer) clearInterval(this.pollTimer);
|
|
668
|
-
};
|
|
669
|
-
}
|
|
670
|
-
return () => {};
|
|
671
|
-
}
|
|
672
|
-
async getChanges(since) {
|
|
673
|
-
if (this.options.fetchChanges) return this.options.fetchChanges(since);
|
|
674
|
-
const entries = await this.getEntries();
|
|
675
|
-
return {
|
|
676
|
-
cursor: Date.now().toString(),
|
|
677
|
-
added: [],
|
|
678
|
-
updated: entries,
|
|
679
|
-
deleted: []
|
|
680
|
-
};
|
|
681
|
-
}
|
|
682
|
-
/**
|
|
683
|
-
* Get webhook configuration for external integration
|
|
684
|
-
*/
|
|
685
|
-
getWebhookConfig() {
|
|
686
|
-
return this.options.webhook;
|
|
687
|
-
}
|
|
688
|
-
};
|
|
689
|
-
/**
|
|
690
|
-
* Create a remote API source
|
|
691
|
-
*/
|
|
692
|
-
function remoteSource(options, id) {
|
|
693
|
-
return new RemoteSource(options, id);
|
|
694
|
-
}
|
|
695
|
-
|
|
696
|
-
//#endregion
|
|
697
|
-
//#region ../ssg/src/sources/custom.ts
|
|
698
|
-
/**
|
|
699
|
-
* Custom source for collections
|
|
700
|
-
*/
|
|
701
|
-
var CustomSource = class extends BaseSource {
|
|
702
|
-
constructor(options) {
|
|
703
|
-
super();
|
|
704
|
-
this.options = options;
|
|
705
|
-
this.id = options.id;
|
|
706
|
-
}
|
|
707
|
-
async getEntries() {
|
|
708
|
-
return (await this.options.getEntries()).map((item, index) => {
|
|
709
|
-
const id = item.id?.toString() ?? index.toString();
|
|
710
|
-
return {
|
|
711
|
-
id,
|
|
712
|
-
slug: item.slug?.toString() ?? id,
|
|
713
|
-
data: item,
|
|
714
|
-
body: item.body?.toString() ?? "",
|
|
715
|
-
render: async () => ({ Content: () => {
|
|
716
|
-
throw new Error("Custom content rendering not yet implemented");
|
|
717
|
-
} })
|
|
718
|
-
};
|
|
719
|
-
});
|
|
720
|
-
}
|
|
721
|
-
async getEntry(id) {
|
|
722
|
-
if (this.options.getEntry) {
|
|
723
|
-
const item = await this.options.getEntry(id);
|
|
724
|
-
if (!item) return null;
|
|
725
|
-
return {
|
|
726
|
-
id,
|
|
727
|
-
slug: item.slug?.toString() ?? id,
|
|
728
|
-
data: item,
|
|
729
|
-
body: item.body?.toString() ?? "",
|
|
730
|
-
render: async () => ({ Content: () => {
|
|
731
|
-
throw new Error("Custom content rendering not yet implemented");
|
|
732
|
-
} })
|
|
733
|
-
};
|
|
734
|
-
}
|
|
735
|
-
return super.getEntry(id);
|
|
736
|
-
}
|
|
737
|
-
watch(callback) {
|
|
738
|
-
if (this.options.watch) return this.options.watch(callback);
|
|
739
|
-
return () => {};
|
|
740
|
-
}
|
|
741
|
-
async getChanges(since) {
|
|
742
|
-
if (this.options.getChanges) return this.options.getChanges(since);
|
|
743
|
-
const entries = await this.getEntries();
|
|
744
|
-
return {
|
|
745
|
-
cursor: Date.now().toString(),
|
|
746
|
-
added: [],
|
|
747
|
-
updated: entries,
|
|
748
|
-
deleted: []
|
|
749
|
-
};
|
|
750
|
-
}
|
|
751
|
-
};
|
|
752
|
-
/**
|
|
753
|
-
* Create a custom source
|
|
754
|
-
*/
|
|
755
|
-
function createSource(options) {
|
|
756
|
-
return new CustomSource(options);
|
|
757
|
-
}
|
|
758
|
-
|
|
759
|
-
//#endregion
|
|
760
11
|
//#region ../ssg/src/watcher/webhook.ts
|
|
761
12
|
/**
|
|
762
13
|
* Create a webhook handler for triggering SSG builds
|