import { test } from 'node:test'; import assert from 'node:assert/strict'; import { readFile } from 'node:fs/promises'; import { fileURLToPath } from 'node:url'; import { dirname, resolve } from 'node:path'; const __dirname = dirname(fileURLToPath(import.meta.url)); const DATA_PATH = resolve(__dirname, '..', 'lint-forbidden-words.json'); async function loadData() { const raw = await readFile(DATA_PATH, 'utf8'); return JSON.parse(raw); } test('forbidden-words JSON parses successfully', async () => { const data = await loadData(); assert.equal(typeof data, 'object'); assert.ok(data !== null); }); test('top-level keys present (tier1, tier2, tier3)', async () => { const data = await loadData(); assert.ok(Array.isArray(data.tier1), 'tier1 must be an array'); assert.ok(Array.isArray(data.tier2), 'tier2 must be an array'); assert.ok(Array.isArray(data.tier3), 'tier3 must be an array'); }); test('tier1 has 19 entries (verbatim from research/03 SC-3 list line 200)', async () => { const data = await loadData(); assert.equal(data.tier1.length, 19, `expected 19 tier1 entries, got ${data.tier1.length}`); }); test('tier2 has 24 entries (verbatim from research/03 SC-3 list line 201)', async () => { const data = await loadData(); assert.equal(data.tier2.length, 24, `expected 24 tier2 entries, got ${data.tier2.length}`); }); test('tier3 has 12 entries (verbatim from research/03 SC-3 list line 202 + hook)', async () => { const data = await loadData(); assert.equal(data.tier3.length, 12, `expected 12 tier3 entries, got ${data.tier3.length}`); }); test('every entry has required fields (word, replacement, source, tier)', async () => { const data = await loadData(); for (const tierName of ['tier1', 'tier2', 'tier3']) { for (const entry of data[tierName]) { assert.ok(typeof entry.word === 'string' && entry.word.length > 0, `${tierName} entry missing 'word': ${JSON.stringify(entry)}`); assert.ok(typeof entry.replacement === 'string' && entry.replacement.length > 0, `${tierName} entry "${entry.word}" missing 'replacement'`); assert.ok(typeof entry.source === 'string' && entry.source.length > 0, `${tierName} entry "${entry.word}" missing 'source'`); assert.ok(entry.tier === Number(tierName.replace('tier', '')), `${tierName} entry "${entry.word}" has wrong tier: ${entry.tier}`); } } }); test('tier1 spot-check — required absolute prohibitions present', async () => { const data = await loadData(); const words = data.tier1.map((e) => e.word); for (const required of ['utilize', 'leverage', 'facilitate', 'terminate', 'abort', 'invalid', 'illegal', 'failed to', 'fatal', 'in order to']) { assert.ok(words.includes(required), `tier1 missing required word: ${required}`); } }); test('tier2 spot-check — condescending words present', async () => { const data = await loadData(); const words = data.tier2.map((e) => e.word); for (const required of ['simply', 'just', 'obviously', 'clearly']) { assert.ok(words.includes(required), `tier2 missing required word: ${required}`); } }); test('tier3 spot-check — domain-specific jargon present', async () => { const data = await loadData(); const words = data.tier3.map((e) => e.word); for (const required of ['CLAUDE.md', '@import', 'MCP', 'hook', 'frontmatter']) { assert.ok(words.includes(required), `tier3 missing required word: ${required}`); } }); test('no duplicate words across tiers', async () => { const data = await loadData(); const allWords = [ ...data.tier1.map((e) => e.word), ...data.tier2.map((e) => e.word), ...data.tier3.map((e) => e.word), ]; const seen = new Set(); const dupes = []; for (const w of allWords) { if (seen.has(w)) dupes.push(w); seen.add(w); } assert.equal(dupes.length, 0, `duplicate forbidden words across tiers: ${dupes.join(', ')}`); });