@json-to-office/core-docx 2.3.0 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/highcharts.d.ts.map +1 -1
- package/dist/core/generationContext.d.ts.map +1 -1
- package/dist/index.js +653 -52
- package/dist/index.js.map +1 -1
- package/dist/ir/compiler.d.ts.map +1 -1
- package/dist/plugin/example/index.js +476 -61
- package/dist/plugin/example/index.js.map +1 -1
- package/dist/quality/facts.d.ts +56 -2
- package/dist/quality/facts.d.ts.map +1 -1
- package/dist/quality/rules.d.ts +16 -0
- package/dist/quality/rules.d.ts.map +1 -1
- package/dist/renderers/docxjs/emit.d.ts.map +1 -1
- package/dist/renderers/docxjs/index.d.ts.map +1 -1
- package/dist/renderers/office-open/index.d.ts.map +1 -1
- package/dist/styles/themeToStyles.d.ts.map +1 -1
- package/dist/styles/utils/colorUtils.d.ts +12 -1
- package/dist/styles/utils/colorUtils.d.ts.map +1 -1
- package/dist/styles/utils/styleHelpers.d.ts +2 -0
- package/dist/styles/utils/styleHelpers.d.ts.map +1 -1
- package/dist/templates/themes/index.d.ts +1896 -668
- package/dist/templates/themes/index.d.ts.map +1 -1
- package/dist/themes/defaults.d.ts +196 -181
- package/dist/themes/defaults.d.ts.map +1 -1
- package/dist/themes/design-system.d.ts +4 -0
- package/dist/themes/design-system.d.ts.map +1 -0
- package/dist/themes/overrides.d.ts +2 -1
- package/dist/themes/overrides.d.ts.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utils/normalizeTextCase.d.ts +15 -0
- package/dist/utils/normalizeTextCase.d.ts.map +1 -0
- package/dist/utils/packageDocument.d.ts +2 -0
- package/dist/utils/packageDocument.d.ts.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -15,8 +15,10 @@ var __export = (target, all) => {
|
|
|
15
15
|
};
|
|
16
16
|
|
|
17
17
|
// src/themes/defaults.ts
|
|
18
|
+
import { designColors } from "@json-to-office/shared";
|
|
18
19
|
function ensureThemeDefaults(theme) {
|
|
19
20
|
return {
|
|
21
|
+
...theme,
|
|
20
22
|
$schema: theme.$schema,
|
|
21
23
|
name: theme.name || "default",
|
|
22
24
|
displayName: theme.displayName || "Default Theme",
|
|
@@ -27,6 +29,7 @@ function ensureThemeDefaults(theme) {
|
|
|
27
29
|
...theme.colors || {}
|
|
28
30
|
},
|
|
29
31
|
fonts: {
|
|
32
|
+
...theme.fonts || {},
|
|
30
33
|
heading: { ...DEFAULT_FONTS.heading, ...theme.fonts?.heading || {} },
|
|
31
34
|
body: { ...DEFAULT_FONTS.body, ...theme.fonts?.body || {} },
|
|
32
35
|
mono: { ...DEFAULT_FONTS.mono, ...theme.fonts?.mono || {} },
|
|
@@ -45,10 +48,13 @@ function ensureThemeDefaults(theme) {
|
|
|
45
48
|
};
|
|
46
49
|
}
|
|
47
50
|
function getThemeColors(theme) {
|
|
48
|
-
return
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
51
|
+
return designColors(
|
|
52
|
+
{
|
|
53
|
+
...DEFAULT_COLORS,
|
|
54
|
+
...theme.colors || {}
|
|
55
|
+
},
|
|
56
|
+
theme.palette
|
|
57
|
+
);
|
|
52
58
|
}
|
|
53
59
|
function getThemeFonts(theme) {
|
|
54
60
|
return {
|
|
@@ -186,6 +192,10 @@ var init_defaults = __esm({
|
|
|
186
192
|
});
|
|
187
193
|
|
|
188
194
|
// src/styles/utils/colorUtils.ts
|
|
195
|
+
import {
|
|
196
|
+
DEFAULT_CHART_THEME_COLORS,
|
|
197
|
+
resolveDesignColor
|
|
198
|
+
} from "@json-to-office/shared";
|
|
189
199
|
function resolveColor(colorValue, theme) {
|
|
190
200
|
if (colorValue.startsWith("#")) {
|
|
191
201
|
const hexValue = colorValue.slice(1);
|
|
@@ -199,7 +209,11 @@ function resolveColor(colorValue, theme) {
|
|
|
199
209
|
const colors = getThemeColors(theme);
|
|
200
210
|
const resolvedColor = colors[colorValue];
|
|
201
211
|
if (typeof resolvedColor === "string") {
|
|
202
|
-
|
|
212
|
+
const hex = resolveDesignColor(colorValue, colors);
|
|
213
|
+
if (hex) return hex.toUpperCase();
|
|
214
|
+
throw new Error(
|
|
215
|
+
`Unresolvable theme color: "${colorValue}" (missing reference or cycle).`
|
|
216
|
+
);
|
|
203
217
|
}
|
|
204
218
|
if (/^[0-9A-Fa-f]{6}$/.test(colorValue)) {
|
|
205
219
|
return colorValue.toUpperCase();
|
|
@@ -208,6 +222,15 @@ function resolveColor(colorValue, theme) {
|
|
|
208
222
|
`Invalid color value: "${colorValue}". Must be a hex color with # prefix (e.g., "#000000") or a valid theme color name.`
|
|
209
223
|
);
|
|
210
224
|
}
|
|
225
|
+
function chartPaletteValues(theme) {
|
|
226
|
+
const explicit = theme.palette?.chart;
|
|
227
|
+
if (explicit) return [...explicit];
|
|
228
|
+
const colors = getThemeColors(theme);
|
|
229
|
+
return DEFAULT_CHART_THEME_COLORS.flatMap((token) => {
|
|
230
|
+
const value = colors[token];
|
|
231
|
+
return typeof value === "string" && value.length > 0 ? [value] : [];
|
|
232
|
+
});
|
|
233
|
+
}
|
|
211
234
|
var init_colorUtils = __esm({
|
|
212
235
|
"src/styles/utils/colorUtils.ts"() {
|
|
213
236
|
"use strict";
|
|
@@ -988,6 +1011,8 @@ function resolveFontProperties(theme, fontRef) {
|
|
|
988
1011
|
size: fontDef.size,
|
|
989
1012
|
color: fontDef.color,
|
|
990
1013
|
bold: fontDef.bold,
|
|
1014
|
+
fontWeight: fontDef.fontWeight,
|
|
1015
|
+
case: fontDef.case,
|
|
991
1016
|
italic: fontDef.italic,
|
|
992
1017
|
underline: fontDef.underline,
|
|
993
1018
|
alignment: fontDef.alignment,
|
|
@@ -2070,6 +2095,9 @@ function runOptions(formatting) {
|
|
|
2070
2095
|
options.underline = formatting.underline ? { type: formatting.underline.type } : void 0;
|
|
2071
2096
|
}
|
|
2072
2097
|
if (formatting.strike !== void 0) options.strike = formatting.strike;
|
|
2098
|
+
if (formatting.allCaps !== void 0) options.allCaps = formatting.allCaps;
|
|
2099
|
+
if (formatting.smallCaps !== void 0)
|
|
2100
|
+
options.smallCaps = formatting.smallCaps;
|
|
2073
2101
|
if (formatting.scalePercent !== void 0) {
|
|
2074
2102
|
options.scale = formatting.scalePercent;
|
|
2075
2103
|
}
|
|
@@ -2760,6 +2788,44 @@ var init_styles2 = __esm({
|
|
|
2760
2788
|
}
|
|
2761
2789
|
});
|
|
2762
2790
|
|
|
2791
|
+
// src/utils/normalizeTextCase.ts
|
|
2792
|
+
function normalizeTextCase(zip) {
|
|
2793
|
+
let changed = false;
|
|
2794
|
+
for (const entry of zip.getEntries()) {
|
|
2795
|
+
if (!WORD_XML.test(entry.entryName)) continue;
|
|
2796
|
+
const xml = entry.getData().toString("utf8");
|
|
2797
|
+
if (!ANY_CASE_FLAG.test(xml)) continue;
|
|
2798
|
+
const normalized = xml.replace(RUN_PROPERTIES, completeCaseFlags);
|
|
2799
|
+
if (normalized === xml) continue;
|
|
2800
|
+
zip.updateFile(entry, Buffer.from(normalized, "utf8"));
|
|
2801
|
+
changed = true;
|
|
2802
|
+
}
|
|
2803
|
+
return changed;
|
|
2804
|
+
}
|
|
2805
|
+
function completeCaseFlags(runProperties3) {
|
|
2806
|
+
const flag = CASE_FLAG.exec(runProperties3);
|
|
2807
|
+
if (!flag) return runProperties3;
|
|
2808
|
+
const isCaps = flag[1] === "caps";
|
|
2809
|
+
const opposite = `<w:${isCaps ? "smallCaps" : "caps"} w:val="false"/>`;
|
|
2810
|
+
if (runProperties3.includes(`<w:${isCaps ? "smallCaps" : "caps"}`)) {
|
|
2811
|
+
return runProperties3;
|
|
2812
|
+
}
|
|
2813
|
+
return runProperties3.replace(
|
|
2814
|
+
flag[0],
|
|
2815
|
+
isCaps ? `${flag[0]}${opposite}` : `${opposite}${flag[0]}`
|
|
2816
|
+
);
|
|
2817
|
+
}
|
|
2818
|
+
var WORD_XML, ANY_CASE_FLAG, RUN_PROPERTIES, CASE_FLAG;
|
|
2819
|
+
var init_normalizeTextCase = __esm({
|
|
2820
|
+
"src/utils/normalizeTextCase.ts"() {
|
|
2821
|
+
"use strict";
|
|
2822
|
+
WORD_XML = /^word\/.*\.xml$/;
|
|
2823
|
+
ANY_CASE_FLAG = /<w:(?:caps|smallCaps)\b/;
|
|
2824
|
+
RUN_PROPERTIES = /<w:rPr\b[^>]*>[\s\S]*?<\/w:rPr>/g;
|
|
2825
|
+
CASE_FLAG = /<w:(caps|smallCaps)\b[^>]*(?:\/>|>[\s\S]*?<\/w:\1>)/;
|
|
2826
|
+
}
|
|
2827
|
+
});
|
|
2828
|
+
|
|
2763
2829
|
// src/utils/packageDocument.ts
|
|
2764
2830
|
import AdmZip from "adm-zip";
|
|
2765
2831
|
function resolveGenerationDate(options) {
|
|
@@ -2828,6 +2894,7 @@ function canonicalizeRelationshipIds(zip) {
|
|
|
2828
2894
|
}
|
|
2829
2895
|
function canonicalizeDocxBuffer(buffer, generatedAt = DEFAULT_GENERATION_DATE) {
|
|
2830
2896
|
const zip = new AdmZip(buffer);
|
|
2897
|
+
normalizeTextCase(zip);
|
|
2831
2898
|
canonicalizeRelationshipIds(zip);
|
|
2832
2899
|
const isoTimestamp = generatedAt.toISOString();
|
|
2833
2900
|
const coreProperties3 = zip.getEntry("docProps/core.xml");
|
|
@@ -2844,10 +2911,15 @@ function canonicalizeDocxBuffer(buffer, generatedAt = DEFAULT_GENERATION_DATE) {
|
|
|
2844
2911
|
}
|
|
2845
2912
|
return zip.toBuffer();
|
|
2846
2913
|
}
|
|
2914
|
+
function normalizeDocxCaseBuffer(buffer) {
|
|
2915
|
+
const zip = new AdmZip(buffer);
|
|
2916
|
+
return normalizeTextCase(zip) ? zip.toBuffer() : buffer;
|
|
2917
|
+
}
|
|
2847
2918
|
var DEFAULT_GENERATION_DATE, STABLE_RELATIONSHIP_ID;
|
|
2848
2919
|
var init_packageDocument = __esm({
|
|
2849
2920
|
"src/utils/packageDocument.ts"() {
|
|
2850
2921
|
"use strict";
|
|
2922
|
+
init_normalizeTextCase();
|
|
2851
2923
|
DEFAULT_GENERATION_DATE = /* @__PURE__ */ new Date("2000-01-01T00:00:00.000Z");
|
|
2852
2924
|
STABLE_RELATIONSHIP_ID = /^rId\d+$/;
|
|
2853
2925
|
}
|
|
@@ -2906,7 +2978,8 @@ function createDocxJsRenderer() {
|
|
|
2906
2978
|
const document = buildDocument(ir, resources);
|
|
2907
2979
|
const packed = await Packer.toBuffer(document);
|
|
2908
2980
|
const fixed = fixFloatingImageIdsInBuffer(packed);
|
|
2909
|
-
if (renderOptions?.deterministic === false)
|
|
2981
|
+
if (renderOptions?.deterministic === false)
|
|
2982
|
+
return new Uint8Array(normalizeDocxCaseBuffer(fixed));
|
|
2910
2983
|
return new Uint8Array(
|
|
2911
2984
|
canonicalizeDocxBuffer(
|
|
2912
2985
|
fixed,
|
|
@@ -4185,7 +4258,8 @@ async function createOfficeOpenDocxRenderer() {
|
|
|
4185
4258
|
spliceChartParts(zip, charts);
|
|
4186
4259
|
raw = zip.toBuffer();
|
|
4187
4260
|
}
|
|
4188
|
-
if (options?.deterministic === false)
|
|
4261
|
+
if (options?.deterministic === false)
|
|
4262
|
+
return new Uint8Array(normalizeDocxCaseBuffer(raw));
|
|
4189
4263
|
return new Uint8Array(
|
|
4190
4264
|
canonicalizeDocxBuffer(
|
|
4191
4265
|
raw,
|
|
@@ -5043,7 +5117,6 @@ import {
|
|
|
5043
5117
|
|
|
5044
5118
|
// src/components/highcharts.ts
|
|
5045
5119
|
init_colorUtils();
|
|
5046
|
-
import { DEFAULT_CHART_THEME_COLORS } from "@json-to-office/shared";
|
|
5047
5120
|
var DEFAULT_EXPORT_SERVER_URL = "http://localhost:7801";
|
|
5048
5121
|
async function generateChart(config, servicesConfig) {
|
|
5049
5122
|
if (!isNodeEnvironment()) {
|
|
@@ -5097,11 +5170,10 @@ function toChartColor(value, theme) {
|
|
|
5097
5170
|
function withThemeColors(config, theme) {
|
|
5098
5171
|
const options = config.options;
|
|
5099
5172
|
if (!options || options.colors || !theme?.colors) return config;
|
|
5100
|
-
const
|
|
5101
|
-
|
|
5102
|
-
|
|
5103
|
-
|
|
5104
|
-
}).filter((c) => c !== void 0);
|
|
5173
|
+
const palette = chartPaletteValues(theme).flatMap((value) => {
|
|
5174
|
+
const color = toChartColor(value, theme);
|
|
5175
|
+
return color ? [color] : [];
|
|
5176
|
+
});
|
|
5105
5177
|
if (palette.length === 0) return config;
|
|
5106
5178
|
return {
|
|
5107
5179
|
...config,
|
|
@@ -5347,10 +5419,7 @@ init_colorUtils();
|
|
|
5347
5419
|
import {
|
|
5348
5420
|
FeatureRequirementCollector
|
|
5349
5421
|
} from "@json-to-office/shared/rendering";
|
|
5350
|
-
import {
|
|
5351
|
-
synthesizeFamilyName,
|
|
5352
|
-
DEFAULT_CHART_THEME_COLORS as DEFAULT_CHART_THEME_COLORS2
|
|
5353
|
-
} from "@json-to-office/shared";
|
|
5422
|
+
import { capsFormatting as capsFormatting2, synthesizeFamilyName as synthesizeFamilyName2 } from "@json-to-office/shared";
|
|
5354
5423
|
import {
|
|
5355
5424
|
isNativeVisualProps as isNativeVisualProps4
|
|
5356
5425
|
} from "@json-to-office/shared-docx";
|
|
@@ -5866,6 +5935,7 @@ function resolveColors(entries, at, deps) {
|
|
|
5866
5935
|
init_themes();
|
|
5867
5936
|
init_colorUtils();
|
|
5868
5937
|
init_styleHelpers();
|
|
5938
|
+
import { capsFormatting, synthesizeFamilyName } from "@json-to-office/shared";
|
|
5869
5939
|
var RIGHT_MARGIN_TAB_TWIPS = 9026 * 2;
|
|
5870
5940
|
var STATISTIC_NUMBER_STYLE_ID = "StatisticNumber";
|
|
5871
5941
|
var STATISTIC_DESCRIPTION_STYLE_ID = "StatisticDescription";
|
|
@@ -5874,25 +5944,8 @@ var STATISTIC_SIZE_POINTS = {
|
|
|
5874
5944
|
medium: 28,
|
|
5875
5945
|
large: 40
|
|
5876
5946
|
};
|
|
5877
|
-
function isValidStyleName(name) {
|
|
5878
|
-
return [
|
|
5879
|
-
"normal",
|
|
5880
|
-
"heading1",
|
|
5881
|
-
"heading2",
|
|
5882
|
-
"heading3",
|
|
5883
|
-
"heading4",
|
|
5884
|
-
"heading5",
|
|
5885
|
-
"heading6",
|
|
5886
|
-
"title",
|
|
5887
|
-
"subtitle"
|
|
5888
|
-
].includes(name);
|
|
5889
|
-
}
|
|
5890
5947
|
function getStyleSafe(theme, styleName) {
|
|
5891
|
-
|
|
5892
|
-
console.warn(`Invalid style name: ${styleName}`);
|
|
5893
|
-
return void 0;
|
|
5894
|
-
}
|
|
5895
|
-
return theme.styles?.[styleName];
|
|
5948
|
+
return theme.styles && Object.hasOwn(theme.styles, styleName) ? theme.styles[styleName] : void 0;
|
|
5896
5949
|
}
|
|
5897
5950
|
function resolveStyleWithBaseStyle(theme, styleName, visited = /* @__PURE__ */ new Set()) {
|
|
5898
5951
|
if (visited.has(styleName)) {
|
|
@@ -5949,9 +6002,17 @@ function resolveSpacing(spacing) {
|
|
|
5949
6002
|
...spacing?.after ? { afterTwips: pointsToTwips(spacing.after) } : {}
|
|
5950
6003
|
};
|
|
5951
6004
|
}
|
|
6005
|
+
function weightedFamily(props) {
|
|
6006
|
+
return props.fontWeight === void 0 ? void 0 : synthesizeFamilyName(
|
|
6007
|
+
props.family || "Arial",
|
|
6008
|
+
props.fontWeight,
|
|
6009
|
+
props.italic === true
|
|
6010
|
+
);
|
|
6011
|
+
}
|
|
5952
6012
|
function convertRunProperties(merged, theme, defaultColor, defaultSize) {
|
|
6013
|
+
const weighted = weightedFamily(merged);
|
|
5953
6014
|
return {
|
|
5954
|
-
fontFamily: merged.family
|
|
6015
|
+
fontFamily: weighted?.family ?? merged.family ?? "Arial",
|
|
5955
6016
|
sizeHalfPoints: (merged.size || defaultSize || 11) * 2,
|
|
5956
6017
|
color: {
|
|
5957
6018
|
hex: resolveColor(
|
|
@@ -5961,6 +6022,8 @@ function convertRunProperties(merged, theme, defaultColor, defaultSize) {
|
|
|
5961
6022
|
},
|
|
5962
6023
|
...merged.bold !== void 0 && { bold: merged.bold },
|
|
5963
6024
|
...merged.italic !== void 0 && { italic: merged.italic },
|
|
6025
|
+
...weighted && { bold: weighted.bold, italic: weighted.italic },
|
|
6026
|
+
...merged.case !== void 0 && capsFormatting(merged.case),
|
|
5964
6027
|
...merged.underline !== void 0 && merged.underline && { underline: { type: "single" } },
|
|
5965
6028
|
...merged.characterSpacing && {
|
|
5966
6029
|
characterSpacingTwentieths: merged.characterSpacing.type === "condensed" ? -merged.characterSpacing.value : merged.characterSpacing.value
|
|
@@ -6033,12 +6096,15 @@ function convertBorders(borders3, theme) {
|
|
|
6033
6096
|
return Object.keys(converted).length > 0 ? converted : void 0;
|
|
6034
6097
|
}
|
|
6035
6098
|
function fallbackRun(fontProps, theme, defaultColor, defaultSize) {
|
|
6099
|
+
const weighted = weightedFamily(fontProps);
|
|
6036
6100
|
return {
|
|
6037
|
-
fontFamily: fontProps.family
|
|
6101
|
+
fontFamily: weighted?.family ?? fontProps.family ?? "Arial",
|
|
6038
6102
|
sizeHalfPoints: (fontProps.size || defaultSize) * 2,
|
|
6039
6103
|
color: { hex: resolveColor(fontProps.color || defaultColor, theme) },
|
|
6040
6104
|
...fontProps.bold !== void 0 && { bold: fontProps.bold },
|
|
6041
6105
|
...fontProps.italic !== void 0 && { italic: fontProps.italic },
|
|
6106
|
+
...weighted && { bold: weighted.bold, italic: weighted.italic },
|
|
6107
|
+
...fontProps.case !== void 0 && capsFormatting(fontProps.case),
|
|
6042
6108
|
...fontProps.underline !== void 0 && fontProps.underline && { underline: { type: "single" } }
|
|
6043
6109
|
};
|
|
6044
6110
|
}
|
|
@@ -6068,6 +6134,8 @@ function createDocumentStyles(themeNameOrObject = "minimal", language) {
|
|
|
6068
6134
|
size: normalStyle?.size,
|
|
6069
6135
|
color: normalStyle?.color,
|
|
6070
6136
|
bold: normalStyle?.bold,
|
|
6137
|
+
fontWeight: normalStyle?.fontWeight,
|
|
6138
|
+
case: normalStyle?.case,
|
|
6071
6139
|
italic: normalStyle?.italic,
|
|
6072
6140
|
underline: normalStyle?.underline,
|
|
6073
6141
|
characterSpacing: normalStyle?.characterSpacing,
|
|
@@ -6107,6 +6175,8 @@ function createDocumentStyles(themeNameOrObject = "minimal", language) {
|
|
|
6107
6175
|
size: headingStyle.size,
|
|
6108
6176
|
color: headingStyle.color,
|
|
6109
6177
|
bold: headingStyle.bold,
|
|
6178
|
+
fontWeight: headingStyle.fontWeight,
|
|
6179
|
+
case: headingStyle.case,
|
|
6110
6180
|
italic: headingStyle.italic,
|
|
6111
6181
|
underline: headingStyle.underline,
|
|
6112
6182
|
characterSpacing: headingStyle.characterSpacing,
|
|
@@ -6167,6 +6237,8 @@ function createDocumentStyles(themeNameOrObject = "minimal", language) {
|
|
|
6167
6237
|
size: headingStyle.size,
|
|
6168
6238
|
color: headingStyle.color,
|
|
6169
6239
|
bold: headingStyle.bold,
|
|
6240
|
+
fontWeight: headingStyle.fontWeight,
|
|
6241
|
+
case: headingStyle.case,
|
|
6170
6242
|
italic: headingStyle.italic,
|
|
6171
6243
|
underline: headingStyle.underline,
|
|
6172
6244
|
characterSpacing: headingStyle.characterSpacing,
|
|
@@ -6228,6 +6300,8 @@ function createDocumentStyles(themeNameOrObject = "minimal", language) {
|
|
|
6228
6300
|
size: titleStyle.size,
|
|
6229
6301
|
color: titleStyle.color,
|
|
6230
6302
|
bold: titleStyle.bold,
|
|
6303
|
+
fontWeight: titleStyle.fontWeight,
|
|
6304
|
+
case: titleStyle.case,
|
|
6231
6305
|
italic: titleStyle.italic,
|
|
6232
6306
|
underline: titleStyle.underline,
|
|
6233
6307
|
characterSpacing: titleStyle.characterSpacing,
|
|
@@ -6283,6 +6357,8 @@ function createDocumentStyles(themeNameOrObject = "minimal", language) {
|
|
|
6283
6357
|
size: subtitleStyle.size,
|
|
6284
6358
|
color: subtitleStyle.color,
|
|
6285
6359
|
bold: subtitleStyle.bold,
|
|
6360
|
+
fontWeight: subtitleStyle.fontWeight,
|
|
6361
|
+
case: subtitleStyle.case,
|
|
6286
6362
|
italic: subtitleStyle.italic,
|
|
6287
6363
|
underline: subtitleStyle.underline,
|
|
6288
6364
|
characterSpacing: subtitleStyle.characterSpacing,
|
|
@@ -6405,6 +6481,8 @@ function createDocumentStyles(themeNameOrObject = "minimal", language) {
|
|
|
6405
6481
|
size: customStyle.size,
|
|
6406
6482
|
color: customStyle.color,
|
|
6407
6483
|
bold: customStyle.bold,
|
|
6484
|
+
fontWeight: customStyle.fontWeight,
|
|
6485
|
+
case: customStyle.case,
|
|
6408
6486
|
italic: customStyle.italic,
|
|
6409
6487
|
underline: customStyle.underline,
|
|
6410
6488
|
characterSpacing: customStyle.characterSpacing,
|
|
@@ -8280,6 +8358,7 @@ function compileChromeParagraph(component, scope) {
|
|
|
8280
8358
|
italic: font.italic ?? false,
|
|
8281
8359
|
...font.underline !== void 0 ? { underline: font.underline } : {},
|
|
8282
8360
|
...font.fontWeight !== void 0 ? { fontWeight: font.fontWeight } : {},
|
|
8361
|
+
...font.case !== void 0 ? { case: font.case } : {},
|
|
8283
8362
|
...font.lineSpacing !== void 0 ? { lineSpacing: font.lineSpacing } : {}
|
|
8284
8363
|
}
|
|
8285
8364
|
};
|
|
@@ -9583,7 +9662,11 @@ function isoDateTime(date) {
|
|
|
9583
9662
|
}
|
|
9584
9663
|
function runFormatting3(font, props, ctx) {
|
|
9585
9664
|
const hasWeightRequest = font.fontWeight != null || font.bold === true;
|
|
9586
|
-
const
|
|
9665
|
+
const roleName = props.themeStyle;
|
|
9666
|
+
const role = roleName ? ctx.theme.typography?.roles?.[roleName] : void 0;
|
|
9667
|
+
const roleStyles = ctx.theme.styles;
|
|
9668
|
+
const roleFamily = role && roleName ? resolveFontFamily(ctx.theme, roleStyles?.[roleName]?.font ?? role.face) : void 0;
|
|
9669
|
+
const effectiveFamily = font.family ?? (hasWeightRequest ? roleFamily ?? resolveBodyFamily(ctx.theme) : void 0);
|
|
9587
9670
|
const weighted = applyFontWeightAlias({
|
|
9588
9671
|
fontFamily: effectiveFamily,
|
|
9589
9672
|
bold: font.bold,
|
|
@@ -9591,7 +9674,7 @@ function runFormatting3(font, props, ctx) {
|
|
|
9591
9674
|
fontWeight: font.fontWeight
|
|
9592
9675
|
});
|
|
9593
9676
|
const formatting = {};
|
|
9594
|
-
if (font.family || weighted.font && weighted.font !== effectiveFamily) {
|
|
9677
|
+
if (font.family || hasWeightRequest && roleFamily || weighted.font && weighted.font !== effectiveFamily) {
|
|
9595
9678
|
formatting.fontFamily = weighted.font;
|
|
9596
9679
|
}
|
|
9597
9680
|
if (font.size) formatting.sizeHalfPoints = pointsToHalfPoints(font.size);
|
|
@@ -9603,6 +9686,8 @@ function runFormatting3(font, props, ctx) {
|
|
|
9603
9686
|
formatting.underline = font.underline ? { type: "single" } : void 0;
|
|
9604
9687
|
}
|
|
9605
9688
|
if (font.scale) formatting.scalePercent = font.scale;
|
|
9689
|
+
if (font.case !== void 0)
|
|
9690
|
+
Object.assign(formatting, capsFormatting2(font.case));
|
|
9606
9691
|
if (font.characterSpacing) {
|
|
9607
9692
|
const { type, value } = font.characterSpacing;
|
|
9608
9693
|
formatting.characterSpacingTwentieths = type === "condensed" ? -value : value;
|
|
@@ -9616,7 +9701,7 @@ function applyFontWeightAlias(opts) {
|
|
|
9616
9701
|
return { bold: opts.bold, italic: opts.italic };
|
|
9617
9702
|
}
|
|
9618
9703
|
const weight = opts.fontWeight ?? (opts.bold === true ? 700 : void 0);
|
|
9619
|
-
const synth =
|
|
9704
|
+
const synth = synthesizeFamilyName2(
|
|
9620
9705
|
opts.fontFamily,
|
|
9621
9706
|
weight,
|
|
9622
9707
|
opts.italic === true
|
|
@@ -9955,15 +10040,13 @@ function compileChart(component, scope) {
|
|
|
9955
10040
|
}
|
|
9956
10041
|
const colors = Array.isArray(props.chartColors) ? props.chartColors.map(
|
|
9957
10042
|
(color) => resolveColor(String(color), ctx.theme)
|
|
9958
|
-
) :
|
|
9959
|
-
const value = ctx.theme?.colors?.[token];
|
|
9960
|
-
if (typeof value !== "string" || value.length === 0) return void 0;
|
|
10043
|
+
) : chartPaletteValues(ctx.theme).flatMap((value) => {
|
|
9961
10044
|
try {
|
|
9962
|
-
return resolveColor(
|
|
10045
|
+
return [resolveColor(value, ctx.theme)];
|
|
9963
10046
|
} catch {
|
|
9964
|
-
return
|
|
10047
|
+
return [];
|
|
9965
10048
|
}
|
|
9966
|
-
})
|
|
10049
|
+
});
|
|
9967
10050
|
const page = getPageSetup(ctx.theme);
|
|
9968
10051
|
const contentWidthInches = (page.size.width - page.margin.left - page.margin.right) / 1440;
|
|
9969
10052
|
const widthInches = typeof props.width === "number" ? props.width : contentWidthInches;
|
|
@@ -11298,7 +11381,17 @@ function createRenderContext(document, theme, themeName) {
|
|
|
11298
11381
|
}
|
|
11299
11382
|
|
|
11300
11383
|
// src/quality/facts.ts
|
|
11384
|
+
import {
|
|
11385
|
+
chartEncodingFor,
|
|
11386
|
+
collectColorLiterals,
|
|
11387
|
+
collectFontFamilies,
|
|
11388
|
+
collectPlaceholders,
|
|
11389
|
+
hasUnitMarker,
|
|
11390
|
+
normalizeHex,
|
|
11391
|
+
normalizeHighchartsChart
|
|
11392
|
+
} from "@json-to-office/quality";
|
|
11301
11393
|
import { DEFAULT_DOCX_RENDERER_ID as DEFAULT_DOCX_RENDERER_ID2 } from "@json-to-office/shared-docx";
|
|
11394
|
+
import { designColors as designColors2, resolveDesignColor as resolveDesignColor2 } from "@json-to-office/shared";
|
|
11302
11395
|
|
|
11303
11396
|
// src/core/generationContext.ts
|
|
11304
11397
|
import { applyExportMode } from "@json-to-office/shared";
|
|
@@ -11322,6 +11415,7 @@ function resolveBuiltInTheme(themeName, options = {}) {
|
|
|
11322
11415
|
}
|
|
11323
11416
|
|
|
11324
11417
|
// src/themes/overrides.ts
|
|
11418
|
+
import { mergeWithDefaults as mergeWithDefaults3 } from "@json-to-office/shared";
|
|
11325
11419
|
function applyThemeOverrides(theme, overrides) {
|
|
11326
11420
|
if (!overrides) return theme;
|
|
11327
11421
|
const fonts = { ...theme.fonts };
|
|
@@ -11335,12 +11429,87 @@ function applyThemeOverrides(theme, overrides) {
|
|
|
11335
11429
|
}
|
|
11336
11430
|
return {
|
|
11337
11431
|
...theme,
|
|
11432
|
+
...Object.fromEntries(
|
|
11433
|
+
["palette", "typography", "spacing", "chrome", "motif"].flatMap(
|
|
11434
|
+
(name) => {
|
|
11435
|
+
const key = name;
|
|
11436
|
+
return overrides[key] === void 0 ? [] : [[key, mergeWithDefaults3(overrides[key], theme[key] ?? {})]];
|
|
11437
|
+
}
|
|
11438
|
+
)
|
|
11439
|
+
),
|
|
11338
11440
|
colors: { ...theme.colors, ...overrides.colors ?? {} },
|
|
11339
11441
|
fonts,
|
|
11340
11442
|
...Object.keys(styles).length > 0 && { styles }
|
|
11341
11443
|
};
|
|
11342
11444
|
}
|
|
11343
11445
|
|
|
11446
|
+
// src/themes/design-system.ts
|
|
11447
|
+
init_defaults();
|
|
11448
|
+
import {
|
|
11449
|
+
designCanvas,
|
|
11450
|
+
resolveTypeRoles,
|
|
11451
|
+
validateDesignColors
|
|
11452
|
+
} from "@json-to-office/shared";
|
|
11453
|
+
function resolveDocxDesignSystem(theme) {
|
|
11454
|
+
validateDesignColors(theme, getThemeColors(theme));
|
|
11455
|
+
if (!theme.typography && !theme.spacing) return theme;
|
|
11456
|
+
const canvas = designCanvas("docx", theme.page.size);
|
|
11457
|
+
const roles = resolveTypeRoles(theme, canvas, theme.fonts.body.size ?? 11);
|
|
11458
|
+
const styles = { ...theme.styles };
|
|
11459
|
+
for (const [name, role] of Object.entries(roles)) {
|
|
11460
|
+
const spacing = {
|
|
11461
|
+
...role.spaceBefore !== void 0 && { before: role.spaceBefore },
|
|
11462
|
+
...role.spaceAfter !== void 0 && { after: role.spaceAfter }
|
|
11463
|
+
};
|
|
11464
|
+
styles[name] = {
|
|
11465
|
+
font: role.face ?? "body",
|
|
11466
|
+
size: role.size,
|
|
11467
|
+
...role.weight !== void 0 && { fontWeight: role.weight },
|
|
11468
|
+
...role.color !== void 0 && { color: role.color },
|
|
11469
|
+
...role.case !== void 0 && { case: role.case },
|
|
11470
|
+
...role.lineHeight !== void 0 && {
|
|
11471
|
+
lineSpacing: { type: "multiple", value: role.lineHeight }
|
|
11472
|
+
},
|
|
11473
|
+
...role.tracking !== void 0 && {
|
|
11474
|
+
characterSpacing: {
|
|
11475
|
+
type: role.tracking < 0 ? "condensed" : "expanded",
|
|
11476
|
+
value: Math.abs(role.tracking) * role.size / 5
|
|
11477
|
+
}
|
|
11478
|
+
},
|
|
11479
|
+
...Object.keys(spacing).length && { spacing },
|
|
11480
|
+
...styles[name]
|
|
11481
|
+
};
|
|
11482
|
+
}
|
|
11483
|
+
const gap = theme.spacing?.blockGap?.normal ?? theme.spacing?.basePt;
|
|
11484
|
+
const scale = theme.typography?.scale?.[canvas];
|
|
11485
|
+
if (scale || gap !== void 0) {
|
|
11486
|
+
styles.normal = {
|
|
11487
|
+
...scale && { size: scale.base },
|
|
11488
|
+
...gap !== void 0 && { spacing: { after: gap } },
|
|
11489
|
+
...styles.normal
|
|
11490
|
+
};
|
|
11491
|
+
}
|
|
11492
|
+
const space = theme.spacing?.canvas?.[canvas];
|
|
11493
|
+
const safe = space?.safeAreaIn;
|
|
11494
|
+
return {
|
|
11495
|
+
...theme,
|
|
11496
|
+
styles,
|
|
11497
|
+
page: {
|
|
11498
|
+
...theme.page,
|
|
11499
|
+
margins: {
|
|
11500
|
+
...theme.page.margins,
|
|
11501
|
+
...safe !== void 0 && {
|
|
11502
|
+
top: safe * 1440,
|
|
11503
|
+
bottom: safe * 1440,
|
|
11504
|
+
left: safe * 1440,
|
|
11505
|
+
right: safe * 1440
|
|
11506
|
+
},
|
|
11507
|
+
...space?.gutterIn !== void 0 && { gutter: space.gutterIn * 1440 }
|
|
11508
|
+
}
|
|
11509
|
+
}
|
|
11510
|
+
};
|
|
11511
|
+
}
|
|
11512
|
+
|
|
11344
11513
|
// src/core/generationContext.ts
|
|
11345
11514
|
function defaultNamedThemeLookup(themeName, customThemes, warnings) {
|
|
11346
11515
|
if (customThemes) {
|
|
@@ -11373,6 +11542,7 @@ function resolveThemeContext(documentIn, options = {}) {
|
|
|
11373
11542
|
if (themeOverrides) {
|
|
11374
11543
|
theme = applyThemeOverrides(theme, themeOverrides);
|
|
11375
11544
|
}
|
|
11545
|
+
theme = resolveDocxDesignSystem(theme);
|
|
11376
11546
|
const mode = applyExportMode({ doc: document, theme, fonts });
|
|
11377
11547
|
for (const w of mode.warnings) {
|
|
11378
11548
|
if (warnings) {
|
|
@@ -11539,6 +11709,164 @@ function tableFact(props, path4, availableWidthTwips) {
|
|
|
11539
11709
|
explicitWidths
|
|
11540
11710
|
};
|
|
11541
11711
|
}
|
|
11712
|
+
var SERIES_COLOR_TOKENS = [
|
|
11713
|
+
"primary",
|
|
11714
|
+
"accent",
|
|
11715
|
+
"secondary",
|
|
11716
|
+
"accent4",
|
|
11717
|
+
"accent5",
|
|
11718
|
+
"accent6"
|
|
11719
|
+
];
|
|
11720
|
+
function chartFact(node, props, path4, paletteTokens) {
|
|
11721
|
+
const base = {
|
|
11722
|
+
id: `docx:chart:${path4}`,
|
|
11723
|
+
kind: "docx/chart",
|
|
11724
|
+
path: path4,
|
|
11725
|
+
componentName: typeof node.name === "string" ? node.name : "",
|
|
11726
|
+
paletteTokens
|
|
11727
|
+
};
|
|
11728
|
+
if (node.name === "highcharts") {
|
|
11729
|
+
const shape = normalizeHighchartsChart(props.options);
|
|
11730
|
+
return {
|
|
11731
|
+
...base,
|
|
11732
|
+
chartType: shape.chartType,
|
|
11733
|
+
encoding: shape.encoding,
|
|
11734
|
+
threeD: shape.threeD,
|
|
11735
|
+
seriesCount: shape.seriesCount,
|
|
11736
|
+
categoryCount: shape.categoryCount,
|
|
11737
|
+
seriesColorsStated: shape.seriesColorsStated,
|
|
11738
|
+
seriesColorsPath: `${path4}/props/options`,
|
|
11739
|
+
...shape.valueAxisMin !== void 0 && {
|
|
11740
|
+
valueAxisMin: shape.valueAxisMin
|
|
11741
|
+
},
|
|
11742
|
+
unitStated: shape.unitStated,
|
|
11743
|
+
annotation: {
|
|
11744
|
+
stated: shape.annotationStated,
|
|
11745
|
+
path: path4,
|
|
11746
|
+
slot: "props.options.caption.text"
|
|
11747
|
+
}
|
|
11748
|
+
};
|
|
11749
|
+
}
|
|
11750
|
+
const chartType = typeof props.type === "string" ? props.type : "";
|
|
11751
|
+
if (chartType === "") return void 0;
|
|
11752
|
+
const series = Array.isArray(props.data) ? props.data : [];
|
|
11753
|
+
const categoryCount = Math.max(
|
|
11754
|
+
0,
|
|
11755
|
+
...series.map((entry) => {
|
|
11756
|
+
const record = asRecord(entry);
|
|
11757
|
+
const labels = Array.isArray(record?.labels) ? record.labels.length : 0;
|
|
11758
|
+
const values = Array.isArray(record?.values) ? record.values.length : 0;
|
|
11759
|
+
return Math.max(labels, values);
|
|
11760
|
+
})
|
|
11761
|
+
);
|
|
11762
|
+
const caption = typeof props.caption === "string" ? props.caption : "";
|
|
11763
|
+
const title = typeof props.title === "string" ? props.title : "";
|
|
11764
|
+
return {
|
|
11765
|
+
...base,
|
|
11766
|
+
chartType,
|
|
11767
|
+
encoding: chartEncodingFor(chartType),
|
|
11768
|
+
// No 3D type exists in the DOCX chart schema — `office-open` draws none —
|
|
11769
|
+
// so this is always false here, and stays a field rather than an omission
|
|
11770
|
+
// so both formats answer the same questions.
|
|
11771
|
+
threeD: false,
|
|
11772
|
+
seriesCount: series.length,
|
|
11773
|
+
categoryCount,
|
|
11774
|
+
seriesColorsStated: Array.isArray(props.chartColors) && props.chartColors.length > 0,
|
|
11775
|
+
seriesColorsPath: `${path4}/props/chartColors`,
|
|
11776
|
+
// No `valueAxisMin`: a DOCX chart has no axis-floor property, so the
|
|
11777
|
+
// baseline is always the renderer's, which starts a bar at zero.
|
|
11778
|
+
unitStated: hasUnitMarker(
|
|
11779
|
+
typeof props.valAxisTitle === "string" ? props.valAxisTitle : ""
|
|
11780
|
+
) || hasUnitMarker(title) || hasUnitMarker(caption),
|
|
11781
|
+
annotation: {
|
|
11782
|
+
stated: caption.trim() !== "",
|
|
11783
|
+
path: path4,
|
|
11784
|
+
slot: "props.caption"
|
|
11785
|
+
}
|
|
11786
|
+
};
|
|
11787
|
+
}
|
|
11788
|
+
var DOCX_ALIGNMENTS = /* @__PURE__ */ new Set(["left", "center", "right", "justify"]);
|
|
11789
|
+
function resolvedCellText(content) {
|
|
11790
|
+
return typeof content === "string" ? content : "[component]";
|
|
11791
|
+
}
|
|
11792
|
+
function statesOwnBorders(authored) {
|
|
11793
|
+
if (!authored) return false;
|
|
11794
|
+
if (authored.borderSize !== void 0 || authored.borderColor !== void 0 || authored.hideBorders !== void 0) {
|
|
11795
|
+
return true;
|
|
11796
|
+
}
|
|
11797
|
+
const layers = [
|
|
11798
|
+
asRecord(authored.cellDefaults),
|
|
11799
|
+
asRecord(authored.headerCellDefaults)
|
|
11800
|
+
];
|
|
11801
|
+
if (layers.some(
|
|
11802
|
+
(layer) => layer?.borderSize !== void 0 || layer?.borderColor !== void 0
|
|
11803
|
+
)) {
|
|
11804
|
+
return true;
|
|
11805
|
+
}
|
|
11806
|
+
const columns = Array.isArray(authored.columns) ? authored.columns : [];
|
|
11807
|
+
return columns.some((column) => {
|
|
11808
|
+
const record = asRecord(column);
|
|
11809
|
+
const defaults = asRecord(record?.cellDefaults);
|
|
11810
|
+
return defaults?.borderSize !== void 0 || defaults?.borderColor !== void 0;
|
|
11811
|
+
});
|
|
11812
|
+
}
|
|
11813
|
+
function tableDesignFact(props, path4, theme, themeName, authored) {
|
|
11814
|
+
const authoredColumns = Array.isArray(props.columns) ? props.columns : [];
|
|
11815
|
+
if (authoredColumns.length === 0) return void 0;
|
|
11816
|
+
const model = resolveTableModel(
|
|
11817
|
+
props,
|
|
11818
|
+
theme,
|
|
11819
|
+
themeName
|
|
11820
|
+
);
|
|
11821
|
+
const bodyRows = model.rows;
|
|
11822
|
+
const drawnRows = bodyRows.length + (model.header ? 1 : 0);
|
|
11823
|
+
if (drawnRows === 0) return void 0;
|
|
11824
|
+
const fullGrid = statesOwnBorders(authored) && [...model.header ? [model.header] : [], ...bodyRows].every(
|
|
11825
|
+
(row) => row.cells.every(
|
|
11826
|
+
(cell) => ["top", "right", "bottom", "left"].every(
|
|
11827
|
+
(side) => !cell.borders[side].hidden && cell.borders[side].size > 0
|
|
11828
|
+
)
|
|
11829
|
+
)
|
|
11830
|
+
);
|
|
11831
|
+
const columns = authoredColumns.map(
|
|
11832
|
+
(column, index) => {
|
|
11833
|
+
const authoredColumn = asRecord(column) ?? {};
|
|
11834
|
+
const cells = Array.isArray(authoredColumn.cells) ? authoredColumn.cells : [];
|
|
11835
|
+
const alignments = /* @__PURE__ */ new Set();
|
|
11836
|
+
const values = [];
|
|
11837
|
+
bodyRows.forEach((row) => {
|
|
11838
|
+
const cell = row.cells[index];
|
|
11839
|
+
if (!cell || cell.missing) return;
|
|
11840
|
+
values.push(resolvedCellText(cell.content));
|
|
11841
|
+
alignments.add(cell.horizontalAlignment);
|
|
11842
|
+
});
|
|
11843
|
+
const header = model.header?.cells[index];
|
|
11844
|
+
return {
|
|
11845
|
+
index,
|
|
11846
|
+
path: `${path4}/props/columns/${index}`,
|
|
11847
|
+
...header?.content !== void 0 && {
|
|
11848
|
+
header: resolvedCellText(header.content)
|
|
11849
|
+
},
|
|
11850
|
+
values,
|
|
11851
|
+
alignment: alignments.size === 1 ? [...alignments][0] : alignments.size === 0 ? "left" : "mixed",
|
|
11852
|
+
hasCellDefaults: asRecord(authoredColumn.cellDefaults) !== void 0,
|
|
11853
|
+
hasHeader: asRecord(authoredColumn.header) !== void 0,
|
|
11854
|
+
cellsWithOwnAlignment: cells.flatMap((cell, cellIndex) => {
|
|
11855
|
+
const alignment2 = asRecord(cell)?.horizontalAlignment;
|
|
11856
|
+
return typeof alignment2 === "string" && DOCX_ALIGNMENTS.has(alignment2) && alignment2 !== "right" ? [cellIndex] : [];
|
|
11857
|
+
})
|
|
11858
|
+
};
|
|
11859
|
+
}
|
|
11860
|
+
);
|
|
11861
|
+
return {
|
|
11862
|
+
id: `docx:table-design:${path4}`,
|
|
11863
|
+
kind: "docx/table",
|
|
11864
|
+
path: path4,
|
|
11865
|
+
columns,
|
|
11866
|
+
rowCount: drawnRows,
|
|
11867
|
+
fullGrid
|
|
11868
|
+
};
|
|
11869
|
+
}
|
|
11542
11870
|
var TWIPS_PER_POINT3 = 20;
|
|
11543
11871
|
var SINGLE_LINE_RATIO = 1.2;
|
|
11544
11872
|
function finiteNumber(value) {
|
|
@@ -11567,20 +11895,23 @@ function characterSpacingPt(spacing) {
|
|
|
11567
11895
|
if (rule === void 0 || value === void 0) return 0;
|
|
11568
11896
|
return rule.type === "condensed" ? -value / TWIPS_PER_POINT3 : value / TWIPS_PER_POINT3;
|
|
11569
11897
|
}
|
|
11570
|
-
function
|
|
11898
|
+
function nodeAtPointer(root, pointer) {
|
|
11571
11899
|
let current = root;
|
|
11572
11900
|
for (const token of pointer.split("/").slice(1)) {
|
|
11573
11901
|
if (Array.isArray(current)) {
|
|
11574
11902
|
const index = Number(token);
|
|
11575
|
-
if (!Number.isInteger(index)) return
|
|
11903
|
+
if (!Number.isInteger(index)) return void 0;
|
|
11576
11904
|
current = current[index];
|
|
11577
11905
|
continue;
|
|
11578
11906
|
}
|
|
11579
11907
|
const record = asRecord(current);
|
|
11580
|
-
if (!record) return
|
|
11908
|
+
if (!record) return void 0;
|
|
11581
11909
|
current = record[token];
|
|
11582
11910
|
}
|
|
11583
|
-
return current
|
|
11911
|
+
return current;
|
|
11912
|
+
}
|
|
11913
|
+
function pointerExists(root, pointer) {
|
|
11914
|
+
return nodeAtPointer(root, pointer) !== void 0;
|
|
11584
11915
|
}
|
|
11585
11916
|
function styleKey(node, props) {
|
|
11586
11917
|
if (node.name === "heading") {
|
|
@@ -11761,6 +12092,78 @@ function prepareDocxQualityDocument(document, options = {}) {
|
|
|
11761
12092
|
...fact.relatedPaths && { relatedPaths: fact.relatedPaths }
|
|
11762
12093
|
};
|
|
11763
12094
|
};
|
|
12095
|
+
const paletteHexes = {};
|
|
12096
|
+
const visualColors = designColors2(
|
|
12097
|
+
resolved.theme.colors,
|
|
12098
|
+
resolved.theme.palette
|
|
12099
|
+
);
|
|
12100
|
+
const entries = {
|
|
12101
|
+
...visualColors,
|
|
12102
|
+
...Object.fromEntries(
|
|
12103
|
+
(resolved.theme.palette?.chart ?? []).map((value) => {
|
|
12104
|
+
const hex = resolveDesignColor2(value, visualColors);
|
|
12105
|
+
return [hex ? `#${hex}` : value, value];
|
|
12106
|
+
})
|
|
12107
|
+
)
|
|
12108
|
+
};
|
|
12109
|
+
for (const [token, value] of Object.entries(entries)) {
|
|
12110
|
+
if (typeof value !== "string") continue;
|
|
12111
|
+
const hex = normalizeHex(resolveDesignColor2(value, visualColors) ?? value);
|
|
12112
|
+
if (hex) paletteHexes[token] = hex;
|
|
12113
|
+
}
|
|
12114
|
+
const paletteTokens = resolved.theme.palette?.chart?.map(
|
|
12115
|
+
(value) => `#${resolveDesignColor2(value, visualColors)}`
|
|
12116
|
+
) ?? SERIES_COLOR_TOKENS.filter((token) => paletteHexes[token] !== void 0);
|
|
12117
|
+
const authoredPropsAt = (pointer) => asRecord(asRecord(nodeAtPointer(context.document, pointer))?.props);
|
|
12118
|
+
addFact({
|
|
12119
|
+
id: "docx:theme",
|
|
12120
|
+
kind: "docx/theme",
|
|
12121
|
+
path: "/props",
|
|
12122
|
+
themeName: context.themeName,
|
|
12123
|
+
paletteHexes,
|
|
12124
|
+
// `heading` and `body` only. A theme also names `mono` and `light`, but
|
|
12125
|
+
// those paint nothing until a component asks for them — counting an
|
|
12126
|
+
// unused `Courier New` against a document's family budget would flag a
|
|
12127
|
+
// report that only ever uses one typeface.
|
|
12128
|
+
fontFamilies: [
|
|
12129
|
+
...new Set(
|
|
12130
|
+
["heading", "body"].flatMap((role) => {
|
|
12131
|
+
const family = asRecord(
|
|
12132
|
+
resolved.theme.fonts?.[role]
|
|
12133
|
+
)?.family;
|
|
12134
|
+
return typeof family === "string" && family.trim() !== "" ? [family] : [];
|
|
12135
|
+
})
|
|
12136
|
+
)
|
|
12137
|
+
]
|
|
12138
|
+
});
|
|
12139
|
+
collectColorLiterals(document).forEach((literal, index) => {
|
|
12140
|
+
addFact({
|
|
12141
|
+
id: `docx:color:${index}:${literal.path}`,
|
|
12142
|
+
kind: "docx/color",
|
|
12143
|
+
path: literal.path,
|
|
12144
|
+
raw: literal.raw,
|
|
12145
|
+
hex: literal.hex
|
|
12146
|
+
});
|
|
12147
|
+
});
|
|
12148
|
+
collectFontFamilies(document).forEach((use, index) => {
|
|
12149
|
+
addFact({
|
|
12150
|
+
id: `docx:font:${index}:${use.path}`,
|
|
12151
|
+
kind: "docx/font-family",
|
|
12152
|
+
path: use.path,
|
|
12153
|
+
family: use.family
|
|
12154
|
+
});
|
|
12155
|
+
});
|
|
12156
|
+
collectPlaceholders(document).forEach((occurrence, index) => {
|
|
12157
|
+
addFact({
|
|
12158
|
+
id: `docx:placeholder:${index}:${occurrence.path}`,
|
|
12159
|
+
kind: "docx/placeholder",
|
|
12160
|
+
path: occurrence.path,
|
|
12161
|
+
text: occurrence.text,
|
|
12162
|
+
placeholderKind: occurrence.match.kind,
|
|
12163
|
+
pattern: occurrence.match.pattern,
|
|
12164
|
+
excerpt: occurrence.match.excerpt
|
|
12165
|
+
});
|
|
12166
|
+
});
|
|
11764
12167
|
let previousVisitPath;
|
|
11765
12168
|
let lastFrame;
|
|
11766
12169
|
let flowIndex = 0;
|
|
@@ -11770,6 +12173,18 @@ function prepareDocxQualityDocument(document, options = {}) {
|
|
|
11770
12173
|
if (node.name === "table") {
|
|
11771
12174
|
const fact = tableFact(props, path4, page.availableWidthTwips);
|
|
11772
12175
|
if (fact) addFact(fact);
|
|
12176
|
+
const design = tableDesignFact(
|
|
12177
|
+
props,
|
|
12178
|
+
path4,
|
|
12179
|
+
resolved.theme,
|
|
12180
|
+
context.themeName,
|
|
12181
|
+
authoredPropsAt(path4)
|
|
12182
|
+
);
|
|
12183
|
+
if (design) addFact(design);
|
|
12184
|
+
}
|
|
12185
|
+
if (node.name === "chart" || node.name === "highcharts") {
|
|
12186
|
+
const fact = chartFact(node, props, path4, paletteTokens);
|
|
12187
|
+
if (fact) addFact(fact);
|
|
11773
12188
|
}
|
|
11774
12189
|
if (node.name === "paragraph" || node.name === "text-box") {
|
|
11775
12190
|
const floating = asRecord(props.floating);
|
|
@@ -12193,9 +12608,17 @@ import {
|
|
|
12193
12608
|
|
|
12194
12609
|
// src/quality/rules.ts
|
|
12195
12610
|
import {
|
|
12611
|
+
chartInfoDesignFindings,
|
|
12612
|
+
DEFAULT_MAXIMUM_CHART_SERIES,
|
|
12613
|
+
DEFAULT_MAXIMUM_PIE_SLICES,
|
|
12614
|
+
fontCountFinding,
|
|
12196
12615
|
mergeQualityProfiles,
|
|
12616
|
+
nearestPaletteToken,
|
|
12617
|
+
offPaletteFinding,
|
|
12618
|
+
placeholderFinding,
|
|
12197
12619
|
QUALITY_CODES,
|
|
12198
|
-
QualityEngine
|
|
12620
|
+
QualityEngine,
|
|
12621
|
+
tableInfoDesignFindings
|
|
12199
12622
|
} from "@json-to-office/quality";
|
|
12200
12623
|
|
|
12201
12624
|
// src/quality/text-metrics.ts
|
|
@@ -12661,6 +13084,179 @@ var docxLineBoxRule = {
|
|
|
12661
13084
|
});
|
|
12662
13085
|
}
|
|
12663
13086
|
};
|
|
13087
|
+
var docxPlaceholderRule = {
|
|
13088
|
+
id: "docx/placeholder-text",
|
|
13089
|
+
code: QUALITY_CODES.PLACEHOLDER_TEXT,
|
|
13090
|
+
category: "integrity",
|
|
13091
|
+
defaultSeverity: "warning",
|
|
13092
|
+
defaultCertainty: "deterministic",
|
|
13093
|
+
formats: ["docx"],
|
|
13094
|
+
evaluate: ({ facts }) => facts.filter(
|
|
13095
|
+
(fact) => fact.kind === "docx/placeholder"
|
|
13096
|
+
).map(
|
|
13097
|
+
(fact) => placeholderFinding({
|
|
13098
|
+
path: fact.path,
|
|
13099
|
+
kind: fact.placeholderKind,
|
|
13100
|
+
pattern: fact.pattern,
|
|
13101
|
+
excerpt: fact.excerpt
|
|
13102
|
+
})
|
|
13103
|
+
)
|
|
13104
|
+
};
|
|
13105
|
+
var DEFAULT_MAX_FONT_FAMILIES = 3;
|
|
13106
|
+
var docxFontCountRule = {
|
|
13107
|
+
id: "docx/font-count",
|
|
13108
|
+
code: QUALITY_CODES.FONT_COUNT,
|
|
13109
|
+
category: "brand",
|
|
13110
|
+
defaultSeverity: "warning",
|
|
13111
|
+
defaultCertainty: "deterministic",
|
|
13112
|
+
formats: ["docx"],
|
|
13113
|
+
defaultParameters: { maximumFamilies: DEFAULT_MAX_FONT_FAMILIES },
|
|
13114
|
+
evaluate: ({ facts, configuration }) => {
|
|
13115
|
+
const maximum = numberParameter(
|
|
13116
|
+
configuration.parameters,
|
|
13117
|
+
"maximumFamilies",
|
|
13118
|
+
DEFAULT_MAX_FONT_FAMILIES
|
|
13119
|
+
);
|
|
13120
|
+
const theme = facts.find(
|
|
13121
|
+
(fact) => fact.kind === "docx/theme"
|
|
13122
|
+
);
|
|
13123
|
+
const families = new Set(theme?.fontFamilies ?? []);
|
|
13124
|
+
const extraPaths = [];
|
|
13125
|
+
for (const fact of facts) {
|
|
13126
|
+
if (fact.kind !== "docx/font-family") continue;
|
|
13127
|
+
const use = fact;
|
|
13128
|
+
if (!families.has(use.family)) extraPaths.push(use.path);
|
|
13129
|
+
families.add(use.family);
|
|
13130
|
+
}
|
|
13131
|
+
if (families.size <= maximum) return [];
|
|
13132
|
+
return [
|
|
13133
|
+
fontCountFinding({
|
|
13134
|
+
path: theme?.path ?? "/props",
|
|
13135
|
+
families: [...families].sort(),
|
|
13136
|
+
maximum,
|
|
13137
|
+
relatedPaths: [...new Set(extraPaths)]
|
|
13138
|
+
})
|
|
13139
|
+
];
|
|
13140
|
+
}
|
|
13141
|
+
};
|
|
13142
|
+
var docxPaletteRule = {
|
|
13143
|
+
id: "docx/palette-adherence",
|
|
13144
|
+
code: QUALITY_CODES.OFF_PALETTE,
|
|
13145
|
+
category: "brand",
|
|
13146
|
+
defaultSeverity: "info",
|
|
13147
|
+
defaultCertainty: "deterministic",
|
|
13148
|
+
formats: ["docx"],
|
|
13149
|
+
evaluate: ({ facts }) => {
|
|
13150
|
+
const theme = facts.find(
|
|
13151
|
+
(fact) => fact.kind === "docx/theme"
|
|
13152
|
+
);
|
|
13153
|
+
const palette = theme?.paletteHexes ?? {};
|
|
13154
|
+
const known = new Set(Object.values(palette));
|
|
13155
|
+
return facts.filter((fact) => fact.kind === "docx/color").filter((fact) => !known.has(fact.hex)).map((fact) => {
|
|
13156
|
+
const nearest = nearestPaletteToken(fact.hex, palette);
|
|
13157
|
+
return offPaletteFinding({
|
|
13158
|
+
path: fact.path,
|
|
13159
|
+
raw: fact.raw,
|
|
13160
|
+
hex: fact.hex,
|
|
13161
|
+
...nearest && { nearest }
|
|
13162
|
+
});
|
|
13163
|
+
});
|
|
13164
|
+
}
|
|
13165
|
+
};
|
|
13166
|
+
var DEFAULT_MAX_TABLE_ROWS_PER_PAGE = 25;
|
|
13167
|
+
var docxChartRule = {
|
|
13168
|
+
id: "docx/chart-design",
|
|
13169
|
+
code: QUALITY_CODES.CHART_OVERLOADED,
|
|
13170
|
+
category: "information-design",
|
|
13171
|
+
defaultSeverity: "warning",
|
|
13172
|
+
defaultCertainty: "deterministic",
|
|
13173
|
+
formats: ["docx"],
|
|
13174
|
+
defaultParameters: {
|
|
13175
|
+
maximumSeries: DEFAULT_MAXIMUM_CHART_SERIES,
|
|
13176
|
+
maximumSlices: DEFAULT_MAXIMUM_PIE_SLICES
|
|
13177
|
+
},
|
|
13178
|
+
evaluate: ({ facts, configuration }) => {
|
|
13179
|
+
const maximumSeries = numberParameter(
|
|
13180
|
+
configuration.parameters,
|
|
13181
|
+
"maximumSeries",
|
|
13182
|
+
DEFAULT_MAXIMUM_CHART_SERIES
|
|
13183
|
+
);
|
|
13184
|
+
const maximumSlices = numberParameter(
|
|
13185
|
+
configuration.parameters,
|
|
13186
|
+
"maximumSlices",
|
|
13187
|
+
DEFAULT_MAXIMUM_PIE_SLICES
|
|
13188
|
+
);
|
|
13189
|
+
return facts.filter((fact) => fact.kind === "docx/chart").flatMap((fact) => {
|
|
13190
|
+
const fix = seriesColorFix(fact);
|
|
13191
|
+
return chartInfoDesignFindings(fact, {
|
|
13192
|
+
maximumSeries,
|
|
13193
|
+
maximumSlices,
|
|
13194
|
+
...fix && { seriesColorFix: fix }
|
|
13195
|
+
});
|
|
13196
|
+
});
|
|
13197
|
+
}
|
|
13198
|
+
};
|
|
13199
|
+
function seriesColorFix(fact) {
|
|
13200
|
+
if (fact.componentName !== "chart") return void 0;
|
|
13201
|
+
if (fact.seriesCount < 1 || fact.paletteTokens.length === 0) return void 0;
|
|
13202
|
+
const tokens = Array.from(
|
|
13203
|
+
{ length: fact.seriesCount },
|
|
13204
|
+
(_, index) => fact.paletteTokens[index % fact.paletteTokens.length]
|
|
13205
|
+
);
|
|
13206
|
+
return [{ op: "add", path: fact.seriesColorsPath, value: tokens }];
|
|
13207
|
+
}
|
|
13208
|
+
var docxTableDesignRule = {
|
|
13209
|
+
id: "docx/table-design",
|
|
13210
|
+
code: QUALITY_CODES.TABLE_NUMERIC_ALIGN,
|
|
13211
|
+
category: "information-design",
|
|
13212
|
+
defaultSeverity: "warning",
|
|
13213
|
+
defaultCertainty: "deterministic",
|
|
13214
|
+
formats: ["docx"],
|
|
13215
|
+
defaultParameters: { maximumRows: DEFAULT_MAX_TABLE_ROWS_PER_PAGE },
|
|
13216
|
+
evaluate: ({ facts, configuration }) => {
|
|
13217
|
+
const maximumRows = numberParameter(
|
|
13218
|
+
configuration.parameters,
|
|
13219
|
+
"maximumRows",
|
|
13220
|
+
DEFAULT_MAX_TABLE_ROWS_PER_PAGE
|
|
13221
|
+
);
|
|
13222
|
+
return facts.filter((fact) => fact.kind === "docx/table").flatMap(
|
|
13223
|
+
(fact) => tableInfoDesignFindings(fact, {
|
|
13224
|
+
maximumRows,
|
|
13225
|
+
rowSurface: "page",
|
|
13226
|
+
rowSeverity: "info",
|
|
13227
|
+
alignFix: alignColumnRight
|
|
13228
|
+
})
|
|
13229
|
+
);
|
|
13230
|
+
}
|
|
13231
|
+
};
|
|
13232
|
+
function alignColumnRight(column) {
|
|
13233
|
+
const operations = [
|
|
13234
|
+
column.hasCellDefaults ? {
|
|
13235
|
+
op: "add",
|
|
13236
|
+
path: `${column.path}/cellDefaults/horizontalAlignment`,
|
|
13237
|
+
value: "right"
|
|
13238
|
+
} : {
|
|
13239
|
+
op: "add",
|
|
13240
|
+
path: `${column.path}/cellDefaults`,
|
|
13241
|
+
value: { horizontalAlignment: "right" }
|
|
13242
|
+
}
|
|
13243
|
+
];
|
|
13244
|
+
if (column.hasHeader) {
|
|
13245
|
+
operations.push({
|
|
13246
|
+
op: "add",
|
|
13247
|
+
path: `${column.path}/header/horizontalAlignment`,
|
|
13248
|
+
value: "right"
|
|
13249
|
+
});
|
|
13250
|
+
}
|
|
13251
|
+
for (const index of column.cellsWithOwnAlignment) {
|
|
13252
|
+
operations.push({
|
|
13253
|
+
op: "add",
|
|
13254
|
+
path: `${column.path}/cells/${index}/horizontalAlignment`,
|
|
13255
|
+
value: "right"
|
|
13256
|
+
});
|
|
13257
|
+
}
|
|
13258
|
+
return operations;
|
|
13259
|
+
}
|
|
12664
13260
|
var DOCX_QUALITY_RULES = {
|
|
12665
13261
|
id: "docx/default",
|
|
12666
13262
|
rules: [
|
|
@@ -12669,7 +13265,12 @@ var DOCX_QUALITY_RULES = {
|
|
|
12669
13265
|
docxTextFitRule,
|
|
12670
13266
|
docxFrameCollisionRule,
|
|
12671
13267
|
docxSvgTextBoundsRule,
|
|
12672
|
-
docxLineBoxRule
|
|
13268
|
+
docxLineBoxRule,
|
|
13269
|
+
docxPlaceholderRule,
|
|
13270
|
+
docxChartRule,
|
|
13271
|
+
docxTableDesignRule,
|
|
13272
|
+
docxFontCountRule,
|
|
13273
|
+
docxPaletteRule
|
|
12673
13274
|
]
|
|
12674
13275
|
};
|
|
12675
13276
|
var DOCX_QUALITY_PROFILES = {
|