@graffy/common 0.18.1-alpha.2 → 0.19.1-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/coding/alphabet.js +5 -0
  2. package/coding/args.d.ts +5 -0
  3. package/coding/args.js +93 -0
  4. package/coding/base64.d.ts +2 -0
  5. package/coding/base64.js +41 -0
  6. package/coding/decodeTree.d.ts +2 -0
  7. package/coding/decodeTree.js +197 -0
  8. package/coding/decorate.js +211 -0
  9. package/coding/encodeTree.d.ts +2 -0
  10. package/coding/encodeTree.js +248 -0
  11. package/coding/id.js +4 -0
  12. package/coding/index.d.ts +8 -0
  13. package/{types/coding/index.d.ts → coding/index.js} +4 -4
  14. package/coding/number.d.ts +2 -0
  15. package/coding/number.js +39 -0
  16. package/coding/pack.d.ts +2 -0
  17. package/coding/pack.js +71 -0
  18. package/coding/path.d.ts +3 -0
  19. package/coding/path.js +41 -0
  20. package/coding/string.d.ts +2 -0
  21. package/coding/string.js +8 -0
  22. package/coding/struct.d.ts +11 -0
  23. package/coding/struct.js +163 -0
  24. package/index.d.ts +6 -0
  25. package/node/find.d.ts +2 -0
  26. package/node/find.js +14 -0
  27. package/node/index.d.ts +2 -0
  28. package/{types/node/index.d.ts → node/index.js} +1 -0
  29. package/node/types.d.ts +6 -0
  30. package/node/types.js +18 -0
  31. package/object.d.ts +4 -0
  32. package/object.js +86 -0
  33. package/ops/add.js +64 -0
  34. package/{types/ops → ops}/finalize.d.ts +1 -1
  35. package/ops/finalize.js +19 -0
  36. package/{types/ops → ops}/getKnown.d.ts +1 -4
  37. package/ops/getKnown.js +24 -0
  38. package/ops/index.d.ts +9 -0
  39. package/ops/merge.d.ts +3 -0
  40. package/ops/merge.js +112 -0
  41. package/ops/path.d.ts +6 -0
  42. package/ops/path.js +91 -0
  43. package/ops/setVersion.js +29 -0
  44. package/ops/sieve.d.ts +3 -0
  45. package/ops/sieve.js +193 -0
  46. package/{types/ops → ops}/slice.d.ts +2 -6
  47. package/ops/slice.js +153 -0
  48. package/ops/step.d.ts +6 -0
  49. package/ops/step.js +61 -0
  50. package/package.json +14 -8
  51. package/stream/index.d.ts +2 -0
  52. package/stream/makeWatcher.d.ts +10 -0
  53. package/stream/makeWatcher.js +19 -0
  54. package/stream/mergeStreams.js +20 -0
  55. package/util.d.ts +15 -0
  56. package/util.js +106 -0
  57. package/index.cjs +0 -1673
  58. package/index.mjs +0 -1673
  59. package/types/coding/args.d.ts +0 -5
  60. package/types/coding/base64.d.ts +0 -2
  61. package/types/coding/decodeTree.d.ts +0 -2
  62. package/types/coding/encodeTree.d.ts +0 -2
  63. package/types/coding/number.d.ts +0 -2
  64. package/types/coding/pack.d.ts +0 -2
  65. package/types/coding/path.d.ts +0 -3
  66. package/types/coding/string.d.ts +0 -2
  67. package/types/coding/struct.d.ts +0 -11
  68. package/types/node/find.d.ts +0 -2
  69. package/types/node/types.d.ts +0 -6
  70. package/types/object.d.ts +0 -4
  71. package/types/ops/merge.d.ts +0 -3
  72. package/types/ops/path.d.ts +0 -6
  73. package/types/ops/sieve.d.ts +0 -3
  74. package/types/ops/step.d.ts +0 -6
  75. package/types/stream/makeWatcher.d.ts +0 -16
  76. package/types/util.d.ts +0 -15
  77. package/{types/coding → coding}/alphabet.d.ts +0 -0
  78. package/{types/coding → coding}/decorate.d.ts +0 -0
  79. package/{types/coding → coding}/id.d.ts +0 -0
  80. package/{types/index.d.ts → index.js} +0 -0
  81. package/{types/ops → ops}/add.d.ts +0 -0
  82. package/{types/ops/index.d.ts → ops/index.js} +1 -1
  83. /package/{types/ops → ops}/setVersion.d.ts +0 -0
  84. /package/{types/stream/index.d.ts → stream/index.js} +0 -0
  85. /package/{types/stream → stream}/mergeStreams.d.ts +0 -0
