Files
reverse-skills-max/vendor-new/xbsReverseSkill/web-js-env-patcher/scripts/compare_fixture.js

92 lines
3.8 KiB
JavaScript
Executable File

#!/usr/bin/env node
'use strict';
const fs = require('fs');
function parseArgs(argv) {
const args = { fixture: '', actual: '', field: '', expectedPath: '', actualPath: '', json: false, markdown: false };
for (let i = 2; i < argv.length; i++) {
const a = argv[i];
if (a === '--fixture') args.fixture = argv[++i] || '';
else if (a === '--actual') args.actual = argv[++i] || '';
else if (a === '--field') args.field = argv[++i] || '';
else if (a === '--expected-path') args.expectedPath = argv[++i] || '';
else if (a === '--actual-path') args.actualPath = argv[++i] || '';
else if (a === '--json') args.json = true;
else if (a === '--markdown') args.markdown = true;
else if (a === '--help' || a === '-h') args.help = true;
else throw new Error(`未知参数:${a}`);
}
if (!args.json && !args.markdown) args.markdown = true;
return args;
}
function usage() {
return `用法:
node scripts/compare_fixture.js --fixture sample.fixture.json --actual node-output.json --field sign --markdown
node scripts/compare_fixture.js --fixture sample.fixture.json --actual node-output.json --expected-path expected.sign --actual-path output.sign --json`;
}
function readJson(p, label) {
if (!p) throw new Error(`必须提供 ${label}`);
return JSON.parse(fs.readFileSync(p, 'utf8').replace(/^\uFEFF/, ''));
}
function getPath(obj, p) {
if (!p) return undefined;
let cur = obj;
for (const part of p.split('.').filter(Boolean)) {
if (cur == null) return undefined;
cur = cur[part];
}
return cur;
}
function firstDefined(values) {
for (const v of values) if (v !== undefined) return v;
return undefined;
}
function normalize(v) {
if (v === undefined) return undefined;
if (typeof v === 'string') return v;
return JSON.stringify(v);
}
function compare(args) {
const fixture = readJson(args.fixture, '--fixture');
const actual = readJson(args.actual, '--actual');
const field = args.field || fixture.param || '';
const expectedPath = args.expectedPath || (field ? `expected.${field}` : 'expected');
const actualPath = args.actualPath || '';
const expected = firstDefined([getPath(fixture, expectedPath), field ? getPath(fixture, `expected.${field}`) : undefined, fixture.expectedValue]);
const actualValue = actualPath ? getPath(actual, actualPath) : firstDefined([
field ? getPath(actual, `output.${field}`) : undefined,
field ? getPath(actual, field) : undefined,
getPath(actual, 'output'),
getPath(actual, 'result'),
]);
const expectedText = normalize(expected);
const actualText = normalize(actualValue);
const pass = expected !== undefined && actualValue !== undefined && expectedText === actualText;
return { pass, field, expectedPath, actualPath: actualPath || '(自动识别)', expected, actual: actualValue, expectedText, actualText, fixture: args.fixture, actualFile: args.actual };
}
function renderMarkdown(result) {
const lines = ['# fixtures 对比结果', '', `- 结果:${result.pass ? '通过' : '失败'}`, `- 字段:${result.field || '未指定'}`, `- 期望路径:${result.expectedPath}`, `- 实际路径:${result.actualPath}`, `- 浏览器期望值:${result.expectedText === undefined ? '未找到' : result.expectedText}`, `- Node.js 实际值:${result.actualText === undefined ? '未找到' : result.actualText}`];
return lines.join('\n') + '\n';
}
try {
const args = parseArgs(process.argv);
if (args.help) { console.log(usage()); process.exit(0); }
const result = compare(args);
if (args.json) console.log(JSON.stringify(result, null, 2));
if (args.markdown) process.stdout.write(renderMarkdown(result));
if (!result.pass) process.exit(2);
} catch (err) {
console.error(err.message || String(err));
console.error(usage());
process.exit(1);
}