refactor: nest client manifest metadata under dsh

This commit is contained in:
imccyu
2026-08-10 20:39:26 +08:00
parent 854f6623bb
commit 717792b631
52 changed files with 379 additions and 269 deletions
+2 -2
View File
@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write packages/typert/generator/README.md
README.md: 38030c2b7e07c70ab79001086640b6581943dbd9
README.zh.md: 0cf0a365785775a9461e9744d29a0da482e54d14
README.md: ac2610620af14a30143e95921273a8c254b50a17
README.zh.md: a1fa777493578533c93db6cd3354b89c8757d837
+1 -1
View File
@@ -4,7 +4,7 @@ English | [中文](README.zh.md)
TypeScript project analyzer and model-driven Typert generator. It converts the developer-authored source type tree into compiler-independent `FaceModel` and `TypeGraph` data before any artifact is rendered. Static analysis can consume that model without Cordis; emitters never receive TypeScript AST or checker objects.
The analyzer can use independent `ts.Program` instances seeded from `tsconfig.host.json` or `tsconfig.client.json`. Direct project references establish compiler-face membership, while package subpaths establish TypeRT runtime-face contributions: an ordinary single-project `dshClient` package may contribute both Host and Client runtime models, and only a split project explicitly referenced through `tsconfig.host.json` or `tsconfig.client.json` is restricted to that corresponding face. `package.json#exports` establishes every cross-package public boundary, and source imports or re-exports are the only allowed cross-face edges. Types owned by NPM dependencies, including global declarations from `@types` packages, remain `external` references instead of being expanded.
The analyzer can use independent `ts.Program` instances seeded from `tsconfig.host.json` or `tsconfig.client.json`. Direct project references establish compiler-face membership, while package subpaths establish TypeRT runtime-face contributions: an ordinary single-project package declaring `dsh.client` may contribute both Host and Client runtime models, and only a split project explicitly referenced through `tsconfig.host.json` or `tsconfig.client.json` is restricted to that corresponding face. `package.json#exports` establishes every cross-package public boundary, and source imports or re-exports are the only allowed cross-face edges. Types owned by NPM dependencies, including global declarations from `@types` packages, remain `external` references instead of being expanded.
## Analysis Model
+1 -1
View File
@@ -4,7 +4,7 @@
TypeScript 项目分析器和模型驱动的 Typert 生成器。在生成任何产物之前,它会先将开发者编写的源类型树转换为独立于编译器的 `FaceModel` 和 `TypeGraph` 数据。静态分析无需 Cordis 即可消费该模型;各产物生成组件均不会接收 TypeScript 抽象语法树(AST)或类型检查器对象。
分析器可以分别使用由 `tsconfig.host.json` 或 `tsconfig.client.json` 初始化的独立 `ts.Program`。直接项目引用确定编译器 face 的成员归属,而包子路径确定 TypeRT 运行时 face 的贡献:带 `dshClient` 的普通单项目包可以同时贡献 Host 与 Client 运行时模型;只有通过 `tsconfig.host.json` 或 `tsconfig.client.json` 显式引用的拆分项目,才会被限制在相应 face。`package.json#exports` 确定所有跨包公开边界,跨 face 的边只能来自源码导入或重新导出。NPM 依赖拥有的类型(包括 `@types` 包中的全局声明)继续以 `external` 引用表示,不会被展开。
分析器可以分别使用由 `tsconfig.host.json` 或 `tsconfig.client.json` 初始化的独立 `ts.Program`。直接项目引用确定编译器 face 的成员归属,而包子路径确定 TypeRT 运行时 face 的贡献:声明 `dsh.client` 的普通单项目包可以同时贡献 Host 与 Client 运行时模型;只有通过 `tsconfig.host.json` 或 `tsconfig.client.json` 显式引用的拆分项目,才会被限制在相应 face。`package.json#exports` 确定所有跨包公开边界,跨 face 的边只能来自源码导入或重新导出。NPM 依赖拥有的类型(包括 `@types` 包中的全局声明)继续以 `external` 引用表示,不会被展开。
## 分析模型
+6 -2
View File
@@ -2564,8 +2564,12 @@ function hasPackageSurface(model: PackageModel): boolean {
}
function isDualFacePackage(manifest: Record<string, unknown>): boolean {
return manifest.dshClient !== null
&& typeof manifest.dshClient === 'object'
const dsh = manifest.dsh
const client = dsh !== null && typeof dsh === 'object'
? (dsh as Record<string, unknown>).client
: undefined
return client !== null
&& typeof client === 'object'
&& clientExportSubpaths(manifest).length > 0
}
@@ -309,11 +309,11 @@ export interface RemainingSchema {
const root = copyFixture()
const manifestPath = join(root, 'packages/remote/package.json')
const manifest = JSON.parse(readFileSync(manifestPath, 'utf8')) as {
dshClient?: object
dsh?: { client?: object }
exports: Record<string, unknown>
files: string[]
}
manifest.dshClient = {}
manifest.dsh = { client: {} }
manifest.exports['./client'] = './src/client.ts'
manifest.exports['./client/typert'] = {
types: './lib/typert.client.d.ts',
@@ -332,8 +332,10 @@ export interface ClientMarker {
}
`)
expect(new WorkspaceTypertGenerator(root).generate().map(artifact => artifact.face))
.toEqual(['host', 'client'])
const artifacts = new WorkspaceTypertGenerator(root).generate()
expect(artifacts.map(artifact => artifact.face)).toEqual(['host', 'client'])
expect(artifacts.find(artifact => artifact.face === 'host')?.dts).not.toContain('ClientMarker')
expect(artifacts.find(artifact => artifact.face === 'client')?.dts).toContain('ClientMarker')
})
it.each([
@@ -869,7 +869,7 @@ describe('WorkspaceAnalyzer', { timeout: 60_000 }, () => {
.toEqual(['@fixture/host'])
})
it('keeps both runtime faces for an ordinary dshClient project', () => {
it('keeps both runtime faces for an ordinary dsh.client project', () => {
const root = copyFixture('typert-dual-runtime-')
configureDualRuntimeClient(root, false)
@@ -1227,10 +1227,10 @@ function configureDualRuntimeClient(root: string, splitProjects: boolean): void
const packageRoot = join(root, 'packages/client')
const manifestPath = join(packageRoot, 'package.json')
const manifest = JSON.parse(readFileSync(manifestPath, 'utf8')) as {
dshClient?: object
dsh?: { client?: object }
exports: Record<string, unknown>
}
manifest.dshClient = {}
manifest.dsh = { client: {} }
manifest.exports['./client'] = {
types: './lib/types/client.d.ts',
default: './lib/client.js',
+6 -4
View File
@@ -26,10 +26,12 @@
"./src/*": "./src/*",
"./package.json": "./package.json"
},
"dshClient": {
"inject": [],
"platform": "web",
"immediately": true
"dsh": {
"client": {
"inject": [],
"platform": "web",
"immediately": true
}
},
"scripts": {
"bundle": "tsdown",