@dogsbay/format-astro 0.2.0-beta.1 → 0.2.0-beta.100

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.
Files changed (50) hide show
  1. package/dist/base-path.d.ts +115 -7
  2. package/dist/base-path.d.ts.map +1 -1
  3. package/dist/base-path.js +147 -8
  4. package/dist/base-path.js.map +1 -1
  5. package/dist/blog.d.ts +134 -0
  6. package/dist/blog.d.ts.map +1 -0
  7. package/dist/blog.js +319 -0
  8. package/dist/blog.js.map +1 -0
  9. package/dist/cli.d.ts.map +1 -1
  10. package/dist/cli.js +1 -0
  11. package/dist/cli.js.map +1 -1
  12. package/dist/diff-decoration.d.ts +79 -0
  13. package/dist/diff-decoration.d.ts.map +1 -0
  14. package/dist/diff-decoration.js +541 -0
  15. package/dist/diff-decoration.js.map +1 -0
  16. package/dist/granularity.d.ts +83 -0
  17. package/dist/granularity.d.ts.map +1 -0
  18. package/dist/granularity.js +247 -0
  19. package/dist/granularity.js.map +1 -0
  20. package/dist/index.d.ts +22 -4
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +26 -3
  23. package/dist/index.js.map +1 -1
  24. package/dist/lead.d.ts +19 -0
  25. package/dist/lead.d.ts.map +1 -1
  26. package/dist/lead.js +101 -6
  27. package/dist/lead.js.map +1 -1
  28. package/dist/llms-txt.d.ts +48 -2
  29. package/dist/llms-txt.d.ts.map +1 -1
  30. package/dist/llms-txt.js +131 -14
  31. package/dist/llms-txt.js.map +1 -1
  32. package/dist/plugins.js +1 -1
  33. package/dist/plugins.js.map +1 -1
  34. package/dist/project.d.ts +310 -13
  35. package/dist/project.d.ts.map +1 -1
  36. package/dist/project.js +2270 -193
  37. package/dist/project.js.map +1 -1
  38. package/dist/serialize.d.ts +23 -0
  39. package/dist/serialize.d.ts.map +1 -1
  40. package/dist/serialize.js +442 -136
  41. package/dist/serialize.js.map +1 -1
  42. package/dist/sitemap.d.ts +81 -0
  43. package/dist/sitemap.d.ts.map +1 -0
  44. package/dist/sitemap.js +200 -0
  45. package/dist/sitemap.js.map +1 -0
  46. package/dist/taxonomy.d.ts +61 -1
  47. package/dist/taxonomy.d.ts.map +1 -1
  48. package/dist/taxonomy.js +83 -21
  49. package/dist/taxonomy.js.map +1 -1
  50. package/package.json +8 -7
@@ -1,10 +1,12 @@
1
1
  /**
2
2
  * Single source of truth for the `basePath` URL prefix.
3
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.
4
+ * `basePath` is the path-under-host where docs are served. The default
5
+ * is `""` (host root, matching every other SSG); set
6
+ * `site.basePath: "/docs"` in `dogsbay.config.yml` for the legacy
7
+ * "docs nested under marketing site" shape, or `"/handbook"` (etc.)
8
+ * for any other prefix. See plans/default-basepath-root.md for the
9
+ * rationale behind the default flip in v0.3.
8
10
  *
9
11
  * Every emitter that builds URLs, file paths, or rewrites links
10
12
  * reads from `AstroProjectOptions.basePath` and runs it through
@@ -22,8 +24,18 @@
22
24
  *
23
25
  * See plans/configurable-base-path.md.
24
26
  */
