| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960 |
- #!/usr/bin/env node
- /**
- * smoke.mjs —— 技能自检。
- * 生成一个临时项目并校验:文件齐全、JS 语法通过、无装饰器。
- * 用法:node scripts/smoke.mjs
- */
- import { mkdtempSync, rmSync, readdirSync, statSync, readFileSync } from 'node:fs';
- import { join, dirname } from 'node:path';
- import { tmpdir } from 'node:os';
- import { execFileSync } from 'node:child_process';
- import { fileURLToPath } from 'node:url';
- const __dirname = dirname(fileURLToPath(import.meta.url));
- const scaffold = join(__dirname, 'scaffold.mjs');
- const newGen = join(__dirname, 'new.mjs');
- let fail = 0;
- const check = (name, cond) => { console.log(`${cond ? '✓' : '✗'} ${name}`); if (!cond) fail++; };
- function walk(d, out = []) {
- for (const e of readdirSync(d, { withFileTypes: true })) {
- const p = join(d, e.name);
- if (e.isDirectory()) walk(p, out); else out.push(p);
- }
- return out;
- }
- const dir = mkdtempSync(join(tmpdir(), 'fmode-code-lit-smoke-'));
- try {
- execFileSync(process.execPath, [scaffold, dir, '--project', 'smoke-app'], { stdio: 'pipe' });
- const files = walk(dir);
- check('scaffold 生成 index.html', files.some((f) => f.endsWith('src/index.html')));
- check('scaffold 生成 importmap.json', files.some((f) => f.endsWith('src/importmap.json')));
- check('scaffold 生成 app.js', files.some((f) => f.endsWith('src/app.js')));
- check('scaffold 生成分层目录', ['components', 'services', 'utils'].every((d2) => files.some((f) => f.includes(`/src/${d2}/`))));
- execFileSync(process.execPath, [newGen, 'component', 'smoke-card', '--dir', join(dir, 'src/components')], { stdio: 'pipe' });
- execFileSync(process.execPath, [newGen, 'service', 'smoke-service', '--dir', join(dir, 'src/services')], { stdio: 'pipe' });
- check('new component 生成', files.some((f) => f.endsWith('smoke-card.js')) || walk(dir).some((f) => f.endsWith('smoke-card.js')));
- check('new service 无重复后缀', walk(dir).some((f) => f.endsWith('smoke-service.js')) && !walk(dir).some((f) => f.endsWith('smoke-service-service.js')));
- // 全量语法校验 + 装饰器扫描
- let syntaxOk = true, decoratorFound = false;
- for (const f of walk(dir).filter((f) => f.endsWith('.js'))) {
- try { execFileSync(process.execPath, ['--check', f], { stdio: 'pipe' }); } catch { syntaxOk = false; console.log(' 语法失败:', f); }
- if (/^\s*@(customElement|property|state|consume|provide|query)\b/m.test(readFileSync(f, 'utf8'))) decoratorFound = true;
- }
- check('生成物全部通过语法检查', syntaxOk);
- check('生成物无装饰器语法', !decoratorFound);
- // importmap JSON 合法
- let mapOk = false;
- try { JSON.parse(readFileSync(join(dir, 'src/importmap.json'), 'utf8')); mapOk = true; } catch {}
- check('importmap.json 为合法 JSON', mapOk);
- } finally {
- rmSync(dir, { recursive: true, force: true });
- }
- console.log(fail === 0 ? '\nSMOKE OK' : `\nSMOKE FAILED(${fail})`);
- process.exit(fail === 0 ? 0 : 1);
|