mdzilla 0.0.3 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -12,7 +12,9 @@ Markdown browser for humans and agents.
12
12
 
13
13
  </p>
14
14
 
15
- > Browse docs from local directories, GitHub repos, and remote websites — all from your terminal. Built on [md4x](https://github.com/unjs/md4x), [mdream](https://github.com/harlan-zw/mdream), [giget](https://github.com/unjs/giget) and [speed-highlight](https://github.com/speed-highlight/core).
15
+ > Browse docs from local directories, GitHub repos, and remote websites — all from your terminal.
16
+
17
+ Built with [md4x](https://github.com/unjs/md4x), [mdream](https://github.com/harlan-zw/mdream), [giget](https://github.com/unjs/giget) and [speed-highlight](https://github.com/speed-highlight/core), [nitro](https://v3.nitro.build/), [h3](https://h3.dev/), [srvx](https://srvx.h3.dev/) and [vite](https://vite.dev/).
16
18
 
17
19
  Supports any website with [`/llms.txt`](https://llmstxt.org/) or markdown content negotiation.
18
20
 
@@ -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 {
@@ -768,8 +795,9 @@ const IGNORED_PATHS = new Set(["/llms.txt", "/llms-full.txt"]);
768
795
  /**
769
796
  * Export documentation entries to a local filesystem directory as flat `.md` files.
770
797
  *
771
- * Each entry is written to `<dir>/<path>.md`. Directory stubs (`page === false`)
772
- * are skipped by default unless a custom `filter` is provided.
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.
773
801
  *
774
802
  * A `README.md` table of contents is generated at the root of the output directory.
775
803
  */
@@ -777,13 +805,15 @@ async function exportDocsToFS(manager, dir, options = {}) {
777
805
  const rootEntry = manager.flat.find((f) => f.entry.path === "/");
778
806
  const tocLines = [`# ${options.title ?? rootEntry?.entry.title ?? "Table of Contents"}`, ""];
779
807
  const writtenFiles = /* @__PURE__ */ new Set();
808
+ const dirPaths = /* @__PURE__ */ new Set();
809
+ collectDirPaths(manager.tree, dirPaths);
780
810
  for (const flat of manager.flat) {
781
811
  if (options.filter ? !options.filter(flat) : flat.entry.page === false) continue;
782
812
  if (IGNORED_PATHS.has(flat.entry.path)) continue;
783
813
  let content = await manager.getContent(flat);
784
814
  if (content === void 0) continue;
785
815
  const cleanContent = options.plainText ? renderToText(content) : renderToMarkdown(content);
786
- const filePath = flat.entry.path === "/" ? "/index.md" : flat.entry.path.endsWith(".md") ? flat.entry.path : `${flat.entry.path}.md`;
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`;
787
817
  const dest = join(dir, filePath);
788
818
  await mkdir(dirname(dest), { recursive: true });
789
819
  await writeFile(dest, cleanContent, "utf8");
@@ -795,6 +825,14 @@ async function exportDocsToFS(manager, dir, options = {}) {
795
825
  let tocFile = options.tocFile ?? "README.md";
796
826
  if (writtenFiles.has(tocFile)) tocFile = `_${tocFile}`;
797
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);
835
+ }
798
836
  }
799
837
  //#endregion
800
838
  export { DocsSourceFS as a, DocsSourceGit as i, DocsSourceNpm as n, DocsSource as o, DocsSourceHTTP as r, DocsManager as s, exportDocsToFS as t };