dependency-cruiser 18.2.0 → 18.3.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/README.md +6 -6
- package/bin/depcruise-baseline.mjs +12 -5
- package/bin/{dependency-cruise.mjs → dependency-cruiser.mjs} +24 -14
- package/package.json +7 -7
- package/src/analyze/analyze-modules.mjs +5 -1
- package/src/analyze/index.mjs +1 -1
- package/src/analyze/soften-known-violations.mjs +4 -2
- package/src/analyze/summarize/summarize-options.mjs +2 -0
- package/src/cache/options-compatible.mjs +1 -0
- package/src/cli/index.mjs +11 -3
- package/src/cli/init-config/config-template.mjs +1 -1
- package/src/cli/init-config/write-run-scripts-to-manifest.mjs +7 -7
- package/src/cli/normalize-cli-options.mjs +63 -2
- package/src/extract/helpers.mjs +1 -0
- package/src/extract/swc/dependency-visitor.mjs +18 -3
- package/src/extract/swc/parse.mjs +14 -4
- package/src/extract/transpile/try-import-available.mjs +1 -1
- package/src/graph-utl/compare.mjs +113 -14
- package/src/main/options/normalize.mjs +9 -3
- package/src/main/report-wrap.mjs +4 -2
- package/src/meta.cjs +1 -1
- package/src/report/baseline.mjs +52 -10
- package/src/report/dot-webpage/dot-module.mjs +1 -1
- package/src/report/index.mjs +1 -0
- package/src/schema/configuration.validate.mjs +1 -1
- package/src/schema/cruise-result.validate.mjs +1 -1
- package/src/utl/try-import.mjs +1 -1
- package/types/dependency-cruiser.d.mts +6 -0
- package/types/options.d.mts +17 -1
- package/types/restrictions.d.mts +2 -2
- package/types/shared-types.d.mts +16 -13
package/README.md
CHANGED
|
@@ -30,7 +30,7 @@ pnpm add -D dependency-cruiser
|
|
|
30
30
|
### ... and generate a config
|
|
31
31
|
|
|
32
32
|
```shell
|
|
33
|
-
npx
|
|
33
|
+
npx dependency-cruiser --init
|
|
34
34
|
```
|
|
35
35
|
|
|
36
36
|
This will look around in your environment a bit, ask you some questions and create
|
|
@@ -56,7 +56,7 @@ cruiser with output type `dot` and run _GraphViz dot_[^3] on the result. In
|
|
|
56
56
|
a one liner:
|
|
57
57
|
|
|
58
58
|
```shell
|
|
59
|
-
npx
|
|
59
|
+
npx dependency-cruiser src --include-only "^src" --output-type dot | dot -T svg > dependency-graph.svg
|
|
60
60
|
```
|
|
61
61
|
|
|
62
62
|
> <details>
|
|
@@ -67,7 +67,7 @@ npx depcruise src --include-only "^src" --output-type dot | dot -T svg > depende
|
|
|
67
67
|
> configuration file:
|
|
68
68
|
>
|
|
69
69
|
> ```shell
|
|
70
|
-
> npx
|
|
70
|
+
> npx dependency-cruiser src --include-only "^src" --config --output-type dot | dot -T svg > dependency-graph.svg
|
|
71
71
|
> ```
|
|
72
72
|
|
|
73
73
|
</details>
|
|
@@ -90,7 +90,7 @@ npx depcruise src --include-only "^src" --output-type dot | dot -T svg > depende
|
|
|
90
90
|
|
|
91
91
|
#### Declare some rules
|
|
92
92
|
|
|
93
|
-
When you ran `
|
|
93
|
+
When you ran `dependency-cruiser --init` above, the command also added some rules
|
|
94
94
|
to `.dependency-cruiser.js` that make sense in most projects, like detecting
|
|
95
95
|
**circular dependencies**, dependencies **missing** in package.json, **orphans**,
|
|
96
96
|
and production code relying on dev- or optionalDependencies.
|
|
@@ -120,7 +120,7 @@ Sample rule:
|
|
|
120
120
|
#### Report them
|
|
121
121
|
|
|
122
122
|
```sh
|
|
123
|
-
npx
|
|
123
|
+
npx dependency-cruiser src
|
|
124
124
|
```
|
|
125
125
|
|
|
126
126
|
> <details>
|
|
@@ -131,7 +131,7 @@ npx depcruise src
|
|
|
131
131
|
> configuration file:
|
|
132
132
|
>
|
|
133
133
|
> ```shell
|
|
134
|
-
> npx
|
|
134
|
+
> npx dependency-cruiser --config .dependency-cruiser.js src
|
|
135
135
|
> ```
|
|
136
136
|
|
|
137
137
|
</details>
|
|
@@ -10,14 +10,17 @@ function showHelp() {
|
|
|
10
10
|
.write(`Usage: depcruise-baseline [options] <files-or-directories...>
|
|
11
11
|
|
|
12
12
|
Writes all known violations of rules in a .dependency-cruiser.js to a file.
|
|
13
|
-
Alias for
|
|
14
|
-
Details: https://github.com/sverweij/dependency-cruiser
|
|
13
|
+
Alias for dependency-cruiser --baseline
|
|
15
14
|
|
|
16
15
|
Options:
|
|
17
16
|
-c, --config [file] read rules and options from [file] (default: true)
|
|
18
17
|
-f, --output-to [file] file to write output to; - for stdout (default: ".dependency-cruiser-known-violations.json")
|
|
19
18
|
-V, --version display version number
|
|
20
19
|
-h, --help display help for command
|
|
20
|
+
|
|
21
|
+
‼ Deprecated. Use dependency-cruiser --baseline instead.
|
|
22
|
+
‼ See https://github.com/sverweij/dependency-cruiser/blob/main/doc/cli.md#--baseline-create-or-update-a-known-violations-baseline
|
|
23
|
+
|
|
21
24
|
`);
|
|
22
25
|
}
|
|
23
26
|
|
|
@@ -36,6 +39,10 @@ try {
|
|
|
36
39
|
short: "f",
|
|
37
40
|
default: ".dependency-cruiser-known-violations.json",
|
|
38
41
|
},
|
|
42
|
+
progress: {
|
|
43
|
+
type: "string",
|
|
44
|
+
default: "none",
|
|
45
|
+
},
|
|
39
46
|
version: {
|
|
40
47
|
type: "boolean",
|
|
41
48
|
short: "V",
|
|
@@ -56,11 +63,11 @@ try {
|
|
|
56
63
|
if (options.config === "") {
|
|
57
64
|
options.config = true;
|
|
58
65
|
}
|
|
66
|
+
|
|
59
67
|
process.exitCode = await cli(positionals, {
|
|
60
68
|
config: options.config,
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
outputType: "baseline",
|
|
69
|
+
baseline: options["output-to"],
|
|
70
|
+
progress: options["progress"],
|
|
64
71
|
});
|
|
65
72
|
}
|
|
66
73
|
} catch (pError) {
|
|
@@ -72,10 +72,11 @@ try {
|
|
|
72
72
|
"include modules matching the regex, but don't follow their dependencies",
|
|
73
73
|
)
|
|
74
74
|
.option(
|
|
75
|
-
"
|
|
76
|
-
"
|
|
75
|
+
"-S, --collapse <regex>",
|
|
76
|
+
"collapse a to a folder depth by passing a single digit (e.g. 2). When passed a " +
|
|
77
|
+
'regex collapses to that pattern. E.g. "^packages/[^/]+/" would collapse to ' +
|
|
78
|
+
`modules/ folders directly under your packages folder. ${EOL}`,
|
|
77
79
|
)
|
|
78
|
-
.addOption(new Option("--no-ignore-known").hideHelp(true))
|
|
79
80
|
.addOption(
|
|
80
81
|
new Option(
|
|
81
82
|
"--ts-config [file]",
|
|
@@ -96,20 +97,20 @@ try {
|
|
|
96
97
|
).hideHelp(true),
|
|
97
98
|
)
|
|
98
99
|
.option(
|
|
99
|
-
"
|
|
100
|
-
|
|
101
|
-
'regex collapses to that pattern. E.g. "^packages/[^/]+/" would collapse to ' +
|
|
102
|
-
"modules/ folders directly under your packages folder. ",
|
|
100
|
+
"--baseline [file]",
|
|
101
|
+
'create or update a known violations baseline. Implies --no-ignore-known --no-cache (default: ".dependency-cruiser-known-violations.json")',
|
|
103
102
|
)
|
|
104
103
|
.addOption(
|
|
105
104
|
new Option(
|
|
106
|
-
"-
|
|
107
|
-
"
|
|
108
|
-
).choices(["
|
|
105
|
+
"--baseline-mode <mode>",
|
|
106
|
+
'"shrink-only" - remove fixed violations but don\'t add new ones; "full" (default) - replace everything',
|
|
107
|
+
).choices(["full", "shrink-only"]),
|
|
109
108
|
)
|
|
110
|
-
.
|
|
111
|
-
|
|
109
|
+
.option(
|
|
110
|
+
"--ignore-known [file]",
|
|
111
|
+
`ignore known violations as saved in [file] (default: ".dependency-cruiser-known-violations.json")${EOL}`,
|
|
112
112
|
)
|
|
113
|
+
.addOption(new Option("--no-ignore-known").hideHelp(true))
|
|
113
114
|
.addOption(
|
|
114
115
|
new Option(
|
|
115
116
|
"-d, --max-depth <n>",
|
|
@@ -125,11 +126,11 @@ try {
|
|
|
125
126
|
)
|
|
126
127
|
.option(
|
|
127
128
|
"-P, --prefix <prefix>",
|
|
128
|
-
`prefix to use for links in the dot and err-html reporters
|
|
129
|
+
`prefix to use for links in the dot and err-html reporters`,
|
|
129
130
|
)
|
|
130
131
|
.option(
|
|
131
132
|
"--suffix <suffix>",
|
|
132
|
-
`suffix to use for links in the dot and err-html reporters${EOL}
|
|
133
|
+
`suffix to use for links in the dot and err-html reporters${EOL}`,
|
|
133
134
|
)
|
|
134
135
|
.option(
|
|
135
136
|
"-C, --cache [cache-directory]",
|
|
@@ -155,6 +156,15 @@ try {
|
|
|
155
156
|
"leave symlinks unchanged (off by default)",
|
|
156
157
|
).hideHelp(true),
|
|
157
158
|
)
|
|
159
|
+
.addOption(
|
|
160
|
+
new Option(
|
|
161
|
+
"-p, --progress [type]",
|
|
162
|
+
"show progress while dependency-cruiser is busy",
|
|
163
|
+
).choices(["cli-feedback", "performance-log", "ndjson", "none"]),
|
|
164
|
+
)
|
|
165
|
+
.addOption(
|
|
166
|
+
new Option("--no-progress", "Alias of --progress none").hideHelp(true),
|
|
167
|
+
)
|
|
158
168
|
.addOption(
|
|
159
169
|
new Option("-v, --validate [file]", `alias for --config`).hideHelp(true),
|
|
160
170
|
)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dependency-cruiser",
|
|
3
|
-
"version": "18.
|
|
3
|
+
"version": "18.3.1",
|
|
4
4
|
"description": "Validate and visualize dependencies. With your rules. JavaScript, TypeScript, CoffeeScript. ES6, CommonJS, AMD.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"static analysis",
|
|
@@ -75,9 +75,9 @@
|
|
|
75
75
|
},
|
|
76
76
|
"homepage": "https://github.com/sverweij/dependency-cruiser",
|
|
77
77
|
"bin": {
|
|
78
|
-
"dependency-cruiser": "bin/dependency-
|
|
79
|
-
"dependency-cruise": "bin/dependency-
|
|
80
|
-
"depcruise": "bin/dependency-
|
|
78
|
+
"dependency-cruiser": "bin/dependency-cruiser.mjs",
|
|
79
|
+
"dependency-cruise": "bin/dependency-cruiser.mjs",
|
|
80
|
+
"depcruise": "bin/dependency-cruiser.mjs",
|
|
81
81
|
"depcruise-baseline": "bin/depcruise-baseline.mjs",
|
|
82
82
|
"depcruise-fmt": "bin/depcruise-fmt.mjs",
|
|
83
83
|
"depcruise-wrap-stream-in-html": "bin/wrap-stream-in-html.mjs"
|
|
@@ -149,12 +149,12 @@
|
|
|
149
149
|
"acorn-loose": "8.5.2",
|
|
150
150
|
"acorn-walk": "8.3.5",
|
|
151
151
|
"commander": "15.0.0",
|
|
152
|
-
"enhanced-resolve": "5.
|
|
153
|
-
"ignore": "7.0.
|
|
152
|
+
"enhanced-resolve": "5.25.1",
|
|
153
|
+
"ignore": "7.0.9",
|
|
154
154
|
"interpret": "3.1.1",
|
|
155
155
|
"is-installed-globally": "1.0.0",
|
|
156
156
|
"json5": "2.2.3",
|
|
157
|
-
"picomatch": "4.0.
|
|
157
|
+
"picomatch": "4.0.7",
|
|
158
158
|
"prompts": "2.4.2",
|
|
159
159
|
"rechoir": "0.8.0",
|
|
160
160
|
"safe-regex": "2.1.1",
|
|
@@ -41,7 +41,11 @@ export default function analyzeModules(pModules, pOptions) {
|
|
|
41
41
|
bus.info("analyze: validations");
|
|
42
42
|
lModules = addValidations(lModules, pOptions.ruleSet, pOptions.validate);
|
|
43
43
|
|
|
44
|
-
lModules = softenKnownViolations(
|
|
44
|
+
lModules = softenKnownViolations(
|
|
45
|
+
lModules,
|
|
46
|
+
pOptions.knownViolations,
|
|
47
|
+
pOptions.ignoreKnown,
|
|
48
|
+
);
|
|
45
49
|
|
|
46
50
|
return lModules;
|
|
47
51
|
}
|
package/src/analyze/index.mjs
CHANGED
|
@@ -12,7 +12,7 @@ import { bus } from "#utl/bus.mjs";
|
|
|
12
12
|
* caching) can use that.
|
|
13
13
|
*
|
|
14
14
|
* @param {import("../../types/dependency-cruiser.js").IModule[]} pModules
|
|
15
|
-
* @param {import("../../types/
|
|
15
|
+
* @param {import("../../types/options.mjs").ICruiseOptions} pOptions
|
|
16
16
|
* @param {string[]} pFileAndDirectoryArray
|
|
17
17
|
* @returns {import("../../types/dependency-cruiser.js").ICruiseResult}
|
|
18
18
|
*/
|
|
@@ -111,16 +111,18 @@ function softenKnownViolation(pModule, pKnownViolations, pSoftenedSeverity) {
|
|
|
111
111
|
*
|
|
112
112
|
* @param {import("../../types/cruise-result.mjs").IModule[]} pModules
|
|
113
113
|
* @param {import("../../types/baseline-violations.mjs").IBaselineViolations} pKnownViolations
|
|
114
|
+
* @param {boolean} pIgnoreKnown
|
|
114
115
|
* @param {import("../../types/shared-types.mjs").SeverityType} pSoftenedSeverity
|
|
115
116
|
* @returns {import("../../types/cruise-result.mjs").IModule[]}
|
|
116
117
|
*/
|
|
117
118
|
export default function softenKnownViolations(
|
|
118
119
|
pModules,
|
|
119
120
|
pKnownViolations,
|
|
121
|
+
pIgnoreKnown,
|
|
120
122
|
pSoftenedSeverity = "ignore",
|
|
121
123
|
) {
|
|
122
|
-
if (pKnownViolations) {
|
|
123
|
-
bus.info("analyze: compare to known
|
|
124
|
+
if (pKnownViolations && !(pIgnoreKnown === false)) {
|
|
125
|
+
bus.info("analyze: compare to known violations");
|
|
124
126
|
return pModules.map((pModule) =>
|
|
125
127
|
softenKnownViolation(pModule, pKnownViolations, pSoftenedSeverity),
|
|
126
128
|
);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const SHAREABLE_OPTIONS = [
|
|
2
2
|
"babelConfig",
|
|
3
3
|
"baseDir",
|
|
4
|
+
"baseline",
|
|
4
5
|
"cache",
|
|
5
6
|
"collapse",
|
|
6
7
|
"combinedDependencies",
|
|
@@ -15,6 +16,7 @@ const SHAREABLE_OPTIONS = [
|
|
|
15
16
|
"externalModuleResolutionStrategy",
|
|
16
17
|
"focus",
|
|
17
18
|
"focusDepth",
|
|
19
|
+
"ignoreKnown",
|
|
18
20
|
"includeOnly",
|
|
19
21
|
"knownViolations",
|
|
20
22
|
"maxDepth",
|
|
@@ -56,6 +56,7 @@ export function optionsAreCompatible(pOldOptions, pNewOptions) {
|
|
|
56
56
|
pOldOptions.detectProcessBuiltinModuleCalls ===
|
|
57
57
|
pNewOptions.detectProcessBuiltinModuleCalls &&
|
|
58
58
|
pOldOptions.skipAnalysisNotInRules === pNewOptions.skipAnalysisNotInRules &&
|
|
59
|
+
pOldOptions.ignoreKnown === pNewOptions.ignoreKnown &&
|
|
59
60
|
metricsIsCompatible(pOldOptions.metrics, pNewOptions.metrics) &&
|
|
60
61
|
// includeOnly suffers from a backwards compatibility disease
|
|
61
62
|
includeOnlyIsCompatible(pOldOptions.includeOnly, pNewOptions.includeOnly) &&
|
package/src/cli/index.mjs
CHANGED
|
@@ -12,6 +12,7 @@ import setUpNDJSONListener from "./listeners/ndjson.mjs";
|
|
|
12
12
|
import { set } from "#utl/object-util.mjs";
|
|
13
13
|
import cruise from "#main/cruise.mjs";
|
|
14
14
|
import { INFO, bus } from "#utl/bus.mjs";
|
|
15
|
+
import { EOL } from "node:os";
|
|
15
16
|
|
|
16
17
|
// eslint-disable-next-line complexity
|
|
17
18
|
async function extractResolveOptions(pCruiseOptions) {
|
|
@@ -96,9 +97,9 @@ function setUpListener(pCruiseOptions) {
|
|
|
96
97
|
}
|
|
97
98
|
}
|
|
98
99
|
|
|
99
|
-
async function runCruise(pFileDirectoryArray, pCruiseOptions) {
|
|
100
|
+
async function runCruise(pFileDirectoryArray, pCruiseOptions, pErrorStream) {
|
|
100
101
|
const lCruiseOptions = await addKnownViolations(
|
|
101
|
-
await normalizeCliOptions(pCruiseOptions),
|
|
102
|
+
await normalizeCliOptions(pCruiseOptions, pErrorStream),
|
|
102
103
|
);
|
|
103
104
|
|
|
104
105
|
pFileDirectoryArray
|
|
@@ -128,6 +129,9 @@ async function runCruise(pFileDirectoryArray, pCruiseOptions) {
|
|
|
128
129
|
bus.progress("cli: writing results", { complete: 1 });
|
|
129
130
|
bus.emit("write-start");
|
|
130
131
|
write(lCruiseOptions.outputTo, lReportingResult.output);
|
|
132
|
+
if (lReportingResult.meta) {
|
|
133
|
+
pErrorStream.write(`${lReportingResult.meta}${EOL}`);
|
|
134
|
+
}
|
|
131
135
|
|
|
132
136
|
return lReportingResult.exitCode;
|
|
133
137
|
}
|
|
@@ -179,7 +183,11 @@ export default async function executeCli(
|
|
|
179
183
|
const { default: initConfig } = await import("./init-config/index.mjs");
|
|
180
184
|
initConfig(lCruiseOptions.init, null, lStreams);
|
|
181
185
|
} else {
|
|
182
|
-
lExitCode = await runCruise(
|
|
186
|
+
lExitCode = await runCruise(
|
|
187
|
+
pFileDirectoryArray,
|
|
188
|
+
lCruiseOptions,
|
|
189
|
+
lStreams.stderr,
|
|
190
|
+
);
|
|
183
191
|
}
|
|
184
192
|
} catch (pError) {
|
|
185
193
|
lStreams.stderr.write(
|
|
@@ -304,7 +304,7 @@ module.exports = {
|
|
|
304
304
|
conditionNames: ['import', 'require', 'node', 'default', 'types'],
|
|
305
305
|
|
|
306
306
|
// The extensions, by default are the same as the ones dependency-cruiser
|
|
307
|
-
// can access (run \`npx
|
|
307
|
+
// can access (run \`npx dependency-cruiser --info\` to see which ones that are in
|
|
308
308
|
// _your_ environment). If that list is larger than you need you can pass
|
|
309
309
|
// the extensions you actually use (e.g. ['.js', '.jsx']). This can speed
|
|
310
310
|
// up module resolution, which is the most expensive step.
|
|
@@ -71,13 +71,13 @@ export function compileRunScripts(pInitOptions) {
|
|
|
71
71
|
const lTestLocations = (pInitOptions.testLocation || []).join(" ");
|
|
72
72
|
|
|
73
73
|
lReturnValue = {
|
|
74
|
-
depcruise: `
|
|
75
|
-
"depcruise:graph": `
|
|
76
|
-
"depcruise:graph:dev": `
|
|
77
|
-
"depcruise:graph:archi": `
|
|
78
|
-
"depcruise:html": `
|
|
79
|
-
"depcruise:text": `
|
|
80
|
-
"depcruise:focus": `
|
|
74
|
+
depcruise: `dependency-cruiser ${lSourceLocations} ${lTestLocations}`,
|
|
75
|
+
"depcruise:graph": `dependency-cruiser ${lSourceLocations} --include-only '${lSourceLocationRE}' --output-type dot | dot -T svg | depcruise-wrap-stream-in-html > dependency-graph.html`,
|
|
76
|
+
"depcruise:graph:dev": `dependency-cruiser ${lSourceLocations} --include-only '${lSourceLocationRE}' --prefix vscode://file/$(pwd)/ --output-type dot | dot -T svg | depcruise-wrap-stream-in-html | browser`,
|
|
77
|
+
"depcruise:graph:archi": `dependency-cruiser ${lSourceLocations} --include-only '${lSourceLocationRE}' --output-type archi | dot -T svg | depcruise-wrap-stream-in-html > high-level-dependency-graph.html`,
|
|
78
|
+
"depcruise:html": `dependency-cruiser ${lSourceLocations} ${lTestLocations} --progress --output-type err-html --output-to dependency-violation-report.html`,
|
|
79
|
+
"depcruise:text": `dependency-cruiser ${lSourceLocations} ${lTestLocations} --progress --output-type text`,
|
|
80
|
+
"depcruise:focus": `dependency-cruiser ${lSourceLocations} ${lTestLocations} --progress --output-type text --focus`,
|
|
81
81
|
};
|
|
82
82
|
}
|
|
83
83
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { accessSync, constants } from "node:fs";
|
|
2
2
|
import { isAbsolute } from "node:path";
|
|
3
|
+
import { styleText } from "node:util";
|
|
3
4
|
import {
|
|
4
5
|
RULES_FILE_NAME_SEARCH_ARRAY,
|
|
5
6
|
DEFAULT_BASELINE_FILE_NAME,
|
|
@@ -12,11 +13,31 @@ import {
|
|
|
12
13
|
} from "./defaults.mjs";
|
|
13
14
|
import { set } from "#utl/object-util.mjs";
|
|
14
15
|
import loadConfig from "#config-utl/extract-depcruise-config/index.mjs";
|
|
16
|
+
import extractKnownViolations from "#config-utl/extract-known-violations.mjs";
|
|
15
17
|
|
|
16
18
|
function getOptionValue(pDefault) {
|
|
17
19
|
return (pValue) => (typeof pValue === "string" ? pValue : pDefault);
|
|
18
20
|
}
|
|
19
21
|
|
|
22
|
+
async function getCurrentBaseline(pBaselineFileName, pErrorStream) {
|
|
23
|
+
let lCurrentBaseline = [];
|
|
24
|
+
try {
|
|
25
|
+
lCurrentBaseline = await extractKnownViolations(pBaselineFileName);
|
|
26
|
+
} catch (pKnownViolationsExtractionError) {
|
|
27
|
+
if (pKnownViolationsExtractionError.code === "ENOENT") {
|
|
28
|
+
pErrorStream.write(
|
|
29
|
+
styleText(
|
|
30
|
+
"yellow",
|
|
31
|
+
`‼ Known violations file '${pBaselineFileName}' does not exist yet. Will assume an empty current violations set and create a new one instead.\n`,
|
|
32
|
+
),
|
|
33
|
+
);
|
|
34
|
+
} else {
|
|
35
|
+
throw pKnownViolationsExtractionError;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return lCurrentBaseline;
|
|
39
|
+
}
|
|
40
|
+
|
|
20
41
|
// eslint-disable-next-line complexity
|
|
21
42
|
function normalizeConfigFileName(pCliOptions, pConfigWrapperName, pDefault) {
|
|
22
43
|
const lOptions = structuredClone(pCliOptions);
|
|
@@ -108,6 +129,12 @@ function validateAndGetKnownViolationsFileName(pKnownViolations) {
|
|
|
108
129
|
}
|
|
109
130
|
}
|
|
110
131
|
|
|
132
|
+
function normalizeIgnoreKnown(pCliOptions) {
|
|
133
|
+
return Object.hasOwn(pCliOptions, "ignoreKnown")
|
|
134
|
+
? { ignoreKnown: !!pCliOptions.ignoreKnown }
|
|
135
|
+
: {};
|
|
136
|
+
}
|
|
137
|
+
|
|
111
138
|
function normalizeKnownViolationsOption(pCliOptions) {
|
|
112
139
|
if (
|
|
113
140
|
!Object.hasOwn(pCliOptions, "ignoreKnown") ||
|
|
@@ -196,11 +223,15 @@ function normalizeCache(pCliOptions) {
|
|
|
196
223
|
* returns the pOptionsAsPassedFromCommander, so that the returned value contains a
|
|
197
224
|
* valid value for each possible option
|
|
198
225
|
*
|
|
199
|
-
* @param
|
|
226
|
+
* @param {object} pOptionsAsPassedFromCommander [description]
|
|
200
227
|
* @param {any} pKnownCliOptions [description]
|
|
228
|
+
* @param {typeof process.stderr} pErrorStream
|
|
201
229
|
* @returns {import("../../types/options.mjs").ICruiseOptions} [description]
|
|
202
230
|
*/
|
|
203
|
-
export default async function normalizeOptions(
|
|
231
|
+
export default async function normalizeOptions(
|
|
232
|
+
pOptionsAsPassedFromCommander,
|
|
233
|
+
pErrorStream,
|
|
234
|
+
) {
|
|
204
235
|
let lOptions = {
|
|
205
236
|
outputTo: OUTPUT_TO,
|
|
206
237
|
outputType: OUTPUT_TYPE,
|
|
@@ -217,11 +248,41 @@ export default async function normalizeOptions(pOptionsAsPassedFromCommander) {
|
|
|
217
248
|
lOptions.validate = lOptions.config;
|
|
218
249
|
}
|
|
219
250
|
|
|
251
|
+
if (Object.hasOwn(lOptions, "baseline")) {
|
|
252
|
+
const lBaselineFileName =
|
|
253
|
+
typeof pOptionsAsPassedFromCommander.baseline === "string"
|
|
254
|
+
? pOptionsAsPassedFromCommander.baseline
|
|
255
|
+
: ".dependency-cruiser-known-violations.json";
|
|
256
|
+
|
|
257
|
+
// keeping the baseline option (a boolean or a string) as passed from commander
|
|
258
|
+
// in would overwrite the option as passed in the configuration file (an object,
|
|
259
|
+
// if any)
|
|
260
|
+
Reflect.deleteProperty(lOptions, "baseline");
|
|
261
|
+
|
|
262
|
+
lOptions.ignoreKnown = false;
|
|
263
|
+
lOptions.outputTo = lBaselineFileName;
|
|
264
|
+
lOptions.outputType = "baseline";
|
|
265
|
+
lOptions.knownViolations = await getCurrentBaseline(
|
|
266
|
+
lBaselineFileName,
|
|
267
|
+
pErrorStream,
|
|
268
|
+
);
|
|
269
|
+
lOptions.cache = false;
|
|
270
|
+
Reflect.deleteProperty(lOptions, "cacheStrategy");
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (Object.hasOwn(lOptions, "baselineMode")) {
|
|
274
|
+
lOptions.baseline = {
|
|
275
|
+
...lOptions.baseline,
|
|
276
|
+
mode: lOptions.baselineMode,
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
|
|
220
280
|
lOptions = { ...lOptions, ...(await normalizeValidationOption(lOptions)) };
|
|
221
281
|
lOptions = { ...lOptions, ...normalizeProgress(lOptions) };
|
|
222
282
|
lOptions = { ...lOptions, ...normalizeCache(lOptions) };
|
|
223
283
|
lOptions = { ...lOptions, ...normalizeCacheStrategy(lOptions) };
|
|
224
284
|
lOptions = { ...lOptions, ...normalizeKnownViolationsOption(lOptions) };
|
|
285
|
+
lOptions = { ...lOptions, ...normalizeIgnoreKnown(lOptions) };
|
|
225
286
|
lOptions = normalizeConfigFileName(lOptions, "webpackConfig", WEBPACK_CONFIG);
|
|
226
287
|
lOptions = normalizeConfigFileName(lOptions, "tsConfig", TYPESCRIPT_CONFIG);
|
|
227
288
|
lOptions = normalizeConfigFileName(lOptions, "babelConfig", BABEL_CONFIG);
|
package/src/extract/helpers.mjs
CHANGED
|
@@ -4,10 +4,14 @@ import tryImport from "#utl/try-import.mjs";
|
|
|
4
4
|
import meta from "#meta.cjs";
|
|
5
5
|
|
|
6
6
|
/** @type {import('@swc/core/Visitor')} */
|
|
7
|
-
const
|
|
7
|
+
const lSwcVisitorModule = await tryImport(
|
|
8
8
|
"@swc/core/Visitor.js",
|
|
9
9
|
meta.supportedTranspilers.swc,
|
|
10
10
|
);
|
|
11
|
+
// under bun lSwcVisitorModule resolves to something different
|
|
12
|
+
// as under node.js - see https://github.com/sverweij/dependency-cruiser/issues/1092
|
|
13
|
+
// for details. In order to enable running dependency-cruiser on both:
|
|
14
|
+
const Visitor = lSwcVisitorModule.Visitor ?? lSwcVisitorModule;
|
|
11
15
|
|
|
12
16
|
function pryStringsFromArguments(pArguments) {
|
|
13
17
|
let lReturnValue = null;
|
|
@@ -114,6 +118,16 @@ function isInterestingCallExpression(pExoticRequireStrings, pNode) {
|
|
|
114
118
|
);
|
|
115
119
|
}
|
|
116
120
|
|
|
121
|
+
function nodeIsTypeOnly(pNode) {
|
|
122
|
+
if (pNode.typeOnly) {
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
return (
|
|
126
|
+
pNode?.specifiers.length > 0 &&
|
|
127
|
+
pNode.specifiers.every((pSpecifier) => pSpecifier.isTypeOnly)
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
117
131
|
export default Visitor
|
|
118
132
|
? class SwcDependencyVisitor extends Visitor {
|
|
119
133
|
#exoticRequireStrings;
|
|
@@ -134,14 +148,15 @@ export default Visitor
|
|
|
134
148
|
});
|
|
135
149
|
}
|
|
136
150
|
}
|
|
137
|
-
|
|
138
151
|
#pushImportSource(pNode) {
|
|
139
152
|
if (pNode.source) {
|
|
140
153
|
this.#result.push({
|
|
141
154
|
module: pNode.source.value,
|
|
142
155
|
moduleSystem: "es6",
|
|
143
156
|
exoticallyRequired: false,
|
|
144
|
-
dependencyTypes:
|
|
157
|
+
dependencyTypes: nodeIsTypeOnly(pNode)
|
|
158
|
+
? ["import", "type-only"]
|
|
159
|
+
: ["import"],
|
|
145
160
|
});
|
|
146
161
|
}
|
|
147
162
|
}
|
|
@@ -17,13 +17,23 @@ const SWC_PARSE_OPTIONS = {
|
|
|
17
17
|
target: "es2022",
|
|
18
18
|
// allow for decorators
|
|
19
19
|
decorators: true,
|
|
20
|
-
//
|
|
20
|
+
// no tsx by default - overridden when the extension calls for it (see getOptionsFor)
|
|
21
|
+
// tsx: false
|
|
21
22
|
};
|
|
22
23
|
/** @type {Map<string, ModuleItem[]>} */
|
|
23
24
|
const CACHE = new Map();
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
/**
|
|
27
|
+
* Returns the parse options necessary to have swc parse the file name
|
|
28
|
+
* pFileName correctly (mainly important for jsx/ tsx)
|
|
29
|
+
*
|
|
30
|
+
* @param {string} pFileName
|
|
31
|
+
* @returns {ParseOptions}
|
|
32
|
+
*/
|
|
33
|
+
export function getOptionsFor(pFileName) {
|
|
34
|
+
return /[.](?:tsx|jsx)$/.test(pFileName)
|
|
35
|
+
? { ...SWC_PARSE_OPTIONS, tsx: true }
|
|
36
|
+
: SWC_PARSE_OPTIONS;
|
|
27
37
|
}
|
|
28
38
|
|
|
29
39
|
/**
|
|
@@ -39,7 +49,7 @@ export function getASTCached(pFileName) {
|
|
|
39
49
|
return CACHE.get(pFileName);
|
|
40
50
|
}
|
|
41
51
|
/** @type {swcCore} */
|
|
42
|
-
const lAST = swc.parseFileSync(pFileName,
|
|
52
|
+
const lAST = swc.parseFileSync(pFileName, getOptionsFor(pFileName));
|
|
43
53
|
CACHE.set(pFileName, lAST);
|
|
44
54
|
return lAST;
|
|
45
55
|
}
|
|
@@ -14,7 +14,7 @@ function extractRootModuleName(pModuleName) {
|
|
|
14
14
|
|
|
15
15
|
function getVersion(pModuleName) {
|
|
16
16
|
// of course we'd love to use something like an import with an import assertion
|
|
17
|
-
// As that's _experimental_ we have to use _require_
|
|
17
|
+
// As that's _experimental_ we have to use _require_ instead.
|
|
18
18
|
// eslint-disable-next-line import/no-dynamic-require, security/detect-non-literal-require
|
|
19
19
|
const lManifest = require(
|
|
20
20
|
path.join(extractRootModuleName(pModuleName), "package.json"),
|