Files
tutti/tools/scripts/package-pack-svg-data-urls.mjs
agent-radar 2ed3415fb7
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

72 lines
2.0 KiB
JavaScript

import { readFile, readdir } from "node:fs/promises";
import { extname, join, relative, resolve } from "node:path";
const javascriptExtensions = new Set([".cjs", ".js", ".mjs"]);
const rawSvgDataUrlPattern =
/data:image\/svg\+xml(?:;charset=[^,]+)?,\s*\x3csvg\b/i;
const relativeSvgUrlPattern = /["']\.\/[^"']+\.svg["']/gi;
export async function packedFilesWithRawSvgDataUrls(packageRoot) {
const normalizedRoot = resolve(packageRoot);
const files = await listFiles(normalizedRoot);
const violations = [];
for (const file of files) {
if (!javascriptExtensions.has(extname(file))) {
continue;
}
const source = await readFile(file, "utf8");
if (rawSvgDataUrlPattern.test(source)) {
violations.push(relative(normalizedRoot, file).replaceAll("\\", "/"));
}
}
return violations.sort();
}
export async function packedFilesWithRelativeSvgUrls(packageRoot) {
const normalizedRoot = resolve(packageRoot);
const files = await listFiles(normalizedRoot);
const violations = [];
for (const file of files) {
if (!javascriptExtensions.has(extname(file))) {
continue;
}
const source = await readFile(file, "utf8");
if (hasConsumerUnresolvableRelativeSvgUrl(source)) {
violations.push(relative(normalizedRoot, file).replaceAll("\\", "/"));
}
}
return violations.sort();
}
function hasConsumerUnresolvableRelativeSvgUrl(source) {
for (const match of source.matchAll(relativeSvgUrlPattern)) {
const prefix = source.slice(Math.max(0, match.index - 32), match.index);
if (!/new URL\(\s*$/.test(prefix)) {
return true;
}
}
return false;
}
async function listFiles(directory) {
const entries = await readdir(directory, { withFileTypes: true });
const files = [];
for (const entry of entries) {
const path = join(directory, entry.name);
if (entry.isDirectory()) {
files.push(...(await listFiles(path)));
} else if (entry.isFile()) {
files.push(path);
}
}
return files;
}