dependency-cruiser 17.3.5 → 17.3.7

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.
Files changed (46) hide show
  1. package/LICENSE +1 -1
  2. package/package.json +6 -4
  3. package/src/{enrich/enrich-modules.mjs → analyze/analyze-modules.mjs} +1 -1
  4. package/src/{enrich → analyze}/derive/dependents.mjs +14 -3
  5. package/src/{enrich → analyze}/index.mjs +3 -3
  6. package/src/cache/cache.mjs +9 -27
  7. package/src/cache/content-strategy.mjs +1 -1
  8. package/src/cache/helpers.mjs +16 -6
  9. package/src/cli/init-config/config-template.mjs +112 -145
  10. package/src/cli/init-config/find-extensions.mjs +4 -0
  11. package/src/cli/listeners/ndjson.mjs +16 -1
  12. package/src/config-utl/extract-depcruise-config/merge-configs.mjs +2 -2
  13. package/src/extract/acorn/parse.mjs +18 -25
  14. package/src/extract/resolve/external-module-helpers.mjs +9 -7
  15. package/src/extract/resolve/get-manifest.mjs +25 -13
  16. package/src/extract/resolve/resolve-amd.mjs +10 -5
  17. package/src/extract/resolve/resolve.mjs +4 -5
  18. package/src/extract/swc/parse.mjs +12 -8
  19. package/src/extract/tsc/parse.mjs +12 -15
  20. package/src/main/cruise.mjs +6 -6
  21. package/src/main/report-wrap.mjs +1 -1
  22. package/src/meta.cjs +1 -1
  23. package/src/report/anon/anonymize-path-element.mjs +11 -3
  24. package/src/report/dot/prepare-flat-level.mjs +12 -2
  25. package/src/report/plugins.mjs +1 -1
  26. package/src/report/teamcity.mjs +76 -58
  27. package/src/report/text.mjs +7 -7
  28. /package/src/{enrich → analyze}/add-validations.mjs +0 -0
  29. /package/src/{enrich → analyze}/derive/circular.mjs +0 -0
  30. /package/src/{enrich → analyze}/derive/folders/aggregate-to-folders.mjs +0 -0
  31. /package/src/{enrich → analyze}/derive/folders/index.mjs +0 -0
  32. /package/src/{enrich → analyze}/derive/folders/utl.mjs +0 -0
  33. /package/src/{enrich → analyze}/derive/metrics/get-module-metrics.mjs +0 -0
  34. /package/src/{enrich → analyze}/derive/metrics/index.mjs +0 -0
  35. /package/src/{enrich → analyze}/derive/module-utl.mjs +0 -0
  36. /package/src/{enrich → analyze}/derive/orphan/index.mjs +0 -0
  37. /package/src/{enrich → analyze}/derive/orphan/is-orphan.mjs +0 -0
  38. /package/src/{enrich → analyze}/derive/reachable.mjs +0 -0
  39. /package/src/{enrich → analyze}/soften-known-violations.mjs +0 -0
  40. /package/src/{enrich → analyze}/summarize/add-rule-set-used.mjs +0 -0
  41. /package/src/{enrich → analyze}/summarize/get-stats.mjs +0 -0
  42. /package/src/{enrich → analyze}/summarize/index.mjs +0 -0
  43. /package/src/{enrich → analyze}/summarize/is-same-violation.mjs +0 -0
  44. /package/src/{enrich → analyze}/summarize/summarize-folders.mjs +0 -0
  45. /package/src/{enrich → analyze}/summarize/summarize-modules.mjs +0 -0
  46. /package/src/{enrich → analyze}/summarize/summarize-options.mjs +0 -0
