@boundaries/eslint-plugin 5.3.0 → 5.4.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.
@@ -16,7 +16,7 @@ export declare function getElementsMatcher(settings: SettingsNormalized): Matche
16
16
  export declare function getSpecifiers(node: Rule.Node): string[];
17
17
  /**
18
18
  * Returns the description of the current file being linted
19
- * @param fileName The file name
19
+ * @param fileName The file name (absolute path)
20
20
  * @param settings The ESLint rule context settings normalized
21
21
  * @returns The description of the current file being linted
22
22
  */
@@ -35,7 +35,7 @@ export declare function dependencyDescription({ node, kind, nodeKind, }: {
35
35
  /** The kind of the node generating the dependency */
36
36
  nodeKind?: string;
37
37
  },
38
- /** The file name */
38
+ /** The file name (absolute path) */
39
39
  fileName: string,
40
40
  /** The ESLint rule context settings normalized */
41
41
  settings: SettingsNormalized,
@@ -22,30 +22,11 @@ function getElementsMatcher(settings) {
22
22
  includePaths: settings.includePaths,
23
23
  legacyTemplates: settings.legacyTemplates,
24
24
  cache: settings.cache,
25
+ flagAsExternal: settings.flagAsExternal,
26
+ rootPath: settings.rootPath,
25
27
  });
26
28
  return elementsMatcher;
27
29
  }
28
- /**
29
- * Replaces backslashes with forward slashes in a given path
30
- * @param filePath The file path to modify
31
- * @returns The modified file path with forward slashes
32
- */
33
- function replacePathSlashes(filePath) {
34
- return filePath.replaceAll("\\", "/");
35
- }
36
- /**
37
- * Transforms an absolute path into a project-relative path
38
- * @param absolutePath The absolute path to transform
39
- * @param rootPath The root path of the project
40
- * @returns The relative path from the project root
41
- */
42
- function projectPath(absolutePath, rootPath) {
43
- if (absolutePath) {
44
- // TODO: Use path.relative when possible. With caution because this would break current external paths
45
- return replacePathSlashes(absolutePath).replace(`${replacePathSlashes(rootPath)}/`, "");
46
- }
47
- return "";
48
- }
49
30
  /**
50
31
  * Returns the specifiers used in an import or export statement
51
32
  * @param node The AST node representing the import or export
@@ -69,14 +50,13 @@ function getSpecifiers(node) {
69
50
  }
70
51
  /**
71
52
  * Returns the description of the current file being linted
72
- * @param fileName The file name
53
+ * @param fileName The file name (absolute path)
73
54
  * @param settings The ESLint rule context settings normalized
74
55
  * @returns The description of the current file being linted
75
56
  */
76
57
  function elementDescription(fileName, settings) {
77
58
  const matcher = getElementsMatcher(settings);
78
- const path = projectPath(fileName, settings.rootPath);
79
- const result = matcher.describeElement(path);
59
+ const result = matcher.describeElement(fileName);
80
60
  (0, Support_1.debugDescription)(result);
81
61
  return result;
82
62
  }
