scripts/detect_block_themes.mjs
A supporting file of the wp-block-themes skill, shown as source.
import fs from "node:fs";
import path from "node:path";
const DEFAULT_IGNORES = new Set([
".git",
"node_modules",
"vendor",
"dist",
"build",
"coverage",
".next",
".turbo",
]);
function statSafe(p) {
try {
return fs.statSync(p);
} catch {
return null;
}
}
function existsDir(p) {
const st = statSafe(p);
return Boolean(st && st.isDirectory());
}
function readJsonSafe(p) {
try {
return JSON.parse(fs.readFileSync(p, "utf8"));
} catch {
return null;
}
}
function findFilesRecursive(repoRoot, predicate, { maxFiles = 6000, maxDepth = 10 } = {}) {
const results = [];
const queue = [{ dir: repoRoot, depth: 0 }];
let visited = 0;
while (queue.length > 0) {
const { dir, depth } = queue.shift();
if (depth > maxDepth) continue;
let entries;
try {
entries = fs.readdirSync(dir, { withFileTypes: true });
} catch {
continue;
}
for (const ent of entries) {
const fullPath = path.join(dir, ent.name);
if (ent.isDirectory()) {
if (DEFAULT_IGNORES.has(ent.name)) continue;
queue.push({ dir: fullPath, depth: depth + 1 });
continue;
}
if (!ent.isFile()) continue;
visited += 1;
if (visited > maxFiles) return { results, truncated: true };
if (predicate(fullPath)) results.push(fullPath);
}
}
return { results, truncated: false };
}
function summarizeTheme(repoRoot, themeJsonPath) {
const json = readJsonSafe(themeJsonPath);
const rel = path.relative(repoRoot, themeJsonPath);
const rootDir = path.dirname(rel);
const templatesDir = path.join(repoRoot, rootDir, "templates");
const partsDir = path.join(repoRoot, rootDir, "parts");
const patternsDir = path.join(repoRoot, rootDir, "patterns");
const stylesDir = path.join(repoRoot, rootDir, "styles");
const hasTemplates = existsDir(templatesDir);
const hasParts = existsDir(partsDir);
return {
themeRoot: rootDir,
themeJson: rel,
version: typeof json?.version === "number" ? json.version : null,
hasTemplates,
hasParts,
hasPatterns: existsDir(patternsDir),
hasStyles: existsDir(stylesDir),
isBlockTheme: hasTemplates || hasParts,
};
}
function main() {
const repoRoot = process.cwd();
const { results: themeJsonFiles, truncated } = findFilesRecursive(repoRoot, (p) => path.basename(p) === "theme.json", {
maxFiles: 8000,
maxDepth: 12,
});
const themes = themeJsonFiles.map((p) => summarizeTheme(repoRoot, p));
const report = {
tool: { name: "detect_block_themes", version: "0.1.0" },
repoRoot,
truncated,
count: themes.length,
themes,
};
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
}
main();