cvdl-ts 1.0.25 → 1.0.27
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/dist/AnyLayout.d.ts +3 -1
- package/dist/AnyLayout.js +148 -4
- package/dist/Elem.js +2 -1
- package/dist/Layout.d.ts +1 -0
- package/dist/Layout.js +15 -12
- package/dist/PdfLayout.js +35 -12
- package/dist/Row.d.ts +1 -0
- package/dist/Row.js +31 -4
- package/package.json +4 -2
package/dist/AnyLayout.d.ts
CHANGED
|
@@ -28,11 +28,13 @@ export type RenderProps = {
|
|
|
28
28
|
bindings: Map<string, unknown>;
|
|
29
29
|
storage: Storage;
|
|
30
30
|
fontDict?: FontDict;
|
|
31
|
+
incremental?: boolean;
|
|
31
32
|
};
|
|
33
|
+
export declare function resetIncrementalCaches(): void;
|
|
32
34
|
export declare class FontDict {
|
|
33
35
|
fonts: Map<string, fontkit.Font>;
|
|
34
36
|
constructor();
|
|
35
37
|
load_fonts(storage: Storage): Promise<this>;
|
|
36
38
|
get_font(name: string): fontkit.Font;
|
|
37
39
|
}
|
|
38
|
-
export declare function render({ resume, layout_schemas, data_schemas, resume_layout, bindings, fontDict, }: RenderProps): Layout.RenderedLayout[];
|
|
40
|
+
export declare function render({ resume, layout_schemas, data_schemas, resume_layout, bindings, fontDict, incremental, }: RenderProps): Layout.RenderedLayout[];
|
package/dist/AnyLayout.js
CHANGED
|
@@ -24,10 +24,50 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
26
|
exports.FontDict = void 0;
|
|
27
|
+
exports.resetIncrementalCaches = resetIncrementalCaches;
|
|
27
28
|
exports.render = render;
|
|
28
29
|
const ResumeLayout_1 = require("./ResumeLayout");
|
|
29
30
|
const fontkit = __importStar(require("fontkit"));
|
|
30
31
|
const Layout = __importStar(require("./Layout"));
|
|
32
|
+
const blockCache = new Map();
|
|
33
|
+
let flowPlacementCache = {
|
|
34
|
+
order: [],
|
|
35
|
+
signatures: [],
|
|
36
|
+
offsets: [],
|
|
37
|
+
heights: [],
|
|
38
|
+
};
|
|
39
|
+
const stableBindingsSignature = (bindings) => {
|
|
40
|
+
const sortedEntries = Array.from(bindings.entries()).sort(([a], [b]) => a.localeCompare(b));
|
|
41
|
+
return JSON.stringify(sortedEntries);
|
|
42
|
+
};
|
|
43
|
+
const stableSignature = (value) => {
|
|
44
|
+
try {
|
|
45
|
+
return JSON.stringify(value);
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return String(value);
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
const getOrComputeBlock = (key, signature, compute, stats) => {
|
|
52
|
+
const cached = blockCache.get(key);
|
|
53
|
+
if (cached && cached.signature === signature) {
|
|
54
|
+
stats.hits += 1;
|
|
55
|
+
return cached.layout;
|
|
56
|
+
}
|
|
57
|
+
const layout = compute();
|
|
58
|
+
blockCache.set(key, { signature, layout });
|
|
59
|
+
stats.misses += 1;
|
|
60
|
+
return layout;
|
|
61
|
+
};
|
|
62
|
+
function resetIncrementalCaches() {
|
|
63
|
+
blockCache.clear();
|
|
64
|
+
flowPlacementCache = {
|
|
65
|
+
order: [],
|
|
66
|
+
signatures: [],
|
|
67
|
+
offsets: [],
|
|
68
|
+
heights: [],
|
|
69
|
+
};
|
|
70
|
+
}
|
|
31
71
|
const cartesian = (...a) => a.reduce((a, b) => a.flatMap((d) => b.map((e) => [d, e].flat())));
|
|
32
72
|
class FontDict {
|
|
33
73
|
constructor() {
|
|
@@ -56,7 +96,8 @@ class FontDict {
|
|
|
56
96
|
}
|
|
57
97
|
}
|
|
58
98
|
exports.FontDict = FontDict;
|
|
59
|
-
function render({ resume, layout_schemas, data_schemas, resume_layout, bindings, fontDict, }) {
|
|
99
|
+
function render({ resume, layout_schemas, data_schemas, resume_layout, bindings, fontDict, incremental = true, }) {
|
|
100
|
+
var _a;
|
|
60
101
|
// Compute the total usable width by subtracting the margins from the document width
|
|
61
102
|
const width = resume_layout.width -
|
|
62
103
|
(resume_layout.margin.left + resume_layout.margin.right);
|
|
@@ -65,6 +106,14 @@ function render({ resume, layout_schemas, data_schemas, resume_layout, bindings,
|
|
|
65
106
|
? width
|
|
66
107
|
: width - (0, ResumeLayout_1.vertical_margin)(resume_layout.column_type) / 2.0;
|
|
67
108
|
const layouts = [];
|
|
109
|
+
const usedKeys = new Set();
|
|
110
|
+
const stats = { hits: 0, misses: 0 };
|
|
111
|
+
const blockOrder = [];
|
|
112
|
+
const blockSignatures = [];
|
|
113
|
+
const blockHeights = [];
|
|
114
|
+
const bindingsSignature = stableBindingsSignature(bindings);
|
|
115
|
+
const fontSignature = stableSignature(Array.from(fontDict.fonts.keys()).sort());
|
|
116
|
+
let firstDirtyBlock = incremental ? -1 : 0;
|
|
68
117
|
console.info("Rendering sections...");
|
|
69
118
|
for (const section of resume.sections) {
|
|
70
119
|
// Render Section Header
|
|
@@ -85,8 +134,33 @@ function render({ resume, layout_schemas, data_schemas, resume_layout, bindings,
|
|
|
85
134
|
}
|
|
86
135
|
start_time = Date.now();
|
|
87
136
|
// 3. Render the header
|
|
88
|
-
const
|
|
137
|
+
const headerKey = `${section.section_name}::header`;
|
|
138
|
+
const headerSignature = stableSignature({
|
|
139
|
+
column_width,
|
|
140
|
+
fontSignature,
|
|
141
|
+
bindingsSignature,
|
|
142
|
+
layout: layout_schema.header_layout_schema,
|
|
143
|
+
fields: data_schema.header_schema,
|
|
144
|
+
data: section.data,
|
|
145
|
+
});
|
|
146
|
+
usedKeys.add(headerKey);
|
|
147
|
+
const blockIndex = blockOrder.length;
|
|
148
|
+
blockOrder.push(headerKey);
|
|
149
|
+
blockSignatures.push(headerSignature);
|
|
150
|
+
if (incremental &&
|
|
151
|
+
firstDirtyBlock === -1 &&
|
|
152
|
+
(flowPlacementCache.order[blockIndex] !== headerKey ||
|
|
153
|
+
flowPlacementCache.signatures[blockIndex] !== headerSignature)) {
|
|
154
|
+
firstDirtyBlock = blockIndex;
|
|
155
|
+
}
|
|
156
|
+
const layout = incremental
|
|
157
|
+
? getOrComputeBlock(headerKey, headerSignature, () => Layout.computeBoxes(Layout.normalize(Layout.instantiate(layout_schema.header_layout_schema, section.data, data_schema.header_schema, bindings), column_width, fontDict), fontDict), stats)
|
|
158
|
+
: (() => {
|
|
159
|
+
stats.misses += 1;
|
|
160
|
+
return Layout.computeBoxes(Layout.normalize(Layout.instantiate(layout_schema.header_layout_schema, section.data, data_schema.header_schema, bindings), column_width, fontDict), fontDict);
|
|
161
|
+
})();
|
|
89
162
|
layout.path = { tag: "section", section: section.section_name };
|
|
163
|
+
blockHeights.push(layout.bounding_box.height() + layout.margin.top + layout.margin.bottom);
|
|
90
164
|
console.info("Header is computed");
|
|
91
165
|
layouts.push(layout);
|
|
92
166
|
end_time = Date.now();
|
|
@@ -94,14 +168,84 @@ function render({ resume, layout_schemas, data_schemas, resume_layout, bindings,
|
|
|
94
168
|
start_time = Date.now();
|
|
95
169
|
// Render Section Items
|
|
96
170
|
for (const [index, item] of section.items.entries()) {
|
|
97
|
-
|
|
98
|
-
const
|
|
171
|
+
const itemKey = `${section.section_name}::item::${(_a = item.id) !== null && _a !== void 0 ? _a : index}`;
|
|
172
|
+
const itemSignature = stableSignature({
|
|
173
|
+
column_width,
|
|
174
|
+
fontSignature,
|
|
175
|
+
bindingsSignature,
|
|
176
|
+
layout: layout_schema.item_layout_schema,
|
|
177
|
+
fields: data_schema.item_schema,
|
|
178
|
+
data: item,
|
|
179
|
+
});
|
|
180
|
+
usedKeys.add(itemKey);
|
|
181
|
+
const blockIndex = blockOrder.length;
|
|
182
|
+
blockOrder.push(itemKey);
|
|
183
|
+
blockSignatures.push(itemSignature);
|
|
184
|
+
if (incremental &&
|
|
185
|
+
firstDirtyBlock === -1 &&
|
|
186
|
+
(flowPlacementCache.order[blockIndex] !== itemKey ||
|
|
187
|
+
flowPlacementCache.signatures[blockIndex] !== itemSignature)) {
|
|
188
|
+
firstDirtyBlock = blockIndex;
|
|
189
|
+
}
|
|
190
|
+
const layout = incremental
|
|
191
|
+
? getOrComputeBlock(itemKey, itemSignature, () => Layout.computeBoxes(Layout.normalize(Layout.instantiate(layout_schema.item_layout_schema, item, data_schema.item_schema, bindings), column_width, fontDict), fontDict), stats)
|
|
192
|
+
: (() => {
|
|
193
|
+
stats.misses += 1;
|
|
194
|
+
return Layout.computeBoxes(Layout.normalize(Layout.instantiate(layout_schema.item_layout_schema, item, data_schema.item_schema, bindings), column_width, fontDict), fontDict);
|
|
195
|
+
})();
|
|
99
196
|
layout.path = { tag: "item", section: section.section_name, item: index };
|
|
197
|
+
blockHeights.push(layout.bounding_box.height() + layout.margin.top + layout.margin.bottom);
|
|
100
198
|
layouts.push(layout);
|
|
101
199
|
}
|
|
102
200
|
end_time = Date.now();
|
|
103
201
|
console.info(`Item rendering time: ${end_time - start_time}ms for section ${section.section_name}`);
|
|
104
202
|
}
|
|
203
|
+
const hasSameBlockShape = flowPlacementCache.order.length === blockOrder.length &&
|
|
204
|
+
firstDirtyBlock === -1;
|
|
205
|
+
if (!incremental || !hasSameBlockShape) {
|
|
206
|
+
if (firstDirtyBlock === -1) {
|
|
207
|
+
firstDirtyBlock = Math.min(blockOrder.length, flowPlacementCache.order.length);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
const offsets = new Array(blockOrder.length).fill(0);
|
|
211
|
+
if (incremental && firstDirtyBlock > 0) {
|
|
212
|
+
for (let i = 0; i < firstDirtyBlock; i++) {
|
|
213
|
+
offsets[i] = flowPlacementCache.offsets[i];
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
if (!incremental || firstDirtyBlock !== -1) {
|
|
217
|
+
const start = !incremental ? 0 : Math.max(0, firstDirtyBlock);
|
|
218
|
+
let cursor = start === 0 ? 0 : offsets[start - 1] + blockHeights[start - 1];
|
|
219
|
+
for (let i = start; i < blockOrder.length; i++) {
|
|
220
|
+
offsets[i] = cursor;
|
|
221
|
+
cursor += blockHeights[i];
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
for (let i = 0; i < blockOrder.length; i++) {
|
|
226
|
+
offsets[i] = flowPlacementCache.offsets[i];
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
for (let i = 0; i < layouts.length; i++) {
|
|
230
|
+
layouts[i].flow_offset_y = offsets[i];
|
|
231
|
+
}
|
|
232
|
+
if (incremental) {
|
|
233
|
+
for (const key of Array.from(blockCache.keys())) {
|
|
234
|
+
if (!usedKeys.has(key)) {
|
|
235
|
+
blockCache.delete(key);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
flowPlacementCache = {
|
|
239
|
+
order: blockOrder,
|
|
240
|
+
signatures: blockSignatures,
|
|
241
|
+
offsets,
|
|
242
|
+
heights: blockHeights,
|
|
243
|
+
};
|
|
244
|
+
console.info(`Incremental block cache: ${stats.hits} hit(s), ${stats.misses} miss(es), firstDirtyBlock=${firstDirtyBlock}, size=${blockCache.size}`);
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
console.info(`Full render mode: ${stats.misses} block(s) recomputed`);
|
|
248
|
+
}
|
|
105
249
|
console.log("Position calculations are completed.");
|
|
106
250
|
return layouts;
|
|
107
251
|
}
|
package/dist/Elem.js
CHANGED
|
@@ -354,12 +354,13 @@ function bind(t, bindings) {
|
|
|
354
354
|
return result;
|
|
355
355
|
}
|
|
356
356
|
function instantiate(e, section, fields, bindings) {
|
|
357
|
+
var _a;
|
|
357
358
|
e = bind(e, bindings);
|
|
358
359
|
if (!e.is_ref) {
|
|
359
360
|
return e;
|
|
360
361
|
}
|
|
361
362
|
const itemType = fields.find((f) => f.name === e.item);
|
|
362
|
-
if (itemType.type.tag === "MarkdownString") {
|
|
363
|
+
if (((_a = itemType === null || itemType === void 0 ? void 0 : itemType.type) === null || _a === void 0 ? void 0 : _a.tag) === "MarkdownString") {
|
|
363
364
|
e.is_markdown = true;
|
|
364
365
|
}
|
|
365
366
|
const text = section.fields[e.item];
|
package/dist/Layout.d.ts
CHANGED
|
@@ -43,6 +43,7 @@ export type RenderedElem = Elem.t & {
|
|
|
43
43
|
};
|
|
44
44
|
export type RenderedLayout = (RenderedStack | RenderedRow | RenderedElem) & {
|
|
45
45
|
path?: ElementPath;
|
|
46
|
+
flow_offset_y?: number;
|
|
46
47
|
};
|
|
47
48
|
export declare function default_(tag: string): Stack.t | Row.t | Elem.t;
|
|
48
49
|
export declare function empty(): Layout;
|
package/dist/Layout.js
CHANGED
|
@@ -261,25 +261,27 @@ function computeTextboxPositions(l, top_left, font_dict) {
|
|
|
261
261
|
top_left = top_left.move_y_by(row.margin.top).move_x_by(row.margin.left);
|
|
262
262
|
const originalTopLeft = top_left;
|
|
263
263
|
let per_elem_space = 0.0;
|
|
264
|
+
const rowElementsWidth = Row.elementsWidth(row);
|
|
264
265
|
switch (row.alignment) {
|
|
265
266
|
case "Center":
|
|
266
|
-
top_left = top_left.move_x_by((Width.get_fixed_unchecked(row.width) -
|
|
267
|
-
2.0);
|
|
267
|
+
top_left = top_left.move_x_by((Width.get_fixed_unchecked(row.width) - rowElementsWidth) / 2.0);
|
|
268
268
|
break;
|
|
269
269
|
case "Right":
|
|
270
|
-
top_left = top_left.move_x_by(Width.get_fixed_unchecked(row.width) -
|
|
270
|
+
top_left = top_left.move_x_by(Width.get_fixed_unchecked(row.width) - rowElementsWidth);
|
|
271
271
|
break;
|
|
272
272
|
case "Justified":
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
(row.
|
|
273
|
+
if (row.elements.length > 1) {
|
|
274
|
+
per_elem_space =
|
|
275
|
+
(Width.get_fixed_unchecked(row.width) - rowElementsWidth) /
|
|
276
|
+
(row.elements.length - 1);
|
|
277
|
+
}
|
|
276
278
|
break;
|
|
277
279
|
}
|
|
278
280
|
const renderedElements = [];
|
|
279
281
|
for (const element of row.elements) {
|
|
280
282
|
const result = computeTextboxPositions(element, top_left, font_dict);
|
|
281
283
|
depth = Math.max(depth, result.depth);
|
|
282
|
-
top_left = top_left.move_x_by(
|
|
284
|
+
top_left = top_left.move_x_by(Row.elementOuterWidth(element) + per_elem_space);
|
|
283
285
|
renderedElements.push(result.renderedLayout);
|
|
284
286
|
}
|
|
285
287
|
depth += row.margin.bottom;
|
|
@@ -304,15 +306,16 @@ function computeTextboxPositions(l, top_left, font_dict) {
|
|
|
304
306
|
.move_y_by(elem.margin.top)
|
|
305
307
|
.move_x_by(elem.margin.left);
|
|
306
308
|
let line = 1;
|
|
307
|
-
let cursor =
|
|
309
|
+
let cursor = 0;
|
|
310
|
+
const maxLineWidth = Width.get_fixed_unchecked(elem.width) - elem.margin.right;
|
|
311
|
+
const wrapTolerance = 1e-6;
|
|
308
312
|
elem.spans.forEach((span) => {
|
|
309
|
-
if (cursor
|
|
310
|
-
Width.get_fixed_unchecked(elem.width) - elem.margin.right ||
|
|
313
|
+
if (cursor + span.width > maxLineWidth + wrapTolerance ||
|
|
311
314
|
span.text === "\n\n") {
|
|
312
|
-
cursor =
|
|
315
|
+
cursor = 0;
|
|
313
316
|
line += 1;
|
|
314
317
|
}
|
|
315
|
-
span.bbox = new Box_1.Box(new Point_1.Point(cursor
|
|
318
|
+
span.bbox = new Box_1.Box(new Point_1.Point(cursor, (line - 1) * height), new Point_1.Point(cursor + span.width, line * height));
|
|
316
319
|
span.line = line;
|
|
317
320
|
cursor += span.width;
|
|
318
321
|
});
|
package/dist/PdfLayout.js
CHANGED
|
@@ -32,7 +32,9 @@ const AnyLayout_1 = require("./AnyLayout");
|
|
|
32
32
|
const pdfkit_1 = __importDefault(require("pdfkit"));
|
|
33
33
|
const Resume = __importStar(require("./Resume"));
|
|
34
34
|
const _1 = require(".");
|
|
35
|
+
const Box_1 = require("./Box");
|
|
35
36
|
const render = async ({ resume_name, resume, data_schemas, layout_schemas, resume_layout, bindings, storage, fontDict, }) => {
|
|
37
|
+
var _a;
|
|
36
38
|
let start_time = Date.now();
|
|
37
39
|
if (!resume && !resume_name) {
|
|
38
40
|
throw "Rendering requires either resume_name or resume";
|
|
@@ -95,9 +97,12 @@ const render = async ({ resume_name, resume, data_schemas, layout_schemas, resum
|
|
|
95
97
|
fontDict: fontDict,
|
|
96
98
|
};
|
|
97
99
|
for (const layout of layouts) {
|
|
98
|
-
(
|
|
99
|
-
tracker
|
|
100
|
-
|
|
100
|
+
const flowOffset = (_a = layout.flow_offset_y) !== null && _a !== void 0 ? _a : tracker.height;
|
|
101
|
+
(0, exports.renderSectionLayout)(layout, { ...tracker, height: flowOffset });
|
|
102
|
+
if (layout.flow_offset_y === undefined) {
|
|
103
|
+
tracker.height +=
|
|
104
|
+
layout.bounding_box.height() + layout.margin.top + layout.margin.bottom;
|
|
105
|
+
}
|
|
101
106
|
}
|
|
102
107
|
console.log("Rendering is completed. Saving the document...");
|
|
103
108
|
console.log("Document is saved to output.pdf");
|
|
@@ -122,20 +127,38 @@ const getPageContainer = (page, tracker) => {
|
|
|
122
127
|
return tracker.pageContainer;
|
|
123
128
|
};
|
|
124
129
|
const mergeSpans = (spans) => {
|
|
130
|
+
if (spans.length === 0) {
|
|
131
|
+
return [];
|
|
132
|
+
}
|
|
133
|
+
const firstSpan = spans[0];
|
|
134
|
+
if (!firstSpan) {
|
|
135
|
+
return [];
|
|
136
|
+
}
|
|
125
137
|
const merged_spans = [];
|
|
126
|
-
let currentSpan =
|
|
138
|
+
let currentSpan = firstSpan;
|
|
127
139
|
for (let i = 1; i < spans.length; i++) {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
currentSpan.bbox.
|
|
140
|
+
const nextSpan = spans[i];
|
|
141
|
+
if (!nextSpan) {
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
const hasBothBBoxes = Boolean(currentSpan.bbox && nextSpan.bbox);
|
|
145
|
+
if (hasBothBBoxes &&
|
|
146
|
+
currentSpan.bbox.top_left.y === nextSpan.bbox.top_left.y &&
|
|
147
|
+
currentSpan.font === nextSpan.font &&
|
|
148
|
+
currentSpan.is_code === nextSpan.is_code &&
|
|
149
|
+
currentSpan.is_bold === nextSpan.is_bold &&
|
|
150
|
+
currentSpan.is_italic === nextSpan.is_italic) {
|
|
151
|
+
currentSpan = {
|
|
152
|
+
...currentSpan,
|
|
153
|
+
text: currentSpan.text + nextSpan.text,
|
|
154
|
+
bbox: currentSpan.bbox && nextSpan.bbox
|
|
155
|
+
? new Box_1.Box(currentSpan.bbox.top_left, nextSpan.bbox.bottom_right)
|
|
156
|
+
: currentSpan.bbox,
|
|
157
|
+
};
|
|
135
158
|
}
|
|
136
159
|
else {
|
|
137
160
|
merged_spans.push(currentSpan);
|
|
138
|
-
currentSpan =
|
|
161
|
+
currentSpan = nextSpan;
|
|
139
162
|
}
|
|
140
163
|
}
|
|
141
164
|
merged_spans.push(currentSpan);
|
package/dist/Row.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ export declare function from(w: Optional<Row>): Row;
|
|
|
17
17
|
export declare function row(elements: Layout.t[], margin: Margin.t, alignment: Alignment.t, width: Width.t, is_frozen: boolean, is_fill: boolean): Row;
|
|
18
18
|
export declare function default_(): Row;
|
|
19
19
|
export declare function elementsWidth(r: Row): number;
|
|
20
|
+
export declare function elementOuterWidth(e: Layout.t): number;
|
|
20
21
|
export declare function boundWidth(r: Row, width: number): Row;
|
|
21
22
|
export declare function scaleWidth(r: Row, w: number): Row;
|
|
22
23
|
export {};
|
package/dist/Row.js
CHANGED
|
@@ -27,6 +27,7 @@ exports.from = from;
|
|
|
27
27
|
exports.row = row;
|
|
28
28
|
exports.default_ = default_;
|
|
29
29
|
exports.elementsWidth = elementsWidth;
|
|
30
|
+
exports.elementOuterWidth = elementOuterWidth;
|
|
30
31
|
exports.boundWidth = boundWidth;
|
|
31
32
|
exports.scaleWidth = scaleWidth;
|
|
32
33
|
const Margin = __importStar(require("./Margin"));
|
|
@@ -60,9 +61,10 @@ function default_() {
|
|
|
60
61
|
};
|
|
61
62
|
}
|
|
62
63
|
function elementsWidth(r) {
|
|
63
|
-
return r.elements
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
return r.elements.map(elementOuterWidth).reduce((a, b) => a + b, 0.0);
|
|
65
|
+
}
|
|
66
|
+
function elementOuterWidth(e) {
|
|
67
|
+
return e.margin.left + Width.get_fixed_unchecked(e.width) + e.margin.right;
|
|
66
68
|
}
|
|
67
69
|
function boundWidth(r, width) {
|
|
68
70
|
const bound = r.width.tag === "Absolute"
|
|
@@ -73,7 +75,32 @@ function boundWidth(r, width) {
|
|
|
73
75
|
if (bound === null) {
|
|
74
76
|
throw new Error("Cannot bound width of non-unitized widths!");
|
|
75
77
|
}
|
|
76
|
-
|
|
78
|
+
const fixedWidths = r.elements.map((e) => {
|
|
79
|
+
switch (e.width.tag) {
|
|
80
|
+
case "Fill":
|
|
81
|
+
return null;
|
|
82
|
+
case "Absolute":
|
|
83
|
+
return Math.min(e.width.value, bound);
|
|
84
|
+
case "Percent":
|
|
85
|
+
// Row children are usually scaled before bounding, but this keeps
|
|
86
|
+
// direct boundWidth() calls stable if Percent widths appear.
|
|
87
|
+
return Math.min((e.width.value * bound) / 100.0, bound);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
const totalFixedOuterWidth = fixedWidths.reduce((acc, next, index) => next === null
|
|
91
|
+
? acc
|
|
92
|
+
: acc + r.elements[index].margin.left + next + r.elements[index].margin.right, 0);
|
|
93
|
+
const fillElementCount = fixedWidths.filter((next) => next === null).length;
|
|
94
|
+
const totalFillMargins = fixedWidths.reduce((acc, next, index) => next === null
|
|
95
|
+
? acc +
|
|
96
|
+
r.elements[index].margin.left +
|
|
97
|
+
r.elements[index].margin.right
|
|
98
|
+
: acc, 0);
|
|
99
|
+
const fillWidth = fillElementCount > 0
|
|
100
|
+
? Math.max(0, bound - totalFixedOuterWidth - totalFillMargins) /
|
|
101
|
+
fillElementCount
|
|
102
|
+
: 0;
|
|
103
|
+
return row(r.elements.map((e, index) => { var _a; return Layout.boundWidth(e, (_a = fixedWidths[index]) !== null && _a !== void 0 ? _a : fillWidth); }), r.margin, r.alignment, Width.absolute(bound), r.is_frozen, Width.is_fill(r.width));
|
|
77
104
|
}
|
|
78
105
|
function scaleWidth(r, w) {
|
|
79
106
|
return (0, Utils_1.with_)(r, {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cvdl-ts",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.27",
|
|
4
4
|
"description": "Typescript Implementation of CVDL Compiler",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -24,6 +24,8 @@
|
|
|
24
24
|
"scripts": {
|
|
25
25
|
"build": "tsc",
|
|
26
26
|
"start": "ts-node src/index.ts",
|
|
27
|
-
"cli": "ts-node src/cli.ts"
|
|
27
|
+
"cli": "ts-node src/cli.ts",
|
|
28
|
+
"bench:incremental": "npm run build && node scripts/benchmark_incremental.cjs",
|
|
29
|
+
"bench:incremental:full": "npm run build && BENCH_PROFILE=full node scripts/benchmark_incremental.cjs"
|
|
28
30
|
}
|
|
29
31
|
}
|