pdf-lite 1.6.4 → 1.7.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.
Files changed (71) hide show
  1. package/dist/acroform/appearance/pdf-button-appearance-stream.js +1 -1
  2. package/dist/acroform/appearance/pdf-graphics.d.ts +48 -0
  3. package/dist/acroform/appearance/pdf-graphics.js +177 -4
  4. package/dist/acroform/appearance/pdf-text-appearance-stream.d.ts +3 -0
  5. package/dist/acroform/appearance/pdf-text-appearance-stream.js +58 -29
  6. package/dist/acroform/fields/pdf-button-form-field.d.ts +11 -2
  7. package/dist/acroform/fields/pdf-button-form-field.js +76 -37
  8. package/dist/acroform/fields/pdf-choice-form-field.js +2 -2
  9. package/dist/acroform/fields/pdf-form-field.d.ts +39 -9
  10. package/dist/acroform/fields/pdf-form-field.js +234 -46
  11. package/dist/acroform/fields/pdf-text-form-field.js +23 -3
  12. package/dist/acroform/pdf-acro-form.d.ts +1 -0
  13. package/dist/acroform/pdf-acro-form.js +15 -4
  14. package/dist/acroform/xfa/pdf-xfa-data.d.ts +2 -1
  15. package/dist/acroform/xfa/pdf-xfa-data.js +36 -28
  16. package/dist/annotations/pdf-annotation.d.ts +1 -1
  17. package/dist/annotations/pdf-annotation.js +16 -2
  18. package/dist/core/objects/pdf-array.d.ts +6 -1
  19. package/dist/core/objects/pdf-array.js +3 -0
  20. package/dist/core/objects/pdf-boolean.d.ts +6 -2
  21. package/dist/core/objects/pdf-boolean.js +3 -0
  22. package/dist/core/objects/pdf-comment.d.ts +6 -2
  23. package/dist/core/objects/pdf-comment.js +3 -0
  24. package/dist/core/objects/pdf-date.d.ts +4 -0
  25. package/dist/core/objects/pdf-date.js +3 -0
  26. package/dist/core/objects/pdf-dictionary.d.ts +5 -0
  27. package/dist/core/objects/pdf-dictionary.js +16 -0
  28. package/dist/core/objects/pdf-hexadecimal.d.ts +6 -2
  29. package/dist/core/objects/pdf-hexadecimal.js +3 -0
  30. package/dist/core/objects/pdf-indirect-object.d.ts +8 -1
  31. package/dist/core/objects/pdf-indirect-object.js +14 -0
  32. package/dist/core/objects/pdf-name.d.ts +6 -2
  33. package/dist/core/objects/pdf-name.js +3 -0
  34. package/dist/core/objects/pdf-null.d.ts +5 -2
  35. package/dist/core/objects/pdf-null.js +3 -0
  36. package/dist/core/objects/pdf-number.d.ts +6 -1
  37. package/dist/core/objects/pdf-number.js +3 -0
  38. package/dist/core/objects/pdf-object-reference.d.ts +5 -0
  39. package/dist/core/objects/pdf-object-reference.js +7 -0
  40. package/dist/core/objects/pdf-object.d.ts +1 -0
  41. package/dist/core/objects/pdf-start-xref.d.ts +6 -1
  42. package/dist/core/objects/pdf-start-xref.js +3 -0
  43. package/dist/core/objects/pdf-stream.d.ts +8 -0
  44. package/dist/core/objects/pdf-stream.js +7 -0
  45. package/dist/core/objects/pdf-string.d.ts +8 -2
  46. package/dist/core/objects/pdf-string.js +9 -0
  47. package/dist/core/objects/pdf-trailer.d.ts +7 -0
  48. package/dist/core/objects/pdf-trailer.js +3 -0
  49. package/dist/core/objects/pdf-xref-table.d.ts +31 -5
  50. package/dist/core/objects/pdf-xref-table.js +23 -0
  51. package/dist/fonts/font-family.d.ts +12 -0
  52. package/dist/fonts/font-family.js +1 -0
  53. package/dist/fonts/index.d.ts +1 -0
  54. package/dist/fonts/index.js +1 -0
  55. package/dist/fonts/parsers/otf-parser.d.ts +2 -2
  56. package/dist/fonts/parsers/ttf-parser.d.ts +2 -2
  57. package/dist/fonts/parsers/woff-parser.d.ts +2 -0
  58. package/dist/fonts/parsers/woff-parser.js +6 -0
  59. package/dist/fonts/pdf-font.js +94 -8
  60. package/dist/fonts/types.d.ts +10 -0
  61. package/dist/pdf/pdf-document.d.ts +7 -0
  62. package/dist/pdf/pdf-document.js +6 -0
  63. package/dist/pdf/pdf-revision.d.ts +4 -0
  64. package/dist/pdf/pdf-revision.js +6 -0
  65. package/dist/utils/iterable-readable-stream.d.ts +2 -0
  66. package/dist/utils/iterable-readable-stream.js +8 -1
  67. package/dist/utils/parse-markdown-segments.d.ts +12 -0
  68. package/dist/utils/parse-markdown-segments.js +27 -0
  69. package/dist/utils/xml.d.ts +9 -0
  70. package/dist/utils/xml.js +59 -0
  71. package/package.json +2 -2
