@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
|
@@ -5091,6 +5091,12 @@ function buildDocument(ir, resources = /* @__PURE__ */ new Map(), pageNumbers, e
|
|
|
5091
5091
|
updateFields: ir.settings.updateFields,
|
|
5092
5092
|
...ir.settings.trackRevisions ? { trackRevisions: true } : {}
|
|
5093
5093
|
},
|
|
5094
|
+
// A text's `\n` is a manual line break inside its paragraph, and Word
|
|
5095
|
+
// stretches the line before one across the whole width of a justified
|
|
5096
|
+
// paragraph — a two-word line spread edge to edge. `w:doNotExpandShiftReturn`
|
|
5097
|
+
// sets that line flush like the last line of a paragraph, the way every
|
|
5098
|
+
// reader expects. docx keeps compatibility mode 15 alongside it.
|
|
5099
|
+
compatibility: { doNotExpandShiftReturn: true },
|
|
5094
5100
|
...ir.numbering.length > 0 ? { numbering: { config: ir.numbering.map(numberingConfig) } } : {},
|
|
5095
5101
|
// word/footnotes.xml and word/endnotes.xml, keyed by the id their
|
|
5096
5102
|
// references carry.
|
|
@@ -6812,7 +6818,19 @@ async function buildDocumentOptions(ir, charts2 = [], svgRasterFallback) {
|
|
|
6812
6818
|
...coreProperties2(ir),
|
|
6813
6819
|
settings: {
|
|
6814
6820
|
updateFields: ir.settings.updateFields,
|
|
6815
|
-
...ir.settings.trackRevisions ? { trackRevisions: true } : {}
|
|
6821
|
+
...ir.settings.trackRevisions ? { trackRevisions: true } : {},
|
|
6822
|
+
// A text's `\n` is a manual line break inside its paragraph, and Word
|
|
6823
|
+
// stretches the line before one across the whole width of a justified
|
|
6824
|
+
// paragraph. `w:doNotExpandShiftReturn` sets that line flush instead.
|
|
6825
|
+
// Passing `compatibility` replaces @office-open/docx's fresh-document
|
|
6826
|
+
// defaults rather than extending them, so they are restated here.
|
|
6827
|
+
compatibility: {
|
|
6828
|
+
version: 15,
|
|
6829
|
+
overrideTableStyleFontSizeAndJustification: true,
|
|
6830
|
+
enableOpenTypeFeatures: true,
|
|
6831
|
+
doNotFlipMirrorIndents: true,
|
|
6832
|
+
doNotExpandShiftReturn: true
|
|
6833
|
+
}
|
|
6816
6834
|
},
|
|
6817
6835
|
...ir.numbering.length > 0 ? {
|
|
6818
6836
|
numbering: {
|
|
@@ -8359,292 +8377,504 @@ import {
|
|
|
8359
8377
|
|
|
8360
8378
|
// src/ir/nativeVisual.ts
|
|
8361
8379
|
init_units();
|
|
8362
|
-
|
|
8363
|
-
|
|
8364
|
-
|
|
8365
|
-
|
|
8366
|
-
|
|
8367
|
-
|
|
8368
|
-
|
|
8369
|
-
|
|
8370
|
-
|
|
8371
|
-
}
|
|
8372
|
-
|
|
8373
|
-
|
|
8374
|
-
|
|
8375
|
-
|
|
8376
|
-
|
|
8377
|
-
])
|
|
8378
|
-
|
|
8379
|
-
|
|
8380
|
-
|
|
8381
|
-
|
|
8382
|
-
};
|
|
8383
|
-
var
|
|
8384
|
-
|
|
8385
|
-
|
|
8386
|
-
|
|
8387
|
-
|
|
8388
|
-
|
|
8389
|
-
|
|
8390
|
-
const
|
|
8391
|
-
|
|
8392
|
-
|
|
8393
|
-
|
|
8394
|
-
|
|
8395
|
-
|
|
8396
|
-
|
|
8397
|
-
|
|
8398
|
-
|
|
8399
|
-
|
|
8400
|
-
|
|
8380
|
+
|
|
8381
|
+
// src/utils/unicode.ts
|
|
8382
|
+
function normalizeUnicodeText(text) {
|
|
8383
|
+
return (text ?? "").normalize("NFC");
|
|
8384
|
+
}
|
|
8385
|
+
|
|
8386
|
+
// src/ir/inline.ts
|
|
8387
|
+
function escapeRegExp(value) {
|
|
8388
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
8389
|
+
}
|
|
8390
|
+
function buildNoProofWordsRegex(noProofWords2) {
|
|
8391
|
+
const words = (noProofWords2 ?? []).filter((word) => word?.trim().length > 0);
|
|
8392
|
+
if (words.length === 0) return null;
|
|
8393
|
+
const escaped = words.slice().sort((a, b) => b.length - a.length).map(escapeRegExp);
|
|
8394
|
+
return new RegExp(
|
|
8395
|
+
`(?<![\\p{L}\\p{N}])(?:${escaped.join("|")})(?![\\p{L}\\p{N}])`,
|
|
8396
|
+
"giu"
|
|
8397
|
+
);
|
|
8398
|
+
}
|
|
8399
|
+
var DECORATOR = /(\*\*\*|___)([\s\S]*?)\1|(\*\*|__)([\s\S]*?)\3|(\*|_)([\s\S]*?)\5/g;
|
|
8400
|
+
var ESCAPABLE = "*_[]{}\\";
|
|
8401
|
+
var ESCAPE = /\\([*_[\]{}\\])/g;
|
|
8402
|
+
var SENTINEL = "\uE000";
|
|
8403
|
+
var SENTINEL_SELF = "x";
|
|
8404
|
+
var SENTINEL_DIGIT_BASE = 48;
|
|
8405
|
+
function encodeEscapes(text) {
|
|
8406
|
+
const authored = text.includes(SENTINEL);
|
|
8407
|
+
if (!authored && !text.includes("\\")) return text;
|
|
8408
|
+
const guarded = authored ? text.split(SENTINEL).join(SENTINEL + SENTINEL_SELF) : text;
|
|
8409
|
+
return guarded.replace(
|
|
8410
|
+
ESCAPE,
|
|
8411
|
+
(_whole, char) => SENTINEL + String.fromCharCode(SENTINEL_DIGIT_BASE + ESCAPABLE.indexOf(char))
|
|
8412
|
+
);
|
|
8413
|
+
}
|
|
8414
|
+
function decodeEscapes(text) {
|
|
8415
|
+
if (!text.includes(SENTINEL)) return text;
|
|
8416
|
+
let out = "";
|
|
8417
|
+
for (let i = 0; i < text.length; i += 1) {
|
|
8418
|
+
if (text[i] !== SENTINEL) {
|
|
8419
|
+
out += text[i];
|
|
8420
|
+
continue;
|
|
8401
8421
|
}
|
|
8402
|
-
|
|
8403
|
-
|
|
8404
|
-
|
|
8405
|
-
|
|
8406
|
-
|
|
8407
|
-
deps.reject(`canvas.background.color "${background.color}"`);
|
|
8408
|
-
} else {
|
|
8409
|
-
children.push({
|
|
8410
|
-
kind: "shape",
|
|
8411
|
-
frame: fullBleed(canvas),
|
|
8412
|
-
geometry: "rect",
|
|
8413
|
-
fill: { kind: "solid", color },
|
|
8414
|
-
name: "Canvas background"
|
|
8415
|
-
});
|
|
8422
|
+
const marker = text[i + 1];
|
|
8423
|
+
if (marker === SENTINEL_SELF) {
|
|
8424
|
+
out += SENTINEL;
|
|
8425
|
+
i += 1;
|
|
8426
|
+
continue;
|
|
8416
8427
|
}
|
|
8417
|
-
|
|
8418
|
-
|
|
8419
|
-
|
|
8420
|
-
|
|
8421
|
-
|
|
8422
|
-
deps.reject("canvas.background.image could not be loaded");
|
|
8423
|
-
} else {
|
|
8424
|
-
children.push({
|
|
8425
|
-
kind: "picture",
|
|
8426
|
-
frame: fullBleed(canvas),
|
|
8427
|
-
resourceId: resource.resourceId,
|
|
8428
|
-
name: "Canvas background"
|
|
8429
|
-
});
|
|
8428
|
+
const index = marker === void 0 ? -1 : marker.charCodeAt(0) - SENTINEL_DIGIT_BASE;
|
|
8429
|
+
if (index >= 0 && index < ESCAPABLE.length) {
|
|
8430
|
+
out += ESCAPABLE[index];
|
|
8431
|
+
i += 1;
|
|
8432
|
+
continue;
|
|
8430
8433
|
}
|
|
8434
|
+
out += text[i];
|
|
8431
8435
|
}
|
|
8432
|
-
|
|
8433
|
-
if (element.enabled === false) continue;
|
|
8434
|
-
const child = compileElement(element, index, canvas, deps);
|
|
8435
|
-
if (child) children.push(child);
|
|
8436
|
-
}
|
|
8437
|
-
return refused ? void 0 : { canvas, children };
|
|
8436
|
+
return out;
|
|
8438
8437
|
}
|
|
8439
|
-
|
|
8440
|
-
|
|
8441
|
-
|
|
8442
|
-
|
|
8443
|
-
|
|
8444
|
-
|
|
8445
|
-
|
|
8446
|
-
|
|
8447
|
-
|
|
8448
|
-
|
|
8449
|
-
|
|
8450
|
-
|
|
8451
|
-
}
|
|
8438
|
+
var LINK = /\[([^\]]+)\]\(([^)]+)\)/g;
|
|
8439
|
+
var DECORATOR_OR_PLACEHOLDER = /(\*\*\*|___)([\s\S]*?)\1|(\*\*|__)([\s\S]*?)\3|(\*|_)([\s\S]*?)\5|\{([^}]+)\}/g;
|
|
8440
|
+
var PLACEHOLDER = /\{([^}]+)\}/;
|
|
8441
|
+
var UNSUPPORTED_SYNTAX = [];
|
|
8442
|
+
var CROSS_REFERENCE = /\[@([^\]\s:]+)(?::(relative|no_context|full_context|none))?\]/;
|
|
8443
|
+
var INLINE_TOKEN = new RegExp(
|
|
8444
|
+
`${LINK.source}|${CROSS_REFERENCE.source}`,
|
|
8445
|
+
"g"
|
|
8446
|
+
);
|
|
8447
|
+
var NOTE_MARKER = /\[\^([^\]\s]+)\]/g;
|
|
8448
|
+
function containsPlaceholder(text) {
|
|
8449
|
+
return PLACEHOLDER.test(text);
|
|
8452
8450
|
}
|
|
8453
|
-
function
|
|
8454
|
-
|
|
8455
|
-
|
|
8456
|
-
|
|
8457
|
-
|
|
8458
|
-
|
|
8459
|
-
|
|
8451
|
+
function containsCrossReference(text) {
|
|
8452
|
+
return new RegExp(CROSS_REFERENCE.source).test(text);
|
|
8453
|
+
}
|
|
8454
|
+
function containsLink(text) {
|
|
8455
|
+
return new RegExp(LINK.source).test(text);
|
|
8456
|
+
}
|
|
8457
|
+
function containsUnsupportedSyntax(text) {
|
|
8458
|
+
for (const { pattern, what } of UNSUPPORTED_SYNTAX) {
|
|
8459
|
+
if (pattern.test(text)) return what;
|
|
8460
8460
|
}
|
|
8461
|
-
|
|
8462
|
-
[
|
|
8463
|
-
["color", props.color],
|
|
8464
|
-
["fill.color", props.fill?.color],
|
|
8465
|
-
...runs.map((run, i) => [`runs[${i}].color`, run.color]),
|
|
8466
|
-
...runs.map(
|
|
8467
|
-
(run, i) => [
|
|
8468
|
-
`runs[${i}].underline.color`,
|
|
8469
|
-
underlineColor(run.underline)
|
|
8470
|
-
]
|
|
8471
|
-
),
|
|
8472
|
-
["underline.color", underlineColor(props.underline)]
|
|
8473
|
-
],
|
|
8474
|
-
at,
|
|
8475
|
-
deps
|
|
8476
|
-
);
|
|
8477
|
-
if (!colors) return void 0;
|
|
8478
|
-
const frame = resolveFrame(props, canvas, {
|
|
8479
|
-
defaultHeightInches: derivedTextHeightInches(props, runs)
|
|
8480
|
-
});
|
|
8481
|
-
const paragraphs = textParagraphs(runs, props, colors, at);
|
|
8482
|
-
return {
|
|
8483
|
-
kind: "shape",
|
|
8484
|
-
frame,
|
|
8485
|
-
geometry: "rect",
|
|
8486
|
-
isTextBox: true,
|
|
8487
|
-
// A text box with no fill is transparent, which is what the rasterized
|
|
8488
|
-
// path draws; saying so explicitly stops Word applying its own default.
|
|
8489
|
-
fill: props.fill?.color ? solidFill(colors.get("fill.color"), props.fill.transparency) : { kind: "none" },
|
|
8490
|
-
text: {
|
|
8491
|
-
paragraphs,
|
|
8492
|
-
// pptx anchors a text box at the top unless told otherwise, and a
|
|
8493
|
-
// drawing that changes anchor between render modes moves its text.
|
|
8494
|
-
anchor: ANCHOR[props.valign ?? "top"] ?? "top",
|
|
8495
|
-
// A text box's insets default to nothing, again matching pptx. A shape
|
|
8496
|
-
// deliberately leaves them unstated so OOXML's own defaults apply.
|
|
8497
|
-
insetsEmu: marginInsets(props.margin) ?? ZERO_INSETS
|
|
8498
|
-
},
|
|
8499
|
-
name: `Text ${at}`
|
|
8500
|
-
};
|
|
8461
|
+
return void 0;
|
|
8501
8462
|
}
|
|
8502
|
-
|
|
8503
|
-
|
|
8504
|
-
if (
|
|
8505
|
-
|
|
8506
|
-
|
|
8463
|
+
function parseInline(text, options) {
|
|
8464
|
+
const normalized = encodeEscapes(normalizeUnicodeText(text));
|
|
8465
|
+
if (!normalized) {
|
|
8466
|
+
return [
|
|
8467
|
+
{ kind: "text", text: "", formatting: emptyToUndefined(options.base) }
|
|
8468
|
+
];
|
|
8469
|
+
}
|
|
8470
|
+
if (containsPlaceholder(normalized)) {
|
|
8471
|
+
return parsePlaceholders(normalized, options);
|
|
8472
|
+
}
|
|
8473
|
+
if (options.hyperlinks) return parseLinks(normalized, options);
|
|
8474
|
+
return parseDecorated(normalized, options);
|
|
8507
8475
|
}
|
|
8508
|
-
function
|
|
8509
|
-
const
|
|
8510
|
-
|
|
8511
|
-
|
|
8512
|
-
|
|
8513
|
-
kind: "paragraph",
|
|
8514
|
-
id: `${at}.p${paragraphs.length}`,
|
|
8515
|
-
path: `${at}.paragraphs[${paragraphs.length}]`,
|
|
8516
|
-
children: current,
|
|
8517
|
-
formatting: {
|
|
8518
|
-
...props.align ? { alignment: ALIGNMENT[props.align] } : {},
|
|
8519
|
-
// A drawing's text is set flush against the shape; the document's
|
|
8520
|
-
// paragraph spacing would push it away from the top edge, which is not
|
|
8521
|
-
// what an absolutely-placed box means.
|
|
8522
|
-
spacing: { beforeTwips: 0, afterTwips: 0 }
|
|
8523
|
-
}
|
|
8524
|
-
});
|
|
8525
|
-
current = [];
|
|
8476
|
+
function parsePlaceholders(normalized, parseOptions) {
|
|
8477
|
+
const options = {
|
|
8478
|
+
...parseOptions,
|
|
8479
|
+
boldColor: void 0,
|
|
8480
|
+
resolveNote: void 0
|
|
8526
8481
|
};
|
|
8527
|
-
|
|
8528
|
-
|
|
8529
|
-
|
|
8530
|
-
|
|
8531
|
-
|
|
8532
|
-
|
|
8533
|
-
|
|
8534
|
-
|
|
8535
|
-
|
|
8536
|
-
if (
|
|
8537
|
-
|
|
8538
|
-
|
|
8539
|
-
|
|
8482
|
+
const out = [];
|
|
8483
|
+
const token = new RegExp(DECORATOR_OR_PLACEHOLDER.source, "g");
|
|
8484
|
+
let lastIndex = 0;
|
|
8485
|
+
let match;
|
|
8486
|
+
const literal = (text, base = options.base) => {
|
|
8487
|
+
if (!text) return;
|
|
8488
|
+
out.push(...parseLiteralLines(text, { ...options, base }));
|
|
8489
|
+
};
|
|
8490
|
+
while ((match = token.exec(normalized)) !== null) {
|
|
8491
|
+
if (match.index > lastIndex) {
|
|
8492
|
+
literal(normalized.slice(lastIndex, match.index));
|
|
8493
|
+
}
|
|
8494
|
+
lastIndex = match.index + match[0].length;
|
|
8495
|
+
if (match[7]) {
|
|
8496
|
+
const resolved = options.resolvePlaceholder?.(match[7]);
|
|
8497
|
+
if (!resolved) {
|
|
8498
|
+
literal(match[0]);
|
|
8499
|
+
} else if (resolved.kind === "text") {
|
|
8500
|
+
literal(resolved.text);
|
|
8501
|
+
} else {
|
|
8502
|
+
const formatting = emptyToUndefined({
|
|
8503
|
+
fontFamily: options.base.fontFamily,
|
|
8504
|
+
sizeHalfPoints: options.base.sizeHalfPoints,
|
|
8505
|
+
color: options.base.color,
|
|
8506
|
+
bold: options.base.bold,
|
|
8507
|
+
italic: options.base.italic,
|
|
8508
|
+
underline: options.base.underline
|
|
8509
|
+
});
|
|
8510
|
+
out.push({
|
|
8511
|
+
kind: "field",
|
|
8512
|
+
instruction: resolved.instruction,
|
|
8513
|
+
...resolved.cachedText !== void 0 && {
|
|
8514
|
+
cachedText: resolved.cachedText
|
|
8515
|
+
},
|
|
8516
|
+
...formatting ? { formatting } : {}
|
|
8517
|
+
});
|
|
8518
|
+
}
|
|
8519
|
+
continue;
|
|
8520
|
+
}
|
|
8521
|
+
const style = decoratedStyle(match, options.base);
|
|
8522
|
+
out.push(
|
|
8523
|
+
...parsePlaceholders(decoratedText(match), {
|
|
8524
|
+
...options,
|
|
8525
|
+
base: { ...options.base, ...style },
|
|
8526
|
+
// No-proof words do not survive into a decorated span here: the
|
|
8527
|
+
// recursion has always been entered without them.
|
|
8528
|
+
noProofWords: void 0
|
|
8529
|
+
})
|
|
8530
|
+
);
|
|
8531
|
+
}
|
|
8532
|
+
if (lastIndex < normalized.length) literal(normalized.slice(lastIndex));
|
|
8533
|
+
if (out.length === 0 && normalized) literal(normalized);
|
|
8534
|
+
return out;
|
|
8540
8535
|
}
|
|
8541
|
-
function
|
|
8542
|
-
const
|
|
8543
|
-
|
|
8544
|
-
|
|
8545
|
-
|
|
8546
|
-
|
|
8547
|
-
const
|
|
8548
|
-
|
|
8549
|
-
|
|
8550
|
-
|
|
8551
|
-
|
|
8552
|
-
|
|
8536
|
+
function parseLiteralLines(text, options) {
|
|
8537
|
+
const out = [];
|
|
8538
|
+
pushSegment(out, text, options);
|
|
8539
|
+
return out;
|
|
8540
|
+
}
|
|
8541
|
+
function parseLiteral(text, options) {
|
|
8542
|
+
const out = [];
|
|
8543
|
+
pushWords(
|
|
8544
|
+
out,
|
|
8545
|
+
normalizeUnicodeText(text),
|
|
8546
|
+
emptyToUndefined(options.base),
|
|
8547
|
+
options
|
|
8553
8548
|
);
|
|
8554
|
-
|
|
8555
|
-
...fontFamily ? { fontFamily } : {},
|
|
8556
|
-
...sizePoints !== void 0 ? { sizeHalfPoints: pointsToHalfPoints(sizePoints) } : {},
|
|
8557
|
-
...color ? { color } : {},
|
|
8558
|
-
...bold !== void 0 ? { bold } : {},
|
|
8559
|
-
...italic !== void 0 ? { italic } : {},
|
|
8560
|
-
...strike !== void 0 ? { strike } : {},
|
|
8561
|
-
...underline ? { underline } : {}
|
|
8562
|
-
};
|
|
8563
|
-
return Object.keys(formatting).length > 0 ? { formatting } : {};
|
|
8549
|
+
return out;
|
|
8564
8550
|
}
|
|
8565
|
-
|
|
8566
|
-
|
|
8567
|
-
|
|
8568
|
-
|
|
8569
|
-
|
|
8570
|
-
|
|
8571
|
-
|
|
8572
|
-
|
|
8573
|
-
|
|
8574
|
-
|
|
8575
|
-
|
|
8576
|
-
|
|
8577
|
-
|
|
8551
|
+
function parseLinks(normalized, options) {
|
|
8552
|
+
const out = [];
|
|
8553
|
+
const token = new RegExp(INLINE_TOKEN.source, "g");
|
|
8554
|
+
let lastIndex = 0;
|
|
8555
|
+
let match;
|
|
8556
|
+
while ((match = token.exec(normalized)) !== null) {
|
|
8557
|
+
if (match.index > lastIndex) {
|
|
8558
|
+
out.push(
|
|
8559
|
+
...parseDecorated(normalized.slice(lastIndex, match.index), options)
|
|
8560
|
+
);
|
|
8561
|
+
}
|
|
8562
|
+
lastIndex = match.index + match[0].length;
|
|
8563
|
+
if (match[1] === void 0) {
|
|
8564
|
+
const resolved = options.resolveCrossReference?.(
|
|
8565
|
+
decodeEscapes(match[3]),
|
|
8566
|
+
match[4] ?? "relative",
|
|
8567
|
+
match[0]
|
|
8568
|
+
);
|
|
8569
|
+
if (resolved) out.push(resolved);
|
|
8570
|
+
else out.push(...parseDecorated(match[0], options));
|
|
8571
|
+
continue;
|
|
8572
|
+
}
|
|
8573
|
+
const [, linkText] = match;
|
|
8574
|
+
const target2 = decodeEscapes(match[2]);
|
|
8575
|
+
out.push({
|
|
8576
|
+
kind: "hyperlink",
|
|
8577
|
+
// A `#anchor` target names a bookmark in this document and needs no
|
|
8578
|
+
// relationship; anything else leaves the document.
|
|
8579
|
+
target: target2.startsWith("#") ? { kind: "bookmark", anchor: target2.slice(1) } : { kind: "external", url: target2 },
|
|
8580
|
+
children: parseDecorated(linkText, options)
|
|
8581
|
+
});
|
|
8582
|
+
}
|
|
8583
|
+
if (lastIndex < normalized.length) {
|
|
8584
|
+
out.push(...parseDecorated(normalized.slice(lastIndex), options));
|
|
8585
|
+
}
|
|
8586
|
+
if (out.length === 0) return parseDecorated(normalized, options);
|
|
8587
|
+
return out;
|
|
8578
8588
|
}
|
|
8579
|
-
function
|
|
8580
|
-
|
|
8589
|
+
function parseDecorated(normalized, options) {
|
|
8590
|
+
const out = [];
|
|
8591
|
+
let lastIndex = 0;
|
|
8592
|
+
let match;
|
|
8593
|
+
const decorator = new RegExp(DECORATOR.source, "g");
|
|
8594
|
+
while ((match = decorator.exec(normalized)) !== null) {
|
|
8595
|
+
if (match.index > lastIndex) {
|
|
8596
|
+
pushSegment(out, normalized.slice(lastIndex, match.index), options);
|
|
8597
|
+
}
|
|
8598
|
+
pushSegment(
|
|
8599
|
+
out,
|
|
8600
|
+
decoratedText(match),
|
|
8601
|
+
options,
|
|
8602
|
+
decoratedStyle(match, options.base)
|
|
8603
|
+
);
|
|
8604
|
+
lastIndex = match.index + match[0].length;
|
|
8605
|
+
}
|
|
8606
|
+
if (lastIndex < normalized.length) {
|
|
8607
|
+
pushSegment(out, normalized.slice(lastIndex), options);
|
|
8608
|
+
}
|
|
8609
|
+
if (out.length === 0) pushSegment(out, normalized, options);
|
|
8610
|
+
return out;
|
|
8581
8611
|
}
|
|
8582
|
-
function
|
|
8583
|
-
|
|
8584
|
-
|
|
8585
|
-
|
|
8586
|
-
|
|
8587
|
-
);
|
|
8588
|
-
return Math.max(
|
|
8589
|
-
MIN_DERIVED_TEXT_HEIGHT_INCHES,
|
|
8590
|
-
fontSize / 72 * DERIVED_LINE_HEIGHT_RATIO * lineCount
|
|
8591
|
-
);
|
|
8612
|
+
function decoratedText(match) {
|
|
8613
|
+
if (match[1]) return match[2];
|
|
8614
|
+
if (match[3]) return match[4];
|
|
8615
|
+
if (match[5]) return match[6];
|
|
8616
|
+
return match[0];
|
|
8592
8617
|
}
|
|
8593
|
-
function
|
|
8594
|
-
const
|
|
8595
|
-
const
|
|
8596
|
-
|
|
8597
|
-
|
|
8598
|
-
|
|
8599
|
-
|
|
8600
|
-
|
|
8601
|
-
|
|
8602
|
-
|
|
8603
|
-
|
|
8604
|
-
|
|
8605
|
-
|
|
8606
|
-
)
|
|
8607
|
-
|
|
8608
|
-
|
|
8609
|
-
|
|
8610
|
-
|
|
8611
|
-
|
|
8612
|
-
|
|
8613
|
-
|
|
8614
|
-
|
|
8618
|
+
function decoratedStyle(match, base) {
|
|
8619
|
+
const bold = base.bold ?? false;
|
|
8620
|
+
const italic = base.italic ?? false;
|
|
8621
|
+
if (match[1]) return { bold: true, italic: true };
|
|
8622
|
+
if (match[3]) return { bold: true, italic };
|
|
8623
|
+
if (match[5]) return { bold, italic: true };
|
|
8624
|
+
return { bold, italic };
|
|
8625
|
+
}
|
|
8626
|
+
function pushSegment(out, text, options, override = {}) {
|
|
8627
|
+
const bold = override.bold ?? options.base.bold;
|
|
8628
|
+
const italic = override.italic ?? options.base.italic;
|
|
8629
|
+
const formatting = runFormatting(options, { bold, italic });
|
|
8630
|
+
const lines = decodeEscapes(text).split("\n");
|
|
8631
|
+
for (const [lineIndex, line] of lines.entries()) {
|
|
8632
|
+
if (!line && lineIndex === 0) continue;
|
|
8633
|
+
if (lineIndex > 0) out.push({ kind: "lineBreak" });
|
|
8634
|
+
if (!line) {
|
|
8635
|
+
out.push({ kind: "text", text: "", formatting });
|
|
8636
|
+
continue;
|
|
8637
|
+
}
|
|
8638
|
+
const tabSegments = line.split(" ");
|
|
8639
|
+
for (const [tabIndex, segment] of tabSegments.entries()) {
|
|
8640
|
+
if (tabIndex > 0) out.push({ kind: "tab", formatting });
|
|
8641
|
+
if (!segment && tabSegments.length > 1) continue;
|
|
8642
|
+
pushWords(out, segment, formatting, options);
|
|
8643
|
+
}
|
|
8615
8644
|
}
|
|
8616
|
-
const outline = props.line ? {
|
|
8617
|
-
...colors.get("line.color") ? { color: colors.get("line.color") } : {},
|
|
8618
|
-
...props.line.width !== void 0 ? { widthEmu: pointsToEmu(props.line.width) } : {},
|
|
8619
|
-
...dash && dash !== "solid" ? { dash } : {}
|
|
8620
|
-
} : void 0;
|
|
8621
|
-
const text = segments.length ? {
|
|
8622
|
-
paragraphs: shapeParagraphs(segments, props, colors, at),
|
|
8623
|
-
anchor: ANCHOR[props.valign ?? "middle"] ?? "middle",
|
|
8624
|
-
// Unstated insets are left unstated so OOXML's own shape defaults
|
|
8625
|
-
// apply, which is what the raster path draws.
|
|
8626
|
-
...marginInsets(props.margin) ? { insetsEmu: marginInsets(props.margin) } : {}
|
|
8627
|
-
} : void 0;
|
|
8628
|
-
return {
|
|
8629
|
-
kind: "shape",
|
|
8630
|
-
frame,
|
|
8631
|
-
geometry: GEOMETRY_ALIASES[props.type] ?? props.type,
|
|
8632
|
-
...props.fill ? {
|
|
8633
|
-
fill: props.fill.color ? solidFill(colors.get("fill.color"), props.fill.transparency) : { kind: "none" }
|
|
8634
|
-
} : {},
|
|
8635
|
-
...outline && Object.keys(outline).length > 0 ? { outline } : {},
|
|
8636
|
-
...text ? { text } : {},
|
|
8637
|
-
name: `Shape ${at}`
|
|
8638
|
-
};
|
|
8639
8645
|
}
|
|
8640
|
-
function
|
|
8641
|
-
if (
|
|
8642
|
-
|
|
8643
|
-
return
|
|
8646
|
+
function pushWords(out, text, formatting, options) {
|
|
8647
|
+
if (options.resolveNote) {
|
|
8648
|
+
splitNoteMarkers(out, text, formatting, options);
|
|
8649
|
+
return;
|
|
8644
8650
|
}
|
|
8645
|
-
|
|
8651
|
+
pushNoProofWords(out, text, formatting, options);
|
|
8646
8652
|
}
|
|
8647
|
-
function
|
|
8653
|
+
function splitNoteMarkers(out, text, formatting, options) {
|
|
8654
|
+
const regex = new RegExp(NOTE_MARKER.source, "g");
|
|
8655
|
+
let lastIndex = 0;
|
|
8656
|
+
let pending = "";
|
|
8657
|
+
let match;
|
|
8658
|
+
while ((match = regex.exec(text)) !== null) {
|
|
8659
|
+
const note = options.resolveNote(match[1]);
|
|
8660
|
+
if (note === void 0) {
|
|
8661
|
+
pending += text.slice(lastIndex, regex.lastIndex);
|
|
8662
|
+
lastIndex = regex.lastIndex;
|
|
8663
|
+
continue;
|
|
8664
|
+
}
|
|
8665
|
+
const before = pending + text.slice(lastIndex, match.index);
|
|
8666
|
+
pending = "";
|
|
8667
|
+
if (before) pushNoProofWords(out, before, formatting, options);
|
|
8668
|
+
out.push({
|
|
8669
|
+
kind: "noteReference",
|
|
8670
|
+
noteKind: note.noteKind,
|
|
8671
|
+
id: note.id
|
|
8672
|
+
});
|
|
8673
|
+
lastIndex = regex.lastIndex;
|
|
8674
|
+
}
|
|
8675
|
+
const rest = pending + text.slice(lastIndex);
|
|
8676
|
+
if (rest) pushNoProofWords(out, rest, formatting, options);
|
|
8677
|
+
}
|
|
8678
|
+
function noProofRuns(text, formatting, noProofWords2) {
|
|
8679
|
+
const out = [];
|
|
8680
|
+
pushNoProofWords(out, text, formatting, { base: {}, noProofWords: noProofWords2 });
|
|
8681
|
+
return out.map(
|
|
8682
|
+
(run) => run.formatting ? run : { kind: "text", text: run.text }
|
|
8683
|
+
);
|
|
8684
|
+
}
|
|
8685
|
+
function pushNoProofWords(out, text, formatting, options) {
|
|
8686
|
+
const wholeRunNoProof = options.base.noProof === true;
|
|
8687
|
+
const regex = wholeRunNoProof ? null : buildNoProofWordsRegex(options.noProofWords);
|
|
8688
|
+
if (!regex) {
|
|
8689
|
+
out.push({ kind: "text", text, formatting });
|
|
8690
|
+
return;
|
|
8691
|
+
}
|
|
8692
|
+
let lastIndex = 0;
|
|
8693
|
+
let match;
|
|
8694
|
+
while ((match = regex.exec(text)) !== null) {
|
|
8695
|
+
if (match.index > lastIndex) {
|
|
8696
|
+
out.push({
|
|
8697
|
+
kind: "text",
|
|
8698
|
+
text: text.slice(lastIndex, match.index),
|
|
8699
|
+
formatting
|
|
8700
|
+
});
|
|
8701
|
+
}
|
|
8702
|
+
out.push({
|
|
8703
|
+
kind: "text",
|
|
8704
|
+
text: match[0],
|
|
8705
|
+
formatting: { ...formatting, noProof: true }
|
|
8706
|
+
});
|
|
8707
|
+
lastIndex = match.index + match[0].length;
|
|
8708
|
+
if (regex.lastIndex === match.index) regex.lastIndex += 1;
|
|
8709
|
+
}
|
|
8710
|
+
if (lastIndex < text.length) {
|
|
8711
|
+
out.push({ kind: "text", text: text.slice(lastIndex), formatting });
|
|
8712
|
+
}
|
|
8713
|
+
}
|
|
8714
|
+
function runFormatting(options, state) {
|
|
8715
|
+
const formatting = { ...options.base };
|
|
8716
|
+
if (state.bold !== void 0) formatting.bold = state.bold;
|
|
8717
|
+
if (state.italic !== void 0) formatting.italic = state.italic;
|
|
8718
|
+
if (state.bold && options.boldColor && options.base.color) {
|
|
8719
|
+
formatting.color = options.boldColor;
|
|
8720
|
+
}
|
|
8721
|
+
return emptyToUndefined(formatting);
|
|
8722
|
+
}
|
|
8723
|
+
function emptyToUndefined(formatting) {
|
|
8724
|
+
const entries = Object.entries(formatting).filter(
|
|
8725
|
+
([, value]) => value !== void 0
|
|
8726
|
+
);
|
|
8727
|
+
return entries.length === 0 ? void 0 : Object.fromEntries(entries);
|
|
8728
|
+
}
|
|
8729
|
+
|
|
8730
|
+
// src/ir/nativeVisual.ts
|
|
8731
|
+
init_imageUtils();
|
|
8732
|
+
var PIXELS_PER_INCH2 = 96;
|
|
8733
|
+
var DEFAULT_WIDTH_FRACTION = 0.75;
|
|
8734
|
+
var ASSUMED_FONT_SIZE_POINTS = 18;
|
|
8735
|
+
var MIN_DERIVED_TEXT_HEIGHT_INCHES = 0.5;
|
|
8736
|
+
var DERIVED_LINE_HEIGHT_RATIO = 1.6;
|
|
8737
|
+
var GEOMETRY_ALIASES = {
|
|
8738
|
+
arrow: "rightArrow",
|
|
8739
|
+
lightning: "lightningBolt"
|
|
8740
|
+
};
|
|
8741
|
+
var DASH_VALUES = /* @__PURE__ */ new Set([
|
|
8742
|
+
"solid",
|
|
8743
|
+
"dash",
|
|
8744
|
+
"dot",
|
|
8745
|
+
"dashDot"
|
|
8746
|
+
]);
|
|
8747
|
+
var ANCHOR = {
|
|
8748
|
+
top: "top",
|
|
8749
|
+
middle: "middle",
|
|
8750
|
+
bottom: "bottom"
|
|
8751
|
+
};
|
|
8752
|
+
var ALIGNMENT = {
|
|
8753
|
+
left: "left",
|
|
8754
|
+
center: "center",
|
|
8755
|
+
right: "right",
|
|
8756
|
+
justify: "justified"
|
|
8757
|
+
};
|
|
8758
|
+
function compileNativeVisualGroup(props, outer) {
|
|
8759
|
+
const canvas = {
|
|
8760
|
+
widthEmu: inchesToEmu(props.canvas.width),
|
|
8761
|
+
heightEmu: inchesToEmu(props.canvas.height)
|
|
8762
|
+
};
|
|
8763
|
+
const children = [];
|
|
8764
|
+
let refused = false;
|
|
8765
|
+
const deps = {
|
|
8766
|
+
...outer,
|
|
8767
|
+
reject: (detail) => {
|
|
8768
|
+
refused = true;
|
|
8769
|
+
outer.reject(detail);
|
|
8770
|
+
}
|
|
8771
|
+
};
|
|
8772
|
+
const background = props.canvas.background;
|
|
8773
|
+
if (background?.color) {
|
|
8774
|
+
const color = deps.color(background.color);
|
|
8775
|
+
if (!color) {
|
|
8776
|
+
deps.reject(`canvas.background.color "${background.color}"`);
|
|
8777
|
+
} else {
|
|
8778
|
+
children.push({
|
|
8779
|
+
kind: "shape",
|
|
8780
|
+
frame: fullBleed(canvas),
|
|
8781
|
+
geometry: "rect",
|
|
8782
|
+
fill: { kind: "solid", color },
|
|
8783
|
+
name: "Canvas background"
|
|
8784
|
+
});
|
|
8785
|
+
}
|
|
8786
|
+
}
|
|
8787
|
+
if (background?.image) {
|
|
8788
|
+
const source = resolveImageSource(background.image);
|
|
8789
|
+
const resource = source ? deps.picture(source) : void 0;
|
|
8790
|
+
if (!resource) {
|
|
8791
|
+
deps.reject("canvas.background.image could not be loaded");
|
|
8792
|
+
} else {
|
|
8793
|
+
children.push({
|
|
8794
|
+
kind: "picture",
|
|
8795
|
+
frame: fullBleed(canvas),
|
|
8796
|
+
resourceId: resource.resourceId,
|
|
8797
|
+
name: "Canvas background"
|
|
8798
|
+
});
|
|
8799
|
+
}
|
|
8800
|
+
}
|
|
8801
|
+
for (const [index, element] of (props.elements ?? []).entries()) {
|
|
8802
|
+
if (element.enabled === false) continue;
|
|
8803
|
+
const child = compileElement(element, index, canvas, deps);
|
|
8804
|
+
if (child) children.push(child);
|
|
8805
|
+
}
|
|
8806
|
+
return refused ? void 0 : { canvas, children };
|
|
8807
|
+
}
|
|
8808
|
+
function compileElement(element, index, canvas, deps) {
|
|
8809
|
+
const at = `elements[${index}]`;
|
|
8810
|
+
switch (element.name) {
|
|
8811
|
+
case "text":
|
|
8812
|
+
return compileText(element.props, at, canvas, deps);
|
|
8813
|
+
case "shape":
|
|
8814
|
+
return compileShape(element.props, at, canvas, deps);
|
|
8815
|
+
case "image":
|
|
8816
|
+
return compileImage(element.props, at, canvas, deps);
|
|
8817
|
+
default:
|
|
8818
|
+
deps.reject(`${at} is a "${element.name}"`);
|
|
8819
|
+
return void 0;
|
|
8820
|
+
}
|
|
8821
|
+
}
|
|
8822
|
+
function compileText(props, at, canvas, deps) {
|
|
8823
|
+
const runs = textRuns(props);
|
|
8824
|
+
if (!runs) {
|
|
8825
|
+
deps.warn(
|
|
8826
|
+
`[core-docx] native visual ${at} has neither "text" nor "runs"; nothing was drawn for it.`
|
|
8827
|
+
);
|
|
8828
|
+
return void 0;
|
|
8829
|
+
}
|
|
8830
|
+
const colors = resolveColors(
|
|
8831
|
+
[
|
|
8832
|
+
["color", props.color],
|
|
8833
|
+
["fill.color", props.fill?.color],
|
|
8834
|
+
...runs.map((run, i) => [`runs[${i}].color`, run.color]),
|
|
8835
|
+
...runs.map(
|
|
8836
|
+
(run, i) => [
|
|
8837
|
+
`runs[${i}].underline.color`,
|
|
8838
|
+
underlineColor(run.underline)
|
|
8839
|
+
]
|
|
8840
|
+
),
|
|
8841
|
+
["underline.color", underlineColor(props.underline)]
|
|
8842
|
+
],
|
|
8843
|
+
at,
|
|
8844
|
+
deps
|
|
8845
|
+
);
|
|
8846
|
+
if (!colors) return void 0;
|
|
8847
|
+
const frame = resolveFrame(props, canvas, {
|
|
8848
|
+
defaultHeightInches: derivedTextHeightInches(props, runs)
|
|
8849
|
+
});
|
|
8850
|
+
const paragraphs = textParagraphs(runs, props, colors, at, deps.noProofWords);
|
|
8851
|
+
return {
|
|
8852
|
+
kind: "shape",
|
|
8853
|
+
frame,
|
|
8854
|
+
geometry: "rect",
|
|
8855
|
+
isTextBox: true,
|
|
8856
|
+
// A text box with no fill is transparent, which is what the rasterized
|
|
8857
|
+
// path draws; saying so explicitly stops Word applying its own default.
|
|
8858
|
+
fill: props.fill?.color ? solidFill(colors.get("fill.color"), props.fill.transparency) : { kind: "none" },
|
|
8859
|
+
text: {
|
|
8860
|
+
paragraphs,
|
|
8861
|
+
// pptx anchors a text box at the top unless told otherwise, and a
|
|
8862
|
+
// drawing that changes anchor between render modes moves its text.
|
|
8863
|
+
anchor: ANCHOR[props.valign ?? "top"] ?? "top",
|
|
8864
|
+
// A text box's insets default to nothing, again matching pptx. A shape
|
|
8865
|
+
// deliberately leaves them unstated so OOXML's own defaults apply.
|
|
8866
|
+
insetsEmu: marginInsets(props.margin) ?? ZERO_INSETS
|
|
8867
|
+
},
|
|
8868
|
+
name: `Text ${at}`
|
|
8869
|
+
};
|
|
8870
|
+
}
|
|
8871
|
+
var ZERO_INSETS = { top: 0, bottom: 0, left: 0, right: 0 };
|
|
8872
|
+
function textRuns(props) {
|
|
8873
|
+
if (props.runs?.length) return props.runs;
|
|
8874
|
+
if (props.text === void 0) return void 0;
|
|
8875
|
+
return [{ text: props.text }];
|
|
8876
|
+
}
|
|
8877
|
+
function textParagraphs(runs, props, colors, at, words) {
|
|
8648
8878
|
const paragraphs = [];
|
|
8649
8879
|
let current = [];
|
|
8650
8880
|
const flush = () => {
|
|
@@ -8654,49 +8884,195 @@ function shapeParagraphs(segments, props, colors, at) {
|
|
|
8654
8884
|
path: `${at}.paragraphs[${paragraphs.length}]`,
|
|
8655
8885
|
children: current,
|
|
8656
8886
|
formatting: {
|
|
8657
|
-
|
|
8658
|
-
//
|
|
8659
|
-
|
|
8887
|
+
...props.align ? { alignment: ALIGNMENT[props.align] } : {},
|
|
8888
|
+
// A drawing's text is set flush against the shape; the document's
|
|
8889
|
+
// paragraph spacing would push it away from the top edge, which is not
|
|
8890
|
+
// what an absolutely-placed box means.
|
|
8660
8891
|
spacing: { beforeTwips: 0, afterTwips: 0 }
|
|
8661
8892
|
}
|
|
8662
8893
|
});
|
|
8663
8894
|
current = [];
|
|
8664
8895
|
};
|
|
8665
|
-
|
|
8666
|
-
const
|
|
8667
|
-
const
|
|
8668
|
-
|
|
8669
|
-
const bold = segment.bold ?? props.bold;
|
|
8670
|
-
const italic = segment.italic ?? props.italic;
|
|
8671
|
-
const formatting = {
|
|
8672
|
-
...fontFamily ? { fontFamily } : {},
|
|
8673
|
-
...sizePoints !== void 0 ? { sizeHalfPoints: pointsToHalfPoints(sizePoints) } : {},
|
|
8674
|
-
...color ? { color } : {},
|
|
8675
|
-
...bold !== void 0 ? { bold } : {},
|
|
8676
|
-
...italic !== void 0 ? { italic } : {}
|
|
8677
|
-
};
|
|
8678
|
-
const wrapped = Object.keys(formatting).length > 0 ? { formatting } : void 0;
|
|
8679
|
-
segment.text.split("\n").forEach((line, lineIndex) => {
|
|
8896
|
+
runs.forEach((run, index) => {
|
|
8897
|
+
const formatting = runFormatting2(run, props, colors, index);
|
|
8898
|
+
const lines = run.text.split("\n");
|
|
8899
|
+
lines.forEach((line, lineIndex) => {
|
|
8680
8900
|
if (lineIndex > 0) current.push({ kind: "lineBreak" });
|
|
8681
|
-
if (line) current.push(
|
|
8901
|
+
if (line) current.push(...textLine(line, formatting.formatting, words));
|
|
8682
8902
|
});
|
|
8683
|
-
if (
|
|
8903
|
+
if (run.breakLine && index < runs.length - 1) flush();
|
|
8684
8904
|
});
|
|
8685
8905
|
flush();
|
|
8686
8906
|
return paragraphs;
|
|
8687
8907
|
}
|
|
8688
|
-
function
|
|
8689
|
-
const
|
|
8690
|
-
|
|
8691
|
-
|
|
8692
|
-
|
|
8693
|
-
|
|
8694
|
-
const
|
|
8695
|
-
|
|
8696
|
-
|
|
8697
|
-
|
|
8698
|
-
|
|
8699
|
-
|
|
8908
|
+
function runFormatting2(run, props, colors, index) {
|
|
8909
|
+
const fontFamily = run.fontFace ?? props.fontFace;
|
|
8910
|
+
const sizePoints = run.fontSize ?? props.fontSize;
|
|
8911
|
+
const color = colors.get(`runs[${index}].color`) ?? (run.color === void 0 ? colors.get("color") : void 0);
|
|
8912
|
+
const bold = run.bold ?? props.bold;
|
|
8913
|
+
const italic = run.italic ?? props.italic;
|
|
8914
|
+
const strike = run.strike ?? props.strike;
|
|
8915
|
+
const underline = compileUnderline(
|
|
8916
|
+
run.underline ?? props.underline,
|
|
8917
|
+
colors.get(
|
|
8918
|
+
run.underline !== void 0 ? `runs[${index}].underline.color` : "underline.color"
|
|
8919
|
+
)
|
|
8920
|
+
);
|
|
8921
|
+
const formatting = {
|
|
8922
|
+
...fontFamily ? { fontFamily } : {},
|
|
8923
|
+
...sizePoints !== void 0 ? { sizeHalfPoints: pointsToHalfPoints(sizePoints) } : {},
|
|
8924
|
+
...color ? { color } : {},
|
|
8925
|
+
...bold !== void 0 ? { bold } : {},
|
|
8926
|
+
...italic !== void 0 ? { italic } : {},
|
|
8927
|
+
...strike !== void 0 ? { strike } : {},
|
|
8928
|
+
...underline ? { underline } : {}
|
|
8929
|
+
};
|
|
8930
|
+
return Object.keys(formatting).length > 0 ? { formatting } : {};
|
|
8931
|
+
}
|
|
8932
|
+
var UNDERLINE_TYPES = {
|
|
8933
|
+
sng: "single",
|
|
8934
|
+
dbl: "double",
|
|
8935
|
+
dash: "dash",
|
|
8936
|
+
dotted: "dotted"
|
|
8937
|
+
};
|
|
8938
|
+
function compileUnderline(value, color) {
|
|
8939
|
+
if (value === void 0 || value === false) return void 0;
|
|
8940
|
+
const style = value === true ? "sng" : value.style ?? "sng";
|
|
8941
|
+
return {
|
|
8942
|
+
type: UNDERLINE_TYPES[style] ?? "single",
|
|
8943
|
+
...color ? { color } : {}
|
|
8944
|
+
};
|
|
8945
|
+
}
|
|
8946
|
+
function underlineColor(value) {
|
|
8947
|
+
return typeof value === "object" ? value.color : void 0;
|
|
8948
|
+
}
|
|
8949
|
+
function derivedTextHeightInches(props, runs) {
|
|
8950
|
+
const fontSize = props.fontSize ?? ASSUMED_FONT_SIZE_POINTS;
|
|
8951
|
+
const lineCount = runs.reduce(
|
|
8952
|
+
(total, run) => total + (run.breakLine ? 1 : 0) + (run.text.match(/\n/g)?.length ?? 0),
|
|
8953
|
+
1
|
|
8954
|
+
);
|
|
8955
|
+
return Math.max(
|
|
8956
|
+
MIN_DERIVED_TEXT_HEIGHT_INCHES,
|
|
8957
|
+
fontSize / 72 * DERIVED_LINE_HEIGHT_RATIO * lineCount
|
|
8958
|
+
);
|
|
8959
|
+
}
|
|
8960
|
+
function compileShape(props, at, canvas, deps) {
|
|
8961
|
+
const segments = shapeSegments(props);
|
|
8962
|
+
const colors = resolveColors(
|
|
8963
|
+
[
|
|
8964
|
+
["fill.color", props.fill?.color],
|
|
8965
|
+
["line.color", props.line?.color],
|
|
8966
|
+
["fontColor", props.fontColor],
|
|
8967
|
+
...segments.map(
|
|
8968
|
+
(segment, i) => [`text[${i}].color`, segment.color]
|
|
8969
|
+
)
|
|
8970
|
+
],
|
|
8971
|
+
at,
|
|
8972
|
+
deps
|
|
8973
|
+
);
|
|
8974
|
+
if (!colors) return void 0;
|
|
8975
|
+
const frame = resolveFrame(props, canvas, { defaultHeightInches: 0 });
|
|
8976
|
+
if (props.flipH) frame.flipHorizontal = true;
|
|
8977
|
+
if (props.flipV) frame.flipVertical = true;
|
|
8978
|
+
const dash = props.line?.dashType;
|
|
8979
|
+
if (dash !== void 0 && !DASH_VALUES.has(dash)) {
|
|
8980
|
+
deps.reject(`${at}.line.dashType "${dash}"`);
|
|
8981
|
+
return void 0;
|
|
8982
|
+
}
|
|
8983
|
+
const outline = props.line ? {
|
|
8984
|
+
...colors.get("line.color") ? { color: colors.get("line.color") } : {},
|
|
8985
|
+
...props.line.width !== void 0 ? { widthEmu: pointsToEmu(props.line.width) } : {},
|
|
8986
|
+
...dash && dash !== "solid" ? { dash } : {}
|
|
8987
|
+
} : void 0;
|
|
8988
|
+
const text = segments.length ? {
|
|
8989
|
+
paragraphs: shapeParagraphs(
|
|
8990
|
+
segments,
|
|
8991
|
+
props,
|
|
8992
|
+
colors,
|
|
8993
|
+
at,
|
|
8994
|
+
deps.noProofWords
|
|
8995
|
+
),
|
|
8996
|
+
anchor: ANCHOR[props.valign ?? "middle"] ?? "middle",
|
|
8997
|
+
// Unstated insets are left unstated so OOXML's own shape defaults
|
|
8998
|
+
// apply, which is what the raster path draws.
|
|
8999
|
+
...marginInsets(props.margin) ? { insetsEmu: marginInsets(props.margin) } : {}
|
|
9000
|
+
} : void 0;
|
|
9001
|
+
return {
|
|
9002
|
+
kind: "shape",
|
|
9003
|
+
frame,
|
|
9004
|
+
geometry: GEOMETRY_ALIASES[props.type] ?? props.type,
|
|
9005
|
+
...props.fill ? {
|
|
9006
|
+
fill: props.fill.color ? solidFill(colors.get("fill.color"), props.fill.transparency) : { kind: "none" }
|
|
9007
|
+
} : {},
|
|
9008
|
+
...outline && Object.keys(outline).length > 0 ? { outline } : {},
|
|
9009
|
+
...text ? { text } : {},
|
|
9010
|
+
name: `Shape ${at}`
|
|
9011
|
+
};
|
|
9012
|
+
}
|
|
9013
|
+
function shapeSegments(props) {
|
|
9014
|
+
if (props.text === void 0) return [];
|
|
9015
|
+
if (typeof props.text === "string") {
|
|
9016
|
+
return props.text ? [{ text: props.text }] : [];
|
|
9017
|
+
}
|
|
9018
|
+
return props.text;
|
|
9019
|
+
}
|
|
9020
|
+
function shapeParagraphs(segments, props, colors, at, words) {
|
|
9021
|
+
const paragraphs = [];
|
|
9022
|
+
let current = [];
|
|
9023
|
+
const flush = () => {
|
|
9024
|
+
paragraphs.push({
|
|
9025
|
+
kind: "paragraph",
|
|
9026
|
+
id: `${at}.p${paragraphs.length}`,
|
|
9027
|
+
path: `${at}.paragraphs[${paragraphs.length}]`,
|
|
9028
|
+
children: current,
|
|
9029
|
+
formatting: {
|
|
9030
|
+
// A shape centres its text unless told otherwise, which is what the
|
|
9031
|
+
// rasterized shape draws.
|
|
9032
|
+
alignment: props.align ? ALIGNMENT[props.align] : "center",
|
|
9033
|
+
spacing: { beforeTwips: 0, afterTwips: 0 }
|
|
9034
|
+
}
|
|
9035
|
+
});
|
|
9036
|
+
current = [];
|
|
9037
|
+
};
|
|
9038
|
+
segments.forEach((segment, index) => {
|
|
9039
|
+
const fontFamily = segment.fontFace ?? props.fontFace;
|
|
9040
|
+
const sizePoints = segment.fontSize ?? props.fontSize;
|
|
9041
|
+
const color = colors.get(`text[${index}].color`) ?? (segment.color === void 0 ? colors.get("fontColor") : void 0);
|
|
9042
|
+
const bold = segment.bold ?? props.bold;
|
|
9043
|
+
const italic = segment.italic ?? props.italic;
|
|
9044
|
+
const formatting = {
|
|
9045
|
+
...fontFamily ? { fontFamily } : {},
|
|
9046
|
+
...sizePoints !== void 0 ? { sizeHalfPoints: pointsToHalfPoints(sizePoints) } : {},
|
|
9047
|
+
...color ? { color } : {},
|
|
9048
|
+
...bold !== void 0 ? { bold } : {},
|
|
9049
|
+
...italic !== void 0 ? { italic } : {}
|
|
9050
|
+
};
|
|
9051
|
+
const wrapped = Object.keys(formatting).length > 0 ? formatting : void 0;
|
|
9052
|
+
segment.text.split("\n").forEach((line, lineIndex) => {
|
|
9053
|
+
if (lineIndex > 0) current.push({ kind: "lineBreak" });
|
|
9054
|
+
if (line) current.push(...textLine(line, wrapped, words));
|
|
9055
|
+
});
|
|
9056
|
+
if (segment.breakLine && index < segments.length - 1) flush();
|
|
9057
|
+
});
|
|
9058
|
+
flush();
|
|
9059
|
+
return paragraphs;
|
|
9060
|
+
}
|
|
9061
|
+
function textLine(line, formatting, words) {
|
|
9062
|
+
return words ? noProofRuns(line, formatting, words) : [{ kind: "text", text: line, ...formatting ? { formatting } : {} }];
|
|
9063
|
+
}
|
|
9064
|
+
function compileImage(props, at, canvas, deps) {
|
|
9065
|
+
const source = resolveImageSource(props);
|
|
9066
|
+
if (!source) {
|
|
9067
|
+
deps.reject(`${at} has none of "path", "base64" or "svg"`);
|
|
9068
|
+
return void 0;
|
|
9069
|
+
}
|
|
9070
|
+
const resource = deps.picture(source);
|
|
9071
|
+
if (!resource) {
|
|
9072
|
+
deps.reject(`${at} image could not be loaded`);
|
|
9073
|
+
return void 0;
|
|
9074
|
+
}
|
|
9075
|
+
const aspect = resource.intrinsic ? resource.intrinsic.width / resource.intrinsic.height : void 0;
|
|
8700
9076
|
const intrinsicInches = resource.intrinsic ? {
|
|
8701
9077
|
width: resource.intrinsic.width / PIXELS_PER_INCH2,
|
|
8702
9078
|
height: resource.intrinsic.height / PIXELS_PER_INCH2
|
|
@@ -10228,801 +10604,459 @@ function resolveTableModel(source, theme, themeName, options = {}) {
|
|
|
10228
10604
|
adjudicateInteriorEdges([...hasHeader ? [header] : [], ...rows]);
|
|
10229
10605
|
return {
|
|
10230
10606
|
...resolveWidths(
|
|
10231
|
-
source,
|
|
10232
|
-
columns,
|
|
10233
|
-
options.measureTwips ?? getAvailableWidthTwips(theme, themeName)
|
|
10234
|
-
),
|
|
10235
|
-
...hasHeader ? { header } : {},
|
|
10236
|
-
rows,
|
|
10237
|
-
repeatHeader: source.repeatHeaderOnPageBreak ?? true
|
|
10238
|
-
};
|
|
10239
|
-
}
|
|
10240
|
-
function drawsNothing(border3) {
|
|
10241
|
-
return border3.hidden || border3.size <= 0;
|
|
10242
|
-
}
|
|
10243
|
-
function channels(hex) {
|
|
10244
|
-
const digits = hex.startsWith("#") ? hex.slice(1) : hex;
|
|
10245
|
-
return [
|
|
10246
|
-
parseInt(digits.slice(0, 2), 16) || 0,
|
|
10247
|
-
parseInt(digits.slice(2, 4), 16) || 0,
|
|
10248
|
-
parseInt(digits.slice(4, 6), 16) || 0
|
|
10249
|
-
];
|
|
10250
|
-
}
|
|
10251
|
-
function outweighs(a, b) {
|
|
10252
|
-
if (drawsNothing(a)) return false;
|
|
10253
|
-
if (drawsNothing(b)) return true;
|
|
10254
|
-
if (a.size !== b.size) return a.size > b.size;
|
|
10255
|
-
const [redA, greenA, blueA] = channels(a.color);
|
|
10256
|
-
const [redB, greenB, blueB] = channels(b.color);
|
|
10257
|
-
const brightness = [
|
|
10258
|
-
[redA + blueA + 2 * greenA, redB + blueB + 2 * greenB],
|
|
10259
|
-
[blueA + 2 * greenA, blueB + 2 * greenB],
|
|
10260
|
-
[greenA, greenB]
|
|
10261
|
-
];
|
|
10262
|
-
for (const [ours, theirs] of brightness) {
|
|
10263
|
-
if (ours !== theirs) return ours < theirs;
|
|
10264
|
-
}
|
|
10265
|
-
return false;
|
|
10266
|
-
}
|
|
10267
|
-
function adjudicateInteriorEdges(rows) {
|
|
10268
|
-
const settle = (earlier, later) => {
|
|
10269
|
-
if (drawsNothing(earlier) && drawsNothing(later)) return;
|
|
10270
|
-
if (earlier.hidden === later.hidden && earlier.size === later.size && earlier.color === later.color) {
|
|
10271
|
-
return;
|
|
10272
|
-
}
|
|
10273
|
-
const winner = earlier.explicit !== later.explicit ? earlier.explicit ? earlier : later : outweighs(later, earlier) ? later : earlier;
|
|
10274
|
-
const loser = winner === earlier ? later : earlier;
|
|
10275
|
-
loser.size = winner.size;
|
|
10276
|
-
loser.color = winner.color;
|
|
10277
|
-
loser.hidden = winner.hidden;
|
|
10278
|
-
};
|
|
10279
|
-
rows.forEach((row, rowIndex) => {
|
|
10280
|
-
row.cells.forEach((cell, colIndex) => {
|
|
10281
|
-
const right = row.cells[colIndex + 1];
|
|
10282
|
-
if (right) settle(cell.borders.right, right.borders.left);
|
|
10283
|
-
const below = rows[rowIndex + 1]?.cells[colIndex];
|
|
10284
|
-
if (below) settle(cell.borders.bottom, below.borders.top);
|
|
10285
|
-
});
|
|
10286
|
-
});
|
|
10287
|
-
}
|
|
10288
|
-
function resolveWidths(source, columns, measureTwips) {
|
|
10289
|
-
const hasExplicitWidths = columns.some((col) => col.width !== void 0);
|
|
10290
|
-
if (!hasExplicitWidths) {
|
|
10291
|
-
const percent = source.width ?? 100;
|
|
10292
|
-
return {
|
|
10293
|
-
columnGrid: {
|
|
10294
|
-
unit: "twips",
|
|
10295
|
-
values: splitTwips(columns.length, measureTwips * percent / 100)
|
|
10296
|
-
},
|
|
10297
|
-
width: { size: percent, unit: "percent" }
|
|
10298
|
-
};
|
|
10299
|
-
}
|
|
10300
|
-
const stated = columns.map(
|
|
10301
|
-
(col) => col.width !== void 0 ? relativeLengthToTwips(col.width, measureTwips) : void 0
|
|
10302
|
-
);
|
|
10303
|
-
const totalStated = stated.reduce((sum, w) => sum + (w ?? 0), 0);
|
|
10304
|
-
const unstatedCount = columns.filter((col) => col.width === void 0).length;
|
|
10305
|
-
const remaining = Math.max(0, measureTwips - totalStated);
|
|
10306
|
-
const shareOfRemainder = unstatedCount > 0 ? remaining / unstatedCount : pointsToTwips(72);
|
|
10307
|
-
const values = stated.map((w) => w || shareOfRemainder);
|
|
10308
|
-
return {
|
|
10309
|
-
columnGrid: { unit: "twips", values },
|
|
10310
|
-
width: {
|
|
10311
|
-
size: values.reduce((sum, w) => sum + w, 0),
|
|
10312
|
-
unit: "twips"
|
|
10313
|
-
},
|
|
10314
|
-
...totalStated > measureTwips ? { overflow: { totalTwips: totalStated, availableTwips: measureTwips } } : {}
|
|
10315
|
-
};
|
|
10316
|
-
}
|
|
10317
|
-
|
|
10318
|
-
// src/ir/compiler.ts
|
|
10319
|
-
init_layoutUtils();
|
|
10320
|
-
|
|
10321
|
-
// src/utils/revisionUtils.ts
|
|
10322
|
-
var DEFAULT_REVISION_AUTHOR = "json-to-office";
|
|
10323
|
-
var DEFAULT_REVISION_DATE = "1970-01-01T00:00:00Z";
|
|
10324
|
-
|
|
10325
|
-
// src/utils/commentRegistry.ts
|
|
10326
|
-
var DEFAULT_COMMENT_AUTHOR = "json-to-office";
|
|
10327
|
-
var DEFAULT_COMMENT_DATE = "1970-01-01T00:00:00Z";
|
|
10328
|
-
|
|
10329
|
-
// src/ir/compiler.ts
|
|
10330
|
-
init_imageUtils();
|
|
10331
|
-
init_widthUtils();
|
|
10332
|
-
|
|
10333
|
-
// src/utils/numberingConfig.ts
|
|
10334
|
-
var HEADING_NUMBERING_REFERENCE = "jto-heading-numbering";
|
|
10335
|
-
function headingNumberLabel(number) {
|
|
10336
|
-
return `${number}.`;
|
|
10337
|
-
}
|
|
10338
|
-
|
|
10339
|
-
// src/utils/unicode.ts
|
|
10340
|
-
function normalizeUnicodeText(text) {
|
|
10341
|
-
return (text ?? "").normalize("NFC");
|
|
10342
|
-
}
|
|
10343
|
-
|
|
10344
|
-
// src/core/collectTocHeadings.ts
|
|
10345
|
-
import { getStandardComponent } from "@json-to-office/shared-docx";
|
|
10346
|
-
|
|
10347
|
-
// src/core/sectionBookmarks.ts
|
|
10348
|
-
function sectionBookmark(ordinal) {
|
|
10349
|
-
return { id: `_Section_${ordinal}`, linkId: ordinal };
|
|
10350
|
-
}
|
|
10351
|
-
|
|
10352
|
-
// src/utils/numberFormatting.ts
|
|
10353
|
-
var ROMAN_NUMERALS = [
|
|
10354
|
-
[1e3, "m"],
|
|
10355
|
-
[900, "cm"],
|
|
10356
|
-
[500, "d"],
|
|
10357
|
-
[400, "cd"],
|
|
10358
|
-
[100, "c"],
|
|
10359
|
-
[90, "xc"],
|
|
10360
|
-
[50, "l"],
|
|
10361
|
-
[40, "xl"],
|
|
10362
|
-
[10, "x"],
|
|
10363
|
-
[9, "ix"],
|
|
10364
|
-
[5, "v"],
|
|
10365
|
-
[4, "iv"],
|
|
10366
|
-
[1, "i"]
|
|
10367
|
-
];
|
|
10368
|
-
function toRoman(value) {
|
|
10369
|
-
let remaining = value;
|
|
10370
|
-
let out = "";
|
|
10371
|
-
for (const [amount, glyph] of ROMAN_NUMERALS) {
|
|
10372
|
-
while (remaining >= amount) {
|
|
10373
|
-
out += glyph;
|
|
10374
|
-
remaining -= amount;
|
|
10375
|
-
}
|
|
10376
|
-
}
|
|
10377
|
-
return out;
|
|
10378
|
-
}
|
|
10379
|
-
function toLetters(value) {
|
|
10380
|
-
const index = (value - 1) % 26;
|
|
10381
|
-
const repeats = Math.floor((value - 1) / 26) + 1;
|
|
10382
|
-
return String.fromCharCode(97 + index).repeat(repeats);
|
|
10383
|
-
}
|
|
10384
|
-
function formatNumberForLevel(value, format2) {
|
|
10385
|
-
if (!Number.isFinite(value) || value < 1) return void 0;
|
|
10386
|
-
const n = Math.floor(value);
|
|
10387
|
-
switch (format2) {
|
|
10388
|
-
case "decimal":
|
|
10389
|
-
return String(n);
|
|
10390
|
-
case "lowerLetter":
|
|
10391
|
-
return toLetters(n);
|
|
10392
|
-
case "upperLetter":
|
|
10393
|
-
return toLetters(n).toUpperCase();
|
|
10394
|
-
case "lowerRoman":
|
|
10395
|
-
return toRoman(n);
|
|
10396
|
-
case "upperRoman":
|
|
10397
|
-
return toRoman(n).toUpperCase();
|
|
10398
|
-
default:
|
|
10399
|
-
return void 0;
|
|
10400
|
-
}
|
|
10401
|
-
}
|
|
10402
|
-
|
|
10403
|
-
// src/core/collectTocHeadings.ts
|
|
10404
|
-
var MAX_HEADING_LEVEL = 6;
|
|
10405
|
-
var MAX_LIST_LEVEL = 9;
|
|
10406
|
-
function normalizeEntryTitle(text) {
|
|
10407
|
-
return normalizeUnicodeText(text).replace(/(\*\*\*|___)([\s\S]*?)\1/g, "$2").replace(/(\*\*|__)([\s\S]*?)\1/g, "$2").replace(/(\*|_)([\s\S]*?)\1/g, "$2").trim();
|
|
10408
|
-
}
|
|
10409
|
-
function isContainer(name) {
|
|
10410
|
-
return getStandardComponent(name)?.hasChildren === true;
|
|
10411
|
-
}
|
|
10412
|
-
function isEnabled(component) {
|
|
10413
|
-
return !("enabled" in component && component.enabled === false);
|
|
10414
|
-
}
|
|
10415
|
-
function styleEntryKey(props) {
|
|
10416
|
-
const themeStyle = props.themeStyle;
|
|
10417
|
-
if (typeof themeStyle !== "string" || !themeStyle) return void 0;
|
|
10418
|
-
if (/^heading[1-6]$/i.test(themeStyle)) return void 0;
|
|
10419
|
-
if (["normal", "title", "subtitle"].includes(themeStyle.toLowerCase())) {
|
|
10420
|
-
return void 0;
|
|
10421
|
-
}
|
|
10422
|
-
return themeStyle;
|
|
10423
|
-
}
|
|
10424
|
-
function levelStart(levels, level) {
|
|
10425
|
-
return levels[level]?.start ?? 1;
|
|
10426
|
-
}
|
|
10427
|
-
function collectDocumentOutline(sections) {
|
|
10428
|
-
const entries = [];
|
|
10429
|
-
const numberedItems = /* @__PURE__ */ new Map();
|
|
10430
|
-
const ordinals = computeSectionOrdinals(sections);
|
|
10431
|
-
const takenIds = /* @__PURE__ */ new Set();
|
|
10432
|
-
const headingCounters = new Array(MAX_HEADING_LEVEL).fill(0);
|
|
10433
|
-
const listCounters = /* @__PURE__ */ new Map();
|
|
10434
|
-
const visitHeading = (component, props, sectionBookmarkId) => {
|
|
10435
|
-
const text = typeof props.text === "string" ? props.text : "";
|
|
10436
|
-
const title = normalizeEntryTitle(text);
|
|
10437
|
-
const level = typeof props.level === "number" ? props.level : 1;
|
|
10438
|
-
const styleLevel = level >= 1 && level <= MAX_HEADING_LEVEL ? level : 1;
|
|
10439
|
-
let full;
|
|
10440
|
-
let own;
|
|
10441
|
-
if (props.numbering === true) {
|
|
10442
|
-
headingCounters[styleLevel - 1] += 1;
|
|
10443
|
-
for (let deeper = styleLevel; deeper < MAX_HEADING_LEVEL; deeper++) {
|
|
10444
|
-
headingCounters[deeper] = 0;
|
|
10445
|
-
}
|
|
10446
|
-
full = headingCounters.slice(0, styleLevel).join(".");
|
|
10447
|
-
own = String(headingCounters[styleLevel - 1]);
|
|
10448
|
-
}
|
|
10449
|
-
const explicitId = component.id;
|
|
10450
|
-
const bookmarkId = typeof explicitId === "string" && explicitId ? explicitId : dedupeBookmarkId(slugifyBookmarkText(text), (id) => takenIds.has(id));
|
|
10451
|
-
takenIds.add(bookmarkId);
|
|
10452
|
-
numberedItems.set(bookmarkId, {
|
|
10453
|
-
kind: "heading",
|
|
10454
|
-
text: title,
|
|
10455
|
-
...full !== void 0 && { full, own }
|
|
10456
|
-
});
|
|
10457
|
-
if (title) {
|
|
10458
|
-
entries.push({
|
|
10459
|
-
title,
|
|
10460
|
-
level,
|
|
10461
|
-
sectionBookmarkId,
|
|
10462
|
-
...full !== void 0 && { number: full }
|
|
10463
|
-
});
|
|
10464
|
-
}
|
|
10465
|
-
};
|
|
10466
|
-
const visitList = (props) => {
|
|
10467
|
-
const items = Array.isArray(props.items) ? props.items : [];
|
|
10468
|
-
if (items.length === 0) return;
|
|
10469
|
-
const reference = typeof props.reference === "string" && props.reference ? props.reference : void 0;
|
|
10470
|
-
const freshState = () => {
|
|
10471
|
-
const levels = resolveListLevels(
|
|
10472
|
-
props
|
|
10473
|
-
);
|
|
10474
|
-
return {
|
|
10475
|
-
levels,
|
|
10476
|
-
counters: Array.from(
|
|
10477
|
-
{ length: MAX_LIST_LEVEL },
|
|
10478
|
-
(_, level) => levelStart(levels, level) - 1
|
|
10479
|
-
)
|
|
10480
|
-
};
|
|
10481
|
-
};
|
|
10482
|
-
let state;
|
|
10483
|
-
if (reference === void 0) {
|
|
10484
|
-
state = freshState();
|
|
10485
|
-
} else {
|
|
10486
|
-
state = listCounters.get(reference) ?? freshState();
|
|
10487
|
-
listCounters.set(reference, state);
|
|
10488
|
-
}
|
|
10489
|
-
for (const item of items) {
|
|
10490
|
-
const isObject = typeof item === "object" && item !== null;
|
|
10491
|
-
const raw = isObject ? item.text : item;
|
|
10492
|
-
const text = typeof raw === "string" ? raw : "";
|
|
10493
|
-
if (!text.trim() && !(isObject && item.revision)) continue;
|
|
10494
|
-
const rawLevel = isObject ? item.level : void 0;
|
|
10495
|
-
const level = typeof rawLevel === "number" && rawLevel >= 0 ? rawLevel : 0;
|
|
10496
|
-
if (level >= MAX_LIST_LEVEL) continue;
|
|
10497
|
-
state.counters[level] += 1;
|
|
10498
|
-
for (let deeper = level + 1; deeper < MAX_LIST_LEVEL; deeper++) {
|
|
10499
|
-
state.counters[deeper] = levelStart(state.levels, deeper) - 1;
|
|
10500
|
-
}
|
|
10501
|
-
const id = isObject ? item.id : void 0;
|
|
10502
|
-
if (typeof id !== "string" || !id) continue;
|
|
10503
|
-
takenIds.add(id);
|
|
10504
|
-
const number = formatNumberForLevel(
|
|
10505
|
-
state.counters[level],
|
|
10506
|
-
state.levels[level]?.format
|
|
10507
|
-
);
|
|
10508
|
-
numberedItems.set(id, {
|
|
10509
|
-
kind: "list-item",
|
|
10510
|
-
text: normalizeUnicodeText(text).trim(),
|
|
10511
|
-
...number !== void 0 && { full: number, own: number }
|
|
10512
|
-
});
|
|
10513
|
-
}
|
|
10514
|
-
};
|
|
10515
|
-
sections.forEach((section2, index) => {
|
|
10516
|
-
const ordinal = ordinals[index]?.ordinal;
|
|
10517
|
-
const sectionBookmarkId = ordinal ? sectionBookmark(ordinal).id : void 0;
|
|
10518
|
-
const visit = (component) => {
|
|
10519
|
-
if (!isEnabled(component)) return;
|
|
10520
|
-
const props = component.props ?? {};
|
|
10521
|
-
if (component.name === "heading") {
|
|
10522
|
-
visitHeading(component, props, sectionBookmarkId);
|
|
10523
|
-
return;
|
|
10524
|
-
}
|
|
10525
|
-
if (component.name === "paragraph") {
|
|
10526
|
-
if (typeof props.id === "string" && props.id) takenIds.add(props.id);
|
|
10527
|
-
const styleId = styleEntryKey(props);
|
|
10528
|
-
const text = typeof props.text === "string" ? props.text : "";
|
|
10529
|
-
const title = normalizeEntryTitle(text);
|
|
10530
|
-
if (styleId && title) {
|
|
10531
|
-
entries.push({ title, level: 1, styleId, sectionBookmarkId });
|
|
10532
|
-
}
|
|
10533
|
-
return;
|
|
10534
|
-
}
|
|
10535
|
-
if (component.name === "list") {
|
|
10536
|
-
visitList(props);
|
|
10537
|
-
return;
|
|
10538
|
-
}
|
|
10539
|
-
if (!isContainer(component.name)) return;
|
|
10540
|
-
const children = component.children;
|
|
10541
|
-
if (Array.isArray(children)) children.forEach(visit);
|
|
10542
|
-
};
|
|
10543
|
-
section2.components.forEach(visit);
|
|
10544
|
-
});
|
|
10545
|
-
return { entries, numberedItems };
|
|
10546
|
-
}
|
|
10547
|
-
|
|
10548
|
-
// src/core/tocField.ts
|
|
10549
|
-
function toStyleDisplayName(styleId) {
|
|
10550
|
-
return styleId.replace(/([A-Z])/g, " $1").replace(/[-_]+/g, " ").replace(/\s+/g, " ").trim();
|
|
10551
|
-
}
|
|
10552
|
-
function parseDepthRange(rawDepth, fieldName, defaultFrom = 1, defaultTo = 3) {
|
|
10553
|
-
if (typeof rawDepth !== "object" || rawDepth === null) {
|
|
10554
|
-
throw new Error(
|
|
10555
|
-
`${fieldName} must be a range object with optional "from" and/or "to" fields, received: ${JSON.stringify(rawDepth)}`
|
|
10556
|
-
);
|
|
10557
|
-
}
|
|
10558
|
-
const { from = defaultFrom, to = defaultTo } = rawDepth;
|
|
10559
|
-
if (from < 1 || from > 6 || to < 1 || to > 6) {
|
|
10560
|
-
throw new Error(
|
|
10561
|
-
`${fieldName} range values must be between 1 and 6, received: from=${from}, to=${to}`
|
|
10562
|
-
);
|
|
10563
|
-
}
|
|
10564
|
-
if (from > to) {
|
|
10565
|
-
throw new Error(
|
|
10566
|
-
`${fieldName} "from" must be less than or equal to "to", received: from=${from}, to=${to}`
|
|
10567
|
-
);
|
|
10568
|
-
}
|
|
10569
|
-
return { from, to };
|
|
10570
|
-
}
|
|
10571
|
-
function selectEntries(collected, options) {
|
|
10572
|
-
if (!collected || collected.length === 0) return [];
|
|
10573
|
-
const { depthStart, depthEnd, bookmarkScope, styleLevels } = options;
|
|
10574
|
-
const entries = [];
|
|
10575
|
-
for (const entry of collected) {
|
|
10576
|
-
if (bookmarkScope && entry.sectionBookmarkId !== bookmarkScope) continue;
|
|
10577
|
-
if (entry.styleId !== void 0) {
|
|
10578
|
-
const level = styleLevels.get(entry.styleId) ?? styleLevels.get(toStyleDisplayName(entry.styleId));
|
|
10579
|
-
if (level === void 0) continue;
|
|
10580
|
-
entries.push({ text: entry.title, level });
|
|
10581
|
-
continue;
|
|
10582
|
-
}
|
|
10583
|
-
if (entry.level < depthStart || entry.level > depthEnd) continue;
|
|
10584
|
-
entries.push({
|
|
10585
|
-
text: entry.number ? `${headingNumberLabel(entry.number)} ${entry.title}` : entry.title,
|
|
10586
|
-
level: entry.level
|
|
10587
|
-
});
|
|
10588
|
-
}
|
|
10589
|
-
return entries;
|
|
10590
|
-
}
|
|
10591
|
-
function resolveTocField(props, theme, context) {
|
|
10592
|
-
const warnings = [];
|
|
10593
|
-
const headingRange = parseDepthRange(
|
|
10594
|
-
props.depth ?? { to: 3 },
|
|
10595
|
-
"TOC depth",
|
|
10596
|
-
1,
|
|
10597
|
-
3
|
|
10598
|
-
);
|
|
10599
|
-
const pageNumbers = props.pageNumbersDepth !== void 0 ? parseDepthRange(props.pageNumbersDepth, "TOC pageNumbersDepth", 1, 3) : void 0;
|
|
10600
|
-
if (props.numberingStyle !== void 0) {
|
|
10601
|
-
warnings.push(
|
|
10602
|
-
`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.`
|
|
10603
|
-
);
|
|
10604
|
-
}
|
|
10605
|
-
const scope = props.scope ?? "auto";
|
|
10606
|
-
const effectiveScope = scope === "auto" ? context.sectionBookmarkId ? "section" : "document" : scope;
|
|
10607
|
-
const bookmarkScope = effectiveScope === "section" ? context.sectionBookmarkId : void 0;
|
|
10608
|
-
if (effectiveScope === "section" && !bookmarkScope) {
|
|
10609
|
-
warnings.push(
|
|
10610
|
-
"TOC configured for section scope but no section bookmark found. Falling back to document scope."
|
|
10611
|
-
);
|
|
10612
|
-
}
|
|
10613
|
-
const styleLevels = /* @__PURE__ */ new Map();
|
|
10614
|
-
const styleSwitches = [];
|
|
10615
|
-
for (const mapping of props.styles ?? []) {
|
|
10616
|
-
const isCustomStyle = !!theme.styles && Object.prototype.hasOwnProperty.call(theme.styles, mapping.styleId);
|
|
10617
|
-
const displayName = isCustomStyle ? toStyleDisplayName(mapping.styleId) : mapping.styleId;
|
|
10618
|
-
styleLevels.set(mapping.styleId, mapping.level);
|
|
10619
|
-
styleLevels.set(displayName, mapping.level);
|
|
10620
|
-
styleSwitches.push({ styleName: displayName, level: mapping.level });
|
|
10621
|
-
}
|
|
10622
|
-
return {
|
|
10623
|
-
headingRange,
|
|
10624
|
-
styleLevels: styleSwitches,
|
|
10625
|
-
...bookmarkScope ? { bookmarkScope } : {},
|
|
10626
|
-
omitPageNumbersForLevels: omittedLevels(
|
|
10627
|
-
headingRange,
|
|
10628
|
-
pageNumbers,
|
|
10629
|
-
props.includePageNumbers !== false
|
|
10630
|
-
),
|
|
10631
|
-
// A boolean chooses between a tab and a space; a tab is the default.
|
|
10632
|
-
entrySeparator: props.numberSeparator === false ? " " : " ",
|
|
10633
|
-
entries: selectEntries(context.collected, {
|
|
10634
|
-
depthStart: headingRange.from,
|
|
10635
|
-
depthEnd: headingRange.to,
|
|
10636
|
-
bookmarkScope,
|
|
10637
|
-
styleLevels
|
|
10638
|
-
}),
|
|
10639
|
-
warnings
|
|
10607
|
+
source,
|
|
10608
|
+
columns,
|
|
10609
|
+
options.measureTwips ?? getAvailableWidthTwips(theme, themeName)
|
|
10610
|
+
),
|
|
10611
|
+
...hasHeader ? { header } : {},
|
|
10612
|
+
rows,
|
|
10613
|
+
repeatHeader: source.repeatHeaderOnPageBreak ?? true
|
|
10640
10614
|
};
|
|
10641
10615
|
}
|
|
10642
|
-
function
|
|
10643
|
-
|
|
10644
|
-
|
|
10645
|
-
|
|
10646
|
-
|
|
10647
|
-
|
|
10648
|
-
|
|
10649
|
-
|
|
10650
|
-
|
|
10651
|
-
|
|
10616
|
+
function drawsNothing(border3) {
|
|
10617
|
+
return border3.hidden || border3.size <= 0;
|
|
10618
|
+
}
|
|
10619
|
+
function channels(hex) {
|
|
10620
|
+
const digits = hex.startsWith("#") ? hex.slice(1) : hex;
|
|
10621
|
+
return [
|
|
10622
|
+
parseInt(digits.slice(0, 2), 16) || 0,
|
|
10623
|
+
parseInt(digits.slice(2, 4), 16) || 0,
|
|
10624
|
+
parseInt(digits.slice(4, 6), 16) || 0
|
|
10625
|
+
];
|
|
10626
|
+
}
|
|
10627
|
+
function outweighs(a, b) {
|
|
10628
|
+
if (drawsNothing(a)) return false;
|
|
10629
|
+
if (drawsNothing(b)) return true;
|
|
10630
|
+
if (a.size !== b.size) return a.size > b.size;
|
|
10631
|
+
const [redA, greenA, blueA] = channels(a.color);
|
|
10632
|
+
const [redB, greenB, blueB] = channels(b.color);
|
|
10633
|
+
const brightness = [
|
|
10634
|
+
[redA + blueA + 2 * greenA, redB + blueB + 2 * greenB],
|
|
10635
|
+
[blueA + 2 * greenA, blueB + 2 * greenB],
|
|
10636
|
+
[greenA, greenB]
|
|
10637
|
+
];
|
|
10638
|
+
for (const [ours, theirs] of brightness) {
|
|
10639
|
+
if (ours !== theirs) return ours < theirs;
|
|
10652
10640
|
}
|
|
10653
|
-
return
|
|
10641
|
+
return false;
|
|
10654
10642
|
}
|
|
10655
|
-
|
|
10656
|
-
|
|
10657
|
-
|
|
10658
|
-
|
|
10659
|
-
|
|
10660
|
-
let isUnordered = null;
|
|
10661
|
-
let isOrdered = null;
|
|
10662
|
-
for (const line of lines) {
|
|
10663
|
-
if (!line.trim()) continue;
|
|
10664
|
-
const unorderedMatch = line.match(/^(\s*)([-*])\s+(.+)$/);
|
|
10665
|
-
if (unorderedMatch) {
|
|
10666
|
-
const indentLevel = Math.floor(unorderedMatch[1].length / 2);
|
|
10667
|
-
const text2 = unorderedMatch[3];
|
|
10668
|
-
items.push({ text: text2, level: indentLevel });
|
|
10669
|
-
if (isUnordered === null) isUnordered = true;
|
|
10670
|
-
continue;
|
|
10671
|
-
}
|
|
10672
|
-
const orderedMatch = line.match(/^(\s*)(\d+)\.\s+(.+)$/);
|
|
10673
|
-
if (orderedMatch) {
|
|
10674
|
-
const indentLevel = Math.floor(orderedMatch[1].length / 2);
|
|
10675
|
-
const text2 = orderedMatch[3];
|
|
10676
|
-
items.push({ text: text2, level: indentLevel });
|
|
10677
|
-
if (isOrdered === null) isOrdered = true;
|
|
10678
|
-
continue;
|
|
10643
|
+
function adjudicateInteriorEdges(rows) {
|
|
10644
|
+
const settle = (earlier, later) => {
|
|
10645
|
+
if (drawsNothing(earlier) && drawsNothing(later)) return;
|
|
10646
|
+
if (earlier.hidden === later.hidden && earlier.size === later.size && earlier.color === later.color) {
|
|
10647
|
+
return;
|
|
10679
10648
|
}
|
|
10680
|
-
|
|
10681
|
-
|
|
10682
|
-
|
|
10683
|
-
|
|
10649
|
+
const winner = earlier.explicit !== later.explicit ? earlier.explicit ? earlier : later : outweighs(later, earlier) ? later : earlier;
|
|
10650
|
+
const loser = winner === earlier ? later : earlier;
|
|
10651
|
+
loser.size = winner.size;
|
|
10652
|
+
loser.color = winner.color;
|
|
10653
|
+
loser.hidden = winner.hidden;
|
|
10654
|
+
};
|
|
10655
|
+
rows.forEach((row, rowIndex) => {
|
|
10656
|
+
row.cells.forEach((cell, colIndex) => {
|
|
10657
|
+
const right = row.cells[colIndex + 1];
|
|
10658
|
+
if (right) settle(cell.borders.right, right.borders.left);
|
|
10659
|
+
const below = rows[rowIndex + 1]?.cells[colIndex];
|
|
10660
|
+
if (below) settle(cell.borders.bottom, below.borders.top);
|
|
10661
|
+
});
|
|
10662
|
+
});
|
|
10663
|
+
}
|
|
10664
|
+
function resolveWidths(source, columns, measureTwips) {
|
|
10665
|
+
const hasExplicitWidths = columns.some((col) => col.width !== void 0);
|
|
10666
|
+
if (!hasExplicitWidths) {
|
|
10667
|
+
const percent = source.width ?? 100;
|
|
10668
|
+
return {
|
|
10669
|
+
columnGrid: {
|
|
10670
|
+
unit: "twips",
|
|
10671
|
+
values: splitTwips(columns.length, measureTwips * percent / 100)
|
|
10672
|
+
},
|
|
10673
|
+
width: { size: percent, unit: "percent" }
|
|
10674
|
+
};
|
|
10684
10675
|
}
|
|
10676
|
+
const stated = columns.map(
|
|
10677
|
+
(col) => col.width !== void 0 ? relativeLengthToTwips(col.width, measureTwips) : void 0
|
|
10678
|
+
);
|
|
10679
|
+
const totalStated = stated.reduce((sum, w) => sum + (w ?? 0), 0);
|
|
10680
|
+
const unstatedCount = columns.filter((col) => col.width === void 0).length;
|
|
10681
|
+
const remaining = Math.max(0, measureTwips - totalStated);
|
|
10682
|
+
const shareOfRemainder = unstatedCount > 0 ? remaining / unstatedCount : pointsToTwips(72);
|
|
10683
|
+
const values = stated.map((w) => w || shareOfRemainder);
|
|
10685
10684
|
return {
|
|
10686
|
-
|
|
10687
|
-
|
|
10685
|
+
columnGrid: { unit: "twips", values },
|
|
10686
|
+
width: {
|
|
10687
|
+
size: values.reduce((sum, w) => sum + w, 0),
|
|
10688
|
+
unit: "twips"
|
|
10689
|
+
},
|
|
10690
|
+
...totalStated > measureTwips ? { overflow: { totalTwips: totalStated, availableTwips: measureTwips } } : {}
|
|
10688
10691
|
};
|
|
10689
10692
|
}
|
|
10690
10693
|
|
|
10691
|
-
// src/ir/
|
|
10692
|
-
|
|
10693
|
-
|
|
10694
|
-
|
|
10695
|
-
|
|
10696
|
-
|
|
10697
|
-
|
|
10698
|
-
|
|
10699
|
-
|
|
10700
|
-
|
|
10701
|
-
|
|
10702
|
-
|
|
10694
|
+
// src/ir/compiler.ts
|
|
10695
|
+
init_layoutUtils();
|
|
10696
|
+
|
|
10697
|
+
// src/utils/revisionUtils.ts
|
|
10698
|
+
var DEFAULT_REVISION_AUTHOR = "json-to-office";
|
|
10699
|
+
var DEFAULT_REVISION_DATE = "1970-01-01T00:00:00Z";
|
|
10700
|
+
|
|
10701
|
+
// src/utils/commentRegistry.ts
|
|
10702
|
+
var DEFAULT_COMMENT_AUTHOR = "json-to-office";
|
|
10703
|
+
var DEFAULT_COMMENT_DATE = "1970-01-01T00:00:00Z";
|
|
10704
|
+
|
|
10705
|
+
// src/ir/compiler.ts
|
|
10706
|
+
init_imageUtils();
|
|
10707
|
+
init_widthUtils();
|
|
10708
|
+
|
|
10709
|
+
// src/utils/numberingConfig.ts
|
|
10710
|
+
var HEADING_NUMBERING_REFERENCE = "jto-heading-numbering";
|
|
10711
|
+
function headingNumberLabel(number) {
|
|
10712
|
+
return `${number}.`;
|
|
10703
10713
|
}
|
|
10704
|
-
|
|
10705
|
-
|
|
10706
|
-
|
|
10707
|
-
|
|
10708
|
-
|
|
10709
|
-
|
|
10710
|
-
|
|
10711
|
-
const authored = text.includes(SENTINEL);
|
|
10712
|
-
if (!authored && !text.includes("\\")) return text;
|
|
10713
|
-
const guarded = authored ? text.split(SENTINEL).join(SENTINEL + SENTINEL_SELF) : text;
|
|
10714
|
-
return guarded.replace(
|
|
10715
|
-
ESCAPE,
|
|
10716
|
-
(_whole, char) => SENTINEL + String.fromCharCode(SENTINEL_DIGIT_BASE + ESCAPABLE.indexOf(char))
|
|
10717
|
-
);
|
|
10714
|
+
|
|
10715
|
+
// src/core/collectTocHeadings.ts
|
|
10716
|
+
import { getStandardComponent } from "@json-to-office/shared-docx";
|
|
10717
|
+
|
|
10718
|
+
// src/core/sectionBookmarks.ts
|
|
10719
|
+
function sectionBookmark(ordinal) {
|
|
10720
|
+
return { id: `_Section_${ordinal}`, linkId: ordinal };
|
|
10718
10721
|
}
|
|
10719
|
-
|
|
10720
|
-
|
|
10722
|
+
|
|
10723
|
+
// src/utils/numberFormatting.ts
|
|
10724
|
+
var ROMAN_NUMERALS = [
|
|
10725
|
+
[1e3, "m"],
|
|
10726
|
+
[900, "cm"],
|
|
10727
|
+
[500, "d"],
|
|
10728
|
+
[400, "cd"],
|
|
10729
|
+
[100, "c"],
|
|
10730
|
+
[90, "xc"],
|
|
10731
|
+
[50, "l"],
|
|
10732
|
+
[40, "xl"],
|
|
10733
|
+
[10, "x"],
|
|
10734
|
+
[9, "ix"],
|
|
10735
|
+
[5, "v"],
|
|
10736
|
+
[4, "iv"],
|
|
10737
|
+
[1, "i"]
|
|
10738
|
+
];
|
|
10739
|
+
function toRoman(value) {
|
|
10740
|
+
let remaining = value;
|
|
10721
10741
|
let out = "";
|
|
10722
|
-
for (
|
|
10723
|
-
|
|
10724
|
-
out +=
|
|
10725
|
-
|
|
10726
|
-
}
|
|
10727
|
-
const marker = text[i + 1];
|
|
10728
|
-
if (marker === SENTINEL_SELF) {
|
|
10729
|
-
out += SENTINEL;
|
|
10730
|
-
i += 1;
|
|
10731
|
-
continue;
|
|
10732
|
-
}
|
|
10733
|
-
const index = marker === void 0 ? -1 : marker.charCodeAt(0) - SENTINEL_DIGIT_BASE;
|
|
10734
|
-
if (index >= 0 && index < ESCAPABLE.length) {
|
|
10735
|
-
out += ESCAPABLE[index];
|
|
10736
|
-
i += 1;
|
|
10737
|
-
continue;
|
|
10742
|
+
for (const [amount, glyph] of ROMAN_NUMERALS) {
|
|
10743
|
+
while (remaining >= amount) {
|
|
10744
|
+
out += glyph;
|
|
10745
|
+
remaining -= amount;
|
|
10738
10746
|
}
|
|
10739
|
-
out += text[i];
|
|
10740
10747
|
}
|
|
10741
10748
|
return out;
|
|
10742
10749
|
}
|
|
10743
|
-
|
|
10744
|
-
|
|
10745
|
-
|
|
10746
|
-
|
|
10747
|
-
var CROSS_REFERENCE = /\[@([^\]\s:]+)(?::(relative|no_context|full_context|none))?\]/;
|
|
10748
|
-
var INLINE_TOKEN = new RegExp(
|
|
10749
|
-
`${LINK.source}|${CROSS_REFERENCE.source}`,
|
|
10750
|
-
"g"
|
|
10751
|
-
);
|
|
10752
|
-
var NOTE_MARKER = /\[\^([^\]\s]+)\]/g;
|
|
10753
|
-
function containsPlaceholder(text) {
|
|
10754
|
-
return PLACEHOLDER.test(text);
|
|
10750
|
+
function toLetters(value) {
|
|
10751
|
+
const index = (value - 1) % 26;
|
|
10752
|
+
const repeats = Math.floor((value - 1) / 26) + 1;
|
|
10753
|
+
return String.fromCharCode(97 + index).repeat(repeats);
|
|
10755
10754
|
}
|
|
10756
|
-
function
|
|
10757
|
-
|
|
10755
|
+
function formatNumberForLevel(value, format2) {
|
|
10756
|
+
if (!Number.isFinite(value) || value < 1) return void 0;
|
|
10757
|
+
const n = Math.floor(value);
|
|
10758
|
+
switch (format2) {
|
|
10759
|
+
case "decimal":
|
|
10760
|
+
return String(n);
|
|
10761
|
+
case "lowerLetter":
|
|
10762
|
+
return toLetters(n);
|
|
10763
|
+
case "upperLetter":
|
|
10764
|
+
return toLetters(n).toUpperCase();
|
|
10765
|
+
case "lowerRoman":
|
|
10766
|
+
return toRoman(n);
|
|
10767
|
+
case "upperRoman":
|
|
10768
|
+
return toRoman(n).toUpperCase();
|
|
10769
|
+
default:
|
|
10770
|
+
return void 0;
|
|
10771
|
+
}
|
|
10772
|
+
}
|
|
10773
|
+
|
|
10774
|
+
// src/core/collectTocHeadings.ts
|
|
10775
|
+
var MAX_HEADING_LEVEL = 6;
|
|
10776
|
+
var MAX_LIST_LEVEL = 9;
|
|
10777
|
+
function normalizeEntryTitle(text) {
|
|
10778
|
+
return normalizeUnicodeText(text).replace(/(\*\*\*|___)([\s\S]*?)\1/g, "$2").replace(/(\*\*|__)([\s\S]*?)\1/g, "$2").replace(/(\*|_)([\s\S]*?)\1/g, "$2").trim();
|
|
10779
|
+
}
|
|
10780
|
+
function isContainer(name) {
|
|
10781
|
+
return getStandardComponent(name)?.hasChildren === true;
|
|
10758
10782
|
}
|
|
10759
|
-
function
|
|
10760
|
-
return
|
|
10783
|
+
function isEnabled(component) {
|
|
10784
|
+
return !("enabled" in component && component.enabled === false);
|
|
10761
10785
|
}
|
|
10762
|
-
function
|
|
10763
|
-
|
|
10764
|
-
|
|
10786
|
+
function styleEntryKey(props) {
|
|
10787
|
+
const themeStyle = props.themeStyle;
|
|
10788
|
+
if (typeof themeStyle !== "string" || !themeStyle) return void 0;
|
|
10789
|
+
if (/^heading[1-6]$/i.test(themeStyle)) return void 0;
|
|
10790
|
+
if (["normal", "title", "subtitle"].includes(themeStyle.toLowerCase())) {
|
|
10791
|
+
return void 0;
|
|
10765
10792
|
}
|
|
10766
|
-
return
|
|
10793
|
+
return themeStyle;
|
|
10767
10794
|
}
|
|
10768
|
-
function
|
|
10769
|
-
|
|
10770
|
-
if (!normalized) {
|
|
10771
|
-
return [
|
|
10772
|
-
{ kind: "text", text: "", formatting: emptyToUndefined(options.base) }
|
|
10773
|
-
];
|
|
10774
|
-
}
|
|
10775
|
-
if (containsPlaceholder(normalized)) {
|
|
10776
|
-
return parsePlaceholders(normalized, options);
|
|
10777
|
-
}
|
|
10778
|
-
if (options.hyperlinks) return parseLinks(normalized, options);
|
|
10779
|
-
return parseDecorated(normalized, options);
|
|
10795
|
+
function levelStart(levels, level) {
|
|
10796
|
+
return levels[level]?.start ?? 1;
|
|
10780
10797
|
}
|
|
10781
|
-
function
|
|
10782
|
-
const
|
|
10783
|
-
|
|
10784
|
-
|
|
10785
|
-
|
|
10786
|
-
|
|
10787
|
-
const
|
|
10788
|
-
const
|
|
10789
|
-
|
|
10790
|
-
|
|
10791
|
-
|
|
10792
|
-
|
|
10793
|
-
|
|
10798
|
+
function collectDocumentOutline(sections) {
|
|
10799
|
+
const entries = [];
|
|
10800
|
+
const numberedItems = /* @__PURE__ */ new Map();
|
|
10801
|
+
const ordinals = computeSectionOrdinals(sections);
|
|
10802
|
+
const takenIds = /* @__PURE__ */ new Set();
|
|
10803
|
+
const headingCounters = new Array(MAX_HEADING_LEVEL).fill(0);
|
|
10804
|
+
const listCounters = /* @__PURE__ */ new Map();
|
|
10805
|
+
const visitHeading = (component, props, sectionBookmarkId) => {
|
|
10806
|
+
const text = typeof props.text === "string" ? props.text : "";
|
|
10807
|
+
const title = normalizeEntryTitle(text);
|
|
10808
|
+
const level = typeof props.level === "number" ? props.level : 1;
|
|
10809
|
+
const styleLevel = level >= 1 && level <= MAX_HEADING_LEVEL ? level : 1;
|
|
10810
|
+
let full;
|
|
10811
|
+
let own;
|
|
10812
|
+
if (props.numbering === true) {
|
|
10813
|
+
headingCounters[styleLevel - 1] += 1;
|
|
10814
|
+
for (let deeper = styleLevel; deeper < MAX_HEADING_LEVEL; deeper++) {
|
|
10815
|
+
headingCounters[deeper] = 0;
|
|
10816
|
+
}
|
|
10817
|
+
full = headingCounters.slice(0, styleLevel).join(".");
|
|
10818
|
+
own = String(headingCounters[styleLevel - 1]);
|
|
10819
|
+
}
|
|
10820
|
+
const explicitId = component.id;
|
|
10821
|
+
const bookmarkId = typeof explicitId === "string" && explicitId ? explicitId : dedupeBookmarkId(slugifyBookmarkText(text), (id) => takenIds.has(id));
|
|
10822
|
+
takenIds.add(bookmarkId);
|
|
10823
|
+
numberedItems.set(bookmarkId, {
|
|
10824
|
+
kind: "heading",
|
|
10825
|
+
text: title,
|
|
10826
|
+
...full !== void 0 && { full, own }
|
|
10827
|
+
});
|
|
10828
|
+
if (title) {
|
|
10829
|
+
entries.push({
|
|
10830
|
+
title,
|
|
10831
|
+
level,
|
|
10832
|
+
sectionBookmarkId,
|
|
10833
|
+
...full !== void 0 && { number: full }
|
|
10834
|
+
});
|
|
10835
|
+
}
|
|
10794
10836
|
};
|
|
10795
|
-
|
|
10796
|
-
|
|
10797
|
-
|
|
10837
|
+
const visitList = (props) => {
|
|
10838
|
+
const items = Array.isArray(props.items) ? props.items : [];
|
|
10839
|
+
if (items.length === 0) return;
|
|
10840
|
+
const reference = typeof props.reference === "string" && props.reference ? props.reference : void 0;
|
|
10841
|
+
const freshState = () => {
|
|
10842
|
+
const levels = resolveListLevels(
|
|
10843
|
+
props
|
|
10844
|
+
);
|
|
10845
|
+
return {
|
|
10846
|
+
levels,
|
|
10847
|
+
counters: Array.from(
|
|
10848
|
+
{ length: MAX_LIST_LEVEL },
|
|
10849
|
+
(_, level) => levelStart(levels, level) - 1
|
|
10850
|
+
)
|
|
10851
|
+
};
|
|
10852
|
+
};
|
|
10853
|
+
let state;
|
|
10854
|
+
if (reference === void 0) {
|
|
10855
|
+
state = freshState();
|
|
10856
|
+
} else {
|
|
10857
|
+
state = listCounters.get(reference) ?? freshState();
|
|
10858
|
+
listCounters.set(reference, state);
|
|
10798
10859
|
}
|
|
10799
|
-
|
|
10800
|
-
|
|
10801
|
-
const
|
|
10802
|
-
|
|
10803
|
-
|
|
10804
|
-
|
|
10805
|
-
|
|
10806
|
-
|
|
10807
|
-
|
|
10808
|
-
|
|
10809
|
-
|
|
10810
|
-
color: options.base.color,
|
|
10811
|
-
bold: options.base.bold,
|
|
10812
|
-
italic: options.base.italic,
|
|
10813
|
-
underline: options.base.underline
|
|
10814
|
-
});
|
|
10815
|
-
out.push({
|
|
10816
|
-
kind: "field",
|
|
10817
|
-
instruction: resolved.instruction,
|
|
10818
|
-
...resolved.cachedText !== void 0 && {
|
|
10819
|
-
cachedText: resolved.cachedText
|
|
10820
|
-
},
|
|
10821
|
-
...formatting ? { formatting } : {}
|
|
10822
|
-
});
|
|
10860
|
+
for (const item of items) {
|
|
10861
|
+
const isObject = typeof item === "object" && item !== null;
|
|
10862
|
+
const raw = isObject ? item.text : item;
|
|
10863
|
+
const text = typeof raw === "string" ? raw : "";
|
|
10864
|
+
if (!text.trim() && !(isObject && item.revision)) continue;
|
|
10865
|
+
const rawLevel = isObject ? item.level : void 0;
|
|
10866
|
+
const level = typeof rawLevel === "number" && rawLevel >= 0 ? rawLevel : 0;
|
|
10867
|
+
if (level >= MAX_LIST_LEVEL) continue;
|
|
10868
|
+
state.counters[level] += 1;
|
|
10869
|
+
for (let deeper = level + 1; deeper < MAX_LIST_LEVEL; deeper++) {
|
|
10870
|
+
state.counters[deeper] = levelStart(state.levels, deeper) - 1;
|
|
10823
10871
|
}
|
|
10824
|
-
|
|
10872
|
+
const id = isObject ? item.id : void 0;
|
|
10873
|
+
if (typeof id !== "string" || !id) continue;
|
|
10874
|
+
takenIds.add(id);
|
|
10875
|
+
const number = formatNumberForLevel(
|
|
10876
|
+
state.counters[level],
|
|
10877
|
+
state.levels[level]?.format
|
|
10878
|
+
);
|
|
10879
|
+
numberedItems.set(id, {
|
|
10880
|
+
kind: "list-item",
|
|
10881
|
+
text: normalizeUnicodeText(text).trim(),
|
|
10882
|
+
...number !== void 0 && { full: number, own: number }
|
|
10883
|
+
});
|
|
10825
10884
|
}
|
|
10826
|
-
|
|
10827
|
-
|
|
10828
|
-
|
|
10829
|
-
|
|
10830
|
-
|
|
10831
|
-
|
|
10832
|
-
|
|
10833
|
-
|
|
10834
|
-
|
|
10835
|
-
|
|
10836
|
-
|
|
10837
|
-
|
|
10838
|
-
|
|
10839
|
-
|
|
10840
|
-
|
|
10841
|
-
|
|
10842
|
-
|
|
10843
|
-
|
|
10844
|
-
|
|
10885
|
+
};
|
|
10886
|
+
sections.forEach((section2, index) => {
|
|
10887
|
+
const ordinal = ordinals[index]?.ordinal;
|
|
10888
|
+
const sectionBookmarkId = ordinal ? sectionBookmark(ordinal).id : void 0;
|
|
10889
|
+
const visit = (component) => {
|
|
10890
|
+
if (!isEnabled(component)) return;
|
|
10891
|
+
const props = component.props ?? {};
|
|
10892
|
+
if (component.name === "heading") {
|
|
10893
|
+
visitHeading(component, props, sectionBookmarkId);
|
|
10894
|
+
return;
|
|
10895
|
+
}
|
|
10896
|
+
if (component.name === "paragraph") {
|
|
10897
|
+
if (typeof props.id === "string" && props.id) takenIds.add(props.id);
|
|
10898
|
+
const styleId = styleEntryKey(props);
|
|
10899
|
+
const text = typeof props.text === "string" ? props.text : "";
|
|
10900
|
+
const title = normalizeEntryTitle(text);
|
|
10901
|
+
if (styleId && title) {
|
|
10902
|
+
entries.push({ title, level: 1, styleId, sectionBookmarkId });
|
|
10903
|
+
}
|
|
10904
|
+
return;
|
|
10905
|
+
}
|
|
10906
|
+
if (component.name === "list") {
|
|
10907
|
+
visitList(props);
|
|
10908
|
+
return;
|
|
10909
|
+
}
|
|
10910
|
+
if (!isContainer(component.name)) return;
|
|
10911
|
+
const children = component.children;
|
|
10912
|
+
if (Array.isArray(children)) children.forEach(visit);
|
|
10913
|
+
};
|
|
10914
|
+
section2.components.forEach(visit);
|
|
10915
|
+
});
|
|
10916
|
+
return { entries, numberedItems };
|
|
10845
10917
|
}
|
|
10846
|
-
|
|
10847
|
-
|
|
10848
|
-
|
|
10849
|
-
|
|
10850
|
-
normalizeUnicodeText(text),
|
|
10851
|
-
emptyToUndefined(options.base),
|
|
10852
|
-
options
|
|
10853
|
-
);
|
|
10854
|
-
return out;
|
|
10918
|
+
|
|
10919
|
+
// src/core/tocField.ts
|
|
10920
|
+
function toStyleDisplayName(styleId) {
|
|
10921
|
+
return styleId.replace(/([A-Z])/g, " $1").replace(/[-_]+/g, " ").replace(/\s+/g, " ").trim();
|
|
10855
10922
|
}
|
|
10856
|
-
function
|
|
10857
|
-
|
|
10858
|
-
|
|
10859
|
-
|
|
10860
|
-
|
|
10861
|
-
|
|
10862
|
-
|
|
10863
|
-
|
|
10864
|
-
|
|
10865
|
-
|
|
10866
|
-
|
|
10867
|
-
|
|
10868
|
-
|
|
10869
|
-
|
|
10870
|
-
|
|
10871
|
-
|
|
10872
|
-
|
|
10873
|
-
|
|
10874
|
-
|
|
10875
|
-
|
|
10923
|
+
function parseDepthRange(rawDepth, fieldName, defaultFrom = 1, defaultTo = 3) {
|
|
10924
|
+
if (typeof rawDepth !== "object" || rawDepth === null) {
|
|
10925
|
+
throw new Error(
|
|
10926
|
+
`${fieldName} must be a range object with optional "from" and/or "to" fields, received: ${JSON.stringify(rawDepth)}`
|
|
10927
|
+
);
|
|
10928
|
+
}
|
|
10929
|
+
const { from = defaultFrom, to = defaultTo } = rawDepth;
|
|
10930
|
+
if (from < 1 || from > 6 || to < 1 || to > 6) {
|
|
10931
|
+
throw new Error(
|
|
10932
|
+
`${fieldName} range values must be between 1 and 6, received: from=${from}, to=${to}`
|
|
10933
|
+
);
|
|
10934
|
+
}
|
|
10935
|
+
if (from > to) {
|
|
10936
|
+
throw new Error(
|
|
10937
|
+
`${fieldName} "from" must be less than or equal to "to", received: from=${from}, to=${to}`
|
|
10938
|
+
);
|
|
10939
|
+
}
|
|
10940
|
+
return { from, to };
|
|
10941
|
+
}
|
|
10942
|
+
function selectEntries(collected, options) {
|
|
10943
|
+
if (!collected || collected.length === 0) return [];
|
|
10944
|
+
const { depthStart, depthEnd, bookmarkScope, styleLevels } = options;
|
|
10945
|
+
const entries = [];
|
|
10946
|
+
for (const entry of collected) {
|
|
10947
|
+
if (bookmarkScope && entry.sectionBookmarkId !== bookmarkScope) continue;
|
|
10948
|
+
if (entry.styleId !== void 0) {
|
|
10949
|
+
const level = styleLevels.get(entry.styleId) ?? styleLevels.get(toStyleDisplayName(entry.styleId));
|
|
10950
|
+
if (level === void 0) continue;
|
|
10951
|
+
entries.push({ text: entry.title, level });
|
|
10876
10952
|
continue;
|
|
10877
10953
|
}
|
|
10878
|
-
|
|
10879
|
-
|
|
10880
|
-
|
|
10881
|
-
|
|
10882
|
-
// A `#anchor` target names a bookmark in this document and needs no
|
|
10883
|
-
// relationship; anything else leaves the document.
|
|
10884
|
-
target: target2.startsWith("#") ? { kind: "bookmark", anchor: target2.slice(1) } : { kind: "external", url: target2 },
|
|
10885
|
-
children: parseDecorated(linkText, options)
|
|
10954
|
+
if (entry.level < depthStart || entry.level > depthEnd) continue;
|
|
10955
|
+
entries.push({
|
|
10956
|
+
text: entry.number ? `${headingNumberLabel(entry.number)} ${entry.title}` : entry.title,
|
|
10957
|
+
level: entry.level
|
|
10886
10958
|
});
|
|
10887
10959
|
}
|
|
10888
|
-
|
|
10889
|
-
out.push(...parseDecorated(normalized.slice(lastIndex), options));
|
|
10890
|
-
}
|
|
10891
|
-
if (out.length === 0) return parseDecorated(normalized, options);
|
|
10892
|
-
return out;
|
|
10960
|
+
return entries;
|
|
10893
10961
|
}
|
|
10894
|
-
function
|
|
10895
|
-
const
|
|
10896
|
-
|
|
10897
|
-
|
|
10898
|
-
|
|
10899
|
-
|
|
10900
|
-
|
|
10901
|
-
|
|
10902
|
-
|
|
10903
|
-
|
|
10904
|
-
|
|
10905
|
-
|
|
10906
|
-
options,
|
|
10907
|
-
decoratedStyle(match, options.base)
|
|
10962
|
+
function resolveTocField(props, theme, context) {
|
|
10963
|
+
const warnings = [];
|
|
10964
|
+
const headingRange = parseDepthRange(
|
|
10965
|
+
props.depth ?? { to: 3 },
|
|
10966
|
+
"TOC depth",
|
|
10967
|
+
1,
|
|
10968
|
+
3
|
|
10969
|
+
);
|
|
10970
|
+
const pageNumbers = props.pageNumbersDepth !== void 0 ? parseDepthRange(props.pageNumbersDepth, "TOC pageNumbersDepth", 1, 3) : void 0;
|
|
10971
|
+
if (props.numberingStyle !== void 0) {
|
|
10972
|
+
warnings.push(
|
|
10973
|
+
`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.`
|
|
10908
10974
|
);
|
|
10909
|
-
lastIndex = match.index + match[0].length;
|
|
10910
10975
|
}
|
|
10911
|
-
|
|
10912
|
-
|
|
10976
|
+
const scope = props.scope ?? "auto";
|
|
10977
|
+
const effectiveScope = scope === "auto" ? context.sectionBookmarkId ? "section" : "document" : scope;
|
|
10978
|
+
const bookmarkScope = effectiveScope === "section" ? context.sectionBookmarkId : void 0;
|
|
10979
|
+
if (effectiveScope === "section" && !bookmarkScope) {
|
|
10980
|
+
warnings.push(
|
|
10981
|
+
"TOC configured for section scope but no section bookmark found. Falling back to document scope."
|
|
10982
|
+
);
|
|
10913
10983
|
}
|
|
10914
|
-
|
|
10915
|
-
|
|
10916
|
-
|
|
10917
|
-
|
|
10918
|
-
|
|
10919
|
-
|
|
10920
|
-
|
|
10921
|
-
|
|
10922
|
-
}
|
|
10923
|
-
|
|
10924
|
-
|
|
10925
|
-
|
|
10926
|
-
|
|
10927
|
-
|
|
10928
|
-
|
|
10929
|
-
|
|
10984
|
+
const styleLevels = /* @__PURE__ */ new Map();
|
|
10985
|
+
const styleSwitches = [];
|
|
10986
|
+
for (const mapping of props.styles ?? []) {
|
|
10987
|
+
const isCustomStyle = !!theme.styles && Object.prototype.hasOwnProperty.call(theme.styles, mapping.styleId);
|
|
10988
|
+
const displayName = isCustomStyle ? toStyleDisplayName(mapping.styleId) : mapping.styleId;
|
|
10989
|
+
styleLevels.set(mapping.styleId, mapping.level);
|
|
10990
|
+
styleLevels.set(displayName, mapping.level);
|
|
10991
|
+
styleSwitches.push({ styleName: displayName, level: mapping.level });
|
|
10992
|
+
}
|
|
10993
|
+
return {
|
|
10994
|
+
headingRange,
|
|
10995
|
+
styleLevels: styleSwitches,
|
|
10996
|
+
...bookmarkScope ? { bookmarkScope } : {},
|
|
10997
|
+
omitPageNumbersForLevels: omittedLevels(
|
|
10998
|
+
headingRange,
|
|
10999
|
+
pageNumbers,
|
|
11000
|
+
props.includePageNumbers !== false
|
|
11001
|
+
),
|
|
11002
|
+
// A boolean chooses between a tab and a space; a tab is the default.
|
|
11003
|
+
entrySeparator: props.numberSeparator === false ? " " : " ",
|
|
11004
|
+
entries: selectEntries(context.collected, {
|
|
11005
|
+
depthStart: headingRange.from,
|
|
11006
|
+
depthEnd: headingRange.to,
|
|
11007
|
+
bookmarkScope,
|
|
11008
|
+
styleLevels
|
|
11009
|
+
}),
|
|
11010
|
+
warnings
|
|
11011
|
+
};
|
|
10930
11012
|
}
|
|
10931
|
-
function
|
|
10932
|
-
|
|
10933
|
-
|
|
10934
|
-
|
|
10935
|
-
|
|
10936
|
-
for (const [lineIndex, line] of lines.entries()) {
|
|
10937
|
-
if (!line && lineIndex === 0) continue;
|
|
10938
|
-
if (lineIndex > 0) out.push({ kind: "lineBreak" });
|
|
10939
|
-
if (!line) {
|
|
10940
|
-
out.push({ kind: "text", text: "", formatting });
|
|
10941
|
-
continue;
|
|
11013
|
+
function omittedLevels(headingRange, pageNumbers, includePageNumbers) {
|
|
11014
|
+
if (pageNumbers) {
|
|
11015
|
+
const omitted = [];
|
|
11016
|
+
if (pageNumbers.from > headingRange.from) {
|
|
11017
|
+
omitted.push({ from: headingRange.from, to: pageNumbers.from - 1 });
|
|
10942
11018
|
}
|
|
10943
|
-
|
|
10944
|
-
|
|
10945
|
-
if (tabIndex > 0) out.push({ kind: "tab", formatting });
|
|
10946
|
-
if (!segment && tabSegments.length > 1) continue;
|
|
10947
|
-
pushWords(out, segment, formatting, options);
|
|
11019
|
+
if (pageNumbers.to < headingRange.to) {
|
|
11020
|
+
omitted.push({ from: pageNumbers.to + 1, to: headingRange.to });
|
|
10948
11021
|
}
|
|
11022
|
+
return omitted;
|
|
10949
11023
|
}
|
|
11024
|
+
return includePageNumbers ? [] : [headingRange];
|
|
10950
11025
|
}
|
|
10951
|
-
|
|
10952
|
-
|
|
10953
|
-
|
|
10954
|
-
|
|
10955
|
-
|
|
10956
|
-
|
|
10957
|
-
|
|
10958
|
-
|
|
10959
|
-
|
|
10960
|
-
|
|
10961
|
-
|
|
10962
|
-
|
|
10963
|
-
|
|
10964
|
-
|
|
10965
|
-
|
|
10966
|
-
pending += text.slice(lastIndex, regex.lastIndex);
|
|
10967
|
-
lastIndex = regex.lastIndex;
|
|
11026
|
+
|
|
11027
|
+
// src/core/markdownList.ts
|
|
11028
|
+
function parseMarkdownList(text) {
|
|
11029
|
+
const lines = text.split("\n");
|
|
11030
|
+
const items = [];
|
|
11031
|
+
let isUnordered = null;
|
|
11032
|
+
let isOrdered = null;
|
|
11033
|
+
for (const line of lines) {
|
|
11034
|
+
if (!line.trim()) continue;
|
|
11035
|
+
const unorderedMatch = line.match(/^(\s*)([-*])\s+(.+)$/);
|
|
11036
|
+
if (unorderedMatch) {
|
|
11037
|
+
const indentLevel = Math.floor(unorderedMatch[1].length / 2);
|
|
11038
|
+
const text2 = unorderedMatch[3];
|
|
11039
|
+
items.push({ text: text2, level: indentLevel });
|
|
11040
|
+
if (isUnordered === null) isUnordered = true;
|
|
10968
11041
|
continue;
|
|
10969
11042
|
}
|
|
10970
|
-
const
|
|
10971
|
-
|
|
10972
|
-
|
|
10973
|
-
|
|
10974
|
-
|
|
10975
|
-
|
|
10976
|
-
|
|
10977
|
-
});
|
|
10978
|
-
lastIndex = regex.lastIndex;
|
|
10979
|
-
}
|
|
10980
|
-
const rest = pending + text.slice(lastIndex);
|
|
10981
|
-
if (rest) pushNoProofWords(out, rest, formatting, options);
|
|
10982
|
-
}
|
|
10983
|
-
function pushNoProofWords(out, text, formatting, options) {
|
|
10984
|
-
const wholeRunNoProof = options.base.noProof === true;
|
|
10985
|
-
const regex = wholeRunNoProof ? null : buildNoProofWordsRegex(options.noProofWords);
|
|
10986
|
-
if (!regex) {
|
|
10987
|
-
out.push({ kind: "text", text, formatting });
|
|
10988
|
-
return;
|
|
10989
|
-
}
|
|
10990
|
-
let lastIndex = 0;
|
|
10991
|
-
let match;
|
|
10992
|
-
while ((match = regex.exec(text)) !== null) {
|
|
10993
|
-
if (match.index > lastIndex) {
|
|
10994
|
-
out.push({
|
|
10995
|
-
kind: "text",
|
|
10996
|
-
text: text.slice(lastIndex, match.index),
|
|
10997
|
-
formatting
|
|
10998
|
-
});
|
|
11043
|
+
const orderedMatch = line.match(/^(\s*)(\d+)\.\s+(.+)$/);
|
|
11044
|
+
if (orderedMatch) {
|
|
11045
|
+
const indentLevel = Math.floor(orderedMatch[1].length / 2);
|
|
11046
|
+
const text2 = orderedMatch[3];
|
|
11047
|
+
items.push({ text: text2, level: indentLevel });
|
|
11048
|
+
if (isOrdered === null) isOrdered = true;
|
|
11049
|
+
continue;
|
|
10999
11050
|
}
|
|
11000
|
-
|
|
11001
|
-
kind: "text",
|
|
11002
|
-
text: match[0],
|
|
11003
|
-
formatting: { ...formatting, noProof: true }
|
|
11004
|
-
});
|
|
11005
|
-
lastIndex = match.index + match[0].length;
|
|
11006
|
-
if (regex.lastIndex === match.index) regex.lastIndex += 1;
|
|
11007
|
-
}
|
|
11008
|
-
if (lastIndex < text.length) {
|
|
11009
|
-
out.push({ kind: "text", text: text.slice(lastIndex), formatting });
|
|
11051
|
+
return null;
|
|
11010
11052
|
}
|
|
11011
|
-
|
|
11012
|
-
|
|
11013
|
-
const formatting = { ...options.base };
|
|
11014
|
-
if (state.bold !== void 0) formatting.bold = state.bold;
|
|
11015
|
-
if (state.italic !== void 0) formatting.italic = state.italic;
|
|
11016
|
-
if (state.bold && options.boldColor && options.base.color) {
|
|
11017
|
-
formatting.color = options.boldColor;
|
|
11053
|
+
if (items.length === 0 || isUnordered && isOrdered) {
|
|
11054
|
+
return null;
|
|
11018
11055
|
}
|
|
11019
|
-
return
|
|
11020
|
-
|
|
11021
|
-
|
|
11022
|
-
|
|
11023
|
-
([, value]) => value !== void 0
|
|
11024
|
-
);
|
|
11025
|
-
return entries.length === 0 ? void 0 : Object.fromEntries(entries);
|
|
11056
|
+
return {
|
|
11057
|
+
type: isUnordered ? "unordered" : "ordered",
|
|
11058
|
+
items
|
|
11059
|
+
};
|
|
11026
11060
|
}
|
|
11027
11061
|
|
|
11028
11062
|
// src/ir/compiler.ts
|
|
@@ -11266,6 +11300,10 @@ function noProofWords(theme) {
|
|
|
11266
11300
|
const words = theme.noProofWords;
|
|
11267
11301
|
return words && words.length > 0 ? words : void 0;
|
|
11268
11302
|
}
|
|
11303
|
+
function plainRuns(text, ctx, formatting) {
|
|
11304
|
+
const words = noProofWords(ctx.theme);
|
|
11305
|
+
return words && text ? noProofRuns(text, formatting, words) : [{ kind: "text", text, ...formatting ? { formatting } : {} }];
|
|
11306
|
+
}
|
|
11269
11307
|
function mergeNoProofWords(themeWords, componentWords) {
|
|
11270
11308
|
const own = Array.isArray(componentWords) ? componentWords : [];
|
|
11271
11309
|
const merged = [...themeWords ?? [], ...own];
|
|
@@ -11624,7 +11662,8 @@ function compileParagraph(component, scope) {
|
|
|
11624
11662
|
...props.alignment ? { alignment: props.alignment } : {},
|
|
11625
11663
|
...props.comment ? { comment: props.comment } : {},
|
|
11626
11664
|
...props.footnotes ? { footnotes: props.footnotes } : {},
|
|
11627
|
-
...props.endnotes ? { endnotes: props.endnotes } : {}
|
|
11665
|
+
...props.endnotes ? { endnotes: props.endnotes } : {},
|
|
11666
|
+
...props.noProofWords ? { noProofWords: props.noProofWords } : {}
|
|
11628
11667
|
}
|
|
11629
11668
|
},
|
|
11630
11669
|
scope,
|
|
@@ -12138,13 +12177,10 @@ function compileToc(component, scope) {
|
|
|
12138
12177
|
// No style, not even Normal: a title with an outline level would collect
|
|
12139
12178
|
// itself into the very list it introduces. It carries its own weight and
|
|
12140
12179
|
// size instead.
|
|
12141
|
-
children:
|
|
12142
|
-
|
|
12143
|
-
|
|
12144
|
-
|
|
12145
|
-
formatting: { bold: true, sizeHalfPoints: 28 }
|
|
12146
|
-
}
|
|
12147
|
-
],
|
|
12180
|
+
children: plainRuns(String(props.title), ctx, {
|
|
12181
|
+
bold: true,
|
|
12182
|
+
sizeHalfPoints: 28
|
|
12183
|
+
}),
|
|
12148
12184
|
formatting: {
|
|
12149
12185
|
alignment: "left",
|
|
12150
12186
|
spacing: {
|
|
@@ -12332,7 +12368,7 @@ function compileStatistic(component, scope) {
|
|
|
12332
12368
|
...spacing ? { spacing } : {}
|
|
12333
12369
|
}),
|
|
12334
12370
|
line(
|
|
12335
|
-
descriptionText ?
|
|
12371
|
+
descriptionText ? plainRuns(descriptionText, ctx) : [],
|
|
12336
12372
|
STATISTIC_DESCRIPTION_STYLE_ID,
|
|
12337
12373
|
"description",
|
|
12338
12374
|
{ alignment: alignment2 }
|
|
@@ -12350,6 +12386,7 @@ function compileList(component, scope, referencePrefix = "list", explicitLevels)
|
|
|
12350
12386
|
ctx
|
|
12351
12387
|
);
|
|
12352
12388
|
const notes = createNoteBinding(props.footnotes, props.endnotes, ctx);
|
|
12389
|
+
const words = mergeNoProofWords(noProofWords(ctx.theme), props.noProofWords);
|
|
12353
12390
|
const reference = declareNumbering(
|
|
12354
12391
|
props,
|
|
12355
12392
|
ctx,
|
|
@@ -12386,10 +12423,11 @@ function compileList(component, scope, referencePrefix = "list", explicitLevels)
|
|
|
12386
12423
|
revision === void 0 ? parseInline(text, {
|
|
12387
12424
|
base,
|
|
12388
12425
|
hyperlinks: true,
|
|
12426
|
+
...words ? { noProofWords: words } : {},
|
|
12389
12427
|
...notes ? { resolveNote: notes.resolve } : {},
|
|
12390
12428
|
resolvePlaceholder: placeholderResolver(ctx),
|
|
12391
12429
|
resolveCrossReference: crossReferenceResolver(ctx, itemPath)
|
|
12392
|
-
}) : compileRevision(revision, base, ctx),
|
|
12430
|
+
}) : compileRevision(revision, base, ctx, words),
|
|
12393
12431
|
{
|
|
12394
12432
|
styleId: "Normal",
|
|
12395
12433
|
formatting: {
|
|
@@ -12559,7 +12597,7 @@ function compileRuns(props, text, ctx, path3, mode = "inline") {
|
|
|
12559
12597
|
ctx.features.require("revisions", path3);
|
|
12560
12598
|
return [
|
|
12561
12599
|
...props.columnBreak ? [{ kind: "columnBreak" }] : [],
|
|
12562
|
-
...compileRevision(props.revision, base, ctx)
|
|
12600
|
+
...compileRevision(props.revision, base, ctx, words)
|
|
12563
12601
|
];
|
|
12564
12602
|
}
|
|
12565
12603
|
const parseOptions = {
|
|
@@ -12682,7 +12720,7 @@ function createNoteBinding(footnotes, endnotes, ctx) {
|
|
|
12682
12720
|
id: `${note.endnote ? "endnote" : "footnote"}${resolved.id}:p${index}`,
|
|
12683
12721
|
path: `${note.endnote ? "endnotes" : "footnotes"}[${resolved.id}].children[${index}]`,
|
|
12684
12722
|
styleId: note.endnote ? "EndnoteText" : "FootnoteText",
|
|
12685
|
-
children:
|
|
12723
|
+
children: plainRuns(line, ctx)
|
|
12686
12724
|
}))
|
|
12687
12725
|
});
|
|
12688
12726
|
registered.set(id, resolved);
|
|
@@ -12735,7 +12773,7 @@ function declareComment(comment, ctx, path3) {
|
|
|
12735
12773
|
kind: "paragraph",
|
|
12736
12774
|
id: `comment${id}:p${index}`,
|
|
12737
12775
|
path: `comments[${id}].children[${index}]`,
|
|
12738
|
-
children:
|
|
12776
|
+
children: plainRuns(line, ctx)
|
|
12739
12777
|
})),
|
|
12740
12778
|
...parentId !== void 0 ? { parentId } : {},
|
|
12741
12779
|
...resolved !== void 0 ? { resolved } : {}
|
|
@@ -12761,7 +12799,7 @@ function closeComment(ids) {
|
|
|
12761
12799
|
{ kind: "commentReference", id }
|
|
12762
12800
|
]);
|
|
12763
12801
|
}
|
|
12764
|
-
function compileRevision(revision, base, ctx) {
|
|
12802
|
+
function compileRevision(revision, base, ctx, words = noProofWords(ctx.theme)) {
|
|
12765
12803
|
const author = revision.author || DEFAULT_REVISION_AUTHOR;
|
|
12766
12804
|
const date = revision.date || DEFAULT_REVISION_DATE;
|
|
12767
12805
|
const out = [];
|
|
@@ -12769,15 +12807,17 @@ function compileRevision(revision, base, ctx) {
|
|
|
12769
12807
|
if (!segment.text) continue;
|
|
12770
12808
|
const text = normalizeUnicodeText(segment.text);
|
|
12771
12809
|
if (segment.type === "insert" || segment.type === "delete") {
|
|
12772
|
-
for (const line of literalLines(text, base)) {
|
|
12773
|
-
|
|
12774
|
-
|
|
12775
|
-
|
|
12776
|
-
|
|
12777
|
-
|
|
12778
|
-
|
|
12779
|
-
|
|
12780
|
-
|
|
12810
|
+
for (const line of literalLines(text, base, words)) {
|
|
12811
|
+
for (const children of oneRunEach(line)) {
|
|
12812
|
+
out.push({
|
|
12813
|
+
kind: "revision",
|
|
12814
|
+
type: segment.type,
|
|
12815
|
+
id: ctx.nextRevisionId++,
|
|
12816
|
+
author,
|
|
12817
|
+
date,
|
|
12818
|
+
children
|
|
12819
|
+
});
|
|
12820
|
+
}
|
|
12781
12821
|
}
|
|
12782
12822
|
continue;
|
|
12783
12823
|
}
|
|
@@ -12785,24 +12825,36 @@ function compileRevision(revision, base, ctx) {
|
|
|
12785
12825
|
out.push(
|
|
12786
12826
|
...parseInline(text, {
|
|
12787
12827
|
base,
|
|
12828
|
+
...words ? { noProofWords: words } : {},
|
|
12788
12829
|
resolvePlaceholder: placeholderResolver(ctx)
|
|
12789
12830
|
})
|
|
12790
12831
|
);
|
|
12791
12832
|
continue;
|
|
12792
12833
|
}
|
|
12793
|
-
for (const line of literalLines(text, base)) out.push(...line);
|
|
12834
|
+
for (const line of literalLines(text, base, words)) out.push(...line);
|
|
12794
12835
|
}
|
|
12795
12836
|
return out;
|
|
12796
12837
|
}
|
|
12797
|
-
function
|
|
12838
|
+
function oneRunEach(line) {
|
|
12839
|
+
const ranges = [];
|
|
12840
|
+
for (const node of line) {
|
|
12841
|
+
const last = ranges[ranges.length - 1];
|
|
12842
|
+
if (last?.[last.length - 1]?.kind === "lineBreak") last.push(node);
|
|
12843
|
+
else ranges.push([node]);
|
|
12844
|
+
}
|
|
12845
|
+
return ranges;
|
|
12846
|
+
}
|
|
12847
|
+
function literalLines(text, base, words) {
|
|
12798
12848
|
const formatting = Object.keys(base).length > 0 ? base : void 0;
|
|
12799
12849
|
return text.split("\n").map((line, index) => [
|
|
12800
12850
|
...index > 0 ? [{ kind: "lineBreak" }] : [],
|
|
12801
|
-
|
|
12802
|
-
|
|
12803
|
-
|
|
12804
|
-
|
|
12805
|
-
|
|
12851
|
+
...words && line ? noProofRuns(line, formatting, words) : [
|
|
12852
|
+
{
|
|
12853
|
+
kind: "text",
|
|
12854
|
+
text: line,
|
|
12855
|
+
...formatting ? { formatting } : {}
|
|
12856
|
+
}
|
|
12857
|
+
]
|
|
12806
12858
|
]);
|
|
12807
12859
|
}
|
|
12808
12860
|
function resolvePlaceholder(name, generatedAt) {
|
|
@@ -13097,7 +13149,8 @@ function nativeVisualDeps(ctx, path3) {
|
|
|
13097
13149
|
};
|
|
13098
13150
|
},
|
|
13099
13151
|
reject: (detail) => ctx.unsupported.push({ name: "visual", path: path3, detail }),
|
|
13100
|
-
warn: (message) => warnOnce(ctx, `visual:${message}`, message)
|
|
13152
|
+
warn: (message) => warnOnce(ctx, `visual:${message}`, message),
|
|
13153
|
+
...noProofWords(ctx.theme) ? { noProofWords: noProofWords(ctx.theme) } : {}
|
|
13101
13154
|
};
|
|
13102
13155
|
}
|
|
13103
13156
|
function visualPlacementPixels(props, canvas, reference) {
|
|
@@ -13381,6 +13434,7 @@ function captionBlock(value, scope, componentName) {
|
|
|
13381
13434
|
ctx.unsupported.push({ name: componentName, path: path3, detail: syntax });
|
|
13382
13435
|
return void 0;
|
|
13383
13436
|
}
|
|
13437
|
+
const words = noProofWords(ctx.theme);
|
|
13384
13438
|
return {
|
|
13385
13439
|
kind: "paragraph",
|
|
13386
13440
|
id: `${scope.id}:caption`,
|
|
@@ -13393,9 +13447,13 @@ function captionBlock(value, scope, componentName) {
|
|
|
13393
13447
|
children: DECORATED.test(caption) ? parseInline(caption, {
|
|
13394
13448
|
base: {},
|
|
13395
13449
|
hyperlinks: true,
|
|
13450
|
+
...words ? { noProofWords: words } : {},
|
|
13396
13451
|
resolvePlaceholder: placeholderResolver(ctx),
|
|
13397
13452
|
resolveCrossReference: crossReferenceResolver(ctx, path3)
|
|
13398
|
-
}) : parseLiteral(caption, {
|
|
13453
|
+
}) : parseLiteral(caption, {
|
|
13454
|
+
base: {},
|
|
13455
|
+
...words ? { noProofWords: words } : {}
|
|
13456
|
+
})
|
|
13399
13457
|
};
|
|
13400
13458
|
}
|
|
13401
13459
|
function relativeFrom(value, axis) {
|
|
@@ -13880,10 +13938,14 @@ function cellChildren(cell, baseStyle, scope, rowRevision) {
|
|
|
13880
13938
|
}
|
|
13881
13939
|
const text = cellText(cell);
|
|
13882
13940
|
if (text === void 0) return wrap([]);
|
|
13941
|
+
const words = mergeNoProofWords(
|
|
13942
|
+
noProofWords(ctx.theme),
|
|
13943
|
+
typeof content === "object" ? content.props?.noProofWords : void 0
|
|
13944
|
+
);
|
|
13883
13945
|
const revision = cell.revision ?? cellComponentRevision(cell);
|
|
13884
13946
|
if (revision) {
|
|
13885
13947
|
ctx.features.require("revisions", "");
|
|
13886
|
-
return wrap(compileRevision(revision, base, ctx));
|
|
13948
|
+
return wrap(compileRevision(revision, base, ctx, words));
|
|
13887
13949
|
}
|
|
13888
13950
|
if (rowRevision) {
|
|
13889
13951
|
return wrap(
|
|
@@ -13894,7 +13956,8 @@ function cellChildren(cell, baseStyle, scope, rowRevision) {
|
|
|
13894
13956
|
segments: [{ type: rowRevision.type, text }]
|
|
13895
13957
|
},
|
|
13896
13958
|
base,
|
|
13897
|
-
ctx
|
|
13959
|
+
ctx,
|
|
13960
|
+
words
|
|
13898
13961
|
)
|
|
13899
13962
|
);
|
|
13900
13963
|
}
|
|
@@ -13902,6 +13965,7 @@ function cellChildren(cell, baseStyle, scope, rowRevision) {
|
|
|
13902
13965
|
parseInline(text, {
|
|
13903
13966
|
base,
|
|
13904
13967
|
hyperlinks: true,
|
|
13968
|
+
...words ? { noProofWords: words } : {},
|
|
13905
13969
|
resolvePlaceholder: placeholderResolver(ctx),
|
|
13906
13970
|
resolveCrossReference: crossReferenceResolver(ctx, "table")
|
|
13907
13971
|
})
|