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.
Files changed (36) hide show
  1. package/README.md +1 -1
  2. package/bin/dependency-cruiser.mjs +2 -2
  3. package/package.json +4 -4
  4. package/src/analyze/summarize/get-stats.mjs +38 -3
  5. package/src/analyze/summarize/index.mjs +30 -6
  6. package/src/analyze/summarize/summarize-options.mjs +1 -0
  7. package/src/cache/cache.mjs +1 -1
  8. package/src/cache/options-compatible.mjs +2 -0
  9. package/src/cli/init-config/build-config.mjs +14 -0
  10. package/src/cli/init-config/config-template.mjs +5 -0
  11. package/src/cli/init-config/environment-helpers.mjs +5 -1
  12. package/src/cli/init-config/get-user-input.mjs +11 -0
  13. package/src/cli/init-config/index.mjs +1 -0
  14. package/src/cli/init-config/normalize-init-options.mjs +1 -1
  15. package/src/cli/init-config/types.d.mts +4 -0
  16. package/src/cli/init-config/write-run-scripts-to-manifest.mjs +2 -2
  17. package/src/extract/transpile/meta.mjs +2 -2
  18. package/src/extract/transpile/try-import-available.mjs +1 -1
  19. package/src/extract/tsc/extract-typescript-deps.mjs +57 -12
  20. package/src/extract/tsc/extract.mjs +2 -0
  21. package/src/main/options/defaults.mjs +1 -0
  22. package/src/main/options/normalize.mjs +4 -1
  23. package/src/meta.cjs +1 -1
  24. package/src/report/azure-devops.mjs +6 -2
  25. package/src/report/baseline.mjs +22 -7
  26. package/src/report/error-html/error-html-template.mjs +2 -0
  27. package/src/report/error-html/index.mjs +84 -8
  28. package/src/report/error.mjs +62 -13
  29. package/src/report/markdown.mjs +89 -19
  30. package/src/report/null.mjs +6 -3
  31. package/src/report/teamcity.mjs +4 -1
  32. package/src/schema/configuration.validate.mjs +1 -1
  33. package/src/schema/cruise-result.validate.mjs +1 -1
  34. package/types/cruise-result.d.mts +14 -0
  35. package/types/options.d.mts +21 -2
  36. package/types/reporter-options.d.mts +30 -5
