From 54ef0f315a52440c372b06be063d2c6702a3e3f4 Mon Sep 17 00:00:00 2001 From: imccyu <276526105+imccyu@users.noreply.github.com> Date: Tue, 25 Aug 2026 22:28:47 +0800 Subject: [PATCH] perf(typert): skip re-verified diagnostics and share analyzer caches in the tsdown plugin --- .../typert/generator/src/tsdown-plugin.ts | 9 +++++-- packages/typert/generator/src/workspace.ts | 26 +++++++++++++++++-- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/packages/typert/generator/src/tsdown-plugin.ts b/packages/typert/generator/src/tsdown-plugin.ts index eca5ad47d2..dedfd366e9 100644 --- a/packages/typert/generator/src/tsdown-plugin.ts +++ b/packages/typert/generator/src/tsdown-plugin.ts @@ -22,6 +22,11 @@ interface TypertPlugin { const DECORATOR_SYNTAX = /^\s*@[A-Za-z_$][\w$]*/m +// This plugin consumes tsc-emitted `lib/types` output, so every project it +// would re-diagnose has already passed the workspace tsc build in the same +// orchestration; the generator skips its per-package diagnostic pass here. +const TSC_VERIFIED_INPUT = { checkDiagnostics: false } as const + /** Generation scope selected by a tsdown build phase. */ export interface TypertPluginOptions { /** Package mode emits only the package being bundled; workspace mode emits every explicit contributor once. */ @@ -78,7 +83,7 @@ export function typertPlugin(pluginOptions: TypertPluginOptions = {}): TypertPlu if (manifest.name === undefined || !hasTypertExport(manifest.exports)) return let artifacts = artifactsByRoot.get(root) if (artifacts === undefined) { - const generator = new WorkspaceTypertGenerator(root) + const generator = new WorkspaceTypertGenerator(root, TSC_VERIFIED_INPUT) artifacts = pluginOptions.faces === undefined ? generator.generate() : generator.generate(undefined, pluginOptions.faces) @@ -89,7 +94,7 @@ export function typertPlugin(pluginOptions: TypertPluginOptions = {}): TypertPlu } function emitWorkspace(root: string, faces: readonly TypertFace[] | undefined): void { - const generator = new WorkspaceTypertGenerator(root) + const generator = new WorkspaceTypertGenerator(root, TSC_VERIFIED_INPUT) const packages = generator.discover(faces) .filter(candidate => hasTypertExport(readManifest(join(root, candidate.root)).exports)) .map(candidate => candidate.package) diff --git a/packages/typert/generator/src/workspace.ts b/packages/typert/generator/src/workspace.ts index 94d1d937e4..50866dc8b1 100644 --- a/packages/typert/generator/src/workspace.ts +++ b/packages/typert/generator/src/workspace.ts @@ -5,7 +5,7 @@ import { readFileSync } from 'node:fs' import { resolve } from 'node:path' -import { TypertAnalysisError, WorkspaceAnalyzer } from './analyzer.ts' +import { TypertAnalysisError, WorkspaceAnalyzer, WorkspaceCaches } from './analyzer.ts' import type { DiscoveredTypertPackage } from './analyzer.ts' import { FaceModelEmitter } from './emitter.ts' import type { ModelEmitResult } from './emitter.ts' @@ -16,13 +16,32 @@ export interface WorkspaceEmitResult extends ModelEmitResult { readonly packageRoot: string } +/** Behavior switches for one {@link WorkspaceTypertGenerator}. */ +export interface WorkspaceTypertGeneratorOptions { + /** + * Run the per-package syntactic/semantic diagnostic pass before analysis + * (default true). Pass false only when the same orchestration already + * verified the workspace with tsc; the Typert-specific analysis checks + * (annotation coverage, private cross-package references, unretainable + * merges) run regardless. + */ + readonly checkDiagnostics?: boolean +} + /** Discover, analyze, and emit package reflection from independent faces. */ export class WorkspaceTypertGenerator { + /** Parsed-config and program-host state shared by every analyzer this generator creates. */ + private readonly caches = new WorkspaceCaches() + /** * Bind generation to one workspace root. * @param root - directory containing face aggregate tsconfigs. + * @param options - behavior switches applied to every pass of this generator. */ - constructor(private readonly root: string) {} + constructor( + private readonly root: string, + private readonly options: WorkspaceTypertGeneratorOptions = {}, + ) {} /** * Find public package faces that contribute Cordis services/events or @@ -33,6 +52,7 @@ export class WorkspaceTypertGenerator { discover(faces?: readonly TypertFace[]): DiscoveredTypertPackage[] { return new WorkspaceAnalyzer({ root: this.root, + caches: this.caches, ...(faces === undefined ? {} : { faces }), }).discoverPackages() } @@ -48,7 +68,9 @@ export class WorkspaceTypertGenerator { const workspace = new WorkspaceAnalyzer({ root: this.root, packages: selected, + caches: this.caches, ...(faces === undefined ? {} : { faces }), + ...(this.options.checkDiagnostics === undefined ? {} : { checkDiagnostics: this.options.checkDiagnostics }), }).analyze() const artifacts: WorkspaceEmitResult[] = [] for (const face of workspace.faces) {