@pdf-testkit/core 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/dist/diff/diff.d.ts +9 -0
- package/dist/diff/diff.d.ts.map +1 -0
- package/dist/diff/diff.js +139 -0
- package/dist/diff/diff.js.map +1 -0
- package/dist/diff/match.d.ts +21 -0
- package/dist/diff/match.d.ts.map +1 -0
- package/dist/diff/match.js +133 -0
- package/dist/diff/match.js.map +1 -0
- package/dist/events.d.ts +79 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +11 -0
- package/dist/events.js.map +1 -0
- package/dist/extract/finalize.d.ts +16 -0
- package/dist/extract/finalize.d.ts.map +1 -0
- package/dist/extract/finalize.js +88 -0
- package/dist/extract/finalize.js.map +1 -0
- package/dist/extract/fromFormeLayout.d.ts +82 -0
- package/dist/extract/fromFormeLayout.d.ts.map +1 -0
- package/dist/extract/fromFormeLayout.js +324 -0
- package/dist/extract/fromFormeLayout.js.map +1 -0
- package/dist/extract/fromPdf.d.ts +15 -0
- package/dist/extract/fromPdf.d.ts.map +1 -0
- package/dist/extract/fromPdf.js +120 -0
- package/dist/extract/fromPdf.js.map +1 -0
- package/dist/extract/pdfjs/headings.d.ts +16 -0
- package/dist/extract/pdfjs/headings.d.ts.map +1 -0
- package/dist/extract/pdfjs/headings.js +39 -0
- package/dist/extract/pdfjs/headings.js.map +1 -0
- package/dist/extract/pdfjs/loadDocument.d.ts +32 -0
- package/dist/extract/pdfjs/loadDocument.d.ts.map +1 -0
- package/dist/extract/pdfjs/loadDocument.js +45 -0
- package/dist/extract/pdfjs/loadDocument.js.map +1 -0
- package/dist/extract/pdfjs/overflow.d.ts +16 -0
- package/dist/extract/pdfjs/overflow.d.ts.map +1 -0
- package/dist/extract/pdfjs/overflow.js +35 -0
- package/dist/extract/pdfjs/overflow.js.map +1 -0
- package/dist/extract/pdfjs/tables.d.ts +31 -0
- package/dist/extract/pdfjs/tables.d.ts.map +1 -0
- package/dist/extract/pdfjs/tables.js +142 -0
- package/dist/extract/pdfjs/tables.js.map +1 -0
- package/dist/extract/pdfjs/textRuns.d.ts +26 -0
- package/dist/extract/pdfjs/textRuns.d.ts.map +1 -0
- package/dist/extract/pdfjs/textRuns.js +69 -0
- package/dist/extract/pdfjs/textRuns.js.map +1 -0
- package/dist/extract/raw.d.ts +29 -0
- package/dist/extract/raw.d.ts.map +1 -0
- package/dist/extract/raw.js +2 -0
- package/dist/extract/raw.js.map +1 -0
- package/dist/geometry.d.ts +13 -0
- package/dist/geometry.d.ts.map +1 -0
- package/dist/geometry.js +41 -0
- package/dist/geometry.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/snapshot/io.d.ts +4 -0
- package/dist/snapshot/io.d.ts.map +1 -0
- package/dist/snapshot/io.js +12 -0
- package/dist/snapshot/io.js.map +1 -0
- package/dist/snapshot/load.d.ts +9 -0
- package/dist/snapshot/load.d.ts.map +1 -0
- package/dist/snapshot/load.js +25 -0
- package/dist/snapshot/load.js.map +1 -0
- package/dist/snapshot/serialize.d.ts +14 -0
- package/dist/snapshot/serialize.d.ts.map +1 -0
- package/dist/snapshot/serialize.js +31 -0
- package/dist/snapshot/serialize.js.map +1 -0
- package/dist/text/headingLevels.d.ts +11 -0
- package/dist/text/headingLevels.d.ts.map +1 -0
- package/dist/text/headingLevels.js +40 -0
- package/dist/text/headingLevels.js.map +1 -0
- package/dist/text/normalize.d.ts +17 -0
- package/dist/text/normalize.d.ts.map +1 -0
- package/dist/text/normalize.js +67 -0
- package/dist/text/normalize.js.map +1 -0
- package/dist/types.d.ts +85 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/package.json +41 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
/** Deterministic JSON with recursively sorted object keys. */
|
|
3
|
+
export function stableStringify(value) {
|
|
4
|
+
return JSON.stringify(sortKeys(value));
|
|
5
|
+
}
|
|
6
|
+
function sortKeys(value) {
|
|
7
|
+
if (Array.isArray(value))
|
|
8
|
+
return value.map(sortKeys);
|
|
9
|
+
if (value && typeof value === 'object') {
|
|
10
|
+
const out = {};
|
|
11
|
+
for (const key of Object.keys(value).sort()) {
|
|
12
|
+
out[key] = sortKeys(value[key]);
|
|
13
|
+
}
|
|
14
|
+
return out;
|
|
15
|
+
}
|
|
16
|
+
return value;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Content hash over everything that describes the document structure, excluding
|
|
20
|
+
* volatile/derived fields (`createdAt`, `contentHash` itself, and reporting-only
|
|
21
|
+
* `source`). Identical structure -> identical hash, which lets the matcher and
|
|
22
|
+
* CLI short-circuit to "no change".
|
|
23
|
+
*/
|
|
24
|
+
export function computeContentHash(snapshot) {
|
|
25
|
+
const { createdAt: _createdAt, source: _source, contentHash: _hash, ...rest } = snapshot;
|
|
26
|
+
return 'sha256:' + createHash('sha256').update(stableStringify(rest)).digest('hex');
|
|
27
|
+
}
|
|
28
|
+
export function serializeSnapshot(snapshot, pretty = true) {
|
|
29
|
+
return JSON.stringify(snapshot, null, pretty ? 2 : undefined);
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=serialize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialize.js","sourceRoot":"","sources":["../../src/snapshot/serialize.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGzC,8DAA8D;AAC9D,MAAM,UAAU,eAAe,CAAC,KAAc;IAC5C,OAAO,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;AACzC,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACrD,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACvC,MAAM,GAAG,GAA4B,EAAE,CAAC;QACxC,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,KAAgC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;YACvE,GAAG,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAE,KAAiC,CAAC,GAAG,CAAC,CAAC,CAAC;QAC/D,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAChC,QAA4E;IAE5E,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,GAAG,IAAI,EAAE,GAAG,QAAQ,CAAC;IACzF,OAAO,SAAS,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACtF,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,QAA4B,EAAE,MAAM,GAAG,IAAI;IAC3E,OAAO,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;AAChE,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Given the set of font sizes that belong to headings, return a function that
|
|
3
|
+
* maps a font size to a heading level 1..6. Distinct sizes are clustered (0.5pt
|
|
4
|
+
* tolerance) and ranked largest-first: the biggest tier is H1.
|
|
5
|
+
*
|
|
6
|
+
* Both extractors share this. For FormePDF the input is the sizes of nodes
|
|
7
|
+
* already known to be headings; for pdfjs it is the candidate sizes surfaced by
|
|
8
|
+
* font-size clustering.
|
|
9
|
+
*/
|
|
10
|
+
export declare function buildHeadingLevelMap(sizes: number[]): (size: number) => number;
|
|
11
|
+
//# sourceMappingURL=headingLevels.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"headingLevels.d.ts","sourceRoot":"","sources":["../../src/text/headingLevels.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAe9E"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { round1 } from '../geometry.js';
|
|
2
|
+
/**
|
|
3
|
+
* Given the set of font sizes that belong to headings, return a function that
|
|
4
|
+
* maps a font size to a heading level 1..6. Distinct sizes are clustered (0.5pt
|
|
5
|
+
* tolerance) and ranked largest-first: the biggest tier is H1.
|
|
6
|
+
*
|
|
7
|
+
* Both extractors share this. For FormePDF the input is the sizes of nodes
|
|
8
|
+
* already known to be headings; for pdfjs it is the candidate sizes surfaced by
|
|
9
|
+
* font-size clustering.
|
|
10
|
+
*/
|
|
11
|
+
export function buildHeadingLevelMap(sizes) {
|
|
12
|
+
const tiers = clusterTiers(sizes);
|
|
13
|
+
return (size) => {
|
|
14
|
+
if (tiers.length === 0)
|
|
15
|
+
return 1;
|
|
16
|
+
let bestI = 0;
|
|
17
|
+
let bestD = Infinity;
|
|
18
|
+
for (let i = 0; i < tiers.length; i++) {
|
|
19
|
+
const d = Math.abs(tiers[i] - size);
|
|
20
|
+
if (d < bestD) {
|
|
21
|
+
bestD = d;
|
|
22
|
+
bestI = i;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return Math.min(bestI + 1, 6);
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/** Descending, de-duplicated size tiers (sizes within 0.5pt collapse to one). */
|
|
29
|
+
function clusterTiers(sizes) {
|
|
30
|
+
const uniq = [...new Set(sizes.map(round1))].sort((a, b) => b - a);
|
|
31
|
+
const tiers = [];
|
|
32
|
+
for (const s of uniq) {
|
|
33
|
+
const last = tiers[tiers.length - 1];
|
|
34
|
+
if (last !== undefined && Math.abs(last - s) <= 0.5)
|
|
35
|
+
continue;
|
|
36
|
+
tiers.push(s);
|
|
37
|
+
}
|
|
38
|
+
return tiers;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=headingLevels.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"headingLevels.js","sourceRoot":"","sources":["../../src/text/headingLevels.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAExC;;;;;;;;GAQG;AACH,MAAM,UAAU,oBAAoB,CAAC,KAAe;IAClD,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;IAClC,OAAO,CAAC,IAAY,EAAU,EAAE;QAC9B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,CAAC,CAAC;QACjC,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,IAAI,KAAK,GAAG,QAAQ,CAAC;QACrB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACtC,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAE,KAAK,CAAC,CAAC,CAAY,GAAG,IAAI,CAAC,CAAC;YAChD,IAAI,CAAC,GAAG,KAAK,EAAE,CAAC;gBACd,KAAK,GAAG,CAAC,CAAC;gBACV,KAAK,GAAG,CAAC,CAAC;YACZ,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IAChC,CAAC,CAAC;AACJ,CAAC;AAED,iFAAiF;AACjF,SAAS,YAAY,CAAC,KAAe;IACnC,MAAM,IAAI,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACnE,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACrC,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,GAAG;YAAE,SAAS;QAC9D,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAChB,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text normalization used both when building snapshots (`normText`) and when
|
|
3
|
+
* matching nodes across snapshots. Collapsing whitespace + lowercasing is what
|
|
4
|
+
* makes trivial whitespace/case edits read as *unchanged* — a core promise of
|
|
5
|
+
* the tool (see the negative-direction diff tests).
|
|
6
|
+
*/
|
|
7
|
+
export declare function normalizeText(raw: string | null | undefined): string | null;
|
|
8
|
+
/** Short single-line preview of a node's text for event messages. */
|
|
9
|
+
export declare function textPreview(raw: string | null | undefined, max?: number): string;
|
|
10
|
+
/**
|
|
11
|
+
* Similarity in [0,1] between two normalized strings, using token-set Jaccard
|
|
12
|
+
* blended with a length-normalized Levenshtein ratio. Used by the fuzzy match
|
|
13
|
+
* stage to treat a minor text edit (a changed number) as a modification of the
|
|
14
|
+
* same node rather than remove+add.
|
|
15
|
+
*/
|
|
16
|
+
export declare function textSimilarity(a: string, b: string): number;
|
|
17
|
+
//# sourceMappingURL=normalize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../../src/text/normalize.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAI3E;AAED,qEAAqE;AACrE,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,GAAG,SAAK,GAAG,MAAM,CAI5E;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAM3D"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text normalization used both when building snapshots (`normText`) and when
|
|
3
|
+
* matching nodes across snapshots. Collapsing whitespace + lowercasing is what
|
|
4
|
+
* makes trivial whitespace/case edits read as *unchanged* — a core promise of
|
|
5
|
+
* the tool (see the negative-direction diff tests).
|
|
6
|
+
*/
|
|
7
|
+
export function normalizeText(raw) {
|
|
8
|
+
if (raw == null)
|
|
9
|
+
return null;
|
|
10
|
+
const collapsed = raw.replace(/\s+/g, ' ').trim().toLowerCase();
|
|
11
|
+
return collapsed.length === 0 ? null : collapsed;
|
|
12
|
+
}
|
|
13
|
+
/** Short single-line preview of a node's text for event messages. */
|
|
14
|
+
export function textPreview(raw, max = 40) {
|
|
15
|
+
if (!raw)
|
|
16
|
+
return '';
|
|
17
|
+
const oneLine = raw.replace(/\s+/g, ' ').trim();
|
|
18
|
+
return oneLine.length <= max ? oneLine : oneLine.slice(0, max - 1) + '…';
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Similarity in [0,1] between two normalized strings, using token-set Jaccard
|
|
22
|
+
* blended with a length-normalized Levenshtein ratio. Used by the fuzzy match
|
|
23
|
+
* stage to treat a minor text edit (a changed number) as a modification of the
|
|
24
|
+
* same node rather than remove+add.
|
|
25
|
+
*/
|
|
26
|
+
export function textSimilarity(a, b) {
|
|
27
|
+
if (a === b)
|
|
28
|
+
return 1;
|
|
29
|
+
if (a.length === 0 || b.length === 0)
|
|
30
|
+
return 0;
|
|
31
|
+
const jac = jaccard(tokens(a), tokens(b));
|
|
32
|
+
const lev = 1 - levenshtein(a, b) / Math.max(a.length, b.length);
|
|
33
|
+
return Math.max(0, 0.5 * jac + 0.5 * lev);
|
|
34
|
+
}
|
|
35
|
+
function tokens(s) {
|
|
36
|
+
return new Set(s.split(/\s+/).filter(Boolean));
|
|
37
|
+
}
|
|
38
|
+
function jaccard(a, b) {
|
|
39
|
+
if (a.size === 0 && b.size === 0)
|
|
40
|
+
return 1;
|
|
41
|
+
let inter = 0;
|
|
42
|
+
for (const t of a)
|
|
43
|
+
if (b.has(t))
|
|
44
|
+
inter++;
|
|
45
|
+
return inter / (a.size + b.size - inter);
|
|
46
|
+
}
|
|
47
|
+
function levenshtein(a, b) {
|
|
48
|
+
const m = a.length;
|
|
49
|
+
const n = b.length;
|
|
50
|
+
let prev = new Array(n + 1).fill(0);
|
|
51
|
+
let curr = new Array(n + 1).fill(0);
|
|
52
|
+
for (let j = 0; j <= n; j++)
|
|
53
|
+
prev[j] = j;
|
|
54
|
+
for (let i = 1; i <= m; i++) {
|
|
55
|
+
curr[0] = i;
|
|
56
|
+
for (let j = 1; j <= n; j++) {
|
|
57
|
+
const cost = a.charCodeAt(i - 1) === b.charCodeAt(j - 1) ? 0 : 1;
|
|
58
|
+
const del = prev[j] + 1;
|
|
59
|
+
const ins = curr[j - 1] + 1;
|
|
60
|
+
const sub = prev[j - 1] + cost;
|
|
61
|
+
curr[j] = Math.min(del, ins, sub);
|
|
62
|
+
}
|
|
63
|
+
[prev, curr] = [curr, prev];
|
|
64
|
+
}
|
|
65
|
+
return prev[n];
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=normalize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"normalize.js","sourceRoot":"","sources":["../../src/text/normalize.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The normalized structural model that every extractor produces and the diff
|
|
3
|
+
* engine + matcher consume. This is the architectural crux of pdf-testkit: a
|
|
4
|
+
* flat, producer-agnostic, coordinate-normalized representation of a document's
|
|
5
|
+
* structure (NOT its pixels).
|
|
6
|
+
*/
|
|
7
|
+
export type SnapshotSchemaVersion = 1;
|
|
8
|
+
export type Producer = 'formepdf' | 'pdfjs';
|
|
9
|
+
export type NodeRole = 'text' | 'heading' | 'table' | 'row' | 'cell' | 'image' | 'container';
|
|
10
|
+
/** Axis-aligned bounding box. Top-left origin, points, rounded to 0.1pt. */
|
|
11
|
+
export interface BBox {
|
|
12
|
+
x: number;
|
|
13
|
+
y: number;
|
|
14
|
+
width: number;
|
|
15
|
+
height: number;
|
|
16
|
+
}
|
|
17
|
+
export interface FontInfo {
|
|
18
|
+
/** Point size, rounded to 0.1. `null` when unknown. */
|
|
19
|
+
size: number | null;
|
|
20
|
+
/** 100..900. pdfjs infers 700 from a bold-ish font name, else 400. */
|
|
21
|
+
weight: number | null;
|
|
22
|
+
/** May be a subset name from pdfjs (e.g. "ABCDEE+Helvetica"). */
|
|
23
|
+
family: string | null;
|
|
24
|
+
italic?: boolean;
|
|
25
|
+
}
|
|
26
|
+
export interface OverflowInfo {
|
|
27
|
+
axis: 'x' | 'y' | 'both';
|
|
28
|
+
/** How far past the container box, in points, rounded to 0.1 (max axis). */
|
|
29
|
+
overflowPts: number;
|
|
30
|
+
container: 'page-content' | 'parent';
|
|
31
|
+
}
|
|
32
|
+
export interface StructuralNode {
|
|
33
|
+
/** Stable within a snapshot: `${pageIndex}:${role}:${ordinal}`. */
|
|
34
|
+
id: string;
|
|
35
|
+
role: NodeRole;
|
|
36
|
+
/** 0-based page index. */
|
|
37
|
+
pageIndex: number;
|
|
38
|
+
bbox: BBox;
|
|
39
|
+
/** Reading order within the page (top-to-bottom by y-band, then left-to-right). */
|
|
40
|
+
order: number;
|
|
41
|
+
/** For nesting: cell -> row -> table. `null` at the top level. */
|
|
42
|
+
parentId: string | null;
|
|
43
|
+
/** Raw concatenated text; `null` for containers/images. */
|
|
44
|
+
text: string | null;
|
|
45
|
+
/** Normalized text (trimmed, whitespace-collapsed, lowercased); `null` if empty. */
|
|
46
|
+
normText: string | null;
|
|
47
|
+
font: FontInfo | null;
|
|
48
|
+
/** 1..6 when role === 'heading', else null. */
|
|
49
|
+
headingLevel: number | null;
|
|
50
|
+
/** Set when this node's bbox exceeds its container. */
|
|
51
|
+
overflow: OverflowInfo | null;
|
|
52
|
+
/** Summary for table nodes so table diffs don't require walking children. */
|
|
53
|
+
table?: {
|
|
54
|
+
rows: number;
|
|
55
|
+
cols: number;
|
|
56
|
+
};
|
|
57
|
+
/** 0..1 — 1.0 for authoritative (FormePDF) roles, <1 for pdfjs-inferred. */
|
|
58
|
+
confidence: number;
|
|
59
|
+
}
|
|
60
|
+
export interface PageSnapshot {
|
|
61
|
+
index: number;
|
|
62
|
+
width: number;
|
|
63
|
+
height: number;
|
|
64
|
+
/** FormePDF: the real content box. pdfjs: an inferred margin box. */
|
|
65
|
+
contentBox: BBox;
|
|
66
|
+
/** Ids of nodes on this page, in reading order. */
|
|
67
|
+
nodeIds: string[];
|
|
68
|
+
}
|
|
69
|
+
export interface StructuralSnapshot {
|
|
70
|
+
version: SnapshotSchemaVersion;
|
|
71
|
+
producer: Producer;
|
|
72
|
+
/** ISO timestamp; excluded from the diff and from `contentHash`. */
|
|
73
|
+
createdAt: string;
|
|
74
|
+
/** Reporting-only provenance (e.g. original filename). */
|
|
75
|
+
source?: {
|
|
76
|
+
name?: string;
|
|
77
|
+
};
|
|
78
|
+
pageCount: number;
|
|
79
|
+
pages: PageSnapshot[];
|
|
80
|
+
/** All nodes, all pages, flat. */
|
|
81
|
+
nodes: StructuralNode[];
|
|
82
|
+
/** `sha256:...` over the canonical serialization, excluding createdAt. */
|
|
83
|
+
contentHash: string;
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC;AAEtC,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG,OAAO,CAAC;AAE5C,MAAM,MAAM,QAAQ,GAChB,MAAM,GACN,SAAS,GACT,OAAO,GACP,KAAK,GACL,MAAM,GACN,OAAO,GACP,WAAW,CAAC;AAEhB,4EAA4E;AAC5E,MAAM,WAAW,IAAI;IACnB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,QAAQ;IACvB,uDAAuD;IACvD,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,sEAAsE;IACtE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,iEAAiE;IACjE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,GAAG,GAAG,GAAG,GAAG,MAAM,CAAC;IACzB,4EAA4E;IAC5E,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,cAAc,GAAG,QAAQ,CAAC;CACtC;AAED,MAAM,WAAW,cAAc;IAC7B,mEAAmE;IACnE,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,QAAQ,CAAC;IACf,0BAA0B;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,IAAI,CAAC;IACX,mFAAmF;IACnF,KAAK,EAAE,MAAM,CAAC;IACd,kEAAkE;IAClE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,2DAA2D;IAC3D,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,oFAAoF;IACpF,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAC;IACtB,+CAA+C;IAC/C,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,uDAAuD;IACvD,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAC;IAC9B,6EAA6E;IAC7E,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACvC,4EAA4E;IAC5E,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,UAAU,EAAE,IAAI,CAAC;IACjB,mDAAmD;IACnD,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,qBAAqB,CAAC;IAC/B,QAAQ,EAAE,QAAQ,CAAC;IACnB,oEAAoE;IACpE,SAAS,EAAE,MAAM,CAAC;IAClB,0DAA0D;IAC1D,MAAM,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,kCAAkC;IAClC,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,0EAA0E;IAC1E,WAAW,EAAE,MAAM,CAAC;CACrB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The normalized structural model that every extractor produces and the diff
|
|
3
|
+
* engine + matcher consume. This is the architectural crux of pdf-testkit: a
|
|
4
|
+
* flat, producer-agnostic, coordinate-normalized representation of a document's
|
|
5
|
+
* structure (NOT its pixels).
|
|
6
|
+
*/
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@pdf-testkit/core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Semantic structural model, extractors, and diff engine for pdf-testkit",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsc --build",
|
|
20
|
+
"test": "vitest run"
|
|
21
|
+
},
|
|
22
|
+
"peerDependencies": {
|
|
23
|
+
"@formepdf/core": "*",
|
|
24
|
+
"pdfjs-dist": "^4.10 || ^5"
|
|
25
|
+
},
|
|
26
|
+
"peerDependenciesMeta": {
|
|
27
|
+
"@formepdf/core": {
|
|
28
|
+
"optional": true
|
|
29
|
+
},
|
|
30
|
+
"pdfjs-dist": {
|
|
31
|
+
"optional": true
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@formepdf/core": "0.12.1",
|
|
36
|
+
"pdfjs-dist": "^4.10.38"
|
|
37
|
+
},
|
|
38
|
+
"publishConfig": {
|
|
39
|
+
"access": "public"
|
|
40
|
+
}
|
|
41
|
+
}
|