@dogsbay/ssg 0.2.0-beta.143 → 0.2.0-beta.146
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 +280 -68
- package/dist/package/types/core/build.d.ts +33 -5
- package/dist/package/types/core/canonical.d.ts +1 -2
- package/dist/package/types/core/config.d.ts +41 -3
- package/dist/package/types/core/dev.d.ts +10 -1
- package/dist/package/types/package/browser.d.ts +1 -1
- 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.146 (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.146 (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.146 (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.146 (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.146 (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,8 @@ 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 {
|
|
21
|
+
import { mergeHeaders, mergeRedirects, productRootRedirects, siteFiles, siteRootTarget, toScript, unitOf } from "@dogsbay/site-files";
|
|
22
|
+
import { buildHreflangLinks, isMountRoot, missingTranslations, mountRefs, mountRootNote, namespaceNavGroup, namespacePrefixes, placeMountedNav, prefixSlug as prefixSlug2, rewriteContentRefs } from "@dogsbay/site-files";
|
|
22
23
|
|
|
23
24
|
// src/core/canonical.ts
|
|
24
25
|
import { decideCanonical } from "@dogsbay/site-files";
|
|
@@ -26,7 +27,7 @@ import { declaresParams, splitFrontmatter } from "@dogsbay/format-dogsbay-md/bro
|
|
|
26
27
|
|
|
27
28
|
// src/core/config.ts
|
|
28
29
|
import { scriptUrl } from "@dogsbay/render-html";
|
|
29
|
-
import { assertLeafSitemap, checkVersionSeo, isNamespaceAxisActive, namespaceSegments, parseMount } from "@dogsbay/site-files";
|
|
30
|
+
import { assertLeafSitemap, checkVersionSeo, isNamespaceAxisActive, namespaceSegments, parseMount, ProductConfigError, productModel, productOf, sourceNamespace, sourceUnit, unitSegments } from "@dogsbay/site-files";
|
|
30
31
|
|
|
31
32
|
// src/core/yaml.ts
|
|
32
33
|
import { load } from "js-yaml";
|
|
@@ -36,6 +37,17 @@ function loadYaml(text) {
|
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
// src/core/config.ts
|
|
40
|
+
function shared(f) {
|
|
41
|
+
try {
|
|
42
|
+
return f();
|
|
43
|
+
} catch (e) {
|
|
44
|
+
if (e instanceof ProductConfigError) throw new ConfigError(e.message);
|
|
45
|
+
throw e;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function versionsOf(cfg, product) {
|
|
49
|
+
return cfg.productVersions?.get(product ?? "") ?? { versions: cfg.versions, defaultVersion: cfg.defaultVersion };
|
|
50
|
+
}
|
|
39
51
|
var ConfigError = class extends Error {
|
|
40
52
|
};
|
|
41
53
|
function sourceTemplates(v, path) {
|
|
@@ -67,10 +79,10 @@ function unitId(kind, v) {
|
|
|
67
79
|
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
80
|
return id;
|
|
69
81
|
}
|
|
70
|
-
function sourceMount(s) {
|
|
82
|
+
function sourceMount(s, products) {
|
|
71
83
|
const at = `content.sources[${String(s.path)}]`;
|
|
72
84
|
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`);
|
|
85
|
+
if (s.name != null && !products) throw new ConfigError(`${at} has both name and mount: a mounted source goes inside its version, so it takes no name (with content.products:, it names its product)`);
|
|
74
86
|
const parsed = parseMount(s.mount);
|
|
75
87
|
if ("error" in parsed) throw new ConfigError(`${at}: ${parsed.error}`);
|
|
76
88
|
return parsed.segments.join("/");
|
|
@@ -140,6 +152,7 @@ function parseConfig(text, overrides = {}) {
|
|
|
140
152
|
if (navMode !== void 0 && navMode !== "client" && navMode !== "ssr-full") throw new ConfigError(`build.navMode must be "client" or "ssr-full"; got ${JSON.stringify(navMode)}`);
|
|
141
153
|
const site = raw.site ?? {};
|
|
142
154
|
const content = raw.content ?? {};
|
|
155
|
+
const productsBlock = content.products != null;
|
|
143
156
|
const ssg = raw.ssg ?? {};
|
|
144
157
|
const agent = raw.agent ?? {};
|
|
145
158
|
const signal = agent.contentSignal ?? {};
|
|
@@ -147,7 +160,7 @@ function parseConfig(text, overrides = {}) {
|
|
|
147
160
|
path: sourcePath(s),
|
|
148
161
|
...s.name != null ? { name: sourceName(s.name) } : {},
|
|
149
162
|
...s.from != null ? { from: sourceFrom(s.from, String(s.path)) } : {},
|
|
150
|
-
...s.mount != null ? { mount: sourceMount(s) } : {},
|
|
163
|
+
...s.mount != null ? { mount: sourceMount(s, productsBlock) } : {},
|
|
151
164
|
version: s.version != null ? unitId("version", s.version) : void 0,
|
|
152
165
|
locale: s.locale != null ? unitId("locale", s.locale) : void 0,
|
|
153
166
|
attributes: s.attributes ?? void 0,
|
|
@@ -164,7 +177,7 @@ function parseConfig(text, overrides = {}) {
|
|
|
164
177
|
hidden: v.hidden || void 0,
|
|
165
178
|
removed: removedOf(v.removed, String(v.id)),
|
|
166
179
|
...versionSeoOf(v, String(v.id)),
|
|
167
|
-
...versionPathOf(v, String(v.id))
|
|
180
|
+
...versionPathOf(v, String(v.id), productsBlock)
|
|
168
181
|
}));
|
|
169
182
|
const locales = (content.locales ?? raw.locales ?? []).map((l) => ({
|
|
170
183
|
id: unitId("locales", l.id),
|
|
@@ -267,6 +280,7 @@ function parseConfig(text, overrides = {}) {
|
|
|
267
280
|
}
|
|
268
281
|
if (dv.noindex) throw new ConfigError(`versions: "${dv.id}" is the defaultVersion and has noindex: true; older versions' pages name it as their canonical`);
|
|
269
282
|
}
|
|
283
|
+
if (productsBlock) Object.assign(cfg, productsOf(content, raw, cfg));
|
|
270
284
|
return cfg;
|
|
271
285
|
}
|
|
272
286
|
var TAG_COLORS = /* @__PURE__ */ new Set(["blue", "amber", "emerald", "violet", "rose", "slate"]);
|
|
@@ -392,11 +406,41 @@ function versionSeoOf(v, id) {
|
|
|
392
406
|
...typeof v.sitemap === "boolean" ? { sitemap: v.sitemap } : {}
|
|
393
407
|
};
|
|
394
408
|
}
|
|
395
|
-
function versionPathOf(v, id) {
|
|
409
|
+
function versionPathOf(v, id, products = false) {
|
|
396
410
|
if (v.path === void 0 || v.path === null) return {};
|
|
397
|
-
if (v.path !== "")
|
|
411
|
+
if (products && v.path !== "") return { path: String(v.path) };
|
|
412
|
+
if (v.path !== "") throw new ConfigError(`versions: "${id}".path can only be "" (serve the version at the root); another segment needs content.products:`);
|
|
398
413
|
return { path: "" };
|
|
399
414
|
}
|
|
415
|
+
function productsOf(content, raw, cfg) {
|
|
416
|
+
const siteVersions = content.versions ?? raw.versions;
|
|
417
|
+
const written = (Array.isArray(content.sources) ? content.sources : []).filter((s) => typeof s?.path === "string");
|
|
418
|
+
const sources = written.length ? written : [{ path: "content" }];
|
|
419
|
+
const model = shared(() => productModel({ products: content.products, sources, versions: siteVersions, defaultVersion: content.defaultVersion ?? raw.defaultVersion, locales: cfg.locales, defaultLocale: cfg.defaultLocale }));
|
|
420
|
+
if (!model) return {};
|
|
421
|
+
const productVersions = /* @__PURE__ */ new Map();
|
|
422
|
+
for (const p of model.products) {
|
|
423
|
+
const rawList = (p.name ? content.products[p.name]?.versions : void 0) ?? siteVersions ?? [];
|
|
424
|
+
const versions = p.versions.map((v) => {
|
|
425
|
+
const r = rawList.find((x) => String(x?.id) === v.id) ?? {};
|
|
426
|
+
return {
|
|
427
|
+
id: v.id,
|
|
428
|
+
label: v.label,
|
|
429
|
+
...v.eol ? { eol: true } : {},
|
|
430
|
+
...v.prerelease ? { prerelease: true } : {},
|
|
431
|
+
...v.hidden ? { hidden: true } : {},
|
|
432
|
+
...r.removed != null ? { removed: removedOf(r.removed, v.id) } : {},
|
|
433
|
+
...v.canonical ? { canonical: v.canonical } : {},
|
|
434
|
+
...v.noindex !== void 0 ? { noindex: v.noindex } : {},
|
|
435
|
+
...v.sitemap !== void 0 ? { sitemap: v.sitemap } : {},
|
|
436
|
+
...v.path !== v.id ? { path: v.path } : {},
|
|
437
|
+
...v.banner ? { banner: v.banner } : {}
|
|
438
|
+
};
|
|
439
|
+
});
|
|
440
|
+
productVersions.set(p.name ?? "", { versions, ...p.defaultVersion ? { defaultVersion: p.defaultVersion } : {} });
|
|
441
|
+
}
|
|
442
|
+
return { products: model, productVersions };
|
|
443
|
+
}
|
|
400
444
|
function unitOfPath(units, sitePath2) {
|
|
401
445
|
let best;
|
|
402
446
|
for (const u of units) {
|
|
@@ -406,7 +450,12 @@ function unitOfPath(units, sitePath2) {
|
|
|
406
450
|
}
|
|
407
451
|
return best;
|
|
408
452
|
}
|
|
453
|
+
function groupPrefix(u) {
|
|
454
|
+
return [u.product, u.locale].filter(Boolean).join("/");
|
|
455
|
+
}
|
|
456
|
+
var sameProduct = (a, b) => (a.product ?? "") === (b.product ?? "");
|
|
409
457
|
function buildUnits(cfg) {
|
|
458
|
+
if (cfg.products) return productUnits(cfg, cfg.products);
|
|
410
459
|
const withDefaults2 = cfg.sources.map((s) => ({
|
|
411
460
|
source: s,
|
|
412
461
|
version: s.version ?? cfg.defaultVersion,
|
|
@@ -424,26 +473,26 @@ function buildUnits(cfg) {
|
|
|
424
473
|
}
|
|
425
474
|
}
|
|
426
475
|
const namespaces = isNamespaceAxisActive(cfg.sources.filter((s) => !s.mount));
|
|
427
|
-
|
|
428
|
-
throw new ConfigError("named sources (content.sources name:) cannot be combined with versions or locales yet (plans/openapi-sources.md)");
|
|
429
|
-
}
|
|
476
|
+
const products = namespaces && (versionAxis || localeAxis);
|
|
430
477
|
for (const s of cfg.sources) {
|
|
431
478
|
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`);
|
|
432
479
|
}
|
|
433
480
|
const units = /* @__PURE__ */ new Map();
|
|
434
481
|
for (const u of withDefaults2) {
|
|
435
482
|
const atRoot = cfg.versions.find((v) => v.id === u.version)?.path === "";
|
|
436
|
-
const
|
|
437
|
-
const
|
|
483
|
+
const product = products && !u.source.mount ? sourceNamespace(u.source) : void 0;
|
|
484
|
+
const prefix = [product, localeAxis ? u.locale : void 0, versionAxis && !atRoot ? u.version : void 0].filter(Boolean).join("/");
|
|
485
|
+
const member = u.source.mount ? { source: u.source, namespace: "", mount: u.source.mount } : { source: u.source, namespace: products ? "" : namespaceSegments(u.source, cfg.sources).join("/") };
|
|
438
486
|
const unit = units.get(prefix);
|
|
439
487
|
if (!unit) {
|
|
440
|
-
units.set(prefix, { source: u.source, members: [member], version: versionAxis ? u.version : void 0, locale: localeAxis ? u.locale : void 0, prefix });
|
|
488
|
+
units.set(prefix, { source: u.source, members: [member], version: versionAxis ? u.version : void 0, ...versionAxis && u.version ? { versionPath: atRoot ? "" : u.version } : {}, locale: localeAxis ? u.locale : void 0, ...product ? { product } : {}, prefix });
|
|
441
489
|
continue;
|
|
442
490
|
}
|
|
443
491
|
if (member.mount) {
|
|
444
492
|
const taken = unit.members.find((m) => m.mount === member.mount);
|
|
445
493
|
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
494
|
} else if (unit.members.some((m) => !m.mount)) {
|
|
495
|
+
if (products) throw new ConfigError(`two sources publish to "${prefix || "/"}" (${unit.members.find((m) => !m.mount).source.path}, ${u.source.path}): give each its own name, version or locale`);
|
|
447
496
|
if (!namespaces) throw new ConfigError(`two sources publish to the same prefix "${prefix || "/"}"`);
|
|
448
497
|
if (unit.members.some((m) => !m.mount && m.namespace === member.namespace)) {
|
|
449
498
|
throw new ConfigError(member.namespace ? `two sources are named "${member.namespace}"` : `two unnamed sources publish to the same prefix "${prefix || "/"}"`);
|
|
@@ -453,6 +502,16 @@ function buildUnits(cfg) {
|
|
|
453
502
|
const main = unit.members.find((m) => m.source === unit.source);
|
|
454
503
|
if (!member.namespace && !member.mount && (main.namespace || main.mount)) unit.source = u.source;
|
|
455
504
|
}
|
|
505
|
+
if (products) {
|
|
506
|
+
const names = new Set([...units.values()].map((u) => u.product).filter(Boolean));
|
|
507
|
+
for (const unit of units.values()) {
|
|
508
|
+
const main = unit.members.find((m) => !m.mount);
|
|
509
|
+
for (const m of unit.members.filter((x) => x.mount)) {
|
|
510
|
+
if (!main) throw new ConfigError(`content.sources[${m.source.path}]: a mounted source goes beside the unnamed source of its version and locale, and there is none at "${unit.prefix || "/"}"; a mount inside a named source's version is not supported yet`);
|
|
511
|
+
if (names.has(m.mount.split("/")[0])) throw new ConfigError(`content.sources[${m.source.path}]: mount "${m.mount}" starts with the name of a source, where that source's pages are; mount it elsewhere`);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
}
|
|
456
515
|
for (const unit of units.values()) {
|
|
457
516
|
for (const m of unit.members) {
|
|
458
517
|
const ns = m.mount && unit.members.find((o) => o.namespace && m.mount.split("/")[0] === o.namespace);
|
|
@@ -461,6 +520,43 @@ function buildUnits(cfg) {
|
|
|
461
520
|
}
|
|
462
521
|
return [...units.values()];
|
|
463
522
|
}
|
|
523
|
+
function productUnits(cfg, model) {
|
|
524
|
+
const units = /* @__PURE__ */ new Map();
|
|
525
|
+
for (const s of cfg.sources) {
|
|
526
|
+
const key = shared(() => sourceUnit(model, s, cfg.defaultLocale));
|
|
527
|
+
const prefix = shared(() => unitSegments(model, key)).join("/");
|
|
528
|
+
const member = s.mount ? { source: s, namespace: "", mount: s.mount } : { source: s, namespace: "" };
|
|
529
|
+
const unit = units.get(prefix);
|
|
530
|
+
if (!unit) {
|
|
531
|
+
const versionPath = key.version === void 0 ? void 0 : shared(() => productOf(model, key.product)).versions.find((v) => v.id === key.version)?.path;
|
|
532
|
+
units.set(prefix, {
|
|
533
|
+
source: s,
|
|
534
|
+
members: [member],
|
|
535
|
+
...key.version !== void 0 ? { version: key.version, versionPath } : {},
|
|
536
|
+
...key.locale !== void 0 ? { locale: key.locale } : {},
|
|
537
|
+
...key.product ? { product: key.product } : {},
|
|
538
|
+
prefix
|
|
539
|
+
});
|
|
540
|
+
continue;
|
|
541
|
+
}
|
|
542
|
+
if (member.mount) {
|
|
543
|
+
const taken = unit.members.find((m) => m.mount === member.mount);
|
|
544
|
+
if (taken) throw new ConfigError(`two sources are mounted at "${member.mount}" in the same version and locale (${taken.source.path}, ${s.path})`);
|
|
545
|
+
} else if (unit.members.some((m) => !m.mount)) {
|
|
546
|
+
throw new ConfigError(`two sources publish to "${prefix || "/"}" (${unit.members.find((m) => !m.mount).source.path}, ${s.path}): give each its own name, version or locale`);
|
|
547
|
+
}
|
|
548
|
+
unit.members.push(member);
|
|
549
|
+
if (!member.mount) unit.source = s;
|
|
550
|
+
}
|
|
551
|
+
const names = new Set(model.products.map((p) => p.name).filter(Boolean));
|
|
552
|
+
for (const unit of units.values()) {
|
|
553
|
+
if (unit.prefix !== "") continue;
|
|
554
|
+
for (const m of unit.members) {
|
|
555
|
+
if (m.mount && names.has(m.mount.split("/")[0])) throw new ConfigError(`content.sources[${m.source.path}]: mount "${m.mount}" starts with the name of a product, where that product's pages are; mount it elsewhere`);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
return [...units.values()];
|
|
559
|
+
}
|
|
464
560
|
function memberPath(unit, projectPath2) {
|
|
465
561
|
let best;
|
|
466
562
|
for (const m of unit.members) {
|
|
@@ -1069,16 +1165,19 @@ function parseFrontMatter(text) {
|
|
|
1069
1165
|
return {};
|
|
1070
1166
|
}
|
|
1071
1167
|
}
|
|
1168
|
+
var tableKey = (u) => u.product ? `${u.product}\0${u.locale ?? ""}` : u.locale ?? "";
|
|
1072
1169
|
async function defaultTables(cfg, units, built, files, read, warn = () => {
|
|
1073
1170
|
}, fm) {
|
|
1074
1171
|
const tables = /* @__PURE__ */ new Map();
|
|
1075
|
-
|
|
1076
|
-
|
|
1172
|
+
const dv = (u) => versionsOf(cfg, u.product).defaultVersion;
|
|
1173
|
+
const older = (u) => !!u.version && !!dv(u) && u.version !== dv(u);
|
|
1174
|
+
if (!built.some(older)) return tables;
|
|
1175
|
+
for (const unit of units.filter((u) => u.version !== void 0 && u.version === dv(u))) {
|
|
1077
1176
|
const t = await scan(cfg, unit, units, files, fm ?? frontMatterCache(read), read);
|
|
1078
|
-
if (!t.pages.size && built.some((u) => u
|
|
1079
|
-
warn(`[canonical] the default version "${
|
|
1177
|
+
if (!t.pages.size && built.some((u) => older(u) && u.locale === unit.locale && sameProduct(u, unit))) {
|
|
1178
|
+
warn(`[canonical] the default version "${dv(unit)}" has no pages under ${unit.source.path}, so older versions' pages keep themselves as canonical`);
|
|
1080
1179
|
}
|
|
1081
|
-
tables.set(unit
|
|
1180
|
+
tables.set(tableKey(unit), t);
|
|
1082
1181
|
}
|
|
1083
1182
|
return tables;
|
|
1084
1183
|
}
|
|
@@ -1163,11 +1262,12 @@ async function scan(cfg, unit, units, files, frontMatterOf, read, mode = { kind:
|
|
|
1163
1262
|
return { prefix: unit.prefix, pages, redirects };
|
|
1164
1263
|
}
|
|
1165
1264
|
function pageCanonical(cfg, unit, tables, page, urls) {
|
|
1166
|
-
const table = tables.get(unit
|
|
1167
|
-
const
|
|
1265
|
+
const table = tables.get(tableKey(unit));
|
|
1266
|
+
const { versions, defaultVersion } = versionsOf(cfg, unit.product);
|
|
1267
|
+
const version = versions.find((v) => v.id === unit.version);
|
|
1168
1268
|
const fmCanonical = typeof page.frontmatter.canonicalUrl === "string" ? page.frontmatter.canonicalUrl : void 0;
|
|
1169
1269
|
const d = decideCanonical({
|
|
1170
|
-
isDefault: !unit.version || unit.version ===
|
|
1270
|
+
isDefault: !unit.version || unit.version === defaultVersion || !table,
|
|
1171
1271
|
path: page.slug || "index",
|
|
1172
1272
|
version,
|
|
1173
1273
|
frontmatter: fmCanonical,
|
|
@@ -1312,31 +1412,31 @@ var CLIENT_CANDIDATES = ['""', '"&"', '"\\\\$&")).join("|")})', '"\\\\$&")}"', '
|
|
|
1312
1412
|
var SITE_NOTICES = `Third-party software in this site's _dogsbay/ files (dogsbay.js, site.css) and pages
|
|
1313
1413
|
|
|
1314
1414
|
========================================================================
|
|
1315
|
-
@dogsbay/elements@0.2.0-beta.
|
|
1415
|
+
@dogsbay/elements@0.2.0-beta.146 (MIT)
|
|
1316
1416
|
https://github.com/dogsbay/dogsbay.git
|
|
1317
1417
|
|
|
1318
1418
|
Licensed under MIT; the package ships no licence file.
|
|
1319
1419
|
|
|
1320
1420
|
========================================================================
|
|
1321
|
-
@dogsbay/primitives@0.2.0-beta.
|
|
1421
|
+
@dogsbay/primitives@0.2.0-beta.146 (MIT)
|
|
1322
1422
|
https://github.com/dogsbay/dogsbay.git
|
|
1323
1423
|
|
|
1324
1424
|
Licensed under MIT; the package ships no licence file.
|
|
1325
1425
|
|
|
1326
1426
|
========================================================================
|
|
1327
|
-
@dogsbay/render-html@0.2.0-beta.
|
|
1427
|
+
@dogsbay/render-html@0.2.0-beta.146 (MIT)
|
|
1328
1428
|
https://github.com/dogsbay/dogsbay.git
|
|
1329
1429
|
|
|
1330
1430
|
Licensed under MIT; the package ships no licence file.
|
|
1331
1431
|
|
|
1332
1432
|
========================================================================
|
|
1333
|
-
@dogsbay/search@0.2.0-beta.
|
|
1433
|
+
@dogsbay/search@0.2.0-beta.146 (MIT)
|
|
1334
1434
|
https://github.com/dogsbay/dogsbay.git
|
|
1335
1435
|
|
|
1336
1436
|
Licensed under MIT; the package ships no licence file.
|
|
1337
1437
|
|
|
1338
1438
|
========================================================================
|
|
1339
|
-
@dogsbay/ui@0.2.0-beta.
|
|
1439
|
+
@dogsbay/ui@0.2.0-beta.146 (MIT)
|
|
1340
1440
|
https://github.com/dogsbay/dogsbay.git
|
|
1341
1441
|
|
|
1342
1442
|
Licensed under MIT; the package ships no licence file.
|
|
@@ -2498,6 +2598,8 @@ var EN = {
|
|
|
2498
2598
|
prerelease: "pre-release",
|
|
2499
2599
|
latest: "latest",
|
|
2500
2600
|
oldVersion: "You are viewing documentation for an older version.",
|
|
2601
|
+
eolVersion: "This version is no longer maintained.",
|
|
2602
|
+
prereleaseVersion: "This version is not released yet.",
|
|
2501
2603
|
goLatest: "Go to the latest version",
|
|
2502
2604
|
notFound: "Page not found",
|
|
2503
2605
|
notFoundBody: "The page you asked for does not exist in this version of the documentation.",
|
|
@@ -3064,7 +3166,8 @@ function diagramStore(input, cfg) {
|
|
|
3064
3166
|
async function siteCssBuilder(input) {
|
|
3065
3167
|
return input.css ?? (await import("./chunks/tailwind-fallback-KPRFHW3C.mjs")).buildSiteCss;
|
|
3066
3168
|
}
|
|
3067
|
-
var SITE_FILES = /* @__PURE__ */ new Set(["robots.txt", "
|
|
3169
|
+
var SITE_FILES = /* @__PURE__ */ new Set(["robots.txt", "sitemap-index.xml"]);
|
|
3170
|
+
var MERGED_FILES = /* @__PURE__ */ new Set(["_headers", "_redirects"]);
|
|
3068
3171
|
function reporter(warnings, problems) {
|
|
3069
3172
|
return (code, text, at = {}) => {
|
|
3070
3173
|
const t = detach(text);
|
|
@@ -3079,7 +3182,8 @@ function linedDiagnostics(found, raw, body, parsed, after = "of the page after t
|
|
|
3079
3182
|
const LINE = /\bline (\d+)/g;
|
|
3080
3183
|
const shifted = (m) => m.replace(LINE, (_, n) => `line ${Number(n) + offset}`);
|
|
3081
3184
|
const named = (d) => d.name === void 0 ? {} : { name: detach(d.name) };
|
|
3082
|
-
const
|
|
3185
|
+
const columns = (d) => ({ ...d.column === void 0 ? {} : { column: d.column }, ...d.endColumn === void 0 ? {} : { endColumn: d.endColumn } });
|
|
3186
|
+
const lined = (d) => ({ code: d.code, message: detach(shifted(d.message)), line: d.line + offset, ...named(d), ...columns(d) });
|
|
3083
3187
|
if (parsed === body) return found.map(lined);
|
|
3084
3188
|
let asWritten;
|
|
3085
3189
|
try {
|
|
@@ -3094,6 +3198,36 @@ function linedDiagnostics(found, raw, body, parsed, after = "of the page after t
|
|
|
3094
3198
|
return { code: d.code, message: detach(d.message.replace(LINE, `line $1 ${after}`)), ...named(d) };
|
|
3095
3199
|
});
|
|
3096
3200
|
}
|
|
3201
|
+
function sourceLinesOf(tree, raw, body, parsed) {
|
|
3202
|
+
const offset = raw.slice(0, raw.length - body.length).split("\n").length - 1;
|
|
3203
|
+
let map = (line) => line + offset;
|
|
3204
|
+
if (parsed !== body) {
|
|
3205
|
+
const a = body.split("\n");
|
|
3206
|
+
const b = parsed.split("\n");
|
|
3207
|
+
if (a.length !== b.length || /\{[%#]/.test(body)) {
|
|
3208
|
+
let head = 0;
|
|
3209
|
+
while (head < a.length && head < b.length && a[head] === b[head]) head++;
|
|
3210
|
+
let tail = 0;
|
|
3211
|
+
while (tail < a.length - head && tail < b.length - head && a[a.length - 1 - tail] === b[b.length - 1 - tail]) tail++;
|
|
3212
|
+
map = (line) => line <= head ? line + offset : line > b.length - tail ? line - (b.length - a.length) + offset : void 0;
|
|
3213
|
+
}
|
|
3214
|
+
}
|
|
3215
|
+
const walk = (node) => {
|
|
3216
|
+
if (Array.isArray(node)) {
|
|
3217
|
+
for (const n of node) walk(n);
|
|
3218
|
+
return;
|
|
3219
|
+
}
|
|
3220
|
+
if (!node || typeof node !== "object") return;
|
|
3221
|
+
const meta = node.meta;
|
|
3222
|
+
if (meta && typeof meta.line === "number") {
|
|
3223
|
+
const to = map(meta.line);
|
|
3224
|
+
if (to === void 0) delete meta.line;
|
|
3225
|
+
else meta.line = to;
|
|
3226
|
+
}
|
|
3227
|
+
for (const v of Object.values(node)) if (v && typeof v === "object" && v !== meta) walk(v);
|
|
3228
|
+
};
|
|
3229
|
+
walk(tree);
|
|
3230
|
+
}
|
|
3097
3231
|
var decoder = new TextDecoder();
|
|
3098
3232
|
var DATA_DIRECTIVE_NODES = new Set(DATA_DIRECTIVES);
|
|
3099
3233
|
var DEFAULT_DATA_CACHE_BYTES = 32 * 1024 * 1024;
|
|
@@ -3167,7 +3301,7 @@ function frontMatterCopy(fm) {
|
|
|
3167
3301
|
}
|
|
3168
3302
|
}
|
|
3169
3303
|
function rebuildUnitLazy(ctx, unit) {
|
|
3170
|
-
return buildUnit(unit, ctx.allUnits, ctx.cfg, ctx.input, ctx.highlighter, ctx.emit, ctx.report, ctx.phase, ctx.theme.templates, ctx.state, { lazy: true, diagnostics: ctx.diagnostics });
|
|
3304
|
+
return buildUnit(unit, ctx.allUnits, ctx.cfg, ctx.input, ctx.highlighter, ctx.emit, ctx.report, ctx.phase, ctx.theme.templates, ctx.state, { lazy: true, diagnostics: ctx.diagnostics, dataLines: ctx.dataLines });
|
|
3171
3305
|
}
|
|
3172
3306
|
async function build(input, hooks = {}) {
|
|
3173
3307
|
const t0 = now();
|
|
@@ -3179,6 +3313,7 @@ async function build(input, hooks = {}) {
|
|
|
3179
3313
|
const allUnits = buildUnits(cfg);
|
|
3180
3314
|
const units = selectUnits(allUnits, input.units);
|
|
3181
3315
|
checkRootVersion(allUnits, input.files);
|
|
3316
|
+
checkProductFolders(allUnits, input.files);
|
|
3182
3317
|
const out = /* @__PURE__ */ new Map();
|
|
3183
3318
|
const sink = input.sink;
|
|
3184
3319
|
let classes = new Set(CLIENT_CANDIDATES);
|
|
@@ -3207,7 +3342,7 @@ async function build(input, hooks = {}) {
|
|
|
3207
3342
|
phase.init = now() - t0;
|
|
3208
3343
|
let pages = 0;
|
|
3209
3344
|
let assets = 0;
|
|
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) };
|
|
3345
|
+
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(), hostFiles: /* @__PURE__ */ new Map(), 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) };
|
|
3211
3346
|
for (const r of cfg.redirects) {
|
|
3212
3347
|
const from = sitePath(r.from, cfg.basePath);
|
|
3213
3348
|
if (!from) {
|
|
@@ -3228,10 +3363,10 @@ async function build(input, hooks = {}) {
|
|
|
3228
3363
|
if (siteBase(cfg)) state.languages = await languageTables(cfg, allUnits, units, input.files, readText, frontMatterOf);
|
|
3229
3364
|
const translations = await translationTables(cfg, allUnits, input.files, readText, input.includeDrafts === true, frontMatterOf);
|
|
3230
3365
|
frontMatterOf = void 0;
|
|
3231
|
-
hooks.context?.({ cfg, allUnits, input, highlighter, emit, warnings, problems, report, phase, theme, state, diagnostics: hooks.diagnostics });
|
|
3366
|
+
hooks.context?.({ cfg, allUnits, input, highlighter, emit, warnings, problems, report, phase, theme, state, diagnostics: hooks.diagnostics, dataLines: hooks.dataLines });
|
|
3232
3367
|
for (const unit of units) {
|
|
3233
3368
|
classes = new Set(CLIENT_CANDIDATES);
|
|
3234
|
-
const r = await buildUnit(unit, allUnits, cfg, input, highlighter, emit, report, phase, theme.templates, state, { keep: hooks.keep, lazy: hooks.lazy, diagnostics: hooks.diagnostics });
|
|
3369
|
+
const r = await buildUnit(unit, allUnits, cfg, input, highlighter, emit, report, phase, theme.templates, state, { keep: hooks.keep, lazy: hooks.lazy, diagnostics: hooks.diagnostics, dataLines: hooks.dataLines });
|
|
3235
3370
|
hooks.unitBuilt?.(unit, r, classes);
|
|
3236
3371
|
pages += r.pages;
|
|
3237
3372
|
assets += r.assets;
|
|
@@ -3261,20 +3396,36 @@ async function build(input, hooks = {}) {
|
|
|
3261
3396
|
defaultLocale: cfg.defaultLocale,
|
|
3262
3397
|
versions: cfg.versions,
|
|
3263
3398
|
locales: cfg.locales,
|
|
3264
|
-
units: allUnits.map((u) => ({ prefix: u.prefix, version: u.version, locale: u.locale }))
|
|
3399
|
+
units: allUnits.map((u) => ({ prefix: u.prefix, version: u.version, locale: u.locale, ...u.product ? { product: u.product } : {}, ...cfg.products && u.versionPath !== u.version ? { versionPath: u.versionPath } : {} })),
|
|
3400
|
+
// With content.products, each product's own versions and default (key "" for the unnamed source's).
|
|
3401
|
+
...cfg.productVersions ? { products: Object.fromEntries(cfg.productVersions) } : {}
|
|
3265
3402
|
// As nav.js: a host may inline the script, and a name with "<\/script>" must not close it.
|
|
3266
3403
|
}).replace(/<\//g, "<\\/")};
|
|
3267
3404
|
`
|
|
3268
3405
|
);
|
|
3406
|
+
if (cfg.products) await emit("_dogsbay/versions.js", `${toScript("__DOGSBAY_VERSIONS__", siteFiles(cfg.products, []).versions)}
|
|
3407
|
+
`);
|
|
3269
3408
|
const def = defaultUnit(allUnits, cfg);
|
|
3270
3409
|
const tSite = now();
|
|
3410
|
+
const rootUnit = allUnits.find((u) => u.prefix === "");
|
|
3411
|
+
if (rootUnit && !input.untrusted) {
|
|
3412
|
+
for (const n of MERGED_FILES) {
|
|
3413
|
+
const own = input.files.get(sourceRoot(rootUnit.source) + n);
|
|
3414
|
+
if (own !== void 0) state.hostFiles.set(n, own);
|
|
3415
|
+
}
|
|
3416
|
+
}
|
|
3271
3417
|
await emitSiteFiles(cfg, allUnits, units, def, state, emit, report, input.onRedirects);
|
|
3272
3418
|
phase.site = (phase.site ?? 0) + now() - tSite;
|
|
3273
3419
|
if (def && def.prefix) {
|
|
3274
3420
|
await emit("index.html", redirectPage(`${def.prefix}/index.html`, cfg.name));
|
|
3275
3421
|
await emit("404.html", redirectPage(`${def.prefix}/404.html`, cfg.name));
|
|
3422
|
+
}
|
|
3423
|
+
if (cfg.products) {
|
|
3424
|
+
for (const [from, to] of productRootRedirects(cfg.products)) await emit(`${from.slice(1)}index.html`, redirectPage(`${relativeHome(from, to)}index.html`, cfg.name));
|
|
3425
|
+
} else if (def && def.prefix) {
|
|
3276
3426
|
for (const u of allUnits) {
|
|
3277
|
-
|
|
3427
|
+
const root = groupPrefix(u);
|
|
3428
|
+
if (root && u.version && u.version === cfg.defaultVersion && u.prefix !== root) await emit(`${root}/index.html`, redirectPage(`${u.version}/index.html`, cfg.name));
|
|
3278
3429
|
}
|
|
3279
3430
|
}
|
|
3280
3431
|
state.stubs = await writeTranslationStubs(cfg, allUnits, units, translations, state, emit);
|
|
@@ -3284,14 +3435,17 @@ async function build(input, hooks = {}) {
|
|
|
3284
3435
|
files: out,
|
|
3285
3436
|
warnings,
|
|
3286
3437
|
problems,
|
|
3287
|
-
notes: [...state.notes.values()].flat(),
|
|
3438
|
+
notes: [...state.notes.values()].flat().map((n) => n.message),
|
|
3288
3439
|
config: cfg,
|
|
3289
3440
|
stats: { pages, assets, units: units.length, ms: Math.round(now() - t0), msByPhase: roundAll(phase), highlightCache: highlighter.cacheStats(), ...state.parseCache ? { parseCache: state.parseCache.stats() } : {} }
|
|
3290
3441
|
};
|
|
3291
3442
|
}
|
|
3292
3443
|
function selectUnits(allUnits, names) {
|
|
3293
3444
|
if (!names) return allUnits;
|
|
3294
|
-
const named = (u, name) =>
|
|
3445
|
+
const named = (u, name) => {
|
|
3446
|
+
if (u.product) return u.product === name || u.prefix === name && u.prefix !== groupPrefix(u) || u.version !== void 0 && name === `${groupPrefix(u)}/${u.version}`;
|
|
3447
|
+
return u.prefix === name || u.version !== void 0 && (u.version === name && u.prefix === groupPrefix(u) || [groupPrefix(u), u.version].filter(Boolean).join("/") === name);
|
|
3448
|
+
};
|
|
3295
3449
|
const unknown = names.filter((p) => !allUnits.some((u) => named(u, p)));
|
|
3296
3450
|
if (unknown.length) {
|
|
3297
3451
|
const list = allUnits.map((u) => u.prefix ? `"${u.prefix}"` : `"${u.version ?? ""}" (at the root)`).join(", ");
|
|
@@ -3301,13 +3455,13 @@ function selectUnits(allUnits, names) {
|
|
|
3301
3455
|
}
|
|
3302
3456
|
function checkRootVersion(allUnits, files) {
|
|
3303
3457
|
const rootOf = (x) => x.source.path === "." ? "" : x.source.path.replace(/^\.\//, "").replace(/\/+$/, "") + "/";
|
|
3304
|
-
for (const u of allUnits.filter((x) => x.version && x.prefix === (x
|
|
3458
|
+
for (const u of allUnits.filter((x) => x.version && x.prefix === groupPrefix(x))) {
|
|
3305
3459
|
const root = rootOf(u);
|
|
3306
3460
|
const nested = allUnits.find((x) => x !== u && rootOf(x).startsWith(root) && rootOf(x) !== root);
|
|
3307
3461
|
if (nested) {
|
|
3308
3462
|
throw new ConfigError(`source "${nested.source.path}" is inside "${u.source.path}", the source of version "${u.version}" served at the root; give each version its own folder`);
|
|
3309
3463
|
}
|
|
3310
|
-
const segs = new Set(allUnits.filter((x) => x !== u && x.locale === u.locale && x.
|
|
3464
|
+
const segs = new Set(allUnits.filter((x) => x !== u && x.locale === u.locale && sameProduct(x, u) && x.versionPath).map((x) => x.versionPath));
|
|
3311
3465
|
if (!segs.size) continue;
|
|
3312
3466
|
for (const k of files.keys()) {
|
|
3313
3467
|
if (!k.startsWith(root)) continue;
|
|
@@ -3315,7 +3469,26 @@ function checkRootVersion(allUnits, files) {
|
|
|
3315
3469
|
if (rel.split("/").some((s) => s.startsWith("_") || s.startsWith("."))) continue;
|
|
3316
3470
|
const first = rel.split("/")[0].replace(/\.(md|markdown)$/i, "");
|
|
3317
3471
|
if (segs.has(first) && (rel.includes("/") || /\.(md|markdown)$/i.test(rel))) {
|
|
3318
|
-
|
|
3472
|
+
const other = allUnits.find((x) => x.versionPath === first && x.locale === u.locale && sameProduct(x, u));
|
|
3473
|
+
throw new ConfigError(`${k} is at ${[u.prefix, first].filter(Boolean).join("/")}/\u2026, where version "${other.version}" is served (version "${u.version}" is at the root); rename the folder or the page`);
|
|
3474
|
+
}
|
|
3475
|
+
}
|
|
3476
|
+
}
|
|
3477
|
+
}
|
|
3478
|
+
function checkProductFolders(allUnits, files) {
|
|
3479
|
+
const names = new Set(allUnits.map((u) => u.product).filter((p) => !!p));
|
|
3480
|
+
if (!names.size) return;
|
|
3481
|
+
for (const u of allUnits.filter((x) => !x.product && x.prefix === "")) {
|
|
3482
|
+
const roots = u.members.filter((m) => !m.mount && m.source.from !== "openapi").map((m) => sourceRoot(m.source));
|
|
3483
|
+
const others = allUnits.filter((x) => x !== u).flatMap((x) => x.members.map((m) => sourceRoot(m.source))).filter(Boolean);
|
|
3484
|
+
for (const k of files.keys()) {
|
|
3485
|
+
const root = roots.find((r) => k.startsWith(r));
|
|
3486
|
+
if (root === void 0 || others.some((o) => k.startsWith(o) && o.length > root.length)) continue;
|
|
3487
|
+
const rel = k.slice(root.length);
|
|
3488
|
+
if (rel.split("/").some((seg) => seg.startsWith("_") || seg.startsWith("."))) continue;
|
|
3489
|
+
const first = rel.split("/")[0].replace(/\.(md|markdown)$/i, "");
|
|
3490
|
+
if (names.has(first) && (rel.includes("/") || /\.(md|markdown)$/i.test(rel))) {
|
|
3491
|
+
throw new ConfigError(`${k} is at ${first}/\u2026, where the source named "${first}" is published; rename the folder or the page`);
|
|
3319
3492
|
}
|
|
3320
3493
|
}
|
|
3321
3494
|
}
|
|
@@ -3326,15 +3499,23 @@ async function emitSiteFiles(cfg, all, built, def, state, emit, report, onRedire
|
|
|
3326
3499
|
if (state.supplied.has(p)) report("site", `[site] ${p} comes from the content, so the generated one is not written`);
|
|
3327
3500
|
else await emit(p, content);
|
|
3328
3501
|
};
|
|
3502
|
+
const cloudflare = cfg.deployTarget === "cloudflare-workers";
|
|
3503
|
+
const merged = async (p, generated, merge) => {
|
|
3504
|
+
const own = state.hostFiles.get(p);
|
|
3505
|
+
if (own === void 0 && generated === void 0) return;
|
|
3506
|
+
const { text, notes } = merge(own === void 0 ? "" : await readText(own), generated, cloudflare);
|
|
3507
|
+
for (const n of notes) report("site", `[site] ${n}`);
|
|
3508
|
+
await emit(p, text);
|
|
3509
|
+
};
|
|
3329
3510
|
await put("robots.txt", buildRobotsTxt(cfg, defPrefix));
|
|
3330
|
-
|
|
3511
|
+
await merged("_headers", cfg.llmsTxt ? buildHeadersFile(cfg, defPrefix) : void 0, mergeHeaders);
|
|
3331
3512
|
if (siteBase(cfg)) {
|
|
3332
3513
|
const maps = all.flatMap((u) => state.sitemaps.get(u.prefix) ?? [[u.prefix, "sitemap-0.xml"].filter(Boolean).join("/")]);
|
|
3333
3514
|
await put("sitemap-index.xml", buildSitemapIndex(cfg, maps));
|
|
3334
3515
|
} else if (cfg.url) {
|
|
3335
3516
|
report("config", `[site] site.url "${cfg.url}" has no http:// or https://, so canonical links, the sitemap and absolute llms.txt links are left out`);
|
|
3336
3517
|
}
|
|
3337
|
-
if (!state.redirects.length) return;
|
|
3518
|
+
if (!state.redirects.length) return merged("_redirects", void 0, mergeRedirects);
|
|
3338
3519
|
const known = (p) => {
|
|
3339
3520
|
const u = unitOfPath(all, p);
|
|
3340
3521
|
return !!u && built.includes(u);
|
|
@@ -3344,9 +3525,15 @@ async function emitSiteFiles(cfg, all, built, def, state, emit, report, onRedire
|
|
|
3344
3525
|
for (const m of w) report("redirects", `[redirects] ${m}`);
|
|
3345
3526
|
onRedirects?.(rules);
|
|
3346
3527
|
for (const r of rules) await emit(stubFile(r), renderRedirectPage(r, cfg));
|
|
3347
|
-
|
|
3528
|
+
const ownRedirects = state.hostFiles.has("_redirects");
|
|
3529
|
+
await merged("_redirects", (cloudflare || ownRedirects) && rules.length ? renderRedirectsFile(rules, cfg) : void 0, mergeRedirects);
|
|
3348
3530
|
}
|
|
3349
3531
|
function defaultUnit(units, cfg) {
|
|
3532
|
+
if (cfg.products) {
|
|
3533
|
+
const target = siteRootTarget(cfg.products);
|
|
3534
|
+
if (target) return units.find((u) => `/${u.prefix}/` === target || u.prefix === "" && target === "/") ?? units[0];
|
|
3535
|
+
units = units.filter((u) => !u.product);
|
|
3536
|
+
}
|
|
3350
3537
|
return units.find((u) => (u.version ?? cfg.defaultVersion) === cfg.defaultVersion && (u.locale ?? cfg.defaultLocale) === cfg.defaultLocale) ?? units[0];
|
|
3351
3538
|
}
|
|
3352
3539
|
var mathLoad;
|
|
@@ -3394,7 +3581,7 @@ async function buildUnit(unit, allUnits, cfg, input, highlighter, emit, report,
|
|
|
3394
3581
|
};
|
|
3395
3582
|
};
|
|
3396
3583
|
const namespaceOf = (p) => named.find((m) => p === m.namespace || p.startsWith(m.namespace + "/"))?.namespace ?? "";
|
|
3397
|
-
const globalPrefixes = new Set(cfg.taxonomies.map((t2) => t2.path.split("/")[0]).filter(Boolean));
|
|
3584
|
+
const globalPrefixes = /* @__PURE__ */ new Set([...cfg.taxonomies.map((t2) => t2.path.split("/")[0]).filter(Boolean), ...namespacePrefixes(cfg.sources.filter((s) => !s.mount))]);
|
|
3398
3585
|
const mounts = [cfg.basePath, ...cfg.linkPrefixes ?? []].filter(Boolean);
|
|
3399
3586
|
const prefix = unit.prefix ? unit.prefix + "/" : "";
|
|
3400
3587
|
const label = unit.prefix || "/";
|
|
@@ -3695,7 +3882,8 @@ ${marker}${title}${marker}`, path, attributesOf(path), includesFor(path, read2),
|
|
|
3695
3882
|
if (mount) {
|
|
3696
3883
|
const there = infos.get(slug);
|
|
3697
3884
|
if (there && isMountRoot(page.slug) && !there.virtual) {
|
|
3698
|
-
|
|
3885
|
+
const page2 = prefixSlug2(unit.prefix ? unit.prefix.split("/") : [], slug);
|
|
3886
|
+
notes.push({ message: mountRootNote(m.mount, page2), file: srcOf(there), page: page2 });
|
|
3699
3887
|
label2 = there.title;
|
|
3700
3888
|
continue;
|
|
3701
3889
|
}
|
|
@@ -3964,8 +4152,9 @@ ${marker}${title}${marker}`, path, attributesOf(path), includesFor(path, read2),
|
|
|
3964
4152
|
t2 = now();
|
|
3965
4153
|
let tree;
|
|
3966
4154
|
try {
|
|
3967
|
-
const parsed = dogsbayMdToTree(pre.text, mode.diagnostics ? { diagnostics: true } : void 0);
|
|
4155
|
+
const parsed = dogsbayMdToTree(pre.text, mode.diagnostics || mode.dataLines ? { ...mode.diagnostics ? { diagnostics: true } : {}, ...mode.dataLines ? { sourceLines: true } : {} } : void 0);
|
|
3968
4156
|
tree = parsed.tree;
|
|
4157
|
+
if (mode.dataLines) sourceLinesOf(tree, raw, bodySrc, pre.text);
|
|
3969
4158
|
if (mode.diagnostics) (diagnostics ??= []).push(...linedDiagnostics(parsed.diagnostics ?? [], raw, bodySrc, pre.text, templated === bodySrc ? "of the page with its data directives drawn" : void 0));
|
|
3970
4159
|
} catch (e) {
|
|
3971
4160
|
warn2("parse", `parse error: ${e.message}`);
|
|
@@ -4146,7 +4335,8 @@ ${marker}${title}${marker}`, path, attributesOf(path), includesFor(path, read2),
|
|
|
4146
4335
|
imageZoom: cfg.imageZoom ? cfg.imageZoom.excludeInsideLinks ? "outside-links" : "all" : void 0,
|
|
4147
4336
|
imageCaptions: cfg.imageCaptions,
|
|
4148
4337
|
rawHtml: sanitizing ? (h) => sanitizeHtml(h, noteRemoved) : void 0,
|
|
4149
|
-
embeddedEndpoints: apiLayout.wide ? apiLayout.embeddedEndpoints : void 0
|
|
4338
|
+
embeddedEndpoints: apiLayout.wide ? apiLayout.embeddedEndpoints : void 0,
|
|
4339
|
+
dataLines: mode.dataLines
|
|
4150
4340
|
});
|
|
4151
4341
|
let hasH1 = tree[0]?.type === "heading" && Number(tree[0].props?.level) === 1;
|
|
4152
4342
|
const post = postNeighbours.has(info.slug) ? blog.get(info.slug) : void 0;
|
|
@@ -4317,6 +4507,8 @@ ${marker}${title}${marker}`, path, attributesOf(path), includesFor(path, read2),
|
|
|
4317
4507
|
t = now();
|
|
4318
4508
|
for (const a of assetPaths) {
|
|
4319
4509
|
if (SITE_FILES.has(prefix + a)) state.supplied.add(prefix + a);
|
|
4510
|
+
if (MERGED_FILES.has(prefix + a)) continue;
|
|
4511
|
+
if (MERGED_FILES.has(a)) warn("site", `${a} is copied to ${prefix}${a}, where hosts do not read it: they read _headers and _redirects at the site root only, from the unit served there`, { file: abs(a) });
|
|
4320
4512
|
await emit(prefix + a, files.get(a));
|
|
4321
4513
|
}
|
|
4322
4514
|
const pagesJs = `(window.__DOGSBAY_PAGES__=window.__DOGSBAY_PAGES__||{})[${JSON.stringify(unit.prefix)}]=${JSON.stringify([...[...infos.values()].filter((i) => i.slug !== replaced).map((i) => i.out), ...generatedOuts])};
|
|
@@ -4829,13 +5021,14 @@ function switchOptions(kind, unit, all, cfg, out, siteRoot, t) {
|
|
|
4829
5021
|
const axis = kind === "version" ? "version" : "locale";
|
|
4830
5022
|
const other = kind === "version" ? "locale" : "version";
|
|
4831
5023
|
if (!unit[axis]) return [];
|
|
4832
|
-
const peers = all.filter((u) => u[other] === unit[other] && u[axis]);
|
|
4833
|
-
const
|
|
5024
|
+
const peers = all.filter((u) => u[other] === unit[other] && sameProduct(u, unit) && u[axis]);
|
|
5025
|
+
const { versions, defaultVersion } = versionsOf(cfg, unit.product);
|
|
5026
|
+
const defs = kind === "version" ? versions : cfg.locales;
|
|
4834
5027
|
const ordered = defs.length ? defs.map((d) => peers.find((u) => u[axis] === d.id)).filter((u) => !!u) : peers;
|
|
4835
|
-
return ordered.filter((u) => !(kind === "version" &&
|
|
4836
|
-
const v = kind === "version" ?
|
|
5028
|
+
return ordered.filter((u) => !(kind === "version" && versions.find((v) => v.id === u.version)?.hidden && u !== unit)).map((u) => {
|
|
5029
|
+
const v = kind === "version" ? versions.find((d) => d.id === u.version) : void 0;
|
|
4837
5030
|
const l = kind === "locale" ? cfg.locales.find((d) => d.id === u.locale) : void 0;
|
|
4838
|
-
const note = v?.eol ? t("eol") : v?.prerelease ? t("prerelease") : v && v.id ===
|
|
5031
|
+
const note = v?.eol ? t("eol") : v?.prerelease ? t("prerelease") : v && v.id === defaultVersion && v.id !== "latest" ? t("latest") : void 0;
|
|
4839
5032
|
return {
|
|
4840
5033
|
label: v?.label ?? l?.label ?? String(u[axis]),
|
|
4841
5034
|
href: `${siteRoot}${u.prefix ? u.prefix + "/" : ""}${out}`,
|
|
@@ -4846,19 +5039,28 @@ function switchOptions(kind, unit, all, cfg, out, siteRoot, t) {
|
|
|
4846
5039
|
});
|
|
4847
5040
|
}
|
|
4848
5041
|
function versionBanner(unit, all, cfg, out, siteRoot, t) {
|
|
5042
|
+
const link = (latest2) => ` <a href="${esc3(`${siteRoot}${latest2.prefix ? latest2.prefix + "/" : ""}${out}`)}" data-db-version-link data-prefix="${esc3(latest2.prefix)}">${esc3(t("goLatest"))}</a>`;
|
|
5043
|
+
if (cfg.products) {
|
|
5044
|
+
if (unit.version === void 0 || versionsOf(cfg, unit.product).versions.find((d) => d.id === unit.version)?.hidden) return void 0;
|
|
5045
|
+
const b = shared(() => unitOf(cfg.products, { product: unit.product, locale: unit.locale, version: unit.version })).banner;
|
|
5046
|
+
if (!b) return void 0;
|
|
5047
|
+
const text = esc3(b.kind === "custom" ? b.text : t(b.kind === "eol" ? "eolVersion" : b.kind === "prerelease" ? "prereleaseVersion" : "oldVersion"));
|
|
5048
|
+
const latest2 = b.latest && all.find((u) => `/${u.prefix ? u.prefix + "/" : ""}` === b.latest.home);
|
|
5049
|
+
return latest2 ? text + link(latest2) : text;
|
|
5050
|
+
}
|
|
4849
5051
|
if (!unit.version || !cfg.defaultVersion || unit.version === cfg.defaultVersion) return void 0;
|
|
4850
5052
|
const v = cfg.versions.find((d) => d.id === unit.version);
|
|
4851
5053
|
if (v?.hidden) return void 0;
|
|
4852
|
-
const latest = all.find((u) => u.version === cfg.defaultVersion && u.locale === unit.locale);
|
|
5054
|
+
const latest = all.find((u) => u.version === cfg.defaultVersion && u.locale === unit.locale && sameProduct(u, unit));
|
|
4853
5055
|
if (!latest) return void 0;
|
|
4854
|
-
return
|
|
5056
|
+
return esc3(t("oldVersion")) + link(latest);
|
|
4855
5057
|
}
|
|
4856
5058
|
async function writeTranslationStubs(cfg, all, built, tables, state, emit, exists = () => false) {
|
|
4857
5059
|
const def = cfg.defaultLocale;
|
|
4858
5060
|
if (!def || !tables.size) return [];
|
|
4859
|
-
const
|
|
5061
|
+
const unitOf2 = (locale, version) => all.find((u) => u.locale === locale && u.version === version && !u.product);
|
|
4860
5062
|
const missing = missingTranslations(
|
|
4861
|
-
all.filter((u) => u.locale).map((u) => {
|
|
5063
|
+
all.filter((u) => u.locale && !u.product).map((u) => {
|
|
4862
5064
|
const t = tables.get(u.prefix);
|
|
4863
5065
|
return { locale: u.locale, version: u.version, pages: !t ? [] : u.locale === def ? t.pages.keys() : [...t.pages.keys(), ...t.redirects.keys()] };
|
|
4864
5066
|
}),
|
|
@@ -4869,9 +5071,9 @@ async function writeTranslationStubs(cfg, all, built, tables, state, emit, exist
|
|
|
4869
5071
|
const written = [];
|
|
4870
5072
|
for (const m of missing) {
|
|
4871
5073
|
if (m.page === "404") continue;
|
|
4872
|
-
const home =
|
|
5074
|
+
const home = unitOf2(def, m.version);
|
|
4873
5075
|
const out = tables.get(home.prefix).pages.get(m.page);
|
|
4874
|
-
const target =
|
|
5076
|
+
const target = unitOf2(m.locale, m.version);
|
|
4875
5077
|
if (!built.includes(target ?? home)) continue;
|
|
4876
5078
|
const to = join(home.prefix, out);
|
|
4877
5079
|
if (built.includes(home) && !pageFiles.has(to)) continue;
|
|
@@ -4882,6 +5084,10 @@ async function writeTranslationStubs(cfg, all, built, tables, state, emit, exist
|
|
|
4882
5084
|
}
|
|
4883
5085
|
return written;
|
|
4884
5086
|
}
|
|
5087
|
+
function relativeHome(from, to) {
|
|
5088
|
+
if (to.startsWith(from)) return to.slice(from.length);
|
|
5089
|
+
return "../".repeat(from.split("/").filter(Boolean).length) + to.slice(1);
|
|
5090
|
+
}
|
|
4885
5091
|
function redirectPage(target, name) {
|
|
4886
5092
|
const u = esc3(target);
|
|
4887
5093
|
return `<!doctype html><html><head><meta charset="utf-8"><title>${esc3(name)}</title><meta name="robots" content="noindex"><meta http-equiv="refresh" content="0; url=${u}"><link rel="canonical" href="${u}"><link rel="icon" href="data:,"></head><body><p><a href="${u}">${esc3(name)}</a></p></body></html>
|
|
@@ -4957,7 +5163,7 @@ function hreflangFor(cfg, unit, all, languages, slug) {
|
|
|
4957
5163
|
const path = slug || "index";
|
|
4958
5164
|
const alts = [];
|
|
4959
5165
|
for (const u of all) {
|
|
4960
|
-
if (!u.locale || u.version !== unit.version) continue;
|
|
5166
|
+
if (!u.locale || u.version !== unit.version || !sameProduct(u, unit)) continue;
|
|
4961
5167
|
const out = languages.get(u.prefix)?.get(path);
|
|
4962
5168
|
const url = out ? absoluteUrl(cfg, u.prefix, servedPath(out, cfg.linkStyle)) : void 0;
|
|
4963
5169
|
if (url) alts.push({ lang: u.locale, url });
|
|
@@ -4969,7 +5175,7 @@ function hreflangFor(cfg, unit, all, languages, slug) {
|
|
|
4969
5175
|
var CONFIG_FILES = /* @__PURE__ */ new Set(["dogsbay.config.yml", "dogsbay.config.yaml"]);
|
|
4970
5176
|
var NAV_FILES2 = /(^|\/)nav\.(ya?ml|json)$/;
|
|
4971
5177
|
var START_ONLY = /(^|\/)(_dogsbay\/search\/|llms(-full)?\.txt$)/;
|
|
4972
|
-
var SITE_WIDE = /^(_dogsbay\/assets\/|_dogsbay\/site\.js$|robots\.txt$|_headers$|_redirects$|sitemap-index\.xml$)/;
|
|
5178
|
+
var SITE_WIDE = /^(_dogsbay\/assets\/|_dogsbay\/(site|versions)\.js$|robots\.txt$|_headers$|_redirects$|sitemap-index\.xml$)/;
|
|
4973
5179
|
var UNIT_CSS = /(^|\/)_dogsbay\/site\.css$/;
|
|
4974
5180
|
async function openDevSession(input, o = {}) {
|
|
4975
5181
|
let out = /* @__PURE__ */ new Map();
|
|
@@ -5014,7 +5220,7 @@ async function openDevSession(input, o = {}) {
|
|
|
5014
5220
|
} catch (e) {
|
|
5015
5221
|
throw inConfig(e, name);
|
|
5016
5222
|
}
|
|
5017
|
-
const nextConfig = { ...parsed, llmsTxt: o.llms === true && parsed.llmsTxt, search: o.search === false ? false : parsed.search };
|
|
5223
|
+
const nextConfig = { ...parsed, llmsTxt: o.llms === true && parsed.llmsTxt, search: o.search === false ? false : parsed.search, math: o.math === false ? false : parsed.math };
|
|
5018
5224
|
try {
|
|
5019
5225
|
await build(
|
|
5020
5226
|
// Drafts are shown while writing, as `dogsbay site dev` shows them.
|
|
@@ -5027,6 +5233,7 @@ async function openDevSession(input, o = {}) {
|
|
|
5027
5233
|
watchScan(c, nextScan);
|
|
5028
5234
|
},
|
|
5029
5235
|
diagnostics: (f, list) => nextDiagnosed.set(f, list),
|
|
5236
|
+
dataLines: o.dataLines,
|
|
5030
5237
|
// A copy: the build keeps adding the classes of pages it renders later to its own set.
|
|
5031
5238
|
unitBuilt: (unit, handle, classes) => nextUnits.set(unit.prefix, { unit, handle, classes: new Set(classes) })
|
|
5032
5239
|
}
|
|
@@ -5046,7 +5253,8 @@ async function openDevSession(input, o = {}) {
|
|
|
5046
5253
|
stale = /* @__PURE__ */ new Set();
|
|
5047
5254
|
if (o.lazy) for (const u of units.values()) for (const p of u.handle.pageOuts) stale.add(p);
|
|
5048
5255
|
};
|
|
5049
|
-
const
|
|
5256
|
+
const noteItems = () => [...ctx?.state.notes.values() ?? []].flat().map((n) => ({ ...n }));
|
|
5257
|
+
const unitOf2 = (path) => {
|
|
5050
5258
|
let best;
|
|
5051
5259
|
let bestLen = -1;
|
|
5052
5260
|
for (const u of units.values()) {
|
|
@@ -5131,7 +5339,7 @@ async function openDevSession(input, o = {}) {
|
|
|
5131
5339
|
const lazy = await textOf(c);
|
|
5132
5340
|
return lazy ?? c;
|
|
5133
5341
|
};
|
|
5134
|
-
const pageFor = (source) =>
|
|
5342
|
+
const pageFor = (source) => unitOf2(source)?.handle.pageForSource(source);
|
|
5135
5343
|
return {
|
|
5136
5344
|
get config() {
|
|
5137
5345
|
return config;
|
|
@@ -5147,8 +5355,9 @@ async function openDevSession(input, o = {}) {
|
|
|
5147
5355
|
return unitForSitePath(path)?.handle.sourceForPage(path);
|
|
5148
5356
|
},
|
|
5149
5357
|
notes() {
|
|
5150
|
-
return
|
|
5358
|
+
return noteItems().map((n) => n.message);
|
|
5151
5359
|
},
|
|
5360
|
+
noteItems,
|
|
5152
5361
|
takeWarnings() {
|
|
5153
5362
|
const all = ctx?.warnings ?? [];
|
|
5154
5363
|
const fresh = all.slice(taken);
|
|
@@ -5241,7 +5450,7 @@ async function openDevSession(input, o = {}) {
|
|
|
5241
5450
|
if (CONFIG_FILES.has(p)) continue;
|
|
5242
5451
|
const readers = [...units.values()].filter((u2) => u2.handle.navInputs.includes(p) || u2.unit.members.some((m) => m.source.nav === p));
|
|
5243
5452
|
if (readers.length) {
|
|
5244
|
-
for (const u2 of [...readers,
|
|
5453
|
+
for (const u2 of [...readers, unitOf2(p)]) if (u2) lazy.add(u2.unit.prefix);
|
|
5245
5454
|
mark("unit");
|
|
5246
5455
|
continue;
|
|
5247
5456
|
}
|
|
@@ -5263,7 +5472,7 @@ async function openDevSession(input, o = {}) {
|
|
|
5263
5472
|
}
|
|
5264
5473
|
continue;
|
|
5265
5474
|
}
|
|
5266
|
-
const u =
|
|
5475
|
+
const u = unitOf2(p);
|
|
5267
5476
|
if (!u) continue;
|
|
5268
5477
|
const content = input.files.get(p);
|
|
5269
5478
|
if (/\.(md|markdown)$/i.test(p)) {
|
|
@@ -5289,6 +5498,7 @@ async function openDevSession(input, o = {}) {
|
|
|
5289
5498
|
const at = memberPath(u.unit, p)?.path ?? p.slice(sourceRoot(u.unit.source).length);
|
|
5290
5499
|
const key = u.unit.prefix ? `${u.unit.prefix}/${at}` : at;
|
|
5291
5500
|
const sanitizing = (config.html ?? input.defaultHtml ?? "keep") === "sanitize";
|
|
5501
|
+
if (key === "_headers" || key === "_redirects") continue;
|
|
5292
5502
|
if (copiedPath(at) && await assetVerdict(at, content, input.untrusted === true, sanitizing) === "copy") out.set(key, content);
|
|
5293
5503
|
else out.delete(key);
|
|
5294
5504
|
}
|
|
@@ -5315,10 +5525,12 @@ async function openDevSession(input, o = {}) {
|
|
|
5315
5525
|
units.set(prefix, next);
|
|
5316
5526
|
for (const o2 of handle.pageOuts) markStale(o2, next, true);
|
|
5317
5527
|
}
|
|
5318
|
-
|
|
5528
|
+
const isDefault = (u) => u.version !== void 0 && u.version === versionsOf(config, u.product).defaultVersion;
|
|
5529
|
+
const changedDefaults = [...lazy].map((prefix) => units.get(prefix)?.unit).filter((u) => !!u && isDefault(u));
|
|
5530
|
+
if (changedDefaults.length) {
|
|
5319
5531
|
const all = [...units.values()].map((u) => u.unit);
|
|
5320
5532
|
ctx.state.canonical = await defaultTables(config, all, all, input.files, readText);
|
|
5321
|
-
for (const u of units.values()) if (u.unit.version !==
|
|
5533
|
+
for (const u of units.values()) if (u.unit.version !== void 0 && !isDefault(u.unit) && changedDefaults.some((d) => (d.product ?? "") === (u.unit.product ?? ""))) for (const o2 of u.handle.pageOuts) markStale(o2, u);
|
|
5322
5534
|
}
|
|
5323
5535
|
if (lazy.size && ctx.state.languages) {
|
|
5324
5536
|
const all = [...units.values()].map((u) => u.unit);
|
|
@@ -201,19 +201,29 @@ export interface BuiltPage {
|
|
|
201
201
|
/** The parsed body, after templating. */
|
|
202
202
|
tree: TreeNode[];
|
|
203
203
|
}
|
|
204
|
+
/** A note (BuildResult.notes) as data: its text, and the page it is about when there is one. */
|
|
205
|
+
export interface BuildNote {
|
|
206
|
+
message: string;
|
|
207
|
+
/** The page's source file, a project path (the content page standing as a mounted API's root). */
|
|
208
|
+
file?: string;
|
|
209
|
+
/** The page's path in the site (`3.32/reference/rest-api`), as the message names it. */
|
|
210
|
+
page?: string;
|
|
211
|
+
}
|
|
204
212
|
/** What the site-level files need from every unit. Small: a few strings per page. */
|
|
205
213
|
export interface SiteState {
|
|
206
214
|
redirects: RedirectInput[];
|
|
207
215
|
/** What the build says about the content, not a problem, by unit prefix (replaced when a unit is built again). */
|
|
208
|
-
notes: Map<string,
|
|
216
|
+
notes: Map<string, BuildNote[]>;
|
|
209
217
|
/** The sidebar items kept between pages (src/theme/regions.ts). */
|
|
210
218
|
navCache: NavCache;
|
|
211
219
|
/** Site path ("en/latest/guide/x") → output file relative to the site root. */
|
|
212
220
|
pageOut: Map<string, string>;
|
|
213
221
|
/** Sitemap files, relative to the site root, by unit prefix. */
|
|
214
222
|
sitemaps: Map<string, string[]>;
|
|
215
|
-
/** Site-level files a content root supplies itself (robots.txt,
|
|
223
|
+
/** Site-level files a content root supplies itself (robots.txt, the sitemap index); they win over generated ones. */
|
|
216
224
|
supplied: Set<string>;
|
|
225
|
+
/** The root's own `_headers` and `_redirects`, merged with the generated ones (@dogsbay/site-files host-files.ts). */
|
|
226
|
+
hostFiles: Map<string, FileContent>;
|
|
217
227
|
/** A page rendered math, so the KaTeX stylesheet and fonts are written. */
|
|
218
228
|
usedMath: boolean;
|
|
219
229
|
/** Rendered diagrams, shared by the units of the build. */
|
|
@@ -309,6 +319,9 @@ export interface PageDiagnostic {
|
|
|
309
319
|
line?: number;
|
|
310
320
|
/** The directive's name, without colons, on `unknown-container` and `unknown-inline`. */
|
|
311
321
|
name?: string;
|
|
322
|
+
/** The part of `line` meant, when the parser knows it: 1-based UTF-16 code units, `endColumn` exclusive. Only with `line`. */
|
|
323
|
+
column?: number;
|
|
324
|
+
endColumn?: number;
|
|
312
325
|
}
|
|
313
326
|
/**
|
|
314
327
|
* The parser's diagnostics on `parsed` (the body after templating) with lines in the file: `line`,
|
|
@@ -318,6 +331,15 @@ export interface PageDiagnostic {
|
|
|
318
331
|
* it names are the templated page's. Messages are detached (a session keeps them; some quote a line).
|
|
319
332
|
*/
|
|
320
333
|
export declare function linedDiagnostics(found: ParseDiagnostic[], raw: string, body: string, parsed: string, after?: string): PageDiagnostic[];
|
|
334
|
+
/**
|
|
335
|
+
* A page's block lines (`meta.line`, from the parser's `sourceLines`) as lines of its file: `parsed`
|
|
336
|
+
* is the body after templating, `body` as written, `raw` the file. The front matter moves every line
|
|
337
|
+
* by its length. Templating that keeps the line count (variables, one-line includes) keeps each
|
|
338
|
+
* line where it was. One that changes it (an include, a condition) keeps the lines before and after
|
|
339
|
+
* the change, and a block in between loses its line: a wrong line would scroll the editor elsewhere.
|
|
340
|
+
* Changes the tree in place.
|
|
341
|
+
*/
|
|
342
|
+
export declare function sourceLinesOf(tree: unknown, raw: string, body: string, parsed: string): void;
|
|
321
343
|
/** A file's text, read now if it is lazy. */
|
|
322
344
|
export declare function readText(c: FileContent): Promise<string>;
|
|
323
345
|
/**
|
|
@@ -379,6 +401,7 @@ export interface BuildContext {
|
|
|
379
401
|
theme: LoadedTheme;
|
|
380
402
|
state: SiteState;
|
|
381
403
|
diagnostics?: BuildHooks["diagnostics"];
|
|
404
|
+
dataLines?: boolean;
|
|
382
405
|
}
|
|
383
406
|
/** Internal: a dev session's view of a build (see src/core/dev.ts). */
|
|
384
407
|
export interface BuildHooks {
|
|
@@ -392,15 +415,20 @@ export interface BuildHooks {
|
|
|
392
415
|
* path, and the list (empty when it has none, so a fixed page clears).
|
|
393
416
|
*/
|
|
394
417
|
diagnostics?: (file: string, list: PageDiagnostic[]) => void;
|
|
418
|
+
/**
|
|
419
|
+
* Mark each block with its line in the page's file (`data-line`, render-html's `dataLines`), for
|
|
420
|
+
* an editor's scroll sync. Lines templating moved are left out (`sourceLinesOf`).
|
|
421
|
+
*/
|
|
422
|
+
dataLines?: boolean;
|
|
395
423
|
unitBuilt?: (unit: BuildUnit, handle: UnitHandle, classes: Set<string>) => void;
|
|
396
424
|
}
|
|
397
425
|
/** Build one unit again without rendering its pages (they are rendered on request). */
|
|
398
426
|
export declare function rebuildUnitLazy(ctx: BuildContext, unit: BuildUnit): Promise<UnitHandle>;
|
|
399
427
|
export declare function build(input: BuildInput, hooks?: BuildHooks): Promise<BuildResult>;
|
|
400
|
-
/** robots.txt, _headers, the sitemap index and redirects: the files that belong to the whole site. */
|
|
401
428
|
/**
|
|
402
|
-
* The units `--unit` names: by prefix
|
|
403
|
-
*
|
|
429
|
+
* The units `--unit` names: by prefix; a version served at the root (prefix "", the locale or
|
|
430
|
+
* the product) also by its id, and inside a product by `<product>/<id>`; and a product by its
|
|
431
|
+
* name, which is all its versions and locales. Throws on a name that is no unit.
|
|
404
432
|
*/
|
|
405
433
|
export declare function selectUnits(allUnits: BuildUnit[], names: string[] | undefined): BuildUnit[];
|
|
406
434
|
/**
|
|
@@ -31,8 +31,7 @@ export type FrontMatterOf = (path: string, c: FileContent) => Promise<Record<str
|
|
|
31
31
|
*/
|
|
32
32
|
export declare function frontMatterCache(read: Read): FrontMatterOf;
|
|
33
33
|
/**
|
|
34
|
-
* One table per language of the default version, keyed by
|
|
35
|
-
* without a locale axis). Empty when none of the units being built is an
|
|
34
|
+
* One table per language of the default version and per product, keyed by `tableKey`. Empty when none of the units being built is an
|
|
36
35
|
* older version (then nothing points elsewhere, and nothing is read).
|
|
37
36
|
*/
|
|
38
37
|
export declare function defaultTables(cfg: SiteConfig, units: BuildUnit[], built: BuildUnit[], files: Map<string, FileContent>, read: Read, warn?: (m: string) => void, fm?: FrontMatterOf): Promise<Map<string, DefaultTable>>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type ProductModel } from "@dogsbay/site-files";
|
|
1
2
|
export type LinkStyle = "html" | "pretty";
|
|
2
3
|
export type TocMode = "top" | "popover" | "rail" | "off";
|
|
3
4
|
export interface VersionDef {
|
|
@@ -14,9 +15,26 @@ export interface VersionDef {
|
|
|
14
15
|
noindex?: boolean;
|
|
15
16
|
/** Override whether the version's pages are in the sitemap. */
|
|
16
17
|
sitemap?: boolean;
|
|
17
|
-
/**
|
|
18
|
-
|
|
18
|
+
/**
|
|
19
|
+
* The version's URL segment when it is not its id. `""`: served at the root (no version segment),
|
|
20
|
+
* only on the default version. Any other segment (`latest`) only inside `content.products:`.
|
|
21
|
+
*/
|
|
22
|
+
path?: string;
|
|
23
|
+
/** The version's own banner text (`content.products:` only), instead of the standard one. */
|
|
24
|
+
banner?: string;
|
|
25
|
+
}
|
|
26
|
+
/** A call into @dogsbay/site-files' product model, its config errors reported as ours (dev and the CLI tell them apart). */
|
|
27
|
+
export declare function shared<T>(f: () => T): T;
|
|
28
|
+
/** The versions a unit's product has, and its default. */
|
|
29
|
+
export interface ProductVersions {
|
|
30
|
+
versions: VersionDef[];
|
|
31
|
+
defaultVersion?: string;
|
|
19
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* A product's versions and default: its own with `content.products:`, else the site-wide `versions:`
|
|
35
|
+
* and `defaultVersion` (the unnamed source's, and every product's without the block).
|
|
36
|
+
*/
|
|
37
|
+
export declare function versionsOf(cfg: Pick<SiteConfig, "versions" | "defaultVersion" | "productVersions">, product: string | undefined): ProductVersions;
|
|
20
38
|
export interface LocaleDef {
|
|
21
39
|
id: string;
|
|
22
40
|
label: string;
|
|
@@ -72,6 +90,10 @@ export interface SiteConfig {
|
|
|
72
90
|
routablesFrom: "all" | "nav";
|
|
73
91
|
versions: VersionDef[];
|
|
74
92
|
defaultVersion?: string;
|
|
93
|
+
/** `content.products:`, read by @dogsbay/site-files' `productModel` (plans/product-versions-ssg.md). Undefined without the block. */
|
|
94
|
+
products?: ProductModel;
|
|
95
|
+
/** With `products`: each product's versions and default (key `""` for the unnamed source's), read through `versionsOf`. */
|
|
96
|
+
productVersions?: Map<string, ProductVersions>;
|
|
75
97
|
locales: LocaleDef[];
|
|
76
98
|
defaultLocale?: string;
|
|
77
99
|
search: boolean;
|
|
@@ -274,10 +296,26 @@ export interface BuildUnit {
|
|
|
274
296
|
/** Every source the unit builds, the main one included, in config order. */
|
|
275
297
|
members: UnitMember[];
|
|
276
298
|
version?: string;
|
|
299
|
+
/** The version's URL segment: its id, its `path` (`latest`), or `""` when served without one. */
|
|
300
|
+
versionPath?: string;
|
|
277
301
|
locale?: string;
|
|
278
|
-
/**
|
|
302
|
+
/**
|
|
303
|
+
* The named source the unit publishes, when named sources are combined with versions or locales
|
|
304
|
+
* (a product): its first prefix segment, as the CLI's `/<name>/<locale>/<version>/` order.
|
|
305
|
+
* Units of one product share it; the unnamed source's units have none.
|
|
306
|
+
*/
|
|
307
|
+
product?: string;
|
|
308
|
+
/** Output prefix inside the site, e.g. "en/3.31", "calico/3.31", or "" when no axis is active. */
|
|
279
309
|
prefix: string;
|
|
280
310
|
}
|
|
311
|
+
/**
|
|
312
|
+
* The prefix of a unit's product and locale, without its version: where the unit's
|
|
313
|
+
* versions sit side by side ("calico/en", "en", or ""). A version served at the root
|
|
314
|
+
* (`path: ""`) has this as its prefix.
|
|
315
|
+
*/
|
|
316
|
+
export declare function groupPrefix(u: Pick<BuildUnit, "product" | "locale">): string;
|
|
317
|
+
/** Whether two units are versions or languages of the same product (or both of no product). */
|
|
318
|
+
export declare const sameProduct: (a: Pick<BuildUnit, "product">, b: Pick<BuildUnit, "product">) => boolean;
|
|
281
319
|
/**
|
|
282
320
|
* Expand sources into units. An axis is "active" (adds a URL segment)
|
|
283
321
|
* when the sources carry two or more distinct values for it, or when
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
* Node-free: the dev server (src/node/dev.ts) owns the file map and the
|
|
30
30
|
* watcher, and updates `input.files` before calling `change`.
|
|
31
31
|
*/
|
|
32
|
-
import { type BuildProblem, type PageDiagnostic, type BuildInput, type OutputContent } from "./build.js";
|
|
32
|
+
import { type BuildNote, type BuildProblem, type PageDiagnostic, type BuildInput, type OutputContent } from "./build.js";
|
|
33
33
|
import { type SiteConfig } from "./config.js";
|
|
34
34
|
export interface DevSession {
|
|
35
35
|
config: SiteConfig;
|
|
@@ -45,6 +45,8 @@ export interface DevSession {
|
|
|
45
45
|
takeWarnings(): string[];
|
|
46
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
47
|
notes(): string[];
|
|
48
|
+
/** The same notes as data: each with the page it is about, its source file (a project path) and its path in the site. */
|
|
49
|
+
noteItems(): BuildNote[];
|
|
48
50
|
/**
|
|
49
51
|
* The same warnings as data, not handed out yet (its own count: taking one kind leaves the other):
|
|
50
52
|
* the file each is about as a project path, with its line when known, and a code.
|
|
@@ -101,6 +103,13 @@ export interface DevOptions {
|
|
|
101
103
|
search?: boolean;
|
|
102
104
|
/** Build llms.txt, its section files and llms-full.txt at the start (default: no). */
|
|
103
105
|
llms?: boolean;
|
|
106
|
+
/**
|
|
107
|
+
* Mark each block with its line in the page's file (`data-line`), for an editor's scroll sync.
|
|
108
|
+
* Lines templating moved are left out (`sourceLinesOf` in build.ts). Default: no.
|
|
109
|
+
*/
|
|
110
|
+
dataLines?: boolean;
|
|
111
|
+
/** `false`: leave math as LaTeX (`<code class="math-display">` and inline), for a host that renders it itself. Default: as the config says. */
|
|
112
|
+
math?: boolean;
|
|
104
113
|
}
|
|
105
114
|
export declare function openDevSession(input: BuildInput & {
|
|
106
115
|
configText?: string;
|
|
@@ -19,7 +19,7 @@ export declare function openDevSession(input: BuildInput & {
|
|
|
19
19
|
configText?: string;
|
|
20
20
|
}, o?: DevOptions): Promise<DevSession>;
|
|
21
21
|
export { prebuiltSiteCss };
|
|
22
|
-
export type { BuildInput, BuildResult, FileContent, OutputContent, SinkContent, SiteCssBuilder, BuiltPage, HighlightPool, BuildProblem, PageDiagnostic } from "../core/build.js";
|
|
22
|
+
export type { BuildInput, BuildResult, FileContent, OutputContent, SinkContent, SiteCssBuilder, BuiltPage, HighlightPool, BuildProblem, BuildNote, PageDiagnostic } from "../core/build.js";
|
|
23
23
|
export { PageClashError } from "../core/build.js";
|
|
24
24
|
export type { ChangeResult, DevOptions, DevSession } from "../core/dev.js";
|
|
25
25
|
export { parseConfig, projectRoots, ConfigError, type SiteConfig, type DiagramEngine } from "../core/config.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.146",
|
|
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.146",
|
|
53
|
+
"@dogsbay/format-dogsbay-md": "0.2.0-beta.146",
|
|
54
|
+
"@dogsbay/format-openapi": "0.2.0-beta.146",
|
|
55
|
+
"@dogsbay/format-topicmap": "0.2.0-beta.146",
|
|
56
|
+
"@dogsbay/highlight": "0.2.0-beta.146",
|
|
57
|
+
"@dogsbay/minja": "0.2.0-beta.146",
|
|
58
|
+
"@dogsbay/primitives": "0.2.0-beta.146",
|
|
59
|
+
"@dogsbay/render-html": "0.2.0-beta.146",
|
|
60
|
+
"@dogsbay/search": "0.2.0-beta.146",
|
|
61
|
+
"@dogsbay/serialize-core": "0.2.0-beta.146",
|
|
62
|
+
"@dogsbay/site-check": "0.2.0-beta.146",
|
|
63
|
+
"@dogsbay/site-files": "0.2.0-beta.146",
|
|
64
|
+
"@dogsbay/types": "0.2.0-beta.146"
|
|
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.146",
|
|
70
|
+
"@dogsbay/format-dogsbay-md": "0.2.0-beta.146",
|
|
71
|
+
"@dogsbay/format-openapi": "0.2.0-beta.146",
|
|
72
|
+
"@dogsbay/format-topicmap": "0.2.0-beta.146",
|
|
73
|
+
"@dogsbay/highlight": "0.2.0-beta.146",
|
|
74
|
+
"@dogsbay/icons": "0.2.0-beta.146",
|
|
75
|
+
"@dogsbay/minja": "0.2.0-beta.146",
|
|
76
|
+
"@dogsbay/primitives": "0.2.0-beta.146",
|
|
77
|
+
"@dogsbay/render-html": "0.2.0-beta.146",
|
|
78
|
+
"@dogsbay/search": "0.2.0-beta.146",
|
|
79
|
+
"@dogsbay/serialize-core": "0.2.0-beta.146",
|
|
80
|
+
"@dogsbay/site-check": "0.2.0-beta.146",
|
|
81
|
+
"@dogsbay/site-files": "0.2.0-beta.146",
|
|
82
|
+
"@dogsbay/types": "0.2.0-beta.146",
|
|
83
|
+
"@dogsbay/ui": "0.2.0-beta.146",
|
|
84
84
|
"@mermanjs/web": "0.7.0",
|
|
85
85
|
"@playwright/test": "1.61.1",
|
|
86
86
|
"@types/node": "^22.10.0",
|