@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 +348 -64
- package/dist/index.browser.d.mts +280 -319
- package/dist/index.browser.d.ts +280 -319
- package/dist/index.browser.js +562 -469
- package/dist/index.browser.js.map +1 -1
- package/dist/index.browser.mjs +562 -469
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.d.mts +280 -319
- package/dist/index.d.ts +280 -319
- package/dist/index.js +565 -476
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +562 -469
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -6
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
|
-
|
|
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.
|
|
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.
|
|
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
|
|
281
|
+
#### Element Selectors
|
|
282
|
+
|
|
283
|
+
When matching elements, you can use element selectors that specify conditions on the element's properties.
|
|
185
284
|
|
|
186
|
-
|
|
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`):
|
|
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
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
- `
|
|
213
|
-
- `
|
|
214
|
-
|
|
215
|
-
- **`
|
|
216
|
-
-
|
|
217
|
-
-
|
|
218
|
-
-
|
|
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
|
|
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.
|
|
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.
|
|
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 }}"
|
|
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.
|
|
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 `
|
|
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.
|
|
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 `
|
|
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 `
|
|
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`**:
|
|
457
|
+
- **`to`**: Element selector(s) for the target file
|
|
458
|
+
- **`dependency`**: Dependency metadata selector(s)
|
|
328
459
|
|
|
329
460
|
```ts
|
|
330
|
-
const isDependencyMatch = matcher.
|
|
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"
|
|
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
|
|
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
|
-
#### `
|
|
655
|
+
#### `isElementMatch`
|
|
413
656
|
|
|
414
|
-
Checks if a given path matches
|
|
657
|
+
Checks if a given path matches an element selector.
|
|
415
658
|
|
|
416
659
|
```ts
|
|
417
|
-
const isElementMatch = matcher.
|
|
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
|
-
|
|
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"
|
|
678
|
+
to: { type: "service" },
|
|
679
|
+
dependency: { nodeKind: "Import*" },
|
|
430
680
|
}
|
|
431
681
|
);
|
|
432
682
|
```
|
|
433
683
|
|
|
434
|
-
|
|
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.
|
|
689
|
+
const matchingSelector = matcher.getElementSelectorMatching("src/components/Button.tsx", [{ type: "component" }]);
|
|
450
690
|
```
|
|
451
691
|
|
|
452
|
-
|
|
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
|
-
#### `
|
|
744
|
+
#### `getElementSelectorMatchingDescription`
|
|
483
745
|
|
|
484
|
-
Matches
|
|
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.
|
|
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.
|
|
817
|
+
const isElementMatch = matcher.isElementMatch("src/components/Button.tsx", "component");
|
|
534
818
|
// Legacy selector using an array of strings
|
|
535
|
-
const isElementMatch = matcher.
|
|
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.
|
|
826
|
+
const isElementMatch = matcher.isElementMatch(
|
|
543
827
|
"src/modules/auth/LoginForm.component.tsx",
|
|
544
|
-
["component", {
|
|
828
|
+
["component", { foo: "auth" }]
|
|
545
829
|
);
|
|
546
830
|
```
|
|
547
831
|
|