pols-pdf 1.0.0
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 +216 -0
- package/dist/index.d.ts +287 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +811 -0
- package/eslint.config.mjs +19 -0
- package/package.json +30 -0
package/README.md
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# Pols-Pdf
|
|
2
|
+
|
|
3
|
+
Clase en TypeScript/JavaScript que encapsula [`pdfkit`](https://pdfkit.org/) para agregar
|
|
4
|
+
primitivas de maquetado que `pdfkit` no ofrece de forma nativa: rectángulos con bordes y esquinas
|
|
5
|
+
redondeadas independientes por lado, tablas con paginación automática, celdas con texto
|
|
6
|
+
carácter-por-carácter (wrap, alineación, espaciado, fuentes mixtas) e imágenes con ajuste
|
|
7
|
+
`proportional`/`cover`/`stretch`.
|
|
8
|
+
|
|
9
|
+
## Instalación
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install pols-pdf
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Inicio rápido
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import fs from 'fs'
|
|
21
|
+
import { PPdf } from 'pols-pdf'
|
|
22
|
+
|
|
23
|
+
const pdf = new PPdf({ title: 'Reporte' })
|
|
24
|
+
|
|
25
|
+
pdf.cell({ text: 'Hola mundo', height: 20 })
|
|
26
|
+
|
|
27
|
+
pdf.build().pipe(fs.createWriteStream('output.pdf'))
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
`build()` cierra el documento y devuelve el `PDFDocument` de `pdfkit` (que ya es un
|
|
31
|
+
`stream.Readable`), listo para ser canalizado (`pipe`) a un archivo, a la respuesta HTTP, etc.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Constructor
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
new PPdf(params?: {
|
|
39
|
+
title?: string
|
|
40
|
+
page?: Partial<PPage>
|
|
41
|
+
template?: () => void
|
|
42
|
+
addFirstPage?: boolean
|
|
43
|
+
})
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
- `title`: título del documento (metadato PDF). También accesible/editable luego vía `pdf.title`.
|
|
47
|
+
- `page`: configuración de página por defecto (`size`, `layout`, `margins`), ver [`PPage`](#ppage).
|
|
48
|
+
- `template`: función que se ejecuta automáticamente cada vez que se agrega una página
|
|
49
|
+
(`addPage`), útil para dibujar encabezados/pies de página repetidos.
|
|
50
|
+
- `addFirstPage`: si es `false`, no agrega la primera página automáticamente (por defecto `true`).
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## El cursor
|
|
55
|
+
|
|
56
|
+
`PPdf` mantiene internamente un cursor `{ left, top }` que la mayoría de los métodos de dibujo
|
|
57
|
+
leen como posición por defecto y actualizan después de dibujar. Se puede leer y mover manualmente:
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
pdf.getCursorLeftPosition()
|
|
61
|
+
pdf.getCursorTopPosition()
|
|
62
|
+
pdf.getBottomSpaceQuantity() // espacio restante hasta el borde inferior de la página
|
|
63
|
+
pdf.getPageWidth()
|
|
64
|
+
|
|
65
|
+
pdf.setCursorLeftPosition('left') // vuelve al margen izquierdo
|
|
66
|
+
pdf.setCursorLeftPosition(50)
|
|
67
|
+
pdf.moveCursorLeft(20)
|
|
68
|
+
|
|
69
|
+
pdf.setCursorTopPosition('top') // vuelve al margen superior
|
|
70
|
+
pdf.setCursorTopPosition(100)
|
|
71
|
+
pdf.moveCursorTop(20) // si autoJump (por defecto true) y se pasa del margen inferior, agrega una página nueva
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Páginas
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
pdf.addPage({ size: 'LETTER', layout: 'landscape', margins: 30 })
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
`margins` (como todos los parámetros de tipo `*BoundParams` en esta librería) acepta un único
|
|
83
|
+
número para los cuatro lados, o un objeto parcial `{ top?, right?, bottom?, left? }`.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Rectángulos
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
pdf.rectangle({
|
|
91
|
+
left: 20,
|
|
92
|
+
top: 20,
|
|
93
|
+
width: 200,
|
|
94
|
+
height: 80,
|
|
95
|
+
fillColor: '#eeeeee',
|
|
96
|
+
border: true, // o { left, right, top, bottom } individuales
|
|
97
|
+
radius: 8, // o { leftTop, rightTop, rightBottom, leftBottom }
|
|
98
|
+
stroke: { width: 1, color: '#333333' }
|
|
99
|
+
})
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
`rectangleTo(params)` dibuja un rectángulo desde la posición actual del cursor hasta el punto
|
|
103
|
+
`{ left, top }` indicado (ancho/alto se calculan como la diferencia con el cursor).
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Celdas de texto (`cell`)
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
pdf.cell({
|
|
111
|
+
text: 'Texto de la celda',
|
|
112
|
+
width: 200,
|
|
113
|
+
height: 40, // o autojump: true si no se conoce el alto de antemano
|
|
114
|
+
padding: 6,
|
|
115
|
+
hAlign: 'center',
|
|
116
|
+
vAlign: 'center',
|
|
117
|
+
font: { size: 12, bold: true, color: '#111111' },
|
|
118
|
+
border: true,
|
|
119
|
+
fillColor: '#f5f5f5'
|
|
120
|
+
})
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
- `text` acepta `string`, `number`, `null`/`undefined`, un objeto `{ chars, font? }`, o un arreglo
|
|
124
|
+
de estos últimos para mezclar fuentes/estilos dentro de una misma celda.
|
|
125
|
+
- Una celda necesita **o bien** `height` (alto fijo) **o bien** `autojump: true` (el alto se
|
|
126
|
+
calcula según el contenido y, si no entra en la página actual, el texto restante continúa
|
|
127
|
+
automáticamente en una página nueva).
|
|
128
|
+
- Si el contenido no entra en la página, `cell()` agrega una página nueva y continúa dibujando el
|
|
129
|
+
resto automáticamente.
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## Filas y tablas (`row` / `table`)
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
pdf.table({
|
|
137
|
+
width: 'full', // 'full' | 'auto' | número
|
|
138
|
+
border: true,
|
|
139
|
+
padding: 4,
|
|
140
|
+
rows: [
|
|
141
|
+
{
|
|
142
|
+
fillColor: '#dddddd',
|
|
143
|
+
cells: [
|
|
144
|
+
{ text: 'Nombre', weight: 2 },
|
|
145
|
+
{ text: 'Edad', weight: 1 },
|
|
146
|
+
]
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
cells: [
|
|
150
|
+
{ text: 'Ana', weight: 2 },
|
|
151
|
+
{ text: '30', weight: 1 },
|
|
152
|
+
]
|
|
153
|
+
}
|
|
154
|
+
]
|
|
155
|
+
})
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
- Cada celda de una fila define su ancho con `width` (número fijo) **o** `weight` (proporción del
|
|
159
|
+
ancho disponible restante), nunca ambos.
|
|
160
|
+
- `table()` va maquetando fila por fila; en cuanto una fila no entra en la página actual, dibuja
|
|
161
|
+
el buffer acumulado, agrega una página nueva y continúa con el resto — una tabla puede así
|
|
162
|
+
abarcar varias páginas sin que el llamador tenga que ocuparse de la paginación.
|
|
163
|
+
- `row()` expone el mismo mecanismo para dibujar una única fila suelta (fuera de una tabla).
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## Imágenes
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
pdf.image({ filePath: 'logo.png', left: 20, top: 20, width: 120 })
|
|
171
|
+
|
|
172
|
+
pdf.image({
|
|
173
|
+
filePath: 'foto.jpg',
|
|
174
|
+
left: 20,
|
|
175
|
+
top: 20,
|
|
176
|
+
width: 200,
|
|
177
|
+
height: 120,
|
|
178
|
+
fill: 'cover', // 'stretch' | 'proportional' | 'cover'
|
|
179
|
+
hAlign: 'center',
|
|
180
|
+
vAlign: 'center'
|
|
181
|
+
})
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Fuentes
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
pdf.setFont({ name: 'Helvetica', bold: true, size: 14, color: '#000000' })
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Cambia la fuente activa del documento; los métodos de texto (`cell`, `row`, `table`) también
|
|
193
|
+
aceptan `font` por llamada (y por fragmento de texto individual dentro de `text`), sin necesidad
|
|
194
|
+
de llamar a `setFont` explícitamente.
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## Tipos con forma abreviada (`*Params`)
|
|
199
|
+
|
|
200
|
+
Los parámetros de borde, radio y márgenes/padding aceptan una forma abreviada además del objeto
|
|
201
|
+
completo:
|
|
202
|
+
|
|
203
|
+
| Tipo | Forma corta | Forma completa |
|
|
204
|
+
|---|---|---|
|
|
205
|
+
| `PBoundParams` (`padding`, `margins`) | `number` (aplica a los 4 lados) | `{ top?, right?, bottom?, left? }` |
|
|
206
|
+
| `PRadiusParams` (`radius`) | `number` | `{ leftTop?, rightTop?, rightBottom?, leftBottom? }` |
|
|
207
|
+
| `PBorderParams` (`border`) | `boolean` | `{ leftTop?, top?, rightTop?, right?, rightBottom?, bottom?, leftBottom?, left? }` |
|
|
208
|
+
| `PBorderColorParams` (`stroke.color`) | `string` (color aplicado a los 4/8 lados) | `{ top?, rightTop?, right?, rightBottom?, bottom?, leftBottom?, left?, leftTop? }` |
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## Convención de nombres
|
|
213
|
+
|
|
214
|
+
Todas las clases y tipos exportados llevan el prefijo `P` (`PPdf`, `PCell`, `PRowParams`, etc.),
|
|
215
|
+
siguiendo la convención usada en los paquetes hermanos de este ecosistema: `pols-date` (`PDate`)
|
|
216
|
+
y `pols-utils` (`PRecord`, `PUtilsNumber`).
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
export type PBoundParams = number | {
|
|
2
|
+
top?: number;
|
|
3
|
+
bottom?: number;
|
|
4
|
+
left?: number;
|
|
5
|
+
right?: number;
|
|
6
|
+
};
|
|
7
|
+
export type PBound = {
|
|
8
|
+
top: number;
|
|
9
|
+
bottom: number;
|
|
10
|
+
left: number;
|
|
11
|
+
right: number;
|
|
12
|
+
};
|
|
13
|
+
export type PRadiusParams = number | {
|
|
14
|
+
leftTop?: number;
|
|
15
|
+
rightTop?: number;
|
|
16
|
+
rightBottom?: number;
|
|
17
|
+
leftBottom?: number;
|
|
18
|
+
};
|
|
19
|
+
export type PRadius = {
|
|
20
|
+
leftTop: number;
|
|
21
|
+
rightTop: number;
|
|
22
|
+
rightBottom: number;
|
|
23
|
+
leftBottom: number;
|
|
24
|
+
};
|
|
25
|
+
export type PBorderParams = boolean | {
|
|
26
|
+
leftTop?: boolean;
|
|
27
|
+
top?: boolean;
|
|
28
|
+
rightTop?: boolean;
|
|
29
|
+
right?: boolean;
|
|
30
|
+
rightBottom?: boolean;
|
|
31
|
+
bottom?: boolean;
|
|
32
|
+
leftBottom?: boolean;
|
|
33
|
+
left?: boolean;
|
|
34
|
+
};
|
|
35
|
+
export type PBorder = {
|
|
36
|
+
leftTop: boolean;
|
|
37
|
+
top: boolean;
|
|
38
|
+
rightTop: boolean;
|
|
39
|
+
right: boolean;
|
|
40
|
+
rightBottom: boolean;
|
|
41
|
+
bottom: boolean;
|
|
42
|
+
leftBottom: boolean;
|
|
43
|
+
left: boolean;
|
|
44
|
+
};
|
|
45
|
+
export type PBorderColorParams = string | {
|
|
46
|
+
top?: string;
|
|
47
|
+
rightTop?: string;
|
|
48
|
+
right?: string;
|
|
49
|
+
rightBottom?: string;
|
|
50
|
+
bottom?: string;
|
|
51
|
+
leftBottom?: string;
|
|
52
|
+
left?: string;
|
|
53
|
+
leftTop?: string;
|
|
54
|
+
};
|
|
55
|
+
export type PBorderColor = {
|
|
56
|
+
top: string;
|
|
57
|
+
rightTop: string;
|
|
58
|
+
right: string;
|
|
59
|
+
rightBottom: string;
|
|
60
|
+
bottom: string;
|
|
61
|
+
leftBottom: string;
|
|
62
|
+
left: string;
|
|
63
|
+
leftTop: string;
|
|
64
|
+
};
|
|
65
|
+
export type PPage = {
|
|
66
|
+
size: 'A4' | 'LETTER';
|
|
67
|
+
layout: 'portrait' | 'landscape';
|
|
68
|
+
margins: PBoundParams;
|
|
69
|
+
};
|
|
70
|
+
export type PFont = {
|
|
71
|
+
name: string;
|
|
72
|
+
bold: boolean;
|
|
73
|
+
oblique: boolean;
|
|
74
|
+
size: number;
|
|
75
|
+
color: string;
|
|
76
|
+
};
|
|
77
|
+
export type PImage = {
|
|
78
|
+
filePath: string | Buffer;
|
|
79
|
+
left?: number;
|
|
80
|
+
top?: number;
|
|
81
|
+
} & ({
|
|
82
|
+
width?: number;
|
|
83
|
+
} | {
|
|
84
|
+
height?: number;
|
|
85
|
+
} | {
|
|
86
|
+
width?: number;
|
|
87
|
+
height?: number;
|
|
88
|
+
fill?: 'stretch';
|
|
89
|
+
} | {
|
|
90
|
+
width?: number;
|
|
91
|
+
height?: number;
|
|
92
|
+
fill?: 'proportional' | 'cover';
|
|
93
|
+
hAlign?: 'left' | 'center' | 'right';
|
|
94
|
+
vAlign?: 'top' | 'center' | 'bottom';
|
|
95
|
+
});
|
|
96
|
+
export type PRectangle = {
|
|
97
|
+
left: number;
|
|
98
|
+
top: number;
|
|
99
|
+
width: number;
|
|
100
|
+
height: number;
|
|
101
|
+
stroke?: {
|
|
102
|
+
width?: number;
|
|
103
|
+
color?: PBorderColorParams;
|
|
104
|
+
};
|
|
105
|
+
fillColor?: string;
|
|
106
|
+
border?: boolean | {
|
|
107
|
+
left?: boolean;
|
|
108
|
+
right?: boolean;
|
|
109
|
+
top?: boolean;
|
|
110
|
+
bottom?: boolean;
|
|
111
|
+
};
|
|
112
|
+
radius?: PRadiusParams;
|
|
113
|
+
};
|
|
114
|
+
export type PTextParams = {
|
|
115
|
+
chars: string;
|
|
116
|
+
font?: Partial<PFont>;
|
|
117
|
+
};
|
|
118
|
+
type PLetter = {
|
|
119
|
+
char: string;
|
|
120
|
+
left: number;
|
|
121
|
+
top: number;
|
|
122
|
+
width: number;
|
|
123
|
+
height: number;
|
|
124
|
+
font: PFont;
|
|
125
|
+
};
|
|
126
|
+
export type PCell = {
|
|
127
|
+
letters: PLetter[];
|
|
128
|
+
left: number;
|
|
129
|
+
top: number;
|
|
130
|
+
height: number;
|
|
131
|
+
width: number;
|
|
132
|
+
padding: PBound;
|
|
133
|
+
border: PBorder;
|
|
134
|
+
radius: PRadius;
|
|
135
|
+
stroke?: {
|
|
136
|
+
width?: number;
|
|
137
|
+
color?: PBorderColorParams;
|
|
138
|
+
};
|
|
139
|
+
fillColor?: string;
|
|
140
|
+
hAlign?: 'left' | 'center' | 'right';
|
|
141
|
+
vAlign?: 'top' | 'center' | 'bottom';
|
|
142
|
+
};
|
|
143
|
+
export type PCellParams = {
|
|
144
|
+
text: null | undefined | number | string | PTextParams | PTextParams[];
|
|
145
|
+
left?: number;
|
|
146
|
+
top?: number;
|
|
147
|
+
width?: 'auto' | number;
|
|
148
|
+
font?: Partial<PFont>;
|
|
149
|
+
fillColor?: string;
|
|
150
|
+
padding?: PBoundParams;
|
|
151
|
+
border?: PBorderParams;
|
|
152
|
+
radius?: PRadiusParams;
|
|
153
|
+
stroke?: {
|
|
154
|
+
width?: number;
|
|
155
|
+
color?: PBorderColorParams;
|
|
156
|
+
};
|
|
157
|
+
hAlign?: 'left' | 'center' | 'right';
|
|
158
|
+
vAlign?: 'top' | 'center' | 'bottom';
|
|
159
|
+
spacing?: number;
|
|
160
|
+
complete?: boolean;
|
|
161
|
+
} & ({
|
|
162
|
+
height: number;
|
|
163
|
+
} | {
|
|
164
|
+
autojump: true | undefined;
|
|
165
|
+
});
|
|
166
|
+
export type PRow = {
|
|
167
|
+
cells: Omit<PCell, 'autojump'>[];
|
|
168
|
+
gap?: number;
|
|
169
|
+
left: number;
|
|
170
|
+
top: number;
|
|
171
|
+
width: number;
|
|
172
|
+
height: number;
|
|
173
|
+
padding: PBound;
|
|
174
|
+
border: PBorder;
|
|
175
|
+
radius: PRadius;
|
|
176
|
+
stroke?: {
|
|
177
|
+
width?: number;
|
|
178
|
+
color?: PBorderColorParams;
|
|
179
|
+
};
|
|
180
|
+
fillColor?: string;
|
|
181
|
+
};
|
|
182
|
+
export type PRowParams = {
|
|
183
|
+
cells: (Omit<PCellParams, 'width' | 'left' | 'top' | 'height' | 'autojump'> & ({
|
|
184
|
+
width: number;
|
|
185
|
+
} | {
|
|
186
|
+
weight: number;
|
|
187
|
+
}))[];
|
|
188
|
+
gap?: number;
|
|
189
|
+
left?: number;
|
|
190
|
+
top?: number;
|
|
191
|
+
padding?: PBoundParams;
|
|
192
|
+
border?: PBorderParams;
|
|
193
|
+
radius?: PRadiusParams;
|
|
194
|
+
font?: Partial<PFont>;
|
|
195
|
+
stroke?: {
|
|
196
|
+
width?: number;
|
|
197
|
+
color?: PBorderColorParams;
|
|
198
|
+
};
|
|
199
|
+
fillColor?: string;
|
|
200
|
+
width?: 'full' | 'auto' | number;
|
|
201
|
+
autojump?: boolean;
|
|
202
|
+
complete?: boolean;
|
|
203
|
+
};
|
|
204
|
+
export type PTableParams = {
|
|
205
|
+
rows: Omit<PRowParams, 'left' | 'top' | 'width' | 'autojump'>[];
|
|
206
|
+
gap?: number;
|
|
207
|
+
left?: number;
|
|
208
|
+
top?: number;
|
|
209
|
+
padding?: PBoundParams;
|
|
210
|
+
border?: PBorderParams;
|
|
211
|
+
radius?: PRadiusParams;
|
|
212
|
+
font?: Partial<PFont>;
|
|
213
|
+
stroke?: {
|
|
214
|
+
width?: number;
|
|
215
|
+
color?: PBorderColorParams;
|
|
216
|
+
};
|
|
217
|
+
fillColor?: string;
|
|
218
|
+
width?: 'full' | 'auto' | number;
|
|
219
|
+
autojump?: boolean;
|
|
220
|
+
};
|
|
221
|
+
export type PTable = {
|
|
222
|
+
rows: PRow[];
|
|
223
|
+
gap?: number;
|
|
224
|
+
left: number;
|
|
225
|
+
top: number;
|
|
226
|
+
width: number;
|
|
227
|
+
height: number;
|
|
228
|
+
padding: PBound;
|
|
229
|
+
border: PBorder;
|
|
230
|
+
radius: PRadius;
|
|
231
|
+
stroke?: {
|
|
232
|
+
width?: number;
|
|
233
|
+
color?: PBorderColorParams;
|
|
234
|
+
};
|
|
235
|
+
fillColor?: string;
|
|
236
|
+
};
|
|
237
|
+
export declare class PPdf {
|
|
238
|
+
private cursor;
|
|
239
|
+
private configPage;
|
|
240
|
+
private engine;
|
|
241
|
+
template?: () => void;
|
|
242
|
+
private currentFont;
|
|
243
|
+
get title(): string;
|
|
244
|
+
set title(value: string);
|
|
245
|
+
get page(): {
|
|
246
|
+
readonly height: number;
|
|
247
|
+
readonly width: number;
|
|
248
|
+
};
|
|
249
|
+
private capturedFont?;
|
|
250
|
+
private captureFont;
|
|
251
|
+
private restoreFont;
|
|
252
|
+
setFont(font: Partial<PFont>): void;
|
|
253
|
+
constructor(params?: {
|
|
254
|
+
title?: string;
|
|
255
|
+
page?: Partial<PPage>;
|
|
256
|
+
template?: () => void;
|
|
257
|
+
addFirstPage?: boolean;
|
|
258
|
+
});
|
|
259
|
+
addPage(config?: Partial<PPage>): void;
|
|
260
|
+
rectangleTo(params: Omit<PRectangle, 'width' | 'height'>): void;
|
|
261
|
+
rectangle(params: PRectangle): void;
|
|
262
|
+
build(): PDFKit.PDFDocument;
|
|
263
|
+
table(params: PTableParams): void;
|
|
264
|
+
private drawTable;
|
|
265
|
+
private prepareRow;
|
|
266
|
+
private drawRow;
|
|
267
|
+
row(params: PRowParams): void;
|
|
268
|
+
setCursorLeftPosition(value: number | 'left'): this;
|
|
269
|
+
moveCursorLeft(value: number): this;
|
|
270
|
+
setCursorTopPosition(value: number | 'top'): this;
|
|
271
|
+
moveCursorTop(value: number, autoJump?: boolean): this;
|
|
272
|
+
getCursorLeftPosition(): number;
|
|
273
|
+
getCursorTopPosition(): number;
|
|
274
|
+
getBottomSpaceQuantity(): number;
|
|
275
|
+
getPageWidth(): number;
|
|
276
|
+
private verticalAlign;
|
|
277
|
+
private prepareCell;
|
|
278
|
+
private drawCell;
|
|
279
|
+
cell(params: PCellParams): void;
|
|
280
|
+
image(params: PImage): void;
|
|
281
|
+
private prepareBoundValues;
|
|
282
|
+
private prepareRadiusValues;
|
|
283
|
+
private prepareBorderValues;
|
|
284
|
+
private prepareBorderColorValues;
|
|
285
|
+
}
|
|
286
|
+
export {};
|
|
287
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,811 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.PPdf = void 0;
|
|
7
|
+
const pdfkit_1 = __importDefault(require("pdfkit"));
|
|
8
|
+
const pols_utils_1 = require("pols-utils");
|
|
9
|
+
class PPdf {
|
|
10
|
+
cursor = {
|
|
11
|
+
left: 0,
|
|
12
|
+
top: 0
|
|
13
|
+
};
|
|
14
|
+
configPage;
|
|
15
|
+
engine;
|
|
16
|
+
template;
|
|
17
|
+
currentFont = {
|
|
18
|
+
name: 'Helvetica',
|
|
19
|
+
bold: false,
|
|
20
|
+
oblique: false,
|
|
21
|
+
size: 10,
|
|
22
|
+
color: '#000000'
|
|
23
|
+
};
|
|
24
|
+
get title() {
|
|
25
|
+
return this.engine.info.Title ?? '';
|
|
26
|
+
}
|
|
27
|
+
set title(value) {
|
|
28
|
+
this.engine.info.Title = value;
|
|
29
|
+
}
|
|
30
|
+
get page() {
|
|
31
|
+
return {
|
|
32
|
+
height: this.engine.page.height,
|
|
33
|
+
width: this.engine.page.width
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
capturedFont;
|
|
37
|
+
captureFont() {
|
|
38
|
+
this.capturedFont = this.currentFont;
|
|
39
|
+
}
|
|
40
|
+
restoreFont() {
|
|
41
|
+
if (this.capturedFont)
|
|
42
|
+
this.currentFont = this.capturedFont;
|
|
43
|
+
}
|
|
44
|
+
/* Establece en el engine la fuente especificada en currentFont */
|
|
45
|
+
setFont(font) {
|
|
46
|
+
const finalFont = {
|
|
47
|
+
name: font.name ?? this.currentFont.name,
|
|
48
|
+
bold: font.bold ?? this.currentFont.bold,
|
|
49
|
+
oblique: font.oblique ?? this.currentFont.oblique,
|
|
50
|
+
size: font.size ?? this.currentFont.size,
|
|
51
|
+
color: font.color ?? this.currentFont.color,
|
|
52
|
+
};
|
|
53
|
+
let fontName = this.currentFont.name;
|
|
54
|
+
if (finalFont.bold || finalFont.oblique) {
|
|
55
|
+
fontName += `-${finalFont.bold ? 'Bold' : ''}${finalFont.oblique ? 'Oblique' : ''}`;
|
|
56
|
+
}
|
|
57
|
+
this.engine.font(fontName, finalFont.size);
|
|
58
|
+
this.currentFont = finalFont;
|
|
59
|
+
}
|
|
60
|
+
constructor(params) {
|
|
61
|
+
this.engine = new pdfkit_1.default({ autoFirstPage: false });
|
|
62
|
+
this.engine.info.Title = params?.title ?? 'pdf';
|
|
63
|
+
this.setFont(this.currentFont);
|
|
64
|
+
this.template = params?.template?.bind(this);
|
|
65
|
+
this.configPage = {
|
|
66
|
+
size: 'A4',
|
|
67
|
+
layout: 'portrait',
|
|
68
|
+
...(params?.page ?? {}),
|
|
69
|
+
margins: this.prepareBoundValues(params?.page?.margins, {
|
|
70
|
+
left: 20,
|
|
71
|
+
top: 20,
|
|
72
|
+
right: 20,
|
|
73
|
+
bottom: 20
|
|
74
|
+
})
|
|
75
|
+
};
|
|
76
|
+
if (params?.addFirstPage == null || params.addFirstPage)
|
|
77
|
+
this.addPage();
|
|
78
|
+
}
|
|
79
|
+
addPage(config) {
|
|
80
|
+
const finalConfig = {
|
|
81
|
+
...this.configPage,
|
|
82
|
+
...(config ?? {}),
|
|
83
|
+
margins: this.prepareBoundValues(config?.margins ?? this.configPage.margins, {
|
|
84
|
+
left: 20,
|
|
85
|
+
top: 20,
|
|
86
|
+
right: 20,
|
|
87
|
+
bottom: 20
|
|
88
|
+
})
|
|
89
|
+
};
|
|
90
|
+
this.engine.addPage(finalConfig);
|
|
91
|
+
this.configPage = finalConfig;
|
|
92
|
+
this.cursor.top = finalConfig.margins.top;
|
|
93
|
+
this.template?.();
|
|
94
|
+
}
|
|
95
|
+
rectangleTo(params) {
|
|
96
|
+
this.rectangle({
|
|
97
|
+
...params,
|
|
98
|
+
left: this.cursor.left,
|
|
99
|
+
top: this.cursor.top,
|
|
100
|
+
width: params.left - this.cursor.left,
|
|
101
|
+
height: params.top - this.cursor.top,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
rectangle(params) {
|
|
105
|
+
this.engine.lineWidth(params.stroke?.width ?? 0);
|
|
106
|
+
const border = this.prepareBorderValues(params.border);
|
|
107
|
+
const radius = this.prepareRadiusValues(params.radius);
|
|
108
|
+
radius.leftBottom = Math.min(radius.leftBottom, params.height / 2, params.width / 2);
|
|
109
|
+
radius.leftTop = Math.min(radius.leftTop, params.height / 2, params.width / 2);
|
|
110
|
+
radius.rightBottom = Math.min(radius.rightBottom, params.height / 2, params.width / 2);
|
|
111
|
+
radius.rightTop = Math.min(radius.rightTop, params.height / 2, params.width / 2);
|
|
112
|
+
if (params.fillColor) {
|
|
113
|
+
this.engine.path('M' + `${params.left + radius.leftTop},${params.top} `
|
|
114
|
+
+ `L${params.left + params.width - radius.rightTop},${params.top} `
|
|
115
|
+
+ (radius.rightTop ? `A${radius.rightTop},${radius.rightTop} 0 0 1 ${params.left + params.width},${params.top + radius.rightTop} ` : ' ')
|
|
116
|
+
+ `L${params.left + params.width},${params.top + params.height - radius.rightBottom} `
|
|
117
|
+
+ (radius.rightBottom ? `A${radius.rightBottom},${radius.rightBottom} 0 0 1 ${params.left + params.width - radius.rightBottom},${params.top + params.height} ` : ' ')
|
|
118
|
+
+ `L${params.left + radius.leftBottom},${params.top + params.height} `
|
|
119
|
+
+ (radius.leftBottom ? `A${radius.leftBottom},${radius.leftBottom} 0 0 1 ${params.left},${params.top + params.height - radius.leftBottom} ` : ' ')
|
|
120
|
+
+ `L${params.left},${params.top + radius.leftTop} `
|
|
121
|
+
+ (radius.leftTop ? `A${radius.leftTop},${radius.leftTop} 0 0 1 ${params.left + radius.leftTop},${params.top} ` : ' ')
|
|
122
|
+
+ '').fill(params.fillColor);
|
|
123
|
+
}
|
|
124
|
+
const color = this.prepareBorderColorValues(params.stroke?.color);
|
|
125
|
+
if (border.top)
|
|
126
|
+
this.engine.path(`M${params.left + radius.leftTop},${params.top} L${params.left + params.width - radius.rightTop},${params.top}`).stroke(color.top);
|
|
127
|
+
if (border.rightTop && radius.rightTop)
|
|
128
|
+
this.engine.path(`M${params.left + params.width - radius.rightTop},${params.top} A${radius.rightTop},${radius.rightTop} 0 0 1 ${params.left + params.width},${params.top + radius.rightTop}`).stroke(color.rightTop);
|
|
129
|
+
if (border.right)
|
|
130
|
+
this.engine.path(`M${params.left + params.width},${params.top + radius.rightTop} L${params.left + params.width},${params.top + params.height - radius.rightBottom}`).stroke(color.right);
|
|
131
|
+
if (border.rightBottom && radius.rightBottom)
|
|
132
|
+
this.engine.path(`
|
|
133
|
+
M${params.left + params.width},${params.top + params.height - radius.rightBottom}
|
|
134
|
+
A${radius.rightBottom},${radius.rightBottom} 0 0 1 ${params.left + params.width - radius.rightBottom},${params.top + params.height}
|
|
135
|
+
`).stroke(color.rightBottom);
|
|
136
|
+
if (border.bottom)
|
|
137
|
+
this.engine.path(`M${params.left + params.width - radius.rightBottom},${params.top + params.height} L${params.left + radius.leftBottom},${params.top + params.height}`).stroke(color.bottom);
|
|
138
|
+
if (border.leftBottom && radius.leftBottom)
|
|
139
|
+
this.engine.path(`M${params.left + radius.leftBottom},${params.top + params.height} A${radius.leftBottom},${radius.leftBottom} 0 0 1 ${params.left},${params.top + params.height - radius.leftBottom}`).stroke(color.leftBottom);
|
|
140
|
+
if (border.left)
|
|
141
|
+
this.engine.path(`M${params.left},${params.top + params.height - radius.leftBottom} L${params.left},${params.top + radius.leftTop}`).stroke(color.left);
|
|
142
|
+
if (border.leftTop && radius.leftTop)
|
|
143
|
+
this.engine.path(`M${params.left},${params.top + radius.leftTop} A${radius.leftTop},${radius.leftTop} 0 0 1 ${params.left + radius.leftTop},${params.top}`).stroke(color.leftTop);
|
|
144
|
+
this.cursor.top = params.top + params.height;
|
|
145
|
+
this.cursor.left = params.left + params.width;
|
|
146
|
+
}
|
|
147
|
+
/* PDFDocument ya es un stream.Readable; "end" cierra la escritura y lo deja listo para ser consumido/canalizado por el llamador. */
|
|
148
|
+
build() {
|
|
149
|
+
this.engine.end();
|
|
150
|
+
return this.engine;
|
|
151
|
+
}
|
|
152
|
+
table(params) {
|
|
153
|
+
const width = (() => {
|
|
154
|
+
if (params.width == null || params.width == 'auto') {
|
|
155
|
+
return this.engine.page.width - this.engine.page.margins.right - (params.left ?? this.cursor.left);
|
|
156
|
+
}
|
|
157
|
+
else if (params.width == 'full') {
|
|
158
|
+
return this.engine.page.width - this.engine.page.margins.right - this.engine.page.margins.left;
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
return params.width;
|
|
162
|
+
}
|
|
163
|
+
})();
|
|
164
|
+
const left = params.left ?? this.cursor.left;
|
|
165
|
+
const top = params.top ?? this.cursor.top;
|
|
166
|
+
const padding = this.prepareBoundValues(params.padding);
|
|
167
|
+
const gap = params.gap ?? 0;
|
|
168
|
+
let cursorTop = top + padding.top;
|
|
169
|
+
const usefulWidth = width - padding.left - padding.right;
|
|
170
|
+
const buffer = {
|
|
171
|
+
...params,
|
|
172
|
+
rows: [],
|
|
173
|
+
left,
|
|
174
|
+
top,
|
|
175
|
+
padding,
|
|
176
|
+
border: this.prepareBorderValues(params.border),
|
|
177
|
+
radius: this.prepareRadiusValues(params.radius),
|
|
178
|
+
width,
|
|
179
|
+
height: 0 /* valor provisional */
|
|
180
|
+
};
|
|
181
|
+
let i = 0;
|
|
182
|
+
let rowToDraw = params.rows[i];
|
|
183
|
+
while (rowToDraw) {
|
|
184
|
+
const preparedRow = this.prepareRow({
|
|
185
|
+
...rowToDraw,
|
|
186
|
+
left: left + padding.left,
|
|
187
|
+
top: cursorTop,
|
|
188
|
+
width: usefulWidth,
|
|
189
|
+
font: params.font,
|
|
190
|
+
autojump: (params.autojump ?? true) ? true : undefined
|
|
191
|
+
});
|
|
192
|
+
if (preparedRow.currentPage.cells.some(cell => cell.letters?.length)) {
|
|
193
|
+
buffer.rows.push(preparedRow.currentPage);
|
|
194
|
+
}
|
|
195
|
+
/* Si la fila actual se rompe, dibuja el buffer de la tabla */
|
|
196
|
+
if (preparedRow.nextPage.cells.some(cell => cell.text)) {
|
|
197
|
+
const lastRow = buffer.rows[buffer.rows.length - 1];
|
|
198
|
+
buffer.height = lastRow ? ((lastRow?.top ?? 0) + (lastRow?.height ?? 0) - buffer.top + padding.bottom) : 0;
|
|
199
|
+
this.drawTable(buffer);
|
|
200
|
+
this.addPage();
|
|
201
|
+
rowToDraw = preparedRow.nextPage;
|
|
202
|
+
buffer.rows = [];
|
|
203
|
+
buffer.top = this.cursor.top;
|
|
204
|
+
cursorTop = this.cursor.top + padding.top;
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
i++;
|
|
208
|
+
rowToDraw = params.rows[i];
|
|
209
|
+
cursorTop += preparedRow.currentPage.height + gap;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
if (buffer.rows.length) {
|
|
213
|
+
const lastRow = buffer.rows[buffer.rows.length - 1];
|
|
214
|
+
buffer.height = lastRow.top + lastRow.height - buffer.top + padding.bottom;
|
|
215
|
+
this.drawTable(buffer);
|
|
216
|
+
}
|
|
217
|
+
this.cursor.left = left;
|
|
218
|
+
}
|
|
219
|
+
drawTable(params) {
|
|
220
|
+
/* Dibuja el borde. Este bloque podría ignorarse si al final no se escribirá ningún caracter debido al salto de página */
|
|
221
|
+
if (params.border || params.fillColor) {
|
|
222
|
+
this.rectangle({
|
|
223
|
+
left: params.left,
|
|
224
|
+
top: params.top,
|
|
225
|
+
width: params.width,
|
|
226
|
+
height: params.height,
|
|
227
|
+
border: params.border,
|
|
228
|
+
radius: params.radius,
|
|
229
|
+
fillColor: params.fillColor,
|
|
230
|
+
stroke: params.stroke
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
/* Dibujo de las celdas */
|
|
234
|
+
for (const row of params.rows) {
|
|
235
|
+
this.drawRow(row);
|
|
236
|
+
}
|
|
237
|
+
this.setCursorTopPosition(params.top + params.height);
|
|
238
|
+
}
|
|
239
|
+
prepareRow(params) {
|
|
240
|
+
const width = (() => {
|
|
241
|
+
if (params.width == null || params.width == 'auto') {
|
|
242
|
+
return this.engine.page.width - this.engine.page.margins.right - (params.left ?? this.cursor.left);
|
|
243
|
+
}
|
|
244
|
+
else if (params.width == 'full') {
|
|
245
|
+
return this.engine.page.width - this.engine.page.margins.right - this.engine.page.margins.left;
|
|
246
|
+
}
|
|
247
|
+
else {
|
|
248
|
+
return params.width;
|
|
249
|
+
}
|
|
250
|
+
})();
|
|
251
|
+
const left = params.left ?? this.cursor.left;
|
|
252
|
+
const top = params.top ?? this.cursor.top;
|
|
253
|
+
const padding = this.prepareBoundValues(params.padding);
|
|
254
|
+
const response = {
|
|
255
|
+
currentPage: {
|
|
256
|
+
...params,
|
|
257
|
+
cells: [],
|
|
258
|
+
left,
|
|
259
|
+
top,
|
|
260
|
+
padding,
|
|
261
|
+
border: this.prepareBorderValues(params.border),
|
|
262
|
+
radius: this.prepareRadiusValues(params.radius),
|
|
263
|
+
width,
|
|
264
|
+
height: 0 /* valor provisional */
|
|
265
|
+
},
|
|
266
|
+
nextPage: {
|
|
267
|
+
...params,
|
|
268
|
+
cells: []
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
const gap = params.gap ?? 0;
|
|
272
|
+
let cursorLeft = left + padding.left;
|
|
273
|
+
const usedWidth = params.cells.reduce((ac, cell) => ac + (('width' in cell && cell.width != null) ? cell.width : 0), 0);
|
|
274
|
+
const usefulWidth = width - padding.left - padding.right - gap * (params.cells.length - 1) - usedWidth;
|
|
275
|
+
const totalWeight = params.cells.reduce((ac, cell) => ac + (('weight' in cell && cell.weight != null) ? cell.weight : 0), 0);
|
|
276
|
+
for (const cell of params.cells) {
|
|
277
|
+
let cellWidth = 0;
|
|
278
|
+
if ('width' in cell && cell.width != null) {
|
|
279
|
+
cellWidth = cell.width;
|
|
280
|
+
}
|
|
281
|
+
else if ('weight' in cell && cell.weight != null) {
|
|
282
|
+
cellWidth = usefulWidth * cell.weight / totalWeight;
|
|
283
|
+
}
|
|
284
|
+
const preparedCell = this.prepareCell({
|
|
285
|
+
...cell,
|
|
286
|
+
left: cursorLeft,
|
|
287
|
+
top: top + padding.top,
|
|
288
|
+
width: cellWidth,
|
|
289
|
+
font: cell.font ?? params.font,
|
|
290
|
+
autojump: (params.autojump ?? true) ? true : undefined,
|
|
291
|
+
complete: params.complete
|
|
292
|
+
});
|
|
293
|
+
response.currentPage.cells.push(preparedCell.currentPage);
|
|
294
|
+
response.nextPage.cells.push({
|
|
295
|
+
...cell,
|
|
296
|
+
text: undefined,
|
|
297
|
+
...preparedCell.nextPage,
|
|
298
|
+
...('width' in cell ? { width: cell.width } : { weight: cell.weight })
|
|
299
|
+
});
|
|
300
|
+
cursorLeft += preparedCell.currentPage.width + gap;
|
|
301
|
+
}
|
|
302
|
+
/* Efectúa la alineación vertical en cada celda */
|
|
303
|
+
const height = Math.max(...response.currentPage.cells.map(cell => cell.height));
|
|
304
|
+
for (const [i, cell] of response.currentPage.cells.entries()) {
|
|
305
|
+
if (params.cells[i].vAlign != null)
|
|
306
|
+
this.verticalAlign(cell.letters, params.cells[i].vAlign, height, cell.padding);
|
|
307
|
+
cell.height = height;
|
|
308
|
+
}
|
|
309
|
+
response.currentPage.height = height + padding.top + padding.bottom;
|
|
310
|
+
return response;
|
|
311
|
+
}
|
|
312
|
+
drawRow(params) {
|
|
313
|
+
/* Dibuja el borde. Este bloque podría ignorarse si al final no se escribirá ningún caracter debido al salto de página */
|
|
314
|
+
if (params.border || params.fillColor) {
|
|
315
|
+
this.rectangle({
|
|
316
|
+
left: params.left,
|
|
317
|
+
top: params.top,
|
|
318
|
+
width: params.width,
|
|
319
|
+
height: params.height,
|
|
320
|
+
border: params.border,
|
|
321
|
+
radius: params.radius,
|
|
322
|
+
fillColor: params.fillColor,
|
|
323
|
+
stroke: params.stroke
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
/* Dibujo de las celdas */
|
|
327
|
+
for (const cell of params.cells) {
|
|
328
|
+
this.drawCell(cell);
|
|
329
|
+
}
|
|
330
|
+
this.setCursorTopPosition(params.top + params.height);
|
|
331
|
+
}
|
|
332
|
+
row(params) {
|
|
333
|
+
let paramsToDraw = params;
|
|
334
|
+
while (paramsToDraw) {
|
|
335
|
+
const prepared = this.prepareRow(paramsToDraw);
|
|
336
|
+
this.drawRow(prepared.currentPage);
|
|
337
|
+
if (prepared.nextPage.cells.some(cell => cell.text)) {
|
|
338
|
+
this.addPage();
|
|
339
|
+
paramsToDraw = {
|
|
340
|
+
...prepared.nextPage,
|
|
341
|
+
top: this.cursor.top
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
else {
|
|
345
|
+
paramsToDraw = null;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
setCursorLeftPosition(value) {
|
|
350
|
+
let n;
|
|
351
|
+
if (value == 'left') {
|
|
352
|
+
n = this.engine.page.margins.left;
|
|
353
|
+
}
|
|
354
|
+
else {
|
|
355
|
+
n = value;
|
|
356
|
+
}
|
|
357
|
+
this.cursor.left = n;
|
|
358
|
+
return this;
|
|
359
|
+
}
|
|
360
|
+
moveCursorLeft(value) {
|
|
361
|
+
this.cursor.left += value;
|
|
362
|
+
return this;
|
|
363
|
+
}
|
|
364
|
+
setCursorTopPosition(value) {
|
|
365
|
+
let n;
|
|
366
|
+
if (value == 'top') {
|
|
367
|
+
n = this.engine.page.margins.top;
|
|
368
|
+
}
|
|
369
|
+
else {
|
|
370
|
+
n = value;
|
|
371
|
+
}
|
|
372
|
+
this.cursor.top = n;
|
|
373
|
+
return this;
|
|
374
|
+
}
|
|
375
|
+
moveCursorTop(value, autoJump = true) {
|
|
376
|
+
this.cursor.top += value;
|
|
377
|
+
if (autoJump) {
|
|
378
|
+
if (this.cursor.top >= this.engine.page.height - this.configPage.margins.bottom)
|
|
379
|
+
this.addPage();
|
|
380
|
+
}
|
|
381
|
+
return this;
|
|
382
|
+
}
|
|
383
|
+
getCursorLeftPosition() {
|
|
384
|
+
return this.cursor.left;
|
|
385
|
+
}
|
|
386
|
+
getCursorTopPosition() {
|
|
387
|
+
return this.cursor.top;
|
|
388
|
+
}
|
|
389
|
+
getBottomSpaceQuantity() {
|
|
390
|
+
return this.page.height - this.cursor.top;
|
|
391
|
+
}
|
|
392
|
+
getPageWidth() {
|
|
393
|
+
return this.engine.page.width;
|
|
394
|
+
}
|
|
395
|
+
verticalAlign(letters, vAlign, height, padding) {
|
|
396
|
+
if (vAlign != 'top') {
|
|
397
|
+
const charTop = Math.min(...letters.map(letter => letter.top));
|
|
398
|
+
const textHeight = Math.max(...letters.map(letter => letter.top + letter.height)) - charTop;
|
|
399
|
+
const delta = height - padding.top - padding.bottom - textHeight;
|
|
400
|
+
/* Observa la distancia entre el último caracter y el ancho */
|
|
401
|
+
for (const letter of letters) {
|
|
402
|
+
letter.top += vAlign == 'bottom' ? delta : (delta / 2);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
prepareCell(params) {
|
|
407
|
+
const text = [];
|
|
408
|
+
if (typeof params.text == 'string') {
|
|
409
|
+
text.push({ chars: params.text });
|
|
410
|
+
}
|
|
411
|
+
else if (typeof params.text == 'number') {
|
|
412
|
+
text.push({ chars: params.text.toString() });
|
|
413
|
+
}
|
|
414
|
+
else if (params.text == null) {
|
|
415
|
+
text.push({ chars: '' });
|
|
416
|
+
}
|
|
417
|
+
else if (params.text instanceof Array) {
|
|
418
|
+
if (params.text.length) {
|
|
419
|
+
text.push(...params.text);
|
|
420
|
+
}
|
|
421
|
+
else {
|
|
422
|
+
text.push({ chars: '' });
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
const letters = [];
|
|
426
|
+
const spacesIndexes = [];
|
|
427
|
+
const width = params.width == 'auto' ? this.engine.page.width - this.engine.page.margins.right - (params.left ?? this.cursor.left) : params.width;
|
|
428
|
+
/* Captura las coordenadas de inicio de celda */
|
|
429
|
+
const left = params.left ?? this.cursor.left;
|
|
430
|
+
const top = params.top ?? this.cursor.top;
|
|
431
|
+
/* Calcula el padding */
|
|
432
|
+
const padding = this.prepareBoundValues(params.padding, {
|
|
433
|
+
left: 0,
|
|
434
|
+
top: 0,
|
|
435
|
+
right: 0,
|
|
436
|
+
bottom: 0
|
|
437
|
+
});
|
|
438
|
+
/* Separa cada caracter por un objeto independiente identificando sus dimensiones, posición, fuente y color */
|
|
439
|
+
let charLeftPosition = left + padding.left;
|
|
440
|
+
const charTopStartPosition = top + padding.top;
|
|
441
|
+
for (const t of text) {
|
|
442
|
+
/* Almacena el estado anterior de la fuente para restablcerla. */
|
|
443
|
+
this.captureFont();
|
|
444
|
+
const font = {
|
|
445
|
+
name: t.font?.name ?? params.font?.name ?? this.currentFont.name,
|
|
446
|
+
bold: t.font?.bold ?? params.font?.bold ?? this.currentFont.bold,
|
|
447
|
+
oblique: t.font?.oblique ?? params.font?.oblique ?? this.currentFont.oblique,
|
|
448
|
+
size: t.font?.size ?? params.font?.size ?? this.currentFont.size,
|
|
449
|
+
color: t.font?.color ?? params.font?.color ?? this.currentFont.color,
|
|
450
|
+
};
|
|
451
|
+
this.setFont(font);
|
|
452
|
+
if (t.chars == null)
|
|
453
|
+
t.chars = '';
|
|
454
|
+
/* Sustituye los tabs por espacios regulares. */
|
|
455
|
+
t.chars = t.chars.replace(/\t/g, ' ');
|
|
456
|
+
for (let i = 0; i < t.chars.length; i++) {
|
|
457
|
+
const char = t.chars[i];
|
|
458
|
+
const charWidth = pols_utils_1.PUtilsNumber.round(this.engine.widthOfString(char), 6);
|
|
459
|
+
const charHeight = pols_utils_1.PUtilsNumber.round(this.engine.heightOfString(char), 6);
|
|
460
|
+
letters.push({
|
|
461
|
+
left: charLeftPosition,
|
|
462
|
+
top: charTopStartPosition,
|
|
463
|
+
char,
|
|
464
|
+
width: charWidth,
|
|
465
|
+
height: charHeight,
|
|
466
|
+
font,
|
|
467
|
+
});
|
|
468
|
+
charLeftPosition += charWidth;
|
|
469
|
+
if (char === ' ')
|
|
470
|
+
spacesIndexes.push(letters.length - 1);
|
|
471
|
+
}
|
|
472
|
+
this.restoreFont();
|
|
473
|
+
}
|
|
474
|
+
/* Si se ha definido el ancho de un párrafo, se determina dónde se puede hacer salto de línea */
|
|
475
|
+
/* Reinicia el inicio del primer caracter */
|
|
476
|
+
charLeftPosition = left + padding.left;
|
|
477
|
+
let lastSpaceIndex = null;
|
|
478
|
+
let lastSpaceSet = null;
|
|
479
|
+
let i = 0;
|
|
480
|
+
while (i < letters.length) {
|
|
481
|
+
const letter = letters[i];
|
|
482
|
+
letter.left = charLeftPosition;
|
|
483
|
+
if (letter.char != ' ' && width != null && (letter.left + letter.width > width + left - padding.right)) {
|
|
484
|
+
/* Si la posición excede el ancho de la celda, se busca el último espacio insertado, si no se ha insertado ningún espacio, el script continua */
|
|
485
|
+
if (lastSpaceIndex == null && i > 0)
|
|
486
|
+
lastSpaceIndex = i - 1;
|
|
487
|
+
if (lastSpaceIndex != null) {
|
|
488
|
+
if (lastSpaceIndex !== lastSpaceSet) {
|
|
489
|
+
i = lastSpaceIndex;
|
|
490
|
+
lastSpaceSet = lastSpaceIndex;
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
else {
|
|
494
|
+
letter.left = left + padding.left;
|
|
495
|
+
}
|
|
496
|
+
charLeftPosition = left + padding.left;
|
|
497
|
+
}
|
|
498
|
+
else if (letter.char == '\n') {
|
|
499
|
+
charLeftPosition = left + padding.left;
|
|
500
|
+
}
|
|
501
|
+
else {
|
|
502
|
+
charLeftPosition += letter.width;
|
|
503
|
+
}
|
|
504
|
+
if ([' ', '-'].includes(letter.char))
|
|
505
|
+
lastSpaceIndex = i;
|
|
506
|
+
i++;
|
|
507
|
+
}
|
|
508
|
+
/* Inserta cada caracter en un arreglo diferente según la línea que ocupa */
|
|
509
|
+
const lines = [[]];
|
|
510
|
+
let currentLine = 0;
|
|
511
|
+
for (const [i, letter] of letters.entries()) {
|
|
512
|
+
if (i > 0 && letter.left == left + padding.left) {
|
|
513
|
+
/* Si la letra tiene como posición */
|
|
514
|
+
lines.push([]);
|
|
515
|
+
currentLine++;
|
|
516
|
+
}
|
|
517
|
+
lines[currentLine].push(letter);
|
|
518
|
+
}
|
|
519
|
+
/* Define la posición vertical de cada letra en su respectiva línea */
|
|
520
|
+
let charTopPosition = charTopStartPosition;
|
|
521
|
+
let isFirstLine = true;
|
|
522
|
+
for (const line of lines) {
|
|
523
|
+
const maxHeight = Math.max(...line.map(letter => letter.height));
|
|
524
|
+
for (const letter of line) {
|
|
525
|
+
letter.top = charTopPosition - 0.4 + (!isFirstLine ? (params.spacing ?? 0) : 0);
|
|
526
|
+
/* Corrige la alineación vertical de las letras */
|
|
527
|
+
if (letter.height < maxHeight)
|
|
528
|
+
letter.top += maxHeight - letter.height;
|
|
529
|
+
}
|
|
530
|
+
charTopPosition = Math.max(...line.map(letter => letter.height + letter.top));
|
|
531
|
+
isFirstLine = false;
|
|
532
|
+
}
|
|
533
|
+
/* Elimina los espacios finales de cada línea */
|
|
534
|
+
for (const line of lines) {
|
|
535
|
+
if (line[line.length - 1]?.char == ' ')
|
|
536
|
+
line.splice(line.length - 1, 1);
|
|
537
|
+
}
|
|
538
|
+
const paragraphs = {
|
|
539
|
+
currentPage: [],
|
|
540
|
+
nextPage: []
|
|
541
|
+
};
|
|
542
|
+
let currentParagraph = 'currentPage';
|
|
543
|
+
/* Identifica qué líneas se desbordan de la página y las marca con "nextPage" a true */
|
|
544
|
+
for (const line of lines) {
|
|
545
|
+
const firstLetterOfLine = line[0];
|
|
546
|
+
if (!firstLetterOfLine)
|
|
547
|
+
continue;
|
|
548
|
+
/* Si la letra se desborda, se crea un nuevo párrafo */
|
|
549
|
+
if ('autojump' in params && currentParagraph != 'nextPage' && firstLetterOfLine.top + firstLetterOfLine.height + padding.bottom > (this.engine.page.height - this.engine.page.margins.bottom)) {
|
|
550
|
+
if (params.complete) {
|
|
551
|
+
paragraphs.nextPage = paragraphs.currentPage;
|
|
552
|
+
paragraphs.currentPage = [];
|
|
553
|
+
}
|
|
554
|
+
currentParagraph = 'nextPage';
|
|
555
|
+
}
|
|
556
|
+
paragraphs[currentParagraph].push(line);
|
|
557
|
+
}
|
|
558
|
+
/* Realiza la alineación horizontal */
|
|
559
|
+
if (width != null && (params.hAlign ?? 'left') != 'left') {
|
|
560
|
+
/* Observa la distancia entre el último caracter y el ancho */
|
|
561
|
+
for (const line of lines) {
|
|
562
|
+
if (!line.length)
|
|
563
|
+
continue;
|
|
564
|
+
const letter = line[line.length - 1];
|
|
565
|
+
const delta = left + width - padding.right - (letter.left + letter.width);
|
|
566
|
+
for (const letter of line) {
|
|
567
|
+
letter.left += params.hAlign === 'right' ? delta : (delta / 2);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
/* Realiza la alineación vertical sólo para el primer párrafo */
|
|
572
|
+
if ('height' in params && (params.vAlign ?? 'top') != 'top') {
|
|
573
|
+
this.verticalAlign(paragraphs.currentPage.flat(), params.vAlign ?? 'top', params.height, padding);
|
|
574
|
+
}
|
|
575
|
+
const letterForCurrentPage = paragraphs.currentPage.flat();
|
|
576
|
+
const lastLetterForCurrentPage = letterForCurrentPage[letterForCurrentPage.length - 1];
|
|
577
|
+
const finalWidth = width ?? (Math.max(...lines.map(line => line.reduce((ac, letter) => ac + letter.width, 0))) + padding.left + padding.right);
|
|
578
|
+
return {
|
|
579
|
+
currentPage: {
|
|
580
|
+
letters: letterForCurrentPage,
|
|
581
|
+
left,
|
|
582
|
+
top,
|
|
583
|
+
width: finalWidth,
|
|
584
|
+
height: 'height' in params ? params.height : (lastLetterForCurrentPage == null ? top : (lastLetterForCurrentPage.top + lastLetterForCurrentPage.height)) - top + padding.bottom,
|
|
585
|
+
padding,
|
|
586
|
+
border: this.prepareBorderValues(params.border),
|
|
587
|
+
radius: this.prepareRadiusValues(params.radius),
|
|
588
|
+
stroke: params.stroke,
|
|
589
|
+
fillColor: params.fillColor
|
|
590
|
+
},
|
|
591
|
+
nextPage: paragraphs.nextPage.length ? {
|
|
592
|
+
...params,
|
|
593
|
+
text: (() => {
|
|
594
|
+
const letters = [];
|
|
595
|
+
for (const [i, line] of paragraphs.nextPage.entries()) {
|
|
596
|
+
letters.push(...line.map(letter => ({
|
|
597
|
+
chars: letter.char,
|
|
598
|
+
font: letter.font
|
|
599
|
+
})));
|
|
600
|
+
if (i < paragraphs.nextPage.length - 1 && letters[letters.length - 1].chars != '\n') {
|
|
601
|
+
letters.push({
|
|
602
|
+
chars: '\n',
|
|
603
|
+
font: letters[letters.length - 1].font
|
|
604
|
+
});
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
return letters;
|
|
608
|
+
})(),
|
|
609
|
+
width: finalWidth
|
|
610
|
+
} : undefined
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
drawCell(params) {
|
|
614
|
+
/* Dibuja el borde. Este bloque podría ignorarse si al final no se escribirá ningún caracter debido al salto de página */
|
|
615
|
+
if (params.border || params.fillColor) {
|
|
616
|
+
this.rectangle({
|
|
617
|
+
left: params.left,
|
|
618
|
+
top: params.top,
|
|
619
|
+
width: params.width,
|
|
620
|
+
height: params.height,
|
|
621
|
+
border: params.border,
|
|
622
|
+
radius: params.radius,
|
|
623
|
+
fillColor: params.fillColor,
|
|
624
|
+
stroke: params.stroke
|
|
625
|
+
});
|
|
626
|
+
}
|
|
627
|
+
/* Dibujo de las letras */
|
|
628
|
+
let moveCursorTop = 0;
|
|
629
|
+
for (const letter of params.letters) {
|
|
630
|
+
/* Almacena el estado anterior de la fuente para restablcerla. */
|
|
631
|
+
this.captureFont();
|
|
632
|
+
this.setFont(letter.font);
|
|
633
|
+
let deltaFix = 0;
|
|
634
|
+
if ((letter.font.name ?? this.currentFont.name) == 'Helvetica') {
|
|
635
|
+
deltaFix = (letter.font.size ?? this.currentFont.size) * 0.2;
|
|
636
|
+
}
|
|
637
|
+
this.engine.fillColor(letter.font.color ?? this.currentFont.color).text(letter.char, letter.left, letter.top + deltaFix + (letter.font.name == 'Symbol' ? (letter.height * 0.6) : 0), { lineBreak: false });
|
|
638
|
+
moveCursorTop = Math.max(moveCursorTop, letter.top + letter.height);
|
|
639
|
+
this.restoreFont();
|
|
640
|
+
}
|
|
641
|
+
this.setCursorTopPosition(params.top + params.height);
|
|
642
|
+
}
|
|
643
|
+
cell(params) {
|
|
644
|
+
let paramsToDraw = params;
|
|
645
|
+
while (paramsToDraw) {
|
|
646
|
+
const prepared = this.prepareCell(paramsToDraw);
|
|
647
|
+
this.drawCell(prepared.currentPage);
|
|
648
|
+
if (prepared.nextPage) {
|
|
649
|
+
this.addPage();
|
|
650
|
+
paramsToDraw = {
|
|
651
|
+
...prepared.nextPage,
|
|
652
|
+
top: this.cursor.top
|
|
653
|
+
};
|
|
654
|
+
}
|
|
655
|
+
else {
|
|
656
|
+
paramsToDraw = null;
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
image(params) {
|
|
661
|
+
const options = {};
|
|
662
|
+
if ('fill' in params) {
|
|
663
|
+
if (params.fill == 'proportional') {
|
|
664
|
+
options.fit = [params.width, params.height];
|
|
665
|
+
}
|
|
666
|
+
else if (params.fill == 'cover') {
|
|
667
|
+
options.cover = [params.width, params.height];
|
|
668
|
+
}
|
|
669
|
+
if ('vAlign' in params)
|
|
670
|
+
options.valign = params.vAlign == 'top' ? undefined : params.vAlign;
|
|
671
|
+
if ('hAlign' in params)
|
|
672
|
+
options.align = params.hAlign == 'left' ? undefined : params.hAlign;
|
|
673
|
+
}
|
|
674
|
+
else {
|
|
675
|
+
if ('width' in params)
|
|
676
|
+
options.width = params.width;
|
|
677
|
+
if ('height' in params)
|
|
678
|
+
options.height = params.height;
|
|
679
|
+
}
|
|
680
|
+
this.engine.image(params.filePath, params.left, params.top, options);
|
|
681
|
+
this.cursor.left = this.engine.x;
|
|
682
|
+
this.cursor.top = this.engine.y;
|
|
683
|
+
}
|
|
684
|
+
prepareBoundValues(value, defa = {
|
|
685
|
+
left: 0,
|
|
686
|
+
top: 0,
|
|
687
|
+
bottom: 0,
|
|
688
|
+
right: 0
|
|
689
|
+
}) {
|
|
690
|
+
if (value != null) {
|
|
691
|
+
if (typeof value == 'number') {
|
|
692
|
+
return {
|
|
693
|
+
left: value,
|
|
694
|
+
right: value,
|
|
695
|
+
top: value,
|
|
696
|
+
bottom: value,
|
|
697
|
+
};
|
|
698
|
+
}
|
|
699
|
+
else {
|
|
700
|
+
return {
|
|
701
|
+
top: value.top ?? defa?.top ?? 0,
|
|
702
|
+
right: value.right ?? defa?.right ?? 0,
|
|
703
|
+
bottom: value.bottom ?? defa?.bottom ?? 0,
|
|
704
|
+
left: value.left ?? defa?.left ?? 0,
|
|
705
|
+
};
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
else {
|
|
709
|
+
return defa;
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
prepareRadiusValues(value, defa = {
|
|
713
|
+
leftTop: 0,
|
|
714
|
+
leftBottom: 0,
|
|
715
|
+
rightTop: 0,
|
|
716
|
+
rightBottom: 0,
|
|
717
|
+
}) {
|
|
718
|
+
if (value != null) {
|
|
719
|
+
if (typeof value == 'number') {
|
|
720
|
+
return {
|
|
721
|
+
leftTop: value,
|
|
722
|
+
rightTop: value,
|
|
723
|
+
leftBottom: value,
|
|
724
|
+
rightBottom: value,
|
|
725
|
+
};
|
|
726
|
+
}
|
|
727
|
+
else {
|
|
728
|
+
return {
|
|
729
|
+
leftTop: value.leftTop ?? defa?.leftTop ?? 0,
|
|
730
|
+
rightTop: value.rightTop ?? defa?.rightTop ?? 0,
|
|
731
|
+
leftBottom: value.leftBottom ?? defa?.leftBottom ?? 0,
|
|
732
|
+
rightBottom: value.rightBottom ?? defa?.rightBottom ?? 0,
|
|
733
|
+
};
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
else {
|
|
737
|
+
return defa;
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
prepareBorderValues(value, defa = {
|
|
741
|
+
left: false,
|
|
742
|
+
right: false,
|
|
743
|
+
bottom: false,
|
|
744
|
+
top: false,
|
|
745
|
+
leftBottom: false,
|
|
746
|
+
leftTop: false,
|
|
747
|
+
rightBottom: false,
|
|
748
|
+
rightTop: false
|
|
749
|
+
}) {
|
|
750
|
+
if (value != null) {
|
|
751
|
+
if (typeof value == 'boolean') {
|
|
752
|
+
return {
|
|
753
|
+
leftTop: value,
|
|
754
|
+
top: value,
|
|
755
|
+
rightTop: value,
|
|
756
|
+
right: value,
|
|
757
|
+
rightBottom: value,
|
|
758
|
+
bottom: value,
|
|
759
|
+
leftBottom: value,
|
|
760
|
+
left: value,
|
|
761
|
+
};
|
|
762
|
+
}
|
|
763
|
+
else {
|
|
764
|
+
return {
|
|
765
|
+
leftTop: value.leftTop ?? defa?.leftTop ?? false,
|
|
766
|
+
top: value.top ?? defa?.top ?? false,
|
|
767
|
+
rightTop: value.rightTop ?? defa?.rightTop ?? false,
|
|
768
|
+
right: value.right ?? defa?.right ?? false,
|
|
769
|
+
rightBottom: value.rightBottom ?? defa?.rightBottom ?? false,
|
|
770
|
+
bottom: value.bottom ?? defa?.bottom ?? false,
|
|
771
|
+
leftBottom: value.leftBottom ?? defa?.leftBottom ?? false,
|
|
772
|
+
left: value.left ?? defa?.left ?? false,
|
|
773
|
+
};
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
else {
|
|
777
|
+
return defa;
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
prepareBorderColorValues(value, defa = {
|
|
781
|
+
top: 'black',
|
|
782
|
+
rightTop: 'black',
|
|
783
|
+
right: 'black',
|
|
784
|
+
rightBottom: 'black',
|
|
785
|
+
bottom: 'black',
|
|
786
|
+
leftBottom: 'black',
|
|
787
|
+
left: 'black',
|
|
788
|
+
leftTop: 'black',
|
|
789
|
+
}) {
|
|
790
|
+
return typeof value == 'string' ? {
|
|
791
|
+
top: value,
|
|
792
|
+
rightTop: value,
|
|
793
|
+
right: value,
|
|
794
|
+
rightBottom: value,
|
|
795
|
+
bottom: value,
|
|
796
|
+
leftBottom: value,
|
|
797
|
+
left: value,
|
|
798
|
+
leftTop: value,
|
|
799
|
+
} : {
|
|
800
|
+
top: value?.top ?? defa.top,
|
|
801
|
+
rightTop: value?.rightTop ?? defa.rightTop,
|
|
802
|
+
right: value?.right ?? defa.right,
|
|
803
|
+
rightBottom: value?.rightBottom ?? defa.rightBottom,
|
|
804
|
+
bottom: value?.bottom ?? defa.bottom,
|
|
805
|
+
leftBottom: value?.leftBottom ?? defa.leftBottom,
|
|
806
|
+
left: value?.left ?? defa.left,
|
|
807
|
+
leftTop: value?.leftTop ?? defa.leftTop,
|
|
808
|
+
};
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
exports.PPdf = PPdf;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import globals from "globals";
|
|
2
|
+
import pluginJs from "@eslint/js";
|
|
3
|
+
import tseslint from "typescript-eslint";
|
|
4
|
+
|
|
5
|
+
export default [
|
|
6
|
+
{
|
|
7
|
+
files: ["**/*.{ts}"],
|
|
8
|
+
},
|
|
9
|
+
{ languageOptions: { globals: globals.node } },
|
|
10
|
+
pluginJs.configs.recommended,
|
|
11
|
+
...tseslint.configs.recommended,
|
|
12
|
+
{
|
|
13
|
+
rules: {
|
|
14
|
+
"@typescript-eslint/no-unused-vars": "warn",
|
|
15
|
+
"@typescript-eslint/no-explicit-any": "off",
|
|
16
|
+
"no-use-before-define": "off"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
];
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pols-pdf",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"types": "dist/index.d.ts",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "npx tsc",
|
|
8
|
+
"lint": "eslint src/index.ts",
|
|
9
|
+
"test": "npx ts-node-dev -r tsconfig-paths/register --project tsconfig.json",
|
|
10
|
+
"export": "npm run build && npm publish"
|
|
11
|
+
},
|
|
12
|
+
"author": "Jean Paul Sánchez mendoza",
|
|
13
|
+
"license": "ISC",
|
|
14
|
+
"description": "",
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"@eslint/js": "^9.13.0",
|
|
17
|
+
"@types/node": "^22.7.9",
|
|
18
|
+
"@types/pdfkit": "^0.17.6",
|
|
19
|
+
"eslint": "^9.13.0",
|
|
20
|
+
"globals": "^15.11.0",
|
|
21
|
+
"ts-node-dev": "^2.0.0",
|
|
22
|
+
"tsconfig-paths": "^4.2.0",
|
|
23
|
+
"typescript": "^5.6.3",
|
|
24
|
+
"typescript-eslint": "^8.11.0"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"pdfkit": "^0.19.1",
|
|
28
|
+
"pols-utils": "^6.0.1"
|
|
29
|
+
}
|
|
30
|
+
}
|