hd-garden 0.5.1 → 0.5.3

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.
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Links to the site's own address. A post may write a full URL such as
3
+ * `https://example.com/blog/post/`; it is still an internal link.
4
+ *
5
+ * The site address comes from `url` in site.config.yaml, falling back to the
6
+ * SITE_URL the build already uses. Both http and https count, and so do the
7
+ * host with and without `www.`. Any other subdomain is a different site.
8
+ */
9
+
10
+ /** The configured site address, or "" when none is set. */
11
+ export function configuredSiteAddress(config = {}, env = {}) {
12
+ const value = config?.url ?? config?.siteUrl ?? env.SITE_URL ?? env.NEXT_PUBLIC_SITE_URL ?? "";
13
+ return String(value).trim();
14
+ }
15
+
16
+ const hostKey = (hostname) => hostname.toLowerCase().replace(/\.$/u, "").replace(/^www\./u, "");
17
+ const normalizeBase = (basePath) => {
18
+ const trimmed = String(basePath ?? "").trim().replace(/\/+$/u, "");
19
+ return !trimmed ? "" : trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
20
+ };
21
+
22
+ /**
23
+ * Returns `href => path | null`. The path is root-relative and keeps the base
24
+ * path, query and hash; null means the link points somewhere else.
25
+ */
26
+ export function sameSiteMatcher(siteAddress, basePath = "") {
27
+ let site;
28
+ try {
29
+ site = siteAddress ? new URL(siteAddress) : null;
30
+ } catch {
31
+ site = null;
32
+ }
33
+ if (!site || !/^https?:$/u.test(site.protocol)) return () => null;
34
+ const key = hostKey(site.hostname);
35
+ const port = site.port;
36
+ // A base path written into the site address counts the same as NEXT_PUBLIC_BASE_PATH.
37
+ const base = normalizeBase(basePath) || normalizeBase(site.pathname);
38
+ return (href) => {
39
+ if (typeof href !== "string" || !/^(https?:)?\/\//iu.test(href.trim())) return null;
40
+ let url;
41
+ try {
42
+ url = new URL(href.trim(), `${site.protocol}//${site.host}/`);
43
+ } catch {
44
+ return null;
45
+ }
46
+ if (!/^https?:$/u.test(url.protocol) || url.username || url.password) return null;
47
+ if (hostKey(url.hostname) !== key || url.port !== port) return null;
48
+ const pathname = url.pathname || "/";
49
+ if (base && pathname !== base && !pathname.startsWith(`${base}/`)) return null;
50
+ return `${pathname}${url.search}${url.hash}`;
51
+ };
52
+ }
53
+
54
+ /**
55
+ * How an article link renders: a link back to the site becomes its
56
+ * root-relative path and opens in place; other full URLs are external.
57
+ */
58
+ export function articleLink(href, sameSite) {
59
+ if (!href) return { href, external: false };
60
+ const local = sameSite(href);
61
+ if (local !== null) return { href: local, external: false };
62
+ return { href, external: /^(https?:)?\/\//iu.test(href) };
63
+ }