82 lines
4.2 KiB
JavaScript
82 lines
4.2 KiB
JavaScript
'use strict';
|
||
const fs = require('node:fs');
|
||
const path = require('node:path');
|
||
const root = path.resolve(__dirname, '../..');
|
||
const manifest = JSON.parse(fs.readFileSync(path.join(__dirname, 'original-manifest.json'), 'utf8').replace(/^\uFEFF/, ''));
|
||
const destinations = new Map(manifest.map(entry => [path.posix.basename(entry.Source), entry.Destination]));
|
||
destinations.set('README.md', 'docs/104/README.md');
|
||
|
||
function fixLinks(text, document) {
|
||
return text.replace(/\]\(([^)]+)\)/g, (match, href) => {
|
||
if (/^(?:[a-z]+:|#)/i.test(href)) return match;
|
||
const hash = href.indexOf('#');
|
||
const target = hash < 0 ? href : href.slice(0, hash);
|
||
const anchor = hash < 0 ? '' : href.slice(hash);
|
||
const destination = target === 'examples/README.md'
|
||
? 'docs/examples/IEC104子站示例.md'
|
||
: destinations.get(path.posix.basename(target));
|
||
if (!destination) throw new Error(`Unknown link in ${document}: ${href}`);
|
||
return `](${path.posix.relative(path.posix.dirname(document), destination)}${anchor})`;
|
||
});
|
||
}
|
||
|
||
function fixBuildBlock(block) {
|
||
block = block.replace(/(?<![\w/\\])(?:IEC104|IEC60870|iec104|iec60870)[\w]*\.c\b/g, name => {
|
||
const destination = destinations.get(name);
|
||
if (!destination) throw new Error(`Unknown build input: ${name}`);
|
||
return destination;
|
||
});
|
||
return block.replace(/^gcc .+$/gm, line => {
|
||
if (line.includes('-I.')) return line.replace('-I.', '-I104 -Icommon');
|
||
const includes = /@(?:asdu|extended)Sources/.test(line) ? '-Icommon' : '-I104 -Icommon';
|
||
return line.replace('-O2 ', `-O2 ${includes} `);
|
||
});
|
||
}
|
||
|
||
let changed = 0;
|
||
for (const entry of manifest.filter(entry => entry.Destination.endsWith('.md'))) {
|
||
const file = path.join(root, entry.Destination);
|
||
const before = fs.readFileSync(file, 'utf8');
|
||
let after = fixLinks(before, entry.Destination)
|
||
.replaceAll('./examples/build.ps1', './scripts/build.ps1')
|
||
.replaceAll('`examples/slave_example_loopback_test.cjs`', '`test/slave_example_loopback_test.cjs`');
|
||
if (entry.Destination === 'docs/examples/IEC104子站示例.md') {
|
||
after = after.replace(
|
||
'示例通过 `../IEC104_Interrogation.h` 引入上级目录的库声明,方便编辑器单独解析。',
|
||
'示例通过 `IEC104_Interrogation.h` 引入库声明;构建脚本同时添加 `104/` 和 `common/` 头文件搜索路径,编辑器也应配置这两个目录。'
|
||
);
|
||
}
|
||
if (entry.Destination === 'docs/test/IEC104测试文档.md') {
|
||
after = after.replace(/```powershell\r?\n[\s\S]*?```/g, fixBuildBlock);
|
||
after = after.replace(
|
||
'> **同步日期**:2026-10-23。本文仅列出当前保留的测试入口及可运行命令。',
|
||
'> **目录与命令同步日期**:2026-10-26。测试代码位于根目录的 `test/`,本文仅列出当前保留的测试入口及可运行命令。'
|
||
);
|
||
after = after.replace(
|
||
'`iec104_slave_example_test.c`验证单文件总召示例,包含9组业务流程测试:',
|
||
'`iec104_slave_example_test.c`验证总召模块及单文件示例,包含59组业务流程测试:'
|
||
);
|
||
after = after.replace('`Slave example: 9 groups passed ...`', '`Slave example: 59 groups passed ...`')
|
||
.replace('可控后端使用251字节HIGH和每轮1次业务提交,', '可控后端使用251字节HIGH和2槽业务事件FIFO,');
|
||
}
|
||
if (entry.Destination === 'docs/104/IEC104_TcpServer_设计架构.md') {
|
||
after = after.replace(/```(?:powershell|text)\r?\n[\s\S]*?```/g, fixBuildBlock);
|
||
after = after.replace(
|
||
'以上为当前Windows后端的源码清单,不要用根目录全部`.c`通配构建。',
|
||
'以上路径均相对于项目根目录;工程需将 `104/` 和 `common/` 加入头文件搜索路径,并按所用模块选择源文件。'
|
||
);
|
||
after = after.replace(
|
||
'```powershell\ngcc -std=c11',
|
||
'```powershell\nNew-Item -ItemType Directory -Path .build -Force | Out-Null\ngcc -std=c11'
|
||
).replace(
|
||
'```powershell\r\ngcc -std=c11',
|
||
'```powershell\r\nNew-Item -ItemType Directory -Path .build -Force | Out-Null\r\ngcc -std=c11'
|
||
);
|
||
}
|
||
if (after !== before) {
|
||
fs.writeFileSync(file, after, 'utf8');
|
||
changed++;
|
||
}
|
||
}
|
||
console.log(`Updated links and build paths in ${changed} documents.`);
|