@@ -1,6 +1,5 @@
1
1
  import { Ref } from '../ref.js';
2
- import { PdfXRefTableEntryToken } from '../tokens/xref-table-entry-token.js';
3
- import { PdfXRefTableSectionStartToken } from '../tokens/xref-table-section-start-token.js';
2
+ import { PdfToken } from '../tokens/token.js';
4
3
  import { PdfIndirectObject } from './pdf-indirect-object.js';
5
4
  import { PdfNumber } from './pdf-number.js';
6
5
  import { PdfObject } from './pdf-object.js';
@@ -15,8 +14,15 @@ export declare class PdfXRefTableEntry extends PdfObject {
15
14
  generationNumber: number | PdfNumber;
16
15
  inUse: boolean;
17
16
  });
18
- protected tokenize(): PdfXRefTableEntryToken[];
17
+ protected tokenize(): PdfToken[];
19
18
  cloneImpl(): this;
19
+ toJSON(): {
20
+ type: string;
21
+ objectNumber: number;
22
+ generationNumber: number;
23
+ byteOffset: number;
24
+ inUse: boolean;
25
+ };
20
26
  isModified(): boolean;
21
27
  }
22
28
  export declare class PdfXRefTableSectionHeader extends PdfObject {
@@ -26,8 +32,13 @@ export declare class PdfXRefTableSectionHeader extends PdfObject {
26
32
  startObjectNumber: number | PdfNumber;
27
33
  entryCount: number | PdfNumber;
28
34
  });
29
- protected tokenize(): PdfXRefTableSectionStartToken[];
35
+ protected tokenize(): PdfToken[];
30
36
  cloneImpl(): this;
37
+ toJSON(): {
38
+ type: string;
39
+ startObjectNumber: number;
40
+ entryCount: number;
41
+ };
31
42
  }
32
43
  export declare class PdfXRefTable extends PdfObject {
33
44
  sections: PdfXRefTableSectionHeader[];
@@ -42,7 +53,22 @@ export declare class PdfXRefTable extends PdfObject {
42
53
  addEntryForObject(obj: PdfIndirectObject): void;
43
54
  getEntry(objectNumber: number): PdfXRefTableEntry | undefined;
44
55
  get lastSection(): PdfXRefTableSectionHeader | null;
45
- protected tokenize(): import("../index.js").PdfToken[];
56
+ protected tokenize(): PdfToken[];
46
57
  private sortEntriesIntoSections;
47
58
  cloneImpl(): this;
59
+ toJSON(): {
60
+ type: string;
61
+ sections: {
62
+ type: string;
63
+ startObjectNumber: number;
64
+ entryCount: number;
65
+ }[];
66
+ entries: {
67
+ type: string;
68
+ objectNumber: number;
69
+ generationNumber: number;
70
+ byteOffset: number;
71
+ inUse: boolean;
72
+ }[];
73
+ };
48
74
  }
@@ -44,6 +44,15 @@ export class PdfXRefTableEntry extends PdfObject {
44
44
  inUse: this.inUse,
45
45
  });
46
46
  }
47
+ toJSON() {
48
+ return {
49
+ type: 'xref-entry',
50
+ objectNumber: this.objectNumber.value,
51
+ generationNumber: this.generationNumber.value,
52
+ byteOffset: this.byteOffset.value,
53
+ inUse: this.inUse,
54
+ };
55
+ }
47
56
  isModified() {
48
57
  return (super.isModified() ||
49
58
  this.byteOffset.isModified() ||
@@ -70,6 +79,13 @@ export class PdfXRefTableSectionHeader extends PdfObject {
70
79
  entryCount: this.entryCount.clone(),
71
80
  });
72
81
  }
82
+ toJSON() {
83
+ return {
84
+ type: 'xref-section-header',
85
+ startObjectNumber: this.startObjectNumber.value,
86
+ entryCount: this.entryCount.value,
87
+ };
88
+ }
73
89
  }
74
90
  export class PdfXRefTable extends PdfObject {
75
91
  sections;
@@ -180,4 +196,11 @@ export class PdfXRefTable extends PdfObject {
180
196
  offset: new Ref(this.offset.resolve()),
181
197
  });
182
198
  }
199
+ toJSON() {
200
+ return {
201
+ type: 'xref-table',
202
+ sections: this.sections.map((s) => s.toJSON()),
203
+ entries: this.entries.map((e) => e.toJSON()),
204
+ };
205
+ }
183
206
  }
