@boundaries/elements 1.0.0 → 1.1.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.
@@ -5,99 +5,6 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
5
5
  throw Error('Dynamic require of "' + x + '" is not supported');
6
6
  });
7
7
 
8
- // src/Cache/Cache.ts
9
- import objectHash from "object-hash";
10
- var CacheManager = class {
11
- /**
12
- * Internal cache map
13
- */
14
- _cache;
15
- /**
16
- * Creates a new CacheManager instance
17
- */
18
- constructor() {
19
- this._cache = /* @__PURE__ */ new Map();
20
- }
21
- /**
22
- * Generates a hashed key for the given cache key
23
- * @param key The cache key to hash
24
- * @returns The hashed key as a string
25
- */
26
- _getHashedKey(key) {
27
- return objectHash(key);
28
- }
29
- /**
30
- * Retrieves a value from the cache based on the given key
31
- * @param key The cache key to retrieve
32
- * @returns The cached value or undefined if not found
33
- */
34
- get(key) {
35
- const hashedKey = this._getHashedKey(key);
36
- return this._cache.get(hashedKey);
37
- }
38
- /**
39
- * Stores a value in the cache
40
- * @param key The cache key to store
41
- * @param value The value to cache
42
- */
43
- set(key, value) {
44
- const hashedKey = this._getHashedKey(key);
45
- this._cache.set(hashedKey, value);
46
- }
47
- /**
48
- * Restores a value in the cache from a given already hashed key
49
- * @param key The hashed key to restore
50
- * @param value The value to restore
51
- */
52
- restore(key, value) {
53
- this._cache.set(key, value);
54
- }
55
- /**
56
- * Checks if a value exists in the cache
57
- * @param key The cache key to check
58
- * @returns True if the value exists, false otherwise
59
- */
60
- has(key) {
61
- const hashedKey = this._getHashedKey(key);
62
- return this._cache.has(hashedKey);
63
- }
64
- /**
65
- * Retrieves all cached values
66
- * @returns A map of all cached values
67
- */
68
- getAll() {
69
- return this._cache;
70
- }
71
- /**
72
- * Clears the entire cache
73
- */
74
- clear() {
75
- this._cache.clear();
76
- }
77
- /**
78
- * Serializes the cache to a plain object.
79
- * @returns The serialized cache.
80
- */
81
- serialize() {
82
- return Array.from(this.getAll().entries()).reduce(
83
- (acc, [key, value]) => {
84
- acc[key] = value;
85
- return acc;
86
- },
87
- {}
88
- );
89
- }
90
- /**
91
- * Sets the cache from a serialized object.
92
- * @param serializedCache The serialized cache.
93
- */
94
- setFromSerialized(serializedCache) {
95
- for (const key in serializedCache) {
96
- this.restore(key, serializedCache[key]);
97
- }
98
- }
99
- };
100
-
101
8
  // src/Config/Config.ts