25
- /** Default `basePath` when no override is supplied. */
26
- export declare const DEFAULT_BASE_PATH = "/docs";
27
+ /**
28
+ * Default `basePath` when no override is supplied.
29
+ *
30
+ * Changed in v0.3 from `"/docs"` to `""` (host root) so the default
31
+ * matches the plurality of doc-site deployments (GH Pages project
32
+ * sites, `docs.acme.com` subdomains, standalone wikis) and aligns
33
+ * with peer SSGs (Astro, Next, MkDocs, Docusaurus). The `cli`'s
34
+ * `site build` emits a one-shot migration warning when this default
35
+ * is hit so users from the `/docs` era can opt in to either value
36
+ * explicitly. See plans/default-basepath-root.md.
37
+ */
38
+ export declare const DEFAULT_BASE_PATH = "";
27
39
  /**
28
40
  * Normalize a user-supplied `basePath` to canonical form.
29
41
  *
@@ -33,7 +45,7 @@ export declare const DEFAULT_BASE_PATH = "/docs";
33
45
  * non-empty prefix.
34
46
  *
35
47
  * Examples:
36
- * - `undefined` → `"/docs"` (default)
48
+ * - `undefined` → `""` (default in v0.3+; was `"/docs"` previously)
37
49
  * - `""` → `""`
38
50
  * - `"/"` → `""`
39
51
  * - `"docs"` → `"/docs"`
@@ -68,6 +80,92 @@ export declare function basePathSegments(basePath: string): string[];
68
80
  * - `joinBaseUrl("", undefined, "")` → `"/"`
69
81
  */
70
82
  export declare function joinBaseUrl(basePath: string, section: string | undefined, slug: string): string;
