收紧宿主壳结构门禁

根级原生壳门禁按完整路径反查三端桥接层文档

移动端和桌面端壳目录拒绝未登记子目录或生产入口

桌面端单端配置检查改为精确 Rust 模块清单

更新宿主壳架构文档和共享记忆中的验收口径
This commit is contained in:
2026-06-19 07:54:52 +08:00
parent de2798d415
commit e27834930f
6 changed files with 75 additions and 58 deletions
+63 -50
View File
@@ -188,15 +188,15 @@ const expectedDesktopShellRustFiles = [
const documentedShellLayerGroups = [
{
label: 'wechat host bridge files',
files: expectedWechatHostBridgeFiles.filter(
(fileName) => !fileName.includes('.test.'),
),
files: expectedWechatHostBridgeFiles
.filter((fileName) => !fileName.includes('.test.'))
.map((fileName) => `miniprogram/host-bridge/${fileName}`),
},
{
label: 'wechat shell files',
files: expectedWechatShellFiles.filter(
(fileName) => !fileName.includes('.test.'),
),
files: expectedWechatShellFiles
.filter((fileName) => !fileName.includes('.test.'))
.map((fileName) => `miniprogram/shell/${fileName}`),
},
{
label: 'wechat page wrapper files',
@@ -204,32 +204,39 @@ const documentedShellLayerGroups = [
([route, files]) =>
files
.filter((fileName) => !fileName.includes('.test.'))
.map((fileName) => `${route}/${fileName}`),
.map((fileName) => `miniprogram/pages/${route}/${fileName}`),
),
},
{
label: 'mobile host bridge files',
files: expectedMobileHostBridgeFiles.filter(
(fileName) => !fileName.includes('.test.'),
),
files: expectedMobileHostBridgeFiles
.filter((fileName) => !fileName.includes('.test.'))
.map((fileName) => `apps/mobile-shell/src/host-bridge/${fileName}`),
},
{
label: 'mobile shell files',
files: expectedMobileShellFiles.filter(
(fileName) => !fileName.includes('.test.'),
),
files: expectedMobileShellFiles
.filter((fileName) => !fileName.includes('.test.'))
.map((fileName) => `apps/mobile-shell/src/shell/${fileName}`),
},
{
label: 'desktop entrypoint files',
files: ['app.rs', 'main.rs'],
files: [
'apps/desktop-shell/src-tauri/src/app.rs',
'apps/desktop-shell/src-tauri/src/main.rs',
],
},
{
label: 'desktop host bridge files',
files: expectedDesktopHostBridgeRustFiles,
files: expectedDesktopHostBridgeRustFiles.map(
(fileName) => `apps/desktop-shell/src-tauri/src/host_bridge/${fileName}`,
),
},
{
label: 'desktop shell files',
files: expectedDesktopShellRustFiles,
files: expectedDesktopShellRustFiles.map(
(fileName) => `apps/desktop-shell/src-tauri/src/shell/${fileName}`,
),
},
];
const capabilityListMarkers = {
@@ -601,6 +608,25 @@ function assertSameList(actual, expected, label) {
}
}
function readDirectoryEntryList(directory, label) {
const entries = fs
.readdirSync(directory, { withFileTypes: true })
.map((entry) => {
if (entry.isFile()) {
return `file:${entry.name}`;
}
if (entry.isDirectory()) {
return `dir:${entry.name}`;
}
throw new Error(`${label} must not contain special entries: ${entry.name}`);
})
.sort();
if (entries.length === 0) {
throw new Error(`${label} must not be empty`);
}
return entries;
}
function readDirectoryFileList(directory, label) {
const files = [];
for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
@@ -1155,26 +1181,19 @@ function assertHostBridgeLayerLayout() {
}
}
const mobileHostBridgeFiles = fs
.readdirSync('apps/mobile-shell/src/host-bridge', { withFileTypes: true })
.filter((entry) => entry.isFile())
.map((entry) => entry.name)
.sort();
assertSameList(
mobileHostBridgeFiles,
readDirectoryFileList(
'apps/mobile-shell/src/host-bridge',
'mobile host bridge files',
),
expectedMobileHostBridgeFiles,
'mobile host bridge files',
);
const mobileShellLayerFiles = fs
.readdirSync('apps/mobile-shell/src/shell', { withFileTypes: true })
.filter((entry) => entry.isFile())
.map((entry) => entry.name)
.sort();
assertSameList(
mobileShellLayerFiles,
readDirectoryFileList('apps/mobile-shell/src/shell', 'mobile shell files'),
expectedMobileShellFiles,
'mobile shell bridge files',
'mobile shell files',
);
const mobileAppSource = fs.readFileSync('apps/mobile-shell/App.tsx', 'utf8');
@@ -1185,15 +1204,13 @@ function assertHostBridgeLayerLayout() {
throw new Error('mobile shell App.tsx must not import HostBridge directly');
}
const desktopEntrypointRustFiles = fs
.readdirSync('apps/desktop-shell/src-tauri/src', { withFileTypes: true })
.filter((entry) => entry.isFile() && entry.name.endsWith('.rs'))
.map((entry) => entry.name)
.sort();
assertSameList(
desktopEntrypointRustFiles,
['app.rs', 'main.rs'],
'desktop shell entrypoint Rust files',
readDirectoryEntryList(
'apps/desktop-shell/src-tauri/src',
'desktop shell Rust root entries',
),
['dir:host_bridge', 'dir:shell', 'file:app.rs', 'file:main.rs'],
'desktop shell Rust root entries',
);
const desktopMainSource = fs.readFileSync(
@@ -1220,26 +1237,22 @@ function assertHostBridgeLayerLayout() {
throw new Error('desktop shell app.rs must own Tauri app setup');
}
const desktopHostBridgeRustFiles = fs
.readdirSync('apps/desktop-shell/src-tauri/src/host_bridge', { withFileTypes: true })
.filter((entry) => entry.isFile() && entry.name.endsWith('.rs'))
.map((entry) => entry.name)
.sort();
assertSameList(
desktopHostBridgeRustFiles,
readDirectoryFileList(
'apps/desktop-shell/src-tauri/src/host_bridge',
'desktop host bridge Rust files',
),
expectedDesktopHostBridgeRustFiles,
'desktop host bridge Rust files',
);
const desktopShellRustFiles = fs
.readdirSync('apps/desktop-shell/src-tauri/src/shell', { withFileTypes: true })
.filter((entry) => entry.isFile() && entry.name.endsWith('.rs'))
.map((entry) => entry.name)
.sort();
assertSameList(
desktopShellRustFiles,
readDirectoryFileList(
'apps/desktop-shell/src-tauri/src/shell',
'desktop shell Rust files',
),
expectedDesktopShellRustFiles,
'desktop shell Rust bridge files',
'desktop shell Rust files',
);
}