@json-to-office/core-docx 7.2.0 → 7.3.1
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.js +1565 -471
- package/dist/index.js.map +1 -1
- package/dist/ir/chartValues.d.ts +18 -0
- package/dist/ir/chartValues.d.ts.map +1 -0
- package/dist/ir/compiler.d.ts.map +1 -1
- package/dist/ir/features.d.ts.map +1 -1
- package/dist/ir/theme.d.ts +43 -0
- package/dist/ir/theme.d.ts.map +1 -0
- package/dist/ir/types.d.ts +39 -3
- package/dist/ir/types.d.ts.map +1 -1
- package/dist/ir/validation.d.ts +2 -1
- package/dist/ir/validation.d.ts.map +1 -1
- package/dist/plugin/example/index.js +1562 -468
- package/dist/plugin/example/index.js.map +1 -1
- package/dist/renderers/chartText.d.ts +43 -0
- package/dist/renderers/chartText.d.ts.map +1 -0
- package/dist/renderers/docxjs/charts.d.ts +45 -0
- package/dist/renderers/docxjs/charts.d.ts.map +1 -0
- package/dist/renderers/docxjs/docxSubpath.d.ts +34 -0
- package/dist/renderers/docxjs/docxSubpath.d.ts.map +1 -0
- package/dist/renderers/docxjs/drawingGroup.d.ts +79 -0
- package/dist/renderers/docxjs/drawingGroup.d.ts.map +1 -0
- package/dist/renderers/docxjs/drawingGroupRepair.d.ts +36 -0
- package/dist/renderers/docxjs/drawingGroupRepair.d.ts.map +1 -0
- package/dist/renderers/docxjs/emit.d.ts +10 -2
- package/dist/renderers/docxjs/emit.d.ts.map +1 -1
- package/dist/renderers/docxjs/index.d.ts +2 -1
- package/dist/renderers/docxjs/index.d.ts.map +1 -1
- package/dist/renderers/docxjs/presetShapes.d.ts +233 -0
- package/dist/renderers/docxjs/presetShapes.d.ts.map +1 -0
- package/dist/renderers/office-open/chartLook.d.ts +45 -0
- package/dist/renderers/office-open/chartLook.d.ts.map +1 -0
- package/dist/renderers/office-open/chartParts.d.ts +29 -15
- package/dist/renderers/office-open/chartParts.d.ts.map +1 -1
- package/dist/renderers/office-open/emit.d.ts +25 -39
- package/dist/renderers/office-open/emit.d.ts.map +1 -1
- package/dist/renderers/office-open/index.d.ts +16 -4
- package/dist/renderers/office-open/index.d.ts.map +1 -1
- package/dist/renderers/office-open/themePart.d.ts +28 -0
- package/dist/renderers/office-open/themePart.d.ts.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utils/chartWorkbook.d.ts +2 -1
- package/dist/utils/chartWorkbook.d.ts.map +1 -1
- package/dist/utils/fixFloatingImageIds.d.ts +17 -9
- package/dist/utils/fixFloatingImageIds.d.ts.map +1 -1
- package/dist/utils/packageDocument.d.ts.map +1 -1
- package/package.json +6 -6
- package/dist/renderers/office-open/cellTocs.d.ts +0 -26
- package/dist/renderers/office-open/cellTocs.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -2779,7 +2779,7 @@ var init_imageUtils = __esm({
|
|
|
2779
2779
|
});
|
|
2780
2780
|
|
|
2781
2781
|
// src/ir/types.ts
|
|
2782
|
-
var TWIPS_PER_INCH, TWIPS_PER_POINT2, EMU_PER_INCH, EMU_PER_TWIP, DOCX_IR_SCHEMA_VERSION, DOCX_IR_BORDER_STYLES;
|
|
2782
|
+
var TWIPS_PER_INCH, TWIPS_PER_POINT2, EMU_PER_INCH, EMU_PER_TWIP, DOCX_IR_SCHEMA_VERSION, NOT_XML_CHAR, DOCX_IR_BORDER_STYLES;
|
|
2783
2783
|
var init_types = __esm({
|
|
2784
2784
|
"src/ir/types.ts"() {
|
|
2785
2785
|
"use strict";
|
|
@@ -2788,6 +2788,7 @@ var init_types = __esm({
|
|
|
2788
2788
|
EMU_PER_INCH = 914400;
|
|
2789
2789
|
EMU_PER_TWIP = EMU_PER_INCH / TWIPS_PER_INCH;
|
|
2790
2790
|
DOCX_IR_SCHEMA_VERSION = 1;
|
|
2791
|
+
NOT_XML_CHAR = /[^\t\n\r\u0020-\uD7FF\uE000-\uFFFD\u{10000}-\u{10FFFF}]/u;
|
|
2791
2792
|
DOCX_IR_BORDER_STYLES = [
|
|
2792
2793
|
"single",
|
|
2793
2794
|
"dashDotStroked",
|
|
@@ -2874,6 +2875,242 @@ var init_units = __esm({
|
|
|
2874
2875
|
}
|
|
2875
2876
|
});
|
|
2876
2877
|
|
|
2878
|
+
// src/ir/chartValues.ts
|
|
2879
|
+
function numericLabelValue(label) {
|
|
2880
|
+
const value = label.trim();
|
|
2881
|
+
return NUMERIC_LABEL.test(value) ? Number(value) : void 0;
|
|
2882
|
+
}
|
|
2883
|
+
function isNumericLabel(label) {
|
|
2884
|
+
const value = numericLabelValue(label);
|
|
2885
|
+
return value !== void 0 && Number.isFinite(value);
|
|
2886
|
+
}
|
|
2887
|
+
function isOutOfRangeNumericLabel(label) {
|
|
2888
|
+
const value = numericLabelValue(label);
|
|
2889
|
+
return value !== void 0 && !Number.isFinite(value);
|
|
2890
|
+
}
|
|
2891
|
+
function scatterX(labels, index) {
|
|
2892
|
+
const label = labels[index];
|
|
2893
|
+
const value = label === void 0 ? void 0 : numericLabelValue(label);
|
|
2894
|
+
if (value === void 0) return index + 1;
|
|
2895
|
+
if (!Number.isFinite(value)) {
|
|
2896
|
+
throw new RangeError(
|
|
2897
|
+
`Scatter x label ${JSON.stringify(label)} is not finite.`
|
|
2898
|
+
);
|
|
2899
|
+
}
|
|
2900
|
+
return value;
|
|
2901
|
+
}
|
|
2902
|
+
var NUMERIC_LABEL;
|
|
2903
|
+
var init_chartValues = __esm({
|
|
2904
|
+
"src/ir/chartValues.ts"() {
|
|
2905
|
+
"use strict";
|
|
2906
|
+
NUMERIC_LABEL = /^[+-]?(\d+(\.\d*)?|\.\d+)([eE][+-]?\d+)?$/;
|
|
2907
|
+
}
|
|
2908
|
+
});
|
|
2909
|
+
|
|
2910
|
+
// src/renderers/chartText.ts
|
|
2911
|
+
function chartTextRoles(font) {
|
|
2912
|
+
const { bold, ...rest } = font;
|
|
2913
|
+
const text = rest;
|
|
2914
|
+
return {
|
|
2915
|
+
text,
|
|
2916
|
+
axisTitle: { ...text, bold },
|
|
2917
|
+
title: {
|
|
2918
|
+
...text,
|
|
2919
|
+
fontSize: Math.round(text.fontSize * CHART_TITLE_SCALE),
|
|
2920
|
+
bold: true
|
|
2921
|
+
}
|
|
2922
|
+
};
|
|
2923
|
+
}
|
|
2924
|
+
var CHART_TITLE_SCALE;
|
|
2925
|
+
var init_chartText = __esm({
|
|
2926
|
+
"src/renderers/chartText.ts"() {
|
|
2927
|
+
"use strict";
|
|
2928
|
+
CHART_TITLE_SCALE = 1.4;
|
|
2929
|
+
}
|
|
2930
|
+
});
|
|
2931
|
+
|
|
2932
|
+
// src/renderers/docxjs/docxSubpath.ts
|
|
2933
|
+
function docxSubpath(specifier, component, importer) {
|
|
2934
|
+
let module;
|
|
2935
|
+
let failure;
|
|
2936
|
+
let loading;
|
|
2937
|
+
return {
|
|
2938
|
+
specifier,
|
|
2939
|
+
load() {
|
|
2940
|
+
loading ??= importer().then(
|
|
2941
|
+
(loadedModule) => {
|
|
2942
|
+
module = loadedModule;
|
|
2943
|
+
},
|
|
2944
|
+
(reason) => {
|
|
2945
|
+
failure = { reason };
|
|
2946
|
+
}
|
|
2947
|
+
);
|
|
2948
|
+
return loading;
|
|
2949
|
+
},
|
|
2950
|
+
loaded: () => module !== void 0,
|
|
2951
|
+
get() {
|
|
2952
|
+
if (module !== void 0) return module;
|
|
2953
|
+
if (failure !== void 0) {
|
|
2954
|
+
const { reason } = failure;
|
|
2955
|
+
const detail = reason instanceof Error ? reason.message : String(reason);
|
|
2956
|
+
throw new Error(
|
|
2957
|
+
`The docx \`${component}\` component needs docx 9.8.0 or later: the \`${specifier}\` entry could not be loaded (${detail})`
|
|
2958
|
+
);
|
|
2959
|
+
}
|
|
2960
|
+
throw new Error(
|
|
2961
|
+
`${specifier} is not loaded: await its load() before buildDocument() (render() does)`
|
|
2962
|
+
);
|
|
2963
|
+
}
|
|
2964
|
+
};
|
|
2965
|
+
}
|
|
2966
|
+
var init_docxSubpath = __esm({
|
|
2967
|
+
"src/renderers/docxjs/docxSubpath.ts"() {
|
|
2968
|
+
"use strict";
|
|
2969
|
+
}
|
|
2970
|
+
});
|
|
2971
|
+
|
|
2972
|
+
// src/renderers/docxjs/charts.ts
|
|
2973
|
+
import { assertNever } from "@json-to-office/shared/rendering";
|
|
2974
|
+
function loadDocxCharts() {
|
|
2975
|
+
return charts.load();
|
|
2976
|
+
}
|
|
2977
|
+
function chartFont(role) {
|
|
2978
|
+
return {
|
|
2979
|
+
name: role.fontFamily,
|
|
2980
|
+
size: role.fontSize,
|
|
2981
|
+
color: role.color,
|
|
2982
|
+
bold: role.bold ?? false
|
|
2983
|
+
};
|
|
2984
|
+
}
|
|
2985
|
+
function chartRunOptions(chart, floating) {
|
|
2986
|
+
const roles = chartTextRoles(chart.textFont);
|
|
2987
|
+
const text = chartFont(roles.text);
|
|
2988
|
+
const axisTitle = chartFont(roles.axisTitle);
|
|
2989
|
+
const palette = chart.colors;
|
|
2990
|
+
const colorAt = (index) => palette.length > 0 ? palette[index % palette.length] : void 0;
|
|
2991
|
+
const withColor = (index) => {
|
|
2992
|
+
const color = colorAt(index);
|
|
2993
|
+
return color ? { color } : {};
|
|
2994
|
+
};
|
|
2995
|
+
const seriesName = (index) => chart.series[index].name ?? `Series ${index + 1}`;
|
|
2996
|
+
const categories = chart.series[0]?.labels ?? [];
|
|
2997
|
+
const axis = (title) => ({
|
|
2998
|
+
...title ? { title: { text: title, font: axisTitle } } : {},
|
|
2999
|
+
font: text
|
|
3000
|
+
});
|
|
3001
|
+
const common = {
|
|
3002
|
+
...chart.title && chart.showTitle !== false ? { title: { text: chart.title, font: chartFont(roles.title) } } : {},
|
|
3003
|
+
legend: chart.showLegend === false ? false : {
|
|
3004
|
+
position: LEGEND_POSITION[chart.legendPosition ?? "b"],
|
|
3005
|
+
font: text
|
|
3006
|
+
},
|
|
3007
|
+
font: { name: roles.text.fontFamily, color: roles.text.color },
|
|
3008
|
+
// Office-open's chart space is unfilled and unbordered; `ChartRun`'s
|
|
3009
|
+
// default is Word's white fill and grey border.
|
|
3010
|
+
chartArea: { fill: "none", border: "none" },
|
|
3011
|
+
transformation: {
|
|
3012
|
+
width: emuToPixels(chart.widthEmu),
|
|
3013
|
+
height: emuToPixels(chart.heightEmu)
|
|
3014
|
+
},
|
|
3015
|
+
// Without an authored description `ChartRun` describes the chart from
|
|
3016
|
+
// its data, which is deterministic; the name stays empty, as it is on
|
|
3017
|
+
// every other drawing this renderer writes.
|
|
3018
|
+
...chart.altText ? { altText: { name: "", description: chart.altText } } : {},
|
|
3019
|
+
...floating ? { floating } : {}
|
|
3020
|
+
};
|
|
3021
|
+
switch (chart.chartType) {
|
|
3022
|
+
case "column":
|
|
3023
|
+
case "bar":
|
|
3024
|
+
case "area":
|
|
3025
|
+
case "line":
|
|
3026
|
+
return {
|
|
3027
|
+
...common,
|
|
3028
|
+
type: chart.chartType,
|
|
3029
|
+
categories,
|
|
3030
|
+
...chart.chartType === "line" ? { markers: true } : {},
|
|
3031
|
+
series: chart.series.map((entry, index) => ({
|
|
3032
|
+
name: seriesName(index),
|
|
3033
|
+
values: entry.values,
|
|
3034
|
+
...withColor(index)
|
|
3035
|
+
})),
|
|
3036
|
+
categoryAxis: axis(chart.categoryAxisTitle),
|
|
3037
|
+
valueAxis: axis(chart.valueAxisTitle)
|
|
3038
|
+
};
|
|
3039
|
+
case "pie":
|
|
3040
|
+
case "doughnut":
|
|
3041
|
+
return {
|
|
3042
|
+
...common,
|
|
3043
|
+
type: chart.chartType,
|
|
3044
|
+
categories,
|
|
3045
|
+
series: chart.series.map((entry, index) => ({
|
|
3046
|
+
name: seriesName(index),
|
|
3047
|
+
values: entry.values,
|
|
3048
|
+
...palette.length > 0 ? { colors: entry.values.map((_, point) => colorAt(point)) } : {}
|
|
3049
|
+
}))
|
|
3050
|
+
};
|
|
3051
|
+
case "radar":
|
|
3052
|
+
return {
|
|
3053
|
+
...common,
|
|
3054
|
+
type: "radar",
|
|
3055
|
+
categories,
|
|
3056
|
+
markers: true,
|
|
3057
|
+
series: chart.series.map((entry, index) => ({
|
|
3058
|
+
name: seriesName(index),
|
|
3059
|
+
values: entry.values,
|
|
3060
|
+
...withColor(index)
|
|
3061
|
+
})),
|
|
3062
|
+
categoryAxis: axis(chart.categoryAxisTitle),
|
|
3063
|
+
valueAxis: axis(chart.valueAxisTitle)
|
|
3064
|
+
};
|
|
3065
|
+
case "scatter":
|
|
3066
|
+
return {
|
|
3067
|
+
...common,
|
|
3068
|
+
type: "scatter",
|
|
3069
|
+
markers: true,
|
|
3070
|
+
lines: "straight",
|
|
3071
|
+
series: chart.series.map((entry, index) => ({
|
|
3072
|
+
name: seriesName(index),
|
|
3073
|
+
points: entry.values.map((y, point) => ({
|
|
3074
|
+
x: scatterX(entry.labels, point),
|
|
3075
|
+
y
|
|
3076
|
+
})),
|
|
3077
|
+
...withColor(index)
|
|
3078
|
+
})),
|
|
3079
|
+
xAxis: { ...axis(chart.categoryAxisTitle), gridlines: false },
|
|
3080
|
+
yAxis: axis(chart.valueAxisTitle)
|
|
3081
|
+
};
|
|
3082
|
+
case "bubble":
|
|
3083
|
+
throw new Error(
|
|
3084
|
+
"the docxjs renderer has no emitter for a bubble chart; the compiler should have refused it"
|
|
3085
|
+
);
|
|
3086
|
+
default:
|
|
3087
|
+
return assertNever(chart.chartType, "DocxIrChartType");
|
|
3088
|
+
}
|
|
3089
|
+
}
|
|
3090
|
+
function emitChart(chart, floating) {
|
|
3091
|
+
return new (charts.get()).ChartRun(
|
|
3092
|
+
chartRunOptions(chart, floating)
|
|
3093
|
+
);
|
|
3094
|
+
}
|
|
3095
|
+
var charts, LEGEND_POSITION;
|
|
3096
|
+
var init_charts = __esm({
|
|
3097
|
+
"src/renderers/docxjs/charts.ts"() {
|
|
3098
|
+
"use strict";
|
|
3099
|
+
init_chartValues();
|
|
3100
|
+
init_units();
|
|
3101
|
+
init_chartText();
|
|
3102
|
+
init_docxSubpath();
|
|
3103
|
+
charts = docxSubpath("docx/charts", "chart", () => import("docx/charts"));
|
|
3104
|
+
LEGEND_POSITION = {
|
|
3105
|
+
b: "bottom",
|
|
3106
|
+
l: "left",
|
|
3107
|
+
r: "right",
|
|
3108
|
+
t: "top",
|
|
3109
|
+
tr: "topRight"
|
|
3110
|
+
};
|
|
3111
|
+
}
|
|
3112
|
+
});
|
|
3113
|
+
|
|
2877
3114
|
// src/renderers/docxjs/emit.ts
|
|
2878
3115
|
import {
|
|
2879
3116
|
AlignmentType,
|
|
@@ -2909,7 +3146,7 @@ import {
|
|
|
2909
3146
|
WidthType,
|
|
2910
3147
|
WpsShapeRun
|
|
2911
3148
|
} from "docx";
|
|
2912
|
-
import { assertNever } from "@json-to-office/shared/rendering";
|
|
3149
|
+
import { assertNever as assertNever2 } from "@json-to-office/shared/rendering";
|
|
2913
3150
|
function complexField(instruction, formatting, leading, cachedText) {
|
|
2914
3151
|
const options = runOptions(formatting);
|
|
2915
3152
|
const fieldChar = (type, extra = {}) => new TextRun({
|
|
@@ -2946,7 +3183,12 @@ function runOptions(formatting) {
|
|
|
2946
3183
|
if (formatting.bold !== void 0) options.bold = formatting.bold;
|
|
2947
3184
|
if (formatting.italic !== void 0) options.italics = formatting.italic;
|
|
2948
3185
|
if (formatting.underline !== void 0) {
|
|
2949
|
-
options.underline = formatting.underline ? {
|
|
3186
|
+
options.underline = formatting.underline ? {
|
|
3187
|
+
type: formatting.underline.type,
|
|
3188
|
+
// A native visual's text is the one place a run states its own
|
|
3189
|
+
// underline colour.
|
|
3190
|
+
...formatting.underline.color ? { color: formatting.underline.color.hex } : {}
|
|
3191
|
+
} : void 0;
|
|
2950
3192
|
}
|
|
2951
3193
|
if (formatting.strike !== void 0) options.strike = formatting.strike;
|
|
2952
3194
|
if (formatting.allCaps !== void 0) options.allCaps = formatting.allCaps;
|
|
@@ -3072,21 +3314,36 @@ function inlineChildren(children, resources = /* @__PURE__ */ new Map()) {
|
|
|
3072
3314
|
case "shape":
|
|
3073
3315
|
out.push(emitShape(child, resources));
|
|
3074
3316
|
break;
|
|
3075
|
-
case "drawingGroup":
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3317
|
+
case "drawingGroup": {
|
|
3318
|
+
const build = resources.drawingGroup;
|
|
3319
|
+
if (!build) {
|
|
3320
|
+
throw new Error(
|
|
3321
|
+
"the docxjs renderer was handed a drawing group without loading docx/shapes; render() loads it whenever the IR holds one"
|
|
3322
|
+
);
|
|
3323
|
+
}
|
|
3324
|
+
const pending = breakOption();
|
|
3325
|
+
if (pending.break) out.push(new TextRun(pending));
|
|
3326
|
+
out.push(build(child, resources));
|
|
3327
|
+
break;
|
|
3328
|
+
}
|
|
3329
|
+
case "chart": {
|
|
3330
|
+
const pending = breakOption();
|
|
3331
|
+
if (pending.break) out.push(new TextRun(pending));
|
|
3332
|
+
out.push(
|
|
3333
|
+
emitChart(
|
|
3334
|
+
child,
|
|
3335
|
+
child.floating ? floatingOptions(child.floating) : void 0
|
|
3336
|
+
)
|
|
3082
3337
|
);
|
|
3338
|
+
break;
|
|
3339
|
+
}
|
|
3083
3340
|
case "noteReference":
|
|
3084
3341
|
out.push(
|
|
3085
3342
|
child.noteKind === "endnote" ? new EndnoteReferenceRun(child.id) : new FootnoteReferenceRun(child.id)
|
|
3086
3343
|
);
|
|
3087
3344
|
break;
|
|
3088
3345
|
default:
|
|
3089
|
-
|
|
3346
|
+
assertNever2(child, "DocxIrInline");
|
|
3090
3347
|
}
|
|
3091
3348
|
}
|
|
3092
3349
|
return out;
|
|
@@ -3291,7 +3548,7 @@ function emitBlock(block2, resources = /* @__PURE__ */ new Map()) {
|
|
|
3291
3548
|
case "toc":
|
|
3292
3549
|
return emitToc(block2);
|
|
3293
3550
|
default:
|
|
3294
|
-
return
|
|
3551
|
+
return assertNever2(block2, "DocxIrBlock");
|
|
3295
3552
|
}
|
|
3296
3553
|
}
|
|
3297
3554
|
function emitToc(block2) {
|
|
@@ -3435,6 +3692,7 @@ var ALIGNMENT2, PAGE_FIELDS, isSequenceField, WRAP_TYPE, ThemedTableOfContents,
|
|
|
3435
3692
|
var init_emit = __esm({
|
|
3436
3693
|
"src/renderers/docxjs/emit.ts"() {
|
|
3437
3694
|
"use strict";
|
|
3695
|
+
init_charts();
|
|
3438
3696
|
ALIGNMENT2 = {
|
|
3439
3697
|
left: AlignmentType.LEFT,
|
|
3440
3698
|
center: AlignmentType.CENTER,
|
|
@@ -3733,10 +3991,13 @@ function canonicalizeRelationshipIds(zip) {
|
|
|
3733
3991
|
const rename = new Map(
|
|
3734
3992
|
ordered.map((id, index) => [id, `rId${highest + 1 + index}`])
|
|
3735
3993
|
);
|
|
3736
|
-
const rewrite = (xml) => xml.replace(
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3994
|
+
const rewrite = (xml) => xml.replace(
|
|
3995
|
+
/(\s[\w:.-]+=)"([^"]*)"/g,
|
|
3996
|
+
(whole, prefix, value) => {
|
|
3997
|
+
const replacement = rename.get(value);
|
|
3998
|
+
return replacement === void 0 ? whole : `${prefix}"${replacement}"`;
|
|
3999
|
+
}
|
|
4000
|
+
);
|
|
3740
4001
|
updates.push({ name: relsName, xml: rewrite(relsXml) });
|
|
3741
4002
|
if (partEntry) {
|
|
3742
4003
|
updates.push({ name: partName, xml: rewrite(partXml) });
|
|
@@ -3747,17 +4008,62 @@ function canonicalizeRelationshipIds(zip) {
|
|
|
3747
4008
|
if (entry) zip.updateFile(entry, Buffer.from(update.xml, "utf8"));
|
|
3748
4009
|
}
|
|
3749
4010
|
}
|
|
4011
|
+
function canonicalizeEmbeddedPackages(zip, generatedAt, depth = 1) {
|
|
4012
|
+
const names = zip.getEntries().map((entry) => entry.entryName).filter((name) => EMBEDDED_OFFICE_PACKAGE.test(name));
|
|
4013
|
+
let changed = false;
|
|
4014
|
+
for (const name of names) {
|
|
4015
|
+
const entry = zip.getEntry(name);
|
|
4016
|
+
if (!entry) continue;
|
|
4017
|
+
let nested;
|
|
4018
|
+
try {
|
|
4019
|
+
nested = new AdmZip(entry.getData());
|
|
4020
|
+
nested.getEntries();
|
|
4021
|
+
} catch {
|
|
4022
|
+
continue;
|
|
4023
|
+
}
|
|
4024
|
+
if (canonicalizeNestedPackage(nested, generatedAt, depth)) {
|
|
4025
|
+
zip.updateFile(entry, nested.toBuffer());
|
|
4026
|
+
changed = true;
|
|
4027
|
+
}
|
|
4028
|
+
}
|
|
4029
|
+
return changed;
|
|
4030
|
+
}
|
|
4031
|
+
function canonicalizeNestedPackage(zip, generatedAt, depth) {
|
|
4032
|
+
let changed = false;
|
|
4033
|
+
const coreProperties3 = zip.getEntry("docProps/core.xml");
|
|
4034
|
+
if (coreProperties3) {
|
|
4035
|
+
const xml = coreProperties3.getData().toString("utf8");
|
|
4036
|
+
const normalized = xml.replace(
|
|
4037
|
+
CORE_TIMESTAMP,
|
|
4038
|
+
`$1${generatedAt.toISOString()}$2`
|
|
4039
|
+
);
|
|
4040
|
+
if (normalized !== xml) {
|
|
4041
|
+
zip.updateFile(coreProperties3, Buffer.from(normalized, "utf8"));
|
|
4042
|
+
changed = true;
|
|
4043
|
+
}
|
|
4044
|
+
}
|
|
4045
|
+
if (depth < MAX_EMBEDDED_DEPTH && canonicalizeEmbeddedPackages(zip, generatedAt, depth + 1)) {
|
|
4046
|
+
changed = true;
|
|
4047
|
+
}
|
|
4048
|
+
const zipTimestamp = toDosTime(generatedAt);
|
|
4049
|
+
for (const entry of zip.getEntries()) {
|
|
4050
|
+
const header = entry.header;
|
|
4051
|
+
if (header.timeval !== zipTimestamp) {
|
|
4052
|
+
header.timeval = zipTimestamp;
|
|
4053
|
+
changed = true;
|
|
4054
|
+
}
|
|
4055
|
+
}
|
|
4056
|
+
return changed;
|
|
4057
|
+
}
|
|
3750
4058
|
function canonicalizeDocxBuffer(buffer, generatedAt = DEFAULT_GENERATION_DATE) {
|
|
3751
4059
|
const zip = new AdmZip(buffer);
|
|
3752
4060
|
normalizeTextCase(zip);
|
|
3753
4061
|
canonicalizeRelationshipIds(zip);
|
|
4062
|
+
canonicalizeEmbeddedPackages(zip, generatedAt);
|
|
3754
4063
|
const isoTimestamp = generatedAt.toISOString();
|
|
3755
4064
|
const coreProperties3 = zip.getEntry("docProps/core.xml");
|
|
3756
4065
|
if (coreProperties3) {
|
|
3757
|
-
const normalized = coreProperties3.getData().toString("utf8").replace(
|
|
3758
|
-
/(<dcterms:(?:created|modified)\b[^>]*>)[^<]*(<\/dcterms:(?:created|modified)>)/g,
|
|
3759
|
-
`$1${isoTimestamp}$2`
|
|
3760
|
-
);
|
|
4066
|
+
const normalized = coreProperties3.getData().toString("utf8").replace(CORE_TIMESTAMP, `$1${isoTimestamp}$2`);
|
|
3761
4067
|
zip.updateFile(coreProperties3, Buffer.from(normalized, "utf8"));
|
|
3762
4068
|
}
|
|
3763
4069
|
const zipTimestamp = toDosTime(generatedAt);
|
|
@@ -3770,35 +4076,567 @@ function normalizeDocxCaseBuffer(buffer) {
|
|
|
3770
4076
|
const zip = new AdmZip(buffer);
|
|
3771
4077
|
return normalizeTextCase(zip) ? zip.toBuffer() : buffer;
|
|
3772
4078
|
}
|
|
3773
|
-
var DEFAULT_GENERATION_DATE, STABLE_RELATIONSHIP_ID;
|
|
4079
|
+
var DEFAULT_GENERATION_DATE, STABLE_RELATIONSHIP_ID, CORE_TIMESTAMP, EMBEDDED_OFFICE_PACKAGE, MAX_EMBEDDED_DEPTH;
|
|
3774
4080
|
var init_packageDocument = __esm({
|
|
3775
4081
|
"src/utils/packageDocument.ts"() {
|
|
3776
4082
|
"use strict";
|
|
3777
4083
|
init_normalizeTextCase();
|
|
3778
4084
|
DEFAULT_GENERATION_DATE = /* @__PURE__ */ new Date("2000-01-01T00:00:00.000Z");
|
|
3779
4085
|
STABLE_RELATIONSHIP_ID = /^rId\d+$/;
|
|
4086
|
+
CORE_TIMESTAMP = /(<dcterms:(?:created|modified)\b[^>]*>)[^<]*(<\/dcterms:(?:created|modified)>)/g;
|
|
4087
|
+
EMBEDDED_OFFICE_PACKAGE = /\.(?:docx|pptx|xlsx|xlsm)$/i;
|
|
4088
|
+
MAX_EMBEDDED_DEPTH = 3;
|
|
3780
4089
|
}
|
|
3781
4090
|
});
|
|
3782
4091
|
|
|
3783
4092
|
// src/utils/fixFloatingImageIds.ts
|
|
3784
4093
|
import AdmZip2 from "adm-zip";
|
|
4094
|
+
function compareDrawingParts(a, b) {
|
|
4095
|
+
const ma = DRAWING_PART.exec(a);
|
|
4096
|
+
const mb = DRAWING_PART.exec(b);
|
|
4097
|
+
const rank = RANK.indexOf(ma[1]) - RANK.indexOf(mb[1]);
|
|
4098
|
+
return rank !== 0 ? rank : Number(ma[2] || 0) - Number(mb[2] || 0);
|
|
4099
|
+
}
|
|
3785
4100
|
function fixFloatingImageIdsInBuffer(buffer) {
|
|
3786
4101
|
const zip = new AdmZip2(buffer);
|
|
3787
|
-
|
|
3788
|
-
if (!documentEntry) {
|
|
4102
|
+
if (!zip.getEntry("word/document.xml")) {
|
|
3789
4103
|
throw new Error("document.xml not found in DOCX");
|
|
3790
4104
|
}
|
|
4105
|
+
const parts = zip.getEntries().filter((entry) => DRAWING_PART.test(entry.entryName)).sort((a, b) => compareDrawingParts(a.entryName, b.entryName));
|
|
3791
4106
|
let idCounter = 1;
|
|
3792
|
-
const
|
|
3793
|
-
const
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
4107
|
+
for (const entry of parts) {
|
|
4108
|
+
const xml = entry.getData().toString("utf8");
|
|
4109
|
+
const renumbered = xml.replace(
|
|
4110
|
+
/(<wp:docPr\b[^>]*?\s)id="\d+"/g,
|
|
4111
|
+
(_match, prefix) => `${prefix}id="${idCounter++}"`
|
|
4112
|
+
);
|
|
4113
|
+
zip.updateFile(entry, Buffer.from(renumbered, "utf8"));
|
|
4114
|
+
}
|
|
3797
4115
|
return zip.toBuffer();
|
|
3798
4116
|
}
|
|
4117
|
+
var DRAWING_PART, RANK;
|
|
3799
4118
|
var init_fixFloatingImageIds = __esm({
|
|
3800
4119
|
"src/utils/fixFloatingImageIds.ts"() {
|
|
3801
4120
|
"use strict";
|
|
4121
|
+
DRAWING_PART = /^word\/(document|header|footer|footnotes|endnotes|comments)(\d*)\.xml$/;
|
|
4122
|
+
RANK = [
|
|
4123
|
+
"document",
|
|
4124
|
+
"header",
|
|
4125
|
+
"footer",
|
|
4126
|
+
"footnotes",
|
|
4127
|
+
"endnotes",
|
|
4128
|
+
"comments"
|
|
4129
|
+
];
|
|
4130
|
+
}
|
|
4131
|
+
});
|
|
4132
|
+
|
|
4133
|
+
// src/renderers/docxjs/presetShapes.ts
|
|
4134
|
+
function docxPresetShape(geometry) {
|
|
4135
|
+
const name = Object.hasOwn(OOXML_PRESET_TO_DOCX, geometry) ? OOXML_PRESET_TO_DOCX[geometry] : void 0;
|
|
4136
|
+
if (!name) {
|
|
4137
|
+
throw new Error(
|
|
4138
|
+
`the docxjs renderer has no preset for the OOXML geometry "${geometry}"`
|
|
4139
|
+
);
|
|
4140
|
+
}
|
|
4141
|
+
return name;
|
|
4142
|
+
}
|
|
4143
|
+
function docxLineDash(dash) {
|
|
4144
|
+
const name = Object.hasOwn(OOXML_DASH_TO_DOCX, dash) ? OOXML_DASH_TO_DOCX[dash] : void 0;
|
|
4145
|
+
if (!name) {
|
|
4146
|
+
throw new Error(
|
|
4147
|
+
`the docxjs renderer has no line dash for the OOXML value "${dash}"`
|
|
4148
|
+
);
|
|
4149
|
+
}
|
|
4150
|
+
return name;
|
|
4151
|
+
}
|
|
4152
|
+
var OOXML_PRESET_TO_DOCX, OOXML_DASH_TO_DOCX;
|
|
4153
|
+
var init_presetShapes = __esm({
|
|
4154
|
+
"src/renderers/docxjs/presetShapes.ts"() {
|
|
4155
|
+
"use strict";
|
|
4156
|
+
OOXML_PRESET_TO_DOCX = {
|
|
4157
|
+
line: "line",
|
|
4158
|
+
lineInv: "inverseLine",
|
|
4159
|
+
straightConnector1: "straightConnector",
|
|
4160
|
+
bentConnector2: "elbowConnectorOneBend",
|
|
4161
|
+
bentConnector3: "elbowConnector",
|
|
4162
|
+
bentConnector4: "elbowConnectorThreeBends",
|
|
4163
|
+
bentConnector5: "elbowConnectorFourBends",
|
|
4164
|
+
curvedConnector2: "curvedConnectorOneBend",
|
|
4165
|
+
curvedConnector3: "curvedConnector",
|
|
4166
|
+
curvedConnector4: "curvedConnectorThreeBends",
|
|
4167
|
+
curvedConnector5: "curvedConnectorFourBends",
|
|
4168
|
+
triangle: "triangle",
|
|
4169
|
+
rtTriangle: "rightTriangle",
|
|
4170
|
+
diamond: "diamond",
|
|
4171
|
+
parallelogram: "parallelogram",
|
|
4172
|
+
trapezoid: "trapezoid",
|
|
4173
|
+
nonIsoscelesTrapezoid: "nonIsoscelesTrapezoid",
|
|
4174
|
+
pentagon: "pentagon",
|
|
4175
|
+
hexagon: "hexagon",
|
|
4176
|
+
heptagon: "heptagon",
|
|
4177
|
+
octagon: "octagon",
|
|
4178
|
+
decagon: "decagon",
|
|
4179
|
+
dodecagon: "dodecagon",
|
|
4180
|
+
ellipse: "ellipse",
|
|
4181
|
+
teardrop: "teardrop",
|
|
4182
|
+
pieWedge: "pieWedge",
|
|
4183
|
+
pie: "pie",
|
|
4184
|
+
blockArc: "blockArc",
|
|
4185
|
+
donut: "donut",
|
|
4186
|
+
noSmoking: "noSymbol",
|
|
4187
|
+
chord: "chord",
|
|
4188
|
+
arc: "arc",
|
|
4189
|
+
frame: "frame",
|
|
4190
|
+
halfFrame: "halfFrame",
|
|
4191
|
+
corner: "lShape",
|
|
4192
|
+
diagStripe: "diagonalStripe",
|
|
4193
|
+
plus: "cross",
|
|
4194
|
+
plaque: "plaque",
|
|
4195
|
+
can: "cylinder",
|
|
4196
|
+
cube: "cube",
|
|
4197
|
+
bevel: "beveledRectangle",
|
|
4198
|
+
foldedCorner: "foldedCorner",
|
|
4199
|
+
smileyFace: "smileyFace",
|
|
4200
|
+
heart: "heart",
|
|
4201
|
+
lightningBolt: "lightningBolt",
|
|
4202
|
+
sun: "sun",
|
|
4203
|
+
moon: "moon",
|
|
4204
|
+
cloud: "cloud",
|
|
4205
|
+
leftBracket: "leftBracket",
|
|
4206
|
+
rightBracket: "rightBracket",
|
|
4207
|
+
leftBrace: "leftBrace",
|
|
4208
|
+
rightBrace: "rightBrace",
|
|
4209
|
+
bracketPair: "bracketPair",
|
|
4210
|
+
bracePair: "bracePair",
|
|
4211
|
+
rect: "rectangle",
|
|
4212
|
+
roundRect: "roundedRectangle",
|
|
4213
|
+
round1Rect: "roundedCornerRectangle",
|
|
4214
|
+
round2SameRect: "topRoundedCornersRectangle",
|
|
4215
|
+
round2DiagRect: "diagonalRoundedCornersRectangle",
|
|
4216
|
+
snip1Rect: "snippedCornerRectangle",
|
|
4217
|
+
snip2SameRect: "topSnippedCornersRectangle",
|
|
4218
|
+
snip2DiagRect: "diagonalSnippedCornersRectangle",
|
|
4219
|
+
snipRoundRect: "roundedAndSnippedCornersRectangle",
|
|
4220
|
+
rightArrow: "rightArrow",
|
|
4221
|
+
leftArrow: "leftArrow",
|
|
4222
|
+
upArrow: "upArrow",
|
|
4223
|
+
downArrow: "downArrow",
|
|
4224
|
+
leftRightArrow: "leftRightArrow",
|
|
4225
|
+
upDownArrow: "upDownArrow",
|
|
4226
|
+
quadArrow: "quadArrow",
|
|
4227
|
+
leftRightUpArrow: "leftRightUpArrow",
|
|
4228
|
+
bentArrow: "bentArrow",
|
|
4229
|
+
uturnArrow: "uTurnArrow",
|
|
4230
|
+
leftUpArrow: "leftUpArrow",
|
|
4231
|
+
bentUpArrow: "bentUpArrow",
|
|
4232
|
+
curvedRightArrow: "curvedRightArrow",
|
|
4233
|
+
curvedLeftArrow: "curvedLeftArrow",
|
|
4234
|
+
curvedUpArrow: "curvedUpArrow",
|
|
4235
|
+
curvedDownArrow: "curvedDownArrow",
|
|
4236
|
+
stripedRightArrow: "stripedRightArrow",
|
|
4237
|
+
notchedRightArrow: "notchedRightArrow",
|
|
4238
|
+
homePlate: "pentagonArrow",
|
|
4239
|
+
chevron: "chevron",
|
|
4240
|
+
rightArrowCallout: "rightArrowCallout",
|
|
4241
|
+
downArrowCallout: "downArrowCallout",
|
|
4242
|
+
leftArrowCallout: "leftArrowCallout",
|
|
4243
|
+
upArrowCallout: "upArrowCallout",
|
|
4244
|
+
leftRightArrowCallout: "leftRightArrowCallout",
|
|
4245
|
+
upDownArrowCallout: "upDownArrowCallout",
|
|
4246
|
+
quadArrowCallout: "quadArrowCallout",
|
|
4247
|
+
circularArrow: "circularArrow",
|
|
4248
|
+
leftCircularArrow: "leftCircularArrow",
|
|
4249
|
+
leftRightCircularArrow: "leftRightCircularArrow",
|
|
4250
|
+
swooshArrow: "swooshArrow",
|
|
4251
|
+
mathPlus: "mathPlus",
|
|
4252
|
+
mathMinus: "mathMinus",
|
|
4253
|
+
mathMultiply: "mathMultiply",
|
|
4254
|
+
mathDivide: "mathDivide",
|
|
4255
|
+
mathEqual: "mathEqual",
|
|
4256
|
+
mathNotEqual: "mathNotEqual",
|
|
4257
|
+
flowChartProcess: "flowChartProcess",
|
|
4258
|
+
flowChartAlternateProcess: "flowChartAlternateProcess",
|
|
4259
|
+
flowChartDecision: "flowChartDecision",
|
|
4260
|
+
flowChartInputOutput: "flowChartInputOutput",
|
|
4261
|
+
flowChartPredefinedProcess: "flowChartPredefinedProcess",
|
|
4262
|
+
flowChartInternalStorage: "flowChartInternalStorage",
|
|
4263
|
+
flowChartDocument: "flowChartDocument",
|
|
4264
|
+
flowChartMultidocument: "flowChartMultidocument",
|
|
4265
|
+
flowChartTerminator: "flowChartTerminator",
|
|
4266
|
+
flowChartPreparation: "flowChartPreparation",
|
|
4267
|
+
flowChartManualInput: "flowChartManualInput",
|
|
4268
|
+
flowChartManualOperation: "flowChartManualOperation",
|
|
4269
|
+
flowChartConnector: "flowChartConnector",
|
|
4270
|
+
flowChartOffpageConnector: "flowChartOffpageConnector",
|
|
4271
|
+
flowChartPunchedCard: "flowChartPunchedCard",
|
|
4272
|
+
flowChartPunchedTape: "flowChartPunchedTape",
|
|
4273
|
+
flowChartSummingJunction: "flowChartSummingJunction",
|
|
4274
|
+
flowChartOr: "flowChartOr",
|
|
4275
|
+
flowChartCollate: "flowChartCollate",
|
|
4276
|
+
flowChartSort: "flowChartSort",
|
|
4277
|
+
flowChartExtract: "flowChartExtract",
|
|
4278
|
+
flowChartMerge: "flowChartMerge",
|
|
4279
|
+
flowChartOfflineStorage: "flowChartOfflineStorage",
|
|
4280
|
+
flowChartOnlineStorage: "flowChartOnlineStorage",
|
|
4281
|
+
flowChartDelay: "flowChartDelay",
|
|
4282
|
+
flowChartMagneticTape: "flowChartMagneticTape",
|
|
4283
|
+
flowChartMagneticDisk: "flowChartMagneticDisk",
|
|
4284
|
+
flowChartMagneticDrum: "flowChartMagneticDrum",
|
|
4285
|
+
flowChartDisplay: "flowChartDisplay",
|
|
4286
|
+
irregularSeal1: "explosion12",
|
|
4287
|
+
irregularSeal2: "explosion14",
|
|
4288
|
+
star4: "star4",
|
|
4289
|
+
star5: "star5",
|
|
4290
|
+
star6: "star6",
|
|
4291
|
+
star7: "star7",
|
|
4292
|
+
star8: "star8",
|
|
4293
|
+
star10: "star10",
|
|
4294
|
+
star12: "star12",
|
|
4295
|
+
star16: "star16",
|
|
4296
|
+
star24: "star24",
|
|
4297
|
+
star32: "star32",
|
|
4298
|
+
ribbon2: "ribbonUp",
|
|
4299
|
+
ribbon: "ribbonDown",
|
|
4300
|
+
ellipseRibbon2: "curvedRibbonUp",
|
|
4301
|
+
ellipseRibbon: "curvedRibbonDown",
|
|
4302
|
+
leftRightRibbon: "leftRightRibbon",
|
|
4303
|
+
verticalScroll: "verticalScroll",
|
|
4304
|
+
horizontalScroll: "horizontalScroll",
|
|
4305
|
+
wave: "wave",
|
|
4306
|
+
doubleWave: "doubleWave",
|
|
4307
|
+
wedgeRectCallout: "rectangularCallout",
|
|
4308
|
+
wedgeRoundRectCallout: "roundedRectangularCallout",
|
|
4309
|
+
wedgeEllipseCallout: "ellipticalCallout",
|
|
4310
|
+
cloudCallout: "cloudCallout",
|
|
4311
|
+
borderCallout1: "lineCallout",
|
|
4312
|
+
borderCallout2: "bentLineCallout",
|
|
4313
|
+
borderCallout3: "doubleBentLineCallout",
|
|
4314
|
+
accentCallout1: "lineCalloutWithAccentBar",
|
|
4315
|
+
accentCallout2: "bentLineCalloutWithAccentBar",
|
|
4316
|
+
accentCallout3: "doubleBentLineCalloutWithAccentBar",
|
|
4317
|
+
callout1: "lineCalloutWithNoBorder",
|
|
4318
|
+
callout2: "bentLineCalloutWithNoBorder",
|
|
4319
|
+
callout3: "doubleBentLineCalloutWithNoBorder",
|
|
4320
|
+
accentBorderCallout1: "lineCalloutWithBorderAndAccentBar",
|
|
4321
|
+
accentBorderCallout2: "bentLineCalloutWithBorderAndAccentBar",
|
|
4322
|
+
accentBorderCallout3: "doubleBentLineCalloutWithBorderAndAccentBar",
|
|
4323
|
+
actionButtonBlank: "actionButtonBlank",
|
|
4324
|
+
actionButtonHome: "actionButtonHome",
|
|
4325
|
+
actionButtonHelp: "actionButtonHelp",
|
|
4326
|
+
actionButtonInformation: "actionButtonInformation",
|
|
4327
|
+
actionButtonForwardNext: "actionButtonForwardNext",
|
|
4328
|
+
actionButtonBackPrevious: "actionButtonBackPrevious",
|
|
4329
|
+
actionButtonEnd: "actionButtonEnd",
|
|
4330
|
+
actionButtonBeginning: "actionButtonBeginning",
|
|
4331
|
+
actionButtonReturn: "actionButtonReturn",
|
|
4332
|
+
actionButtonDocument: "actionButtonDocument",
|
|
4333
|
+
actionButtonSound: "actionButtonSound",
|
|
4334
|
+
actionButtonMovie: "actionButtonMovie",
|
|
4335
|
+
gear6: "gear6",
|
|
4336
|
+
gear9: "gear9",
|
|
4337
|
+
funnel: "funnel",
|
|
4338
|
+
cornerTabs: "cornerTabs",
|
|
4339
|
+
squareTabs: "squareTabs",
|
|
4340
|
+
plaqueTabs: "plaqueTabs",
|
|
4341
|
+
chartX: "chartX",
|
|
4342
|
+
chartStar: "chartStar",
|
|
4343
|
+
chartPlus: "chartPlus"
|
|
4344
|
+
};
|
|
4345
|
+
OOXML_DASH_TO_DOCX = {
|
|
4346
|
+
solid: "solid",
|
|
4347
|
+
dot: "dot",
|
|
4348
|
+
dash: "dash",
|
|
4349
|
+
lgDash: "longDash",
|
|
4350
|
+
dashDot: "dashDot",
|
|
4351
|
+
lgDashDot: "longDashDot",
|
|
4352
|
+
lgDashDotDot: "longDashDotDot",
|
|
4353
|
+
sysDash: "shortDash",
|
|
4354
|
+
sysDot: "shortDot",
|
|
4355
|
+
sysDashDot: "shortDashDot",
|
|
4356
|
+
sysDashDotDot: "shortDashDotDot"
|
|
4357
|
+
};
|
|
4358
|
+
}
|
|
4359
|
+
});
|
|
4360
|
+
|
|
4361
|
+
// src/renderers/docxjs/drawingGroup.ts
|
|
4362
|
+
function chooseMarkers(ir) {
|
|
4363
|
+
const strings = [];
|
|
4364
|
+
collectStrings(ir, strings, /* @__PURE__ */ new WeakSet());
|
|
4365
|
+
const unused = (base) => {
|
|
4366
|
+
for (let n = 0; ; n += 1) {
|
|
4367
|
+
const candidate = n === 0 ? base : `${base}-${n}`;
|
|
4368
|
+
if (!strings.some((value) => value.includes(candidate))) return candidate;
|
|
4369
|
+
}
|
|
4370
|
+
};
|
|
4371
|
+
return {
|
|
4372
|
+
noAltText: unused(DEFAULT_MARKERS.noAltText),
|
|
4373
|
+
textBox: unused(DEFAULT_MARKERS.textBox)
|
|
4374
|
+
};
|
|
4375
|
+
}
|
|
4376
|
+
function collectStrings(node, out, seen) {
|
|
4377
|
+
if (typeof node === "string") {
|
|
4378
|
+
out.push(node);
|
|
4379
|
+
return;
|
|
4380
|
+
}
|
|
4381
|
+
if (!node || typeof node !== "object") return;
|
|
4382
|
+
if (node instanceof ArrayBuffer || ArrayBuffer.isView(node)) return;
|
|
4383
|
+
if (seen.has(node)) return;
|
|
4384
|
+
seen.add(node);
|
|
4385
|
+
if (node instanceof Map) {
|
|
4386
|
+
for (const [key, value] of node) {
|
|
4387
|
+
collectStrings(key, out, seen);
|
|
4388
|
+
collectStrings(value, out, seen);
|
|
4389
|
+
}
|
|
4390
|
+
return;
|
|
4391
|
+
}
|
|
4392
|
+
if (node instanceof Set) {
|
|
4393
|
+
for (const value of node) collectStrings(value, out, seen);
|
|
4394
|
+
return;
|
|
4395
|
+
}
|
|
4396
|
+
for (const value of Object.values(node)) collectStrings(value, out, seen);
|
|
4397
|
+
}
|
|
4398
|
+
function createDrawingGroupFactory(shapes2, pictures, markers) {
|
|
4399
|
+
return (group, resources) => new shapes2.ShapeGroupRun(
|
|
4400
|
+
drawingGroupOptions(group, resources, pictures, markers)
|
|
4401
|
+
);
|
|
4402
|
+
}
|
|
4403
|
+
function drawingGroupOptions(group, resources, pictures, markers = DEFAULT_MARKERS) {
|
|
4404
|
+
const canvasWidth = group.canvasWidthEmu;
|
|
4405
|
+
const canvasHeight = group.canvasHeightEmu;
|
|
4406
|
+
const near = (value, edge) => Math.abs(value - edge) <= OVERFLOW_TOLERANCE_EMU;
|
|
4407
|
+
const bounds = unrotatedBounds(group.children);
|
|
4408
|
+
const fillsCanvas = bounds !== void 0 && near(bounds.left, 0) && near(bounds.top, 0) && near(bounds.right, canvasWidth) && near(bounds.bottom, canvasHeight);
|
|
4409
|
+
const union = {
|
|
4410
|
+
left: Math.min(0, bounds?.left ?? 0),
|
|
4411
|
+
top: Math.min(0, bounds?.top ?? 0),
|
|
4412
|
+
right: Math.max(canvasWidth, bounds?.right ?? 0),
|
|
4413
|
+
bottom: Math.max(canvasHeight, bounds?.bottom ?? 0)
|
|
4414
|
+
};
|
|
4415
|
+
const overflows = union.left < -OVERFLOW_TOLERANCE_EMU || union.top < -OVERFLOW_TOLERANCE_EMU || union.right > canvasWidth + OVERFLOW_TOLERANCE_EMU || union.bottom > canvasHeight + OVERFLOW_TOLERANCE_EMU;
|
|
4416
|
+
const widthEmu = overflows ? (union.right - union.left) * group.widthEmu / canvasWidth : group.widthEmu;
|
|
4417
|
+
const heightEmu = overflows ? (union.bottom - union.top) * group.heightEmu / canvasHeight : group.heightEmu;
|
|
4418
|
+
return {
|
|
4419
|
+
children: [
|
|
4420
|
+
...fillsCanvas ? [] : [canvasPad(canvasWidth, canvasHeight)],
|
|
4421
|
+
...group.children.map(
|
|
4422
|
+
(child, index) => groupChild(child, index, resources, pictures, markers)
|
|
4423
|
+
)
|
|
4424
|
+
],
|
|
4425
|
+
transformation: {
|
|
4426
|
+
width: emuToPixels(widthEmu),
|
|
4427
|
+
height: emuToPixels(heightEmu)
|
|
4428
|
+
},
|
|
4429
|
+
// `||`, not `??`: docx treats '' as no description too, and would then
|
|
4430
|
+
// describe the diagram from the child names.
|
|
4431
|
+
altText: { name: "", description: group.altText || markers.noAltText },
|
|
4432
|
+
...group.floating ? { floating: floatingOptions(group.floating) } : {}
|
|
4433
|
+
};
|
|
4434
|
+
}
|
|
4435
|
+
function groupChild(child, index, resources, pictures, markers) {
|
|
4436
|
+
return child.kind === "picture" ? pictureChild(child, index, pictures) : shapeChild(child, index, resources, markers);
|
|
4437
|
+
}
|
|
4438
|
+
function canvasPad(canvasWidthEmu, canvasHeightEmu) {
|
|
4439
|
+
return {
|
|
4440
|
+
type: "rectangle",
|
|
4441
|
+
transformation: {
|
|
4442
|
+
offset: { left: 0, top: 0 },
|
|
4443
|
+
width: emuToPixels(canvasWidthEmu),
|
|
4444
|
+
height: emuToPixels(canvasHeightEmu)
|
|
4445
|
+
},
|
|
4446
|
+
fill: "none",
|
|
4447
|
+
line: "none",
|
|
4448
|
+
decorative: true,
|
|
4449
|
+
altText: { name: "Canvas" }
|
|
4450
|
+
};
|
|
4451
|
+
}
|
|
4452
|
+
function childTransformation(frame) {
|
|
4453
|
+
const rotation2 = frame.rotationDegrees;
|
|
4454
|
+
return {
|
|
4455
|
+
offset: { left: emuToPixels(frame.xEmu), top: emuToPixels(frame.yEmu) },
|
|
4456
|
+
width: emuToPixels(frame.widthEmu),
|
|
4457
|
+
height: emuToPixels(frame.heightEmu),
|
|
4458
|
+
...rotation2 !== void 0 && rotation2 % 360 !== 0 ? { rotation: rotation2 } : {},
|
|
4459
|
+
...frame.flipHorizontal || frame.flipVertical ? {
|
|
4460
|
+
flip: {
|
|
4461
|
+
...frame.flipHorizontal ? { horizontal: true } : {},
|
|
4462
|
+
...frame.flipVertical ? { vertical: true } : {}
|
|
4463
|
+
}
|
|
4464
|
+
} : {}
|
|
4465
|
+
};
|
|
4466
|
+
}
|
|
4467
|
+
function shapeChild(shape, index, resources, markers) {
|
|
4468
|
+
const paragraphs = shape.text?.paragraphs ?? [];
|
|
4469
|
+
return {
|
|
4470
|
+
type: docxPresetShape(shape.geometry),
|
|
4471
|
+
transformation: childTransformation(shape.frame),
|
|
4472
|
+
fill: shapeFill(shape.fill),
|
|
4473
|
+
line: shapeLine(shape.outline),
|
|
4474
|
+
altText: {
|
|
4475
|
+
name: shape.name ?? `Shape ${index + 1}`,
|
|
4476
|
+
...shape.isTextBox ? { title: markers.textBox } : {}
|
|
4477
|
+
},
|
|
4478
|
+
// Never `children: []`: docx would write an empty `w:txbxContent`, which
|
|
4479
|
+
// the schema does not allow.
|
|
4480
|
+
...paragraphs.length > 0 ? {
|
|
4481
|
+
children: paragraphs.map(
|
|
4482
|
+
(paragraph2) => emitParagraph(paragraph2, resources)
|
|
4483
|
+
)
|
|
4484
|
+
} : {},
|
|
4485
|
+
...shape.text ? { textOptions: textOptions(shape.text) } : {}
|
|
4486
|
+
};
|
|
4487
|
+
}
|
|
4488
|
+
function pictureChild(picture2, index, pictures) {
|
|
4489
|
+
const crop = picture2.crop;
|
|
4490
|
+
return {
|
|
4491
|
+
type: "picture",
|
|
4492
|
+
image: pictures(picture2.resourceId, {
|
|
4493
|
+
widthEmu: picture2.frame.widthEmu,
|
|
4494
|
+
heightEmu: picture2.frame.heightEmu
|
|
4495
|
+
}),
|
|
4496
|
+
transformation: childTransformation(picture2.frame),
|
|
4497
|
+
...crop ? {
|
|
4498
|
+
crop: {
|
|
4499
|
+
...crop.left !== void 0 ? { left: crop.left * 100 } : {},
|
|
4500
|
+
...crop.top !== void 0 ? { top: crop.top * 100 } : {},
|
|
4501
|
+
...crop.right !== void 0 ? { right: crop.right * 100 } : {},
|
|
4502
|
+
...crop.bottom !== void 0 ? { bottom: crop.bottom * 100 } : {}
|
|
4503
|
+
}
|
|
4504
|
+
} : {},
|
|
4505
|
+
altText: {
|
|
4506
|
+
name: picture2.name ?? `Picture ${index + 1}`,
|
|
4507
|
+
...picture2.altText ? { description: picture2.altText } : {}
|
|
4508
|
+
}
|
|
4509
|
+
};
|
|
4510
|
+
}
|
|
4511
|
+
function shapeFill(fill) {
|
|
4512
|
+
if (!fill || fill.kind === "none") return "none";
|
|
4513
|
+
return {
|
|
4514
|
+
type: "solid",
|
|
4515
|
+
color: fill.color.hex,
|
|
4516
|
+
...fill.transparencyPercent !== void 0 ? { transparency: clamp(fill.transparencyPercent, 0, 100) } : {}
|
|
4517
|
+
};
|
|
4518
|
+
}
|
|
4519
|
+
function shapeLine(outline) {
|
|
4520
|
+
if (!outline || !outline.color) return "none";
|
|
4521
|
+
return {
|
|
4522
|
+
color: outline.color.hex,
|
|
4523
|
+
// An omitted width is office-open's omitted `w`, a hairline, where docx's
|
|
4524
|
+
// own default would be 1pt.
|
|
4525
|
+
width: outline.widthEmu !== void 0 ? clamp(outline.widthEmu / EMU_PER_POINT, 0, MAX_POINTS) : 0,
|
|
4526
|
+
...outline.dash ? { dash: docxLineDash(outline.dash) } : {}
|
|
4527
|
+
};
|
|
4528
|
+
}
|
|
4529
|
+
function textOptions(text) {
|
|
4530
|
+
const insets = text.insetsEmu;
|
|
4531
|
+
const points = (emu) => clamp(emu / EMU_PER_POINT, 0, MAX_POINTS);
|
|
4532
|
+
const margins = insets ? {
|
|
4533
|
+
...insets.top !== void 0 ? { top: points(insets.top) } : {},
|
|
4534
|
+
...insets.right !== void 0 ? { right: points(insets.right) } : {},
|
|
4535
|
+
...insets.bottom !== void 0 ? { bottom: points(insets.bottom) } : {},
|
|
4536
|
+
...insets.left !== void 0 ? { left: points(insets.left) } : {}
|
|
4537
|
+
} : void 0;
|
|
4538
|
+
return {
|
|
4539
|
+
verticalAlignment: VERTICAL_ALIGNMENT[text.anchor ?? "top"],
|
|
4540
|
+
...margins && Object.keys(margins).length > 0 ? { margins } : {}
|
|
4541
|
+
};
|
|
4542
|
+
}
|
|
4543
|
+
function unrotatedBounds(children) {
|
|
4544
|
+
if (children.length === 0) return void 0;
|
|
4545
|
+
let left = Infinity;
|
|
4546
|
+
let top = Infinity;
|
|
4547
|
+
let right = -Infinity;
|
|
4548
|
+
let bottom = -Infinity;
|
|
4549
|
+
for (const { frame } of children) {
|
|
4550
|
+
left = Math.min(left, frame.xEmu);
|
|
4551
|
+
top = Math.min(top, frame.yEmu);
|
|
4552
|
+
right = Math.max(right, frame.xEmu + frame.widthEmu);
|
|
4553
|
+
bottom = Math.max(bottom, frame.yEmu + frame.heightEmu);
|
|
4554
|
+
}
|
|
4555
|
+
return { left, top, right, bottom };
|
|
4556
|
+
}
|
|
4557
|
+
function clamp(value, low, high) {
|
|
4558
|
+
return Math.min(high, Math.max(low, value));
|
|
4559
|
+
}
|
|
4560
|
+
var DEFAULT_MARKERS, EMU_PER_POINT, MAX_POINTS, OVERFLOW_TOLERANCE_EMU, VERTICAL_ALIGNMENT;
|
|
4561
|
+
var init_drawingGroup = __esm({
|
|
4562
|
+
"src/renderers/docxjs/drawingGroup.ts"() {
|
|
4563
|
+
"use strict";
|
|
4564
|
+
init_units();
|
|
4565
|
+
init_emit();
|
|
4566
|
+
init_presetShapes();
|
|
4567
|
+
DEFAULT_MARKERS = {
|
|
4568
|
+
noAltText: "jto:no-alt-text",
|
|
4569
|
+
textBox: "jto:text-box"
|
|
4570
|
+
};
|
|
4571
|
+
EMU_PER_POINT = 12700;
|
|
4572
|
+
MAX_POINTS = 1584;
|
|
4573
|
+
OVERFLOW_TOLERANCE_EMU = 2;
|
|
4574
|
+
VERTICAL_ALIGNMENT = {
|
|
4575
|
+
top: "top",
|
|
4576
|
+
middle: "center",
|
|
4577
|
+
bottom: "bottom"
|
|
4578
|
+
};
|
|
4579
|
+
}
|
|
4580
|
+
});
|
|
4581
|
+
|
|
4582
|
+
// src/renderers/docxjs/drawingGroupRepair.ts
|
|
4583
|
+
import AdmZip3 from "adm-zip";
|
|
4584
|
+
function repairDrawingGroupsInBuffer(buffer, markers) {
|
|
4585
|
+
const textBox = new RegExp(
|
|
4586
|
+
`(<wps:cNvPr\\b[^>]*?) title="${escapeRegExp2(markers.textBox)}"(\\s*/>)<wps:cNvSpPr/>`,
|
|
4587
|
+
"g"
|
|
4588
|
+
);
|
|
4589
|
+
const noAltText = new RegExp(
|
|
4590
|
+
`(<wp:docPr\\b[^>]*?) descr="${escapeRegExp2(markers.noAltText)}"`,
|
|
4591
|
+
"g"
|
|
4592
|
+
);
|
|
4593
|
+
const zip = new AdmZip3(buffer);
|
|
4594
|
+
const parts = zip.getEntries().filter((entry) => DRAWING_PART.test(entry.entryName)).sort((a, b) => compareDrawingParts(a.entryName, b.entryName));
|
|
4595
|
+
const texts = new Map(
|
|
4596
|
+
parts.map((entry) => [entry, entry.getData().toString("utf8")])
|
|
4597
|
+
);
|
|
4598
|
+
let highest = 0;
|
|
4599
|
+
for (const xml of texts.values()) {
|
|
4600
|
+
for (const match of xml.matchAll(DOC_PR_ID)) {
|
|
4601
|
+
highest = Math.max(highest, Number(match[1]));
|
|
4602
|
+
}
|
|
4603
|
+
for (const match of xml.replace(GROUP, "").matchAll(CNVPR_ID)) {
|
|
4604
|
+
highest = Math.max(highest, Number(match[1]));
|
|
4605
|
+
}
|
|
4606
|
+
}
|
|
4607
|
+
let next = highest + 1;
|
|
4608
|
+
for (const [entry, xml] of texts) {
|
|
4609
|
+
if (!xml.includes("<wpg:wgp")) continue;
|
|
4610
|
+
const repaired = xml.replace(
|
|
4611
|
+
GROUP,
|
|
4612
|
+
(span) => span.replace(CHILD_ID, (_match, head) => `${head}id="${next++}"`).replace(
|
|
4613
|
+
ROTATION,
|
|
4614
|
+
(_match, head, value) => `${head}rot="${Math.round(Number(value))}"`
|
|
4615
|
+
).replace(textBox, '$1$2<wps:cNvSpPr txBox="1"/>')
|
|
4616
|
+
).replace(noAltText, "$1");
|
|
4617
|
+
texts.set(entry, repaired);
|
|
4618
|
+
zip.updateFile(entry, Buffer.from(repaired, "utf8"));
|
|
4619
|
+
}
|
|
4620
|
+
for (const [entry, xml] of texts) {
|
|
4621
|
+
if (xml.includes(markers.noAltText) || xml.includes(markers.textBox)) {
|
|
4622
|
+
throw new Error(
|
|
4623
|
+
`the drawing-group repair left a marker in ${entry.entryName}`
|
|
4624
|
+
);
|
|
4625
|
+
}
|
|
4626
|
+
}
|
|
4627
|
+
return zip.toBuffer();
|
|
4628
|
+
}
|
|
4629
|
+
var GROUP, DOC_PR_ID, CNVPR_ID, CHILD_ID, ROTATION, escapeRegExp2;
|
|
4630
|
+
var init_drawingGroupRepair = __esm({
|
|
4631
|
+
"src/renderers/docxjs/drawingGroupRepair.ts"() {
|
|
4632
|
+
"use strict";
|
|
4633
|
+
init_fixFloatingImageIds();
|
|
4634
|
+
GROUP = /<wpg:wgp\b[^>]*>[\s\S]*?<\/wpg:wgp>/g;
|
|
4635
|
+
DOC_PR_ID = /<wp:docPr\b[^>]*?\sid="(\d+)"/g;
|
|
4636
|
+
CNVPR_ID = /<(?:wps|pic|wpg):cNvPr\b[^>]*?\sid="(\d+)"/g;
|
|
4637
|
+
CHILD_ID = /(<(?:wps|pic|wpg):cNvPr\b[^>]*?\s)id="\d+"/g;
|
|
4638
|
+
ROTATION = /(<a:xfrm\b[^>]*?\s)rot="([^"]*)"/g;
|
|
4639
|
+
escapeRegExp2 = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3802
4640
|
}
|
|
3803
4641
|
});
|
|
3804
4642
|
|
|
@@ -3827,18 +4665,32 @@ function createDocxJsRenderer() {
|
|
|
3827
4665
|
format: "docx",
|
|
3828
4666
|
capabilities: DOCXJS_CAPABILITIES,
|
|
3829
4667
|
async render(ir, renderOptions) {
|
|
3830
|
-
|
|
4668
|
+
await loadDocxCharts();
|
|
4669
|
+
const prepared = await prepareImages(
|
|
3831
4670
|
ir,
|
|
3832
4671
|
renderOptions?.svgRasterFallback
|
|
3833
4672
|
);
|
|
4673
|
+
const markers = prepared.drawingGroups > 0 ? chooseMarkers(ir) : void 0;
|
|
4674
|
+
let resources = prepared.images;
|
|
4675
|
+
if (markers) {
|
|
4676
|
+
await shapes.load();
|
|
4677
|
+
resources = Object.assign(prepared.images, {
|
|
4678
|
+
drawingGroup: createDrawingGroupFactory(
|
|
4679
|
+
shapes.get(),
|
|
4680
|
+
prepared.pictureSource,
|
|
4681
|
+
markers
|
|
4682
|
+
)
|
|
4683
|
+
});
|
|
4684
|
+
}
|
|
3834
4685
|
const document = buildDocument(ir, resources);
|
|
3835
4686
|
const packed = await Packer.toBuffer(document);
|
|
3836
4687
|
const fixed = fixFloatingImageIdsInBuffer(packed);
|
|
4688
|
+
const repaired = markers ? repairDrawingGroupsInBuffer(fixed, markers) : fixed;
|
|
3837
4689
|
if (renderOptions?.deterministic === false)
|
|
3838
|
-
return new Uint8Array(normalizeDocxCaseBuffer(
|
|
4690
|
+
return new Uint8Array(normalizeDocxCaseBuffer(repaired));
|
|
3839
4691
|
return new Uint8Array(
|
|
3840
4692
|
canonicalizeDocxBuffer(
|
|
3841
|
-
|
|
4693
|
+
repaired,
|
|
3842
4694
|
resolveGenerationDate({
|
|
3843
4695
|
deterministic: renderOptions?.deterministic,
|
|
3844
4696
|
generatedAt: renderOptions?.generatedAt
|
|
@@ -3851,6 +4703,7 @@ function createDocxJsRenderer() {
|
|
|
3851
4703
|
function buildDocument(ir, resources = /* @__PURE__ */ new Map()) {
|
|
3852
4704
|
return new Document({
|
|
3853
4705
|
styles: emitStyles(ir.styles),
|
|
4706
|
+
...ir.theme ? { theme: themeOptions(ir.theme) } : {},
|
|
3854
4707
|
sections: ir.sections.map(
|
|
3855
4708
|
(section2, index) => sectionOptions(section2, resources, index === ir.sections.length - 1)
|
|
3856
4709
|
),
|
|
@@ -3882,6 +4735,21 @@ function buildDocument(ir, resources = /* @__PURE__ */ new Map()) {
|
|
|
3882
4735
|
} : {}
|
|
3883
4736
|
});
|
|
3884
4737
|
}
|
|
4738
|
+
function themeOptions(theme) {
|
|
4739
|
+
const colors = {};
|
|
4740
|
+
for (const [slot, color] of Object.entries(theme.colors)) {
|
|
4741
|
+
if (color) colors[slot] = color.hex;
|
|
4742
|
+
}
|
|
4743
|
+
const fonts = {
|
|
4744
|
+
...theme.headingFont ? { headings: theme.headingFont } : {},
|
|
4745
|
+
...theme.bodyFont ? { body: theme.bodyFont } : {}
|
|
4746
|
+
};
|
|
4747
|
+
return {
|
|
4748
|
+
name: theme.name,
|
|
4749
|
+
...Object.keys(colors).length > 0 ? { colors } : {},
|
|
4750
|
+
...Object.keys(fonts).length > 0 ? { fonts } : {}
|
|
4751
|
+
};
|
|
4752
|
+
}
|
|
3885
4753
|
function noteBodies(notes, resources) {
|
|
3886
4754
|
const bodies = {};
|
|
3887
4755
|
for (const note of notes) {
|
|
@@ -3919,7 +4787,7 @@ function numberingConfig(numbering) {
|
|
|
3919
4787
|
};
|
|
3920
4788
|
}
|
|
3921
4789
|
async function prepareImages(ir, svgRasterFallback) {
|
|
3922
|
-
const placements = collectImagePlacements(ir);
|
|
4790
|
+
const { placements, drawingGroups } = collectImagePlacements(ir);
|
|
3923
4791
|
const jobs = [];
|
|
3924
4792
|
for (const resource of ir.resources) {
|
|
3925
4793
|
if (resource.kind !== "image" || resource.mediaType !== "svg") continue;
|
|
@@ -3967,16 +4835,55 @@ async function prepareImages(ir, svgRasterFallback) {
|
|
|
3967
4835
|
});
|
|
3968
4836
|
});
|
|
3969
4837
|
}
|
|
3970
|
-
|
|
4838
|
+
const pictureSource = (resourceId, placement) => {
|
|
4839
|
+
const resource = ir.resources.find(
|
|
4840
|
+
(candidate) => candidate.kind === "image" && candidate.id === resourceId
|
|
4841
|
+
);
|
|
4842
|
+
if (!resource) {
|
|
4843
|
+
throw new Error(`no image was prepared for resource "${resourceId}"`);
|
|
4844
|
+
}
|
|
4845
|
+
const data = Buffer.from(resource.bytes);
|
|
4846
|
+
if (resource.mediaType !== "svg") {
|
|
4847
|
+
return {
|
|
4848
|
+
type: resource.mediaType,
|
|
4849
|
+
data
|
|
4850
|
+
};
|
|
4851
|
+
}
|
|
4852
|
+
const size = `${emuToPixels(placement.widthEmu)}x${emuToPixels(placement.heightEmu)}`;
|
|
4853
|
+
return {
|
|
4854
|
+
type: "svg",
|
|
4855
|
+
data,
|
|
4856
|
+
fallback: {
|
|
4857
|
+
type: "png",
|
|
4858
|
+
data: rasters.get(`${resourceId}:${size}`) ?? data
|
|
4859
|
+
}
|
|
4860
|
+
};
|
|
4861
|
+
};
|
|
4862
|
+
return { images: resources, pictureSource, drawingGroups };
|
|
3971
4863
|
}
|
|
3972
4864
|
function collectImagePlacements(ir) {
|
|
3973
4865
|
const placements = /* @__PURE__ */ new Map();
|
|
4866
|
+
let drawingGroups = 0;
|
|
4867
|
+
const record = (resourceId, widthEmu, heightEmu) => {
|
|
4868
|
+
const key = `${emuToPixels(widthEmu)}x${emuToPixels(heightEmu)}`;
|
|
4869
|
+
const sizes = placements.get(resourceId) ?? /* @__PURE__ */ new Set();
|
|
4870
|
+
sizes.add(key);
|
|
4871
|
+
placements.set(resourceId, sizes);
|
|
4872
|
+
};
|
|
3974
4873
|
const visitInline = (inline) => {
|
|
3975
4874
|
if (inline.kind === "image") {
|
|
3976
|
-
|
|
3977
|
-
|
|
3978
|
-
|
|
3979
|
-
|
|
4875
|
+
record(inline.resourceId, inline.widthEmu, inline.heightEmu);
|
|
4876
|
+
return;
|
|
4877
|
+
}
|
|
4878
|
+
if (inline.kind === "drawingGroup") {
|
|
4879
|
+
drawingGroups += 1;
|
|
4880
|
+
for (const child of inline.children) {
|
|
4881
|
+
if (child.kind === "picture") {
|
|
4882
|
+
record(child.resourceId, child.frame.widthEmu, child.frame.heightEmu);
|
|
4883
|
+
} else {
|
|
4884
|
+
child.text?.paragraphs.forEach(visitBlock);
|
|
4885
|
+
}
|
|
4886
|
+
}
|
|
3980
4887
|
return;
|
|
3981
4888
|
}
|
|
3982
4889
|
if (inline.kind === "hyperlink" || inline.kind === "revision") {
|
|
@@ -4007,7 +4914,7 @@ function collectImagePlacements(ir) {
|
|
|
4007
4914
|
for (const note of [...ir.footnotes, ...ir.endnotes]) {
|
|
4008
4915
|
note.children.forEach(visitBlock);
|
|
4009
4916
|
}
|
|
4010
|
-
return placements;
|
|
4917
|
+
return { placements, drawingGroups };
|
|
4011
4918
|
}
|
|
4012
4919
|
function sectionOptions(section2, resources, closesDocument = false) {
|
|
4013
4920
|
const { page, columns } = section2.properties;
|
|
@@ -4120,17 +5027,26 @@ function coreProperties(ir) {
|
|
|
4120
5027
|
...metadata.custom?.length ? { customProperties: metadata.custom } : {}
|
|
4121
5028
|
};
|
|
4122
5029
|
}
|
|
4123
|
-
var DOCXJS_RENDERER_ID, DOCXJS_CAPABILITIES;
|
|
5030
|
+
var DOCXJS_RENDERER_ID, shapes, DOCXJS_CAPABILITIES;
|
|
4124
5031
|
var init_docxjs = __esm({
|
|
4125
5032
|
"src/renderers/docxjs/index.ts"() {
|
|
4126
5033
|
"use strict";
|
|
4127
5034
|
init_styles2();
|
|
5035
|
+
init_charts();
|
|
4128
5036
|
init_imageUtils();
|
|
4129
5037
|
init_packageDocument();
|
|
4130
5038
|
init_fixFloatingImageIds();
|
|
4131
5039
|
init_emit();
|
|
5040
|
+
init_docxSubpath();
|
|
5041
|
+
init_drawingGroup();
|
|
5042
|
+
init_drawingGroupRepair();
|
|
4132
5043
|
init_units();
|
|
4133
5044
|
DOCXJS_RENDERER_ID = "docxjs";
|
|
5045
|
+
shapes = docxSubpath(
|
|
5046
|
+
"docx/shapes",
|
|
5047
|
+
"visual",
|
|
5048
|
+
() => import("docx/shapes")
|
|
5049
|
+
);
|
|
4134
5050
|
DOCXJS_CAPABILITIES = /* @__PURE__ */ new Set([
|
|
4135
5051
|
"paragraphs",
|
|
4136
5052
|
"styles",
|
|
@@ -4143,8 +5059,10 @@ var init_docxjs = __esm({
|
|
|
4143
5059
|
"images",
|
|
4144
5060
|
"floating-images",
|
|
4145
5061
|
"svg-images",
|
|
5062
|
+
"charts",
|
|
4146
5063
|
"text-frames",
|
|
4147
5064
|
"text-boxes",
|
|
5065
|
+
"drawing-groups",
|
|
4148
5066
|
"toc",
|
|
4149
5067
|
"cached-toc",
|
|
4150
5068
|
"fields",
|
|
@@ -4165,183 +5083,331 @@ var init_docxjs = __esm({
|
|
|
4165
5083
|
}
|
|
4166
5084
|
});
|
|
4167
5085
|
|
|
4168
|
-
// src/
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
|
|
4177
|
-
|
|
4178
|
-
|
|
4179
|
-
|
|
4180
|
-
|
|
4181
|
-
zip.addFile(name, Buffer.from(content, "utf8"));
|
|
5086
|
+
// src/renderers/office-open/chartLook.ts
|
|
5087
|
+
function seriesLook(chartType) {
|
|
5088
|
+
switch (chartType) {
|
|
5089
|
+
case "line":
|
|
5090
|
+
case "scatter":
|
|
5091
|
+
return { marker: MARKER, smooth: false };
|
|
5092
|
+
case "radar":
|
|
5093
|
+
return { marker: MARKER };
|
|
5094
|
+
case "column":
|
|
5095
|
+
case "bar":
|
|
5096
|
+
return { invertIfNegative: false };
|
|
5097
|
+
default:
|
|
5098
|
+
return {};
|
|
4182
5099
|
}
|
|
4183
|
-
|
|
4184
|
-
|
|
5100
|
+
}
|
|
5101
|
+
function axesLook(chartType) {
|
|
5102
|
+
switch (chartType) {
|
|
5103
|
+
case "column":
|
|
5104
|
+
case "bar":
|
|
5105
|
+
case "line":
|
|
5106
|
+
case "area": {
|
|
5107
|
+
const horizontal = chartType === "bar";
|
|
5108
|
+
return {
|
|
5109
|
+
categoryAxis: {
|
|
5110
|
+
position: horizontal ? "l" : "b",
|
|
5111
|
+
...NO_TICKS,
|
|
5112
|
+
line: AXIS_LINE
|
|
5113
|
+
},
|
|
5114
|
+
valueAxis: {
|
|
5115
|
+
position: horizontal ? "b" : "l",
|
|
5116
|
+
gridLine: GRIDLINES,
|
|
5117
|
+
...NO_TICKS,
|
|
5118
|
+
lineVisible: false,
|
|
5119
|
+
crossBetween: chartType === "area" ? "midCat" : "between"
|
|
5120
|
+
}
|
|
5121
|
+
};
|
|
5122
|
+
}
|
|
5123
|
+
case "radar":
|
|
5124
|
+
return {
|
|
5125
|
+
categoryAxis: {
|
|
5126
|
+
position: "b",
|
|
5127
|
+
gridLine: GRIDLINES,
|
|
5128
|
+
...NO_TICKS,
|
|
5129
|
+
majorTickMark: "cross",
|
|
5130
|
+
line: AXIS_LINE
|
|
5131
|
+
},
|
|
5132
|
+
valueAxis: {
|
|
5133
|
+
position: "l",
|
|
5134
|
+
gridLine: GRIDLINES,
|
|
5135
|
+
...NO_TICKS,
|
|
5136
|
+
majorTickMark: "cross",
|
|
5137
|
+
line: AXIS_LINE,
|
|
5138
|
+
crossBetween: "between"
|
|
5139
|
+
}
|
|
5140
|
+
};
|
|
5141
|
+
case "scatter": {
|
|
5142
|
+
const line = { ...AXIS_LINE, color: SCATTER_AXIS_TINT };
|
|
5143
|
+
return {
|
|
5144
|
+
categoryAxis: {
|
|
5145
|
+
position: "b",
|
|
5146
|
+
...NO_TICKS,
|
|
5147
|
+
line,
|
|
5148
|
+
crossBetween: "midCat"
|
|
5149
|
+
},
|
|
5150
|
+
valueAxis: {
|
|
5151
|
+
position: "l",
|
|
5152
|
+
gridLine: GRIDLINES,
|
|
5153
|
+
...NO_TICKS,
|
|
5154
|
+
line,
|
|
5155
|
+
crossBetween: "midCat"
|
|
5156
|
+
}
|
|
5157
|
+
};
|
|
5158
|
+
}
|
|
5159
|
+
default:
|
|
5160
|
+
return {};
|
|
5161
|
+
}
|
|
5162
|
+
}
|
|
5163
|
+
function plotLook(chart) {
|
|
5164
|
+
const common = {
|
|
5165
|
+
...axesLook(chart.chartType),
|
|
5166
|
+
autoTitleDeleted: !(chart.title && chart.showTitle !== false),
|
|
5167
|
+
plotAreaUnfilled: true
|
|
5168
|
+
};
|
|
5169
|
+
switch (chart.chartType) {
|
|
5170
|
+
case "column":
|
|
5171
|
+
return { ...common, dataBorder: "none", gapWidth: 219, overlap: -27 };
|
|
5172
|
+
case "bar":
|
|
5173
|
+
return { ...common, dataBorder: "none", gapWidth: 182, overlap: 0 };
|
|
5174
|
+
case "area":
|
|
5175
|
+
return { ...common, dataBorder: "none" };
|
|
5176
|
+
case "line":
|
|
5177
|
+
return { ...common, ...LINE_SERIES, lineMarkers: true };
|
|
5178
|
+
case "radar":
|
|
5179
|
+
return { ...common, ...LINE_SERIES, radarStyle: "marker" };
|
|
5180
|
+
case "scatter": {
|
|
5181
|
+
const labels = chart.series[0]?.labels ?? [];
|
|
5182
|
+
return {
|
|
5183
|
+
...common,
|
|
5184
|
+
...LINE_SERIES,
|
|
5185
|
+
lineWidthPoints: 1.5,
|
|
5186
|
+
scatterStyle: "lineMarker",
|
|
5187
|
+
scatterXValues: labels.map((_, index) => scatterX(labels, index))
|
|
5188
|
+
};
|
|
5189
|
+
}
|
|
5190
|
+
case "pie":
|
|
5191
|
+
case "doughnut":
|
|
5192
|
+
return {
|
|
5193
|
+
...common,
|
|
5194
|
+
dataBorder: { widthPoints: 1.5, color: { scheme: "lt1" } },
|
|
5195
|
+
firstSliceAngle: 0,
|
|
5196
|
+
...chart.chartType === "doughnut" ? { holeSize: 50 } : {}
|
|
5197
|
+
};
|
|
5198
|
+
default:
|
|
5199
|
+
return common;
|
|
4185
5200
|
}
|
|
4186
|
-
return new Uint8Array(zip.toBuffer());
|
|
4187
5201
|
}
|
|
4188
|
-
var
|
|
4189
|
-
var
|
|
4190
|
-
"src/
|
|
5202
|
+
var TEXT_1_TINT, SCATTER_AXIS_TINT, HAIRLINE_POINTS, GRIDLINES, AXIS_LINE, NO_TICKS, LINE_SERIES, MARKER;
|
|
5203
|
+
var init_chartLook = __esm({
|
|
5204
|
+
"src/renderers/office-open/chartLook.ts"() {
|
|
4191
5205
|
"use strict";
|
|
4192
|
-
|
|
4193
|
-
|
|
5206
|
+
init_chartValues();
|
|
5207
|
+
TEXT_1_TINT = { scheme: "tx1", lumMod: 15e3, lumOff: 85e3 };
|
|
5208
|
+
SCATTER_AXIS_TINT = {
|
|
5209
|
+
scheme: "tx1",
|
|
5210
|
+
lumMod: 25e3,
|
|
5211
|
+
lumOff: 75e3
|
|
5212
|
+
};
|
|
5213
|
+
HAIRLINE_POINTS = 0.75;
|
|
5214
|
+
GRIDLINES = {
|
|
5215
|
+
size: HAIRLINE_POINTS,
|
|
5216
|
+
color: TEXT_1_TINT
|
|
5217
|
+
};
|
|
5218
|
+
AXIS_LINE = {
|
|
5219
|
+
widthPoints: HAIRLINE_POINTS,
|
|
5220
|
+
color: TEXT_1_TINT
|
|
5221
|
+
};
|
|
5222
|
+
NO_TICKS = {
|
|
5223
|
+
majorTickMark: "none",
|
|
5224
|
+
minorTickMark: "none",
|
|
5225
|
+
tickLabelPosition: "nextTo"
|
|
5226
|
+
};
|
|
5227
|
+
LINE_SERIES = {
|
|
5228
|
+
lineWidthPoints: 2.25,
|
|
5229
|
+
lineCap: "rnd",
|
|
5230
|
+
lineJoin: "round",
|
|
5231
|
+
markerLineWidthPoints: HAIRLINE_POINTS
|
|
5232
|
+
};
|
|
5233
|
+
MARKER = { symbol: "circle", size: 5 };
|
|
4194
5234
|
}
|
|
4195
5235
|
});
|
|
4196
5236
|
|
|
4197
5237
|
// src/renderers/office-open/chartParts.ts
|
|
4198
5238
|
import {
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
matchChartParts,
|
|
4202
|
-
spliceChartXml
|
|
5239
|
+
finishChartXml,
|
|
5240
|
+
matchChartParts
|
|
4203
5241
|
} from "@json-to-office/shared/rendering";
|
|
4204
|
-
function
|
|
4205
|
-
const
|
|
4206
|
-
const textFont =
|
|
4207
|
-
const axisTitleFont =
|
|
4208
|
-
const chartTitleFont =
|
|
4209
|
-
|
|
4210
|
-
|
|
4211
|
-
|
|
5242
|
+
function chartInput(chart) {
|
|
5243
|
+
const roles = chartTextRoles(chart.textFont);
|
|
5244
|
+
const textFont = roles.text;
|
|
5245
|
+
const axisTitleFont = roles.axisTitle;
|
|
5246
|
+
const chartTitleFont = roles.title;
|
|
5247
|
+
const look = plotLook(chart);
|
|
5248
|
+
const categoryAxis = {
|
|
5249
|
+
...look.categoryAxis,
|
|
5250
|
+
...chart.categoryAxisTitle ? { title: chart.categoryAxisTitle, titleFont: axisTitleFont } : {}
|
|
5251
|
+
};
|
|
5252
|
+
const valueAxis = {
|
|
5253
|
+
...look.valueAxis,
|
|
5254
|
+
...chart.valueAxisTitle ? { title: chart.valueAxisTitle, titleFont: axisTitleFont } : {}
|
|
4212
5255
|
};
|
|
4213
5256
|
return {
|
|
5257
|
+
...look,
|
|
4214
5258
|
chartType: chart.chartType,
|
|
4215
5259
|
series: chart.series,
|
|
4216
5260
|
colors: chart.colors,
|
|
5261
|
+
...chart.title && chart.showTitle !== false ? { title: chart.title } : {},
|
|
4217
5262
|
textFont,
|
|
4218
5263
|
titleFont: chartTitleFont,
|
|
4219
5264
|
...chart.legendPosition ? { legendPosition: chart.legendPosition } : {},
|
|
4220
|
-
...
|
|
4221
|
-
|
|
4222
|
-
title: chart.categoryAxisTitle,
|
|
4223
|
-
titleFont: axisTitleFont
|
|
4224
|
-
}
|
|
4225
|
-
} : {},
|
|
4226
|
-
...chart.valueAxisTitle ? {
|
|
4227
|
-
valueAxis: { title: chart.valueAxisTitle, titleFont: axisTitleFont }
|
|
4228
|
-
} : {}
|
|
5265
|
+
...Object.keys(categoryAxis).length > 0 ? { categoryAxis } : {},
|
|
5266
|
+
...Object.keys(valueAxis).length > 0 ? { valueAxis } : {}
|
|
4229
5267
|
};
|
|
4230
5268
|
}
|
|
4231
|
-
function
|
|
4232
|
-
|
|
4233
|
-
if (!entry) return;
|
|
4234
|
-
const xml = entry.getData().toString("utf8");
|
|
4235
|
-
if (xml.includes(`Extension="xlsx"`)) return;
|
|
4236
|
-
zip.updateFile(
|
|
4237
|
-
entry,
|
|
4238
|
-
Buffer.from(
|
|
4239
|
-
xml.replace(
|
|
4240
|
-
'<Default Extension="xml"',
|
|
4241
|
-
`<Default Extension="xlsx" ContentType="${CHART_WORKBOOK_CONTENT_TYPE}"/><Default Extension="xml"`
|
|
4242
|
-
),
|
|
4243
|
-
"utf8"
|
|
4244
|
-
)
|
|
4245
|
-
);
|
|
4246
|
-
}
|
|
4247
|
-
function spliceChartParts(zip, charts) {
|
|
4248
|
-
if (charts.length === 0) return;
|
|
5269
|
+
function finishChartParts(zip, charts2) {
|
|
5270
|
+
if (charts2.length === 0) return;
|
|
4249
5271
|
const parts = zip.getEntries().map((entry) => entry.entryName).map((name) => name.match(/^word\/charts\/chart(\d+)\.xml$/)).filter((match) => match !== null).map(
|
|
4250
5272
|
(match) => [
|
|
4251
5273
|
Number(match[1]),
|
|
4252
5274
|
zip.getEntry(match[0]).getData().toString("utf8")
|
|
4253
5275
|
]
|
|
4254
5276
|
);
|
|
4255
|
-
|
|
4256
|
-
|
|
5277
|
+
const inputs = charts2.map(chartInput);
|
|
5278
|
+
for (const { ordinal, xml, chart } of matchChartParts(parts, inputs)) {
|
|
5279
|
+
const finished = finishChartXml(xml, chart);
|
|
5280
|
+
if (finished === xml) continue;
|
|
4257
5281
|
zip.updateFile(
|
|
4258
5282
|
zip.getEntry(`word/charts/chart${ordinal}.xml`),
|
|
4259
|
-
Buffer.from(
|
|
4260
|
-
);
|
|
4261
|
-
zip.addFile(
|
|
4262
|
-
`word/embeddings/${workbookName}`,
|
|
4263
|
-
Buffer.from(buildChartWorkbook(chart.series))
|
|
4264
|
-
);
|
|
4265
|
-
zip.addFile(
|
|
4266
|
-
`word/charts/_rels/chart${ordinal}.xml.rels`,
|
|
4267
|
-
Buffer.from(chartWorkbookRelsXml(workbookName), "utf8")
|
|
5283
|
+
Buffer.from(finished, "utf8")
|
|
4268
5284
|
);
|
|
4269
5285
|
}
|
|
4270
|
-
declareWorkbookContentType(zip);
|
|
4271
5286
|
}
|
|
4272
|
-
var CHART_TITLE_SCALE;
|
|
4273
5287
|
var init_chartParts = __esm({
|
|
4274
5288
|
"src/renderers/office-open/chartParts.ts"() {
|
|
4275
5289
|
"use strict";
|
|
4276
|
-
|
|
4277
|
-
|
|
5290
|
+
init_chartText();
|
|
5291
|
+
init_chartLook();
|
|
4278
5292
|
}
|
|
4279
5293
|
});
|
|
4280
5294
|
|
|
4281
|
-
// src/renderers/office-open/
|
|
4282
|
-
function
|
|
4283
|
-
|
|
4284
|
-
|
|
4285
|
-
for (const entry of zip.getEntries()) {
|
|
4286
|
-
if (!TABLE_PARTS.test(entry.entryName)) continue;
|
|
4287
|
-
const original = entry.getData().toString("utf8");
|
|
4288
|
-
let xml = original;
|
|
4289
|
-
for (const toc of tocs) {
|
|
4290
|
-
const start = markerParagraph(xml, toc.start);
|
|
4291
|
-
if (!start) continue;
|
|
4292
|
-
const end = markerParagraph(xml, toc.end);
|
|
4293
|
-
if (spliced.has(toc) || !end || end.from < start.to) {
|
|
4294
|
-
throw new Error(
|
|
4295
|
-
`the office-open renderer lost track of a table of contents in a table cell (${entry.entryName})`
|
|
4296
|
-
);
|
|
4297
|
-
}
|
|
4298
|
-
xml = xml.slice(0, start.from) + stringifyTableOfContents(
|
|
4299
|
-
toc.alias,
|
|
4300
|
-
toc.options,
|
|
4301
|
-
xml.slice(start.to, end.from)
|
|
4302
|
-
) + xml.slice(end.to);
|
|
4303
|
-
spliced.add(toc);
|
|
4304
|
-
}
|
|
4305
|
-
if (xml !== original) zip.updateFile(entry, Buffer.from(xml, "utf8"));
|
|
4306
|
-
}
|
|
4307
|
-
if (spliced.size !== tocs.length) {
|
|
5295
|
+
// src/renderers/office-open/themePart.ts
|
|
5296
|
+
function replaceOnce(xml, pattern, replacer, what) {
|
|
5297
|
+
const count = [...xml.matchAll(pattern)].length;
|
|
5298
|
+
if (count !== 1) {
|
|
4308
5299
|
throw new Error(
|
|
4309
|
-
`
|
|
5300
|
+
`office-open's theme part has ${count} ${what}, expected one`
|
|
4310
5301
|
);
|
|
4311
5302
|
}
|
|
5303
|
+
return xml.replace(pattern, replacer);
|
|
5304
|
+
}
|
|
5305
|
+
function spliceTheme(zip, theme) {
|
|
5306
|
+
const entry = zip.getEntry(THEME_PART);
|
|
5307
|
+
if (!entry) throw new Error(`office-open wrote no ${THEME_PART}`);
|
|
5308
|
+
let xml = entry.getData().toString("utf8");
|
|
5309
|
+
const name = esc(theme.name);
|
|
5310
|
+
xml = renamed(xml, "theme", name);
|
|
5311
|
+
const colors = Object.entries(theme.colors);
|
|
5312
|
+
if (colors.some(([, color]) => color)) {
|
|
5313
|
+
xml = renamed(xml, "clrScheme", name);
|
|
5314
|
+
for (const [slot, color] of colors) {
|
|
5315
|
+
if (!color) continue;
|
|
5316
|
+
const element = SCHEME_ELEMENT[slot];
|
|
5317
|
+
xml = replaceOnce(
|
|
5318
|
+
xml,
|
|
5319
|
+
new RegExp(`<a:${element}>[\\s\\S]*?</a:${element}>`, "g"),
|
|
5320
|
+
() => `<a:${element}><a:srgbClr val="${color.hex}"/></a:${element}>`,
|
|
5321
|
+
`a:${element}`
|
|
5322
|
+
);
|
|
5323
|
+
}
|
|
5324
|
+
}
|
|
5325
|
+
if (theme.headingFont || theme.bodyFont) {
|
|
5326
|
+
xml = renamed(xml, "fontScheme", name);
|
|
5327
|
+
for (const [collection, key, officeFace] of OFFICE_FACES) {
|
|
5328
|
+
const family = theme[key];
|
|
5329
|
+
if (family === void 0 || family === officeFace) continue;
|
|
5330
|
+
xml = replaceOnce(
|
|
5331
|
+
xml,
|
|
5332
|
+
new RegExp(`(<a:${collection}>)<a:latin\\b[^>]*/>`, "g"),
|
|
5333
|
+
(_match, open) => `${open}<a:latin typeface="${esc(family)}"/>`,
|
|
5334
|
+
`a:${collection} a:latin`
|
|
5335
|
+
);
|
|
5336
|
+
}
|
|
5337
|
+
}
|
|
5338
|
+
zip.updateFile(THEME_PART, Buffer.from(xml, "utf8"));
|
|
4312
5339
|
}
|
|
4313
|
-
|
|
4314
|
-
|
|
4315
|
-
|
|
4316
|
-
|
|
4317
|
-
xml
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
|
|
4323
|
-
|
|
5340
|
+
var THEME_PART, SCHEME_ELEMENT, OFFICE_FACES, esc, renamed;
|
|
5341
|
+
var init_themePart = __esm({
|
|
5342
|
+
"src/renderers/office-open/themePart.ts"() {
|
|
5343
|
+
"use strict";
|
|
5344
|
+
THEME_PART = "word/theme/theme1.xml";
|
|
5345
|
+
SCHEME_ELEMENT = {
|
|
5346
|
+
dark1: "dk1",
|
|
5347
|
+
light1: "lt1",
|
|
5348
|
+
dark2: "dk2",
|
|
5349
|
+
light2: "lt2",
|
|
5350
|
+
accent1: "accent1",
|
|
5351
|
+
accent2: "accent2",
|
|
5352
|
+
accent3: "accent3",
|
|
5353
|
+
accent4: "accent4",
|
|
5354
|
+
accent5: "accent5",
|
|
5355
|
+
accent6: "accent6",
|
|
5356
|
+
hyperlink: "hlink",
|
|
5357
|
+
followedHyperlink: "folHlink"
|
|
5358
|
+
};
|
|
5359
|
+
OFFICE_FACES = [
|
|
5360
|
+
["majorFont", "headingFont", "Calibri Light"],
|
|
5361
|
+
["minorFont", "bodyFont", "Calibri"]
|
|
5362
|
+
];
|
|
5363
|
+
esc = (value) => value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
5364
|
+
renamed = (xml, element, name) => replaceOnce(
|
|
5365
|
+
xml,
|
|
5366
|
+
new RegExp(`(<a:${element}\\b[^>]*?\\bname=")[^"]*(")`, "g"),
|
|
5367
|
+
(_match, open, close) => `${open}${name}${close}`,
|
|
5368
|
+
`a:${element} name`
|
|
4324
5369
|
);
|
|
4325
5370
|
}
|
|
4326
|
-
|
|
5371
|
+
});
|
|
5372
|
+
|
|
5373
|
+
// src/utils/chartWorkbook.ts
|
|
5374
|
+
import AdmZip4 from "adm-zip";
|
|
5375
|
+
import { chartWorkbookParts } from "@json-to-office/shared/rendering";
|
|
5376
|
+
import {
|
|
5377
|
+
CHART_WORKBOOK_SHEET_NAME,
|
|
5378
|
+
categoryReference,
|
|
5379
|
+
columnLetter,
|
|
5380
|
+
seriesNameReference,
|
|
5381
|
+
seriesValueReference
|
|
5382
|
+
} from "@json-to-office/shared/rendering";
|
|
5383
|
+
function buildChartWorkbook(series, options = {}) {
|
|
5384
|
+
const zip = new AdmZip4();
|
|
5385
|
+
for (const [name, content] of chartWorkbookParts(series, options)) {
|
|
5386
|
+
zip.addFile(name, Buffer.from(content, "utf8"));
|
|
5387
|
+
}
|
|
5388
|
+
for (const entry of zip.getEntries()) {
|
|
5389
|
+
entry.header.timeval = WORKBOOK_TIMESTAMP;
|
|
5390
|
+
}
|
|
5391
|
+
return new Uint8Array(zip.toBuffer());
|
|
4327
5392
|
}
|
|
4328
|
-
var
|
|
4329
|
-
var
|
|
4330
|
-
"src/
|
|
5393
|
+
var WORKBOOK_TIMESTAMP;
|
|
5394
|
+
var init_chartWorkbook = __esm({
|
|
5395
|
+
"src/utils/chartWorkbook.ts"() {
|
|
4331
5396
|
"use strict";
|
|
4332
|
-
|
|
5397
|
+
init_packageDocument();
|
|
5398
|
+
WORKBOOK_TIMESTAMP = toDosTime(DEFAULT_GENERATION_DATE);
|
|
4333
5399
|
}
|
|
4334
5400
|
});
|
|
4335
5401
|
|
|
4336
5402
|
// src/renderers/office-open/emit.ts
|
|
4337
|
-
import { assertNever as
|
|
5403
|
+
import { assertNever as assertNever3 } from "@json-to-office/shared/rendering";
|
|
5404
|
+
import { chartLook, withSeriesLook } from "@json-to-office/shared/rendering";
|
|
4338
5405
|
function emptyContext() {
|
|
4339
5406
|
let next = 1;
|
|
4340
5407
|
return {
|
|
4341
5408
|
pictures: /* @__PURE__ */ new Map(),
|
|
4342
5409
|
nextDrawingId: () => next++,
|
|
4343
|
-
charts: []
|
|
4344
|
-
cellTocs: []
|
|
5410
|
+
charts: []
|
|
4345
5411
|
};
|
|
4346
5412
|
}
|
|
4347
5413
|
function simpleField(instruction, cachedText) {
|
|
@@ -4382,18 +5448,19 @@ function runProperties2(formatting) {
|
|
|
4382
5448
|
if (formatting.doubleStrike !== void 0) {
|
|
4383
5449
|
out.doubleStrike = formatting.doubleStrike;
|
|
4384
5450
|
}
|
|
4385
|
-
if (formatting.superScript) out.
|
|
4386
|
-
if (formatting.subScript) out.
|
|
5451
|
+
if (formatting.superScript) out.verticalAlign = "superscript";
|
|
5452
|
+
if (formatting.subScript) out.verticalAlign = "subscript";
|
|
4387
5453
|
if (formatting.smallCaps !== void 0) out.smallCaps = formatting.smallCaps;
|
|
4388
5454
|
if (formatting.allCaps !== void 0) out.allCaps = formatting.allCaps;
|
|
4389
|
-
if (formatting.highlight !== void 0)
|
|
5455
|
+
if (formatting.highlight !== void 0) {
|
|
5456
|
+
out.highlight = formatting.highlight;
|
|
5457
|
+
}
|
|
4390
5458
|
if (formatting.shading) out.shading = shading(formatting.shading);
|
|
4391
5459
|
if (formatting.scalePercent !== void 0)
|
|
4392
5460
|
out.scale = formatting.scalePercent;
|
|
4393
|
-
|
|
4394
|
-
|
|
4395
|
-
|
|
4396
|
-
out.characterSpacing = twentieths === 0 && stated !== 0 ? "0pt" : twentieths;
|
|
5461
|
+
const stated = formatting.characterSpacingTwentieths;
|
|
5462
|
+
if (stated !== void 0 && stated !== 0) {
|
|
5463
|
+
out.characterSpacing = twips(stated);
|
|
4397
5464
|
}
|
|
4398
5465
|
if (formatting.language) out.language = { value: formatting.language };
|
|
4399
5466
|
if (formatting.noProof !== void 0) out.noProof = formatting.noProof;
|
|
@@ -4423,7 +5490,9 @@ function inlineChildren2(children, ctx = emptyContext()) {
|
|
|
4423
5490
|
switch (child.kind) {
|
|
4424
5491
|
case "lineBreak":
|
|
4425
5492
|
pendingBreaks += 1;
|
|
4426
|
-
if (child.clear && child.clear !== "none")
|
|
5493
|
+
if (child.clear && child.clear !== "none") {
|
|
5494
|
+
pendingClear = child.clear;
|
|
5495
|
+
}
|
|
4427
5496
|
break;
|
|
4428
5497
|
case "text":
|
|
4429
5498
|
out.push({
|
|
@@ -4461,7 +5530,7 @@ function inlineChildren2(children, ctx = emptyContext()) {
|
|
|
4461
5530
|
case "drawingGroup": {
|
|
4462
5531
|
const pending = breakOption();
|
|
4463
5532
|
if (pending.break) out.push(pending);
|
|
4464
|
-
out.push({ wpgGroup:
|
|
5533
|
+
out.push({ wpgGroup: drawingGroupOptions2(child, ctx) });
|
|
4465
5534
|
break;
|
|
4466
5535
|
}
|
|
4467
5536
|
case "hyperlink":
|
|
@@ -4491,8 +5560,9 @@ function inlineChildren2(children, ctx = emptyContext()) {
|
|
|
4491
5560
|
out.push({ wpsShape: shapeOptions(child, ctx) });
|
|
4492
5561
|
break;
|
|
4493
5562
|
case "chart":
|
|
4494
|
-
|
|
4495
|
-
|
|
5563
|
+
out.push({
|
|
5564
|
+
chart: chartOptions(child, ctx, ctx.charts?.push(child) ?? 1)
|
|
5565
|
+
});
|
|
4496
5566
|
break;
|
|
4497
5567
|
case "noteReference":
|
|
4498
5568
|
out.push(
|
|
@@ -4500,7 +5570,7 @@ function inlineChildren2(children, ctx = emptyContext()) {
|
|
|
4500
5570
|
);
|
|
4501
5571
|
break;
|
|
4502
5572
|
default:
|
|
4503
|
-
|
|
5573
|
+
assertNever3(child, "DocxIrInline");
|
|
4504
5574
|
}
|
|
4505
5575
|
}
|
|
4506
5576
|
return out;
|
|
@@ -4541,8 +5611,11 @@ function floatingOptions2(floating) {
|
|
|
4541
5611
|
...floating.vertical ? { verticalPosition: position(floating.vertical) } : {},
|
|
4542
5612
|
...floating.wrap ? {
|
|
4543
5613
|
wrap: {
|
|
4544
|
-
|
|
4545
|
-
|
|
5614
|
+
// Named, as OOXML names them; 0.11 took docx.js's numbers.
|
|
5615
|
+
type: floating.wrap.type,
|
|
5616
|
+
...floating.wrap.side ? {
|
|
5617
|
+
side: floating.wrap.side
|
|
5618
|
+
} : {}
|
|
4546
5619
|
}
|
|
4547
5620
|
} : {},
|
|
4548
5621
|
...floating.margins ? {
|
|
@@ -4569,66 +5642,92 @@ function imageMedia(ctx, resourceId, placement) {
|
|
|
4569
5642
|
}
|
|
4570
5643
|
function pictureOptions(image, ctx) {
|
|
4571
5644
|
const media = imageMedia(ctx, image.resourceId, image);
|
|
4572
|
-
|
|
4573
|
-
type:
|
|
5645
|
+
const source = media.type === "svg" ? {
|
|
5646
|
+
type: "svg",
|
|
4574
5647
|
data: media.data,
|
|
4575
|
-
//
|
|
4576
|
-
//
|
|
4577
|
-
|
|
5648
|
+
// The SVG slot always carries a raster: `prepareImages` falls back
|
|
5649
|
+
// to the vector bytes when none could be made.
|
|
5650
|
+
fallback: media.fallback ?? {
|
|
5651
|
+
type: "png",
|
|
5652
|
+
data: media.data
|
|
5653
|
+
}
|
|
5654
|
+
} : { type: media.type, data: media.data };
|
|
5655
|
+
return {
|
|
5656
|
+
...source,
|
|
4578
5657
|
// Raw numbers are EMUs in @office-open/docx. Passing pixels here makes a
|
|
4579
5658
|
// normal image only a few hundred EMUs wide, effectively a dot.
|
|
4580
5659
|
transformation: { width: image.widthEmu, height: image.heightEmu },
|
|
4581
5660
|
// The id is stated rather than left to the backend's process-global
|
|
4582
|
-
// counter. `name` stays empty, which is what
|
|
4583
|
-
|
|
4584
|
-
altText: { id: String(ctx.nextDrawingId()) },
|
|
5661
|
+
// counter. `name` stays empty, which is what the backend falls back to.
|
|
5662
|
+
altText: { id: String(ctx.nextDrawingId()), name: "" },
|
|
4585
5663
|
...image.floating ? { floating: floatingOptions2(image.floating) } : {}
|
|
4586
5664
|
// No `description` or `title`: no DOCX this pipeline has produced carries
|
|
4587
5665
|
// `wp:docPr` alt text, and the compiler warns so the gap is visible rather
|
|
4588
5666
|
// than silent.
|
|
4589
5667
|
};
|
|
4590
5668
|
}
|
|
4591
|
-
function
|
|
5669
|
+
function drawingGroupOptions2(group, ctx) {
|
|
4592
5670
|
const id = ctx.nextDrawingId();
|
|
4593
5671
|
return {
|
|
4594
5672
|
altText: {
|
|
4595
5673
|
id: String(id),
|
|
5674
|
+
name: "",
|
|
4596
5675
|
...group.altText ? { description: group.altText } : {}
|
|
4597
5676
|
},
|
|
4598
5677
|
transformation: { width: group.widthEmu, height: group.heightEmu },
|
|
4599
|
-
|
|
4600
|
-
|
|
4601
|
-
|
|
5678
|
+
childOffsetX: 0,
|
|
5679
|
+
childOffsetY: 0,
|
|
5680
|
+
childExtentWidth: group.canvasWidthEmu,
|
|
5681
|
+
childExtentHeight: group.canvasHeightEmu,
|
|
5682
|
+
children: group.children.map((child) => groupChild2(child, ctx)),
|
|
4602
5683
|
...group.floating ? { floating: floatingOptions2(group.floating) } : {}
|
|
4603
5684
|
};
|
|
4604
5685
|
}
|
|
4605
|
-
function chartOptions(chart, ctx) {
|
|
5686
|
+
function chartOptions(chart, ctx, ordinal) {
|
|
4606
5687
|
const id = ctx.nextDrawingId();
|
|
5688
|
+
const input = chartInput(chart);
|
|
5689
|
+
const look = chartLook(input);
|
|
4607
5690
|
return {
|
|
4608
5691
|
type: chart.chartType,
|
|
4609
5692
|
categories: chart.series[0]?.labels ?? [],
|
|
4610
|
-
series: chart.series.map(
|
|
4611
|
-
|
|
4612
|
-
|
|
4613
|
-
|
|
4614
|
-
|
|
5693
|
+
series: chart.series.map(
|
|
5694
|
+
(entry, index) => withSeriesLook(
|
|
5695
|
+
{
|
|
5696
|
+
name: entry.name ?? `Series ${index + 1}`,
|
|
5697
|
+
values: entry.values,
|
|
5698
|
+
...seriesLook(chart.chartType)
|
|
5699
|
+
},
|
|
5700
|
+
look.series[index]
|
|
5701
|
+
)
|
|
5702
|
+
),
|
|
5703
|
+
...look.chart,
|
|
4615
5704
|
...chart.showLegend !== void 0 ? { showLegend: chart.showLegend } : {},
|
|
5705
|
+
externalData: {
|
|
5706
|
+
...look.chart.externalData,
|
|
5707
|
+
fileName: `chart${ordinal}.xlsx`,
|
|
5708
|
+
// A scatter chart's column A holds the x values its `c:xVal` caches.
|
|
5709
|
+
data: buildChartWorkbook(
|
|
5710
|
+
chart.series,
|
|
5711
|
+
input.scatterXValues ? { categoryValues: input.scatterXValues } : {}
|
|
5712
|
+
)
|
|
5713
|
+
},
|
|
4616
5714
|
transformation: { width: chart.widthEmu, height: chart.heightEmu },
|
|
4617
5715
|
altText: {
|
|
4618
5716
|
id: String(id),
|
|
5717
|
+
name: "",
|
|
4619
5718
|
...chart.altText ? { description: chart.altText } : {}
|
|
4620
5719
|
},
|
|
4621
5720
|
...chart.floating ? { floating: floatingOptions2(chart.floating) } : {}
|
|
4622
5721
|
};
|
|
4623
5722
|
}
|
|
4624
|
-
function
|
|
5723
|
+
function groupChild2(child, ctx) {
|
|
4625
5724
|
return child.kind === "shape" ? groupShape(child, ctx) : groupPicture(child, ctx);
|
|
4626
5725
|
}
|
|
4627
5726
|
function groupShape(shape, ctx) {
|
|
4628
5727
|
const id = ctx.nextDrawingId();
|
|
4629
5728
|
return {
|
|
4630
5729
|
type: "wps",
|
|
4631
|
-
transformation:
|
|
5730
|
+
transformation: childTransformation2(shape.frame),
|
|
4632
5731
|
data: {
|
|
4633
5732
|
nonVisualProperties: {
|
|
4634
5733
|
id,
|
|
@@ -4637,7 +5736,7 @@ function groupShape(shape, ctx) {
|
|
|
4637
5736
|
// to hold text, and it changes how the object behaves on selection.
|
|
4638
5737
|
...shape.isTextBox ? { textBox: "1" } : {}
|
|
4639
5738
|
},
|
|
4640
|
-
|
|
5739
|
+
geometry: shape.geometry,
|
|
4641
5740
|
...shape.fill ? { fill: drawingFill(shape.fill) } : {},
|
|
4642
5741
|
...shape.outline ? { outline: drawingOutline(shape.outline) } : {},
|
|
4643
5742
|
children: (shape.text?.paragraphs ?? []).map(
|
|
@@ -4663,7 +5762,7 @@ function groupPicture(picture2, ctx) {
|
|
|
4663
5762
|
fileName: media.fallbackFileName
|
|
4664
5763
|
}
|
|
4665
5764
|
} : {},
|
|
4666
|
-
transformation:
|
|
5765
|
+
transformation: childTransformation2(picture2.frame),
|
|
4667
5766
|
nonVisualProperties: {
|
|
4668
5767
|
id,
|
|
4669
5768
|
...picture2.name ? { name: picture2.name } : {},
|
|
@@ -4672,11 +5771,7 @@ function groupPicture(picture2, ctx) {
|
|
|
4672
5771
|
...picture2.crop ? { sourceRectangle: sourceRectangle(picture2.crop) } : {}
|
|
4673
5772
|
};
|
|
4674
5773
|
}
|
|
4675
|
-
function
|
|
4676
|
-
const flip = {
|
|
4677
|
-
...frame.flipHorizontal ? { horizontal: true } : {},
|
|
4678
|
-
...frame.flipVertical ? { vertical: true } : {}
|
|
4679
|
-
};
|
|
5774
|
+
function childTransformation2(frame) {
|
|
4680
5775
|
return {
|
|
4681
5776
|
offset: {
|
|
4682
5777
|
emus: { x: frame.xEmu, y: frame.yEmu },
|
|
@@ -4692,7 +5787,8 @@ function childTransformation(frame) {
|
|
|
4692
5787
|
},
|
|
4693
5788
|
// Degrees: the backend multiplies by 60000 on the way into `@rot`.
|
|
4694
5789
|
...frame.rotationDegrees !== void 0 ? { rotation: frame.rotationDegrees } : {},
|
|
4695
|
-
...
|
|
5790
|
+
...frame.flipHorizontal ? { flipHorizontal: true } : {},
|
|
5791
|
+
...frame.flipVertical ? { flipVertical: true } : {}
|
|
4696
5792
|
};
|
|
4697
5793
|
}
|
|
4698
5794
|
function drawingFill(fill) {
|
|
@@ -4700,7 +5796,6 @@ function drawingFill(fill) {
|
|
|
4700
5796
|
return {
|
|
4701
5797
|
type: "solid",
|
|
4702
5798
|
color: {
|
|
4703
|
-
type: "rgb",
|
|
4704
5799
|
value: fill.color.hex,
|
|
4705
5800
|
// Transparency becomes an alpha transform on the colour. DrawingML
|
|
4706
5801
|
// states *opacity*, so the value is the complement of what the author
|
|
@@ -4742,7 +5837,7 @@ function sourceRectangle(crop) {
|
|
|
4742
5837
|
function shapeOptions(shape, ctx) {
|
|
4743
5838
|
const id = String(ctx.nextDrawingId());
|
|
4744
5839
|
return {
|
|
4745
|
-
altText: { id },
|
|
5840
|
+
altText: { id, name: "" },
|
|
4746
5841
|
children: shape.children.map((child) => paragraph(child, ctx)),
|
|
4747
5842
|
// Raw transformation numbers are EMUs in @office-open/docx, while the IR
|
|
4748
5843
|
// deliberately stores native shape dimensions in pixels.
|
|
@@ -4753,7 +5848,7 @@ function shapeOptions(shape, ctx) {
|
|
|
4753
5848
|
...shape.fill ? {
|
|
4754
5849
|
fill: {
|
|
4755
5850
|
type: "solid",
|
|
4756
|
-
color: {
|
|
5851
|
+
color: { value: shape.fill.hex }
|
|
4757
5852
|
}
|
|
4758
5853
|
} : {},
|
|
4759
5854
|
...shape.outline ? { outline: drawingOutline(shape.outline) } : {},
|
|
@@ -4858,13 +5953,19 @@ function frameOptions2(frame) {
|
|
|
4858
5953
|
...frame.anchorLock !== void 0 ? { anchorLock: frame.anchorLock } : {},
|
|
4859
5954
|
...frame.rule ? { rule: frame.rule } : {}
|
|
4860
5955
|
};
|
|
4861
|
-
|
|
4862
|
-
|
|
4863
|
-
|
|
4864
|
-
|
|
4865
|
-
|
|
5956
|
+
if (frame.xTwips !== void 0 || frame.yTwips !== void 0) {
|
|
5957
|
+
return {
|
|
5958
|
+
type: "absolute",
|
|
5959
|
+
position: { x: frame.xTwips ?? 0, y: frame.yTwips ?? 0 },
|
|
5960
|
+
...base
|
|
5961
|
+
};
|
|
5962
|
+
}
|
|
5963
|
+
return {
|
|
4866
5964
|
type: "alignment",
|
|
4867
|
-
alignment: {
|
|
5965
|
+
alignment: {
|
|
5966
|
+
x: frame.xAlign,
|
|
5967
|
+
y: frame.yAlign
|
|
5968
|
+
},
|
|
4868
5969
|
...base
|
|
4869
5970
|
};
|
|
4870
5971
|
}
|
|
@@ -4885,7 +5986,7 @@ function block(value, ctx = emptyContext()) {
|
|
|
4885
5986
|
case "toc":
|
|
4886
5987
|
return { toc: tableOfContents(value) };
|
|
4887
5988
|
default:
|
|
4888
|
-
return
|
|
5989
|
+
return assertNever3(value, "DocxIrBlock");
|
|
4889
5990
|
}
|
|
4890
5991
|
}
|
|
4891
5992
|
function tocEntry(entry) {
|
|
@@ -4904,6 +6005,7 @@ function tableOfContents(value) {
|
|
|
4904
6005
|
headingStyleRange: `${value.headingRange.from}-${value.headingRange.to}`
|
|
4905
6006
|
} : {},
|
|
4906
6007
|
...value.styleLevels?.length ? {
|
|
6008
|
+
// `StyleLevel` is a class the backend only reads the two fields of.
|
|
4907
6009
|
stylesWithLevels: value.styleLevels.map((style) => ({
|
|
4908
6010
|
styleName: style.styleName,
|
|
4909
6011
|
level: style.level
|
|
@@ -4925,14 +6027,16 @@ function table(value, ctx) {
|
|
|
4925
6027
|
// unstated columns comes out fractional, and the XML would carry it
|
|
4926
6028
|
// verbatim; floored here, as the docxjs backend floors it.
|
|
4927
6029
|
size: value.width.kind === "auto" ? 0 : value.width.kind === "twips" ? twips(value.width.value) : value.width.value,
|
|
4928
|
-
type: value.width.kind === "twips" ? "
|
|
6030
|
+
type: value.width.kind === "twips" ? "twips" : value.width.kind === "percent" ? "percent" : "auto"
|
|
4929
6031
|
},
|
|
4930
6032
|
layout: value.layout,
|
|
4931
6033
|
// An empty grid is a table with nothing to say about its columns, which is
|
|
4932
6034
|
// not the same as one whose columns are all zero wide. The compiler hands
|
|
4933
6035
|
// over every grid in twips; floored for the same reason as the width.
|
|
4934
6036
|
...value.columnGrid.values.length > 0 ? { columnWidths: value.columnGrid.values.map(twips) } : {},
|
|
4935
|
-
...value.alignment ? {
|
|
6037
|
+
...value.alignment ? {
|
|
6038
|
+
alignment: alignment(value.alignment)
|
|
6039
|
+
} : {},
|
|
4936
6040
|
...value.borders ? { borders: borders2(value.borders) } : {},
|
|
4937
6041
|
...value.cellMargins ? { margins: cellMargins(value.cellMargins) } : {},
|
|
4938
6042
|
...value.floating ? { float: tableFloat2(value.floating) } : {}
|
|
@@ -4977,52 +6081,29 @@ function tableRow(row, ctx) {
|
|
|
4977
6081
|
}
|
|
4978
6082
|
function tableCell(cell, ctx) {
|
|
4979
6083
|
const children = cellChildren2(cell, ctx);
|
|
4980
|
-
if (cell.children[cell.children.length - 1]?.kind
|
|
6084
|
+
if (cell.children[cell.children.length - 1]?.kind === "toc")
|
|
4981
6085
|
children.push({ paragraph: { children: [] } });
|
|
4982
6086
|
return {
|
|
4983
6087
|
children,
|
|
4984
|
-
...cell.widthTwips !== void 0 ? { width: { size: twips(cell.widthTwips), type: "
|
|
4985
|
-
...cell.verticalAlign ? {
|
|
6088
|
+
...cell.widthTwips !== void 0 ? { width: { size: twips(cell.widthTwips), type: "twips" } } : {},
|
|
6089
|
+
...cell.verticalAlign ? {
|
|
6090
|
+
verticalAlign: cell.verticalAlign
|
|
6091
|
+
} : {},
|
|
4986
6092
|
...cell.shading ? { shading: shading(cell.shading) } : {},
|
|
4987
6093
|
...cell.margins ? { margins: cellMargins(cell.margins) } : {},
|
|
4988
6094
|
...cell.borders ? { borders: borders2(cell.borders) } : {},
|
|
4989
6095
|
...cell.columnSpan !== void 0 ? { columnSpan: cell.columnSpan } : {},
|
|
4990
6096
|
...cell.rowSpan !== void 0 ? { verticalMerge: cell.rowSpan } : {},
|
|
4991
|
-
...cell.textDirection ? {
|
|
6097
|
+
...cell.textDirection ? {
|
|
6098
|
+
textDirection: cell.textDirection
|
|
6099
|
+
} : {}
|
|
4992
6100
|
};
|
|
4993
6101
|
}
|
|
4994
6102
|
function cellChildren2(cell, ctx) {
|
|
4995
|
-
|
|
4996
|
-
for (const child of cell.children) {
|
|
4997
|
-
if (child.kind !== "toc") {
|
|
4998
|
-
children.push(block(child, ctx));
|
|
4999
|
-
continue;
|
|
5000
|
-
}
|
|
5001
|
-
const { alias, entries, ...options } = tableOfContents(child);
|
|
5002
|
-
const index = ctx.cellTocs.length;
|
|
5003
|
-
const toc = {
|
|
5004
|
-
start: cellTocMarker(index, "start"),
|
|
5005
|
-
end: cellTocMarker(index, "end"),
|
|
5006
|
-
alias: String(alias),
|
|
5007
|
-
options
|
|
5008
|
-
};
|
|
5009
|
-
ctx.cellTocs.push(toc);
|
|
5010
|
-
children.push(
|
|
5011
|
-
markerParagraph2(toc.start),
|
|
5012
|
-
...entries ?? [],
|
|
5013
|
-
markerParagraph2(toc.end)
|
|
5014
|
-
);
|
|
5015
|
-
}
|
|
5016
|
-
return children;
|
|
5017
|
-
}
|
|
5018
|
-
function cellTocMarker(index, edge) {
|
|
5019
|
-
return `\uE000jto-cell-toc-${index}-${edge}\uE000`;
|
|
5020
|
-
}
|
|
5021
|
-
function markerParagraph2(text) {
|
|
5022
|
-
return { paragraph: { children: [{ text }] } };
|
|
6103
|
+
return cell.children.map((child) => block(child, ctx));
|
|
5023
6104
|
}
|
|
5024
6105
|
function cellMargins(margins) {
|
|
5025
|
-
const side = (value) => value === void 0 ? void 0 : { size: twips(value), type: "
|
|
6106
|
+
const side = (value) => value === void 0 ? void 0 : { size: twips(value), type: "twips" };
|
|
5026
6107
|
const out = {};
|
|
5027
6108
|
for (const [name, value] of [
|
|
5028
6109
|
["top", margins.topTwips],
|
|
@@ -5065,39 +6146,43 @@ function section(value, ctx, closesDocument = false) {
|
|
|
5065
6146
|
properties: {
|
|
5066
6147
|
...value.properties.type ? { type: value.properties.type } : {},
|
|
5067
6148
|
...value.properties.titlePage !== void 0 ? { titlePage: value.properties.titlePage } : {},
|
|
5068
|
-
|
|
5069
|
-
|
|
5070
|
-
|
|
5071
|
-
|
|
5072
|
-
|
|
5073
|
-
|
|
5074
|
-
|
|
5075
|
-
|
|
5076
|
-
|
|
5077
|
-
|
|
5078
|
-
|
|
5079
|
-
|
|
5080
|
-
|
|
5081
|
-
|
|
5082
|
-
|
|
5083
|
-
...page.margins.gutterTwips !== void 0 ? { gutter: twips(page.margins.gutterTwips) } : {}
|
|
5084
|
-
},
|
|
5085
|
-
...value.properties.pageNumbers ? {
|
|
5086
|
-
pageNumbers: {
|
|
5087
|
-
...value.properties.pageNumbers.start !== void 0 ? { start: value.properties.pageNumbers.start } : {},
|
|
5088
|
-
...value.properties.pageNumbers.formatType ? { formatType: value.properties.pageNumbers.formatType } : {}
|
|
5089
|
-
}
|
|
5090
|
-
} : {},
|
|
5091
|
-
...value.properties.borders ? {
|
|
5092
|
-
borders: {
|
|
5093
|
-
...value.properties.borders.display ? { display: value.properties.borders.display } : {},
|
|
5094
|
-
...value.properties.borders.offsetFrom ? { offsetFrom: value.properties.borders.offsetFrom } : {},
|
|
5095
|
-
...value.properties.borders.borders ? borders2(value.properties.borders.borders) : {}
|
|
5096
|
-
}
|
|
5097
|
-
} : {}
|
|
6149
|
+
// Orientation is implied by the width/height pair, which is how this
|
|
6150
|
+
// pipeline has always expressed it; stating it as well changes `w:pgSz`.
|
|
6151
|
+
pageSize: {
|
|
6152
|
+
width: twips(page.widthTwips),
|
|
6153
|
+
height: twips(page.heightTwips),
|
|
6154
|
+
...page.code !== void 0 ? { code: page.code } : {}
|
|
6155
|
+
},
|
|
6156
|
+
pageMargin: {
|
|
6157
|
+
top: twips(page.margins.topTwips),
|
|
6158
|
+
right: twips(page.margins.rightTwips),
|
|
6159
|
+
bottom: twips(page.margins.bottomTwips),
|
|
6160
|
+
left: twips(page.margins.leftTwips),
|
|
6161
|
+
...page.margins.headerTwips !== void 0 ? { header: twips(page.margins.headerTwips) } : {},
|
|
6162
|
+
...page.margins.footerTwips !== void 0 ? { footer: twips(page.margins.footerTwips) } : {},
|
|
6163
|
+
...page.margins.gutterTwips !== void 0 ? { gutter: twips(page.margins.gutterTwips) } : {}
|
|
5098
6164
|
},
|
|
6165
|
+
...value.properties.pageNumbers ? {
|
|
6166
|
+
pageNumberType: {
|
|
6167
|
+
...value.properties.pageNumbers.start !== void 0 ? { start: value.properties.pageNumbers.start } : {},
|
|
6168
|
+
...value.properties.pageNumbers.formatType ? {
|
|
6169
|
+
format: value.properties.pageNumbers.formatType
|
|
6170
|
+
} : {}
|
|
6171
|
+
}
|
|
6172
|
+
} : {},
|
|
6173
|
+
...value.properties.borders ? {
|
|
6174
|
+
pageBorders: {
|
|
6175
|
+
...value.properties.borders.display ? {
|
|
6176
|
+
display: value.properties.borders.display
|
|
6177
|
+
} : {},
|
|
6178
|
+
...value.properties.borders.offsetFrom ? {
|
|
6179
|
+
offsetFrom: value.properties.borders.offsetFrom
|
|
6180
|
+
} : {},
|
|
6181
|
+
...value.properties.borders.borders ? borders2(value.properties.borders.borders) : {}
|
|
6182
|
+
}
|
|
6183
|
+
} : {},
|
|
5099
6184
|
...columns ? {
|
|
5100
|
-
|
|
6185
|
+
columns: {
|
|
5101
6186
|
count: columns.count,
|
|
5102
6187
|
...columns.spaceTwips !== void 0 ? { space: twips(columns.spaceTwips) } : {},
|
|
5103
6188
|
...columns.separator !== void 0 ? { separate: columns.separator } : {},
|
|
@@ -5141,6 +6226,8 @@ function sectionChildren2(value, ctx, closesDocument = false) {
|
|
|
5141
6226
|
spacing: { before: 0, after: 0, line: 20, lineRule: "exact" }
|
|
5142
6227
|
}
|
|
5143
6228
|
});
|
|
6229
|
+
if (!closesDocument && !bookmark?.closes && last?.kind === "toc")
|
|
6230
|
+
blocks.push({ paragraph: { children: [] } });
|
|
5144
6231
|
if (!bookmark) return blocks;
|
|
5145
6232
|
return [
|
|
5146
6233
|
...bookmark.opens ? [{ bookmarkStart: { id: bookmark.id, name: bookmark.name } }] : [],
|
|
@@ -5151,15 +6238,19 @@ function sectionChildren2(value, ctx, closesDocument = false) {
|
|
|
5151
6238
|
function numberingConfig2(numbering) {
|
|
5152
6239
|
return {
|
|
5153
6240
|
reference: numbering.reference,
|
|
5154
|
-
levels: numbering.levels.map(
|
|
5155
|
-
level
|
|
5156
|
-
|
|
5157
|
-
|
|
5158
|
-
|
|
5159
|
-
|
|
5160
|
-
|
|
5161
|
-
|
|
5162
|
-
|
|
6241
|
+
levels: numbering.levels.map(
|
|
6242
|
+
(level) => ({
|
|
6243
|
+
level: level.level,
|
|
6244
|
+
format: level.format,
|
|
6245
|
+
text: level.text,
|
|
6246
|
+
...level.alignment ? { alignment: alignment(level.alignment) } : {},
|
|
6247
|
+
...level.suffix ? { suffix: level.suffix } : {},
|
|
6248
|
+
// Always stated. docx.js writes `w:start w:val="1"` for a level that
|
|
6249
|
+
// names none, and so did this backend until 0.14, which writes no
|
|
6250
|
+
// `w:start` at all when it is not given one; Word and LibreOffice then
|
|
6251
|
+
// count every such list from 0.
|
|
6252
|
+
start: level.start ?? 1,
|
|
6253
|
+
...level.paragraphStyleId ? { paragraphStyle: level.paragraphStyleId } : {},
|
|
5163
6254
|
...level.indent ? {
|
|
5164
6255
|
paragraph: {
|
|
5165
6256
|
indent: {
|
|
@@ -5169,25 +6260,22 @@ function numberingConfig2(numbering) {
|
|
|
5169
6260
|
}
|
|
5170
6261
|
} : {},
|
|
5171
6262
|
...level.run ? { run: runProperties2(level.run) } : {}
|
|
5172
|
-
}
|
|
5173
|
-
|
|
6263
|
+
})
|
|
6264
|
+
)
|
|
5174
6265
|
};
|
|
5175
6266
|
}
|
|
5176
|
-
var
|
|
6267
|
+
var BODY_ANCHOR;
|
|
5177
6268
|
var init_emit2 = __esm({
|
|
5178
6269
|
"src/renderers/office-open/emit.ts"() {
|
|
5179
6270
|
"use strict";
|
|
5180
6271
|
init_units();
|
|
5181
|
-
|
|
5182
|
-
|
|
5183
|
-
|
|
5184
|
-
tight: 2,
|
|
5185
|
-
topAndBottom: 3
|
|
5186
|
-
};
|
|
6272
|
+
init_chartWorkbook();
|
|
6273
|
+
init_chartLook();
|
|
6274
|
+
init_chartParts();
|
|
5187
6275
|
BODY_ANCHOR = {
|
|
5188
|
-
top: "
|
|
5189
|
-
middle: "
|
|
5190
|
-
bottom: "
|
|
6276
|
+
top: "top",
|
|
6277
|
+
middle: "center",
|
|
6278
|
+
bottom: "bottom"
|
|
5191
6279
|
};
|
|
5192
6280
|
}
|
|
5193
6281
|
});
|
|
@@ -5247,37 +6335,49 @@ var init_styles3 = __esm({
|
|
|
5247
6335
|
var office_open_exports = {};
|
|
5248
6336
|
__export(office_open_exports, {
|
|
5249
6337
|
OFFICE_OPEN_DOCX_RENDERER_ID: () => OFFICE_OPEN_DOCX_RENDERER_ID,
|
|
6338
|
+
OFFICE_OPEN_VERSION: () => OFFICE_OPEN_VERSION,
|
|
5250
6339
|
buildDocumentOptions: () => buildDocumentOptions,
|
|
5251
6340
|
createOfficeOpenDocxRenderer: () => createOfficeOpenDocxRenderer
|
|
5252
6341
|
});
|
|
5253
|
-
import
|
|
6342
|
+
import AdmZip5 from "adm-zip";
|
|
6343
|
+
import {
|
|
6344
|
+
assertBackendVersion,
|
|
6345
|
+
installedPackageVersion
|
|
6346
|
+
} from "@json-to-office/shared/rendering/node";
|
|
6347
|
+
function installedBackendVersion() {
|
|
6348
|
+
let resolved;
|
|
6349
|
+
try {
|
|
6350
|
+
resolved = import.meta.resolve?.(OFFICE_OPEN_DOCX);
|
|
6351
|
+
} catch {
|
|
6352
|
+
resolved = void 0;
|
|
6353
|
+
}
|
|
6354
|
+
return installedPackageVersion(OFFICE_OPEN_DOCX, import.meta.url, resolved);
|
|
6355
|
+
}
|
|
5254
6356
|
async function createOfficeOpenDocxRenderer() {
|
|
5255
6357
|
const backend = await import(
|
|
5256
6358
|
/* @vite-ignore */
|
|
5257
6359
|
OFFICE_OPEN_DOCX
|
|
5258
6360
|
);
|
|
5259
|
-
|
|
5260
|
-
|
|
5261
|
-
|
|
5262
|
-
|
|
5263
|
-
|
|
5264
|
-
|
|
5265
|
-
|
|
5266
|
-
);
|
|
5267
|
-
|
|
6361
|
+
assertBackendVersion(
|
|
6362
|
+
OFFICE_OPEN_DOCX,
|
|
6363
|
+
OFFICE_OPEN_VERSION,
|
|
6364
|
+
installedBackendVersion()
|
|
6365
|
+
);
|
|
6366
|
+
if (typeof backend.generateDocument !== "function") {
|
|
6367
|
+
throw new Error(
|
|
6368
|
+
`${OFFICE_OPEN_DOCX} does not export generateDocument(); the installed version is not compatible with this adapter.`
|
|
6369
|
+
);
|
|
5268
6370
|
}
|
|
5269
6371
|
return {
|
|
5270
6372
|
id: OFFICE_OPEN_DOCX_RENDERER_ID,
|
|
5271
6373
|
format: "docx",
|
|
5272
6374
|
capabilities: OFFICE_OPEN_CAPABILITIES,
|
|
5273
6375
|
async render(ir, options) {
|
|
5274
|
-
const
|
|
5275
|
-
const cellTocs = [];
|
|
6376
|
+
const charts2 = [];
|
|
5276
6377
|
const document = await buildDocumentOptions(
|
|
5277
6378
|
ir,
|
|
5278
|
-
|
|
5279
|
-
options?.svgRasterFallback
|
|
5280
|
-
cellTocs
|
|
6379
|
+
charts2,
|
|
6380
|
+
options?.svgRasterFallback
|
|
5281
6381
|
);
|
|
5282
6382
|
const bytes = await backend.generateDocument(document, {
|
|
5283
6383
|
type: "uint8array"
|
|
@@ -5285,10 +6385,10 @@ async function createOfficeOpenDocxRenderer() {
|
|
|
5285
6385
|
let raw = Buffer.from(
|
|
5286
6386
|
bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes)
|
|
5287
6387
|
);
|
|
5288
|
-
if (
|
|
5289
|
-
const zip = new
|
|
5290
|
-
|
|
5291
|
-
|
|
6388
|
+
if (ir.theme || charts2.length > 0) {
|
|
6389
|
+
const zip = new AdmZip5(raw);
|
|
6390
|
+
if (ir.theme) spliceTheme(zip, ir.theme);
|
|
6391
|
+
finishChartParts(zip, charts2);
|
|
5292
6392
|
raw = zip.toBuffer();
|
|
5293
6393
|
}
|
|
5294
6394
|
if (options?.deterministic === false)
|
|
@@ -5305,13 +6405,12 @@ async function createOfficeOpenDocxRenderer() {
|
|
|
5305
6405
|
}
|
|
5306
6406
|
};
|
|
5307
6407
|
}
|
|
5308
|
-
async function buildDocumentOptions(ir,
|
|
6408
|
+
async function buildDocumentOptions(ir, charts2 = [], svgRasterFallback) {
|
|
5309
6409
|
let nextDrawingId = 1;
|
|
5310
6410
|
const ctx = {
|
|
5311
6411
|
pictures: await prepareImages2(ir, svgRasterFallback),
|
|
5312
6412
|
nextDrawingId: () => nextDrawingId++,
|
|
5313
|
-
charts
|
|
5314
|
-
cellTocs
|
|
6413
|
+
charts: charts2
|
|
5315
6414
|
};
|
|
5316
6415
|
return {
|
|
5317
6416
|
styles: emitStyles2(ir.styles),
|
|
@@ -5319,16 +6418,20 @@ async function buildDocumentOptions(ir, charts = [], svgRasterFallback, cellTocs
|
|
|
5319
6418
|
(value, index) => section(value, ctx, index === ir.sections.length - 1)
|
|
5320
6419
|
),
|
|
5321
6420
|
...coreProperties2(ir),
|
|
5322
|
-
|
|
6421
|
+
settings: {
|
|
5323
6422
|
updateFields: ir.settings.updateFields,
|
|
5324
6423
|
...ir.settings.trackRevisions ? { trackRevisions: true } : {}
|
|
5325
6424
|
},
|
|
5326
|
-
...ir.numbering.length > 0 ? {
|
|
6425
|
+
...ir.numbering.length > 0 ? {
|
|
6426
|
+
numbering: {
|
|
6427
|
+
abstractNumberings: ir.numbering.map(numberingConfig2)
|
|
6428
|
+
}
|
|
6429
|
+
} : {},
|
|
5327
6430
|
...ir.footnotes.length > 0 ? { footnotes: noteBodies2(ir.footnotes, ctx) } : {},
|
|
5328
6431
|
...ir.endnotes.length > 0 ? { endnotes: noteBodies2(ir.endnotes, ctx) } : {},
|
|
5329
6432
|
...ir.comments.length > 0 ? {
|
|
5330
|
-
comments:
|
|
5331
|
-
|
|
6433
|
+
comments: ir.comments.map(
|
|
6434
|
+
(comment) => ({
|
|
5332
6435
|
id: comment.id,
|
|
5333
6436
|
author: comment.author,
|
|
5334
6437
|
...comment.initials ? { initials: comment.initials } : {},
|
|
@@ -5336,29 +6439,25 @@ async function buildDocumentOptions(ir, charts = [], svgRasterFallback, cellTocs
|
|
|
5336
6439
|
children: comment.children.map(
|
|
5337
6440
|
(child) => paragraphOf(child, ctx)
|
|
5338
6441
|
)
|
|
5339
|
-
})
|
|
5340
|
-
|
|
6442
|
+
})
|
|
6443
|
+
)
|
|
5341
6444
|
} : {}
|
|
5342
6445
|
};
|
|
5343
6446
|
}
|
|
5344
6447
|
function paragraphOf(value, ctx) {
|
|
5345
6448
|
const emitted = block(value, ctx);
|
|
5346
|
-
|
|
5347
|
-
if (!asParagraph) {
|
|
6449
|
+
if (!("paragraph" in emitted) || typeof emitted.paragraph === "string") {
|
|
5348
6450
|
throw new Error(
|
|
5349
6451
|
`the office-open renderer expected a paragraph, not a "${value.kind}"`
|
|
5350
6452
|
);
|
|
5351
6453
|
}
|
|
5352
|
-
return
|
|
6454
|
+
return emitted.paragraph;
|
|
5353
6455
|
}
|
|
5354
6456
|
function noteBodies2(notes, ctx) {
|
|
5355
|
-
|
|
5356
|
-
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
};
|
|
5360
|
-
}
|
|
5361
|
-
return bodies;
|
|
6457
|
+
return notes.map((note) => ({
|
|
6458
|
+
id: note.id,
|
|
6459
|
+
children: note.children.map((child) => paragraphOf(child, ctx))
|
|
6460
|
+
}));
|
|
5362
6461
|
}
|
|
5363
6462
|
async function prepareImages2(ir, svgRasterFallback) {
|
|
5364
6463
|
const placements = collectImagePlacements2(ir);
|
|
@@ -5381,23 +6480,16 @@ async function prepareImages2(ir, svgRasterFallback) {
|
|
|
5381
6480
|
if (resource.kind !== "image") continue;
|
|
5382
6481
|
const type = resource.mediaType;
|
|
5383
6482
|
const data = Buffer.from(resource.bytes);
|
|
5384
|
-
const placementData = /* @__PURE__ */ new Map();
|
|
5385
|
-
[...placements.get(resource.id) ?? []].forEach((size, index) => {
|
|
5386
|
-
placementData.set(
|
|
5387
|
-
size,
|
|
5388
|
-
index === 0 ? data : distinguishImageBytes(data, type, size)
|
|
5389
|
-
);
|
|
5390
|
-
});
|
|
5391
6483
|
resources.set(resource.id, (placement) => {
|
|
5392
6484
|
const sizeKey = placementKey(placement);
|
|
5393
6485
|
const stem = `${resource.id}-${sizeKey}`;
|
|
5394
6486
|
return {
|
|
5395
6487
|
type,
|
|
5396
|
-
//
|
|
5397
|
-
//
|
|
5398
|
-
//
|
|
5399
|
-
//
|
|
5400
|
-
data
|
|
6488
|
+
// The same bytes at every size: the backend keeps each drawing's
|
|
6489
|
+
// extent on the drawing. 0.11 kept it on its deduplicated media
|
|
6490
|
+
// entry, and an image drawn at a second size took the first one's,
|
|
6491
|
+
// unless its bytes were told apart.
|
|
6492
|
+
data,
|
|
5401
6493
|
// Named after the resource and the size it is drawn at, so two
|
|
5402
6494
|
// placements of one image at one size share a single part and a third
|
|
5403
6495
|
// at another size gets its own.
|
|
@@ -5420,104 +6512,6 @@ async function prepareImages2(ir, svgRasterFallback) {
|
|
|
5420
6512
|
function placementKey(placement) {
|
|
5421
6513
|
return `${emuToPixels(placement.widthEmu)}x${emuToPixels(placement.heightEmu)}`;
|
|
5422
6514
|
}
|
|
5423
|
-
function distinguishImageBytes(data, mediaType, placement) {
|
|
5424
|
-
const marker = Buffer.from(`json-to-office:${placement}`, "utf8");
|
|
5425
|
-
switch (mediaType) {
|
|
5426
|
-
case "png":
|
|
5427
|
-
return addPngTextChunk(data, marker);
|
|
5428
|
-
case "jpg":
|
|
5429
|
-
return addJpegComment(data, marker);
|
|
5430
|
-
case "gif":
|
|
5431
|
-
return addGifComment(data, marker);
|
|
5432
|
-
case "svg":
|
|
5433
|
-
return Buffer.concat([
|
|
5434
|
-
data,
|
|
5435
|
-
Buffer.from(`
|
|
5436
|
-
<!-- ${marker.toString("utf8")} -->`, "utf8")
|
|
5437
|
-
]);
|
|
5438
|
-
case "bmp": {
|
|
5439
|
-
const marked = Buffer.concat([data, marker]);
|
|
5440
|
-
if (marked.length >= 14 && marked.subarray(0, 2).toString("ascii") === "BM") {
|
|
5441
|
-
marked.writeUInt32LE(marked.length, 2);
|
|
5442
|
-
}
|
|
5443
|
-
return marked;
|
|
5444
|
-
}
|
|
5445
|
-
default:
|
|
5446
|
-
return Buffer.concat([data, marker]);
|
|
5447
|
-
}
|
|
5448
|
-
}
|
|
5449
|
-
function addPngTextChunk(data, marker) {
|
|
5450
|
-
const signature = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]);
|
|
5451
|
-
if (data.length < 8 || !data.subarray(0, 8).equals(signature)) {
|
|
5452
|
-
return Buffer.concat([data, marker]);
|
|
5453
|
-
}
|
|
5454
|
-
let offset = 8;
|
|
5455
|
-
while (offset + 12 <= data.length) {
|
|
5456
|
-
const payloadLength = data.readUInt32BE(offset);
|
|
5457
|
-
const chunkEnd = offset + 12 + payloadLength;
|
|
5458
|
-
if (chunkEnd > data.length) break;
|
|
5459
|
-
if (data.subarray(offset + 4, offset + 8).toString("ascii") === "IEND") {
|
|
5460
|
-
const payload = Buffer.concat([
|
|
5461
|
-
Buffer.from("json-to-office\0", "latin1"),
|
|
5462
|
-
marker
|
|
5463
|
-
]);
|
|
5464
|
-
const chunk = Buffer.alloc(12 + payload.length);
|
|
5465
|
-
chunk.writeUInt32BE(payload.length, 0);
|
|
5466
|
-
chunk.write("tEXt", 4, 4, "ascii");
|
|
5467
|
-
payload.copy(chunk, 8);
|
|
5468
|
-
chunk.writeUInt32BE(
|
|
5469
|
-
crc32(chunk.subarray(4, 8 + payload.length)),
|
|
5470
|
-
8 + payload.length
|
|
5471
|
-
);
|
|
5472
|
-
return Buffer.concat([
|
|
5473
|
-
data.subarray(0, offset),
|
|
5474
|
-
chunk,
|
|
5475
|
-
data.subarray(offset)
|
|
5476
|
-
]);
|
|
5477
|
-
}
|
|
5478
|
-
offset = chunkEnd;
|
|
5479
|
-
}
|
|
5480
|
-
throw new Error(
|
|
5481
|
-
"Cannot mark a PNG that has no intact IEND chunk; its bytes were not checked to decode before rendering"
|
|
5482
|
-
);
|
|
5483
|
-
}
|
|
5484
|
-
function addJpegComment(data, marker) {
|
|
5485
|
-
if (data.length < 2 || data[0] !== 255 || data[1] !== 216) {
|
|
5486
|
-
return Buffer.concat([data, marker]);
|
|
5487
|
-
}
|
|
5488
|
-
const comment = Buffer.alloc(4 + marker.length);
|
|
5489
|
-
comment[0] = 255;
|
|
5490
|
-
comment[1] = 254;
|
|
5491
|
-
comment.writeUInt16BE(marker.length + 2, 2);
|
|
5492
|
-
marker.copy(comment, 4);
|
|
5493
|
-
return Buffer.concat([data.subarray(0, 2), comment, data.subarray(2)]);
|
|
5494
|
-
}
|
|
5495
|
-
function addGifComment(data, marker) {
|
|
5496
|
-
const trailer = data.lastIndexOf(59);
|
|
5497
|
-
if (trailer < 0 || marker.length > 255) {
|
|
5498
|
-
return Buffer.concat([data, marker]);
|
|
5499
|
-
}
|
|
5500
|
-
const comment = Buffer.concat([
|
|
5501
|
-
Buffer.from([33, 254, marker.length]),
|
|
5502
|
-
marker,
|
|
5503
|
-
Buffer.from([0])
|
|
5504
|
-
]);
|
|
5505
|
-
return Buffer.concat([
|
|
5506
|
-
data.subarray(0, trailer),
|
|
5507
|
-
comment,
|
|
5508
|
-
data.subarray(trailer)
|
|
5509
|
-
]);
|
|
5510
|
-
}
|
|
5511
|
-
function crc32(data) {
|
|
5512
|
-
let crc = 4294967295;
|
|
5513
|
-
for (const byte of data) {
|
|
5514
|
-
crc ^= byte;
|
|
5515
|
-
for (let bit = 0; bit < 8; bit += 1) {
|
|
5516
|
-
crc = crc >>> 1 ^ (crc & 1 ? 3988292384 : 0);
|
|
5517
|
-
}
|
|
5518
|
-
}
|
|
5519
|
-
return (crc ^ 4294967295) >>> 0;
|
|
5520
|
-
}
|
|
5521
6515
|
function collectImagePlacements2(ir) {
|
|
5522
6516
|
const placements = /* @__PURE__ */ new Map();
|
|
5523
6517
|
const record = (resourceId, placement) => {
|
|
@@ -5585,18 +6579,19 @@ function coreProperties2(ir) {
|
|
|
5585
6579
|
...metadata.custom?.length ? { customProperties: metadata.custom } : {}
|
|
5586
6580
|
};
|
|
5587
6581
|
}
|
|
5588
|
-
var OFFICE_OPEN_DOCX_RENDERER_ID, OFFICE_OPEN_DOCX, OFFICE_OPEN_CAPABILITIES;
|
|
6582
|
+
var OFFICE_OPEN_DOCX_RENDERER_ID, OFFICE_OPEN_DOCX, OFFICE_OPEN_VERSION, OFFICE_OPEN_CAPABILITIES;
|
|
5589
6583
|
var init_office_open = __esm({
|
|
5590
6584
|
"src/renderers/office-open/index.ts"() {
|
|
5591
6585
|
"use strict";
|
|
5592
6586
|
init_chartParts();
|
|
5593
|
-
|
|
6587
|
+
init_themePart();
|
|
5594
6588
|
init_imageUtils();
|
|
5595
6589
|
init_packageDocument();
|
|
5596
6590
|
init_emit2();
|
|
5597
6591
|
init_styles3();
|
|
5598
6592
|
OFFICE_OPEN_DOCX_RENDERER_ID = "office-open";
|
|
5599
6593
|
OFFICE_OPEN_DOCX = "@office-open/docx";
|
|
6594
|
+
OFFICE_OPEN_VERSION = "0.14.6";
|
|
5600
6595
|
OFFICE_OPEN_CAPABILITIES = /* @__PURE__ */ new Set([
|
|
5601
6596
|
"paragraphs",
|
|
5602
6597
|
"styles",
|
|
@@ -9227,6 +10222,7 @@ function emptyToUndefined(formatting) {
|
|
|
9227
10222
|
}
|
|
9228
10223
|
|
|
9229
10224
|
// src/ir/compiler.ts
|
|
10225
|
+
init_chartValues();
|
|
9230
10226
|
init_types();
|
|
9231
10227
|
|
|
9232
10228
|
// src/ir/measure.ts
|
|
@@ -9259,6 +10255,49 @@ function tableWidthTwips(width, measureTwips) {
|
|
|
9259
10255
|
|
|
9260
10256
|
// src/ir/compiler.ts
|
|
9261
10257
|
init_units();
|
|
10258
|
+
|
|
10259
|
+
// src/ir/theme.ts
|
|
10260
|
+
init_colorUtils();
|
|
10261
|
+
init_styleHelpers();
|
|
10262
|
+
init_types();
|
|
10263
|
+
var THEME_COLOR_TOKENS = [
|
|
10264
|
+
["dark1", "text"],
|
|
10265
|
+
["light1", "background"],
|
|
10266
|
+
["dark2", "textSecondary"],
|
|
10267
|
+
["light2", "backgroundSecondary"],
|
|
10268
|
+
["accent1", "primary"],
|
|
10269
|
+
["accent2", "secondary"],
|
|
10270
|
+
["accent3", "accent"],
|
|
10271
|
+
["accent4", "accent4"],
|
|
10272
|
+
["accent5", "accent5"],
|
|
10273
|
+
["accent6", "accent6"]
|
|
10274
|
+
];
|
|
10275
|
+
var NOT_XML_CHARS = new RegExp(NOT_XML_CHAR.source, "gu");
|
|
10276
|
+
var xmlText = (value) => (value ?? "").replace(NOT_XML_CHARS, "").trim();
|
|
10277
|
+
function compileTheme(theme, themeName) {
|
|
10278
|
+
const colors = {};
|
|
10279
|
+
for (const [slot, token] of THEME_COLOR_TOKENS) {
|
|
10280
|
+
const hex = schemeHex(token, theme);
|
|
10281
|
+
if (hex) colors[slot] = { hex };
|
|
10282
|
+
}
|
|
10283
|
+
const headingFont = xmlText(resolveFontFamily(theme, "heading"));
|
|
10284
|
+
const bodyFont = xmlText(resolveFontFamily(theme, "body"));
|
|
10285
|
+
return {
|
|
10286
|
+
name: xmlText(theme.name) || xmlText(themeName) || "Office Theme",
|
|
10287
|
+
colors,
|
|
10288
|
+
...headingFont ? { headingFont } : {},
|
|
10289
|
+
...bodyFont ? { bodyFont } : {}
|
|
10290
|
+
};
|
|
10291
|
+
}
|
|
10292
|
+
function schemeHex(token, theme) {
|
|
10293
|
+
try {
|
|
10294
|
+
return resolveColor(token, theme);
|
|
10295
|
+
} catch {
|
|
10296
|
+
return void 0;
|
|
10297
|
+
}
|
|
10298
|
+
}
|
|
10299
|
+
|
|
10300
|
+
// src/ir/compiler.ts
|
|
9262
10301
|
var CONTENT_BOOKMARK_ID_BASE = 2e6;
|
|
9263
10302
|
var SINGLE_LINE_TWIPS = 240;
|
|
9264
10303
|
function compileDocument(structure, layout, warnings = [], images = /* @__PURE__ */ new Map(), options = {}) {
|
|
@@ -9324,6 +10363,7 @@ function compileDocument(structure, layout, warnings = [], images = /* @__PURE__
|
|
|
9324
10363
|
trackRevisions: structure.trackRevisions === true,
|
|
9325
10364
|
...noProofWords(structure.theme) ? { noProofWords: noProofWords(structure.theme) } : {}
|
|
9326
10365
|
},
|
|
10366
|
+
theme: compileTheme(structure.theme, structure.themeName),
|
|
9327
10367
|
// The statistic styles are appended rather than built with the rest: a
|
|
9328
10368
|
// document that uses no statistic must keep the exact style set it had
|
|
9329
10369
|
// before the component had styles, or every recorded golden moves for a
|
|
@@ -10092,14 +11132,6 @@ function compileShape2(props, children, scope) {
|
|
|
10092
11132
|
);
|
|
10093
11133
|
}
|
|
10094
11134
|
const fill = style?.shading?.fill;
|
|
10095
|
-
const dropOutline = Boolean(fill) && Boolean(outline.outline);
|
|
10096
|
-
if (dropOutline) {
|
|
10097
|
-
warnOnce(
|
|
10098
|
-
ctx,
|
|
10099
|
-
"text-box",
|
|
10100
|
-
'[core-docx] text-box renderAs "shape" cannot carry a fill and a border at once (docx emits invalid shape properties); keeping the fill and dropping the border.'
|
|
10101
|
-
);
|
|
10102
|
-
}
|
|
10103
11135
|
ctx.features.require("text-boxes", path4);
|
|
10104
11136
|
if (props.floating) ctx.features.require("floating-images", path4);
|
|
10105
11137
|
const insets = shapeInsets(
|
|
@@ -10118,7 +11150,7 @@ function compileShape2(props, children, scope) {
|
|
|
10118
11150
|
heightPx: height.pixels,
|
|
10119
11151
|
children,
|
|
10120
11152
|
...fill ? { fill: irColor(resolveColor(fill, ctx.theme)) } : {},
|
|
10121
|
-
...outline.outline
|
|
11153
|
+
...outline.outline ? { outline: outline.outline } : {},
|
|
10122
11154
|
...insets ? { insetsEmu: insets } : {},
|
|
10123
11155
|
...props.floating ? { floating: compileFloating(props.floating, ctx, path4) } : {}
|
|
10124
11156
|
}
|
|
@@ -11341,6 +12373,7 @@ function compileImage2(component, scope) {
|
|
|
11341
12373
|
}
|
|
11342
12374
|
var DEFAULT_CHART_HEIGHT_INCHES = 3;
|
|
11343
12375
|
var MAX_CHART_TEXT_POINTS = 10;
|
|
12376
|
+
var MIN_CHART_TEXT_POINTS = 1;
|
|
11344
12377
|
function chartTextFont(theme) {
|
|
11345
12378
|
const bodySize = getThemeFonts(theme).body?.size;
|
|
11346
12379
|
let color = "000000";
|
|
@@ -11350,9 +12383,12 @@ function chartTextFont(theme) {
|
|
|
11350
12383
|
}
|
|
11351
12384
|
return {
|
|
11352
12385
|
fontFamily: resolveFontFamily(theme, "body"),
|
|
11353
|
-
fontSize: Math.
|
|
11354
|
-
|
|
11355
|
-
|
|
12386
|
+
fontSize: Math.max(
|
|
12387
|
+
MIN_CHART_TEXT_POINTS,
|
|
12388
|
+
Math.min(
|
|
12389
|
+
typeof bodySize === "number" && bodySize > 0 ? bodySize : 11,
|
|
12390
|
+
MAX_CHART_TEXT_POINTS
|
|
12391
|
+
)
|
|
11356
12392
|
),
|
|
11357
12393
|
bold: false,
|
|
11358
12394
|
color
|
|
@@ -11363,7 +12399,7 @@ function compileChart(component, scope) {
|
|
|
11363
12399
|
const props = component.props ?? {};
|
|
11364
12400
|
if (props.type === "bubble") {
|
|
11365
12401
|
throw new Error(
|
|
11366
|
-
`Chart at ${path4} is a bubble chart,
|
|
12402
|
+
`Chart at ${path4} is a bubble chart, but the docx \`chart\` component has no bubble sizes; use the pptx \`chart\` component on the pptxgenjs renderer.`
|
|
11367
12403
|
);
|
|
11368
12404
|
}
|
|
11369
12405
|
const rawSeries = Array.isArray(props.data) ? props.data : [];
|
|
@@ -11385,10 +12421,22 @@ function compileChart(component, scope) {
|
|
|
11385
12421
|
`Chart series "${label}" at ${path4} has ${labels.length} labels and ${values.length} values; they must be the same length.`
|
|
11386
12422
|
);
|
|
11387
12423
|
}
|
|
12424
|
+
if (labels.length === 0) {
|
|
12425
|
+
throw new Error(
|
|
12426
|
+
`Chart series "${label}" at ${path4} has no data points; give it at least one label and value.`
|
|
12427
|
+
);
|
|
12428
|
+
}
|
|
12429
|
+
const numbers = values.map((value) => Number(value));
|
|
12430
|
+
const bad = numbers.findIndex((value) => !Number.isFinite(value));
|
|
12431
|
+
if (bad !== -1) {
|
|
12432
|
+
throw new Error(
|
|
12433
|
+
`Chart series "${label}" at ${path4} has a value that is not a finite number (${JSON.stringify(values[bad])} at "${String(labels[bad])}").`
|
|
12434
|
+
);
|
|
12435
|
+
}
|
|
11388
12436
|
return {
|
|
11389
12437
|
...typeof raw.name === "string" ? { name: raw.name } : {},
|
|
11390
12438
|
labels: labels.map((value) => String(value)),
|
|
11391
|
-
values:
|
|
12439
|
+
values: numbers
|
|
11392
12440
|
};
|
|
11393
12441
|
});
|
|
11394
12442
|
const categories = series[0].labels;
|
|
@@ -11400,6 +12448,44 @@ function compileChart(component, scope) {
|
|
|
11400
12448
|
);
|
|
11401
12449
|
}
|
|
11402
12450
|
}
|
|
12451
|
+
if (props.type === "pie" && series.length > 1) {
|
|
12452
|
+
throw new Error(
|
|
12453
|
+
`Chart at ${path4} is a pie with ${series.length} series; a pie draws one series. Use a doughnut for one ring per series, or a column chart to compare them.`
|
|
12454
|
+
);
|
|
12455
|
+
}
|
|
12456
|
+
if (props.type === "pie" || props.type === "doughnut") {
|
|
12457
|
+
for (const [index, entry] of series.entries()) {
|
|
12458
|
+
const at = entry.values.findIndex((value) => value < 0);
|
|
12459
|
+
if (at === -1) continue;
|
|
12460
|
+
throw new Error(
|
|
12461
|
+
`Chart series "${entry.name ?? `series ${index}`}" at ${path4} has a negative value (${entry.values[at]} at "${entry.labels[at]}"); a ${props.type} chart draws each value as a share of the whole.`
|
|
12462
|
+
);
|
|
12463
|
+
}
|
|
12464
|
+
}
|
|
12465
|
+
if (props.type === "scatter") {
|
|
12466
|
+
for (const [index, entry] of series.entries()) {
|
|
12467
|
+
const at = entry.labels.findIndex(isOutOfRangeNumericLabel);
|
|
12468
|
+
if (at !== -1) {
|
|
12469
|
+
throw new Error(
|
|
12470
|
+
`Chart series "${entry.name ?? `series ${index}`}" at ${path4} has an x label ${JSON.stringify(entry.labels[at])} outside the finite number range.`
|
|
12471
|
+
);
|
|
12472
|
+
}
|
|
12473
|
+
}
|
|
12474
|
+
}
|
|
12475
|
+
if (props.type === "scatter" && series.some((entry) => entry.labels.some((label) => !isNumericLabel(label)))) {
|
|
12476
|
+
warnOnce(
|
|
12477
|
+
ctx,
|
|
12478
|
+
"chart",
|
|
12479
|
+
`Chart at ${path4} is a scatter chart whose labels are not all finite numbers; labels that do not read as finite numbers use their 1-based positions for x.`
|
|
12480
|
+
);
|
|
12481
|
+
}
|
|
12482
|
+
if ((props.type === "pie" || props.type === "doughnut") && (typeof props.catAxisTitle === "string" || typeof props.valAxisTitle === "string")) {
|
|
12483
|
+
warnOnce(
|
|
12484
|
+
ctx,
|
|
12485
|
+
"chart",
|
|
12486
|
+
`Chart at ${path4} is a ${props.type} chart, which has no axes; its axis titles are not drawn.`
|
|
12487
|
+
);
|
|
12488
|
+
}
|
|
11403
12489
|
const colors = Array.isArray(props.chartColors) ? props.chartColors.map(
|
|
11404
12490
|
(color) => resolveColor(String(color), ctx.theme)
|
|
11405
12491
|
) : chartPaletteValues(ctx.theme).flatMap((value) => {
|
|
@@ -11412,13 +12498,21 @@ function compileChart(component, scope) {
|
|
|
11412
12498
|
const contentWidthInches = scope.measureTwips / 1440;
|
|
11413
12499
|
const widthInches = typeof props.width === "number" ? props.width : contentWidthInches;
|
|
11414
12500
|
const heightInches = typeof props.height === "number" ? props.height : DEFAULT_CHART_HEIGHT_INCHES;
|
|
12501
|
+
const widthEmu = inchesToEmu(widthInches);
|
|
12502
|
+
const heightEmu = inchesToEmu(heightInches);
|
|
12503
|
+
if (!(widthEmu > 0 && heightEmu > 0)) {
|
|
12504
|
+
const inches = (value) => String(Number.isFinite(value) ? Math.round(value * 100) / 100 : value);
|
|
12505
|
+
throw new Error(
|
|
12506
|
+
`Chart at ${path4} has no room: it would be ${inches(widthInches)}\xD7${inches(heightInches)} in. Set \`width\`/\`height\`, or give it a container with space.`
|
|
12507
|
+
);
|
|
12508
|
+
}
|
|
11415
12509
|
const chart = {
|
|
11416
12510
|
kind: "chart",
|
|
11417
12511
|
chartType: props.type,
|
|
11418
12512
|
series,
|
|
11419
12513
|
colors,
|
|
11420
|
-
widthEmu
|
|
11421
|
-
heightEmu
|
|
12514
|
+
widthEmu,
|
|
12515
|
+
heightEmu,
|
|
11422
12516
|
...typeof props.title === "string" ? { title: props.title } : {},
|
|
11423
12517
|
...props.showTitle !== void 0 ? { showTitle: props.showTitle } : {},
|
|
11424
12518
|
...props.showLegend !== void 0 ? { showLegend: props.showLegend } : {},
|
|
@@ -11621,7 +12715,7 @@ function compileFrame(floating, ctx, path4) {
|
|
|
11621
12715
|
function compileFloating(floating, ctx, path4) {
|
|
11622
12716
|
if (floating.wrap?.type === "tight") {
|
|
11623
12717
|
throw new Error(
|
|
11624
|
-
"Image floating wrap.type 'tight' is not supported
|
|
12718
|
+
"Image floating wrap.type 'tight' is not supported. Use 'square', 'topAndBottom', or 'none'."
|
|
11625
12719
|
);
|
|
11626
12720
|
}
|
|
11627
12721
|
const hRelative = floating.horizontalPosition?.relative;
|
|
@@ -15783,18 +16877,18 @@ var docxExhibitRequiredRule = {
|
|
|
15783
16877
|
1
|
|
15784
16878
|
);
|
|
15785
16879
|
if (minimum <= 0) return [];
|
|
15786
|
-
const
|
|
16880
|
+
const charts2 = facts.filter((fact) => fact.kind === "docx/chart").length;
|
|
15787
16881
|
const tables = facts.filter(
|
|
15788
16882
|
(fact) => fact.kind === "docx/table" && fact.columns.length >= 2
|
|
15789
16883
|
).length;
|
|
15790
|
-
const exhibits =
|
|
16884
|
+
const exhibits = charts2 + tables;
|
|
15791
16885
|
if (exhibits >= minimum) return [];
|
|
15792
16886
|
return [
|
|
15793
16887
|
{
|
|
15794
16888
|
path: themeFact(facts)?.path ?? "/props",
|
|
15795
16889
|
message: exhibits === 0 ? `The document carries no data exhibit \u2014 no chart, no table of two or more columns; the ${profile?.id ?? "selected"} profile expects at least ${minimum}.` : `The document carries ${exhibits} data exhibit(s); the ${profile?.id ?? "selected"} profile expects at least ${minimum}.`,
|
|
15796
16890
|
suggestion: "Put the numbers the argument leans on into a chart-figure or a data-table block, with a takeaway and a source, where the text discusses them. A kpi-row summarises; it does not count.",
|
|
15797
|
-
context: { charts, tables, minimum }
|
|
16891
|
+
context: { charts: charts2, tables, minimum }
|
|
15798
16892
|
}
|
|
15799
16893
|
];
|
|
15800
16894
|
}
|