Files
neon-survivors/tools/scan-calls.js
T
neon-survivors-dev 796880375e NEON SURVIVORS v1.1 — full-featured bullet-heaven survivor game
Vanilla JS + Canvas, zero dependencies, offline-first PWA.

Gameplay:
- 11 weapons x8 levels + 11 evolutions (chest-based), incl. timed mines
- 13 passives, crit system with directional hit-sparks & hit-stop
- 10 characters w/ unique mods + unlock conditions, gold cosmetic skins
- 3 biomes (Neon Graveyard / Frozen Hollow / Magma Rift) each with own
  spawn tables, boss plans and music flavor; Endless mode + surges;
  4 difficulty grades; breakable crystal-lamp props
- Elite random affixes (Swift/Sturdy/Volatile), 4 bosses, win flow
- Achievements (23) w/ gold rewards, run history, daily seeded challenge

Tech:
- Cinematic canvas main-menu scene, game-feel FX suite (trails, muzzle,
  status tints, low-HP pulse), viewport culling + particle pooling
- WebAudio synth SFX + generative per-biome soundtrack
- Gamepad support, remappable keys, touch joystick, fullscreen
- i18n VI/EN, localStorage saves w/ export-import codes
- Cloudflare Workers leaderboard scaffold (KV) w/ signed submits
- Headless integrity test-suite (node test/integrity.js)
2026-08-23 07:01:22 +00:00

50 lines
2.8 KiB
JavaScript

// dev tool: scan for calls to members/functions that are never defined
'use strict';
const fs = require('fs');
const files = fs.readdirSync('js').filter(f => f.endsWith('.js'));
let all = '';
for (const f of files) all += fs.readFileSync('js/' + f, 'utf8') + '\n';
const defs = new Set();
for (const m of all.matchAll(/(?:^|\n)[ \t]*(?:async\s+)?([A-Za-z_$][\w$]*)\s*\([^()]*\)\s*\{/g)) defs.add(m[1]);
for (const m of all.matchAll(/\bfunction\s+([A-Za-z_$][\w$]*)/g)) defs.add(m[1]);
for (const m of all.matchAll(/(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=/g)) defs.add(m[1]);
const allow = new Set([
'push','pop','shift','unshift','splice','slice','concat','join','map','filter','forEach',
'reduce','find','findIndex','some','every','includes','indexOf','sort','fill','keys',
'values','entries','from','isArray','assign','create','freeze','getOwnPropertyNames',
'setItem','getItem','removeItem','clear','log','warn','error','now','floor','ceil','round',
'abs','min','max','sqrt','pow','sin','cos','tan','atan','atan2','random','hypot','sign','exp',
'add','has','delete','get','set',
'translate','rotate','scale','save','restore','beginPath','closePath','moveTo','lineTo','arc',
'arcTo','quadraticCurveTo','bezierCurveTo','rect','fill','stroke','clip','fillText','strokeText',
'measureText','drawImage','createLinearGradient','createRadialGradient','createPattern','fillRect',
'strokeRect','clearRect','setTransform','resetTransform','ellipse',
'play','pause','resume','connect','start','stop','setValueAtTime','linearRampToValueAtTime',
'exponentialRampToValueAtTime','createGain','createOscillator','createBuffer','createBufferSource',
'createBiquadFilter',
'addEventListener','removeEventListener','preventDefault','stopPropagation','appendChild',
'removeChild','remove','querySelector','querySelectorAll','getElementById','createElement',
'toggle','contains','setAttribute','getAttribute','insertBefore','closest','matches',
'test','exec','replace','split','trim','toLowerCase','toUpperCase','charAt','charCodeAt',
'padStart','padEnd','repeat','match','matchAll','toString','toFixed','stringify','parse',
'requestAnimationFrame','setTimeout','setInterval','clearTimeout','clearInterval','fetch',
'then','catch','finally','bind','call','apply'
]);
let bad = 0;
for (const m of all.matchAll(/\b(UI|Sys|R|Snd|Store|GAME)\.([A-Za-z_$][\w$]*)\s*\(/g)) {
const meth = m[2];
if (!allow.has(meth) && !defs.has(meth)) { console.log('MISSING:', m[1] + '.' + meth); bad++; }
}
console.log(bad === 0 ? 'No missing member calls OK' : bad + ' issues');
for (const f of ['render.js', 'systems.js', 'ui.js', 'audio.js', 'save.js']) {
const src = fs.readFileSync('js/' + f, 'utf8');
for (const m of src.matchAll(/this\.(_?[A-Za-z_$][\w$]*)\s*\(/g)) {
if (!defs.has(m[1])) console.log('MISSING this.' + m[1] + ' in ' + f);
}
}
console.log('this-method scan done');