eslint-plugin-boundaries 3.1.0 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-boundaries",
3
- "version": "3.1.0",
3
+ "version": "3.2.0",
4
4
  "description": "Eslint plugin checking architecture boundaries between elements",
5
5
  "keywords": [
6
6
  "eslint",
@@ -32,21 +32,21 @@
32
32
  },
33
33
  "dependencies": {
34
34
  "chalk": "4.1.2",
35
- "eslint-import-resolver-node": "0.3.6",
35
+ "eslint-import-resolver-node": "0.3.7",
36
36
  "eslint-module-utils": "2.7.4",
37
37
  "is-core-module": "2.11.0",
38
38
  "micromatch": "4.0.5"
39
39
  },
40
40
  "devDependencies": {
41
41
  "cross-env": "7.0.3",
42
- "eslint": "8.29.0",
43
- "eslint-config-prettier": "8.5.0",
42
+ "eslint": "8.37.0",
43
+ "eslint-config-prettier": "8.8.0",
44
44
  "eslint-plugin-prettier": "4.2.1",
45
- "husky": "8.0.2",
45
+ "husky": "8.0.3",
46
46
  "is-ci": "3.0.1",
47
- "jest": "29.3.1",
48
- "lint-staged": "13.0.4",
49
- "prettier": "2.8.0"
47
+ "jest": "29.5.0",
48
+ "lint-staged": "13.2.0",
49
+ "prettier": "2.8.7"
50
50
  },
