禁止壳生产代码保留临时替身
移动壳配置检查扫描生产源码脚手架词 桌面壳配置检查扫描生产源码脚手架词 保留测试文件使用 mock 的边界 更新原生壳方案和团队决策记录
This commit is contained in:
@@ -21,6 +21,26 @@ const sharedContractPath = new URL(
|
||||
const sharedContractSource = fs.readFileSync(sharedContractPath, 'utf8');
|
||||
const mainPath = new URL('../src-tauri/src/main.rs', import.meta.url);
|
||||
const main = fs.readFileSync(mainPath, 'utf8');
|
||||
const productionSourceRoots = [
|
||||
new URL('../package.json', import.meta.url),
|
||||
new URL('../src-tauri/Cargo.toml', import.meta.url),
|
||||
new URL('../src-tauri/build.rs', import.meta.url),
|
||||
new URL('../src-tauri/capabilities/main.json', import.meta.url),
|
||||
new URL('../src-tauri/src/', import.meta.url),
|
||||
new URL('../src-tauri/tauri.conf.json', import.meta.url),
|
||||
];
|
||||
const productionFileExtensions = new Set(['.json', '.mjs', '.rs', '.toml']);
|
||||
const devScaffoldTerms = [
|
||||
'mo' + 'ck',
|
||||
'fa' + 'ke',
|
||||
'place' + 'holder',
|
||||
'st' + 'ub',
|
||||
'TO' + 'DO',
|
||||
'FIX' + 'ME',
|
||||
'占' + '位',
|
||||
'模' + '拟',
|
||||
'伪' + '造',
|
||||
];
|
||||
|
||||
function extractCargoPackageString(source, key) {
|
||||
const match = source.match(new RegExp(`^${key}\\s*=\\s*"([^"]+)"`, 'm'));
|
||||
@@ -31,6 +51,58 @@ function extractCargoPackageString(source, key) {
|
||||
return match[1];
|
||||
}
|
||||
|
||||
function collectProductionSourceFiles(entry) {
|
||||
const stats = fs.statSync(entry);
|
||||
if (stats.isDirectory()) {
|
||||
const directory = entry.href.endsWith('/') ? entry : new URL(`${entry.href}/`);
|
||||
return fs
|
||||
.readdirSync(entry, { withFileTypes: true })
|
||||
.flatMap((child) =>
|
||||
collectProductionSourceFiles(
|
||||
new URL(`${child.name}${child.isDirectory() ? '/' : ''}`, directory),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
const path = entry.pathname;
|
||||
const extension = path.match(/\.[^.]+$/)?.[0] ?? '';
|
||||
if (!productionFileExtensions.has(extension)) {
|
||||
return [];
|
||||
}
|
||||
if (path.includes('.test.') || path.endsWith('/scripts/check-config.mjs')) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return [entry];
|
||||
}
|
||||
|
||||
function assertNoDevScaffoldTerms(files) {
|
||||
for (const file of files) {
|
||||
const source = fs.readFileSync(file, 'utf8');
|
||||
const lineStarts = [0];
|
||||
for (let index = 0; index < source.length; index += 1) {
|
||||
if (source[index] === '\n') {
|
||||
lineStarts.push(index + 1);
|
||||
}
|
||||
}
|
||||
|
||||
for (const term of devScaffoldTerms) {
|
||||
const matchIndex = source.toLowerCase().indexOf(term.toLowerCase());
|
||||
if (matchIndex === -1) {
|
||||
continue;
|
||||
}
|
||||
const line = lineStarts.filter((start) => start <= matchIndex).length;
|
||||
throw new Error(
|
||||
`desktop shell production source must not include ${term}: ${file.pathname}:${line}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assertNoDevScaffoldTerms(
|
||||
productionSourceRoots.flatMap((root) => collectProductionSourceFiles(root)),
|
||||
);
|
||||
|
||||
function extractStringArrayExport(source, exportName) {
|
||||
const match = source.match(
|
||||
new RegExp(`export const ${exportName}[^=]*= \\[([\\s\\S]*?)\\](?: as const)?;`),
|
||||
|
||||
Reference in New Issue
Block a user