import { type ViteUserConfig } from 'vitest/config'; import type { InlineConfig, ProjectConfig } from 'vitest/node'; import { type TierName } from './tiers.js'; export type { TierName } from './tiers.js'; /** * Test options Vitest honours only at the root of a `projects` config. Derived from Vitest's own types rather than * hand-listed, so an option that changes scope in a later release changes scope here too. */ export type RootTestOptions = Omit; /** Root-scoped overrides: Vite-level options plus the test options that survive at the root. */ export type RootOverrides = Omit & { test?: RootTestOptions; }; export interface VitestConfigOptions { /** * Merged into the root config, which every project inherits because each declares `extends: true`. * * `resolve` is per-environment. Vitest resolves a test's own imports through the server environment, so a * condition meant for them goes under `ssr`; a top-level `resolve.conditions` entry reaches the client * environment, which only browser-mode tests resolve through. */ root?: RootOverrides; /** Merged into every declared project. This is where per-project options such as `setupFiles` go. */ project?: ProjectConfig; /** * Merged into one tier's project alone, after this layer's `project` block. Raising a budget for `tool` here * leaves `unit` on the tight default that makes a hung unit test fail fast, which a uniform `project` override * would flatten. */ tiers?: Partial>; /** * Directory basenames kept out of every project's collection, additive to the ones the shared config always * prunes. Each name is matched at any depth, and every layer's entries are concatenated rather than the last * winning, matching the config's rule for arrays. * * The same array declares the scope of nmr's exported test-file conventions check, so the sweep and the * collection glob cannot drift. Excluding a directory from the sweep alone leaves a test file that runs and * reports nothing; excluding it from collection alone leaves a report a consumer cannot act on. A repo wanting * a glob rather than a directory name has the `project` seam's own `exclude`. */ testCollectionExclude?: readonly string[]; /** * Loads nmr's git-isolation setup file into every project, ahead of any the layers supply. Defaults to `true`. * Turn it off only where a suite is meant to read the developer's own git configuration. */ isolateGit?: boolean; /** * Resolves a package whose files sit outside every `node_modules` through its `source` export condition, so a * suite runs without a prior build. Defaults to `true`. A package declaring no such condition is unaffected, * and so is every package under `node_modules`, which Node resolves and which the condition never reaches. */ resolveFromSource?: boolean; /** * Resolves a specifier through the `paths` a `tsconfig.json` declares, so a test reaches an alias the way `tsc` * does. Defaults to `false`, matching Vite, and requires Vite 8. * * Not a default, because both directions are safe to leave to the consumer: omitting it fails loudly with an * unresolved import, while turning it on for a repo that declares `paths` for `tsc` alone changes which module a * specifier reaches with nothing in the run reporting it. A repo declaring no `paths` is unaffected either way. */ tsconfigPaths?: boolean; } export interface RootVitestConfigOptions extends VitestConfigOptions { /** * An absolute path to the monorepo root, which must hold `pnpm-workspace.yaml`. A root config sits at that * directory by construction, so this is `import.meta.dirname`. Stated rather than searched for: resolving it * from the working directory would make the config describe whichever monorepo the run happened to start in. */ monorepoRoot: string; } /** Any number of shared layers, then the config file's own, which states the monorepo root. */ type RootConfigLayers = [...(VitestConfigOptions | undefined)[], RootVitestConfigOptions]; /** * Builds the shared Vitest config for a workspace package, declaring the `unit`, `tool`, `localhost`, and `remote` * projects. Select them at run time with `--project`, which unions when repeated and accepts negation. * * Layers fold left to right, later winning and arrays composing, so a config file shares settings by passing a * layer ahead of its own. Merging two of this function's *outputs* is not the way: both declare the same four * project names, which Vitest rejects at startup. * * An `undefined` layer is skipped, so `defineVitestConfig(shared, isCI ? ciLayer : undefined)` composes. */ export declare function defineVitestConfig(...layers: (VitestConfigOptions | undefined)[]): ViteUserConfig; /** * Builds the shared Vitest config for repo-root tests. Excludes every workspace package from all projects, and * reports no coverage of its own — packages cover their own sources. * * `monorepoRoot` rides on the last layer, which is the config file's own: a shared layer describes settings, not * which repo they belong to, and only the root config's `import.meta.dirname` states this one. The guard below * still catches the JavaScript config that types never reach. */ export declare function defineRootVitestConfig(...layers: RootConfigLayers): ViteUserConfig;