mdsvr 2.2.17 → 2.2.19
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/cli.js +16 -8
- package/dist/cli.js.map +1 -1
- package/dist/export-state.d.ts +44 -0
- package/dist/export-state.d.ts.map +1 -0
- package/dist/export-state.js +164 -0
- package/dist/export-state.js.map +1 -0
- package/dist/generators/static-export.d.ts +1 -0
- package/dist/generators/static-export.d.ts.map +1 -1
- package/dist/generators/static-export.js +133 -25
- package/dist/generators/static-export.js.map +1 -1
- package/dist/og/generator.d.ts.map +1 -1
- package/dist/og/generator.js +43 -0
- package/dist/og/generator.js.map +1 -1
- package/dist/og/incremental.d.ts +48 -0
- package/dist/og/incremental.d.ts.map +1 -0
- package/dist/og/incremental.js +194 -0
- package/dist/og/incremental.js.map +1 -0
- package/dist/og/index.d.ts +3 -2
- package/dist/og/index.d.ts.map +1 -1
- package/dist/og/index.js +3 -2
- package/dist/og/index.js.map +1 -1
- package/dist/renderer/components.js +1 -1
- package/dist/renderer/components.js.map +1 -1
- package/dist/renderer/markdown.d.ts.map +1 -1
- package/dist/renderer/markdown.js +42 -6
- package/dist/renderer/markdown.js.map +1 -1
- package/dist/router.js +9 -2
- package/dist/router.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +2 -2
- package/dist/server.js.map +1 -1
- package/dist/settings/defaults.d.ts.map +1 -1
- package/dist/settings/defaults.js +1 -0
- package/dist/settings/defaults.js.map +1 -1
- package/dist/settings/index.d.ts.map +1 -1
- package/dist/settings/index.js +13 -6
- package/dist/settings/index.js.map +1 -1
- package/dist/settings/schema.js +1 -1
- package/dist/settings/schema.js.map +1 -1
- package/dist/template/index.d.ts.map +1 -1
- package/dist/template/index.js +345 -61
- package/dist/template/index.js.map +1 -1
- package/dist/template/sidebar.d.ts.map +1 -1
- package/dist/template/sidebar.js +21 -7
- package/dist/template/sidebar.js.map +1 -1
- package/package.json +3 -3
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createServer, getNetworkAddress } from "./server.js";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import { readFile, writeFile } from "node:fs/promises";
|
|
4
|
+
import { readFile, writeFile, mkdir } from "node:fs/promises";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
import { validateSettingsFile, generateDefaultSettings, } from "./settings/index.js";
|
|
7
7
|
function parseArgs(argv) {
|
|
@@ -18,6 +18,7 @@ function parseArgs(argv) {
|
|
|
18
18
|
validate: false,
|
|
19
19
|
watchSettings: true,
|
|
20
20
|
export: null,
|
|
21
|
+
forceOg: false,
|
|
21
22
|
};
|
|
22
23
|
for (let i = 0; i < argv.length; i++) {
|
|
23
24
|
const arg = argv[i];
|
|
@@ -64,6 +65,9 @@ function parseArgs(argv) {
|
|
|
64
65
|
args.export = null; // Will use default _html folder
|
|
65
66
|
}
|
|
66
67
|
}
|
|
68
|
+
else if (arg === "--force-og") {
|
|
69
|
+
args.forceOg = true;
|
|
70
|
+
}
|
|
67
71
|
else if (!arg.startsWith("--") && !arg.startsWith("-")) {
|
|
68
72
|
args.dir = arg;
|
|
69
73
|
args.dirSpecified = true;
|
|
@@ -82,9 +86,10 @@ Options:
|
|
|
82
86
|
-o, --open Auto-open browser
|
|
83
87
|
-s, --silent Suppress console output
|
|
84
88
|
-e, --export [PATH] Export static HTML (default: _html/public in input dir)
|
|
85
|
-
--
|
|
86
|
-
--
|
|
87
|
-
--
|
|
89
|
+
--force-og Force full OG image regeneration (skip incremental)
|
|
90
|
+
--init Create a starter _mdsvr/settings.json in [dir]
|
|
91
|
+
--validate Validate _mdsvr/settings.json and exit
|
|
92
|
+
--no-watch Disable _mdsvr/settings.json hot-reload
|
|
88
93
|
-v, --version Print version
|
|
89
94
|
-h, --help Print this help
|
|
90
95
|
|
|
@@ -94,6 +99,7 @@ Examples:
|
|
|
94
99
|
mdsvr . --host 0.0.0.0 --port 8080
|
|
95
100
|
mdsvr ./docs --export # Export to ./_html/public
|
|
96
101
|
mdsvr ./docs -e ./output # Export to custom directory
|
|
102
|
+
mdsvr ./docs --export --force-og # Export with full OG regeneration
|
|
97
103
|
mdsvr ./docs --init
|
|
98
104
|
mdsvr ./docs --validate
|
|
99
105
|
`);
|
|
@@ -120,8 +126,9 @@ async function openBrowser(url) {
|
|
|
120
126
|
exec(`${cmd} "${url}"`);
|
|
121
127
|
}
|
|
122
128
|
async function initSettings(dir) {
|
|
123
|
-
const settingsPath = path.join(dir, "settings.json");
|
|
129
|
+
const settingsPath = path.join(dir, "_mdsvr/settings.json");
|
|
124
130
|
const defaultSettings = generateDefaultSettings();
|
|
131
|
+
await mkdir(path.join(dir, "_mdsvr"), { recursive: true });
|
|
125
132
|
await writeFile(settingsPath, JSON.stringify(defaultSettings, null, 2), "utf-8");
|
|
126
133
|
}
|
|
127
134
|
async function main() {
|
|
@@ -146,7 +153,7 @@ async function main() {
|
|
|
146
153
|
if (args.init) {
|
|
147
154
|
try {
|
|
148
155
|
await initSettings(absoluteDir);
|
|
149
|
-
console.log(`\n ✔ Created ${args.dir}/settings.json with defaults`);
|
|
156
|
+
console.log(`\n ✔ Created ${args.dir}/_mdsvr/settings.json with defaults`);
|
|
150
157
|
console.log(` ✔ Run \`npx mdsvr ${args.dir}\` to start\n`);
|
|
151
158
|
process.exit(0);
|
|
152
159
|
}
|
|
@@ -160,11 +167,11 @@ async function main() {
|
|
|
160
167
|
try {
|
|
161
168
|
const result = await validateSettingsFile(absoluteDir);
|
|
162
169
|
if (result.valid) {
|
|
163
|
-
console.log(`\n ✔ settings.json is valid\n`);
|
|
170
|
+
console.log(`\n ✔ _mdsvr/settings.json is valid\n`);
|
|
164
171
|
process.exit(0);
|
|
165
172
|
}
|
|
166
173
|
else {
|
|
167
|
-
console.log(`\n ✖ settings.json has errors:`);
|
|
174
|
+
console.log(`\n ✖ _mdsvr/settings.json has errors:`);
|
|
168
175
|
result.errors?.forEach((e) => console.log(` - ${e}`));
|
|
169
176
|
console.log();
|
|
170
177
|
process.exit(1);
|
|
@@ -190,6 +197,7 @@ async function main() {
|
|
|
190
197
|
outputDir,
|
|
191
198
|
settings,
|
|
192
199
|
silent: args.silent,
|
|
200
|
+
forceOg: args.forceOg,
|
|
193
201
|
});
|
|
194
202
|
if (!args.silent) {
|
|
195
203
|
console.log(`\n ✔ Static site exported to: ${outputDir}\n`);
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EACL,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,qBAAqB,CAAC;AAkB7B,SAAS,SAAS,CAAC,IAAc;IAC/B,MAAM,IAAI,GAAe;QACvB,GAAG,EAAE,GAAG;QACR,YAAY,EAAE,KAAK;QACnB,IAAI,EAAE,IAAI;QACV,IAAI,EAAE,WAAW;QACjB,IAAI,EAAE,KAAK;QACX,MAAM,EAAE,KAAK;QACb,OAAO,EAAE,KAAK;QACd,IAAI,EAAE,KAAK;QACX,IAAI,EAAE,KAAK;QACX,QAAQ,EAAE,KAAK;QACf,aAAa,EAAE,IAAI;QACnB,MAAM,EAAE,IAAI;QACZ,OAAO,EAAE,KAAK;KACf,CAAC;IAEF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAEpB,IAAI,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YACrC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACnB,CAAC;aAAM,IAAI,GAAG,KAAK,WAAW,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YAC/C,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACtB,CAAC;aAAM,IAAI,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YAC5C,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;YACtB,IAAI,GAAG;gBAAE,IAAI,CAAC,IAAI,GAAG,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACzC,CAAC;aAAM,IAAI,GAAG,KAAK,QAAQ,EAAE,CAAC;YAC5B,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;YACtB,IAAI,GAAG;gBAAE,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC;QAC3B,CAAC;aAAM,IAAI,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YAC5C,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACnB,CAAC;aAAM,IAAI,GAAG,KAAK,UAAU,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YAC9C,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACrB,CAAC;aAAM,IAAI,GAAG,KAAK,QAAQ,EAAE,CAAC;YAC5B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACnB,CAAC;aAAM,IAAI,GAAG,KAAK,YAAY,EAAE,CAAC;YAChC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACvB,CAAC;aAAM,IAAI,GAAG,KAAK,YAAY,EAAE,CAAC;YAChC,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC;QAC7B,CAAC;aAAM,IAAI,GAAG,KAAK,UAAU,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YAC9C,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;YACtB,uEAAuE;YACvE,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;gBAChC,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC;YACpB,CAAC;iBAAM,CAAC;gBACN,IAAI,GAAG;oBAAE,CAAC,EAAE,CAAC,CAAC,0BAA0B;gBACxC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,gCAAgC;YACtD,CAAC;QACH,CAAC;aAAM,IAAI,GAAG,KAAK,YAAY,EAAE,CAAC;YAChC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACtB,CAAC;aAAM,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACzD,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;YACf,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QAC3B,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,SAAS;IAChB,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;CA0Bb,CAAC,CAAC;AACH,CAAC;AAED,KAAK,UAAU,UAAU;IACvB,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QAC/D,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC;QAC3D,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;QACzD,OAAO,GAAG,CAAC,OAAO,IAAI,OAAO,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,OAAO,CAAC;IACjB,CAAC;AACH,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,GAAW;IACpC,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;IACpD,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;IAClC,MAAM,GAAG,GACP,QAAQ,KAAK,QAAQ;QACnB,CAAC,CAAC,MAAM;QACR,CAAC,CAAC,QAAQ,KAAK,OAAO;YACpB,CAAC,CAAC,OAAO;YACT,CAAC,CAAC,UAAU,CAAC;IACnB,IAAI,CAAC,GAAG,GAAG,KAAK,GAAG,GAAG,CAAC,CAAC;AAC1B,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,GAAW;IACrC,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,sBAAsB,CAAC,CAAC;IAC5D,MAAM,eAAe,GAAG,uBAAuB,EAAE,CAAC;IAClD,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3D,MAAM,SAAS,CACb,YAAY,EACZ,IAAI,CAAC,SAAS,CAAC,eAAe,EAAE,IAAI,EAAE,CAAC,CAAC,EACxC,OAAO,CACR,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAE9C,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,SAAS,EAAE,CAAC;QACZ,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QACjB,MAAM,OAAO,GAAG,MAAM,UAAU,EAAE,CAAC;QACnC,OAAO,CAAC,GAAG,CAAC,UAAU,OAAO,EAAE,CAAC,CAAC;QACjC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,0DAA0D;IAC1D,IAAI,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;IACnB,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;QACvB,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QAC/D,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC;IACnD,CAAC;IAED,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAEtC,gBAAgB;IAChB,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,IAAI,CAAC;YACH,MAAM,YAAY,CAAC,WAAW,CAAC,CAAC;YAChC,OAAO,CAAC,GAAG,CACT,iBAAiB,IAAI,CAAC,GAAG,qCAAqC,CAC/D,CAAC;YACF,OAAO,CAAC,GAAG,CAAC,uBAAuB,IAAI,CAAC,GAAG,eAAe,CAAC,CAAC;YAC5D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YAClE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAED,oBAAoB;IACpB,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,WAAW,CAAC,CAAC;YACvD,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;gBACjB,OAAO,CAAC,GAAG,CAAC,uCAAuC,CAAC,CAAC;gBACrD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,GAAG,CAAC,wCAAwC,CAAC,CAAC;gBACtD,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC;gBACzD,OAAO,CAAC,GAAG,EAAE,CAAC;gBACd,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YAClE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAED,kBAAkB;IAClB,IACE,IAAI,CAAC,MAAM,KAAK,IAAI;QACpB,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC;QACjC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAC3B,CAAC;QACD,IAAI,CAAC;YACH,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,qBAAqB,CAAC,CAAC;YAC7D,MAAM,EAAE,gBAAgB,EAAE,GACxB,MAAM,MAAM,CAAC,+BAA+B,CAAC,CAAC;YAEhD,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,WAAW,CAAC,CAAC;YACjD,2EAA2E;YAC3E,MAAM,SAAS,GACb,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;YAC3D,MAAM,gBAAgB,CAAC;gBACrB,OAAO,EAAE,WAAW;gBACpB,SAAS;gBACT,QAAQ;gBACR,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,OAAO,EAAE,IAAI,CAAC,OAAO;aACtB,CAAC,CAAC;YAEH,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;gBACjB,OAAO,CAAC,GAAG,CAAC,kCAAkC,SAAS,IAAI,CAAC,CAAC;YAC/D,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,eAAe,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YACzE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,GAAG,EAAE;YACrC,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,aAAa,EAAE,IAAI,CAAC,aAAa;SAClC,CAAC,CAAC;QAEH,MAAM,OAAO,GAAG,MAAM,UAAU,EAAE,CAAC;QACnC,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;QAEjC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,OAAO,CAAC,GAAG,CAAC,cAAc,OAAO,IAAI,CAAC,CAAC;YACvC,OAAO,CAAC,GAAG,CAAC,eAAe,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC;YAEzC,MAAM,WAAW,GAAG,iBAAiB,EAAE,CAAC;YACxC,IAAI,IAAI,CAAC,IAAI,KAAK,WAAW,IAAI,WAAW,EAAE,CAAC;gBAC7C,OAAO,CAAC,GAAG,CAAC,sBAAsB,WAAW,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;YAClE,CAAC;YAED,OAAO,CAAC,GAAG,CAAC,gBAAgB,WAAW,EAAE,CAAC,CAAC;YAC3C,OAAO,CAAC,GAAG,CACT,cAAc,QAAQ,CAAC,IAAI,CAAC,KAAK,KAAK,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,gBAAgB,EAAE,CACnF,CAAC;YACF,OAAO,CAAC,GAAG,CACT,cAAc,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,EAAE,CAC9D,CAAC;YACF,OAAO,CAAC,GAAG,CACT,cAAc,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,EAAE,CACjE,CAAC;YACF,IAAI,QAAQ,CAAC,GAAG,CAAC,eAAe,EAAE,CAAC;gBACjC,OAAO,CAAC,GAAG,CAAC,cAAc,MAAM,CAAC,GAAG,cAAc,CAAC,CAAC;YACtD,CAAC;YAED,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;QAC3C,CAAC;QAED,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,MAAM,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAChC,CAAC;QAED,wEAAwE;QACxE,IAAI,cAAc,GAAG,KAAK,CAAC;QAC3B,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE;YAChC,IAAI,cAAc;gBAAE,OAAO;YAC3B,cAAc,GAAG,IAAI,CAAC;YACtB,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;gBACjB,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;YACpC,CAAC;YACD,MAAM,CAAC,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAClE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export interface ExportState {
|
|
2
|
+
settingsHash: string;
|
|
3
|
+
html: Record<string, PageState>;
|
|
4
|
+
og: Record<string, OgState>;
|
|
5
|
+
}
|
|
6
|
+
export interface PageState {
|
|
7
|
+
outputPath: string;
|
|
8
|
+
sourcePath: string;
|
|
9
|
+
hash: string;
|
|
10
|
+
}
|
|
11
|
+
export interface OgState {
|
|
12
|
+
outputPath: string;
|
|
13
|
+
hash: string;
|
|
14
|
+
}
|
|
15
|
+
export interface CleanupResult {
|
|
16
|
+
deleted: string[];
|
|
17
|
+
deletedDirs: string[];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Load the export state file from the root directory
|
|
21
|
+
*/
|
|
22
|
+
export declare function loadExportState(rootDir: string): Promise<ExportState>;
|
|
23
|
+
/**
|
|
24
|
+
* Save the export state file to the root directory
|
|
25
|
+
*/
|
|
26
|
+
export declare function saveExportState(rootDir: string, state: ExportState): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Migrate old OG state format to new export state format
|
|
29
|
+
*/
|
|
30
|
+
export declare function migrateOldState(rootDir: string, exportDir: string): Promise<ExportState | null>;
|
|
31
|
+
/**
|
|
32
|
+
* Calculate hash for a file
|
|
33
|
+
*/
|
|
34
|
+
export declare function calculateFileHash(filePath: string): Promise<string>;
|
|
35
|
+
/**
|
|
36
|
+
* Calculate hash of settings file
|
|
37
|
+
* If settings file doesn't exist, use default settings hash
|
|
38
|
+
*/
|
|
39
|
+
export declare function calculateSettingsHash(rootDir: string): Promise<string>;
|
|
40
|
+
/**
|
|
41
|
+
* Clean up orphaned files (files that exist in old state but not in new state)
|
|
42
|
+
*/
|
|
43
|
+
export declare function cleanupOrphanedFiles(exportDir: string, oldState: ExportState, newState: ExportState): Promise<CleanupResult>;
|
|
44
|
+
//# sourceMappingURL=export-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export-state.d.ts","sourceRoot":"","sources":["../src/export-state.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,WAAW;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAChC,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC7B;AAED,MAAM,WAAW,SAAS;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,OAAO;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAS3E;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,WAAW,GACjB,OAAO,CAAC,IAAI,CAAC,CAIf;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAgC7B;AAiBD;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAOzE;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAe5E;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CACxC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,WAAW,EACrB,QAAQ,EAAE,WAAW,GACpB,OAAO,CAAC,aAAa,CAAC,CAiCxB"}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
// Centralized export state management for HTML and OG files
|
|
2
|
+
import { promises as fs } from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { createHash } from "node:crypto";
|
|
5
|
+
import { generateDefaultSettings } from "./settings/index.js";
|
|
6
|
+
const STATE_FILE_NAME = "_mdsvr/export-state.json";
|
|
7
|
+
const OLD_STATE_FILE_NAME = ".mdsvr-og-state.json";
|
|
8
|
+
/**
|
|
9
|
+
* Load the export state file from the root directory
|
|
10
|
+
*/
|
|
11
|
+
export async function loadExportState(rootDir) {
|
|
12
|
+
const statePath = path.join(rootDir, STATE_FILE_NAME);
|
|
13
|
+
try {
|
|
14
|
+
const content = await fs.readFile(statePath, "utf-8");
|
|
15
|
+
return JSON.parse(content);
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
// File doesn't exist or is invalid, return empty state
|
|
19
|
+
return { settingsHash: "", html: {}, og: {} };
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Save the export state file to the root directory
|
|
24
|
+
*/
|
|
25
|
+
export async function saveExportState(rootDir, state) {
|
|
26
|
+
const statePath = path.join(rootDir, STATE_FILE_NAME);
|
|
27
|
+
await fs.mkdir(path.join(rootDir, "_mdsvr"), { recursive: true });
|
|
28
|
+
await fs.writeFile(statePath, JSON.stringify(state, null, 2), "utf-8");
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Migrate old OG state format to new export state format
|
|
32
|
+
*/
|
|
33
|
+
export async function migrateOldState(rootDir, exportDir) {
|
|
34
|
+
const oldOgDir = path.join(exportDir, "public", "og");
|
|
35
|
+
const oldStatePath = path.join(oldOgDir, OLD_STATE_FILE_NAME);
|
|
36
|
+
try {
|
|
37
|
+
const content = await fs.readFile(oldStatePath, "utf-8");
|
|
38
|
+
const oldOgState = JSON.parse(content);
|
|
39
|
+
// Convert old format to new format
|
|
40
|
+
const newState = {
|
|
41
|
+
settingsHash: "",
|
|
42
|
+
html: {},
|
|
43
|
+
og: {},
|
|
44
|
+
};
|
|
45
|
+
for (const [filePath, hash] of Object.entries(oldOgState)) {
|
|
46
|
+
// Generate OG filename from file path
|
|
47
|
+
const ogFilename = generateOgFilename(filePath, "jpg");
|
|
48
|
+
newState.og[filePath] = {
|
|
49
|
+
outputPath: path.join("public", "og", ogFilename),
|
|
50
|
+
hash,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
// Delete old state file after migration
|
|
54
|
+
await fs.unlink(oldStatePath);
|
|
55
|
+
return newState;
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
// Old state file doesn't exist or is invalid, return null
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Generate OG filename from file path
|
|
64
|
+
* e.g., /docs/README.md -> docs-readme-og.jpg
|
|
65
|
+
*/
|
|
66
|
+
function generateOgFilename(filePath, format = "jpg") {
|
|
67
|
+
const normalized = filePath.replace(/^\//, "").replace(/\\/g, "/");
|
|
68
|
+
const segments = normalized.split("/").map((segment) => {
|
|
69
|
+
return segment.toLowerCase().replace(/\.(md|mdx)$/, "");
|
|
70
|
+
});
|
|
71
|
+
return segments.join("-") + `-og.${format}`;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Calculate hash for a file
|
|
75
|
+
*/
|
|
76
|
+
export async function calculateFileHash(filePath) {
|
|
77
|
+
try {
|
|
78
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
79
|
+
return createHash("sha256").update(content).digest("hex");
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return "";
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Calculate hash of settings file
|
|
87
|
+
* If settings file doesn't exist, use default settings hash
|
|
88
|
+
*/
|
|
89
|
+
export async function calculateSettingsHash(rootDir) {
|
|
90
|
+
const settingsPath = path.join(rootDir, "_mdsvr/settings.json");
|
|
91
|
+
try {
|
|
92
|
+
const content = await fs.readFile(settingsPath, "utf-8");
|
|
93
|
+
const parsed = JSON.parse(content);
|
|
94
|
+
delete parsed.$schema; // Exclude schema from hash
|
|
95
|
+
return createHash("sha256").update(JSON.stringify(parsed)).digest("hex");
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
// No settings file, use hash of default settings
|
|
99
|
+
const defaultSettings = generateDefaultSettings();
|
|
100
|
+
const { $schema, ...settingsWithoutSchema } = defaultSettings;
|
|
101
|
+
return createHash("sha256")
|
|
102
|
+
.update(JSON.stringify(settingsWithoutSchema))
|
|
103
|
+
.digest("hex");
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Clean up orphaned files (files that exist in old state but not in new state)
|
|
108
|
+
*/
|
|
109
|
+
export async function cleanupOrphanedFiles(exportDir, oldState, newState) {
|
|
110
|
+
const deleted = [];
|
|
111
|
+
const deletedDirs = [];
|
|
112
|
+
// Cleanup HTML
|
|
113
|
+
for (const [urlPath, pageState] of Object.entries(oldState.html)) {
|
|
114
|
+
if (!newState.html[urlPath]) {
|
|
115
|
+
const fullPath = path.join(exportDir, pageState.outputPath);
|
|
116
|
+
try {
|
|
117
|
+
await fs.unlink(fullPath);
|
|
118
|
+
deleted.push(fullPath);
|
|
119
|
+
await cleanupEmptyDir(path.dirname(fullPath), exportDir, deletedDirs);
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
// File might not exist, ignore
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// Cleanup OG
|
|
127
|
+
for (const [urlPath, ogState] of Object.entries(oldState.og)) {
|
|
128
|
+
if (!newState.og[urlPath]) {
|
|
129
|
+
const fullPath = path.join(exportDir, ogState.outputPath);
|
|
130
|
+
try {
|
|
131
|
+
await fs.unlink(fullPath);
|
|
132
|
+
deleted.push(fullPath);
|
|
133
|
+
await cleanupEmptyDir(path.dirname(fullPath), exportDir, deletedDirs);
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
// File might not exist, ignore
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return { deleted, deletedDirs };
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Recursively delete empty directories up to rootDir
|
|
144
|
+
*/
|
|
145
|
+
async function cleanupEmptyDir(dir, rootDir, deletedDirs) {
|
|
146
|
+
while (dir !== rootDir) {
|
|
147
|
+
try {
|
|
148
|
+
const entries = await fs.readdir(dir);
|
|
149
|
+
if (entries.length === 0) {
|
|
150
|
+
await fs.rmdir(dir);
|
|
151
|
+
deletedDirs.push(dir);
|
|
152
|
+
dir = path.dirname(dir);
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
// Directory might not exist, stop
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=export-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export-state.js","sourceRoot":"","sources":["../src/export-state.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"static-export.d.ts","sourceRoot":"","sources":["../../src/generators/static-export.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"static-export.d.ts","sourceRoot":"","sources":["../../src/generators/static-export.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAkBrD,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAyBD,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAqK5E"}
|
|
@@ -7,6 +7,7 @@ import { buildSidebar } from "../template/sidebar.js";
|
|
|
7
7
|
import { renderDirectory } from "../directory.js";
|
|
8
8
|
import { buildSearchIndex } from "./search-index.js";
|
|
9
9
|
import { generateOgImage, getOgImagePath, } from "../og/index.js";
|
|
10
|
+
import { loadExportState, saveExportState, migrateOldState, cleanupOrphanedFiles, calculateFileHash, calculateSettingsHash, } from "../export-state.js";
|
|
10
11
|
function withBasePath(href, settings) {
|
|
11
12
|
const basePath = settings.generate.basePath || "";
|
|
12
13
|
if (!basePath)
|
|
@@ -17,7 +18,7 @@ function withBasePath(href, settings) {
|
|
|
17
18
|
return normalizedBase + href;
|
|
18
19
|
}
|
|
19
20
|
export async function exportStaticSite(options) {
|
|
20
|
-
|
|
21
|
+
let { rootDir, outputDir, settings, silent = false, forceOg = false, } = options;
|
|
21
22
|
try {
|
|
22
23
|
// 1. Validate input/output directories
|
|
23
24
|
const absRootDir = path.resolve(rootDir);
|
|
@@ -34,11 +35,36 @@ export async function exportStaticSite(options) {
|
|
|
34
35
|
console.log(` From: ${absRootDir}`);
|
|
35
36
|
console.log(` To: ${absOutputDir}\n`);
|
|
36
37
|
}
|
|
38
|
+
// 1.5. Load and migrate old state if needed
|
|
39
|
+
let oldState = await loadExportState(absRootDir);
|
|
40
|
+
const migratedState = await migrateOldState(absRootDir, absOutputDir);
|
|
41
|
+
if (migratedState) {
|
|
42
|
+
oldState = migratedState;
|
|
43
|
+
if (!silent) {
|
|
44
|
+
console.log(` 📦 Migrated old OG state to new format`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// 1.6. Check if settings changed - if so, force full export
|
|
48
|
+
const currentSettingsHash = await calculateSettingsHash(absRootDir);
|
|
49
|
+
if (oldState.settingsHash &&
|
|
50
|
+
oldState.settingsHash !== currentSettingsHash) {
|
|
51
|
+
if (!silent) {
|
|
52
|
+
console.log(` ⚙️ Settings changed, forcing full export`);
|
|
53
|
+
}
|
|
54
|
+
// Clear old state to force regeneration of all files
|
|
55
|
+
oldState = { settingsHash: "", html: {}, og: {} };
|
|
56
|
+
forceOg = true;
|
|
57
|
+
}
|
|
37
58
|
// 2. Process all markdown files
|
|
38
59
|
let processedCount = 0;
|
|
39
60
|
const dirMap = new Map();
|
|
40
61
|
const pageInfos = [];
|
|
41
|
-
|
|
62
|
+
const currentState = {
|
|
63
|
+
settingsHash: currentSettingsHash,
|
|
64
|
+
html: {},
|
|
65
|
+
og: {},
|
|
66
|
+
};
|
|
67
|
+
await processDirectory(absRootDir, absOutputDir, absRootDir, settings, silent, dirMap, pageInfos, currentState, (count) => {
|
|
42
68
|
processedCount = count;
|
|
43
69
|
});
|
|
44
70
|
// 3. Generate auto-index pages for directories without README/index
|
|
@@ -47,17 +73,41 @@ export async function exportStaticSite(options) {
|
|
|
47
73
|
if (!dirInfo.hasIndex) {
|
|
48
74
|
await generateAutoIndex(dirInfo, rootDir, settings);
|
|
49
75
|
autoIndexCount++;
|
|
76
|
+
const autoIndexOutputPath = path.join(dirInfo.outputPath, "index.html");
|
|
77
|
+
const relativeOutputPath = path.relative(absOutputDir, autoIndexOutputPath);
|
|
78
|
+
// Add to pageInfos so OG images are generated for auto-index pages
|
|
79
|
+
pageInfos.push({
|
|
80
|
+
urlPath: dirInfo.urlPath,
|
|
81
|
+
outputPath: autoIndexOutputPath,
|
|
82
|
+
sourcePath: "", // Auto-index pages have no source file
|
|
83
|
+
title: dirInfo.urlPath ? `Index of ${dirInfo.urlPath}` : "Index",
|
|
84
|
+
description: settings.site.description,
|
|
85
|
+
});
|
|
86
|
+
// Track auto-index page in current state
|
|
87
|
+
currentState.html[dirInfo.urlPath] = {
|
|
88
|
+
outputPath: relativeOutputPath,
|
|
89
|
+
sourcePath: "",
|
|
90
|
+
hash: "auto-index",
|
|
91
|
+
};
|
|
50
92
|
if (!silent) {
|
|
51
|
-
console.log(` ✓ ${
|
|
93
|
+
console.log(` ✓ ${relativeOutputPath} (auto-generated)`);
|
|
52
94
|
}
|
|
53
95
|
}
|
|
54
96
|
}
|
|
97
|
+
// 3.5. Cleanup orphaned files before generating new content
|
|
98
|
+
const cleanupResult = await cleanupOrphanedFiles(absOutputDir, oldState, currentState);
|
|
99
|
+
if (cleanupResult.deleted.length > 0 && !silent) {
|
|
100
|
+
console.log(` 🧹 Cleaned up ${cleanupResult.deleted.length} orphaned files`);
|
|
101
|
+
}
|
|
102
|
+
if (cleanupResult.deletedDirs.length > 0 && !silent) {
|
|
103
|
+
console.log(` 🧹 Cleaned up ${cleanupResult.deletedDirs.length} empty directories`);
|
|
104
|
+
}
|
|
55
105
|
// 4. Generate OG images if enabled
|
|
56
106
|
if (settings.seo.og?.enabled) {
|
|
57
107
|
if (!silent) {
|
|
58
108
|
console.log(`\n 🖼️ Generating OG images...`);
|
|
59
109
|
}
|
|
60
|
-
await generateOgImages(pageInfos, absOutputDir, settings, silent);
|
|
110
|
+
await generateOgImages(pageInfos, absOutputDir, absRootDir, settings, silent, forceOg, currentState, oldState);
|
|
61
111
|
}
|
|
62
112
|
// 5. Generate search-index.json if search is enabled
|
|
63
113
|
if (settings.search.enabled) {
|
|
@@ -68,6 +118,8 @@ export async function exportStaticSite(options) {
|
|
|
68
118
|
console.log(` ✓ search-index.json (${searchIndex.length} entries)`);
|
|
69
119
|
}
|
|
70
120
|
}
|
|
121
|
+
// 6. Save new export state
|
|
122
|
+
await saveExportState(absRootDir, currentState);
|
|
71
123
|
if (!silent) {
|
|
72
124
|
console.log(`\n ✓ Export complete: ${processedCount} pages generated\n`);
|
|
73
125
|
}
|
|
@@ -77,7 +129,7 @@ export async function exportStaticSite(options) {
|
|
|
77
129
|
throw new Error(`Export failed: ${message}`);
|
|
78
130
|
}
|
|
79
131
|
}
|
|
80
|
-
async function processDirectory(dirPath, outputPath, rootDir, settings, silent, dirMap, pageInfos, updateCount, count = 0) {
|
|
132
|
+
async function processDirectory(dirPath, outputPath, rootDir, settings, silent, dirMap, pageInfos, currentState, updateCount, count = 0) {
|
|
81
133
|
const entries = await fs.readdir(dirPath, { withFileTypes: true });
|
|
82
134
|
// Track this directory for auto-index generation
|
|
83
135
|
const relativePath = path.relative(rootDir, dirPath);
|
|
@@ -111,7 +163,7 @@ async function processDirectory(dirPath, outputPath, rootDir, settings, silent,
|
|
|
111
163
|
else {
|
|
112
164
|
// Create directory in output and process normally
|
|
113
165
|
await fs.mkdir(outputFilePath, { recursive: true });
|
|
114
|
-
count = await processDirectory(fullPath, outputFilePath, rootDir, settings, silent, dirMap, pageInfos, updateCount, count);
|
|
166
|
+
count = await processDirectory(fullPath, outputFilePath, rootDir, settings, silent, dirMap, pageInfos, currentState, updateCount, count);
|
|
115
167
|
}
|
|
116
168
|
}
|
|
117
169
|
else if (entry.isFile()) {
|
|
@@ -152,7 +204,7 @@ async function processDirectory(dirPath, outputPath, rootDir, settings, silent,
|
|
|
152
204
|
.replace(/\.(md|mdx)$/, "");
|
|
153
205
|
urlPath = withBasePath(rawUrlPath, settings);
|
|
154
206
|
}
|
|
155
|
-
const pageInfo = await renderMarkdownFile(fullPath, htmlOutputPath, urlPath, rootDir, settings);
|
|
207
|
+
const pageInfo = await renderMarkdownFile(fullPath, htmlOutputPath, urlPath, rootDir, settings, currentState);
|
|
156
208
|
pageInfos.push(pageInfo);
|
|
157
209
|
if (!silent) {
|
|
158
210
|
const displayPath = baseNameLower === "readme"
|
|
@@ -172,7 +224,7 @@ async function processDirectory(dirPath, outputPath, rootDir, settings, silent,
|
|
|
172
224
|
}
|
|
173
225
|
return count;
|
|
174
226
|
}
|
|
175
|
-
async function renderMarkdownFile(filePath, outputPath, urlPath, rootDir, settings) {
|
|
227
|
+
async function renderMarkdownFile(filePath, outputPath, urlPath, rootDir, settings, currentState) {
|
|
176
228
|
const content = await fs.readFile(filePath, "utf-8");
|
|
177
229
|
const ext = path.extname(filePath).toLowerCase();
|
|
178
230
|
let result;
|
|
@@ -204,10 +256,20 @@ async function renderMarkdownFile(filePath, outputPath, urlPath, rootDir, settin
|
|
|
204
256
|
isStaticExport: true,
|
|
205
257
|
});
|
|
206
258
|
await fs.writeFile(outputPath, html, "utf-8");
|
|
259
|
+
// Calculate hash and track in current state
|
|
260
|
+
const hash = await calculateFileHash(filePath);
|
|
261
|
+
const relativeOutputPath = path.relative(rootDir, outputPath);
|
|
262
|
+
const relativeSourcePath = path.relative(rootDir, filePath);
|
|
263
|
+
currentState.html[urlPath] = {
|
|
264
|
+
outputPath: relativeOutputPath,
|
|
265
|
+
sourcePath: relativeSourcePath,
|
|
266
|
+
hash,
|
|
267
|
+
};
|
|
207
268
|
// Return page info for OG generation
|
|
208
269
|
return {
|
|
209
270
|
urlPath,
|
|
210
271
|
outputPath,
|
|
272
|
+
sourcePath: filePath,
|
|
211
273
|
title,
|
|
212
274
|
description: result.frontmatter.description,
|
|
213
275
|
};
|
|
@@ -297,16 +359,15 @@ function humanizeFilename(filename) {
|
|
|
297
359
|
/**
|
|
298
360
|
* Generate OG images for all pages
|
|
299
361
|
*/
|
|
300
|
-
async function generateOgImages(pageInfos, outputDir, settings, silent) {
|
|
362
|
+
async function generateOgImages(pageInfos, outputDir, rootDir, settings, silent, forceOg = false, currentState, oldState) {
|
|
301
363
|
const publicDir = path.join(outputDir, "public");
|
|
302
364
|
const ogDir = path.join(publicDir, "og");
|
|
303
365
|
const format = settings.seo.og?.imageFormat || "jpg";
|
|
304
366
|
const ogSettings = settings.seo.og;
|
|
305
367
|
let generatedCount = 0;
|
|
306
368
|
let failedCount = 0;
|
|
369
|
+
let skippedCount = 0;
|
|
307
370
|
for (const pageInfo of pageInfos) {
|
|
308
|
-
// Skip if the page already has a custom image
|
|
309
|
-
// if (pageInfo.image) continue;
|
|
310
371
|
const ogImagePath = getOgImagePath(pageInfo.urlPath, ogDir, format, settings.generate.basePath);
|
|
311
372
|
// Build OG image data
|
|
312
373
|
const ogData = {
|
|
@@ -319,23 +380,65 @@ async function generateOgImages(pageInfos, outputDir, settings, silent) {
|
|
|
319
380
|
backgroundColor: ogSettings?.colors?.background || "#0a0a0f",
|
|
320
381
|
textColor: ogSettings?.colors?.text || "#ffffff",
|
|
321
382
|
};
|
|
322
|
-
//
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
383
|
+
// For incremental export, check if file has changed
|
|
384
|
+
let shouldGenerate = forceOg;
|
|
385
|
+
let fileHash = "";
|
|
386
|
+
if (!forceOg) {
|
|
387
|
+
// Calculate hash for the source file
|
|
388
|
+
if (pageInfo.sourcePath) {
|
|
389
|
+
try {
|
|
390
|
+
fileHash = await calculateFileHash(pageInfo.sourcePath);
|
|
391
|
+
const relativeOgPath = path.relative(outputDir, ogImagePath);
|
|
392
|
+
currentState.og[pageInfo.urlPath] = {
|
|
393
|
+
outputPath: relativeOgPath,
|
|
394
|
+
hash: fileHash,
|
|
395
|
+
};
|
|
396
|
+
// Check if hash changed by comparing with old state
|
|
397
|
+
const oldHash = oldState.html[pageInfo.urlPath]?.hash;
|
|
398
|
+
if (oldHash !== fileHash) {
|
|
399
|
+
shouldGenerate = true;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
catch {
|
|
403
|
+
// If we can't calculate hash, generate the image
|
|
404
|
+
shouldGenerate = true;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
else {
|
|
408
|
+
// Auto-index pages have no source, always generate
|
|
409
|
+
shouldGenerate = true;
|
|
410
|
+
const relativeOgPath = path.relative(outputDir, ogImagePath);
|
|
411
|
+
currentState.og[pageInfo.urlPath] = {
|
|
412
|
+
outputPath: relativeOgPath,
|
|
413
|
+
hash: "auto-index",
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
if (shouldGenerate) {
|
|
418
|
+
// Generate the OG image
|
|
419
|
+
const result = await generateOgImage(ogData, {
|
|
420
|
+
outputPath: ogImagePath,
|
|
421
|
+
format,
|
|
422
|
+
quality: 85,
|
|
423
|
+
});
|
|
424
|
+
if (result.success) {
|
|
425
|
+
generatedCount++;
|
|
426
|
+
if (!silent) {
|
|
427
|
+
const displayPath = path.relative(outputDir, ogImagePath);
|
|
428
|
+
console.log(` ✓ OG image: ${displayPath}`);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
else {
|
|
432
|
+
failedCount++;
|
|
433
|
+
if (!silent) {
|
|
434
|
+
console.log(` ✗ OG image failed: ${pageInfo.urlPath} (${result.error})`);
|
|
435
|
+
}
|
|
333
436
|
}
|
|
334
437
|
}
|
|
335
438
|
else {
|
|
336
|
-
|
|
439
|
+
skippedCount++;
|
|
337
440
|
if (!silent) {
|
|
338
|
-
console.log(`
|
|
441
|
+
console.log(` ⊘ OG image skipped: ${pageInfo.urlPath} (unchanged)`);
|
|
339
442
|
}
|
|
340
443
|
}
|
|
341
444
|
}
|
|
@@ -343,7 +446,12 @@ async function generateOgImages(pageInfos, outputDir, settings, silent) {
|
|
|
343
446
|
await createEmptyIndexFile(publicDir);
|
|
344
447
|
await createEmptyIndexFile(ogDir);
|
|
345
448
|
if (!silent) {
|
|
346
|
-
|
|
449
|
+
if (forceOg) {
|
|
450
|
+
console.log(` ✓ OG images: ${generatedCount} generated, ${failedCount} failed (forced)`);
|
|
451
|
+
}
|
|
452
|
+
else {
|
|
453
|
+
console.log(` ✓ OG images: ${generatedCount} changed, ${skippedCount} skipped, ${failedCount} failed`);
|
|
454
|
+
}
|
|
347
455
|
}
|
|
348
456
|
}
|
|
349
457
|
/**
|