83
+ /**
84
+ * Prepend the normalized `basePath` onto a raw config-supplied
85
+ * `indexPath` (e.g. `/tags` from `taxonomies.tags.indexPath`),
86
+ * producing the URL prefix that components use to compose hrefs.
87
+ *
88
+ * Different from `joinBaseUrl` because it preserves absolute paths
89
+ * with internal `/` segments and does NOT add a trailing slash —
90
+ * downstream consumers do `${out}/<term>/` themselves.
91
+ *
92
+ * - `withBasePath("/docs", "/tags")` → `"/docs/tags"`
93
+ * - `withBasePath("/docs", "tags")` → `"/docs/tags"`
94
+ * - `withBasePath("", "/tags")` → `"/tags"`
95
+ * - `withBasePath("/docs", "/by-type")` → `"/docs/by-type"`
96
+ *
97
+ * Used for the URL-bearing `indexPath` baked into the taxonomy data
98
+ * file and the `tagsIndexPath` / `taxonomyIndexPaths` Astro props,
99
+ * so components like `<TagList>`, `<TaxonomyIndex>`, `<TaxonomyTerm>`,
100
+ * and `<TypeBadge>` produce hrefs that resolve under the configured
101
+ * site base. Without this prefix, taxonomy navigation 404s on any
102
+ * site with `site.basePath` set.
103
+ */
104
+ export declare function withBasePath(basePath: string, indexPath: string): string;
105
+ /**
106
+ * Parse `site.url` into its origin and path-component parts. The
107
+ * path component (if any) becomes the **urlBase** — the prefix the
108
+ * host serves dist/ at, distinct from `basePath` (which is the
109
+ * filesystem position of content within that served space).
110
+ *
111
+ * Used by emitters that need to (a) emit Astro's `base` config
112
+ * (= urlBase), (b) produce absolute URLs in sitemap / canonical /
113
+ * llms.txt (= origin + combined prefix + slug), or (c) build the
114
+ * combined prefix that internal hrefs need (`combinePrefix` below).
115
+ *
116
+ * Returns `origin` undefined when `siteUrl` is missing or unparseable
117
+ * — the caller then degrades to relative URLs (existing behavior).
118
+ *
119
+ * - `undefined` → `{ origin: undefined, urlBase: "" }`
120
+ * - `"https://example.com"` → `{ origin: "https://example.com", urlBase: "" }`
121
+ * - `"https://example.com/"` → `{ origin: "https://example.com", urlBase: "" }`
122
+ * - `"https://example.com/docs"` → `{ origin: "https://example.com", urlBase: "/docs" }`
123
+ * - `"https://example.com/docs/"` → `{ origin: "https://example.com", urlBase: "/docs" }`
124
+ * - `"https://user.github.io/dogsbay-docs"` → `{ origin: "https://user.github.io", urlBase: "/dogsbay-docs" }`
125
+ * - `"/relative-path"` → `{ origin: undefined, urlBase: "" }` (not a full URL)
126
+ *
127
+ * See plans/astro-base-from-site-url.md.
128
+ */
129
+ export declare function parseSiteUrl(siteUrl: string | undefined): {
130
+ origin: string | undefined;
131
+ urlBase: string;
132
+ };
133
+ /**
134
+ * Combine a urlBase (host subpath, from `site.url`) with a
135
+ * basePath (filesystem layout prefix, from `site.basePath`) into the
136
+ * single prefix that nav hrefs, sitemap URLs, llms.txt, and the
137
+ * link rewriter all need.
138
+ *
139
+ * Both inputs MUST already be normalized (output of `normalizeBasePath`
140
+ * or `parseSiteUrl`): empty string OR a single leading slash with no
141
+ * trailing slash. The output respects the same shape.
142
+ *
143
+ * - `combinePrefix("", "")` → `""`
144
+ * - `combinePrefix("", "/docs")` → `"/docs"`
145
+ * - `combinePrefix("/repo", "")` → `"/repo"`
146
+ * - `combinePrefix("/repo", "/docs")` → `"/repo/docs"`
147
+ * - `combinePrefix("/handbook", "/team-docs")` → `"/handbook/team-docs"`
148
+ *
149
+ * See plans/astro-base-from-site-url.md.
150
+ */
151
+ export declare function combinePrefix(urlBase: string, basePath: string): string;
152
+ /**
153
+ * One-shot resolver: given the user's `site.url` + `site.basePath`,
154
+ * return everything emitters need. Convenience wrapper around
155
+ * `parseSiteUrl` + `normalizeBasePath` + `combinePrefix` so callers
156
+ * only do the math once.
157
+ *
158
+ * Used at the boundary in cli/site-build and cli/site-init to compute
159
+ * the effective prefixes before threading them into the emit tier.
160
+ *
161
+ * See plans/astro-base-from-site-url.md.
162
+ */
163
+ export declare function resolvePrefixes(siteUrl: string | undefined, basePath: string | undefined): {
164
+ origin: string | undefined;
165
+ urlBase: string;
166
+ basePath: string;
167
+ combined: string;
168
+ };
71
169
  /**
72
170
  * Build the `currentPath` value embedded in generated `.astro` pages
73
171
  * for `getPagination` lookups. No trailing slash so it matches the
@@ -78,6 +176,16 @@ export declare function joinBaseUrl(basePath: string, section: string | undefine
78
176
  * - default basePath, empty slug → `"/docs"`
79
177
  * - empty basePath, slug "auth" → `"/auth"`
80
178
  * - empty basePath, empty slug → `"/"`
179
+ * - empty basePath, slug "index" → `"/"` (root home)
180
+ *
181
+ * A bare `index` slug means the directory root: `content/index.md` is
182
+ * deliberately loaded with slug `"index"` (so the root-home and `.md`-mirror
183
+ * special cases fire — see plans/dir-index-slug-nav-drop.md), but the page is
184
+ * served at the directory URL and its nav href drops `index` (via
185
+ * `fileToHref`'s `/index` strip). `currentPath` must match that nav href for
186
+ * `getPagination` to find the home page, so we drop a whole-slug `index` here
187
+ * too. Without this the home page's `currentPath` (`/base/index`) never matches
188
+ * its nav entry (`/base`), so prev/next silently falls back to the first item.
81
189
  */
82
190
  export declare function buildCurrentPath(basePath: string, section: string | undefined, slug: string): string;
83
191
  //# sourceMappingURL=base-path.d.ts.map
