@json-to-office/core-docx 3.2.0 → 4.0.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/blueprints/index.d.ts +45 -0
- package/dist/blueprints/index.d.ts.map +1 -0
- package/dist/core/structure.d.ts.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1135 -8
- package/dist/index.js.map +1 -1
- package/dist/plugin/example/index.js +220 -4
- package/dist/plugin/example/index.js.map +1 -1
- package/dist/quality/facts.d.ts +53 -1
- package/dist/quality/facts.d.ts.map +1 -1
- package/dist/quality/preflight.d.ts.map +1 -1
- package/dist/quality/rules.d.ts +77 -0
- package/dist/quality/rules.d.ts.map +1 -1
- package/dist/templates/blueprints/client-report.docx.blueprint.json +473 -0
- package/dist/templates/themes/consulting.docx.theme.json +1 -0
- package/dist/templates/themes/devportal.docx.theme.json +1 -0
- package/dist/templates/themes/index.d.ts +5 -0
- package/dist/templates/themes/index.d.ts.map +1 -1
- package/dist/templates/themes/minimal.docx.theme.json +1 -0
- package/dist/templates/themes/vermilion.docx.theme.json +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utils/serviceClient.d.ts +6 -0
- package/dist/utils/serviceClient.d.ts.map +1 -1
- package/package.json +4 -4
|
@@ -193,6 +193,7 @@ var init_minimal_docx_theme = __esm({
|
|
|
193
193
|
name: "minimal",
|
|
194
194
|
displayName: "Minimal Clean",
|
|
195
195
|
description: "A quiet, warm minimal theme \u2014 Calibri throughout, sage-green ink on ivory neutrals, a large tracked-tight bold title, wide margins and hairline rules",
|
|
196
|
+
whenToUse: "Quiet documents where the type carries the tone: notes, briefs, drafts and internal papers that want warmth without decoration.",
|
|
196
197
|
version: "4.0.0",
|
|
197
198
|
colors: {
|
|
198
199
|
primary: "#2B302B",
|
|
@@ -382,6 +383,7 @@ var init_devportal_docx_theme = __esm({
|
|
|
382
383
|
name: "devportal",
|
|
383
384
|
displayName: "Field Editorial",
|
|
384
385
|
description: "A compact editorial theme \u2014 Helvetica in near-black ink with a burnt-orange accent, tight condensed titles, letterspaced labels, warm tinted fills and hairline rules",
|
|
386
|
+
whenToUse: "Developer and product documentation, API guides and technical handbooks: dense text, code and tables that need compact, letterspaced structure.",
|
|
385
387
|
version: "4.0.0",
|
|
386
388
|
colors: {
|
|
387
389
|
primary: "#12191F",
|
|
@@ -580,6 +582,7 @@ var init_vermilion_docx_theme = __esm({
|
|
|
580
582
|
name: "vermilion",
|
|
581
583
|
displayName: "Vermilion Editorial",
|
|
582
584
|
description: "Poster-red editorial system \u2014 vermilion display headings, ink text, warm creams and hairline rules",
|
|
585
|
+
whenToUse: "Editorial and annual-report work that wants a strong red display voice: covers, feature-style sections, reports built around a few large headings.",
|
|
583
586
|
version: "1.0.0",
|
|
584
587
|
colors: {
|
|
585
588
|
primary: "#282829",
|
|
@@ -798,6 +801,7 @@ var init_consulting_docx_theme = __esm({
|
|
|
798
801
|
name: "consulting",
|
|
799
802
|
displayName: "Consulting House",
|
|
800
803
|
description: "The house style for client and technical reports \u2014 near-black ink, three greys and one deep-blue accent, Calibri body under Arial headings, hairline rules, no fills behind body text, safe fonts only",
|
|
804
|
+
whenToUse: "Client and technical reports, memos and anything a client will read as the house's own work; the default choice for a report unless the brief names a brand.",
|
|
801
805
|
version: "1.0.0",
|
|
802
806
|
colors: {
|
|
803
807
|
primary: "#1A1F26",
|
|
@@ -5307,6 +5311,10 @@ function resolveServiceUrl(propsUrl, servicesUrl, defaultUrl) {
|
|
|
5307
5311
|
const withScheme = /^https?:\/\//i.test(raw) ? raw : `http://${raw}`;
|
|
5308
5312
|
return withScheme.replace(/\/+$/, "");
|
|
5309
5313
|
}
|
|
5314
|
+
var SERVICE_UNAVAILABLE_CODE = "SERVICE_UNAVAILABLE";
|
|
5315
|
+
function serviceUnavailable(message) {
|
|
5316
|
+
return Object.assign(new Error(message), { code: SERVICE_UNAVAILABLE_CODE });
|
|
5317
|
+
}
|
|
5310
5318
|
async function postJsonToService(opts) {
|
|
5311
5319
|
const resolvedHeaders = typeof opts.headers === "function" ? await opts.headers(opts.body) : opts.headers;
|
|
5312
5320
|
const headers = {
|
|
@@ -5326,12 +5334,12 @@ async function postJsonToService(opts) {
|
|
|
5326
5334
|
});
|
|
5327
5335
|
} catch (error) {
|
|
5328
5336
|
if (error?.name === "AbortError") {
|
|
5329
|
-
throw
|
|
5337
|
+
throw serviceUnavailable(
|
|
5330
5338
|
`${opts.serviceLabel} timed out after ${timeoutMs}ms at ${opts.url}.`
|
|
5331
5339
|
);
|
|
5332
5340
|
}
|
|
5333
5341
|
const cause = error instanceof Error ? error.message : String(error);
|
|
5334
|
-
throw
|
|
5342
|
+
throw serviceUnavailable(opts.onUnreachable(opts.url, cause));
|
|
5335
5343
|
} finally {
|
|
5336
5344
|
clearTimeout(timer);
|
|
5337
5345
|
}
|
|
@@ -12026,6 +12034,7 @@ async function processResolvedDocument(document, resolved, themeName, generation
|
|
|
12026
12034
|
};
|
|
12027
12035
|
}
|
|
12028
12036
|
function createDocumentMetadata(props, generationDate = /* @__PURE__ */ new Date()) {
|
|
12037
|
+
const parsed = props.metadata?.date ? new Date(props.metadata.date) : void 0;
|
|
12029
12038
|
return {
|
|
12030
12039
|
title: props.metadata?.title,
|
|
12031
12040
|
subtitle: props.metadata?.subtitle,
|
|
@@ -12034,7 +12043,7 @@ function createDocumentMetadata(props, generationDate = /* @__PURE__ */ new Date
|
|
|
12034
12043
|
company: props.metadata?.company,
|
|
12035
12044
|
version: props.metadata?.version,
|
|
12036
12045
|
tags: props.metadata?.tags,
|
|
12037
|
-
date:
|
|
12046
|
+
date: parsed && !Number.isNaN(parsed.getTime()) ? parsed : generationDate
|
|
12038
12047
|
};
|
|
12039
12048
|
}
|
|
12040
12049
|
async function extractSections(components, context) {
|
|
@@ -12126,7 +12135,12 @@ import {
|
|
|
12126
12135
|
normalizeHighchartsChart
|
|
12127
12136
|
} from "@json-to-office/quality";
|
|
12128
12137
|
import { DEFAULT_DOCX_RENDERER_ID as DEFAULT_DOCX_RENDERER_ID2 } from "@json-to-office/shared-docx";
|
|
12129
|
-
import {
|
|
12138
|
+
import {
|
|
12139
|
+
designCanvas as designCanvas2,
|
|
12140
|
+
designColors as designColors2,
|
|
12141
|
+
resolveDesignColor as resolveDesignColor2,
|
|
12142
|
+
typeScaleSizes
|
|
12143
|
+
} from "@json-to-office/shared";
|
|
12130
12144
|
|
|
12131
12145
|
// src/json/normalizer.ts
|
|
12132
12146
|
function normalizeComponent(component) {
|
|
@@ -12895,6 +12909,93 @@ function walkActive(node, path3, page, visit) {
|
|
|
12895
12909
|
(child, index) => walkActive(child, `${path3}/children/${index}`, page, visit)
|
|
12896
12910
|
);
|
|
12897
12911
|
}
|
|
12912
|
+
function textSizeFact(node, props, path3, typography, role) {
|
|
12913
|
+
const size = effectiveFontSize(node, props, typography);
|
|
12914
|
+
if (size === void 0) return void 0;
|
|
12915
|
+
return {
|
|
12916
|
+
id: `docx:text-size:${path3}`,
|
|
12917
|
+
kind: "docx/text-size",
|
|
12918
|
+
path: path3,
|
|
12919
|
+
role: role ?? styleKey(node, props),
|
|
12920
|
+
fontSizePt: size.fontSizePt,
|
|
12921
|
+
authored: size.authored,
|
|
12922
|
+
...size.authored && { sizePath: `${path3}/props/font/size` }
|
|
12923
|
+
};
|
|
12924
|
+
}
|
|
12925
|
+
function tableTextSizeFacts(props, authored, path3, typography, page) {
|
|
12926
|
+
const facts = [];
|
|
12927
|
+
const sizeOf = (holder) => finiteNumber(asRecord(asRecord(holder)?.font)?.size);
|
|
12928
|
+
const authoredSize = (holder, pointer, role) => {
|
|
12929
|
+
const size = sizeOf(holder);
|
|
12930
|
+
if (size === void 0) return;
|
|
12931
|
+
facts.push({
|
|
12932
|
+
id: `docx:text-size:${pointer}`,
|
|
12933
|
+
kind: "docx/text-size",
|
|
12934
|
+
path: pointer,
|
|
12935
|
+
role,
|
|
12936
|
+
fontSizePt: size,
|
|
12937
|
+
authored: true,
|
|
12938
|
+
sizePath: `${pointer}/font/size`
|
|
12939
|
+
});
|
|
12940
|
+
};
|
|
12941
|
+
const cellContent = (holder, pointer, role) => {
|
|
12942
|
+
const content = asRecord(holder)?.content;
|
|
12943
|
+
if (asRecord(content) === void 0) return;
|
|
12944
|
+
walkActive(content, `${pointer}/content`, page, (node, nodePath) => {
|
|
12945
|
+
if (node.name !== "paragraph" && node.name !== "heading") return;
|
|
12946
|
+
const nodeProps = asRecord(node.props) ?? {};
|
|
12947
|
+
if (typeof nodeProps.text !== "string" || nodeProps.text.trim() === "")
|
|
12948
|
+
return;
|
|
12949
|
+
const fact = textSizeFact(node, nodeProps, nodePath, typography, role);
|
|
12950
|
+
if (fact) facts.push(fact);
|
|
12951
|
+
});
|
|
12952
|
+
};
|
|
12953
|
+
if (authored) {
|
|
12954
|
+
authoredSize(
|
|
12955
|
+
authored.cellDefaults,
|
|
12956
|
+
`${path3}/props/cellDefaults`,
|
|
12957
|
+
"tableCell"
|
|
12958
|
+
);
|
|
12959
|
+
authoredSize(
|
|
12960
|
+
authored.headerCellDefaults,
|
|
12961
|
+
`${path3}/props/headerCellDefaults`,
|
|
12962
|
+
"tableHeader"
|
|
12963
|
+
);
|
|
12964
|
+
const columns = Array.isArray(authored.columns) ? authored.columns : [];
|
|
12965
|
+
columns.forEach((column, index) => {
|
|
12966
|
+
const record = asRecord(column) ?? {};
|
|
12967
|
+
const columnPath = `${path3}/props/columns/${index}`;
|
|
12968
|
+
authoredSize(
|
|
12969
|
+
record.cellDefaults,
|
|
12970
|
+
`${columnPath}/cellDefaults`,
|
|
12971
|
+
"tableCell"
|
|
12972
|
+
);
|
|
12973
|
+
authoredSize(record.header, `${columnPath}/header`, "tableHeader");
|
|
12974
|
+
cellContent(record.header, `${columnPath}/header`, "tableHeader");
|
|
12975
|
+
const cells = Array.isArray(record.cells) ? record.cells : [];
|
|
12976
|
+
cells.forEach((cell, cellIndex) => {
|
|
12977
|
+
authoredSize(cell, `${columnPath}/cells/${cellIndex}`, "tableCell");
|
|
12978
|
+
cellContent(cell, `${columnPath}/cells/${cellIndex}`, "tableCell");
|
|
12979
|
+
});
|
|
12980
|
+
});
|
|
12981
|
+
}
|
|
12982
|
+
for (const [key, role] of [
|
|
12983
|
+
["cellDefaults", "tableCell"],
|
|
12984
|
+
["headerCellDefaults", "tableHeader"]
|
|
12985
|
+
]) {
|
|
12986
|
+
const size = sizeOf(props[key]);
|
|
12987
|
+
if (size === void 0) continue;
|
|
12988
|
+
facts.push({
|
|
12989
|
+
id: `docx:text-size:${path3}:${role}`,
|
|
12990
|
+
kind: "docx/text-size",
|
|
12991
|
+
path: path3,
|
|
12992
|
+
role,
|
|
12993
|
+
fontSizePt: size,
|
|
12994
|
+
authored: false
|
|
12995
|
+
});
|
|
12996
|
+
}
|
|
12997
|
+
return facts;
|
|
12998
|
+
}
|
|
12898
12999
|
function prepareDocxQualityDocument(document, options = {}) {
|
|
12899
13000
|
const themed = options.context ?? resolveThemeContext(normalizeDocument(document)[0], {
|
|
12900
13001
|
customThemes: options.customThemes,
|
|
@@ -12942,6 +13043,75 @@ function prepareDocxQualityDocument(document, options = {}) {
|
|
|
12942
13043
|
...budget
|
|
12943
13044
|
});
|
|
12944
13045
|
}
|
|
13046
|
+
for (const role of blockSlotRoles2(themed.document, expanded.blocks)) {
|
|
13047
|
+
addFact({
|
|
13048
|
+
id: `docx:chrome-slot:${role.path}`,
|
|
13049
|
+
kind: "docx/chrome-slot",
|
|
13050
|
+
path: role.path,
|
|
13051
|
+
relatedPaths: [role.invocation],
|
|
13052
|
+
block: role.block,
|
|
13053
|
+
slot: role.slot,
|
|
13054
|
+
role: role.role,
|
|
13055
|
+
present: slotIsFilled(role.value),
|
|
13056
|
+
invocation: role.invocation
|
|
13057
|
+
});
|
|
13058
|
+
}
|
|
13059
|
+
const topLevel = Array.isArray(context.document.children) ? context.document.children : [];
|
|
13060
|
+
let inherited = {};
|
|
13061
|
+
topLevel.forEach((node, index) => {
|
|
13062
|
+
if (node?.name !== "section") return;
|
|
13063
|
+
const props = asRecord(node.props) ?? {};
|
|
13064
|
+
const part = (kind) => props[kind] === "linkToPrevious" ? inherited[kind] : props[kind];
|
|
13065
|
+
const header = part("header");
|
|
13066
|
+
const footer = part("footer");
|
|
13067
|
+
inherited = { header, footer };
|
|
13068
|
+
for (const kind of ["header", "footer"]) {
|
|
13069
|
+
if (!Array.isArray(props[kind])) continue;
|
|
13070
|
+
const drawnByBlock = !Array.isArray(
|
|
13071
|
+
asRecord(
|
|
13072
|
+
asRecord(
|
|
13073
|
+
(Array.isArray(themed.document.children) ? themed.document.children : [])[index]
|
|
13074
|
+
)?.props
|
|
13075
|
+
)?.[kind]
|
|
13076
|
+
);
|
|
13077
|
+
const part2 = props[kind];
|
|
13078
|
+
const visitChrome = (child, childPath) => {
|
|
13079
|
+
if (child.name !== "paragraph" && child.name !== "heading") return;
|
|
13080
|
+
const childProps = asRecord(child.props) ?? {};
|
|
13081
|
+
if (typeof childProps.text !== "string" || childProps.text.trim() === "")
|
|
13082
|
+
return;
|
|
13083
|
+
const fact = textSizeFact(
|
|
13084
|
+
child,
|
|
13085
|
+
childProps,
|
|
13086
|
+
childPath,
|
|
13087
|
+
typography,
|
|
13088
|
+
kind
|
|
13089
|
+
);
|
|
13090
|
+
if (fact)
|
|
13091
|
+
addFact({
|
|
13092
|
+
...fact,
|
|
13093
|
+
generated: drawnByBlock || authoredPath(childPath) !== childPath
|
|
13094
|
+
});
|
|
13095
|
+
};
|
|
13096
|
+
part2.forEach(
|
|
13097
|
+
(child, childIndex) => walkActive(
|
|
13098
|
+
child,
|
|
13099
|
+
`/children/${index}/props/${kind}/${childIndex}`,
|
|
13100
|
+
basePage,
|
|
13101
|
+
visitChrome
|
|
13102
|
+
)
|
|
13103
|
+
);
|
|
13104
|
+
}
|
|
13105
|
+
addFact({
|
|
13106
|
+
id: `docx:section-chrome:${index}`,
|
|
13107
|
+
kind: "docx/section-chrome",
|
|
13108
|
+
path: `/children/${index}`,
|
|
13109
|
+
index,
|
|
13110
|
+
header: partPresent(header),
|
|
13111
|
+
footer: partPresent(footer),
|
|
13112
|
+
pageNumber: hasPageField(header) || hasPageField(footer)
|
|
13113
|
+
});
|
|
13114
|
+
});
|
|
12945
13115
|
const paletteHexes = {};
|
|
12946
13116
|
const visualColors = designColors2(
|
|
12947
13117
|
resolved.theme.colors,
|
|
@@ -12965,12 +13135,34 @@ function prepareDocxQualityDocument(document, options = {}) {
|
|
|
12965
13135
|
(value) => `#${resolveDesignColor2(value, visualColors)}`
|
|
12966
13136
|
) ?? SERIES_COLOR_TOKENS.filter((token) => paletteHexes[token] !== void 0);
|
|
12967
13137
|
const authoredPropsAt = (pointer) => asRecord(asRecord(nodeAtPointer(context.document, pointer))?.props);
|
|
13138
|
+
const roleSizesPt = {};
|
|
13139
|
+
for (const key of Object.keys(typography.styles)) {
|
|
13140
|
+
const size = effectiveFontSize(
|
|
13141
|
+
{ name: "paragraph" },
|
|
13142
|
+
{ themeStyle: key },
|
|
13143
|
+
typography
|
|
13144
|
+
);
|
|
13145
|
+
if (size) roleSizesPt[key] = size.fontSizePt;
|
|
13146
|
+
}
|
|
13147
|
+
const scale = resolved.theme.typography?.scale?.[designCanvas2("docx", resolved.theme.page?.size)];
|
|
13148
|
+
const typeScalePt = [
|
|
13149
|
+
.../* @__PURE__ */ new Set([
|
|
13150
|
+
...Object.values(roleSizesPt),
|
|
13151
|
+
...["heading", "body", "mono", "light"].flatMap((role) => {
|
|
13152
|
+
const size = resolveFontSize(resolved.theme, role);
|
|
13153
|
+
return size === void 0 ? [] : [size];
|
|
13154
|
+
}),
|
|
13155
|
+
...scale ? typeScaleSizes(scale) : []
|
|
13156
|
+
])
|
|
13157
|
+
].sort((a, b) => a - b);
|
|
12968
13158
|
addFact({
|
|
12969
13159
|
id: "docx:theme",
|
|
12970
13160
|
kind: "docx/theme",
|
|
12971
13161
|
path: "/props",
|
|
12972
13162
|
themeName: context.themeName,
|
|
12973
13163
|
paletteHexes,
|
|
13164
|
+
typeScalePt,
|
|
13165
|
+
roleSizesPt,
|
|
12974
13166
|
// `heading` and `body` only. A theme also names `mono` and `light`, but
|
|
12975
13167
|
// those paint nothing until a component asks for them — counting an
|
|
12976
13168
|
// unused `Courier New` against a document's family budget would flag a
|
|
@@ -13023,6 +13215,15 @@ function prepareDocxQualityDocument(document, options = {}) {
|
|
|
13023
13215
|
if (node.name === "table") {
|
|
13024
13216
|
const fact = tableFact(props, path3, page.availableWidthTwips);
|
|
13025
13217
|
if (fact) addFact(fact);
|
|
13218
|
+
for (const size of tableTextSizeFacts(
|
|
13219
|
+
props,
|
|
13220
|
+
authoredPropsAt(path3),
|
|
13221
|
+
path3,
|
|
13222
|
+
typography,
|
|
13223
|
+
page
|
|
13224
|
+
)) {
|
|
13225
|
+
addFact({ ...size, generated: authoredPath(size.path) !== size.path });
|
|
13226
|
+
}
|
|
13026
13227
|
const design = tableDesignFact(
|
|
13027
13228
|
props,
|
|
13028
13229
|
path3,
|
|
@@ -13081,6 +13282,10 @@ function prepareDocxQualityDocument(document, options = {}) {
|
|
|
13081
13282
|
if (node.name === "paragraph" || node.name === "heading") {
|
|
13082
13283
|
const fact = lineBoxFact(node, props, path3, typography, context.document);
|
|
13083
13284
|
if (fact) addFact(fact);
|
|
13285
|
+
if (typeof props.text === "string" && props.text.trim() !== "") {
|
|
13286
|
+
const fact2 = textSizeFact(node, props, path3, typography);
|
|
13287
|
+
if (fact2) addFact({ ...fact2, generated: authoredPath(path3) !== path3 });
|
|
13288
|
+
}
|
|
13084
13289
|
}
|
|
13085
13290
|
if (node.name === "image" || node.name === "visual") {
|
|
13086
13291
|
for (const fact of svgTextFacts(props, path3)) addFact(fact);
|
|
@@ -13136,6 +13341,17 @@ function prepareDocxQualityDocument(document, options = {}) {
|
|
|
13136
13341
|
}
|
|
13137
13342
|
};
|
|
13138
13343
|
}
|
|
13344
|
+
function slotIsFilled(value) {
|
|
13345
|
+
if (typeof value === "string") return value.trim() !== "";
|
|
13346
|
+
return value !== void 0 && value !== null && value !== false && (!Array.isArray(value) || value.length > 0);
|
|
13347
|
+
}
|
|
13348
|
+
function partPresent(part) {
|
|
13349
|
+
return Array.isArray(part) && part.length > 0;
|
|
13350
|
+
}
|
|
13351
|
+
var PAGE_FIELD = /\{(PAGE|PAGE_NUMBER|TOTAL_PAGES|NUMPAGES)\}/;
|
|
13352
|
+
function hasPageField(part) {
|
|
13353
|
+
return Array.isArray(part) && PAGE_FIELD.test(JSON.stringify(part));
|
|
13354
|
+
}
|
|
13139
13355
|
|
|
13140
13356
|
// src/core/generateFromIr.ts
|
|
13141
13357
|
var UncompiledComponentError = class extends Error {
|