0.1.5 #4

Merged
Thilawyn merged 4 commits from next into master 2026-04-30 01:55:49 +02:00
4 changed files with 22 additions and 22 deletions
Showing only changes of commit 90f4a50eb9 - Show all commits

View File

@@ -137,9 +137,9 @@ const ref = yield* SubscriptionRef.make<{
// \/ Lens<User, NoSuchElementException, NoSuchElementException, never, never> // \/ Lens<User, NoSuchElementException, NoSuchElementException, never, never>
const jeanDupontLens = ref.pipe( const jeanDupontLens = ref.pipe(
Lens.fromSubscriptionRef, // Creates a lens that proxies the ref Lens.fromSubscriptionRef, // Creates a lens that proxies the ref
Lens.focusObjectField("users"), // Creates a focused lens that points to the users field Lens.focusObjectOn("users"), // Creates a focused lens that points to the users field
Lens.focusArrayAt(0), // Creates a focused lens that points to the first entry of the user array Lens.focusArrayAt(0), // Creates a focused lens that points to the first entry of the user array
) )
// Reading or writing from this lense can fail with NoSuchElementException // Reading or writing from this lense can fail with NoSuchElementException
// This is because of Lens.focusArrayAt(0), as reading and writing to an array is an unsafe operation // This is because of Lens.focusArrayAt(0), as reading and writing to an array is an unsafe operation
@@ -148,18 +148,18 @@ const jeanDupont = yield* Lens.get(jeanDupontLens)
yield* Lens.set( yield* Lens.set(
// You can focus even further down // You can focus even further down
Lens.focusObjectField(jeanDupontLens, "age"), Lens.focusObjectOn(jeanDupontLens, "age"),
yield* DateTime.make("03/25/1970"), yield* DateTime.make("03/25/1970"),
) )
// Mutations with the parent state are performed immutably by default // Mutations with the parent state are performed immutably by default
// unless you use a specific mutable transform such as 'focusMutableField' // unless you use a specific mutable transform such as 'focusObjectOnWritable'
``` ```
Currently available: Currently available:
| Name | Description | Parent state mutation behavior | Notes | | Name | Description | Parent state mutation behavior | Notes |
| - | - | - | - | | - | - | - | - |
| `focusObjectField` | Focuses to the field of an object. Replaces the parent object immutably when writing to the focused field | Immutable | | | `focusObjectOn` | Focuses to a field of an object. Replaces the parent object immutably when writing to the focused field | Immutable | |
| `focusObjectMutableField` | Focuses to the writable field of an object. Mutates the parent object in place via the writable field | Mutable | Type-safe: will not allow you to mutate `readonly` fields | | `focusObjectOnWritable` | Focuses to a writable field of an object. Mutates the parent object in place via the writable field | Mutable | Type-safe: will not allow you to mutate `readonly` fields |
| `focusArrayAt` | Focuses to an indexed entry of an array. Replaces the parent array immutably when writing to the focused index | Immutable | | | `focusArrayAt` | Focuses to an indexed entry of an array. Replaces the parent array immutably when writing to the focused index | Immutable | |
| `focusMutableArrayAt` | Focuses to an indexed entry of an array. Mutates the parent array in place at the focused index | Mutable | Type-safe: will not allow you to mutate `readonly` arrays | | `focusMutableArrayAt` | Focuses to an indexed entry of an array. Mutates the parent array in place at the focused index | Mutable | Type-safe: will not allow you to mutate `readonly` arrays |
| `focusTupleAt` | Focuses to an indexed entry of a readonly tuple. Replaces the parent tuple immutably when writing to the focused index | Immutable | | | `focusTupleAt` | Focuses to an indexed entry of a readonly tuple. Replaces the parent tuple immutably when writing to the focused index | Immutable | |
@@ -216,7 +216,7 @@ const someFunctionThatShouldOnlyHaveReadonlyAccessToTheState = (
const lens = ref.pipe( const lens = ref.pipe(
Lens.fromSubscriptionRef, Lens.fromSubscriptionRef,
Lens.focusObjectField("users"), Lens.focusObjectOn("users"),
) )
yield* someFunctionThatShouldOnlyHaveReadonlyAccessToTheState(lens) yield* someFunctionThatShouldOnlyHaveReadonlyAccessToTheState(lens)
``` ```
@@ -231,14 +231,14 @@ declare const sub: Subscribabe.Subscribable<readonly { name: string }[], never,
// \/ Subscribabe.Subscribable<string, NoSuchElementException, never> // \/ Subscribabe.Subscribable<string, NoSuchElementException, never>
const nameSub = sub.pipe( const nameSub = sub.pipe(
Subscribable.focusArrayAt(1), Subscribable.focusArrayAt(1),
Subscribable.focusObjectField("name"), Subscribable.focusObjectOn("name"),
) )
``` ```
Currently available: Currently available:
| Name | Description | | Name | Description |
| - | - | | - | - |
| `focusObjectField` | Focuses to the field of an object | | `focusObjectOn` | Focuses to the field of an object |
| `focusArrayAt` | Focuses to an indexed entry of an array | | `focusArrayAt` | Focuses to an indexed entry of an array |
| `focusTupleAt` | Focuses to an indexed entry of a tuple | | `focusTupleAt` | Focuses to an indexed entry of a tuple |
| `focusChunkAt` | Focuses to an indexed entry of a `Chunk` | | `focusChunkAt` | Focuses to an indexed entry of a `Chunk` |

View File

@@ -54,12 +54,12 @@ describe("Lens", () => {
expect(result[1]).toEqual(Option.some(50)) // 100 / 2 expect(result[1]).toEqual(Option.some(50)) // 100 / 2
}) })
test("focusObjectField focuses a nested property without touching other fields", async () => { test("focusObjectOn focuses a nested property without touching other fields", async () => {
const [initialCount, updatedState] = await Effect.runPromise( const [initialCount, updatedState] = await Effect.runPromise(
Effect.flatMap( Effect.flatMap(
SubscriptionRef.make({ count: 1, label: "original" }), SubscriptionRef.make({ count: 1, label: "original" }),
parent => { parent => {
const countLens = Lens.focusObjectField(Lens.fromSubscriptionRef(parent), "count") const countLens = Lens.focusObjectOn(Lens.fromSubscriptionRef(parent), "count")
return Effect.flatMap( return Effect.flatMap(
Lens.get(countLens), Lens.get(countLens),
count => Effect.flatMap( count => Effect.flatMap(
@@ -75,13 +75,13 @@ describe("Lens", () => {
expect(updatedState).toEqual({ count: 6, label: "original" }) expect(updatedState).toEqual({ count: 6, label: "original" })
}) })
test("focusObjectMutableField preserves the root identity when mutating in place", async () => { test("focusObjectOnWritable preserves the root identity when mutating in place", async () => {
const original = { detail: "keep" } const original = { detail: "keep" }
const updated = await Effect.runPromise( const updated = await Effect.runPromise(
Effect.flatMap( Effect.flatMap(
SubscriptionRef.make(original), SubscriptionRef.make(original),
parent => { parent => {
const detailLens = Lens.focusObjectMutableField(Lens.fromSubscriptionRef(parent), "detail") const detailLens = Lens.focusObjectOnWritable(Lens.fromSubscriptionRef(parent), "detail")
return Effect.flatMap( return Effect.flatMap(
Lens.set(detailLens, "mutated"), Lens.set(detailLens, "mutated"),
() => parent.get, () => parent.get,

View File

@@ -273,7 +273,7 @@ export const mapStream: {
/** /**
* Narrows the focus to a field of an object. Replaces the object in an immutable fashion when written to. * Narrows the focus to a field of an object. Replaces the object in an immutable fashion when written to.
*/ */
export const focusObjectField: { export const focusObjectOn: {
<A extends object, ER, EW, RR, RW, K extends keyof A>( <A extends object, ER, EW, RR, RW, K extends keyof A>(
self: Lens<A, ER, EW, RR, RW>, self: Lens<A, ER, EW, RR, RW>,
key: K, key: K,
@@ -290,7 +290,7 @@ export const focusObjectField: {
(a, b) => Object.setPrototypeOf({ ...a, [key]: b }, Object.getPrototypeOf(a)), (a, b) => Object.setPrototypeOf({ ...a, [key]: b }, Object.getPrototypeOf(a)),
)) ))
export declare namespace focusObjectMutableField { export declare namespace focusObjectOnWritable {
export type WritableKeys<T> = { export type WritableKeys<T> = {
[K in keyof T]-?: IfEquals< [K in keyof T]-?: IfEquals<
{ [P in K]: T[K] }, { [P in K]: T[K] },
@@ -304,17 +304,17 @@ export declare namespace focusObjectMutableField {
} }
/** /**
* Narrows the focus to a mutable field of an object. Mutates the object in place when written to. * Narrows the focus to a writable field of an object. Mutates the object in place when written to.
*/ */
export const focusObjectMutableField: { export const focusObjectOnWritable: {
<A extends object, ER, EW, RR, RW, K extends focusObjectMutableField.WritableKeys<A>>( <A extends object, ER, EW, RR, RW, K extends focusObjectOnWritable.WritableKeys<A>>(
self: Lens<A, ER, EW, RR, RW>, self: Lens<A, ER, EW, RR, RW>,
key: K, key: K,
): Lens<A[K], ER, EW, RR, RW> ): Lens<A[K], ER, EW, RR, RW>
<A extends object, ER, EW, RR, RW, K extends focusObjectMutableField.WritableKeys<A>>( <A extends object, ER, EW, RR, RW, K extends focusObjectOnWritable.WritableKeys<A>>(
key: K, key: K,
): (self: Lens<A, ER, EW, RR, RW>) => Lens<A[K], ER, EW, RR, RW> ): (self: Lens<A, ER, EW, RR, RW>) => Lens<A[K], ER, EW, RR, RW>
} = Function.dual(2, <A extends object, ER, EW, RR, RW, K extends focusObjectMutableField.WritableKeys<A>>( } = Function.dual(2, <A extends object, ER, EW, RR, RW, K extends focusObjectOnWritable.WritableKeys<A>>(
self: Lens<A, ER, EW, RR, RW>, self: Lens<A, ER, EW, RR, RW>,
key: K, key: K,
): Lens<A[K], ER, EW, RR, RW> => map(self, a => a[key], (a, b) => { a[key] = b; return a })) ): Lens<A[K], ER, EW, RR, RW> => map(self, a => a[key], (a, b) => { a[key] = b; return a }))

View File

@@ -42,7 +42,7 @@ export const mapOptionEffect: {
/** /**
* Narrows the focus to a field of an object. * Narrows the focus to a field of an object.
*/ */
export const focusObjectField: { export const focusObjectOn: {
<A extends object, K extends keyof A, E, R>( <A extends object, K extends keyof A, E, R>(
self: Subscribable.Subscribable<A, E, R>, self: Subscribable.Subscribable<A, E, R>,
key: K, key: K,