@@ -1 +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"}
1
+ {"version":3,"file":"base-path.d.ts","sourceRoot":"","sources":["../src/base-path.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iBAAiB,KAAK,CAAC;AAEpC;;;;;;;;;;;;;;;;;;;;;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;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAGxE;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG;IACzD,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;CACjB,CAiBA;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAMvE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,QAAQ,EAAE,MAAM,GAAG,SAAS,GAC3B;IACD,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB,CASA;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,IAAI,EAAE,MAAM,GACX,MAAM,CAMR"}
package/dist/base-path.js CHANGED
@@ -1,10 +1,12 @@
1
1
  /**
2
2
  * Single source of truth for the `basePath` URL prefix.
3
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.
4
+ * `basePath` is the path-under-host where docs are served. The default
5
+ * is `""` (host root, matching every other SSG); set
6
+ * `site.basePath: "/docs"` in `dogsbay.config.yml` for the legacy
7
+ * "docs nested under marketing site" shape, or `"/handbook"` (etc.)
8
+ * for any other prefix. See plans/default-basepath-root.md for the
9
+ * rationale behind the default flip in v0.3.
8
10
  *
9
11
  * Every emitter that builds URLs, file paths, or rewrites links
10
12
  * reads from `AstroProjectOptions.basePath` and runs it through
@@ -22,8 +24,18 @@
22
24
  *
23
25
  * See plans/configurable-base-path.md.
24
26
  */
25
- /** Default `basePath` when no override is supplied. */
26
- export const DEFAULT_BASE_PATH = "/docs";
27
+ /**
28
+ * Default `basePath` when no override is supplied.
29
+ *
30
+ * Changed in v0.3 from `"/docs"` to `""` (host root) so the default
31
+ * matches the plurality of doc-site deployments (GH Pages project
32
+ * sites, `docs.acme.com` subdomains, standalone wikis) and aligns
33
+ * with peer SSGs (Astro, Next, MkDocs, Docusaurus). The `cli`'s
34
+ * `site build` emits a one-shot migration warning when this default
35
+ * is hit so users from the `/docs` era can opt in to either value
36
+ * explicitly. See plans/default-basepath-root.md.
37
+ */
38
+ export const DEFAULT_BASE_PATH = "";
27
39
  /**
28
40
  * Normalize a user-supplied `basePath` to canonical form.
29
41
  *
@@ -33,7 +45,7 @@ export const DEFAULT_BASE_PATH = "/docs";
33
45
  * non-empty prefix.
34
46
  *
35
47
  * Examples:
36
- * - `undefined` → `"/docs"` (default)
48
+ * - `undefined` → `""` (default in v0.3+; was `"/docs"` previously)
37
49
  * - `""` → `""`
38
50
  * - `"/"` → `""`
39
51
  * - `"docs"` → `"/docs"`
@@ -86,6 +98,123 @@ export function joinBaseUrl(basePath, section, slug) {
86
98
  parts.push(slug);
87
99
  return parts.length === 0 ? "/" : `/${parts.join("/")}/`;
88
100
  }
101
+ /**
102
+ * Prepend the normalized `basePath` onto a raw config-supplied
103
+ * `indexPath` (e.g. `/tags` from `taxonomies.tags.indexPath`),
104
+ * producing the URL prefix that components use to compose hrefs.
105
+ *
106
+ * Different from `joinBaseUrl` because it preserves absolute paths
107
+ * with internal `/` segments and does NOT add a trailing slash —
108
+ * downstream consumers do `${out}/<term>/` themselves.
109
+ *
110
+ * - `withBasePath("/docs", "/tags")` → `"/docs/tags"`
111
+ * - `withBasePath("/docs", "tags")` → `"/docs/tags"`
112
+ * - `withBasePath("", "/tags")` → `"/tags"`
113
+ * - `withBasePath("/docs", "/by-type")` → `"/docs/by-type"`
114
+ *
115
+ * Used for the URL-bearing `indexPath` baked into the taxonomy data
116
+ * file and the `tagsIndexPath` / `taxonomyIndexPaths` Astro props,
117
+ * so components like `<TagList>`, `<TaxonomyIndex>`, `<TaxonomyTerm>`,
118
+ * and `<TypeBadge>` produce hrefs that resolve under the configured
119
+ * site base. Without this prefix, taxonomy navigation 404s on any
120
+ * site with `site.basePath` set.
121
+ */
122
+ export function withBasePath(basePath, indexPath) {
123
+ const cleanIndex = indexPath.startsWith("/") ? indexPath : `/${indexPath}`;
124
+ return basePath ? `${basePath}${cleanIndex}` : cleanIndex;
125
+ }
126
+ /**
127
+ * Parse `site.url` into its origin and path-component parts. The
128
+ * path component (if any) becomes the **urlBase** — the prefix the
129
+ * host serves dist/ at, distinct from `basePath` (which is the
130
+ * filesystem position of content within that served space).
131
+ *
132
+ * Used by emitters that need to (a) emit Astro's `base` config
133
+ * (= urlBase), (b) produce absolute URLs in sitemap / canonical /
134
+ * llms.txt (= origin + combined prefix + slug), or (c) build the
135
+ * combined prefix that internal hrefs need (`combinePrefix` below).
136
+ *
137
+ * Returns `origin` undefined when `siteUrl` is missing or unparseable
138
+ * — the caller then degrades to relative URLs (existing behavior).
139
+ *
140
+ * - `undefined` → `{ origin: undefined, urlBase: "" }`
141
+ * - `"https://example.com"` → `{ origin: "https://example.com", urlBase: "" }`
142
+ * - `"https://example.com/"` → `{ origin: "https://example.com", urlBase: "" }`
143
+ * - `"https://example.com/docs"` → `{ origin: "https://example.com", urlBase: "/docs" }`
144
+ * - `"https://example.com/docs/"` → `{ origin: "https://example.com", urlBase: "/docs" }`
145
+ * - `"https://user.github.io/dogsbay-docs"` → `{ origin: "https://user.github.io", urlBase: "/dogsbay-docs" }`
146
+ * - `"/relative-path"` → `{ origin: undefined, urlBase: "" }` (not a full URL)
147
+ *
148
+ * See plans/astro-base-from-site-url.md.
149
+ */
150
+ export function parseSiteUrl(siteUrl) {
151
+ if (!siteUrl)
152
+ return { origin: undefined, urlBase: "" };
153
+ // Only accept absolute http(s) URLs as full site URLs. Anything else
154
+ // (relative paths, mailto:, tel:, …) yields no origin — emitters
155
+ // fall back to whatever they do today when site.url is missing.
156
+ if (!/^https?:\/\//i.test(siteUrl)) {
157
+ return { origin: undefined, urlBase: "" };
158
+ }
159
+ let parsed;
160
+ try {
161
+ parsed = new URL(siteUrl);
162
+ }
163
+ catch {
164
+ return { origin: undefined, urlBase: "" };
165
+ }
166
+ const origin = `${parsed.protocol}//${parsed.host}`;
167
+ const urlBase = normalizeBasePath(parsed.pathname);
168
+ return { origin, urlBase };
169
+ }
170
+ /**
171
+ * Combine a urlBase (host subpath, from `site.url`) with a
172
+ * basePath (filesystem layout prefix, from `site.basePath`) into the
173
+ * single prefix that nav hrefs, sitemap URLs, llms.txt, and the
174
+ * link rewriter all need.
175
+ *
176
+ * Both inputs MUST already be normalized (output of `normalizeBasePath`
177
+ * or `parseSiteUrl`): empty string OR a single leading slash with no
178
+ * trailing slash. The output respects the same shape.
179
+ *
180
+ * - `combinePrefix("", "")` → `""`
181
+ * - `combinePrefix("", "/docs")` → `"/docs"`
182
+ * - `combinePrefix("/repo", "")` → `"/repo"`
183
+ * - `combinePrefix("/repo", "/docs")` → `"/repo/docs"`
184
+ * - `combinePrefix("/handbook", "/team-docs")` → `"/handbook/team-docs"`
185
+ *
186
+ * See plans/astro-base-from-site-url.md.
187
+ */
188
+ export function combinePrefix(urlBase, basePath) {
189
+ // Both already normalized — concatenation is safe; no double slashes
190
+ // appear because each is empty OR starts with `/` and has no trailing.
191
+ if (!urlBase)
192
+ return basePath;
193
+ if (!basePath)
194
+ return urlBase;
195
+ return `${urlBase}${basePath}`;
196
+ }
197
+ /**
198
+ * One-shot resolver: given the user's `site.url` + `site.basePath`,
199
+ * return everything emitters need. Convenience wrapper around
200
+ * `parseSiteUrl` + `normalizeBasePath` + `combinePrefix` so callers
201
+ * only do the math once.
202
+ *
203
+ * Used at the boundary in cli/site-build and cli/site-init to compute
204
+ * the effective prefixes before threading them into the emit tier.
205
+ *
206
+ * See plans/astro-base-from-site-url.md.
207
+ */
208
+ export function resolvePrefixes(siteUrl, basePath) {
209
+ const { origin, urlBase } = parseSiteUrl(siteUrl);
210
+ const normalizedBasePath = normalizeBasePath(basePath);
211
+ return {
212
+ origin,
213
+ urlBase,
214
+ basePath: normalizedBasePath,
215
+ combined: combinePrefix(urlBase, normalizedBasePath),
216
+ };
217
+ }
89
218
  /**
90
219
  * Build the `currentPath` value embedded in generated `.astro` pages
91
220
  * for `getPagination` lookups. No trailing slash so it matches the
@@ -96,6 +225,16 @@ export function joinBaseUrl(basePath, section, slug) {
96
225
  * - default basePath, empty slug → `"/docs"`
97
226
  * - empty basePath, slug "auth" → `"/auth"`
98
227
  * - empty basePath, empty slug → `"/"`
228
+ * - empty basePath, slug "index" → `"/"` (root home)
229
+ *
230
+ * A bare `index` slug means the directory root: `content/index.md` is
231
+ * deliberately loaded with slug `"index"` (so the root-home and `.md`-mirror
232
+ * special cases fire — see plans/dir-index-slug-nav-drop.md), but the page is
233
+ * served at the directory URL and its nav href drops `index` (via
234
+ * `fileToHref`'s `/index` strip). `currentPath` must match that nav href for
235
+ * `getPagination` to find the home page, so we drop a whole-slug `index` here
236
+ * too. Without this the home page's `currentPath` (`/base/index`) never matches
237
+ * its nav entry (`/base`), so prev/next silently falls back to the first item.
99
238
  */
100
239
  export function buildCurrentPath(basePath, section, slug) {
101
240
  const parts = [];
@@ -103,7 +242,7 @@ export function buildCurrentPath(basePath, section, slug) {
103
242
  parts.push(seg);
104
243
  if (section)
105
244
  parts.push(section);
106
- if (slug)
245
+ if (slug && slug !== "index")
107
246
  parts.push(slug);
108
247
  return parts.length === 0 ? "/" : `/${parts.join("/")}`;
109
248
  }
@@ -1 +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"}
1
+ {"version":3,"file":"base-path.js","sourceRoot":"","sources":["../src/base-path.ts"],"names":[],"mappings":"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"}
package/dist/blog.d.ts ADDED
@@ -0,0 +1,134 @@
1
+ import type { ExportPage } from "@dogsbay/types";
2
+ /** Resolved `blog:` config (defaults filled). */
3
+ export interface BlogEmitConfig {
4
+ /**
5
+ * Where the reverse-chronological index lives, relative to the site.
6
+ * `"/"` (the default) means the site root IS the blog index — the
7
+ * shape a blog-only site wants.
8
+ */
9
+ indexPath: string;
10
+ /** Posts per index page. */
11
+ postsPerPage: number;
12
+ /** Emit an RSS feed route. Phase 4; accepted and ignored for now. */
13
+ rss: boolean;
14
+ /** Which `PageMeta` date orders the list. */
15
+ dateField: "created" | "updated";
16
+ }
17
+ /** Defaults for a `blog:` block that omits fields. */
18
+ export declare const BLOG_DEFAULTS: BlogEmitConfig;
19
+ /** One post in the emitted data file. */
20
+ export interface BlogPostRef {
21
+ slug: string;
22
+ title: string;
23
+ url: string;
24
+ description?: string;
25
+ /** ISO date from `meta[dateField]`. Absent when the post carries none. */
26
+ date?: string;
27
+ /** Only when it differs from `date` — the layout shows it as "updated". */
28
+ updated?: string;
29
+ author?: string[];
30
+ tags?: string[];
31
+ heroImage?: string;
32
+ /** Whole minutes, minimum 1. */
33
+ readingMinutes: number;
34
+ }
35
+ /** `src/data/blog.json`. */
36
+ export interface BlogData {
37
+ /** URL-form index path, prefixed with the COMBINED serving prefix. */
38
+ indexPath: string;
39
+ /**
40
+ * Filesystem-layout prefix (`site.basePath`), used to place route
41
+ * files under `src/pages/`. Deliberately NOT the same field as the URL
42
+ * prefix: Astro's `base` adds `urlBase` at request time, so baking it
43
+ * into file paths too would double it. Same split `taxonomy.ts` takes
44
+ * as `basePath` + `urlPrefix`.
45
+ */
46
+ basePath: string;
47
+ /**
48
+ * The COMBINED serving prefix (urlBase + basePath). What DocsLayout's
49
+ * `basePath` prop wants — it composes the llms.txt link, switcher
50
+ * hrefs and the alternate link from it, all of which are URLs. Kept
51
+ * separate from `basePath` above, which is a filesystem path.
52
+ */
53
+ urlPrefix: string;
54
+ /** `content.section`, when the build has one. Part of route placement. */
55
+ section?: string;
56
+ postsPerPage: number;
57
+ /** Newest first. */
58
+ posts: BlogPostRef[];
59
+ postCount: number;
60
+ }
61
+ /** Prev/next for one post, in date order. */
62
+ export interface BlogAdjacency {
63
+ /** The OLDER neighbour — back along the timeline, rendered on the left. */
64
+ prev?: {
65
+ title: string;
66
+ href: string;
67
+ };
68
+ /** The NEWER neighbour — forward, rendered on the right. */
69
+ next?: {
70
+ title: string;
71
+ href: string;
72
+ };
73
+ }
74
+ /**
75
+ * Count words in a page's body.
76
+ *
77
+ * Deliberately crude: whitespace-split on the extracted plain text.
78
+ * Reading time is a reading CUE, not a measurement, and a more precise
79
+ * count would not change the rendered minutes.
80
+ */
81
+ export declare function countWords(page: ExportPage): number;
82
+ /** Whole minutes at {@link WORDS_PER_MINUTE}, never less than 1. */
83
+ export declare function readingMinutes(page: ExportPage): number;
84
+ /**
85
+ * Build the post list from the page set.
86
+ *
87
+ * EVERY page is a post except the one that would occupy the index
88
+ * route itself. A site that declares `blog:` IS a blog; there is no
89
+ * second "is this a post?" axis to configure, and inventing one would
90
+ * mean a post silently vanishing because a field was missing.
91
+ *
92
+ * Undated posts sort last, in title order, rather than being dropped —
93
+ * a post with no date is an authoring mistake worth SEEING, not
94
+ * hiding.
95
+ */
96
+ export declare function buildBlogData(pages: ExportPage[], opts: {
97
+ basePath: string;
98
+ urlPrefix?: string;
99
+ /** `content.section`, threaded exactly as taxonomy.ts threads it. */
100
+ section?: string;
101
+ /** `excludeFromRoutes` predicate — see makeSlugExcluder. */
102
+ excludeSlug?: (slug: string) => boolean;
103
+ config: BlogEmitConfig;
104
+ }): BlogData;
105
+ /**
106
+ * Prev/next per post slug, in TIME order — `prev` older, `next` newer.
107
+ *
108
+ * The footer renders prev on the left and next on the right, so this is
109
+ * the direction a timeline runs: older behind you, newer ahead. It also
110
+ * matches how a series is read. `data.posts` is newest-first for the
111
+ * index listing, so the neighbours are deliberately taken the other way
112
+ * round from the array order.
113
+ *
114
+ * The first version had `prev` as the NEWER neighbour, reasoning that a
115
+ * blog archive is browsed backwards. That made the right-hand link walk
116
+ * a reader BACKWARDS through a series — part 1's "next" was nothing, and
117
+ * its left-hand link was part 2.
118
+ */
119
+ export declare function blogAdjacency(data: BlogData): Map<string, BlogAdjacency>;
120
+ /** Number of index pages at the configured page size. */
121
+ export declare function indexPageCount(data: BlogData): number;
122
+ /**
123
+ * Emit `src/data/blog.json` plus the index route(s).
124
+ *
125
+ * Page 1 lives at the index path; subsequent pages at
126
+ * `<indexPath>/page/<n>`. Data JSON is overwritten unconditionally —
127
+ * it is pure derived data — while route files respect the marker.
128
+ */
129
+ export declare function emitBlogFiles(outputDir: string, data: BlogData, config: BlogEmitConfig): {
130
+ routes: string[];
131
+ skipped: string[];
132
+ pruned: string[];
133
+ };
134
+ //# sourceMappingURL=blog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blog.d.ts","sourceRoot":"","sources":["../src/blog.ts"],"names":[],"mappings":"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"}