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/dist/index.js CHANGED
@@ -1,34 +1,7 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
- // src/index.ts
21
- var index_exports = {};
22
- __export(index_exports, {
23
- path: () => path,
24
- unsafePath: () => unsafePath
25
- });
26
- module.exports = __toCommonJS(index_exports);
27
-
28
1
  // src/constants.ts
29
2
  var PATH_SEGMENTS = /* @__PURE__ */ Symbol("PATH_SEGMENTS");
30
- var WILDCARD = "*";
31
- var DEEP_WILDCARD = "**";
3
+ var WILDCARD = /* @__PURE__ */ Symbol("WILDCARD");
4
+ var DEEP_WILDCARD = /* @__PURE__ */ Symbol("DEEP_WILDCARD");
32
5
 
33
6
  // src/utils.ts
34
7
  function isCanonicalArrayIndex(key) {
@@ -41,7 +14,7 @@ function resolveSegments(target) {
41
14
  const result = target(proxy);
42
15
  return result?.[PATH_SEGMENTS] ?? [];
43
16
  }
44
- if (target && typeof target === "object" && "segments" in target) {
17
+ if (target != null && typeof target === "object" && "segments" in target) {
45
18
  return target.segments;
46
19
  }
47
20
  return [];
@@ -53,11 +26,9 @@ function createPathProxy(segments) {
53
26
  get(target, key) {
54
27
  if (key === PATH_SEGMENTS)
55
28
  return target[PATH_SEGMENTS];
56
- if (typeof key === "string" && key !== "Symbol") {
57
- const next = isCanonicalArrayIndex(key) ? Number(key) : key;
58
- return createPathProxy([...segments, next]);
59
- }
60
- return typeof key === "symbol" ? void 0 : createPathProxy(segments);
29
+ if (typeof key === "symbol") return void 0;
30
+ const next = isCanonicalArrayIndex(key) ? Number(key) : key;
31
+ return createPathProxy([...segments, next]);
61
32
  }
62
33
  }
63
34
  );
@@ -67,10 +38,12 @@ function segmentsEqual(a, b) {
67
38
  return a.every((s, i) => s === b[i]);
68
39
  }
69
40
  function matchesPrefix(full, prefix) {
70
- if (prefix.length > full.length) return false;
41
+ let minPrefixLen = 0;
42
+ for (const s of prefix) if (s !== DEEP_WILDCARD) minPrefixLen++;
43
+ if (minPrefixLen > full.length) return false;
71
44
  let p = 0;
72
45
  let f = 0;
73
- while (p < prefix.length && f < full.length) {
46
+ while (p < prefix.length) {
74
47
  if (prefix[p] === DEEP_WILDCARD) {
75
48
  if (p === prefix.length - 1) return true;
76
49
  const restPrefix = prefix.slice(p + 1);
@@ -79,6 +52,7 @@ function matchesPrefix(full, prefix) {
79
52
  }
80
53
  return false;
81
54
  }
55
+ if (f >= full.length) return false;
82
56
  if (prefix[p] !== WILDCARD && prefix[p] !== full[f]) return false;
83
57
  p++;
84
58
  f++;
@@ -86,57 +60,76 @@ function matchesPrefix(full, prefix) {
86
60
  return p === prefix.length;
87
61
  }
88
62
  function patternMatches(pattern, concrete) {
89
- if (pattern.length !== concrete.length) return false;
90
- for (let i = 0; i < pattern.length; i++) {
91
- if (pattern[i] !== WILDCARD && pattern[i] !== DEEP_WILDCARD && pattern[i] !== concrete[i])
63
+ function walk(pi, ci) {
64
+ if (pi === pattern.length) return ci === concrete.length;
65
+ const seg = pattern[pi];
66
+ if (seg === DEEP_WILDCARD) {
67
+ for (let skip = 0; ci + skip <= concrete.length; skip++) {
68
+ if (walk(pi + 1, ci + skip)) return true;
69
+ }
92
70
  return false;
71
+ }
72
+ if (ci === concrete.length) return false;
73
+ if (seg === WILDCARD) return walk(pi + 1, ci + 1);
74
+ if (seg !== concrete[ci]) return false;
75
+ return walk(pi + 1, ci + 1);
93
76
  }
94
- return true;
77
+ return walk(0, 0);
95
78
  }
96
-
97
- // src/impl/path-impl.ts
98
- var TemplatePathCtor;
99
- function setTemplatePathCtor(ctor) {
100
- TemplatePathCtor = ctor;
79
+ function hasWildcardSegment(segments) {
80
+ for (const s of segments) {
81
+ if (s === WILDCARD || s === DEEP_WILDCARD) return true;
82
+ }
83
+ return false;
101
84
  }
102
- var PathImpl = class _PathImpl {
85
+
86
+ // src/impl/base-path-impl.ts
87
+ var AbstractPathImpl = class {
103
88
  segments;
104
89
  constructor(segments) {
105
90
  this.segments = segments;
106
91
  }
107
- /**
108
- * The number of segments in this path.
109
- */
110
92
  get length() {
111
93
  return this.segments.length;
112
94
  }
113
- /**
114
- * The string representation of the path (e.g. "users.0.name").
115
- * Useful for binding paths to form libraries or UI components.
116
- *
117
- * @example
118
- * path<Root>().users[0].name.$; // "users.0.name"
119
- */
120
95
  get $() {
121
96
  return this.toString();
122
97
  }
123
- /**
124
- * Returns the string representation of the path (e.g. "users.0.name").
125
- *
126
- * @example
127
- * path<Root>().users[0].name.toString(); // "users.0.name"
128
- */
129
98
  toString() {
130
- return this.segments.join(".");
99
+ return this.segments.map(
100
+ (s) => s === WILDCARD ? "*" : s === DEEP_WILDCARD ? "**" : String(s)
101
+ ).join(".");
102
+ }
103
+ startsWith(other) {
104
+ return matchesPrefix(this.segments, resolveSegments(other));
105
+ }
106
+ covers(other) {
107
+ return matchesPrefix(resolveSegments(other), this.segments);
108
+ }
109
+ equals(other) {
110
+ return segmentsEqual(this.segments, resolveSegments(other));
111
+ }
112
+ match(other) {
113
+ const otherSegs = resolveSegments(other);
114
+ if (segmentsEqual(this.segments, otherSegs)) return { relation: "equals" };
115
+ if (patternMatches(this.segments, otherSegs)) return { relation: "covers" };
116
+ if (patternMatches(otherSegs, this.segments))
117
+ return { relation: "covered-by" };
118
+ if (!hasWildcardSegment(otherSegs) && matchesPrefix(this.segments, otherSegs) && this.segments.length > otherSegs.length)
119
+ return { relation: "child" };
120
+ if (!hasWildcardSegment(this.segments) && matchesPrefix(otherSegs, this.segments) && otherSegs.length > this.segments.length)
121
+ return { relation: "parent" };
122
+ return null;
123
+ }
124
+ };
125
+
126
+ // src/impl/path-impl.ts
127
+ var PathImpl = class extends AbstractPathImpl {
128
+ fn;
129
+ constructor(segments) {
130
+ super(segments);
131
+ this.fn = (data) => this.get(data);
131
132
  }
132
- /**
133
- * Extracts the value at this path from the given data object.
134
- * Safely handles missing intermediate properties by returning `undefined` instead of throwing an error.
135
- *
136
- * @example
137
- * const namePath = path<User>().name;
138
- * const name = namePath.get({ name: "Alice" }); // "Alice"
139
- */
140
133
  get(data) {
141
134
  let current = data;
142
135
  for (const seg of this.segments) {
@@ -145,25 +138,6 @@ var PathImpl = class _PathImpl {
145
138
  }
146
139
  return current;
147
140
  }
148
- /**
149
- * Returns an accessor function that extracts the value at this path from the given data object.
150
- * Useful for array methods like `.map()` or `.filter()`.
151
- *
152
- * @example
153
- * const names = users.map(path<User>().name.fn);
154
- */
155
- get fn() {
156
- return (data) => this.get(data);
157
- }
158
- /**
159
- * Sets the value at this path in the given data object, returning a new updated object (immutable).
160
- * If intermediate properties are missing, they are automatically created as objects or arrays
161
- * depending on the segment types (numeric keys become arrays).
162
- *
163
- * @example
164
- * const namePath = path<User>().name;
165
- * const updatedUser = namePath.set({ name: "Alice" }, "Bob"); // { name: "Bob" }
166
- */
167
141
  set(data, value) {
168
142
  if (this.segments.length === 0) return value;
169
143
  const setAt = (obj, segs, val) => {
@@ -190,308 +164,211 @@ var PathImpl = class _PathImpl {
190
164
  const baseObj = typeof data === "object" && data !== null ? Array.isArray(data) ? [...data] : { ...data } : data;
191
165
  return setAt(baseObj, this.segments, value);
192
166
  }
193
- /**
194
- * Traverses into a collection (Array or Record) to operate on each item.
195
- *
196
- * @example
197
- * const users = path<Root>().users;
198
- * const userNames = users.each(u => u.name); // Path matches all names
199
- */
167
+ update(data, updater) {
168
+ return this.set(data, updater(this.get(data)));
169
+ }
170
+ parent() {
171
+ if (this.segments.length === 0) return null;
172
+ return makeConcrete(
173
+ this.segments.slice(0, -1)
174
+ );
175
+ }
176
+ subtract(prefix) {
177
+ const a = this.segments;
178
+ const b = resolveSegments(prefix);
179
+ if (b.length > a.length) return null;
180
+ if (!segmentsEqual(a.slice(0, b.length), b)) return null;
181
+ return makeConcrete(a.slice(b.length));
182
+ }
183
+ slice(start, end) {
184
+ return makeConcrete(
185
+ this.segments.slice(start, end)
186
+ );
187
+ }
200
188
  each(expr) {
201
- let tailSegments = [];
202
- if (expr) {
203
- const proxy = createPathProxy([]);
204
- const result = expr(proxy);
205
- tailSegments = result?.[PATH_SEGMENTS] ?? [];
206
- }
207
- return new TemplatePathCtor([...this.segments, WILDCARD, ...tailSegments]);
189
+ const tail = expr ? evalExpr(expr) : [];
190
+ return new TemplatePathImpl([
191
+ ...this.segments,
192
+ WILDCARD,
193
+ ...tail
194
+ ]);
208
195
  }
209
- /**
210
- * Traverses deeply into a structure, matching any nested property.
211
- *
212
- * @example
213
- * const root = path<Root>();
214
- * const allIds = root.deep(node => node.id); // Path matches any 'id' at any depth
215
- */
216
196
  deep(expr) {
217
- let tailSegments = [];
218
- if (expr) {
219
- const proxy = createPathProxy([]);
220
- const result = expr(proxy);
221
- tailSegments = result?.[PATH_SEGMENTS] ?? [];
222
- }
223
- return new TemplatePathCtor([
197
+ const tail = expr ? evalExpr(expr) : [];
198
+ return new TemplatePathImpl([
224
199
  ...this.segments,
225
200
  DEEP_WILDCARD,
226
- ...tailSegments
201
+ ...tail
227
202
  ]);
228
203
  }
229
- /**
230
- * Checks if this path starts with the segments of another path.
231
- *
232
- * @example
233
- * const a = path<Root>().users[0].name;
234
- * const b = path<Root>().users;
235
- * a.startsWith(b); // true
236
- */
237
- startsWith(other) {
238
- return matchesPrefix(this.segments, resolveSegments(other));
204
+ to(relative) {
205
+ return makeFromSegments([
206
+ ...this.segments,
207
+ ...resolveSegments(relative)
208
+ ]);
239
209
  }
240
- /**
241
- * Checks if this path encompasses the segments of another path (i.e., this path is a prefix of the other).
242
- *
243
- * @example
244
- * const a = path<Root>().users;
245
- * const b = path<Root>().users[0].name;
246
- * a.includes(b); // true
247
- */
248
- includes(other) {
249
- return matchesPrefix(resolveSegments(other), this.segments);
210
+ merge(other) {
211
+ return makeFromSegments(
212
+ mergeSegments(this.segments, resolveSegments(other))
213
+ );
250
214
  }
251
- /**
252
- * Checks if this path is exactly equal to another path.
253
- *
254
- * @example
255
- * const a = path<Root>().users;
256
- * const b = path<Root>().users;
257
- * a.equals(b); // true
258
- */
259
- equals(other) {
260
- return segmentsEqual(this.segments, resolveSegments(other));
215
+ };
216
+ function makeFromSegments(segments) {
217
+ return hasWildcard(segments) ? new TemplatePathImpl(segments) : new PathImpl(segments);
218
+ }
219
+ function hasWildcard(segments) {
220
+ for (const s of segments) {
221
+ if (s === WILDCARD || s === DEEP_WILDCARD) return true;
261
222
  }
262
- /**
263
- * Matches this path against another path, returning their relationship.
264
- *
265
- * @example
266
- * const a = path<Root>().users[0];
267
- * const b = path<Root>().users;
268
- * a.match(b); // { relation: 'child', params: {} }
269
- */
270
- match(other) {
271
- const otherSegs = resolveSegments(other);
272
- if (segmentsEqual(this.segments, otherSegs)) {
273
- return { relation: "equals", params: {} };
274
- }
275
- if (matchesPrefix(this.segments, otherSegs) && this.segments.length > otherSegs.length) {
276
- return { relation: "child", params: {} };
277
- }
278
- if (matchesPrefix(otherSegs, this.segments) && otherSegs.length > this.segments.length) {
279
- return { relation: "parent", params: {} };
280
- }
281
- if (patternMatches(this.segments, otherSegs)) {
282
- return { relation: "includes", params: {} };
283
- }
284
- if (patternMatches(otherSegs, this.segments)) {
285
- return { relation: "included-by", params: {} };
223
+ return false;
224
+ }
225
+ var TemplatePathImpl = class _TemplatePathImpl extends AbstractPathImpl {
226
+ // fn returns V[] (not V|undefined) — no covariance conflict since we don't
227
+ // extend PathImpl; the declared type here matches TemplatePath<T,V>.fn.
228
+ fn;
229
+ constructor(segments) {
230
+ super(segments);
231
+ this.fn = (data) => this.get(data);
232
+ }
233
+ get(data) {
234
+ return this.expand(data).map(
235
+ // expand() only returns paths where the key exists in data, so get() is safe
236
+ (p) => p.get(data)
237
+ );
238
+ }
239
+ set(data, value) {
240
+ const paths = this.expand(data);
241
+ let current = data;
242
+ for (const p of paths) {
243
+ current = p.set(current, value);
286
244
  }
287
- return null;
245
+ return current;
288
246
  }
289
247
  /**
290
- * Appends another path to the end of this path. If the end of this path matches
291
- * the beginning of the other path, the overlapping segments are intelligently deduplicated.
292
- *
293
- * @example
294
- * const base = path<Root>().users;
295
- * const full = base.merge(p => p[0].name); // equivalent to path<Root>().users[0].name
248
+ * Applies `updater` to each matched value individually (per-item transform).
249
+ * Use `.set(data, constant)` to assign the same value to every match.
296
250
  */
297
- merge(other) {
298
- const a = this.segments;
299
- const b = resolveSegments(other);
300
- let overlapLen = 0;
301
- for (let len = Math.min(a.length, b.length); len >= 1; len--) {
302
- const aSuffix = a.slice(-len);
303
- const bPrefix = b.slice(0, len);
304
- if (segmentsEqual(aSuffix, bPrefix)) {
305
- overlapLen = len;
306
- break;
307
- }
251
+ update(data, updater) {
252
+ const paths = this.expand(data);
253
+ let current = data;
254
+ for (const p of paths) {
255
+ current = p.set(current, updater(p.get(current)));
308
256
  }
309
- const merged = overlapLen > 0 ? [...a.slice(0, -overlapLen), ...b] : [...a, ...b];
310
- return new _PathImpl(merged);
257
+ return current;
311
258
  }
312
- /**
313
- * Removes the segments of another path from either the beginning or the end of this path.
314
- * Returns `null` if the other path is neither a prefix nor a suffix.
315
- *
316
- * @example
317
- * const full = path<Root>().users[0].name;
318
- * const base = path<Root>().users;
319
- * const remainder = full.subtract(base); // equivalent to path()[0].name
320
- */
321
- subtract(other) {
259
+ parent() {
260
+ if (this.segments.length === 0) return null;
261
+ return makeFromSegments(
262
+ this.segments.slice(0, -1)
263
+ );
264
+ }
265
+ subtract(prefix) {
322
266
  const a = this.segments;
323
- const b = resolveSegments(other);
267
+ const b = resolveSegments(prefix);
324
268
  if (b.length > a.length) return null;
325
- if (segmentsEqual(a, b)) return new _PathImpl([]);
326
- if (segmentsEqual(a.slice(0, b.length), b)) {
327
- return new _PathImpl(a.slice(b.length));
328
- }
329
- if (segmentsEqual(a.slice(-b.length), b)) {
330
- return new _PathImpl(a.slice(0, -b.length));
331
- }
332
- return null;
269
+ if (!segmentsEqual(a.slice(0, b.length), b)) return null;
270
+ return makeFromSegments(a.slice(b.length));
333
271
  }
334
- /**
335
- * Returns a new path containing a subset of the segments, similar to Array.prototype.slice.
336
- *
337
- * @example
338
- * const full = path<Root>().users[0].name;
339
- * full.slice(0, 1); // equivalent to path<Root>().users
340
- */
341
272
  slice(start, end) {
342
- const s = this.segments.slice(start, end);
343
- return new _PathImpl(s);
273
+ return makeFromSegments(
274
+ this.segments.slice(start, end)
275
+ );
344
276
  }
345
- /**
346
- * Extends the current path using a lambda expression starting from the resolved value.
347
- *
348
- * @example
349
- * const userPath = path<Root>().users[0];
350
- * const namePath = userPath.to(u => u.name);
351
- */
352
- to(expr) {
353
- const proxy = createPathProxy([]);
354
- const result = expr(proxy);
355
- const tailSegments = result?.[PATH_SEGMENTS] ?? [];
356
- return new _PathImpl([...this.segments, ...tailSegments]);
357
- }
358
- };
359
-
360
- // src/impl/template-path-impl.ts
361
- var TemplatePathImpl = class _TemplatePathImpl extends PathImpl {
362
- /**
363
- * Traverses into a collection (Array or Record) to operate on each item, returning a TemplatePath.
364
- *
365
- * @example
366
- * const users = path<Root>().users;
367
- * const userNames = users.each(u => u.name); // TemplatePath matching all names
368
- */
369
277
  each(expr) {
370
- let tailSegments = [];
371
- if (expr) {
372
- const proxy = createPathProxy([]);
373
- const result = expr(proxy);
374
- tailSegments = result?.[PATH_SEGMENTS] ?? [];
375
- }
278
+ const tail = expr ? evalExpr(expr) : [];
376
279
  return new _TemplatePathImpl([
377
280
  ...this.segments,
378
281
  WILDCARD,
379
- ...tailSegments
282
+ ...tail
380
283
  ]);
381
284
  }
382
- /**
383
- * Traverses deeply into a structure, matching any nested property, returning a TemplatePath.
384
- *
385
- * @example
386
- * const root = path<Root>();
387
- * const allIds = root.deep(node => node.id); // TemplatePath matching any 'id' at any depth
388
- */
389
285
  deep(expr) {
390
- let tailSegments = [];
391
- if (expr) {
392
- const proxy = createPathProxy([]);
393
- const result = expr(proxy);
394
- tailSegments = result?.[PATH_SEGMENTS] ?? [];
395
- }
286
+ const tail = expr ? evalExpr(expr) : [];
396
287
  return new _TemplatePathImpl([
397
288
  ...this.segments,
398
289
  DEEP_WILDCARD,
399
- ...tailSegments
290
+ ...tail
291
+ ]);
292
+ }
293
+ to(relative) {
294
+ const tail = resolveSegments(relative);
295
+ return new _TemplatePathImpl([
296
+ ...this.segments,
297
+ ...tail
400
298
  ]);
401
299
  }
300
+ merge(other) {
301
+ return new _TemplatePathImpl(
302
+ mergeSegments(this.segments, resolveSegments(other))
303
+ );
304
+ }
402
305
  /**
403
- * Resolves this template path against actual data to return an array of concrete paths
404
- * that exist in the given data.
405
- *
406
- * @example
407
- * const template = path<Root>().users.each().name;
408
- * const concretePaths = template.expand(data); // [path<Root>().users[0].name, ...]
306
+ * Resolves this template to all concrete paths that exist in `data`.
409
307
  */
410
308
  expand(data) {
411
309
  const results = [];
412
- const walk = (currentData, segmentIdx, currentPath) => {
413
- if (segmentIdx >= this.segments.length) {
414
- results.push(new PathImpl(currentPath));
310
+ const walk = (current, idx, acc) => {
311
+ if (idx >= this.segments.length) {
312
+ results.push(new PathImpl(acc));
415
313
  return;
416
314
  }
417
- const seg = this.segments[segmentIdx];
315
+ const seg = this.segments[idx];
418
316
  if (seg === WILDCARD) {
419
- if (currentData != null && typeof currentData === "object") {
420
- const keys = Array.isArray(currentData) ? Array.from(currentData.keys()) : Object.keys(currentData);
317
+ if (current != null && typeof current === "object") {
318
+ const keys = Array.isArray(current) ? Array.from(current.keys()) : Object.keys(current);
421
319
  for (const key of keys) {
422
- walk(
423
- currentData[key],
424
- segmentIdx + 1,
425
- [...currentPath, key]
426
- );
320
+ walk(current[key], idx + 1, [
321
+ ...acc,
322
+ key
323
+ ]);
427
324
  }
428
325
  }
429
326
  } else if (seg === DEEP_WILDCARD) {
430
- walk(currentData, segmentIdx + 1, currentPath);
431
- if (currentData != null && typeof currentData === "object") {
432
- const keys = Array.isArray(currentData) ? Array.from(currentData.keys()) : Object.keys(currentData);
327
+ walk(current, idx + 1, acc);
328
+ if (current != null && typeof current === "object") {
329
+ const keys = Array.isArray(current) ? Array.from(current.keys()) : Object.keys(current);
433
330
  for (const key of keys) {
434
- walk(
435
- currentData[key],
436
- segmentIdx,
437
- [...currentPath, key]
438
- );
331
+ walk(current[key], idx, [
332
+ ...acc,
333
+ key
334
+ ]);
439
335
  }
440
336
  }
441
337
  } else {
442
- if (currentData != null && typeof currentData === "object" && seg in currentData) {
443
- walk(
444
- currentData[seg],
445
- segmentIdx + 1,
446
- [...currentPath, seg]
447
- );
338
+ if (current != null && typeof current === "object" && seg in current) {
339
+ walk(current[seg], idx + 1, [
340
+ ...acc,
341
+ seg
342
+ ]);
448
343
  }
449
344
  }
450
345
  };
451
346
  walk(data, 0, []);
452
347
  return results;
453
348
  }
454
- /**
455
- * Extracts an array of values at this template path from the given data object.
456
- *
457
- * @example
458
- * const names = path<Root>().users.each().name.get(data); // string[]
459
- */
460
- // @ts-expect-error Overriding get to return an array instead of a single value
461
- get(data) {
462
- return this.expand(data).map((p) => p.get(data));
463
- }
464
- /**
465
- * Returns an accessor function that extracts an array of values at this template path from the given data object.
466
- * Useful for array methods like `.map()` or `.filter()`.
467
- *
468
- * @example
469
- * const allNames = companies.map(path<Company>().departments.each().name.fn);
470
- */
471
- // @ts-expect-error Overriding fn to return an array instead of a single value
472
- get fn() {
473
- return (data) => this.get(data);
474
- }
475
- /**
476
- * Sets the provided value to all matching paths immutably.
477
- *
478
- * @example
479
- * const updatedData = path<Root>().users.each().name.set(data, "Bob");
480
- */
481
- set(data, value) {
482
- const paths = this.expand(data);
483
- let current = data;
484
- for (const p of paths) {
485
- current = p.set(current, value);
349
+ };
350
+ function makeConcrete(segments) {
351
+ return new PathImpl(segments);
352
+ }
353
+ function evalExpr(expr) {
354
+ const proxy = createPathProxy([]);
355
+ const result = expr(proxy);
356
+ return result?.[PATH_SEGMENTS] ?? [];
357
+ }
358
+ function mergeSegments(a, b) {
359
+ let overlapLen = 0;
360
+ for (let len = Math.min(a.length, b.length); len >= 1; len--) {
361
+ if (segmentsEqual(a.slice(-len), b.slice(0, len))) {
362
+ overlapLen = len;
363
+ break;
486
364
  }
487
- return current;
488
365
  }
489
- };
366
+ return overlapLen > 0 ? [...a.slice(0, -overlapLen), ...b] : [...a, ...b];
367
+ }
490
368
 
491
369
  // src/path.ts
492
- setTemplatePathCtor(TemplatePathImpl);
493
370
  function path(baseOrExpr, expr) {
494
- if (!baseOrExpr) {
371
+ if (baseOrExpr === void 0) {
495
372
  return new PathImpl([]);
496
373
  }
497
374
  if (typeof baseOrExpr === "function") {
@@ -501,18 +378,11 @@ function path(baseOrExpr, expr) {
501
378
  return new PathImpl(segments);
502
379
  }
503
380
  const baseSegments = baseOrExpr.segments;
504
- if (expr) {
505
- if (typeof expr === "function") {
506
- const proxy = createPathProxy([]);
507
- const result = expr(proxy);
508
- const tailSegments = result?.[PATH_SEGMENTS] ?? [];
509
- return new PathImpl([...baseSegments, ...tailSegments]);
510
- } else if (typeof expr === "object" && "segments" in expr) {
511
- return new PathImpl([
512
- ...baseSegments,
513
- ...expr.segments
514
- ]);
515
- }
381
+ if (expr !== void 0) {
382
+ const proxy = createPathProxy([]);
383
+ const result = expr(proxy);
384
+ const tailSegments = result?.[PATH_SEGMENTS] ?? [];
385
+ return new PathImpl([...baseSegments, ...tailSegments]);
516
386
  }
517
387
  return new PathImpl(baseSegments);
518
388
  }
@@ -520,8 +390,10 @@ function unsafePath(raw) {
520
390
  const segments = raw ? raw.split(".").map((s) => s === "" ? s : isCanonicalArrayIndex(s) ? Number(s) : s) : [];
521
391
  return new PathImpl(segments);
522
392
  }
523
- // Annotate the CommonJS export names for ESM import in node:
524
- 0 && (module.exports = {
393
+ export {
394
+ DEEP_WILDCARD,
395
+ WILDCARD,
525
396
  path,
526
397
  unsafePath
527
- });
398
+ };
399
+ //# sourceMappingURL=index.js.map