Skip to content

Commit

Permalink
Merge pull request #17 from anthonyjoeseph/array-index
Browse files Browse the repository at this point in the history
Array & Record index
  • Loading branch information
anthonyjoeseph authored Apr 5, 2022
2 parents f5f66af + 130e1a5 commit 92b11ab
Show file tree
Hide file tree
Showing 45 changed files with 1,025 additions and 416 deletions.
25 changes: 25 additions & 0 deletions PathIdea2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Build (tail recursive)

```ts
_Obj1 = { a: { b: number, x: boolean }, c: { d: { e: string } } }
Obj1 = [
{ path: ['a']; value: { b: number, x: boolean} },
{ path: ['c']; value: { d: { e: string } }
]
Output1 = ['a'] | ['c']
|
V
Obj2 = [
{ path: ['a', 'b']; value: number },
{ path: ['a', 'x']; value: boolean }
{ path: ['c', 'd']; value: { e: string } }
]
Output2 = ['a', 'b'] | ['a', 'x'] | ['c', 'd']
|
V
Obj3 = [
{ path: ['c', 'd', 'e']; value: string }
]
Output3 = ['c', 'd', 'e']

```
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
"prepublishOnly": "yarn fix:lint && yarn test"
},
"dependencies": {
"fp-ts-std": "^0.10.1",
"monocle-ts": "^2.3.5"
},
"devDependencies": {
Expand Down
19 changes: 10 additions & 9 deletions src/types/get.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
import type { Option } from "fp-ts/Option";
import type { AtPath } from "../util/AtPath";
import type { Build } from "../util/Build";
import type { IndiciesForPath } from "../util/indicies";
import type { Paths } from "../util/Paths";
import type { GiveOpt, HasOptional } from "../util/predicates";
import { AddNullSegments } from "../util/segments";
import type { Segments } from "../util/segments";

export type Get = <
Infer,
Path extends unknown extends Infer ? string : Paths<Infer>,
Ret extends unknown extends Infer ? unknown : GiveOpt<AtPath<Infer, AddNullSegments<Path>>, AddNullSegments<Path>>
Ret extends unknown extends Infer ? unknown : GiveOpt<AtPath<Infer, S>, S>,
S extends unknown[] = Segments<Path>
>(
path: Path & string
path: Path & string,
...indicies: IndiciesForPath<S>
) => unknown extends Infer
? unknown extends Ret
? <Constructed extends Build<Path, unknown>>(
obj: Constructed
) => GiveOpt<AtPath<Constructed, AddNullSegments<Path>>, AddNullSegments<Path>>
: true extends HasOptional<Path>
? (obj: Build<Path, [Ret] extends [Option<infer A>] ? A : unknown>) => Ret
: (obj: Build<Path, Ret>) => Ret
? <Constructed extends Build<S, unknown>>(obj: Constructed) => GiveOpt<AtPath<Constructed, S>, S>
: true extends HasOptional<S>
? (obj: Build<S, [Ret] extends [Option<infer A>] ? A : unknown>) => Ret
: (obj: Build<S, Ret>) => Ret
: (obj: Infer) => Ret;
14 changes: 9 additions & 5 deletions src/types/modify.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import type { Paths } from "../util/Paths";
import type { AtPath } from "../util/AtPath";
import { AddNullSegments } from "../util/segments";
import type { Segments } from "../util/segments";
import type { IndiciesForPath } from "../util/indicies";

export type Modify = <Infer, Path extends Paths<Infer>>(
export type Modify = <
Infer,
Path extends Paths<Infer>,
S extends unknown[] = Segments<Path>,
A = AtPath<Infer, S, "no-traversals">
>(
path: Path & string,
modFunc: (
v: AtPath<Infer, AddNullSegments<Path>, "no-traversals">
) => AtPath<Infer, AddNullSegments<Path>, "no-traversals">
...args: [...indicies: IndiciesForPath<S>, modFunc: (v: A) => A]
) => (a: Infer) => Infer;
23 changes: 14 additions & 9 deletions src/types/modifyF.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,47 @@ import { Applicative, Applicative1, Applicative2, Applicative3 } from "fp-ts/lib
import { HKT, Kind, Kind2, Kind3, URIS, URIS2, URIS3 } from "fp-ts/lib/HKT";
import type { Paths } from "../util/Paths";
import type { AtPath } from "../util/AtPath";
import { AddNullSegments } from "../util/segments";
import { Segments } from "../util/segments";
import { IndiciesForPath } from "../util/indicies";

export type ModifyF = {
<F extends URIS3>(F: Applicative3<F>): <
R,
E,
Infer,
Path extends Paths<Infer>,
Val extends AtPath<Infer, AddNullSegments<Path>, "no-traversals">
Val extends AtPath<Infer, S, "no-traversals">,
S extends unknown[] = Segments<Path>
>(
path: Path & string,
modFunc: (v: Val) => Kind3<F, R, E, Val>
...args: [...indicies: IndiciesForPath<S>, modFunc: (v: Val) => Kind3<F, R, E, Val>]
) => (a: Infer) => Kind3<F, R, E, Infer>;
<F extends URIS2>(F: Applicative2<F>): <
E,
Infer,
Path extends Paths<Infer>,
Val extends AtPath<Infer, AddNullSegments<Path>, "no-traversals">
Val extends AtPath<Infer, S, "no-traversals">,
S extends unknown[] = Segments<Path>
>(
path: Path & string,
modFunc: (v: Val) => Kind2<F, E, Val>
...args: [...indicies: IndiciesForPath<S>, modFunc: (v: Val) => Kind2<F, E, Val>]
) => (a: Infer) => Kind2<F, E, Infer>;
<F extends URIS>(F: Applicative1<F>): <
Infer,
Path extends Paths<Infer>,
Val extends AtPath<Infer, AddNullSegments<Path>, "no-traversals">
Val extends AtPath<Infer, S, "no-traversals">,
S extends unknown[] = Segments<Path>
>(
path: Path & string,
modFunc: (v: Val) => Kind<F, Val>
...args: [...indicies: IndiciesForPath<S>, modFunc: (v: Val) => Kind<F, Val>]
) => (a: Infer) => Kind<F, Infer>;
<F>(F: Applicative<F>): <
Infer,
Path extends Paths<Infer>,
Val extends AtPath<Infer, AddNullSegments<Path>, "no-traversals">
Val extends AtPath<Infer, S, "no-traversals">,
S extends unknown[] = Segments<Path>
>(
path: Path & string,
modFunc: (v: Val) => HKT<F, Val>
...args: [...indicies: IndiciesForPath<S>, modFunc: (v: Val) => HKT<F, Val>]
) => (a: Infer) => HKT<F, Infer>;
};
16 changes: 10 additions & 6 deletions src/types/modifyOption.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import type { AtPath } from "../util/AtPath";
import type { IndiciesForPath } from "../util/indicies";
import type { Paths } from "../util/Paths";
import type { GiveOpt } from "../util/predicates";
import { AddNullSegments } from "../util/segments";
import type { Segments } from "../util/segments";

export type ModifyOption = <Infer, Path extends Paths<Infer>>(
export type ModifyOption = <
Infer,
Path extends Paths<Infer>,
S extends unknown[] = Segments<Path>,
A = AtPath<Infer, S, "no-traversals">
>(
path: Path & string,
modFunc: (
v: AtPath<Infer, AddNullSegments<Path>, "no-traversals">
) => AtPath<Infer, AddNullSegments<Path>, "no-traversals">
) => (a: Infer) => GiveOpt<Infer, AddNullSegments<Path>>;
...args: [...indicies: IndiciesForPath<S>, modFunc: (v: A) => A]
) => (a: Infer) => GiveOpt<Infer, S>;
19 changes: 13 additions & 6 deletions src/types/modifyOptionW.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import type { Paths } from "../util/Paths";
import type { Build } from "../util/Build";
import type { ApplyTraversals, AtPath } from "../util/AtPath";
import type { GiveOpt } from "../util/predicates";
import { AddNullSegments } from "../util/segments";
import type { AtPath } from "../util/AtPath";
import type { GiveOpt, HasIndexedAccess } from "../util/predicates";
import type { Segments } from "../util/segments";
import type { IndiciesForPath } from "../util/indicies";

export type ModifyOptionW = <Infer, Path extends Paths<Infer>, RetVal>(
export type ModifyOptionW = <
Infer,
Path extends Paths<Infer>,
RetVal,
S extends unknown[] = Segments<Path>,
A = AtPath<Infer, S, "no-traversals">
>(
path: Path & string,
modFunc: (v: AtPath<Infer, AddNullSegments<Path>, "no-traversals">) => RetVal
) => (a: Infer) => GiveOpt<ApplyTraversals<Build<Path, RetVal, Infer>, Path>, Path>;
...args: [...indicies: IndiciesForPath<S>, modFunc: (v: A) => RetVal]
) => (a: Infer) => GiveOpt<Build<S, true extends HasIndexedAccess<S> ? RetVal | AtPath<Infer, S> : RetVal, Infer>, S>;
23 changes: 13 additions & 10 deletions src/types/modifyW.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import type { Paths } from "../util/Paths";
import type { Build } from "../util/Build";
import type { ApplyTraversals, AtPath } from "../util/AtPath";
import type { HasOptional } from "../util/predicates";
import { AddNullSegments } from "../util/segments";
import type { AtPath } from "../util/AtPath";
import type { HasIndexedAccess } from "../util/predicates";
import type { Segments } from "../util/segments";
import type { IndiciesForPath } from "../util/indicies";

export type ModifyW = <Infer, Path extends Paths<Infer>, RetVal>(
export type ModifyW = <
Infer,
Path extends Paths<Infer>,
RetVal,
S extends unknown[] = Segments<Path>,
A = AtPath<Infer, S, "no-traversals">
>(
path: Path & string,
modFunc: (v: AtPath<Infer, AddNullSegments<Path>, "no-traversals">) => RetVal
) => (
a: Infer
) => true extends HasOptional<Path>
? ApplyTraversals<Build<Path, RetVal | AtPath<Infer, AddNullSegments<Path>>, Infer>, AddNullSegments<Path>>
: ApplyTraversals<Build<Path, RetVal, Infer>, AddNullSegments<Path>>;
...args: [...indicies: IndiciesForPath<S>, modFunc: (v: A) => RetVal]
) => (a: Infer) => Build<S, true extends HasIndexedAccess<S> ? RetVal | AtPath<Infer, S> : RetVal, Infer>;
3 changes: 2 additions & 1 deletion src/types/remove.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Paths } from "../util/Paths";
import type { Build } from "../util/Build";
import { Segments } from "../util/segments";

export type Remove = <Infer, Path extends Paths<Infer, "dynamic">>(
fullPath: Path & string
) => (a: Infer) => Build<Path, unknown, Infer, string, "remove">;
) => (a: Infer) => Build<Segments<Path>, unknown, Infer, string, "remove">;
11 changes: 8 additions & 3 deletions src/types/rename.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import type { Paths } from "../util/Paths";
import type { Build } from "../util/Build";
import { AtPath } from "../util/AtPath";
import { AddNullSegments } from "../util/segments";
import { Segments } from "../util/segments";

