dependency-cruiser 18.0.0-beta-2 → 18.1.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 +4 -4
- package/src/analyze/summarize/index.mjs +121 -4
- package/src/cache/cache.mjs +1 -1
- package/src/cli/format-meta-info.mjs +10 -12
- package/src/cli/index.mjs +1 -2
- package/src/cli/normalize-cli-options.mjs +1 -1
- package/src/environment.mjs +17 -0
- package/src/main/report-wrap.mjs +1 -0
- package/src/meta.cjs +1 -1
- package/src/report/error-html/error-html-template.mjs +7 -0
- package/src/report/error.mjs +32 -1
- package/src/schema/cruise-result.validate.mjs +1 -1
- package/src/utl/regex-util.mjs +1 -1
- package/types/cruise-result.d.mts +27 -0
- package/types/dependency-cruiser.d.mts +5 -26
- package/types/environment.d.mts +29 -0
- package/types/options.d.mts +1 -4
- package/types/rule-set.d.mts +2 -5
- package/types/shared-types.d.mts +1 -5
- package/types/strict-rule-set.d.mts +2 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dependency-cruiser",
|
|
3
|
-
"version": "18.
|
|
3
|
+
"version": "18.1.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": "15.0.0",
|
|
152
|
-
"enhanced-resolve": "5.24.
|
|
153
|
-
"ignore": "7.0.
|
|
152
|
+
"enhanced-resolve": "5.24.2",
|
|
153
|
+
"ignore": "7.0.6",
|
|
154
154
|
"interpret": "3.1.1",
|
|
155
155
|
"is-installed-globally": "1.0.0",
|
|
156
156
|
"json5": "2.2.3",
|
|
157
|
-
"picomatch": "4.0.
|
|
157
|
+
"picomatch": "4.0.5",
|
|
158
158
|
"prompts": "2.4.2",
|
|
159
159
|
"rechoir": "0.8.0",
|
|
160
160
|
"safe-regex": "2.1.1",
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { EOL } from "node:os";
|
|
1
2
|
import addRuleSetUsed from "./add-rule-set-used.mjs";
|
|
2
3
|
import summarizeModules from "./summarize-modules.mjs";
|
|
3
4
|
import summarizeFolders from "./summarize-folders.mjs";
|
|
@@ -8,31 +9,146 @@ import {
|
|
|
8
9
|
getDependenciesCruised,
|
|
9
10
|
} from "./get-stats.mjs";
|
|
10
11
|
import { compareViolations } from "#graph-utl/compare.mjs";
|
|
12
|
+
import { getEnvironmentInfo } from "#environment.mjs";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @import { IOptions, IEnvironmentIssue, ISummary, IModule, IFolder } from "../../../types/cruise-result.mjs"
|
|
16
|
+
* @import { IAvailableTranspiler } from "../../../types/environment.mjs"
|
|
17
|
+
* @import { IStrictCruiseOptions } from "../../../types/strict-options.mjs"
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @param { IOptions } pOptions
|
|
22
|
+
* @param { IAvailableTranspiler[] } pAvailableTranspilers
|
|
23
|
+
* @returns { boolean }
|
|
24
|
+
*/
|
|
25
|
+
function swcIsConsistent(pOptions, pAvailableTranspilers) {
|
|
26
|
+
const lSWCNeeded = (pOptions?.parser ?? "acorn") === "swc";
|
|
27
|
+
return lSWCNeeded
|
|
28
|
+
? pAvailableTranspilers.some(
|
|
29
|
+
(pTranspiler) => pTranspiler.name === "swc" && pTranspiler.available,
|
|
30
|
+
)
|
|
31
|
+
: true;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @param { IOptions } pOptions
|
|
36
|
+
* @param { IAvailableTranspiler[] } pAvailableTranspilers
|
|
37
|
+
* @returns { boolean }
|
|
38
|
+
*/
|
|
39
|
+
function typescriptIsConsistent(pOptions, pAvailableTranspilers) {
|
|
40
|
+
const lTypeScriptNeeded =
|
|
41
|
+
Boolean(pOptions?.tsConfig) ||
|
|
42
|
+
Boolean(pOptions?.tsPreCompilationDeps) ||
|
|
43
|
+
Boolean(pOptions?.detectJSDocImports) ||
|
|
44
|
+
(pOptions?.parser ?? "acorn") === "tsc";
|
|
45
|
+
return lTypeScriptNeeded
|
|
46
|
+
? pAvailableTranspilers.some(
|
|
47
|
+
(pTranspiler) =>
|
|
48
|
+
pTranspiler.name === "typescript" && pTranspiler.available,
|
|
49
|
+
)
|
|
50
|
+
: true;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* @param { IOptions } pOptions
|
|
54
|
+
* @param { IAvailableTranspiler[] } pAvailableTranspilers
|
|
55
|
+
* @returns { boolean }
|
|
56
|
+
*/
|
|
57
|
+
function babelIsConsistent(pOptions, pAvailableTranspilers) {
|
|
58
|
+
return Boolean(pOptions?.babelConfig)
|
|
59
|
+
? pAvailableTranspilers.some(
|
|
60
|
+
(pTranspiler) => pTranspiler.name === "babel" && pTranspiler.available,
|
|
61
|
+
)
|
|
62
|
+
: true;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* @param {IOptions} pOptions
|
|
67
|
+
* @param {IAvailableTranspiler[]} pAvailableTranspilers
|
|
68
|
+
* @returns {{issues?: IEnvironmentIssue[]}}
|
|
69
|
+
*/
|
|
70
|
+
function determineEnvironmentIssues(pOptions, pAvailableTranspilers) {
|
|
71
|
+
const lIssues = [];
|
|
72
|
+
if (!typescriptIsConsistent(pOptions, pAvailableTranspilers)) {
|
|
73
|
+
const tsTranspiler = pAvailableTranspilers.find(
|
|
74
|
+
(pTranspiler) => pTranspiler.name === "typescript",
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
lIssues.push({
|
|
78
|
+
severity: "warn",
|
|
79
|
+
name: "missing-typescript-transpiler",
|
|
80
|
+
description:
|
|
81
|
+
`dependency-cruiser detected a TypeScript environment,${EOL}` +
|
|
82
|
+
` but not a compatible TypeScript compiler (${tsTranspiler.name}: ${tsTranspiler.version}). This means${EOL}` +
|
|
83
|
+
` it's likely to have missed TypeScript sources and dependencies.${EOL}${EOL}` +
|
|
84
|
+
` Install typescript to get better results (e.g. npm i -D typescript@^6).${EOL}${EOL}` +
|
|
85
|
+
` => Support for typescript@>=7 will follow when its API is published and stable.${EOL}`,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
if (!swcIsConsistent(pOptions, pAvailableTranspilers)) {
|
|
89
|
+
const swcTranspiler = pAvailableTranspilers.find(
|
|
90
|
+
(pTranspiler) => pTranspiler.name === "swc",
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
lIssues.push({
|
|
94
|
+
severity: "warn",
|
|
95
|
+
name: "missing-swc-transpiler",
|
|
96
|
+
description:
|
|
97
|
+
`dependency-cruiser found swc configured as parser, but ${EOL}` +
|
|
98
|
+
` it did not find a compatible version of swc (${swcTranspiler.name}: ${swcTranspiler.version}).${EOL}` +
|
|
99
|
+
` dependency-cruiser might have missed some sources or dependencies.${EOL}${EOL}` +
|
|
100
|
+
` Install swc (e.g. npm i -D @swc/core) to get better results.${EOL}`,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
if (!babelIsConsistent(pOptions, pAvailableTranspilers)) {
|
|
104
|
+
const babelTranspiler = pAvailableTranspilers.find(
|
|
105
|
+
(pTranspiler) => pTranspiler.name === "babel",
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
lIssues.push({
|
|
109
|
+
severity: "warn",
|
|
110
|
+
name: "missing-babel-transpiler",
|
|
111
|
+
description:
|
|
112
|
+
`dependency-cruiser detected a babel configuration, but not a${EOL}` +
|
|
113
|
+
` compatible babel transpiler (${babelTranspiler.name}: ${babelTranspiler.version}). If you indeed use babel,${EOL}` +
|
|
114
|
+
` dependency-cruiser might have missed some sources or dependencies.${EOL}${EOL}` +
|
|
115
|
+
` Install babel (e.g. npm i -D @babel/core@^7) to get better results.${EOL}`,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
return lIssues.length > 0 ? { issues: lIssues } : {};
|
|
119
|
+
}
|
|
11
120
|
|
|
12
121
|
/**
|
|
13
122
|
*
|
|
14
|
-
* @param {
|
|
123
|
+
* @param {IModule[]} pModules -
|
|
15
124
|
* cruised modules that have been enriched with mandatory attributes &
|
|
16
125
|
* have been validated against rules as passed in the options
|
|
17
|
-
* @param {
|
|
126
|
+
* @param {IStrictCruiseOptions} pOptions -
|
|
18
127
|
* @param {string[]} pFileDirectoryArray -
|
|
19
128
|
* the files/ directories originally passed to be cruised
|
|
20
|
-
* @param {
|
|
129
|
+
* @param {IFolder[]} pFolders -
|
|
21
130
|
* the pModules collapsed to folders, with their own metrics & deps
|
|
22
131
|
*
|
|
23
|
-
* @returns {
|
|
132
|
+
* @returns {ISummary} -
|
|
24
133
|
* a summary of the found modules, dependencies and any violations
|
|
25
134
|
*/
|
|
135
|
+
// eslint-disable-next-line max-params
|
|
26
136
|
export default function summarize(
|
|
27
137
|
pModules,
|
|
28
138
|
pOptions,
|
|
29
139
|
pFileDirectoryArray,
|
|
30
140
|
pFolders,
|
|
141
|
+
pGetEnvironmentInfoFunction = getEnvironmentInfo,
|
|
31
142
|
) {
|
|
32
143
|
const lViolations = summarizeModules(pModules, pOptions.ruleSet)
|
|
33
144
|
.concat(summarizeFolders(pFolders || [], pOptions.ruleSet))
|
|
34
145
|
.sort(compareViolations);
|
|
35
146
|
|
|
147
|
+
const lEnvironment = pGetEnvironmentInfoFunction();
|
|
148
|
+
const lEnvironmentWithIssues = {
|
|
149
|
+
...lEnvironment,
|
|
150
|
+
...determineEnvironmentIssues(pOptions, lEnvironment.transpilersFound),
|
|
151
|
+
};
|
|
36
152
|
return {
|
|
37
153
|
violations: lViolations,
|
|
38
154
|
...getViolationStats(lViolations),
|
|
@@ -40,5 +156,6 @@ export default function summarize(
|
|
|
40
156
|
totalDependenciesCruised: getDependenciesCruised(pModules),
|
|
41
157
|
...summarizeOptions(pFileDirectoryArray, pOptions),
|
|
42
158
|
...(pOptions.ruleSet ? { ruleSetUsed: addRuleSetUsed(pOptions) } : {}),
|
|
159
|
+
environment: lEnvironmentWithIssues,
|
|
43
160
|
};
|
|
44
161
|
}
|
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 =
|
|
36
|
+
const CACHE_FORMAT_VERSION = 18.1;
|
|
37
37
|
|
|
38
38
|
export default class Cache {
|
|
39
39
|
/** @type {(IRevisionData | null)=} */
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import { release, platform, arch } from "node:os";
|
|
2
1
|
import { styleText } from "node:util";
|
|
3
|
-
|
|
4
|
-
import { getAvailableTranspilers, allExtensions } from "#main/index.mjs";
|
|
5
|
-
import meta from "#meta.cjs";
|
|
2
|
+
import { getEnvironmentInfo } from "#environment.mjs";
|
|
6
3
|
|
|
7
4
|
function bool2Symbol(pBool) {
|
|
8
5
|
return pBool ? styleText("green", "✔") : styleText("red", "x");
|
|
@@ -12,13 +9,13 @@ const MAX_VERSION_RANGE_STRING_LENGTH = 19;
|
|
|
12
9
|
const MAX_TRANSPILER_NAME_LENGTH = 22;
|
|
13
10
|
const MAX_VERSION_STRING_LENGTH = 24;
|
|
14
11
|
|
|
15
|
-
function formatTranspilers() {
|
|
12
|
+
function formatTranspilers(pAvailableTranspilers) {
|
|
16
13
|
let lTranspilerTableHeader = styleText(
|
|
17
14
|
"bold",
|
|
18
15
|
` ✔ ${"transpiler".padEnd(MAX_TRANSPILER_NAME_LENGTH)} ${"versions supported".padEnd(MAX_VERSION_RANGE_STRING_LENGTH)} version found`,
|
|
19
16
|
);
|
|
20
17
|
let lTranspilerTableDivider = ` - ${"-".repeat(MAX_TRANSPILER_NAME_LENGTH)} ${"-".repeat(MAX_VERSION_RANGE_STRING_LENGTH)} ${"-".repeat(MAX_VERSION_STRING_LENGTH)}`;
|
|
21
|
-
let lTranspilerTable =
|
|
18
|
+
let lTranspilerTable = pAvailableTranspilers
|
|
22
19
|
.map(
|
|
23
20
|
(pTranspiler) =>
|
|
24
21
|
` ${bool2Symbol(pTranspiler.available)} ${pTranspiler.name.padEnd(MAX_TRANSPILER_NAME_LENGTH)} ${pTranspiler.version.padEnd(MAX_VERSION_RANGE_STRING_LENGTH)} ${pTranspiler.currentVersion}`,
|
|
@@ -36,12 +33,13 @@ function formatExtensions(pExtensions) {
|
|
|
36
33
|
}
|
|
37
34
|
|
|
38
35
|
export default function formatMetaInfo() {
|
|
36
|
+
const lMetaInfo = getEnvironmentInfo();
|
|
39
37
|
return `
|
|
40
|
-
${styleText("bold", "dependency-cruiser")}@${
|
|
38
|
+
${styleText("bold", "dependency-cruiser")}@${lMetaInfo.version}
|
|
41
39
|
|
|
42
|
-
node version supported : ${
|
|
43
|
-
node version found : ${
|
|
44
|
-
os version found : ${
|
|
40
|
+
node version supported : ${lMetaInfo.nodeVersionSupported}
|
|
41
|
+
node version found : ${lMetaInfo.nodeVersionFound}
|
|
42
|
+
os version found : ${lMetaInfo.osVersionFound}
|
|
45
43
|
|
|
46
44
|
If you need a supported, but not enabled transpiler ('${styleText(
|
|
47
45
|
"red",
|
|
@@ -50,10 +48,10 @@ export default function formatMetaInfo() {
|
|
|
50
48
|
it in the same folder dependency-cruiser is installed. E.g. 'npm i livescript'
|
|
51
49
|
will enable livescript support if it's installed in your project folder.
|
|
52
50
|
|
|
53
|
-
${formatTranspilers()}
|
|
51
|
+
${formatTranspilers(lMetaInfo.transpilersFound)}
|
|
54
52
|
${styleText("bold", "✔ extension")}
|
|
55
53
|
- ---------
|
|
56
|
-
${formatExtensions(
|
|
54
|
+
${formatExtensions(lMetaInfo.extensionsFound)}
|
|
57
55
|
`;
|
|
58
56
|
}
|
|
59
57
|
|
package/src/cli/index.mjs
CHANGED
|
@@ -135,11 +135,10 @@ async function runCruise(pFileDirectoryArray, pCruiseOptions) {
|
|
|
135
135
|
/**
|
|
136
136
|
*
|
|
137
137
|
* @param {string[]} pFileDirectoryArray
|
|
138
|
-
* @param {import("../../types/options.mjs").ICruiseOptions}
|
|
138
|
+
* @param {import("../../types/options.mjs").ICruiseOptions} pCruiseOptions
|
|
139
139
|
* @param {{stdout: NodeJS.WritableStream, stderr: NodeJS.WritableStream}=} pStreams
|
|
140
140
|
* @returns {number}
|
|
141
141
|
*/
|
|
142
|
-
|
|
143
142
|
// eslint-disable-next-line max-lines-per-function
|
|
144
143
|
export default async function executeCli(
|
|
145
144
|
pFileDirectoryArray,
|
|
@@ -196,7 +196,7 @@ function normalizeCache(pCliOptions) {
|
|
|
196
196
|
*
|
|
197
197
|
* @param {object} pOptionsAsPassedFromCommander [description]
|
|
198
198
|
* @param {any} pKnownCliOptions [description]
|
|
199
|
-
* @return {
|
|
199
|
+
* @return {import("../../types/options.mjs").ICruiseOptions} [description]
|
|
200
200
|
*/
|
|
201
201
|
export default async function normalizeOptions(pOptionsAsPassedFromCommander) {
|
|
202
202
|
let lOptions = {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { release, platform, arch } from "node:os";
|
|
2
|
+
import meta from "#meta.cjs";
|
|
3
|
+
import {
|
|
4
|
+
getAvailableTranspilers,
|
|
5
|
+
allExtensions,
|
|
6
|
+
} from "#extract/transpile/meta.mjs";
|
|
7
|
+
|
|
8
|
+
export function getEnvironmentInfo() {
|
|
9
|
+
return {
|
|
10
|
+
version: meta.version,
|
|
11
|
+
nodeVersionSupported: meta.engines.node,
|
|
12
|
+
nodeVersionFound: process.version,
|
|
13
|
+
osVersionFound: `${arch()} ${platform()}@${release()}`,
|
|
14
|
+
transpilersFound: getAvailableTranspilers(),
|
|
15
|
+
extensionsFound: structuredClone(allExtensions),
|
|
16
|
+
};
|
|
17
|
+
}
|
package/src/main/report-wrap.mjs
CHANGED
package/src/meta.cjs
CHANGED
package/src/report/error.mjs
CHANGED
|
@@ -15,6 +15,13 @@ const SEVERITY2COLOR = new Map([
|
|
|
15
15
|
["ignore", "gray"],
|
|
16
16
|
]);
|
|
17
17
|
|
|
18
|
+
const SEVERITY2ICON = new Map([
|
|
19
|
+
["error", "x"],
|
|
20
|
+
["warn", "‼"],
|
|
21
|
+
["info", "i"],
|
|
22
|
+
["ignore", "-"],
|
|
23
|
+
]);
|
|
24
|
+
|
|
18
25
|
const EXTRA_PATH_INFORMATION_INDENT = 6;
|
|
19
26
|
|
|
20
27
|
function formatMiniDependency(pMiniDependency) {
|
|
@@ -116,6 +123,29 @@ function formatIgnoreWarning(pNumberOfIgnoredViolations) {
|
|
|
116
123
|
}
|
|
117
124
|
return "";
|
|
118
125
|
}
|
|
126
|
+
/**
|
|
127
|
+
* @param {import("../../types/cruise-result.mjs").IEnvironmentIssue} pEnvironmentIssue
|
|
128
|
+
* @returns {string}
|
|
129
|
+
*/
|
|
130
|
+
function formatEnvironmentIssue(pEnvironmentIssue) {
|
|
131
|
+
return styleText(
|
|
132
|
+
SEVERITY2COLOR.get(pEnvironmentIssue.severity),
|
|
133
|
+
`${SEVERITY2ICON.get(pEnvironmentIssue.severity)} ${styleText("bold", pEnvironmentIssue.name)}: ${pEnvironmentIssue.description}`,
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* @param {import("../../types/cruise-result.mjs").IEnvironmentIssue[]} pEnvironmentIssues
|
|
139
|
+
* @returns {string}
|
|
140
|
+
*/
|
|
141
|
+
function formatEnvironmentIssues(pEnvironmentIssues) {
|
|
142
|
+
const lEnvironmentIssues = pEnvironmentIssues ?? [];
|
|
143
|
+
|
|
144
|
+
return (
|
|
145
|
+
(lEnvironmentIssues.length > 0 ? EOL : "") +
|
|
146
|
+
lEnvironmentIssues.map(formatEnvironmentIssue).join(EOL)
|
|
147
|
+
);
|
|
148
|
+
}
|
|
119
149
|
|
|
120
150
|
function report(pResults, pOptions) {
|
|
121
151
|
const lOptions = {
|
|
@@ -135,7 +165,7 @@ function report(pResults, pOptions) {
|
|
|
135
165
|
pResults.summary.totalDependenciesCruised
|
|
136
166
|
} dependencies cruised)${EOL}${formatIgnoreWarning(
|
|
137
167
|
pResults.summary.ignore,
|
|
138
|
-
)}${EOL}`;
|
|
168
|
+
)}${formatEnvironmentIssues(pResults.summary.environment?.issues)}${EOL}`;
|
|
139
169
|
}
|
|
140
170
|
|
|
141
171
|
return lNonIgnorableViolations
|
|
@@ -147,6 +177,7 @@ function report(pResults, pOptions) {
|
|
|
147
177
|
)
|
|
148
178
|
.concat(formatSummary(pResults.summary))
|
|
149
179
|
.concat(formatIgnoreWarning(pResults.summary.ignore))
|
|
180
|
+
.concat(formatEnvironmentIssues(pResults.summary.environment?.issues))
|
|
150
181
|
.concat(EOL);
|
|
151
182
|
}
|
|
152
183
|
|