dependency-cruiser 17.3.9 → 17.4.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dependency-cruiser",
3
- "version": "17.3.9",
3
+ "version": "17.4.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,12 +149,12 @@
149
149
  "acorn-loose": "8.5.2",
150
150
  "acorn-walk": "8.3.5",
151
151
  "commander": "14.0.3",
152
- "enhanced-resolve": "5.20.0",
152
+ "enhanced-resolve": "5.21.0",
153
153
  "ignore": "7.0.5",
154
154
  "interpret": "3.1.1",
155
155
  "is-installed-globally": "1.0.0",
156
156
  "json5": "2.2.3",
157
- "picomatch": "4.0.3",
157
+ "picomatch": "4.0.4",
158
158
  "prompts": "2.4.2",
159
159
  "rechoir": "0.8.0",
160
160
  "safe-regex": "2.1.1",
@@ -17,6 +17,8 @@ function toDependencyViolationSummary(pRule, pModule, pDependency, pRuleSet) {
17
17
  type: "dependency",
18
18
  from: pModule.source,
19
19
  to: pDependency.resolved,
20
+ unresolvedTo: pDependency.module,
21
+ dependencyTypes: pDependency.dependencyTypes,
20
22
  rule: pRule,
21
23
  };
22
24
 
@@ -3,7 +3,7 @@ import { folderNameArrayToRE } from "./utl.mjs";
3
3
  import configTemplate from "./config-template.mjs";
4
4
 
5
5
  /**
6
- * @import { IInitConfig } from "./types.js";
6
+ * @import { IInitConfig } from "./types.mjs";
7
7
  */
8
8
 
9
9
  /**
@@ -0,0 +1,111 @@
1
+ /* eslint-disable prefer-template */
2
+ /**
3
+ * @import { IInitConfig } from "./types.mjs";
4
+ * @import { IAvailableTranspiler } from "../../../types/dependency-cruiser.mjs"
5
+ */
6
+
7
+ import { EOL } from "node:os";
8
+ import { styleText } from "node:util";
9
+ import { getAvailableTranspilers } from "#extract/transpile/meta.mjs";
10
+
11
+ /**
12
+ * returns true if
13
+ * - typescript features are detected _and_ a typescript compiler is present
14
+ * - no typescript features were detected
15
+ * returns false in all other cases
16
+ *
17
+ * @param {IInitConfig} pInitOptions
18
+ * @param {IAvailableTranspiler[]} pAvailableTranspilers
19
+ * @return {boolean}
20
+ */
21
+ function typescriptIsConsistent(pInitOptions, pAvailableTranspilers) {
22
+ if (pInitOptions.usesTypeScript) {
23
+ return pAvailableTranspilers.some(
24
+ (pAvailableTranspiler) =>
25
+ pAvailableTranspiler.name === "typescript" &&
26
+ pAvailableTranspiler.available,
27
+ );
28
+ }
29
+ return true;
30
+ }
31
+
32
+ /**
33
+ * returns true if
34
+ * - babel features are detected _and_ the babel transpiler is present
35
+ * - no babel features were detected
36
+ * returns false in all other cases
37
+ *
38
+ * @param {IInitConfig} pInitOptions
39
+ * @param {IAvailableTranspiler[]} pAvailableTranspilers
40
+ * @return {boolean}
41
+ */
42
+ function babelIsConsistent(pInitOptions, pAvailableTranspilers) {
43
+ if (pInitOptions.babelConfig) {
44
+ return pAvailableTranspilers.some(
45
+ (pAvailableTranspiler) =>
46
+ pAvailableTranspiler.name === "babel" && pAvailableTranspiler.available,
47
+ );
48
+ }
49
+ return true;
50
+ }
51
+
52
+ /**
53
+ * Prints warnings to stderr if there's inconsistencies in the init options.
54
+ * E.g. typescript options are used, but the (microsoft) typescript compiler
55
+ * isn't installed.
56
+ *
57
+ * @param {IInitConfig} pInitOptions
58
+ * @param {NodeJS.WritableStream} [pErrorStream]
59
+ * @param {typeof getAvailableTranspilers} [pAvailableTranspilerFunction]
60
+ * @return {IInitConfig} pInitOptions
61
+ */
62
+ export function checkAndWarnInconsistencies(
63
+ pInitOptions,
64
+ pErrorStream = process.stderr,
65
+ pAvailableTranspilerFunction = getAvailableTranspilers,
66
+ ) {
67
+ const lAvailableTranspilers = pAvailableTranspilerFunction();
68
+ const lWarningMessages = [];
69
+
70
+ if (!typescriptIsConsistent(pInitOptions, lAvailableTranspilers)) {
71
+ lWarningMessages.push(
72
+ EOL +
73
+ " ‼ TypeScript compiler not found" +
74
+ EOL +
75
+ " TypeScript features are used but the TypeScript compiler isn't installed. " +
76
+ EOL +
77
+ " Install it to ensure dependency-cruiser cruises TypeScript sources e.g. by running" +
78
+ EOL +
79
+ EOL +
80
+ " npm i -D typescript" +
81
+ EOL,
82
+ );
83
+ }
84
+ if (!babelIsConsistent(pInitOptions, lAvailableTranspilers)) {
85
+ lWarningMessages.push(
86
+ EOL +
87
+ " ‼ Babel not found " +
88
+ EOL +
89
+ " Babel features are used but Babel isn't installed. " +
90
+ EOL +
91
+ " Install it to ensure dependency-cruiser takes them into account. E.g. by running" +
92
+ EOL +
93
+ EOL +
94
+ " npm i -D @babel/core" +
95
+ EOL,
96
+ );
97
+ }
98
+
99
+ // future features: do the same for ...
100
+ // ... webpack
101
+ // ... svelte
102
+ // ... vue
103
+ // ... coffeescript
104
+ // ... livescript?
105
+ if (lWarningMessages.length > 0) {
106
+ pErrorStream.write(styleText("yellow", lWarningMessages.join("")));
107
+ }
108
+
109
+ // as it's used in a promise chain ...
110
+ return pInitOptions;
111
+ }
@@ -163,7 +163,7 @@ const QUESTIONS = [
163
163
  ];
