build(GOV-009): 建立 Node 与工作区基线
This commit is contained in:
@@ -0,0 +1,3 @@
|
|||||||
|
engine-strict=true
|
||||||
|
save-exact=true
|
||||||
|
strict-peer-dependencies=true
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"singleQuote": true,
|
||||||
|
"trailingComma": "all",
|
||||||
|
"printWidth": 100,
|
||||||
|
"semi": true
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
export default [
|
||||||
|
{
|
||||||
|
ignores: ['**/dist/**', '**/coverage/**', '**/node_modules/**', '**/.local/**'],
|
||||||
|
},
|
||||||
|
];
|
||||||
+17
-1
@@ -3,7 +3,14 @@
|
|||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
"packageManager": "pnpm@10.25.0",
|
||||||
|
"engines": {
|
||||||
|
"node": "22.x",
|
||||||
|
"pnpm": "10.x"
|
||||||
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"check:runtime": "node tools/runtime/verify-runtime.mjs",
|
||||||
|
"test:runtime": "node --test tools/runtime/verify-runtime.test.mjs",
|
||||||
"test:governance": "node --test tools/governance/feature-record.test.mjs",
|
"test:governance": "node --test tools/governance/feature-record.test.mjs",
|
||||||
"test:mysql-baseline": "node --test tools/governance/mysql-baseline.test.mjs",
|
"test:mysql-baseline": "node --test tools/governance/mysql-baseline.test.mjs",
|
||||||
"test:environment-baseline": "node --test tools/governance/environment-baseline.test.mjs",
|
"test:environment-baseline": "node --test tools/governance/environment-baseline.test.mjs",
|
||||||
@@ -11,6 +18,15 @@
|
|||||||
"schema:baseline": "node tools/database/schema-baseline.mjs generate",
|
"schema:baseline": "node tools/database/schema-baseline.mjs generate",
|
||||||
"schema:verify": "node tools/database/schema-baseline.mjs verify",
|
"schema:verify": "node tools/database/schema-baseline.mjs verify",
|
||||||
"governance:start": "node tools/governance/start.mjs",
|
"governance:start": "node tools/governance/start.mjs",
|
||||||
"governance:finish": "node tools/governance/finish.mjs"
|
"governance:finish": "node tools/governance/finish.mjs",
|
||||||
|
"lint": "pnpm --filter @a-share-analysis/web --if-present lint && pnpm --filter @a-share-analysis/server --if-present lint",
|
||||||
|
"format:check": "pnpm exec prettier --check .",
|
||||||
|
"typecheck": "pnpm --filter @a-share-analysis/web --if-present typecheck && pnpm --filter @a-share-analysis/server --if-present typecheck",
|
||||||
|
"test": "pnpm test:runtime && pnpm test:governance && pnpm test:mysql-baseline && pnpm test:environment-baseline && pnpm test:schema-baseline && pnpm --filter @a-share-analysis/web --if-present test && pnpm --filter @a-share-analysis/server --if-present test",
|
||||||
|
"build": "pnpm --filter @a-share-analysis/web --if-present build && pnpm --filter @a-share-analysis/server --if-present build",
|
||||||
|
"verify": "pnpm check:runtime && pnpm lint && pnpm format:check && pnpm typecheck && pnpm test && pnpm build"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"prettier": "3.9.6"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+24
@@ -0,0 +1,24 @@
|
|||||||
|
lockfileVersion: '9.0'
|
||||||
|
|
||||||
|
settings:
|
||||||
|
autoInstallPeers: true
|
||||||
|
excludeLinksFromLockfile: false
|
||||||
|
|
||||||
|
importers:
|
||||||
|
|
||||||
|
.:
|
||||||
|
devDependencies:
|
||||||
|
prettier:
|
||||||
|
specifier: 3.9.6
|
||||||
|
version: 3.9.6
|
||||||
|
|
||||||
|
packages:
|
||||||
|
|
||||||
|
prettier@3.9.6:
|
||||||
|
resolution: {integrity: sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g==}
|
||||||
|
engines: {node: '>=14'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
snapshots:
|
||||||
|
|
||||||
|
prettier@3.9.6: {}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
packages:
|
||||||
|
- web
|
||||||
|
- server
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
import { execFileSync } from 'node:child_process';
|
||||||
|
import path from 'node:path';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
|
|
||||||
|
const VERSION_PATTERN = /^(?:v)?(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/;
|
||||||
|
|
||||||
|
function parseVersion(value, label) {
|
||||||
|
const normalized = String(value ?? '').trim();
|
||||||
|
const match = normalized.match(VERSION_PATTERN);
|
||||||
|
if (!match) {
|
||||||
|
throw new Error(`${label} 版本格式无效:${normalized || '(空)'}`);
|
||||||
|
}
|
||||||
|
return Object.freeze({ raw: normalized.replace(/^v/, ''), major: Number(match[1]) });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 项目只验证开发机已经提供的运行时,不安装或切换 Node。严格固定主版本可以让
|
||||||
|
* 本地源码运行、CI 和生产镜像使用同一语义,避免跨主版本的 ESM 与工具链差异。
|
||||||
|
*/
|
||||||
|
export function assertSupportedRuntime({ nodeVersion, pnpmVersion }) {
|
||||||
|
const node = parseVersion(nodeVersion, 'Node.js');
|
||||||
|
const pnpm = parseVersion(pnpmVersion, 'pnpm');
|
||||||
|
if (node.major !== 22) {
|
||||||
|
throw new Error(`Node.js 必须为 22.x,实际 ${node.raw}`);
|
||||||
|
}
|
||||||
|
if (pnpm.major !== 10) {
|
||||||
|
throw new Error(`pnpm 必须为 10.x,实际 ${pnpm.raw}`);
|
||||||
|
}
|
||||||
|
return Object.freeze({ nodeVersion: node.raw, pnpmVersion: pnpm.raw });
|
||||||
|
}
|
||||||
|
|
||||||
|
function runCommandLine() {
|
||||||
|
const pnpmVersion = execFileSync('pnpm', ['--version'], {
|
||||||
|
encoding: 'utf8',
|
||||||
|
stdio: ['ignore', 'pipe', 'pipe'],
|
||||||
|
}).trim();
|
||||||
|
const result = assertSupportedRuntime({ nodeVersion: process.version, pnpmVersion });
|
||||||
|
process.stdout.write(
|
||||||
|
`运行时验证通过:Node.js ${result.nodeVersion},pnpm ${result.pnpmVersion}\n`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
||||||
|
runCommandLine();
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import assert from 'node:assert/strict';
|
||||||
|
import test from 'node:test';
|
||||||
|
|
||||||
|
import { assertSupportedRuntime } from './verify-runtime.mjs';
|
||||||
|
|
||||||
|
test('只接受 Node 22 与 pnpm 10', () => {
|
||||||
|
assert.doesNotThrow(() =>
|
||||||
|
assertSupportedRuntime({ nodeVersion: '22.11.0', pnpmVersion: '10.25.0' }),
|
||||||
|
);
|
||||||
|
|
||||||
|
for (const nodeVersion of ['20.20.2', '24.0.0']) {
|
||||||
|
assert.throws(
|
||||||
|
() => assertSupportedRuntime({ nodeVersion, pnpmVersion: '10.25.0' }),
|
||||||
|
new RegExp(`Node\\.js 必须为 22\\.x,实际 ${nodeVersion.replaceAll('.', '\\.')}`),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const pnpmVersion of ['9.15.0', '11.0.0']) {
|
||||||
|
assert.throws(
|
||||||
|
() => assertSupportedRuntime({ nodeVersion: '22.11.0', pnpmVersion }),
|
||||||
|
new RegExp(`pnpm 必须为 10\\.x,实际 ${pnpmVersion.replaceAll('.', '\\.')}`),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('拒绝无法解析的运行时版本', () => {
|
||||||
|
for (const runtime of [
|
||||||
|
{ nodeVersion: '', pnpmVersion: '10.25.0' },
|
||||||
|
{ nodeVersion: 'v22', pnpmVersion: '10.25.0' },
|
||||||
|
{ nodeVersion: '22.11.0', pnpmVersion: '' },
|
||||||
|
{ nodeVersion: '22.11.0', pnpmVersion: 'ten' },
|
||||||
|
]) {
|
||||||
|
assert.throws(() => assertSupportedRuntime(runtime), /版本格式无效/);
|
||||||
|
}
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user