@dxos/datalog 0.0.1 → 0.13.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 +105 -0
- package/README.md +58 -1
- package/dist/lib/Ast.mjs +72 -0
- package/dist/lib/Ast.mjs.map +1 -0
- package/dist/lib/Builtin.mjs +37 -0
- package/dist/lib/Builtin.mjs.map +1 -0
- package/dist/lib/Checker.mjs +3 -0
- package/dist/lib/Engine.mjs +3 -0
- package/dist/lib/Parser.mjs +2 -0
- package/dist/lib/chunk-Checker.mjs +414 -0
- package/dist/lib/chunk-Checker.mjs.map +1 -0
- package/dist/lib/chunk-Engine.mjs +488 -0
- package/dist/lib/chunk-Engine.mjs.map +1 -0
- package/dist/lib/chunk-Parser.mjs +366 -0
- package/dist/lib/chunk-Parser.mjs.map +1 -0
- package/dist/lib/chunk-rolldown-runtime.mjs +13 -0
- package/dist/lib/index.mjs +6 -0
- package/dist/types/src/Ast.d.ts +81 -0
- package/dist/types/src/Ast.d.ts.map +1 -0
- package/dist/types/src/Builtin.d.ts +35 -0
- package/dist/types/src/Builtin.d.ts.map +1 -0
- package/dist/types/src/Checker.d.ts +61 -0
- package/dist/types/src/Checker.d.ts.map +1 -0
- package/dist/types/src/Checker.test.d.ts +2 -0
- package/dist/types/src/Checker.test.d.ts.map +1 -0
- package/dist/types/src/Engine.d.ts +55 -0
- package/dist/types/src/Engine.d.ts.map +1 -0
- package/dist/types/src/Engine.test.d.ts +2 -0
- package/dist/types/src/Engine.test.d.ts.map +1 -0
- package/dist/types/src/Engine.workerd.test.d.ts +2 -0
- package/dist/types/src/Engine.workerd.test.d.ts.map +1 -0
- package/dist/types/src/Parser.d.ts +43 -0
- package/dist/types/src/Parser.d.ts.map +1 -0
- package/dist/types/src/Parser.test.d.ts +2 -0
- package/dist/types/src/Parser.test.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +6 -0
- package/dist/types/src/index.d.ts.map +1 -0
- package/dist/types/src/internal/lexer.d.ts +46 -0
- package/dist/types/src/internal/lexer.d.ts.map +1 -0
- package/dist/types/src/internal/plan.d.ts +96 -0
- package/dist/types/src/internal/plan.d.ts.map +1 -0
- package/dist/types/src/internal/relation.d.ts +20 -0
- package/dist/types/src/internal/relation.d.ts.map +1 -0
- package/dist/types/src/internal/stratify.d.ts +28 -0
- package/dist/types/src/internal/stratify.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -0
- package/package.json +57 -5
- package/src/Ast.ts +136 -0
- package/src/Builtin.ts +73 -0
- package/src/Checker.test.ts +99 -0
- package/src/Checker.ts +156 -0
- package/src/Engine.test.ts +239 -0
- package/src/Engine.ts +614 -0
- package/src/Engine.workerd.test.ts +33 -0
- package/src/Parser.test.ts +84 -0
- package/src/Parser.ts +180 -0
- package/src/index.ts +9 -0
- package/src/internal/lexer.ts +154 -0
- package/src/internal/plan.ts +346 -0
- package/src/internal/relation.ts +95 -0
- package/src/internal/stratify.ts +114 -0
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
import { t as __exportAll } from "./chunk-rolldown-runtime.mjs";
|
|
2
|
+
import { formatRule, variablesOf } from "./Ast.mjs";
|
|
3
|
+
import { acceptsBinding } from "./Builtin.mjs";
|
|
4
|
+
import { BaseError } from "@dxos/errors";
|
|
5
|
+
//#region src/internal/plan.ts
|
|
6
|
+
/** Assigns a slot per named variable of a rule. */
|
|
7
|
+
var Slots = class {
|
|
8
|
+
#slots = /* @__PURE__ */ new Map();
|
|
9
|
+
get size() {
|
|
10
|
+
return this.#slots.size;
|
|
11
|
+
}
|
|
12
|
+
slot(name) {
|
|
13
|
+
let slot = this.#slots.get(name);
|
|
14
|
+
if (slot === void 0) {
|
|
15
|
+
slot = this.#slots.size;
|
|
16
|
+
this.#slots.set(name, slot);
|
|
17
|
+
}
|
|
18
|
+
return slot;
|
|
19
|
+
}
|
|
20
|
+
ref(term) {
|
|
21
|
+
if (term.type === "constant") return {
|
|
22
|
+
kind: "const",
|
|
23
|
+
value: term.value
|
|
24
|
+
};
|
|
25
|
+
return term.anonymous ? { kind: "wild" } : {
|
|
26
|
+
kind: "slot",
|
|
27
|
+
slot: this.slot(term.name)
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
var isBound = (term, bound) => term.type === "constant" || !term.anonymous && bound.has(term.name);
|
|
32
|
+
var unboundNames = (terms, bound) => terms.flatMap((term) => term.type === "variable" && !term.anonymous && !bound.has(term.name) ? [term.name] : []);
|
|
33
|
+
var variableNames = (literal) => {
|
|
34
|
+
switch (literal.type) {
|
|
35
|
+
case "atom": return literal.atom.terms.flatMap((term) => term.type === "variable" && !term.anonymous ? [term.name] : []);
|
|
36
|
+
case "comparison": return [literal.left, literal.right].flatMap((term) => term.type === "variable" && !term.anonymous ? [term.name] : []);
|
|
37
|
+
case "aggregate": return [...[literal.result, ...literal.target ? [literal.target] : []].flatMap((term) => term.type === "variable" && !term.anonymous ? [term.name] : []), ...literal.body.flatMap(variableNames)];
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Orders a rule body so every literal runs once its inputs are bound: filters as early as
|
|
42
|
+
* possible, then the relation scan with the most bound columns, then generating built-ins.
|
|
43
|
+
* @param outer Variables used outside the body (the head, or the enclosing rule of an aggregate).
|
|
44
|
+
* @param first Literal to scan first (the semi-naive delta).
|
|
45
|
+
*/
|
|
46
|
+
var planBody = (options) => {
|
|
47
|
+
const { body, builtins, slots, outer, first } = options;
|
|
48
|
+
const bound = new Set(options.bound ?? []);
|
|
49
|
+
const steps = [];
|
|
50
|
+
const remaining = new Set(body.keys());
|
|
51
|
+
const unresolved = [];
|
|
52
|
+
const scan = (index, literal) => {
|
|
53
|
+
const boundColumns = [];
|
|
54
|
+
const binds = [];
|
|
55
|
+
literal.atom.terms.forEach((term, column) => {
|
|
56
|
+
if (isBound(term, bound)) boundColumns.push({
|
|
57
|
+
column,
|
|
58
|
+
ref: slots.ref(term)
|
|
59
|
+
});
|
|
60
|
+
else if (term.type === "variable" && !term.anonymous) binds.push({
|
|
61
|
+
column,
|
|
62
|
+
slot: slots.slot(term.name)
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
for (const name of unboundNames(literal.atom.terms, bound)) bound.add(name);
|
|
66
|
+
steps.push({
|
|
67
|
+
kind: "scan",
|
|
68
|
+
literal: index,
|
|
69
|
+
relation: literal.atom.predicate,
|
|
70
|
+
bound: boundColumns,
|
|
71
|
+
binds
|
|
72
|
+
});
|
|
73
|
+
};
|
|
74
|
+
/** Variables any other literal or the outer scope uses, which an aggregate must correlate on. */
|
|
75
|
+
const correlated = (index, literal) => {
|
|
76
|
+
const elsewhere = /* @__PURE__ */ new Set([...outer, ...body.flatMap((other, at) => at === index ? [] : variableNames(other))]);
|
|
77
|
+
return [...new Set(literal.body.flatMap(variableNames))].filter((name) => elsewhere.has(name));
|
|
78
|
+
};
|
|
79
|
+
/** Schedules `index` if it is a filter (or, with `generate`, a generator) whose inputs are bound. */
|
|
80
|
+
const trySchedule = (index, generate) => {
|
|
81
|
+
const literal = body[index];
|
|
82
|
+
switch (literal.type) {
|
|
83
|
+
case "atom": {
|
|
84
|
+
const builtin = builtins.get(literal.atom.predicate);
|
|
85
|
+
if (!builtin) {
|
|
86
|
+
if (!literal.negated) return false;
|
|
87
|
+
if (unboundNames(literal.atom.terms, bound).length > 0) return false;
|
|
88
|
+
steps.push({
|
|
89
|
+
kind: "negation",
|
|
90
|
+
relation: literal.atom.predicate,
|
|
91
|
+
bound: literal.atom.terms.flatMap((term, column) => term.type === "variable" && term.anonymous ? [] : [{
|
|
92
|
+
column,
|
|
93
|
+
ref: slots.ref(term)
|
|
94
|
+
}])
|
|
95
|
+
});
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
const boundArgs = literal.atom.terms.map((term) => isBound(term, bound));
|
|
99
|
+
if (!boundArgs.every(Boolean) && (!generate || literal.negated || !acceptsBinding(builtin, boundArgs))) return false;
|
|
100
|
+
steps.push({
|
|
101
|
+
kind: "builtin",
|
|
102
|
+
builtin,
|
|
103
|
+
args: literal.atom.terms.map((term) => slots.ref(term)),
|
|
104
|
+
free: boundArgs.map((value) => !value),
|
|
105
|
+
negated: literal.negated
|
|
106
|
+
});
|
|
107
|
+
for (const name of unboundNames(literal.atom.terms, bound)) bound.add(name);
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
case "comparison": {
|
|
111
|
+
const left = isBound(literal.left, bound);
|
|
112
|
+
const right = isBound(literal.right, bound);
|
|
113
|
+
if (left && right) {
|
|
114
|
+
steps.push({
|
|
115
|
+
kind: "compare",
|
|
116
|
+
operator: literal.operator,
|
|
117
|
+
left: slots.ref(literal.left),
|
|
118
|
+
right: slots.ref(literal.right)
|
|
119
|
+
});
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
if (!generate || literal.operator !== "=" || left === right) return false;
|
|
123
|
+
const [target, source] = left ? [literal.right, literal.left] : [literal.left, literal.right];
|
|
124
|
+
if (target.type !== "variable" || target.anonymous) return false;
|
|
125
|
+
steps.push({
|
|
126
|
+
kind: "compare",
|
|
127
|
+
operator: "=",
|
|
128
|
+
left: slots.ref(literal.left),
|
|
129
|
+
right: slots.ref(literal.right),
|
|
130
|
+
assign: {
|
|
131
|
+
slot: slots.slot(target.name),
|
|
132
|
+
from: slots.ref(source)
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
bound.add(target.name);
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
case "aggregate": {
|
|
139
|
+
const correlation = correlated(index, literal);
|
|
140
|
+
if (correlation.some((name) => !bound.has(name))) return false;
|
|
141
|
+
const resultBound = isBound(literal.result, bound);
|
|
142
|
+
if (!resultBound && !generate) return false;
|
|
143
|
+
const inner = planBody({
|
|
144
|
+
body: literal.body,
|
|
145
|
+
builtins,
|
|
146
|
+
slots,
|
|
147
|
+
outer: new Set(correlation),
|
|
148
|
+
bound: new Set(correlation)
|
|
149
|
+
});
|
|
150
|
+
if (inner.unresolved.length > 0) {
|
|
151
|
+
unresolved.push(...inner.unresolved.map(({ reason }) => ({
|
|
152
|
+
literal: index,
|
|
153
|
+
reason
|
|
154
|
+
})));
|
|
155
|
+
return true;
|
|
156
|
+
}
|
|
157
|
+
if (literal.target && !isBound(literal.target, inner.bound)) {
|
|
158
|
+
unresolved.push({
|
|
159
|
+
literal: index,
|
|
160
|
+
reason: `aggregate target is not bound by the aggregate body`
|
|
161
|
+
});
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
const local = [...inner.bound].filter((name) => !correlation.includes(name)).map((name) => slots.slot(name));
|
|
165
|
+
steps.push({
|
|
166
|
+
kind: "aggregate",
|
|
167
|
+
function: literal.function,
|
|
168
|
+
steps: inner.steps,
|
|
169
|
+
local,
|
|
170
|
+
target: literal.target ? slots.ref(literal.target) : void 0,
|
|
171
|
+
result: slots.ref(literal.result),
|
|
172
|
+
assignResult: !resultBound
|
|
173
|
+
});
|
|
174
|
+
if (literal.result.type === "variable" && !literal.result.anonymous) bound.add(literal.result.name);
|
|
175
|
+
return true;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
if (first !== void 0) {
|
|
180
|
+
const literal = body[first];
|
|
181
|
+
if (literal.type === "atom" && !literal.negated && !builtins.has(literal.atom.predicate)) {
|
|
182
|
+
remaining.delete(first);
|
|
183
|
+
scan(first, literal);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
while (remaining.size > 0) {
|
|
187
|
+
let progressed = false;
|
|
188
|
+
for (const index of remaining) if (trySchedule(index, false)) {
|
|
189
|
+
remaining.delete(index);
|
|
190
|
+
progressed = true;
|
|
191
|
+
}
|
|
192
|
+
if (progressed) continue;
|
|
193
|
+
let best;
|
|
194
|
+
let bestBound = -1;
|
|
195
|
+
for (const index of remaining) {
|
|
196
|
+
const literal = body[index];
|
|
197
|
+
if (literal.type === "atom" && !literal.negated && !builtins.has(literal.atom.predicate)) {
|
|
198
|
+
const boundCount = literal.atom.terms.filter((term) => isBound(term, bound)).length;
|
|
199
|
+
if (boundCount > bestBound) {
|
|
200
|
+
best = index;
|
|
201
|
+
bestBound = boundCount;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
if (best !== void 0) {
|
|
206
|
+
const literal = body[best];
|
|
207
|
+
if (literal.type === "atom") {
|
|
208
|
+
remaining.delete(best);
|
|
209
|
+
scan(best, literal);
|
|
210
|
+
}
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
for (const index of remaining) if (trySchedule(index, true)) {
|
|
214
|
+
remaining.delete(index);
|
|
215
|
+
progressed = true;
|
|
216
|
+
break;
|
|
217
|
+
}
|
|
218
|
+
if (!progressed) break;
|
|
219
|
+
}
|
|
220
|
+
for (const index of remaining) unresolved.push({
|
|
221
|
+
literal: index,
|
|
222
|
+
reason: describeUnresolved(body[index], bound, builtins)
|
|
223
|
+
});
|
|
224
|
+
return {
|
|
225
|
+
steps,
|
|
226
|
+
unresolved,
|
|
227
|
+
bound
|
|
228
|
+
};
|
|
229
|
+
};
|
|
230
|
+
var describeUnresolved = (literal, bound, builtins) => {
|
|
231
|
+
switch (literal.type) {
|
|
232
|
+
case "atom": {
|
|
233
|
+
const names = unboundNames(literal.atom.terms, bound).join(", ");
|
|
234
|
+
if (builtins.has(literal.atom.predicate)) return literal.negated ? `negated built-in ${literal.atom.predicate} needs every argument bound (${names} unbound)` : `no binding mode of built-in ${literal.atom.predicate}/${literal.atom.terms.length} accepts ${names} unbound`;
|
|
235
|
+
return `variable ${names} under negation is not bound by a positive literal`;
|
|
236
|
+
}
|
|
237
|
+
case "comparison": return `variable ${unboundNames([literal.left, literal.right], bound).join(", ")} in comparison is not bound`;
|
|
238
|
+
case "aggregate": return `aggregate depends on unbound variables`;
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
//#endregion
|
|
242
|
+
//#region src/internal/stratify.ts
|
|
243
|
+
/** Relations a literal reads; negation and aggregation read them non-monotonically. */
|
|
244
|
+
var dependencies = (literal, builtins) => {
|
|
245
|
+
switch (literal.type) {
|
|
246
|
+
case "atom": return builtins.has(literal.atom.predicate) ? [] : [{
|
|
247
|
+
predicate: literal.atom.predicate,
|
|
248
|
+
negative: literal.negated
|
|
249
|
+
}];
|
|
250
|
+
case "comparison": return [];
|
|
251
|
+
case "aggregate": return literal.body.flatMap((inner) => dependencies(inner, builtins).map(({ predicate }) => ({
|
|
252
|
+
predicate,
|
|
253
|
+
negative: true
|
|
254
|
+
})));
|
|
255
|
+
}
|
|
256
|
+
};
|
|
257
|
+
/**
|
|
258
|
+
* Splits rules into strata: one per strongly connected component of the predicate graph, in
|
|
259
|
+
* dependency order; fails when negation or aggregation occurs inside a component.
|
|
260
|
+
*/
|
|
261
|
+
var stratify = (rules, builtins) => {
|
|
262
|
+
const defined = new Set(rules.filter((rule) => rule.body.length > 0).map((rule) => rule.head.predicate));
|
|
263
|
+
const edges = /* @__PURE__ */ new Map();
|
|
264
|
+
for (const predicate of defined) edges.set(predicate, []);
|
|
265
|
+
for (const rule of rules) for (const literal of rule.body) for (const dependency of dependencies(literal, builtins)) if (defined.has(dependency.predicate)) edges.get(rule.head.predicate)?.push(dependency);
|
|
266
|
+
const components = [];
|
|
267
|
+
const index = /* @__PURE__ */ new Map();
|
|
268
|
+
const lowLink = /* @__PURE__ */ new Map();
|
|
269
|
+
const stack = [];
|
|
270
|
+
const onStack = /* @__PURE__ */ new Set();
|
|
271
|
+
const visit = (predicate) => {
|
|
272
|
+
index.set(predicate, index.size);
|
|
273
|
+
lowLink.set(predicate, index.get(predicate) ?? 0);
|
|
274
|
+
stack.push(predicate);
|
|
275
|
+
onStack.add(predicate);
|
|
276
|
+
for (const { predicate: next } of edges.get(predicate) ?? []) if (!index.has(next)) {
|
|
277
|
+
visit(next);
|
|
278
|
+
lowLink.set(predicate, Math.min(lowLink.get(predicate) ?? 0, lowLink.get(next) ?? 0));
|
|
279
|
+
} else if (onStack.has(next)) lowLink.set(predicate, Math.min(lowLink.get(predicate) ?? 0, index.get(next) ?? 0));
|
|
280
|
+
if (lowLink.get(predicate) === index.get(predicate)) {
|
|
281
|
+
const component = [];
|
|
282
|
+
let member;
|
|
283
|
+
do {
|
|
284
|
+
member = stack.pop();
|
|
285
|
+
if (member !== void 0) {
|
|
286
|
+
onStack.delete(member);
|
|
287
|
+
component.push(member);
|
|
288
|
+
}
|
|
289
|
+
} while (member !== void 0 && member !== predicate);
|
|
290
|
+
components.push(component);
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
for (const predicate of defined) if (!index.has(predicate)) visit(predicate);
|
|
294
|
+
const cycles = [];
|
|
295
|
+
const strata = components.map((component) => {
|
|
296
|
+
const members = new Set(component);
|
|
297
|
+
const internal = component.flatMap((predicate) => (edges.get(predicate) ?? []).filter((dependency) => members.has(dependency.predicate)));
|
|
298
|
+
if (internal.some((dependency) => dependency.negative)) cycles.push(component.sort());
|
|
299
|
+
return {
|
|
300
|
+
predicates: members,
|
|
301
|
+
rules: rules.flatMap((rule, ruleIndex) => rule.body.length > 0 && members.has(rule.head.predicate) ? [ruleIndex] : []),
|
|
302
|
+
recursive: internal.length > 0
|
|
303
|
+
};
|
|
304
|
+
});
|
|
305
|
+
return cycles.length > 0 ? {
|
|
306
|
+
ok: false,
|
|
307
|
+
cycles
|
|
308
|
+
} : {
|
|
309
|
+
ok: true,
|
|
310
|
+
strata
|
|
311
|
+
};
|
|
312
|
+
};
|
|
313
|
+
//#endregion
|
|
314
|
+
//#region src/Checker.ts
|
|
315
|
+
var Checker_exports = /* @__PURE__ */ __exportAll({
|
|
316
|
+
CheckError: () => CheckError,
|
|
317
|
+
check: () => check,
|
|
318
|
+
formatDiagnostic: () => formatDiagnostic
|
|
319
|
+
});
|
|
320
|
+
/** Thrown when a program with diagnostics is evaluated. */
|
|
321
|
+
var CheckError = class extends BaseError.extend("CheckError", "Invalid program") {
|
|
322
|
+
diagnostics;
|
|
323
|
+
constructor(diagnostics) {
|
|
324
|
+
super({ message: `Invalid program:\n${diagnostics.map(formatDiagnostic).join("\n")}` });
|
|
325
|
+
this.diagnostics = diagnostics;
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
/** Formats a diagnostic as `line:column code: message`. */
|
|
329
|
+
var formatDiagnostic = (diagnostic) => {
|
|
330
|
+
return `${diagnostic.position ? `${diagnostic.position.line}:${diagnostic.position.column} ` : ""}${diagnostic.code}: ${diagnostic.message}`;
|
|
331
|
+
};
|
|
332
|
+
/**
|
|
333
|
+
* Checks arity consistency, built-in heads, undefined predicates, range restriction (safety) and
|
|
334
|
+
* stratification; an empty result means the program can be evaluated.
|
|
335
|
+
*/
|
|
336
|
+
var check = (program, options = {}) => {
|
|
337
|
+
const builtins = options.builtins ?? /* @__PURE__ */ new Map();
|
|
338
|
+
const diagnostics = [];
|
|
339
|
+
const arities = /* @__PURE__ */ new Map();
|
|
340
|
+
for (const builtin of builtins.values()) arities.set(builtin.name, builtin.arity);
|
|
341
|
+
for (const [name, arity] of Object.entries(options.relations ?? {})) arities.set(name, arity);
|
|
342
|
+
const defined = new Set(program.rules.map((rule) => rule.head.predicate));
|
|
343
|
+
const visitAtom = (atom, rule, position) => {
|
|
344
|
+
const expected = arities.get(atom.predicate);
|
|
345
|
+
if (expected === void 0) arities.set(atom.predicate, atom.terms.length);
|
|
346
|
+
else if (expected !== atom.terms.length) diagnostics.push({
|
|
347
|
+
code: "arity",
|
|
348
|
+
message: `${atom.predicate}/${atom.terms.length} used where ${atom.predicate}/${expected} is expected`,
|
|
349
|
+
rule,
|
|
350
|
+
position
|
|
351
|
+
});
|
|
352
|
+
};
|
|
353
|
+
const visitLiteral = (literal, rule, fallback) => {
|
|
354
|
+
const position = literal.position ?? fallback;
|
|
355
|
+
if (literal.type === "atom") {
|
|
356
|
+
visitAtom(literal.atom, rule, position);
|
|
357
|
+
const predicate = literal.atom.predicate;
|
|
358
|
+
if (options.relations && !defined.has(predicate) && !builtins.has(predicate) && !(predicate in options.relations)) diagnostics.push({
|
|
359
|
+
code: "undefined",
|
|
360
|
+
message: `${predicate}/${literal.atom.terms.length} is not a relation, rule or built-in`,
|
|
361
|
+
rule,
|
|
362
|
+
position
|
|
363
|
+
});
|
|
364
|
+
} else if (literal.type === "aggregate") literal.body.forEach((inner) => visitLiteral(inner, rule, position));
|
|
365
|
+
};
|
|
366
|
+
program.rules.forEach((rule, index) => {
|
|
367
|
+
if (builtins.has(rule.head.predicate)) diagnostics.push({
|
|
368
|
+
code: "builtin-head",
|
|
369
|
+
message: `rule defines built-in ${rule.head.predicate}`,
|
|
370
|
+
rule: index,
|
|
371
|
+
position: rule.position
|
|
372
|
+
});
|
|
373
|
+
visitAtom(rule.head, index, rule.position);
|
|
374
|
+
rule.body.forEach((literal) => visitLiteral(literal, index, rule.position));
|
|
375
|
+
const head = new Set(variablesOf(rule.head.terms));
|
|
376
|
+
const plan = planBody({
|
|
377
|
+
body: rule.body,
|
|
378
|
+
builtins,
|
|
379
|
+
slots: new Slots(),
|
|
380
|
+
outer: head
|
|
381
|
+
});
|
|
382
|
+
for (const { literal, reason } of plan.unresolved) diagnostics.push({
|
|
383
|
+
code: "unsafe",
|
|
384
|
+
message: `${reason} in: ${formatRule(rule)}`,
|
|
385
|
+
rule: index,
|
|
386
|
+
position: rule.body[literal].position ?? rule.position
|
|
387
|
+
});
|
|
388
|
+
const unboundHead = [...head].filter((name) => !plan.bound.has(name));
|
|
389
|
+
if (unboundHead.length > 0) diagnostics.push({
|
|
390
|
+
code: "unsafe",
|
|
391
|
+
message: `head variable ${unboundHead.join(", ")} is not bound by the body in: ${formatRule(rule)}`,
|
|
392
|
+
rule: index,
|
|
393
|
+
position: rule.position
|
|
394
|
+
});
|
|
395
|
+
if (rule.head.terms.some((term) => term.type === "variable" && term.anonymous)) diagnostics.push({
|
|
396
|
+
code: "unsafe",
|
|
397
|
+
message: `anonymous variable in head of: ${formatRule(rule)}`,
|
|
398
|
+
rule: index,
|
|
399
|
+
position: rule.position
|
|
400
|
+
});
|
|
401
|
+
});
|
|
402
|
+
const stratification = stratify(program.rules, builtins);
|
|
403
|
+
if (!stratification.ok) for (const cycle of stratification.cycles) diagnostics.push({
|
|
404
|
+
code: "unstratifiable",
|
|
405
|
+
message: `negation or aggregation through recursion among: ${cycle.join(", ")}`,
|
|
406
|
+
rule: program.rules.findIndex((rule) => cycle.includes(rule.head.predicate)),
|
|
407
|
+
position: program.rules.find((rule) => cycle.includes(rule.head.predicate))?.position
|
|
408
|
+
});
|
|
409
|
+
return diagnostics;
|
|
410
|
+
};
|
|
411
|
+
//#endregion
|
|
412
|
+
export { dependencies as a, planBody as c, formatDiagnostic as i, Checker_exports as n, stratify as o, check as r, Slots as s, CheckError as t };
|
|
413
|
+
|
|
414
|
+
//# sourceMappingURL=chunk-Checker.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunk-Checker.mjs","names":[],"sources":["../../src/internal/plan.ts","../../src/internal/stratify.ts","../../src/Checker.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport type * as Ast from '../Ast.ts';\nimport * as Builtin from '../Builtin.ts';\n\n/** A term resolved against a rule's variable slots; `wild` is an anonymous variable. */\nexport type Ref =\n | { readonly kind: 'const'; readonly value: Ast.Value }\n | { readonly kind: 'slot'; readonly slot: number }\n | { readonly kind: 'wild' };\n\nexport type ScanStep = {\n readonly kind: 'scan';\n readonly literal: number;\n readonly relation: string;\n /** Columns whose value is known before the scan, with the value source. */\n readonly bound: ReadonlyArray<{ readonly column: number; readonly ref: Ref }>;\n /** Columns that bind a slot, or check it when the variable repeats within the atom. */\n readonly binds: ReadonlyArray<{ readonly column: number; readonly slot: number }>;\n};\n\nexport type NegationStep = {\n readonly kind: 'negation';\n readonly relation: string;\n readonly bound: ReadonlyArray<{ readonly column: number; readonly ref: Ref }>;\n};\n\nexport type CompareStep = {\n readonly kind: 'compare';\n readonly operator: Ast.ComparisonOperator;\n readonly left: Ref;\n readonly right: Ref;\n /** Set for `X = term` with `X` unbound: assigns instead of comparing. */\n readonly assign?: { readonly slot: number; readonly from: Ref };\n};\n\nexport type BuiltinStep = {\n readonly kind: 'builtin';\n readonly builtin: Builtin.Builtin;\n readonly args: ReadonlyArray<Ref>;\n /** Arguments unbound at call time, passed as `undefined` and bound from the results. */\n readonly free: ReadonlyArray<boolean>;\n readonly negated: boolean;\n};\n\nexport type AggregateStep = {\n readonly kind: 'aggregate';\n readonly function: Ast.AggregateFunction;\n readonly steps: ReadonlyArray<Step>;\n /** Slots local to the aggregate body; distinct assignments of these are aggregated. */\n readonly local: ReadonlyArray<number>;\n readonly target?: Ref;\n readonly result: Ref;\n readonly assignResult: boolean;\n};\n\nexport type Step = ScanStep | NegationStep | CompareStep | BuiltinStep | AggregateStep;\n\nexport type Unresolved = { readonly literal: number; readonly reason: string };\n\nexport type Plan = {\n readonly steps: ReadonlyArray<Step>;\n readonly unresolved: ReadonlyArray<Unresolved>;\n readonly bound: ReadonlySet<string>;\n};\n\n/** Assigns a slot per named variable of a rule. */\nexport class Slots {\n readonly #slots = new Map<string, number>();\n\n get size(): number {\n return this.#slots.size;\n }\n\n slot(name: string): number {\n let slot = this.#slots.get(name);\n if (slot === undefined) {\n slot = this.#slots.size;\n this.#slots.set(name, slot);\n }\n return slot;\n }\n\n ref(term: Ast.Term): Ref {\n if (term.type === 'constant') {\n return { kind: 'const', value: term.value };\n }\n return term.anonymous ? { kind: 'wild' } : { kind: 'slot', slot: this.slot(term.name) };\n }\n}\n\nconst isBound = (term: Ast.Term, bound: ReadonlySet<string>) =>\n term.type === 'constant' || (!term.anonymous && bound.has(term.name));\n\nconst unboundNames = (terms: ReadonlyArray<Ast.Term>, bound: ReadonlySet<string>) =>\n terms.flatMap((term) => (term.type === 'variable' && !term.anonymous && !bound.has(term.name) ? [term.name] : []));\n\nconst variableNames = (literal: Ast.Literal): string[] => {\n switch (literal.type) {\n case 'atom':\n return literal.atom.terms.flatMap((term) => (term.type === 'variable' && !term.anonymous ? [term.name] : []));\n case 'comparison':\n return [literal.left, literal.right].flatMap((term) =>\n term.type === 'variable' && !term.anonymous ? [term.name] : [],\n );\n case 'aggregate':\n return [\n ...[literal.result, ...(literal.target ? [literal.target] : [])].flatMap((term) =>\n term.type === 'variable' && !term.anonymous ? [term.name] : [],\n ),\n ...literal.body.flatMap(variableNames),\n ];\n }\n};\n\n/**\n * Orders a rule body so every literal runs once its inputs are bound: filters as early as\n * possible, then the relation scan with the most bound columns, then generating built-ins.\n * @param outer Variables used outside the body (the head, or the enclosing rule of an aggregate).\n * @param first Literal to scan first (the semi-naive delta).\n */\nexport const planBody = (options: {\n body: ReadonlyArray<Ast.Literal>;\n builtins: Builtin.Registry;\n slots: Slots;\n outer: ReadonlySet<string>;\n bound?: ReadonlySet<string>;\n first?: number;\n}): Plan => {\n const { body, builtins, slots, outer, first } = options;\n const bound = new Set(options.bound ?? []);\n const steps: Step[] = [];\n const remaining = new Set(body.keys());\n const unresolved: Unresolved[] = [];\n\n const scan = (index: number, literal: Ast.AtomLiteral) => {\n const boundColumns: { column: number; ref: Ref }[] = [];\n const binds: { column: number; slot: number }[] = [];\n literal.atom.terms.forEach((term, column) => {\n if (isBound(term, bound)) {\n boundColumns.push({ column, ref: slots.ref(term) });\n } else if (term.type === 'variable' && !term.anonymous) {\n binds.push({ column, slot: slots.slot(term.name) });\n }\n });\n for (const name of unboundNames(literal.atom.terms, bound)) {\n bound.add(name);\n }\n steps.push({ kind: 'scan', literal: index, relation: literal.atom.predicate, bound: boundColumns, binds });\n };\n\n /** Variables any other literal or the outer scope uses, which an aggregate must correlate on. */\n const correlated = (index: number, literal: Ast.AggregateLiteral): string[] => {\n const elsewhere = new Set([...outer, ...body.flatMap((other, at) => (at === index ? [] : variableNames(other)))]);\n const inner = new Set(literal.body.flatMap(variableNames));\n return [...inner].filter((name) => elsewhere.has(name));\n };\n\n /** Schedules `index` if it is a filter (or, with `generate`, a generator) whose inputs are bound. */\n const trySchedule = (index: number, generate: boolean): boolean => {\n const literal = body[index];\n switch (literal.type) {\n case 'atom': {\n const builtin = builtins.get(literal.atom.predicate);\n if (!builtin) {\n if (!literal.negated) {\n return false;\n }\n if (unboundNames(literal.atom.terms, bound).length > 0) {\n return false;\n }\n steps.push({\n kind: 'negation',\n relation: literal.atom.predicate,\n bound: literal.atom.terms.flatMap((term, column) =>\n term.type === 'variable' && term.anonymous ? [] : [{ column, ref: slots.ref(term) }],\n ),\n });\n return true;\n }\n const boundArgs = literal.atom.terms.map((term) => isBound(term, bound));\n const allBound = boundArgs.every(Boolean);\n if (!allBound && (!generate || literal.negated || !Builtin.acceptsBinding(builtin, boundArgs))) {\n return false;\n }\n steps.push({\n kind: 'builtin',\n builtin,\n args: literal.atom.terms.map((term) => slots.ref(term)),\n free: boundArgs.map((value) => !value),\n negated: literal.negated,\n });\n for (const name of unboundNames(literal.atom.terms, bound)) {\n bound.add(name);\n }\n return true;\n }\n case 'comparison': {\n const left = isBound(literal.left, bound);\n const right = isBound(literal.right, bound);\n if (left && right) {\n steps.push({\n kind: 'compare',\n operator: literal.operator,\n left: slots.ref(literal.left),\n right: slots.ref(literal.right),\n });\n return true;\n }\n if (!generate || literal.operator !== '=' || left === right) {\n return false;\n }\n const [target, source] = left ? [literal.right, literal.left] : [literal.left, literal.right];\n if (target.type !== 'variable' || target.anonymous) {\n return false;\n }\n steps.push({\n kind: 'compare',\n operator: '=',\n left: slots.ref(literal.left),\n right: slots.ref(literal.right),\n assign: { slot: slots.slot(target.name), from: slots.ref(source) },\n });\n bound.add(target.name);\n return true;\n }\n case 'aggregate': {\n const correlation = correlated(index, literal);\n if (correlation.some((name) => !bound.has(name))) {\n return false;\n }\n const resultBound = isBound(literal.result, bound);\n if (!resultBound && !generate) {\n return false;\n }\n const inner = planBody({\n body: literal.body,\n builtins,\n slots,\n outer: new Set(correlation),\n bound: new Set(correlation),\n });\n if (inner.unresolved.length > 0) {\n unresolved.push(...inner.unresolved.map(({ reason }) => ({ literal: index, reason })));\n return true;\n }\n if (literal.target && !isBound(literal.target, inner.bound)) {\n unresolved.push({ literal: index, reason: `aggregate target is not bound by the aggregate body` });\n return true;\n }\n const local = [...inner.bound].filter((name) => !correlation.includes(name)).map((name) => slots.slot(name));\n steps.push({\n kind: 'aggregate',\n function: literal.function,\n steps: inner.steps,\n local,\n target: literal.target ? slots.ref(literal.target) : undefined,\n result: slots.ref(literal.result),\n assignResult: !resultBound,\n });\n if (literal.result.type === 'variable' && !literal.result.anonymous) {\n bound.add(literal.result.name);\n }\n return true;\n }\n }\n };\n\n if (first !== undefined) {\n const literal = body[first];\n if (literal.type === 'atom' && !literal.negated && !builtins.has(literal.atom.predicate)) {\n remaining.delete(first);\n scan(first, literal);\n }\n }\n\n while (remaining.size > 0) {\n let progressed = false;\n for (const index of remaining) {\n if (trySchedule(index, false)) {\n remaining.delete(index);\n progressed = true;\n }\n }\n if (progressed) {\n continue;\n }\n\n let best: number | undefined;\n let bestBound = -1;\n for (const index of remaining) {\n const literal = body[index];\n if (literal.type === 'atom' && !literal.negated && !builtins.has(literal.atom.predicate)) {\n const boundCount = literal.atom.terms.filter((term) => isBound(term, bound)).length;\n if (boundCount > bestBound) {\n best = index;\n bestBound = boundCount;\n }\n }\n }\n if (best !== undefined) {\n const literal = body[best];\n if (literal.type === 'atom') {\n remaining.delete(best);\n scan(best, literal);\n }\n continue;\n }\n\n for (const index of remaining) {\n if (trySchedule(index, true)) {\n remaining.delete(index);\n progressed = true;\n break;\n }\n }\n if (!progressed) {\n break;\n }\n }\n\n for (const index of remaining) {\n unresolved.push({ literal: index, reason: describeUnresolved(body[index], bound, builtins) });\n }\n return { steps, unresolved, bound };\n};\n\nconst describeUnresolved = (literal: Ast.Literal, bound: ReadonlySet<string>, builtins: Builtin.Registry): string => {\n switch (literal.type) {\n case 'atom': {\n const names = unboundNames(literal.atom.terms, bound).join(', ');\n if (builtins.has(literal.atom.predicate)) {\n return literal.negated\n ? `negated built-in ${literal.atom.predicate} needs every argument bound (${names} unbound)`\n : `no binding mode of built-in ${literal.atom.predicate}/${literal.atom.terms.length} accepts ${names} unbound`;\n }\n return `variable ${names} under negation is not bound by a positive literal`;\n }\n case 'comparison':\n return `variable ${unboundNames([literal.left, literal.right], bound).join(', ')} in comparison is not bound`;\n case 'aggregate':\n return `aggregate depends on unbound variables`;\n }\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport type * as Ast from '../Ast.ts';\nimport type * as Builtin from '../Builtin.ts';\n\nexport type Dependency = { readonly predicate: string; readonly negative: boolean };\n\nexport type Stratum = {\n /** Predicates defined by the stratum's rules (one strongly connected component). */\n readonly predicates: ReadonlySet<string>;\n /** Indexes into the program's rules. */\n readonly rules: ReadonlyArray<number>;\n readonly recursive: boolean;\n};\n\nexport type Stratification =\n | { readonly ok: true; readonly strata: ReadonlyArray<Stratum> }\n | { readonly ok: false; readonly cycles: ReadonlyArray<ReadonlyArray<string>> };\n\n/** Relations a literal reads; negation and aggregation read them non-monotonically. */\nexport const dependencies = (literal: Ast.Literal, builtins: Builtin.Registry): Dependency[] => {\n switch (literal.type) {\n case 'atom':\n return builtins.has(literal.atom.predicate)\n ? []\n : [{ predicate: literal.atom.predicate, negative: literal.negated }];\n case 'comparison':\n return [];\n case 'aggregate':\n return literal.body.flatMap((inner) =>\n dependencies(inner, builtins).map(({ predicate }) => ({ predicate, negative: true })),\n );\n }\n};\n\n/**\n * Splits rules into strata: one per strongly connected component of the predicate graph, in\n * dependency order; fails when negation or aggregation occurs inside a component.\n */\nexport const stratify = (rules: ReadonlyArray<Ast.Rule>, builtins: Builtin.Registry): Stratification => {\n const defined = new Set(rules.filter((rule) => rule.body.length > 0).map((rule) => rule.head.predicate));\n const edges = new Map<string, Dependency[]>();\n for (const predicate of defined) {\n edges.set(predicate, []);\n }\n for (const rule of rules) {\n for (const literal of rule.body) {\n for (const dependency of dependencies(literal, builtins)) {\n if (defined.has(dependency.predicate)) {\n edges.get(rule.head.predicate)?.push(dependency);\n }\n }\n }\n }\n\n // Tarjan's algorithm emits each component after every component it depends on.\n const components: string[][] = [];\n const index = new Map<string, number>();\n const lowLink = new Map<string, number>();\n const stack: string[] = [];\n const onStack = new Set<string>();\n const visit = (predicate: string) => {\n index.set(predicate, index.size);\n lowLink.set(predicate, index.get(predicate) ?? 0);\n stack.push(predicate);\n onStack.add(predicate);\n for (const { predicate: next } of edges.get(predicate) ?? []) {\n if (!index.has(next)) {\n visit(next);\n lowLink.set(predicate, Math.min(lowLink.get(predicate) ?? 0, lowLink.get(next) ?? 0));\n } else if (onStack.has(next)) {\n lowLink.set(predicate, Math.min(lowLink.get(predicate) ?? 0, index.get(next) ?? 0));\n }\n }\n if (lowLink.get(predicate) === index.get(predicate)) {\n const component: string[] = [];\n let member: string | undefined;\n do {\n member = stack.pop();\n if (member !== undefined) {\n onStack.delete(member);\n component.push(member);\n }\n } while (member !== undefined && member !== predicate);\n components.push(component);\n }\n };\n for (const predicate of defined) {\n if (!index.has(predicate)) {\n visit(predicate);\n }\n }\n\n const cycles: string[][] = [];\n const strata: Stratum[] = components.map((component) => {\n const members = new Set(component);\n const internal = component.flatMap((predicate) =>\n (edges.get(predicate) ?? []).filter((dependency) => members.has(dependency.predicate)),\n );\n if (internal.some((dependency) => dependency.negative)) {\n cycles.push(component.sort());\n }\n return {\n predicates: members,\n rules: rules.flatMap((rule, ruleIndex) =>\n rule.body.length > 0 && members.has(rule.head.predicate) ? [ruleIndex] : [],\n ),\n recursive: internal.length > 0,\n };\n });\n return cycles.length > 0 ? { ok: false, cycles } : { ok: true, strata };\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n// @import-as-namespace\n\nimport { BaseError } from '@dxos/errors';\n\nimport * as Ast from './Ast.ts';\nimport type * as Builtin from './Builtin.ts';\nimport { Slots, planBody } from './internal/plan.ts';\nimport { stratify } from './internal/stratify.ts';\n\nexport type DiagnosticCode = 'arity' | 'builtin-head' | 'undefined' | 'unsafe' | 'unstratifiable';\n\n/** A static error in a program. */\nexport type Diagnostic = {\n readonly code: DiagnosticCode;\n readonly message: string;\n /** Index of the offending rule. */\n readonly rule?: number;\n readonly position?: Ast.Position;\n};\n\nexport type Options = {\n readonly builtins?: Builtin.Registry;\n /**\n * Base relations and their arities. When given, a body predicate that is neither defined by a\n * rule, declared here nor a built-in is reported as `undefined`.\n */\n readonly relations?: Readonly<Record<string, number>>;\n};\n\n/** Thrown when a program with diagnostics is evaluated. */\nexport class CheckError extends BaseError.extend('CheckError', 'Invalid program') {\n // A typed field rather than `context`, which would repeat every diagnostic in the message as JSON.\n readonly diagnostics: ReadonlyArray<Diagnostic>;\n\n constructor(diagnostics: ReadonlyArray<Diagnostic>) {\n super({ message: `Invalid program:\\n${diagnostics.map(formatDiagnostic).join('\\n')}` });\n this.diagnostics = diagnostics;\n }\n}\n\n/** Formats a diagnostic as `line:column code: message`. */\nexport const formatDiagnostic = (diagnostic: Diagnostic): string => {\n const at = diagnostic.position ? `${diagnostic.position.line}:${diagnostic.position.column} ` : '';\n return `${at}${diagnostic.code}: ${diagnostic.message}`;\n};\n\n/**\n * Checks arity consistency, built-in heads, undefined predicates, range restriction (safety) and\n * stratification; an empty result means the program can be evaluated.\n */\nexport const check = (program: Ast.Program, options: Options = {}): Diagnostic[] => {\n const builtins = options.builtins ?? new Map();\n const diagnostics: Diagnostic[] = [];\n const arities = new Map<string, number>();\n for (const builtin of builtins.values()) {\n arities.set(builtin.name, builtin.arity);\n }\n for (const [name, arity] of Object.entries(options.relations ?? {})) {\n arities.set(name, arity);\n }\n const defined = new Set(program.rules.map((rule) => rule.head.predicate));\n\n const visitAtom = (atom: Ast.Atom, rule: number, position: Ast.Position | undefined) => {\n const expected = arities.get(atom.predicate);\n if (expected === undefined) {\n arities.set(atom.predicate, atom.terms.length);\n } else if (expected !== atom.terms.length) {\n diagnostics.push({\n code: 'arity',\n message: `${atom.predicate}/${atom.terms.length} used where ${atom.predicate}/${expected} is expected`,\n rule,\n position,\n });\n }\n };\n const visitLiteral = (literal: Ast.Literal, rule: number, fallback: Ast.Position | undefined) => {\n const position = literal.position ?? fallback;\n if (literal.type === 'atom') {\n visitAtom(literal.atom, rule, position);\n const predicate = literal.atom.predicate;\n if (\n options.relations &&\n !defined.has(predicate) &&\n !builtins.has(predicate) &&\n !(predicate in options.relations)\n ) {\n diagnostics.push({\n code: 'undefined',\n message: `${predicate}/${literal.atom.terms.length} is not a relation, rule or built-in`,\n rule,\n position,\n });\n }\n } else if (literal.type === 'aggregate') {\n literal.body.forEach((inner) => visitLiteral(inner, rule, position));\n }\n };\n\n program.rules.forEach((rule, index) => {\n if (builtins.has(rule.head.predicate)) {\n diagnostics.push({\n code: 'builtin-head',\n message: `rule defines built-in ${rule.head.predicate}`,\n rule: index,\n position: rule.position,\n });\n }\n visitAtom(rule.head, index, rule.position);\n rule.body.forEach((literal) => visitLiteral(literal, index, rule.position));\n\n const head = new Set(Ast.variablesOf(rule.head.terms));\n const plan = planBody({ body: rule.body, builtins, slots: new Slots(), outer: head });\n for (const { literal, reason } of plan.unresolved) {\n diagnostics.push({\n code: 'unsafe',\n message: `${reason} in: ${Ast.formatRule(rule)}`,\n rule: index,\n position: rule.body[literal].position ?? rule.position,\n });\n }\n const unboundHead = [...head].filter((name) => !plan.bound.has(name));\n if (unboundHead.length > 0) {\n diagnostics.push({\n code: 'unsafe',\n message: `head variable ${unboundHead.join(', ')} is not bound by the body in: ${Ast.formatRule(rule)}`,\n rule: index,\n position: rule.position,\n });\n }\n if (rule.head.terms.some((term) => term.type === 'variable' && term.anonymous)) {\n diagnostics.push({\n code: 'unsafe',\n message: `anonymous variable in head of: ${Ast.formatRule(rule)}`,\n rule: index,\n position: rule.position,\n });\n }\n });\n\n const stratification = stratify(program.rules, builtins);\n if (!stratification.ok) {\n for (const cycle of stratification.cycles) {\n diagnostics.push({\n code: 'unstratifiable',\n message: `negation or aggregation through recursion among: ${cycle.join(', ')}`,\n rule: program.rules.findIndex((rule) => cycle.includes(rule.head.predicate)),\n position: program.rules.find((rule) => cycle.includes(rule.head.predicate))?.position,\n });\n }\n }\n return diagnostics;\n};\n"],"mappings":"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"}
|