@json-to-office/core-docx 6.1.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/index.js +510 -236
- package/dist/index.js.map +1 -1
- package/dist/plugin/example/index.js +207 -0
- 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 +2 -2
|
@@ -12970,6 +12970,7 @@ async function expandBlocksWithPlugins(document, theme, plugins, render, preserv
|
|
|
12970
12970
|
init_styleHelpers();
|
|
12971
12971
|
init_defaults();
|
|
12972
12972
|
init_widthUtils();
|
|
12973
|
+
import probe2 from "probe-image-size";
|
|
12973
12974
|
|
|
12974
12975
|
// src/quality/text-inventory.ts
|
|
12975
12976
|
function tocDepth(depth) {
|
|
@@ -13220,6 +13221,92 @@ function collectDocxTextInventory(children, basePath = "/children") {
|
|
|
13220
13221
|
return entries;
|
|
13221
13222
|
}
|
|
13222
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
|
+
|
|
13223
13310
|
// src/quality/facts.ts
|
|
13224
13311
|
function asRecord2(value) {
|
|
13225
13312
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
@@ -14031,14 +14118,29 @@ function prepareDocxQualityDocument(document, options = {}) {
|
|
|
14031
14118
|
}
|
|
14032
14119
|
if (node.name === "image" || node.name === "visual") {
|
|
14033
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
|
+
});
|
|
14034
14132
|
}
|
|
14035
14133
|
if (node.name === "heading") {
|
|
14036
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;
|
|
14037
14138
|
addFact({
|
|
14038
14139
|
id: `docx:heading:${path3}`,
|
|
14039
14140
|
kind: "docx/heading",
|
|
14040
14141
|
path: `${path3}/props/level`,
|
|
14041
14142
|
level,
|
|
14143
|
+
keepNext: props.keepNext === true || props.keepNext === void 0 && styleKeepNext === true,
|
|
14042
14144
|
...previousHeadingLevel !== void 0 && {
|
|
14043
14145
|
previousLevel: previousHeadingLevel
|
|
14044
14146
|
}
|
|
@@ -14053,6 +14155,65 @@ function prepareDocxQualityDocument(document, options = {}) {
|
|
|
14053
14155
|
const page = rec.name === "section" ? pageBox(resolved.theme, context.themeName, rec.props?.page) : basePage;
|
|
14054
14156
|
walkActive(component, `/children/${index}`, page, visit);
|
|
14055
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
|
+
});
|
|
14056
14217
|
return {
|
|
14057
14218
|
format: "docx",
|
|
14058
14219
|
model: {
|
|
@@ -14083,6 +14244,52 @@ function prepareDocxQualityDocument(document, options = {}) {
|
|
|
14083
14244
|
}
|
|
14084
14245
|
};
|
|
14085
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
|
+
}
|
|
14086
14293
|
function slotIsFilled(value) {
|
|
14087
14294
|
if (typeof value === "string") return value.trim() !== "";
|
|
14088
14295
|
return value !== void 0 && value !== null && value !== false && (!Array.isArray(value) || value.length > 0);
|