export type Rename = <Infer, Path extends Paths<Infer, "dynamic">, NewKey extends string>(
export type Rename = <
Infer,
Path extends Paths<Infer, "dynamic">,
NewKey extends string,
S extends unknown[] = Segments<Path>
>(
fullPath: Path & string,
newKey: NewKey
) => (a: Infer) => Build<Path, AtPath<Infer, AddNullSegments<Path>>, Infer, NewKey>;
) => (a: Infer) => Build<S, AtPath<Infer, S>, Infer, NewKey>;
12 changes: 9 additions & 3 deletions src/types/set.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import type { AtPath } from "../util/AtPath";
import { IndiciesForPath } from "../util/indicies";
import type { Paths } from "../util/Paths";
import { AddNullSegments } from "../util/segments";
import { Segments } from "../util/segments";

export type Set = <Infer, Path extends Paths<Infer>, Val extends AtPath<Infer, AddNullSegments<Path>, "no-traversals">>(
export type Set = <
Infer,
Path extends Paths<Infer>,
Val extends AtPath<Infer, S, "no-traversals">,
S extends unknown[] = Segments<Path>
>(
path: Path & string,
val: Val
...args: [...indicies: IndiciesForPath<S>, val: Val]
) => (obj: Infer) => Infer;
10 changes: 6 additions & 4 deletions src/types/setOption.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import type { AtPath } from "../util/AtPath";
import type { IndiciesForPath } from "../util/indicies";
import type { Paths } from "../util/Paths";
import type { GiveOpt } from "../util/predicates";
import { AddNullSegments } from "../util/segments";
import type { Segments } from "../util/segments";

export type SetOption = <
Infer,
Path extends Paths<Infer>,
Val extends AtPath<Infer, AddNullSegments<Path>, "no-traversals">
Val extends AtPath<Infer, S, "no-traversals">,
S extends unknown[] = Segments<Path>
>(
path: Path & string,
val: Val
) => (obj: Infer) => GiveOpt<Infer, Path>;
...args: [...indicies: IndiciesForPath<S>, val: Val]
) => (obj: Infer) => GiveOpt<Infer, S>;
16 changes: 13 additions & 3 deletions src/types/upsert.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
import type { Paths } from "../util/Paths";
import type { Build } from "../util/Build";
import type { IndiciesForPath } from "../util/indicies";
import type { HasIndexedAccess } from "../util/predicates";
import type { Segments } from "../util/segments";
import type { AtPath } from "../util/AtPath";

