mdzilla 0.0.2 → 0.0.4

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.
@@ -1,6 +1,6 @@
1
1
  import { mkdir, readFile, readdir, stat, writeFile } from "node:fs/promises";
2
2
  import { basename, dirname, extname, join } from "node:path";
3
- import { parseMeta, renderToText } from "md4x";
3
+ import { parseMeta, renderToMarkdown, renderToText } from "md4x";
4
4
  import { existsSync } from "node:fs";
5
5
  import { tmpdir } from "node:os";
6
6
  //#region src/docs/manager.ts
@@ -279,6 +279,7 @@ async function _scanNav(dirPath, parentPath, options) {
279
279
  if (draft && !options.drafts) continue;
280
280
  const meta = applyNavigationOverride(parseMeta(await readFile(fullPath, "utf8")));
281
281
  if (meta.navigation === false) continue;
282
+ const resolvedOrder = typeof meta.order === "number" ? meta.order : order;
282
283
  const resolvedSlug = slug === "index" ? "" : slug;
283
284
  const title = meta.title || humanizeSlug(slug) || "index";
284
285
  const entryPath = resolvedSlug === "" ? parentPath === "/" ? "/" : parentPath : parentPath === "/" ? `/${resolvedSlug}` : `${parentPath}/${resolvedSlug}`;
@@ -287,7 +288,7 @@ async function _scanNav(dirPath, parentPath, options) {
287
288
  slug: resolvedSlug,
288
289
  path: entryPath,
289
290
  title,
290
- order,
291
+ order: resolvedOrder,
291
292
  ...meta.icon ? { icon: meta.icon } : {},
292
293
  ...meta.description ? { description: meta.description } : {},
293
294
  ...draft ? { draft: true } : {},
@@ -308,8 +309,10 @@ var DocsSourceFS = class extends DocsSource {
308
309
  this.dir = dir;
309
310
  }
310
311
  async load() {
312
+ const tree = await scanNav(this.dir);
313
+ await applyNavManifest(tree, this.dir);
311
314
  return {
312
- tree: await scanNav(this.dir),
315
+ tree,
313
316
  fileMap: await buildFileMap("/", this.dir)
314
317
  };
315
318
  }
@@ -341,6 +344,30 @@ async function buildFileMap(parentPath, dirPath) {
341
344
  }
342
345
  return map;
343
346
  }
347
+ /**
348
+ * Read `_navigation.json` manifest (exported by mdzilla) and apply its
349
+ * ordering to the scanned nav tree. Only reorders; does not add/remove entries.
350
+ */
351
+ async function applyNavManifest(tree, dir) {
352
+ let manifest;
353
+ try {
354
+ manifest = JSON.parse(await readFile(join(dir, "_navigation.json"), "utf8"));
355
+ } catch {
356
+ return;
357
+ }
358
+ reorderTree(tree, manifest);
359
+ }
360
+ /** Recursively reorder tree entries to match manifest ordering. */
361
+ function reorderTree(entries, manifest) {
362
+ const pathIndex = new Map(manifest.map((m, i) => [m.path, i]));
363
+ entries.sort((a, b) => {
364
+ return (pathIndex.get(a.path) ?? Infinity) - (pathIndex.get(b.path) ?? Infinity);
365
+ });
366
+ for (const entry of entries) if (entry.children?.length) {
367
+ const manifestEntry = manifest.find((m) => m.path === entry.path);
368
+ if (manifestEntry?.children) reorderTree(entry.children, manifestEntry.children);
369
+ }
370
+ }
344
371
  //#endregion
345
372
  //#region src/docs/sources/git.ts
346
373
  var DocsSourceGit = class extends DocsSource {
@@ -763,25 +790,49 @@ async function npmProvider(input) {
763
790
  }
764
791
  //#endregion
765
792
  //#region src/docs/exporter.ts
766
- var DocsExporter = class {};
767
- var DocsExporterFS = class extends DocsExporter {
768
- dir;
769
- constructor(dir) {
770
- super();
771
- this.dir = dir;
772
- }
773
- async export(manager, options = {}) {
774
- for (const flat of manager.flat) {
775
- if (!options.includeStubs && flat.entry.page === false) continue;
776
- let content = await manager.getContent(flat);
777
- if (content === void 0) continue;
778
- if (options.plainText) content = renderToText(content);
779
- const filePath = flat.entry.path === "/" ? "/index.md" : `${flat.entry.path}.md`;
780
- const dest = join(this.dir, filePath);
781
- await mkdir(dirname(dest), { recursive: true });
782
- await writeFile(dest, content, "utf8");
783
- }
793
+ /** Paths to skip during export (generated by source, not actual docs) */
794
+ const IGNORED_PATHS = new Set(["/llms.txt", "/llms-full.txt"]);
795
+ /**
796
+ * Export documentation entries to a local filesystem directory as flat `.md` files.
797
+ *
798
+ * Each entry is written to `<dir>/<path>.md` (or `<dir>/<path>/index.md` for directory
799
+ * index pages). Navigation order is preserved via `order` frontmatter in pages and
800
+ * `.navigation.yml` files in directories.
801
+ *
802
+ * A `README.md` table of contents is generated at the root of the output directory.
803
+ */
804
+ async function exportDocsToFS(manager, dir, options = {}) {
805
+ const rootEntry = manager.flat.find((f) => f.entry.path === "/");
806
+ const tocLines = [`# ${options.title ?? rootEntry?.entry.title ?? "Table of Contents"}`, ""];
807
+ const writtenFiles = /* @__PURE__ */ new Set();
808
+ const dirPaths = /* @__PURE__ */ new Set();
809
+ collectDirPaths(manager.tree, dirPaths);
810
+ for (const flat of manager.flat) {
811
+ if (options.filter ? !options.filter(flat) : flat.entry.page === false) continue;
812
+ if (IGNORED_PATHS.has(flat.entry.path)) continue;
813
+ let content = await manager.getContent(flat);
814
+ if (content === void 0) continue;
815
+ const cleanContent = options.plainText ? renderToText(content) : renderToMarkdown(content);
816
+ const filePath = flat.entry.path === "/" || dirPaths.has(flat.entry.path) ? flat.entry.path === "/" ? "/index.md" : `${flat.entry.path}/index.md` : flat.entry.path.endsWith(".md") ? flat.entry.path : `${flat.entry.path}.md`;
817
+ const dest = join(dir, filePath);
818
+ await mkdir(dirname(dest), { recursive: true });
819
+ await writeFile(dest, cleanContent, "utf8");
820
+ writtenFiles.add(filePath.slice(1));
821
+ const indent = " ".repeat(flat.depth);
822
+ const desc = flat.entry.description ? `: ${flat.entry.description}` : "";
823
+ tocLines.push(`${indent}- [${flat.entry.title}](.${filePath})${desc}`);
824
+ }
825
+ let tocFile = options.tocFile ?? "README.md";
826
+ if (writtenFiles.has(tocFile)) tocFile = `_${tocFile}`;
827
+ await writeFile(join(dir, tocFile), tocLines.join("\n") + "\n", "utf8");
828
+ await writeFile(join(dir, "_navigation.json"), JSON.stringify(manager.tree, null, 2) + "\n", "utf8");
829
+ }
830
+ /** Collect all paths that are directories (have children in the tree). */
831
+ function collectDirPaths(entries, set) {
832
+ for (const entry of entries) if (entry.children?.length) {
833
+ set.add(entry.path);
834
+ collectDirPaths(entry.children, set);
784
835
  }
785
- };
836
+ }
786
837
  //#endregion
787
- export { DocsSourceGit as a, DocsManager as c, DocsSourceHTTP as i, DocsExporterFS as n, DocsSourceFS as o, DocsSourceNpm as r, DocsSource as s, DocsExporter as t };
838
+ export { DocsSourceFS as a, DocsSourceGit as i, DocsSourceNpm as n, DocsSource as o, DocsSourceHTTP as r, DocsManager as s, exportDocsToFS as t };
package/dist/cli/main.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { a as DocsSourceGit, c as DocsManager, i as DocsSourceHTTP, n as DocsExporterFS, o as DocsSourceFS, r as DocsSourceNpm } from "../_chunks/exporter.mjs";
2
+ import { a as DocsSourceFS, i as DocsSourceGit, n as DocsSourceNpm, r as DocsSourceHTTP, s as DocsManager, t as exportDocsToFS } from "../_chunks/exporter.mjs";
3
3
  import { readFile } from "node:fs/promises";
4
4
  import { basename } from "node:path";
5
5
  import { parseMeta, renderToAnsi, renderToText } from "md4x";
@@ -765,7 +765,7 @@ async function main() {
765
765
  const docs = new DocsManager(isURL ? new DocsSourceHTTP(docsDir) : docsDir.startsWith("gh:") ? new DocsSourceGit(docsDir) : docsDir.startsWith("npm:") ? new DocsSourceNpm(docsDir) : new DocsSourceFS(docsDir));
766
766
  await docs.load();
767
767
  if (exportDir) {
768
- await new DocsExporterFS(exportDir).export(docs, { plainText: plain });
768
+ await exportDocsToFS(docs, exportDir, { plainText: plain });
769
769
  console.log(`Exported ${docs.pages.length} pages to ${exportDir}`);
770
770
  return;
771
771
  }
package/dist/index.d.mts CHANGED
@@ -144,18 +144,24 @@ declare class DocsManager {
144
144
  //#endregion
145
145
  //#region src/docs/exporter.d.ts
146
146
  interface ExportOptions {
147
- /** Include entries where page === false (directory stubs). Default: false */
148
- includeStubs?: boolean;
147
+ /** Custom filter callback. Return false to skip an entry. Default: skip stubs (page === false) */
148
+ filter?: (entry: FlatEntry) => boolean;
149
149
  /** Compile markdown to plain text using md4x. Default: false */
150
150
  plainText?: boolean;
151
+ /** Filename for the generated table of contents. Default: "README.md" */
152
+ tocFile?: string;
153
+ /** Title for the table of contents. Default: root entry title or "Table of Contents" */
154
+ title?: string;
151
155
  }
152
- declare abstract class DocsExporter {
153
- abstract export(manager: DocsManager, options?: ExportOptions): Promise<void>;
154
- }
155
- declare class DocsExporterFS extends DocsExporter {
156
- dir: string;
157
- constructor(dir: string);
158
- export(manager: DocsManager, options?: ExportOptions): Promise<void>;
159
- }
156
+ /**
157
+ * Export documentation entries to a local filesystem directory as flat `.md` files.
158
+ *
159
+ * Each entry is written to `<dir>/<path>.md` (or `<dir>/<path>/index.md` for directory
160
+ * index pages). Navigation order is preserved via `order` frontmatter in pages and
161
+ * `.navigation.yml` files in directories.
162
+ *
163
+ * A `README.md` table of contents is generated at the root of the output directory.
164
+ */
165
+ declare function exportDocsToFS(manager: DocsManager, dir: string, options?: ExportOptions): Promise<void>;
160
166
  //#endregion
161
- export { DocsExporter, DocsExporterFS, DocsManager, DocsSource, DocsSourceFS, DocsSourceGit, type DocsSourceGitOptions, DocsSourceHTTP, type DocsSourceHTTPOptions, DocsSourceNpm, type DocsSourceNpmOptions, type ExportOptions, type FlatEntry, type NavEntry };
167
+ export { DocsManager, DocsSource, DocsSourceFS, DocsSourceGit, type DocsSourceGitOptions, DocsSourceHTTP, type DocsSourceHTTPOptions, DocsSourceNpm, type DocsSourceNpmOptions, type ExportOptions, type FlatEntry, type NavEntry, exportDocsToFS };
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { a as DocsSourceGit, c as DocsManager, i as DocsSourceHTTP, n as DocsExporterFS, o as DocsSourceFS, r as DocsSourceNpm, s as DocsSource, t as DocsExporter } from "./_chunks/exporter.mjs";
2
- export { DocsExporter, DocsExporterFS, DocsManager, DocsSource, DocsSourceFS, DocsSourceGit, DocsSourceHTTP, DocsSourceNpm };
1
+ import { a as DocsSourceFS, i as DocsSourceGit, n as DocsSourceNpm, o as DocsSource, r as DocsSourceHTTP, s as DocsManager, t as exportDocsToFS } from "./_chunks/exporter.mjs";
2
+ export { DocsManager, DocsSource, DocsSourceFS, DocsSourceGit, DocsSourceHTTP, DocsSourceNpm, exportDocsToFS };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mdzilla",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "description": "",
5
5
  "license": "MIT",
6
6
  "repository": "pi0/mdzilla",
@@ -32,7 +32,7 @@
32
32
  "dependencies": {
33
33
  "@speed-highlight/core": "^1.2.14",
34
34
  "giget": "^3.1.2",
35
- "md4x": ">=0.0.21",
35
+ "md4x": ">=0.0.22",
36
36
  "mdream": "^0.16.0",
37
37
  "std-env": "4.0.0-rc.1"
38
38
  },