qa fixes: full sitemap coverage + a11y check recognises empty alt
- sitemap.xml.js now includes services, projects (+ DB-driven project pages), resume, changelog, faq (was blog-only) — clears 12 QA sitemap warnings - runQa a11y check treats a bare/empty alt as present (valid decorative image), fixing a false positive on the blog cover
This commit is contained in:
parent
d548d8a8a8
commit
87fceea726
2 changed files with 19 additions and 2 deletions
|
|
@ -639,8 +639,12 @@ const qaAbs = (href, pagePath) => { try { return new URL(href, QA_BASE + pagePat
|
||||||
const qaGrabAll = (re, html) => [...String(html).matchAll(re)].map((m) => m[1]);
|
const qaGrabAll = (re, html) => [...String(html).matchAll(re)].map((m) => m[1]);
|
||||||
const qaFirst = (re, html) => { const m = String(html).match(re); return m ? m[1].trim() : ""; };
|
const qaFirst = (re, html) => { const m = String(html).match(re); return m ? m[1].trim() : ""; };
|
||||||
function qaImgsNoAlt(html) {
|
function qaImgsNoAlt(html) {
|
||||||
|
// An image "has alt" if it carries an alt attribute at all — including an
|
||||||
|
// empty one (alt="" or a bare `alt`), which is the valid, deliberate signal
|
||||||
|
// for a decorative image. Only a total absence of alt is a finding.
|
||||||
|
const hasAlt = (tag) => /\salt(\s*=|[\s>\/])/i.test(tag);
|
||||||
return [...String(html).matchAll(/<img\b[^>]*>/gi)].map((m) => m[0])
|
return [...String(html).matchAll(/<img\b[^>]*>/gi)].map((m) => m[0])
|
||||||
.filter((tag) => !/\balt\s*=/i.test(tag))
|
.filter((tag) => !hasAlt(tag))
|
||||||
.map((tag) => (tag.match(/\bsrc=["']([^"']+)["']/i) || [])[1])
|
.map((tag) => (tag.match(/\bsrc=["']([^"']+)["']/i) || [])[1])
|
||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,27 @@
|
||||||
import { SITE, authors, categories, sortedPosts, tags } from "../lib/blog-data.js";
|
import { SITE, authors, categories, sortedPosts, tags } from "../lib/blog-data.js";
|
||||||
|
import { getProjects } from "../lib/projects.js";
|
||||||
|
|
||||||
const BASE_URL = SITE.url || "";
|
const BASE_URL = SITE.url || "";
|
||||||
|
|
||||||
export async function GET() {
|
export async function GET() {
|
||||||
const posts = await sortedPosts();
|
const posts = await sortedPosts();
|
||||||
|
const projects = await getProjects();
|
||||||
const entries = [
|
const entries = [
|
||||||
{ path: "/", changefreq: "weekly", priority: "1.0" },
|
{ path: "/", changefreq: "weekly", priority: "1.0" },
|
||||||
{ path: "/blog", changefreq: "daily", priority: "0.9" },
|
|
||||||
{ path: "/about", changefreq: "monthly", priority: "0.6" },
|
{ path: "/about", changefreq: "monthly", priority: "0.6" },
|
||||||
|
{ path: "/services", changefreq: "monthly", priority: "0.7" },
|
||||||
|
{ path: "/services/website-design", changefreq: "monthly", priority: "0.6" },
|
||||||
|
{ path: "/projects", changefreq: "weekly", priority: "0.8" },
|
||||||
|
{ path: "/resume", changefreq: "monthly", priority: "0.6" },
|
||||||
{ path: "/contact", changefreq: "monthly", priority: "0.5" },
|
{ path: "/contact", changefreq: "monthly", priority: "0.5" },
|
||||||
|
{ path: "/faq", changefreq: "monthly", priority: "0.4" },
|
||||||
|
{ path: "/changelog", changefreq: "weekly", priority: "0.3" },
|
||||||
|
{ path: "/blog", changefreq: "daily", priority: "0.9" },
|
||||||
|
...projects.map((project) => ({
|
||||||
|
path: `/projects/${project.slug}`,
|
||||||
|
changefreq: "monthly",
|
||||||
|
priority: "0.7",
|
||||||
|
})),
|
||||||
...posts.map((post) => ({
|
...posts.map((post) => ({
|
||||||
path: `/blog/${post.slug}`,
|
path: `/blog/${post.slug}`,
|
||||||
lastmod: post.updated || post.date,
|
lastmod: post.updated || post.date,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue