@lpdfio/lpdf 0.30.0 → 0.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +2 -2
- package/dist/_shared.d.ts +42 -3
- package/dist/_shared.js +52 -3
- package/dist/attrs.d.ts +580 -89
- package/dist/browser.js +125 -61
- package/dist/canvas.d.ts +10 -9
- package/dist/constants.d.ts +27 -0
- package/dist/constants.js +25 -1
- package/dist/engine.d.ts +23 -41
- package/dist/engine.js +114 -43
- package/dist/index.d.ts +3 -4
- package/dist/index.js +4 -1
- package/dist/kit.d.ts +97 -32
- package/dist/kit.js +7 -1
- package/dist/layout.d.ts +20 -19
- package/dist/markdown.d.ts +5 -4
- package/dist/wasm/lpdf-web.js +64 -50
- package/dist/wasm/lpdf.js +64 -50
- package/dist/wasm/lpdf_bg.wasm +0 -0
- package/package.json +1 -1
package/dist/engine.js
CHANGED
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.PdfEngine = exports.LpdfRenderError = void 0;
|
|
4
4
|
const node_crypto_1 = require("node:crypto");
|
|
5
5
|
const node_fs_1 = require("node:fs");
|
|
6
|
+
const _shared_1 = require("./_shared");
|
|
6
7
|
// require() path is relative to the compiled output at dist/engine.js.
|
|
7
8
|
// In the published package, wasm-pack artifacts live in dist/wasm/.
|
|
8
9
|
// In the monorepo, `npm run build` copies them there from <root>/dist/node/.
|
|
@@ -29,24 +30,19 @@ class LpdfRenderError extends Error {
|
|
|
29
30
|
}
|
|
30
31
|
}
|
|
31
32
|
exports.LpdfRenderError = LpdfRenderError;
|
|
32
|
-
/**
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
*/
|
|
36
|
-
function configureEncryption(engine, options) {
|
|
37
|
-
const algorithm = options.algorithm ?? 'aes-256';
|
|
38
|
-
const entropy = algorithm === 'aes-256' ? new Uint8Array((0, node_crypto_1.randomBytes)(32)) : new Uint8Array(0);
|
|
39
|
-
const permsJson = JSON.stringify(options.permissions ?? {});
|
|
40
|
-
engine.set_encryption(options.userPassword, options.ownerPassword, permsJson, algorithm, entropy);
|
|
33
|
+
/** Node's secure generator, for the entropy of AES-256. */
|
|
34
|
+
function secureRandomBytes(count) {
|
|
35
|
+
return new Uint8Array((0, node_crypto_1.randomBytes)(count));
|
|
41
36
|
}
|
|
42
37
|
class PdfEngine {
|
|
43
38
|
constructor() {
|
|
44
39
|
this._licenseKey = '';
|
|
45
40
|
this._fonts = new Map();
|
|
46
41
|
this._images = new Map();
|
|
42
|
+
this._files = new Map();
|
|
43
|
+
this._profiles = new Map();
|
|
47
44
|
this._markdownStyles = new Map();
|
|
48
45
|
this._disposed = false;
|
|
49
|
-
this._encrypt = null;
|
|
50
46
|
}
|
|
51
47
|
/**
|
|
52
48
|
* Set the license key. Returns `this` for chaining.
|
|
@@ -90,30 +86,31 @@ class PdfEngine {
|
|
|
90
86
|
return this;
|
|
91
87
|
}
|
|
92
88
|
/**
|
|
93
|
-
* Register the
|
|
94
|
-
*
|
|
89
|
+
* Register the bytes of a file the document carries, for the `<file>` of its `<attachments>` whose `ref`, or with
|
|
90
|
+
* no ref whose name, is `name`. The PDF carries them as they are. Call before `render`. Returns `this` for chaining.
|
|
95
91
|
*/
|
|
96
|
-
|
|
92
|
+
loadFile(name, bytes) {
|
|
97
93
|
this._throwIfDisposed();
|
|
98
|
-
this.
|
|
94
|
+
this._files.set(name, bytes);
|
|
99
95
|
return this;
|
|
100
96
|
}
|
|
101
97
|
/**
|
|
102
|
-
*
|
|
103
|
-
*
|
|
98
|
+
* Register the bytes of an ICC color profile, for the `<profile>` of the document's `<assets>` whose `ref`, or with
|
|
99
|
+
* no ref whose name, is `name`: the press profile a PDF/X document names in its output. Call before `render`.
|
|
100
|
+
* Returns `this` for chaining.
|
|
104
101
|
*/
|
|
105
|
-
|
|
102
|
+
loadProfile(name, bytes) {
|
|
106
103
|
this._throwIfDisposed();
|
|
107
|
-
this.
|
|
104
|
+
this._profiles.set(name, bytes);
|
|
108
105
|
return this;
|
|
109
106
|
}
|
|
110
107
|
/**
|
|
111
|
-
*
|
|
112
|
-
* Returns `this` for chaining.
|
|
108
|
+
* Register the text of a file of Markdown rules, the root of which is a `<markdown-styles>`, for the `src` that
|
|
109
|
+
* names it, as `<markdown-styles src="…">` does. Call before `render`. Returns `this` for chaining.
|
|
113
110
|
*/
|
|
114
|
-
|
|
111
|
+
loadMarkdownStyles(src, text) {
|
|
115
112
|
this._throwIfDisposed();
|
|
116
|
-
this.
|
|
113
|
+
this._markdownStyles.set(src, text);
|
|
117
114
|
return this;
|
|
118
115
|
}
|
|
119
116
|
/**
|
|
@@ -142,6 +139,46 @@ class PdfEngine {
|
|
|
142
139
|
engine.load_markdown_styles(src, text);
|
|
143
140
|
}
|
|
144
141
|
}
|
|
142
|
+
/**
|
|
143
|
+
* Hand the engine the files the document carries: the ones loaded here, and the ones read from the `src` of a file
|
|
144
|
+
* that wasn't. A `src` that can't be read is an error that names the file and the path.
|
|
145
|
+
*/
|
|
146
|
+
_loadFiles(engine, srcs) {
|
|
147
|
+
const files = new Map(this._files);
|
|
148
|
+
for (const [key, src] of srcs) {
|
|
149
|
+
if (files.has(key))
|
|
150
|
+
continue;
|
|
151
|
+
try {
|
|
152
|
+
files.set(key, (0, node_fs_1.readFileSync)(src));
|
|
153
|
+
}
|
|
154
|
+
catch (e) {
|
|
155
|
+
throw new LpdfRenderError(`file '${key}' of <attachments>: cannot read its src '${src}': ${e instanceof Error ? e.message : String(e)}`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
for (const [key, bytes] of files) {
|
|
159
|
+
engine.load_file(key, bytes);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Hand the engine the color profiles the document declares: the ones loaded here, and the ones read from the `src`
|
|
164
|
+
* of a profile that wasn't. A `src` that can't be read is an error that names the profile and the path.
|
|
165
|
+
*/
|
|
166
|
+
_loadProfiles(engine, srcs) {
|
|
167
|
+
const profiles = new Map(this._profiles);
|
|
168
|
+
for (const [key, src] of srcs) {
|
|
169
|
+
if (profiles.has(key))
|
|
170
|
+
continue;
|
|
171
|
+
try {
|
|
172
|
+
profiles.set(key, (0, node_fs_1.readFileSync)(src));
|
|
173
|
+
}
|
|
174
|
+
catch (e) {
|
|
175
|
+
throw new LpdfRenderError(`profile '${key}' of <assets>: cannot read its src '${src}': ${e instanceof Error ? e.message : String(e)}`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
for (const [key, bytes] of profiles) {
|
|
179
|
+
engine.load_profile(key, bytes);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
145
182
|
_throwIfDisposed() {
|
|
146
183
|
if (this._disposed)
|
|
147
184
|
throw new Error('PdfEngine has been disposed.');
|
|
@@ -176,6 +213,8 @@ class PdfEngine {
|
|
|
176
213
|
engine.load_image(name, bytes);
|
|
177
214
|
}
|
|
178
215
|
this._loadMarkdownStyles(engine, markdownStylesSrcs(xml));
|
|
216
|
+
this._loadFiles(engine, extractAssetSrcs(xml, 'file'));
|
|
217
|
+
this._loadProfiles(engine, extractAssetSrcs(xml, 'profile'));
|
|
179
218
|
// Auto-load images declared via <image src="…"> that weren't pre-loaded.
|
|
180
219
|
for (const [key, src] of extractAssetSrcs(xml, 'image')) {
|
|
181
220
|
if (!this._images.has(key)) {
|
|
@@ -185,11 +224,8 @@ class PdfEngine {
|
|
|
185
224
|
catch { /* skip unresolvable image */ }
|
|
186
225
|
}
|
|
187
226
|
}
|
|
188
|
-
if (this._encrypt) {
|
|
189
|
-
configureEncryption(engine, this._encrypt);
|
|
190
|
-
}
|
|
191
227
|
const dataJson = callOptions.data != null ? JSON.stringify(callOptions.data) : null;
|
|
192
|
-
pdf = engine.render_pdf(xml, dataJson);
|
|
228
|
+
pdf = engine.render_pdf(xml, dataJson, ...(0, _shared_1.encryptionArguments)(callOptions, secureRandomBytes));
|
|
193
229
|
}
|
|
194
230
|
else {
|
|
195
231
|
// JSON (Kit tree) path — pass JSON directly to render_tree_pdf. Fonts and images the
|
|
@@ -220,14 +256,15 @@ class PdfEngine {
|
|
|
220
256
|
engine.load_image(name, bytes);
|
|
221
257
|
}
|
|
222
258
|
this._loadMarkdownStyles(engine, markdownStylesSrcsOfDocument(input));
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
pdf = engine.render_tree_pdf(json);
|
|
259
|
+
this._loadFiles(engine, fileSrcsOfDocument(input));
|
|
260
|
+
this._loadProfiles(engine, assetSrcsOfDocument(input, 'profiles'));
|
|
261
|
+
pdf = engine.render_tree_pdf(json, ...(0, _shared_1.encryptionArguments)(callOptions, secureRandomBytes));
|
|
227
262
|
}
|
|
228
263
|
}
|
|
229
264
|
catch (e) {
|
|
230
265
|
engine.free();
|
|
266
|
+
if (e instanceof LpdfRenderError)
|
|
267
|
+
throw e;
|
|
231
268
|
const msg = e instanceof Error ? e.message : String(e);
|
|
232
269
|
throw new LpdfRenderError(msg);
|
|
233
270
|
}
|
|
@@ -237,16 +274,40 @@ class PdfEngine {
|
|
|
237
274
|
}
|
|
238
275
|
exports.PdfEngine = PdfEngine;
|
|
239
276
|
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
240
|
-
|
|
277
|
+
// Comments and CDATA sections, whose text is not markup: a <file> shown in a Markdown block is text, not a file.
|
|
278
|
+
const XML_NOT_MARKUP_RE = /<!--[\s\S]*?-->|<!\[CDATA\[[\s\S]*?\]\]>/g;
|
|
279
|
+
const XML_ATTRIBUTE_RE = /([\w:.-]+)\s*=\s*(?:"([^"]*)"|'([^']*)')/g;
|
|
280
|
+
const XML_ENTITY_RE = /&(?:(amp|lt|gt|quot|apos)|#(\d+)|#x([0-9a-fA-F]+));/g;
|
|
281
|
+
const XML_ENTITIES = { amp: '&', lt: '<', gt: '>', quot: '"', apos: "'" };
|
|
282
|
+
/** An attribute value as the XML means it, with its entities and character references decoded. */
|
|
283
|
+
function decodeXml(value) {
|
|
284
|
+
return value.replace(XML_ENTITY_RE, (_, name, decimal, hex) =>
|
|
285
|
+
// XML_ENTITY_RE matches exactly one of its three groups, so without a name or a decimal there is a hex.
|
|
286
|
+
name ? XML_ENTITIES[name] : String.fromCodePoint(parseInt(decimal ?? hex, decimal ? 10 : 16)));
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* The attributes of each `<tag>` element in XML, read as the engine reads them: comments and CDATA sections are left
|
|
290
|
+
* out, a quoted value may hold a `>`, either quote may be used, and the values are decoded.
|
|
291
|
+
*/
|
|
292
|
+
function xmlElements(xml, tag) {
|
|
293
|
+
const elements = [];
|
|
294
|
+
// Attribute values may contain '>', so quoted runs are matched whole.
|
|
295
|
+
const re = new RegExp(`<${tag}\\b((?:[^>"']|"[^"]*"|'[^']*')*)>`, 'g');
|
|
296
|
+
for (const match of xml.replace(XML_NOT_MARKUP_RE, '').matchAll(re)) {
|
|
297
|
+
const attributes = new Map();
|
|
298
|
+
for (const attribute of match[1].matchAll(XML_ATTRIBUTE_RE)) {
|
|
299
|
+
attributes.set(attribute[1], decodeXml(attribute[2] ?? attribute[3]));
|
|
300
|
+
}
|
|
301
|
+
elements.push(attributes);
|
|
302
|
+
}
|
|
303
|
+
return elements;
|
|
304
|
+
}
|
|
305
|
+
/** The `ref ?? name → src` pairs of the `<font>`, `<image>`, `<file>` or `<profile>` elements in XML. */
|
|
241
306
|
function extractAssetSrcs(xml, tag) {
|
|
242
307
|
const result = new Map();
|
|
243
|
-
const
|
|
244
|
-
|
|
245
|
-
const
|
|
246
|
-
const name = /\bname="([^"]*)"/.exec(t)?.[1];
|
|
247
|
-
const ref = /\bref="([^"]*)"/.exec(t)?.[1];
|
|
248
|
-
const src = /\bsrc="([^"]*)"/.exec(t)?.[1];
|
|
249
|
-
const key = ref ?? name;
|
|
308
|
+
for (const attributes of xmlElements(xml, tag)) {
|
|
309
|
+
const key = attributes.get('ref') ?? attributes.get('name');
|
|
310
|
+
const src = attributes.get('src');
|
|
250
311
|
if (key && src)
|
|
251
312
|
result.set(key, src);
|
|
252
313
|
}
|
|
@@ -255,8 +316,8 @@ function extractAssetSrcs(xml, tag) {
|
|
|
255
316
|
/** The `src` of each `<markdown-styles>` in XML. */
|
|
256
317
|
function markdownStylesSrcs(xml) {
|
|
257
318
|
const srcs = [];
|
|
258
|
-
for (const
|
|
259
|
-
const src =
|
|
319
|
+
for (const attributes of xmlElements(xml, 'markdown-styles')) {
|
|
320
|
+
const src = attributes.get('src');
|
|
260
321
|
if (src)
|
|
261
322
|
srcs.push(src);
|
|
262
323
|
}
|
|
@@ -270,14 +331,24 @@ function markdownStylesSrcsOfDocument(document) {
|
|
|
270
331
|
if (child.type !== 'markdown')
|
|
271
332
|
continue;
|
|
272
333
|
for (const part of child.nodes) {
|
|
273
|
-
|
|
274
|
-
|
|
334
|
+
const src = part.type === 'markdown-styles' ? part.attrs['src'] : undefined;
|
|
335
|
+
if (typeof src === 'string' && src)
|
|
336
|
+
srcs.push(src);
|
|
275
337
|
}
|
|
276
338
|
}
|
|
277
339
|
}
|
|
278
340
|
return srcs;
|
|
279
341
|
}
|
|
280
|
-
/** The `ref ?? name → src` pairs of the
|
|
342
|
+
/** The `ref ?? name → src` pairs of the files a document carries in `attrs.attachments`. */
|
|
343
|
+
function fileSrcsOfDocument(document) {
|
|
344
|
+
const result = new Map();
|
|
345
|
+
for (const { name, ref, src } of document.attrs['attachments'] ?? []) {
|
|
346
|
+
if (src)
|
|
347
|
+
result.set(ref ?? name, src);
|
|
348
|
+
}
|
|
349
|
+
return result;
|
|
350
|
+
}
|
|
351
|
+
/** The `ref ?? name → src` pairs of the fonts, images or color profiles a document declares in `attrs.assets`. */
|
|
281
352
|
function assetSrcsOfDocument(document, kind) {
|
|
282
353
|
const result = new Map();
|
|
283
354
|
const declared = document.attrs['assets']?.[kind] ?? [];
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
export { PdfEngine, LpdfRenderError } from './engine';
|
|
2
|
-
export type { EncryptAlgorithm, EncryptPermissions, EncryptOptions } from './engine';
|
|
3
2
|
export type { RenderOptions, EngineOptions } from './_shared';
|
|
4
|
-
export { FieldType, Pin, Orientation, SectionType, FootnoteCounter, BuiltinFont, PageScope } from './constants';
|
|
5
|
-
export type { PdfDocument, LpdfSectionNode, LpdfSectionChild, LpdfLayoutBlock, DocumentTokens,
|
|
6
|
-
export type { ColumnAttr, RowAttr, GridAttr, ListAttr, LiAttr, FrameAttr, LinkAttr, TableAttr, TheadAttr, TrAttr, TdAttr, TextAttr, CodeAttr, SpanAttr, CodeSpanAttr, DividerAttr, ImgAttr, ShapeAttr, BarcodeAttr, RegionAttr, FieldAttr, BookmarkAttr, LayerAttr, RectAttr, CircleAttr, EllipseAttr, LineAttr, PathAttr, TextAtAttr, ImgAtAttr, BarcodeAtAttr, FontAttr, ImageAttr, LayoutAttr, MarkdownAttr, MarkdownStylesAttr, MarkdownH1Attr, MarkdownH2Attr, MarkdownH3Attr, MarkdownH4Attr, MarkdownH5Attr, MarkdownH6Attr, MarkdownPAttr, MarkdownCodeAttr, MarkdownQuoteAttr, MarkdownLiAttr, MarkdownAAttr, MarkdownStrongAttr, MarkdownEmAttr, MarkdownDelAttr, MarkdownTableAttr, MarkdownThAttr, MarkdownTdAttr, } from './attrs';
|
|
3
|
+
export { FieldType, Pin, Orientation, SectionType, FootnoteCounter, Cipher, Permission, FileRelationship, BuiltinFont, PageScope, } from './constants';
|
|
4
|
+
export type { PdfDocument, LpdfSectionNode, LpdfSectionChild, LpdfLayoutBlock, DocumentTokens, TokenSlot, TokenRow, DocumentAssets, DocumentMeta, DocumentOutput, SectionAttr, DocumentAttr, } from './kit';
|
|
5
|
+
export type { ColumnAttr, RowAttr, GridAttr, ListAttr, LiAttr, FrameAttr, LinkAttr, TableAttr, TheadAttr, TrAttr, TdAttr, TextAttr, CodeAttr, SpanAttr, CodeSpanAttr, DividerAttr, ImgAttr, ShapeAttr, BarcodeAttr, RegionAttr, FieldAttr, BookmarkAttr, LayerAttr, RectAttr, CircleAttr, EllipseAttr, LineAttr, PathAttr, TextAtAttr, ImgAtAttr, BarcodeAtAttr, FontAttr, ImageAttr, FileAttr, ProfileAttr, LayoutAttr, GradientToken, GradientStop, MarkdownAttr, MarkdownStylesAttr, MarkdownH1Attr, MarkdownH2Attr, MarkdownH3Attr, MarkdownH4Attr, MarkdownH5Attr, MarkdownH6Attr, MarkdownPAttr, MarkdownCodeAttr, MarkdownQuoteAttr, MarkdownLiAttr, MarkdownAAttr, MarkdownStrongAttr, MarkdownEmAttr, MarkdownDelAttr, MarkdownTableAttr, MarkdownThAttr, MarkdownTdAttr, } from './attrs';
|
|
7
6
|
export type { LpdfNode, LpdfContainerNode, LpdfListNode, LpdfLiNode, LpdfTextNode, LpdfCodeNode, LpdfSpanNode, LpdfCodeSpanNode, LpdfFnNode, LpdfDividerNode, LpdfImgNode, LpdfShapeNode, LpdfBarcodeNode, LpdfTableNode, LpdfTheadNode, LpdfTrNode, LpdfTdNode, LpdfRegionNode, LpdfFieldNode, LpdfBookmarkNode, } from './layout';
|
|
8
7
|
export { LMarkdown } from './markdown';
|
|
9
8
|
export type { LpdfMarkdownNode, LpdfMarkdownStylesNode, LpdfMarkdownContentNode, LpdfMarkdownRuleNode, } from './markdown';
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.NoAttr = exports.L = exports.CanvasTransform = exports.LMarkdown = exports.PageScope = exports.BuiltinFont = exports.FootnoteCounter = exports.SectionType = exports.Orientation = exports.Pin = exports.FieldType = exports.LpdfRenderError = exports.PdfEngine = void 0;
|
|
3
|
+
exports.NoAttr = exports.L = exports.CanvasTransform = exports.LMarkdown = exports.PageScope = exports.BuiltinFont = exports.FileRelationship = exports.Permission = exports.Cipher = exports.FootnoteCounter = exports.SectionType = exports.Orientation = exports.Pin = exports.FieldType = exports.LpdfRenderError = exports.PdfEngine = void 0;
|
|
4
4
|
// ── Engine ────────────────────────────────────────────────────────────────────
|
|
5
5
|
var engine_1 = require("./engine");
|
|
6
6
|
Object.defineProperty(exports, "PdfEngine", { enumerable: true, get: function () { return engine_1.PdfEngine; } });
|
|
@@ -12,6 +12,9 @@ Object.defineProperty(exports, "Pin", { enumerable: true, get: function () { ret
|
|
|
12
12
|
Object.defineProperty(exports, "Orientation", { enumerable: true, get: function () { return constants_1.Orientation; } });
|
|
13
13
|
Object.defineProperty(exports, "SectionType", { enumerable: true, get: function () { return constants_1.SectionType; } });
|
|
14
14
|
Object.defineProperty(exports, "FootnoteCounter", { enumerable: true, get: function () { return constants_1.FootnoteCounter; } });
|
|
15
|
+
Object.defineProperty(exports, "Cipher", { enumerable: true, get: function () { return constants_1.Cipher; } });
|
|
16
|
+
Object.defineProperty(exports, "Permission", { enumerable: true, get: function () { return constants_1.Permission; } });
|
|
17
|
+
Object.defineProperty(exports, "FileRelationship", { enumerable: true, get: function () { return constants_1.FileRelationship; } });
|
|
15
18
|
Object.defineProperty(exports, "BuiltinFont", { enumerable: true, get: function () { return constants_1.BuiltinFont; } });
|
|
16
19
|
Object.defineProperty(exports, "PageScope", { enumerable: true, get: function () { return constants_1.PageScope; } });
|
|
17
20
|
// ── Markdown ──────────────────────────────────────────────────────────────────
|
package/dist/kit.d.ts
CHANGED
|
@@ -22,24 +22,12 @@
|
|
|
22
22
|
import type { LpdfBookmarkNode, LpdfNode } from './layout';
|
|
23
23
|
import type { LpdfCanvasLayerNode } from './canvas';
|
|
24
24
|
import type { LpdfMarkdownNode } from './markdown';
|
|
25
|
-
import type { FontAttr, ImageAttr, LayoutAttr } from './attrs';
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* A gradient of the tokens, which a background or a fill uses as `gradient:name`. Give `from` and `to` for two
|
|
33
|
-
* colors, or `stops` for more. `angle` is the direction of a linear gradient in degrees: 0 runs top to bottom
|
|
34
|
-
* and 90 left to right. A radial gradient runs from the center of the box out to its farthest corner.
|
|
35
|
-
*/
|
|
36
|
-
export interface GradientToken {
|
|
37
|
-
type: 'linear' | 'radial';
|
|
38
|
-
from?: string;
|
|
39
|
-
to?: string;
|
|
40
|
-
angle?: number | string;
|
|
41
|
-
stops?: GradientStop[];
|
|
42
|
-
}
|
|
25
|
+
import type { FileAttr, FontAttr, GradientToken, ImageAttr, LayoutAttr, ProfileAttr } from './attrs';
|
|
26
|
+
import { type AttrValue } from './_shared';
|
|
27
|
+
/** A slot of a token row, from the smallest to the largest. */
|
|
28
|
+
export type TokenSlot = 'xs' | 's' | 'm' | 'l' | 'xl' | 'xxl';
|
|
29
|
+
/** A token row: a value for each slot it sets. */
|
|
30
|
+
export type TokenRow<T> = Partial<Record<TokenSlot, T>>;
|
|
43
31
|
export interface DocumentTokens {
|
|
44
32
|
colors?: Record<string, string>;
|
|
45
33
|
gradients?: Record<string, GradientToken>;
|
|
@@ -49,23 +37,30 @@ export interface DocumentTokens {
|
|
|
49
37
|
* starting with a letter, and is neither a slot nor `fill` or `full`.
|
|
50
38
|
*/
|
|
51
39
|
aliases?: Record<string, string>;
|
|
52
|
-
space?:
|
|
53
|
-
grid?:
|
|
54
|
-
border?:
|
|
55
|
-
radius?:
|
|
56
|
-
width?:
|
|
40
|
+
space?: TokenRow<string>;
|
|
41
|
+
grid?: TokenRow<string>;
|
|
42
|
+
border?: TokenRow<string>;
|
|
43
|
+
radius?: TokenRow<string>;
|
|
44
|
+
width?: TokenRow<string>;
|
|
57
45
|
/** The heights `height` names: `{ xs: '16pt', s: '24pt', m: '32pt', l: '48pt', xl: '64pt', xxl: '96pt' }` by default. */
|
|
58
|
-
height?:
|
|
59
|
-
textSize?:
|
|
60
|
-
lineHeight
|
|
46
|
+
height?: TokenRow<string>;
|
|
47
|
+
textSize?: TokenRow<string>;
|
|
48
|
+
/** The factors `lineHeight` names, each a number above 0: `{ xs: 1, s: 1.1, m: 1.2, l: 1.4, xl: 1.6, xxl: 2 }` by default. */
|
|
49
|
+
lineHeight?: TokenRow<number>;
|
|
61
50
|
}
|
|
62
51
|
/**
|
|
63
|
-
* The fonts and
|
|
64
|
-
* is picked by its `name`: text sets `font` to a font's name, an `img` sets `name` to an image's
|
|
52
|
+
* The fonts, images and color profiles the document declares, as the `assets` element of the XML does. A font or
|
|
53
|
+
* image is picked by its `name`: text sets `font` to a font's name, an `img` sets `name` to an image's, and the
|
|
54
|
+
* output's `profile` names a profile.
|
|
65
55
|
*/
|
|
66
56
|
export interface DocumentAssets {
|
|
67
57
|
fonts?: FontAttr[];
|
|
68
58
|
images?: ImageAttr[];
|
|
59
|
+
/**
|
|
60
|
+
* ICC color profiles: the profile of the printing press a PDF/X document is made for, which the printer gives out.
|
|
61
|
+
* Each is read from its `src`, or loaded with `loadProfile` under its `ref` or name.
|
|
62
|
+
*/
|
|
63
|
+
profiles?: ProfileAttr[];
|
|
69
64
|
}
|
|
70
65
|
export interface DocumentMeta {
|
|
71
66
|
title?: string;
|
|
@@ -73,37 +68,107 @@ export interface DocumentMeta {
|
|
|
73
68
|
subject?: string;
|
|
74
69
|
keywords?: string;
|
|
75
70
|
creator?: string;
|
|
71
|
+
/** The language the document is written in, as a language tag such as `en-US`. A PDF/UA document needs it. */
|
|
72
|
+
lang?: string;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* How the PDF file is written, as the `output` element of the XML is: whether it is encrypted, and what a reader
|
|
76
|
+
* may do with it, and the standard it meets. The passwords are not here: they come with the render call.
|
|
77
|
+
*/
|
|
78
|
+
export interface DocumentOutput {
|
|
79
|
+
/** The cipher the PDF is encrypted with, `aes-256` or `rc4-128` (`Cipher`). Without it the PDF is not encrypted. */
|
|
80
|
+
encrypt?: string;
|
|
81
|
+
/**
|
|
82
|
+
* What a reader may do without the owner password, separated by spaces (`Permission`): `all`, or any of
|
|
83
|
+
* `print`, `modify`, `copy`, `annotate`, `fill-forms`, `accessibility`, `assemble`. A permission comes only from
|
|
84
|
+
* naming it: without `allow`, or with `''`, nothing is allowed, and `all` allows everything. It needs `encrypt`.
|
|
85
|
+
*/
|
|
86
|
+
allow?: string;
|
|
87
|
+
/**
|
|
88
|
+
* Writes the PDF as PDF/A, the standard for files kept for the long term: `2b`, or `2u` when its text must also
|
|
89
|
+
* be searchable. The render needs `createdOn`, and every text a font of `assets`. What PDF/A cannot hold is an
|
|
90
|
+
* error that says what to change: a built-in font, a CMYK color, a form field, a barcode's digits, `encrypt`.
|
|
91
|
+
*/
|
|
92
|
+
pdfa?: string;
|
|
93
|
+
/**
|
|
94
|
+
* Writes the PDF as PDF/UA-1, a tagged PDF a screen reader can read: `1`. It combines with `pdfa`. The render
|
|
95
|
+
* needs `createdOn`, the meta a `title` and a `lang`, every image and barcode of the layout an `alt`, and every
|
|
96
|
+
* text a font of `assets`. What PDF/UA cannot hold is an error that says what to change.
|
|
97
|
+
*/
|
|
98
|
+
pdfua?: string;
|
|
99
|
+
/**
|
|
100
|
+
* Writes the PDF as PDF/X-4, for a commercial printer: `4`. It needs `profile`, and combines with `pdfua`. Every
|
|
101
|
+
* page gets a TrimBox and a BleedBox, RGB is tied to sRGB, and links print as text, as PDF/X allows nothing
|
|
102
|
+
* clickable. The render needs `createdOn`, the meta a `title`, and every text a font of `assets`. What PDF/X cannot
|
|
103
|
+
* hold is an error that says what to change: a profile that is not a printer profile, a built-in font, a form
|
|
104
|
+
* field, a CMYK color with a profile that is not a CMYK one, `encrypt`, `pdfa`, attachments.
|
|
105
|
+
*/
|
|
106
|
+
pdfx?: string;
|
|
107
|
+
/** The profile of `assets` that a PDF/X file is made for: the ICC profile of the printing press. It needs `pdfx`. */
|
|
108
|
+
profile?: string;
|
|
109
|
+
/**
|
|
110
|
+
* Writes the PDF linearized, for fast web view: page 1 comes first in the file, with hints that say where every
|
|
111
|
+
* other page is, so a viewer that fetches the file by byte ranges, as a browser does, shows page 1 while the rest
|
|
112
|
+
* downloads. Each page then names only the fonts and images it draws. With `encrypt` the file is encrypted first
|
|
113
|
+
* and linearized last. Any change to the file afterwards, such as a stamp, ends the linearization.
|
|
114
|
+
*/
|
|
115
|
+
linearize?: boolean;
|
|
76
116
|
}
|
|
77
117
|
export interface SectionAttr {
|
|
78
118
|
size?: string;
|
|
79
119
|
orientation?: string;
|
|
120
|
+
/** How far this section's pages reach past their trim edge, such as `5mm`. Overrides the document's; `0mm` takes it away. */
|
|
121
|
+
bleed?: string;
|
|
80
122
|
background?: string;
|
|
81
123
|
title?: string;
|
|
82
|
-
debug?:
|
|
124
|
+
debug?: boolean;
|
|
83
125
|
type?: string;
|
|
84
126
|
tocIndentStep?: string;
|
|
85
127
|
footnoteCounter?: string;
|
|
128
|
+
/**
|
|
129
|
+
* The number of the section's first page, which starts a new run of pages: `1` restarts the count. Without it the
|
|
130
|
+
* pages count on from the section before. `{page}` prints a page's number, and `{pages}` how many pages its run has.
|
|
131
|
+
*/
|
|
132
|
+
pageStart?: number;
|
|
133
|
+
/**
|
|
134
|
+
* How the section's page numbers are written: `decimal`, `lower-alpha`, `upper-alpha`, `lower-roman` or
|
|
135
|
+
* `upper-roman`. Without it the section keeps the format before.
|
|
136
|
+
*/
|
|
137
|
+
pageFormat?: string;
|
|
138
|
+
/** Text before the section's page numbers, such as `A-`. Without it the section keeps the prefix before; `''` takes it away. */
|
|
139
|
+
pagePrefix?: string;
|
|
86
140
|
}
|
|
87
141
|
export interface DocumentAttr {
|
|
88
142
|
size?: string;
|
|
89
143
|
orientation?: string;
|
|
144
|
+
/**
|
|
145
|
+
* How far each page reaches past its trim edge, such as `3mm`, for a background or an image that runs off the page
|
|
146
|
+
* when it is cut. The page grows by it and its background fills it; the layout keeps to the trimmed page.
|
|
147
|
+
*/
|
|
148
|
+
bleed?: string;
|
|
90
149
|
background?: string;
|
|
91
150
|
font?: string;
|
|
92
151
|
assets?: DocumentAssets;
|
|
93
152
|
tokens?: DocumentTokens;
|
|
94
153
|
meta?: DocumentMeta;
|
|
95
|
-
|
|
154
|
+
output?: DocumentOutput;
|
|
155
|
+
/**
|
|
156
|
+
* Files the PDF carries inside it, as the `attachments` element of the XML does: a reader lists them in its
|
|
157
|
+
* attachments panel. Each file's bytes are read from its `src`, or loaded with `loadFile` under its `ref` or name.
|
|
158
|
+
*/
|
|
159
|
+
attachments?: FileAttr[];
|
|
160
|
+
debug?: boolean;
|
|
96
161
|
footnoteCounter?: string;
|
|
97
162
|
}
|
|
98
163
|
/** A layout block — wraps an ordered list of layout nodes. */
|
|
99
164
|
export interface LpdfLayoutBlock {
|
|
100
165
|
type: 'layout';
|
|
101
|
-
attrs: Record<string,
|
|
166
|
+
attrs: Record<string, AttrValue>;
|
|
102
167
|
nodes: LpdfNode[];
|
|
103
168
|
}
|
|
104
169
|
export interface LpdfSectionNode {
|
|
105
170
|
type: 'section';
|
|
106
|
-
attrs: Record<string,
|
|
171
|
+
attrs: Record<string, AttrValue>;
|
|
107
172
|
nodes: LpdfSectionChild[];
|
|
108
173
|
}
|
|
109
174
|
/**
|
package/dist/kit.js
CHANGED
|
@@ -35,13 +35,15 @@ function section(attrs, nodes = []) {
|
|
|
35
35
|
};
|
|
36
36
|
}
|
|
37
37
|
function document(attrs, nodes = []) {
|
|
38
|
-
const { assets, tokens, meta, ...restOpts } = attrs ?? {};
|
|
38
|
+
const { assets, tokens, meta, output, attachments, ...restOpts } = attrs ?? {};
|
|
39
39
|
const attrsObj = {
|
|
40
40
|
...(0, _shared_1.buildAttrs)(restOpts),
|
|
41
41
|
};
|
|
42
42
|
if (assets !== undefined)
|
|
43
43
|
attrsObj['assets'] = assets;
|
|
44
44
|
if (tokens !== undefined) {
|
|
45
|
+
// A factor of the line-height row and a gradient's angle are numbers, which JSON can't hold as NaN or infinity.
|
|
46
|
+
(0, _shared_1.assertFiniteIn)('tokens', tokens);
|
|
45
47
|
const { textSize, lineHeight, ...rest } = tokens;
|
|
46
48
|
attrsObj['tokens'] = {
|
|
47
49
|
...rest,
|
|
@@ -51,6 +53,10 @@ function document(attrs, nodes = []) {
|
|
|
51
53
|
}
|
|
52
54
|
if (meta !== undefined)
|
|
53
55
|
attrsObj['meta'] = meta;
|
|
56
|
+
if (output !== undefined)
|
|
57
|
+
attrsObj['output'] = output;
|
|
58
|
+
if (attachments !== undefined)
|
|
59
|
+
attrsObj['attachments'] = attachments;
|
|
54
60
|
return {
|
|
55
61
|
version: 1,
|
|
56
62
|
type: 'document',
|
package/dist/layout.d.ts
CHANGED
|
@@ -1,98 +1,99 @@
|
|
|
1
1
|
import type { ColumnAttr, RowAttr, GridAttr, ListAttr, LiAttr, FrameAttr, LinkAttr, TableAttr, TheadAttr, TrAttr, TdAttr, TextAttr, CodeAttr, SpanAttr, CodeSpanAttr, DividerAttr, ImgAttr, ShapeAttr, BarcodeAttr, FieldAttr, RegionAttr, BookmarkAttr } from './attrs';
|
|
2
|
+
import { type AttrValue } from './_shared';
|
|
2
3
|
export interface LpdfSpanNode {
|
|
3
4
|
type: 'span';
|
|
4
|
-
attrs: Record<string,
|
|
5
|
+
attrs: Record<string, AttrValue>;
|
|
5
6
|
nodes: string[];
|
|
6
7
|
}
|
|
7
8
|
/** A run of code inside a text: its words in the code font on a tint. */
|
|
8
9
|
export interface LpdfCodeSpanNode {
|
|
9
10
|
type: 'code-span';
|
|
10
|
-
attrs: Record<string,
|
|
11
|
+
attrs: Record<string, AttrValue>;
|
|
11
12
|
nodes: string[];
|
|
12
13
|
}
|
|
13
14
|
/** A footnote: its words go at the bottom of the page where its number lands. */
|
|
14
15
|
export interface LpdfFnNode {
|
|
15
16
|
type: 'fn';
|
|
16
|
-
attrs: Record<string,
|
|
17
|
+
attrs: Record<string, AttrValue>;
|
|
17
18
|
nodes: (string | LpdfSpanNode)[];
|
|
18
19
|
}
|
|
19
20
|
export interface LpdfContainerNode {
|
|
20
21
|
type: 'column' | 'row' | 'grid' | 'frame' | 'link';
|
|
21
|
-
attrs: Record<string,
|
|
22
|
+
attrs: Record<string, AttrValue>;
|
|
22
23
|
nodes: LpdfNode[];
|
|
23
24
|
}
|
|
24
25
|
/** A list of items, each marked with a bullet or a number the engine gives. */
|
|
25
26
|
export interface LpdfListNode {
|
|
26
27
|
type: 'list';
|
|
27
|
-
attrs: Record<string,
|
|
28
|
+
attrs: Record<string, AttrValue>;
|
|
28
29
|
nodes: LpdfLiNode[];
|
|
29
30
|
}
|
|
30
31
|
/** One item of a list: what a layout holds, beside the item's marker. */
|
|
31
32
|
export interface LpdfLiNode {
|
|
32
33
|
type: 'li';
|
|
33
|
-
attrs: Record<string,
|
|
34
|
+
attrs: Record<string, AttrValue>;
|
|
34
35
|
nodes: LpdfNode[];
|
|
35
36
|
}
|
|
36
37
|
export interface LpdfTextNode {
|
|
37
38
|
type: 'text';
|
|
38
|
-
attrs: Record<string,
|
|
39
|
+
attrs: Record<string, AttrValue>;
|
|
39
40
|
nodes: (string | LpdfSpanNode | LpdfCodeSpanNode | LpdfFnNode)[];
|
|
40
41
|
}
|
|
41
42
|
/** Code in a box. Its strings keep their spaces and lines; its spans color parts of it. */
|
|
42
43
|
export interface LpdfCodeNode {
|
|
43
44
|
type: 'code';
|
|
44
|
-
attrs: Record<string,
|
|
45
|
+
attrs: Record<string, AttrValue>;
|
|
45
46
|
nodes: (string | LpdfSpanNode)[];
|
|
46
47
|
}
|
|
47
48
|
export interface LpdfDividerNode {
|
|
48
49
|
type: 'divider';
|
|
49
|
-
attrs: Record<string,
|
|
50
|
+
attrs: Record<string, AttrValue>;
|
|
50
51
|
}
|
|
51
52
|
export interface LpdfImgNode {
|
|
52
53
|
type: 'img';
|
|
53
|
-
attrs: Record<string,
|
|
54
|
+
attrs: Record<string, AttrValue>;
|
|
54
55
|
}
|
|
55
56
|
export interface LpdfShapeNode {
|
|
56
57
|
type: 'shape';
|
|
57
|
-
attrs: Record<string,
|
|
58
|
+
attrs: Record<string, AttrValue>;
|
|
58
59
|
}
|
|
59
60
|
export interface LpdfBarcodeNode {
|
|
60
61
|
type: 'barcode';
|
|
61
|
-
attrs: Record<string,
|
|
62
|
+
attrs: Record<string, AttrValue>;
|
|
62
63
|
}
|
|
63
64
|
export interface LpdfTheadNode {
|
|
64
65
|
type: 'thead';
|
|
65
|
-
attrs: Record<string,
|
|
66
|
+
attrs: Record<string, AttrValue>;
|
|
66
67
|
nodes: LpdfTdNode[];
|
|
67
68
|
}
|
|
68
69
|
export interface LpdfTrNode {
|
|
69
70
|
type: 'tr';
|
|
70
|
-
attrs: Record<string,
|
|
71
|
+
attrs: Record<string, AttrValue>;
|
|
71
72
|
nodes: LpdfTdNode[];
|
|
72
73
|
}
|
|
73
74
|
export interface LpdfTdNode {
|
|
74
75
|
type: 'td';
|
|
75
|
-
attrs: Record<string,
|
|
76
|
+
attrs: Record<string, AttrValue>;
|
|
76
77
|
nodes: LpdfNode[];
|
|
77
78
|
}
|
|
78
79
|
export interface LpdfTableNode {
|
|
79
80
|
type: 'table';
|
|
80
|
-
attrs: Record<string,
|
|
81
|
+
attrs: Record<string, AttrValue>;
|
|
81
82
|
nodes: (LpdfTheadNode | LpdfTrNode)[];
|
|
82
83
|
}
|
|
83
84
|
export interface LpdfRegionNode {
|
|
84
85
|
type: 'region';
|
|
85
|
-
attrs: Record<string,
|
|
86
|
+
attrs: Record<string, AttrValue>;
|
|
86
87
|
nodes: LpdfNode[];
|
|
87
88
|
}
|
|
88
89
|
export interface LpdfFieldNode {
|
|
89
90
|
type: 'field';
|
|
90
|
-
attrs: Record<string,
|
|
91
|
+
attrs: Record<string, AttrValue>;
|
|
91
92
|
}
|
|
92
93
|
/** An outline entry and link target that marks the node after it; it draws nothing. */
|
|
93
94
|
export interface LpdfBookmarkNode {
|
|
94
95
|
type: 'bookmark';
|
|
95
|
-
attrs: Record<string,
|
|
96
|
+
attrs: Record<string, AttrValue>;
|
|
96
97
|
}
|
|
97
98
|
export type LpdfNode = LpdfContainerNode | LpdfListNode | LpdfTextNode | LpdfCodeNode | LpdfDividerNode | LpdfTableNode | LpdfImgNode | LpdfShapeNode | LpdfBarcodeNode | LpdfRegionNode | LpdfFieldNode | LpdfBookmarkNode;
|
|
98
99
|
declare function column(attrs: ColumnAttr | null, nodes?: LpdfNode[]): LpdfContainerNode;
|
package/dist/markdown.d.ts
CHANGED
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
import type { MarkdownAttr, MarkdownStylesAttr, MarkdownH1Attr, MarkdownH2Attr, MarkdownH3Attr, MarkdownH4Attr, MarkdownH5Attr, MarkdownH6Attr, MarkdownPAttr, MarkdownCodeAttr, MarkdownQuoteAttr, MarkdownLiAttr, MarkdownAAttr, MarkdownStrongAttr, MarkdownEmAttr, MarkdownDelAttr, MarkdownTableAttr, MarkdownThAttr, MarkdownTdAttr } from './attrs';
|
|
2
|
+
import { type AttrValue } from './_shared';
|
|
2
3
|
/** A rule of a markdown's styles: the element it is named after, with the attributes it sets. */
|
|
3
4
|
export interface LpdfMarkdownRuleNode {
|
|
4
5
|
type: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'p' | 'code' | 'quote' | 'li' | 'a' | 'strong' | 'em' | 'del' | 'table' | 'th' | 'td';
|
|
5
|
-
attrs: Record<string,
|
|
6
|
+
attrs: Record<string, AttrValue>;
|
|
6
7
|
}
|
|
7
8
|
/** The rules that say how the parts of a markdown look, with a file of them in `src` when it has one. */
|
|
8
9
|
export interface LpdfMarkdownStylesNode {
|
|
9
10
|
type: 'markdown-styles';
|
|
10
|
-
attrs: Record<string,
|
|
11
|
+
attrs: Record<string, AttrValue>;
|
|
11
12
|
nodes: LpdfMarkdownRuleNode[];
|
|
12
13
|
}
|
|
13
14
|
/** The Markdown itself, as strings. */
|
|
14
15
|
export interface LpdfMarkdownContentNode {
|
|
15
16
|
type: 'markdown-content';
|
|
16
|
-
attrs: Record<string,
|
|
17
|
+
attrs: Record<string, AttrValue>;
|
|
17
18
|
nodes: string[];
|
|
18
19
|
}
|
|
19
20
|
/** A markdown, which takes the place of a layout in a section and holds only Markdown. */
|
|
20
21
|
export interface LpdfMarkdownNode {
|
|
21
22
|
type: 'markdown';
|
|
22
|
-
attrs: Record<string,
|
|
23
|
+
attrs: Record<string, AttrValue>;
|
|
23
24
|
nodes: (LpdfMarkdownStylesNode | LpdfMarkdownContentNode)[];
|
|
24
25
|
}
|
|
25
26
|
/**
|