dependency-cruiser 16.10.2 → 16.10.4-beta-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.
@@ -1,43 +1,69 @@
1
1
  #!/usr/bin/env node
2
- import { program } from "commander";
2
+ // eslint-disable-next-line n/no-unsupported-features/node-builtins
3
+ import { parseArgs } from "node:util";
3
4
  import assertNodeEnvironmentSuitable from "#cli/assert-node-environment-suitable.mjs";
4
5
  import cli from "#cli/index.mjs";
5
6
  import meta from "#meta.cjs";
6
7
 
7
- function formatError(pError) {
8
- process.stderr.write(pError.message);
9
- process.exitCode = 1;
8
+ function showHelp() {
9
+ process.stdout
10
+ .write(`Usage: depcruise-baseline [options] <files-or-directories...>
11
+
12
+ Writes all known violations of rules in a .dependency-cruiser.js to a file.
13
+ Alias for depcruise -c -T baseline -f .dependency-cruiser-known-violations.json [files-or-directories]
14
+ Details: https://github.com/sverweij/dependency-cruiser
15
+
16
+ Options:
17
+ -c, --config [file] read rules and options from [file] (default: true)
18
+ -f, --output-to [file] file to write output to; - for stdout (default: ".dependency-cruiser-known-violations.json")
19
+ -V, --version display version number
20
+ -h, --help display help for command
21
+ `);
10
22
  }
11
23
 
12
24
  try {
13
25
  assertNodeEnvironmentSuitable();
14
26
 
15
- program
16
- .description(
17
- "Writes all known violations of rules in a .dependency-cruiser.js to a file.\n" +
18
- "Alias for depcruise -c -T baseline -f .dependency-cruiser-known-violations.json [files-or-directories]\n" +
19
- "Details: https://github.com/sverweij/dependency-cruiser",
20
- )
21
- .option("-c, --config [file]", "read rules and options from [file]", true)
22
- .option(
23
- "-f, --output-to [file]",
24
- "file to write output to; - for stdout",
25
- ".dependency-cruiser-known-violations.json",
26
- )
27
- .version(meta.version)
28
- .argument("<files-or-directories...>")
29
- .parse(process.argv);
27
+ const { values: options, positionals } = parseArgs({
28
+ options: {
29
+ config: {
30
+ type: "string",
31
+ short: "c",
32
+ default: "",
33
+ },
34
+ "output-to": {
35
+ type: "string",
36
+ short: "f",
37
+ default: ".dependency-cruiser-known-violations.json",
38
+ },
39
+ version: {
40
+ type: "boolean",
41
+ short: "V",
42
+ },
43
+ help: {
44
+ type: "boolean",
45
+ short: "h",
46
+ },
47
+ },
48
+ allowPositionals: true,
49
+ });
30
50
 
31
- if (program.args[0]) {
32
- process.exitCode = await cli(program.args, {
33
- ...program.opts(),
51
+ if (options.version) {
52
+ process.stdout.write(`${meta.version}\n`);
53
+ } else if (options.help || positionals.length === 0) {
54
+ showHelp();
55
+ } else {
56
+ if (options.config === "") {
57
+ options.config = true;
58
+ }
59
+ process.exitCode = await cli(positionals, {
60
+ config: options.config,
61
+ outputTo: options["output-to"],
34
62
  cache: false,
35
63
  outputType: "baseline",
36
64
  });
37
- } else {
38
- program.help();
39
65
  }
40
66
  } catch (pError) {
41
- formatError(pError);
67
+ process.stderr.write(pError.message);
42
68
  process.exitCode = 1;
43
69
  }
@@ -1,82 +1,126 @@
1
1
  #!/usr/bin/env node
2
-
3
- import { program } from "commander";
2
+ // eslint-disable-next-line n/no-unsupported-features/node-builtins
3
+ import { parseArgs } from "node:util";
4
4
  import assertNodeEnvironmentSuitable from "#cli/assert-node-environment-suitable.mjs";
5
5
  import format from "#cli/format.mjs";
6
6
  import meta from "#meta.cjs";
7
7
 
8
- function formatError(pError) {
9
- process.stderr.write(pError.message);
10
- process.exitCode = 1;
8
+ function showHelp() {
9
+ process.stdout.write(`Usage: depcruise-fmt [options] <dependency-cruiser-json>
10
+
11
+ Format dependency-cruiser output json.
12
+ Details: https://github.com/sverweij/dependency-cruiser
13
+
14
+ Options:
15
+ -f, --output-to <file> file to write output to; - for stdout (default: "-")
16
+ -T, --output-type <type> output type; e.g. err, err-html, dot, ddot, archi, flat,
17
+ d2, mermaid or json (default: "err")
18
+ -I, --include-only <regex> only include modules matching the regex
19
+ -F, --focus <regex> only include modules matching the regex + their direct neighbours
20
+ --focus-depth <number> the depth to focus on - only applied when --focus is passed too.
21
+ 1= direct neighbors, 2=neighbours of neighbours etc. (default: 1)
22
+ -R, --reaches <regex> only include modules matching the regex + all modules that can reach it
23
+ -H, --highlight <regex> mark modules matching the regex as 'highlighted'
24
+ -x, --exclude <regex> exclude all modules matching the regex
25
+ -S, --collapse <regex> collapse to a folder depth by passing a single digit (e.g. 2). Or
26
+ pass a regex to collapse to a pattern E.g. ^packages/[^/]+/ would
27
+ collapse to modules/ folders directly under your packages folder.
28
+ -P, --prefix <prefix> prefix to use for links in the dot and err-html reporters
29
+ -e, --exit-code exit with a non-zero exit code when the input json contains error
30
+ level dependency violations. Works for err, err-long and teamcity
31
+ output types
32
+ -V, --version display version number
33
+ -h, --help display help for command
34
+ `);
11
35
  }
12
36
 
13
37
  try {
14
38
  assertNodeEnvironmentSuitable();
15
39
 
16
- program
17
- .description(
18
- "Format dependency-cruiser output json.\nDetails: https://github.com/sverweij/dependency-cruiser",
19
- )
20
- .option(
21
- "-f, --output-to <file>",
22
- "file to write output to; - for stdout",
23
- "-",
24
- )
25
- .option(
26
- "-T, --output-type <type>",
27
- "output type; e.g. err, err-html, dot, ddot, archi, flat, d2, mermaid or json",
28
- "err",
29
- )
30
- .option(
31
- "-I, --include-only <regex>",
32
- "only include modules matching the regex",
33
- )
34
- .option(
35
- "-F, --focus <regex>",
36
- "only include modules matching the regex + their direct neighbours",
37
- )
38
- .option(
39
- "--focus-depth <number>",
40
- "the depth to focus on - only applied when --focus is passed too. " +
41
- "1= direct neighbors, 2=neighbours of neighbours etc.",
42
- 1,
43
- )
44
- .option(
45
- "-R, --reaches <regex>",
46
- "only include modules matching the regex + all modules that can reach it",
47
- )
48
- .option(
49
- "-H, --highlight <regex>",
50
- "mark modules matching the regex as 'highlighted'",
51
- )
52
- .option("-x, --exclude <regex>", "exclude all modules matching the regex")
53
- .option(
54
- "-S, --collapse <regex>",
55
- "collapse to a folder depth by passing a single digit (e.g. 2). Or pass a " +
56
- "regex to collapse to a pattern E.g. ^packages/[^/]+/ would collapse to " +
57
- "modules/ folders directly under your packages folder. ",
58
- )
59
- .option(
60
- "-P, --prefix <prefix>",
61
- "prefix to use for links in the dot and err-html reporters",
62
- )
63
- .option(
64
- "-e, --exit-code",
65
- "exit with a non-zero exit code when the input json contains error level " +
66
- "dependency violations. Works for err, err-long and teamcity output types",
67
- )
68
- .version(meta.version)
69
- .argument("<dependency-cruiser-json>")
70
- .parse(process.argv);
40
+ const { values: options, positionals } = parseArgs({
41
+ options: {
42
+ "output-to": {
43
+ type: "string",
44
+ short: "f",
45
+ default: "-",
46
+ },
47
+ "output-type": {
48
+ type: "string",
49
+ short: "T",
50
+ default: "err",
51
+ },
52
+ "include-only": {
53
+ type: "string",
54
+ short: "I",
55
+ },
56
+ focus: {
57
+ type: "string",
58
+ short: "F",
59
+ },
60
+ "focus-depth": {
61
+ type: "string",
62
+ default: "1",
63
+ },
64
+ reaches: {
65
+ type: "string",
66
+ short: "R",
67
+ },
68
+ highlight: {
69
+ type: "string",
70
+ short: "H",
71
+ },
72
+ exclude: {
73
+ type: "string",
74
+ short: "x",
75
+ },
76
+ collapse: {
77
+ type: "string",
78
+ short: "S",
79
+ },
80
+ prefix: {
81
+ type: "string",
82
+ short: "P",
83
+ },
84
+ "exit-code": {
85
+ type: "boolean",
86
+ short: "e",
87
+ },
88
+ version: {
89
+ type: "boolean",
90
+ short: "V",
91
+ },
92
+ help: {
93
+ type: "boolean",
94
+ short: "h",
95
+ },
96
+ },
97
+ allowPositionals: true,
98
+ });
71
99
 
72
- if (program.args[0]) {
73
- const lExitCode = await format(program.args[0], program.opts());
74
- if (program.opts().exitCode) {
100
+ if (options.version) {
101
+ process.stdout.write(`${meta.version}\n`);
102
+ } else if (options.help || positionals.length === 0) {
103
+ showHelp();
104
+ } else {
105
+ const lFormatOptions = {
106
+ ...options,
107
+ outputTo: options["output-to"],
108
+ outputType: options["output-type"],
109
+ includeOnly: options["include-only"],
110
+ focusDepth: options["focus-depth"],
111
+ exitCode: options["exit-code"],
112
+ };
113
+ delete lFormatOptions["output-to"];
114
+ delete lFormatOptions["output-type"];
115
+ delete lFormatOptions["include-only"];
116
+ delete lFormatOptions["focus-depth"];
117
+ delete lFormatOptions["exit-code"];
118
+ const lExitCode = await format(positionals[0], lFormatOptions);
119
+ if (lFormatOptions.exitCode) {
75
120
  process.exitCode = lExitCode;
76
121
  }
77
- } else {
78
- program.help();
79
122
  }
80
123
  } catch (pError) {
81
- formatError(pError);
124
+ process.stderr.write(pError.message);
125
+ process.exitCode = 1;
82
126
  }
@@ -76,7 +76,7 @@ export default (pCruiseResult) => ({
76
76
  output: JSON.stringify(
77
77
  samplePluginReporter(pCruiseResult),
78
78
  null,
79
- DEFAULT_JSON_INDENT
79
+ DEFAULT_JSON_INDENT,
80
80
  ),
81
81
  exitCode: 0,
82
82
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dependency-cruiser",
3
- "version": "16.10.2",
3
+ "version": "16.10.4-beta-1",
4
4
  "description": "Validate and visualize dependencies. With your rules. JavaScript, TypeScript, CoffeeScript. ES6, CommonJS, AMD.",
5
5
  "keywords": [
6
6
  "static analysis",
@@ -140,15 +140,15 @@
140
140
  "README.md"
141
141
  ],
142
142
  "dependencies": {
143
- "acorn": "^8.14.1",
143
+ "acorn": "^8.15.0",
144
144
  "acorn-jsx": "^5.3.2",
145
145
  "acorn-jsx-walk": "^2.0.0",
146
- "acorn-loose": "^8.5.0",
146
+ "acorn-loose": "^8.5.1",
147
147
  "acorn-walk": "^8.3.4",
148
148
  "ajv": "^8.17.1",
149
149
  "commander": "^13.1.0",
150
150
  "enhanced-resolve": "^5.18.1",
151
- "ignore": "^7.0.4",
151
+ "ignore": "^7.0.5",
152
152
  "interpret": "^3.1.1",
153
153
  "is-installed-globally": "^1.0.0",
154
154
  "json5": "^2.2.3",
@@ -158,7 +158,7 @@
158
158
  "prompts": "^2.4.2",
159
159
  "rechoir": "^0.8.0",
160
160
  "safe-regex": "^2.1.1",
161
- "semver": "^7.7.1",
161
+ "semver": "^7.7.2",
162
162
  "teamcity-service-messages": "^0.1.14",
163
163
  "tsconfig-paths-webpack-plugin": "^4.2.0",
164
164
  "watskeburt": "^4.2.3"
@@ -7,13 +7,13 @@ export function findFolderByName(pAllFolders, pName) {
7
7
 
8
8
  export function getAfferentCouplings(pModule, pDirname) {
9
9
  return pModule.dependents.filter(
10
- (pDependent) => !pDependent.startsWith(pDirname.concat(sep))
10
+ (pDependent) => !pDependent.startsWith(pDirname.concat(sep)),
11
11
  );
12
12
  }
13
13
 
14
14
  export function getEfferentCouplings(pModule, pDirname) {
15
15
  return pModule.dependencies.filter(
16
- (pDependency) => !pDependency.resolved.startsWith(pDirname.concat(sep))
16
+ (pDependency) => !pDependency.resolved.startsWith(pDirname.concat(sep)),
17
17
  );
18
18
  }
19
19
 
@@ -1,7 +1,7 @@
1
1
  export function isDependent(pResolvedName) {
2
2
  return (pModule) =>
3
3
  pModule.dependencies.some(
4
- (pDependency) => pDependency.resolved === pResolvedName
4
+ (pDependency) => pDependency.resolved === pResolvedName,
5
5
  );
6
6
  }
7
7
 
@@ -23,7 +23,7 @@ export function metricsAreCalculable(pModule) {
23
23
  */
24
24
  export function calculateInstability(
25
25
  pEfferentCouplingCount,
26
- pAfferentCouplingCount
26
+ pAfferentCouplingCount,
27
27
  ) {
28
28
  // when both afferentCouplings and efferentCouplings equal 0 instability will
29
29
  // yield NaN. Judging Bob Martin's intention, a component with no outgoing
@@ -59,11 +59,12 @@ function softenDependencyViolations(
59
59
  }
60
60
  return pDependency;
61
61
  }
62
+
62
63
  /**
63
64
  *
64
65
  * @param {import("../../types/cruise-result.mjs").IModule} pModule
65
- * @param {import("../../types/baseline-violations.js").IBaselineViolations} pKnownViolations
66
- * @param {import("../../types/shared-types.js").SeverityType} pSoftenedSeverity
66
+ * @param {import("../../types/baseline-violations.mjs").IBaselineViolations} pKnownViolations
67
+ * @param {import("../../types/shared-types.mjs").SeverityType} pSoftenedSeverity
67
68
  * @returns {import("../../types/cruise-result.mjs").IModule}
68
69
  */
69
70
  function softenKnownViolation(pModule, pKnownViolations, pSoftenedSeverity) {
@@ -76,9 +77,8 @@ function softenKnownViolation(pModule, pKnownViolations, pSoftenedSeverity) {
76
77
  softenModuleViolation(
77
78
  pRule,
78
79
  pModule.source,
79
- pKnownViolations.filter(
80
- (pKnownError) =>
81
- pKnownError.from === pKnownError.to && !pKnownError.cycle,
80
+ pKnownViolations.filter((pKnownViolation) =>
81
+ ["module", "reachability"].includes(pKnownViolation.type),
82
82
  ),
83
83
  pSoftenedSeverity,
84
84
  ),
@@ -92,23 +92,26 @@ function softenKnownViolation(pModule, pKnownViolations, pSoftenedSeverity) {
92
92
  softenDependencyViolations(
93
93
  pDependency,
94
94
  pModule.source,
95
- pKnownViolations.filter(
96
- (pKnownError) =>
97
- pKnownError.from !== pKnownError.to || pKnownError.cycle,
95
+ pKnownViolations.filter((pKnownViolation) =>
96
+ ["dependency", "cycle", "instability"].includes(pKnownViolation.type),
98
97
  ),
99
98
  pSoftenedSeverity,
100
99
  ),
101
100
  ),
102
101
  };
103
102
 
103
+ // TODO: folder level violations (e.g. with 'instability' rules - these need
104
+ // to be softened within the "folders" node, which lives next to the "modules"
105
+ // one)
106
+
104
107
  return lReturnValue;
105
108
  }
106
109
 
107
110
  /**
108
111
  *
109
112
  * @param {import("../../types/cruise-result.mjs").IModule[]} pModules
110
- * @param {import("../../types/baseline-violations.js").IBaselineViolations} pKnownViolations
111
- * @param {import("../../types/shared-types.js").SeverityType} pSoftenedSeverity
113
+ * @param {import("../../types/baseline-violations.mjs").IBaselineViolations} pKnownViolations
114
+ * @param {import("../../types/shared-types.mjs").SeverityType} pSoftenedSeverity
112
115
  * @returns {import("../../types/cruise-result.mjs").IModule[]}
113
116
  */
114
117
  export default function softenKnownViolations(
@@ -9,7 +9,7 @@ export function getViolationStats(pViolations) {
9
9
  warn: 0,
10
10
  info: 0,
11
11
  ignore: 0,
12
- }
12
+ },
13
13
  );
14
14
  }
15
15
 
@@ -20,6 +20,6 @@ export function getModulesCruised(pModules) {
20
20
  export function getDependenciesCruised(pModules) {
21
21
  return pModules.reduce(
22
22
  (pAll, pModule) => pAll + pModule.dependencies.length,
23
- 0
23
+ 0,
24
24
  );
25
25
  }
@@ -3,22 +3,31 @@ function pluckName({ name }) {
3
3
  }
4
4
 
5
5
  export default function isSameViolation(pLeftViolation, pRightViolation) {
6
- let lReturnValue = false;
7
-
8
6
  if (pLeftViolation.rule.name === pRightViolation.rule.name) {
9
7
  if (pRightViolation.cycle && pLeftViolation.cycle) {
10
- lReturnValue =
8
+ return (
11
9
  pLeftViolation.cycle.length === pRightViolation.cycle.length &&
12
10
  pLeftViolation.cycle
13
11
  .map(pluckName)
14
12
  .every((pModule) =>
15
13
  pRightViolation.cycle.map(pluckName).includes(pModule),
16
- );
17
- } else {
18
- lReturnValue =
19
- pLeftViolation.from === pRightViolation.from &&
20
- pLeftViolation.to === pRightViolation.to;
14
+ )
15
+ );
16
+ }
17
+ if (pRightViolation.via && pLeftViolation.via) {
18
+ return (
19
+ pLeftViolation.via.length === pRightViolation.via.length &&
20
+ pLeftViolation.via
21
+ .map(pluckName)
22
+ .every((pModule) =>
23
+ pRightViolation.via.map(pluckName).includes(pModule),
24
+ )
25
+ );
21
26
  }
27
+ return (
28
+ pLeftViolation.from === pRightViolation.from &&
29
+ pLeftViolation.to === pRightViolation.to
30
+ );
22
31
  }
23
- return lReturnValue;
32
+ return false;
24
33
  }
@@ -19,6 +19,6 @@ function squashModuleToDirectory(pModule) {
19
19
 
20
20
  export default function consolidateToFolder(pModules) {
21
21
  return consolidateModules(pModules.map(squashModuleToDirectory)).map(
22
- consolidateModuleDependencies
22
+ consolidateModuleDependencies,
23
23
  );
24
24
  }
@@ -35,10 +35,10 @@ function squashModuleToPattern(pCollapsePattern) {
35
35
  consolidated: determineConsolidatedness(
36
36
  pModule.consolidated,
37
37
  lCollapseMatch,
38
- pModule.source
38
+ pModule.source,
39
39
  ),
40
40
  dependencies: pModule.dependencies.map(
41
- squashDependencyToPattern(pCollapsePattern)
41
+ squashDependencyToPattern(pCollapsePattern),
42
42
  ),
43
43
  };
44
44
  };
@@ -46,6 +46,6 @@ function squashModuleToPattern(pCollapsePattern) {
46
46
 
47
47
  export default function consolidateToPattern(pModules, pCollapsePattern) {
48
48
  return consolidateModules(
49
- pModules.map(squashModuleToPattern(pCollapsePattern))
49
+ pModules.map(squashModuleToPattern(pCollapsePattern)),
50
50
  ).map(consolidateModuleDependencies);
51
51
  }
@@ -2,7 +2,7 @@ export default function stripSelfTransitions(pModule) {
2
2
  return {
3
3
  ...pModule,
4
4
  dependencies: pModule.dependencies.filter(
5
- (pDependency) => pModule.source !== pDependency.resolved
5
+ (pDependency) => pModule.source !== pDependency.resolved,
6
6
  ),
7
7
  };
8
8
  }
package/src/meta.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  /* generated - don't edit */
2
2
 
3
3
  module.exports = {
4
- version: "16.10.2",
4
+ version: "16.10.4-beta-1",
5
5
  engines: {
6
6
  node: "^18.17||>=20",
7
7
  },
@@ -9,7 +9,7 @@ function compareOnSource(pOne, pTwo) {
9
9
  function determineIncidenceType(pFromListEntry) {
10
10
  return (pModule) => {
11
11
  let lDependency = pModule.dependencies.find(
12
- (pDependency) => pDependency.resolved === pFromListEntry.source
12
+ (pDependency) => pDependency.resolved === pFromListEntry.source,
13
13
  );
14
14
 
15
15
  if (lDependency) {
@@ -26,7 +26,7 @@ function fileIsDirectory(pFullPathToFile, pBaseDirectory) {
26
26
  */
27
27
  function walk(
28
28
  pDirectoryName,
29
- { baseDir, ignoreFilterFn, excludeFilterFn, includeOnlyFilterFn }
29
+ { baseDir, ignoreFilterFn, excludeFilterFn, includeOnlyFilterFn },
30
30
  ) {
31
31
  return readdirSync(join(baseDir, pDirectoryName))
32
32
  .map((pFileName) => join(pDirectoryName, pFileName))
@@ -51,12 +51,12 @@ function walk(
51
51
  ignoreFilterFn,
52
52
  excludeFilterFn,
53
53
  includeOnlyFilterFn,
54
- })
54
+ }),
55
55
  );
56
56
  }
57
57
  return pSum.concat(fullPathToFile);
58
58
  },
59
- []
59
+ [],
60
60
  )
61
61
  .map((pFullPathToFile) => pathToPosix(pFullPathToFile));
62
62
  }
@@ -90,7 +90,7 @@ export default function findAllFiles(
90
90
  additionalIgnorePatterns,
91
91
  excludeFilterFn,
92
92
  includeOnlyFilterFn,
93
- }
93
+ },
94
94
  ) {
95
95
  const lIgnoreFileContents =
96
96
  ignoreFileContents ?? readIgnoreFile(join(baseDir, ".gitignore"));