@rsdk/depdoc.cli 6.0.0-next.42 → 6.0.0-next.44
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/DEPDOC_MODEL.md +22 -11
- package/__tests__/compatibility.test.ts +74 -15
- package/__tests__/config-validation.test.ts +46 -1
- package/__tests__/engine.test.ts +162 -2
- package/__tests__/fixtures/imports/config/aliases.json +8 -0
- package/__tests__/fixtures/imports/plain-root-file.ts +3 -0
- package/__tests__/fixtures/imports/sidebars.ts +5 -0
- package/__tests__/fixtures/imports/src/aliases.ts +4 -0
- package/__tests__/fixtures/imports/src/virtual.ts +3 -0
- package/__tests__/fixtures/imports/tsconfig.build.json +3 -0
- package/__tests__/fixtures/imports/tsconfig.json +8 -0
- package/__tests__/fixtures/imports/vite.config.ts +3 -0
- package/__tests__/imports.test.ts +72 -0
- package/dist/collectors/tsconfig-aliases.d.ts +1 -0
- package/dist/collectors/tsconfig-aliases.js +40 -0
- package/dist/collectors/tsconfig-aliases.js.map +1 -0
- package/dist/collectors/workspaces.d.ts +2 -2
- package/dist/collectors/workspaces.js +21 -6
- package/dist/collectors/workspaces.js.map +1 -1
- package/dist/lib/imports.d.ts +9 -4
- package/dist/lib/imports.js +62 -9
- package/dist/lib/imports.js.map +1 -1
- package/dist/model/config-validation.d.ts +2 -0
- package/dist/model/config-validation.js +44 -1
- package/dist/model/config-validation.js.map +1 -1
- package/dist/model/diagnostics.d.ts +1 -0
- package/dist/model/diagnostics.js +67 -0
- package/dist/model/diagnostics.js.map +1 -1
- package/dist/model/engine.js +1 -0
- package/dist/model/engine.js.map +1 -1
- package/dist/model/placement.js +12 -1
- package/dist/model/placement.js.map +1 -1
- package/dist/model/types.d.ts +8 -1
- package/dist/model/types.js.map +1 -1
- package/dist/runner.js +1 -1
- package/dist/runner.js.map +1 -1
- package/package.json +2 -2
- package/src/collectors/tsconfig-aliases.ts +45 -0
- package/src/collectors/workspaces.ts +50 -7
- package/src/lib/imports.ts +114 -8
- package/src/model/config-validation.ts +62 -3
- package/src/model/diagnostics.ts +105 -1
- package/src/model/engine.ts +7 -1
- package/src/model/placement.ts +19 -1
- package/src/model/types.ts +16 -0
- package/src/runner.ts +6 -1
package/DEPDOC_MODEL.md
CHANGED
|
@@ -19,6 +19,7 @@ autofixable.
|
|
|
19
19
|
| Public type surface | Imports that appear in emitted `dist/**/*.d.ts`. |
|
|
20
20
|
| Private dev surface | Test, build, lint, type-only, and tooling usage that does not reach runtime or public `.d.ts`. |
|
|
21
21
|
| Mirror | A `library` package has the same dependency name and range in both `peerDependencies` and `devDependencies`. |
|
|
22
|
+
| Ignored import | A module specifier that appears in source but is provided virtually or resolved as an internal alias, so it is not a package dependency. |
|
|
22
23
|
|
|
23
24
|
## Invariants
|
|
24
25
|
|
|
@@ -86,6 +87,7 @@ autofixable.
|
|
|
86
87
|
| V3 | The constraints config does not describe the whole model. | It contains versions, overrides, root-only rules, manual required dependencies, and workspace-specific exceptions. |
|
|
87
88
|
| V4 | The last matching rule wins. | Enables broad rules plus specific overrides. |
|
|
88
89
|
| V5 | `rootOnly` means the dependency belongs only to the root dev environment. | Workspace declarations and source usage are forbidden unless a more specific override exists. `required` + `rootOnly` means required for the selected workspace but physically owned by root `devDependencies`. |
|
|
90
|
+
| V6 | Concrete dependency rules must describe packages that exist in the repo model. | Wildcard policy rules are allowed, but concrete stale `depdoc.yml` entries are reported. |
|
|
89
91
|
|
|
90
92
|
## Placement Formula
|
|
91
93
|
|
|
@@ -114,8 +116,9 @@ guess something that an earlier phase can derive.
|
|
|
114
116
|
1. Read root `package.json`.
|
|
115
117
|
2. Read every workspace `package.json`.
|
|
116
118
|
3. Build the set of local workspace package names.
|
|
117
|
-
4. Read dependency rules: version rules, section
|
|
118
|
-
manual `required` dependencies, and
|
|
119
|
+
4. Read ignored import patterns and dependency rules: version rules, section
|
|
120
|
+
overrides, `rootOnly` rules, manual `required` dependencies, and
|
|
121
|
+
workspace-specific exceptions.
|
|
119
122
|
5. Read package manager metadata overrides, such as `packageExtensions`.
|
|
120
123
|
|
|
121
124
|
### Phase 2. Validate Basic Shape
|
|
@@ -136,16 +139,21 @@ guess something that an earlier phase can derive.
|
|
|
136
139
|
1. Scan source imports for every workspace from `src/`, `test/`, `tests/`,
|
|
137
140
|
`__tests__/`, concrete package entry-points, and relative imports reachable
|
|
138
141
|
from those entry-points.
|
|
139
|
-
2.
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
142
|
+
2. Ignore module specifiers from `ignoredImports` and every `compilerOptions.paths`
|
|
143
|
+
alias collected from root-level `tsconfig*.json` files in the workspace.
|
|
144
|
+
For example, `@docusaurus/router` can be ignored as a virtual Docusaurus
|
|
145
|
+
runtime module, and `~app/*` / `~shared/*` are ignored when declared as
|
|
146
|
+
TypeScript path aliases.
|
|
147
|
+
3. Classify each import as local or external.
|
|
148
|
+
4. Classify each import as runtime, type-only, test-only, or tooling-only.
|
|
149
|
+
5. Scan emitted `dist/**/*.d.ts` imports when `dist/` exists.
|
|
150
|
+
6. In `--with-dts` mode, require `dist/` for workspaces with `src/`; without
|
|
143
151
|
`--with-dts`, missing `dist/` is allowed so local source-only checks remain
|
|
144
152
|
usable before build.
|
|
145
|
-
|
|
146
|
-
|
|
153
|
+
7. Mark all dependencies found in emitted `.d.ts` as public type surface.
|
|
154
|
+
8. Skip generated entry-point roots such as `dist/`, `build/`, `coverage/`, and
|
|
147
155
|
`node_modules/`.
|
|
148
|
-
|
|
156
|
+
9. Warn when a workspace has scanned source files and declared dependencies,
|
|
149
157
|
but zero collected source or `.d.ts` package usage.
|
|
150
158
|
|
|
151
159
|
### Phase 4. Derive Required Public/Runtime Deps
|
|
@@ -214,8 +222,11 @@ For each manifest:
|
|
|
214
222
|
3. Report dependencies with the wrong version range.
|
|
215
223
|
4. Report forbidden dependencies.
|
|
216
224
|
5. Report stale dependencies that are not required by the derived graph.
|
|
217
|
-
6. Report
|
|
218
|
-
|
|
225
|
+
6. Report stale concrete dependency rules from `depdoc.yml` when no matching
|
|
226
|
+
source usage, `.d.ts` usage, manifest declaration, or expected dependency
|
|
227
|
+
exists in the matching workspace scope.
|
|
228
|
+
7. Report missing or incorrect library peer/dev mirrors.
|
|
229
|
+
8. Report root-only violations.
|
|
219
230
|
|
|
220
231
|
### Phase 9. Autofix
|
|
221
232
|
|
|
@@ -4,8 +4,8 @@ import { tmpdir } from 'node:os';
|
|
|
4
4
|
import { resolve } from 'node:path';
|
|
5
5
|
|
|
6
6
|
// Paths relative to this test file:
|
|
7
|
-
// __tests__/ -> depdoc/ -> packages/ -> monorepo root
|
|
8
|
-
const MONOREPO_ROOT = resolve(__dirname, '
|
|
7
|
+
// __tests__/ -> depdoc/ -> dx/ -> packages/ -> monorepo root
|
|
8
|
+
const MONOREPO_ROOT = resolve(__dirname, '../../../..');
|
|
9
9
|
const YARN_BIN = resolve(MONOREPO_ROOT, '.yarn/releases/yarn-4.5.3.cjs');
|
|
10
10
|
const YARN_CACHE = resolve(MONOREPO_ROOT, '.yarn/cache');
|
|
11
11
|
// Reuse the main project's tsc instead of installing typescript in each temp monorepo.
|
|
@@ -136,13 +136,20 @@ describe('compatibility: yarn-install-clean', () => {
|
|
|
136
136
|
const { dir, cleanup: c } = createMonorepo(
|
|
137
137
|
{ private: true, name: '@compat/root' },
|
|
138
138
|
[
|
|
139
|
+
{
|
|
140
|
+
location: 'packages/lodash',
|
|
141
|
+
manifest: {
|
|
142
|
+
name: 'lodash',
|
|
143
|
+
version: '4.17.21',
|
|
144
|
+
},
|
|
145
|
+
},
|
|
139
146
|
{
|
|
140
147
|
location: 'packages/lib',
|
|
141
148
|
manifest: {
|
|
142
149
|
name: '@compat/lib',
|
|
143
150
|
version: '1.0.0',
|
|
144
|
-
peerDependencies: { lodash: '
|
|
145
|
-
devDependencies: { lodash: '
|
|
151
|
+
peerDependencies: { lodash: '*' },
|
|
152
|
+
devDependencies: { lodash: '*' },
|
|
146
153
|
},
|
|
147
154
|
},
|
|
148
155
|
{
|
|
@@ -152,7 +159,7 @@ describe('compatibility: yarn-install-clean', () => {
|
|
|
152
159
|
version: '1.0.0',
|
|
153
160
|
dependencies: {
|
|
154
161
|
'@compat/lib': 'workspace:*',
|
|
155
|
-
lodash: '
|
|
162
|
+
lodash: '*',
|
|
156
163
|
},
|
|
157
164
|
},
|
|
158
165
|
},
|
|
@@ -175,7 +182,7 @@ describe('compatibility: yarn-install-clean', () => {
|
|
|
175
182
|
});
|
|
176
183
|
|
|
177
184
|
// ---------------------------------------------------------------------------
|
|
178
|
-
// yarn-peer-requirements-clean: required
|
|
185
|
+
// yarn-peer-requirements-clean: required peers propagated to service
|
|
179
186
|
// ---------------------------------------------------------------------------
|
|
180
187
|
|
|
181
188
|
describe('compatibility: yarn-peer-requirements-clean', () => {
|
|
@@ -184,20 +191,45 @@ describe('compatibility: yarn-peer-requirements-clean', () => {
|
|
|
184
191
|
let cleanup: () => void;
|
|
185
192
|
|
|
186
193
|
beforeAll(() => {
|
|
187
|
-
// @
|
|
188
|
-
//
|
|
194
|
+
// @compat/framework requires rxjs and reflect-metadata. The model should
|
|
195
|
+
// propagate both into service dependencies (invariant P2 + S1).
|
|
189
196
|
const { dir, cleanup: c } = createMonorepo(
|
|
190
197
|
{ private: true, name: '@compat/root' },
|
|
191
198
|
[
|
|
199
|
+
{
|
|
200
|
+
location: 'packages/framework',
|
|
201
|
+
manifest: {
|
|
202
|
+
name: '@compat/framework',
|
|
203
|
+
version: '1.0.0',
|
|
204
|
+
peerDependencies: {
|
|
205
|
+
rxjs: '*',
|
|
206
|
+
'reflect-metadata': '*',
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
location: 'packages/rxjs',
|
|
212
|
+
manifest: {
|
|
213
|
+
name: 'rxjs',
|
|
214
|
+
version: '7.8.2',
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
location: 'packages/reflect-metadata',
|
|
219
|
+
manifest: {
|
|
220
|
+
name: 'reflect-metadata',
|
|
221
|
+
version: '0.2.2',
|
|
222
|
+
},
|
|
223
|
+
},
|
|
192
224
|
{
|
|
193
225
|
location: 'packages/svc',
|
|
194
226
|
manifest: {
|
|
195
227
|
name: '@compat/svc',
|
|
196
228
|
version: '1.0.0',
|
|
197
229
|
dependencies: {
|
|
198
|
-
'@
|
|
199
|
-
rxjs: '
|
|
200
|
-
'reflect-metadata': '
|
|
230
|
+
'@compat/framework': 'workspace:*',
|
|
231
|
+
rxjs: '*',
|
|
232
|
+
'reflect-metadata': '*',
|
|
201
233
|
},
|
|
202
234
|
},
|
|
203
235
|
},
|
|
@@ -233,12 +265,23 @@ describe('compatibility: missing-peer-detected (negative)', () => {
|
|
|
233
265
|
const { dir, cleanup: c } = createMonorepo(
|
|
234
266
|
{ private: true, name: '@compat/root' },
|
|
235
267
|
[
|
|
268
|
+
{
|
|
269
|
+
location: 'packages/framework',
|
|
270
|
+
manifest: {
|
|
271
|
+
name: '@compat/framework',
|
|
272
|
+
version: '1.0.0',
|
|
273
|
+
peerDependencies: {
|
|
274
|
+
rxjs: '*',
|
|
275
|
+
'reflect-metadata': '*',
|
|
276
|
+
},
|
|
277
|
+
},
|
|
278
|
+
},
|
|
236
279
|
{
|
|
237
280
|
location: 'packages/svc',
|
|
238
281
|
manifest: {
|
|
239
282
|
name: '@compat/svc',
|
|
240
283
|
version: '1.0.0',
|
|
241
|
-
dependencies: { '@
|
|
284
|
+
dependencies: { '@compat/framework': 'workspace:*' },
|
|
242
285
|
},
|
|
243
286
|
},
|
|
244
287
|
],
|
|
@@ -268,19 +311,35 @@ describe('compatibility: tsc-library-build', () => {
|
|
|
268
311
|
let cleanup: () => void;
|
|
269
312
|
|
|
270
313
|
beforeAll(() => {
|
|
271
|
-
// Library imports rxjs (
|
|
314
|
+
// Library imports rxjs (provided by a local workspace with types). After install the
|
|
272
315
|
// dev mirror (devDependencies = peerDependencies) makes rxjs available for
|
|
273
316
|
// tsc without any additional @types packages.
|
|
274
317
|
const { dir, cleanup: c } = createMonorepo(
|
|
275
318
|
{ private: true, name: '@compat/root' },
|
|
276
319
|
[
|
|
320
|
+
{
|
|
321
|
+
location: 'packages/rxjs',
|
|
322
|
+
manifest: {
|
|
323
|
+
name: 'rxjs',
|
|
324
|
+
version: '7.8.2',
|
|
325
|
+
types: 'index.d.ts',
|
|
326
|
+
},
|
|
327
|
+
files: {
|
|
328
|
+
'index.d.ts': [
|
|
329
|
+
'export declare class Observable<T> {',
|
|
330
|
+
' readonly value?: T;',
|
|
331
|
+
'}',
|
|
332
|
+
'',
|
|
333
|
+
].join('\n'),
|
|
334
|
+
},
|
|
335
|
+
},
|
|
277
336
|
{
|
|
278
337
|
location: 'packages/lib',
|
|
279
338
|
manifest: {
|
|
280
339
|
name: '@compat/lib',
|
|
281
340
|
version: '1.0.0',
|
|
282
|
-
peerDependencies: { rxjs: '
|
|
283
|
-
devDependencies: { rxjs: '
|
|
341
|
+
peerDependencies: { rxjs: '*' },
|
|
342
|
+
devDependencies: { rxjs: '*' },
|
|
284
343
|
},
|
|
285
344
|
files: {
|
|
286
345
|
'src/index.ts': [
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
validateDependencyRules,
|
|
3
|
+
validateIgnoredImports,
|
|
4
|
+
validateToolingFiles,
|
|
5
|
+
} from '../src/model/config-validation';
|
|
2
6
|
|
|
3
7
|
describe('validateDependencyRules', () => {
|
|
4
8
|
it('rejects required wildcard rules because they cannot expand to concrete deps', () => {
|
|
@@ -40,3 +44,44 @@ describe('validateDependencyRules', () => {
|
|
|
40
44
|
]);
|
|
41
45
|
});
|
|
42
46
|
});
|
|
47
|
+
|
|
48
|
+
describe('validateIgnoredImports', () => {
|
|
49
|
+
it('allows string module specifier patterns', () => {
|
|
50
|
+
expect(validateIgnoredImports(['@docusaurus/router'])).toEqual([]);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('rejects non-string items', () => {
|
|
54
|
+
expect(validateIgnoredImports([42])).toEqual([
|
|
55
|
+
expect.stringContaining('ignoredImports[0] must be a string'),
|
|
56
|
+
]);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
describe('validateToolingFiles', () => {
|
|
61
|
+
it('allows a global rule with no workspace scoping', () => {
|
|
62
|
+
expect(validateToolingFiles([{ match: 'sidebars.ts' }])).toEqual([]);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('allows a workspace-scoped rule with an array of matches', () => {
|
|
66
|
+
expect(
|
|
67
|
+
validateToolingFiles([
|
|
68
|
+
{
|
|
69
|
+
match: ['sidebars.ts', 'sidebars.js'],
|
|
70
|
+
workspace: 'niisokb.artifactory.docusaurus',
|
|
71
|
+
},
|
|
72
|
+
]),
|
|
73
|
+
).toEqual([]);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('rejects entries missing match', () => {
|
|
77
|
+
expect(validateToolingFiles([{ workspace: 'foo' }])).toEqual([
|
|
78
|
+
expect.stringContaining('toolingFiles[0].match must be a string'),
|
|
79
|
+
]);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('rejects a non-array value', () => {
|
|
83
|
+
expect(validateToolingFiles('sidebars.ts')).toEqual([
|
|
84
|
+
expect.stringContaining('toolingFiles must be an array'),
|
|
85
|
+
]);
|
|
86
|
+
});
|
|
87
|
+
});
|