package/node/types.js ADDED
@@ -0,0 +1,18 @@
1
+ export function isRange(node) {
2
+ return node && typeof node.end !== 'undefined';
3
+ }
4
+ export function isBranch(node) {
5
+ return node && typeof node.children !== 'undefined';
6
+ }
7
+ export function isPrefix(node) {
8
+ return node?.prefix;
9
+ }
10
+ export function isLink(node) {
11
+ return node && typeof node.path !== 'undefined';
12
+ }
13
+ export function isOlder(node, version) {
14
+ return typeof node.version !== 'undefined' && node.version < version;
15
+ }
16
+ export function isNewer(node, version) {
17
+ return typeof node.version !== 'undefined' && node.version > version;
18
+ }
package/object.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ export declare function mergeObject(base: any, change: any): any;
2
+ export declare function cloneObject(object: any): any;
3
+ export declare function wrapObject(object: any, path: any): any;
4
+ export declare function unwrapObject(object: any, path: any): any;
package/object.js ADDED
@@ -0,0 +1,86 @@
1
+ import isEqual from 'lodash/isEqual.js';
2
+ import { splitArgs } from "./coding/index.js";
3
+ import { isEmpty } from "./util.js";
4
+ export function mergeObject(base, change) {
5
+ if (typeof change !== 'object' ||
6
+ typeof base !== 'object' ||
7
+ !base ||
8
+ !change) {
9
+ return change;
10
+ }
11
+ for (const prop in change) {
12
+ if (prop in base) {
13
+ const value = mergeObject(base[prop], change[prop]);
14
+ if (value === null) {
15
+ delete base[prop];
16
+ }
17
+ else {
18
+ base[prop] = value;
19
+ }
20
+ }
21
+ else {
22
+ base[prop] = change[prop];
23
+ }
24
+ }
25
+ return isEmpty(base) ? null : base;
26
+ }
27
+ export function cloneObject(object) {
28
+ if (typeof object !== 'object' || !object) {
29
+ return object;
30
+ }
31
+ const clone = {};
32
+ for (const prop in object) {
33
+ const value = cloneObject(object[prop]);
34
+ if (value === null)
35
+ continue;
36
+ clone[prop] = value;
37
+ }
38
+ return isEmpty(clone) ? null : clone;
39
+ }
40
+ export function wrapObject(object, path) {
41
+ if (!Array.isArray(path))
42
+ throw Error(`wrapObject.path_not_array ${path}`);
43
+ for (let i = path.length - 1; i >= 0; i--) {
44
+ const $key = path[i];
45
+ if (typeof $key === 'string') {
46
+ object = { [$key]: object };
47
+ }
48
+ else if (Array.isArray(object)) {
49
+ object = [{ $key, $chi: object }];
50
+ }
51
+ else {
52
+ object = [{ $key, ...object }];
53
+ }
54
+ }
55
+ return object;
56
+ }
57
+ export function unwrapObject(object, path) {
58
+ if (!Array.isArray(path))
59
+ throw Error(`unwrapObject.path_not_array ${path}`);
60
+ for (let i = 0; i < path.length; i++) {
61
+ if (!object || typeof object !== 'object')
62
+ return;
63
+ const $key = path[i];
64
+ if (typeof $key === 'string') {
65
+ if (Array.isArray(object)) {
66
+ throw Error(`unwrapObject.string_key_array:${$key}`);
67
+ }
68
+ object = object[$key];
69
+ }
70
+ else {
71
+ if (!Array.isArray(object)) {
72
+ throw Error(`unwrapObject.arg_key_object:${JSON.stringify($key)}`);
73
+ }
74
+ const [page, filter] = splitArgs($key);
75
+ if (page && !page.$cursor) {
76
+ // TODO: Return a slice of this array
77
+ return object;
78
+ }
79
+ const target = page?.$cursor
80
+ ? { ...filter, $cursor: page.$cursor }
81
+ : filter;
82
+ object = object.find(({ $key }) => isEqual($key, target));
83
+ }
84
+ }
85
+ return object;
86
+ }
package/ops/add.js ADDED
@@ -0,0 +1,64 @@
1
+ import { isBranch } from "../node/index.js";
2
+ import { cmp as compareKey, find } from "../util.js";
3
+ export default function add(base, diff) {
4
+ let changed = false;
5
+ // console.log('Add', diff);
6
+ // console.log('before add', base);
7
+ let index = 0;
8
+ for (const node of diff) {
9
+ const cmp = compare(node);
10
+ const nodeIsBranch = isBranch(node);
11
+ index = find(base, cmp, index);
12
+ const item = base[index];
13
+ const itemIsBranch = isBranch(item);
14
+ if (!item || cmp(item)) {
15
+ // This node doesn't exist in the base, insert it.
16
+ base.splice(index, 0, clone(node));
17
+ changed = true;
18
+ continue;
19
+ }
20
+ if (nodeIsBranch && itemIsBranch) {
21
+ changed = add(item.children, node.children) || changed;
22
+ }
23
+ else if (nodeIsBranch) {
24
+ continue;
25
+ }
26
+ else if (itemIsBranch) {
27
+ item.value = node.value;
28
+ changed = true;
29
+ }
30
+ else {
31
+ item.value += node.value;
32
+ }
33
+ // If this item was decremented to zero, remove it.
34
+ const size = itemIsBranch ? item.children.length : item.value;
35
+ if (!size) {
36
+ base.splice(index, 1);
37
+ changed = true;
38
+ }
39
+ }
40
+ return changed;
41
+ }
42
+ function compare(node) {
43
+ return (item) => {
44
+ const v = compareKey(item.key, node.key) ||
45
+ compareValue(!!item.end, !!node.end) ||
46
+ (item.end && compareKey(item.end, node.end)) ||
47
+ compareValue(item.limit, node.limit);
48
+ return v;
49
+ };
50
+ }
51
+ function compareValue(a, b) {
52
+ if (a === b)
53
+ return 0;
54
+ return a < b ? -1 : 1;
55
+ }
56
+ /*
57
+ We clone to ensure that the original query (passed as diff) never gets modified, even after successive adds.
58
+ */
59
+ function clone(node) {
60
+ const copy = { ...node };
61
+ if (node.children)
62
+ copy.children = node.children.map((child) => clone(child));
63
+ return copy;
64
+ }
@@ -5,7 +5,7 @@
5
5
  * @param {number | false} version
