Files
STM32F4-Base/IEC60870-Slave/.build/command-comments/check-comments.cjs
T
STF cd42b4d61d
CI / L0 静态门禁 (pre-commit) (push) Failing after 2m51s
CI / L0.5 主机侧单测 (MSVC) (push) Successful in 18s
添加遥控业务代码
2026-10-30 20:03:19 -07:00

67 lines
3.2 KiB
JavaScript

const fs = require('node:fs');
const path = require('node:path');
const assert = require('node:assert/strict');
const root = path.resolve(__dirname, '../..');
const files = [
'104/business/IEC104_Command.c',
'104/business/IEC104_Command.h',
'examples/iec104_slave_example.c',
'test/iec104_command_test.c',
];
// Preserve literals and token boundaries while ignoring only comments/whitespace.
function tokens(source) {
const input = source.replace(/\\\r?\n/g, '');
const result = [];
let offset = 0;
while (offset < input.length) {
if (/\s/.test(input[offset])) { offset++; continue; }
if (input.startsWith('//', offset)) {
const end = input.indexOf('\n', offset + 2);
offset = end < 0 ? input.length : end + 1;
continue;
}
if (input.startsWith('/*', offset)) {
const end = input.indexOf('*/', offset + 2);
assert(end >= 0, 'unterminated comment');
offset = end + 2;
continue;
}
const tail = input.slice(offset);
const literal = /^(?:u8|u|U|L)?(?:"(?:\\[\s\S]|[^"\\])*"|'(?:\\[\s\S]|[^'\\])*')/.exec(tail);
const word = literal || /^(?:[A-Za-z_][A-Za-z_0-9]*|(?:[0-9]|\.[0-9])(?:[eEpP][+-]|[A-Za-z_0-9.])*)/.exec(tail);
const token = word || /^(?:>>=|<<=|\.\.\.|->|\+\+|--|<<|>>|<=|>=|==|!=|&&|\|\||\*=|\/=|%=|\+=|-=|&=|\^=|\|=|##|.)/.exec(tail);
assert(token, `cannot tokenize at ${offset}`);
result.push(token[0]);
offset += token[0].length;
}
return result;
}
for (const file of files) {
const originalBytes = fs.readFileSync(path.join(__dirname, `${path.basename(file)}.before`));
const currentBytes = fs.readFileSync(path.join(root, file));
const decoder = new TextDecoder('utf-8', { fatal: true });
const original = decoder.decode(originalBytes);
const current = decoder.decode(currentBytes);
assert.deepEqual(tokens(current), tokens(original), `${file}: code tokens changed`);
assert.equal(currentBytes.subarray(0, 3).equals(Buffer.from([0xef, 0xbb, 0xbf])),
originalBytes.subarray(0, 3).equals(Buffer.from([0xef, 0xbb, 0xbf])), `${file}: BOM changed`);
assert(!current.includes('\r'), `${file}: CR line endings`);
assert(!current.includes('\ufffd'), `${file}: replacement character`);
assert(!/[\t ]+$/m.test(current), `${file}: trailing whitespace`);
assert(current.endsWith('\n'), `${file}: missing terminal newline`);
console.log(`${file}: ${tokens(current).length} unchanged tokens, UTF-8/LF OK`);
}
// The loopback update only adds standalone line comments; compare all other bytes.
const loopbackPath = 'test/slave_example_loopback_test.cjs';
const loopbackBefore = fs.readFileSync(path.join(__dirname, 'slave_example_loopback_test.cjs.before'), 'utf8');
const loopbackAfter = fs.readFileSync(path.join(root, loopbackPath), 'utf8');
const withoutCommentLines = (source) => source.split('\n').filter(line => !/^\s*\/\//.test(line)).join('\n');
assert.equal(withoutCommentLines(loopbackAfter), withoutCommentLines(loopbackBefore));
assert(!loopbackAfter.includes('\r') && !loopbackAfter.includes('\ufffd'));
assert(!/[\t ]+$/m.test(loopbackAfter) && loopbackAfter.endsWith('\n'));
new TextDecoder('utf-8', { fatal: true }).decode(fs.readFileSync(path.join(root, loopbackPath)));
console.log(`${loopbackPath}: only standalone comments changed, UTF-8/LF OK`);