@nodes-dev/core 0.0.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 +33 -0
- package/dist/corpus.d.ts +61 -0
- package/dist/corpus.d.ts.map +1 -0
- package/dist/corpus.js +383 -0
- package/dist/corpus.js.map +1 -0
- package/dist/errors.d.ts +20 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +23 -0
- package/dist/errors.js.map +1 -0
- package/dist/frontmatter.d.ts +5 -0
- package/dist/frontmatter.d.ts.map +1 -0
- package/dist/frontmatter.js +103 -0
- package/dist/frontmatter.js.map +1 -0
- package/dist/ids.d.ts +11 -0
- package/dist/ids.d.ts.map +1 -0
- package/dist/ids.js +36 -0
- package/dist/ids.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/node.d.ts +106 -0
- package/dist/node.d.ts.map +1 -0
- package/dist/node.js +66 -0
- package/dist/node.js.map +1 -0
- package/dist/ranking.d.ts +7 -0
- package/dist/ranking.d.ts.map +1 -0
- package/dist/ranking.js +9 -0
- package/dist/ranking.js.map +1 -0
- package/dist/registry.d.ts +36 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +123 -0
- package/dist/registry.js.map +1 -0
- package/dist/relations.d.ts +30 -0
- package/dist/relations.d.ts.map +1 -0
- package/dist/relations.js +44 -0
- package/dist/relations.js.map +1 -0
- package/dist/search.d.ts +46 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +280 -0
- package/dist/search.js.map +1 -0
- package/dist/shapes.d.ts +86 -0
- package/dist/shapes.d.ts.map +1 -0
- package/dist/shapes.js +138 -0
- package/dist/shapes.js.map +1 -0
- package/dist/similarity.d.ts +68 -0
- package/dist/similarity.d.ts.map +1 -0
- package/dist/similarity.js +305 -0
- package/dist/similarity.js.map +1 -0
- package/dist/snapshot.d.ts +56 -0
- package/dist/snapshot.d.ts.map +1 -0
- package/dist/snapshot.js +252 -0
- package/dist/snapshot.js.map +1 -0
- package/dist/store.d.ts +15 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +44 -0
- package/dist/store.js.map +1 -0
- package/dist/structural-index.d.ts +72 -0
- package/dist/structural-index.d.ts.map +1 -0
- package/dist/structural-index.js +434 -0
- package/dist/structural-index.js.map +1 -0
- package/package.json +50 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { RefError } from "./errors.js";
|
|
3
|
+
export const RELATES_TO = "relatesTo";
|
|
4
|
+
export const RelationSchema = z.object({
|
|
5
|
+
source: z.string(),
|
|
6
|
+
predicate: z.string(),
|
|
7
|
+
target: z.string(),
|
|
8
|
+
directed: z.boolean().default(true),
|
|
9
|
+
weight: z.number().nullable().default(null),
|
|
10
|
+
attrs: z.record(z.unknown()).default({}),
|
|
11
|
+
});
|
|
12
|
+
// Low-level schema helpers. Like Python's `Relation(...)` / `Relation.from_serialized`, these may
|
|
13
|
+
// surface a raw ZodError on malformed input. The "never leak raw" contract lives in the boundary
|
|
14
|
+
// parsers (`makeNode`, `nodeFromMarkdown`, `membershipOf`), which catch and re-wrap as kernel errors.
|
|
15
|
+
export function fromSerialized(data, containerId) {
|
|
16
|
+
const { source, ...rest } = data;
|
|
17
|
+
return RelationSchema.parse({ source: source !== undefined ? source : containerId, ...rest });
|
|
18
|
+
}
|
|
19
|
+
export function toSerialized(rel, containerId) {
|
|
20
|
+
const out = {};
|
|
21
|
+
if (rel.source !== containerId)
|
|
22
|
+
out.source = rel.source;
|
|
23
|
+
out.predicate = rel.predicate;
|
|
24
|
+
out.target = rel.target;
|
|
25
|
+
if (rel.directed !== true)
|
|
26
|
+
out.directed = rel.directed;
|
|
27
|
+
if (rel.weight !== null)
|
|
28
|
+
out.weight = rel.weight;
|
|
29
|
+
if (Object.keys(rel.attrs).length > 0)
|
|
30
|
+
out.attrs = rel.attrs;
|
|
31
|
+
return out;
|
|
32
|
+
}
|
|
33
|
+
export function relatesTo(source, target) {
|
|
34
|
+
return RelationSchema.parse({ source, predicate: RELATES_TO, target });
|
|
35
|
+
}
|
|
36
|
+
export function tagToRelation(source, tag, aliasMap) {
|
|
37
|
+
const name = tag.replace(/^#+/, "");
|
|
38
|
+
const target = aliasMap[name] ?? aliasMap[name.toLowerCase()];
|
|
39
|
+
if (target === undefined) {
|
|
40
|
+
throw new RefError(`tag ${JSON.stringify(tag)} does not resolve to a known node`);
|
|
41
|
+
}
|
|
42
|
+
return relatesTo(source, target);
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=relations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relations.js","sourceRoot":"","sources":["../src/relations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,MAAM,CAAC,MAAM,UAAU,GAAG,WAAW,CAAC;AAEtC,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC;IACrC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;IAClB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;IACrB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;IAClB,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IACnC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IAC3C,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;CACzC,CAAC,CAAC;AAIH,kGAAkG;AAClG,iGAAiG;AACjG,sGAAsG;AACtG,MAAM,UAAU,cAAc,CAAC,IAA6B,EAAE,WAAmB;IAC/E,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC;IACjC,OAAO,cAAc,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;AAChG,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,GAAa,EAAE,WAAmB;IAC7D,MAAM,GAAG,GAA4B,EAAE,CAAC;IACxC,IAAI,GAAG,CAAC,MAAM,KAAK,WAAW;QAAE,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;IACxD,GAAG,CAAC,SAAS,GAAG,GAAG,CAAC,SAAS,CAAC;IAC9B,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;IACxB,IAAI,GAAG,CAAC,QAAQ,KAAK,IAAI;QAAE,GAAG,CAAC,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC;IACvD,IAAI,GAAG,CAAC,MAAM,KAAK,IAAI;QAAE,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;IACjD,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC;QAAE,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC;IAC7D,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,MAAc,EAAE,MAAc;IACtD,OAAO,cAAc,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC,CAAC;AACzE,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,MAAc,EAAE,GAAW,EAAE,QAAgC;IACzF,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACpC,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;IAC9D,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,MAAM,IAAI,QAAQ,CAAC,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;IACpF,CAAC;IACD,OAAO,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACnC,CAAC"}
|
package/dist/search.d.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { Node } from "./node.js";
|
|
2
|
+
/** Fixed English stop-word list (33 words), frozen by the tokenizer oracle. */
|
|
3
|
+
export declare const STOP_WORDS: ReadonlySet<string>;
|
|
4
|
+
/** Compare by Unicode code point. Array.from iterates by code point (surrogate-pair aware),
|
|
5
|
+
* so this is the explicit comparator the spec requires instead of default UTF-16 sort.
|
|
6
|
+
* Shared ordering contract: query terms (STANDARD §9.1) and check violations/findings (§8). */
|
|
7
|
+
export declare function compareCodepoints(a: string, b: string): number;
|
|
8
|
+
/** Sort by Unicode code-point order — mirrors Python's default string sort (which is
|
|
9
|
+
* already code-point order) and is the cross-language ordering contract. */
|
|
10
|
+
export declare function codepointSorted(values: Iterable<string>): string[];
|
|
11
|
+
/** NFC-normalize, lowercase, split into Unicode-alphanumeric runs, drop stop words.
|
|
12
|
+
* Document tokenization keeps duplicates; query-side dedup happens in SearchIndex.search. */
|
|
13
|
+
export declare function tokenize(text: string): string[];
|
|
14
|
+
export declare const K1 = 1.5;
|
|
15
|
+
export declare const B = 0.75;
|
|
16
|
+
export declare const TITLE_BOOST = 2;
|
|
17
|
+
export declare const BODY_BOOST = 1;
|
|
18
|
+
export interface SearchHit {
|
|
19
|
+
id: string;
|
|
20
|
+
uid: string;
|
|
21
|
+
score: number;
|
|
22
|
+
matchedTerms: string[];
|
|
23
|
+
}
|
|
24
|
+
export interface SearchSnapshot {
|
|
25
|
+
postings: Record<string, Record<string, [number, number]>>;
|
|
26
|
+
lengths: Record<string, [number, number]>;
|
|
27
|
+
idByUid: Record<string, string>;
|
|
28
|
+
}
|
|
29
|
+
/** In-memory inverted index over node title+body. Pure data; no file I/O. */
|
|
30
|
+
export declare class SearchIndex {
|
|
31
|
+
postings: Map<string, Map<string, [number, number]>>;
|
|
32
|
+
lengths: Map<string, [number, number]>;
|
|
33
|
+
idByUid: Map<string, string>;
|
|
34
|
+
totalTitle: number;
|
|
35
|
+
totalBody: number;
|
|
36
|
+
get n(): number;
|
|
37
|
+
static build(nodes: Iterable<Node>): SearchIndex;
|
|
38
|
+
private static counts;
|
|
39
|
+
upsert(node: Node): void;
|
|
40
|
+
remove(uid: string): void;
|
|
41
|
+
toDict(): SearchSnapshot;
|
|
42
|
+
static fromDict(d: unknown): SearchIndex;
|
|
43
|
+
search(query: string, limit?: number): SearchHit[];
|
|
44
|
+
private drop;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=search.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../src/search.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGtC,+EAA+E;AAC/E,eAAO,MAAM,UAAU,EAAE,WAAW,CAAC,MAAM,CAkCzC,CAAC;AAMH;;+FAE+F;AAC/F,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAU9D;AAED;4EAC4E;AAC5E,wBAAgB,eAAe,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE,CAElE;AAED;6FAC6F;AAC7F,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAI/C;AAED,eAAO,MAAM,EAAE,MAAM,CAAC;AACtB,eAAO,MAAM,CAAC,OAAO,CAAC;AACtB,eAAO,MAAM,WAAW,IAAM,CAAC;AAC/B,eAAO,MAAM,UAAU,IAAM,CAAC;AAE9B,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IAC3D,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC1C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED,6EAA6E;AAC7E,qBAAa,WAAW;IACtB,QAAQ,6CAAoD;IAC5D,OAAO,gCAAuC;IAC9C,OAAO,sBAA6B;IACpC,UAAU,SAAK;IACf,SAAS,SAAK;IAEd,IAAI,CAAC,IAAI,MAAM,CAEd;IAED,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,WAAW;IAWhD,OAAO,CAAC,MAAM,CAAC,MAAM;IAMrB,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;IAqBxB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIzB,MAAM,IAAI,cAAc;IAcxB,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,OAAO,GAAG,WAAW;IA+DxC,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,EAAE;IAsDlD,OAAO,CAAC,IAAI;CAcb"}
|
package/dist/search.js
ADDED
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import { CollisionError } from "./errors.js";
|
|
2
|
+
import { scoreKey } from "./ranking.js";
|
|
3
|
+
/** Fixed English stop-word list (33 words), frozen by the tokenizer oracle. */
|
|
4
|
+
export const STOP_WORDS = new Set([
|
|
5
|
+
"a",
|
|
6
|
+
"an",
|
|
7
|
+
"and",
|
|
8
|
+
"are",
|
|
9
|
+
"as",
|
|
10
|
+
"at",
|
|
11
|
+
"be",
|
|
12
|
+
"but",
|
|
13
|
+
"by",
|
|
14
|
+
"for",
|
|
15
|
+
"if",
|
|
16
|
+
"in",
|
|
17
|
+
"into",
|
|
18
|
+
"is",
|
|
19
|
+
"it",
|
|
20
|
+
"no",
|
|
21
|
+
"not",
|
|
22
|
+
"of",
|
|
23
|
+
"on",
|
|
24
|
+
"or",
|
|
25
|
+
"such",
|
|
26
|
+
"that",
|
|
27
|
+
"the",
|
|
28
|
+
"their",
|
|
29
|
+
"then",
|
|
30
|
+
"there",
|
|
31
|
+
"these",
|
|
32
|
+
"they",
|
|
33
|
+
"this",
|
|
34
|
+
"to",
|
|
35
|
+
"was",
|
|
36
|
+
"will",
|
|
37
|
+
"with",
|
|
38
|
+
]);
|
|
39
|
+
// Maximal runs of Unicode alphanumerics (\p{L} ∪ \p{N}); everything else separates.
|
|
40
|
+
// This is the parity twin of Python's re.findall(r"[^\W_]+", s).
|
|
41
|
+
const TOKEN_RE = /[\p{L}\p{N}]+/gu;
|
|
42
|
+
/** Compare by Unicode code point. Array.from iterates by code point (surrogate-pair aware),
|
|
43
|
+
* so this is the explicit comparator the spec requires instead of default UTF-16 sort.
|
|
44
|
+
* Shared ordering contract: query terms (STANDARD §9.1) and check violations/findings (§8). */
|
|
45
|
+
export function compareCodepoints(a, b) {
|
|
46
|
+
const ca = Array.from(a);
|
|
47
|
+
const cb = Array.from(b);
|
|
48
|
+
const len = Math.min(ca.length, cb.length);
|
|
49
|
+
for (let i = 0; i < len; i++) {
|
|
50
|
+
const x = ca[i].codePointAt(0);
|
|
51
|
+
const y = cb[i].codePointAt(0);
|
|
52
|
+
if (x !== y)
|
|
53
|
+
return x - y;
|
|
54
|
+
}
|
|
55
|
+
return ca.length - cb.length;
|
|
56
|
+
}
|
|
57
|
+
/** Sort by Unicode code-point order — mirrors Python's default string sort (which is
|
|
58
|
+
* already code-point order) and is the cross-language ordering contract. */
|
|
59
|
+
export function codepointSorted(values) {
|
|
60
|
+
return [...values].sort(compareCodepoints);
|
|
61
|
+
}
|
|
62
|
+
/** NFC-normalize, lowercase, split into Unicode-alphanumeric runs, drop stop words.
|
|
63
|
+
* Document tokenization keeps duplicates; query-side dedup happens in SearchIndex.search. */
|
|
64
|
+
export function tokenize(text) {
|
|
65
|
+
const normalized = text.normalize("NFC").toLowerCase();
|
|
66
|
+
const matches = normalized.match(TOKEN_RE) ?? [];
|
|
67
|
+
return matches.filter((tok) => !STOP_WORDS.has(tok));
|
|
68
|
+
}
|
|
69
|
+
export const K1 = 1.5;
|
|
70
|
+
export const B = 0.75;
|
|
71
|
+
export const TITLE_BOOST = 2.0;
|
|
72
|
+
export const BODY_BOOST = 1.0;
|
|
73
|
+
/** In-memory inverted index over node title+body. Pure data; no file I/O. */
|
|
74
|
+
export class SearchIndex {
|
|
75
|
+
postings = new Map(); // term -> uid -> [titleTf, bodyTf]
|
|
76
|
+
lengths = new Map(); // uid -> [titleLen, bodyLen]
|
|
77
|
+
idByUid = new Map();
|
|
78
|
+
totalTitle = 0;
|
|
79
|
+
totalBody = 0;
|
|
80
|
+
get n() {
|
|
81
|
+
return this.lengths.size;
|
|
82
|
+
}
|
|
83
|
+
static build(nodes) {
|
|
84
|
+
const idx = new SearchIndex();
|
|
85
|
+
for (const node of nodes) {
|
|
86
|
+
if (idx.lengths.has(node.uid)) {
|
|
87
|
+
throw new CollisionError(`duplicate uid ${JSON.stringify(node.uid)} in corpus`);
|
|
88
|
+
}
|
|
89
|
+
idx.upsert(node);
|
|
90
|
+
}
|
|
91
|
+
return idx;
|
|
92
|
+
}
|
|
93
|
+
static counts(tokens) {
|
|
94
|
+
const counts = new Map();
|
|
95
|
+
for (const tok of tokens)
|
|
96
|
+
counts.set(tok, (counts.get(tok) ?? 0) + 1);
|
|
97
|
+
return counts;
|
|
98
|
+
}
|
|
99
|
+
upsert(node) {
|
|
100
|
+
if (this.lengths.has(node.uid))
|
|
101
|
+
this.drop(node.uid);
|
|
102
|
+
const titleTokens = tokenize(node.title);
|
|
103
|
+
const bodyTokens = tokenize(node.body);
|
|
104
|
+
const titleCounts = SearchIndex.counts(titleTokens);
|
|
105
|
+
const bodyCounts = SearchIndex.counts(bodyTokens);
|
|
106
|
+
const terms = new Set([...titleCounts.keys(), ...bodyCounts.keys()]);
|
|
107
|
+
for (const term of terms) {
|
|
108
|
+
let docs = this.postings.get(term);
|
|
109
|
+
if (docs === undefined) {
|
|
110
|
+
docs = new Map();
|
|
111
|
+
this.postings.set(term, docs);
|
|
112
|
+
}
|
|
113
|
+
docs.set(node.uid, [titleCounts.get(term) ?? 0, bodyCounts.get(term) ?? 0]);
|
|
114
|
+
}
|
|
115
|
+
this.lengths.set(node.uid, [titleTokens.length, bodyTokens.length]);
|
|
116
|
+
this.idByUid.set(node.uid, node.id);
|
|
117
|
+
this.totalTitle += titleTokens.length;
|
|
118
|
+
this.totalBody += bodyTokens.length;
|
|
119
|
+
}
|
|
120
|
+
remove(uid) {
|
|
121
|
+
this.drop(uid);
|
|
122
|
+
}
|
|
123
|
+
toDict() {
|
|
124
|
+
const postings = {};
|
|
125
|
+
for (const [term, docs] of this.postings) {
|
|
126
|
+
const bucket = {};
|
|
127
|
+
for (const [uid, tf] of docs)
|
|
128
|
+
bucket[uid] = [tf[0], tf[1]];
|
|
129
|
+
postings[term] = bucket;
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
postings,
|
|
133
|
+
lengths: Object.fromEntries([...this.lengths].map(([uid, l]) => [uid, [l[0], l[1]]])),
|
|
134
|
+
idByUid: Object.fromEntries(this.idByUid),
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
static fromDict(d) {
|
|
138
|
+
if (typeof d !== "object" || d === null)
|
|
139
|
+
throw new Error("search snapshot: document must be an object");
|
|
140
|
+
const raw = d;
|
|
141
|
+
if (typeof raw.lengths !== "object" || raw.lengths === null) {
|
|
142
|
+
throw new Error("search snapshot: lengths must be an object");
|
|
143
|
+
}
|
|
144
|
+
if (typeof raw.idByUid !== "object" || raw.idByUid === null) {
|
|
145
|
+
throw new Error("search snapshot: idByUid must be an object");
|
|
146
|
+
}
|
|
147
|
+
if (typeof raw.postings !== "object" || raw.postings === null) {
|
|
148
|
+
throw new Error("search snapshot: postings must be an object");
|
|
149
|
+
}
|
|
150
|
+
const lengths = new Map();
|
|
151
|
+
for (const [uid, v] of Object.entries(raw.lengths)) {
|
|
152
|
+
lengths.set(uid, nonNegativeIntPair(v, `search snapshot: length for uid ${JSON.stringify(uid)}`));
|
|
153
|
+
}
|
|
154
|
+
const idByUid = new Map();
|
|
155
|
+
for (const [uid, id] of Object.entries(raw.idByUid)) {
|
|
156
|
+
if (typeof id !== "string")
|
|
157
|
+
throw new Error("search snapshot: idByUid must map uids to string ids");
|
|
158
|
+
idByUid.set(uid, id);
|
|
159
|
+
}
|
|
160
|
+
if (lengths.size !== idByUid.size || [...lengths.keys()].some((uid) => !idByUid.has(uid))) {
|
|
161
|
+
throw new Error("search snapshot: lengths/idByUid uid sets differ");
|
|
162
|
+
}
|
|
163
|
+
const postings = new Map();
|
|
164
|
+
for (const [term, docs] of Object.entries(raw.postings)) {
|
|
165
|
+
if (typeof docs !== "object" || docs === null)
|
|
166
|
+
throw new Error("search snapshot: postings bucket must be an object");
|
|
167
|
+
if (Object.keys(docs).length === 0)
|
|
168
|
+
throw new Error(`search snapshot: postings bucket for term ${JSON.stringify(term)} must not be empty`);
|
|
169
|
+
const bucket = new Map();
|
|
170
|
+
for (const [uid, tf] of Object.entries(docs)) {
|
|
171
|
+
if (!lengths.has(uid)) {
|
|
172
|
+
throw new Error(`search snapshot: posting uid ${JSON.stringify(uid)} absent from lengths`);
|
|
173
|
+
}
|
|
174
|
+
const tfPair = nonNegativeIntPair(tf, `search snapshot: posting tf for term ${JSON.stringify(term)} uid ${JSON.stringify(uid)}`);
|
|
175
|
+
if (tfPair[0] === 0 && tfPair[1] === 0) {
|
|
176
|
+
throw new Error(`search snapshot: posting tf for term ${JSON.stringify(term)} uid ${JSON.stringify(uid)} must not be all zero`);
|
|
177
|
+
}
|
|
178
|
+
const [titleLen, bodyLen] = lengths.get(uid);
|
|
179
|
+
if (tfPair[0] > titleLen || tfPair[1] > bodyLen) {
|
|
180
|
+
throw new Error(`search snapshot: posting tf for term ${JSON.stringify(term)} uid ${JSON.stringify(uid)} exceeds field length`);
|
|
181
|
+
}
|
|
182
|
+
bucket.set(uid, tfPair);
|
|
183
|
+
}
|
|
184
|
+
postings.set(term, bucket);
|
|
185
|
+
}
|
|
186
|
+
const idx = new SearchIndex();
|
|
187
|
+
idx.postings = postings;
|
|
188
|
+
idx.lengths = lengths;
|
|
189
|
+
idx.idByUid = idByUid;
|
|
190
|
+
idx.totalTitle = [...lengths.values()].reduce((s, l) => s + l[0], 0);
|
|
191
|
+
idx.totalBody = [...lengths.values()].reduce((s, l) => s + l[1], 0);
|
|
192
|
+
return idx;
|
|
193
|
+
}
|
|
194
|
+
search(query, limit) {
|
|
195
|
+
if (limit !== undefined && (!Number.isInteger(limit) || limit <= 0)) {
|
|
196
|
+
throw new RangeError(`limit must be a positive integer or undefined, got ${JSON.stringify(limit)}`);
|
|
197
|
+
}
|
|
198
|
+
const terms = codepointSorted(new Set(tokenize(query))); // dedup + code-point order
|
|
199
|
+
if (terms.length === 0)
|
|
200
|
+
return [];
|
|
201
|
+
const n = this.n;
|
|
202
|
+
const avgTitle = n > 0 ? this.totalTitle / n : 0;
|
|
203
|
+
const avgBody = n > 0 ? this.totalBody / n : 0;
|
|
204
|
+
const scores = new Map();
|
|
205
|
+
const matched = new Map();
|
|
206
|
+
for (const term of terms) {
|
|
207
|
+
const docs = this.postings.get(term);
|
|
208
|
+
if (docs === undefined)
|
|
209
|
+
continue;
|
|
210
|
+
const df = docs.size;
|
|
211
|
+
const idf = Math.log(1 + (n - df + 0.5) / (df + 0.5));
|
|
212
|
+
for (const [uid, [titleTf, bodyTf]] of docs) {
|
|
213
|
+
const [titleLen, bodyLen] = this.lengths.get(uid);
|
|
214
|
+
let tfPrime = 0;
|
|
215
|
+
if (titleTf > 0) {
|
|
216
|
+
const denom = avgTitle > 0 ? 1 - B + B * (titleLen / avgTitle) : 1;
|
|
217
|
+
tfPrime += (TITLE_BOOST * titleTf) / denom;
|
|
218
|
+
}
|
|
219
|
+
if (bodyTf > 0) {
|
|
220
|
+
const denom = avgBody > 0 ? 1 - B + B * (bodyLen / avgBody) : 1;
|
|
221
|
+
tfPrime += (BODY_BOOST * bodyTf) / denom;
|
|
222
|
+
}
|
|
223
|
+
scores.set(uid, (scores.get(uid) ?? 0) + (idf * (K1 + 1) * tfPrime) / (K1 + tfPrime));
|
|
224
|
+
const m = matched.get(uid);
|
|
225
|
+
if (m === undefined)
|
|
226
|
+
matched.set(uid, [term]);
|
|
227
|
+
else
|
|
228
|
+
m.push(term);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
const hits = [];
|
|
232
|
+
for (const [uid, score] of scores) {
|
|
233
|
+
hits.push({
|
|
234
|
+
id: this.idByUid.get(uid),
|
|
235
|
+
uid,
|
|
236
|
+
score,
|
|
237
|
+
matchedTerms: codepointSorted(matched.get(uid)),
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
hits.sort((a, b) => {
|
|
241
|
+
const ka = scoreKey(a.score);
|
|
242
|
+
const kb = scoreKey(b.score);
|
|
243
|
+
if (ka !== kb)
|
|
244
|
+
return kb - ka; // scoreKey descending
|
|
245
|
+
return a.id < b.id ? -1 : a.id > b.id ? 1 : 0; // id ascending
|
|
246
|
+
});
|
|
247
|
+
return limit === undefined ? hits : hits.slice(0, limit);
|
|
248
|
+
}
|
|
249
|
+
drop(uid) {
|
|
250
|
+
const lengths = this.lengths.get(uid);
|
|
251
|
+
if (lengths === undefined)
|
|
252
|
+
return;
|
|
253
|
+
this.totalTitle -= lengths[0];
|
|
254
|
+
this.totalBody -= lengths[1];
|
|
255
|
+
this.lengths.delete(uid);
|
|
256
|
+
this.idByUid.delete(uid);
|
|
257
|
+
for (const [term, docs] of [...this.postings]) {
|
|
258
|
+
if (docs.has(uid)) {
|
|
259
|
+
docs.delete(uid);
|
|
260
|
+
if (docs.size === 0)
|
|
261
|
+
this.postings.delete(term);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
function nonNegativeIntPair(value, label) {
|
|
267
|
+
if (!Array.isArray(value) || value.length !== 2)
|
|
268
|
+
throw new Error(`${label} must be a 2-item array`);
|
|
269
|
+
const [first, second] = value;
|
|
270
|
+
if (typeof first !== "number" ||
|
|
271
|
+
typeof second !== "number" ||
|
|
272
|
+
!Number.isInteger(first) ||
|
|
273
|
+
!Number.isInteger(second) ||
|
|
274
|
+
first < 0 ||
|
|
275
|
+
second < 0) {
|
|
276
|
+
throw new Error(`${label} must contain non-negative integers`);
|
|
277
|
+
}
|
|
278
|
+
return [first, second];
|
|
279
|
+
}
|
|
280
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../src/search.ts"],"names":[],"mappings":"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"}
|
package/dist/shapes.d.ts
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { Node } from "./node.js";
|
|
3
|
+
import type { Registry } from "./registry.js";
|
|
4
|
+
export declare const MEMBERSHIP = "membership";
|
|
5
|
+
export declare const EDGES = "edges";
|
|
6
|
+
export declare const ORDER = "order";
|
|
7
|
+
export declare const KEYS = "keys";
|
|
8
|
+
export declare const MembershipSchema: z.ZodObject<{
|
|
9
|
+
members: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
10
|
+
}, "strip", z.ZodTypeAny, {
|
|
11
|
+
members: string[];
|
|
12
|
+
}, {
|
|
13
|
+
members?: string[] | undefined;
|
|
14
|
+
}>;
|
|
15
|
+
export declare const EdgesSchema: z.ZodObject<{
|
|
16
|
+
edges: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
17
|
+
source: z.ZodString;
|
|
18
|
+
predicate: z.ZodString;
|
|
19
|
+
target: z.ZodString;
|
|
20
|
+
directed: z.ZodDefault<z.ZodBoolean>;
|
|
21
|
+
weight: z.ZodDefault<z.ZodNullable<z.ZodNumber>>;
|
|
22
|
+
attrs: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
23
|
+
}, "strip", z.ZodTypeAny, {
|
|
24
|
+
source: string;
|
|
25
|
+
predicate: string;
|
|
26
|
+
target: string;
|
|
27
|
+
directed: boolean;
|
|
28
|
+
weight: number | null;
|
|
29
|
+
attrs: Record<string, unknown>;
|
|
30
|
+
}, {
|
|
31
|
+
source: string;
|
|
32
|
+
predicate: string;
|
|
33
|
+
target: string;
|
|
34
|
+
directed?: boolean | undefined;
|
|
35
|
+
weight?: number | null | undefined;
|
|
36
|
+
attrs?: Record<string, unknown> | undefined;
|
|
37
|
+
}>, "many">>;
|
|
38
|
+
}, "strip", z.ZodTypeAny, {
|
|
39
|
+
edges: {
|
|
40
|
+
source: string;
|
|
41
|
+
predicate: string;
|
|
42
|
+
target: string;
|
|
43
|
+
directed: boolean;
|
|
44
|
+
weight: number | null;
|
|
45
|
+
attrs: Record<string, unknown>;
|
|
46
|
+
}[];
|
|
47
|
+
}, {
|
|
48
|
+
edges?: {
|
|
49
|
+
source: string;
|
|
50
|
+
predicate: string;
|
|
51
|
+
target: string;
|
|
52
|
+
directed?: boolean | undefined;
|
|
53
|
+
weight?: number | null | undefined;
|
|
54
|
+
attrs?: Record<string, unknown> | undefined;
|
|
55
|
+
}[] | undefined;
|
|
56
|
+
}>;
|
|
57
|
+
export declare const OrderSchema: z.ZodObject<{
|
|
58
|
+
order: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
59
|
+
}, "strip", z.ZodTypeAny, {
|
|
60
|
+
order: string[];
|
|
61
|
+
}, {
|
|
62
|
+
order?: string[] | undefined;
|
|
63
|
+
}>;
|
|
64
|
+
export declare const KeysSchema: z.ZodObject<{
|
|
65
|
+
keys: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
66
|
+
}, "strip", z.ZodTypeAny, {
|
|
67
|
+
keys: Record<string, string>;
|
|
68
|
+
}, {
|
|
69
|
+
keys?: Record<string, string> | undefined;
|
|
70
|
+
}>;
|
|
71
|
+
export type Membership = z.infer<typeof MembershipSchema>;
|
|
72
|
+
export type Edges = z.infer<typeof EdgesSchema>;
|
|
73
|
+
export type Order = z.infer<typeof OrderSchema>;
|
|
74
|
+
export type Keys = z.infer<typeof KeysSchema>;
|
|
75
|
+
export declare function membershipOf(node: Node): Membership;
|
|
76
|
+
export declare function edgesOf(node: Node): Edges;
|
|
77
|
+
export declare function orderOf(node: Node): Order;
|
|
78
|
+
export declare function keysOf(node: Node): Keys;
|
|
79
|
+
export declare function requireUniqueMembers(node: Node): void;
|
|
80
|
+
export declare function requireEdgeEndpointsAreMembers(node: Node): void;
|
|
81
|
+
export declare function requireOrderIsPermutation(node: Node): void;
|
|
82
|
+
export declare function requireKeyValuesAreMembers(node: Node): void;
|
|
83
|
+
export declare function requireAcyclic(node: Node): void;
|
|
84
|
+
export declare function requireSingleParent(node: Node): void;
|
|
85
|
+
export declare function registerBuiltinShapes(reg: Registry): void;
|
|
86
|
+
//# sourceMappingURL=shapes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shapes.d.ts","sourceRoot":"","sources":["../src/shapes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,KAAK,EAAY,QAAQ,EAAa,MAAM,eAAe,CAAC;AAGnE,eAAO,MAAM,UAAU,eAAe,CAAC;AACvC,eAAO,MAAM,KAAK,UAAU,CAAC;AAC7B,eAAO,MAAM,KAAK,UAAU,CAAC;AAC7B,eAAO,MAAM,IAAI,SAAS,CAAC;AAE3B,eAAO,MAAM,gBAAgB;;;;;;EAAyD,CAAC;AACvF,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAA2D,CAAC;AACpF,eAAO,MAAM,WAAW;;;;;;EAAuD,CAAC;AAChF,eAAO,MAAM,UAAU;;;;;;EAAuD,CAAC;AAE/E,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC1D,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAChD,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAChD,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAc9C,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,GAAG,UAAU,CAEnD;AACD,wBAAgB,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,KAAK,CAEzC;AACD,wBAAgB,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,KAAK,CAEzC;AACD,wBAAgB,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAEvC;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAKrD;AAED,wBAAgB,8BAA8B,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAO/D;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAS1D;AAED,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAO3D;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAkB/C;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAYpD;AAED,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,QAAQ,GAAG,IAAI,CAkCzD"}
|
package/dist/shapes.js
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { FacetError, InvariantError } from "./errors.js";
|
|
3
|
+
import { RelationSchema } from "./relations.js";
|
|
4
|
+
export const MEMBERSHIP = "membership";
|
|
5
|
+
export const EDGES = "edges";
|
|
6
|
+
export const ORDER = "order";
|
|
7
|
+
export const KEYS = "keys";
|
|
8
|
+
export const MembershipSchema = z.object({ members: z.array(z.string()).default([]) });
|
|
9
|
+
export const EdgesSchema = z.object({ edges: z.array(RelationSchema).default([]) });
|
|
10
|
+
export const OrderSchema = z.object({ order: z.array(z.string()).default([]) });
|
|
11
|
+
export const KeysSchema = z.object({ keys: z.record(z.string()).default({}) });
|
|
12
|
+
function load(node, name, schema) {
|
|
13
|
+
const raw = node.facets[name];
|
|
14
|
+
if (raw === undefined)
|
|
15
|
+
throw new FacetError(`${node.id}: missing '${name}' facet`);
|
|
16
|
+
const result = schema.safeParse(raw);
|
|
17
|
+
if (!result.success) {
|
|
18
|
+
throw new FacetError(`${node.id}: invalid '${name}' facet: ${result.error.issues.map((i) => i.message).join("; ")}`);
|
|
19
|
+
}
|
|
20
|
+
return result.data;
|
|
21
|
+
}
|
|
22
|
+
export function membershipOf(node) {
|
|
23
|
+
return load(node, MEMBERSHIP, MembershipSchema);
|
|
24
|
+
}
|
|
25
|
+
export function edgesOf(node) {
|
|
26
|
+
return load(node, EDGES, EdgesSchema);
|
|
27
|
+
}
|
|
28
|
+
export function orderOf(node) {
|
|
29
|
+
return load(node, ORDER, OrderSchema);
|
|
30
|
+
}
|
|
31
|
+
export function keysOf(node) {
|
|
32
|
+
return load(node, KEYS, KeysSchema);
|
|
33
|
+
}
|
|
34
|
+
export function requireUniqueMembers(node) {
|
|
35
|
+
const members = membershipOf(node).members;
|
|
36
|
+
if (members.length !== new Set(members).size) {
|
|
37
|
+
throw new InvariantError(`${node.id}: members must be unique`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
export function requireEdgeEndpointsAreMembers(node) {
|
|
41
|
+
const members = new Set(membershipOf(node).members);
|
|
42
|
+
for (const e of edgesOf(node).edges) {
|
|
43
|
+
if (!members.has(e.source) || !members.has(e.target)) {
|
|
44
|
+
throw new InvariantError(`${node.id}: edge endpoints must be members`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
export function requireOrderIsPermutation(node) {
|
|
49
|
+
const members = membershipOf(node).members;
|
|
50
|
+
const order = orderOf(node).order;
|
|
51
|
+
const memberSet = new Set(members);
|
|
52
|
+
const orderSet = new Set(order);
|
|
53
|
+
const sameSet = memberSet.size === orderSet.size && [...memberSet].every((m) => orderSet.has(m));
|
|
54
|
+
if (order.length !== members.length || !sameSet) {
|
|
55
|
+
throw new InvariantError(`${node.id}: order must be a permutation of members`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
export function requireKeyValuesAreMembers(node) {
|
|
59
|
+
const members = new Set(membershipOf(node).members);
|
|
60
|
+
for (const value of Object.values(keysOf(node).keys)) {
|
|
61
|
+
if (!members.has(value)) {
|
|
62
|
+
throw new InvariantError(`${node.id}: key values must be members`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
export function requireAcyclic(node) {
|
|
67
|
+
const adj = new Map();
|
|
68
|
+
for (const e of edgesOf(node).edges) {
|
|
69
|
+
const list = adj.get(e.source) ?? [];
|
|
70
|
+
list.push(e.target);
|
|
71
|
+
adj.set(e.source, list);
|
|
72
|
+
}
|
|
73
|
+
const visiting = new Set();
|
|
74
|
+
const done = new Set();
|
|
75
|
+
const walk = (n) => {
|
|
76
|
+
if (visiting.has(n))
|
|
77
|
+
throw new InvariantError(`${node.id}: cycle detected at ${n}`);
|
|
78
|
+
if (done.has(n))
|
|
79
|
+
return;
|
|
80
|
+
visiting.add(n);
|
|
81
|
+
for (const nxt of adj.get(n) ?? [])
|
|
82
|
+
walk(nxt);
|
|
83
|
+
visiting.delete(n);
|
|
84
|
+
done.add(n);
|
|
85
|
+
};
|
|
86
|
+
for (const start of [...adj.keys()])
|
|
87
|
+
walk(start);
|
|
88
|
+
}
|
|
89
|
+
export function requireSingleParent(node) {
|
|
90
|
+
const parents = new Map();
|
|
91
|
+
for (const e of edgesOf(node).edges) {
|
|
92
|
+
parents.set(e.target, (parents.get(e.target) ?? 0) + 1);
|
|
93
|
+
}
|
|
94
|
+
const over = [...parents.entries()]
|
|
95
|
+
.filter(([, c]) => c > 1)
|
|
96
|
+
.map(([t]) => t)
|
|
97
|
+
.sort();
|
|
98
|
+
if (over.length > 0) {
|
|
99
|
+
throw new InvariantError(`${node.id}: nodes with multiple parents: ${JSON.stringify(over)}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
export function registerBuiltinShapes(reg) {
|
|
103
|
+
const shapes = [
|
|
104
|
+
{ name: "set", requiredFacets: new Set([MEMBERSHIP]), invariants: [requireUniqueMembers] },
|
|
105
|
+
{
|
|
106
|
+
name: "list",
|
|
107
|
+
requiredFacets: new Set([MEMBERSHIP, ORDER]),
|
|
108
|
+
invariants: [requireUniqueMembers, requireOrderIsPermutation],
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
name: "dict",
|
|
112
|
+
requiredFacets: new Set([MEMBERSHIP, KEYS]),
|
|
113
|
+
invariants: [requireUniqueMembers, requireKeyValuesAreMembers],
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
name: "graph",
|
|
117
|
+
requiredFacets: new Set([MEMBERSHIP, EDGES]),
|
|
118
|
+
invariants: [requireUniqueMembers, requireEdgeEndpointsAreMembers],
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
name: "dag",
|
|
122
|
+
requiredFacets: new Set([MEMBERSHIP, EDGES]),
|
|
123
|
+
invariants: [requireUniqueMembers, requireEdgeEndpointsAreMembers, requireAcyclic],
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
name: "tree",
|
|
127
|
+
requiredFacets: new Set([MEMBERSHIP, EDGES]),
|
|
128
|
+
invariants: [requireUniqueMembers, requireEdgeEndpointsAreMembers, requireAcyclic, requireSingleParent],
|
|
129
|
+
},
|
|
130
|
+
];
|
|
131
|
+
for (const shape of shapes)
|
|
132
|
+
reg.registerShape(shape);
|
|
133
|
+
for (const name of ["set", "list", "dict", "graph", "dag", "tree"]) {
|
|
134
|
+
const spec = { name, shape: name };
|
|
135
|
+
reg.register(spec);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=shapes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shapes.js","sourceRoot":"","sources":["../src/shapes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAGzD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEhD,MAAM,CAAC,MAAM,UAAU,GAAG,YAAY,CAAC;AACvC,MAAM,CAAC,MAAM,KAAK,GAAG,OAAO,CAAC;AAC7B,MAAM,CAAC,MAAM,KAAK,GAAG,OAAO,CAAC;AAC7B,MAAM,CAAC,MAAM,IAAI,GAAG,MAAM,CAAC;AAE3B,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AACvF,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AACpF,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AAChF,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AAO/E,SAAS,IAAI,CAAyB,IAAU,EAAE,IAAY,EAAE,MAAS;IACvE,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC9B,IAAI,GAAG,KAAK,SAAS;QAAE,MAAM,IAAI,UAAU,CAAC,GAAG,IAAI,CAAC,EAAE,cAAc,IAAI,SAAS,CAAC,CAAC;IACnF,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IACrC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,IAAI,UAAU,CAClB,GAAG,IAAI,CAAC,EAAE,cAAc,IAAI,YAAY,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC/F,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC,IAAmB,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAU;IACrC,OAAO,IAAI,CAAC,IAAI,EAAE,UAAU,EAAE,gBAAgB,CAAC,CAAC;AAClD,CAAC;AACD,MAAM,UAAU,OAAO,CAAC,IAAU;IAChC,OAAO,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC;AACxC,CAAC;AACD,MAAM,UAAU,OAAO,CAAC,IAAU;IAChC,OAAO,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC;AACxC,CAAC;AACD,MAAM,UAAU,MAAM,CAAC,IAAU;IAC/B,OAAO,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,IAAU;IAC7C,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC;IAC3C,IAAI,OAAO,CAAC,MAAM,KAAK,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;QAC7C,MAAM,IAAI,cAAc,CAAC,GAAG,IAAI,CAAC,EAAE,0BAA0B,CAAC,CAAC;IACjE,CAAC;AACH,CAAC;AAED,MAAM,UAAU,8BAA8B,CAAC,IAAU;IACvD,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC;IACpD,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC;QACpC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;YACrD,MAAM,IAAI,cAAc,CAAC,GAAG,IAAI,CAAC,EAAE,kCAAkC,CAAC,CAAC;QACzE,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,IAAU;IAClD,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC;IAC3C,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC;IAClC,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;IACnC,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;IAChC,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI,IAAI,CAAC,GAAG,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACjG,IAAI,KAAK,CAAC,MAAM,KAAK,OAAO,CAAC,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QAChD,MAAM,IAAI,cAAc,CAAC,GAAG,IAAI,CAAC,EAAE,0CAA0C,CAAC,CAAC;IACjF,CAAC;AACH,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,IAAU;IACnD,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC;IACpD,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;QACrD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YACxB,MAAM,IAAI,cAAc,CAAC,GAAG,IAAI,CAAC,EAAE,8BAA8B,CAAC,CAAC;QACrE,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,IAAU;IACvC,MAAM,GAAG,GAAG,IAAI,GAAG,EAAoB,CAAC;IACxC,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC;QACpC,MAAM,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QACrC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QACpB,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC1B,CAAC;IACD,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IACnC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,IAAI,GAAG,CAAC,CAAS,EAAQ,EAAE;QAC/B,IAAI,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;YAAE,MAAM,IAAI,cAAc,CAAC,GAAG,IAAI,CAAC,EAAE,uBAAuB,CAAC,EAAE,CAAC,CAAC;QACpF,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;YAAE,OAAO;QACxB,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAChB,KAAK,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE;YAAE,IAAI,CAAC,GAAG,CAAC,CAAC;QAC9C,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACnB,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACd,CAAC,CAAC;IACF,KAAK,MAAM,KAAK,IAAI,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;QAAE,IAAI,CAAC,KAAK,CAAC,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,IAAU;IAC5C,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC1C,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC;QACpC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1D,CAAC;IACD,MAAM,IAAI,GAAG,CAAC,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;SAChC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;SACxB,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;SACf,IAAI,EAAE,CAAC;IACV,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpB,MAAM,IAAI,cAAc,CAAC,GAAG,IAAI,CAAC,EAAE,kCAAkC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC/F,CAAC;AACH,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,GAAa;IACjD,MAAM,MAAM,GAAgB;QAC1B,EAAE,IAAI,EAAE,KAAK,EAAE,cAAc,EAAE,IAAI,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,oBAAoB,CAAC,EAAE;QAC1F;YACE,IAAI,EAAE,MAAM;YACZ,cAAc,EAAE,IAAI,GAAG,CAAC,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;YAC5C,UAAU,EAAE,CAAC,oBAAoB,EAAE,yBAAyB,CAAC;SAC9D;QACD;YACE,IAAI,EAAE,MAAM;YACZ,cAAc,EAAE,IAAI,GAAG,CAAC,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;YAC3C,UAAU,EAAE,CAAC,oBAAoB,EAAE,0BAA0B,CAAC;SAC/D;QACD;YACE,IAAI,EAAE,OAAO;YACb,cAAc,EAAE,IAAI,GAAG,CAAC,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;YAC5C,UAAU,EAAE,CAAC,oBAAoB,EAAE,8BAA8B,CAAC;SACnE;QACD;YACE,IAAI,EAAE,KAAK;YACX,cAAc,EAAE,IAAI,GAAG,CAAC,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;YAC5C,UAAU,EAAE,CAAC,oBAAoB,EAAE,8BAA8B,EAAE,cAAc,CAAC;SACnF;QACD;YACE,IAAI,EAAE,MAAM;YACZ,cAAc,EAAE,IAAI,GAAG,CAAC,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;YAC5C,UAAU,EAAE,CAAC,oBAAoB,EAAE,8BAA8B,EAAE,cAAc,EAAE,mBAAmB,CAAC;SACxG;KACF,CAAC;IACF,KAAK,MAAM,KAAK,IAAI,MAAM;QAAE,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IACrD,KAAK,MAAM,IAAI,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,EAAE,CAAC;QACnE,MAAM,IAAI,GAAa,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QAC7C,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACrB,CAAC;AACH,CAAC"}
|