@boundaries/eslint-plugin 5.3.1 → 6.0.0-beta.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 (64) hide show
  1. package/README.md +9 -9
  2. package/dist/Config/Config.d.ts +6 -3
  3. package/dist/Config/Config.js +18 -7
  4. package/dist/Config/Recommended.d.ts +1 -1
  5. package/dist/Config/Recommended.js +3 -2
  6. package/dist/Config/Strict.d.ts +1 -1
  7. package/dist/Config/Strict.js +2 -2
  8. package/dist/Debug/Debug.d.ts +34 -0
  9. package/dist/Debug/Debug.js +285 -0
  10. package/dist/Debug/index.d.ts +1 -0
  11. package/dist/{Support → Debug}/index.js +0 -1
  12. package/dist/Elements/Elements.d.ts +11 -9
  13. package/dist/Elements/Elements.js +20 -34
  14. package/dist/Elements/Elements.types.d.ts +1 -0
  15. package/dist/Messages/CustomMessages.d.ts +44 -0
  16. package/dist/Messages/CustomMessages.js +156 -0
  17. package/dist/Messages/CustomMessages.types.d.ts +25 -0
  18. package/dist/Messages/CustomMessages.types.js +2 -0
  19. package/dist/Messages/Messages.d.ts +42 -13
  20. package/dist/Messages/Messages.js +400 -177
  21. package/dist/Messages/index.d.ts +2 -0
  22. package/dist/Messages/index.js +2 -0
  23. package/dist/Public/Config.types.d.ts +2 -2
  24. package/dist/Public/Config.types.js +2 -2
  25. package/dist/Public/Rules.types.d.ts +5 -4
  26. package/dist/Public/Rules.types.js +5 -6
  27. package/dist/Public/Settings.types.d.ts +3 -2
  28. package/dist/Public/Settings.types.js +4 -3
  29. package/dist/Public/index.d.ts +1 -0
  30. package/dist/Rules/Dependencies.d.ts +59 -0
  31. package/dist/Rules/Dependencies.js +439 -0
  32. package/dist/Rules/EntryPoint.js +44 -94
  33. package/dist/Rules/External.js +93 -68
  34. package/dist/Rules/NoIgnored.js +4 -4
  35. package/dist/Rules/NoPrivate.js +18 -5
  36. package/dist/Rules/NoUnknown.js +5 -5
  37. package/dist/Rules/NoUnknownFiles.js +4 -3
  38. package/dist/Rules/Support/DependencyRule.d.ts +9 -1
  39. package/dist/Rules/Support/DependencyRule.js +15 -15
  40. package/dist/Rules/Support/DependencyRule.types.d.ts +1 -1
  41. package/dist/Rules/Support/Helpers.d.ts +6 -2
  42. package/dist/Rules/Support/Helpers.js +7 -31
  43. package/dist/Settings/Helpers.d.ts +83 -1
  44. package/dist/Settings/Helpers.js +197 -7
  45. package/dist/Settings/Settings.d.ts +19 -2
  46. package/dist/Settings/Settings.js +20 -10
  47. package/dist/Settings/Validations.d.ts +11958 -45
  48. package/dist/Settings/Validations.js +797 -184
  49. package/dist/Settings/index.d.ts +0 -1
  50. package/dist/Settings/index.js +0 -1
  51. package/dist/{Settings → Shared}/Settings.types.d.ts +143 -37
  52. package/dist/{Settings → Shared}/Settings.types.js +32 -6
  53. package/dist/{Support/Common.d.ts → Shared/TypeHelpers.d.ts} +18 -0
  54. package/dist/{Support/Common.js → Shared/TypeHelpers.js} +28 -1
  55. package/dist/Shared/index.d.ts +2 -0
  56. package/dist/Shared/index.js +18 -0
  57. package/dist/index.d.ts +1 -1
  58. package/dist/index.js +12 -10
  59. package/package.json +9 -8
  60. package/dist/Rules/ElementTypes.d.ts +0 -25
  61. package/dist/Rules/ElementTypes.js +0 -279
  62. package/dist/Support/Debug.d.ts +0 -5
  63. package/dist/Support/Debug.js +0 -54
  64. package/dist/Support/index.d.ts +0 -2
@@ -1,46 +1,168 @@
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
- exports.elementsMatcherSchema = elementsMatcherSchema;
3
+ exports.legacyPoliciesSchema = legacyPoliciesSchema;
7
4
  exports.rulesOptionsSchema = rulesOptionsSchema;
8
- exports.validateElementTypesMatcher = validateElementTypesMatcher;
9
- exports.isValidElementAssigner = isValidElementAssigner;
5
+ exports.getRuleMainSelector = getRuleMainSelector;
6
+ exports.validateAndWarnRuleOptions = validateAndWarnRuleOptions;
7
+ exports.isValidElementDescriptor = isValidElementDescriptor;
8
+ exports.validateElementDescriptors = validateElementDescriptors;
9
+ exports.validateDependencyNodes = validateDependencyNodes;
10
+ exports.validateLegacyTemplates = validateLegacyTemplates;
11
+ exports.isValidDependencyNodeSelector = isValidDependencyNodeSelector;
12
+ exports.validateAdditionalDependencyNodes = validateAdditionalDependencyNodes;
13
+ exports.isAliasSetting = isAliasSetting;
14
+ exports.deprecateAlias = deprecateAlias;
15
+ exports.deprecateTypes = deprecateTypes;
16
+ exports.validateIgnore = validateIgnore;
17
+ exports.validateInclude = validateInclude;
18
+ exports.validateRootPath = validateRootPath;
19
+ exports.validateFlagAsExternal = validateFlagAsExternal;
20
+ exports.validateDebugFilterSelectors = validateDebugFilterSelectors;
21
+ exports.validateDebugFilesFilter = validateDebugFilesFilter;
22
+ exports.validateDebugDependenciesFilter = validateDebugDependenciesFilter;
23
+ exports.validateDebug = validateDebug;
10
24
  exports.validateSettings = validateSettings;
11
25
  exports.getSettings = getSettings;
12
- exports.validateRules = validateRules;
13
26
  const elements_1 = require("@boundaries/elements");
14
- const micromatch_1 = __importDefault(require("micromatch"));
15
- const Common_1 = require("../Support/Common");
16
- const Debug_1 = require("../Support/Debug");
27
+ const Debug_1 = require("../Debug");
28
+ const Shared_1 = require("../Shared");
29
+ const Settings_types_1 = require("../Shared/Settings.types");
17
30
  const Helpers_1 = require("./Helpers");
18
31
  const Settings_1 = require("./Settings");
19
- const Settings_types_1 = require("./Settings.types");
20
32
  const { TYPES, ALIAS, ELEMENTS, DEPENDENCY_NODES, ADDITIONAL_DEPENDENCY_NODES, VALID_DEPENDENCY_NODE_KINDS, DEFAULT_DEPENDENCY_NODES, VALID_MODES, } = Settings_types_1.SETTINGS;
