PHpullh
학습 라이브러리/AI Prompts/데이터 검증 유틸리티 스크립트

AI PROMPTS · 인프라 & 자동화

데이터 검증 유틸리티 스크립트

개발 중 데이터 파일의 스키마, 중복, 코드 예제 길이 등을 검증합니다.

인프라 & 자동화

핵심 설명

개발 중 데이터 파일의 스키마, 중복, 코드 예제 길이 등을 검증합니다.

scripts/validate.js

// scripts/validate.js
// 사용법: node scripts/validate.js [파일명]
// 예시: node scripts/validate.js kotlin

const fs  = require('fs');
const vm  = require('vm');
const path = require('path');

const targets = process.argv[2]
  ? [process.argv[2]]
  : ['kotlin', 'python', 'go', 'java'];

let totalErrors = 0;
let totalItems  = 0;

for (const lang of targets) {
  const filePath = path.join('data', `${lang}.js`);
  if (!fs.existsSync(filePath)) {
    console.log(`⏭️  건너뜀: ${filePath}`);
    continue;
  }

  console.log(`\n📂 검증: ${filePath}`);

  // 안전한 실행 컨텍스트
  const ctx = { window: { DATA: {} } };
  vm.createContext(ctx);

  try {
    vm.runInContext(fs.readFileSync(filePath, 'utf8'), ctx);
  } catch (e) {
    console.error(`  ❌ 실행 오류: ${e.message}`);
    totalErrors++;
    continue;
  }

  const data  = ctx.window.DATA[lang];
  if (!data?.items) {
    console.error(`  ❌ window.DATA.${lang}.items 없음`);
    totalErrors++;
    continue;
  }

  const items    = data.items;
  const seenIds  = new Set();
  let fileErrors = 0;

  for (const [i, item] of items.entries()) {
    const loc = `  [${String(i+1).padStart(3,'0')}] ${item.id || '?'}`;

    // 필수 필드
    const required = ['id','cat','diff','title','desc','code','lang','tip','mistake'];
    for (const field of required) {
      if (!item[field] || String(item[field]).trim() === '') {
        console.warn(`${loc} ⚠️  '${field}' 빈 값`);
        fileErrors++;
      }
    }

    // 중복 ID
    if (seenIds.has(item.id)) {
      console.error(`${loc} ❌ 중복 ID`);
      fileErrors++;
    }
    seenIds.add(item.id);

    // ID 형식 검증
    const prefixMap = {kotlin:'k',python:'p',go:'g',java:'j'};
    const expectedPrefix = prefixMap[lang];
    if (!item.id?.startsWith(expectedPrefix + '-')) {
      console.warn(`${loc} ⚠️  ID 형식 불일치 (예상: ${expectedPrefix}-NNN)`);
      fileErrors++;
    }

    // 코드 길이
    const codeLen = (item.code || '').replace(/<[^>]+>/g,'').length;
    if (codeLen < 50) {
      console.warn(`${loc} ⚠️  코드가 너무 짧음 (${codeLen}자)`);
    }
    if (codeLen > 3000) {
      console.warn(`${loc} ⚠️  코드가 너무 김 (${codeLen}자)`);
    }
  }

  totalItems  += items.length;
  totalErrors += fileErrors;

  const status = fileErrors === 0 ? '✅' : `❌ (${fileErrors}개 오류)`;
  console.log(`  ${status} ${items.length}개 항목 검증 완료`);
}

console.log(`\n==================================================`);
console.log(`총 ${totalItems}개 항목, ${totalErrors}개 오류`);
process.exit(totalErrors > 0 ? 1 : 0);