@json-to-office/core-docx 0.34.0 → 0.36.1
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/components/visual.d.ts +15 -2
- package/dist/components/visual.d.ts.map +1 -1
- package/dist/core/flattenVisuals.d.ts +8 -1
- package/dist/core/flattenVisuals.d.ts.map +1 -1
- package/dist/core/fontResolution.d.ts +15 -1
- package/dist/core/fontResolution.d.ts.map +1 -1
- package/dist/core/generator.d.ts.map +1 -1
- package/dist/core/prerasterizeVisuals.d.ts +8 -1
- package/dist/core/prerasterizeVisuals.d.ts.map +1 -1
- package/dist/core/render.d.ts +14 -1
- package/dist/core/render.d.ts.map +1 -1
- package/dist/index.js +213 -59
- package/dist/index.js.map +1 -1
- package/dist/plugin/createDocumentGenerator.d.ts.map +1 -1
- package/dist/plugin/example/index.js +3353 -3218
- package/dist/plugin/example/index.js.map +1 -1
- package/dist/templates/themes/index.d.ts +156 -8
- package/dist/templates/themes/index.d.ts.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/index.d.ts +8 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/generationContext.d.ts +9 -0
- package/dist/utils/generationContext.d.ts.map +1 -1
- package/dist/utils/imageUtils.d.ts +7 -3
- package/dist/utils/imageUtils.d.ts.map +1 -1
- package/package.json +4 -3
package/dist/index.js
CHANGED
|
@@ -2665,10 +2665,68 @@ function resolveFromBaseDir(filePath) {
|
|
|
2665
2665
|
if (!base || isAbsolute(filePath)) return filePath;
|
|
2666
2666
|
return resolve(base, filePath);
|
|
2667
2667
|
}
|
|
2668
|
+
var warningsStorage = new AsyncLocalStorage();
|
|
2669
|
+
function runWithWarnings(warnings, callback) {
|
|
2670
|
+
return warnings === void 0 ? callback() : warningsStorage.run(warnings, callback);
|
|
2671
|
+
}
|
|
2672
|
+
function reportWarning(component, code, message, context) {
|
|
2673
|
+
const warnings = warningsStorage.getStore();
|
|
2674
|
+
if (warnings) {
|
|
2675
|
+
warnings.push({
|
|
2676
|
+
component,
|
|
2677
|
+
message,
|
|
2678
|
+
severity: "warning",
|
|
2679
|
+
context: { code, ...context }
|
|
2680
|
+
});
|
|
2681
|
+
return;
|
|
2682
|
+
}
|
|
2683
|
+
console.warn(`[json-to-docx] [${code}] ${message}`);
|
|
2684
|
+
}
|
|
2668
2685
|
|
|
2669
2686
|
// src/utils/imageUtils.ts
|
|
2670
2687
|
init_widthUtils();
|
|
2671
2688
|
import { ImageRun } from "docx";
|
|
2689
|
+
var SVG_RASTER_SCALE = 3;
|
|
2690
|
+
var SVG_MAX_EDGE_PX = 4096;
|
|
2691
|
+
var SVG_MIN_EDGE_PX = 16;
|
|
2692
|
+
var resvgModule;
|
|
2693
|
+
function loadResvg() {
|
|
2694
|
+
resvgModule ??= import("@resvg/resvg-js");
|
|
2695
|
+
return resvgModule;
|
|
2696
|
+
}
|
|
2697
|
+
function toRasterPx(px) {
|
|
2698
|
+
return Math.min(
|
|
2699
|
+
SVG_MAX_EDGE_PX,
|
|
2700
|
+
Math.max(SVG_MIN_EDGE_PX, Math.round(px * SVG_RASTER_SCALE))
|
|
2701
|
+
);
|
|
2702
|
+
}
|
|
2703
|
+
async function rasterizeSvgFallback(svg, transformation) {
|
|
2704
|
+
let Resvg;
|
|
2705
|
+
try {
|
|
2706
|
+
({ Resvg } = await loadResvg());
|
|
2707
|
+
} catch (error) {
|
|
2708
|
+
reportWarning(
|
|
2709
|
+
"image",
|
|
2710
|
+
"IMAGE_SVG_RASTER_FAILED",
|
|
2711
|
+
`Could not load the SVG rasterizer, so inline SVG keeps a fallback that only Word 2016+ can draw: ${String(error)}`
|
|
2712
|
+
);
|
|
2713
|
+
return void 0;
|
|
2714
|
+
}
|
|
2715
|
+
try {
|
|
2716
|
+
const markup = svg.toString("utf-8");
|
|
2717
|
+
const probeImage = new Resvg(markup);
|
|
2718
|
+
const wide = probeImage.width / probeImage.height > transformation.width / transformation.height;
|
|
2719
|
+
const fitTo = wide ? { mode: "height", value: toRasterPx(transformation.height) } : { mode: "width", value: toRasterPx(transformation.width) };
|
|
2720
|
+
return Buffer.from(new Resvg(markup, { fitTo }).render().asPng());
|
|
2721
|
+
} catch (error) {
|
|
2722
|
+
reportWarning(
|
|
2723
|
+
"image",
|
|
2724
|
+
"IMAGE_SVG_RASTER_FAILED",
|
|
2725
|
+
`Could not rasterize inline SVG, so its fallback only renders in Word 2016+: ${String(error)}`
|
|
2726
|
+
);
|
|
2727
|
+
return void 0;
|
|
2728
|
+
}
|
|
2729
|
+
}
|
|
2672
2730
|
function parseWidthValue(width, availableWidthPx) {
|
|
2673
2731
|
if (typeof width === "number") {
|
|
2674
2732
|
return width;
|
|
@@ -2778,17 +2836,18 @@ function detectImageType(imagePath, responseContentType) {
|
|
|
2778
2836
|
if (typeFromExtension) return typeFromExtension;
|
|
2779
2837
|
return "png";
|
|
2780
2838
|
}
|
|
2781
|
-
function createTypedImageRun(opts) {
|
|
2839
|
+
async function createTypedImageRun(opts) {
|
|
2782
2840
|
const base = {
|
|
2783
2841
|
data: opts.data,
|
|
2784
2842
|
transformation: opts.transformation,
|
|
2785
2843
|
...opts.floating && { floating: opts.floating }
|
|
2786
2844
|
};
|
|
2787
2845
|
if (opts.type === "svg") {
|
|
2846
|
+
const raster = await rasterizeSvgFallback(opts.data, opts.transformation);
|
|
2788
2847
|
return new ImageRun({
|
|
2789
2848
|
type: "svg",
|
|
2790
2849
|
...base,
|
|
2791
|
-
fallback: { type: "png", data: opts.data }
|
|
2850
|
+
fallback: { type: "png", data: raster ?? opts.data }
|
|
2792
2851
|
});
|
|
2793
2852
|
}
|
|
2794
2853
|
return new ImageRun({ type: opts.type, ...base });
|
|
@@ -5217,7 +5276,7 @@ async function createImage(path4, theme, themeName, options = {}) {
|
|
|
5217
5276
|
const { mapFloatingOptions: mapFloatingOptions2 } = await Promise.resolve().then(() => (init_docxImagePositioning(), docxImagePositioning_exports));
|
|
5218
5277
|
const floating = isFloating ? mapFloatingOptions2(options.floating, theme, themeName) : void 0;
|
|
5219
5278
|
const imageType = detectImageType(imagePath, responseContentType);
|
|
5220
|
-
const imageRun = createTypedImageRun({
|
|
5279
|
+
const imageRun = await createTypedImageRun({
|
|
5221
5280
|
type: imageType,
|
|
5222
5281
|
data: imageBuffer,
|
|
5223
5282
|
transformation: { width: dimensions.width, height: dimensions.height },
|
|
@@ -5762,7 +5821,7 @@ async function createTable(columns, tableConfig, theme, themeName, _options = {}
|
|
|
5762
5821
|
// fallback height
|
|
5763
5822
|
);
|
|
5764
5823
|
const imgType = detectImageType(imageSource, imageResult.contentType);
|
|
5765
|
-
const imageRun = createTypedImageRun({
|
|
5824
|
+
const imageRun = await createTypedImageRun({
|
|
5766
5825
|
type: imgType,
|
|
5767
5826
|
data: imageResult.buffer,
|
|
5768
5827
|
transformation: {
|
|
@@ -7610,14 +7669,19 @@ function effectiveVisualServerUrl(props, serviceConfig) {
|
|
|
7610
7669
|
if (serviceConfig?.render) return void 0;
|
|
7611
7670
|
return props.serverUrl;
|
|
7612
7671
|
}
|
|
7613
|
-
async function rasterizeVisualSlide(presentation, dpi, propsServerUrl, serviceConfig, baseDir) {
|
|
7672
|
+
async function rasterizeVisualSlide(presentation, dpi, propsServerUrl, serviceConfig, baseDir, fonts) {
|
|
7614
7673
|
if (!isNodeEnvironment()) {
|
|
7615
7674
|
throw new Error(
|
|
7616
7675
|
"Visual rasterization requires a Node.js environment. It is not available in browser environments."
|
|
7617
7676
|
);
|
|
7618
7677
|
}
|
|
7619
7678
|
if (serviceConfig?.render) {
|
|
7620
|
-
return serviceConfig.render({
|
|
7679
|
+
return serviceConfig.render({
|
|
7680
|
+
presentation,
|
|
7681
|
+
dpi,
|
|
7682
|
+
baseDir,
|
|
7683
|
+
...fonts?.length ? { fonts: [...fonts] } : {}
|
|
7684
|
+
});
|
|
7621
7685
|
}
|
|
7622
7686
|
const serverUrl = resolveServiceUrl(
|
|
7623
7687
|
propsServerUrl,
|
|
@@ -7627,7 +7691,12 @@ async function rasterizeVisualSlide(presentation, dpi, propsServerUrl, serviceCo
|
|
|
7627
7691
|
const response = await postJsonToService({
|
|
7628
7692
|
url: serverUrl,
|
|
7629
7693
|
path: "/rasterize",
|
|
7630
|
-
body: {
|
|
7694
|
+
body: {
|
|
7695
|
+
presentation,
|
|
7696
|
+
dpi,
|
|
7697
|
+
...baseDir !== void 0 && { baseDir },
|
|
7698
|
+
...fonts?.length ? { fonts } : {}
|
|
7699
|
+
},
|
|
7631
7700
|
headers: serviceConfig?.headers,
|
|
7632
7701
|
serviceLabel: "PPTX rasterization service",
|
|
7633
7702
|
onUnreachable: (url, cause) => `PPTX rasterization service is not reachable at ${url}. Configure services.pptx with a \`render\` callback or a running \`serverUrl\`.
|
|
@@ -7673,7 +7742,8 @@ async function renderVisualComponent(component, theme, themeName, context) {
|
|
|
7673
7742
|
dpi,
|
|
7674
7743
|
props.serverUrl,
|
|
7675
7744
|
serviceConfig,
|
|
7676
|
-
getBaseDir()
|
|
7745
|
+
getBaseDir(),
|
|
7746
|
+
context?.visualFonts
|
|
7677
7747
|
);
|
|
7678
7748
|
}
|
|
7679
7749
|
return await createImage(
|
|
@@ -7807,6 +7877,11 @@ function collectVisualProps(root) {
|
|
|
7807
7877
|
function toErrorMessage(error) {
|
|
7808
7878
|
return error instanceof Error ? error.message : String(error);
|
|
7809
7879
|
}
|
|
7880
|
+
var HTTP_STATUS_IN_MESSAGE = /\breturned (\d{3})\b/;
|
|
7881
|
+
function isSchemaRejection(error) {
|
|
7882
|
+
const match = HTTP_STATUS_IN_MESSAGE.exec(toErrorMessage(error));
|
|
7883
|
+
return match !== null && match[1] === "400";
|
|
7884
|
+
}
|
|
7810
7885
|
function* chunksOf(items, size) {
|
|
7811
7886
|
for (let i = 0; i < items.length; i += size) yield items.slice(i, i + size);
|
|
7812
7887
|
}
|
|
@@ -7865,22 +7940,38 @@ async function prerasterizeVisuals(root, serviceConfig, options = {}) {
|
|
|
7865
7940
|
const limit = createLimiter(
|
|
7866
7941
|
Math.max(1, options.concurrency ?? DEFAULT_FALLBACK_CONCURRENCY)
|
|
7867
7942
|
);
|
|
7943
|
+
let fontsRejected = false;
|
|
7944
|
+
const requestFonts = () => fontsRejected || !options.fonts?.length ? void 0 : options.fonts;
|
|
7945
|
+
const rasterizeOne = async (target) => {
|
|
7946
|
+
const fonts = requestFonts();
|
|
7947
|
+
const call = (withFonts) => rasterizeVisualSlide(
|
|
7948
|
+
target.presentation,
|
|
7949
|
+
target.dpi,
|
|
7950
|
+
void 0,
|
|
7951
|
+
serviceConfig,
|
|
7952
|
+
options.baseDir,
|
|
7953
|
+
withFonts
|
|
7954
|
+
);
|
|
7955
|
+
try {
|
|
7956
|
+
return { ok: true, ...await call(fonts) };
|
|
7957
|
+
} catch (error) {
|
|
7958
|
+
if (!fonts || !isSchemaRejection(error)) {
|
|
7959
|
+
return { ok: false, error: toErrorMessage(error) };
|
|
7960
|
+
}
|
|
7961
|
+
try {
|
|
7962
|
+
const result = await call(void 0);
|
|
7963
|
+
fontsRejected = true;
|
|
7964
|
+
return { ok: true, ...result };
|
|
7965
|
+
} catch {
|
|
7966
|
+
return { ok: false, error: toErrorMessage(error) };
|
|
7967
|
+
}
|
|
7968
|
+
}
|
|
7969
|
+
};
|
|
7868
7970
|
const rasterizeIndividually = async (chunk) => {
|
|
7869
7971
|
await Promise.all(
|
|
7870
7972
|
chunk.map(
|
|
7871
7973
|
(target) => limit(async () => {
|
|
7872
|
-
|
|
7873
|
-
const result = await rasterizeVisualSlide(
|
|
7874
|
-
target.presentation,
|
|
7875
|
-
target.dpi,
|
|
7876
|
-
void 0,
|
|
7877
|
-
serviceConfig,
|
|
7878
|
-
options.baseDir
|
|
7879
|
-
);
|
|
7880
|
-
map.set(target.key, { ok: true, ...result });
|
|
7881
|
-
} catch (error) {
|
|
7882
|
-
map.set(target.key, { ok: false, error: toErrorMessage(error) });
|
|
7883
|
-
}
|
|
7974
|
+
map.set(target.key, await rasterizeOne(target));
|
|
7884
7975
|
})
|
|
7885
7976
|
)
|
|
7886
7977
|
);
|
|
@@ -7893,7 +7984,8 @@ async function prerasterizeVisuals(root, serviceConfig, options = {}) {
|
|
|
7893
7984
|
presentation: target.presentation,
|
|
7894
7985
|
dpi: target.dpi
|
|
7895
7986
|
})),
|
|
7896
|
-
...options.baseDir !== void 0 && { baseDir: options.baseDir }
|
|
7987
|
+
...options.baseDir !== void 0 && { baseDir: options.baseDir },
|
|
7988
|
+
...options.fonts?.length ? { fonts: [...options.fonts] } : {}
|
|
7897
7989
|
});
|
|
7898
7990
|
if (!applyBatchResponse(chunk, response, map)) {
|
|
7899
7991
|
throw new Error(
|
|
@@ -7922,10 +8014,10 @@ async function prerasterizeVisuals(root, serviceConfig, options = {}) {
|
|
|
7922
8014
|
serviceConfig?.serverUrl,
|
|
7923
8015
|
DEFAULT_RASTERIZE_SERVER_URL
|
|
7924
8016
|
);
|
|
7925
|
-
|
|
7926
|
-
let
|
|
8017
|
+
const postBatch = async (chunk, fonts) => {
|
|
8018
|
+
let response;
|
|
7927
8019
|
try {
|
|
7928
|
-
|
|
8020
|
+
response = await postJsonToService({
|
|
7929
8021
|
url: serverUrl,
|
|
7930
8022
|
path: "/rasterize/batch",
|
|
7931
8023
|
body: {
|
|
@@ -7933,18 +8025,36 @@ async function prerasterizeVisuals(root, serviceConfig, options = {}) {
|
|
|
7933
8025
|
presentation: target.presentation,
|
|
7934
8026
|
dpi: target.dpi
|
|
7935
8027
|
})),
|
|
7936
|
-
...options.baseDir !== void 0 && { baseDir: options.baseDir }
|
|
8028
|
+
...options.baseDir !== void 0 && { baseDir: options.baseDir },
|
|
8029
|
+
...fonts?.length ? { fonts } : {}
|
|
7937
8030
|
},
|
|
7938
8031
|
headers: serviceConfig?.headers,
|
|
7939
8032
|
timeoutMs: BATCH_TIMEOUT_BASE_MS + BATCH_TIMEOUT_PER_SLIDE_MS * chunk.length,
|
|
7940
8033
|
serviceLabel: "PPTX batch rasterization service",
|
|
7941
8034
|
onUnreachable: (url, cause) => `PPTX rasterization service is not reachable at ${url}. Cause: ${cause}`
|
|
7942
8035
|
});
|
|
7943
|
-
|
|
8036
|
+
} catch (error) {
|
|
8037
|
+
return { applied: false, schemaRejected: isSchemaRejection(error) };
|
|
8038
|
+
}
|
|
8039
|
+
try {
|
|
8040
|
+
if (applyBatchResponse(chunk, await response.json(), map)) {
|
|
8041
|
+
return { applied: true };
|
|
8042
|
+
}
|
|
7944
8043
|
} catch {
|
|
7945
|
-
applied = false;
|
|
7946
8044
|
}
|
|
7947
|
-
|
|
8045
|
+
return { applied: false, schemaRejected: false };
|
|
8046
|
+
};
|
|
8047
|
+
for (const chunk of chunksOf(unique, MAX_RASTERIZE_BATCH_SLIDES)) {
|
|
8048
|
+
const fonts = requestFonts();
|
|
8049
|
+
let outcome = await postBatch(chunk, fonts);
|
|
8050
|
+
if (!outcome.applied && fonts && outcome.schemaRejected) {
|
|
8051
|
+
const retry = await postBatch(chunk, void 0);
|
|
8052
|
+
if (retry.applied) {
|
|
8053
|
+
fontsRejected = true;
|
|
8054
|
+
outcome = retry;
|
|
8055
|
+
}
|
|
8056
|
+
}
|
|
8057
|
+
if (!outcome.applied) await rasterizeIndividually(chunk);
|
|
7948
8058
|
}
|
|
7949
8059
|
return map;
|
|
7950
8060
|
}
|
|
@@ -8053,23 +8163,26 @@ function coreProperties(metadata) {
|
|
|
8053
8163
|
async function renderDocument(structure, layout, options) {
|
|
8054
8164
|
return runWithGenerationDate(
|
|
8055
8165
|
structure.metadata.date,
|
|
8056
|
-
() =>
|
|
8057
|
-
options?.
|
|
8058
|
-
() =>
|
|
8059
|
-
|
|
8060
|
-
|
|
8061
|
-
|
|
8062
|
-
|
|
8063
|
-
|
|
8064
|
-
|
|
8065
|
-
|
|
8066
|
-
|
|
8067
|
-
|
|
8068
|
-
|
|
8069
|
-
|
|
8070
|
-
|
|
8071
|
-
|
|
8072
|
-
|
|
8166
|
+
() => runWithWarnings(
|
|
8167
|
+
options?.warnings,
|
|
8168
|
+
() => runWithBaseDir(
|
|
8169
|
+
options?.baseDir,
|
|
8170
|
+
() => globalBookmarkRegistry.runScoped(
|
|
8171
|
+
() => globalRevisionIdRegistry.runScoped(
|
|
8172
|
+
() => globalNumberingRegistry.runScoped(
|
|
8173
|
+
() => globalSectionBookmarkRegistry.runScoped(
|
|
8174
|
+
() => (
|
|
8175
|
+
// Comment ids are a separate OOXML namespace from w:ins/w:del,
|
|
8176
|
+
// but they need the same per-render isolation: outside this nest
|
|
8177
|
+
// concurrent generations would interleave counters and an anchor
|
|
8178
|
+
// would point at another document's comment body.
|
|
8179
|
+
globalCommentRegistry.runScoped(
|
|
8180
|
+
() => (
|
|
8181
|
+
// Footnote ids are document-scoped too: a reference resolved
|
|
8182
|
+
// against another render's counter points at the wrong body.
|
|
8183
|
+
globalNoteRegistry.runScoped(
|
|
8184
|
+
() => renderDocumentScoped(structure, layout, options)
|
|
8185
|
+
)
|
|
8073
8186
|
)
|
|
8074
8187
|
)
|
|
8075
8188
|
)
|
|
@@ -8094,11 +8207,12 @@ async function renderDocumentScoped(structure, layout, options) {
|
|
|
8094
8207
|
structure.themeName
|
|
8095
8208
|
);
|
|
8096
8209
|
context.services = options?.services;
|
|
8210
|
+
context.visualFonts = options?.visualFonts;
|
|
8097
8211
|
try {
|
|
8098
8212
|
const visualRasterResults = await prerasterizeVisuals(
|
|
8099
8213
|
layout.sections,
|
|
8100
8214
|
options?.services?.pptx,
|
|
8101
|
-
{ baseDir: getBaseDir() }
|
|
8215
|
+
{ baseDir: getBaseDir(), fonts: options?.visualFonts }
|
|
8102
8216
|
);
|
|
8103
8217
|
if (visualRasterResults.size > 0) {
|
|
8104
8218
|
context.visualRasterResults = visualRasterResults;
|
|
@@ -8288,7 +8402,7 @@ async function renderHeaderFooterComponents(components, theme, themeName, contex
|
|
|
8288
8402
|
themeName
|
|
8289
8403
|
);
|
|
8290
8404
|
const imageType = detectImageType(imageSource, responseContentType);
|
|
8291
|
-
const imageRun = createTypedImageRun({
|
|
8405
|
+
const imageRun = await createTypedImageRun({
|
|
8292
8406
|
type: imageType,
|
|
8293
8407
|
data: imageBuffer,
|
|
8294
8408
|
transformation: {
|
|
@@ -8468,14 +8582,17 @@ async function renderComponent(component, theme, themeName, context) {
|
|
|
8468
8582
|
import {
|
|
8469
8583
|
collectFontNamesFromDocx,
|
|
8470
8584
|
validateFontReferences,
|
|
8471
|
-
FontRegistry
|
|
8585
|
+
FontRegistry,
|
|
8586
|
+
documentFontRegistry,
|
|
8587
|
+
themeFontRegistry,
|
|
8588
|
+
mergeFontRegistries
|
|
8472
8589
|
} from "@json-to-office/shared";
|
|
8473
8590
|
import {
|
|
8474
8591
|
loadFileFontSource,
|
|
8475
8592
|
FontDiskCache,
|
|
8476
8593
|
fetchVariableFontSource
|
|
8477
8594
|
} from "@json-to-office/shared/fonts/node";
|
|
8478
|
-
async function resolveDocumentFonts(document, theme, fonts, warnings) {
|
|
8595
|
+
async function resolveDocumentFonts(document, theme, fonts, warnings, forceMaterialize = false) {
|
|
8479
8596
|
const emit = (code, message) => {
|
|
8480
8597
|
if (warnings) {
|
|
8481
8598
|
warnings.push({
|
|
@@ -8492,9 +8609,14 @@ async function resolveDocumentFonts(document, theme, fonts, warnings) {
|
|
|
8492
8609
|
for (const n of collectFontNamesFromDocx(document)) names.add(n);
|
|
8493
8610
|
for (const n of collectFontNamesFromDocx(theme)) names.add(n);
|
|
8494
8611
|
if (names.size === 0) return [];
|
|
8612
|
+
const registryEntries = mergeFontRegistries(
|
|
8613
|
+
themeFontRegistry(theme),
|
|
8614
|
+
documentFontRegistry(document),
|
|
8615
|
+
fonts?.extraEntries
|
|
8616
|
+
);
|
|
8495
8617
|
const validation = validateFontReferences({
|
|
8496
8618
|
referencedNames: names,
|
|
8497
|
-
registeredEntries:
|
|
8619
|
+
registeredEntries: registryEntries
|
|
8498
8620
|
});
|
|
8499
8621
|
if (validation.warnings.length > 0) {
|
|
8500
8622
|
if (fonts?.strict) {
|
|
@@ -8507,9 +8629,11 @@ async function resolveDocumentFonts(document, theme, fonts, warnings) {
|
|
|
8507
8629
|
emit(w.code, w.message);
|
|
8508
8630
|
}
|
|
8509
8631
|
}
|
|
8510
|
-
if (!fonts?.onResolved) return [];
|
|
8632
|
+
if (!fonts?.onResolved && !forceMaterialize) return [];
|
|
8511
8633
|
const registry = new FontRegistry({
|
|
8512
|
-
|
|
8634
|
+
// Spread keeps baseDir/googleFonts/mode/substitution intact for
|
|
8635
|
+
// materializeSource; extraEntries carries the merged registry.
|
|
8636
|
+
opts: { ...fonts, extraEntries: registryEntries },
|
|
8513
8637
|
fileLoader: loadFileFontSource,
|
|
8514
8638
|
variableLoader: fetchVariableFontSource,
|
|
8515
8639
|
diskCache: fonts?.googleFonts?.cacheDir ? new FontDiskCache(fonts.googleFonts.cacheDir) : void 0
|
|
@@ -8520,10 +8644,13 @@ async function resolveDocumentFonts(document, theme, fonts, warnings) {
|
|
|
8520
8644
|
emit("FONT_UNRESOLVED", msg);
|
|
8521
8645
|
}
|
|
8522
8646
|
}
|
|
8523
|
-
fonts
|
|
8647
|
+
fonts?.onResolved?.(resolved);
|
|
8524
8648
|
return resolved;
|
|
8525
8649
|
}
|
|
8526
8650
|
|
|
8651
|
+
// src/core/generator.ts
|
|
8652
|
+
import { toRasterizeFontFaces } from "@json-to-office/shared/fonts/node";
|
|
8653
|
+
|
|
8527
8654
|
// src/utils/packageDocument.ts
|
|
8528
8655
|
import AdmZip2 from "adm-zip";
|
|
8529
8656
|
import { Packer } from "docx";
|
|
@@ -8783,7 +8910,15 @@ async function generateDocumentWithCustomThemes(documentIn, customThemes, servic
|
|
|
8783
8910
|
fonts,
|
|
8784
8911
|
warnings
|
|
8785
8912
|
});
|
|
8786
|
-
|
|
8913
|
+
const hasVisual = collectVisualProps(document).length > 0;
|
|
8914
|
+
const resolvedFonts = await resolveDocumentFonts(
|
|
8915
|
+
document,
|
|
8916
|
+
theme,
|
|
8917
|
+
fonts,
|
|
8918
|
+
warnings,
|
|
8919
|
+
hasVisual
|
|
8920
|
+
);
|
|
8921
|
+
const visualFonts = hasVisual ? toRasterizeFontFaces(resolvedFonts, warnings) : [];
|
|
8787
8922
|
const structure = await processDocument(
|
|
8788
8923
|
document,
|
|
8789
8924
|
theme,
|
|
@@ -8794,7 +8929,9 @@ async function generateDocumentWithCustomThemes(documentIn, customThemes, servic
|
|
|
8794
8929
|
const renderedDocument = await renderDocument(structure, layout, {
|
|
8795
8930
|
bypassCache: false,
|
|
8796
8931
|
services,
|
|
8797
|
-
baseDir
|
|
8932
|
+
baseDir,
|
|
8933
|
+
warnings,
|
|
8934
|
+
...visualFonts.length > 0 && { visualFonts }
|
|
8798
8935
|
});
|
|
8799
8936
|
return renderedDocument;
|
|
8800
8937
|
}
|
|
@@ -8908,7 +9045,11 @@ async function flattenVisuals(doc, options) {
|
|
|
8908
9045
|
renderBatch: options.rasterizeBatch,
|
|
8909
9046
|
dpi: options.dpi
|
|
8910
9047
|
},
|
|
8911
|
-
{
|
|
9048
|
+
{
|
|
9049
|
+
baseDir: options.baseDir,
|
|
9050
|
+
concurrency: options.concurrency,
|
|
9051
|
+
fonts: options.fonts
|
|
9052
|
+
}
|
|
8912
9053
|
).catch(() => /* @__PURE__ */ new Map());
|
|
8913
9054
|
rasterize = async (request) => {
|
|
8914
9055
|
const hit = preRasterized.get(
|
|
@@ -8929,6 +9070,7 @@ async function flattenVisuals(doc, options) {
|
|
|
8929
9070
|
rasterize,
|
|
8930
9071
|
dpi: options.dpi,
|
|
8931
9072
|
baseDir: options.baseDir,
|
|
9073
|
+
fonts: options.fonts,
|
|
8932
9074
|
limit: createLimiter(
|
|
8933
9075
|
Math.max(1, options.concurrency ?? DEFAULT_CONCURRENCY)
|
|
8934
9076
|
)
|
|
@@ -8942,7 +9084,8 @@ async function rasterizeVisual(obj, ctx) {
|
|
|
8942
9084
|
() => ctx.rasterize({
|
|
8943
9085
|
presentation: buildVisualPresentation(props),
|
|
8944
9086
|
dpi,
|
|
8945
|
-
baseDir: ctx.baseDir
|
|
9087
|
+
baseDir: ctx.baseDir,
|
|
9088
|
+
...ctx.fonts?.length ? { fonts: [...ctx.fonts] } : {}
|
|
8946
9089
|
})
|
|
8947
9090
|
);
|
|
8948
9091
|
const image = {
|
|
@@ -9218,6 +9361,7 @@ async function runExample(example, options = {}) {
|
|
|
9218
9361
|
|
|
9219
9362
|
// src/plugin/createDocumentGenerator.ts
|
|
9220
9363
|
init_themes();
|
|
9364
|
+
import { toRasterizeFontFaces as toRasterizeFontFaces2 } from "@json-to-office/shared/fonts/node";
|
|
9221
9365
|
|
|
9222
9366
|
// src/plugin/version-resolver.ts
|
|
9223
9367
|
import { resolveComponentVersion } from "@json-to-office/shared/plugin";
|
|
@@ -9745,7 +9889,15 @@ function createBuilderImpl(state) {
|
|
|
9745
9889
|
warnings,
|
|
9746
9890
|
preserveSet
|
|
9747
9891
|
} = await expandDocument(document, options);
|
|
9748
|
-
|
|
9892
|
+
const hasVisual = collectVisualProps(modedDoc).length > 0;
|
|
9893
|
+
const resolvedFonts = await resolveDocumentFonts(
|
|
9894
|
+
modedDoc,
|
|
9895
|
+
modedTheme,
|
|
9896
|
+
state.fonts,
|
|
9897
|
+
warnings,
|
|
9898
|
+
hasVisual
|
|
9899
|
+
);
|
|
9900
|
+
const visualFonts = hasVisual ? toRasterizeFontFaces2(resolvedFonts, warnings) : [];
|
|
9749
9901
|
const packageOptions = {
|
|
9750
9902
|
deterministic: options?.deterministic ?? state.deterministic,
|
|
9751
9903
|
generatedAt: options?.generatedAt ?? state.generatedAt
|
|
@@ -9760,7 +9912,9 @@ function createBuilderImpl(state) {
|
|
|
9760
9912
|
const generatedDocument = await renderDocument(structure, layout, {
|
|
9761
9913
|
services: state.services,
|
|
9762
9914
|
bypassCache: !state.enableCache,
|
|
9763
|
-
baseDir: options?.baseDir ?? state.baseDir
|
|
9915
|
+
baseDir: options?.baseDir ?? state.baseDir,
|
|
9916
|
+
warnings,
|
|
9917
|
+
...visualFonts.length > 0 && { visualFonts }
|
|
9764
9918
|
});
|
|
9765
9919
|
const preservedDefinition = preserveSet ? {
|
|
9766
9920
|
...modedRoot,
|