dependency-cruiser 18.3.1 → 18.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/bin/dependency-cruiser.mjs +2 -2
- package/package.json +4 -4
- package/src/analyze/summarize/get-stats.mjs +38 -3
- package/src/analyze/summarize/index.mjs +30 -6
- package/src/analyze/summarize/summarize-options.mjs +1 -0
- package/src/cache/cache.mjs +1 -1
- package/src/cache/options-compatible.mjs +2 -0
- package/src/cli/init-config/build-config.mjs +14 -0
- package/src/cli/init-config/config-template.mjs +5 -0
- package/src/cli/init-config/environment-helpers.mjs +5 -1
- package/src/cli/init-config/get-user-input.mjs +11 -0
- package/src/cli/init-config/index.mjs +1 -0
- package/src/cli/init-config/normalize-init-options.mjs +1 -1
- package/src/cli/init-config/types.d.mts +4 -0
- package/src/cli/init-config/write-run-scripts-to-manifest.mjs +2 -2
- package/src/extract/transpile/meta.mjs +2 -2
- package/src/extract/transpile/try-import-available.mjs +1 -1
- package/src/extract/tsc/extract-typescript-deps.mjs +57 -12
- package/src/extract/tsc/extract.mjs +2 -0
- package/src/main/options/defaults.mjs +1 -0
- package/src/main/options/normalize.mjs +4 -1
- package/src/meta.cjs +1 -1
- package/src/report/azure-devops.mjs +6 -2
- package/src/report/baseline.mjs +22 -7
- package/src/report/error-html/error-html-template.mjs +2 -0
- package/src/report/error-html/index.mjs +84 -8
- package/src/report/error.mjs +62 -13
- package/src/report/markdown.mjs +89 -19
- package/src/report/null.mjs +6 -3
- package/src/report/teamcity.mjs +4 -1
- package/src/schema/configuration.validate.mjs +1 -1
- package/src/schema/cruise-result.validate.mjs +1 -1
- package/types/cruise-result.d.mts +14 -0
- package/types/options.d.mts +21 -2
- package/types/reporter-options.d.mts +30 -5
package/README.md
CHANGED
|
@@ -45,7 +45,7 @@ a `.dependency-cruiser.js` configuration file attuned to your project[^1][^2].
|
|
|
45
45
|
If you don't want to use `npx`, but instead `pnpx` (from the `pnpm`
|
|
46
46
|
package manager) or `yarn` - please refer to that tool's documentation.
|
|
47
47
|
Particularly `pnpx` has semantics that differ from `npx` quite significantly
|
|
48
|
-
and that you want to be aware of before using it. In the
|
|
48
|
+
and that you want to be aware of before using it. In the meantime: `npx`
|
|
49
49
|
_should_ work even when you installed the dependency with a package manager
|
|
50
50
|
different from `npm`.
|
|
51
51
|
|
|
@@ -103,8 +103,8 @@ try {
|
|
|
103
103
|
.addOption(
|
|
104
104
|
new Option(
|
|
105
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"]),
|
|
106
|
+
'"shrink-only" - remove fixed violations but don\'t add new ones; "format" - rewrite but add nor remove anything; "full" (default) - replace everything',
|
|
107
|
+
).choices(["full", "shrink-only", "format"]),
|
|
108
108
|
)
|
|
109
109
|
.option(
|
|
110
110
|
"--ignore-known [file]",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dependency-cruiser",
|
|
3
|
-
"version": "18.
|
|
3
|
+
"version": "18.5.0",
|
|
4
4
|
"description": "Validate and visualize dependencies. With your rules. JavaScript, TypeScript, CoffeeScript. ES6, CommonJS, AMD.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"static analysis",
|
|
@@ -149,10 +149,10 @@
|
|
|
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.26.0",
|
|
153
|
+
"ignore": "7.0.11",
|
|
154
154
|
"interpret": "3.1.1",
|
|
155
|
-
"is-installed-globally": "1.0.
|
|
155
|
+
"is-installed-globally": "1.0.1",
|
|
156
156
|
"json5": "2.2.3",
|
|
157
157
|
"picomatch": "4.0.7",
|
|
158
158
|
"prompts": "2.4.2",
|
|
@@ -1,4 +1,14 @@
|
|
|
1
|
-
|
|
1
|
+
import { diffViolationArrays } from "#graph-utl/compare.mjs";
|
|
2
|
+
/**
|
|
3
|
+
* @import { IViolation } from "../../../types/violations.mjs"
|
|
4
|
+
* @import { IModule } from "../../../types/cruise-result.d.mts"
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @param {IViolation[]} pViolations
|
|
9
|
+
* @returns {{error:number; warn: number; info: number; ignore:number; }}
|
|
10
|
+
*/
|
|
11
|
+
export function getViolationCounts(pViolations) {
|
|
2
12
|
return pViolations.reduce(
|
|
3
13
|
(pAll, pThis) => {
|
|
4
14
|
pAll[pThis.rule.severity] += 1;
|
|
@@ -13,13 +23,38 @@ export function getViolationStats(pViolations) {
|
|
|
13
23
|
);
|
|
14
24
|
}
|
|
15
25
|
|
|
16
|
-
|
|
26
|
+
/**
|
|
27
|
+
* @param {IModule[]} pModules
|
|
28
|
+
* @returns {number} number of modules cruised
|
|
29
|
+
*/
|
|
30
|
+
export function getModulesCruisedCount(pModules) {
|
|
17
31
|
return pModules.length;
|
|
18
32
|
}
|
|
19
33
|
|
|
20
|
-
|
|
34
|
+
/**
|
|
35
|
+
* @param {IModule[]} pModules
|
|
36
|
+
* @returns {number} number of dependencies cruised
|
|
37
|
+
*/
|
|
38
|
+
export function getDependenciesCruisedCount(pModules) {
|
|
21
39
|
return pModules.reduce(
|
|
22
40
|
(pAll, pModule) => pAll + pModule.dependencies.length,
|
|
23
41
|
0,
|
|
24
42
|
);
|
|
25
43
|
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* @param {IViolation[]} pKnownViolations
|
|
47
|
+
* @param {IViolation[]} pCurrentViolations
|
|
48
|
+
* @returns {{baselineSize:number; baselineStale:number; }}
|
|
49
|
+
*/
|
|
50
|
+
export function getBaselineDiffCounts(pKnownViolations, pCurrentViolations) {
|
|
51
|
+
const lViolationArrayDiff = diffViolationArrays(
|
|
52
|
+
pKnownViolations,
|
|
53
|
+
pCurrentViolations,
|
|
54
|
+
);
|
|
55
|
+
return {
|
|
56
|
+
baselineSize: pKnownViolations.length,
|
|
57
|
+
baselineStale: lViolationArrayDiff.old.length,
|
|
58
|
+
// lViolationArrayDiff.same.length is already present in the ignore attribute
|
|
59
|
+
};
|
|
60
|
+
}
|
|
@@ -4,9 +4,10 @@ import summarizeModules from "./summarize-modules.mjs";
|
|
|
4
4
|
import summarizeFolders from "./summarize-folders.mjs";
|
|
5
5
|
import summarizeOptions from "./summarize-options.mjs";
|
|
6
6
|
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
getViolationCounts,
|
|
8
|
+
getModulesCruisedCount,
|
|
9
|
+
getDependenciesCruisedCount,
|
|
10
|
+
getBaselineDiffCounts,
|
|
10
11
|
} from "./get-stats.mjs";
|
|
11
12
|
import { compareViolations } from "#graph-utl/compare.mjs";
|
|
12
13
|
import { getEnvironmentInfo } from "#environment.mjs";
|
|
@@ -118,6 +119,17 @@ function determineEnvironmentIssues(pOptions, pAvailableTranspilers) {
|
|
|
118
119
|
return lIssues.length > 0 ? { issues: lIssues } : {};
|
|
119
120
|
}
|
|
120
121
|
|
|
122
|
+
function getAdvisedExitCode(
|
|
123
|
+
pErrorCount,
|
|
124
|
+
pBaselineStaleCount,
|
|
125
|
+
pStaleEntriesSeverity,
|
|
126
|
+
) {
|
|
127
|
+
if ((pStaleEntriesSeverity ?? "warn") === "error") {
|
|
128
|
+
return pErrorCount + (pBaselineStaleCount ?? 0);
|
|
129
|
+
}
|
|
130
|
+
return pErrorCount;
|
|
131
|
+
}
|
|
132
|
+
|
|
121
133
|
/**
|
|
122
134
|
*
|
|
123
135
|
* @param {IModule[]} pModules -
|
|
@@ -149,11 +161,23 @@ export default function summarize(
|
|
|
149
161
|
...lEnvironment,
|
|
150
162
|
...determineEnvironmentIssues(pOptions, lEnvironment.transpilersFound),
|
|
151
163
|
};
|
|
164
|
+
const lViolationCounts = getViolationCounts(lViolations);
|
|
165
|
+
const lBaselineDiffCounts = pOptions.knownViolations
|
|
166
|
+
? getBaselineDiffCounts(pOptions.knownViolations, lViolations)
|
|
167
|
+
: {};
|
|
168
|
+
const lAdvisedExitCode = getAdvisedExitCode(
|
|
169
|
+
lViolationCounts.error,
|
|
170
|
+
lBaselineDiffCounts?.baselineStale,
|
|
171
|
+
pOptions?.baseline?.staleEntriesSeverity,
|
|
172
|
+
);
|
|
173
|
+
|
|
152
174
|
return {
|
|
153
175
|
violations: lViolations,
|
|
154
|
-
...
|
|
155
|
-
|
|
156
|
-
|
|
176
|
+
...lViolationCounts,
|
|
177
|
+
...lBaselineDiffCounts,
|
|
178
|
+
advisedExitCode: lAdvisedExitCode,
|
|
179
|
+
totalCruised: getModulesCruisedCount(pModules),
|
|
180
|
+
totalDependenciesCruised: getDependenciesCruisedCount(pModules),
|
|
157
181
|
...summarizeOptions(pFileDirectoryArray, pOptions),
|
|
158
182
|
...(pOptions.ruleSet ? { ruleSetUsed: addRuleSetUsed(pOptions) } : {}),
|
|
159
183
|
environment: lEnvironmentWithIssues,
|
package/src/cache/cache.mjs
CHANGED
|
@@ -33,7 +33,7 @@ const EMPTY_CACHE = {
|
|
|
33
33
|
};
|
|
34
34
|
|
|
35
35
|
// see ./cache-rationales.md#cache-format-versioning for rationale & bump instructions
|
|
36
|
-
const CACHE_FORMAT_VERSION = 18.
|
|
36
|
+
const CACHE_FORMAT_VERSION = 18.5;
|
|
37
37
|
|
|
38
38
|
export default class Cache {
|
|
39
39
|
/** @type {(IRevisionData | null)=} */
|
|
@@ -52,6 +52,8 @@ export function optionsAreCompatible(pOldOptions, pNewOptions) {
|
|
|
52
52
|
pOldOptions.preserveSymlinks === pNewOptions.preserveSymlinks &&
|
|
53
53
|
pOldOptions.combinedDependencies === pNewOptions.combinedDependencies &&
|
|
54
54
|
pOldOptions.experimentalStats === pNewOptions.experimentalStats &&
|
|
55
|
+
pOldOptions.detectImportsInAmbientModules ===
|
|
56
|
+
pNewOptions.detectImportsInAmbientModules &&
|
|
55
57
|
pOldOptions.detectJSDocImports === pNewOptions.detectJSDocImports &&
|
|
56
58
|
pOldOptions.detectProcessBuiltinModuleCalls ===
|
|
57
59
|
pNewOptions.detectProcessBuiltinModuleCalls &&
|
|
@@ -73,6 +73,16 @@ function buildDetectJSDocumentImportsAttribute(pInitOptions) {
|
|
|
73
73
|
: "// detectJSDocImports: true,";
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
/**
|
|
77
|
+
* @param {IInitConfig} pInitOptions
|
|
78
|
+
* @returns {string}
|
|
79
|
+
*/
|
|
80
|
+
function buildDetectImportsInAmbientModulesAttribute(pInitOptions) {
|
|
81
|
+
return pInitOptions.detectImportsInAmbientModules
|
|
82
|
+
? "detectImportsInAmbientModules: true,"
|
|
83
|
+
: "// detectImportsInAmbientModules: true,";
|
|
84
|
+
}
|
|
85
|
+
|
|
76
86
|
/**
|
|
77
87
|
*
|
|
78
88
|
* @param {IInitConfig} pInitOptions
|
|
@@ -224,6 +234,10 @@ export default function buildConfig(pInitOptions) {
|
|
|
224
234
|
"{{detectJSDocImportsAttribute}}",
|
|
225
235
|
buildDetectJSDocumentImportsAttribute(pInitOptions),
|
|
226
236
|
)
|
|
237
|
+
.replace(
|
|
238
|
+
"{{detectImportsInAmbientModulesAttribute}}",
|
|
239
|
+
buildDetectImportsInAmbientModulesAttribute(pInitOptions),
|
|
240
|
+
)
|
|
227
241
|
.replace(
|
|
228
242
|
"{{detectProcessBuiltinModuleCalls}}",
|
|
229
243
|
buildDetectProcessBuiltinModuleCalls(pInitOptions),
|
|
@@ -227,6 +227,11 @@ module.exports = {
|
|
|
227
227
|
// to be installed in the same spot you run dependency-cruiser from.
|
|
228
228
|
{{detectJSDocImportsAttribute}}
|
|
229
229
|
|
|
230
|
+
// false: don't look at imports in ambient module declarations (the default)
|
|
231
|
+
// true: detect imports, re-exports and import-equals declarations inside
|
|
232
|
+
// ambient modules and namespaces. Implies parser: 'tsc'.
|
|
233
|
+
{{detectImportsInAmbientModulesAttribute}}
|
|
234
|
+
|
|
230
235
|
// false: don't look at process.getBuiltinModule calls (the default)
|
|
231
236
|
// true: dependency-cruiser will detect calls to process.getBuiltinModule/
|
|
232
237
|
// globalThis.process.getBuiltinModule as imports.
|
|
@@ -105,6 +105,10 @@ export function isLikelyMonoRepo(pFolderNames = getFolderNames(process.cwd())) {
|
|
|
105
105
|
return pFolderNames.includes("packages");
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
+
/**
|
|
109
|
+
* @param {Record<string,any>} [pManifest]
|
|
110
|
+
* @returns
|
|
111
|
+
*/
|
|
108
112
|
function getPackageManager(pManifest) {
|
|
109
113
|
let lReturnValue = "";
|
|
110
114
|
try {
|
|
@@ -119,7 +123,7 @@ function getPackageManager(pManifest) {
|
|
|
119
123
|
}
|
|
120
124
|
|
|
121
125
|
/**
|
|
122
|
-
* @param {Record<string,any>} pManifest
|
|
126
|
+
* @param {Record<string,any>} [pManifest]
|
|
123
127
|
* @returns {boolean}
|
|
124
128
|
*/
|
|
125
129
|
export function likelyUsesBun(pManifest) {
|
|
@@ -21,6 +21,10 @@ import {
|
|
|
21
21
|
import { validateLocation } from "./validators.mjs";
|
|
22
22
|
import { isAvailable as tscIsAvailable } from "#extract/tsc/parse.mjs";
|
|
23
23
|
|
|
24
|
+
/**
|
|
25
|
+
* @param {string} pString
|
|
26
|
+
* @returns {{title:string;value:string}}
|
|
27
|
+
*/
|
|
24
28
|
function toPromptChoice(pString) {
|
|
25
29
|
return {
|
|
26
30
|
title: pString,
|
|
@@ -116,6 +120,13 @@ const QUESTIONS = [
|
|
|
116
120
|
message: "Do you want to detect JSDoc imports (slightly slower)?",
|
|
117
121
|
initial: false,
|
|
118
122
|
},
|
|
123
|
+
{
|
|
124
|
+
name: "detectImportsInAmbientModules",
|
|
125
|
+
type: () => (tscIsAvailable() ? "confirm" : false),
|
|
126
|
+
message:
|
|
127
|
+
"Do you want to detect imports inside ambient modules (slightly slower)?",
|
|
128
|
+
initial: false,
|
|
129
|
+
},
|
|
119
130
|
{
|
|
120
131
|
name: "detectProcessBuiltinModuleCalls",
|
|
121
132
|
type: "confirm",
|
|
@@ -46,6 +46,7 @@ function getOneShotConfig(pOneShotConfigId) {
|
|
|
46
46
|
useTsConfig: hasTSConfigCandidates(),
|
|
47
47
|
tsConfig: getTSConfigCandidates().shift(),
|
|
48
48
|
detectJSDocImports: false,
|
|
49
|
+
detectImportsInAmbientModules: false,
|
|
49
50
|
detectProcessBuiltinModuleCalls: true,
|
|
50
51
|
tsPreCompilationDeps: hasTSConfigCandidates(),
|
|
51
52
|
useWebpackConfig: hasWebpackConfigCandidates(),
|
|
@@ -20,7 +20,7 @@ function usesTypeScript(pInitOptions, pExtensions) {
|
|
|
20
20
|
return Boolean(
|
|
21
21
|
pInitOptions.tsConfig ||
|
|
22
22
|
pInitOptions.tsPreCompilationDeps ||
|
|
23
|
-
(pExtensions || []).some((pExtension) =>
|
|
23
|
+
(pExtensions /* c8 ignore next */ || []).some((pExtension) =>
|
|
24
24
|
[".ts", ".tsx", ".d.ts", ".mts", ".d.mts", ".cts", ".d.cts"].includes(
|
|
25
25
|
pExtension,
|
|
26
26
|
),
|
|
@@ -36,6 +36,10 @@ export interface IInitConfig {
|
|
|
36
36
|
* Whether or not to detect JSDoc imports
|
|
37
37
|
*/
|
|
38
38
|
detectJSDocImports?: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Whether or not to detect imports in ambient module and namespace declarations
|
|
41
|
+
*/
|
|
42
|
+
detectImportsInAmbientModules?: boolean;
|
|
39
43
|
/**
|
|
40
44
|
* Whether or not to detect calls to `process.getBuiltinModule`/
|
|
41
45
|
* `globalThis.process.getBuiltinModule` as imports
|
|
@@ -72,8 +72,8 @@ export function compileRunScripts(pInitOptions) {
|
|
|
72
72
|
|
|
73
73
|
lReturnValue = {
|
|
74
74
|
depcruise: `dependency-cruiser ${lSourceLocations} ${lTestLocations}`,
|
|
75
|
-
"depcruise:graph": `dependency-cruiser ${lSourceLocations} --include-only '${lSourceLocationRE}' --output-type dot
|
|
76
|
-
"depcruise:graph:dev": `dependency-cruiser ${lSourceLocations} --include-only '${lSourceLocationRE}' --prefix vscode://file/$(pwd)/ --output-type dot
|
|
75
|
+
"depcruise:graph": `dependency-cruiser ${lSourceLocations} --include-only '${lSourceLocationRE}' --output-type dot-webpage > dependency-graph.html`,
|
|
76
|
+
"depcruise:graph:dev": `dependency-cruiser ${lSourceLocations} --include-only '${lSourceLocationRE}' --prefix vscode://file/$(pwd)/ --output-type dot-webpage | browser`,
|
|
77
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
78
|
"depcruise:html": `dependency-cruiser ${lSourceLocations} ${lTestLocations} --progress --output-type err-html --output-to dependency-violation-report.html`,
|
|
79
79
|
"depcruise:text": `dependency-cruiser ${lSourceLocations} ${lTestLocations} --progress --output-type text`,
|
|
@@ -30,8 +30,8 @@ function gotCoffee() {
|
|
|
30
30
|
tryImportAvailable(
|
|
31
31
|
"coffeescript",
|
|
32
32
|
meta.supportedTranspilers.coffeescript,
|
|
33
|
+
/* c8 ignore start */
|
|
33
34
|
) ||
|
|
34
|
-
/* c8 ignore start */
|
|
35
35
|
// fallback for ancient versions of the coffeescript compilers
|
|
36
36
|
tryImportAvailable(
|
|
37
37
|
"coffee-script",
|
|
@@ -96,7 +96,7 @@ export const EXTENSION2AVAILABLE = new Map([
|
|
|
96
96
|
[".d.mts", TRANSPILER2AVAILABLE.typescript],
|
|
97
97
|
[
|
|
98
98
|
".vue",
|
|
99
|
-
TRANSPILER2AVAILABLE["vue-template-compiler"] ||
|
|
99
|
+
TRANSPILER2AVAILABLE["vue-template-compiler"] /* c8 ignore next */ ||
|
|
100
100
|
TRANSPILER2AVAILABLE["@vue/compiler-sfc"],
|
|
101
101
|
],
|
|
102
102
|
[".svelte", TRANSPILER2AVAILABLE.svelte],
|
|
@@ -9,7 +9,7 @@ const SCOPED_PACKAGE_RE = "@[^/]+(?:/[^/]+)";
|
|
|
9
9
|
const ROOT_MODULE_RE = new RegExp(`^(${SCOPED_PACKAGE_RE}|${PACKAGE_RE})`, "g");
|
|
10
10
|
|
|
11
11
|
function extractRootModuleName(pModuleName) {
|
|
12
|
-
return (pModuleName.match(ROOT_MODULE_RE) || []).shift();
|
|
12
|
+
return (pModuleName.match(ROOT_MODULE_RE) || /* c8 ignore next */ []).shift();
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
function getVersion(pModuleName) {
|
|
@@ -55,11 +55,53 @@ function isTypeOnlyExport(pStatement) {
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
/*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
58
|
+
* The extractImport* below take their statements from getStatements, because
|
|
59
|
+
* imports and exports are allowed in one place besides the top level: inside a
|
|
60
|
+
* module block, which is what `declare module "some-package" { ... }` and
|
|
61
|
+
* `declare namespace Thing { ... }` compile to.
|
|
61
62
|
*/
|
|
62
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Get the statements of the passed AST node, plus the statements of any module
|
|
66
|
+
* blocks nested in it
|
|
67
|
+
*
|
|
68
|
+
* @param {Node} pAST - an AST node with statements
|
|
69
|
+
* @returns {Node[]} - the node's statements, flattened over module blocks
|
|
70
|
+
*/
|
|
71
|
+
function getModuleBlock(pStatement) {
|
|
72
|
+
if (pStatement.kind !== typescript.SyntaxKind.ModuleDeclaration) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// A qualified name nests: `declare namespace A.B {}` is a ModuleDeclaration
|
|
77
|
+
// whose body is another ModuleDeclaration, and only the innermost one holds
|
|
78
|
+
// the block.
|
|
79
|
+
let lBody = pStatement.body;
|
|
80
|
+
|
|
81
|
+
while (lBody?.kind === typescript.SyntaxKind.ModuleDeclaration) {
|
|
82
|
+
lBody = lBody.body;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return lBody?.kind === typescript.SyntaxKind.ModuleBlock ? lBody : null;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function getStatements(pAST, pDetectImportsInAmbientModules) {
|
|
89
|
+
if (!pDetectImportsInAmbientModules) {
|
|
90
|
+
return pAST.statements ?? [];
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return (pAST.statements ?? []).flatMap((pStatement) => {
|
|
94
|
+
const lModuleBlock = getModuleBlock(pStatement);
|
|
95
|
+
|
|
96
|
+
return lModuleBlock
|
|
97
|
+
? [
|
|
98
|
+
pStatement,
|
|
99
|
+
...getStatements(lModuleBlock, pDetectImportsInAmbientModules),
|
|
100
|
+
]
|
|
101
|
+
: [pStatement];
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
63
105
|
/**
|
|
64
106
|
* Get all import statements from the top level AST node
|
|
65
107
|
*
|
|
@@ -67,8 +109,8 @@ function isTypeOnlyExport(pStatement) {
|
|
|
67
109
|
* @returns {{module: string; moduleSystem: string; exoticallyRequired: boolean; dependencyTypes?: string[];}[]} -
|
|
68
110
|
* all import statements in the (top level) AST node
|
|
69
111
|
*/
|
|
70
|
-
function extractImports(pAST) {
|
|
71
|
-
return pAST
|
|
112
|
+
function extractImports(pAST, pDetectImportsInAmbientModules) {
|
|
113
|
+
return getStatements(pAST, pDetectImportsInAmbientModules)
|
|
72
114
|
.filter(
|
|
73
115
|
(pStatement) =>
|
|
74
116
|
pStatement.kind === typescript.SyntaxKind.ImportDeclaration &&
|
|
@@ -91,8 +133,8 @@ function extractImports(pAST) {
|
|
|
91
133
|
* @returns {{module: string; moduleSystem: string; exoticallyRequired: boolean; dependencyTypes?: string[];}[]} -
|
|
92
134
|
* all export statements in the (top level) AST node
|
|
93
135
|
*/
|
|
94
|
-
function extractExports(pAST) {
|
|
95
|
-
return pAST
|
|
136
|
+
function extractExports(pAST, pDetectImportsInAmbientModules) {
|
|
137
|
+
return getStatements(pAST, pDetectImportsInAmbientModules)
|
|
96
138
|
.filter(
|
|
97
139
|
(pStatement) =>
|
|
98
140
|
pStatement.kind === typescript.SyntaxKind.ExportDeclaration &&
|
|
@@ -119,8 +161,8 @@ function extractExports(pAST) {
|
|
|
119
161
|
* @returns {{module: string, moduleSystem: string;exoticallyRequired: boolean;}[]} - all import equals statements in the
|
|
120
162
|
* (top level) AST node
|
|
121
163
|
*/
|
|
122
|
-
function extractImportEquals(pAST) {
|
|
123
|
-
return pAST
|
|
164
|
+
function extractImportEquals(pAST, pDetectImportsInAmbientModules) {
|
|
165
|
+
return getStatements(pAST, pDetectImportsInAmbientModules)
|
|
124
166
|
.filter(
|
|
125
167
|
(pStatement) =>
|
|
126
168
|
pStatement.kind === typescript.SyntaxKind.ImportEqualsDeclaration &&
|
|
@@ -562,11 +604,14 @@ export default function extractTypeScriptDependencies(
|
|
|
562
604
|
pExoticRequireStrings,
|
|
563
605
|
pDetectJSDocImports,
|
|
564
606
|
pDetectProcessBuiltinModuleCalls,
|
|
607
|
+
pDetectImportsInAmbientModules,
|
|
565
608
|
) {
|
|
566
609
|
return typescript
|
|
567
|
-
? extractImports(pTypeScriptAST)
|
|
568
|
-
.concat(extractExports(pTypeScriptAST))
|
|
569
|
-
.concat(
|
|
610
|
+
? extractImports(pTypeScriptAST, pDetectImportsInAmbientModules)
|
|
611
|
+
.concat(extractExports(pTypeScriptAST, pDetectImportsInAmbientModules))
|
|
612
|
+
.concat(
|
|
613
|
+
extractImportEquals(pTypeScriptAST, pDetectImportsInAmbientModules),
|
|
614
|
+
)
|
|
570
615
|
.concat(extractTripleSlashDirectives(pTypeScriptAST))
|
|
571
616
|
.concat(
|
|
572
617
|
extractNestedDependencies(
|
|
@@ -19,6 +19,7 @@ export function extract(
|
|
|
19
19
|
moduleSystems,
|
|
20
20
|
detectJSDocImports,
|
|
21
21
|
detectProcessBuiltinModuleCalls,
|
|
22
|
+
detectImportsInAmbientModules,
|
|
22
23
|
},
|
|
23
24
|
pFileName,
|
|
24
25
|
pTranspileOptions,
|
|
@@ -28,6 +29,7 @@ export function extract(
|
|
|
28
29
|
exoticRequireStrings,
|
|
29
30
|
detectJSDocImports,
|
|
30
31
|
detectProcessBuiltinModuleCalls,
|
|
32
|
+
detectImportsInAmbientModules,
|
|
31
33
|
).filter(({ moduleSystem }) => moduleSystems.includes(moduleSystem));
|
|
32
34
|
}
|
|
33
35
|
|
|
@@ -223,7 +223,10 @@ export function normalizeCruiseOptions(pOptions, pFileAndDirectoryArray = []) {
|
|
|
223
223
|
if (lReturnValue.cache) {
|
|
224
224
|
lReturnValue.cache = normalizeCacheOptions(lReturnValue.cache);
|
|
225
225
|
}
|
|
226
|
-
if (
|
|
226
|
+
if (
|
|
227
|
+
lReturnValue.detectJSDocImports ||
|
|
228
|
+
lReturnValue.detectImportsInAmbientModules
|
|
229
|
+
) {
|
|
227
230
|
lReturnValue.parser = "tsc";
|
|
228
231
|
}
|
|
229
232
|
|
package/src/meta.cjs
CHANGED
|
@@ -154,7 +154,8 @@ function formatResultMessage(pSummary) {
|
|
|
154
154
|
*/
|
|
155
155
|
function formatSummary(pSummary) {
|
|
156
156
|
return `##vso[task.complete result=${formatResultStatus(
|
|
157
|
-
|
|
157
|
+
// see below on the why of the fallback
|
|
158
|
+
pSummary.advisedExitCode ?? pSummary.error,
|
|
158
159
|
)};]${formatResultMessage(pSummary)}${EOL}`;
|
|
159
160
|
}
|
|
160
161
|
|
|
@@ -180,6 +181,9 @@ export default function azureDevOps(pResults) {
|
|
|
180
181
|
.map(formatViolation)
|
|
181
182
|
.join("")
|
|
182
183
|
.concat(formatSummary(pResults.summary)),
|
|
183
|
-
|
|
184
|
+
// advisedExitCode is a mandatory attribute as of dependency-cruiser 18.4.0
|
|
185
|
+
// however, this reporter can still encounter dependency-cruiser results
|
|
186
|
+
// from before that, hence the fallback
|
|
187
|
+
exitCode: pResults.summary.advisedExitCode ?? pResults.summary.error,
|
|
184
188
|
};
|
|
185
189
|
}
|
package/src/report/baseline.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { diffViolationArrays } from "#graph-utl/compare.mjs";
|
|
1
|
+
import { compareViolations, diffViolationArrays } from "#graph-utl/compare.mjs";
|
|
2
2
|
/**
|
|
3
3
|
* @import { ICruiseResult, IReporterOutput } from "../../types/dependency-cruiser.mjs";
|
|
4
4
|
* @import { IViolation} from "../../types/violations.mjs"
|
|
@@ -23,20 +23,35 @@ function getBaseline(pKnownViolations, pCurrentViolations, pMode) {
|
|
|
23
23
|
pCurrentViolations,
|
|
24
24
|
);
|
|
25
25
|
let lViolationsToEmit = pCurrentViolations;
|
|
26
|
-
let
|
|
26
|
+
let lModeAdditionTotal = "";
|
|
27
|
+
let lModeAdditionNew = " (running in 'full' mode => added to the baseline)";
|
|
28
|
+
let lModeAdditionOld =
|
|
29
|
+
" (running in 'full' mode => removed from the baseline)";
|
|
27
30
|
|
|
28
31
|
if (pMode === "shrink-only") {
|
|
29
32
|
lViolationsToEmit = lViolationArrayDiff.same;
|
|
30
|
-
|
|
33
|
+
lModeAdditionNew =
|
|
31
34
|
" (running in 'shrink-only' mode => not added to the baseline)";
|
|
35
|
+
lModeAdditionOld =
|
|
36
|
+
" (running in 'shrink-only' mode => removed from the baseline)";
|
|
37
|
+
}
|
|
38
|
+
if (pMode === "format") {
|
|
39
|
+
lViolationsToEmit = lKnownViolations;
|
|
40
|
+
lModeAdditionTotal = " (running in 'format' mode so no updates made)";
|
|
41
|
+
lModeAdditionNew = "";
|
|
42
|
+
lModeAdditionOld = "";
|
|
32
43
|
}
|
|
33
44
|
lReturnValue.meta =
|
|
34
|
-
`${EOL}baseline : ${lViolationsToEmit.length} violations${EOL}${EOL}` +
|
|
35
|
-
` new : ${lViolationArrayDiff.new.length}${lViolationArrayDiff.new.length > 0 ?
|
|
45
|
+
`${EOL}baseline : ${lViolationsToEmit.length} violations${lModeAdditionTotal}${EOL}${EOL}` +
|
|
46
|
+
` new : ${lViolationArrayDiff.new.length}${lViolationArrayDiff.new.length > 0 ? lModeAdditionNew : ""}${EOL}` +
|
|
36
47
|
` same : ${lViolationArrayDiff.same.length}${EOL}` +
|
|
37
|
-
`
|
|
48
|
+
` stale : ${lViolationArrayDiff.old.length}${lViolationArrayDiff.old.length > 0 ? lModeAdditionOld : ""}${EOL}`;
|
|
38
49
|
lReturnValue.output =
|
|
39
|
-
JSON.stringify(
|
|
50
|
+
JSON.stringify(
|
|
51
|
+
lViolationsToEmit.toSorted(compareViolations),
|
|
52
|
+
null,
|
|
53
|
+
DEFAULT_JSON_INDENT,
|
|
54
|
+
) + EOL;
|
|
40
55
|
|
|
41
56
|
return lReturnValue;
|
|
42
57
|
}
|
|
@@ -230,12 +230,14 @@ export default `<!DOCTYPE html>
|
|
|
230
230
|
<div style="float:left;padding-right:20px" class="ignore">
|
|
231
231
|
<strong>{{ignore}}</strong> ignored
|
|
232
232
|
</div>
|
|
233
|
+
{{staleDiv}}
|
|
233
234
|
|
|
234
235
|
</p>
|
|
235
236
|
{{violatedRulesTable}}
|
|
236
237
|
</span>
|
|
237
238
|
|
|
238
239
|
{{violationsList}}
|
|
240
|
+
{{baselineStaleTable}}
|
|
239
241
|
<footer>
|
|
240
242
|
<p><a href="https://github.com/sverweij/dependency-cruiser">{{depcruiseVersion}}</a> /
|
|
241
243
|
{{runDate}}</p>
|