dependency-cruiser 12.5.1 → 12.6.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.
@@ -111,6 +111,11 @@ try {
111
111
  "(experimental) strategy to use for detecting changed files in the cache. " +
112
112
  "Possible values: metadata (= use git, the default), content"
113
113
  )
114
+ .option(
115
+ "--no-cache",
116
+ "switch off caching. Overrides the 'cache' key in .dependency-cruiser.js " +
117
+ "and --cache options set earlier on the command line"
118
+ )
114
119
  .option("--preserve-symlinks", `leave symlinks unchanged (off by default)`)
115
120
  .option("-v, --validate [file]", `alias for --config`)
116
121
  .option(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dependency-cruiser",
3
- "version": "12.5.1",
3
+ "version": "12.6.0",
4
4
  "description": "Validate and visualize dependencies. With your rules. JavaScript, TypeScript, CoffeeScript. ES6, CommonJS, AMD.",
5
5
  "keywords": [
6
6
  "static analysis",
@@ -2,7 +2,7 @@ const chalk = require("chalk");
2
2
 
3
3
  const MS_PER_SECOND = 1000;
4
4
  const MS_PER_MICRO_SECOND = 0.001;
5
- const MAX_LENGTH_EXPECTED = 12;
5
+ const MAX_EXPECTED_LENGTH = 13;
6
6
  const NUMBER_OF_COLUMNS = 8;
7
7
  const K = 1024;
8
8
  /*
@@ -28,7 +28,11 @@ const gSizeFormat = new Intl.NumberFormat(LOCALE, {
28
28
  maximumFractionDigits: 0,
29
29
  }).format;
30
30
 
31
- const pad = (pString) => pString.padStart(MAX_LENGTH_EXPECTED).concat(" ");
31
+ const pad = (pString) => pString.padStart(MAX_EXPECTED_LENGTH).concat(" ");
32
+
33
+ function formatDividerLine() {
34
+ return `${`${"-".repeat(MAX_EXPECTED_LENGTH)} `.repeat(NUMBER_OF_COLUMNS)}\n`;
35
+ }
32
36
 
33
37
  function formatHeader() {
34
38
  return chalk
@@ -43,19 +47,17 @@ function formatHeader() {
43
47
  pad("∆ external")
44
48
  }after step...\n`
45
49
  )
46
- .concat(
47
- `${`${"-".repeat(MAX_LENGTH_EXPECTED)} `.repeat(NUMBER_OF_COLUMNS)}\n`
48
- );
50
+ .concat(formatDividerLine());
49
51
  }
50
52
 
51
53
  function formatTime(pNumber, pConversionMultiplier = MS_PER_SECOND) {
52
54
  return gTimeFormat(pConversionMultiplier * pNumber)
53
- .padStart(MAX_LENGTH_EXPECTED)
55
+ .padStart(MAX_EXPECTED_LENGTH)
54
56
  .concat(" ");
55
57
  }
56
58
 
57
59
  function formatMemory(pBytes) {
58
- const lReturnValue = gSizeFormat(pBytes / K).padStart(MAX_LENGTH_EXPECTED);
60
+ const lReturnValue = gSizeFormat(pBytes / K).padStart(MAX_EXPECTED_LENGTH);
59
61
 
60
62
  return (pBytes < 0 ? chalk.blue(lReturnValue) : lReturnValue).concat(" ");
61
63
  }
@@ -87,4 +89,5 @@ module.exports = {
87
89
  formatMemory,
88
90
  formatPerfLine,
89
91
  formatHeader,
92
+ formatDividerLine,
90
93
  };
@@ -1,8 +1,7 @@
1
1
  const {
2
- formatTime,
3
2
  formatPerfLine,
4
3
  formatHeader,
5
- formatMemory,
4
+ formatDividerLine,
6
5
  } = require("./format-helpers");
7
6
 
8
7
  function getHeader(pLevel, pMaxLevel) {
@@ -47,11 +46,24 @@ function getProgressLine(pMessage, pState, pLevel, pMaxLevel) {
47
46
  function getEndText(pState, pLevel, pMaxLevel) {
48
47
  if (pLevel <= pMaxLevel) {
49
48
  const lTime = process.uptime();
50
- const { heapUsed } = process.memoryUsage();
51
- pState.previousMessage = `really done (${formatTime(
52
- lTime
53
- ).trim()}, ${formatMemory(heapUsed).trim()})`;
54
- return getProgressLine("", pState, pLevel, pMaxLevel);
49
+ const { user, system } = process.cpuUsage();
50
+ const { heapUsed, heapTotal, external, rss } = process.memoryUsage();
51
+ pState.previousMessage = "really done";
52
+
53
+ return (
54
+ getProgressLine("", pState, pLevel, pMaxLevel) +
55
+ formatDividerLine() +
56
+ formatPerfLine({
57
+ elapsedTime: lTime,
58
+ elapsedUser: user,
59
+ elapsedSystem: system,
60
+ deltaRss: rss,
61
+ deltaHeapUsed: heapUsed,
62
+ deltaHeapTotal: heapTotal,
63
+ deltaExternal: external,
64
+ message: "",
65
+ })
66
+ );
55
67
  }
56
68
  return "";
57
69
  }
@@ -1,20 +1,20 @@
1
1
  /* eslint-disable security/detect-object-injection */
2
- const getCycle = require("./get-cycle");
3
2
 
4
3
  function addCircularityCheckToDependency(
5
- pGraph,
4
+ pIndexedGraph,
6
5
  pFrom,
7
6
  pToDep,
8
- { pDependencyName, pFindNodeByName }
7
+ pDependencyName
9
8
  ) {
10
9
  let lReturnValue = {
11
10
  ...pToDep,
12
11
  circular: false,
13
12
  };
14
- const lCycle = getCycle(pGraph, pFrom, pToDep[pDependencyName], {
15
- pDependencyName,
16
- pFindNodeByName,
17
- });
13
+ const lCycle = pIndexedGraph.getCycle(
14
+ pFrom,
15
+ pToDep[pDependencyName],
16
+ pDependencyName
17
+ );
18
18
 
19
19
  if (lCycle.length > 0) {
20
20
  lReturnValue = {
@@ -32,21 +32,20 @@ function addCircularityCheckToDependency(
32
32
  * whether it's (part of a) circular (relationship) and returns the
33
33
  * dependencies with that added.
34
34
  */
35
- module.exports = (
35
+ module.exports = function detectAndAddCycles(
36
36
  pNodes,
37
- { pSourceAttribute, pDependencyName, pFindNodeByName }
38
- ) =>
39
- pNodes.map((pModule) => ({
37
+ pIndexedNodes,
38
+ { pSourceAttribute, pDependencyName }
39
+ ) {
40
+ return pNodes.map((pModule) => ({
40
41
  ...pModule,
41
42
  dependencies: pModule.dependencies.map((pToDep) =>
42
43
  addCircularityCheckToDependency(
43
- pNodes,
44
+ pIndexedNodes,
44
45
  pModule[pSourceAttribute],
45
46
  pToDep,
46
- {
47
- pDependencyName,
48
- pFindNodeByName,
49
- }
47
+ pDependencyName
50
48
  )
51
49
  ),
52
50
  }));
51
+ };
@@ -2,6 +2,7 @@
2
2
  const path = require("path").posix;
3
3
  const { calculateInstability, metricsAreCalculable } = require("../module-utl");
4
4
  const detectCycles = require("../circular");
5
+ const IndexedModuleGraph = require("../../../graph-utl/indexed-module-graph");
5
6
  const {
6
7
  findFolderByName,
7
8
  getAfferentCouplings,
@@ -82,7 +83,7 @@ function calculateFolderMetrics(pFolder) {
82
83
  };
83
84
  }
84
85
 
85
- function denormalizeInstability(pFolder, _, pAllFolders) {
86
+ function deNormalizeInstability(pFolder, _, pAllFolders) {
86
87
  return {
87
88
  ...pFolder,
88
89
  dependencies: pFolder.dependencies.map((pDependency) => {
@@ -114,15 +115,15 @@ function getSinks(pFolders) {
114
115
  }
115
116
 
116
117
  module.exports = function aggregateToFolders(pModules) {
117
- const lFolders = object2Array(
118
+ let lFolders = object2Array(
118
119
  pModules.filter(metricsAreCalculable).reduce(aggregateToFolder, {})
119
120
  )
120
121
  .map(calculateFolderMetrics)
121
- .map(denormalizeInstability);
122
+ .map(deNormalizeInstability);
123
+ lFolders = lFolders.concat(getSinks(lFolders));
122
124
 
123
- return detectCycles(lFolders.concat(getSinks(lFolders)), {
125
+ return detectCycles(lFolders, new IndexedModuleGraph(lFolders, "name"), {
124
126
  pSourceAttribute: "name",
125
127
  pDependencyName: "name",
126
- pFindNodeByName: findFolderByName,
127
128
  });
128
129
  };
@@ -2,8 +2,7 @@ const validate = require("../../../validate");
2
2
  const aggregateToFolders = require("./aggregate-to-folders");
3
3
 
4
4
  /**
5
- *
6
- * @param {*} pFolder
5
+ * @param {import("../../../..").IFolder} pFolder
7
6
  * @param {import('../../../..').IOptions} pOptions
8
7
  * @returns
9
8
  */
@@ -1,4 +1,4 @@
1
- const { findModuleByName } = require("../module-utl");
1
+ const IndexedModuleGraph = require("../../../graph-utl/indexed-module-graph");
2
2
  const { calculateInstability, metricsAreCalculable } = require("../module-utl");
3
3
 
4
4
  function addInstabilityMetric(pModule) {
@@ -16,11 +16,12 @@ function addInstabilityMetric(pModule) {
16
16
  }
17
17
 
18
18
  function addInstabilityToDependency(pAllModules) {
19
+ const lIndexedModules = new IndexedModuleGraph(pAllModules);
19
20
  return (pDependency) => ({
20
21
  ...pDependency,
21
22
  instability:
22
- (findModuleByName(pAllModules, pDependency.resolved) || {}).instability ||
23
- 0,
23
+ (lIndexedModules.findModuleByName(pDependency.resolved) || {})
24
+ .instability || 0,
24
25
  });
25
26
  }
26
27
 
@@ -1,4 +1,3 @@
1
- const { clearCache } = require("../module-utl");
2
1
  const {
3
2
  addInstabilityMetric,
4
3
  deNormalizeInstabilityMetricsToDependencies,
@@ -6,9 +5,9 @@ const {
6
5
 
7
6
  module.exports = function deriveModulesMetrics(pModules, pOptions) {
8
7
  if (pOptions.metrics) {
9
- const lModules = pModules.map(addInstabilityMetric);
10
- clearCache();
11
- return lModules.map(deNormalizeInstabilityMetricsToDependencies);
8
+ return pModules
9
+ .map(addInstabilityMetric)
10
+ .map(deNormalizeInstabilityMetricsToDependencies);
12
11
  }
13
12
  return pModules;
14
13
  };
@@ -1,29 +1,3 @@
1
- /** @type {Map<string,import('../../../types/cruise-result').IModule>} */
2
- let gIndexedGraph = null;
3
-
4
- /**
5
- * Returns the module with attribute pSource, when it exists in the pModuleGraph.
6
- * Returns undefined when it doesn't.
7
- *
8
- * This function uses an indexed cache for efficiency reasons. If you need to
9
- * call this function consecutively for different module graphs, you can clear
10
- * this cache with the clearCache function from this module.
11
- *
12
- * TODO: use IndexedModuleGraph class from src/graph-utl in stead
13
- *
14
- * @param {import('../../../types/cruise-result').IModule[]} pModuleGraph
15
- * @param {string} pSource
16
- * @returns {import('../../../types/cruise-result').IModule | undefined}
17
- */
18
- function findModuleByName(pModuleGraph, pSource) {
19
- if (!gIndexedGraph) {
20
- gIndexedGraph = new Map(
21
- pModuleGraph.map((pModule) => [pModule.source, pModule])
22
- );
23
- }
24
- return gIndexedGraph.get(pSource);
25
- }
26
-
27
1
  function isDependent(pResolvedName) {
28
2
  return (pModule) =>
29
3
  pModule.dependencies.some(
@@ -41,7 +15,7 @@ function metricsAreCalculable(pModule) {
41
15
 
42
16
  /**
43
17
  * returns the Instability of a component given the number of incoming (afferent)
44
- * and outgoign (efferent) connections ('couplings')
18
+ * and outgoing (efferent) connections ('couplings')
45
19
  *
46
20
  * @param {number} pEfferentCouplingCount
47
21
  * @param {number} pAfferentCouplingCount
@@ -57,13 +31,7 @@ function calculateInstability(pEfferentCouplingCount, pAfferentCouplingCount) {
57
31
  );
58
32
  }
59
33
 
60
- function clearCache() {
61
- gIndexedGraph = null;
62
- }
63
-
64
34
  module.exports = {
65
- findModuleByName,
66
- clearCache,
67
35
  isDependent,
68
36
  metricsAreCalculable,
69
37
  calculateInstability,
@@ -1,10 +1,10 @@
1
1
  /* eslint-disable security/detect-object-injection, no-inline-comments */
2
2
 
3
- const clone = require("lodash/clone");
3
+ const cloneDeep = require("lodash/cloneDeep");
4
4
  const has = require("lodash/has");
5
- const matchers = require("../../../validate/matchers");
6
- const { extractGroups } = require("../../../utl/regex-util");
7
- const getPath = require("./get-path");
5
+ const matchers = require("../../validate/matchers");
6
+ const { extractGroups } = require("../../utl/regex-util");
7
+ const IndexedModuleGraph = require("../../graph-utl/indexed-module-graph");
8
8
 
9
9
  function getReachableRules(pRuleSet) {
10
10
  return (pRuleSet?.forbidden ?? [])
@@ -105,14 +105,14 @@ function shouldAddReachable(pRule, pModuleTo, pGraph) {
105
105
  return lReturnValue;
106
106
  }
107
107
 
108
- function addReachesToModule(pModule, pGraph, pReachableRule) {
108
+ function addReachesToModule(pModule, pGraph, pIndexedGraph, pReachableRule) {
109
109
  const lToModules = pGraph.filter((pToModule) =>
110
110
  isModuleInRuleTo(pReachableRule, pToModule, pModule)
111
111
  );
112
112
 
113
113
  for (let lToModule of lToModules) {
114
114
  if (pModule.source !== lToModule.source) {
115
- const lPath = getPath(pGraph, pModule.source, lToModule.source);
115
+ const lPath = pIndexedGraph.getPath(pModule.source, lToModule.source);
116
116
 
117
117
  if (lPath.length > 0) {
118
118
  pModule.reaches = mergeReachesProperties(
@@ -127,7 +127,7 @@ function addReachesToModule(pModule, pGraph, pReachableRule) {
127
127
  return pModule;
128
128
  }
129
129
 
130
- function addReachableToModule(pModule, pGraph, pReachableRule) {
130
+ function addReachableToModule(pModule, pGraph, pIndexedGraph, pReachableRule) {
131
131
  const lFromModules = pGraph.filter(isModuleInRuleFrom(pReachableRule));
132
132
  let lFound = false;
133
133
 
@@ -137,7 +137,7 @@ function addReachableToModule(pModule, pGraph, pReachableRule) {
137
137
  pModule.source !== lFromModule.source &&
138
138
  isModuleInRuleTo(pReachableRule, pModule, lFromModule)
139
139
  ) {
140
- const lPath = getPath(pGraph, lFromModule.source, pModule.source);
140
+ const lPath = pIndexedGraph.getPath(lFromModule.source, pModule.source);
141
141
 
142
142
  lFound = lPath.length > 0;
143
143
  pModule.reachable = mergeReachableProperties(
@@ -151,17 +151,23 @@ function addReachableToModule(pModule, pGraph, pReachableRule) {
151
151
  return pModule;
152
152
  }
153
153
 
154
- function addReachabilityToGraph(pGraph, pReachableRule) {
154
+ function addReachabilityToGraph(pGraph, pIndexedGraph, pReachableRule) {
155
155
  return pGraph.map((pModule) => {
156
- let lClonedModule = clone(pModule);
156
+ let lClonedModule = cloneDeep(pModule);
157
157
 
158
158
  if (shouldAddReaches(pReachableRule, lClonedModule)) {
159
- lClonedModule = addReachesToModule(lClonedModule, pGraph, pReachableRule);
159
+ lClonedModule = addReachesToModule(
160
+ lClonedModule,
161
+ pGraph,
162
+ pIndexedGraph,
163
+ pReachableRule
164
+ );
160
165
  }
161
166
  if (shouldAddReachable(pReachableRule, lClonedModule, pGraph)) {
162
167
  lClonedModule = addReachableToModule(
163
168
  lClonedModule,
164
169
  pGraph,
170
+ pIndexedGraph,
165
171
  pReachableRule
166
172
  );
167
173
  }
@@ -171,9 +177,12 @@ function addReachabilityToGraph(pGraph, pReachableRule) {
171
177
 
172
178
  module.exports = function deriveReachables(pGraph, pRuleSet) {
173
179
  const lReachableRules = pRuleSet ? getReachableRules(pRuleSet) : [];
180
+ const lIndexedGraph =
181
+ lReachableRules.length > 0 ? new IndexedModuleGraph(pGraph) : {};
174
182
 
175
183
  return lReachableRules.reduce(
176
- (pReturnGraph, pRule) => addReachabilityToGraph(pReturnGraph, pRule),
177
- clone(pGraph)
184
+ (pReturnGraph, pRule) =>
185
+ addReachabilityToGraph(pReturnGraph, lIndexedGraph, pRule),
186
+ cloneDeep(pGraph)
178
187
  );
179
188
  };
@@ -1,6 +1,7 @@
1
1
  const bus = require("../utl/bus");
2
2
  const busLogLevels = require("../utl/bus-log-levels");
3
3
  const addFocus = require("../../src/graph-utl/add-focus");
4
+ const IndexedModuleGraph = require("../graph-utl/indexed-module-graph");
4
5
  const deriveCycles = require("./derive/circular");
5
6
  const deriveOrphans = require("./derive/orphan");
6
7
  const addDependents = require("./derive/dependents");
@@ -8,14 +9,13 @@ const deriveReachable = require("./derive/reachable");
8
9
  const addValidations = require("./add-validations");
9
10
  const softenKnownViolations = require("./soften-known-violations");
10
11
  const deriveModuleMetrics = require("./derive/metrics");
11
- const { findModuleByName } = require("./derive/module-utl");
12
12
 
13
13
  module.exports = function enrichModules(pModules, pOptions) {
14
14
  bus.emit("progress", "analyzing: cycles", { level: busLogLevels.INFO });
15
- let lModules = deriveCycles(pModules, {
15
+ const lIndexedModules = new IndexedModuleGraph(pModules);
16
+ let lModules = deriveCycles(pModules, lIndexedModules, {
16
17
  pSourceAttribute: "source",
17
18
  pDependencyName: "resolved",
18
- pFindNodeByName: findModuleByName,
19
19
  });
20
20
  bus.emit("progress", "analyzing: dependents", { level: busLogLevels.INFO });
21
21
  lModules = addDependents(lModules, pOptions);
@@ -1,7 +1,6 @@
1
1
  const enrichModules = require("./enrich-modules");
2
2
  const aggregateToFolders = require("./derive/folders");
3
3
  const summarize = require("./summarize");
4
- const clearCaches = require("./clear-caches");
5
4
 
6
5
  /**
7
6
  * Enriches the passed modules with things like cycle detection, validations,
@@ -17,11 +16,9 @@ const clearCaches = require("./clear-caches");
17
16
  * @returns {import("../..").ICruiseResult}
18
17
  */
19
18
  module.exports = function enrich(pModules, pOptions, pFileAndDirectoryArray) {
20
- clearCaches();
21
19
  const lModules = enrichModules(pModules, pOptions);
22
20
  const lFolders = aggregateToFolders(lModules, pOptions);
23
21
 
24
- clearCaches();
25
22
  const lReturnValue = {
26
23
  modules: lModules,
27
24
  ...lFolders,
@@ -53,19 +53,19 @@ function gatherScannableFilesFromDirectory(pDirectoryName, pOptions) {
53
53
  shouldNotBeExcluded(pathToPosix(pFullPathToFile), pOptions)
54
54
  )
55
55
  .reduce((pSum, pFullPathToFile) => {
56
- let lStat = {};
57
- try {
58
- lStat = fs.statSync(path.join(pOptions.baseDir, pFullPathToFile));
59
- } catch (pError) {
60
- return pSum;
61
- }
62
- if (lStat.isDirectory()) {
63
- return pSum.concat(
64
- gatherScannableFilesFromDirectory(pFullPathToFile, pOptions)
65
- );
66
- }
67
- if (fileIsScannable(pOptions, pFullPathToFile)) {
68
- return pSum.concat(pFullPathToFile);
56
+ let lStat = fs.statSync(path.join(pOptions.baseDir, pFullPathToFile), {
57
+ throwIfNoEntry: false,
58
+ });
59
+
60
+ if (lStat) {
61
+ if (lStat.isDirectory()) {
62
+ return pSum.concat(
63
+ gatherScannableFilesFromDirectory(pFullPathToFile, pOptions)
64
+ );
65
+ }
66
+ if (fileIsScannable(pOptions, pFullPathToFile)) {
67
+ return pSum.concat(pFullPathToFile);
68
+ }
69
69
  }
70
70
  return pSum;
71
71
  }, [])
@@ -1,18 +1,18 @@
1
+ /* eslint-disable security/detect-object-injection */
1
2
  module.exports = class IndexedModuleGraph {
2
- init(pModules) {
3
+ init(pModules, pIndexAttribute) {
3
4
  this.indexedGraph = new Map(
4
- pModules.map((pModule) => [pModule.source, pModule])
5
+ pModules.map((pModule) => [pModule[pIndexAttribute], pModule])
5
6
  );
6
7
  }
7
8
 
8
- constructor(pModules) {
9
- this.init(pModules);
9
+ constructor(pModules, pIndexAttribute = "source") {
10
+ this.init(pModules, pIndexAttribute);
10
11
  }
11
12
 
12
13
  /**
13
- *
14
14
  * @param {string} pName
15
- * @return {import("../types/cruise-result").IModule}
15
+ * @return {import("..").IModule}
16
16
  */
17
17
  findModuleByName(pName) {
18
18
  return this.indexedGraph.get(pName);
@@ -102,4 +102,78 @@ module.exports = class IndexedModuleGraph {
102
102
  }
103
103
  return lReturnValue;
104
104
  }
105
+
106
+ /**
107
+ * @param {string} pFrom
108
+ * @param {string} pTo
109
+ * @param {Set<string>} pVisited
110
+ * @returns {string[]}
111
+ */
112
+ getPath(pFrom, pTo, pVisited = new Set()) {
113
+ let lReturnValue = [];
114
+ const lFromNode = this.findModuleByName(pFrom);
115
+
116
+ pVisited.add(pFrom);
117
+
118
+ if (lFromNode) {
119
+ const lDirectUnvisitedDependencies = lFromNode.dependencies
120
+ .filter((pDependency) => !pVisited.has(pDependency.resolved))
121
+ .map((pDependency) => pDependency.resolved);
122
+ if (lDirectUnvisitedDependencies.includes(pTo)) {
123
+ lReturnValue = [pFrom, pTo];
124
+ } else {
125
+ for (const lFrom of lDirectUnvisitedDependencies) {
126
+ let lCandidatePath = this.getPath(lFrom, pTo, pVisited);
127
+ // eslint-disable-next-line max-depth
128
+ if (lCandidatePath.length > 0) {
129
+ lReturnValue = [pFrom].concat(lCandidatePath);
130
+ break;
131
+ }
132
+ }
133
+ }
134
+ }
135
+ return lReturnValue;
136
+ }
137
+
138
+ /**
139
+ * Returns the first non-zero length path from pInitialSource to pInitialSource
140
+ * Returns the empty array if there is no such path
141
+ *
142
+ * @param {string} pInitialSource The 'source' attribute of the node to be tested
143
+ * (source uniquely identifying a node)
144
+ * @param {string} pCurrentSource The 'source' attribute of the 'to' node to
145
+ * be traversed
146
+ * @param {string} pDependencyName The attribute name of the dependency to use.
147
+ * defaults to "resolved" (which is in use for
148
+ * modules). For folders pass "name"
149
+ * @return {string[]} see description above
150
+ */
151
+ getCycle(pInitialSource, pCurrentSource, pDependencyName, pVisited) {
152
+ let lVisited = pVisited || new Set();
153
+ const lCurrentNode = this.findModuleByName(pCurrentSource);
154
+ const lDependencies = lCurrentNode.dependencies.filter(
155
+ (pDependency) => !lVisited.has(pDependency[pDependencyName])
156
+ );
157
+ const lMatch = lDependencies.find(
158
+ (pDependency) => pDependency[pDependencyName] === pInitialSource
159
+ );
160
+ if (lMatch) {
161
+ return [pCurrentSource, lMatch[pDependencyName]];
162
+ }
163
+ return lDependencies.reduce((pAll, pDependency) => {
164
+ if (!pAll.includes(pCurrentSource)) {
165
+ const lCycle = this.getCycle(
166
+ pInitialSource,
167
+ pDependency[pDependencyName],
168
+ pDependencyName,
169
+ lVisited.add(pDependency[pDependencyName])
170
+ );
171
+
172
+ if (lCycle.length > 0 && !lCycle.includes(pCurrentSource)) {
173
+ return pAll.concat(pCurrentSource).concat(lCycle);
174
+ }
175
+ }
176
+ return pAll;
177
+ }, []);
178
+ }
105
179
  };
package/src/meta.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /* generated - don't edit */
2
2
 
3
3
  module.exports = {
4
- version: "12.5.1",
4
+ version: "12.6.0",
5
5
  engines: {
6
6
  node: "^14||^16||>=18",
7
7
  },
@@ -13,12 +13,10 @@ const pathToPosix = require("./path-to-posix");
13
13
  * @returns {boolean}
14
14
  */
15
15
  function fileIsDirectory(pFullPathToFile, pBaseDirectory) {
16
- try {
17
- const lStat = statSync(join(pBaseDirectory, pFullPathToFile));
18
- return lStat.isDirectory();
19
- } catch (pError) {
20
- return false;
21
- }
16
+ const lStat = statSync(join(pBaseDirectory, pFullPathToFile), {
17
+ throwIfNoEntry: false,
18
+ });
19
+ return lStat?.isDirectory() ?? false;
22
20
  }
23
21
 
24
22
  /**
@@ -1,5 +0,0 @@
1
- const utl = require("./derive/module-utl");
2
-
3
- module.exports = function clearCaches() {
4
- utl.clearCache();
5
- };
@@ -1,70 +0,0 @@
1
- /* eslint-disable security/detect-object-injection */
2
- /* about the absence of checks whether attributes/ objects actually
3
- * exist:
4
- * - it saves CPU cycles to the effect of being ~30% faster than with the
5
- * checks
6
- * - .dependencies is a mandatory attribute (as per json schema)
7
- * - .resolved is a mandatory attribute (as per json schema)
8
- */
9
-
10
- /**
11
- * Returns the first non-zero length path from pInitialSource to pInitialSource
12
- * Returns the empty array if there is no such path
13
- *
14
- * @param {any} pGraph The graph in which to test this condition
15
- * @param {string} pInitialSource The 'source' attribute of the node to be tested
16
- * (source uniquely identifying a node)
17
- * @param {string} pCurrentSource The 'source' attribute of the 'to' node to
18
- * be traversed
19
- * @param {string} pDependencyName The attribute name of the dependency to use.
20
- * defaults to "resolved" (which is in use for
21
- * modules). For folders pass "name"
22
- * @param {function} pFindNodeByName Function taking a Graph and a pCurrentSource string
23
- * that returns the Node in that graph going by
24
- * that name. Defaults to findModuleByName (which
25
- * is in use for modules). For folders pass
26
- * findFolderByName
27
- * @param {Set} pVisited The set of nodes visited hithereto (optional
28
- * attribute - there's no need to pass it when
29
- * calling it; it's used by the algorithm to
30
- * determine the stop condition)
31
- * @return {string[]} see description above
32
- */
33
- // eslint-disable-next-line max-params
34
- function getCycle(
35
- pGraph,
36
- pInitialSource,
37
- pCurrentSource,
38
- { pDependencyName, pFindNodeByName },
39
- pVisited
40
- ) {
41
- let lVisited = pVisited || new Set();
42
- const lCurrentNode = pFindNodeByName(pGraph, pCurrentSource);
43
- const lDependencies = lCurrentNode.dependencies.filter(
44
- (pDependency) => !lVisited.has(pDependency[pDependencyName])
45
- );
46
- const lMatch = lDependencies.find(
47
- (pDependency) => pDependency[pDependencyName] === pInitialSource
48
- );
49
- if (lMatch) {
50
- return [pCurrentSource, lMatch[pDependencyName]];
51
- }
52
- return lDependencies.reduce((pAll, pDependency) => {
53
- if (!pAll.includes(pCurrentSource)) {
54
- const lCycle = getCycle(
55
- pGraph,
56
- pInitialSource,
57
- pDependency[pDependencyName],
58
- { pDependencyName, pFindNodeByName },
59
- lVisited.add(pDependency[pDependencyName])
60
- );
61
-
62
- if (lCycle.length > 0 && !lCycle.includes(pCurrentSource)) {
63
- return pAll.concat(pCurrentSource).concat(lCycle);
64
- }
65
- }
66
- return pAll;
67
- }, []);
68
- }
69
-
70
- module.exports = getCycle;
@@ -1,29 +0,0 @@
1
- const { findModuleByName } = require("../module-utl");
2
-
3
- function getPath(pGraph, pFrom, pTo, pVisited = new Set()) {
4
- let lReturnValue = [];
5
- const lFromNode = findModuleByName(pGraph, pFrom);
6
-
7
- pVisited.add(pFrom);
8
-
9
- if (lFromNode) {
10
- const lDirectUnvisitedDependencies = lFromNode.dependencies
11
- .filter((pDependency) => !pVisited.has(pDependency.resolved))
12
- .map((pDependency) => pDependency.resolved);
13
- if (lDirectUnvisitedDependencies.includes(pTo)) {
14
- lReturnValue = [pFrom, pTo];
15
- } else {
16
- for (const lFrom of lDirectUnvisitedDependencies) {
17
- let lCandidatePath = getPath(pGraph, lFrom, pTo, pVisited);
18
- // eslint-disable-next-line max-depth
19
- if (lCandidatePath.length > 0) {
20
- lReturnValue = [pFrom].concat(lCandidatePath);
21
- break;
22
- }
23
- }
24
- }
25
- }
26
- return lReturnValue;
27
- }
28
-
29
- module.exports = getPath;