@@ -0,0 +1,12 @@
1
+ import type { PdfFont } from './pdf-font.js';
2
+ /**
3
+ * A group of font variants for a single typeface family.
4
+ * Set on a form field via `field.fontFamily` to enable true bold/italic
5
+ * rendering in markdown appearance streams rather than stroke simulation.
6
+ */
7
+ export interface FontFamily {
8
+ regular: PdfFont;
9
+ bold?: PdfFont;
10
+ italic?: PdfFont;
11
+ boldItalic?: PdfFont;
12
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,3 +1,4 @@
1
1
  export * from './types.js';
2
2
  export * from './pdf-font.js';
3
+ export * from './font-family.js';
3
4
  export * from './parsers/index.js';
@@ -1,3 +1,4 @@
1
1
  export * from './types.js';
2
2
  export * from './pdf-font.js';
3
+ export * from './font-family.js';
3
4
  export * from './parsers/index.js';
@@ -41,10 +41,10 @@ export declare class OtfParser implements FontParser {
41
41
  private parseOS2;
42
42
  private parsePost;
43
43
  private parseName;
44
- private parseCmap;
44
+ parseCmap(): Map<number, number>;
45
45
  private parseCmapFormat4;
46
46
  private parseCmapFormat12;
47
- private parseHmtx;
47
+ parseHmtx(): Map<number, number>;
48
48
  private parseMaxp;
49
49
  private estimateStemV;
50
50
  }
@@ -33,10 +33,10 @@ export declare class TtfParser implements FontParser {
33
33
  private parseOS2;
34
34
  private parsePost;
35
35
  private parseName;
36
- private parseCmap;
36
+ parseCmap(): Map<number, number>;
37
37
  private parseCmapFormat4;
38
38
  private parseCmapFormat12;
39
- private parseHmtx;
39
+ parseHmtx(): Map<number, number>;
40
40
  private parseMaxp;
41
41
  private estimateStemV;
42
42
  }
@@ -24,6 +24,8 @@ export declare class WoffParser implements FontParser {
24
24
  * Gets character widths for a range of characters.
25
25
  */
26
26
  getCharWidths(firstChar: number, lastChar: number): number[];
27
+ parseCmap(): Map<number, number>;
28
+ parseHmtx(): Map<number, number>;
27
29
  private decompressWoff;
28
30
  }
29
31
  /**
@@ -35,6 +35,12 @@ export class WoffParser {
35
35
  getCharWidths(firstChar, lastChar) {
36
36
  return this.ttfParser.getCharWidths(firstChar, lastChar);
37
37
  }
38
+ parseCmap() {
39
+ return this.ttfParser.parseCmap();
40
+ }
41
+ parseHmtx() {
42
+ return this.ttfParser.parseHmtx();
43
+ }
38
44
  decompressWoff(woffData) {
39
45
  const data = new DataView(woffData.buffer, woffData.byteOffset, woffData.byteLength);
40
46
  // Verify WOFF signature
@@ -213,6 +213,27 @@ export class PdfFont extends PdfIndirectObject {
213
213
  * @returns The raw character width or null if not found
214
214
  */
215
215
  getRawCharacterWidth(charCode) {
216
+ // For Type0 fonts, check CID widths in descriptor
217
+ if (this.isUnicode && this._descriptor) {
218
+ const unicodeDesc = this._descriptor;
219
+ if (unicodeDesc.cidWidths) {
220
+ // Find width for this CID (which equals Unicode code point for Identity-H)
221
+ for (const entry of unicodeDesc.cidWidths) {
222
+ if ('width' in entry && entry.cid === charCode) {
223
+ return entry.width;
224
+ }
225
+ else if ('widths' in entry) {
226
+ const offset = charCode - entry.startCid;
227
+ if (offset >= 0 && offset < entry.widths.length) {
228
+ return entry.widths[offset];
229
+ }
230
+ }
231
+ }
232
+ // Not found, use default width
233
+ return unicodeDesc.defaultWidth ?? 1000;
234
+ }
235
+ }
236
+ // For Type1/TrueType fonts, use simple widths array
216
237
  if (this.widths === undefined || this.firstChar === undefined) {
217
238
  return null;
218
239
  }
@@ -285,8 +306,7 @@ export class PdfFont extends PdfIndirectObject {
285
306
  * @returns A PdfFont instance ready to be written to the PDF
286
307
  */
287
308
  static fromBytes(data) {
288
- const parser = parseFont(data);
289
- return PdfFont.fromParser(parser);
309
+ return PdfFont.fromFile(data);
290
310
  }
291
311
  /**
292
312
  * Creates a PdfFont from a FontParser instance.
@@ -582,8 +602,37 @@ export class PdfFont extends PdfIndirectObject {
582
602
  if (descriptor.cidWidths && descriptor.cidWidths.length > 0) {
583
603
  cidFontDict.set('W', PdfFont.buildCIDWidthArray(descriptor.cidWidths));
584
604
  }
585
- // CIDToGIDMap
586
- cidFontDict.set('CIDToGIDMap', new PdfName(descriptor.cidToGidMap ?? 'Identity'));
605
+ // CIDToGIDMap - Generate binary stream if unicodeMappings provided
606
+ if (unicodeMappings && unicodeMappings.size > 0) {
607
+ // Create a binary CIDToGIDMap stream
608
+ // For Identity-H encoding, CID = Unicode value
609
+ // We need to map each CID to its GID
610
+ const maxCid = Math.max(...Array.from(unicodeMappings.keys()));
611
+ const cidToGidData = new Uint8Array((maxCid + 1) * 2);
612
+ // Initialize all mappings to 0 (missing glyph)
613
+ for (let i = 0; i < cidToGidData.length; i++) {
614
+ cidToGidData[i] = 0;
615
+ }
616
+ // Fill in the mappings
617
+ for (const [unicode, glyphId] of unicodeMappings.entries()) {
618
+ const offset = unicode * 2;
619
+ // Big-endian 16-bit glyph ID
620
+ cidToGidData[offset] = (glyphId >> 8) & 0xff;
621
+ cidToGidData[offset + 1] = glyphId & 0xff;
622
+ }
623
+ const cidToGidStream = new PdfStream({
624
+ header: new PdfDictionary(),
625
+ original: cidToGidData,
626
+ });
627
+ cidToGidStream.addFilter('FlateDecode');
628
+ const cidToGidObject = new PdfIndirectObject({
629
+ content: cidToGidStream,
630
+ });
631
+ cidFontDict.set('CIDToGIDMap', cidToGidObject.reference);
632
+ }
633
+ else {
634
+ cidFontDict.set('CIDToGIDMap', new PdfName(descriptor.cidToGidMap ?? 'Identity'));
635
+ }
587
636
  const cidFontObject = new PdfIndirectObject({
588
637
  content: cidFontDict,
589
638
  });
@@ -611,21 +660,58 @@ export class PdfFont extends PdfIndirectObject {
611
660
  static fromFile(fontData, options) {
612
661
  // Parse the font to extract metadata
613
662
  const parser = parseFont(fontData);
663
+ // Check if CFF-based OTF (not supported)
664
+ if (parser instanceof OtfParser && parser.isCFFBased()) {
665
+ throw new Error('CFF-based OTF fonts are not supported yet');
666
+ }
614
667
  const info = parser.getFontInfo();
615
668
  // Auto-generate font name from metadata if not provided
616
669
  const fontName = options?.fontName ?? info.postScriptName ?? info.fullName;
617
670
  // Get the appropriate descriptor based on unicode option
618
671
  const descriptor = parser.getFontDescriptor(fontName);
672
+ // Auto-detect if Unicode font is needed if not explicitly specified
673
+ let useUnicode = options?.unicode;
674
+ if (useUnicode === undefined) {
675
+ // Check if font has glyphs beyond WinAnsiEncoding range (0-255)
676
+ const cmap = parser.parseCmap();
677
+ useUnicode = Array.from(cmap.keys()).some((unicode) => unicode > 0xff);
678
+ }
619
679
  // Embed using the appropriate method and return PdfFont
620
- if (options?.unicode) {
680
+ if (useUnicode) {
681
+ // Auto-extract cmap if not provided
682
+ const unicodeMappings = options?.unicodeMappings ?? parser.parseCmap();
683
+ // Extract glyph widths for Unicode characters
684
+ const hmtx = parser.parseHmtx();
685
+ const unitsPerEm = info.unitsPerEm;
686
+ const cidWidths = [];
687
+ // Build CID widths array from cmap + hmtx
688
+ for (const [unicode, glyphId] of unicodeMappings.entries()) {
689
+ const glyphWidth = hmtx.get(glyphId) ?? 0;
690
+ // Scale to 1000-unit em square
691
+ const scaledWidth = Math.round((glyphWidth * 1000) / unitsPerEm);
692
+ cidWidths.push({ cid: unicode, width: scaledWidth });
693
+ }
694
+ // Compute average width for default
695
+ const avgWidth = cidWidths.length > 0
696
+ ? Math.round(cidWidths.reduce((sum, entry) => {
697
+ if ('width' in entry) {
698
+ return sum + entry.width;
699
+ }
700
+ else {
701
+ // Average the widths in the range
702
+ const rangeSum = entry.widths.reduce((a, b) => a + b, 0);
703
+ return sum + rangeSum / entry.widths.length;
704
+ }
705
+ }, 0) / cidWidths.length)
706
+ : 1000;
621
707
  // For Unicode fonts, we need a UnicodeFontDescriptor
622
- // Create one by extending the base descriptor
623
708
  const unicodeDescriptor = {
624
709
  ...descriptor,
625
- defaultWidth: 1000,
710
+ defaultWidth: avgWidth,
711
+ cidWidths,
626
712
  cidToGidMap: 'Identity',
627
713
  };
628
- return PdfFont.fromType0Data(fontData, fontName, unicodeDescriptor, options.unicodeMappings);
714
+ return PdfFont.fromType0Data(fontData, fontName, unicodeDescriptor, unicodeMappings);
629
715
  }
630
716
  else {
631
717
  // Use standard TrueType embedding
@@ -8,6 +8,16 @@ export interface FontParser {
8
8
  getFontDescriptor(fontName?: string): FontDescriptor;
9
9
  getCharWidths(firstChar: number, lastChar: number): number[];
10
10
  getFontData(): ByteArray;
11
+ /**
12
+ * Parses the font's cmap table to extract Unicode to glyph ID mappings.
13
+ * @returns A map from Unicode code points to glyph IDs
14
+ */
15
+ parseCmap(): Map<number, number>;
16
+ /**
17
+ * Parses the font's hmtx table to extract glyph advance widths.
18
+ * @returns A map from glyph IDs to advance widths (in font units)
19
+ */
20
+ parseHmtx(): Map<number, number>;
11
21
  }
12
22
  /**
13
23
  * Parsed TrueType font information.
@@ -311,6 +311,13 @@ export declare class PdfDocument extends PdfObject implements IPdfObjectResolver
311
311
  * @returns A cloned PdfDocument instance
312
312
  */
313
313
  cloneImpl(): this;
314
+ toJSON(): {
315
+ type: string;
316
+ revisions: {
317
+ type: string;
318
+ objects: object[];
319
+ }[];
320
+ };
314
321
  /**
315
322
  * Creates a PdfDocument from a byte stream.
316
323
  *
@@ -967,6 +967,12 @@ export class PdfDocument extends PdfObject {
967
967
  securityHandler: this.securityHandler,
968
968
  });
969
969
  }
970
+ toJSON() {
971
+ return {
972
+ type: 'document',
973
+ revisions: this.revisions.map((rev) => rev.toJSON()),
974
+ };
975
+ }
970
976
  /**
971
977
  * Creates a PdfDocument from a byte stream.
972
978
  *
@@ -124,6 +124,10 @@ export declare class PdfRevision extends PdfObject {
124
124
  *
125
125
  * @returns A cloned PdfRevision instance
126
126
  */
127
+ toJSON(): {
128
+ type: string;
129
+ objects: object[];
130
+ };
127
131
  cloneImpl(): this;
128
132
  protected tokenize(): PdfToken[];
129
133
  isEmpty(): boolean;
@@ -251,6 +251,12 @@ export class PdfRevision extends PdfObject {
251
251
  *
252
252
  * @returns A cloned PdfRevision instance
253
253
  */
254
+ toJSON() {
255
+ return {
256
+ type: 'revision',
257
+ objects: this._objects.map((obj) => obj.toJSON()),
258
+ };
259
+ }
254
260
  cloneImpl() {
255
261
  const clonedObjects = this.objects.map((obj) => obj.clone());
256
262
  return new PdfRevision({ objects: clonedObjects });
@@ -20,5 +20,7 @@ export declare class IterableReadableStream<T> extends ReadableStream<T> {
20
20
  */
21
21
  [Symbol.asyncIterator](): {
22
22
  next(): Promise<IteratorResult<T>>;
23
+ [Symbol.asyncIterator](): /*elided*/ any;
24
+ [Symbol.asyncDispose](): Promise<void>;
23
25
  };
24
26
  }
@@ -20,11 +20,18 @@ export class IterableReadableStream extends ReadableStream {
20
20
  */
21
21
  [Symbol.asyncIterator]() {
22
22
  const reader = this.getReader();
23
- return {
23
+ const iterator = {
24
24
  async next() {
25
25
  const result = await reader.read();
26
26
  return result;
27
27
  },
28
+ [Symbol.asyncIterator]() {
29
+ return iterator;
30
+ },
31
+ async [Symbol.asyncDispose]() {
32
+ reader.releaseLock();
33
+ },
28
34
  };
35
+ return iterator;
29
36
  }
30
37
  }
@@ -0,0 +1,12 @@
1
+ export type StyledSegment = {
2
+ text: string;
3
+ bold: boolean;
4
+ italic: boolean;
5
+ };
6
+ /**
7
+ * Parses a markdown string with **bold**, *italic*, and ***bold+italic***
8
+ * syntax into an array of styled text segments.
9
+ *
10
+ * Unrecognized or unmatched asterisks are emitted as plain text.
11
+ */
12
+ export declare function parseMarkdownSegments(text: string): StyledSegment[];
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Parses a markdown string with **bold**, *italic*, and ***bold+italic***
3
+ * syntax into an array of styled text segments.
4
+ *
5
+ * Unrecognized or unmatched asterisks are emitted as plain text.
6
+ */
7
+ export function parseMarkdownSegments(text) {
8
+ const segments = [];
9
+ // Match *** before ** before * to handle longest-match first
10
+ const re = /\*\*\*(.+?)\*\*\*|\*\*(.+?)\*\*|\*(.+?)\*|([^*]+|\*)/gs;
11
+ let match;
12
+ while ((match = re.exec(text)) !== null) {
13
+ if (match[1] !== undefined) {
14
+ segments.push({ text: match[1], bold: true, italic: true });
15
+ }
16
+ else if (match[2] !== undefined) {
17
+ segments.push({ text: match[2], bold: true, italic: false });
18
+ }
19
+ else if (match[3] !== undefined) {
20
+ segments.push({ text: match[3], bold: false, italic: true });
21
+ }
22
+ else if (match[4] !== undefined && match[4].length > 0) {
23
+ segments.push({ text: match[4], bold: false, italic: false });
24
+ }
25
+ }
26
+ return segments;
27
+ }
@@ -0,0 +1,9 @@
1
+ export declare class Xml {
2
+ static escapeValue(value: string): string;
3
+ static getElementContent(xml: string, tagName: string): string | null;
4
+ static setElementContent(xml: string, tagName: string, content: string): string;
5
+ static hasElement(xml: string, tagName: string): boolean;
6
+ static insertChild(xml: string, parentTagName: string, childXml: string): string;
7
+ static wrapInElements(content: string, tagNames: string[]): string;
8
+ static escapeRegex(str: string): string;
9
+ }
@@ -0,0 +1,59 @@
1
+ export class Xml {
2
+ static escapeValue(value) {
3
+ return value
4
+ .replace(/&/g, '&amp;')
5
+ .replace(/</g, '&lt;')
6
+ .replace(/>/g, '&gt;')
7
+ .replace(/"/g, '&quot;')
8
+ .replace(/'/g, '&apos;');
9
+ }
10
+ static getElementContent(xml, tagName) {
11
+ const escaped = Xml.escapeRegex(tagName);
12
+ const regex = new RegExp(`<${escaped}(?:\\s[^>]*)?>([\\s\\S]*?)</${escaped}\\s*>`);
13
+ const match = xml.match(regex);
14
+ return match ? match[1] : null;
15
+ }
16
+ static setElementContent(xml, tagName, content) {
17
+ const escaped = Xml.escapeRegex(tagName);
18
+ // Try expanding a self-closing tag
19
+ const selfClosing = new RegExp(`<${escaped}\\s*/>`);
20
+ if (selfClosing.test(xml)) {
21
+ return xml.replace(selfClosing, `<${tagName}>${content}</${tagName}>`);
22
+ }
23
+ // Try replacing content of an existing tag
24
+ const contentRegex = new RegExp(`(<${escaped}(?:\\s[^>]*)?>)[\\s\\S]*?(</${escaped}\\s*>)`);
25
+ if (contentRegex.test(xml)) {
26
+ return xml.replace(contentRegex, `$1${content}$2`);
27
+ }
28
+ return xml;
29
+ }
30
+ static hasElement(xml, tagName) {
31
+ const escaped = Xml.escapeRegex(tagName);
32
+ return (new RegExp(`</${escaped}\\s*>`).test(xml) ||
33
+ new RegExp(`<${escaped}\\s*/>`).test(xml));
34
+ }
35
+ static insertChild(xml, parentTagName, childXml) {
36
+ const escaped = Xml.escapeRegex(parentTagName);
37
+ // Insert before closing tag
38
+ const closingRegex = new RegExp(`(</${escaped}\\s*>)`);
39
+ if (closingRegex.test(xml)) {
40
+ return xml.replace(closingRegex, `${childXml}$1`);
41
+ }
42
+ // Expand self-closing tag
43
+ const selfClosing = new RegExp(`<${escaped}\\s*/>`);
44
+ if (selfClosing.test(xml)) {
45
+ return xml.replace(selfClosing, `<${parentTagName}>${childXml}</${parentTagName}>`);
46
+ }
47
+ return xml;
48
+ }
49
+ static wrapInElements(content, tagNames) {
50
+ let result = content;
51
+ for (let i = tagNames.length - 1; i >= 0; i--) {
52
+ result = `<${tagNames[i]}>${result}</${tagNames[i]}>`;
53
+ }
54
+ return result;
55
+ }
56
+ static escapeRegex(str) {
57
+ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
58
+ }
59
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pdf-lite",
3
- "version": "1.6.4",
3
+ "version": "1.7.1",
4
4
  "main": "dist/index.js",
5
5
  "type": "module",
6
6
  "exports": {
@@ -35,7 +35,7 @@
35
35
  "@vitest/browser-playwright": "^4.0.14",
36
36
  "@vitest/coverage-v8": "^4.0.14",
37
37
  "playwright": "^1.56.1",
38
- "typescript": "5.9.3",
38
+ "typescript": "6.0.2",
39
39
  "vitest": "^4.0.14"
40
40
  },
41
41
  "repository": {