export type Upsert = <Infer, Path extends Paths<Infer, "upsert">, Final extends string, Val>(
export type Upsert = <
Infer,
Path extends Paths<Infer, "upsert">,
Final extends string,
Val,
S extends unknown[] = Segments<Path>
>(
path: Path & string,
final: Final,
val: Val
) => (a: Infer) => Build<`${Extract<Path, string>}.${Final}`, Val, Infer>;
...args: [...indicies: IndiciesForPath<S>, val: Val]
) => (a: Infer) => Build<[...S, Final], true extends HasIndexedAccess<S> ? AtPath<Infer, S> | Val : Val, Infer>;
43 changes: 21 additions & 22 deletions src/util/AtPath.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,35 @@
import { Some } from "fp-ts/Option";
import { Left, Right } from "fp-ts/Either";
import { FirstSegment, TailSegment, UnescapeParenthesis } from "./segments";

type Operation = "apply-traversals" | "no-traversals";

export type AtPath<A, Args extends string, Op extends Operation = "apply-traversals"> = unknown extends A
export type AtPath<A, Args extends unknown[], Op extends Operation = "apply-traversals"> = unknown extends A
? unknown
: Args extends ""
? A
: Op extends "apply-traversals"
? ApplyTraversals<
TailSegment<Args> extends ""
? ApplySegment<A, Args>
: AtPath<ApplySegment<A, FirstSegment<Args>>, TailSegment<Args>, "no-traversals">,
Args extends [infer First, ...infer Tail]
? AtPath<ApplySegment<A, Extract<First, string>>, Tail, "no-traversals">
: A,
Args
>
: TailSegment<Args> extends ""
? ApplySegment<A, Args>
: AtPath<ApplySegment<A, FirstSegment<Args>>, TailSegment<Args>, Op>;
: Args extends [infer First, ...infer Tail]
? AtPath<ApplySegment<A, Extract<First, string>>, Tail, Op>
: A;

