@json-to-office/core-docx 6.0.0 → 6.2.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/components/visual.d.ts.map +1 -1
- package/dist/core/desugarExternals.d.ts.map +1 -1
- package/dist/core/prerasterizeVisuals.d.ts.map +1 -1
- package/dist/index.js +548 -273
- package/dist/index.js.map +1 -1
- package/dist/plugin/example/index.js +245 -37
- package/dist/plugin/example/index.js.map +1 -1
- package/dist/quality/facts.d.ts +55 -1
- package/dist/quality/facts.d.ts.map +1 -1
- package/dist/quality/rules.d.ts +73 -12
- package/dist/quality/rules.d.ts.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
|
@@ -5870,7 +5870,7 @@ async function rasterizeVisualSlide(presentation, dpi, propsServerUrl, serviceCo
|
|
|
5870
5870
|
serviceConfig?.serverUrl,
|
|
5871
5871
|
DEFAULT_RASTERIZE_SERVER_URL
|
|
5872
5872
|
);
|
|
5873
|
-
const
|
|
5873
|
+
const body = await postJsonToService({
|
|
5874
5874
|
url: serverUrl,
|
|
5875
5875
|
path: "/rasterize",
|
|
5876
5876
|
body: {
|
|
@@ -5882,11 +5882,12 @@ async function rasterizeVisualSlide(presentation, dpi, propsServerUrl, serviceCo
|
|
|
5882
5882
|
headers: serviceConfig?.headers,
|
|
5883
5883
|
serviceLabel: "PPTX rasterization service",
|
|
5884
5884
|
onUnreachable: (url, cause) => `PPTX rasterization service is not reachable at ${url}. Configure services.pptx with a \`render\` callback or a running \`serverUrl\`.
|
|
5885
|
-
Cause: ${cause}
|
|
5885
|
+
Cause: ${cause}`,
|
|
5886
|
+
decode: (response) => response.text()
|
|
5886
5887
|
});
|
|
5887
5888
|
let result;
|
|
5888
5889
|
try {
|
|
5889
|
-
result =
|
|
5890
|
+
result = JSON.parse(body);
|
|
5890
5891
|
} catch {
|
|
5891
5892
|
throw new Error(
|
|
5892
5893
|
"PPTX rasterization service returned a non-JSON response (expected { base64DataUri, width, height })."
|
|
@@ -6074,9 +6075,9 @@ async function prerasterizeVisuals(root, serviceConfig, options = {}) {
|
|
|
6074
6075
|
DEFAULT_RASTERIZE_SERVER_URL
|
|
6075
6076
|
);
|
|
6076
6077
|
const postBatch = async (chunk, fonts) => {
|
|
6077
|
-
let
|
|
6078
|
+
let body;
|
|
6078
6079
|
try {
|
|
6079
|
-
|
|
6080
|
+
body = await postJsonToService2({
|
|
6080
6081
|
url: serverUrl,
|
|
6081
6082
|
path: "/rasterize/batch",
|
|
6082
6083
|
body: {
|
|
@@ -6089,14 +6090,21 @@ async function prerasterizeVisuals(root, serviceConfig, options = {}) {
|
|
|
6089
6090
|
},
|
|
6090
6091
|
headers: serviceConfig?.headers,
|
|
6091
6092
|
timeoutMs: BATCH_TIMEOUT_BASE_MS + BATCH_TIMEOUT_PER_SLIDE_MS * chunk.length,
|
|
6093
|
+
// The per-visual fallback below IS this call's retry, and a better
|
|
6094
|
+
// one: it degrades to smaller work instead of repeating the same
|
|
6095
|
+
// large request. Retrying here first would spend three full batch
|
|
6096
|
+
// timeouts — up to seventeen minutes on a 32-slide chunk — before
|
|
6097
|
+
// the fallback that was going to run anyway gets its turn.
|
|
6098
|
+
retries: 0,
|
|
6092
6099
|
serviceLabel: "PPTX batch rasterization service",
|
|
6093
|
-
onUnreachable: (url, cause) => `PPTX rasterization service is not reachable at ${url}. Cause: ${cause}
|
|
6100
|
+
onUnreachable: (url, cause) => `PPTX rasterization service is not reachable at ${url}. Cause: ${cause}`,
|
|
6101
|
+
decode: (response) => response.text()
|
|
6094
6102
|
});
|
|
6095
6103
|
} catch (error) {
|
|
6096
6104
|
return { applied: false, schemaRejected: isSchemaRejection(error) };
|
|
6097
6105
|
}
|
|
6098
6106
|
try {
|
|
6099
|
-
if (applyBatchResponse(chunk,
|
|
6107
|
+
if (applyBatchResponse(chunk, JSON.parse(body), map)) {
|
|
6100
6108
|
return { applied: true };
|
|
6101
6109
|
}
|
|
6102
6110
|
} catch {
|
|
@@ -6203,7 +6211,7 @@ function containsComponent(root, name) {
|
|
|
6203
6211
|
import {
|
|
6204
6212
|
clampVisualDpi as clampVisualDpi2,
|
|
6205
6213
|
DEFAULT_VISUAL_DPI as DEFAULT_VISUAL_DPI2,
|
|
6206
|
-
|
|
6214
|
+
recordChartCollected
|
|
6207
6215
|
} from "@json-to-office/shared";
|
|
6208
6216
|
import {
|
|
6209
6217
|
isNativeVisualProps as isNativeVisualProps2
|
|
@@ -6222,9 +6230,8 @@ import {
|
|
|
6222
6230
|
withChartTypography,
|
|
6223
6231
|
resolveServiceUrl as resolveServiceUrl3,
|
|
6224
6232
|
postJsonToService as postJsonToService3,
|
|
6225
|
-
|
|
6226
|
-
|
|
6227
|
-
recordChartRetry
|
|
6233
|
+
recordChartRetry,
|
|
6234
|
+
sendChartRequest
|
|
6228
6235
|
} from "@json-to-office/shared";
|
|
6229
6236
|
var DEFAULT_EXPORT_SERVER_URL = "http://localhost:7801";
|
|
6230
6237
|
function effectiveChartServerUrl(props, servicesConfig) {
|
|
@@ -6265,14 +6272,16 @@ async function generateChart(config, servicesConfig, warnings, cache) {
|
|
|
6265
6272
|
// byte-identical to before for callers that omit it.
|
|
6266
6273
|
...config.resources ? { resources: config.resources } : {}
|
|
6267
6274
|
};
|
|
6268
|
-
return
|
|
6275
|
+
return sendChartRequest({
|
|
6269
6276
|
cache,
|
|
6270
|
-
|
|
6271
|
-
|
|
6272
|
-
|
|
6277
|
+
serverUrl,
|
|
6278
|
+
concurrency: servicesConfig?.concurrency,
|
|
6279
|
+
requestBody,
|
|
6280
|
+
send: () => postChart(serverUrl, requestBody, config, servicesConfig)
|
|
6281
|
+
});
|
|
6273
6282
|
}
|
|
6274
6283
|
async function postChart(serverUrl, requestBody, config, servicesConfig) {
|
|
6275
|
-
const
|
|
6284
|
+
const base64Data = await postJsonToService3({
|
|
6276
6285
|
url: serverUrl,
|
|
6277
6286
|
path: "/export",
|
|
6278
6287
|
body: requestBody,
|
|
@@ -6282,16 +6291,13 @@ async function postChart(serverUrl, requestBody, config, servicesConfig) {
|
|
|
6282
6291
|
onRetry: recordChartRetry,
|
|
6283
6292
|
serviceLabel: "Highcharts export server",
|
|
6284
6293
|
onUnreachable: (url, cause) => `Highcharts Export Server is not running at ${url}. Start it with: npx highcharts-export-server --enableServer true
|
|
6285
|
-
Cause: ${cause}
|
|
6294
|
+
Cause: ${cause}`,
|
|
6295
|
+
decode: (response) => response.text()
|
|
6286
6296
|
});
|
|
6287
|
-
const base64Data = await response.text();
|
|
6288
|
-
const base64DataUri = `data:image/png;base64,${base64Data}`;
|
|
6289
|
-
const width = config.options.chart.width;
|
|
6290
|
-
const height = config.options.chart.height;
|
|
6291
6297
|
return {
|
|
6292
|
-
base64DataUri
|
|
6293
|
-
width,
|
|
6294
|
-
height
|
|
6298
|
+
base64DataUri: `data:image/png;base64,${base64Data}`,
|
|
6299
|
+
width: config.options.chart.width,
|
|
6300
|
+
height: config.options.chart.height
|
|
6295
6301
|
};
|
|
6296
6302
|
}
|
|
6297
6303
|
function toChartColor(value, theme) {
|
|
@@ -6419,21 +6425,16 @@ async function desugarExternals(document, options) {
|
|
|
6419
6425
|
});
|
|
6420
6426
|
}
|
|
6421
6427
|
if (node.name === "highcharts") {
|
|
6422
|
-
|
|
6423
|
-
const chartConfig = options.services?.highcharts;
|
|
6428
|
+
recordChartCollected();
|
|
6424
6429
|
return withNodeIdentity(node, {
|
|
6425
6430
|
name: "image",
|
|
6426
|
-
props: await
|
|
6427
|
-
|
|
6428
|
-
|
|
6429
|
-
|
|
6430
|
-
|
|
6431
|
-
|
|
6432
|
-
|
|
6433
|
-
options.chartFonts,
|
|
6434
|
-
options.warnings,
|
|
6435
|
-
chartCache
|
|
6436
|
-
)
|
|
6431
|
+
props: await renderChartToImageProps(
|
|
6432
|
+
node.props,
|
|
6433
|
+
options.theme,
|
|
6434
|
+
options.services?.highcharts,
|
|
6435
|
+
options.chartFonts,
|
|
6436
|
+
options.warnings,
|
|
6437
|
+
chartCache
|
|
6437
6438
|
)
|
|
6438
6439
|
});
|
|
6439
6440
|
}
|
|
@@ -12969,6 +12970,7 @@ async function expandBlocksWithPlugins(document, theme, plugins, render, preserv
|
|
|
12969
12970
|
init_styleHelpers();
|
|
12970
12971
|
init_defaults();
|
|
12971
12972
|
init_widthUtils();
|
|
12973
|
+
import probe2 from "probe-image-size";
|
|
12972
12974
|
|
|
12973
12975
|
// src/quality/text-inventory.ts
|
|
12974
12976
|
function tocDepth(depth) {
|
|
@@ -13219,6 +13221,92 @@ function collectDocxTextInventory(children, basePath = "/children") {
|
|
|
13219
13221
|
return entries;
|
|
13220
13222
|
}
|
|
13221
13223
|
|
|
13224
|
+
// src/quality/text-metrics.ts
|
|
13225
|
+
var DEFAULT_ADVANCE = 556;
|
|
13226
|
+
var ADVANCE = {
|
|
13227
|
+
" ": 278,
|
|
13228
|
+
A: 667,
|
|
13229
|
+
B: 667,
|
|
13230
|
+
C: 722,
|
|
13231
|
+
D: 722,
|
|
13232
|
+
E: 667,
|
|
13233
|
+
F: 611,
|
|
13234
|
+
G: 778,
|
|
13235
|
+
H: 722,
|
|
13236
|
+
I: 278,
|
|
13237
|
+
J: 500,
|
|
13238
|
+
K: 667,
|
|
13239
|
+
L: 556,
|
|
13240
|
+
M: 833,
|
|
13241
|
+
N: 722,
|
|
13242
|
+
O: 778,
|
|
13243
|
+
P: 667,
|
|
13244
|
+
Q: 778,
|
|
13245
|
+
R: 722,
|
|
13246
|
+
S: 667,
|
|
13247
|
+
T: 611,
|
|
13248
|
+
U: 722,
|
|
13249
|
+
V: 667,
|
|
13250
|
+
W: 944,
|
|
13251
|
+
X: 667,
|
|
13252
|
+
Y: 667,
|
|
13253
|
+
Z: 611,
|
|
13254
|
+
a: 556,
|
|
13255
|
+
b: 556,
|
|
13256
|
+
c: 500,
|
|
13257
|
+
d: 556,
|
|
13258
|
+
e: 556,
|
|
13259
|
+
f: 278,
|
|
13260
|
+
g: 556,
|
|
13261
|
+
h: 556,
|
|
13262
|
+
i: 222,
|
|
13263
|
+
j: 222,
|
|
13264
|
+
k: 500,
|
|
13265
|
+
l: 222,
|
|
13266
|
+
m: 833,
|
|
13267
|
+
n: 556,
|
|
13268
|
+
o: 556,
|
|
13269
|
+
p: 556,
|
|
13270
|
+
q: 556,
|
|
13271
|
+
r: 333,
|
|
13272
|
+
s: 500,
|
|
13273
|
+
t: 278,
|
|
13274
|
+
u: 556,
|
|
13275
|
+
v: 500,
|
|
13276
|
+
w: 722,
|
|
13277
|
+
x: 500,
|
|
13278
|
+
y: 500,
|
|
13279
|
+
z: 500,
|
|
13280
|
+
".": 278,
|
|
13281
|
+
",": 278,
|
|
13282
|
+
":": 278,
|
|
13283
|
+
";": 278,
|
|
13284
|
+
"!": 278,
|
|
13285
|
+
"?": 556,
|
|
13286
|
+
"'": 191,
|
|
13287
|
+
'"': 355,
|
|
13288
|
+
"-": 333,
|
|
13289
|
+
"\u2013": 556,
|
|
13290
|
+
"\u2014": 1e3,
|
|
13291
|
+
"&": 667,
|
|
13292
|
+
"%": 889,
|
|
13293
|
+
"(": 333,
|
|
13294
|
+
")": 333,
|
|
13295
|
+
"/": 278,
|
|
13296
|
+
"@": 1015,
|
|
13297
|
+
"#": 556,
|
|
13298
|
+
"+": 584,
|
|
13299
|
+
"=": 584
|
|
13300
|
+
};
|
|
13301
|
+
function estimateTextWidthPt(text, fontSizePt, trackingPt = 0) {
|
|
13302
|
+
let units = 0;
|
|
13303
|
+
for (const character of text) {
|
|
13304
|
+
units += ADVANCE[character] ?? DEFAULT_ADVANCE;
|
|
13305
|
+
}
|
|
13306
|
+
const width = units / 1e3 * fontSizePt + text.length * trackingPt;
|
|
13307
|
+
return Math.max(0, width);
|
|
13308
|
+
}
|
|
13309
|
+
|
|
13222
13310
|
// src/quality/facts.ts
|
|
13223
13311
|
function asRecord2(value) {
|
|
13224
13312
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
@@ -14030,14 +14118,29 @@ function prepareDocxQualityDocument(document, options = {}) {
|
|
|
14030
14118
|
}
|
|
14031
14119
|
if (node.name === "image" || node.name === "visual") {
|
|
14032
14120
|
for (const fact of svgTextFacts(props, path3)) addFact(fact);
|
|
14121
|
+
const drawn = drawnRatio(props);
|
|
14122
|
+
const natural = readableRatio(props);
|
|
14123
|
+
addFact({
|
|
14124
|
+
id: `docx:image:${path3}`,
|
|
14125
|
+
kind: "docx/image",
|
|
14126
|
+
path: path3,
|
|
14127
|
+
...typeof props.alt === "string" && props.alt.trim() !== "" && { alt: props.alt },
|
|
14128
|
+
captioned: isCaptioned(facts, authoredPath(path3)),
|
|
14129
|
+
...drawn !== void 0 && { drawnRatio: drawn },
|
|
14130
|
+
...natural !== void 0 && { naturalRatio: natural }
|
|
14131
|
+
});
|
|
14033
14132
|
}
|
|
14034
14133
|
if (node.name === "heading") {
|
|
14035
14134
|
const level = typeof props.level === "number" && Number.isFinite(props.level) ? props.level : 1;
|
|
14135
|
+
const styleKeepNext = asRecord2(
|
|
14136
|
+
typography.styles[`heading${level}`]
|
|
14137
|
+
)?.keepNext;
|
|
14036
14138
|
addFact({
|
|
14037
14139
|
id: `docx:heading:${path3}`,
|
|
14038
14140
|
kind: "docx/heading",
|
|
14039
14141
|
path: `${path3}/props/level`,
|
|
14040
14142
|
level,
|
|
14143
|
+
keepNext: props.keepNext === true || props.keepNext === void 0 && styleKeepNext === true,
|
|
14041
14144
|
...previousHeadingLevel !== void 0 && {
|
|
14042
14145
|
previousLevel: previousHeadingLevel
|
|
14043
14146
|
}
|
|
@@ -14052,6 +14155,65 @@ function prepareDocxQualityDocument(document, options = {}) {
|
|
|
14052
14155
|
const page = rec.name === "section" ? pageBox(resolved.theme, context.themeName, rec.props?.page) : basePage;
|
|
14053
14156
|
walkActive(component, `/children/${index}`, page, visit);
|
|
14054
14157
|
});
|
|
14158
|
+
const wordsOf = (text) => text.split(/\s+/).filter(Boolean).length;
|
|
14159
|
+
const bodyRoles = /* @__PURE__ */ new Set([
|
|
14160
|
+
"body",
|
|
14161
|
+
"list-item",
|
|
14162
|
+
"table-header",
|
|
14163
|
+
"table-cell",
|
|
14164
|
+
"statistic",
|
|
14165
|
+
"caption"
|
|
14166
|
+
]);
|
|
14167
|
+
const exhibitKinds = /* @__PURE__ */ new Set(["docx/table", "docx/chart", "docx/image"]);
|
|
14168
|
+
resolved.children.forEach((component, index) => {
|
|
14169
|
+
const rec = component;
|
|
14170
|
+
if (rec.name !== "section") return;
|
|
14171
|
+
const prefix = `/children/${index}/`;
|
|
14172
|
+
const own = facts.filter((fact) => fact.path.startsWith(prefix));
|
|
14173
|
+
const texts = own.filter(
|
|
14174
|
+
(fact) => fact.kind === "docx/text"
|
|
14175
|
+
);
|
|
14176
|
+
addFact({
|
|
14177
|
+
id: `docx:section:${index}`,
|
|
14178
|
+
kind: "docx/section",
|
|
14179
|
+
path: `/children/${index}`,
|
|
14180
|
+
index,
|
|
14181
|
+
words: texts.filter((fact) => bodyRoles.has(fact.role)).reduce((total, fact) => total + wordsOf(fact.text), 0),
|
|
14182
|
+
exhibits: own.filter((fact) => exhibitKinds.has(fact.kind)).length,
|
|
14183
|
+
headings: texts.filter((fact) => fact.role === "heading").length
|
|
14184
|
+
});
|
|
14185
|
+
if (hasColumnsComponent(rec)) return;
|
|
14186
|
+
const page = pageBox(
|
|
14187
|
+
resolved.theme,
|
|
14188
|
+
context.themeName,
|
|
14189
|
+
rec.props?.page
|
|
14190
|
+
);
|
|
14191
|
+
const fontSizePt = effectiveFontSize({ name: "paragraph" }, {}, typography)?.fontSizePt ?? 11;
|
|
14192
|
+
const widthPt = page.availableWidthTwips / 20;
|
|
14193
|
+
const averageAdvancePt = estimateTextWidthPt(MEASURE_SAMPLE, fontSizePt) / MEASURE_SAMPLE.length;
|
|
14194
|
+
if (averageAdvancePt > 0)
|
|
14195
|
+
addFact({
|
|
14196
|
+
id: `docx:measure:${index}`,
|
|
14197
|
+
kind: "docx/measure",
|
|
14198
|
+
path: `/children/${index}`,
|
|
14199
|
+
index,
|
|
14200
|
+
charactersPerLine: Math.round(widthPt / averageAdvancePt),
|
|
14201
|
+
widthTwips: page.availableWidthTwips,
|
|
14202
|
+
fontSizePt
|
|
14203
|
+
});
|
|
14204
|
+
});
|
|
14205
|
+
const headingCount = facts.filter(
|
|
14206
|
+
(fact) => fact.kind === "docx/text" && fact.role === "heading"
|
|
14207
|
+
).length;
|
|
14208
|
+
addFact({
|
|
14209
|
+
id: "docx:outline",
|
|
14210
|
+
kind: "docx/outline",
|
|
14211
|
+
path: "/props",
|
|
14212
|
+
headings: headingCount,
|
|
14213
|
+
contents: facts.some(
|
|
14214
|
+
(fact) => fact.kind === "docx/text" && fact.role === "toc-entry"
|
|
14215
|
+
)
|
|
14216
|
+
});
|
|
14055
14217
|
return {
|
|
14056
14218
|
format: "docx",
|
|
14057
14219
|
model: {
|
|
@@ -14082,6 +14244,52 @@ function prepareDocxQualityDocument(document, options = {}) {
|
|
|
14082
14244
|
}
|
|
14083
14245
|
};
|
|
14084
14246
|
}
|
|
14247
|
+
function hasColumnsComponent(node) {
|
|
14248
|
+
if (Array.isArray(node)) return node.some(hasColumnsComponent);
|
|
14249
|
+
const rec = asRecord2(node);
|
|
14250
|
+
if (!rec) return false;
|
|
14251
|
+
if (rec.name === "columns") return true;
|
|
14252
|
+
return Object.values(rec).some(hasColumnsComponent);
|
|
14253
|
+
}
|
|
14254
|
+
var CAPTION_LABEL = /^\s*(?:\*\*)?\s*(figure|exhibit|table|chart|image)\b/i;
|
|
14255
|
+
function isCaptioned(facts, image) {
|
|
14256
|
+
return facts.some((fact) => {
|
|
14257
|
+
if (fact.kind !== "docx/text") return false;
|
|
14258
|
+
const text = fact;
|
|
14259
|
+
const near = siblingOf(text.path) === siblingOf(image) || text.path.startsWith(`${image}/`) || image.startsWith(`${text.path}/`);
|
|
14260
|
+
return near && (text.role === "caption" || CAPTION_LABEL.test(text.text));
|
|
14261
|
+
});
|
|
14262
|
+
}
|
|
14263
|
+
function siblingOf(pointer) {
|
|
14264
|
+
return pointer.slice(0, pointer.lastIndexOf("/"));
|
|
14265
|
+
}
|
|
14266
|
+
var MEASURE_SAMPLE = "the quick brown fox jumps over the lazy dog and then settles under it ";
|
|
14267
|
+
function drawnRatio(props) {
|
|
14268
|
+
const width = finiteNumber(props.width);
|
|
14269
|
+
const height = finiteNumber(props.height);
|
|
14270
|
+
return width !== void 0 && height !== void 0 && height > 0 ? width / height : void 0;
|
|
14271
|
+
}
|
|
14272
|
+
function readableRatio(props) {
|
|
14273
|
+
if (typeof props.svg === "string") {
|
|
14274
|
+
const box = /viewBox\s*=\s*["']\s*[-\d.]+[ ,]+[-\d.]+[ ,]+([\d.]+)[ ,]+([\d.]+)/.exec(
|
|
14275
|
+
props.svg
|
|
14276
|
+
);
|
|
14277
|
+
const width = box ? Number(box[1]) : NaN;
|
|
14278
|
+
const height = box ? Number(box[2]) : NaN;
|
|
14279
|
+
return Number.isFinite(width) && Number.isFinite(height) && height > 0 ? width / height : void 0;
|
|
14280
|
+
}
|
|
14281
|
+
if (typeof props.base64 !== "string") return void 0;
|
|
14282
|
+
const comma = props.base64.indexOf(",");
|
|
14283
|
+
if (comma < 0) return void 0;
|
|
14284
|
+
try {
|
|
14285
|
+
const size = probe2.sync(
|
|
14286
|
+
Buffer.from(props.base64.slice(comma + 1), "base64")
|
|
14287
|
+
);
|
|
14288
|
+
return size && size.height > 0 ? size.width / size.height : void 0;
|
|
14289
|
+
} catch {
|
|
14290
|
+
return void 0;
|
|
14291
|
+
}
|
|
14292
|
+
}
|
|
14085
14293
|
function slotIsFilled(value) {
|
|
14086
14294
|
if (typeof value === "string") return value.trim() !== "";
|
|
14087
14295
|
return value !== void 0 && value !== null && value !== false && (!Array.isArray(value) || value.length > 0);
|