dependency-cruiser 16.4.1 → 16.4.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.
Files changed (37) hide show
  1. package/package.json +4 -4
  2. package/src/enrich/add-validations.mjs +3 -3
  3. package/src/enrich/derive/folders/index.mjs +2 -2
  4. package/src/enrich/derive/reachable.mjs +6 -3
  5. package/src/enrich/summarize/index.mjs +2 -2
  6. package/src/enrich/summarize/summarize-modules.mjs +2 -2
  7. package/src/extract/acorn/extract.mjs +3 -3
  8. package/src/extract/acorn/parse.mjs +0 -6
  9. package/src/extract/clear-caches.mjs +6 -6
  10. package/src/extract/swc/extract.mjs +3 -5
  11. package/src/extract/swc/parse.mjs +14 -22
  12. package/src/extract/tsc/extract.mjs +4 -4
  13. package/src/extract/tsc/parse.mjs +14 -22
  14. package/src/graph-utl/compare.mjs +10 -14
  15. package/src/graph-utl/consolidate-module-dependencies.mjs +2 -2
  16. package/src/graph-utl/consolidate-modules.mjs +2 -2
  17. package/src/main/options/assert-validity.mjs +2 -2
  18. package/src/main/report-wrap.mjs +4 -4
  19. package/src/meta.cjs +1 -1
  20. package/src/report/dot/index.mjs +6 -12
  21. package/src/report/dot/module-utl.mjs +5 -35
  22. package/src/report/dot/prepare-custom-level.mjs +8 -7
  23. package/src/report/dot/prepare-flat-level.mjs +8 -7
  24. package/src/report/dot/prepare-folder-level.mjs +9 -7
  25. package/src/report/dot/theming.mjs +20 -6
  26. package/src/report/error-html/utl.mjs +2 -11
  27. package/src/report/index.mjs +2 -7
  28. package/src/report/markdown.mjs +5 -3
  29. package/src/utl/regex-util.mjs +2 -7
  30. package/src/validate/index.mjs +14 -17
  31. package/src/validate/match-dependency-rule.mjs +34 -25
  32. package/src/validate/match-folder-dependency-rule.mjs +3 -3
  33. package/src/validate/match-module-rule-helpers.mjs +132 -0
  34. package/src/validate/match-module-rule.mjs +6 -130
  35. package/src/validate/matchers.mjs +22 -38
  36. package/src/validate/rule-classifiers.mjs +0 -2
  37. package/src/validate/violates-required-rule.mjs +8 -4
@@ -1,14 +1,16 @@
1
- import moduleUtl from "./module-utl.mjs";
1
+ import { folderify, extractFirstTransgression, addURL } from "./module-utl.mjs";
2
+ import { applyTheme } from "./theming.mjs";
2
3
  import consolidateToFolder from "#graph-utl/consolidate-to-folder.mjs";
3
- import compare from "#graph-utl/compare.mjs";
4
+ import { compareModules } from "#graph-utl/compare.mjs";
4
5
  import stripSelfTransitions from "#graph-utl/strip-self-transitions.mjs";
6
+ // fuk eslint
5
7
 
6
8
  export default function prepareFolderLevel(pResults, pTheme, _, pShowMetrics) {
7
9
  return consolidateToFolder(pResults.modules)
8
- .sort(compare.modules)
9
- .map(moduleUtl.extractFirstTransgression)
10
- .map(moduleUtl.folderify(pShowMetrics))
10
+ .sort(compareModules)
11
+ .map(extractFirstTransgression)
12
+ .map(folderify(pShowMetrics))
11
13
  .map(stripSelfTransitions)
12
- .map(moduleUtl.applyTheme(pTheme))
13
- .map(moduleUtl.addURL(pResults.summary.optionsUsed?.prefix ?? ""));
14
+ .map(applyTheme(pTheme))
15
+ .map(addURL(pResults.summary.optionsUsed?.prefix ?? ""));
14
16
  }
@@ -1,4 +1,5 @@
1
1
  import DEFAULT_THEME from "./default-theme.mjs";
2
+ import { attributizeObject } from "./module-utl.mjs";
2
3
  import { has, get } from "#utl/object-util.mjs";
3
4
 
