Merge worktree-llm-dynamic-config (884, with latest master) into worktree-llm-web-config
This commit is contained in:
@@ -74,6 +74,7 @@ for (const file of files) {
|
||||
|
||||
errors.push(...validateExampleResolution())
|
||||
errors.push(...validateAppResolution())
|
||||
errors.push(...validateSourcePlaneResolution())
|
||||
|
||||
if (errors.length > 0) {
|
||||
console.error('verify-cordis-config: invalid Loader metadata or plugin package resolution:')
|
||||
@@ -152,6 +153,57 @@ function validateAppResolution(): string[] {
|
||||
return missingPluginDependencies(references, dependencies, 'apps/cli/package.json')
|
||||
}
|
||||
|
||||
/**
|
||||
* Every configured specifier of a local workspace package must resolve through
|
||||
* the tsconfig `paths` facade to a `.ts`/`.tsx` source file. The `dsh` source
|
||||
* launch (tsx) and vitest resolve in the source plane; without a `paths` match
|
||||
* they fall back to package `exports`, which reach built `lib/` — present on a
|
||||
* built dev tree, absent on a clean one — so a missing mapping boots locally
|
||||
* yet breaks every clean checkout. Anything but a `.ts`/`.tsx` hit (a `.d.ts`
|
||||
* or `.js` under built `lib/`) is that artifact-plane fallback, not source.
|
||||
*/
|
||||
function validateSourcePlaneResolution(): string[] {
|
||||
const violations: string[] = []
|
||||
const localPackages = localPackageDirectories()
|
||||
const config = ts.readConfigFile(resolve(root, 'tsconfig.base.json'), path => ts.sys.readFile(path))
|
||||
if (config.error !== undefined) {
|
||||
throw new Error(ts.flattenDiagnosticMessageText(config.error.messageText, '\n'))
|
||||
}
|
||||
const { options, errors: optionErrors } = ts.convertCompilerOptionsFromJson(
|
||||
(config.config as { compilerOptions?: unknown }).compilerOptions,
|
||||
root,
|
||||
'tsconfig.base.json',
|
||||
)
|
||||
if (optionErrors.length > 0) {
|
||||
throw new Error(optionErrors.map(error => ts.flattenDiagnosticMessageText(error.messageText, '\n')).join('\n'))
|
||||
}
|
||||
// convertCompilerOptionsFromJson leaves `pathsBasePath` unset, so relative
|
||||
// `paths` targets resolve against the host's current directory; anchor it to
|
||||
// the repository root to keep the gate cwd-independent.
|
||||
const host: ts.ModuleResolutionHost = {
|
||||
fileExists: path => ts.sys.fileExists(path),
|
||||
readFile: path => ts.sys.readFile(path),
|
||||
directoryExists: path => ts.sys.directoryExists(path),
|
||||
getCurrentDirectory: () => root,
|
||||
}
|
||||
const sourceExtensions = new Set<string>([ts.Extension.Ts, ts.Extension.Tsx])
|
||||
const containingFile = resolve(root, 'scripts/verify-cordis-config.ts')
|
||||
const locationsBySpecifier = new Map<string, Set<string>>()
|
||||
for (const reference of pluginReferences) {
|
||||
const packageName = packageNameFromSpecifier(reference.name)
|
||||
if (packageName === undefined || !localPackages.has(packageName)) continue
|
||||
const locations = locationsBySpecifier.get(reference.name) ?? new Set<string>()
|
||||
locations.add(reference.file)
|
||||
locationsBySpecifier.set(reference.name, locations)
|
||||
}
|
||||
for (const [specifier, locations] of locationsBySpecifier) {
|
||||
const resolved = ts.resolveModuleName(specifier, containingFile, options, host).resolvedModule
|
||||
if (resolved !== undefined && sourceExtensions.has(resolved.extension)) continue
|
||||
violations.push(`${[...locations].join(', ')}: ${specifier} does not resolve to workspace source through tsconfig.base.json paths (add a mapping so the tsx source launch does not depend on built lib/)`)
|
||||
}
|
||||
return violations
|
||||
}
|
||||
|
||||
function missingPluginDependencies(
|
||||
references: readonly PluginReference[],
|
||||
dependencies: Readonly<Record<string, string>>,
|
||||
|
||||
Reference in New Issue
Block a user