@zukhruf/nx 0.3.57 → 0.4.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.
- package/README.md +350 -6
- package/dist/test/plugin.d.ts +14 -0
- package/dist/test/plugin.d.ts.map +1 -0
- package/dist/test/plugin.js +151 -0
- package/dist/test/plugin.js.map +1 -0
- package/package.json +14 -6
package/README.md
CHANGED
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
# @zukhruf/nx
|
|
2
2
|
|
|
3
|
-
This package is the Nx part of the monorepo standard. Each workspace copied the same Nx configuration into each project. This package gives that configuration one time, in areas. Each area has its own import path, and the package has no root entry point.
|
|
3
|
+
This package is the Nx part of the monorepo standard. Each workspace copied the same Nx configuration into each project. This package gives that configuration one time, in areas. Each area has its own import path, and the package has no root entry point. The lint rules stay in `@zukhruf/eslint`, and the Git hooks stay in `@zukhruf/git-hooks`.
|
|
4
4
|
|
|
5
5
|
The words in these documents have one meaning each. See the glossary in [CONTEXT.md](./CONTEXT.md).
|
|
6
6
|
|
|
7
7
|
## Areas
|
|
8
8
|
|
|
9
|
-
| Area
|
|
10
|
-
|
|
|
11
|
-
| format
|
|
12
|
-
| test
|
|
13
|
-
|
|
|
9
|
+
| Area | Import path | Status |
|
|
10
|
+
| ---------------- | ---------------------- | --------------------------------------------------------------------------------------------- |
|
|
11
|
+
| format | `@zukhruf/nx/format` | This README |
|
|
12
|
+
| test | `@zukhruf/nx/test` | This README |
|
|
13
|
+
| lint | `@zukhruf/nx/lint` | Design for review (#3335) |
|
|
14
|
+
| portless | `@zukhruf/nx/portless` | Candidate (#3336): 14 projects in 3 repos |
|
|
15
|
+
| opentofu, prisma | — | Candidates (#3339): 5 places each |
|
|
16
|
+
| generators | — | Candidates: the workspace generator of `@factory/foundation` (#3337); app kinds later (#3338) |
|
|
17
|
+
|
|
18
|
+
The lint rules stay in `@zukhruf/eslint`. The `lint` area gives only the inputs of the `lint` target (#3335).
|
|
14
19
|
|
|
15
20
|
## format
|
|
16
21
|
|
|
@@ -131,3 +136,342 @@ context-compiler already does this for `@nx/eslint/plugin`. See [ADR 0003](./doc
|
|
|
131
136
|
| deepagents | #3323 |
|
|
132
137
|
|
|
133
138
|
The umbrella item is #3317.
|
|
139
|
+
|
|
140
|
+
## test
|
|
141
|
+
|
|
142
|
+
> Status: shipped (#3328).
|
|
143
|
+
|
|
144
|
+
Seven workspaces run their tests with `node --test` through Nx. Each one copies the `test` target, and the flags drifted. The `test` area is an Nx inference plugin. It gives the `test` target to each project that has `node:test` files. You list the plugin one time in `nx.json`. You do not copy the target, and you do not tag the project.
|
|
145
|
+
|
|
146
|
+
### Use the test area
|
|
147
|
+
|
|
148
|
+
You need Nx 23.2.1 or later. The peer range of `nx` and `@nx/devkit` becomes `>=23.2.1 <25`. See [Prerequisites of the test area](#prerequisites-of-the-test-area).
|
|
149
|
+
|
|
150
|
+
Add the plugin to `plugins` in `nx.json`. The options are optional. They apply to each project of the workspace:
|
|
151
|
+
|
|
152
|
+
```json
|
|
153
|
+
{
|
|
154
|
+
"plugins": [
|
|
155
|
+
"@zukhruf/nx/format",
|
|
156
|
+
{
|
|
157
|
+
"plugin": "@zukhruf/nx/test",
|
|
158
|
+
"options": { "timeout": 60000, "flags": [] }
|
|
159
|
+
}
|
|
160
|
+
]
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
zukhruf builds this package, so it lists the plugin by path, as it does for `format`: `"./packages/nx/src/test/plugin.ts"`.
|
|
165
|
+
|
|
166
|
+
### Signature of the test area
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
// @zukhruf/nx/test
|
|
170
|
+
export const createNodes: CreateNodes<{
|
|
171
|
+
timeout?: number;
|
|
172
|
+
flags?: string[];
|
|
173
|
+
}>;
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Unlike `format`, this plugin takes options. The repos use different flags, so each difference is a parameter:
|
|
177
|
+
|
|
178
|
+
| Option | Default | Effect |
|
|
179
|
+
| --------- | ------- | -------------------------------------------------------------------------------------------------------------------------------- |
|
|
180
|
+
| `timeout` | `60000` | the value of `--test-timeout`, in milliseconds |
|
|
181
|
+
| `flags` | `[]` | more Node flags for each project of the workspace, for example `["--test-force-exit"]` or `["--experimental-test-module-mocks"]` |
|
|
182
|
+
|
|
183
|
+
### Which projects get the test target
|
|
184
|
+
|
|
185
|
+
The plugin finds the test files. It does not read tags or imports. A project root gets the `test` target when all of these are true:
|
|
186
|
+
|
|
187
|
+
- The root owns at least one test file: `*.test.ts`, `*.test.mts`, `*.test.cts`, `*.test.js` or `*.test.mjs`. A file belongs to its nearest project root.
|
|
188
|
+
- The root has no `vitest.config.*`.
|
|
189
|
+
- The root has no `vite.config.*` with a `test` key. `@nx/vitest` uses the same condition (`@nx/vitest/dist/src/plugins/plugin.js:132`).
|
|
190
|
+
- The root is not the workspace root `.`.
|
|
191
|
+
|
|
192
|
+
The project roots are the same as for `format` (see [ADR 0003](./docs/adr/0003-which-roots-get-targets.md)). The plugin adds `**/*.test.{ts,mts,cts,js,mjs}` and `**/{vite,vitest}.config.{js,ts,mjs,mts,cjs,cts}` to the files that it reads. Thus Nx runs the plugin again when a test file or a Vite config changes. The plugin loads Vite from the workspace only for a root with a `vite.config.*`. Nx does not give the plugin the paths in `.gitignore`, so the plugin does not see `dist`.
|
|
193
|
+
|
|
194
|
+
A project with Vitest files and `node:test` files gets no `test` target from this plugin. `@nx/vitest` gives it its target, as today.
|
|
195
|
+
|
|
196
|
+
The 2026-10-29 audit of the 7 repos measured the effect. The rule matches each `node:test` target in use. 11 targets that test nothing go: in context-compiler the connectors `call-history`, `contacts`, `messages`, `slack` and `teams`; in text2sql `backend/inputs`, `harness/runs`, `toolkit/dashboards`, `reports`, `rpc` and `threads`. In text2sql, `.agents` and `.claude` get a target, because they own test files. The `test:node` tag is not necessary. A repo can delete it. See [ADR 0004](./docs/adr/0004-node-test-target-from-test-files.md).
|
|
197
|
+
|
|
198
|
+
### What the test target runs
|
|
199
|
+
|
|
200
|
+
| Part | Value |
|
|
201
|
+
| ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
202
|
+
| Command | `node --test --no-warnings --test-timeout=<timeout> <flags> --test-reporter=spec --test-reporter-destination=stdout --test-reporter=junit --test-reporter-destination=test-results.xml {args}` |
|
|
203
|
+
| `cwd` | `{projectRoot}` |
|
|
204
|
+
| `args` | the test selection (see below) |
|
|
205
|
+
| `outputs` | `["{projectRoot}/test-results.xml"]` |
|
|
206
|
+
| `cache` | `false` |
|
|
207
|
+
| `dependsOn` | `["^build"]` |
|
|
208
|
+
|
|
209
|
+
- `--no-warnings`: 5 of the 7 repos use it.
|
|
210
|
+
- `--test-timeout`: zukhruf and deepagents use 60 s, so the default is 60 s. The other repos have no time limit, and that is drift.
|
|
211
|
+
- Two reporters: `spec` to the terminal and `junit` to `test-results.xml`. zukhruf, deepagents and text2sql use both.
|
|
212
|
+
- `^build`: a test imports the built output of the packages that the project depends on. factory, whatisgoingon and text2sql test from the source, so `^build` is sufficient for them. A repo whose tests also need the project's own `build` adds it (see [Prerequisites of the test area](#prerequisites-of-the-test-area)).
|
|
213
|
+
- No cache: no repo caches a `node:test` run today.
|
|
214
|
+
|
|
215
|
+
The base command has no `--test-force-exit` and no `--experimental-test-module-mocks`. Only Docker tests and tests with open handles need `--test-force-exit`. Only deepagents and the text2sql electron app use module mocks. A repo adds these flags with the `flags` option. One project adds them in its own `args` (see [Override the test target of a project](#override-the-test-target-of-a-project)).
|
|
216
|
+
|
|
217
|
+
The test selection is a list of globs:
|
|
218
|
+
|
|
219
|
+
- one glob for each top-level folder that has test files, for example `"src/**/*.test.ts" "eval/**/*.test.ts"`,
|
|
220
|
+
- one glob with no `**` for the test files directly in the project root, for example `"*.test.ts"`, only when such files exist.
|
|
221
|
+
|
|
222
|
+
Thus a file outside these globs does not run, for example a build output or a `test/helpers/*` file with no test file next to it. Node's own default pattern, `**/{test,test/**/*,test-*,*[._-]test}.{js,mjs,cjs,ts,mts,cts}`, matches too much: `dist/spec/test/*`, `test/helpers/*` and `*.e2e.test.ts`.
|
|
223
|
+
|
|
224
|
+
### Run one file or one test
|
|
225
|
+
|
|
226
|
+
`--args` replaces the test selection. Use it to run one file:
|
|
227
|
+
|
|
228
|
+
```sh
|
|
229
|
+
nx run mutex:test --args="src/mutex/mutex.test.ts"
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
A Node flag on the CLI keeps the test selection. Use it to run the tests with a name:
|
|
233
|
+
|
|
234
|
+
```sh
|
|
235
|
+
nx run mutex:test --test-name-pattern=login
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
The command ends with `{args}`. For a command with `{args}`, Nx puts the CLI flags and the positional words first, then `args` (`nx/dist/src/executors/run-commands/run-commands.impl.js:136-142`). Thus `--test-name-pattern=login` comes before the globs, and Node reads it as a flag.
|
|
239
|
+
|
|
240
|
+
Without `{args}`, the order is different. Nx puts a CLI flag after `args` (`run-commands.impl.js:117-119` and `145-162`): only an unknown option that is not on the CLI comes before `args`. Then `nx run mutex:test --test-name-pattern=login` puts the flag after the globs, and Node reads it as a file name.
|
|
241
|
+
|
|
242
|
+
A positional file does not replace the selection. In `nx run mutex:test src/mutex/mutex.test.ts`, Nx adds the file before the selection, and all the tests run. Use `--args`.
|
|
243
|
+
|
|
244
|
+
A probe on Nx 23.2.1 (2026-10-29) showed this, with `args` `DEFAULT` and a command that prints its arguments:
|
|
245
|
+
|
|
246
|
+
| CLI | With `{args}` | Without `{args}` |
|
|
247
|
+
| ------------------------------------ | ----------------------------------- | ----------------------------------- |
|
|
248
|
+
| `--args=X` | `X` | `X` |
|
|
249
|
+
| `--test-name-pattern=login` | `--test-name-pattern=login DEFAULT` | `DEFAULT --test-name-pattern=login` |
|
|
250
|
+
| `pos.test.ts` | `pos.test.ts DEFAULT` | `DEFAULT pos.test.ts` |
|
|
251
|
+
| `--args=X --test-name-pattern=login` | `--test-name-pattern=login X` | — |
|
|
252
|
+
|
|
253
|
+
The selection is in `args` and not in the command, because a flag after a glob does not work. `node --test "x.test.ts" --test-timeout=1` reads the flag as a file name. It stops with exit code 1: `Could not find 'x.test.ts, --test-timeout=1'`. zukhruf has `"src/**/*.test.ts"` at the end of its command today, so a zukhruf run cannot narrow. Also, a glob that matches no file gives exit code 0. Thus a wrong narrowing passes with no test.
|
|
254
|
+
|
|
255
|
+
### Docker tests
|
|
256
|
+
|
|
257
|
+
A project with the tag `test:docker` starts Docker containers in its tests. zukhruf and deepagents already use this tag. The plugin adds three items to the `test` target of such a project:
|
|
258
|
+
|
|
259
|
+
- `--test-global-setup=<path>`. The global setup of `@zukhruf/testing` makes one run of all the test processes, and it removes what a killed run leaves.
|
|
260
|
+
- `--test-force-exit`. The teardown of the global setup is synchronous on purpose, so it runs also under `--test-force-exit` (`packages/testing/src/scripts/docker-global-setup.ts:99-104`).
|
|
261
|
+
- `cache: false`. The result depends on the engine, not only on the files.
|
|
262
|
+
|
|
263
|
+
`cache: false` is the default, not a guarantee. The base target has no cache too. `targetDefaults` and the project files come after the plugin, so a repo can set `cache: true` on both.
|
|
264
|
+
|
|
265
|
+
The plugin selects the path in this order:
|
|
266
|
+
|
|
267
|
+
1. The project's own `src/testing/docker-global-setup.ts`, if it exists. mutex has one: it starts the shared servers before the run. `@zukhruf/testing` has one: its tests use its own source.
|
|
268
|
+
2. Else, `@zukhruf/testing/docker-global-setup`, resolved from the project root with the default conditions. This gives `dist/scripts/docker-global-setup.js`. The plugin writes the path relative to the `cwd` of the target.
|
|
269
|
+
3. If the plugin cannot resolve the package, it stops with an error. It does not run the tests with no global setup.
|
|
270
|
+
|
|
271
|
+
The value must be a path. Node resolves it with `path.resolve(cwd, value)`, so a package name does not work. That is why 5 repos keep a file that only re-exports the global setup. Each repo deletes this file when it migrates. The global setup runs one time for each `node --test` process.
|
|
272
|
+
|
|
273
|
+
The plugin does not select the Docker engine. It never sets or deletes `DOCKER_CONTEXT` or `DOCKER_HOST`, and it never calls the Docker CLI. The user, CI or the repo selects the engine. See [ADR 0005](./docs/adr/0005-docker-tests-get-the-global-setup.md).
|
|
274
|
+
|
|
275
|
+
On an SSH engine, a repo adds `--test-concurrency=1` with `flags`, or `"parallelism": false` in `targetDefaults`. The plugin does not add them.
|
|
276
|
+
|
|
277
|
+
### Override the test target of a project
|
|
278
|
+
|
|
279
|
+
Nx applies the plugin first, then `targetDefaults`, then `project.json` and `package.json`. A later source wins.
|
|
280
|
+
|
|
281
|
+
A flag for each project of the workspace goes into the `flags` option. A flag for one project goes into the `args` of that project, before its own selection. `args` comes after the command, and a flag must come before a glob. For example, the text2sql backends have a time limit of 120 s:
|
|
282
|
+
|
|
283
|
+
```json
|
|
284
|
+
{
|
|
285
|
+
"targets": {
|
|
286
|
+
"test": {
|
|
287
|
+
"options": { "args": "--test-timeout=120000 \"src/**/*.test.ts\"" }
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
Node uses the last `--test-timeout`, so the value in `args` wins. A probe on Node 26.10.0 showed this on 2026-10-29: `--test-timeout=50 --test-timeout=60000` passed a test of 300 ms, and the reverse order failed it.
|
|
294
|
+
|
|
295
|
+
text2sql leaves the integration tests out of `test` in the same way: `"args": "\"src/**/!(*.integration).test.ts\""`. Other flags for one project: a time limit of 10 s, `--experimental-test-module-mocks`, `--test-force-exit`, `--env-file`.
|
|
296
|
+
|
|
297
|
+
Do not override the `command`. A command in a project file is a new copy of the target.
|
|
298
|
+
|
|
299
|
+
These rules stay in their repo, because they are of a different kind:
|
|
300
|
+
|
|
301
|
+
- the script of deepagents that selects the Docker context,
|
|
302
|
+
- the tests of elt and context-compiler that run from the workspace root,
|
|
303
|
+
- the list of e2e files of the context-compiler desktop app.
|
|
304
|
+
|
|
305
|
+
A `scripts.test` in a `package.json` replaces the inferred target. Nx runs it with `nx:run-script`. The 4 demo projects of deepagents keep their scripts.
|
|
306
|
+
|
|
307
|
+
### Prerequisites of the test area
|
|
308
|
+
|
|
309
|
+
- Nx 23.2.1 or later. In Nx 23.2.1, a target default with its own `command` replaces the command of a plugin (`nx/dist/src/project-graph/utils/project-configuration/target-defaults.js:201-229`). Nx 23.1.0 does not do this. text2sql uses 23.1.0 today.
|
|
310
|
+
- Delete the `command` of `targetDefaults.test` in `nx.json`. If you keep it, it replaces the command of the plugin.
|
|
311
|
+
- Write each extra dependency with `"..."`, so that `^build` stays. For example, factory writes `["...", "^sdk"]`.
|
|
312
|
+
- If the tests of a project use its own built output, add `build`: `targetDefaults.test.dependsOn: ["...", "build"]`. zukhruf, deepagents, elt and context-compiler need this. For example, the tests of `@zukhruf/nx` resolve `@zukhruf/nx/format` to `dist`. Nx skips a dependency on a target that the project does not have, so this is safe for a project with no `build`.
|
|
313
|
+
|
|
314
|
+
### Migrate a workspace to the test area
|
|
315
|
+
|
|
316
|
+
1. Update `nx` and `@nx/devkit` to 23.2.1 or later.
|
|
317
|
+
2. Add `@zukhruf/nx/test` to `plugins` in `nx.json`. Set `timeout` and `flags` if the repo needs other values.
|
|
318
|
+
3. Delete the `command` of `targetDefaults.test`, and its tag filters. Write each extra dependency with `"..."`.
|
|
319
|
+
4. Delete each `test` target in a `project.json` or `package.json` that the plugin now gives. Move the flags of one project into its `args`.
|
|
320
|
+
5. Add the tag `test:docker` to each project with Docker tests.
|
|
321
|
+
6. Delete the file that only re-exports `@zukhruf/testing/docker-global-setup`. Keep a file that does more, for example the mutex file.
|
|
322
|
+
7. Delete the `test:node` tags.
|
|
323
|
+
8. Compare `nx show projects --withTarget test` before and after. The differences must be the ones in the table.
|
|
324
|
+
|
|
325
|
+
| Workspace | Today | Changes |
|
|
326
|
+
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
327
|
+
| zukhruf | `targetDefaults.test` with filters `tag:test:node` and `tag:test:docker`; `dependsOn` `["build", "^build"]`; `--test-force-exit` for each project | 30 tagged projects; 2 Docker projects (mutex, testing) keep their own global setup; `dependsOn` `["...", "build"]`; `flags` `["--test-force-exit"]` if it keeps force-exit for each project |
|
|
328
|
+
| factory | 2 targets: `api` with Docker arguments; `foundation` with its tests in `tests/` | delete `apps/factory/api/src/testing/docker-global-setup.ts`; `dependsOn` `["...", "^sdk"]` |
|
|
329
|
+
| whatisgoingon | 1 target | 1 |
|
|
330
|
+
| deepagents | 11 tagged projects, 3 Docker projects, 4 demo scripts | delete `tools/src/docker-global-setup.ts`; `dependsOn` `["...", "build"]`; module mocks in `flags` or in the `args` of a project; the 4 demo scripts and the Docker context script stay |
|
|
331
|
+
| elt | 55 commands in the projects, 8 with the global setup | delete `docker-global-setup.ts`; `dependsOn` `["...", "build"]`; the runs from the workspace root stay as overrides |
|
|
332
|
+
| context-compiler | 17 targets; the `plugin` project has a no-op `test` that depends on `server:test` | 5 connector targets that test nothing go; `dependsOn` `["...", "build"]`; the desktop e2e files stay as an override; if `plugin` owns no test file, the plugin gives it nothing and its own `test` in `project.json` stays |
|
|
333
|
+
| text2sql | about 24 commands in the projects, and 13 projects on the shared default; Nx 23.1.0 | update Nx; delete `packages/adapters/src/testing/docker-global-setup.ts` and `apps/desktop/backend/src/testing/docker-global-setup.ts`; 6 targets that test nothing go; `.agents` and `.claude` get a target; the backends set `--test-timeout=120000` in `args`; the daemon keeps `["image"]` or uses `"..."` |
|
|
334
|
+
|
|
335
|
+
### Who uses the test area
|
|
336
|
+
|
|
337
|
+
| Workspace | Backlog item |
|
|
338
|
+
| ---------------- | ------------------------------------------- |
|
|
339
|
+
| zukhruf | uses it: `nx.json` lists the plugin by path |
|
|
340
|
+
| factory | #3363 |
|
|
341
|
+
| whatisgoingon | #3364 |
|
|
342
|
+
| deepagents | #3365 |
|
|
343
|
+
| elt | #3366 |
|
|
344
|
+
| context-compiler | #3367 |
|
|
345
|
+
| text2sql | #3368 |
|
|
346
|
+
|
|
347
|
+
The umbrella item is #3328.
|
|
348
|
+
|
|
349
|
+
## lint
|
|
350
|
+
|
|
351
|
+
> Status: design for review (#3335). The code does not exist yet.
|
|
352
|
+
|
|
353
|
+
Nx caches the `lint` target. A cached result is correct only when each file and each package that ESLint loads is an input. Seven workspaces write the packages by hand in `targetDefaults.lint.inputs`, and the lists drift: 5 to 15 packages. When a package is not in the list, an update of that package does not change the hash. Nx then replays a cached pass, and the new rules do not run.
|
|
354
|
+
|
|
355
|
+
The `lint` area is an Nx inference plugin. It adds inputs to the `lint` target that `@nx/eslint/plugin` gives. It does not make a `lint` target, and it does not change the command. It reads the packages from `@zukhruf/eslint`, so no workspace writes a list.
|
|
356
|
+
|
|
357
|
+
### Use the lint area
|
|
358
|
+
|
|
359
|
+
You need Nx 23.2.1 or later, `@nx/eslint` and `@zukhruf/eslint`. Add the plugin to `plugins` in `nx.json`, after `@nx/eslint/plugin`:
|
|
360
|
+
|
|
361
|
+
```json
|
|
362
|
+
{
|
|
363
|
+
"plugins": [
|
|
364
|
+
{ "plugin": "@nx/eslint/plugin", "options": { "targetName": "lint" } },
|
|
365
|
+
"@zukhruf/nx/lint"
|
|
366
|
+
]
|
|
367
|
+
}
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
The order is necessary. Nx merges the plugins in the order of the list, and a later plugin wins. The plugin writes `"..."` first in its `inputs`, so the inputs of `@nx/eslint/plugin` stay. If the plugin comes first, `@nx/eslint/plugin` replaces its inputs, and no run reports it. Thus the plugin stops with an error when `@nx/eslint/plugin` is not before it in `plugins`.
|
|
371
|
+
|
|
372
|
+
zukhruf builds this package, so it lists the plugin by path, as it does for `format` and `test`: `"./packages/nx/src/lint/plugin.ts"`.
|
|
373
|
+
|
|
374
|
+
### Signature of the lint area
|
|
375
|
+
|
|
376
|
+
```ts
|
|
377
|
+
// @zukhruf/nx/lint
|
|
378
|
+
export const createNodes: CreateNodes;
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
The plugin takes no options. A workspace adds its own lint packages in `targetDefaults` (see [Add a lint package of the workspace](#add-a-lint-package-of-the-workspace)).
|
|
382
|
+
|
|
383
|
+
### What the lint area adds
|
|
384
|
+
|
|
385
|
+
`@nx/eslint/plugin` already gives these inputs to `lint` (`@nx/eslint/dist/src/plugins/plugin.js:284-297`):
|
|
386
|
+
|
|
387
|
+
- `default` and `^default`,
|
|
388
|
+
- the root ESLint config and the ESLint config of the project,
|
|
389
|
+
- the `.eslintignore` of the project, when it exists,
|
|
390
|
+
- the tsconfig files outside the project root that the tsconfig of the project extends,
|
|
391
|
+
- `{workspaceRoot}/tools/eslint-rules/**/*`,
|
|
392
|
+
- `externalDependencies` on `eslint`.
|
|
393
|
+
|
|
394
|
+
The plugin keeps them, and it adds the packages of `@zukhruf/eslint`. It finds `@zukhruf/eslint` from the workspace root, in one of two forms:
|
|
395
|
+
|
|
396
|
+
| Form of `@zukhruf/eslint` | Inputs that the plugin adds |
|
|
397
|
+
| ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
|
|
398
|
+
| an installed package in `node_modules` (each workspace but zukhruf) | `{ "externalDependencies": ["@zukhruf/eslint"] }` |
|
|
399
|
+
| a package of the workspace (zukhruf) | the files of its `src` folder, and `externalDependencies` on each name in its `dependencies` and `peerDependencies` |
|
|
400
|
+
|
|
401
|
+
One entry is sufficient for an installed package. Nx makes a node for each package of the lockfile, with an edge for each name in `dependencies`, `peerDependencies` and `optionalDependencies` (`nx/dist/src/plugins/js/lock-file/npm-parser.js:155-170`). An input on `@zukhruf/eslint` hashes all the packages that these edges reach. Thus the hash includes each peer of `@zukhruf/eslint`, each dependency, and the packages that they load in turn. A peer that is not installed has no node, so it is not an input, and it gives no error. The hash of a package is its `integrity` in the lockfile, or its version (`npm-parser.js:103`).
|
|
402
|
+
|
|
403
|
+
A package of the workspace has no node in the lockfile. An `externalDependencies` entry with no node stops the run with an error: `The externalDependency '<name>' for '<project>:lint' could not be found`. Thus, for zukhruf, the plugin reads the names from the `package.json` of `@zukhruf/eslint`.
|
|
404
|
+
|
|
405
|
+
When the plugin cannot find `@zukhruf/eslint`, it stops with an error. It does not give `lint` without the inputs.
|
|
406
|
+
|
|
407
|
+
The plugin gives inputs to each project root (see [ADR 0003](./docs/adr/0003-which-roots-get-targets.md)). A project with no `lint` from `@nx/eslint/plugin` gets no `lint`: Nx deletes a target with no executor, no command and no `dependsOn` (`nx/dist/src/project-graph/utils/project-configuration/target-normalization.js:202-214`).
|
|
408
|
+
|
|
409
|
+
A probe on Nx 23.2.1 (2026-10-30) showed this:
|
|
410
|
+
|
|
411
|
+
| Order of `plugins` | `inputs` of the plugin | `lint` of the project |
|
|
412
|
+
| ------------------------------------- | ---------------------------------------- | ------------------------------------------------------------------------------- |
|
|
413
|
+
| `@nx/eslint/plugin`, then this plugin | `["...", { externalDependencies }]` | `eslint .` with the inputs of `@nx/eslint/plugin` and the new inputs |
|
|
414
|
+
| `@nx/eslint/plugin`, then this plugin | `[{ externalDependencies }]`, no `"..."` | `eslint .` with only the new inputs |
|
|
415
|
+
| this plugin, then `@nx/eslint/plugin` | with or without `"..."` | `eslint .` with only the inputs of `@nx/eslint/plugin`; the new inputs are lost |
|
|
416
|
+
|
|
417
|
+
In the same probe, `@zukhruf/eslint` had the peer `typescript-eslint`. A change of the version of `typescript-eslint` in the lockfile gave a new hash, and `lint` ran again. A change of the `integrity` of `globals`, a dependency of `@zukhruf/eslint`, did the same. Without the input, the same change gave a cached pass. See [ADR 0006](./docs/adr/0006-lint-inputs-from-the-eslint-package.md).
|
|
418
|
+
|
|
419
|
+
### Add a lint package of the workspace
|
|
420
|
+
|
|
421
|
+
Some configs load a package that is not in the edges of `@zukhruf/eslint`. Add it in `targetDefaults` with `"..."` first:
|
|
422
|
+
|
|
423
|
+
```json
|
|
424
|
+
{
|
|
425
|
+
"targetDefaults": {
|
|
426
|
+
"lint": {
|
|
427
|
+
"inputs": [
|
|
428
|
+
"...",
|
|
429
|
+
{
|
|
430
|
+
"externalDependencies": [
|
|
431
|
+
"eslint-plugin-import",
|
|
432
|
+
"eslint-plugin-jsx-a11y",
|
|
433
|
+
"eslint-plugin-react",
|
|
434
|
+
"eslint-plugin-react-hooks"
|
|
435
|
+
]
|
|
436
|
+
}
|
|
437
|
+
]
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
`targetDefaults` comes after the plugins. Without `"..."`, its `inputs` replace the inputs of both plugins. A probe on Nx 23.2.1 (2026-10-30) showed both results.
|
|
444
|
+
|
|
445
|
+
The four packages above are an example from the audit. `nx.configs['flat/react']` of `@nx/eslint-plugin` loads them (`@nx/eslint-plugin/dist/src/flat-configs/react-base.js:4` and `react-jsx.js`), but `@nx/eslint-plugin` does not declare them. factory, whatisgoingon, deepagents and text2sql use `flat/react`.
|
|
446
|
+
|
|
447
|
+
A local file that the root ESLint config imports is also an input of the workspace, for example `{workspaceRoot}/island.eslint.config.mjs`. Add it in the same way.
|
|
448
|
+
|
|
449
|
+
### Prerequisites of the lint area
|
|
450
|
+
|
|
451
|
+
- Nx 23.2.1 or later. The peer range of the package is `>=23.2.1 <25`.
|
|
452
|
+
- `@zukhruf/eslint` in the workspace. elt and context-compiler do not use it today: they have their own `personal.eslint.config.mjs`. They move to `@zukhruf/eslint` first.
|
|
453
|
+
- Delete the hand list in `targetDefaults.lint.inputs`. `targetDefaults` comes after the plugins, so a list without `"..."` replaces the inputs of the plugin.
|
|
454
|
+
- Keep the other keys of `targetDefaults.lint`, for example the `command`, `env` and `parallelism` of deepagents.
|
|
455
|
+
|
|
456
|
+
### Migrate a workspace to the lint area
|
|
457
|
+
|
|
458
|
+
1. Add `@zukhruf/nx/lint` to `plugins`, after `@nx/eslint/plugin`.
|
|
459
|
+
2. Delete `targetDefaults.lint.inputs`.
|
|
460
|
+
3. If the configs load a package that is not in the edges of `@zukhruf/eslint`, add `["...", { "externalDependencies": [...] }]` (see [Add a lint package of the workspace](#add-a-lint-package-of-the-workspace)).
|
|
461
|
+
4. Compare `nx show target inputs <project>:lint --json` before and after, for one project of each kind. Each package of the old list must be in `external`.
|
|
462
|
+
|
|
463
|
+
| Workspace | Packages in the hand list today | After the migration |
|
|
464
|
+
| ---------------- | ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
465
|
+
| zukhruf | 13, and `packages/eslint/src` | no list; `@zukhruf/eslint` is a package of the workspace |
|
|
466
|
+
| factory | 14 | 4 packages of `flat/react` in `targetDefaults`; `tools/eslint-rules` goes from the list, because `@nx/eslint/plugin` gives it |
|
|
467
|
+
| whatisgoingon | 15 | the same as factory |
|
|
468
|
+
| deepagents | 9 | the 4 packages of `flat/react`, which the list does not have today; `tsconfig.base.json` goes when the tsconfig chain gives it; `command`, `env` and `parallelism` stay |
|
|
469
|
+
| text2sql | 7 | the 4 packages of `flat/react` and `eslint-plugin-no-barrel-files` (3 project configs load it), which the list does not have today; Nx updates from 23.1.0 first; `command` stays |
|
|
470
|
+
| elt | 7 | waits: moves to `@zukhruf/eslint` first |
|
|
471
|
+
| context-compiler | 5 | waits: moves to `@zukhruf/eslint` first |
|
|
472
|
+
|
|
473
|
+
The lockfile measured the edges on 2026-10-30. For factory, whatisgoingon, deepagents and text2sql, each package of the hand list is in the edges of `@zukhruf/eslint`, except the 4 packages of `flat/react`.
|
|
474
|
+
|
|
475
|
+
### Who uses the lint area
|
|
476
|
+
|
|
477
|
+
No workspace uses it yet. The umbrella item is #3335.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type CreateNodes } from '@nx/devkit';
|
|
2
|
+
export interface TestOptions {
|
|
3
|
+
timeout?: number;
|
|
4
|
+
flags?: string[];
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Gives the `test` target, a `node --test` run, to each project root that
|
|
8
|
+
* owns test files and is not a Vitest project (ADR 0004). A project with the
|
|
9
|
+
* tag `test:docker` also gets the global setup of `@zukhruf/testing` (ADR
|
|
10
|
+
* 0005). The project roots are the roots of `./format`: a copy of its rule,
|
|
11
|
+
* on the record in docs/copied-code.md.
|
|
12
|
+
*/
|
|
13
|
+
export declare const createNodes: CreateNodes<TestOptions>;
|
|
14
|
+
//# sourceMappingURL=plugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/test/plugin.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,KAAK,WAAW,EAIjB,MAAM,YAAY,CAAC;AAMpB,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB;AAOD;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,EAAE,WAAW,CAAC,WAAW,CAwFhD,CAAC"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
2
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
3
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
4
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
5
|
+
});
|
|
6
|
+
}
|
|
7
|
+
return path;
|
|
8
|
+
};
|
|
9
|
+
import { existsSync } from 'node:fs';
|
|
10
|
+
import { createRequire } from 'node:module';
|
|
11
|
+
import { basename, dirname, extname, join, relative } from 'node:path';
|
|
12
|
+
import { pathToFileURL } from 'node:url';
|
|
13
|
+
import { createNodesFromFiles, readJsonFile, } from '@nx/devkit';
|
|
14
|
+
import { buildPackageJsonPatterns, buildPackageJsonWorkspacesMatcher, } from '@nx/devkit/internal';
|
|
15
|
+
const testFile = /\.test\.(?:ts|mts|cts|js|mjs)$/;
|
|
16
|
+
const viteConfig = /^vite\.config\.(?:js|ts|mjs|mts|cjs|cts)$/;
|
|
17
|
+
const vitestConfig = /^vitest\.config\.(?:js|ts|mjs|mts|cjs|cts)$/;
|
|
18
|
+
const ownGlobalSetup = 'src/testing/docker-global-setup.ts';
|
|
19
|
+
/**
|
|
20
|
+
* Gives the `test` target, a `node --test` run, to each project root that
|
|
21
|
+
* owns test files and is not a Vitest project (ADR 0004). A project with the
|
|
22
|
+
* tag `test:docker` also gets the global setup of `@zukhruf/testing` (ADR
|
|
23
|
+
* 0005). The project roots are the roots of `./format`: a copy of its rule,
|
|
24
|
+
* on the record in docs/copied-code.md.
|
|
25
|
+
*/
|
|
26
|
+
export const createNodes = [
|
|
27
|
+
'{package.json,**/package.json,project.json,**/project.json,**/*.test.{ts,mts,cts,js,mjs},**/{vite,vitest}.config.{js,ts,mjs,mts,cjs,cts}}',
|
|
28
|
+
async (files, options, context) => {
|
|
29
|
+
// The defaults of ADR 0004: 60 s is the time limit of zukhruf and
|
|
30
|
+
// deepagents, and no repo adds a flag for each project.
|
|
31
|
+
const { timeout = 60_000, flags = [] } = options ?? {};
|
|
32
|
+
const configFiles = files.filter((file) => ['package.json', 'project.json'].includes(basename(file)));
|
|
33
|
+
const projectJsonRoots = new Set(configFiles
|
|
34
|
+
.filter((file) => basename(file) === 'project.json')
|
|
35
|
+
.map((file) => dirname(file)));
|
|
36
|
+
const isInWorkspaces = buildPackageJsonWorkspacesMatcher(buildPackageJsonPatterns(context.workspaceRoot, (file) => readJsonFile(join(context.workspaceRoot, file))));
|
|
37
|
+
const rootFiles = configFiles.filter((file) => basename(file) === 'project.json'
|
|
38
|
+
? true
|
|
39
|
+
: !projectJsonRoots.has(dirname(file)) && isInWorkspaces(file));
|
|
40
|
+
const roots = new Set(rootFiles.map((file) => dirname(file)));
|
|
41
|
+
const owned = new Map();
|
|
42
|
+
for (const file of files.filter((file) => testFile.test(file))) {
|
|
43
|
+
const root = nearestRoot(roots, dirname(file));
|
|
44
|
+
if (root !== undefined && root !== '.') {
|
|
45
|
+
owned.set(root, [...(owned.get(root) ?? []), relative(root, file)]);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const vitestRoots = new Set(files
|
|
49
|
+
.filter((file) => vitestConfig.test(basename(file)))
|
|
50
|
+
.map((file) => dirname(file)));
|
|
51
|
+
const viteConfigs = new Map(files
|
|
52
|
+
.filter((file) => viteConfig.test(basename(file)))
|
|
53
|
+
.map((file) => [dirname(file), file]));
|
|
54
|
+
return createNodesFromFiles(async (file) => {
|
|
55
|
+
const root = dirname(file);
|
|
56
|
+
const tests = owned.get(root);
|
|
57
|
+
if (tests === undefined ||
|
|
58
|
+
vitestRoots.has(root) ||
|
|
59
|
+
(await hasViteTest(context.workspaceRoot, viteConfigs.get(root)))) {
|
|
60
|
+
return {};
|
|
61
|
+
}
|
|
62
|
+
const docker = tags(context.workspaceRoot, root, new Set(configFiles)).includes('test:docker');
|
|
63
|
+
const command = [
|
|
64
|
+
'node --test --no-warnings',
|
|
65
|
+
`--test-timeout=${timeout}`,
|
|
66
|
+
...new Set([
|
|
67
|
+
...flags,
|
|
68
|
+
...(docker
|
|
69
|
+
? [
|
|
70
|
+
`--test-global-setup=${globalSetup(context.workspaceRoot, root)}`,
|
|
71
|
+
'--test-force-exit',
|
|
72
|
+
]
|
|
73
|
+
: []),
|
|
74
|
+
]),
|
|
75
|
+
'--test-reporter=spec --test-reporter-destination=stdout',
|
|
76
|
+
'--test-reporter=junit --test-reporter-destination=test-results.xml',
|
|
77
|
+
'{args}',
|
|
78
|
+
].join(' ');
|
|
79
|
+
const test = {
|
|
80
|
+
executor: 'nx:run-commands',
|
|
81
|
+
options: { command, cwd: '{projectRoot}', args: selection(tests) },
|
|
82
|
+
outputs: ['{projectRoot}/test-results.xml'],
|
|
83
|
+
cache: false,
|
|
84
|
+
dependsOn: ['^build'],
|
|
85
|
+
};
|
|
86
|
+
return { projects: { [root]: { targets: { test } } } };
|
|
87
|
+
}, rootFiles, options, context);
|
|
88
|
+
},
|
|
89
|
+
];
|
|
90
|
+
function nearestRoot(roots, folder) {
|
|
91
|
+
if (roots.has(folder)) {
|
|
92
|
+
return folder;
|
|
93
|
+
}
|
|
94
|
+
return folder === '.' ? undefined : nearestRoot(roots, dirname(folder));
|
|
95
|
+
}
|
|
96
|
+
// One glob for each top-level folder with test files, and one glob with no
|
|
97
|
+
// `**` for the test files directly in the root (ADR 0004).
|
|
98
|
+
function selection(tests) {
|
|
99
|
+
const extensions = new Map();
|
|
100
|
+
for (const test of tests) {
|
|
101
|
+
const slash = test.indexOf('/');
|
|
102
|
+
const folder = slash === -1 ? '' : test.slice(0, slash);
|
|
103
|
+
extensions.set(folder, (extensions.get(folder) ?? new Set()).add(extname(test).slice(1)));
|
|
104
|
+
}
|
|
105
|
+
return [...extensions]
|
|
106
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
107
|
+
.map(([folder, found]) => {
|
|
108
|
+
const extension = found.size === 1
|
|
109
|
+
? [...found].join('')
|
|
110
|
+
: `{${[...found].sort().join(',')}}`;
|
|
111
|
+
return `"${folder === '' ? '' : `${folder}/**/`}*.test.${extension}"`;
|
|
112
|
+
})
|
|
113
|
+
.join(' ');
|
|
114
|
+
}
|
|
115
|
+
// The rule of `@nx/vitest`: a `vite.config.*` whose resolved config has
|
|
116
|
+
// `test` makes a Vitest project (`@nx/vitest/dist/src/plugins/plugin.js:
|
|
117
|
+
// 120-138`). Vite is loaded from the workspace, and only when a root has a
|
|
118
|
+
// `vite.config.*`.
|
|
119
|
+
async function hasViteTest(workspaceRoot, file) {
|
|
120
|
+
if (file === undefined) {
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
const vite = await import(__rewriteRelativeImportExtension(pathToFileURL(createRequire(join(workspaceRoot, 'package.json')).resolve('vite')).href));
|
|
124
|
+
const config = await vite.resolveConfig({ configFile: join(workspaceRoot, file), mode: 'development' }, 'build');
|
|
125
|
+
return 'test' in config && Boolean(config.test);
|
|
126
|
+
}
|
|
127
|
+
function tags(workspaceRoot, root, configFiles) {
|
|
128
|
+
const projectJson = join(root, 'project.json');
|
|
129
|
+
const packageJson = join(root, 'package.json');
|
|
130
|
+
return [
|
|
131
|
+
...(configFiles.has(projectJson)
|
|
132
|
+
? (readJsonFile(join(workspaceRoot, projectJson))
|
|
133
|
+
.tags ?? [])
|
|
134
|
+
: []),
|
|
135
|
+
...(configFiles.has(packageJson)
|
|
136
|
+
? (readJsonFile(join(workspaceRoot, packageJson)).nx?.tags ?? [])
|
|
137
|
+
: []),
|
|
138
|
+
];
|
|
139
|
+
}
|
|
140
|
+
// The project's own global setup wins; else the one of `@zukhruf/testing`,
|
|
141
|
+
// resolved from the project root with the default conditions and written
|
|
142
|
+
// relative to the `cwd` of the target (ADR 0005). Node reads the value as a
|
|
143
|
+
// path, so a package name does not work.
|
|
144
|
+
function globalSetup(workspaceRoot, root) {
|
|
145
|
+
const projectRoot = join(workspaceRoot, root);
|
|
146
|
+
if (existsSync(join(projectRoot, ownGlobalSetup))) {
|
|
147
|
+
return ownGlobalSetup;
|
|
148
|
+
}
|
|
149
|
+
return relative(projectRoot, createRequire(join(projectRoot, 'package.json')).resolve('@zukhruf/testing/docker-global-setup'));
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/test/plugin.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zukhruf/nx",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "The Nx part of the monorepo standard
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "The Nx part of the monorepo standard, one area per subpath. @zukhruf/nx/format gives each project format and a cached format:check, both with Prettier. @zukhruf/nx/test gives each project that has node:test files a test target, a node --test run.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -20,7 +20,9 @@
|
|
|
20
20
|
"monorepo",
|
|
21
21
|
"prettier",
|
|
22
22
|
"format",
|
|
23
|
-
"check"
|
|
23
|
+
"check",
|
|
24
|
+
"node-test",
|
|
25
|
+
"test"
|
|
24
26
|
],
|
|
25
27
|
"type": "module",
|
|
26
28
|
"exports": {
|
|
@@ -30,6 +32,12 @@
|
|
|
30
32
|
"types": "./dist/format/plugin.d.ts",
|
|
31
33
|
"import": "./dist/format/plugin.js",
|
|
32
34
|
"default": "./dist/format/plugin.js"
|
|
35
|
+
},
|
|
36
|
+
"./test": {
|
|
37
|
+
"@zukhruf/source": "./src/test/plugin.ts",
|
|
38
|
+
"types": "./dist/test/plugin.d.ts",
|
|
39
|
+
"import": "./dist/test/plugin.js",
|
|
40
|
+
"default": "./dist/test/plugin.js"
|
|
33
41
|
}
|
|
34
42
|
},
|
|
35
43
|
"files": [
|
|
@@ -42,11 +50,11 @@
|
|
|
42
50
|
"access": "public"
|
|
43
51
|
},
|
|
44
52
|
"peerDependencies": {
|
|
45
|
-
"@nx/devkit": ">=23.
|
|
46
|
-
"nx": ">=23.
|
|
53
|
+
"@nx/devkit": ">=23.2.1 <25.0.0",
|
|
54
|
+
"nx": ">=23.2.1 <25.0.0",
|
|
47
55
|
"prettier": "^3.0.0"
|
|
48
56
|
},
|
|
49
57
|
"devDependencies": {
|
|
50
|
-
"@zukhruf/testing": "^0.
|
|
58
|
+
"@zukhruf/testing": "^0.4.0"
|
|
51
59
|
}
|
|
52
60
|
}
|