dependency-cruiser 11.15.0 → 11.16.0-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.
package/README.md CHANGED
@@ -13,47 +13,64 @@ This runs through the dependencies in any JavaScript, TypeScript, LiveScript or
13
13
  - in text (for your builds)
14
14
  - in graphics (for your eyeballs)
15
15
 
16
- As a side effect it can generate [**cool dependency graphs**](./doc/real-world-samples.md)
16
+ As a side effect it can generate dependency graphs in various output formats including [**cool visualizations**](./doc/real-world-samples.md)
17
17
  you can stick on the wall to impress your grandma.
18
18
 
19
19
  ## How do I use it?
20
20
 
21
21
  ### Install it
22
22
 
23
- - `npm install --save-dev dependency-cruiser` to use it as a validator in your project (recommended) or...
24
- - `npm install --global dependency-cruiser` if you just want to inspect multiple projects.
23
+ - `npm install --save-dev dependency-cruiser` (with `yarn` or `pnpm` use their
24
+ equivalent to install & save dependency-cruiser as a development dependency).
25
+
26
+ ### Generate a config
27
+
28
+ ```shell
29
+ npx depcruise --init
30
+ ```
31
+
32
+ This will look around in your environment a bit, ask you some questions and create
33
+ a `.dependency-cruiser.js` configuration file attuned to your project[^1].
34
+
35
+ [^1]:
36
+ We're using `npx` in the example scripts for convenience. When you use the
37
+ commands in a script in `package.json` it's not necessary to prefix them with
38
+ `npx`.
25
39
 
26
40
  ### Show stuff to your grandma
27
41
 
28
42
  To create a graph of the dependencies in your src folder, you'd run dependency
29
- cruiser with output type `dot` and run _GraphViz dot_ on the result. In
43
+ cruiser with output type `dot` and run _GraphViz dot_[^2] on the result. In
30
44
  a one liner:
31
45
 
32
46
  ```shell
33
- depcruise --include-only "^src" --output-type dot src | dot -T svg > dependencygraph.svg
47
+ npx depcruise src --include-only "^src" --config --output-type dot | dot -T svg > dependency-graph.svg
34
48
  ```
35
49
 
36
50
  - You can read more about what you can do with `--include-only` and other command line
37
51
  options in the [command line interface](./doc/cli.md) documentation.
38
52
  - _[Real world samples](./doc/real-world-samples.md)_
39
53
  contains dependency cruises of some of the most used projects on npm.
54
+ - If our grandma is more into formats like `mermaid`, `json`, `csv`, `html` or plain text
55
+ we've [got her covered](./doc/cli.md#--output-type-specify-the-output-format)
56
+ as well.
57
+
58
+ [^2]:
59
+ This assumes the GraphViz `dot` command is available - on most linux and
60
+ comparable systems this will be. In case it's not, see
61
+ [GraphViz' download page](https://www.graphviz.org/download/) for instructions
62
+ on how to get it on your machine.
40
63
 
41
64
  ### Validate things
42
65
 
43
66
  #### Declare some rules
44
67
 
45
- The easy way to get you started:
46
-
47
- ```shell
48
- depcruise --init
49
- ```
50
-
51
- This will ask you some questions and create a `.dependency-cruiser.js` with some
52
- rules that make sense in most projects (detecting **circular dependencies**,
53
- dependencies **missing** in package.json, **orphans**, production code relying on
54
- dev- or optionalDependencies, ...).
68
+ When you ran the `depcruise --init command` above, the command also added some rules
69
+ to `.dependency-cruiser.js` that make sense in most projects, like detecting
70
+ **circular dependencies**, dependencies **missing** in package.json, **orphans**,
71
+ and production code relying on dev- or optionalDependencies.
55
72
 
56
- Start adding your rules by tweaking that file.
73
+ Start adding your rules own by tweaking that file.
57
74
 
58
75
  Sample rule:
59
76
 
@@ -74,12 +91,11 @@ Sample rule:
74
91
  - To read more about writing rules check the
75
92
  [writing rules](./doc/rules-tutorial.md) tutorial
76
93
  or the [rules reference](./doc/rules-reference.md)
77
- - You can find the `--init-rules` set [here](./doc/rules.starter.json)
78
94
 
79
95
  #### Report them
80
96
 
81
97
  ```sh
82
- depcruise --config .dependency-cruiser.js src
98
+ npx depcruise --config .dependency-cruiser.js src
83
99
  ```
84
100
 
85
101
  This will validate against your rules and shows any violations in an eslint-like format:
@@ -87,14 +103,14 @@ This will validate against your rules and shows any violations in an eslint-like
87
103
  ![sample err output](https://raw.githubusercontent.com/sverweij/dependency-cruiser/master/doc/assets/sample-err-output.png)
88
104
 
89
105
  There's more ways to report validations; in a graph (like the one on top of this
90
- readme) or in a table.
106
+ readme) or in an self-containing `html` file.
91
107
 
