|
| 1 | +import { describe, it, expect } from "vitest"; |
| 2 | +import fs from "node:fs"; |
| 3 | +import path from "node:path"; |
| 4 | + |
| 5 | +const SRC_DIR = path.resolve(import.meta.dirname, "../src"); |
| 6 | + |
| 7 | +/** Recursively collect all files matching an extension under dir. */ |
| 8 | +function collectFiles(dir, ext) { |
| 9 | + const results = []; |
| 10 | + for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { |
| 11 | + const full = path.join(dir, entry.name); |
| 12 | + if (entry.isDirectory()) { |
| 13 | + results.push(...collectFiles(full, ext)); |
| 14 | + } else if (entry.isFile() && entry.name.endsWith(ext)) { |
| 15 | + results.push(full); |
| 16 | + } |
| 17 | + } |
| 18 | + return results; |
| 19 | +} |
| 20 | + |
| 21 | +/** Match <img ...src="https://..."> across tag boundaries (multiline). */ |
| 22 | +const IMG_EXTERNAL_SRC = /<img\b[^>]*\bsrc=["']https?:\/\/[^"']+["'][^>]*>/gis; |
| 23 | + |
| 24 | +describe("external image references in source files", () => { |
| 25 | + it("no .astro file uses an external http(s) URL as <img src>", () => { |
| 26 | + const astroFiles = collectFiles(SRC_DIR, ".astro"); |
| 27 | + const violations = []; |
| 28 | + |
| 29 | + for (const file of astroFiles) { |
| 30 | + const content = fs.readFileSync(file, "utf8"); |
| 31 | + const matches = [...content.matchAll(IMG_EXTERNAL_SRC)]; |
| 32 | + for (const m of matches) { |
| 33 | + const lineNumber = content.slice(0, m.index).split("\n").length; |
| 34 | + violations.push(`${path.relative(SRC_DIR, file)}:${lineNumber}: ${m[0].slice(0, 80)}…`); |
| 35 | + } |
| 36 | + } |
| 37 | + |
| 38 | + expect(violations, `External <img src> URLs found:\n${violations.join("\n")}`).toEqual([]); |
| 39 | + }); |
| 40 | +}); |
0 commit comments