@zukhruf/nx 0.3.58 → 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.
Files changed (2) hide show
  1. package/README.md +133 -2
  2. package/package.json +2 -2
package/README.md CHANGED
@@ -1,6 +1,6 @@
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. Lint stays in `@zukhruf/eslint`, and the Git hooks stay in `@zukhruf/git-hooks`.
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
 
@@ -10,11 +10,12 @@ The words in these documents have one meaning each. See the glossary in [CONTEXT
10
10
  | ---------------- | ---------------------- | --------------------------------------------------------------------------------------------- |
11
11
  | format | `@zukhruf/nx/format` | This README |
12
12
  | test | `@zukhruf/nx/test` | This README |
13
+ | lint | `@zukhruf/nx/lint` | Design for review (#3335) |
13
14
  | portless | `@zukhruf/nx/portless` | Candidate (#3336): 14 projects in 3 repos |
14
15
  | opentofu, prisma | — | Candidates (#3339): 5 places each |
15
16
  | generators | — | Candidates: the workspace generator of `@factory/foundation` (#3337); app kinds later (#3338) |
16
17
 
17
- The lint inputs (7 copies) are #3335; their home (`@zukhruf/eslint` or an area here) is still open.
18
+ The lint rules stay in `@zukhruf/eslint`. The `lint` area gives only the inputs of the `lint` target (#3335).
18
19
 
19
20
  ## format
20
21
 
@@ -344,3 +345,133 @@ A `scripts.test` in a `package.json` replaces the inferred target. Nx runs it wi
344
345
  | text2sql | #3368 |
345
346
 
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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zukhruf/nx",
3
- "version": "0.3.58",
3
+ "version": "0.4.0",
4
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": {
@@ -55,6 +55,6 @@
55
55
  "prettier": "^3.0.0"
56
56
  },
57
57
  "devDependencies": {
58
- "@zukhruf/testing": "^0.3.58"
58
+ "@zukhruf/testing": "^0.4.0"
59
59
  }
60
60
  }