@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
|
@@ -2751,7 +2751,7 @@ var init_imageUtils = __esm({
|
|
|
2751
2751
|
});
|
|
2752
2752
|
|
|
2753
2753
|
// src/ir/types.ts
|
|
2754
|
-
var TWIPS_PER_INCH, TWIPS_PER_POINT2, EMU_PER_INCH, EMU_PER_TWIP, DOCX_IR_SCHEMA_VERSION, DOCX_IR_BORDER_STYLES;
|
|
2754
|
+
var TWIPS_PER_INCH, TWIPS_PER_POINT2, EMU_PER_INCH, EMU_PER_TWIP, DOCX_IR_SCHEMA_VERSION, NOT_XML_CHAR, DOCX_IR_BORDER_STYLES;
|
|
2755
2755
|
var init_types = __esm({
|
|
2756
2756
|
"src/ir/types.ts"() {
|
|
2757
2757
|
"use strict";
|
|
@@ -2760,6 +2760,7 @@ var init_types = __esm({
|
|
|
2760
2760
|
EMU_PER_INCH = 914400;
|
|
2761
2761
|
EMU_PER_TWIP = EMU_PER_INCH / TWIPS_PER_INCH;
|
|
2762
2762
|
DOCX_IR_SCHEMA_VERSION = 1;
|
|
2763
|
+
NOT_XML_CHAR = /[^\t\n\r\u0020-\uD7FF\uE000-\uFFFD\u{10000}-\u{10FFFF}]/u;
|
|
2763
2764
|
DOCX_IR_BORDER_STYLES = [
|
|
2764
2765
|
"single",
|
|
2765
2766
|
"dashDotStroked",
|
|
@@ -2846,6 +2847,242 @@ var init_units = __esm({
|
|
|
2846
2847
|
}
|
|
2847
2848
|
});
|
|
2848
2849
|
|
|
2850
|
+
// src/ir/chartValues.ts
|
|
2851
|
+
function numericLabelValue(label) {
|
|
2852
|
+
const value = label.trim();
|
|
2853
|
+
return NUMERIC_LABEL.test(value) ? Number(value) : void 0;
|
|
2854
|
+
}
|
|
2855
|
+
function isNumericLabel(label) {
|
|
2856
|
+
const value = numericLabelValue(label);
|
|
2857
|
+
return value !== void 0 && Number.isFinite(value);
|
|
2858
|
+
}
|
|
2859
|
+
function isOutOfRangeNumericLabel(label) {
|
|
2860
|
+
const value = numericLabelValue(label);
|
|
2861
|
+
return value !== void 0 && !Number.isFinite(value);
|
|
2862
|
+
}
|
|
2863
|
+
function scatterX(labels, index) {
|
|
2864
|
+
const label = labels[index];
|
|
2865
|
+
const value = label === void 0 ? void 0 : numericLabelValue(label);
|
|
2866
|
+
if (value === void 0) return index + 1;
|
|
2867
|
+
if (!Number.isFinite(value)) {
|
|
2868
|
+
throw new RangeError(
|
|
2869
|
+
`Scatter x label ${JSON.stringify(label)} is not finite.`
|
|
2870
|
+
);
|
|
2871
|
+
}
|
|
2872
|
+
return value;
|
|
2873
|
+
}
|
|
2874
|
+
var NUMERIC_LABEL;
|
|
2875
|
+
var init_chartValues = __esm({
|
|
2876
|
+
"src/ir/chartValues.ts"() {
|
|
2877
|
+
"use strict";
|
|
2878
|
+
NUMERIC_LABEL = /^[+-]?(\d+(\.\d*)?|\.\d+)([eE][+-]?\d+)?$/;
|
|
2879
|
+
}
|
|
2880
|
+
});
|
|
2881
|
+
|
|
2882
|
+
// src/renderers/chartText.ts
|
|
2883
|
+
function chartTextRoles(font) {
|
|
2884
|
+
const { bold, ...rest } = font;
|
|
2885
|
+
const text = rest;
|
|
2886
|
+
return {
|
|
2887
|
+
text,
|
|
2888
|
+
axisTitle: { ...text, bold },
|
|
2889
|
+
title: {
|
|
2890
|
+
...text,
|
|
2891
|
+
fontSize: Math.round(text.fontSize * CHART_TITLE_SCALE),
|
|
2892
|
+
bold: true
|
|
2893
|
+
}
|
|
2894
|
+
};
|
|
2895
|
+
}
|
|
2896
|
+
var CHART_TITLE_SCALE;
|
|
2897
|
+
var init_chartText = __esm({
|
|
2898
|
+
"src/renderers/chartText.ts"() {
|
|
2899
|
+
"use strict";
|
|
2900
|
+
CHART_TITLE_SCALE = 1.4;
|
|
2901
|
+
}
|
|
2902
|
+
});
|
|
2903
|
+
|
|
2904
|
+
// src/renderers/docxjs/docxSubpath.ts
|
|
2905
|
+
function docxSubpath(specifier, component, importer) {
|
|
2906
|
+
let module;
|
|
2907
|
+
let failure;
|
|
2908
|
+
let loading;
|
|
2909
|
+
return {
|
|
2910
|
+
specifier,
|
|
2911
|
+
load() {
|
|
2912
|
+
loading ??= importer().then(
|
|
2913
|
+
(loadedModule) => {
|
|
2914
|
+
module = loadedModule;
|
|
2915
|
+
},
|
|
2916
|
+
(reason) => {
|
|
2917
|
+
failure = { reason };
|
|
2918
|
+
}
|
|
2919
|
+
);
|
|
2920
|
+
return loading;
|
|
2921
|
+
},
|
|
2922
|
+
loaded: () => module !== void 0,
|
|
2923
|
+
get() {
|
|
2924
|
+
if (module !== void 0) return module;
|
|
2925
|
+
if (failure !== void 0) {
|
|
2926
|
+
const { reason } = failure;
|
|
2927
|
+
const detail = reason instanceof Error ? reason.message : String(reason);
|
|
2928
|
+
throw new Error(
|
|
2929
|
+
`The docx \`${component}\` component needs docx 9.8.0 or later: the \`${specifier}\` entry could not be loaded (${detail})`
|
|
2930
|
+
);
|
|
2931
|
+
}
|
|
2932
|
+
throw new Error(
|
|
2933
|
+
`${specifier} is not loaded: await its load() before buildDocument() (render() does)`
|
|
2934
|
+
);
|
|
2935
|
+
}
|
|
2936
|
+
};
|
|
2937
|
+
}
|
|
2938
|
+
var init_docxSubpath = __esm({
|
|
2939
|
+
"src/renderers/docxjs/docxSubpath.ts"() {
|
|
2940
|
+
"use strict";
|
|
2941
|
+
}
|
|
2942
|
+
});
|
|
2943
|
+
|
|
2944
|
+
// src/renderers/docxjs/charts.ts
|
|
2945
|
+
import { assertNever } from "@json-to-office/shared/rendering";
|
|
2946
|
+
function loadDocxCharts() {
|
|
2947
|
+
return charts.load();
|
|
2948
|
+
}
|
|
2949
|
+
function chartFont(role) {
|
|
2950
|
+
return {
|
|
2951
|
+
name: role.fontFamily,
|
|
2952
|
+
size: role.fontSize,
|
|
2953
|
+
color: role.color,
|
|
2954
|
+
bold: role.bold ?? false
|
|
2955
|
+
};
|
|
2956
|
+
}
|
|
2957
|
+
function chartRunOptions(chart, floating) {
|
|
2958
|
+
const roles = chartTextRoles(chart.textFont);
|
|
2959
|
+
const text = chartFont(roles.text);
|
|
2960
|
+
const axisTitle = chartFont(roles.axisTitle);
|
|
2961
|
+
const palette = chart.colors;
|
|
2962
|
+
const colorAt = (index) => palette.length > 0 ? palette[index % palette.length] : void 0;
|
|
2963
|
+
const withColor = (index) => {
|
|
2964
|
+
const color = colorAt(index);
|
|
2965
|
+
return color ? { color } : {};
|
|
2966
|
+
};
|
|
2967
|
+
const seriesName = (index) => chart.series[index].name ?? `Series ${index + 1}`;
|
|
2968
|
+
const categories = chart.series[0]?.labels ?? [];
|
|
2969
|
+
const axis = (title) => ({
|
|
2970
|
+
...title ? { title: { text: title, font: axisTitle } } : {},
|
|
2971
|
+
font: text
|
|
2972
|
+
});
|
|
2973
|
+
const common = {
|
|
2974
|
+
...chart.title && chart.showTitle !== false ? { title: { text: chart.title, font: chartFont(roles.title) } } : {},
|
|
2975
|
+
legend: chart.showLegend === false ? false : {
|
|
2976
|
+
position: LEGEND_POSITION[chart.legendPosition ?? "b"],
|
|
2977
|
+
font: text
|
|
2978
|
+
},
|
|
2979
|
+
font: { name: roles.text.fontFamily, color: roles.text.color },
|
|
2980
|
+
// Office-open's chart space is unfilled and unbordered; `ChartRun`'s
|
|
2981
|
+
// default is Word's white fill and grey border.
|
|
2982
|
+
chartArea: { fill: "none", border: "none" },
|
|
2983
|
+
transformation: {
|
|
2984
|
+
width: emuToPixels(chart.widthEmu),
|
|
2985
|
+
height: emuToPixels(chart.heightEmu)
|
|
2986
|
+
},
|
|
2987
|
+
// Without an authored description `ChartRun` describes the chart from
|
|
2988
|
+
// its data, which is deterministic; the name stays empty, as it is on
|
|
2989
|
+
// every other drawing this renderer writes.
|
|
2990
|
+
...chart.altText ? { altText: { name: "", description: chart.altText } } : {},
|
|
2991
|
+
...floating ? { floating } : {}
|
|
2992
|
+
};
|
|
2993
|
+
switch (chart.chartType) {
|
|
2994
|
+
case "column":
|
|
2995
|
+
case "bar":
|
|
2996
|
+
case "area":
|
|
2997
|
+
case "line":
|
|
2998
|
+
return {
|
|
2999
|
+
...common,
|
|
3000
|
+
type: chart.chartType,
|
|
3001
|
+
categories,
|
|
3002
|
+
...chart.chartType === "line" ? { markers: true } : {},
|
|
3003
|
+
series: chart.series.map((entry, index) => ({
|
|
3004
|
+
name: seriesName(index),
|
|
3005
|
+
values: entry.values,
|
|
3006
|
+
...withColor(index)
|
|
3007
|
+
})),
|
|
3008
|
+
categoryAxis: axis(chart.categoryAxisTitle),
|
|
3009
|
+
valueAxis: axis(chart.valueAxisTitle)
|
|
3010
|
+
};
|
|
3011
|
+
case "pie":
|
|
3012
|
+
case "doughnut":
|
|
3013
|
+
return {
|
|
3014
|
+
...common,
|
|
3015
|
+
type: chart.chartType,
|
|
3016
|
+
categories,
|
|
3017
|
+
series: chart.series.map((entry, index) => ({
|
|
3018
|
+
name: seriesName(index),
|
|
3019
|
+
values: entry.values,
|
|
3020
|
+
...palette.length > 0 ? { colors: entry.values.map((_, point) => colorAt(point)) } : {}
|
|
3021
|
+
}))
|
|
3022
|
+
};
|
|
3023
|
+
case "radar":
|
|
3024
|
+
return {
|
|
3025
|
+
...common,
|
|
3026
|
+
type: "radar",
|
|
3027
|
+
categories,
|
|
3028
|
+
markers: true,
|
|
3029
|
+
series: chart.series.map((entry, index) => ({
|
|
3030
|
+
name: seriesName(index),
|
|
3031
|
+
values: entry.values,
|
|
3032
|
+
...withColor(index)
|
|
3033
|
+
})),
|
|
3034
|
+
categoryAxis: axis(chart.categoryAxisTitle),
|
|
3035
|
+
valueAxis: axis(chart.valueAxisTitle)
|
|
3036
|
+
};
|
|
3037
|
+
case "scatter":
|
|
3038
|
+
return {
|
|
3039
|
+
...common,
|
|
3040
|
+
type: "scatter",
|
|
3041
|
+
markers: true,
|
|
3042
|
+
lines: "straight",
|
|
3043
|
+
series: chart.series.map((entry, index) => ({
|
|
3044
|
+
name: seriesName(index),
|
|
3045
|
+
points: entry.values.map((y, point) => ({
|
|
3046
|
+
x: scatterX(entry.labels, point),
|
|
3047
|
+
y
|
|
3048
|
+
})),
|
|
3049
|
+
...withColor(index)
|
|
3050
|
+
})),
|
|
3051
|
+
xAxis: { ...axis(chart.categoryAxisTitle), gridlines: false },
|
|
3052
|
+
yAxis: axis(chart.valueAxisTitle)
|
|
3053
|
+
};
|
|
3054
|
+
case "bubble":
|
|
3055
|
+
throw new Error(
|
|
3056
|
+
"the docxjs renderer has no emitter for a bubble chart; the compiler should have refused it"
|
|
3057
|
+
);
|
|
3058
|
+
default:
|
|
3059
|
+
return assertNever(chart.chartType, "DocxIrChartType");
|
|
3060
|
+
}
|
|
3061
|
+
}
|
|
3062
|
+
function emitChart(chart, floating) {
|
|
3063
|
+
return new (charts.get()).ChartRun(
|
|
3064
|
+
chartRunOptions(chart, floating)
|
|
3065
|
+
);
|
|
3066
|
+
}
|
|
3067
|
+
var charts, LEGEND_POSITION;
|
|
3068
|
+
var init_charts = __esm({
|
|
3069
|
+
"src/renderers/docxjs/charts.ts"() {
|
|
3070
|
+
"use strict";
|
|
3071
|
+
init_chartValues();
|
|
3072
|
+
init_units();
|
|
3073
|
+
init_chartText();
|
|
3074
|
+
init_docxSubpath();
|
|
3075
|
+
charts = docxSubpath("docx/charts", "chart", () => import("docx/charts"));
|
|
3076
|
+
LEGEND_POSITION = {
|
|
3077
|
+
b: "bottom",
|
|
3078
|
+
l: "left",
|
|
3079
|
+
r: "right",
|
|
3080
|
+
t: "top",
|
|
3081
|
+
tr: "topRight"
|
|
3082
|
+
};
|
|
3083
|
+
}
|
|
3084
|
+
});
|
|
3085
|
+
|
|
2849
3086
|
// src/renderers/docxjs/emit.ts
|
|
2850
3087
|
import {
|
|
2851
3088
|
AlignmentType,
|
|
@@ -2881,7 +3118,7 @@ import {
|
|
|
2881
3118
|
WidthType,
|
|
2882
3119
|
WpsShapeRun
|
|
2883
3120
|
} from "docx";
|
|
2884
|
-
import { assertNever } from "@json-to-office/shared/rendering";
|
|
3121
|
+
import { assertNever as assertNever2 } from "@json-to-office/shared/rendering";
|
|
2885
3122
|
function complexField(instruction, formatting, leading, cachedText) {
|
|
2886
3123
|
const options = runOptions(formatting);
|
|
2887
3124
|
const fieldChar = (type, extra = {}) => new TextRun({
|
|
@@ -2918,7 +3155,12 @@ function runOptions(formatting) {
|
|
|
2918
3155
|
if (formatting.bold !== void 0) options.bold = formatting.bold;
|
|
2919
3156
|
if (formatting.italic !== void 0) options.italics = formatting.italic;
|
|
2920
3157
|
if (formatting.underline !== void 0) {
|
|
2921
|
-
options.underline = formatting.underline ? {
|
|
3158
|
+
options.underline = formatting.underline ? {
|
|
3159
|
+
type: formatting.underline.type,
|
|
3160
|
+
// A native visual's text is the one place a run states its own
|
|
3161
|
+
// underline colour.
|
|
3162
|
+
...formatting.underline.color ? { color: formatting.underline.color.hex } : {}
|
|
3163
|
+
} : void 0;
|
|
2922
3164
|
}
|
|
2923
3165
|
if (formatting.strike !== void 0) options.strike = formatting.strike;
|
|
2924
3166
|
if (formatting.allCaps !== void 0) options.allCaps = formatting.allCaps;
|
|
@@ -3044,21 +3286,36 @@ function inlineChildren(children, resources = /* @__PURE__ */ new Map()) {
|
|
|
3044
3286
|
case "shape":
|
|
3045
3287
|
out.push(emitShape(child, resources));
|
|
3046
3288
|
break;
|
|
3047
|
-
case "drawingGroup":
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3289
|
+
case "drawingGroup": {
|
|
3290
|
+
const build = resources.drawingGroup;
|
|
3291
|
+
if (!build) {
|
|
3292
|
+
throw new Error(
|
|
3293
|
+
"the docxjs renderer was handed a drawing group without loading docx/shapes; render() loads it whenever the IR holds one"
|
|
3294
|
+
);
|
|
3295
|
+
}
|
|
3296
|
+
const pending = breakOption();
|
|
3297
|
+
if (pending.break) out.push(new TextRun(pending));
|
|
3298
|
+
out.push(build(child, resources));
|
|
3299
|
+
break;
|
|
3300
|
+
}
|
|
3301
|
+
case "chart": {
|
|
3302
|
+
const pending = breakOption();
|
|
3303
|
+
if (pending.break) out.push(new TextRun(pending));
|
|
3304
|
+
out.push(
|
|
3305
|
+
emitChart(
|
|
3306
|
+
child,
|
|
3307
|
+
child.floating ? floatingOptions(child.floating) : void 0
|
|
3308
|
+
)
|
|
3054
3309
|
);
|
|
3310
|
+
break;
|
|
3311
|
+
}
|
|
3055
3312
|
case "noteReference":
|
|
3056
3313
|
out.push(
|
|
3057
3314
|
child.noteKind === "endnote" ? new EndnoteReferenceRun(child.id) : new FootnoteReferenceRun(child.id)
|
|
3058
3315
|
);
|
|
3059
3316
|
break;
|
|
3060
3317
|
default:
|
|
3061
|
-
|
|
3318
|
+
assertNever2(child, "DocxIrInline");
|
|
3062
3319
|
}
|
|
3063
3320
|
}
|
|
3064
3321
|
return out;
|
|
@@ -3263,7 +3520,7 @@ function emitBlock(block2, resources = /* @__PURE__ */ new Map()) {
|
|
|
3263
3520
|
case "toc":
|
|
3264
3521
|
return emitToc(block2);
|
|
3265
3522
|
default:
|
|
3266
|
-
return
|
|
3523
|
+
return assertNever2(block2, "DocxIrBlock");
|
|
3267
3524
|
}
|
|
3268
3525
|
}
|
|
3269
3526
|
function emitToc(block2) {
|
|
@@ -3407,6 +3664,7 @@ var ALIGNMENT2, PAGE_FIELDS, isSequenceField, WRAP_TYPE, ThemedTableOfContents,
|
|
|
3407
3664
|
var init_emit = __esm({
|
|
3408
3665
|
"src/renderers/docxjs/emit.ts"() {
|
|
3409
3666
|
"use strict";
|
|
3667
|
+
init_charts();
|
|
3410
3668
|
ALIGNMENT2 = {
|
|
3411
3669
|
left: AlignmentType.LEFT,
|
|
3412
3670
|
center: AlignmentType.CENTER,
|
|
@@ -3705,10 +3963,13 @@ function canonicalizeRelationshipIds(zip) {
|
|
|
3705
3963
|
const rename = new Map(
|
|
3706
3964
|
ordered.map((id, index) => [id, `rId${highest + 1 + index}`])
|
|
3707
3965
|
);
|
|
3708
|
-
const rewrite = (xml) => xml.replace(
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
|
|
3966
|
+
const rewrite = (xml) => xml.replace(
|
|
3967
|
+
/(\s[\w:.-]+=)"([^"]*)"/g,
|
|
3968
|
+
(whole, prefix, value) => {
|
|
3969
|
+
const replacement = rename.get(value);
|
|
3970
|
+
return replacement === void 0 ? whole : `${prefix}"${replacement}"`;
|
|
3971
|
+
}
|
|
3972
|
+
);
|
|
3712
3973
|
updates.push({ name: relsName, xml: rewrite(relsXml) });
|
|
3713
3974
|
if (partEntry) {
|
|
3714
3975
|
updates.push({ name: partName, xml: rewrite(partXml) });
|
|
@@ -3719,17 +3980,62 @@ function canonicalizeRelationshipIds(zip) {
|
|
|
3719
3980
|
if (entry) zip.updateFile(entry, Buffer.from(update.xml, "utf8"));
|
|
3720
3981
|
}
|
|
3721
3982
|
}
|
|
3983
|
+
function canonicalizeEmbeddedPackages(zip, generatedAt, depth = 1) {
|
|
3984
|
+
const names = zip.getEntries().map((entry) => entry.entryName).filter((name) => EMBEDDED_OFFICE_PACKAGE.test(name));
|
|
3985
|
+
let changed = false;
|
|
3986
|
+
for (const name of names) {
|
|
3987
|
+
const entry = zip.getEntry(name);
|
|
3988
|
+
if (!entry) continue;
|
|
3989
|
+
let nested;
|
|
3990
|
+
try {
|
|
3991
|
+
nested = new AdmZip(entry.getData());
|
|
3992
|
+
nested.getEntries();
|
|
3993
|
+
} catch {
|
|
3994
|
+
continue;
|
|
3995
|
+
}
|
|
3996
|
+
if (canonicalizeNestedPackage(nested, generatedAt, depth)) {
|
|
3997
|
+
zip.updateFile(entry, nested.toBuffer());
|
|
3998
|
+
changed = true;
|
|
3999
|
+
}
|
|
4000
|
+
}
|
|
4001
|
+
return changed;
|
|
4002
|
+
}
|
|
4003
|
+
function canonicalizeNestedPackage(zip, generatedAt, depth) {
|
|
4004
|
+
let changed = false;
|
|
4005
|
+
const coreProperties3 = zip.getEntry("docProps/core.xml");
|
|
4006
|
+
if (coreProperties3) {
|
|
4007
|
+
const xml = coreProperties3.getData().toString("utf8");
|
|
4008
|
+
const normalized = xml.replace(
|
|
4009
|
+
CORE_TIMESTAMP,
|
|
4010
|
+
`$1${generatedAt.toISOString()}$2`
|
|
4011
|
+
);
|
|
4012
|
+
if (normalized !== xml) {
|
|
4013
|
+
zip.updateFile(coreProperties3, Buffer.from(normalized, "utf8"));
|
|
4014
|
+
changed = true;
|
|
4015
|
+
}
|
|
4016
|
+
}
|
|
4017
|
+
if (depth < MAX_EMBEDDED_DEPTH && canonicalizeEmbeddedPackages(zip, generatedAt, depth + 1)) {
|
|
4018
|
+
changed = true;
|
|
4019
|
+
}
|
|
4020
|
+
const zipTimestamp = toDosTime(generatedAt);
|
|
4021
|
+
for (const entry of zip.getEntries()) {
|
|
4022
|
+
const header = entry.header;
|
|
4023
|
+
if (header.timeval !== zipTimestamp) {
|
|
4024
|
+
header.timeval = zipTimestamp;
|
|
4025
|
+
changed = true;
|
|
4026
|
+
}
|
|
4027
|
+
}
|
|
4028
|
+
return changed;
|
|
4029
|
+
}
|
|
3722
4030
|
function canonicalizeDocxBuffer(buffer, generatedAt = DEFAULT_GENERATION_DATE) {
|
|
3723
4031
|
const zip = new AdmZip(buffer);
|
|
3724
4032
|
normalizeTextCase(zip);
|
|
3725
4033
|
canonicalizeRelationshipIds(zip);
|
|
4034
|
+
canonicalizeEmbeddedPackages(zip, generatedAt);
|
|
3726
4035
|
const isoTimestamp = generatedAt.toISOString();
|
|
3727
4036
|
const coreProperties3 = zip.getEntry("docProps/core.xml");
|
|
3728
4037
|
if (coreProperties3) {
|
|
3729
|
-
const normalized = coreProperties3.getData().toString("utf8").replace(
|
|
3730
|
-
/(<dcterms:(?:created|modified)\b[^>]*>)[^<]*(<\/dcterms:(?:created|modified)>)/g,
|
|
3731
|
-
`$1${isoTimestamp}$2`
|
|
3732
|
-
);
|
|
4038
|
+
const normalized = coreProperties3.getData().toString("utf8").replace(CORE_TIMESTAMP, `$1${isoTimestamp}$2`);
|
|
3733
4039
|
zip.updateFile(coreProperties3, Buffer.from(normalized, "utf8"));
|
|
3734
4040
|
}
|
|
3735
4041
|
const zipTimestamp = toDosTime(generatedAt);
|
|
@@ -3742,35 +4048,567 @@ function normalizeDocxCaseBuffer(buffer) {
|
|
|
3742
4048
|
const zip = new AdmZip(buffer);
|
|
3743
4049
|
return normalizeTextCase(zip) ? zip.toBuffer() : buffer;
|
|
3744
4050
|
}
|
|
3745
|
-
var DEFAULT_GENERATION_DATE, STABLE_RELATIONSHIP_ID;
|
|
4051
|
+
var DEFAULT_GENERATION_DATE, STABLE_RELATIONSHIP_ID, CORE_TIMESTAMP, EMBEDDED_OFFICE_PACKAGE, MAX_EMBEDDED_DEPTH;
|
|
3746
4052
|
var init_packageDocument = __esm({
|
|
3747
4053
|
"src/utils/packageDocument.ts"() {
|
|
3748
4054
|
"use strict";
|
|
3749
4055
|
init_normalizeTextCase();
|
|
3750
4056
|
DEFAULT_GENERATION_DATE = /* @__PURE__ */ new Date("2000-01-01T00:00:00.000Z");
|
|
3751
4057
|
STABLE_RELATIONSHIP_ID = /^rId\d+$/;
|
|
4058
|
+
CORE_TIMESTAMP = /(<dcterms:(?:created|modified)\b[^>]*>)[^<]*(<\/dcterms:(?:created|modified)>)/g;
|
|
4059
|
+
EMBEDDED_OFFICE_PACKAGE = /\.(?:docx|pptx|xlsx|xlsm)$/i;
|
|
4060
|
+
MAX_EMBEDDED_DEPTH = 3;
|
|
3752
4061
|
}
|
|
3753
4062
|
});
|
|
3754
4063
|
|
|
3755
4064
|
// src/utils/fixFloatingImageIds.ts
|
|
3756
4065
|
import AdmZip2 from "adm-zip";
|
|
4066
|
+
function compareDrawingParts(a, b) {
|
|
4067
|
+
const ma = DRAWING_PART.exec(a);
|
|
4068
|
+
const mb = DRAWING_PART.exec(b);
|
|
4069
|
+
const rank = RANK.indexOf(ma[1]) - RANK.indexOf(mb[1]);
|
|
4070
|
+
return rank !== 0 ? rank : Number(ma[2] || 0) - Number(mb[2] || 0);
|
|
4071
|
+
}
|
|
3757
4072
|
function fixFloatingImageIdsInBuffer(buffer) {
|
|
3758
4073
|
const zip = new AdmZip2(buffer);
|
|
3759
|
-
|
|
3760
|
-
if (!documentEntry) {
|
|
4074
|
+
if (!zip.getEntry("word/document.xml")) {
|
|
3761
4075
|
throw new Error("document.xml not found in DOCX");
|
|
3762
4076
|
}
|
|
4077
|
+
const parts = zip.getEntries().filter((entry) => DRAWING_PART.test(entry.entryName)).sort((a, b) => compareDrawingParts(a.entryName, b.entryName));
|
|
3763
4078
|
let idCounter = 1;
|
|
3764
|
-
const
|
|
3765
|
-
const
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
|
|
4079
|
+
for (const entry of parts) {
|
|
4080
|
+
const xml = entry.getData().toString("utf8");
|
|
4081
|
+
const renumbered = xml.replace(
|
|
4082
|
+
/(<wp:docPr\b[^>]*?\s)id="\d+"/g,
|
|
4083
|
+
(_match, prefix) => `${prefix}id="${idCounter++}"`
|
|
4084
|
+
);
|
|
4085
|
+
zip.updateFile(entry, Buffer.from(renumbered, "utf8"));
|
|
4086
|
+
}
|
|
3769
4087
|
return zip.toBuffer();
|
|
3770
4088
|
}
|
|
4089
|
+
var DRAWING_PART, RANK;
|
|
3771
4090
|
var init_fixFloatingImageIds = __esm({
|
|
3772
4091
|
"src/utils/fixFloatingImageIds.ts"() {
|
|
3773
4092
|
"use strict";
|
|
4093
|
+
DRAWING_PART = /^word\/(document|header|footer|footnotes|endnotes|comments)(\d*)\.xml$/;
|
|
4094
|
+
RANK = [
|
|
4095
|
+
"document",
|
|
4096
|
+
"header",
|
|
4097
|
+
"footer",
|
|
4098
|
+
"footnotes",
|
|
4099
|
+
"endnotes",
|
|
4100
|
+
"comments"
|
|
4101
|
+
];
|
|
4102
|
+
}
|
|
4103
|
+
});
|
|
4104
|
+
|
|
4105
|
+
// src/renderers/docxjs/presetShapes.ts
|
|
4106
|
+
function docxPresetShape(geometry) {
|
|
4107
|
+
const name = Object.hasOwn(OOXML_PRESET_TO_DOCX, geometry) ? OOXML_PRESET_TO_DOCX[geometry] : void 0;
|
|
4108
|
+
if (!name) {
|
|
4109
|
+
throw new Error(
|
|
4110
|
+
`the docxjs renderer has no preset for the OOXML geometry "${geometry}"`
|
|
4111
|
+
);
|
|
4112
|
+
}
|
|
4113
|
+
return name;
|
|
4114
|
+
}
|
|
4115
|
+
function docxLineDash(dash) {
|
|
4116
|
+
const name = Object.hasOwn(OOXML_DASH_TO_DOCX, dash) ? OOXML_DASH_TO_DOCX[dash] : void 0;
|
|
4117
|
+
if (!name) {
|
|
4118
|
+
throw new Error(
|
|
4119
|
+
`the docxjs renderer has no line dash for the OOXML value "${dash}"`
|
|
4120
|
+
);
|
|
4121
|
+
}
|
|
4122
|
+
return name;
|
|
4123
|
+
}
|
|
4124
|
+
var OOXML_PRESET_TO_DOCX, OOXML_DASH_TO_DOCX;
|
|
4125
|
+
var init_presetShapes = __esm({
|
|
4126
|
+
"src/renderers/docxjs/presetShapes.ts"() {
|
|
4127
|
+
"use strict";
|
|
4128
|
+
OOXML_PRESET_TO_DOCX = {
|
|
4129
|
+
line: "line",
|
|
4130
|
+
lineInv: "inverseLine",
|
|
4131
|
+
straightConnector1: "straightConnector",
|
|
4132
|
+
bentConnector2: "elbowConnectorOneBend",
|
|
4133
|
+
bentConnector3: "elbowConnector",
|
|
4134
|
+
bentConnector4: "elbowConnectorThreeBends",
|
|
4135
|
+
bentConnector5: "elbowConnectorFourBends",
|
|
4136
|
+
curvedConnector2: "curvedConnectorOneBend",
|
|
4137
|
+
curvedConnector3: "curvedConnector",
|
|
4138
|
+
curvedConnector4: "curvedConnectorThreeBends",
|
|
4139
|
+
curvedConnector5: "curvedConnectorFourBends",
|
|
4140
|
+
triangle: "triangle",
|
|
4141
|
+
rtTriangle: "rightTriangle",
|
|
4142
|
+
diamond: "diamond",
|
|
4143
|
+
parallelogram: "parallelogram",
|
|
4144
|
+
trapezoid: "trapezoid",
|
|
4145
|
+
nonIsoscelesTrapezoid: "nonIsoscelesTrapezoid",
|
|
4146
|
+
pentagon: "pentagon",
|
|
4147
|
+
hexagon: "hexagon",
|
|
4148
|
+
heptagon: "heptagon",
|
|
4149
|
+
octagon: "octagon",
|
|
4150
|
+
decagon: "decagon",
|
|
4151
|
+
dodecagon: "dodecagon",
|
|
4152
|
+
ellipse: "ellipse",
|
|
4153
|
+
teardrop: "teardrop",
|
|
4154
|
+
pieWedge: "pieWedge",
|
|
4155
|
+
pie: "pie",
|
|
4156
|
+
blockArc: "blockArc",
|
|
4157
|
+
donut: "donut",
|
|
4158
|
+
noSmoking: "noSymbol",
|
|
4159
|
+
chord: "chord",
|
|
4160
|
+
arc: "arc",
|
|
4161
|
+
frame: "frame",
|
|
4162
|
+
halfFrame: "halfFrame",
|
|
4163
|
+
corner: "lShape",
|
|
4164
|
+
diagStripe: "diagonalStripe",
|
|
4165
|
+
plus: "cross",
|
|
4166
|
+
plaque: "plaque",
|
|
4167
|
+
can: "cylinder",
|
|
4168
|
+
cube: "cube",
|
|
4169
|
+
bevel: "beveledRectangle",
|
|
4170
|
+
foldedCorner: "foldedCorner",
|
|
4171
|
+
smileyFace: "smileyFace",
|
|
4172
|
+
heart: "heart",
|
|
4173
|
+
lightningBolt: "lightningBolt",
|
|
4174
|
+
sun: "sun",
|
|
4175
|
+
moon: "moon",
|
|
4176
|
+
cloud: "cloud",
|
|
4177
|
+
leftBracket: "leftBracket",
|
|
4178
|
+
rightBracket: "rightBracket",
|
|
4179
|
+
leftBrace: "leftBrace",
|
|
4180
|
+
rightBrace: "rightBrace",
|
|
4181
|
+
bracketPair: "bracketPair",
|
|
4182
|
+
bracePair: "bracePair",
|
|
4183
|
+
rect: "rectangle",
|
|
4184
|
+
roundRect: "roundedRectangle",
|
|
4185
|
+
round1Rect: "roundedCornerRectangle",
|
|
4186
|
+
round2SameRect: "topRoundedCornersRectangle",
|
|
4187
|
+
round2DiagRect: "diagonalRoundedCornersRectangle",
|
|
4188
|
+
snip1Rect: "snippedCornerRectangle",
|
|
4189
|
+
snip2SameRect: "topSnippedCornersRectangle",
|
|
4190
|
+
snip2DiagRect: "diagonalSnippedCornersRectangle",
|
|
4191
|
+
snipRoundRect: "roundedAndSnippedCornersRectangle",
|
|
4192
|
+
rightArrow: "rightArrow",
|
|
4193
|
+
leftArrow: "leftArrow",
|
|
4194
|
+
upArrow: "upArrow",
|
|
4195
|
+
downArrow: "downArrow",
|
|
4196
|
+
leftRightArrow: "leftRightArrow",
|
|
4197
|
+
upDownArrow: "upDownArrow",
|
|
4198
|
+
quadArrow: "quadArrow",
|
|
4199
|
+
leftRightUpArrow: "leftRightUpArrow",
|
|
4200
|
+
bentArrow: "bentArrow",
|
|
4201
|
+
uturnArrow: "uTurnArrow",
|
|
4202
|
+
leftUpArrow: "leftUpArrow",
|
|
4203
|
+
bentUpArrow: "bentUpArrow",
|
|
4204
|
+
curvedRightArrow: "curvedRightArrow",
|
|
4205
|
+
curvedLeftArrow: "curvedLeftArrow",
|
|
4206
|
+
curvedUpArrow: "curvedUpArrow",
|
|
4207
|
+
curvedDownArrow: "curvedDownArrow",
|
|
4208
|
+
stripedRightArrow: "stripedRightArrow",
|
|
4209
|
+
notchedRightArrow: "notchedRightArrow",
|
|
4210
|
+
homePlate: "pentagonArrow",
|
|
4211
|
+
chevron: "chevron",
|
|
4212
|
+
rightArrowCallout: "rightArrowCallout",
|
|
4213
|
+
downArrowCallout: "downArrowCallout",
|
|
4214
|
+
leftArrowCallout: "leftArrowCallout",
|
|
4215
|
+
upArrowCallout: "upArrowCallout",
|
|
4216
|
+
leftRightArrowCallout: "leftRightArrowCallout",
|
|
4217
|
+
upDownArrowCallout: "upDownArrowCallout",
|
|
4218
|
+
quadArrowCallout: "quadArrowCallout",
|
|
4219
|
+
circularArrow: "circularArrow",
|
|
4220
|
+
leftCircularArrow: "leftCircularArrow",
|
|
4221
|
+
leftRightCircularArrow: "leftRightCircularArrow",
|
|
4222
|
+
swooshArrow: "swooshArrow",
|
|
4223
|
+
mathPlus: "mathPlus",
|
|
4224
|
+
mathMinus: "mathMinus",
|
|
4225
|
+
mathMultiply: "mathMultiply",
|
|
4226
|
+
mathDivide: "mathDivide",
|
|
4227
|
+
mathEqual: "mathEqual",
|
|
4228
|
+
mathNotEqual: "mathNotEqual",
|
|
4229
|
+
flowChartProcess: "flowChartProcess",
|
|
4230
|
+
flowChartAlternateProcess: "flowChartAlternateProcess",
|
|
4231
|
+
flowChartDecision: "flowChartDecision",
|
|
4232
|
+
flowChartInputOutput: "flowChartInputOutput",
|
|
4233
|
+
flowChartPredefinedProcess: "flowChartPredefinedProcess",
|
|
4234
|
+
flowChartInternalStorage: "flowChartInternalStorage",
|
|
4235
|
+
flowChartDocument: "flowChartDocument",
|
|
4236
|
+
flowChartMultidocument: "flowChartMultidocument",
|
|
4237
|
+
flowChartTerminator: "flowChartTerminator",
|
|
4238
|
+
flowChartPreparation: "flowChartPreparation",
|
|
4239
|
+
flowChartManualInput: "flowChartManualInput",
|
|
4240
|
+
flowChartManualOperation: "flowChartManualOperation",
|
|
4241
|
+
flowChartConnector: "flowChartConnector",
|
|
4242
|
+
flowChartOffpageConnector: "flowChartOffpageConnector",
|
|
4243
|
+
flowChartPunchedCard: "flowChartPunchedCard",
|
|
4244
|
+
flowChartPunchedTape: "flowChartPunchedTape",
|
|
4245
|
+
flowChartSummingJunction: "flowChartSummingJunction",
|
|
4246
|
+
flowChartOr: "flowChartOr",
|
|
4247
|
+
flowChartCollate: "flowChartCollate",
|
|
4248
|
+
flowChartSort: "flowChartSort",
|
|
4249
|
+
flowChartExtract: "flowChartExtract",
|
|
4250
|
+
flowChartMerge: "flowChartMerge",
|
|
4251
|
+
flowChartOfflineStorage: "flowChartOfflineStorage",
|
|
4252
|
+
flowChartOnlineStorage: "flowChartOnlineStorage",
|
|
4253
|
+
flowChartDelay: "flowChartDelay",
|
|
4254
|
+
flowChartMagneticTape: "flowChartMagneticTape",
|
|
4255
|
+
flowChartMagneticDisk: "flowChartMagneticDisk",
|
|
4256
|
+
flowChartMagneticDrum: "flowChartMagneticDrum",
|
|
4257
|
+
flowChartDisplay: "flowChartDisplay",
|
|
4258
|
+
irregularSeal1: "explosion12",
|
|
4259
|
+
irregularSeal2: "explosion14",
|
|
4260
|
+
star4: "star4",
|
|
4261
|
+
star5: "star5",
|
|
4262
|
+
star6: "star6",
|
|
4263
|
+
star7: "star7",
|
|
4264
|
+
star8: "star8",
|
|
4265
|
+
star10: "star10",
|
|
4266
|
+
star12: "star12",
|
|
4267
|
+
star16: "star16",
|
|
4268
|
+
star24: "star24",
|
|
4269
|
+
star32: "star32",
|
|
4270
|
+
ribbon2: "ribbonUp",
|
|
4271
|
+
ribbon: "ribbonDown",
|
|
4272
|
+
ellipseRibbon2: "curvedRibbonUp",
|
|
4273
|
+
ellipseRibbon: "curvedRibbonDown",
|
|
4274
|
+
leftRightRibbon: "leftRightRibbon",
|
|
4275
|
+
verticalScroll: "verticalScroll",
|
|
4276
|
+
horizontalScroll: "horizontalScroll",
|
|
4277
|
+
wave: "wave",
|
|
4278
|
+
doubleWave: "doubleWave",
|
|
4279
|
+
wedgeRectCallout: "rectangularCallout",
|
|
4280
|
+
wedgeRoundRectCallout: "roundedRectangularCallout",
|
|
4281
|
+
wedgeEllipseCallout: "ellipticalCallout",
|
|
4282
|
+
cloudCallout: "cloudCallout",
|
|
4283
|
+
borderCallout1: "lineCallout",
|
|
4284
|
+
borderCallout2: "bentLineCallout",
|
|
4285
|
+
borderCallout3: "doubleBentLineCallout",
|
|
4286
|
+
accentCallout1: "lineCalloutWithAccentBar",
|
|
4287
|
+
accentCallout2: "bentLineCalloutWithAccentBar",
|
|
4288
|
+
accentCallout3: "doubleBentLineCalloutWithAccentBar",
|
|
4289
|
+
callout1: "lineCalloutWithNoBorder",
|
|
4290
|
+
callout2: "bentLineCalloutWithNoBorder",
|
|
4291
|
+
callout3: "doubleBentLineCalloutWithNoBorder",
|
|
4292
|
+
accentBorderCallout1: "lineCalloutWithBorderAndAccentBar",
|
|
4293
|
+
accentBorderCallout2: "bentLineCalloutWithBorderAndAccentBar",
|
|
4294
|
+
accentBorderCallout3: "doubleBentLineCalloutWithBorderAndAccentBar",
|
|
4295
|
+
actionButtonBlank: "actionButtonBlank",
|
|
4296
|
+
actionButtonHome: "actionButtonHome",
|
|
4297
|
+
actionButtonHelp: "actionButtonHelp",
|
|
4298
|
+
actionButtonInformation: "actionButtonInformation",
|
|
4299
|
+
actionButtonForwardNext: "actionButtonForwardNext",
|
|
4300
|
+
actionButtonBackPrevious: "actionButtonBackPrevious",
|
|
4301
|
+
actionButtonEnd: "actionButtonEnd",
|
|
4302
|
+
actionButtonBeginning: "actionButtonBeginning",
|
|
4303
|
+
actionButtonReturn: "actionButtonReturn",
|
|
4304
|
+
actionButtonDocument: "actionButtonDocument",
|
|
4305
|
+
actionButtonSound: "actionButtonSound",
|
|
4306
|
+
actionButtonMovie: "actionButtonMovie",
|
|
4307
|
+
gear6: "gear6",
|
|
4308
|
+
gear9: "gear9",
|
|
4309
|
+
funnel: "funnel",
|
|
4310
|
+
cornerTabs: "cornerTabs",
|
|
4311
|
+
squareTabs: "squareTabs",
|
|
4312
|
+
plaqueTabs: "plaqueTabs",
|
|
4313
|
+
chartX: "chartX",
|
|
4314
|
+
chartStar: "chartStar",
|
|
4315
|
+
chartPlus: "chartPlus"
|
|
4316
|
+
};
|
|
4317
|
+
OOXML_DASH_TO_DOCX = {
|
|
4318
|
+
solid: "solid",
|
|
4319
|
+
dot: "dot",
|
|
4320
|
+
dash: "dash",
|
|
4321
|
+
lgDash: "longDash",
|
|
4322
|
+
dashDot: "dashDot",
|
|
4323
|
+
lgDashDot: "longDashDot",
|
|
4324
|
+
lgDashDotDot: "longDashDotDot",
|
|
4325
|
+
sysDash: "shortDash",
|
|
4326
|
+
sysDot: "shortDot",
|
|
4327
|
+
sysDashDot: "shortDashDot",
|
|
4328
|
+
sysDashDotDot: "shortDashDotDot"
|
|
4329
|
+
};
|
|
4330
|
+
}
|
|
4331
|
+
});
|
|
4332
|
+
|
|
4333
|
+
// src/renderers/docxjs/drawingGroup.ts
|
|
4334
|
+
function chooseMarkers(ir) {
|
|
4335
|
+
const strings = [];
|
|
4336
|
+
collectStrings(ir, strings, /* @__PURE__ */ new WeakSet());
|
|
4337
|
+
const unused = (base) => {
|
|
4338
|
+
for (let n = 0; ; n += 1) {
|
|
4339
|
+
const candidate = n === 0 ? base : `${base}-${n}`;
|
|
4340
|
+
if (!strings.some((value) => value.includes(candidate))) return candidate;
|
|
4341
|
+
}
|
|
4342
|
+
};
|
|
4343
|
+
return {
|
|
4344
|
+
noAltText: unused(DEFAULT_MARKERS.noAltText),
|
|
4345
|
+
textBox: unused(DEFAULT_MARKERS.textBox)
|
|
4346
|
+
};
|
|
4347
|
+
}
|
|
4348
|
+
function collectStrings(node, out, seen) {
|
|
4349
|
+
if (typeof node === "string") {
|
|
4350
|
+
out.push(node);
|
|
4351
|
+
return;
|
|
4352
|
+
}
|
|
4353
|
+
if (!node || typeof node !== "object") return;
|
|
4354
|
+
if (node instanceof ArrayBuffer || ArrayBuffer.isView(node)) return;
|
|
4355
|
+
if (seen.has(node)) return;
|
|
4356
|
+
seen.add(node);
|
|
4357
|
+
if (node instanceof Map) {
|
|
4358
|
+
for (const [key, value] of node) {
|
|
4359
|
+
collectStrings(key, out, seen);
|
|
4360
|
+
collectStrings(value, out, seen);
|
|
4361
|
+
}
|
|
4362
|
+
return;
|
|
4363
|
+
}
|
|
4364
|
+
if (node instanceof Set) {
|
|
4365
|
+
for (const value of node) collectStrings(value, out, seen);
|
|
4366
|
+
return;
|
|
4367
|
+
}
|
|
4368
|
+
for (const value of Object.values(node)) collectStrings(value, out, seen);
|
|
4369
|
+
}
|
|
4370
|
+
function createDrawingGroupFactory(shapes2, pictures, markers) {
|
|
4371
|
+
return (group, resources) => new shapes2.ShapeGroupRun(
|
|
4372
|
+
drawingGroupOptions(group, resources, pictures, markers)
|
|
4373
|
+
);
|
|
4374
|
+
}
|
|
4375
|
+
function drawingGroupOptions(group, resources, pictures, markers = DEFAULT_MARKERS) {
|
|
4376
|
+
const canvasWidth = group.canvasWidthEmu;
|
|
4377
|
+
const canvasHeight = group.canvasHeightEmu;
|
|
4378
|
+
const near = (value, edge) => Math.abs(value - edge) <= OVERFLOW_TOLERANCE_EMU;
|
|
4379
|
+
const bounds = unrotatedBounds(group.children);
|
|
4380
|
+
const fillsCanvas = bounds !== void 0 && near(bounds.left, 0) && near(bounds.top, 0) && near(bounds.right, canvasWidth) && near(bounds.bottom, canvasHeight);
|
|
4381
|
+
const union = {
|
|
4382
|
+
left: Math.min(0, bounds?.left ?? 0),
|
|
4383
|
+
top: Math.min(0, bounds?.top ?? 0),
|
|
4384
|
+
right: Math.max(canvasWidth, bounds?.right ?? 0),
|
|
4385
|
+
bottom: Math.max(canvasHeight, bounds?.bottom ?? 0)
|
|
4386
|
+
};
|
|
4387
|
+
const overflows = union.left < -OVERFLOW_TOLERANCE_EMU || union.top < -OVERFLOW_TOLERANCE_EMU || union.right > canvasWidth + OVERFLOW_TOLERANCE_EMU || union.bottom > canvasHeight + OVERFLOW_TOLERANCE_EMU;
|
|
4388
|
+
const widthEmu = overflows ? (union.right - union.left) * group.widthEmu / canvasWidth : group.widthEmu;
|
|
4389
|
+
const heightEmu = overflows ? (union.bottom - union.top) * group.heightEmu / canvasHeight : group.heightEmu;
|
|
4390
|
+
return {
|
|
4391
|
+
children: [
|
|
4392
|
+
...fillsCanvas ? [] : [canvasPad(canvasWidth, canvasHeight)],
|
|
4393
|
+
...group.children.map(
|
|
4394
|
+
(child, index) => groupChild(child, index, resources, pictures, markers)
|
|
4395
|
+
)
|
|
4396
|
+
],
|
|
4397
|
+
transformation: {
|
|
4398
|
+
width: emuToPixels(widthEmu),
|
|
4399
|
+
height: emuToPixels(heightEmu)
|
|
4400
|
+
},
|
|
4401
|
+
// `||`, not `??`: docx treats '' as no description too, and would then
|
|
4402
|
+
// describe the diagram from the child names.
|
|
4403
|
+
altText: { name: "", description: group.altText || markers.noAltText },
|
|
4404
|
+
...group.floating ? { floating: floatingOptions(group.floating) } : {}
|
|
4405
|
+
};
|
|
4406
|
+
}
|
|
4407
|
+
function groupChild(child, index, resources, pictures, markers) {
|
|
4408
|
+
return child.kind === "picture" ? pictureChild(child, index, pictures) : shapeChild(child, index, resources, markers);
|
|
4409
|
+
}
|
|
4410
|
+
function canvasPad(canvasWidthEmu, canvasHeightEmu) {
|
|
4411
|
+
return {
|
|
4412
|
+
type: "rectangle",
|
|
4413
|
+
transformation: {
|
|
4414
|
+
offset: { left: 0, top: 0 },
|
|
4415
|
+
width: emuToPixels(canvasWidthEmu),
|
|
4416
|
+
height: emuToPixels(canvasHeightEmu)
|
|
4417
|
+
},
|
|
4418
|
+
fill: "none",
|
|
4419
|
+
line: "none",
|
|
4420
|
+
decorative: true,
|
|
4421
|
+
altText: { name: "Canvas" }
|
|
4422
|
+
};
|
|
4423
|
+
}
|
|
4424
|
+
function childTransformation(frame) {
|
|
4425
|
+
const rotation2 = frame.rotationDegrees;
|
|
4426
|
+
return {
|
|
4427
|
+
offset: { left: emuToPixels(frame.xEmu), top: emuToPixels(frame.yEmu) },
|
|
4428
|
+
width: emuToPixels(frame.widthEmu),
|
|
4429
|
+
height: emuToPixels(frame.heightEmu),
|
|
4430
|
+
...rotation2 !== void 0 && rotation2 % 360 !== 0 ? { rotation: rotation2 } : {},
|
|
4431
|
+
...frame.flipHorizontal || frame.flipVertical ? {
|
|
4432
|
+
flip: {
|
|
4433
|
+
...frame.flipHorizontal ? { horizontal: true } : {},
|
|
4434
|
+
...frame.flipVertical ? { vertical: true } : {}
|
|
4435
|
+
}
|
|
4436
|
+
} : {}
|
|
4437
|
+
};
|
|
4438
|
+
}
|
|
4439
|
+
function shapeChild(shape, index, resources, markers) {
|
|
4440
|
+
const paragraphs = shape.text?.paragraphs ?? [];
|
|
4441
|
+
return {
|
|
4442
|
+
type: docxPresetShape(shape.geometry),
|
|
4443
|
+
transformation: childTransformation(shape.frame),
|
|
4444
|
+
fill: shapeFill(shape.fill),
|
|
4445
|
+
line: shapeLine(shape.outline),
|
|
4446
|
+
altText: {
|
|
4447
|
+
name: shape.name ?? `Shape ${index + 1}`,
|
|
4448
|
+
...shape.isTextBox ? { title: markers.textBox } : {}
|
|
4449
|
+
},
|
|
4450
|
+
// Never `children: []`: docx would write an empty `w:txbxContent`, which
|
|
4451
|
+
// the schema does not allow.
|
|
4452
|
+
...paragraphs.length > 0 ? {
|
|
4453
|
+
children: paragraphs.map(
|
|
4454
|
+
(paragraph2) => emitParagraph(paragraph2, resources)
|
|
4455
|
+
)
|
|
4456
|
+
} : {},
|
|
4457
|
+
...shape.text ? { textOptions: textOptions(shape.text) } : {}
|
|
4458
|
+
};
|
|
4459
|
+
}
|
|
4460
|
+
function pictureChild(picture2, index, pictures) {
|
|
4461
|
+
const crop = picture2.crop;
|
|
4462
|
+
return {
|
|
4463
|
+
type: "picture",
|
|
4464
|
+
image: pictures(picture2.resourceId, {
|
|
4465
|
+
widthEmu: picture2.frame.widthEmu,
|
|
4466
|
+
heightEmu: picture2.frame.heightEmu
|
|
4467
|
+
}),
|
|
4468
|
+
transformation: childTransformation(picture2.frame),
|
|
4469
|
+
...crop ? {
|
|
4470
|
+
crop: {
|
|
4471
|
+
...crop.left !== void 0 ? { left: crop.left * 100 } : {},
|
|
4472
|
+
...crop.top !== void 0 ? { top: crop.top * 100 } : {},
|
|
4473
|
+
...crop.right !== void 0 ? { right: crop.right * 100 } : {},
|
|
4474
|
+
...crop.bottom !== void 0 ? { bottom: crop.bottom * 100 } : {}
|
|
4475
|
+
}
|
|
4476
|
+
} : {},
|
|
4477
|
+
altText: {
|
|
4478
|
+
name: picture2.name ?? `Picture ${index + 1}`,
|
|
4479
|
+
...picture2.altText ? { description: picture2.altText } : {}
|
|
4480
|
+
}
|
|
4481
|
+
};
|
|
4482
|
+
}
|
|
4483
|
+
function shapeFill(fill) {
|
|
4484
|
+
if (!fill || fill.kind === "none") return "none";
|
|
4485
|
+
return {
|
|
4486
|
+
type: "solid",
|
|
4487
|
+
color: fill.color.hex,
|
|
4488
|
+
...fill.transparencyPercent !== void 0 ? { transparency: clamp(fill.transparencyPercent, 0, 100) } : {}
|
|
4489
|
+
};
|
|
4490
|
+
}
|
|
4491
|
+
function shapeLine(outline) {
|
|
4492
|
+
if (!outline || !outline.color) return "none";
|
|
4493
|
+
return {
|
|
4494
|
+
color: outline.color.hex,
|
|
4495
|
+
// An omitted width is office-open's omitted `w`, a hairline, where docx's
|
|
4496
|
+
// own default would be 1pt.
|
|
4497
|
+
width: outline.widthEmu !== void 0 ? clamp(outline.widthEmu / EMU_PER_POINT, 0, MAX_POINTS) : 0,
|
|
4498
|
+
...outline.dash ? { dash: docxLineDash(outline.dash) } : {}
|
|
4499
|
+
};
|
|
4500
|
+
}
|
|
4501
|
+
function textOptions(text) {
|
|
4502
|
+
const insets = text.insetsEmu;
|
|
4503
|
+
const points = (emu) => clamp(emu / EMU_PER_POINT, 0, MAX_POINTS);
|
|
4504
|
+
const margins = insets ? {
|
|
4505
|
+
...insets.top !== void 0 ? { top: points(insets.top) } : {},
|
|
4506
|
+
...insets.right !== void 0 ? { right: points(insets.right) } : {},
|
|
4507
|
+
...insets.bottom !== void 0 ? { bottom: points(insets.bottom) } : {},
|
|
4508
|
+
...insets.left !== void 0 ? { left: points(insets.left) } : {}
|
|
4509
|
+
} : void 0;
|
|
4510
|
+
return {
|
|
4511
|
+
verticalAlignment: VERTICAL_ALIGNMENT[text.anchor ?? "top"],
|
|
4512
|
+
...margins && Object.keys(margins).length > 0 ? { margins } : {}
|
|
4513
|
+
};
|
|
4514
|
+
}
|
|
4515
|
+
function unrotatedBounds(children) {
|
|
4516
|
+
if (children.length === 0) return void 0;
|
|
4517
|
+
let left = Infinity;
|
|
4518
|
+
let top = Infinity;
|
|
4519
|
+
let right = -Infinity;
|
|
4520
|
+
let bottom = -Infinity;
|
|
4521
|
+
for (const { frame } of children) {
|
|
4522
|
+
left = Math.min(left, frame.xEmu);
|
|
4523
|
+
top = Math.min(top, frame.yEmu);
|
|
4524
|
+
right = Math.max(right, frame.xEmu + frame.widthEmu);
|
|
4525
|
+
bottom = Math.max(bottom, frame.yEmu + frame.heightEmu);
|
|
4526
|
+
}
|
|
4527
|
+
return { left, top, right, bottom };
|
|
4528
|
+
}
|
|
4529
|
+
function clamp(value, low, high) {
|
|
4530
|
+
return Math.min(high, Math.max(low, value));
|
|
4531
|
+
}
|
|
4532
|
+
var DEFAULT_MARKERS, EMU_PER_POINT, MAX_POINTS, OVERFLOW_TOLERANCE_EMU, VERTICAL_ALIGNMENT;
|
|
4533
|
+
var init_drawingGroup = __esm({
|
|
4534
|
+
"src/renderers/docxjs/drawingGroup.ts"() {
|
|
4535
|
+
"use strict";
|
|
4536
|
+
init_units();
|
|
4537
|
+
init_emit();
|
|
4538
|
+
init_presetShapes();
|
|
4539
|
+
DEFAULT_MARKERS = {
|
|
4540
|
+
noAltText: "jto:no-alt-text",
|
|
4541
|
+
textBox: "jto:text-box"
|
|
4542
|
+
};
|
|
4543
|
+
EMU_PER_POINT = 12700;
|
|
4544
|
+
MAX_POINTS = 1584;
|
|
4545
|
+
OVERFLOW_TOLERANCE_EMU = 2;
|
|
4546
|
+
VERTICAL_ALIGNMENT = {
|
|
4547
|
+
top: "top",
|
|
4548
|
+
middle: "center",
|
|
4549
|
+
bottom: "bottom"
|
|
4550
|
+
};
|
|
4551
|
+
}
|
|
4552
|
+
});
|
|
4553
|
+
|
|
4554
|
+
// src/renderers/docxjs/drawingGroupRepair.ts
|
|
4555
|
+
import AdmZip3 from "adm-zip";
|
|
4556
|
+
function repairDrawingGroupsInBuffer(buffer, markers) {
|
|
4557
|
+
const textBox = new RegExp(
|
|
4558
|
+
`(<wps:cNvPr\\b[^>]*?) title="${escapeRegExp2(markers.textBox)}"(\\s*/>)<wps:cNvSpPr/>`,
|
|
4559
|
+
"g"
|
|
4560
|
+
);
|
|
4561
|
+
const noAltText = new RegExp(
|
|
4562
|
+
`(<wp:docPr\\b[^>]*?) descr="${escapeRegExp2(markers.noAltText)}"`,
|
|
4563
|
+
"g"
|
|
4564
|
+
);
|
|
4565
|
+
const zip = new AdmZip3(buffer);
|
|
4566
|
+
const parts = zip.getEntries().filter((entry) => DRAWING_PART.test(entry.entryName)).sort((a, b) => compareDrawingParts(a.entryName, b.entryName));
|
|
4567
|
+
const texts = new Map(
|
|
4568
|
+
parts.map((entry) => [entry, entry.getData().toString("utf8")])
|
|
4569
|
+
);
|
|
4570
|
+
let highest = 0;
|
|
4571
|
+
for (const xml of texts.values()) {
|
|
4572
|
+
for (const match of xml.matchAll(DOC_PR_ID)) {
|
|
4573
|
+
highest = Math.max(highest, Number(match[1]));
|
|
4574
|
+
}
|
|
4575
|
+
for (const match of xml.replace(GROUP, "").matchAll(CNVPR_ID)) {
|
|
4576
|
+
highest = Math.max(highest, Number(match[1]));
|
|
4577
|
+
}
|
|
4578
|
+
}
|
|
4579
|
+
let next = highest + 1;
|
|
4580
|
+
for (const [entry, xml] of texts) {
|
|
4581
|
+
if (!xml.includes("<wpg:wgp")) continue;
|
|
4582
|
+
const repaired = xml.replace(
|
|
4583
|
+
GROUP,
|
|
4584
|
+
(span) => span.replace(CHILD_ID, (_match, head) => `${head}id="${next++}"`).replace(
|
|
4585
|
+
ROTATION,
|
|
4586
|
+
(_match, head, value) => `${head}rot="${Math.round(Number(value))}"`
|
|
4587
|
+
).replace(textBox, '$1$2<wps:cNvSpPr txBox="1"/>')
|
|
4588
|
+
).replace(noAltText, "$1");
|
|
4589
|
+
texts.set(entry, repaired);
|
|
4590
|
+
zip.updateFile(entry, Buffer.from(repaired, "utf8"));
|
|
4591
|
+
}
|
|
4592
|
+
for (const [entry, xml] of texts) {
|
|
4593
|
+
if (xml.includes(markers.noAltText) || xml.includes(markers.textBox)) {
|
|
4594
|
+
throw new Error(
|
|
4595
|
+
`the drawing-group repair left a marker in ${entry.entryName}`
|
|
4596
|
+
);
|
|
4597
|
+
}
|
|
4598
|
+
}
|
|
4599
|
+
return zip.toBuffer();
|
|
4600
|
+
}
|
|
4601
|
+
var GROUP, DOC_PR_ID, CNVPR_ID, CHILD_ID, ROTATION, escapeRegExp2;
|
|
4602
|
+
var init_drawingGroupRepair = __esm({
|
|
4603
|
+
"src/renderers/docxjs/drawingGroupRepair.ts"() {
|
|
4604
|
+
"use strict";
|
|
4605
|
+
init_fixFloatingImageIds();
|
|
4606
|
+
GROUP = /<wpg:wgp\b[^>]*>[\s\S]*?<\/wpg:wgp>/g;
|
|
4607
|
+
DOC_PR_ID = /<wp:docPr\b[^>]*?\sid="(\d+)"/g;
|
|
4608
|
+
CNVPR_ID = /<(?:wps|pic|wpg):cNvPr\b[^>]*?\sid="(\d+)"/g;
|
|
4609
|
+
CHILD_ID = /(<(?:wps|pic|wpg):cNvPr\b[^>]*?\s)id="\d+"/g;
|
|
4610
|
+
ROTATION = /(<a:xfrm\b[^>]*?\s)rot="([^"]*)"/g;
|
|
4611
|
+
escapeRegExp2 = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3774
4612
|
}
|
|
3775
4613
|
});
|
|
3776
4614
|
|
|
@@ -3799,18 +4637,32 @@ function createDocxJsRenderer() {
|
|
|
3799
4637
|
format: "docx",
|
|
3800
4638
|
capabilities: DOCXJS_CAPABILITIES,
|
|
3801
4639
|
async render(ir, renderOptions) {
|
|
3802
|
-
|
|
4640
|
+
await loadDocxCharts();
|
|
4641
|
+
const prepared = await prepareImages(
|
|
3803
4642
|
ir,
|
|
3804
4643
|
renderOptions?.svgRasterFallback
|
|
3805
4644
|
);
|
|
4645
|
+
const markers = prepared.drawingGroups > 0 ? chooseMarkers(ir) : void 0;
|
|
4646
|
+
let resources = prepared.images;
|
|
4647
|
+
if (markers) {
|
|
4648
|
+
await shapes.load();
|
|
4649
|
+
resources = Object.assign(prepared.images, {
|
|
4650
|
+
drawingGroup: createDrawingGroupFactory(
|
|
4651
|
+
shapes.get(),
|
|
4652
|
+
prepared.pictureSource,
|
|
4653
|
+
markers
|
|
4654
|
+
)
|
|
4655
|
+
});
|
|
4656
|
+
}
|
|
3806
4657
|
const document = buildDocument(ir, resources);
|
|
3807
4658
|
const packed = await Packer.toBuffer(document);
|
|
3808
4659
|
const fixed = fixFloatingImageIdsInBuffer(packed);
|
|
4660
|
+
const repaired = markers ? repairDrawingGroupsInBuffer(fixed, markers) : fixed;
|
|
3809
4661
|
if (renderOptions?.deterministic === false)
|
|
3810
|
-
return new Uint8Array(normalizeDocxCaseBuffer(
|
|
4662
|
+
return new Uint8Array(normalizeDocxCaseBuffer(repaired));
|
|
3811
4663
|
return new Uint8Array(
|
|
3812
4664
|
canonicalizeDocxBuffer(
|
|
3813
|
-
|
|
4665
|
+
repaired,
|
|
3814
4666
|
resolveGenerationDate({
|
|
3815
4667
|
deterministic: renderOptions?.deterministic,
|
|
3816
4668
|
generatedAt: renderOptions?.generatedAt
|
|
@@ -3823,6 +4675,7 @@ function createDocxJsRenderer() {
|
|
|
3823
4675
|
function buildDocument(ir, resources = /* @__PURE__ */ new Map()) {
|
|
3824
4676
|
return new Document({
|
|
3825
4677
|
styles: emitStyles(ir.styles),
|
|
4678
|
+
...ir.theme ? { theme: themeOptions(ir.theme) } : {},
|
|
3826
4679
|
sections: ir.sections.map(
|
|
3827
4680
|
(section2, index) => sectionOptions(section2, resources, index === ir.sections.length - 1)
|
|
3828
4681
|
),
|
|
@@ -3854,6 +4707,21 @@ function buildDocument(ir, resources = /* @__PURE__ */ new Map()) {
|
|
|
3854
4707
|
} : {}
|
|
3855
4708
|
});
|
|
3856
4709
|
}
|
|
4710
|
+
function themeOptions(theme) {
|
|
4711
|
+
const colors = {};
|
|
4712
|
+
for (const [slot, color] of Object.entries(theme.colors)) {
|
|
4713
|
+
if (color) colors[slot] = color.hex;
|
|
4714
|
+
}
|
|
4715
|
+
const fonts = {
|
|
4716
|
+
...theme.headingFont ? { headings: theme.headingFont } : {},
|
|
4717
|
+
...theme.bodyFont ? { body: theme.bodyFont } : {}
|
|
4718
|
+
};
|
|
4719
|
+
return {
|
|
4720
|
+
name: theme.name,
|
|
4721
|
+
...Object.keys(colors).length > 0 ? { colors } : {},
|
|
4722
|
+
...Object.keys(fonts).length > 0 ? { fonts } : {}
|
|
4723
|
+
};
|
|
4724
|
+
}
|
|
3857
4725
|
function noteBodies(notes, resources) {
|
|
3858
4726
|
const bodies = {};
|
|
3859
4727
|
for (const note of notes) {
|
|
@@ -3891,7 +4759,7 @@ function numberingConfig(numbering) {
|
|
|
3891
4759
|
};
|
|
3892
4760
|
}
|
|
3893
4761
|
async function prepareImages(ir, svgRasterFallback) {
|
|
3894
|
-
const placements = collectImagePlacements(ir);
|
|
4762
|
+
const { placements, drawingGroups } = collectImagePlacements(ir);
|
|
3895
4763
|
const jobs = [];
|
|
3896
4764
|
for (const resource of ir.resources) {
|
|
3897
4765
|
if (resource.kind !== "image" || resource.mediaType !== "svg") continue;
|
|
@@ -3939,16 +4807,55 @@ async function prepareImages(ir, svgRasterFallback) {
|
|
|
3939
4807
|
});
|
|
3940
4808
|
});
|
|
3941
4809
|
}
|
|
3942
|
-
|
|
4810
|
+
const pictureSource = (resourceId, placement) => {
|
|
4811
|
+
const resource = ir.resources.find(
|
|
4812
|
+
(candidate) => candidate.kind === "image" && candidate.id === resourceId
|
|
4813
|
+
);
|
|
4814
|
+
if (!resource) {
|
|
4815
|
+
throw new Error(`no image was prepared for resource "${resourceId}"`);
|
|
4816
|
+
}
|
|
4817
|
+
const data = Buffer.from(resource.bytes);
|
|
4818
|
+
if (resource.mediaType !== "svg") {
|
|
4819
|
+
return {
|
|
4820
|
+
type: resource.mediaType,
|
|
4821
|
+
data
|
|
4822
|
+
};
|
|
4823
|
+
}
|
|
4824
|
+
const size = `${emuToPixels(placement.widthEmu)}x${emuToPixels(placement.heightEmu)}`;
|
|
4825
|
+
return {
|
|
4826
|
+
type: "svg",
|
|
4827
|
+
data,
|
|
4828
|
+
fallback: {
|
|
4829
|
+
type: "png",
|
|
4830
|
+
data: rasters.get(`${resourceId}:${size}`) ?? data
|
|
4831
|
+
}
|
|
4832
|
+
};
|
|
4833
|
+
};
|
|
4834
|
+
return { images: resources, pictureSource, drawingGroups };
|
|
3943
4835
|
}
|
|
3944
4836
|
function collectImagePlacements(ir) {
|
|
3945
4837
|
const placements = /* @__PURE__ */ new Map();
|
|
4838
|
+
let drawingGroups = 0;
|
|
4839
|
+
const record = (resourceId, widthEmu, heightEmu) => {
|
|
4840
|
+
const key = `${emuToPixels(widthEmu)}x${emuToPixels(heightEmu)}`;
|
|
4841
|
+
const sizes = placements.get(resourceId) ?? /* @__PURE__ */ new Set();
|
|
4842
|
+
sizes.add(key);
|
|
4843
|
+
placements.set(resourceId, sizes);
|
|
4844
|
+
};
|
|
3946
4845
|
const visitInline = (inline) => {
|
|
3947
4846
|
if (inline.kind === "image") {
|
|
3948
|
-
|
|
3949
|
-
|
|
3950
|
-
|
|
3951
|
-
|
|
4847
|
+
record(inline.resourceId, inline.widthEmu, inline.heightEmu);
|
|
4848
|
+
return;
|
|
4849
|
+
}
|
|
4850
|
+
if (inline.kind === "drawingGroup") {
|
|
4851
|
+
drawingGroups += 1;
|
|
4852
|
+
for (const child of inline.children) {
|
|
4853
|
+
if (child.kind === "picture") {
|
|
4854
|
+
record(child.resourceId, child.frame.widthEmu, child.frame.heightEmu);
|
|
4855
|
+
} else {
|
|
4856
|
+
child.text?.paragraphs.forEach(visitBlock);
|
|
4857
|
+
}
|
|
4858
|
+
}
|
|
3952
4859
|
return;
|
|
3953
4860
|
}
|
|
3954
4861
|
if (inline.kind === "hyperlink" || inline.kind === "revision") {
|
|
@@ -3979,7 +4886,7 @@ function collectImagePlacements(ir) {
|
|
|
3979
4886
|
for (const note of [...ir.footnotes, ...ir.endnotes]) {
|
|
3980
4887
|
note.children.forEach(visitBlock);
|
|
3981
4888
|
}
|
|
3982
|
-
return placements;
|
|
4889
|
+
return { placements, drawingGroups };
|
|
3983
4890
|
}
|
|
3984
4891
|
function sectionOptions(section2, resources, closesDocument = false) {
|
|
3985
4892
|
const { page, columns } = section2.properties;
|
|
@@ -4092,17 +4999,26 @@ function coreProperties(ir) {
|
|
|
4092
4999
|
...metadata.custom?.length ? { customProperties: metadata.custom } : {}
|
|
4093
5000
|
};
|
|
4094
5001
|
}
|
|
4095
|
-
var DOCXJS_RENDERER_ID, DOCXJS_CAPABILITIES;
|
|
5002
|
+
var DOCXJS_RENDERER_ID, shapes, DOCXJS_CAPABILITIES;
|
|
4096
5003
|
var init_docxjs = __esm({
|
|
4097
5004
|
"src/renderers/docxjs/index.ts"() {
|
|
4098
5005
|
"use strict";
|
|
4099
5006
|
init_styles2();
|
|
5007
|
+
init_charts();
|
|
4100
5008
|
init_imageUtils();
|
|
4101
5009
|
init_packageDocument();
|
|
4102
5010
|
init_fixFloatingImageIds();
|
|
4103
5011
|
init_emit();
|
|
5012
|
+
init_docxSubpath();
|
|
5013
|
+
init_drawingGroup();
|
|
5014
|
+
init_drawingGroupRepair();
|
|
4104
5015
|
init_units();
|
|
4105
5016
|
DOCXJS_RENDERER_ID = "docxjs";
|
|
5017
|
+
shapes = docxSubpath(
|
|
5018
|
+
"docx/shapes",
|
|
5019
|
+
"visual",
|
|
5020
|
+
() => import("docx/shapes")
|
|
5021
|
+
);
|
|
4106
5022
|
DOCXJS_CAPABILITIES = /* @__PURE__ */ new Set([
|
|
4107
5023
|
"paragraphs",
|
|
4108
5024
|
"styles",
|
|
@@ -4115,8 +5031,10 @@ var init_docxjs = __esm({
|
|
|
4115
5031
|
"images",
|
|
4116
5032
|
"floating-images",
|
|
4117
5033
|
"svg-images",
|
|
5034
|
+
"charts",
|
|
4118
5035
|
"text-frames",
|
|
4119
5036
|
"text-boxes",
|
|
5037
|
+
"drawing-groups",
|
|
4120
5038
|
"toc",
|
|
4121
5039
|
"cached-toc",
|
|
4122
5040
|
"fields",
|
|
@@ -4137,183 +5055,331 @@ var init_docxjs = __esm({
|
|
|
4137
5055
|
}
|
|
4138
5056
|
});
|
|
4139
5057
|
|
|
4140
|
-
// src/
|
|
4141
|
-
|
|
4142
|
-
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
|
|
4146
|
-
|
|
4147
|
-
|
|
4148
|
-
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
zip.addFile(name, Buffer.from(content, "utf8"));
|
|
5058
|
+
// src/renderers/office-open/chartLook.ts
|
|
5059
|
+
function seriesLook(chartType) {
|
|
5060
|
+
switch (chartType) {
|
|
5061
|
+
case "line":
|
|
5062
|
+
case "scatter":
|
|
5063
|
+
return { marker: MARKER, smooth: false };
|
|
5064
|
+
case "radar":
|
|
5065
|
+
return { marker: MARKER };
|
|
5066
|
+
case "column":
|
|
5067
|
+
case "bar":
|
|
5068
|
+
return { invertIfNegative: false };
|
|
5069
|
+
default:
|
|
5070
|
+
return {};
|
|
4154
5071
|
}
|
|
4155
|
-
|
|
4156
|
-
|
|
5072
|
+
}
|
|
5073
|
+
function axesLook(chartType) {
|
|
5074
|
+
switch (chartType) {
|
|
5075
|
+
case "column":
|
|
5076
|
+
case "bar":
|
|
5077
|
+
case "line":
|
|
5078
|
+
case "area": {
|
|
5079
|
+
const horizontal = chartType === "bar";
|
|
5080
|
+
return {
|
|
5081
|
+
categoryAxis: {
|
|
5082
|
+
position: horizontal ? "l" : "b",
|
|
5083
|
+
...NO_TICKS,
|
|
5084
|
+
line: AXIS_LINE
|
|
5085
|
+
},
|
|
5086
|
+
valueAxis: {
|
|
5087
|
+
position: horizontal ? "b" : "l",
|
|
5088
|
+
gridLine: GRIDLINES,
|
|
5089
|
+
...NO_TICKS,
|
|
5090
|
+
lineVisible: false,
|
|
5091
|
+
crossBetween: chartType === "area" ? "midCat" : "between"
|
|
5092
|
+
}
|
|
5093
|
+
};
|
|
5094
|
+
}
|
|
5095
|
+
case "radar":
|
|
5096
|
+
return {
|
|
5097
|
+
categoryAxis: {
|
|
5098
|
+
position: "b",
|
|
5099
|
+
gridLine: GRIDLINES,
|
|
5100
|
+
...NO_TICKS,
|
|
5101
|
+
majorTickMark: "cross",
|
|
5102
|
+
line: AXIS_LINE
|
|
5103
|
+
},
|
|
5104
|
+
valueAxis: {
|
|
5105
|
+
position: "l",
|
|
5106
|
+
gridLine: GRIDLINES,
|
|
5107
|
+
...NO_TICKS,
|
|
5108
|
+
majorTickMark: "cross",
|
|
5109
|
+
line: AXIS_LINE,
|
|
5110
|
+
crossBetween: "between"
|
|
5111
|
+
}
|
|
5112
|
+
};
|
|
5113
|
+
case "scatter": {
|
|
5114
|
+
const line = { ...AXIS_LINE, color: SCATTER_AXIS_TINT };
|
|
5115
|
+
return {
|
|
5116
|
+
categoryAxis: {
|
|
5117
|
+
position: "b",
|
|
5118
|
+
...NO_TICKS,
|
|
5119
|
+
line,
|
|
5120
|
+
crossBetween: "midCat"
|
|
5121
|
+
},
|
|
5122
|
+
valueAxis: {
|
|
5123
|
+
position: "l",
|
|
5124
|
+
gridLine: GRIDLINES,
|
|
5125
|
+
...NO_TICKS,
|
|
5126
|
+
line,
|
|
5127
|
+
crossBetween: "midCat"
|
|
5128
|
+
}
|
|
5129
|
+
};
|
|
5130
|
+
}
|
|
5131
|
+
default:
|
|
5132
|
+
return {};
|
|
5133
|
+
}
|
|
5134
|
+
}
|
|
5135
|
+
function plotLook(chart) {
|
|
5136
|
+
const common = {
|
|
5137
|
+
...axesLook(chart.chartType),
|
|
5138
|
+
autoTitleDeleted: !(chart.title && chart.showTitle !== false),
|
|
5139
|
+
plotAreaUnfilled: true
|
|
5140
|
+
};
|
|
5141
|
+
switch (chart.chartType) {
|
|
5142
|
+
case "column":
|
|
5143
|
+
return { ...common, dataBorder: "none", gapWidth: 219, overlap: -27 };
|
|
5144
|
+
case "bar":
|
|
5145
|
+
return { ...common, dataBorder: "none", gapWidth: 182, overlap: 0 };
|
|
5146
|
+
case "area":
|
|
5147
|
+
return { ...common, dataBorder: "none" };
|
|
5148
|
+
case "line":
|
|
5149
|
+
return { ...common, ...LINE_SERIES, lineMarkers: true };
|
|
5150
|
+
case "radar":
|
|
5151
|
+
return { ...common, ...LINE_SERIES, radarStyle: "marker" };
|
|
5152
|
+
case "scatter": {
|
|
5153
|
+
const labels = chart.series[0]?.labels ?? [];
|
|
5154
|
+
return {
|
|
5155
|
+
...common,
|
|
5156
|
+
...LINE_SERIES,
|
|
5157
|
+
lineWidthPoints: 1.5,
|
|
5158
|
+
scatterStyle: "lineMarker",
|
|
5159
|
+
scatterXValues: labels.map((_, index) => scatterX(labels, index))
|
|
5160
|
+
};
|
|
5161
|
+
}
|
|
5162
|
+
case "pie":
|
|
5163
|
+
case "doughnut":
|
|
5164
|
+
return {
|
|
5165
|
+
...common,
|
|
5166
|
+
dataBorder: { widthPoints: 1.5, color: { scheme: "lt1" } },
|
|
5167
|
+
firstSliceAngle: 0,
|
|
5168
|
+
...chart.chartType === "doughnut" ? { holeSize: 50 } : {}
|
|
5169
|
+
};
|
|
5170
|
+
default:
|
|
5171
|
+
return common;
|
|
4157
5172
|
}
|
|
4158
|
-
return new Uint8Array(zip.toBuffer());
|
|
4159
5173
|
}
|
|
4160
|
-
var
|
|
4161
|
-
var
|
|
4162
|
-
"src/
|
|
5174
|
+
var TEXT_1_TINT, SCATTER_AXIS_TINT, HAIRLINE_POINTS, GRIDLINES, AXIS_LINE, NO_TICKS, LINE_SERIES, MARKER;
|
|
5175
|
+
var init_chartLook = __esm({
|
|
5176
|
+
"src/renderers/office-open/chartLook.ts"() {
|
|
4163
5177
|
"use strict";
|
|
4164
|
-
|
|
4165
|
-
|
|
5178
|
+
init_chartValues();
|
|
5179
|
+
TEXT_1_TINT = { scheme: "tx1", lumMod: 15e3, lumOff: 85e3 };
|
|
5180
|
+
SCATTER_AXIS_TINT = {
|
|
5181
|
+
scheme: "tx1",
|
|
5182
|
+
lumMod: 25e3,
|
|
5183
|
+
lumOff: 75e3
|
|
5184
|
+
};
|
|
5185
|
+
HAIRLINE_POINTS = 0.75;
|
|
5186
|
+
GRIDLINES = {
|
|
5187
|
+
size: HAIRLINE_POINTS,
|
|
5188
|
+
color: TEXT_1_TINT
|
|
5189
|
+
};
|
|
5190
|
+
AXIS_LINE = {
|
|
5191
|
+
widthPoints: HAIRLINE_POINTS,
|
|
5192
|
+
color: TEXT_1_TINT
|
|
5193
|
+
};
|
|
5194
|
+
NO_TICKS = {
|
|
5195
|
+
majorTickMark: "none",
|
|
5196
|
+
minorTickMark: "none",
|
|
5197
|
+
tickLabelPosition: "nextTo"
|
|
5198
|
+
};
|
|
5199
|
+
LINE_SERIES = {
|
|
5200
|
+
lineWidthPoints: 2.25,
|
|
5201
|
+
lineCap: "rnd",
|
|
5202
|
+
lineJoin: "round",
|
|
5203
|
+
markerLineWidthPoints: HAIRLINE_POINTS
|
|
5204
|
+
};
|
|
5205
|
+
MARKER = { symbol: "circle", size: 5 };
|
|
4166
5206
|
}
|
|
4167
5207
|
});
|
|
4168
5208
|
|
|
4169
5209
|
// src/renderers/office-open/chartParts.ts
|
|
4170
5210
|
import {
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
matchChartParts,
|
|
4174
|
-
spliceChartXml
|
|
5211
|
+
finishChartXml,
|
|
5212
|
+
matchChartParts
|
|
4175
5213
|
} from "@json-to-office/shared/rendering";
|
|
4176
|
-
function
|
|
4177
|
-
const
|
|
4178
|
-
const textFont =
|
|
4179
|
-
const axisTitleFont =
|
|
4180
|
-
const chartTitleFont =
|
|
4181
|
-
|
|
4182
|
-
|
|
4183
|
-
|
|
5214
|
+
function chartInput(chart) {
|
|
5215
|
+
const roles = chartTextRoles(chart.textFont);
|
|
5216
|
+
const textFont = roles.text;
|
|
5217
|
+
const axisTitleFont = roles.axisTitle;
|
|
5218
|
+
const chartTitleFont = roles.title;
|
|
5219
|
+
const look = plotLook(chart);
|
|
5220
|
+
const categoryAxis = {
|
|
5221
|
+
...look.categoryAxis,
|
|
5222
|
+
...chart.categoryAxisTitle ? { title: chart.categoryAxisTitle, titleFont: axisTitleFont } : {}
|
|
5223
|
+
};
|
|
5224
|
+
const valueAxis = {
|
|
5225
|
+
...look.valueAxis,
|
|
5226
|
+
...chart.valueAxisTitle ? { title: chart.valueAxisTitle, titleFont: axisTitleFont } : {}
|
|
4184
5227
|
};
|
|
4185
5228
|
return {
|
|
5229
|
+
...look,
|
|
4186
5230
|
chartType: chart.chartType,
|
|
4187
5231
|
series: chart.series,
|
|
4188
5232
|
colors: chart.colors,
|
|
5233
|
+
...chart.title && chart.showTitle !== false ? { title: chart.title } : {},
|
|
4189
5234
|
textFont,
|
|
4190
5235
|
titleFont: chartTitleFont,
|
|
4191
5236
|
...chart.legendPosition ? { legendPosition: chart.legendPosition } : {},
|
|
4192
|
-
...
|
|
4193
|
-
|
|
4194
|
-
title: chart.categoryAxisTitle,
|
|
4195
|
-
titleFont: axisTitleFont
|
|
4196
|
-
}
|
|
4197
|
-
} : {},
|
|
4198
|
-
...chart.valueAxisTitle ? {
|
|
4199
|
-
valueAxis: { title: chart.valueAxisTitle, titleFont: axisTitleFont }
|
|
4200
|
-
} : {}
|
|
5237
|
+
...Object.keys(categoryAxis).length > 0 ? { categoryAxis } : {},
|
|
5238
|
+
...Object.keys(valueAxis).length > 0 ? { valueAxis } : {}
|
|
4201
5239
|
};
|
|
4202
5240
|
}
|
|
4203
|
-
function
|
|
4204
|
-
|
|
4205
|
-
if (!entry) return;
|
|
4206
|
-
const xml = entry.getData().toString("utf8");
|
|
4207
|
-
if (xml.includes(`Extension="xlsx"`)) return;
|
|
4208
|
-
zip.updateFile(
|
|
4209
|
-
entry,
|
|
4210
|
-
Buffer.from(
|
|
4211
|
-
xml.replace(
|
|
4212
|
-
'<Default Extension="xml"',
|
|
4213
|
-
`<Default Extension="xlsx" ContentType="${CHART_WORKBOOK_CONTENT_TYPE}"/><Default Extension="xml"`
|
|
4214
|
-
),
|
|
4215
|
-
"utf8"
|
|
4216
|
-
)
|
|
4217
|
-
);
|
|
4218
|
-
}
|
|
4219
|
-
function spliceChartParts(zip, charts) {
|
|
4220
|
-
if (charts.length === 0) return;
|
|
5241
|
+
function finishChartParts(zip, charts2) {
|
|
5242
|
+
if (charts2.length === 0) return;
|
|
4221
5243
|
const parts = zip.getEntries().map((entry) => entry.entryName).map((name) => name.match(/^word\/charts\/chart(\d+)\.xml$/)).filter((match) => match !== null).map(
|
|
4222
5244
|
(match) => [
|
|
4223
5245
|
Number(match[1]),
|
|
4224
5246
|
zip.getEntry(match[0]).getData().toString("utf8")
|
|
4225
5247
|
]
|
|
4226
5248
|
);
|
|
4227
|
-
|
|
4228
|
-
|
|
5249
|
+
const inputs = charts2.map(chartInput);
|
|
5250
|
+
for (const { ordinal, xml, chart } of matchChartParts(parts, inputs)) {
|
|
5251
|
+
const finished = finishChartXml(xml, chart);
|
|
5252
|
+
if (finished === xml) continue;
|
|
4229
5253
|
zip.updateFile(
|
|
4230
5254
|
zip.getEntry(`word/charts/chart${ordinal}.xml`),
|
|
4231
|
-
Buffer.from(
|
|
4232
|
-
);
|
|
4233
|
-
zip.addFile(
|
|
4234
|
-
`word/embeddings/${workbookName}`,
|
|
4235
|
-
Buffer.from(buildChartWorkbook(chart.series))
|
|
4236
|
-
);
|
|
4237
|
-
zip.addFile(
|
|
4238
|
-
`word/charts/_rels/chart${ordinal}.xml.rels`,
|
|
4239
|
-
Buffer.from(chartWorkbookRelsXml(workbookName), "utf8")
|
|
5255
|
+
Buffer.from(finished, "utf8")
|
|
4240
5256
|
);
|
|
4241
5257
|
}
|
|
4242
|
-
declareWorkbookContentType(zip);
|
|
4243
5258
|
}
|
|
4244
|
-
var CHART_TITLE_SCALE;
|
|
4245
5259
|
var init_chartParts = __esm({
|
|
4246
5260
|
"src/renderers/office-open/chartParts.ts"() {
|
|
4247
5261
|
"use strict";
|
|
4248
|
-
|
|
4249
|
-
|
|
5262
|
+
init_chartText();
|
|
5263
|
+
init_chartLook();
|
|
4250
5264
|
}
|
|
4251
5265
|
});
|
|
4252
5266
|
|
|
4253
|
-
// src/renderers/office-open/
|
|
4254
|
-
function
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
for (const entry of zip.getEntries()) {
|
|
4258
|
-
if (!TABLE_PARTS.test(entry.entryName)) continue;
|
|
4259
|
-
const original = entry.getData().toString("utf8");
|
|
4260
|
-
let xml = original;
|
|
4261
|
-
for (const toc of tocs) {
|
|
4262
|
-
const start = markerParagraph(xml, toc.start);
|
|
4263
|
-
if (!start) continue;
|
|
4264
|
-
const end = markerParagraph(xml, toc.end);
|
|
4265
|
-
if (spliced.has(toc) || !end || end.from < start.to) {
|
|
4266
|
-
throw new Error(
|
|
4267
|
-
`the office-open renderer lost track of a table of contents in a table cell (${entry.entryName})`
|
|
4268
|
-
);
|
|
4269
|
-
}
|
|
4270
|
-
xml = xml.slice(0, start.from) + stringifyTableOfContents(
|
|
4271
|
-
toc.alias,
|
|
4272
|
-
toc.options,
|
|
4273
|
-
xml.slice(start.to, end.from)
|
|
4274
|
-
) + xml.slice(end.to);
|
|
4275
|
-
spliced.add(toc);
|
|
4276
|
-
}
|
|
4277
|
-
if (xml !== original) zip.updateFile(entry, Buffer.from(xml, "utf8"));
|
|
4278
|
-
}
|
|
4279
|
-
if (spliced.size !== tocs.length) {
|
|
5267
|
+
// src/renderers/office-open/themePart.ts
|
|
5268
|
+
function replaceOnce(xml, pattern, replacer, what) {
|
|
5269
|
+
const count = [...xml.matchAll(pattern)].length;
|
|
5270
|
+
if (count !== 1) {
|
|
4280
5271
|
throw new Error(
|
|
4281
|
-
`
|
|
5272
|
+
`office-open's theme part has ${count} ${what}, expected one`
|
|
4282
5273
|
);
|
|
4283
5274
|
}
|
|
5275
|
+
return xml.replace(pattern, replacer);
|
|
5276
|
+
}
|
|
5277
|
+
function spliceTheme(zip, theme) {
|
|
5278
|
+
const entry = zip.getEntry(THEME_PART);
|
|
5279
|
+
if (!entry) throw new Error(`office-open wrote no ${THEME_PART}`);
|
|
5280
|
+
let xml = entry.getData().toString("utf8");
|
|
5281
|
+
const name = esc(theme.name);
|
|
5282
|
+
xml = renamed(xml, "theme", name);
|
|
5283
|
+
const colors = Object.entries(theme.colors);
|
|
5284
|
+
if (colors.some(([, color]) => color)) {
|
|
5285
|
+
xml = renamed(xml, "clrScheme", name);
|
|
5286
|
+
for (const [slot, color] of colors) {
|
|
5287
|
+
if (!color) continue;
|
|
5288
|
+
const element = SCHEME_ELEMENT[slot];
|
|
5289
|
+
xml = replaceOnce(
|
|
5290
|
+
xml,
|
|
5291
|
+
new RegExp(`<a:${element}>[\\s\\S]*?</a:${element}>`, "g"),
|
|
5292
|
+
() => `<a:${element}><a:srgbClr val="${color.hex}"/></a:${element}>`,
|
|
5293
|
+
`a:${element}`
|
|
5294
|
+
);
|
|
5295
|
+
}
|
|
5296
|
+
}
|
|
5297
|
+
if (theme.headingFont || theme.bodyFont) {
|
|
5298
|
+
xml = renamed(xml, "fontScheme", name);
|
|
5299
|
+
for (const [collection, key, officeFace] of OFFICE_FACES) {
|
|
5300
|
+
const family = theme[key];
|
|
5301
|
+
if (family === void 0 || family === officeFace) continue;
|
|
5302
|
+
xml = replaceOnce(
|
|
5303
|
+
xml,
|
|
5304
|
+
new RegExp(`(<a:${collection}>)<a:latin\\b[^>]*/>`, "g"),
|
|
5305
|
+
(_match, open) => `${open}<a:latin typeface="${esc(family)}"/>`,
|
|
5306
|
+
`a:${collection} a:latin`
|
|
5307
|
+
);
|
|
5308
|
+
}
|
|
5309
|
+
}
|
|
5310
|
+
zip.updateFile(THEME_PART, Buffer.from(xml, "utf8"));
|
|
4284
5311
|
}
|
|
4285
|
-
|
|
4286
|
-
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
xml
|
|
4290
|
-
|
|
4291
|
-
|
|
4292
|
-
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
|
|
5312
|
+
var THEME_PART, SCHEME_ELEMENT, OFFICE_FACES, esc, renamed;
|
|
5313
|
+
var init_themePart = __esm({
|
|
5314
|
+
"src/renderers/office-open/themePart.ts"() {
|
|
5315
|
+
"use strict";
|
|
5316
|
+
THEME_PART = "word/theme/theme1.xml";
|
|
5317
|
+
SCHEME_ELEMENT = {
|
|
5318
|
+
dark1: "dk1",
|
|
5319
|
+
light1: "lt1",
|
|
5320
|
+
dark2: "dk2",
|
|
5321
|
+
light2: "lt2",
|
|
5322
|
+
accent1: "accent1",
|
|
5323
|
+
accent2: "accent2",
|
|
5324
|
+
accent3: "accent3",
|
|
5325
|
+
accent4: "accent4",
|
|
5326
|
+
accent5: "accent5",
|
|
5327
|
+
accent6: "accent6",
|
|
5328
|
+
hyperlink: "hlink",
|
|
5329
|
+
followedHyperlink: "folHlink"
|
|
5330
|
+
};
|
|
5331
|
+
OFFICE_FACES = [
|
|
5332
|
+
["majorFont", "headingFont", "Calibri Light"],
|
|
5333
|
+
["minorFont", "bodyFont", "Calibri"]
|
|
5334
|
+
];
|
|
5335
|
+
esc = (value) => value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
5336
|
+
renamed = (xml, element, name) => replaceOnce(
|
|
5337
|
+
xml,
|
|
5338
|
+
new RegExp(`(<a:${element}\\b[^>]*?\\bname=")[^"]*(")`, "g"),
|
|
5339
|
+
(_match, open, close) => `${open}${name}${close}`,
|
|
5340
|
+
`a:${element} name`
|
|
4296
5341
|
);
|
|
4297
5342
|
}
|
|
4298
|
-
|
|
5343
|
+
});
|
|
5344
|
+
|
|
5345
|
+
// src/utils/chartWorkbook.ts
|
|
5346
|
+
import AdmZip4 from "adm-zip";
|
|
5347
|
+
import { chartWorkbookParts } from "@json-to-office/shared/rendering";
|
|
5348
|
+
import {
|
|
5349
|
+
CHART_WORKBOOK_SHEET_NAME,
|
|
5350
|
+
categoryReference,
|
|
5351
|
+
columnLetter,
|
|
5352
|
+
seriesNameReference,
|
|
5353
|
+
seriesValueReference
|
|
5354
|
+
} from "@json-to-office/shared/rendering";
|
|
5355
|
+
function buildChartWorkbook(series, options = {}) {
|
|
5356
|
+
const zip = new AdmZip4();
|
|
5357
|
+
for (const [name, content] of chartWorkbookParts(series, options)) {
|
|
5358
|
+
zip.addFile(name, Buffer.from(content, "utf8"));
|
|
5359
|
+
}
|
|
5360
|
+
for (const entry of zip.getEntries()) {
|
|
5361
|
+
entry.header.timeval = WORKBOOK_TIMESTAMP;
|
|
5362
|
+
}
|
|
5363
|
+
return new Uint8Array(zip.toBuffer());
|
|
4299
5364
|
}
|
|
4300
|
-
var
|
|
4301
|
-
var
|
|
4302
|
-
"src/
|
|
5365
|
+
var WORKBOOK_TIMESTAMP;
|
|
5366
|
+
var init_chartWorkbook = __esm({
|
|
5367
|
+
"src/utils/chartWorkbook.ts"() {
|
|
4303
5368
|
"use strict";
|
|
4304
|
-
|
|
5369
|
+
init_packageDocument();
|
|
5370
|
+
WORKBOOK_TIMESTAMP = toDosTime(DEFAULT_GENERATION_DATE);
|
|
4305
5371
|
}
|
|
4306
5372
|
});
|
|
4307
5373
|
|
|
4308
5374
|
// src/renderers/office-open/emit.ts
|
|
4309
|
-
import { assertNever as
|
|
5375
|
+
import { assertNever as assertNever3 } from "@json-to-office/shared/rendering";
|
|
5376
|
+
import { chartLook, withSeriesLook } from "@json-to-office/shared/rendering";
|
|
4310
5377
|
function emptyContext() {
|
|
4311
5378
|
let next = 1;
|
|
4312
5379
|
return {
|
|
4313
5380
|
pictures: /* @__PURE__ */ new Map(),
|
|
4314
5381
|
nextDrawingId: () => next++,
|
|
4315
|
-
charts: []
|
|
4316
|
-
cellTocs: []
|
|
5382
|
+
charts: []
|
|
4317
5383
|
};
|
|
4318
5384
|
}
|
|
4319
5385
|
function simpleField(instruction, cachedText) {
|
|
@@ -4354,18 +5420,19 @@ function runProperties2(formatting) {
|
|
|
4354
5420
|
if (formatting.doubleStrike !== void 0) {
|
|
4355
5421
|
out.doubleStrike = formatting.doubleStrike;
|
|
4356
5422
|
}
|
|
4357
|
-
if (formatting.superScript) out.
|
|
4358
|
-
if (formatting.subScript) out.
|
|
5423
|
+
if (formatting.superScript) out.verticalAlign = "superscript";
|
|
5424
|
+
if (formatting.subScript) out.verticalAlign = "subscript";
|
|
4359
5425
|
if (formatting.smallCaps !== void 0) out.smallCaps = formatting.smallCaps;
|
|
4360
5426
|
if (formatting.allCaps !== void 0) out.allCaps = formatting.allCaps;
|
|
4361
|
-
if (formatting.highlight !== void 0)
|
|
5427
|
+
if (formatting.highlight !== void 0) {
|
|
5428
|
+
out.highlight = formatting.highlight;
|
|
5429
|
+
}
|
|
4362
5430
|
if (formatting.shading) out.shading = shading(formatting.shading);
|
|
4363
5431
|
if (formatting.scalePercent !== void 0)
|
|
4364
5432
|
out.scale = formatting.scalePercent;
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
out.characterSpacing = twentieths === 0 && stated !== 0 ? "0pt" : twentieths;
|
|
5433
|
+
const stated = formatting.characterSpacingTwentieths;
|
|
5434
|
+
if (stated !== void 0 && stated !== 0) {
|
|
5435
|
+
out.characterSpacing = twips(stated);
|
|
4369
5436
|
}
|
|
4370
5437
|
if (formatting.language) out.language = { value: formatting.language };
|
|
4371
5438
|
if (formatting.noProof !== void 0) out.noProof = formatting.noProof;
|
|
@@ -4395,7 +5462,9 @@ function inlineChildren2(children, ctx = emptyContext()) {
|
|
|
4395
5462
|
switch (child.kind) {
|
|
4396
5463
|
case "lineBreak":
|
|
4397
5464
|
pendingBreaks += 1;
|
|
4398
|
-
if (child.clear && child.clear !== "none")
|
|
5465
|
+
if (child.clear && child.clear !== "none") {
|
|
5466
|
+
pendingClear = child.clear;
|
|
5467
|
+
}
|
|
4399
5468
|
break;
|
|
4400
5469
|
case "text":
|
|
4401
5470
|
out.push({
|
|
@@ -4433,7 +5502,7 @@ function inlineChildren2(children, ctx = emptyContext()) {
|
|
|
4433
5502
|
case "drawingGroup": {
|
|
4434
5503
|
const pending = breakOption();
|
|
4435
5504
|
if (pending.break) out.push(pending);
|
|
4436
|
-
out.push({ wpgGroup:
|
|
5505
|
+
out.push({ wpgGroup: drawingGroupOptions2(child, ctx) });
|
|
4437
5506
|
break;
|
|
4438
5507
|
}
|
|
4439
5508
|
case "hyperlink":
|
|
@@ -4463,8 +5532,9 @@ function inlineChildren2(children, ctx = emptyContext()) {
|
|
|
4463
5532
|
out.push({ wpsShape: shapeOptions(child, ctx) });
|
|
4464
5533
|
break;
|
|
4465
5534
|
case "chart":
|
|
4466
|
-
|
|
4467
|
-
|
|
5535
|
+
out.push({
|
|
5536
|
+
chart: chartOptions(child, ctx, ctx.charts?.push(child) ?? 1)
|
|
5537
|
+
});
|
|
4468
5538
|
break;
|
|
4469
5539
|
case "noteReference":
|
|
4470
5540
|
out.push(
|
|
@@ -4472,7 +5542,7 @@ function inlineChildren2(children, ctx = emptyContext()) {
|
|
|
4472
5542
|
);
|
|
4473
5543
|
break;
|
|
4474
5544
|
default:
|
|
4475
|
-
|
|
5545
|
+
assertNever3(child, "DocxIrInline");
|
|
4476
5546
|
}
|
|
4477
5547
|
}
|
|
4478
5548
|
return out;
|
|
@@ -4513,8 +5583,11 @@ function floatingOptions2(floating) {
|
|
|
4513
5583
|
...floating.vertical ? { verticalPosition: position(floating.vertical) } : {},
|
|
4514
5584
|
...floating.wrap ? {
|
|
4515
5585
|
wrap: {
|
|
4516
|
-
|
|
4517
|
-
|
|
5586
|
+
// Named, as OOXML names them; 0.11 took docx.js's numbers.
|
|
5587
|
+
type: floating.wrap.type,
|
|
5588
|
+
...floating.wrap.side ? {
|
|
5589
|
+
side: floating.wrap.side
|
|
5590
|
+
} : {}
|
|
4518
5591
|
}
|
|
4519
5592
|
} : {},
|
|
4520
5593
|
...floating.margins ? {
|
|
@@ -4541,66 +5614,92 @@ function imageMedia(ctx, resourceId, placement) {
|
|
|
4541
5614
|
}
|
|
4542
5615
|
function pictureOptions(image, ctx) {
|
|
4543
5616
|
const media = imageMedia(ctx, image.resourceId, image);
|
|
4544
|
-
|
|
4545
|
-
type:
|
|
5617
|
+
const source = media.type === "svg" ? {
|
|
5618
|
+
type: "svg",
|
|
4546
5619
|
data: media.data,
|
|
4547
|
-
//
|
|
4548
|
-
//
|
|
4549
|
-
|
|
5620
|
+
// The SVG slot always carries a raster: `prepareImages` falls back
|
|
5621
|
+
// to the vector bytes when none could be made.
|
|
5622
|
+
fallback: media.fallback ?? {
|
|
5623
|
+
type: "png",
|
|
5624
|
+
data: media.data
|
|
5625
|
+
}
|
|
5626
|
+
} : { type: media.type, data: media.data };
|
|
5627
|
+
return {
|
|
5628
|
+
...source,
|
|
4550
5629
|
// Raw numbers are EMUs in @office-open/docx. Passing pixels here makes a
|
|
4551
5630
|
// normal image only a few hundred EMUs wide, effectively a dot.
|
|
4552
5631
|
transformation: { width: image.widthEmu, height: image.heightEmu },
|
|
4553
5632
|
// The id is stated rather than left to the backend's process-global
|
|
4554
|
-
// counter. `name` stays empty, which is what
|
|
4555
|
-
|
|
4556
|
-
altText: { id: String(ctx.nextDrawingId()) },
|
|
5633
|
+
// counter. `name` stays empty, which is what the backend falls back to.
|
|
5634
|
+
altText: { id: String(ctx.nextDrawingId()), name: "" },
|
|
4557
5635
|
...image.floating ? { floating: floatingOptions2(image.floating) } : {}
|
|
4558
5636
|
// No `description` or `title`: no DOCX this pipeline has produced carries
|
|
4559
5637
|
// `wp:docPr` alt text, and the compiler warns so the gap is visible rather
|
|
4560
5638
|
// than silent.
|
|
4561
5639
|
};
|
|
4562
5640
|
}
|
|
4563
|
-
function
|
|
5641
|
+
function drawingGroupOptions2(group, ctx) {
|
|
4564
5642
|
const id = ctx.nextDrawingId();
|
|
4565
5643
|
return {
|
|
4566
5644
|
altText: {
|
|
4567
5645
|
id: String(id),
|
|
5646
|
+
name: "",
|
|
4568
5647
|
...group.altText ? { description: group.altText } : {}
|
|
4569
5648
|
},
|
|
4570
5649
|
transformation: { width: group.widthEmu, height: group.heightEmu },
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
|
|
5650
|
+
childOffsetX: 0,
|
|
5651
|
+
childOffsetY: 0,
|
|
5652
|
+
childExtentWidth: group.canvasWidthEmu,
|
|
5653
|
+
childExtentHeight: group.canvasHeightEmu,
|
|
5654
|
+
children: group.children.map((child) => groupChild2(child, ctx)),
|
|
4574
5655
|
...group.floating ? { floating: floatingOptions2(group.floating) } : {}
|
|
4575
5656
|
};
|
|
4576
5657
|
}
|
|
4577
|
-
function chartOptions(chart, ctx) {
|
|
5658
|
+
function chartOptions(chart, ctx, ordinal) {
|
|
4578
5659
|
const id = ctx.nextDrawingId();
|
|
5660
|
+
const input = chartInput(chart);
|
|
5661
|
+
const look = chartLook(input);
|
|
4579
5662
|
return {
|
|
4580
5663
|
type: chart.chartType,
|
|
4581
5664
|
categories: chart.series[0]?.labels ?? [],
|
|
4582
|
-
series: chart.series.map(
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
5665
|
+
series: chart.series.map(
|
|
5666
|
+
(entry, index) => withSeriesLook(
|
|
5667
|
+
{
|
|
5668
|
+
name: entry.name ?? `Series ${index + 1}`,
|
|
5669
|
+
values: entry.values,
|
|
5670
|
+
...seriesLook(chart.chartType)
|
|
5671
|
+
},
|
|
5672
|
+
look.series[index]
|
|
5673
|
+
)
|
|
5674
|
+
),
|
|
5675
|
+
...look.chart,
|
|
4587
5676
|
...chart.showLegend !== void 0 ? { showLegend: chart.showLegend } : {},
|
|
5677
|
+
externalData: {
|
|
5678
|
+
...look.chart.externalData,
|
|
5679
|
+
fileName: `chart${ordinal}.xlsx`,
|
|
5680
|
+
// A scatter chart's column A holds the x values its `c:xVal` caches.
|
|
5681
|
+
data: buildChartWorkbook(
|
|
5682
|
+
chart.series,
|
|
5683
|
+
input.scatterXValues ? { categoryValues: input.scatterXValues } : {}
|
|
5684
|
+
)
|
|
5685
|
+
},
|
|
4588
5686
|
transformation: { width: chart.widthEmu, height: chart.heightEmu },
|
|
4589
5687
|
altText: {
|
|
4590
5688
|
id: String(id),
|
|
5689
|
+
name: "",
|
|
4591
5690
|
...chart.altText ? { description: chart.altText } : {}
|
|
4592
5691
|
},
|
|
4593
5692
|
...chart.floating ? { floating: floatingOptions2(chart.floating) } : {}
|
|
4594
5693
|
};
|
|
4595
5694
|
}
|
|
4596
|
-
function
|
|
5695
|
+
function groupChild2(child, ctx) {
|
|
4597
5696
|
return child.kind === "shape" ? groupShape(child, ctx) : groupPicture(child, ctx);
|
|
4598
5697
|
}
|
|
4599
5698
|
function groupShape(shape, ctx) {
|
|
4600
5699
|
const id = ctx.nextDrawingId();
|
|
4601
5700
|
return {
|
|
4602
5701
|
type: "wps",
|
|
4603
|
-
transformation:
|
|
5702
|
+
transformation: childTransformation2(shape.frame),
|
|
4604
5703
|
data: {
|
|
4605
5704
|
nonVisualProperties: {
|
|
4606
5705
|
id,
|
|
@@ -4609,7 +5708,7 @@ function groupShape(shape, ctx) {
|
|
|
4609
5708
|
// to hold text, and it changes how the object behaves on selection.
|
|
4610
5709
|
...shape.isTextBox ? { textBox: "1" } : {}
|
|
4611
5710
|
},
|
|
4612
|
-
|
|
5711
|
+
geometry: shape.geometry,
|
|
4613
5712
|
...shape.fill ? { fill: drawingFill(shape.fill) } : {},
|
|
4614
5713
|
...shape.outline ? { outline: drawingOutline(shape.outline) } : {},
|
|
4615
5714
|
children: (shape.text?.paragraphs ?? []).map(
|
|
@@ -4635,7 +5734,7 @@ function groupPicture(picture2, ctx) {
|
|
|
4635
5734
|
fileName: media.fallbackFileName
|
|
4636
5735
|
}
|
|
4637
5736
|
} : {},
|
|
4638
|
-
transformation:
|
|
5737
|
+
transformation: childTransformation2(picture2.frame),
|
|
4639
5738
|
nonVisualProperties: {
|
|
4640
5739
|
id,
|
|
4641
5740
|
...picture2.name ? { name: picture2.name } : {},
|
|
@@ -4644,11 +5743,7 @@ function groupPicture(picture2, ctx) {
|
|
|
4644
5743
|
...picture2.crop ? { sourceRectangle: sourceRectangle(picture2.crop) } : {}
|
|
4645
5744
|
};
|
|
4646
5745
|
}
|
|
4647
|
-
function
|
|
4648
|
-
const flip = {
|
|
4649
|
-
...frame.flipHorizontal ? { horizontal: true } : {},
|
|
4650
|
-
...frame.flipVertical ? { vertical: true } : {}
|
|
4651
|
-
};
|
|
5746
|
+
function childTransformation2(frame) {
|
|
4652
5747
|
return {
|
|
4653
5748
|
offset: {
|
|
4654
5749
|
emus: { x: frame.xEmu, y: frame.yEmu },
|
|
@@ -4664,7 +5759,8 @@ function childTransformation(frame) {
|
|
|
4664
5759
|
},
|
|
4665
5760
|
// Degrees: the backend multiplies by 60000 on the way into `@rot`.
|
|
4666
5761
|
...frame.rotationDegrees !== void 0 ? { rotation: frame.rotationDegrees } : {},
|
|
4667
|
-
...
|
|
5762
|
+
...frame.flipHorizontal ? { flipHorizontal: true } : {},
|
|
5763
|
+
...frame.flipVertical ? { flipVertical: true } : {}
|
|
4668
5764
|
};
|
|
4669
5765
|
}
|
|
4670
5766
|
function drawingFill(fill) {
|
|
@@ -4672,7 +5768,6 @@ function drawingFill(fill) {
|
|
|
4672
5768
|
return {
|
|
4673
5769
|
type: "solid",
|
|
4674
5770
|
color: {
|
|
4675
|
-
type: "rgb",
|
|
4676
5771
|
value: fill.color.hex,
|
|
4677
5772
|
// Transparency becomes an alpha transform on the colour. DrawingML
|
|
4678
5773
|
// states *opacity*, so the value is the complement of what the author
|
|
@@ -4714,7 +5809,7 @@ function sourceRectangle(crop) {
|
|
|
4714
5809
|
function shapeOptions(shape, ctx) {
|
|
4715
5810
|
const id = String(ctx.nextDrawingId());
|
|
4716
5811
|
return {
|
|
4717
|
-
altText: { id },
|
|
5812
|
+
altText: { id, name: "" },
|
|
4718
5813
|
children: shape.children.map((child) => paragraph(child, ctx)),
|
|
4719
5814
|
// Raw transformation numbers are EMUs in @office-open/docx, while the IR
|
|
4720
5815
|
// deliberately stores native shape dimensions in pixels.
|
|
@@ -4725,7 +5820,7 @@ function shapeOptions(shape, ctx) {
|
|
|
4725
5820
|
...shape.fill ? {
|
|
4726
5821
|
fill: {
|
|
4727
5822
|
type: "solid",
|
|
4728
|
-
color: {
|
|
5823
|
+
color: { value: shape.fill.hex }
|
|
4729
5824
|
}
|
|
4730
5825
|
} : {},
|
|
4731
5826
|
...shape.outline ? { outline: drawingOutline(shape.outline) } : {},
|
|
@@ -4830,13 +5925,19 @@ function frameOptions2(frame) {
|
|
|
4830
5925
|
...frame.anchorLock !== void 0 ? { anchorLock: frame.anchorLock } : {},
|
|
4831
5926
|
...frame.rule ? { rule: frame.rule } : {}
|
|
4832
5927
|
};
|
|
4833
|
-
|
|
4834
|
-
|
|
4835
|
-
|
|
4836
|
-
|
|
4837
|
-
|
|
5928
|
+
if (frame.xTwips !== void 0 || frame.yTwips !== void 0) {
|
|
5929
|
+
return {
|
|
5930
|
+
type: "absolute",
|
|
5931
|
+
position: { x: frame.xTwips ?? 0, y: frame.yTwips ?? 0 },
|
|
5932
|
+
...base
|
|
5933
|
+
};
|
|
5934
|
+
}
|
|
5935
|
+
return {
|
|
4838
5936
|
type: "alignment",
|
|
4839
|
-
alignment: {
|
|
5937
|
+
alignment: {
|
|
5938
|
+
x: frame.xAlign,
|
|
5939
|
+
y: frame.yAlign
|
|
5940
|
+
},
|
|
4840
5941
|
...base
|
|
4841
5942
|
};
|
|
4842
5943
|
}
|
|
@@ -4857,7 +5958,7 @@ function block(value, ctx = emptyContext()) {
|
|
|
4857
5958
|
case "toc":
|
|
4858
5959
|
return { toc: tableOfContents(value) };
|
|
4859
5960
|
default:
|
|
4860
|
-
return
|
|
5961
|
+
return assertNever3(value, "DocxIrBlock");
|
|
4861
5962
|
}
|
|
4862
5963
|
}
|
|
4863
5964
|
function tocEntry(entry) {
|
|
@@ -4876,6 +5977,7 @@ function tableOfContents(value) {
|
|
|
4876
5977
|
headingStyleRange: `${value.headingRange.from}-${value.headingRange.to}`
|
|
4877
5978
|
} : {},
|
|
4878
5979
|
...value.styleLevels?.length ? {
|
|
5980
|
+
// `StyleLevel` is a class the backend only reads the two fields of.
|
|
4879
5981
|
stylesWithLevels: value.styleLevels.map((style) => ({
|
|
4880
5982
|
styleName: style.styleName,
|
|
4881
5983
|
level: style.level
|
|
@@ -4897,14 +5999,16 @@ function table(value, ctx) {
|
|
|
4897
5999
|
// unstated columns comes out fractional, and the XML would carry it
|
|
4898
6000
|
// verbatim; floored here, as the docxjs backend floors it.
|
|
4899
6001
|
size: value.width.kind === "auto" ? 0 : value.width.kind === "twips" ? twips(value.width.value) : value.width.value,
|
|
4900
|
-
type: value.width.kind === "twips" ? "
|
|
6002
|
+
type: value.width.kind === "twips" ? "twips" : value.width.kind === "percent" ? "percent" : "auto"
|
|
4901
6003
|
},
|
|
4902
6004
|
layout: value.layout,
|
|
4903
6005
|
// An empty grid is a table with nothing to say about its columns, which is
|
|
4904
6006
|
// not the same as one whose columns are all zero wide. The compiler hands
|
|
4905
6007
|
// over every grid in twips; floored for the same reason as the width.
|
|
4906
6008
|
...value.columnGrid.values.length > 0 ? { columnWidths: value.columnGrid.values.map(twips) } : {},
|
|
4907
|
-
...value.alignment ? {
|
|
6009
|
+
...value.alignment ? {
|
|
6010
|
+
alignment: alignment(value.alignment)
|
|
6011
|
+
} : {},
|
|
4908
6012
|
...value.borders ? { borders: borders2(value.borders) } : {},
|
|
4909
6013
|
...value.cellMargins ? { margins: cellMargins(value.cellMargins) } : {},
|
|
4910
6014
|
...value.floating ? { float: tableFloat2(value.floating) } : {}
|
|
@@ -4949,52 +6053,29 @@ function tableRow(row, ctx) {
|
|
|
4949
6053
|
}
|
|
4950
6054
|
function tableCell(cell, ctx) {
|
|
4951
6055
|
const children = cellChildren2(cell, ctx);
|
|
4952
|
-
if (cell.children[cell.children.length - 1]?.kind
|
|
6056
|
+
if (cell.children[cell.children.length - 1]?.kind === "toc")
|
|
4953
6057
|
children.push({ paragraph: { children: [] } });
|
|
4954
6058
|
return {
|
|
4955
6059
|
children,
|
|
4956
|
-
...cell.widthTwips !== void 0 ? { width: { size: twips(cell.widthTwips), type: "
|
|
4957
|
-
...cell.verticalAlign ? {
|
|
6060
|
+
...cell.widthTwips !== void 0 ? { width: { size: twips(cell.widthTwips), type: "twips" } } : {},
|
|
6061
|
+
...cell.verticalAlign ? {
|
|
6062
|
+
verticalAlign: cell.verticalAlign
|
|
6063
|
+
} : {},
|
|
4958
6064
|
...cell.shading ? { shading: shading(cell.shading) } : {},
|
|
4959
6065
|
...cell.margins ? { margins: cellMargins(cell.margins) } : {},
|
|
4960
6066
|
...cell.borders ? { borders: borders2(cell.borders) } : {},
|
|
4961
6067
|
...cell.columnSpan !== void 0 ? { columnSpan: cell.columnSpan } : {},
|
|
4962
6068
|
...cell.rowSpan !== void 0 ? { verticalMerge: cell.rowSpan } : {},
|
|
4963
|
-
...cell.textDirection ? {
|
|
6069
|
+
...cell.textDirection ? {
|
|
6070
|
+
textDirection: cell.textDirection
|
|
6071
|
+
} : {}
|
|
4964
6072
|
};
|
|
4965
6073
|
}
|
|
4966
6074
|
function cellChildren2(cell, ctx) {
|
|
4967
|
-
|
|
4968
|
-
for (const child of cell.children) {
|
|
4969
|
-
if (child.kind !== "toc") {
|
|
4970
|
-
children.push(block(child, ctx));
|
|
4971
|
-
continue;
|
|
4972
|
-
}
|
|
4973
|
-
const { alias, entries, ...options } = tableOfContents(child);
|
|
4974
|
-
const index = ctx.cellTocs.length;
|
|
4975
|
-
const toc = {
|
|
4976
|
-
start: cellTocMarker(index, "start"),
|
|
4977
|
-
end: cellTocMarker(index, "end"),
|
|
4978
|
-
alias: String(alias),
|
|
4979
|
-
options
|
|
4980
|
-
};
|
|
4981
|
-
ctx.cellTocs.push(toc);
|
|
4982
|
-
children.push(
|
|
4983
|
-
markerParagraph2(toc.start),
|
|
4984
|
-
...entries ?? [],
|
|
4985
|
-
markerParagraph2(toc.end)
|
|
4986
|
-
);
|
|
4987
|
-
}
|
|
4988
|
-
return children;
|
|
4989
|
-
}
|
|
4990
|
-
function cellTocMarker(index, edge) {
|
|
4991
|
-
return `\uE000jto-cell-toc-${index}-${edge}\uE000`;
|
|
4992
|
-
}
|
|
4993
|
-
function markerParagraph2(text) {
|
|
4994
|
-
return { paragraph: { children: [{ text }] } };
|
|
6075
|
+
return cell.children.map((child) => block(child, ctx));
|
|
4995
6076
|
}
|
|
4996
6077
|
function cellMargins(margins) {
|
|
4997
|
-
const side = (value) => value === void 0 ? void 0 : { size: twips(value), type: "
|
|
6078
|
+
const side = (value) => value === void 0 ? void 0 : { size: twips(value), type: "twips" };
|
|
4998
6079
|
const out = {};
|
|
4999
6080
|
for (const [name, value] of [
|
|
5000
6081
|
["top", margins.topTwips],
|
|
@@ -5037,39 +6118,43 @@ function section(value, ctx, closesDocument = false) {
|
|
|
5037
6118
|
properties: {
|
|
5038
6119
|
...value.properties.type ? { type: value.properties.type } : {},
|
|
5039
6120
|
...value.properties.titlePage !== void 0 ? { titlePage: value.properties.titlePage } : {},
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
|
|
5044
|
-
|
|
5045
|
-
|
|
5046
|
-
|
|
5047
|
-
|
|
5048
|
-
|
|
5049
|
-
|
|
5050
|
-
|
|
5051
|
-
|
|
5052
|
-
|
|
5053
|
-
|
|
5054
|
-
|
|
5055
|
-
...page.margins.gutterTwips !== void 0 ? { gutter: twips(page.margins.gutterTwips) } : {}
|
|
5056
|
-
},
|
|
5057
|
-
...value.properties.pageNumbers ? {
|
|
5058
|
-
pageNumbers: {
|
|
5059
|
-
...value.properties.pageNumbers.start !== void 0 ? { start: value.properties.pageNumbers.start } : {},
|
|
5060
|
-
...value.properties.pageNumbers.formatType ? { formatType: value.properties.pageNumbers.formatType } : {}
|
|
5061
|
-
}
|
|
5062
|
-
} : {},
|
|
5063
|
-
...value.properties.borders ? {
|
|
5064
|
-
borders: {
|
|
5065
|
-
...value.properties.borders.display ? { display: value.properties.borders.display } : {},
|
|
5066
|
-
...value.properties.borders.offsetFrom ? { offsetFrom: value.properties.borders.offsetFrom } : {},
|
|
5067
|
-
...value.properties.borders.borders ? borders2(value.properties.borders.borders) : {}
|
|
5068
|
-
}
|
|
5069
|
-
} : {}
|
|
6121
|
+
// Orientation is implied by the width/height pair, which is how this
|
|
6122
|
+
// pipeline has always expressed it; stating it as well changes `w:pgSz`.
|
|
6123
|
+
pageSize: {
|
|
6124
|
+
width: twips(page.widthTwips),
|
|
6125
|
+
height: twips(page.heightTwips),
|
|
6126
|
+
...page.code !== void 0 ? { code: page.code } : {}
|
|
6127
|
+
},
|
|
6128
|
+
pageMargin: {
|
|
6129
|
+
top: twips(page.margins.topTwips),
|
|
6130
|
+
right: twips(page.margins.rightTwips),
|
|
6131
|
+
bottom: twips(page.margins.bottomTwips),
|
|
6132
|
+
left: twips(page.margins.leftTwips),
|
|
6133
|
+
...page.margins.headerTwips !== void 0 ? { header: twips(page.margins.headerTwips) } : {},
|
|
6134
|
+
...page.margins.footerTwips !== void 0 ? { footer: twips(page.margins.footerTwips) } : {},
|
|
6135
|
+
...page.margins.gutterTwips !== void 0 ? { gutter: twips(page.margins.gutterTwips) } : {}
|
|
5070
6136
|
},
|
|
6137
|
+
...value.properties.pageNumbers ? {
|
|
6138
|
+
pageNumberType: {
|
|
6139
|
+
...value.properties.pageNumbers.start !== void 0 ? { start: value.properties.pageNumbers.start } : {},
|
|
6140
|
+
...value.properties.pageNumbers.formatType ? {
|
|
6141
|
+
format: value.properties.pageNumbers.formatType
|
|
6142
|
+
} : {}
|
|
6143
|
+
}
|
|
6144
|
+
} : {},
|
|
6145
|
+
...value.properties.borders ? {
|
|
6146
|
+
pageBorders: {
|
|
6147
|
+
...value.properties.borders.display ? {
|
|
6148
|
+
display: value.properties.borders.display
|
|
6149
|
+
} : {},
|
|
6150
|
+
...value.properties.borders.offsetFrom ? {
|
|
6151
|
+
offsetFrom: value.properties.borders.offsetFrom
|
|
6152
|
+
} : {},
|
|
6153
|
+
...value.properties.borders.borders ? borders2(value.properties.borders.borders) : {}
|
|
6154
|
+
}
|
|
6155
|
+
} : {},
|
|
5071
6156
|
...columns ? {
|
|
5072
|
-
|
|
6157
|
+
columns: {
|
|
5073
6158
|
count: columns.count,
|
|
5074
6159
|
...columns.spaceTwips !== void 0 ? { space: twips(columns.spaceTwips) } : {},
|
|
5075
6160
|
...columns.separator !== void 0 ? { separate: columns.separator } : {},
|
|
@@ -5113,6 +6198,8 @@ function sectionChildren2(value, ctx, closesDocument = false) {
|
|
|
5113
6198
|
spacing: { before: 0, after: 0, line: 20, lineRule: "exact" }
|
|
5114
6199
|
}
|
|
5115
6200
|
});
|
|
6201
|
+
if (!closesDocument && !bookmark?.closes && last?.kind === "toc")
|
|
6202
|
+
blocks.push({ paragraph: { children: [] } });
|
|
5116
6203
|
if (!bookmark) return blocks;
|
|
5117
6204
|
return [
|
|
5118
6205
|
...bookmark.opens ? [{ bookmarkStart: { id: bookmark.id, name: bookmark.name } }] : [],
|
|
@@ -5123,15 +6210,19 @@ function sectionChildren2(value, ctx, closesDocument = false) {
|
|
|
5123
6210
|
function numberingConfig2(numbering) {
|
|
5124
6211
|
return {
|
|
5125
6212
|
reference: numbering.reference,
|
|
5126
|
-
levels: numbering.levels.map(
|
|
5127
|
-
level
|
|
5128
|
-
|
|
5129
|
-
|
|
5130
|
-
|
|
5131
|
-
|
|
5132
|
-
|
|
5133
|
-
|
|
5134
|
-
|
|
6213
|
+
levels: numbering.levels.map(
|
|
6214
|
+
(level) => ({
|
|
6215
|
+
level: level.level,
|
|
6216
|
+
format: level.format,
|
|
6217
|
+
text: level.text,
|
|
6218
|
+
...level.alignment ? { alignment: alignment(level.alignment) } : {},
|
|
6219
|
+
...level.suffix ? { suffix: level.suffix } : {},
|
|
6220
|
+
// Always stated. docx.js writes `w:start w:val="1"` for a level that
|
|
6221
|
+
// names none, and so did this backend until 0.14, which writes no
|
|
6222
|
+
// `w:start` at all when it is not given one; Word and LibreOffice then
|
|
6223
|
+
// count every such list from 0.
|
|
6224
|
+
start: level.start ?? 1,
|
|
6225
|
+
...level.paragraphStyleId ? { paragraphStyle: level.paragraphStyleId } : {},
|
|
5135
6226
|
...level.indent ? {
|
|
5136
6227
|
paragraph: {
|
|
5137
6228
|
indent: {
|
|
@@ -5141,25 +6232,22 @@ function numberingConfig2(numbering) {
|
|
|
5141
6232
|
}
|
|
5142
6233
|
} : {},
|
|
5143
6234
|
...level.run ? { run: runProperties2(level.run) } : {}
|
|
5144
|
-
}
|
|
5145
|
-
|
|
6235
|
+
})
|
|
6236
|
+
)
|
|
5146
6237
|
};
|
|
5147
6238
|
}
|
|
5148
|
-
var
|
|
6239
|
+
var BODY_ANCHOR;
|
|
5149
6240
|
var init_emit2 = __esm({
|
|
5150
6241
|
"src/renderers/office-open/emit.ts"() {
|
|
5151
6242
|
"use strict";
|
|
5152
6243
|
init_units();
|
|
5153
|
-
|
|
5154
|
-
|
|
5155
|
-
|
|
5156
|
-
tight: 2,
|
|
5157
|
-
topAndBottom: 3
|
|
5158
|
-
};
|
|
6244
|
+
init_chartWorkbook();
|
|
6245
|
+
init_chartLook();
|
|
6246
|
+
init_chartParts();
|
|
5159
6247
|
BODY_ANCHOR = {
|
|
5160
|
-
top: "
|
|
5161
|
-
middle: "
|
|
5162
|
-
bottom: "
|
|
6248
|
+
top: "top",
|
|
6249
|
+
middle: "center",
|
|
6250
|
+
bottom: "bottom"
|
|
5163
6251
|
};
|
|
5164
6252
|
}
|
|
5165
6253
|
});
|
|
@@ -5219,37 +6307,49 @@ var init_styles3 = __esm({
|
|
|
5219
6307
|
var office_open_exports = {};
|
|
5220
6308
|
__export(office_open_exports, {
|
|
5221
6309
|
OFFICE_OPEN_DOCX_RENDERER_ID: () => OFFICE_OPEN_DOCX_RENDERER_ID,
|
|
6310
|
+
OFFICE_OPEN_VERSION: () => OFFICE_OPEN_VERSION,
|
|
5222
6311
|
buildDocumentOptions: () => buildDocumentOptions,
|
|
5223
6312
|
createOfficeOpenDocxRenderer: () => createOfficeOpenDocxRenderer
|
|
5224
6313
|
});
|
|
5225
|
-
import
|
|
6314
|
+
import AdmZip5 from "adm-zip";
|
|
6315
|
+
import {
|
|
6316
|
+
assertBackendVersion,
|
|
6317
|
+
installedPackageVersion
|
|
6318
|
+
} from "@json-to-office/shared/rendering/node";
|
|
6319
|
+
function installedBackendVersion() {
|
|
6320
|
+
let resolved;
|
|
6321
|
+
try {
|
|
6322
|
+
resolved = import.meta.resolve?.(OFFICE_OPEN_DOCX);
|
|
6323
|
+
} catch {
|
|
6324
|
+
resolved = void 0;
|
|
6325
|
+
}
|
|
6326
|
+
return installedPackageVersion(OFFICE_OPEN_DOCX, import.meta.url, resolved);
|
|
6327
|
+
}
|
|
5226
6328
|
async function createOfficeOpenDocxRenderer() {
|
|
5227
6329
|
const backend = await import(
|
|
5228
6330
|
/* @vite-ignore */
|
|
5229
6331
|
OFFICE_OPEN_DOCX
|
|
5230
6332
|
);
|
|
5231
|
-
|
|
5232
|
-
|
|
5233
|
-
|
|
5234
|
-
|
|
5235
|
-
|
|
5236
|
-
|
|
5237
|
-
|
|
5238
|
-
);
|
|
5239
|
-
|
|
6333
|
+
assertBackendVersion(
|
|
6334
|
+
OFFICE_OPEN_DOCX,
|
|
6335
|
+
OFFICE_OPEN_VERSION,
|
|
6336
|
+
installedBackendVersion()
|
|
6337
|
+
);
|
|
6338
|
+
if (typeof backend.generateDocument !== "function") {
|
|
6339
|
+
throw new Error(
|
|
6340
|
+
`${OFFICE_OPEN_DOCX} does not export generateDocument(); the installed version is not compatible with this adapter.`
|
|
6341
|
+
);
|
|
5240
6342
|
}
|
|
5241
6343
|
return {
|
|
5242
6344
|
id: OFFICE_OPEN_DOCX_RENDERER_ID,
|
|
5243
6345
|
format: "docx",
|
|
5244
6346
|
capabilities: OFFICE_OPEN_CAPABILITIES,
|
|
5245
6347
|
async render(ir, options) {
|
|
5246
|
-
const
|
|
5247
|
-
const cellTocs = [];
|
|
6348
|
+
const charts2 = [];
|
|
5248
6349
|
const document = await buildDocumentOptions(
|
|
5249
6350
|
ir,
|
|
5250
|
-
|
|
5251
|
-
options?.svgRasterFallback
|
|
5252
|
-
cellTocs
|
|
6351
|
+
charts2,
|
|
6352
|
+
options?.svgRasterFallback
|
|
5253
6353
|
);
|
|
5254
6354
|
const bytes = await backend.generateDocument(document, {
|
|
5255
6355
|
type: "uint8array"
|
|
@@ -5257,10 +6357,10 @@ async function createOfficeOpenDocxRenderer() {
|
|
|
5257
6357
|
let raw = Buffer.from(
|
|
5258
6358
|
bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes)
|
|
5259
6359
|
);
|
|
5260
|
-
if (
|
|
5261
|
-
const zip = new
|
|
5262
|
-
|
|
5263
|
-
|
|
6360
|
+
if (ir.theme || charts2.length > 0) {
|
|
6361
|
+
const zip = new AdmZip5(raw);
|
|
6362
|
+
if (ir.theme) spliceTheme(zip, ir.theme);
|
|
6363
|
+
finishChartParts(zip, charts2);
|
|
5264
6364
|
raw = zip.toBuffer();
|
|
5265
6365
|
}
|
|
5266
6366
|
if (options?.deterministic === false)
|
|
@@ -5277,13 +6377,12 @@ async function createOfficeOpenDocxRenderer() {
|
|
|
5277
6377
|
}
|
|
5278
6378
|
};
|
|
5279
6379
|
}
|
|
5280
|
-
async function buildDocumentOptions(ir,
|
|
6380
|
+
async function buildDocumentOptions(ir, charts2 = [], svgRasterFallback) {
|
|
5281
6381
|
let nextDrawingId = 1;
|
|
5282
6382
|
const ctx = {
|
|
5283
6383
|
pictures: await prepareImages2(ir, svgRasterFallback),
|
|
5284
6384
|
nextDrawingId: () => nextDrawingId++,
|
|
5285
|
-
charts
|
|
5286
|
-
cellTocs
|
|
6385
|
+
charts: charts2
|
|
5287
6386
|
};
|
|
5288
6387
|
return {
|
|
5289
6388
|
styles: emitStyles2(ir.styles),
|
|
@@ -5291,16 +6390,20 @@ async function buildDocumentOptions(ir, charts = [], svgRasterFallback, cellTocs
|
|
|
5291
6390
|
(value, index) => section(value, ctx, index === ir.sections.length - 1)
|
|
5292
6391
|
),
|
|
5293
6392
|
...coreProperties2(ir),
|
|
5294
|
-
|
|
6393
|
+
settings: {
|
|
5295
6394
|
updateFields: ir.settings.updateFields,
|
|
5296
6395
|
...ir.settings.trackRevisions ? { trackRevisions: true } : {}
|
|
5297
6396
|
},
|
|
5298
|
-
...ir.numbering.length > 0 ? {
|
|
6397
|
+
...ir.numbering.length > 0 ? {
|
|
6398
|
+
numbering: {
|
|
6399
|
+
abstractNumberings: ir.numbering.map(numberingConfig2)
|
|
6400
|
+
}
|
|
6401
|
+
} : {},
|
|
5299
6402
|
...ir.footnotes.length > 0 ? { footnotes: noteBodies2(ir.footnotes, ctx) } : {},
|
|
5300
6403
|
...ir.endnotes.length > 0 ? { endnotes: noteBodies2(ir.endnotes, ctx) } : {},
|
|
5301
6404
|
...ir.comments.length > 0 ? {
|
|
5302
|
-
comments:
|
|
5303
|
-
|
|
6405
|
+
comments: ir.comments.map(
|
|
6406
|
+
(comment) => ({
|
|
5304
6407
|
id: comment.id,
|
|
5305
6408
|
author: comment.author,
|
|
5306
6409
|
...comment.initials ? { initials: comment.initials } : {},
|
|
@@ -5308,29 +6411,25 @@ async function buildDocumentOptions(ir, charts = [], svgRasterFallback, cellTocs
|
|
|
5308
6411
|
children: comment.children.map(
|
|
5309
6412
|
(child) => paragraphOf(child, ctx)
|
|
5310
6413
|
)
|
|
5311
|
-
})
|
|
5312
|
-
|
|
6414
|
+
})
|
|
6415
|
+
)
|
|
5313
6416
|
} : {}
|
|
5314
6417
|
};
|
|
5315
6418
|
}
|
|
5316
6419
|
function paragraphOf(value, ctx) {
|
|
5317
6420
|
const emitted = block(value, ctx);
|
|
5318
|
-
|
|
5319
|
-
if (!asParagraph) {
|
|
6421
|
+
if (!("paragraph" in emitted) || typeof emitted.paragraph === "string") {
|
|
5320
6422
|
throw new Error(
|
|
5321
6423
|
`the office-open renderer expected a paragraph, not a "${value.kind}"`
|
|
5322
6424
|
);
|
|
5323
6425
|
}
|
|
5324
|
-
return
|
|
6426
|
+
return emitted.paragraph;
|
|
5325
6427
|
}
|
|
5326
6428
|
function noteBodies2(notes, ctx) {
|
|
5327
|
-
|
|
5328
|
-
|
|
5329
|
-
|
|
5330
|
-
|
|
5331
|
-
};
|
|
5332
|
-
}
|
|
5333
|
-
return bodies;
|
|
6429
|
+
return notes.map((note) => ({
|
|
6430
|
+
id: note.id,
|
|
6431
|
+
children: note.children.map((child) => paragraphOf(child, ctx))
|
|
6432
|
+
}));
|
|
5334
6433
|
}
|
|
5335
6434
|
async function prepareImages2(ir, svgRasterFallback) {
|
|
5336
6435
|
const placements = collectImagePlacements2(ir);
|
|
@@ -5353,23 +6452,16 @@ async function prepareImages2(ir, svgRasterFallback) {
|
|
|
5353
6452
|
if (resource.kind !== "image") continue;
|
|
5354
6453
|
const type = resource.mediaType;
|
|
5355
6454
|
const data = Buffer.from(resource.bytes);
|
|
5356
|
-
const placementData = /* @__PURE__ */ new Map();
|
|
5357
|
-
[...placements.get(resource.id) ?? []].forEach((size, index) => {
|
|
5358
|
-
placementData.set(
|
|
5359
|
-
size,
|
|
5360
|
-
index === 0 ? data : distinguishImageBytes(data, type, size)
|
|
5361
|
-
);
|
|
5362
|
-
});
|
|
5363
6455
|
resources.set(resource.id, (placement) => {
|
|
5364
6456
|
const sizeKey = placementKey(placement);
|
|
5365
6457
|
const stem = `${resource.id}-${sizeKey}`;
|
|
5366
6458
|
return {
|
|
5367
6459
|
type,
|
|
5368
|
-
//
|
|
5369
|
-
//
|
|
5370
|
-
//
|
|
5371
|
-
//
|
|
5372
|
-
data
|
|
6460
|
+
// The same bytes at every size: the backend keeps each drawing's
|
|
6461
|
+
// extent on the drawing. 0.11 kept it on its deduplicated media
|
|
6462
|
+
// entry, and an image drawn at a second size took the first one's,
|
|
6463
|
+
// unless its bytes were told apart.
|
|
6464
|
+
data,
|
|
5373
6465
|
// Named after the resource and the size it is drawn at, so two
|
|
5374
6466
|
// placements of one image at one size share a single part and a third
|
|
5375
6467
|
// at another size gets its own.
|
|
@@ -5392,104 +6484,6 @@ async function prepareImages2(ir, svgRasterFallback) {
|
|
|
5392
6484
|
function placementKey(placement) {
|
|
5393
6485
|
return `${emuToPixels(placement.widthEmu)}x${emuToPixels(placement.heightEmu)}`;
|
|
5394
6486
|
}
|
|
5395
|
-
function distinguishImageBytes(data, mediaType, placement) {
|
|
5396
|
-
const marker = Buffer.from(`json-to-office:${placement}`, "utf8");
|
|
5397
|
-
switch (mediaType) {
|
|
5398
|
-
case "png":
|
|
5399
|
-
return addPngTextChunk(data, marker);
|
|
5400
|
-
case "jpg":
|
|
5401
|
-
return addJpegComment(data, marker);
|
|
5402
|
-
case "gif":
|
|
5403
|
-
return addGifComment(data, marker);
|
|
5404
|
-
case "svg":
|
|
5405
|
-
return Buffer.concat([
|
|
5406
|
-
data,
|
|
5407
|
-
Buffer.from(`
|
|
5408
|
-
<!-- ${marker.toString("utf8")} -->`, "utf8")
|
|
5409
|
-
]);
|
|
5410
|
-
case "bmp": {
|
|
5411
|
-
const marked = Buffer.concat([data, marker]);
|
|
5412
|
-
if (marked.length >= 14 && marked.subarray(0, 2).toString("ascii") === "BM") {
|
|
5413
|
-
marked.writeUInt32LE(marked.length, 2);
|
|
5414
|
-
}
|
|
5415
|
-
return marked;
|
|
5416
|
-
}
|
|
5417
|
-
default:
|
|
5418
|
-
return Buffer.concat([data, marker]);
|
|
5419
|
-
}
|
|
5420
|
-
}
|
|
5421
|
-
function addPngTextChunk(data, marker) {
|
|
5422
|
-
const signature = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]);
|
|
5423
|
-
if (data.length < 8 || !data.subarray(0, 8).equals(signature)) {
|
|
5424
|
-
return Buffer.concat([data, marker]);
|
|
5425
|
-
}
|
|
5426
|
-
let offset = 8;
|
|
5427
|
-
while (offset + 12 <= data.length) {
|
|
5428
|
-
const payloadLength = data.readUInt32BE(offset);
|
|
5429
|
-
const chunkEnd = offset + 12 + payloadLength;
|
|
5430
|
-
if (chunkEnd > data.length) break;
|
|
5431
|
-
if (data.subarray(offset + 4, offset + 8).toString("ascii") === "IEND") {
|
|
5432
|
-
const payload = Buffer.concat([
|
|
5433
|
-
Buffer.from("json-to-office\0", "latin1"),
|
|
5434
|
-
marker
|
|
5435
|
-
]);
|
|
5436
|
-
const chunk = Buffer.alloc(12 + payload.length);
|
|
5437
|
-
chunk.writeUInt32BE(payload.length, 0);
|
|
5438
|
-
chunk.write("tEXt", 4, 4, "ascii");
|
|
5439
|
-
payload.copy(chunk, 8);
|
|
5440
|
-
chunk.writeUInt32BE(
|
|
5441
|
-
crc32(chunk.subarray(4, 8 + payload.length)),
|
|
5442
|
-
8 + payload.length
|
|
5443
|
-
);
|
|
5444
|
-
return Buffer.concat([
|
|
5445
|
-
data.subarray(0, offset),
|
|
5446
|
-
chunk,
|
|
5447
|
-
data.subarray(offset)
|
|
5448
|
-
]);
|
|
5449
|
-
}
|
|
5450
|
-
offset = chunkEnd;
|
|
5451
|
-
}
|
|
5452
|
-
throw new Error(
|
|
5453
|
-
"Cannot mark a PNG that has no intact IEND chunk; its bytes were not checked to decode before rendering"
|
|
5454
|
-
);
|
|
5455
|
-
}
|
|
5456
|
-
function addJpegComment(data, marker) {
|
|
5457
|
-
if (data.length < 2 || data[0] !== 255 || data[1] !== 216) {
|
|
5458
|
-
return Buffer.concat([data, marker]);
|
|
5459
|
-
}
|
|
5460
|
-
const comment = Buffer.alloc(4 + marker.length);
|
|
5461
|
-
comment[0] = 255;
|
|
5462
|
-
comment[1] = 254;
|
|
5463
|
-
comment.writeUInt16BE(marker.length + 2, 2);
|
|
5464
|
-
marker.copy(comment, 4);
|
|
5465
|
-
return Buffer.concat([data.subarray(0, 2), comment, data.subarray(2)]);
|
|
5466
|
-
}
|
|
5467
|
-
function addGifComment(data, marker) {
|
|
5468
|
-
const trailer = data.lastIndexOf(59);
|
|
5469
|
-
if (trailer < 0 || marker.length > 255) {
|
|
5470
|
-
return Buffer.concat([data, marker]);
|
|
5471
|
-
}
|
|
5472
|
-
const comment = Buffer.concat([
|
|
5473
|
-
Buffer.from([33, 254, marker.length]),
|
|
5474
|
-
marker,
|
|
5475
|
-
Buffer.from([0])
|
|
5476
|
-
]);
|
|
5477
|
-
return Buffer.concat([
|
|
5478
|
-
data.subarray(0, trailer),
|
|
5479
|
-
comment,
|
|
5480
|
-
data.subarray(trailer)
|
|
5481
|
-
]);
|
|
5482
|
-
}
|
|
5483
|
-
function crc32(data) {
|
|
5484
|
-
let crc = 4294967295;
|
|
5485
|
-
for (const byte of data) {
|
|
5486
|
-
crc ^= byte;
|
|
5487
|
-
for (let bit = 0; bit < 8; bit += 1) {
|
|
5488
|
-
crc = crc >>> 1 ^ (crc & 1 ? 3988292384 : 0);
|
|
5489
|
-
}
|
|
5490
|
-
}
|
|
5491
|
-
return (crc ^ 4294967295) >>> 0;
|
|
5492
|
-
}
|
|
5493
6487
|
function collectImagePlacements2(ir) {
|
|
5494
6488
|
const placements = /* @__PURE__ */ new Map();
|
|
5495
6489
|
const record = (resourceId, placement) => {
|
|
@@ -5557,18 +6551,19 @@ function coreProperties2(ir) {
|
|
|
5557
6551
|
...metadata.custom?.length ? { customProperties: metadata.custom } : {}
|
|
5558
6552
|
};
|
|
5559
6553
|
}
|
|
5560
|
-
var OFFICE_OPEN_DOCX_RENDERER_ID, OFFICE_OPEN_DOCX, OFFICE_OPEN_CAPABILITIES;
|
|
6554
|
+
var OFFICE_OPEN_DOCX_RENDERER_ID, OFFICE_OPEN_DOCX, OFFICE_OPEN_VERSION, OFFICE_OPEN_CAPABILITIES;
|
|
5561
6555
|
var init_office_open = __esm({
|
|
5562
6556
|
"src/renderers/office-open/index.ts"() {
|
|
5563
6557
|
"use strict";
|
|
5564
6558
|
init_chartParts();
|
|
5565
|
-
|
|
6559
|
+
init_themePart();
|
|
5566
6560
|
init_imageUtils();
|
|
5567
6561
|
init_packageDocument();
|
|
5568
6562
|
init_emit2();
|
|
5569
6563
|
init_styles3();
|
|
5570
6564
|
OFFICE_OPEN_DOCX_RENDERER_ID = "office-open";
|
|
5571
6565
|
OFFICE_OPEN_DOCX = "@office-open/docx";
|
|
6566
|
+
OFFICE_OPEN_VERSION = "0.14.6";
|
|
5572
6567
|
OFFICE_OPEN_CAPABILITIES = /* @__PURE__ */ new Set([
|
|
5573
6568
|
"paragraphs",
|
|
5574
6569
|
"styles",
|
|
@@ -9484,6 +10479,7 @@ function emptyToUndefined(formatting) {
|
|
|
9484
10479
|
}
|
|
9485
10480
|
|
|
9486
10481
|
// src/ir/compiler.ts
|
|
10482
|
+
init_chartValues();
|
|
9487
10483
|
init_types();
|
|
9488
10484
|
|
|
9489
10485
|
// src/ir/measure.ts
|
|
@@ -9516,6 +10512,49 @@ function tableWidthTwips(width, measureTwips) {
|
|
|
9516
10512
|
|
|
9517
10513
|
// src/ir/compiler.ts
|
|
9518
10514
|
init_units();
|
|
10515
|
+
|
|
10516
|
+
// src/ir/theme.ts
|
|
10517
|
+
init_colorUtils();
|
|
10518
|
+
init_styleHelpers();
|
|
10519
|
+
init_types();
|
|
10520
|
+
var THEME_COLOR_TOKENS = [
|
|
10521
|
+
["dark1", "text"],
|
|
10522
|
+
["light1", "background"],
|
|
10523
|
+
["dark2", "textSecondary"],
|
|
10524
|
+
["light2", "backgroundSecondary"],
|
|
10525
|
+
["accent1", "primary"],
|
|
10526
|
+
["accent2", "secondary"],
|
|
10527
|
+
["accent3", "accent"],
|
|
10528
|
+
["accent4", "accent4"],
|
|
10529
|
+
["accent5", "accent5"],
|
|
10530
|
+
["accent6", "accent6"]
|
|
10531
|
+
];
|
|
10532
|
+
var NOT_XML_CHARS = new RegExp(NOT_XML_CHAR.source, "gu");
|
|
10533
|
+
var xmlText = (value) => (value ?? "").replace(NOT_XML_CHARS, "").trim();
|
|
10534
|
+
function compileTheme(theme, themeName) {
|
|
10535
|
+
const colors = {};
|
|
10536
|
+
for (const [slot, token] of THEME_COLOR_TOKENS) {
|
|
10537
|
+
const hex = schemeHex(token, theme);
|
|
10538
|
+
if (hex) colors[slot] = { hex };
|
|
10539
|
+
}
|
|
10540
|
+
const headingFont = xmlText(resolveFontFamily(theme, "heading"));
|
|
10541
|
+
const bodyFont = xmlText(resolveFontFamily(theme, "body"));
|
|
10542
|
+
return {
|
|
10543
|
+
name: xmlText(theme.name) || xmlText(themeName) || "Office Theme",
|
|
10544
|
+
colors,
|
|
10545
|
+
...headingFont ? { headingFont } : {},
|
|
10546
|
+
...bodyFont ? { bodyFont } : {}
|
|
10547
|
+
};
|
|
10548
|
+
}
|
|
10549
|
+
function schemeHex(token, theme) {
|
|
10550
|
+
try {
|
|
10551
|
+
return resolveColor(token, theme);
|
|
10552
|
+
} catch {
|
|
10553
|
+
return void 0;
|
|
10554
|
+
}
|
|
10555
|
+
}
|
|
10556
|
+
|
|
10557
|
+
// src/ir/compiler.ts
|
|
9519
10558
|
var CONTENT_BOOKMARK_ID_BASE = 2e6;
|
|
9520
10559
|
var SINGLE_LINE_TWIPS = 240;
|
|
9521
10560
|
function compileDocument(structure, layout, warnings = [], images = /* @__PURE__ */ new Map(), options = {}) {
|
|
@@ -9581,6 +10620,7 @@ function compileDocument(structure, layout, warnings = [], images = /* @__PURE__
|
|
|
9581
10620
|
trackRevisions: structure.trackRevisions === true,
|
|
9582
10621
|
...noProofWords(structure.theme) ? { noProofWords: noProofWords(structure.theme) } : {}
|
|
9583
10622
|
},
|
|
10623
|
+
theme: compileTheme(structure.theme, structure.themeName),
|
|
9584
10624
|
// The statistic styles are appended rather than built with the rest: a
|
|
9585
10625
|
// document that uses no statistic must keep the exact style set it had
|
|
9586
10626
|
// before the component had styles, or every recorded golden moves for a
|
|
@@ -10349,14 +11389,6 @@ function compileShape2(props, children, scope) {
|
|
|
10349
11389
|
);
|
|
10350
11390
|
}
|
|
10351
11391
|
const fill = style?.shading?.fill;
|
|
10352
|
-
const dropOutline = Boolean(fill) && Boolean(outline.outline);
|
|
10353
|
-
if (dropOutline) {
|
|
10354
|
-
warnOnce(
|
|
10355
|
-
ctx,
|
|
10356
|
-
"text-box",
|
|
10357
|
-
'[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.'
|
|
10358
|
-
);
|
|
10359
|
-
}
|
|
10360
11392
|
ctx.features.require("text-boxes", path3);
|
|
10361
11393
|
if (props.floating) ctx.features.require("floating-images", path3);
|
|
10362
11394
|
const insets = shapeInsets(
|
|
@@ -10375,7 +11407,7 @@ function compileShape2(props, children, scope) {
|
|
|
10375
11407
|
heightPx: height.pixels,
|
|
10376
11408
|
children,
|
|
10377
11409
|
...fill ? { fill: irColor(resolveColor(fill, ctx.theme)) } : {},
|
|
10378
|
-
...outline.outline
|
|
11410
|
+
...outline.outline ? { outline: outline.outline } : {},
|
|
10379
11411
|
...insets ? { insetsEmu: insets } : {},
|
|
10380
11412
|
...props.floating ? { floating: compileFloating(props.floating, ctx, path3) } : {}
|
|
10381
11413
|
}
|
|
@@ -11598,6 +12630,7 @@ function compileImage2(component, scope) {
|
|
|
11598
12630
|
}
|
|
11599
12631
|
var DEFAULT_CHART_HEIGHT_INCHES = 3;
|
|
11600
12632
|
var MAX_CHART_TEXT_POINTS = 10;
|
|
12633
|
+
var MIN_CHART_TEXT_POINTS = 1;
|
|
11601
12634
|
function chartTextFont(theme) {
|
|
11602
12635
|
const bodySize = getThemeFonts(theme).body?.size;
|
|
11603
12636
|
let color = "000000";
|
|
@@ -11607,9 +12640,12 @@ function chartTextFont(theme) {
|
|
|
11607
12640
|
}
|
|
11608
12641
|
return {
|
|
11609
12642
|
fontFamily: resolveFontFamily(theme, "body"),
|
|
11610
|
-
fontSize: Math.
|
|
11611
|
-
|
|
11612
|
-
|
|
12643
|
+
fontSize: Math.max(
|
|
12644
|
+
MIN_CHART_TEXT_POINTS,
|
|
12645
|
+
Math.min(
|
|
12646
|
+
typeof bodySize === "number" && bodySize > 0 ? bodySize : 11,
|
|
12647
|
+
MAX_CHART_TEXT_POINTS
|
|
12648
|
+
)
|
|
11613
12649
|
),
|
|
11614
12650
|
bold: false,
|
|
11615
12651
|
color
|
|
@@ -11620,7 +12656,7 @@ function compileChart(component, scope) {
|
|
|
11620
12656
|
const props = component.props ?? {};
|
|
11621
12657
|
if (props.type === "bubble") {
|
|
11622
12658
|
throw new Error(
|
|
11623
|
-
`Chart at ${path3} is a bubble chart,
|
|
12659
|
+
`Chart at ${path3} is a bubble chart, but the docx \`chart\` component has no bubble sizes; use the pptx \`chart\` component on the pptxgenjs renderer.`
|
|
11624
12660
|
);
|
|
11625
12661
|
}
|
|
11626
12662
|
const rawSeries = Array.isArray(props.data) ? props.data : [];
|
|
@@ -11642,10 +12678,22 @@ function compileChart(component, scope) {
|
|
|
11642
12678
|
`Chart series "${label}" at ${path3} has ${labels.length} labels and ${values.length} values; they must be the same length.`
|
|
11643
12679
|
);
|
|
11644
12680
|
}
|
|
12681
|
+
if (labels.length === 0) {
|
|
12682
|
+
throw new Error(
|
|
12683
|
+
`Chart series "${label}" at ${path3} has no data points; give it at least one label and value.`
|
|
12684
|
+
);
|
|
12685
|
+
}
|
|
12686
|
+
const numbers = values.map((value) => Number(value));
|
|
12687
|
+
const bad = numbers.findIndex((value) => !Number.isFinite(value));
|
|
12688
|
+
if (bad !== -1) {
|
|
12689
|
+
throw new Error(
|
|
12690
|
+
`Chart series "${label}" at ${path3} has a value that is not a finite number (${JSON.stringify(values[bad])} at "${String(labels[bad])}").`
|
|
12691
|
+
);
|
|
12692
|
+
}
|
|
11645
12693
|
return {
|
|
11646
12694
|
...typeof raw.name === "string" ? { name: raw.name } : {},
|
|
11647
12695
|
labels: labels.map((value) => String(value)),
|
|
11648
|
-
values:
|
|
12696
|
+
values: numbers
|
|
11649
12697
|
};
|
|
11650
12698
|
});
|
|
11651
12699
|
const categories = series[0].labels;
|
|
@@ -11657,6 +12705,44 @@ function compileChart(component, scope) {
|
|
|
11657
12705
|
);
|
|
11658
12706
|
}
|
|
11659
12707
|
}
|
|
12708
|
+
if (props.type === "pie" && series.length > 1) {
|
|
12709
|
+
throw new Error(
|
|
12710
|
+
`Chart at ${path3} 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.`
|
|
12711
|
+
);
|
|
12712
|
+
}
|
|
12713
|
+
if (props.type === "pie" || props.type === "doughnut") {
|
|
12714
|
+
for (const [index, entry] of series.entries()) {
|
|
12715
|
+
const at = entry.values.findIndex((value) => value < 0);
|
|
12716
|
+
if (at === -1) continue;
|
|
12717
|
+
throw new Error(
|
|
12718
|
+
`Chart series "${entry.name ?? `series ${index}`}" at ${path3} has a negative value (${entry.values[at]} at "${entry.labels[at]}"); a ${props.type} chart draws each value as a share of the whole.`
|
|
12719
|
+
);
|
|
12720
|
+
}
|
|
12721
|
+
}
|
|
12722
|
+
if (props.type === "scatter") {
|
|
12723
|
+
for (const [index, entry] of series.entries()) {
|
|
12724
|
+
const at = entry.labels.findIndex(isOutOfRangeNumericLabel);
|
|
12725
|
+
if (at !== -1) {
|
|
12726
|
+
throw new Error(
|
|
12727
|
+
`Chart series "${entry.name ?? `series ${index}`}" at ${path3} has an x label ${JSON.stringify(entry.labels[at])} outside the finite number range.`
|
|
12728
|
+
);
|
|
12729
|
+
}
|
|
12730
|
+
}
|
|
12731
|
+
}
|
|
12732
|
+
if (props.type === "scatter" && series.some((entry) => entry.labels.some((label) => !isNumericLabel(label)))) {
|
|
12733
|
+
warnOnce(
|
|
12734
|
+
ctx,
|
|
12735
|
+
"chart",
|
|
12736
|
+
`Chart at ${path3} 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.`
|
|
12737
|
+
);
|
|
12738
|
+
}
|
|
12739
|
+
if ((props.type === "pie" || props.type === "doughnut") && (typeof props.catAxisTitle === "string" || typeof props.valAxisTitle === "string")) {
|
|
12740
|
+
warnOnce(
|
|
12741
|
+
ctx,
|
|
12742
|
+
"chart",
|
|
12743
|
+
`Chart at ${path3} is a ${props.type} chart, which has no axes; its axis titles are not drawn.`
|
|
12744
|
+
);
|
|
12745
|
+
}
|
|
11660
12746
|
const colors = Array.isArray(props.chartColors) ? props.chartColors.map(
|
|
11661
12747
|
(color) => resolveColor(String(color), ctx.theme)
|
|
11662
12748
|
) : chartPaletteValues(ctx.theme).flatMap((value) => {
|
|
@@ -11669,13 +12755,21 @@ function compileChart(component, scope) {
|
|
|
11669
12755
|
const contentWidthInches = scope.measureTwips / 1440;
|
|
11670
12756
|
const widthInches = typeof props.width === "number" ? props.width : contentWidthInches;
|
|
11671
12757
|
const heightInches = typeof props.height === "number" ? props.height : DEFAULT_CHART_HEIGHT_INCHES;
|
|
12758
|
+
const widthEmu = inchesToEmu(widthInches);
|
|
12759
|
+
const heightEmu = inchesToEmu(heightInches);
|
|
12760
|
+
if (!(widthEmu > 0 && heightEmu > 0)) {
|
|
12761
|
+
const inches = (value) => String(Number.isFinite(value) ? Math.round(value * 100) / 100 : value);
|
|
12762
|
+
throw new Error(
|
|
12763
|
+
`Chart at ${path3} has no room: it would be ${inches(widthInches)}\xD7${inches(heightInches)} in. Set \`width\`/\`height\`, or give it a container with space.`
|
|
12764
|
+
);
|
|
12765
|
+
}
|
|
11672
12766
|
const chart = {
|
|
11673
12767
|
kind: "chart",
|
|
11674
12768
|
chartType: props.type,
|
|
11675
12769
|
series,
|
|
11676
12770
|
colors,
|
|
11677
|
-
widthEmu
|
|
11678
|
-
heightEmu
|
|
12771
|
+
widthEmu,
|
|
12772
|
+
heightEmu,
|
|
11679
12773
|
...typeof props.title === "string" ? { title: props.title } : {},
|
|
11680
12774
|
...props.showTitle !== void 0 ? { showTitle: props.showTitle } : {},
|
|
11681
12775
|
...props.showLegend !== void 0 ? { showLegend: props.showLegend } : {},
|
|
@@ -11878,7 +12972,7 @@ function compileFrame(floating, ctx, path3) {
|
|
|
11878
12972
|
function compileFloating(floating, ctx, path3) {
|
|
11879
12973
|
if (floating.wrap?.type === "tight") {
|
|
11880
12974
|
throw new Error(
|
|
11881
|
-
"Image floating wrap.type 'tight' is not supported
|
|
12975
|
+
"Image floating wrap.type 'tight' is not supported. Use 'square', 'topAndBottom', or 'none'."
|
|
11882
12976
|
);
|
|
11883
12977
|
}
|
|
11884
12978
|
const hRelative = floating.horizontalPosition?.relative;
|