refactor(vitest): resolve every lane through the tsconfig.base.json facade
tsconfig.vitest.json is deleted; its job (a paths map applying to all test files) is inherent in tsconfig.base.json having no include — vite-tsconfig-paths treats that as match-all. All four vitest configs now pin the same facade: the unit config gains a shared pathsPlugin() helper, the web lane drops its handwritten webserver alias (apps/web tests are covered by match-all), and the snapshot lane leaves the root solution (which no longer carries paths) and stops resolving client imports through package exports. tsconfig.base.json documents the facade role and bans include/files; the CI eslint cache key hashes the four graph tsconfigs; the eslint tests-block comment states resolution via the solution to tsconfig.host.json. Per missions/tsconfig-single-graph-migration.md §3.
This commit is contained in:
@@ -58,7 +58,7 @@ jobs:
|
||||
- uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: .cache/eslint
|
||||
key: ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-${{ hashFiles('pnpm-lock.yaml', 'eslint.config.mjs', 'tsconfig.json', 'packages/*/*/tsconfig.json', 'examples/*/tsconfig.json') }}
|
||||
key: ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-${{ hashFiles('pnpm-lock.yaml', 'eslint.config.mjs', 'tsconfig.json', 'tsconfig.base.json', 'tsconfig.base.client.json', 'tsconfig.host.json', 'tsconfig.client.json', 'packages/*/*/tsconfig.json', 'examples/*/tsconfig.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-
|
||||
|
||||
@@ -173,7 +173,7 @@ jobs:
|
||||
- uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: .cache/eslint
|
||||
key: ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-${{ hashFiles('pnpm-lock.yaml', 'eslint.config.mjs', 'tsconfig.json', 'packages/*/*/tsconfig.json', 'examples/*/tsconfig.json') }}
|
||||
key: ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-${{ hashFiles('pnpm-lock.yaml', 'eslint.config.mjs', 'tsconfig.json', 'tsconfig.base.json', 'tsconfig.base.client.json', 'tsconfig.host.json', 'tsconfig.client.json', 'packages/*/*/tsconfig.json', 'examples/*/tsconfig.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-
|
||||
|
||||
@@ -237,7 +237,7 @@ jobs:
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: .cache/eslint
|
||||
key: ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-${{ hashFiles('pnpm-lock.yaml', 'eslint.config.mjs', 'tsconfig.json', 'packages/*/*/tsconfig.json', 'examples/*/tsconfig.json') }}
|
||||
key: ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-${{ hashFiles('pnpm-lock.yaml', 'eslint.config.mjs', 'tsconfig.json', 'tsconfig.base.json', 'tsconfig.base.client.json', 'tsconfig.host.json', 'tsconfig.client.json', 'packages/*/*/tsconfig.json', 'examples/*/tsconfig.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-
|
||||
|
||||
@@ -309,7 +309,7 @@ jobs:
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: .cache/eslint
|
||||
key: ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-${{ hashFiles('pnpm-lock.yaml', 'eslint.config.mjs', 'tsconfig.json', 'packages/*/*/tsconfig.json', 'examples/*/tsconfig.json') }}
|
||||
key: ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-${{ hashFiles('pnpm-lock.yaml', 'eslint.config.mjs', 'tsconfig.json', 'tsconfig.base.json', 'tsconfig.base.client.json', 'tsconfig.host.json', 'tsconfig.client.json', 'packages/*/*/tsconfig.json', 'examples/*/tsconfig.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-
|
||||
|
||||
@@ -525,7 +525,7 @@ jobs:
|
||||
if: matrix.platform == 'linux'
|
||||
with:
|
||||
path: .cache/eslint
|
||||
key: ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-${{ hashFiles('pnpm-lock.yaml', 'eslint.config.mjs', 'tsconfig.json', 'packages/*/*/tsconfig.json', 'examples/*/tsconfig.json') }}
|
||||
key: ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-${{ hashFiles('pnpm-lock.yaml', 'eslint.config.mjs', 'tsconfig.json', 'tsconfig.base.json', 'tsconfig.base.client.json', 'tsconfig.host.json', 'tsconfig.client.json', 'packages/*/*/tsconfig.json', 'examples/*/tsconfig.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-
|
||||
|
||||
|
||||
+2
-1
@@ -86,7 +86,8 @@ export default tseslint.config(
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
// Same shared project service as the src block: test files resolve
|
||||
// through the root tsconfig (its include covers every tests/ tree).
|
||||
// through the root solution to tsconfig.host.json (its include covers
|
||||
// every host tests/ tree).
|
||||
projectService: true,
|
||||
tsconfigRootDir: import.meta.dirname,
|
||||
},
|
||||
|
||||
+6
-2
@@ -1,4 +1,7 @@
|
||||
{
|
||||
// Doubles as the resolution facade for vite-tsconfig-paths (vitest configs
|
||||
// point here). NEVER add include/files to this file: it would leak into
|
||||
// every extending package project and narrow the facade's match-all scope.
|
||||
"compilerOptions": {
|
||||
"target": "es2024",
|
||||
"module": "esnext",
|
||||
@@ -87,8 +90,9 @@
|
||||
// One wildcard maps every @deepseek-ai/dsh-<name> to its source. Package
|
||||
// dir names are unique across groups, so first-on-disk-wins resolution is
|
||||
// unambiguous; adding a package under an existing group needs no edit
|
||||
// here. The build graph's project references (tsconfig.build.json) stay
|
||||
// explicit — TS project references have no wildcard form.
|
||||
// here. The aggregates' project references (tsconfig.host.json /
|
||||
// tsconfig.client.json) stay explicit — TS project references have no
|
||||
// wildcard form.
|
||||
"@deepseek-ai/dsh-host-apiproxy": ["./packages/host/apiproxy/src"],
|
||||
"@deepseek-ai/dsh-host-apiproxy/client": ["./packages/host/apiproxy/src/fetch/client.ts"],
|
||||
"@deepseek-ai/dsh-host-apiproxy/*": ["./packages/host/apiproxy/src/*"],
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
// Path-map scope for vite-tsconfig-paths in vitest only (never a tsc -b target):
|
||||
// widens include to package src and .tsx so bare workspace imports resolve to source.
|
||||
"extends": "./tsconfig.base.json",
|
||||
"include": [
|
||||
"examples/*/src/**/*.ts",
|
||||
"examples/*/start.ts",
|
||||
"examples/*/tests/**/*.ts",
|
||||
"packages/*/*/src/**/*.ts",
|
||||
"packages/*/*/src/**/*.tsx",
|
||||
"packages/*/*/tests/**/*.ts",
|
||||
"packages/*/*/tests/**/*.tsx",
|
||||
"scripts/**/*.ts"
|
||||
]
|
||||
}
|
||||
+9
-8
@@ -1,6 +1,12 @@
|
||||
import tsconfigPaths from 'vite-tsconfig-paths'
|
||||
import { defineConfig } from 'vitest/config'
|
||||
|
||||
// Resolution facade shared by every plugin instance below: tsconfig.base.json
|
||||
// has no include, which vite-tsconfig-paths treats as match-all, so its paths
|
||||
// map applies to every test file. paths must win over package exports so built
|
||||
// lib/ never loads a second module-singleton copy.
|
||||
const pathsPlugin = (): ReturnType<typeof tsconfigPaths> => tsconfigPaths({ projects: ['./tsconfig.base.json'] })
|
||||
|
||||
const windowsUnsupportedPackages = process.platform === 'win32'
|
||||
? [
|
||||
'packages/bash/*',
|
||||
@@ -40,12 +46,7 @@ const processBoundTests = [
|
||||
]
|
||||
|
||||
export default defineConfig({
|
||||
// Native path resolution reads each package's nearest tsconfig, but only the root defines
|
||||
// workspace paths. Keep this plugin pinned to the root map so bare package imports resolve
|
||||
// to source — with built lib/ present, manifest-exports fallthrough would load a second
|
||||
// copy of module singletons. tsconfig.vitest.json widens include to .tsx specs (the root
|
||||
// include stops at .ts for tsc -b; the plugin scopes applicability by include).
|
||||
plugins: [tsconfigPaths({ projects: ['./tsconfig.vitest.json'] })],
|
||||
plugins: [pathsPlugin()],
|
||||
test: {
|
||||
setupFiles: ['./scripts/test-invariants.ts'],
|
||||
// .tsx: client component specs (jsdom via per-file @vitest-environment pragma).
|
||||
@@ -55,7 +56,7 @@ export default defineConfig({
|
||||
// for lower startup/IPC overhead; only explicit process-bound suites fork.
|
||||
projects: [
|
||||
{
|
||||
plugins: [tsconfigPaths({ projects: ['./tsconfig.vitest.json'] })],
|
||||
plugins: [pathsPlugin()],
|
||||
test: {
|
||||
name: 'thread-safe',
|
||||
pool: 'threads',
|
||||
@@ -68,7 +69,7 @@ export default defineConfig({
|
||||
},
|
||||
},
|
||||
{
|
||||
plugins: [tsconfigPaths({ projects: ['./tsconfig.vitest.json'] })],
|
||||
plugins: [pathsPlugin()],
|
||||
test: {
|
||||
name: 'process-bound',
|
||||
pool: 'forks',
|
||||
|
||||
@@ -29,13 +29,13 @@ const e2eMaxWorkers = positiveIntFromEnv('DSH_E2E_MAX_WORKERS', DEFAULT_E2E_MAX_
|
||||
|
||||
export default defineConfig({
|
||||
// Same resolution note as vitest.config.ts: bare workspace names resolve
|
||||
// through the vitest-scoped tsconfig paths map (its include spans package
|
||||
// src, so client-package sources get mapping too — the root tsconfig
|
||||
// excludes packages/client, which would drop /client subpath imports onto
|
||||
// package exports and load browser dist bundles into node). Built-artifact
|
||||
// e2e suites are unaffected: their built-ness lives in subprocesses and
|
||||
// createRequire lookups, which bypass vite resolution entirely.
|
||||
plugins: [tsconfigPaths({ projects: ['./tsconfig.vitest.json'] })],
|
||||
// through the tsconfig.base.json paths facade (no include = match-all, so
|
||||
// client-package sources get mapping too — dropping /client subpath imports
|
||||
// onto package exports would load browser dist bundles into node).
|
||||
// Built-artifact e2e suites are unaffected: their built-ness lives in
|
||||
// subprocesses and createRequire lookups, which bypass vite resolution
|
||||
// entirely.
|
||||
plugins: [tsconfigPaths({ projects: ['./tsconfig.base.json'] })],
|
||||
test: {
|
||||
setupFiles: ['./scripts/test-invariants.ts'],
|
||||
include: ['packages/*/*/tests/**/*.e2e.ts', 'examples/*/tests/**/*.e2e.ts'],
|
||||
|
||||
@@ -36,8 +36,9 @@ if (process.env.DSH_SNAPSHOT === 'record') {
|
||||
|
||||
export default defineConfig({
|
||||
// Same resolution note as vitest.config.ts: bare workspace names resolve
|
||||
// through the root tsconfig paths map; the native option cannot do this.
|
||||
plugins: [tsconfigPaths({ projects: ['./tsconfig.json'] })],
|
||||
// through the tsconfig.base.json paths facade; the native option cannot do
|
||||
// this (the root tsconfig is a solution file with no paths).
|
||||
plugins: [tsconfigPaths({ projects: ['./tsconfig.base.json'] })],
|
||||
test: {
|
||||
setupFiles: ['./scripts/test-invariants.ts'],
|
||||
include: [
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import tsconfigPaths from 'vite-tsconfig-paths'
|
||||
import { defineConfig } from 'vitest/config'
|
||||
|
||||
// Web smoke lane (GUI, gate-exempt — not part of the CI sequence yet): built
|
||||
@@ -13,13 +13,10 @@ try {
|
||||
}
|
||||
|
||||
export default defineConfig({
|
||||
resolve: {
|
||||
alias: {
|
||||
// apps/web/tests is outside the root tsconfig include, so the shared
|
||||
// tsconfig-paths plugin never maps it; alias the one bare import to source.
|
||||
'@deepseek-ai/dsh-host-webserver': fileURLToPath(new URL('packages/host/webserver/src/index.ts', import.meta.url)),
|
||||
},
|
||||
},
|
||||
// Same resolution note as vitest.config.ts: the tsconfig.base.json paths
|
||||
// facade has no include (match-all), so apps/web/tests resolves bare
|
||||
// workspace imports to source like every other lane.
|
||||
plugins: [tsconfigPaths({ projects: ['./tsconfig.base.json'] })],
|
||||
test: {
|
||||
include: ['apps/web/tests/**/*.e2e.ts'],
|
||||
// Browser boot + real-model turns are slow; files share one browser, run serial.
|
||||
|
||||
Reference in New Issue
Block a user