pdfdancer-client-typescript 1.0.1 → 1.0.3

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 (45) hide show
  1. package/.github/workflows/ci.yml +37 -0
  2. package/README.md +61 -65
  3. package/dist/__tests__/assertions.d.ts +2 -0
  4. package/dist/__tests__/assertions.d.ts.map +1 -0
  5. package/dist/__tests__/assertions.js +11 -0
  6. package/dist/__tests__/assertions.js.map +1 -0
  7. package/dist/client-v1.d.ts +16 -26
  8. package/dist/client-v1.d.ts.map +1 -1
  9. package/dist/client-v1.js +47 -26
  10. package/dist/client-v1.js.map +1 -1
  11. package/dist/exceptions.d.ts +0 -3
  12. package/dist/exceptions.d.ts.map +1 -1
  13. package/dist/exceptions.js +0 -3
  14. package/dist/exceptions.js.map +1 -1
  15. package/dist/index.d.ts +1 -1
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +2 -1
  18. package/dist/index.js.map +1 -1
  19. package/dist/models.d.ts +34 -9
  20. package/dist/models.d.ts.map +1 -1
  21. package/dist/models.js +71 -14
  22. package/dist/models.js.map +1 -1
  23. package/dist/paragraph-builder.d.ts +0 -8
  24. package/dist/paragraph-builder.d.ts.map +1 -1
  25. package/dist/paragraph-builder.js +0 -8
  26. package/dist/paragraph-builder.js.map +1 -1
  27. package/example.ts +6 -10
  28. package/fixtures/form-xobject-example.pdf +0 -0
  29. package/jest.config.js +25 -24
  30. package/package.json +1 -1
  31. package/src/__tests__/assertions.ts +12 -0
  32. package/src/__tests__/client-v1.test.ts +6 -6
  33. package/src/__tests__/e2e/acroform.test.ts +92 -0
  34. package/src/__tests__/e2e/form_x_object.test.ts +49 -0
  35. package/src/__tests__/e2e/image.test.ts +97 -101
  36. package/src/__tests__/e2e/line.test.ts +115 -127
  37. package/src/__tests__/e2e/page.test.ts +3 -6
  38. package/src/__tests__/e2e/paragraph.test.ts +187 -204
  39. package/src/__tests__/e2e/path.test.ts +12 -16
  40. package/src/client-v1.ts +676 -638
  41. package/src/exceptions.ts +27 -30
  42. package/src/index.ts +1 -0
  43. package/src/models.ts +436 -355
  44. package/src/paragraph-builder.ts +0 -8
  45. package/src/__tests__/e2e/form.test.ts +0 -51
package/src/models.ts CHANGED
@@ -7,38 +7,42 @@
7
7
  * Object type enumeration matching the Python ObjectType.
8
8
  */
9
9
  export enum ObjectType {
10
- IMAGE = "IMAGE",
11
- FORM = "FORM",
12
- PATH = "PATH",
13
- PARAGRAPH = "PARAGRAPH",
14
- TEXT_LINE = "TEXT_LINE",
15
- PAGE = "PAGE"
10
+ IMAGE = "IMAGE",
11
+ FORM_X_OBJECT = "FORM_X_OBJECT",
12
+ PATH = "PATH",
13
+ PARAGRAPH = "PARAGRAPH",
14
+ TEXT_LINE = "TEXT_LINE",
15
+ PAGE = "PAGE",
16
+ FORM_FIELD = "FORM_FIELD",
17
+ TEXT_FIELD = "TEXT_FIELD",
18
+ CHECK_BOX = "CHECK_BOX",
19
+ RADIO_BUTTON = "RADIO_BUTTON"
16
20
  }
17
21
 
18
22
  /**
19
23
  * Defines how position matching should be performed when searching for objects.
20
24
  */
21
25
  export enum PositionMode {
22
- INTERSECT = "INTERSECT", // Objects that intersect with the specified position area
23
- CONTAINS = "CONTAINS" // Objects completely contained within the specified position area
26
+ INTERSECT = "INTERSECT", // Objects that intersect with the specified position area
27
+ CONTAINS = "CONTAINS" // Objects completely contained within the specified position area
24
28
  }
25
29
 
26
30
  /**
27
31
  * Defines the geometric shape type used for position specification.
28
32
  */
