dependency-cruiser 16.2.4 → 16.3.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.
Files changed (40) hide show
  1. package/package.json +3 -3
  2. package/src/cache/options-compatible.mjs +1 -0
  3. package/src/enrich/derive/folders/aggregate-to-folders.mjs +28 -10
  4. package/src/extract/{ast-extractors → acorn}/estree-helpers.mjs +3 -3
  5. package/src/extract/acorn/extract-stats.mjs +6 -0
  6. package/src/extract/acorn/extract.mjs +32 -0
  7. package/src/extract/clear-caches.mjs +6 -6
  8. package/src/extract/{get-dependencies.mjs → extract-dependencies.mjs} +37 -109
  9. package/src/extract/extract-stats.mjs +48 -0
  10. package/src/extract/helpers.mjs +20 -1
  11. package/src/extract/index.mjs +13 -3
  12. package/src/extract/resolve/merge-manifests.mjs +6 -8
  13. package/src/extract/{ast-extractors → swc}/extract-swc-deps.mjs +1 -1
  14. package/src/extract/swc/extract.mjs +20 -0
  15. package/src/extract/transpile/index.mjs +3 -3
  16. package/src/extract/tsc/extract-stats.mjs +6 -0
  17. package/src/extract/tsc/extract.mjs +29 -0
  18. package/src/graph-utl/consolidate-module-dependencies.mjs +3 -6
  19. package/src/graph-utl/rule-set.mjs +3 -2
  20. package/src/main/options/normalize.mjs +1 -4
  21. package/src/main/report-wrap.mjs +7 -2
  22. package/src/meta.cjs +1 -1
  23. package/src/report/dot/default-theme.mjs +4 -0
  24. package/src/report/dot-webpage/dot-module.mjs +2 -3
  25. package/src/report/metrics.mjs +226 -72
  26. package/src/report/utl/index.mjs +3 -0
  27. package/src/schema/configuration.schema.mjs +1 -1
  28. package/src/schema/cruise-result.schema.mjs +1 -1
  29. package/src/utl/array-util.mjs +4 -0
  30. package/types/cruise-result.d.mts +11 -0
  31. package/types/options.d.mts +10 -1
  32. package/types/shared-types.d.mts +15 -0
  33. /package/src/extract/{ast-extractors → acorn}/extract-amd-deps.mjs +0 -0
  34. /package/src/extract/{ast-extractors → acorn}/extract-cjs-deps.mjs +0 -0
  35. /package/src/extract/{ast-extractors → acorn}/extract-es6-deps.mjs +0 -0
  36. /package/src/extract/{parse/to-javascript-ast.mjs → acorn/parse.mjs} +0 -0
  37. /package/src/extract/{ast-extractors/swc-dependency-visitor.mjs → swc/dependency-visitor.mjs} +0 -0
  38. /package/src/extract/{parse/to-swc-ast.mjs → swc/parse.mjs} +0 -0
  39. /package/src/extract/{ast-extractors → tsc}/extract-typescript-deps.mjs +0 -0
  40. /package/src/extract/{parse/to-typescript-ast.mjs → tsc/parse.mjs} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dependency-cruiser",
3
- "version": "16.2.4",
3
+ "version": "16.3.1",
4
4
  "description": "Validate and visualize dependencies. With your rules. JavaScript, TypeScript, CoffeeScript. ES6, CommonJS, AMD.",
5
5
  "keywords": [
6
6
  "static analysis",
@@ -148,7 +148,7 @@
148
148
  "json5": "2.2.3",
149
149
  "lodash": "4.17.21",
150
150
  "memoize": "10.0.0",
151
- "picomatch": "4.0.1",
151
+ "picomatch": "4.0.2",
152
152
  "prompts": "2.4.2",
153
153
  "rechoir": "^0.8.0",
154
154
  "safe-regex": "2.1.1",
@@ -156,7 +156,7 @@
156
156
  "semver-try-require": "6.2.3",
157
157
  "teamcity-service-messages": "0.1.14",
158
158
  "tsconfig-paths-webpack-plugin": "4.1.0",
159
- "watskeburt": "4.0.1",
159
+ "watskeburt": "4.0.2",
160
160
  "wrap-ansi": "9.0.0"
161
161
  },
