Skip to content

Commit c714b0f

Browse files
committed
chore: formatting and linting fixes
1 parent 32f2f1e commit c714b0f

12 files changed

Lines changed: 943 additions & 794 deletions

src/impl/path-impl.ts

Lines changed: 324 additions & 298 deletions
Large diffs are not rendered by default.

src/impl/template-path-impl.ts

Lines changed: 164 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -1,144 +1,176 @@
1-
import type { Segment, TemplatePath, Path, CollectionItem, DeepReachable } from "../types.js";
2-
import { WILDCARD, DEEP_WILDCARD, PATH_SEGMENTS } from "../constants.js";
1+
import { DEEP_WILDCARD, PATH_SEGMENTS, WILDCARD } from "../constants.js";
2+
import type {
3+
CollectionItem,
4+
DeepReachable,
5+
Path,
6+
Segment,
7+
TemplatePath,
8+
} from "../types.js";
39
import { createPathProxy } from "../utils.js";
410
import { PathImpl } from "./path-impl.js";
511

6-
export class TemplatePathImpl<T = unknown, V = unknown, P extends string = string>
7-
extends PathImpl<T, V, P>
8-
{
9-
/**
10-
* Traverses into a collection (Array or Record) to operate on each item, returning a TemplatePath.
11-
*
12-
* @example
13-
* const users = path<Root>().users;
14-
* const userNames = users.each(u => u.name); // TemplatePath matching all names
15-
*/
16-
each<U = CollectionItem<V>>(
17-
expr?: (item: CollectionItem<V>) => U,
18-
): TemplatePath<T, U, `${string}.${"*"}.${string}`> {
19-
let tailSegments: readonly Segment[] = [];
20-
if (expr) {
21-
const proxy = createPathProxy([]);
22-
const result = expr(proxy as CollectionItem<V>);
23-
tailSegments = (result as Record<symbol, unknown>)?.[PATH_SEGMENTS] as Segment[] ?? [];
24-
}
25-
return new TemplatePathImpl([
26-
...this.segments,
27-
WILDCARD,
28-
...tailSegments,
29-
]) as unknown as TemplatePath<T, U, `${string}.${"*"}.${string}`>;
30-
}
12+
export class TemplatePathImpl<
13+
T = unknown,
14+
V = unknown,
15+
P extends string = string,
16+
> extends PathImpl<T, V, P> {
17+
/**
18+
* Traverses into a collection (Array or Record) to operate on each item, returning a TemplatePath.
19+
*
20+
* @example
21+
* const users = path<Root>().users;
22+
* const userNames = users.each(u => u.name); // TemplatePath matching all names
23+
*/
24+
each<U = CollectionItem<V>>(
25+
expr?: (item: CollectionItem<V>) => U,
26+
): TemplatePath<T, U, `${string}.${"*"}.${string}`> {
27+
let tailSegments: readonly Segment[] = [];
28+
if (expr) {
29+
const proxy = createPathProxy([]);
30+
const result = expr(proxy as CollectionItem<V>);
31+
tailSegments =
32+
((result as Record<symbol, unknown>)?.[PATH_SEGMENTS] as Segment[]) ??
33+
[];
34+
}
35+
return new TemplatePathImpl([
36+
...this.segments,
37+
WILDCARD,
38+
...tailSegments,
39+
]) as unknown as TemplatePath<T, U, `${string}.${"*"}.${string}`>;
40+
}
3141

32-
/**
33-
* Traverses deeply into a structure, matching any nested property, returning a TemplatePath.
34-
*
35-
* @example
36-
* const root = path<Root>();
37-
* const allIds = root.deep(node => node.id); // TemplatePath matching any 'id' at any depth
38-
*/
39-
deep<U = DeepReachable<V>>(
40-
expr?: (leaf: DeepReachable<V>) => U,
41-
): TemplatePath<T, U, `${string}.${"**"}.${string}`> {
42-
let tailSegments: readonly Segment[] = [];
43-
if (expr) {
44-
const proxy = createPathProxy([]);
45-
const result = expr(proxy as DeepReachable<V>);
46-
tailSegments = (result as Record<symbol, unknown>)?.[PATH_SEGMENTS] as Segment[] ?? [];
47-
}
48-
return new TemplatePathImpl([
49-
...this.segments,
50-
DEEP_WILDCARD,
51-
...tailSegments,
52-
]) as unknown as TemplatePath<T, U, `${string}.${"**"}.${string}`>;
53-
}
42+
/**
43+
* Traverses deeply into a structure, matching any nested property, returning a TemplatePath.
44+
*
45+
* @example
46+
* const root = path<Root>();
47+
* const allIds = root.deep(node => node.id); // TemplatePath matching any 'id' at any depth
48+
*/
49+
deep<U = DeepReachable<V>>(
50+
expr?: (leaf: DeepReachable<V>) => U,
51+
): TemplatePath<T, U, `${string}.${"**"}.${string}`> {
52+
let tailSegments: readonly Segment[] = [];
53+
if (expr) {
54+
const proxy = createPathProxy([]);
55+
const result = expr(proxy as DeepReachable<V>);
56+
tailSegments =
57+
((result as Record<symbol, unknown>)?.[PATH_SEGMENTS] as Segment[]) ??
58+
[];
59+
}
60+
return new TemplatePathImpl([
61+
...this.segments,
62+
DEEP_WILDCARD,
63+
...tailSegments,
64+
]) as unknown as TemplatePath<T, U, `${string}.${"**"}.${string}`>;
65+
}
5466

55-
/**
56-
* Resolves this template path against actual data to return an array of concrete paths
57-
* that exist in the given data.
58-
*
59-
* @example
60-
* const template = path<Root>().users.each().name;
61-
* const concretePaths = template.expand(data); // [path<Root>().users[0].name, ...]
62-
*/
63-
expand(data: T): Path<T, V, string>[] {
64-
const results: Path<T, V, string>[] = [];
65-
66-
const walk = (currentData: unknown, segmentIdx: number, currentPath: Segment[]) => {
67-
if (segmentIdx >= this.segments.length) {
68-
results.push(new PathImpl<T, V, string>(currentPath));
69-
return;
70-
}
67+
/**
68+
* Resolves this template path against actual data to return an array of concrete paths
69+
* that exist in the given data.
70+
*
71+
* @example
72+
* const template = path<Root>().users.each().name;
73+
* const concretePaths = template.expand(data); // [path<Root>().users[0].name, ...]
74+
*/
75+
expand(data: T): Path<T, V, string>[] {
76+
const results: Path<T, V, string>[] = [];
7177

72-
const seg = this.segments[segmentIdx];
78+
const walk = (
79+
currentData: unknown,
80+
segmentIdx: number,
81+
currentPath: Segment[],
82+
) => {
83+
if (segmentIdx >= this.segments.length) {
84+
results.push(new PathImpl<T, V, string>(currentPath));
85+
return;
86+
}
7387

74-
if (seg === WILDCARD) {
75-
if (currentData != null && typeof currentData === "object") {
76-
const keys = Array.isArray(currentData)
77-
? Array.from(currentData.keys())
78-
: Object.keys(currentData);
79-
for (const key of keys) {
80-
walk((currentData as Record<string | number, unknown>)[key], segmentIdx + 1, [...currentPath, key]);
81-
}
82-
}
83-
} else if (seg === DEEP_WILDCARD) {
84-
// Match the rest of the path on the current node
85-
walk(currentData, segmentIdx + 1, currentPath);
88+
const seg = this.segments[segmentIdx];
8689

87-
// Recursively explore all descendants
88-
if (currentData != null && typeof currentData === "object") {
89-
const keys = Array.isArray(currentData)
90-
? Array.from(currentData.keys())
91-
: Object.keys(currentData);
92-
for (const key of keys) {
93-
walk((currentData as Record<string | number, unknown>)[key], segmentIdx, [...currentPath, key]);
94-
}
95-
}
96-
} else {
97-
if (currentData != null && typeof currentData === "object" && seg in currentData) {
98-
walk((currentData as Record<string | number, unknown>)[seg], segmentIdx + 1, [...currentPath, seg]);
99-
}
100-
}
101-
};
90+
if (seg === WILDCARD) {
91+
if (currentData != null && typeof currentData === "object") {
92+
const keys = Array.isArray(currentData)
93+
? Array.from(currentData.keys())
94+
: Object.keys(currentData);
95+
for (const key of keys) {
96+
walk(
97+
(currentData as Record<string | number, unknown>)[key],
98+
segmentIdx + 1,
99+
[...currentPath, key],
100+
);
101+
}
102+
}
103+
} else if (seg === DEEP_WILDCARD) {
104+
// Match the rest of the path on the current node
105+
walk(currentData, segmentIdx + 1, currentPath);
102106

103-
walk(data, 0, []);
104-
return results;
105-
}
107+
// Recursively explore all descendants
108+
if (currentData != null && typeof currentData === "object") {
109+
const keys = Array.isArray(currentData)
110+
? Array.from(currentData.keys())
111+
: Object.keys(currentData);
112+
for (const key of keys) {
113+
walk(
114+
(currentData as Record<string | number, unknown>)[key],
115+
segmentIdx,
116+
[...currentPath, key],
117+
);
118+
}
119+
}
120+
} else {
121+
if (
122+
currentData != null &&
123+
typeof currentData === "object" &&
124+
seg in currentData
125+
) {
126+
walk(
127+
(currentData as Record<string | number, unknown>)[seg],
128+
segmentIdx + 1,
129+
[...currentPath, seg],
130+
);
131+
}
132+
}
133+
};
106134

107-
/**
108-
* Extracts an array of values at this template path from the given data object.
109-
*
110-
* @example
111-
* const names = path<Root>().users.each().name.get(data); // string[]
112-
*/
113-
// @ts-expect-error Overriding get to return an array instead of a single value
114-
get(data: T): V[] {
115-
return this.expand(data).map(p => p.get(data));
116-
}
135+
walk(data, 0, []);
136+
return results;
137+
}
117138

118-
/**
119-
* Returns an accessor function that extracts an array of values at this template path from the given data object.
120-
* Useful for array methods like `.map()` or `.filter()`.
121-
*
122-
* @example
123-
* const allNames = companies.map(path<Company>().departments.each().name.fn);
124-
*/
125-
// @ts-expect-error Overriding fn to return an array instead of a single value
126-
get fn(): (data: T) => V[] {
127-
return (data: T) => this.get(data);
128-
}
139+
/**
140+
* Extracts an array of values at this template path from the given data object.
141+
*
142+
* @example
143+
* const names = path<Root>().users.each().name.get(data); // string[]
144+
*/
145+
// @ts-expect-error Overriding get to return an array instead of a single value
146+
get(data: T): V[] {
147+
return this.expand(data).map((p) => p.get(data));
148+
}
129149

130-
/**
131-
* Sets the provided value to all matching paths immutably.
132-
*
133-
* @example
134-
* const updatedData = path<Root>().users.each().name.set(data, "Bob");
135-
*/
136-
set(data: T, value: V): T {
137-
const paths = this.expand(data);
138-
let current = data;
139-
for (const p of paths) {
140-
current = p.set(current, value);
141-
}
142-
return current;
143-
}
144-
}
150+
/**
151+
* Returns an accessor function that extracts an array of values at this template path from the given data object.
152+
* Useful for array methods like `.map()` or `.filter()`.
153+
*
154+
* @example
155+
* const allNames = companies.map(path<Company>().departments.each().name.fn);
156+
*/
157+
// @ts-expect-error Overriding fn to return an array instead of a single value
158+
get fn(): (data: T) => V[] {
159+
return (data: T) => this.get(data);
160+
}
161+
162+
/**
163+
* Sets the provided value to all matching paths immutably.
164+
*
165+
* @example
166+
* const updatedData = path<Root>().users.each().name.set(data, "Bob");
167+
*/
168+
set(data: T, value: V): T {
169+
const paths = this.expand(data);
170+
let current = data;
171+
for (const p of paths) {
172+
current = p.set(current, value);
173+
}
174+
return current;
175+
}
176+
}

0 commit comments

Comments
 (0)