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.
- package/README.md +189 -27
- package/dist/__tests__/e2e/pdf-assertions.d.ts +20 -3
- package/dist/__tests__/e2e/pdf-assertions.d.ts.map +1 -1
- package/dist/__tests__/e2e/pdf-assertions.js +151 -86
- package/dist/__tests__/e2e/pdf-assertions.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/models.d.ts +106 -1
- package/dist/models.d.ts.map +1 -1
- package/dist/models.js +195 -2
- package/dist/models.js.map +1 -1
- package/dist/paragraph-builder.d.ts +2 -2
- package/dist/paragraph-builder.d.ts.map +1 -1
- package/dist/paragraph-builder.js +10 -2
- package/dist/paragraph-builder.js.map +1 -1
- package/dist/pdfdancer_v1.d.ts +41 -4
- package/dist/pdfdancer_v1.d.ts.map +1 -1
- package/dist/pdfdancer_v1.js +198 -20
- package/dist/pdfdancer_v1.js.map +1 -1
- package/dist/types.d.ts +15 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +41 -1
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/e2e/acroform.test.ts +13 -0
- package/src/__tests__/e2e/create-new.test.ts +133 -0
- package/src/__tests__/e2e/form_x_object.test.ts +8 -0
- package/src/__tests__/e2e/image.test.ts +30 -18
- package/src/__tests__/e2e/line.test.ts +33 -6
- package/src/__tests__/e2e/page.test.ts +4 -0
- package/src/__tests__/e2e/paragraph.test.ts +29 -2
- package/src/__tests__/e2e/path.test.ts +8 -0
- package/src/__tests__/e2e/pdf-assertions.ts +164 -73
- package/src/__tests__/url-builder.test.ts +44 -0
- package/src/index.ts +8 -1
- package/src/models.ts +255 -1
- package/src/paragraph-builder.ts +13 -5
- package/src/pdfdancer_v1.ts +277 -28
- package/src/types.ts +55 -3
package/src/paragraph-builder.ts
CHANGED
|
@@ -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<
|
|
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
|
-
|
|
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
|
-
|
|
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
|
package/src/pdfdancer_v1.ts
CHANGED
|
@@ -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
|
-
|
|
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.
|
|
117
|
+
async delete(): Promise<boolean> {
|
|
118
|
+
return this._client.deletePage(this._pageIndex);
|
|
103
119
|
}
|
|
104
120
|
|
|
105
|
-
|
|
106
|
-
|
|
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(
|
|
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(
|
|
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<
|
|
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.
|
|
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<
|
|
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.
|
|
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
|
|
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<
|
|
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
|
-
|
|
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()
|
|
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()
|
|
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<
|
|
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()
|
|
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(
|
|
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
|
-
|
|
953
|
-
return pageRefs.map((
|
|
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<
|
|
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
|
-
|
|
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
|
}
|