dependency-cruiser 17.3.5 → 17.3.7
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/LICENSE +1 -1
- package/package.json +6 -4
- package/src/{enrich/enrich-modules.mjs → analyze/analyze-modules.mjs} +1 -1
- package/src/{enrich → analyze}/derive/dependents.mjs +14 -3
- package/src/{enrich → analyze}/index.mjs +3 -3
- package/src/cache/cache.mjs +9 -27
- package/src/cache/content-strategy.mjs +1 -1
- package/src/cache/helpers.mjs +16 -6
- package/src/cli/init-config/config-template.mjs +112 -145
- package/src/cli/init-config/find-extensions.mjs +4 -0
- package/src/cli/listeners/ndjson.mjs +16 -1
- package/src/config-utl/extract-depcruise-config/merge-configs.mjs +2 -2
- package/src/extract/acorn/parse.mjs +18 -25
- package/src/extract/resolve/external-module-helpers.mjs +9 -7
- package/src/extract/resolve/get-manifest.mjs +25 -13
- package/src/extract/resolve/resolve-amd.mjs +10 -5
- package/src/extract/resolve/resolve.mjs +4 -5
- package/src/extract/swc/parse.mjs +12 -8
- package/src/extract/tsc/parse.mjs +12 -15
- package/src/main/cruise.mjs +6 -6
- package/src/main/report-wrap.mjs +1 -1
- package/src/meta.cjs +1 -1
- package/src/report/anon/anonymize-path-element.mjs +11 -3
- package/src/report/dot/prepare-flat-level.mjs +12 -2
- package/src/report/plugins.mjs +1 -1
- package/src/report/teamcity.mjs +76 -58
- package/src/report/text.mjs +7 -7
- /package/src/{enrich → analyze}/add-validations.mjs +0 -0
- /package/src/{enrich → analyze}/derive/circular.mjs +0 -0
- /package/src/{enrich → analyze}/derive/folders/aggregate-to-folders.mjs +0 -0
- /package/src/{enrich → analyze}/derive/folders/index.mjs +0 -0
- /package/src/{enrich → analyze}/derive/folders/utl.mjs +0 -0
- /package/src/{enrich → analyze}/derive/metrics/get-module-metrics.mjs +0 -0
- /package/src/{enrich → analyze}/derive/metrics/index.mjs +0 -0
- /package/src/{enrich → analyze}/derive/module-utl.mjs +0 -0
- /package/src/{enrich → analyze}/derive/orphan/index.mjs +0 -0
- /package/src/{enrich → analyze}/derive/orphan/is-orphan.mjs +0 -0
- /package/src/{enrich → analyze}/derive/reachable.mjs +0 -0
- /package/src/{enrich → analyze}/soften-known-violations.mjs +0 -0
- /package/src/{enrich → analyze}/summarize/add-rule-set-used.mjs +0 -0
- /package/src/{enrich → analyze}/summarize/get-stats.mjs +0 -0
- /package/src/{enrich → analyze}/summarize/index.mjs +0 -0
- /package/src/{enrich → analyze}/summarize/is-same-violation.mjs +0 -0
- /package/src/{enrich → analyze}/summarize/summarize-folders.mjs +0 -0
- /package/src/{enrich → analyze}/summarize/summarize-modules.mjs +0 -0
- /package/src/{enrich → analyze}/summarize/summarize-options.mjs +0 -0
package/src/report/teamcity.mjs
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import { randomInt } from "node:crypto";
|
|
2
|
-
import memoize, { memoizeClear } from "memoize";
|
|
3
|
-
|
|
4
2
|
import { formatPercentage, formatViolation } from "./utl/index.mjs";
|
|
3
|
+
/** @import { IInspection, IInspectionType } from "./teamcity.types.ts" */
|
|
4
|
+
|
|
5
|
+
const CATEGORY = "dependency-cruiser";
|
|
6
|
+
const SEVERITY2TEAMCITY_SEVERITY = new Map([
|
|
7
|
+
["error", "ERROR"],
|
|
8
|
+
["warn", "WARNING"],
|
|
9
|
+
["info", "INFO"],
|
|
10
|
+
]);
|
|
11
|
+
const EOL = "\n";
|
|
5
12
|
|
|
6
13
|
/**
|
|
7
14
|
* Escape string for TeamCity output.
|
|
@@ -35,14 +42,15 @@ function escape(pMessageString) {
|
|
|
35
42
|
}
|
|
36
43
|
|
|
37
44
|
/**
|
|
38
|
-
* Returns a random flowId consisting of 10 numeric digits.
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
45
|
+
* Returns a random flowId consisting of 10 numeric digits.
|
|
46
|
+
*
|
|
47
|
+
* TeamCity doesn't seem to have demands on the format (it's just a string),
|
|
48
|
+
* but this is what teamcity-service-messages used, so as
|
|
49
|
+
* per the rule of least surprise, this is what we use as well.
|
|
42
50
|
*
|
|
43
|
-
* @return {string}
|
|
51
|
+
* @return {string} 10 random numeric digits
|
|
44
52
|
*/
|
|
45
|
-
function
|
|
53
|
+
function getRandomFlowId() {
|
|
46
54
|
const lFlowIdLength = 10;
|
|
47
55
|
// eslint-disable-next-line no-magic-numbers
|
|
48
56
|
const lFlowIdMax = 10 ** lFlowIdLength;
|
|
@@ -50,13 +58,10 @@ function getRandomFlowIdBare() {
|
|
|
50
58
|
return randomInt(1, lFlowIdMax).toString().padStart(lFlowIdLength, "0");
|
|
51
59
|
}
|
|
52
60
|
|
|
53
|
-
const getRandomFlowId = memoize(getRandomFlowIdBare);
|
|
54
|
-
|
|
55
61
|
/**
|
|
56
|
-
* Returns a timestamp in ISO format without the trailing 'Z'.
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
* this is still the case, but better safe than sorry.
|
|
62
|
+
* Returns a timestamp in ISO format without the trailing 'Z'. TeamCity
|
|
63
|
+
* didn't use the trailing 'Z' (documented in the teamcity-service-messages
|
|
64
|
+
* source) - not sure whether still the case, but better safe than sorry.
|
|
60
65
|
*
|
|
61
66
|
* @returns {string} a timestamp in ISO format without the trailing 'Z'
|
|
62
67
|
*/
|
|
@@ -64,101 +69,113 @@ function getTimeStamp() {
|
|
|
64
69
|
return new Date().toISOString().slice(0, -1);
|
|
65
70
|
}
|
|
66
71
|
|
|
67
|
-
|
|
72
|
+
/**
|
|
73
|
+
* formats an inspection type TeamCity service message
|
|
74
|
+
* @param {IInspectionType} pInspectionTypeData
|
|
75
|
+
* @returns {string}
|
|
76
|
+
*/
|
|
77
|
+
function formatInspectionType(pInspectionTypeData) {
|
|
68
78
|
const lAttributes = [];
|
|
69
79
|
lAttributes.push(
|
|
70
|
-
`id='${
|
|
71
|
-
`name='${
|
|
72
|
-
`description='${escape(
|
|
73
|
-
`category='${
|
|
74
|
-
`flowId='${
|
|
80
|
+
`id='${pInspectionTypeData.id}'`,
|
|
81
|
+
`name='${pInspectionTypeData.name}'`,
|
|
82
|
+
`description='${escape(pInspectionTypeData.description)}'`,
|
|
83
|
+
`category='${pInspectionTypeData.category}'`,
|
|
84
|
+
`flowId='${pInspectionTypeData.flowId}'`,
|
|
75
85
|
`timestamp='${getTimeStamp()}'`,
|
|
76
86
|
);
|
|
77
87
|
return `##teamcity[inspectionType ${lAttributes.join(" ")}]`;
|
|
78
88
|
}
|
|
79
89
|
|
|
80
|
-
|
|
90
|
+
/**
|
|
91
|
+
* formats an inspection TeamCity service message
|
|
92
|
+
* @param {IInspection} pInspectionData
|
|
93
|
+
* @returns {string}
|
|
94
|
+
*/
|
|
95
|
+
function formatInspection(pInspectionData) {
|
|
81
96
|
const lAttributes = [];
|
|
82
97
|
lAttributes.push(
|
|
83
|
-
`typeId='${
|
|
84
|
-
`message='${escape(
|
|
98
|
+
`typeId='${pInspectionData.typeId}'`,
|
|
99
|
+
`message='${escape(pInspectionData.message)}'`,
|
|
85
100
|
);
|
|
86
|
-
if (
|
|
87
|
-
lAttributes.push(`file='${
|
|
101
|
+
if (pInspectionData.file) {
|
|
102
|
+
lAttributes.push(`file='${pInspectionData.file}'`);
|
|
88
103
|
}
|
|
89
104
|
lAttributes.push(
|
|
90
|
-
`SEVERITY='${
|
|
91
|
-
`flowId='${
|
|
105
|
+
`SEVERITY='${pInspectionData.SEVERITY}'`,
|
|
106
|
+
`flowId='${pInspectionData.flowId}'`,
|
|
92
107
|
`timestamp='${getTimeStamp()}'`,
|
|
93
108
|
);
|
|
94
109
|
|
|
95
110
|
return `##teamcity[inspection ${lAttributes.join(" ")}]`;
|
|
96
111
|
}
|
|
97
112
|
|
|
98
|
-
const CATEGORY = "dependency-cruiser";
|
|
99
|
-
const SEVERITY2TEAMCITY_SEVERITY = new Map([
|
|
100
|
-
["error", "ERROR"],
|
|
101
|
-
["warn", "WARNING"],
|
|
102
|
-
["info", "INFO"],
|
|
103
|
-
]);
|
|
104
|
-
const EOL = "\n";
|
|
105
|
-
|
|
106
113
|
function severity2teamcitySeverity(pSeverity) {
|
|
107
114
|
return SEVERITY2TEAMCITY_SEVERITY.get(pSeverity) || "INFO";
|
|
108
115
|
}
|
|
109
116
|
|
|
110
|
-
function reportRules(pRules, pViolations) {
|
|
117
|
+
function reportRules(pRules, pViolations, pFlowId) {
|
|
111
118
|
return pRules
|
|
112
119
|
.filter((pRule) =>
|
|
113
120
|
pViolations.some((pViolation) => pRule.name === pViolation.rule.name),
|
|
114
121
|
)
|
|
115
122
|
.map((pRule) =>
|
|
116
|
-
|
|
123
|
+
formatInspectionType({
|
|
117
124
|
id: pRule.name,
|
|
118
125
|
name: pRule.name,
|
|
119
126
|
description: pRule.comment || pRule.name,
|
|
120
127
|
category: CATEGORY,
|
|
128
|
+
flowId: pFlowId,
|
|
121
129
|
}),
|
|
122
130
|
);
|
|
123
131
|
}
|
|
124
132
|
|
|
125
|
-
function reportAllowedRule(pAllowedRule, pViolations) {
|
|
133
|
+
function reportAllowedRule(pAllowedRule, pViolations, pFlowId) {
|
|
126
134
|
let lReturnValue = [];
|
|
127
135
|
|
|
128
136
|
if (
|
|
129
137
|
pAllowedRule.length > 0 &&
|
|
130
138
|
pViolations.some((pViolation) => pViolation.rule.name === "not-in-allowed")
|
|
131
139
|
) {
|
|
132
|
-
lReturnValue =
|
|
140
|
+
lReturnValue = formatInspectionType({
|
|
133
141
|
id: "not-in-allowed",
|
|
134
142
|
name: "not-in-allowed",
|
|
135
143
|
description: "dependency is not in the 'allowed' set of rules",
|
|
136
144
|
category: CATEGORY,
|
|
145
|
+
flowId: pFlowId,
|
|
137
146
|
});
|
|
138
147
|
}
|
|
139
148
|
return lReturnValue;
|
|
140
149
|
}
|
|
141
150
|
|
|
142
|
-
function reportIgnoredRules(pIgnoredCount) {
|
|
151
|
+
function reportIgnoredRules(pIgnoredCount, pFlowId) {
|
|
143
152
|
let lReturnValue = [];
|
|
144
153
|
|
|
145
154
|
if (pIgnoredCount > 0) {
|
|
146
|
-
lReturnValue =
|
|
155
|
+
lReturnValue = formatInspectionType({
|
|
147
156
|
id: "ignored-known-violations",
|
|
148
157
|
name: "ignored-known-violations",
|
|
149
158
|
description:
|
|
150
159
|
"some dependency violations were ignored; run with --no-ignore-known to see them",
|
|
151
160
|
category: CATEGORY,
|
|
161
|
+
flowId: pFlowId,
|
|
152
162
|
});
|
|
153
163
|
}
|
|
154
164
|
return lReturnValue;
|
|
155
165
|
}
|
|
156
166
|
|
|
157
|
-
function reportViolatedRules(
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
167
|
+
function reportViolatedRules(
|
|
168
|
+
pRuleSetUsed,
|
|
169
|
+
pViolations,
|
|
170
|
+
pIgnoredCount,
|
|
171
|
+
pFlowId,
|
|
172
|
+
) {
|
|
173
|
+
return reportRules(pRuleSetUsed?.forbidden ?? [], pViolations, pFlowId)
|
|
174
|
+
.concat(
|
|
175
|
+
reportAllowedRule(pRuleSetUsed?.allowed ?? [], pViolations, pFlowId),
|
|
176
|
+
)
|
|
177
|
+
.concat(reportRules(pRuleSetUsed?.required ?? [], pViolations, pFlowId))
|
|
178
|
+
.concat(reportIgnoredRules(pIgnoredCount, pFlowId));
|
|
162
179
|
}
|
|
163
180
|
|
|
164
181
|
function formatModuleViolation(pViolation) {
|
|
@@ -204,12 +221,13 @@ function bakeViolationMessage(pViolation) {
|
|
|
204
221
|
);
|
|
205
222
|
}
|
|
206
223
|
|
|
207
|
-
function reportIgnoredViolation(pIgnoredCount) {
|
|
224
|
+
function reportIgnoredViolation(pIgnoredCount, pFlowId) {
|
|
208
225
|
let lReturnValue = [];
|
|
209
226
|
|
|
210
227
|
if (pIgnoredCount > 0) {
|
|
211
|
-
lReturnValue =
|
|
228
|
+
lReturnValue = formatInspection({
|
|
212
229
|
typeId: "ignored-known-violations",
|
|
230
|
+
flowId: pFlowId,
|
|
213
231
|
message: `${pIgnoredCount} known violations ignored. Run with --no-ignore-known to see them.`,
|
|
214
232
|
SEVERITY: "WARNING",
|
|
215
233
|
});
|
|
@@ -217,17 +235,18 @@ function reportIgnoredViolation(pIgnoredCount) {
|
|
|
217
235
|
return lReturnValue;
|
|
218
236
|
}
|
|
219
237
|
|
|
220
|
-
function reportViolations(pViolations, pIgnoredCount) {
|
|
238
|
+
function reportViolations(pViolations, pIgnoredCount, pFlowId) {
|
|
221
239
|
return pViolations
|
|
222
240
|
.map((pViolation) =>
|
|
223
|
-
|
|
241
|
+
formatInspection({
|
|
224
242
|
typeId: pViolation.rule.name,
|
|
243
|
+
flowId: pFlowId,
|
|
225
244
|
message: bakeViolationMessage(pViolation),
|
|
226
245
|
file: pViolation.from,
|
|
227
246
|
SEVERITY: severity2teamcitySeverity(pViolation.rule.severity),
|
|
228
247
|
}),
|
|
229
248
|
)
|
|
230
|
-
.concat(reportIgnoredViolation(pIgnoredCount));
|
|
249
|
+
.concat(reportIgnoredViolation(pIgnoredCount, pFlowId));
|
|
231
250
|
}
|
|
232
251
|
|
|
233
252
|
/**
|
|
@@ -237,13 +256,12 @@ function reportViolations(pViolations, pIgnoredCount) {
|
|
|
237
256
|
* - for each violation in the passed results: an `inspection` with the
|
|
238
257
|
* violated rule name and the tos and froms
|
|
239
258
|
*
|
|
240
|
-
* @param {import("../../types/dependency-cruiser.
|
|
241
|
-
* @returns {import("../../types/dependency-cruiser.
|
|
259
|
+
* @param {import("../../types/dependency-cruiser.mjs").ICruiseResult} pResults
|
|
260
|
+
* @returns {import("../../types/dependency-cruiser.mjs").IReporterOutput}
|
|
242
261
|
*/
|
|
243
262
|
// eslint-disable-next-line complexity
|
|
244
263
|
export default function teamcity(pResults) {
|
|
245
|
-
|
|
246
|
-
|
|
264
|
+
const lFlowId = getRandomFlowId();
|
|
247
265
|
const lRuleSet = pResults?.summary?.ruleSetUsed ?? [];
|
|
248
266
|
const lViolations = (pResults?.summary?.violations ?? []).filter(
|
|
249
267
|
(pViolation) => pViolation.rule.severity !== "ignore",
|
|
@@ -252,9 +270,9 @@ export default function teamcity(pResults) {
|
|
|
252
270
|
|
|
253
271
|
return {
|
|
254
272
|
output:
|
|
255
|
-
reportViolatedRules(lRuleSet, lViolations, lIgnoredCount)
|
|
256
|
-
.concat(reportViolations(lViolations, lIgnoredCount))
|
|
257
|
-
.reduce((pAll, pCurrent) => `${pAll}${pCurrent}
|
|
273
|
+
reportViolatedRules(lRuleSet, lViolations, lIgnoredCount, lFlowId)
|
|
274
|
+
.concat(reportViolations(lViolations, lIgnoredCount, lFlowId))
|
|
275
|
+
.reduce((pAll, pCurrent) => `${pAll}${pCurrent}${EOL}`, "") || EOL,
|
|
258
276
|
exitCode: pResults.summary.error,
|
|
259
277
|
};
|
|
260
278
|
}
|
package/src/report/text.mjs
CHANGED
|
@@ -7,7 +7,7 @@ const EOL = "\n";
|
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
*
|
|
10
|
-
* @param {import("../../types/cruise-result").IModule} pModule
|
|
10
|
+
* @param {import("../../types/cruise-result.mjs").IModule} pModule
|
|
11
11
|
* @param {Set<string>} pModulesInFocus
|
|
12
12
|
* @param {boolean} pHighlightFocused
|
|
13
13
|
* @returns {any}
|
|
@@ -47,7 +47,7 @@ function stringify(pFlatDependency) {
|
|
|
47
47
|
|
|
48
48
|
/**
|
|
49
49
|
*
|
|
50
|
-
* @param {import("../../types/cruise-result").IModule[]} pModules
|
|
50
|
+
* @param {import("../../types/cruise-result.mjs").IModule[]} pModules
|
|
51
51
|
* @returns {Set<string>}
|
|
52
52
|
*/
|
|
53
53
|
function getModulesInFocus(pModules) {
|
|
@@ -60,8 +60,8 @@ function getModulesInFocus(pModules) {
|
|
|
60
60
|
|
|
61
61
|
/**
|
|
62
62
|
*
|
|
63
|
-
* @param {import("../../types/cruise-result").ICruiseResult} pResults
|
|
64
|
-
* @param {import("../../types/reporter-options").ITextReporterOptions} pOptions
|
|
63
|
+
* @param {import("../../types/cruise-result.mjs").ICruiseResult} pResults
|
|
64
|
+
* @param {import("../../types/reporter-options.mjs").ITextReporterOptions} pOptions
|
|
65
65
|
* @returns {string}
|
|
66
66
|
*/
|
|
67
67
|
function report(pResults, pOptions) {
|
|
@@ -82,9 +82,9 @@ function report(pResults, pOptions) {
|
|
|
82
82
|
/**
|
|
83
83
|
* Returns the results of a cruise in a text only format
|
|
84
84
|
* - for each dependency the from and the two, separated by an arrow.
|
|
85
|
-
* @param {import("../../types/cruise-result").ICruiseResult} pResults
|
|
86
|
-
* @param {import("../../types/reporter-options").ITextReporterOptions} pOptions
|
|
87
|
-
* @returns {import("../../types/dependency-cruiser").IReporterOutput}
|
|
85
|
+
* @param {import("../../types/cruise-result.mjs").ICruiseResult} pResults
|
|
86
|
+
* @param {import("../../types/reporter-options.mjs").ITextReporterOptions} pOptions
|
|
87
|
+
* @returns {import("../../types/dependency-cruiser.mjs").IReporterOutput}
|
|
88
88
|
*/
|
|
89
89
|
export default function text(pResults, pOptions) {
|
|
90
90
|
return {
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|