@@ -6,6 +6,12 @@ import {
6
6
  import template from "./error-html-template.mjs";
7
7
  import meta from "#meta.cjs";
8
8
  import { getOneLetterDependencyType } from "#report/utl/index.mjs";
9
+ import { diffViolationArrays } from "#graph-utl/compare.mjs";
10
+ /**
11
+ * @import { ICruiseResult, IViolation } from "../../../types/cruise-result.mjs"
12
+ * @import { IErrorReporterOptions } from "../../../types/reporter-options.mjs"
13
+ * @import { IReporterOutput } from "../../../types/dependency-cruiser.mjs"
14
+ */
9
15
 
10
16
  function getViolatedRuleRowClass(pViolatedRule) {
11
17
  return pViolatedRule.unviolated ? ' class="unviolated"' : "";
@@ -34,7 +40,7 @@ function buildViolatedRuleRow(pViolatedRule) {
34
40
  }
35
41
 
36
42
  /**
37
- * @param {import('../../../types/cruise-result.mjs')} pResults
43
+ * @param {ICruiseResult} pResults
38
44
  * @returns {string}
39
45
  */
40
46
  function constructViolatedRulesTable(pResults) {
@@ -71,15 +77,17 @@ function constructViolatedRulesTable(pResults) {
71
77
  }
72
78
 
73
79
  /**
74
- * @param {import('../../../types/cruise-result.mjs').IViolation} pViolation
80
+ * @param {IViolation} pViolation
75
81
  * @returns {string}
76
82
  */
77
83
  function getViolationRowClass(pViolation) {
78
84
  return pViolation.rule.severity === "ignore" ? ' class="ignored"' : "";
79
85
  }
86
+
80
87
  /**
81
- * @param {import('../../../types/cruise-result.mjs').IViolation} pViolation
82
- * @returns {string}
88
+ * @param {string} pPrefix
89
+ * @param {IErrorReporterOptions} pOptions
90
+ * @returns {(pViolation: IViolation) => string}
83
91
  */
84
92
  function constructViolationRow(pPrefix, pOptions) {
85
93
  return (pViolation) => {
@@ -101,7 +109,8 @@ function constructViolationRow(pPrefix, pOptions) {
101
109
  }
102
110
 
103
111
  /**
104
- * @param {import('../../../types/cruise-result.mjs').ICruiseResult} pResults
112
+ * @param {ICruiseResult} pResults
113
+ * @param {IErrorReporterOptions} pOptions
105
114
  * @returns {string}
106
115
  */
107
116
  function constructViolationsList(pResults, pOptions) {
@@ -154,7 +163,68 @@ function constructViolationsList(pResults, pOptions) {
154
163
  }
155
164
 
156
165
  /**
157
- * @param {import('../../../types/cruise-result.mjs')} pResults
166
+ * @param {number} pBaselineStaleCount
167
+ * @returns {string}
168
+ */
169
+ function constructStaleDiv(pBaselineStaleCount) {
170
+ if ((pBaselineStaleCount ?? 0) > 0) {
171
+ return `<div style="float:left;padding-right:20px" class="ignore">
172
+ <strong>${pBaselineStaleCount}</strong> stale entries in baseline
173
+ </div>`;
174
+ }
175
+ return "";
176
+ }
177
+
178
+ /**
179
+ * @param {ICruiseResult} pResults
180
+ * @param {IErrorReporterOptions} pOptions
181
+ * @returns {string}
182
+ */
183
+ function constructBaselineStaleTable(pResults, pOptions) {
184
+ if ((pResults.summary.baselineStale ?? 0) > 0) {
185
+ const { old } = diffViolationArrays(
186
+ pResults.summary.optionsUsed.knownViolations,
187
+ pResults.summary.violations,
188
+ );
189
+ return `<span id="stale-baseline-entries">
190
+ <h2><svg class="p__svg--inline" viewBox="144 144 512 512" version="1.1" aria-hidden="true"><path d="M583.48 299.64a202 202 0 0 0-108.32-109.58 194.4 194.4 0 0 0-150.29 0 202.3 202.3 0 0 0-123.43 186.4v224.26a25.2 25.2 0 0 0 5.04 14.7q4.46.63 8.96.61c8.52.2 16.98-1.52 24.74-5.04a89 89 0 0 0 26.8-22.57c2.57-2.82 5.04-5.54 7.66-8.06 3.6-3.67 7.7-6.84 12.14-9.42a41 41 0 0 1 20.81-5.04c19.75 0 29.43 10.53 40.6 22.73a101 101 0 0 0 22.58 20.15 63 63 0 0 0 4.48 2.42 60.4 60.4 0 0 0 49.48 0q2.33-1.08 4.43-2.37c8.5-5.54 16.1-12.34 22.57-20.15 11.18-12.2 20.86-22.73 40.6-22.73A41 41 0 0 1 513.2 571a58 58 0 0 1 12.15 9.42 132 132 0 0 1 7.65 8.07 89 89 0 0 0 27 22.36 57 57 0 0 0 24.75 5.04q4.53 0 9.01-.6c3.2-4.25 4.95-9.4 5.04-14.71v-224.1a202 202 0 0 0-15.32-76.83zm0 124.74v176.33c-18.9-.45-28.41-10.73-39.35-22.67-2.42-2.62-5.04-5.34-7.5-7.96a83 83 0 0 0-11.44-9.73 55.4 55.4 0 0 0-32.8-10.07c-26.4 0-39.9 14.71-51.74 27.66s-20.9 23.02-40.65 23.02-29.43-10.53-40.61-22.72-25.2-27.66-51.74-27.66a55.4 55.4 0 0 0-32.75 10.08 83 83 0 0 0-11.44 9.72c-2.62 2.62-5.04 5.34-7.56 7.96-10.93 11.94-20.45 22.17-39.3 22.67V376.46c0-102.78 82.33-186.4 183.5-186.4 101.16 0 183.49 83.63 183.49 186.4z"/><path d="M511.69 280.75a59.6 59.6 0 1 0 59.6 63.83q.4-3.98 0-7.95a59.55 59.55 0 0 0-59.6-55.88m-44.53 59.65a44.45 44.45 0 0 1 66.1-38.84h-.91a38.92 38.92 0 0 0 0 77.84h.9a44.45 44.45 0 0 1-66.1-38.84zm-38.59-3.98a59.6 59.6 0 1 0 0 7.96q.4-3.99 0-7.96m-104.14 3.98a44.44 44.44 0 0 1 66.1-38.84h-.6a38.91 38.91 0 1 0 0 77.84h.9a44.45 44.45 0 0 1-66.4-39"/>
191
+ </svg> Stale entries in the baseline</h2>
192
+ <p>
193
+ These violations are in the baseline (typically <tt>.dependency-cruiser-known-violations.json</tt>),
194
+ but don't match any real violations anymore, e.g. because they were fixed in the meantime. You
195
+ can remove them with dependency-cruiser's
196
+ <a href="https://github.com/sverweij/dependency-cruiser/blob/main/doc/cli.md#--baseline-create-or-update-a-known-violations-baseline"><tt>--baseline --baseline-mode shrink-only</tt>
197
+ command line options</a>.
198
+ </p>
199
+ <table>
200
+ <thead>
201
+ <tr>
202
+ <th>severity</th>
203
+ <th>rule</th>
204
+ <th>from</th>
205
+ <th>types</th>
206
+ <th>to</th>
207
+ </tr>
208
+ </thead>
209
+ <tbody>
210
+ ${old
211
+ .map(
212
+ constructViolationRow(
213
+ pResults.summary.optionsUsed.prefix ?? "",
214
+ pOptions,
215
+ ),
216
+ )
217
+ .join("\n")}
218
+ </tbody>
219
+ </table>
220
+ </span>`;
221
+ }
222
+ return "";
223
+ }
224
+
225
+ /**
226
+ * @param {ICruiseResult} pResults
227
+ * @param {IErrorReporterOptions} pOptions
158
228
  * @returns {string}
159
229
  */
160
230
  function report(pResults, pOptions) {
@@ -173,8 +243,13 @@ function report(pResults, pOptions) {
173
243
  .replace("{{warn}}", pResults.summary.warn)
174
244
  .replace("{{info}}", pResults.summary.info)
175
245
  .replace("{{ignore}}", pResults.summary.ignore ?? 0)
246
+ .replace("{{staleDiv}}", constructStaleDiv(pResults.summary.baselineStale))
176
247
  .replace("{{violatedRulesTable}}", constructViolatedRulesTable(pResults))
177
248
  .replace("{{violationsList}}", constructViolationsList(pResults, lOptions))
249
+ .replace(
250
+ "{{baselineStaleTable}}",
251
+ constructBaselineStaleTable(pResults, pOptions),
252
+ )
178
253
  .replace("{{depcruiseVersion}}", `dependency-cruiser@${meta.version}`)
179
254
  .replace("{{runDate}}", new Date().toISOString());
180
255
  }
@@ -182,8 +257,9 @@ function report(pResults, pOptions) {
182
257
  /**
183
258
  * Returns the results of a cruise in an 'incidence matrix'
184
259
  *
185
- * @param {import("../../../types/cruise-result.mjs").ICruiseResult} pResults - the output of a dependency-cruise adhering to ../../schema/cruise-result.schema.json
186
- * @returns {import("../../../types/dependency-cruiser.js").IReporterOutput} - output: an html program showing the summary & the violations (if any)
260
+ * @param {ICruiseResult} pResults - the output of a dependency-cruise adhering to ../../schema/cruise-result.schema.json
261
+ * @param {IErrorReporterOptions} pOptions
262
+ * @returns {IReporterOutput} - output: an html program showing the summary & the violations (if any)
187
263
  * exitCode: 0
188
264
  */
189
265
  export default function errorHtml(pResults, pOptions) {
@@ -8,6 +8,13 @@ import {
8
8
  import { findRuleByName } from "#graph-utl/rule-set.mjs";
9
9
  import wrapAndIndent from "#utl/wrap-and-indent.mjs";
10
10
 
11
+ /**
12
+ * @import { ICruiseResult, IEnvironmentIssue } from "../../types/cruise-result.mjs"
13
+ * @import { IErrorReporterOptions } from "../../types/reporter-options.mjs"
14
+ * @import { IReporterOutput } from "../../types/dependency-cruiser.js"
15
+ * @import { SeverityType } from "../../types/shared-types.mjs"
16
+ */
17
+
11
18
  const SEVERITY2COLOR = new Map([
12
19
  ["error", "red"],
13
20
  ["warn", "yellow"],
@@ -114,6 +121,10 @@ function addExplanation(pRuleSet, pLong) {
114
121
  : (pViolation) => pViolation;
115
122
  }
116
123
 
124
+ /**
125
+ * @param {number} pNumberOfIgnoredViolations
126
+ * @returns {string}
127
+ */
117
128
  function formatIgnoreWarning(pNumberOfIgnoredViolations) {
118
129
  if (pNumberOfIgnoredViolations > 0) {
119
130
  return styleText(
@@ -123,8 +134,9 @@ function formatIgnoreWarning(pNumberOfIgnoredViolations) {
123
134
  }
124
135
  return "";
125
136
  }
137
+
126
138
  /**
127
- * @param {import("../../types/cruise-result.mjs").IEnvironmentIssue} pEnvironmentIssue
139
+ * @param {IEnvironmentIssue} pEnvironmentIssue
128
140
  * @returns {string}
129
141
  */
130
142
  function formatEnvironmentIssue(pEnvironmentIssue) {
@@ -135,7 +147,7 @@ function formatEnvironmentIssue(pEnvironmentIssue) {
135
147
  }
136
148
 
137
149
  /**
138
- * @param {import("../../types/cruise-result.mjs").IEnvironmentIssue[]} pEnvironmentIssues
150
+ * @param {IEnvironmentIssue[]} pEnvironmentIssues
139
151
  * @returns {string}
140
152
  */
141
153
  function formatEnvironmentIssues(pEnvironmentIssues) {
@@ -147,6 +159,30 @@ function formatEnvironmentIssues(pEnvironmentIssues) {
147
159
  );
148
160
  }
149
161
 
162
+ /**
163
+ * @param {number} pBaselineStaleCount
164
+ * @param {SeverityType} pStaleEntriesSeverity
165
+ * @returns {string}
166
+ */
167
+ function formatStaleBaselineMessage(
168
+ pBaselineStaleCount,
169
+ pStaleEntriesSeverity,
170
+ ) {
171
+ if ((pBaselineStaleCount ?? 0) > 0) {
172
+ const lStaleEntriesSeverity = pStaleEntriesSeverity ?? "warn";
173
+ return styleText(
174
+ SEVERITY2COLOR.get(lStaleEntriesSeverity),
175
+ `${SEVERITY2ICON.get(lStaleEntriesSeverity)} ${pBaselineStaleCount} stale known violations in the baseline. Run with '--baseline --baseline-mode shrink-only' to remove them.${EOL}`,
176
+ );
177
+ }
178
+ return "";
179
+ }
180
+
181
+ /**
182
+ * @param {ICruiseResult} pResults
183
+ * @param {IErrorReporterOptions} pOptions
184
+ * @returns {string}
185
+ */
150
186
  function report(pResults, pOptions) {
151
187
  const lOptions = {
152
188
  long: false,
@@ -163,13 +199,20 @@ function report(pResults, pOptions) {
163
199
  pResults.summary.totalCruised
164
200
  } modules, ${
165
201
  pResults.summary.totalDependenciesCruised
166
- } dependencies cruised)${EOL}${formatIgnoreWarning(
167
- pResults.summary.ignore,
168
- )}${formatEnvironmentIssues(pResults.summary.environment?.issues)}${EOL}`;
202
+ } dependencies cruised)${EOL}`
203
+ .concat(formatIgnoreWarning(pResults.summary.ignore))
204
+ .concat(
205
+ formatStaleBaselineMessage(
206
+ pResults.summary.baselineStale,
207
+ pResults.summary.optionsUsed?.baseline?.staleEntriesSeverity,
208
+ ),
209
+ )
210
+ .concat(formatEnvironmentIssues(pResults.summary.environment?.issues))
211
+ .concat(EOL);
169
212
  }
170
213
 
171
214
  return lNonIgnorableViolations
172
- .reverse()
215
+ .toReversed()
173
216
  .map(addExplanation(pResults.summary.ruleSetUsed, lOptions.long))
174
217
  .reduce(
175
218
  (pAll, pThis) => `${pAll} ${formatViolation(pThis, lOptions)}${EOL}`,
@@ -177,6 +220,12 @@ function report(pResults, pOptions) {
177
220
  )
178
221
  .concat(formatSummary(pResults.summary))
179
222
  .concat(formatIgnoreWarning(pResults.summary.ignore))
223
+ .concat(
224
+ formatStaleBaselineMessage(
225
+ pResults.summary.baselineStale,
226
+ pResults.summary.optionsUsed?.baseline?.staleEntriesSeverity,
227
+ ),
228
+ )
180
229
  .concat(formatEnvironmentIssues(pResults.summary.environment?.issues))
181
230
  .concat(EOL);
182
231
  }
@@ -187,16 +236,16 @@ function report(pResults, pOptions) {
187
236
  * - for each violation a message stating the violation name and the to and from
188
237
  * - a summary with total number of errors and warnings found, and the total
189
238
  * number of files cruised
190
- * @param {import("../../types/cruise-result.mjs").ICruiseResult} pResults -
191
- * @param {any} pOptions - An object with options;
192
- * {boolean} long - whether or not to include an explanation
193
- * (/ comment) which each violation
194
- * @returns {import("../../types/dependency-cruiser.js").IReporterOutput} - output: the formatted text in a string
195
- * exitCode: the number of errors found
239
+ * @param {ICruiseResult} pResults
240
+ * @param {IErrorReporterOptions} pOptions
241
+ * @returns {IReporterOutput}
196
242
  */
197
243
  export default function error(pResults, pOptions) {
198
244
  return {
199
245
  output: report(pResults, pOptions || {}),
200
- exitCode: pResults.summary.error,
246
+ // advisedExitCode is a mandatory attribute as of dependency-cruiser 18.4.0
247
+ // however, this reporter can still encounter dependency-cruiser results
248
+ // from before that, hence the fallback
249
+ exitCode: pResults.summary.advisedExitCode ?? pResults.summary.error,
201
250
  };
202
251
  }
@@ -4,7 +4,16 @@ import {
4
4
  determineFromExtras,
5
5
  } from "./error-html/utl.mjs";
6
6
  import meta from "#meta.cjs";
7
+ import { diffViolationArrays } from "#graph-utl/compare.mjs";
7
8
 
9
+ /**
10
+ * @import { ICruiseResult, IViolation, ISummary } from "../../types/cruise-result.mjs"
11
+ * @import { IMarkdownReporterOptions } from "../../types/reporter-options.mjs"
12
+ * @import { IReporterOutput } from "../../types/dependency-cruiser.mjs"
13
+ * @import { SeverityType } from "../../types/shared-types.mjs"
14
+ */
15
+
16
+ /** @type {IMarkdownReporterOptions} */
8
17
  const REPORT_DEFAULTS = {
9
18
  showTitle: true,
10
19
  title: "## Forbidden dependency check - results",
@@ -27,6 +36,14 @@ const REPORT_DEFAULTS = {
27
36
  noViolationsMessage:
28
37
  ":revolving_hearts: No violations found. Get gummy bears to celebrate.",
29
38
 
39
+ showStaleBaselineDetails: true,
40
+ staleBaselineHeader: "### :ghost: Stale entries in the baseline",
41
+ collapseStaleBaseline: true,
42
+ collapseStaleBaselineMessage:
43
+ "Stale violations in the baseline - click to expand",
44
+ staleBaselineIntro:
45
+ "These violations are in the baseline (typically `.dependency-cruiser-known-violations.json`) but don't match any real violations anymore, e.g. because they were fixed in the meantime. You can remove them with dependency-cruiser's [`--baseline --baseline-mode shrink-only`](https://github.com/sverweij/dependency-cruiser/blob/main/doc/cli.md#--baseline-create-or-update-a-known-violations-baseline) command line options.",
46
+
30
47
  showFooter: true,
31
48
  footer: `---\n[dependency-cruiser@${
32
49
  meta.version
@@ -34,7 +51,7 @@ const REPORT_DEFAULTS = {
34
51
  };
35
52
 
36
53
  /**
37
- * @param {import("../../types/shared-types.js").SeverityType} pSeverity
54
+ * @param {SeverityType} pSeverity
38
55
  * @returns {string}
39
56
  */
40
57
  function severity2Icon(pSeverity) {
@@ -48,17 +65,28 @@ function severity2Icon(pSeverity) {
48
65
  }
49
66
 
50
67
  /**
51
- * @param {import("../../types/cruise-result.mjs").ISummary} pSummary
68
+ * @param {ISummary} pSummary
52
69
  * @returns {string}
53
70
  */
54
71
  function formatStatsSummary(pSummary) {
55
72
  const lSpacerLength = 4;
56
73
  const lSpacer = "&nbsp;".repeat(lSpacerLength);
57
- return `**${pSummary.totalCruised}** modules${lSpacer}**${pSummary.totalDependenciesCruised}** dependencies${lSpacer}**${pSummary.error}** errors${lSpacer}**${pSummary.warn}** warnings${lSpacer}**${pSummary.info}** informational${lSpacer}**${pSummary.ignore}** ignored\n`;
74
+ return `**${pSummary.totalCruised}** modules${lSpacer}`
75
+ .concat(`**${pSummary.totalDependenciesCruised}** dependencies${lSpacer}`)
76
+ .concat(`**${pSummary.error}** errors${lSpacer}`)
77
+ .concat(`**${pSummary.warn}** warnings${lSpacer}`)
78
+ .concat(`**${pSummary.info}** informational${lSpacer}`)
79
+ .concat(`**${pSummary.ignore}** ignored`)
80
+ .concat(
81
+ (pSummary.baselineStale ?? 0) > 0
82
+ ? `${lSpacer}**${pSummary.baselineStale}** stale entries in baseline`
83
+ : "",
84
+ )
85
+ .concat("\n");
58
86
  }
59
87
 
60
88
  /**
61
- * @param {import("../../types/cruise-result.mjs").ICruiseResult} pCruiseResult
89
+ * @param {ICruiseResult} pCruiseResult
62
90
  * @param {Boolean} pIncludeIgnoredInSummary
63
91
  * @returns {string}
64
92
  */
@@ -84,9 +112,8 @@ function formatRulesSummary(pCruiseResult, pIncludeIgnoredInSummary) {
84
112
  }
85
113
 
86
114
  /**
87
- *
88
- * @param {import("../../types/cruise-result.mjs").IViolation[]} pViolations
89
- * @param {object} pOptions
115
+ * @param {IViolation[]} pViolations
116
+ * @param {IMarkdownReporterOptions} pOptions
90
117
  * @returns {string}
91
118
  */
92
119
  function formatViolations(pViolations, pOptions) {
@@ -108,19 +135,49 @@ function formatViolations(pViolations, pOptions) {
108
135
  }, lTableHead);
109
136
  }
110
137
 
111
- function details(pResults, pOptions) {
138
+ /**
139
+ * @param {IViolation[]} pViolations
140
+ * @param {IViolation[]} pKnownViolations
141
+ * @param {IMarkdownReporterOptions} pOptions
142
+ */
143
+ function staleBaselineDetails(pViolations, pKnownViolations, pOptions) {
112
144
  let lReturnValue = "";
113
- if (pResults.summary.violations.length > 0) {
145
+
146
+ if (!pKnownViolations) {
147
+ return lReturnValue;
148
+ }
149
+
150
+ const { old } = diffViolationArrays(pKnownViolations, pViolations);
151
+
152
+ if (old.length > 0) {
153
+ lReturnValue = `${pOptions.staleBaselineHeader}\n\n`;
154
+ if (pOptions.collapseStaleBaseline) {
155
+ lReturnValue += `<details><summary>${pOptions.collapseStaleBaselineMessage}</summary>\n\n`;
156
+ }
157
+ lReturnValue += `${pOptions.staleBaselineIntro}\n\n`;
158
+ lReturnValue += `${formatViolations(old, pOptions)}\n\n`;
159
+ if (pOptions.collapseStaleBaseline) {
160
+ lReturnValue += `</details>\n\n`;
161
+ }
162
+ }
163
+ return lReturnValue;
164
+ }
165
+
166
+ /**
167
+ * @param {IViolation[]} pViolations
168
+ * @param {IMarkdownReporterOptions} pOptions
169
+ * @returns {string}
170
+ */
171
+ function details(pViolations, pOptions) {
172
+ let lReturnValue = "";
173
+ if (pViolations.length > 0) {
114
174
  if (pOptions.showDetailsHeader) {
115
175
  lReturnValue += `${pOptions.detailsHeader}\n\n`;
116
176
  }
117
177
  if (pOptions.collapseDetails) {
118
178
  lReturnValue += `<details><summary>${pOptions.collapsedMessage}</summary>\n\n`;
119
179
  }
120
- lReturnValue += `${formatViolations(
121
- pResults.summary.violations,
122
- pOptions,
123
- )}\n\n`;
180
+ lReturnValue += `${formatViolations(pViolations, pOptions)}\n\n`;
124
181
  if (pOptions.collapseDetails) {
125
182
  lReturnValue += "</details>\n\n";
126
183
  }
@@ -130,6 +187,11 @@ function details(pResults, pOptions) {
130
187
  return lReturnValue;
131
188
  }
132
189
 
190
+ /**
191
+ * @param {ICruiseResult} pResults
192
+ * @param {IMarkdownReporterOptions} pOptions
193
+ * @returns {string}
194
+ */
133
195
  function summary(pResults, pOptions) {
134
196
  let lReturnValue = "";
135
197
 
@@ -148,8 +210,8 @@ function summary(pResults, pOptions) {
148
210
  }
149
211
 
150
212
  /**
151
- * @param {import("../../types/cruise-result.mjs").ICruiseResult} pResults
152
- * @param {import("../../types/reporter-options.js").IMarkdownReporterOptions} pOptions
213
+ * @param {ICruiseResult} pResults
214
+ * @param {IMarkdownReporterOptions} pOptions
153
215
  * @returns {string}
154
216
  */
155
217
  function report(pResults, pOptions) {
@@ -165,7 +227,15 @@ function report(pResults, pOptions) {
165
227
  }
166
228
 
167
229
  if (lOptions.showDetails) {
168
- lReturnValue += details(pResults, lOptions);
230
+ lReturnValue += details(pResults.summary.violations, lOptions);
231
+ }
232
+
233
+ if (lOptions.showStaleBaselineDetails) {
234
+ lReturnValue += staleBaselineDetails(
235
+ pResults.summary.violations,
236
+ pResults.summary.optionsUsed?.knownViolations,
237
+ lOptions,
238
+ );
169
239
  }
170
240
 
171
241
  if (lOptions.showFooter) {
@@ -178,9 +248,9 @@ function report(pResults, pOptions) {
178
248
  /**
179
249
  * Returns the violations from a cruise in markdown format
180
250
  *
181
- * @param {import("../../types/cruise-result.mjs").ICruiseResult} pResults
182
- * @param {import("../../types/reporter-options.js").IMarkdownReporterOptions} pOptions
183
- * @returns {import("../../types/dependency-cruiser.js").IReporterOutput}
251
+ * @param {ICruiseResult} pResults
252
+ * @param {IMarkdownReporterOptions} pOptions
253
+ * @returns {IReporterOutput}
184
254
  */
185
255
  export default function markdown(pResults, pOptions) {
186
256
  return {
@@ -1,12 +1,15 @@
1
1
  /**
2
2
  * Returns the results of a cruise _only_ in an exitCode
3
3
  *
4
- * @param {import("../../types/cruise-result").ICruiseResult} pResults
5
- * @returns {import("../../types/dependency-cruiser").IReporterOutput}
4
+ * @param {import("../../types/cruise-result.mjs").ICruiseResult} pResults
5
+ * @returns {import("../../types/dependency-cruiser.mjs").IReporterOutput}
6
6
  */
7
7
  export default function nullReporter(pResults) {
8
8
  return {
9
9
  output: "",
10
- exitCode: pResults.summary.error,
10
+ // advisedExitCode is a mandatory attribute as of dependency-cruiser 18.4.0
11
+ // however, this reporter can still encounter dependency-cruiser results
12
+ // from before that, hence the fallback
13
+ exitCode: pResults.summary.advisedExitCode ?? pResults.summary.error,
11
14
  };
12
15
  }
@@ -273,6 +273,9 @@ export default function teamcity(pResults) {
273
273
  reportViolatedRules(lRuleSet, lViolations, lIgnoredCount, lFlowId)
274
274
  .concat(reportViolations(lViolations, lIgnoredCount, lFlowId))
275
275
  .reduce((pAll, pCurrent) => `${pAll}${pCurrent}${EOL}`, "") || EOL,
276
- exitCode: pResults.summary.error,
276
+ // advisedExitCode is a mandatory attribute as of dependency-cruiser 18.4.0
277
+ // however, this reporter can still encounter dependency-cruiser results
278
+ // from before that, hence the fallback
279
+ exitCode: pResults.summary.advisedExitCode ?? pResults.summary.error,
277
280
  };
278
281
  }