pdfdancer-client-typescript 1.0.9 → 1.0.10

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 (41) hide show
  1. package/README.md +189 -27
  2. package/dist/__tests__/e2e/pdf-assertions.d.ts +20 -3
  3. package/dist/__tests__/e2e/pdf-assertions.d.ts.map +1 -1
  4. package/dist/__tests__/e2e/pdf-assertions.js +151 -86
  5. package/dist/__tests__/e2e/pdf-assertions.js.map +1 -1
  6. package/dist/index.d.ts +1 -1
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +7 -1
  9. package/dist/index.js.map +1 -1
  10. package/dist/models.d.ts +106 -1
  11. package/dist/models.d.ts.map +1 -1
  12. package/dist/models.js +195 -2
  13. package/dist/models.js.map +1 -1
  14. package/dist/paragraph-builder.d.ts +2 -2
  15. package/dist/paragraph-builder.d.ts.map +1 -1
  16. package/dist/paragraph-builder.js +10 -2
  17. package/dist/paragraph-builder.js.map +1 -1
  18. package/dist/pdfdancer_v1.d.ts +41 -4
  19. package/dist/pdfdancer_v1.d.ts.map +1 -1
  20. package/dist/pdfdancer_v1.js +198 -20
  21. package/dist/pdfdancer_v1.js.map +1 -1
  22. package/dist/types.d.ts +15 -3
  23. package/dist/types.d.ts.map +1 -1
  24. package/dist/types.js +41 -1
  25. package/dist/types.js.map +1 -1
  26. package/package.json +1 -1
  27. package/src/__tests__/e2e/acroform.test.ts +13 -0
  28. package/src/__tests__/e2e/create-new.test.ts +133 -0
  29. package/src/__tests__/e2e/form_x_object.test.ts +8 -0
  30. package/src/__tests__/e2e/image.test.ts +30 -18
  31. package/src/__tests__/e2e/line.test.ts +33 -6
  32. package/src/__tests__/e2e/page.test.ts +4 -0
  33. package/src/__tests__/e2e/paragraph.test.ts +29 -2
  34. package/src/__tests__/e2e/path.test.ts +8 -0
  35. package/src/__tests__/e2e/pdf-assertions.ts +164 -73
  36. package/src/__tests__/url-builder.test.ts +44 -0
  37. package/src/index.ts +8 -1
  38. package/src/models.ts +255 -1
  39. package/src/paragraph-builder.ts +13 -5
  40. package/src/pdfdancer_v1.ts +277 -28
  41. package/src/types.ts +55 -3
@@ -3,12 +3,12 @@
3
3
  */
4
4
 
5
5
  import {ValidationException} from './exceptions';
6
- import {Color, Font, ObjectRef, Paragraph, Position, TextObjectRef} from './models';
6
+ import {Color, CommandResult, Font, ObjectRef, Paragraph, Position, TextObjectRef} from './models';
7
7
  import {PDFDancer} from "./pdfdancer_v1";
8
8
 
9
9
  // 👇 Internal view of PDFDancer methods, not exported
10
10
  interface PDFDancerInternals {
11
- modifyParagraph(objectRefOrPageIndex: ObjectRef, text: string | Paragraph): Promise<boolean>;
11
+ modifyParagraph(objectRefOrPageIndex: ObjectRef, text: string | Paragraph): Promise<CommandResult>;
12
12
 
13
13
  addParagraph(paragraph: Paragraph): Promise<boolean>;
14
14
  }
@@ -226,7 +226,7 @@ export class ParagraphBuilder {
226
226
  return lines;
227
227
  }
228
228
 
