@naturalcycles/dev-lib 20.64.0 → 20.65.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -15,30 +15,43 @@ import type { InlineConfig } from 'vitest/node'
15
15
  */
16
16
  export function defineVitestConfig(config?: Partial<ViteUserConfig>, cwd?: string): ViteUserConfig
17
17
 
18
+ /**
19
+ * For the ROOT vitest.config.ts of a monorepo (Vitest `projects` mode):
20
+ *
21
+ * export default defineVitestMonorepoConfig({
22
+ * test: {
23
+ * projects: ['./packages/*'],
24
+ * // overrides here, e.g:
25
+ * // coverage: { enabled: false },
26
+ * },
27
+ * })
28
+ *
29
+ * Sets the root-only options (reporters, outputFile, coverage, silent, watch,
30
+ * slowTestThreshold, sequence.sequencer), which Vitest reads from the root config only and
31
+ * ignores on the per-project configs (defineVitestConfig in each package).
32
+ */
33
+ export function defineVitestMonorepoConfig(config: Partial<ViteUserConfig>): ViteUserConfig
34
+
18
35
  /**
19
36
  * Pass `import.meta.dirname` as cwd if running from a monorepo.
20
37
  */
21
38
  export function getSharedConfig(cwd?: string): InlineConfig
22
39
 
23
40
  /**
24
- * Reporters for the monorepo root config (Vitest `projects` mode), where
25
- * `reporters` is a root-only option. Returns the compact 'agent' reporter for
26
- * agents, otherwise the default reporters plus a monorepo-wide SummaryReporter.
41
+ * @deprecated Use defineVitestMonorepoConfig for the monorepo root config instead. It sets
42
+ * `reporters` together with all the other root-only options.
27
43
  */
28
44
  export function getRootReporters(): InlineConfig['reporters']
29
45
 
30
46
  /**
31
- * `outputFile` for the junit/json reporters at the monorepo root config (Vitest
32
- * `projects` mode), where `outputFile` is a root-only option. Pair it with
33
- * getRootReporters so the junit/json report is written in the aggregate root run.
47
+ * @deprecated Use defineVitestMonorepoConfig for the monorepo root config instead. It sets
48
+ * `outputFile` together with all the other root-only options.
34
49
  */
35
50
  export function getRootOutputFile(): InlineConfig['outputFile']
36
51
 
37
52
  /**
38
- * `coverage` for the monorepo root config (Vitest `projects` mode), where
39
- * `coverage` is a root-only option. Without it on the root config no coverage
40
- * report is produced when running via `projects`. Produces a single unified
41
- * report spanning all projects.
53
+ * @deprecated Use defineVitestMonorepoConfig for the monorepo root config instead. It sets
54
+ * `coverage` together with all the other root-only options.
42
55
  */
43
56
  export function getRootCoverage(): InlineConfig['coverage']
44
57
 
@@ -37,6 +37,9 @@ if (silent) {
37
37
  * // overrides here, e.g:
38
38
  * // bail: 1,
39
39
  * })
40
+ *
41
+ * In a monorepo: use it in the vitest.config.ts of each package (passing `import.meta.dirname`
42
+ * as cwd), and defineVitestMonorepoConfig in the root vitest.config.ts.
40
43
  */
