@pdfme/common 6.2.4 → 6.2.5-dev.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/expression.d.ts +6 -0
- package/dist/helper.d.ts +9 -0
- package/dist/index.js +188 -30
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/version.d.ts +1 -1
- package/package.json +1 -1
package/dist/expression.d.ts
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import type { Schema, SchemaPageArray } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* False only for strings JSON.parse would reject, so parseData can skip the throw. Index scans, not
|
|
4
|
+
* regexes: V8 keeps the subject of the last successful match (RegExp.input), which would pin a large
|
|
5
|
+
* value after the call.
|
|
6
|
+
*/
|
|
7
|
+
export declare const mayBeJson: (value: string) => boolean;
|
|
2
8
|
/**
|
|
3
9
|
* Resolve a read-only schema's render value.
|
|
4
10
|
* Text `content` is an expression template. MVT `content` is a variable JSON
|
package/dist/helper.d.ts
CHANGED
|
@@ -2,6 +2,11 @@ import type { PDFDocument, PDFPage } from '@pdfme/pdf-lib';
|
|
|
2
2
|
import { Template, Font, BasePdf, Plugins, BlankPdf, PdfBytes } from './types.js';
|
|
3
3
|
export declare const cloneDeep: <T>(value: T) => T;
|
|
4
4
|
export declare const getFallbackFontName: (font: Font) => string;
|
|
5
|
+
/**
|
|
6
|
+
* The built-in fallback font. Every call returns a new Font object around the same bytes, decoded
|
|
7
|
+
* once and kept for the life of the process: do not modify or transfer them (e.g. in a
|
|
8
|
+
* postMessage transfer list).
|
|
9
|
+
*/
|
|
5
10
|
export declare const getDefaultFont: () => Font;
|
|
6
11
|
export declare const mm2pt: (mm: number) => number;
|
|
7
12
|
export declare const pt2mm: (pt: number) => number;
|
|
@@ -16,6 +21,10 @@ export declare const migrateTemplate: (template: Template) => void;
|
|
|
16
21
|
export declare const getInputFromTemplate: (template: Template) => {
|
|
17
22
|
[key: string]: string;
|
|
18
23
|
}[];
|
|
24
|
+
/**
|
|
25
|
+
* Checks the URL's literal host only. DNS names that resolve to internal addresses and
|
|
26
|
+
* redirects are not covered; validate untrusted templates server-side if that matters.
|
|
27
|
+
*/
|
|
19
28
|
export declare const isUrlSafeToFetch: (urlString: string) => boolean;
|
|
20
29
|
export type PdfLinkAnnotationRect = {
|
|
21
30
|
x: number;
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import { Buffer } from "buffer";
|
|
|
3
3
|
import { PDFName } from "@pdfme/pdf-lib";
|
|
4
4
|
import * as acorn from "acorn";
|
|
5
5
|
//#region src/version.ts
|
|
6
|
-
var PDFME_VERSION = "6.2.
|
|
6
|
+
var PDFME_VERSION = "6.2.5";
|
|
7
7
|
//#endregion
|
|
8
8
|
//#region src/pageSize.ts
|
|
9
9
|
var PAGE_SIZE_PRESETS = {
|
|
@@ -373,10 +373,19 @@ var getFallbackFontName = (font) => {
|
|
|
373
373
|
if (fallbackFontName === initial) throw Error(`[@pdfme/common] fallback flag is not found in font. true fallback flag must be only one.`);
|
|
374
374
|
return fallbackFontName;
|
|
375
375
|
};
|
|
376
|
-
var
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
376
|
+
var defaultFontData;
|
|
377
|
+
/**
|
|
378
|
+
* The built-in fallback font. Every call returns a new Font object around the same bytes, decoded
|
|
379
|
+
* once and kept for the life of the process: do not modify or transfer them (e.g. in a
|
|
380
|
+
* postMessage transfer list).
|
|
381
|
+
*/
|
|
382
|
+
var getDefaultFont = () => {
|
|
383
|
+
if (!defaultFontData) defaultFontData = b64toUint8Array(DEFAULT_FONT_VALUE);
|
|
384
|
+
return { [DEFAULT_FONT_NAME]: {
|
|
385
|
+
data: defaultFontData,
|
|
386
|
+
fallback: true
|
|
387
|
+
} };
|
|
388
|
+
};
|
|
380
389
|
var mm2pt = (mm) => {
|
|
381
390
|
return parseFloat(String(mm)) * MM_TO_PT_RATIO;
|
|
382
391
|
};
|
|
@@ -423,6 +432,123 @@ var getInputFromTemplate = (template) => {
|
|
|
423
432
|
});
|
|
424
433
|
return [input];
|
|
425
434
|
};
|
|
435
|
+
var parseIpv4 = (host) => {
|
|
436
|
+
const match = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(host);
|
|
437
|
+
if (!match) return null;
|
|
438
|
+
const octets = match.slice(1).map(Number);
|
|
439
|
+
return octets.every((octet) => octet <= 255) ? octets : null;
|
|
440
|
+
};
|
|
441
|
+
var parseIpv6 = (host) => {
|
|
442
|
+
let address = host.toLowerCase();
|
|
443
|
+
const lastColon = address.lastIndexOf(":");
|
|
444
|
+
const tail = address.slice(lastColon + 1);
|
|
445
|
+
if (tail.includes(".")) {
|
|
446
|
+
const octets = parseIpv4(tail);
|
|
447
|
+
if (!octets) return null;
|
|
448
|
+
const high = (octets[0] << 8 | octets[1]).toString(16);
|
|
449
|
+
const low = (octets[2] << 8 | octets[3]).toString(16);
|
|
450
|
+
address = `${address.slice(0, lastColon + 1)}${high}:${low}`;
|
|
451
|
+
}
|
|
452
|
+
const halves = address.split("::");
|
|
453
|
+
if (halves.length > 2) return null;
|
|
454
|
+
const toGroups = (part) => part === "" ? [] : part.split(":");
|
|
455
|
+
const head = toGroups(halves[0]);
|
|
456
|
+
let groups = head;
|
|
457
|
+
if (halves.length === 2) {
|
|
458
|
+
const rest = toGroups(halves[1]);
|
|
459
|
+
const missing = 8 - head.length - rest.length;
|
|
460
|
+
if (missing < 1) return null;
|
|
461
|
+
groups = [
|
|
462
|
+
...head,
|
|
463
|
+
...Array(missing).fill("0"),
|
|
464
|
+
...rest
|
|
465
|
+
];
|
|
466
|
+
}
|
|
467
|
+
if (groups.length !== 8 || !groups.every((group) => /^[0-9a-f]{1,4}$/.test(group))) return null;
|
|
468
|
+
return groups.map((group) => parseInt(group, 16));
|
|
469
|
+
};
|
|
470
|
+
var ipv4ToInt = (octets) => (octets[0] << 24 | octets[1] << 16 | octets[2] << 8 | octets[3]) >>> 0;
|
|
471
|
+
var toIpv4Range = (cidr) => {
|
|
472
|
+
const [address, prefix] = cidr.split("/");
|
|
473
|
+
const prefixLength = Number(prefix);
|
|
474
|
+
const mask = prefixLength === 0 ? 0 : -1 << 32 - prefixLength >>> 0;
|
|
475
|
+
return {
|
|
476
|
+
base: (ipv4ToInt(parseIpv4(address)) & mask) >>> 0,
|
|
477
|
+
mask
|
|
478
|
+
};
|
|
479
|
+
};
|
|
480
|
+
var toIpv6Range = (cidr) => {
|
|
481
|
+
const [address, prefix] = cidr.split("/");
|
|
482
|
+
return {
|
|
483
|
+
base: parseIpv6(address),
|
|
484
|
+
prefixLength: Number(prefix)
|
|
485
|
+
};
|
|
486
|
+
};
|
|
487
|
+
var NON_PUBLIC_IPV4_RANGES = [
|
|
488
|
+
"0.0.0.0/8",
|
|
489
|
+
"10.0.0.0/8",
|
|
490
|
+
"100.64.0.0/10",
|
|
491
|
+
"127.0.0.0/8",
|
|
492
|
+
"169.254.0.0/16",
|
|
493
|
+
"172.16.0.0/12",
|
|
494
|
+
"192.0.0.0/24",
|
|
495
|
+
"192.0.2.0/24",
|
|
496
|
+
"192.88.99.0/24",
|
|
497
|
+
"192.168.0.0/16",
|
|
498
|
+
"198.18.0.0/15",
|
|
499
|
+
"198.51.100.0/24",
|
|
500
|
+
"203.0.113.0/24",
|
|
501
|
+
"224.0.0.0/4",
|
|
502
|
+
"240.0.0.0/4"
|
|
503
|
+
].map(toIpv4Range);
|
|
504
|
+
var NON_PUBLIC_IPV6_RANGES = [
|
|
505
|
+
"::/96",
|
|
506
|
+
"100::/64",
|
|
507
|
+
"2001::/32",
|
|
508
|
+
"2001:db8::/32",
|
|
509
|
+
"64:ff9b:1::/48",
|
|
510
|
+
"fc00::/7",
|
|
511
|
+
"fe80::/10",
|
|
512
|
+
"fec0::/10",
|
|
513
|
+
"ff00::/8"
|
|
514
|
+
].map(toIpv6Range);
|
|
515
|
+
var LOOPBACK_HOSTNAMES = /* @__PURE__ */ new Set([
|
|
516
|
+
"localhost",
|
|
517
|
+
"localhost.localdomain",
|
|
518
|
+
"ip6-localhost",
|
|
519
|
+
"ip6-loopback"
|
|
520
|
+
]);
|
|
521
|
+
var IPV4_MAPPED_RANGE = toIpv6Range("::ffff:0:0/96");
|
|
522
|
+
var NAT64_WELL_KNOWN_RANGE = toIpv6Range("64:ff9b::/96");
|
|
523
|
+
var SIX_TO_FOUR_RANGE = toIpv6Range("2002::/16");
|
|
524
|
+
var isPublicIpv4 = (octets) => {
|
|
525
|
+
const value = ipv4ToInt(octets);
|
|
526
|
+
return NON_PUBLIC_IPV4_RANGES.every(({ base, mask }) => (value & mask) >>> 0 !== base);
|
|
527
|
+
};
|
|
528
|
+
var isInIpv6Range = (groups, { base, prefixLength }) => {
|
|
529
|
+
for (let i = 0; i < 8; i++) {
|
|
530
|
+
const bits = Math.min(16, Math.max(0, prefixLength - i * 16));
|
|
531
|
+
if (bits === 0) return true;
|
|
532
|
+
const mask = 65535 << 16 - bits & 65535;
|
|
533
|
+
if ((groups[i] & mask) !== (base[i] & mask)) return false;
|
|
534
|
+
}
|
|
535
|
+
return true;
|
|
536
|
+
};
|
|
537
|
+
var ipv4FromGroups = (high, low) => [
|
|
538
|
+
high >> 8,
|
|
539
|
+
high & 255,
|
|
540
|
+
low >> 8,
|
|
541
|
+
low & 255
|
|
542
|
+
];
|
|
543
|
+
var isPublicIpv6 = (groups) => {
|
|
544
|
+
if (isInIpv6Range(groups, IPV4_MAPPED_RANGE) || isInIpv6Range(groups, NAT64_WELL_KNOWN_RANGE)) return isPublicIpv4(ipv4FromGroups(groups[6], groups[7]));
|
|
545
|
+
if (isInIpv6Range(groups, SIX_TO_FOUR_RANGE)) return isPublicIpv4(ipv4FromGroups(groups[1], groups[2]));
|
|
546
|
+
return NON_PUBLIC_IPV6_RANGES.every((range) => !isInIpv6Range(groups, range));
|
|
547
|
+
};
|
|
548
|
+
/**
|
|
549
|
+
* Checks the URL's literal host only. DNS names that resolve to internal addresses and
|
|
550
|
+
* redirects are not covered; validate untrusted templates server-side if that matters.
|
|
551
|
+
*/
|
|
426
552
|
var isUrlSafeToFetch = (urlString) => {
|
|
427
553
|
let parsed;
|
|
428
554
|
try {
|
|
@@ -432,31 +558,15 @@ var isUrlSafeToFetch = (urlString) => {
|
|
|
432
558
|
}
|
|
433
559
|
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return false;
|
|
434
560
|
const hostname = parsed.hostname.toLowerCase();
|
|
435
|
-
if (hostname
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
if (/^f[cd]/i.test(bare)) return false;
|
|
439
|
-
const ipv4MappedMatch = bare.match(/^::ffff:(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/i);
|
|
440
|
-
if (ipv4MappedMatch) {
|
|
441
|
-
const a = Number(ipv4MappedMatch[1]);
|
|
442
|
-
const b = Number(ipv4MappedMatch[2]);
|
|
443
|
-
if (a === 0 || a === 10 || a === 127) return false;
|
|
444
|
-
if (a === 169 && b === 254) return false;
|
|
445
|
-
if (a === 172 && b >= 16 && b <= 31) return false;
|
|
446
|
-
if (a === 192 && b === 168) return false;
|
|
447
|
-
}
|
|
448
|
-
const ipv4Match = hostname.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/);
|
|
449
|
-
if (ipv4Match) {
|
|
450
|
-
const a = Number(ipv4Match[1]);
|
|
451
|
-
const b = Number(ipv4Match[2]);
|
|
452
|
-
if (a === 0) return false;
|
|
453
|
-
if (a === 10) return false;
|
|
454
|
-
if (a === 127) return false;
|
|
455
|
-
if (a === 169 && b === 254) return false;
|
|
456
|
-
if (a === 172 && b >= 16 && b <= 31) return false;
|
|
457
|
-
if (a === 192 && b === 168) return false;
|
|
561
|
+
if (hostname.startsWith("[") && hostname.endsWith("]")) {
|
|
562
|
+
const groups = parseIpv6(hostname.slice(1, -1));
|
|
563
|
+
return groups !== null && isPublicIpv6(groups);
|
|
458
564
|
}
|
|
459
|
-
|
|
565
|
+
const host = hostname.replace(/\.+$/, "");
|
|
566
|
+
if (!host) return false;
|
|
567
|
+
const ipv4 = parseIpv4(host);
|
|
568
|
+
if (ipv4) return isPublicIpv4(ipv4);
|
|
569
|
+
return !LOOPBACK_HOSTNAMES.has(host) && !host.endsWith(".localhost");
|
|
460
570
|
};
|
|
461
571
|
var SAFE_LINK_URI_PROTOCOLS = /* @__PURE__ */ new Set([
|
|
462
572
|
"http:",
|
|
@@ -665,6 +775,50 @@ var checkGenerateProps = (data) => {
|
|
|
665
775
|
//#endregion
|
|
666
776
|
//#region src/expression.ts
|
|
667
777
|
var expressionCache = /* @__PURE__ */ new Map();
|
|
778
|
+
var isJsonWhitespace = (ch) => ch === " " || ch === " " || ch === "\n" || ch === "\r";
|
|
779
|
+
var isDigit = (ch) => ch !== void 0 && ch >= "0" && ch <= "9";
|
|
780
|
+
var isJsonNumber = (value, start, end) => {
|
|
781
|
+
let i = start;
|
|
782
|
+
if (value[i] === "-") i++;
|
|
783
|
+
if (!isDigit(value[i])) return false;
|
|
784
|
+
if (value[i] === "0") i++;
|
|
785
|
+
else while (i < end && isDigit(value[i])) i++;
|
|
786
|
+
if (value[i] === ".") {
|
|
787
|
+
const digits = ++i;
|
|
788
|
+
while (i < end && isDigit(value[i])) i++;
|
|
789
|
+
if (i === digits) return false;
|
|
790
|
+
}
|
|
791
|
+
if (value[i] === "e" || value[i] === "E") {
|
|
792
|
+
i++;
|
|
793
|
+
if (value[i] === "+" || value[i] === "-") i++;
|
|
794
|
+
const digits = i;
|
|
795
|
+
while (i < end && isDigit(value[i])) i++;
|
|
796
|
+
if (i === digits) return false;
|
|
797
|
+
}
|
|
798
|
+
return i === end;
|
|
799
|
+
};
|
|
800
|
+
/**
|
|
801
|
+
* False only for strings JSON.parse would reject, so parseData can skip the throw. Index scans, not
|
|
802
|
+
* regexes: V8 keeps the subject of the last successful match (RegExp.input), which would pin a large
|
|
803
|
+
* value after the call.
|
|
804
|
+
*/
|
|
805
|
+
var mayBeJson = (value) => {
|
|
806
|
+
let start = 0;
|
|
807
|
+
let end = value.length;
|
|
808
|
+
while (start < end && isJsonWhitespace(value[start])) start++;
|
|
809
|
+
while (end > start && isJsonWhitespace(value[end - 1])) end--;
|
|
810
|
+
const first = value[start];
|
|
811
|
+
if (first === "{") {
|
|
812
|
+
let i = start + 1;
|
|
813
|
+
while (i < end && isJsonWhitespace(value[i])) i++;
|
|
814
|
+
return value[i] === "\"" || value[i] === "}";
|
|
815
|
+
}
|
|
816
|
+
if (first === "[" || first === "\"") return true;
|
|
817
|
+
if (first === "t") return end - start === 4 && value.startsWith("true", start);
|
|
818
|
+
if (first === "f") return end - start === 5 && value.startsWith("false", start);
|
|
819
|
+
if (first === "n") return end - start === 4 && value.startsWith("null", start);
|
|
820
|
+
return isJsonNumber(value, start, end);
|
|
821
|
+
};
|
|
668
822
|
/**
|
|
669
823
|
* Parse each string value in `data` as JSON, falling back to the original
|
|
670
824
|
* string on failure. Previously memoized via a module-level `parseDataCache`
|
|
@@ -674,10 +828,14 @@ var expressionCache = /* @__PURE__ */ new Map();
|
|
|
674
828
|
* base64 (e.g. image schemas) or inputs containing base64 values. Every
|
|
675
829
|
* unique inputs state pinned its own multi-MB key for the app lifetime.
|
|
676
830
|
* Parsing is O(fields) and cheap; removing the cache is strictly a win.
|
|
831
|
+
*
|
|
832
|
+
* It is called once per placeholder field, over every field, so most strings are not JSON and
|
|
833
|
+
* a thrown SyntaxError each made it the bulk of a render. Strings that cannot be JSON skip
|
|
834
|
+
* JSON.parse (see mayBeJson); the result is the same.
|
|
677
835
|
*/
|
|
678
836
|
var parseData = (data) => {
|
|
679
837
|
return Object.fromEntries(Object.entries(data).map(([key, value]) => {
|
|
680
|
-
if (typeof value === "string") try {
|
|
838
|
+
if (typeof value === "string" && mayBeJson(value)) try {
|
|
681
839
|
return [key, JSON.parse(value)];
|
|
682
840
|
} catch {
|
|
683
841
|
return [key, value];
|