@dogsbay/ssg 0.2.0-beta.151 → 0.2.0-beta.151.1
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/browser.mjs +389 -28
- package/dist/package/types/core/build.d.ts +19 -4
- package/dist/package/types/core/icon-notices.d.ts +9 -0
- package/dist/package/types/core/site-files.d.ts +6 -0
- package/dist/package/types/core/unit-manifest.d.ts +74 -0
- package/dist/package/types/generated/assets.d.ts +7 -0
- package/dist/package/types/generated/icon-notices.d.ts +2 -0
- package/package.json +1 -1
package/dist/package/browser.mjs
CHANGED
|
@@ -1207,15 +1207,12 @@ function renderRedirectPage(rule, cfg) {
|
|
|
1207
1207
|
const canonical = isExternal(rule.to) ? rule.to : rule.toOut ? absoluteUrl(cfg, "", servedPath(rule.toOut, cfg.linkStyle)) : void 0;
|
|
1208
1208
|
return renderRedirectStub(href, canonical);
|
|
1209
1209
|
}
|
|
1210
|
-
function
|
|
1210
|
+
function servedRedirect(r, cfg) {
|
|
1211
1211
|
const served = (sitePathOrOut) => "/" + [cfg.basePath, sitePathOrOut].filter(Boolean).join("/");
|
|
1212
|
-
return
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
status: r.status
|
|
1217
|
-
}))
|
|
1218
|
-
);
|
|
1212
|
+
return { from: served(r.from), to: isExternal(r.to) ? r.to : served(r.toOut ? servedPath(r.toOut, cfg.linkStyle) : r.to) + (r.suffix ?? ""), status: r.status };
|
|
1213
|
+
}
|
|
1214
|
+
function renderRedirectsFile(rules, cfg) {
|
|
1215
|
+
return renderRedirectsLines(rules.map((r) => servedRedirect(r, cfg)));
|
|
1219
1216
|
}
|
|
1220
1217
|
|
|
1221
1218
|
// src/core/canonical.ts
|
|
@@ -1362,6 +1359,8 @@ var CLIENT_JS = `/*! dogsbay-ssg site client (Apache-2.0). Third-party notices:
|
|
|
1362
1359
|
Expects a CSS selector, a Node element, a NodeList or an array.
|
|
1363
1360
|
See: https://github.com/francoischalifour/medium-zoom\`)}},no=function(t){var e=document.createElement("div");return e.classList.add("medium-zoom-overlay"),e.style.background=t,e},so=function(t){var e=t.getBoundingClientRect(),n=e.top,s=e.left,o=e.width,r=e.height,a=t.cloneNode(),l=window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0,c=window.pageXOffset||document.documentElement.scrollLeft||document.body.scrollLeft||0;return a.removeAttribute("id"),a.style.position="absolute",a.style.top=n+l+"px",a.style.left=s+c+"px",a.style.width=o+"px",a.style.height=r+"px",a.style.transform="",a},kt=function(t,e){var n=pt({bubbles:!1,cancelable:!1,detail:void 0},e);if(typeof window.CustomEvent=="function")return new CustomEvent(t,n);var s=document.createEvent("CustomEvent");return s.initCustomEvent(t,n.bubbles,n.cancelable,n.detail),s},oo=function i(t){var e=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},n=window.Promise||function(x){function E(){}x(E,E)},s=function(x){var E=x.target;if(E===q){p();return}L.indexOf(E)!==-1&&b({target:E})},o=function(){if(!(I||!v.original)){var x=window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0;Math.abs(H-x)>O.scrollOffset&&setTimeout(p,150)}},r=function(x){var E=x.key||x.keyCode;(E==="Escape"||E==="Esc"||E===27)&&p()},a=function(){var x=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},E=x;if(x.background&&(q.style.background=x.background),x.container&&x.container instanceof Object&&(E.container=pt({},O.container,x.container)),x.template){var C=ne(x.template)?x.template:document.querySelector(x.template);E.template=C}return O=pt({},O,E),L.forEach(function(T){T.dispatchEvent(kt("medium-zoom:update",{detail:{zoom:M}}))}),M},l=function(){var x=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};return i(pt({},O,x))},c=function(){for(var x=arguments.length,E=Array(x),C=0;C<x;C++)E[C]=arguments[C];var T=E.reduce(function(A,k){return[].concat(A,rn(k))},[]);return T.filter(function(A){return L.indexOf(A)===-1}).forEach(function(A){L.push(A),A.classList.add("medium-zoom-image")}),R.forEach(function(A){var k=A.type,D=A.listener,_=A.options;T.forEach(function(P){P.addEventListener(k,D,_)})}),M},d=function(){for(var x=arguments.length,E=Array(x),C=0;C<x;C++)E[C]=arguments[C];v.zoomed&&p();var T=E.length>0?E.reduce(function(A,k){return[].concat(A,rn(k))},[]):L;return T.forEach(function(A){A.classList.remove("medium-zoom-image"),A.dispatchEvent(kt("medium-zoom:detach",{detail:{zoom:M}}))}),L=L.filter(function(A){return T.indexOf(A)===-1}),M},u=function(x,E){var C=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{};return L.forEach(function(T){T.addEventListener("medium-zoom:"+x,E,C)}),R.push({type:"medium-zoom:"+x,listener:E,options:C}),M},f=function(x,E){var C=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{};return L.forEach(function(T){T.removeEventListener("medium-zoom:"+x,E,C)}),R=R.filter(function(T){return!(T.type==="medium-zoom:"+x&&T.listener.toString()===E.toString())}),M},m=function(){var x=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},E=x.target,C=function(){var A={width:document.documentElement.clientWidth,height:document.documentElement.clientHeight,left:0,top:0,right:0,bottom:0},k=void 0,D=void 0;if(O.container)if(O.container instanceof Object)A=pt({},A,O.container),k=A.width-A.left-A.right-O.margin*2,D=A.height-A.top-A.bottom-O.margin*2;else{var _=ne(O.container)?O.container:document.querySelector(O.container),P=_.getBoundingClientRect(),tt=P.width,qt=P.height,dn=P.left,un=P.top;A=pt({},A,{width:tt,height:qt,left:dn,top:un})}k=k||A.width-O.margin*2,D=D||A.height-O.margin*2;var Ot=v.zoomedHd||v.original,hn=on(Ot)?k:Ot.naturalWidth||k,fn=on(Ot)?D:Ot.naturalHeight||D,Kt=Ot.getBoundingClientRect(),mn=Kt.top,pn=Kt.left,ae=Kt.width,le=Kt.height,gn=Math.min(Math.max(ae,hn),k)/ae,bn=Math.min(Math.max(le,fn),D)/le,ce=Math.min(gn,bn),vn=(-pn+(k-ae)/2+O.margin+A.left)/ce,yn=(-mn+(D-le)/2+O.margin+A.top)/ce,Re="scale("+ce+") translate3d("+vn+"px, "+yn+"px, 0)";v.zoomed.style.transform=Re,v.zoomedHd&&(v.zoomedHd.style.transform=Re)};return new n(function(T){if(E&&L.indexOf(E)===-1){T(M);return}var A=function tt(){I=!1,v.zoomed.removeEventListener("transitionend",tt),v.original.dispatchEvent(kt("medium-zoom:opened",{detail:{zoom:M}})),T(M)};if(v.zoomed){T(M);return}if(E)v.original=E;else if(L.length>0){var k=L;v.original=k[0]}else{T(M);return}if(v.original.dispatchEvent(kt("medium-zoom:open",{detail:{zoom:M}})),H=window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0,I=!0,v.zoomed=so(v.original),document.body.appendChild(q),O.template){var D=ne(O.template)?O.template:document.querySelector(O.template);v.template=document.createElement("div"),v.template.appendChild(D.content.cloneNode(!0)),document.body.appendChild(v.template)}if(v.original.parentElement&&v.original.parentElement.tagName==="PICTURE"&&v.original.currentSrc&&(v.zoomed.src=v.original.currentSrc),document.body.appendChild(v.zoomed),window.requestAnimationFrame(function(){document.body.classList.add("medium-zoom--opened")}),v.original.classList.add("medium-zoom-image--hidden"),v.zoomed.classList.add("medium-zoom-image--opened"),v.zoomed.addEventListener("click",p),v.zoomed.addEventListener("transitionend",A),v.original.getAttribute("data-zoom-src")){v.zoomedHd=v.zoomed.cloneNode(),v.zoomedHd.removeAttribute("srcset"),v.zoomedHd.removeAttribute("sizes"),v.zoomedHd.removeAttribute("loading"),v.zoomedHd.src=v.zoomed.getAttribute("data-zoom-src"),v.zoomedHd.onerror=function(){clearInterval(_),console.warn("Unable to reach the zoom image target "+v.zoomedHd.src),v.zoomedHd=null,C()};var _=setInterval(function(){v.zoomedHd.complete&&(clearInterval(_),v.zoomedHd.classList.add("medium-zoom-image--opened"),v.zoomedHd.addEventListener("click",p),document.body.appendChild(v.zoomedHd),C())},10)}else if(v.original.hasAttribute("srcset")){v.zoomedHd=v.zoomed.cloneNode(),v.zoomedHd.removeAttribute("sizes"),v.zoomedHd.removeAttribute("loading");var P=v.zoomedHd.addEventListener("load",function(){v.zoomedHd.removeEventListener("load",P),v.zoomedHd.classList.add("medium-zoom-image--opened"),v.zoomedHd.addEventListener("click",p),document.body.appendChild(v.zoomedHd),C()})}else C()})},p=function(){return new n(function(x){if(I||!v.original){x(M);return}var E=function C(){v.original.classList.remove("medium-zoom-image--hidden"),document.body.removeChild(v.zoomed),v.zoomedHd&&document.body.removeChild(v.zoomedHd),document.body.removeChild(q),v.zoomed.classList.remove("medium-zoom-image--opened"),v.template&&document.body.removeChild(v.template),I=!1,v.zoomed.removeEventListener("transitionend",C),v.original.dispatchEvent(kt("medium-zoom:closed",{detail:{zoom:M}})),v.original=null,v.zoomed=null,v.zoomedHd=null,v.template=null,x(M)};I=!0,document.body.classList.remove("medium-zoom--opened"),v.zoomed.style.transform="",v.zoomedHd&&(v.zoomedHd.style.transform=""),v.template&&(v.template.style.transition="opacity 150ms",v.template.style.opacity=0),v.original.dispatchEvent(kt("medium-zoom:close",{detail:{zoom:M}})),v.zoomed.addEventListener("transitionend",E)})},b=function(){var x=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},E=x.target;return v.original?p():m({target:E})},g=function(){return O},y=function(){return L},w=function(){return v.original},L=[],R=[],I=!1,H=0,O=e,v={original:null,zoomed:null,zoomedHd:null,template:null};Object.prototype.toString.call(t)==="[object Object]"?O=t:(t||typeof t=="string")&&c(t),O=pt({margin:0,background:"#fff",scrollOffset:40,container:null,template:null},O);var q=no(O.background);document.addEventListener("click",s),document.addEventListener("keyup",r),document.addEventListener("scroll",o),window.addEventListener("resize",p);var M={open:m,close:p,toggle:b,update:a,clone:l,attach:c,detach:d,on:u,off:f,getOptions:g,getImages:y,getZoomedImage:w};return M};function ro(i,t){t===void 0&&(t={});var e=t.insertAt;if(!(!i||typeof document>"u")){var n=document.head||document.getElementsByTagName("head")[0],s=document.createElement("style");s.type="text/css",e==="top"&&n.firstChild?n.insertBefore(s,n.firstChild):n.appendChild(s),s.styleSheet?s.styleSheet.cssText=i:s.appendChild(document.createTextNode(i))}}var ao=".medium-zoom-overlay{position:fixed;top:0;right:0;bottom:0;left:0;opacity:0;transition:opacity .3s;will-change:opacity}.medium-zoom--opened .medium-zoom-overlay{cursor:pointer;cursor:zoom-out;opacity:1}.medium-zoom-image{cursor:pointer;cursor:zoom-in;transition:transform .3s cubic-bezier(.2,0,.2,1)!important}.medium-zoom-image--hidden{visibility:hidden}.medium-zoom-image--opened{position:relative;cursor:pointer;cursor:zoom-out;will-change:transform}";ro(ao);var an=oo;var lo;function ln(i){let t=document.body.dataset.imageZoom;if(!t)return;let e;try{e=JSON.parse(t)}catch{return}let n=[...document.querySelectorAll('img[data-zoomable="true"]')];if(!n.length)return;let s=lo??(lo=an());s.update(e),s.attach(...n),i==null||i.addEventListener("abort",()=>{s.close(),s.detach(...n)});let o={signal:i},r=!1,a=l=>l.key==="Enter"||l.key===" ";for(let l of n)l.alt&&(l.tabIndex=0,l.addEventListener("keydown",c=>{a(c)&&(c.preventDefault(),r=!0,s.open({target:l}))},o),l.addEventListener("medium-zoom:opened",()=>{let c=document.querySelector(".medium-zoom-image--opened");!r||!c||(c.tabIndex=-1,c.addEventListener("keydown",d=>{a(d)&&(d.preventDefault(),s.close())}),c.focus())},o),l.addEventListener("medium-zoom:closed",()=>{r&&l.focus(),r=!1},o))}function se(i){return!/^[\\x00-\\x20]*([a-z][a-z0-9+.-]*:|[\\\\/])/i.test(i.replace(/[\\t\\n\\r]/g,""))}var Oe=new Map;function cn(i){let t=Oe.get(i);return t||(t=new Promise((e,n)=>{let s=document.createElement("script");s.src=i,s.onload=()=>e(),s.onerror=()=>{Oe.delete(i),n(new Error(\`could not load \${i}\`))},document.head.appendChild(s)}),Oe.set(i,t)),t}function co(i){document.querySelectorAll("[data-component='theme-toggle']").forEach(t=>{let e=()=>t.setAttribute("aria-pressed",String(document.documentElement.classList.contains("dark")));e(),t.addEventListener("click",()=>{let n=!document.documentElement.classList.contains("dark");document.documentElement.classList.toggle("dark",n);try{localStorage.setItem("theme",n?"dark":"light")}catch{}e()},{signal:i})})}function uo(i){document.addEventListener("click",async t=>{var s,o,r,a;let e=t.target.closest("[data-copy-markdown]");if(!e)return;let n=(((s=document.getElementById("db-page-markdown"))==null?void 0:s.textContent)??"").replace(/<\\\\\\/(script)/gi,"</$1").replace(/<\\\\!--/g,"<!--");try{await navigator.clipboard.writeText(n);let l=(o=e.dataset).label??(o.label=e.textContent??"");e.textContent="Copied",clearTimeout(Number(e.dataset.timer)),e.dataset.timer=String(setTimeout(()=>e.textContent=l,1500))}catch{}(a=(r=e.closest("db-popover"))==null?void 0:r.close)==null||a.call(r,"close-press")},{signal:i})}function ho(i,t){let e=document.body.dataset.page??"index.html";document.querySelectorAll("select[data-db-switch]").forEach(n=>{n.addEventListener("change",async()=>{var a;let s=n.selectedOptions[0];if(!s||s.disabled||!s.hasAttribute("value"))return;let o=s.dataset.prefix??"",r=n.value;if(s.hasAttribute("data-link")){(se(r)||/^https?:\\/\\//i.test(r))&&(location.href=r);return}if(!(!se(r)||!se(o))){if(n.dataset.dbSwitch==="product"){location.href=r;return}try{let l=o?\`\${i}\${o}/\`:i;await cn(\`\${l}_dogsbay/pages.js\`);let c=(a=window.__DOGSBAY_PAGES__)==null?void 0:a[o];location.href=c&&!c.includes(e)?\`\${l}index.html\`:r}catch{location.href=r}}},{signal:t})})}function fo(i){document.addEventListener("click",t=>{var n;let e=t.target.closest("a.db-anchor");!e||location.protocol==="file:"||(n=navigator.clipboard)==null||n.writeText(e.href).catch(()=>{})},{signal:i})}var Bt=new Map,re=new Set;function oe(){for(let[i,t]of Bt)i.isConnected||(ot(i),t.abort(),Bt.delete(i));for(let i of re)i.isConnected||ot(i)}function mo(i,t){let e=EventTarget.prototype,n=e.addEventListener,s=0;e.addEventListener=function(o,r,a){s++;let l=typeof a=="object"?a.signal:void 0;n.call(this,o,r,typeof a=="object"?{...a,signal:l?AbortSignal.any([l,i]):i}:{capture:a===!0,signal:i})};try{t()}finally{e.addEventListener=n}return s}function po(){oe(),document.querySelectorAll("[data-component='sidebar-provider']").forEach(i=>{if(Bt.has(i)||re.has(i))return;let t=new AbortController;mo(t.signal,()=>Se(i))?Bt.set(i,t):i.querySelector("[data-component='sidebar']")&&re.add(i)}),document.removeEventListener("keydown",oe),document.addEventListener("keydown",oe)}var Tt;function De(i={}){Tt==null||Tt.unmount();let t=new AbortController,{signal:e}=t,n=document.body,s=n.dataset.unitRoot??"",o=n.dataset.siteRoot??"";i.nav!==void 0&&(window.__DOGSBAY_NAV__=i.nav),po(),i.theme!==!1&&co(e),uo(e),i.switchers!==!1&&ho(o,e),fo(e),i.search!==!1&&en({unitRoot:s,loadScript:cn,signal:e}),sn(e),ln(e);let r={unmount(){if(!e.aborted){t.abort();for(let a of[...Bt.keys(),...re])ot(a);oe(),Tt===r&&(Tt=void 0)}}};return Tt=r}document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>De()):De();})();
|
|
1364
1361
|
`;
|
|
1362
|
+
var CLIENT_FILE = "dogsbay-4e1b1719ed.js";
|
|
1363
|
+
var SSG_VERSION = "0.2.0-beta.151.1";
|
|
1365
1364
|
var THEME_TEMPLATES = { "layouts/blank.html": '{# A page without the sidebar or table of contents: landing pages, splash pages, 404. -#}\n<!doctype html>\n<html lang="{{ page.lang }}" dir="{{ page.dir }}"{% if site.colorMode == "dark" %} class="dark"{% endif %}>\n<head>\n{% include "partials/head.html" %}\n</head>\n<body class="bg-background text-foreground antialiased" data-unit-root="{{ paths.unit }}" data-site-root="{{ paths.site }}" data-prefix="{{ page.prefix }}" data-page="{{ page.out }}"{{ bodyAttrs }}>\n{{ skipLink }}\n<div class="relative flex min-h-svh w-full flex-col bg-background">\n{{ announcementBar }}\n{% include "partials/header.html" %}\n<main id="db-content" class="min-w-0 flex-1 px-6 py-8 outline-none lg:px-12" tabindex="-1">\n<div class="mx-auto {{ widthClass }}">\n{{ banner }}{{ versionBadge }}{{ h1 }}{{ byline }}{{ lede }}{{ hero }}{{ metaStrip }}\n<article class="docs-prose">\n{{ content }}\n</article>\n{% include "partials/footer.html" %}\n</div>\n</main>\n</div>\n{{ searchDialog }}\n{{ scripts }}\n</body>\n</html>\n', "layouts/docs.html": '{# The docs layout: a port of @dogsbay/docs-layout DocsLayout.astro. -#}\n<!doctype html>\n<html lang="{{ page.lang }}" dir="{{ page.dir }}"{% if site.colorMode == "dark" %} class="dark"{% endif %}>\n<head>\n{% include "partials/head.html" %}\n</head>\n<body class="bg-background text-foreground antialiased" data-unit-root="{{ paths.unit }}" data-site-root="{{ paths.site }}" data-prefix="{{ page.prefix }}" data-page="{{ page.out }}"{{ bodyAttrs }}>\n{{ skipLink }}\n<div class="group/sidebar-wrapper flex min-h-svh w-full has-[[data-variant=inset]]:bg-sidebar" data-component="sidebar-provider" style="--sidebar-width: 16rem; --sidebar-width-icon: 3rem;">\n{{ sidebar }}\n<div class="relative flex w-full min-w-0 flex-1 flex-col bg-background">\n{{ announcementBar }}\n{% include "partials/header.html" %}\n<div class="flex min-w-0">\n<main id="db-content" class="min-w-0 flex-1 px-6 py-8 outline-none lg:px-12" tabindex="-1">\n<div class="mx-auto {{ widthClass }}">\n{{ banner }}{{ breadcrumb }}{{ pageActionsInline }}{{ versionBadge }}{{ h1 }}{{ byline }}{{ lede }}{{ hero }}{{ metaStrip }}{{ tocTop }}\n<article class="docs-prose">\n{{ content }}\n</article>\n{% include "partials/footer.html" %}\n</div>\n</main>\n{{ tocRail }}\n</div>\n</div>\n</div>\n{{ searchDialog }}\n{{ scripts }}\n</body>\n</html>\n', "partials/announcement.html": `{#- The site's announcement bar (site.announcement), as DocsLayout's AnnouncementBar.astro: a band above the
|
|
1366
1365
|
header in the callout colours of its tone. A closeable one is closed and remembered by <db-announcement>,
|
|
1367
1366
|
and the head script hides a closed one before first paint. Context: announcement = {id, key (what a close is
|
|
@@ -2643,7 +2642,7 @@ async function composePage(p, cfg, templates) {
|
|
|
2643
2642
|
// into its escaped script states; the client reverses both before copying.
|
|
2644
2643
|
(p.markdown != null && cfg.pageActions.enabled && cfg.pageActions.copyButton ? `<script type="text/markdown" id="db-page-markdown">${p.markdown.replace(/<\/(script)/gi, "<\\/$1").replace(/<!--/g, "<\\!--")}<\/script>
|
|
2645
2644
|
` : "") + `<script src="${esc2(p.unitRoot)}_dogsbay/nav.js" defer><\/script>
|
|
2646
|
-
<script src="${esc2(p.siteRoot)}_dogsbay/assets
|
|
2645
|
+
<script src="${esc2(p.siteRoot)}_dogsbay/assets/${CLIENT_FILE}" defer><\/script>`
|
|
2647
2646
|
)
|
|
2648
2647
|
};
|
|
2649
2648
|
return templates.render(p.layout, ctx);
|
|
@@ -3115,6 +3114,264 @@ function strings(locale, overrides) {
|
|
|
3115
3114
|
return (key) => table[key] ?? "";
|
|
3116
3115
|
}
|
|
3117
3116
|
|
|
3117
|
+
// src/core/unit-manifest.ts
|
|
3118
|
+
import { unitKeyString, unitManifest } from "@dogsbay/site-files";
|
|
3119
|
+
function unitKey(u) {
|
|
3120
|
+
return unitKeyString({ product: u.product, locale: u.locale, version: u.version });
|
|
3121
|
+
}
|
|
3122
|
+
function manifestPath(u) {
|
|
3123
|
+
return `_dogsbay/units/${unitKey(u)}.json`;
|
|
3124
|
+
}
|
|
3125
|
+
function makeManifest(u, ssg, redirects) {
|
|
3126
|
+
const inside = (p) => !u.prefix ? p : p === u.prefix ? "" : p.startsWith(`${u.prefix}/`) ? p.slice(u.prefix.length + 1) : p;
|
|
3127
|
+
return { ...unitManifest({ product: u.product, locale: u.locale, version: u.version }, { pages: ssg.pageOut.map(([p]) => inside(p)), sitemap: [], redirects }), ssg };
|
|
3128
|
+
}
|
|
3129
|
+
function parseManifest(raw) {
|
|
3130
|
+
let v = raw;
|
|
3131
|
+
if (typeof raw === "string") {
|
|
3132
|
+
try {
|
|
3133
|
+
v = JSON.parse(raw);
|
|
3134
|
+
} catch (e) {
|
|
3135
|
+
return { problem: `not JSON (${e.message})` };
|
|
3136
|
+
}
|
|
3137
|
+
}
|
|
3138
|
+
const m = v;
|
|
3139
|
+
if (!m || typeof m !== "object" || m.schemaVersion !== 1) return { problem: "not a unit manifest (schemaVersion 1)" };
|
|
3140
|
+
const s = m.ssg;
|
|
3141
|
+
const strings2 = (x) => Array.isArray(x) && x.every((y) => typeof y === "string");
|
|
3142
|
+
const pairs = (x) => Array.isArray(x) && x.every((y) => Array.isArray(y) && y.length === 2 && typeof y[0] === "string" && typeof y[1] === "string");
|
|
3143
|
+
if (!s || typeof s !== "object" || typeof s.prefix !== "string" || !Array.isArray(s.redirectInputs) || !pairs(s.pageOut) || !strings2(s.sitemaps) || !strings2(s.files) || typeof s.client !== "string" || typeof s.builder !== "string") {
|
|
3144
|
+
return { problem: "has no dogsbay-ssg section (written by another tool, or an older dogsbay-ssg)" };
|
|
3145
|
+
}
|
|
3146
|
+
if (s.math !== void 0 && typeof s.math !== "boolean" || s.iconSets !== void 0 && !strings2(s.iconSets)) return { problem: "has a malformed notices record" };
|
|
3147
|
+
const triples = (x) => Array.isArray(x) && x.every((y) => Array.isArray(y) && y.length === 3 && typeof y[0] === "string" && typeof y[1] === "string" && typeof y[2] === "number");
|
|
3148
|
+
if (!triples(m.redirects)) return { problem: "has malformed redirects" };
|
|
3149
|
+
const inputs = s.redirectInputs;
|
|
3150
|
+
if (!inputs.every((r) => !!r && typeof r === "object" && typeof r.from === "string" && typeof r.to === "string" && typeof r.status === "number")) {
|
|
3151
|
+
return { problem: "has a malformed redirect" };
|
|
3152
|
+
}
|
|
3153
|
+
return { manifest: m };
|
|
3154
|
+
}
|
|
3155
|
+
|
|
3156
|
+
// src/generated/icon-notices.ts
|
|
3157
|
+
var ICON_SET_NOTICES = { "fa6-brands": "Font Awesome 6 Brands icons (CC-BY-4.0), by Dave Gandy\nhttps://github.com/FortAwesome/Font-Awesome\nLicence: https://creativecommons.org/licenses/by/4.0/", "fa6-regular": "Font Awesome 6 Regular icons (CC-BY-4.0), by Dave Gandy\nhttps://github.com/FortAwesome/Font-Awesome\nLicence: https://creativecommons.org/licenses/by/4.0/", "fa6-solid": "Font Awesome 6 Solid icons (CC-BY-4.0), by Dave Gandy\nhttps://github.com/FortAwesome/Font-Awesome\nLicence: https://creativecommons.org/licenses/by/4.0/", "lucide": 'Lucide icons (ISC), by Lucide Contributors\nhttps://github.com/lucide-icons/lucide\nLicence: https://github.com/lucide-icons/lucide/blob/main/LICENSE\n\nISC License\n\nCopyright (c) 2026 Lucide Icons and Contributors\n\nPermission to use, copy, modify, and/or distribute this software for any\npurpose with or without fee is hereby granted, provided that the above\ncopyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\nWITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\nANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\nWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\nACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\nOR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n\n---\n\nThe following Lucide icons are derived from the Feather project:\n\nairplay, alert-circle, alert-octagon, alert-triangle, aperture, arrow-down-circle, arrow-down-left, arrow-down-right, arrow-down, arrow-left-circle, arrow-left, arrow-right-circle, arrow-right, arrow-up-circle, arrow-up-left, arrow-up-right, arrow-up, at-sign, calendar, cast, check, chevron-down, chevron-left, chevron-right, chevron-up, chevrons-down, chevrons-left, chevrons-right, chevrons-up, circle, clipboard, clock, code, columns, command, compass, corner-down-left, corner-down-right, corner-left-down, corner-left-up, corner-right-down, corner-right-up, corner-up-left, corner-up-right, crosshair, database, divide-circle, divide-square, dollar-sign, download, external-link, feather, frown, hash, headphones, help-circle, info, italic, key, layout, life-buoy, link-2, link, loader, lock, log-in, log-out, maximize, meh, minimize, minimize-2, minus-circle, minus-square, minus, monitor, moon, more-horizontal, more-vertical, move, music, navigation-2, navigation, octagon, pause-circle, percent, plus-circle, plus-square, plus, power, radio, rss, search, server, share, shopping-bag, sidebar, smartphone, smile, square, table-2, tablet, target, terminal, trash-2, trash, triangle, tv, type, upload, x-circle, x-octagon, x-square, x, zoom-in, zoom-out\n\nThe MIT License (MIT) (for the icons listed above)\n\nCopyright (c) 2013-present Cole Bemis\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the "Software"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.', "mdi": `Material Design Icons (Apache-2.0), by Pictogrammers
|
|
3158
|
+
https://github.com/Templarian/MaterialDesign
|
|
3159
|
+
Licence: https://github.com/Templarian/MaterialDesign/blob/master/LICENSE
|
|
3160
|
+
|
|
3161
|
+
Apache License
|
|
3162
|
+
Version 2.0, January 2004
|
|
3163
|
+
http://www.apache.org/licenses/
|
|
3164
|
+
|
|
3165
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
3166
|
+
|
|
3167
|
+
1. Definitions.
|
|
3168
|
+
|
|
3169
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
3170
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
3171
|
+
|
|
3172
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
3173
|
+
the copyright owner that is granting the License.
|
|
3174
|
+
|
|
3175
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
3176
|
+
other entities that control, are controlled by, or are under common
|
|
3177
|
+
control with that entity. For the purposes of this definition,
|
|
3178
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
3179
|
+
direction or management of such entity, whether by contract or
|
|
3180
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
3181
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
3182
|
+
|
|
3183
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
3184
|
+
exercising permissions granted by this License.
|
|
3185
|
+
|
|
3186
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
3187
|
+
including but not limited to software source code, documentation
|
|
3188
|
+
source, and configuration files.
|
|
3189
|
+
|
|
3190
|
+
"Object" form shall mean any form resulting from mechanical
|
|
3191
|
+
transformation or translation of a Source form, including but
|
|
3192
|
+
not limited to compiled object code, generated documentation,
|
|
3193
|
+
and conversions to other media types.
|
|
3194
|
+
|
|
3195
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
3196
|
+
Object form, made available under the License, as indicated by a
|
|
3197
|
+
copyright notice that is included in or attached to the work
|
|
3198
|
+
(an example is provided in the Appendix below).
|
|
3199
|
+
|
|
3200
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
3201
|
+
form, that is based on (or derived from) the Work and for which the
|
|
3202
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
3203
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
3204
|
+
of this License, Derivative Works shall not include works that remain
|
|
3205
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
3206
|
+
the Work and Derivative Works thereof.
|
|
3207
|
+
|
|
3208
|
+
"Contribution" shall mean any work of authorship, including
|
|
3209
|
+
the original version of the Work and any modifications or additions
|
|
3210
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
3211
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
3212
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
3213
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
3214
|
+
means any form of electronic, verbal, or written communication sent
|
|
3215
|
+
to the Licensor or its representatives, including but not limited to
|
|
3216
|
+
communication on electronic mailing lists, source code control systems,
|
|
3217
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
3218
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
3219
|
+
excluding communication that is conspicuously marked or otherwise
|
|
3220
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
3221
|
+
|
|
3222
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
3223
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
3224
|
+
subsequently incorporated within the Work.
|
|
3225
|
+
|
|
3226
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
3227
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
3228
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
3229
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
3230
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
3231
|
+
Work and such Derivative Works in Source or Object form.
|
|
3232
|
+
|
|
3233
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
3234
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
3235
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
3236
|
+
(except as stated in this section) patent license to make, have made,
|
|
3237
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
3238
|
+
where such license applies only to those patent claims licensable
|
|
3239
|
+
by such Contributor that are necessarily infringed by their
|
|
3240
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
3241
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
3242
|
+
institute patent litigation against any entity (including a
|
|
3243
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
3244
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
3245
|
+
or contributory patent infringement, then any patent licenses
|
|
3246
|
+
granted to You under this License for that Work shall terminate
|
|
3247
|
+
as of the date such litigation is filed.
|
|
3248
|
+
|
|
3249
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
3250
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
3251
|
+
modifications, and in Source or Object form, provided that You
|
|
3252
|
+
meet the following conditions:
|
|
3253
|
+
|
|
3254
|
+
(a) You must give any other recipients of the Work or
|
|
3255
|
+
Derivative Works a copy of this License; and
|
|
3256
|
+
|
|
3257
|
+
(b) You must cause any modified files to carry prominent notices
|
|
3258
|
+
stating that You changed the files; and
|
|
3259
|
+
|
|
3260
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
3261
|
+
that You distribute, all copyright, patent, trademark, and
|
|
3262
|
+
attribution notices from the Source form of the Work,
|
|
3263
|
+
excluding those notices that do not pertain to any part of
|
|
3264
|
+
the Derivative Works; and
|
|
3265
|
+
|
|
3266
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
3267
|
+
distribution, then any Derivative Works that You distribute must
|
|
3268
|
+
include a readable copy of the attribution notices contained
|
|
3269
|
+
within such NOTICE file, excluding those notices that do not
|
|
3270
|
+
pertain to any part of the Derivative Works, in at least one
|
|
3271
|
+
of the following places: within a NOTICE text file distributed
|
|
3272
|
+
as part of the Derivative Works; within the Source form or
|
|
3273
|
+
documentation, if provided along with the Derivative Works; or,
|
|
3274
|
+
within a display generated by the Derivative Works, if and
|
|
3275
|
+
wherever such third-party notices normally appear. The contents
|
|
3276
|
+
of the NOTICE file are for informational purposes only and
|
|
3277
|
+
do not modify the License. You may add Your own attribution
|
|
3278
|
+
notices within Derivative Works that You distribute, alongside
|
|
3279
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
3280
|
+
that such additional attribution notices cannot be construed
|
|
3281
|
+
as modifying the License.
|
|
3282
|
+
|
|
3283
|
+
You may add Your own copyright statement to Your modifications and
|
|
3284
|
+
may provide additional or different license terms and conditions
|
|
3285
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
3286
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
3287
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
3288
|
+
the conditions stated in this License.
|
|
3289
|
+
|
|
3290
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
3291
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
3292
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
3293
|
+
this License, without any additional terms or conditions.
|
|
3294
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
3295
|
+
the terms of any separate license agreement you may have executed
|
|
3296
|
+
with Licensor regarding such Contributions.
|
|
3297
|
+
|
|
3298
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
3299
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
3300
|
+
except as required for reasonable and customary use in describing the
|
|
3301
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
3302
|
+
|
|
3303
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
3304
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
3305
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
3306
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
3307
|
+
implied, including, without limitation, any warranties or conditions
|
|
3308
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
3309
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
3310
|
+
appropriateness of using or redistributing the Work and assume any
|
|
3311
|
+
risks associated with Your exercise of permissions under this License.
|
|
3312
|
+
|
|
3313
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
3314
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
3315
|
+
unless required by applicable law (such as deliberate and grossly
|
|
3316
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
3317
|
+
liable to You for damages, including any direct, indirect, special,
|
|
3318
|
+
incidental, or consequential damages of any character arising as a
|
|
3319
|
+
result of this License or out of the use or inability to use the
|
|
3320
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
3321
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
3322
|
+
other commercial damages or losses), even if such Contributor
|
|
3323
|
+
has been advised of the possibility of such damages.
|
|
3324
|
+
|
|
3325
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
3326
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
3327
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
3328
|
+
or other liability obligations and/or rights consistent with this
|
|
3329
|
+
License. However, in accepting such obligations, You may act only
|
|
3330
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
3331
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
3332
|
+
defend, and hold each Contributor harmless for any liability
|
|
3333
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
3334
|
+
of your accepting any such warranty or additional liability.
|
|
3335
|
+
|
|
3336
|
+
END OF TERMS AND CONDITIONS
|
|
3337
|
+
|
|
3338
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
3339
|
+
|
|
3340
|
+
To apply the Apache License to your work, attach the following
|
|
3341
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
3342
|
+
replaced with your own identifying information. (Don't include
|
|
3343
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
3344
|
+
comment syntax for the file format. We also recommend that a
|
|
3345
|
+
file or class name and description of purpose be included on the
|
|
3346
|
+
same "printed page" as the copyright notice for easier
|
|
3347
|
+
identification within third-party archives.
|
|
3348
|
+
|
|
3349
|
+
Copyright [yyyy] [name of copyright owner]
|
|
3350
|
+
|
|
3351
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
3352
|
+
you may not use this file except in compliance with the License.
|
|
3353
|
+
You may obtain a copy of the License at
|
|
3354
|
+
|
|
3355
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
3356
|
+
|
|
3357
|
+
Unless required by applicable law or agreed to in writing, software
|
|
3358
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
3359
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
3360
|
+
See the License for the specific language governing permissions and
|
|
3361
|
+
limitations under the License.`, "octicon": 'Octicons (MIT), by GitHub\nhttps://github.com/primer/octicons/\nLicence: https://github.com/primer/octicons/blob/main/LICENSE\n\nMIT License\n\nCopyright (c) 2026 GitHub Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the "Software"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.', "simple-icons": "Simple Icons (CC0-1.0), by Simple Icons Collaborators\nhttps://github.com/simple-icons/simple-icons\nLicence: https://github.com/simple-icons/simple-icons/blob/develop/LICENSE.md" };
|
|
3362
|
+
|
|
3363
|
+
// src/core/icon-notices.ts
|
|
3364
|
+
var ICON_SET_NAME = /^[a-z0-9][a-z0-9-]{0,63}$/;
|
|
3365
|
+
function iconSetNotices(sets) {
|
|
3366
|
+
const more = [...new Set(sets)].filter((s) => s !== "lucide" && s !== "mdi" && ICON_SET_NAME.test(s)).sort();
|
|
3367
|
+
if (!more.length) return void 0;
|
|
3368
|
+
const lines = more.map((set) => ICON_SET_NOTICES[set] ?? `Iconify set "${set}": its licence is in @iconify-json/${set}/info.json`);
|
|
3369
|
+
return `Icons in the pages from other Iconify sets (@dogsbay/icons)
|
|
3370
|
+
|
|
3371
|
+
${lines.join("\n\n")}
|
|
3372
|
+
`;
|
|
3373
|
+
}
|
|
3374
|
+
|
|
3118
3375
|
// src/core/taxonomy.ts
|
|
3119
3376
|
import { parseMeta } from "@dogsbay/types";
|
|
3120
3377
|
function safeSegment(s) {
|
|
@@ -3734,7 +3991,7 @@ async function build(input, hooks = {}) {
|
|
|
3734
3991
|
phase.init = now() - t0;
|
|
3735
3992
|
let pages = 0;
|
|
3736
3993
|
let assets = 0;
|
|
3737
|
-
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(), homeForward: /* @__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) };
|
|
3994
|
+
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(), homeForward: /* @__PURE__ */ new Map(), usedMath: false, mathUnits: /* @__PURE__ */ new Set(), 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) };
|
|
3738
3995
|
for (const w of cfg.chrome.warnings) report("config", `[config] ${w}`);
|
|
3739
3996
|
state.logo = await emitLogo(cfg, input, emit, report);
|
|
3740
3997
|
for (const r of cfg.redirects) {
|
|
@@ -3752,6 +4009,17 @@ async function build(input, hooks = {}) {
|
|
|
3752
4009
|
stub: /\/\s*$/.test(r.from) ? `${from}/index.html` : void 0
|
|
3753
4010
|
});
|
|
3754
4011
|
}
|
|
4012
|
+
const stored = storedManifests(input.manifests, allUnits, units, report);
|
|
4013
|
+
input.manifests?.splice(0);
|
|
4014
|
+
const configRedirects = state.redirects.length;
|
|
4015
|
+
const unitRedirects = /* @__PURE__ */ new Map();
|
|
4016
|
+
for (const [prefix, m] of stored) {
|
|
4017
|
+
unitRedirects.set(prefix, m.redirectInputs);
|
|
4018
|
+
for (const [p, o] of m.pageOut) state.pageOut.set(p, o);
|
|
4019
|
+
state.sitemaps.set(prefix, m.sitemaps);
|
|
4020
|
+
if (m.homeForward !== void 0) state.homeForward.set(prefix, m.homeForward);
|
|
4021
|
+
}
|
|
4022
|
+
const unitRecords = /* @__PURE__ */ new Map();
|
|
3755
4023
|
let frontMatterOf = frontMatterCache(readText);
|
|
3756
4024
|
state.canonical = await defaultTables(cfg, allUnits, units, input.files, readText, (m) => report("canonical", m), frontMatterOf);
|
|
3757
4025
|
if (siteBase(cfg)) state.languages = await languageTables(cfg, allUnits, units, input.files, readText, frontMatterOf);
|
|
@@ -3761,6 +4029,7 @@ async function build(input, hooks = {}) {
|
|
|
3761
4029
|
hooks.context?.({ cfg, allUnits, input, highlighter, emit, warnings, problems, report, phase, theme, state, diagnostics: hooks.diagnostics, dataLines: hooks.dataLines });
|
|
3762
4030
|
for (const unit of units) {
|
|
3763
4031
|
classes = new Set(CLIENT_CANDIDATES);
|
|
4032
|
+
const before = { redirects: state.redirects.length, pageOut: state.pageOut.size, written: state.written.size };
|
|
3764
4033
|
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 });
|
|
3765
4034
|
hooks.unitBuilt?.(unit, r, classes);
|
|
3766
4035
|
pages += r.pages;
|
|
@@ -3772,15 +4041,21 @@ async function build(input, hooks = {}) {
|
|
|
3772
4041
|
report("css", `[css] could not build the stylesheet for ${unit.prefix || "/"}: ${e.message}`, { unit: unit.prefix || "/" });
|
|
3773
4042
|
}
|
|
3774
4043
|
phase.css = (phase.css ?? 0) + now() - tCss;
|
|
4044
|
+
unitRedirects.set(unit.prefix, state.redirects.slice(before.redirects));
|
|
4045
|
+
unitRecords.set(unit.prefix, { pageOut: [...state.pageOut].slice(before.pageOut), files: [...state.written].slice(before.written), iconSets: input.icons?.sets?.() ?? [] });
|
|
3775
4046
|
}
|
|
4047
|
+
state.redirects = [...state.redirects.slice(0, configRedirects), ...allUnits.flatMap((u) => unitRedirects.get(u.prefix) ?? [])];
|
|
4048
|
+
await emit(`_dogsbay/assets/${CLIENT_FILE}`, CLIENT_JS);
|
|
3776
4049
|
await emit("_dogsbay/assets/dogsbay.js", CLIENT_JS);
|
|
3777
|
-
|
|
4050
|
+
const storedUnits = [...stored.values()];
|
|
4051
|
+
const anyMath = state.usedMath || storedUnits.some((m) => m.math);
|
|
4052
|
+
if (anyMath) {
|
|
3778
4053
|
const { KATEX_CSS, KATEX_FONTS } = await import("./chunks/katex-assets-7BGR6WCR.mjs");
|
|
3779
4054
|
await emit("_dogsbay/assets/katex/katex.min.css", KATEX_CSS);
|
|
3780
4055
|
for (const [f, b64] of Object.entries(KATEX_FONTS)) await emit(`_dogsbay/assets/katex/fonts/${f}`, base64Bytes(b64));
|
|
3781
4056
|
}
|
|
3782
|
-
const iconNotices = input.icons?.
|
|
3783
|
-
await emit("_dogsbay/assets/THIRD-PARTY-NOTICES.txt", [SITE_NOTICES,
|
|
4057
|
+
const iconNotices = iconSetNotices([...input.icons?.sets?.() ?? [], ...storedUnits.flatMap((m) => m.iconSets ?? [])]);
|
|
4058
|
+
await emit("_dogsbay/assets/THIRD-PARTY-NOTICES.txt", [SITE_NOTICES, anyMath && KATEX_NOTICE, iconNotices].filter(Boolean).join("\n"));
|
|
3784
4059
|
await emit("_dogsbay/assets/favicon.svg", `${FAVICON_SVG}
|
|
3785
4060
|
`);
|
|
3786
4061
|
await emit(
|
|
@@ -3812,11 +4087,14 @@ async function build(input, hooks = {}) {
|
|
|
3812
4087
|
if (!input.untrusted) state.hostFiles.set(n, c);
|
|
3813
4088
|
else if (fromStatic !== void 0) report("untrusted", `[untrusted] ${cfg.staticDir}/${n} is not used: an untrusted build takes no host configuration`);
|
|
3814
4089
|
}
|
|
4090
|
+
if (rootUnit && !units.includes(rootUnit)) {
|
|
4091
|
+
for (const n of SITE_FILES) if (input.files.has(sourceRoot(rootUnit.source) + n)) state.supplied.add(n);
|
|
4092
|
+
}
|
|
3815
4093
|
if (state.staticFiles?.has("robots.txt")) {
|
|
3816
4094
|
if (state.supplied.has("robots.txt")) throw new ConfigError(`${cfg.staticDir}/robots.txt and the root content's robots.txt are both the site's robots.txt: keep the one in content.static (${cfg.staticDir})`);
|
|
3817
4095
|
state.supplied.add("robots.txt");
|
|
3818
4096
|
}
|
|
3819
|
-
await emitSiteFiles(cfg, allUnits, units, def, state, emit, report, input.onRedirects);
|
|
4097
|
+
const rules = await emitSiteFiles(cfg, allUnits, units, stored, def, state, emit, report, input.onRedirects);
|
|
3820
4098
|
phase.site = (phase.site ?? 0) + now() - tSite;
|
|
3821
4099
|
const homeOf = (fromDir, unitPrefix, fallback) => {
|
|
3822
4100
|
const page = state.homeForward.get(unitPrefix);
|
|
@@ -3834,8 +4112,30 @@ async function build(input, hooks = {}) {
|
|
|
3834
4112
|
if (root && u.version && u.version === cfg.defaultVersion && u.prefix !== root) await emit(`${root}/index.html`, redirectPage(homeOf(root, u.prefix, `${u.version}/index.html`), cfg.name));
|
|
3835
4113
|
}
|
|
3836
4114
|
}
|
|
3837
|
-
if (state.staticFiles && (units.length === allUnits.length || rootUnit && units.includes(rootUnit))) await emitStatic(cfg, state, allUnits, input.untrusted === true, emit, report);
|
|
3838
|
-
state.stubs = await writeTranslationStubs(cfg, allUnits, units, translations, state, emit);
|
|
4115
|
+
if (state.staticFiles && (units.length === allUnits.length || units.length === 0 || rootUnit && units.includes(rootUnit))) await emitStatic(cfg, state, allUnits, input.untrusted === true, emit, report);
|
|
4116
|
+
state.stubs = await writeTranslationStubs(cfg, allUnits, units, translations, state, emit, void 0, new Set(stored.keys()));
|
|
4117
|
+
if (allUnits.length > 1 && !hooks.lazy && !hooks.keep) {
|
|
4118
|
+
for (const u of units) {
|
|
4119
|
+
const rec = unitRecords.get(u.prefix);
|
|
4120
|
+
const own = rules.filter((r) => unitOfPath(allUnits, r.from) === u);
|
|
4121
|
+
const ssg = {
|
|
4122
|
+
prefix: u.prefix,
|
|
4123
|
+
redirectInputs: unitRedirects.get(u.prefix) ?? [],
|
|
4124
|
+
pageOut: rec.pageOut,
|
|
4125
|
+
sitemaps: state.sitemaps.get(u.prefix) ?? [],
|
|
4126
|
+
...state.homeForward.has(u.prefix) ? { homeForward: state.homeForward.get(u.prefix) } : {},
|
|
4127
|
+
// Its redirect stubs and missing-translation stubs are written after the units, in its folder.
|
|
4128
|
+
files: [.../* @__PURE__ */ new Set([...rec.files, ...own.map(stubFile), ...state.stubs.filter((f) => unitOfPath(allUnits, f) === u)])],
|
|
4129
|
+
client: CLIENT_FILE,
|
|
4130
|
+
builder: SSG_VERSION,
|
|
4131
|
+
...state.mathUnits.has(u.prefix) ? { math: true } : {},
|
|
4132
|
+
...rec.iconSets.length ? { iconSets: rec.iconSets } : {}
|
|
4133
|
+
};
|
|
4134
|
+
const served = own.map((r) => siteRedirect(r, cfg)).map((r) => [r.from, r.to, r.status]);
|
|
4135
|
+
await emit(manifestPath(u), `${JSON.stringify(makeManifest(u, ssg, served))}
|
|
4136
|
+
`);
|
|
4137
|
+
}
|
|
4138
|
+
}
|
|
3839
4139
|
const spent = state.templateBudget.problem();
|
|
3840
4140
|
if (spent) report("template", spent);
|
|
3841
4141
|
return {
|
|
@@ -3938,7 +4238,7 @@ async function emitStatic(cfg, state, units, untrusted, emit, report) {
|
|
|
3938
4238
|
const label = `content.static (${cfg.staticDir})`;
|
|
3939
4239
|
const lower = /* @__PURE__ */ new Map();
|
|
3940
4240
|
const dirs = /* @__PURE__ */ new Map();
|
|
3941
|
-
for (const w of state.written) {
|
|
4241
|
+
for (const w of /* @__PURE__ */ new Set([...state.written, ...state.pageOut.values()])) {
|
|
3942
4242
|
lower.set(w.toLowerCase(), w);
|
|
3943
4243
|
for (let i = w.indexOf("/"); i > 0; i = w.indexOf("/", i + 1)) dirs.set(w.slice(0, i).toLowerCase(), w);
|
|
3944
4244
|
}
|
|
@@ -3982,7 +4282,7 @@ async function emitStatic(cfg, state, units, untrusted, emit, report) {
|
|
|
3982
4282
|
if (plan.robots) for (const w of staticRobotsWarnings(await readText(files.get("robots.txt")), label)) report("static", `[static] ${w}`);
|
|
3983
4283
|
for (const p of plan.copy) await emit(p, files.get(p));
|
|
3984
4284
|
}
|
|
3985
|
-
async function emitSiteFiles(cfg, all, built, def, state, emit, report, onRedirects) {
|
|
4285
|
+
async function emitSiteFiles(cfg, all, built, stored, def, state, emit, report, onRedirects) {
|
|
3986
4286
|
const defPrefix = def?.prefix ?? "";
|
|
3987
4287
|
const put = async (p, content) => {
|
|
3988
4288
|
if (state.supplied.has(p)) {
|
|
@@ -4005,18 +4305,71 @@ async function emitSiteFiles(cfg, all, built, def, state, emit, report, onRedire
|
|
|
4005
4305
|
} else if (cfg.url) {
|
|
4006
4306
|
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`);
|
|
4007
4307
|
}
|
|
4008
|
-
if (!state.redirects.length)
|
|
4308
|
+
if (!state.redirects.length) {
|
|
4309
|
+
await merged("_redirects", void 0, mergeRedirects);
|
|
4310
|
+
return [];
|
|
4311
|
+
}
|
|
4312
|
+
const unitOf2 = (p) => unitOfPath(all, p);
|
|
4009
4313
|
const known = (p) => {
|
|
4010
|
-
const u =
|
|
4011
|
-
return !!u && built.includes(u);
|
|
4314
|
+
const u = unitOf2(p);
|
|
4315
|
+
return !!u && (built.includes(u) || stored.has(u.prefix));
|
|
4012
4316
|
};
|
|
4013
4317
|
const inputs = state.redirects.filter((r) => known(r.from));
|
|
4014
4318
|
const { rules, warnings: w } = collectRedirects(inputs, (p) => state.pageOut.get(p), known);
|
|
4319
|
+
const builtFrom = (r) => built.includes(unitOf2(r.from));
|
|
4015
4320
|
for (const m of w) report("redirects", `[redirects] ${m}`);
|
|
4016
|
-
onRedirects?.(rules);
|
|
4017
|
-
|
|
4321
|
+
onRedirects?.(rules.filter(builtFrom));
|
|
4322
|
+
const servedBefore = (r) => stored.get(unitOf2(r.from).prefix)?.redirects.get(siteRedirect(r, cfg).from);
|
|
4323
|
+
for (const r of rules) if (builtFrom(r) || servedBefore(r) !== siteRedirect(r, cfg).to) await emit(stubFile(r), renderRedirectPage(r, cfg));
|
|
4018
4324
|
const ownRedirects = state.hostFiles.has("_redirects");
|
|
4019
4325
|
await merged("_redirects", (cloudflare || ownRedirects) && rules.length ? renderRedirectsFile(rules, cfg) : void 0, mergeRedirects);
|
|
4326
|
+
return rules;
|
|
4327
|
+
}
|
|
4328
|
+
var siteRedirect = (r, cfg) => servedRedirect(r, { ...cfg, basePath: "" });
|
|
4329
|
+
function storedManifests(given, all, built, report) {
|
|
4330
|
+
const out = /* @__PURE__ */ new Map();
|
|
4331
|
+
if (!given) return out;
|
|
4332
|
+
for (const { path, text } of given) {
|
|
4333
|
+
const { manifest: m, problem } = parseManifest(text);
|
|
4334
|
+
if (!m) {
|
|
4335
|
+
report("units", `[units] ${path}: ${problem}; ignored`);
|
|
4336
|
+
continue;
|
|
4337
|
+
}
|
|
4338
|
+
const key = unitKey({ product: m.product ?? void 0, locale: m.locale ?? void 0, version: m.version ?? void 0 });
|
|
4339
|
+
const u = all.find((x) => unitKey(x) === key);
|
|
4340
|
+
if (!u) {
|
|
4341
|
+
report("units", `[units] ${path} is for ${key}, which the config no longer builds; ignored (remove its folder, ${m.ssg.prefix || "the site root"}, and the manifest)`);
|
|
4342
|
+
continue;
|
|
4343
|
+
}
|
|
4344
|
+
if (path !== manifestPath(u)) {
|
|
4345
|
+
report("units", `[units] ${path} is for ${key}, whose manifest is ${manifestPath(u)}; ignored`);
|
|
4346
|
+
continue;
|
|
4347
|
+
}
|
|
4348
|
+
if (u.prefix !== m.ssg.prefix) {
|
|
4349
|
+
report("units", `[units] ${path}: ${key} was built at ${m.ssg.prefix || "the site root"} and is now at ${u.prefix || "the site root"}; ignored until it is built again`);
|
|
4350
|
+
continue;
|
|
4351
|
+
}
|
|
4352
|
+
if (built.includes(u)) continue;
|
|
4353
|
+
const clean = (x) => !/[\s\u0000-\u001f\u007f]/.test(x) && !x.split("/").some((p) => p === ".." || p === ".");
|
|
4354
|
+
const mine = (p) => clean(p) && unitOfPath(all, p) === u;
|
|
4355
|
+
const redirectInputs = m.ssg.redirectInputs.filter((r) => mine(r.from) && (r.stub === void 0 || mine(r.stub)) && clean(r.to) && (r.suffix === void 0 || clean(r.suffix)));
|
|
4356
|
+
const pageOut = m.ssg.pageOut.filter(([p, o]) => mine(p) && mine(o));
|
|
4357
|
+
const sitemaps = m.ssg.sitemaps.filter(mine);
|
|
4358
|
+
const dropped = m.ssg.redirectInputs.length - redirectInputs.length + m.ssg.pageOut.length - pageOut.length + m.ssg.sitemaps.length - sitemaps.length;
|
|
4359
|
+
if (dropped) report("units", `[units] ${path}: ${dropped} entr${dropped === 1 ? "y" : "ies"} outside ${u.prefix || "the root unit"} left out`);
|
|
4360
|
+
out.set(u.prefix, {
|
|
4361
|
+
redirectInputs,
|
|
4362
|
+
pageOut,
|
|
4363
|
+
sitemaps,
|
|
4364
|
+
homeForward: m.ssg.homeForward !== void 0 && mine(m.ssg.homeForward) ? m.ssg.homeForward : void 0,
|
|
4365
|
+
math: m.ssg.math,
|
|
4366
|
+
iconSets: m.ssg.iconSets,
|
|
4367
|
+
redirects: new Map(m.redirects.map(([f, t]) => [f, t]))
|
|
4368
|
+
});
|
|
4369
|
+
}
|
|
4370
|
+
const missing = all.filter((u) => !built.includes(u) && !out.has(u.prefix));
|
|
4371
|
+
if (missing.length) report("units", `[units] no manifest for ${missing.map((u) => u.prefix || "the root unit").join(", ")}: not built yet, so the site-wide files leave out their redirects`);
|
|
4372
|
+
return out;
|
|
4020
4373
|
}
|
|
4021
4374
|
function defaultUnit(units, cfg) {
|
|
4022
4375
|
if (cfg.products) {
|
|
@@ -4336,6 +4689,10 @@ ${marker}${title}${marker}`, path, attributesOf(path), includesFor(path, read2),
|
|
|
4336
4689
|
blog?.add(slug, infos.get(slug).title, fm);
|
|
4337
4690
|
if (mode.keep || mode.lazy) frontMatter.set(p, memo2 ? memo2.fmKey ??= fmKey(await source()) : fmKey(await source()));
|
|
4338
4691
|
} else if (!SKIP_FILES.has(memberRel(p)) && copiedPath(p)) {
|
|
4692
|
+
if (p.split("/").some((seg) => seg.toLowerCase() === "_dogsbay")) {
|
|
4693
|
+
warn("site", `${p} is inside a folder named _dogsbay, the build's own; not copied`, { file: abs(p) });
|
|
4694
|
+
continue;
|
|
4695
|
+
}
|
|
4339
4696
|
const verdict = await assetVerdict(p, c, input.untrusted === true, sanitizing);
|
|
4340
4697
|
if (verdict === "untrusted") untrustedFiles.push(p);
|
|
4341
4698
|
else if (verdict === "active") activeFiles.push(p);
|
|
@@ -4863,7 +5220,10 @@ ${marker}${title}${marker}`, path, attributesOf(path), includesFor(path, read2),
|
|
|
4863
5220
|
for (const u of ctx.unsafeUrls ?? []) warnPage(info, "unsafe-url", `refused the unsafe URL "${u}"`);
|
|
4864
5221
|
for (const m of removed) warnPage(info, "html", m);
|
|
4865
5222
|
for (const name of ctx.missingIcons ?? []) warnPage(info, "icon", `unknown icon "${name}"${input.icons ? "" : " (only the built-in icons are available in this build)"}`);
|
|
4866
|
-
if (ctx.usedMath)
|
|
5223
|
+
if (ctx.usedMath) {
|
|
5224
|
+
state.usedMath = true;
|
|
5225
|
+
state.mathUnits.add(unit.prefix);
|
|
5226
|
+
}
|
|
4867
5227
|
for (const b of resolver.broken) brokenCounts.has(b) ? brokenCounts.set(b, brokenCounts.get(b) + 1) : brokenCounts.set(detach(b), 1);
|
|
4868
5228
|
phase.render = (phase.render ?? 0) + now() - t;
|
|
4869
5229
|
t = now();
|
|
@@ -5580,7 +5940,7 @@ function versionBanner(unit, all, cfg, out, siteRoot, t) {
|
|
|
5580
5940
|
if (!latest) return void 0;
|
|
5581
5941
|
return esc3(t("oldVersion")) + link(latest);
|
|
5582
5942
|
}
|
|
5583
|
-
async function writeTranslationStubs(cfg, all, built, tables, state, emit, exists = () => false) {
|
|
5943
|
+
async function writeTranslationStubs(cfg, all, built, tables, state, emit, exists = () => false, stored = /* @__PURE__ */ new Set()) {
|
|
5584
5944
|
const def = cfg.defaultLocale;
|
|
5585
5945
|
if (!def || !tables.size) return [];
|
|
5586
5946
|
const unitOf2 = (locale, version) => all.find((u) => u.locale === locale && u.version === version && !u.product);
|
|
@@ -5599,10 +5959,11 @@ async function writeTranslationStubs(cfg, all, built, tables, state, emit, exist
|
|
|
5599
5959
|
const home = unitOf2(def, m.version);
|
|
5600
5960
|
const out = tables.get(home.prefix).pages.get(m.page);
|
|
5601
5961
|
const target = unitOf2(m.locale, m.version);
|
|
5602
|
-
if (!built.includes(target ?? home)) continue;
|
|
5603
|
-
const to = join(home.prefix, out);
|
|
5604
|
-
if (built.includes(home) && !pageFiles.has(to)) continue;
|
|
5605
5962
|
const file = join(target ? target.prefix : m.locale + home.prefix.slice(def.length), out);
|
|
5963
|
+
const folder = target ? void 0 : unitOfPath(all, file);
|
|
5964
|
+
if (!built.includes(target ?? home) && !(folder && built.includes(folder) && stored.has(home.prefix))) continue;
|
|
5965
|
+
const to = join(home.prefix, out);
|
|
5966
|
+
if ((built.includes(home) || stored.has(home.prefix)) && !pageFiles.has(to)) continue;
|
|
5606
5967
|
if (state.written.has(file) || pageFiles.has(file) || exists(file)) continue;
|
|
5607
5968
|
await emit(file, redirectPage(hrefBetween(file, to, cfg.linkStyle), cfg.name));
|
|
5608
5969
|
written.push(file);
|
|
@@ -34,11 +34,11 @@ export type SinkContent = string | Uint8Array | FileRef | TextStream;
|
|
|
34
34
|
/** A built file held in memory (no sink). */
|
|
35
35
|
export type OutputContent = string | Uint8Array;
|
|
36
36
|
/**
|
|
37
|
-
* Icon name → SVG markup or an emoji (undefined when unknown). `
|
|
38
|
-
*
|
|
37
|
+
* Icon name → SVG markup or an emoji (undefined when unknown). `sets`, when the host has it, returns
|
|
38
|
+
* the Iconify sets the pages drew from, whose attribution goes in THIRD-PARTY-NOTICES.txt.
|
|
39
39
|
*/
|
|
40
40
|
export type IconResolver = ((name: string) => string | undefined) & {
|
|
41
|
-
|
|
41
|
+
sets?: () => string[];
|
|
42
42
|
};
|
|
43
43
|
export interface BuildInput {
|
|
44
44
|
/** Project files keyed by path relative to the project root (where the config lives). */
|
|
@@ -47,6 +47,17 @@ export interface BuildInput {
|
|
|
47
47
|
config?: string | SiteConfig;
|
|
48
48
|
/** Build only the units with these prefixes (a Worker builds one unit per request). */
|
|
49
49
|
units?: string[];
|
|
50
|
+
/**
|
|
51
|
+
* The unit manifests of the site this build updates (`_dogsbay/units/…`, plans/unit-publishing.md):
|
|
52
|
+
* a unit not built here is represented by its manifest in the site-wide files (`_redirects`, the
|
|
53
|
+
* sitemap index, the root forwards), so a one-unit build writes them as a full build would.
|
|
54
|
+
* `path` names the file in warnings. The build empties the array once it has read them, so their
|
|
55
|
+
* text is not held through the build (the Worker's memory).
|
|
56
|
+
*/
|
|
57
|
+
manifests?: Array<{
|
|
58
|
+
path: string;
|
|
59
|
+
text: string;
|
|
60
|
+
}>;
|
|
50
61
|
/**
|
|
51
62
|
* content.html when the project does not set it: "keep" (the default) or "sanitize"
|
|
52
63
|
* (the Worker's, where projects come from anyone with the token and share one origin).
|
|
@@ -236,6 +247,8 @@ export interface SiteState {
|
|
|
236
247
|
};
|
|
237
248
|
/** A page rendered math, so the KaTeX stylesheet and fonts are written. */
|
|
238
249
|
usedMath: boolean;
|
|
250
|
+
/** The units (prefixes) a page of which rendered math, for their manifests. */
|
|
251
|
+
mathUnits: Set<string>;
|
|
239
252
|
/** Rendered diagrams, shared by the units of the build. */
|
|
240
253
|
diagrams?: DiagramStore;
|
|
241
254
|
/** The default version's pages and redirects per language, for older versions' canonical links (src/core/canonical.ts). */
|
|
@@ -479,4 +492,6 @@ export interface LoadedTheme {
|
|
|
479
492
|
* unit was built here, only to a page it wrote (the nav may leave pages out). In another
|
|
480
493
|
* language a redirect source holds its URL, so it counts as present. Returns the stubs written.
|
|
481
494
|
*/
|
|
482
|
-
export declare function writeTranslationStubs(cfg: SiteConfig, all: BuildUnit[], built: BuildUnit[], tables: Map<string, DefaultTable>, state: Pick<SiteState, "written" | "pageOut">, emit: (path: string, c: FileContent) => Promise<void>, exists?: (path: string) => boolean
|
|
495
|
+
export declare function writeTranslationStubs(cfg: SiteConfig, all: BuildUnit[], built: BuildUnit[], tables: Map<string, DefaultTable>, state: Pick<SiteState, "written" | "pageOut">, emit: (path: string, c: FileContent) => Promise<void>, exists?: (path: string) => boolean,
|
|
496
|
+
/** Units not built here whose pages `state.pageOut` holds (from their manifests). */
|
|
497
|
+
stored?: ReadonlySet<string>): Promise<string[]>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** An Iconify set name as a unit manifest may record it (the `icon-notices` table's keys are of this shape). */
|
|
2
|
+
export declare const ICON_SET_NAME: RegExp;
|
|
3
|
+
/**
|
|
4
|
+
* THIRD-PARTY-NOTICES.txt's section for the Iconify sets the pages drew from (`sets`, prefixes), or
|
|
5
|
+
* undefined when there is none to list. Lucide and MDI are listed with render-html's built-in icons in
|
|
6
|
+
* every site already. Pure, so a one-unit build lists the sets its stored units recorded too
|
|
7
|
+
* (plans/unit-publishing.md).
|
|
8
|
+
*/
|
|
9
|
+
export declare function iconSetNotices(sets: Iterable<string>): string | undefined;
|
|
@@ -117,5 +117,11 @@ export declare function splitSuffix(raw: string): {
|
|
|
117
117
|
export declare function stubFile(rule: RedirectRule): string;
|
|
118
118
|
/** A meta-refresh page, as `renderMetaRefreshPage`, with a relative target so it works from disk. */
|
|
119
119
|
export declare function renderRedirectPage(rule: RedirectRule, cfg: SiteConfig): string;
|
|
120
|
+
/** A rule as the site serves it: `from` and `to` with the base path, `to` as its page is served. */
|
|
121
|
+
export declare function servedRedirect(r: RedirectRule, cfg: SiteConfig): {
|
|
122
|
+
from: string;
|
|
123
|
+
to: string;
|
|
124
|
+
status: number;
|
|
125
|
+
};
|
|
120
126
|
/** _redirects (Cloudflare), as `renderRedirectsFile`, with served paths. */
|
|
121
127
|
export declare function renderRedirectsFile(rules: RedirectRule[], cfg: SiteConfig): string;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A manifest per unit (plans/unit-publishing.md): what each unit's build leaves for the site-wide
|
|
3
|
+
* files, so one product, version or language can be built and published on its own and the
|
|
4
|
+
* `_redirects`, sitemap index and root forwards still cover every unit. The format is
|
|
5
|
+
* @dogsbay/site-files' `UnitManifest` (shared with the Dogsbay CLI), with our own `ssg` section.
|
|
6
|
+
* Written at `_dogsbay/units/<unitKeyString>.json` on sites with two or more units. Pure: the CLI
|
|
7
|
+
* and the Worker read the files and hand them to `build()` as `BuildInput.manifests`.
|
|
8
|
+
*/
|
|
9
|
+
import { type UnitManifest } from "@dogsbay/site-files";
|
|
10
|
+
import type { BuildUnit } from "./config.js";
|
|
11
|
+
import type { RedirectInput } from "./site-files.js";
|
|
12
|
+
/** What a unit's build records for the next one-unit build or assemble. */
|
|
13
|
+
export interface SsgUnitData {
|
|
14
|
+
/** The unit's folder in the site ("" at the root). */
|
|
15
|
+
prefix: string;
|
|
16
|
+
/** Its redirects before they are resolved (front matter and aliases; config redirects come from the config). */
|
|
17
|
+
redirectInputs: RedirectInput[];
|
|
18
|
+
/** `[site path, output file]` of its pages, so other units' redirects resolve against them. */
|
|
19
|
+
pageOut: Array<[string, string]>;
|
|
20
|
+
/** Its sitemap files, for the sitemap index. */
|
|
21
|
+
sitemaps: string[];
|
|
22
|
+
/** The page its home forwards to, when it has no home page. */
|
|
23
|
+
homeForward?: string;
|
|
24
|
+
/** Every file it wrote, so the next publish of the unit can remove the ones it no longer writes. */
|
|
25
|
+
files: string[];
|
|
26
|
+
/** The client file its pages load (`_dogsbay/assets/<client>`). */
|
|
27
|
+
client: string;
|
|
28
|
+
/** The dogsbay-ssg version that built it. */
|
|
29
|
+
builder: string;
|
|
30
|
+
/** A page rendered math: the site keeps KaTeX's files and its notice. */
|
|
31
|
+
math?: boolean;
|
|
32
|
+
/** The Iconify sets its pages drew from, for THIRD-PARTY-NOTICES.txt (may list sets an earlier unit of the same build used). */
|
|
33
|
+
iconSets?: string[];
|
|
34
|
+
}
|
|
35
|
+
export type SsgUnitManifest = UnitManifest & {
|
|
36
|
+
ssg: SsgUnitData;
|
|
37
|
+
};
|
|
38
|
+
/** The unit's key, as site-files names a unit (`calico/_/3.32`). */
|
|
39
|
+
export declare function unitKey(u: Pick<BuildUnit, "product" | "locale" | "version">): string;
|
|
40
|
+
/** Where a unit's manifest is written, from the site root. */
|
|
41
|
+
export declare function manifestPath(u: Pick<BuildUnit, "product" | "locale" | "version">): string;
|
|
42
|
+
/** The folder the manifests sit in, from the site root. */
|
|
43
|
+
export declare const MANIFEST_DIR = "_dogsbay/units/";
|
|
44
|
+
export declare function makeManifest(u: BuildUnit, ssg: SsgUnitData, redirects: Array<[string, string, number]>): SsgUnitManifest;
|
|
45
|
+
/**
|
|
46
|
+
* A manifest read back (JSON text or a parsed value), checked: undefined, with a reason, when it is
|
|
47
|
+
* not one this build can use (another format, or written by something other than dogsbay-ssg).
|
|
48
|
+
*/
|
|
49
|
+
export declare function parseManifest(raw: unknown): {
|
|
50
|
+
manifest?: SsgUnitManifest;
|
|
51
|
+
problem?: string;
|
|
52
|
+
};
|
|
53
|
+
/** The hashed client files (`dogsbay-<hash>.js`, in `_dogsbay/assets/`) an update removes when no unit loads them. */
|
|
54
|
+
export declare const CLIENT_PATTERN: RegExp;
|
|
55
|
+
/** What removing stale files needs of a manifest. */
|
|
56
|
+
export interface UnitFiles {
|
|
57
|
+
prefix: string;
|
|
58
|
+
files: string[];
|
|
59
|
+
client: string;
|
|
60
|
+
}
|
|
61
|
+
/** A manifest's `UnitFiles`, or null when the text is not a manifest this version can read. */
|
|
62
|
+
export declare function unitFilesOf(text: string): UnitFiles | null;
|
|
63
|
+
/**
|
|
64
|
+
* After a one-unit update, the files to remove (site paths). `previous` and `now` are the site's
|
|
65
|
+
* manifests before and after the build, by path (null: unreadable); a unit counts as rebuilt when this
|
|
66
|
+
* build wrote its manifest (`written` holds every path the build wrote).
|
|
67
|
+
* - A rebuilt unit's files its previous manifest listed and its new one does not (pages deleted or
|
|
68
|
+
* moved), unless this build wrote them, or they are not in that unit's own folder: the unit whose
|
|
69
|
+
* prefix is the longest to hold the path (a version at the root holds the others' folders), so a
|
|
70
|
+
* manifest can only ever remove files of its own unit.
|
|
71
|
+
* - The hashed clients in `assets` (file names) no manifest loads any more; none when a manifest
|
|
72
|
+
* cannot be read, since its pages may load one.
|
|
73
|
+
*/
|
|
74
|
+
export declare function staleUnitFiles(previous: ReadonlyMap<string, UnitFiles | null>, now: ReadonlyMap<string, UnitFiles | null>, written: ReadonlySet<string>, assets: readonly string[]): string[];
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
export declare const CLIENT_JS: string;
|
|
2
|
+
/**
|
|
3
|
+
* The name the pages load the client by, from its content (_dogsbay/assets/<CLIENT_FILE>): a unit built
|
|
4
|
+
* by another version of the client keeps loading its own (plans/unit-publishing.md).
|
|
5
|
+
*/
|
|
6
|
+
export declare const CLIENT_FILE: string;
|
|
7
|
+
/** This package's version, recorded in each unit's manifest. */
|
|
8
|
+
export declare const SSG_VERSION: string;
|
|
2
9
|
export declare const THEME_TEMPLATES: Record<string, string>;
|
|
3
10
|
export declare const CLIENT_CANDIDATES: string[];
|
|
4
11
|
/** _dogsbay/assets/THIRD-PARTY-NOTICES.txt: the client's packages and Tailwind (scripts/notices.mjs). */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dogsbay/ssg",
|
|
3
|
-
"version": "0.2.0-beta.151",
|
|
3
|
+
"version": "0.2.0-beta.151.1",
|
|
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",
|