dependency-cruiser 17.0.0 → 17.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/package.json +1 -2
- package/src/meta.cjs +1 -1
- package/src/report/teamcity.mjs +105 -15
- package/types/shared-types.d.mts +1 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dependency-cruiser",
|
|
3
|
-
"version": "17.0.
|
|
3
|
+
"version": "17.0.1",
|
|
4
4
|
"description": "Validate and visualize dependencies. With your rules. JavaScript, TypeScript, CoffeeScript. ES6, CommonJS, AMD.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"static analysis",
|
|
@@ -158,7 +158,6 @@
|
|
|
158
158
|
"rechoir": "^0.8.0",
|
|
159
159
|
"safe-regex": "^2.1.1",
|
|
160
160
|
"semver": "^7.7.2",
|
|
161
|
-
"teamcity-service-messages": "^0.1.14",
|
|
162
161
|
"tsconfig-paths-webpack-plugin": "^4.2.0",
|
|
163
162
|
"watskeburt": "^4.2.3"
|
|
164
163
|
},
|
package/src/meta.cjs
CHANGED
package/src/report/teamcity.mjs
CHANGED
|
@@ -1,6 +1,100 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { randomInt } from "node:crypto";
|
|
2
|
+
import memoize, { memoizeClear } from "memoize";
|
|
3
|
+
|
|
2
4
|
import { formatPercentage, formatViolation } from "./utl/index.mjs";
|
|
3
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Escape string for TeamCity output.
|
|
8
|
+
* @see https://confluence.jetbrains.com/display/TCD65/Build+Script+Interaction+with+TeamCity#BuildScriptInteractionwithTeamCity-servMsgsServiceMessages
|
|
9
|
+
* Copied from https://github.com/pifantastic/teamcity-service-messages/blob/master/lib/message.js#L72
|
|
10
|
+
*
|
|
11
|
+
* @param {String} pMessageString the string to escape
|
|
12
|
+
* @return {String}
|
|
13
|
+
*/
|
|
14
|
+
function escape(pMessageString) {
|
|
15
|
+
if (pMessageString === null) {
|
|
16
|
+
return "";
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
pMessageString
|
|
21
|
+
.toString()
|
|
22
|
+
.replace(/\|/g, "||")
|
|
23
|
+
.replace(/\n/g, "|n")
|
|
24
|
+
.replace(/\r/g, "|r")
|
|
25
|
+
.replace(/\[/g, "|[")
|
|
26
|
+
.replace(/\]/g, "|]")
|
|
27
|
+
// next line
|
|
28
|
+
.replace(/\u0085/g, "|x")
|
|
29
|
+
// line separator
|
|
30
|
+
.replace(/\u2028/g, "|l")
|
|
31
|
+
// paragraph separator
|
|
32
|
+
.replace(/\u2029/g, "|p")
|
|
33
|
+
.replace(/'/g, "|'")
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Returns a random flowId consisting of 10 numeric digits. TeamCity doesn't
|
|
39
|
+
* currently seem to have demands on the format (it's just a string as far
|
|
40
|
+
* as I can tell), but this is what teamcity-service-messages used, so as
|
|
41
|
+
* per the rule of least surprise, this is what we use.
|
|
42
|
+
*
|
|
43
|
+
* @return {string} a random flowId consisting of 10 numeric digits
|
|
44
|
+
*/
|
|
45
|
+
function getRandomFlowIdBare() {
|
|
46
|
+
const lFlowIdLength = 10;
|
|
47
|
+
// eslint-disable-next-line no-magic-numbers
|
|
48
|
+
const lFlowIdMax = 10 ** lFlowIdLength;
|
|
49
|
+
|
|
50
|
+
return randomInt(1, lFlowIdMax).toString().padStart(lFlowIdLength, "0");
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const getRandomFlowId = memoize(getRandomFlowIdBare);
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Returns a timestamp in ISO format without the trailing 'Z'. It used to be
|
|
57
|
+
* an issue with TeamCity that it didn't use the trailing 'Z' (this is
|
|
58
|
+
* documented in the teamcity-service-messages source code) - not sure whether
|
|
59
|
+
* this is still the case, but this is what we do to be on the safe side.
|
|
60
|
+
*
|
|
61
|
+
* @returns {string} a timestamp in ISO format without the trailing 'Z'
|
|
62
|
+
*/
|
|
63
|
+
function getTimeStamp() {
|
|
64
|
+
return new Date().toISOString().slice(0, -1);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function inspectionType(pData) {
|
|
68
|
+
const lAttributes = [];
|
|
69
|
+
lAttributes.push(
|
|
70
|
+
`id='${pData.id}'`,
|
|
71
|
+
`name='${pData.name}'`,
|
|
72
|
+
`description='${escape(pData.description)}'`,
|
|
73
|
+
`category='${pData.category}'`,
|
|
74
|
+
`flowId='${getRandomFlowId()}'`,
|
|
75
|
+
`timestamp='${getTimeStamp()}'`,
|
|
76
|
+
);
|
|
77
|
+
return `##teamcity[inspectionType ${lAttributes.join(" ")}]`;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function inspection(pData) {
|
|
81
|
+
const lAttributes = [];
|
|
82
|
+
lAttributes.push(
|
|
83
|
+
`typeId='${pData.typeId}'`,
|
|
84
|
+
`message='${escape(pData.message)}'`,
|
|
85
|
+
);
|
|
86
|
+
if (pData.file) {
|
|
87
|
+
lAttributes.push(`file='${pData.file}'`);
|
|
88
|
+
}
|
|
89
|
+
lAttributes.push(
|
|
90
|
+
`SEVERITY='${pData.SEVERITY}'`,
|
|
91
|
+
`flowId='${getRandomFlowId()}'`,
|
|
92
|
+
`timestamp='${getTimeStamp()}'`,
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
return `##teamcity[inspection ${lAttributes.join(" ")}]`;
|
|
96
|
+
}
|
|
97
|
+
|
|
4
98
|
const CATEGORY = "dependency-cruiser";
|
|
5
99
|
const SEVERITY2TEAMCITY_SEVERITY = new Map([
|
|
6
100
|
["error", "ERROR"],
|
|
@@ -19,7 +113,7 @@ function reportRules(pRules, pViolations) {
|
|
|
19
113
|
pViolations.some((pViolation) => pRule.name === pViolation.rule.name),
|
|
20
114
|
)
|
|
21
115
|
.map((pRule) =>
|
|
22
|
-
|
|
116
|
+
inspectionType({
|
|
23
117
|
id: pRule.name,
|
|
24
118
|
name: pRule.name,
|
|
25
119
|
description: pRule.comment || pRule.name,
|
|
@@ -35,7 +129,7 @@ function reportAllowedRule(pAllowedRule, pViolations) {
|
|
|
35
129
|
pAllowedRule.length > 0 &&
|
|
36
130
|
pViolations.some((pViolation) => pViolation.rule.name === "not-in-allowed")
|
|
37
131
|
) {
|
|
38
|
-
lReturnValue =
|
|
132
|
+
lReturnValue = inspectionType({
|
|
39
133
|
id: "not-in-allowed",
|
|
40
134
|
name: "not-in-allowed",
|
|
41
135
|
description: "dependency is not in the 'allowed' set of rules",
|
|
@@ -49,7 +143,7 @@ function reportIgnoredRules(pIgnoredCount) {
|
|
|
49
143
|
let lReturnValue = [];
|
|
50
144
|
|
|
51
145
|
if (pIgnoredCount > 0) {
|
|
52
|
-
lReturnValue =
|
|
146
|
+
lReturnValue = inspectionType({
|
|
53
147
|
id: "ignored-known-violations",
|
|
54
148
|
name: "ignored-known-violations",
|
|
55
149
|
description:
|
|
@@ -114,7 +208,7 @@ function reportIgnoredViolation(pIgnoredCount) {
|
|
|
114
208
|
let lReturnValue = [];
|
|
115
209
|
|
|
116
210
|
if (pIgnoredCount > 0) {
|
|
117
|
-
lReturnValue =
|
|
211
|
+
lReturnValue = inspection({
|
|
118
212
|
typeId: "ignored-known-violations",
|
|
119
213
|
message: `${pIgnoredCount} known violations ignored. Run with --no-ignore-known to see them.`,
|
|
120
214
|
SEVERITY: "WARNING",
|
|
@@ -126,7 +220,7 @@ function reportIgnoredViolation(pIgnoredCount) {
|
|
|
126
220
|
function reportViolations(pViolations, pIgnoredCount) {
|
|
127
221
|
return pViolations
|
|
128
222
|
.map((pViolation) =>
|
|
129
|
-
|
|
223
|
+
inspection({
|
|
130
224
|
typeId: pViolation.rule.name,
|
|
131
225
|
message: bakeViolationMessage(pViolation),
|
|
132
226
|
file: pViolation.from,
|
|
@@ -138,21 +232,17 @@ function reportViolations(pViolations, pIgnoredCount) {
|
|
|
138
232
|
|
|
139
233
|
/**
|
|
140
234
|
* Returns a bunch of TeamCity service messages:
|
|
141
|
-
* - for each violated rule in the passed results: an `inspectionType` with the
|
|
142
|
-
*
|
|
235
|
+
* - for each violated rule in the passed results: an `inspectionType` with the
|
|
236
|
+
* name and comment of that rule
|
|
237
|
+
* - for each violation in the passed results: an `inspection` with the
|
|
238
|
+
* violated rule name and the tos and froms
|
|
143
239
|
*
|
|
144
240
|
* @param {import("../../types/dependency-cruiser.js").ICruiseResult} pResults
|
|
145
241
|
* @returns {import("../../types/dependency-cruiser.js").IReporterOutput}
|
|
146
242
|
*/
|
|
147
243
|
// eslint-disable-next-line complexity
|
|
148
244
|
export default function teamcity(pResults) {
|
|
149
|
-
|
|
150
|
-
// Alternatively we could've used the 'low level API', which
|
|
151
|
-
// involves creating new `Message`s and stringifying those.
|
|
152
|
-
// The abstraction of the 'higher level API' makes this
|
|
153
|
-
// reporter more easy to implement and maintain, despite
|
|
154
|
-
// setting this property directly
|
|
155
|
-
tsm.stdout = false;
|
|
245
|
+
memoizeClear(getRandomFlowId);
|
|
156
246
|
|
|
157
247
|
const lRuleSet = pResults?.summary?.ruleSetUsed ?? [];
|
|
158
248
|
const lViolations = (pResults?.summary?.violations ?? []).filter(
|
package/types/shared-types.d.mts
CHANGED
|
@@ -2,10 +2,6 @@
|
|
|
2
2
|
export type ModuleSystemType = "cjs" | "amd" | "es6" | "tsd";
|
|
3
3
|
|
|
4
4
|
// cruise options, dependency-cruiser
|
|
5
|
-
/* as we don't care about types beyond code completion, we ignore the
|
|
6
|
-
* eslint warning that the 'string' type is redundant here.
|
|
7
|
-
*/
|
|
8
|
-
/* eslint-disable @typescript-eslint/no-redundant-type-constituents */
|
|
9
5
|
export type OutputType =
|
|
10
6
|
| "json"
|
|
11
7
|
| "html"
|
|
@@ -29,7 +25,7 @@ export type OutputType =
|
|
|
29
25
|
| "null"
|
|
30
26
|
// for plugins: string. TODO: research whether it's possible to
|
|
31
27
|
// tie this down to the `^plugin:[^:]+-reporter-plugin.[cm]?js$` regex
|
|
32
|
-
| string;
|
|
28
|
+
| (string & {}); // autocompletion hack
|
|
33
29
|
|
|
34
30
|
export type SeverityType = "error" | "warn" | "info" | "ignore";
|
|
35
31
|
|