4
5
  function matchesRE(pValue, pRE) {
@@ -48,7 +49,7 @@ function moduleOrDependencyMatchesCriteria(pSchemeEntry, pModule) {
48
49
  });
49
50
  }
50
51
 
51
- function determineAttributes(pModuleOrDependency, pAttributeCriteria) {
52
+ export function getThemeAttributes(pModuleOrDependency, pAttributeCriteria) {
52
53
  return (pAttributeCriteria || [])
53
54
  .filter((pSchemeEntry) =>
54
55
  moduleOrDependencyMatchesCriteria(pSchemeEntry, pModuleOrDependency),
@@ -57,7 +58,7 @@ function determineAttributes(pModuleOrDependency, pAttributeCriteria) {
57
58
  .reduce((pAll, pCurrent) => ({ ...pCurrent, ...pAll }), {});
58
59
  }
59
60
 
60
- function normalizeTheme(pTheme) {
61
+ export function normalizeTheme(pTheme) {
61
62
  let lReturnValue = structuredClone(DEFAULT_THEME);
62
63
 
63
64
  if (pTheme) {
@@ -78,7 +79,20 @@ function normalizeTheme(pTheme) {
78
79
  return lReturnValue;
79
80
  }
80
81
 
81
- export default {
82
- normalizeTheme,
83
- determineAttributes,
84
- };
82
+ export function applyTheme(pTheme) {
83
+ return (pModule) => ({
84
+ ...pModule,
85
+ dependencies: pModule.dependencies
86
+ .map((pDependency) => ({
87
+ ...pDependency,
88
+ themeAttrs: attributizeObject(
89
+ getThemeAttributes(pDependency, pTheme.dependencies),
90
+ ),
91
+ }))
92
+ .map((pDependency) => ({
93
+ ...pDependency,
94
+ hasExtraAttributes: Boolean(pDependency.rule || pDependency.themeAttrs),
95
+ })),
96
+ themeAttrs: attributizeObject(getThemeAttributes(pModule, pTheme.modules)),
97
+ });
98
+ }
@@ -1,7 +1,7 @@
1
1
  import { formatViolation, formatPercentage } from "../utl/index.mjs";
2
2
  import meta from "#meta.cjs";
3
3
 
4
- function getFormattedAllowedRule(pRuleSetUsed) {
4
+ export function getFormattedAllowedRule(pRuleSetUsed) {
5
5
  const lAllowed = pRuleSetUsed?.allowed ?? [];
6
6
  const lCommentedRule = lAllowed.find((pRule) =>
7
7
  Object.hasOwn(pRule, "comment"),
@@ -17,7 +17,7 @@ function getFormattedAllowedRule(pRuleSetUsed) {
17
17
  : [];
18
18
  }
19
19
 
20
- function mergeCountsIntoRule(pRule, pViolationCounts) {
20
+ export function mergeCountsIntoRule(pRule, pViolationCounts) {
21
21
  const lCounts = pViolationCounts[pRule.name]
22
22
  ? pViolationCounts[pRule.name]
23
23
  : { count: 0, ignoredCount: 0 };
@@ -138,12 +138,3 @@ export function aggregateViolations(pViolations, pRuleSetUsed) {
138
138
  pFirst.name.localeCompare(pSecond.name),
139
139
  );
140
140
  }
141
-
142
- export default {
143
- aggregateViolations,
144
- getFormattedAllowedRule,
145
- mergeCountsIntoRule,
146
- formatSummaryForReport,
147
- determineFromExtras,
148
- determineTo,
149
- };
@@ -35,7 +35,7 @@ const TYPE2MODULE = new Map([
35
35
  * an options object (specific to that function)
36
36
  * and returns an IReporterOutput
37
37
  */
38
- async function getReporter(pOutputType) {
38
+ export async function getReporter(pOutputType) {
39
39
  let lReturnValue = {};
40
40
  if (pOutputType?.startsWith("plugin:")) {
41
41
  lReturnValue = await getExternalPluginReporter(pOutputType);
@@ -52,11 +52,6 @@ async function getReporter(pOutputType) {
52
52
  *
53
53
  * @returns {import("../../types/shared-types.js").OutputType[]} -
54
54
  */
55
- function getAvailableReporters() {
55
+ export function getAvailableReporters() {
56
56
  return Array.from(TYPE2MODULE.keys());
57
57
  }
58
-
59
- export default {
60
- getAvailableReporters,
61
- getReporter,
62
- };
@@ -1,8 +1,10 @@
1
- import errorHtmlUtl from "./error-html/utl.mjs";
1
+ import {
2
+ aggregateViolations,
3
+ determineTo,
4
+ determineFromExtras,
5
+ } from "./error-html/utl.mjs";
2
6
  import meta from "#meta.cjs";
3
7
 
4
- const { aggregateViolations, determineTo, determineFromExtras } = errorHtmlUtl;
5
-
6
8
  const REPORT_DEFAULTS = {
7
9
  showTitle: true,
8
10
  title: "## Forbidden dependency check - results",
@@ -23,7 +23,7 @@ export function extractGroups(pFromRestriction, pActualPath) {
23
23
 
24
24
  if (lMatchResult && lMatchResult.length > 1) {
25
25
  lReturnValue = lMatchResult.filter(
26
- (pResult) => typeof pResult === "string"
26
+ (pResult) => typeof pResult === "string",
27
27
  );
28
28
  }
29
29
  }
@@ -51,11 +51,6 @@ export function replaceGroupPlaceholders(pString, pExtractedGroups) {
51
51
  (pAll, pThis, pIndex) =>
52
52
  // eslint-disable-next-line security/detect-non-literal-regexp
53
53
  pAll.replace(new RegExp(`\\$${pIndex}`, "g"), pThis),
54
- pString
54
+ pString,
55
55
  );
56
56
  }
57
-
58
- export default {
59
- extractGroups,
60
- replaceGroupPlaceholders,
61
- };
@@ -89,22 +89,19 @@ function validateAgainstRules(pRuleSet, pFrom, pTo, pMatchModule) {
89
89
  }
90
90
  return lReturnValue;
91
91
  }
92
+ export function validateModule(pRuleSet, pModule) {
93
+ return validateAgainstRules(pRuleSet, pModule, {}, matchModuleRule);
94
+ }
92
95
 
93
- export default {
94
- module: function module(pRuleSet, pModule) {
95
- return validateAgainstRules(pRuleSet, pModule, {}, matchModuleRule);
96
- },
97
-
98
- dependency: function dependency(pRuleSet, pFrom, pTo) {
99
- return validateAgainstRules(pRuleSet, pFrom, pTo, matchDependencyRule);
100
- },
96
+ export function validateDependency(pRuleSet, pFrom, pTo) {
97
+ return validateAgainstRules(pRuleSet, pFrom, pTo, matchDependencyRule);
98
+ }
101
99
 
102
- folder: function folder(pRuleSet, pFromFolder, pToFolder) {
103
- return validateAgainstRules(
104
- pRuleSet,
105
- pFromFolder,
106
- pToFolder,
107
- matchFolderRule,
108
- );
109
- },
110
- };
100
+ export function validateFolder(pRuleSet, pFromFolder, pToFolder) {
101
+ return validateAgainstRules(
102
+ pRuleSet,
103
+ pFromFolder,
104
+ pToFolder,
105
+ matchFolderRule,
106
+ );
107
+ }
@@ -1,6 +1,20 @@
1
1
  // @ts-check
2
2
  import { isModuleOnlyRule, isFolderScope } from "./rule-classifiers.mjs";
3
- import matchers from "./matchers.mjs";
3
+ import {
4
+ propertyEquals,
5
+ propertyMatches,
6
+ propertyMatchesNot,
7
+ matchesFromPath,
8
+ matchesFromPathNot,
9
+ matchesToPath,
10
+ matchesToPathNot,
11
+ matchesToDependencyTypes,
12
+ matchesToDependencyTypesNot,
13
+ matchesToVia,
14
+ matchesToViaOnly,
15
+ matchesToIsMoreUnstable,
16
+ matchesMoreThanOneDependencyType,
17
+ } from "./matchers.mjs";
4
18
  import { extractGroups } from "#utl/regex-util.mjs";
5
19
 
6
20
  /**
@@ -15,34 +29,29 @@ function match(pFrom, pTo) {
15
29
  const lGroups = extractGroups(pRule.from, pFrom.source);
16
30
 
17
31
  return (
18
- matchers.fromPath(pRule, pFrom) &&
19
- matchers.fromPathNot(pRule, pFrom) &&
20
- matchers.toPath(pRule, pTo, lGroups) &&
21
- matchers.toPathNot(pRule, pTo, lGroups) &&
22
- matchers.toDependencyTypes(pRule, pTo) &&
23
- matchers.toDependencyTypesNot(pRule, pTo) &&
24
- matchers.matchesMoreThanOneDependencyType(pRule, pTo) &&
32
+ matchesFromPath(pRule, pFrom) &&
33
+ matchesFromPathNot(pRule, pFrom) &&
34
+ matchesToPath(pRule, pTo, lGroups) &&
35
+ matchesToPathNot(pRule, pTo, lGroups) &&
36
+ matchesToDependencyTypes(pRule, pTo) &&
37
+ matchesToDependencyTypesNot(pRule, pTo) &&
38
+ matchesMoreThanOneDependencyType(pRule, pTo) &&
25
39
  // preCompilationOnly is not a mandatory attribute, but if the attribute
26
40
  // is in the rule but not in the dependency there won't be a match
27
41
  // anyway, so we can use the default propertyEquals method regardless
28
- matchers.propertyEquals(pRule, pTo, "preCompilationOnly") &&
42
+ propertyEquals(pRule, pTo, "preCompilationOnly") &&
29
43
  // couldNotResolve, circular, dynamic and exoticallyRequired _are_ mandatory
30
- matchers.propertyEquals(pRule, pTo, "couldNotResolve") &&
31
- matchers.propertyEquals(pRule, pTo, "circular") &&
32
- matchers.propertyEquals(pRule, pTo, "dynamic") &&
33
- matchers.propertyEquals(pRule, pTo, "exoticallyRequired") &&
34
- matchers.propertyMatches(pRule, pTo, "license", "license") &&
35
- matchers.propertyMatchesNot(pRule, pTo, "licenseNot", "license") &&
36
- matchers.propertyMatches(pRule, pTo, "exoticRequire", "exoticRequire") &&
37
- matchers.propertyMatchesNot(
38
- pRule,
39
- pTo,
40
- "exoticRequireNot",
41
- "exoticRequire",
42
- ) &&
43
- matchers.toVia(pRule, pTo, lGroups) &&
44
- matchers.toViaOnly(pRule, pTo, lGroups) &&
45
- matchers.toIsMoreUnstable(pRule, pFrom, pTo)
44
+ propertyEquals(pRule, pTo, "couldNotResolve") &&
45
+ propertyEquals(pRule, pTo, "circular") &&
46
+ propertyEquals(pRule, pTo, "dynamic") &&
47
+ propertyEquals(pRule, pTo, "exoticallyRequired") &&
48
+ propertyMatches(pRule, pTo, "license", "license") &&
49
+ propertyMatchesNot(pRule, pTo, "licenseNot", "license") &&
50
+ propertyMatches(pRule, pTo, "exoticRequire", "exoticRequire") &&
51
+ propertyMatchesNot(pRule, pTo, "exoticRequireNot", "exoticRequire") &&
52
+ matchesToVia(pRule, pTo, lGroups) &&
53
+ matchesToViaOnly(pRule, pTo, lGroups) &&
54
+ matchesToIsMoreUnstable(pRule, pFrom, pTo)
46
55
  );
47
56
  };
48
57
  }
@@ -1,5 +1,5 @@
1
1
  import { isModuleOnlyRule, isFolderScope } from "./rule-classifiers.mjs";
2
- import matchers from "./matchers.mjs";
2
+ import { propertyEquals, matchesToIsMoreUnstable } from "./matchers.mjs";
3
3
  import { extractGroups, replaceGroupPlaceholders } from "#utl/regex-util.mjs";
4
4
 
5
5
  function fromFolderPath(pRule, pFromFolder) {
@@ -44,8 +44,8 @@ function match(pFromFolder, pToFolder) {
44
44
  fromFolderPathNot(pRule, pFromFolder) &&
45
45
  toFolderPath(pRule, pToFolder, lGroups) &&
46
46
  toFolderPathNot(pRule, pToFolder, lGroups) &&
47
- matchers.toIsMoreUnstable(pRule, pFromFolder, pToFolder) &&
48
- matchers.propertyEquals(pRule, pToFolder, "circular")
47
+ matchesToIsMoreUnstable(pRule, pFromFolder, pToFolder) &&
48
+ propertyEquals(pRule, pToFolder, "circular")
49
49
  );
50
50
  };
51
51
  }
@@ -0,0 +1,132 @@
1
+ import {
2
+ matchToModulePath,
3
+ matchToModulePathNot,
4
+ matchesFromPath,
5
+ matchesFromPathNot,
6
+ matchesModulePath,
7
+ matchesModulePathNot,
8
+ } from "./matchers.mjs";
9
+ import { extractGroups } from "#utl/regex-util.mjs";
10
+ /**
11
+ * Returns true if pRule is an orphan rule and pModule is an orphan.
12
+ * Returns false in all other cases
13
+ *
14
+ * @param {import("../../types/rule-set.mjs").IAnyRuleType} pRule
15
+ * @param {import("../../types/cruise-result.mjs").IModule} pModule
16
+ * @returns {boolean}
17
+ */
18
+ export function matchesOrphanRule(pRule, pModule) {
19
+ return (
20
+ Object.hasOwn(pRule?.from ?? {}, "orphan") &&
21
+ // @ts-expect-error the 'hasOwn' above guarantees there's a 'from.orphan' attribute
22
+ pModule.orphan === pRule.from.orphan &&
23
+ matchesFromPath(pRule, pModule) &&
24
+ matchesFromPathNot(pRule, pModule)
25
+ );
26
+ }
27
+
28
+ /**
29
+ * Returns true if pRule is a 'reachable' rule and pModule matches the reachability
30
+ * criteria.
31
+ * Returns false in all other cases
32
+ *
33
+ * @param {import("../../types/rule-set.mjs").IAnyRuleType} pRule
34
+ * @param {import("../../types/cruise-result.mjs").IModule} pModule
35
+ * @returns {boolean}
36
+ */
37
+ export function matchesReachableRule(pRule, pModule) {
38
+ if (
39
+ Object.hasOwn(pRule?.to ?? {}, "reachable") &&
40
+ Object.hasOwn(pModule, "reachable")
41
+ ) {
42
+ // @ts-expect-error the 'hasOwn' above ensures the 'reachable' exists
43
+ const lReachableRecord = pModule.reachable.find(
44
+ (pReachable) =>
45
+ pReachable.asDefinedInRule === pRule.name &&
46
+ // @ts-expect-error the 'hasOwn' above ensures the 'to.reachable' exists
47
+ pReachable.value === pRule.to.reachable,
48
+ );
49
+ if (lReachableRecord) {
50
+ const lGroups = extractGroups(pRule.from, lReachableRecord.matchedFrom);
51
+
52
+ return (
53
+ matchToModulePath(pRule, pModule, lGroups) &&
54
+ matchToModulePathNot(pRule, pModule, lGroups)
55
+ );
56
+ }
57
+ }
58
+ return false;
59
+ }
60
+
61
+ /**
62
+ * Returns true if pRule is a 'reaches' rule and pModule matches the reachability
63
+ * criteria.
64
+ * Returns false in all other cases
65
+ *
66
+ * @param {import("../../types/rule-set.mjs").IAnyRuleType} pRule
67
+ * @param {import("../../types/cruise-result.mjs").IModule} pModule
68
+ * @returns {boolean}
69
+ */
70
+ export function matchesReachesRule(pRule, pModule) {
71
+ return (
72
+ Object.hasOwn(pRule?.to ?? {}, "reachable") &&
73
+ Object.hasOwn(pModule, "reaches") &&
74
+ // @ts-expect-error the 'hasOwn' above guarantees the .reaches exists
75
+ pModule.reaches.some(
76
+ (pReaches) =>
77
+ pReaches.asDefinedInRule === pRule.name &&
78
+ pReaches.modules.some(
79
+ (pReachesModule) =>
80
+ matchToModulePath(pRule, pReachesModule) &&
81
+ matchToModulePathNot(pRule, pReachesModule),
82
+ ),
83
+ )
84
+ );
85
+ }
86
+ /**
87
+ *
88
+ * @param {import("../../types/rule-set.mjs").IAnyRuleType} pRule
89
+ * @param {string[]} pDependents
90
+ * @returns {boolean}
91
+ */
92
+ function dependentsCountsMatch(pRule, pDependents) {
93
+ const lMatchingDependentsCount = pDependents.filter(
94
+ (pDependent) =>
95
+ Boolean(!pRule.from.path || pDependent.match(pRule.from.path)) &&
96
+ Boolean(!pRule.from.pathNot || !pDependent.match(pRule.from.pathNot)),
97
+ ).length;
98
+ return (
99
+ (!pRule.module.numberOfDependentsLessThan ||
100
+ lMatchingDependentsCount < pRule.module.numberOfDependentsLessThan) &&
101
+ (!pRule.module.numberOfDependentsMoreThan ||
102
+ lMatchingDependentsCount > pRule.module.numberOfDependentsMoreThan)
103
+ );
104
+ }
105
+
106
+ /**
107
+ *
108
+ * @param {import("../../types/rule-set.mjs").IAnyRuleType} pRule
109
+ * @param {import("../../types/cruise-result.mjs").IModule} pModule
110
+ * @returns {boolean}
111
+ */
112
+ // eslint-disable-next-line complexity
113
+ export function matchesDependentsRule(pRule, pModule) {
114
+ if (
115
+ (Object.hasOwn(pModule, "dependents") &&
116
+ Object.hasOwn(pRule?.module ?? {}, "numberOfDependentsLessThan")) ||
117
+ Object.hasOwn(pRule?.module ?? {}, "numberOfDependentsMoreThan")
118
+ ) {
119
+ return (
120
+ // group matching seems like a nice idea, however, the 'from' part of the
121
+ // rule is going to match not one module (as with regular dependency rules)
122
+ // but a whole bunch of them, being the 'dependents'. So that match is going
123
+ // to produce not one result, but one per matching dependent. To get meaningful
124
+ // results we'd probably have to loop over these and or the
125
+ // matchToModulePath together.
126
+ matchesModulePath(pRule, pModule) &&
127
+ matchesModulePathNot(pRule, pModule) &&
128
+ dependentsCountsMatch(pRule, pModule.dependents)
129
+ );
130
+ }
131
+ return false;
132
+ }
@@ -1,130 +1,10 @@
1
1
  import { isModuleOnlyRule, isFolderScope } from "./rule-classifiers.mjs";
2
- import matchers from "./matchers.mjs";
3
- import { extractGroups } from "#utl/regex-util.mjs";
4
-
5
- /**
6
- * Returns true if pRule is an orphan rule and pModule is an orphan.
7
- * Returns false in all other cases
8
- *
9
- * @param {import("../../types/rule-set.mjs").IAnyRuleType} pRule
10
- * @param {import("../../types/cruise-result.mjs").IModule} pModule
11
- * @returns {boolean}
12
- */
13
- function matchesOrphanRule(pRule, pModule) {
14
- return (
15
- Object.hasOwn(pRule?.from ?? {}, "orphan") &&
16
- // @ts-expect-error the 'hasOwn' above guarantees there's a 'from.orphan' attribute
17
- pModule.orphan === pRule.from.orphan &&
18
- matchers.fromPath(pRule, pModule) &&
19
- matchers.fromPathNot(pRule, pModule)
20
- );
21
- }
22
-
23
- /**
24
- * Returns true if pRule is a 'reachable' rule and pModule matches the reachability
25
- * criteria.
26
- * Returns false in all other cases
27
- *
28
- * @param {import("../../types/rule-set.mjs").IAnyRuleType} pRule
29
- * @param {import("../../types/cruise-result.mjs").IModule} pModule
30
- * @returns {boolean}
31
- */
32
- function matchesReachableRule(pRule, pModule) {
33
- if (
34
- Object.hasOwn(pRule?.to ?? {}, "reachable") &&
35
- Object.hasOwn(pModule, "reachable")
36
- ) {
37
- // @ts-expect-error the 'hasOwn' above ensures the 'reachable' exists
38
- const lReachableRecord = pModule.reachable.find(
39
- (pReachable) =>
40
- pReachable.asDefinedInRule === pRule.name &&
41
- // @ts-expect-error the 'hasOwn' above ensures the 'to.reachable' exists
42
- pReachable.value === pRule.to.reachable,
43
- );
44
- if (lReachableRecord) {
45
- const lGroups = extractGroups(pRule.from, lReachableRecord.matchedFrom);
46
-
47
- return (
48
- matchers.toModulePath(pRule, pModule, lGroups) &&
49
- matchers.toModulePathNot(pRule, pModule, lGroups)
50
- );
51
- }
52
- }
53
- return false;
54
- }
55
-
56
- /**
57
- * Returns true if pRule is a 'reaches' rule and pModule matches the reachability
58
- * criteria.
59
- * Returns false in all other cases
60
- *
61
- * @param {import("../../types/rule-set.mjs").IAnyRuleType} pRule
62
- * @param {import("../../types/cruise-result.mjs").IModule} pModule
63
- * @returns {boolean}
64
- */
65
- function matchesReachesRule(pRule, pModule) {
66
- return (
67
- Object.hasOwn(pRule?.to ?? {}, "reachable") &&
68
- Object.hasOwn(pModule, "reaches") &&
69
- // @ts-expect-error the 'hasOwn' above guarantees the .reaches exists
70
- pModule.reaches.some(
71
- (pReaches) =>
72
- pReaches.asDefinedInRule === pRule.name &&
73
- pReaches.modules.some(
74
- (pReachesModule) =>
75
- matchers.toModulePath(pRule, pReachesModule) &&
76
- matchers.toModulePathNot(pRule, pReachesModule),
77
- ),
78
- )
79
- );
80
- }
81
- /**
82
- *
83
- * @param {import("../../types/rule-set.mjs").IAnyRuleType} pRule
84
- * @param {string[]} pDependents
85
- * @returns {boolean}
86
- */
87
- function dependentsCountsMatch(pRule, pDependents) {
88
- const lMatchingDependentsCount = pDependents.filter(
89
- (pDependent) =>
90
- Boolean(!pRule.from.path || pDependent.match(pRule.from.path)) &&
91
- Boolean(!pRule.from.pathNot || !pDependent.match(pRule.from.pathNot)),
92
- ).length;
93
- return (
94
- (!pRule.module.numberOfDependentsLessThan ||
95
- lMatchingDependentsCount < pRule.module.numberOfDependentsLessThan) &&
96
- (!pRule.module.numberOfDependentsMoreThan ||
97
- lMatchingDependentsCount > pRule.module.numberOfDependentsMoreThan)
98
- );
99
- }
100
-
101
- /**
102
- *
103
- * @param {import("../../types/rule-set.mjs").IAnyRuleType} pRule
104
- * @param {import("../../types/cruise-result.mjs").IModule} pModule
105
- * @returns {boolean}
106
- */
107
- // eslint-disable-next-line complexity
108
- function matchesDependentsRule(pRule, pModule) {
109
- if (
110
- (Object.hasOwn(pModule, "dependents") &&
111
- Object.hasOwn(pRule?.module ?? {}, "numberOfDependentsLessThan")) ||
112
- Object.hasOwn(pRule?.module ?? {}, "numberOfDependentsMoreThan")
113
- ) {
114
- return (
115
- // group matching seems like a nice idea, however, the 'from' part of the
116
- // rule is going to match not one module (as with regular dependency rules)
117
- // but a whole bunch of them, being the 'dependents'. So that match is going
118
- // to produce not one result, but one per matching dependent. To get meaningful
119
- // results we'd probably have to loop over these and or the
120
- // matchers.toModulePath together.
121
- matchers.modulePath(pRule, pModule) &&
122
- matchers.modulePathNot(pRule, pModule) &&
123
- dependentsCountsMatch(pRule, pModule.dependents)
124
- );
125
- }
126
- return false;
127
- }
2
+ import {
3
+ matchesOrphanRule,
4
+ matchesReachableRule,
5
+ matchesReachesRule,
6
+ matchesDependentsRule,
7
+ } from "./match-module-rule-helpers.mjs";
128
8
 
129
9
  /**
130
10
  *
@@ -148,10 +28,6 @@ const isInteresting = (pRule) =>
148
28
  isModuleOnlyRule(pRule) && !isFolderScope(pRule);
149
29
 
150
30
  export default {
151
- matchesOrphanRule,
152
- matchesReachableRule,
153
- matchesReachesRule,
154
- matchesDependentsRule,
155
31
  match,
156
32
  isInteresting,
157
33
  };