@heripo/document-processor 0.1.27 → 0.1.29
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/README.ko.md +71 -9
- package/README.md +87 -9
- package/dist/index.cjs +295 -34
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +84 -7
- package/dist/index.d.ts +84 -7
- package/dist/index.js +294 -34
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -559,6 +559,52 @@ var RefResolver = class {
|
|
|
559
559
|
buildIndex(items, _prefix) {
|
|
560
560
|
return new Map(items.map((item) => [item.self_ref, item]));
|
|
561
561
|
}
|
|
562
|
+
/**
|
|
563
|
+
* Check whether a Docling self reference exists in the indexed document.
|
|
564
|
+
*/
|
|
565
|
+
hasRef(ref) {
|
|
566
|
+
const match = ref.match(/^#\/(\w+)\//);
|
|
567
|
+
if (!match) {
|
|
568
|
+
return false;
|
|
569
|
+
}
|
|
570
|
+
const collection = match[1];
|
|
571
|
+
if (collection === "texts") {
|
|
572
|
+
return this.textMap.has(ref);
|
|
573
|
+
}
|
|
574
|
+
if (collection === "pictures") {
|
|
575
|
+
return this.pictureMap.has(ref);
|
|
576
|
+
}
|
|
577
|
+
if (collection === "tables") {
|
|
578
|
+
return this.tableMap.has(ref);
|
|
579
|
+
}
|
|
580
|
+
if (collection === "groups") {
|
|
581
|
+
return this.groupMap.has(ref);
|
|
582
|
+
}
|
|
583
|
+
return false;
|
|
584
|
+
}
|
|
585
|
+
/**
|
|
586
|
+
* Assert that a Docling self reference exists in the indexed document.
|
|
587
|
+
*/
|
|
588
|
+
assertRef(ref, context) {
|
|
589
|
+
if (this.hasRef(ref)) {
|
|
590
|
+
return;
|
|
591
|
+
}
|
|
592
|
+
const message = `[RefResolver] Missing source reference in ${context}: ${ref}`;
|
|
593
|
+
this.logger.warn(message);
|
|
594
|
+
throw new Error(message);
|
|
595
|
+
}
|
|
596
|
+
/**
|
|
597
|
+
* Assert that every Docling self reference exists in the indexed document.
|
|
598
|
+
*/
|
|
599
|
+
assertRefs(refs, context) {
|
|
600
|
+
const missingRefs = refs.filter((ref) => !this.hasRef(ref));
|
|
601
|
+
if (missingRefs.length === 0) {
|
|
602
|
+
return;
|
|
603
|
+
}
|
|
604
|
+
const message = `[RefResolver] Missing source references in ${context}: ${missingRefs.join(", ")}`;
|
|
605
|
+
this.logger.warn(message);
|
|
606
|
+
throw new Error(message);
|
|
607
|
+
}
|
|
562
608
|
/**
|
|
563
609
|
* Resolve a $ref string to the actual item
|
|
564
610
|
* @param ref - Reference string (e.g., "#/texts/0")
|
|
@@ -650,6 +696,7 @@ var IdGenerator = class {
|
|
|
650
696
|
imageCounter = 0;
|
|
651
697
|
tableCounter = 0;
|
|
652
698
|
footnoteCounter = 0;
|
|
699
|
+
textBlockCounter = 0;
|
|
653
700
|
/**
|
|
654
701
|
* Generate a chapter ID
|
|
655
702
|
* @returns A chapter ID in the format "ch-001"
|
|
@@ -682,6 +729,14 @@ var IdGenerator = class {
|
|
|
682
729
|
this.footnoteCounter++;
|
|
683
730
|
return `ftn-${this.padNumber(this.footnoteCounter)}`;
|
|
684
731
|
}
|
|
732
|
+
/**
|
|
733
|
+
* Generate a text block ID
|
|
734
|
+
* @returns A text block ID in the format "txt-001"
|
|
735
|
+
*/
|
|
736
|
+
generateTextBlockId() {
|
|
737
|
+
this.textBlockCounter++;
|
|
738
|
+
return `txt-${this.padNumber(this.textBlockCounter)}`;
|
|
739
|
+
}
|
|
685
740
|
/**
|
|
686
741
|
* Reset all counters to zero
|
|
687
742
|
*/
|
|
@@ -690,6 +745,7 @@ var IdGenerator = class {
|
|
|
690
745
|
this.imageCounter = 0;
|
|
691
746
|
this.tableCounter = 0;
|
|
692
747
|
this.footnoteCounter = 0;
|
|
748
|
+
this.textBlockCounter = 0;
|
|
693
749
|
}
|
|
694
750
|
/**
|
|
695
751
|
* Get current counter values (for testing/debugging)
|
|
@@ -699,7 +755,8 @@ var IdGenerator = class {
|
|
|
699
755
|
chapter: this.chapterCounter,
|
|
700
756
|
image: this.imageCounter,
|
|
701
757
|
table: this.tableCounter,
|
|
702
|
-
footnote: this.footnoteCounter
|
|
758
|
+
footnote: this.footnoteCounter,
|
|
759
|
+
textBlock: this.textBlockCounter
|
|
703
760
|
};
|
|
704
761
|
}
|
|
705
762
|
/**
|
|
@@ -1005,6 +1062,7 @@ var ChapterConverter = class _ChapterConverter {
|
|
|
1005
1062
|
title: _ChapterConverter.FRONT_MATTER_TITLE,
|
|
1006
1063
|
pageNo: 1,
|
|
1007
1064
|
level: 1,
|
|
1065
|
+
sourceRefs: [],
|
|
1008
1066
|
textBlocks: [],
|
|
1009
1067
|
imageIds: [],
|
|
1010
1068
|
tableIds: [],
|
|
@@ -1024,6 +1082,7 @@ var ChapterConverter = class _ChapterConverter {
|
|
|
1024
1082
|
title: TextCleaner.normalize(entry.title),
|
|
1025
1083
|
pageNo: entry.pageNo,
|
|
1026
1084
|
level: entry.level,
|
|
1085
|
+
sourceRefs: entry.sourceRefs ?? [],
|
|
1027
1086
|
textBlocks: [],
|
|
1028
1087
|
imageIds: [],
|
|
1029
1088
|
tableIds: [],
|
|
@@ -1114,6 +1173,8 @@ var ChapterConverter = class _ChapterConverter {
|
|
|
1114
1173
|
).map((item) => {
|
|
1115
1174
|
const pdfPageNo = item.prov?.[0]?.page_no ?? 1;
|
|
1116
1175
|
return {
|
|
1176
|
+
id: this.idGenerator.generateTextBlockId(),
|
|
1177
|
+
sourceRef: item.self_ref,
|
|
1117
1178
|
text: TextCleaner.normalize(item.text),
|
|
1118
1179
|
pdfPageNo
|
|
1119
1180
|
};
|
|
@@ -1218,6 +1279,84 @@ var ChapterConverter = class _ChapterConverter {
|
|
|
1218
1279
|
};
|
|
1219
1280
|
|
|
1220
1281
|
// src/converters/resource-converter.ts
|
|
1282
|
+
function getFiniteNumber(value) {
|
|
1283
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
1284
|
+
}
|
|
1285
|
+
function getRowSpan(cell) {
|
|
1286
|
+
const startRow = getFiniteNumber(cell.start_row_offset_idx);
|
|
1287
|
+
const endRow = getFiniteNumber(cell.end_row_offset_idx);
|
|
1288
|
+
const offsetSpan = startRow !== void 0 && endRow !== void 0 ? endRow - startRow : 0;
|
|
1289
|
+
return Math.max(1, offsetSpan || getFiniteNumber(cell.row_span) || 1);
|
|
1290
|
+
}
|
|
1291
|
+
function getColSpan(cell) {
|
|
1292
|
+
const startCol = getFiniteNumber(cell.start_col_offset_idx);
|
|
1293
|
+
const endCol = getFiniteNumber(cell.end_col_offset_idx);
|
|
1294
|
+
const offsetSpan = startCol !== void 0 && endCol !== void 0 ? endCol - startCol : 0;
|
|
1295
|
+
return Math.max(1, offsetSpan || getFiniteNumber(cell.col_span) || 1);
|
|
1296
|
+
}
|
|
1297
|
+
function convertTableCell(cell) {
|
|
1298
|
+
return {
|
|
1299
|
+
text: cell.text ?? "",
|
|
1300
|
+
rowSpan: getRowSpan(cell),
|
|
1301
|
+
colSpan: getColSpan(cell),
|
|
1302
|
+
isHeader: cell.column_header || cell.row_header || false
|
|
1303
|
+
};
|
|
1304
|
+
}
|
|
1305
|
+
function getAnchorColumn(cell, rowIndex, colIndex) {
|
|
1306
|
+
const startRow = getFiniteNumber(cell.start_row_offset_idx) ?? rowIndex;
|
|
1307
|
+
const startCol = getFiniteNumber(cell.start_col_offset_idx) ?? colIndex;
|
|
1308
|
+
return startRow === rowIndex ? startCol : void 0;
|
|
1309
|
+
}
|
|
1310
|
+
function buildGridFromRawGrid(rawGrid) {
|
|
1311
|
+
return rawGrid.map((row, rowIndex) => {
|
|
1312
|
+
const cellsByColumn = /* @__PURE__ */ new Map();
|
|
1313
|
+
row.forEach((cell, colIndex) => {
|
|
1314
|
+
const anchorColumn = getAnchorColumn(cell, rowIndex, colIndex);
|
|
1315
|
+
if (anchorColumn === void 0 || cellsByColumn.has(anchorColumn)) {
|
|
1316
|
+
return;
|
|
1317
|
+
}
|
|
1318
|
+
cellsByColumn.set(anchorColumn, convertTableCell(cell));
|
|
1319
|
+
});
|
|
1320
|
+
return Array.from(cellsByColumn.entries()).sort(([left], [right]) => left - right).map(([, cell]) => cell);
|
|
1321
|
+
});
|
|
1322
|
+
}
|
|
1323
|
+
function buildGridFromTableCells(tableCells, rowCount) {
|
|
1324
|
+
if (!tableCells || tableCells.length === 0) return [];
|
|
1325
|
+
const maxRow = tableCells.reduce(
|
|
1326
|
+
(max, cell) => Math.max(max, getFiniteNumber(cell.start_row_offset_idx) ?? 0),
|
|
1327
|
+
rowCount - 1
|
|
1328
|
+
) + 1;
|
|
1329
|
+
const rows = Array.from({ length: Math.max(0, maxRow) }, () => []);
|
|
1330
|
+
for (const cell of tableCells) {
|
|
1331
|
+
const row = getFiniteNumber(cell.start_row_offset_idx) ?? 0;
|
|
1332
|
+
const col = getFiniteNumber(cell.start_col_offset_idx) ?? 0;
|
|
1333
|
+
if (row < 0 || row >= rows.length) continue;
|
|
1334
|
+
rows[row].push({ col, cell: convertTableCell(cell) });
|
|
1335
|
+
}
|
|
1336
|
+
return rows.map(
|
|
1337
|
+
(row) => row.sort((a, b) => a.col - b.col).map(({ cell }) => cell)
|
|
1338
|
+
);
|
|
1339
|
+
}
|
|
1340
|
+
function getGridColumnCount(grid) {
|
|
1341
|
+
return grid.reduce(
|
|
1342
|
+
(max, row) => Math.max(
|
|
1343
|
+
max,
|
|
1344
|
+
row.reduce((sum, cell) => sum + Math.max(1, cell.colSpan), 0)
|
|
1345
|
+
),
|
|
1346
|
+
0
|
|
1347
|
+
);
|
|
1348
|
+
}
|
|
1349
|
+
function buildProcessedTableGrid(table) {
|
|
1350
|
+
const rawGrid = table.data.grid ?? [];
|
|
1351
|
+
const rawNumRows = getFiniteNumber(table.data.num_rows);
|
|
1352
|
+
const rawNumCols = getFiniteNumber(table.data.num_cols);
|
|
1353
|
+
const grid = rawGrid.length > 0 ? buildGridFromRawGrid(rawGrid) : buildGridFromTableCells(table.data.table_cells, rawNumRows ?? 0);
|
|
1354
|
+
return {
|
|
1355
|
+
grid,
|
|
1356
|
+
numRows: rawNumRows !== void 0 && rawNumRows > 0 ? rawNumRows : grid.length,
|
|
1357
|
+
numCols: rawNumCols !== void 0 && rawNumCols > 0 ? rawNumCols : getGridColumnCount(grid)
|
|
1358
|
+
};
|
|
1359
|
+
}
|
|
1221
1360
|
var ResourceConverter = class {
|
|
1222
1361
|
logger;
|
|
1223
1362
|
idGenerator;
|
|
@@ -1253,12 +1392,17 @@ var ResourceConverter = class {
|
|
|
1253
1392
|
this.logger.info(
|
|
1254
1393
|
`[ResourceConverter] Converting ${doclingDoc.pictures.length} images...`
|
|
1255
1394
|
);
|
|
1256
|
-
const
|
|
1257
|
-
(picture) => this.captionProcessingPipeline.
|
|
1395
|
+
const captionSources = doclingDoc.pictures.map(
|
|
1396
|
+
(picture) => this.captionProcessingPipeline.extractCaptionSource(picture.captions)
|
|
1397
|
+
);
|
|
1398
|
+
const captionTexts = captionSources.map(
|
|
1399
|
+
(captionSource) => captionSource.text
|
|
1258
1400
|
);
|
|
1259
1401
|
const images = doclingDoc.pictures.map(
|
|
1260
1402
|
(picture, index) => ({
|
|
1261
1403
|
id: this.idGenerator.generateImageId(),
|
|
1404
|
+
sourceRef: picture.self_ref,
|
|
1405
|
+
captionSourceRefs: captionSources[index].sourceRefs,
|
|
1262
1406
|
path: `${artifactDir}/images/image_${index}.png`,
|
|
1263
1407
|
pdfPageNo: picture.prov?.[0]?.page_no ?? 0
|
|
1264
1408
|
})
|
|
@@ -1281,23 +1425,21 @@ var ResourceConverter = class {
|
|
|
1281
1425
|
this.logger.info(
|
|
1282
1426
|
`[ResourceConverter] Converting ${doclingDoc.tables.length} tables...`
|
|
1283
1427
|
);
|
|
1284
|
-
const
|
|
1285
|
-
(table) => this.captionProcessingPipeline.
|
|
1428
|
+
const captionSources = doclingDoc.tables.map(
|
|
1429
|
+
(table) => this.captionProcessingPipeline.extractCaptionSource(table.captions)
|
|
1286
1430
|
);
|
|
1287
|
-
const
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
colSpan: cell.col_span ?? 1,
|
|
1293
|
-
isHeader: cell.column_header || cell.row_header || false
|
|
1294
|
-
}))
|
|
1295
|
-
);
|
|
1431
|
+
const captionTexts = captionSources.map(
|
|
1432
|
+
(captionSource) => captionSource.text
|
|
1433
|
+
);
|
|
1434
|
+
const tables = doclingDoc.tables.map((table, index) => {
|
|
1435
|
+
const { grid, numRows, numCols } = buildProcessedTableGrid(table);
|
|
1296
1436
|
return {
|
|
1297
1437
|
id: this.idGenerator.generateTableId(),
|
|
1438
|
+
sourceRef: table.self_ref,
|
|
1439
|
+
captionSourceRefs: captionSources[index].sourceRefs,
|
|
1298
1440
|
pdfPageNo: table.prov?.[0]?.page_no ?? 0,
|
|
1299
|
-
numRows
|
|
1300
|
-
numCols
|
|
1441
|
+
numRows,
|
|
1442
|
+
numCols,
|
|
1301
1443
|
grid
|
|
1302
1444
|
};
|
|
1303
1445
|
});
|
|
@@ -1324,6 +1466,7 @@ var ResourceConverter = class {
|
|
|
1324
1466
|
);
|
|
1325
1467
|
const footnotes = footnoteItems.filter((item) => TextCleaner.isValidText(item.text)).map((item) => ({
|
|
1326
1468
|
id: this.idGenerator.generateFootnoteId(),
|
|
1469
|
+
sourceRef: item.self_ref,
|
|
1327
1470
|
text: TextCleaner.normalize(item.text),
|
|
1328
1471
|
pdfPageNo: item.prov?.[0]?.page_no ?? 1
|
|
1329
1472
|
}));
|
|
@@ -3623,7 +3766,8 @@ Remember: Look for SMALL numbers in MARGINS only. Ignore figure/table/photo numb
|
|
|
3623
3766
|
};
|
|
3624
3767
|
|
|
3625
3768
|
// src/pipelines/caption-processing-pipeline.ts
|
|
3626
|
-
var CaptionProcessingPipeline = class {
|
|
3769
|
+
var CaptionProcessingPipeline = class _CaptionProcessingPipeline {
|
|
3770
|
+
static CAPTION_JOIN_SEPARATOR = " ";
|
|
3627
3771
|
logger;
|
|
3628
3772
|
captionParser;
|
|
3629
3773
|
captionValidator;
|
|
@@ -3772,23 +3916,51 @@ var CaptionProcessingPipeline = class {
|
|
|
3772
3916
|
return captionsByIndex;
|
|
3773
3917
|
}
|
|
3774
3918
|
/**
|
|
3775
|
-
* Extract caption text from resource
|
|
3919
|
+
* Extract combined caption text from resource captions.
|
|
3920
|
+
*
|
|
3921
|
+
* Returns every caption joined with a single space; empty/whitespace-only
|
|
3922
|
+
* entries are skipped. Returns `undefined` when nothing resolves to text.
|
|
3776
3923
|
*
|
|
3777
|
-
*
|
|
3924
|
+
* @deprecated Use {@link extractCaptionSource} to also receive the
|
|
3925
|
+
* caption `$ref` list. This helper is retained as a thin wrapper for
|
|
3926
|
+
* legacy callers.
|
|
3778
3927
|
*/
|
|
3779
3928
|
extractCaptionText(captions) {
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3929
|
+
return this.extractCaptionSource(captions).text;
|
|
3930
|
+
}
|
|
3931
|
+
/**
|
|
3932
|
+
* Extract caption text and source references from resource captions.
|
|
3933
|
+
*
|
|
3934
|
+
* Iterates captions in order. String captions contribute to text only;
|
|
3935
|
+
* `$ref` captions also push the ref onto `sourceRefs` regardless of whether
|
|
3936
|
+
* the resolver finds text. Resolved/raw text is trimmed, and empty parts
|
|
3937
|
+
* are skipped before joining.
|
|
3938
|
+
*/
|
|
3939
|
+
extractCaptionSource(captions) {
|
|
3940
|
+
const sourceRefs = [];
|
|
3941
|
+
const textParts = [];
|
|
3942
|
+
captions?.forEach((caption) => {
|
|
3943
|
+
if (typeof caption === "string") {
|
|
3944
|
+
const text2 = caption.trim();
|
|
3945
|
+
if (text2.length > 0) {
|
|
3946
|
+
textParts.push(text2);
|
|
3947
|
+
}
|
|
3948
|
+
return;
|
|
3949
|
+
}
|
|
3950
|
+
sourceRefs.push(caption.$ref);
|
|
3951
|
+
const resolved = this.refResolver?.resolveText(caption.$ref);
|
|
3952
|
+
const text = resolved?.text.trim();
|
|
3953
|
+
if (text && text.length > 0) {
|
|
3954
|
+
textParts.push(text);
|
|
3955
|
+
}
|
|
3956
|
+
});
|
|
3957
|
+
if (textParts.length === 0) {
|
|
3958
|
+
return { sourceRefs };
|
|
3790
3959
|
}
|
|
3791
|
-
return
|
|
3960
|
+
return {
|
|
3961
|
+
text: textParts.join(_CaptionProcessingPipeline.CAPTION_JOIN_SEPARATOR),
|
|
3962
|
+
sourceRefs
|
|
3963
|
+
};
|
|
3792
3964
|
}
|
|
3793
3965
|
};
|
|
3794
3966
|
|
|
@@ -4360,6 +4532,7 @@ var CaptionValidationError = class extends Error {
|
|
|
4360
4532
|
};
|
|
4361
4533
|
|
|
4362
4534
|
// src/document-processor.ts
|
|
4535
|
+
var PROCESSED_DOCUMENT_SCHEMA_VERSION = "processed-document.v2";
|
|
4363
4536
|
var DocumentProcessor = class {
|
|
4364
4537
|
logger;
|
|
4365
4538
|
fallbackModel;
|
|
@@ -4510,18 +4683,26 @@ var DocumentProcessor = class {
|
|
|
4510
4683
|
`[DocumentProcessor] Chapter conversion took ${chaptersTime}ms`
|
|
4511
4684
|
);
|
|
4512
4685
|
const startTimeAssemble = Date.now();
|
|
4513
|
-
const processedDoc = this.assembleProcessedDocument(
|
|
4686
|
+
const processedDoc = this.assembleProcessedDocument({
|
|
4514
4687
|
reportId,
|
|
4515
4688
|
pageRangeMap,
|
|
4516
4689
|
chapters,
|
|
4517
4690
|
images,
|
|
4518
4691
|
tables,
|
|
4519
|
-
footnotes
|
|
4520
|
-
|
|
4692
|
+
footnotes,
|
|
4693
|
+
source: processOptions.source
|
|
4694
|
+
});
|
|
4521
4695
|
const assembleTime = Date.now() - startTimeAssemble;
|
|
4522
4696
|
this.logger.info(
|
|
4523
4697
|
`[DocumentProcessor] Document assembly took ${assembleTime}ms`
|
|
4524
4698
|
);
|
|
4699
|
+
const sourceRefValidationMode = this.resolveSourceRefValidationMode(processOptions);
|
|
4700
|
+
if (sourceRefValidationMode !== "off") {
|
|
4701
|
+
this.validateProcessedDocumentSourceRefs(
|
|
4702
|
+
processedDoc,
|
|
4703
|
+
sourceRefValidationMode
|
|
4704
|
+
);
|
|
4705
|
+
}
|
|
4525
4706
|
this.logger.info("[DocumentProcessor] Document processing completed");
|
|
4526
4707
|
return {
|
|
4527
4708
|
document: processedDoc,
|
|
@@ -4660,15 +4841,93 @@ var DocumentProcessor = class {
|
|
|
4660
4841
|
);
|
|
4661
4842
|
return pageRangeMap;
|
|
4662
4843
|
}
|
|
4844
|
+
resolveSourceRefValidationMode(processOptions) {
|
|
4845
|
+
if (processOptions.sourceRefValidationMode !== void 0) {
|
|
4846
|
+
return processOptions.sourceRefValidationMode;
|
|
4847
|
+
}
|
|
4848
|
+
return processOptions.validateSourceRefs === true ? "error" : "off";
|
|
4849
|
+
}
|
|
4850
|
+
validateProcessedDocumentSourceRefs(processedDoc, mode) {
|
|
4851
|
+
if (!this.refResolver) {
|
|
4852
|
+
throw new Error(
|
|
4853
|
+
"[DocumentProcessor] Cannot validate source references before RefResolver initialization"
|
|
4854
|
+
);
|
|
4855
|
+
}
|
|
4856
|
+
const issues = this.collectMissingSourceRefs(
|
|
4857
|
+
processedDoc,
|
|
4858
|
+
this.refResolver
|
|
4859
|
+
);
|
|
4860
|
+
if (issues.length === 0) {
|
|
4861
|
+
this.logger.info(
|
|
4862
|
+
"[DocumentProcessor] Source reference validation passed"
|
|
4863
|
+
);
|
|
4864
|
+
return;
|
|
4865
|
+
}
|
|
4866
|
+
const details = issues.map((issue) => `${issue.context} (${issue.ref})`).join("; ");
|
|
4867
|
+
const message = `[DocumentProcessor] Source reference validation found ${issues.length} missing reference(s): ${details}`;
|
|
4868
|
+
if (mode === "warn") {
|
|
4869
|
+
this.logger.warn(message);
|
|
4870
|
+
return;
|
|
4871
|
+
}
|
|
4872
|
+
this.logger.error(message);
|
|
4873
|
+
throw new Error(message);
|
|
4874
|
+
}
|
|
4875
|
+
collectMissingSourceRefs(processedDoc, refResolver) {
|
|
4876
|
+
const issues = [];
|
|
4877
|
+
const addRef = (ref, context) => {
|
|
4878
|
+
if (ref !== void 0 && !refResolver.hasRef(ref)) {
|
|
4879
|
+
issues.push({ context, ref });
|
|
4880
|
+
}
|
|
4881
|
+
};
|
|
4882
|
+
const addRefs = (refs, context) => {
|
|
4883
|
+
refs?.forEach((ref, index) => {
|
|
4884
|
+
addRef(ref, `${context}[${index}]`);
|
|
4885
|
+
});
|
|
4886
|
+
};
|
|
4887
|
+
const visitChapter = (chapter) => {
|
|
4888
|
+
addRefs(chapter.sourceRefs, `chapter ${chapter.id} sourceRefs`);
|
|
4889
|
+
chapter.textBlocks.forEach((textBlock, index) => {
|
|
4890
|
+
addRef(
|
|
4891
|
+
textBlock.sourceRef,
|
|
4892
|
+
`chapter ${chapter.id} textBlock ${textBlock.id ?? index} sourceRef`
|
|
4893
|
+
);
|
|
4894
|
+
});
|
|
4895
|
+
chapter.children?.forEach(visitChapter);
|
|
4896
|
+
};
|
|
4897
|
+
processedDoc.chapters.forEach(visitChapter);
|
|
4898
|
+
processedDoc.images.forEach((image) => {
|
|
4899
|
+
addRef(image.sourceRef, `image ${image.id} sourceRef`);
|
|
4900
|
+
addRefs(image.captionSourceRefs, `image ${image.id} captionSourceRefs`);
|
|
4901
|
+
});
|
|
4902
|
+
processedDoc.tables.forEach((table) => {
|
|
4903
|
+
addRef(table.sourceRef, `table ${table.id} sourceRef`);
|
|
4904
|
+
addRefs(table.captionSourceRefs, `table ${table.id} captionSourceRefs`);
|
|
4905
|
+
});
|
|
4906
|
+
processedDoc.footnotes.forEach((footnote) => {
|
|
4907
|
+
addRef(footnote.sourceRef, `footnote ${footnote.id} sourceRef`);
|
|
4908
|
+
});
|
|
4909
|
+
return issues;
|
|
4910
|
+
}
|
|
4663
4911
|
/**
|
|
4664
4912
|
* Assemble the final ProcessedDocument
|
|
4665
4913
|
*
|
|
4666
4914
|
* Creates the ProcessedDocument structure with all converted components
|
|
4667
4915
|
*/
|
|
4668
|
-
assembleProcessedDocument(
|
|
4916
|
+
assembleProcessedDocument(input) {
|
|
4669
4917
|
this.logger.info("[DocumentProcessor] Assembling ProcessedDocument...");
|
|
4918
|
+
const {
|
|
4919
|
+
reportId,
|
|
4920
|
+
pageRangeMap,
|
|
4921
|
+
chapters,
|
|
4922
|
+
images,
|
|
4923
|
+
tables,
|
|
4924
|
+
footnotes,
|
|
4925
|
+
source
|
|
4926
|
+
} = input;
|
|
4670
4927
|
const processedDoc = {
|
|
4671
4928
|
reportId,
|
|
4929
|
+
schemaVersion: PROCESSED_DOCUMENT_SCHEMA_VERSION,
|
|
4930
|
+
...source !== void 0 ? { source } : {},
|
|
4672
4931
|
pageRangeMap,
|
|
4673
4932
|
chapters,
|
|
4674
4933
|
images,
|
|
@@ -4719,6 +4978,7 @@ export {
|
|
|
4719
4978
|
ChapterConverter,
|
|
4720
4979
|
DocumentProcessor,
|
|
4721
4980
|
PAGE_NUMBER_PATTERN,
|
|
4981
|
+
PROCESSED_DOCUMENT_SCHEMA_VERSION,
|
|
4722
4982
|
PagePattern,
|
|
4723
4983
|
PageRangeParseError,
|
|
4724
4984
|
PageRangeParser,
|