@json-to-office/core-docx 7.7.1 → 7.7.3
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 +1145 -1081
- package/dist/index.js.map +1 -1
- package/dist/ir/compiler.d.ts.map +1 -1
- package/dist/ir/inline.d.ts +6 -1
- package/dist/ir/inline.d.ts.map +1 -1
- package/dist/ir/nativeVisual.d.ts +5 -3
- package/dist/ir/nativeVisual.d.ts.map +1 -1
- package/dist/plugin/example/index.js +1145 -1081
- package/dist/plugin/example/index.js.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/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -5119,6 +5119,12 @@ function buildDocument(ir, resources = /* @__PURE__ */ new Map(), pageNumbers, e
|
|
|
5119
5119
|
updateFields: ir.settings.updateFields,
|
|
5120
5120
|
...ir.settings.trackRevisions ? { trackRevisions: true } : {}
|
|
5121
5121
|
},
|
|
5122
|
+
// A text's `\n` is a manual line break inside its paragraph, and Word
|
|
5123
|
+
// stretches the line before one across the whole width of a justified
|
|
5124
|
+
// paragraph — a two-word line spread edge to edge. `w:doNotExpandShiftReturn`
|
|
5125
|
+
// sets that line flush like the last line of a paragraph, the way every
|
|
5126
|
+
// reader expects. docx keeps compatibility mode 15 alongside it.
|
|
5127
|
+
compatibility: { doNotExpandShiftReturn: true },
|
|
5122
5128
|
...ir.numbering.length > 0 ? { numbering: { config: ir.numbering.map(numberingConfig) } } : {},
|
|
5123
5129
|
// word/footnotes.xml and word/endnotes.xml, keyed by the id their
|
|
5124
5130
|
// references carry.
|
|
@@ -6840,7 +6846,19 @@ async function buildDocumentOptions(ir, charts2 = [], svgRasterFallback) {
|
|
|
6840
6846
|
...coreProperties2(ir),
|
|
6841
6847
|
settings: {
|
|
6842
6848
|
updateFields: ir.settings.updateFields,
|
|
6843
|
-
...ir.settings.trackRevisions ? { trackRevisions: true } : {}
|
|
6849
|
+
...ir.settings.trackRevisions ? { trackRevisions: true } : {},
|
|
6850
|
+
// A text's `\n` is a manual line break inside its paragraph, and Word
|
|
6851
|
+
// stretches the line before one across the whole width of a justified
|
|
6852
|
+
// paragraph. `w:doNotExpandShiftReturn` sets that line flush instead.
|
|
6853
|
+
// Passing `compatibility` replaces @office-open/docx's fresh-document
|
|
6854
|
+
// defaults rather than extending them, so they are restated here.
|
|
6855
|
+
compatibility: {
|
|
6856
|
+
version: 15,
|
|
6857
|
+
overrideTableStyleFontSizeAndJustification: true,
|
|
6858
|
+
enableOpenTypeFeatures: true,
|
|
6859
|
+
doNotFlipMirrorIndents: true,
|
|
6860
|
+
doNotExpandShiftReturn: true
|
|
6861
|
+
}
|
|
6844
6862
|
},
|
|
6845
6863
|
...ir.numbering.length > 0 ? {
|
|
6846
6864
|
numbering: {
|
|
@@ -8105,292 +8123,504 @@ import {
|
|
|
8105
8123
|
|
|
8106
8124
|
// src/ir/nativeVisual.ts
|
|
8107
8125
|
init_units();
|
|
8108
|
-
|
|
8109
|
-
|
|
8110
|
-
|
|
8111
|
-
|
|
8112
|
-
|
|
8113
|
-
|
|
8114
|
-
|
|
8115
|
-
|
|
8116
|
-
|
|
8117
|
-
}
|
|
8118
|
-
|
|
8119
|
-
|
|
8120
|
-
|
|
8121
|
-
|
|
8122
|
-
|
|
8123
|
-
])
|
|
8124
|
-
|
|
8125
|
-
|
|
8126
|
-
|
|
8127
|
-
|
|
8128
|
-
};
|
|
8129
|
-
var
|
|
8130
|
-
|
|
8131
|
-
|
|
8132
|
-
|
|
8133
|
-
|
|
8134
|
-
|
|
8135
|
-
|
|
8136
|
-
const
|
|
8137
|
-
|
|
8138
|
-
|
|
8139
|
-
|
|
8140
|
-
|
|
8141
|
-
|
|
8142
|
-
|
|
8143
|
-
|
|
8144
|
-
|
|
8145
|
-
|
|
8146
|
-
|
|
8126
|
+
|
|
8127
|
+
// src/utils/unicode.ts
|
|
8128
|
+
function normalizeUnicodeText(text) {
|
|
8129
|
+
return (text ?? "").normalize("NFC");
|
|
8130
|
+
}
|
|
8131
|
+
|
|
8132
|
+
// src/ir/inline.ts
|
|
8133
|
+
function escapeRegExp(value) {
|
|
8134
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
8135
|
+
}
|
|
8136
|
+
function buildNoProofWordsRegex(noProofWords2) {
|
|
8137
|
+
const words = (noProofWords2 ?? []).filter((word) => word?.trim().length > 0);
|
|
8138
|
+
if (words.length === 0) return null;
|
|
8139
|
+
const escaped = words.slice().sort((a, b) => b.length - a.length).map(escapeRegExp);
|
|
8140
|
+
return new RegExp(
|
|
8141
|
+
`(?<![\\p{L}\\p{N}])(?:${escaped.join("|")})(?![\\p{L}\\p{N}])`,
|
|
8142
|
+
"giu"
|
|
8143
|
+
);
|
|
8144
|
+
}
|
|
8145
|
+
var DECORATOR = /(\*\*\*|___)([\s\S]*?)\1|(\*\*|__)([\s\S]*?)\3|(\*|_)([\s\S]*?)\5/g;
|
|
8146
|
+
var ESCAPABLE = "*_[]{}\\";
|
|
8147
|
+
var ESCAPE = /\\([*_[\]{}\\])/g;
|
|
8148
|
+
var SENTINEL = "\uE000";
|
|
8149
|
+
var SENTINEL_SELF = "x";
|
|
8150
|
+
var SENTINEL_DIGIT_BASE = 48;
|
|
8151
|
+
function encodeEscapes(text) {
|
|
8152
|
+
const authored = text.includes(SENTINEL);
|
|
8153
|
+
if (!authored && !text.includes("\\")) return text;
|
|
8154
|
+
const guarded = authored ? text.split(SENTINEL).join(SENTINEL + SENTINEL_SELF) : text;
|
|
8155
|
+
return guarded.replace(
|
|
8156
|
+
ESCAPE,
|
|
8157
|
+
(_whole, char) => SENTINEL + String.fromCharCode(SENTINEL_DIGIT_BASE + ESCAPABLE.indexOf(char))
|
|
8158
|
+
);
|
|
8159
|
+
}
|
|
8160
|
+
function decodeEscapes(text) {
|
|
8161
|
+
if (!text.includes(SENTINEL)) return text;
|
|
8162
|
+
let out = "";
|
|
8163
|
+
for (let i = 0; i < text.length; i += 1) {
|
|
8164
|
+
if (text[i] !== SENTINEL) {
|
|
8165
|
+
out += text[i];
|
|
8166
|
+
continue;
|
|
8147
8167
|
}
|
|
8148
|
-
|
|
8149
|
-
|
|
8150
|
-
|
|
8151
|
-
|
|
8152
|
-
|
|
8153
|
-
deps.reject(`canvas.background.color "${background.color}"`);
|
|
8154
|
-
} else {
|
|
8155
|
-
children.push({
|
|
8156
|
-
kind: "shape",
|
|
8157
|
-
frame: fullBleed(canvas),
|
|
8158
|
-
geometry: "rect",
|
|
8159
|
-
fill: { kind: "solid", color },
|
|
8160
|
-
name: "Canvas background"
|
|
8161
|
-
});
|
|
8168
|
+
const marker = text[i + 1];
|
|
8169
|
+
if (marker === SENTINEL_SELF) {
|
|
8170
|
+
out += SENTINEL;
|
|
8171
|
+
i += 1;
|
|
8172
|
+
continue;
|
|
8162
8173
|
}
|
|
8163
|
-
|
|
8164
|
-
|
|
8165
|
-
|
|
8166
|
-
|
|
8167
|
-
|
|
8168
|
-
deps.reject("canvas.background.image could not be loaded");
|
|
8169
|
-
} else {
|
|
8170
|
-
children.push({
|
|
8171
|
-
kind: "picture",
|
|
8172
|
-
frame: fullBleed(canvas),
|
|
8173
|
-
resourceId: resource.resourceId,
|
|
8174
|
-
name: "Canvas background"
|
|
8175
|
-
});
|
|
8174
|
+
const index = marker === void 0 ? -1 : marker.charCodeAt(0) - SENTINEL_DIGIT_BASE;
|
|
8175
|
+
if (index >= 0 && index < ESCAPABLE.length) {
|
|
8176
|
+
out += ESCAPABLE[index];
|
|
8177
|
+
i += 1;
|
|
8178
|
+
continue;
|
|
8176
8179
|
}
|
|
8180
|
+
out += text[i];
|
|
8177
8181
|
}
|
|
8178
|
-
|
|
8179
|
-
if (element.enabled === false) continue;
|
|
8180
|
-
const child = compileElement(element, index, canvas, deps);
|
|
8181
|
-
if (child) children.push(child);
|
|
8182
|
-
}
|
|
8183
|
-
return refused ? void 0 : { canvas, children };
|
|
8182
|
+
return out;
|
|
8184
8183
|
}
|
|
8185
|
-
|
|
8186
|
-
|
|
8187
|
-
|
|
8188
|
-
|
|
8189
|
-
|
|
8190
|
-
|
|
8191
|
-
|
|
8192
|
-
|
|
8193
|
-
|
|
8194
|
-
|
|
8195
|
-
|
|
8196
|
-
|
|
8197
|
-
}
|
|
8184
|
+
var LINK = /\[([^\]]+)\]\(([^)]+)\)/g;
|
|
8185
|
+
var DECORATOR_OR_PLACEHOLDER = /(\*\*\*|___)([\s\S]*?)\1|(\*\*|__)([\s\S]*?)\3|(\*|_)([\s\S]*?)\5|\{([^}]+)\}/g;
|
|
8186
|
+
var PLACEHOLDER = /\{([^}]+)\}/;
|
|
8187
|
+
var UNSUPPORTED_SYNTAX = [];
|
|
8188
|
+
var CROSS_REFERENCE = /\[@([^\]\s:]+)(?::(relative|no_context|full_context|none))?\]/;
|
|
8189
|
+
var INLINE_TOKEN = new RegExp(
|
|
8190
|
+
`${LINK.source}|${CROSS_REFERENCE.source}`,
|
|
8191
|
+
"g"
|
|
8192
|
+
);
|
|
8193
|
+
var NOTE_MARKER = /\[\^([^\]\s]+)\]/g;
|
|
8194
|
+
function containsPlaceholder(text) {
|
|
8195
|
+
return PLACEHOLDER.test(text);
|
|
8198
8196
|
}
|
|
8199
|
-
function
|
|
8200
|
-
|
|
8201
|
-
|
|
8202
|
-
|
|
8203
|
-
|
|
8204
|
-
|
|
8205
|
-
|
|
8197
|
+
function containsCrossReference(text) {
|
|
8198
|
+
return new RegExp(CROSS_REFERENCE.source).test(text);
|
|
8199
|
+
}
|
|
8200
|
+
function containsLink(text) {
|
|
8201
|
+
return new RegExp(LINK.source).test(text);
|
|
8202
|
+
}
|
|
8203
|
+
function containsUnsupportedSyntax(text) {
|
|
8204
|
+
for (const { pattern, what } of UNSUPPORTED_SYNTAX) {
|
|
8205
|
+
if (pattern.test(text)) return what;
|
|
8206
8206
|
}
|
|
8207
|
-
|
|
8208
|
-
[
|
|
8209
|
-
["color", props.color],
|
|
8210
|
-
["fill.color", props.fill?.color],
|
|
8211
|
-
...runs.map((run, i) => [`runs[${i}].color`, run.color]),
|
|
8212
|
-
...runs.map(
|
|
8213
|
-
(run, i) => [
|
|
8214
|
-
`runs[${i}].underline.color`,
|
|
8215
|
-
underlineColor(run.underline)
|
|
8216
|
-
]
|
|
8217
|
-
),
|
|
8218
|
-
["underline.color", underlineColor(props.underline)]
|
|
8219
|
-
],
|
|
8220
|
-
at,
|
|
8221
|
-
deps
|
|
8222
|
-
);
|
|
8223
|
-
if (!colors) return void 0;
|
|
8224
|
-
const frame = resolveFrame(props, canvas, {
|
|
8225
|
-
defaultHeightInches: derivedTextHeightInches(props, runs)
|
|
8226
|
-
});
|
|
8227
|
-
const paragraphs = textParagraphs(runs, props, colors, at);
|
|
8228
|
-
return {
|
|
8229
|
-
kind: "shape",
|
|
8230
|
-
frame,
|
|
8231
|
-
geometry: "rect",
|
|
8232
|
-
isTextBox: true,
|
|
8233
|
-
// A text box with no fill is transparent, which is what the rasterized
|
|
8234
|
-
// path draws; saying so explicitly stops Word applying its own default.
|
|
8235
|
-
fill: props.fill?.color ? solidFill(colors.get("fill.color"), props.fill.transparency) : { kind: "none" },
|
|
8236
|
-
text: {
|
|
8237
|
-
paragraphs,
|
|
8238
|
-
// pptx anchors a text box at the top unless told otherwise, and a
|
|
8239
|
-
// drawing that changes anchor between render modes moves its text.
|
|
8240
|
-
anchor: ANCHOR[props.valign ?? "top"] ?? "top",
|
|
8241
|
-
// A text box's insets default to nothing, again matching pptx. A shape
|
|
8242
|
-
// deliberately leaves them unstated so OOXML's own defaults apply.
|
|
8243
|
-
insetsEmu: marginInsets(props.margin) ?? ZERO_INSETS
|
|
8244
|
-
},
|
|
8245
|
-
name: `Text ${at}`
|
|
8246
|
-
};
|
|
8207
|
+
return void 0;
|
|
8247
8208
|
}
|
|
8248
|
-
|
|
8249
|
-
|
|
8250
|
-
if (
|
|
8251
|
-
|
|
8252
|
-
|
|
8209
|
+
function parseInline(text, options) {
|
|
8210
|
+
const normalized = encodeEscapes(normalizeUnicodeText(text));
|
|
8211
|
+
if (!normalized) {
|
|
8212
|
+
return [
|
|
8213
|
+
{ kind: "text", text: "", formatting: emptyToUndefined(options.base) }
|
|
8214
|
+
];
|
|
8215
|
+
}
|
|
8216
|
+
if (containsPlaceholder(normalized)) {
|
|
8217
|
+
return parsePlaceholders(normalized, options);
|
|
8218
|
+
}
|
|
8219
|
+
if (options.hyperlinks) return parseLinks(normalized, options);
|
|
8220
|
+
return parseDecorated(normalized, options);
|
|
8253
8221
|
}
|
|
8254
|
-
function
|
|
8255
|
-
const
|
|
8256
|
-
|
|
8257
|
-
|
|
8258
|
-
|
|
8259
|
-
kind: "paragraph",
|
|
8260
|
-
id: `${at}.p${paragraphs.length}`,
|
|
8261
|
-
path: `${at}.paragraphs[${paragraphs.length}]`,
|
|
8262
|
-
children: current,
|
|
8263
|
-
formatting: {
|
|
8264
|
-
...props.align ? { alignment: ALIGNMENT[props.align] } : {},
|
|
8265
|
-
// A drawing's text is set flush against the shape; the document's
|
|
8266
|
-
// paragraph spacing would push it away from the top edge, which is not
|
|
8267
|
-
// what an absolutely-placed box means.
|
|
8268
|
-
spacing: { beforeTwips: 0, afterTwips: 0 }
|
|
8269
|
-
}
|
|
8270
|
-
});
|
|
8271
|
-
current = [];
|
|
8222
|
+
function parsePlaceholders(normalized, parseOptions) {
|
|
8223
|
+
const options = {
|
|
8224
|
+
...parseOptions,
|
|
8225
|
+
boldColor: void 0,
|
|
8226
|
+
resolveNote: void 0
|
|
8272
8227
|
};
|
|
8273
|
-
|
|
8274
|
-
|
|
8275
|
-
|
|
8276
|
-
|
|
8277
|
-
|
|
8278
|
-
|
|
8279
|
-
|
|
8280
|
-
|
|
8281
|
-
|
|
8282
|
-
if (
|
|
8283
|
-
|
|
8284
|
-
|
|
8285
|
-
|
|
8228
|
+
const out = [];
|
|
8229
|
+
const token = new RegExp(DECORATOR_OR_PLACEHOLDER.source, "g");
|
|
8230
|
+
let lastIndex = 0;
|
|
8231
|
+
let match;
|
|
8232
|
+
const literal = (text, base = options.base) => {
|
|
8233
|
+
if (!text) return;
|
|
8234
|
+
out.push(...parseLiteralLines(text, { ...options, base }));
|
|
8235
|
+
};
|
|
8236
|
+
while ((match = token.exec(normalized)) !== null) {
|
|
8237
|
+
if (match.index > lastIndex) {
|
|
8238
|
+
literal(normalized.slice(lastIndex, match.index));
|
|
8239
|
+
}
|
|
8240
|
+
lastIndex = match.index + match[0].length;
|
|
8241
|
+
if (match[7]) {
|
|
8242
|
+
const resolved = options.resolvePlaceholder?.(match[7]);
|
|
8243
|
+
if (!resolved) {
|
|
8244
|
+
literal(match[0]);
|
|
8245
|
+
} else if (resolved.kind === "text") {
|
|
8246
|
+
literal(resolved.text);
|
|
8247
|
+
} else {
|
|
8248
|
+
const formatting = emptyToUndefined({
|
|
8249
|
+
fontFamily: options.base.fontFamily,
|
|
8250
|
+
sizeHalfPoints: options.base.sizeHalfPoints,
|
|
8251
|
+
color: options.base.color,
|
|
8252
|
+
bold: options.base.bold,
|
|
8253
|
+
italic: options.base.italic,
|
|
8254
|
+
underline: options.base.underline
|
|
8255
|
+
});
|
|
8256
|
+
out.push({
|
|
8257
|
+
kind: "field",
|
|
8258
|
+
instruction: resolved.instruction,
|
|
8259
|
+
...resolved.cachedText !== void 0 && {
|
|
8260
|
+
cachedText: resolved.cachedText
|
|
8261
|
+
},
|
|
8262
|
+
...formatting ? { formatting } : {}
|
|
8263
|
+
});
|
|
8264
|
+
}
|
|
8265
|
+
continue;
|
|
8266
|
+
}
|
|
8267
|
+
const style = decoratedStyle(match, options.base);
|
|
8268
|
+
out.push(
|
|
8269
|
+
...parsePlaceholders(decoratedText(match), {
|
|
8270
|
+
...options,
|
|
8271
|
+
base: { ...options.base, ...style },
|
|
8272
|
+
// No-proof words do not survive into a decorated span here: the
|
|
8273
|
+
// recursion has always been entered without them.
|
|
8274
|
+
noProofWords: void 0
|
|
8275
|
+
})
|
|
8276
|
+
);
|
|
8277
|
+
}
|
|
8278
|
+
if (lastIndex < normalized.length) literal(normalized.slice(lastIndex));
|
|
8279
|
+
if (out.length === 0 && normalized) literal(normalized);
|
|
8280
|
+
return out;
|
|
8286
8281
|
}
|
|
8287
|
-
function
|
|
8288
|
-
const
|
|
8289
|
-
|
|
8290
|
-
|
|
8291
|
-
|
|
8292
|
-
|
|
8293
|
-
const
|
|
8294
|
-
|
|
8295
|
-
|
|
8296
|
-
|
|
8297
|
-
|
|
8298
|
-
|
|
8282
|
+
function parseLiteralLines(text, options) {
|
|
8283
|
+
const out = [];
|
|
8284
|
+
pushSegment(out, text, options);
|
|
8285
|
+
return out;
|
|
8286
|
+
}
|
|
8287
|
+
function parseLiteral(text, options) {
|
|
8288
|
+
const out = [];
|
|
8289
|
+
pushWords(
|
|
8290
|
+
out,
|
|
8291
|
+
normalizeUnicodeText(text),
|
|
8292
|
+
emptyToUndefined(options.base),
|
|
8293
|
+
options
|
|
8299
8294
|
);
|
|
8300
|
-
|
|
8301
|
-
...fontFamily ? { fontFamily } : {},
|
|
8302
|
-
...sizePoints !== void 0 ? { sizeHalfPoints: pointsToHalfPoints(sizePoints) } : {},
|
|
8303
|
-
...color ? { color } : {},
|
|
8304
|
-
...bold !== void 0 ? { bold } : {},
|
|
8305
|
-
...italic !== void 0 ? { italic } : {},
|
|
8306
|
-
...strike !== void 0 ? { strike } : {},
|
|
8307
|
-
...underline ? { underline } : {}
|
|
8308
|
-
};
|
|
8309
|
-
return Object.keys(formatting).length > 0 ? { formatting } : {};
|
|
8295
|
+
return out;
|
|
8310
8296
|
}
|
|
8311
|
-
|
|
8312
|
-
|
|
8313
|
-
|
|
8314
|
-
|
|
8315
|
-
|
|
8316
|
-
|
|
8317
|
-
|
|
8318
|
-
|
|
8319
|
-
|
|
8320
|
-
|
|
8321
|
-
|
|
8322
|
-
|
|
8323
|
-
|
|
8297
|
+
function parseLinks(normalized, options) {
|
|
8298
|
+
const out = [];
|
|
8299
|
+
const token = new RegExp(INLINE_TOKEN.source, "g");
|
|
8300
|
+
let lastIndex = 0;
|
|
8301
|
+
let match;
|
|
8302
|
+
while ((match = token.exec(normalized)) !== null) {
|
|
8303
|
+
if (match.index > lastIndex) {
|
|
8304
|
+
out.push(
|
|
8305
|
+
...parseDecorated(normalized.slice(lastIndex, match.index), options)
|
|
8306
|
+
);
|
|
8307
|
+
}
|
|
8308
|
+
lastIndex = match.index + match[0].length;
|
|
8309
|
+
if (match[1] === void 0) {
|
|
8310
|
+
const resolved = options.resolveCrossReference?.(
|
|
8311
|
+
decodeEscapes(match[3]),
|
|
8312
|
+
match[4] ?? "relative",
|
|
8313
|
+
match[0]
|
|
8314
|
+
);
|
|
8315
|
+
if (resolved) out.push(resolved);
|
|
8316
|
+
else out.push(...parseDecorated(match[0], options));
|
|
8317
|
+
continue;
|
|
8318
|
+
}
|
|
8319
|
+
const [, linkText] = match;
|
|
8320
|
+
const target2 = decodeEscapes(match[2]);
|
|
8321
|
+
out.push({
|
|
8322
|
+
kind: "hyperlink",
|
|
8323
|
+
// A `#anchor` target names a bookmark in this document and needs no
|
|
8324
|
+
// relationship; anything else leaves the document.
|
|
8325
|
+
target: target2.startsWith("#") ? { kind: "bookmark", anchor: target2.slice(1) } : { kind: "external", url: target2 },
|
|
8326
|
+
children: parseDecorated(linkText, options)
|
|
8327
|
+
});
|
|
8328
|
+
}
|
|
8329
|
+
if (lastIndex < normalized.length) {
|
|
8330
|
+
out.push(...parseDecorated(normalized.slice(lastIndex), options));
|
|
8331
|
+
}
|
|
8332
|
+
if (out.length === 0) return parseDecorated(normalized, options);
|
|
8333
|
+
return out;
|
|
8324
8334
|
}
|
|
8325
|
-
function
|
|
8326
|
-
|
|
8335
|
+
function parseDecorated(normalized, options) {
|
|
8336
|
+
const out = [];
|
|
8337
|
+
let lastIndex = 0;
|
|
8338
|
+
let match;
|
|
8339
|
+
const decorator = new RegExp(DECORATOR.source, "g");
|
|
8340
|
+
while ((match = decorator.exec(normalized)) !== null) {
|
|
8341
|
+
if (match.index > lastIndex) {
|
|
8342
|
+
pushSegment(out, normalized.slice(lastIndex, match.index), options);
|
|
8343
|
+
}
|
|
8344
|
+
pushSegment(
|
|
8345
|
+
out,
|
|
8346
|
+
decoratedText(match),
|
|
8347
|
+
options,
|
|
8348
|
+
decoratedStyle(match, options.base)
|
|
8349
|
+
);
|
|
8350
|
+
lastIndex = match.index + match[0].length;
|
|
8351
|
+
}
|
|
8352
|
+
if (lastIndex < normalized.length) {
|
|
8353
|
+
pushSegment(out, normalized.slice(lastIndex), options);
|
|
8354
|
+
}
|
|
8355
|
+
if (out.length === 0) pushSegment(out, normalized, options);
|
|
8356
|
+
return out;
|
|
8327
8357
|
}
|
|
8328
|
-
function
|
|
8329
|
-
|
|
8330
|
-
|
|
8331
|
-
|
|
8332
|
-
|
|
8333
|
-
);
|
|
8334
|
-
return Math.max(
|
|
8335
|
-
MIN_DERIVED_TEXT_HEIGHT_INCHES,
|
|
8336
|
-
fontSize / 72 * DERIVED_LINE_HEIGHT_RATIO * lineCount
|
|
8337
|
-
);
|
|
8358
|
+
function decoratedText(match) {
|
|
8359
|
+
if (match[1]) return match[2];
|
|
8360
|
+
if (match[3]) return match[4];
|
|
8361
|
+
if (match[5]) return match[6];
|
|
8362
|
+
return match[0];
|
|
8338
8363
|
}
|
|
8339
|
-
function
|
|
8340
|
-
const
|
|
8341
|
-
const
|
|
8342
|
-
|
|
8343
|
-
|
|
8344
|
-
|
|
8345
|
-
|
|
8346
|
-
|
|
8347
|
-
|
|
8348
|
-
|
|
8349
|
-
|
|
8350
|
-
|
|
8351
|
-
|
|
8352
|
-
)
|
|
8353
|
-
|
|
8354
|
-
|
|
8355
|
-
|
|
8356
|
-
|
|
8357
|
-
|
|
8358
|
-
|
|
8359
|
-
|
|
8360
|
-
|
|
8364
|
+
function decoratedStyle(match, base) {
|
|
8365
|
+
const bold = base.bold ?? false;
|
|
8366
|
+
const italic = base.italic ?? false;
|
|
8367
|
+
if (match[1]) return { bold: true, italic: true };
|
|
8368
|
+
if (match[3]) return { bold: true, italic };
|
|
8369
|
+
if (match[5]) return { bold, italic: true };
|
|
8370
|
+
return { bold, italic };
|
|
8371
|
+
}
|
|
8372
|
+
function pushSegment(out, text, options, override = {}) {
|
|
8373
|
+
const bold = override.bold ?? options.base.bold;
|
|
8374
|
+
const italic = override.italic ?? options.base.italic;
|
|
8375
|
+
const formatting = runFormatting(options, { bold, italic });
|
|
8376
|
+
const lines = decodeEscapes(text).split("\n");
|
|
8377
|
+
for (const [lineIndex, line] of lines.entries()) {
|
|
8378
|
+
if (!line && lineIndex === 0) continue;
|
|
8379
|
+
if (lineIndex > 0) out.push({ kind: "lineBreak" });
|
|
8380
|
+
if (!line) {
|
|
8381
|
+
out.push({ kind: "text", text: "", formatting });
|
|
8382
|
+
continue;
|
|
8383
|
+
}
|
|
8384
|
+
const tabSegments = line.split(" ");
|
|
8385
|
+
for (const [tabIndex, segment] of tabSegments.entries()) {
|
|
8386
|
+
if (tabIndex > 0) out.push({ kind: "tab", formatting });
|
|
8387
|
+
if (!segment && tabSegments.length > 1) continue;
|
|
8388
|
+
pushWords(out, segment, formatting, options);
|
|
8389
|
+
}
|
|
8361
8390
|
}
|
|
8362
|
-
const outline = props.line ? {
|
|
8363
|
-
...colors.get("line.color") ? { color: colors.get("line.color") } : {},
|
|
8364
|
-
...props.line.width !== void 0 ? { widthEmu: pointsToEmu(props.line.width) } : {},
|
|
8365
|
-
...dash && dash !== "solid" ? { dash } : {}
|
|
8366
|
-
} : void 0;
|
|
8367
|
-
const text = segments.length ? {
|
|
8368
|
-
paragraphs: shapeParagraphs(segments, props, colors, at),
|
|
8369
|
-
anchor: ANCHOR[props.valign ?? "middle"] ?? "middle",
|
|
8370
|
-
// Unstated insets are left unstated so OOXML's own shape defaults
|
|
8371
|
-
// apply, which is what the raster path draws.
|
|
8372
|
-
...marginInsets(props.margin) ? { insetsEmu: marginInsets(props.margin) } : {}
|
|
8373
|
-
} : void 0;
|
|
8374
|
-
return {
|
|
8375
|
-
kind: "shape",
|
|
8376
|
-
frame,
|
|
8377
|
-
geometry: GEOMETRY_ALIASES[props.type] ?? props.type,
|
|
8378
|
-
...props.fill ? {
|
|
8379
|
-
fill: props.fill.color ? solidFill(colors.get("fill.color"), props.fill.transparency) : { kind: "none" }
|
|
8380
|
-
} : {},
|
|
8381
|
-
...outline && Object.keys(outline).length > 0 ? { outline } : {},
|
|
8382
|
-
...text ? { text } : {},
|
|
8383
|
-
name: `Shape ${at}`
|
|
8384
|
-
};
|
|
8385
8391
|
}
|
|
8386
|
-
function
|
|
8387
|
-
if (
|
|
8388
|
-
|
|
8389
|
-
return
|
|
8392
|
+
function pushWords(out, text, formatting, options) {
|
|
8393
|
+
if (options.resolveNote) {
|
|
8394
|
+
splitNoteMarkers(out, text, formatting, options);
|
|
8395
|
+
return;
|
|
8390
8396
|
}
|
|
8391
|
-
|
|
8397
|
+
pushNoProofWords(out, text, formatting, options);
|
|
8392
8398
|
}
|
|
8393
|
-
function
|
|
8399
|
+
function splitNoteMarkers(out, text, formatting, options) {
|
|
8400
|
+
const regex = new RegExp(NOTE_MARKER.source, "g");
|
|
8401
|
+
let lastIndex = 0;
|
|
8402
|
+
let pending = "";
|
|
8403
|
+
let match;
|
|
8404
|
+
while ((match = regex.exec(text)) !== null) {
|
|
8405
|
+
const note = options.resolveNote(match[1]);
|
|
8406
|
+
if (note === void 0) {
|
|
8407
|
+
pending += text.slice(lastIndex, regex.lastIndex);
|
|
8408
|
+
lastIndex = regex.lastIndex;
|
|
8409
|
+
continue;
|
|
8410
|
+
}
|
|
8411
|
+
const before = pending + text.slice(lastIndex, match.index);
|
|
8412
|
+
pending = "";
|
|
8413
|
+
if (before) pushNoProofWords(out, before, formatting, options);
|
|
8414
|
+
out.push({
|
|
8415
|
+
kind: "noteReference",
|
|
8416
|
+
noteKind: note.noteKind,
|
|
8417
|
+
id: note.id
|
|
8418
|
+
});
|
|
8419
|
+
lastIndex = regex.lastIndex;
|
|
8420
|
+
}
|
|
8421
|
+
const rest = pending + text.slice(lastIndex);
|
|
8422
|
+
if (rest) pushNoProofWords(out, rest, formatting, options);
|
|
8423
|
+
}
|
|
8424
|
+
function noProofRuns(text, formatting, noProofWords2) {
|
|
8425
|
+
const out = [];
|
|
8426
|
+
pushNoProofWords(out, text, formatting, { base: {}, noProofWords: noProofWords2 });
|
|
8427
|
+
return out.map(
|
|
8428
|
+
(run) => run.formatting ? run : { kind: "text", text: run.text }
|
|
8429
|
+
);
|
|
8430
|
+
}
|
|
8431
|
+
function pushNoProofWords(out, text, formatting, options) {
|
|
8432
|
+
const wholeRunNoProof = options.base.noProof === true;
|
|
8433
|
+
const regex = wholeRunNoProof ? null : buildNoProofWordsRegex(options.noProofWords);
|
|
8434
|
+
if (!regex) {
|
|
8435
|
+
out.push({ kind: "text", text, formatting });
|
|
8436
|
+
return;
|
|
8437
|
+
}
|
|
8438
|
+
let lastIndex = 0;
|
|
8439
|
+
let match;
|
|
8440
|
+
while ((match = regex.exec(text)) !== null) {
|
|
8441
|
+
if (match.index > lastIndex) {
|
|
8442
|
+
out.push({
|
|
8443
|
+
kind: "text",
|
|
8444
|
+
text: text.slice(lastIndex, match.index),
|
|
8445
|
+
formatting
|
|
8446
|
+
});
|
|
8447
|
+
}
|
|
8448
|
+
out.push({
|
|
8449
|
+
kind: "text",
|
|
8450
|
+
text: match[0],
|
|
8451
|
+
formatting: { ...formatting, noProof: true }
|
|
8452
|
+
});
|
|
8453
|
+
lastIndex = match.index + match[0].length;
|
|
8454
|
+
if (regex.lastIndex === match.index) regex.lastIndex += 1;
|
|
8455
|
+
}
|
|
8456
|
+
if (lastIndex < text.length) {
|
|
8457
|
+
out.push({ kind: "text", text: text.slice(lastIndex), formatting });
|
|
8458
|
+
}
|
|
8459
|
+
}
|
|
8460
|
+
function runFormatting(options, state) {
|
|
8461
|
+
const formatting = { ...options.base };
|
|
8462
|
+
if (state.bold !== void 0) formatting.bold = state.bold;
|
|
8463
|
+
if (state.italic !== void 0) formatting.italic = state.italic;
|
|
8464
|
+
if (state.bold && options.boldColor && options.base.color) {
|
|
8465
|
+
formatting.color = options.boldColor;
|
|
8466
|
+
}
|
|
8467
|
+
return emptyToUndefined(formatting);
|
|
8468
|
+
}
|
|
8469
|
+
function emptyToUndefined(formatting) {
|
|
8470
|
+
const entries = Object.entries(formatting).filter(
|
|
8471
|
+
([, value]) => value !== void 0
|
|
8472
|
+
);
|
|
8473
|
+
return entries.length === 0 ? void 0 : Object.fromEntries(entries);
|
|
8474
|
+
}
|
|
8475
|
+
|
|
8476
|
+
// src/ir/nativeVisual.ts
|
|
8477
|
+
init_imageUtils();
|
|
8478
|
+
var PIXELS_PER_INCH2 = 96;
|
|
8479
|
+
var DEFAULT_WIDTH_FRACTION = 0.75;
|
|
8480
|
+
var ASSUMED_FONT_SIZE_POINTS = 18;
|
|
8481
|
+
var MIN_DERIVED_TEXT_HEIGHT_INCHES = 0.5;
|
|
8482
|
+
var DERIVED_LINE_HEIGHT_RATIO = 1.6;
|
|
8483
|
+
var GEOMETRY_ALIASES = {
|
|
8484
|
+
arrow: "rightArrow",
|
|
8485
|
+
lightning: "lightningBolt"
|
|
8486
|
+
};
|
|
8487
|
+
var DASH_VALUES = /* @__PURE__ */ new Set([
|
|
8488
|
+
"solid",
|
|
8489
|
+
"dash",
|
|
8490
|
+
"dot",
|
|
8491
|
+
"dashDot"
|
|
8492
|
+
]);
|
|
8493
|
+
var ANCHOR = {
|
|
8494
|
+
top: "top",
|
|
8495
|
+
middle: "middle",
|
|
8496
|
+
bottom: "bottom"
|
|
8497
|
+
};
|
|
8498
|
+
var ALIGNMENT = {
|
|
8499
|
+
left: "left",
|
|
8500
|
+
center: "center",
|
|
8501
|
+
right: "right",
|
|
8502
|
+
justify: "justified"
|
|
8503
|
+
};
|
|
8504
|
+
function compileNativeVisualGroup(props, outer) {
|
|
8505
|
+
const canvas = {
|
|
8506
|
+
widthEmu: inchesToEmu(props.canvas.width),
|
|
8507
|
+
heightEmu: inchesToEmu(props.canvas.height)
|
|
8508
|
+
};
|
|
8509
|
+
const children = [];
|
|
8510
|
+
let refused = false;
|
|
8511
|
+
const deps = {
|
|
8512
|
+
...outer,
|
|
8513
|
+
reject: (detail) => {
|
|
8514
|
+
refused = true;
|
|
8515
|
+
outer.reject(detail);
|
|
8516
|
+
}
|
|
8517
|
+
};
|
|
8518
|
+
const background = props.canvas.background;
|
|
8519
|
+
if (background?.color) {
|
|
8520
|
+
const color = deps.color(background.color);
|
|
8521
|
+
if (!color) {
|
|
8522
|
+
deps.reject(`canvas.background.color "${background.color}"`);
|
|
8523
|
+
} else {
|
|
8524
|
+
children.push({
|
|
8525
|
+
kind: "shape",
|
|
8526
|
+
frame: fullBleed(canvas),
|
|
8527
|
+
geometry: "rect",
|
|
8528
|
+
fill: { kind: "solid", color },
|
|
8529
|
+
name: "Canvas background"
|
|
8530
|
+
});
|
|
8531
|
+
}
|
|
8532
|
+
}
|
|
8533
|
+
if (background?.image) {
|
|
8534
|
+
const source = resolveImageSource(background.image);
|
|
8535
|
+
const resource = source ? deps.picture(source) : void 0;
|
|
8536
|
+
if (!resource) {
|
|
8537
|
+
deps.reject("canvas.background.image could not be loaded");
|
|
8538
|
+
} else {
|
|
8539
|
+
children.push({
|
|
8540
|
+
kind: "picture",
|
|
8541
|
+
frame: fullBleed(canvas),
|
|
8542
|
+
resourceId: resource.resourceId,
|
|
8543
|
+
name: "Canvas background"
|
|
8544
|
+
});
|
|
8545
|
+
}
|
|
8546
|
+
}
|
|
8547
|
+
for (const [index, element] of (props.elements ?? []).entries()) {
|
|
8548
|
+
if (element.enabled === false) continue;
|
|
8549
|
+
const child = compileElement(element, index, canvas, deps);
|
|
8550
|
+
if (child) children.push(child);
|
|
8551
|
+
}
|
|
8552
|
+
return refused ? void 0 : { canvas, children };
|
|
8553
|
+
}
|
|
8554
|
+
function compileElement(element, index, canvas, deps) {
|
|
8555
|
+
const at = `elements[${index}]`;
|
|
8556
|
+
switch (element.name) {
|
|
8557
|
+
case "text":
|
|
8558
|
+
return compileText(element.props, at, canvas, deps);
|
|
8559
|
+
case "shape":
|
|
8560
|
+
return compileShape(element.props, at, canvas, deps);
|
|
8561
|
+
case "image":
|
|
8562
|
+
return compileImage(element.props, at, canvas, deps);
|
|
8563
|
+
default:
|
|
8564
|
+
deps.reject(`${at} is a "${element.name}"`);
|
|
8565
|
+
return void 0;
|
|
8566
|
+
}
|
|
8567
|
+
}
|
|
8568
|
+
function compileText(props, at, canvas, deps) {
|
|
8569
|
+
const runs = textRuns(props);
|
|
8570
|
+
if (!runs) {
|
|
8571
|
+
deps.warn(
|
|
8572
|
+
`[core-docx] native visual ${at} has neither "text" nor "runs"; nothing was drawn for it.`
|
|
8573
|
+
);
|
|
8574
|
+
return void 0;
|
|
8575
|
+
}
|
|
8576
|
+
const colors = resolveColors(
|
|
8577
|
+
[
|
|
8578
|
+
["color", props.color],
|
|
8579
|
+
["fill.color", props.fill?.color],
|
|
8580
|
+
...runs.map((run, i) => [`runs[${i}].color`, run.color]),
|
|
8581
|
+
...runs.map(
|
|
8582
|
+
(run, i) => [
|
|
8583
|
+
`runs[${i}].underline.color`,
|
|
8584
|
+
underlineColor(run.underline)
|
|
8585
|
+
]
|
|
8586
|
+
),
|
|
8587
|
+
["underline.color", underlineColor(props.underline)]
|
|
8588
|
+
],
|
|
8589
|
+
at,
|
|
8590
|
+
deps
|
|
8591
|
+
);
|
|
8592
|
+
if (!colors) return void 0;
|
|
8593
|
+
const frame = resolveFrame(props, canvas, {
|
|
8594
|
+
defaultHeightInches: derivedTextHeightInches(props, runs)
|
|
8595
|
+
});
|
|
8596
|
+
const paragraphs = textParagraphs(runs, props, colors, at, deps.noProofWords);
|
|
8597
|
+
return {
|
|
8598
|
+
kind: "shape",
|
|
8599
|
+
frame,
|
|
8600
|
+
geometry: "rect",
|
|
8601
|
+
isTextBox: true,
|
|
8602
|
+
// A text box with no fill is transparent, which is what the rasterized
|
|
8603
|
+
// path draws; saying so explicitly stops Word applying its own default.
|
|
8604
|
+
fill: props.fill?.color ? solidFill(colors.get("fill.color"), props.fill.transparency) : { kind: "none" },
|
|
8605
|
+
text: {
|
|
8606
|
+
paragraphs,
|
|
8607
|
+
// pptx anchors a text box at the top unless told otherwise, and a
|
|
8608
|
+
// drawing that changes anchor between render modes moves its text.
|
|
8609
|
+
anchor: ANCHOR[props.valign ?? "top"] ?? "top",
|
|
8610
|
+
// A text box's insets default to nothing, again matching pptx. A shape
|
|
8611
|
+
// deliberately leaves them unstated so OOXML's own defaults apply.
|
|
8612
|
+
insetsEmu: marginInsets(props.margin) ?? ZERO_INSETS
|
|
8613
|
+
},
|
|
8614
|
+
name: `Text ${at}`
|
|
8615
|
+
};
|
|
8616
|
+
}
|
|
8617
|
+
var ZERO_INSETS = { top: 0, bottom: 0, left: 0, right: 0 };
|
|
8618
|
+
function textRuns(props) {
|
|
8619
|
+
if (props.runs?.length) return props.runs;
|
|
8620
|
+
if (props.text === void 0) return void 0;
|
|
8621
|
+
return [{ text: props.text }];
|
|
8622
|
+
}
|
|
8623
|
+
function textParagraphs(runs, props, colors, at, words) {
|
|
8394
8624
|
const paragraphs = [];
|
|
8395
8625
|
let current = [];
|
|
8396
8626
|
const flush = () => {
|
|
@@ -8400,49 +8630,195 @@ function shapeParagraphs(segments, props, colors, at) {
|
|
|
8400
8630
|
path: `${at}.paragraphs[${paragraphs.length}]`,
|
|
8401
8631
|
children: current,
|
|
8402
8632
|
formatting: {
|
|
8403
|
-
|
|
8404
|
-
//
|
|
8405
|
-
|
|
8633
|
+
...props.align ? { alignment: ALIGNMENT[props.align] } : {},
|
|
8634
|
+
// A drawing's text is set flush against the shape; the document's
|
|
8635
|
+
// paragraph spacing would push it away from the top edge, which is not
|
|
8636
|
+
// what an absolutely-placed box means.
|
|
8406
8637
|
spacing: { beforeTwips: 0, afterTwips: 0 }
|
|
8407
8638
|
}
|
|
8408
8639
|
});
|
|
8409
8640
|
current = [];
|
|
8410
8641
|
};
|
|
8411
|
-
|
|
8412
|
-
const
|
|
8413
|
-
const
|
|
8414
|
-
|
|
8415
|
-
const bold = segment.bold ?? props.bold;
|
|
8416
|
-
const italic = segment.italic ?? props.italic;
|
|
8417
|
-
const formatting = {
|
|
8418
|
-
...fontFamily ? { fontFamily } : {},
|
|
8419
|
-
...sizePoints !== void 0 ? { sizeHalfPoints: pointsToHalfPoints(sizePoints) } : {},
|
|
8420
|
-
...color ? { color } : {},
|
|
8421
|
-
...bold !== void 0 ? { bold } : {},
|
|
8422
|
-
...italic !== void 0 ? { italic } : {}
|
|
8423
|
-
};
|
|
8424
|
-
const wrapped = Object.keys(formatting).length > 0 ? { formatting } : void 0;
|
|
8425
|
-
segment.text.split("\n").forEach((line, lineIndex) => {
|
|
8642
|
+
runs.forEach((run, index) => {
|
|
8643
|
+
const formatting = runFormatting2(run, props, colors, index);
|
|
8644
|
+
const lines = run.text.split("\n");
|
|
8645
|
+
lines.forEach((line, lineIndex) => {
|
|
8426
8646
|
if (lineIndex > 0) current.push({ kind: "lineBreak" });
|
|
8427
|
-
if (line) current.push(
|
|
8647
|
+
if (line) current.push(...textLine(line, formatting.formatting, words));
|
|
8428
8648
|
});
|
|
8429
|
-
if (
|
|
8649
|
+
if (run.breakLine && index < runs.length - 1) flush();
|
|
8430
8650
|
});
|
|
8431
8651
|
flush();
|
|
8432
8652
|
return paragraphs;
|
|
8433
8653
|
}
|
|
8434
|
-
function
|
|
8435
|
-
const
|
|
8436
|
-
|
|
8437
|
-
|
|
8438
|
-
|
|
8439
|
-
|
|
8440
|
-
const
|
|
8441
|
-
|
|
8442
|
-
|
|
8443
|
-
|
|
8444
|
-
|
|
8445
|
-
|
|
8654
|
+
function runFormatting2(run, props, colors, index) {
|
|
8655
|
+
const fontFamily = run.fontFace ?? props.fontFace;
|
|
8656
|
+
const sizePoints = run.fontSize ?? props.fontSize;
|
|
8657
|
+
const color = colors.get(`runs[${index}].color`) ?? (run.color === void 0 ? colors.get("color") : void 0);
|
|
8658
|
+
const bold = run.bold ?? props.bold;
|
|
8659
|
+
const italic = run.italic ?? props.italic;
|
|
8660
|
+
const strike = run.strike ?? props.strike;
|
|
8661
|
+
const underline = compileUnderline(
|
|
8662
|
+
run.underline ?? props.underline,
|
|
8663
|
+
colors.get(
|
|
8664
|
+
run.underline !== void 0 ? `runs[${index}].underline.color` : "underline.color"
|
|
8665
|
+
)
|
|
8666
|
+
);
|
|
8667
|
+
const formatting = {
|
|
8668
|
+
...fontFamily ? { fontFamily } : {},
|
|
8669
|
+
...sizePoints !== void 0 ? { sizeHalfPoints: pointsToHalfPoints(sizePoints) } : {},
|
|
8670
|
+
...color ? { color } : {},
|
|
8671
|
+
...bold !== void 0 ? { bold } : {},
|
|
8672
|
+
...italic !== void 0 ? { italic } : {},
|
|
8673
|
+
...strike !== void 0 ? { strike } : {},
|
|
8674
|
+
...underline ? { underline } : {}
|
|
8675
|
+
};
|
|
8676
|
+
return Object.keys(formatting).length > 0 ? { formatting } : {};
|
|
8677
|
+
}
|
|
8678
|
+
var UNDERLINE_TYPES = {
|
|
8679
|
+
sng: "single",
|
|
8680
|
+
dbl: "double",
|
|
8681
|
+
dash: "dash",
|
|
8682
|
+
dotted: "dotted"
|
|
8683
|
+
};
|
|
8684
|
+
function compileUnderline(value, color) {
|
|
8685
|
+
if (value === void 0 || value === false) return void 0;
|
|
8686
|
+
const style = value === true ? "sng" : value.style ?? "sng";
|
|
8687
|
+
return {
|
|
8688
|
+
type: UNDERLINE_TYPES[style] ?? "single",
|
|
8689
|
+
...color ? { color } : {}
|
|
8690
|
+
};
|
|
8691
|
+
}
|
|
8692
|
+
function underlineColor(value) {
|
|
8693
|
+
return typeof value === "object" ? value.color : void 0;
|
|
8694
|
+
}
|
|
8695
|
+
function derivedTextHeightInches(props, runs) {
|
|
8696
|
+
const fontSize = props.fontSize ?? ASSUMED_FONT_SIZE_POINTS;
|
|
8697
|
+
const lineCount = runs.reduce(
|
|
8698
|
+
(total, run) => total + (run.breakLine ? 1 : 0) + (run.text.match(/\n/g)?.length ?? 0),
|
|
8699
|
+
1
|
|
8700
|
+
);
|
|
8701
|
+
return Math.max(
|
|
8702
|
+
MIN_DERIVED_TEXT_HEIGHT_INCHES,
|
|
8703
|
+
fontSize / 72 * DERIVED_LINE_HEIGHT_RATIO * lineCount
|
|
8704
|
+
);
|
|
8705
|
+
}
|
|
8706
|
+
function compileShape(props, at, canvas, deps) {
|
|
8707
|
+
const segments = shapeSegments(props);
|
|
8708
|
+
const colors = resolveColors(
|
|
8709
|
+
[
|
|
8710
|
+
["fill.color", props.fill?.color],
|
|
8711
|
+
["line.color", props.line?.color],
|
|
8712
|
+
["fontColor", props.fontColor],
|
|
8713
|
+
...segments.map(
|
|
8714
|
+
(segment, i) => [`text[${i}].color`, segment.color]
|
|
8715
|
+
)
|
|
8716
|
+
],
|
|
8717
|
+
at,
|
|
8718
|
+
deps
|
|
8719
|
+
);
|
|
8720
|
+
if (!colors) return void 0;
|
|
8721
|
+
const frame = resolveFrame(props, canvas, { defaultHeightInches: 0 });
|
|
8722
|
+
if (props.flipH) frame.flipHorizontal = true;
|
|
8723
|
+
if (props.flipV) frame.flipVertical = true;
|
|
8724
|
+
const dash = props.line?.dashType;
|
|
8725
|
+
if (dash !== void 0 && !DASH_VALUES.has(dash)) {
|
|
8726
|
+
deps.reject(`${at}.line.dashType "${dash}"`);
|
|
8727
|
+
return void 0;
|
|
8728
|
+
}
|
|
8729
|
+
const outline = props.line ? {
|
|
8730
|
+
...colors.get("line.color") ? { color: colors.get("line.color") } : {},
|
|
8731
|
+
...props.line.width !== void 0 ? { widthEmu: pointsToEmu(props.line.width) } : {},
|
|
8732
|
+
...dash && dash !== "solid" ? { dash } : {}
|
|
8733
|
+
} : void 0;
|
|
8734
|
+
const text = segments.length ? {
|
|
8735
|
+
paragraphs: shapeParagraphs(
|
|
8736
|
+
segments,
|
|
8737
|
+
props,
|
|
8738
|
+
colors,
|
|
8739
|
+
at,
|
|
8740
|
+
deps.noProofWords
|
|
8741
|
+
),
|
|
8742
|
+
anchor: ANCHOR[props.valign ?? "middle"] ?? "middle",
|
|
8743
|
+
// Unstated insets are left unstated so OOXML's own shape defaults
|
|
8744
|
+
// apply, which is what the raster path draws.
|
|
8745
|
+
...marginInsets(props.margin) ? { insetsEmu: marginInsets(props.margin) } : {}
|
|
8746
|
+
} : void 0;
|
|
8747
|
+
return {
|
|
8748
|
+
kind: "shape",
|
|
8749
|
+
frame,
|
|
8750
|
+
geometry: GEOMETRY_ALIASES[props.type] ?? props.type,
|
|
8751
|
+
...props.fill ? {
|
|
8752
|
+
fill: props.fill.color ? solidFill(colors.get("fill.color"), props.fill.transparency) : { kind: "none" }
|
|
8753
|
+
} : {},
|
|
8754
|
+
...outline && Object.keys(outline).length > 0 ? { outline } : {},
|
|
8755
|
+
...text ? { text } : {},
|
|
8756
|
+
name: `Shape ${at}`
|
|
8757
|
+
};
|
|
8758
|
+
}
|
|
8759
|
+
function shapeSegments(props) {
|
|
8760
|
+
if (props.text === void 0) return [];
|
|
8761
|
+
if (typeof props.text === "string") {
|
|
8762
|
+
return props.text ? [{ text: props.text }] : [];
|
|
8763
|
+
}
|
|
8764
|
+
return props.text;
|
|
8765
|
+
}
|
|
8766
|
+
function shapeParagraphs(segments, props, colors, at, words) {
|
|
8767
|
+
const paragraphs = [];
|
|
8768
|
+
let current = [];
|
|
8769
|
+
const flush = () => {
|
|
8770
|
+
paragraphs.push({
|
|
8771
|
+
kind: "paragraph",
|
|
8772
|
+
id: `${at}.p${paragraphs.length}`,
|
|
8773
|
+
path: `${at}.paragraphs[${paragraphs.length}]`,
|
|
8774
|
+
children: current,
|
|
8775
|
+
formatting: {
|
|
8776
|
+
// A shape centres its text unless told otherwise, which is what the
|
|
8777
|
+
// rasterized shape draws.
|
|
8778
|
+
alignment: props.align ? ALIGNMENT[props.align] : "center",
|
|
8779
|
+
spacing: { beforeTwips: 0, afterTwips: 0 }
|
|
8780
|
+
}
|
|
8781
|
+
});
|
|
8782
|
+
current = [];
|
|
8783
|
+
};
|
|
8784
|
+
segments.forEach((segment, index) => {
|
|
8785
|
+
const fontFamily = segment.fontFace ?? props.fontFace;
|
|
8786
|
+
const sizePoints = segment.fontSize ?? props.fontSize;
|
|
8787
|
+
const color = colors.get(`text[${index}].color`) ?? (segment.color === void 0 ? colors.get("fontColor") : void 0);
|
|
8788
|
+
const bold = segment.bold ?? props.bold;
|
|
8789
|
+
const italic = segment.italic ?? props.italic;
|
|
8790
|
+
const formatting = {
|
|
8791
|
+
...fontFamily ? { fontFamily } : {},
|
|
8792
|
+
...sizePoints !== void 0 ? { sizeHalfPoints: pointsToHalfPoints(sizePoints) } : {},
|
|
8793
|
+
...color ? { color } : {},
|
|
8794
|
+
...bold !== void 0 ? { bold } : {},
|
|
8795
|
+
...italic !== void 0 ? { italic } : {}
|
|
8796
|
+
};
|
|
8797
|
+
const wrapped = Object.keys(formatting).length > 0 ? formatting : void 0;
|
|
8798
|
+
segment.text.split("\n").forEach((line, lineIndex) => {
|
|
8799
|
+
if (lineIndex > 0) current.push({ kind: "lineBreak" });
|
|
8800
|
+
if (line) current.push(...textLine(line, wrapped, words));
|
|
8801
|
+
});
|
|
8802
|
+
if (segment.breakLine && index < segments.length - 1) flush();
|
|
8803
|
+
});
|
|
8804
|
+
flush();
|
|
8805
|
+
return paragraphs;
|
|
8806
|
+
}
|
|
8807
|
+
function textLine(line, formatting, words) {
|
|
8808
|
+
return words ? noProofRuns(line, formatting, words) : [{ kind: "text", text: line, ...formatting ? { formatting } : {} }];
|
|
8809
|
+
}
|
|
8810
|
+
function compileImage(props, at, canvas, deps) {
|
|
8811
|
+
const source = resolveImageSource(props);
|
|
8812
|
+
if (!source) {
|
|
8813
|
+
deps.reject(`${at} has none of "path", "base64" or "svg"`);
|
|
8814
|
+
return void 0;
|
|
8815
|
+
}
|
|
8816
|
+
const resource = deps.picture(source);
|
|
8817
|
+
if (!resource) {
|
|
8818
|
+
deps.reject(`${at} image could not be loaded`);
|
|
8819
|
+
return void 0;
|
|
8820
|
+
}
|
|
8821
|
+
const aspect = resource.intrinsic ? resource.intrinsic.width / resource.intrinsic.height : void 0;
|
|
8446
8822
|
const intrinsicInches = resource.intrinsic ? {
|
|
8447
8823
|
width: resource.intrinsic.width / PIXELS_PER_INCH2,
|
|
8448
8824
|
height: resource.intrinsic.height / PIXELS_PER_INCH2
|
|
@@ -9973,802 +10349,460 @@ function resolveTableModel(source, theme, themeName, options = {}) {
|
|
|
9973
10349
|
});
|
|
9974
10350
|
adjudicateInteriorEdges([...hasHeader ? [header] : [], ...rows]);
|
|
9975
10351
|
return {
|
|
9976
|
-
...resolveWidths(
|
|
9977
|
-
source,
|
|
9978
|
-
columns,
|
|
9979
|
-
options.measureTwips ?? getAvailableWidthTwips(theme, themeName)
|
|
9980
|
-
),
|
|
9981
|
-
...hasHeader ? { header } : {},
|
|
9982
|
-
rows,
|
|
9983
|
-
repeatHeader: source.repeatHeaderOnPageBreak ?? true
|
|
9984
|
-
};
|
|
9985
|
-
}
|
|
9986
|
-
function drawsNothing(border3) {
|
|
9987
|
-
return border3.hidden || border3.size <= 0;
|
|
9988
|
-
}
|
|
9989
|
-
function channels(hex) {
|
|
9990
|
-
const digits = hex.startsWith("#") ? hex.slice(1) : hex;
|
|
9991
|
-
return [
|
|
9992
|
-
parseInt(digits.slice(0, 2), 16) || 0,
|
|
9993
|
-
parseInt(digits.slice(2, 4), 16) || 0,
|
|
9994
|
-
parseInt(digits.slice(4, 6), 16) || 0
|
|
9995
|
-
];
|
|
9996
|
-
}
|
|
9997
|
-
function outweighs(a, b) {
|
|
9998
|
-
if (drawsNothing(a)) return false;
|
|
9999
|
-
if (drawsNothing(b)) return true;
|
|
10000
|
-
if (a.size !== b.size) return a.size > b.size;
|
|
10001
|
-
const [redA, greenA, blueA] = channels(a.color);
|
|
10002
|
-
const [redB, greenB, blueB] = channels(b.color);
|
|
10003
|
-
const brightness = [
|
|
10004
|
-
[redA + blueA + 2 * greenA, redB + blueB + 2 * greenB],
|
|
10005
|
-
[blueA + 2 * greenA, blueB + 2 * greenB],
|
|
10006
|
-
[greenA, greenB]
|
|
10007
|
-
];
|
|
10008
|
-
for (const [ours, theirs] of brightness) {
|
|
10009
|
-
if (ours !== theirs) return ours < theirs;
|
|
10010
|
-
}
|
|
10011
|
-
return false;
|
|
10012
|
-
}
|
|
10013
|
-
function adjudicateInteriorEdges(rows) {
|
|
10014
|
-
const settle = (earlier, later) => {
|
|
10015
|
-
if (drawsNothing(earlier) && drawsNothing(later)) return;
|
|
10016
|
-
if (earlier.hidden === later.hidden && earlier.size === later.size && earlier.color === later.color) {
|
|
10017
|
-
return;
|
|
10018
|
-
}
|
|
10019
|
-
const winner = earlier.explicit !== later.explicit ? earlier.explicit ? earlier : later : outweighs(later, earlier) ? later : earlier;
|
|
10020
|
-
const loser = winner === earlier ? later : earlier;
|
|
10021
|
-
loser.size = winner.size;
|
|
10022
|
-
loser.color = winner.color;
|
|
10023
|
-
loser.hidden = winner.hidden;
|
|
10024
|
-
};
|
|
10025
|
-
rows.forEach((row, rowIndex) => {
|
|
10026
|
-
row.cells.forEach((cell, colIndex) => {
|
|
10027
|
-
const right = row.cells[colIndex + 1];
|
|
10028
|
-
if (right) settle(cell.borders.right, right.borders.left);
|
|
10029
|
-
const below = rows[rowIndex + 1]?.cells[colIndex];
|
|
10030
|
-
if (below) settle(cell.borders.bottom, below.borders.top);
|
|
10031
|
-
});
|
|
10032
|
-
});
|
|
10033
|
-
}
|
|
10034
|
-
function resolveWidths(source, columns, measureTwips) {
|
|
10035
|
-
const hasExplicitWidths = columns.some((col) => col.width !== void 0);
|
|
10036
|
-
if (!hasExplicitWidths) {
|
|
10037
|
-
const percent = source.width ?? 100;
|
|
10038
|
-
return {
|
|
10039
|
-
columnGrid: {
|
|
10040
|
-
unit: "twips",
|
|
10041
|
-
values: splitTwips(columns.length, measureTwips * percent / 100)
|
|
10042
|
-
},
|
|
10043
|
-
width: { size: percent, unit: "percent" }
|
|
10044
|
-
};
|
|
10045
|
-
}
|
|
10046
|
-
const stated = columns.map(
|
|
10047
|
-
(col) => col.width !== void 0 ? relativeLengthToTwips(col.width, measureTwips) : void 0
|
|
10048
|
-
);
|
|
10049
|
-
const totalStated = stated.reduce((sum, w) => sum + (w ?? 0), 0);
|
|
10050
|
-
const unstatedCount = columns.filter((col) => col.width === void 0).length;
|
|
10051
|
-
const remaining = Math.max(0, measureTwips - totalStated);
|
|
10052
|
-
const shareOfRemainder = unstatedCount > 0 ? remaining / unstatedCount : pointsToTwips(72);
|
|
10053
|
-
const values = stated.map((w) => w || shareOfRemainder);
|
|
10054
|
-
return {
|
|
10055
|
-
columnGrid: { unit: "twips", values },
|
|
10056
|
-
width: {
|
|
10057
|
-
size: values.reduce((sum, w) => sum + w, 0),
|
|
10058
|
-
unit: "twips"
|
|
10059
|
-
},
|
|
10060
|
-
...totalStated > measureTwips ? { overflow: { totalTwips: totalStated, availableTwips: measureTwips } } : {}
|
|
10061
|
-
};
|
|
10062
|
-
}
|
|
10063
|
-
|
|
10064
|
-
// src/ir/compiler.ts
|
|
10065
|
-
init_layoutUtils();
|
|
10066
|
-
|
|
10067
|
-
// src/utils/revisionUtils.ts
|
|
10068
|
-
var DEFAULT_REVISION_AUTHOR = "json-to-office";
|
|
10069
|
-
var DEFAULT_REVISION_DATE = "1970-01-01T00:00:00Z";
|
|
10070
|
-
|
|
10071
|
-
// src/utils/commentRegistry.ts
|
|
10072
|
-
var DEFAULT_COMMENT_AUTHOR = "json-to-office";
|
|
10073
|
-
var DEFAULT_COMMENT_DATE = "1970-01-01T00:00:00Z";
|
|
10074
|
-
|
|
10075
|
-
// src/ir/compiler.ts
|
|
10076
|
-
init_imageUtils();
|
|
10077
|
-
init_widthUtils();
|
|
10078
|
-
|
|
10079
|
-
// src/utils/numberingConfig.ts
|
|
10080
|
-
var HEADING_NUMBERING_REFERENCE = "jto-heading-numbering";
|
|
10081
|
-
function headingNumberLabel(number) {
|
|
10082
|
-
return `${number}.`;
|
|
10083
|
-
}
|
|
10084
|
-
|
|
10085
|
-
// src/utils/unicode.ts
|
|
10086
|
-
function normalizeUnicodeText(text) {
|
|
10087
|
-
return (text ?? "").normalize("NFC");
|
|
10088
|
-
}
|
|
10089
|
-
|
|
10090
|
-
// src/core/collectTocHeadings.ts
|
|
10091
|
-
import { getStandardComponent } from "@json-to-office/shared-docx";
|
|
10092
|
-
|
|
10093
|
-
// src/core/sectionBookmarks.ts
|
|
10094
|
-
function sectionBookmark(ordinal) {
|
|
10095
|
-
return { id: `_Section_${ordinal}`, linkId: ordinal };
|
|
10096
|
-
}
|
|
10097
|
-
|
|
10098
|
-
// src/utils/numberFormatting.ts
|
|
10099
|
-
var ROMAN_NUMERALS = [
|
|
10100
|
-
[1e3, "m"],
|
|
10101
|
-
[900, "cm"],
|
|
10102
|
-
[500, "d"],
|
|
10103
|
-
[400, "cd"],
|
|
10104
|
-
[100, "c"],
|
|
10105
|
-
[90, "xc"],
|
|
10106
|
-
[50, "l"],
|
|
10107
|
-
[40, "xl"],
|
|
10108
|
-
[10, "x"],
|
|
10109
|
-
[9, "ix"],
|
|
10110
|
-
[5, "v"],
|
|
10111
|
-
[4, "iv"],
|
|
10112
|
-
[1, "i"]
|
|
10113
|
-
];
|
|
10114
|
-
function toRoman(value) {
|
|
10115
|
-
let remaining = value;
|
|
10116
|
-
let out = "";
|
|
10117
|
-
for (const [amount, glyph] of ROMAN_NUMERALS) {
|
|
10118
|
-
while (remaining >= amount) {
|
|
10119
|
-
out += glyph;
|
|
10120
|
-
remaining -= amount;
|
|
10121
|
-
}
|
|
10122
|
-
}
|
|
10123
|
-
return out;
|
|
10124
|
-
}
|
|
10125
|
-
function toLetters(value) {
|
|
10126
|
-
const index = (value - 1) % 26;
|
|
10127
|
-
const repeats = Math.floor((value - 1) / 26) + 1;
|
|
10128
|
-
return String.fromCharCode(97 + index).repeat(repeats);
|
|
10129
|
-
}
|
|
10130
|
-
function formatNumberForLevel(value, format2) {
|
|
10131
|
-
if (!Number.isFinite(value) || value < 1) return void 0;
|
|
10132
|
-
const n = Math.floor(value);
|
|
10133
|
-
switch (format2) {
|
|
10134
|
-
case "decimal":
|
|
10135
|
-
return String(n);
|
|
10136
|
-
case "lowerLetter":
|
|
10137
|
-
return toLetters(n);
|
|
10138
|
-
case "upperLetter":
|
|
10139
|
-
return toLetters(n).toUpperCase();
|
|
10140
|
-
case "lowerRoman":
|
|
10141
|
-
return toRoman(n);
|
|
10142
|
-
case "upperRoman":
|
|
10143
|
-
return toRoman(n).toUpperCase();
|
|
10144
|
-
default:
|
|
10145
|
-
return void 0;
|
|
10146
|
-
}
|
|
10147
|
-
}
|
|
10148
|
-
|
|
10149
|
-
// src/core/collectTocHeadings.ts
|
|
10150
|
-
var MAX_HEADING_LEVEL = 6;
|
|
10151
|
-
var MAX_LIST_LEVEL = 9;
|
|
10152
|
-
function normalizeEntryTitle(text) {
|
|
10153
|
-
return normalizeUnicodeText(text).replace(/(\*\*\*|___)([\s\S]*?)\1/g, "$2").replace(/(\*\*|__)([\s\S]*?)\1/g, "$2").replace(/(\*|_)([\s\S]*?)\1/g, "$2").trim();
|
|
10154
|
-
}
|
|
10155
|
-
function isContainer(name) {
|
|
10156
|
-
return getStandardComponent(name)?.hasChildren === true;
|
|
10157
|
-
}
|
|
10158
|
-
function isEnabled(component) {
|
|
10159
|
-
return !("enabled" in component && component.enabled === false);
|
|
10160
|
-
}
|
|
10161
|
-
function styleEntryKey(props) {
|
|
10162
|
-
const themeStyle = props.themeStyle;
|
|
10163
|
-
if (typeof themeStyle !== "string" || !themeStyle) return void 0;
|
|
10164
|
-
if (/^heading[1-6]$/i.test(themeStyle)) return void 0;
|
|
10165
|
-
if (["normal", "title", "subtitle"].includes(themeStyle.toLowerCase())) {
|
|
10166
|
-
return void 0;
|
|
10167
|
-
}
|
|
10168
|
-
return themeStyle;
|
|
10169
|
-
}
|
|
10170
|
-
function levelStart(levels, level) {
|
|
10171
|
-
return levels[level]?.start ?? 1;
|
|
10172
|
-
}
|
|
10173
|
-
function collectDocumentOutline(sections) {
|
|
10174
|
-
const entries = [];
|
|
10175
|
-
const numberedItems = /* @__PURE__ */ new Map();
|
|
10176
|
-
const ordinals = computeSectionOrdinals(sections);
|
|
10177
|
-
const takenIds = /* @__PURE__ */ new Set();
|
|
10178
|
-
const headingCounters = new Array(MAX_HEADING_LEVEL).fill(0);
|
|
10179
|
-
const listCounters = /* @__PURE__ */ new Map();
|
|
10180
|
-
const visitHeading = (component, props, sectionBookmarkId) => {
|
|
10181
|
-
const text = typeof props.text === "string" ? props.text : "";
|
|
10182
|
-
const title = normalizeEntryTitle(text);
|
|
10183
|
-
const level = typeof props.level === "number" ? props.level : 1;
|
|
10184
|
-
const styleLevel = level >= 1 && level <= MAX_HEADING_LEVEL ? level : 1;
|
|
10185
|
-
let full;
|
|
10186
|
-
let own;
|
|
10187
|
-
if (props.numbering === true) {
|
|
10188
|
-
headingCounters[styleLevel - 1] += 1;
|
|
10189
|
-
for (let deeper = styleLevel; deeper < MAX_HEADING_LEVEL; deeper++) {
|
|
10190
|
-
headingCounters[deeper] = 0;
|
|
10191
|
-
}
|
|
10192
|
-
full = headingCounters.slice(0, styleLevel).join(".");
|
|
10193
|
-
own = String(headingCounters[styleLevel - 1]);
|
|
10194
|
-
}
|
|
10195
|
-
const explicitId = component.id;
|
|
10196
|
-
const bookmarkId = typeof explicitId === "string" && explicitId ? explicitId : dedupeBookmarkId(slugifyBookmarkText(text), (id) => takenIds.has(id));
|
|
10197
|
-
takenIds.add(bookmarkId);
|
|
10198
|
-
numberedItems.set(bookmarkId, {
|
|
10199
|
-
kind: "heading",
|
|
10200
|
-
text: title,
|
|
10201
|
-
...full !== void 0 && { full, own }
|
|
10202
|
-
});
|
|
10203
|
-
if (title) {
|
|
10204
|
-
entries.push({
|
|
10205
|
-
title,
|
|
10206
|
-
level,
|
|
10207
|
-
sectionBookmarkId,
|
|
10208
|
-
...full !== void 0 && { number: full }
|
|
10209
|
-
});
|
|
10210
|
-
}
|
|
10211
|
-
};
|
|
10212
|
-
const visitList = (props) => {
|
|
10213
|
-
const items = Array.isArray(props.items) ? props.items : [];
|
|
10214
|
-
if (items.length === 0) return;
|
|
10215
|
-
const reference = typeof props.reference === "string" && props.reference ? props.reference : void 0;
|
|
10216
|
-
const freshState = () => {
|
|
10217
|
-
const levels = resolveListLevels(
|
|
10218
|
-
props
|
|
10219
|
-
);
|
|
10220
|
-
return {
|
|
10221
|
-
levels,
|
|
10222
|
-
counters: Array.from(
|
|
10223
|
-
{ length: MAX_LIST_LEVEL },
|
|
10224
|
-
(_, level) => levelStart(levels, level) - 1
|
|
10225
|
-
)
|
|
10226
|
-
};
|
|
10227
|
-
};
|
|
10228
|
-
let state;
|
|
10229
|
-
if (reference === void 0) {
|
|
10230
|
-
state = freshState();
|
|
10231
|
-
} else {
|
|
10232
|
-
state = listCounters.get(reference) ?? freshState();
|
|
10233
|
-
listCounters.set(reference, state);
|
|
10234
|
-
}
|
|
10235
|
-
for (const item of items) {
|
|
10236
|
-
const isObject = typeof item === "object" && item !== null;
|
|
10237
|
-
const raw = isObject ? item.text : item;
|
|
10238
|
-
const text = typeof raw === "string" ? raw : "";
|
|
10239
|
-
if (!text.trim() && !(isObject && item.revision)) continue;
|
|
10240
|
-
const rawLevel = isObject ? item.level : void 0;
|
|
10241
|
-
const level = typeof rawLevel === "number" && rawLevel >= 0 ? rawLevel : 0;
|
|
10242
|
-
if (level >= MAX_LIST_LEVEL) continue;
|
|
10243
|
-
state.counters[level] += 1;
|
|
10244
|
-
for (let deeper = level + 1; deeper < MAX_LIST_LEVEL; deeper++) {
|
|
10245
|
-
state.counters[deeper] = levelStart(state.levels, deeper) - 1;
|
|
10246
|
-
}
|
|
10247
|
-
const id = isObject ? item.id : void 0;
|
|
10248
|
-
if (typeof id !== "string" || !id) continue;
|
|
10249
|
-
takenIds.add(id);
|
|
10250
|
-
const number = formatNumberForLevel(
|
|
10251
|
-
state.counters[level],
|
|
10252
|
-
state.levels[level]?.format
|
|
10253
|
-
);
|
|
10254
|
-
numberedItems.set(id, {
|
|
10255
|
-
kind: "list-item",
|
|
10256
|
-
text: normalizeUnicodeText(text).trim(),
|
|
10257
|
-
...number !== void 0 && { full: number, own: number }
|
|
10258
|
-
});
|
|
10259
|
-
}
|
|
10260
|
-
};
|
|
10261
|
-
sections.forEach((section2, index) => {
|
|
10262
|
-
const ordinal = ordinals[index]?.ordinal;
|
|
10263
|
-
const sectionBookmarkId = ordinal ? sectionBookmark(ordinal).id : void 0;
|
|
10264
|
-
const visit = (component) => {
|
|
10265
|
-
if (!isEnabled(component)) return;
|
|
10266
|
-
const props = component.props ?? {};
|
|
10267
|
-
if (component.name === "heading") {
|
|
10268
|
-
visitHeading(component, props, sectionBookmarkId);
|
|
10269
|
-
return;
|
|
10270
|
-
}
|
|
10271
|
-
if (component.name === "paragraph") {
|
|
10272
|
-
if (typeof props.id === "string" && props.id) takenIds.add(props.id);
|
|
10273
|
-
const styleId = styleEntryKey(props);
|
|
10274
|
-
const text = typeof props.text === "string" ? props.text : "";
|
|
10275
|
-
const title = normalizeEntryTitle(text);
|
|
10276
|
-
if (styleId && title) {
|
|
10277
|
-
entries.push({ title, level: 1, styleId, sectionBookmarkId });
|
|
10278
|
-
}
|
|
10279
|
-
return;
|
|
10280
|
-
}
|
|
10281
|
-
if (component.name === "list") {
|
|
10282
|
-
visitList(props);
|
|
10283
|
-
return;
|
|
10284
|
-
}
|
|
10285
|
-
if (!isContainer(component.name)) return;
|
|
10286
|
-
const children = component.children;
|
|
10287
|
-
if (Array.isArray(children)) children.forEach(visit);
|
|
10288
|
-
};
|
|
10289
|
-
section2.components.forEach(visit);
|
|
10290
|
-
});
|
|
10291
|
-
return { entries, numberedItems };
|
|
10292
|
-
}
|
|
10293
|
-
|
|
10294
|
-
// src/core/tocField.ts
|
|
10295
|
-
function toStyleDisplayName(styleId) {
|
|
10296
|
-
return styleId.replace(/([A-Z])/g, " $1").replace(/[-_]+/g, " ").replace(/\s+/g, " ").trim();
|
|
10297
|
-
}
|
|
10298
|
-
function parseDepthRange(rawDepth, fieldName, defaultFrom = 1, defaultTo = 3) {
|
|
10299
|
-
if (typeof rawDepth !== "object" || rawDepth === null) {
|
|
10300
|
-
throw new Error(
|
|
10301
|
-
`${fieldName} must be a range object with optional "from" and/or "to" fields, received: ${JSON.stringify(rawDepth)}`
|
|
10302
|
-
);
|
|
10303
|
-
}
|
|
10304
|
-
const { from = defaultFrom, to = defaultTo } = rawDepth;
|
|
10305
|
-
if (from < 1 || from > 6 || to < 1 || to > 6) {
|
|
10306
|
-
throw new Error(
|
|
10307
|
-
`${fieldName} range values must be between 1 and 6, received: from=${from}, to=${to}`
|
|
10308
|
-
);
|
|
10309
|
-
}
|
|
10310
|
-
if (from > to) {
|
|
10311
|
-
throw new Error(
|
|
10312
|
-
`${fieldName} "from" must be less than or equal to "to", received: from=${from}, to=${to}`
|
|
10313
|
-
);
|
|
10314
|
-
}
|
|
10315
|
-
return { from, to };
|
|
10316
|
-
}
|
|
10317
|
-
function selectEntries(collected, options) {
|
|
10318
|
-
if (!collected || collected.length === 0) return [];
|
|
10319
|
-
const { depthStart, depthEnd, bookmarkScope, styleLevels } = options;
|
|
10320
|
-
const entries = [];
|
|
10321
|
-
for (const entry of collected) {
|
|
10322
|
-
if (bookmarkScope && entry.sectionBookmarkId !== bookmarkScope) continue;
|
|
10323
|
-
if (entry.styleId !== void 0) {
|
|
10324
|
-
const level = styleLevels.get(entry.styleId) ?? styleLevels.get(toStyleDisplayName(entry.styleId));
|
|
10325
|
-
if (level === void 0) continue;
|
|
10326
|
-
entries.push({ text: entry.title, level });
|
|
10327
|
-
continue;
|
|
10328
|
-
}
|
|
10329
|
-
if (entry.level < depthStart || entry.level > depthEnd) continue;
|
|
10330
|
-
entries.push({
|
|
10331
|
-
text: entry.number ? `${headingNumberLabel(entry.number)} ${entry.title}` : entry.title,
|
|
10332
|
-
level: entry.level
|
|
10333
|
-
});
|
|
10334
|
-
}
|
|
10335
|
-
return entries;
|
|
10336
|
-
}
|
|
10337
|
-
function resolveTocField(props, theme, context) {
|
|
10338
|
-
const warnings = [];
|
|
10339
|
-
const headingRange = parseDepthRange(
|
|
10340
|
-
props.depth ?? { to: 3 },
|
|
10341
|
-
"TOC depth",
|
|
10342
|
-
1,
|
|
10343
|
-
3
|
|
10344
|
-
);
|
|
10345
|
-
const pageNumbers = props.pageNumbersDepth !== void 0 ? parseDepthRange(props.pageNumbersDepth, "TOC pageNumbersDepth", 1, 3) : void 0;
|
|
10346
|
-
if (props.numberingStyle !== void 0) {
|
|
10347
|
-
warnings.push(
|
|
10348
|
-
`TOC numberingStyle "${props.numberingStyle}" is ignored: Word's table-of-contents field has no numbering switch. TOC entries inherit numbering from the heading styles they reference.`
|
|
10349
|
-
);
|
|
10350
|
-
}
|
|
10351
|
-
const scope = props.scope ?? "auto";
|
|
10352
|
-
const effectiveScope = scope === "auto" ? context.sectionBookmarkId ? "section" : "document" : scope;
|
|
10353
|
-
const bookmarkScope = effectiveScope === "section" ? context.sectionBookmarkId : void 0;
|
|
10354
|
-
if (effectiveScope === "section" && !bookmarkScope) {
|
|
10355
|
-
warnings.push(
|
|
10356
|
-
"TOC configured for section scope but no section bookmark found. Falling back to document scope."
|
|
10357
|
-
);
|
|
10358
|
-
}
|
|
10359
|
-
const styleLevels = /* @__PURE__ */ new Map();
|
|
10360
|
-
const styleSwitches = [];
|
|
10361
|
-
for (const mapping of props.styles ?? []) {
|
|
10362
|
-
const isCustomStyle = !!theme.styles && Object.prototype.hasOwnProperty.call(theme.styles, mapping.styleId);
|
|
10363
|
-
const displayName = isCustomStyle ? toStyleDisplayName(mapping.styleId) : mapping.styleId;
|
|
10364
|
-
styleLevels.set(mapping.styleId, mapping.level);
|
|
10365
|
-
styleLevels.set(displayName, mapping.level);
|
|
10366
|
-
styleSwitches.push({ styleName: displayName, level: mapping.level });
|
|
10367
|
-
}
|
|
10368
|
-
return {
|
|
10369
|
-
headingRange,
|
|
10370
|
-
styleLevels: styleSwitches,
|
|
10371
|
-
...bookmarkScope ? { bookmarkScope } : {},
|
|
10372
|
-
omitPageNumbersForLevels: omittedLevels(
|
|
10373
|
-
headingRange,
|
|
10374
|
-
pageNumbers,
|
|
10375
|
-
props.includePageNumbers !== false
|
|
10376
|
-
),
|
|
10377
|
-
// A boolean chooses between a tab and a space; a tab is the default.
|
|
10378
|
-
entrySeparator: props.numberSeparator === false ? " " : " ",
|
|
10379
|
-
entries: selectEntries(context.collected, {
|
|
10380
|
-
depthStart: headingRange.from,
|
|
10381
|
-
depthEnd: headingRange.to,
|
|
10382
|
-
bookmarkScope,
|
|
10383
|
-
styleLevels
|
|
10384
|
-
}),
|
|
10385
|
-
warnings
|
|
10352
|
+
...resolveWidths(
|
|
10353
|
+
source,
|
|
10354
|
+
columns,
|
|
10355
|
+
options.measureTwips ?? getAvailableWidthTwips(theme, themeName)
|
|
10356
|
+
),
|
|
10357
|
+
...hasHeader ? { header } : {},
|
|
10358
|
+
rows,
|
|
10359
|
+
repeatHeader: source.repeatHeaderOnPageBreak ?? true
|
|
10386
10360
|
};
|
|
10387
10361
|
}
|
|
10388
|
-
function
|
|
10389
|
-
|
|
10390
|
-
|
|
10391
|
-
|
|
10392
|
-
|
|
10393
|
-
|
|
10394
|
-
|
|
10395
|
-
|
|
10396
|
-
|
|
10397
|
-
|
|
10362
|
+
function drawsNothing(border3) {
|
|
10363
|
+
return border3.hidden || border3.size <= 0;
|
|
10364
|
+
}
|
|
10365
|
+
function channels(hex) {
|
|
10366
|
+
const digits = hex.startsWith("#") ? hex.slice(1) : hex;
|
|
10367
|
+
return [
|
|
10368
|
+
parseInt(digits.slice(0, 2), 16) || 0,
|
|
10369
|
+
parseInt(digits.slice(2, 4), 16) || 0,
|
|
10370
|
+
parseInt(digits.slice(4, 6), 16) || 0
|
|
10371
|
+
];
|
|
10372
|
+
}
|
|
10373
|
+
function outweighs(a, b) {
|
|
10374
|
+
if (drawsNothing(a)) return false;
|
|
10375
|
+
if (drawsNothing(b)) return true;
|
|
10376
|
+
if (a.size !== b.size) return a.size > b.size;
|
|
10377
|
+
const [redA, greenA, blueA] = channels(a.color);
|
|
10378
|
+
const [redB, greenB, blueB] = channels(b.color);
|
|
10379
|
+
const brightness = [
|
|
10380
|
+
[redA + blueA + 2 * greenA, redB + blueB + 2 * greenB],
|
|
10381
|
+
[blueA + 2 * greenA, blueB + 2 * greenB],
|
|
10382
|
+
[greenA, greenB]
|
|
10383
|
+
];
|
|
10384
|
+
for (const [ours, theirs] of brightness) {
|
|
10385
|
+
if (ours !== theirs) return ours < theirs;
|
|
10398
10386
|
}
|
|
10399
|
-
return
|
|
10387
|
+
return false;
|
|
10400
10388
|
}
|
|
10401
|
-
|
|
10402
|
-
|
|
10403
|
-
|
|
10404
|
-
|
|
10405
|
-
|
|
10406
|
-
let isUnordered = null;
|
|
10407
|
-
let isOrdered = null;
|
|
10408
|
-
for (const line of lines) {
|
|
10409
|
-
if (!line.trim()) continue;
|
|
10410
|
-
const unorderedMatch = line.match(/^(\s*)([-*])\s+(.+)$/);
|
|
10411
|
-
if (unorderedMatch) {
|
|
10412
|
-
const indentLevel = Math.floor(unorderedMatch[1].length / 2);
|
|
10413
|
-
const text2 = unorderedMatch[3];
|
|
10414
|
-
items.push({ text: text2, level: indentLevel });
|
|
10415
|
-
if (isUnordered === null) isUnordered = true;
|
|
10416
|
-
continue;
|
|
10417
|
-
}
|
|
10418
|
-
const orderedMatch = line.match(/^(\s*)(\d+)\.\s+(.+)$/);
|
|
10419
|
-
if (orderedMatch) {
|
|
10420
|
-
const indentLevel = Math.floor(orderedMatch[1].length / 2);
|
|
10421
|
-
const text2 = orderedMatch[3];
|
|
10422
|
-
items.push({ text: text2, level: indentLevel });
|
|
10423
|
-
if (isOrdered === null) isOrdered = true;
|
|
10424
|
-
continue;
|
|
10389
|
+
function adjudicateInteriorEdges(rows) {
|
|
10390
|
+
const settle = (earlier, later) => {
|
|
10391
|
+
if (drawsNothing(earlier) && drawsNothing(later)) return;
|
|
10392
|
+
if (earlier.hidden === later.hidden && earlier.size === later.size && earlier.color === later.color) {
|
|
10393
|
+
return;
|
|
10425
10394
|
}
|
|
10426
|
-
|
|
10427
|
-
|
|
10428
|
-
|
|
10429
|
-
|
|
10395
|
+
const winner = earlier.explicit !== later.explicit ? earlier.explicit ? earlier : later : outweighs(later, earlier) ? later : earlier;
|
|
10396
|
+
const loser = winner === earlier ? later : earlier;
|
|
10397
|
+
loser.size = winner.size;
|
|
10398
|
+
loser.color = winner.color;
|
|
10399
|
+
loser.hidden = winner.hidden;
|
|
10400
|
+
};
|
|
10401
|
+
rows.forEach((row, rowIndex) => {
|
|
10402
|
+
row.cells.forEach((cell, colIndex) => {
|
|
10403
|
+
const right = row.cells[colIndex + 1];
|
|
10404
|
+
if (right) settle(cell.borders.right, right.borders.left);
|
|
10405
|
+
const below = rows[rowIndex + 1]?.cells[colIndex];
|
|
10406
|
+
if (below) settle(cell.borders.bottom, below.borders.top);
|
|
10407
|
+
});
|
|
10408
|
+
});
|
|
10409
|
+
}
|
|
10410
|
+
function resolveWidths(source, columns, measureTwips) {
|
|
10411
|
+
const hasExplicitWidths = columns.some((col) => col.width !== void 0);
|
|
10412
|
+
if (!hasExplicitWidths) {
|
|
10413
|
+
const percent = source.width ?? 100;
|
|
10414
|
+
return {
|
|
10415
|
+
columnGrid: {
|
|
10416
|
+
unit: "twips",
|
|
10417
|
+
values: splitTwips(columns.length, measureTwips * percent / 100)
|
|
10418
|
+
},
|
|
10419
|
+
width: { size: percent, unit: "percent" }
|
|
10420
|
+
};
|
|
10430
10421
|
}
|
|
10422
|
+
const stated = columns.map(
|
|
10423
|
+
(col) => col.width !== void 0 ? relativeLengthToTwips(col.width, measureTwips) : void 0
|
|
10424
|
+
);
|
|
10425
|
+
const totalStated = stated.reduce((sum, w) => sum + (w ?? 0), 0);
|
|
10426
|
+
const unstatedCount = columns.filter((col) => col.width === void 0).length;
|
|
10427
|
+
const remaining = Math.max(0, measureTwips - totalStated);
|
|
10428
|
+
const shareOfRemainder = unstatedCount > 0 ? remaining / unstatedCount : pointsToTwips(72);
|
|
10429
|
+
const values = stated.map((w) => w || shareOfRemainder);
|
|
10431
10430
|
return {
|
|
10432
|
-
|
|
10433
|
-
|
|
10431
|
+
columnGrid: { unit: "twips", values },
|
|
10432
|
+
width: {
|
|
10433
|
+
size: values.reduce((sum, w) => sum + w, 0),
|
|
10434
|
+
unit: "twips"
|
|
10435
|
+
},
|
|
10436
|
+
...totalStated > measureTwips ? { overflow: { totalTwips: totalStated, availableTwips: measureTwips } } : {}
|
|
10434
10437
|
};
|
|
10435
10438
|
}
|
|
10436
10439
|
|
|
10437
|
-
// src/ir/
|
|
10438
|
-
|
|
10439
|
-
|
|
10440
|
-
|
|
10441
|
-
|
|
10442
|
-
|
|
10443
|
-
|
|
10444
|
-
|
|
10445
|
-
|
|
10446
|
-
|
|
10447
|
-
|
|
10448
|
-
|
|
10440
|
+
// src/ir/compiler.ts
|
|
10441
|
+
init_layoutUtils();
|
|
10442
|
+
|
|
10443
|
+
// src/utils/revisionUtils.ts
|
|
10444
|
+
var DEFAULT_REVISION_AUTHOR = "json-to-office";
|
|
10445
|
+
var DEFAULT_REVISION_DATE = "1970-01-01T00:00:00Z";
|
|
10446
|
+
|
|
10447
|
+
// src/utils/commentRegistry.ts
|
|
10448
|
+
var DEFAULT_COMMENT_AUTHOR = "json-to-office";
|
|
10449
|
+
var DEFAULT_COMMENT_DATE = "1970-01-01T00:00:00Z";
|
|
10450
|
+
|
|
10451
|
+
// src/ir/compiler.ts
|
|
10452
|
+
init_imageUtils();
|
|
10453
|
+
init_widthUtils();
|
|
10454
|
+
|
|
10455
|
+
// src/utils/numberingConfig.ts
|
|
10456
|
+
var HEADING_NUMBERING_REFERENCE = "jto-heading-numbering";
|
|
10457
|
+
function headingNumberLabel(number) {
|
|
10458
|
+
return `${number}.`;
|
|
10449
10459
|
}
|
|
10450
|
-
|
|
10451
|
-
|
|
10452
|
-
|
|
10453
|
-
|
|
10454
|
-
|
|
10455
|
-
|
|
10456
|
-
|
|
10457
|
-
const authored = text.includes(SENTINEL);
|
|
10458
|
-
if (!authored && !text.includes("\\")) return text;
|
|
10459
|
-
const guarded = authored ? text.split(SENTINEL).join(SENTINEL + SENTINEL_SELF) : text;
|
|
10460
|
-
return guarded.replace(
|
|
10461
|
-
ESCAPE,
|
|
10462
|
-
(_whole, char) => SENTINEL + String.fromCharCode(SENTINEL_DIGIT_BASE + ESCAPABLE.indexOf(char))
|
|
10463
|
-
);
|
|
10460
|
+
|
|
10461
|
+
// src/core/collectTocHeadings.ts
|
|
10462
|
+
import { getStandardComponent } from "@json-to-office/shared-docx";
|
|
10463
|
+
|
|
10464
|
+
// src/core/sectionBookmarks.ts
|
|
10465
|
+
function sectionBookmark(ordinal) {
|
|
10466
|
+
return { id: `_Section_${ordinal}`, linkId: ordinal };
|
|
10464
10467
|
}
|
|
10465
|
-
|
|
10466
|
-
|
|
10468
|
+
|
|
10469
|
+
// src/utils/numberFormatting.ts
|
|
10470
|
+
var ROMAN_NUMERALS = [
|
|
10471
|
+
[1e3, "m"],
|
|
10472
|
+
[900, "cm"],
|
|
10473
|
+
[500, "d"],
|
|
10474
|
+
[400, "cd"],
|
|
10475
|
+
[100, "c"],
|
|
10476
|
+
[90, "xc"],
|
|
10477
|
+
[50, "l"],
|
|
10478
|
+
[40, "xl"],
|
|
10479
|
+
[10, "x"],
|
|
10480
|
+
[9, "ix"],
|
|
10481
|
+
[5, "v"],
|
|
10482
|
+
[4, "iv"],
|
|
10483
|
+
[1, "i"]
|
|
10484
|
+
];
|
|
10485
|
+
function toRoman(value) {
|
|
10486
|
+
let remaining = value;
|
|
10467
10487
|
let out = "";
|
|
10468
|
-
for (
|
|
10469
|
-
|
|
10470
|
-
out +=
|
|
10471
|
-
|
|
10472
|
-
}
|
|
10473
|
-
const marker = text[i + 1];
|
|
10474
|
-
if (marker === SENTINEL_SELF) {
|
|
10475
|
-
out += SENTINEL;
|
|
10476
|
-
i += 1;
|
|
10477
|
-
continue;
|
|
10478
|
-
}
|
|
10479
|
-
const index = marker === void 0 ? -1 : marker.charCodeAt(0) - SENTINEL_DIGIT_BASE;
|
|
10480
|
-
if (index >= 0 && index < ESCAPABLE.length) {
|
|
10481
|
-
out += ESCAPABLE[index];
|
|
10482
|
-
i += 1;
|
|
10483
|
-
continue;
|
|
10488
|
+
for (const [amount, glyph] of ROMAN_NUMERALS) {
|
|
10489
|
+
while (remaining >= amount) {
|
|
10490
|
+
out += glyph;
|
|
10491
|
+
remaining -= amount;
|
|
10484
10492
|
}
|
|
10485
|
-
out += text[i];
|
|
10486
10493
|
}
|
|
10487
10494
|
return out;
|
|
10488
10495
|
}
|
|
10489
|
-
|
|
10490
|
-
|
|
10491
|
-
|
|
10492
|
-
|
|
10493
|
-
var CROSS_REFERENCE = /\[@([^\]\s:]+)(?::(relative|no_context|full_context|none))?\]/;
|
|
10494
|
-
var INLINE_TOKEN = new RegExp(
|
|
10495
|
-
`${LINK.source}|${CROSS_REFERENCE.source}`,
|
|
10496
|
-
"g"
|
|
10497
|
-
);
|
|
10498
|
-
var NOTE_MARKER = /\[\^([^\]\s]+)\]/g;
|
|
10499
|
-
function containsPlaceholder(text) {
|
|
10500
|
-
return PLACEHOLDER.test(text);
|
|
10496
|
+
function toLetters(value) {
|
|
10497
|
+
const index = (value - 1) % 26;
|
|
10498
|
+
const repeats = Math.floor((value - 1) / 26) + 1;
|
|
10499
|
+
return String.fromCharCode(97 + index).repeat(repeats);
|
|
10501
10500
|
}
|
|
10502
|
-
function
|
|
10503
|
-
|
|
10501
|
+
function formatNumberForLevel(value, format2) {
|
|
10502
|
+
if (!Number.isFinite(value) || value < 1) return void 0;
|
|
10503
|
+
const n = Math.floor(value);
|
|
10504
|
+
switch (format2) {
|
|
10505
|
+
case "decimal":
|
|
10506
|
+
return String(n);
|
|
10507
|
+
case "lowerLetter":
|
|
10508
|
+
return toLetters(n);
|
|
10509
|
+
case "upperLetter":
|
|
10510
|
+
return toLetters(n).toUpperCase();
|
|
10511
|
+
case "lowerRoman":
|
|
10512
|
+
return toRoman(n);
|
|
10513
|
+
case "upperRoman":
|
|
10514
|
+
return toRoman(n).toUpperCase();
|
|
10515
|
+
default:
|
|
10516
|
+
return void 0;
|
|
10517
|
+
}
|
|
10518
|
+
}
|
|
10519
|
+
|
|
10520
|
+
// src/core/collectTocHeadings.ts
|
|
10521
|
+
var MAX_HEADING_LEVEL = 6;
|
|
10522
|
+
var MAX_LIST_LEVEL = 9;
|
|
10523
|
+
function normalizeEntryTitle(text) {
|
|
10524
|
+
return normalizeUnicodeText(text).replace(/(\*\*\*|___)([\s\S]*?)\1/g, "$2").replace(/(\*\*|__)([\s\S]*?)\1/g, "$2").replace(/(\*|_)([\s\S]*?)\1/g, "$2").trim();
|
|
10525
|
+
}
|
|
10526
|
+
function isContainer(name) {
|
|
10527
|
+
return getStandardComponent(name)?.hasChildren === true;
|
|
10504
10528
|
}
|
|
10505
|
-
function
|
|
10506
|
-
return
|
|
10529
|
+
function isEnabled(component) {
|
|
10530
|
+
return !("enabled" in component && component.enabled === false);
|
|
10507
10531
|
}
|
|
10508
|
-
function
|
|
10509
|
-
|
|
10510
|
-
|
|
10532
|
+
function styleEntryKey(props) {
|
|
10533
|
+
const themeStyle = props.themeStyle;
|
|
10534
|
+
if (typeof themeStyle !== "string" || !themeStyle) return void 0;
|
|
10535
|
+
if (/^heading[1-6]$/i.test(themeStyle)) return void 0;
|
|
10536
|
+
if (["normal", "title", "subtitle"].includes(themeStyle.toLowerCase())) {
|
|
10537
|
+
return void 0;
|
|
10511
10538
|
}
|
|
10512
|
-
return
|
|
10539
|
+
return themeStyle;
|
|
10513
10540
|
}
|
|
10514
|
-
function
|
|
10515
|
-
|
|
10516
|
-
if (!normalized) {
|
|
10517
|
-
return [
|
|
10518
|
-
{ kind: "text", text: "", formatting: emptyToUndefined(options.base) }
|
|
10519
|
-
];
|
|
10520
|
-
}
|
|
10521
|
-
if (containsPlaceholder(normalized)) {
|
|
10522
|
-
return parsePlaceholders(normalized, options);
|
|
10523
|
-
}
|
|
10524
|
-
if (options.hyperlinks) return parseLinks(normalized, options);
|
|
10525
|
-
return parseDecorated(normalized, options);
|
|
10541
|
+
function levelStart(levels, level) {
|
|
10542
|
+
return levels[level]?.start ?? 1;
|
|
10526
10543
|
}
|
|
10527
|
-
function
|
|
10528
|
-
const
|
|
10529
|
-
|
|
10530
|
-
|
|
10531
|
-
|
|
10532
|
-
|
|
10533
|
-
const
|
|
10534
|
-
const
|
|
10535
|
-
|
|
10536
|
-
|
|
10537
|
-
|
|
10538
|
-
|
|
10539
|
-
|
|
10544
|
+
function collectDocumentOutline(sections) {
|
|
10545
|
+
const entries = [];
|
|
10546
|
+
const numberedItems = /* @__PURE__ */ new Map();
|
|
10547
|
+
const ordinals = computeSectionOrdinals(sections);
|
|
10548
|
+
const takenIds = /* @__PURE__ */ new Set();
|
|
10549
|
+
const headingCounters = new Array(MAX_HEADING_LEVEL).fill(0);
|
|
10550
|
+
const listCounters = /* @__PURE__ */ new Map();
|
|
10551
|
+
const visitHeading = (component, props, sectionBookmarkId) => {
|
|
10552
|
+
const text = typeof props.text === "string" ? props.text : "";
|
|
10553
|
+
const title = normalizeEntryTitle(text);
|
|
10554
|
+
const level = typeof props.level === "number" ? props.level : 1;
|
|
10555
|
+
const styleLevel = level >= 1 && level <= MAX_HEADING_LEVEL ? level : 1;
|
|
10556
|
+
let full;
|
|
10557
|
+
let own;
|
|
10558
|
+
if (props.numbering === true) {
|
|
10559
|
+
headingCounters[styleLevel - 1] += 1;
|
|
10560
|
+
for (let deeper = styleLevel; deeper < MAX_HEADING_LEVEL; deeper++) {
|
|
10561
|
+
headingCounters[deeper] = 0;
|
|
10562
|
+
}
|
|
10563
|
+
full = headingCounters.slice(0, styleLevel).join(".");
|
|
10564
|
+
own = String(headingCounters[styleLevel - 1]);
|
|
10565
|
+
}
|
|
10566
|
+
const explicitId = component.id;
|
|
10567
|
+
const bookmarkId = typeof explicitId === "string" && explicitId ? explicitId : dedupeBookmarkId(slugifyBookmarkText(text), (id) => takenIds.has(id));
|
|
10568
|
+
takenIds.add(bookmarkId);
|
|
10569
|
+
numberedItems.set(bookmarkId, {
|
|
10570
|
+
kind: "heading",
|
|
10571
|
+
text: title,
|
|
10572
|
+
...full !== void 0 && { full, own }
|
|
10573
|
+
});
|
|
10574
|
+
if (title) {
|
|
10575
|
+
entries.push({
|
|
10576
|
+
title,
|
|
10577
|
+
level,
|
|
10578
|
+
sectionBookmarkId,
|
|
10579
|
+
...full !== void 0 && { number: full }
|
|
10580
|
+
});
|
|
10581
|
+
}
|
|
10540
10582
|
};
|
|
10541
|
-
|
|
10542
|
-
|
|
10543
|
-
|
|
10583
|
+
const visitList = (props) => {
|
|
10584
|
+
const items = Array.isArray(props.items) ? props.items : [];
|
|
10585
|
+
if (items.length === 0) return;
|
|
10586
|
+
const reference = typeof props.reference === "string" && props.reference ? props.reference : void 0;
|
|
10587
|
+
const freshState = () => {
|
|
10588
|
+
const levels = resolveListLevels(
|
|
10589
|
+
props
|
|
10590
|
+
);
|
|
10591
|
+
return {
|
|
10592
|
+
levels,
|
|
10593
|
+
counters: Array.from(
|
|
10594
|
+
{ length: MAX_LIST_LEVEL },
|
|
10595
|
+
(_, level) => levelStart(levels, level) - 1
|
|
10596
|
+
)
|
|
10597
|
+
};
|
|
10598
|
+
};
|
|
10599
|
+
let state;
|
|
10600
|
+
if (reference === void 0) {
|
|
10601
|
+
state = freshState();
|
|
10602
|
+
} else {
|
|
10603
|
+
state = listCounters.get(reference) ?? freshState();
|
|
10604
|
+
listCounters.set(reference, state);
|
|
10544
10605
|
}
|
|
10545
|
-
|
|
10546
|
-
|
|
10547
|
-
const
|
|
10548
|
-
|
|
10549
|
-
|
|
10550
|
-
|
|
10551
|
-
|
|
10552
|
-
|
|
10553
|
-
|
|
10554
|
-
|
|
10555
|
-
|
|
10556
|
-
color: options.base.color,
|
|
10557
|
-
bold: options.base.bold,
|
|
10558
|
-
italic: options.base.italic,
|
|
10559
|
-
underline: options.base.underline
|
|
10560
|
-
});
|
|
10561
|
-
out.push({
|
|
10562
|
-
kind: "field",
|
|
10563
|
-
instruction: resolved.instruction,
|
|
10564
|
-
...resolved.cachedText !== void 0 && {
|
|
10565
|
-
cachedText: resolved.cachedText
|
|
10566
|
-
},
|
|
10567
|
-
...formatting ? { formatting } : {}
|
|
10568
|
-
});
|
|
10606
|
+
for (const item of items) {
|
|
10607
|
+
const isObject = typeof item === "object" && item !== null;
|
|
10608
|
+
const raw = isObject ? item.text : item;
|
|
10609
|
+
const text = typeof raw === "string" ? raw : "";
|
|
10610
|
+
if (!text.trim() && !(isObject && item.revision)) continue;
|
|
10611
|
+
const rawLevel = isObject ? item.level : void 0;
|
|
10612
|
+
const level = typeof rawLevel === "number" && rawLevel >= 0 ? rawLevel : 0;
|
|
10613
|
+
if (level >= MAX_LIST_LEVEL) continue;
|
|
10614
|
+
state.counters[level] += 1;
|
|
10615
|
+
for (let deeper = level + 1; deeper < MAX_LIST_LEVEL; deeper++) {
|
|
10616
|
+
state.counters[deeper] = levelStart(state.levels, deeper) - 1;
|
|
10569
10617
|
}
|
|
10570
|
-
|
|
10618
|
+
const id = isObject ? item.id : void 0;
|
|
10619
|
+
if (typeof id !== "string" || !id) continue;
|
|
10620
|
+
takenIds.add(id);
|
|
10621
|
+
const number = formatNumberForLevel(
|
|
10622
|
+
state.counters[level],
|
|
10623
|
+
state.levels[level]?.format
|
|
10624
|
+
);
|
|
10625
|
+
numberedItems.set(id, {
|
|
10626
|
+
kind: "list-item",
|
|
10627
|
+
text: normalizeUnicodeText(text).trim(),
|
|
10628
|
+
...number !== void 0 && { full: number, own: number }
|
|
10629
|
+
});
|
|
10571
10630
|
}
|
|
10572
|
-
|
|
10573
|
-
|
|
10574
|
-
|
|
10575
|
-
|
|
10576
|
-
|
|
10577
|
-
|
|
10578
|
-
|
|
10579
|
-
|
|
10580
|
-
|
|
10581
|
-
|
|
10582
|
-
|
|
10583
|
-
|
|
10584
|
-
|
|
10585
|
-
|
|
10631
|
+
};
|
|
10632
|
+
sections.forEach((section2, index) => {
|
|
10633
|
+
const ordinal = ordinals[index]?.ordinal;
|
|
10634
|
+
const sectionBookmarkId = ordinal ? sectionBookmark(ordinal).id : void 0;
|
|
10635
|
+
const visit = (component) => {
|
|
10636
|
+
if (!isEnabled(component)) return;
|
|
10637
|
+
const props = component.props ?? {};
|
|
10638
|
+
if (component.name === "heading") {
|
|
10639
|
+
visitHeading(component, props, sectionBookmarkId);
|
|
10640
|
+
return;
|
|
10641
|
+
}
|
|
10642
|
+
if (component.name === "paragraph") {
|
|
10643
|
+
if (typeof props.id === "string" && props.id) takenIds.add(props.id);
|
|
10644
|
+
const styleId = styleEntryKey(props);
|
|
10645
|
+
const text = typeof props.text === "string" ? props.text : "";
|
|
10646
|
+
const title = normalizeEntryTitle(text);
|
|
10647
|
+
if (styleId && title) {
|
|
10648
|
+
entries.push({ title, level: 1, styleId, sectionBookmarkId });
|
|
10649
|
+
}
|
|
10650
|
+
return;
|
|
10651
|
+
}
|
|
10652
|
+
if (component.name === "list") {
|
|
10653
|
+
visitList(props);
|
|
10654
|
+
return;
|
|
10655
|
+
}
|
|
10656
|
+
if (!isContainer(component.name)) return;
|
|
10657
|
+
const children = component.children;
|
|
10658
|
+
if (Array.isArray(children)) children.forEach(visit);
|
|
10659
|
+
};
|
|
10660
|
+
section2.components.forEach(visit);
|
|
10661
|
+
});
|
|
10662
|
+
return { entries, numberedItems };
|
|
10586
10663
|
}
|
|
10587
|
-
|
|
10588
|
-
|
|
10589
|
-
|
|
10590
|
-
return
|
|
10664
|
+
|
|
10665
|
+
// src/core/tocField.ts
|
|
10666
|
+
function toStyleDisplayName(styleId) {
|
|
10667
|
+
return styleId.replace(/([A-Z])/g, " $1").replace(/[-_]+/g, " ").replace(/\s+/g, " ").trim();
|
|
10591
10668
|
}
|
|
10592
|
-
function
|
|
10593
|
-
|
|
10594
|
-
|
|
10595
|
-
|
|
10596
|
-
|
|
10597
|
-
|
|
10598
|
-
|
|
10599
|
-
)
|
|
10600
|
-
|
|
10669
|
+
function parseDepthRange(rawDepth, fieldName, defaultFrom = 1, defaultTo = 3) {
|
|
10670
|
+
if (typeof rawDepth !== "object" || rawDepth === null) {
|
|
10671
|
+
throw new Error(
|
|
10672
|
+
`${fieldName} must be a range object with optional "from" and/or "to" fields, received: ${JSON.stringify(rawDepth)}`
|
|
10673
|
+
);
|
|
10674
|
+
}
|
|
10675
|
+
const { from = defaultFrom, to = defaultTo } = rawDepth;
|
|
10676
|
+
if (from < 1 || from > 6 || to < 1 || to > 6) {
|
|
10677
|
+
throw new Error(
|
|
10678
|
+
`${fieldName} range values must be between 1 and 6, received: from=${from}, to=${to}`
|
|
10679
|
+
);
|
|
10680
|
+
}
|
|
10681
|
+
if (from > to) {
|
|
10682
|
+
throw new Error(
|
|
10683
|
+
`${fieldName} "from" must be less than or equal to "to", received: from=${from}, to=${to}`
|
|
10684
|
+
);
|
|
10685
|
+
}
|
|
10686
|
+
return { from, to };
|
|
10601
10687
|
}
|
|
10602
|
-
function
|
|
10603
|
-
|
|
10604
|
-
const
|
|
10605
|
-
|
|
10606
|
-
|
|
10607
|
-
|
|
10608
|
-
if (
|
|
10609
|
-
|
|
10610
|
-
|
|
10611
|
-
);
|
|
10612
|
-
}
|
|
10613
|
-
lastIndex = match.index + match[0].length;
|
|
10614
|
-
if (match[1] === void 0) {
|
|
10615
|
-
const resolved = options.resolveCrossReference?.(
|
|
10616
|
-
decodeEscapes(match[3]),
|
|
10617
|
-
match[4] ?? "relative",
|
|
10618
|
-
match[0]
|
|
10619
|
-
);
|
|
10620
|
-
if (resolved) out.push(resolved);
|
|
10621
|
-
else out.push(...parseDecorated(match[0], options));
|
|
10688
|
+
function selectEntries(collected, options) {
|
|
10689
|
+
if (!collected || collected.length === 0) return [];
|
|
10690
|
+
const { depthStart, depthEnd, bookmarkScope, styleLevels } = options;
|
|
10691
|
+
const entries = [];
|
|
10692
|
+
for (const entry of collected) {
|
|
10693
|
+
if (bookmarkScope && entry.sectionBookmarkId !== bookmarkScope) continue;
|
|
10694
|
+
if (entry.styleId !== void 0) {
|
|
10695
|
+
const level = styleLevels.get(entry.styleId) ?? styleLevels.get(toStyleDisplayName(entry.styleId));
|
|
10696
|
+
if (level === void 0) continue;
|
|
10697
|
+
entries.push({ text: entry.title, level });
|
|
10622
10698
|
continue;
|
|
10623
10699
|
}
|
|
10624
|
-
|
|
10625
|
-
|
|
10626
|
-
|
|
10627
|
-
|
|
10628
|
-
// A `#anchor` target names a bookmark in this document and needs no
|
|
10629
|
-
// relationship; anything else leaves the document.
|
|
10630
|
-
target: target2.startsWith("#") ? { kind: "bookmark", anchor: target2.slice(1) } : { kind: "external", url: target2 },
|
|
10631
|
-
children: parseDecorated(linkText, options)
|
|
10700
|
+
if (entry.level < depthStart || entry.level > depthEnd) continue;
|
|
10701
|
+
entries.push({
|
|
10702
|
+
text: entry.number ? `${headingNumberLabel(entry.number)} ${entry.title}` : entry.title,
|
|
10703
|
+
level: entry.level
|
|
10632
10704
|
});
|
|
10633
10705
|
}
|
|
10634
|
-
|
|
10635
|
-
out.push(...parseDecorated(normalized.slice(lastIndex), options));
|
|
10636
|
-
}
|
|
10637
|
-
if (out.length === 0) return parseDecorated(normalized, options);
|
|
10638
|
-
return out;
|
|
10706
|
+
return entries;
|
|
10639
10707
|
}
|
|
10640
|
-
function
|
|
10641
|
-
const
|
|
10642
|
-
|
|
10643
|
-
|
|
10644
|
-
|
|
10645
|
-
|
|
10646
|
-
|
|
10647
|
-
|
|
10648
|
-
|
|
10649
|
-
|
|
10650
|
-
|
|
10651
|
-
|
|
10652
|
-
options,
|
|
10653
|
-
decoratedStyle(match, options.base)
|
|
10708
|
+
function resolveTocField(props, theme, context) {
|
|
10709
|
+
const warnings = [];
|
|
10710
|
+
const headingRange = parseDepthRange(
|
|
10711
|
+
props.depth ?? { to: 3 },
|
|
10712
|
+
"TOC depth",
|
|
10713
|
+
1,
|
|
10714
|
+
3
|
|
10715
|
+
);
|
|
10716
|
+
const pageNumbers = props.pageNumbersDepth !== void 0 ? parseDepthRange(props.pageNumbersDepth, "TOC pageNumbersDepth", 1, 3) : void 0;
|
|
10717
|
+
if (props.numberingStyle !== void 0) {
|
|
10718
|
+
warnings.push(
|
|
10719
|
+
`TOC numberingStyle "${props.numberingStyle}" is ignored: Word's table-of-contents field has no numbering switch. TOC entries inherit numbering from the heading styles they reference.`
|
|
10654
10720
|
);
|
|
10655
|
-
lastIndex = match.index + match[0].length;
|
|
10656
10721
|
}
|
|
10657
|
-
|
|
10658
|
-
|
|
10722
|
+
const scope = props.scope ?? "auto";
|
|
10723
|
+
const effectiveScope = scope === "auto" ? context.sectionBookmarkId ? "section" : "document" : scope;
|
|
10724
|
+
const bookmarkScope = effectiveScope === "section" ? context.sectionBookmarkId : void 0;
|
|
10725
|
+
if (effectiveScope === "section" && !bookmarkScope) {
|
|
10726
|
+
warnings.push(
|
|
10727
|
+
"TOC configured for section scope but no section bookmark found. Falling back to document scope."
|
|
10728
|
+
);
|
|
10659
10729
|
}
|
|
10660
|
-
|
|
10661
|
-
|
|
10662
|
-
|
|
10663
|
-
|
|
10664
|
-
|
|
10665
|
-
|
|
10666
|
-
|
|
10667
|
-
|
|
10668
|
-
}
|
|
10669
|
-
|
|
10670
|
-
|
|
10671
|
-
|
|
10672
|
-
|
|
10673
|
-
|
|
10674
|
-
|
|
10675
|
-
|
|
10730
|
+
const styleLevels = /* @__PURE__ */ new Map();
|
|
10731
|
+
const styleSwitches = [];
|
|
10732
|
+
for (const mapping of props.styles ?? []) {
|
|
10733
|
+
const isCustomStyle = !!theme.styles && Object.prototype.hasOwnProperty.call(theme.styles, mapping.styleId);
|
|
10734
|
+
const displayName = isCustomStyle ? toStyleDisplayName(mapping.styleId) : mapping.styleId;
|
|
10735
|
+
styleLevels.set(mapping.styleId, mapping.level);
|
|
10736
|
+
styleLevels.set(displayName, mapping.level);
|
|
10737
|
+
styleSwitches.push({ styleName: displayName, level: mapping.level });
|
|
10738
|
+
}
|
|
10739
|
+
return {
|
|
10740
|
+
headingRange,
|
|
10741
|
+
styleLevels: styleSwitches,
|
|
10742
|
+
...bookmarkScope ? { bookmarkScope } : {},
|
|
10743
|
+
omitPageNumbersForLevels: omittedLevels(
|
|
10744
|
+
headingRange,
|
|
10745
|
+
pageNumbers,
|
|
10746
|
+
props.includePageNumbers !== false
|
|
10747
|
+
),
|
|
10748
|
+
// A boolean chooses between a tab and a space; a tab is the default.
|
|
10749
|
+
entrySeparator: props.numberSeparator === false ? " " : " ",
|
|
10750
|
+
entries: selectEntries(context.collected, {
|
|
10751
|
+
depthStart: headingRange.from,
|
|
10752
|
+
depthEnd: headingRange.to,
|
|
10753
|
+
bookmarkScope,
|
|
10754
|
+
styleLevels
|
|
10755
|
+
}),
|
|
10756
|
+
warnings
|
|
10757
|
+
};
|
|
10676
10758
|
}
|
|
10677
|
-
function
|
|
10678
|
-
|
|
10679
|
-
|
|
10680
|
-
|
|
10681
|
-
|
|
10682
|
-
for (const [lineIndex, line] of lines.entries()) {
|
|
10683
|
-
if (!line && lineIndex === 0) continue;
|
|
10684
|
-
if (lineIndex > 0) out.push({ kind: "lineBreak" });
|
|
10685
|
-
if (!line) {
|
|
10686
|
-
out.push({ kind: "text", text: "", formatting });
|
|
10687
|
-
continue;
|
|
10759
|
+
function omittedLevels(headingRange, pageNumbers, includePageNumbers) {
|
|
10760
|
+
if (pageNumbers) {
|
|
10761
|
+
const omitted = [];
|
|
10762
|
+
if (pageNumbers.from > headingRange.from) {
|
|
10763
|
+
omitted.push({ from: headingRange.from, to: pageNumbers.from - 1 });
|
|
10688
10764
|
}
|
|
10689
|
-
|
|
10690
|
-
|
|
10691
|
-
if (tabIndex > 0) out.push({ kind: "tab", formatting });
|
|
10692
|
-
if (!segment && tabSegments.length > 1) continue;
|
|
10693
|
-
pushWords(out, segment, formatting, options);
|
|
10765
|
+
if (pageNumbers.to < headingRange.to) {
|
|
10766
|
+
omitted.push({ from: pageNumbers.to + 1, to: headingRange.to });
|
|
10694
10767
|
}
|
|
10768
|
+
return omitted;
|
|
10695
10769
|
}
|
|
10770
|
+
return includePageNumbers ? [] : [headingRange];
|
|
10696
10771
|
}
|
|
10697
|
-
|
|
10698
|
-
|
|
10699
|
-
|
|
10700
|
-
|
|
10701
|
-
|
|
10702
|
-
|
|
10703
|
-
|
|
10704
|
-
|
|
10705
|
-
|
|
10706
|
-
|
|
10707
|
-
|
|
10708
|
-
|
|
10709
|
-
|
|
10710
|
-
|
|
10711
|
-
|
|
10712
|
-
pending += text.slice(lastIndex, regex.lastIndex);
|
|
10713
|
-
lastIndex = regex.lastIndex;
|
|
10772
|
+
|
|
10773
|
+
// src/core/markdownList.ts
|
|
10774
|
+
function parseMarkdownList(text) {
|
|
10775
|
+
const lines = text.split("\n");
|
|
10776
|
+
const items = [];
|
|
10777
|
+
let isUnordered = null;
|
|
10778
|
+
let isOrdered = null;
|
|
10779
|
+
for (const line of lines) {
|
|
10780
|
+
if (!line.trim()) continue;
|
|
10781
|
+
const unorderedMatch = line.match(/^(\s*)([-*])\s+(.+)$/);
|
|
10782
|
+
if (unorderedMatch) {
|
|
10783
|
+
const indentLevel = Math.floor(unorderedMatch[1].length / 2);
|
|
10784
|
+
const text2 = unorderedMatch[3];
|
|
10785
|
+
items.push({ text: text2, level: indentLevel });
|
|
10786
|
+
if (isUnordered === null) isUnordered = true;
|
|
10714
10787
|
continue;
|
|
10715
10788
|
}
|
|
10716
|
-
const
|
|
10717
|
-
|
|
10718
|
-
|
|
10719
|
-
|
|
10720
|
-
|
|
10721
|
-
|
|
10722
|
-
|
|
10723
|
-
});
|
|
10724
|
-
lastIndex = regex.lastIndex;
|
|
10725
|
-
}
|
|
10726
|
-
const rest = pending + text.slice(lastIndex);
|
|
10727
|
-
if (rest) pushNoProofWords(out, rest, formatting, options);
|
|
10728
|
-
}
|
|
10729
|
-
function pushNoProofWords(out, text, formatting, options) {
|
|
10730
|
-
const wholeRunNoProof = options.base.noProof === true;
|
|
10731
|
-
const regex = wholeRunNoProof ? null : buildNoProofWordsRegex(options.noProofWords);
|
|
10732
|
-
if (!regex) {
|
|
10733
|
-
out.push({ kind: "text", text, formatting });
|
|
10734
|
-
return;
|
|
10735
|
-
}
|
|
10736
|
-
let lastIndex = 0;
|
|
10737
|
-
let match;
|
|
10738
|
-
while ((match = regex.exec(text)) !== null) {
|
|
10739
|
-
if (match.index > lastIndex) {
|
|
10740
|
-
out.push({
|
|
10741
|
-
kind: "text",
|
|
10742
|
-
text: text.slice(lastIndex, match.index),
|
|
10743
|
-
formatting
|
|
10744
|
-
});
|
|
10789
|
+
const orderedMatch = line.match(/^(\s*)(\d+)\.\s+(.+)$/);
|
|
10790
|
+
if (orderedMatch) {
|
|
10791
|
+
const indentLevel = Math.floor(orderedMatch[1].length / 2);
|
|
10792
|
+
const text2 = orderedMatch[3];
|
|
10793
|
+
items.push({ text: text2, level: indentLevel });
|
|
10794
|
+
if (isOrdered === null) isOrdered = true;
|
|
10795
|
+
continue;
|
|
10745
10796
|
}
|
|
10746
|
-
|
|
10747
|
-
kind: "text",
|
|
10748
|
-
text: match[0],
|
|
10749
|
-
formatting: { ...formatting, noProof: true }
|
|
10750
|
-
});
|
|
10751
|
-
lastIndex = match.index + match[0].length;
|
|
10752
|
-
if (regex.lastIndex === match.index) regex.lastIndex += 1;
|
|
10753
|
-
}
|
|
10754
|
-
if (lastIndex < text.length) {
|
|
10755
|
-
out.push({ kind: "text", text: text.slice(lastIndex), formatting });
|
|
10797
|
+
return null;
|
|
10756
10798
|
}
|
|
10757
|
-
|
|
10758
|
-
|
|
10759
|
-
const formatting = { ...options.base };
|
|
10760
|
-
if (state.bold !== void 0) formatting.bold = state.bold;
|
|
10761
|
-
if (state.italic !== void 0) formatting.italic = state.italic;
|
|
10762
|
-
if (state.bold && options.boldColor && options.base.color) {
|
|
10763
|
-
formatting.color = options.boldColor;
|
|
10799
|
+
if (items.length === 0 || isUnordered && isOrdered) {
|
|
10800
|
+
return null;
|
|
10764
10801
|
}
|
|
10765
|
-
return
|
|
10766
|
-
|
|
10767
|
-
|
|
10768
|
-
|
|
10769
|
-
([, value]) => value !== void 0
|
|
10770
|
-
);
|
|
10771
|
-
return entries.length === 0 ? void 0 : Object.fromEntries(entries);
|
|
10802
|
+
return {
|
|
10803
|
+
type: isUnordered ? "unordered" : "ordered",
|
|
10804
|
+
items
|
|
10805
|
+
};
|
|
10772
10806
|
}
|
|
10773
10807
|
|
|
10774
10808
|
// src/ir/compiler.ts
|
|
@@ -11012,6 +11046,10 @@ function noProofWords(theme) {
|
|
|
11012
11046
|
const words = theme.noProofWords;
|
|
11013
11047
|
return words && words.length > 0 ? words : void 0;
|
|
11014
11048
|
}
|
|
11049
|
+
function plainRuns(text, ctx, formatting) {
|
|
11050
|
+
const words = noProofWords(ctx.theme);
|
|
11051
|
+
return words && text ? noProofRuns(text, formatting, words) : [{ kind: "text", text, ...formatting ? { formatting } : {} }];
|
|
11052
|
+
}
|
|
11015
11053
|
function mergeNoProofWords(themeWords, componentWords) {
|
|
11016
11054
|
const own = Array.isArray(componentWords) ? componentWords : [];
|
|
11017
11055
|
const merged = [...themeWords ?? [], ...own];
|
|
@@ -11370,7 +11408,8 @@ function compileParagraph(component, scope) {
|
|
|
11370
11408
|
...props.alignment ? { alignment: props.alignment } : {},
|
|
11371
11409
|
...props.comment ? { comment: props.comment } : {},
|
|
11372
11410
|
...props.footnotes ? { footnotes: props.footnotes } : {},
|
|
11373
|
-
...props.endnotes ? { endnotes: props.endnotes } : {}
|
|
11411
|
+
...props.endnotes ? { endnotes: props.endnotes } : {},
|
|
11412
|
+
...props.noProofWords ? { noProofWords: props.noProofWords } : {}
|
|
11374
11413
|
}
|
|
11375
11414
|
},
|
|
11376
11415
|
scope,
|
|
@@ -11884,13 +11923,10 @@ function compileToc(component, scope) {
|
|
|
11884
11923
|
// No style, not even Normal: a title with an outline level would collect
|
|
11885
11924
|
// itself into the very list it introduces. It carries its own weight and
|
|
11886
11925
|
// size instead.
|
|
11887
|
-
children:
|
|
11888
|
-
|
|
11889
|
-
|
|
11890
|
-
|
|
11891
|
-
formatting: { bold: true, sizeHalfPoints: 28 }
|
|
11892
|
-
}
|
|
11893
|
-
],
|
|
11926
|
+
children: plainRuns(String(props.title), ctx, {
|
|
11927
|
+
bold: true,
|
|
11928
|
+
sizeHalfPoints: 28
|
|
11929
|
+
}),
|
|
11894
11930
|
formatting: {
|
|
11895
11931
|
alignment: "left",
|
|
11896
11932
|
spacing: {
|
|
@@ -12078,7 +12114,7 @@ function compileStatistic(component, scope) {
|
|
|
12078
12114
|
...spacing ? { spacing } : {}
|
|
12079
12115
|
}),
|
|
12080
12116
|
line(
|
|
12081
|
-
descriptionText ?
|
|
12117
|
+
descriptionText ? plainRuns(descriptionText, ctx) : [],
|
|
12082
12118
|
STATISTIC_DESCRIPTION_STYLE_ID,
|
|
12083
12119
|
"description",
|
|
12084
12120
|
{ alignment: alignment2 }
|
|
@@ -12096,6 +12132,7 @@ function compileList(component, scope, referencePrefix = "list", explicitLevels)
|
|
|
12096
12132
|
ctx
|
|
12097
12133
|
);
|
|
12098
12134
|
const notes = createNoteBinding(props.footnotes, props.endnotes, ctx);
|
|
12135
|
+
const words = mergeNoProofWords(noProofWords(ctx.theme), props.noProofWords);
|
|
12099
12136
|
const reference = declareNumbering(
|
|
12100
12137
|
props,
|
|
12101
12138
|
ctx,
|
|
@@ -12132,10 +12169,11 @@ function compileList(component, scope, referencePrefix = "list", explicitLevels)
|
|
|
12132
12169
|
revision === void 0 ? parseInline(text, {
|
|
12133
12170
|
base,
|
|
12134
12171
|
hyperlinks: true,
|
|
12172
|
+
...words ? { noProofWords: words } : {},
|
|
12135
12173
|
...notes ? { resolveNote: notes.resolve } : {},
|
|
12136
12174
|
resolvePlaceholder: placeholderResolver(ctx),
|
|
12137
12175
|
resolveCrossReference: crossReferenceResolver(ctx, itemPath)
|
|
12138
|
-
}) : compileRevision(revision, base, ctx),
|
|
12176
|
+
}) : compileRevision(revision, base, ctx, words),
|
|
12139
12177
|
{
|
|
12140
12178
|
styleId: "Normal",
|
|
12141
12179
|
formatting: {
|
|
@@ -12305,7 +12343,7 @@ function compileRuns(props, text, ctx, path4, mode = "inline") {
|
|
|
12305
12343
|
ctx.features.require("revisions", path4);
|
|
12306
12344
|
return [
|
|
12307
12345
|
...props.columnBreak ? [{ kind: "columnBreak" }] : [],
|
|
12308
|
-
...compileRevision(props.revision, base, ctx)
|
|
12346
|
+
...compileRevision(props.revision, base, ctx, words)
|
|
12309
12347
|
];
|
|
12310
12348
|
}
|
|
12311
12349
|
const parseOptions = {
|
|
@@ -12428,7 +12466,7 @@ function createNoteBinding(footnotes, endnotes, ctx) {
|
|
|
12428
12466
|
id: `${note.endnote ? "endnote" : "footnote"}${resolved.id}:p${index}`,
|
|
12429
12467
|
path: `${note.endnote ? "endnotes" : "footnotes"}[${resolved.id}].children[${index}]`,
|
|
12430
12468
|
styleId: note.endnote ? "EndnoteText" : "FootnoteText",
|
|
12431
|
-
children:
|
|
12469
|
+
children: plainRuns(line, ctx)
|
|
12432
12470
|
}))
|
|
12433
12471
|
});
|
|
12434
12472
|
registered.set(id, resolved);
|
|
@@ -12481,7 +12519,7 @@ function declareComment(comment, ctx, path4) {
|
|
|
12481
12519
|
kind: "paragraph",
|
|
12482
12520
|
id: `comment${id}:p${index}`,
|
|
12483
12521
|
path: `comments[${id}].children[${index}]`,
|
|
12484
|
-
children:
|
|
12522
|
+
children: plainRuns(line, ctx)
|
|
12485
12523
|
})),
|
|
12486
12524
|
...parentId !== void 0 ? { parentId } : {},
|
|
12487
12525
|
...resolved !== void 0 ? { resolved } : {}
|
|
@@ -12507,7 +12545,7 @@ function closeComment(ids) {
|
|
|
12507
12545
|
{ kind: "commentReference", id }
|
|
12508
12546
|
]);
|
|
12509
12547
|
}
|
|
12510
|
-
function compileRevision(revision, base, ctx) {
|
|
12548
|
+
function compileRevision(revision, base, ctx, words = noProofWords(ctx.theme)) {
|
|
12511
12549
|
const author = revision.author || DEFAULT_REVISION_AUTHOR;
|
|
12512
12550
|
const date = revision.date || DEFAULT_REVISION_DATE;
|
|
12513
12551
|
const out = [];
|
|
@@ -12515,15 +12553,17 @@ function compileRevision(revision, base, ctx) {
|
|
|
12515
12553
|
if (!segment.text) continue;
|
|
12516
12554
|
const text = normalizeUnicodeText(segment.text);
|
|
12517
12555
|
if (segment.type === "insert" || segment.type === "delete") {
|
|
12518
|
-
for (const line of literalLines(text, base)) {
|
|
12519
|
-
|
|
12520
|
-
|
|
12521
|
-
|
|
12522
|
-
|
|
12523
|
-
|
|
12524
|
-
|
|
12525
|
-
|
|
12526
|
-
|
|
12556
|
+
for (const line of literalLines(text, base, words)) {
|
|
12557
|
+
for (const children of oneRunEach(line)) {
|
|
12558
|
+
out.push({
|
|
12559
|
+
kind: "revision",
|
|
12560
|
+
type: segment.type,
|
|
12561
|
+
id: ctx.nextRevisionId++,
|
|
12562
|
+
author,
|
|
12563
|
+
date,
|
|
12564
|
+
children
|
|
12565
|
+
});
|
|
12566
|
+
}
|
|
12527
12567
|
}
|
|
12528
12568
|
continue;
|
|
12529
12569
|
}
|
|
@@ -12531,24 +12571,36 @@ function compileRevision(revision, base, ctx) {
|
|
|
12531
12571
|
out.push(
|
|
12532
12572
|
...parseInline(text, {
|
|
12533
12573
|
base,
|
|
12574
|
+
...words ? { noProofWords: words } : {},
|
|
12534
12575
|
resolvePlaceholder: placeholderResolver(ctx)
|
|
12535
12576
|
})
|
|
12536
12577
|
);
|
|
12537
12578
|
continue;
|
|
12538
12579
|
}
|
|
12539
|
-
for (const line of literalLines(text, base)) out.push(...line);
|
|
12580
|
+
for (const line of literalLines(text, base, words)) out.push(...line);
|
|
12540
12581
|
}
|
|
12541
12582
|
return out;
|
|
12542
12583
|
}
|
|
12543
|
-
function
|
|
12584
|
+
function oneRunEach(line) {
|
|
12585
|
+
const ranges = [];
|
|
12586
|
+
for (const node of line) {
|
|
12587
|
+
const last = ranges[ranges.length - 1];
|
|
12588
|
+
if (last?.[last.length - 1]?.kind === "lineBreak") last.push(node);
|
|
12589
|
+
else ranges.push([node]);
|
|
12590
|
+
}
|
|
12591
|
+
return ranges;
|
|
12592
|
+
}
|
|
12593
|
+
function literalLines(text, base, words) {
|
|
12544
12594
|
const formatting = Object.keys(base).length > 0 ? base : void 0;
|
|
12545
12595
|
return text.split("\n").map((line, index) => [
|
|
12546
12596
|
...index > 0 ? [{ kind: "lineBreak" }] : [],
|
|
12547
|
-
|
|
12548
|
-
|
|
12549
|
-
|
|
12550
|
-
|
|
12551
|
-
|
|
12597
|
+
...words && line ? noProofRuns(line, formatting, words) : [
|
|
12598
|
+
{
|
|
12599
|
+
kind: "text",
|
|
12600
|
+
text: line,
|
|
12601
|
+
...formatting ? { formatting } : {}
|
|
12602
|
+
}
|
|
12603
|
+
]
|
|
12552
12604
|
]);
|
|
12553
12605
|
}
|
|
12554
12606
|
function resolvePlaceholder(name, generatedAt) {
|
|
@@ -12843,7 +12895,8 @@ function nativeVisualDeps(ctx, path4) {
|
|
|
12843
12895
|
};
|
|
12844
12896
|
},
|
|
12845
12897
|
reject: (detail) => ctx.unsupported.push({ name: "visual", path: path4, detail }),
|
|
12846
|
-
warn: (message) => warnOnce(ctx, `visual:${message}`, message)
|
|
12898
|
+
warn: (message) => warnOnce(ctx, `visual:${message}`, message),
|
|
12899
|
+
...noProofWords(ctx.theme) ? { noProofWords: noProofWords(ctx.theme) } : {}
|
|
12847
12900
|
};
|
|
12848
12901
|
}
|
|
12849
12902
|
function visualPlacementPixels(props, canvas, reference) {
|
|
@@ -13127,6 +13180,7 @@ function captionBlock(value, scope, componentName) {
|
|
|
13127
13180
|
ctx.unsupported.push({ name: componentName, path: path4, detail: syntax });
|
|
13128
13181
|
return void 0;
|
|
13129
13182
|
}
|
|
13183
|
+
const words = noProofWords(ctx.theme);
|
|
13130
13184
|
return {
|
|
13131
13185
|
kind: "paragraph",
|
|
13132
13186
|
id: `${scope.id}:caption`,
|
|
@@ -13139,9 +13193,13 @@ function captionBlock(value, scope, componentName) {
|
|
|
13139
13193
|
children: DECORATED.test(caption) ? parseInline(caption, {
|
|
13140
13194
|
base: {},
|
|
13141
13195
|
hyperlinks: true,
|
|
13196
|
+
...words ? { noProofWords: words } : {},
|
|
13142
13197
|
resolvePlaceholder: placeholderResolver(ctx),
|
|
13143
13198
|
resolveCrossReference: crossReferenceResolver(ctx, path4)
|
|
13144
|
-
}) : parseLiteral(caption, {
|
|
13199
|
+
}) : parseLiteral(caption, {
|
|
13200
|
+
base: {},
|
|
13201
|
+
...words ? { noProofWords: words } : {}
|
|
13202
|
+
})
|
|
13145
13203
|
};
|
|
13146
13204
|
}
|
|
13147
13205
|
function relativeFrom(value, axis) {
|
|
@@ -13626,10 +13684,14 @@ function cellChildren(cell, baseStyle, scope, rowRevision) {
|
|
|
13626
13684
|
}
|
|
13627
13685
|
const text = cellText(cell);
|
|
13628
13686
|
if (text === void 0) return wrap([]);
|
|
13687
|
+
const words = mergeNoProofWords(
|
|
13688
|
+
noProofWords(ctx.theme),
|
|
13689
|
+
typeof content === "object" ? content.props?.noProofWords : void 0
|
|
13690
|
+
);
|
|
13629
13691
|
const revision = cell.revision ?? cellComponentRevision(cell);
|
|
13630
13692
|
if (revision) {
|
|
13631
13693
|
ctx.features.require("revisions", "");
|
|
13632
|
-
return wrap(compileRevision(revision, base, ctx));
|
|
13694
|
+
return wrap(compileRevision(revision, base, ctx, words));
|
|
13633
13695
|
}
|
|
13634
13696
|
if (rowRevision) {
|
|
13635
13697
|
return wrap(
|
|
@@ -13640,7 +13702,8 @@ function cellChildren(cell, baseStyle, scope, rowRevision) {
|
|
|
13640
13702
|
segments: [{ type: rowRevision.type, text }]
|
|
13641
13703
|
},
|
|
13642
13704
|
base,
|
|
13643
|
-
ctx
|
|
13705
|
+
ctx,
|
|
13706
|
+
words
|
|
13644
13707
|
)
|
|
13645
13708
|
);
|
|
13646
13709
|
}
|
|
@@ -13648,6 +13711,7 @@ function cellChildren(cell, baseStyle, scope, rowRevision) {
|
|
|
13648
13711
|
parseInline(text, {
|
|
13649
13712
|
base,
|
|
13650
13713
|
hyperlinks: true,
|
|
13714
|
+
...words ? { noProofWords: words } : {},
|
|
13651
13715
|
resolvePlaceholder: placeholderResolver(ctx),
|
|
13652
13716
|
resolveCrossReference: crossReferenceResolver(ctx, "table")
|
|
13653
13717
|
})
|