dom-docx 0.1.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/API.md +533 -0
- package/LICENSE +21 -0
- package/README.md +236 -0
- package/dist/browser.d.ts +34 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +35 -0
- package/dist/browser.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +118 -0
- package/dist/cli.js.map +1 -0
- package/dist/converter/bordered-block.d.ts +54 -0
- package/dist/converter/bordered-block.d.ts.map +1 -0
- package/dist/converter/bordered-block.js +124 -0
- package/dist/converter/bordered-block.js.map +1 -0
- package/dist/converter/build-docx.d.ts +46 -0
- package/dist/converter/build-docx.d.ts.map +1 -0
- package/dist/converter/build-docx.js +161 -0
- package/dist/converter/build-docx.js.map +1 -0
- package/dist/converter/computed-style-snapshot.browser.js +73 -0
- package/dist/converter/computed-style-snapshot.d.ts +10 -0
- package/dist/converter/computed-style-snapshot.d.ts.map +1 -0
- package/dist/converter/computed-style-snapshot.js +78 -0
- package/dist/converter/computed-style-snapshot.js.map +1 -0
- package/dist/converter/constants.d.ts +51 -0
- package/dist/converter/constants.d.ts.map +1 -0
- package/dist/converter/constants.js +163 -0
- package/dist/converter/constants.js.map +1 -0
- package/dist/converter/css.d.ts +112 -0
- package/dist/converter/css.d.ts.map +1 -0
- package/dist/converter/css.js +621 -0
- package/dist/converter/css.js.map +1 -0
- package/dist/converter/flex.d.ts +59 -0
- package/dist/converter/flex.d.ts.map +1 -0
- package/dist/converter/flex.js +252 -0
- package/dist/converter/flex.js.map +1 -0
- package/dist/converter/image.d.ts +38 -0
- package/dist/converter/image.d.ts.map +1 -0
- package/dist/converter/image.js +159 -0
- package/dist/converter/image.js.map +1 -0
- package/dist/converter/inline.d.ts +18 -0
- package/dist/converter/inline.d.ts.map +1 -0
- package/dist/converter/inline.js +213 -0
- package/dist/converter/inline.js.map +1 -0
- package/dist/converter/ooxml-patch.d.ts +23 -0
- package/dist/converter/ooxml-patch.d.ts.map +1 -0
- package/dist/converter/ooxml-patch.js +54 -0
- package/dist/converter/ooxml-patch.js.map +1 -0
- package/dist/converter/style-path.d.ts +4 -0
- package/dist/converter/style-path.d.ts.map +1 -0
- package/dist/converter/style-path.js +17 -0
- package/dist/converter/style-path.js.map +1 -0
- package/dist/converter/style-resolver-node.d.ts +7 -0
- package/dist/converter/style-resolver-node.d.ts.map +1 -0
- package/dist/converter/style-resolver-node.js +26 -0
- package/dist/converter/style-resolver-node.js.map +1 -0
- package/dist/converter/style-resolver.d.ts +24 -0
- package/dist/converter/style-resolver.d.ts.map +1 -0
- package/dist/converter/style-resolver.js +122 -0
- package/dist/converter/style-resolver.js.map +1 -0
- package/dist/converter/svg.d.ts +11 -0
- package/dist/converter/svg.d.ts.map +1 -0
- package/dist/converter/svg.js +116 -0
- package/dist/converter/svg.js.map +1 -0
- package/dist/converter/table.d.ts +8 -0
- package/dist/converter/table.d.ts.map +1 -0
- package/dist/converter/table.js +745 -0
- package/dist/converter/table.js.map +1 -0
- package/dist/converter/text-metrics.d.ts +17 -0
- package/dist/converter/text-metrics.d.ts.map +1 -0
- package/dist/converter/text-metrics.js +51 -0
- package/dist/converter/text-metrics.js.map +1 -0
- package/dist/converter/types.d.ts +82 -0
- package/dist/converter/types.d.ts.map +1 -0
- package/dist/converter/types.js +9 -0
- package/dist/converter/types.js.map +1 -0
- package/dist/converter/visitor.d.ts +11 -0
- package/dist/converter/visitor.d.ts.map +1 -0
- package/dist/converter/visitor.js +910 -0
- package/dist/converter/visitor.js.map +1 -0
- package/dist/converter.d.ts +28 -0
- package/dist/converter.d.ts.map +1 -0
- package/dist/converter.js +44 -0
- package/dist/converter.js.map +1 -0
- package/dist/html-wrap.d.ts +3 -0
- package/dist/html-wrap.d.ts.map +1 -0
- package/dist/html-wrap.js +26 -0
- package/dist/html-wrap.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/examples/README.md +39 -0
- package/examples/balance-sheet/compare_side_by_side.png +0 -0
- package/examples/balance-sheet/input.html +41 -0
- package/examples/balance-sheet/output.docx +0 -0
- package/examples/balance-sheet/preview.png +0 -0
- package/examples/invoice/compare_side_by_side.png +0 -0
- package/examples/invoice/input.html +88 -0
- package/examples/invoice/logo.png +0 -0
- package/examples/invoice/output.docx +0 -0
- package/examples/invoice/preview.png +0 -0
- package/examples/javascript-essay/compare_side_by_side.png +0 -0
- package/examples/javascript-essay/input.html +39 -0
- package/examples/javascript-essay/output.docx +0 -0
- package/examples/javascript-essay/preview.png +0 -0
- package/examples/product-launch-brief/compare_side_by_side.png +0 -0
- package/examples/product-launch-brief/input.html +120 -0
- package/examples/product-launch-brief/output.docx +0 -0
- package/examples/product-launch-brief/preview.png +0 -0
- package/examples/quarterly-financials/compare_side_by_side.png +0 -0
- package/examples/quarterly-financials/input.html +27 -0
- package/examples/quarterly-financials/output.docx +0 -0
- package/examples/quarterly-financials/preview.png +0 -0
- package/examples/react-dashboard/compare_side_by_side.png +0 -0
- package/examples/react-dashboard/input.html +1 -0
- package/examples/react-dashboard/output.docx +0 -0
- package/examples/react-dashboard/preview.html +107 -0
- package/examples/react-dashboard/preview.png +0 -0
- package/examples/regional-sales-dashboard/compare_side_by_side.png +0 -0
- package/examples/regional-sales-dashboard/input.html +129 -0
- package/examples/regional-sales-dashboard/output.docx +0 -0
- package/examples/regional-sales-dashboard/preview.png +0 -0
- package/examples/sales-contract/compare_side_by_side.png +0 -0
- package/examples/sales-contract/input.html +68 -0
- package/examples/sales-contract/output.docx +0 -0
- package/examples/sales-contract/preview.png +0 -0
- package/examples/sprint-retrospective/compare_side_by_side.png +0 -0
- package/examples/sprint-retrospective/input.html +51 -0
- package/examples/sprint-retrospective/output.docx +0 -0
- package/examples/sprint-retrospective/preview.png +0 -0
- package/package.json +108 -0
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { ExternalHyperlink, TextRun, UnderlineType, } from "docx";
|
|
2
|
+
import { BODY_FONT_HALF_POINTS, HYPERLINK_COLOR } from "./constants.js";
|
|
3
|
+
import { imageRunFromElement } from "./image.js";
|
|
4
|
+
import { cssToInlineRunTypography, isBlockElement, isHiddenElement, runShadingForFill, typographyFromBlockElement, } from "./css.js";
|
|
5
|
+
import { INLINE_STYLE_RESOLVER } from "./style-resolver.js";
|
|
6
|
+
function mergeTypography(base, overlay) {
|
|
7
|
+
return {
|
|
8
|
+
bold: overlay.bold ?? base.bold,
|
|
9
|
+
italics: overlay.italics ?? base.italics,
|
|
10
|
+
underline: overlay.underline ?? base.underline,
|
|
11
|
+
allCaps: overlay.allCaps ?? base.allCaps,
|
|
12
|
+
characterSpacing: overlay.characterSpacing ?? base.characterSpacing,
|
|
13
|
+
color: overlay.color ?? base.color,
|
|
14
|
+
shading: overlay.shading ?? base.shading,
|
|
15
|
+
style: overlay.style ?? base.style,
|
|
16
|
+
fontSize: overlay.fontSize ?? base.fontSize,
|
|
17
|
+
font: overlay.font ?? base.font,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function tagTypographyFlags(tag) {
|
|
21
|
+
switch (tag) {
|
|
22
|
+
case "strong":
|
|
23
|
+
case "b":
|
|
24
|
+
return { bold: true };
|
|
25
|
+
case "em":
|
|
26
|
+
case "i":
|
|
27
|
+
return { italics: true };
|
|
28
|
+
case "u":
|
|
29
|
+
return { underline: true };
|
|
30
|
+
case "code":
|
|
31
|
+
// Font size inherits from the surrounding text (matches browsers).
|
|
32
|
+
// Consolas over Courier New: full-weight like the browser's monospace.
|
|
33
|
+
return { font: "Consolas" };
|
|
34
|
+
case "a":
|
|
35
|
+
return { underline: true, style: "Hyperlink" };
|
|
36
|
+
default:
|
|
37
|
+
return {};
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
export function typographyToTextRunOptions(style, defaultSize = BODY_FONT_HALF_POINTS) {
|
|
41
|
+
const defaultColor = style.style === "Hyperlink" ? HYPERLINK_COLOR : "111111";
|
|
42
|
+
const options = {
|
|
43
|
+
size: style.fontSize ?? defaultSize,
|
|
44
|
+
color: style.color ?? defaultColor,
|
|
45
|
+
};
|
|
46
|
+
if (style.bold)
|
|
47
|
+
options.bold = true;
|
|
48
|
+
if (style.italics)
|
|
49
|
+
options.italics = true;
|
|
50
|
+
if (style.allCaps)
|
|
51
|
+
options.allCaps = true;
|
|
52
|
+
if (style.characterSpacing)
|
|
53
|
+
options.characterSpacing = style.characterSpacing;
|
|
54
|
+
if (style.underline) {
|
|
55
|
+
options.underline = {
|
|
56
|
+
type: UnderlineType.SINGLE,
|
|
57
|
+
...(style.style === "Hyperlink" ? { color: style.color ?? HYPERLINK_COLOR } : {}),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
if (style.font)
|
|
61
|
+
options.font = style.font;
|
|
62
|
+
if (style.style)
|
|
63
|
+
options.style = style.style;
|
|
64
|
+
if (style.shading?.fill) {
|
|
65
|
+
options.shading = runShadingForFill(style.shading.fill);
|
|
66
|
+
}
|
|
67
|
+
return options;
|
|
68
|
+
}
|
|
69
|
+
const RUN_TEXT = new WeakMap();
|
|
70
|
+
function detachTrailingSpaces(runs, style, defaultSize) {
|
|
71
|
+
if (runs.length === 0)
|
|
72
|
+
return;
|
|
73
|
+
const last = runs[runs.length - 1];
|
|
74
|
+
if (!(last instanceof TextRun))
|
|
75
|
+
return;
|
|
76
|
+
const text = RUN_TEXT.get(last) ?? "";
|
|
77
|
+
const match = text.match(/^(.*?)( +)$/);
|
|
78
|
+
if (!match || !match[1])
|
|
79
|
+
return;
|
|
80
|
+
runs[runs.length - 1] = textRun(match[1], style, defaultSize);
|
|
81
|
+
runs.push(textRun(match[2], style, defaultSize));
|
|
82
|
+
}
|
|
83
|
+
function textRun(text, style, defaultSize = BODY_FONT_HALF_POINTS) {
|
|
84
|
+
const run = new TextRun({ text, ...typographyToTextRunOptions(style, defaultSize) });
|
|
85
|
+
RUN_TEXT.set(run, text);
|
|
86
|
+
return run;
|
|
87
|
+
}
|
|
88
|
+
function isElement(node) {
|
|
89
|
+
return node.type === "tag";
|
|
90
|
+
}
|
|
91
|
+
function prependPendingSpace(text, inherited, state) {
|
|
92
|
+
if (!state.needsSpaceBeforeNext || !text || text.startsWith(" ")) {
|
|
93
|
+
state.needsSpaceBeforeNext = false;
|
|
94
|
+
return text;
|
|
95
|
+
}
|
|
96
|
+
state.needsSpaceBeforeNext = false;
|
|
97
|
+
return ` ${text}`;
|
|
98
|
+
}
|
|
99
|
+
function markPendingSpace(state, runs) {
|
|
100
|
+
if (state.afterLineBreak)
|
|
101
|
+
return;
|
|
102
|
+
if (state.leadingTextDone && runs.length > 0) {
|
|
103
|
+
state.needsSpaceBeforeNext = true;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
export function collectInlineRunsFromNodes(childNodes, inherited = {}, state = { leadingTextDone: false, needsSpaceBeforeNext: false, afterLineBreak: false }, styleResolver = INLINE_STYLE_RESOLVER, defaultSize = BODY_FONT_HALF_POINTS) {
|
|
107
|
+
const runs = [];
|
|
108
|
+
for (const node of childNodes) {
|
|
109
|
+
if (node.type === "text") {
|
|
110
|
+
const raw = node.data ?? "";
|
|
111
|
+
let normalized = raw.replace(/\s+/g, " ");
|
|
112
|
+
if (state.afterLineBreak) {
|
|
113
|
+
// Pretty-printed HTML adds newline+indent after `<br>` — browsers drop that,
|
|
114
|
+
// but a literal `<br> Line two` space after the break should stay.
|
|
115
|
+
if (/^\s*[\r\n]/.test(raw)) {
|
|
116
|
+
normalized = normalized.trimStart();
|
|
117
|
+
}
|
|
118
|
+
if (!normalized)
|
|
119
|
+
continue;
|
|
120
|
+
state.afterLineBreak = false;
|
|
121
|
+
state.leadingTextDone = true;
|
|
122
|
+
}
|
|
123
|
+
else if (!state.leadingTextDone) {
|
|
124
|
+
normalized = normalized.trimStart();
|
|
125
|
+
if (normalized)
|
|
126
|
+
state.leadingTextDone = true;
|
|
127
|
+
}
|
|
128
|
+
if (!normalized.trim()) {
|
|
129
|
+
markPendingSpace(state, runs);
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
normalized = prependPendingSpace(normalized, inherited, state);
|
|
133
|
+
if (normalized.startsWith(" ") && runs.length > 0) {
|
|
134
|
+
runs.push(textRun(" ", inherited, defaultSize));
|
|
135
|
+
normalized = normalized.trimStart();
|
|
136
|
+
}
|
|
137
|
+
runs.push(textRun(normalized, inherited, defaultSize));
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
if (!isElement(node))
|
|
141
|
+
continue;
|
|
142
|
+
if (isHiddenElement(node, styleResolver))
|
|
143
|
+
continue;
|
|
144
|
+
const tag = node.name.toLowerCase();
|
|
145
|
+
if (tag === "br") {
|
|
146
|
+
state.needsSpaceBeforeNext = false;
|
|
147
|
+
state.afterLineBreak = true;
|
|
148
|
+
runs.push(new TextRun({
|
|
149
|
+
break: 1,
|
|
150
|
+
size: inherited.fontSize ?? defaultSize,
|
|
151
|
+
}));
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
if (tag === "img") {
|
|
155
|
+
const image = imageRunFromElement(node);
|
|
156
|
+
if (image) {
|
|
157
|
+
runs.push(image);
|
|
158
|
+
}
|
|
159
|
+
else if (node.attribs?.alt) {
|
|
160
|
+
runs.push(textRun(node.attribs.alt, inherited, defaultSize));
|
|
161
|
+
}
|
|
162
|
+
state.needsSpaceBeforeNext = false;
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
if (state.needsSpaceBeforeNext && runs.length > 0) {
|
|
166
|
+
runs.push(textRun(" ", inherited, defaultSize));
|
|
167
|
+
state.needsSpaceBeforeNext = false;
|
|
168
|
+
}
|
|
169
|
+
if (state.afterLineBreak) {
|
|
170
|
+
state.afterLineBreak = false;
|
|
171
|
+
}
|
|
172
|
+
const cssTypography = cssToInlineRunTypography(styleResolver.getCss(node));
|
|
173
|
+
const typography = mergeTypography(mergeTypography(inherited, tagTypographyFlags(tag)), cssTypography);
|
|
174
|
+
if (tag === "a") {
|
|
175
|
+
const href = node.attribs?.href ?? "";
|
|
176
|
+
detachTrailingSpaces(runs, inherited, defaultSize);
|
|
177
|
+
const linkTypography = {
|
|
178
|
+
...typography,
|
|
179
|
+
color: cssTypography.color,
|
|
180
|
+
style: "Hyperlink",
|
|
181
|
+
};
|
|
182
|
+
const childRuns = collectInlineRunsFromNodes(node.children ?? [], {
|
|
183
|
+
...linkTypography,
|
|
184
|
+
underline: true,
|
|
185
|
+
}, state, styleResolver, defaultSize);
|
|
186
|
+
// Anchors with no inline content render as nothing in browsers (e.g. a
|
|
187
|
+
// link that only wrapped an image) — emitting the raw href is noise.
|
|
188
|
+
if (childRuns.length > 0) {
|
|
189
|
+
runs.push(new ExternalHyperlink({ link: href, children: childRuns }));
|
|
190
|
+
}
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
runs.push(...collectInlineRunsFromNodes(node.children ?? [], typography, state, styleResolver, defaultSize));
|
|
194
|
+
}
|
|
195
|
+
return runs;
|
|
196
|
+
}
|
|
197
|
+
export function hasDirectBlockChild(element, styleResolver = INLINE_STYLE_RESOLVER) {
|
|
198
|
+
return (element.children ?? []).some((node) => isElement(node) && isBlockElement(node, styleResolver));
|
|
199
|
+
}
|
|
200
|
+
export function getDirectBlockChildren(element, styleResolver = INLINE_STYLE_RESOLVER) {
|
|
201
|
+
return (element.children ?? []).filter((node) => isElement(node) && isBlockElement(node, styleResolver));
|
|
202
|
+
}
|
|
203
|
+
export function getInlineOrTextNodes(element, styleResolver = INLINE_STYLE_RESOLVER) {
|
|
204
|
+
return (element.children ?? []).filter((node) => {
|
|
205
|
+
if (node.type === "text")
|
|
206
|
+
return (node.data ?? "").trim().length > 0;
|
|
207
|
+
if (!isElement(node))
|
|
208
|
+
return false;
|
|
209
|
+
return !isBlockElement(node, styleResolver);
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
export { isBlockElement, typographyFromBlockElement };
|
|
213
|
+
//# sourceMappingURL=inline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inline.js","sourceRoot":"","sources":["../../src/converter/inline.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Post-pack OOXML tweaks for primitives the docx npm API does not expose.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* LibreOffice ignores tentative numbering levels and needs w:tab/@w:val="num"
|
|
6
|
+
* (not "left") for decimal list markers to appear in PDF export.
|
|
7
|
+
*/
|
|
8
|
+
export declare function patchNumberingXml(numberingXml: string): string;
|
|
9
|
+
/**
|
|
10
|
+
* Vertically center text inside shaded paragraphs that use EXACT line spacing
|
|
11
|
+
* to simulate block padding. LibreOffice PDF export paints spacing.before outside
|
|
12
|
+
* w:shd, so padding is folded into w:spacing/@w:line; w:textAlignment centers
|
|
13
|
+
* glyphs within that shaded band.
|
|
14
|
+
*/
|
|
15
|
+
export declare function patchShadedParagraphVerticalAlign(documentXml: string): string;
|
|
16
|
+
/**
|
|
17
|
+
* The docx library appends w:tblCellSpacing after w:tblLayout, but CT_TblPrBase
|
|
18
|
+
* requires it before w:tblInd/w:tblBorders (right after w:tblW/w:jc) — schema
|
|
19
|
+
* validation fails otherwise and Word may drop the spacing.
|
|
20
|
+
*/
|
|
21
|
+
export declare function patchTableCellSpacingOrder(documentXml: string): string;
|
|
22
|
+
export declare function patchDocumentXml(documentXml: string): string;
|
|
23
|
+
//# sourceMappingURL=ooxml-patch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ooxml-patch.d.ts","sourceRoot":"","sources":["../../src/converter/ooxml-patch.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAO9D;AAED;;;;;GAKG;AACH,wBAAgB,iCAAiC,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAY7E;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAatE;AAED,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE5D"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Post-pack OOXML tweaks for primitives the docx npm API does not expose.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* LibreOffice ignores tentative numbering levels and needs w:tab/@w:val="num"
|
|
6
|
+
* (not "left") for decimal list markers to appear in PDF export.
|
|
7
|
+
*/
|
|
8
|
+
export function patchNumberingXml(numberingXml) {
|
|
9
|
+
let xml = numberingXml.replace(/\s*w15:tentative="1"/g, "");
|
|
10
|
+
return xml.replace(/(<w:lvl[\s\S]*?<w:pPr>[\s\S]*?<w:tabs>\s*)<w:tab w:val="left"/g, '$1<w:tab w:val="num"');
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Vertically center text inside shaded paragraphs that use EXACT line spacing
|
|
14
|
+
* to simulate block padding. LibreOffice PDF export paints spacing.before outside
|
|
15
|
+
* w:shd, so padding is folded into w:spacing/@w:line; w:textAlignment centers
|
|
16
|
+
* glyphs within that shaded band.
|
|
17
|
+
*/
|
|
18
|
+
export function patchShadedParagraphVerticalAlign(documentXml) {
|
|
19
|
+
return documentXml.replace(/<w:pPr>([\s\S]*?)<\/w:pPr>/g, (full, inner) => {
|
|
20
|
+
// Shaded EXACT paragraphs (padding folded into the line) and AT_LEAST
|
|
21
|
+
// paragraphs (CSS line-height) both need glyphs centered in the line box:
|
|
22
|
+
// LO otherwise stacks ALL extra leading above the text, while browsers
|
|
23
|
+
// split it half above / half below.
|
|
24
|
+
const shadedExact = inner.includes("<w:shd") && inner.includes('w:lineRule="exact"');
|
|
25
|
+
const atLeastLine = inner.includes('w:lineRule="atLeast"');
|
|
26
|
+
if (!shadedExact && !atLeastLine)
|
|
27
|
+
return full;
|
|
28
|
+
if (inner.includes("<w:textAlignment"))
|
|
29
|
+
return full;
|
|
30
|
+
return `<w:pPr>${inner}<w:textAlignment w:val="center"/></w:pPr>`;
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The docx library appends w:tblCellSpacing after w:tblLayout, but CT_TblPrBase
|
|
35
|
+
* requires it before w:tblInd/w:tblBorders (right after w:tblW/w:jc) — schema
|
|
36
|
+
* validation fails otherwise and Word may drop the spacing.
|
|
37
|
+
*/
|
|
38
|
+
export function patchTableCellSpacingOrder(documentXml) {
|
|
39
|
+
return documentXml.replace(/<w:tblPr>([\s\S]*?)<\/w:tblPr>/g, (full, inner) => {
|
|
40
|
+
const spacing = inner.match(/<w:tblCellSpacing[^/]*\/>/);
|
|
41
|
+
if (!spacing)
|
|
42
|
+
return full;
|
|
43
|
+
const rest = inner.replace(spacing[0], "");
|
|
44
|
+
const anchor = rest.match(/<w:jc [^/]*\/>/) ?? rest.match(/<w:tblW [^/]*\/>/);
|
|
45
|
+
if (!anchor)
|
|
46
|
+
return `<w:tblPr>${spacing[0]}${rest}</w:tblPr>`;
|
|
47
|
+
const at = rest.indexOf(anchor[0]) + anchor[0].length;
|
|
48
|
+
return `<w:tblPr>${rest.slice(0, at)}${spacing[0]}${rest.slice(at)}</w:tblPr>`;
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
export function patchDocumentXml(documentXml) {
|
|
52
|
+
return patchTableCellSpacingOrder(patchShadedParagraphVerticalAlign(documentXml));
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=ooxml-patch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ooxml-patch.js","sourceRoot":"","sources":["../../src/converter/ooxml-patch.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,YAAoB;IACpD,IAAI,GAAG,GAAG,YAAY,CAAC,OAAO,CAAC,uBAAuB,EAAE,EAAE,CAAC,CAAC;IAE5D,OAAO,GAAG,CAAC,OAAO,CAChB,gEAAgE,EAChE,sBAAsB,CACvB,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iCAAiC,CAAC,WAAmB;IACnE,OAAO,WAAW,CAAC,OAAO,CAAC,6BAA6B,EAAE,CAAC,IAAI,EAAE,KAAa,EAAE,EAAE;QAChF,sEAAsE;QACtE,0EAA0E;QAC1E,uEAAuE;QACvE,oCAAoC;QACpC,MAAM,WAAW,GAAG,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC;QACrF,MAAM,WAAW,GAAG,KAAK,CAAC,QAAQ,CAAC,sBAAsB,CAAC,CAAC;QAC3D,IAAI,CAAC,WAAW,IAAI,CAAC,WAAW;YAAE,OAAO,IAAI,CAAC;QAC9C,IAAI,KAAK,CAAC,QAAQ,CAAC,kBAAkB,CAAC;YAAE,OAAO,IAAI,CAAC;QACpD,OAAO,UAAU,KAAK,2CAA2C,CAAC;IACpE,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,0BAA0B,CAAC,WAAmB;IAC5D,OAAO,WAAW,CAAC,OAAO,CACxB,iCAAiC,EACjC,CAAC,IAAI,EAAE,KAAa,EAAE,EAAE;QACtB,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC;QACzD,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC;QAC1B,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC3C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;QAC9E,IAAI,CAAC,MAAM;YAAE,OAAO,YAAY,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,YAAY,CAAC;QAC9D,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QACtD,OAAO,YAAY,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC;IACjF,CAAC,CACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,WAAmB;IAClD,OAAO,0BAA0B,CAAC,iCAAiC,CAAC,WAAW,CAAC,CAAC,CAAC;AACpF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"style-path.d.ts","sourceRoot":"","sources":["../../src/converter/style-path.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAW,OAAO,EAAE,MAAM,YAAY,CAAC;AAEnD,wEAAwE;AACxE,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAkBzD"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** Stable path for style lookup — must match browser batch resolver. */
|
|
2
|
+
export function elementStylePath(element) {
|
|
3
|
+
const parts = [];
|
|
4
|
+
let current = element;
|
|
5
|
+
while (current && current.name.toLowerCase() !== "body") {
|
|
6
|
+
const tagName = current.name.toLowerCase();
|
|
7
|
+
const parent = current.parent;
|
|
8
|
+
if (!parent || parent.type !== "tag")
|
|
9
|
+
break;
|
|
10
|
+
const siblings = (parent.children ?? []).filter((c) => c.type === "tag" && c.name.toLowerCase() === tagName);
|
|
11
|
+
const index = siblings.indexOf(current);
|
|
12
|
+
parts.unshift(`${tagName}[${index}]`);
|
|
13
|
+
current = parent;
|
|
14
|
+
}
|
|
15
|
+
return parts.join("/");
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=style-path.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"style-path.js","sourceRoot":"","sources":["../../src/converter/style-path.ts"],"names":[],"mappings":"AAEA,wEAAwE;AACxE,MAAM,UAAU,gBAAgB,CAAC,OAAgB;IAC/C,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,OAAO,GAAmB,OAAO,CAAC;IAEtC,OAAO,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,MAAM,EAAE,CAAC;QACxD,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;QAC3C,MAAM,MAAM,GAAG,OAAO,CAAC,MAAoC,CAAC;QAC5D,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,KAAK,KAAK;YAAE,MAAM;QAE5C,MAAM,QAAQ,GAAG,CAAC,MAAM,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,MAAM,CAC7C,CAAC,CAAU,EAAgB,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,OAAO,CACnF,CAAC;QACF,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACxC,KAAK,CAAC,OAAO,CAAC,GAAG,OAAO,IAAI,KAAK,GAAG,CAAC,CAAC;QACtC,OAAO,GAAG,MAAM,CAAC;IACnB,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACzB,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Browser, Page } from "playwright";
|
|
2
|
+
import type { ComputedStyleSnapshot } from "./computed-style-snapshot.js";
|
|
3
|
+
import { ComputedStyleResolver } from "./style-resolver.js";
|
|
4
|
+
export declare function snapshotComputedStyles(page: Page): Promise<ComputedStyleSnapshot[]>;
|
|
5
|
+
export declare function createComputedStyleResolver(html: string, browser: Browser): Promise<ComputedStyleResolver>;
|
|
6
|
+
export declare function computedStyleResolverFromPage(page: Page): Promise<ComputedStyleResolver>;
|
|
7
|
+
//# sourceMappingURL=style-resolver-node.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"style-resolver-node.d.ts","sourceRoot":"","sources":["../../src/converter/style-resolver-node.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAGhD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAC1E,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAQ5D,wBAAsB,sBAAsB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,qBAAqB,EAAE,CAAC,CAIzF;AAED,wBAAsB,2BAA2B,CAC/C,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,qBAAqB,CAAC,CAUhC;AAED,wBAAsB,6BAA6B,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAE9F"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { wrapHtml } from "../html-wrap.js";
|
|
4
|
+
import { VIEWPORT_HEIGHT_PX, VIEWPORT_WIDTH_PX } from "./constants.js";
|
|
5
|
+
import { ComputedStyleResolver } from "./style-resolver.js";
|
|
6
|
+
/** Playwright evaluate payload — kept as raw JS to avoid tsx `__name` injection. */
|
|
7
|
+
const COMPUTED_STYLE_SNAPSHOT_FN = readFileSync(fileURLToPath(new URL("./computed-style-snapshot.browser.js", import.meta.url)), "utf-8");
|
|
8
|
+
export async function snapshotComputedStyles(page) {
|
|
9
|
+
return (await page.evaluate(`(${COMPUTED_STYLE_SNAPSHOT_FN.trim()})()`));
|
|
10
|
+
}
|
|
11
|
+
export async function createComputedStyleResolver(html, browser) {
|
|
12
|
+
const page = await browser.newPage({
|
|
13
|
+
viewport: { width: VIEWPORT_WIDTH_PX, height: VIEWPORT_HEIGHT_PX },
|
|
14
|
+
});
|
|
15
|
+
try {
|
|
16
|
+
await page.setContent(wrapHtml(html), { waitUntil: "networkidle" });
|
|
17
|
+
return ComputedStyleResolver.fromSnapshots(await snapshotComputedStyles(page));
|
|
18
|
+
}
|
|
19
|
+
finally {
|
|
20
|
+
await page.close();
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export async function computedStyleResolverFromPage(page) {
|
|
24
|
+
return ComputedStyleResolver.fromSnapshots(await snapshotComputedStyles(page));
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=style-resolver-node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"style-resolver-node.js","sourceRoot":"","sources":["../../src/converter/style-resolver-node.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAEvE,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAE5D,oFAAoF;AACpF,MAAM,0BAA0B,GAAG,YAAY,CAC7C,aAAa,CAAC,IAAI,GAAG,CAAC,sCAAsC,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAC/E,OAAO,CACR,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,IAAU;IACrD,OAAO,CAAC,MAAM,IAAI,CAAC,QAAQ,CACzB,IAAI,0BAA0B,CAAC,IAAI,EAAE,KAAK,CAC3C,CAA4B,CAAC;AAChC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAC/C,IAAY,EACZ,OAAgB;IAEhB,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC;QACjC,QAAQ,EAAE,EAAE,KAAK,EAAE,iBAAiB,EAAE,MAAM,EAAE,kBAAkB,EAAE;KACnE,CAAC,CAAC;IACH,IAAI,CAAC;QACH,MAAM,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC,CAAC;QACpE,OAAO,qBAAqB,CAAC,aAAa,CAAC,MAAM,sBAAsB,CAAC,IAAI,CAAC,CAAC,CAAC;IACjF,CAAC;YAAS,CAAC;QACT,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,6BAA6B,CAAC,IAAU;IAC5D,OAAO,qBAAqB,CAAC,aAAa,CAAC,MAAM,sBAAsB,CAAC,IAAI,CAAC,CAAC,CAAC;AACjF,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Element } from "domhandler";
|
|
2
|
+
import { type ParsedCss } from "./css.js";
|
|
3
|
+
import type { ComputedStyleSnapshot } from "./computed-style-snapshot.js";
|
|
4
|
+
export type { ComputedStyleSnapshot } from "./computed-style-snapshot.js";
|
|
5
|
+
export { snapshotComputedStylesFromDocument } from "./computed-style-snapshot.js";
|
|
6
|
+
export type StyleSource = "inline" | "computed";
|
|
7
|
+
export interface StyleResolver {
|
|
8
|
+
readonly source: StyleSource;
|
|
9
|
+
getCss(element: Element): ParsedCss;
|
|
10
|
+
}
|
|
11
|
+
export declare function parsedCssFromComputedRecord(raw: Record<string, string>): ParsedCss;
|
|
12
|
+
export declare class InlineStyleResolver implements StyleResolver {
|
|
13
|
+
readonly source: "inline";
|
|
14
|
+
getCss(element: Element): ParsedCss;
|
|
15
|
+
}
|
|
16
|
+
export declare class ComputedStyleResolver implements StyleResolver {
|
|
17
|
+
readonly source: "computed";
|
|
18
|
+
private readonly byPath;
|
|
19
|
+
constructor(snapshots: ComputedStyleSnapshot[]);
|
|
20
|
+
static fromSnapshots(snapshots: ComputedStyleSnapshot[]): ComputedStyleResolver;
|
|
21
|
+
getCss(element: Element): ParsedCss;
|
|
22
|
+
}
|
|
23
|
+
export declare const INLINE_STYLE_RESOLVER: StyleResolver;
|
|
24
|
+
//# sourceMappingURL=style-resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"style-resolver.d.ts","sourceRoot":"","sources":["../../src/converter/style-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAQL,KAAK,SAAS,EACf,MAAM,UAAU,CAAC;AAGlB,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAE1E,YAAY,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAC1E,OAAO,EAAE,kCAAkC,EAAE,MAAM,8BAA8B,CAAC;AAElF,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,UAAU,CAAC;AAEhD,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,SAAS,CAAC;CACrC;AAmBD,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAmClF;AAED,qBAAa,mBAAoB,YAAW,aAAa;IACvD,QAAQ,CAAC,MAAM,EAAG,QAAQ,CAAU;IAEpC,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,SAAS;CAOpC;AA4CD,qBAAa,qBAAsB,YAAW,aAAa;IACzD,QAAQ,CAAC,MAAM,EAAG,UAAU,CAAU;IACtC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAyB;gBAEpC,SAAS,EAAE,qBAAqB,EAAE;IAM9C,MAAM,CAAC,aAAa,CAAC,SAAS,EAAE,qBAAqB,EAAE,GAAG,qBAAqB;IAI/E,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,SAAS;CAIpC;AAED,eAAO,MAAM,qBAAqB,EAAE,aAAyC,CAAC"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { parseColor, parseFontSize, parseGap, parseInlineStyle, presentationalAttributesCss, pxToTwips, } from "./css.js";
|
|
2
|
+
import { elementStylePath } from "./style-path.js";
|
|
3
|
+
import { HEADING_FONT_HALF_POINTS, HEADING_MARGIN_EM } from "./constants.js";
|
|
4
|
+
export { snapshotComputedStylesFromDocument } from "./computed-style-snapshot.js";
|
|
5
|
+
function parseLengthPx(value) {
|
|
6
|
+
if (!value)
|
|
7
|
+
return undefined;
|
|
8
|
+
const trimmed = value.trim();
|
|
9
|
+
if (!trimmed || trimmed === "auto" || trimmed === "normal")
|
|
10
|
+
return undefined;
|
|
11
|
+
if (trimmed.endsWith("px"))
|
|
12
|
+
return pxToTwips(parseFloat(trimmed));
|
|
13
|
+
if (trimmed.endsWith("pt"))
|
|
14
|
+
return Math.round(parseFloat(trimmed) * 20);
|
|
15
|
+
if (trimmed.endsWith("em"))
|
|
16
|
+
return pxToTwips(parseFloat(trimmed) * 16);
|
|
17
|
+
const num = parseFloat(trimmed);
|
|
18
|
+
return Number.isFinite(num) ? pxToTwips(num) : undefined;
|
|
19
|
+
}
|
|
20
|
+
function computedBorderSide(width, color) {
|
|
21
|
+
const w = parseFloat(width);
|
|
22
|
+
if (!Number.isFinite(w) || w <= 0)
|
|
23
|
+
return undefined;
|
|
24
|
+
return { widthPx: w, color: parseColor(color) };
|
|
25
|
+
}
|
|
26
|
+
export function parsedCssFromComputedRecord(raw) {
|
|
27
|
+
const css = {};
|
|
28
|
+
css.color = parseColor(raw.color);
|
|
29
|
+
css.backgroundColor = parseColor(raw.backgroundColor);
|
|
30
|
+
css.display = raw.display?.trim().toLowerCase() || undefined;
|
|
31
|
+
css.flexDirection = raw.flexDirection?.trim().toLowerCase() || undefined;
|
|
32
|
+
css.gap = parseGap(raw.gap) ?? parseGap(raw.columnGap) ?? parseGap(raw.rowGap);
|
|
33
|
+
css.textAlign = raw.textAlign?.trim().toLowerCase() || undefined;
|
|
34
|
+
css.fontSize = parseFontSize(raw.fontSize);
|
|
35
|
+
css.fontWeight = raw.fontWeight?.trim() || undefined;
|
|
36
|
+
css.fontStyle = raw.fontStyle?.trim().toLowerCase() || undefined;
|
|
37
|
+
css.marginTop = parseLengthPx(raw.marginTop);
|
|
38
|
+
css.marginRight = parseLengthPx(raw.marginRight);
|
|
39
|
+
css.marginBottom = parseLengthPx(raw.marginBottom);
|
|
40
|
+
css.marginLeft = parseLengthPx(raw.marginLeft);
|
|
41
|
+
css.paddingTop = parseLengthPx(raw.paddingTop);
|
|
42
|
+
css.paddingRight = parseLengthPx(raw.paddingRight);
|
|
43
|
+
css.paddingBottom = parseLengthPx(raw.paddingBottom);
|
|
44
|
+
css.paddingLeft = parseLengthPx(raw.paddingLeft);
|
|
45
|
+
// getComputedStyle resolves percentages to concrete px, so width lands in widthTwips.
|
|
46
|
+
css.heightTwips = parseLengthPx(raw.height);
|
|
47
|
+
const rawWidth = raw.width?.trim();
|
|
48
|
+
if (rawWidth?.endsWith("%"))
|
|
49
|
+
css.widthPercent = parseFloat(rawWidth);
|
|
50
|
+
else
|
|
51
|
+
css.widthTwips = parseLengthPx(raw.width);
|
|
52
|
+
css.maxWidthTwips = parseLengthPx(raw.maxWidth);
|
|
53
|
+
css.borderTop = computedBorderSide(raw.borderTopWidth ?? "", raw.borderTopColor ?? "");
|
|
54
|
+
css.borderRight = computedBorderSide(raw.borderRightWidth ?? "", raw.borderRightColor ?? "");
|
|
55
|
+
css.borderBottom = computedBorderSide(raw.borderBottomWidth ?? "", raw.borderBottomColor ?? "");
|
|
56
|
+
css.borderLeft = computedBorderSide(raw.borderLeftWidth ?? "", raw.borderLeftColor ?? "");
|
|
57
|
+
return css;
|
|
58
|
+
}
|
|
59
|
+
export class InlineStyleResolver {
|
|
60
|
+
source = "inline";
|
|
61
|
+
getCss(element) {
|
|
62
|
+
const attrCss = presentationalAttributesCss(element);
|
|
63
|
+
const styleCss = parseInlineStyle(element.attribs?.style);
|
|
64
|
+
// Inline style wins over presentational attributes (browser precedence);
|
|
65
|
+
// parsed style objects only carry keys that were actually declared.
|
|
66
|
+
return { ...attrCss, ...styleCss };
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/** Strip UA defaults that inline style="" resolution never sees (headings, blockquotes). */
|
|
70
|
+
function approxEquals(value, expected, tolerance) {
|
|
71
|
+
return value !== undefined && Math.abs(value - expected) <= tolerance;
|
|
72
|
+
}
|
|
73
|
+
function normalizeComputedUACss(element, css) {
|
|
74
|
+
const tag = element.name.toLowerCase();
|
|
75
|
+
const inlineStyle = element.attribs?.style ?? "";
|
|
76
|
+
if (/^h[1-6]$/.test(tag)) {
|
|
77
|
+
// Strip heading values ONLY when they match the UA default — a stylesheet
|
|
78
|
+
// `.banner h1 { font-size: 20px }` must survive; blanket-stripping (the old
|
|
79
|
+
// behavior) threw author CSS away along with the UA noise.
|
|
80
|
+
const result = { ...css };
|
|
81
|
+
const headingTag = tag;
|
|
82
|
+
const uaFontHalfPoints = HEADING_FONT_HALF_POINTS[headingTag];
|
|
83
|
+
if (!/\bfont-size\s*:/i.test(inlineStyle) &&
|
|
84
|
+
approxEquals(css.fontSize, uaFontHalfPoints, 1)) {
|
|
85
|
+
result.fontSize = undefined;
|
|
86
|
+
}
|
|
87
|
+
if (!/\bmargin(?:\s|:|-)/i.test(inlineStyle)) {
|
|
88
|
+
const headingFontPx = (css.fontSize ?? uaFontHalfPoints) / 1.5;
|
|
89
|
+
const uaMarginTwips = Math.round(HEADING_MARGIN_EM[headingTag] * headingFontPx * 15);
|
|
90
|
+
if (approxEquals(css.marginTop, uaMarginTwips, 15))
|
|
91
|
+
result.marginTop = undefined;
|
|
92
|
+
if (approxEquals(css.marginBottom, uaMarginTwips, 15))
|
|
93
|
+
result.marginBottom = undefined;
|
|
94
|
+
if (approxEquals(css.marginLeft, 0, 1))
|
|
95
|
+
result.marginLeft = undefined;
|
|
96
|
+
if (approxEquals(css.marginRight, 0, 1))
|
|
97
|
+
result.marginRight = undefined;
|
|
98
|
+
}
|
|
99
|
+
if (!/\bfont-weight\s*:/i.test(inlineStyle) &&
|
|
100
|
+
(css.fontWeight === "700" || css.fontWeight === "bold")) {
|
|
101
|
+
result.fontWeight = undefined;
|
|
102
|
+
}
|
|
103
|
+
return result;
|
|
104
|
+
}
|
|
105
|
+
return css;
|
|
106
|
+
}
|
|
107
|
+
export class ComputedStyleResolver {
|
|
108
|
+
source = "computed";
|
|
109
|
+
byPath;
|
|
110
|
+
constructor(snapshots) {
|
|
111
|
+
this.byPath = new Map(snapshots.map((s) => [s.path, parsedCssFromComputedRecord(s.styles)]));
|
|
112
|
+
}
|
|
113
|
+
static fromSnapshots(snapshots) {
|
|
114
|
+
return new ComputedStyleResolver(snapshots);
|
|
115
|
+
}
|
|
116
|
+
getCss(element) {
|
|
117
|
+
const css = this.byPath.get(elementStylePath(element)) ?? {};
|
|
118
|
+
return normalizeComputedUACss(element, css);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
export const INLINE_STYLE_RESOLVER = new InlineStyleResolver();
|
|
122
|
+
//# sourceMappingURL=style-resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"style-resolver.js","sourceRoot":"","sources":["../../src/converter/style-resolver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Element } from "domhandler";
|
|
2
|
+
import type { DocxBlock } from "./types.js";
|
|
3
|
+
export declare function isSvgElement(element: Element): boolean;
|
|
4
|
+
/**
|
|
5
|
+
* Low-complexity SVG → native DOCX vector-ish blocks (no rasterization).
|
|
6
|
+
* Supports stacked `<rect>` bars (e.g. funnel/bar charts) rendered as centered
|
|
7
|
+
* shaded paragraph bands, plus `<text>` labels. Painter's-algorithm overlap is
|
|
8
|
+
* resolved so visible band heights match the browser render.
|
|
9
|
+
*/
|
|
10
|
+
export declare function convertSvg(svg: Element): DocxBlock[];
|
|
11
|
+
//# sourceMappingURL=svg.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"svg.d.ts","sourceRoot":"","sources":["../../src/converter/svg.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAW,OAAO,EAAE,MAAM,YAAY,CAAC;AAGnD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AA4C5C,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAEtD;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,SAAS,EAAE,CAyFpD"}
|