dogsbay 0.2.0-beta.52 → 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 +75 -10
- 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,11 +245,14 @@ 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
|
}
|
|
@@ -263,6 +266,10 @@ function convertFragmentAdocs(sourceRoot, outputContentDir, scopedRootDirs) {
|
|
|
263
266
|
basePath: srcPath,
|
|
264
267
|
dlistFormat: "pandoc",
|
|
265
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,
|
|
266
273
|
});
|
|
267
274
|
mkdirSync(dstDir, { recursive: true });
|
|
268
275
|
// No frontmatter — fragments are pure content. An earlier
|
|
@@ -459,6 +466,22 @@ export async function migrateAsciidoc(source, options) {
|
|
|
459
466
|
process.exit(1);
|
|
460
467
|
}
|
|
461
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;
|
|
462
485
|
console.log();
|
|
463
486
|
console.log(pc.bold(`Migrating AsciiDoc corpus to Dogsbay-MD: ${siteName}`));
|
|
464
487
|
console.log(`Source: ${sourceDir}`);
|
|
@@ -467,6 +490,19 @@ export async function migrateAsciidoc(source, options) {
|
|
|
467
490
|
// 1. Output skeleton.
|
|
468
491
|
const contentDir = join(outputDir, "content");
|
|
469
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
|
+
}
|
|
470
506
|
mkdirSync(contentDir, { recursive: true });
|
|
471
507
|
mkdirSync(astroDir, { recursive: true });
|
|
472
508
|
// 2. Import via the format-asciidoc plugin. Phase 9a moved corpus
|
|
@@ -478,7 +514,7 @@ export async function migrateAsciidoc(source, options) {
|
|
|
478
514
|
throw new Error("format-asciidoc plugin has no import function");
|
|
479
515
|
}
|
|
480
516
|
const { pages: importedPages, nav } = await asciidocPlugin.import(sourceDir, {
|
|
481
|
-
attributes,
|
|
517
|
+
attributes: engineAttributes,
|
|
482
518
|
loader: options.loader,
|
|
483
519
|
});
|
|
484
520
|
if (importedPages.length === 0) {
|
|
@@ -503,12 +539,19 @@ export async function migrateAsciidoc(source, options) {
|
|
|
503
539
|
// Fall back to treeToDogsbayMd for importers that don't produce
|
|
504
540
|
// bodyMarkdown (e.g. mkdocs imports during a future
|
|
505
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();
|
|
506
548
|
for (const page of importedPages) {
|
|
507
549
|
const body = page.bodyMarkdown ?? treeToDogsbayMd(page.tree);
|
|
508
550
|
const dst = join(contentDir, `${page.slug}.md`);
|
|
509
551
|
mkdirSync(dirname(dst), { recursive: true });
|
|
510
552
|
const frontmatter = `---\ntitle: ${yamlQuote(page.title)}\n---\n\n`;
|
|
511
553
|
writeFileSync(dst, frontmatter + body);
|
|
554
|
+
pageWrittenPaths.add(dst);
|
|
512
555
|
}
|
|
513
556
|
console.log(pc.green(`Converted`) + ` ${importedPages.length} page(s) to ./content/`);
|
|
514
557
|
// 3b. Compute the scoped set of root-level dirs we'll walk for
|
|
@@ -531,7 +574,11 @@ export async function migrateAsciidoc(source, options) {
|
|
|
531
574
|
// skips routes for them via the generated config's
|
|
532
575
|
// excludeFromRoutes. Adding them to scope just lets the walkers
|
|
533
576
|
// descend; the route skip happens separately.
|
|
534
|
-
|
|
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"]) {
|
|
535
582
|
scopedRootDirs.add(d);
|
|
536
583
|
}
|
|
537
584
|
// 3c. Fragment .adoc files (everything not topic-listed but in
|
|
@@ -542,7 +589,7 @@ export async function migrateAsciidoc(source, options) {
|
|
|
542
589
|
// fragments. Fragment conversion is engine-only (no Minja,
|
|
543
590
|
// no markdown-it) so directives inside fragments survive
|
|
544
591
|
// verbatim and resolve in the parent page's context.
|
|
545
|
-
const frag = convertFragmentAdocs(sourceDir, contentDir, scopedRootDirs);
|
|
592
|
+
const frag = convertFragmentAdocs(sourceDir, contentDir, scopedRootDirs, pageWrittenPaths, engineImagesdir);
|
|
546
593
|
if (frag.converted > 0) {
|
|
547
594
|
console.log(pc.green(`Converted`) +
|
|
548
595
|
` ${frag.converted} fragment(s)` +
|
|
@@ -563,6 +610,24 @@ export async function migrateAsciidoc(source, options) {
|
|
|
563
610
|
parts.push(`${mirror.assets} asset(s)`);
|
|
564
611
|
console.log(pc.green(`Mirrored`) + ` ${parts.join(" + ")}`);
|
|
565
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
|
+
}
|
|
566
631
|
// 4. nav.yml — directly from the loader's NavItem[]. The loader
|
|
567
632
|
// decides the shape (directory-mirror for plain, per-title
|
|
568
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-mkdocs": "0.2.0-beta.
|
|
38
|
-
"@dogsbay/format-astro": "0.2.0-beta.
|
|
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/adoc2md-modular": "0.2.0-beta.
|
|
45
|
-
"@dogsbay/format-asciidoc": "0.2.0-beta.
|
|
46
|
-
"@dogsbay/minja": "0.2.0-beta.
|
|
47
|
-
"@dogsbay/types": "0.2.0-beta.
|
|
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",
|