@kgdiff/core 0.0.0-stage → 0.1.0
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.
- package/LICENSE +21 -0
- package/README.md +69 -2
- package/dist/canonical.d.ts +73 -0
- package/dist/canonical.d.ts.map +1 -0
- package/dist/canonical.js +246 -0
- package/dist/canonical.js.map +1 -0
- package/dist/classify.d.ts +19 -0
- package/dist/classify.d.ts.map +1 -0
- package/dist/classify.js +250 -0
- package/dist/classify.js.map +1 -0
- package/dist/delta.d.ts +52 -0
- package/dist/delta.d.ts.map +1 -0
- package/dist/delta.js +750 -0
- package/dist/delta.js.map +1 -0
- package/dist/diff-index.d.ts +7 -0
- package/dist/diff-index.d.ts.map +1 -0
- package/dist/diff-index.js +52 -0
- package/dist/diff-index.js.map +1 -0
- package/dist/diff.d.ts +13 -0
- package/dist/diff.d.ts.map +1 -0
- package/dist/diff.js +147 -0
- package/dist/diff.js.map +1 -0
- package/dist/edges.d.ts +3 -0
- package/dist/edges.d.ts.map +1 -0
- package/dist/edges.js +336 -0
- package/dist/edges.js.map +1 -0
- package/dist/errors.d.ts +9 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +12 -0
- package/dist/errors.js.map +1 -0
- package/dist/graph-json.d.ts +28 -0
- package/dist/graph-json.d.ts.map +1 -0
- package/dist/graph-json.js +132 -0
- package/dist/graph-json.js.map +1 -0
- package/dist/hunks.d.ts +16 -0
- package/dist/hunks.d.ts.map +1 -0
- package/dist/hunks.js +284 -0
- package/dist/hunks.js.map +1 -0
- package/dist/i18n.d.ts +14 -0
- package/dist/i18n.d.ts.map +1 -0
- package/dist/i18n.js +622 -0
- package/dist/i18n.js.map +1 -0
- package/dist/index.d.ts +93 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +128 -0
- package/dist/index.js.map +1 -0
- package/dist/json.d.ts +15 -0
- package/dist/json.d.ts.map +1 -0
- package/dist/json.js +284 -0
- package/dist/json.js.map +1 -0
- package/dist/match.d.ts +49 -0
- package/dist/match.d.ts.map +1 -0
- package/dist/match.js +475 -0
- package/dist/match.js.map +1 -0
- package/dist/merge-split.d.ts +57 -0
- package/dist/merge-split.d.ts.map +1 -0
- package/dist/merge-split.js +445 -0
- package/dist/merge-split.js.map +1 -0
- package/dist/model.d.ts +70 -0
- package/dist/model.d.ts.map +1 -0
- package/dist/model.js +23 -0
- package/dist/model.js.map +1 -0
- package/dist/normalize.d.ts +20 -0
- package/dist/normalize.d.ts.map +1 -0
- package/dist/normalize.js +531 -0
- package/dist/normalize.js.map +1 -0
- package/dist/options.d.ts +16 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +100 -0
- package/dist/options.js.map +1 -0
- package/dist/order.d.ts +17 -0
- package/dist/order.d.ts.map +1 -0
- package/dist/order.js +334 -0
- package/dist/order.js.map +1 -0
- package/dist/stats.d.ts +7 -0
- package/dist/stats.d.ts.map +1 -0
- package/dist/stats.js +44 -0
- package/dist/stats.js.map +1 -0
- package/dist/text.d.ts +67 -0
- package/dist/text.d.ts.map +1 -0
- package/dist/text.js +346 -0
- package/dist/text.js.map +1 -0
- package/dist/types.d.ts +629 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +20 -0
- package/dist/types.js.map +1 -0
- package/dist/util.d.ts +28 -0
- package/dist/util.d.ts.map +1 -0
- package/dist/util.js +86 -0
- package/dist/util.js.map +1 -0
- package/package.json +46 -3
- package/src/canonical.ts +261 -0
- package/src/classify.ts +278 -0
- package/src/delta.ts +843 -0
- package/src/diff-index.ts +59 -0
- package/src/diff.ts +173 -0
- package/src/edges.ts +373 -0
- package/src/errors.ts +13 -0
- package/src/graph-json.ts +130 -0
- package/src/hunks.ts +296 -0
- package/src/i18n.ts +781 -0
- package/src/index.ts +169 -0
- package/src/json.ts +306 -0
- package/src/match.ts +551 -0
- package/src/merge-split.ts +527 -0
- package/src/model.ts +106 -0
- package/src/normalize.ts +616 -0
- package/src/options.ts +122 -0
- package/src/order.ts +359 -0
- package/src/stats.ts +64 -0
- package/src/text.ts +377 -0
- package/src/types.ts +674 -0
- package/src/util.ts +93 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 iiwish and kgdiff contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,70 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @kgdiff/core
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The semantic diff engine behind [kgdiff](../../README.md). It matches nodes across two versions
|
|
4
|
+
of a knowledge graph, classifies what changed (rename, rekey, merge, split, hierarchy move,
|
|
5
|
+
retarget, …), groups the changes into reviewable hunks and emits an invertible delta.
|
|
6
|
+
Deterministic, zero dependencies, and it runs unchanged in browsers, Node, Deno, Bun and workers.
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
pnpm add @kgdiff/core
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
ESM only. Node.js ≥ 22 or any evergreen browser.
|
|
15
|
+
|
|
16
|
+
## Quick start
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
import { applyDelta, diff, formatHunk, hashGraph, invertDelta } from '@kgdiff/core';
|
|
20
|
+
|
|
21
|
+
const v1 = {
|
|
22
|
+
nodes: [
|
|
23
|
+
{ id: 'org', label: 'Organization' },
|
|
24
|
+
{ id: 'company', label: 'Company' },
|
|
25
|
+
{ id: 'ngo', label: 'NGO' },
|
|
26
|
+
],
|
|
27
|
+
edges: [
|
|
28
|
+
{ source: 'company', target: 'org', predicate: 'subClassOf' },
|
|
29
|
+
{ source: 'ngo', target: 'org', predicate: 'subClassOf' },
|
|
30
|
+
],
|
|
31
|
+
};
|
|
32
|
+
const v2 = {
|
|
33
|
+
nodes: [
|
|
34
|
+
{ id: 'org', label: 'Organisation' },
|
|
35
|
+
{ id: 'company', label: 'Company' },
|
|
36
|
+
{ id: 'startup', label: 'Startup' },
|
|
37
|
+
],
|
|
38
|
+
edges: [
|
|
39
|
+
{ source: 'company', target: 'org', predicate: 'subClassOf' },
|
|
40
|
+
{ source: 'startup', target: 'company', predicate: 'subClassOf' },
|
|
41
|
+
],
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const result = diff(v1, v2);
|
|
45
|
+
for (const hunk of result.hunks) console.log(formatHunk(hunk, result).title);
|
|
46
|
+
// Removed “NGO” and 1 relation
|
|
47
|
+
// Renamed “Organization” → “Organisation”
|
|
48
|
+
// Added “Startup” and 1 relation
|
|
49
|
+
|
|
50
|
+
result.stats.nodes; // { added: 1, removed: 1, modified: 1, unchanged: 1 }
|
|
51
|
+
|
|
52
|
+
// The delta is invertible: undoing it gives the first version back.
|
|
53
|
+
const undone = applyDelta(result.after, invertDelta(result.delta));
|
|
54
|
+
hashGraph(undone) === hashGraph(result.before); // true
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
- Graph files (RDF, OBO, JSON graph formats): parse them with [`@kgdiff/formats`](../formats).
|
|
58
|
+
- Ids that mean nothing across versions, such as two LLM extraction runs: match by label and
|
|
59
|
+
neighbourhood with `diff(a, b, { match: { strategy: 'similarity' } })`.
|
|
60
|
+
- `formatHunk(hunk, result, 'zh-CN')` gives Chinese titles.
|
|
61
|
+
|
|
62
|
+
## Learn more
|
|
63
|
+
|
|
64
|
+
- [Algorithms](../../docs/algorithms.md): normalization, matching, classification, hunks, delta.
|
|
65
|
+
- [Delta format](../../docs/delta-format.md): the JSON patch format and its guarantees.
|
|
66
|
+
- [Architecture](../../docs/architecture.md): how the kgdiff packages fit together.
|
|
67
|
+
|
|
68
|
+
## License
|
|
69
|
+
|
|
70
|
+
[MIT](../../LICENSE)
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical values: key-order-insensitive equality, canonical JSON, structural edge
|
|
3
|
+
* keys and the cyrb53 hash. Everything here is allocation-conscious because it sits
|
|
4
|
+
* on the hot path of `normalize` and `diff`.
|
|
5
|
+
*/
|
|
6
|
+
import type { Attrs, AttrValue } from './types.js';
|
|
7
|
+
/** `JSON.stringify(s)` for a string, with a fast path for the common case. */
|
|
8
|
+
export declare function jsonString(s: string): string;
|
|
9
|
+
/**
|
|
10
|
+
* Structural edge key: exactly `JSON.stringify([source, predicate, target])`
|
|
11
|
+
* (docs/algorithms.md §1), built without the intermediate array.
|
|
12
|
+
*/
|
|
13
|
+
export declare function tripleKey(source: string, predicate: string, target: string): string;
|
|
14
|
+
/** True when a structural key carries a parallel-edge suffix (`#2`, `#3`…). */
|
|
15
|
+
export declare function hasParallelSuffix(key: string): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Splits a structural key into its triple part and its parallel-edge suffix (`#2`, `#3`…).
|
|
18
|
+
* Structural keys always end with `]` before the suffix, so the last `#` after the last
|
|
19
|
+
* `]` starts the suffix.
|
|
20
|
+
*/
|
|
21
|
+
export declare function splitStructuralKey(key: string): {
|
|
22
|
+
readonly base: string;
|
|
23
|
+
readonly suffix: string;
|
|
24
|
+
};
|
|
25
|
+
/** Deep, key-order-insensitive equality of JSON values (canonical JSON equality). */
|
|
26
|
+
export declare function attrValueEquals(a: AttrValue | undefined, b: AttrValue | undefined): boolean;
|
|
27
|
+
/** A new, empty attribute map. Write it with `setAttr`. */
|
|
28
|
+
export declare function emptyAttrMap(): Record<string, AttrValue>;
|
|
29
|
+
/** Sets an own data property — also for the key `__proto__`, which `=` would not create. */
|
|
30
|
+
export declare function setAttr(attrs: Record<string, AttrValue>, key: string, value: AttrValue): void;
|
|
31
|
+
/** The own value of `key`, or undefined — never an inherited member such as `constructor`. */
|
|
32
|
+
export declare function ownAttr(attrs: Attrs, key: string): AttrValue | undefined;
|
|
33
|
+
/**
|
|
34
|
+
* Equality of two attribute maps, ignoring key order, keys whose value is `undefined`
|
|
35
|
+
* and the keys in `ignore`.
|
|
36
|
+
*/
|
|
37
|
+
export declare function attrsEqual(a: Attrs, b: Attrs, ignore?: ReadonlySet<string>): boolean;
|
|
38
|
+
/** Sorted own keys of an attribute map whose value is defined. */
|
|
39
|
+
export declare function attrKeys(attrs: Attrs): string[];
|
|
40
|
+
/** True when the map has no defined value. */
|
|
41
|
+
export declare function isEmptyAttrs(attrs: Attrs): boolean;
|
|
42
|
+
/** Deep copy with object keys sorted and `undefined` members dropped. */
|
|
43
|
+
export declare function canonicalize(value: AttrValue): AttrValue;
|
|
44
|
+
/** `canonicalize` for an attribute map (`__proto__` stays an own key). */
|
|
45
|
+
export declare function canonicalAttrs(attrs: Attrs): Attrs;
|
|
46
|
+
/** Canonical JSON of a JSON value: object keys sorted, arrays in order. */
|
|
47
|
+
export declare function canonicalJSON(value: AttrValue): string;
|
|
48
|
+
/**
|
|
49
|
+
* Streaming cyrb53 (bryc, public domain): a fast, well-mixed, non-cryptographic 53-bit
|
|
50
|
+
* hash over UTF-16 code units. Feeding strings one after another hashes their
|
|
51
|
+
* concatenation, so nothing has to be built in memory.
|
|
52
|
+
*/
|
|
53
|
+
export declare class Cyrb53 {
|
|
54
|
+
private readonly seed;
|
|
55
|
+
private h1;
|
|
56
|
+
private h2;
|
|
57
|
+
constructor(seed?: number);
|
|
58
|
+
reset(): this;
|
|
59
|
+
/** Feeds one UTF-16 code unit (used for unambiguous framing such as lengths and tags). */
|
|
60
|
+
code(unit: number): this;
|
|
61
|
+
update(text: string): this;
|
|
62
|
+
/** Length-prefixed string: makes a sequence of strings injective. */
|
|
63
|
+
string(text: string): this;
|
|
64
|
+
/** Tagged, length-prefixed, key-sorted encoding of a JSON value. */
|
|
65
|
+
value(value: AttrValue | undefined): this;
|
|
66
|
+
/** Both finalized 32-bit halves (64 bits of state) without resetting. */
|
|
67
|
+
digestPair(): [number, number];
|
|
68
|
+
/** The 53-bit cyrb53 digest. */
|
|
69
|
+
digest(): number;
|
|
70
|
+
}
|
|
71
|
+
/** One-shot cyrb53 of a string. */
|
|
72
|
+
export declare function cyrb53(text: string, seed?: number): number;
|
|
73
|
+
//# sourceMappingURL=canonical.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canonical.d.ts","sourceRoot":"","sources":["../src/canonical.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAanD,8EAA8E;AAC9E,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE5C;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAEnF;AAED,+EAA+E;AAC/E,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG;IAC/C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,CAIA;AAQD,qFAAqF;AACrF,wBAAgB,eAAe,CAAC,CAAC,EAAE,SAAS,GAAG,SAAS,EAAE,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,OAAO,CAa3F;AAOD,2DAA2D;AAC3D,wBAAgB,YAAY,IAAI,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAExD;AAED,4FAA4F;AAC5F,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,IAAI,CAW7F;AAED,8FAA8F;AAC9F,wBAAgB,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAExE;AAOD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,OAAO,CAcpF;AAED,kEAAkE;AAClE,wBAAgB,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,EAAE,CAE/C;AAED,8CAA8C;AAC9C,wBAAgB,YAAY,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAGlD;AAED,yEAAyE;AACzE,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,GAAG,SAAS,CAIxD;AAED,0EAA0E;AAC1E,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,CAIlD;AAED,2EAA2E;AAC3E,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,CAEtD;AAID;;;;GAIG;AACH,qBAAa,MAAM;IAIL,OAAO,CAAC,QAAQ,CAAC,IAAI;IAHjC,OAAO,CAAC,EAAE,CAAK;IACf,OAAO,CAAC,EAAE,CAAK;IAEf,YAA6B,IAAI,SAAI,EAEpC;IAED,KAAK,IAAI,IAAI,CAIZ;IAED,0FAA0F;IAC1F,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAIvB;IAED,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAWzB;IAED,qEAAqE;IACrE,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAIzB;IAED,oEAAoE;IACpE,KAAK,CAAC,KAAK,EAAE,SAAS,GAAG,SAAS,GAAG,IAAI,CAgCxC;IAED,yEAAyE;IACzE,UAAU,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAQ7B;IAED,gCAAgC;IAChC,MAAM,IAAI,MAAM,CAGf;CACF;AAED,mCAAmC;AACnC,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,SAAI,GAAG,MAAM,CAErD"}
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
// ─── JSON strings and structural keys ────────────────────────────────────────
|
|
2
|
+
/** True when `JSON.stringify(s)` would escape something (quotes, backslash, control, surrogates). */
|
|
3
|
+
function needsEscape(s) {
|
|
4
|
+
for (let i = 0; i < s.length; i++) {
|
|
5
|
+
const c = s.charCodeAt(i);
|
|
6
|
+
if (c < 0x20 || c === 0x22 || c === 0x5c || (c >= 0xd800 && c <= 0xdfff))
|
|
7
|
+
return true;
|
|
8
|
+
}
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
/** `JSON.stringify(s)` for a string, with a fast path for the common case. */
|
|
12
|
+
export function jsonString(s) {
|
|
13
|
+
return needsEscape(s) ? JSON.stringify(s) : `"${s}"`;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Structural edge key: exactly `JSON.stringify([source, predicate, target])`
|
|
17
|
+
* (docs/algorithms.md §1), built without the intermediate array.
|
|
18
|
+
*/
|
|
19
|
+
export function tripleKey(source, predicate, target) {
|
|
20
|
+
return `[${jsonString(source)},${jsonString(predicate)},${jsonString(target)}]`;
|
|
21
|
+
}
|
|
22
|
+
/** True when a structural key carries a parallel-edge suffix (`#2`, `#3`…). */
|
|
23
|
+
export function hasParallelSuffix(key) {
|
|
24
|
+
return key.charCodeAt(key.length - 1) !== 0x5d;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Splits a structural key into its triple part and its parallel-edge suffix (`#2`, `#3`…).
|
|
28
|
+
* Structural keys always end with `]` before the suffix, so the last `#` after the last
|
|
29
|
+
* `]` starts the suffix.
|
|
30
|
+
*/
|
|
31
|
+
export function splitStructuralKey(key) {
|
|
32
|
+
if (key.charCodeAt(key.length - 1) === 0x5d)
|
|
33
|
+
return { base: key, suffix: '' };
|
|
34
|
+
const at = key.lastIndexOf('#');
|
|
35
|
+
return at < 0 ? { base: key, suffix: '' } : { base: key.slice(0, at), suffix: key.slice(at) };
|
|
36
|
+
}
|
|
37
|
+
// ─── Attribute values ────────────────────────────────────────────────────────
|
|
38
|
+
function isArrayValue(value) {
|
|
39
|
+
return Array.isArray(value);
|
|
40
|
+
}
|
|
41
|
+
/** Deep, key-order-insensitive equality of JSON values (canonical JSON equality). */
|
|
42
|
+
export function attrValueEquals(a, b) {
|
|
43
|
+
if (a === b)
|
|
44
|
+
return true;
|
|
45
|
+
if (a === undefined || b === undefined || a === null || b === null)
|
|
46
|
+
return false;
|
|
47
|
+
if (typeof a !== 'object' || typeof b !== 'object') {
|
|
48
|
+
return typeof a === 'number' && typeof b === 'number' && Number.isNaN(a) && Number.isNaN(b);
|
|
49
|
+
}
|
|
50
|
+
if (isArrayValue(a)) {
|
|
51
|
+
if (!isArrayValue(b) || a.length !== b.length)
|
|
52
|
+
return false;
|
|
53
|
+
for (let i = 0; i < a.length; i++)
|
|
54
|
+
if (!attrValueEquals(a[i], b[i]))
|
|
55
|
+
return false;
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
if (isArrayValue(b))
|
|
59
|
+
return false;
|
|
60
|
+
return attrsEqual(a, b);
|
|
61
|
+
}
|
|
62
|
+
// Attribute maps come from user data: keys such as `__proto__` or `constructor` are ordinary
|
|
63
|
+
// data. Maps are written through `setAttr` (so `__proto__` becomes an own key, never the
|
|
64
|
+
// prototype) and every read goes through `ownAttr` (so inherited members are never mistaken
|
|
65
|
+
// for data). Plain objects are kept rather than null-prototype ones, which V8 stores slowly.
|
|
66
|
+
/** A new, empty attribute map. Write it with `setAttr`. */
|
|
67
|
+
export function emptyAttrMap() {
|
|
68
|
+
return {};
|
|
69
|
+
}
|
|
70
|
+
/** Sets an own data property — also for the key `__proto__`, which `=` would not create. */
|
|
71
|
+
export function setAttr(attrs, key, value) {
|
|
72
|
+
if (key === '__proto__') {
|
|
73
|
+
Object.defineProperty(attrs, key, {
|
|
74
|
+
value,
|
|
75
|
+
enumerable: true,
|
|
76
|
+
writable: true,
|
|
77
|
+
configurable: true,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
attrs[key] = value;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/** The own value of `key`, or undefined — never an inherited member such as `constructor`. */
|
|
85
|
+
export function ownAttr(attrs, key) {
|
|
86
|
+
return Object.hasOwn(attrs, key) ? attrs[key] : undefined;
|
|
87
|
+
}
|
|
88
|
+
/** Own keys whose value is defined. */
|
|
89
|
+
function definedKeys(attrs) {
|
|
90
|
+
return Object.keys(attrs).filter((key) => attrs[key] !== undefined);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Equality of two attribute maps, ignoring key order, keys whose value is `undefined`
|
|
94
|
+
* and the keys in `ignore`.
|
|
95
|
+
*/
|
|
96
|
+
export function attrsEqual(a, b, ignore) {
|
|
97
|
+
if (a === b)
|
|
98
|
+
return true;
|
|
99
|
+
let countA = 0;
|
|
100
|
+
for (const key of Object.keys(a)) {
|
|
101
|
+
const value = a[key];
|
|
102
|
+
if (value === undefined || ignore?.has(key))
|
|
103
|
+
continue;
|
|
104
|
+
countA++;
|
|
105
|
+
if (!attrValueEquals(value, ownAttr(b, key)))
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
let countB = 0;
|
|
109
|
+
for (const key of Object.keys(b)) {
|
|
110
|
+
if (b[key] !== undefined && !ignore?.has(key))
|
|
111
|
+
countB++;
|
|
112
|
+
}
|
|
113
|
+
return countA === countB;
|
|
114
|
+
}
|
|
115
|
+
/** Sorted own keys of an attribute map whose value is defined. */
|
|
116
|
+
export function attrKeys(attrs) {
|
|
117
|
+
return definedKeys(attrs).sort();
|
|
118
|
+
}
|
|
119
|
+
/** True when the map has no defined value. */
|
|
120
|
+
export function isEmptyAttrs(attrs) {
|
|
121
|
+
for (const key of Object.keys(attrs))
|
|
122
|
+
if (attrs[key] !== undefined)
|
|
123
|
+
return false;
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
/** Deep copy with object keys sorted and `undefined` members dropped. */
|
|
127
|
+
export function canonicalize(value) {
|
|
128
|
+
if (value === null || typeof value !== 'object')
|
|
129
|
+
return value;
|
|
130
|
+
if (isArrayValue(value))
|
|
131
|
+
return value.map(canonicalize);
|
|
132
|
+
return canonicalAttrs(value);
|
|
133
|
+
}
|
|
134
|
+
/** `canonicalize` for an attribute map (`__proto__` stays an own key). */
|
|
135
|
+
export function canonicalAttrs(attrs) {
|
|
136
|
+
const out = emptyAttrMap();
|
|
137
|
+
for (const key of attrKeys(attrs))
|
|
138
|
+
setAttr(out, key, canonicalize(attrs[key]));
|
|
139
|
+
return out;
|
|
140
|
+
}
|
|
141
|
+
/** Canonical JSON of a JSON value: object keys sorted, arrays in order. */
|
|
142
|
+
export function canonicalJSON(value) {
|
|
143
|
+
return JSON.stringify(canonicalize(value));
|
|
144
|
+
}
|
|
145
|
+
// ─── cyrb53 ──────────────────────────────────────────────────────────────────
|
|
146
|
+
/**
|
|
147
|
+
* Streaming cyrb53 (bryc, public domain): a fast, well-mixed, non-cryptographic 53-bit
|
|
148
|
+
* hash over UTF-16 code units. Feeding strings one after another hashes their
|
|
149
|
+
* concatenation, so nothing has to be built in memory.
|
|
150
|
+
*/
|
|
151
|
+
export class Cyrb53 {
|
|
152
|
+
seed;
|
|
153
|
+
h1 = 0;
|
|
154
|
+
h2 = 0;
|
|
155
|
+
constructor(seed = 0) {
|
|
156
|
+
this.seed = seed;
|
|
157
|
+
this.reset();
|
|
158
|
+
}
|
|
159
|
+
reset() {
|
|
160
|
+
this.h1 = 0xdeadbeef ^ this.seed;
|
|
161
|
+
this.h2 = 0x41c6ce57 ^ this.seed;
|
|
162
|
+
return this;
|
|
163
|
+
}
|
|
164
|
+
/** Feeds one UTF-16 code unit (used for unambiguous framing such as lengths and tags). */
|
|
165
|
+
code(unit) {
|
|
166
|
+
this.h1 = Math.imul(this.h1 ^ unit, 2654435761);
|
|
167
|
+
this.h2 = Math.imul(this.h2 ^ unit, 1597334677);
|
|
168
|
+
return this;
|
|
169
|
+
}
|
|
170
|
+
update(text) {
|
|
171
|
+
let h1 = this.h1;
|
|
172
|
+
let h2 = this.h2;
|
|
173
|
+
for (let i = 0; i < text.length; i++) {
|
|
174
|
+
const unit = text.charCodeAt(i);
|
|
175
|
+
h1 = Math.imul(h1 ^ unit, 2654435761);
|
|
176
|
+
h2 = Math.imul(h2 ^ unit, 1597334677);
|
|
177
|
+
}
|
|
178
|
+
this.h1 = h1;
|
|
179
|
+
this.h2 = h2;
|
|
180
|
+
return this;
|
|
181
|
+
}
|
|
182
|
+
/** Length-prefixed string: makes a sequence of strings injective. */
|
|
183
|
+
string(text) {
|
|
184
|
+
return this.code(text.length & 0xffff)
|
|
185
|
+
.code(text.length >>> 16)
|
|
186
|
+
.update(text);
|
|
187
|
+
}
|
|
188
|
+
/** Tagged, length-prefixed, key-sorted encoding of a JSON value. */
|
|
189
|
+
value(value) {
|
|
190
|
+
if (value === undefined)
|
|
191
|
+
return this.code(0x75); // u
|
|
192
|
+
if (value === null)
|
|
193
|
+
return this.code(0x6e); // n
|
|
194
|
+
switch (typeof value) {
|
|
195
|
+
case 'boolean':
|
|
196
|
+
return this.code(value ? 0x74 : 0x66); // t / f
|
|
197
|
+
case 'number':
|
|
198
|
+
return this.code(0x64).string(String(value)); // d
|
|
199
|
+
case 'string':
|
|
200
|
+
return this.code(0x73).string(value); // s
|
|
201
|
+
default:
|
|
202
|
+
break;
|
|
203
|
+
}
|
|
204
|
+
if (isArrayValue(value)) {
|
|
205
|
+
this.code(0x61)
|
|
206
|
+
.code(value.length & 0xffff)
|
|
207
|
+
.code(value.length >>> 16); // a
|
|
208
|
+
for (const item of value)
|
|
209
|
+
this.value(item);
|
|
210
|
+
return this;
|
|
211
|
+
}
|
|
212
|
+
const own = Object.keys(value);
|
|
213
|
+
// Common cases first: no attributes, or one — no filtering or sorting needed.
|
|
214
|
+
if (own.length === 0)
|
|
215
|
+
return this.code(0x6f).code(0).code(0);
|
|
216
|
+
const keys = own.length === 1 && value[own[0]] !== undefined
|
|
217
|
+
? own
|
|
218
|
+
: attrKeys(value);
|
|
219
|
+
this.code(0x6f)
|
|
220
|
+
.code(keys.length & 0xffff)
|
|
221
|
+
.code(keys.length >>> 16); // o
|
|
222
|
+
for (const key of keys)
|
|
223
|
+
this.string(key).value(value[key]);
|
|
224
|
+
return this;
|
|
225
|
+
}
|
|
226
|
+
/** Both finalized 32-bit halves (64 bits of state) without resetting. */
|
|
227
|
+
digestPair() {
|
|
228
|
+
let h1 = this.h1;
|
|
229
|
+
let h2 = this.h2;
|
|
230
|
+
h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507);
|
|
231
|
+
h1 ^= Math.imul(h2 ^ (h2 >>> 13), 3266489909);
|
|
232
|
+
h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507);
|
|
233
|
+
h2 ^= Math.imul(h1 ^ (h1 >>> 13), 3266489909);
|
|
234
|
+
return [h1 >>> 0, h2 >>> 0];
|
|
235
|
+
}
|
|
236
|
+
/** The 53-bit cyrb53 digest. */
|
|
237
|
+
digest() {
|
|
238
|
+
const [h1, h2] = this.digestPair();
|
|
239
|
+
return 4294967296 * (2097151 & h2) + h1;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
/** One-shot cyrb53 of a string. */
|
|
243
|
+
export function cyrb53(text, seed = 0) {
|
|
244
|
+
return new Cyrb53(seed).update(text).digest();
|
|
245
|
+
}
|
|
246
|
+
//# sourceMappingURL=canonical.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canonical.js","sourceRoot":"","sources":["../src/canonical.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { NodeRecord, PipelineContext, RestructureIndex } from './model.js';
|
|
2
|
+
import type { AttrChange, Attrs, Id, KGraph, UnionId } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Union ids of before-version nodes that differ from their own id: matched nodes take the
|
|
5
|
+
* after id; unmatched nodes keep their id unless an after node already uses it, in which case
|
|
6
|
+
* `@before` is appended (repeatedly, in the pathological case that the result is taken too).
|
|
7
|
+
*/
|
|
8
|
+
export declare function assignUnionIds(before: KGraph, after: KGraph, beforeToAfter: ReadonlyMap<Id, Id>): Map<Id, UnionId>;
|
|
9
|
+
/** Attribute changes sorted by key, `ignore`d keys skipped, values canonicalized. */
|
|
10
|
+
export declare function attrChanges(before: Attrs, after: Attrs, ignore: ReadonlySet<string>): AttrChange[];
|
|
11
|
+
/**
|
|
12
|
+
* Builds one record per union node, sorted by union id, plus the restructure index the
|
|
13
|
+
* edge stage needs. A matched node is `modified` exactly when it has a facet.
|
|
14
|
+
*/
|
|
15
|
+
export declare function classifyNodes(ctx: PipelineContext): {
|
|
16
|
+
readonly nodes: NodeRecord[];
|
|
17
|
+
readonly index: RestructureIndex;
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=classify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"classify.d.ts","sourceRoot":"","sources":["../src/classify.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEhF,OAAO,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,EAAU,MAAM,EAAa,OAAO,EAAE,MAAM,YAAY,CAAC;AAG5F;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,WAAW,CAAC,EAAE,EAAE,EAAE,CAAC,GACjC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,CAsBlB;AAED,qFAAqF;AACrF,wBAAgB,WAAW,CACzB,MAAM,EAAE,KAAK,EACb,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,GAC1B,UAAU,EAAE,CAcd;AA8ID;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,eAAe,GAAG;IACnD,QAAQ,CAAC,KAAK,EAAE,UAAU,EAAE,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,gBAAgB,CAAC;CAClC,CAkEA"}
|