@codependix/nx 0.0.0-stage β 0.0.1
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/CHANGELOG.md +9 -0
- package/LICENSE +21 -0
- package/README.md +470 -2
- package/dist/plugin-context.utilities-Bre57JBa.js +211 -0
- package/dist/src/executors/gate/executor.d.ts +36 -0
- package/dist/src/executors/gate/executor.js +11 -0
- package/dist/src/index.d.ts +262 -0
- package/dist/src/index.js +78 -0
- package/executors.json +10 -0
- package/package.json +71 -3
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
## 0.0.1 (2026-10-13)
|
|
2
|
+
|
|
3
|
+
### π Features
|
|
4
|
+
|
|
5
|
+
- **codependix:** β¨ infer a per-project codependix-gate target from a new nx plugin ([#1429](https://github.com/organizzolini/codebase/pull/1429), [#1403](https://github.com/organizzolini/codebase/issues/1403))
|
|
6
|
+
|
|
7
|
+
### π§± Updated Dependencies
|
|
8
|
+
|
|
9
|
+
- Updated codependix-cli to 0.0.16
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jimmy Paolini
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,471 @@
|
|
|
1
|
-
#
|
|
1
|
+
# πΈοΈπ§¬ Codependix Nx
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@codependix/nx)
|
|
4
|
+
|
|
5
|
+
**An Nx plugin that checks codependix boundaries per project, built over each project's Nx dependency closure.**
|
|
6
|
+
|
|
7
|
+
Canonical documentation for graph exports, configuration, boundary rules, and
|
|
8
|
+
how a finding is charged to a project is in the
|
|
9
|
+
[`@codependix/cli` README](https://github.com/Organizzolini/codebase/tree/main/packages/ic-suite/codependix/codependix-cli#readme).
|
|
10
|
+
`@codependix/cli` needs no Nx plugin: `--projects` and `--tags` already
|
|
11
|
+
narrow a `--check boundaries` run to the projects it judges, from a plain
|
|
12
|
+
shell. This package is the one place in the toolchain that depends on
|
|
13
|
+
`@nx/devkit`, and it adds what only a task runner can:
|
|
14
|
+
|
|
15
|
+
- **A gate on every project**, so `nx affected`, `--projects=tag:β¦`, and the
|
|
16
|
+
task cache do the selecting.
|
|
17
|
+
- **A failure named after the project whose boundary broke**, rather than one
|
|
18
|
+
workspace-wide task that fails for all of them.
|
|
19
|
+
|
|
20
|
+
## Install
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm install --save-dev @codependix/nx
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Register it in `nx.json`:
|
|
27
|
+
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"plugins": [
|
|
31
|
+
{
|
|
32
|
+
"plugin": "@codependix/nx",
|
|
33
|
+
"options": {
|
|
34
|
+
"configurationPath": "configuration/codependix.config.ts",
|
|
35
|
+
"gateTargetName": "codependix-gate"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
| Option | Meaning |
|
|
43
|
+
| ------ | ------- |
|
|
44
|
+
| `configurationPath` | Where the codependix configuration lives. `codependix.config.ts`, then `configuration/codependix.config.ts`, are searched when omitted |
|
|
45
|
+
| `gateTargetName` | Name of the inferred gate target. `codependix-gate` when omitted |
|
|
46
|
+
|
|
47
|
+
The gate runs the command line under `node --import
|
|
48
|
+
@swc-node/register/esm-register` from the workspace root, so the root must
|
|
49
|
+
resolve `@swc-node/register` and carry a `tsconfig.json` that emits decorator
|
|
50
|
+
metadata β the boundary check boots NestJS containers from their TypeScript
|
|
51
|
+
sources, and constructor injection reads that metadata.
|
|
52
|
+
|
|
53
|
+
## Usage
|
|
54
|
+
|
|
55
|
+
The gate is inferred onto every project except the workspace root, whose
|
|
56
|
+
dependency closure is the whole workspace:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
nx run lexico-entities:codependix-gate # one project
|
|
60
|
+
nx run-many -t codependix-gate # every project
|
|
61
|
+
nx affected -t codependix-gate # only what changed
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### The gate
|
|
65
|
+
|
|
66
|
+
Each gate runs, from the workspace root:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
node --import @swc-node/register/esm-register <@codependix/cli/main> \
|
|
70
|
+
map --directory <workspaceRoot> --config <configurationPath> \
|
|
71
|
+
--check boundaries --projects <project>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
The command line's entry is resolved through `@codependix/cli`'s package
|
|
75
|
+
exports, so the same gate runs the TypeScript source inside this workspace and
|
|
76
|
+
the built `dist/src/main.js` from an installed copy. Its output is streamed to
|
|
77
|
+
the task as it arrives, and the task passes only when it exits zero.
|
|
78
|
+
|
|
79
|
+
**A dependency's broken boundary is that dependency's gate's business.** The
|
|
80
|
+
graphs are built over the project and everything it depends on, so a cycle
|
|
81
|
+
reaching into a dependency is still seen β but only a finding charged to the
|
|
82
|
+
project fails its gate. One charged to a dependency is printed as a note, and
|
|
83
|
+
fails the dependency's own gate instead.
|
|
84
|
+
|
|
85
|
+
The target is cached. Its inputs are the project's own sources and its
|
|
86
|
+
dependencies' (`default`, `^default`), the workspace configuration the rules
|
|
87
|
+
live in, the project's own `codependix.config.*`, and the codependix command
|
|
88
|
+
line itself β because no judged project depends on the code that decides its
|
|
89
|
+
verdict, a change to that code would otherwise replay every cached pass:
|
|
90
|
+
|
|
91
|
+
- When `@codependix/cli` is a package of the same workspace, a
|
|
92
|
+
`{workspaceRoot}/<package>/src/**/*` and `{workspaceRoot}/<package>/package.json`
|
|
93
|
+
input for it and for every workspace package it reaches through
|
|
94
|
+
`workspace:` dependencies. File globs rather than `{ "input", "projects" }`
|
|
95
|
+
inputs, because Nx's affected computation follows `{workspaceRoot}` globs
|
|
96
|
+
and ignores the latter β so a branch that changes the command line selects
|
|
97
|
+
every gate.
|
|
98
|
+
- When it is installed from a registry, an `externalDependencies` input naming
|
|
99
|
+
it and the `@codependix/*` packages it depends on, so a version bump
|
|
100
|
+
invalidates the cache.
|
|
101
|
+
|
|
102
|
+
If the command line cannot be resolved while the graph is built, those inputs
|
|
103
|
+
are left out rather than failing the graph. The target declares no
|
|
104
|
+
`configurations`, so an aggregator run with `--configuration=check` falls
|
|
105
|
+
through to the defaults.
|
|
106
|
+
|
|
107
|
+
### Executor options
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
nx run lexico-api:codependix-gate --projects=lexico-entities,lexico-api
|
|
111
|
+
nx run logging:codependix-gate --tags=type:package --dependencies=false
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
| Option | Meaning |
|
|
115
|
+
| ------ | ------- |
|
|
116
|
+
| `projects` | Nx project names to judge, replacing the target's own project |
|
|
117
|
+
| `tags` | Nx project tags, judging every project carrying **any** of them |
|
|
118
|
+
| `dependencies` | Build over the judged projects' Nx dependency closure. `true` by default; `false` builds over the judged projects alone |
|
|
119
|
+
| `configurationPath` | Overrides the registered configuration path |
|
|
120
|
+
|
|
121
|
+
Nx hands plugin options to inference and to nothing else, so a gate given no
|
|
122
|
+
`configurationPath` reads this plugin's registration back out of `nx.json` β
|
|
123
|
+
and resolves it exactly as inference did, so the file a gate reads is the file
|
|
124
|
+
its cache inputs named.
|
|
125
|
+
|
|
126
|
+
## Packages
|
|
127
|
+
|
|
128
|
+
| Package | Role |
|
|
129
|
+
| ------- | ---- |
|
|
130
|
+
| [`@codependix/nx`](.) | Nx plugin: a per-project boundary gate, built over the Nx dependency closure |
|
|
131
|
+
| [`@codependix/cli`](../codependix-cli/README.md) | Orchestrates the four graph builders, delivers their exports, and runs `--check boundaries` |
|
|
132
|
+
| [`@codependix/boundaries`](../codependix-boundaries/README.md) | Builds each level's graph, judges it against the declared rules, and charges each finding to a project |
|
|
133
|
+
| [`@codependix/configuration`](../codependix-configuration/README.md) | Reads `codependix.config.ts` and resolves per-project export destinations and boundary rules |
|
|
134
|
+
|
|
135
|
+
## Test
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
nx run codependix-nx:vitest
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Contributing
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
nx run codependix-nx:lint-code --configuration=check
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## License
|
|
148
|
+
|
|
149
|
+
MIT β see [LICENSE](../../../../LICENSE).
|
|
150
|
+
|
|
151
|
+
## π Conformetry
|
|
152
|
+
|
|
153
|
+
This project was generated from the [nestjs-service-project](../../../../configuration/conformetry-templates/nestjs-service-project) conformetry template.
|
|
154
|
+
|
|
155
|
+
## πΈοΈ Codependix
|
|
156
|
+
|
|
157
|
+
Dependency graphs exported by [codependix](https://github.com/Organizzolini/codebase/tree/main/packages/ic-suite/codependix/codependix-cli), regenerated by `nx run codebase:codependix:write`.
|
|
158
|
+
|
|
159
|
+
### Nx Neighborhood
|
|
160
|
+
|
|
161
|
+
<!-- codependix:start name="codependix-nx-projects" -->
|
|
162
|
+
```mermaid
|
|
163
|
+
graph LR
|
|
164
|
+
codependix_cli["codependix-cli"]
|
|
165
|
+
codependix_nx["codependix-nx"]
|
|
166
|
+
codependix_nx --> codependix_cli
|
|
167
|
+
classDef subject fill:#7c3aed,color:#fff,stroke:#4c1d95,stroke-width:2px
|
|
168
|
+
class codependix_nx subject
|
|
169
|
+
```
|
|
170
|
+
<!-- codependix:end name="codependix-nx-projects" -->
|
|
171
|
+
|
|
172
|
+
### NestJS Module Graph
|
|
173
|
+
|
|
174
|
+
<!-- codependix:start name="codependix-nestjs-modules" -->
|
|
175
|
+
```mermaid
|
|
176
|
+
flowchart LR
|
|
177
|
+
GateModule
|
|
178
|
+
MainModule
|
|
179
|
+
PluginModule
|
|
180
|
+
GateModule --> PluginModule
|
|
181
|
+
MainModule --> GateModule
|
|
182
|
+
MainModule --> PluginModule
|
|
183
|
+
```
|
|
184
|
+
<!-- codependix:end name="codependix-nestjs-modules" -->
|
|
185
|
+
|
|
186
|
+
### File Imports
|
|
187
|
+
|
|
188
|
+
<!-- codependix:start name="codependix-file-imports" -->
|
|
189
|
+
```mermaid
|
|
190
|
+
graph LR
|
|
191
|
+
file_callidescope_config_ts["callidescope.config.ts"]
|
|
192
|
+
file_codependix_config_ts["codependix.config.ts"]
|
|
193
|
+
file_codometer_config_ts["codometer.config.ts"]
|
|
194
|
+
file_eslint_config_ts["eslint.config.ts"]
|
|
195
|
+
file_src_executors_gate_executor_integration_test_ts["src/executors/gate/executor.integration.test.ts"]
|
|
196
|
+
file_src_executors_gate_executor_ts["src/executors/gate/executor.ts"]
|
|
197
|
+
file_src_executors_gate_executor_types_ts["src/executors/gate/executor.types.ts"]
|
|
198
|
+
file_src_executors_gate_executor_unit_test_ts["src/executors/gate/executor.unit.test.ts"]
|
|
199
|
+
file_src_index_ts["src/index.ts"]
|
|
200
|
+
file_src_index_unit_test_ts["src/index.unit.test.ts"]
|
|
201
|
+
file_src_main_module_ts["src/main.module.ts"]
|
|
202
|
+
file_src_modules_gate_gate_constants_ts["src/modules/gate/gate.constants.ts"]
|
|
203
|
+
file_src_modules_gate_gate_module_ts["src/modules/gate/gate.module.ts"]
|
|
204
|
+
file_src_modules_gate_gate_service_ts["src/modules/gate/gate.service.ts"]
|
|
205
|
+
file_src_modules_gate_gate_service_unit_test_ts["src/modules/gate/gate.service.unit.test.ts"]
|
|
206
|
+
file_src_modules_gate_gate_types_ts["src/modules/gate/gate.types.ts"]
|
|
207
|
+
file_src_modules_plugin_plugin_context_utilities_ts["src/modules/plugin/plugin-context.utilities.ts"]
|
|
208
|
+
file_src_modules_plugin_plugin_context_utilities_unit_test_ts["src/modules/plugin/plugin-context.utilities.unit.test.ts"]
|
|
209
|
+
file_src_modules_plugin_plugin_inputs_utilities_ts["src/modules/plugin/plugin-inputs.utilities.ts"]
|
|
210
|
+
file_src_modules_plugin_plugin_inputs_utilities_unit_test_ts["src/modules/plugin/plugin-inputs.utilities.unit.test.ts"]
|
|
211
|
+
file_src_modules_plugin_plugin_constants_ts["src/modules/plugin/plugin.constants.ts"]
|
|
212
|
+
file_src_modules_plugin_plugin_module_ts["src/modules/plugin/plugin.module.ts"]
|
|
213
|
+
file_src_modules_plugin_plugin_service_ts["src/modules/plugin/plugin.service.ts"]
|
|
214
|
+
file_src_modules_plugin_plugin_service_unit_test_ts["src/modules/plugin/plugin.service.unit.test.ts"]
|
|
215
|
+
file_src_modules_plugin_plugin_types_ts["src/modules/plugin/plugin.types.ts"]
|
|
216
|
+
file_testing_mocks_ts["testing/mocks.ts"]
|
|
217
|
+
file_testing_setup_ts["testing/setup.ts"]
|
|
218
|
+
file_vite_config_ts["vite.config.ts"]
|
|
219
|
+
file_vitest_config_ts["vitest.config.ts"]
|
|
220
|
+
file_src_executors_gate_executor_integration_test_ts --> file_src_executors_gate_executor_ts
|
|
221
|
+
file_src_executors_gate_executor_integration_test_ts --> file_src_executors_gate_executor_types_ts
|
|
222
|
+
file_src_executors_gate_executor_ts --> file_src_executors_gate_executor_types_ts
|
|
223
|
+
file_src_executors_gate_executor_ts --> file_src_modules_plugin_plugin_context_utilities_ts
|
|
224
|
+
file_src_executors_gate_executor_types_ts --> file_src_modules_gate_gate_types_ts
|
|
225
|
+
file_src_executors_gate_executor_unit_test_ts --> file_src_executors_gate_executor_ts
|
|
226
|
+
file_src_executors_gate_executor_unit_test_ts --> file_src_modules_gate_gate_service_ts
|
|
227
|
+
file_src_index_ts --> file_src_modules_plugin_plugin_context_utilities_ts
|
|
228
|
+
file_src_index_ts --> file_src_modules_plugin_plugin_inputs_utilities_ts
|
|
229
|
+
file_src_index_ts --> file_src_modules_plugin_plugin_constants_ts
|
|
230
|
+
file_src_index_unit_test_ts --> file_src_index_ts
|
|
231
|
+
file_src_index_unit_test_ts --> file_src_modules_plugin_plugin_service_ts
|
|
232
|
+
file_src_index_unit_test_ts --> file_src_modules_plugin_plugin_types_ts
|
|
233
|
+
file_src_main_module_ts --> file_src_modules_gate_gate_module_ts
|
|
234
|
+
file_src_main_module_ts --> file_src_modules_plugin_plugin_module_ts
|
|
235
|
+
file_src_modules_gate_gate_module_ts --> file_src_modules_gate_gate_service_ts
|
|
236
|
+
file_src_modules_gate_gate_module_ts --> file_src_modules_plugin_plugin_module_ts
|
|
237
|
+
file_src_modules_gate_gate_service_ts --> file_src_modules_gate_gate_constants_ts
|
|
238
|
+
file_src_modules_gate_gate_service_ts --> file_src_modules_gate_gate_types_ts
|
|
239
|
+
file_src_modules_gate_gate_service_ts --> file_src_modules_plugin_plugin_service_ts
|
|
240
|
+
file_src_modules_gate_gate_service_unit_test_ts --> file_src_modules_gate_gate_service_ts
|
|
241
|
+
file_src_modules_gate_gate_service_unit_test_ts --> file_src_modules_plugin_plugin_service_ts
|
|
242
|
+
file_src_modules_plugin_plugin_context_utilities_ts --> file_src_main_module_ts
|
|
243
|
+
file_src_modules_plugin_plugin_context_utilities_ts --> file_src_modules_gate_gate_service_ts
|
|
244
|
+
file_src_modules_plugin_plugin_context_utilities_ts --> file_src_modules_plugin_plugin_constants_ts
|
|
245
|
+
file_src_modules_plugin_plugin_context_utilities_ts --> file_src_modules_plugin_plugin_service_ts
|
|
246
|
+
file_src_modules_plugin_plugin_context_utilities_ts --> file_src_modules_plugin_plugin_types_ts
|
|
247
|
+
file_src_modules_plugin_plugin_context_utilities_unit_test_ts --> file_src_modules_gate_gate_service_ts
|
|
248
|
+
file_src_modules_plugin_plugin_context_utilities_unit_test_ts --> file_src_modules_plugin_plugin_context_utilities_ts
|
|
249
|
+
file_src_modules_plugin_plugin_context_utilities_unit_test_ts --> file_src_modules_plugin_plugin_service_ts
|
|
250
|
+
file_src_modules_plugin_plugin_inputs_utilities_ts --> file_src_modules_plugin_plugin_constants_ts
|
|
251
|
+
file_src_modules_plugin_plugin_inputs_utilities_ts --> file_src_modules_plugin_plugin_types_ts
|
|
252
|
+
file_src_modules_plugin_plugin_inputs_utilities_unit_test_ts --> file_src_modules_plugin_plugin_inputs_utilities_ts
|
|
253
|
+
file_src_modules_plugin_plugin_module_ts --> file_src_modules_plugin_plugin_service_ts
|
|
254
|
+
file_src_modules_plugin_plugin_service_ts --> file_src_modules_plugin_plugin_constants_ts
|
|
255
|
+
file_src_modules_plugin_plugin_service_ts --> file_src_modules_plugin_plugin_types_ts
|
|
256
|
+
file_src_modules_plugin_plugin_service_unit_test_ts --> file_src_modules_plugin_plugin_service_ts
|
|
257
|
+
file_src_modules_plugin_plugin_types_ts --> file_src_modules_plugin_plugin_constants_ts
|
|
258
|
+
```
|
|
259
|
+
<!-- codependix:end name="codependix-file-imports" -->
|
|
260
|
+
|
|
261
|
+
<!-- codometer:start -->
|
|
262
|
+
|
|
263
|
+
## β²οΈ Codometer
|
|
264
|
+
|
|
265
|
+
### Project
|
|
266
|
+
|
|
267
|
+

|
|
268
|
+

|
|
269
|
+

|
|
270
|
+

|
|
271
|
+
|
|
272
|
+
### TypeScript
|
|
273
|
+
|
|
274
|
+

|
|
275
|
+

|
|
276
|
+

|
|
277
|
+

|
|
278
|
+

|
|
279
|
+

|
|
280
|
+

|
|
281
|
+
|
|
282
|
+
### JavaScript
|
|
283
|
+
|
|
284
|
+

|
|
285
|
+

|
|
286
|
+

|
|
287
|
+

|
|
288
|
+

|
|
289
|
+

|
|
290
|
+

|
|
291
|
+

|
|
292
|
+

|
|
293
|
+

|
|
294
|
+

|
|
295
|
+

|
|
296
|
+

|
|
297
|
+

|
|
298
|
+
|
|
299
|
+
### Python
|
|
300
|
+
|
|
301
|
+

|
|
302
|
+

|
|
303
|
+

|
|
304
|
+

|
|
305
|
+

|
|
306
|
+

|
|
307
|
+

|
|
308
|
+

|
|
309
|
+

|
|
310
|
+

|
|
311
|
+

|
|
312
|
+

|
|
313
|
+
|
|
314
|
+
### JSON
|
|
315
|
+
|
|
316
|
+

|
|
317
|
+

|
|
318
|
+

|
|
319
|
+

|
|
320
|
+

|
|
321
|
+

|
|
322
|
+

|
|
323
|
+

|
|
324
|
+

|
|
325
|
+

|
|
326
|
+

|
|
327
|
+

|
|
328
|
+
|
|
329
|
+
### YAML
|
|
330
|
+
|
|
331
|
+

|
|
332
|
+

|
|
333
|
+

|
|
334
|
+

|
|
335
|
+

|
|
336
|
+

|
|
337
|
+

|
|
338
|
+

|
|
339
|
+

|
|
340
|
+

|
|
341
|
+

|
|
342
|
+
|
|
343
|
+
### TOML
|
|
344
|
+
|
|
345
|
+

|
|
346
|
+

|
|
347
|
+

|
|
348
|
+

|
|
349
|
+

|
|
350
|
+

|
|
351
|
+

|
|
352
|
+
|
|
353
|
+
### Shell
|
|
354
|
+
|
|
355
|
+

|
|
356
|
+

|
|
357
|
+

|
|
358
|
+

|
|
359
|
+

|
|
360
|
+

|
|
361
|
+

|
|
362
|
+

|
|
363
|
+

|
|
364
|
+

|
|
365
|
+

|
|
366
|
+
|
|
367
|
+
### SQL
|
|
368
|
+
|
|
369
|
+

|
|
370
|
+

|
|
371
|
+

|
|
372
|
+

|
|
373
|
+

|
|
374
|
+

|
|
375
|
+

|
|
376
|
+

|
|
377
|
+

|
|
378
|
+

|
|
379
|
+

|
|
380
|
+
|
|
381
|
+
### HCL
|
|
382
|
+
|
|
383
|
+

|
|
384
|
+

|
|
385
|
+

|
|
386
|
+

|
|
387
|
+

|
|
388
|
+

|
|
389
|
+

|
|
390
|
+

|
|
391
|
+

|
|
392
|
+
|
|
393
|
+
### CSS
|
|
394
|
+
|
|
395
|
+

|
|
396
|
+

|
|
397
|
+

|
|
398
|
+

|
|
399
|
+

|
|
400
|
+

|
|
401
|
+

|
|
402
|
+

|
|
403
|
+

|
|
404
|
+
|
|
405
|
+
### Conventions
|
|
406
|
+
|
|
407
|
+

|
|
408
|
+

|
|
409
|
+

|
|
410
|
+

|
|
411
|
+

|
|
412
|
+

|
|
413
|
+

|
|
414
|
+

|
|
415
|
+

|
|
416
|
+

|
|
417
|
+

|
|
418
|
+

|
|
419
|
+

|
|
420
|
+

|
|
421
|
+

|
|
422
|
+

|
|
423
|
+

|
|
424
|
+

|
|
425
|
+
|
|
426
|
+
### Jupyter
|
|
427
|
+
|
|
428
|
+

|
|
429
|
+

|
|
430
|
+

|
|
431
|
+

|
|
432
|
+

|
|
433
|
+

|
|
434
|
+

|
|
435
|
+

|
|
436
|
+

|
|
437
|
+

|
|
438
|
+

|
|
439
|
+

|
|
440
|
+

|
|
441
|
+

|
|
442
|
+

|
|
443
|
+

|
|
444
|
+

|
|
445
|
+

|
|
446
|
+

|
|
447
|
+

|
|
448
|
+
|
|
449
|
+
### Markdown
|
|
450
|
+
|
|
451
|
+

|
|
452
|
+

|
|
453
|
+

|
|
454
|
+

|
|
455
|
+

|
|
456
|
+

|
|
457
|
+

|
|
458
|
+

|
|
459
|
+

|
|
460
|
+

|
|
461
|
+

|
|
462
|
+

|
|
463
|
+

|
|
464
|
+

|
|
465
|
+

|
|
466
|
+

|
|
467
|
+

|
|
468
|
+

|
|
469
|
+

|
|
470
|
+

|
|
471
|
+
<!-- codometer:end -->
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import "reflect-metadata";
|
|
2
|
+
import { NestFactory as e } from "@nestjs/core";
|
|
3
|
+
import { Injectable as t, Module as n } from "@nestjs/common";
|
|
4
|
+
import { existsSync as r, readFileSync as i } from "node:fs";
|
|
5
|
+
import a from "node:path";
|
|
6
|
+
import { spawn as o } from "node:child_process";
|
|
7
|
+
import { createRequire as s } from "node:module";
|
|
8
|
+
//#region \0rolldown/runtime.js
|
|
9
|
+
var c = Object.defineProperty, __name = (e, t) => c(e, "name", {
|
|
10
|
+
value: t,
|
|
11
|
+
configurable: !0
|
|
12
|
+
}), l = "**/{project.json,codependix.config.*}", u = "project.json", d = "{projectRoot}/codependix.config.*", f = "__codependixPluginContext", p = "@codependix/nx", m = "codependix-gate", h = ["codependix.config.ts", "configuration/codependix.config.ts"], g = "@codependix/cli", _ = "workspace:", v = ["package.json", "src/**/*"];
|
|
13
|
+
//#endregion
|
|
14
|
+
//#region \0@oxc-project+runtime@0.153.0/helpers/esm/decorateMetadata.js
|
|
15
|
+
function __decorateMetadata(e, t) {
|
|
16
|
+
if (typeof Reflect == "object" && typeof Reflect.metadata == "function") return Reflect.metadata(e, t);
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region \0@oxc-project+runtime@0.153.0/helpers/esm/decorate.js
|
|
20
|
+
function __decorate(e, t, n, r) {
|
|
21
|
+
var i = arguments.length, a = i < 3 ? t : r === null ? r = Object.getOwnPropertyDescriptor(t, n) : r, o;
|
|
22
|
+
if (typeof Reflect == "object" && typeof Reflect.decorate == "function") a = Reflect.decorate(e, t, n, r);
|
|
23
|
+
else for (var s = e.length - 1; s >= 0; s--) (o = e[s]) && (a = (i < 3 ? o(a) : i > 3 ? o(t, n, a) : o(t, n)) || a);
|
|
24
|
+
return i > 3 && a && Object.defineProperty(t, n, a), a;
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
//#region packages/ic-suite/codependix/codependix-nx/src/modules/plugin/plugin.service.ts
|
|
28
|
+
var y = class PluginService {
|
|
29
|
+
constructor() {}
|
|
30
|
+
isUnknownArray(e) {
|
|
31
|
+
return Array.isArray(e);
|
|
32
|
+
}
|
|
33
|
+
readString(e) {
|
|
34
|
+
let t = e.record[e.key];
|
|
35
|
+
return typeof t == "string" && t !== "" ? t : void 0;
|
|
36
|
+
}
|
|
37
|
+
selectProjectRoots(e) {
|
|
38
|
+
return e.filter((e) => a.basename(e) === u).map((e) => a.dirname(e)).filter((e) => e !== ".");
|
|
39
|
+
}
|
|
40
|
+
toRecord(e) {
|
|
41
|
+
return typeof e == "object" && e ? { ...e } : {};
|
|
42
|
+
}
|
|
43
|
+
inferTargets(e) {
|
|
44
|
+
let t = this.resolvePluginOptions({
|
|
45
|
+
exists: (t) => r(a.join(e.workspaceRoot, t)),
|
|
46
|
+
options: e.options
|
|
47
|
+
}), n = { [t.gateTargetName]: {
|
|
48
|
+
cache: !0,
|
|
49
|
+
executor: `${p}:gate`,
|
|
50
|
+
inputs: [
|
|
51
|
+
"default",
|
|
52
|
+
"^default",
|
|
53
|
+
`{workspaceRoot}/${t.configurationPath}`,
|
|
54
|
+
d,
|
|
55
|
+
...e.toolInputs
|
|
56
|
+
],
|
|
57
|
+
options: {}
|
|
58
|
+
} };
|
|
59
|
+
return new Map(this.selectProjectRoots(e.projectConfigurationFiles).map((e) => [e, n]));
|
|
60
|
+
}
|
|
61
|
+
readRegisteredOptions(e) {
|
|
62
|
+
let { plugins: t } = this.toRecord(e);
|
|
63
|
+
if (!this.isUnknownArray(t)) return;
|
|
64
|
+
let { options: n } = t.map((e) => this.toRecord(e)).find(({ plugin: e }) => e === "@codependix/nx") ?? {};
|
|
65
|
+
return n;
|
|
66
|
+
}
|
|
67
|
+
resolvePluginOptions(e) {
|
|
68
|
+
let t = this.toRecord(e.options);
|
|
69
|
+
return {
|
|
70
|
+
configurationPath: this.readString({
|
|
71
|
+
key: "configurationPath",
|
|
72
|
+
record: t
|
|
73
|
+
}) ?? h.find((t) => e.exists(t)) ?? h[0],
|
|
74
|
+
gateTargetName: this.readString({
|
|
75
|
+
key: "gateTargetName",
|
|
76
|
+
record: t
|
|
77
|
+
}) ?? "codependix-gate"
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
y = __decorate([t(), __decorateMetadata("design:paramtypes", [])], y);
|
|
82
|
+
//#endregion
|
|
83
|
+
//#region packages/ic-suite/codependix/codependix-nx/src/modules/plugin/plugin.module.ts
|
|
84
|
+
var b = class PluginModule {};
|
|
85
|
+
b = __decorate([n({
|
|
86
|
+
controllers: [],
|
|
87
|
+
exports: [y],
|
|
88
|
+
imports: [],
|
|
89
|
+
providers: [y]
|
|
90
|
+
})], b);
|
|
91
|
+
//#endregion
|
|
92
|
+
//#region packages/ic-suite/codependix/codependix-nx/src/modules/gate/gate.constants.ts
|
|
93
|
+
var x = "@swc-node/register/esm-register", S = "@codependix/cli/main", C = "nx.json", w = class GateService {
|
|
94
|
+
pluginService;
|
|
95
|
+
constructor(e) {
|
|
96
|
+
this.pluginService = e;
|
|
97
|
+
}
|
|
98
|
+
readNameList(e) {
|
|
99
|
+
return (e ?? []).flatMap((e) => e.split(",")).map((e) => e.trim()).filter((e) => e !== "");
|
|
100
|
+
}
|
|
101
|
+
readNxConfiguration(e) {
|
|
102
|
+
try {
|
|
103
|
+
return JSON.parse(i(a.join(e, C), "utf8"));
|
|
104
|
+
} catch {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
async spawnCommandLine(e) {
|
|
109
|
+
return await new Promise((t, n) => {
|
|
110
|
+
let r = o(process.execPath, e.argv, {
|
|
111
|
+
cwd: e.workspaceRoot,
|
|
112
|
+
stdio: [
|
|
113
|
+
"ignore",
|
|
114
|
+
"pipe",
|
|
115
|
+
"pipe"
|
|
116
|
+
]
|
|
117
|
+
});
|
|
118
|
+
r.stdout.on("data", (e) => process.stdout.write(e)), r.stderr.on("data", (e) => process.stderr.write(e)), r.on("error", n), r.on("close", (e) => {
|
|
119
|
+
t(e === 0);
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
buildCommandArguments(e) {
|
|
124
|
+
return [
|
|
125
|
+
"--import",
|
|
126
|
+
e.loaderSpecifier,
|
|
127
|
+
e.cliEntryPath,
|
|
128
|
+
"map",
|
|
129
|
+
"--directory",
|
|
130
|
+
e.workspaceRoot,
|
|
131
|
+
"--config",
|
|
132
|
+
e.configurationPath,
|
|
133
|
+
"--check",
|
|
134
|
+
"boundaries",
|
|
135
|
+
...e.projects.length > 0 ? ["--projects", e.projects.join(",")] : [],
|
|
136
|
+
...e.tags.length > 0 ? ["--tags", e.tags.join(",")] : [],
|
|
137
|
+
...e.dependencies ? [] : ["--no-dependencies"]
|
|
138
|
+
];
|
|
139
|
+
}
|
|
140
|
+
resolveConfigurationPath(e) {
|
|
141
|
+
return e.configurationPath !== void 0 && e.configurationPath !== "" ? e.configurationPath : this.pluginService.resolvePluginOptions({
|
|
142
|
+
exists: (t) => r(a.join(e.workspaceRoot, t)),
|
|
143
|
+
options: this.pluginService.readRegisteredOptions(this.readNxConfiguration(e.workspaceRoot))
|
|
144
|
+
}).configurationPath;
|
|
145
|
+
}
|
|
146
|
+
resolveSelection(e) {
|
|
147
|
+
let t = this.readNameList(e.options.projects), n = this.readNameList(e.options.tags);
|
|
148
|
+
if (t.length > 0 || n.length > 0) return {
|
|
149
|
+
projects: t,
|
|
150
|
+
tags: n
|
|
151
|
+
};
|
|
152
|
+
if (e.projectName === void 0) throw Error("The codependix gate executor must be run against a project, or given `projects` or `tags`.");
|
|
153
|
+
return {
|
|
154
|
+
projects: [e.projectName],
|
|
155
|
+
tags: n
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
async run(e) {
|
|
159
|
+
let t = this.buildCommandArguments({
|
|
160
|
+
...this.resolveSelection(e),
|
|
161
|
+
cliEntryPath: s(import.meta.url).resolve(S),
|
|
162
|
+
configurationPath: this.resolveConfigurationPath({
|
|
163
|
+
configurationPath: e.options.configurationPath,
|
|
164
|
+
workspaceRoot: e.workspaceRoot
|
|
165
|
+
}),
|
|
166
|
+
dependencies: e.options.dependencies !== !1,
|
|
167
|
+
loaderSpecifier: x,
|
|
168
|
+
workspaceRoot: e.workspaceRoot
|
|
169
|
+
});
|
|
170
|
+
return await this.spawnCommandLine({
|
|
171
|
+
argv: t,
|
|
172
|
+
workspaceRoot: e.workspaceRoot
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
w = __decorate([t(), __decorateMetadata("design:paramtypes", [y === void 0 ? Object : y])], w);
|
|
177
|
+
//#endregion
|
|
178
|
+
//#region packages/ic-suite/codependix/codependix-nx/src/modules/gate/gate.module.ts
|
|
179
|
+
var T = class GateModule {};
|
|
180
|
+
T = __decorate([n({
|
|
181
|
+
controllers: [],
|
|
182
|
+
exports: [w],
|
|
183
|
+
imports: [b],
|
|
184
|
+
providers: [w]
|
|
185
|
+
})], T);
|
|
186
|
+
//#endregion
|
|
187
|
+
//#region packages/ic-suite/codependix/codependix-nx/src/main.module.ts
|
|
188
|
+
var E = class MainModule {};
|
|
189
|
+
E = __decorate([n({
|
|
190
|
+
controllers: [],
|
|
191
|
+
exports: [T, b],
|
|
192
|
+
imports: [T, b],
|
|
193
|
+
providers: []
|
|
194
|
+
})], E);
|
|
195
|
+
//#endregion
|
|
196
|
+
//#region packages/ic-suite/codependix/codependix-nx/src/modules/plugin/plugin-context.utilities.ts
|
|
197
|
+
async function resolveGateService() {
|
|
198
|
+
return (await resolvePluginContext()).get(w);
|
|
199
|
+
}
|
|
200
|
+
async function resolvePluginService() {
|
|
201
|
+
return (await resolvePluginContext()).get(y);
|
|
202
|
+
}
|
|
203
|
+
async function resolvePluginContext() {
|
|
204
|
+
let t = globalThis;
|
|
205
|
+
return t[f] ??= e.createApplicationContext(E, {
|
|
206
|
+
abortOnError: !1,
|
|
207
|
+
logger: !1
|
|
208
|
+
}), await t[f];
|
|
209
|
+
}
|
|
210
|
+
//#endregion
|
|
211
|
+
export { w as a, g as c, l as d, v as f, T as i, p as l, __name as m, resolvePluginService as n, b as o, _ as p, E as r, y as s, resolveGateService as t, m as u };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { ExecutorContext } from '@nx/devkit';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Fails one project's task when a codependix boundary finding is charged to it.
|
|
5
|
+
*
|
|
6
|
+
* Inferred onto every project but the workspace root, so
|
|
7
|
+
* `nx affected -t codependix-gate` checks a branch's boundaries by the
|
|
8
|
+
* projects it changed, and the task that fails is named after the project
|
|
9
|
+
* whose boundary broke β which one workspace-wide check never could.
|
|
10
|
+
*
|
|
11
|
+
* The graphs are built over the project and everything it depends on, and
|
|
12
|
+
* only a finding charged to the project fails it: a broken boundary in a
|
|
13
|
+
* dependency is that dependency's gate's business, and is printed here as a
|
|
14
|
+
* note rather than a failure.
|
|
15
|
+
*/
|
|
16
|
+
declare function gateExecutor(options: GateExecutorOptions, context: ExecutorContext): Promise<{
|
|
17
|
+
success: boolean;
|
|
18
|
+
}>;
|
|
19
|
+
export default gateExecutor;
|
|
20
|
+
|
|
21
|
+
/** Options the gate executor accepts β see `schema.json` beside this. */
|
|
22
|
+
declare type GateExecutorOptions = GateOptions;
|
|
23
|
+
|
|
24
|
+
/** Options the gate executor accepts. */
|
|
25
|
+
declare interface GateOptions {
|
|
26
|
+
/** Workspace-relative configuration path; the registration's when omitted. */
|
|
27
|
+
readonly configurationPath?: string | undefined;
|
|
28
|
+
/** Build over the named projects' dependency closure. Defaults to true. */
|
|
29
|
+
readonly dependencies?: boolean | undefined;
|
|
30
|
+
/** Nx project names to judge, replacing the target's own project. */
|
|
31
|
+
readonly projects?: string[] | undefined;
|
|
32
|
+
/** Nx project tags to judge, selecting a project carrying any of them. */
|
|
33
|
+
readonly tags?: string[] | undefined;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export { }
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { t as e } from "../../../plugin-context.utilities-Bre57JBa.js";
|
|
2
|
+
//#region packages/ic-suite/codependix/codependix-nx/src/executors/gate/executor.ts
|
|
3
|
+
async function gateExecutor(t, n) {
|
|
4
|
+
return { success: await (await e()).run({
|
|
5
|
+
options: t,
|
|
6
|
+
projectName: n.projectName,
|
|
7
|
+
workspaceRoot: n.root
|
|
8
|
+
}) };
|
|
9
|
+
}
|
|
10
|
+
//#endregion
|
|
11
|
+
export { gateExecutor as default };
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import { CreateNodes } from '@nx/devkit';
|
|
2
|
+
|
|
3
|
+
/** Arguments for building the command line one gate runs. */
|
|
4
|
+
declare interface BuildCommandArguments extends GateSelection {
|
|
5
|
+
/** Filesystem path of the codependix command line's entry. */
|
|
6
|
+
readonly cliEntryPath: string;
|
|
7
|
+
readonly configurationPath: string;
|
|
8
|
+
readonly dependencies: boolean;
|
|
9
|
+
/** What `node --import` registers the TypeScript loader from. */
|
|
10
|
+
readonly loaderSpecifier: string;
|
|
11
|
+
readonly workspaceRoot: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** Name this plugin is registered under in a workspace's `nx.json`. */
|
|
15
|
+
export declare const CODEPENDIX_NX_PLUGIN_NAME = "@codependix/nx";
|
|
16
|
+
|
|
17
|
+
declare const codependixPlugin: {
|
|
18
|
+
createNodes: CreateNodes;
|
|
19
|
+
name: string;
|
|
20
|
+
};
|
|
21
|
+
export default codependixPlugin;
|
|
22
|
+
|
|
23
|
+
/** Options accepted from this plugin's `nx.json` registration. */
|
|
24
|
+
export declare interface CodependixPluginOptions {
|
|
25
|
+
/** Where the codependix configuration lives, workspace-root relative. */
|
|
26
|
+
readonly configurationPath: string;
|
|
27
|
+
/** Name of the inferred per-project gate target. */
|
|
28
|
+
readonly gateTargetName: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Name of the inferred per-project gate target, when the registration names
|
|
33
|
+
* none.
|
|
34
|
+
*
|
|
35
|
+
* Prefixed, unlike `@callidescope/nx`'s bare `gate`, because a workspace
|
|
36
|
+
* registering both plugins would otherwise infer two targets under one name,
|
|
37
|
+
* and Nx keeps whichever plugin it ran last without saying so.
|
|
38
|
+
*/
|
|
39
|
+
export declare const DEFAULT_GATE_TARGET_NAME = "codependix-gate";
|
|
40
|
+
|
|
41
|
+
/** Provides the run behind the gate executor. */
|
|
42
|
+
export declare class GateModule {
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Options the gate executor accepts. */
|
|
46
|
+
export declare interface GateOptions {
|
|
47
|
+
/** Workspace-relative configuration path; the registration's when omitted. */
|
|
48
|
+
readonly configurationPath?: string | undefined;
|
|
49
|
+
/** Build over the named projects' dependency closure. Defaults to true. */
|
|
50
|
+
readonly dependencies?: boolean | undefined;
|
|
51
|
+
/** Nx project names to judge, replacing the target's own project. */
|
|
52
|
+
readonly projects?: string[] | undefined;
|
|
53
|
+
/** Nx project tags to judge, selecting a project carrying any of them. */
|
|
54
|
+
readonly tags?: string[] | undefined;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** The projects one gate judges. */
|
|
58
|
+
export declare interface GateSelection {
|
|
59
|
+
readonly projects: string[];
|
|
60
|
+
readonly tags: string[];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Runs `codependix map --check boundaries` for the projects one gate judges.
|
|
65
|
+
*
|
|
66
|
+
* The command line runs as a child process rather than in this one, because
|
|
67
|
+
* its boundary check boots the workspace's NestJS containers by importing
|
|
68
|
+
* their TypeScript sources, and constructor injection there needs the
|
|
69
|
+
* decorator metadata the `@swc-node/register` loader emits. Nx loads this
|
|
70
|
+
* plugin under no such loader, so only a fresh `node --import` can provide it.
|
|
71
|
+
*/
|
|
72
|
+
export declare class GateService {
|
|
73
|
+
private readonly pluginService;
|
|
74
|
+
constructor(pluginService: PluginService);
|
|
75
|
+
/**
|
|
76
|
+
* Reads a list of names out of an executor's options.
|
|
77
|
+
*
|
|
78
|
+
* Entries are split on commas, trimmed, and the blanks dropped, so
|
|
79
|
+
* `--projects="a, b,"` names two projects rather than three β and the list
|
|
80
|
+
* reaches the command line joined by commas, where a blank would read as a
|
|
81
|
+
* project named nothing.
|
|
82
|
+
*/
|
|
83
|
+
private readNameList;
|
|
84
|
+
/**
|
|
85
|
+
* Reads the workspace's `nx.json`, or nothing when it cannot be read.
|
|
86
|
+
*
|
|
87
|
+
* Unreadable or malformed is not an error: the caller falls back to the
|
|
88
|
+
* conventional paths, which a workspace with no registration gets anyway.
|
|
89
|
+
*/
|
|
90
|
+
private readNxConfiguration;
|
|
91
|
+
/**
|
|
92
|
+
* Starts the command line and settles on whether it exited zero.
|
|
93
|
+
*
|
|
94
|
+
* Its output is forwarded as it arrives rather than collected, so a long
|
|
95
|
+
* container boot shows progress and a finding reaches the task log even
|
|
96
|
+
* when the run is interrupted. Killed by a signal counts as a failure: no
|
|
97
|
+
* verdict was reached, so none may be recorded as a pass.
|
|
98
|
+
*/
|
|
99
|
+
private spawnCommandLine;
|
|
100
|
+
/**
|
|
101
|
+
* Builds the `node` arguments one gate runs.
|
|
102
|
+
*
|
|
103
|
+
* `--projects` and `--tags` name what is judged; the command line builds
|
|
104
|
+
* over their dependency closure and fails only on a finding charged to one
|
|
105
|
+
* of them, which is what lets a dependency's broken boundary fail that
|
|
106
|
+
* dependency's own gate rather than every gate downstream of it.
|
|
107
|
+
*/
|
|
108
|
+
buildCommandArguments(args: BuildCommandArguments): string[];
|
|
109
|
+
/**
|
|
110
|
+
* Resolves the configuration path one gate runs with.
|
|
111
|
+
*
|
|
112
|
+
* A path the target was given wins. Otherwise the one this plugin was
|
|
113
|
+
* registered with is read back out of `nx.json`, and resolved exactly as
|
|
114
|
+
* inference resolved it β so the file a gate reads is always the file its
|
|
115
|
+
* cache inputs named.
|
|
116
|
+
*/
|
|
117
|
+
resolveConfigurationPath(args: {
|
|
118
|
+
configurationPath?: string | undefined;
|
|
119
|
+
workspaceRoot: string;
|
|
120
|
+
}): string;
|
|
121
|
+
/**
|
|
122
|
+
* Resolves which projects one gate judges.
|
|
123
|
+
*
|
|
124
|
+
* With neither `projects` nor `tags` given, it is the project the target
|
|
125
|
+
* belongs to. Throws rather than judging nothing, because Nx turns a thrown
|
|
126
|
+
* executor into a failed task with the message attached, and a gate that
|
|
127
|
+
* judged nothing has no verdict to record.
|
|
128
|
+
*/
|
|
129
|
+
resolveSelection(args: {
|
|
130
|
+
options: GateOptions;
|
|
131
|
+
projectName: string | undefined;
|
|
132
|
+
}): GateSelection;
|
|
133
|
+
/** Runs one gate, and settles on whether it passed. */
|
|
134
|
+
run(args: RunGateArguments): Promise<boolean>;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* One cache input of an inferred target: a file glob, or the npm packages an
|
|
139
|
+
* installed command line is versioned by.
|
|
140
|
+
*/
|
|
141
|
+
declare type InferredInput = string | {
|
|
142
|
+
externalDependencies: string[];
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
/** A target this plugin infers onto a project. */
|
|
146
|
+
declare interface InferredTarget {
|
|
147
|
+
readonly cache: boolean;
|
|
148
|
+
readonly executor: string;
|
|
149
|
+
/** Files whose change must invalidate the cached result. */
|
|
150
|
+
readonly inputs: InferredInput[];
|
|
151
|
+
readonly options: Record<string, unknown>;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/** One project's inferred targets, keyed by target name. */
|
|
155
|
+
declare type InferredTargets = Record<string, InferredTarget>;
|
|
156
|
+
|
|
157
|
+
/** Arguments for inferring targets across every project in a workspace. */
|
|
158
|
+
declare interface InferTargetsArguments {
|
|
159
|
+
/** Whatever the `nx.json` registration holds, unvalidated. */
|
|
160
|
+
readonly options: unknown;
|
|
161
|
+
/** Every file Nx matched, workspace-root relative. */
|
|
162
|
+
readonly projectConfigurationFiles: readonly string[];
|
|
163
|
+
/** The command line's own inputs, from `resolveToolInputs`. */
|
|
164
|
+
readonly toolInputs: readonly InferredInput[];
|
|
165
|
+
readonly workspaceRoot: string;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Root module of the plugin's application context.
|
|
170
|
+
*
|
|
171
|
+
* Built once per process and cached β the Nx daemon is long-lived, so paying
|
|
172
|
+
* for a NestJS context on every inference or executor invocation would make
|
|
173
|
+
* this plugin the slowest thing in the graph.
|
|
174
|
+
*/
|
|
175
|
+
export declare class MainModule {
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/** Provides target inference for the plugin's `createNodes`. */
|
|
179
|
+
export declare class PluginModule {
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Reads this plugin's registration and infers the gate from it.
|
|
184
|
+
*
|
|
185
|
+
* Nx calls plugins from module-level functions with no injection of their own,
|
|
186
|
+
* so the bare entry point in `index.ts` builds nothing itself β it resolves this
|
|
187
|
+
* service and hands it the arguments.
|
|
188
|
+
*
|
|
189
|
+
* Nx passes whatever the consumer wrote in `nx.json` with no validation, so
|
|
190
|
+
* every option is checked before use rather than cast. A bad value falls back
|
|
191
|
+
* to its default: a typo in a target name should not stop the project graph
|
|
192
|
+
* from being built.
|
|
193
|
+
*/
|
|
194
|
+
export declare class PluginService {
|
|
195
|
+
constructor();
|
|
196
|
+
/** Narrows an untrusted value to an array without widening it to `any`. */
|
|
197
|
+
private isUnknownArray;
|
|
198
|
+
/** Reads a non-empty string field from an untrusted record. */
|
|
199
|
+
private readString;
|
|
200
|
+
/**
|
|
201
|
+
* The project roots among the files Nx matched: each `project.json`'s
|
|
202
|
+
* directory, the workspace root excepted.
|
|
203
|
+
*/
|
|
204
|
+
private selectProjectRoots;
|
|
205
|
+
/** Copies an untrusted value into a record, or an empty one. */
|
|
206
|
+
private toRecord;
|
|
207
|
+
/**
|
|
208
|
+
* Builds the gate for every project Nx matched, keyed by project root.
|
|
209
|
+
*
|
|
210
|
+
* Every project gets one, the workspace root excepted. The gate builds over
|
|
211
|
+
* a project's dependency closure, so its inputs reach the dependencies'
|
|
212
|
+
* sources through `^default`; the workspace configuration holds the rules,
|
|
213
|
+
* so editing it invalidates every gate; the project's own configuration is
|
|
214
|
+
* the one file only this project's gate reads; and the command line's own
|
|
215
|
+
* code decides every verdict, through the `toolInputs` the caller resolved
|
|
216
|
+
* with `resolveToolInputs`. No `configurations` are
|
|
217
|
+
* declared, so an aggregator run with `--configuration=check` falls through
|
|
218
|
+
* to the defaults rather than failing for a configuration this target lacks.
|
|
219
|
+
*/
|
|
220
|
+
inferTargets(args: InferTargetsArguments): Map<string, InferredTargets>;
|
|
221
|
+
/**
|
|
222
|
+
* Finds this plugin's own entry in an `nx.json` and returns its options.
|
|
223
|
+
*
|
|
224
|
+
* Nx hands plugin options to `createNodes` and to nothing else, so the gate
|
|
225
|
+
* executor reads them back from the file the workspace registered them in β
|
|
226
|
+
* the only way a target inferred without options can honor the path the
|
|
227
|
+
* registration chose.
|
|
228
|
+
*/
|
|
229
|
+
readRegisteredOptions(nxConfiguration: unknown): unknown;
|
|
230
|
+
/**
|
|
231
|
+
* Resolves the effective plugin options from an untrusted value.
|
|
232
|
+
*
|
|
233
|
+
* A configuration path nobody named is searched for rather than assumed,
|
|
234
|
+
* because it becomes a cache input: an input naming a file that does not
|
|
235
|
+
* exist would leave every gate cached across an edit to the one that does.
|
|
236
|
+
*/
|
|
237
|
+
resolvePluginOptions(args: ResolvePluginOptionsArguments): CodependixPluginOptions;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/** Resolves the service behind the gate executor. */
|
|
241
|
+
export declare function resolveGateService(): Promise<GateService>;
|
|
242
|
+
|
|
243
|
+
/** Arguments for resolving the plugin options from an untrusted value. */
|
|
244
|
+
declare interface ResolvePluginOptionsArguments {
|
|
245
|
+
/** Whether a workspace-relative path exists, for the default search. */
|
|
246
|
+
readonly exists: (candidatePath: string) => boolean;
|
|
247
|
+
/** Whatever the `nx.json` registration holds, unvalidated. */
|
|
248
|
+
readonly options: unknown;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/** Resolves the service behind target inference. */
|
|
252
|
+
export declare function resolvePluginService(): Promise<PluginService>;
|
|
253
|
+
|
|
254
|
+
/** Arguments for one gate run. */
|
|
255
|
+
declare interface RunGateArguments {
|
|
256
|
+
readonly options: GateOptions;
|
|
257
|
+
/** The project the target belongs to, absent when run against none. */
|
|
258
|
+
readonly projectName: string | undefined;
|
|
259
|
+
readonly workspaceRoot: string;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
export { }
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { a as e, c as t, d as n, f as r, i, l as a, n as o, o as s, p as c, r as l, s as u, t as d, u as f } from "../plugin-context.utilities-Bre57JBa.js";
|
|
2
|
+
import { readFileSync as p, realpathSync as m } from "node:fs";
|
|
3
|
+
import h from "node:path";
|
|
4
|
+
import { createRequire as g } from "node:module";
|
|
5
|
+
//#region packages/ic-suite/codependix/codependix-nx/src/modules/plugin/plugin-inputs.utilities.ts
|
|
6
|
+
function resolveToolInputs(e) {
|
|
7
|
+
try {
|
|
8
|
+
let t = locateCommandLine();
|
|
9
|
+
return toWorkspacePath({
|
|
10
|
+
directory: t,
|
|
11
|
+
workspaceRoot: e
|
|
12
|
+
}) === void 0 ? resolveExternalInputs(t) : resolveWorkspaceInputs({
|
|
13
|
+
cliDirectory: t,
|
|
14
|
+
workspaceRoot: e
|
|
15
|
+
});
|
|
16
|
+
} catch {
|
|
17
|
+
return [];
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function collectWorkspacePackages(e) {
|
|
21
|
+
e.visited.add(e.packageDirectory);
|
|
22
|
+
let t = readDependencies(e.packageDirectory).filter(([, e]) => String(e).startsWith(c)).map(([t]) => locateDependency({
|
|
23
|
+
fromDirectory: e.packageDirectory,
|
|
24
|
+
name: t
|
|
25
|
+
})).filter((t) => !e.visited.has(t));
|
|
26
|
+
for (let n of t) collectWorkspacePackages({
|
|
27
|
+
packageDirectory: n,
|
|
28
|
+
visited: e.visited
|
|
29
|
+
});
|
|
30
|
+
return e.visited;
|
|
31
|
+
}
|
|
32
|
+
function locateCommandLine() {
|
|
33
|
+
return h.dirname(m(g(import.meta.url).resolve(`${t}/package.json`)));
|
|
34
|
+
}
|
|
35
|
+
function locateDependency(e) {
|
|
36
|
+
return h.dirname(m(g(h.join(e.fromDirectory, "package.json")).resolve(`${e.name}/package.json`)));
|
|
37
|
+
}
|
|
38
|
+
function readDependencies(e) {
|
|
39
|
+
let t = toRecord(JSON.parse(p(h.join(e, "package.json"), "utf8")));
|
|
40
|
+
return [...Object.entries(toRecord(t.dependencies)), ...Object.entries(toRecord(t.devDependencies))];
|
|
41
|
+
}
|
|
42
|
+
function resolveExternalInputs(e) {
|
|
43
|
+
let n = readDependencies(e).map(([e]) => e).filter((e) => e.startsWith("@codependix/"));
|
|
44
|
+
return [{ externalDependencies: [t, ...n].toSorted() }];
|
|
45
|
+
}
|
|
46
|
+
function resolveWorkspaceInputs(e) {
|
|
47
|
+
let t = m(e.workspaceRoot);
|
|
48
|
+
return [...collectWorkspacePackages({
|
|
49
|
+
packageDirectory: e.cliDirectory,
|
|
50
|
+
visited: /* @__PURE__ */ new Set()
|
|
51
|
+
})].flatMap((e) => r.map((n) => `{workspaceRoot}/${h.relative(t, e)}/${n}`)).toSorted();
|
|
52
|
+
}
|
|
53
|
+
function toRecord(e) {
|
|
54
|
+
return typeof e == "object" && e ? { ...e } : {};
|
|
55
|
+
}
|
|
56
|
+
function toWorkspacePath(e) {
|
|
57
|
+
let t = h.relative(m(e.workspaceRoot), e.directory);
|
|
58
|
+
return t.startsWith("..") || h.isAbsolute(t) || t.split(h.sep).includes("node_modules") ? void 0 : t;
|
|
59
|
+
}
|
|
60
|
+
//#endregion
|
|
61
|
+
//#region packages/ic-suite/codependix/codependix-nx/src/index.ts
|
|
62
|
+
var _ = {
|
|
63
|
+
createNodes: [n, async (e, t, n) => {
|
|
64
|
+
let r = (await o()).inferTargets({
|
|
65
|
+
options: t,
|
|
66
|
+
projectConfigurationFiles: e,
|
|
67
|
+
toolInputs: resolveToolInputs(n.workspaceRoot),
|
|
68
|
+
workspaceRoot: n.workspaceRoot
|
|
69
|
+
});
|
|
70
|
+
return e.map((e) => {
|
|
71
|
+
let t = h.dirname(e), n = r.get(t);
|
|
72
|
+
return [e, n === void 0 ? {} : { projects: { [t]: { targets: n } } }];
|
|
73
|
+
}).filter(([, e]) => Object.keys(e).length > 0);
|
|
74
|
+
}],
|
|
75
|
+
name: "@codependix/nx"
|
|
76
|
+
};
|
|
77
|
+
//#endregion
|
|
78
|
+
export { a as CODEPENDIX_NX_PLUGIN_NAME, f as DEFAULT_GATE_TARGET_NAME, i as GateModule, e as GateService, l as MainModule, s as PluginModule, u as PluginService, _ as default, d as resolveGateService, o as resolvePluginService };
|
package/executors.json
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../../../../node_modules/nx/schemas/executors.json",
|
|
3
|
+
"executors": {
|
|
4
|
+
"gate": {
|
|
5
|
+
"description": "Fail a project whose dependency graphs break a codependix boundary rule charged to it, built over the project and its Nx dependencies.",
|
|
6
|
+
"implementation": "./src/executors/gate/executor",
|
|
7
|
+
"schema": "./src/executors/gate/schema.json"
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,74 @@
|
|
|
1
1
|
{
|
|
2
|
+
"author": "Jimmy Paolini",
|
|
3
|
+
"bugs": {
|
|
4
|
+
"url": "https://github.com/organizzolini/codebase/issues"
|
|
5
|
+
},
|
|
6
|
+
"dependencies": {
|
|
7
|
+
"@codependix/cli": "0.0.16",
|
|
8
|
+
"@nestjs/common": "^11.1.21 || ^12.0.1",
|
|
9
|
+
"@nestjs/core": "^11.1.21 || ^12.0.1",
|
|
10
|
+
"@nx/devkit": "^23.0.0",
|
|
11
|
+
"@swc-node/register": "^1.11.1",
|
|
12
|
+
"@swc/core": "^1.15.40",
|
|
13
|
+
"reflect-metadata": "^0.2.2"
|
|
14
|
+
},
|
|
15
|
+
"description": "Nx plugin inferring a per-project codependix boundary gate, judged over each project's Nx dependency closure",
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@golevelup/ts-vitest": "^4.0.0",
|
|
18
|
+
"@nestjs/testing": "^12.0.1",
|
|
19
|
+
"@nx/eslint-plugin": "^23.0.0",
|
|
20
|
+
"@swc/helpers": "^0.5.21",
|
|
21
|
+
"@types/node": "^26.5.1",
|
|
22
|
+
"@vitest/coverage-v8": "^5.0.0",
|
|
23
|
+
"typescript": "^6.0.3",
|
|
24
|
+
"vitest": "^5.0.0"
|
|
25
|
+
},
|
|
26
|
+
"executors": "./executors.json",
|
|
27
|
+
"exports": {
|
|
28
|
+
".": {
|
|
29
|
+
"types": "./dist/src/index.d.ts",
|
|
30
|
+
"default": "./dist/src/index.js"
|
|
31
|
+
},
|
|
32
|
+
"./executors.json": "./executors.json",
|
|
33
|
+
"./package.json": "./package.json",
|
|
34
|
+
"./src/executors/*": "./dist/src/executors/*.js"
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"CHANGELOG.md",
|
|
38
|
+
"dist",
|
|
39
|
+
"executors.json",
|
|
40
|
+
"LICENSE",
|
|
41
|
+
"README.md"
|
|
42
|
+
],
|
|
43
|
+
"homepage": "https://github.com/organizzolini/codebase/tree/main/packages/ic-suite/codependix/codependix-nx#readme",
|
|
44
|
+
"keywords": [
|
|
45
|
+
"architecture-linter",
|
|
46
|
+
"boundaries",
|
|
47
|
+
"codependix",
|
|
48
|
+
"dependency-graph",
|
|
49
|
+
"nx",
|
|
50
|
+
"nx-plugin"
|
|
51
|
+
],
|
|
52
|
+
"license": "MIT",
|
|
53
|
+
"main": "./dist/src/index.js",
|
|
2
54
|
"name": "@codependix/nx",
|
|
3
|
-
"
|
|
4
|
-
|
|
5
|
-
|
|
55
|
+
"nx": {
|
|
56
|
+
"executors": "./executors.json"
|
|
57
|
+
},
|
|
58
|
+
"publishConfig": {
|
|
59
|
+
"access": "public",
|
|
60
|
+
"registry": "https://registry.npmjs.org"
|
|
61
|
+
},
|
|
62
|
+
"repository": {
|
|
63
|
+
"directory": "packages/ic-suite/codependix/codependix-nx",
|
|
64
|
+
"type": "git",
|
|
65
|
+
"url": "git+https://github.com/organizzolini/codebase.git"
|
|
66
|
+
},
|
|
67
|
+
"type": "module",
|
|
68
|
+
"typeCoverage": {
|
|
69
|
+
"atLeast": 100,
|
|
70
|
+
"strict": true
|
|
71
|
+
},
|
|
72
|
+
"types": "./dist/src/index.d.ts",
|
|
73
|
+
"version": "0.0.1"
|
|
6
74
|
}
|