102
9
  var Config = class {
103
10
  /** The ignore paths */
@@ -106,6 +13,8 @@ var Config = class {
106
13
  _includePaths;
107
14
  /** Whether legacy template support is enabled */
108
15
  _legacyTemplates;
16
+ /** Whether the cache is enabled */
17
+ _cache;
109
18
  /**
110
19
  * Creates a new Config instance
111
20
  * @param options Configuration options
@@ -114,6 +23,7 @@ var Config = class {
114
23
  this._ignorePaths = options?.ignorePaths;
115
24
  this._includePaths = options?.includePaths;
116
25
  this._legacyTemplates = options?.legacyTemplates ?? true;
26
+ this._cache = options?.cache ?? true;
117
27
  }
118
28
  /**
119
29
  * The normalized configuration options
@@ -122,14 +32,38 @@ var Config = class {
122
32
  return {
123
33
  ignorePaths: this._ignorePaths,
124
34
  includePaths: this._includePaths,
35
+ legacyTemplates: this._legacyTemplates,
36
+ cache: this._cache
37
+ };
38
+ }
39
+ /**
40
+ * Normalized options for descriptors
41
+ */
42
+ get descriptorOptions() {
43
+ return {
44
+ ignorePaths: this._ignorePaths,
45
+ includePaths: this._includePaths,
46
+ cache: this._cache
47
+ };
48
+ }
49
+ /**
50
+ * Normalized options for element matchers
51
+ */
52
+ get matchersOptions() {
53
+ return {
125
54
  legacyTemplates: this._legacyTemplates
126
55
  };
127
56
  }
57
+ /**
58
+ * Whether caching is enabled
59
+ */
60
+ get cache() {
61
+ return this._cache;
62
+ }
128
63
  };
129
64
 
130
65
  // src/Matcher/BaseElementsMatcher.ts
131
66
  import Handlebars from "handlebars";
132
- import micromatch from "micromatch";
133
67
 
134
68
  // src/Support/TypeGuards.ts
135
69
  function isString(value) {
@@ -147,6 +81,9 @@ function isBoolean(value) {
147
81
  function isObject(value) {
148
82
  return !isNullish(value) && !isBoolean(value) && !isArray(value) && typeof value === "object";
149
83
  }
84
+ function isEmptyObject(obj) {
85
+ return isObject(obj) && Object.keys(obj).length === 0;
86
+ }
150
87
  function isArray(value) {
151
88
  return Array.isArray(value);
152
89
  }
@@ -199,8 +136,9 @@ function isElementSelectorData(value) {
199
136
  ]);
200
137
  }
201
138
  function isElementSelectorWithLegacyOptions(value) {
202
- return isArray(value) && value.length === 2 && isSimpleElementSelectorByType(value[0]) && // NOTE: Arrays of length 2 with captured values selector as second element having a key "type" or "category" will be treated as legacy options instead of two different selectors. We have to live with this limitation for now.
203
- isCapturedValuesSelector(value[1]);
139
+ return isArray(value) && (value.length === 2 && isSimpleElementSelectorByType(value[0]) && // NOTE: Arrays of length 2 with captured values selector as second element having a key "type" or "category" will be treated as legacy options instead of two different selectors. We have to live with this limitation for now.
140
+ isCapturedValuesSelector(value[1]) || // NOTE: Backwards compatibility: Allow arrays of length 1 with simple element selector. Some users might defined arrays without options.
141
+ value.length === 1 && isSimpleElementSelectorByType(value[0]));
204
142
  }
205
143
  function isElementSelector(value) {
206
144
  return isSimpleElementSelectorByType(value) || isElementSelectorData(value) || isElementSelectorWithLegacyOptions(value);
@@ -231,6 +169,8 @@ function isExternalLibrariesSelector(value) {
231
169
  }
232
170
 
233
171
  // src/Matcher/BaseElementsMatcher.ts
172
+ var HANDLEBARS_TEMPLATE_REGEX = /{{\s*[^}]+\s*}}/;
173
+ var LEGACY_TEMPLATE_REGEX = /\$\{([^}]+)\}/g;
234
174
  function normalizeSelector(selector) {
235
175
  if (isSimpleElementSelectorByType(selector)) {
236
176
  return { type: selector };
@@ -241,7 +181,7 @@ function normalizeSelector(selector) {
241
181
  if (isElementSelectorWithLegacyOptions(selector)) {
242
182
  return {
243
183
  type: selector[0],
244
- captured: { ...selector[1] }
184
+ captured: selector[1] ? { ...selector[1] } : void 0
245
185
  };
246
186
  }
247
187
  throw new Error("Invalid element selector");
@@ -256,12 +196,21 @@ function normalizeElementsSelector(elementsSelector) {
256
196
  return [normalizeSelector(elementsSelector)];
257
197
  }
258
198
  var BaseElementsMatcher = class {
199
+ /**
200
+ * Option to use legacy templates with ${} syntax.
201
+ */
259
202
  _legacyTemplates;
203
+ /**
204
+ * Micromatch instance for matching.
205
+ */
206
+ micromatch;
260
207
  /**
261
208
  * Creates a new BaseElementsMatcher.
262
209
  * @param config Configuration options for the matcher.
210
+ * @param globalCache Global cache instance.
263
211
  */
264
- constructor(config) {
212
+ constructor(config, micromatch2) {
213
+ this.micromatch = micromatch2;
265
214
  this._legacyTemplates = config.legacyTemplates;
266
215
  }
267
216
  /**
@@ -270,17 +219,30 @@ var BaseElementsMatcher = class {
270
219
  * @returns The converted template.
271
220
  */
272
221
  _getBackwardsCompatibleTemplate(template) {
273
- return template.replaceAll(/\$\{([^}]+)\}/g, "{{ $1 }}");
222
+ return template.replaceAll(LEGACY_TEMPLATE_REGEX, "{{ $1 }}");
223
+ }
224
+ /**
225
+ * Determines if a template contains Handlebars syntax.
226
+ * @param template The template to check.
227
+ * @returns True if the template contains Handlebars syntax, false otherwise.
228
+ */
229
+ _isHandlebarsTemplate(template) {
230
+ return HANDLEBARS_TEMPLATE_REGEX.test(template);
274
231
  }
275
232
  /**
276
233
  * Returns a rendered template using the provided template data.
234
+ * Optimized version with template caching for better performance.
277
235
  * @param template The template to render.
278
- * @param extraTemplateData The data to use for replace in the template.
236
+ * @param templateData The data to use for replace in the template.
279
237
  * @returns The rendered template.
280
238
  */
281
239
  _getRenderedTemplate(template, templateData) {
282
240
  const templateToUse = this._legacyTemplates ? this._getBackwardsCompatibleTemplate(template) : template;
283
- return Handlebars.compile(templateToUse)(templateData);
241
+ if (!this._isHandlebarsTemplate(templateToUse)) {
242
+ return template;
243
+ }
244
+ const compiledTemplate = Handlebars.compile(templateToUse);
245
+ return compiledTemplate(templateData);
284
246
  }
285
247
  /**
286
248
  * Returns rendered templates using the provided template data.
@@ -298,6 +260,7 @@ var BaseElementsMatcher = class {
298
260
  }
299
261
  /**
300
262
  * Returns whether the given value matches the micromatch pattern, converting non-string values to strings.
263
+ * Optimized version with caching for better performance.
301
264
  * @param value The value to check.
302
265
  * @param pattern The micromatch pattern to match against.
303
266
  * @returns Whether the value matches the pattern.
@@ -305,7 +268,28 @@ var BaseElementsMatcher = class {
305
268
  isMicromatchMatch(value, pattern) {
306
269
  const elementValueToCheck = !value || !isString(value) ? String(value) : value;
307
270
  const selectorValueToCheck = isArray(pattern) ? pattern.filter(Boolean) : pattern;
308
- return micromatch.isMatch(elementValueToCheck, selectorValueToCheck);
271
+ return this.micromatch.isMatch(elementValueToCheck, selectorValueToCheck);
272
+ }
273
+ /**
274
+ * Returns whether the given value matches the micromatch pattern after rendering it as a template.
275
+ * @param pattern The micromatch pattern to render and match against.
276
+ * @param templateData The data to use for rendering the pattern as a template.
277
+ * @param value The value to check.
278
+ * @returns Whether the value matches the rendered pattern.
279
+ */
280
+ isTemplateMicromatchMatch(pattern, templateData, value) {
281
+ if (isNullish(value)) {
282
+ return false;
283
+ }
284
+ const patternRendered = this.getRenderedTemplates(pattern, templateData);
285
+ if (!patternRendered) {
286
+ return false;
287
+ }
288
+ const filteredPattern = isArray(patternRendered) ? patternRendered.filter(Boolean) : patternRendered;
289
+ if (isArray(value)) {
290
+ return value.some((val) => this.isMicromatchMatch(val, filteredPattern));
291
+ }
292
+ return this.isMicromatchMatch(value, filteredPattern);
309
293
  }
310
294
  /**
311
295
  * Whether the given element key matches the selector key as booleans.
@@ -352,61 +336,34 @@ var BaseElementsMatcher = class {
352
336
  if (!selectorValue) {
353
337
  return false;
354
338
  }
355
- const selectorValueRendered = this.getRenderedTemplates(
356
- selectorValue,
357
- templateData
358
- );
359
- if (!selectorValueRendered) {
360
- return false;
361
- }
362
339
  if (!isObjectWithProperty(element, elementKey)) {
363
340
  return false;
364
341
  }
365
- if (isNullish(element[elementKey])) {
366
- return false;
367
- }
368
- return this.isMicromatchMatch(element[elementKey], selectorValueRendered);
342
+ return this.isTemplateMicromatchMatch(
343
+ selectorValue,
344
+ templateData,
345
+ element[elementKey]
346
+ );
369
347
  }
370
348
  };
371
349
 
372
350
  // src/Matcher/DependenciesMatcher.ts
373
351
  var DependenciesMatcher = class extends BaseElementsMatcher {
374
- /**
375
- * Cache to store previously described dependencies.
376
- */
377
- _cache;
378
352
  /**
379
353
  * Elements matcher to use for matching elements within dependencies.
380
354
  */
381
355
  _elementsMatcher;
382
356
  /**
383
357
  * Creates a new DependenciesMatcher.
358
+ * @param elementsMatcher Elements matcher to use for matching elements within dependencies.
359
+ * @param config Configuration options for the matcher.
360
+ * @param micromatch Micromatch instance for matching.
361
+ * @param globalCache Global cache instance.
384
362
  */
385
- constructor(elementsMatcher, config) {
386
- super(config);
387
- this._cache = new CacheManager();
363
+ constructor(elementsMatcher, config, micromatch2) {
364
+ super(config, micromatch2);
388
365
  this._elementsMatcher = elementsMatcher;
389
366
  }
390
- /**
391
- * Serializes the cache to a plain object.
392
- * @returns The serialized cache.
393
- */
394
- serializeCache() {
395
- return this._cache.serialize();
396
- }
397
- /**
398
- * Sets the cache from a serialized object.
399
- * @param serializedCache The serialized cache.
400
- */
401
- setCacheFromSerialized(serializedCache) {
402
- this._cache.setFromSerialized(serializedCache);
403
- }
404
- /**
405
- * Clears the cache.
406
- */
407
- clearCache() {
408
- this._cache.clear();
409
- }
410
367
  /**
411
368
  * Normalizes selector into DependencySelectorNormalized format, containing arrays of selectors data.
412
369
  * @param selector The dependency selector to normalize.
@@ -544,17 +501,11 @@ var DependenciesMatcher = class extends BaseElementsMatcher {
544
501
  if (!selector.relationship) {
545
502
  return true;
546
503
  }
547
- const renderedPattern = this.getRenderedTemplates(
504
+ return this.isTemplateMicromatchMatch(
548
505
  selector.relationship,
549
- templateData
506
+ templateData,
507
+ relationship
550
508
  );
551
- if (!renderedPattern) {
552
- return false;
553
- }
554
- if (!relationship) {
555
- return false;
556
- }
557
- return this.isMicromatchMatch(relationship, renderedPattern);
558
509
  }
559
510
  /**
560
511
  * Determines if the selector matches an specific kind
@@ -567,17 +518,7 @@ var DependenciesMatcher = class extends BaseElementsMatcher {
567
518
  if (!selector.kind) {
568
519
  return true;
569
520
  }
570
- const renderedPattern = this.getRenderedTemplates(
571
- selector.kind,
572
- templateData
573
- );
574
- if (!renderedPattern) {
575
- return false;
576
- }
577
- if (!kind) {
578
- return false;
579
- }
580
- return this.isMicromatchMatch(kind, renderedPattern);
521
+ return this.isTemplateMicromatchMatch(selector.kind, templateData, kind);
581
522
  }
582
523
  /**
583
524
  * Determines if the selector matches some of the specifiers
@@ -587,22 +528,13 @@ var DependenciesMatcher = class extends BaseElementsMatcher {
587
528
  * @returns Whether the selector matches some of the specifiers
588
529
  */
589
530
  _specifierMatches(selector, specifiers, templateData) {
590
- const specifierPattern = selector.specifiers;
591
- if (!specifierPattern) {
531
+ if (!selector.specifiers) {
592
532
  return true;
593
533
  }
594
- const renderedPattern = this.getRenderedTemplates(
595
- specifierPattern,
596
- templateData
597
- );
598
- if (!renderedPattern) {
599
- return false;
600
- }
601
- if (!specifiers) {
602
- return false;
603
- }
604
- return specifiers.some(
605
- (specifier) => this.isMicromatchMatch(specifier, renderedPattern)
534
+ return this.isTemplateMicromatchMatch(
535
+ selector.specifiers,
536
+ templateData,
537
+ specifiers
606
538
  );
607
539
  }
608
540
  /**
@@ -613,21 +545,14 @@ var DependenciesMatcher = class extends BaseElementsMatcher {
613
545
  * @returns Whether the selector matches the nodeKind
614
546
  */
615
547
  _nodeKindMatches(selector, nodeKind, templateData) {
616
- const nodeKindPattern = selector.nodeKind;
617
- if (!nodeKindPattern) {
548
+ if (!selector.nodeKind) {
618
549
  return true;
619
550
  }
620
- const renderedPattern = this.getRenderedTemplates(
621
- nodeKindPattern,
622
- templateData
551
+ return this.isTemplateMicromatchMatch(
552
+ selector.nodeKind,
553
+ templateData,
554
+ nodeKind
623
555
  );
624
- if (!renderedPattern) {
625
- return false;
626
- }
627
- if (!nodeKind) {
628
- return false;
629
- }
630
- return this.isMicromatchMatch(nodeKind, renderedPattern);
631
556
  }
632
557
  /**
633
558
  * Determines if the dependency description matches the selector for 'from'.
@@ -653,25 +578,17 @@ var DependenciesMatcher = class extends BaseElementsMatcher {
653
578
  * @returns Whether the dependency properties match the selector for 'to'.
654
579
  */
655
580
  _dependencyToPropertiesMatch(dependency, toSelector, templateData) {
656
- return toSelector.some((selectorData) => {
657
- return this._relationshipMatches(
658
- selectorData,
659
- dependency.dependency.relationship.to,
660
- templateData
661
- ) && this._kindMatches(
662
- selectorData,
663
- dependency.dependency.kind,
664
- templateData
665
- ) && this._nodeKindMatches(
666
- selectorData,
667
- dependency.dependency.nodeKind,
668
- templateData
669
- ) && this._specifierMatches(
670
- selectorData,
671
- dependency.dependency.specifiers,
672
- templateData
673
- );
674
- });
581
+ const dependencyInfo = dependency.dependency;
582
+ const relationshipTo = dependencyInfo.relationship.to;
583
+ const kind = dependencyInfo.kind;
584
+ const nodeKind = dependencyInfo.nodeKind;
585
+ const specifiers = dependencyInfo.specifiers;
586
+ for (const selectorData of toSelector) {
587
+ if (this._kindMatches(selectorData, kind, templateData) && this._nodeKindMatches(selectorData, nodeKind, templateData) && this._relationshipMatches(selectorData, relationshipTo, templateData) && this._specifierMatches(selectorData, specifiers, templateData)) {
588
+ return true;
589
+ }
590
+ }
591
+ return false;
675
592
  }
676
593
  /**
677
594
  * Returns the selectors matching result for the given dependency.
@@ -684,29 +601,18 @@ var DependenciesMatcher = class extends BaseElementsMatcher {
684
601
  extraTemplateData = {},
685
602
  dependencySelectorsGlobals = {}
686
603
  } = {}) {
687
- if (this._cache.has({
688
- dependency,
689
- selector,
690
- extraTemplateData,
691
- dependencySelectorsGlobals
692
- })) {
693
- return this._cache.get({
694
- dependency,
695
- selector,
696
- extraTemplateData,
697
- dependencySelectorsGlobals
698
- });
699
- }
700
604
  const normalizedSelector = this._normalizeDependencySelector(
701
605
  selector,
702
606
  dependencySelectorsGlobals
703
607
  );
608
+ const fromExtraData = extraTemplateData.from || {};
609
+ const toExtraData = extraTemplateData.to || {};
704
610
  const templateData = {
705
611
  ...extraTemplateData,
706
612
  from: {
707
613
  ...dependency.from,
708
614
  relationship: dependency.dependency.relationship.from,
709
- ...extraTemplateData.from || {}
615
+ ...fromExtraData
710
616
  },
711
617
  to: {
712
618
  ...dependency.to,
@@ -714,7 +620,7 @@ var DependenciesMatcher = class extends BaseElementsMatcher {
714
620
  kind: dependency.dependency.kind,
715
621
  nodeKind: dependency.dependency.nodeKind,
716
622
  specifiers: dependency.dependency.specifiers,
717
- ...extraTemplateData.to || {}
623
+ ...toExtraData
718
624
  }
719
625
  };
720
626
  const result = this._getSelectorMatching(
@@ -722,15 +628,6 @@ var DependenciesMatcher = class extends BaseElementsMatcher {
722
628
  normalizedSelector,
723
629
  templateData
724
630
  );
725
- this._cache.set(
726
- {
727
- dependency,
728
- selector,
729
- extraTemplateData,
730
- dependencySelectorsGlobals
731
- },
732
- result
733
- );
734
631
  return result;
735
632
  }
736
633
  /**
@@ -751,38 +648,17 @@ var DependenciesMatcher = class extends BaseElementsMatcher {
751
648
  };
752
649
 
753
650
  // src/Matcher/ElementsMatcher.ts
754
- import micromatch2 from "micromatch";
755
651
  var ElementsMatcher = class extends BaseElementsMatcher {
756
- /**
757
- * Cache to store previously described elements.
758
- */
759
- _cache;
652
+ /** Whether the cache is enabled or not */
653
+ _cacheIsEnabled;
760
654
  /**
761
655
  * Creates a new ElementsSelectorMatcher.
656
+ * @param config Configuration options for the matcher.
657
+ * @param micromatch Micromatch instance for matching.
658
+ * @param globalCache Global cache instance.
762
659
  */
763
- constructor(config) {
764
- super(config);
765
- this._cache = new CacheManager();
766
- }
767
- /**
768
- * Serializes the cache to a plain object.
769
- * @returns The serialized cache.
770
- */
771
- serializeCache() {
772
- return this._cache.serialize();
773
- }
774
- /**
775
- * Sets the cache from a serialized object.
776
- * @param serializedCache The serialized cache.
777
- */
778
- setCacheFromSerialized(serializedCache) {
779
- this._cache.setFromSerialized(serializedCache);
780
- }
781
- /**
782
- * Clears the cache.
783
- */
784
- clearCache() {
785
- this._cache.clear();
660
+ constructor(config, micromatch2) {
661
+ super(config, micromatch2);
786
662
  }
787
663
  /**
788
664
  * Whether the given element type matches the selector type.
@@ -928,13 +804,13 @@ var ElementsMatcher = class extends BaseElementsMatcher {
928
804
  * @returns True if the captured values match, false otherwise.
929
805
  */
930
806
  _isCapturedValuesMatch(element, selector, templateData) {
931
- if (!selector.captured) {
807
+ if (!selector.captured || isEmptyObject(selector.captured)) {
932
808
  return true;
933
809
  }
934
810
  if (!element.captured) {
935
811
  return false;
936
812
  }
937
- return Object.entries(selector.captured).every(([key, pattern]) => {
813
+ for (const [key, pattern] of Object.entries(selector.captured)) {
938
814
  const elementValue = element.captured?.[key];
939
815
  if (!elementValue) {
940
816
  return false;
@@ -944,8 +820,12 @@ var ElementsMatcher = class extends BaseElementsMatcher {
944
820
  return false;
945
821
  }
946
822
  const filteredPattern = isArray(renderedPattern) ? renderedPattern.filter(Boolean) : renderedPattern;
947
- return micromatch2.isMatch(elementValue, filteredPattern);
948
- });
823
+ const isMatch = this.micromatch.isMatch(elementValue, filteredPattern);
824
+ if (!isMatch) {
825
+ return false;
826
+ }
827
+ }
828
+ return true;
949
829
  }
950
830
  /**
951
831
  * Determines if the isIgnored property of the element matches that in the selector.
@@ -982,17 +862,16 @@ var ElementsMatcher = class extends BaseElementsMatcher {
982
862
  * @param extraTemplateData Extra template data to use for matching.
983
863
  * @returns The selector matching result for the given element, or null if none matches.
984
864
  */
985
- _getSelectorMatching(element, selector, extraTemplateData) {
986
- const selectorsData = normalizeElementsSelector(selector);
865
+ _getSelectorMatching(element, selectorsData, extraTemplateData) {
987
866
  const templateData = {
988
867
  element,
989
868
  ...extraTemplateData
990
869
  };
991
870
  for (const selectorData of selectorsData) {
992
- const isMatch = this._isTypeMatch(element, selectorData, templateData) && this._isCategoryMatch(element, selectorData, templateData) && this._isCapturedValuesMatch(element, selectorData, templateData) && this._isPathMatch(element, selectorData, templateData) && this._isElementPathMatch(element, selectorData, templateData) && this._isInternalPathMatch(element, selectorData, templateData) && this._isOriginMatch(element, selectorData, templateData) && this._isSourceMatch(element, selectorData, templateData) && this._isBaseSourceMatch(element, selectorData, templateData) && this._isIgnoredMatch(element, selectorData) && this._isUnknownMatch(element, selectorData);
993
- if (isMatch) {
994
- return selectorData;
871
+ if (!this._isTypeMatch(element, selectorData, templateData) || !this._isCategoryMatch(element, selectorData, templateData) || !this._isOriginMatch(element, selectorData, templateData) || !this._isIgnoredMatch(element, selectorData) || !this._isUnknownMatch(element, selectorData) || !this._isPathMatch(element, selectorData, templateData) || !this._isElementPathMatch(element, selectorData, templateData) || !this._isInternalPathMatch(element, selectorData, templateData) || !this._isSourceMatch(element, selectorData, templateData) || !this._isBaseSourceMatch(element, selectorData, templateData) || !this._isCapturedValuesMatch(element, selectorData, templateData)) {
872
+ continue;
995
873
  }
874
+ return selectorData;
996
875
  }
997
876
  return null;
998
877
  }
@@ -1005,31 +884,8 @@ var ElementsMatcher = class extends BaseElementsMatcher {
1005
884
  * @returns The selector matching result for the given element, or null if none matches.
1006
885
  */
1007
886
  getSelectorMatching(element, selector, { extraTemplateData = {} } = {}) {
1008
- if (this._cache.has({
1009
- element,
1010
- selector,
1011
- extraTemplateData
1012
- })) {
1013
- return this._cache.get({
1014
- element,
1015
- selector,
1016
- extraTemplateData
1017
- });
1018
- }
1019
- const result = this._getSelectorMatching(
1020
- element,
1021
- selector,
1022
- extraTemplateData
1023
- );
1024
- this._cache.set(
1025
- {
1026
- element,
1027
- selector,
1028
- extraTemplateData
1029
- },
1030
- result
1031
- );
1032
- return result;
887
+ const selectorsData = normalizeElementsSelector(selector);
888
+ return this._getSelectorMatching(element, selectorsData, extraTemplateData);
1033
889
  }
1034
890
  /**
1035
891
  * Returns whether the given element matches the selector.
@@ -1122,11 +978,14 @@ function isCoreDependencyElement(value) {
1122
978
  // src/Descriptor/DependenciesDescriptor.types.ts
1123
979
  var DEPENDENCY_KIND_TYPE = "type";
1124
980
  var DEPENDENCY_KIND_VALUE = "value";
981
+ var DEPENDENCY_KIND_TYPEOF = "typeof";
1125
982
  var DEPENDENCY_KINDS_MAP = {
1126
983
  /** Type import, e.g., `import type { X } from 'module'` */
1127
984
  TYPE: DEPENDENCY_KIND_TYPE,
1128
985
  /** Value import, e.g., `import { X } from 'module'` */
1129
- VALUE: DEPENDENCY_KIND_VALUE
986
+ VALUE: DEPENDENCY_KIND_VALUE,
987
+ /** typeof import, e.g. `type ModuleType = typeof import("./my_module");` */
988
+ TYPE_OF: DEPENDENCY_KIND_TYPEOF
1130
989
  };
1131
990
  var DEPENDENCY_RELATIONSHIPS_MAP = {
1132
991
  /** The dependency is internal to the element */
@@ -1179,22 +1038,173 @@ function isInternalDependency(dependency) {
1179
1038
  return dependency.dependency.relationship.to === DEPENDENCY_RELATIONSHIPS_MAP.INTERNAL;
1180
1039
  }
1181
1040
 
1041
+ // src/Cache/Cache.ts
1042
+ var CacheManager = class {
1043
+ /**
1044
+ * Internal cache map
1045
+ */
1046
+ _cache;
1047
+ /**
1048
+ * Creates a new CacheManager instance
1049
+ */
1050
+ constructor() {
1051
+ this._cache = /* @__PURE__ */ new Map();
1052
+ }
1053
+ /**
1054
+ * Generates a string key from the given cache key. Has to be implemented for non-string keys.
1055
+ * @param key The cache key to generate from
1056
+ * @returns The generated string key
1057
+ */
1058
+ generateKey(key) {
1059
+ if (isString(key)) {
1060
+ return key;
1061
+ }
1062
+ const errorMessage = "Cache key generation for non-string keys is not implemented because it causes performance issues: " + JSON.stringify(key);
1063
+ throw new Error(errorMessage);
1064
+ }
1065
+ /**
1066
+ * Generates a hashed key for the given cache key
1067
+ * @param key The cache key to hash
1068
+ * @returns The hashed key as a string
1069
+ */
1070
+ getKey(key) {
1071
+ return this.generateKey(key);
1072
+ }
1073
+ /**
1074
+ * Retrieves a value from the cache based on the given hashed key
1075
+ * @param hashedKey The hashed key to retrieve
1076
+ * @returns The cached value or undefined if not found
1077
+ */
1078
+ get(hashedKey) {
1079
+ return this._cache.get(hashedKey);
1080
+ }
1081
+ /**
1082
+ * Stores a value in the cache with a given hashed key
1083
+ * @param hashedKey The hashed key to store
1084
+ * @param value The value to cache
1085
+ */
1086
+ set(hashedKey, value) {
1087
+ this._cache.set(hashedKey, value);
1088
+ }
1089
+ /**
1090
+ * Checks if a value exists in the cache based on the given hashed key
1091
+ * @param hashedKey The hashed key to check
1092
+ * @returns True if the value exists, false otherwise
1093
+ */
1094
+ has(hashedKey) {
1095
+ return this._cache.has(hashedKey);
1096
+ }
1097
+ /**
1098
+ * Retrieves all cached values
1099
+ * @returns A map of all cached values
1100
+ */
1101
+ getAll() {
1102
+ return this._cache;
1103
+ }
1104
+ /**
1105
+ * Clears the entire cache
1106
+ */
1107
+ clear() {
1108
+ this._cache.clear();
1109
+ }
1110
+ /**
1111
+ * Serializes the cache to a plain object.
1112
+ * @returns The serialized cache.
1113
+ */
1114
+ serialize() {
1115
+ return Array.from(this.getAll().entries()).reduce(
1116
+ (acc, [key, value]) => {
1117
+ acc[key] = value;
1118
+ return acc;
1119
+ },
1120
+ {}
1121
+ );
1122
+ }
1123
+ /**
1124
+ * Sets the cache from a serialized object.
1125
+ * @param serializedCache The serialized cache.
1126
+ */
1127
+ setFromSerialized(serializedCache) {
1128
+ for (const key in serializedCache) {
1129
+ this.set(key, serializedCache[key]);
1130
+ }
1131
+ }
1132
+ };
1133
+
1134
+ // src/Cache/CacheDisabled.ts
1135
+ var CacheManagerDisabled = class extends CacheManager {
1136
+ /**
1137
+ * Generates a fake cache key as caching is disabled
1138
+ * @param key The cache key to hash
1139
+ * @returns An empty string
1140
+ */
1141
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1142
+ getKey(_key) {
1143
+ return "";
1144
+ }
1145
+ /**
1146
+ * Does nothing as caching is disabled
1147
+ * @param hashedKey The hashed key to retrieve
1148
+ * @returns Undefined as caching is disabled
1149
+ */
1150
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1151
+ get(_hashedKey) {
1152
+ return void 0;
1153
+ }
1154
+ /**
1155
+ * Does nothing as caching is disabled
1156
+ * @param hashedKey The hashed key to store
1157
+ * @param value The value to cache
1158
+ */
1159
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1160
+ set(_hashedKey, _value) {
1161
+ return;
1162
+ }
1163
+ /**
1164
+ * Does nothing as caching is disabled
1165
+ * @param hashedKey The hashed key to check
1166
+ * @returns False as caching is disabled
1167
+ */
1168
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1169
+ has(_hashedKey) {
1170
+ return false;
1171
+ }
1172
+ };
1173
+
1174
+ // src/Descriptor/DependenciesDescriptionsCache.ts
1175
+ var DependenciesDescriptionsCache = class extends CacheManager {
1176
+ /** Generates a unique key for the given dependency description options.
1177
+ * @param options The options to generate the key from.
1178
+ * @returns The generated key.
1179
+ */
1180
+ generateKey(options) {
1181
+ return `${options.from}|${options.to}|${options.source}|${options.kind}|${options.nodeKind}|${options.specifiers ? options.specifiers.join(",") : ""}`;
1182
+ }
1183
+ };
1184
+
1182
1185
  // src/Descriptor/DependenciesDescriptor.ts
1183
1186
  var DependenciesDescriptor = class {
1184
1187
  /**
1185
1188
  * Cache to store previously described dependencies.
1186
1189
  */
1187
- _dependenciesCache = new CacheManager();
1190
+ _dependenciesCache;
1188
1191
  /**
1189
1192
  * Elements descriptor instance.
1190
1193
  */
1191
1194
  _elementsDescriptor;
1195
+ /**
1196
+ * Configuration options.
1197
+ */
1198
+ _config;
1192
1199
  /**
1193
1200
  * Creates a new DependenciesDescriptor instance.
1194
1201
  * @param elementsDescriptor The elements descriptor instance.
1202
+ * @param config The configuration options.
1195
1203
  */
1196
- constructor(elementsDescriptor) {
1204
+ constructor(elementsDescriptor, config) {
1197
1205
  this._elementsDescriptor = elementsDescriptor;
1206
+ this._config = config;
1207
+ this._dependenciesCache = this._config.cache ? new DependenciesDescriptionsCache() : new CacheManagerDisabled();
1198
1208
  }
1199
1209
  /**
1200
1210
  * Serializes the elements cache to a plain object.
@@ -1345,22 +1355,16 @@ var DependenciesDescriptor = class {
1345
1355
  nodeKind,
1346
1356
  specifiers
1347
1357
  }) {
1348
- if (this._dependenciesCache.has({
1358
+ const cacheKey = this._dependenciesCache.getKey({
1349
1359
  from,
1350
1360
  to,
1351
1361
  source,
1352
1362
  kind,
1353
1363
  nodeKind,
1354
1364
  specifiers
1355
- })) {
1356
- return this._dependenciesCache.get({
1357
- from,
1358
- to,
1359
- source,
1360
- kind,
1361
- nodeKind,
1362
- specifiers
1363
- });
1365
+ });
1366
+ if (this._dependenciesCache.has(cacheKey)) {
1367
+ return this._dependenciesCache.get(cacheKey);
1364
1368
  }
1365
1369
  const fromElement = this._elementsDescriptor.describeElement(from);
1366
1370
  const toElement = this._elementsDescriptor.describeDependencyElement(
@@ -1377,25 +1381,14 @@ var DependenciesDescriptor = class {
1377
1381
  specifiers: specifiers || null
1378
1382
  }
1379
1383
  };
1380
- this._dependenciesCache.set(
1381
- {
1382
- from,
1383
- to,
1384
- source,
1385
- kind,
1386
- nodeKind,
1387
- specifiers
1388
- },
1389
- result
1390
- );
1384
+ this._dependenciesCache.set(cacheKey, result);
1391
1385
  return result;
1392
1386
  }
1393
1387
  };
1394
1388
 
1395
1389
  // src/Descriptor/ElementsDescriptor.ts
1396
1390
  import isCoreModule from "is-core-module";
1397
- import micromatch3 from "micromatch";
1398
- var UNKNOWN_LOCAL_ELEMENT = {
1391
+ var UNKNOWN_ELEMENT = {
1399
1392
  path: null,
1400
1393
  elementPath: null,
1401
1394
  internalPath: null,
@@ -1409,16 +1402,18 @@ var UNKNOWN_LOCAL_ELEMENT = {
1409
1402
  isIgnored: false,
1410
1403
  isUnknown: true
1411
1404
  };
1405
+ var SCOPED_PACKAGE_REGEX = /^@[^/]*\/?[^/]+/;
1406
+ var EXTERNAL_PATH_REGEX = /^\w/;
1412
1407
  var ElementsDescriptor = class {
1413
1408
  _mod = null;
1414
1409
  /**
1415
1410
  * Cache to store previously described elements.
1416
1411
  */
1417
- _elementsCache = new CacheManager();
1412
+ _descriptionsCache;
1418
1413
  /**
1419
1414
  * Cache to store previously described files.
1420
1415
  */
1421
- _filesCache = new CacheManager();
1416
+ _filesCache;
1422
1417
  /**
1423
1418
  * Configuration instance for this descriptor.
1424
1419
  */
@@ -1427,15 +1422,22 @@ var ElementsDescriptor = class {
1427
1422
  * Element descriptors used by this descriptor.
1428
1423
  */
1429
1424
  _elementDescriptors;
1425
+ /** Micromatch instance for path matching */
1426
+ _micromatch;
1430
1427
  /**
1431
1428
  * The configuration options for this descriptor.
1432
1429
  * @param elementDescriptors The element descriptors.
1433
1430
  * @param configOptions The configuration options.
1431
+ * @param globalCache The global cache for various caching needs.
1432
+ * @param micromatch The micromatch instance for path matching.
1434
1433
  */
1435
- constructor(elementDescriptors, configOptions) {
1434
+ constructor(elementDescriptors, configOptions, micromatch2) {
1435
+ this._micromatch = micromatch2;
1436
1436
  this._elementDescriptors = elementDescriptors;
1437
1437
  this._validateDescriptors(elementDescriptors);
1438
- this._config = new Config(configOptions);
1438
+ this._config = configOptions;
1439
+ this._filesCache = this._config.cache ? new CacheManager() : new CacheManagerDisabled();
1440
+ this._descriptionsCache = this._config.cache ? new CacheManager() : new CacheManagerDisabled();
1439
1441
  this._loadModuleInNode();
1440
1442
  }
1441
1443
  /**
@@ -1443,20 +1445,24 @@ var ElementsDescriptor = class {
1443
1445
  * @returns The serialized elements cache.
1444
1446
  */
1445
1447
  serializeCache() {
1446
- return this._elementsCache.serialize();
1448
+ return {
1449
+ descriptions: this._descriptionsCache.serialize(),
1450
+ files: this._filesCache.serialize()
1451
+ };
1447
1452
  }
1448
1453
  /**
1449
1454
  * Sets the elements cache from a serialized object.
1450
1455
  * @param serializedCache The serialized elements cache.
1451
1456
  */
1452
1457
  setCacheFromSerialized(serializedCache) {
1453
- this._elementsCache.setFromSerialized(serializedCache);
1458
+ this._descriptionsCache.setFromSerialized(serializedCache.descriptions);
1459
+ this._filesCache.setFromSerialized(serializedCache.files);
1454
1460
  }
1455
1461
  /**
1456
1462
  * Clears the elements cache.
1457
1463
  */
1458
1464
  clearCache() {
1459
- this._elementsCache.clear();
1465
+ this._descriptionsCache.clear();
1460
1466
  this._filesCache.clear();
1461
1467
  }
1462
1468
  /**
@@ -1500,7 +1506,7 @@ var ElementsDescriptor = class {
1500
1506
  * @returns True if the dependency source is scoped, false otherwise.
1501
1507
  */
1502
1508
  _dependencySourceIsScoped(dependencySource) {
1503
- return /^@[^/]*\/?[^/]+/.test(dependencySource);
1509
+ return SCOPED_PACKAGE_REGEX.test(dependencySource);
1504
1510
  }
1505
1511
  /**
1506
1512
  * Determines if a dependency source is external or an alias.
@@ -1508,14 +1514,14 @@ var ElementsDescriptor = class {
1508
1514
  * @returns True if the dependency source is external or an alias, false otherwise.
1509
1515
  */
1510
1516
  _dependencySourceIsExternalOrScoped(dependencySource) {
1511
- return /^\w/.test(dependencySource) || this._dependencySourceIsScoped(dependencySource);
1517
+ return EXTERNAL_PATH_REGEX.test(dependencySource) || this._dependencySourceIsScoped(dependencySource);
1512
1518
  }
1513
1519
  /**
1514
1520
  * Gets the base source of an external module.
1515
1521
  * @param dependencySource The source of the dependency to check.
1516
1522
  * @returns The base source of the external module. (e.g., for "@scope/package/submodule", it returns "@scope/package")
1517
1523
  */
1518
- _getExternalModuleBaseSource(dependencySource) {
1524
+ _getExternalOrCoreModuleBaseSource(dependencySource) {
1519
1525
  if (this._dependencySourceIsScoped(dependencySource)) {
1520
1526
  const [scope, packageName] = dependencySource.split("/");
1521
1527
  return `${scope}/${packageName}`;
@@ -1538,27 +1544,31 @@ var ElementsDescriptor = class {
1538
1544
  }
1539
1545
  /**
1540
1546
  * Determines if a given path is included based on the configuration.
1547
+ * Uses caching for better performance on repeated calls.
1541
1548
  * @param elementPath The element path to check.
1549
+ * @param includeExternal Whether to include external files.
1542
1550
  * @returns True if the path is included, false otherwise.
1543
1551
  */
1544
- _pathIsIncluded(elementPath, includeExternal) {
1545
- const isExternal = includeExternal ? micromatch3.isMatch(elementPath, "**/node_modules/**") : false;
1546
- if (this._config.options.includePaths && this._config.options.ignorePaths) {
1547
- const isIncluded = micromatch3.isMatch(
1552
+ _pathIsIncluded(elementPath) {
1553
+ let result;
1554
+ if (this._config.includePaths && this._config.ignorePaths) {
1555
+ const isIncluded = this._micromatch.isMatch(
1548
1556
  elementPath,
1549
- this._config.options.includePaths
1557
+ this._config.includePaths
1550
1558
  );
1551
- const isIgnored = micromatch3.isMatch(
1559
+ const isIgnored = this._micromatch.isMatch(
1552
1560
  elementPath,
1553
- this._config.options.ignorePaths
1561
+ this._config.ignorePaths
1554
1562
  );
1555
- return (isIncluded || isExternal) && !isIgnored;
1556
- } else if (this._config.options.includePaths) {
1557
- return micromatch3.isMatch(elementPath, this._config.options.includePaths) || isExternal;
1558
- } else if (this._config.options.ignorePaths) {
1559
- return !micromatch3.isMatch(elementPath, this._config.options.ignorePaths);
1563
+ result = isIncluded && !isIgnored;
1564
+ } else if (this._config.includePaths) {
1565
+ result = this._micromatch.isMatch(elementPath, this._config.includePaths);
1566
+ } else if (this._config.ignorePaths) {
1567
+ result = !this._micromatch.isMatch(elementPath, this._config.ignorePaths);
1568
+ } else {
1569
+ result = true;
1560
1570
  }
1561
- return true;
1571
+ return result;
1562
1572
  }
1563
1573
  /**
1564
1574
  * Gets captured values from the captured array and capture configuration.
@@ -1585,16 +1595,15 @@ var ElementsDescriptor = class {
1585
1595
  * @returns The element path.
1586
1596
  */
1587
1597
  _getElementPath(pathPattern, pathSegments, allPathSegments) {
1588
- const elementPathRegexp = micromatch3.makeRe(pathPattern);
1598
+ const elementPathRegexp = this._micromatch.makeRe(pathPattern);
1589
1599
  const testedSegments = [];
1590
1600
  let result;
1591
1601
  for (const pathSegment of pathSegments) {
1592
- if (!result) {
1593
- testedSegments.push(pathSegment);
1594
- const joinedSegments = testedSegments.join("/");
1595
- if (elementPathRegexp.test(joinedSegments)) {
1596
- result = joinedSegments;
1597
- }
1602
+ testedSegments.push(pathSegment);
1603
+ const joinedSegments = testedSegments.join("/");
1604
+ if (elementPathRegexp.test(joinedSegments)) {
1605
+ result = joinedSegments;
1606
+ break;
1598
1607
  }
1599
1608
  }
1600
1609
  return `${[...allPathSegments].reverse().join("/").split(result)[0]}${result}`;
@@ -1611,20 +1620,18 @@ var ElementsDescriptor = class {
1611
1620
  for (const pattern of patterns) {
1612
1621
  const useFullPathMatch = mode === ELEMENT_DESCRIPTOR_MODES_MAP.FULL && !alreadyMatched;
1613
1622
  const effectivePattern = mode === ELEMENT_DESCRIPTOR_MODES_MAP.FOLDER && !alreadyMatched ? `${pattern}/**/*` : pattern;
1623
+ const targetPath = useFullPathMatch ? filePath : currentPathSegments.join("/");
1614
1624
  let baseCapture = null;
1615
1625
  let hasCapture = true;
1616
1626
  if (elementDescriptor.basePattern) {
1617
1627
  const baseTarget = filePath.split("/").slice(0, filePath.split("/").length - lastPathSegmentMatching).join("/");
1618
- baseCapture = micromatch3.capture(
1628
+ baseCapture = this._micromatch.capture(
1619
1629
  [elementDescriptor.basePattern, "**", effectivePattern].join("/"),
1620
1630
  baseTarget
1621
1631
  );
1622
1632
  hasCapture = baseCapture !== null;
1623
1633
  }
1624
- const capture = micromatch3.capture(
1625
- effectivePattern,
1626
- useFullPathMatch ? filePath : currentPathSegments.join("/")
1627
- );
1634
+ const capture = this._micromatch.capture(effectivePattern, targetPath);
1628
1635
  if (capture && hasCapture) {
1629
1636
  return {
1630
1637
  matched: true,
@@ -1638,22 +1645,19 @@ var ElementsDescriptor = class {
1638
1645
  return { matched: false };
1639
1646
  }
1640
1647
  /**
1641
- * Retrieves the description of an element given its path.
1642
- * It does not identify external files. Files not matching any element are considered unknown.
1643
- * If a file in node_modules does a match, it is considered local as well.
1644
- * @param includeExternal Whether to include external files (inside node_modules) in the matching process.
1648
+ * Retrieves the description of a local file given its path.
1645
1649
  * @param elementPath The path of the element to describe.
1646
1650
  * @returns The description of the element.
1647
1651
  */
1648
- _getFileDescription(includeExternal, filePath) {
1652
+ _getFileDescription(filePath) {
1649
1653
  if (!filePath) {
1650
1654
  return {
1651
- ...UNKNOWN_LOCAL_ELEMENT
1655
+ ...UNKNOWN_ELEMENT
1652
1656
  };
1653
1657
  }
1654
- if (!this._pathIsIncluded(filePath, includeExternal)) {
1658
+ if (!this._pathIsIncluded(filePath)) {
1655
1659
  return {
1656
- ...UNKNOWN_LOCAL_ELEMENT,
1660
+ ...UNKNOWN_ELEMENT,
1657
1661
  path: filePath,
1658
1662
  isIgnored: true,
1659
1663
  origin: null
@@ -1709,13 +1713,14 @@ var ElementsDescriptor = class {
1709
1713
  for (let i = 0; i < pathSegments.length; i++) {
1710
1714
  const segment = pathSegments[i];
1711
1715
  state.pathSegmentsAccumulator.unshift(segment);
1716
+ const alreadyHasMainElement = Boolean(elementResult.type) || Boolean(elementResult.category);
1712
1717
  for (const elementDescriptor of this._elementDescriptors) {
1713
1718
  const match = this._fileDescriptorMatch({
1714
1719
  elementDescriptor,
1715
1720
  filePath,
1716
1721
  currentPathSegments: state.pathSegmentsAccumulator,
1717
1722
  lastPathSegmentMatching: state.lastPathSegmentMatching,
1718
- alreadyMatched: Boolean(elementResult.type) || Boolean(elementResult.category)
1723
+ alreadyMatched: alreadyHasMainElement
1719
1724
  });
1720
1725
  if (match.matched) {
1721
1726
  processElementMatch(
@@ -1733,7 +1738,7 @@ var ElementsDescriptor = class {
1733
1738
  const result = { ...elementResult, parents };
1734
1739
  if (!isKnownLocalElement(result)) {
1735
1740
  return {
1736
- ...UNKNOWN_LOCAL_ELEMENT,
1741
+ ...UNKNOWN_ELEMENT,
1737
1742
  path: filePath
1738
1743
  };
1739
1744
  }
@@ -1745,35 +1750,30 @@ var ElementsDescriptor = class {
1745
1750
  * @param filePath The path of the file to describe.
1746
1751
  * @returns The description of the element.
1747
1752
  */
1748
- _describeFile(includeExternal, filePath) {
1749
- if (this._filesCache.has(String(filePath))) {
1750
- return this._filesCache.get(String(filePath));
1753
+ _describeFile(filePath) {
1754
+ const cacheKey = this._filesCache.getKey(String(filePath));
1755
+ if (this._filesCache.has(cacheKey)) {
1756
+ return this._filesCache.get(cacheKey);
1751
1757
  }
1752
- const description = this._getFileDescription(includeExternal, filePath);
1753
- this._filesCache.set(String(filePath), description);
1758
+ const description = this._getFileDescription(filePath);
1759
+ this._filesCache.set(cacheKey, description);
1754
1760
  return description;
1755
1761
  }
1756
1762
  /**
1757
- * Describes a dependency element given the file element and dependency source, by completing the file description.
1758
- * @param element The file element to complete the description for.
1763
+ * Returns an external or core dependency element given its dependency source and file path.
1759
1764
  * @param dependencySource The source of the dependency.
1760
- * @returns The description of the dependency element.
1765
+ * @param filePath The resolved file path of the dependency, if known.
1766
+ * @returns The external or core dependency element, or null if it is a local dependency.
1761
1767
  */
1762
- _describeDependencyElement(element, dependencySource) {
1763
- if (isIgnoredElement(element)) {
1764
- return {
1765
- ...element,
1766
- source: dependencySource
1767
- };
1768
- }
1769
- const baseDependencySource = this._getExternalModuleBaseSource(dependencySource);
1768
+ _getExternalOrCoreDependencyElement(dependencySource, filePath) {
1769
+ const baseDependencySource = this._getExternalOrCoreModuleBaseSource(dependencySource);
1770
1770
  const isCore = this._dependencySourceIsCoreModule(
1771
1771
  dependencySource,
1772
1772
  baseDependencySource
1773
1773
  );
1774
1774
  if (isCore) {
1775
1775
  const coreElement = {
1776
- ...element,
1776
+ ...UNKNOWN_ELEMENT,
1777
1777
  source: dependencySource,
1778
1778
  baseSource: baseDependencySource,
1779
1779
  origin: ELEMENT_ORIGINS_MAP.CORE
@@ -1781,44 +1781,38 @@ var ElementsDescriptor = class {
1781
1781
  return coreElement;
1782
1782
  }
1783
1783
  const isExternal = this._isExternalDependency(
1784
- element.path,
1784
+ filePath || null,
1785
1785
  dependencySource
1786
1786
  );
1787
- if (!isExternal) {
1788
- const localElement = {
1789
- ...element,
1790
- source: dependencySource
1787
+ if (isExternal) {
1788
+ const externalElement = {
1789
+ ...UNKNOWN_ELEMENT,
1790
+ path: filePath || null,
1791
+ internalPath: dependencySource.replace(baseDependencySource, ""),
1792
+ source: dependencySource,
1793
+ baseSource: baseDependencySource,
1794
+ origin: ELEMENT_ORIGINS_MAP.EXTERNAL
1791
1795
  };
1792
- return localElement;
1793
- }
1794
- const externalElement = {
1795
- ...element,
1796
- internalPath: dependencySource.replace(baseDependencySource, ""),
1797
- source: dependencySource,
1798
- baseSource: baseDependencySource,
1799
- origin: ELEMENT_ORIGINS_MAP.EXTERNAL
1800
- };
1801
- return externalElement;
1796
+ return externalElement;
1797
+ }
1798
+ return null;
1802
1799
  }
1803
1800
  _describeElement(filePath, dependencySource) {
1804
- if (this._elementsCache.has({
1805
- dependencySource,
1806
- filePath: String(filePath)
1807
- })) {
1808
- return this._elementsCache.get({
1809
- dependencySource,
1810
- filePath: String(filePath)
1811
- });
1812
- }
1813
- const fileDescription = this._describeFile(!!dependencySource, filePath);
1814
- const elementResult = dependencySource ? this._describeDependencyElement(fileDescription, dependencySource) : fileDescription;
1815
- this._elementsCache.set(
1816
- {
1817
- dependencySource,
1818
- filePath: String(filePath)
1819
- },
1820
- elementResult
1821
- );
1801
+ const cacheKey = `${String(dependencySource)}::${String(filePath)}`;
1802
+ if (this._descriptionsCache.has(cacheKey)) {
1803
+ return this._descriptionsCache.get(cacheKey);
1804
+ }
1805
+ const externalOrCoreDependencyElement = dependencySource ? this._getExternalOrCoreDependencyElement(dependencySource, filePath) : null;
1806
+ if (externalOrCoreDependencyElement) {
1807
+ this._descriptionsCache.set(cacheKey, externalOrCoreDependencyElement);
1808
+ return externalOrCoreDependencyElement;
1809
+ }
1810
+ const fileDescription = this._describeFile(filePath);
1811
+ const elementResult = dependencySource ? {
1812
+ ...fileDescription,
1813
+ source: dependencySource
1814
+ } : fileDescription;
1815
+ this._descriptionsCache.set(cacheKey, elementResult);
1822
1816
  return elementResult;
1823
1817
  }
1824
1818
  /**
@@ -1847,14 +1841,17 @@ var Descriptors = class {
1847
1841
  /** Creates a new DescriptorsManager instance
1848
1842
  * @param elementDescriptors The element descriptors.
1849
1843
  * @param configOptions The configuration options.
1844
+ * @param micromatch The Micromatch instance.
1850
1845
  */
1851
- constructor(elementDescriptors, configOptions) {
1846
+ constructor(elementDescriptors, config, micromatch2) {
1852
1847
  this._elementsDescriptor = new ElementsDescriptor(
1853
1848
  elementDescriptors,
1854
- configOptions
1849
+ config,
1850
+ micromatch2
1855
1851
  );
1856
1852
  this._dependenciesDescriptor = new DependenciesDescriptor(
1857
- this._elementsDescriptor
1853
+ this._elementsDescriptor,
1854
+ config
1858
1855
  );
1859
1856
  }
1860
1857
  /**
@@ -1922,15 +1919,15 @@ var Matcher = class {
1922
1919
  /**
1923
1920
  * Constructor for the Matcher class.
1924
1921
  * @param descriptors Element descriptors to use for matching.
1922
+ * @param elementsMatcher Elements matcher instance.
1923
+ * @param dependenciesMatcher Dependencies matcher instance.
1925
1924
  * @param config Configuration options.
1925
+ * @param globalCache Global cache instance.
1926
1926
  */
1927
- constructor(descriptors, config) {
1928
- this._descriptors = new Descriptors(descriptors, config);
1929
- this._elementsMatcher = new ElementsMatcher(config);
1930
- this._dependenciesMatcher = new DependenciesMatcher(
1931
- this._elementsMatcher,
1932
- config
1933
- );
1927
+ constructor(descriptors, elementsMatcher, dependenciesMatcher, config, micromatch2) {
1928
+ this._descriptors = new Descriptors(descriptors, config, micromatch2);
1929
+ this._elementsMatcher = elementsMatcher;
1930
+ this._dependenciesMatcher = dependenciesMatcher;
1934
1931
  }
1935
1932
  /**
1936
1933
  * Determines if an element matches a given selector.
@@ -1994,7 +1991,7 @@ var Matcher = class {
1994
1991
  * @param options Extra options for matching
1995
1992
  * @returns The matching dependency result or null if no match is found
1996
1993
  */
1997
- _isDependencySelectorMatching(dependencyData, selector, options) {
1994
+ _getDependencySelectorMatching(dependencyData, selector, options) {
1998
1995
  const description = this._descriptors.describeDependency(dependencyData);
1999
1996
  return this._dependenciesMatcher.getSelectorsMatching(
2000
1997
  description,
@@ -2010,7 +2007,7 @@ var Matcher = class {
2010
2007
  options
2011
2008
  );
2012
2009
  }
2013
- return this._isDependencySelectorMatching(
2010
+ return this._getDependencySelectorMatching(
2014
2011
  descriptorOptions,
2015
2012
  selector,
2016
2013
  options
@@ -2067,32 +2064,161 @@ var Matcher = class {
2067
2064
  */
2068
2065
  clearCache() {
2069
2066
  this._descriptors.clearCache();
2070
- this._elementsMatcher.clearCache();
2071
- this._dependenciesMatcher.clearCache();
2072
2067
  }
2073
2068
  /**
2074
- * Serializes the descriptors and elements matchers cache to a plain object.
2069
+ * Serializes the descriptors matchers cache to a plain object.
2075
2070
  * @returns The serialized cache
2076
2071
  */
2077
2072
  serializeCache() {
2078
2073
  return {
2079
- descriptors: this._descriptors.serializeCache(),
2080
- elementsMatcher: this._elementsMatcher.serializeCache(),
2081
- dependenciesMatcher: this._dependenciesMatcher.serializeCache()
2074
+ descriptors: this._descriptors.serializeCache()
2082
2075
  };
2083
2076
  }
2084
2077
  /**
2085
- * Sets the descriptors and elements matchers cache from a serialized object.
2078
+ * Sets the descriptors matchers cache from a serialized object.
2086
2079
  * @param serializedCache The serialized cache
2087
2080
  */
2088
2081
  setCacheFromSerialized(serializedCache) {
2089
2082
  this._descriptors.setCacheFromSerialized(serializedCache.descriptors);
2090
- this._elementsMatcher.setCacheFromSerialized(
2091
- serializedCache.elementsMatcher
2092
- );
2093
- this._dependenciesMatcher.setCacheFromSerialized(
2094
- serializedCache.dependenciesMatcher
2083
+ }
2084
+ };
2085
+
2086
+ // src/Matcher/Micromatch.ts
2087
+ import micromatch from "micromatch";
2088
+ var MatchingResultsCache = class extends CacheManager {
2089
+ /**
2090
+ * Generates a unique cache key based on the value and pattern
2091
+ * @param param0 The cache key components
2092
+ * @returns The generated cache key
2093
+ */
2094
+ generateKey({ value, pattern }) {
2095
+ return `${value}::${isArray(pattern) ? pattern.join("|") : pattern}`;
2096
+ }
2097
+ };
2098
+ var CapturedValueCache = class extends CacheManager {
2099
+ /**
2100
+ * Generates a unique cache key based on the pattern and target
2101
+ * @param param0 The cache key components
2102
+ * @returns The generated cache key
2103
+ */
2104
+ generateKey({ pattern, target }) {
2105
+ return `${pattern}|${target}`;
2106
+ }
2107
+ };
2108
+ var Micromatch = class {
2109
+ /**
2110
+ * Cache for micromatch matching results
2111
+ */
2112
+ _matchingResultsCache;
2113
+ /**
2114
+ * Cache for micromatch captures
2115
+ */
2116
+ _capturesCache = new CacheManagerDisabled();
2117
+ /**
2118
+ * Cache for micromatch makeRe results
2119
+ */
2120
+ _makeReCache = new CacheManagerDisabled();
2121
+ /**
2122
+ * Creates an instance of Micromatch class.
2123
+ * @param cache Whether to use caching or not.
2124
+ */
2125
+ constructor(cache) {
2126
+ this._matchingResultsCache = cache ? new MatchingResultsCache() : new CacheManagerDisabled();
2127
+ this._capturesCache = cache ? new CapturedValueCache() : new CacheManagerDisabled();
2128
+ this._makeReCache = cache ? new CacheManager() : new CacheManagerDisabled();
2129
+ }
2130
+ /**
2131
+ * Clears all caches.
2132
+ */
2133
+ clearCache() {
2134
+ this._matchingResultsCache.clear();
2135
+ this._capturesCache.clear();
2136
+ this._makeReCache.clear();
2137
+ }
2138
+ /**
2139
+ * Serializes the current cache state.
2140
+ * @returns The serialized cache data.
2141
+ */
2142
+ serializeCache() {
2143
+ return {
2144
+ matchingResults: this._matchingResultsCache.serialize(),
2145
+ captures: this._capturesCache.serialize()
2146
+ };
2147
+ }
2148
+ /**
2149
+ * Restores the cache state from serialized data.
2150
+ * @param serializedCache The serialized cache data.
2151
+ */
2152
+ setFromSerialized(serializedCache) {
2153
+ this._matchingResultsCache.setFromSerialized(
2154
+ serializedCache.matchingResults
2095
2155
  );
2156
+ this._capturesCache.setFromSerialized(serializedCache.captures);
2157
+ }
2158
+ /**
2159
+ * Optimized micromatch match with caching.
2160
+ * @param value The value to match.
2161
+ * @param pattern The pattern to match against.
2162
+ * @returns True if the value matches the pattern, false otherwise.
2163
+ */
2164
+ isMatch(value, pattern) {
2165
+ const cacheKey = this._matchingResultsCache.getKey({
2166
+ value,
2167
+ pattern
2168
+ });
2169
+ if (this._matchingResultsCache.has(cacheKey)) {
2170
+ return this._matchingResultsCache.get(cacheKey);
2171
+ }
2172
+ const isMatch = micromatch.isMatch(value, pattern);
2173
+ this._matchingResultsCache.set(cacheKey, isMatch);
2174
+ return isMatch;
2175
+ }
2176
+ /**
2177
+ * Optimized micromatch capture with caching.
2178
+ * @param pattern The pattern to match against.
2179
+ * @param target The target string to test.
2180
+ * @returns Captured groups or null if no match.
2181
+ */
2182
+ capture(pattern, target) {
2183
+ const cacheKey = this._capturesCache.getKey({ pattern, target });
2184
+ if (this._capturesCache.has(cacheKey)) {
2185
+ return this._capturesCache.get(cacheKey);
2186
+ }
2187
+ const result = micromatch.capture(pattern, target);
2188
+ this._capturesCache.set(cacheKey, result);
2189
+ return result;
2190
+ }
2191
+ /**
2192
+ * Optimized micromatch makeRe with caching.
2193
+ * @param pattern The pattern to convert to RegExp.
2194
+ * @returns The RegExp instance.
2195
+ */
2196
+ makeRe(pattern) {
2197
+ if (this._makeReCache.has(pattern)) {
2198
+ return this._makeReCache.get(pattern);
2199
+ }
2200
+ const regexp = micromatch.makeRe(pattern);
2201
+ this._makeReCache.set(pattern, regexp);
2202
+ return regexp;
2203
+ }
2204
+ };
2205
+
2206
+ // src/MatchersCache.ts
2207
+ var MatchersCache = class extends CacheManager {
2208
+ /**
2209
+ * Generates a unique key based on the configuration options and element descriptors
2210
+ * @param params The configuration and element descriptors
2211
+ * @returns A unique string key
2212
+ */
2213
+ generateKey({
2214
+ config,
2215
+ elementDescriptors
2216
+ }) {
2217
+ const configHash = `${config.legacyTemplates}|${config.includePaths}|${config.ignorePaths}|${config.cache}`;
2218
+ const elementDescriptorsHash = elementDescriptors.map(
2219
+ (descriptor) => `${descriptor.type}|${descriptor.category}|${descriptor.pattern}|${descriptor.basePattern}|${descriptor.mode}|${descriptor.capture}|${descriptor.baseCapture}`
2220
+ ).join(",");
2221
+ return `${configHash}|:|${elementDescriptorsHash}`;
2096
2222
  }
2097
2223
  };
2098
2224
 
@@ -2101,11 +2227,10 @@ var Elements = class {
2101
2227
  /** The global configuration options for Elements. Can be overridden when getting a descriptor */
2102
2228
  _globalConfigOptions;
2103
2229
  /** Cache manager for Matcher instances, unique for each different configuration */
2104
- _matchersCache = new CacheManager();
2105
- /** Matcher for element selectors */
2106
- _elementsMatcher;
2107
- /** Matcher for dependency selectors */
2108
- _dependenciesMatcher;
2230
+ _matchersCache = new MatchersCache();
2231
+ /** Micromatch instances for pattern matching */
2232
+ _micromatchWithCache = new Micromatch(true);
2233
+ _micromatchWithoutCache = new Micromatch(false);
2109
2234
  /**
2110
2235
  * Creates a new Elements instance
2111
2236
  * @param configOptions The global configuration options for Elements. Can be overridden when getting a descriptor.
@@ -2113,11 +2238,6 @@ var Elements = class {
2113
2238
  constructor(configOptions) {
2114
2239
  const globalConfig = new Config(configOptions);
2115
2240
  this._globalConfigOptions = globalConfig.options;
2116
- this._elementsMatcher = new ElementsMatcher(this._globalConfigOptions);
2117
- this._dependenciesMatcher = new DependenciesMatcher(
2118
- this._elementsMatcher,
2119
- this._globalConfigOptions
2120
- );
2121
2241
  }
2122
2242
  /**
2123
2243
  * Returns a serialized representation of the current state of the cache.
@@ -2127,20 +2247,20 @@ var Elements = class {
2127
2247
  const matchersCache = Array.from(
2128
2248
  this._matchersCache.getAll().entries()
2129
2249
  ).reduce(
2130
- (acc, [key, descriptorCache]) => {
2250
+ (acc, [key, cache]) => {
2131
2251
  acc[key] = {
2132
- config: descriptorCache.config,
2133
- elementDescriptors: descriptorCache.elementDescriptors,
2134
- cache: descriptorCache.matcher.serializeCache()
2252
+ config: cache.config,
2253
+ elementDescriptors: cache.elementDescriptors,
2254
+ cache: cache.matcher.serializeCache()
2135
2255
  };
2136
2256
  return acc;
2137
2257
  },
2138
2258
  {}
2139
2259
  );
2260
+ const micromatchCache = this._micromatchWithCache.serializeCache();
2140
2261
  return {
2141
2262
  matchers: matchersCache,
2142
- elementsMatcher: this._elementsMatcher.serializeCache(),
2143
- dependenciesMatcher: this._dependenciesMatcher.serializeCache()
2263
+ micromatch: micromatchCache
2144
2264
  };
2145
2265
  }
2146
2266
  /**
@@ -2148,54 +2268,70 @@ var Elements = class {
2148
2268
  * @param serializedCache The serialized cache to set.
2149
2269
  */
2150
2270
  setCacheFromSerialized(serializedCache) {
2271
+ this._micromatchWithCache.setFromSerialized(serializedCache.micromatch);
2151
2272
  for (const key in serializedCache.matchers) {
2152
2273
  const matcher = this.getMatcher(
2153
2274
  serializedCache.matchers[key].elementDescriptors,
2154
2275
  serializedCache.matchers[key].config
2155
2276
  );
2156
2277
  matcher.setCacheFromSerialized(serializedCache.matchers[key].cache);
2157
- this._matchersCache.restore(key, {
2278
+ this._matchersCache.set(key, {
2158
2279
  config: serializedCache.matchers[key].config,
2159
2280
  elementDescriptors: serializedCache.matchers[key].elementDescriptors,
2160
2281
  matcher
2161
2282
  });
2162
2283
  }
2163
- this._elementsMatcher.setCacheFromSerialized(
2164
- serializedCache.elementsMatcher
2165
- );
2166
- this._dependenciesMatcher.setCacheFromSerialized(
2167
- serializedCache.dependenciesMatcher
2168
- );
2169
2284
  }
2170
2285
  /**
2171
2286
  * Clears cache
2172
2287
  */
2173
2288
  clearCache() {
2174
- this._elementsMatcher.clearCache();
2175
- this._dependenciesMatcher.clearCache();
2176
2289
  for (const { matcher } of this._matchersCache.getAll().values()) {
2177
2290
  matcher.clearCache();
2178
2291
  }
2179
2292
  this._matchersCache.clear();
2293
+ this._micromatchWithCache.clearCache();
2180
2294
  }
2181
2295
  /**
2182
2296
  * Gets a Matcher instance for the given configuration options.
2183
2297
  * It uses caching to return the same instance for the same configuration options. If no options are provided, the global configuration options are used.
2184
2298
  * @param elementDescriptors The element descriptors to use.
2185
- * @param configOptions Optional configuration options to override the global ones.
2299
+ * @param config Optional configuration options to override the global ones.
2186
2300
  * @returns A matcher instance, unique for each different configuration.
2187
2301
  */
2188
- getMatcher(elementDescriptors, configOptions) {
2189
- const optionsToUse = configOptions || this._globalConfigOptions;
2302
+ getMatcher(elementDescriptors, config) {
2303
+ const optionsToUse = config || this._globalConfigOptions;
2190
2304
  const configInstance = new Config(optionsToUse);
2191
- const normalizedOptions = configInstance.options;
2192
- const cacheKey = { config: normalizedOptions, elementDescriptors };
2305
+ const cacheIsEnabled = configInstance.cache;
2306
+ const configOptionsNormalized = configInstance.options;
2307
+ const descriptorNormalizedOptions = configInstance.descriptorOptions;
2308
+ const matchersNormalizedOptions = configInstance.matchersOptions;
2309
+ const cacheKey = this._matchersCache.getKey({
2310
+ config: configOptionsNormalized,
2311
+ elementDescriptors
2312
+ });
2193
2313
  if (this._matchersCache.has(cacheKey)) {
2194
2314
  return this._matchersCache.get(cacheKey).matcher;
2195
2315
  }
2196
- const matcher = new Matcher(elementDescriptors, normalizedOptions);
2316
+ const micromatch2 = cacheIsEnabled ? this._micromatchWithCache : this._micromatchWithoutCache;
2317
+ const elementsMatcher = new ElementsMatcher(
2318
+ matchersNormalizedOptions,
2319
+ micromatch2
2320
+ );
2321
+ const dependenciesMatcher = new DependenciesMatcher(
2322
+ elementsMatcher,
2323
+ matchersNormalizedOptions,
2324
+ micromatch2
2325
+ );
2326
+ const matcher = new Matcher(
2327
+ elementDescriptors,
2328
+ elementsMatcher,
2329
+ dependenciesMatcher,
2330
+ descriptorNormalizedOptions,
2331
+ micromatch2
2332
+ );
2197
2333
  this._matchersCache.set(cacheKey, {
2198
- config: normalizedOptions,
2334
+ config: configOptionsNormalized,
2199
2335
  elementDescriptors,
2200
2336
  matcher
2201
2337
  });
@@ -2206,6 +2342,7 @@ export {
2206
2342
  CacheManager,
2207
2343
  DEPENDENCY_KINDS_MAP,
2208
2344
  DEPENDENCY_KIND_TYPE,
2345
+ DEPENDENCY_KIND_TYPEOF,
2209
2346
  DEPENDENCY_KIND_VALUE,
2210
2347
  DEPENDENCY_RELATIONSHIPS_INVERTED_MAP,
2211
2348
  DEPENDENCY_RELATIONSHIPS_MAP,