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