@boxpdf/html-writer 0.1.16 → 0.1.17
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/index.cjs +33 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +33 -11
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -16,7 +16,7 @@ function dominantTextColor(lines) {
|
|
|
16
16
|
}
|
|
17
17
|
return [...counts].sort((left, right) => right[1] - left[1])[0]?.[0] ?? "#000000";
|
|
18
18
|
}
|
|
19
|
-
function semanticTextHtml(text, lines, defaultColor) {
|
|
19
|
+
function semanticTextHtml(text, lines, defaultColor, preserveWeight = true) {
|
|
20
20
|
const ranges = [];
|
|
21
21
|
let cursor = 0;
|
|
22
22
|
for (const span of lines.flatMap((line) => line.spans)) {
|
|
@@ -25,14 +25,25 @@ function semanticTextHtml(text, lines, defaultColor) {
|
|
|
25
25
|
if (start < 0) continue;
|
|
26
26
|
cursor = start + span.text.length;
|
|
27
27
|
const color = normalizedColor(span.color);
|
|
28
|
-
|
|
28
|
+
const bold = preserveWeight && /(?:bold|semibold|demi|medium|medi)/i.test(span.fontFamily ?? "");
|
|
29
|
+
const italic = /(?:italic|oblique|slanted|slant|ital)/i.test(span.fontFamily ?? "");
|
|
30
|
+
const nondefaultColor = color && color !== defaultColor ? color : void 0;
|
|
31
|
+
if (nondefaultColor || bold || italic) {
|
|
32
|
+
ranges.push({
|
|
33
|
+
start,
|
|
34
|
+
end: cursor,
|
|
35
|
+
...nondefaultColor ? { color: nondefaultColor } : {},
|
|
36
|
+
bold,
|
|
37
|
+
italic
|
|
38
|
+
});
|
|
39
|
+
}
|
|
29
40
|
}
|
|
30
41
|
const merged = mergeRanges(ranges, text);
|
|
31
42
|
let html = "";
|
|
32
43
|
let offset = 0;
|
|
33
44
|
for (const range of merged) {
|
|
34
45
|
html += escapeHtml(text.slice(offset, range.start));
|
|
35
|
-
html +=
|
|
46
|
+
html += styledHtml(text.slice(range.start, range.end), range);
|
|
36
47
|
offset = range.end;
|
|
37
48
|
}
|
|
38
49
|
return html + escapeHtml(text.slice(offset));
|
|
@@ -41,7 +52,7 @@ function mergeRanges(ranges, text) {
|
|
|
41
52
|
const merged = [];
|
|
42
53
|
for (const range of ranges) {
|
|
43
54
|
const previous = merged.at(-1);
|
|
44
|
-
if (previous && previous.color === range.color && /^\s*$/.test(text.slice(previous.end, range.start))) {
|
|
55
|
+
if (previous && previous.color === range.color && previous.bold === range.bold && previous.italic === range.italic && /^\s*$/.test(text.slice(previous.end, range.start))) {
|
|
45
56
|
previous.end = range.end;
|
|
46
57
|
} else {
|
|
47
58
|
merged.push({ ...range });
|
|
@@ -49,6 +60,13 @@ function mergeRanges(ranges, text) {
|
|
|
49
60
|
}
|
|
50
61
|
return merged;
|
|
51
62
|
}
|
|
63
|
+
function styledHtml(value, range) {
|
|
64
|
+
let html = escapeHtml(value);
|
|
65
|
+
if (range.color) html = `<span style="color:${range.color}">${html}</span>`;
|
|
66
|
+
if (range.italic) html = `<em>${html}</em>`;
|
|
67
|
+
if (range.bold) html = `<strong>${html}</strong>`;
|
|
68
|
+
return html;
|
|
69
|
+
}
|
|
52
70
|
function normalizedColor(value) {
|
|
53
71
|
if (!value || !/^#[\da-f]{6}$/i.test(value)) return void 0;
|
|
54
72
|
const color = value.toLowerCase();
|
|
@@ -342,7 +360,9 @@ async function writeSemanticDocument(pages, write, lookaheadPages) {
|
|
|
342
360
|
await flushPendingParagraph();
|
|
343
361
|
if (employmentOpen && block.type !== "list") await closeEmployment();
|
|
344
362
|
if (!contentStarted && !headerOpen && block.type === "heading" && block.level === 1) {
|
|
345
|
-
await write(
|
|
363
|
+
await write(
|
|
364
|
+
`<header><h1>${semanticTextHtml(block.text, block.lines, defaultColor, false)}</h1>`
|
|
365
|
+
);
|
|
346
366
|
headerOpen = true;
|
|
347
367
|
continue;
|
|
348
368
|
}
|
|
@@ -357,7 +377,7 @@ async function writeSemanticDocument(pages, write, lookaheadPages) {
|
|
|
357
377
|
}
|
|
358
378
|
if (block.type === "heading" && !headerHasParagraph && (block.level === 1 || block.text.trimStart().startsWith("#") || block.level === 4 && nextBlock?.type === "paragraph" && isContactBlock(nextBlock))) {
|
|
359
379
|
await write(
|
|
360
|
-
`<h${block.level}>${semanticTextHtml(block.text, block.lines, defaultColor)}</h${block.level}>`
|
|
380
|
+
`<h${block.level}>${semanticTextHtml(block.text, block.lines, defaultColor, false)}</h${block.level}>`
|
|
361
381
|
);
|
|
362
382
|
continue;
|
|
363
383
|
}
|
|
@@ -395,7 +415,7 @@ async function writeSemanticDocument(pages, write, lookaheadPages) {
|
|
|
395
415
|
const level = contentStarted && block.level === 1 ? 2 : block.level;
|
|
396
416
|
await closeSections(level);
|
|
397
417
|
await write(
|
|
398
|
-
`<section data-level="${level}"><h${level}>${semanticTextHtml(block.text, block.lines, defaultColor)}</h${level}>`
|
|
418
|
+
`<section data-level="${level}"><h${level}>${semanticTextHtml(block.text, block.lines, defaultColor, false)}</h${level}>`
|
|
399
419
|
);
|
|
400
420
|
sectionLevels.push(level);
|
|
401
421
|
continue;
|
|
@@ -564,7 +584,7 @@ function financialSummaryRow(entry, columns) {
|
|
|
564
584
|
}
|
|
565
585
|
function semanticBlockHtml(block, defaultColor = "#000000") {
|
|
566
586
|
if (block.type === "heading")
|
|
567
|
-
return `<h${block.level}>${semanticTextHtml(block.text, block.lines, defaultColor)}</h${block.level}>`;
|
|
587
|
+
return `<h${block.level}>${semanticTextHtml(block.text, block.lines, defaultColor, false)}</h${block.level}>`;
|
|
568
588
|
if (block.type === "paragraph")
|
|
569
589
|
return `<p>${semanticTextHtml(block.text, block.lines, defaultColor)}</p>`;
|
|
570
590
|
if (block.type === "preformatted") return `<pre>${escapeHtml3(block.text)}</pre>`;
|
|
@@ -589,7 +609,7 @@ function semanticBlockHtml(block, defaultColor = "#000000") {
|
|
|
589
609
|
return `<section><h3>${escapeHtml3(block.role)}</h3><p>${escapeHtml3(block.organization)}</p><p>${escapeHtml3(block.date)}</p></section>`;
|
|
590
610
|
}
|
|
591
611
|
const tag = block.ordered ? "ol" : "ul";
|
|
592
|
-
return `<${tag}>${block.items.map((item) => `<li>${
|
|
612
|
+
return `<${tag}>${block.items.map((item) => `<li>${semanticTextHtml(item.text, item.lines, defaultColor)}</li>`).join("")}</${tag}>`;
|
|
593
613
|
}
|
|
594
614
|
function semanticBlockY(block) {
|
|
595
615
|
const lines = block.type === "list" ? block.items.flatMap((item) => item.lines) : block.lines;
|
|
@@ -862,7 +882,7 @@ async function writeFlowPage(page, write) {
|
|
|
862
882
|
if (block.type === "table") await write(tableToHtml(block.table));
|
|
863
883
|
else if (block.type === "heading") {
|
|
864
884
|
await write(
|
|
865
|
-
`<h${block.level}>${semanticTextHtml(block.text, block.lines, defaultColor)}</h${block.level}>`
|
|
885
|
+
`<h${block.level}>${semanticTextHtml(block.text, block.lines, defaultColor, false)}</h${block.level}>`
|
|
866
886
|
);
|
|
867
887
|
} else if (block.type === "paragraph") {
|
|
868
888
|
await write(
|
|
@@ -901,7 +921,9 @@ async function writeFlowPage(page, write) {
|
|
|
901
921
|
} else {
|
|
902
922
|
const tag = block.ordered ? "ol" : "ul";
|
|
903
923
|
await write(`<${tag}>`);
|
|
904
|
-
for (const item of block.items)
|
|
924
|
+
for (const item of block.items) {
|
|
925
|
+
await write(`<li>${semanticTextHtml(item.text, item.lines, defaultColor)}</li>`);
|
|
926
|
+
}
|
|
905
927
|
await write(`</${tag}>`);
|
|
906
928
|
}
|
|
907
929
|
}
|