docground 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 +217 -0
- package/dist/src/compiler/zod-compiler.d.ts +31 -0
- package/dist/src/compiler/zod-compiler.d.ts.map +1 -0
- package/dist/src/compiler/zod-compiler.js +150 -0
- package/dist/src/compiler/zod-compiler.js.map +1 -0
- package/dist/src/core/extractor.d.ts +17 -0
- package/dist/src/core/extractor.d.ts.map +1 -0
- package/dist/src/core/extractor.js +268 -0
- package/dist/src/core/extractor.js.map +1 -0
- package/dist/src/core/types.d.ts +102 -0
- package/dist/src/core/types.d.ts.map +1 -0
- package/dist/src/core/types.js +2 -0
- package/dist/src/core/types.js.map +1 -0
- package/dist/src/grounding/bbox.d.ts +40 -0
- package/dist/src/grounding/bbox.d.ts.map +1 -0
- package/dist/src/grounding/bbox.js +98 -0
- package/dist/src/grounding/bbox.js.map +1 -0
- package/dist/src/index.d.ts +16 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +16 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/normalizers/currency.d.ts +14 -0
- package/dist/src/normalizers/currency.d.ts.map +1 -0
- package/dist/src/normalizers/currency.js +96 -0
- package/dist/src/normalizers/currency.js.map +1 -0
- package/dist/src/normalizers/tabular.d.ts +16 -0
- package/dist/src/normalizers/tabular.d.ts.map +1 -0
- package/dist/src/normalizers/tabular.js +81 -0
- package/dist/src/normalizers/tabular.js.map +1 -0
- package/dist/src/providers/anthropic-provider.d.ts +13 -0
- package/dist/src/providers/anthropic-provider.d.ts.map +1 -0
- package/dist/src/providers/anthropic-provider.js +62 -0
- package/dist/src/providers/anthropic-provider.js.map +1 -0
- package/dist/src/providers/factory.d.ts +11 -0
- package/dist/src/providers/factory.d.ts.map +1 -0
- package/dist/src/providers/factory.js +32 -0
- package/dist/src/providers/factory.js.map +1 -0
- package/dist/src/providers/gemini-provider.d.ts +13 -0
- package/dist/src/providers/gemini-provider.d.ts.map +1 -0
- package/dist/src/providers/gemini-provider.js +48 -0
- package/dist/src/providers/gemini-provider.js.map +1 -0
- package/dist/src/providers/openai-provider.d.ts +14 -0
- package/dist/src/providers/openai-provider.d.ts.map +1 -0
- package/dist/src/providers/openai-provider.js +48 -0
- package/dist/src/providers/openai-provider.js.map +1 -0
- package/dist/src/providers/types.d.ts +45 -0
- package/dist/src/providers/types.d.ts.map +1 -0
- package/dist/src/providers/types.js +2 -0
- package/dist/src/providers/types.js.map +1 -0
- package/dist/src/stitcher/table-stitcher.d.ts +19 -0
- package/dist/src/stitcher/table-stitcher.d.ts.map +1 -0
- package/dist/src/stitcher/table-stitcher.js +129 -0
- package/dist/src/stitcher/table-stitcher.js.map +1 -0
- package/dist/src/tiling/cutter.d.ts +14 -0
- package/dist/src/tiling/cutter.d.ts.map +1 -0
- package/dist/src/tiling/cutter.js +46 -0
- package/dist/src/tiling/cutter.js.map +1 -0
- package/dist/src/tiling/tiler.d.ts +41 -0
- package/dist/src/tiling/tiler.d.ts.map +1 -0
- package/dist/src/tiling/tiler.js +82 -0
- package/dist/src/tiling/tiler.js.map +1 -0
- package/dist/src/validators/invariants.d.ts +30 -0
- package/dist/src/validators/invariants.d.ts.map +1 -0
- package/dist/src/validators/invariants.js +164 -0
- package/dist/src/validators/invariants.js.map +1 -0
- package/dist/tests/compiler.test.d.ts +2 -0
- package/dist/tests/compiler.test.d.ts.map +1 -0
- package/dist/tests/compiler.test.js +110 -0
- package/dist/tests/compiler.test.js.map +1 -0
- package/dist/tests/extractor.test.d.ts +2 -0
- package/dist/tests/extractor.test.d.ts.map +1 -0
- package/dist/tests/extractor.test.js +195 -0
- package/dist/tests/extractor.test.js.map +1 -0
- package/dist/tests/fixtures.d.ts +9 -0
- package/dist/tests/fixtures.d.ts.map +1 -0
- package/dist/tests/fixtures.js +20 -0
- package/dist/tests/fixtures.js.map +1 -0
- package/dist/tests/grounding.test.d.ts +2 -0
- package/dist/tests/grounding.test.d.ts.map +1 -0
- package/dist/tests/grounding.test.js +82 -0
- package/dist/tests/grounding.test.js.map +1 -0
- package/dist/tests/multi-domain.test.d.ts +2 -0
- package/dist/tests/multi-domain.test.d.ts.map +1 -0
- package/dist/tests/multi-domain.test.js +135 -0
- package/dist/tests/multi-domain.test.js.map +1 -0
- package/dist/tests/normalizer.test.d.ts +2 -0
- package/dist/tests/normalizer.test.d.ts.map +1 -0
- package/dist/tests/normalizer.test.js +70 -0
- package/dist/tests/normalizer.test.js.map +1 -0
- package/dist/tests/providers.test.d.ts +2 -0
- package/dist/tests/providers.test.d.ts.map +1 -0
- package/dist/tests/providers.test.js +110 -0
- package/dist/tests/providers.test.js.map +1 -0
- package/dist/tests/stitcher.test.d.ts +2 -0
- package/dist/tests/stitcher.test.d.ts.map +1 -0
- package/dist/tests/stitcher.test.js +85 -0
- package/dist/tests/stitcher.test.js.map +1 -0
- package/dist/tests/tiling.test.d.ts +2 -0
- package/dist/tests/tiling.test.d.ts.map +1 -0
- package/dist/tests/tiling.test.js +85 -0
- package/dist/tests/tiling.test.js.map +1 -0
- package/dist/tests/validators.test.d.ts +2 -0
- package/dist/tests/validators.test.d.ts.map +1 -0
- package/dist/tests/validators.test.js +125 -0
- package/dist/tests/validators.test.js.map +1 -0
- package/dist/vitest.config.d.ts +3 -0
- package/dist/vitest.config.d.ts.map +1 -0
- package/dist/vitest.config.js +13 -0
- package/dist/vitest.config.js.map +1 -0
- package/package.json +44 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { compileZodToGeminiSchema } from "../src/compiler/zod-compiler.js";
|
|
4
|
+
describe("compileZodToGeminiSchema", () => {
|
|
5
|
+
it("compiles a primitive schema", () => {
|
|
6
|
+
const schema = z.object({
|
|
7
|
+
name: z.string(),
|
|
8
|
+
age: z.number(),
|
|
9
|
+
active: z.boolean(),
|
|
10
|
+
});
|
|
11
|
+
const geminiSchema = compileZodToGeminiSchema(schema);
|
|
12
|
+
expect(geminiSchema.type).toBe("object");
|
|
13
|
+
expect(geminiSchema.properties).toMatchObject({
|
|
14
|
+
name: { type: "string" },
|
|
15
|
+
age: { type: "number" },
|
|
16
|
+
active: { type: "boolean" },
|
|
17
|
+
});
|
|
18
|
+
expect(geminiSchema.required).toContain("name");
|
|
19
|
+
expect(geminiSchema.required).toContain("age");
|
|
20
|
+
expect(geminiSchema.required).toContain("active");
|
|
21
|
+
});
|
|
22
|
+
it("compiles nested objects", () => {
|
|
23
|
+
const schema = z.object({
|
|
24
|
+
user: z.object({
|
|
25
|
+
id: z.number(),
|
|
26
|
+
email: z.string(),
|
|
27
|
+
}),
|
|
28
|
+
});
|
|
29
|
+
const geminiSchema = compileZodToGeminiSchema(schema);
|
|
30
|
+
expect(geminiSchema.type).toBe("object");
|
|
31
|
+
expect(geminiSchema.properties).toHaveProperty("user");
|
|
32
|
+
expect(geminiSchema.properties).toMatchObject({
|
|
33
|
+
user: {
|
|
34
|
+
type: "object",
|
|
35
|
+
properties: {
|
|
36
|
+
id: { type: "number" },
|
|
37
|
+
email: { type: "string" },
|
|
38
|
+
},
|
|
39
|
+
required: ["id", "email"],
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
it("compiles arrays", () => {
|
|
44
|
+
const schema = z.object({
|
|
45
|
+
tags: z.array(z.string()),
|
|
46
|
+
});
|
|
47
|
+
const geminiSchema = compileZodToGeminiSchema(schema);
|
|
48
|
+
expect(geminiSchema.properties).toMatchObject({
|
|
49
|
+
tags: {
|
|
50
|
+
type: "array",
|
|
51
|
+
items: { type: "string" },
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
it("compiles optional fields", () => {
|
|
56
|
+
const schema = z.object({
|
|
57
|
+
title: z.string(),
|
|
58
|
+
subtitle: z.string().optional(),
|
|
59
|
+
});
|
|
60
|
+
const geminiSchema = compileZodToGeminiSchema(schema);
|
|
61
|
+
expect(geminiSchema.properties).toHaveProperty("subtitle");
|
|
62
|
+
expect(geminiSchema.required).toContain("title");
|
|
63
|
+
expect(geminiSchema.required).not.toContain("subtitle");
|
|
64
|
+
});
|
|
65
|
+
it("compiles enums", () => {
|
|
66
|
+
const schema = z.object({
|
|
67
|
+
status: z.enum(["pending", "paid", "overdue"]),
|
|
68
|
+
});
|
|
69
|
+
const geminiSchema = compileZodToGeminiSchema(schema);
|
|
70
|
+
expect(geminiSchema.properties).toMatchObject({
|
|
71
|
+
status: {
|
|
72
|
+
type: "string",
|
|
73
|
+
enum: ["pending", "paid", "overdue"],
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
it("compiles complex nested schemas with arrays of objects", () => {
|
|
78
|
+
const schema = z.object({
|
|
79
|
+
invoice: z.object({
|
|
80
|
+
lines: z.array(z.object({
|
|
81
|
+
description: z.string(),
|
|
82
|
+
amount: z.number(),
|
|
83
|
+
})),
|
|
84
|
+
total: z.number(),
|
|
85
|
+
}),
|
|
86
|
+
});
|
|
87
|
+
const geminiSchema = compileZodToGeminiSchema(schema);
|
|
88
|
+
expect(geminiSchema.properties).toMatchObject({
|
|
89
|
+
invoice: {
|
|
90
|
+
type: "object",
|
|
91
|
+
properties: {
|
|
92
|
+
lines: {
|
|
93
|
+
type: "array",
|
|
94
|
+
items: {
|
|
95
|
+
type: "object",
|
|
96
|
+
properties: {
|
|
97
|
+
description: { type: "string" },
|
|
98
|
+
amount: { type: "number" },
|
|
99
|
+
},
|
|
100
|
+
required: ["description", "amount"],
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
total: { type: "number" },
|
|
104
|
+
},
|
|
105
|
+
required: ["lines", "total"],
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
//# sourceMappingURL=compiler.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compiler.test.js","sourceRoot":"","sources":["../../tests/compiler.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAE3E,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;IACxC,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;QACrC,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;YACtB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;YAChB,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE;YACf,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE;SACpB,CAAC,CAAC;QAEH,MAAM,YAAY,GAAG,wBAAwB,CAAC,MAAM,CAAC,CAAC;QAEtD,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACzC,MAAM,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,aAAa,CAAC;YAC5C,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YACxB,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YACvB,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;SAC5B,CAAC,CAAC;QACH,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAChD,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAC/C,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yBAAyB,EAAE,GAAG,EAAE;QACjC,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;YACtB,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;gBACb,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;gBACd,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;aAClB,CAAC;SACH,CAAC,CAAC;QAEH,MAAM,YAAY,GAAG,wBAAwB,CAAC,MAAM,CAAC,CAAC;QAEtD,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACzC,MAAM,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;QACvD,MAAM,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,aAAa,CAAC;YAC5C,IAAI,EAAE;gBACJ,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE;oBACV,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;oBACtB,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;iBAC1B;gBACD,QAAQ,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC;aAC1B;SACF,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iBAAiB,EAAE,GAAG,EAAE;QACzB,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;YACtB,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;SAC1B,CAAC,CAAC;QAEH,MAAM,YAAY,GAAG,wBAAwB,CAAC,MAAM,CAAC,CAAC;QAEtD,MAAM,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,aAAa,CAAC;YAC5C,IAAI,EAAE;gBACJ,IAAI,EAAE,OAAO;gBACb,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;aAC1B;SACF,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0BAA0B,EAAE,GAAG,EAAE;QAClC,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;YACtB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;YACjB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;SAChC,CAAC,CAAC;QAEH,MAAM,YAAY,GAAG,wBAAwB,CAAC,MAAM,CAAC,CAAC;QAEtD,MAAM,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;QAC3D,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACjD,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gBAAgB,EAAE,GAAG,EAAE;QACxB,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;YACtB,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;SAC/C,CAAC,CAAC;QAEH,MAAM,YAAY,GAAG,wBAAwB,CAAC,MAAM,CAAC,CAAC;QAEtD,MAAM,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,aAAa,CAAC;YAC5C,MAAM,EAAE;gBACN,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,CAAC;aACrC;SACF,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;YACtB,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC;gBAChB,KAAK,EAAE,CAAC,CAAC,KAAK,CACZ,CAAC,CAAC,MAAM,CAAC;oBACP,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;oBACvB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;iBACnB,CAAC,CACH;gBACD,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;aAClB,CAAC;SACH,CAAC,CAAC;QAEH,MAAM,YAAY,GAAG,wBAAwB,CAAC,MAAM,CAAC,CAAC;QAEtD,MAAM,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,aAAa,CAAC;YAC5C,OAAO,EAAE;gBACP,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE;oBACV,KAAK,EAAE;wBACL,IAAI,EAAE,OAAO;wBACb,KAAK,EAAE;4BACL,IAAI,EAAE,QAAQ;4BACd,UAAU,EAAE;gCACV,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gCAC/B,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;6BAC3B;4BACD,QAAQ,EAAE,CAAC,aAAa,EAAE,QAAQ,CAAC;yBACpC;qBACF;oBACD,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;iBAC1B;gBACD,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC;aAC7B;SACF,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extractor.test.d.ts","sourceRoot":"","sources":["../../tests/extractor.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeAll } from "vitest";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { DocumentExtractor } from "../src/core/extractor.js";
|
|
4
|
+
import { createBlankImage } from "./fixtures.js";
|
|
5
|
+
const Invoice = z.object({
|
|
6
|
+
invoiceNumber: z.string(),
|
|
7
|
+
subtotal: z.number(),
|
|
8
|
+
tax: z.number(),
|
|
9
|
+
total: z.number(),
|
|
10
|
+
items: z.array(z.object({
|
|
11
|
+
description: z.string(),
|
|
12
|
+
amount: z.number(),
|
|
13
|
+
})),
|
|
14
|
+
});
|
|
15
|
+
describe("DocumentExtractor", () => {
|
|
16
|
+
let image;
|
|
17
|
+
beforeAll(async () => {
|
|
18
|
+
image = await createBlankImage(800, 600);
|
|
19
|
+
});
|
|
20
|
+
it("extracts typed data and groundings using a custom VLM", async () => {
|
|
21
|
+
const mockProvider = {
|
|
22
|
+
name: "mock",
|
|
23
|
+
extract: vi.fn().mockResolvedValue({
|
|
24
|
+
text: JSON.stringify({
|
|
25
|
+
data: {
|
|
26
|
+
invoiceNumber: "INV-001",
|
|
27
|
+
subtotal: 100,
|
|
28
|
+
tax: 21,
|
|
29
|
+
total: 121,
|
|
30
|
+
items: [{ description: "A", amount: 100 }],
|
|
31
|
+
},
|
|
32
|
+
groundings: [
|
|
33
|
+
{
|
|
34
|
+
pageIndex: 0,
|
|
35
|
+
field: "invoiceNumber",
|
|
36
|
+
value: "INV-001",
|
|
37
|
+
bbox: [0.1, 0.1, 0.2, 0.4],
|
|
38
|
+
confidence: 0.98,
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
}),
|
|
42
|
+
raw: null,
|
|
43
|
+
}),
|
|
44
|
+
};
|
|
45
|
+
const extractor = new DocumentExtractor({ customVLM: mockProvider });
|
|
46
|
+
const result = await extractor.extract(image.buffer, Invoice, { tiling: "off" });
|
|
47
|
+
expect(result.data.invoiceNumber).toBe("INV-001");
|
|
48
|
+
expect(result.data.total).toBe(121);
|
|
49
|
+
expect(result.groundings).toHaveLength(1);
|
|
50
|
+
expect(result.fields.invoiceNumber.bbox).toEqual([0.1, 0.1, 0.2, 0.4]);
|
|
51
|
+
expect(result.confidence).toBeGreaterThan(0);
|
|
52
|
+
expect(result.provenance.provider).toBe("mock");
|
|
53
|
+
expect(result.provenance.tilesUsed).toBe(1);
|
|
54
|
+
});
|
|
55
|
+
it("runs invariants and returns a report", async () => {
|
|
56
|
+
const mockProvider = {
|
|
57
|
+
name: "mock",
|
|
58
|
+
extract: vi.fn().mockResolvedValue({
|
|
59
|
+
text: JSON.stringify({
|
|
60
|
+
data: {
|
|
61
|
+
invoiceNumber: "INV-002",
|
|
62
|
+
subtotal: 100,
|
|
63
|
+
tax: 21,
|
|
64
|
+
total: 121,
|
|
65
|
+
items: [{ description: "A", amount: 100 }],
|
|
66
|
+
},
|
|
67
|
+
}),
|
|
68
|
+
raw: null,
|
|
69
|
+
}),
|
|
70
|
+
};
|
|
71
|
+
const extractor = new DocumentExtractor({ customVLM: mockProvider });
|
|
72
|
+
const result = await extractor.extract(image.buffer, Invoice, {
|
|
73
|
+
tiling: "off",
|
|
74
|
+
prove: true,
|
|
75
|
+
invariants: [
|
|
76
|
+
{ id: "balance", expression: "subtotal + tax === total" },
|
|
77
|
+
{ id: "items-total", expression: "sum(items.amount) === subtotal" },
|
|
78
|
+
],
|
|
79
|
+
});
|
|
80
|
+
expect(result.invariants?.ok).toBe(true);
|
|
81
|
+
expect(result.invariants?.checks).toHaveLength(2);
|
|
82
|
+
});
|
|
83
|
+
it("auto-repairs when invariants fail", async () => {
|
|
84
|
+
const responses = [
|
|
85
|
+
{
|
|
86
|
+
text: JSON.stringify({
|
|
87
|
+
data: {
|
|
88
|
+
invoiceNumber: "INV-003",
|
|
89
|
+
subtotal: 100,
|
|
90
|
+
tax: 21,
|
|
91
|
+
total: 120, // wrong
|
|
92
|
+
items: [{ description: "A", amount: 100 }],
|
|
93
|
+
},
|
|
94
|
+
}),
|
|
95
|
+
raw: null,
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
text: JSON.stringify({
|
|
99
|
+
data: {
|
|
100
|
+
invoiceNumber: "INV-003",
|
|
101
|
+
subtotal: 100,
|
|
102
|
+
tax: 21,
|
|
103
|
+
total: 121, // corrected
|
|
104
|
+
items: [{ description: "A", amount: 100 }],
|
|
105
|
+
},
|
|
106
|
+
}),
|
|
107
|
+
raw: null,
|
|
108
|
+
},
|
|
109
|
+
];
|
|
110
|
+
const mockProvider = {
|
|
111
|
+
name: "mock",
|
|
112
|
+
extract: vi
|
|
113
|
+
.fn()
|
|
114
|
+
.mockImplementation(() => Promise.resolve(responses.shift())),
|
|
115
|
+
};
|
|
116
|
+
const extractor = new DocumentExtractor({ customVLM: mockProvider });
|
|
117
|
+
const result = await extractor.extract(image.buffer, Invoice, {
|
|
118
|
+
tiling: "off",
|
|
119
|
+
prove: true,
|
|
120
|
+
autoRepair: true,
|
|
121
|
+
invariants: [{ id: "balance", expression: "subtotal + tax === total" }],
|
|
122
|
+
});
|
|
123
|
+
expect(mockProvider.extract).toHaveBeenCalledTimes(2);
|
|
124
|
+
expect(result.data.total).toBe(121);
|
|
125
|
+
expect(result.invariants?.ok).toBe(true);
|
|
126
|
+
expect(result.provenance.repairs).toBe(1);
|
|
127
|
+
});
|
|
128
|
+
it("stitches multi-page tables returned by the VLM", async () => {
|
|
129
|
+
const mockProvider = {
|
|
130
|
+
name: "mock",
|
|
131
|
+
extract: vi.fn().mockResolvedValue({
|
|
132
|
+
text: JSON.stringify({
|
|
133
|
+
data: {
|
|
134
|
+
invoiceNumber: "INV-004",
|
|
135
|
+
subtotal: 200,
|
|
136
|
+
tax: 42,
|
|
137
|
+
total: 242,
|
|
138
|
+
items: [{ description: "A", amount: 200 }],
|
|
139
|
+
},
|
|
140
|
+
tables: [
|
|
141
|
+
{
|
|
142
|
+
pageIndex: 1,
|
|
143
|
+
header: ["Item", "Qty"],
|
|
144
|
+
rows: [["A", 1]],
|
|
145
|
+
bbox: [0, 0, 0.4, 0.9],
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
pageIndex: 2,
|
|
149
|
+
header: ["Item", "Qty"],
|
|
150
|
+
rows: [
|
|
151
|
+
["Item", "Qty"],
|
|
152
|
+
["B", 2],
|
|
153
|
+
],
|
|
154
|
+
bbox: [0, 0, 0.4, 0.9],
|
|
155
|
+
},
|
|
156
|
+
],
|
|
157
|
+
}),
|
|
158
|
+
raw: null,
|
|
159
|
+
}),
|
|
160
|
+
};
|
|
161
|
+
const extractor = new DocumentExtractor({ customVLM: mockProvider });
|
|
162
|
+
const result = await extractor.extract(image.buffer, Invoice, { tiling: "off" });
|
|
163
|
+
expect(result.tables).toHaveLength(1);
|
|
164
|
+
expect(result.tables[0].rows).toEqual([
|
|
165
|
+
["A", 1],
|
|
166
|
+
["B", 2],
|
|
167
|
+
]);
|
|
168
|
+
});
|
|
169
|
+
it("supports tiling when the image exceeds tile limits", async () => {
|
|
170
|
+
const largeImage = await createBlankImage(2000, 2000);
|
|
171
|
+
const mockProvider = {
|
|
172
|
+
name: "mock",
|
|
173
|
+
extract: vi.fn().mockResolvedValue({
|
|
174
|
+
text: JSON.stringify({
|
|
175
|
+
data: {
|
|
176
|
+
invoiceNumber: "INV-005",
|
|
177
|
+
subtotal: 50,
|
|
178
|
+
tax: 10.5,
|
|
179
|
+
total: 60.5,
|
|
180
|
+
items: [{ description: "A", amount: 50 }],
|
|
181
|
+
},
|
|
182
|
+
}),
|
|
183
|
+
raw: null,
|
|
184
|
+
}),
|
|
185
|
+
};
|
|
186
|
+
const extractor = new DocumentExtractor({ customVLM: mockProvider });
|
|
187
|
+
const result = await extractor.extract(largeImage.buffer, Invoice, {
|
|
188
|
+
tiling: { maxTileWidth: 1024, maxTileHeight: 1024, overlap: 0.2 },
|
|
189
|
+
});
|
|
190
|
+
expect(result.provenance.tilesUsed).toBeGreaterThan(1);
|
|
191
|
+
const call = mockProvider.extract.mock.calls[0];
|
|
192
|
+
expect(call[0].images.length).toBeGreaterThan(1);
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
//# sourceMappingURL=extractor.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extractor.test.js","sourceRoot":"","sources":["../../tests/extractor.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface TestImage {
|
|
2
|
+
mimeType: string;
|
|
3
|
+
base64: string;
|
|
4
|
+
width: number;
|
|
5
|
+
height: number;
|
|
6
|
+
buffer: Buffer;
|
|
7
|
+
}
|
|
8
|
+
export declare function createBlankImage(width: number, height: number, mimeType?: "image/png" | "image/jpeg"): Promise<TestImage>;
|
|
9
|
+
//# sourceMappingURL=fixtures.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fixtures.d.ts","sourceRoot":"","sources":["../../tests/fixtures.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,QAAQ,GAAE,WAAW,GAAG,YAA0B,GACjD,OAAO,CAAC,SAAS,CAAC,CAiBpB"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import sharp from "sharp";
|
|
2
|
+
export async function createBlankImage(width, height, mimeType = "image/png") {
|
|
3
|
+
const pipeline = sharp({
|
|
4
|
+
create: {
|
|
5
|
+
width,
|
|
6
|
+
height,
|
|
7
|
+
channels: 3,
|
|
8
|
+
background: "white",
|
|
9
|
+
},
|
|
10
|
+
});
|
|
11
|
+
const buf = mimeType === "image/jpeg" ? await pipeline.jpeg().toBuffer() : await pipeline.png().toBuffer();
|
|
12
|
+
return {
|
|
13
|
+
mimeType,
|
|
14
|
+
base64: buf.toString("base64"),
|
|
15
|
+
width,
|
|
16
|
+
height,
|
|
17
|
+
buffer: buf,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=fixtures.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fixtures.js","sourceRoot":"","sources":["../../tests/fixtures.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAU1B,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,KAAa,EACb,MAAc,EACd,WAAuC,WAAW;IAElD,MAAM,QAAQ,GAAG,KAAK,CAAC;QACrB,MAAM,EAAE;YACN,KAAK;YACL,MAAM;YACN,QAAQ,EAAE,CAAC;YACX,UAAU,EAAE,OAAO;SACpB;KACF,CAAC,CAAC;IACH,MAAM,GAAG,GAAG,QAAQ,KAAK,YAAY,CAAC,CAAC,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,MAAM,QAAQ,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC;IAC3G,OAAO;QACL,QAAQ;QACR,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAC9B,KAAK;QACL,MAAM;QACN,MAAM,EAAE,GAAG;KACZ,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grounding.test.d.ts","sourceRoot":"","sources":["../../tests/grounding.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { normalizeBBox, denormalizeBBox, iou, mergeBoxes, } from "../src/grounding/bbox.js";
|
|
3
|
+
describe("bbox grounding", () => {
|
|
4
|
+
const pageSize = { width: 800, height: 1200 };
|
|
5
|
+
describe("normalizeBBox / denormalizeBBox", () => {
|
|
6
|
+
it("normalizes absolute pixel coordinates to [ymin, xmin, ymax, xmax]", () => {
|
|
7
|
+
const box = { x1: 200, y1: 300, x2: 400, y2: 600 };
|
|
8
|
+
const normalized = normalizeBBox(box, pageSize);
|
|
9
|
+
expect(normalized).toEqual([
|
|
10
|
+
300 / 1200,
|
|
11
|
+
200 / 800,
|
|
12
|
+
600 / 1200,
|
|
13
|
+
400 / 800,
|
|
14
|
+
]);
|
|
15
|
+
});
|
|
16
|
+
it("round-trips through denormalize", () => {
|
|
17
|
+
const box = { x1: 100, y1: 150, x2: 300, y2: 450 };
|
|
18
|
+
const normalized = normalizeBBox(box, pageSize);
|
|
19
|
+
const denormalized = denormalizeBBox(normalized, pageSize);
|
|
20
|
+
expect(denormalized.x1).toBeCloseTo(box.x1);
|
|
21
|
+
expect(denormalized.y1).toBeCloseTo(box.y1);
|
|
22
|
+
expect(denormalized.x2).toBeCloseTo(box.x2);
|
|
23
|
+
expect(denormalized.y2).toBeCloseTo(box.y2);
|
|
24
|
+
});
|
|
25
|
+
it("normalizes inverted absolute boxes", () => {
|
|
26
|
+
const box = { x1: 400, y1: 600, x2: 200, y2: 300 };
|
|
27
|
+
const normalized = normalizeBBox(box, pageSize);
|
|
28
|
+
expect(normalized).toEqual([
|
|
29
|
+
300 / 1200,
|
|
30
|
+
200 / 800,
|
|
31
|
+
600 / 1200,
|
|
32
|
+
400 / 800,
|
|
33
|
+
]);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
describe("iou", () => {
|
|
37
|
+
it("returns 1.0 for identical boxes", () => {
|
|
38
|
+
const a = [0.1, 0.1, 0.5, 0.5];
|
|
39
|
+
const b = [0.1, 0.1, 0.5, 0.5];
|
|
40
|
+
expect(iou(a, b)).toBe(1);
|
|
41
|
+
});
|
|
42
|
+
it("returns 0.0 for non-overlapping boxes", () => {
|
|
43
|
+
const a = [0, 0, 0.2, 0.2];
|
|
44
|
+
const b = [0.3, 0.3, 0.5, 0.5];
|
|
45
|
+
expect(iou(a, b)).toBe(0);
|
|
46
|
+
});
|
|
47
|
+
it("returns the correct overlap ratio for partial overlap", () => {
|
|
48
|
+
const a = [0, 0, 0.5, 0.5];
|
|
49
|
+
const b = [0.25, 0.25, 0.75, 0.75];
|
|
50
|
+
// Intersection area: 0.25 * 0.25 = 0.0625
|
|
51
|
+
// Union area: 0.25 + 0.25 - 0.0625 = 0.4375
|
|
52
|
+
// IoU: 0.0625 / 0.4375 ≈ 0.1428
|
|
53
|
+
expect(iou(a, b)).toBeCloseTo(0.0625 / 0.4375, 4);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
describe("mergeBoxes", () => {
|
|
57
|
+
it("merges two overlapping boxes", () => {
|
|
58
|
+
// Box b is almost fully inside a, producing a high IoU (>0.5).
|
|
59
|
+
const a = [0, 0, 0.5, 0.5];
|
|
60
|
+
const b = [0.1, 0.1, 0.5, 0.5];
|
|
61
|
+
const merged = mergeBoxes([a, b], 0.5);
|
|
62
|
+
expect(merged).toHaveLength(1);
|
|
63
|
+
expect(merged[0]).toEqual([0, 0, 0.5, 0.5]);
|
|
64
|
+
});
|
|
65
|
+
it("does not merge boxes below the IoU threshold", () => {
|
|
66
|
+
const a = [0, 0, 0.1, 0.1];
|
|
67
|
+
const b = [0.2, 0.2, 0.3, 0.3];
|
|
68
|
+
const merged = mergeBoxes([a, b], 0.5);
|
|
69
|
+
expect(merged).toHaveLength(2);
|
|
70
|
+
});
|
|
71
|
+
it("chains merges across multiple boxes", () => {
|
|
72
|
+
// Three boxes with high mutual overlap (>0.5 IoU) that should collapse into one.
|
|
73
|
+
const a = [0, 0, 0.5, 0.5];
|
|
74
|
+
const b = [0, 0, 0.45, 0.45];
|
|
75
|
+
const c = [0.05, 0.05, 0.5, 0.5];
|
|
76
|
+
const merged = mergeBoxes([a, b, c], 0.5);
|
|
77
|
+
expect(merged).toHaveLength(1);
|
|
78
|
+
expect(merged[0]).toEqual([0, 0, 0.5, 0.5]);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
//# sourceMappingURL=grounding.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grounding.test.js","sourceRoot":"","sources":["../../tests/grounding.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multi-domain.test.d.ts","sourceRoot":"","sources":["../../tests/multi-domain.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeAll } from "vitest";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { DocumentExtractor } from "../src/core/extractor.js";
|
|
4
|
+
import { compileZodToJsonSchema } from "../src/compiler/zod-compiler.js";
|
|
5
|
+
import { createBlankImage } from "./fixtures.js";
|
|
6
|
+
const LegalContractSchema = z.object({
|
|
7
|
+
contractNumber: z.string(),
|
|
8
|
+
parties: z.object({
|
|
9
|
+
client: z.string(),
|
|
10
|
+
contractor: z.string(),
|
|
11
|
+
}),
|
|
12
|
+
effectiveDate: z.string(),
|
|
13
|
+
termYears: z.number(),
|
|
14
|
+
clauseCount: z.number(),
|
|
15
|
+
penaltyAmount: z.number(),
|
|
16
|
+
});
|
|
17
|
+
const EngineeringSpecSchema = z.object({
|
|
18
|
+
project: z.string(),
|
|
19
|
+
revision: z.string(),
|
|
20
|
+
material: z.string(),
|
|
21
|
+
dimensions: z.object({
|
|
22
|
+
length: z.number(),
|
|
23
|
+
width: z.number(),
|
|
24
|
+
height: z.number(),
|
|
25
|
+
}),
|
|
26
|
+
tolerances: z.object({
|
|
27
|
+
linear: z.number(),
|
|
28
|
+
angular: z.number(),
|
|
29
|
+
}),
|
|
30
|
+
testResults: z.array(z.object({
|
|
31
|
+
test: z.string(),
|
|
32
|
+
passed: z.boolean(),
|
|
33
|
+
value: z.number(),
|
|
34
|
+
})),
|
|
35
|
+
});
|
|
36
|
+
const ClinicalReportSchema = z.object({
|
|
37
|
+
patient: z.object({
|
|
38
|
+
name: z.string(),
|
|
39
|
+
id: z.string(),
|
|
40
|
+
dob: z.string(),
|
|
41
|
+
}),
|
|
42
|
+
reportDate: z.string(),
|
|
43
|
+
biomarkers: z.array(z.object({
|
|
44
|
+
marker: z.string(),
|
|
45
|
+
value: z.number(),
|
|
46
|
+
unit: z.string(),
|
|
47
|
+
referenceRange: z.string(),
|
|
48
|
+
})),
|
|
49
|
+
});
|
|
50
|
+
function mockProvider(responseData) {
|
|
51
|
+
return {
|
|
52
|
+
name: "mock",
|
|
53
|
+
extract: vi.fn().mockResolvedValue({
|
|
54
|
+
text: JSON.stringify({ data: responseData, groundings: [] }),
|
|
55
|
+
raw: null,
|
|
56
|
+
}),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
describe("Multi-Domain Extraction", () => {
|
|
60
|
+
let image;
|
|
61
|
+
beforeAll(async () => {
|
|
62
|
+
image = await createBlankImage(800, 600);
|
|
63
|
+
});
|
|
64
|
+
it("compiles heterogeneous Zod schemas to valid JSON Schema", () => {
|
|
65
|
+
expect(compileZodToJsonSchema(LegalContractSchema)).toMatchObject({ type: "object" });
|
|
66
|
+
expect(compileZodToJsonSchema(EngineeringSpecSchema)).toMatchObject({ type: "object" });
|
|
67
|
+
expect(compileZodToJsonSchema(ClinicalReportSchema)).toMatchObject({ type: "object" });
|
|
68
|
+
});
|
|
69
|
+
it("extracts a Legal Contract", async () => {
|
|
70
|
+
const data = {
|
|
71
|
+
contractNumber: "CNT-2026-001",
|
|
72
|
+
parties: { client: "Acme Corp", contractor: "BuildRight LLC" },
|
|
73
|
+
effectiveDate: "2026-01-15",
|
|
74
|
+
termYears: 3,
|
|
75
|
+
clauseCount: 12,
|
|
76
|
+
penaltyAmount: 50000,
|
|
77
|
+
};
|
|
78
|
+
const extractor = new DocumentExtractor({ customVLM: mockProvider(data) });
|
|
79
|
+
const result = await extractor.extract(image.buffer, LegalContractSchema, { tiling: "off" });
|
|
80
|
+
expect(result.data).toEqual(data);
|
|
81
|
+
expect(result.data.parties.client).toBe("Acme Corp");
|
|
82
|
+
expect(result.confidence).toBeGreaterThan(0);
|
|
83
|
+
});
|
|
84
|
+
it("extracts an Engineering Spec", async () => {
|
|
85
|
+
const data = {
|
|
86
|
+
project: "Brigde-Alpha",
|
|
87
|
+
revision: "Rev-C",
|
|
88
|
+
material: "Steel S355",
|
|
89
|
+
dimensions: { length: 1200, width: 400, height: 80 },
|
|
90
|
+
tolerances: { linear: 0.5, angular: 0.25 },
|
|
91
|
+
testResults: [
|
|
92
|
+
{ test: "Tensile", passed: true, value: 520 },
|
|
93
|
+
{ test: "Compression", passed: true, value: 410 },
|
|
94
|
+
],
|
|
95
|
+
};
|
|
96
|
+
const extractor = new DocumentExtractor({ customVLM: mockProvider(data) });
|
|
97
|
+
const result = await extractor.extract(image.buffer, EngineeringSpecSchema, { tiling: "off" });
|
|
98
|
+
expect(result.data.project).toBe("Brigde-Alpha");
|
|
99
|
+
expect(result.data.dimensions.height).toBe(80);
|
|
100
|
+
expect(result.data.testResults).toHaveLength(2);
|
|
101
|
+
});
|
|
102
|
+
it("extracts a Clinical Report with biomarkers", async () => {
|
|
103
|
+
const data = {
|
|
104
|
+
patient: { name: "John Doe", id: "PAT-987654", dob: "1985-03-15" },
|
|
105
|
+
reportDate: "2026-08-30",
|
|
106
|
+
biomarkers: [
|
|
107
|
+
{ marker: "Glucose", value: 95, unit: "mg/dL", referenceRange: "70 - 100" },
|
|
108
|
+
{ marker: "LDL", value: 110, unit: "mg/dL", referenceRange: "< 130" },
|
|
109
|
+
],
|
|
110
|
+
};
|
|
111
|
+
const extractor = new DocumentExtractor({ customVLM: mockProvider(data) });
|
|
112
|
+
const result = await extractor.extract(image.buffer, ClinicalReportSchema, { tiling: "off" });
|
|
113
|
+
expect(result.data.patient.name).toBe("John Doe");
|
|
114
|
+
expect(result.data.biomarkers[0].marker).toBe("Glucose");
|
|
115
|
+
expect(result.data.biomarkers).toHaveLength(2);
|
|
116
|
+
});
|
|
117
|
+
it("runs invariants across domains", async () => {
|
|
118
|
+
const data = {
|
|
119
|
+
contractNumber: "CNT-2026-002",
|
|
120
|
+
parties: { client: "Client A", contractor: "Contractor B" },
|
|
121
|
+
effectiveDate: "2026-02-01",
|
|
122
|
+
termYears: 2,
|
|
123
|
+
clauseCount: 8,
|
|
124
|
+
penaltyAmount: 10000,
|
|
125
|
+
};
|
|
126
|
+
const extractor = new DocumentExtractor({ customVLM: mockProvider(data) });
|
|
127
|
+
const result = await extractor.extract(image.buffer, LegalContractSchema, {
|
|
128
|
+
tiling: "off",
|
|
129
|
+
prove: true,
|
|
130
|
+
invariants: [{ id: "min-clauses", expression: "clauseCount >= 5" }],
|
|
131
|
+
});
|
|
132
|
+
expect(result.invariants?.ok).toBe(true);
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
//# sourceMappingURL=multi-domain.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multi-domain.test.js","sourceRoot":"","sources":["../../tests/multi-domain.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"normalizer.test.d.ts","sourceRoot":"","sources":["../../tests/normalizer.test.ts"],"names":[],"mappings":""}
|