@piercebarney/whs-eleventy 2026.9.23 → 2026.9.24

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.
@@ -135,7 +135,7 @@ function outputHas(urlPath) {
135
135
  return fs.existsSync(asFile + "/index.html") || fs.existsSync(asFile + ".html");
136
136
  }
137
137
 
138
- function checkRef(file, pageUrl, raw, { external = true, isHyperlink = false } = {}) {
138
+ function checkRef(file, pageUrl, resolveBase, raw, { external = true, isHyperlink = false } = {}) {
139
139
  if (!raw) return;
140
140
  const v = raw.trim();
141
141
  if (v === "" || v.startsWith("data:") || v.startsWith("mailto:") || v.startsWith("tel:")) return;
@@ -185,13 +185,15 @@ function checkRef(file, pageUrl, raw, { external = true, isHyperlink = false } =
185
185
  return;
186
186
  }
187
187
  // relative path — resolve against the page dir
188
- const resolved = path.posix.join(pageUrl, v);
188
+ const resolved = path.posix.join(resolveBase, v);
189
189
  if (!outputHas(resolved)) err(file, `relative reference does not resolve: ${v}`);
190
190
  }
191
191
 
192
192
  for (const f of htmlFiles) {
193
193
  const rel = "/" + path.relative(SITE, f).replace(/\\/g, "/");
194
194
  const pageUrl = rel.replace(/index\.html$/, "");
195
+ const dir = path.posix.dirname(rel);
196
+ const resolveBase = dir === "/" ? "/" : dir + "/";
195
197
  const root = parse(fs.readFileSync(f, "utf8"));
196
198
 
197
199
  // CSP-safety: the strict CSP (script-src 'self'; style-src 'self') rejects
@@ -216,7 +218,7 @@ for (const f of htmlFiles) {
216
218
 
217
219
  root.querySelectorAll("a[href]").forEach((a) => {
218
220
  const href = a.getAttribute("href");
219
- checkRef(f, pageUrl, href, { isHyperlink: true });
221
+ checkRef(f, pageUrl, resolveBase, href, { isHyperlink: true });
220
222
  if (/^https?:\/\//i.test(href || "")) {
221
223
  let origin;
222
224
  try {
@@ -233,12 +235,18 @@ for (const f of htmlFiles) {
233
235
  }
234
236
  });
235
237
 
236
- root.querySelectorAll("link[href]").forEach((l) => checkRef(f, pageUrl, l.getAttribute("href")));
237
- root.querySelectorAll("script[src]").forEach((s) => checkRef(f, pageUrl, s.getAttribute("src")));
238
- root.querySelectorAll("img[src]").forEach((i) => checkRef(f, pageUrl, i.getAttribute("src")));
238
+ root
239
+ .querySelectorAll("link[href]")
240
+ .forEach((l) => checkRef(f, pageUrl, resolveBase, l.getAttribute("href")));
241
+ root
242
+ .querySelectorAll("script[src]")
243
+ .forEach((s) => checkRef(f, pageUrl, resolveBase, s.getAttribute("src")));
244
+ root
245
+ .querySelectorAll("img[src]")
246
+ .forEach((i) => checkRef(f, pageUrl, resolveBase, i.getAttribute("src")));
239
247
  root
240
248
  .querySelectorAll('meta[property="og:image"], meta[name="twitter:image"]')
241
- .forEach((m) => checkRef(f, pageUrl, m.getAttribute("content")));
249
+ .forEach((m) => checkRef(f, pageUrl, resolveBase, m.getAttribute("content")));
242
250
 
243
251
  root.querySelectorAll('script[type="application/ld+json"]').forEach((s, i) => {
244
252
  let data;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@piercebarney/whs-eleventy",
3
- "version": "2026.9.23",
3
+ "version": "2026.9.24",
4
4
  "description": "The web house style's Eleventy + Netlify tooling — the compliance sweep, the infra doctor, the link/CSP integrity check, and the a11y scan, shared by every project on the stack.",
5
5
  "bin": {
6
6
  "whs": "cli.js"
@@ -21,6 +21,34 @@ enforced, new *opt-in* chapters/capabilities, tooling-only changes — is
21
21
 
22
22
  ---
23
23
 
24
+ ## 2026-09-24 [non-breaking]
25
+
26
+ ### packages/whs-eleventy
27
+
28
+ `check-links.js` resolved a relative reference (`favicon.svg`, `styles.css`,
29
+ etc.) against `pageUrl`, a literal `index.html`-stripped path — correct for
30
+ directory-style permalinks (`/foo/index.html` → `/foo/`) but wrong for a
31
+ flat, non-directory permalink like `privacy.html`, where `pageUrl` stayed
32
+ `/privacy.html` and `path.posix.join` then treated it as if it were a
33
+ directory, producing false `relative reference does not resolve` findings
34
+ for files that genuinely exist and resolve correctly in a real browser.
35
+ `pageUrl` is also used for same-page `#anchor` lookups, where the literal
36
+ value is exactly what's needed — so the fix doesn't touch `pageUrl` itself.
37
+ Instead `checkRef()` now takes a separate `resolveBase` (the directory
38
+ containing the page, via `path.posix.dirname`) used only for relative-
39
+ reference resolution, leaving anchor lookups untouched. Found while
40
+ covenant-in-color's adoption session ran the newly-fixed `npm run links` for
41
+ the first time and filed as
42
+ `feedback/2026-09-23-check-links-relative-resolution-non-directory-permalink.md`;
43
+ fixed in `7edbc68`.
44
+
45
+ This is the fourth `packages/whs-eleventy`-only fix shipped this week (the
46
+ third, 2026.9.23, already published and live) — `core.md`, `stacks/*.md`,
47
+ and `index.json` content are unchanged; only the doc pins and
48
+ `packages/whs-eleventy/package.json` (now `2026.9.24`) moved.
49
+
50
+ ---
51
+
24
52
  ## 2026-09-23 — Republish 2026-09-22-2 as a clean bare-date version [non-breaking]
25
53
 
26
54
  ### packages/whs-eleventy
package/standard/core.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Web project house style — CORE (stack-agnostic)
2
2
 
3
- **Version:** 2026-09-23 · **Status:** active
3
+ **Version:** 2026-09-24 · **Status:** active
4
4
 
5
5
  This is the stack-agnostic contract every web project follows, regardless of
6
6
  framework, host, or CSS system. It says **what** must be true, with concrete
@@ -1467,7 +1467,7 @@ governs it and follow that chapter — the slugs are the index (a `<script>` →
1467
1467
  - production-url: https://example.com
1468
1468
  - content-type: tool # tool | article (article => feeds)
1469
1469
  - publishing-rate: ~5 pages/week
1470
- - standard-version: 2026-09-23 # recommended — enables standard-version drift tracking (#compliance)
1470
+ - standard-version: 2026-09-24 # recommended — enables standard-version drift tracking (#compliance)
1471
1471
  ```
1472
1472
 
1473
1473
  If the section is absent, the assistant's first action is to run the flow above