#!/usr/bin/env node // Copyright 2026 OpenObserve Inc. // // Pre-flight before deleting any CSS class rule (O2_STYLE_MIGRATION_PLAN.md §7.3). // Answers: "who actually uses this class?" — covering the ways a class name can // reach the DOM and escape a naive template grep (plan risks R1 / R5): // // 1. static class="… foo …" // 2. bound :class="{ foo: cond }" / :class="['foo']" / :class="x ? 'foo' : ''" // 3. JS classList.add('foo'), `status-${x}` fragments, string literals in .ts // 4. CSS the rules that DEFINE it (so you can see every definition site) // 5. specs assertions on the class (these break when you delete it) // // Usage: // node scripts/find-class-consumers.mjs logPage_bkcss histogram-container // node scripts/find-class-consumers.mjs --quiet foo # exit 1 if consumers exist // // Verdict per class: // NO CONSUMERS → safe to delete // SELF-CONTAINED → only the defining file uses it → colocate // HAS CONSUMERS → migrate consumers in the same PR import { readFileSync, readdirSync, statSync } from "node:fs"; import { join, extname, dirname } from "node:path"; import { fileURLToPath } from "node:url"; const __dirname = dirname(fileURLToPath(import.meta.url)); const SRC_DIR = join(__dirname, "..", "src"); const EXTS = new Set([".css", ".vue", ".ts", ".js", ".scss"]); const args = process.argv.slice(2); const quiet = args.includes("--quiet"); const names = args.filter((a) => !a.startsWith("--")); if (names.length === 0) { console.error("Usage: node scripts/find-class-consumers.mjs ..."); process.exit(2); } function walk(dir, files = []) { for (const entry of readdirSync(dir)) { if (entry === "node_modules" || entry === "dist") continue; const full = join(dir, entry); const stat = statSync(full); if (stat.isDirectory()) walk(full, files); else if (EXTS.has(extname(entry))) files.push(full); } return files; } const files = walk(SRC_DIR); const cache = new Map(); for (const f of files) cache.set(f, readFileSync(f, "utf8").split("\n")); const rel = (f) => f.replace(SRC_DIR + "/", "src/"); /** * Split a .vue file into template / script / style line ranges so we can say * *where* a hit lives — a hit in