diff --git a/src/unfold/site/manifest.ts b/src/unfold/site/manifest.ts index 8eb0fc8..3648886 100644 --- a/src/unfold/site/manifest.ts +++ b/src/unfold/site/manifest.ts @@ -1,5 +1,7 @@ import { DOMParser, type HTMLDocument } from "deno-dom-wasm"; import { normalizeSiteUrl } from "./site_url.ts"; +import type { VaultNode } from "../inputs/jsonld/types.ts"; +import { loadVault } from "../inputs/jsonld/loader.ts"; type ManifestPage = { path: string; @@ -209,6 +211,15 @@ const requireVaultPath = (value?: string): string => { return raw; }; +/// Unlike its siblings above, this does not throw: `defaultSiteUrl` already +/// supplies a normalized SITE_URL-or-placeholder, so an absent site URL has a +/// sensible answer. The fallback argument carries the WebSite node's url when +/// building from the vault graph. +const requireSiteUrl = (value?: string, fallback?: string): string => { + const raw = value?.trim() || fallback?.trim(); + return raw ? normalizeSiteUrl(raw) : defaultSiteUrl(); +}; + const hasJsonLdType = (node: VaultNode, type: string): boolean => { const value = node["@type"]; if (!value) return false; diff --git a/src/unfold/site/site_url.ts b/src/unfold/site/site_url.ts new file mode 100644 index 0000000..9ecb3d6 --- /dev/null +++ b/src/unfold/site/site_url.ts @@ -0,0 +1,18 @@ +const stripTrailingSlash = (value: string): string => value.replace(/\/$/, ""); + +const stripFoldEnginePrefix = (pathname: string): string => + pathname.replace(/^\/fold-engine(?=\/|$)/, ""); + +export const normalizeSiteUrl = (value: string): string => { + const trimmed = stripTrailingSlash(value.trim()); + try { + const url = new URL(trimmed); + const normalizedPath = stripFoldEnginePrefix( + stripTrailingSlash(url.pathname), + ); + url.pathname = normalizedPath || "/"; + return stripTrailingSlash(url.toString()); + } catch { + return stripTrailingSlash(stripFoldEnginePrefix(trimmed)); + } +};