@dogsbay/ssg 0.2.0-beta.141 → 0.2.0-beta.142
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/package/THIRD-PARTY-NOTICES.txt +5 -5
- package/dist/package/browser.mjs +317 -210
- package/dist/package/types/core/build.d.ts +15 -0
- package/dist/package/types/core/config.d.ts +8 -0
- package/dist/package/types/core/dev.d.ts +2 -0
- package/dist/package/types/core/openapi-pages.d.ts +31 -0
- package/dist/package/types/package/browser.d.ts +1 -0
- package/package.json +29 -29
|
@@ -1,31 +1,31 @@
|
|
|
1
1
|
Third-party software in @dogsbay/ssg (dist/package/)
|
|
2
2
|
|
|
3
3
|
========================================================================
|
|
4
|
-
@dogsbay/elements@0.2.0-beta.
|
|
4
|
+
@dogsbay/elements@0.2.0-beta.142 (MIT)
|
|
5
5
|
https://github.com/dogsbay/dogsbay.git
|
|
6
6
|
|
|
7
7
|
Licensed under MIT; the package ships no licence file.
|
|
8
8
|
|
|
9
9
|
========================================================================
|
|
10
|
-
@dogsbay/primitives@0.2.0-beta.
|
|
10
|
+
@dogsbay/primitives@0.2.0-beta.142 (MIT)
|
|
11
11
|
https://github.com/dogsbay/dogsbay.git
|
|
12
12
|
|
|
13
13
|
Licensed under MIT; the package ships no licence file.
|
|
14
14
|
|
|
15
15
|
========================================================================
|
|
16
|
-
@dogsbay/render-html@0.2.0-beta.
|
|
16
|
+
@dogsbay/render-html@0.2.0-beta.142 (MIT)
|
|
17
17
|
https://github.com/dogsbay/dogsbay.git
|
|
18
18
|
|
|
19
19
|
Licensed under MIT; the package ships no licence file.
|
|
20
20
|
|
|
21
21
|
========================================================================
|
|
22
|
-
@dogsbay/search@0.2.0-beta.
|
|
22
|
+
@dogsbay/search@0.2.0-beta.142 (MIT)
|
|
23
23
|
https://github.com/dogsbay/dogsbay.git
|
|
24
24
|
|
|
25
25
|
Licensed under MIT; the package ships no licence file.
|
|
26
26
|
|
|
27
27
|
========================================================================
|
|
28
|
-
@dogsbay/ui@0.2.0-beta.
|
|
28
|
+
@dogsbay/ui@0.2.0-beta.142 (MIT)
|
|
29
29
|
https://github.com/dogsbay/dogsbay.git
|
|
30
30
|
|
|
31
31
|
Licensed under MIT; the package ships no licence file.
|
package/dist/package/browser.mjs
CHANGED
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
|
|
19
19
|
// src/core/build.ts
|
|
20
20
|
import { dogsbayMdToTree, splitFrontmatter as splitFrontmatter2, treeToDogsbayMd } from "@dogsbay/format-dogsbay-md/browser";
|
|
21
|
-
import { buildHreflangLinks, missingTranslations, namespaceNavGroup, prefixSlug, rewriteContentRefs } from "@dogsbay/site-files";
|
|
21
|
+
import { buildHreflangLinks, isMountRoot, missingTranslations, mountRefs, mountRootNote, namespaceNavGroup, placeMountedNav, prefixSlug as prefixSlug2, rewriteContentRefs } from "@dogsbay/site-files";
|
|
22
22
|
|
|
23
23
|
// src/core/canonical.ts
|
|
24
24
|
import { decideCanonical } from "@dogsbay/site-files";
|
|
@@ -26,7 +26,7 @@ import { declaresParams, splitFrontmatter } from "@dogsbay/format-dogsbay-md/bro
|
|
|
26
26
|
|
|
27
27
|
// src/core/config.ts
|
|
28
28
|
import { scriptUrl } from "@dogsbay/render-html";
|
|
29
|
-
import { assertLeafSitemap, checkVersionSeo, isNamespaceAxisActive, namespaceSegments } from "@dogsbay/site-files";
|
|
29
|
+
import { assertLeafSitemap, checkVersionSeo, isNamespaceAxisActive, namespaceSegments, parseMount } from "@dogsbay/site-files";
|
|
30
30
|
|
|
31
31
|
// src/core/yaml.ts
|
|
32
32
|
import { load } from "js-yaml";
|
|
@@ -67,6 +67,14 @@ function unitId(kind, v) {
|
|
|
67
67
|
if (!/^[a-z0-9][a-z0-9._-]*$/i.test(id)) throw new ConfigError(`${kind}: id "${id.slice(0, 80)}" must be one URL segment of letters, digits, dots, dashes and underscores`);
|
|
68
68
|
return id;
|
|
69
69
|
}
|
|
70
|
+
function sourceMount(s) {
|
|
71
|
+
const at = `content.sources[${String(s.path)}]`;
|
|
72
|
+
if (s.from !== "openapi") throw new ConfigError(`${at}: mount is only for a "from: openapi" source`);
|
|
73
|
+
if (s.name != null) throw new ConfigError(`${at} has both name and mount: a mounted source goes inside its version, so it takes no name`);
|
|
74
|
+
const parsed = parseMount(s.mount);
|
|
75
|
+
if ("error" in parsed) throw new ConfigError(`${at}: ${parsed.error}`);
|
|
76
|
+
return parsed.segments.join("/");
|
|
77
|
+
}
|
|
70
78
|
function sourceFrom(v, path) {
|
|
71
79
|
if (v === "dogsbay-md" || v === "openapi") return v;
|
|
72
80
|
throw new ConfigError(`content.sources[${path}].from must be "dogsbay-md" or "openapi"; got ${JSON.stringify(v)}`);
|
|
@@ -139,6 +147,7 @@ function parseConfig(text, overrides = {}) {
|
|
|
139
147
|
path: sourcePath(s),
|
|
140
148
|
...s.name != null ? { name: sourceName(s.name) } : {},
|
|
141
149
|
...s.from != null ? { from: sourceFrom(s.from, String(s.path)) } : {},
|
|
150
|
+
...s.mount != null ? { mount: sourceMount(s) } : {},
|
|
142
151
|
version: s.version != null ? unitId("version", s.version) : void 0,
|
|
143
152
|
locale: s.locale != null ? unitId("locale", s.locale) : void 0,
|
|
144
153
|
attributes: s.attributes ?? void 0,
|
|
@@ -414,29 +423,41 @@ function buildUnits(cfg) {
|
|
|
414
423
|
throw new ConfigError(`source "${u.source.path}" has locale "${u.locale}" which is not declared in locales`);
|
|
415
424
|
}
|
|
416
425
|
}
|
|
417
|
-
const namespaces = isNamespaceAxisActive(cfg.sources);
|
|
426
|
+
const namespaces = isNamespaceAxisActive(cfg.sources.filter((s) => !s.mount));
|
|
418
427
|
if (namespaces && (versionAxis || localeAxis)) {
|
|
419
428
|
throw new ConfigError("named sources (content.sources name:) cannot be combined with versions or locales yet (plans/openapi-sources.md)");
|
|
420
429
|
}
|
|
421
430
|
for (const s of cfg.sources) {
|
|
422
|
-
if (s.from === "openapi" && cfg.sources.length > 1 && !s.name) throw new ConfigError(`content.sources[${s.path}]: an OpenAPI source beside other sources needs a name:, so its pages do not land on theirs`);
|
|
431
|
+
if (s.from === "openapi" && cfg.sources.length > 1 && !s.name && !s.mount) throw new ConfigError(`content.sources[${s.path}]: an OpenAPI source beside other sources needs a name: or a mount:, so its pages do not land on theirs`);
|
|
423
432
|
}
|
|
424
433
|
const units = /* @__PURE__ */ new Map();
|
|
425
434
|
for (const u of withDefaults2) {
|
|
426
435
|
const atRoot = cfg.versions.find((v) => v.id === u.version)?.path === "";
|
|
427
436
|
const prefix = [localeAxis ? u.locale : void 0, versionAxis && !atRoot ? u.version : void 0].filter(Boolean).join("/");
|
|
428
|
-
const member = { source: u.source, namespace: namespaceSegments(u.source, cfg.sources).join("/") };
|
|
437
|
+
const member = u.source.mount ? { source: u.source, namespace: "", mount: u.source.mount } : { source: u.source, namespace: namespaceSegments(u.source, cfg.sources).join("/") };
|
|
429
438
|
const unit = units.get(prefix);
|
|
430
439
|
if (!unit) {
|
|
431
440
|
units.set(prefix, { source: u.source, members: [member], version: versionAxis ? u.version : void 0, locale: localeAxis ? u.locale : void 0, prefix });
|
|
432
441
|
continue;
|
|
433
442
|
}
|
|
434
|
-
if (
|
|
435
|
-
|
|
436
|
-
throw new ConfigError(
|
|
443
|
+
if (member.mount) {
|
|
444
|
+
const taken = unit.members.find((m) => m.mount === member.mount);
|
|
445
|
+
if (taken) throw new ConfigError(`two sources are mounted at "${member.mount}" in the same version and locale (${taken.source.path}, ${u.source.path})`);
|
|
446
|
+
} else if (unit.members.some((m) => !m.mount)) {
|
|
447
|
+
if (!namespaces) throw new ConfigError(`two sources publish to the same prefix "${prefix || "/"}"`);
|
|
448
|
+
if (unit.members.some((m) => !m.mount && m.namespace === member.namespace)) {
|
|
449
|
+
throw new ConfigError(member.namespace ? `two sources are named "${member.namespace}"` : `two unnamed sources publish to the same prefix "${prefix || "/"}"`);
|
|
450
|
+
}
|
|
437
451
|
}
|
|
438
452
|
unit.members.push(member);
|
|
439
|
-
|
|
453
|
+
const main = unit.members.find((m) => m.source === unit.source);
|
|
454
|
+
if (!member.namespace && !member.mount && (main.namespace || main.mount)) unit.source = u.source;
|
|
455
|
+
}
|
|
456
|
+
for (const unit of units.values()) {
|
|
457
|
+
for (const m of unit.members) {
|
|
458
|
+
const ns = m.mount && unit.members.find((o) => o.namespace && m.mount.split("/")[0] === o.namespace);
|
|
459
|
+
if (ns) throw new ConfigError(`content.sources[${m.source.path}]: mount "${m.mount}" is inside the folder of the source named "${ns.namespace}"; mount it elsewhere`);
|
|
460
|
+
}
|
|
440
461
|
}
|
|
441
462
|
return [...units.values()];
|
|
442
463
|
}
|
|
@@ -454,8 +475,7 @@ function projectPath(unit, path) {
|
|
|
454
475
|
for (const m of unit.members) {
|
|
455
476
|
if (m.namespace && m.source.from !== "openapi" && (path === m.namespace || path.startsWith(m.namespace + "/"))) return sourceRoot(m.source) + path.slice(m.namespace.length + 1);
|
|
456
477
|
}
|
|
457
|
-
|
|
458
|
-
return sourceRoot(main.source) + path;
|
|
478
|
+
return sourceRoot(unit.source) + path;
|
|
459
479
|
}
|
|
460
480
|
var TOPIC_MAP = /\.topicmap\.ya?ml$/;
|
|
461
481
|
function sourceNav(v, path, from) {
|
|
@@ -559,6 +579,209 @@ function createResolver(table, page) {
|
|
|
559
579
|
};
|
|
560
580
|
}
|
|
561
581
|
|
|
582
|
+
// src/core/openapi-pages.ts
|
|
583
|
+
import { mountSlug, prefixSlug } from "@dogsbay/site-files";
|
|
584
|
+
|
|
585
|
+
// src/core/resolve.ts
|
|
586
|
+
import { inlineText } from "@dogsbay/render-html";
|
|
587
|
+
import { slugify } from "@dogsbay/render-html/html";
|
|
588
|
+
import { CORE_SCHEMA, load as loadYaml2 } from "js-yaml";
|
|
589
|
+
function hasPlaceholder(nodes, types) {
|
|
590
|
+
return (nodes ?? []).some((n) => types.has(n.type) || hasPlaceholder(n.children, types));
|
|
591
|
+
}
|
|
592
|
+
async function resolvePlaceholders(tree, resolvers, ctx) {
|
|
593
|
+
const byType = new Map(resolvers.map((r) => [r.type, r]));
|
|
594
|
+
if (!hasPlaceholder(tree, new Set(byType.keys()))) return void 0;
|
|
595
|
+
const usedIds = headingIds(tree);
|
|
596
|
+
const warnings = [];
|
|
597
|
+
const walk = async (nodes) => {
|
|
598
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
599
|
+
const r = byType.get(nodes[i].type);
|
|
600
|
+
if (!r) {
|
|
601
|
+
if (nodes[i].children) await walk(nodes[i].children);
|
|
602
|
+
continue;
|
|
603
|
+
}
|
|
604
|
+
let got;
|
|
605
|
+
try {
|
|
606
|
+
got = await r.resolve(nodes[i], { ...ctx, usedIds });
|
|
607
|
+
} catch (e) {
|
|
608
|
+
got = { warning: e.message || String(e) };
|
|
609
|
+
}
|
|
610
|
+
if ("warning" in got) {
|
|
611
|
+
warnings.push(got.warning);
|
|
612
|
+
nodes.splice(i, 1, ...nodes[i].children ?? []);
|
|
613
|
+
i--;
|
|
614
|
+
continue;
|
|
615
|
+
}
|
|
616
|
+
headingIds(got.nodes, usedIds);
|
|
617
|
+
nodes.splice(i, 1, ...got.nodes);
|
|
618
|
+
i += got.nodes.length - 1;
|
|
619
|
+
}
|
|
620
|
+
};
|
|
621
|
+
await walk(tree);
|
|
622
|
+
return warnings;
|
|
623
|
+
}
|
|
624
|
+
function headingIds(nodes, ids = /* @__PURE__ */ new Set()) {
|
|
625
|
+
const take = (raw) => {
|
|
626
|
+
const base = RESERVED_ID.test(raw) ? `h-${raw}` : raw;
|
|
627
|
+
let id = base || "section";
|
|
628
|
+
for (let n = 2; ids.has(id); n++) id = `${base}-${n}`;
|
|
629
|
+
ids.add(id);
|
|
630
|
+
};
|
|
631
|
+
const walk = (list) => {
|
|
632
|
+
for (const n of list) {
|
|
633
|
+
if (n.type === "heading") {
|
|
634
|
+
const p = n.props ?? {};
|
|
635
|
+
take(typeof p.id === "string" ? p.id : typeof p.slug === "string" ? p.slug : slugify(inlineText(n.inline)));
|
|
636
|
+
} else if ((n.type === "prose" || n.type === "html") && typeof n.html === "string") {
|
|
637
|
+
for (const m of n.html.matchAll(/<h[1-6]\b[^>]*\sid="([^"]*)"/gi)) take(m[1]);
|
|
638
|
+
}
|
|
639
|
+
if (n.children) walk(n.children);
|
|
640
|
+
}
|
|
641
|
+
};
|
|
642
|
+
walk(nodes);
|
|
643
|
+
return ids;
|
|
644
|
+
}
|
|
645
|
+
var RESERVED_ID = /^(db-|tab-\d|tabpanel-\d|acc-\d|accpanel-\d|fn-|fnref-)/;
|
|
646
|
+
var autodocUnresolved = {
|
|
647
|
+
type: "autodoc-ref",
|
|
648
|
+
async resolve(node) {
|
|
649
|
+
const ref = typeof node.props?.ref === "string" ? node.props.ref : "";
|
|
650
|
+
return { warning: `:::autodoc${ref ? `{ref="${ref}"}` : ""} is not resolved in this build: resolve it at migration time (dogsbay migrate-mkdocs --inline-autodoc)` };
|
|
651
|
+
}
|
|
652
|
+
};
|
|
653
|
+
var coreLoad;
|
|
654
|
+
var loadCore = () => coreLoad ??= import("@dogsbay/format-openapi/core");
|
|
655
|
+
function openApiResolver(read, maxChars = 8e6) {
|
|
656
|
+
let specs;
|
|
657
|
+
return {
|
|
658
|
+
type: "openapi-ref",
|
|
659
|
+
async resolve(node, ctx) {
|
|
660
|
+
const spec = typeof node.props?.spec === "string" ? node.props.spec : "";
|
|
661
|
+
const core = await loadCore();
|
|
662
|
+
const selected = core.directiveOperation(node.props);
|
|
663
|
+
if ("error" in selected) return { warning: `:::openapi: ${selected.error}` };
|
|
664
|
+
const slug = ctx.source.replace(/\.(md|markdown)$/i, "").replace(/(^|\/)index$/, "");
|
|
665
|
+
const found = core.findSpec(spec, slug, (p) => {
|
|
666
|
+
const at = ctx.scope ? ctx.scope(p) : p;
|
|
667
|
+
return ctx.has(at) ? { path: at } : void 0;
|
|
668
|
+
});
|
|
669
|
+
if ("error" in found) return { warning: `:::openapi: ${found.error}` };
|
|
670
|
+
specs ??= core.createSpecCache(async (p) => {
|
|
671
|
+
const text = await read(p);
|
|
672
|
+
if (text === void 0) throw new Error("not found");
|
|
673
|
+
return text;
|
|
674
|
+
}, (text) => loadYaml2(text, { schema: CORE_SCHEMA }));
|
|
675
|
+
let prepared;
|
|
676
|
+
try {
|
|
677
|
+
prepared = await specs.get(found.path);
|
|
678
|
+
} catch (e) {
|
|
679
|
+
return { warning: `:::openapi: cannot read ${spec}: ${e.message}` };
|
|
680
|
+
}
|
|
681
|
+
let tree;
|
|
682
|
+
try {
|
|
683
|
+
tree = core.embedSpec(prepared, { usedIds: ctx.usedIds, operation: selected.operation }).tree;
|
|
684
|
+
} catch (e) {
|
|
685
|
+
return { warning: `:::openapi: cannot use ${spec}: ${e.message}` };
|
|
686
|
+
}
|
|
687
|
+
const size = boundedSize(tree, maxChars);
|
|
688
|
+
if (size === "cycle") return { warning: `:::openapi: ${spec} has a cyclic example or schema, which cannot be shown` };
|
|
689
|
+
if (size === "over") return { warning: `:::openapi: ${spec} is too large to embed in one page (over ${Math.round(maxChars / 1e6)}M characters)` };
|
|
690
|
+
return { nodes: tree };
|
|
691
|
+
}
|
|
692
|
+
};
|
|
693
|
+
}
|
|
694
|
+
async function openApiSourcePages(read, specPath, reservedSlugs) {
|
|
695
|
+
const core = await loadCore();
|
|
696
|
+
const specs = core.createSpecCache(async (p) => {
|
|
697
|
+
const text = await read(p);
|
|
698
|
+
if (text === void 0) throw new Error("not found");
|
|
699
|
+
return text;
|
|
700
|
+
}, (text) => loadYaml2(text, { schema: CORE_SCHEMA }));
|
|
701
|
+
try {
|
|
702
|
+
return core.specToPages(await specs.get(specPath), { reservedSlugs });
|
|
703
|
+
} catch (e) {
|
|
704
|
+
return { error: `cannot read ${specPath}: ${e.message}` };
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
async function specFileOf(path, has, read) {
|
|
708
|
+
const p = path.replace(/^\.\//, "").replace(/\/+$/, "");
|
|
709
|
+
if (/\.(ya?ml|json)$/i.test(p)) return has(p) ? p : void 0;
|
|
710
|
+
const dir = p === "." || p === "" ? "" : p + "/";
|
|
711
|
+
const found = ["openapi", "swagger", "spec"].flatMap((b) => ["yaml", "yml", "json"].map((e) => `${dir}${b}.${e}`)).filter(has);
|
|
712
|
+
for (const f of found) {
|
|
713
|
+
const head = (await read(f))?.slice(0, 2048) ?? "";
|
|
714
|
+
if (/(?:^|[{,])\s*"?(openapi|swagger)"?\s*[:=]/m.test(head)) return f;
|
|
715
|
+
}
|
|
716
|
+
return found[0];
|
|
717
|
+
}
|
|
718
|
+
function boundedSize(value, max) {
|
|
719
|
+
let total = 0;
|
|
720
|
+
const path = /* @__PURE__ */ new Set();
|
|
721
|
+
const walk = (v) => {
|
|
722
|
+
if (typeof v === "string") total += v.length;
|
|
723
|
+
else if (v && typeof v === "object") {
|
|
724
|
+
if (path.has(v)) return "cycle";
|
|
725
|
+
path.add(v);
|
|
726
|
+
total += 2;
|
|
727
|
+
for (const x of Array.isArray(v) ? v : Object.values(v)) {
|
|
728
|
+
const r = walk(x);
|
|
729
|
+
if (r) return r;
|
|
730
|
+
if (total > max) return "over";
|
|
731
|
+
}
|
|
732
|
+
path.delete(v);
|
|
733
|
+
} else total += 4;
|
|
734
|
+
return total > max ? "over" : void 0;
|
|
735
|
+
};
|
|
736
|
+
return walk(value) ?? total;
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
// src/core/openapi-pages.ts
|
|
740
|
+
function urlPathOf(url) {
|
|
741
|
+
if (!url) return [];
|
|
742
|
+
try {
|
|
743
|
+
return new URL(url).pathname.split("/").filter(Boolean);
|
|
744
|
+
} catch {
|
|
745
|
+
return [];
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
async function placeApiPages(cfg, unit, m, files, readText2) {
|
|
749
|
+
const read = async (p) => {
|
|
750
|
+
const c = files.get(p);
|
|
751
|
+
return c == null ? void 0 : readText2(c);
|
|
752
|
+
};
|
|
753
|
+
const spec = await specFileOf(m.source.path, (p) => files.has(p), read);
|
|
754
|
+
if (!spec) return { missing: true };
|
|
755
|
+
const ns = m.namespace;
|
|
756
|
+
const mount = m.mount?.split("/");
|
|
757
|
+
const segs = mount ?? (ns ? [ns] : []);
|
|
758
|
+
const first = ns || unit.prefix.split("/")[0];
|
|
759
|
+
const combined = [...urlPathOf(cfg.url), ...cfg.basePath.split("/").filter(Boolean)];
|
|
760
|
+
const taxonomies = new Set(cfg.taxonomies.map((t) => t.path.split("/")[0]).filter(Boolean));
|
|
761
|
+
const got = await openApiSourcePages(read, spec, [...first ? [first] : [], ...combined.slice(0, 1), ...taxonomies]);
|
|
762
|
+
if ("error" in got) return { spec, error: got.error };
|
|
763
|
+
const pages = got.pages.map((page) => {
|
|
764
|
+
const slug = mount ? mountSlug(mount, page.slug) : prefixSlug(segs, page.slug === "index" ? "" : page.slug);
|
|
765
|
+
const isIndex = page.slug === "index" || got.pages.some((q) => q.slug.startsWith(page.slug + "/"));
|
|
766
|
+
return { slug, out: outFileFor(slug, isIndex && slug !== ""), isIndex, page };
|
|
767
|
+
});
|
|
768
|
+
return { spec, pages, nav: got.nav, segs };
|
|
769
|
+
}
|
|
770
|
+
var outsCache = /* @__PURE__ */ new WeakMap();
|
|
771
|
+
async function apiPageOuts(cfg, unit, m, files, readText2) {
|
|
772
|
+
let cache = outsCache.get(files);
|
|
773
|
+
if (!cache) outsCache.set(files, cache = /* @__PURE__ */ new Map());
|
|
774
|
+
const id = `${unit.prefix}\0${m.source.path}`;
|
|
775
|
+
const key = JSON.stringify([m.namespace, m.mount, cfg.url, cfg.basePath, cfg.taxonomies.map((t) => t.path)]);
|
|
776
|
+
const hit = cache.get(id);
|
|
777
|
+
const specFile = /\.(ya?ml|json)$/i.test(m.source.path) ? files.get(m.source.path.replace(/^\.\//, "")) : void 0;
|
|
778
|
+
if (hit && hit.key === key && specFile !== void 0 && hit.spec === specFile) return hit.outs;
|
|
779
|
+
const placed = await placeApiPages(cfg, unit, m, files, readText2);
|
|
780
|
+
const outs = "pages" in placed ? placed.pages.map((p) => [p.slug, p.out]) : [];
|
|
781
|
+
cache.set(id, { spec: specFile, key, outs });
|
|
782
|
+
return outs;
|
|
783
|
+
}
|
|
784
|
+
|
|
562
785
|
// src/core/nav.ts
|
|
563
786
|
import { scriptUrl as scriptUrl2 } from "@dogsbay/render-html";
|
|
564
787
|
function slugFromPath(p) {
|
|
@@ -851,7 +1074,7 @@ async function defaultTables(cfg, units, built, files, read, warn = () => {
|
|
|
851
1074
|
const tables = /* @__PURE__ */ new Map();
|
|
852
1075
|
if (!cfg.defaultVersion || !built.some((u) => u.version && u.version !== cfg.defaultVersion)) return tables;
|
|
853
1076
|
for (const unit of units.filter((u) => u.version === cfg.defaultVersion)) {
|
|
854
|
-
const t = await scan(cfg, unit, units, files, fm ?? frontMatterCache(read));
|
|
1077
|
+
const t = await scan(cfg, unit, units, files, fm ?? frontMatterCache(read), read);
|
|
855
1078
|
if (!t.pages.size && built.some((u) => u.version !== cfg.defaultVersion && u.locale === unit.locale)) {
|
|
856
1079
|
warn(`[canonical] the default version "${cfg.defaultVersion}" has no pages under ${unit.source.path}, so older versions' pages keep themselves as canonical`);
|
|
857
1080
|
}
|
|
@@ -864,17 +1087,17 @@ async function languageTables(cfg, units, built, files, read, fm) {
|
|
|
864
1087
|
if (new Set(units.map((u) => u.locale).filter(Boolean)).size < 2) return tables;
|
|
865
1088
|
const versions = new Set(built.map((u) => u.version));
|
|
866
1089
|
const fmOf = fm ?? frontMatterCache(read);
|
|
867
|
-
for (const unit of units) if (versions.has(unit.version)) tables.set(unit.prefix, (await scan(cfg, unit, units, files, fmOf)).pages);
|
|
1090
|
+
for (const unit of units) if (versions.has(unit.version)) tables.set(unit.prefix, (await scan(cfg, unit, units, files, fmOf, read)).pages);
|
|
868
1091
|
return tables;
|
|
869
1092
|
}
|
|
870
1093
|
async function translationTables(cfg, units, files, read, includeDrafts, fm) {
|
|
871
1094
|
const tables = /* @__PURE__ */ new Map();
|
|
872
1095
|
if (new Set(units.map((u) => u.locale).filter(Boolean)).size < 2) return tables;
|
|
873
1096
|
const fmOf = fm ?? frontMatterCache(read);
|
|
874
|
-
for (const unit of units) tables.set(unit.prefix, await scan(cfg, unit, units, files, fmOf, { kind: "built", includeDrafts }));
|
|
1097
|
+
for (const unit of units) tables.set(unit.prefix, await scan(cfg, unit, units, files, fmOf, read, { kind: "built", includeDrafts }));
|
|
875
1098
|
return tables;
|
|
876
1099
|
}
|
|
877
|
-
async function scan(cfg, unit, units, files, frontMatterOf, mode = { kind: "targets" }) {
|
|
1100
|
+
async function scan(cfg, unit, units, files, frontMatterOf, read, mode = { kind: "targets" }) {
|
|
878
1101
|
const rootOf = (u) => u.source.path === "." ? "" : u.source.path.replace(/^\.\//, "").replace(/\/+$/, "") + "/";
|
|
879
1102
|
const root = rootOf(unit);
|
|
880
1103
|
const otherRoots = units.filter((u) => u !== unit).map(rootOf).filter((r) => r && r.startsWith(root));
|
|
@@ -912,6 +1135,10 @@ async function scan(cfg, unit, units, files, frontMatterOf, mode = { kind: "targ
|
|
|
912
1135
|
for (const a of fm.aliases) if (typeof a === "string" && inUnit(a) !== void 0) setFirst(inUnit(a), detach(key(slug)));
|
|
913
1136
|
}
|
|
914
1137
|
}
|
|
1138
|
+
for (const m of unit.members) {
|
|
1139
|
+
if (m.source.from !== "openapi") continue;
|
|
1140
|
+
for (const [slug, out] of await apiPageOuts(cfg, unit, m, files, read)) if (!pages.has(key(slug))) pages.set(detach(key(slug)), out);
|
|
1141
|
+
}
|
|
915
1142
|
for (const r of cfg.redirects) {
|
|
916
1143
|
const from = sitePath(r.from, cfg.basePath);
|
|
917
1144
|
if (!mine(from)) continue;
|
|
@@ -1085,31 +1312,31 @@ var CLIENT_CANDIDATES = ['""', '"&"', '"\\\\$&")).join("|")})', '"\\\\$&")}"', '
|
|
|
1085
1312
|
var SITE_NOTICES = `Third-party software in this site's _dogsbay/ files (dogsbay.js, site.css) and pages
|
|
1086
1313
|
|
|
1087
1314
|
========================================================================
|
|
1088
|
-
@dogsbay/elements@0.2.0-beta.
|
|
1315
|
+
@dogsbay/elements@0.2.0-beta.142 (MIT)
|
|
1089
1316
|
https://github.com/dogsbay/dogsbay.git
|
|
1090
1317
|
|
|
1091
1318
|
Licensed under MIT; the package ships no licence file.
|
|
1092
1319
|
|
|
1093
1320
|
========================================================================
|
|
1094
|
-
@dogsbay/primitives@0.2.0-beta.
|
|
1321
|
+
@dogsbay/primitives@0.2.0-beta.142 (MIT)
|
|
1095
1322
|
https://github.com/dogsbay/dogsbay.git
|
|
1096
1323
|
|
|
1097
1324
|
Licensed under MIT; the package ships no licence file.
|
|
1098
1325
|
|
|
1099
1326
|
========================================================================
|
|
1100
|
-
@dogsbay/render-html@0.2.0-beta.
|
|
1327
|
+
@dogsbay/render-html@0.2.0-beta.142 (MIT)
|
|
1101
1328
|
https://github.com/dogsbay/dogsbay.git
|
|
1102
1329
|
|
|
1103
1330
|
Licensed under MIT; the package ships no licence file.
|
|
1104
1331
|
|
|
1105
1332
|
========================================================================
|
|
1106
|
-
@dogsbay/search@0.2.0-beta.
|
|
1333
|
+
@dogsbay/search@0.2.0-beta.142 (MIT)
|
|
1107
1334
|
https://github.com/dogsbay/dogsbay.git
|
|
1108
1335
|
|
|
1109
1336
|
Licensed under MIT; the package ships no licence file.
|
|
1110
1337
|
|
|
1111
1338
|
========================================================================
|
|
1112
|
-
@dogsbay/ui@0.2.0-beta.
|
|
1339
|
+
@dogsbay/ui@0.2.0-beta.142 (MIT)
|
|
1113
1340
|
https://github.com/dogsbay/dogsbay.git
|
|
1114
1341
|
|
|
1115
1342
|
Licensed under MIT; the package ships no licence file.
|
|
@@ -1560,160 +1787,6 @@ import { FAVICON_SVG } from "@dogsbay/render-html/favicon";
|
|
|
1560
1787
|
import { codeRequest, createRenderContext, highlightInputs, inlineText as inlineText2, renderBlocks, scriptUrl as scriptUrl3 } from "@dogsbay/render-html";
|
|
1561
1788
|
import { apiPageLayout } from "@dogsbay/serialize-core";
|
|
1562
1789
|
|
|
1563
|
-
// src/core/resolve.ts
|
|
1564
|
-
import { inlineText } from "@dogsbay/render-html";
|
|
1565
|
-
import { slugify } from "@dogsbay/render-html/html";
|
|
1566
|
-
import { CORE_SCHEMA, load as loadYaml2 } from "js-yaml";
|
|
1567
|
-
function hasPlaceholder(nodes, types) {
|
|
1568
|
-
return (nodes ?? []).some((n) => types.has(n.type) || hasPlaceholder(n.children, types));
|
|
1569
|
-
}
|
|
1570
|
-
async function resolvePlaceholders(tree, resolvers, ctx) {
|
|
1571
|
-
const byType = new Map(resolvers.map((r) => [r.type, r]));
|
|
1572
|
-
if (!hasPlaceholder(tree, new Set(byType.keys()))) return void 0;
|
|
1573
|
-
const usedIds = headingIds(tree);
|
|
1574
|
-
const warnings = [];
|
|
1575
|
-
const walk = async (nodes) => {
|
|
1576
|
-
for (let i = 0; i < nodes.length; i++) {
|
|
1577
|
-
const r = byType.get(nodes[i].type);
|
|
1578
|
-
if (!r) {
|
|
1579
|
-
if (nodes[i].children) await walk(nodes[i].children);
|
|
1580
|
-
continue;
|
|
1581
|
-
}
|
|
1582
|
-
let got;
|
|
1583
|
-
try {
|
|
1584
|
-
got = await r.resolve(nodes[i], { ...ctx, usedIds });
|
|
1585
|
-
} catch (e) {
|
|
1586
|
-
got = { warning: e.message || String(e) };
|
|
1587
|
-
}
|
|
1588
|
-
if ("warning" in got) {
|
|
1589
|
-
warnings.push(got.warning);
|
|
1590
|
-
nodes.splice(i, 1, ...nodes[i].children ?? []);
|
|
1591
|
-
i--;
|
|
1592
|
-
continue;
|
|
1593
|
-
}
|
|
1594
|
-
headingIds(got.nodes, usedIds);
|
|
1595
|
-
nodes.splice(i, 1, ...got.nodes);
|
|
1596
|
-
i += got.nodes.length - 1;
|
|
1597
|
-
}
|
|
1598
|
-
};
|
|
1599
|
-
await walk(tree);
|
|
1600
|
-
return warnings;
|
|
1601
|
-
}
|
|
1602
|
-
function headingIds(nodes, ids = /* @__PURE__ */ new Set()) {
|
|
1603
|
-
const take = (raw) => {
|
|
1604
|
-
const base = RESERVED_ID.test(raw) ? `h-${raw}` : raw;
|
|
1605
|
-
let id = base || "section";
|
|
1606
|
-
for (let n = 2; ids.has(id); n++) id = `${base}-${n}`;
|
|
1607
|
-
ids.add(id);
|
|
1608
|
-
};
|
|
1609
|
-
const walk = (list) => {
|
|
1610
|
-
for (const n of list) {
|
|
1611
|
-
if (n.type === "heading") {
|
|
1612
|
-
const p = n.props ?? {};
|
|
1613
|
-
take(typeof p.id === "string" ? p.id : typeof p.slug === "string" ? p.slug : slugify(inlineText(n.inline)));
|
|
1614
|
-
} else if ((n.type === "prose" || n.type === "html") && typeof n.html === "string") {
|
|
1615
|
-
for (const m of n.html.matchAll(/<h[1-6]\b[^>]*\sid="([^"]*)"/gi)) take(m[1]);
|
|
1616
|
-
}
|
|
1617
|
-
if (n.children) walk(n.children);
|
|
1618
|
-
}
|
|
1619
|
-
};
|
|
1620
|
-
walk(nodes);
|
|
1621
|
-
return ids;
|
|
1622
|
-
}
|
|
1623
|
-
var RESERVED_ID = /^(db-|tab-\d|tabpanel-\d|acc-\d|accpanel-\d|fn-|fnref-)/;
|
|
1624
|
-
var autodocUnresolved = {
|
|
1625
|
-
type: "autodoc-ref",
|
|
1626
|
-
async resolve(node) {
|
|
1627
|
-
const ref = typeof node.props?.ref === "string" ? node.props.ref : "";
|
|
1628
|
-
return { warning: `:::autodoc${ref ? `{ref="${ref}"}` : ""} is not resolved in this build: resolve it at migration time (dogsbay migrate-mkdocs --inline-autodoc)` };
|
|
1629
|
-
}
|
|
1630
|
-
};
|
|
1631
|
-
var coreLoad;
|
|
1632
|
-
var loadCore = () => coreLoad ??= import("@dogsbay/format-openapi/core");
|
|
1633
|
-
function openApiResolver(read, maxChars = 8e6) {
|
|
1634
|
-
let specs;
|
|
1635
|
-
return {
|
|
1636
|
-
type: "openapi-ref",
|
|
1637
|
-
async resolve(node, ctx) {
|
|
1638
|
-
const spec = typeof node.props?.spec === "string" ? node.props.spec : "";
|
|
1639
|
-
const core = await loadCore();
|
|
1640
|
-
const selected = core.directiveOperation(node.props);
|
|
1641
|
-
if ("error" in selected) return { warning: `:::openapi: ${selected.error}` };
|
|
1642
|
-
const slug = ctx.source.replace(/\.(md|markdown)$/i, "").replace(/(^|\/)index$/, "");
|
|
1643
|
-
const found = core.findSpec(spec, slug, (p) => {
|
|
1644
|
-
const at = ctx.scope ? ctx.scope(p) : p;
|
|
1645
|
-
return ctx.has(at) ? { path: at } : void 0;
|
|
1646
|
-
});
|
|
1647
|
-
if ("error" in found) return { warning: `:::openapi: ${found.error}` };
|
|
1648
|
-
specs ??= core.createSpecCache(async (p) => {
|
|
1649
|
-
const text = await read(p);
|
|
1650
|
-
if (text === void 0) throw new Error("not found");
|
|
1651
|
-
return text;
|
|
1652
|
-
}, (text) => loadYaml2(text, { schema: CORE_SCHEMA }));
|
|
1653
|
-
let prepared;
|
|
1654
|
-
try {
|
|
1655
|
-
prepared = await specs.get(found.path);
|
|
1656
|
-
} catch (e) {
|
|
1657
|
-
return { warning: `:::openapi: cannot read ${spec}: ${e.message}` };
|
|
1658
|
-
}
|
|
1659
|
-
let tree;
|
|
1660
|
-
try {
|
|
1661
|
-
tree = core.embedSpec(prepared, { usedIds: ctx.usedIds, operation: selected.operation }).tree;
|
|
1662
|
-
} catch (e) {
|
|
1663
|
-
return { warning: `:::openapi: cannot use ${spec}: ${e.message}` };
|
|
1664
|
-
}
|
|
1665
|
-
const size = boundedSize(tree, maxChars);
|
|
1666
|
-
if (size === "cycle") return { warning: `:::openapi: ${spec} has a cyclic example or schema, which cannot be shown` };
|
|
1667
|
-
if (size === "over") return { warning: `:::openapi: ${spec} is too large to embed in one page (over ${Math.round(maxChars / 1e6)}M characters)` };
|
|
1668
|
-
return { nodes: tree };
|
|
1669
|
-
}
|
|
1670
|
-
};
|
|
1671
|
-
}
|
|
1672
|
-
async function openApiSourcePages(read, specPath, reservedSlugs) {
|
|
1673
|
-
const core = await loadCore();
|
|
1674
|
-
const specs = core.createSpecCache(async (p) => {
|
|
1675
|
-
const text = await read(p);
|
|
1676
|
-
if (text === void 0) throw new Error("not found");
|
|
1677
|
-
return text;
|
|
1678
|
-
}, (text) => loadYaml2(text, { schema: CORE_SCHEMA }));
|
|
1679
|
-
try {
|
|
1680
|
-
return core.specToPages(await specs.get(specPath), { reservedSlugs });
|
|
1681
|
-
} catch (e) {
|
|
1682
|
-
return { error: `cannot read ${specPath}: ${e.message}` };
|
|
1683
|
-
}
|
|
1684
|
-
}
|
|
1685
|
-
async function specFileOf(path, has, read) {
|
|
1686
|
-
const p = path.replace(/^\.\//, "").replace(/\/+$/, "");
|
|
1687
|
-
if (/\.(ya?ml|json)$/i.test(p)) return has(p) ? p : void 0;
|
|
1688
|
-
const dir = p === "." || p === "" ? "" : p + "/";
|
|
1689
|
-
const found = ["openapi", "swagger", "spec"].flatMap((b) => ["yaml", "yml", "json"].map((e) => `${dir}${b}.${e}`)).filter(has);
|
|
1690
|
-
for (const f of found) {
|
|
1691
|
-
const head = (await read(f))?.slice(0, 2048) ?? "";
|
|
1692
|
-
if (/(?:^|[{,])\s*"?(openapi|swagger)"?\s*[:=]/m.test(head)) return f;
|
|
1693
|
-
}
|
|
1694
|
-
return found[0];
|
|
1695
|
-
}
|
|
1696
|
-
function boundedSize(value, max) {
|
|
1697
|
-
let total = 0;
|
|
1698
|
-
const path = /* @__PURE__ */ new Set();
|
|
1699
|
-
const walk = (v) => {
|
|
1700
|
-
if (typeof v === "string") total += v.length;
|
|
1701
|
-
else if (v && typeof v === "object") {
|
|
1702
|
-
if (path.has(v)) return "cycle";
|
|
1703
|
-
path.add(v);
|
|
1704
|
-
total += 2;
|
|
1705
|
-
for (const x of Array.isArray(v) ? v : Object.values(v)) {
|
|
1706
|
-
const r = walk(x);
|
|
1707
|
-
if (r) return r;
|
|
1708
|
-
if (total > max) return "over";
|
|
1709
|
-
}
|
|
1710
|
-
path.delete(v);
|
|
1711
|
-
} else total += 4;
|
|
1712
|
-
return total > max ? "over" : void 0;
|
|
1713
|
-
};
|
|
1714
|
-
return walk(value) ?? total;
|
|
1715
|
-
}
|
|
1716
|
-
|
|
1717
1790
|
// src/theme/regions.ts
|
|
1718
1791
|
import { attrs, esc } from "@dogsbay/render-html/html";
|
|
1719
1792
|
var svg = (body, cls, size = 16, extra = "") => `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="${cls}" aria-hidden="true" focusable="false"${extra}>${body}</svg>`;
|
|
@@ -3134,7 +3207,7 @@ async function build(input, hooks = {}) {
|
|
|
3134
3207
|
phase.init = now() - t0;
|
|
3135
3208
|
let pages = 0;
|
|
3136
3209
|
let assets = 0;
|
|
3137
|
-
const state = { redirects: [], navCache: navCache(), written: /* @__PURE__ */ new Set(), stubs: [], pageOut: /* @__PURE__ */ new Map(), sitemaps: /* @__PURE__ */ new Map(), supplied: /* @__PURE__ */ new Set(), usedMath: false, diagrams: diagramStore(input, cfg), scan: hooks.keep || hooks.lazy ? new ScanCache() : void 0, parseCache: input.parseCacheBytes === 0 ? false : new ParseCache(input.parseCacheBytes ?? DEFAULT_PARSE_CACHE_BYTES), templateBudget: templateBudget(input.untrusted === true, input.templateMs), dataCache: new DataCache(input.dataCacheBytes ?? DEFAULT_DATA_CACHE_BYTES) };
|
|
3210
|
+
const state = { redirects: [], notes: /* @__PURE__ */ new Map(), navCache: navCache(), written: /* @__PURE__ */ new Set(), stubs: [], pageOut: /* @__PURE__ */ new Map(), sitemaps: /* @__PURE__ */ new Map(), supplied: /* @__PURE__ */ new Set(), usedMath: false, diagrams: diagramStore(input, cfg), scan: hooks.keep || hooks.lazy ? new ScanCache() : void 0, parseCache: input.parseCacheBytes === 0 ? false : new ParseCache(input.parseCacheBytes ?? DEFAULT_PARSE_CACHE_BYTES), templateBudget: templateBudget(input.untrusted === true, input.templateMs), dataCache: new DataCache(input.dataCacheBytes ?? DEFAULT_DATA_CACHE_BYTES) };
|
|
3138
3211
|
for (const r of cfg.redirects) {
|
|
3139
3212
|
const from = sitePath(r.from, cfg.basePath);
|
|
3140
3213
|
if (!from) {
|
|
@@ -3211,6 +3284,7 @@ async function build(input, hooks = {}) {
|
|
|
3211
3284
|
files: out,
|
|
3212
3285
|
warnings,
|
|
3213
3286
|
problems,
|
|
3287
|
+
notes: [...state.notes.values()].flat(),
|
|
3214
3288
|
config: cfg,
|
|
3215
3289
|
stats: { pages, assets, units: units.length, ms: Math.round(now() - t0), msByPhase: roundAll(phase), highlightCache: highlighter.cacheStats(), ...state.parseCache ? { parseCache: state.parseCache.stats() } : {} }
|
|
3216
3290
|
};
|
|
@@ -3523,7 +3597,7 @@ ${marker}${title}${marker}`, path, attributesOf(path), includesFor(path, read2),
|
|
|
3523
3597
|
if (templatesOf(p).isPartial(fm, p)) continue;
|
|
3524
3598
|
const inUnit = (s) => unit.prefix && (s === unit.prefix || s.startsWith(unit.prefix + "/")) ? s : [unit.prefix, s].filter(Boolean).join("/");
|
|
3525
3599
|
const pageNs = named.length ? namespaceOf(p) : "";
|
|
3526
|
-
const inScope = (s) => inUnit(pageNs && !(s === pageNs || s.startsWith(pageNs + "/")) ?
|
|
3600
|
+
const inScope = (s) => inUnit(pageNs && !(s === pageNs || s.startsWith(pageNs + "/")) ? prefixSlug2([pageNs], s) : s);
|
|
3527
3601
|
const target = (raw) => isExternal(raw) ? raw : inScope(sitePath(raw, cfg.basePath));
|
|
3528
3602
|
const isIndexFile = /(^|\/)index\.(md|markdown)$/i.test(p) && slug !== "";
|
|
3529
3603
|
if (typeof fm.redirect === "string" && fm.redirect.trim()) {
|
|
@@ -3595,36 +3669,48 @@ ${marker}${title}${marker}`, path, attributesOf(path), includesFor(path, read2),
|
|
|
3595
3669
|
if (activeFiles.length) warn("html", `content.html is sanitize, so ${activeFiles.length} HTML, XML or script file(s) are not copied: ${some(activeFiles)}`);
|
|
3596
3670
|
if (untrustedFiles.length) report("untrusted", `[untrusted] ${untrustedFiles.length} file(s) not copied: only images, fonts, media, stylesheets, documents and data are, and no SVG that runs script or host configuration (_headers, _redirects): ${some(untrustedFiles)}`);
|
|
3597
3671
|
const specNavs = /* @__PURE__ */ new Map();
|
|
3598
|
-
const
|
|
3672
|
+
const mountedNavs = /* @__PURE__ */ new Map();
|
|
3673
|
+
const mountedSlugs = /* @__PURE__ */ new Set();
|
|
3674
|
+
const notes = [];
|
|
3675
|
+
state.notes.set(unit.prefix, notes);
|
|
3599
3676
|
for (const m of unit.members) {
|
|
3600
3677
|
if (m.source.from !== "openapi") continue;
|
|
3601
|
-
const
|
|
3602
|
-
|
|
3603
|
-
return c == null ? void 0 : readText(c);
|
|
3604
|
-
};
|
|
3605
|
-
const spec = await specFileOf(m.source.path, (p) => input.files.has(p), readProject);
|
|
3606
|
-
if (!spec) {
|
|
3678
|
+
const placed = await placeApiPages(cfg, unit, m, input.files, readText);
|
|
3679
|
+
if ("missing" in placed) {
|
|
3607
3680
|
warn("openapi", `${m.source.path}: no OpenAPI spec there (a .yaml, .yml or .json file, or a folder holding openapi.*, swagger.* or spec.*)`);
|
|
3608
3681
|
continue;
|
|
3609
3682
|
}
|
|
3610
|
-
const
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
const got = await openApiSourcePages(readProject, spec, reserved);
|
|
3614
|
-
if ("error" in got) {
|
|
3615
|
-
warnFile("openapi", m.source.path, spec, got.error);
|
|
3683
|
+
const spec = placed.spec;
|
|
3684
|
+
if ("error" in placed) {
|
|
3685
|
+
warnFile("openapi", m.source.path, spec, placed.error);
|
|
3616
3686
|
continue;
|
|
3617
3687
|
}
|
|
3688
|
+
const ns = m.namespace;
|
|
3689
|
+
const mount = m.mount?.split("/");
|
|
3690
|
+
const segs = placed.segs;
|
|
3618
3691
|
const limit = input.openApiChars ?? 8e6;
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3692
|
+
const own = new Set(placed.pages.map((p) => p.page.slug));
|
|
3693
|
+
let label2 = placed.pages.find((p) => isMountRoot(p.page.slug))?.page.title ?? m.mount ?? "";
|
|
3694
|
+
for (const { slug, out, isIndex, page } of placed.pages) {
|
|
3695
|
+
if (mount) {
|
|
3696
|
+
const there = infos.get(slug);
|
|
3697
|
+
if (there && isMountRoot(page.slug) && !there.virtual) {
|
|
3698
|
+
notes.push(mountRootNote(m.mount, prefixSlug2(unit.prefix ? unit.prefix.split("/") : [], slug)));
|
|
3699
|
+
label2 = there.title;
|
|
3700
|
+
continue;
|
|
3701
|
+
}
|
|
3702
|
+
if (there) throw mountClash(slug, m.mount, srcOf(there), there.virtual ? `a page of ${srcOf(there)}` : `another page (${srcOf(there)})`);
|
|
3703
|
+
mountRefs(page.tree, mount, own);
|
|
3704
|
+
mountedSlugs.add(slug);
|
|
3705
|
+
} else if (mountedSlugs.has(slug)) {
|
|
3706
|
+
const by = unit.members.find((o) => o.mount && (slug === o.mount || slug.startsWith(o.mount + "/")))?.mount ?? "";
|
|
3707
|
+
throw mountClash(slug, by, spec, `a page of ${spec}`);
|
|
3708
|
+
} else if (infos.has(slug)) {
|
|
3622
3709
|
warn("duplicate-page", `two sources map to the page "${slug || "/"}"; keeping ${srcOf(infos.get(slug))}, ignoring ${spec}'s`, { file: spec });
|
|
3623
3710
|
continue;
|
|
3624
3711
|
}
|
|
3625
|
-
const isIndex = page.slug === "index" || got.pages.some((q) => q.slug.startsWith(page.slug + "/"));
|
|
3626
3712
|
let tree = page.tree;
|
|
3627
|
-
if (ns) rewriteContentRefs(tree, segs, globalPrefixes);
|
|
3713
|
+
if (ns && !mount) rewriteContentRefs(tree, segs, globalPrefixes);
|
|
3628
3714
|
const size = boundedSize(tree, limit);
|
|
3629
3715
|
if (typeof size !== "number") {
|
|
3630
3716
|
warnFile("openapi", spec, spec, `the page ${slug || "/"} ${size === "cycle" ? "has a cyclic example or schema, which cannot be shown" : `is too large to build (over ${Math.round(limit / 1e6 * 10) / 10}M characters)`}`);
|
|
@@ -3633,13 +3719,17 @@ ${marker}${title}${marker}`, path, attributesOf(path), includesFor(path, read2),
|
|
|
3633
3719
|
infos.set(slug, {
|
|
3634
3720
|
slug,
|
|
3635
3721
|
source: isIndex ? slug ? `${slug}/index.md` : "index.md" : `${slug}.md`,
|
|
3636
|
-
out
|
|
3722
|
+
out,
|
|
3637
3723
|
title: detach(page.title),
|
|
3638
3724
|
draft: false,
|
|
3639
3725
|
virtual: { tree, project: spec }
|
|
3640
3726
|
});
|
|
3641
3727
|
}
|
|
3642
|
-
|
|
3728
|
+
if (mount) {
|
|
3729
|
+
mountedNavs.set(m, { nav: specNav(placed.nav, segs), label: label2 });
|
|
3730
|
+
continue;
|
|
3731
|
+
}
|
|
3732
|
+
specNavs.set(ns, specNav(placed.nav, segs));
|
|
3643
3733
|
const strays = [...infos.values()].filter((i) => !i.virtual && ns && (i.slug === ns || i.slug.startsWith(ns + "/")));
|
|
3644
3734
|
if (strays.length) warn("openapi", `${strays.length} page(s) are in the folder of the OpenAPI source "${ns}", and are left out of the nav: ${strays.slice(0, 5).map(srcOf).join(", ")}${strays.length > 5 ? ", \u2026" : ""}`);
|
|
3645
3735
|
}
|
|
@@ -3647,16 +3737,16 @@ ${marker}${title}${marker}`, path, attributesOf(path), includesFor(path, read2),
|
|
|
3647
3737
|
const navLoad = state.scan ? (text) => state.scan.yaml(text, loadYaml) : void 0;
|
|
3648
3738
|
const memberNav = async (ns) => {
|
|
3649
3739
|
const dir2 = ns ? ns + "/" : "";
|
|
3650
|
-
const member = unit.members.find((m) => m.namespace === ns);
|
|
3740
|
+
const member = unit.members.find((m) => m.namespace === ns && !m.mount);
|
|
3651
3741
|
if (member?.source.nav) return ownNav(member.source, ns);
|
|
3652
3742
|
const file = NAV_FILES.map((f) => dir2 + f).find((f) => files.has(f));
|
|
3653
3743
|
const others = unit.members.filter((m) => m.namespace);
|
|
3654
|
-
const mine = [...infos.values()].filter((i) => ns ? i.slug === ns || i.slug.startsWith(dir2) : !others.some((m) => i.slug === m.namespace || i.slug.startsWith(m.namespace + "/")));
|
|
3744
|
+
const mine = [...infos.values()].filter((i) => !mountedSlugs.has(i.slug) && (ns ? i.slug === ns || i.slug.startsWith(dir2) : !others.some((m) => i.slug === m.namespace || i.slug.startsWith(m.namespace + "/"))));
|
|
3655
3745
|
const fromPages = () => ns ? prefixNav(navFromPages(mine.map((i) => ({ ...i, slug: i.slug === ns ? "" : i.slug.slice(dir2.length) }))), ns) : navFromPages(mine);
|
|
3656
3746
|
if (!file) return { nav: fromPages() };
|
|
3657
3747
|
try {
|
|
3658
3748
|
const text = await read(file);
|
|
3659
|
-
return { nav: file.endsWith(".json") ? prefixNav(parseNavJson(text, (slug) => labelFor(ns ?
|
|
3749
|
+
return { nav: file.endsWith(".json") ? prefixNav(parseNavJson(text, (slug) => labelFor(ns ? prefixSlug2([ns], slug) : slug)), ns) : parseNavYaml(text, labelFor, ns, navLoad), file, project: abs(file) };
|
|
3660
3750
|
} catch (e) {
|
|
3661
3751
|
const mark = e.mark;
|
|
3662
3752
|
warn("nav", `could not read ${file}: ${e.message}; using the directory layout`, {
|
|
@@ -3668,7 +3758,7 @@ ${marker}${title}${marker}`, path, attributesOf(path), includesFor(path, read2),
|
|
|
3668
3758
|
};
|
|
3669
3759
|
const ownNav = async (src, ns) => {
|
|
3670
3760
|
const path = src.nav;
|
|
3671
|
-
const nsLabel = (slug) => labelFor(ns ?
|
|
3761
|
+
const nsLabel = (slug) => labelFor(ns ? prefixSlug2([ns], slug) : slug);
|
|
3672
3762
|
const map = topicMaps.get(path);
|
|
3673
3763
|
if (map) return { nav: prefixNav(parseNavJson(JSON.stringify(map.entries), nsLabel), ns), file: path, project: path, files: map.maps };
|
|
3674
3764
|
const c = input.files.get(path);
|
|
@@ -3679,7 +3769,13 @@ ${marker}${title}${marker}`, path, attributesOf(path), includesFor(path, read2),
|
|
|
3679
3769
|
let nav = [];
|
|
3680
3770
|
const navFiles = [];
|
|
3681
3771
|
const navProjectFiles = [];
|
|
3772
|
+
const host = unit.members.find((m) => !m.namespace && !m.mount && m.source.from !== "openapi");
|
|
3682
3773
|
for (const m of unit.members) {
|
|
3774
|
+
const placed = mountedNavs.get(m);
|
|
3775
|
+
if (placed) {
|
|
3776
|
+
if (!host) nav.push(...placed.nav);
|
|
3777
|
+
continue;
|
|
3778
|
+
}
|
|
3683
3779
|
if (m.source.from === "openapi") {
|
|
3684
3780
|
const items = specNavs.get(m.namespace) ?? [];
|
|
3685
3781
|
const group2 = namespaceNavGroup(m.namespace || void 0, items);
|
|
@@ -3688,6 +3784,7 @@ ${marker}${title}${marker}`, path, attributesOf(path), includesFor(path, read2),
|
|
|
3688
3784
|
continue;
|
|
3689
3785
|
}
|
|
3690
3786
|
const got = await memberNav(m.namespace);
|
|
3787
|
+
if (m === host) for (const [mm, { nav: items, label: label2 }] of mountedNavs) got.nav = placeMounted(got.nav, items, mm.mount, label2);
|
|
3691
3788
|
if (got.file) navFiles.push(got.file);
|
|
3692
3789
|
if (got.project) navProjectFiles.push(got.project);
|
|
3693
3790
|
const group = namespaceNavGroup(m.namespace || void 0, got.nav);
|
|
@@ -4596,22 +4693,28 @@ function postHeader(p, lang, t, asset) {
|
|
|
4596
4693
|
function specNav(items, segs) {
|
|
4597
4694
|
return items.map((it) => ({
|
|
4598
4695
|
label: it.label,
|
|
4599
|
-
...it.href != null ? { slug:
|
|
4696
|
+
...it.href != null ? { slug: prefixSlug2(segs, it.href.replace(/^\/+|\/+$/g, "")) } : {},
|
|
4600
4697
|
children: specNav(it.children ?? [], segs)
|
|
4601
4698
|
}));
|
|
4602
4699
|
}
|
|
4700
|
+
var PageClashError = class extends Error {
|
|
4701
|
+
constructor(message, file) {
|
|
4702
|
+
super(message);
|
|
4703
|
+
this.file = file;
|
|
4704
|
+
}
|
|
4705
|
+
};
|
|
4706
|
+
function mountClash(slug, mount, file, other) {
|
|
4707
|
+
return new PageClashError(`"${slug}" is both a page of the source mounted at "${mount}" and ${other}; move the page, or mount the source somewhere else`, file);
|
|
4708
|
+
}
|
|
4709
|
+
function placeMounted(host, mounted, mount, label) {
|
|
4710
|
+
const to = (nodes) => nodes.map((n) => ({ label: n.label, href: n.slug != null ? `/${n.slug}` : n.href, children: to(n.children), node: n }));
|
|
4711
|
+
const back = (items) => items.map((i) => i.node ? { ...i.node, children: back(i.children ?? []) } : { label: i.label, slug: i.href.replace(/^\/+|\/+$/g, ""), children: back(i.children ?? []) });
|
|
4712
|
+
return back(placeMountedNav(to(host), to(mounted), `/${mount}`, label, mount).nav);
|
|
4713
|
+
}
|
|
4603
4714
|
function prefixNav(nodes, ns) {
|
|
4604
4715
|
if (!ns) return nodes;
|
|
4605
4716
|
return nodes.map((n) => ({ ...n, ...n.slug != null ? { slug: n.slug ? `${ns}/${n.slug}` : ns } : {}, children: prefixNav(n.children, ns) }));
|
|
4606
4717
|
}
|
|
4607
|
-
function urlPathOf(url) {
|
|
4608
|
-
if (!url) return [];
|
|
4609
|
-
try {
|
|
4610
|
-
return new URL(url).pathname.split("/").filter(Boolean);
|
|
4611
|
-
} catch {
|
|
4612
|
-
return [];
|
|
4613
|
-
}
|
|
4614
|
-
}
|
|
4615
4718
|
function dropMount(tree, mounts) {
|
|
4616
4719
|
if (!mounts.length) return tree;
|
|
4617
4720
|
const strip = (u) => {
|
|
@@ -5043,6 +5146,9 @@ async function openDevSession(input, o = {}) {
|
|
|
5043
5146
|
sourceFor(path) {
|
|
5044
5147
|
return unitForSitePath(path)?.handle.sourceForPage(path);
|
|
5045
5148
|
},
|
|
5149
|
+
notes() {
|
|
5150
|
+
return [...ctx?.state.notes.values() ?? []].flat();
|
|
5151
|
+
},
|
|
5046
5152
|
takeWarnings() {
|
|
5047
5153
|
const all = ctx?.warnings ?? [];
|
|
5048
5154
|
const fresh = all.slice(taken);
|
|
@@ -5287,7 +5393,7 @@ function inConfig(e, file) {
|
|
|
5287
5393
|
function problemOf(e, text) {
|
|
5288
5394
|
const err = e ?? {};
|
|
5289
5395
|
const config = err.inConfig === true || e instanceof ConfigError;
|
|
5290
|
-
const file = err.configFile;
|
|
5396
|
+
const file = err.configFile ?? (e instanceof PageClashError ? e.file : void 0);
|
|
5291
5397
|
const at = typeof err.mark?.line === "number" ? { line: err.mark.line + 1, column: (err.mark.column ?? 0) + 1 } : {};
|
|
5292
5398
|
return { code: config ? "config" : "build", ...file ? { file } : {}, ...at, message: err.reason || text.split("\n")[0], text };
|
|
5293
5399
|
}
|
|
@@ -5366,6 +5472,7 @@ function openDevSession2(input, o) {
|
|
|
5366
5472
|
}
|
|
5367
5473
|
export {
|
|
5368
5474
|
ConfigError,
|
|
5475
|
+
PageClashError,
|
|
5369
5476
|
build2 as build,
|
|
5370
5477
|
composePage,
|
|
5371
5478
|
indexNav,
|
|
@@ -204,6 +204,8 @@ export interface BuiltPage {
|
|
|
204
204
|
/** What the site-level files need from every unit. Small: a few strings per page. */
|
|
205
205
|
export interface SiteState {
|
|
206
206
|
redirects: RedirectInput[];
|
|
207
|
+
/** What the build says about the content, not a problem, by unit prefix (replaced when a unit is built again). */
|
|
208
|
+
notes: Map<string, string[]>;
|
|
207
209
|
/** The sidebar items kept between pages (src/theme/regions.ts). */
|
|
208
210
|
navCache: NavCache;
|
|
209
211
|
/** Site path ("en/latest/guide/x") → output file relative to the site root. */
|
|
@@ -262,6 +264,11 @@ export interface BuildResult {
|
|
|
262
264
|
warnings: string[];
|
|
263
265
|
/** The warnings as data, one per warning, in the same order. */
|
|
264
266
|
problems: BuildProblem[];
|
|
267
|
+
/**
|
|
268
|
+
* What the build says that is not a problem: a content page standing as a mounted API's root
|
|
269
|
+
* (@dogsbay/site-files' `mountRootNote`), once per mount. The CLI prints them as the Astro pipeline does.
|
|
270
|
+
*/
|
|
271
|
+
notes: string[];
|
|
265
272
|
stats: BuildStats;
|
|
266
273
|
config: SiteConfig;
|
|
267
274
|
}
|
|
@@ -402,6 +409,14 @@ export declare function selectUnits(allUnits: BuildUnit[], names: string[] | und
|
|
|
402
409
|
* yes only loads KaTeX early; code is skipped, its `$` is not math.
|
|
403
410
|
*/
|
|
404
411
|
export declare function mayHaveMath(v: unknown, inProps?: boolean): boolean;
|
|
412
|
+
/** A page an API mounted beside it would land on: the build stops, on that page's file. */
|
|
413
|
+
export declare class PageClashError extends Error {
|
|
414
|
+
/** The project path of the other page (or spec). */
|
|
415
|
+
readonly file: string;
|
|
416
|
+
constructor(message: string,
|
|
417
|
+
/** The project path of the other page (or spec). */
|
|
418
|
+
file: string);
|
|
419
|
+
}
|
|
405
420
|
export interface LoadedTheme {
|
|
406
421
|
templates: ThemeTemplates;
|
|
407
422
|
themeCss?: string;
|
|
@@ -32,6 +32,12 @@ export interface SourceDef {
|
|
|
32
32
|
name?: string;
|
|
33
33
|
/** What the source holds: Dogsbay-MD pages (the default) or an OpenAPI spec, a page per operation. */
|
|
34
34
|
from?: "dogsbay-md" | "openapi";
|
|
35
|
+
/**
|
|
36
|
+
* Where an OpenAPI source's pages go inside its version and locale (`reference/rest-api`), beside
|
|
37
|
+
* the Markdown it belongs to: its root page is the mount, and a content page there stands in for it
|
|
38
|
+
* (@dogsbay/site-files mounts.ts, plans/openapi-mount.md). Not with `name:`, which puts a source outside its version.
|
|
39
|
+
*/
|
|
40
|
+
mount?: string;
|
|
35
41
|
version?: string;
|
|
36
42
|
locale?: string;
|
|
37
43
|
attributes?: Record<string, unknown>;
|
|
@@ -258,6 +264,8 @@ export declare function unitOfPath<U extends {
|
|
|
258
264
|
export interface UnitMember {
|
|
259
265
|
source: SourceDef;
|
|
260
266
|
namespace: string;
|
|
267
|
+
/** A mounted OpenAPI source's mount (`source.mount`): its pages go there, inside the unit. */
|
|
268
|
+
mount?: string;
|
|
261
269
|
}
|
|
262
270
|
/** One independent build: one or more content roots published under a locale/version prefix. */
|
|
263
271
|
export interface BuildUnit {
|
|
@@ -43,6 +43,8 @@ export interface DevSession {
|
|
|
43
43
|
change(paths: string[]): Promise<ChangeResult>;
|
|
44
44
|
/** Warnings not handed out yet (the start's, then those of each change and page render). */
|
|
45
45
|
takeWarnings(): string[];
|
|
46
|
+
/** What the site's build says that is not a problem (BuildResult.notes: a content page standing as a mounted API's root), as it stands now. */
|
|
47
|
+
notes(): string[];
|
|
46
48
|
/**
|
|
47
49
|
* The same warnings as data, not handed out yet (its own count: taking one kind leaves the other):
|
|
48
50
|
* the file each is about as a project path, with its line when known, and a code.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { BuildUnit, SiteConfig, UnitMember } from "./config.js";
|
|
2
|
+
import type { FileContent } from "./build.js";
|
|
3
|
+
import { openApiSourcePages } from "./resolve.js";
|
|
4
|
+
type Got = Exclude<Awaited<ReturnType<typeof openApiSourcePages>>, {
|
|
5
|
+
error: string;
|
|
6
|
+
}>;
|
|
7
|
+
export interface PlacedApiPage {
|
|
8
|
+
/** In the unit: under the namespace or the mount (the root page is the mount itself). */
|
|
9
|
+
slug: string;
|
|
10
|
+
/** Output file relative to the unit: the root and the tag pages are folders of the pages under them (`api/pets/`). */
|
|
11
|
+
out: string;
|
|
12
|
+
isIndex: boolean;
|
|
13
|
+
page: Got["pages"][number];
|
|
14
|
+
}
|
|
15
|
+
export type PlacedApi = {
|
|
16
|
+
missing: true;
|
|
17
|
+
} | {
|
|
18
|
+
spec: string;
|
|
19
|
+
error: string;
|
|
20
|
+
} | {
|
|
21
|
+
spec: string;
|
|
22
|
+
pages: PlacedApiPage[];
|
|
23
|
+
nav: Got["nav"];
|
|
24
|
+
segs: string[];
|
|
25
|
+
};
|
|
26
|
+
/** The path segments of `site.url` (`https://x.github.io/docs/` → ["docs"]). */
|
|
27
|
+
export declare function urlPathOf(url: string | undefined): string[];
|
|
28
|
+
/** An OpenAPI member's pages, placed in its unit. */
|
|
29
|
+
export declare function placeApiPages(cfg: SiteConfig, unit: BuildUnit, m: UnitMember, files: Map<string, FileContent>, readText: (c: FileContent) => Promise<string>): Promise<PlacedApi>;
|
|
30
|
+
export declare function apiPageOuts(cfg: SiteConfig, unit: BuildUnit, m: UnitMember, files: Map<string, FileContent>, readText: (c: FileContent) => Promise<string>): Promise<[string, string][]>;
|
|
31
|
+
export {};
|
|
@@ -20,6 +20,7 @@ export declare function openDevSession(input: BuildInput & {
|
|
|
20
20
|
}, o?: DevOptions): Promise<DevSession>;
|
|
21
21
|
export { prebuiltSiteCss };
|
|
22
22
|
export type { BuildInput, BuildResult, FileContent, OutputContent, SinkContent, SiteCssBuilder, BuiltPage, HighlightPool, BuildProblem, PageDiagnostic } from "../core/build.js";
|
|
23
|
+
export { PageClashError } from "../core/build.js";
|
|
23
24
|
export type { ChangeResult, DevOptions, DevSession } from "../core/dev.js";
|
|
24
25
|
export { parseConfig, projectRoots, ConfigError, type SiteConfig, type DiagramEngine } from "../core/config.js";
|
|
25
26
|
export type { DiagramRenderer, DiagramRenderers, DiagramRequest, DiagramResult } from "../core/diagrams.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dogsbay/ssg",
|
|
3
|
-
"version": "0.2.0-beta.
|
|
3
|
+
"version": "0.2.0-beta.142",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Documentation static site generator for Dogsbay-MD that builds inside Cloudflare Workers and publishes sites that work offline",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -49,38 +49,38 @@
|
|
|
49
49
|
"tailwindcss": "^4.3.2"
|
|
50
50
|
},
|
|
51
51
|
"peerDependencies": {
|
|
52
|
-
"@dogsbay/elements": "0.2.0-beta.
|
|
53
|
-
"@dogsbay/format-dogsbay-md": "0.2.0-beta.
|
|
54
|
-
"@dogsbay/format-openapi": "0.2.0-beta.
|
|
55
|
-
"@dogsbay/format-topicmap": "0.2.0-beta.
|
|
56
|
-
"@dogsbay/highlight": "0.2.0-beta.
|
|
57
|
-
"@dogsbay/minja": "0.2.0-beta.
|
|
58
|
-
"@dogsbay/primitives": "0.2.0-beta.
|
|
59
|
-
"@dogsbay/render-html": "0.2.0-beta.
|
|
60
|
-
"@dogsbay/search": "0.2.0-beta.
|
|
61
|
-
"@dogsbay/serialize-core": "0.2.0-beta.
|
|
62
|
-
"@dogsbay/site-check": "0.2.0-beta.
|
|
63
|
-
"@dogsbay/site-files": "0.2.0-beta.
|
|
64
|
-
"@dogsbay/types": "0.2.0-beta.
|
|
52
|
+
"@dogsbay/elements": "0.2.0-beta.142",
|
|
53
|
+
"@dogsbay/format-dogsbay-md": "0.2.0-beta.142",
|
|
54
|
+
"@dogsbay/format-openapi": "0.2.0-beta.142",
|
|
55
|
+
"@dogsbay/format-topicmap": "0.2.0-beta.142",
|
|
56
|
+
"@dogsbay/highlight": "0.2.0-beta.142",
|
|
57
|
+
"@dogsbay/minja": "0.2.0-beta.142",
|
|
58
|
+
"@dogsbay/primitives": "0.2.0-beta.142",
|
|
59
|
+
"@dogsbay/render-html": "0.2.0-beta.142",
|
|
60
|
+
"@dogsbay/search": "0.2.0-beta.142",
|
|
61
|
+
"@dogsbay/serialize-core": "0.2.0-beta.142",
|
|
62
|
+
"@dogsbay/site-check": "0.2.0-beta.142",
|
|
63
|
+
"@dogsbay/site-files": "0.2.0-beta.142",
|
|
64
|
+
"@dogsbay/types": "0.2.0-beta.142"
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
67
67
|
"@axe-core/playwright": "^4.12.1",
|
|
68
68
|
"@cloudflare/workers-types": "^5.20260921.1",
|
|
69
|
-
"@dogsbay/elements": "0.2.0-beta.
|
|
70
|
-
"@dogsbay/format-dogsbay-md": "0.2.0-beta.
|
|
71
|
-
"@dogsbay/format-openapi": "0.2.0-beta.
|
|
72
|
-
"@dogsbay/format-topicmap": "0.2.0-beta.
|
|
73
|
-
"@dogsbay/highlight": "0.2.0-beta.
|
|
74
|
-
"@dogsbay/icons": "0.2.0-beta.
|
|
75
|
-
"@dogsbay/minja": "0.2.0-beta.
|
|
76
|
-
"@dogsbay/primitives": "0.2.0-beta.
|
|
77
|
-
"@dogsbay/render-html": "0.2.0-beta.
|
|
78
|
-
"@dogsbay/search": "0.2.0-beta.
|
|
79
|
-
"@dogsbay/serialize-core": "0.2.0-beta.
|
|
80
|
-
"@dogsbay/site-check": "0.2.0-beta.
|
|
81
|
-
"@dogsbay/site-files": "0.2.0-beta.
|
|
82
|
-
"@dogsbay/types": "0.2.0-beta.
|
|
83
|
-
"@dogsbay/ui": "0.2.0-beta.
|
|
69
|
+
"@dogsbay/elements": "0.2.0-beta.142",
|
|
70
|
+
"@dogsbay/format-dogsbay-md": "0.2.0-beta.142",
|
|
71
|
+
"@dogsbay/format-openapi": "0.2.0-beta.142",
|
|
72
|
+
"@dogsbay/format-topicmap": "0.2.0-beta.142",
|
|
73
|
+
"@dogsbay/highlight": "0.2.0-beta.142",
|
|
74
|
+
"@dogsbay/icons": "0.2.0-beta.142",
|
|
75
|
+
"@dogsbay/minja": "0.2.0-beta.142",
|
|
76
|
+
"@dogsbay/primitives": "0.2.0-beta.142",
|
|
77
|
+
"@dogsbay/render-html": "0.2.0-beta.142",
|
|
78
|
+
"@dogsbay/search": "0.2.0-beta.142",
|
|
79
|
+
"@dogsbay/serialize-core": "0.2.0-beta.142",
|
|
80
|
+
"@dogsbay/site-check": "0.2.0-beta.142",
|
|
81
|
+
"@dogsbay/site-files": "0.2.0-beta.142",
|
|
82
|
+
"@dogsbay/types": "0.2.0-beta.142",
|
|
83
|
+
"@dogsbay/ui": "0.2.0-beta.142",
|
|
84
84
|
"@mermanjs/web": "0.7.0",
|
|
85
85
|
"@playwright/test": "1.61.1",
|
|
86
86
|
"@types/node": "^22.10.0",
|