// mechLine が拾えずに素の内部語のまま出してしまう鍵を、ソースから全部数える。
import fs from 'fs';
const src = fs.readFileSync('app/game/index.html', 'utf8');

// 表に載っている鍵（ここにあれば言葉になる）
function tableKeys(name) {
  const i = src.search(new RegExp('const ' + name + '\\s*=\\s*\\{'));
  if (i < 0) return new Set();
  let d = 0, j = i, started = false;
  for (; j < src.length; j++) {
    const c = src[j];
    if (c === '{') { d++; started = true; }
    else if (c === '}') { d--; if (started && d === 0) { j++; break; } }
  }
  const b = src.slice(i, j);
  // 第一階層のキーだけ拾う: 改行 + 空白 + 名前 + ':'
  return new Set([...b.matchAll(/[\n{,]\s*([A-Za-z_$][\w$]*)\s*:\s*\(/g)].map(m => m[1]));
}
const covered = new Set([...tableKeys('MECH_ADD'), ...tableKeys('MECH_MULT'),
                         ...tableKeys('WORLD_ADD'), ...tableKeys('WORLD_MULT')]);

// 実際に mechLine / add / mult に渡される鍵
const used = new Map();
const bump = k => used.set(k, (used.get(k) || 0) + 1);
for (const m of src.matchAll(/mechLine\(\s*"([\w$]+)"/g)) bump(m[1]);
for (const m of src.matchAll(/\b(?:add|mult)\s*:\s*\{([^{}]*)\}/g))
  for (const k of m[1].matchAll(/([A-Za-z_$][\w$]*)\s*:/g)) bump(k[1]);

console.log('表にある鍵:', covered.size);
console.log('使われている鍵:', used.size);
const miss = [...used.entries()].filter(([k]) => !covered.has(k)).sort((a, b) => b[1] - a[1]);
console.log('\n表に無く、内部語のまま出るもの:', miss.length, '種');
miss.forEach(([k, n]) => console.log(`  ${String(n).padStart(4)}箇所  ${k}`));
console.log('\n表にある鍵の一覧:');
console.log('  ' + [...covered].sort().join(' '));
