@pdfme/common 0.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 +5 -0
- package/dist/cjs/__tests__/dynamicTemplate.test.js +275 -0
- package/dist/cjs/__tests__/dynamicTemplate.test.js.map +1 -0
- package/dist/cjs/__tests__/expression.test.js +474 -0
- package/dist/cjs/__tests__/expression.test.js.map +1 -0
- package/dist/cjs/__tests__/helper.test.js +647 -0
- package/dist/cjs/__tests__/helper.test.js.map +1 -0
- package/dist/cjs/__tests__/pluginRegistry.test.js +83 -0
- package/dist/cjs/__tests__/pluginRegistry.test.js.map +1 -0
- package/dist/cjs/src/constants.js +27 -0
- package/dist/cjs/src/constants.js.map +1 -0
- package/dist/cjs/src/dynamicTemplate.js +284 -0
- package/dist/cjs/src/dynamicTemplate.js.map +1 -0
- package/dist/cjs/src/expression.js +463 -0
- package/dist/cjs/src/expression.js.map +1 -0
- package/dist/cjs/src/helper.js +217 -0
- package/dist/cjs/src/helper.js.map +1 -0
- package/dist/cjs/src/index.js +42 -0
- package/dist/cjs/src/index.js.map +1 -0
- package/dist/cjs/src/pluginRegistry.js +33 -0
- package/dist/cjs/src/pluginRegistry.js.map +1 -0
- package/dist/cjs/src/schema.js +190 -0
- package/dist/cjs/src/schema.js.map +1 -0
- package/dist/cjs/src/types.js +3 -0
- package/dist/cjs/src/types.js.map +1 -0
- package/dist/cjs/src/version.js +5 -0
- package/dist/cjs/src/version.js.map +1 -0
- package/dist/esm/__tests__/dynamicTemplate.test.js +240 -0
- package/dist/esm/__tests__/dynamicTemplate.test.js.map +1 -0
- package/dist/esm/__tests__/expression.test.js +472 -0
- package/dist/esm/__tests__/expression.test.js.map +1 -0
- package/dist/esm/__tests__/helper.test.js +612 -0
- package/dist/esm/__tests__/helper.test.js.map +1 -0
- package/dist/esm/__tests__/pluginRegistry.test.js +81 -0
- package/dist/esm/__tests__/pluginRegistry.test.js.map +1 -0
- package/dist/esm/src/constants.js +24 -0
- package/dist/esm/src/constants.js.map +1 -0
- package/dist/esm/src/dynamicTemplate.js +280 -0
- package/dist/esm/src/dynamicTemplate.js.map +1 -0
- package/dist/esm/src/expression.js +426 -0
- package/dist/esm/src/expression.js.map +1 -0
- package/dist/esm/src/helper.js +193 -0
- package/dist/esm/src/helper.js.map +1 -0
- package/dist/esm/src/index.js +8 -0
- package/dist/esm/src/index.js.map +1 -0
- package/dist/esm/src/pluginRegistry.js +29 -0
- package/dist/esm/src/pluginRegistry.js.map +1 -0
- package/dist/esm/src/schema.js +187 -0
- package/dist/esm/src/schema.js.map +1 -0
- package/dist/esm/src/types.js +2 -0
- package/dist/esm/src/types.js.map +1 -0
- package/dist/esm/src/version.js +2 -0
- package/dist/esm/src/version.js.map +1 -0
- package/dist/node/__tests__/dynamicTemplate.test.js +275 -0
- package/dist/node/__tests__/dynamicTemplate.test.js.map +1 -0
- package/dist/node/__tests__/expression.test.js +474 -0
- package/dist/node/__tests__/expression.test.js.map +1 -0
- package/dist/node/__tests__/helper.test.js +647 -0
- package/dist/node/__tests__/helper.test.js.map +1 -0
- package/dist/node/__tests__/pluginRegistry.test.js +83 -0
- package/dist/node/__tests__/pluginRegistry.test.js.map +1 -0
- package/dist/node/src/constants.js +27 -0
- package/dist/node/src/constants.js.map +1 -0
- package/dist/node/src/dynamicTemplate.js +284 -0
- package/dist/node/src/dynamicTemplate.js.map +1 -0
- package/dist/node/src/expression.js +463 -0
- package/dist/node/src/expression.js.map +1 -0
- package/dist/node/src/helper.js +217 -0
- package/dist/node/src/helper.js.map +1 -0
- package/dist/node/src/index.js +42 -0
- package/dist/node/src/index.js.map +1 -0
- package/dist/node/src/pluginRegistry.js +33 -0
- package/dist/node/src/pluginRegistry.js.map +1 -0
- package/dist/node/src/schema.js +190 -0
- package/dist/node/src/schema.js.map +1 -0
- package/dist/node/src/types.js +3 -0
- package/dist/node/src/types.js.map +1 -0
- package/dist/node/src/version.js +5 -0
- package/dist/node/src/version.js.map +1 -0
- package/dist/types/__tests__/dynamicTemplate.test.d.ts +1 -0
- package/dist/types/__tests__/expression.test.d.ts +1 -0
- package/dist/types/__tests__/helper.test.d.ts +1 -0
- package/dist/types/__tests__/pluginRegistry.test.d.ts +1 -0
- package/dist/types/src/constants.d.ts +20 -0
- package/dist/types/src/dynamicTemplate.d.ts +15 -0
- package/dist/types/src/expression.d.ts +6 -0
- package/dist/types/src/helper.d.ts +35 -0
- package/dist/types/src/index.d.ts +9 -0
- package/dist/types/src/pluginRegistry.d.ts +5 -0
- package/dist/types/src/schema.d.ts +820 -0
- package/dist/types/src/types.d.ts +181 -0
- package/dist/types/src/version.d.ts +1 -0
- package/eslint.config.mjs +22 -0
- package/package.json +84 -0
- package/set-version.js +31 -0
- package/src/constants.ts +30 -0
- package/src/dynamicTemplate.ts +349 -0
- package/src/expression.ts +460 -0
- package/src/helper.ts +284 -0
- package/src/index.ts +136 -0
- package/src/pluginRegistry.ts +30 -0
- package/src/schema.ts +223 -0
- package/src/types.ts +198 -0
- package/src/version.ts +1 -0
- package/tsconfig.cjs.json +10 -0
- package/tsconfig.esm.json +11 -0
- package/tsconfig.json +6 -0
- package/tsconfig.node.json +11 -0
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
import { Schema, Template, BasePdf, BlankPdf, CommonOptions } from './types.js';
|
|
2
|
+
import { cloneDeep, isBlankPdf } from './helper.js';
|
|
3
|
+
|
|
4
|
+
interface ModifyTemplateForDynamicTableArg {
|
|
5
|
+
template: Template;
|
|
6
|
+
input: Record<string, string>;
|
|
7
|
+
_cache: Map<string | number, unknown>;
|
|
8
|
+
options: CommonOptions;
|
|
9
|
+
getDynamicHeights: (
|
|
10
|
+
value: string,
|
|
11
|
+
args: {
|
|
12
|
+
schema: Schema;
|
|
13
|
+
basePdf: BasePdf;
|
|
14
|
+
options: CommonOptions;
|
|
15
|
+
_cache: Map<string | number, unknown>;
|
|
16
|
+
},
|
|
17
|
+
) => Promise<number[]>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
class LayoutNode {
|
|
21
|
+
index = 0;
|
|
22
|
+
|
|
23
|
+
schema?: Schema;
|
|
24
|
+
|
|
25
|
+
children: LayoutNode[] = [];
|
|
26
|
+
|
|
27
|
+
width = 0;
|
|
28
|
+
height = 0;
|
|
29
|
+
padding: [number, number, number, number] = [0, 0, 0, 0];
|
|
30
|
+
position: { x: number; y: number } = { x: 0, y: 0 };
|
|
31
|
+
|
|
32
|
+
constructor({ width = 0, height = 0 } = {}) {
|
|
33
|
+
this.width = width;
|
|
34
|
+
this.height = height;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
setIndex(index: number): void {
|
|
38
|
+
this.index = index;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
setSchema(schema: Schema): void {
|
|
42
|
+
this.schema = schema;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
setWidth(width: number): void {
|
|
46
|
+
this.width = width;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
setHeight(height: number): void {
|
|
50
|
+
this.height = height;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
setPadding(padding: [number, number, number, number]): void {
|
|
54
|
+
this.padding = padding;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
setPosition(position: { x: number; y: number }): void {
|
|
58
|
+
this.position = position;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
insertChild(child: LayoutNode): void {
|
|
62
|
+
const index = this.getChildCount();
|
|
63
|
+
child.setIndex(index);
|
|
64
|
+
this.children.splice(index, 0, child);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
getChildCount(): number {
|
|
68
|
+
return this.children.length;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
getChild(index: number): LayoutNode {
|
|
72
|
+
return this.children[index];
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function createPage(basePdf: BlankPdf) {
|
|
77
|
+
const page = new LayoutNode({ ...basePdf });
|
|
78
|
+
page.setPadding(basePdf.padding);
|
|
79
|
+
return page;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function createNode(arg: {
|
|
83
|
+
schema: Schema;
|
|
84
|
+
position: { x: number; y: number };
|
|
85
|
+
width: number;
|
|
86
|
+
height: number;
|
|
87
|
+
}) {
|
|
88
|
+
const { position, width, height, schema } = arg;
|
|
89
|
+
const node = new LayoutNode({ width, height });
|
|
90
|
+
node.setPosition(position);
|
|
91
|
+
node.setSchema(schema);
|
|
92
|
+
return node;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function resortChildren(page: LayoutNode, orderMap: Map<string, number>): void {
|
|
96
|
+
page.children = page.children
|
|
97
|
+
.sort((a, b) => {
|
|
98
|
+
const orderA = orderMap.get(a.schema?.name ?? '');
|
|
99
|
+
const orderB = orderMap.get(b.schema?.name ?? '');
|
|
100
|
+
if (orderA === undefined || orderB === undefined) {
|
|
101
|
+
throw new Error('[@pdfme/common] order is not defined');
|
|
102
|
+
}
|
|
103
|
+
return orderA - orderB;
|
|
104
|
+
})
|
|
105
|
+
.map((child, index) => {
|
|
106
|
+
child.setIndex(index);
|
|
107
|
+
return child;
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async function createOnePage(
|
|
112
|
+
arg: {
|
|
113
|
+
basePdf: BlankPdf;
|
|
114
|
+
schemaPage: Schema[];
|
|
115
|
+
orderMap: Map<string, number>;
|
|
116
|
+
} & Omit<ModifyTemplateForDynamicTableArg, 'template'>,
|
|
117
|
+
): Promise<LayoutNode> {
|
|
118
|
+
const { basePdf, schemaPage, orderMap, input, options, _cache, getDynamicHeights } = arg;
|
|
119
|
+
const page = createPage(basePdf);
|
|
120
|
+
|
|
121
|
+
const schemaPositions: number[] = [];
|
|
122
|
+
const sortedSchemaEntries = cloneDeep(schemaPage).sort((a, b) => a.position.y - b.position.y);
|
|
123
|
+
const diffMap = new Map();
|
|
124
|
+
for (const schema of sortedSchemaEntries) {
|
|
125
|
+
const { position, width } = schema;
|
|
126
|
+
|
|
127
|
+
const opt = { schema, basePdf, options, _cache };
|
|
128
|
+
const value = (schema.readOnly ? schema.content : input?.[schema.name]) || '';
|
|
129
|
+
const heights = await getDynamicHeights(value, opt);
|
|
130
|
+
|
|
131
|
+
const heightsSum = heights.reduce((acc, cur) => acc + cur, 0);
|
|
132
|
+
const originalHeight = schema.height;
|
|
133
|
+
if (heightsSum !== originalHeight) {
|
|
134
|
+
diffMap.set(position.y + originalHeight, heightsSum - originalHeight);
|
|
135
|
+
}
|
|
136
|
+
heights.forEach((height, index) => {
|
|
137
|
+
let y = schema.position.y + heights.reduce((acc, cur, i) => (i < index ? acc + cur : acc), 0);
|
|
138
|
+
for (const [diffY, diff] of diffMap.entries()) {
|
|
139
|
+
if (diffY <= schema.position.y) {
|
|
140
|
+
y += diff;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
const node = createNode({ schema, position: { ...position, y }, width, height });
|
|
144
|
+
|
|
145
|
+
schemaPositions.push(y + height + basePdf.padding[2]);
|
|
146
|
+
page.insertChild(node);
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const pageHeight = Math.max(...schemaPositions, basePdf.height - basePdf.padding[2]);
|
|
151
|
+
page.setHeight(pageHeight);
|
|
152
|
+
|
|
153
|
+
resortChildren(page, orderMap);
|
|
154
|
+
|
|
155
|
+
return page;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function breakIntoPages(arg: {
|
|
159
|
+
longPage: LayoutNode;
|
|
160
|
+
orderMap: Map<string, number>;
|
|
161
|
+
basePdf: BlankPdf;
|
|
162
|
+
}): LayoutNode[] {
|
|
163
|
+
const { longPage, orderMap, basePdf } = arg;
|
|
164
|
+
const pages: LayoutNode[] = [createPage(basePdf)];
|
|
165
|
+
const [paddingTop, , paddingBottom] = basePdf.padding;
|
|
166
|
+
const yAdjustments: { page: number; value: number }[] = [];
|
|
167
|
+
|
|
168
|
+
const getPageHeight = (pageIndex: number) =>
|
|
169
|
+
basePdf.height - paddingBottom - (pageIndex > 0 ? paddingTop : 0);
|
|
170
|
+
|
|
171
|
+
const calculateNewY = (y: number, pageIndex: number) => {
|
|
172
|
+
const newY = y - pageIndex * (basePdf.height - paddingTop - paddingBottom);
|
|
173
|
+
|
|
174
|
+
while (pages.length <= pageIndex) {
|
|
175
|
+
if (!pages[pageIndex]) {
|
|
176
|
+
pages.push(createPage(basePdf));
|
|
177
|
+
yAdjustments.push({ page: pageIndex, value: (newY - paddingTop) * -1 });
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return newY + (yAdjustments.find((adj) => adj.page === pageIndex)?.value || 0);
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
const calculateTargetPageIndex = (y: number) => {
|
|
185
|
+
let accumulatedHeight = 0;
|
|
186
|
+
let pageIndex = 0;
|
|
187
|
+
|
|
188
|
+
while (true) {
|
|
189
|
+
const currentPageHeight = getPageHeight(pageIndex);
|
|
190
|
+
|
|
191
|
+
if (y <= accumulatedHeight + currentPageHeight) {
|
|
192
|
+
return pageIndex;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
accumulatedHeight += currentPageHeight;
|
|
196
|
+
pageIndex++;
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
const children = longPage.children.sort((a, b) => a.position.y - b.position.y);
|
|
201
|
+
|
|
202
|
+
let currentPageIndex = 0;
|
|
203
|
+
|
|
204
|
+
for (let i = 0; i < children.length; i++) {
|
|
205
|
+
const { schema, position, height, width } = children[i];
|
|
206
|
+
const { y, x } = position;
|
|
207
|
+
|
|
208
|
+
let targetPageIndex = calculateTargetPageIndex(y);
|
|
209
|
+
|
|
210
|
+
if (targetPageIndex < currentPageIndex) {
|
|
211
|
+
targetPageIndex = currentPageIndex;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
let newY = calculateNewY(y, targetPageIndex);
|
|
215
|
+
|
|
216
|
+
while (newY + height > basePdf.height - paddingBottom) {
|
|
217
|
+
const currentPageContentHeight = getPageHeight(targetPageIndex + 1);
|
|
218
|
+
|
|
219
|
+
if (height > currentPageContentHeight) {
|
|
220
|
+
targetPageIndex++;
|
|
221
|
+
newY = calculateNewY(y, targetPageIndex);
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
targetPageIndex++;
|
|
226
|
+
newY = calculateNewY(y, targetPageIndex);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
currentPageIndex = targetPageIndex;
|
|
230
|
+
|
|
231
|
+
if (!schema) throw new Error('[@pdfme/common] schema is undefined');
|
|
232
|
+
|
|
233
|
+
const clonedElement = createNode({ schema, position: { x, y: newY }, width, height });
|
|
234
|
+
pages[targetPageIndex].insertChild(clonedElement);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
pages.forEach((page) => resortChildren(page, orderMap));
|
|
238
|
+
|
|
239
|
+
return pages;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function createNewTemplate(pages: LayoutNode[], basePdf: BlankPdf): Template {
|
|
243
|
+
const newTemplate: Template = {
|
|
244
|
+
schemas: Array.from({ length: pages.length }, () => [] as Schema[]),
|
|
245
|
+
basePdf: basePdf,
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
const nameToSchemas = new Map<string, LayoutNode[]>();
|
|
249
|
+
|
|
250
|
+
cloneDeep(pages).forEach((page, pageIndex) => {
|
|
251
|
+
page.children.forEach((child) => {
|
|
252
|
+
const { schema } = child;
|
|
253
|
+
if (!schema) throw new Error('[@pdfme/common] schema is undefined');
|
|
254
|
+
|
|
255
|
+
const name = schema.name;
|
|
256
|
+
if (!nameToSchemas.has(name)) {
|
|
257
|
+
nameToSchemas.set(name, []);
|
|
258
|
+
}
|
|
259
|
+
nameToSchemas.get(name)!.push(child);
|
|
260
|
+
|
|
261
|
+
const sameNameSchemas = page.children.filter((c) => c.schema?.name === name);
|
|
262
|
+
const start = nameToSchemas.get(name)!.length - sameNameSchemas.length;
|
|
263
|
+
|
|
264
|
+
if (sameNameSchemas.length > 0) {
|
|
265
|
+
if (!sameNameSchemas[0].schema) {
|
|
266
|
+
throw new Error('[@pdfme/common] schema is undefined');
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Use the first schema to get the schema and position
|
|
270
|
+
const schema = sameNameSchemas[0].schema;
|
|
271
|
+
const height = sameNameSchemas.reduce((acc, cur) => acc + cur.height, 0);
|
|
272
|
+
const position = sameNameSchemas[0].position;
|
|
273
|
+
|
|
274
|
+
// Currently, __bodyRange exists for table schemas, but if we make it more abstract,
|
|
275
|
+
// it could be used for other schemas as well to render schemas that have been split by page breaks, starting from the middle.
|
|
276
|
+
schema.__bodyRange = {
|
|
277
|
+
start: Math.max(start - 1, 0),
|
|
278
|
+
end: start + sameNameSchemas.length - 1,
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
// Currently, this is used to determine whether to display the header when a table is split.
|
|
282
|
+
schema.__isSplit = start > 0;
|
|
283
|
+
|
|
284
|
+
const newSchema = Object.assign({}, schema, { position, height });
|
|
285
|
+
const index = newTemplate.schemas[pageIndex].findIndex((s) => s.name === name);
|
|
286
|
+
if (index !== -1) {
|
|
287
|
+
newTemplate.schemas[pageIndex][index] = newSchema;
|
|
288
|
+
} else {
|
|
289
|
+
newTemplate.schemas[pageIndex].push(newSchema);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
return newTemplate;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
function flattenSchemasWithOffset(
|
|
299
|
+
templateSchemas: Schema[][],
|
|
300
|
+
basePdf: BlankPdf,
|
|
301
|
+
): { flatSchemas: Schema[]; orderMap: Map<string, number> } {
|
|
302
|
+
const flatSchemas: Schema[] = [];
|
|
303
|
+
const orderMap = new Map<string, number>();
|
|
304
|
+
let globalOrder = 0;
|
|
305
|
+
const [paddingTop, , paddingBottom] = basePdf.padding;
|
|
306
|
+
const getPageHeight = (pageIndex: number) =>
|
|
307
|
+
basePdf.height - paddingBottom - (pageIndex > 0 ? paddingTop : 0);
|
|
308
|
+
|
|
309
|
+
let yOffset = 0;
|
|
310
|
+
templateSchemas.forEach((schemaPage, pageIndex) => {
|
|
311
|
+
if (pageIndex > 0) yOffset += getPageHeight(pageIndex - 1);
|
|
312
|
+
|
|
313
|
+
schemaPage.forEach((schema) => {
|
|
314
|
+
const clonedSchema = cloneDeep(schema);
|
|
315
|
+
clonedSchema.position = { ...clonedSchema.position, y: clonedSchema.position.y + yOffset };
|
|
316
|
+
flatSchemas.push(clonedSchema);
|
|
317
|
+
|
|
318
|
+
if (!orderMap.has(schema.name)) {
|
|
319
|
+
orderMap.set(schema.name, globalOrder++);
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
return { flatSchemas, orderMap };
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
export const getDynamicTemplate = async (
|
|
328
|
+
arg: ModifyTemplateForDynamicTableArg,
|
|
329
|
+
): Promise<Template> => {
|
|
330
|
+
const { template, ...rest } = arg;
|
|
331
|
+
const basePdf = template.basePdf;
|
|
332
|
+
|
|
333
|
+
if (!isBlankPdf(basePdf)) {
|
|
334
|
+
return template;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
const { flatSchemas, orderMap } = flattenSchemasWithOffset(template.schemas, basePdf);
|
|
338
|
+
|
|
339
|
+
const longPage = await createOnePage({
|
|
340
|
+
basePdf,
|
|
341
|
+
schemaPage: flatSchemas,
|
|
342
|
+
orderMap,
|
|
343
|
+
...rest,
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
const pages = breakIntoPages({ longPage, basePdf, orderMap });
|
|
347
|
+
|
|
348
|
+
return createNewTemplate(pages, basePdf);
|
|
349
|
+
};
|