dependency-cruiser 17.2.0 → 17.3.2
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/package.json +54 -61
- package/src/cache/content-strategy.mjs +9 -9
- package/src/cache/find-content-changes.mjs +1 -0
- package/src/cache/options-compatible.mjs +2 -0
- package/src/cli/index.mjs +10 -15
- package/src/cli/init-config/build-config.mjs +15 -0
- package/src/cli/init-config/config-template.mjs +7 -0
- package/src/cli/init-config/get-user-input.mjs +8 -1
- package/src/cli/init-config/index.mjs +1 -0
- package/src/cli/init-config/normalize-init-options.mjs +5 -5
- package/src/enrich/derive/{dependents/index.mjs → dependents.mjs} +9 -2
- package/src/enrich/derive/folders/aggregate-to-folders.mjs +7 -7
- package/src/enrich/derive/reachable.mjs +18 -14
- package/src/enrich/enrich-modules.mjs +1 -1
- package/src/enrich/summarize/summarize-options.mjs +1 -0
- package/src/extract/acorn/estree-helpers.mjs +44 -22
- package/src/extract/acorn/extract-amd-deps.mjs +24 -18
- package/src/extract/acorn/extract-cjs-deps.mjs +43 -15
- package/src/extract/acorn/extract-es6-deps.mjs +6 -3
- package/src/extract/acorn/extract.mjs +13 -2
- package/src/extract/gather-initial-sources.mjs +16 -14
- package/src/extract/index.mjs +38 -42
- package/src/extract/resolve/module-classifiers.mjs +3 -3
- package/src/extract/tsc/extract-typescript-deps.mjs +81 -11
- package/src/extract/tsc/extract.mjs +8 -1
- package/src/graph-utl/consolidate-module-dependencies.mjs +18 -21
- package/src/graph-utl/consolidate-modules.mjs +19 -19
- package/src/graph-utl/filter-bank.mjs +11 -8
- package/src/graph-utl/indexed-module-graph.mjs +21 -19
- package/src/main/options/defaults.mjs +1 -0
- package/src/main/resolve-options/normalize.mjs +6 -4
- package/src/meta.cjs +1 -1
- package/src/report/d2.mjs +1 -0
- package/src/report/mermaid.mjs +7 -6
- package/src/schema/baseline-violations.schema.mjs +1 -1
- package/src/schema/configuration.schema.mjs +1 -1
- package/src/schema/cruise-result.schema.mjs +1 -1
- package/src/utl/find-all-files.mjs +20 -28
- package/src/validate/match-folder-dependency-rule.mjs +2 -4
- package/src/validate/matchers.mjs +7 -7
- package/types/options.d.mts +6 -0
- package/types/shared-types.d.mts +1 -0
- package/types/strict-restrictions.d.mts +4 -8
- package/types/strict-rule-set.d.mts +2 -4
- package/src/enrich/derive/dependents/get-dependents.mjs +0 -8
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dependency-cruiser",
|
|
3
|
-
"version": "17.2
|
|
3
|
+
"version": "17.3.2",
|
|
4
4
|
"description": "Validate and visualize dependencies. With your rules. JavaScript, TypeScript, CoffeeScript. ES6, CommonJS, AMD.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"static analysis",
|
|
@@ -18,50 +18,51 @@
|
|
|
18
18
|
],
|
|
19
19
|
"author": "Sander Verweij (https://sverweij.github.io)",
|
|
20
20
|
"contributors": [
|
|
21
|
-
"
|
|
22
|
-
"TruongSinh Tran-Nguyen (https://truongsinh.pro)",
|
|
23
|
-
"Bastian Hess (https://github.com/bashess)",
|
|
21
|
+
"0xflotus (https://github.com/0xflotus)",
|
|
24
22
|
"Álvaro Cuesta (https://github.com/alvaro-cuesta)",
|
|
25
23
|
"anna (https://github.com/annamooseity)",
|
|
26
|
-
"
|
|
27
|
-
"Joshua T (https://github.com/radiantly)",
|
|
28
|
-
"Ivan (https://github.com/Winner95)",
|
|
29
|
-
"Millicent Billette (https://github.com/1000i100)",
|
|
30
|
-
"Frieder Bluemle (https://github.com/friederbluemle)",
|
|
31
|
-
"davidparkagoda (https://github.com/davidparkagoda)",
|
|
32
|
-
"Matt Button (https://github.com/BRMatt)",
|
|
33
|
-
"Jon Lauridsen (https://jonlauridsen.com)",
|
|
34
|
-
"Klaus Meinhardt (https://github.com/ajafff)",
|
|
35
|
-
"cunzaizhuyi (https://github.com/cunzaizhuyi)",
|
|
36
|
-
"Greg Lockwood (https://github.com/greglockwood)",
|
|
37
|
-
"Jeremy Magland (https://github.com/magland)",
|
|
38
|
-
"Sebastian Landwehr (https://sebastianlandwehr.com)",
|
|
39
|
-
"Brody McKee (https://github.com/mrmckeb)",
|
|
24
|
+
"Bastian Hess (https://github.com/bashess)",
|
|
40
25
|
"Bin (https://github.com/soulhat)",
|
|
41
|
-
"
|
|
42
|
-
"Roy Swinkels (https://github.com/donroyco)",
|
|
43
|
-
"Martin Slota (https://github.com/martinslota)",
|
|
44
|
-
"Luke Page (https://github.com/lukeapage)",
|
|
45
|
-
"Emily Marigold Klassen (https://forivall.com)",
|
|
26
|
+
"Brody McKee (https://github.com/mrmckeb)",
|
|
46
27
|
"Christian Vuerings (https://github.com/christianvuerings)",
|
|
47
|
-
"Yuanhai He (https://bestmike007.com)",
|
|
48
|
-
"Quentin de Metz (https://github.com/quentindemetz)",
|
|
49
|
-
"Lars Artmann (https://larsartmann.com)",
|
|
50
|
-
"Jessica Kerr (https://jessitron.com)",
|
|
51
28
|
"Creative Ataraxia (https://github.com/Creative-Ataraxia)",
|
|
52
|
-
"
|
|
53
|
-
"KenjiroKubota (https://github.com/kubotak-is)",
|
|
29
|
+
"cunzaizhuyi (https://github.com/cunzaizhuyi)",
|
|
54
30
|
"Daniel Edholm Ignat (https://github.com/dignite)",
|
|
55
31
|
"Daniel Rodríguez Rivero (https://danielorodriguez.com)",
|
|
32
|
+
"davidparkagoda (https://github.com/davidparkagoda)",
|
|
33
|
+
"electrovir (https://github.com/electrovir)",
|
|
34
|
+
"Emily Marigold Klassen (https://forivall.com)",
|
|
35
|
+
"Frederik Schubert (https://github.com/ferdynator)",
|
|
36
|
+
"Frieder Bluemle (https://github.com/friederbluemle)",
|
|
37
|
+
"fusheng (https://github.com/lin-hun)",
|
|
38
|
+
"Greg Lockwood (https://github.com/greglockwood)",
|
|
39
|
+
"Hirotaka Miyagi (https://mh4gf.dev)",
|
|
40
|
+
"Ivan (https://github.com/Winner95)",
|
|
41
|
+
"Jeremy Magland (https://github.com/magland)",
|
|
42
|
+
"Jessica Kerr (https://jessitron.com)",
|
|
43
|
+
"Jon Lauridsen (https://jonlauridsen.com)",
|
|
44
|
+
"Joshua T (https://github.com/radiantly)",
|
|
45
|
+
"KenjiroKubota (https://github.com/kubotak-is)",
|
|
46
|
+
"Kentaro Suzuki (https://github.com/sushichan044)",
|
|
47
|
+
"Klaus Meinhardt (https://github.com/ajafff)",
|
|
48
|
+
"Lars Artmann (https://larsartmann.com)",
|
|
49
|
+
"Luke Page (https://github.com/lukeapage)",
|
|
50
|
+
"Martin Slota (https://github.com/martinslota)",
|
|
51
|
+
"Matt Button (https://github.com/BRMatt)",
|
|
52
|
+
"Millicent Billette (https://github.com/1000i100)",
|
|
56
53
|
"Nick Ribal (https://github.com/elektronik2k5)",
|
|
54
|
+
"Quentin de Metz (https://github.com/quentindemetz)",
|
|
55
|
+
"Radosław Kłos (https://klos.dev)",
|
|
57
56
|
"Richard Musiol (https://github.com/neelance)",
|
|
57
|
+
"Roy Swinkels (https://github.com/donroyco)",
|
|
58
|
+
"Sebastian Landwehr (https://sebastianlandwehr.com)",
|
|
58
59
|
"Sharang Pai (https://sharangpai.me)",
|
|
59
60
|
"Stefan Gojan (https://stefan-gojan.de)",
|
|
60
|
-
"Valentin Semirulnik (https://github.com/7rulnik)",
|
|
61
61
|
"Tharun Rajendran (https://github.com/tharun208)",
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
"
|
|
62
|
+
"TruongSinh Tran-Nguyen (https://truongsinh.pro)",
|
|
63
|
+
"Valentin Semirulnik (https://github.com/7rulnik)",
|
|
64
|
+
"Yuanhai He (https://bestmike007.com)",
|
|
65
|
+
"정건우 (https://www.zigae.com/)"
|
|
65
66
|
],
|
|
66
67
|
"type": "module",
|
|
67
68
|
"license": "MIT",
|
|
@@ -141,34 +142,26 @@
|
|
|
141
142
|
"README.md"
|
|
142
143
|
],
|
|
143
144
|
"dependencies": {
|
|
144
|
-
"acorn": "
|
|
145
|
-
"acorn-jsx": "
|
|
146
|
-
"acorn-jsx-walk": "
|
|
147
|
-
"acorn-loose": "
|
|
148
|
-
"acorn-walk": "
|
|
149
|
-
"ajv": "
|
|
150
|
-
"commander": "
|
|
151
|
-
"enhanced-resolve": "
|
|
152
|
-
"ignore": "
|
|
153
|
-
"interpret": "
|
|
154
|
-
"is-installed-globally": "
|
|
155
|
-
"json5": "
|
|
156
|
-
"memoize": "
|
|
157
|
-
"picomatch": "
|
|
158
|
-
"prompts": "
|
|
159
|
-
"rechoir": "
|
|
160
|
-
"safe-regex": "
|
|
161
|
-
"semver": "
|
|
162
|
-
"tsconfig-paths-webpack-plugin": "
|
|
163
|
-
"watskeburt": "
|
|
164
|
-
},
|
|
165
|
-
"overrides": {
|
|
166
|
-
"cross-spawn": ">=6.0.6",
|
|
167
|
-
"nanoid": "^3.3.8"
|
|
168
|
-
},
|
|
169
|
-
"resolutions": {
|
|
170
|
-
"cross-spawn": ">=6.0.6",
|
|
171
|
-
"nanoid": "^3.3.8"
|
|
145
|
+
"acorn": "8.15.0",
|
|
146
|
+
"acorn-jsx": "5.3.2",
|
|
147
|
+
"acorn-jsx-walk": "2.0.0",
|
|
148
|
+
"acorn-loose": "8.5.2",
|
|
149
|
+
"acorn-walk": "8.3.4",
|
|
150
|
+
"ajv": "8.17.1",
|
|
151
|
+
"commander": "14.0.2",
|
|
152
|
+
"enhanced-resolve": "5.18.3",
|
|
153
|
+
"ignore": "7.0.5",
|
|
154
|
+
"interpret": "3.1.1",
|
|
155
|
+
"is-installed-globally": "1.0.0",
|
|
156
|
+
"json5": "2.2.3",
|
|
157
|
+
"memoize": "10.2.0",
|
|
158
|
+
"picomatch": "4.0.3",
|
|
159
|
+
"prompts": "2.4.2",
|
|
160
|
+
"rechoir": "0.8.0",
|
|
161
|
+
"safe-regex": "2.1.1",
|
|
162
|
+
"semver": "7.7.3",
|
|
163
|
+
"tsconfig-paths-webpack-plugin": "4.2.0",
|
|
164
|
+
"watskeburt": "5.0.0"
|
|
172
165
|
},
|
|
173
166
|
"engines": {
|
|
174
167
|
"node": "^20.12||^22||>=24"
|
|
@@ -87,15 +87,15 @@ export default class ContentStrategy {
|
|
|
87
87
|
revisionDataEqual(pExistingRevisionData, pNewRevisionData) {
|
|
88
88
|
return Boolean(
|
|
89
89
|
pExistingRevisionData &&
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
90
|
+
pNewRevisionData &&
|
|
91
|
+
// Even though we don't really have a SHA1, it might be the previous version
|
|
92
|
+
// of the cache did, e.g. because it was rendered with the metadata cache
|
|
93
|
+
// strategy. In that case the SHA1 comparison is a reliable, fast bailout.
|
|
94
|
+
pExistingRevisionData.SHA1 === pNewRevisionData.SHA1 &&
|
|
95
|
+
isDeepStrictEqual(
|
|
96
|
+
pExistingRevisionData.changes,
|
|
97
|
+
pNewRevisionData.changes,
|
|
98
|
+
),
|
|
99
99
|
);
|
|
100
100
|
}
|
|
101
101
|
|
|
@@ -106,6 +106,8 @@ export function optionsAreCompatible(pOldOptions, pNewOptions) {
|
|
|
106
106
|
pOldOptions.combinedDependencies === pNewOptions.combinedDependencies &&
|
|
107
107
|
pOldOptions.experimentalStats === pNewOptions.experimentalStats &&
|
|
108
108
|
pOldOptions.detectJSDocImports === pNewOptions.detectJSDocImports &&
|
|
109
|
+
pOldOptions.detectProcessBuiltinModuleCalls ===
|
|
110
|
+
pNewOptions.detectProcessBuiltinModuleCalls &&
|
|
109
111
|
pOldOptions.skipAnalysisNotInRules === pNewOptions.skipAnalysisNotInRules &&
|
|
110
112
|
metricsIsCompatible(pOldOptions.metrics, pNewOptions.metrics) &&
|
|
111
113
|
// includeOnly suffers from a backwards compatibility disease
|
package/src/cli/index.mjs
CHANGED
|
@@ -20,9 +20,8 @@ async function extractResolveOptions(pCruiseOptions) {
|
|
|
20
20
|
pCruiseOptions?.ruleSet?.options?.webpackConfig?.fileName ?? null;
|
|
21
21
|
|
|
22
22
|
if (lWebPackConfigFileName) {
|
|
23
|
-
const { default: extractWebpackResolveConfig } =
|
|
24
|
-
"#config-utl/extract-webpack-resolve-config.mjs"
|
|
25
|
-
);
|
|
23
|
+
const { default: extractWebpackResolveConfig } =
|
|
24
|
+
await import("#config-utl/extract-webpack-resolve-config.mjs");
|
|
26
25
|
lResolveOptions = await extractWebpackResolveConfig(
|
|
27
26
|
lWebPackConfigFileName,
|
|
28
27
|
pCruiseOptions?.ruleSet?.options?.webpackConfig?.env ?? null,
|
|
@@ -34,9 +33,8 @@ async function extractResolveOptions(pCruiseOptions) {
|
|
|
34
33
|
|
|
35
34
|
async function addKnownViolations(pCruiseOptions) {
|
|
36
35
|
if (pCruiseOptions.knownViolationsFile) {
|
|
37
|
-
const { default: extractKnownViolations } =
|
|
38
|
-
"#config-utl/extract-known-violations.mjs"
|
|
39
|
-
);
|
|
36
|
+
const { default: extractKnownViolations } =
|
|
37
|
+
await import("#config-utl/extract-known-violations.mjs");
|
|
40
38
|
const lKnownViolations = await extractKnownViolations(
|
|
41
39
|
pCruiseOptions.knownViolationsFile,
|
|
42
40
|
);
|
|
@@ -56,9 +54,8 @@ async function extractTSConfigOptions(pCruiseOptions) {
|
|
|
56
54
|
pCruiseOptions?.ruleSet?.options?.tsConfig?.fileName ?? null;
|
|
57
55
|
|
|
58
56
|
if (lTSConfigFileName) {
|
|
59
|
-
const { default: extractTSConfig } =
|
|
60
|
-
"#config-utl/extract-ts-config.mjs"
|
|
61
|
-
);
|
|
57
|
+
const { default: extractTSConfig } =
|
|
58
|
+
await import("#config-utl/extract-ts-config.mjs");
|
|
62
59
|
lReturnValue = extractTSConfig(lTSConfigFileName);
|
|
63
60
|
}
|
|
64
61
|
|
|
@@ -70,9 +67,8 @@ async function extractBabelConfigOptions(pCruiseOptions) {
|
|
|
70
67
|
const lBabelConfigFileName =
|
|
71
68
|
pCruiseOptions?.ruleSet?.options?.babelConfig?.fileName ?? null;
|
|
72
69
|
if (lBabelConfigFileName) {
|
|
73
|
-
const { default: extractBabelConfig } =
|
|
74
|
-
"#config-utl/extract-babel-config.mjs"
|
|
75
|
-
);
|
|
70
|
+
const { default: extractBabelConfig } =
|
|
71
|
+
await import("#config-utl/extract-babel-config.mjs");
|
|
76
72
|
lReturnValue = extractBabelConfig(lBabelConfigFileName);
|
|
77
73
|
}
|
|
78
74
|
|
|
@@ -177,9 +173,8 @@ export default async function executeCli(
|
|
|
177
173
|
}
|
|
178
174
|
/* c8 ignore stop */
|
|
179
175
|
if (lCruiseOptions.info === true) {
|
|
180
|
-
const { default: formatMetaInfo } =
|
|
181
|
-
"./format-meta-info.mjs"
|
|
182
|
-
);
|
|
176
|
+
const { default: formatMetaInfo } =
|
|
177
|
+
await import("./format-meta-info.mjs");
|
|
183
178
|
lStreams.stdout.write(await formatMetaInfo());
|
|
184
179
|
} else if (lCruiseOptions.init) {
|
|
185
180
|
const { default: initConfig } = await import("./init-config/index.mjs");
|
|
@@ -73,6 +73,17 @@ function buildDetectJSDocumentImportsAttribute(pInitOptions) {
|
|
|
73
73
|
: "// detectJSDocImports: true,";
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
/**
|
|
77
|
+
*
|
|
78
|
+
* @param {IInitConfig} pInitOptions
|
|
79
|
+
* @returns {string}
|
|
80
|
+
*/
|
|
81
|
+
function buildDetectProcessBuiltinModuleCalls(pInitOptions) {
|
|
82
|
+
return pInitOptions.detectProcessBuiltinModuleCalls
|
|
83
|
+
? "detectProcessBuiltinModuleCalls: true,"
|
|
84
|
+
: "// detectProcessBuiltinModuleCalls: true,";
|
|
85
|
+
}
|
|
86
|
+
|
|
76
87
|
/**
|
|
77
88
|
* @param {IInitConfig} pInitOptions
|
|
78
89
|
* @returns {string}
|
|
@@ -213,6 +224,10 @@ export default function buildConfig(pInitOptions) {
|
|
|
213
224
|
"{{detectJSDocImportsAttribute}}",
|
|
214
225
|
buildDetectJSDocumentImportsAttribute(pInitOptions),
|
|
215
226
|
)
|
|
227
|
+
.replace(
|
|
228
|
+
"{{detectProcessBuiltinModuleCalls}}",
|
|
229
|
+
buildDetectProcessBuiltinModuleCalls(pInitOptions),
|
|
230
|
+
)
|
|
216
231
|
.replace(
|
|
217
232
|
"{{tsPreCompilationDepsAttribute}}",
|
|
218
233
|
buildTsPreCompilationDepsAttribute(pInitOptions),
|
|
@@ -239,6 +239,13 @@ module.exports = {
|
|
|
239
239
|
*/
|
|
240
240
|
{{detectJSDocImportsAttribute}}
|
|
241
241
|
|
|
242
|
+
/*
|
|
243
|
+
false: don't look at process.getBuiltinModule calls (the default)
|
|
244
|
+
true: dependency-cruiser will detect calls to process.getBuiltinModule/
|
|
245
|
+
globalThis.process.getBuiltinModule as imports.
|
|
246
|
+
*/
|
|
247
|
+
{{detectProcessBuiltinModuleCalls}}
|
|
248
|
+
|
|
242
249
|
/* prefix for links in html and svg output (e.g. 'https://github.com/you/yourrepo/blob/main/'
|
|
243
250
|
to open it on your online repo or \`vscode://file/$\{process.cwd()}/\` to
|
|
244
251
|
open it in visual studio code),
|
|
@@ -113,9 +113,16 @@ const QUESTIONS = [
|
|
|
113
113
|
{
|
|
114
114
|
name: "detectJSDocImports",
|
|
115
115
|
type: () => (tscIsAvailable() ? "confirm" : false),
|
|
116
|
-
message: "Do you want to detect JSDoc imports
|
|
116
|
+
message: "Do you want to detect JSDoc imports (slightly slower)?",
|
|
117
117
|
initial: false,
|
|
118
118
|
},
|
|
119
|
+
{
|
|
120
|
+
name: "detectProcessBuiltinModuleCalls",
|
|
121
|
+
type: "confirm",
|
|
122
|
+
message:
|
|
123
|
+
"Do you want to detect process.getBuiltinModule imports (slightly slower)?",
|
|
124
|
+
initial: true,
|
|
125
|
+
},
|
|
119
126
|
{
|
|
120
127
|
name: "tsPreCompilationDeps",
|
|
121
128
|
type: (_, pAnswers) => (pAnswers.useTsConfig ? "confirm" : false),
|
|
@@ -45,6 +45,7 @@ function getOneShotConfig(pOneShotConfigId) {
|
|
|
45
45
|
useTsConfig: hasTSConfigCandidates(),
|
|
46
46
|
tsConfig: getTSConfigCandidates().shift(),
|
|
47
47
|
detectJSDocImports: false,
|
|
48
|
+
detectProcessBuiltinModuleCalls: true,
|
|
48
49
|
tsPreCompilationDeps: hasTSConfigCandidates(),
|
|
49
50
|
useWebpackConfig: hasWebpackConfigCandidates(),
|
|
50
51
|
webpackConfig: getWebpackConfigCandidates().shift(),
|
|
@@ -19,12 +19,12 @@ import meta from "#meta.cjs";
|
|
|
19
19
|
function usesTypeScript(pInitOptions, pExtensions) {
|
|
20
20
|
return Boolean(
|
|
21
21
|
pInitOptions.tsConfig ||
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
),
|
|
22
|
+
pInitOptions.tsPreCompilationDeps ||
|
|
23
|
+
(pExtensions || []).some((pExtension) =>
|
|
24
|
+
[".ts", ".tsx", ".d.ts", ".mts", ".d.mts", ".cts", ".d.cts"].includes(
|
|
25
|
+
pExtension,
|
|
27
26
|
),
|
|
27
|
+
),
|
|
28
28
|
);
|
|
29
29
|
}
|
|
30
30
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { isDependent } from "./module-utl.mjs";
|
|
2
2
|
|
|
3
|
-
/** @import { IFlattenedRuleSet } from "
|
|
3
|
+
/** @import { IFlattenedRuleSet } from "../../../types/rule-set.mjs" */
|
|
4
4
|
|
|
5
5
|
function isDependentsRule(pRule) {
|
|
6
6
|
// used in folder rules and when moreUnstable is in the 'to' => governed by
|
|
@@ -16,6 +16,13 @@ function isDependentsRule(pRule) {
|
|
|
16
16
|
);
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
export function getDependents(pModule, pModules) {
|
|
20
|
+
// perf between O(n) in an unconnected graph and O(n^2) in a fully connected one
|
|
21
|
+
return pModules
|
|
22
|
+
.filter(isDependent(pModule.source))
|
|
23
|
+
.map((pDependentModule) => pDependentModule.source);
|
|
24
|
+
}
|
|
25
|
+
|
|
19
26
|
/**
|
|
20
27
|
* @param {IFlattenedRuleSet} pRuleSet
|
|
21
28
|
* @returns {boolean}
|
|
@@ -13,12 +13,12 @@ import IndexedModuleGraph from "#graph-utl/indexed-module-graph.mjs";
|
|
|
13
13
|
import { uniq } from "#utl/array-util.mjs";
|
|
14
14
|
|
|
15
15
|
function upsertCouplings(pAllDependents, pNewDependents) {
|
|
16
|
-
pNewDependents
|
|
17
|
-
pAllDependents[
|
|
16
|
+
for (const lNewDependent of pNewDependents) {
|
|
17
|
+
pAllDependents[lNewDependent] = pAllDependents[lNewDependent] || {
|
|
18
18
|
count: 0,
|
|
19
19
|
};
|
|
20
|
-
pAllDependents[
|
|
21
|
-
}
|
|
20
|
+
pAllDependents[lNewDependent].count += 1;
|
|
21
|
+
}
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
/**
|
|
@@ -64,9 +64,9 @@ function upsertFolderAttributes(pAllMetrics, pModule, pDirname) {
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
function aggregateToFolder(pAllFolders, pModule) {
|
|
67
|
-
getParentFolders(dirname(pModule.source))
|
|
68
|
-
upsertFolderAttributes(pAllFolders, pModule,
|
|
69
|
-
|
|
67
|
+
for (const lParentDirectory of getParentFolders(dirname(pModule.source))) {
|
|
68
|
+
upsertFolderAttributes(pAllFolders, pModule, lParentDirectory);
|
|
69
|
+
}
|
|
70
70
|
return pAllFolders;
|
|
71
71
|
}
|
|
72
72
|
|
|
@@ -171,25 +171,29 @@ function addReachabilityToGraph(pGraph, pIndexedGraph, pReachableRule) {
|
|
|
171
171
|
const lFromModules = pGraph.filter(isModuleInRuleFrom(pReachableRule));
|
|
172
172
|
|
|
173
173
|
return pGraph.map((pModule) => {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
174
|
+
// strictly speaking we should clone pModule to prevent mutating it,
|
|
175
|
+
// but in practice this function is called with a structuredClone'd graph
|
|
176
|
+
// anyway and the (reference only) copy we use now is faster (observable
|
|
177
|
+
// even on dependency-cruiser's self scan) and less memory intentsive.
|
|
178
|
+
let lModule = pModule;
|
|
179
|
+
|
|
180
|
+
if (shouldAddReaches(pReachableRule, lModule)) {
|
|
181
|
+
lModule = addReachesToModule(
|
|
182
|
+
lModule,
|
|
179
183
|
pGraph,
|
|
180
184
|
pIndexedGraph,
|
|
181
185
|
pReachableRule,
|
|
182
186
|
);
|
|
183
187
|
}
|
|
184
|
-
if (shouldAddReachable(pReachableRule,
|
|
185
|
-
|
|
186
|
-
|
|
188
|
+
if (shouldAddReachable(pReachableRule, lModule, pGraph)) {
|
|
189
|
+
lModule = addReachableToModule(
|
|
190
|
+
lModule,
|
|
187
191
|
pIndexedGraph,
|
|
188
192
|
pReachableRule,
|
|
189
193
|
lFromModules,
|
|
190
194
|
);
|
|
191
195
|
}
|
|
192
|
-
return
|
|
196
|
+
return lModule;
|
|
193
197
|
});
|
|
194
198
|
}
|
|
195
199
|
|
|
@@ -199,11 +203,11 @@ export default function deriveReachables(pGraph, pRuleSet) {
|
|
|
199
203
|
if (lReachableRules.length > 0) {
|
|
200
204
|
const lIndexedGraph = new IndexedModuleGraph(pGraph);
|
|
201
205
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
206
|
+
let lResultGraph = structuredClone(pGraph);
|
|
207
|
+
for (const lRule of lReachableRules) {
|
|
208
|
+
lResultGraph = addReachabilityToGraph(lResultGraph, lIndexedGraph, lRule);
|
|
209
|
+
}
|
|
210
|
+
return lResultGraph;
|
|
207
211
|
}
|
|
208
212
|
return pGraph;
|
|
209
213
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import deriveCycles from "./derive/circular.mjs";
|
|
2
2
|
import deriveOrphans from "./derive/orphan/index.mjs";
|
|
3
|
-
import addDependents from "./derive/dependents
|
|
3
|
+
import addDependents from "./derive/dependents.mjs";
|
|
4
4
|
import deriveReachable from "./derive/reachable.mjs";
|
|
5
5
|
import addValidations from "./add-validations.mjs";
|
|
6
6
|
import softenKnownViolations from "./soften-known-violations.mjs";
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
/* eslint-disable no-inline-comments */
|
|
2
|
+
export function isStringLiteral(pArgument) {
|
|
2
3
|
return pArgument.type === "Literal" && typeof pArgument.value === "string";
|
|
3
4
|
}
|
|
4
5
|
|
|
5
|
-
function firstArgumentIsAString(pArgumentsNode) {
|
|
6
|
+
export function firstArgumentIsAString(pArgumentsNode) {
|
|
6
7
|
return (
|
|
7
8
|
pArgumentsNode && pArgumentsNode[0] && isStringLiteral(pArgumentsNode[0])
|
|
8
9
|
);
|
|
9
10
|
}
|
|
10
11
|
|
|
11
|
-
function isPlaceholderLessTemplateLiteral(pArgument) {
|
|
12
|
+
export function isPlaceholderLessTemplateLiteral(pArgument) {
|
|
12
13
|
return (
|
|
13
14
|
pArgument.type === "TemplateLiteral" &&
|
|
14
15
|
pArgument.quasis.length === 1 &&
|
|
@@ -16,7 +17,7 @@ function isPlaceholderLessTemplateLiteral(pArgument) {
|
|
|
16
17
|
);
|
|
17
18
|
}
|
|
18
19
|
|
|
19
|
-
function firstArgumentIsATemplateLiteral(pArgumentsNode) {
|
|
20
|
+
export function firstArgumentIsATemplateLiteral(pArgumentsNode) {
|
|
20
21
|
return (
|
|
21
22
|
pArgumentsNode &&
|
|
22
23
|
pArgumentsNode[0] &&
|
|
@@ -35,19 +36,52 @@ function isMemberCallExpression(pNode, pObjectName, pPropertyName) {
|
|
|
35
36
|
);
|
|
36
37
|
}
|
|
37
38
|
|
|
39
|
+
function isNestedMemberCallExpression(
|
|
40
|
+
pNode,
|
|
41
|
+
pObjectName,
|
|
42
|
+
pSecondObjectName,
|
|
43
|
+
pPropertyName,
|
|
44
|
+
) {
|
|
45
|
+
return (
|
|
46
|
+
pNode.type === "CallExpression" &&
|
|
47
|
+
pNode.callee.type === "MemberExpression" &&
|
|
48
|
+
pNode.callee.object.type === "MemberExpression" &&
|
|
49
|
+
pNode.callee.object.object.type === "Identifier" &&
|
|
50
|
+
pNode.callee.object.object.name === pObjectName && // i.e. globalThis
|
|
51
|
+
pNode.callee.object.property.type === "Identifier" &&
|
|
52
|
+
pNode.callee.object.property.name === pSecondObjectName && // i.e. process
|
|
53
|
+
pNode.callee.property.type === "Identifier" &&
|
|
54
|
+
pNode.callee.property.name === pPropertyName // i.e. getBuiltinModule
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
38
58
|
function isCalleeIdentifier(pNode, pName) {
|
|
39
59
|
return "Identifier" === pNode?.callee?.type && pName === pNode?.callee?.name;
|
|
40
60
|
}
|
|
41
61
|
|
|
42
|
-
function isRequireOfSomeSort(pNode, pName) {
|
|
62
|
+
export function isRequireOfSomeSort(pNode, pName) {
|
|
63
|
+
// prevent doing the pName.split for the common case
|
|
64
|
+
if (pName === "require") {
|
|
65
|
+
return isCalleeIdentifier(pNode, pName);
|
|
66
|
+
}
|
|
67
|
+
|
|
43
68
|
const lRequireStringElements = pName.split(".");
|
|
44
69
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
70
|
+
switch (lRequireStringElements.length) {
|
|
71
|
+
case 1:
|
|
72
|
+
return isCalleeIdentifier(pNode, pName);
|
|
73
|
+
// eslint-disable-next-line no-magic-numbers
|
|
74
|
+
case 2:
|
|
75
|
+
return isMemberCallExpression(pNode, ...lRequireStringElements);
|
|
76
|
+
// eslint-disable-next-line no-magic-numbers
|
|
77
|
+
case 3:
|
|
78
|
+
return isNestedMemberCallExpression(pNode, ...lRequireStringElements);
|
|
79
|
+
default:
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
48
82
|
}
|
|
49
83
|
|
|
50
|
-
function isLikelyAMDDefineOrRequire(pNode) {
|
|
84
|
+
export function isLikelyAMDDefineOrRequire(pNode) {
|
|
51
85
|
return (
|
|
52
86
|
pNode.expression.type === "CallExpression" &&
|
|
53
87
|
pNode.expression.callee.type === "Identifier" &&
|
|
@@ -56,22 +90,10 @@ function isLikelyAMDDefineOrRequire(pNode) {
|
|
|
56
90
|
);
|
|
57
91
|
}
|
|
58
92
|
|
|
59
|
-
function isLikelyAMDDefine(pNode) {
|
|
93
|
+
export function isLikelyAMDDefine(pNode) {
|
|
60
94
|
return (
|
|
61
95
|
pNode.expression.type === "CallExpression" &&
|
|
62
96
|
pNode.expression.callee.type === "Identifier" &&
|
|
63
97
|
pNode.expression.callee.name === "define"
|
|
64
98
|
);
|
|
65
99
|
}
|
|
66
|
-
|
|
67
|
-
export default {
|
|
68
|
-
firstArgumentIsAString,
|
|
69
|
-
firstArgumentIsATemplateLiteral,
|
|
70
|
-
isStringLiteral,
|
|
71
|
-
isPlaceholderlessTemplateLiteral: isPlaceholderLessTemplateLiteral,
|
|
72
|
-
isMemberCallExpression,
|
|
73
|
-
isCalleeIdentifier,
|
|
74
|
-
isRequireOfSomeSort,
|
|
75
|
-
isLikelyAMDDefineOrRequire,
|
|
76
|
-
isLikelyAMDDefine,
|
|
77
|
-
};
|
|
@@ -1,29 +1,35 @@
|
|
|
1
1
|
import { simple as walk_simple, base as walk_base } from "acorn-walk";
|
|
2
2
|
import extractCommonJSDependencies from "./extract-cjs-deps.mjs";
|
|
3
|
-
import
|
|
3
|
+
import {
|
|
4
|
+
isLikelyAMDDefineOrRequire,
|
|
5
|
+
isLikelyAMDDefine,
|
|
6
|
+
} from "./estree-helpers.mjs";
|
|
4
7
|
|
|
5
8
|
function extractRegularAMDDependencies(pNode, pDependencies) {
|
|
6
|
-
if (
|
|
7
|
-
pNode.expression.arguments
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
9
|
+
if (isLikelyAMDDefineOrRequire(pNode)) {
|
|
10
|
+
const lArrayExpressionArguments = pNode.expression.arguments.filter(
|
|
11
|
+
(pArgument) => pArgument.type === "ArrayExpression",
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
for (const lArgument of lArrayExpressionArguments) {
|
|
15
|
+
for (const lElement of lArgument.elements) {
|
|
16
|
+
// eslint-disable-next-line max-depth
|
|
17
|
+
if (lElement.value && typeof lElement.value === "string") {
|
|
18
|
+
pDependencies.push({
|
|
19
|
+
module: lElement.value,
|
|
20
|
+
moduleSystem: "amd",
|
|
21
|
+
dynamic: false,
|
|
22
|
+
exoticallyRequired: false,
|
|
23
|
+
dependencyTypes: ["amd-define"],
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
22
28
|
}
|
|
23
29
|
}
|
|
24
30
|
|
|
25
31
|
function extractCommonJSWrappers(pNode, pDependencies, pExoticRequireStrings) {
|
|
26
|
-
if (
|
|
32
|
+
if (isLikelyAMDDefine(pNode)) {
|
|
27
33
|
pNode.expression.arguments
|
|
28
34
|
.filter(
|
|
29
35
|
(pArgument) =>
|