Skip to content

Commit c590cb6

Browse files
aster-voidclaude
andcommitted
scripts(check-parity): NO_IMAGE 検知をレンダリング属性のみに限定
SvelteKit の hydration payload (`coverUrl: "+/images/..."` 文字列) を 誤検知して fail していたのを、img[src] / og:image / twitter:image / JSON-LD image の実描画属性のみ検査する形に修正。 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 783e856 commit c590cb6

1 file changed

Lines changed: 39 additions & 6 deletions

File tree

scripts/check-parity.ts

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -218,24 +218,57 @@ async function checkMeta() {
218218

219219
// === 4. no-image fallback ===
220220
async function checkNoImage() {
221-
// 旧 28 件のうち代表サンプル
221+
// 旧 28 件のうち代表サンプル。
222+
// SvelteKit の hydration payload には生データ (`coverUrl: "+/images/..."`) が含まれることがあるが、
223+
// それは描画には使われない。実際にレンダリングされる属性 (img[src], meta[content], JSON-LD) のみ検査する。
222224
const samples = [
223225
"/articles/2019-11-03-utcode-lectures-01",
224226
"/articles/2021-09-24-tuk-programming-workshop",
225227
"/articles/2022-07-15-summer-events",
226228
"/articles/2019-09-30-2019a-schedule",
227229
];
230+
const brokenPattern = /\+\/images\/no-image\.svg/;
231+
const renderingChecks: Array<{ name: string; re: RegExp }> = [
232+
{ name: "img[src]", re: /<img\b[^>]*\bsrc\s*=\s*["'][^"']*\+\/images\/no-image\.svg/i },
233+
{
234+
name: "og:image",
235+
re: /<meta\b[^>]*\bproperty\s*=\s*["']og:image["'][^>]*\bcontent\s*=\s*["'][^"']*\+\/images\/no-image\.svg/i,
236+
},
237+
{
238+
name: "og:image (reverse)",
239+
re: /<meta\b[^>]*\bcontent\s*=\s*["'][^"']*\+\/images\/no-image\.svg["'][^>]*\bproperty\s*=\s*["']og:image["']/i,
240+
},
241+
{
242+
name: "twitter:image",
243+
re: /<meta\b[^>]*\bname\s*=\s*["']twitter:image["'][^>]*\bcontent\s*=\s*["'][^"']*\+\/images\/no-image\.svg/i,
244+
},
245+
{
246+
name: "twitter:image (reverse)",
247+
re: /<meta\b[^>]*\bcontent\s*=\s*["'][^"']*\+\/images\/no-image\.svg["'][^>]*\bname\s*=\s*["']twitter:image["']/i,
248+
},
249+
];
228250
for (const path of samples) {
229251
const r = await fetchFollow(path);
230252
if (r.status !== 200) {
231253
record("NO_IMAGE", path, false, `article not reachable (status=${r.status})`);
232254
continue;
233255
}
234-
const broken =
235-
r.body.includes("+/images/no-image.svg") ||
236-
r.body.includes("%2B/images/no-image.svg") ||
237-
r.body.includes("+%2Fimages%2Fno-image.svg");
238-
record("NO_IMAGE", path, !broken, broken ? "found broken `+/images/no-image.svg`" : "ok");
256+
const failures = renderingChecks.filter((c) => c.re.test(r.body)).map((c) => c.name);
257+
// JSON-LD inside <script type="application/ld+json"> の image フィールドも検査
258+
const ldJsonMatch = r.body.match(
259+
/<script[^>]*type=["']application\/ld\+json["'][^>]*>([\s\S]*?)<\/script>/i,
260+
);
261+
if (ldJsonMatch?.[1]) {
262+
const imageMatch = ldJsonMatch[1].match(/"image"\s*:\s*"([^"]+)"/);
263+
if (imageMatch?.[1] && brokenPattern.test(imageMatch[1])) {
264+
failures.push("ld+json image");
265+
}
266+
}
267+
if (failures.length > 0) {
268+
record("NO_IMAGE", path, false, `broken in: ${failures.join(", ")}`);
269+
} else {
270+
record("NO_IMAGE", path, true, "ok");
271+
}
239272
}
240273
}
241274

0 commit comments

Comments
 (0)