51
51
  "lint-staged": {
52
52
  "test/**/*.js": "eslint",
@@ -9,10 +9,7 @@ const { isArray } = require("../helpers/utils");
9
9
 
10
10
  const { filesCache, importsCache, elementsCache } = require("./cache");
11
11
 
12
- function baseModule(name, path) {
13
- if (path) {
14
- return null;
15
- }
12
+ function baseModule(name) {
16
13
  if (isScoped(name)) {
17
14
  const [scope, packageName] = name.split("/");
18
15
  return `${scope}/${packageName}`;
@@ -193,6 +190,10 @@ function projectPath(absolutePath) {
193
190
  }
194
191
  }
195
192
 
193
+ function externalModulePath(source, baseModuleValue) {
194
+ return source.replace(baseModuleValue, "");
195
+ }
196
+
196
197
  function importInfo(source, context) {
197
198
  const path = projectPath(resolve(source, context));
198
199
  const isExternalModule = isExternal(source, path);
@@ -205,8 +206,9 @@ function importInfo(source, context) {
205
206
  result = resultCache;
206
207
  } else {
207
208
  elementCache = elementsCache.load(path, context.settings);
209
+ const baseModuleValue = isExternalModule ? baseModule(source) : null;
208
210
  const isBuiltInModule = isBuiltIn(source, path);
209
- const pathToUse = isExternalModule ? null : path;
211
+ const pathToUse = isExternalModule ? externalModulePath(source, baseModuleValue) : path;
210
212
  if (elementCache) {
211
213
  elementResult = elementCache;
212
214
  } else {
@@ -221,7 +223,7 @@ function importInfo(source, context) {
221
223
  isLocal: !isExternalModule && !isBuiltInModule,
222
224
  isBuiltIn: isBuiltInModule,
223
225
  isExternal: isExternalModule,
224
- baseModule: baseModule(source, pathToUse),
226
+ baseModule: baseModuleValue,
225
227
  ...elementResult,
226
228
  };
227
229
 
@@ -11,14 +11,15 @@ const {
11
11
  micromatchPatternReplacingObjectsValues,
12
12
  } = require("../helpers/rules");
13
13
  const { customErrorMessage, ruleElementMessage, elementMessage } = require("../helpers/messages");
14
+ const { isArray } = require("../helpers/utils");
14
15
 
15
- function specifiersMatch(specifiers, options, elementsCapturedValues) {
16
+ function specifiersMatch(specifiers, specifierOptions, elementsCapturedValues) {
16
17
  const importedSpecifiersNames = specifiers
17
18
  .filter((specifier) => {
18
19
  return specifier.type === "ImportSpecifier" && specifier.imported.name;
19
20
  })
20
21
  .map((specifier) => specifier.imported.name);
21
- return options.reduce((found, option) => {
22
+ return specifierOptions.reduce((found, option) => {
22
23
  const matcherWithTemplateReplaced = micromatchPatternReplacingObjectsValues(
23
24
  option,
24
25
  elementsCapturedValues
@@ -30,6 +31,23 @@ function specifiersMatch(specifiers, options, elementsCapturedValues) {
30
31
  }, []);
31
32
  }
32
33
 
34
+ function pathMatch(path, pathOptions, elementsCapturedValues) {
35
+ const pathMatchers = isArray(pathOptions) ? pathOptions : [pathOptions];
36
+ return pathMatchers.reduce((isMatch, option) => {
37
+ if (isMatch) {
38
+ return isMatch;
39
+ }
40
+ const matcherWithTemplateReplaced = micromatchPatternReplacingObjectsValues(
41
+ option,
42
+ elementsCapturedValues
43
+ );
44
+ if (micromatch.some(path, matcherWithTemplateReplaced)) {
45
+ isMatch = true;
46
+ }
47
+ return isMatch;
48
+ }, false);
49
+ }
50
+
33
51
  function isMatchExternalDependency(dependency, matcher, options, elementsCapturedValues) {
34
52
  const matcherWithTemplatesReplaced = micromatchPatternReplacingObjectsValues(
35
53
  matcher,
@@ -37,14 +55,27 @@ function isMatchExternalDependency(dependency, matcher, options, elementsCapture
37
55
  );
38
56
  const isMatch = micromatch.isMatch(dependency.baseModule, matcherWithTemplatesReplaced);
39
57
  if (isMatch && options && Object.keys(options).length) {
40
- const specifiersResult = specifiersMatch(
41
- dependency.specifiers,
42
- options.specifiers,
43
- elementsCapturedValues
44
- );
58
+ const isPathMatch = options.path
59
+ ? pathMatch(dependency.path, options.path, elementsCapturedValues)
60
+ : true;
61
+ if (isPathMatch && options.specifiers) {
62
+ const specifiersResult = specifiersMatch(
63
+ dependency.specifiers,
64
+ options.specifiers,
65
+ elementsCapturedValues
66
+ );
67
+ return {
68
+ result: specifiersResult.length > 0,
69
+ report: {
70
+ specifiers: specifiersResult,
71
+ },
72
+ };
73
+ }
45
74
  return {
46
- result: specifiersResult.length > 0,
47
- report: specifiersResult,
75
+ result: isPathMatch,
76
+ report: {
77
+ path: dependency.path,
78
+ },
48
79
  };
49
80
  }
50
81
  return {
@@ -61,11 +92,20 @@ function elementRulesAllowExternalDependency(element, dependency, options) {
61
92
  });
62
93
  }
63
94
 
95
+ function getErrorReportMessage(report) {
96
+ if (report.path) {
97
+ return report.path;
98
+ }
99
+ return report.specifiers.join(", ");
100
+ }
101
+
64
102
  function errorMessage(ruleData, file, dependency) {
65
103
  const ruleReport = ruleData.ruleReport;
66
104
  if (ruleReport.message) {
67
105
  return customErrorMessage(ruleReport.message, file, dependency, {
68
- specifiers: ruleData.report && ruleData.report.join(", "),
106
+ specifiers:
107
+ ruleData.report && ruleData.report.specifiers && ruleData.report.specifiers.join(", "),
108
+ path: ruleData.report && ruleData.report.path,
69
109
  });
70
110
  }
71
111
  if (ruleReport.isDefault) {
@@ -80,7 +120,7 @@ function errorMessage(ruleData, file, dependency) {
80
120
  )}. Disallowed in rule ${ruleReport.index + 1}`;
81
121
 
82
122
  if (ruleData.report) {
83
- return `Usage of '${ruleData.report.join(", ")}' from external module '${
123
+ return `Usage of '${getErrorReportMessage(ruleData.report)}' from external module '${
84
124
  dependency.baseModule
85
125
  }' ${fileReport}`;
86
126
  }
@@ -101,6 +141,19 @@ module.exports = dependencyRule(
101
141
  type: "string",
102
142
  },
103
143
  },
144
+ path: {
145
+ oneOf: [
146
+ {
147
+ type: "string",
148
+ },
149
+ {
150
+ type: "array",
151
+ items: {
152
+ type: "string",
153
+ },
154
+ },
155
+ ],
156
+ },
104
157
  },
105
158
  additionalProperties: false,
106
159
  },