@dogsbay/format-astro 0.2.0-beta.0

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,83 @@
1
+ /**
2
+ * Single source of truth for the `basePath` URL prefix.
3
+ *
4
+ * `basePath` is the path-under-host where docs are served. By default
5
+ * it's `/docs` (every existing dogsbay site uses this); set
6
+ * `site.basePath: ""` in `dogsbay.config.yml` to serve at the host
7
+ * root, or `"/handbook"` (etc.) for any other prefix.
8
+ *
9
+ * Every emitter that builds URLs, file paths, or rewrites links
10
+ * reads from `AstroProjectOptions.basePath` and runs it through
11
+ * `normalizeBasePath` so the prefix is consistent across:
12
+ *
13
+ * - generated page URLs (`/<basePath>/<slug>/`)
14
+ * - emitted file paths (`src/pages/<basePath segments>/<slug>.astro`)
15
+ * - nav.json hrefs
16
+ * - llms.txt URL prefixes
17
+ * - taxonomy term URLs
18
+ * - draft-pruning slug → href matching
19
+ *
20
+ * Changing the default lives here. Don't hardcode `/docs` anywhere
21
+ * else in `format-astro/src/`.
22
+ *
23
+ * See plans/configurable-base-path.md.
24
+ */
25
+ /** Default `basePath` when no override is supplied. */
26
+ export declare const DEFAULT_BASE_PATH = "/docs";
27
+ /**
28
+ * Normalize a user-supplied `basePath` to canonical form.
29
+ *
30
+ * Output shape:
31
+ * - `""` (empty string) → site is served at host root.
32
+ * - `"/<segments>"` (single leading slash, no trailing slash) for any
33
+ * non-empty prefix.
34
+ *
35
+ * Examples:
36
+ * - `undefined` → `"/docs"` (default)
37
+ * - `""` → `""`
38
+ * - `"/"` → `""`
39
+ * - `"docs"` → `"/docs"`
40
+ * - `"/docs"` → `"/docs"`
41
+ * - `"/docs/"` → `"/docs"`
42
+ * - `"docs/"` → `"/docs"`
43
+ * - `"/handbook/team"` → `"/handbook/team"`
44
+ *
45
+ * Schema validation in `@dogsbay/cli`'s `loadConfig` rejects values
46
+ * that contain `?`, `#`, whitespace, or repeated slashes, so this
47
+ * function only handles the trim/prepend cases.
48
+ */
49
+ export declare function normalizeBasePath(input: string | undefined): string;
50
+ /**
51
+ * Split a normalized basePath into its path segments. `""` produces
52
+ * an empty array; `"/docs"` produces `["docs"]`; `"/handbook/team"`
53
+ * produces `["handbook", "team"]`.
54
+ *
55
+ * Useful for `path.join(outputDir, "src", "pages", ...segments)`.
56
+ */
57
+ export declare function basePathSegments(basePath: string): string[];
58
+ /**
59
+ * Join a normalized basePath with a section name (when set), then a
60
+ * slug. Produces a URL path with leading slash and trailing slash for
61
+ * non-leaf paths. Empty basePath collapses cleanly.
62
+ *
63
+ * - `joinBaseUrl("/docs", "workers", "auth")` → `"/docs/workers/auth/"`
64
+ * - `joinBaseUrl("/docs", undefined, "auth")` → `"/docs/auth/"`
65
+ * - `joinBaseUrl("", "workers", "auth")` → `"/workers/auth/"`
66
+ * - `joinBaseUrl("", undefined, "auth")` → `"/auth/"`
67
+ * - `joinBaseUrl("/docs", undefined, "")` → `"/docs/"`
68
+ * - `joinBaseUrl("", undefined, "")` → `"/"`
69
+ */
70
+ export declare function joinBaseUrl(basePath: string, section: string | undefined, slug: string): string;
71
+ /**
72
+ * Build the `currentPath` value embedded in generated `.astro` pages
73
+ * for `getPagination` lookups. No trailing slash so it matches the
74
+ * shape `getPagination` compares against in `nav.json` hrefs.
75
+ *
76
+ * - default basePath, no section, slug "auth" → `"/docs/auth"`
77
+ * - default basePath, section "workers", slug "auth" → `"/docs/workers/auth"`
78
+ * - default basePath, empty slug → `"/docs"`
79
+ * - empty basePath, slug "auth" → `"/auth"`
80
+ * - empty basePath, empty slug → `"/"`
81
+ */
82
+ export declare function buildCurrentPath(basePath: string, section: string | undefined, slug: string): string;
83
+ //# sourceMappingURL=base-path.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base-path.d.ts","sourceRoot":"","sources":["../src/base-path.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,uDAAuD;AACvD,eAAO,MAAM,iBAAiB,UAAU,CAAC;AAEzC;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAKnE;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAE3D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CACzB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,IAAI,EAAE,MAAM,GACX,MAAM,CAMR;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,IAAI,EAAE,MAAM,GACX,MAAM,CAMR"}
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Single source of truth for the `basePath` URL prefix.
3
+ *
4
+ * `basePath` is the path-under-host where docs are served. By default
5
+ * it's `/docs` (every existing dogsbay site uses this); set
6
+ * `site.basePath: ""` in `dogsbay.config.yml` to serve at the host
7
+ * root, or `"/handbook"` (etc.) for any other prefix.
8
+ *
9
+ * Every emitter that builds URLs, file paths, or rewrites links
10
+ * reads from `AstroProjectOptions.basePath` and runs it through
11
+ * `normalizeBasePath` so the prefix is consistent across:
12
+ *
13
+ * - generated page URLs (`/<basePath>/<slug>/`)
14
+ * - emitted file paths (`src/pages/<basePath segments>/<slug>.astro`)
15
+ * - nav.json hrefs
16
+ * - llms.txt URL prefixes
17
+ * - taxonomy term URLs
18
+ * - draft-pruning slug → href matching
19
+ *
20
+ * Changing the default lives here. Don't hardcode `/docs` anywhere
21
+ * else in `format-astro/src/`.
22
+ *
23
+ * See plans/configurable-base-path.md.
24
+ */
25
+ /** Default `basePath` when no override is supplied. */
26
+ export const DEFAULT_BASE_PATH = "/docs";
27
+ /**
28
+ * Normalize a user-supplied `basePath` to canonical form.
29
+ *
30
+ * Output shape:
31
+ * - `""` (empty string) → site is served at host root.
32
+ * - `"/<segments>"` (single leading slash, no trailing slash) for any
33
+ * non-empty prefix.
34
+ *
35
+ * Examples:
36
+ * - `undefined` → `"/docs"` (default)
37
+ * - `""` → `""`
38
+ * - `"/"` → `""`
39
+ * - `"docs"` → `"/docs"`
40
+ * - `"/docs"` → `"/docs"`
41
+ * - `"/docs/"` → `"/docs"`
42
+ * - `"docs/"` → `"/docs"`
43
+ * - `"/handbook/team"` → `"/handbook/team"`
44
+ *
45
+ * Schema validation in `@dogsbay/cli`'s `loadConfig` rejects values
46
+ * that contain `?`, `#`, whitespace, or repeated slashes, so this
47
+ * function only handles the trim/prepend cases.
48
+ */
49
+ export function normalizeBasePath(input) {
50
+ if (input === undefined)
51
+ return DEFAULT_BASE_PATH;
52
+ const trimmed = input.replace(/^\/+/, "").replace(/\/+$/, "");
53
+ if (trimmed.length === 0)
54
+ return "";
55
+ return `/${trimmed}`;
56
+ }
57
+ /**
58
+ * Split a normalized basePath into its path segments. `""` produces
59
+ * an empty array; `"/docs"` produces `["docs"]`; `"/handbook/team"`
60
+ * produces `["handbook", "team"]`.
61
+ *
62
+ * Useful for `path.join(outputDir, "src", "pages", ...segments)`.
63
+ */
64
+ export function basePathSegments(basePath) {
65
+ return basePath.split("/").filter((s) => s.length > 0);
66
+ }
67
+ /**
68
+ * Join a normalized basePath with a section name (when set), then a
69
+ * slug. Produces a URL path with leading slash and trailing slash for
70
+ * non-leaf paths. Empty basePath collapses cleanly.
71
+ *
72
+ * - `joinBaseUrl("/docs", "workers", "auth")` → `"/docs/workers/auth/"`
73
+ * - `joinBaseUrl("/docs", undefined, "auth")` → `"/docs/auth/"`
74
+ * - `joinBaseUrl("", "workers", "auth")` → `"/workers/auth/"`
75
+ * - `joinBaseUrl("", undefined, "auth")` → `"/auth/"`
76
+ * - `joinBaseUrl("/docs", undefined, "")` → `"/docs/"`
77
+ * - `joinBaseUrl("", undefined, "")` → `"/"`
78
+ */
79
+ export function joinBaseUrl(basePath, section, slug) {
80
+ const parts = [];
81
+ for (const seg of basePathSegments(basePath))
82
+ parts.push(seg);
83
+ if (section)
84
+ parts.push(section);
85
+ if (slug && slug !== "index")
86
+ parts.push(slug);
87
+ return parts.length === 0 ? "/" : `/${parts.join("/")}/`;
88
+ }
89
+ /**
90
+ * Build the `currentPath` value embedded in generated `.astro` pages
91
+ * for `getPagination` lookups. No trailing slash so it matches the
92
+ * shape `getPagination` compares against in `nav.json` hrefs.
93
+ *
94
+ * - default basePath, no section, slug "auth" → `"/docs/auth"`
95
+ * - default basePath, section "workers", slug "auth" → `"/docs/workers/auth"`
96
+ * - default basePath, empty slug → `"/docs"`
97
+ * - empty basePath, slug "auth" → `"/auth"`
98
+ * - empty basePath, empty slug → `"/"`
99
+ */
100
+ export function buildCurrentPath(basePath, section, slug) {
101
+ const parts = [];
102
+ for (const seg of basePathSegments(basePath))
103
+ parts.push(seg);
104
+ if (section)
105
+ parts.push(section);
106
+ if (slug)
107
+ parts.push(slug);
108
+ return parts.length === 0 ? "/" : `/${parts.join("/")}`;
109
+ }
110
+ //# sourceMappingURL=base-path.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base-path.js","sourceRoot":"","sources":["../src/base-path.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,uDAAuD;AACvD,MAAM,CAAC,MAAM,iBAAiB,GAAG,OAAO,CAAC;AAEzC;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAyB;IACzD,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,iBAAiB,CAAC;IAClD,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC9D,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACpC,OAAO,IAAI,OAAO,EAAE,CAAC;AACvB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAgB;IAC/C,OAAO,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACzD,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,WAAW,CACzB,QAAgB,EAChB,OAA2B,EAC3B,IAAY;IAEZ,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,GAAG,IAAI,gBAAgB,CAAC,QAAQ,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC9D,IAAI,OAAO;QAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACjC,IAAI,IAAI,IAAI,IAAI,KAAK,OAAO;QAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/C,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;AAC3D,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,gBAAgB,CAC9B,QAAgB,EAChB,OAA2B,EAC3B,IAAY;IAEZ,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,GAAG,IAAI,gBAAgB,CAAC,QAAQ,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC9D,IAAI,OAAO;QAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACjC,IAAI,IAAI;QAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC3B,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;AAC1D,CAAC"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,22 @@
1
+ import type { FormatPlugin } from "@dogsbay/types";
2
+ /**
3
+ * `dogsbay convert --to astro` plugin.
4
+ *
5
+ * Pure content-format primitive. Emits the .astro pages, .md mirror
6
+ * endpoints (when enabled), `nav.json`, and the index redirect — but
7
+ * NOT site scaffold, site.json, robots.txt, llms.txt, middleware,
8
+ * or any other SSG-tier file. For a complete project, run
9
+ * `dogsbay site init && dogsbay site build`.
10
+ *
11
+ * Format-specific knobs accepted here are content-tier only:
12
+ * --local monorepo dev-mode dependency style (used
13
+ * only when these pages will be consumed
14
+ * by site init / build)
15
+ * --dynamic / --keep-dynamic experimental [...slug].astro routing
16
+ *
17
+ * Site-level config (siteUrl, description, deploy, AI permissions,
18
+ * llms.txt, md-mirror, etc.) lives in dogsbay.config.yml and is
19
+ * applied by `dogsbay site build`.
20
+ */
21
+ export declare const plugin: FormatPlugin;
22
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAuB,MAAM,gBAAgB,CAAC;AAGxE;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,MAAM,EAAE,YAuCpB,CAAC"}
package/dist/cli.js ADDED
@@ -0,0 +1,53 @@
1
+ import { emitAstroPages } from "./project.js";
2
+ /**
3
+ * `dogsbay convert --to astro` plugin.
4
+ *
5
+ * Pure content-format primitive. Emits the .astro pages, .md mirror
6
+ * endpoints (when enabled), `nav.json`, and the index redirect — but
7
+ * NOT site scaffold, site.json, robots.txt, llms.txt, middleware,
8
+ * or any other SSG-tier file. For a complete project, run
9
+ * `dogsbay site init && dogsbay site build`.
10
+ *
11
+ * Format-specific knobs accepted here are content-tier only:
12
+ * --local monorepo dev-mode dependency style (used
13
+ * only when these pages will be consumed
14
+ * by site init / build)
15
+ * --dynamic / --keep-dynamic experimental [...slug].astro routing
16
+ *
17
+ * Site-level config (siteUrl, description, deploy, AI permissions,
18
+ * llms.txt, md-mirror, etc.) lives in dogsbay.config.yml and is
19
+ * applied by `dogsbay site build`.
20
+ */
21
+ export const plugin = {
22
+ name: "astro",
23
+ canImport: false,
24
+ canExport: true,
25
+ detectSource: () => false,
26
+ exportOptions: [
27
+ { flags: "--local", description: "Use file: references to local monorepo packages (for development)" },
28
+ { flags: "--dynamic", description: "Use dynamic catch-all route instead of static .astro pages" },
29
+ { flags: "--keep-dynamic", description: "Keep the dynamic [..slug] route alongside static pages (for comparison)" },
30
+ ],
31
+ async export(pages, nav, output, opts) {
32
+ const codeTitles = opts.codeTitles;
33
+ const codeBlockTitle = codeTitles === "auto" ? "auto"
34
+ : codeTitles === "never" ? false
35
+ : true;
36
+ await emitAstroPages(pages, nav, output, {
37
+ siteName: opts.siteName,
38
+ theme: opts.theme,
39
+ local: opts.local,
40
+ sourceDir: opts.sourceDir,
41
+ imageOptimization: opts.optimizeImages,
42
+ codeBlockTitle,
43
+ section: opts.section,
44
+ // mdMirror defaults to true inside emitAstroPages — content tier
45
+ // emits the .md endpoints alongside .astro pages so the agent-
46
+ // readiness story works without site build (when llms.txt / Accept
47
+ // negotiation aren't needed). Site build re-emits these as part
48
+ // of the agent-tier; idempotent either way.
49
+ mdMirror: opts.mdMirror,
50
+ });
51
+ },
52
+ };
53
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,MAAM,MAAM,GAAiB;IAClC,IAAI,EAAE,OAAO;IACb,SAAS,EAAE,KAAK;IAChB,SAAS,EAAE,IAAI;IACf,YAAY,EAAE,GAAG,EAAE,CAAC,KAAK;IACzB,aAAa,EAAE;QACb,EAAE,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,mEAAmE,EAAE;QACtG,EAAE,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,4DAA4D,EAAE;QACjG,EAAE,KAAK,EAAE,gBAAgB,EAAE,WAAW,EAAE,yEAAyE,EAAE;KACpH;IAED,KAAK,CAAC,MAAM,CACV,KAAmB,EACnB,GAAc,EACd,MAAc,EACd,IAA6B;QAE7B,MAAM,UAAU,GAAG,IAAI,CAAC,UAAgC,CAAC;QACzD,MAAM,cAAc,GAClB,UAAU,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM;YAC9B,CAAC,CAAC,UAAU,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK;gBAChC,CAAC,CAAC,IAAI,CAAC;QAET,MAAM,cAAc,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE;YACvC,QAAQ,EAAE,IAAI,CAAC,QAA8B;YAC7C,KAAK,EAAE,IAAI,CAAC,KAA2B;YACvC,KAAK,EAAE,IAAI,CAAC,KAA4B;YACxC,SAAS,EAAE,IAAI,CAAC,SAA+B;YAC/C,iBAAiB,EAAE,IAAI,CAAC,cAAqC;YAC7D,cAAc;YACd,OAAO,EAAE,IAAI,CAAC,OAA6B;YAC3C,iEAAiE;YACjE,+DAA+D;YAC/D,mEAAmE;YACnE,gEAAgE;YAChE,4CAA4C;YAC5C,QAAQ,EAAE,IAAI,CAAC,QAA+B;SAC/C,CAAC,CAAC;IACL,CAAC;CACF,CAAC"}
@@ -0,0 +1,14 @@
1
+ export { treeToAstro, escapeExpr, escapeAttr, escapeTemplate } from "./serialize.js";
2
+ export { detectLeadingNodes } from "./lead.js";
3
+ export type { LeadingNodeInfo } from "./lead.js";
4
+ export type { AstroGenResult, AstroGenOptions, AstroRenderMode } from "./serialize.js";
5
+ export { DEFAULT_BASE_PATH, normalizeBasePath, basePathSegments, joinBaseUrl, buildCurrentPath, } from "./base-path.js";
6
+ export { buildLlmsTxt, buildSectionLlmsTxt, buildLlmsFullTxt, extractFirstParagraph, } from "./llms-txt.js";
7
+ export type { BuildLlmsTxtOptions, BuildLlmsFullTxtOptions, } from "./llms-txt.js";
8
+ export { exportAstroProject, emitSiteScaffold, emitSiteConfig, emitAstroPages, emitConfigDerivedFiles, emitAgentReadinessFiles, emitSwitcherMap, emitMissingTranslationStubs, } from "./project.js";
9
+ export type { AstroProjectOptions, SwitcherMap } from "./project.js";
10
+ export { emitPluginRuntime } from "./plugins.js";
11
+ export type { EmitPluginRuntimeOptions, PluginClientModulesGroup, PluginStylesGroup, PluginClientConfig, } from "./plugins.js";
12
+ export { buildTaxonomyData, emitTaxonomyForName, emitTaxonomyRoutes, getPageTerms, } from "./taxonomy.js";
13
+ export type { TaxonomyEmitConfig, TaxonomyTerm, TaxonomyPageRef, TaxonomyData, } from "./taxonomy.js";
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAMrF,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAC/C,YAAY,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACjD,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAKvF,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,EAChB,WAAW,EACX,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EACL,YAAY,EACZ,mBAAmB,EACnB,gBAAgB,EAChB,qBAAqB,GACtB,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,mBAAmB,EACnB,uBAAuB,GACxB,MAAM,eAAe,CAAC;AAavB,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,sBAAsB,EACtB,uBAAuB,EACvB,eAAe,EACf,2BAA2B,GAC5B,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAKrE,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,YAAY,EACV,wBAAwB,EACxB,wBAAwB,EACxB,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,cAAc,CAAC;AAKtB,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,YAAY,GACb,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,kBAAkB,EAClB,YAAY,EACZ,eAAe,EACf,YAAY,GACb,MAAM,eAAe,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,34 @@
1
+ // Astro serializer (TreeNode[] → Astro component markup)
2
+ export { treeToAstro, escapeExpr, escapeAttr, escapeTemplate } from "./serialize.js";
3
+ // Auto-lede detection — figures out whether a page tree already
4
+ // has a leading H1 / paragraph so format-astro can decide whether
5
+ // to inject frontmatter title + description at the top of <main>.
6
+ // See plans/auto-lede.md.
7
+ export { detectLeadingNodes } from "./lead.js";
8
+ // Base-path helpers — single source of truth for the `basePath` URL
9
+ // prefix shared across project / nav / llms-txt / taxonomy emitters.
10
+ // See plans/configurable-base-path.md.
11
+ export { DEFAULT_BASE_PATH, normalizeBasePath, basePathSegments, joinBaseUrl, buildCurrentPath, } from "./base-path.js";
12
+ // llms.txt + llms-full.txt builders (LLM discovery files)
13
+ export { buildLlmsTxt, buildSectionLlmsTxt, buildLlmsFullTxt, extractFirstParagraph, } from "./llms-txt.js";
14
+ // Project export — orchestrator + per-tier emitters
15
+ //
16
+ // `exportAstroProject` is the high-level entry: generates a complete
17
+ // Astro project. `dogsbay convert` and the legacy `import-mkdocs`
18
+ // command call it.
19
+ //
20
+ // The four `emit*` functions are the per-tier emitters that the
21
+ // orchestrator composes. `dogsbay site init` calls `emitSiteScaffold`
22
+ // alone; `dogsbay site build` calls `emitAstroPages` +
23
+ // `emitConfigDerivedFiles` + `emitAgentReadinessFiles`. Pure
24
+ // `dogsbay convert --to astro` (Step 7) calls only `emitAstroPages`.
25
+ export { exportAstroProject, emitSiteScaffold, emitSiteConfig, emitAstroPages, emitConfigDerivedFiles, emitAgentReadinessFiles, emitSwitcherMap, emitMissingTranslationStubs, } from "./project.js";
26
+ // Plugin runtime codegen — emits the entry, virtual config modules,
27
+ // stylesheets, and Vite alias file each plugin needs to participate
28
+ // in the Astro / Vite build. See plans/plugin-api.md.
29
+ export { emitPluginRuntime } from "./plugins.js";
30
+ // Taxonomy emission — Step 4 of plans/metadata-and-taxonomies.md.
31
+ // Per declared taxonomy in `dogsbay.config.yml`'s `taxonomies:` block,
32
+ // emits a JSON data file + index/term .astro route files.
33
+ export { buildTaxonomyData, emitTaxonomyForName, emitTaxonomyRoutes, getPageTerms, } from "./taxonomy.js";
34
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,yDAAyD;AACzD,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErF,gEAAgE;AAChE,kEAAkE;AAClE,kEAAkE;AAClE,0BAA0B;AAC1B,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAI/C,oEAAoE;AACpE,qEAAqE;AACrE,uCAAuC;AACvC,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,EAChB,WAAW,EACX,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AAExB,0DAA0D;AAC1D,OAAO,EACL,YAAY,EACZ,mBAAmB,EACnB,gBAAgB,EAChB,qBAAqB,GACtB,MAAM,eAAe,CAAC;AAMvB,oDAAoD;AACpD,EAAE;AACF,qEAAqE;AACrE,kEAAkE;AAClE,mBAAmB;AACnB,EAAE;AACF,gEAAgE;AAChE,sEAAsE;AACtE,uDAAuD;AACvD,6DAA6D;AAC7D,qEAAqE;AACrE,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,sBAAsB,EACtB,uBAAuB,EACvB,eAAe,EACf,2BAA2B,GAC5B,MAAM,cAAc,CAAC;AAGtB,oEAAoE;AACpE,oEAAoE;AACpE,sDAAsD;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAQjD,kEAAkE;AAClE,uEAAuE;AACvE,0DAA0D;AAC1D,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,YAAY,GACb,MAAM,eAAe,CAAC"}
package/dist/lead.d.ts ADDED
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Detect whether a page's body tree already provides a level-1
3
+ * heading and / or a leading paragraph.
4
+ *
5
+ * `format-astro` uses this to decide whether to auto-inject the
6
+ * frontmatter `title` and `description` at the top of `<main>` —
7
+ * we never overwrite writer-authored content, only fill in what
8
+ * the body doesn't already cover.
9
+ *
10
+ * See plans/auto-lede.md.
11
+ */
12
+ import type { TreeNode } from "@dogsbay/types";
13
+ export interface LeadingNodeInfo {
14
+ /**
15
+ * `true` when `tree[0]` is a level-1 heading. Heading depth
16
+ * lives at either `node.depth` (some importers) or
17
+ * `node.props.level` (others); both shapes are recognized.
18
+ */
19
+ hasH1: boolean;
20
+ /**
21
+ * `true` when the body's first non-heading node is a paragraph.
22
+ * Used to decide whether the description should be auto-rendered
23
+ * as a lede `<p>` — if the writer already wrote a lede
24
+ * paragraph, we leave it alone.
25
+ *
26
+ * "First non-heading node" means: `tree[1]` when `tree[0]` is a
27
+ * heading; otherwise `tree[0]`. So `# Title\nLede paragraph`
28
+ * yields `{ hasH1: true, hasLede: true }`.
29
+ */
30
+ hasLede: boolean;
31
+ }
32
+ /**
33
+ * Inspect the leading nodes of a page tree.
34
+ *
35
+ * Defensive against empty trees and missing properties — returns
36
+ * `false` for both flags when the tree is empty.
37
+ */
38
+ export declare function detectLeadingNodes(tree: TreeNode[] | undefined): LeadingNodeInfo;
39
+ //# sourceMappingURL=lead.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lead.d.ts","sourceRoot":"","sources":["../src/lead.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,KAAK,EAAE,OAAO,CAAC;IACf;;;;;;;;;OASG;IACH,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,QAAQ,EAAE,GAAG,SAAS,GAC3B,eAAe,CAcjB"}
package/dist/lead.js ADDED
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Inspect the leading nodes of a page tree.
3
+ *
4
+ * Defensive against empty trees and missing properties — returns
5
+ * `false` for both flags when the tree is empty.
6
+ */
7
+ export function detectLeadingNodes(tree) {
8
+ if (!tree || tree.length === 0) {
9
+ return { hasH1: false, hasLede: false };
10
+ }
11
+ const first = tree[0];
12
+ const firstIsH1 = isH1(first);
13
+ if (firstIsH1) {
14
+ const second = tree[1];
15
+ return { hasH1: true, hasLede: isParagraph(second) };
16
+ }
17
+ return { hasH1: false, hasLede: isParagraph(first) };
18
+ }
19
+ function isH1(node) {
20
+ if (!node || node.type !== "heading")
21
+ return false;
22
+ // Some importers (dogsbay-md, mkdocs) attach depth as a top-level
23
+ // field; others (Starlight via mdx-jsx) use props.level. Both
24
+ // conventions are valid — check both.
25
+ const depth = node.depth;
26
+ if (typeof depth === "number")
27
+ return depth === 1;
28
+ const level = node.props?.level;
29
+ if (typeof level === "number")
30
+ return level === 1;
31
+ return false;
32
+ }
33
+ function isParagraph(node) {
34
+ if (!node)
35
+ return false;
36
+ return node.type === "paragraph";
37
+ }
38
+ //# sourceMappingURL=lead.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lead.js","sourceRoot":"","sources":["../src/lead.ts"],"names":[],"mappings":"AAiCA;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAChC,IAA4B;IAE5B,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/B,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAC1C,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACtB,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;IAE9B,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACvB,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;IACvD,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;AACvD,CAAC;AAED,SAAS,IAAI,CAAC,IAA0B;IACtC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IACnD,kEAAkE;IAClE,8DAA8D;IAC9D,sCAAsC;IACtC,MAAM,KAAK,GAAI,IAAsC,CAAC,KAAK,CAAC;IAC5D,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,KAAK,CAAC,CAAC;IAClD,MAAM,KAAK,GAAI,IAAI,CAAC,KAAwC,EAAE,KAAK,CAAC;IACpE,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,KAAK,CAAC,CAAC;IAClD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,WAAW,CAAC,IAA0B;IAC7C,IAAI,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC;IACxB,OAAO,IAAI,CAAC,IAAI,KAAK,WAAW,CAAC;AACnC,CAAC"}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * llms.txt + llms-full.txt builders.
3
+ *
4
+ * Produces the LLM-discovery files defined at llmstxt.org and recommended
5
+ * by Cloudflare's agent-readiness post. Pure functions: each builder
6
+ * takes (siteConfig, nav, pages) and returns a string.
7
+ *
8
+ * Three outputs:
9
+ * - `buildLlmsTxt(...)` → top-level index, grouped by nav
10
+ * - `buildSectionLlmsTxt(...)` → per-section index for one nav group
11
+ * - `buildLlmsFullTxt(...)` → bundled body of every page
12
+ *
13
+ * Body serialization is opt-in via a callback so this module stays
14
+ * dependency-free (only @dogsbay/types). Callers wire the actual
15
+ * `treeToDogsbayMd` serializer when they want full-body bundles.
16
+ */
17
+ import type { ExportPage, NavItem, SiteConfig, TreeNode } from "@dogsbay/types";
18
+ export interface BuildLlmsTxtOptions {
19
+ /**
20
+ * Used to derive page slugs from nav hrefs. Defaults to
21
+ * `DEFAULT_BASE_PATH` (`"/docs"`). Set to `""` for sites served at
22
+ * the host root.
23
+ */
24
+ hrefPrefix?: string;
25
+ /**
26
+ * When the site has a siteUrl, emitted entry URLs become absolute
27
+ * (e.g. `https://example.com/docs/x.md`). When omitted, URLs stay
28
+ * relative (`/docs/x.md`).
29
+ */
30
+ siteUrl?: string;
31
+ /** Cap on description text length. Default: 160. */
32
+ descriptionLimit?: number;
33
+ /**
34
+ * Label for top-level leaf pages that aren't under a nav group.
35
+ * Default: "Documentation".
36
+ */
37
+ topLevelLabel?: string;
38
+ }
39
+ export interface BuildLlmsFullTxtOptions extends BuildLlmsTxtOptions {
40
+ /**
41
+ * "body" → full markdown body of each page (requires `serializePage`)
42
+ * "description" → page title + description only
43
+ * Default: "body" if `serializePage` is provided, else "description".
44
+ */
45
+ summary?: "body" | "description";
46
+ /**
47
+ * Required when `summary === "body"`. Returns the canonical markdown
48
+ * body for a page (typically `treeToDogsbayMd(page.tree)`). Kept as a
49
+ * callback so this module doesn't pull in format-dogsbay-md.
50
+ */
51
+ serializePage?: (page: ExportPage) => string;
52
+ }
53
+ /**
54
+ * Build the top-level llms.txt index for a site.
55
+ *
56
+ * Layout:
57
+ * - One `## {label}` section per top-level nav group with children.
58
+ * - Top-level leaf nav items collected into a single
59
+ * `## {topLevelLabel}` block at the end.
60
+ * - External hrefs and pages not in nav are skipped.
61
+ */
62
+ export declare function buildLlmsTxt(siteConfig: Pick<SiteConfig, "siteName" | "description" | "siteUrl">, nav: NavItem[], pages: ExportPage[], options?: BuildLlmsTxtOptions): string;
63
+ /**
64
+ * Per-section llms.txt — same shape as the root index, scoped to one
65
+ * top-level nav group. Useful for `/docs/{section}/llms.txt` so agents
66
+ * can pull only the section they care about.
67
+ */
68
+ export declare function buildSectionLlmsTxt(siteConfig: Pick<SiteConfig, "siteName" | "siteUrl">, group: NavItem, pages: ExportPage[], options?: BuildLlmsTxtOptions): string;
69
+ /**
70
+ * Bundle every page reachable from `nav` into a single document, in
71
+ * nav order. Each page is delimited by a `# Title` header and `URL:`
72
+ * line, then either the full body (default) or just a description.
73
+ */
74
+ export declare function buildLlmsFullTxt(siteConfig: Pick<SiteConfig, "siteName" | "description" | "siteUrl">, nav: NavItem[], pages: ExportPage[], options?: BuildLlmsFullTxtOptions): string;
75
+ /**
76
+ * Extract plain text of the first paragraph in a page tree. Cross-shape
77
+ * tolerant: handles `node.inline` (dogsbay-md parser) and
78
+ * `node.children[{type: "prose", inline}]` (Starlight importer).
79
+ */
80
+ export declare function extractFirstParagraph(tree: TreeNode[]): string;
81
+ //# sourceMappingURL=llms-txt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llms-txt.d.ts","sourceRoot":"","sources":["../src/llms-txt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EACV,UAAU,EAEV,OAAO,EACP,UAAU,EACV,QAAQ,EACT,MAAM,gBAAgB,CAAC;AAUxB,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oDAAoD;IACpD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,uBAAwB,SAAQ,mBAAmB;IAClE;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,aAAa,CAAC;IACjC;;;;OAIG;IACH,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,MAAM,CAAC;CAC9C;AAID;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC1B,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,UAAU,GAAG,aAAa,GAAG,SAAS,CAAC,EACpE,GAAG,EAAE,OAAO,EAAE,EACd,KAAK,EAAE,UAAU,EAAE,EACnB,OAAO,GAAE,mBAAwB,GAChC,MAAM,CAoDR;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,UAAU,GAAG,SAAS,CAAC,EACpD,KAAK,EAAE,OAAO,EACd,KAAK,EAAE,UAAU,EAAE,EACnB,OAAO,GAAE,mBAAwB,GAChC,MAAM,CAqBR;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,UAAU,GAAG,aAAa,GAAG,SAAS,CAAC,EACpE,GAAG,EAAE,OAAO,EAAE,EACd,KAAK,EAAE,UAAU,EAAE,EACnB,OAAO,GAAE,uBAA4B,GACpC,MAAM,CA8CR;AAsGD;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,MAAM,CAO9D"}