#!/usr/bin/env node /** 前端静态检查: ①SFC 脚本未定义引用扫描 ②前端 API 路径与后端路由一致性比对 */ const fs = require('fs'); const path = require('path'); const ROOT = path.resolve(__dirname, '..'); const SRC = path.join(ROOT, 'src'); const API = path.join(ROOT, '..', 'src', 'huamenchuang', 'api'); const BUILTIN = new Set(['if','for','while','switch','catch','return','function','typeof','new','delete','void', 'fetch','setTimeout','setInterval','clearTimeout','clearInterval','parseInt','parseFloat','isNaN','isFinite', 'Number','String','Boolean','Array','Object','JSON','Math','Date','Promise','console','window','document', 'localStorage','sessionStorage','navigator','location','alert','requestAnimationFrame','cancelAnimationFrame', 'URL','Blob','File','FileReader','Error','TypeError','structuredClone','crypto','atob','btoa','history', 'defineProps','defineEmits','defineExpose','withDefaults','require','module','Infinity','NaN','encodeURIComponent','decodeURIComponent']); const VUE = new Set(['ref','reactive','computed','watch','watchEffect','onMounted','onBeforeUnmount','onUnmounted','nextTick', 'createApp','useRouter','useRoute','toRefs','toRef','unref','isRef','provide','inject','defineStore','storeToRefs']); function walk(dir, out = []) { for (const f of fs.readdirSync(dir)) { const p = path.join(dir, f); if (fs.statSync(p).isDirectory()) walk(p, out); else out.push(p); } return out; } // ---- ① SFC 未定义引用 ---- console.log('=== ① SFC 脚本未定义引用扫描 ==='); const vueFiles = walk(SRC).filter(f => f.endsWith('.vue')); let issues = 0; for (const f of vueFiles) { const src = fs.readFileSync(f, 'utf8'); const m = src.match(/