Files
maka/scripts/check-stale-dist.mjs
agent-radar 7be535059e
Dependency audit / audit (push) Canceled after 0s
CI / plan (push) Canceled after 0s
Gitoxide helper admission / macos-latest (push) Canceled after 0s
Gitoxide helper admission / ubuntu-latest (push) Canceled after 0s
Gitoxide helper admission / windows-latest (push) Canceled after 0s
Runtime Host peer admission / quality (push) Canceled after 0s
Windows recovery / windows_recovery (push) Canceled after 0s
CI / heavy (push) Canceled after 0s
CI / test (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 19:05:14 +08:00

124 lines
4.1 KiB
JavaScript

#!/usr/bin/env node
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/**
* PR-BUILD-HYGIENE-0: detect a stale `dist/` (source newer than its
* compiled output) and exit non-zero so CI / pre-test hooks can
* force a rebuild.
*
* Rule per workspace pkg `<W>`:
* - If `<W>/dist` is missing, treat as stale.
* - If any `*.ts(x)` file under `<W>/src` has mtime newer than the
* newest file under `<W>/dist`, treat as stale.
*
* `apps/desktop` has two outputs (`dist` for main + preload,
* `dist-renderer` for the renderer bundle). Source paths split by
* `src/main` / `src/preload` vs `src/renderer`, so this script
* walks them independently to avoid false positives where a
* renderer edit invalidates the main dist or vice versa.
*
* Pure file mtime comparison — no TypeScript program is started,
* keeps the gate cheap enough to run before every `npm test`.
*/
import { readdirSync, statSync, existsSync } from 'node:fs';
import { dirname, join, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
const here = dirname(fileURLToPath(import.meta.url));
const repoRoot = resolve(here, '..');
const pairs = [
{ pkg: '@maka/core', src: 'packages/core/src', dist: 'packages/core/dist' },
{ pkg: '@maka/storage', src: 'packages/storage/src', dist: 'packages/storage/dist' },
{ pkg: '@maka/runtime', src: 'packages/runtime/src', dist: 'packages/runtime/dist' },
{
pkg: '@maka/runtime-host',
src: 'packages/runtime-host/src',
dist: 'packages/runtime-host/dist',
},
{ pkg: '@maka/ui', src: 'packages/ui/src', dist: 'packages/ui/dist' },
{ pkg: '@maka/desktop:main', src: 'apps/desktop/src/main', dist: 'apps/desktop/dist/main' },
{
pkg: '@maka/desktop:preload',
src: 'apps/desktop/src/preload',
dist: 'apps/desktop/dist/preload',
},
{
pkg: '@maka/desktop:renderer',
src: 'apps/desktop/src/renderer',
dist: 'apps/desktop/dist-renderer',
},
];
function walkMaxMtime(dir, predicate) {
if (!existsSync(dir)) return 0;
let max = 0;
const stack = [dir];
while (stack.length > 0) {
const cur = stack.pop();
for (const entry of readdirSync(cur, { withFileTypes: true })) {
const full = join(cur, entry.name);
if (entry.isDirectory()) {
if (entry.name === '__tests__' || entry.name === 'node_modules') continue;
stack.push(full);
continue;
}
if (!predicate(entry.name)) continue;
const m = statSync(full).mtimeMs;
if (m > max) max = m;
}
}
return max;
}
const stale = [];
for (const pair of pairs) {
const srcDir = join(repoRoot, pair.src);
const distDir = join(repoRoot, pair.dist);
if (!existsSync(srcDir)) continue; // workspace not present
if (!existsSync(distDir)) {
stale.push({ pkg: pair.pkg, reason: 'dist missing' });
continue;
}
const srcMax = walkMaxMtime(srcDir, (n) => n.endsWith('.ts') || n.endsWith('.tsx'));
const distMax = walkMaxMtime(
distDir,
(n) => n.endsWith('.js') || n.endsWith('.mjs') || n.endsWith('.cjs') || n === 'index.html',
);
if (srcMax > distMax) {
stale.push({
pkg: pair.pkg,
reason: `src newer than dist (Δ=${Math.round((srcMax - distMax) / 1000)}s)`,
});
}
}
if (stale.length === 0) {
console.log('dist is fresh.');
process.exit(0);
}
console.error('STALE DIST DETECTED:');
for (const s of stale) console.error(` - ${s.pkg}: ${s.reason}`);
console.error('\nRun `npm run rebuild` and retry.');
process.exit(2);