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:
10
.github/workflows/ci.yml
vendored
10
.github/workflows/ci.yml
vendored
@@ -58,7 +58,7 @@ jobs:
|
|||||||
- uses: actions/cache/restore@v4
|
- uses: actions/cache/restore@v4
|
||||||
with:
|
with:
|
||||||
path: .cache/eslint
|
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: |
|
restore-keys: |
|
||||||
${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-
|
${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-
|
||||||
|
|
||||||
@@ -173,7 +173,7 @@ jobs:
|
|||||||
- uses: actions/cache/restore@v4
|
- uses: actions/cache/restore@v4
|
||||||
with:
|
with:
|
||||||
path: .cache/eslint
|
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: |
|
restore-keys: |
|
||||||
${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-
|
${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-
|
||||||
|
|
||||||
@@ -237,7 +237,7 @@ jobs:
|
|||||||
- uses: actions/cache@v4
|
- uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: .cache/eslint
|
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: |
|
restore-keys: |
|
||||||
${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-
|
${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-
|
||||||
|
|
||||||
@@ -309,7 +309,7 @@ jobs:
|
|||||||
- uses: actions/cache@v4
|
- uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: .cache/eslint
|
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: |
|
restore-keys: |
|
||||||
${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-
|
${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-
|
||||||
|
|
||||||
@@ -525,7 +525,7 @@ jobs:
|
|||||||
if: matrix.platform == 'linux'
|
if: matrix.platform == 'linux'
|
||||||
with:
|
with:
|
||||||
path: .cache/eslint
|
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: |
|
restore-keys: |
|
||||||
${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-
|
${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-
|
||||||
|
|
||||||
|
|||||||
@@ -86,7 +86,8 @@ export default tseslint.config(
|
|||||||
languageOptions: {
|
languageOptions: {
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
// Same shared project service as the src block: test files resolve
|
// 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,
|
projectService: true,
|
||||||
tsconfigRootDir: import.meta.dirname,
|
tsconfigRootDir: import.meta.dirname,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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": {
|
"compilerOptions": {
|
||||||
"target": "es2024",
|
"target": "es2024",
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
@@ -87,8 +90,9 @@
|
|||||||
// One wildcard maps every @deepseek-ai/dsh-<name> to its source. Package
|
// 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
|
// dir names are unique across groups, so first-on-disk-wins resolution is
|
||||||
// unambiguous; adding a package under an existing group needs no edit
|
// unambiguous; adding a package under an existing group needs no edit
|
||||||
// here. The build graph's project references (tsconfig.build.json) stay
|
// here. The aggregates' project references (tsconfig.host.json /
|
||||||
// explicit — TS project references have no wildcard form.
|
// 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": ["./packages/host/apiproxy/src"],
|
||||||
"@deepseek-ai/dsh-host-apiproxy/client": ["./packages/host/apiproxy/src/fetch/client.ts"],
|
"@deepseek-ai/dsh-host-apiproxy/client": ["./packages/host/apiproxy/src/fetch/client.ts"],
|
||||||
"@deepseek-ai/dsh-host-apiproxy/*": ["./packages/host/apiproxy/src/*"],
|
"@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"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,12 @@
|
|||||||
import tsconfigPaths from 'vite-tsconfig-paths'
|
import tsconfigPaths from 'vite-tsconfig-paths'
|
||||||
import { defineConfig } from 'vitest/config'
|
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'
|
const windowsUnsupportedPackages = process.platform === 'win32'
|
||||||
? [
|
? [
|
||||||
'packages/bash/*',
|
'packages/bash/*',
|
||||||
@@ -40,12 +46,7 @@ const processBoundTests = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
// Native path resolution reads each package's nearest tsconfig, but only the root defines
|
plugins: [pathsPlugin()],
|
||||||
// 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'] })],
|
|
||||||
test: {
|
test: {
|
||||||
setupFiles: ['./scripts/test-invariants.ts'],
|
setupFiles: ['./scripts/test-invariants.ts'],
|
||||||
// .tsx: client component specs (jsdom via per-file @vitest-environment pragma).
|
// .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.
|
// for lower startup/IPC overhead; only explicit process-bound suites fork.
|
||||||
projects: [
|
projects: [
|
||||||
{
|
{
|
||||||
plugins: [tsconfigPaths({ projects: ['./tsconfig.vitest.json'] })],
|
plugins: [pathsPlugin()],
|
||||||
test: {
|
test: {
|
||||||
name: 'thread-safe',
|
name: 'thread-safe',
|
||||||
pool: 'threads',
|
pool: 'threads',
|
||||||
@@ -68,7 +69,7 @@ export default defineConfig({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
plugins: [tsconfigPaths({ projects: ['./tsconfig.vitest.json'] })],
|
plugins: [pathsPlugin()],
|
||||||
test: {
|
test: {
|
||||||
name: 'process-bound',
|
name: 'process-bound',
|
||||||
pool: 'forks',
|
pool: 'forks',
|
||||||
|
|||||||
@@ -29,13 +29,13 @@ const e2eMaxWorkers = positiveIntFromEnv('DSH_E2E_MAX_WORKERS', DEFAULT_E2E_MAX_
|
|||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
// Same resolution note as vitest.config.ts: bare workspace names resolve
|
// Same resolution note as vitest.config.ts: bare workspace names resolve
|
||||||
// through the vitest-scoped tsconfig paths map (its include spans package
|
// through the tsconfig.base.json paths facade (no include = match-all, so
|
||||||
// src, so client-package sources get mapping too — the root tsconfig
|
// client-package sources get mapping too — dropping /client subpath imports
|
||||||
// excludes packages/client, which would drop /client subpath imports onto
|
// onto package exports would load browser dist bundles into node).
|
||||||
// package exports and load browser dist bundles into node). Built-artifact
|
// Built-artifact e2e suites are unaffected: their built-ness lives in
|
||||||
// e2e suites are unaffected: their built-ness lives in subprocesses and
|
// subprocesses and createRequire lookups, which bypass vite resolution
|
||||||
// createRequire lookups, which bypass vite resolution entirely.
|
// entirely.
|
||||||
plugins: [tsconfigPaths({ projects: ['./tsconfig.vitest.json'] })],
|
plugins: [tsconfigPaths({ projects: ['./tsconfig.base.json'] })],
|
||||||
test: {
|
test: {
|
||||||
setupFiles: ['./scripts/test-invariants.ts'],
|
setupFiles: ['./scripts/test-invariants.ts'],
|
||||||
include: ['packages/*/*/tests/**/*.e2e.ts', 'examples/*/tests/**/*.e2e.ts'],
|
include: ['packages/*/*/tests/**/*.e2e.ts', 'examples/*/tests/**/*.e2e.ts'],
|
||||||
|
|||||||
@@ -36,8 +36,9 @@ if (process.env.DSH_SNAPSHOT === 'record') {
|
|||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
// Same resolution note as vitest.config.ts: bare workspace names resolve
|
// Same resolution note as vitest.config.ts: bare workspace names resolve
|
||||||
// through the root tsconfig paths map; the native option cannot do this.
|
// through the tsconfig.base.json paths facade; the native option cannot do
|
||||||
plugins: [tsconfigPaths({ projects: ['./tsconfig.json'] })],
|
// this (the root tsconfig is a solution file with no paths).
|
||||||
|
plugins: [tsconfigPaths({ projects: ['./tsconfig.base.json'] })],
|
||||||
test: {
|
test: {
|
||||||
setupFiles: ['./scripts/test-invariants.ts'],
|
setupFiles: ['./scripts/test-invariants.ts'],
|
||||||
include: [
|
include: [
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { fileURLToPath } from 'node:url'
|
import tsconfigPaths from 'vite-tsconfig-paths'
|
||||||
import { defineConfig } from 'vitest/config'
|
import { defineConfig } from 'vitest/config'
|
||||||
|
|
||||||
// Web smoke lane (GUI, gate-exempt — not part of the CI sequence yet): built
|
// Web smoke lane (GUI, gate-exempt — not part of the CI sequence yet): built
|
||||||
@@ -13,13 +13,10 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
resolve: {
|
// Same resolution note as vitest.config.ts: the tsconfig.base.json paths
|
||||||
alias: {
|
// facade has no include (match-all), so apps/web/tests resolves bare
|
||||||
// apps/web/tests is outside the root tsconfig include, so the shared
|
// workspace imports to source like every other lane.
|
||||||
// tsconfig-paths plugin never maps it; alias the one bare import to source.
|
plugins: [tsconfigPaths({ projects: ['./tsconfig.base.json'] })],
|
||||||
'@deepseek-ai/dsh-host-webserver': fileURLToPath(new URL('packages/host/webserver/src/index.ts', import.meta.url)),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
test: {
|
test: {
|
||||||
include: ['apps/web/tests/**/*.e2e.ts'],
|
include: ['apps/web/tests/**/*.e2e.ts'],
|
||||||
// Browser boot + real-model turns are slow; files share one browser, run serial.
|
// Browser boot + real-model turns are slow; files share one browser, run serial.
|
||||||
|
|||||||
Reference in New Issue
Block a user