dogsbay 0.2.0-beta.51 → 0.2.0-beta.53
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/commands/migrate-asciidoc.js +84 -11
- package/dist/index.js +2 -1
- package/dist/site-build/preprocess.js +15 -0
- package/package.json +13 -13
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
* astro/ ← scaffolded by emitSiteScaffold
|
|
26
26
|
* MIGRATION.md ← what survived + re-run command
|
|
27
27
|
*/
|
|
28
|
-
import { copyFileSync, existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, readlinkSync, statSync, symlinkSync, writeFileSync, } from "node:fs";
|
|
28
|
+
import { copyFileSync, cpSync, existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, readlinkSync, rmSync, statSync, symlinkSync, writeFileSync, } from "node:fs";
|
|
29
29
|
import { basename, dirname, join, relative, resolve } from "node:path";
|
|
30
30
|
import pc from "picocolors";
|
|
31
31
|
import { emitSiteScaffold } from "@dogsbay/format-astro";
|
|
@@ -207,7 +207,7 @@ function mirrorSourceFs(sourceRoot, outputContentDir, scopedRootDirs) {
|
|
|
207
207
|
*
|
|
208
208
|
* Returns counts for the summary.
|
|
209
209
|
*/
|
|
210
|
-
function convertFragmentAdocs(sourceRoot, outputContentDir, scopedRootDirs) {
|
|
210
|
+
function convertFragmentAdocs(sourceRoot, outputContentDir, scopedRootDirs, pageWrittenPaths, imagesdir) {
|
|
211
211
|
let converted = 0;
|
|
212
212
|
let failed = 0;
|
|
213
213
|
let skipped = 0;
|
|
@@ -245,17 +245,32 @@ function convertFragmentAdocs(sourceRoot, outputContentDir, scopedRootDirs) {
|
|
|
245
245
|
continue;
|
|
246
246
|
const mdName = name.replace(/\.adoc$/i, ".md");
|
|
247
247
|
const mdPath = join(dstDir, mdName);
|
|
248
|
-
// A topic page
|
|
249
|
-
//
|
|
250
|
-
//
|
|
251
|
-
//
|
|
252
|
-
|
|
248
|
+
// A topic page wrote this destination THIS run — don't overwrite
|
|
249
|
+
// it with the engine-only fragment output (the page version has
|
|
250
|
+
// frontmatter, headings, and went through markdown-it + serialize
|
|
251
|
+
// for canonical Dogsbay-MD shape). We check the known set of
|
|
252
|
+
// this-run page writes, NOT existsSync: a stale .md left by a
|
|
253
|
+
// prior --force run must be re-converted, not mistaken for a page
|
|
254
|
+
// and skipped (#364).
|
|
255
|
+
if (pageWrittenPaths.has(mdPath)) {
|
|
253
256
|
skipped += 1;
|
|
254
257
|
continue;
|
|
255
258
|
}
|
|
256
259
|
try {
|
|
257
260
|
const content = readFileSync(srcPath, "utf-8");
|
|
258
|
-
|
|
261
|
+
// Same Dogsbay house defaults as the topic-page path
|
|
262
|
+
// (format-asciidoc parse.ts): 'pandoc' dlists + 'docusaurus'
|
|
263
|
+
// admonitions — the shapes Dogsbay's renderer renders natively.
|
|
264
|
+
// Fragments are included into pages, so their shape must match.
|
|
265
|
+
const md = asciidocToMarkdown(content, {
|
|
266
|
+
basePath: srcPath,
|
|
267
|
+
dlistFormat: "pandoc",
|
|
268
|
+
admonitionFormat: "docusaurus",
|
|
269
|
+
// imagesdir = "/_assets/<dir>" makes the engine emit image
|
|
270
|
+
// srcs already content-rooted (/_assets/images/foo.png), so
|
|
271
|
+
// they resolve regardless of fragment depth. See #363.
|
|
272
|
+
attributes: imagesdir ? { imagesdir } : undefined,
|
|
273
|
+
});
|
|
259
274
|
mkdirSync(dstDir, { recursive: true });
|
|
260
275
|
// No frontmatter — fragments are pure content. An earlier
|
|
261
276
|
// attempt stamped `_fragment: true` here as a loader-driven
|
|
@@ -451,6 +466,22 @@ export async function migrateAsciidoc(source, options) {
|
|
|
451
466
|
process.exit(1);
|
|
452
467
|
}
|
|
453
468
|
const attributes = parseAttributePairs(options.attribute);
|
|
469
|
+
// Image handling (#363). AsciiDoc keeps images in an `:imagesdir:`
|
|
470
|
+
// (OpenShift / AsciiBinder / Antora convention: a top-level `images/`
|
|
471
|
+
// dir). The engine's image() prepends imagesdir to every src, so
|
|
472
|
+
// supplying `imagesdir = "/_assets/<dir>"` makes refs emit
|
|
473
|
+
// already-rooted (`/_assets/images/foo.png`) — matching the Dogsbay
|
|
474
|
+
// `_assets` convention (docs/images.md). We copy the dir into
|
|
475
|
+
// content/_assets/<dir>/ below. Detected, NOT persisted to config
|
|
476
|
+
// (a migrate-time rendering concern, not a content attribute).
|
|
477
|
+
const srcImagesDir = existsSync(join(sourceDir, "images")) &&
|
|
478
|
+
statSync(join(sourceDir, "images")).isDirectory()
|
|
479
|
+
? "images"
|
|
480
|
+
: undefined;
|
|
481
|
+
const engineImagesdir = srcImagesDir ? `/_assets/${srcImagesDir}` : undefined;
|
|
482
|
+
const engineAttributes = engineImagesdir
|
|
483
|
+
? { ...attributes, imagesdir: engineImagesdir }
|
|
484
|
+
: attributes;
|
|
454
485
|
console.log();
|
|
455
486
|
console.log(pc.bold(`Migrating AsciiDoc corpus to Dogsbay-MD: ${siteName}`));
|
|
456
487
|
console.log(`Source: ${sourceDir}`);
|
|
@@ -459,6 +490,19 @@ export async function migrateAsciidoc(source, options) {
|
|
|
459
490
|
// 1. Output skeleton.
|
|
460
491
|
const contentDir = join(outputDir, "content");
|
|
461
492
|
const astroDir = join(outputDir, "astro");
|
|
493
|
+
// Clean slate for the regenerated content tree (#364). We only reach
|
|
494
|
+
// here on a fresh output or with --force (the existing-site guard
|
|
495
|
+
// above already exited otherwise), so a pre-existing content/ is a
|
|
496
|
+
// prior migration's output. Clear it so stale files don't linger
|
|
497
|
+
// across re-migrations — renamed/removed dirs (e.g. content/images/
|
|
498
|
+
// after #363 moved images to _assets) and orphaned pages. content/ is
|
|
499
|
+
// entirely migration-generated; --force is a clean re-import and
|
|
500
|
+
// discards any hand edits under content/ (see the --force help text).
|
|
501
|
+
// astro/ is left intact: emitSiteScaffold overwrites its files in
|
|
502
|
+
// place, and clearing it would drop a warm node_modules.
|
|
503
|
+
if (existsSync(contentDir)) {
|
|
504
|
+
rmSync(contentDir, { recursive: true, force: true });
|
|
505
|
+
}
|
|
462
506
|
mkdirSync(contentDir, { recursive: true });
|
|
463
507
|
mkdirSync(astroDir, { recursive: true });
|
|
464
508
|
// 2. Import via the format-asciidoc plugin. Phase 9a moved corpus
|
|
@@ -470,7 +514,7 @@ export async function migrateAsciidoc(source, options) {
|
|
|
470
514
|
throw new Error("format-asciidoc plugin has no import function");
|
|
471
515
|
}
|
|
472
516
|
const { pages: importedPages, nav } = await asciidocPlugin.import(sourceDir, {
|
|
473
|
-
attributes,
|
|
517
|
+
attributes: engineAttributes,
|
|
474
518
|
loader: options.loader,
|
|
475
519
|
});
|
|
476
520
|
if (importedPages.length === 0) {
|
|
@@ -495,12 +539,19 @@ export async function migrateAsciidoc(source, options) {
|
|
|
495
539
|
// Fall back to treeToDogsbayMd for importers that don't produce
|
|
496
540
|
// bodyMarkdown (e.g. mkdocs imports during a future
|
|
497
541
|
// dual-format migration). No behaviour change for those.
|
|
542
|
+
// Track the .md paths the page step wrote THIS run. The fragment
|
|
543
|
+
// converter skips these so it can't clobber a topic page with its
|
|
544
|
+
// headerless engine-only output. Using a known set (not existsSync)
|
|
545
|
+
// means a stale .md left over from a prior --force run is NOT mistaken
|
|
546
|
+
// for a this-run page — it gets re-converted. See #364.
|
|
547
|
+
const pageWrittenPaths = new Set();
|
|
498
548
|
for (const page of importedPages) {
|
|
499
549
|
const body = page.bodyMarkdown ?? treeToDogsbayMd(page.tree);
|
|
500
550
|
const dst = join(contentDir, `${page.slug}.md`);
|
|
501
551
|
mkdirSync(dirname(dst), { recursive: true });
|
|
502
552
|
const frontmatter = `---\ntitle: ${yamlQuote(page.title)}\n---\n\n`;
|
|
503
553
|
writeFileSync(dst, frontmatter + body);
|
|
554
|
+
pageWrittenPaths.add(dst);
|
|
504
555
|
}
|
|
505
556
|
console.log(pc.green(`Converted`) + ` ${importedPages.length} page(s) to ./content/`);
|
|
506
557
|
// 3b. Compute the scoped set of root-level dirs we'll walk for
|
|
@@ -523,7 +574,11 @@ export async function migrateAsciidoc(source, options) {
|
|
|
523
574
|
// skips routes for them via the generated config's
|
|
524
575
|
// excludeFromRoutes. Adding them to scope just lets the walkers
|
|
525
576
|
// descend; the route skip happens separately.
|
|
526
|
-
|
|
577
|
+
// Note: the imagesdir (`images`) is intentionally NOT here — it's
|
|
578
|
+
// copied to content/_assets/<dir>/ below and referenced as
|
|
579
|
+
// /_assets/<dir>/... (#363), so the generic mirror must not also
|
|
580
|
+
// copy it to content/images/ (dead weight; refs don't point there).
|
|
581
|
+
for (const d of ["_attributes", "modules", "snippets", "includes"]) {
|
|
527
582
|
scopedRootDirs.add(d);
|
|
528
583
|
}
|
|
529
584
|
// 3c. Fragment .adoc files (everything not topic-listed but in
|
|
@@ -534,7 +589,7 @@ export async function migrateAsciidoc(source, options) {
|
|
|
534
589
|
// fragments. Fragment conversion is engine-only (no Minja,
|
|
535
590
|
// no markdown-it) so directives inside fragments survive
|
|
536
591
|
// verbatim and resolve in the parent page's context.
|
|
537
|
-
const frag = convertFragmentAdocs(sourceDir, contentDir, scopedRootDirs);
|
|
592
|
+
const frag = convertFragmentAdocs(sourceDir, contentDir, scopedRootDirs, pageWrittenPaths, engineImagesdir);
|
|
538
593
|
if (frag.converted > 0) {
|
|
539
594
|
console.log(pc.green(`Converted`) +
|
|
540
595
|
` ${frag.converted} fragment(s)` +
|
|
@@ -555,6 +610,24 @@ export async function migrateAsciidoc(source, options) {
|
|
|
555
610
|
parts.push(`${mirror.assets} asset(s)`);
|
|
556
611
|
console.log(pc.green(`Mirrored`) + ` ${parts.join(" + ")}`);
|
|
557
612
|
}
|
|
613
|
+
// 3e. Copy the imagesdir tree into content/_assets/<dir>/ so the
|
|
614
|
+
// rooted image refs (/_assets/<dir>/foo.png, emitted by the
|
|
615
|
+
// engine via the supplied imagesdir) resolve. format-astro's
|
|
616
|
+
// copyAssets serves content/_assets/** at /_assets/** on every
|
|
617
|
+
// build. (#363)
|
|
618
|
+
if (srcImagesDir) {
|
|
619
|
+
const from = join(sourceDir, srcImagesDir);
|
|
620
|
+
const to = join(contentDir, "_assets", srcImagesDir);
|
|
621
|
+
try {
|
|
622
|
+
mkdirSync(dirname(to), { recursive: true });
|
|
623
|
+
cpSync(from, to, { recursive: true });
|
|
624
|
+
console.log(pc.green(`Copied`) + ` images → content/_assets/${srcImagesDir}/`);
|
|
625
|
+
}
|
|
626
|
+
catch (err) {
|
|
627
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
628
|
+
console.warn(`images: could not copy ${from} → ${to}: ${msg}`);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
558
631
|
// 4. nav.yml — directly from the loader's NavItem[]. The loader
|
|
559
632
|
// decides the shape (directory-mirror for plain, per-title
|
|
560
633
|
// grouping for master.adoc, etc.). We just serialize.
|
package/dist/index.js
CHANGED
|
@@ -212,7 +212,8 @@ program
|
|
|
212
212
|
"Antora, and AAP master.adoc loaders are planned for a later release.")
|
|
213
213
|
.argument("<source>", "Path to a directory containing .adoc files")
|
|
214
214
|
.option("-o, --output <dir>", "Output directory (default: {source}-dogsbay)")
|
|
215
|
-
.option("--force", "Overwrite an existing Dogsbay site
|
|
215
|
+
.option("--force", "Overwrite an existing Dogsbay site. Clean re-import: clears the " +
|
|
216
|
+
"content/ tree first, discarding any edits under it (astro/ kept).")
|
|
216
217
|
.option("--site-name <name>", "Site name written into dogsbay.config.yml")
|
|
217
218
|
.option("--site-url <url>", "Canonical URL of the destination site (e.g. " +
|
|
218
219
|
"https://you.github.io/repo). Drives robots.txt, sitemap, " +
|
|
@@ -57,6 +57,21 @@ export function mergeAttributes(siteWide, perSource, cliOverrides) {
|
|
|
57
57
|
...(perSource ?? {}),
|
|
58
58
|
...(cliOverrides ?? {}),
|
|
59
59
|
};
|
|
60
|
+
// AsciiDoc attribute names are hyphenated by convention (product-title,
|
|
61
|
+
// openshift-enterprise), but the engine emits underscored Minja vars
|
|
62
|
+
// ({{ product_title }}) and minja's context lookup is keyed on the
|
|
63
|
+
// underscored form (hyphenToUnderscore normalizes the *lookup*, not the
|
|
64
|
+
// stored keys). So a supplied `product-title` would never match. Add an
|
|
65
|
+
// underscored alias for every hyphenated key so users can pass either
|
|
66
|
+
// form. The original is kept; explicit underscored keys win over an
|
|
67
|
+
// alias derived from a hyphenated one.
|
|
68
|
+
for (const [key, value] of Object.entries({ ...merged })) {
|
|
69
|
+
if (key.includes("-")) {
|
|
70
|
+
const underscored = key.replace(/-/g, "_");
|
|
71
|
+
if (!(underscored in merged))
|
|
72
|
+
merged[underscored] = value;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
60
75
|
return Object.keys(merged).length > 0 ? merged : undefined;
|
|
61
76
|
}
|
|
62
77
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dogsbay",
|
|
3
|
-
"version": "0.2.0-beta.
|
|
3
|
+
"version": "0.2.0-beta.53",
|
|
4
4
|
"description": "CLI for Dogsbay — scaffold, build, and serve documentation sites with markdown / MkDocs / Obsidian / OpenAPI sources",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -33,18 +33,18 @@
|
|
|
33
33
|
"picocolors": "^1.1.0",
|
|
34
34
|
"prompts": "^2.4.2",
|
|
35
35
|
"yaml": "^2.8.3",
|
|
36
|
-
"@dogsbay/autodoc-python": "0.2.0-beta.
|
|
37
|
-
"@dogsbay/format-
|
|
38
|
-
"@dogsbay/format-
|
|
39
|
-
"@dogsbay/format-obsidian": "0.2.0-beta.
|
|
40
|
-
"@dogsbay/format-mdx": "0.2.0-beta.
|
|
41
|
-
"@dogsbay/format-
|
|
42
|
-
"@dogsbay/format-
|
|
43
|
-
"@dogsbay/format-openapi": "0.2.0-beta.
|
|
44
|
-
"@dogsbay/
|
|
45
|
-
"@dogsbay/
|
|
46
|
-
"@dogsbay/
|
|
47
|
-
"@dogsbay/
|
|
36
|
+
"@dogsbay/autodoc-python": "0.2.0-beta.53",
|
|
37
|
+
"@dogsbay/format-mkdocs": "0.2.0-beta.53",
|
|
38
|
+
"@dogsbay/format-astro": "0.2.0-beta.53",
|
|
39
|
+
"@dogsbay/format-obsidian": "0.2.0-beta.53",
|
|
40
|
+
"@dogsbay/format-mdx": "0.2.0-beta.53",
|
|
41
|
+
"@dogsbay/format-dogsbay-md": "0.2.0-beta.53",
|
|
42
|
+
"@dogsbay/format-starlight": "0.2.0-beta.53",
|
|
43
|
+
"@dogsbay/format-openapi": "0.2.0-beta.53",
|
|
44
|
+
"@dogsbay/adoc2md-modular": "0.2.0-beta.53",
|
|
45
|
+
"@dogsbay/format-asciidoc": "0.2.0-beta.53",
|
|
46
|
+
"@dogsbay/minja": "0.2.0-beta.53",
|
|
47
|
+
"@dogsbay/types": "0.2.0-beta.53"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"@types/markdown-it": "^14.1.0",
|