@dogsbay/format-gatsby 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.
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Gatsby site adapter — the extension point for what a specific Gatsby
3
+ * docs site invented on top of standard Gatsby MDX.
4
+ *
5
+ * The generic importer (cli.ts) handles the Gatsby-shape concerns: the
6
+ * `title != ""` page/partial split, `_snippets` transclusion, path→slug,
7
+ * and MDX parsing via `@dogsbay/format-mdx`. Anything site-specific — the
8
+ * custom component surface (PostHog's `<ProductScreenshot>`), and the nav
9
+ * (PostHog's hand-written `src/navs/index.js` module) — lives in a
10
+ * per-site adapter, injected by name (like the Docusaurus/Tigera split).
11
+ *
12
+ * convert ../posthog.com/contents/docs --from gatsby --adapter posthog
13
+ */
14
+ import type { MdxAdapter, NavItem } from "@dogsbay/format-mdx";
15
+ export interface GatsbyNavContext {
16
+ /** The docs source directory `convert` was pointed at. */
17
+ sourceDir: string;
18
+ /** Prefix for emitted hrefs (the target site's mount, e.g. "/docs"). */
19
+ hrefPrefix: string;
20
+ }
21
+ export interface GatsbyAdapter {
22
+ /** Adapter name (e.g. "posthog"). */
23
+ name: string;
24
+ /**
25
+ * The MDX adapter merged into the parser: component mappings,
26
+ * self-closing tags, inline transforms, preprocess. This is where a
27
+ * site's `<ProductScreenshot>`/`<CalloutBox>`/… become directives (or
28
+ * are stripped + ledgered).
29
+ */
30
+ mdx?: MdxAdapter;
31
+ /**
32
+ * The site's hardcoded mount prefix in internal links (e.g. "/docs").
33
+ * Links starting with it are rewritten root-relative so they resolve
34
+ * on the migrated site (which serves at its own root). Same prefix the
35
+ * nav extractor strips.
36
+ */
37
+ linkBase?: string;
38
+ /**
39
+ * Origin URL for links that point outside the migrated docs (e.g.
40
+ * "https://posthog.com"). A docs source links to sibling pages of the
41
+ * wider site (`/pricing`, `/blog/x`) that aren't migrated; left
42
+ * root-relative they 404. Any root-relative link whose target is not a
43
+ * migrated page or synthesized landing is rewritten to
44
+ * `externalBase + href`. Omit to leave unresolved links as-is.
45
+ */
46
+ externalBase?: string;
47
+ /**
48
+ * Extract the site's nav from its own nav module (e.g. PostHog's
49
+ * `src/navs/index.js`) → NavItem[]. Return null to fall back to the
50
+ * generic directory + frontmatter nav. This is the adapter's headline
51
+ * job for a hand-maintained-nav site.
52
+ */
53
+ extractNav?: (ctx: GatsbyNavContext) => NavItem[] | null;
54
+ }
55
+ //# sourceMappingURL=adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAE/D,MAAM,WAAW,gBAAgB;IAC/B,0DAA0D;IAC1D,SAAS,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,qCAAqC;IACrC,IAAI,EAAE,MAAM,CAAC;IACb;;;;;OAKG;IACH,GAAG,CAAC,EAAE,UAAU,CAAC;IACjB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,OAAO,EAAE,GAAG,IAAI,CAAC;CAC1D"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Gatsby site adapter — the extension point for what a specific Gatsby
3
+ * docs site invented on top of standard Gatsby MDX.
4
+ *
5
+ * The generic importer (cli.ts) handles the Gatsby-shape concerns: the
6
+ * `title != ""` page/partial split, `_snippets` transclusion, path→slug,
7
+ * and MDX parsing via `@dogsbay/format-mdx`. Anything site-specific — the
8
+ * custom component surface (PostHog's `<ProductScreenshot>`), and the nav
9
+ * (PostHog's hand-written `src/navs/index.js` module) — lives in a
10
+ * per-site adapter, injected by name (like the Docusaurus/Tigera split).
11
+ *
12
+ * convert ../posthog.com/contents/docs --from gatsby --adapter posthog
13
+ */
14
+ export {};
15
+ //# sourceMappingURL=adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ import type { FormatPlugin } from "@dogsbay/types";
2
+ export declare const plugin: FormatPlugin;
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAuB,MAAM,gBAAgB,CAAC;AAoTxE,eAAO,MAAM,MAAM,EAAE,YAYpB,CAAC"}
package/dist/cli.js ADDED
@@ -0,0 +1,266 @@
1
+ import { readFileSync, readdirSync, statSync } from "node:fs";
2
+ import { isAbsolute, join, relative } from "node:path";
3
+ import YAML from "yaml";
4
+ import { parseMeta } from "@dogsbay/types";
5
+ import { parseMdx, extractHeadings, compileComponentConfig, makeExtractMapping, MDX_BUILTIN_HANDLERS, } from "@dogsbay/format-mdx";
6
+ import { transcludeSnippets } from "./transclude.js";
7
+ import { normalizeInternalLinks, rewriteUnresolvedLinks } from "./links.js";
8
+ /** Directories whose files are partials/assets, never pages. */
9
+ const PARTIAL_DIRS = new Set(["_snippets", "_includes", "_media", "_posts"]);
10
+ /**
11
+ * Detect a Gatsby docs source: a `gatsby-config.*` at the root, or a
12
+ * directory of `.mdx` content (the `contents/docs` case pointed at
13
+ * directly with `--from gatsby`).
14
+ */
15
+ function detectGatsby(path) {
16
+ try {
17
+ const entries = readdirSync(path);
18
+ if (entries.some((e) => /^gatsby-config\.(js|ts|mjs|cjs)$/.test(e)))
19
+ return true;
20
+ // A contents dir with mdx + a _snippets sibling anywhere is Gatsby-shaped.
21
+ const hasMdx = entries.some((e) => e.endsWith(".mdx"));
22
+ const hasSnippets = entries.includes("_snippets");
23
+ return hasMdx && hasSnippets;
24
+ }
25
+ catch {
26
+ return false;
27
+ }
28
+ }
29
+ const FRONTMATTER_RE = /^?---\r?\n([\s\S]*?)\r?\n---\r?\n?/;
30
+ function extractFrontmatter(source) {
31
+ const match = FRONTMATTER_RE.exec(source);
32
+ if (!match || match[1].trim().length === 0)
33
+ return undefined;
34
+ try {
35
+ const parsed = YAML.parse(match[1]);
36
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed)
37
+ ? parsed
38
+ : undefined;
39
+ }
40
+ catch {
41
+ return undefined;
42
+ }
43
+ }
44
+ function walkDocFiles(dir, root) {
45
+ const out = [];
46
+ for (const entry of readdirSync(dir)) {
47
+ const full = join(dir, entry);
48
+ const st = statSync(full);
49
+ if (st.isDirectory()) {
50
+ out.push(...walkDocFiles(full, root));
51
+ }
52
+ else if (/\.(md|mdx)$/.test(entry) && entry !== "llms.txt") {
53
+ const rel = relative(root, full).replace(/\\/g, "/");
54
+ const slug = rel.replace(/\.(md|mdx)$/, "");
55
+ const isPartial = entry.startsWith("_") ||
56
+ rel.split("/").some((seg) => PARTIAL_DIRS.has(seg));
57
+ out.push({ filePath: full, slug, isPartial });
58
+ }
59
+ }
60
+ return out;
61
+ }
62
+ /** Build a nested nav from page slugs when no adapter nav is available. */
63
+ function directoryNav(pages, hrefPrefix) {
64
+ const root = [];
65
+ const groups = new Map();
66
+ const pref = hrefPrefix.replace(/\/$/, "");
67
+ for (const p of [...pages].sort((a, b) => a.slug.localeCompare(b.slug))) {
68
+ const segs = p.slug.split("/");
69
+ const item = { label: p.title || segs[segs.length - 1], href: `${pref}/${p.slug}` };
70
+ if (segs.length === 1) {
71
+ root.push(item);
72
+ continue;
73
+ }
74
+ const top = segs[0];
75
+ let group = groups.get(top);
76
+ if (!group) {
77
+ group = { label: top.replace(/[-_]/g, " "), children: [] };
78
+ groups.set(top, group);
79
+ root.push(group);
80
+ }
81
+ (group.children ??= []).push(item);
82
+ }
83
+ return root;
84
+ }
85
+ function escapeHtml(s) {
86
+ return s
87
+ .replace(/&/g, "&amp;")
88
+ .replace(/</g, "&lt;")
89
+ .replace(/>/g, "&gt;")
90
+ .replace(/"/g, "&quot;");
91
+ }
92
+ /**
93
+ * The path a page slug is actually served at: an `x/index` page serves
94
+ * at `/x`, a top-level `index` at `/`. Link targets and section-root
95
+ * existence checks compare against this, not the raw file slug.
96
+ */
97
+ function servedSlug(slug) {
98
+ if (slug === "index")
99
+ return "";
100
+ if (slug.endsWith("/index"))
101
+ return slug.slice(0, -"/index".length);
102
+ return slug;
103
+ }
104
+ /** Slug (relative to the docs root) for a nav href, stripping the mount prefix. */
105
+ function slugFromHref(href, pref) {
106
+ let h = href.replace(/[#?].*$/, "").replace(/\/+$/, "");
107
+ if (pref && h.startsWith(`${pref}/`))
108
+ h = h.slice(pref.length);
109
+ else if (pref && h === pref)
110
+ h = "";
111
+ return h.replace(/^\/+/, "");
112
+ }
113
+ /**
114
+ * Synthesize landing pages for nav "section roots" that have no page of
115
+ * their own. A Gatsby docs site often renders a product landing (e.g.
116
+ * `/docs/error-tracking`) from a template with NO backing `index.mdx`;
117
+ * after migration that URL — and every prose link to it — 404s, and it's
118
+ * usually a top-level sidebar target. For each nav item that has both an
119
+ * href and children but no migrated page, and whose slug is a real
120
+ * section root (a prefix of existing page slugs), emit an index page
121
+ * listing its child links. Fixes the sidebar clicks and the prose links
122
+ * together, generically (no per-site config).
123
+ */
124
+ function synthesizeNavLandings(pageSlugs, nav, hrefPrefix, taxonomyNames) {
125
+ const pref = hrefPrefix.replace(/\/$/, "");
126
+ // Existence is by served path — a nav root already covered by an
127
+ // `x/index` page must not get a second, colliding landing.
128
+ const served = new Set(pageSlugs.map(servedSlug));
129
+ const isSectionRoot = (slug) => !!slug && pageSlugs.some((s) => s.startsWith(`${slug}/`));
130
+ const out = [];
131
+ const made = new Set();
132
+ const walk = (items) => {
133
+ for (const it of items) {
134
+ const kids = it.children ?? [];
135
+ if (it.href && kids.length) {
136
+ const slug = slugFromHref(it.href, pref);
137
+ if (slug && !served.has(slug) && !made.has(slug) && isSectionRoot(slug)) {
138
+ made.add(slug);
139
+ const lis = kids
140
+ .filter((c) => c.href)
141
+ .map((c) => `<li><a href="${c.href}">${escapeHtml(c.label)}</a></li>`)
142
+ .join("");
143
+ const title = it.label || slug.split("/").pop() || slug;
144
+ const frontmatter = { title };
145
+ out.push({
146
+ slug,
147
+ title,
148
+ // `type: "html"` (not `{type:"paragraph", html}`) — the
149
+ // canonical serializers read raw markup off an html node in
150
+ // BOTH the direct tree→astro path and the dogsbay-md
151
+ // round-trip; a paragraph's `.html` is only honored on the
152
+ // latter, so it would render empty via `convert --to astro`.
153
+ tree: [
154
+ { type: "html", html: `<p>Pages in this section:</p>` },
155
+ { type: "html", html: `<ul>${lis}</ul>` },
156
+ ],
157
+ headings: [],
158
+ frontmatter,
159
+ meta: parseMeta(frontmatter, { slug, taxonomyNames }),
160
+ });
161
+ }
162
+ }
163
+ if (kids.length)
164
+ walk(kids);
165
+ }
166
+ };
167
+ walk(nav);
168
+ return out;
169
+ }
170
+ async function importGatsby(source, opts) {
171
+ const adapter = opts.adapterInstance;
172
+ const hrefPrefix = typeof opts.hrefPrefix === "string" ? opts.hrefPrefix : "";
173
+ const parseOpts = {};
174
+ const mdxAdapter = adapter?.mdx;
175
+ if (mdxAdapter)
176
+ parseOpts.adapter = mdxAdapter;
177
+ if (opts.componentsConfig) {
178
+ const compiled = compileComponentConfig(opts.componentsConfig, MDX_BUILTIN_HANDLERS, (spec) => makeExtractMapping(spec, (f) => (isAbsolute(f) ? f : join(source, f))));
179
+ parseOpts.components = compiled.components;
180
+ parseOpts.selfClosingTags = compiled.selfClosingTags;
181
+ }
182
+ const files = walkDocFiles(source, source);
183
+ const pages = [];
184
+ const ledger = [];
185
+ let skippedPartials = 0;
186
+ const taxonomyNames = Array.isArray(opts.taxonomyNames)
187
+ ? opts.taxonomyNames
188
+ : undefined;
189
+ const sources = [];
190
+ for (const { filePath, slug, isPartial } of files) {
191
+ if (isPartial)
192
+ continue; // partials are transcluded, never pages
193
+ const raw = readFileSync(filePath, "utf-8");
194
+ const frontmatter = extractFrontmatter(raw);
195
+ const title = typeof frontmatter?.title === "string" ? frontmatter.title : "";
196
+ // Gatsby's page rule: allMdx filtered to title != "". No title → partial.
197
+ if (title.trim() === "") {
198
+ skippedPartials++;
199
+ continue;
200
+ }
201
+ // Resolve _snippets transclusion, then normalize the site's internal
202
+ // link prefix (e.g. "/docs/x" → "/x").
203
+ let text = transcludeSnippets(raw, filePath);
204
+ if (adapter?.linkBase)
205
+ text = normalizeInternalLinks(text, adapter.linkBase, hrefPrefix);
206
+ sources.push({ filePath, slug, title, frontmatter, text });
207
+ }
208
+ const pageSlugs = sources.map((s) => s.slug);
209
+ // Nav: adapter extractor (e.g. posthog navs/index.js) → directory fallback.
210
+ let nav = null;
211
+ if (adapter?.extractNav) {
212
+ try {
213
+ nav = adapter.extractNav({ sourceDir: source, hrefPrefix });
214
+ }
215
+ catch {
216
+ nav = null;
217
+ }
218
+ }
219
+ if (!nav || nav.length === 0)
220
+ nav = directoryNav(sources, hrefPrefix);
221
+ // Landing pages for nav section-roots with no backing file, so sidebar
222
+ // clicks and prose links to them resolve instead of 404ing.
223
+ const landings = synthesizeNavLandings(pageSlugs, nav, hrefPrefix, taxonomyNames);
224
+ // Everything the migrated site can serve — used to decide which
225
+ // root-relative links are off-docs and belong on the origin site. Both
226
+ // the raw file slug and its served path count (`/x` and `/x/index`).
227
+ const resolvable = new Set([
228
+ ...pageSlugs,
229
+ ...pageSlugs.map(servedSlug),
230
+ ...landings.map((l) => l.slug),
231
+ ]);
232
+ const isResolvable = (slug) => resolvable.has(slug);
233
+ // Phase 2 — rewrite off-docs links to the origin, then parse.
234
+ for (const { filePath, slug, title, frontmatter, text: text0 } of sources) {
235
+ const text = adapter?.externalBase
236
+ ? rewriteUnresolvedLinks(text0, isResolvable, adapter.externalBase, hrefPrefix)
237
+ : text0;
238
+ const result = parseMdx(text, { ...parseOpts, file: relative(source, filePath) });
239
+ ledger.push(...result.ledger);
240
+ const headings = extractHeadings(result.tree);
241
+ const meta = parseMeta(frontmatter, { slug, taxonomyNames });
242
+ pages.push({ slug, title, tree: result.tree, headings, frontmatter, meta });
243
+ }
244
+ if (landings.length)
245
+ pages.push(...landings);
246
+ opts.importLedger = ledger;
247
+ if (opts.report) {
248
+ console.log(`\nGatsby import: ${pages.length} pages (${landings.length} synthesized landings), ` +
249
+ `${skippedPartials} partials skipped, ${ledger.length} ledger entries.`);
250
+ }
251
+ return { pages, nav };
252
+ }
253
+ export const plugin = {
254
+ name: "gatsby",
255
+ canImport: true,
256
+ canExport: false,
257
+ detectSource: detectGatsby,
258
+ importOptions: [
259
+ { flags: "--adapter <name>", description: "Gatsby site adapter (e.g. posthog)" },
260
+ { flags: "--components <path>", description: "YAML/JSON declarative component mappings" },
261
+ { flags: "--report", description: "Print the import summary + fidelity ledger" },
262
+ ],
263
+ exportOptions: [],
264
+ import: importGatsby,
265
+ };
266
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export type { GatsbyAdapter, GatsbyNavContext } from "./adapter.js";
2
+ export { transcludeSnippets } from "./transclude.js";
3
+ export { normalizeInternalLinks, rewriteUnresolvedLinks } from "./links.js";
4
+ export { plugin } from "./cli.js";
5
+ export type { MdxAdapter, ComponentMapping, NavItem, TreeNode } from "@dogsbay/format-mdx";
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAC5E,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,YAAY,EAAE,UAAU,EAAE,gBAAgB,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export { transcludeSnippets } from "./transclude.js";
2
+ export { normalizeInternalLinks, rewriteUnresolvedLinks } from "./links.js";
3
+ export { plugin } from "./cli.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAC5E,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Internal-link normalization. A Gatsby docs site hardcodes its mount
3
+ * prefix into every internal link (`href="/docs/error-tracking"`,
4
+ * `[x](/docs/session-replay)`). The migrated site serves content at its
5
+ * own root (slugs relative to the docs dir), so that prefix must be
6
+ * stripped or every link 404s. Mirrors the nav extractor's `/docs`
7
+ * stripping.
8
+ *
9
+ * Fence-safe: only prose is rewritten, never fenced code (a code example
10
+ * containing `/docs/…` is left intact). Rewrites only inside link
11
+ * contexts (`](…)` and `href="…"`), so bare prose mentions are untouched.
12
+ */
13
+ /**
14
+ * Rewrite internal links that start with `base` (e.g. "/docs") to be
15
+ * root-relative under `hrefPrefix` (default root). `/docs/x` → `/x`,
16
+ * `/docs` → `/`, `/docs/x#a` → `/x#a`.
17
+ */
18
+ export declare function normalizeInternalLinks(source: string, base: string, hrefPrefix?: string): string;
19
+ /**
20
+ * Rewrite root-relative links whose target is NOT a migrated page to an
21
+ * absolute URL under `externalBase` (the origin site). A docs source
22
+ * links to sibling pages of the wider site (`/pricing`, `/blog/x`,
23
+ * `/talk-to-a-human`) that live on the origin, not in the migrated docs;
24
+ * left as `/pricing` they 404. `isResolvable(slug)` reports whether a
25
+ * slug maps to a migrated page or synthesized landing.
26
+ *
27
+ * Only root-relative link targets are candidates. Anchors (`#x`),
28
+ * protocol-relative (`//host`), already-absolute (`https://…`),
29
+ * `mailto:`, and image links (`![](…)`) are left untouched. Fence-safe.
30
+ */
31
+ export declare function rewriteUnresolvedLinks(source: string, isResolvable: (slug: string) => boolean, externalBase: string, hrefPrefix?: string): string;
32
+ //# sourceMappingURL=links.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"links.d.ts","sourceRoot":"","sources":["../src/links.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAoBH;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,UAAU,SAAK,GACd,MAAM,CAeR;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,EACvC,YAAY,EAAE,MAAM,EACpB,UAAU,SAAK,GACd,MAAM,CAiCR"}
package/dist/links.js ADDED
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Internal-link normalization. A Gatsby docs site hardcodes its mount
3
+ * prefix into every internal link (`href="/docs/error-tracking"`,
4
+ * `[x](/docs/session-replay)`). The migrated site serves content at its
5
+ * own root (slugs relative to the docs dir), so that prefix must be
6
+ * stripped or every link 404s. Mirrors the nav extractor's `/docs`
7
+ * stripping.
8
+ *
9
+ * Fence-safe: only prose is rewritten, never fenced code (a code example
10
+ * containing `/docs/…` is left intact). Rewrites only inside link
11
+ * contexts (`](…)` and `href="…"`), so bare prose mentions are untouched.
12
+ */
13
+ /** Escape a string for use in a RegExp. */
14
+ function esc(s) {
15
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
16
+ }
17
+ /**
18
+ * Apply `fn` to prose only, leaving code untouched — both fenced blocks
19
+ * (```` ``` ````/`~~~`) and inline spans (single backticks). A code
20
+ * sample that literally shows link/anchor syntax (`` `[x](/docs/y)` ``)
21
+ * must not be rewritten. Fenced alternatives come first so a fenced
22
+ * block's inner backticks can't be mistaken for an inline span.
23
+ */
24
+ function rewriteProse(source, fn) {
25
+ const parts = source.split(/(```[\s\S]*?```|~~~[\s\S]*?~~~|`[^`\n]+`)/g);
26
+ for (let i = 0; i < parts.length; i += 2)
27
+ parts[i] = fn(parts[i]);
28
+ return parts.join("");
29
+ }
30
+ /**
31
+ * Rewrite internal links that start with `base` (e.g. "/docs") to be
32
+ * root-relative under `hrefPrefix` (default root). `/docs/x` → `/x`,
33
+ * `/docs` → `/`, `/docs/x#a` → `/x#a`.
34
+ */
35
+ export function normalizeInternalLinks(source, base, hrefPrefix = "") {
36
+ if (!base)
37
+ return source;
38
+ const b = esc(base.replace(/\/$/, ""));
39
+ const pref = hrefPrefix.replace(/\/$/, "");
40
+ // Anchor: after a markdown link `](` or an `href="`/`href='`.
41
+ const anchor = `(\\]\\(|href=["'])`;
42
+ const withSlash = new RegExp(`${anchor}${b}/`, "g"); // /docs/x → <pref>/x
43
+ const bare = new RegExp(`${anchor}${b}(?=[)"'#?\\s])`, "g"); // /docs → <pref>/
44
+ const rewrite = (text) => text
45
+ .replace(withSlash, `$1${pref}/`)
46
+ .replace(bare, `$1${pref}/`);
47
+ return rewriteProse(source, rewrite);
48
+ }
49
+ /**
50
+ * Rewrite root-relative links whose target is NOT a migrated page to an
51
+ * absolute URL under `externalBase` (the origin site). A docs source
52
+ * links to sibling pages of the wider site (`/pricing`, `/blog/x`,
53
+ * `/talk-to-a-human`) that live on the origin, not in the migrated docs;
54
+ * left as `/pricing` they 404. `isResolvable(slug)` reports whether a
55
+ * slug maps to a migrated page or synthesized landing.
56
+ *
57
+ * Only root-relative link targets are candidates. Anchors (`#x`),
58
+ * protocol-relative (`//host`), already-absolute (`https://…`),
59
+ * `mailto:`, and image links (`![](…)`) are left untouched. Fence-safe.
60
+ */
61
+ export function rewriteUnresolvedLinks(source, isResolvable, externalBase, hrefPrefix = "") {
62
+ if (!externalBase)
63
+ return source;
64
+ const base = externalBase.replace(/\/$/, "");
65
+ const pref = hrefPrefix.replace(/\/$/, "");
66
+ /** Slug for a root-relative href, or null if not a rewrite candidate. */
67
+ const toSlug = (href) => {
68
+ if (!href.startsWith("/") || href.startsWith("//"))
69
+ return null;
70
+ let p = href.replace(/[#?].*$/, "").replace(/\/+$/, "");
71
+ if (pref && (p === pref || p.startsWith(`${pref}/`)))
72
+ p = p.slice(pref.length);
73
+ return p.replace(/^\/+/, "");
74
+ };
75
+ const rewriteHref = (href) => {
76
+ const slug = toSlug(href);
77
+ if (slug === null || slug === "")
78
+ return href; // not a candidate / site root
79
+ return isResolvable(slug) ? href : base + href; // off-docs → origin URL
80
+ };
81
+ const rewrite = (text) => text
82
+ // HTML anchors: href="/x" / href='/x' (path may carry #anchor/?query)
83
+ .replace(/href=("|')(\/[^"']*)\1/g, (_m, q, href) => `href=${q}${rewriteHref(href)}${q}`)
84
+ // Markdown links [text](/x) or [text](/x "title"); skip images (`!`).
85
+ .replace(/(!?)\[([^\]]*)\]\((\/[^)\s]*)(\s+"[^"]*")?\)/g, (m, bang, txt, href, title) => bang ? m : `[${txt}](${rewriteHref(href)}${title ?? ""})`);
86
+ return rewriteProse(source, rewrite);
87
+ }
88
+ //# sourceMappingURL=links.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"links.js","sourceRoot":"","sources":["../src/links.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * `_snippets` transclusion — the Gatsby MDX pattern PostHog uses on 57%
3
+ * of files: `import X from './_snippets/x.mdx'` at the top, then `<X/>`
4
+ * in the body. Gatsby renders the imported component (the partial's MDX)
5
+ * at that site; without resolution the import is stripped and the
6
+ * `<X/>` renders empty, silently dropping content.
7
+ *
8
+ * This runs BEFORE the MDX parse: it resolves each local `.md/.mdx`
9
+ * default import, reads + frontmatter-strips + (recursively) transcludes
10
+ * the partial, and substitutes its body at every `<X/>` / `<X ... />`
11
+ * usage. Non-`.md(x)` imports (real components) are left for the
12
+ * component adapter. Cycle-guarded.
13
+ */
14
+ /**
15
+ * Inline local `.md(x)` default imports at their `<Ident/>` usage sites.
16
+ * `filePath` is the absolute path of the file being processed (imports
17
+ * resolve relative to its directory). `seen` guards cycles.
18
+ */
19
+ export declare function transcludeSnippets(source: string, filePath: string, seen?: Set<string>): string;
20
+ //# sourceMappingURL=transclude.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transclude.d.ts","sourceRoot":"","sources":["../src/transclude.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AA8BH;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE,GAAG,CAAC,MAAM,CAAa,GAC5B,MAAM,CAiDR"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * `_snippets` transclusion — the Gatsby MDX pattern PostHog uses on 57%
3
+ * of files: `import X from './_snippets/x.mdx'` at the top, then `<X/>`
4
+ * in the body. Gatsby renders the imported component (the partial's MDX)
5
+ * at that site; without resolution the import is stripped and the
6
+ * `<X/>` renders empty, silently dropping content.
7
+ *
8
+ * This runs BEFORE the MDX parse: it resolves each local `.md/.mdx`
9
+ * default import, reads + frontmatter-strips + (recursively) transcludes
10
+ * the partial, and substitutes its body at every `<X/>` / `<X ... />`
11
+ * usage. Non-`.md(x)` imports (real components) are left for the
12
+ * component adapter. Cycle-guarded.
13
+ */
14
+ import { existsSync, readFileSync } from "node:fs";
15
+ import { dirname, resolve } from "node:path";
16
+ const FRONTMATTER_RE = /^?---\r?\n[\s\S]*?\r?\n---\r?\n/;
17
+ /**
18
+ * A FRESH regex per call — `transcludeSnippets` recurses, and a shared
19
+ * `/g` regex's `lastIndex` would be corrupted by inner calls (infinite
20
+ * loop). Never hoist this to module scope.
21
+ */
22
+ function importRe() {
23
+ return /^\s*import\s+([A-Za-z_$][\w$]*)\s+from\s+["']([^"']+)["']\s*;?\s*$/gm;
24
+ }
25
+ function stripFrontmatter(src) {
26
+ return src.replace(FRONTMATTER_RE, "");
27
+ }
28
+ /** Resolve an import specifier to a partial file path, or null. */
29
+ function resolvePartial(spec, fromDir) {
30
+ if (!spec.startsWith(".") && !spec.startsWith("/"))
31
+ return null; // bare pkg / @site alias → not a local partial
32
+ const base = resolve(fromDir, spec);
33
+ const candidates = /\.(md|mdx)$/.test(spec)
34
+ ? [base]
35
+ : [`${base}.mdx`, `${base}.md`, resolve(base, "index.mdx"), resolve(base, "index.md")];
36
+ return candidates.find((c) => existsSync(c)) ?? null;
37
+ }
38
+ /**
39
+ * Inline local `.md(x)` default imports at their `<Ident/>` usage sites.
40
+ * `filePath` is the absolute path of the file being processed (imports
41
+ * resolve relative to its directory). `seen` guards cycles.
42
+ */
43
+ export function transcludeSnippets(source, filePath, seen = new Set()) {
44
+ const fromDir = dirname(filePath);
45
+ const inlines = new Map(); // Ident → resolved body
46
+ // Pass 1: collect + strip local .md(x) imports; leave others in place.
47
+ const kept = [];
48
+ const re = importRe();
49
+ let lastIndex = 0;
50
+ let m;
51
+ const drops = [];
52
+ while ((m = re.exec(source)) !== null) {
53
+ const [full, ident, spec] = m;
54
+ const partial = resolvePartial(spec, fromDir);
55
+ if (!partial)
56
+ continue; // real component import — keep for the adapter
57
+ drops.push([m.index, m.index + full.length]);
58
+ if (seen.has(partial)) {
59
+ inlines.set(ident, ""); // cycle — drop
60
+ continue;
61
+ }
62
+ const raw = stripFrontmatter(readFileSync(partial, "utf-8"));
63
+ const next = new Set(seen);
64
+ next.add(partial);
65
+ inlines.set(ident, transcludeSnippets(raw, partial, next).trim());
66
+ }
67
+ // Remove the collected import lines.
68
+ if (drops.length) {
69
+ drops.sort((a, b) => a[0] - b[0]);
70
+ for (const [s, e] of drops) {
71
+ kept.push(source.slice(lastIndex, s));
72
+ lastIndex = e;
73
+ }
74
+ kept.push(source.slice(lastIndex));
75
+ source = kept.join("");
76
+ }
77
+ if (inlines.size === 0)
78
+ return source;
79
+ // Pass 2: substitute <Ident/> and <Ident …/> (block usage) with the body.
80
+ for (const [ident, body] of inlines) {
81
+ const usage = new RegExp(`<${ident}(\\s[^>]*?)?\\s*/>`, "g");
82
+ source = source.replace(usage, () => `\n\n${body}\n\n`);
83
+ // Also handle paired <Ident>…</Ident> (rare) → body + inner dropped.
84
+ const paired = new RegExp(`<${ident}(\\s[^>]*?)?>[\\s\\S]*?</${ident}>`, "g");
85
+ source = source.replace(paired, () => `\n\n${body}\n\n`);
86
+ }
87
+ return source;
88
+ }
89
+ //# sourceMappingURL=transclude.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transclude.js","sourceRoot":"","sources":["../src/transclude.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@dogsbay/format-gatsby",
3
+ "version": "0.2.0-beta.101",
4
+ "description": "GatsbyJS docs importer for Dogsbay — a Gatsby shell over @dogsbay/format-mdx: page-walk (title!=\"\"), _snippets transclusion, and injected site adapters (nav + components).",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ },
13
+ "./cli": {
14
+ "types": "./dist/cli.d.ts",
15
+ "import": "./dist/cli.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "README.md"
21
+ ],
22
+ "dependencies": {
23
+ "yaml": "^2.9.0",
24
+ "@dogsbay/format-mdx": "0.2.0-beta.101",
25
+ "@dogsbay/types": "0.2.0-beta.101"
26
+ },
27
+ "devDependencies": {
28
+ "@types/node": "^25.9.5",
29
+ "typescript": "^5.9.3",
30
+ "vitest": "^4.1.10",
31
+ "@dogsbay/format-astro": "0.2.0-beta.101"
32
+ },
33
+ "license": "MIT",
34
+ "scripts": {
35
+ "build": "tsc",
36
+ "test": "vitest run",
37
+ "test:watch": "vitest"
38
+ }
39
+ }