All files / json-crdt/model/api proxy.ts

100% Statements 9/9
100% Branches 4/4
83.33% Functions 5/6
100% Lines 7/7

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109                                                                                                                                                                                    171x       65x 49x 16x     171x         139x   139x    
import type {JsonNodeApi} from './types';
import type * as nodes from '../../nodes';
import type {PeritextNode, QuillDeltaNode} from '../../../json-crdt-extensions';
import type {VecNodeExtensionData} from '../../schema/types';
import type {PathStep} from '@jsonjoy.com/json-pointer';
import type {NodeApi} from '..';
 
export interface ProxyNode<N extends nodes.JsonNode = nodes.JsonNode> {
  $: JsonNodeApi<N>;
}
 
export type ProxyNodeCon<N extends nodes.ConNode<any>> = ProxyNode<N>;
export type ProxyNodeVal<N extends nodes.ValNode<any>> = ProxyNode<N> & {
  _: JsonNodeToProxyNode<ReturnType<N['child']>>;
};
export type ProxyNodeVec<N extends nodes.VecNode<any>> = ProxyNode<N> & {
  [K in keyof nodes.JsonNodeView<N>]: JsonNodeToProxyNode<nodes.JsonNodeView<N>[K]>;
} & {
  toExt: () => JsonNodeApi<VecNodeExtensionData<N>>;
};
export type ProxyNodeObj<N extends nodes.ObjNode<any>> = ProxyNode<N> & {
  [K in keyof nodes.JsonNodeView<N>]: JsonNodeToProxyNode<(N extends nodes.ObjNode<infer M> ? M : never)[K]>;
};
export type ProxyNodeStr = ProxyNode<nodes.StrNode>;
export type ProxyNodeBin = ProxyNode<nodes.BinNode>;
export type ProxyNodeArr<N extends nodes.ArrNode<any>> = ProxyNode<N> &
  Record<number, JsonNodeToProxyNode<N extends nodes.ArrNode<infer E> ? E : never>>;
 
// prettier-ignore
export type JsonNodeToProxyNode<N> = N extends nodes.ConNode<any>
  ? ProxyNodeCon<N>
  : N extends nodes.RootNode<any>
    ? ProxyNodeVal<N>
    : N extends nodes.ValNode<any>
      ? ProxyNodeVal<N>
      : N extends nodes.StrNode
        ? ProxyNodeStr
        : N extends nodes.BinNode
          ? ProxyNodeBin
          : N extends nodes.ArrNode<any>
            ? ProxyNodeArr<N>
            : N extends nodes.ObjNode<any>
              ? ProxyNodeObj<N>
              : N extends nodes.VecNode<any>
                ? ProxyNodeVec<N>
                : N extends PeritextNode
                  ? ProxyNode<PeritextNode>
                  : N extends QuillDeltaNode
                    ? ProxyNode<QuillDeltaNode>
                    : never;
 
export type JsonNodeToProxyPathNodeEnd<N> = {$?: JsonNodeApi<N>};
 
// prettier-ignore
export type JsonNodeToProxyPathNode<N> = 0 extends 1 & N
  ? ProxyPathNode<{$?: NodeApi<N extends nodes.JsonNode<unknown> ? N : nodes.JsonNode>}>
  : N extends nodes.ArrNode<infer Element>
    ? JsonNodeToProxyPathNode<Element>[] & JsonNodeToProxyPathNodeEnd<N>
    : N extends nodes.ObjNode<infer Obj>
      ? {[K in keyof Obj]: JsonNodeToProxyPathNode<Obj[K]>} & JsonNodeToProxyPathNodeEnd<N>
      : N extends nodes.VecNode<infer Tuple>
        ? {[K in keyof Tuple]: JsonNodeToProxyPathNode<Tuple[K]>} & JsonNodeToProxyPathNodeEnd<N>
        : N extends nodes.RootNode<infer M>
          ? JsonNodeToProxyPathNode<M>
          : nodes.JsonNode<unknown> extends N
            ? ProxyPathNode<{$?: NodeApi<N extends nodes.JsonNode<unknown> ? N : nodes.JsonNode>}>
            : JsonNodeToProxyPathNodeEnd<N>;
 
export type ProxyPathEndMethod<Args extends unknown[], Return> = (path: PathStep[], ...args: Args) => Return;
export type ProxyPathUserEndMethod<M extends ProxyPathEndMethod<any[], any>> = M extends ProxyPathEndMethod<
  infer Args,
  infer Return
>
  ? (...args: Args) => Return
  : never;
export type ProxyPathNodeStep<Api, Next> = Api & Record<string | number, Next>;
export type ProxyPathNode<Api> = ProxyPathNodeStep<
  Api,
  ProxyPathNodeStep<
    Api,
    ProxyPathNodeStep<
      Api,
      ProxyPathNodeStep<
        Api,
        ProxyPathNodeStep<Api, ProxyPathNodeStep<Api, ProxyPathNodeStep<Api, ProxyPathNodeStep<Api, any>>>>
      >
    >
  >
>;
 
export const proxy = <EndMethod extends ProxyPathEndMethod<any[], any>>(
  fn: EndMethod,
  path: PathStep[] = [],
): ProxyPathNode<ProxyPathUserEndMethod<EndMethod>> =>
  new Proxy(() => {}, {
    get: (target, prop, receiver) => (path.push(String(prop)), proxy(fn, path)),
    apply: (target, thisArg, args) => fn(path, ...args),
  }) as any;
 
export const proxy$ = <EndMethod extends ProxyPathEndMethod<any[], any>, Sentinel extends string>(
  fn: EndMethod,
  sentinel: Sentinel,
  path: PathStep[] = [],
): ProxyPathNode<{[k in Sentinel]: ReturnType<EndMethod>}> =>
  new Proxy(
    {},
    {get: (t, prop, r) => (prop === sentinel ? fn(path) : (path.push(String(prop)), proxy$(fn, sentinel, path)))},
  ) as any;