@@ -105,7 +105,7 @@ function mergeAllowedSeverities(pConfigExtended, pConfigBase) {
105
105
  * @returns {Object} - The merged rule set
106
106
  */
107
107
  // eslint-disable-next-line complexity
108
- export default (pConfigExtended, pConfigBase) => {
108
+ export default function mergeConfigs(pConfigExtended, pConfigBase) {
109
109
  const lForbidden = mergeRules(
110
110
  pConfigExtended?.forbidden ?? [],
111
111
  pConfigBase?.forbidden ?? [],
@@ -133,4 +133,4 @@ export default (pConfigExtended, pConfigBase) => {
133
133
  pConfigBase?.options ?? {},
134
134
  ),
135
135
  };
136
- };
136
+ }
@@ -2,7 +2,6 @@ import { readFileSync } from "node:fs";
2
2
  import { Parser as acornParser, parse as acornParse } from "acorn";
3
3
  import { parse as acornLooseParse } from "acorn-loose";
4
4
  import acornJsx from "acorn-jsx";
5
- import memoize, { memoizeClear } from "memoize";
6
5
  import transpile from "../transpile/index.mjs";
7
6
  import getExtension from "#utl/get-extension.mjs";
8
7
 
@@ -11,10 +10,12 @@ const ACORN_OPTIONS = {
11
10
  sourceType: "module",
12
11
  ecmaVersion: 11,
13
12
  };
14
-
15
13
  const TSCONFIG_CONSTANTS = {
16
14
  PRESERVE_JSX: 1,
17
15
  };
16
+ /**@type {Map<string, acorn.Node>} */
17
+ const CACHE = new Map();
18
+
18
19
  const acornJsxParser = acornParser.extend(acornJsx());
19
20
 
20
21
  function needsJSXTreatment(pFileRecord, pTranspileOptions) {
@@ -57,13 +58,19 @@ export function getASTFromSource(pFileRecord, pTranspileOptions) {
57
58
  *
58
59
  * If parsing fails we fall back to acorn's 'loose' parser
59
60
  *
60
- * @param {string} pFileName path to the file to be parsed
61
- * @param {any} pTranspileOptions options for the transpiler(s) - a tsconfig or
62
- * a babel config
63
- * @returns {acorn.Node} the abstract syntax tree
61
+ * Subsequent calls for the same file name will return the result from a cache.
62
+ *
63
+ * @param {string} pFileName - the name of the file to compile
64
+ * @param {any} pTranspileOptions - options for the transpiler(s) - typically a tsconfig or a babel config
65
+ * @return {acorn.Node} - a (javascript) AST
64
66
  */
65
- function getAST(pFileName, pTranspileOptions) {
66
- return getASTFromSource(
67
+ export function getASTCached(pFileName, pTranspileOptions) {
68
+ // taking the transpile options into account of the cache key seems like
69
+ // a good idea, but a.t.m. isn't necessary. Easy to add later if needed.
70
+ if (CACHE.has(pFileName)) {
71
+ return CACHE.get(pFileName);
72
+ }
73
+ const lAST = getASTFromSource(
67
74
  {
68
75
  source: readFileSync(pFileName, "utf8"),
69
76
  extension: getExtension(pFileName),
@@ -71,24 +78,10 @@ function getAST(pFileName, pTranspileOptions) {
71
78
  },
72
79
  pTranspileOptions,
73
80
  );
81
+ CACHE.set(pFileName, lAST);
82
+ return lAST;
74
83
  }
75
84
 
76
- /**
77
- * Compiles the file identified by pFileName into a (javascript)
78
- * AST and returns it. Subsequent calls for the same file name will
79
- * return the result from a cache.
80
- *
81
- * @param {string} pFileName - the name of the file to compile
82
- * @param {any} pTranspileOptions - options for the transpiler(s) - typically a tsconfig or a babel config
83
- * @return {acorn.Node} - a (javascript) AST
84
- */
85
- // taking the transpile options into account of the memoize cache key seems like
86
- // a good idea. However, previously we use `${pTranspileOptions}` which always
87
- // serializes to [object Object], which doesn't help. So for now we're not
88
- // taking the transpile options into account. If we ever need to, it'll be
89
- // a JSON.stringify away (which _will_ be significantly slower)
90
- export const getASTCached = memoize(getAST);
91
-
92
85
  export function clearCache() {
93
- memoizeClear(getASTCached);
86
+ CACHE.clear();
94
87
  }
@@ -1,9 +1,10 @@
1
1
  import { readFileSync } from "node:fs";
2
2
  import { join } from "node:path";
3
- import memoize, { memoizeClear } from "memoize";
4
3
  import { resolve } from "./resolve.mjs";
5
4
  import { isScoped, isRelativeModuleName } from "./module-classifiers.mjs";
6
5
 
6
+ const PACKAGE_JSON_CACHE = new Map();
7
+
7
8
  /**
8
9
  * Returns the 'root' of the package - the spot where we can probably find
9
10
  * the package.json of that package, and the reference we'd usualy have
@@ -72,7 +73,11 @@ export function getPackageRoot(pModule) {
72
73
  * null if either module or package.json could
73
74
  * not be found
74
75
  */
75
- function bareGetPackageJson(pModuleName, pFileDirectory, pResolveOptions) {
76
+ export function getPackageJson(pModuleName, pFileDirectory, pResolveOptions) {
77
+ const lCacheKey = `${pModuleName}|${pFileDirectory}`;
78
+ if (PACKAGE_JSON_CACHE.has(lCacheKey)) {
79
+ return PACKAGE_JSON_CACHE.get(lCacheKey);
80
+ }
76
81
  let lReturnValue = null;
77
82
 
78
83
  try {
@@ -102,13 +107,10 @@ function bareGetPackageJson(pModuleName, pFileDirectory, pResolveOptions) {
102
107
  } catch (pError) {
103
108
  // left empty on purpose
104
109
  }
110
+ PACKAGE_JSON_CACHE.set(lCacheKey, lReturnValue);
105
111
  return lReturnValue;
106
112
  }
107
113
 
108
- export const getPackageJson = memoize(bareGetPackageJson, {
109
- cacheKey: (pArguments) => `${pArguments[0]}|${pArguments[1]}`,
110
- });
111
-
112
114
  /**
113
115
  * Tells whether the pModule as resolved to pBaseDirectory is deprecated
114
116
  *
@@ -164,5 +166,5 @@ export function getLicense(pModuleName, pFileDirectory, pResolveOptions) {
164
166
  }
165
167
 
166
168
  export function clearCache() {
167
- memoizeClear(getPackageJson);
169
+ PACKAGE_JSON_CACHE.clear();
168
170
  }
@@ -1,8 +1,10 @@
1
1
  import { join, dirname, sep } from "node:path";
2
2
  import { readFileSync } from "node:fs";
3
- import memoize, { memoizeClear } from "memoize";
4
3
  import mergePackages from "./merge-manifests.mjs";
5
4
 
5
+ const SINGLE_MANIFEST_CACHE = new Map();
6
+ const COMBINED_MANIFEST_CACHE = new Map();
7
+
6
8
  /**
7
9
  * return the contents of the package manifest ('package.json' closest to
8
10
  * the passed folder (or null if there's no such package.json/ that
@@ -16,7 +18,11 @@ import mergePackages from "./merge-manifests.mjs";
16
18
  * object or null if the package.json could not be
17
19
  * found or is invalid
18
20
  */
19
- const getSingleManifest = memoize((pFileDirectory) => {
21
+ function getSingleManifest(pFileDirectory) {
22
+ if (SINGLE_MANIFEST_CACHE.has(pFileDirectory)) {
23
+ return SINGLE_MANIFEST_CACHE.get(pFileDirectory);
24
+ }
25
+
20
26
  let lReturnValue = null;
21
27
 
22
28
  try {
@@ -39,8 +45,9 @@ const getSingleManifest = memoize((pFileDirectory) => {
39
45
  lReturnValue = getSingleManifest(lNextDirectory);
40
46
  }
41
47
  }
48
+ SINGLE_MANIFEST_CACHE.set(pFileDirectory, lReturnValue);
42
49
  return lReturnValue;
43
- });
50
+ }
44
51
 
45
52
  function maybeReadPackage(pFileDirectory) {
46
53
  let lReturnValue = {};
@@ -80,11 +87,7 @@ function getIntermediatePaths(pFileDirectory, pBaseDirectory) {
80
87
  return lReturnValue;
81
88
  }
82
89
 
83
- // despite the two parameters there's no resolver function provided
84
- // to memoize. This is deliberate - the pBaseDirectory will typically
85
- // be the same for each call in a typical cruise, so the default
86
- // memoize resolver (the first param) will suffice.
87
- const getCombinedManifests = memoize((pFileDirectory, pBaseDirectory) => {
90
+ function getCombinedManifests(pFileDirectory, pBaseDirectory) {
88
91
  // The way this is called, this shouldn't happen. If it is, there's
89
92
  // something gone terribly awry
90
93
  if (
@@ -97,8 +100,14 @@ const getCombinedManifests = memoize((pFileDirectory, pBaseDirectory) => {
97
100
  `&title=Unexpected Error: Unusual baseDir passed to package reading function: '${pBaseDirectory}'`,
98
101
  );
99
102
  }
103
+ // despite the two parameters this function has, we only use the pFileDirectory
104
+ // parameter as cache key. This is deliberate as the pBaseDirectory will
105
+ // be the same for each call in a typical cruise.
106
+ if (COMBINED_MANIFEST_CACHE.has(pFileDirectory)) {
107
+ return COMBINED_MANIFEST_CACHE.get(pFileDirectory);
108
+ }
100
109
 
101
- const lReturnValue = getIntermediatePaths(
110
+ const lMergedPackages = getIntermediatePaths(
102
111
  pFileDirectory,
103
112
  pBaseDirectory,
104
113
  ).reduce(
@@ -106,8 +115,11 @@ const getCombinedManifests = memoize((pFileDirectory, pBaseDirectory) => {
106
115
  {},
107
116
  );
108
117
 
109
- return Object.keys(lReturnValue).length > 0 ? lReturnValue : null;
110
- });
118
+ const lReturnValue =
119
+ Object.keys(lMergedPackages).length > 0 ? lMergedPackages : null;
120
+ COMBINED_MANIFEST_CACHE.set(pFileDirectory, lReturnValue);
121
+ return lReturnValue;
122
+ }
111
123
 
112
124
  /**
113
125
  * return
@@ -138,6 +150,6 @@ export function getManifest(
138
150
  }
139
151
 
140
152
  export function clearCache() {
141
- memoizeClear(getCombinedManifests);
142
- memoizeClear(getSingleManifest);
153
+ SINGLE_MANIFEST_CACHE.clear();
154
+ COMBINED_MANIFEST_CACHE.clear();
143
155
  }
@@ -1,18 +1,23 @@
1
1
  import { accessSync, constants } from "node:fs";
2
2
  import { relative, join } from "node:path";
3
- import memoize, { memoizeClear } from "memoize";
4
3
  import { isBuiltin } from "./is-built-in.mjs";
5
4
  import pathToPosix from "#utl/path-to-posix.mjs";
6
5
 
7
- const fileExists = memoize((pFile) => {
6
+ const FILE_EXISTENCE_CACHE = new Map();
7
+ const fileExists = (pFile) => {
8
+ if (FILE_EXISTENCE_CACHE.has(pFile)) {
9
+ return FILE_EXISTENCE_CACHE.get(pFile);
10
+ }
11
+
8
12
  try {
9
13
  accessSync(pFile, constants.R_OK);
10
14
  } catch (pError) {
15
+ FILE_EXISTENCE_CACHE.set(pFile, false);
11
16
  return false;
12
17
  }
13
-
18
+ FILE_EXISTENCE_CACHE.set(pFile, true);
14
19
  return true;
15
- });
20
+ };
16
21
 
17
22
  function guessPath(pBaseDirectory, pFileDirectory, pStrippedModuleName) {
18
23
  return pathToPosix(
@@ -63,5 +68,5 @@ export function resolveAMD(
63
68
  }
64
69
 
65
70
  export function clearCache() {
66
- memoizeClear(fileExists);
71
+ FILE_EXISTENCE_CACHE.clear();
67
72
  }
@@ -6,8 +6,8 @@ import pathToPosix from "#utl/path-to-posix.mjs";
6
6
 
7
7
  /** @type {Map<string, enhancedResolve.Resolver>} */
8
8
  let gResolvers = new Map();
9
- /** @type {Map<string, boolean>} */
10
- let gInitialized = new Map();
9
+ /** @type {Set<string>} */
10
+ let gInitialized = new Set();
11
11
 
12
12
  /**
13
13
  * Initializes a resolver for the given caching context if not already done
@@ -18,15 +18,14 @@ let gInitialized = new Map();
18
18
  * @returns {void}
19
19
  */
20
20
  function init(pEHResolveOptions, pCachingContext) {
21
- if (!gInitialized.get(pCachingContext) || pEHResolveOptions.bustTheCache) {
21
+ if (!gInitialized.has(pCachingContext) || pEHResolveOptions.bustTheCache) {
22
22
  // assuming the cached file system here
23
23
  pEHResolveOptions.fileSystem.purge();
24
24
  gResolvers.set(
25
25
  pCachingContext,
26
26
  enhancedResolve.ResolverFactory.createResolver(pEHResolveOptions),
27
27
  );
28
- /* eslint security/detect-object-injection:0 */
29
- gInitialized.set(pCachingContext, true);
28
+ gInitialized.add(pCachingContext);
30
29
  }
31
30
  }
32
31
 
@@ -1,4 +1,3 @@
1
- import memoize, { memoizeClear } from "memoize";
2
1
  import tryImport from "#utl/try-import.mjs";
3
2
  import meta from "#meta.cjs";
4
3
 
@@ -20,16 +19,13 @@ const SWC_PARSE_OPTIONS = {
20
19
  decorators: true,
21
20
  // TODO: {tj}sx ?
22
21
  };
22
+ /** @type {Map<string, ModuleItem[]>} */
23
+ const CACHE = new Map();
23
24
 
24
25
  export function getASTFromSource(pSource) {
25
26
  return swc.parseSync(pSource, SWC_PARSE_OPTIONS);
26
27
  }
27
28
 
28
- function getAST(pFileName) {
29
- /** @type {swcCore swc} */
30
- return swc.parseFileSync(pFileName, SWC_PARSE_OPTIONS);
31
- }
32
-
33
29
  /**
34
30
  * Compiles the file identified by pFileName into an (swc)
35
31
  * AST and returns it. Subsequent calls for the same file name will
@@ -38,10 +34,18 @@ function getAST(pFileName) {
38
34
  * @param {string} pFileName - the name of the file to compile
39
35
  * @return {ModuleItem[]} - an (swc) AST
40
36
  */
41
- export const getASTCached = memoize(getAST);
37
+ export function getASTCached(pFileName) {
38
+ if (CACHE.has(pFileName)) {
39
+ return CACHE.get(pFileName);
40
+ }
41
+ /** @type {swcCore} */
42
+ const lAST = swc.parseFileSync(pFileName, SWC_PARSE_OPTIONS);
43
+ CACHE.set(pFileName, lAST);
44
+ return lAST;
45
+ }
42
46
 
43
47
  export function clearCache() {
44
- memoizeClear(getASTCached);
48
+ CACHE.clear();
45
49
  }
46
50
 
47
51
  /**
@@ -1,5 +1,4 @@
1
1
  import { readFileSync } from "node:fs";
2
- import memoize, { memoizeClear } from "memoize";
3
2
  import transpile from "../transpile/index.mjs";
4
3
  import tryImport from "#utl/try-import.mjs";
5
4
  import meta from "#meta.cjs";
@@ -10,6 +9,8 @@ const typescript = await tryImport(
10
9
  "typescript",
11
10
  meta.supportedTranspilers.typescript,
12
11
  );
12
+ /** @type {Map<string, any>} */
13
+ const CACHE = new Map();
13
14
 
14
15
  /**
15
16
  * Compiles pTypescriptSource into a (typescript) AST
@@ -35,15 +36,19 @@ export function getASTFromSource(pFileRecord, pTranspileOptions) {
35
36
 
36
37
  /**
37
38
  * Compiles the file identified by pFileName into a (typescript)
38
- * AST and returns it
39
+ * AST and returns it. Subsequent calls for the same file name will
40
+ * return the result from a cache
39
41
  *
40
42
  * @param {string} pFileName - the name of the file to compile
41
43
  * @param {any} [pTranspileOptions] options for the transpiler(s) - a tsconfig or
42
44
  * a babel config
43
45
  * @return {object} - a (typescript) AST
44
46
  */
45
- function getAST(pFileName, pTranspileOptions) {
46
- return getASTFromSource(
47
+ export function getASTCached(pFileName, pTranspileOptions) {
48
+ if (CACHE.has(pFileName)) {
49
+ return CACHE.get(pFileName);
50
+ }
51
+ const lAST = getASTFromSource(
47
52
  {
48
53
  source: readFileSync(pFileName, "utf8"),
49
54
  extension: getExtension(pFileName),
@@ -51,18 +56,10 @@ function getAST(pFileName, pTranspileOptions) {
51
56
  },
52
57
  pTranspileOptions,
53
58
  );
59
+ CACHE.set(pFileName, lAST);
60
+ return lAST;
54
61
  }
55
62
 
56
- /**
57
- * Compiles the file identified by pFileName into a (typescript)
58
- * AST and returns it. Subsequent calls for the same file name will
59
- * return the result from a cache
60
- *
61
- * @param {string} pFileName - the name of the file to compile
62
- * @return {object} - a (typescript) AST
63
- */
64
- export const getASTCached = memoize(getAST);
65
-
66
63
  /**
67
64
  * @return {boolean} - true if the typescript compiler is available,
68
65
  * false in all other cases
@@ -70,5 +67,5 @@ export const getASTCached = memoize(getAST);
70
67
  export const isAvailable = () => typescript !== false;
71
68
 
72
69
  export function clearCache() {
73
- memoizeClear(getASTCached);
70
+ CACHE.clear();
74
71
  }
@@ -11,7 +11,7 @@ export function c(pComplete, pTotal = TOTAL_STEPS) {
11
11
  return { complete: pComplete / pTotal };
12
12
  }
13
13
 
14
- /** @type {import("../../types/dependency-cruiser.js").cruise} */
14
+ /** @type {import("../../types/dependency-cruiser.mjs").cruise} */
15
15
  // eslint-disable-next-line max-lines-per-function, max-statements
16
16
  export default async function cruise(
17
17
  pFileAndDirectoryArray,
@@ -21,7 +21,7 @@ export default async function cruise(
21
21
  ) {
22
22
  bus.summary("startup: parse options", c(1));
23
23
  const lCruiseOptionsValid = assertCruiseOptionsValid(pCruiseOptions);
24
- /** @type {import("../../types/strict-options.js").IStrictCruiseOptions} */
24
+ /** @type {import("../../types/strict-options.mjs").IStrictCruiseOptions} */
25
25
  let lCruiseOptions = normalizeCruiseOptions(
26
26
  lCruiseOptionsValid,
27
27
  pFileAndDirectoryArray,
@@ -42,7 +42,7 @@ export default async function cruise(
42
42
  const lCachedResults = await lCache.read(lCruiseOptions.cache.folder);
43
43
 
44
44
  if (await lCache.canServeFromCache(lCruiseOptions, lCachedResults)) {
45
- bus.summary("cache: report from cache", c(8));
45
+ bus.summary("report: from cache", c(8));
46
46
  return await reportWrap(lCachedResults, lCruiseOptions);
47
47
  }
48
48
  }
@@ -54,7 +54,7 @@ export default async function cruise(
54
54
  { default: normalizeFilesAndDirectories },
55
55
  { default: normalizeResolveOptions },
56
56
  { default: extract },
57
- { default: enrich },
57
+ { default: analyze },
58
58
  ] = await Promise.all([
59
59
  // despite rule set parsing being behind an if, it's the 'normal' use case
60
60
  // for dependency-cruiser, so import it unconditionally nonetheless
@@ -63,7 +63,7 @@ export default async function cruise(
63
63
  import("./files-and-dirs/normalize.mjs"),
64
64
  import("./resolve-options/normalize.mjs"),
65
65
  import("#extract/index.mjs"),
66
- import("#enrich/index.mjs"),
66
+ import("#analyze/index.mjs"),
67
67
  ]);
68
68
 
69
69
  if (lCruiseOptions.ruleSet) {
@@ -93,7 +93,7 @@ export default async function cruise(
93
93
  );
94
94
 
95
95
  bus.summary("analyze", c(7));
96
- const lCruiseResult = enrich(
96
+ const lCruiseResult = analyze(
97
97
  lExtractionResult,
98
98
  lCruiseOptions,
99
99
  lNormalizedFileAndDirectoryArray,
@@ -1,5 +1,5 @@
1
1
  import { getReporter } from "#report/index.mjs";
2
- import summarize from "#enrich/summarize/index.mjs";
2
+ import summarize from "#analyze/summarize/index.mjs";
3
3
  import { applyFilters } from "#graph-utl/filter-bank.mjs";
4
4
  import consolidateToPattern from "#graph-utl/consolidate-to-pattern.mjs";
5
5
  import { compareModules } from "#graph-utl/compare.mjs";
package/src/meta.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  /* generated - don't edit */
2
2
  module.exports = {
3
- version: "17.3.5",
3
+ version: "17.3.7",
4
4
  engines: {
5
5
  node: "^20.12||^22||>=24",
6
6
  },
@@ -1,11 +1,19 @@
1
- import memoize, { memoizeClear } from "memoize";
2
1
  import randomString from "./random-string.mjs";
3
2
 
3
+ const ALREADY_USED_WORDS = new Map();
4
+
4
5
  function replace(pElement, pIndex, pWordList) {
5
6
  return pIndex === 0 ? pWordList.shift() || randomString(pElement) : pElement;
6
7
  }
7
8
 
8
- const replaceCached = memoize(replace);
9
+ function replaceCached(pElement, pIndex, pWordList) {
10
+ if (ALREADY_USED_WORDS.has(pElement)) {
11
+ return ALREADY_USED_WORDS.get(pElement);
12
+ }
13
+ const lReplaced = replace(pElement, pIndex, pWordList);
14
+ ALREADY_USED_WORDS.set(pElement, lReplaced);
15
+ return lReplaced;
16
+ }
9
17
 
10
18
  function replaceFromWordList(pPathElement, pWordList, pCached) {
11
19
  return pPathElement
@@ -49,5 +57,5 @@ export function anonymizePathElement(
49
57
  * @returns {void}
50
58
  */
51
59
  export function clearCache() {
52
- memoizeClear(replaceCached);
60
+ ALREADY_USED_WORDS.clear();
53
61
  }
@@ -1,9 +1,19 @@
1
1
  import { flatLabel, extractFirstTransgression, addURL } from "./module-utl.mjs";
2
2
  import { applyTheme } from "./theming.mjs";
3
3
  import { compareModules } from "#graph-utl/compare.mjs";
4
+ import consolidateToPattern from "#graph-utl/consolidate-to-pattern.mjs";
4
5
 
5
- export default function prepareFlatLevel(pResults, pTheme, _, pShowMetrics) {
6
- return pResults.modules
6
+ export default function prepareFlatLevel(
7
+ pResults,
8
+ pTheme,
9
+ pCollapsePattern,
10
+ pShowMetrics,
11
+ ) {
12
+ return (
13
+ pCollapsePattern
14
+ ? consolidateToPattern(pResults.modules, pCollapsePattern)
15
+ : pResults.modules
16
+ )
7
17
  .sort(compareModules)
8
18
  .map(flatLabel(pShowMetrics))
9
19
  .map(extractFirstTransgression)
@@ -1,6 +1,6 @@
1
1
  export function isValidPlugin(pPluginFunction) {
2
2
  let lReturnValue = false;
3
- /** @type {import('../../types/dependency-cruiser').ICruiseResult} */
3
+ /** @type {import('../../types/dependency-cruiser.mjs').ICruiseResult} */
4
4
  const lMinimalCruiseResult = {
5
5
  modules: [],
6
6
  summary: {