@writedocs/generator 0.4.8 → 0.4.9

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.
@@ -0,0 +1,78 @@
1
+ // Which files in a content directory are pages. Plain JavaScript, not
2
+ // TypeScript, so `writedocs validate` can load it with plain Node (Node
3
+ // refuses to strip types under node_modules - see lib/icons.js's comment);
4
+ // lib/config.ts re-exports findAllPages() for everything inside Astro.
5
+ import fs from 'node:fs';
6
+ import path from 'node:path';
7
+ import matter from 'gray-matter';
8
+
9
+ // Top-level folders of a content directory that are never scanned for
10
+ // pages - build output, dependencies, and static assets.
11
+ export const EXCLUDED_TOP_LEVEL_DIRS = new Set(['node_modules', 'dist', '.astro', '.writedocs', 'public', '.git']);
12
+
13
+ /** Recursively finds every .md/.mdx file under `contentDir` that has a
14
+ * frontmatter block, skipping the handful of build/dependency
15
+ * directories a real content directory tends to also contain (see
16
+ * EXCLUDED_TOP_LEVEL_DIRS above) - docs/ is scanned exactly like any
17
+ * other folder, no special-casing. Returns POSIX-relative paths (from
18
+ * `contentDir`) suitable to hand straight to Astro's `glob()` loader as
19
+ * a literal `pattern` array - see content.config.ts's `pages`
20
+ * collection, and [...slug].astro, which needs the identical list to
21
+ * decide whether calling `getCollection('pages')` is worth doing at all
22
+ * (see content.config.ts's own comment on why an empty collection still
23
+ * needs to exist, just backed by a no-op loader, to avoid Astro's "does
24
+ * not exist or is empty" warning). Also reused directly by
25
+ * astro.config.mjs's noindex/sitemap scan and by `writedocs validate`, so
26
+ * both always see exactly the same file set that actually becomes a page.
27
+ * Synchronous and re-run from scratch wherever it's called rather than
28
+ * cached and shared across modules - cheap enough in practice (a docs
29
+ * site's own file count) not to matter. */
30
+ export function findAllPages(contentDir) {
31
+ const results = [];
32
+ function walk(dir, relBase) {
33
+ let entries;
34
+ try {
35
+ entries = fs.readdirSync(dir, { withFileTypes: true });
36
+ } catch {
37
+ return;
38
+ }
39
+ for (const entry of entries) {
40
+ const rel = relBase ? `${relBase}/${entry.name}` : entry.name;
41
+ const abs = path.join(dir, entry.name);
42
+ if (entry.isDirectory()) {
43
+ if (relBase === '' && EXCLUDED_TOP_LEVEL_DIRS.has(entry.name)) continue;
44
+ walk(abs, rel);
45
+ continue;
46
+ }
47
+ if (!entry.isFile() || !/\.mdx?$/i.test(entry.name)) continue;
48
+ let raw;
49
+ try {
50
+ raw = fs.readFileSync(abs, 'utf-8');
51
+ } catch {
52
+ continue;
53
+ }
54
+ let data;
55
+ try {
56
+ ({ data } = matter(raw));
57
+ } catch {
58
+ // Frontmatter that isn't valid YAML: still a page (it opens a
59
+ // frontmatter block), so the error surfaces with this file's name -
60
+ // from `writedocs validate`, or Astro's own loader in the build -
61
+ // instead of as a bare YAML error thrown from here.
62
+ if (/^---\r?\n/.test(raw)) results.push(rel);
63
+ continue;
64
+ }
65
+ if (Object.keys(data).length === 0) continue; // no frontmatter at all - not a page
66
+ results.push(rel);
67
+ }
68
+ }
69
+ walk(contentDir, '');
70
+ return results;
71
+ }
72
+
73
+ /** The id writedocs.json's navigation refers to a page by: its path from
74
+ * the content directory, without the extension or a trailing `/index`
75
+ * (same algorithm as fileIdForEntry() in lib/config.ts). */
76
+ export function fileIdForPath(relativePath) {
77
+ return relativePath.replace(/\.mdx?$/i, '').replace(/\/index$/, '');
78
+ }