data-path 1.0.2 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +60 -407
- package/dist/index.cjs +429 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +376 -0
- package/dist/index.d.ts +243 -186
- package/dist/index.js +221 -349
- package/dist/index.js.map +1 -0
- package/package.json +109 -68
- package/dist/index.d.mts +0 -319
- package/dist/index.mjs +0 -499
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sentinel for a single-level wildcard segment (`each`).
|
|
3
|
+
*
|
|
4
|
+
* Stored as a unique Symbol — NOT the string `"*"` — so that a legitimate
|
|
5
|
+
* object key named `"*"` is preserved as a literal segment and never
|
|
6
|
+
* reinterpreted as a wildcard by `.get`, `.expand`, `.covers`, `.match`, etc.
|
|
7
|
+
*
|
|
8
|
+
* Renders as `"*"` in `toString()` / `.$` for dot-notation compatibility.
|
|
9
|
+
*/
|
|
10
|
+
declare const WILDCARD: unique symbol;
|
|
11
|
+
/**
|
|
12
|
+
* Sentinel for a deep wildcard segment (`deep`).
|
|
13
|
+
*
|
|
14
|
+
* Same rationale as {@link WILDCARD}: stored as a unique Symbol so the
|
|
15
|
+
* literal string `"**"` remains a valid (literal) object key.
|
|
16
|
+
*
|
|
17
|
+
* Renders as `"**"` in `toString()` / `.$`.
|
|
18
|
+
*/
|
|
19
|
+
declare const DEEP_WILDCARD: unique symbol;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Core type definitions for data-path.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* A path segment.
|
|
27
|
+
*
|
|
28
|
+
* - `string` — object key
|
|
29
|
+
* - `number` — array index
|
|
30
|
+
* - `typeof WILDCARD` — single-level wildcard sentinel (inserted by `.each()`)
|
|
31
|
+
* - `typeof DEEP_WILDCARD` — deep wildcard sentinel (inserted by `.deep()`)
|
|
32
|
+
*
|
|
33
|
+
* The wildcard sentinels are unique Symbols (not the strings `"*"` / `"**"`),
|
|
34
|
+
* so legitimate object keys named `"*"` or `"**"` are preserved as literal
|
|
35
|
+
* string segments and never reinterpreted as wildcards by any method.
|
|
36
|
+
*
|
|
37
|
+
* The sentinels render as `"*"` / `"**"` in `toString()` / `.$` so dot-notation
|
|
38
|
+
* output and form-library bindings are unaffected.
|
|
39
|
+
*/
|
|
40
|
+
type Segment = string | number | typeof WILDCARD | typeof DEEP_WILDCARD;
|
|
41
|
+
/**
|
|
42
|
+
* The structural relation returned by `.match()`.
|
|
43
|
+
*
|
|
44
|
+
* Semantics when calling `a.match(b)`:
|
|
45
|
+
* - `"parent"` — `a` is a prefix of `b` (a is the parent, b is deeper)
|
|
46
|
+
* - `"child"` — `b` is a prefix of `a` (b is the parent, a is deeper)
|
|
47
|
+
* - `"equals"` — `a` and `b` are identical
|
|
48
|
+
* - `"covers"` — `a` (with wildcards) covers `b` as a concrete match
|
|
49
|
+
* - `"covered-by"` — `b` (with wildcards) covers `a` as a concrete match
|
|
50
|
+
*/
|
|
51
|
+
type MatchRelation = "covers" | "covered-by" | "equals" | "parent" | "child";
|
|
52
|
+
/** Result of .match() — relation only; params are reserved for named-wildcard support */
|
|
53
|
+
interface MatchResult {
|
|
54
|
+
relation: MatchRelation;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Extracts the resolved value type from a path object.
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* const agePath = path<User>(p => p.profile.age);
|
|
61
|
+
* type Age = ResolvedType<typeof agePath>; // number
|
|
62
|
+
*/
|
|
63
|
+
type ResolvedType<P> = P extends {
|
|
64
|
+
get(data: any): (infer V)[];
|
|
65
|
+
} ? V : P extends BasePath<any, infer V> ? V : never;
|
|
66
|
+
/**
|
|
67
|
+
* Extracts the item type from a collection (Array or Record).
|
|
68
|
+
* Used by `.each()` to infer the traversal target.
|
|
69
|
+
*/
|
|
70
|
+
type CollectionItem<V> = V extends ReadonlyArray<infer U> ? U : V extends Record<PropertyKey, infer U> ? U : unknown;
|
|
71
|
+
/** Primitive types that cannot be traversed — `.each()` and `.deep()` are hidden when V extends Primitive */
|
|
72
|
+
type Primitive = string | number | boolean | symbol | bigint | null | undefined;
|
|
73
|
+
/** Lambda used to build a path — receives a proxy typed as T, infers the path from property access */
|
|
74
|
+
type PathExpression<T, R = unknown> = (proxy: T) => R;
|
|
75
|
+
/**
|
|
76
|
+
* Flexible path argument — accepts an existing path, a `{segments}` shape, or a lambda expression.
|
|
77
|
+
* Used by all methods that accept a path as an argument.
|
|
78
|
+
*/
|
|
79
|
+
type ResolvablePath<T, V = unknown> = BasePath<T, V> | {
|
|
80
|
+
segments: readonly Segment[];
|
|
81
|
+
} | PathExpression<T, V>;
|
|
82
|
+
/**
|
|
83
|
+
* Traversal methods — only present when V is not a primitive type.
|
|
84
|
+
* Conditionally excluded by the Path and TemplatePath types.
|
|
85
|
+
*/
|
|
86
|
+
interface TraversablePathMethods<T, V> {
|
|
87
|
+
/**
|
|
88
|
+
* Traverses into a collection (Array or Record), inserting a `*` wildcard.
|
|
89
|
+
* Returns a TemplatePath that matches every item.
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* path<Root>().users.each(u => u.name) // TemplatePath — all names
|
|
93
|
+
* path<Root>().users.each() // TemplatePath — all items
|
|
94
|
+
*/
|
|
95
|
+
each<U = CollectionItem<V>>(expr?: (item: CollectionItem<V>) => U): TemplatePath<T, U>;
|
|
96
|
+
/**
|
|
97
|
+
* Traverses deeply into a structure, inserting a `**` wildcard.
|
|
98
|
+
* Returns a TemplatePath that matches the given property at any nesting depth.
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* path<Root>().tree.deep(node => node.id) // TemplatePath — any nested 'id'
|
|
102
|
+
* path<Root>().tree.deep() // TemplatePath — every descendant node
|
|
103
|
+
*/
|
|
104
|
+
deep<U = V>(expr?: (leaf: V) => U): TemplatePath<T, U>;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* The foundational interface shared by both Path and TemplatePath.
|
|
108
|
+
*
|
|
109
|
+
* @template T Root data type the path operates on
|
|
110
|
+
* @template V Resolved value type at the end of the path
|
|
111
|
+
*/
|
|
112
|
+
interface BasePath<T = unknown, V = unknown> {
|
|
113
|
+
/** Ordered array of string keys and numeric indices that compose this path. */
|
|
114
|
+
readonly segments: readonly Segment[];
|
|
115
|
+
/** Number of segments in this path. */
|
|
116
|
+
readonly length: number;
|
|
117
|
+
/**
|
|
118
|
+
* Dot-notation string representation (e.g. `"users.0.name"`).
|
|
119
|
+
* Convenient for binding paths to form libraries.
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* path<Root>(r => r.users[0].name).$ // "users.0.name"
|
|
123
|
+
*/
|
|
124
|
+
readonly $: string;
|
|
125
|
+
/** Returns the dot-notation string representation. */
|
|
126
|
+
toString(): string;
|
|
127
|
+
/**
|
|
128
|
+
* Extracts the value at this path from a data object.
|
|
129
|
+
* Returns `undefined` — rather than throwing — when any intermediate segment is missing.
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* path<User>(u => u.profile.name).get(user) // string | undefined
|
|
133
|
+
*/
|
|
134
|
+
get(data: T): V | undefined;
|
|
135
|
+
/**
|
|
136
|
+
* Pre-bound accessor function. Useful for array higher-order methods.
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* users.map(path<User>(u => u.name).fn) // string | undefined[]
|
|
140
|
+
*/
|
|
141
|
+
readonly fn: (data: T) => V | undefined;
|
|
142
|
+
/**
|
|
143
|
+
* Immutably sets the value at this path, returning a structurally-cloned object.
|
|
144
|
+
* Missing intermediates are created automatically:
|
|
145
|
+
* numeric next-segment → array, string next-segment → object.
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* path<User>(u => u.name).set(user, "Alice")
|
|
149
|
+
*/
|
|
150
|
+
set(data: T, value: V): T;
|
|
151
|
+
/**
|
|
152
|
+
* Reads the current value, passes it to `updater`, and writes the result back immutably.
|
|
153
|
+
* Combines `.get()` + `.set()` in a single expression.
|
|
154
|
+
* On a `TemplatePath`, `updater` is called once per expanded match (per-item transform).
|
|
155
|
+
*
|
|
156
|
+
* @example
|
|
157
|
+
* namePath.update(user, name => (name ?? "").toUpperCase())
|
|
158
|
+
*/
|
|
159
|
+
update(data: T, updater: (current: V | undefined) => V): T;
|
|
160
|
+
/**
|
|
161
|
+
* Returns the parent path (all segments except the last), or `null` for a root/empty path.
|
|
162
|
+
* Value type becomes `unknown` — use a typed path expression if the parent type is needed.
|
|
163
|
+
*
|
|
164
|
+
* @example
|
|
165
|
+
* path<User>(u => u.profile.name).parent()?.$ // "profile"
|
|
166
|
+
* path<User>().parent() // null
|
|
167
|
+
*/
|
|
168
|
+
parent(): Path<T, unknown> | null;
|
|
169
|
+
/**
|
|
170
|
+
* Returns `true` if this path's segments begin with all segments of `other`
|
|
171
|
+
* (i.e. `other` is a prefix of `this`). Supports wildcard segments.
|
|
172
|
+
*/
|
|
173
|
+
startsWith(other: ResolvablePath<T>): boolean;
|
|
174
|
+
/**
|
|
175
|
+
* Returns `true` if this path's domain covers `other` — i.e. this path's segments
|
|
176
|
+
* are a prefix of `other`'s segments (or match `other` via wildcards). The inverse
|
|
177
|
+
* direction of {@link startsWith}.
|
|
178
|
+
*
|
|
179
|
+
* NOTE: this is NOT analogous to `Array.prototype.includes` / `String.prototype.includes`.
|
|
180
|
+
* Think "covers a location in the data tree", not "contains as an element".
|
|
181
|
+
*
|
|
182
|
+
* @example
|
|
183
|
+
* profilePath.covers(namePath) // true — "profile" covers "profile.name"
|
|
184
|
+
* namePath.covers(profilePath) // false
|
|
185
|
+
*/
|
|
186
|
+
covers(other: ResolvablePath<T>): boolean;
|
|
187
|
+
/** Returns `true` if this path is segment-by-segment identical to `other`. */
|
|
188
|
+
equals(other: ResolvablePath<T>): boolean;
|
|
189
|
+
/**
|
|
190
|
+
* Returns the structural relationship between this path and `other`, or `null` when unrelated.
|
|
191
|
+
*
|
|
192
|
+
* `"parent"` means **this** path is the parent (shorter prefix); `"child"` means **this** is deeper.
|
|
193
|
+
*
|
|
194
|
+
* @example
|
|
195
|
+
* profilePath.match(namePath) // { relation: "parent" } — profilePath IS the parent
|
|
196
|
+
* namePath.match(profilePath) // { relation: "child" } — namePath is deeper
|
|
197
|
+
*/
|
|
198
|
+
match(other: ResolvablePath<T>): MatchResult | null;
|
|
199
|
+
/**
|
|
200
|
+
* Appends `other` (a T-rooted path) with smart suffix/prefix overlap deduplication.
|
|
201
|
+
* When the tail of this path matches the head of `other`, the overlap is collapsed once.
|
|
202
|
+
*
|
|
203
|
+
* If `other` carries wildcards (`*` / `**`), the result is a `TemplatePath` so the
|
|
204
|
+
* appended pattern still expands at `.get()` time; otherwise a concrete `Path`.
|
|
205
|
+
* Narrow at the call site if you need to disambiguate.
|
|
206
|
+
*
|
|
207
|
+
* @example
|
|
208
|
+
* const base = path<Root>(r => r.users[0].profile);
|
|
209
|
+
* base.merge(r => r.users[0].profile.name) // "users.0.profile.name" (no duplication)
|
|
210
|
+
*/
|
|
211
|
+
merge<U>(other: ResolvablePath<T, U>): Path<T, U> | TemplatePath<T, U>;
|
|
212
|
+
/**
|
|
213
|
+
* Removes `prefix` from the start of this path and returns the remaining tail.
|
|
214
|
+
* Returns `null` when `prefix` is not a leading segment-sequence of this path.
|
|
215
|
+
*
|
|
216
|
+
* The returned path carries the correct root type (`U` — the type `prefix` resolves to),
|
|
217
|
+
* so it can be passed directly to `.to()` or used independently.
|
|
218
|
+
*
|
|
219
|
+
* @example
|
|
220
|
+
* const full = path<Company>(c => c.departments[0].employees[0].name);
|
|
221
|
+
* const prefix = path<Company>(c => c.departments[0]);
|
|
222
|
+
* full.subtract(prefix) // Path<Department, string>
|
|
223
|
+
*/
|
|
224
|
+
subtract<U>(prefix: ResolvablePath<T, U>): Path<U, V> | null;
|
|
225
|
+
/**
|
|
226
|
+
* Returns a new path over a slice of segments, following `Array.prototype.slice` semantics.
|
|
227
|
+
* Value type becomes `unknown` because the type at an arbitrary segment boundary is not statically inferable.
|
|
228
|
+
*
|
|
229
|
+
* @example
|
|
230
|
+
* path<Root>(r => r.users[0].name).slice(0, 2).$ // "users.0"
|
|
231
|
+
*/
|
|
232
|
+
slice(start?: number, end?: number): Path<T, unknown>;
|
|
233
|
+
/**
|
|
234
|
+
* Extends this path with a relative path rooted at `V`.
|
|
235
|
+
* Accepts a lambda expression, a pre-built `Path<V, U>`, a `TemplatePath<V, U>`, or any `{segments}` object.
|
|
236
|
+
*
|
|
237
|
+
* If `relative` carries wildcards (`*` / `**`), the result is a `TemplatePath` so the
|
|
238
|
+
* appended pattern still expands at `.get()` time; otherwise a concrete `Path`.
|
|
239
|
+
* Narrow at the call site if you need to disambiguate.
|
|
240
|
+
*
|
|
241
|
+
* @example
|
|
242
|
+
* // Lambda form:
|
|
243
|
+
* employeePath.to(e => e.profile.firstName)
|
|
244
|
+
*
|
|
245
|
+
* // Pre-built path form (no extra lambda needed):
|
|
246
|
+
* const firstName = path<Employee>(e => e.profile.firstName);
|
|
247
|
+
* employeePath.to(firstName)
|
|
248
|
+
*/
|
|
249
|
+
to<U>(relative: ResolvablePath<V, U>): Path<T, U> | TemplatePath<T, U>;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* A strongly-typed object property path.
|
|
253
|
+
* `.each()` and `.deep()` are only present when `V` is not a primitive type.
|
|
254
|
+
*
|
|
255
|
+
* @template T Root data type
|
|
256
|
+
* @template V Resolved value type at the end of the path
|
|
257
|
+
*/
|
|
258
|
+
type Path<T = unknown, V = unknown> = BasePath<T, V> & ([V] extends [Primitive] ? {} : TraversablePathMethods<T, V>);
|
|
259
|
+
/**
|
|
260
|
+
* A path that contains wildcards (`*` or `**`), matching multiple values at once.
|
|
261
|
+
*
|
|
262
|
+
* - `.get(data)` returns an array of all matched values.
|
|
263
|
+
* - `.set(data, value)` immutably sets every match to the same constant.
|
|
264
|
+
* - `.update(data, fn)` applies a per-item transform to every match.
|
|
265
|
+
* - `.expand(data)` resolves the template to an array of concrete `Path` objects.
|
|
266
|
+
*
|
|
267
|
+
* @template T Root data type
|
|
268
|
+
* @template V Item value type at the end of the template path
|
|
269
|
+
*/
|
|
270
|
+
type TemplatePath<T = unknown, V = unknown> = Omit<BasePath<T, V>, "get" | "fn" | "to" | "merge" | "subtract" | "parent" | "slice"> & {
|
|
271
|
+
/**
|
|
272
|
+
* Returns an array of all values matched by this template.
|
|
273
|
+
*
|
|
274
|
+
* @example
|
|
275
|
+
* path<Root>().users.each(u => u.name).get(data) // string[]
|
|
276
|
+
*/
|
|
277
|
+
get(data: T): V[];
|
|
278
|
+
/**
|
|
279
|
+
* Pre-bound accessor function returning an array of all matched values.
|
|
280
|
+
*
|
|
281
|
+
* @example
|
|
282
|
+
* companies.map(path<Company>().departments.each(d => d.name).fn)
|
|
283
|
+
*/
|
|
284
|
+
readonly fn: (data: T) => V[];
|
|
285
|
+
/**
|
|
286
|
+
* Resolves this template to an array of concrete paths that exist in `data`.
|
|
287
|
+
*
|
|
288
|
+
* @example
|
|
289
|
+
* path<Root>().users.each().name.expand(data)
|
|
290
|
+
* // [path<Root>().users[0].name, path<Root>().users[1].name, ...]
|
|
291
|
+
*/
|
|
292
|
+
expand(data: T): Path<T, V>[];
|
|
293
|
+
/**
|
|
294
|
+
* Extends this template with a relative path rooted at `V`, preserving wildcard expansion.
|
|
295
|
+
* Returns a `TemplatePath` so the full chain (including the appended segments) is template-aware.
|
|
296
|
+
*
|
|
297
|
+
* @example
|
|
298
|
+
* path<Root>(r => r.users).each().to(u => u.name)
|
|
299
|
+
* // TemplatePath — collects every user's name
|
|
300
|
+
*/
|
|
301
|
+
to<U>(relative: ResolvablePath<V, U>): TemplatePath<T, U>;
|
|
302
|
+
/**
|
|
303
|
+
* Appends `other` with smart overlap deduplication, preserving wildcard behavior.
|
|
304
|
+
* Returns a `TemplatePath` because `this` carries wildcards.
|
|
305
|
+
*/
|
|
306
|
+
merge<U>(other: ResolvablePath<T, U>): TemplatePath<T, U>;
|
|
307
|
+
/**
|
|
308
|
+
* Returns the parent path (all segments except the last), or `null` for an empty path.
|
|
309
|
+
* If the parent still contains wildcards (`*` / `**`) it remains a `TemplatePath`;
|
|
310
|
+
* otherwise a concrete `Path` is returned. Narrow at the call site if needed.
|
|
311
|
+
*/
|
|
312
|
+
parent(): Path<T, unknown> | TemplatePath<T, unknown> | null;
|
|
313
|
+
/**
|
|
314
|
+
* Returns a new path over a slice of segments. If the slice still contains wildcards
|
|
315
|
+
* the result is a `TemplatePath`; otherwise a concrete `Path`.
|
|
316
|
+
*/
|
|
317
|
+
slice(start?: number, end?: number): Path<T, unknown> | TemplatePath<T, unknown>;
|
|
318
|
+
/**
|
|
319
|
+
* Removes `prefix` from the start of this path and returns the remaining tail.
|
|
320
|
+
* If the tail still contains wildcards the result is a `TemplatePath<U, V>`;
|
|
321
|
+
* otherwise a concrete `Path<U, V>`. Returns `null` when `prefix` is not a leading segment-sequence.
|
|
322
|
+
*/
|
|
323
|
+
subtract<U>(prefix: ResolvablePath<T, U>): Path<U, V> | TemplatePath<U, V> | null;
|
|
324
|
+
} & ([V] extends [Primitive] ? {} : {
|
|
325
|
+
each<U = CollectionItem<V>>(expr?: (item: CollectionItem<V>) => U): TemplatePath<T, U>;
|
|
326
|
+
deep<U = V>(expr?: (leaf: V) => U): TemplatePath<T, U>;
|
|
327
|
+
});
|
|
328
|
+
/**
|
|
329
|
+
* The overloaded call signature of the `path()` function.
|
|
330
|
+
*/
|
|
331
|
+
type PathConstructor = {
|
|
332
|
+
<T>(): Path<T, T>;
|
|
333
|
+
<T, V = unknown>(expr: PathExpression<T, V>): Path<T, V>;
|
|
334
|
+
<T, U, V = unknown>(base: BasePath<T, U>, expr: PathExpression<U, V>): Path<T, V>;
|
|
335
|
+
};
|
|
336
|
+
/** Call signature of the `unsafePath()` function */
|
|
337
|
+
type UnsafePathConstructor = <T, V = unknown>(raw: string) => Path<T, V>;
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Create a typed path from a lambda expression, from an existing base path, or as a root.
|
|
341
|
+
*
|
|
342
|
+
* @example
|
|
343
|
+
* // Lambda — recommended: annotate the parameter so both T and V are inferred
|
|
344
|
+
* const p = path((user: User) => user.profile.firstName);
|
|
345
|
+
*
|
|
346
|
+
* @example
|
|
347
|
+
* // Both generics explicit
|
|
348
|
+
* const p = path<User, string>((u) => u.profile.firstName);
|
|
349
|
+
*
|
|
350
|
+
* @example
|
|
351
|
+
* // Root path (no segments) — typically extended via .to() or path(root, expr)
|
|
352
|
+
* const root = path<User>();
|
|
353
|
+
*
|
|
354
|
+
* @example
|
|
355
|
+
* // Extend an existing base path
|
|
356
|
+
* const p2 = path(root, (u) => u.profile);
|
|
357
|
+
*/
|
|
358
|
+
declare function path<T>(): Path<T, T>;
|
|
359
|
+
declare function path<T, V = unknown>(expr: PathExpression<T, V>): Path<T, V>;
|
|
360
|
+
declare function path<T, U, V = unknown>(base: BasePath<T, U>, expr: PathExpression<U, V>): Path<T, V>;
|
|
361
|
+
/**
|
|
362
|
+
* Create a path from a raw dot-separated string (e.g. `"users.0.name"`).
|
|
363
|
+
*
|
|
364
|
+
* Useful for dynamic paths from external sources (API responses, Zod issue paths, etc.).
|
|
365
|
+
* Segments that are canonical non-negative integers are stored as numbers; all others as strings.
|
|
366
|
+
*
|
|
367
|
+
* The optional second generic `V` declares the expected leaf type without a cast:
|
|
368
|
+
* ```ts
|
|
369
|
+
* unsafePath<User, string>("profile.firstName").get(user) // string | undefined
|
|
370
|
+
* ```
|
|
371
|
+
*
|
|
372
|
+
* @param raw Dot-separated string. Empty string returns a zero-segment root path.
|
|
373
|
+
*/
|
|
374
|
+
declare function unsafePath<T, V = unknown>(raw: string): Path<T, V>;
|
|
375
|
+
|
|
376
|
+
export { type BasePath, type CollectionItem, DEEP_WILDCARD, type MatchRelation, type MatchResult, type Path, type PathConstructor, type PathExpression, type Primitive, type ResolvablePath, type ResolvedType, type Segment, type TemplatePath, type TraversablePathMethods, type UnsafePathConstructor, WILDCARD, path, unsafePath };
|