229
- async apply() {
229
+ async apply(): Promise<boolean | CommandResult> {
230
230
  // Wait for all deferred operations (e.g., fontFile, images, etc.)
231
231
  if (this._pending.length) {
232
232
  await Promise.all(this._pending);
@@ -247,7 +247,11 @@ export class ParagraphBuilder {
247
247
  this._font === undefined &&
248
248
  this._textColor === undefined) {
249
249
  // Simple text-only modification
250
- return await this._internals.modifyParagraph(originalRef, this._text!);
250
+ const result = await this._internals.modifyParagraph(originalRef, this._text!);
251
+ if (result.warning) {
252
+ process.stderr.write(`WARNING: ${result.warning}\n`);
253
+ }
254
+ return result;
251
255
  } else {
252
256
  // Full paragraph modification - build new paragraph using getter methods to preserve original values
253
257
  const newParagraph = new Paragraph();
@@ -257,7 +261,11 @@ export class ParagraphBuilder {
257
261
  newParagraph.textLines = this._text ? this._processTextLines(this._text) : this._processTextLines(originalRef.text!);
258
262
  newParagraph.color = this._getColor(originalRef);
259
263
 
260
- return await this._internals.modifyParagraph(originalRef, newParagraph);
264
+ const result = await this._internals.modifyParagraph(originalRef, newParagraph);
265
+ if (result.warning) {
266
+ process.stderr.write(`WARNING: ${result.warning}\n`);
267
+ }
268
+ return result;
261
269
  }
262
270
  } else {
263
271
  // Adding new paragraph
@@ -15,22 +15,32 @@ import {
15
15
  AddRequest,
16
16
  BoundingRect,
17
17
  ChangeFormFieldRequest,
18
+ Color,
19
+ CommandResult,
20
+ CreatePdfRequest,
18
21
  DeleteRequest,
19
22
  FindRequest,
20
23
  Font,
24
+ FontRecommendation,
25
+ FontType,
21
26
  FormFieldRef,
22
27
  Image,
23
28
  ModifyRequest,
24
29
  ModifyTextRequest,
25
30
  MoveRequest,
31
+ MovePageRequest,
26
32
  ObjectRef,
27
33
  ObjectType,
34
+ PageRef,
35
+ PageSize,
36
+ PageSizeInput,
37
+ Orientation,
28
38
  Paragraph,
29
39
  Position,
30
40
  PositionMode,
31
41
  ShapeType,
32
42
  TextObjectRef,
33
- Color
43
+ TextStatus
34
44
  } from './models';
35
45
  import {ParagraphBuilder} from './paragraph-builder';
36
46
  import {FormFieldObject, FormXObject, ImageObject, ParagraphObject, PathObject, TextLineObject} from "./types";
@@ -47,8 +57,6 @@ interface PDFDancerInternals {
47
57
 
48
58
  toFormXObjects(objectRefs: ObjectRef[]): FormXObject[];
49
59
 
50
- deletePage(objectRef: ObjectRef): Promise<boolean>;
51
-
52
60
  toTextLineObjects(objectRefs: ObjectRef[]): TextLineObject[];
53
61
 
54
62
  toFormFields(formFieldRefs: FormFieldRef[]): FormFieldObject[];
@@ -75,13 +83,17 @@ class PageClient {
75
83
  type: ObjectType = ObjectType.PAGE;
76
84
  position: Position;
77
85
  internalId: string;
86
+ pageSize?: PageSize;
87
+ orientation?: Orientation;
78
88
  private _internals: PDFDancerInternals;
79
89
 
80
- constructor(client: PDFDancer, pageIndex: number) {
90
+ constructor(client: PDFDancer, pageIndex: number, pageRef?: PageRef) {
81
91
  this._client = client;
82
92
  this._pageIndex = pageIndex;
83
- this.internalId = `PAGE-${this._pageIndex}`;
84
- this.position = Position.atPage(this._pageIndex);
93
+ this.internalId = pageRef?.internalId ?? `PAGE-${this._pageIndex}`;
94
+ this.position = pageRef?.position ?? Position.atPage(this._pageIndex);
95
+ this.pageSize = pageRef?.pageSize;
96
+ this.orientation = pageRef?.orientation;
85
97
  // Cast to the internal interface to get access
86
98
  this._internals = this._client as unknown as PDFDancerInternals;
87
99
  }
@@ -90,6 +102,10 @@ class PageClient {
90
102
  return this._internals.toPathObjects(await this._internals.findPaths(Position.atPageCoordinates(this._pageIndex, x, y)));
91
103
  }
92
104
 
105
+ async selectPaths() {
106
+ return this._internals.toPathObjects(await this._internals.findPaths(Position.atPage(this._pageIndex)));
107
+ }
108
+
93
109
  async selectImages() {
94
110
  return this._internals.toImageObjects(await this._internals._findImages(Position.atPage(this._pageIndex)));
95
111
  }
@@ -98,12 +114,18 @@ class PageClient {
98
114
  return this._internals.toImageObjects(await this._internals._findImages(Position.atPageCoordinates(this._pageIndex, x, y)));
99
115
  }
100
116
 
101
- async delete() {
102
- return this._internals.deletePage(this.ref());
117
+ async delete(): Promise<boolean> {
118
+ return this._client.deletePage(this._pageIndex);
103
119
  }
104
120
 
105
- private ref() {
106
- return new ObjectRef(this.internalId, this.position, this.type);
121
+ async moveTo(targetPageIndex: number): Promise<PageRef> {
122
+ const pageRef = await this._client.movePage(this._pageIndex, targetPageIndex);
123
+ this._pageIndex = pageRef.position.pageIndex ?? targetPageIndex;
124
+ this.position = pageRef.position;
125
+ this.internalId = pageRef.internalId;
126
+ this.pageSize = pageRef.pageSize;
127
+ this.orientation = pageRef.orientation;
128
+ return pageRef;
107
129
  }
108
130
 
109
131
  // noinspection JSUnusedGlobalSymbols
@@ -243,6 +265,94 @@ export class PDFDancer {
243
265
  return await client.init();
244
266
  }
245
267
 
268
+ /**
269
+ * Creates a new, blank PDF document with the specified parameters.
270
+ *
271
+ * @param options Configuration options for the new PDF
272
+ * @param options.pageSize Page size (default: "A4")
273
+ * @param options.orientation Page orientation (default: "PORTRAIT")
274
+ * @param options.initialPageCount Number of initial pages (default: 1)
275
+ * @param token Authentication token (optional, can use PDFDANCER_TOKEN env var)
276
+ * @param baseUrl Base URL for the PDFDancer API (optional)
277
+ * @param timeout Request timeout in milliseconds (default: 30000)
278
+ */
279
+ static async new(
280
+ options?: {
281
+ pageSize?: PageSizeInput;
282
+ orientation?: Orientation;
283
+ initialPageCount?: number;
284
+ },
285
+ token?: string,
286
+ baseUrl?: string,
287
+ timeout?: number
288
+ ): Promise<PDFDancer> {
289
+ const resolvedToken = token ?? process.env.PDFDANCER_TOKEN;
290
+ const resolvedBaseUrl =
291
+ baseUrl ??
292
+ process.env.PDFDANCER_BASE_URL ??
293
+ "https://api.pdfdancer.com";
294
+ const resolvedTimeout = timeout ?? 30000;
295
+
296
+ if (!resolvedToken) {
297
+ throw new Error("Missing PDFDancer token (pass it explicitly or set PDFDANCER_TOKEN in environment).");
298
+ }
299
+
300
+ let createRequest: CreatePdfRequest;
301
+ try {
302
+ createRequest = new CreatePdfRequest(
303
+ options?.pageSize ?? "A4",
304
+ options?.orientation ?? Orientation.PORTRAIT,
305
+ options?.initialPageCount ?? 1
306
+ );
307
+ } catch (error) {
308
+ const message = error instanceof Error ? error.message : String(error);
309
+ throw new ValidationException(message);
310
+ }
311
+
312
+ try {
313
+ // Build URL ensuring no double slashes
314
+ const base = resolvedBaseUrl.replace(/\/+$/, '');
315
+ const endpoint = '/session/new'.replace(/^\/+/, '');
316
+ const url = `${base}/${endpoint}`;
317
+
318
+ // Make request to create endpoint
319
+ const response = await fetch(url, {
320
+ method: 'POST',
321
+ headers: {
322
+ 'Authorization': `Bearer ${resolvedToken}`,
323
+ 'Content-Type': 'application/json'
324
+ },
325
+ body: JSON.stringify(createRequest.toDict()),
326
+ signal: resolvedTimeout > 0 ? AbortSignal.timeout(resolvedTimeout) : undefined
327
+ });
328
+
329
+ if (!response.ok) {
330
+ const errorText = await response.text();
331
+ throw new HttpClientException(`Failed to create new PDF: ${errorText}`, response);
332
+ }
333
+
334
+ const sessionId = (await response.text()).trim();
335
+
336
+ if (!sessionId) {
337
+ throw new SessionException("Server returned empty session ID");
338
+ }
339
+
340
+ const client = Object.create(PDFDancer.prototype) as PDFDancer;
341
+ client._token = resolvedToken.trim();
342
+ client._baseUrl = resolvedBaseUrl.replace(/\/+$/, '');
343
+ client._readTimeout = resolvedTimeout;
344
+ client._pdfBytes = new Uint8Array();
345
+ client._sessionId = sessionId;
346
+ return client;
347
+ } catch (error) {
348
+ if (error instanceof HttpClientException || error instanceof SessionException || error instanceof ValidationException) {
349
+ throw error;
350
+ }
351
+ const errorMessage = error instanceof Error ? error.message : String(error);
352
+ throw new HttpClientException(`Failed to create new PDF: ${errorMessage}`, undefined, error as Error);
353
+ }
354
+ }
355
+
246
356
  /**
247
357
  * Process PDF data from various input types with strict validation.
248
358
  */
@@ -277,6 +387,16 @@ export class PDFDancer {
277
387
  }
278
388
  }
279
389
 
390
+ /**
391
+ * Build a URL path ensuring no double slashes.
392
+ * Combines baseUrl and path while handling trailing/leading slashes.
393
+ */
394
+ private _buildUrl(path: string): string {
395
+ const base = this._baseUrl.replace(/\/+$/, '');
396
+ const endpoint = path.replace(/^\/+/, '');
397
+ return `${base}/${endpoint}`;
398
+ }
399
+
280
400
  /**
281
401
  * Extract meaningful error messages from API response.
282
402
  * Parses JSON error responses with _embedded.errors structure.
@@ -335,7 +455,7 @@ export class PDFDancer {
335
455
  formData.append('pdf', blob, 'document.pdf');
336
456
  }
337
457
 
338
- const response = await fetch(`${this._baseUrl}/session/create`, {
458
+ const response = await fetch(this._buildUrl('/session/create'), {
339
459
  method: 'POST',
340
460
  headers: {
341
461
  'Authorization': `Bearer ${this._token}`
@@ -374,7 +494,7 @@ export class PDFDancer {
374
494
  data?: Record<string, any>,
375
495
  params?: Record<string, string>
376
496
  ): Promise<Response> {
377
- const url = new URL(`${this._baseUrl}${path}`);
497
+ const url = new URL(this._buildUrl(path));
378
498
  if (params) {
379
499
  Object.entries(params).forEach(([key, value]) => {
380
500
  url.searchParams.append(key, value);
@@ -512,16 +632,16 @@ export class PDFDancer {
512
632
  /**
513
633
  * Retrieves references to all pages in the PDF document.
514
634
  */
515
- private async getPages(): Promise<ObjectRef[]> {
635
+ private async getPages(): Promise<PageRef[]> {
516
636
  const response = await this._makeRequest('POST', '/pdf/page/find');
517
637
  const pagesData = await response.json() as any[];
518
- return pagesData.map((pageData: any) => this._parseObjectRef(pageData));
638
+ return pagesData.map((pageData: any) => this._parsePageRef(pageData));
519
639
  }
520
640
 
521
641
  /**
522
642
  * Retrieves a reference to a specific page by its page index.
523
643
  */
524
- private async _getPage(pageIndex: number): Promise<ObjectRef | null> {
644
+ private async _getPage(pageIndex: number): Promise<PageRef | null> {
525
645
  if (pageIndex < 0) {
526
646
  throw new ValidationException(`Page index must be >= 0, got ${pageIndex}`);
527
647
  }
@@ -534,13 +654,62 @@ export class PDFDancer {
534
654
  return null;
535
655
  }
536
656
 
537
- return this._parseObjectRef(pagesData[0]);
657
+ return this._parsePageRef(pagesData[0]);
658
+ }
659
+
660
+ /**
661
+ * Moves an existing page to a new index.
662
+ */
663
+ async movePage(pageIndex: number, targetPageIndex: number): Promise<PageRef> {
664
+ this._validatePageIndex(pageIndex, 'pageIndex');
665
+ this._validatePageIndex(targetPageIndex, 'targetPageIndex');
666
+
667
+ // Ensure the source page exists before attempting the move
668
+ await this._requirePageRef(pageIndex);
669
+
670
+ const request = new MovePageRequest(pageIndex, targetPageIndex).toDict();
671
+ const response = await this._makeRequest('PUT', '/pdf/page/move', request);
672
+ const success = await response.json() as boolean;
673
+
674
+ if (!success) {
675
+ throw new HttpClientException(`Failed to move page from ${pageIndex} to ${targetPageIndex}`, response);
676
+ }
677
+
678
+ // Fetch the page again at its new position for up-to-date metadata
679
+ return await this._requirePageRef(targetPageIndex);
680
+ }
681
+
682
+ /**
683
+ * Deletes the page at the specified index.
684
+ */
685
+ async deletePage(pageIndex: number): Promise<boolean> {
686
+ this._validatePageIndex(pageIndex, 'pageIndex');
687
+
688
+ const pageRef = await this._requirePageRef(pageIndex);
689
+ return this._deletePage(pageRef);
690
+ }
691
+
692
+ private _validatePageIndex(pageIndex: number, fieldName: string): void {
693
+ if (!Number.isInteger(pageIndex)) {
694
+ throw new ValidationException(`${fieldName} must be an integer, got ${pageIndex}`);
695
+ }
696
+ if (pageIndex < 0) {
697
+ throw new ValidationException(`${fieldName} must be >= 0, got ${pageIndex}`);
698
+ }
699
+ }
700
+
701
+ private async _requirePageRef(pageIndex: number): Promise<PageRef> {
702
+ const pageRef = await this._getPage(pageIndex);
703
+ if (!pageRef) {
704
+ throw new ValidationException(`Page not found at index ${pageIndex}`);
705
+ }
706
+ return pageRef;
538
707
  }
539
708
 
540
709
  /**
541
710
  * Deletes a page from the PDF document.
542
711
  */
543
- private async deletePage(pageRef: ObjectRef): Promise<boolean> {
712
+ private async _deletePage(pageRef: ObjectRef): Promise<boolean> {
544
713
  if (!pageRef) {
545
714
  throw new ValidationException("Page reference cannot be null");
546
715
  }
@@ -649,31 +818,31 @@ export class PDFDancer {
649
818
  /**
650
819
  * Modifies a paragraph object or its text content.
651
820
  */
652
- private async modifyParagraph(objectRef: ObjectRef, newParagraph: Paragraph | string): Promise<boolean> {
821
+ private async modifyParagraph(objectRef: ObjectRef, newParagraph: Paragraph | string): Promise<CommandResult> {
653
822
  if (!objectRef) {
654
823
  throw new ValidationException("Object reference cannot be null");
655
824
  }
656
825
  if (newParagraph === null || newParagraph === undefined) {
657
- throw new ValidationException("New paragraph cannot be null");
826
+ return CommandResult.empty("ModifyParagraph", objectRef.internalId);
658
827
  }
659
828
 
660
829
  if (typeof newParagraph === 'string') {
661
- // Text modification
830
+ // Text modification - returns CommandResult
662
831
  const requestData = new ModifyTextRequest(objectRef, newParagraph).toDict();
663
832
  const response = await this._makeRequest('PUT', '/pdf/text/paragraph', requestData);
664
- return await response.json() as boolean;
833
+ return CommandResult.fromDict(await response.json());
665
834
  } else {
666
835
  // Object modification
667
836
  const requestData = new ModifyRequest(objectRef, newParagraph).toDict();
668
837
  const response = await this._makeRequest('PUT', '/pdf/modify', requestData);
669
- return await response.json() as boolean;
838
+ return CommandResult.fromDict(await response.json());
670
839
  }
671
840
  }
672
841
 
673
842
  /**
674
843
  * Modifies a text line object.
675
844
  */
676
- private async modifyTextLine(objectRef: ObjectRef, newText: string): Promise<boolean> {
845
+ private async modifyTextLine(objectRef: ObjectRef, newText: string): Promise<CommandResult> {
677
846
  if (!objectRef) {
678
847
  throw new ValidationException("Object reference cannot be null");
679
848
  }
@@ -683,7 +852,7 @@ export class PDFDancer {
683
852
 
684
853
  const requestData = new ModifyTextRequest(objectRef, newText).toDict();
685
854
  const response = await this._makeRequest('PUT', '/pdf/text/line', requestData);
686
- return await response.json() as boolean;
855
+ return CommandResult.fromDict(await response.json());
687
856
  }
688
857
 
689
858
  // Font Operations
@@ -745,7 +914,7 @@ export class PDFDancer {
745
914
  const blob = new Blob([fontData.buffer as ArrayBuffer], {type: 'font/ttf'});
746
915
  formData.append('ttfFile', blob, filename);
747
916
 
748
- const response = await fetch(`${this._baseUrl}/font/register`, {
917
+ const response = await fetch(this._buildUrl('/font/register'), {
749
918
  method: 'POST',
750
919
  headers: {
751
920
  'Authorization': `Bearer ${this._token}`,
@@ -809,6 +978,10 @@ export class PDFDancer {
809
978
 
810
979
  const objectType = objData.type as ObjectType;
811
980
 
981
+ if (objectType === ObjectType.PAGE) {
982
+ return this._parsePageRef(objData);
983
+ }
984
+
812
985
  if (this._isTextObjectData(objData, objectType)) {
813
986
  return this._parseTextObjectRef(objData);
814
987
  }
@@ -836,6 +1009,32 @@ export class PDFDancer {
836
1009
  const lineSpacings = Array.isArray(objData.lineSpacings) ? objData.lineSpacings : null;
837
1010
  const internalId = objData.internalId ?? fallbackId ?? '';
838
1011
 
1012
+ // Parse status if present
1013
+ let status: TextStatus | undefined;
1014
+ const statusData = objData.status;
1015
+ if (statusData && typeof statusData === 'object') {
1016
+ // Parse font recommendation
1017
+ const fontRecData = statusData.fontRecommendation;
1018
+ let fontRec: FontRecommendation;
1019
+ if (fontRecData && typeof fontRecData === 'object') {
1020
+ fontRec = new FontRecommendation(
1021
+ fontRecData.fontName || '',
1022
+ (fontRecData.fontType as FontType) || FontType.SYSTEM,
1023
+ fontRecData.similarityScore || 0.0
1024
+ );
1025
+ } else {
1026
+ // Create empty font recommendation if not provided
1027
+ fontRec = new FontRecommendation('', FontType.SYSTEM, 0.0);
1028
+ }
1029
+
1030
+ status = new TextStatus(
1031
+ statusData.modified || false,
1032
+ statusData.encodable !== undefined ? statusData.encodable : true,
1033
+ (statusData.fontType as FontType) || FontType.SYSTEM,
1034
+ fontRec
1035
+ );
1036
+ }
1037
+
839
1038
  const textObject = new TextObjectRef(
840
1039
  internalId,
841
1040
  position,
@@ -845,7 +1044,8 @@ export class PDFDancer {
845
1044
  typeof objData.fontSize === 'number' ? objData.fontSize : undefined,
846
1045
  lineSpacings,
847
1046
  undefined,
848
- this._parseColor(objData.color)
1047
+ this._parseColor(objData.color),
1048
+ status
849
1049
  );
850
1050
 
851
1051
  if (Array.isArray(objData.children) && objData.children.length > 0) {
@@ -858,6 +1058,55 @@ export class PDFDancer {
858
1058
  return textObject;
859
1059
  }
860
1060
 
1061
+ private _parsePageRef(objData: any): PageRef {
1062
+ const positionData = objData.position || {};
1063
+ const position = positionData ? this._parsePosition(positionData) : new Position();
1064
+
1065
+ const pageSize = this._parsePageSize(objData.pageSize);
1066
+ const orientation = this._parseOrientation(objData.orientation);
1067
+
1068
+ return new PageRef(
1069
+ objData.internalId,
1070
+ position,
1071
+ ObjectType.PAGE,
1072
+ pageSize,
1073
+ orientation
1074
+ );
1075
+ }
1076
+
1077
+ private _parsePageSize(pageSizeData: any): PageSize | undefined {
1078
+ if (!pageSizeData || typeof pageSizeData !== 'object') {
1079
+ return undefined;
1080
+ }
1081
+
1082
+ const name = typeof pageSizeData.name === 'string' ? pageSizeData.name : undefined;
1083
+ const width = typeof pageSizeData.width === 'number' ? pageSizeData.width : undefined;
1084
+ const height = typeof pageSizeData.height === 'number' ? pageSizeData.height : undefined;
1085
+
1086
+ if (name === undefined && width === undefined && height === undefined) {
1087
+ return undefined;
1088
+ }
1089
+
1090
+ return {name, width, height};
1091
+ }
1092
+
1093
+ private _parseOrientation(orientationData: any): Orientation | undefined {
1094
+ if (typeof orientationData !== 'string') {
1095
+ return undefined;
1096
+ }
1097
+
1098
+ if (orientationData === Orientation.PORTRAIT || orientationData === Orientation.LANDSCAPE) {
1099
+ return orientationData;
1100
+ }
1101
+
1102
+ const normalized = orientationData.trim().toUpperCase();
1103
+ if (normalized === Orientation.PORTRAIT || normalized === Orientation.LANDSCAPE) {
1104
+ return normalized as Orientation;
1105
+ }
1106
+
1107
+ return undefined;
1108
+ }
1109
+
861
1110
  private _parseColor(colorData: any): Color | undefined {
862
1111
  if (!colorData || typeof colorData !== 'object') {
863
1112
  return undefined;
@@ -949,8 +1198,8 @@ export class PDFDancer {
949
1198
  }
950
1199
 
951
1200
  async pages() {
952
- let pageRefs = await this.getPages();
953
- return pageRefs.map((_, pageIndex) => new PageClient(this, pageIndex));
1201
+ const pageRefs = await this.getPages();
1202
+ return pageRefs.map((pageRef, pageIndex) => new PageClient(this, pageIndex, pageRef));
954
1203
  }
955
1204
 
956
1205
  private toFormFields(objectRefs: FormFieldRef[]) {
package/src/types.ts CHANGED
@@ -1,4 +1,4 @@
1
- import {Color, FormFieldRef, ObjectRef, ObjectType, Position, TextObjectRef} from "./models";
1
+ import {Color, CommandResult, FormFieldRef, ObjectRef, ObjectType, Position, TextObjectRef} from "./models";
2
2
  import {PDFDancer} from "./pdfdancer_v1";
3
3
  import {ParagraphBuilder} from "./paragraph-builder";
4
4
 
@@ -10,7 +10,7 @@ interface PDFDancerInternals {
10
10
 
11
11
  changeFormField(formFieldRef: FormFieldRef, value: string): Promise<boolean>;
12
12
 
13
- modifyTextLine(objectRef: ObjectRef, newText: string): Promise<boolean>;
13
+ modifyTextLine(objectRef: ObjectRef, newText: string): Promise<CommandResult>;
14
14
  }
15
15
 
16
16
  export class BaseObject<TRef extends ObjectRef = ObjectRef> {
@@ -112,6 +112,30 @@ export class ParagraphObject extends BaseObject<TextObjectRef> {
112
112
  return new ParagraphBuilder(this._client, this.ref());
113
113
  }
114
114
 
115
+ objectRef() {
116
+ return this.ref();
117
+ }
118
+
119
+ getText() {
120
+ return this.text;
121
+ }
122
+
123
+ getFontName() {
124
+ return this.fontName;
125
+ }
126
+
127
+ getFontSize() {
128
+ return this.fontSize;
129
+ }
130
+
131
+ getColor() {
132
+ return this.color;
133
+ }
134
+
135
+ getChildren() {
136
+ return this.children;
137
+ }
138
+
115
139
  private setFontName(fontName: string | undefined) {
116
140
  this.fontName = fontName;
117
141
  }
@@ -185,6 +209,30 @@ export class TextLineObject extends BaseObject<TextObjectRef> {
185
209
  private setColor(color: Color | undefined) {
186
210
  this.color = color;
187
211
  }
212
+
213
+ objectRef() {
214
+ return this.ref();
215
+ }
216
+
217
+ getText() {
218
+ return this.text;
219
+ }
220
+
221
+ getFontName() {
222
+ return this.fontName;
223
+ }
224
+
225
+ getFontSize() {
226
+ return this.fontSize;
227
+ }
228
+
229
+ getColor() {
230
+ return this.color;
231
+ }
232
+
233
+ getChildren() {
234
+ return this.children;
235
+ }
188
236
  }
189
237
 
190
238
 
@@ -207,6 +255,10 @@ class TextLineBuilder {
207
255
  }
208
256
 
209
257
  async apply() {
210
- return await this._internals.modifyTextLine(this._objectRef, this._text!);
258
+ const result = await this._internals.modifyTextLine(this._objectRef, this._text!);
259
+ if (result.warning) {
260
+ process.stderr.write(`WARNING: ${result.warning}\n`);
261
+ }
262
+ return result;
211
263
  }
212
264
  }