@boundaries/elements 1.1.2 → 2.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.
package/README.md CHANGED
@@ -19,12 +19,18 @@
19
19
  - [Usage](#usage)
20
20
  - [Configuration Options](#configuration-options)
21
21
  - [Creating a matcher](#creating-a-matcher)
22
- - [Element Descriptors](#element-descriptors)
22
+ - [Element Descriptors](#element-descriptors)
23
+ - [Descriptions API](#descriptions-api)
24
+ - [Element Description](#element-description)
25
+ - [Dependency Description](#dependency-description)
23
26
  - [Selectors](#selectors)
27
+ - [Element Selectors](#element-selectors)
28
+ - [Dependency Selectors](#dependency-selectors)
24
29
  - [Template Variables](#template-variables)
25
30
  - [Using Matchers](#using-matchers)
26
31
  - [Element Matching](#element-matching)
27
32
  - [Dependency Matching](#dependency-matching)
33
+ - [Flagging Dependencies as External](#flagging-dependencies-as-external)
28
34
  - [API Reference](#api-reference)
29
35
  - [Legacy Selectors](#legacy-selectors)
30
36
  - [Contributing](#contributing)
@@ -90,12 +96,12 @@ const matcher = elements.getMatcher([
90
96
  ]);
91
97
 
92
98
  // Match an element
93
- const isComponent = matcher.isMatch("src/components/Button.tsx", {
99
+ const isComponent = matcher.isElementMatch("src/components/Button.tsx", {
94
100
  type: "component"
95
101
  }); // true
96
102
 
97
103
  // Match a dependency
98
- const isValidDependency = matcher.isMatch(
104
+ const isValidDependency = matcher.isDependencyMatch(
99
105
  {
100
106
  from: "src/components/Button.tsx",
101
107
  to: "src/services/Api.ts",
@@ -106,6 +112,7 @@ const isValidDependency = matcher.isMatch(
106
112
  {
107
113
  from: { category: "react" },
108
114
  to: { type: "service" },
115
+ dependency: { nodeKind: "ImportDeclaration" },
109
116
  }
110
117
  ); // true
111
118
  ```
@@ -120,6 +127,13 @@ When creating an `Elements` instance, you can provide configuration options that
120
127
  const elements = new Elements({
121
128
  ignorePaths: ["**/dist/**", "**/build/**", "**/node_modules/**"],
122
129
  includePaths: ["src/**/*"],
130
+ rootPath: "/absolute/path/to/project",
131
+ flagAsExternal: {
132
+ unresolvableAlias: true,
133
+ inNodeModules: true,
134
+ outsideRootPath: true,
135
+ customSourcePatterns: ["@myorg/*"],
136
+ },
123
137
  });
124
138
  ```
125
139
 
@@ -129,6 +143,15 @@ const elements = new Elements({
129
143
  - **`includePaths`**: Micromatch pattern(s) to include only specific paths (default: all paths)
130
144
  - **`legacyTemplates`**: Whether to enable legacy template syntax support (default: `true`, but it will be `false` in future releases). This allows using `${variable}` syntax in templates for backward compatibility.
131
145
  - **`cache`**: Whether to enable internal caching to improve performance (default: `true`)
146
+ - **`rootPath`**: Absolute path to the project root. When configured, file paths should be provided as absolute paths to allow the package to determine which files are outside the project root (default: `undefined`)
147
+ - **`flagAsExternal`**: Configuration for categorizing dependencies as external or local. Multiple conditions can be specified, and dependencies will be categorized as external if ANY condition is met (OR logic). See [Flagging Dependencies as External](#flagging-dependencies-as-external) for details.
148
+
149
+ > [!NOTE]
150
+ > **Pattern Matching with `rootPath`:**
151
+ > When `rootPath` **is configured**:
152
+ > - **Matching patterns** in element descriptors are **relative to the `rootPath`**. The package automatically converts absolute paths to relative paths internally for pattern matching.
153
+ > - In **`file` and `folder` modes**, patterns are evaluated **right-to-left** (from the end of the path), so the relativity to `rootPath` is typically less important. For example, a pattern like `*.model.ts` will match any file ending with `.model.ts` regardless of its location within `rootPath`.
154
+ > - In **`full` mode**, patterns must match the complete relative path from `rootPath`. Files outside `rootPath` maintain their absolute paths and require absolute patterns to match.
132
155
 
133
156
  ### Creating a Matcher
134
157
 
@@ -177,17 +200,98 @@ Element descriptors define how files are identified and categorized. Each descri
177
200
  - **`capture`** (`string[]`): Array of keys to capture path fragments
178
201
  - **`baseCapture`** (`string[]`): Array of keys to capture fragments from `basePattern`. If the same key is defined in both `capture` and `baseCapture`, the value from `capture` takes precedence.
179
202
 
203
+ ### Descriptions API
204
+
205
+ The matcher can also return normalized runtime descriptions. These descriptions are the canonical API used by `@boundaries/eslint-plugin` and are useful for debugging, reporting, and custom tooling.
206
+
207
+ > [!IMPORTANT]
208
+ > This section describes the **output API** of `describeElement` / `describeDependency`, which is different from the **input API** used by `isDependencyMatch`.
209
+
210
+ #### Element Description
211
+
212
+ `matcher.describeElement(filePath)` returns an object with normalized element metadata.
213
+
214
+ Common fields:
215
+
216
+ - `path`: Absolute or relative file path used in the matcher call
217
+ - `type`: Matched element type, or `null` if unknown
218
+ - `category`: Matched element category, or `null`
219
+ - `captured`: Captured values map from descriptor patterns, or `null`
220
+ - `elementPath`: Path representing the detected element boundary, or `null`
221
+ - `internalPath`: Path of the file relative to `elementPath`, or `null`
222
+ - `origin`: One of `"local" | "external" | "core"`
223
+ - `isIgnored`: Whether the file was excluded by `ignorePaths` / `includePaths`
224
+ - `isUnknown`: Whether no descriptor matched
225
+
226
+ Additional fields for local known elements:
227
+
228
+ - `parents`: Parent element chain, or `null`
229
+
230
+ #### Dependency Description
231
+
232
+ `matcher.describeDependency(options)` returns:
233
+
234
+ ```ts
235
+ {
236
+ from: ElementDescription,
237
+ to: ElementDescription,
238
+ dependency: {
239
+ source: string,
240
+ module: string | null,
241
+ kind: "value" | "type" | "typeof",
242
+ nodeKind: string | null,
243
+ specifiers: string[] | null,
244
+ relationship: {
245
+ from: "internal" | "child" | "descendant" | "sibling" | "parent" | "uncle" | "nephew" | "ancestor" | null,
246
+ to: "internal" | "child" | "descendant" | "sibling" | "parent" | "uncle" | "nephew" | "ancestor" | null,
247
+ }
248
+ }
249
+ }
250
+ ```
251
+
252
+ Notes:
253
+
254
+ - `dependency.source` is the raw import/export source string from code.
255
+ - `dependency.module` is the normalized module base for external/core dependencies.
256
+ - `dependency.relationship.to` describes how `to` relates to `from`.
257
+ - `dependency.relationship.from` is the inverse perspective.
258
+ - For unknown/ignored scenarios, some values can be `null`.
259
+
260
+ Example:
261
+
262
+ ```ts
263
+ const description = matcher.describeDependency({
264
+ from: "src/components/Button.tsx",
265
+ to: "src/services/Api.ts",
266
+ source: "../services/Api",
267
+ kind: "value",
268
+ nodeKind: "ImportDeclaration",
269
+ specifiers: ["ApiClient"],
270
+ });
271
+
272
+ console.log(description.dependency.source); // "../services/Api"
273
+ console.log(description.dependency.kind); // "value"
274
+ console.log(description.dependency.relationship); // { from: ..., to: ... }
275
+ ```
276
+
180
277
  ### Selectors
181
278
 
182
279
  Selectors are used to match elements and dependencies against specific criteria. They are objects where each property represents a matching condition.
183
280
 
184
- #### Element Properties
281
+ #### Element Selectors
282
+
283
+ When matching elements, you can use element selectors that specify conditions on the element's properties.
185
284
 
186
- All element selectors support the following properties:
285
+ Element selectors support the following properties:
187
286
 
188
287
  - **`type`** (`string | string[]`): Micromatch pattern(s) for the element type/s
189
288
  - **`category`** (`string | string[]`): Micromatch pattern(s) for the element category/categories
190
- - **`captured`** (`object`): Object with keys matching captured values. Each key can be a string or an array of strings representing micromatch patterns.
289
+ - **`captured`** (`object | object[]`): Captured values selector. When provided as an object, all keys must match (AND logic). When provided as an array of objects, the element matches if any of the objects matches all keys (OR logic). Each key in the objects can be a string or an array of strings representing micromatch patterns.
290
+ - **`parent`** (`object` | `null`): Selector for the first parent in the element description (`parents[0]`). Supported properties are:
291
+ - **`type`** (`string | string[]`): Micromatch pattern(s) for parent type
292
+ - **`category`** (`string | string[]`): Micromatch pattern(s) for parent category
293
+ - **`elementPath`** (`string | string[]`): Micromatch pattern(s) for parent element path
294
+ - **`captured`** (`object | object[]`): Parent captured values selector. Uses the same semantics as `captured` in the root selector (object = AND, array = OR)
191
295
  - **`origin`** (`"local" | "external" | "core"`): Element origin
192
296
  - `local`: Files within the project
193
297
  - `external`: External dependencies (e.g., `node_modules`)
@@ -198,24 +302,33 @@ All element selectors support the following properties:
198
302
  - **`isIgnored`** (`boolean`): Whether the element is ignored
199
303
  - **`isUnknown`** (`boolean`): Whether the element type is unknown (i.e., doesn't match any descriptor)
200
304
 
201
- #### Dependency Properties
202
-
203
- When matching dependencies, the `to` selector can additionally use:
204
-
205
- - **`kind`** (`string | string[]`): Micromatch pattern(s) for the dependency kind
206
- - **`relationship`** (`string | string[]`): Element relationship. Micromatch pattern(s) for the relationship between source and target elements:
207
- - `internal`: Both files belong to the same element
208
- - `child`: Target is a child of source
209
- - `parent`: Target is a parent of source
210
- - `sibling`: Elements share the same parent
211
- - `uncle`: Target is a sibling of a source ancestor
212
- - `nephew`: Target is a child of a source sibling
213
- - `descendant`: Target is a descendant of source
214
- - `ancestor`: Target is an ancestor of source
215
- - **`specifiers`** (`string | string[]`): Pattern(s) for import/export specifiers (e.g., named imports)
216
- - **`nodeKind`** (`string | string[]`): Pattern(s) for the AST node type causing the dependency (e.g., `"ImportDeclaration"`)
217
- - **`source`** (`string | string[]`): Pattern(s) to match the source of the dependency. (e.g., the import path).
218
- - **`baseSource`** (`string | string[]`): Pattern(s) for the base module name for external imports.
305
+
306
+ > [!NOTE]
307
+ > All properties in the selector are optional. You can also use `null` values in selector to match only elements with `null` values in the corresponding properties. In the case of `parent`, setting it to `null` will match elements that have no parents (i.e., top-level elements). If `parent` is an object, it will only match elements that have at least one parent, and the first parent (`parents[0]`) matches the specified conditions.
308
+
309
+ #### Dependency Selectors
310
+
311
+ When matching dependencies, you can use dependency selectors that specify conditions on the source and target elements, as well as the dependency metadata.
312
+
313
+ - **`from`** (`element selector | element selector[]`): [Selector(s)](#element-selectors) for the source element
314
+ - **`to`** (`element selector | element selector[]`): [Selector(s)](#element-selectors) for the target element
315
+ - **`dependency`** (`object | object[]`): Selector(s) for dependency metadata. When an array is provided, the dependency metadata matches if any selector in the array matches (OR logic). Supported selector properties:
316
+ - **`kind`** (`string | string[]`): Micromatch pattern(s) for the dependency kind
317
+ - **`relationship`** (`object`): Relationship selectors from both perspectives:
318
+ - **`from`** (`string | string[]`): Relationship from the perspective of `from`
319
+ - **`to`** (`string | string[]`): Relationship from the perspective of `to`
320
+ - `internal`: Both files belong to the same element
321
+ - `child`: Target is a child of source
322
+ - `parent`: Target is a parent of source
323
+ - `sibling`: Elements share the same parent
324
+ - `uncle`: Target is a sibling of a source ancestor
325
+ - `nephew`: Target is a child of a source sibling
326
+ - `descendant`: Target is a descendant of source
327
+ - `ancestor`: Target is an ancestor of source
328
+ - **`specifiers`** (`string | string[]`): Pattern(s) for import/export specifiers (e.g., named imports)
329
+ - **`nodeKind`** (`string | string[]`): Pattern(s) for the AST node type causing the dependency (e.g., `"ImportDeclaration"`)
330
+ - **`source`** (`string | string[]`): Pattern(s) to match the source of the dependency (e.g., the import path)
331
+ - **`module`** (`string | string[]`): Pattern(s) for the base module name for external or core dependencies.
219
332
 
220
333
  > **⚠️ Important:** All properties in a selector must match for the selector to be considered a match (AND logic). Use multiple selectors for OR logic.
221
334
 
@@ -226,7 +339,7 @@ When matching dependencies, the `to` selector can additionally use:
226
339
  Selectors support template variables using [Handlebars syntax](https://handlebarsjs.com/) (`{{ variableName }}`). Templates are resolved at match time using:
227
340
 
228
341
  - **Element properties** (`type`, `category`, `captured`, etc.)
229
- - **Dependency properties** (`from`, `to`)
342
+ - **Dependency properties** (`from`, `to`, `dependency`)
230
343
 
231
344
  #### Available Template Data
232
345
 
@@ -237,7 +350,8 @@ When matching, the following data is automatically available:
237
350
 
238
351
  **For dependency matching:**
239
352
  - `from`: Properties of the dependency source element
240
- - `to`: Properties of the dependency target element, and properties of the dependency itself (source, kind, nodeKind, specifiers, etc.)
353
+ - `to`: Properties of the dependency target element
354
+ - `dependency`: Dependency metadata (`kind`, `nodeKind`, `specifiers`, `source`, `module`, `relationship`, etc.)
241
355
 
242
356
  #### Template Examples
243
357
 
@@ -253,7 +367,7 @@ const matcher = elements.getMatcher([
253
367
  ]);
254
368
 
255
369
  // Match components from specific module using template
256
- const isAuthComponent = matcher.isMatch(
370
+ const isAuthComponent = matcher.isElementMatch(
257
371
  "src/modules/auth/LoginForm.component.tsx",
258
372
  {
259
373
  type: "component",
@@ -261,8 +375,20 @@ const isAuthComponent = matcher.isMatch(
261
375
  },
262
376
  );
263
377
 
378
+ // Using captured array for OR logic
379
+ const isAuthOrUserComponent = matcher.isElementMatch(
380
+ "src/modules/auth/LoginForm.component.tsx",
381
+ {
382
+ type: "component",
383
+ captured: [
384
+ { module: "auth" }, // Matches if module is "auth"
385
+ { module: "user", fileName: "UserProfile" } // OR if module is "user" and fileName is "UserProfile"
386
+ ]
387
+ },
388
+ );
389
+
264
390
  // Using templates in dependency selectors
265
- const isDependencyMatch = matcher.isMatch(
391
+ const isDependencyMatch = matcher.isDependencyMatch(
266
392
  {
267
393
  from: "src/components/Button.tsx",
268
394
  to: "src/services/Api.ts",
@@ -273,7 +399,11 @@ const isDependencyMatch = matcher.isMatch(
273
399
  },
274
400
  {
275
401
  from: { type: "{{ from.type }}", captured: { fileName: "{{ from.captured.fileName }}" } },
276
- to: { path: "{{ to.path }}", specifiers: "{{ lookup to.specifiers 0 }}", kind: "{{ to.kind }}" },
402
+ to: { path: "{{ to.path }}" },
403
+ dependency: {
404
+ specifiers: "{{ lookup dependency.specifiers 0 }}",
405
+ kind: "{{ dependency.kind }}",
406
+ },
277
407
  }
278
408
  );
279
409
  ```
@@ -284,7 +414,7 @@ You can provide additional template data using the `extraTemplateData` option in
284
414
 
285
415
  ```ts
286
416
  // Using templates in selectors
287
- const isMatch = matcher.isMatch(
417
+ const isMatch = matcher.isElementMatch(
288
418
  "src/components/UserProfile.tsx",
289
419
  { type: "{{ componentType }}" },
290
420
  {
@@ -299,18 +429,18 @@ You can use element selectors with a created matcher to check if a given path co
299
429
 
300
430
  #### Element Matching
301
431
 
302
- To match an element, use the `isMatch` method of the matcher, providing the file path and an element selector.
432
+ To match an element, use the `isElementMatch` method of the matcher, providing the file path and an element selector.
303
433
 
304
434
  ```ts
305
- const isElementMatch = matcher.isMatch("src/components/Button.tsx", { type: "component" });
435
+ const isElementMatch = matcher.isElementMatch("src/components/Button.tsx", { type: "component" });
306
436
  ```
307
437
 
308
438
  > [!TIP]
309
- > You can also provide an array of selectors to the `isMatch` method. In this case, the method will return `true` if the element matches any of the provided selectors (OR logic).
439
+ > You can also provide an array of selectors to the `isElementMatch` method. In this case, the method will return `true` if the element matches any of the provided selectors (OR logic).
310
440
 
311
441
  #### Dependency Matching
312
442
 
313
- To match a dependency, use the `isMatch` method of the matcher, providing the properties of the dependency and a dependency selector.
443
+ To match a dependency, use the `isDependencyMatch` method of the matcher, providing the properties of the dependency and a dependency selector.
314
444
 
315
445
  **Dependency object properties:**
316
446
 
@@ -324,10 +454,11 @@ To match a dependency, use the `isMatch` method of the matcher, providing the pr
324
454
  **Dependency selector:**
325
455
 
326
456
  - **`from`**: Element selector(s) for the source file
327
- - **`to`**: Dependency selector(s) for the target file
457
+ - **`to`**: Element selector(s) for the target file
458
+ - **`dependency`**: Dependency metadata selector(s)
328
459
 
329
460
  ```ts
330
- const isDependencyMatch = matcher.isMatch(
461
+ const isDependencyMatch = matcher.isDependencyMatch(
331
462
  { // Dependency properties
332
463
  from: "src/components/Button.tsx",
333
464
  to: "src/services/Api.ts",
@@ -337,13 +468,125 @@ const isDependencyMatch = matcher.isMatch(
337
468
  },
338
469
  {
339
470
  from: { category: "react" }, // Dependency source selector/s
340
- to: { type: "service", nodeKind: "Import*" }, // Dependency target selector/s
471
+ to: { type: "service" }, // Dependency target selector/s
472
+ dependency: [
473
+ { nodeKind: "Import*" },
474
+ { source: "@services/*" },
475
+ ], // Dependency metadata selector/s (OR logic)
341
476
  }
342
477
  );
343
478
  ```
344
479
 
345
480
  > [!TIP]
346
- > You can also provide an array of selectors both to the `from` and `to` properties of the dependency selector. In this case, the method will return `true` if the dependency matches any combination of the provided selectors (OR logic).
481
+ > You can also provide an array of selectors to `from`, `to` and `dependency`. The matcher will return `true` when all provided selector groups match.
482
+
483
+ ### Flagging Dependencies as External
484
+
485
+ The `flagAsExternal` configuration allows you to control how dependencies are categorized as external or local. This is especially useful in monorepo setups where you may want to treat inter-package dependencies as external even though they're within the same repository.
486
+
487
+ **Multiple conditions can be specified, and dependencies will be flagged as external if ANY condition is met (OR logic).**
488
+
489
+ #### Available Options
490
+
491
+ - **`unresolvableAlias`** (boolean, default: `true`): Non-relative imports whose path cannot be resolved are categorized as external
492
+
493
+ ```typescript
494
+ const elements = new Elements({
495
+ flagAsExternal: { unresolvableAlias: true },
496
+ });
497
+ const matcher = elements.getMatcher([/* descriptors */]);
498
+
499
+ // describeDependency({ from, to, source, kind }):
500
+ // to: null, source: 'unresolved-module' -> origin: 'external'
501
+ // to: '/project/src/Button.ts', source: './Button' -> origin: 'local'
502
+ ```
503
+
504
+ - **`inNodeModules`** (boolean, default: `true`): Non-relative paths that include `node_modules` in the resolved path are categorized as external
505
+
506
+ ```typescript
507
+ const elements = new Elements({
508
+ flagAsExternal: { inNodeModules: true },
509
+ });
510
+ const matcher = elements.getMatcher([/* descriptors */]);
511
+
512
+ // describeDependency({ from, to, source, kind }):
513
+ // to: '/project/node_modules/react/index.js', source: 'react' -> origin: 'external'
514
+ // to: '/project/src/utils.ts', source: './utils' -> origin: 'local'
515
+ ```
516
+
517
+ - **`outsideRootPath`** (boolean, default: `false`): Dependencies whose resolved path is outside the configured `rootPath` are categorized as external. This is particularly useful in monorepo setups.
518
+
519
+ > **⚠️ Important:** This option requires `rootPath` to be configured. When using this option, all file paths must be absolute and include the `rootPath` prefix for files within the project.
520
+
521
+ ```typescript
522
+ const elements = new Elements({
523
+ rootPath: '/monorepo/packages/app',
524
+ flagAsExternal: { outsideRootPath: true },
525
+ });
526
+ const matcher = elements.getMatcher([/* descriptors */]);
527
+
528
+ // describeDependency({ from, to, source, kind }):
529
+ // to: '/monorepo/packages/shared/index.ts', source: '@myorg/shared' -> origin: 'external'
530
+ // to: '/monorepo/packages/app/src/utils/helper.ts', source: './utils/helper' -> origin: 'local'
531
+ ```
532
+
533
+ - **`customSourcePatterns`** (string[], default: `[]`): Array of micromatch patterns that, when matching the import/export source string, categorize the dependency as external
534
+
535
+ ```typescript
536
+ const elements = new Elements({
537
+ flagAsExternal: { customSourcePatterns: ['@myorg/*', '~/**'] },
538
+ });
539
+ const matcher = elements.getMatcher([/* descriptors */]);
540
+
541
+ // describeDependency({ from, to, source, kind }):
542
+ // source: '@myorg/shared' -> origin: 'external' (matches '@myorg/*')
543
+ // source: '~/utils/helper' -> origin: 'external' (matches '~/**')
544
+ // source: '@other/package' -> origin: 'local' (no match, unless inNodeModules is true or other conditions met)
545
+ ```
546
+
547
+ #### Path Requirements with `rootPath`
548
+
549
+ When `rootPath` is configured, the package needs absolute paths to correctly determine which files are outside the project root, but matching patterns must remain relative to `rootPath`, especially in `full` mode (because `file` and `folder` modes match progressively from the right, so they may be less affected by relativity).
550
+
551
+ ```typescript
552
+ const elements = new Elements({
553
+ rootPath: '/project/packages/app',
554
+ flagAsExternal: {
555
+ outsideRootPath: true,
556
+ },
557
+ });
558
+
559
+ // Matching patterns are relative to rootPath
560
+ const matcher = elements.getMatcher([
561
+ { type: 'component', pattern: 'src/**/*.ts', mode: 'full' }, // Relative to /project/packages/app
562
+ ]);
563
+
564
+ // ✅ Correct: Using absolute file paths with relative patterns
565
+ const dep = matcher.describeDependency({
566
+ from: '/project/packages/app/src/index.ts', // absolute file path
567
+ to: '/project/packages/shared/index.ts', // absolute file path
568
+ source: '@myorg/shared',
569
+ kind: 'value',
570
+ });
571
+ // Result: dep.to.origin === 'external' (outside rootPath)
572
+ // Note: Pattern 'src/**/*.ts' matches because the package converts
573
+ // absolute paths to relative internally for pattern matching
574
+
575
+ // ❌ Incorrect: Using relative file paths (won't detect outsideRootPath correctly)
576
+ const dep2 = matcher.describeDependency({
577
+ from: 'src/index.ts', // relative file path
578
+ to: '../shared/index.ts', // relative file path
579
+ source: '@myorg/shared',
580
+ kind: 'value',
581
+ });
582
+ // Result: Won't correctly detect if outside rootPath
583
+ ```
584
+
585
+ > **💡 Key Points:**
586
+ > - **File paths** in API calls (`from`, `to`, `filePath`) must be **absolute** when using `rootPath`
587
+ > - **Matching patterns** in element descriptors stay **relative** to `rootPath`
588
+ > - The package handles the conversion internally
589
+ > - When not using `rootPath`, the package continues to work with relative paths as before, maintaining backward compatibility.
347
590
 
348
591
  ## API Reference
349
592
 
@@ -409,14 +652,20 @@ elements.setCacheFromSerialized(cache);
409
652
 
410
653
  ### Matcher Instance Methods
411
654
 
412
- #### `isMatch`
655
+ #### `isElementMatch`
413
656
 
414
- Checks if a given path matches the specified element or dependency selector.
657
+ Checks if a given path matches an element selector.
415
658
 
416
659
  ```ts
417
- const isElementMatch = matcher.isMatch("src/components/Button.tsx", [{ type: "component" }]);
660
+ const isElementMatch = matcher.isElementMatch("src/components/Button.tsx", [{ type: "component" }]);
661
+ ```
662
+
663
+ #### `isDependencyMatch`
664
+
665
+ Checks if dependency properties match a dependency selector.
418
666
 
419
- const isDependencyMatch = matcher.isMatch(
667
+ ```ts
668
+ const isDependencyMatch = matcher.isDependencyMatch(
420
669
  {
421
670
  from: "src/components/Button.tsx",
422
671
  to: "src/services/Api.ts",
@@ -426,30 +675,41 @@ const isDependencyMatch = matcher.isMatch(
426
675
  },
427
676
  {
428
677
  from: [{ category: "react" }],
429
- to: { type: "service", nodeKind: "Import*" },
678
+ to: { type: "service" },
679
+ dependency: { nodeKind: "Import*" },
430
680
  }
431
681
  );
432
682
  ```
433
683
 
434
- - __Parameters__:
435
- - `path`:
436
- - `string` The path to check when using an [element selector](#selectors).
437
- - `DependencyProperties` The [properties of the dependency](#dependency-matching) to check when using a [dependency selector](#selectors).
438
- - `selector`: `ElementSelector | DependencySelector` The [selector](#selectors) to match against. It can be either an element selector (for path matching) or a dependency selector (for dependency matching).
439
- - If `path` is a string, `selector` should be an [`ElementSelector`](#selectors) or an array of `ElementSelector`.
440
- - If `path` are dependency properties, `selector` should be a [`DependencySelector`](#selectors) or an array of `DependencySelector`.
441
- - `options`: `MatcherOptions` Optional. Additional options for matching:
442
- - `extraTemplateData`: `object` Optional. Extra data to pass to selector templates. When using [template variables](#template-variables) in selectors, this data will be available for rendering.
443
-
444
- #### `getSelectorMatching`
684
+ #### `getElementSelectorMatching`
445
685
 
446
- Returns the first matching selector or `null`.
686
+ Returns the first matching element selector or `null`.
447
687
 
448
688
  ```ts
449
- const matchingSelector = matcher.getSelectorMatching("src/components/Button.tsx", [{ type: "component" }]);
689
+ const matchingSelector = matcher.getElementSelectorMatching("src/components/Button.tsx", [{ type: "component" }]);
450
690
  ```
451
691
 
452
- Parameters are the same as `isMatch`, but instead of returning a boolean, it returns the first matching selector or `null` if none match.
692
+ #### `getDependencySelectorMatching`
693
+
694
+ Returns the dependency selector matching result (`from`, `to`, `dependency`, `isMatch`).
695
+
696
+ > [!NOTE]
697
+ > This method provides detailed information about which part of the selector matched or didn't match. When arrays of selectors are provided in the `from`, `to` or `dependency` properties, the method will return the first selector that matches on each side, so the returned `from`, `to` and `dependency` will be the matching selector from each group.
698
+
699
+ ```ts
700
+ const matchingSelector = matcher.getDependencySelectorMatching(
701
+ {
702
+ from: "src/components/Button.tsx",
703
+ to: "src/services/Api.ts",
704
+ source: "../services/Api",
705
+ kind: "type",
706
+ },
707
+ {
708
+ to: { type: "service" },
709
+ dependency: { kind: "type" },
710
+ }
711
+ );
712
+ ```
453
713
 
454
714
  #### `describeElement`
455
715
 
@@ -461,6 +721,7 @@ const elementDescription = matcher.describeElement("src/components/Button.tsx");
461
721
 
462
722
  - __Parameters__:
463
723
  - `path`: `string` The path of the element to describe.
724
+ - __Returns__: [Element Description](#element-description).
464
725
 
465
726
  #### `describeDependency`
466
727
 
@@ -478,14 +739,37 @@ const dependencyDescription = matcher.describeDependency({
478
739
 
479
740
  - __Parameters__:
480
741
  - `dependency`: The [properties of the dependency to describe](#dependency-matching).
742
+ - __Returns__: [Dependency Description](#dependency-description).
481
743
 
482
- #### `getSelectorMatchingDescription`
744
+ #### `getElementSelectorMatchingDescription`
483
745
 
484
- Matches a description against selectors. As first argument, it should receive the result of `describeElement` or `describeDependency`.
746
+ Matches an element description against element selectors. As first argument, it should receive the result of `describeElement`.
747
+
748
+ As second argument, it should receive an array of element selectors. The method will return the first selector that matches the description or `null` if no selector matches.
485
749
 
486
750
  ```ts
487
751
  const elementDescription = matcher.describeElement("src/components/Button.tsx");
488
- const matchingSelector = matcher.getSelectorMatchingDescription(elementDescription, [{ type: "component" }]);
752
+ const matchingSelector = matcher.getElementSelectorMatchingDescription(elementDescription, [{ type: "component" }]);
753
+ ```
754
+
755
+ #### `getDependencySelectorMatchingDescription`
756
+
757
+ Matches a dependency description against dependency selectors. As first argument, it should receive the result of `describeDependency`.
758
+
759
+ As second argument, it should receive an array of dependency selectors. The method will return the first selector that matches the description or `null` if no selector matches.
760
+
761
+ > [!NOTE]
762
+ > This method provides detailed information about which part of the selector matched or didn't match. When arrays of selectors are provided in the `from`, `to` or `dependency` properties in a dependency selector, the method will return the first selector that matches on each side, so the returned `from`, `to` and `dependency` will be the matching selector from each group.
763
+
764
+ ```ts
765
+ const dependencyDescription = matcher.describeDependency({
766
+ from: "src/components/Button.tsx",
767
+ to: "src/services/Api.ts",
768
+ source: "../services/Api",
769
+ kind: "type",
770
+ nodeKind: "ImportDeclaration",
771
+ });
772
+ const matchingSelector = matcher.getDependencySelectorMatchingDescription(dependencyDescription, [{ to: { type: "service" }, dependency: { kind: "type" } }]);
489
773
  ```
490
774
 
491
775
  #### `clearCache`
@@ -530,18 +814,18 @@ Selectors can be defined as either a string or an array of strings representing
530
814
 
531
815
  ```ts
532
816
  // Legacy selector using a string
533
- const isElementMatch = matcher.isMatch("src/components/Button.tsx", "component");
817
+ const isElementMatch = matcher.isElementMatch("src/components/Button.tsx", "component");
534
818
  // Legacy selector using an array of strings
535
- const isElementMatch = matcher.isMatch("src/components/Button.tsx", ["component", "service"]);
819
+ const isElementMatch = matcher.isElementMatch("src/components/Button.tsx", ["component", "service"]);
536
820
  ```
537
821
 
538
822
  They can also be defined as an array where the first element is the type and the second element is an object containing captured values:
539
823
 
540
824
  ```ts
541
825
  // Legacy selector with captured values
542
- const isElementMatch = matcher.isMatch(
826
+ const isElementMatch = matcher.isElementMatch(
543
827
  "src/modules/auth/LoginForm.component.tsx",
544
- ["component", { module: "auth" }]
828
+ ["component", { foo: "auth" }]
545
829
  );
546
830
  ```
547
831