mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 20:42:43 +00:00
refactor(documents): type the text read with pdfjs' own declarations
extractPdfText cast the dynamic import to a hand-written shape (`as unknown as`), so the compiler could not check the call against pdfjs. It now uses pdfjs' own types: PDFDocumentLoadingTask, TextItem and TextMarkedContent, all type-only imports that are erased at build. That check found a dead option at once: pdfjs 6 has no isEvalSupported. The option went away with the font-program eval path it used to switch off, so it did nothing here; it is removed.
This commit is contained in:
1 file changed
+11
-34
@@ -28,6 +28,12 @@
|
||||
*/
|
||||
import { Buffer } from "node:buffer";
|
||||
|
||||
import type { PDFDocumentLoadingTask } from "pdfjs-dist";
|
||||
import type {
|
||||
TextItem,
|
||||
TextMarkedContent,
|
||||
} from "pdfjs-dist/types/src/display/api";
|
||||
|
||||
import { annotate } from "@/lib/logging/context";
|
||||
|
||||
// pdfjs' module top-level references the browser-only `DOMMatrix` global. A
|
||||
@@ -35,42 +41,15 @@ import { annotate } from "@/lib/logging/context";
|
||||
// instantiation and throw `DOMMatrix is not defined`, taking down every
|
||||
// route/worker that shares the chunk (the document routes among them). The
|
||||
// module is therefore loaded lazily inside `extractPdfText` via a runtime
|
||||
// `import()`, and only the slice of its API used here is typed, structurally.
|
||||
interface PdfTextItem {
|
||||
str: string;
|
||||
/** [a, b, c, d, x, y]: the run's text matrix; x and y place it on the page. */
|
||||
transform: number[];
|
||||
width: number;
|
||||
height: number;
|
||||
hasEOL: boolean;
|
||||
}
|
||||
interface PdfTextPage {
|
||||
getTextContent(): Promise<{ items: Array<PdfTextItem | object> }>;
|
||||
cleanup(): void;
|
||||
}
|
||||
interface PdfTextDocument {
|
||||
numPages: number;
|
||||
getPage(pageNumber: number): Promise<PdfTextPage>;
|
||||
}
|
||||
interface PdfTextLoadingTask {
|
||||
promise: Promise<PdfTextDocument>;
|
||||
destroy(): Promise<void>;
|
||||
}
|
||||
interface PdfTextModule {
|
||||
getDocument(opts: {
|
||||
data: Uint8Array;
|
||||
verbosity?: number;
|
||||
isEvalSupported?: boolean;
|
||||
useSystemFonts?: boolean;
|
||||
}): PdfTextLoadingTask;
|
||||
}
|
||||
// `import()`. The type imports above are erased at build, so they load
|
||||
// nothing; they let the compiler check this file against pdfjs' own API.
|
||||
|
||||
/**
|
||||
* One page's text runs as text: a new line where a run ends its line or the
|
||||
* next one sits on another, a space where two runs on one line leave a gap,
|
||||
* nothing where they touch (a word split across two fonts stays one word).
|
||||
*/
|
||||
function pageText(items: Array<PdfTextItem | object>): string {
|
||||
function pageText(items: Array<TextItem | TextMarkedContent>): string {
|
||||
let text = "";
|
||||
let last: { end: number; y: number; size: number } | null = null;
|
||||
for (const item of items) {
|
||||
@@ -128,16 +107,14 @@ export type LocalExtractResult =
|
||||
export async function extractPdfText(
|
||||
buffer: Buffer,
|
||||
): Promise<LocalExtractResult> {
|
||||
let task: PdfTextLoadingTask | null = null;
|
||||
let task: PDFDocumentLoadingTask | null = null;
|
||||
try {
|
||||
// Lazy load: keeps pdfjs/DOMMatrix out of the eager server chunk (see the
|
||||
// import-site note). Resolved at first PDF extraction, then module-cached.
|
||||
const pdfjs =
|
||||
(await import("pdfjs-dist/legacy/build/pdf.mjs")) as unknown as PdfTextModule;
|
||||
const pdfjs = await import("pdfjs-dist/legacy/build/pdf.mjs");
|
||||
task = pdfjs.getDocument({
|
||||
data: new Uint8Array(buffer),
|
||||
verbosity: 0, // VerbosityLevel.ERRORS — no console spam on odd PDFs.
|
||||
isEvalSupported: false, // never eval font programs (defence in depth).
|
||||
useSystemFonts: false,
|
||||
});
|
||||
const doc = await task.promise;
|
||||
|
||||
Reference in new issue
Block a user