export type ApplyTraversals<A, Args extends string> = Args extends ""
? A
: FirstSegment<Args> extends `(${string}`
? ApplyTraversals<A, TailSegment<Args>>
: FirstSegment<Args> extends "[]>"
? ApplyTraversals<A[], TailSegment<Args>>
: FirstSegment<Args> extends "{}>"
? ApplyTraversals<Record<string, A>, TailSegment<Args>>
: ApplyTraversals<A, TailSegment<Args>>;
export type ApplyTraversals<A, Args extends unknown[]> = Args extends [infer First, ...infer Tail]
? First extends `(${string}`
? ApplyTraversals<A, Tail>
: First extends "[]>"
? ApplyTraversals<A[], Tail>
: First extends "{}>"
? ApplyTraversals<Record<string, A>, Tail>
: ApplyTraversals<A, Tail>
: A;

type ApplySegment<A, Seg extends string> = Seg extends `(${string}`
? A[Extract<UnescapeParenthesis<Seg>, keyof A>]
type ApplySegment<A, Seg extends string> = Seg extends `(${infer Middle})`
? A[Extract<Middle, keyof A>]
: Seg extends "?"
? NonNullable<A>
: Seg extends "?some"
Expand All @@ -39,9 +38,9 @@ type ApplySegment<A, Seg extends string> = Seg extends `(${string}`
? Extract<A, Left<unknown>>["left"]
: Seg extends "?right"
? Extract<A, Right<unknown>>["right"]
: Seg extends "[]>"
? Extract<A, unknown[]>[number]
: Seg extends "{}>"
: Seg extends "[]>" | "[number]"
? Extract<A, readonly unknown[]>[number]
: Seg extends "{}>" | "[string]"
? Extract<A, Record<string, unknown>>[string]
: Seg extends `[${infer TupleIndex}]`
? A[Extract<TupleIndex, keyof A>]
Expand Down
Loading

0 comments on commit 92b11ab

Please sign in to comment.