162
162
  "overrides": {
@@ -104,6 +104,7 @@ export function optionsAreCompatible(pOldOptions, pNewOptions) {
104
104
  pOldOptions.tsPreCompilationDeps === pNewOptions.tsPreCompilationDeps &&
105
105
  pOldOptions.preserveSymlinks === pNewOptions.preserveSymlinks &&
106
106
  pOldOptions.combinedDependencies === pNewOptions.combinedDependencies &&
107
+ pOldOptions.experimentalStats === pNewOptions.experimentalStats &&
107
108
  metricsIsCompatible(pOldOptions.metrics, pNewOptions.metrics) &&
108
109
  // includeOnly suffers from a backwards compatibility disease
109
110
  includeOnlyIsCompatible(pOldOptions.includeOnly, pNewOptions.includeOnly) &&
@@ -10,6 +10,7 @@ import {
10
10
  object2Array,
11
11
  } from "./utl.mjs";
12
12
  import IndexedModuleGraph from "#graph-utl/indexed-module-graph.mjs";
13
+ import { uniq } from "#utl/array-util.mjs";
13
14
 
14
15
  function upsertCouplings(pAllDependents, pNewDependents) {
15
16
  pNewDependents.forEach((pNewDependent) => {
@@ -20,6 +21,14 @@ function upsertCouplings(pAllDependents, pNewDependents) {
20
21
  });
21
22
  }
22
23
 
24
+ /**
25
+ *
26
+ * @param {any} pAllMetrics
27
+ * @param {import("../../../../types/cruise-result.d.mts").IModule} pModule
28
+ * @param {string} pDirname
29
+ * @returns {any}
30
+ */
31
+
23
32
  function upsertFolderAttributes(pAllMetrics, pModule, pDirname) {
24
33
  pAllMetrics[pDirname] = pAllMetrics[pDirname] || {
25
34
  dependencies: {},
@@ -38,6 +47,19 @@ function upsertFolderAttributes(pAllMetrics, pModule, pDirname) {
38
47
  ),
39
48
  );
40
49
  pAllMetrics[pDirname].moduleCount += 1;
50
+
51
+ if (pModule.experimentalStats) {
52
+ if (!Object.hasOwn(pAllMetrics[pDirname], "experimentalStats")) {
53
+ pAllMetrics[pDirname].experimentalStats = {
54
+ size: 0,
55
+ topLevelStatementCount: 0,
56
+ };
57
+ }
58
+ pAllMetrics[pDirname].experimentalStats.size +=
59
+ pModule.experimentalStats.size;
60
+ pAllMetrics[pDirname].experimentalStats.topLevelStatementCount +=
61
+ pModule.experimentalStats.topLevelStatementCount;
62
+ }
41
63
  return pAllMetrics;
42
64
  }
43
65
 
@@ -53,13 +75,11 @@ function sumCounts(pAll, pCurrent) {
53
75
  }
54
76
 
55
77
  function getFolderLevelCouplings(pCouplingArray) {
56
- return Array.from(
57
- new Set(
58
- pCouplingArray.map((pCoupling) =>
59
- dirname(pCoupling.name) === "."
60
- ? pCoupling.name
61
- : dirname(pCoupling.name),
62
- ),
78
+ return uniq(
79
+ pCouplingArray.map((pCoupling) =>
80
+ dirname(pCoupling.name) === "."
81
+ ? pCoupling.name
82
+ : dirname(pCoupling.name),
63
83
  ),
64
84
  ).map((pCoupling) => ({ name: pCoupling }));
65
85
  }
@@ -95,9 +115,7 @@ function deNormalizeInstability(pFolder, _, pAllFolders) {
95
115
  }),
96
116
  };
97
117
  }
98
- function uniq(pArray) {
99
- return [...new Set(pArray)];
100
- }
118
+
101
119
  function getSinks(pFolders) {
102
120
  const lKnownFolders = new Set(pFolders.map(({ name }) => name));
103
121
  const lAllFolders = uniq(
@@ -10,7 +10,7 @@ function firstArgumentIsAString(pArgumentsNode) {
10
10
  );
11
11
  }
12
12
 
13
- function isPlaceholderlessTemplateLiteral(pArgument) {
13
+ function isPlaceholderLessTemplateLiteral(pArgument) {
14
14
  return (
15
15
  pArgument.type === "TemplateLiteral" &&
16
16
  pArgument.quasis.length === 1 &&
@@ -22,7 +22,7 @@ function firstArgumentIsATemplateLiteral(pArgumentsNode) {
22
22
  return (
23
23
  Boolean(pArgumentsNode) &&
24
24
  pArgumentsNode[0] &&
25
- isPlaceholderlessTemplateLiteral(pArgumentsNode[0])
25
+ isPlaceholderLessTemplateLiteral(pArgumentsNode[0])
26
26
  );
27
27
  }
28
28
 
@@ -70,7 +70,7 @@ export default {
70
70
  firstArgumentIsAString,
71
71
  firstArgumentIsATemplateLiteral,
72
72
  isStringLiteral,
73
- isPlaceholderlessTemplateLiteral,
73
+ isPlaceholderlessTemplateLiteral: isPlaceholderLessTemplateLiteral,
74
74
  isMemberCallExpression,
75
75
  isCalleeIdentifier,
76
76
  isRequireOfSomeSort,
@@ -0,0 +1,6 @@
1
+ export default function extractStats(pAST) {
2
+ return {
3
+ topLevelStatementCount: pAST?.body?.length || 0,
4
+ size: pAST?.end || 0,
5
+ };
6
+ }
@@ -0,0 +1,32 @@
1
+ import { join } from "node:path";
2
+ import extractES6Deps from "./extract-es6-deps.mjs";
3
+ import extractCommonJSDeps from "./extract-cjs-deps.mjs";
4
+ import extractAMDDeps from "./extract-amd-deps.mjs";
5
+ import parse from "./parse.mjs";
6
+ import extractStats from "./extract-stats.mjs";
7
+
8
+ export function extract(
9
+ { baseDir, moduleSystems, exoticRequireStrings },
10
+ pFileName,
11
+ pTranspileOptions,
12
+ ) {
13
+ let lDependencies = [];
14
+ const lAST = parse.getASTCached(join(baseDir, pFileName), pTranspileOptions);
15
+
16
+ if (moduleSystems.includes("cjs")) {
17
+ extractCommonJSDeps(lAST, lDependencies, "cjs", exoticRequireStrings);
18
+ }
19
+ if (moduleSystems.includes("es6")) {
20
+ extractES6Deps(lAST, lDependencies);
21
+ }
22
+ if (moduleSystems.includes("amd")) {
23
+ extractAMDDeps(lAST, lDependencies, exoticRequireStrings);
24
+ }
25
+
26
+ return lDependencies;
27
+ }
28
+
29
+ export function getStats({ baseDir }, pFileName, pTranspileOptions) {
30
+ const lAST = parse.getASTCached(join(baseDir, pFileName), pTranspileOptions);
31
+ return extractStats(lAST);
32
+ }
@@ -1,15 +1,15 @@
1
- import toTypescriptAST from "./parse/to-typescript-ast.mjs";
2
- import toJavascriptAST from "./parse/to-javascript-ast.mjs";
3
- import toSwcAST from "./parse/to-swc-ast.mjs";
1
+ import tscParse from "./tsc/parse.mjs";
2
+ import acornParse from "./acorn/parse.mjs";
3
+ import swcParse from "./swc/parse.mjs";
4
4
  import { clearCache as externalModuleHelpers_clearCache } from "./resolve/external-module-helpers.mjs";
5
5
  import { clearCache as getManifest_clearCache } from "./resolve/get-manifest.mjs";
6
6
  import { clearCache as resolveAMD_clearCache } from "./resolve/resolve-amd.mjs";
7
7
  import { clearCache as resolve_clearCache } from "./resolve/resolve.mjs";
8
8
 
9
9
  export default function clearCaches() {
10
- toTypescriptAST.clearCache();
11
- toJavascriptAST.clearCache();
12
- toSwcAST.clearCache();
10
+ tscParse.clearCache();
11
+ acornParse.clearCache();
12
+ swcParse.clearCache();
13
13
  externalModuleHelpers_clearCache();
14
14
  getManifest_clearCache();
15
15
  resolveAMD_clearCache();
@@ -1,117 +1,51 @@
1
1
  import { join, extname, dirname } from "node:path";
2
2
  import uniqBy from "lodash/uniqBy.js";
3
+ import { extract as acornExtract } from "./acorn/extract.mjs";
4
+ import {
5
+ extract as tscExtract,
6
+ shouldUse as tscShouldUse,
7
+ } from "./tsc/extract.mjs";
8
+ import {
9
+ extract as swcExtract,
10
+ shouldUse as swcShouldUse,
11
+ } from "./swc/extract.mjs";
3
12
  import resolve from "./resolve/index.mjs";
4
- import extractES6Deps from "./ast-extractors/extract-es6-deps.mjs";
5
- import extractCommonJSDeps from "./ast-extractors/extract-cjs-deps.mjs";
6
- import extractAMDDeps from "./ast-extractors/extract-amd-deps.mjs";
7
- import extractTypeScriptDeps from "./ast-extractors/extract-typescript-deps.mjs";
8
- import extractSwcDeps from "./ast-extractors/extract-swc-deps.mjs";
9
- import toJavascriptAST from "./parse/to-javascript-ast.mjs";
10
- import toTypescriptAST from "./parse/to-typescript-ast.mjs";
11
- import toSwcAST from "./parse/to-swc-ast.mjs";
12
13
  import {
13
14
  detectPreCompilationNess,
14
15
  extractModuleAttributes,
15
16
  } from "./helpers.mjs";
16
17
  import { intersects } from "#utl/array-util.mjs";
17
18
 
18
- function extractFromSwcAST({ baseDir, exoticRequireStrings }, pFileName) {
19
- return extractSwcDeps(
20
- toSwcAST.getASTCached(join(baseDir, pFileName)),
21
- exoticRequireStrings,
22
- );
23
- }
24
-
25
- function extractFromTypeScriptAST(
26
- { baseDir, exoticRequireStrings },
27
- pFileName,
28
- pTranspileOptions,
29
- ) {
30
- return extractTypeScriptDeps(
31
- toTypescriptAST.getASTCached(join(baseDir, pFileName), pTranspileOptions),
32
- exoticRequireStrings,
33
- );
34
- }
35
-
36
- function isTypeScriptCompatible(pFileName) {
37
- return [
38
- ".ts",
39
- ".tsx",
40
- ".mts",
41
- ".cts",
42
- ".js",
43
- ".mjs",
44
- ".cjs",
45
- ".vue",
46
- ].includes(extname(pFileName));
47
- }
48
-
49
- function shouldUseTsc({ tsPreCompilationDeps, parser }, pFileName) {
50
- return (
51
- (tsPreCompilationDeps || parser === "tsc") &&
52
- toTypescriptAST.isAvailable() &&
53
- isTypeScriptCompatible(pFileName)
54
- );
55
- }
56
-
57
- function shouldUseSwc({ parser }, pFileName) {
58
- return (
59
- parser === "swc" &&
60
- toSwcAST.isAvailable() &&
61
- isTypeScriptCompatible(pFileName)
62
- );
63
- }
64
-
65
- function extractFromJavaScriptAST(
66
- { baseDir, moduleSystems, exoticRequireStrings },
67
- pFileName,
68
- pTranspileOptions,
69
- ) {
70
- let lDependencies = [];
71
- const lAST = toJavascriptAST.getASTCached(
72
- join(baseDir, pFileName),
73
- pTranspileOptions,
74
- );
75
-
76
- if (moduleSystems.includes("cjs")) {
77
- extractCommonJSDeps(lAST, lDependencies, "cjs", exoticRequireStrings);
78
- }
79
- if (moduleSystems.includes("es6")) {
80
- extractES6Deps(lAST, lDependencies);
81
- }
82
- if (moduleSystems.includes("amd")) {
83
- extractAMDDeps(lAST, lDependencies, exoticRequireStrings);
84
- }
85
-
86
- return lDependencies;
87
- }
88
-
89
- function extractWithSwc(pCruiseOptions, pFileName) {
90
- return extractFromSwcAST(pCruiseOptions, pFileName).filter(
91
- ({ moduleSystem }) => pCruiseOptions.moduleSystems.includes(moduleSystem),
92
- );
93
- }
94
-
95
19
  function extractWithTsc(pCruiseOptions, pFileName, pTranspileOptions) {
96
- let lDependencies = extractFromTypeScriptAST(
97
- pCruiseOptions,
98
- pFileName,
99
- pTranspileOptions,
100
- ).filter(({ moduleSystem }) =>
101
- pCruiseOptions.moduleSystems.includes(moduleSystem),
102
- );
20
+ let lDependencies = tscExtract(pCruiseOptions, pFileName, pTranspileOptions);
103
21
 
104
22
  if (pCruiseOptions.tsPreCompilationDeps === "specify") {
105
23
  lDependencies = detectPreCompilationNess(
106
24
  lDependencies,
107
- extractFromJavaScriptAST(pCruiseOptions, pFileName, pTranspileOptions),
25
+ acornExtract(pCruiseOptions, pFileName, pTranspileOptions),
108
26
  );
109
27
  }
110
28
  return lDependencies;
111
29
  }
112
30
 
113
31
  /**
114
- *
32
+ * @param {IStrictCruiseOptions} pCruiseOptions
33
+ * @param {string} pFileName
34
+ * @returns {(IStrictCruiseOptions, string, any) => import("../../types/cruise-result.mjs").IDependency[]}
35
+ */
36
+ function determineExtractionFunction(pCruiseOptions, pFileName) {
37
+ let lExtractionFunction = acornExtract;
38
+
39
+ if (tscShouldUse(pCruiseOptions, pFileName)) {
40
+ lExtractionFunction = extractWithTsc;
41
+ } else if (swcShouldUse(pCruiseOptions, pFileName)) {
42
+ lExtractionFunction = swcExtract;
43
+ }
44
+
45
+ return lExtractionFunction;
46
+ }
47
+
48
+ /**
115
49
  * @param {import('../../types/dependency-cruiser.js').IStrictCruiseOptions} pCruiseOptions
116
50
  * @param {string} pFileName
117
51
  * @param {any} pTranspileOptions
@@ -122,21 +56,15 @@ function extractDependencies(pCruiseOptions, pFileName, pTranspileOptions) {
122
56
  let lDependencies = [];
123
57
 
124
58
  if (!pCruiseOptions.extraExtensionsToScan.includes(extname(pFileName))) {
125
- if (shouldUseSwc(pCruiseOptions, pFileName)) {
126
- lDependencies = extractWithSwc(pCruiseOptions, pFileName);
127
- } else if (shouldUseTsc(pCruiseOptions, pFileName)) {
128
- lDependencies = extractWithTsc(
129
- pCruiseOptions,
130
- pFileName,
131
- pTranspileOptions,
132
- );
133
- } else {
134
- lDependencies = extractFromJavaScriptAST(
135
- pCruiseOptions,
136
- pFileName,
137
- pTranspileOptions,
138
- );
139
- }
59
+ const lExtractionFunction = determineExtractionFunction(
60
+ pCruiseOptions,
61
+ pFileName,
62
+ );
63
+ lDependencies = lExtractionFunction(
64
+ pCruiseOptions,
65
+ pFileName,
66
+ pTranspileOptions,
67
+ );
140
68
  }
141
69
 
142
70
  return lDependencies.map((pDependency) => ({
@@ -0,0 +1,48 @@
1
+ import {
2
+ getStats as tscStats,
3
+ shouldUse as tscShouldUse,
4
+ } from "./tsc/extract.mjs";
5
+ import { getStats as acornStats } from "./acorn/extract.mjs";
6
+
7
+ /**
8
+ * @param {IStrictCruiseOptions} pCruiseOptions
9
+ * @param {string} pFileName
10
+ * @returns {(IStrictCruiseOptions, string, any) => import("../../types/cruise-result.mjs").IDependency[]}
11
+ */
12
+ function determineExtractionFunction(pCruiseOptions, pFileName) {
13
+ let lExtractionFunction = acornStats;
14
+
15
+ if (tscShouldUse(pCruiseOptions, pFileName)) {
16
+ lExtractionFunction = tscStats;
17
+ }
18
+
19
+ return lExtractionFunction;
20
+ }
21
+
22
+ /**
23
+ * Returns some stats for the module in pFileName
24
+ *
25
+ * @param {string} pFileName path to the file
26
+ * @param {import("../../types/dependency-cruiser.js").IStrictCruiseOptions} pCruiseOptions cruise options
27
+ * @param {import("../../types/dependency-cruiser.js").ITranspileOptions} pTranspileOptions an object with tsconfig ('typescript project') options
28
+ * ('flattened' so there's no need for file access on any
29
+ * 'extends' option in there)
30
+ * @return {import("../../types/dependency-cruiser.js").IDependency[]} an array of dependency objects (see above)
31
+ */
32
+ export default function extractStats(
33
+ pFileName,
34
+ pCruiseOptions,
35
+ pTranspileOptions,
36
+ ) {
37
+ try {
38
+ return determineExtractionFunction(pCruiseOptions, pFileName)(
39
+ pCruiseOptions,
40
+ pFileName,
41
+ pTranspileOptions,
42
+ );
43
+ } catch (pError) {
44
+ throw new Error(
45
+ `Extracting stats ran afoul of...\n\n ${pError.message}\n... in ${pFileName}\n\n`,
46
+ );
47
+ }
48
+ }
@@ -1,3 +1,5 @@
1
+ import { extname } from "node:path";
2
+
1
3
  export function dependenciesEqual(pLeftDependency) {
2
4
  // As we're using this to compare (typescript) pre-compilation dependencies
3
5
  // with post-compilation dependencies we do not consider the moduleSystem.
@@ -77,6 +79,23 @@ export function extractModuleAttributes(pString) {
77
79
  */
78
80
  export function stripQueryParameters(pFilenameString) {
79
81
  // url.parse(pFilenameString).pathname did this quite admirably, but it's
80
- // deprecated, hence this fonky RE replace. And accompanying unit test :-/
82
+ // deprecated, hence this funky RE replace. And accompanying unit test :-/
81
83
  return pFilenameString.replace(/\?.+$/, "");
82
84
  }
85
+ /**
86
+ * Returns true if the file name has a TypeScript compatible extension
87
+ * @param {string} pFileName
88
+ * @returns {boolean}
89
+ */
90
+ export function isTypeScriptCompatible(pFileName) {
91
+ return [
92
+ ".ts",
93
+ ".tsx",
94
+ ".mts",
95
+ ".cts",
96
+ ".js",
97
+ ".mjs",
98
+ ".cjs",
99
+ ".vue",
100
+ ].includes(extname(pFileName));
101
+ }
@@ -1,9 +1,10 @@
1
- import getDependencies from "./get-dependencies.mjs";
1
+ import extractDependencies from "./extract-dependencies.mjs";
2
+ import extractStats from "./extract-stats.mjs";
2
3
  import gatherInitialSources from "./gather-initial-sources.mjs";
3
4
  import clearCaches from "./clear-caches.mjs";
4
5
  import { bus } from "#utl/bus.mjs";
5
6
 
6
- /* eslint max-params:0 */
7
+ /* eslint max-params:0 , max-lines-per-function:0*/
7
8
  function extractRecursive(
8
9
  pFileName,
9
10
  pCruiseOptions,
@@ -15,7 +16,7 @@ function extractRecursive(
15
16
  pVisited.add(pFileName);
16
17
  const lDependencies =
17
18
  pCruiseOptions.maxDepth <= 0 || pDepth < pCruiseOptions.maxDepth
18
- ? getDependencies(
19
+ ? extractDependencies(
19
20
  pFileName,
20
21
  pCruiseOptions,
21
22
  pResolveOptions,
@@ -46,6 +47,15 @@ function extractRecursive(
46
47
  [
47
48
  {
48
49
  source: pFileName,
50
+ ...(pCruiseOptions.experimentalStats
51
+ ? {
52
+ experimentalStats: extractStats(
53
+ pFileName,
54
+ pCruiseOptions,
55
+ pTranspileOptions,
56
+ ),
57
+ }
58
+ : {}),
49
59
  dependencies: lDependencies,
50
60
  },
51
61
  ],
@@ -1,3 +1,5 @@
1
+ import { uniq } from "#utl/array-util.mjs";
2
+
1
3
  /* eslint-disable security/detect-object-injection */
2
4
  function normalizeManifestKeys(pManifest) {
3
5
  let lReturnValue = pManifest;
@@ -19,9 +21,7 @@ function mergeDependencyKey(pClosestDependencyKey, pFurtherDependencyKey) {
19
21
  }
20
22
 
21
23
  function mergeDependencyArray(pClosestDependencyKey, pFurtherDependencyKey) {
22
- return Array.from(
23
- new Set(pClosestDependencyKey.concat(pFurtherDependencyKey)),
24
- );
24
+ return uniq(pClosestDependencyKey.concat(pFurtherDependencyKey));
25
25
  }
26
26
 
27
27
  function isInterestingKey(pKey) {
@@ -35,11 +35,9 @@ function getDependencyKeys(pPackage) {
35
35
  }
36
36
 
37
37
  function getJointUniqueDependencyKeys(pClosestPackage, pFurtherPackage) {
38
- return Array.from(
39
- new Set(
40
- getDependencyKeys(pClosestPackage).concat(
41
- getDependencyKeys(pFurtherPackage),
42
- ),
38
+ return uniq(
39
+ getDependencyKeys(pClosestPackage).concat(
40
+ getDependencyKeys(pFurtherPackage),
43
41
  ),
44
42
  );
45
43
  }
@@ -1,4 +1,4 @@
1
- import SwcDependencyVisitor from "./swc-dependency-visitor.mjs";
1
+ import SwcDependencyVisitor from "./dependency-visitor.mjs";
2
2
 
3
3
  /**
4
4
  * @param {import('@swc/core').ModuleItem[]} pSwcAST
@@ -0,0 +1,20 @@
1
+ import { join } from "node:path/posix";
2
+ import { isTypeScriptCompatible } from "../helpers.mjs";
3
+ import extractSwcDeps from "./extract-swc-deps.mjs";
4
+ import parse from "./parse.mjs";
5
+
6
+ export function shouldUse({ parser }, pFileName) {
7
+ return (
8
+ parser === "swc" && parse.isAvailable() && isTypeScriptCompatible(pFileName)
9
+ );
10
+ }
11
+
12
+ export function extract(
13
+ { baseDir, exoticRequireStrings, moduleSystems },
14
+ pFileName,
15
+ ) {
16
+ return extractSwcDeps(
17
+ parse.getASTCached(join(baseDir, pFileName)),
18
+ exoticRequireStrings,
19
+ ).filter(({ moduleSystem }) => moduleSystems.includes(moduleSystem));
20
+ }
@@ -35,7 +35,7 @@ export const EXTENSION2WRAPPER = new Map([
35
35
  [".cjsx", coffeeVanillaWrap],
36
36
  ]);
37
37
 
38
- const BABELEABLE_EXTENSIONS = [
38
+ const BABEL_ABLE_EXTENSIONS = [
39
39
  ".js",
40
40
  ".cjs",
41
41
  ".mjs",
@@ -47,7 +47,7 @@ const BABELEABLE_EXTENSIONS = [
47
47
 
48
48
  /**
49
49
  * returns the babel wrapper if there's a babelConfig in the transpiler
50
- * options for babeleable extensions (javascript and typescript - currently
50
+ * options for babel- able extensions (javascript and typescript - currently
51
51
  * not configurable)
52
52
  *
53
53
  * returns the wrapper module configured for the extension pExtension if
@@ -63,7 +63,7 @@ const BABELEABLE_EXTENSIONS = [
63
63
  export function getWrapper(pExtension, pTranspilerOptions) {
64
64
  if (
65
65
  Object.keys(pTranspilerOptions?.babelConfig ?? {}).length > 0 &&
66
- BABELEABLE_EXTENSIONS.includes(pExtension)
66
+ BABEL_ABLE_EXTENSIONS.includes(pExtension)
67
67
  ) {
68
68
  return babelWrap;
69
69
  }
@@ -0,0 +1,6 @@
1
+ export default function extractStats(pAST) {
2
+ return {
3
+ topLevelStatementCount: pAST?.statements?.length || 0,
4
+ size: pAST?.end || 0,
5
+ };
6
+ }
@@ -0,0 +1,29 @@
1
+ import { join } from "node:path";
2
+ import { isTypeScriptCompatible } from "../helpers.mjs";
3
+ import extractTypeScriptDeps from "./extract-typescript-deps.mjs";
4
+ import parse from "./parse.mjs";
5
+ import extractStats from "./extract-stats.mjs";
6
+
7
+ export function shouldUse({ tsPreCompilationDeps, parser }, pFileName) {
8
+ return (
9
+ (tsPreCompilationDeps || parser === "tsc") &&
10
+ parse.isAvailable() &&
11
+ isTypeScriptCompatible(pFileName)
12
+ );
13
+ }
14
+
15
+ export function extract(
16
+ { baseDir, exoticRequireStrings, moduleSystems },
17
+ pFileName,
18
+ pTranspileOptions,
19
+ ) {
20
+ return extractTypeScriptDeps(
21
+ parse.getASTCached(join(baseDir, pFileName), pTranspileOptions),
22
+ exoticRequireStrings,
23
+ ).filter(({ moduleSystem }) => moduleSystems.includes(moduleSystem));
24
+ }
25
+
26
+ export function getStats({ baseDir }, pFileName, pTranspileOptions) {
27
+ const lAST = parse.getASTCached(join(baseDir, pFileName), pTranspileOptions);
28
+ return extractStats(lAST);
29
+ }
@@ -1,16 +1,13 @@
1
1
  import reject from "lodash/reject.js";
2
2
  import compare from "./compare.mjs";
3
+ import { uniq } from "#utl/array-util.mjs";
3
4
 
4
5
  function mergeDependency(pLeftDependency, pRightDependency) {
5
6
  return {
6
7
  ...pLeftDependency,
7
8
  ...pRightDependency,
8
- dependencyTypes: Array.from(
9
- new Set(
10
- pLeftDependency.dependencyTypes.concat(
11
- pRightDependency.dependencyTypes,
12
- ),
13
- ),
9
+ dependencyTypes: uniq(
10
+ pLeftDependency.dependencyTypes.concat(pRightDependency.dependencyTypes),
14
11
  ),
15
12
  rules: pLeftDependency.rules
16
13
  .concat(pRightDependency?.rules ?? [])
@@ -10,9 +10,10 @@
10
10
  * @return {import("../../types/rule-set").IForbiddenRuleType|undefined} - a rule (or 'undefined' if nothing found)
11
11
  */
12
12
  export function findRuleByName(pRuleSet, pName) {
13
- return (pRuleSet?.forbidden ?? []).find(
14
- (pForbiddenRule) => pForbiddenRule.name === pName,
13
+ const lNamedRules = (pRuleSet?.forbidden ?? []).concat(
14
+ pRuleSet?.required ?? [],
15
15
  );
16
+ return lNamedRules.find((pRule) => pRule.name === pName);
16
17
  }
17
18
 
18
19
  function ruleHasALicenseLikeAttribute(pRule) {
@@ -1,14 +1,11 @@
1
1
  /* eslint-disable security/detect-object-injection */
2
2
  import { normalizeREProperties } from "../helpers.mjs";
3
3
  import defaults from "./defaults.mjs";
4
+ import { uniq } from "#utl/array-util.mjs";
4
5
 
5
6
  const DEFAULT_CACHE_FOLDER = "node_modules/.cache/dependency-cruiser";
6
7
  const DEFAULT_CACHE_STRATEGY = "metadata";
7
8
 
8
- function uniq(pArray) {
9
- return [...new Set(pArray)];
10
- }
11
-
12
9
  function normalizeFilterOption(pFilterOption) {
13
10
  let lReturnValue = pFilterOption || {};
14
11