dependency-cruiser 18.6.0 → 18.7.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.
@@ -2,7 +2,7 @@ module.exports = {
2
2
  name: "no-duplicate-dep-types",
3
3
  comment:
4
4
  "Likely this module depends on an external ('npm') package that occurs more " +
5
- "than once in your package.json i.e. bot as a devDependencies and in dependencies. " +
5
+ "than once in your package.json i.e. both as a devDependencies and in dependencies. " +
6
6
  "This will cause maintenance problems later on. If it's intentional, you can " +
7
7
  "disable this rule by adding this override as a rule in the 'forbidden' section " +
8
8
  "of your dependency-cruiser configuration: " +
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dependency-cruiser",
3
- "version": "18.6.0",
3
+ "version": "18.7.0",
4
4
  "description": "Validate and visualize dependencies. With your rules. JavaScript, TypeScript, CoffeeScript. ES6, CommonJS, AMD.",
5
5
  "keywords": [
6
6
  "static analysis",
@@ -1,4 +1,3 @@
1
- import { EOL } from "node:os";
2
1
  import addRuleSetUsed from "./add-rule-set-used.mjs";
3
2
  import summarizeModules from "./summarize-modules.mjs";
4
3
  import summarizeFolders from "./summarize-folders.mjs";
@@ -11,6 +10,7 @@ import {
11
10
  } from "./get-stats.mjs";
12
11
  import { compareViolations } from "#graph-utl/compare.mjs";
13
12
  import { getEnvironmentInfo } from "#environment.mjs";
13
+ import { determineEnvironmentIssues } from "./verify-environment.mjs";
14
14
 
15
15
  /**
16
16
  * @import { IOptions, IEnvironmentIssue, ISummary, IModule, IFolder } from "../../../types/cruise-result.mjs"
@@ -18,107 +18,6 @@ import { getEnvironmentInfo } from "#environment.mjs";
18
18
  * @import { IStrictCruiseOptions } from "../../../types/strict-options.mjs"
19
19
  */
20
20
 
21
- /**
22
- * @param { IOptions } pOptions
23
- * @param { IAvailableTranspiler[] } pAvailableTranspilers
24
- * @returns { boolean }
25
- */
26
- function swcIsConsistent(pOptions, pAvailableTranspilers) {
27
- const lSWCNeeded = (pOptions?.parser ?? "acorn") === "swc";
28
- return lSWCNeeded
29
- ? pAvailableTranspilers.some(
30
- (pTranspiler) => pTranspiler.name === "swc" && pTranspiler.available,
31
- )
32
- : true;
33
- }
34
-
35
- /**
36
- * @param { IOptions } pOptions
37
- * @param { IAvailableTranspiler[] } pAvailableTranspilers
38
- * @returns { boolean }
39
- */
40
- function typescriptIsConsistent(pOptions, pAvailableTranspilers) {
41
- const lTypeScriptNeeded =
42
- Boolean(pOptions?.tsConfig) ||
43
- Boolean(pOptions?.tsPreCompilationDeps) ||
44
- Boolean(pOptions?.detectJSDocImports) ||
45
- (pOptions?.parser ?? "acorn") === "tsc";
46
- return lTypeScriptNeeded
47
- ? pAvailableTranspilers.some(
48
- (pTranspiler) =>
49
- pTranspiler.name === "typescript" && pTranspiler.available,
50
- )
51
- : true;
52
- }
53
- /**
54
- * @param { IOptions } pOptions
55
- * @param { IAvailableTranspiler[] } pAvailableTranspilers
56
- * @returns { boolean }
57
- */
58
- function babelIsConsistent(pOptions, pAvailableTranspilers) {
59
- return Boolean(pOptions?.babelConfig)
60
- ? pAvailableTranspilers.some(
61
- (pTranspiler) => pTranspiler.name === "babel" && pTranspiler.available,
62
- )
63
- : true;
64
- }
65
-
66
- /**
67
- * @param {IOptions} pOptions
68
- * @param {IAvailableTranspiler[]} pAvailableTranspilers
69
- * @returns {{issues?: IEnvironmentIssue[]}}
70
- */
71
- function determineEnvironmentIssues(pOptions, pAvailableTranspilers) {
72
- const lIssues = [];
73
- if (!typescriptIsConsistent(pOptions, pAvailableTranspilers)) {
74
- const tsTranspiler = pAvailableTranspilers.find(
75
- (pTranspiler) => pTranspiler.name === "typescript",
76
- );
77
-
78
- lIssues.push({
79
- severity: "warn",
80
- name: "missing-typescript-transpiler",
81
- description:
82
- `dependency-cruiser detected a TypeScript environment,${EOL}` +
83
- ` but not a compatible TypeScript compiler (${tsTranspiler.name}: ${tsTranspiler.version}). This means${EOL}` +
84
- ` it's likely to have missed TypeScript sources and dependencies.${EOL}${EOL}` +
85
- ` Install typescript to get better results (e.g. npm i -D typescript@^6).${EOL}${EOL}` +
86
- ` => Support for typescript@>=7 will follow when its API is published and stable.${EOL}`,
87
- });
88
- }
89
- if (!swcIsConsistent(pOptions, pAvailableTranspilers)) {
90
- const swcTranspiler = pAvailableTranspilers.find(
91
- (pTranspiler) => pTranspiler.name === "swc",
92
- );
93
-
94
- lIssues.push({
95
- severity: "warn",
96
- name: "missing-swc-transpiler",
97
- description:
98
- `dependency-cruiser found swc configured as parser, but ${EOL}` +
99
- ` it did not find a compatible version of swc (${swcTranspiler.name}: ${swcTranspiler.version}).${EOL}` +
100
- ` dependency-cruiser might have missed some sources or dependencies.${EOL}${EOL}` +
101
- ` Install swc (e.g. npm i -D @swc/core) to get better results.${EOL}`,
102
- });
103
- }
104
- if (!babelIsConsistent(pOptions, pAvailableTranspilers)) {
105
- const babelTranspiler = pAvailableTranspilers.find(
106
- (pTranspiler) => pTranspiler.name === "babel",
107
- );
108
-
109
- lIssues.push({
110
- severity: "warn",
111
- name: "missing-babel-transpiler",
112
- description:
113
- `dependency-cruiser detected a babel configuration, but not a${EOL}` +
114
- ` compatible babel transpiler (${babelTranspiler.name}: ${babelTranspiler.version}). If you indeed use babel,${EOL}` +
115
- ` dependency-cruiser might have missed some sources or dependencies.${EOL}${EOL}` +
116
- ` Install babel (e.g. npm i -D @babel/core@^7) to get better results.${EOL}`,
117
- });
118
- }
119
- return lIssues.length > 0 ? { issues: lIssues } : {};
120
- }
121
-
122
21
  function getAdvisedExitCode(
123
22
  pErrorCount,
124
23
  pBaselineStaleCount,
@@ -0,0 +1,146 @@
1
+ import { EOL } from "node:os";
2
+ /**
3
+ * @import { IOptions, IEnvironmentIssue } from "../../../types/cruise-result.mjs"
4
+ * @import { IAvailableTranspiler } from "../../../types/environment.mjs"
5
+ */
6
+
7
+ /**
8
+ * @param { IOptions } pOptions
9
+ * @param { IAvailableTranspiler[] } pAvailableTranspilers
10
+ * @returns { boolean }
11
+ */
12
+ function swcIsConsistent(pOptions, pAvailableTranspilers) {
13
+ const lSWCNeeded = (pOptions?.parser ?? "acorn") === "swc";
14
+ return lSWCNeeded
15
+ ? pAvailableTranspilers.some(
16
+ (pTranspiler) => pTranspiler.name === "swc" && pTranspiler.available,
17
+ )
18
+ : true;
19
+ }
20
+
21
+ /**
22
+ * @param { IOptions } pOptions
23
+ * @param { IAvailableTranspiler[] } pAvailableTranspilers
24
+ * @returns { boolean }
25
+ */
26
+ function tscIsConsistent(pOptions, pAvailableTranspilers) {
27
+ const lTSCNeeded =
28
+ Boolean(pOptions?.tsPreCompilationDeps) ||
29
+ Boolean(pOptions?.detectJSDocImports) ||
30
+ (pOptions?.parser ?? "acorn") === "tsc";
31
+ return lTSCNeeded
32
+ ? pAvailableTranspilers.some(
33
+ (pTranspiler) =>
34
+ pTranspiler.name === "typescript" && pTranspiler.available,
35
+ )
36
+ : true;
37
+ }
38
+
39
+ function typeScriptIsConsistent(pOptions, pAvailableTranspilers) {
40
+ const lTypeScriptNeeded =
41
+ Boolean(pOptions?.tsConfig) &&
42
+ !(
43
+ // these two options require tsc (covered in tscIsConsistent), so
44
+ // to prevent typeScriptIsConsistent from also firing (and printing
45
+ // two messages) we exclude them here
46
+ Boolean(pOptions?.tsPreCompilationDeps) ||
47
+ Boolean(pOptions?.detectJSDocImports)
48
+ );
49
+ return lTypeScriptNeeded
50
+ ? pAvailableTranspilers.some(
51
+ (pTranspiler) =>
52
+ (pTranspiler.name === "typescript" ||
53
+ (pTranspiler.name === "swc" && pOptions?.parser === "swc")) &&
54
+ pTranspiler.available,
55
+ )
56
+ : true;
57
+ }
58
+
59
+ /**
60
+ * @param { IOptions } pOptions
61
+ * @param { IAvailableTranspiler[] } pAvailableTranspilers
62
+ * @returns { boolean }
63
+ */
64
+ function babelIsConsistent(pOptions, pAvailableTranspilers) {
65
+ return Boolean(pOptions?.babelConfig)
66
+ ? pAvailableTranspilers.some(
67
+ (pTranspiler) => pTranspiler.name === "babel" && pTranspiler.available,
68
+ )
69
+ : true;
70
+ }
71
+
72
+ /**
73
+ * @param {IOptions} pOptions
74
+ * @param {IAvailableTranspiler[]} pAvailableTranspilers
75
+ * @returns {{issues?: IEnvironmentIssue[]}}
76
+ */
77
+ export function determineEnvironmentIssues(pOptions, pAvailableTranspilers) {
78
+ const lIssues = [];
79
+ if (!tscIsConsistent(pOptions, pAvailableTranspilers)) {
80
+ const tsTranspiler = pAvailableTranspilers.find(
81
+ (pTranspiler) => pTranspiler.name === "typescript",
82
+ );
83
+
84
+ lIssues.push({
85
+ severity: "warn",
86
+ name: "missing-tsc-transpiler",
87
+ description:
88
+ `dependency-cruiser detected a TypeScript environment,${EOL}` +
89
+ ` but not a compatible TypeScript compiler (${tsTranspiler.name}: ${tsTranspiler.version}). This means${EOL}` +
90
+ ` it's likely to have missed TypeScript sources and dependencies.${EOL}${EOL}` +
91
+ ` Install typescript to get better results (e.g. npm i -D typescript@^6).${EOL}${EOL}` +
92
+ ` => Support for typescript@>=7 will follow when its API is published and stable.${EOL}`,
93
+ });
94
+ }
95
+ if (!typeScriptIsConsistent(pOptions, pAvailableTranspilers)) {
96
+ const tsTranspilersString = pAvailableTranspilers
97
+ .filter(
98
+ (pTranspiler) =>
99
+ pTranspiler.name === "typescript" || pTranspiler.name === "swc",
100
+ )
101
+ .map((pTranspiler) => `${pTranspiler.name}: ${pTranspiler.version}`)
102
+ .join(", ");
103
+ lIssues.push({
104
+ severity: "warn",
105
+ name: "missing-typescript-transpiler",
106
+ description:
107
+ `dependency-cruiser detected an environment that needs a TypeScript compiler of some sort,${EOL}` +
108
+ ` but did not find one of the supported ones (${tsTranspilersString}).${EOL}` +
109
+ ` This means it's likely to have missed TypeScript sources and dependencies.${EOL}${EOL}` +
110
+ ` Install one of the above for better results.${EOL}${EOL}` +
111
+ ` => if you choose to use swc don't forget to set the "parser" option to "swc"${EOL}` +
112
+ ` => Support for typescript@>=7 will follow when its API is published and stable.${EOL}`,
113
+ });
114
+ }
115
+ if (!swcIsConsistent(pOptions, pAvailableTranspilers)) {
116
+ const swcTranspiler = pAvailableTranspilers.find(
117
+ (pTranspiler) => pTranspiler.name === "swc",
118
+ );
119
+
120
+ lIssues.push({
121
+ severity: "warn",
122
+ name: "missing-swc-transpiler",
123
+ description:
124
+ `dependency-cruiser found swc configured as compiler, but ${EOL}` +
125
+ ` it did not find a compatible version of swc (${swcTranspiler.name}: ${swcTranspiler.version}).${EOL}` +
126
+ ` dependency-cruiser might have missed some sources or dependencies.${EOL}${EOL}` +
127
+ ` Install swc (e.g. npm i -D @swc/core) to get better results.${EOL}`,
128
+ });
129
+ }
130
+ if (!babelIsConsistent(pOptions, pAvailableTranspilers)) {
131
+ const babelTranspiler = pAvailableTranspilers.find(
132
+ (pTranspiler) => pTranspiler.name === "babel",
133
+ );
134
+
135
+ lIssues.push({
136
+ severity: "warn",
137
+ name: "missing-babel-transpiler",
138
+ description:
139
+ `dependency-cruiser detected a babel configuration, but not a${EOL}` +
140
+ ` compatible babel transpiler (${babelTranspiler.name}: ${babelTranspiler.version}). If you indeed use babel,${EOL}` +
141
+ ` dependency-cruiser might have missed some sources or dependencies.${EOL}${EOL}` +
142
+ ` Install babel (e.g. npm i -D @babel/core@^7) to get better results.${EOL}`,
143
+ });
144
+ }
145
+ return lIssues.length > 0 ? { issues: lIssues } : {};
146
+ }
@@ -112,7 +112,7 @@ module.exports = {
112
112
  name: 'no-duplicate-dep-types',
113
113
  comment:
114
114
  "Likely this module depends on an external ('npm') package that occurs more than once " +
115
- "in your package.json i.e. bot as a devDependencies and in dependencies. This will cause " +
115
+ "in your package.json i.e. both as a devDependencies and in dependencies. This will cause " +
116
116
  "maintenance problems later on.",
117
117
  severity: 'warn',
118
118
  from: {},
@@ -22,7 +22,9 @@ function dependencyKeyHasModuleName(
22
22
  pPrefix,
23
23
  ) {
24
24
  return (pKey) =>
25
- pKey.includes("ependencies") &&
25
+ // dependencies, devDependencies, peerDependencies, optionalDependencies, bundleDependencies, bundledDependencies.
26
+ // But not peerDependenciesMeta. Or dependenciesIDoNotWantToTalkabout.
27
+ pKey.endsWith("ependencies") &&
26
28
  Object.hasOwn(pPackageDependencies[pKey], join(pPrefix, pModuleName));
27
29
  }
28
30
 
@@ -123,7 +123,7 @@ function nodeIsTypeOnly(pNode) {
123
123
  return true;
124
124
  }
125
125
  return (
126
- pNode?.specifiers.length > 0 &&
126
+ pNode?.specifiers?.length > 0 &&
127
127
  pNode.specifiers.every((pSpecifier) => pSpecifier.isTypeOnly)
128
128
  );
129
129
  }
@@ -144,7 +144,9 @@ export default Visitor
144
144
  module: pNode.source.value,
145
145
  moduleSystem: "es6",
146
146
  exoticallyRequired: false,
147
- dependencyTypes: ["export"],
147
+ dependencyTypes: nodeIsTypeOnly(pNode)
148
+ ? ["export", "type-only"]
149
+ : ["export"],
148
150
  });
149
151
  }
150
152
  }
@@ -109,7 +109,19 @@ export const EXTENSION2AVAILABLE = new Map([
109
109
  ]);
110
110
 
111
111
  const EXTENSIONS_PER_PARSER = {
112
- swc: new Set([".js", ".cjs", ".mjs", ".jsx", ".ts", ".tsx", ".d.ts"]),
112
+ swc: new Set([
113
+ ".js",
114
+ ".cjs",
115
+ ".mjs",
116
+ ".jsx",
117
+ ".ts",
118
+ ".tsx",
119
+ ".d.ts",
120
+ ".cts",
121
+ ".d.cts",
122
+ ".mts",
123
+ ".d.mts",
124
+ ]),
113
125
  // tsc: [".js", ".cjs", ".mjs", ".jsx", ".ts", ".tsx", ".d.ts"],
114
126
  // acorn: [".js", ".cjs", ".mjs", ".jsx"],
115
127
  };
package/src/meta.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  /* generated - don't edit */
2
2
  module.exports = {
3
- version: "18.6.0",
3
+ version: "18.7.0",
4
4
  engines: {
5
5
  node: "^22||^24||>=26",
6
6
  },