@json-to-office/core-docx 2.1.0 → 2.4.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 +462 -29
- package/dist/index.js.map +1 -1
- package/dist/plugin/example/index.js +274 -27
- package/dist/plugin/example/index.js.map +1 -1
- package/dist/plugin/validation.d.ts.map +1 -1
- package/dist/quality/facts.d.ts +56 -2
- package/dist/quality/facts.d.ts.map +1 -1
- package/dist/quality/rules.d.ts +16 -0
- package/dist/quality/rules.d.ts.map +1 -1
- package/dist/themes/defaults.d.ts +13 -1
- package/dist/themes/defaults.d.ts.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -17,6 +17,7 @@ var __export = (target, all) => {
|
|
|
17
17
|
// src/themes/defaults.ts
|
|
18
18
|
function ensureThemeDefaults(theme) {
|
|
19
19
|
return {
|
|
20
|
+
...theme,
|
|
20
21
|
$schema: theme.$schema,
|
|
21
22
|
name: theme.name || "default",
|
|
22
23
|
displayName: theme.displayName || "Default Theme",
|
|
@@ -27,6 +28,7 @@ function ensureThemeDefaults(theme) {
|
|
|
27
28
|
...theme.colors || {}
|
|
28
29
|
},
|
|
29
30
|
fonts: {
|
|
31
|
+
...theme.fonts || {},
|
|
30
32
|
heading: { ...DEFAULT_FONTS.heading, ...theme.fonts?.heading || {} },
|
|
31
33
|
body: { ...DEFAULT_FONTS.body, ...theme.fonts?.body || {} },
|
|
32
34
|
mono: { ...DEFAULT_FONTS.mono, ...theme.fonts?.mono || {} },
|
|
@@ -11298,6 +11300,15 @@ function createRenderContext(document, theme, themeName) {
|
|
|
11298
11300
|
}
|
|
11299
11301
|
|
|
11300
11302
|
// src/quality/facts.ts
|
|
11303
|
+
import {
|
|
11304
|
+
chartEncodingFor,
|
|
11305
|
+
collectColorLiterals,
|
|
11306
|
+
collectFontFamilies,
|
|
11307
|
+
collectPlaceholders,
|
|
11308
|
+
hasUnitMarker,
|
|
11309
|
+
normalizeHex,
|
|
11310
|
+
normalizeHighchartsChart
|
|
11311
|
+
} from "@json-to-office/quality";
|
|
11301
11312
|
import { DEFAULT_DOCX_RENDERER_ID as DEFAULT_DOCX_RENDERER_ID2 } from "@json-to-office/shared-docx";
|
|
11302
11313
|
|
|
11303
11314
|
// src/core/generationContext.ts
|
|
@@ -11539,6 +11550,164 @@ function tableFact(props, path4, availableWidthTwips) {
|
|
|
11539
11550
|
explicitWidths
|
|
11540
11551
|
};
|
|
11541
11552
|
}
|
|
11553
|
+
var SERIES_COLOR_TOKENS = [
|
|
11554
|
+
"primary",
|
|
11555
|
+
"accent",
|
|
11556
|
+
"secondary",
|
|
11557
|
+
"accent4",
|
|
11558
|
+
"accent5",
|
|
11559
|
+
"accent6"
|
|
11560
|
+
];
|
|
11561
|
+
function chartFact(node, props, path4, paletteTokens) {
|
|
11562
|
+
const base = {
|
|
11563
|
+
id: `docx:chart:${path4}`,
|
|
11564
|
+
kind: "docx/chart",
|
|
11565
|
+
path: path4,
|
|
11566
|
+
componentName: typeof node.name === "string" ? node.name : "",
|
|
11567
|
+
paletteTokens
|
|
11568
|
+
};
|
|
11569
|
+
if (node.name === "highcharts") {
|
|
11570
|
+
const shape = normalizeHighchartsChart(props.options);
|
|
11571
|
+
return {
|
|
11572
|
+
...base,
|
|
11573
|
+
chartType: shape.chartType,
|
|
11574
|
+
encoding: shape.encoding,
|
|
11575
|
+
threeD: shape.threeD,
|
|
11576
|
+
seriesCount: shape.seriesCount,
|
|
11577
|
+
categoryCount: shape.categoryCount,
|
|
11578
|
+
seriesColorsStated: shape.seriesColorsStated,
|
|
11579
|
+
seriesColorsPath: `${path4}/props/options`,
|
|
11580
|
+
...shape.valueAxisMin !== void 0 && {
|
|
11581
|
+
valueAxisMin: shape.valueAxisMin
|
|
11582
|
+
},
|
|
11583
|
+
unitStated: shape.unitStated,
|
|
11584
|
+
annotation: {
|
|
11585
|
+
stated: shape.annotationStated,
|
|
11586
|
+
path: path4,
|
|
11587
|
+
slot: "props.options.caption.text"
|
|
11588
|
+
}
|
|
11589
|
+
};
|
|
11590
|
+
}
|
|
11591
|
+
const chartType = typeof props.type === "string" ? props.type : "";
|
|
11592
|
+
if (chartType === "") return void 0;
|
|
11593
|
+
const series = Array.isArray(props.data) ? props.data : [];
|
|
11594
|
+
const categoryCount = Math.max(
|
|
11595
|
+
0,
|
|
11596
|
+
...series.map((entry) => {
|
|
11597
|
+
const record = asRecord(entry);
|
|
11598
|
+
const labels = Array.isArray(record?.labels) ? record.labels.length : 0;
|
|
11599
|
+
const values = Array.isArray(record?.values) ? record.values.length : 0;
|
|
11600
|
+
return Math.max(labels, values);
|
|
11601
|
+
})
|
|
11602
|
+
);
|
|
11603
|
+
const caption = typeof props.caption === "string" ? props.caption : "";
|
|
11604
|
+
const title = typeof props.title === "string" ? props.title : "";
|
|
11605
|
+
return {
|
|
11606
|
+
...base,
|
|
11607
|
+
chartType,
|
|
11608
|
+
encoding: chartEncodingFor(chartType),
|
|
11609
|
+
// No 3D type exists in the DOCX chart schema — `office-open` draws none —
|
|
11610
|
+
// so this is always false here, and stays a field rather than an omission
|
|
11611
|
+
// so both formats answer the same questions.
|
|
11612
|
+
threeD: false,
|
|
11613
|
+
seriesCount: series.length,
|
|
11614
|
+
categoryCount,
|
|
11615
|
+
seriesColorsStated: Array.isArray(props.chartColors) && props.chartColors.length > 0,
|
|
11616
|
+
seriesColorsPath: `${path4}/props/chartColors`,
|
|
11617
|
+
// No `valueAxisMin`: a DOCX chart has no axis-floor property, so the
|
|
11618
|
+
// baseline is always the renderer's, which starts a bar at zero.
|
|
11619
|
+
unitStated: hasUnitMarker(
|
|
11620
|
+
typeof props.valAxisTitle === "string" ? props.valAxisTitle : ""
|
|
11621
|
+
) || hasUnitMarker(title) || hasUnitMarker(caption),
|
|
11622
|
+
annotation: {
|
|
11623
|
+
stated: caption.trim() !== "",
|
|
11624
|
+
path: path4,
|
|
11625
|
+
slot: "props.caption"
|
|
11626
|
+
}
|
|
11627
|
+
};
|
|
11628
|
+
}
|
|
11629
|
+
var DOCX_ALIGNMENTS = /* @__PURE__ */ new Set(["left", "center", "right", "justify"]);
|
|
11630
|
+
function resolvedCellText(content) {
|
|
11631
|
+
return typeof content === "string" ? content : "[component]";
|
|
11632
|
+
}
|
|
11633
|
+
function statesOwnBorders(authored) {
|
|
11634
|
+
if (!authored) return false;
|
|
11635
|
+
if (authored.borderSize !== void 0 || authored.borderColor !== void 0 || authored.hideBorders !== void 0) {
|
|
11636
|
+
return true;
|
|
11637
|
+
}
|
|
11638
|
+
const layers = [
|
|
11639
|
+
asRecord(authored.cellDefaults),
|
|
11640
|
+
asRecord(authored.headerCellDefaults)
|
|
11641
|
+
];
|
|
11642
|
+
if (layers.some(
|
|
11643
|
+
(layer) => layer?.borderSize !== void 0 || layer?.borderColor !== void 0
|
|
11644
|
+
)) {
|
|
11645
|
+
return true;
|
|
11646
|
+
}
|
|
11647
|
+
const columns = Array.isArray(authored.columns) ? authored.columns : [];
|
|
11648
|
+
return columns.some((column) => {
|
|
11649
|
+
const record = asRecord(column);
|
|
11650
|
+
const defaults = asRecord(record?.cellDefaults);
|
|
11651
|
+
return defaults?.borderSize !== void 0 || defaults?.borderColor !== void 0;
|
|
11652
|
+
});
|
|
11653
|
+
}
|
|
11654
|
+
function tableDesignFact(props, path4, theme, themeName, authored) {
|
|
11655
|
+
const authoredColumns = Array.isArray(props.columns) ? props.columns : [];
|
|
11656
|
+
if (authoredColumns.length === 0) return void 0;
|
|
11657
|
+
const model = resolveTableModel(
|
|
11658
|
+
props,
|
|
11659
|
+
theme,
|
|
11660
|
+
themeName
|
|
11661
|
+
);
|
|
11662
|
+
const bodyRows = model.rows;
|
|
11663
|
+
const drawnRows = bodyRows.length + (model.header ? 1 : 0);
|
|
11664
|
+
if (drawnRows === 0) return void 0;
|
|
11665
|
+
const fullGrid = statesOwnBorders(authored) && [...model.header ? [model.header] : [], ...bodyRows].every(
|
|
11666
|
+
(row) => row.cells.every(
|
|
11667
|
+
(cell) => ["top", "right", "bottom", "left"].every(
|
|
11668
|
+
(side) => !cell.borders[side].hidden && cell.borders[side].size > 0
|
|
11669
|
+
)
|
|
11670
|
+
)
|
|
11671
|
+
);
|
|
11672
|
+
const columns = authoredColumns.map(
|
|
11673
|
+
(column, index) => {
|
|
11674
|
+
const authoredColumn = asRecord(column) ?? {};
|
|
11675
|
+
const cells = Array.isArray(authoredColumn.cells) ? authoredColumn.cells : [];
|
|
11676
|
+
const alignments = /* @__PURE__ */ new Set();
|
|
11677
|
+
const values = [];
|
|
11678
|
+
bodyRows.forEach((row) => {
|
|
11679
|
+
const cell = row.cells[index];
|
|
11680
|
+
if (!cell || cell.missing) return;
|
|
11681
|
+
values.push(resolvedCellText(cell.content));
|
|
11682
|
+
alignments.add(cell.horizontalAlignment);
|
|
11683
|
+
});
|
|
11684
|
+
const header = model.header?.cells[index];
|
|
11685
|
+
return {
|
|
11686
|
+
index,
|
|
11687
|
+
path: `${path4}/props/columns/${index}`,
|
|
11688
|
+
...header?.content !== void 0 && {
|
|
11689
|
+
header: resolvedCellText(header.content)
|
|
11690
|
+
},
|
|
11691
|
+
values,
|
|
11692
|
+
alignment: alignments.size === 1 ? [...alignments][0] : alignments.size === 0 ? "left" : "mixed",
|
|
11693
|
+
hasCellDefaults: asRecord(authoredColumn.cellDefaults) !== void 0,
|
|
11694
|
+
hasHeader: asRecord(authoredColumn.header) !== void 0,
|
|
11695
|
+
cellsWithOwnAlignment: cells.flatMap((cell, cellIndex) => {
|
|
11696
|
+
const alignment2 = asRecord(cell)?.horizontalAlignment;
|
|
11697
|
+
return typeof alignment2 === "string" && DOCX_ALIGNMENTS.has(alignment2) && alignment2 !== "right" ? [cellIndex] : [];
|
|
11698
|
+
})
|
|
11699
|
+
};
|
|
11700
|
+
}
|
|
11701
|
+
);
|
|
11702
|
+
return {
|
|
11703
|
+
id: `docx:table-design:${path4}`,
|
|
11704
|
+
kind: "docx/table",
|
|
11705
|
+
path: path4,
|
|
11706
|
+
columns,
|
|
11707
|
+
rowCount: drawnRows,
|
|
11708
|
+
fullGrid
|
|
11709
|
+
};
|
|
11710
|
+
}
|
|
11542
11711
|
var TWIPS_PER_POINT3 = 20;
|
|
11543
11712
|
var SINGLE_LINE_RATIO = 1.2;
|
|
11544
11713
|
function finiteNumber(value) {
|
|
@@ -11567,20 +11736,23 @@ function characterSpacingPt(spacing) {
|
|
|
11567
11736
|
if (rule === void 0 || value === void 0) return 0;
|
|
11568
11737
|
return rule.type === "condensed" ? -value / TWIPS_PER_POINT3 : value / TWIPS_PER_POINT3;
|
|
11569
11738
|
}
|
|
11570
|
-
function
|
|
11739
|
+
function nodeAtPointer(root, pointer) {
|
|
11571
11740
|
let current = root;
|
|
11572
11741
|
for (const token of pointer.split("/").slice(1)) {
|
|
11573
11742
|
if (Array.isArray(current)) {
|
|
11574
11743
|
const index = Number(token);
|
|
11575
|
-
if (!Number.isInteger(index)) return
|
|
11744
|
+
if (!Number.isInteger(index)) return void 0;
|
|
11576
11745
|
current = current[index];
|
|
11577
11746
|
continue;
|
|
11578
11747
|
}
|
|
11579
11748
|
const record = asRecord(current);
|
|
11580
|
-
if (!record) return
|
|
11749
|
+
if (!record) return void 0;
|
|
11581
11750
|
current = record[token];
|
|
11582
11751
|
}
|
|
11583
|
-
return current
|
|
11752
|
+
return current;
|
|
11753
|
+
}
|
|
11754
|
+
function pointerExists(root, pointer) {
|
|
11755
|
+
return nodeAtPointer(root, pointer) !== void 0;
|
|
11584
11756
|
}
|
|
11585
11757
|
function styleKey(node, props) {
|
|
11586
11758
|
if (node.name === "heading") {
|
|
@@ -11761,6 +11933,67 @@ function prepareDocxQualityDocument(document, options = {}) {
|
|
|
11761
11933
|
...fact.relatedPaths && { relatedPaths: fact.relatedPaths }
|
|
11762
11934
|
};
|
|
11763
11935
|
};
|
|
11936
|
+
const paletteHexes = {};
|
|
11937
|
+
for (const [token, value] of Object.entries(
|
|
11938
|
+
resolved.theme.colors ?? {}
|
|
11939
|
+
)) {
|
|
11940
|
+
if (typeof value !== "string") continue;
|
|
11941
|
+
const hex = normalizeHex(value);
|
|
11942
|
+
if (hex) paletteHexes[token] = hex;
|
|
11943
|
+
}
|
|
11944
|
+
const paletteTokens = SERIES_COLOR_TOKENS.filter(
|
|
11945
|
+
(token) => paletteHexes[token] !== void 0
|
|
11946
|
+
);
|
|
11947
|
+
const authoredPropsAt = (pointer) => asRecord(asRecord(nodeAtPointer(context.document, pointer))?.props);
|
|
11948
|
+
addFact({
|
|
11949
|
+
id: "docx:theme",
|
|
11950
|
+
kind: "docx/theme",
|
|
11951
|
+
path: "/props",
|
|
11952
|
+
themeName: context.themeName,
|
|
11953
|
+
paletteHexes,
|
|
11954
|
+
// `heading` and `body` only. A theme also names `mono` and `light`, but
|
|
11955
|
+
// those paint nothing until a component asks for them — counting an
|
|
11956
|
+
// unused `Courier New` against a document's family budget would flag a
|
|
11957
|
+
// report that only ever uses one typeface.
|
|
11958
|
+
fontFamilies: [
|
|
11959
|
+
...new Set(
|
|
11960
|
+
["heading", "body"].flatMap((role) => {
|
|
11961
|
+
const family = asRecord(
|
|
11962
|
+
resolved.theme.fonts?.[role]
|
|
11963
|
+
)?.family;
|
|
11964
|
+
return typeof family === "string" && family.trim() !== "" ? [family] : [];
|
|
11965
|
+
})
|
|
11966
|
+
)
|
|
11967
|
+
]
|
|
11968
|
+
});
|
|
11969
|
+
collectColorLiterals(document).forEach((literal, index) => {
|
|
11970
|
+
addFact({
|
|
11971
|
+
id: `docx:color:${index}:${literal.path}`,
|
|
11972
|
+
kind: "docx/color",
|
|
11973
|
+
path: literal.path,
|
|
11974
|
+
raw: literal.raw,
|
|
11975
|
+
hex: literal.hex
|
|
11976
|
+
});
|
|
11977
|
+
});
|
|
11978
|
+
collectFontFamilies(document).forEach((use, index) => {
|
|
11979
|
+
addFact({
|
|
11980
|
+
id: `docx:font:${index}:${use.path}`,
|
|
11981
|
+
kind: "docx/font-family",
|
|
11982
|
+
path: use.path,
|
|
11983
|
+
family: use.family
|
|
11984
|
+
});
|
|
11985
|
+
});
|
|
11986
|
+
collectPlaceholders(document).forEach((occurrence, index) => {
|
|
11987
|
+
addFact({
|
|
11988
|
+
id: `docx:placeholder:${index}:${occurrence.path}`,
|
|
11989
|
+
kind: "docx/placeholder",
|
|
11990
|
+
path: occurrence.path,
|
|
11991
|
+
text: occurrence.text,
|
|
11992
|
+
placeholderKind: occurrence.match.kind,
|
|
11993
|
+
pattern: occurrence.match.pattern,
|
|
11994
|
+
excerpt: occurrence.match.excerpt
|
|
11995
|
+
});
|
|
11996
|
+
});
|
|
11764
11997
|
let previousVisitPath;
|
|
11765
11998
|
let lastFrame;
|
|
11766
11999
|
let flowIndex = 0;
|
|
@@ -11770,6 +12003,18 @@ function prepareDocxQualityDocument(document, options = {}) {
|
|
|
11770
12003
|
if (node.name === "table") {
|
|
11771
12004
|
const fact = tableFact(props, path4, page.availableWidthTwips);
|
|
11772
12005
|
if (fact) addFact(fact);
|
|
12006
|
+
const design = tableDesignFact(
|
|
12007
|
+
props,
|
|
12008
|
+
path4,
|
|
12009
|
+
resolved.theme,
|
|
12010
|
+
context.themeName,
|
|
12011
|
+
authoredPropsAt(path4)
|
|
12012
|
+
);
|
|
12013
|
+
if (design) addFact(design);
|
|
12014
|
+
}
|
|
12015
|
+
if (node.name === "chart" || node.name === "highcharts") {
|
|
12016
|
+
const fact = chartFact(node, props, path4, paletteTokens);
|
|
12017
|
+
if (fact) addFact(fact);
|
|
11773
12018
|
}
|
|
11774
12019
|
if (node.name === "paragraph" || node.name === "text-box") {
|
|
11775
12020
|
const floating = asRecord(props.floating);
|
|
@@ -12193,9 +12438,17 @@ import {
|
|
|
12193
12438
|
|
|
12194
12439
|
// src/quality/rules.ts
|
|
12195
12440
|
import {
|
|
12441
|
+
chartInfoDesignFindings,
|
|
12442
|
+
DEFAULT_MAXIMUM_CHART_SERIES,
|
|
12443
|
+
DEFAULT_MAXIMUM_PIE_SLICES,
|
|
12444
|
+
fontCountFinding,
|
|
12196
12445
|
mergeQualityProfiles,
|
|
12446
|
+
nearestPaletteToken,
|
|
12447
|
+
offPaletteFinding,
|
|
12448
|
+
placeholderFinding,
|
|
12197
12449
|
QUALITY_CODES,
|
|
12198
|
-
QualityEngine
|
|
12450
|
+
QualityEngine,
|
|
12451
|
+
tableInfoDesignFindings
|
|
12199
12452
|
} from "@json-to-office/quality";
|
|
12200
12453
|
|
|
12201
12454
|
// src/quality/text-metrics.ts
|
|
@@ -12661,6 +12914,179 @@ var docxLineBoxRule = {
|
|
|
12661
12914
|
});
|
|
12662
12915
|
}
|
|
12663
12916
|
};
|
|
12917
|
+
var docxPlaceholderRule = {
|
|
12918
|
+
id: "docx/placeholder-text",
|
|
12919
|
+
code: QUALITY_CODES.PLACEHOLDER_TEXT,
|
|
12920
|
+
category: "integrity",
|
|
12921
|
+
defaultSeverity: "warning",
|
|
12922
|
+
defaultCertainty: "deterministic",
|
|
12923
|
+
formats: ["docx"],
|
|
12924
|
+
evaluate: ({ facts }) => facts.filter(
|
|
12925
|
+
(fact) => fact.kind === "docx/placeholder"
|
|
12926
|
+
).map(
|
|
12927
|
+
(fact) => placeholderFinding({
|
|
12928
|
+
path: fact.path,
|
|
12929
|
+
kind: fact.placeholderKind,
|
|
12930
|
+
pattern: fact.pattern,
|
|
12931
|
+
excerpt: fact.excerpt
|
|
12932
|
+
})
|
|
12933
|
+
)
|
|
12934
|
+
};
|
|
12935
|
+
var DEFAULT_MAX_FONT_FAMILIES = 3;
|
|
12936
|
+
var docxFontCountRule = {
|
|
12937
|
+
id: "docx/font-count",
|
|
12938
|
+
code: QUALITY_CODES.FONT_COUNT,
|
|
12939
|
+
category: "brand",
|
|
12940
|
+
defaultSeverity: "warning",
|
|
12941
|
+
defaultCertainty: "deterministic",
|
|
12942
|
+
formats: ["docx"],
|
|
12943
|
+
defaultParameters: { maximumFamilies: DEFAULT_MAX_FONT_FAMILIES },
|
|
12944
|
+
evaluate: ({ facts, configuration }) => {
|
|
12945
|
+
const maximum = numberParameter(
|
|
12946
|
+
configuration.parameters,
|
|
12947
|
+
"maximumFamilies",
|
|
12948
|
+
DEFAULT_MAX_FONT_FAMILIES
|
|
12949
|
+
);
|
|
12950
|
+
const theme = facts.find(
|
|
12951
|
+
(fact) => fact.kind === "docx/theme"
|
|
12952
|
+
);
|
|
12953
|
+
const families = new Set(theme?.fontFamilies ?? []);
|
|
12954
|
+
const extraPaths = [];
|
|
12955
|
+
for (const fact of facts) {
|
|
12956
|
+
if (fact.kind !== "docx/font-family") continue;
|
|
12957
|
+
const use = fact;
|
|
12958
|
+
if (!families.has(use.family)) extraPaths.push(use.path);
|
|
12959
|
+
families.add(use.family);
|
|
12960
|
+
}
|
|
12961
|
+
if (families.size <= maximum) return [];
|
|
12962
|
+
return [
|
|
12963
|
+
fontCountFinding({
|
|
12964
|
+
path: theme?.path ?? "/props",
|
|
12965
|
+
families: [...families].sort(),
|
|
12966
|
+
maximum,
|
|
12967
|
+
relatedPaths: [...new Set(extraPaths)]
|
|
12968
|
+
})
|
|
12969
|
+
];
|
|
12970
|
+
}
|
|
12971
|
+
};
|
|
12972
|
+
var docxPaletteRule = {
|
|
12973
|
+
id: "docx/palette-adherence",
|
|
12974
|
+
code: QUALITY_CODES.OFF_PALETTE,
|
|
12975
|
+
category: "brand",
|
|
12976
|
+
defaultSeverity: "info",
|
|
12977
|
+
defaultCertainty: "deterministic",
|
|
12978
|
+
formats: ["docx"],
|
|
12979
|
+
evaluate: ({ facts }) => {
|
|
12980
|
+
const theme = facts.find(
|
|
12981
|
+
(fact) => fact.kind === "docx/theme"
|
|
12982
|
+
);
|
|
12983
|
+
const palette = theme?.paletteHexes ?? {};
|
|
12984
|
+
const known = new Set(Object.values(palette));
|
|
12985
|
+
return facts.filter((fact) => fact.kind === "docx/color").filter((fact) => !known.has(fact.hex)).map((fact) => {
|
|
12986
|
+
const nearest = nearestPaletteToken(fact.hex, palette);
|
|
12987
|
+
return offPaletteFinding({
|
|
12988
|
+
path: fact.path,
|
|
12989
|
+
raw: fact.raw,
|
|
12990
|
+
hex: fact.hex,
|
|
12991
|
+
...nearest && { nearest }
|
|
12992
|
+
});
|
|
12993
|
+
});
|
|
12994
|
+
}
|
|
12995
|
+
};
|
|
12996
|
+
var DEFAULT_MAX_TABLE_ROWS_PER_PAGE = 25;
|
|
12997
|
+
var docxChartRule = {
|
|
12998
|
+
id: "docx/chart-design",
|
|
12999
|
+
code: QUALITY_CODES.CHART_OVERLOADED,
|
|
13000
|
+
category: "information-design",
|
|
13001
|
+
defaultSeverity: "warning",
|
|
13002
|
+
defaultCertainty: "deterministic",
|
|
13003
|
+
formats: ["docx"],
|
|
13004
|
+
defaultParameters: {
|
|
13005
|
+
maximumSeries: DEFAULT_MAXIMUM_CHART_SERIES,
|
|
13006
|
+
maximumSlices: DEFAULT_MAXIMUM_PIE_SLICES
|
|
13007
|
+
},
|
|
13008
|
+
evaluate: ({ facts, configuration }) => {
|
|
13009
|
+
const maximumSeries = numberParameter(
|
|
13010
|
+
configuration.parameters,
|
|
13011
|
+
"maximumSeries",
|
|
13012
|
+
DEFAULT_MAXIMUM_CHART_SERIES
|
|
13013
|
+
);
|
|
13014
|
+
const maximumSlices = numberParameter(
|
|
13015
|
+
configuration.parameters,
|
|
13016
|
+
"maximumSlices",
|
|
13017
|
+
DEFAULT_MAXIMUM_PIE_SLICES
|
|
13018
|
+
);
|
|
13019
|
+
return facts.filter((fact) => fact.kind === "docx/chart").flatMap((fact) => {
|
|
13020
|
+
const fix = seriesColorFix(fact);
|
|
13021
|
+
return chartInfoDesignFindings(fact, {
|
|
13022
|
+
maximumSeries,
|
|
13023
|
+
maximumSlices,
|
|
13024
|
+
...fix && { seriesColorFix: fix }
|
|
13025
|
+
});
|
|
13026
|
+
});
|
|
13027
|
+
}
|
|
13028
|
+
};
|
|
13029
|
+
function seriesColorFix(fact) {
|
|
13030
|
+
if (fact.componentName !== "chart") return void 0;
|
|
13031
|
+
if (fact.seriesCount < 1 || fact.paletteTokens.length === 0) return void 0;
|
|
13032
|
+
const tokens = Array.from(
|
|
13033
|
+
{ length: fact.seriesCount },
|
|
13034
|
+
(_, index) => fact.paletteTokens[index % fact.paletteTokens.length]
|
|
13035
|
+
);
|
|
13036
|
+
return [{ op: "add", path: fact.seriesColorsPath, value: tokens }];
|
|
13037
|
+
}
|
|
13038
|
+
var docxTableDesignRule = {
|
|
13039
|
+
id: "docx/table-design",
|
|
13040
|
+
code: QUALITY_CODES.TABLE_NUMERIC_ALIGN,
|
|
13041
|
+
category: "information-design",
|
|
13042
|
+
defaultSeverity: "warning",
|
|
13043
|
+
defaultCertainty: "deterministic",
|
|
13044
|
+
formats: ["docx"],
|
|
13045
|
+
defaultParameters: { maximumRows: DEFAULT_MAX_TABLE_ROWS_PER_PAGE },
|
|
13046
|
+
evaluate: ({ facts, configuration }) => {
|
|
13047
|
+
const maximumRows = numberParameter(
|
|
13048
|
+
configuration.parameters,
|
|
13049
|
+
"maximumRows",
|
|
13050
|
+
DEFAULT_MAX_TABLE_ROWS_PER_PAGE
|
|
13051
|
+
);
|
|
13052
|
+
return facts.filter((fact) => fact.kind === "docx/table").flatMap(
|
|
13053
|
+
(fact) => tableInfoDesignFindings(fact, {
|
|
13054
|
+
maximumRows,
|
|
13055
|
+
rowSurface: "page",
|
|
13056
|
+
rowSeverity: "info",
|
|
13057
|
+
alignFix: alignColumnRight
|
|
13058
|
+
})
|
|
13059
|
+
);
|
|
13060
|
+
}
|
|
13061
|
+
};
|
|
13062
|
+
function alignColumnRight(column) {
|
|
13063
|
+
const operations = [
|
|
13064
|
+
column.hasCellDefaults ? {
|
|
13065
|
+
op: "add",
|
|
13066
|
+
path: `${column.path}/cellDefaults/horizontalAlignment`,
|
|
13067
|
+
value: "right"
|
|
13068
|
+
} : {
|
|
13069
|
+
op: "add",
|
|
13070
|
+
path: `${column.path}/cellDefaults`,
|
|
13071
|
+
value: { horizontalAlignment: "right" }
|
|
13072
|
+
}
|
|
13073
|
+
];
|
|
13074
|
+
if (column.hasHeader) {
|
|
13075
|
+
operations.push({
|
|
13076
|
+
op: "add",
|
|
13077
|
+
path: `${column.path}/header/horizontalAlignment`,
|
|
13078
|
+
value: "right"
|
|
13079
|
+
});
|
|
13080
|
+
}
|
|
13081
|
+
for (const index of column.cellsWithOwnAlignment) {
|
|
13082
|
+
operations.push({
|
|
13083
|
+
op: "add",
|
|
13084
|
+
path: `${column.path}/cells/${index}/horizontalAlignment`,
|
|
13085
|
+
value: "right"
|
|
13086
|
+
});
|
|
13087
|
+
}
|
|
13088
|
+
return operations;
|
|
13089
|
+
}
|
|
12664
13090
|
var DOCX_QUALITY_RULES = {
|
|
12665
13091
|
id: "docx/default",
|
|
12666
13092
|
rules: [
|
|
@@ -12669,7 +13095,12 @@ var DOCX_QUALITY_RULES = {
|
|
|
12669
13095
|
docxTextFitRule,
|
|
12670
13096
|
docxFrameCollisionRule,
|
|
12671
13097
|
docxSvgTextBoundsRule,
|
|
12672
|
-
docxLineBoxRule
|
|
13098
|
+
docxLineBoxRule,
|
|
13099
|
+
docxPlaceholderRule,
|
|
13100
|
+
docxChartRule,
|
|
13101
|
+
docxTableDesignRule,
|
|
13102
|
+
docxFontCountRule,
|
|
13103
|
+
docxPaletteRule
|
|
12673
13104
|
]
|
|
12674
13105
|
};
|
|
12675
13106
|
var DOCX_QUALITY_PROFILES = {
|
|
@@ -13042,34 +13473,36 @@ function validateDocument(document, customComponents, options) {
|
|
|
13042
13473
|
const errors = [...documentResult.errors || []];
|
|
13043
13474
|
function validateComponents(components, pathPrefix = "children") {
|
|
13044
13475
|
components.forEach((componentData, index) => {
|
|
13045
|
-
|
|
13046
|
-
(cc) => cc.name === componentData.name
|
|
13047
|
-
);
|
|
13048
|
-
if (!customComponent) {
|
|
13476
|
+
if (!componentData || typeof componentData !== "object" || Array.isArray(componentData)) {
|
|
13049
13477
|
return;
|
|
13050
13478
|
}
|
|
13051
|
-
const
|
|
13052
|
-
|
|
13053
|
-
customComponent.versions,
|
|
13054
|
-
componentData.version
|
|
13055
|
-
);
|
|
13056
|
-
const validation = validateComponentProps(
|
|
13057
|
-
versionEntry,
|
|
13058
|
-
componentData.props,
|
|
13059
|
-
customComponent.name,
|
|
13060
|
-
// Reject unknown custom props unless the caller allows them.
|
|
13061
|
-
{ clean: options?.allowUnknownFields === true }
|
|
13479
|
+
const customComponent = customComponents.find(
|
|
13480
|
+
(cc) => cc.name === componentData.name
|
|
13062
13481
|
);
|
|
13063
|
-
if (
|
|
13064
|
-
const
|
|
13065
|
-
|
|
13066
|
-
|
|
13067
|
-
|
|
13068
|
-
|
|
13482
|
+
if (customComponent) {
|
|
13483
|
+
const versionEntry = resolveComponentVersion(
|
|
13484
|
+
customComponent.name,
|
|
13485
|
+
customComponent.versions,
|
|
13486
|
+
componentData.version
|
|
13487
|
+
);
|
|
13488
|
+
const validation = validateComponentProps(
|
|
13489
|
+
versionEntry,
|
|
13490
|
+
componentData.props,
|
|
13491
|
+
customComponent.name,
|
|
13492
|
+
// Reject unknown custom props unless the caller allows them.
|
|
13493
|
+
{ clean: options?.allowUnknownFields === true }
|
|
13069
13494
|
);
|
|
13070
|
-
errors
|
|
13495
|
+
if (!validation.valid && validation.errors) {
|
|
13496
|
+
const indexedErrors = validation.errors.map(
|
|
13497
|
+
(error) => ({
|
|
13498
|
+
...error,
|
|
13499
|
+
path: `${pathPrefix}[${index}].${error.path}`
|
|
13500
|
+
})
|
|
13501
|
+
);
|
|
13502
|
+
errors.push(...indexedErrors);
|
|
13503
|
+
}
|
|
13071
13504
|
}
|
|
13072
|
-
if (
|
|
13505
|
+
if (Array.isArray(componentData.children)) {
|
|
13073
13506
|
validateComponents(
|
|
13074
13507
|
componentData.children,
|
|
13075
13508
|
`${pathPrefix}[${index}].children`
|