6
6
  * @returns any
7
7
  */
8
- export default function finalize(graph: any, query: any, version?: number | false): {
8
+ export default function finalize(graph: any, query: any, version?: number): {
9
9
  key: Uint8Array<ArrayBuffer>;
10
10
  end: Uint8Array<ArrayBuffer>;
11
11
  version: number;
@@ -0,0 +1,19 @@
1
+ import { MAX_KEY, MIN_KEY } from "../util.js";
2
+ import { merge, setVersion, slice } from "./index.js";
3
+ /**
4
+ *
5
+ * @param {any} graph
6
+ * @param {any} query
7
+ * @param {number | false} version
8
+ * @returns any
9
+ */
10
+ export default function finalize(graph, query, version = Date.now()) {
11
+ let result = [{ key: MIN_KEY, end: MAX_KEY, version: 0 }];
12
+ merge(result, graph);
13
+ if (query)
14
+ result = slice(result, query).known || [];
15
+ if (version !== false)
16
+ result = setVersion(result, version, true);
17
+ // console.log('Finalizing', result, '\n\n', query, '\n\n', graph);
18
+ return result;
19
+ }
@@ -1,4 +1 @@
1
- export default function getKnown(graph: any, version?: number): {
2
- key: any;
3
- version: number;
4
- }[];
1
+ export default function getKnown(graph: any, version?: number): any[];
@@ -0,0 +1,24 @@
1
+ /*
2
+ getKnown accepts a graph and returns a query for the knowledge
3
+ in that graph.
4
+ */
5
+ import { cmp } from "../util.js";
6
+ export default function getKnown(graph, version = 0) {
7
+ const query = [];
8
+ for (const { key, end, children } of graph) {
9
+ const node = { key, version };
10
+ if (end) {
11
+ if (cmp(end, key) !== 0)
12
+ node.end = end;
13
+ node.value = 1;
14
+ }
15
+ if (children) {
16
+ node.children = getKnown(children);
17
+ }
18
+ else {
19
+ node.value = 1;
20
+ }
21
+ query.push(node);
22
+ }
23
+ return query;
24
+ }
package/ops/index.d.ts ADDED
@@ -0,0 +1,9 @@
1
+ export { default as add } from './add.js';
2
+ export { default as finalize } from './finalize.js';
3
+ export { default as getKnown } from './getKnown.js';
4
+ export { default as merge } from './merge.js';
5
+ export * from './path.js';
6
+ export { default as setVersion } from './setVersion.js';
7
+ export { default as sieve } from './sieve.js';
8
+ export { default as slice } from './slice.js';
9
+ export * from './step.js';
package/ops/merge.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ export default function merge(current: any, changes: any): any;
2
+ export declare function insertRange(current: any, change: any, start?: number): number;
3
+ export declare function insertNode(current: any, change: any, start?: number): any;
package/ops/merge.js ADDED
@@ -0,0 +1,112 @@
1
+ import { findFirst, findLast, isBranch, isRange } from "../node/index.js";
2
+ import { cmp, MAX_KEY, MIN_KEY } from "../util.js";
3
+ import { keyAfter, keyBefore } from "./step.js";
4
+ export default function merge(current, changes) {
5
+ let index = 0;
6
+ if (typeof changes === 'undefined')
7
+ return current;
8
+ for (const change of changes) {
9
+ index = isRange(change)
10
+ ? insertRange(current, change, index)
11
+ : insertNode(current, change, index);
12
+ }
13
+ return current;
14
+ }
15
+ export function insertRange(current, change, start = 0) {
16
+ const { key, end } = change;
17
+ const keyIx = findFirst(current, key, start);
18
+ const endIx = findLast(current, end, keyIx);
19
+ // If current contains nodes that are newer than this range, keep them.
20
+ // We do this by merging them back into insertions first.
21
+ const insertions = [change];
22
+ for (let i = keyIx; i < endIx; i++) {
23
+ const node = current[i];
24
+ if (isRange(node)) {
25
+ insertions.push(...mergeRanges(insertions.pop(), node));
26
+ }
27
+ else {
28
+ insertNode(insertions, node, insertions.length - 1);
29
+ }
30
+ }
31
+ current.splice(keyIx, endIx - keyIx, ...insertions);
32
+ return keyIx + insertions.length - 1;
33
+ }
34
+ function mergeRanges(base, node) {
35
+ // assertVersion(node, base.version);
36
+ if (node.version < base.version)
37
+ [node, base] = [base, node];
38
+ return [
39
+ cmp(base.key, node.key) < 0 && { ...base, end: keyBefore(node.key) },
40
+ node,
41
+ cmp(base.end, node.end) > 0 && { ...base, key: keyAfter(node.end) },
42
+ ].filter(Boolean);
43
+ }
44
+ export function insertNode(current, change, start = 0) {
45
+ if (!current)
46
+ throw new Error(`merge.insertNode: ${current}`);
47
+ const key = change.key;
48
+ const index = findFirst(current, key, start);
49
+ const node = current[index];
50
+ if (node && cmp(node.key, key) <= 0) {
51
+ // This change overlaps with something that exists.
52
+ return isRange(node)
53
+ ? insertNodeIntoRange(current, index, change)
54
+ : updateNode(current, index, change);
55
+ }
56
+ // This change does not overlap with any existing knowledge. Insert it
57
+ current.splice(index, 0, change);
58
+ return index + 1;
59
+ }
60
+ function insertNodeIntoRange(current, index, change) {
61
+ const key = change.key;
62
+ const range = current[index];
63
+ const newChange = getNewer(change, range);
64
+ if (!newChange)
65
+ return;
66
+ const insertions = [
67
+ cmp(range.key, key) < 0 && { ...range, end: keyBefore(key) },
68
+ newChange,
69
+ cmp(range.end, key) > 0 && { ...range, key: keyAfter(key) },
70
+ ].filter(Boolean);
71
+ current.splice(index, 1, ...insertions);
72
+ // Subtract 1 to keep the final range in consideration for future insertions.
73
+ return index + insertions.length - 1;
74
+ }
75
+ function updateNode(current, index, change) {
76
+ const node = current[index];
77
+ if (isBranch(change) && isBranch(node)) {
78
+ // Both are branches: Recursively merge children.
79
+ merge(node.children, change.children);
80
+ }
81
+ else if (isBranch(node)) {
82
+ // Current node is a branch but the change is a leaf; if the branch
83
+ // has newer children, ignore the change and keep only those children;
84
+ // Otherwise, discard the branch and keep the change.
85
+ const newNode = getNewer(node, change);
86
+ current[index] = newNode || change;
87
+ }
88
+ else {
89
+ // Current node is a leaf. Replace with the change if it is newer.
90
+ const newChange = getNewer(change, node);
91
+ if (newChange)
92
+ current[index] = newChange;
93
+ }
94
+ if (change.prefix)
95
+ current[index].prefix = true;
96
+ return index + 1;
97
+ }
98
+ function getNewer(node, base) {
99
+ const { version } = base;
100
+ if (isBranch(node)) {
101
+ const children = [{ key: MIN_KEY, end: MAX_KEY, version }];
102
+ merge(children, node.children);
103
+ return children.length === 1 ? null : { ...node, children };
104
+ }
105
+ // assertVersion(node, version);
106
+ return node.version >= version ? node : null;
107
+ }
108
+ // function assertVersion(node, version) {
109
+ // // if (node.version === version) {
110
+ // // throw Error('merge.version_collision ' + [node.key, version].join(' '));
111
+ // // }
112
+ // }
package/ops/path.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ export declare const IS_VAL: unique symbol;
2
+ export declare function wrapValue(value: any, path: any, version?: number): any;
3
+ export declare function wrap(children: any, path: any, version?: number, prefix?: boolean): any;
4
+ export declare function unwrap(tree: any, path: any): any;
5
+ export declare function getNodeValue(node: any): any;
6
+ export declare function remove(children: any, path: any): any;
package/ops/path.js ADDED
@@ -0,0 +1,91 @@
1
+ import { findFirst, isBranch, isRange } from "../node/index.js";
2
+ import { cmp } from "../util.js";
3
+ export const IS_VAL = Symbol('IS_VAL');
4
+ function makeNode(seg, props) {
5
+ if (ArrayBuffer.isView(seg))
6
+ return { key: seg, ...props };
7
+ return { ...seg, ...props };
8
+ }
9
+ export function wrapValue(value, path, version = 0) {
10
+ const node = makeNode(path[path.length - 1], { value, version });
11
+ return wrap([node], path.slice(0, -1), version);
12
+ }
13
+ export function wrap(children, path, version = 0, prefix = false) {
14
+ if (!Array.isArray(path))
15
+ throw Error(`wrap.path_not_array ${path}`);
16
+ if (!path.length)
17
+ return children;
18
+ let i = path.length - 1;
19
+ // If it is a plain value, make it a value node
20
+ if (!Array.isArray(children)) {
21
+ children = [makeNode(path[i--], { value: children, version })];
22
+ }
23
+ else {
24
+ if (!children.length)
25
+ return;
26
+ children = [makeNode(path[i--], { children, version })];
27
+ }
28
+ if (prefix)
29
+ children[0].prefix = true;
30
+ while (i >= 0)
31
+ children = [makeNode(path[i--], { children, version })];
32
+ return children;
33
+ }
34
+ export function unwrap(tree, path) {
35
+ if (!Array.isArray(path))
36
+ throw Error(`unwrap.path_not_array ${path}`);
37
+ let children = tree;
38
+ let node = { children };
39
+ for (let i = 0; i < path.length; i++) {
40
+ const key = path[i];
41
+ if (!ArrayBuffer.isView(key))
42
+ throw Error('unwrap.ranges_unsupported');
43
+ children = node.children;
44
+ if (!children)
45
+ return null; // This path does not exist.
46
+ node = children[findFirst(children, key)];
47
+ if (!node || cmp(node.key, key) > 0)
48
+ return undefined; // We lack knowledge.
49
+ if (isRange(node))
50
+ return null; // This is known to be null.
51
+ if (node.path)
52
+ return unwrap(tree, node.path.concat(path.slice(i + 1)));
53
+ }
54
+ return getNodeValue(node);
55
+ }
56
+ export function getNodeValue(node) {
57
+ if (node.children)
58
+ return node.children;
59
+ if (node.value && typeof node.value === 'object') {
60
+ node.value[IS_VAL] = true;
61
+ }
62
+ return node.value;
63
+ }
64
+ export function remove(children, path) {
65
+ if (!Array.isArray(path))
66
+ throw Error(`del.path_not_array ${path}`);
67
+ if (!children)
68
+ return null; // This path does not exist.
69
+ if (!path.length)
70
+ return []; // Remove everything.
71
+ const key = path[0];
72
+ const ix = findFirst(children, key);
73
+ const node = children[ix];
74
+ if (!node || cmp(node.key, key) > 0 || isRange(node))
75
+ return children;
76
+ // let filteredNode;
77
+ if (path.length === 1) {
78
+ // This is the final segment, delete the matching node from children.
79
+ return children.slice(0, ix).concat(children.slice(ix + 1));
80
+ }
81
+ if (!isBranch(node))
82
+ return children;
83
+ // Recurse into the next slice.
84
+ const filteredChildren = remove(node.children, path.slice(1));
85
+ if (filteredChildren === children)
86
+ return children;
87
+ const filteredNode = filteredChildren.length
88
+ ? { ...node, children: filteredChildren }
89
+ : [];
90
+ return children.slice(0, ix).concat(filteredNode, children.slice(ix + 1));
91
+ }
@@ -0,0 +1,29 @@
1
+ // import { isRange } from '../node/index.ts';
2
+ // import { keyAfter } from './step.ts';
3
+ export default function setVersion(graph, version, onlyIfZero = false) {
4
+ // mergeRanges(graph);
5
+ for (const node of graph) {
6
+ if (!(onlyIfZero && node.version))
7
+ node.version = version;
8
+ if (node.children)
9
+ setVersion(node.children, version, onlyIfZero);
10
+ }
11
+ return graph;
12
+ }
13
+ // function mergeRanges(graph) {
14
+ // for (let i = 0; i < graph.length; i++) {
15
+ // if (!isRange(graph[i])) continue;
16
+ // let j = i;
17
+ // do {
18
+ // j++;
19
+ // } while (isRange(graph[j]) && cmp(graph[j].key , keyAfter(graph[j - 1].end)) === 0);
20
+ // j = j - 1;
21
+ // if (j === i) continue;
22
+ // graph.splice(i, j - i + 1, {
23
+ // key: graph[i].key,
24
+ // end: graph[j].end,
25
+ // version: graph[i].version,
26
+ // });
27
+ // // i = j;
28
+ // }
29
+ // }
package/ops/sieve.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ export default function sieve(current: any, changes: any, result?: any[]): any[];
2
+ export declare function insertRange(current: any, change: any, result: any, start?: number): number;
3
+ export declare function insertNode(current: any, change: any, result: any, start?: number): any;