pretext-pdf 0.9.3 → 1.0.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/CHANGELOG.md +99 -0
- package/README.md +874 -795
- package/dist/assets.d.ts +4 -2
- package/dist/assets.d.ts.map +1 -1
- package/dist/assets.js +22 -1
- package/dist/assets.js.map +1 -1
- package/dist/benchmarks/corpora.d.ts +11 -0
- package/dist/benchmarks/corpora.d.ts.map +1 -0
- package/dist/benchmarks/corpora.js +228 -0
- package/dist/benchmarks/corpora.js.map +1 -0
- package/dist/builder.d.ts +10 -2
- package/dist/builder.d.ts.map +1 -1
- package/dist/builder.js +12 -4
- package/dist/builder.js.map +1 -1
- package/dist/cli.js +19 -19
- package/dist/element-types.d.ts +16 -0
- package/dist/element-types.d.ts.map +1 -0
- package/dist/element-types.js +16 -0
- package/dist/element-types.js.map +1 -0
- package/dist/errors.d.ts +8 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +4 -0
- package/dist/errors.js.map +1 -1
- package/dist/fonts.d.ts +2 -1
- package/dist/fonts.d.ts.map +1 -1
- package/dist/fonts.js.map +1 -1
- package/dist/index.d.ts +21 -17
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +25 -309
- package/dist/index.js.map +1 -1
- package/dist/layout-state.d.ts +39 -0
- package/dist/layout-state.d.ts.map +1 -0
- package/dist/layout-state.js +46 -0
- package/dist/layout-state.js.map +1 -0
- package/dist/measure-blocks.d.ts +2 -1
- package/dist/measure-blocks.d.ts.map +1 -1
- package/dist/measure-blocks.js.map +1 -1
- package/dist/measure.d.ts +4 -2
- package/dist/measure.d.ts.map +1 -1
- package/dist/measure.js +15 -5
- package/dist/measure.js.map +1 -1
- package/dist/page-sizes.d.ts +1 -0
- package/dist/page-sizes.d.ts.map +1 -1
- package/dist/page-sizes.js.map +1 -1
- package/dist/paginate.d.ts +1 -1
- package/dist/paginate.d.ts.map +1 -1
- package/dist/paginate.js +11 -2
- package/dist/paginate.js.map +1 -1
- package/dist/pipeline-footnotes.d.ts +18 -0
- package/dist/pipeline-footnotes.d.ts.map +1 -0
- package/dist/pipeline-footnotes.js +98 -0
- package/dist/pipeline-footnotes.js.map +1 -0
- package/dist/pipeline-toc.d.ts +11 -0
- package/dist/pipeline-toc.d.ts.map +1 -0
- package/dist/pipeline-toc.js +28 -0
- package/dist/pipeline-toc.js.map +1 -0
- package/dist/pipeline.d.ts +24 -0
- package/dist/pipeline.d.ts.map +1 -0
- package/dist/pipeline.js +116 -0
- package/dist/pipeline.js.map +1 -0
- package/dist/plugin-registry.d.ts +40 -0
- package/dist/plugin-registry.d.ts.map +1 -0
- package/dist/plugin-registry.js +104 -0
- package/dist/plugin-registry.js.map +1 -0
- package/dist/plugin-types.d.ts +185 -0
- package/dist/plugin-types.d.ts.map +1 -0
- package/dist/plugin-types.js +27 -0
- package/dist/plugin-types.js.map +1 -0
- package/dist/post-process.d.ts +16 -0
- package/dist/post-process.d.ts.map +1 -0
- package/dist/post-process.js +80 -0
- package/dist/post-process.js.map +1 -0
- package/dist/render-blocks.d.ts +2 -1
- package/dist/render-blocks.d.ts.map +1 -1
- package/dist/render-blocks.js.map +1 -1
- package/dist/render-extras.d.ts +2 -2
- package/dist/render-extras.d.ts.map +1 -1
- package/dist/render-extras.js.map +1 -1
- package/dist/render.d.ts +4 -2
- package/dist/render.d.ts.map +1 -1
- package/dist/render.js +23 -4
- package/dist/render.js.map +1 -1
- package/dist/types-internal.d.ts +302 -0
- package/dist/types-internal.d.ts.map +1 -0
- package/dist/types-internal.js +9 -0
- package/dist/types-internal.js.map +1 -0
- package/dist/types-public.d.ts +1031 -0
- package/dist/types-public.d.ts.map +1 -0
- package/dist/types-public.js +2 -0
- package/dist/types-public.js.map +1 -0
- package/dist/types.d.ts +6 -1224
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -1
- package/dist/validate.d.ts +6 -4
- package/dist/validate.d.ts.map +1 -1
- package/dist/validate.js +35 -4
- package/dist/validate.js.map +1 -1
- package/package.json +192 -184
- package/docs/screenshots/showcase-invoice.png +0 -0
- package/docs/screenshots/showcase-report.png +0 -0
- package/docs/screenshots/showcase-resume.png +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline-footnotes.js","sourceRoot":"","sources":["../src/pipeline-footnotes.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAExC,MAAM,gBAAgB,GAAG,EAAE,CAAA,CAAE,uCAAuC;AAEpE,4FAA4F;AAC5F,MAAM,UAAU,sBAAsB,CAAC,OAAyB;IAC9D,MAAM,SAAS,GAAG,IAAI,GAAG,EAAkB,CAAA;IAC3C,IAAI,OAAO,GAAG,CAAC,CAAA;IACf,KAAK,MAAM,EAAE,IAAI,OAAO,EAAE,CAAC;QACzB,IAAI,EAAE,CAAC,IAAI,KAAK,gBAAgB,EAAE,CAAC;YACjC,KAAK,MAAM,IAAI,IAAI,EAAE,CAAC,KAAK,EAAE,CAAC;gBAC5B,IAAI,IAAI,CAAC,WAAW,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;oBACzD,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,EAAE,CAAC,CAAA;gBAC5C,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAA;AAClB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAChC,cAA+B,EAC/B,aAAqB,EACrB,cAAiE,EACjE,GAAkC;IAElC,MAAM,mBAAmB,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CAC5C,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,KAAK,cAAc,CACT,CAAA;IAEzB,IAAI,mBAAmB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrC,OAAO,QAAQ,CAAC,cAAc,EAAE,aAAa,EAAE,cAAc,CAAC,CAAA;IAChE,CAAC;IAED,+EAA+E;IAC/E,MAAM,oBAAoB,GAAG,IAAI,GAAG,EAAkB,CAAA;IACtD,KAAK,MAAM,KAAK,IAAI,cAAc,EAAE,CAAC;QACnC,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;YAC1C,MAAM,GAAG,GAAG,KAAK,CAAC,OAA6B,CAAA;YAC/C,oBAAoB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,UAAU,IAAI,CAAC,CAAC,CAAC,CAAA;QAC1E,CAAC;IACH,CAAC;IAED,gFAAgF;IAChF,MAAM,UAAU,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,KAAK,cAAc,CAAC,CAAA;IAEhF,uFAAuF;IACvF,MAAM,iBAAiB,GAAG,sBAAsB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IAE7D,yDAAyD;IACzD,MAAM,KAAK,GAAG,QAAQ,CAAC,UAAU,EAAE,aAAa,EAAE,cAAc,CAAC,CAAA;IAEjE,mDAAmD;IACnD,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAAoB,CAAA;IACpD,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,CAAC;QAC9D,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,OAAO,CAAE,CAAA;QAClC,MAAM,aAAa,GAAG,IAAI,GAAG,EAAU,CAAA;QACvC,KAAK,MAAM,UAAU,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YACrC,MAAM,EAAE,GAAG,UAAU,CAAC,aAAa,CAAC,OAAO,CAAA;YAC3C,IAAI,EAAE,CAAC,IAAI,KAAK,gBAAgB,EAAE,CAAC;gBACjC,KAAK,MAAM,IAAI,IAAI,EAAE,CAAC,KAAK,EAAE,CAAC;oBAC5B,IAAI,IAAI,CAAC,WAAW;wBAAE,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;gBAC3D,CAAC;YACH,CAAC;QACH,CAAC;QACD,IAAI,aAAa,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;YAC3B,gBAAgB,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,GAAG,aAAa,CAAC,CAAC,CAAA;QACnD,CAAC;IACH,CAAC;IAED,uCAAuC;IACvC,MAAM,aAAa,GAAG,IAAI,GAAG,EAAkB,CAAA;IAC/C,KAAK,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,gBAAgB,EAAE,CAAC;QACjD,IAAI,UAAU,GAAG,gBAAgB,CAAA;QACjC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,UAAU,IAAI,oBAAoB,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QACpD,CAAC;QACD,aAAa,CAAC,GAAG,CAAC,OAAO,EAAE,UAAU,CAAC,CAAA;IACxC,CAAC;IAED,uCAAuC;IACvC,MAAM,WAAW,GAAG,EAAE,GAAG,cAAc,EAAE,aAAa,EAAE,CAAA;IACxD,MAAM,YAAY,GAAG,QAAQ,CAAC,UAAU,EAAE,aAAa,EAAE,WAAW,CAAC,CAAA;IACrE,YAAY,CAAC,iBAAiB,GAAG,iBAAiB,CAAA;IAElD,qDAAqD;IACrD,KAAK,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,gBAAgB,EAAE,CAAC;QACjD,IAAI,OAAO,IAAI,YAAY,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;YACzC,MAAM,IAAI,eAAe,CAAC,mBAAmB,EAAE,mCAAmC,OAAO,0BAA0B,YAAY,CAAC,KAAK,CAAC,MAAM,mCAAmC,CAAC,CAAA;QAClL,CAAC;QACD,MAAM,IAAI,GAAG,YAAY,CAAC,KAAK,CAAC,OAAO,CAAE,CAAA;QACzC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,eAAe,CAAC,mBAAmB,EAAE,mCAAmC,OAAO,0BAA0B,YAAY,CAAC,KAAK,CAAC,MAAM,mCAAmC,CAAC,CAAA;QAClL,CAAC;QACD,IAAI,CAAC,aAAa,GAAG,MAAM;aACxB,GAAG,CAAC,EAAE,CAAC,EAAE;YACR,MAAM,GAAG,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAA;YACtD,MAAM,GAAG,GAAG,iBAAiB,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAA;YAC1C,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA;QAC1C,CAAC,CAAC;aACD,MAAM,CAAC,OAAO,CAAuD,CAAA;QACxE,MAAM,UAAU,GAAG,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;QAC7C,IAAI,UAAU,KAAK,SAAS;YAAE,IAAI,CAAC,kBAAkB,GAAG,UAAU,CAAA;IACpE,CAAC;IAED,OAAO,YAAY,CAAA;AACrB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { PdfDocument } from './types-public.js';
|
|
2
|
+
import type { MeasuredBlock } from './types-internal.js';
|
|
3
|
+
/**
|
|
4
|
+
* Two-pass TOC entry building.
|
|
5
|
+
*
|
|
6
|
+
* Pass 1: draft pagination to collect heading page numbers.
|
|
7
|
+
* Splices real TOC entry blocks into measuredBlocks at the placeholder index.
|
|
8
|
+
* Returns the updated measuredBlocks array (new reference, original untouched).
|
|
9
|
+
*/
|
|
10
|
+
export declare function runTocTwoPass(measuredBlocks: MeasuredBlock[], doc: Pick<PdfDocument, 'content' | 'defaultFont'> & Partial<PdfDocument>, contentWidth: number, contentHeight: number): Promise<MeasuredBlock[]>;
|
|
11
|
+
//# sourceMappingURL=pipeline-toc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline-toc.d.ts","sourceRoot":"","sources":["../src/pipeline-toc.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AACpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAGxD;;;;;;GAMG;AACH,wBAAsB,aAAa,CACjC,cAAc,EAAE,aAAa,EAAE,EAC/B,GAAG,EAAE,IAAI,CAAC,WAAW,EAAE,SAAS,GAAG,aAAa,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,EACxE,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,aAAa,EAAE,CAAC,CA0B1B"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { paginate } from './paginate.js';
|
|
2
|
+
/**
|
|
3
|
+
* Two-pass TOC entry building.
|
|
4
|
+
*
|
|
5
|
+
* Pass 1: draft pagination to collect heading page numbers.
|
|
6
|
+
* Splices real TOC entry blocks into measuredBlocks at the placeholder index.
|
|
7
|
+
* Returns the updated measuredBlocks array (new reference, original untouched).
|
|
8
|
+
*/
|
|
9
|
+
export async function runTocTwoPass(measuredBlocks, doc, contentWidth, contentHeight) {
|
|
10
|
+
const tocIndex = doc.content.findIndex(el => el.type === 'toc');
|
|
11
|
+
if (tocIndex === -1)
|
|
12
|
+
return measuredBlocks;
|
|
13
|
+
const tocElement = doc.content[tocIndex];
|
|
14
|
+
if (!tocElement || tocElement.type !== 'toc')
|
|
15
|
+
throw new Error('TOC element type mismatch');
|
|
16
|
+
// Pass 1: paginate without real TOC content to collect heading page numbers
|
|
17
|
+
const draftPaginatedDoc = paginate(measuredBlocks, contentHeight);
|
|
18
|
+
// Dynamic import preserves lazy-load semantics (measure.ts can be heavy)
|
|
19
|
+
const { buildTocEntryBlocks } = await import('./measure.js');
|
|
20
|
+
const tocEntryBlocks = await buildTocEntryBlocks(draftPaginatedDoc.headings, tocElement, contentWidth, doc);
|
|
21
|
+
// Splice TOC entries in place of the placeholder (zero-height) block at tocIndex
|
|
22
|
+
return [
|
|
23
|
+
...measuredBlocks.slice(0, tocIndex),
|
|
24
|
+
...tocEntryBlocks,
|
|
25
|
+
...measuredBlocks.slice(tocIndex + 1),
|
|
26
|
+
];
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=pipeline-toc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline-toc.js","sourceRoot":"","sources":["../src/pipeline-toc.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAExC;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,cAA+B,EAC/B,GAAwE,EACxE,YAAoB,EACpB,aAAqB;IAErB,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,KAAK,KAAK,CAAC,CAAA;IAC/D,IAAI,QAAQ,KAAK,CAAC,CAAC;QAAE,OAAO,cAAc,CAAA;IAE1C,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;IACxC,IAAI,CAAC,UAAU,IAAI,UAAU,CAAC,IAAI,KAAK,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAA;IAE1F,4EAA4E;IAC5E,MAAM,iBAAiB,GAAG,QAAQ,CAAC,cAAc,EAAE,aAAa,CAAC,CAAA;IAEjE,yEAAyE;IACzE,MAAM,EAAE,mBAAmB,EAAE,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,CAAA;IAE5D,MAAM,cAAc,GAAG,MAAM,mBAAmB,CAC9C,iBAAiB,CAAC,QAAQ,EAC1B,UAAU,EACV,YAAY,EACZ,GAAkB,CACnB,CAAA;IAED,iFAAiF;IACjF,OAAO;QACL,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC;QACpC,GAAG,cAAc;QACjB,GAAG,cAAc,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC;KACtC,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { PDFDocument } from '@cantoo/pdf-lib';
|
|
2
|
+
import type { PdfDocument, RenderOptions } from './types-public.js';
|
|
3
|
+
import type { PageGeometry, FontMap, ImageMap, MeasuredBlock } from './types-internal.js';
|
|
4
|
+
import { runFootnoteTwoPass } from './pipeline-footnotes.js';
|
|
5
|
+
export declare function stageValidate(doc: PdfDocument, options?: RenderOptions): void;
|
|
6
|
+
export declare function stageInit(doc: PdfDocument): Promise<{
|
|
7
|
+
pdfDoc: PDFDocument;
|
|
8
|
+
geo: Omit<PageGeometry, 'contentHeight' | 'headerHeight' | 'footerHeight'>;
|
|
9
|
+
defaultFont: string;
|
|
10
|
+
}>;
|
|
11
|
+
export declare function stageLoadAssets(doc: PdfDocument, pdfDoc: PDFDocument, contentWidth: number, plugins?: import('./plugin-types.js').PluginDefinition[]): Promise<{
|
|
12
|
+
fontMap: FontMap;
|
|
13
|
+
imageMap: ImageMap;
|
|
14
|
+
}>;
|
|
15
|
+
export declare function stageFinalizeGeo(doc: PdfDocument, partialGeo: Omit<PageGeometry, 'contentHeight' | 'headerHeight' | 'footerHeight'>, defaultFont: string): Promise<PageGeometry>;
|
|
16
|
+
export declare function stageMeasure(doc: PdfDocument, contentWidth: number, imageMap: ImageMap, contentHeight: number, plugins?: import('./plugin-types.js').PluginDefinition[]): Promise<MeasuredBlock[]>;
|
|
17
|
+
export declare function stagePaginate(measuredBlocks: MeasuredBlock[], contentHeight: number, doc: PdfDocument): ReturnType<typeof runFootnoteTwoPass>;
|
|
18
|
+
export declare function stageRender(paginatedDoc: ReturnType<typeof stagePaginate>, doc: PdfDocument, fontMap: FontMap, imageMap: ImageMap, pdfDoc: PDFDocument, geo: PageGeometry, plugins?: import('./plugin-types.js').PluginDefinition[]): Promise<Uint8Array>;
|
|
19
|
+
/**
|
|
20
|
+
* Run all 5 stages in sequence and return raw PDF bytes.
|
|
21
|
+
* Post-processing (signature, encryption) is applied by the public render() in index.ts.
|
|
22
|
+
*/
|
|
23
|
+
export declare function runPipeline(doc: PdfDocument, options?: RenderOptions): Promise<Uint8Array>;
|
|
24
|
+
//# sourceMappingURL=pipeline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAsB,MAAM,iBAAiB,CAAA;AACjE,OAAO,KAAK,EAAE,WAAW,EAAW,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAC5E,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAUzF,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAI5D,wBAAgB,aAAa,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,IAAI,CAE7E;AAID,wBAAsB,SAAS,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC;IACzD,MAAM,EAAE,WAAW,CAAA;IACnB,GAAG,EAAE,IAAI,CAAC,YAAY,EAAE,eAAe,GAAG,cAAc,GAAG,cAAc,CAAC,CAAA;IAC1E,WAAW,EAAE,MAAM,CAAA;CACpB,CAAC,CAwCD;AAID,wBAAsB,eAAe,CACnC,GAAG,EAAE,WAAW,EAChB,MAAM,EAAE,WAAW,EACnB,YAAY,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE,OAAO,mBAAmB,EAAE,gBAAgB,EAAE,GACvD,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,CAAC,CAMnD;AAID,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,WAAW,EAChB,UAAU,EAAE,IAAI,CAAC,YAAY,EAAE,eAAe,GAAG,cAAc,GAAG,cAAc,CAAC,EACjF,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,YAAY,CAAC,CAiCvB;AAID,wBAAsB,YAAY,CAChC,GAAG,EAAE,WAAW,EAChB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,QAAQ,EAClB,aAAa,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE,OAAO,mBAAmB,EAAE,gBAAgB,EAAE,GACvD,OAAO,CAAC,aAAa,EAAE,CAAC,CAI1B;AAID,wBAAgB,aAAa,CAC3B,cAAc,EAAE,aAAa,EAAE,EAC/B,aAAa,EAAE,MAAM,EACrB,GAAG,EAAE,WAAW,GACf,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAGvC;AAID,wBAAsB,WAAW,CAC/B,YAAY,EAAE,UAAU,CAAC,OAAO,aAAa,CAAC,EAC9C,GAAG,EAAE,WAAW,EAChB,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,WAAW,EACnB,GAAG,EAAE,YAAY,EACjB,OAAO,CAAC,EAAE,OAAO,mBAAmB,EAAE,gBAAgB,EAAE,GACvD,OAAO,CAAC,UAAU,CAAC,CAErB;AAID;;;GAGG;AACH,wBAAsB,WAAW,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,UAAU,CAAC,CAiBhG"}
|
package/dist/pipeline.js
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { PDFDocument, PDFName, PDFString } from '@cantoo/pdf-lib';
|
|
2
|
+
import { PretextPdfError } from './errors.js';
|
|
3
|
+
import { resolvePageDimensions } from './page-sizes.js';
|
|
4
|
+
import { validate } from './validate.js';
|
|
5
|
+
import { loadFonts } from './fonts.js';
|
|
6
|
+
import { loadImages } from './assets.js';
|
|
7
|
+
import { measureAllBlocks, measureHeaderFooterHeight } from './measure.js';
|
|
8
|
+
import { LINE_HEIGHT_COMPACT } from './render-utils.js';
|
|
9
|
+
import { renderDocument } from './render.js';
|
|
10
|
+
import { runTocTwoPass } from './pipeline-toc.js';
|
|
11
|
+
import { runFootnoteTwoPass } from './pipeline-footnotes.js';
|
|
12
|
+
// ─── Stage 1: Validate ────────────────────────────────────────────────────────
|
|
13
|
+
export function stageValidate(doc, options) {
|
|
14
|
+
validate(doc, options);
|
|
15
|
+
}
|
|
16
|
+
// ─── Stage 2a: Init (geometry + pdfDoc + metadata) ───────────────────────────
|
|
17
|
+
export async function stageInit(doc) {
|
|
18
|
+
const [pageWidth, pageHeight] = resolvePageDimensions(doc.pageSize);
|
|
19
|
+
const margins = {
|
|
20
|
+
top: doc.margins?.top ?? 72,
|
|
21
|
+
bottom: doc.margins?.bottom ?? 72,
|
|
22
|
+
left: doc.margins?.left ?? 72,
|
|
23
|
+
right: doc.margins?.right ?? 72,
|
|
24
|
+
};
|
|
25
|
+
const contentWidth = pageWidth - margins.left - margins.right;
|
|
26
|
+
if (contentWidth <= 0) {
|
|
27
|
+
throw new PretextPdfError('PAGE_TOO_SMALL', `Content width is ${contentWidth}pt after applying margins. Reduce margins or increase page size.`);
|
|
28
|
+
}
|
|
29
|
+
const pdfDoc = await PDFDocument.create();
|
|
30
|
+
if (doc.metadata) {
|
|
31
|
+
const m = doc.metadata;
|
|
32
|
+
if (m.title)
|
|
33
|
+
pdfDoc.setTitle(m.title);
|
|
34
|
+
if (m.author)
|
|
35
|
+
pdfDoc.setAuthor(m.author);
|
|
36
|
+
if (m.subject)
|
|
37
|
+
pdfDoc.setSubject(m.subject);
|
|
38
|
+
if (m.keywords)
|
|
39
|
+
pdfDoc.setKeywords(m.keywords);
|
|
40
|
+
pdfDoc.setCreator(m.creator ?? 'pretext-pdf');
|
|
41
|
+
if (m.producer)
|
|
42
|
+
pdfDoc.setProducer(m.producer);
|
|
43
|
+
if (m.language) {
|
|
44
|
+
pdfDoc.catalog.set(PDFName.of('Lang'), PDFString.of(m.language));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const creationDate = doc.renderDate
|
|
48
|
+
? (doc.renderDate instanceof Date ? doc.renderDate : new Date(doc.renderDate))
|
|
49
|
+
: new Date();
|
|
50
|
+
pdfDoc.setCreationDate(creationDate);
|
|
51
|
+
pdfDoc.setModificationDate(creationDate);
|
|
52
|
+
return {
|
|
53
|
+
pdfDoc,
|
|
54
|
+
geo: { pageWidth, pageHeight, margins, contentWidth },
|
|
55
|
+
defaultFont: doc.defaultFont ?? 'Inter',
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
// ─── Stage 2b: Load assets (fonts + images in parallel) ──────────────────────
|
|
59
|
+
export async function stageLoadAssets(doc, pdfDoc, contentWidth, plugins) {
|
|
60
|
+
const [fontMap, imageMap] = await Promise.all([
|
|
61
|
+
loadFonts(doc, pdfDoc),
|
|
62
|
+
loadImages(doc, pdfDoc, contentWidth, plugins),
|
|
63
|
+
]);
|
|
64
|
+
return { fontMap, imageMap };
|
|
65
|
+
}
|
|
66
|
+
// ─── Stage 2c: Finalize geometry (header/footer heights) ─────────────────────
|
|
67
|
+
export async function stageFinalizeGeo(doc, partialGeo, defaultFont) {
|
|
68
|
+
const { pageHeight, margins, contentWidth } = partialGeo;
|
|
69
|
+
const headerHeight = doc.header
|
|
70
|
+
? await measureHeaderFooterHeight(doc.header.text, doc.header.fontSize ?? 10, doc.header.fontFamily ?? defaultFont, contentWidth, (doc.header.fontSize ?? 10) * LINE_HEIGHT_COMPACT) + 8
|
|
71
|
+
: 0;
|
|
72
|
+
const footerHeight = doc.footer
|
|
73
|
+
? await measureHeaderFooterHeight(doc.footer.text, doc.footer.fontSize ?? 10, doc.footer.fontFamily ?? defaultFont, contentWidth, (doc.footer.fontSize ?? 10) * LINE_HEIGHT_COMPACT) + 8
|
|
74
|
+
: 0;
|
|
75
|
+
const contentHeight = pageHeight - margins.top - margins.bottom - headerHeight - footerHeight;
|
|
76
|
+
if (contentHeight <= 0) {
|
|
77
|
+
throw new PretextPdfError('PAGE_TOO_SMALL', `Content height is ${contentHeight}pt after applying margins + header/footer. Try reducing margins, header/footer font size, or increasing page size.`);
|
|
78
|
+
}
|
|
79
|
+
return { ...partialGeo, headerHeight, footerHeight, contentHeight };
|
|
80
|
+
}
|
|
81
|
+
// ─── Stage 3: Measure ─────────────────────────────────────────────────────────
|
|
82
|
+
export async function stageMeasure(doc, contentWidth, imageMap, contentHeight, plugins) {
|
|
83
|
+
let measuredBlocks = await measureAllBlocks(doc, contentWidth, imageMap, contentHeight, plugins);
|
|
84
|
+
measuredBlocks = await runTocTwoPass(measuredBlocks, doc, contentWidth, contentHeight);
|
|
85
|
+
return measuredBlocks;
|
|
86
|
+
}
|
|
87
|
+
// ─── Stage 4: Paginate ────────────────────────────────────────────────────────
|
|
88
|
+
export function stagePaginate(measuredBlocks, contentHeight, doc) {
|
|
89
|
+
const paginateConfig = { minOrphanLines: 2, minWidowLines: 2 };
|
|
90
|
+
return runFootnoteTwoPass(measuredBlocks, contentHeight, paginateConfig, doc);
|
|
91
|
+
}
|
|
92
|
+
// ─── Stage 5: Render ──────────────────────────────────────────────────────────
|
|
93
|
+
export async function stageRender(paginatedDoc, doc, fontMap, imageMap, pdfDoc, geo, plugins) {
|
|
94
|
+
return renderDocument(paginatedDoc, doc, fontMap, imageMap, pdfDoc, geo, plugins);
|
|
95
|
+
}
|
|
96
|
+
// ─── Composed pipeline ────────────────────────────────────────────────────────
|
|
97
|
+
/**
|
|
98
|
+
* Run all 5 stages in sequence and return raw PDF bytes.
|
|
99
|
+
* Post-processing (signature, encryption) is applied by the public render() in index.ts.
|
|
100
|
+
*/
|
|
101
|
+
export async function runPipeline(doc, options) {
|
|
102
|
+
// Node canvas polyfill MUST be installed before any Pretext import (measure.ts uses it)
|
|
103
|
+
if (typeof OffscreenCanvas === 'undefined' && typeof window === 'undefined') {
|
|
104
|
+
const { installNodePolyfill } = await import('./node-polyfill.js');
|
|
105
|
+
await installNodePolyfill();
|
|
106
|
+
}
|
|
107
|
+
const plugins = options?.plugins;
|
|
108
|
+
stageValidate(doc, options);
|
|
109
|
+
const { pdfDoc, geo: partialGeo, defaultFont } = await stageInit(doc);
|
|
110
|
+
const { fontMap, imageMap } = await stageLoadAssets(doc, pdfDoc, partialGeo.contentWidth, plugins);
|
|
111
|
+
const geo = await stageFinalizeGeo(doc, partialGeo, defaultFont);
|
|
112
|
+
const measuredBlocks = await stageMeasure(doc, geo.contentWidth, imageMap, geo.contentHeight, plugins);
|
|
113
|
+
const paginatedDoc = stagePaginate(measuredBlocks, geo.contentHeight, doc);
|
|
114
|
+
return stageRender(paginatedDoc, doc, fontMap, imageMap, pdfDoc, geo, plugins);
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=pipeline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin registry — orchestration helpers for the 4 injection points.
|
|
3
|
+
*
|
|
4
|
+
* All functions are pure (no module-level state). The plugin list is
|
|
5
|
+
* threaded through the pipeline via RenderOptions and passed explicitly.
|
|
6
|
+
*
|
|
7
|
+
* @internal Not part of the public API. Import PluginDefinition from plugin-types.ts.
|
|
8
|
+
*/
|
|
9
|
+
import type { PluginDefinition, PluginMeasureContext } from './plugin-types.js';
|
|
10
|
+
import type { MeasuredBlock, PageGeometry } from './types-internal.js';
|
|
11
|
+
/**
|
|
12
|
+
* Return the first plugin whose `type` matches `elementType`, or `undefined`.
|
|
13
|
+
* @internal
|
|
14
|
+
*/
|
|
15
|
+
export declare function findPlugin(plugins: PluginDefinition[], elementType: string): PluginDefinition | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* Run a plugin's optional `validate` hook.
|
|
18
|
+
* Returns the rejection message if the hook rejects, or `undefined` if accepted.
|
|
19
|
+
*/
|
|
20
|
+
export declare function runPluginValidate(plugin: PluginDefinition, element: Record<string, unknown>): string | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* Run a plugin's optional `loadAsset` hook and return the resulting PDFImage key
|
|
23
|
+
* if an image was embedded.
|
|
24
|
+
*
|
|
25
|
+
* Callers are responsible for setting `imageMap.set(key, image)` with the returned image.
|
|
26
|
+
*/
|
|
27
|
+
export declare function runPluginLoadAsset(plugin: PluginDefinition, element: Record<string, unknown>, pdfDoc: import('@cantoo/pdf-lib').PDFDocument, contentWidth: number, contentIndex: number): Promise<{
|
|
28
|
+
key: string;
|
|
29
|
+
image: import('@cantoo/pdf-lib').PDFImage;
|
|
30
|
+
} | undefined>;
|
|
31
|
+
/**
|
|
32
|
+
* Run a plugin's `measure` hook and wrap the result into a `MeasuredBlock`.
|
|
33
|
+
*/
|
|
34
|
+
export declare function runPluginMeasure(plugin: PluginDefinition, element: Record<string, unknown>, context: PluginMeasureContext, pluginImageKey?: string): Promise<MeasuredBlock>;
|
|
35
|
+
/**
|
|
36
|
+
* Run a plugin's `render` hook with the fully-assembled render context.
|
|
37
|
+
* Wraps thrown errors in RENDER_FAILED so callers see a consistent error type.
|
|
38
|
+
*/
|
|
39
|
+
export declare function runPluginRender(plugin: PluginDefinition, block: MeasuredBlock, pdfPage: import('@cantoo/pdf-lib').PDFPage, pdfDoc: import('@cantoo/pdf-lib').PDFDocument, x: number, y: number, geo: PageGeometry, imageMap: import('./types-internal.js').ImageMap): void;
|
|
40
|
+
//# sourceMappingURL=plugin-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-registry.d.ts","sourceRoot":"","sources":["../src/plugin-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,oBAAoB,EAA4C,MAAM,mBAAmB,CAAA;AACzH,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAKtE;;;GAGG;AACH,wBAAgB,UAAU,CACxB,OAAO,EAAE,gBAAgB,EAAE,EAC3B,WAAW,EAAE,MAAM,GAClB,gBAAgB,GAAG,SAAS,CAE9B;AAID;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,gBAAgB,EACxB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,MAAM,GAAG,SAAS,CAKpB;AAID;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,gBAAgB,EACxB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,MAAM,EAAE,OAAO,iBAAiB,EAAE,WAAW,EAC7C,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,iBAAiB,EAAE,QAAQ,CAAA;CAAE,GAAG,SAAS,CAAC,CAMjF;AAID;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,gBAAgB,EACxB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,OAAO,EAAE,oBAAoB,EAC7B,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,aAAa,CAAC,CA+BxB;AAID;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,gBAAgB,EACxB,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE,OAAO,iBAAiB,EAAE,OAAO,EAC1C,MAAM,EAAE,OAAO,iBAAiB,EAAE,WAAW,EAC7C,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,GAAG,EAAE,YAAY,EACjB,QAAQ,EAAE,OAAO,qBAAqB,EAAE,QAAQ,GAC/C,IAAI,CAwBN"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin registry — orchestration helpers for the 4 injection points.
|
|
3
|
+
*
|
|
4
|
+
* All functions are pure (no module-level state). The plugin list is
|
|
5
|
+
* threaded through the pipeline via RenderOptions and passed explicitly.
|
|
6
|
+
*
|
|
7
|
+
* @internal Not part of the public API. Import PluginDefinition from plugin-types.ts.
|
|
8
|
+
*/
|
|
9
|
+
import { PretextPdfError } from './errors.js';
|
|
10
|
+
// ─── Lookup ───────────────────────────────────────────────────────────────────
|
|
11
|
+
/**
|
|
12
|
+
* Return the first plugin whose `type` matches `elementType`, or `undefined`.
|
|
13
|
+
* @internal
|
|
14
|
+
*/
|
|
15
|
+
export function findPlugin(plugins, elementType) {
|
|
16
|
+
return plugins.find(p => p.type === elementType);
|
|
17
|
+
}
|
|
18
|
+
// ─── Stage 1: validate ────────────────────────────────────────────────────────
|
|
19
|
+
/**
|
|
20
|
+
* Run a plugin's optional `validate` hook.
|
|
21
|
+
* Returns the rejection message if the hook rejects, or `undefined` if accepted.
|
|
22
|
+
*/
|
|
23
|
+
export function runPluginValidate(plugin, element) {
|
|
24
|
+
if (!plugin.validate)
|
|
25
|
+
return undefined;
|
|
26
|
+
const result = plugin.validate(element);
|
|
27
|
+
// Normalize: only non-empty strings are rejections; '' and void are acceptance
|
|
28
|
+
return typeof result === 'string' && result.length > 0 ? result : undefined;
|
|
29
|
+
}
|
|
30
|
+
// ─── Stage 2b: load assets ────────────────────────────────────────────────────
|
|
31
|
+
/**
|
|
32
|
+
* Run a plugin's optional `loadAsset` hook and return the resulting PDFImage key
|
|
33
|
+
* if an image was embedded.
|
|
34
|
+
*
|
|
35
|
+
* Callers are responsible for setting `imageMap.set(key, image)` with the returned image.
|
|
36
|
+
*/
|
|
37
|
+
export async function runPluginLoadAsset(plugin, element, pdfDoc, contentWidth, contentIndex) {
|
|
38
|
+
if (!plugin.loadAsset)
|
|
39
|
+
return undefined;
|
|
40
|
+
const image = await plugin.loadAsset(element, pdfDoc, contentWidth);
|
|
41
|
+
if (!image)
|
|
42
|
+
return undefined;
|
|
43
|
+
const key = `${plugin.type}-${contentIndex}`;
|
|
44
|
+
return { key, image };
|
|
45
|
+
}
|
|
46
|
+
// ─── Stage 3: measure ─────────────────────────────────────────────────────────
|
|
47
|
+
/**
|
|
48
|
+
* Run a plugin's `measure` hook and wrap the result into a `MeasuredBlock`.
|
|
49
|
+
*/
|
|
50
|
+
export async function runPluginMeasure(plugin, element, context, pluginImageKey) {
|
|
51
|
+
let result;
|
|
52
|
+
try {
|
|
53
|
+
result = await plugin.measure(element, context);
|
|
54
|
+
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
throw new PretextPdfError('RENDER_FAILED', `Plugin '${plugin.type}' measure hook threw: ${err instanceof Error ? err.message : String(err)}`);
|
|
57
|
+
}
|
|
58
|
+
if (typeof result.height !== 'number' || !isFinite(result.height) || result.height < 0) {
|
|
59
|
+
throw new PretextPdfError('RENDER_FAILED', `Plugin '${plugin.type}' measure hook returned invalid height: ${result.height}. Must be a finite non-negative number.`);
|
|
60
|
+
}
|
|
61
|
+
const block = {
|
|
62
|
+
element: element,
|
|
63
|
+
height: result.height,
|
|
64
|
+
lines: [],
|
|
65
|
+
fontSize: 0,
|
|
66
|
+
lineHeight: 0,
|
|
67
|
+
fontKey: '',
|
|
68
|
+
spaceAfter: result.spaceAfter ?? 0,
|
|
69
|
+
spaceBefore: result.spaceBefore ?? 0,
|
|
70
|
+
pluginData: result.pluginData,
|
|
71
|
+
};
|
|
72
|
+
if (pluginImageKey !== undefined)
|
|
73
|
+
block.pluginImageKey = pluginImageKey;
|
|
74
|
+
return block;
|
|
75
|
+
}
|
|
76
|
+
// ─── Stage 5: render ──────────────────────────────────────────────────────────
|
|
77
|
+
/**
|
|
78
|
+
* Run a plugin's `render` hook with the fully-assembled render context.
|
|
79
|
+
* Wraps thrown errors in RENDER_FAILED so callers see a consistent error type.
|
|
80
|
+
*/
|
|
81
|
+
export function runPluginRender(plugin, block, pdfPage, pdfDoc, x, y, geo, imageMap) {
|
|
82
|
+
const pdfImage = block.pluginImageKey ? imageMap.get(block.pluginImageKey) : undefined;
|
|
83
|
+
const ctx = {
|
|
84
|
+
element: block.element,
|
|
85
|
+
pdfPage,
|
|
86
|
+
pdfDoc,
|
|
87
|
+
pageWidth: geo.pageWidth,
|
|
88
|
+
pageHeight: geo.pageHeight,
|
|
89
|
+
margins: geo.margins,
|
|
90
|
+
x,
|
|
91
|
+
y,
|
|
92
|
+
width: geo.contentWidth,
|
|
93
|
+
height: block.height,
|
|
94
|
+
pluginData: block.pluginData,
|
|
95
|
+
...(pdfImage !== undefined ? { pdfImage } : {}),
|
|
96
|
+
};
|
|
97
|
+
try {
|
|
98
|
+
plugin.render(ctx);
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
throw new PretextPdfError('RENDER_FAILED', `Plugin '${plugin.type}' render hook threw: ${err instanceof Error ? err.message : String(err)}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=plugin-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-registry.js","sourceRoot":"","sources":["../src/plugin-registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin extension points for pretext-pdf.
|
|
3
|
+
*
|
|
4
|
+
* Register custom element types by passing an array of `PluginDefinition` objects
|
|
5
|
+
* in `RenderOptions.plugins`. Each definition handles one `type` string.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { render } from 'pretext-pdf'
|
|
10
|
+
* import type { PluginDefinition } from 'pretext-pdf/plugin-types'
|
|
11
|
+
*
|
|
12
|
+
* const boxPlugin: PluginDefinition = {
|
|
13
|
+
* type: 'highlight-box',
|
|
14
|
+
* measure: async (el, { contentWidth }) => ({ height: 50, spaceBefore: 8, spaceAfter: 8 }),
|
|
15
|
+
* render: ({ pdfPage, x, y, width, height }) => {
|
|
16
|
+
* pdfPage.drawRectangle({ x, y: y - height, width, height, color: rgb(1, 0.9, 0.8) })
|
|
17
|
+
* },
|
|
18
|
+
* }
|
|
19
|
+
*
|
|
20
|
+
* const bytes = await render(doc, { plugins: [boxPlugin] })
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* @module
|
|
24
|
+
* @beta
|
|
25
|
+
*/
|
|
26
|
+
import type { PdfDocument, Margins } from './types-public.js';
|
|
27
|
+
/**
|
|
28
|
+
* Context passed to a plugin's `measure` hook.
|
|
29
|
+
* @beta
|
|
30
|
+
*/
|
|
31
|
+
export interface PluginMeasureContext {
|
|
32
|
+
/** Available content width in pt (page width minus left/right margins) */
|
|
33
|
+
contentWidth: number;
|
|
34
|
+
/** Available content height per page in pt */
|
|
35
|
+
contentHeight: number;
|
|
36
|
+
/** The full document being rendered */
|
|
37
|
+
doc: PdfDocument;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Return value from a plugin's `measure` hook.
|
|
41
|
+
* @beta
|
|
42
|
+
*/
|
|
43
|
+
export interface PluginMeasureResult {
|
|
44
|
+
/** Total block height in pt. Must be a finite non-negative number. */
|
|
45
|
+
height: number;
|
|
46
|
+
/** Space before the block in pt. Defaults to 0. */
|
|
47
|
+
spaceBefore?: number;
|
|
48
|
+
/** Space after the block in pt. Defaults to 0. */
|
|
49
|
+
spaceAfter?: number;
|
|
50
|
+
/**
|
|
51
|
+
* Arbitrary plugin-specific data that the pipeline carries untouched from
|
|
52
|
+
* `measure` to `render`. Use this to avoid re-computing expensive values.
|
|
53
|
+
*/
|
|
54
|
+
pluginData?: unknown;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Context passed to a plugin's `render` hook.
|
|
58
|
+
* @beta
|
|
59
|
+
*/
|
|
60
|
+
export interface PluginRenderContext {
|
|
61
|
+
/** The raw element object from doc.content */
|
|
62
|
+
element: Record<string, unknown>;
|
|
63
|
+
/** The pdf-lib page object to draw onto */
|
|
64
|
+
pdfPage: import('@cantoo/pdf-lib').PDFPage;
|
|
65
|
+
/** The pdf-lib document — use for color/font helpers */
|
|
66
|
+
pdfDoc: import('@cantoo/pdf-lib').PDFDocument;
|
|
67
|
+
/** Page width in pt */
|
|
68
|
+
pageWidth: number;
|
|
69
|
+
/** Page height in pt */
|
|
70
|
+
pageHeight: number;
|
|
71
|
+
/** Page margins in pt */
|
|
72
|
+
margins: Margins;
|
|
73
|
+
/** Left edge of the block's bounding box in pt (from page left) */
|
|
74
|
+
x: number;
|
|
75
|
+
/**
|
|
76
|
+
* pdf-lib Y coordinate of the **top** edge of the block in pt.
|
|
77
|
+
*
|
|
78
|
+
* pdf-lib uses a bottom-left origin, so `y` decreases as you move down the page.
|
|
79
|
+
* To draw a rectangle that fills the block exactly:
|
|
80
|
+
* ```ts
|
|
81
|
+
* pdfPage.drawRectangle({ x, y: y - height, width, height })
|
|
82
|
+
* ```
|
|
83
|
+
* To draw text starting at the top of the block:
|
|
84
|
+
* ```ts
|
|
85
|
+
* pdfPage.drawText(line1, { x, y: y - fontSize })
|
|
86
|
+
* pdfPage.drawText(line2, { x, y: y - fontSize - lineHeight })
|
|
87
|
+
* // For subsequent lines: y - fontSize - (n * lineHeight)
|
|
88
|
+
* ```
|
|
89
|
+
* `y - fontSize` places the baseline of the first line flush against the block top.
|
|
90
|
+
* For wrapped or multi-line text, subtract `lineHeight` per additional line.
|
|
91
|
+
*/
|
|
92
|
+
y: number;
|
|
93
|
+
/** Block width in pt */
|
|
94
|
+
width: number;
|
|
95
|
+
/** Block height in pt (as returned by measure) */
|
|
96
|
+
height: number;
|
|
97
|
+
/**
|
|
98
|
+
* Embedded image, if the plugin's `loadAsset` hook returned a PDFImage.
|
|
99
|
+
* Undefined when the plugin has no `loadAsset` or it returned undefined.
|
|
100
|
+
*/
|
|
101
|
+
pdfImage?: import('@cantoo/pdf-lib').PDFImage;
|
|
102
|
+
/**
|
|
103
|
+
* Data returned by the plugin's `measure` hook in `PluginMeasureResult.pluginData`.
|
|
104
|
+
* Undefined when measure did not set pluginData.
|
|
105
|
+
*/
|
|
106
|
+
pluginData?: unknown;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Defines a custom element type that can be used in `doc.content`.
|
|
110
|
+
*
|
|
111
|
+
* All four hooks correspond to the pipeline stage they participate in:
|
|
112
|
+
* - `validate` → Stage 1
|
|
113
|
+
* - `loadAsset` → Stage 2b
|
|
114
|
+
* - `measure` → Stage 3 (required)
|
|
115
|
+
* - `render` → Stage 5 (required)
|
|
116
|
+
*
|
|
117
|
+
* @beta
|
|
118
|
+
*/
|
|
119
|
+
export interface PluginDefinition {
|
|
120
|
+
/**
|
|
121
|
+
* Unique type string. Must match the `type` field of the custom element objects
|
|
122
|
+
* in `doc.content`. Must not collide with any built-in type.
|
|
123
|
+
*/
|
|
124
|
+
type: string;
|
|
125
|
+
/**
|
|
126
|
+
* Validate hook — Stage 1.
|
|
127
|
+
*
|
|
128
|
+
* Called once per matching element during validation.
|
|
129
|
+
* Return a non-empty string to reject the element; the message is used verbatim
|
|
130
|
+
* in the thrown `VALIDATION_ERROR`. Return `void`, `undefined`, or `''` to accept.
|
|
131
|
+
*
|
|
132
|
+
* @param element - The raw element object from doc.content
|
|
133
|
+
* @returns A rejection reason string, or void to accept
|
|
134
|
+
*/
|
|
135
|
+
validate?: (element: Record<string, unknown>) => string | void;
|
|
136
|
+
/**
|
|
137
|
+
* Load asset hook — Stage 2b.
|
|
138
|
+
*
|
|
139
|
+
* Called during image/asset loading for each matching element.
|
|
140
|
+
* Return a `PDFImage` to embed it into the document; the embedded image is
|
|
141
|
+
* passed to `render` via `PluginRenderContext.pdfImage`.
|
|
142
|
+
* Return `undefined` to skip asset loading for this element.
|
|
143
|
+
*
|
|
144
|
+
* The image key used in the imageMap is `${plugin.type}-${contentIndex}`.
|
|
145
|
+
*
|
|
146
|
+
* **Error handling:** Errors thrown here are handled differently from `measure`/`render`.
|
|
147
|
+
* If this hook throws a `PretextPdfError`, it propagates and aborts the render.
|
|
148
|
+
* If it throws any other error, the error is logged via `console.warn` and asset loading
|
|
149
|
+
* is silently skipped for this element (the render continues without `pdfImage`).
|
|
150
|
+
* This asymmetry means non-critical asset failures don't abort the whole document.
|
|
151
|
+
*
|
|
152
|
+
* **File safety:** If you load files based on element data, validate the path against
|
|
153
|
+
* `doc.allowedFileDirs` yourself. The framework does not apply its PATH_TRAVERSAL guard
|
|
154
|
+
* to files loaded inside this hook.
|
|
155
|
+
*
|
|
156
|
+
* @param element - The raw element object
|
|
157
|
+
* @param pdfDoc - The pdf-lib PDFDocument (use pdfDoc.embedPng / embedJpg)
|
|
158
|
+
* @param contentWidth - Available width in pt (for sizing decisions)
|
|
159
|
+
*/
|
|
160
|
+
loadAsset?: (element: Record<string, unknown>, pdfDoc: import('@cantoo/pdf-lib').PDFDocument, contentWidth: number) => Promise<import('@cantoo/pdf-lib').PDFImage | undefined>;
|
|
161
|
+
/**
|
|
162
|
+
* Measure hook — Stage 3. **Required.**
|
|
163
|
+
*
|
|
164
|
+
* Called once per matching element to determine its height and layout metadata.
|
|
165
|
+
* The returned `height` drives pagination; `pluginData` is carried to `render`.
|
|
166
|
+
* Return `height: 0` to produce an invisible zero-height block (acts like a spacer).
|
|
167
|
+
*
|
|
168
|
+
* @param element - The raw element object
|
|
169
|
+
* @param context - Content dimensions and the full document
|
|
170
|
+
*/
|
|
171
|
+
measure: (element: Record<string, unknown>, context: PluginMeasureContext) => Promise<PluginMeasureResult>;
|
|
172
|
+
/**
|
|
173
|
+
* Render hook — Stage 5. **Required.**
|
|
174
|
+
*
|
|
175
|
+
* Called once per page-slice of the element during rendering.
|
|
176
|
+
* Draw directly onto `context.pdfPage` using pdf-lib's drawing API.
|
|
177
|
+
*
|
|
178
|
+
* This hook must be synchronous. If you need async work (e.g. font loading),
|
|
179
|
+
* do it in `measure` and pass the result via `PluginMeasureResult.pluginData`.
|
|
180
|
+
*
|
|
181
|
+
* @param context - Page, geometry, embedded image, and plugin data
|
|
182
|
+
*/
|
|
183
|
+
render: (context: PluginRenderContext) => void;
|
|
184
|
+
}
|
|
185
|
+
//# sourceMappingURL=plugin-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-types.d.ts","sourceRoot":"","sources":["../src/plugin-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAI7D;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC,0EAA0E;IAC1E,YAAY,EAAE,MAAM,CAAA;IACpB,8CAA8C;IAC9C,aAAa,EAAE,MAAM,CAAA;IACrB,uCAAuC;IACvC,GAAG,EAAE,WAAW,CAAA;CACjB;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,sEAAsE;IACtE,MAAM,EAAE,MAAM,CAAA;IACd,mDAAmD;IACnD,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,kDAAkD;IAClD,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,8CAA8C;IAC9C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAChC,2CAA2C;IAC3C,OAAO,EAAE,OAAO,iBAAiB,EAAE,OAAO,CAAA;IAC1C,wDAAwD;IACxD,MAAM,EAAE,OAAO,iBAAiB,EAAE,WAAW,CAAA;IAC7C,uBAAuB;IACvB,SAAS,EAAE,MAAM,CAAA;IACjB,wBAAwB;IACxB,UAAU,EAAE,MAAM,CAAA;IAClB,yBAAyB;IACzB,OAAO,EAAE,OAAO,CAAA;IAChB,mEAAmE;IACnE,CAAC,EAAE,MAAM,CAAA;IACT;;;;;;;;;;;;;;;;OAgBG;IACH,CAAC,EAAE,MAAM,CAAA;IACT,wBAAwB;IACxB,KAAK,EAAE,MAAM,CAAA;IACb,kDAAkD;IAClD,MAAM,EAAE,MAAM,CAAA;IACd;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,iBAAiB,EAAE,QAAQ,CAAA;IAC7C;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAID;;;;;;;;;;GAUG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAA;IAEZ;;;;;;;;;OASG;IACH,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,GAAG,IAAI,CAAA;IAE9D;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,SAAS,CAAC,EAAE,CACV,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,MAAM,EAAE,OAAO,iBAAiB,EAAE,WAAW,EAC7C,YAAY,EAAE,MAAM,KACjB,OAAO,CAAC,OAAO,iBAAiB,EAAE,QAAQ,GAAG,SAAS,CAAC,CAAA;IAE5D;;;;;;;;;OASG;IACH,OAAO,EAAE,CACP,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,OAAO,EAAE,oBAAoB,KAC1B,OAAO,CAAC,mBAAmB,CAAC,CAAA;IAEjC;;;;;;;;;;OAUG;IACH,MAAM,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAA;CAC/C"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin extension points for pretext-pdf.
|
|
3
|
+
*
|
|
4
|
+
* Register custom element types by passing an array of `PluginDefinition` objects
|
|
5
|
+
* in `RenderOptions.plugins`. Each definition handles one `type` string.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { render } from 'pretext-pdf'
|
|
10
|
+
* import type { PluginDefinition } from 'pretext-pdf/plugin-types'
|
|
11
|
+
*
|
|
12
|
+
* const boxPlugin: PluginDefinition = {
|
|
13
|
+
* type: 'highlight-box',
|
|
14
|
+
* measure: async (el, { contentWidth }) => ({ height: 50, spaceBefore: 8, spaceAfter: 8 }),
|
|
15
|
+
* render: ({ pdfPage, x, y, width, height }) => {
|
|
16
|
+
* pdfPage.drawRectangle({ x, y: y - height, width, height, color: rgb(1, 0.9, 0.8) })
|
|
17
|
+
* },
|
|
18
|
+
* }
|
|
19
|
+
*
|
|
20
|
+
* const bytes = await render(doc, { plugins: [boxPlugin] })
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* @module
|
|
24
|
+
* @beta
|
|
25
|
+
*/
|
|
26
|
+
export {};
|
|
27
|
+
//# sourceMappingURL=plugin-types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-types.js","sourceRoot":"","sources":["../src/plugin-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { PdfDocument } from './types-public.js';
|
|
2
|
+
/**
|
|
3
|
+
* Apply PKCS#7 digital signature to pre-rendered PDF bytes.
|
|
4
|
+
* Requires the @signpdf/signpdf peer dependency.
|
|
5
|
+
*/
|
|
6
|
+
export declare function applySignature(pdfBytes: Uint8Array, sig: NonNullable<PdfDocument['signature']>): Promise<Uint8Array>;
|
|
7
|
+
/**
|
|
8
|
+
* Apply AES-128 or AES-256 encryption to pre-rendered PDF bytes.
|
|
9
|
+
*/
|
|
10
|
+
export declare function applyEncryption(pdfBytes: Uint8Array, enc: NonNullable<PdfDocument['encryption']>): Promise<Uint8Array>;
|
|
11
|
+
/**
|
|
12
|
+
* Apply signature and encryption post-processing to raw pipeline bytes.
|
|
13
|
+
* Called by both render() in index.ts and PdfBuilder.build() in builder.ts.
|
|
14
|
+
*/
|
|
15
|
+
export declare function applyPostProcessing(rawBytes: Uint8Array, doc: PdfDocument): Promise<Uint8Array>;
|
|
16
|
+
//# sourceMappingURL=post-process.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"post-process.d.ts","sourceRoot":"","sources":["../src/post-process.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAGpD;;;GAGG;AACH,wBAAsB,cAAc,CAClC,QAAQ,EAAE,UAAU,EACpB,GAAG,EAAE,WAAW,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,GACzC,OAAO,CAAC,UAAU,CAAC,CA4DrB;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,UAAU,EACpB,GAAG,EAAE,WAAW,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC,GAC1C,OAAO,CAAC,UAAU,CAAC,CAarB;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,UAAU,EACpB,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,UAAU,CAAC,CAGrB"}
|