@@ -87,7 +67,7 @@ function elementDescription(fileName, settings) {
87
67
  * @returns The description of the dependency node
88
68
  */
89
69
  function dependencyDescription({ node, kind, nodeKind, },
90
- /** The file name */
70
+ /** The file name (absolute path) */
91
71
  fileName,
92
72
  /** The ESLint rule context settings normalized */
93
73
  settings,
@@ -95,9 +75,10 @@ settings,
95
75
  context) {
96
76
  const source = String(node.value);
97
77
  const matcher = getElementsMatcher(settings);
78
+ const resolvedPath = (0, resolve_1.default)(source, context);
98
79
  const description = matcher.describeDependency({
99
- from: projectPath(fileName, settings.rootPath),
100
- to: projectPath((0, resolve_1.default)(source, context), settings.rootPath),
80
+ from: fileName,
81
+ to: resolvedPath || undefined,
101
82
  source,
102
83
  kind: kind || "value", // TODO: Change by runtime in a backwards compatible way
103
84
  nodeKind,
@@ -1,5 +1,5 @@
1
1
  import type { DependencyKind } from "@boundaries/elements";
2
- export type { DependencyKind, CapturedValuesSelector, ElementSelector, ElementSelectors, ElementsSelector, ExternalLibrarySelectorOptions, ExternalLibrarySelectorWithOptions, ExternalLibrarySelector, ExternalLibrarySelectors, ExternalLibrariesSelector, ElementSelectorWithOptions, } from "@boundaries/elements";
2
+ export type { DependencyKind, CapturedValuesSelector, ElementSelector, ElementSelectors, ElementsSelector, ExternalLibrarySelectorOptions, ExternalLibrarySelectorWithOptions, ExternalLibrarySelector, ExternalLibrarySelectors, ExternalLibrariesSelector, ElementSelectorWithOptions, FlagAsExternalOptions, } from "@boundaries/elements";
3
3
  export { isElementSelector, isElementsSelector, isExternalLibrarySelector, isExternalLibrariesSelector, } from "@boundaries/elements";
4
4
  export type { RulePolicy, RuleBaseOptions, ElementTypesRule, ElementTypesRuleOptions, EntryPointRule, EntryPointRuleOptions, ExternalRule, ExternalRuleOptions, NoPrivateOptions, RuleShortName, RuleName, } from "../Settings";
5
5
  export { RULE_POLICIES_MAP, isRulePolicy, RULE_SHORT_NAMES_MAP, RULE_NAMES_MAP, isRuleShortName, isRuleName, } from "../Settings";
@@ -6,12 +6,6 @@ const Settings_1 = require("../../Settings");
6
6
  const Support_1 = require("../../Support");
7
7
  const Helpers_1 = require("./Helpers");
8
8
  const { ADDITIONAL_DEPENDENCY_NODES } = Settings_1.SETTINGS;
9
- function optionsHaveRules(options) {
10
- if (!options) {
11
- return false;
12
- }
13
- return Boolean(options.rules);
14
- }
15
9
  function dependencyRule(ruleMeta, rule, ruleOptions = {}) {
16
10
  return {
17
11
  ...(0, Helpers_1.meta)(ruleMeta),
@@ -22,9 +16,6 @@ function dependencyRule(ruleMeta, rule, ruleOptions = {}) {
22
16
  if (ruleOptions.validate !== false && !options) {
23
17
  return {};
24
18
  }
25
- if (ruleOptions.validate !== false && optionsHaveRules(options)) {
26
- (0, Settings_1.validateRules)(settings, options.rules, ruleOptions.validateRules);
27
- }
28
19
  // TODO: Remove this check when allowing to select by any other property
29
20
  if (file.isIgnored || !file.type) {
30
21
  return {};
@@ -1,4 +1,4 @@
1
- import type { DependencyKind, ElementDescriptors, ElementsSelector, CapturedValues, ExternalLibrariesSelector } from "@boundaries/elements";
1
+ import type { DependencyKind, ElementDescriptors, ElementsSelector, CapturedValues, ExternalLibrariesSelector, FlagAsExternalOptions } from "@boundaries/elements";
2
2
  import type { ESLint, Linter, Rule } from "eslint";
3
3
  export declare const PLUGIN_NAME: "boundaries";
4
4
  export declare const PLUGIN_ENV_VARS_PREFIX: "ESLINT_PLUGIN_BOUNDARIES";
@@ -116,6 +116,7 @@ export declare const SETTINGS: {
116
116
  readonly ADDITIONAL_DEPENDENCY_NODES: "boundaries/additional-dependency-nodes";
117
117
  readonly LEGACY_TEMPLATES: "boundaries/legacy-templates";
118
118
  readonly CACHE: "boundaries/cache";
119
+ readonly FLAG_AS_EXTERNAL: "boundaries/flag-as-external";
119
120
  readonly DEBUG: "ESLINT_PLUGIN_BOUNDARIES_DEBUG";
120
121
  readonly ENV_ROOT_PATH: "ESLINT_PLUGIN_BOUNDARIES_ROOT_PATH";
121
122
  readonly RULE_ELEMENT_TYPES: "boundaries/element-types";
@@ -176,6 +177,7 @@ export declare const SETTINGS_KEYS_MAP: {
176
177
  /** @deprecated Use import/resolver settings instead */
177
178
  readonly ALIAS: "boundaries/alias";
178
179
  readonly CACHE: "boundaries/cache";
180
+ readonly FLAG_AS_EXTERNAL: "boundaries/flag-as-external";
179
181
  };
180
182
  /**
181
183
  * Default value for the legacy templates setting.
@@ -259,6 +261,8 @@ export type Settings = {
259
261
  [SETTINGS_KEYS_MAP.ALIAS]?: AliasSetting;
260
262
  /** Whether to enable caching for the plugin analysis */
261
263
  [SETTINGS_KEYS_MAP.CACHE]?: boolean;
264
+ /** Configuration for categorizing dependencies as external or local */
265
+ [SETTINGS_KEYS_MAP.FLAG_AS_EXTERNAL]?: FlagAsExternalOptions;
262
266
  };
263
267
  /**
264
268
  * Normalized settings for the eslint-plugin-boundaries plugin.
@@ -281,6 +285,8 @@ export type SettingsNormalized = {
281
285
  legacyTemplates: boolean;
282
286
  /** Whether caching is enabled */
283
287
  cache: boolean;
288
+ /** Configuration for categorizing dependencies as external or local */
289
+ flagAsExternal: FlagAsExternalOptions;
284
290
  };
285
291
  /**
286
292
  * Eslint boundaries plugin rules.
@@ -96,6 +96,7 @@ exports.SETTINGS = {
96
96
  ADDITIONAL_DEPENDENCY_NODES: `${exports.PLUGIN_NAME}/additional-dependency-nodes`,
97
97
  LEGACY_TEMPLATES: `${exports.PLUGIN_NAME}/legacy-templates`,
98
98
  CACHE: `${exports.PLUGIN_NAME}/cache`,
99
+ FLAG_AS_EXTERNAL: `${exports.PLUGIN_NAME}/flag-as-external`,
99
100
  // env vars
100
101
  DEBUG: `${exports.PLUGIN_ENV_VARS_PREFIX}_DEBUG`,
101
102
  ENV_ROOT_PATH: `${exports.PLUGIN_ENV_VARS_PREFIX}_ROOT_PATH`,
@@ -177,6 +178,7 @@ exports.SETTINGS_KEYS_MAP = {
177
178
  /** @deprecated Use import/resolver settings instead */
178
179
  ALIAS: exports.SETTINGS.ALIAS,
179
180
  CACHE: exports.SETTINGS.CACHE,
181
+ FLAG_AS_EXTERNAL: exports.SETTINGS.FLAG_AS_EXTERNAL,
180
182
  };
181
183
  /**
182
184
  * Default value for the legacy templates setting.
@@ -1,6 +1,6 @@
1
- import type { ElementsSelector, ExternalLibrariesSelector, ElementDescriptor } from "@boundaries/elements";
1
+ import type { ElementDescriptor } from "@boundaries/elements";
2
2
  import type { Rule } from "eslint";
3
- import type { Settings, RuleMainKey, ValidateRulesOptions, RuleOptionsRules, SettingsNormalized } from "./Settings.types";
3
+ import type { Settings, RuleMainKey, SettingsNormalized } from "./Settings.types";
4
4
  export declare function elementsMatcherSchema(matcherOptions?: Record<string, unknown>): {
5
5
  oneOf: ({
6
6
  type: string;
@@ -125,7 +125,6 @@ export declare function rulesOptionsSchema(options?: {
125
125
  };
126
126
  additionalProperties: boolean;
127
127
  }[];
128
- export declare function validateElementTypesMatcher(elementsMatcher: ElementsSelector | ExternalLibrariesSelector, settings: SettingsNormalized): void;
129
128
  export declare function isValidElementAssigner(element: unknown): element is ElementDescriptor;
130
129
  export declare function validateSettings(settings: Rule.RuleContext["settings"]): Settings;
131
130
  /**
@@ -134,4 +133,3 @@ export declare function validateSettings(settings: Rule.RuleContext["settings"])
134
133
  * @returns The normalized settings
135
134
  */
136
135
  export declare function getSettings(context: Rule.RuleContext): SettingsNormalized;
137
- export declare function validateRules(settings: SettingsNormalized, rules?: RuleOptionsRules[], options?: ValidateRulesOptions): void;
@@ -1,24 +1,17 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.elementsMatcherSchema = elementsMatcherSchema;
7
4
  exports.rulesOptionsSchema = rulesOptionsSchema;
8
- exports.validateElementTypesMatcher = validateElementTypesMatcher;
9
5
  exports.isValidElementAssigner = isValidElementAssigner;
10
6
  exports.validateSettings = validateSettings;
11
7
  exports.getSettings = getSettings;
12
- exports.validateRules = validateRules;
13
8
  const elements_1 = require("@boundaries/elements");
14
- const micromatch_1 = __importDefault(require("micromatch"));
15
9
  const Common_1 = require("../Support/Common");
16
10
  const Debug_1 = require("../Support/Debug");
17
11
  const Helpers_1 = require("./Helpers");
18
12
  const Settings_1 = require("./Settings");
19
13
  const Settings_types_1 = require("./Settings.types");
20
14
  const { TYPES, ALIAS, ELEMENTS, DEPENDENCY_NODES, ADDITIONAL_DEPENDENCY_NODES, VALID_DEPENDENCY_NODE_KINDS, DEFAULT_DEPENDENCY_NODES, VALID_MODES, } = Settings_types_1.SETTINGS;
21
- const invalidMatchers = [];
22
15
  const DEFAULT_MATCHER_OPTIONS = {
23
16
  type: "object",
24
17
  };
@@ -107,26 +100,6 @@ function rulesOptionsSchema(options = {}) {
107
100
  },
108
101
  ];
109
102
  }
110
- function isValidElementTypesMatcher(matcher, settings) {
111
- const matcherToCheck = (0, Common_1.isArray)(matcher) ? matcher[0] : matcher;
112
- const typeMatcherToCheck = (0, Common_1.isString)(matcherToCheck)
113
- ? matcherToCheck
114
- : matcherToCheck.type;
115
- return (!typeMatcherToCheck ||
116
- (typeMatcherToCheck &&
117
- micromatch_1.default.some(settings.elementTypeNames, typeMatcherToCheck)));
118
- }
119
- // TODO: Remove this validation. Selectors should not be limited to element types defined in settings when using selector objects
120
- function validateElementTypesMatcher(elementsMatcher, settings) {
121
- const [matcher] = (0, Common_1.isArray)(elementsMatcher)
122
- ? elementsMatcher
123
- : [elementsMatcher];
124
- if (!invalidMatchers.includes(matcher) &&
125
- !isValidElementTypesMatcher(matcher, settings)) {
126
- invalidMatchers.push(matcher);
127
- (0, Debug_1.warnOnce)(`Option '${matcher}' does not match any element type from '${ELEMENTS}' setting`);
128
- }
129
- }
130
103
  function isValidElementAssigner(element) {
131
104
  if (!element) {
132
105
  (0, Debug_1.warnOnce)(`Please provide a valid object to define element types in '${ELEMENTS}' setting`);
@@ -271,6 +244,50 @@ function validateRootPath(rootPath) {
271
244
  }
272
245
  (0, Debug_1.warnOnce)(`Please provide a valid value in '${Settings_types_1.SETTINGS_KEYS_MAP.ROOT_PATH}' setting. The value should be a string.`);
273
246
  }
247
+ function validateFlagAsExternal(flagAsExternal) {
248
+ if (!flagAsExternal) {
249
+ return;
250
+ }
251
+ if (!(0, Common_1.isObject)(flagAsExternal)) {
252
+ (0, Debug_1.warnOnce)(`Please provide a valid value in '${Settings_types_1.SETTINGS_KEYS_MAP.FLAG_AS_EXTERNAL}' setting. The value should be an object.`);
253
+ return;
254
+ }
255
+ const validated = {};
256
+ if (flagAsExternal.unresolvableAlias !== undefined) {
257
+ if ((0, Common_1.isBoolean)(flagAsExternal.unresolvableAlias)) {
258
+ validated.unresolvableAlias = flagAsExternal.unresolvableAlias;
259
+ }
260
+ else {
261
+ (0, Debug_1.warnOnce)(`Please provide a valid boolean for 'unresolvableAlias' in '${Settings_types_1.SETTINGS_KEYS_MAP.FLAG_AS_EXTERNAL}' setting.`);
262
+ }
263
+ }
264
+ if (flagAsExternal.inNodeModules !== undefined) {
265
+ if ((0, Common_1.isBoolean)(flagAsExternal.inNodeModules)) {
266
+ validated.inNodeModules = flagAsExternal.inNodeModules;
267
+ }
268
+ else {
269
+ (0, Debug_1.warnOnce)(`Please provide a valid boolean for 'inNodeModules' in '${Settings_types_1.SETTINGS_KEYS_MAP.FLAG_AS_EXTERNAL}' setting.`);
270
+ }
271
+ }
272
+ if (flagAsExternal.outsideRootPath !== undefined) {
273
+ if ((0, Common_1.isBoolean)(flagAsExternal.outsideRootPath)) {
274
+ validated.outsideRootPath = flagAsExternal.outsideRootPath;
275
+ }
276
+ else {
277
+ (0, Debug_1.warnOnce)(`Please provide a valid boolean for 'outsideRootPath' in '${Settings_types_1.SETTINGS_KEYS_MAP.FLAG_AS_EXTERNAL}' setting.`);
278
+ }
279
+ }
280
+ if (flagAsExternal.customSourcePatterns !== undefined) {
281
+ if ((0, Common_1.isArray)(flagAsExternal.customSourcePatterns) &&
282
+ flagAsExternal.customSourcePatterns.every(Common_1.isString)) {
283
+ validated.customSourcePatterns = flagAsExternal.customSourcePatterns;
284
+ }
285
+ else {
286
+ (0, Debug_1.warnOnce)(`Please provide a valid array of strings for 'customSourcePatterns' in '${Settings_types_1.SETTINGS_KEYS_MAP.FLAG_AS_EXTERNAL}' setting.`);
287
+ }
288
+ }
289
+ return validated;
290
+ }
274
291
  // TODO: Remove settings validation in next major version. It should be done by schema validation only
275
292
  function validateSettings(settings) {
276
293
  deprecateTypes(settings[TYPES]);
@@ -284,6 +301,7 @@ function validateSettings(settings) {
284
301
  [Settings_types_1.SETTINGS_KEYS_MAP.LEGACY_TEMPLATES]: validateLegacyTemplates(settings[Settings_types_1.SETTINGS_KEYS_MAP.LEGACY_TEMPLATES]),
285
302
  [Settings_types_1.SETTINGS_KEYS_MAP.ADDITIONAL_DEPENDENCY_NODES]: validateAdditionalDependencyNodes(settings[ADDITIONAL_DEPENDENCY_NODES]),
286
303
  [Settings_types_1.SETTINGS_KEYS_MAP.CACHE]: settings[Settings_types_1.SETTINGS_KEYS_MAP.CACHE],
304
+ [Settings_types_1.SETTINGS_KEYS_MAP.FLAG_AS_EXTERNAL]: validateFlagAsExternal(settings[Settings_types_1.SETTINGS_KEYS_MAP.FLAG_AS_EXTERNAL]),
287
305
  };
288
306
  }
289
307
  /**
@@ -335,21 +353,16 @@ function getSettings(context) {
335
353
  legacyTemplates: validatedSettings[Settings_types_1.SETTINGS_KEYS_MAP.LEGACY_TEMPLATES] ??
336
354
  Settings_types_1.LEGACY_TEMPLATES_DEFAULT,
337
355
  cache: validatedSettings[Settings_types_1.SETTINGS_KEYS_MAP.CACHE] ?? Settings_types_1.CACHE_DEFAULT,
356
+ flagAsExternal: {
357
+ unresolvableAlias: validatedSettings[Settings_types_1.SETTINGS_KEYS_MAP.FLAG_AS_EXTERNAL]
358
+ ?.unresolvableAlias ?? true,
359
+ inNodeModules: validatedSettings[Settings_types_1.SETTINGS_KEYS_MAP.FLAG_AS_EXTERNAL]?.inNodeModules ??
360
+ true,
361
+ outsideRootPath: validatedSettings[Settings_types_1.SETTINGS_KEYS_MAP.FLAG_AS_EXTERNAL]
362
+ ?.outsideRootPath ?? false,
363
+ customSourcePatterns: validatedSettings[Settings_types_1.SETTINGS_KEYS_MAP.FLAG_AS_EXTERNAL]
364
+ ?.customSourcePatterns ?? [],
365
+ },
338
366
  };
339
367
  return result;
340
368
  }
341
- function validateRules(settings, rules = [], options = {}) {
342
- const mainKey = (0, Helpers_1.rulesMainKey)(options.mainKey);
343
- for (const rule of rules) {
344
- //@ts-expect-error TODO: Add a different schema validation for each rule type, so keys are properly validated
345
- validateElementTypesMatcher([rule[mainKey]], settings);
346
- if (!options.onlyMainKey) {
347
- if (rule.allow) {
348
- validateElementTypesMatcher(rule.allow, settings);
349
- }
350
- if (rule.disallow) {
351
- validateElementTypesMatcher(rule.disallow, settings);
352
- }
353
- }
354
- }
355
- }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@boundaries/eslint-plugin",
3
- "version": "5.3.0",
3
+ "version": "5.4.0",
4
4
  "description": "Eslint plugin checking architecture boundaries between elements",
5
5
  "keywords": [
6
6
  "eslint",
@@ -53,14 +53,16 @@
53
53
  "eslint-import-resolver-node": "0.3.9",
54
54
  "eslint-module-utils": "2.12.1",
55
55
  "micromatch": "4.0.8",
56
- "@boundaries/elements": "1.1.1"
56
+ "@boundaries/elements": "1.2.0"
57
57
  },
58
58
  "engines": {
59
59
  "node": ">=18.18"
60
60
  },
61
61
  "devDependencies": {
62
62
  "@types/estree": "1.0.8",
63
- "@types/micromatch": "4.0.9"
63
+ "@types/micromatch": "4.0.9",
64
+ "eslint-plugin-eslint-plugin": "7.2.0",
65
+ "eslint-plugin-local-rules": "3.0.2"
64
66
  },
65
67
  "scripts": {
66
68
  "eslint": "eslint",