@json-to-office/core-docx 1.7.0 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +261 -10
- package/dist/index.js.map +1 -1
- package/dist/ir/compiler.d.ts.map +1 -1
- package/dist/plugin/example/index.js +202 -9
- package/dist/plugin/example/index.js.map +1 -1
- package/dist/quality/facts.d.ts +22 -1
- package/dist/quality/facts.d.ts.map +1 -1
- package/dist/quality/rules.d.ts +1 -0
- package/dist/quality/rules.d.ts.map +1 -1
- package/dist/renderers/docxjs/emit.d.ts.map +1 -1
- package/dist/renderers/docxjs/index.d.ts.map +1 -1
- package/dist/renderers/office-open/index.d.ts.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compiler.d.ts","sourceRoot":"","sources":["../../src/ir/compiler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAEL,KAAK,kBAAkB,EACxB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAKhE,OAAO,KAAK,EAAE,UAAU,EAAiB,MAAM,gBAAgB,CAAC;AAChE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AA6C3D,OAAO,KAAK,EAAE,cAAc,EAAe,MAAM,wBAAwB,CAAC;AAuC1E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAEL,KAAK,MAAM,
|
|
1
|
+
{"version":3,"file":"compiler.d.ts","sourceRoot":"","sources":["../../src/ir/compiler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAEL,KAAK,kBAAkB,EACxB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAKhE,OAAO,KAAK,EAAE,UAAU,EAAiB,MAAM,gBAAgB,CAAC;AAChE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AA6C3D,OAAO,KAAK,EAAE,cAAc,EAAe,MAAM,wBAAwB,CAAC;AAuC1E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAEL,KAAK,MAAM,EAqCZ,MAAM,SAAS,CAAC;AAiBjB,2DAA2D;AAC3D,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,kEAAkE;IAClE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,2EAA2E;IAC3E,QAAQ,EAAE,SAAS,kBAAkB,CAAC,WAAW,CAAC,EAAE,CAAC;IACrD,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B;;;;OAIG;IACH,WAAW,EAAE,oBAAoB,EAAE,CAAC;CACrC;AA8FD,wBAAgB,eAAe,CAC7B,SAAS,EAAE,iBAAiB,EAC5B,MAAM,EAAE,UAAU,EAClB,QAAQ,GAAE,iBAAiB,EAAO,EAClC,MAAM,GAAE,cAA0B,EAClC,OAAO,GAAE;IAAE,YAAY,CAAC,EAAE,OAAO,CAAA;CAAO,GACvC,iBAAiB,CAgHnB"}
|
|
@@ -1182,6 +1182,15 @@ function resolveFontFamily(theme, fontRef) {
|
|
|
1182
1182
|
}
|
|
1183
1183
|
return theme.fonts[fontRef]?.family || theme.fonts.body.family;
|
|
1184
1184
|
}
|
|
1185
|
+
function resolveFontSize(theme, fontRef) {
|
|
1186
|
+
if (!theme?.fonts?.body?.size) {
|
|
1187
|
+
return void 0;
|
|
1188
|
+
}
|
|
1189
|
+
if (!fontRef) {
|
|
1190
|
+
return theme.fonts.body.size;
|
|
1191
|
+
}
|
|
1192
|
+
return theme.fonts[fontRef]?.size || theme.fonts.body.size;
|
|
1193
|
+
}
|
|
1185
1194
|
function resolveFontProperties(theme, fontRef) {
|
|
1186
1195
|
const targetFontKey = fontRef || "body";
|
|
1187
1196
|
if (!theme?.fonts?.[targetFontKey]) {
|
|
@@ -2484,6 +2493,14 @@ function paragraphOptions(formatting) {
|
|
|
2484
2493
|
if (formatting.outlineLevel !== void 0) {
|
|
2485
2494
|
options.outlineLevel = formatting.outlineLevel;
|
|
2486
2495
|
}
|
|
2496
|
+
if (formatting.borders) {
|
|
2497
|
+
const borders3 = {};
|
|
2498
|
+
for (const side of ["top", "bottom", "left", "right", "between"]) {
|
|
2499
|
+
const emitted = emitBorder(formatting.borders[side]);
|
|
2500
|
+
if (emitted) borders3[side] = emitted;
|
|
2501
|
+
}
|
|
2502
|
+
if (Object.keys(borders3).length > 0) options.border = borders3;
|
|
2503
|
+
}
|
|
2487
2504
|
return options;
|
|
2488
2505
|
}
|
|
2489
2506
|
function emitParagraph(block2, resources = /* @__PURE__ */ new Map()) {
|
|
@@ -2667,7 +2684,11 @@ function emitBorder(border3) {
|
|
|
2667
2684
|
return {
|
|
2668
2685
|
style: BORDER_STYLE[border3.style] ?? BorderStyle.SINGLE,
|
|
2669
2686
|
size: border3.sizeEighthPoints ?? 0,
|
|
2670
|
-
color: border3.color?.hex ?? "000000"
|
|
2687
|
+
color: border3.color?.hex ?? "000000",
|
|
2688
|
+
// Stated only when the IR states it, so every border that predates the
|
|
2689
|
+
// rule component emits exactly the bytes it did before. office-open
|
|
2690
|
+
// already carries `w:space`; this is what keeps the two agreeing.
|
|
2691
|
+
...border3.spacePoints !== void 0 ? { space: border3.spacePoints } : {}
|
|
2671
2692
|
};
|
|
2672
2693
|
}
|
|
2673
2694
|
var ALIGNMENT2, PAGE_FIELD, WRAP_TYPE, VERTICAL_ALIGN, TABLE_ANCHOR, HORIZONTAL_POSITION, VERTICAL_POSITION, BORDER_STYLE;
|
|
@@ -3337,6 +3358,7 @@ var init_docxjs = __esm({
|
|
|
3337
3358
|
"endnotes",
|
|
3338
3359
|
"revisions",
|
|
3339
3360
|
"breaks",
|
|
3361
|
+
"borders",
|
|
3340
3362
|
"tab-stops",
|
|
3341
3363
|
"proofing-language",
|
|
3342
3364
|
"custom-properties"
|
|
@@ -4636,6 +4658,7 @@ var init_office_open = __esm({
|
|
|
4636
4658
|
"endnotes",
|
|
4637
4659
|
"revisions",
|
|
4638
4660
|
"breaks",
|
|
4661
|
+
"borders",
|
|
4639
4662
|
"tab-stops",
|
|
4640
4663
|
"proofing-language",
|
|
4641
4664
|
"custom-properties"
|
|
@@ -6690,17 +6713,17 @@ function createDocumentStyles(themeNameOrObject = "minimal", language) {
|
|
|
6690
6713
|
"subtitle"
|
|
6691
6714
|
]);
|
|
6692
6715
|
if (theme.styles) {
|
|
6693
|
-
for (const [
|
|
6694
|
-
if (predefinedStyleKeys.has(
|
|
6716
|
+
for (const [styleKey2, styleValue] of Object.entries(theme.styles)) {
|
|
6717
|
+
if (predefinedStyleKeys.has(styleKey2)) {
|
|
6695
6718
|
continue;
|
|
6696
6719
|
}
|
|
6697
6720
|
if (!styleValue) {
|
|
6698
6721
|
continue;
|
|
6699
6722
|
}
|
|
6700
|
-
const tocMatch = /^TOC([1-9])$/.exec(
|
|
6701
|
-
const customStyle = tocMatch ? styleValue : resolveStyleWithBaseStyle(theme,
|
|
6702
|
-
const styleId = tocMatch ? `TOC${tocMatch[1]}` :
|
|
6703
|
-
const styleName = tocMatch ? `TOC ${tocMatch[1]}` :
|
|
6723
|
+
const tocMatch = /^TOC([1-9])$/.exec(styleKey2);
|
|
6724
|
+
const customStyle = tocMatch ? styleValue : resolveStyleWithBaseStyle(theme, styleKey2) || styleValue;
|
|
6725
|
+
const styleId = tocMatch ? `TOC${tocMatch[1]}` : styleKey2;
|
|
6726
|
+
const styleName = tocMatch ? `TOC ${tocMatch[1]}` : styleKey2.replace(/([A-Z])/g, " $1").trim();
|
|
6704
6727
|
const mapBaseStyleId = (base) => {
|
|
6705
6728
|
if (!base) return "Normal";
|
|
6706
6729
|
const lower = base.toLowerCase();
|
|
@@ -8624,6 +8647,8 @@ function compileComponent(component, scope) {
|
|
|
8624
8647
|
return compileStatistic(component, scope);
|
|
8625
8648
|
case "toc":
|
|
8626
8649
|
return compileToc(component, scope);
|
|
8650
|
+
case "rule":
|
|
8651
|
+
return compileRule(component, scope);
|
|
8627
8652
|
case "text-box":
|
|
8628
8653
|
return compileTextBox(component, scope);
|
|
8629
8654
|
case "columns":
|
|
@@ -9200,6 +9225,100 @@ function compileToc(component, scope) {
|
|
|
9200
9225
|
});
|
|
9201
9226
|
return blocks;
|
|
9202
9227
|
}
|
|
9228
|
+
var DEFAULT_RULE_SPACING_PT = 6;
|
|
9229
|
+
var DEFAULT_RULE_THICKNESS_PT = 1;
|
|
9230
|
+
var RULE_LINE_TWIPS = 20;
|
|
9231
|
+
var RULE_BORDER_STYLE = {
|
|
9232
|
+
solid: "single",
|
|
9233
|
+
dashed: "dashed",
|
|
9234
|
+
dotted: "dotted",
|
|
9235
|
+
double: "double"
|
|
9236
|
+
};
|
|
9237
|
+
function compileRule(component, scope) {
|
|
9238
|
+
const { ctx, path: path3 } = scope;
|
|
9239
|
+
const props = component.props ?? {};
|
|
9240
|
+
ctx.features.require("borders", path3);
|
|
9241
|
+
const thicknessPt = Math.min(
|
|
9242
|
+
12,
|
|
9243
|
+
Math.max(
|
|
9244
|
+
0.25,
|
|
9245
|
+
typeof props.thickness === "number" && Number.isFinite(props.thickness) ? props.thickness : DEFAULT_RULE_THICKNESS_PT
|
|
9246
|
+
)
|
|
9247
|
+
);
|
|
9248
|
+
const spacing = props.spacing ?? {};
|
|
9249
|
+
const beforePt = typeof spacing.before === "number" && Number.isFinite(spacing.before) ? spacing.before : DEFAULT_RULE_SPACING_PT;
|
|
9250
|
+
const afterPt = typeof spacing.after === "number" && Number.isFinite(spacing.after) ? spacing.after : DEFAULT_RULE_SPACING_PT;
|
|
9251
|
+
return [
|
|
9252
|
+
{
|
|
9253
|
+
kind: "paragraph",
|
|
9254
|
+
id: scope.id,
|
|
9255
|
+
path: path3,
|
|
9256
|
+
styleId: "Normal",
|
|
9257
|
+
children: [],
|
|
9258
|
+
formatting: {
|
|
9259
|
+
spacing: {
|
|
9260
|
+
beforeTwips: pointsToTwips2(beforePt),
|
|
9261
|
+
afterTwips: pointsToTwips2(afterPt),
|
|
9262
|
+
lineTwips: RULE_LINE_TWIPS,
|
|
9263
|
+
lineRule: "exact"
|
|
9264
|
+
},
|
|
9265
|
+
...ruleIndent(props, ctx, path3),
|
|
9266
|
+
borders: {
|
|
9267
|
+
bottom: {
|
|
9268
|
+
style: RULE_BORDER_STYLE[String(props.style)] ?? "single",
|
|
9269
|
+
sizeEighthPoints: pointsToEighthPoints(thicknessPt),
|
|
9270
|
+
color: irColor(
|
|
9271
|
+
resolveColor(String(props.color ?? "border"), ctx.theme)
|
|
9272
|
+
),
|
|
9273
|
+
// The border hangs off the paragraph edge; any gap the author
|
|
9274
|
+
// wants belongs to `spacing`, where they can see it.
|
|
9275
|
+
spacePoints: 0
|
|
9276
|
+
}
|
|
9277
|
+
}
|
|
9278
|
+
}
|
|
9279
|
+
}
|
|
9280
|
+
];
|
|
9281
|
+
}
|
|
9282
|
+
function ruleIndent(props, ctx, path3) {
|
|
9283
|
+
const width = props.width;
|
|
9284
|
+
if (width === void 0) return {};
|
|
9285
|
+
const page = getPageSetup(ctx.theme);
|
|
9286
|
+
const measureTwips = Math.max(
|
|
9287
|
+
0,
|
|
9288
|
+
page.size.width - page.margin.left - page.margin.right
|
|
9289
|
+
);
|
|
9290
|
+
let usedTwips;
|
|
9291
|
+
if (typeof width === "number" && Number.isFinite(width)) {
|
|
9292
|
+
usedTwips = pointsToTwips2(width);
|
|
9293
|
+
} else if (typeof width === "string" && width.trim().endsWith("%")) {
|
|
9294
|
+
const percent = Number(width.trim().slice(0, -1));
|
|
9295
|
+
if (Number.isFinite(percent)) {
|
|
9296
|
+
usedTwips = Math.round(measureTwips * percent / 100);
|
|
9297
|
+
}
|
|
9298
|
+
}
|
|
9299
|
+
if (usedTwips === void 0) return {};
|
|
9300
|
+
const remainder = measureTwips - usedTwips;
|
|
9301
|
+
if (remainder <= 0) {
|
|
9302
|
+
if (remainder < 0) {
|
|
9303
|
+
warnOnce(
|
|
9304
|
+
ctx,
|
|
9305
|
+
"rule",
|
|
9306
|
+
`Rule width ${JSON.stringify(width)} at ${path3} is wider than the ${Math.round(measureTwips / 20)}pt text measure; it runs the full measure instead.`
|
|
9307
|
+
);
|
|
9308
|
+
}
|
|
9309
|
+
return {};
|
|
9310
|
+
}
|
|
9311
|
+
switch (props.alignment) {
|
|
9312
|
+
case "right":
|
|
9313
|
+
return { indent: { leftTwips: remainder } };
|
|
9314
|
+
case "center": {
|
|
9315
|
+
const half = Math.round(remainder / 2);
|
|
9316
|
+
return { indent: { leftTwips: half, rightTwips: remainder - half } };
|
|
9317
|
+
}
|
|
9318
|
+
default:
|
|
9319
|
+
return { indent: { rightTwips: remainder } };
|
|
9320
|
+
}
|
|
9321
|
+
}
|
|
9203
9322
|
var TREND_GLYPHS = {
|
|
9204
9323
|
up: "\u25B2",
|
|
9205
9324
|
down: "\u25BC",
|
|
@@ -11196,8 +11315,8 @@ function getHeadingDefaults(theme) {
|
|
|
11196
11315
|
function getHeadingDefaultsForLevel(theme, level) {
|
|
11197
11316
|
const defaults = {};
|
|
11198
11317
|
if (theme.styles) {
|
|
11199
|
-
const
|
|
11200
|
-
const headingStyle = theme.styles[
|
|
11318
|
+
const styleKey2 = `heading${level}`;
|
|
11319
|
+
const headingStyle = theme.styles[styleKey2];
|
|
11201
11320
|
if (headingStyle?.alignment) {
|
|
11202
11321
|
defaults.alignment = headingStyle.alignment;
|
|
11203
11322
|
}
|
|
@@ -11545,6 +11664,8 @@ function normalizeDocument(document) {
|
|
|
11545
11664
|
}
|
|
11546
11665
|
|
|
11547
11666
|
// src/quality/facts.ts
|
|
11667
|
+
init_styleHelpers();
|
|
11668
|
+
init_defaults();
|
|
11548
11669
|
init_widthUtils();
|
|
11549
11670
|
function asRecord(value) {
|
|
11550
11671
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
@@ -11634,6 +11755,70 @@ function characterSpacingPt(spacing) {
|
|
|
11634
11755
|
if (rule === void 0 || value === void 0) return 0;
|
|
11635
11756
|
return rule.type === "condensed" ? -value / TWIPS_PER_POINT3 : value / TWIPS_PER_POINT3;
|
|
11636
11757
|
}
|
|
11758
|
+
function pointerExists(root, pointer) {
|
|
11759
|
+
let current = root;
|
|
11760
|
+
for (const token of pointer.split("/").slice(1)) {
|
|
11761
|
+
if (Array.isArray(current)) {
|
|
11762
|
+
const index = Number(token);
|
|
11763
|
+
if (!Number.isInteger(index)) return false;
|
|
11764
|
+
current = current[index];
|
|
11765
|
+
continue;
|
|
11766
|
+
}
|
|
11767
|
+
const record = asRecord(current);
|
|
11768
|
+
if (!record) return false;
|
|
11769
|
+
current = record[token];
|
|
11770
|
+
}
|
|
11771
|
+
return current !== void 0;
|
|
11772
|
+
}
|
|
11773
|
+
function styleKey(node, props) {
|
|
11774
|
+
if (node.name === "heading") {
|
|
11775
|
+
return `heading${finiteNumber(props.level) ?? 1}`;
|
|
11776
|
+
}
|
|
11777
|
+
return typeof props.themeStyle === "string" && props.themeStyle !== "" ? props.themeStyle : "normal";
|
|
11778
|
+
}
|
|
11779
|
+
function effectiveFontSize(node, props, typography) {
|
|
11780
|
+
const authored = finiteNumber(asRecord(props.font)?.size);
|
|
11781
|
+
if (authored !== void 0) return { fontSizePt: authored, authored: true };
|
|
11782
|
+
const { styles, theme } = typography;
|
|
11783
|
+
const style = asRecord(styles[styleKey(node, props)]) ?? asRecord(styles.normal);
|
|
11784
|
+
const stated = finiteNumber(style?.size);
|
|
11785
|
+
if (stated !== void 0) return { fontSizePt: stated, authored: false };
|
|
11786
|
+
const reference = style?.font === "heading" || style?.font === "body" || style?.font === "mono" || style?.font === "light" ? style.font : void 0;
|
|
11787
|
+
const inherited = resolveFontSize(theme, reference);
|
|
11788
|
+
return inherited === void 0 ? void 0 : { fontSizePt: inherited, authored: false };
|
|
11789
|
+
}
|
|
11790
|
+
function pinnedLineBox(props, path3) {
|
|
11791
|
+
const candidates = [
|
|
11792
|
+
[props.lineSpacing, `${path3}/props/lineSpacing`],
|
|
11793
|
+
[asRecord(props.font)?.lineSpacing, `${path3}/props/font/lineSpacing`]
|
|
11794
|
+
];
|
|
11795
|
+
for (const [spacing, pointer] of candidates) {
|
|
11796
|
+
if (spacing === void 0) continue;
|
|
11797
|
+
const rule = asRecord(spacing);
|
|
11798
|
+
if (rule?.type !== "exactly") return void 0;
|
|
11799
|
+
const lineBoxPt = finiteNumber(rule.value);
|
|
11800
|
+
return lineBoxPt === void 0 ? void 0 : { lineBoxPt, pointer };
|
|
11801
|
+
}
|
|
11802
|
+
return void 0;
|
|
11803
|
+
}
|
|
11804
|
+
function lineBoxFact(node, props, path3, typography, authored) {
|
|
11805
|
+
if (typeof props.text !== "string" || props.text.trim() === "") {
|
|
11806
|
+
return void 0;
|
|
11807
|
+
}
|
|
11808
|
+
const pinned = pinnedLineBox(props, path3);
|
|
11809
|
+
if (!pinned) return void 0;
|
|
11810
|
+
const size = effectiveFontSize(node, props, typography);
|
|
11811
|
+
if (size === void 0) return void 0;
|
|
11812
|
+
return {
|
|
11813
|
+
id: `docx:line-box:${path3}`,
|
|
11814
|
+
kind: "docx/line-box",
|
|
11815
|
+
path: pinned.pointer,
|
|
11816
|
+
lineBoxPt: pinned.lineBoxPt,
|
|
11817
|
+
fontSizePt: size.fontSizePt,
|
|
11818
|
+
fontSizeAuthored: size.authored,
|
|
11819
|
+
patchable: pointerExists(authored, pinned.pointer)
|
|
11820
|
+
};
|
|
11821
|
+
}
|
|
11637
11822
|
function frameSignature(floating) {
|
|
11638
11823
|
const horizontal = asRecord(floating.horizontalPosition);
|
|
11639
11824
|
const vertical = asRecord(floating.verticalPosition);
|
|
@@ -11750,6 +11935,10 @@ function prepareDocxQualityDocument(document, options = {}) {
|
|
|
11750
11935
|
});
|
|
11751
11936
|
const resolved = resolveDocumentTree(context.document, context.theme);
|
|
11752
11937
|
const basePage = pageBox(resolved.theme, context.themeName);
|
|
11938
|
+
const typography = {
|
|
11939
|
+
styles: getThemeStyles(resolved.theme),
|
|
11940
|
+
theme: resolved.theme
|
|
11941
|
+
};
|
|
11753
11942
|
const facts = [];
|
|
11754
11943
|
const provenance = {};
|
|
11755
11944
|
let previousHeadingLevel;
|
|
@@ -11780,6 +11969,10 @@ function prepareDocxQualityDocument(document, options = {}) {
|
|
|
11780
11969
|
if (fact) addFact(fact);
|
|
11781
11970
|
}
|
|
11782
11971
|
}
|
|
11972
|
+
if (node.name === "paragraph" || node.name === "heading") {
|
|
11973
|
+
const fact = lineBoxFact(node, props, path3, typography, context.document);
|
|
11974
|
+
if (fact) addFact(fact);
|
|
11975
|
+
}
|
|
11783
11976
|
if (node.name === "image" || node.name === "visual") {
|
|
11784
11977
|
for (const fact of svgTextFacts(props, path3)) addFact(fact);
|
|
11785
11978
|
}
|