92
108
  - Read more about the err, dot, csv and html reporters in the
93
109
  [command line interface](./doc/cli.md)
94
110
  documentation.
95
111
  - dependency-cruiser uses itself to check on itself in its own build process;
96
112
  see the `depcruise` script in the
97
- [package.json](https://github.com/sverweij/dependency-cruiser/blob/master/package.json#L64)
113
+ [package.json](https://github.com/sverweij/dependency-cruiser/blob/master/package.json#L76)
98
114
 
99
115
  ## I want to know more!
100
116
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dependency-cruiser",
3
- "version": "11.15.0",
3
+ "version": "11.16.0-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",
@@ -89,13 +89,13 @@
89
89
  "depcruise:graph:fdp": "node ./bin/dependency-cruise.js bin src --config --output-type dot | fdp -GK=0.1 -Gsplines=true -T svg > tmp_deps.svg",
90
90
  "depcruise:graph:osage": "node ./bin/dependency-cruise.js bin src --config --output-type dot | osage -Gpack=32 -GpackMode=array2 -T svg > tmp_deps.svg",
91
91
  "depcruise:graph:view": "node ./bin/dependency-cruise.js bin src --prefix vscode://file/$(pwd)/ --config configs/.dependency-cruiser-show-metrics-config.json --output-type dot --progress cli-feedback | dot -T svg | node ./bin/wrap-stream-in-html.js | browser",
92
- "depcruise:graph:view:diff": "node ./bin/dependency-cruise.js bin src --prefix vscode://file/$(pwd)/ --config configs/.dependency-cruiser-show-metrics-config.json --output-type dot --progress cli-feedback --focus \"$(watskeburt develop)\" | dot -T svg | node ./bin/wrap-stream-in-html.js | browser",
92
+ "depcruise:graph:view:diff": "node ./bin/dependency-cruise.js bin src test --prefix vscode://file/$(pwd)/ --config configs/.dependency-cruiser-show-metrics-config.json --output-type dot --progress cli-feedback --reaches \"$(watskeburt develop)\" | dot -T svg | node ./bin/wrap-stream-in-html.js | browser",
93
93
  "depcruise:report": "node ./bin/dependency-cruise.js src bin test configs types --output-type err-html --config configs/.dependency-cruiser-show-metrics-config.json --output-to dependency-violations.html",
94
94
  "depcruise:report:view": "node ./bin/dependency-cruise.js src bin test configs types --output-type err-html --config configs/.dependency-cruiser-show-metrics-config.json --output-to - | browser",
95
95
  "depcruise:focus": "node ./bin/dependency-cruise.js src bin test configs types tools --progress --config configs/.dependency-cruiser-show-metrics-config.json --output-type text --focus",
96
96
  "depcruise:reaches": "node ./bin/dependency-cruise.js src bin test configs types tools --progress --config configs/.dependency-cruiser-show-metrics-config.json --output-type text --reaches",
97
97
  "lint": "npm-run-all --parallel --aggregate-output lint:eslint lint:prettier lint:types",
98
- "lint:eslint": "eslint bin/dependency-cruise.js src test configs tools/**/*.mjs --cache --cache-location node_modules/.cache/eslint/",
98
+ "lint:eslint": "eslint bin/dependency-cruise.js bin src test configs tools/**/*.mjs --cache --cache-location node_modules/.cache/eslint/",
99
99
  "lint:eslint:fix": "eslint --fix bin src test configs tools/**/*.mjs --cache --cache-location node_modules/.cache/eslint/",
100
100
  "lint:fix": "npm-run-all lint:eslint:fix lint:prettier:fix lint:types:fix",
101
101
  "lint:prettier": "prettier --loglevel warn --check \"src/**/*.js\" \"configs/**/*.js\" \"tools/**/*.mjs\" \"bin/*\" \"types/*.d.ts\" \"test/**/*.spec.{cjs,js}\" \"test/**/*.{spec,utl}.mjs\"",
@@ -134,6 +134,7 @@
134
134
  "test:load:short": "hyperfine --warmup 1 --runs 5 \"bin/dependency-cruise.js --ignore-known --validate -- src bin test configs types tools\"",
135
135
  "test:watch": "mocha --watch --watch-extensions=json --reporter=min test/\\*\\*/\\*.spec.js",
136
136
  "update-dependencies": "npm-run-all upem:update upem:install build:clean build lint:fix depcruise test:cover",
137
+ "upem-outdated": "npm outdated --json --long | upem --dry-run",
137
138
  "upem:install": "npm install",
138
139
  "upem:update": "npm outdated --json --long | upem | pbcopy && pbpaste",
139
140
  "version": "npm-run-all build depcruise:graph:doc scm:stage"
@@ -154,6 +155,7 @@
154
155
  "handlebars": "4.7.7",
155
156
  "indent-string": "^4.0.0",
156
157
  "interpret": "^2.2.0",
158
+ "is-installed-globally": "0.4.0",
157
159
  "json5": "2.2.1",
158
160
  "lodash": "4.17.21",
159
161
  "prompts": "2.4.2",
@@ -167,24 +169,25 @@
167
169
  "wrap-ansi": "^7.0.0"
168
170
  },
169
171
  "devDependencies": {
170
- "@babel/core": "7.18.10",
172
+ "@babel/core": "7.18.13",
171
173
  "@babel/plugin-transform-modules-commonjs": "7.18.6",
172
174
  "@babel/preset-typescript": "7.18.6",
173
- "@swc/core": "1.2.241",
175
+ "@swc/core": "1.2.246",
174
176
  "@types/lodash": "4.14.184",
175
- "@types/node": "18.7.8",
177
+ "@types/node": "18.7.14",
176
178
  "@types/prompts": "2.0.14",
177
- "@typescript-eslint/eslint-plugin": "5.33.1",
178
- "@typescript-eslint/parser": "5.33.1",
179
- "@vue/compiler-sfc": "3.2.37",
179
+ "@typescript-eslint/eslint-plugin": "5.36.1",
180
+ "@typescript-eslint/parser": "5.36.1",
181
+ "@vue/compiler-sfc": "3.2.38",
180
182
  "c8": "7.12.0",
181
183
  "chai": "4.3.6",
182
184
  "chai-json-schema": "1.5.1",
183
185
  "coffeescript": "2.7.0",
184
- "eslint": "8.22.0",
185
- "eslint-config-moving-meadow": "3.0.0",
186
+ "eslint": "8.23.0",
187
+ "eslint-config-moving-meadow": "4.0.2",
186
188
  "eslint-config-prettier": "8.5.0",
187
- "eslint-plugin-budapestian": "4.0.0",
189
+ "eslint-plugin-budapestian": "5.0.0",
190
+ "eslint-plugin-eslint-comments": "3.2.0",
188
191
  "eslint-plugin-import": "2.26.0",
189
192
  "eslint-plugin-mocha": "10.1.0",
190
193
  "eslint-plugin-node": "11.1.0",
@@ -199,11 +202,11 @@
199
202
  "prettier": "2.7.1",
200
203
  "proxyquire": "2.1.3",
201
204
  "shx": "0.3.4",
202
- "svelte": "3.49.0",
205
+ "svelte": "3.50.0",
203
206
  "symlink-dir": "5.0.1",
204
- "typescript": "4.7.4",
205
- "upem": "7.2.0",
206
- "vue-template-compiler": "2.7.9",
207
+ "typescript": "4.8.2",
208
+ "upem": "7.3.0",
209
+ "vue-template-compiler": "2.7.10",
207
210
  "yarn": "1.22.19"
208
211
  },
209
212
  "upem": {
@@ -14,7 +14,7 @@ function writeCache(pCacheFolder, pCruiseResult) {
14
14
  writeFileSync(
15
15
  join(pCacheFolder, CACHE_FILE_NAME),
16
16
  JSON.stringify(pCruiseResult),
17
- "utf-8"
17
+ "utf8"
18
18
  );
19
19
  }
20
20
 
@@ -26,7 +26,7 @@ function writeCache(pCacheFolder, pCruiseResult) {
26
26
  function readCache(pCacheFolder) {
27
27
  try {
28
28
  return JSON.parse(
29
- readFileSync(join(pCacheFolder, CACHE_FILE_NAME), "utf-8")
29
+ readFileSync(join(pCacheFolder, CACHE_FILE_NAME), "utf8")
30
30
  );
31
31
  } catch (pError) {
32
32
  return { modules: [], summary: {} };
@@ -42,7 +42,7 @@ function hash(pString) {
42
42
 
43
43
  function getFileHash(pFileName) {
44
44
  try {
45
- return hash(readFileSync(pFileName, "utf-8"));
45
+ return hash(readFileSync(pFileName, "utf8"));
46
46
  } catch (pError) {
47
47
  return "file not found";
48
48
  }
package/src/cli/index.js CHANGED
@@ -2,6 +2,8 @@ const glob = require("glob");
2
2
  const get = require("lodash/get");
3
3
  const clone = require("lodash/clone");
4
4
  const set = require("lodash/set");
5
+ const isInstalledGlobally = require("is-installed-globally");
6
+ const { red, yellow, bold } = require("chalk");
5
7
 
6
8
  const main = require("../main");
7
9
  const bus = require("../utl/bus");
@@ -138,13 +140,30 @@ module.exports = function executeCli(pFileDirectoryArray, pCruiseOptions) {
138
140
  let lExitCode = 0;
139
141
 
140
142
  try {
143
+ /* c8 ignore start */
144
+ if (isInstalledGlobally) {
145
+ process.stderr.write(
146
+ `\n ${yellow(
147
+ "WARNING"
148
+ )}: You're running a globally installed dependency-cruiser.\n\n` +
149
+ ` We recommend to ${bold.italic.underline(
150
+ "install and run it as a local devDependency"
151
+ )} in\n` +
152
+ ` your project instead. There it has your project's environment and\n` +
153
+ ` transpilers at its disposal. That will ensure it can find e.g.\n` +
154
+ ` TypeScript, Vue or Svelte modules and dependencies.\n\n`
155
+ );
156
+ }
157
+ /* c8 ignore stop */
141
158
  if (pCruiseOptions.info === true) {
142
159
  process.stdout.write(formatMetaInfo());
143
160
  } else if (pCruiseOptions.init) {
144
- // requiring init-config takes ~100ms (most of it taken up by requiring
161
+ // requiring init-config took ~100ms (most of it taken up by requiring
145
162
  // inquirer, measured on a 2.6GHz quad core i7 with flash storage on
146
163
  // macOS 10.15.7). Only requiring it when '--init' is necessary speeds up
147
- // (the start-up) of cruises by that same amount.
164
+ // (the start-up) of cruises by that same amount. We've since replaced
165
+ // inquirer with 'prompts' (which is much smaller), but the same reasoning
166
+ // holds.
148
167
  // eslint-disable-next-line node/global-require
149
168
  const initConfig = require("./init-config");
150
169
  initConfig(pCruiseOptions.init);
@@ -152,7 +171,7 @@ module.exports = function executeCli(pFileDirectoryArray, pCruiseOptions) {
152
171
  lExitCode = runCruise(pFileDirectoryArray, pCruiseOptions);
153
172
  }
154
173
  } catch (pError) {
155
- process.stderr.write(`\n ERROR: ${pError.message}\n`);
174
+ process.stderr.write(`\n ${red("ERROR")}: ${pError.message}\n`);
156
175
  bus.emit("end");
157
176
  lExitCode = 1;
158
177
  }
@@ -17,11 +17,10 @@ require("./config.js.template");
17
17
  module.exports = function buildConfig(pNormalizedInitOptions) {
18
18
  return Handlebars.templates["config.js.template.hbs"]({
19
19
  ...pNormalizedInitOptions,
20
- ...{
21
- sourceLocationRE: folderNameArrayToRE(
22
- pNormalizedInitOptions.sourceLocation
23
- ),
24
- testLocationRE: folderNameArrayToRE(pNormalizedInitOptions.testLocation),
25
- },
20
+
21
+ sourceLocationRE: folderNameArrayToRE(
22
+ pNormalizedInitOptions.sourceLocation
23
+ ),
24
+ testLocationRE: folderNameArrayToRE(pNormalizedInitOptions.testLocation),
26
25
  });
27
26
  };
@@ -79,11 +79,8 @@ function isLikelyMonoRepo(pFolderNames = getFolderNames(process.cwd())) {
79
79
  }
80
80
 
81
81
  function hasTestsWithinSource(pTestLocations, pSourceLocations) {
82
- return (
83
- pTestLocations.length === 0 ||
84
- pTestLocations.every((pTestLocation) =>
85
- pSourceLocations.includes(pTestLocation)
86
- )
82
+ return pTestLocations.every((pTestLocation) =>
83
+ pSourceLocations.includes(pTestLocation)
87
84
  );
88
85
  }
89
86
 
package/src/cli/utl/io.js CHANGED
@@ -32,7 +32,6 @@ function writeToStdOut(pString, pBufferSize = PIPE_BUFFER_SIZE) {
32
32
 
33
33
  /* eslint no-plusplus: 0 */
34
34
  for (lIndex = 0; lIndex < lNumberOfChunks; lIndex++) {
35
- // eslint-disable-next-line unicorn/prefer-string-slice
36
35
  process.stdout.write(
37
36
  pString.substr(lIndex * pBufferSize, pBufferSize),
38
37
  "utf8"
@@ -5,7 +5,7 @@ const makeAbsolute = require("./make-absolute");
5
5
  module.exports = function extractKnownViolations(pKnownViolationsFileName) {
6
6
  try {
7
7
  return json5.parse(
8
- readFileSync(makeAbsolute(pKnownViolationsFileName), "utf-8")
8
+ readFileSync(makeAbsolute(pKnownViolationsFileName), "utf8")
9
9
  );
10
10
  // TODO: apparently node12 native coverage doesn't see this is covered with UT
11
11
  // (node 14 and 16 do), so c8 doesn't either. The ignore can be removed
@@ -82,7 +82,7 @@ function tryRegisterNonNative(pWebpackConfigFilename) {
82
82
  * @throws {Error} when the webpack config isn't usable (e.g. because it
83
83
  * doesn't exist, or because it's invalid)
84
84
  */
85
- // eslint-disable-next-line max-lines-per-function, complexity
85
+
86
86
  module.exports = function extractWebpackResolveConfig(
87
87
  pWebpackConfigFilename,
88
88
  pEnvironment,
@@ -1,4 +1,4 @@
1
- /* eslint-disable valid-jsdoc, no-inline-comments */
1
+ /* eslint-disable no-inline-comments */
2
2
  const tryRequire = require("semver-try-require");
3
3
  const { supportedTranspilers } = require("../../../src/meta.js");
4
4
 
package/src/main/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /* eslint-disable no-magic-numbers */
2
- /* eslint-disable import/max-dependencies */
2
+
3
3
  const Ajv = require("ajv").default;
4
4
  const extract = require("../extract");
5
5
  const enrich = require("../enrich");
@@ -81,10 +81,10 @@ function validateCruiseOptions(pOptions) {
81
81
  let lReturnValue = {};
82
82
 
83
83
  if (Boolean(pOptions)) {
84
- // neccessary because can slip through the cracks when passed as a cli parameter
84
+ // necessary because can slip through the cracks when passed as a cli parameter
85
85
  validateSystems(pOptions.moduleSystems);
86
86
 
87
- // neccessary because this safety check can't be done in json schema (a.f.a.i.k.)
87
+ // necessary because this safety check can't be done in json schema (a.f.a.i.k.)
88
88
  validatePathsSafety(pOptions.doNotFollow);
89
89
  validatePathsSafety(pOptions.exclude);
90
90
  validateRegExpSafety(pOptions.includeOnly);
@@ -95,7 +95,7 @@ function validateCruiseOptions(pOptions) {
95
95
  // necessary because not in the config schema
96
96
  validateOutputType(pOptions.outputType);
97
97
 
98
- // neccessary because not found a way to do this properly in JSON schema
98
+ // necessary because not found a way to do this properly in JSON schema
99
99
  validateMaxDepth(pOptions.maxDepth);
100
100
 
101
101
  validateFocusDepth(pOptions.focusDepth);
@@ -5,6 +5,18 @@ const { validateCruiseOptions } = require("../options/validate");
5
5
  const configurationSchema = require("../../schema/configuration.schema.js");
6
6
 
7
7
  const ajv = new Ajv();
8
+ // the default for this is 25 - as noted in the safe-regex source code already,
9
+ // the repeat limit is not the best of heuristics for indicating exponential time
10
+ // regular expressions - and it leads to false positives. E.g. if you use rules
11
+ // 'generated' from rules it could be the generated 'from' or 'to' have a list
12
+ // of file patterns that's easily > 25 of length. It's currently not possible
13
+ // to disable this check in safe-regex (e.g. by setting it to an odd value like
14
+ // 0 or -1, or by passing a 'switch this thing off please' option), so the only
15
+ // option is to increase the repeat limit to something fairly high.
16
+ //
17
+ // This does _not_ influence the star height algorithm, which is the main value
18
+ // of the safe-regex package.
19
+ const MAX_SAFE_REGEX_STAR_REPEAT_LIMIT = 10000;
8
20
 
9
21
  function validateAgainstSchema(pSchema, pConfiguration) {
10
22
  if (!ajv.validate(pSchema, pConfiguration)) {
@@ -21,7 +33,9 @@ function hasPath(pObject, pSection, pCondition) {
21
33
  function safeRule(pRule, pSection, pCondition) {
22
34
  return (
23
35
  !hasPath(pRule, pSection, pCondition) ||
24
- safeRegex(pRule[pSection][pCondition])
36
+ safeRegex(pRule[pSection][pCondition], {
37
+ limit: MAX_SAFE_REGEX_STAR_REPEAT_LIMIT,
38
+ })
25
39
  );
26
40
  }
27
41
 
@@ -1,4 +1,3 @@
1
- /* eslint-disable security/detect-object-injection */
2
1
  const get = require("lodash/get");
3
2
  const has = require("lodash/has");
4
3
  const set = require("lodash/set");
package/src/meta.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /* generated - don't edit */
2
2
 
3
3
  module.exports = {
4
- version: "11.15.0",
4
+ version: "11.16.0-beta-1",
5
5
  engines: {
6
6
  node: "^12.20||^14||>=16",
7
7
  },
@@ -1,6 +1,5 @@
1
1
  module.exports = {
2
2
  graph: {
3
- ordering: "out",
4
3
  rankdir: "LR",
5
4
  splines: "true",
6
5
  overlap: "false",
@@ -1,4 +1,3 @@
1
- /* eslint-disable security/detect-object-injection */
2
1
  const Handlebars = require("handlebars/runtime");
3
2
  const { formatSummaryForReport, aggregateViolations } = require("./utl");
4
3
 
@@ -1,4 +1,3 @@
1
- /* eslint-disable security/detect-object-injection */
2
1
  const chalk = require("chalk");
3
2
  const figures = require("figures");
4
3
  const get = require("lodash/get");