Skip to content

Commit

Permalink
cellify: follow, type Path
Browse files Browse the repository at this point in the history
  • Loading branch information
hbbio committed Apr 4, 2024
1 parent 8eac607 commit 340a051
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 2 deletions.
33 changes: 32 additions & 1 deletion src/cellify.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { expect, test } from "vitest";

import { Cellified, Uncellified, _cellify, _uncellify } from "./cellify";
import {
Cellified,
Uncellified,
_cellify,
_uncellify,
follow
} from "./cellify";
import { SheetProxy } from "./proxy";
import { Sheet } from "./sheet";

Expand Down Expand Up @@ -45,3 +51,28 @@ test("_cellify one", async () => {
const cell = await res.get();
await expect(cell.a.get()).resolves.toBe(1);
});

test("follow", async () => {
const sheet = new Sheet();
const proxy = new SheetProxy(sheet);
const v = { a: [1, 2, 3], b: { c: { foo: 1, bar: 1 } } };
const cv = _cellify(proxy, v);
const f = follow(proxy, cv, ["a", 1]);
await expect(f.get()).resolves.toBe(2);
expect(sheet.stats).toEqual({ size: 12, count: 12 });

// update the cell directly
(await (await cv.get()).a.get())[1].set(4);
await expect(f.get()).resolves.toBe(4);
expect(sheet.stats).toEqual({ size: 12, count: 12 }); // unchanged

// prepend a new cell in array
(await cv.get()).a.update((l) => [proxy.new(0), ...l]);
await expect(f.get()).resolves.toBe(1);
expect(sheet.stats).toEqual({ size: 13, count: 14 }); // one new cell, update one pointer

// delete path, cell is error
(await cv.get()).a.set([]);
await expect(f.get()).resolves.toBeInstanceOf(Error);
expect(sheet.stats).toEqual({ size: 13, count: 14 }); // unchanged
});
33 changes: 32 additions & 1 deletion src/cellify.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { AnyCell, Cell, ValueCell } from "./cell";
import { AnyCell, Cell, MapCell, ValueCell } from "./cell";
import { collector } from "./gc";
import { SheetProxy } from "./proxy";

// Cellified computes a cellified type.
Expand Down Expand Up @@ -76,3 +77,33 @@ export const _uncellify = async <T>(
// Classes, null or base types (string, number, ...)
return value as Uncellified<T>;
};

export type Path = (string | number)[];

/**
* follow a static path for a Cellified value.
*/
export const follow = (
proxy: SheetProxy,
v: Cellified<unknown>,
path: Path,
name = "follow"
) => {
const aux = (v: Cellified<unknown>, path: Path, name: string) => {
// @todo multi collector?
const coll = collector<MapCell<unknown, false>>(proxy);
return proxy.map(
[v],
(_v) => {
const key = path[0];
const isContainer = Array.isArray(_v) || isObject(_v);
if (isContainer && _v[key])
return coll(aux(_v[key], path.slice(1), `${name}.${key}`));
if (isContainer) throw new Error(`path not found: ${key}`);
return _v; // pointer
},
name
);
};
return aux(v, path, name);
};
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,10 @@ export {
export {
_cellify,
_uncellify,
follow,
isObject,
type Cellified,
type Path,
type Uncellified
} from "./cellify";
export { Debugger } from "./debug";
Expand Down

0 comments on commit 340a051

Please sign in to comment.