@dogsbay/format-hugo 0.2.0-beta.101

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/dist/nav.js ADDED
@@ -0,0 +1,381 @@
1
+ /**
2
+ * Hugo's implicit navigation, and page identity.
3
+ *
4
+ * Every importer so far reads nav from a FILE — `SUMMARY.md`, `mkdocs.yml`,
5
+ * `sidebars.js`, `docs.json`. Hugo has none. The tree is the directory
6
+ * structure, and the rules are:
7
+ *
8
+ * content/en/docs/concepts/_index.md → a SECTION at /docs/concepts/
9
+ * content/en/docs/concepts/pods.md → a page at /docs/concepts/pods/
10
+ * content/en/docs/setup/index.md → a LEAF BUNDLE (its directory is
11
+ * the page; images sit beside it)
12
+ * weight: 40 → sort position, ascending
13
+ * linkTitle: / title: → nav label
14
+ * slug: / url: → override the URL
15
+ *
16
+ * `_index.md` and `index.md` differ by one character and mean opposite things:
17
+ * the first makes a directory a section with children, the second makes the
18
+ * directory a single page. Getting that wrong either flattens the tree or
19
+ * loses every co-located image.
20
+ */
21
+ import { readdirSync, readFileSync, statSync } from "node:fs";
22
+ import { join, relative } from "node:path";
23
+ import { parse as parseYaml } from "yaml";
24
+ import { parse as parseToml } from "smol-toml";
25
+ /** Split Hugo frontmatter: `---` YAML, `+++` TOML, or `{ }` JSON. */
26
+ export function splitFrontmatter(source) {
27
+ const yamlMatch = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/.exec(source);
28
+ if (yamlMatch) {
29
+ try {
30
+ return {
31
+ frontmatter: (parseYaml(yamlMatch[1]) ?? {}),
32
+ body: source.slice(yamlMatch[0].length),
33
+ };
34
+ }
35
+ catch {
36
+ return { frontmatter: {}, body: source.slice(yamlMatch[0].length) };
37
+ }
38
+ }
39
+ const tomlMatch = /^\+\+\+\r?\n([\s\S]*?)\r?\n\+\+\+\r?\n?/.exec(source);
40
+ if (tomlMatch) {
41
+ try {
42
+ return {
43
+ frontmatter: parseToml(tomlMatch[1]),
44
+ body: source.slice(tomlMatch[0].length),
45
+ };
46
+ }
47
+ catch {
48
+ return { frontmatter: {}, body: source.slice(tomlMatch[0].length) };
49
+ }
50
+ }
51
+ return { frontmatter: {}, body: source };
52
+ }
53
+ function titleFromSlug(slug) {
54
+ const last = slug.split("/").filter(Boolean).pop() ?? "";
55
+ return last
56
+ .split(/[-_]/)
57
+ .filter(Boolean)
58
+ .map((w) => w.charAt(0).toUpperCase() + w.slice(1))
59
+ .join(" ");
60
+ }
61
+ /**
62
+ * Directories whose markdown is include-only by convention. Hugo has no formal
63
+ * marker, but `{{< include "x.md" >}}` resolves here, so these files are
64
+ * fragments rather than pages.
65
+ */
66
+ const FRAGMENT_DIRS = ["includes", "included", "_includes", "shortcodes"];
67
+ /**
68
+ * A page's `menu.main` entry, if it declares one.
69
+ *
70
+ * Hugo accepts several shapes: `menu: main`, `menu: [main]`, and
71
+ * `menu: {main: {weight, title, parent}}`. Only the last carries ordering, but
72
+ * all three mean "this page is in the main menu".
73
+ */
74
+ function readMenuMain(fm) {
75
+ const menu = fm.menu;
76
+ if (!menu)
77
+ return {};
78
+ if (typeof menu === "string" || Array.isArray(menu))
79
+ return {};
80
+ const main = menu.main;
81
+ if (!main || typeof main !== "object")
82
+ return {};
83
+ const entry = main;
84
+ return {
85
+ weight: typeof entry.weight === "number" ? entry.weight : undefined,
86
+ title: typeof entry.title === "string" ? entry.title : undefined,
87
+ };
88
+ }
89
+ /** Whether Hugo would exclude this page from the built site / its lists. */
90
+ function isHidden(fm) {
91
+ if (fm.draft === true)
92
+ return true;
93
+ if (fm.headless === true)
94
+ return true;
95
+ const build = fm._build;
96
+ if (build && (build.render === "never" || build.list === "never"))
97
+ return true;
98
+ return false;
99
+ }
100
+ /**
101
+ * Walk a Hugo content directory into a flat page list.
102
+ *
103
+ * Ordinary markdown only — `.html` content pages exist in Hugo but carry no
104
+ * markdown to import, and pulling them in would emit pages of raw template.
105
+ */
106
+ /**
107
+ * Apply a Hugo `[permalinks]` pattern to a page.
108
+ *
109
+ * Tokens Hugo defines that matter for docs corpora: `:section`, `:sections`,
110
+ * `:year`, `:month`, `:day`, `:slug`, `:title`, `:filename`, `:contentbasename`.
111
+ * An unknown token is left in place rather than silently emitting an empty
112
+ * segment — a wrong URL you can see beats one you cannot.
113
+ */
114
+ export function applyPermalink(pattern, ctx) {
115
+ const pad = (n) => String(n).padStart(2, "0");
116
+ const d = ctx.date;
117
+ const values = {
118
+ section: ctx.section,
119
+ sections: ctx.sections.join("/"),
120
+ slug: ctx.slug,
121
+ title: ctx.title,
122
+ filename: ctx.filename,
123
+ contentbasename: ctx.filename,
124
+ year: d ? String(d.getUTCFullYear()) : "",
125
+ month: d ? pad(d.getUTCMonth() + 1) : "",
126
+ day: d ? pad(d.getUTCDate()) : "",
127
+ monthname: d
128
+ ? d.toLocaleString("en-US", { month: "long", timeZone: "UTC" })
129
+ : "",
130
+ };
131
+ const out = pattern.replace(/:([a-zA-Z]+)/g, (whole, token) => token in values ? values[token] : whole);
132
+ return out
133
+ .split("/")
134
+ .filter((seg) => seg !== "")
135
+ .join("/");
136
+ }
137
+ export function collectHugoPages(contentRoot, permalinks = {}, sectionPermalinks = {}) {
138
+ const pages = [];
139
+ const walk = (dir) => {
140
+ let entries;
141
+ try {
142
+ entries = readdirSync(dir).sort();
143
+ }
144
+ catch {
145
+ return;
146
+ }
147
+ for (const name of entries) {
148
+ const path = join(dir, name);
149
+ let stats;
150
+ try {
151
+ stats = statSync(path);
152
+ }
153
+ catch {
154
+ continue;
155
+ }
156
+ if (stats.isDirectory()) {
157
+ walk(path);
158
+ continue;
159
+ }
160
+ const isHtml = name.endsWith(".html") || name.endsWith(".htm");
161
+ if (!name.endsWith(".md") && !name.endsWith(".markdown") && !isHtml)
162
+ continue;
163
+ const rel = relative(contentRoot, path).split("\\").join("/");
164
+ const source = readFileSync(path, "utf-8");
165
+ const { frontmatter } = splitFrontmatter(source);
166
+ const isSection = /^_index\.(md|markdown|html?)$/.test(name);
167
+ const isLeafBundle = /^index\.(md|markdown|html?)$/.test(name);
168
+ // The slug is the directory for a bundle/section, the filename otherwise.
169
+ let slug = rel.replace(/\.(md|markdown|html?)$/, "");
170
+ if (isSection || isLeafBundle)
171
+ slug = slug.replace(/\/?(_?index)$/, "");
172
+ const sections = slug.split("/").slice(0, -1).filter(Boolean);
173
+ const filename = name.replace(/\.(md|markdown|html?)$/, "");
174
+ const baseName = isSection || isLeafBundle
175
+ ? (slug.split("/").pop() ?? filename)
176
+ : filename;
177
+ // Hugo lets frontmatter override it. `url:` is absolute; `slug:` renames
178
+ // only the last segment.
179
+ const url = typeof frontmatter.url === "string" ? frontmatter.url : undefined;
180
+ const slugOverride = typeof frontmatter.slug === "string" ? frontmatter.slug : undefined;
181
+ const topSection = slug.split("/")[0] ?? "";
182
+ // A SECTION page takes a pattern only from `[permalinks.section]`.
183
+ // Hugo keeps the two apart and so must we: kubernetes declares only
184
+ // `[permalinks.page]`, and applying its blog pattern to
185
+ // `blog/_index.md` rewrote the section's own slug to `blog/blog`,
186
+ // which dropped "Blog" out of its menu position in the nav.
187
+ // A page's own `url:` may itself be a PATTERN — 192 kubernetes blog
188
+ // posts write `url: /:section/:year/:month/:slug/`. Treating it as a
189
+ // literal path emitted files at `docs/:section/:year/:month/:slug/`,
190
+ // which is not a URL and which Docusaurus then tried to compile.
191
+ const patternSource = isSection ? sectionPermalinks : permalinks;
192
+ const pattern = url && /:[a-zA-Z]/.test(url) ? url : patternSource[topSection];
193
+ if (url && !/:[a-zA-Z]/.test(url)) {
194
+ slug = url.replace(/^\/+|\/+$/g, "");
195
+ }
196
+ else if (pattern) {
197
+ // A permalink pattern REPLACES the path-derived slug. This is what
198
+ // removes `_posts/2018` from a kubernetes blog URL.
199
+ const rawDate = frontmatter.date;
200
+ const date = rawDate instanceof Date
201
+ ? rawDate
202
+ : typeof rawDate === "string" || typeof rawDate === "number"
203
+ ? new Date(rawDate)
204
+ : undefined;
205
+ slug = applyPermalink(pattern, {
206
+ section: topSection,
207
+ sections,
208
+ slug: slugOverride ?? baseName,
209
+ filename: baseName,
210
+ title: typeof frontmatter.title === "string" ? frontmatter.title : baseName,
211
+ date: date && !Number.isNaN(date.getTime()) ? date : undefined,
212
+ });
213
+ }
214
+ else if (slugOverride) {
215
+ const parts = slug.split("/");
216
+ parts[parts.length - 1] = slugOverride;
217
+ slug = parts.join("/");
218
+ }
219
+ slug = slug.replace(/^\/+|\/+$/g, "");
220
+ const title = (typeof frontmatter.title === "string" && frontmatter.title) ||
221
+ titleFromSlug(slug || "home");
222
+ // Hugo's MENU system is a second, independent source of both the nav
223
+ // label and the ordering: kubernetes gives `docs` no top-level `weight`
224
+ // at all and writes `menu: {main: {weight: 10}}` instead. Reading only
225
+ // `weight` put every top-level section in the unweighted bucket, so they
226
+ // sorted alphabetically and "Blog" landed above "Documentation".
227
+ const menuMain = readMenuMain(frontmatter);
228
+ const linkTitle = (typeof frontmatter.linkTitle === "string" && frontmatter.linkTitle) ||
229
+ (typeof frontmatter.linktitle === "string" && frontmatter.linktitle) ||
230
+ menuMain.title ||
231
+ title;
232
+ pages.push({
233
+ file: path,
234
+ rel,
235
+ slug,
236
+ title,
237
+ linkTitle,
238
+ weight: typeof frontmatter.weight === "number"
239
+ ? frontmatter.weight
240
+ : menuMain.weight,
241
+ frontmatter,
242
+ isSection,
243
+ isLeafBundle,
244
+ unrenderable: isHtml,
245
+ hidden: isHidden(frontmatter),
246
+ fragment: FRAGMENT_DIRS.some((d) => rel === `${d}` || rel.startsWith(`${d}/`)),
247
+ });
248
+ }
249
+ };
250
+ walk(contentRoot);
251
+ return pages;
252
+ }
253
+ /**
254
+ * Build the nav tree from the page set.
255
+ *
256
+ * Ordering is Hugo's: `weight` ascending, then title. Pages with no weight
257
+ * sort AFTER weighted ones — Hugo treats a missing weight as 0 and then falls
258
+ * back to date/title, but for docs the practical rule authors rely on is
259
+ * "weighted items lead, the rest follow alphabetically".
260
+ */
261
+ export function buildHugoNav(pages, hrefPrefix = "") {
262
+ const visible = pages.filter((p) => !p.hidden && !p.fragment);
263
+ const bySlug = new Map();
264
+ for (const p of visible)
265
+ bySlug.set(p.slug, p);
266
+ const href = (slug) => `${hrefPrefix}/${slug}`.replace(/\/{2,}/g, "/");
267
+ // EVERY directory is a section in Hugo — `_index.md` only lets you give one
268
+ // front matter. Recursing solely into pages that have an `_index.md` lost
269
+ // 1,479 of 2,445 pages, because a directory like `blog/_posts/2022/` has no
270
+ // index file and its children were therefore never reached. So the tree is
271
+ // built from the SLUG PATHS, and a directory with no page of its own becomes
272
+ // a label-only node.
273
+ const childSlugs = new Map();
274
+ const register = (parent, child) => {
275
+ const set = childSlugs.get(parent) ?? new Set();
276
+ set.add(child);
277
+ childSlugs.set(parent, set);
278
+ };
279
+ for (const page of visible) {
280
+ if (page.slug === "")
281
+ continue;
282
+ const parts = page.slug.split("/");
283
+ for (let i = 0; i < parts.length; i++) {
284
+ const child = parts.slice(0, i + 1).join("/");
285
+ const parent = i === 0 ? "" : parts.slice(0, i).join("/");
286
+ register(parent, child);
287
+ }
288
+ }
289
+ const sortKey = (slug) => {
290
+ const page = bySlug.get(slug);
291
+ const label = page?.linkTitle ?? titleFromSlug(slug);
292
+ // Weighted items lead, unweighted follow alphabetically — the rule docs
293
+ // authors actually rely on.
294
+ return [page?.weight === undefined ? 1 : 0, page?.weight ?? 0, label];
295
+ };
296
+ const build = (parent, depth) => {
297
+ if (depth > 12)
298
+ return [];
299
+ const slugs = [...(childSlugs.get(parent) ?? [])].sort((a, b) => {
300
+ const [ag, aw, al] = sortKey(a);
301
+ const [bg, bw, bl] = sortKey(b);
302
+ return ag - bg || aw - bw || al.localeCompare(bl);
303
+ });
304
+ return slugs.map((slug) => {
305
+ const page = bySlug.get(slug);
306
+ const kids = build(slug, depth + 1);
307
+ const item = { label: page?.linkTitle ?? titleFromSlug(slug) };
308
+ // A directory with no page of its own is a label only — giving it an
309
+ // href would produce a nav entry that 404s.
310
+ if (page)
311
+ item.href = href(slug);
312
+ if (kids.length > 0)
313
+ item.children = kids;
314
+ return item;
315
+ });
316
+ };
317
+ return build("", 0);
318
+ }
319
+ /**
320
+ * Resolve a `{{< ref >}}` / `{{< relref >}}` target against the page set.
321
+ *
322
+ * 2,570 calls in the kubernetes corpus — the most common shortcode by a wide
323
+ * margin, and every unresolved one is a broken link. Hugo accepts a lot of
324
+ * forms for the same page:
325
+ *
326
+ * "/docs/concepts/_index.md" root-relative with the file name
327
+ * "docs/concepts" root-relative, no extension
328
+ * "pods.md" relative to the calling page
329
+ * "#anchor" / "page.md#anchor" with a fragment
330
+ */
331
+ export function makeRefResolver(pages, hrefPrefix = "") {
332
+ const bySlug = new Map();
333
+ const byRel = new Map();
334
+ const byBasename = new Map();
335
+ for (const page of pages) {
336
+ bySlug.set(page.slug, page);
337
+ byRel.set(page.rel, page);
338
+ byRel.set(page.rel.replace(/\.(md|markdown)$/, ""), page);
339
+ const base = page.rel.split("/").pop().replace(/\.(md|markdown)$/, "");
340
+ const list = byBasename.get(base) ?? [];
341
+ list.push(page);
342
+ byBasename.set(base, list);
343
+ }
344
+ const href = (page, fragment) => `${hrefPrefix}/${page.slug}${fragment}`.replace(/\/{2,}/g, "/");
345
+ return (target, from) => {
346
+ if (!target)
347
+ return undefined;
348
+ // A bare fragment stays on the page.
349
+ if (target.startsWith("#"))
350
+ return target;
351
+ const hashAt = target.indexOf("#");
352
+ const fragment = hashAt === -1 ? "" : target.slice(hashAt);
353
+ let path = (hashAt === -1 ? target : target.slice(0, hashAt)).trim();
354
+ path = path.replace(/^\/+/, "").replace(/\/+$/, "");
355
+ const noExt = path.replace(/\.(md|markdown)$/, "").replace(/\/?_?index$/, "");
356
+ // Root-relative, by slug or by source path.
357
+ for (const key of [noExt, path]) {
358
+ const hit = bySlug.get(key) ?? byRel.get(key);
359
+ if (hit)
360
+ return href(hit, fragment);
361
+ }
362
+ // Relative to the calling page's directory.
363
+ if (from) {
364
+ const dir = from.split("/").slice(0, -1).join("/");
365
+ const joined = [dir, path].filter(Boolean).join("/");
366
+ const joinedNoExt = joined.replace(/\.(md|markdown)$/, "").replace(/\/?_?index$/, "");
367
+ const hit = byRel.get(joined) ?? byRel.get(joinedNoExt) ?? bySlug.get(joinedNoExt);
368
+ if (hit)
369
+ return href(hit, fragment);
370
+ }
371
+ // Last resort: a unique basename match. Hugo itself does this, and it is
372
+ // how `{{< ref "pods.md" >}}` works from anywhere in the tree. Ambiguous
373
+ // names are NOT guessed — the caller records the failure instead.
374
+ const base = noExt.split("/").pop() ?? "";
375
+ const candidates = byBasename.get(base);
376
+ if (candidates && candidates.length === 1)
377
+ return href(candidates[0], fragment);
378
+ return undefined;
379
+ };
380
+ }
381
+ //# sourceMappingURL=nav.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nav.js","sourceRoot":"","sources":["../src/nav.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Shortcode mapping registry.
3
+ *
4
+ * Hugo has no fixed shortcode vocabulary: a site defines its own in
5
+ * `layouts/shortcodes/`, and a theme ships more. Kubernetes uses 52 distinct
6
+ * names, of which only a handful are Hugo builtins. So the registry is OPEN,
7
+ * in three layers — builtins < theme (docsy) < site (kubernetes) < user —
8
+ * exactly like the MDX adapters, because a site-specific shortcode must never
9
+ * become a core concern.
10
+ *
11
+ * A shortcode with no mapping is NEVER dropped: it is preserved verbatim and
12
+ * recorded in the fidelity ledger, so an unmapped construct is a known loss
13
+ * rather than a silent one.
14
+ */
15
+ import type { ShortcodeArgs, ShortcodeNode } from "./shortcodes.js";
16
+ import type { HugoConfig } from "./config.js";
17
+ export interface ShortcodeContext {
18
+ /** Translate a Hugo source fragment (a shortcode body) to Dogsbay-MD. */
19
+ translate: (source: string) => string;
20
+ /** Site config — params, baseURL, languages. */
21
+ config: HugoConfig;
22
+ /** Record a fidelity note. */
23
+ report: (entry: Omit<HugoLedgerEntry, "file">) => void;
24
+ /** Resolve a `{{< ref >}}`-style page reference to an href, if possible. */
25
+ resolveRef?: (target: string, from?: string) => string | undefined;
26
+ /**
27
+ * Read a file a shortcode references. The SECOND argument is the calling
28
+ * page: `{{< include "included/x.md" >}}` resolves beside the page, while
29
+ * `{{< include "task-tutorial-prereqs.md" >}}` resolves in the site's
30
+ * conventional `includes/` directory — so the resolver needs both.
31
+ */
32
+ readContentFile?: (path: string, fromFile?: string) => string | undefined;
33
+ /** Source file currently being translated, relative to the content root. */
34
+ file?: string;
35
+ }
36
+ export interface HugoLedgerEntry {
37
+ /** Shortcode name. */
38
+ shortcode: string;
39
+ /**
40
+ * What happened:
41
+ * - "preserved" — kept verbatim (unmapped);
42
+ * - "stripped" — deliberately dropped by a mapping;
43
+ * - "degraded" — mapped, but something about it could not be carried.
44
+ */
45
+ action: "preserved" | "stripped" | "degraded";
46
+ /** Why, in one line. */
47
+ note?: string;
48
+ /** 1-based line in the source. */
49
+ line: number;
50
+ file?: string;
51
+ }
52
+ /**
53
+ * Turn a shortcode into Dogsbay-MD source.
54
+ *
55
+ * Return `null` to drop it (recorded as "stripped"), or `undefined` to fall
56
+ * through to preservation (recorded as "preserved"). Returning a string means
57
+ * the mapping owns the output.
58
+ */
59
+ export type ShortcodeMapping = (node: ShortcodeNode, ctx: ShortcodeContext) => string | null | undefined;
60
+ export type ShortcodeRegistry = Record<string, ShortcodeMapping>;
61
+ /** First positional argument, or a named one, whichever the call used. */
62
+ export declare function arg(args: ShortcodeArgs, ...names: string[]): string | undefined;
63
+ /** `{key="value"}` attribute block for a Dogsbay-MD directive, or "". */
64
+ export declare function attrBlock(attrs: Record<string, string | undefined>): string;
65
+ /**
66
+ * Emit a `:::` block directive whose fence is longer than any fence inside it.
67
+ *
68
+ * Hugo shortcodes nest arbitrarily (`tabs > tab > note`), and Dogsbay-MD
69
+ * closes at the first bare `:::`, so a fixed three-colon fence would let an
70
+ * inner directive terminate its own parent and spill the rest of the tab into
71
+ * the page.
72
+ */
73
+ export declare function directive(name: string, attrs: string, body: string): string;
74
+ /**
75
+ * Merge registry layers. Later layers win, which is what lets a site override
76
+ * a theme's shortcode of the same name.
77
+ */
78
+ export declare function composeRegistry(...layers: ShortcodeRegistry[]): ShortcodeRegistry;
79
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACpE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,WAAW,gBAAgB;IAC/B,yEAAyE;IACzE,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC;IACtC,gDAAgD;IAChD,MAAM,EAAE,UAAU,CAAC;IACnB,8BAA8B;IAC9B,MAAM,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,eAAe,EAAE,MAAM,CAAC,KAAK,IAAI,CAAC;IACvD,4EAA4E;IAC5E,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IACnE;;;;;OAKG;IACH,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IAC1E,4EAA4E;IAC5E,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAC9B,sBAAsB;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;OAKG;IACH,MAAM,EAAE,WAAW,GAAG,UAAU,GAAG,UAAU,CAAC;IAC9C,wBAAwB;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;GAMG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAC7B,IAAI,EAAE,aAAa,EACnB,GAAG,EAAE,gBAAgB,KAClB,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;AAE/B,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;AAEjE,0EAA0E;AAC1E,wBAAgB,GAAG,CAAC,IAAI,EAAE,aAAa,EAAE,GAAG,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAK/E;AAED,yEAAyE;AACzE,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG,MAAM,CAQ3E;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,GACX,MAAM,CAUR;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,GAAG,MAAM,EAAE,iBAAiB,EAAE,GAAG,iBAAiB,CAEjF"}
@@ -0,0 +1,41 @@
1
+ /** First positional argument, or a named one, whichever the call used. */
2
+ export function arg(args, ...names) {
3
+ for (const name of names) {
4
+ if (args.named[name] !== undefined)
5
+ return args.named[name];
6
+ }
7
+ return args.positional[0];
8
+ }
9
+ /** `{key="value"}` attribute block for a Dogsbay-MD directive, or "". */
10
+ export function attrBlock(attrs) {
11
+ const entries = Object.entries(attrs).filter((e) => e[1] !== undefined && e[1] !== "");
12
+ if (entries.length === 0)
13
+ return "";
14
+ return `{${entries
15
+ .map(([k, v]) => `${k}="${v.replace(/"/g, "&quot;")}"`)
16
+ .join(" ")}}`;
17
+ }
18
+ /**
19
+ * Emit a `:::` block directive whose fence is longer than any fence inside it.
20
+ *
21
+ * Hugo shortcodes nest arbitrarily (`tabs > tab > note`), and Dogsbay-MD
22
+ * closes at the first bare `:::`, so a fixed three-colon fence would let an
23
+ * inner directive terminate its own parent and spill the rest of the tab into
24
+ * the page.
25
+ */
26
+ export function directive(name, attrs, body) {
27
+ const inner = Math.max(0, ...[...body.matchAll(/^(:{3,})/gm)].map((m) => m[1].length));
28
+ const fence = ":".repeat(Math.max(3, inner + 1));
29
+ const trimmed = body.replace(/^\n+|\n+$/g, "");
30
+ return trimmed
31
+ ? `${fence}${name}${attrs}\n${trimmed}\n${fence}`
32
+ : `${fence}${name}${attrs}\n${fence}`;
33
+ }
34
+ /**
35
+ * Merge registry layers. Later layers win, which is what lets a site override
36
+ * a theme's shortcode of the same name.
37
+ */
38
+ export function composeRegistry(...layers) {
39
+ return Object.assign({}, ...layers);
40
+ }
41
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAoEA,0EAA0E;AAC1E,MAAM,UAAU,GAAG,CAAC,IAAmB,EAAE,GAAG,KAAe;IACzD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,SAAS;YAAE,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC9D,CAAC;IACD,OAAO,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;AAC5B,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,SAAS,CAAC,KAAyC;IACjE,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,MAAM,CAC1C,CAAC,CAAC,EAAyB,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,CAChE,CAAC;IACF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACpC,OAAO,IAAI,OAAO;SACf,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,GAAG,CAAC;SACtD,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;AAClB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,SAAS,CACvB,IAAY,EACZ,KAAa,EACb,IAAY;IAEZ,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CACpB,CAAC,EACD,GAAG,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAC5D,CAAC;IACF,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC;IACjD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IAC/C,OAAO,OAAO;QACZ,CAAC,CAAC,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,KAAK,OAAO,KAAK,KAAK,EAAE;QACjD,CAAC,CAAC,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,KAAK,KAAK,EAAE,CAAC;AAC1C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,GAAG,MAA2B;IAC5D,OAAO,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,GAAG,MAAM,CAAsB,CAAC;AAC3D,CAAC"}
@@ -0,0 +1,26 @@
1
+ export interface ContentResolverOptions {
2
+ /** Absolute path of the language content root, e.g. `<site>/content/en`. */
3
+ contentRoot: string;
4
+ /**
5
+ * Directories to try, relative to the content root, in order. The default
6
+ * covers Hugo's conventional `includes/` plus the `examples/` tree
7
+ * `code_sample` reads from.
8
+ */
9
+ searchDirs?: string[];
10
+ }
11
+ /**
12
+ * Build a reader that takes a shortcode's file argument and the page it was
13
+ * called from, and returns the file's text — or undefined, so the caller
14
+ * records an unresolved reference rather than emitting nothing silently.
15
+ */
16
+ export declare function makeContentResolver(opts: ContentResolverOptions): (path: string, fromFile?: string) => string | undefined;
17
+ /**
18
+ * Whether a shortcode's `include=` argument names a FILE.
19
+ *
20
+ * It does not always: `{{< feature-gate-table include="alpha,beta" >}}` uses
21
+ * the same attribute name as a filter. Treating that as a path produced a
22
+ * guaranteed-failing read and a misleading "could not read included file"
23
+ * ledger entry on every one of them.
24
+ */
25
+ export declare function looksLikeFile(value: string | undefined): boolean;
26
+ //# sourceMappingURL=resolve.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../src/resolve.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,sBAAsB;IACrC,4EAA4E;IAC5E,WAAW,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,sBAAsB,GAC3B,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CA6CzD;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAEhE"}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * File resolution for `{{< include >}}`, `{{< code_sample >}}` and
3
+ * `{{< tab include= >}}`.
4
+ *
5
+ * Hugo shortcodes reference files by a site convention, not by a path the
6
+ * caller can use directly. Measured on kubernetes/website:
7
+ *
8
+ * {{< include "task-tutorial-prereqs.md" >}} → content/en/includes/… (131×)
9
+ * {{< include "included/verify-kubectl.md" >}} → beside the page (9×)
10
+ * {{< code_sample file="pods/simple.yaml" >}} → content/en/examples/…
11
+ * {{< tab include="generated/x.md" />}} → beside the page
12
+ *
13
+ * Resolving only one of those left 171 of 171 includes and 106 tabs empty,
14
+ * each with a ledger entry — honest, but the content was right there.
15
+ */
16
+ import { existsSync, readFileSync, statSync } from "node:fs";
17
+ import { dirname, isAbsolute, resolve, sep } from "node:path";
18
+ /**
19
+ * Build a reader that takes a shortcode's file argument and the page it was
20
+ * called from, and returns the file's text — or undefined, so the caller
21
+ * records an unresolved reference rather than emitting nothing silently.
22
+ */
23
+ export function makeContentResolver(opts) {
24
+ const { contentRoot } = opts;
25
+ const searchDirs = opts.searchDirs ?? ["includes", "examples", "static", "."];
26
+ return (path, fromFile) => {
27
+ if (!path)
28
+ return undefined;
29
+ // Reject `..` outright. Hugo shortcode file arguments are never legitimately
30
+ // parent-relative, and allowing them let a path escape the search
31
+ // directories entirely: `../secret.txt` resolved against `includes/`
32
+ // reaches the content root, and the startsWith guard below does not catch
33
+ // that because the result is still inside the root.
34
+ if (path.split(/[\\/]/).some((seg) => seg === ".."))
35
+ return undefined;
36
+ const clean = path.replace(/^\.\//, "");
37
+ const candidates = [];
38
+ // Page-relative first: `included/verify-kubectl.md` sits beside the page.
39
+ if (fromFile) {
40
+ const pageDir = isAbsolute(fromFile)
41
+ ? dirname(fromFile)
42
+ : resolve(contentRoot, dirname(fromFile));
43
+ candidates.push(resolve(pageDir, clean));
44
+ }
45
+ // Then the site conventions.
46
+ for (const dir of searchDirs) {
47
+ candidates.push(resolve(contentRoot, dir, clean.replace(/^\//, "")));
48
+ }
49
+ // Finally, root-relative.
50
+ candidates.push(resolve(contentRoot, clean.replace(/^\//, "")));
51
+ for (const candidate of candidates) {
52
+ // Never escape the content root: a shortcode argument is site data, and
53
+ // `../../etc/passwd` must not be readable through it.
54
+ // `startsWith` alone would admit a sibling directory whose name shares
55
+ // the prefix (`/content/en-old` for a root of `/content/en`).
56
+ if (candidate !== contentRoot && !candidate.startsWith(contentRoot + sep))
57
+ continue;
58
+ try {
59
+ if (existsSync(candidate) && statSync(candidate).isFile()) {
60
+ return readFileSync(candidate, "utf-8");
61
+ }
62
+ }
63
+ catch {
64
+ // Unreadable — keep trying the remaining candidates.
65
+ }
66
+ }
67
+ return undefined;
68
+ };
69
+ }
70
+ /**
71
+ * Whether a shortcode's `include=` argument names a FILE.
72
+ *
73
+ * It does not always: `{{< feature-gate-table include="alpha,beta" >}}` uses
74
+ * the same attribute name as a filter. Treating that as a path produced a
75
+ * guaranteed-failing read and a misleading "could not read included file"
76
+ * ledger entry on every one of them.
77
+ */
78
+ export function looksLikeFile(value) {
79
+ return typeof value === "string" && /\.[A-Za-z0-9]{1,6}$/.test(value.trim());
80
+ }
81
+ //# sourceMappingURL=resolve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve.js","sourceRoot":"","sources":["../src/resolve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC7D,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAa9D;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CACjC,IAA4B;IAE5B,MAAM,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC;IAC7B,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,CAAC,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,CAAC,CAAC;IAE9E,OAAO,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE;QACxB,IAAI,CAAC,IAAI;YAAE,OAAO,SAAS,CAAC;QAC5B,6EAA6E;QAC7E,kEAAkE;QAClE,qEAAqE;QACrE,0EAA0E;QAC1E,oDAAoD;QACpD,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,KAAK,IAAI,CAAC;YAAE,OAAO,SAAS,CAAC;QACtE,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QACxC,MAAM,UAAU,GAAa,EAAE,CAAC;QAEhC,0EAA0E;QAC1E,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,UAAU,CAAC,QAAQ,CAAC;gBAClC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;gBACnB,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;YAC5C,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;QAC3C,CAAC;QACD,6BAA6B;QAC7B,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;YAC7B,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,GAAG,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;QACvE,CAAC;QACD,0BAA0B;QAC1B,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;QAEhE,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;YACnC,wEAAwE;YACxE,sDAAsD;YACtD,uEAAuE;YACvE,8DAA8D;YAC9D,IAAI,SAAS,KAAK,WAAW,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,WAAW,GAAG,GAAG,CAAC;gBAAE,SAAS;YACpF,IAAI,CAAC;gBACH,IAAI,UAAU,CAAC,SAAS,CAAC,IAAI,QAAQ,CAAC,SAAS,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;oBAC1D,OAAO,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;gBAC1C,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,qDAAqD;YACvD,CAAC;QACH,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAAC,KAAyB;IACrD,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,qBAAqB,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;AAC/E,CAAC"}