164
164
 
165
165
  /**
166
- * @return {Promise<import("./types").IPartialInitConfig>}
166
+ * @return {Promise<import("./types.d.mts").IPartialInitConfig>}
167
167
  */
168
168
  export default function getUserInput() {
169
169
  return prompts(QUESTIONS);
@@ -4,6 +4,7 @@ import normalizeInitOptions from "./normalize-init-options.mjs";
4
4
  import buildConfig from "./build-config.mjs";
5
5
  import writeConfig from "./write-config.mjs";
6
6
  import getUserInput from "./get-user-input.mjs";
7
+ import { checkAndWarnInconsistencies } from "./check-and-warn-inconsistencies.mjs";
7
8
  import {
8
9
  isLikelyMonoRepo,
9
10
  fileExists,
@@ -22,7 +23,7 @@ import {
22
23
  import { writeRunScriptsToManifest } from "./write-run-scripts-to-manifest.mjs";
23
24
 
24
25
  /**
25
- * @import { IInitConfig, IPartialInitConfig, OneShotConfigIDType } from "./types.js";
26
+ * @import { IInitConfig, IPartialInitConfig, OneShotConfigIDType } from "./types.mjs";
26
27
  */
27
28
 
28
29
  const PACKAGE_MANIFEST = `./${_PACKAGE_MANIFEST}`;
@@ -95,6 +96,9 @@ export default function initConfig(pInit, pConfigFileName, pStreams) {
95
96
  if (pInit === true) {
96
97
  getUserInput()
97
98
  .then(normalizeInitOptions)
99
+ .then((pNormalizedInitOptions) =>
100
+ checkAndWarnInconsistencies(pNormalizedInitOptions, lStreams.stderr),
101
+ )
98
102
  .then(buildConfig)
99
103
  .then(writeConfig)
100
104
  .catch((pError) => {
@@ -103,6 +107,7 @@ export default function initConfig(pInit, pConfigFileName, pStreams) {
103
107
  /* c8 ignore stop */
104
108
  } else if (pInit !== false) {
105
109
  const lNormalizedInitConfig = normalizeInitOptions(getOneShotConfig(pInit));
110
+ checkAndWarnInconsistencies(lNormalizedInitConfig, lStreams.stderr);
106
111
  const lConfigFileName = pConfigFileName || getDefaultConfigFileName();
107
112
 
108
113
  if (manifestIsUpdatable(lNormalizedInitConfig)) {
@@ -8,7 +8,7 @@ import findExtensions from "./find-extensions.mjs";
8
8
  import meta from "#meta.cjs";
9
9
 
10
10
  /**
11
- * @import { IInitConfig, IPartialInitConfig } from "./types.js";
11
+ * @import { IInitConfig, IPartialInitConfig } from "./types.mjs";
12
12
  */
13
13
 
14
14
  /**
@@ -0,0 +1,114 @@
1
+ export type OneShotConfigIDType = "yes" | "x-scripts";
2
+
3
+ export interface IInitConfig {
4
+ /**
5
+ * Whether or not the current folder houses a mono repo
6
+ */
7
+ isMonoRepo: boolean;
8
+ /**
9
+ * Whether or not the current folder is a package is an ESM package
10
+ * by default (and resolutions of external dependencies should be
11
+ * treated as such)
12
+ */
13
+ isTypeModule: boolean;
14
+ /**
15
+ * Whether or not you allow usage of external dependencies declared in
16
+ * package.jsons of parent folders
17
+ */
18
+ combinedDependencies: boolean;
19
+ /**
20
+ * Whether or not to use a TypeScript config
21
+ */
22
+ useJsConfig: boolean;
23
+ /**
24
+ * The file name of the TypeScript config to use
25
+ */
26
+ jsConfig?: string;
27
+ /**
28
+ * Whether or not to use a TypeScript config
29
+ */
30
+ useTsConfig: boolean;
31
+ /**
32
+ * The file name of the TypeScript config to use
33
+ */
34
+ tsConfig?: string;
35
+ /**
36
+ * Whether or not to detect JSDoc imports
37
+ */
38
+ detectJSDocImports?: boolean;
39
+ /**
40
+ * Whether or not to detect calls to `process.getBuiltinModule`/
41
+ * `globalThis.process.getBuiltinModule` as imports
42
+ */
43
+ detectProcessBuiltinModuleCalls?: boolean;
44
+ /**
45
+ * Whether or not to take dependencies into account that only exist before
46
+ * compilation to javascript
47
+ */
48
+ tsPreCompilationDeps: boolean;
49
+ /**
50
+ * Derived attribute. True if the current project likely uses typescript (has a
51
+ * tsconfig, has files with typescript extensions in source and/ or test
52
+ * folders, or has a truthy tsPreCompilationDeps)
53
+ */
54
+ usesTypeScript: boolean;
55
+ /**
56
+ * Whether or not to use a Webpack config
57
+ */
58
+ useWebpackConfig: boolean;
59
+ /**
60
+ * The file name of the Webpack config to use
61
+ */
62
+ webpackConfig?: string;
63
+ /**
64
+ * Whether or not to use a Babel config
65
+ */
66
+ useBabelConfig: boolean;
67
+ /**
68
+ * The file name of the Babel config to use
69
+ */
70
+ babelConfig?: string;
71
+ /**
72
+ * Whether or not to include some useful scripts in your package.json
73
+ */
74
+ updateManifest: boolean;
75
+ /**
76
+ * An array of (relative) paths to folders to understand as source code
77
+ */
78
+ sourceLocation: string[];
79
+ /**
80
+ * Whether tests are housed in a folder separate from sources
81
+ * or are embedded within the source folder
82
+ */
83
+ hasTestsOutsideSource: boolean;
84
+ /**
85
+ * An array of (relative) paths to folders to understand as test code
86
+ */
87
+ testLocation?: string[];
88
+ /**
89
+ * Whether or not to explicitly pass extensions to the resolver. When not
90
+ * set explicitly dependency-cruiser will pass it all extensions it knows
91
+ * to handle - which makes it more sure to catch everything, at the trade-off
92
+ * of potentially being slower if the number of extensions used in reality
93
+ * is (a lot) smaller.
94
+ */
95
+ specifyResolutionExtensions: boolean;
96
+ /**
97
+ * An array of extensions the resolver should use when resolving dependencies
98
+ */
99
+ resolutionExtensions?: string[];
100
+ /**
101
+ * Dependency-cruiser version used
102
+ */
103
+ version: string;
104
+ /**
105
+ * (Formatted) date this config is created
106
+ */
107
+ date: string;
108
+ /**
109
+ * bun is used as package manager cq runtime
110
+ */
111
+ usesBun: boolean;
112
+ }
113
+
114
+ export type IPartialInitConfig = Partial<IInitConfig>;
@@ -59,7 +59,7 @@ const EXPERIMENTAL_SCRIPT_DOC = [
59
59
  ];
60
60
 
61
61
  /**
62
- * @param {import("./types").IInitConfig} pInitOptions
62
+ * @param {import("./types.d.mts").IInitConfig} pInitOptions
63
63
  * @return {any} an bunch of key value pairs that can be plonked into a `scripts` attribute in a package.json
64
64
  */
65
65
  export function compileRunScripts(pInitOptions) {
@@ -3,7 +3,7 @@ import {
3
3
  isAvailable as swcIsAvailable,
4
4
  version as swcVersion,
5
5
  } from "../swc/parse.mjs";
6
- import tryAvailable from "./try-import-available.mjs";
6
+ import tryImportAvailable from "./try-import-available.mjs";
7
7
  import javascriptWrap from "./javascript-wrap.mjs";
8
8
  import babelWrap from "./babel-wrap.mjs";
9
9
  import coffeeScriptWrapFunction from "./coffeescript-wrap.mjs";
@@ -13,6 +13,10 @@ import typescriptWrapFunction from "./typescript-wrap.mjs";
13
13
  import vueTemplateWrap from "./vue-template-wrap.cjs";
14
14
  import meta from "#meta.cjs";
15
15
 
16
+ /**
17
+ * @import { IAvailableTranspiler } from "../../../types/dependency-cruiser.mjs";
18
+ */
19
+
16
20
  const swcWrap = {
17
21
  isAvailable: () => swcIsAvailable(),
18
22
  version: () => swcVersion(),
@@ -23,25 +27,43 @@ const typescriptWrap = typescriptWrapFunction("esm");
23
27
 
24
28
  function gotCoffee() {
25
29
  return (
26
- tryAvailable("coffeescript", meta.supportedTranspilers.coffeescript) ||
27
- tryAvailable("coffee-script", meta.supportedTranspilers["coffee-script"])
30
+ tryImportAvailable(
31
+ "coffeescript",
32
+ meta.supportedTranspilers.coffeescript,
33
+ ) ||
34
+ /* c8 ignore start */
35
+ // fallback for ancient versions of the coffeescript compilers
36
+ tryImportAvailable(
37
+ "coffee-script",
38
+ meta.supportedTranspilers["coffee-script"],
39
+ )
40
+ /* c8 ignore stop */
28
41
  );
29
42
  }
30
43
 
31
44
  const TRANSPILER2AVAILABLE = {
32
- babel: tryAvailable("@babel/core", meta.supportedTranspilers.babel),
45
+ babel: tryImportAvailable("@babel/core", meta.supportedTranspilers.babel),
33
46
  javascript: true,
34
47
  "coffee-script": gotCoffee(),
35
48
  coffeescript: gotCoffee(),
36
- livescript: tryAvailable("livescript", meta.supportedTranspilers.livescript),
37
- svelte: tryAvailable("svelte/compiler", meta.supportedTranspilers.svelte),
38
- swc: tryAvailable("@swc/core", meta.supportedTranspilers.swc),
39
- typescript: tryAvailable("typescript", meta.supportedTranspilers.typescript),
40
- "vue-template-compiler": tryAvailable(
49
+ livescript: tryImportAvailable(
50
+ "livescript",
51
+ meta.supportedTranspilers.livescript,
52
+ ),
53
+ svelte: tryImportAvailable(
54
+ "svelte/compiler",
55
+ meta.supportedTranspilers.svelte,
56
+ ),
57
+ swc: tryImportAvailable("@swc/core", meta.supportedTranspilers.swc),
58
+ typescript: tryImportAvailable(
59
+ "typescript",
60
+ meta.supportedTranspilers.typescript,
61
+ ),
62
+ "vue-template-compiler": tryImportAvailable(
41
63
  "vue-template-compiler",
42
64
  meta.supportedTranspilers["vue-template-compiler"],
43
65
  ),
44
- "@vue/compiler-sfc": tryAvailable(
66
+ "@vue/compiler-sfc": tryImportAvailable(
45
67
  "@vue/compiler-sfc",
46
68
  meta.supportedTranspilers["@vue/compiler-sfc"],
47
69
  ),
package/src/meta.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  /* generated - don't edit */
2
2
  module.exports = {
3
- version: "17.3.9",
3
+ version: "17.4.0",
4
4
  engines: {
5
5
  node: "^20.12||^22||>=24",
6
6
  },
@@ -159,6 +159,31 @@ export default `<!DOCTYPE html>
159
159
  .extra {
160
160
  color: gray;
161
161
  }
162
+ .dependency-type {
163
+ font-family: courier;
164
+ padding: 4px;
165
+ border-radius: 3px;
166
+ }
167
+ .local {
168
+ background-color: lightgray;
169
+ color: black;
170
+ }
171
+ .npm-bundled, .npm-dev, .npm-no-pkg, .npm-optional, .npm-peer, .npm-unknown, .npm {
172
+ background-color: darkred;
173
+ color: white;
174
+ }
175
+ .aliased {
176
+ background-color: blue;
177
+ color: white;
178
+ }
179
+ .aliased-subpath-import, .core {
180
+ background-color: green;
181
+ color: white;
182
+ }
183
+ .type-import, .type-only {
184
+ background-color: blue;
185
+ color: white;
186
+ }
162
187
  </style>
163
188
  <style type="text/css" media="print">
164
189
  th,
@@ -5,6 +5,7 @@ import {
5
5
  } from "./utl.mjs";
6
6
  import template from "./error-html-template.mjs";
7
7
  import meta from "#meta.cjs";
8
+ import { getOneLetterDependencyType } from "#report/utl/index.mjs";
8
9
 
9
10
  function getViolatedRuleRowClass(pViolatedRule) {
10
11
  return pViolatedRule.unviolated ? ' class="unviolated"' : "";
@@ -76,13 +77,13 @@ function constructViolatedRulesTable(pResults) {
76
77
  function getViolationRowClass(pViolation) {
77
78
  return pViolation.rule.severity === "ignore" ? ' class="ignored"' : "";
78
79
  }
79
-
80
80
  /**
81
81
  * @param {import('../../../types/cruise-result.mjs').IViolation} pViolation
82
82
  * @returns {string}
83
83
  */
84
- function constructViolationRow(pPrefix) {
84
+ function constructViolationRow(pPrefix, pOptions) {
85
85
  return (pViolation) => {
86
+ const lDependencyTypes = pViolation?.dependencyTypes ?? [];
86
87
  return ` <tr${getViolationRowClass(pViolation)}>
87
88
  <td class="${pViolation.rule.severity}">${pViolation.rule.severity}</td>
88
89
  <td class="nowrap">
@@ -93,7 +94,8 @@ function constructViolationRow(pPrefix) {
93
94
  <td><a href="${pPrefix}${pViolation.from}">${
94
95
  pViolation.from
95
96
  }</a>${determineFromExtras(pViolation)}</td>
96
- <td>${determineTo(pViolation)}</td>
97
+ <td><span class="dependency-type ${lDependencyTypes.join(" ")}" title="dependency types: ${lDependencyTypes.join(", ")}">${getOneLetterDependencyType(lDependencyTypes)}</span></td>
98
+ <td>${determineTo(pViolation, pOptions)}</td>
97
99
  </tr>`;
98
100
  };
99
101
  }
@@ -102,7 +104,7 @@ function constructViolationRow(pPrefix) {
102
104
  * @param {import('../../../types/cruise-result.mjs').ICruiseResult} pResults
103
105
  * @returns {string}
104
106
  */
105
- function constructViolationsList(pResults) {
107
+ function constructViolationsList(pResults, pOptions) {
106
108
  if (pResults.summary.violations.length > 0) {
107
109
  return `<span id="show-ignored-violations">
108
110
  <h2><svg class="p__svg--inline" viewBox="0 0 12 16" version="1.1" aria-hidden="true">
@@ -116,17 +118,23 @@ function constructViolationsList(pResults) {
116
118
  <th>severity</th>
117
119
  <th>rule</th>
118
120
  <th>from</th>
121
+ <th>types</th>
119
122
  <th>to</th>
120
123
  </tr>
121
124
  </thead>
122
125
  <tbody>
123
126
  ${pResults.summary.violations
124
- .map(constructViolationRow(pResults.summary.optionsUsed.prefix ?? ""))
127
+ .map(
128
+ constructViolationRow(
129
+ pResults.summary.optionsUsed.prefix ?? "",
130
+ pOptions,
131
+ ),
132
+ )
125
133
  .join("\n")}
126
134
  ${
127
135
  pResults.summary.ignore > 0
128
136
  ? `<tr>
129
- <td colspan="4" class="controls">
137
+ <td colspan="5" class="controls">
130
138
  <div id="show-ignored">
131
139
  &downarrow; <a href="#show-ignored-violations">also show ignored violations</a>
132
140
  </div>
@@ -149,7 +157,12 @@ function constructViolationsList(pResults) {
149
157
  * @param {import('../../../types/cruise-result.mjs')} pResults
150
158
  * @returns {string}
151
159
  */
152
- function report(pResults) {
160
+ function report(pResults, pOptions) {
161
+ const lOptions = {
162
+ showExternalModulesUnresolved: false,
163
+ showAliasedModulesUnresolved: false,
164
+ ...pOptions,
165
+ };
153
166
  return template
154
167
  .replace("{{totalCruised}}", pResults.summary.totalCruised)
155
168
  .replace(
@@ -161,7 +174,7 @@ function report(pResults) {
161
174
  .replace("{{info}}", pResults.summary.info)
162
175
  .replace("{{ignore}}", pResults.summary.ignore ?? 0)
163
176
  .replace("{{violatedRulesTable}}", constructViolatedRulesTable(pResults))
164
- .replace("{{violationsList}}", constructViolationsList(pResults))
177
+ .replace("{{violationsList}}", constructViolationsList(pResults, lOptions))
165
178
  .replace("{{depcruiseVersion}}", `dependency-cruiser@${meta.version}`)
166
179
  .replace("{{runDate}}", new Date().toISOString());
167
180
  }
@@ -173,9 +186,9 @@ function report(pResults) {
173
186
  * @returns {import("../../../types/dependency-cruiser.js").IReporterOutput} - output: an html program showing the summary & the violations (if any)
174
187
  * exitCode: 0
175
188
  */
176
- export default function errorHtml(pResults) {
189
+ export default function errorHtml(pResults, pOptions) {
177
190
  return {
178
- output: report(pResults),
191
+ output: report(pResults, pOptions || {}),
179
192
  exitCode: 0,
180
193
  };
181
194
  }
@@ -1,4 +1,8 @@
1
- import { formatViolation, formatPercentage } from "../utl/index.mjs";
1
+ import {
2
+ formatViolation,
3
+ formatPercentage,
4
+ formatDependencyTo,
5
+ } from "../utl/index.mjs";
2
6
  import meta from "#meta.cjs";
3
7
 
4
8
  export function getFormattedAllowedRule(pRuleSetUsed) {
@@ -40,21 +44,17 @@ function formatReachabilityTo(pViolation) {
40
44
  .join(" &rightarrow;<br/>")}`;
41
45
  }
42
46
 
43
- function formatDependencyTo(pViolation) {
44
- return pViolation.to;
45
- }
46
-
47
47
  function formatModuleTo() {
48
48
  return "";
49
49
  }
50
50
 
51
- function formatInstabilityTo(pViolation) {
52
- return `${pViolation.to}&nbsp;<span class="extra">(I: ${formatPercentage(
51
+ function formatInstabilityTo(pViolation, pOptions) {
52
+ return `${formatDependencyTo(pViolation, pOptions)}&nbsp;<span class="extra">(I: ${formatPercentage(
53
53
  pViolation.metrics.to.instability,
54
54
  )})</span>`;
55
55
  }
56
56
 
57
- export function determineTo(pViolation) {
57
+ export function determineTo(pViolation, pOptions) {
58
58
  const lViolationType2Formatter = {
59
59
  dependency: formatDependencyTo,
60
60
  module: formatModuleTo,
@@ -66,6 +66,7 @@ export function determineTo(pViolation) {
66
66
  pViolation,
67
67
  lViolationType2Formatter,
68
68
  formatDependencyTo,
69
+ pOptions,
69
70
  );
70
71
  }
71
72
 
@@ -3,6 +3,7 @@ import { styleText } from "node:util";
3
3
  import {
4
4
  formatPercentage,
5
5
  formatViolation as _formatViolation,
6
+ formatDependencyTo,
6
7
  } from "./utl/index.mjs";
7
8
  import { findRuleByName } from "#graph-utl/rule-set.mjs";
8
9
  import wrapAndIndent from "#utl/wrap-and-indent.mjs";
@@ -29,8 +30,8 @@ function formatModuleViolation(pViolation) {
29
30
  return styleText("bold", pViolation.from);
30
31
  }
31
32
 
32
- function formatDependencyViolation(pViolation) {
33
- return `${styleText("bold", pViolation.from)} → ${styleText("bold", pViolation.to)}`;
33
+ function formatDependencyViolation(pViolation, pOptions) {
34
+ return `${styleText("bold", pViolation.from)} → ${styleText("bold", formatDependencyTo(pViolation, pOptions))}`;
34
35
  }
35
36
 
36
37
  function formatCycleViolation(pViolation) {
@@ -41,8 +42,8 @@ function formatReachabilityViolation(pViolation) {
41
42
  return `${styleText("bold", pViolation.from)} → ${styleText("bold", pViolation.to)}${formatMiniDependency(pViolation.via)}`;
42
43
  }
43
44
 
44
- function formatInstabilityViolation(pViolation) {
45
- return `${formatDependencyViolation(pViolation)}${EOL}${styleText(
45
+ function formatInstabilityViolation(pViolation, pOptions) {
46
+ return `${formatDependencyViolation(pViolation, pOptions)}${EOL}${styleText(
46
47
  "dim",
47
48
  wrapAndIndent(
48
49
  `instability: ${formatPercentage(pViolation.metrics.from.instability)} → ${formatPercentage(pViolation.metrics.to.instability)}`,
@@ -51,7 +52,7 @@ function formatInstabilityViolation(pViolation) {
51
52
  )}`;
52
53
  }
53
54
 
54
- function formatViolation(pViolation) {
55
+ function formatViolation(pViolation, pOptions) {
55
56
  const lViolationType2Formatter = {
56
57
  module: formatModuleViolation,
57
58
  dependency: formatDependencyViolation,
@@ -63,6 +64,7 @@ function formatViolation(pViolation) {
63
64
  pViolation,
64
65
  lViolationType2Formatter,
65
66
  formatDependencyViolation,
67
+ pOptions,
66
68
  );
67
69
 
68
70
  return (
@@ -115,7 +117,13 @@ function formatIgnoreWarning(pNumberOfIgnoredViolations) {
115
117
  return "";
116
118
  }
117
119
 
118
- function report(pResults, pLong) {
120
+ function report(pResults, pOptions) {
121
+ const lOptions = {
122
+ long: false,
123
+ showExternalModulesUnresolved: false,
124
+ showAliasedModulesUnresolved: false,
125
+ ...pOptions,
126
+ };
119
127
  const lNonIgnorableViolations = pResults.summary.violations.filter(
120
128
  (pViolation) => pViolation.rule.severity !== "ignore",
121
129
  );
@@ -132,8 +140,11 @@ function report(pResults, pLong) {
132
140
 
133
141
  return lNonIgnorableViolations
134
142
  .reverse()
135
- .map(addExplanation(pResults.summary.ruleSetUsed, pLong))
136
- .reduce((pAll, pThis) => `${pAll} ${formatViolation(pThis)}${EOL}`, EOL)
143
+ .map(addExplanation(pResults.summary.ruleSetUsed, lOptions.long))
144
+ .reduce(
145
+ (pAll, pThis) => `${pAll} ${formatViolation(pThis, lOptions)}${EOL}`,
146
+ EOL,
147
+ )
137
148
  .concat(formatSummary(pResults.summary))
138
149
  .concat(formatIgnoreWarning(pResults.summary.ignore))
139
150
  .concat(EOL);
@@ -154,7 +165,7 @@ function report(pResults, pLong) {
154
165
  */
155
166
  export default function error(pResults, pOptions) {
156
167
  return {
157
- output: report(pResults, (pOptions || {}).long),
168
+ output: report(pResults, pOptions || {}),
158
169
  exitCode: pResults.summary.error,
159
170
  };
160
171
  }