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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/constants.ts","../src/utils.ts","../src/impl/base-path-impl.ts","../src/impl/path-impl.ts","../src/path.ts"],"sourcesContent":["export const PATH_SEGMENTS = Symbol(\"PATH_SEGMENTS\");\n\n/**\n * Sentinel for a single-level wildcard segment (`each`).\n *\n * Stored as a unique Symbol — NOT the string `\"*\"` — so that a legitimate\n * object key named `\"*\"` is preserved as a literal segment and never\n * reinterpreted as a wildcard by `.get`, `.expand`, `.covers`, `.match`, etc.\n *\n * Renders as `\"*\"` in `toString()` / `.$` for dot-notation compatibility.\n */\nexport const WILDCARD: unique symbol = Symbol(\"WILDCARD\");\n\n/**\n * Sentinel for a deep wildcard segment (`deep`).\n *\n * Same rationale as {@link WILDCARD}: stored as a unique Symbol so the\n * literal string `\"**\"` remains a valid (literal) object key.\n *\n * Renders as `\"**\"` in `toString()` / `.$`.\n */\nexport const DEEP_WILDCARD: unique symbol = Symbol(\"DEEP_WILDCARD\");\n","import { DEEP_WILDCARD, PATH_SEGMENTS, WILDCARD } from \"./constants.js\";\nimport type { ResolvablePath, Segment } from \"./types.js\";\n\n/**\n * Returns true only for strings that are the canonical representation of a\n * non-negative integer (e.g. \"0\", \"1\", \"123\"). Rejects \"01\", \"1e3\", \"-1\", etc.,\n * so that numeric-looking object keys are preserved as strings.\n */\nexport function isCanonicalArrayIndex(key: string): boolean {\n\tconst num = Number(key);\n\treturn (\n\t\tNumber.isInteger(num) && num >= 0 && num < 2 ** 32 && String(num) === key\n\t);\n}\n\nexport function resolveSegments(\n\ttarget: ResolvablePath<any>,\n): readonly Segment[] {\n\tif (typeof target === \"function\") {\n\t\tconst proxy = createPathProxy([]);\n\t\tconst result = target(proxy) as unknown;\n\t\treturn (\n\t\t\t((result as Record<symbol, unknown>)?.[PATH_SEGMENTS] as Segment[]) ?? []\n\t\t);\n\t}\n\tif (target != null && typeof target === \"object\" && \"segments\" in target) {\n\t\treturn (target as { segments: readonly Segment[] }).segments;\n\t}\n\treturn [];\n}\n\n// Returns `any` intentionally — the proxy is typed by the caller via PathExpression<T, V>\nexport function createPathProxy(segments: readonly Segment[]): any {\n\treturn new Proxy(\n\t\t{ [PATH_SEGMENTS]: segments },\n\t\t{\n\t\t\tget(target, key) {\n\t\t\t\tif (key === PATH_SEGMENTS)\n\t\t\t\t\treturn target[PATH_SEGMENTS as keyof typeof target];\n\t\t\t\t// Symbols (other than PATH_SEGMENTS) return undefined — not recordable segments\n\t\t\t\tif (typeof key === \"symbol\") return undefined;\n\t\t\t\t// Every string key becomes a new path segment\n\t\t\t\tconst next: Segment = isCanonicalArrayIndex(key) ? Number(key) : key;\n\t\t\t\treturn createPathProxy([...segments, next]);\n\t\t\t},\n\t\t},\n\t);\n}\n\nexport function segmentsEqual(\n\ta: readonly Segment[],\n\tb: readonly Segment[],\n): boolean {\n\tif (a.length !== b.length) return false;\n\treturn a.every((s, i) => s === b[i]);\n}\n\nexport function matchesPrefix(\n\tfull: readonly Segment[],\n\tprefix: readonly Segment[],\n): boolean {\n\t// Quick reject: only when prefix is too long even after every `**` collapses\n\t// to zero segments. (Each `**` can skip 0..N segments, so each one effectively\n\t// subtracts one from the minimum prefix length.)\n\tlet minPrefixLen = 0;\n\tfor (const s of prefix) if (s !== DEEP_WILDCARD) minPrefixLen++;\n\tif (minPrefixLen > full.length) return false;\n\n\tlet p = 0;\n\tlet f = 0;\n\twhile (p < prefix.length) {\n\t\tif (prefix[p] === DEEP_WILDCARD) {\n\t\t\tif (p === prefix.length - 1) return true;\n\t\t\tconst restPrefix = prefix.slice(p + 1);\n\t\t\tfor (let skip = 0; f + skip <= full.length; skip++) {\n\t\t\t\tif (matchesPrefix(full.slice(f + skip), restPrefix)) return true;\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\t\tif (f >= full.length) return false;\n\t\tif (prefix[p] !== WILDCARD && prefix[p] !== full[f]) return false;\n\t\tp++;\n\t\tf++;\n\t}\n\treturn p === prefix.length;\n}\n\n/**\n * Returns `true` iff `pattern` matches `concrete` exactly when wildcards\n * are expanded:\n * - `WILDCARD` (`*`) consumes exactly one segment.\n * - `DEEP_WILDCARD` (`**`) consumes zero or more segments.\n * - all other segments must be `===` to the corresponding concrete segment.\n *\n * Lengths need not match: a single `**` lets the pattern collapse to a\n * shorter concrete or stretch to a longer one. This is the \"covers\"\n * relation used by `.match()` and is broader than `matchesPrefix`, which\n * only requires the pattern to match a leading slice.\n */\nexport function patternMatches(\n\tpattern: readonly Segment[],\n\tconcrete: readonly Segment[],\n): boolean {\n\tfunction walk(pi: number, ci: number): boolean {\n\t\tif (pi === pattern.length) return ci === concrete.length;\n\t\tconst seg = pattern[pi];\n\t\tif (seg === DEEP_WILDCARD) {\n\t\t\tfor (let skip = 0; ci + skip <= concrete.length; skip++) {\n\t\t\t\tif (walk(pi + 1, ci + skip)) return true;\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\t\tif (ci === concrete.length) return false;\n\t\tif (seg === WILDCARD) return walk(pi + 1, ci + 1);\n\t\tif (seg !== concrete[ci]) return false;\n\t\treturn walk(pi + 1, ci + 1);\n\t}\n\treturn walk(0, 0);\n}\n\nfunction hasWildcardSegment(segments: readonly Segment[]): boolean {\n\tfor (const s of segments) {\n\t\tif (s === WILDCARD || s === DEEP_WILDCARD) return true;\n\t}\n\treturn false;\n}\n\n/**\n * Returns `true` iff `segments` contains a wildcard sentinel\n * (`WILDCARD` or `DEEP_WILDCARD`).\n */\nexport { hasWildcardSegment };\n","import { DEEP_WILDCARD, WILDCARD } from \"../constants.js\";\nimport type {\n\tMatchResult,\n\tPath,\n\tResolvablePath,\n\tSegment,\n\tTemplatePath,\n} from \"../types.js\";\nimport {\n\thasWildcardSegment,\n\tmatchesPrefix,\n\tpatternMatches,\n\tresolveSegments,\n\tsegmentsEqual,\n} from \"../utils.js\";\n\n/**\n * Shared structural base for PathImpl and TemplatePathImpl.\n * Contains all methods that do not depend on how a path reads, writes, or\n * creates new concrete path instances.\n */\nexport abstract class AbstractPathImpl<T = unknown, V = unknown> {\n\treadonly segments: readonly Segment[];\n\n\tconstructor(segments: readonly Segment[]) {\n\t\tthis.segments = segments;\n\t}\n\n\tget length(): number {\n\t\treturn this.segments.length;\n\t}\n\n\tget $(): string {\n\t\treturn this.toString();\n\t}\n\n\ttoString(): string {\n\t\treturn this.segments\n\t\t\t.map((s) =>\n\t\t\t\ts === WILDCARD ? \"*\" : s === DEEP_WILDCARD ? \"**\" : String(s),\n\t\t\t)\n\t\t\t.join(\".\");\n\t}\n\n\tstartsWith(other: ResolvablePath<T>): boolean {\n\t\treturn matchesPrefix(this.segments, resolveSegments(other));\n\t}\n\n\tcovers(other: ResolvablePath<T>): boolean {\n\t\treturn matchesPrefix(resolveSegments(other), this.segments);\n\t}\n\n\tequals(other: ResolvablePath<T>): boolean {\n\t\treturn segmentsEqual(this.segments, resolveSegments(other));\n\t}\n\n\tmatch(other: ResolvablePath<T>): MatchResult | null {\n\t\tconst otherSegs = resolveSegments(other);\n\t\tif (segmentsEqual(this.segments, otherSegs)) return { relation: \"equals\" };\n\n\t\t// Check wildcard coverage BEFORE literal prefix. patternMatches handles\n\t\t// `**` collapsing, so a deep template can fully cover a concrete path of\n\t\t// any length — that's a \"covers\", not \"parent\". Order matters: a literal\n\t\t// prefix check that's wildcard-aware (via matchesPrefix) would otherwise\n\t\t// misclassify \"a.**.b covers a.x.y.b\" as \"parent\".\n\t\tif (patternMatches(this.segments, otherSegs)) return { relation: \"covers\" };\n\t\tif (patternMatches(otherSegs, this.segments))\n\t\t\treturn { relation: \"covered-by\" };\n\n\t\t// Literal parent/child: the shorter side must be wildcard-free, otherwise\n\t\t// it's not a literal prefix.\n\t\tif (\n\t\t\t!hasWildcardSegment(otherSegs) &&\n\t\t\tmatchesPrefix(this.segments, otherSegs) &&\n\t\t\tthis.segments.length > otherSegs.length\n\t\t)\n\t\t\treturn { relation: \"child\" };\n\t\tif (\n\t\t\t!hasWildcardSegment(this.segments) &&\n\t\t\tmatchesPrefix(otherSegs, this.segments) &&\n\t\t\totherSegs.length > this.segments.length\n\t\t)\n\t\t\treturn { relation: \"parent\" };\n\t\treturn null;\n\t}\n\n\t// Abstract — implementations create PathImpl or TemplatePathImpl instances which live in path-impl.ts.\n\t// TemplatePathImpl widens these to also allow returning a TemplatePath when the resulting\n\t// segments still contain wildcards.\n\tabstract parent(): Path<T, unknown> | TemplatePath<T, unknown> | null;\n\tabstract subtract<U>(\n\t\tprefix: ResolvablePath<T, U>,\n\t): Path<U, V> | TemplatePath<U, V> | null;\n\tabstract slice(\n\t\tstart?: number,\n\t\tend?: number,\n\t): Path<T, unknown> | TemplatePath<T, unknown>;\n}\n\n// Re-export constants used by both PathImpl and TemplatePathImpl so callers\n// don't need an extra import just for the wildcard check.\nexport { DEEP_WILDCARD, WILDCARD };\n","import { PATH_SEGMENTS } from \"../constants.js\";\nimport type {\n\tBasePath,\n\tCollectionItem,\n\tPath,\n\tResolvablePath,\n\tSegment,\n\tTemplatePath,\n\tTraversablePathMethods,\n} from \"../types.js\";\nimport { createPathProxy, resolveSegments, segmentsEqual } from \"../utils.js\";\nimport { AbstractPathImpl, DEEP_WILDCARD, WILDCARD } from \"./base-path-impl.js\";\n\n// ---------------------------------------------------------------------------\n// PathImpl — concrete path with no wildcards\n// ---------------------------------------------------------------------------\n\nexport class PathImpl<T = unknown, V = unknown>\n\textends AbstractPathImpl<T, V>\n\timplements BasePath<T, V>, TraversablePathMethods<T, V>\n{\n\treadonly fn: (data: T) => V | undefined;\n\n\tconstructor(segments: readonly Segment[]) {\n\t\tsuper(segments);\n\t\tthis.fn = (data: T) => this.get(data);\n\t}\n\n\tget(data: T): V | undefined {\n\t\tlet current: unknown = data;\n\t\tfor (const seg of this.segments) {\n\t\t\tif (current == null) return undefined;\n\t\t\tcurrent = (current as Record<PropertyKey, unknown>)[seg];\n\t\t}\n\t\treturn current as V | undefined;\n\t}\n\n\tset(data: T, value: V): T {\n\t\tif (this.segments.length === 0) return value as unknown as T;\n\n\t\tconst setAt = (\n\t\t\tobj: unknown,\n\t\t\tsegs: readonly Segment[],\n\t\t\tval: unknown,\n\t\t): unknown => {\n\t\t\tif (segs.length === 1) {\n\t\t\t\tconst key = segs[0];\n\t\t\t\tif (Array.isArray(obj)) {\n\t\t\t\t\tconst arr = [...obj];\n\t\t\t\t\tarr[key as number] = val;\n\t\t\t\t\treturn arr;\n\t\t\t\t}\n\t\t\t\treturn { ...(obj as object), [key]: val };\n\t\t\t}\n\t\t\tconst [first, ...rest] = segs;\n\t\t\tconst baseObj = obj as Record<PropertyKey, unknown>;\n\t\t\tconst next = baseObj[first];\n\t\t\tconst nextCopy =\n\t\t\t\tnext != null && typeof next === \"object\"\n\t\t\t\t\t? Array.isArray(next)\n\t\t\t\t\t\t? [...next]\n\t\t\t\t\t\t: { ...next }\n\t\t\t\t\t: typeof rest[0] === \"number\"\n\t\t\t\t\t\t? []\n\t\t\t\t\t\t: {};\n\t\t\tif (Array.isArray(baseObj)) {\n\t\t\t\tconst arr = [...baseObj];\n\t\t\t\tarr[first as number] = setAt(nextCopy, rest, val) as never;\n\t\t\t\treturn arr;\n\t\t\t}\n\t\t\treturn { ...baseObj, [first]: setAt(nextCopy, rest, val) };\n\t\t};\n\n\t\tconst baseObj =\n\t\t\ttypeof data === \"object\" && data !== null\n\t\t\t\t? Array.isArray(data)\n\t\t\t\t\t? [...data]\n\t\t\t\t\t: { ...data }\n\t\t\t\t: data;\n\t\treturn setAt(baseObj, this.segments, value) as T;\n\t}\n\n\tupdate(data: T, updater: (current: V | undefined) => V): T {\n\t\treturn this.set(data, updater(this.get(data)));\n\t}\n\n\tparent(): Path<T, unknown> | null {\n\t\tif (this.segments.length === 0) return null;\n\t\treturn makeConcrete<T, unknown>(\n\t\t\tthis.segments.slice(0, -1),\n\t\t) as unknown as Path<T, unknown>;\n\t}\n\n\tsubtract<U>(prefix: ResolvablePath<T, U>): Path<U, V> | null {\n\t\tconst a = this.segments;\n\t\tconst b = resolveSegments(prefix);\n\t\tif (b.length > a.length) return null;\n\t\tif (!segmentsEqual(a.slice(0, b.length), b)) return null;\n\t\treturn makeConcrete<U, V>(a.slice(b.length)) as unknown as Path<U, V>;\n\t}\n\n\tslice(start?: number, end?: number): Path<T, unknown> {\n\t\treturn makeConcrete<T, unknown>(\n\t\t\tthis.segments.slice(start, end),\n\t\t) as unknown as Path<T, unknown>;\n\t}\n\n\teach<U = CollectionItem<V>>(\n\t\texpr?: (item: CollectionItem<V>) => U,\n\t): TemplatePath<T, U> {\n\t\tconst tail = expr ? evalExpr(expr as (p: unknown) => unknown) : [];\n\t\treturn new TemplatePathImpl<T, U>([\n\t\t\t...this.segments,\n\t\t\tWILDCARD,\n\t\t\t...tail,\n\t\t]) as unknown as TemplatePath<T, U>;\n\t}\n\n\tdeep<U = V>(expr?: (leaf: V) => U): TemplatePath<T, U> {\n\t\tconst tail = expr ? evalExpr(expr as (p: unknown) => unknown) : [];\n\t\treturn new TemplatePathImpl<T, U>([\n\t\t\t...this.segments,\n\t\t\tDEEP_WILDCARD,\n\t\t\t...tail,\n\t\t]) as unknown as TemplatePath<T, U>;\n\t}\n\n\tto<U>(relative: ResolvablePath<V, U>): Path<T, U> | TemplatePath<T, U> {\n\t\treturn makeFromSegments<T, U>([\n\t\t\t...this.segments,\n\t\t\t...resolveSegments(relative),\n\t\t]) as unknown as Path<T, U> | TemplatePath<T, U>;\n\t}\n\n\tmerge<U>(other: ResolvablePath<T, U>): Path<T, U> | TemplatePath<T, U> {\n\t\treturn makeFromSegments<T, U>(\n\t\t\tmergeSegments(this.segments, resolveSegments(other)),\n\t\t) as unknown as Path<T, U> | TemplatePath<T, U>;\n\t}\n}\n\n/**\n * Returns a concrete `PathImpl` when `segments` contains no wildcard\n * sentinels, otherwise a `TemplatePathImpl` so `.get()` correctly expands\n * matches.\n *\n * Safe by construction: wildcards are unique Symbols (see\n * {@link WILDCARD} / {@link DEEP_WILDCARD}). Legitimate object keys named\n * `\"*\"` or `\"**\"` are stored as strings and never trigger the template\n * branch.\n */\nfunction makeFromSegments<T, V>(\n\tsegments: readonly Segment[],\n): PathImpl<T, V> | TemplatePathImpl<T, V> {\n\treturn hasWildcard(segments)\n\t\t? new TemplatePathImpl<T, V>(segments)\n\t\t: new PathImpl<T, V>(segments);\n}\n\nfunction hasWildcard(segments: readonly Segment[]): boolean {\n\tfor (const s of segments) {\n\t\tif (s === WILDCARD || s === DEEP_WILDCARD) return true;\n\t}\n\treturn false;\n}\n\n// ---------------------------------------------------------------------------\n// TemplatePathImpl — path containing * or ** wildcards\n// ---------------------------------------------------------------------------\n\nexport class TemplatePathImpl<\n\tT = unknown,\n\tV = unknown,\n> extends AbstractPathImpl<T, V> {\n\t// fn returns V[] (not V|undefined) — no covariance conflict since we don't\n\t// extend PathImpl; the declared type here matches TemplatePath<T,V>.fn.\n\treadonly fn: (data: T) => V[];\n\n\tconstructor(segments: readonly Segment[]) {\n\t\tsuper(segments);\n\t\tthis.fn = (data: T) => this.get(data);\n\t}\n\n\tget(data: T): V[] {\n\t\treturn this.expand(data).map(\n\t\t\t// expand() only returns paths where the key exists in data, so get() is safe\n\t\t\t(p) => p.get(data) as V,\n\t\t);\n\t}\n\n\tset(data: T, value: V): T {\n\t\tconst paths = this.expand(data);\n\t\tlet current = data;\n\t\tfor (const p of paths) {\n\t\t\tcurrent = p.set(current, value);\n\t\t}\n\t\treturn current;\n\t}\n\n\t/**\n\t * Applies `updater` to each matched value individually (per-item transform).\n\t * Use `.set(data, constant)` to assign the same value to every match.\n\t */\n\tupdate(data: T, updater: (current: V | undefined) => V): T {\n\t\tconst paths = this.expand(data);\n\t\tlet current = data;\n\t\tfor (const p of paths) {\n\t\t\tcurrent = p.set(current, updater(p.get(current)));\n\t\t}\n\t\treturn current;\n\t}\n\n\tparent(): Path<T, unknown> | TemplatePath<T, unknown> | null {\n\t\tif (this.segments.length === 0) return null;\n\t\treturn makeFromSegments<T, unknown>(\n\t\t\tthis.segments.slice(0, -1),\n\t\t) as unknown as Path<T, unknown> | TemplatePath<T, unknown>;\n\t}\n\n\tsubtract<U>(\n\t\tprefix: ResolvablePath<T, U>,\n\t): Path<U, V> | TemplatePath<U, V> | null {\n\t\tconst a = this.segments;\n\t\tconst b = resolveSegments(prefix);\n\t\tif (b.length > a.length) return null;\n\t\tif (!segmentsEqual(a.slice(0, b.length), b)) return null;\n\t\treturn makeFromSegments<U, V>(a.slice(b.length)) as unknown as\n\t\t\t| Path<U, V>\n\t\t\t| TemplatePath<U, V>;\n\t}\n\n\tslice(\n\t\tstart?: number,\n\t\tend?: number,\n\t): Path<T, unknown> | TemplatePath<T, unknown> {\n\t\treturn makeFromSegments<T, unknown>(\n\t\t\tthis.segments.slice(start, end),\n\t\t) as unknown as Path<T, unknown> | TemplatePath<T, unknown>;\n\t}\n\n\teach<U = CollectionItem<V>>(\n\t\texpr?: (item: CollectionItem<V>) => U,\n\t): TemplatePath<T, U> {\n\t\tconst tail = expr ? evalExpr(expr as (p: unknown) => unknown) : [];\n\t\treturn new TemplatePathImpl<T, U>([\n\t\t\t...this.segments,\n\t\t\tWILDCARD,\n\t\t\t...tail,\n\t\t]) as unknown as TemplatePath<T, U>;\n\t}\n\n\tdeep<U = V>(expr?: (leaf: V) => U): TemplatePath<T, U> {\n\t\tconst tail = expr ? evalExpr(expr as (p: unknown) => unknown) : [];\n\t\treturn new TemplatePathImpl<T, U>([\n\t\t\t...this.segments,\n\t\t\tDEEP_WILDCARD,\n\t\t\t...tail,\n\t\t]) as unknown as TemplatePath<T, U>;\n\t}\n\n\tto<U>(relative: ResolvablePath<V, U>): TemplatePath<T, U> {\n\t\tconst tail = resolveSegments(relative);\n\t\treturn new TemplatePathImpl<T, U>([\n\t\t\t...this.segments,\n\t\t\t...tail,\n\t\t]) as unknown as TemplatePath<T, U>;\n\t}\n\n\tmerge<U>(other: ResolvablePath<T, U>): TemplatePath<T, U> {\n\t\treturn new TemplatePathImpl<T, U>(\n\t\t\tmergeSegments(this.segments, resolveSegments(other)),\n\t\t) as unknown as TemplatePath<T, U>;\n\t}\n\n\t/**\n\t * Resolves this template to all concrete paths that exist in `data`.\n\t */\n\texpand(data: T): Path<T, V>[] {\n\t\tconst results: Path<T, V>[] = [];\n\n\t\tconst walk = (current: unknown, idx: number, acc: Segment[]): void => {\n\t\t\tif (idx >= this.segments.length) {\n\t\t\t\tresults.push(new PathImpl<T, V>(acc));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst seg = this.segments[idx];\n\n\t\t\tif (seg === WILDCARD) {\n\t\t\t\tif (current != null && typeof current === \"object\") {\n\t\t\t\t\tconst keys = Array.isArray(current)\n\t\t\t\t\t\t? (Array.from(current.keys()) as number[])\n\t\t\t\t\t\t: Object.keys(current);\n\t\t\t\t\tfor (const key of keys) {\n\t\t\t\t\t\twalk((current as Record<PropertyKey, unknown>)[key], idx + 1, [\n\t\t\t\t\t\t\t...acc,\n\t\t\t\t\t\t\tkey,\n\t\t\t\t\t\t]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (seg === DEEP_WILDCARD) {\n\t\t\t\t// Try matching rest of pattern at current depth\n\t\t\t\twalk(current, idx + 1, acc);\n\t\t\t\t// Recurse into every child\n\t\t\t\tif (current != null && typeof current === \"object\") {\n\t\t\t\t\tconst keys = Array.isArray(current)\n\t\t\t\t\t\t? (Array.from(current.keys()) as number[])\n\t\t\t\t\t\t: Object.keys(current);\n\t\t\t\t\tfor (const key of keys) {\n\t\t\t\t\t\twalk((current as Record<PropertyKey, unknown>)[key], idx, [\n\t\t\t\t\t\t\t...acc,\n\t\t\t\t\t\t\tkey,\n\t\t\t\t\t\t]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (\n\t\t\t\t\tcurrent != null &&\n\t\t\t\t\ttypeof current === \"object\" &&\n\t\t\t\t\tseg in (current as object)\n\t\t\t\t) {\n\t\t\t\t\twalk((current as Record<PropertyKey, unknown>)[seg], idx + 1, [\n\t\t\t\t\t\t...acc,\n\t\t\t\t\t\tseg,\n\t\t\t\t\t]);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\twalk(data, 0, []);\n\t\treturn results;\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Private helpers\n// ---------------------------------------------------------------------------\n\nfunction makeConcrete<T, V>(segments: readonly Segment[]): PathImpl<T, V> {\n\treturn new PathImpl<T, V>(segments);\n}\n\nfunction evalExpr(expr: (proxy: unknown) => unknown): readonly Segment[] {\n\tconst proxy = createPathProxy([]);\n\tconst result = expr(proxy);\n\treturn (\n\t\t((result as Record<symbol, unknown>)?.[PATH_SEGMENTS] as Segment[]) ?? []\n\t);\n}\n\nfunction mergeSegments(\n\ta: readonly Segment[],\n\tb: readonly Segment[],\n): readonly Segment[] {\n\tlet overlapLen = 0;\n\tfor (let len = Math.min(a.length, b.length); len >= 1; len--) {\n\t\tif (segmentsEqual(a.slice(-len), b.slice(0, len))) {\n\t\t\toverlapLen = len;\n\t\t\tbreak;\n\t\t}\n\t}\n\treturn overlapLen > 0 ? [...a.slice(0, -overlapLen), ...b] : [...a, ...b];\n}\n","import { PATH_SEGMENTS } from \"./constants.js\";\nimport { PathImpl } from \"./impl/path-impl.js\";\nimport type { BasePath, Path, PathExpression, Segment } from \"./types.js\";\nimport { createPathProxy, isCanonicalArrayIndex } from \"./utils.js\";\n\n/**\n * Create a typed path from a lambda expression, from an existing base path, or as a root.\n *\n * @example\n * // Lambda — recommended: annotate the parameter so both T and V are inferred\n * const p = path((user: User) => user.profile.firstName);\n *\n * @example\n * // Both generics explicit\n * const p = path<User, string>((u) => u.profile.firstName);\n *\n * @example\n * // Root path (no segments) — typically extended via .to() or path(root, expr)\n * const root = path<User>();\n *\n * @example\n * // Extend an existing base path\n * const p2 = path(root, (u) => u.profile);\n */\nexport function path<T>(): Path<T, T>;\nexport function path<T, V = unknown>(expr: PathExpression<T, V>): Path<T, V>;\nexport function path<T, U, V = unknown>(\n\tbase: BasePath<T, U>,\n\texpr: PathExpression<U, V>,\n): Path<T, V>;\nexport function path<T, V = unknown>(\n\tbaseOrExpr?: BasePath<T, unknown> | PathExpression<T, V>,\n\texpr?: PathExpression<unknown, V>,\n): Path<T, V> {\n\tif (baseOrExpr === undefined) {\n\t\treturn new PathImpl<T, V>([]);\n\t}\n\n\tif (typeof baseOrExpr === \"function\") {\n\t\tconst proxy = createPathProxy([]);\n\t\tconst result = (baseOrExpr as PathExpression<T, V>)(proxy);\n\t\tconst segments: Segment[] =\n\t\t\t((result as Record<symbol, unknown>)?.[PATH_SEGMENTS] as Segment[]) ?? [];\n\t\treturn new PathImpl<T, V>(segments);\n\t}\n\n\tconst baseSegments = (baseOrExpr as BasePath<T, unknown>).segments;\n\tif (expr !== undefined) {\n\t\tconst proxy = createPathProxy([]);\n\t\tconst result = (expr as PathExpression<unknown, V>)(proxy);\n\t\tconst tailSegments =\n\t\t\t((result as Record<symbol, unknown>)?.[PATH_SEGMENTS] as Segment[]) ?? [];\n\t\treturn new PathImpl<T, V>([...baseSegments, ...tailSegments]);\n\t}\n\n\treturn new PathImpl<T, V>(baseSegments);\n}\n\n/**\n * Create a path from a raw dot-separated string (e.g. `\"users.0.name\"`).\n *\n * Useful for dynamic paths from external sources (API responses, Zod issue paths, etc.).\n * Segments that are canonical non-negative integers are stored as numbers; all others as strings.\n *\n * The optional second generic `V` declares the expected leaf type without a cast:\n * ```ts\n * unsafePath<User, string>(\"profile.firstName\").get(user) // string | undefined\n * ```\n *\n * @param raw Dot-separated string. Empty string returns a zero-segment root path.\n */\nexport function unsafePath<T, V = unknown>(raw: string): Path<T, V> {\n\tconst segments: Segment[] = raw\n\t\t? raw\n\t\t\t\t.split(\".\")\n\t\t\t\t.map((s) => (s === \"\" ? s : isCanonicalArrayIndex(s) ? Number(s) : s))\n\t\t: [];\n\treturn new PathImpl<T, V>(segments);\n}\n"],"mappings":"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","names":["baseObj"]}
|
package/package.json
CHANGED
|
@@ -1,70 +1,111 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
2
|
+
"name": "data-path",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "Type-safe object property paths in TypeScript — build, compare, and manipulate with lambda expressions. Zero dependencies.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.cjs",
|
|
8
|
+
"module": "./dist/index.js",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": {
|
|
14
|
+
"types": "./dist/index.d.cts",
|
|
15
|
+
"default": "./dist/index.cjs"
|
|
16
|
+
},
|
|
17
|
+
"default": "./dist/index.js"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"sideEffects": false,
|
|
21
|
+
"files": [
|
|
22
|
+
"dist"
|
|
23
|
+
],
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "tsup src/index.ts --format cjs,esm --dts --clean --sourcemap",
|
|
26
|
+
"dev": "npm run build -- --watch",
|
|
27
|
+
"lint": "biome check src",
|
|
28
|
+
"lint:fix": "biome check --write src",
|
|
29
|
+
"prepare": "husky",
|
|
30
|
+
"typecheck": "tsc --noEmit",
|
|
31
|
+
"test": "vitest run --typecheck",
|
|
32
|
+
"test:watch": "vitest --typecheck"
|
|
33
|
+
},
|
|
34
|
+
"keywords": [
|
|
35
|
+
"typescript",
|
|
36
|
+
"path",
|
|
37
|
+
"object-path",
|
|
38
|
+
"property-path",
|
|
39
|
+
"type-safe",
|
|
40
|
+
"proxy",
|
|
41
|
+
"lambda",
|
|
42
|
+
"dot-notation",
|
|
43
|
+
"accessor",
|
|
44
|
+
"immutable",
|
|
45
|
+
"path-algebra",
|
|
46
|
+
"state-management",
|
|
47
|
+
"form"
|
|
48
|
+
],
|
|
49
|
+
"author": {
|
|
50
|
+
"name": "Sergei Shmakov",
|
|
51
|
+
"url": "https://github.com/sergeyshmakov"
|
|
52
|
+
},
|
|
53
|
+
"repository": {
|
|
54
|
+
"type": "git",
|
|
55
|
+
"url": "git+https://github.com/sergeyshmakov/data-path.git"
|
|
56
|
+
},
|
|
57
|
+
"bugs": {
|
|
58
|
+
"url": "https://github.com/sergeyshmakov/data-path/issues"
|
|
59
|
+
},
|
|
60
|
+
"homepage": "https://sergeyshmakov.github.io/data-path/",
|
|
61
|
+
"release": {
|
|
62
|
+
"branches": [
|
|
63
|
+
"main"
|
|
64
|
+
],
|
|
65
|
+
"plugins": [
|
|
66
|
+
"@semantic-release/commit-analyzer",
|
|
67
|
+
"@semantic-release/release-notes-generator",
|
|
68
|
+
[
|
|
69
|
+
"@semantic-release/changelog",
|
|
70
|
+
{
|
|
71
|
+
"changelogFile": "CHANGELOG.md"
|
|
72
|
+
}
|
|
73
|
+
],
|
|
74
|
+
"@semantic-release/npm",
|
|
75
|
+
[
|
|
76
|
+
"@semantic-release/git",
|
|
77
|
+
{
|
|
78
|
+
"assets": [
|
|
79
|
+
"package.json",
|
|
80
|
+
"package-lock.json",
|
|
81
|
+
"CHANGELOG.md"
|
|
82
|
+
],
|
|
83
|
+
"message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
|
|
84
|
+
}
|
|
85
|
+
],
|
|
86
|
+
"@semantic-release/github"
|
|
87
|
+
]
|
|
88
|
+
},
|
|
89
|
+
"devDependencies": {
|
|
90
|
+
"@biomejs/biome": "2.4.6",
|
|
91
|
+
"@commitlint/cli": "^20.4.3",
|
|
92
|
+
"@commitlint/config-conventional": "^20.4.3",
|
|
93
|
+
"@semantic-release/changelog": "^6.0.3",
|
|
94
|
+
"@semantic-release/git": "^10.0.1",
|
|
95
|
+
"husky": "^9.1.7",
|
|
96
|
+
"lint-staged": "^16.4.0",
|
|
97
|
+
"semantic-release": "^25.0.3",
|
|
98
|
+
"tsup": "^8.5.1",
|
|
99
|
+
"typescript": "^5.9.3",
|
|
100
|
+
"vitest": "^4.0.18"
|
|
101
|
+
},
|
|
102
|
+
"peerDependencies": {
|
|
103
|
+
"typescript": ">=5.0.0"
|
|
104
|
+
},
|
|
105
|
+
"engines": {
|
|
106
|
+
"node": ">=20"
|
|
107
|
+
},
|
|
108
|
+
"volta": {
|
|
109
|
+
"node": "24.14.0"
|
|
110
|
+
}
|
|
70
111
|
}
|
package/dist/index.d.mts
DELETED
|
@@ -1,319 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Core type definitions for data-path.
|
|
3
|
-
* @see spec/idea.md
|
|
4
|
-
*/
|
|
5
|
-
/** A path segment: string key or numeric index */
|
|
6
|
-
type Segment = string | number;
|
|
7
|
-
/** Relation returned by .match() */
|
|
8
|
-
type MatchRelation = "includes" | "included-by" | "equals" | "parent" | "child" | null;
|
|
9
|
-
/** Result of .match() — bidirectional relationship + optional params */
|
|
10
|
-
interface MatchResult {
|
|
11
|
-
relation: MatchRelation;
|
|
12
|
-
params?: Record<string, string>;
|
|
13
|
-
}
|
|
14
|
-
/** Resolved type at the end of a path (leaf value type) */
|
|
15
|
-
type ResolvedType<_T, _P extends string> = unknown;
|
|
16
|
-
/** Deep-reachable types for .deep() leaf parameter (enables IDE autocomplete) */
|
|
17
|
-
type DeepReachable<T> = T;
|
|
18
|
-
/**
|
|
19
|
-
* Extracts the item type from a collection (Array or Record) so that traversal methods
|
|
20
|
-
* (like `.each()`) know what type of item they are iterating over.
|
|
21
|
-
*
|
|
22
|
-
* @template V The collection type (e.g., `string[]` or `Record<string, number>`)
|
|
23
|
-
*/
|
|
24
|
-
type CollectionItem<V> = V extends ReadonlyArray<infer U> ? U : V extends Record<PropertyKey, infer U> ? U : unknown;
|
|
25
|
-
/** Primitives that cannot have traversal methods called on them */
|
|
26
|
-
type Primitive = string | number | boolean | symbol | bigint | null | undefined;
|
|
27
|
-
/** Expression type for path construction — receives proxy, returns any (path is inferred from access) */
|
|
28
|
-
type PathExpression<T, R = unknown> = (proxy: T) => R;
|
|
29
|
-
/**
|
|
30
|
-
* Represents the various forms a path can take when provided as an input argument.
|
|
31
|
-
* This enables API flexibility, allowing methods (like `merge`, `match`, `startsWith`)
|
|
32
|
-
* to accept an existing path object, a raw segments object, or a lambda expression.
|
|
33
|
-
*
|
|
34
|
-
* @template T The root data type.
|
|
35
|
-
* @template V The resolved value type at the end of the path.
|
|
36
|
-
*/
|
|
37
|
-
type ResolvablePath<T, V = unknown> = BasePath<T, V, string> | {
|
|
38
|
-
segments: readonly Segment[];
|
|
39
|
-
} | PathExpression<T, V>;
|
|
40
|
-
/**
|
|
41
|
-
* Extracted methods for traversing into collections or deep structures.
|
|
42
|
-
* This is separated from `BasePath` so that these methods can be conditionally
|
|
43
|
-
* excluded from the type system when a path points to a primitive value
|
|
44
|
-
* (since primitives cannot be traversed).
|
|
45
|
-
*/
|
|
46
|
-
interface TraversablePathMethods<T, V> {
|
|
47
|
-
/**
|
|
48
|
-
* Traverses into a collection (Array or Record) to operate on each item.
|
|
49
|
-
*
|
|
50
|
-
* @example
|
|
51
|
-
* const users = path<Root>().users;
|
|
52
|
-
* const userNames = users.each(u => u.name); // Path matches all names
|
|
53
|
-
*/
|
|
54
|
-
each<U = CollectionItem<V>>(expr?: (item: CollectionItem<V>) => U): TemplatePath<T, U, string>;
|
|
55
|
-
/**
|
|
56
|
-
* Traverses deeply into a structure, matching any nested property.
|
|
57
|
-
*
|
|
58
|
-
* @example
|
|
59
|
-
* const root = path<Root>();
|
|
60
|
-
* const allIds = root.deep(node => node.id); // Path matches any 'id' at any depth
|
|
61
|
-
*/
|
|
62
|
-
deep<U = DeepReachable<V>>(expr?: (leaf: DeepReachable<V>) => U): TemplatePath<T, U, string>;
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* The foundational structure for all path objects (both standard and template paths).
|
|
66
|
-
* Contains common properties and operations including value extraction/mutation,
|
|
67
|
-
* relational algebra (comparisons), and structural manipulation.
|
|
68
|
-
*
|
|
69
|
-
* @template T Root data type the path operates on.
|
|
70
|
-
* @template V The expected value type that the path resolves to.
|
|
71
|
-
* @template _P The string representation of the path (optional/unused in runtime, but useful for type-level strings).
|
|
72
|
-
*/
|
|
73
|
-
interface BasePath<T = unknown, V = unknown, _P extends string = string> {
|
|
74
|
-
/**
|
|
75
|
-
* The array of segments (string keys or numeric indices) that make up this path.
|
|
76
|
-
*/
|
|
77
|
-
readonly segments: readonly Segment[];
|
|
78
|
-
/**
|
|
79
|
-
* The number of segments in this path.
|
|
80
|
-
*/
|
|
81
|
-
readonly length: number;
|
|
82
|
-
/**
|
|
83
|
-
* The string representation of the path (e.g. "users.0.name").
|
|
84
|
-
* Useful for binding paths to form libraries or UI components.
|
|
85
|
-
*
|
|
86
|
-
* @example
|
|
87
|
-
* path<Root>().users[0].name.$; // "users.0.name"
|
|
88
|
-
*/
|
|
89
|
-
readonly $: _P;
|
|
90
|
-
/**
|
|
91
|
-
* Returns the string representation of the path (e.g. "users.0.name").
|
|
92
|
-
*
|
|
93
|
-
* @example
|
|
94
|
-
* path<Root>().users[0].name.toString(); // "users.0.name"
|
|
95
|
-
*/
|
|
96
|
-
toString(): string;
|
|
97
|
-
/**
|
|
98
|
-
* Extracts the value at this path from the given data object.
|
|
99
|
-
* Safely handles missing intermediate properties by returning `undefined` instead of throwing an error.
|
|
100
|
-
*
|
|
101
|
-
* @example
|
|
102
|
-
* const namePath = path<User>().name;
|
|
103
|
-
* const name = namePath.get({ name: "Alice" }); // "Alice"
|
|
104
|
-
*/
|
|
105
|
-
get(data: T): V;
|
|
106
|
-
/**
|
|
107
|
-
* Returns an accessor function that extracts the value at this path from the given data object.
|
|
108
|
-
* Useful for array methods like `.map()` or `.filter()`.
|
|
109
|
-
*
|
|
110
|
-
* @example
|
|
111
|
-
* const names = users.map(path<User>().name.fn);
|
|
112
|
-
*/
|
|
113
|
-
readonly fn: (data: T) => V;
|
|
114
|
-
/**
|
|
115
|
-
* Sets the value at this path in the given data object, returning a new updated object (immutable).
|
|
116
|
-
* If intermediate properties are missing, they are automatically created as objects or arrays
|
|
117
|
-
* depending on the segment types (numeric keys become arrays).
|
|
118
|
-
*
|
|
119
|
-
* @example
|
|
120
|
-
* const namePath = path<User>().name;
|
|
121
|
-
* const updatedUser = namePath.set({ name: "Alice" }, "Bob"); // { name: "Bob" }
|
|
122
|
-
*/
|
|
123
|
-
set(data: T, value: V): T;
|
|
124
|
-
/**
|
|
125
|
-
* Checks if this path starts with the segments of another path.
|
|
126
|
-
*
|
|
127
|
-
* @example
|
|
128
|
-
* const a = path<Root>().users[0].name;
|
|
129
|
-
* const b = path<Root>().users;
|
|
130
|
-
* a.startsWith(b); // true
|
|
131
|
-
*/
|
|
132
|
-
startsWith(other: ResolvablePath<T>): boolean;
|
|
133
|
-
/**
|
|
134
|
-
* Checks if this path encompasses the segments of another path (i.e., this path is a prefix of the other).
|
|
135
|
-
*
|
|
136
|
-
* @example
|
|
137
|
-
* const a = path<Root>().users;
|
|
138
|
-
* const b = path<Root>().users[0].name;
|
|
139
|
-
* a.includes(b); // true
|
|
140
|
-
*/
|
|
141
|
-
includes(other: ResolvablePath<T>): boolean;
|
|
142
|
-
/**
|
|
143
|
-
* Checks if this path is exactly equal to another path.
|
|
144
|
-
*
|
|
145
|
-
* @example
|
|
146
|
-
* const a = path<Root>().users;
|
|
147
|
-
* const b = path<Root>().users;
|
|
148
|
-
* a.equals(b); // true
|
|
149
|
-
*/
|
|
150
|
-
equals(other: ResolvablePath<T>): boolean;
|
|
151
|
-
/**
|
|
152
|
-
* Matches this path against another path, returning their relationship.
|
|
153
|
-
*
|
|
154
|
-
* @example
|
|
155
|
-
* const a = path<Root>().users[0];
|
|
156
|
-
* const b = path<Root>().users;
|
|
157
|
-
* a.match(b); // { relation: 'child', params: {} }
|
|
158
|
-
*/
|
|
159
|
-
match(other: ResolvablePath<T>): MatchResult | null;
|
|
160
|
-
/**
|
|
161
|
-
* Appends another path to the end of this path. If the end of this path matches
|
|
162
|
-
* the beginning of the other path, the overlapping segments are intelligently deduplicated.
|
|
163
|
-
*
|
|
164
|
-
* @example
|
|
165
|
-
* const base = path<Root>().users;
|
|
166
|
-
* const full = base.merge(p => p[0].name); // equivalent to path<Root>().users[0].name
|
|
167
|
-
*/
|
|
168
|
-
merge<U>(other: ResolvablePath<T, U>): Path<T, U, string>;
|
|
169
|
-
/**
|
|
170
|
-
* Removes the segments of another path from either the beginning or the end of this path.
|
|
171
|
-
* Returns `null` if the other path is neither a prefix nor a suffix.
|
|
172
|
-
*
|
|
173
|
-
* @example
|
|
174
|
-
* const full = path<Root>().users[0].name;
|
|
175
|
-
* const base = path<Root>().users;
|
|
176
|
-
* const remainder = full.subtract(base); // equivalent to path()[0].name
|
|
177
|
-
*/
|
|
178
|
-
subtract(other: ResolvablePath<T>): Path<T, V, string> | null;
|
|
179
|
-
/**
|
|
180
|
-
* Returns a new path containing a subset of the segments, similar to Array.prototype.slice.
|
|
181
|
-
*
|
|
182
|
-
* @example
|
|
183
|
-
* const full = path<Root>().users[0].name;
|
|
184
|
-
* full.slice(0, 1); // equivalent to path<Root>().users
|
|
185
|
-
*/
|
|
186
|
-
slice(start?: number, end?: number): Path<T, unknown, string>;
|
|
187
|
-
/**
|
|
188
|
-
* Extends the current path using a lambda expression starting from the resolved value.
|
|
189
|
-
*
|
|
190
|
-
* @example
|
|
191
|
-
* const userPath = path<Root>().users[0];
|
|
192
|
-
* const namePath = userPath.to(u => u.name);
|
|
193
|
-
*/
|
|
194
|
-
to<U>(expr: PathExpression<V, U>): Path<T, U, string>;
|
|
195
|
-
}
|
|
196
|
-
/**
|
|
197
|
-
* Represents a strongly-typed object property path.
|
|
198
|
-
*
|
|
199
|
-
* This type uses intersection (`&`) to combine the base operations (`BasePath`)
|
|
200
|
-
* with conditional traversal methods (`TraversablePathMethods`). The conditional
|
|
201
|
-
* check `[V] extends [Primitive]` ensures that IDEs will not suggest `.each()` or
|
|
202
|
-
* `.deep()` when the path has resolved to a primitive value (like a string or number).
|
|
203
|
-
*
|
|
204
|
-
* @template T Root data type
|
|
205
|
-
* @template V Resolved value type at path end
|
|
206
|
-
* @template P Path string (e.g. "a.b.c") — literal when inferrable, string when dynamic
|
|
207
|
-
*/
|
|
208
|
-
type Path<T = unknown, V = unknown, P extends string = string> = BasePath<T, V, P> & ([V] extends [Primitive] ? {} : TraversablePathMethods<T, V>);
|
|
209
|
-
/**
|
|
210
|
-
* Represents a path containing wildcards (`*` or `**`), useful for operations on multiple items.
|
|
211
|
-
*
|
|
212
|
-
* It extends the standard `Path` concept but alters the return types of `.each()` and `.deep()`
|
|
213
|
-
* to return another `TemplatePath` (chaining templates). It also adds the `.expand()` method
|
|
214
|
-
* which can resolve this template against actual data to return an array of concrete `Path`s.
|
|
215
|
-
*
|
|
216
|
-
* **Data Access:** Calling `.get()` on a `TemplatePath` will return an array of all matched values.
|
|
217
|
-
* Calling `.set()` will immutably update all matched paths in the object and return the updated object.
|
|
218
|
-
*
|
|
219
|
-
* @template T Root data type
|
|
220
|
-
* @template V Resolved value type at path end
|
|
221
|
-
* @template P Path string (e.g. "a.*.c")
|
|
222
|
-
*/
|
|
223
|
-
type TemplatePath<T = unknown, V = unknown, P extends string = string> = (Omit<BasePath<T, V, P>, "get" | "fn"> & {
|
|
224
|
-
/**
|
|
225
|
-
* Extracts an array of values at this template path from the given data object.
|
|
226
|
-
*
|
|
227
|
-
* @example
|
|
228
|
-
* const names = path<Root>().users.each().name.get(data); // string[]
|
|
229
|
-
*/
|
|
230
|
-
get(data: T): V[];
|
|
231
|
-
/**
|
|
232
|
-
* Returns an accessor function that extracts an array of values at this template path from the given data object.
|
|
233
|
-
* Useful for array methods like `.map()` or `.filter()`.
|
|
234
|
-
*
|
|
235
|
-
* @example
|
|
236
|
-
* const allNames = companies.map(path<Company>().departments.each().name.fn);
|
|
237
|
-
*/
|
|
238
|
-
readonly fn: (data: T) => V[];
|
|
239
|
-
}) & ([V] extends [Primitive] ? {} : {
|
|
240
|
-
/**
|
|
241
|
-
* Traverses into a collection (Array or Record) to operate on each item, returning a TemplatePath.
|
|
242
|
-
*
|
|
243
|
-
* @example
|
|
244
|
-
* const users = path<Root>().users;
|
|
245
|
-
* const userNames = users.each(u => u.name); // TemplatePath matching all names
|
|
246
|
-
*/
|
|
247
|
-
each<U = CollectionItem<V>>(expr?: (item: CollectionItem<V>) => U): TemplatePath<T, U, `${string}.${"*"}.${string}`>;
|
|
248
|
-
/**
|
|
249
|
-
* Traverses deeply into a structure, matching any nested property, returning a TemplatePath.
|
|
250
|
-
*
|
|
251
|
-
* @example
|
|
252
|
-
* const root = path<Root>();
|
|
253
|
-
* const allIds = root.deep(node => node.id); // TemplatePath matching any 'id' at any depth
|
|
254
|
-
*/
|
|
255
|
-
deep<U = DeepReachable<V>>(expr?: (leaf: DeepReachable<V>) => U): TemplatePath<T, U, `${string}.${"**"}.${string}`>;
|
|
256
|
-
}) & {
|
|
257
|
-
/**
|
|
258
|
-
* Resolves this template path against actual data to return an array of concrete paths
|
|
259
|
-
* that exist in the given data.
|
|
260
|
-
*
|
|
261
|
-
* Note: Currently, `expand` only supports evaluating a single wildcard (`*` or `**`) per path.
|
|
262
|
-
*
|
|
263
|
-
* @example
|
|
264
|
-
* const template = path<Root>().users.each().name;
|
|
265
|
-
* const concretePaths = template.expand(data); // [path<Root>().users[0].name, ...]
|
|
266
|
-
*/
|
|
267
|
-
expand(data: T): Path<T, V, string>[];
|
|
268
|
-
};
|
|
269
|
-
/**
|
|
270
|
-
* Constructor overloads for creating paths.
|
|
271
|
-
*
|
|
272
|
-
* This allows the `path()` function to be called in several ways:
|
|
273
|
-
* 1. Without arguments: returns a root path `path<T>()`.
|
|
274
|
-
* 2. With a lambda: returns a path built from the expression `path<T>((p) => p.a.b)`.
|
|
275
|
-
* 3. With a base path and a lambda: allows extending an existing path `path(base, (p) => p.c)`.
|
|
276
|
-
*/
|
|
277
|
-
type PathConstructor = {
|
|
278
|
-
<T>(): Path<T, T, "">;
|
|
279
|
-
<T, V = unknown>(expr: PathExpression<T, V>): Path<T, V, string>;
|
|
280
|
-
<T, U, V = unknown>(base: BasePath<T, U, string>, expr: PathExpression<U, V>): Path<T, V, string>;
|
|
281
|
-
};
|
|
282
|
-
/** Unsafe path from string — no type checking on segments */
|
|
283
|
-
type UnsafePathConstructor = <T>(raw: string) => Path<T, unknown, string>;
|
|
284
|
-
|
|
285
|
-
/**
|
|
286
|
-
* Create a typed path from a lambda expression or extend an existing base path.
|
|
287
|
-
*
|
|
288
|
-
* This function serves as the primary entry point for constructing paths. By utilizing
|
|
289
|
-
* a Proxy-based builder (the lambda expression), it captures property accesses and
|
|
290
|
-
* records them as path segments without needing to evaluate actual data.
|
|
291
|
-
*
|
|
292
|
-
* @example
|
|
293
|
-
* // Create a root path
|
|
294
|
-
* const root = path<User>();
|
|
295
|
-
*
|
|
296
|
-
* @example
|
|
297
|
-
* // Create a path via lambda
|
|
298
|
-
* const p = path<User>((u) => u.address.city);
|
|
299
|
-
*
|
|
300
|
-
* @example
|
|
301
|
-
* // Extend an existing path
|
|
302
|
-
* const p2 = path(root, (u) => u.profile);
|
|
303
|
-
*/
|
|
304
|
-
declare function path<T>(): Path<T, T, "">;
|
|
305
|
-
declare function path<T, V = unknown>(expr: PathExpression<T, V>): Path<T, V, string>;
|
|
306
|
-
declare function path<T, U, V = unknown>(base: BasePath<T, U, string>, expr: PathExpression<U, V>): Path<T, V, string>;
|
|
307
|
-
/**
|
|
308
|
-
* Create a path from a raw string (e.g., "users.0.name").
|
|
309
|
-
*
|
|
310
|
-
* This is useful when paths are dynamic (like from a database or API response).
|
|
311
|
-
* Type checking on individual segments is bypassed, and segments are automatically
|
|
312
|
-
* parsed into numeric indices where appropriate.
|
|
313
|
-
*
|
|
314
|
-
* @param raw The dot-separated path string.
|
|
315
|
-
* @returns A Path object representing the given string.
|
|
316
|
-
*/
|
|
317
|
-
declare function unsafePath<T>(raw: string): Path<T, unknown, string>;
|
|
318
|
-
|
|
319
|
-
export { type DeepReachable, type MatchRelation, type MatchResult, type Path, type PathConstructor, type PathExpression, type ResolvedType, type Segment, type TemplatePath, type UnsafePathConstructor, path, unsafePath };
|