21
- const DEFAULT_MATCHER_OPTIONS = {
33
+ const trackedValidatedSettings = new WeakMap();
34
+ const trackedWarnedOptions = new WeakSet();
35
+ const defaultLegacyMatcherOptionsSchema = {
36
+ type: "object",
37
+ };
38
+ /** Schema for validating a micromatch pattern or array of patterns that can also be null. */
39
+ const micromatchPatternNullableSchema = {
40
+ oneOf: [
41
+ { type: ["string", "null"] },
42
+ { type: "array", items: { type: ["string", "null"] } },
43
+ ],
44
+ };
45
+ const dependencyRelationshipSchema = {
46
+ type: "object",
47
+ properties: {
48
+ from: micromatchPatternNullableSchema,
49
+ to: micromatchPatternNullableSchema,
50
+ },
51
+ additionalProperties: false,
52
+ };
53
+ const dependencyMatcherItemSchema = {
54
+ type: "object",
55
+ properties: {
56
+ relationship: dependencyRelationshipSchema,
57
+ kind: micromatchPatternNullableSchema,
58
+ specifiers: micromatchPatternNullableSchema,
59
+ nodeKind: micromatchPatternNullableSchema,
60
+ source: micromatchPatternNullableSchema,
61
+ module: micromatchPatternNullableSchema,
62
+ },
63
+ additionalProperties: false,
64
+ };
65
+ const dependencyMatcherSchema = {
66
+ oneOf: [
67
+ dependencyMatcherItemSchema,
68
+ {
69
+ type: "array",
70
+ items: dependencyMatcherItemSchema,
71
+ },
72
+ ],
73
+ };
74
+ const capturedValuesSelectorSchema = {
75
+ type: "object",
76
+ additionalProperties: micromatchPatternNullableSchema,
77
+ };
78
+ const capturedValuesSchema = {
79
+ oneOf: [
80
+ {
81
+ type: "null",
82
+ },
83
+ capturedValuesSelectorSchema,
84
+ {
85
+ type: "array",
86
+ items: capturedValuesSelectorSchema,
87
+ },
88
+ ],
89
+ };
90
+ const parentElementMatcherSchema = {
22
91
  type: "object",
92
+ properties: {
93
+ type: micromatchPatternNullableSchema,
94
+ category: micromatchPatternNullableSchema,
95
+ elementPath: micromatchPatternNullableSchema,
96
+ captured: capturedValuesSchema,
97
+ },
98
+ additionalProperties: false,
99
+ };
100
+ const objectElementMatcherSchemaItem = {
101
+ type: "object", // single object-based selector (new format)
102
+ properties: {
103
+ path: micromatchPatternNullableSchema,
104
+ elementPath: micromatchPatternNullableSchema,
105
+ internalPath: micromatchPatternNullableSchema,
106
+ type: micromatchPatternNullableSchema,
107
+ category: micromatchPatternNullableSchema,
108
+ captured: capturedValuesSchema,
109
+ parent: {
110
+ oneOf: [
111
+ { type: "null" },
112
+ parentElementMatcherSchema,
113
+ { type: "array", items: parentElementMatcherSchema },
114
+ ],
115
+ },
116
+ origin: micromatchPatternNullableSchema,
117
+ isIgnored: { type: "boolean" },
118
+ isUnknown: { type: "boolean" },
119
+ },
120
+ additionalProperties: false,
121
+ };
122
+ const objectElementMatcherSchema = {
123
+ oneOf: [
124
+ objectElementMatcherSchemaItem,
125
+ {
126
+ type: "array",
127
+ items: objectElementMatcherSchemaItem,
128
+ },
129
+ ],
23
130
  };
24
- function elementsMatcherSchema(matcherOptions = DEFAULT_MATCHER_OPTIONS) {
131
+ /**
132
+ * Builds JSON schema for legacy policy selectors.
133
+ *
134
+ * @param matcherOptions - Extra matcher options accepted in legacy tuple syntax.
135
+ * @returns JSON schema definition for legacy policy values.
136
+ */
137
+ function legacyPoliciesSchema(matcherOptions = defaultLegacyMatcherOptionsSchema) {
25
138
  return {
26
- oneOf: [
139
+ anyOf: [
27
140
  {
28
- type: "string", // single matcher
141
+ type: "string", // single matcher (legacy)
142
+ },
143
+ {
144
+ type: "array", // matcher with captured values (legacy)
145
+ items: [
146
+ {
147
+ type: "string", // matcher
148
+ },
149
+ matcherOptions, // Extra options for legacy rules with custom syntax
150
+ ],
29
151
  },
30
152
  {
31
153
  type: "array", // multiple matchers
32
154
  items: {
33
- oneOf: [
155
+ anyOf: [
34
156
  {
35
- type: "string", // matcher with options
157
+ type: "string", // matcher (legacy)
36
158
  },
37
159
  {
38
- type: "array",
160
+ type: "array", // matcher with captured values (legacy)
39
161
  items: [
40
162
  {
41
163
  type: "string", // matcher
42
164
  },
43
- matcherOptions, // options
165
+ matcherOptions, // Extra options for legacy rules with custom syntax
44
166
  ],
45
167
  },
46
168
  ],
@@ -49,9 +171,116 @@ function elementsMatcherSchema(matcherOptions = DEFAULT_MATCHER_OPTIONS) {
49
171
  ],
50
172
  };
51
173
  }
52
- function rulesOptionsSchema(options = {}) {
53
- const mainKey = (0, Helpers_1.rulesMainKey)(options.rulesMainKey);
54
- return [
174
+ const legacyElementsSelectorItemSchema = {
175
+ anyOf: [
176
+ {
177
+ type: "string", // single matcher (legacy)
178
+ },
179
+ {
180
+ type: "array", // matcher with captured values (legacy)
181
+ items: [
182
+ {
183
+ type: "string", // matcher
184
+ },
185
+ defaultLegacyMatcherOptionsSchema, // Extra options for legacy rules with custom syntax
186
+ ],
187
+ },
188
+ ],
189
+ };
190
+ const legacyElementsSelectorSchema = {
191
+ anyOf: [
192
+ legacyElementsSelectorItemSchema,
193
+ {
194
+ type: "array",
195
+ items: legacyElementsSelectorItemSchema,
196
+ },
197
+ ],
198
+ };
199
+ /**
200
+ * Builds JSON schema for rule options of dependency-based rules.
201
+ *
202
+ * @param options - Schema customization options for rule main key and extras.
203
+ * @returns ESLint-compatible schema array for rule options.
204
+ */
205
+ function rulesOptionsSchema({ rulesMainKey: mainKey, targetMatcherOptions, extraOptionsSchema, isLegacy = false, } = {}) {
206
+ const policySchema = isLegacy
207
+ ? legacyPoliciesSchema(targetMatcherOptions)
208
+ : {
209
+ anyOf: [
210
+ legacyPoliciesSchema(targetMatcherOptions),
211
+ {
212
+ type: "object",
213
+ properties: {
214
+ from: objectElementMatcherSchema,
215
+ to: objectElementMatcherSchema,
216
+ dependency: dependencyMatcherSchema,
217
+ },
218
+ additionalProperties: false,
219
+ },
220
+ ],
221
+ };
222
+ const policiesSchema = {
223
+ anyOf: [
224
+ policySchema,
225
+ {
226
+ type: "array",
227
+ items: policySchema,
228
+ },
229
+ ],
230
+ };
231
+ const elementSelectorSchema = {
232
+ anyOf: [legacyElementsSelectorSchema, objectElementMatcherSchema],
233
+ };
234
+ const legacyMainKey = (0, Helpers_1.rulesMainKey)(mainKey);
235
+ const ruleSupportedProperties = isLegacy
236
+ ? {
237
+ [legacyMainKey]: elementSelectorSchema,
238
+ allow: policiesSchema,
239
+ disallow: policiesSchema,
240
+ }
241
+ : {
242
+ from: elementSelectorSchema,
243
+ to: elementSelectorSchema,
244
+ dependency: dependencyMatcherSchema,
245
+ allow: policiesSchema,
246
+ disallow: policiesSchema,
247
+ };
248
+ const requiredProperties = isLegacy
249
+ ? [
250
+ {
251
+ required: [legacyMainKey, "allow"],
252
+ },
253
+ {
254
+ required: [legacyMainKey, "disallow"],
255
+ },
256
+ ]
257
+ : [
258
+ {
259
+ required: ["allow"],
260
+ },
261
+ {
262
+ required: ["disallow"],
263
+ },
264
+ {
265
+ required: ["from", "allow"],
266
+ },
267
+ {
268
+ required: ["from", "disallow"],
269
+ },
270
+ {
271
+ required: ["to", "allow"],
272
+ },
273
+ {
274
+ required: ["to", "disallow"],
275
+ },
276
+ {
277
+ required: ["dependency", "allow"],
278
+ },
279
+ {
280
+ required: ["dependency", "disallow"],
281
+ },
282
+ ];
283
+ const schema = [
55
284
  {
56
285
  type: "object",
57
286
  properties: {
@@ -67,11 +296,9 @@ function rulesOptionsSchema(options = {}) {
67
296
  items: {
68
297
  type: "object",
69
298
  properties: {
70
- [mainKey]: elementsMatcherSchema(),
71
- allow: elementsMatcherSchema(options.targetMatcherOptions),
72
- disallow: elementsMatcherSchema(options.targetMatcherOptions),
299
+ ...ruleSupportedProperties,
73
300
  importKind: {
74
- oneOf: [
301
+ anyOf: [
75
302
  {
76
303
  type: "string",
77
304
  },
@@ -88,221 +315,611 @@ function rulesOptionsSchema(options = {}) {
88
315
  },
89
316
  },
90
317
  additionalProperties: false,
91
- anyOf: [
92
- {
93
- required: [mainKey, "allow", "disallow"],
94
- },
95
- {
96
- required: [mainKey, "allow"],
97
- },
98
- {
99
- required: [mainKey, "disallow"],
100
- },
101
- ],
318
+ anyOf: requiredProperties,
102
319
  },
103
320
  },
321
+ ...extraOptionsSchema,
104
322
  },
105
323
  additionalProperties: false,
106
324
  },
107
325
  ];
326
+ return schema;
327
+ }
328
+ /**
329
+ * Returns the selector configured under the active rule main key.
330
+ *
331
+ * @param rule - Single rule entry from options.
332
+ * @param mainKey - Main selector key configured for current rule.
333
+ * @returns Selector value from the corresponding property, when present.
334
+ */
335
+ function getRuleMainSelector(rule, mainKey) {
336
+ if (mainKey === "from") {
337
+ return "from" in rule ? rule.from : undefined;
338
+ }
339
+ if (mainKey === "to") {
340
+ return "to" in rule ? rule.to : undefined;
341
+ }
342
+ return "target" in rule ? rule.target : undefined;
108
343
  }
109
- function isValidElementTypesMatcher(matcher, settings) {
110
- const matcherToCheck = (0, Common_1.isArray)(matcher)
111
- ? matcher[0]
112
- : matcher;
113
- return (!matcherToCheck ||
114
- (matcherToCheck &&
115
- micromatch_1.default.some(settings.elementTypeNames, matcherToCheck)));
344
+ /**
345
+ * Returns all rule selectors that must be checked for legacy syntax.
346
+ *
347
+ * @param rule - Rule entry from options.
348
+ * @param mainKey - Main key used by the current rule.
349
+ * @returns List of selectors from main key, allow and disallow.
350
+ */
351
+ function getRuleSelectorsToCheck(rule, mainKey) {
352
+ const ruleMainKey = (0, Helpers_1.rulesMainKey)(mainKey);
353
+ return [getRuleMainSelector(rule, ruleMainKey), rule.allow, rule.disallow];
116
354
  }
117
355
  /**
118
- * Checks if the value is a single matcher with options (tuple of [string, object])
356
+ * Detects deprecated selector and template syntax across selectors.
357
+ *
358
+ * @param selectors - Selector values to inspect.
359
+ * @returns Flags describing whether each deprecated syntax was found.
119
360
  */
120
- function isSingleMatcherWithOptions(value) {
121
- return ((0, Common_1.isArray)(value) &&
122
- value.length === 2 &&
123
- (0, Common_1.isString)(value[0]) &&
124
- (0, Common_1.isObject)(value[1]));
361
+ function detectLegacyFlags(selectors) {
362
+ let hasLegacySelector = false;
363
+ let hasLegacyTemplate = false;
364
+ for (const selector of selectors) {
365
+ if (!selector) {
366
+ continue;
367
+ }
368
+ if ((0, Helpers_1.detectLegacyElementSelector)(selector)) {
369
+ hasLegacySelector = true;
370
+ }
371
+ if ((0, Helpers_1.detectLegacyTemplateSyntax)(selector)) {
372
+ hasLegacyTemplate = true;
373
+ }
374
+ }
375
+ return {
376
+ hasLegacySelector,
377
+ hasLegacyTemplate,
378
+ };
379
+ }
380
+ /**
381
+ * Collects indices of rules using deprecated selector/template/importKind syntax.
382
+ *
383
+ * @param rules - Rule list to inspect.
384
+ * @param mainKey - Main selector key configured for current rule.
385
+ * @returns Rule indices grouped by deprecated syntax type.
386
+ */
387
+ function collectRuleWarningIndexes(rules, mainKey) {
388
+ const indexes = {
389
+ rulesWithLegacySelector: [],
390
+ rulesWithLegacyTemplate: [],
391
+ rulesWithDeprecatedImportKind: [],
392
+ };
393
+ for (const [index, rule] of rules.entries()) {
394
+ const selectorsToCheck = getRuleSelectorsToCheck(rule, mainKey);
395
+ const { hasLegacySelector, hasLegacyTemplate } = detectLegacyFlags(selectorsToCheck);
396
+ if (hasLegacySelector) {
397
+ indexes.rulesWithLegacySelector.push(index);
398
+ }
399
+ if (hasLegacyTemplate) {
400
+ indexes.rulesWithLegacyTemplate.push(index);
401
+ }
402
+ if (!(0, Shared_1.isUndefined)(rule.importKind)) {
403
+ indexes.rulesWithDeprecatedImportKind.push(index);
404
+ }
405
+ }
406
+ return indexes;
125
407
  }
126
- // TODO: Remove this validation. Selectors should not be limited to element types defined in settings when using selector objects
127
- function validateElementTypesMatcher(elementsMatcher, settings) {
128
- // Handle empty array case
129
- if ((0, Common_1.isArray)(elementsMatcher) && elementsMatcher.length === 0) {
408
+ /**
409
+ * Warns once when deprecated selector/template syntax is detected in rules.
410
+ *
411
+ * @param options - Rule options containing `rules` entries.
412
+ * @param ruleName - Rule name displayed in warning messages.
413
+ * @param mainKey - Main selector key used by the current rule.
414
+ */
415
+ function validateAndWarnRuleOptions(options, ruleName, mainKey = "from") {
416
+ if (!options || trackedWarnedOptions.has(options)) {
130
417
  return;
131
418
  }
132
- // Determine if it's a single matcher or an array of matchers
133
- let matcher;
134
- if ((0, Common_1.isString)(elementsMatcher)) {
135
- matcher = elementsMatcher;
419
+ if (!options.rules || !(0, Shared_1.isArray)(options.rules)) {
420
+ return;
136
421
  }
137
- else if (isSingleMatcherWithOptions(elementsMatcher)) {
138
- // It's a single matcher with options: ["type", { option: value }]
139
- matcher = elementsMatcher;
422
+ trackedWarnedOptions.add(options);
423
+ const { rulesWithLegacySelector, rulesWithLegacyTemplate, rulesWithDeprecatedImportKind, } = collectRuleWarningIndexes(options.rules, mainKey);
424
+ if (rulesWithLegacySelector.length > 0) {
425
+ (0, Debug_1.warnOnce)(`[${ruleName}] Detected legacy selector syntax in ${rulesWithLegacySelector.length} rule(s) at indices: ${rulesWithLegacySelector.join(", ")}.`, `Consider migrating to object-based selectors. ${(0, Helpers_1.migrationToV6GuideLink)()}`);
140
426
  }
141
- else if ((0, Common_1.isArray)(elementsMatcher)) {
142
- // It's an array of matchers: ["helpers", "components"] or [["helpers", {...}], "components"]
143
- // NOTE: Validate only the first matcher. It is wrong, but we don't want to impact performance, and anyway it was already validating only the first one.
144
- // In next major version, validation will be removed, because schema validation will handle it.
145
- matcher = elementsMatcher[0];
427
+ if (rulesWithLegacyTemplate.length > 0) {
428
+ (0, Debug_1.warnOnce)(`[${ruleName}] Detected legacy template syntax \${...} in ${rulesWithLegacyTemplate.length} rule(s) at indices: ${rulesWithLegacyTemplate.join(", ")}.`, `Consider migrating to {{...}} syntax. ${(0, Helpers_1.migrationToV6GuideLink)("new-template-syntax")}`);
146
429
  }
147
- else {
148
- (0, Debug_1.warnOnce)(`Option is not a valid elements selector: '${JSON.stringify(elementsMatcher)}'`);
149
- return;
430
+ if (rulesWithDeprecatedImportKind.length > 0) {
431
+ (0, Debug_1.warnOnce)(`[${ruleName}] Detected deprecated rule-level "importKind" in ${rulesWithDeprecatedImportKind.length} rule(s) at indices: ${rulesWithDeprecatedImportKind.join(", ")}.`, `Use selector-level "dependency.kind" instead. When both are defined, "dependency.kind" takes precedence. ${(0, Helpers_1.migrationToV6GuideLink)("rule-level-importkind-is-deprecated")}`);
150
432
  }
151
- // Validate the matcher
152
- if (!isValidElementTypesMatcher(matcher, settings)) {
153
- (0, Debug_1.warnOnce)(`Option '${JSON.stringify(matcher)}' does not match any element type from '${ELEMENTS}' setting`);
433
+ }
434
+ /**
435
+ * Emits a generic warning for invalid element descriptor values.
436
+ */
437
+ function warnInvalidElementDescriptor() {
438
+ (0, Debug_1.warnOnce)(`Invalid element descriptor in '${ELEMENTS}' setting.`, (0, Helpers_1.moreInfoSettingsLink)());
439
+ }
440
+ /**
441
+ * Validates that descriptor contains at least one identity property.
442
+ *
443
+ * @param element - Candidate element descriptor object.
444
+ * @returns `true` when descriptor has either `type` or `category`.
445
+ */
446
+ function hasTypeOrCategory(element) {
447
+ return Boolean(element.type || element.category);
448
+ }
449
+ /**
450
+ * Checks whether descriptor `type` property, when present, is valid.
451
+ *
452
+ * @param element - Candidate element descriptor object.
453
+ * @returns `true` when `type` is absent or a string.
454
+ */
455
+ function hasValidTypeProperty(element) {
456
+ return !element.type || (0, Shared_1.isString)(element.type);
457
+ }
458
+ /**
459
+ * Checks whether descriptor `category` property, when present, is valid.
460
+ *
461
+ * @param element - Candidate element descriptor object.
462
+ * @returns `true` when `category` is absent or a string.
463
+ */
464
+ function hasValidCategoryProperty(element) {
465
+ return !element.category || (0, Shared_1.isString)(element.category);
466
+ }
467
+ /**
468
+ * Checks whether descriptor `mode` property uses a supported mode value.
469
+ *
470
+ * @param element - Candidate element descriptor object.
471
+ * @returns `true` when mode is absent, non-string, or included in valid modes.
472
+ */
473
+ function hasValidModeProperty(element) {
474
+ if (!element.mode || !(0, Shared_1.isString)(element.mode)) {
475
+ return true;
154
476
  }
477
+ return VALID_MODES.includes(element.mode);
155
478
  }
156
- function isValidElementAssigner(element) {
479
+ /**
480
+ * Checks whether descriptor `pattern` property is valid.
481
+ *
482
+ * @param element - Candidate element descriptor object.
483
+ * @returns `true` when pattern exists and is a string or array.
484
+ */
485
+ function hasValidPatternProperty(element) {
486
+ return Boolean(element.pattern && ((0, Shared_1.isString)(element.pattern) || (0, Shared_1.isArray)(element.pattern)));
487
+ }
488
+ /**
489
+ * Checks whether descriptor `capture` property, when present, is valid.
490
+ *
491
+ * @param element - Candidate element descriptor object.
492
+ * @returns `true` when capture is absent or an array.
493
+ */
494
+ function hasValidCaptureProperty(element) {
495
+ return !element.capture || (0, Shared_1.isArray)(element.capture);
496
+ }
497
+ /**
498
+ * Validates object-based element descriptor properties and emits warnings.
499
+ *
500
+ * @param element - Candidate element descriptor object.
501
+ * @returns `true` when descriptor object is valid.
502
+ */
503
+ function validateObjectElementDescriptor(element) {
504
+ if (!hasTypeOrCategory(element)) {
505
+ (0, Debug_1.warnOnce)(`Missing "type" or "category" property in an element descriptor in '${ELEMENTS}' setting.`, (0, Helpers_1.moreInfoSettingsLink)());
506
+ return false;
507
+ }
508
+ if (!hasValidTypeProperty(element)) {
509
+ (0, Debug_1.warnOnce)(`Invalid "type" property in an element descriptor in '${ELEMENTS}' setting.`, (0, Helpers_1.moreInfoSettingsLink)());
510
+ return false;
511
+ }
512
+ if (!hasValidCategoryProperty(element)) {
513
+ (0, Debug_1.warnOnce)(`Invalid "category" property in an element descriptor in '${ELEMENTS}' setting.`, (0, Helpers_1.moreInfoSettingsLink)());
514
+ return false;
515
+ }
516
+ if (!hasValidModeProperty(element)) {
517
+ (0, Debug_1.warnOnce)(`Invalid "mode" property in an element descriptor in '${ELEMENTS}' setting.`, `It should be one of ${VALID_MODES.join(", ")}. ${(0, Helpers_1.moreInfoSettingsLink)()}`);
518
+ return false;
519
+ }
520
+ if (!hasValidPatternProperty(element)) {
521
+ (0, Debug_1.warnOnce)(`Invalid "pattern" property in an element descriptor in '${ELEMENTS}' setting.`, (0, Helpers_1.moreInfoSettingsLink)());
522
+ return false;
523
+ }
524
+ if (!hasValidCaptureProperty(element)) {
525
+ (0, Debug_1.warnOnce)(`Invalid "capture" property in an element descriptor in '${ELEMENTS}' setting.`, `Capture should be an array of strings. ${(0, Helpers_1.moreInfoSettingsLink)()}`);
526
+ return false;
527
+ }
528
+ return true;
529
+ }
530
+ /**
531
+ * Validates one element descriptor item from plugin settings.
532
+ *
533
+ * @param element - Candidate element descriptor from settings.
534
+ * @returns `true` when descriptor is valid or accepted legacy string.
535
+ */
536
+ function isValidElementDescriptor(element) {
157
537
  if (!element) {
158
- (0, Debug_1.warnOnce)(`Please provide a valid object to define element types in '${ELEMENTS}' setting`);
538
+ warnInvalidElementDescriptor();
159
539
  return false;
160
540
  }
161
541
  if ((0, Helpers_1.isLegacyType)(element)) {
162
- (0, Debug_1.warnOnce)(`Defining elements as strings in settings is deprecated. Will be automatically converted, but this feature will be removed in next major versions`);
542
+ (0, Debug_1.warnOnce)(`Defining elements as strings in settings is deprecated.`, `It will be automatically converted, but this feature will be removed in next major versions. ${(0, Helpers_1.migrationToV6GuideLink)()}`);
163
543
  return true;
164
544
  }
165
- else {
166
- const isObjectElement = (0, Common_1.isObject)(element);
167
- if (!isObjectElement) {
168
- (0, Debug_1.warnOnce)(`Please provide a valid object to define element types in '${ELEMENTS}' setting`);
169
- return false;
170
- }
171
- if (!element.type || !(0, Common_1.isString)(element.type)) {
172
- (0, Debug_1.warnOnce)(`Please provide type in '${ELEMENTS}' setting`);
173
- return false;
174
- }
175
- if (element.mode &&
176
- (0, Common_1.isString)(element.mode) &&
177
- !VALID_MODES.includes(element.mode)) {
178
- (0, Debug_1.warnOnce)(`Invalid mode property of type ${element.type} in '${ELEMENTS}' setting. Should be one of ${VALID_MODES.join(",")}. Default value "${VALID_MODES[0]}" will be used instead`);
179
- return false;
180
- }
181
- if (!element.pattern ||
182
- !((0, Common_1.isString)(element.pattern) || (0, Common_1.isArray)(element.pattern))) {
183
- (0, Debug_1.warnOnce)(`Please provide a valid pattern to type ${element.type} in '${ELEMENTS}' setting`);
184
- return false;
185
- }
186
- if (element.capture && !(0, Common_1.isArray)(element.capture)) {
187
- (0, Debug_1.warnOnce)(`Invalid capture property of type ${element.type} in '${ELEMENTS}' setting`);
188
- return false;
189
- }
190
- return true;
545
+ if (!(0, Shared_1.isObject)(element)) {
546
+ warnInvalidElementDescriptor();
547
+ return false;
191
548
  }
549
+ return validateObjectElementDescriptor(element);
192
550
  }
193
- function validateElements(elements) {
194
- if (!elements || !(0, Common_1.isArray)(elements) || !elements.length) {
195
- (0, Debug_1.warnOnce)(`Please provide element types using the '${ELEMENTS}' setting`);
551
+ /**
552
+ * Validates and filters the configured list of element descriptors.
553
+ *
554
+ * @param elements - Raw `boundaries/elements` setting value.
555
+ * @returns Valid descriptors or `undefined` when setting is invalid/missing.
556
+ */
557
+ function validateElementDescriptors(elements) {
558
+ if (!elements || !(0, Shared_1.isArray)(elements) || !elements.length) {
559
+ (0, Debug_1.warnOnce)(`Please provide element descriptors using the '${ELEMENTS}' setting.`, (0, Helpers_1.moreInfoSettingsLink)());
196
560
  return;
197
561
  }
198
- return elements.filter(isValidElementAssigner);
562
+ return elements.filter(isValidElementDescriptor);
199
563
  }
564
+ /**
565
+ * Validates configured dependency node keys.
566
+ *
567
+ * @param dependencyNodes - Raw dependency node keys from settings.
568
+ * @returns Filtered valid keys or `undefined` for missing/invalid setting.
569
+ */
200
570
  function validateDependencyNodes(dependencyNodes) {
201
571
  if (!dependencyNodes) {
202
572
  return;
203
573
  }
204
574
  const defaultNodesNames = Object.keys(DEFAULT_DEPENDENCY_NODES);
205
- const invalidFormatMessage = [
206
- `Please provide a valid value in ${DEPENDENCY_NODES} setting.`,
207
- `The value should be an array of the following strings:`,
208
- ` "${defaultNodesNames.join('", "')}".`,
209
- ].join(" ");
210
- if (!(0, Common_1.isArray)(dependencyNodes)) {
211
- (0, Debug_1.warnOnce)(invalidFormatMessage);
575
+ const invalidFormatTitle = `Invalid ${DEPENDENCY_NODES} setting format.`;
576
+ const invalidNodeMessage = `It should be an array of the following strings: "${defaultNodesNames.join('", "')}". ${(0, Helpers_1.moreInfoSettingsLink)()}`;
577
+ if (!(0, Shared_1.isArray)(dependencyNodes)) {
578
+ (0, Debug_1.warnOnce)(invalidFormatTitle, invalidNodeMessage);
212
579
  return;
213
580
  }
214
581
  for (const dependencyNode of dependencyNodes) {
215
582
  if (!(0, Helpers_1.isDependencyNodeKey)(dependencyNode)) {
216
- (0, Debug_1.warnOnce)(invalidFormatMessage);
583
+ (0, Debug_1.warnOnce)(invalidFormatTitle, invalidNodeMessage);
217
584
  }
218
585
  }
219
586
  return dependencyNodes.filter(Helpers_1.isDependencyNodeKey);
220
587
  }
221
588
  /**
222
589
  * Validates the legacyTemplates setting.
223
- * @param legacyTemplates The legacyTemplates setting value
224
- * @returns The validated legacyTemplates value or undefined
590
+ *
591
+ * @param legacyTemplates - Raw legacyTemplates setting value.
592
+ * @returns Validated boolean value or `undefined` when missing/invalid.
225
593
  */
226
- function validateLegacyTemplates(
227
- /** The legacyTemplates setting value */
228
- legacyTemplates) {
229
- if (legacyTemplates === undefined) {
594
+ function validateLegacyTemplates(legacyTemplates) {
595
+ if ((0, Shared_1.isUndefined)(legacyTemplates)) {
230
596
  return;
231
597
  }
232
- if ((0, Common_1.isBoolean)(legacyTemplates)) {
598
+ if ((0, Shared_1.isBoolean)(legacyTemplates)) {
233
599
  return legacyTemplates;
234
600
  }
235
- (0, Debug_1.warnOnce)(`Please provide a valid value in '${Settings_types_1.SETTINGS_KEYS_MAP.LEGACY_TEMPLATES}' setting. The value should be a boolean.`);
601
+ (0, Debug_1.warnOnce)(`Please provide a valid value in '${Settings_types_1.SETTINGS_KEYS_MAP.LEGACY_TEMPLATES}' setting.`, `The value should be a boolean. ${(0, Helpers_1.moreInfoSettingsLink)()}`);
236
602
  }
603
+ /**
604
+ * Validates one custom dependency-node selector object.
605
+ *
606
+ * @param selector - Candidate additional dependency node selector.
607
+ * @returns `true` when selector has a valid shape.
608
+ */
237
609
  function isValidDependencyNodeSelector(selector) {
238
- const isValidObject = (0, Common_1.isObject)(selector) &&
239
- (0, Common_1.isString)(selector.selector) &&
610
+ const isValidObject = (0, Shared_1.isObject)(selector) &&
611
+ (0, Shared_1.isString)(selector.selector) &&
240
612
  (!selector.kind ||
241
- ((0, Common_1.isString)(selector.kind) &&
242
- VALID_DEPENDENCY_NODE_KINDS.includes(selector.kind)));
613
+ ((0, Shared_1.isString)(selector.kind) &&
614
+ VALID_DEPENDENCY_NODE_KINDS.includes(selector.kind))) &&
615
+ (!selector.name || (0, Shared_1.isString)(selector.name));
243
616
  if (!isValidObject) {
244
- (0, Debug_1.warnOnce)(`Please provide a valid object in ${ADDITIONAL_DEPENDENCY_NODES} setting. The object should be composed of the following properties: { selector: "<esquery selector>", kind: "value" | "type" }. The invalid object will be ignored.`);
617
+ (0, Debug_1.warnOnce)(`Please provide a valid object in ${ADDITIONAL_DEPENDENCY_NODES} setting.`, `The object should be composed of the following properties: { selector: "<esquery selector>", kind: "value" | "type", name: "<string>" (optional) }. The invalid object will be ignored. ${(0, Helpers_1.moreInfoSettingsLink)()}`);
618
+ }
619
+ else if ((0, Shared_1.isObject)(selector) && !selector.name) {
620
+ (0, Debug_1.warnOnce)(`Consider adding a "name" property to your custom dependency node for using it in selectors and custom messages.`, (0, Helpers_1.moreInfoSettingsLink)());
245
621
  }
246
622
  return isValidObject;
247
623
  }
624
+ /**
625
+ * Validates the list of additional dependency node selectors.
626
+ *
627
+ * @param additionalDependencyNodes - Raw custom dependency nodes setting.
628
+ * @returns Valid selectors or `undefined` when absent/invalid.
629
+ */
248
630
  function validateAdditionalDependencyNodes(additionalDependencyNodes) {
249
631
  if (!additionalDependencyNodes) {
250
632
  return;
251
633
  }
252
- const invalidFormatMessage = [
253
- `Please provide a valid value in ${ADDITIONAL_DEPENDENCY_NODES} setting.`,
254
- "The value should be an array composed of the following objects:",
255
- '{ selector: "<esquery selector>", kind: "value" | "type" }.',
256
- ].join(" ");
257
- if (!(0, Common_1.isArray)(additionalDependencyNodes)) {
258
- (0, Debug_1.warnOnce)(invalidFormatMessage);
634
+ const invalidFormatTitle = `Invalid ${ADDITIONAL_DEPENDENCY_NODES} setting format.`;
635
+ const invalidNodeMessage = `It should be an array containing objects with the following properties: { selector: "<esquery selector>", kind: "value" | "type", name: "<string>" (optional) }. ${(0, Helpers_1.moreInfoSettingsLink)()}`;
636
+ if (!(0, Shared_1.isArray)(additionalDependencyNodes)) {
637
+ (0, Debug_1.warnOnce)(invalidFormatTitle, invalidNodeMessage);
259
638
  return;
260
639
  }
261
640
  return additionalDependencyNodes.filter(isValidDependencyNodeSelector);
262
641
  }
642
+ /**
643
+ * Type guard for alias setting object.
644
+ *
645
+ * @param value - Candidate alias setting value.
646
+ * @returns `true` when value is an object whose values are strings.
647
+ */
648
+ function isAliasSetting(value) {
649
+ return (0, Shared_1.isObject)(value) && Object.values(value).every(Shared_1.isString);
650
+ }
651
+ /**
652
+ * Emits deprecation warning for legacy `alias` setting.
653
+ *
654
+ * @param aliases - Alias setting value when present.
655
+ */
263
656
  function deprecateAlias(aliases) {
264
657
  if (aliases) {
265
- (0, Debug_1.warnOnce)(`Defining aliases in '${ALIAS}' setting is deprecated. Please use 'import/resolver' setting`);
658
+ (0, Debug_1.warnOnce)(`Defining aliases in '${ALIAS}' setting is deprecated.`, `Please use 'import/resolver' setting. ${(0, Helpers_1.moreInfoSettingsLink)()}`);
266
659
  }
267
660
  }
661
+ /**
662
+ * Emits deprecation warning for legacy `types` setting.
663
+ *
664
+ * @param types - Legacy types setting value when present.
665
+ */
268
666
  function deprecateTypes(types) {
269
667
  if (types) {
270
- (0, Debug_1.warnOnce)(`'${TYPES}' setting is deprecated. Please use '${ELEMENTS}' instead`);
668
+ (0, Debug_1.warnOnce)(`'${TYPES}' setting is deprecated.`, `Please use '${ELEMENTS}' instead. ${(0, Helpers_1.migrationToV2GuideLink)()}`);
271
669
  }
272
670
  }
671
+ /**
672
+ * Validates `ignore` setting values.
673
+ *
674
+ * @param ignore - Raw ignore setting.
675
+ * @returns String or string array when valid.
676
+ */
273
677
  function validateIgnore(ignore) {
274
678
  if (!ignore) {
275
679
  return;
276
680
  }
277
- if ((0, Common_1.isString)(ignore) || ((0, Common_1.isArray)(ignore) && ignore.every(Common_1.isString))) {
681
+ if ((0, Shared_1.isString)(ignore) || ((0, Shared_1.isArray)(ignore) && ignore.every(Shared_1.isString))) {
278
682
  return ignore;
279
683
  }
280
- (0, Debug_1.warnOnce)(`Please provide a valid value in '${Settings_types_1.SETTINGS_KEYS_MAP.IGNORE}' setting. The value should be a string or an array of strings.`);
684
+ (0, Debug_1.warnOnce)(`Please provide a valid value in '${Settings_types_1.SETTINGS_KEYS_MAP.IGNORE}' setting.`, `The value should be a string or an array of strings. ${(0, Helpers_1.moreInfoSettingsLink)()}`);
281
685
  }
686
+ /**
687
+ * Validates `include` setting values.
688
+ *
689
+ * @param include - Raw include setting.
690
+ * @returns String or string array when valid.
691
+ */
282
692
  function validateInclude(include) {
283
693
  if (!include) {
284
694
  return;
285
695
  }
286
- if ((0, Common_1.isString)(include) || ((0, Common_1.isArray)(include) && include.every(Common_1.isString))) {
696
+ if ((0, Shared_1.isString)(include) || ((0, Shared_1.isArray)(include) && include.every(Shared_1.isString))) {
287
697
  return include;
288
698
  }
289
- (0, Debug_1.warnOnce)(`Please provide a valid value in '${Settings_types_1.SETTINGS_KEYS_MAP.INCLUDE}' setting. The value should be a string or an array of strings.`);
699
+ (0, Debug_1.warnOnce)(`Please provide a valid value in '${Settings_types_1.SETTINGS_KEYS_MAP.INCLUDE}' setting.`, `The value should be a string or an array of strings. ${(0, Helpers_1.moreInfoSettingsLink)()}`);
290
700
  }
701
+ /**
702
+ * Validates `root-path` setting values.
703
+ *
704
+ * @param rootPath - Raw root-path setting.
705
+ * @returns Root path string when valid.
706
+ */
291
707
  function validateRootPath(rootPath) {
292
708
  if (!rootPath) {
293
709
  return;
294
710
  }
295
- if ((0, Common_1.isString)(rootPath)) {
711
+ if ((0, Shared_1.isString)(rootPath)) {
296
712
  return rootPath;
297
713
  }
298
- (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.`);
714
+ (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. ${(0, Helpers_1.moreInfoSettingsLink)()}`);
715
+ }
716
+ /**
717
+ * Validates and assigns an optional boolean field in `flag-as-external` settings.
718
+ *
719
+ * @param options - Raw `flag-as-external` settings object.
720
+ * @param validated - Accumulator for validated options.
721
+ * @param optionKey - Optional boolean field to validate and assign.
722
+ */
723
+ function assignFlagAsExternalBooleanOption(options, validated, optionKey) {
724
+ const value = options[optionKey];
725
+ if ((0, Shared_1.isUndefined)(value)) {
726
+ return;
727
+ }
728
+ if ((0, Shared_1.isBoolean)(value)) {
729
+ validated[optionKey] = value;
730
+ return;
731
+ }
732
+ (0, Debug_1.warnOnce)(`Please provide a valid boolean for '${optionKey}' in '${Settings_types_1.SETTINGS_KEYS_MAP.FLAG_AS_EXTERNAL}' setting.`, (0, Helpers_1.moreInfoSettingsLink)());
299
733
  }
300
- // TODO: Remove settings validation in next major version. It should be done by schema validation only
734
+ /**
735
+ * Validates and assigns `customSourcePatterns` in `flag-as-external` settings.
736
+ *
737
+ * @param options - Raw `flag-as-external` settings object.
738
+ * @param validated - Accumulator for validated options.
739
+ */
740
+ function assignFlagAsExternalCustomSourcePatterns(options, validated) {
741
+ const value = options.customSourcePatterns;
742
+ if ((0, Shared_1.isUndefined)(value)) {
743
+ return;
744
+ }
745
+ if ((0, Shared_1.isArray)(value) && value.every(Shared_1.isString)) {
746
+ validated.customSourcePatterns = value;
747
+ return;
748
+ }
749
+ (0, Debug_1.warnOnce)(`Please provide a valid array of strings for 'customSourcePatterns' in '${Settings_types_1.SETTINGS_KEYS_MAP.FLAG_AS_EXTERNAL}' setting.`, (0, Helpers_1.moreInfoSettingsLink)());
750
+ }
751
+ /**
752
+ * Validates `flag-as-external` setting object and fields.
753
+ *
754
+ * @param flagAsExternal - Raw flag-as-external setting value.
755
+ * @returns Normalized options object with valid fields only.
756
+ */
757
+ function validateFlagAsExternal(flagAsExternal) {
758
+ if (!flagAsExternal) {
759
+ return;
760
+ }
761
+ if (!(0, Shared_1.isObject)(flagAsExternal)) {
762
+ (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. ${(0, Helpers_1.moreInfoSettingsLink)()}`);
763
+ return;
764
+ }
765
+ const options = flagAsExternal;
766
+ const validated = {};
767
+ assignFlagAsExternalBooleanOption(options, validated, "unresolvableAlias");
768
+ assignFlagAsExternalBooleanOption(options, validated, "inNodeModules");
769
+ assignFlagAsExternalBooleanOption(options, validated, "outsideRootPath");
770
+ assignFlagAsExternalCustomSourcePatterns(options, validated);
771
+ return validated;
772
+ }
773
+ /**
774
+ * Validates debug filter selectors for files or dependencies.
775
+ *
776
+ * @param value - Raw filter value.
777
+ * @param filterName - Filter key used in warning messages.
778
+ * @returns Filter array when valid, otherwise `undefined`.
779
+ */
780
+ function validateDebugFilterSelectors(value, filterName) {
781
+ if ((0, Shared_1.isUndefined)(value)) {
782
+ return undefined;
783
+ }
784
+ if ((0, Shared_1.isArray)(value)) {
785
+ return value;
786
+ }
787
+ (0, Debug_1.warnOnce)(`Please provide a valid array for '${filterName}' in '${Settings_types_1.SETTINGS_KEYS_MAP.DEBUG}' setting.`, (0, Helpers_1.moreInfoSettingsLink)());
788
+ return undefined;
789
+ }
790
+ /**
791
+ * Validates debug `files` filter selector list.
792
+ *
793
+ * @param value - Raw `debug.filter.files` setting value.
794
+ * @returns Valid files filter selectors.
795
+ */
796
+ function validateDebugFilesFilter(value) {
797
+ return validateDebugFilterSelectors(value, "files");
798
+ }
799
+ /**
800
+ * Validates debug `dependencies` filter selector list.
801
+ *
802
+ * @param value - Raw `debug.filter.dependencies` setting value.
803
+ * @returns Valid dependency filter selectors.
804
+ */
805
+ function validateDebugDependenciesFilter(value) {
806
+ return validateDebugFilterSelectors(value, "dependencies");
807
+ }
808
+ /**
809
+ * Validates and assigns `debug.enabled` when provided.
810
+ *
811
+ * @param debug - Raw debug setting object.
812
+ * @param validated - Debug setting accumulator.
813
+ */
814
+ function assignDebugEnabled(debug, validated) {
815
+ if ((0, Shared_1.isUndefined)(debug.enabled)) {
816
+ return;
817
+ }
818
+ if ((0, Shared_1.isBoolean)(debug.enabled)) {
819
+ validated.enabled = debug.enabled;
820
+ return;
821
+ }
822
+ (0, Debug_1.warnOnce)(`Please provide a valid boolean for 'enabled' in '${Settings_types_1.SETTINGS_KEYS_MAP.DEBUG}' setting.`, (0, Helpers_1.moreInfoSettingsLink)());
823
+ }
824
+ /**
825
+ * Validates and assigns a `debug.messages.*` boolean flag when provided.
826
+ *
827
+ * @param messages - Raw `debug.messages` object.
828
+ * @param validated - Debug setting accumulator.
829
+ * @param key - Message flag key to validate.
830
+ */
831
+ function assignDebugMessageFlag(messages, validated, key) {
832
+ const value = messages[key];
833
+ if ((0, Shared_1.isUndefined)(value)) {
834
+ return;
835
+ }
836
+ if ((0, Shared_1.isBoolean)(value)) {
837
+ validated.messages[key] = value;
838
+ return;
839
+ }
840
+ (0, Debug_1.warnOnce)(`Please provide a valid boolean for 'messages.${key}' in '${Settings_types_1.SETTINGS_KEYS_MAP.DEBUG}' setting.`, (0, Helpers_1.moreInfoSettingsLink)());
841
+ }
842
+ /**
843
+ * Validates and assigns `debug.messages` object and known flags.
844
+ *
845
+ * @param debug - Raw debug setting object.
846
+ * @param validated - Debug setting accumulator.
847
+ */
848
+ function assignDebugMessages(debug, validated) {
849
+ if ((0, Shared_1.isUndefined)(debug.messages)) {
850
+ return;
851
+ }
852
+ if (!(0, Shared_1.isObject)(debug.messages)) {
853
+ (0, Debug_1.warnOnce)(`Please provide a valid object for 'messages' in '${Settings_types_1.SETTINGS_KEYS_MAP.DEBUG}' setting.`, (0, Helpers_1.moreInfoSettingsLink)());
854
+ return;
855
+ }
856
+ assignDebugMessageFlag(debug.messages, validated, "files");
857
+ assignDebugMessageFlag(debug.messages, validated, "dependencies");
858
+ assignDebugMessageFlag(debug.messages, validated, "violations");
859
+ }
860
+ /**
861
+ * Validates and assigns `debug.filter` object and supported selectors.
862
+ *
863
+ * @param debug - Raw debug setting object.
864
+ * @param validated - Debug setting accumulator.
865
+ */
866
+ function assignDebugFilter(debug, validated) {
867
+ if ((0, Shared_1.isUndefined)(debug.filter)) {
868
+ return;
869
+ }
870
+ if (!(0, Shared_1.isObject)(debug.filter)) {
871
+ (0, Debug_1.warnOnce)(`Please provide a valid object for 'filter' in '${Settings_types_1.SETTINGS_KEYS_MAP.DEBUG}' setting.`, (0, Helpers_1.moreInfoSettingsLink)());
872
+ return;
873
+ }
874
+ const files = validateDebugFilesFilter(debug.filter.files);
875
+ const dependencies = validateDebugDependenciesFilter(debug.filter.dependencies);
876
+ validated.filter = {
877
+ ...((0, Shared_1.isUndefined)(files) ? {} : { files }),
878
+ ...((0, Shared_1.isUndefined)(dependencies) ? {} : { dependencies }),
879
+ };
880
+ }
881
+ /**
882
+ * Validates the `debug` setting object and nested filters.
883
+ *
884
+ * @param debug - Raw debug setting value.
885
+ * @returns Normalized debug setting when valid.
886
+ */
887
+ function validateDebug(debug) {
888
+ const validated = {
889
+ enabled: false,
890
+ filter: {
891
+ files: undefined,
892
+ dependencies: undefined,
893
+ },
894
+ messages: {
895
+ files: true,
896
+ dependencies: true,
897
+ violations: true,
898
+ },
899
+ };
900
+ if (!debug) {
901
+ return validated;
902
+ }
903
+ if (!(0, Shared_1.isObject)(debug)) {
904
+ (0, Debug_1.warnOnce)(`Please provide a valid value in '${Settings_types_1.SETTINGS_KEYS_MAP.DEBUG}' setting.`, `The value should be an object. ${(0, Helpers_1.moreInfoSettingsLink)()}`);
905
+ return validated;
906
+ }
907
+ assignDebugEnabled(debug, validated);
908
+ assignDebugMessages(debug, validated);
909
+ assignDebugFilter(debug, validated);
910
+ return validated;
911
+ }
912
+ /**
913
+ * Validates plugin settings and returns a sanitized settings object.
914
+ *
915
+ * @param settings - Raw ESLint context settings.
916
+ * @returns Validated settings ready for normalization.
917
+ */
301
918
  function validateSettings(settings) {
302
919
  deprecateTypes(settings[TYPES]);
303
- deprecateAlias(settings[ALIAS]);
920
+ deprecateAlias(isAliasSetting(settings[ALIAS]) ? settings[ALIAS] : undefined);
304
921
  return {
305
- [Settings_types_1.SETTINGS_KEYS_MAP.ELEMENTS]: validateElements(settings[ELEMENTS] || settings[TYPES]),
922
+ [Settings_types_1.SETTINGS_KEYS_MAP.ELEMENTS]: validateElementDescriptors(settings[ELEMENTS] || settings[TYPES]),
306
923
  [Settings_types_1.SETTINGS_KEYS_MAP.IGNORE]: validateIgnore(settings[Settings_types_1.SETTINGS_KEYS_MAP.IGNORE]),
307
924
  [Settings_types_1.SETTINGS_KEYS_MAP.INCLUDE]: validateInclude(settings[Settings_types_1.SETTINGS_KEYS_MAP.INCLUDE]),
308
925
  [Settings_types_1.SETTINGS_KEYS_MAP.ROOT_PATH]: validateRootPath(settings[Settings_types_1.SETTINGS_KEYS_MAP.ROOT_PATH]),
@@ -310,46 +927,45 @@ function validateSettings(settings) {
310
927
  [Settings_types_1.SETTINGS_KEYS_MAP.LEGACY_TEMPLATES]: validateLegacyTemplates(settings[Settings_types_1.SETTINGS_KEYS_MAP.LEGACY_TEMPLATES]),
311
928
  [Settings_types_1.SETTINGS_KEYS_MAP.ADDITIONAL_DEPENDENCY_NODES]: validateAdditionalDependencyNodes(settings[ADDITIONAL_DEPENDENCY_NODES]),
312
929
  [Settings_types_1.SETTINGS_KEYS_MAP.CACHE]: settings[Settings_types_1.SETTINGS_KEYS_MAP.CACHE],
930
+ [Settings_types_1.SETTINGS_KEYS_MAP.FLAG_AS_EXTERNAL]: validateFlagAsExternal(settings[Settings_types_1.SETTINGS_KEYS_MAP.FLAG_AS_EXTERNAL]),
931
+ [Settings_types_1.SETTINGS_KEYS_MAP.DEBUG]: validateDebug(settings[Settings_types_1.SETTINGS_KEYS_MAP.DEBUG]),
313
932
  };
314
933
  }
315
934
  /**
316
- * Returns the normalized settings from the ESLint rule context
317
- * @param context The ESLint rule context
318
- * @returns The normalized settings
935
+ * Returns normalized and cached settings from ESLint rule context.
936
+ *
937
+ * @param context - ESLint rule context.
938
+ * @returns Normalized settings object used by rules.
319
939
  */
320
940
  function getSettings(context) {
941
+ const alreadyValidatedSettings = trackedValidatedSettings.get(context.settings);
942
+ if (alreadyValidatedSettings) {
943
+ return alreadyValidatedSettings;
944
+ }
321
945
  const validatedSettings = validateSettings(context.settings);
322
- const dependencyNodesSetting = (0, Common_1.getArrayOrNull)(validatedSettings[Settings_types_1.SETTINGS_KEYS_MAP.DEPENDENCY_NODES]);
323
- const additionalDependencyNodesSetting = (0, Common_1.getArrayOrNull)(validatedSettings[ADDITIONAL_DEPENDENCY_NODES]);
324
- const dependencyNodes =
325
- // TODO In next major version, make this default to all types of nodes!!!
326
- (dependencyNodesSetting || [Settings_types_1.DEPENDENCY_NODE_KEYS_MAP.IMPORT])
327
- .flatMap((dependencyNode) => [
328
- ...DEFAULT_DEPENDENCY_NODES[dependencyNode],
946
+ const dependencyNodesSetting = (0, Shared_1.getArrayOrNull)(validatedSettings[Settings_types_1.SETTINGS_KEYS_MAP.DEPENDENCY_NODES]);
947
+ const additionalDependencyNodesSetting = (0, Shared_1.getArrayOrNull)(validatedSettings[ADDITIONAL_DEPENDENCY_NODES]);
948
+ const dependencyNodes = (dependencyNodesSetting || [
949
+ Settings_types_1.DEPENDENCY_NODE_KEYS_MAP.IMPORT,
950
+ Settings_types_1.DEPENDENCY_NODE_KEYS_MAP.EXPORT,
951
+ Settings_types_1.DEPENDENCY_NODE_KEYS_MAP.REQUIRE,
952
+ Settings_types_1.DEPENDENCY_NODE_KEYS_MAP.DYNAMIC_IMPORT,
329
953
  ])
954
+ .flatMap((dependencyNode) => [...DEFAULT_DEPENDENCY_NODES[dependencyNode]])
330
955
  .filter(Boolean);
331
956
  const additionalDependencyNodes = additionalDependencyNodesSetting || [];
332
957
  const ignoreSetting = validatedSettings[Settings_types_1.SETTINGS_KEYS_MAP.IGNORE];
333
- const ignorePaths = (0, Common_1.isString)(ignoreSetting) ? [ignoreSetting] : ignoreSetting;
958
+ const ignorePaths = (0, Shared_1.isString)(ignoreSetting) ? [ignoreSetting] : ignoreSetting;
334
959
  const includeSetting = validatedSettings[Settings_types_1.SETTINGS_KEYS_MAP.INCLUDE];
335
- const includePaths = (0, Common_1.isString)(includeSetting)
960
+ const includePaths = (0, Shared_1.isString)(includeSetting)
336
961
  ? [includeSetting]
337
962
  : includeSetting;
963
+ const debugSetting = validatedSettings[Settings_types_1.SETTINGS_KEYS_MAP.DEBUG];
338
964
  const descriptors = (0, Settings_1.transformLegacyTypes)(validatedSettings[ELEMENTS]);
339
- // NOTE: Filter valid descriptors only to avoid a breaking change for the moment
340
965
  const validDescriptors = descriptors.filter(elements_1.isElementDescriptor);
341
- const invalidDescriptors = descriptors.filter((desc) => !(0, elements_1.isElementDescriptor)(desc));
342
- if (invalidDescriptors.length > 0) {
343
- /*
344
- * TODO: Report invalid descriptors in ESLint context as a warning in a separate rule:
345
- * context.report({
346
- * message: `Some element descriptors are invalid and will be ignored: ${JSON.stringify(
347
- * invalidDescriptors,
348
- * )}`,
349
- * loc: { line: 1, column: 0 },
350
- * });
351
- */
352
- (0, Debug_1.warnOnce)(`Some element descriptors are invalid and will be ignored: ${JSON.stringify(invalidDescriptors)}`);
966
+ if (validDescriptors.length < descriptors.length) {
967
+ const invalidDescriptors = descriptors.filter((desc) => !(0, elements_1.isElementDescriptor)(desc));
968
+ (0, Debug_1.warnOnce)(`Some element descriptors are invalid and will be ignored.`, `Invalid descriptors:\n${JSON.stringify(invalidDescriptors)}.\n${(0, Helpers_1.moreInfoSettingsLink)()}`);
353
969
  }
354
970
  const result = {
355
971
  elementDescriptors: validDescriptors,
@@ -361,21 +977,18 @@ function getSettings(context) {
361
977
  legacyTemplates: validatedSettings[Settings_types_1.SETTINGS_KEYS_MAP.LEGACY_TEMPLATES] ??
362
978
  Settings_types_1.LEGACY_TEMPLATES_DEFAULT,
363
979
  cache: validatedSettings[Settings_types_1.SETTINGS_KEYS_MAP.CACHE] ?? Settings_types_1.CACHE_DEFAULT,
980
+ flagAsExternal: {
981
+ unresolvableAlias: validatedSettings[Settings_types_1.SETTINGS_KEYS_MAP.FLAG_AS_EXTERNAL]
982
+ ?.unresolvableAlias ?? true,
983
+ inNodeModules: validatedSettings[Settings_types_1.SETTINGS_KEYS_MAP.FLAG_AS_EXTERNAL]?.inNodeModules ??
984
+ true,
985
+ outsideRootPath: validatedSettings[Settings_types_1.SETTINGS_KEYS_MAP.FLAG_AS_EXTERNAL]
986
+ ?.outsideRootPath ?? false,
987
+ customSourcePatterns: validatedSettings[Settings_types_1.SETTINGS_KEYS_MAP.FLAG_AS_EXTERNAL]
988
+ ?.customSourcePatterns ?? [],
989
+ },
990
+ debug: debugSetting,
364
991
  };
992
+ trackedValidatedSettings.set(context.settings, result);
365
993
  return result;
366
994
  }
367
- function validateRules(settings, rules = [], options = {}) {
368
- const mainKey = (0, Helpers_1.rulesMainKey)(options.mainKey);
369
- for (const rule of rules) {
370
- //@ts-expect-error TODO: Add a different schema validation for each rule type, so keys are properly validated
371
- validateElementTypesMatcher([rule[mainKey]], settings);
372
- if (!options.onlyMainKey) {
373
- if (rule.allow) {
374
- validateElementTypesMatcher(rule.allow, settings);
375
- }
376
- if (rule.disallow) {
377
- validateElementTypesMatcher(rule.disallow, settings);
378
- }
379
- }
380
- }
381
- }