29
33
  export enum ShapeType {
30
- POINT = "POINT", // Single point coordinate
31
- LINE = "LINE", // Linear shape between two points
32
- CIRCLE = "CIRCLE", // Circular area with radius
33
- RECT = "RECT" // Rectangular area with width and height
34
+ POINT = "POINT", // Single point coordinate
35
+ LINE = "LINE", // Linear shape between two points
36
+ CIRCLE = "CIRCLE", // Circular area with radius
37
+ RECT = "RECT" // Rectangular area with width and height
34
38
  }
35
39
 
36
40
  /**
37
41
  * Represents a 2D point with x and y coordinates.
38
42
  */
39
43
  export interface Point {
40
- x: number;
41
- y: number;
44
+ x: number;
45
+ y: number;
42
46
  }
43
47
 
44
48
  /**
@@ -46,28 +50,36 @@ export interface Point {
46
50
  * Matches the Python BoundingRect class.
47
51
  */
48
52
  export class BoundingRect {
49
- constructor(
50
- public x: number,
51
- public y: number,
52
- public width: number,
53
- public height: number
54
- ) {}
55
-
56
- getX(): number {
57
- return this.x;
58
- }
59
-
60
- getY(): number {
61
- return this.y;
62
- }
63
-
64
- getWidth(): number {
65
- return this.width;
66
- }
67
-
68
- getHeight(): number {
69
- return this.height;
70
- }
53
+ constructor(
54
+ public x: number,
55
+ public y: number,
56
+ public width: number,
57
+ public height: number
58
+ ) {
59
+ }
60
+
61
+ getX(): number {
62
+ return this.x;
63
+ }
64
+
65
+ getY(): number {
66
+ return this.y;
67
+ }
68
+
69
+ getWidth(): number {
70
+ return this.width;
71
+ }
72
+
73
+ getHeight(): number {
74
+ return this.height;
75
+ }
76
+ }
77
+
78
+ class PositioningError extends Error {
79
+ constructor(msg: string) {
80
+ super(msg);
81
+ this.name = "PositioningException";
82
+ }
71
83
  }
72
84
 
73
85
  /**
@@ -75,98 +87,119 @@ export class BoundingRect {
75
87
  * Closely mirrors the Python Position class with TypeScript conventions.
76
88
  */
77
89
  export class Position {
78
- constructor(
79
- public pageIndex?: number,
80
- public shape?: ShapeType,
81
- public mode?: PositionMode,
82
- public boundingRect?: BoundingRect,
83
- public textStartsWith?: string
84
- ) {}
85
-
86
- /**
87
- * Creates a position specification for an entire page.
88
- * Equivalent to Position.fromPageIndex() in Python.
89
- */
90
- static fromPageIndex(pageIndex: number): Position {
91
- return new Position(pageIndex, undefined, PositionMode.CONTAINS);
92
- }
93
-
94
- /**
95
- * Creates a position specification for specific coordinates on a page.
96
- * Equivalent to Position.onPageCoordinates() in Python.
97
- */
98
- static onPageCoordinates(pageIndex: number, x: number, y: number): Position {
99
- const position = Position.fromPageIndex(pageIndex);
100
- position.setPoint({ x, y });
101
- return position;
102
- }
103
-
104
- /**
105
- * Sets the position to a specific point location.
106
- * Equivalent to Position.set() in Python.
107
- */
108
- setPoint(point: Point): void {
109
- this.mode = PositionMode.CONTAINS;
110
- this.shape = ShapeType.POINT;
111
- this.boundingRect = new BoundingRect(point.x, point.y, 0, 0);
112
- }
113
-
114
- /**
115
- * Move the position horizontally by the specified offset.
116
- */
117
- moveX(xOffset: number): Position {
118
- if (this.boundingRect) {
119
- this.setPoint({ x: this.getX()! + xOffset, y: this.getY()! });
120
- }
121
- return this;
122
- }
123
-
124
- /**
125
- * Move the position vertically by the specified offset.
126
- */
127
- moveY(yOffset: number): Position {
128
- if (this.boundingRect) {
129
- this.setPoint({ x: this.getX()!, y: this.getY()! + yOffset });
130
- }
131
- return this;
132
- }
133
-
134
- /**
135
- * Returns the X coordinate of this position.
136
- */
137
- getX(): number | undefined {
138
- return this.boundingRect?.getX();
139
- }
140
-
141
- /**
142
- * Returns the Y coordinate of this position.
143
- */
144
- getY(): number | undefined {
145
- return this.boundingRect?.getY();
146
- }
147
-
148
- /**
149
- * Creates a copy of this position.
150
- */
151
- copy(): Position {
152
- let boundingRectCopy: BoundingRect | undefined;
153
- if (this.boundingRect) {
154
- boundingRectCopy = new BoundingRect(
155
- this.boundingRect.x,
156
- this.boundingRect.y,
157
- this.boundingRect.width,
158
- this.boundingRect.height
159
- );
160
- }
161
-
162
- return new Position(
163
- this.pageIndex,
164
- this.shape,
165
- this.mode,
166
- boundingRectCopy,
167
- this.textStartsWith
168
- );
169
- }
90
+ public name?: string;
91
+
92
+ constructor(
93
+ public pageIndex?: number,
94
+ public shape?: ShapeType,
95
+ public mode?: PositionMode,
96
+ public boundingRect?: BoundingRect,
97
+ public textStartsWith?: string
98
+ ) {
99
+ }
100
+
101
+ /**
102
+ * Creates a position specification for an entire page. Page indexes start with 0.
103
+ */
104
+ static atPage(pageIndex: number): Position {
105
+ return new Position(pageIndex, undefined, PositionMode.CONTAINS);
106
+ }
107
+
108
+ /**
109
+ * Creates a position specification for specific coordinates on a page.
110
+ */
111
+ static atPageCoordinates(pageIndex: number, x: number, y: number): Position {
112
+ return Position.atPage(pageIndex).atCoordinates({x, y});
113
+ }
114
+
115
+ static atPageWithText(pageIndex: number, text: string) {
116
+ return Position.atPage(pageIndex).withTextStarts(text);
117
+ }
118
+
119
+ /**
120
+ * Creates a position specification for finding objects by name.
121
+ */
122
+ static byName(name: string): Position {
123
+ const position = new Position();
124
+ position.name = name;
125
+ return position;
126
+ }
127
+
128
+ /**
129
+ * Sets the position to a specific point location.
130
+ */
131
+ atCoordinates(point: Point): this {
132
+ this.mode = PositionMode.CONTAINS;
133
+ this.shape = ShapeType.POINT;
134
+ this.boundingRect = new BoundingRect(point.x, point.y, 0, 0);
135
+ return this;
136
+ }
137
+
138
+ withTextStarts(text: string) {
139
+ this.textStartsWith = text;
140
+ return this;
141
+ }
142
+
143
+ /**
144
+ * Move the position horizontally by the specified offset.
145
+ */
146
+ moveX(xOffset: number): Position {
147
+ if (this.boundingRect) {
148
+ this.atCoordinates({x: this.getX()! + xOffset, y: this.getY()!});
149
+ } else {
150
+ throw new PositioningError("Cannot move since no initial position exists");
151
+ }
152
+ return this;
153
+ }
154
+
155
+ /**
156
+ * Move the position vertically by the specified offset.
157
+ */
158
+ moveY(yOffset: number): Position {
159
+ if (this.boundingRect) {
160
+ this.atCoordinates({x: this.getX()!, y: this.getY()! + yOffset});
161
+ } else {
162
+ throw new PositioningError("Cannot move since no initial position exists");
163
+ }
164
+ return this;
165
+ }
166
+
167
+ /**
168
+ * Returns the X coordinate of this position.
169
+ */
170
+ getX(): number | undefined {
171
+ return this.boundingRect?.getX();
172
+ }
173
+
174
+ /**
175
+ * Returns the Y coordinate of this position.
176
+ */
177
+ getY(): number | undefined {
178
+ return this.boundingRect?.getY();
179
+ }
180
+
181
+ /**
182
+ * Creates a copy of this position.
183
+ */
184
+ copy(): Position {
185
+ let boundingRectCopy: BoundingRect | undefined;
186
+ if (this.boundingRect) {
187
+ boundingRectCopy = new BoundingRect(
188
+ this.boundingRect.x,
189
+ this.boundingRect.y,
190
+ this.boundingRect.width,
191
+ this.boundingRect.height
192
+ );
193
+ }
194
+
195
+ return new Position(
196
+ this.pageIndex,
197
+ this.shape,
198
+ this.mode,
199
+ boundingRectCopy,
200
+ this.textStartsWith
201
+ );
202
+ }
170
203
  }
171
204
 
172
205
  /**
@@ -174,68 +207,88 @@ export class Position {
174
207
  * Mirrors the Python ObjectRef class exactly.
175
208
  */
176
209
  export class ObjectRef {
177
- constructor(
178
- public internalId: string,
179
- public position: Position,
180
- public type: ObjectType
181
- ) {}
182
-
183
- getInternalId(): string {
184
- return this.internalId;
185
- }
186
-
187
- getPosition(): Position {
188
- return this.position;
189
- }
190
-
191
- setPosition(position: Position): void {
192
- this.position = position;
193
- }
194
-
195
- getType(): ObjectType {
196
- return this.type;
197
- }
198
-
199
- toDict(): Record<string, any> {
200
- return {
201
- internalId: this.internalId,
202
- position: positionToDict(this.position),
203
- type: this.type
204
- };
205
- }
210
+ public name?: string;
211
+ public value?: string | null;
212
+
213
+ constructor(
214
+ public internalId: string,
215
+ public position: Position,
216
+ public type: ObjectType
217
+ ) {
218
+ }
219
+
220
+ getInternalId(): string {
221
+ return this.internalId;
222
+ }
223
+
224
+ getPosition(): Position {
225
+ return this.position;
226
+ }
227
+
228
+ setPosition(position: Position): void {
229
+ this.position = position;
230
+ }
231
+
232
+ getType(): ObjectType {
233
+ return this.type;
234
+ }
235
+
236
+ toDict(): Record<string, any> {
237
+ return {
238
+ internalId: this.internalId,
239
+ position: positionToDict(this.position),
240
+ type: this.type
241
+ };
242
+ }
243
+ }
244
+
245
+ /**
246
+ * Represents a form field reference with name and value properties.
247
+ * Extends ObjectRef to include form-specific properties.
248
+ */
249
+ export class FormFieldRef extends ObjectRef {
250
+ constructor(
251
+ internalId: string,
252
+ position: Position,
253
+ type: ObjectType,
254
+ public name?: string,
255
+ public value?: string | null
256
+ ) {
257
+ super(internalId, position, type);
258
+ }
206
259
  }
207
260
 
208
261
  /**
209
262
  * Represents an RGB color with optional alpha channel, values from 0-255.
210
263
  */
211
264
  export class Color {
212
- constructor(
213
- public r: number,
214
- public g: number,
215
- public b: number,
216
- public a: number = 255 // Alpha channel, default fully opaque
217
- ) {
218
- // Validation similar to Python client
219
- for (const component of [this.r, this.g, this.b, this.a]) {
220
- if (component < 0 || component > 255) {
221
- throw new Error(`Color component must be between 0 and 255, got ${component}`);
222
- }
223
- }
224
- }
265
+ constructor(
266
+ public r: number,
267
+ public g: number,
268
+ public b: number,
269
+ public a: number = 255 // Alpha channel, default fully opaque
270
+ ) {
271
+ // Validation similar to Python client
272
+ for (const component of [this.r, this.g, this.b, this.a]) {
273
+ if (component < 0 || component > 255) {
274
+ throw new Error(`Color component must be between 0 and 255, got ${component}`);
275
+ }
276
+ }
277
+ }
225
278
  }
226
279
 
227
280
  /**
228
281
  * Represents a font with name and size.
229
282
  */
230
283
  export class Font {
231
- constructor(
232
- public name: string,
233
- public size: number
234
- ) {
235
- if (this.size <= 0) {
236
- throw new Error(`Font size must be positive, got ${this.size}`);
237
- }
238
- }
284
+ constructor(
285
+ public name: string,
286
+ public size: number
287
+ ) {
288
+ if (this.size <= 0) {
289
+ throw new Error(`Font size must be positive, got ${this.size}`);
290
+ }
291
+ }
239
292
  }
240
293
 
241
294
  /**
@@ -243,21 +296,22 @@ export class Font {
243
296
  * Matches the Python Image class structure.
244
297
  */
245
298
  export class Image {
246
- constructor(
247
- public position?: Position,
248
- public format?: string,
249
- public width?: number,
250
- public height?: number,
251
- public data?: Uint8Array
252
- ) {}
253
-
254
- getPosition(): Position | undefined {
255
- return this.position;
256
- }
257
-
258
- setPosition(position: Position): void {
259
- this.position = position;
260
- }
299
+ constructor(
300
+ public position?: Position,
301
+ public format?: string,
302
+ public width?: number,
303
+ public height?: number,
304
+ public data?: Uint8Array
305
+ ) {
306
+ }
307
+
308
+ getPosition(): Position | undefined {
309
+ return this.position;
310
+ }
311
+
312
+ setPosition(position: Position): void {
313
+ this.position = position;
314
+ }
261
315
  }
262
316
 
263
317
  /**
@@ -265,21 +319,22 @@ export class Image {
265
319
  * Structure mirrors the Python Paragraph class.
266
320
  */
267
321
  export class Paragraph {
268
- constructor(
269
- public position?: Position,
270
- public textLines?: string[],
271
- public font?: Font,
272
- public color?: Color,
273
- public lineSpacing: number = 1.2
274
- ) {}
275
-
276
- getPosition(): Position | undefined {
277
- return this.position;
278
- }
279
-
280
- setPosition(position: Position): void {
281
- this.position = position;
282
- }
322
+ constructor(
323
+ public position?: Position,
324
+ public textLines?: string[],
325
+ public font?: Font,
326
+ public color?: Color,
327
+ public lineSpacing: number = 1.2
328
+ ) {
329
+ }
330
+
331
+ getPosition(): Position | undefined {
332
+ return this.position;
333
+ }
334
+
335
+ setPosition(position: Position): void {
336
+ this.position = position;
337
+ }
283
338
  }
284
339
 
285
340
  // Request classes for API communication
@@ -288,189 +343,215 @@ export class Paragraph {
288
343
  * Request object for find operations.
289
344
  */
290
345
  export class FindRequest {
291
- constructor(
292
- public objectType?: ObjectType,
293
- public position?: Position,
294
- public hint?: string
295
- ) {}
296
-
297
- toDict(): Record<string, any> {
298
- return {
299
- objectType: this.objectType || null,
300
- position: this.position ? positionToDict(this.position) : null,
301
- hint: this.hint || null
302
- };
303
- }
346
+ constructor(
347
+ public objectType?: ObjectType,
348
+ public position?: Position,
349
+ public hint?: string
350
+ ) {
351
+ }
352
+
353
+ toDict(): Record<string, any> {
354
+ return {
355
+ objectType: this.objectType || null,
356
+ position: this.position ? positionToDict(this.position) : null,
357
+ hint: this.hint || null
358
+ };
359
+ }
304
360
  }
305
361
 
306
362
  /**
307
363
  * Request object for delete operations.
308
364
  */
309
365
  export class DeleteRequest {
310
- constructor(public objectRef: ObjectRef) {}
311
-
312
- toDict(): Record<string, any> {
313
- return {
314
- objectRef: {
315
- internalId: this.objectRef.internalId,
316
- position: positionToDict(this.objectRef.position),
317
- type: this.objectRef.type
318
- }
319
- };
320
- }
366
+ constructor(public objectRef: ObjectRef) {
367
+ }
368
+
369
+ toDict(): Record<string, any> {
370
+ return {
371
+ objectRef: {
372
+ internalId: this.objectRef.internalId,
373
+ position: positionToDict(this.objectRef.position),
374
+ type: this.objectRef.type
375
+ }
376
+ };
377
+ }
321
378
  }
322
379
 
323
380
  /**
324
381
  * Request object for move operations.
325
382
  */
326
383
  export class MoveRequest {
327
- constructor(
328
- public objectRef: ObjectRef,
329
- public position: Position
330
- ) {}
331
-
332
- toDict(): Record<string, any> {
333
- return {
334
- objectRef: {
335
- internalId: this.objectRef.internalId,
336
- position: positionToDict(this.objectRef.position),
337
- type: this.objectRef.type
338
- },
339
- newPosition: positionToDict(this.position)
340
- };
341
- }
384
+ constructor(
385
+ public objectRef: ObjectRef,
386
+ public position: Position
387
+ ) {
388
+ }
389
+
390
+ toDict(): Record<string, any> {
391
+ return {
392
+ objectRef: {
393
+ internalId: this.objectRef.internalId,
394
+ position: positionToDict(this.objectRef.position),
395
+ type: this.objectRef.type
396
+ },
397
+ newPosition: positionToDict(this.position)
398
+ };
399
+ }
342
400
  }
343
401
 
344
402
  /**
345
403
  * Request object for add operations.
346
404
  */
347
405
  export class AddRequest {
348
- constructor(public pdfObject: Image | Paragraph) {}
349
-
350
- toDict(): Record<string, any> {
351
- return {
352
- object: this.objectToDict(this.pdfObject)
353
- };
354
- }
355
-
356
- private objectToDict(obj: Image | Paragraph): Record<string, any> {
357
- if (obj instanceof Image) {
358
- const size = obj.width !== undefined && obj.height !== undefined
359
- ? { width: obj.width, height: obj.height }
360
- : null;
361
-
362
- const dataB64 = obj.data ? btoa(String.fromCharCode(...obj.data)) : null;
363
-
364
- return {
365
- type: "IMAGE",
366
- position: obj.position ? positionToDict(obj.position) : null,
367
- format: obj.format || null,
368
- size,
369
- data: dataB64
370
- };
371
- } else if (obj instanceof Paragraph) {
372
- const lines: any[] = [];
373
- if (obj.textLines) {
374
- for (const line of obj.textLines) {
375
- const textElement = {
376
- text: line,
377
- font: obj.font ? { name: obj.font.name, size: obj.font.size } : null,
378
- color: obj.color ? { r: obj.color.r, g: obj.color.g, b: obj.color.b } : null,
379
- position: obj.position ? positionToDict(obj.position) : null
380
- };
381
-
382
- const textLine: any = {
383
- textElements: [textElement]
384
- };
385
-
386
- if (obj.color) {
387
- textLine.color = { r: obj.color.r, g: obj.color.g, b: obj.color.b };
388
- }
389
- if (obj.position) {
390
- textLine.position = positionToDict(obj.position);
391
- }
392
- lines.push(textLine);
393
- }
394
- }
406
+ constructor(public pdfObject: Image | Paragraph) {
407
+ }
395
408
 
396
- const lineSpacings = obj.lineSpacing !== undefined ? [obj.lineSpacing] : null;
409
+ toDict(): Record<string, any> {
410
+ return {
411
+ object: this.objectToDict(this.pdfObject)
412
+ };
413
+ }
397
414
 
398
- return {
399
- type: "PARAGRAPH",
400
- position: obj.position ? positionToDict(obj.position) : null,
401
- lines,
402
- lineSpacings,
403
- font: obj.font ? { name: obj.font.name, size: obj.font.size } : null
404
- };
405
- } else {
406
- throw new Error(`Unsupported object type: ${typeof obj}`);
415
+ private objectToDict(obj: Image | Paragraph): Record<string, any> {
416
+ if (obj instanceof Image) {
417
+ const size = obj.width !== undefined && obj.height !== undefined
418
+ ? {width: obj.width, height: obj.height}
419
+ : null;
420
+
421
+ const dataB64 = obj.data ? btoa(String.fromCharCode(...obj.data)) : null;
422
+
423
+ return {
424
+ type: "IMAGE",
425
+ position: obj.position ? positionToDict(obj.position) : null,
426
+ format: obj.format || null,
427
+ size,
428
+ data: dataB64
429
+ };
430
+ } else if (obj instanceof Paragraph) {
431
+ const lines: any[] = [];
432
+ if (obj.textLines) {
433
+ for (const line of obj.textLines) {
434
+ const textElement = {
435
+ text: line,
436
+ font: obj.font ? {name: obj.font.name, size: obj.font.size} : null,
437
+ color: obj.color ? {r: obj.color.r, g: obj.color.g, b: obj.color.b} : null,
438
+ position: obj.position ? positionToDict(obj.position) : null
439
+ };
440
+
441
+ const textLine: any = {
442
+ textElements: [textElement]
443
+ };
444
+
445
+ if (obj.color) {
446
+ textLine.color = {r: obj.color.r, g: obj.color.g, b: obj.color.b};
447
+ }
448
+ if (obj.position) {
449
+ textLine.position = positionToDict(obj.position);
450
+ }
451
+ lines.push(textLine);
452
+ }
453
+ }
454
+
455
+ const lineSpacings = obj.lineSpacing !== undefined ? [obj.lineSpacing] : null;
456
+
457
+ return {
458
+ type: "PARAGRAPH",
459
+ position: obj.position ? positionToDict(obj.position) : null,
460
+ lines,
461
+ lineSpacings,
462
+ font: obj.font ? {name: obj.font.name, size: obj.font.size} : null
463
+ };
464
+ } else {
465
+ throw new Error(`Unsupported object type: ${typeof obj}`);
466
+ }
407
467
  }
408
- }
409
468
  }
410
469
 
411
470
  /**
412
471
  * Request object for modify operations.
413
472
  */
414
473
  export class ModifyRequest {
415
- constructor(
416
- public objectRef: ObjectRef,
417
- public newObject: Image | Paragraph
418
- ) {}
419
-
420
- toDict(): Record<string, any> {
421
- return {
422
- ref: {
423
- internalId: this.objectRef.internalId,
424
- position: positionToDict(this.objectRef.position),
425
- type: this.objectRef.type
426
- },
427
- newObject: new AddRequest(this.newObject).toDict().object
428
- };
429
- }
474
+ constructor(
475
+ public objectRef: ObjectRef,
476
+ public newObject: Image | Paragraph
477
+ ) {
478
+ }
479
+
480
+ toDict(): Record<string, any> {
481
+ return {
482
+ ref: {
483
+ internalId: this.objectRef.internalId,
484
+ position: positionToDict(this.objectRef.position),
485
+ type: this.objectRef.type
486
+ },
487
+ newObject: new AddRequest(this.newObject).toDict().object
488
+ };
489
+ }
430
490
  }
431
491
 
432
492
  /**
433
493
  * Request object for text modification operations.
434
494
  */
435
495
  export class ModifyTextRequest {
436
- constructor(
437
- public objectRef: ObjectRef,
438
- public newText: string
439
- ) {}
440
-
441
- toDict(): Record<string, any> {
442
- return {
443
- ref: {
444
- internalId: this.objectRef.internalId,
445
- position: positionToDict(this.objectRef.position),
446
- type: this.objectRef.type
447
- },
448
- newTextLine: this.newText
449
- };
450
- }
496
+ constructor(
497
+ public objectRef: ObjectRef,
498
+ public newText: string
499
+ ) {
500
+ }
501
+
502
+ toDict(): Record<string, any> {
503
+ return {
504
+ ref: {
505
+ internalId: this.objectRef.internalId,
506
+ position: positionToDict(this.objectRef.position),
507
+ type: this.objectRef.type
508
+ },
509
+ newTextLine: this.newText
510
+ };
511
+ }
512
+ }
513
+
514
+ export class ChangeFormFieldRequest {
515
+ constructor(
516
+ public formFieldRef: FormFieldRef,
517
+ public newValue: string
518
+ ) {
519
+ }
520
+
521
+ toDict(): Record<string, any> {
522
+ return {
523
+ ref: {
524
+ internalId: this.formFieldRef.internalId,
525
+ position: positionToDict(this.formFieldRef.position),
526
+ type: this.formFieldRef.type
527
+ },
528
+ value: this.newValue
529
+ };
530
+ }
451
531
  }
452
532
 
453
533
  // Helper function to convert Position to dictionary for JSON serialization
454
534
  function positionToDict(position: Position): Record<string, any> {
455
- const result: Record<string, any> = {
456
- pageIndex: position.pageIndex,
457
- textStartsWith: position.textStartsWith
458
- };
459
-
460
- if (position.shape) {
461
- result.shape = position.shape;
462
- }
463
- if (position.mode) {
464
- result.mode = position.mode;
465
- }
466
- if (position.boundingRect) {
467
- result.boundingRect = {
468
- x: position.boundingRect.x,
469
- y: position.boundingRect.y,
470
- width: position.boundingRect.width,
471
- height: position.boundingRect.height
535
+ const result: Record<string, any> = {
536
+ pageIndex: position.pageIndex,
537
+ textStartsWith: position.textStartsWith,
538
+ name: position.name
472
539
  };
473
- }
474
540
 
475
- return result;
476
- }
541
+ if (position.shape) {
542
+ result.shape = position.shape;
543
+ }
544
+ if (position.mode) {
545
+ result.mode = position.mode;
546
+ }
547
+ if (position.boundingRect) {
548
+ result.boundingRect = {
549
+ x: position.boundingRect.x,
550
+ y: position.boundingRect.y,
551
+ width: position.boundingRect.width,
552
+ height: position.boundingRect.height
553
+ };
554
+ }
555
+
556
+ return result;
557
+ }