Merging and Extending Paths
Relevant source files
The following files were used as context for generating this wiki page:
The data-path library provides a robust system for programmatic path manipulation through merging, extension, and subtraction. These operations allow developers to build complex, deeply nested paths by combining smaller, reusable path segments or lambda expressions while maintaining full type safety and structural integrity.
Path manipulation is essential for scenarios where a component might receive a base path and need to operate on a relative sub-path, or when merging paths that might share overlapping segments. The library handles these cases using intelligent deduplication logic and immutable operations.
Sources: README.md:104-106, src/impl/path-impl.ts:245-249
Path Extension Mechanisms
Extending a path involves appending new segments to an existing base. This can be achieved through the primary path() constructor overloads or the .to() method on a path instance.
The path() Constructor Overloads
The path() function supports extending a base path with a lambda expression. When a base path is provided as the first argument, the lambda's proxy starts at the type resolved by the base path.
The diagram above illustrates the logic used by the path() function to either start from root or extend an existing base.
Sources: src/path.ts:36-42, src/path.ts:57-67
Instance-based Extension with .to()
The .to() method allows for fluent extension of an existing path instance. It accepts a lambda expression that defines the additional segments relative to the current path's endpoint.
| Method | Argument Type | Description |
|---|---|---|
path(base, expr) | BasePath, PathExpression | Static constructor for extending a base path. |
path.to(expr) | PathExpression | Instance method to extend the current path. |
Sources: src/types.ts:167-172, src/impl/path-impl.ts:285-290
Intelligent Merging and Overlap Deduplication
The .merge() method is used to append another path to the current one. Unlike simple concatenation, .merge() performs "Smart deduplication" by identifying the longest suffix-prefix overlap between the two paths.
Overlap Logic
If the end of the base path matches the beginning of the merging path, those segments are merged into one, preventing redundant segments like users.0.users.0.name.
This logic ensures that if pathA ends with ["list"] and pathB starts with ["list", "items"], the result is ["pathA_prefix", "list", "items"].
Sources: src/impl/path-impl.ts:245-263, src/tests/algebra.spec.ts:23-28
Merging Capabilities
- Lambda Support:
.merge()can accept a lambda expression directly. - Runtime Indices: Correctly handles overlaps involving numeric indices (e.g.,
products.3merged withproducts.3.list). - Immutability: The operation always returns a new path instance without modifying the originals.
Sources: src/tests/algebra.spec.ts:17-21, src/tests/algebra.spec.ts:60-75, src/impl/path-impl.ts:264
Path Subtraction
The .subtract() method provides the inverse of merging. It allows for calculating a relative path by removing segments from either the beginning (prefix) or the end (suffix) of a path.
Subtraction Scenarios
- Prefix Removal: If
pathBis a prefix ofpathA,pathA.subtract(pathB)returns the remaining suffix. - Suffix Removal: If
pathBis a suffix ofpathA,pathA.subtract(pathB)returns the preceding prefix. - Identity: Subtracting a path from itself returns an empty path (length 0).
- Unrelated Paths: If no prefix or suffix relationship exists, the method returns
null.
Segment Slicing
The .slice() method provides granular control over path segments using semantics identical to Array.prototype.slice. This is useful for truncating paths to a specific depth or extracting specific internal segments.
- Positive Indices:
slice(0, 3)extracts the first three segments. - Negative Indices:
slice(-1)extracts only the last segment. - Immutability: Like all manipulation methods,
.slice()produces a new path instance.
Sources: src/impl/path-impl.ts:296-300, src/tests/algebra.spec.ts:133-139
Technical Summary of Operations
| Operation | Method | Input | Output | Immutability |
|---|---|---|---|---|
| Extension | .to(expr) | Lambda | Path | Yes |
| Merging | .merge(other) | Path or Lambda | Path (Deduplicated) | Yes |
| Subtraction | .subtract(other) | Path or Lambda | Path or null | Yes |
| Slicing | .slice(s, e) | number | Path | Yes |
Sources: src/impl/path-impl.ts:245-300, src/types.ts:139-173
Merging and extending paths in data-path provides a safe, immutable way to manage complex data structures. By using suffix-prefix overlap detection and maintaining type safety through lambdas, the library prevents common errors associated with manual string-based path manipulation.