41
44
  export function defineVitestConfig(config, cwd) {
42
45
  const mergedConfig = defineConfig({
@@ -67,26 +70,89 @@ export function defineVitestConfig(config, cwd) {
67
70
  }
68
71
 
69
72
  /**
70
- * Shared config for Vitest.
73
+ * Use it in the ROOT vitest.config.ts of a monorepo (Vitest `projects` mode):
74
+ *
75
+ * export default defineVitestMonorepoConfig({
76
+ * test: {
77
+ * projects: ['./packages/*'],
78
+ * // overrides here, e.g:
79
+ * // coverage: { enabled: false },
80
+ * },
81
+ * })
82
+ *
83
+ * In `projects` mode Vitest has two kinds of config: the root config (this one) and the
84
+ * per-project configs (defineVitestConfig in each package). A set of options is root-only:
85
+ * Vitest reads them from the root config only and silently IGNORES the per-project values
86
+ * (see `NonProjectOptions` in Vitest's types): `reporters`, `outputFile`, `coverage`, `silent`,
87
+ * `watch`, `slowTestThreshold`, `sequence.sequencer`, etc.
88
+ *
89
+ * This helper sets the root-only part of the shared config (see getRootConfig) on the root
90
+ * config, where it takes effect. So the junit/json/coverage reports are written, the
91
+ * SummaryReporter reports the slowest tests across ALL projects, and the
92
+ * VitestAlphabeticSequencer is actually used, monorepo-wide.
93
+ */
94
+ export function defineVitestMonorepoConfig(config) {
95
+ return defineConfig({
96
+ ...config,
97
+ test: {
98
+ ...getRootConfig(),
99
+ // Console output of failed tests only. Not the all-or-nothing boolean `silent` of
100
+ // getSharedConfig, which is kept there for backwards compatibility.
101
+ silent: 'passed-only',
102
+ ...config?.test,
103
+ },
104
+ })
105
+ }
106
+
107
+ /**
108
+ * Shared config for Vitest: for a single-package repo, or for one project (package) of a
109
+ * monorepo (pass `import.meta.dirname` as cwd).
71
110
  */
72
111
  export function getSharedConfig(cwd) {
73
112
  return {
113
+ // Root-only options. In a single-package repo this config IS the root, so they apply.
114
+ // In a monorepo they are IGNORED here (Vitest reads them from the root config only), so
115
+ // defineVitestMonorepoConfig sets them on the root config instead.
116
+ ...getRootConfig(),
117
+ silent,
118
+ // Per-project options
74
119
  pool,
75
120
  maxWorkers,
76
121
  isolate: false,
77
- watch: false,
78
122
  // dir: 'src',
79
123
  restoreMocks: true,
80
124
  // restoreMocks does not cover vi.stubEnv/vi.stubGlobal
81
125
  unstubEnvs: true,
82
126
  unstubGlobals: true,
83
- silent,
84
127
  setupFiles: getSetupFiles(testType, cwd),
85
128
  logHeapUsage: true,
86
129
  testTimeout: 60_000,
87
130
  hookTimeout: 60_000,
88
- slowTestThreshold: isCI ? 500 : 300, // higher threshold in CI
89
131
  injectCjsGlobals: false,
132
+ deps: {
133
+ // Disable CJS/ESM interop to match production Node.js behavior.
134
+ // Without this, vitest auto-promotes default exports to named exports,
135
+ // which can mask import bugs (e.g., ejs v4 renderFile issue).
136
+ // Vitest's own default is `true`.
137
+ interopDefault: false,
138
+ },
139
+ include,
140
+ exclude,
141
+ }
142
+ }
143
+
144
+ /**
145
+ * The root-only subset of the shared config: the options Vitest reads from the root config
146
+ * only (`NonProjectOptions` in Vitest's types, plus `sequence.sequencer`), hence the ones that
147
+ * must be set on the root config of a monorepo to take effect there. Shared by getSharedConfig
148
+ * (where they apply in a single-package repo) and defineVitestMonorepoConfig.
149
+ *
150
+ * `silent` is root-only too, but is set by the callers, as they differ in it.
151
+ */
152
+ function getRootConfig() {
153
+ return {
154
+ watch: false,
155
+ slowTestThreshold: isCI ? 500 : 300, // higher threshold in CI
90
156
  sequence: {
91
157
  sequencer: VitestAlphabeticSequencer,
92
158
  // shuffle: {
@@ -95,46 +161,46 @@ export function getSharedConfig(cwd) {
95
161
  // },
96
162
  // seed: 1, // this makes the order of tests deterministic (but still not alphabetic)
97
163
  },
98
- include,
99
- exclude,
100
164
  reporters: getReporters(junitReporterEnabled, testType),
101
165
  outputFile: getOutputFile(),
102
166
  coverage: getCoverageConfig(),
103
167
  }
104
168
  }
105
169
 
106
- function getReporters(junitReporterEnabled, testType) {
107
- const override = getReporterOverride()
108
- if (override) return override
170
+ /**
171
+ * @deprecated Use defineVitestMonorepoConfig for the monorepo root config instead. It sets
172
+ * `reporters` together with all the other root-only options (see getRootConfig).
173
+ */
174
+ export function getRootReporters() {
175
+ return getReporters(junitReporterEnabled, testType)
176
+ }
109
177
 
110
- const { GITHUB_ACTIONS } = process.env
111
- return [
112
- 'default',
113
- GITHUB_ACTIONS && 'github-actions',
114
- new SummaryReporter(),
115
- ...getJunitReporters(junitReporterEnabled, testType),
116
- ].filter(Boolean)
178
+ /**
179
+ * @deprecated Use defineVitestMonorepoConfig for the monorepo root config instead. It sets
180
+ * `outputFile` together with all the other root-only options (see getRootConfig).
181
+ */
182
+ export function getRootOutputFile() {
183
+ return getOutputFile()
117
184
  }
118
185
 
119
186
  /**
120
- * Reporters for the monorepo root config (Vitest `projects` mode).
121
- *
122
- * `reporters` is a root-only Vitest option: per-project reporters are ignored
123
- * when running via `projects`. So the per-package SummaryReporter never runs in
124
- * the aggregate root run, and - crucially - a root-level SummaryReporter sees
125
- * the test modules of ALL projects at once, letting it report the slowest tests
126
- * across the entire monorepo.
127
- *
128
- * Use it in the root vitest.config.ts:
187
+ * @deprecated Use defineVitestMonorepoConfig for the monorepo root config instead. It sets
188
+ * `coverage` together with all the other root-only options (see getRootConfig).
189
+ */
190
+ export function getRootCoverage() {
191
+ return getCoverageConfig()
192
+ }
193
+
194
+ /**
195
+ * The reporters, shared by the per-package (getSharedConfig) and the monorepo root
196
+ * (defineVitestMonorepoConfig) configs.
129
197
  *
130
- * export default defineConfig({
131
- * test: {
132
- * projects: ['./packages/*'],
133
- * reporters: getRootReporters(),
134
- * },
135
- * })
198
+ * In a monorepo (`projects` mode) `reporters` is root-only: per-project reporters are ignored.
199
+ * So the per-package SummaryReporter never runs in the aggregate root run, and - crucially -
200
+ * a root-level SummaryReporter sees the test modules of ALL projects at once, letting it report
201
+ * the slowest tests across the entire monorepo.
136
202
  */
137
- export function getRootReporters() {
203
+ function getReporters(junitReporterEnabled, testType) {
138
204
  const override = getReporterOverride()
139
205
  if (override) return override
140
206
 
@@ -148,60 +214,19 @@ export function getRootReporters() {
148
214
  }
149
215
 
150
216
  /**
151
- * `outputFile` for the junit/json reporters at the monorepo root config.
152
- *
153
- * Like `reporters`, `outputFile` is a root-only Vitest option: per-project
154
- * `outputFile` is ignored when running via `projects`. So the root config must
155
- * set it (alongside getRootReporters) for the junit/json report to be written
156
- * in the aggregate root run.
157
- *
158
- * Use it in the root vitest.config.ts:
159
- *
160
- * export default defineConfig({
161
- * test: {
162
- * projects: ['./packages/*'],
163
- * reporters: getRootReporters(),
164
- * outputFile: getRootOutputFile(),
165
- * },
166
- * })
167
- */
168
- export function getRootOutputFile() {
169
- return getOutputFile()
170
- }
171
-
172
- /**
173
- * `coverage` config for the monorepo root config (Vitest `projects` mode).
217
+ * The coverage config, shared by the per-package (getSharedConfig) and the monorepo root
218
+ * (defineVitestMonorepoConfig) configs. Only enabled for CI unit-test runs.
174
219
  *
175
- * Like `reporters` and `outputFile`, `coverage` is a root-only Vitest option:
176
- * it is read from the root project only (see Vitest's `getRootProject().
177
- * serializedConfig.coverage`), so the per-package `coverage` set in
178
- * getSharedConfig is IGNORED when running via `projects`. Without this on the
220
+ * In a monorepo (`projects` mode) `coverage` is root-only: it is read from the root project
221
+ * only (see Vitest's `getRootProject().serializedConfig.coverage`), so the per-package
222
+ * `coverage` set in getSharedConfig is IGNORED when running via `projects`. Without it on the
179
223
  * root config no coverage report is produced at all (e.g. the CI upload of
180
224
  * ./coverage/coverage-summary.json finds nothing).
181
225
  *
182
- * The report is a single, unified one spanning all projects: Vitest tracks
183
- * coverage per-project internally but emits one report under `./coverage`.
184
- * Per-project coverage `include` globs are matched unanchored against absolute
185
- * paths, so executed files under `packages/<pkg>/src/**` are still included.
186
- *
187
- * Use it in the root vitest.config.ts:
188
- *
189
- * export default defineConfig({
190
- * test: {
191
- * projects: ['./packages/*'],
192
- * reporters: getRootReporters(),
193
- * outputFile: getRootOutputFile(),
194
- * coverage: getRootCoverage(),
195
- * },
196
- * })
197
- */
198
- export function getRootCoverage() {
199
- return getCoverageConfig()
200
- }
201
-
202
- /**
203
- * The coverage config, shared by the per-package (getSharedConfig) and root
204
- * (getRootCoverage) configs. Only enabled for CI unit-test runs.
226
+ * The report is a single, unified one spanning all projects: Vitest tracks coverage per-project
227
+ * internally but emits one report under `./coverage`. Per-project coverage `include` globs are
228
+ * matched unanchored against absolute paths, so executed files under `packages/<pkg>/src/**`
229
+ * are still included.
205
230
  */
206
231
  function getCoverageConfig() {
207
232
  return {
@@ -240,7 +265,7 @@ function getCoverageConfig() {
240
265
 
241
266
  /**
242
267
  * The junit + json reporters, enabled in CI (except for manual tests).
243
- * Shared by the per-package (getReporters) and root (getRootReporters) configs.
268
+ * Used (via getReporters) by both the per-package and the monorepo root configs.
244
269
  */
245
270
  function getJunitReporters(junitReporterEnabled, testType) {
246
271
  if (!junitReporterEnabled) return []
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@naturalcycles/dev-lib",
3
3
  "type": "module",
4
- "version": "20.64.0",
4
+ "version": "20.65.0",
5
5
  "dependencies": {
6
6
  "prompts": "^2",
7
7
  "@naturalcycles/js-lib": "^15",