@json-to-office/core-docx 0.27.0 → 0.29.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/components/visual.d.ts +27 -0
- package/dist/components/visual.d.ts.map +1 -1
- package/dist/core/cached-render.d.ts.map +1 -1
- package/dist/core/flattenVisuals.d.ts +15 -2
- package/dist/core/flattenVisuals.d.ts.map +1 -1
- package/dist/core/generator.d.ts +6 -0
- package/dist/core/generator.d.ts.map +1 -1
- package/dist/core/prerasterizeVisuals.d.ts +44 -0
- package/dist/core/prerasterizeVisuals.d.ts.map +1 -0
- package/dist/core/render.d.ts +5 -0
- package/dist/core/render.d.ts.map +1 -1
- package/dist/index.js +334 -58
- package/dist/index.js.map +1 -1
- package/dist/plugin/createDocumentGenerator.d.ts +6 -0
- package/dist/plugin/createDocumentGenerator.d.ts.map +1 -1
- package/dist/plugin/example/index.js +286 -30
- package/dist/plugin/example/index.js.map +1 -1
- package/dist/plugin/types.d.ts +6 -0
- package/dist/plugin/types.d.ts.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/index.d.ts +7 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/generationContext.d.ts +15 -0
- package/dist/utils/generationContext.d.ts.map +1 -1
- package/dist/utils/imageUtils.d.ts.map +1 -1
- package/dist/utils/promiseLimiter.d.ts +7 -0
- package/dist/utils/promiseLimiter.d.ts.map +1 -0
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1924,6 +1924,7 @@ var init_docxImagePositioning = __esm({
|
|
|
1924
1924
|
|
|
1925
1925
|
// src/core/generator.ts
|
|
1926
1926
|
import { writeFileSync } from "fs";
|
|
1927
|
+
import { dirname, resolve as resolve3 } from "path";
|
|
1927
1928
|
|
|
1928
1929
|
// src/types/index.ts
|
|
1929
1930
|
import {
|
|
@@ -2698,9 +2699,34 @@ import {
|
|
|
2698
2699
|
} from "docx";
|
|
2699
2700
|
|
|
2700
2701
|
// src/utils/imageUtils.ts
|
|
2701
|
-
init_widthUtils();
|
|
2702
2702
|
import { readFileSync } from "fs";
|
|
2703
2703
|
import probe from "probe-image-size";
|
|
2704
|
+
|
|
2705
|
+
// src/utils/generationContext.ts
|
|
2706
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
2707
|
+
import { isAbsolute, resolve } from "path";
|
|
2708
|
+
var generationDateStorage = new AsyncLocalStorage();
|
|
2709
|
+
function runWithGenerationDate(date, callback) {
|
|
2710
|
+
return generationDateStorage.run(date, callback);
|
|
2711
|
+
}
|
|
2712
|
+
function getGenerationDate() {
|
|
2713
|
+
return generationDateStorage.getStore() ?? /* @__PURE__ */ new Date();
|
|
2714
|
+
}
|
|
2715
|
+
var baseDirStorage = new AsyncLocalStorage();
|
|
2716
|
+
function runWithBaseDir(baseDir, callback) {
|
|
2717
|
+
return baseDir === void 0 ? callback() : baseDirStorage.run(resolve(baseDir), callback);
|
|
2718
|
+
}
|
|
2719
|
+
function getBaseDir() {
|
|
2720
|
+
return baseDirStorage.getStore();
|
|
2721
|
+
}
|
|
2722
|
+
function resolveFromBaseDir(filePath) {
|
|
2723
|
+
const base = baseDirStorage.getStore();
|
|
2724
|
+
if (!base || isAbsolute(filePath)) return filePath;
|
|
2725
|
+
return resolve(base, filePath);
|
|
2726
|
+
}
|
|
2727
|
+
|
|
2728
|
+
// src/utils/imageUtils.ts
|
|
2729
|
+
init_widthUtils();
|
|
2704
2730
|
import { ImageRun } from "docx";
|
|
2705
2731
|
function parseWidthValue(width, availableWidthPx) {
|
|
2706
2732
|
if (typeof width === "number") {
|
|
@@ -2876,7 +2902,7 @@ async function getImageBuffer(imagePath) {
|
|
|
2876
2902
|
if (isValidUrl(imagePath)) {
|
|
2877
2903
|
return await downloadImageFromUrl(imagePath);
|
|
2878
2904
|
}
|
|
2879
|
-
return { buffer: readFileSync(imagePath) };
|
|
2905
|
+
return { buffer: readFileSync(resolveFromBaseDir(imagePath)) };
|
|
2880
2906
|
}
|
|
2881
2907
|
async function getImageDimensions(imagePath) {
|
|
2882
2908
|
try {
|
|
@@ -3948,16 +3974,6 @@ function parseTextWithHyperlinks(text, baseStyle = {}, options = {}) {
|
|
|
3948
3974
|
return runs;
|
|
3949
3975
|
}
|
|
3950
3976
|
|
|
3951
|
-
// src/utils/generationContext.ts
|
|
3952
|
-
import { AsyncLocalStorage } from "async_hooks";
|
|
3953
|
-
var generationDateStorage = new AsyncLocalStorage();
|
|
3954
|
-
function runWithGenerationDate(date, callback) {
|
|
3955
|
-
return generationDateStorage.run(date, callback);
|
|
3956
|
-
}
|
|
3957
|
-
function getGenerationDate() {
|
|
3958
|
-
return generationDateStorage.getStore() ?? /* @__PURE__ */ new Date();
|
|
3959
|
-
}
|
|
3960
|
-
|
|
3961
3977
|
// src/utils/placeholderProcessor.ts
|
|
3962
3978
|
function styledPlaceholderText(text, context) {
|
|
3963
3979
|
return new TextRun2({
|
|
@@ -4312,8 +4328,9 @@ async function renderComponentWithCache(component, theme, themeName, context, by
|
|
|
4312
4328
|
const themeHash = createThemeHash(theme);
|
|
4313
4329
|
const contextKey = context?.section ? `${context.section.currentLayout}:${context.section.columnCount}` : "no-section";
|
|
4314
4330
|
const generationDateKey = getGenerationDate().toISOString();
|
|
4331
|
+
const baseDirKey = getBaseDir() ?? "";
|
|
4315
4332
|
const childrenKey = "children" in component && component.children ? `:children:${JSON.stringify(component.children)}` : "";
|
|
4316
|
-
const cacheKey = `component:${component.name}:${themeHash}:${contextKey}:${generationDateKey}:${componentProps}${childrenKey}`;
|
|
4333
|
+
const cacheKey = `component:${component.name}:${themeHash}:${contextKey}:${generationDateKey}:${baseDirKey}:${componentProps}${childrenKey}`;
|
|
4317
4334
|
const cached = await componentCache.get(cacheKey);
|
|
4318
4335
|
if (cached) {
|
|
4319
4336
|
return cached.result;
|
|
@@ -6996,6 +7013,7 @@ async function renderHighchartsComponent(component, theme, themeName, context) {
|
|
|
6996
7013
|
}
|
|
6997
7014
|
|
|
6998
7015
|
// src/components/visual.ts
|
|
7016
|
+
import { createHash as createHash4 } from "crypto";
|
|
6999
7017
|
import {
|
|
7000
7018
|
clampVisualDpi,
|
|
7001
7019
|
DEFAULT_VISUAL_DPI
|
|
@@ -7045,14 +7063,21 @@ function visualToImageProps(props, base64DataUri) {
|
|
|
7045
7063
|
...props.alt !== void 0 && { alt: props.alt }
|
|
7046
7064
|
};
|
|
7047
7065
|
}
|
|
7048
|
-
|
|
7066
|
+
function visualRasterKey(presentation, dpi, serverUrl) {
|
|
7067
|
+
return createHash4("sha256").update(JSON.stringify({ p: presentation, d: dpi, u: serverUrl ?? null })).digest("hex");
|
|
7068
|
+
}
|
|
7069
|
+
function effectiveVisualServerUrl(props, serviceConfig) {
|
|
7070
|
+
if (serviceConfig?.render) return void 0;
|
|
7071
|
+
return props.serverUrl;
|
|
7072
|
+
}
|
|
7073
|
+
async function rasterizeVisualSlide(presentation, dpi, propsServerUrl, serviceConfig, baseDir) {
|
|
7049
7074
|
if (!isNodeEnvironment()) {
|
|
7050
7075
|
throw new Error(
|
|
7051
7076
|
"Visual rasterization requires a Node.js environment. It is not available in browser environments."
|
|
7052
7077
|
);
|
|
7053
7078
|
}
|
|
7054
7079
|
if (serviceConfig?.render) {
|
|
7055
|
-
return serviceConfig.render({ presentation, dpi });
|
|
7080
|
+
return serviceConfig.render({ presentation, dpi, baseDir });
|
|
7056
7081
|
}
|
|
7057
7082
|
const serverUrl = resolveServiceUrl(
|
|
7058
7083
|
propsServerUrl,
|
|
@@ -7062,7 +7087,7 @@ async function rasterize(presentation, dpi, propsServerUrl, serviceConfig) {
|
|
|
7062
7087
|
const response = await postJsonToService({
|
|
7063
7088
|
url: serverUrl,
|
|
7064
7089
|
path: "/rasterize",
|
|
7065
|
-
body: { presentation, dpi },
|
|
7090
|
+
body: { presentation, dpi, ...baseDir !== void 0 && { baseDir } },
|
|
7066
7091
|
headers: serviceConfig?.headers,
|
|
7067
7092
|
serviceLabel: "PPTX rasterization service",
|
|
7068
7093
|
onUnreachable: (url, cause) => `PPTX rasterization service is not reachable at ${url}. Configure services.pptx with a \`render\` callback or a running \`serverUrl\`.
|
|
@@ -7091,12 +7116,26 @@ async function renderVisualComponent(component, theme, themeName, context) {
|
|
|
7091
7116
|
const dpi = clampVisualDpi(
|
|
7092
7117
|
props.dpi ?? serviceConfig?.dpi ?? DEFAULT_VISUAL_DPI
|
|
7093
7118
|
);
|
|
7094
|
-
const
|
|
7095
|
-
|
|
7096
|
-
|
|
7097
|
-
|
|
7098
|
-
|
|
7119
|
+
const preRasterized = context?.visualRasterResults?.get(
|
|
7120
|
+
visualRasterKey(
|
|
7121
|
+
presentation,
|
|
7122
|
+
dpi,
|
|
7123
|
+
effectiveVisualServerUrl(props, serviceConfig)
|
|
7124
|
+
)
|
|
7099
7125
|
);
|
|
7126
|
+
let result;
|
|
7127
|
+
if (preRasterized) {
|
|
7128
|
+
if (!preRasterized.ok) throw new Error(preRasterized.error);
|
|
7129
|
+
result = preRasterized;
|
|
7130
|
+
} else {
|
|
7131
|
+
result = await rasterizeVisualSlide(
|
|
7132
|
+
presentation,
|
|
7133
|
+
dpi,
|
|
7134
|
+
props.serverUrl,
|
|
7135
|
+
serviceConfig,
|
|
7136
|
+
getBaseDir()
|
|
7137
|
+
);
|
|
7138
|
+
}
|
|
7100
7139
|
return await createImage(
|
|
7101
7140
|
result.base64DataUri,
|
|
7102
7141
|
theme,
|
|
@@ -7158,6 +7197,203 @@ var textSpaceAfterComponent = createComponent({
|
|
|
7158
7197
|
|
|
7159
7198
|
// src/core/render.ts
|
|
7160
7199
|
init_docxImagePositioning();
|
|
7200
|
+
|
|
7201
|
+
// src/core/prerasterizeVisuals.ts
|
|
7202
|
+
import {
|
|
7203
|
+
clampVisualDpi as clampVisualDpi2,
|
|
7204
|
+
DEFAULT_VISUAL_DPI as DEFAULT_VISUAL_DPI2,
|
|
7205
|
+
MAX_RASTERIZE_BATCH_SLIDES
|
|
7206
|
+
} from "@json-to-office/shared";
|
|
7207
|
+
|
|
7208
|
+
// src/utils/promiseLimiter.ts
|
|
7209
|
+
function createLimiter(max) {
|
|
7210
|
+
let active = 0;
|
|
7211
|
+
const queue = [];
|
|
7212
|
+
const release = () => {
|
|
7213
|
+
active--;
|
|
7214
|
+
queue.shift()?.();
|
|
7215
|
+
};
|
|
7216
|
+
return async function limit(fn) {
|
|
7217
|
+
while (active >= max)
|
|
7218
|
+
await new Promise((resolve4) => queue.push(resolve4));
|
|
7219
|
+
active++;
|
|
7220
|
+
try {
|
|
7221
|
+
return await fn();
|
|
7222
|
+
} finally {
|
|
7223
|
+
release();
|
|
7224
|
+
}
|
|
7225
|
+
};
|
|
7226
|
+
}
|
|
7227
|
+
|
|
7228
|
+
// src/core/prerasterizeVisuals.ts
|
|
7229
|
+
var DEFAULT_FALLBACK_CONCURRENCY = 4;
|
|
7230
|
+
var BATCH_TIMEOUT_BASE_MS = 3e4;
|
|
7231
|
+
var BATCH_TIMEOUT_PER_SLIDE_MS = 1e4;
|
|
7232
|
+
function collectVisualProps(root) {
|
|
7233
|
+
const found = [];
|
|
7234
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
7235
|
+
const visit = (node) => {
|
|
7236
|
+
if (!node || typeof node !== "object") return;
|
|
7237
|
+
if (seen.has(node)) return;
|
|
7238
|
+
seen.add(node);
|
|
7239
|
+
if (Array.isArray(node)) {
|
|
7240
|
+
for (const item of node) visit(item);
|
|
7241
|
+
return;
|
|
7242
|
+
}
|
|
7243
|
+
const obj = node;
|
|
7244
|
+
if (typeof obj.name === "string" && obj.enabled === false) return;
|
|
7245
|
+
if (obj.name === "visual" && obj.props && typeof obj.props === "object") {
|
|
7246
|
+
found.push(obj.props);
|
|
7247
|
+
return;
|
|
7248
|
+
}
|
|
7249
|
+
for (const value of Object.values(obj)) visit(value);
|
|
7250
|
+
};
|
|
7251
|
+
visit(root);
|
|
7252
|
+
return found;
|
|
7253
|
+
}
|
|
7254
|
+
function toErrorMessage(error) {
|
|
7255
|
+
return error instanceof Error ? error.message : String(error);
|
|
7256
|
+
}
|
|
7257
|
+
function* chunksOf(items, size) {
|
|
7258
|
+
for (let i = 0; i < items.length; i += size) yield items.slice(i, i + size);
|
|
7259
|
+
}
|
|
7260
|
+
function applyBatchResponse(chunk, response, map) {
|
|
7261
|
+
const results = response?.results;
|
|
7262
|
+
if (!Array.isArray(results) || results.length !== chunk.length) return false;
|
|
7263
|
+
const entries = [];
|
|
7264
|
+
for (let i = 0; i < chunk.length; i++) {
|
|
7265
|
+
const item = results[i];
|
|
7266
|
+
if (item && item.ok === true && typeof item.base64DataUri === "string" && item.base64DataUri.length > 0 && typeof item.width === "number" && typeof item.height === "number") {
|
|
7267
|
+
entries.push([
|
|
7268
|
+
chunk[i].key,
|
|
7269
|
+
{
|
|
7270
|
+
ok: true,
|
|
7271
|
+
base64DataUri: item.base64DataUri,
|
|
7272
|
+
width: item.width,
|
|
7273
|
+
height: item.height
|
|
7274
|
+
}
|
|
7275
|
+
]);
|
|
7276
|
+
} else if (item && item.ok === false && typeof item.error === "string") {
|
|
7277
|
+
entries.push([chunk[i].key, { ok: false, error: item.error }]);
|
|
7278
|
+
} else {
|
|
7279
|
+
return false;
|
|
7280
|
+
}
|
|
7281
|
+
}
|
|
7282
|
+
for (const [key, value] of entries) map.set(key, value);
|
|
7283
|
+
return true;
|
|
7284
|
+
}
|
|
7285
|
+
async function prerasterizeVisuals(root, serviceConfig, options = {}) {
|
|
7286
|
+
const map = /* @__PURE__ */ new Map();
|
|
7287
|
+
if (!isNodeEnvironment() && !serviceConfig?.renderBatch && !serviceConfig?.render) {
|
|
7288
|
+
return map;
|
|
7289
|
+
}
|
|
7290
|
+
const visuals = collectVisualProps(root);
|
|
7291
|
+
if (visuals.length === 0) return map;
|
|
7292
|
+
const targets = /* @__PURE__ */ new Map();
|
|
7293
|
+
for (const props of visuals) {
|
|
7294
|
+
try {
|
|
7295
|
+
const serverUrl2 = effectiveVisualServerUrl(props, serviceConfig);
|
|
7296
|
+
if (serverUrl2 !== void 0) continue;
|
|
7297
|
+
const presentation = buildVisualPresentation(props);
|
|
7298
|
+
const dpi = clampVisualDpi2(
|
|
7299
|
+
props.dpi ?? serviceConfig?.dpi ?? DEFAULT_VISUAL_DPI2
|
|
7300
|
+
);
|
|
7301
|
+
const key = visualRasterKey(presentation, dpi, serverUrl2);
|
|
7302
|
+
if (!targets.has(key)) targets.set(key, { key, presentation, dpi });
|
|
7303
|
+
} catch {
|
|
7304
|
+
continue;
|
|
7305
|
+
}
|
|
7306
|
+
}
|
|
7307
|
+
if (targets.size === 0) return map;
|
|
7308
|
+
const unique = [...targets.values()];
|
|
7309
|
+
const limit = createLimiter(
|
|
7310
|
+
Math.max(1, options.concurrency ?? DEFAULT_FALLBACK_CONCURRENCY)
|
|
7311
|
+
);
|
|
7312
|
+
const rasterizeIndividually = async (chunk) => {
|
|
7313
|
+
await Promise.all(
|
|
7314
|
+
chunk.map(
|
|
7315
|
+
(target) => limit(async () => {
|
|
7316
|
+
try {
|
|
7317
|
+
const result = await rasterizeVisualSlide(
|
|
7318
|
+
target.presentation,
|
|
7319
|
+
target.dpi,
|
|
7320
|
+
void 0,
|
|
7321
|
+
serviceConfig,
|
|
7322
|
+
options.baseDir
|
|
7323
|
+
);
|
|
7324
|
+
map.set(target.key, { ok: true, ...result });
|
|
7325
|
+
} catch (error) {
|
|
7326
|
+
map.set(target.key, { ok: false, error: toErrorMessage(error) });
|
|
7327
|
+
}
|
|
7328
|
+
})
|
|
7329
|
+
)
|
|
7330
|
+
);
|
|
7331
|
+
};
|
|
7332
|
+
if (serviceConfig?.renderBatch) {
|
|
7333
|
+
for (const chunk of chunksOf(unique, MAX_RASTERIZE_BATCH_SLIDES)) {
|
|
7334
|
+
try {
|
|
7335
|
+
const response = await serviceConfig.renderBatch({
|
|
7336
|
+
slides: chunk.map((target) => ({
|
|
7337
|
+
presentation: target.presentation,
|
|
7338
|
+
dpi: target.dpi
|
|
7339
|
+
})),
|
|
7340
|
+
...options.baseDir !== void 0 && { baseDir: options.baseDir }
|
|
7341
|
+
});
|
|
7342
|
+
if (!applyBatchResponse(chunk, response, map)) {
|
|
7343
|
+
throw new Error(
|
|
7344
|
+
"batch rasterizer returned a malformed result (expected index-aligned results[])"
|
|
7345
|
+
);
|
|
7346
|
+
}
|
|
7347
|
+
} catch (error) {
|
|
7348
|
+
if (serviceConfig.render || serviceConfig.serverUrl) {
|
|
7349
|
+
await rasterizeIndividually(chunk);
|
|
7350
|
+
} else {
|
|
7351
|
+
const message = toErrorMessage(error);
|
|
7352
|
+
for (const target of chunk) {
|
|
7353
|
+
map.set(target.key, { ok: false, error: message });
|
|
7354
|
+
}
|
|
7355
|
+
}
|
|
7356
|
+
}
|
|
7357
|
+
}
|
|
7358
|
+
return map;
|
|
7359
|
+
}
|
|
7360
|
+
if (serviceConfig?.render) {
|
|
7361
|
+
await rasterizeIndividually(unique);
|
|
7362
|
+
return map;
|
|
7363
|
+
}
|
|
7364
|
+
const serverUrl = resolveServiceUrl(
|
|
7365
|
+
void 0,
|
|
7366
|
+
serviceConfig?.serverUrl,
|
|
7367
|
+
DEFAULT_RASTERIZE_SERVER_URL
|
|
7368
|
+
);
|
|
7369
|
+
for (const chunk of chunksOf(unique, MAX_RASTERIZE_BATCH_SLIDES)) {
|
|
7370
|
+
let applied = false;
|
|
7371
|
+
try {
|
|
7372
|
+
const response = await postJsonToService({
|
|
7373
|
+
url: serverUrl,
|
|
7374
|
+
path: "/rasterize/batch",
|
|
7375
|
+
body: {
|
|
7376
|
+
slides: chunk.map((target) => ({
|
|
7377
|
+
presentation: target.presentation,
|
|
7378
|
+
dpi: target.dpi
|
|
7379
|
+
})),
|
|
7380
|
+
...options.baseDir !== void 0 && { baseDir: options.baseDir }
|
|
7381
|
+
},
|
|
7382
|
+
headers: serviceConfig?.headers,
|
|
7383
|
+
timeoutMs: BATCH_TIMEOUT_BASE_MS + BATCH_TIMEOUT_PER_SLIDE_MS * chunk.length,
|
|
7384
|
+
serviceLabel: "PPTX batch rasterization service",
|
|
7385
|
+
onUnreachable: (url, cause) => `PPTX rasterization service is not reachable at ${url}. Cause: ${cause}`
|
|
7386
|
+
});
|
|
7387
|
+
applied = applyBatchResponse(chunk, await response.json(), map);
|
|
7388
|
+
} catch {
|
|
7389
|
+
applied = false;
|
|
7390
|
+
}
|
|
7391
|
+
if (!applied) await rasterizeIndividually(chunk);
|
|
7392
|
+
}
|
|
7393
|
+
return map;
|
|
7394
|
+
}
|
|
7395
|
+
|
|
7396
|
+
// src/core/render.ts
|
|
7161
7397
|
function getAlignment3(alignment) {
|
|
7162
7398
|
switch (alignment) {
|
|
7163
7399
|
case "center":
|
|
@@ -7189,10 +7425,13 @@ function coreProperties(metadata) {
|
|
|
7189
7425
|
async function renderDocument(structure, layout, options) {
|
|
7190
7426
|
return runWithGenerationDate(
|
|
7191
7427
|
structure.metadata.date,
|
|
7192
|
-
() =>
|
|
7193
|
-
|
|
7194
|
-
|
|
7195
|
-
|
|
7428
|
+
() => runWithBaseDir(
|
|
7429
|
+
options?.baseDir,
|
|
7430
|
+
() => globalBookmarkRegistry.runScoped(
|
|
7431
|
+
() => globalRevisionIdRegistry.runScoped(
|
|
7432
|
+
() => globalNumberingRegistry.runScoped(
|
|
7433
|
+
() => renderDocumentScoped(structure, layout, options)
|
|
7434
|
+
)
|
|
7196
7435
|
)
|
|
7197
7436
|
)
|
|
7198
7437
|
)
|
|
@@ -7211,6 +7450,21 @@ async function renderDocumentScoped(structure, layout, options) {
|
|
|
7211
7450
|
structure.themeName
|
|
7212
7451
|
);
|
|
7213
7452
|
context.services = options?.services;
|
|
7453
|
+
try {
|
|
7454
|
+
const visualRasterResults = await prerasterizeVisuals(
|
|
7455
|
+
layout.sections,
|
|
7456
|
+
options?.services?.pptx,
|
|
7457
|
+
{ baseDir: getBaseDir() }
|
|
7458
|
+
);
|
|
7459
|
+
if (visualRasterResults.size > 0) {
|
|
7460
|
+
context.visualRasterResults = visualRasterResults;
|
|
7461
|
+
}
|
|
7462
|
+
} catch (error) {
|
|
7463
|
+
console.warn(
|
|
7464
|
+
"[core-docx] Visual pre-rasterization failed; falling back to per-visual rasterization:",
|
|
7465
|
+
error instanceof Error ? error.message : error
|
|
7466
|
+
);
|
|
7467
|
+
}
|
|
7214
7468
|
let sectionBookmarkCounter = 0;
|
|
7215
7469
|
let previousHeader = void 0;
|
|
7216
7470
|
let previousFooter = void 0;
|
|
@@ -7787,10 +8041,10 @@ function normalizeDocument(document) {
|
|
|
7787
8041
|
|
|
7788
8042
|
// src/json/filesystem.ts
|
|
7789
8043
|
import { promises as fs3 } from "fs";
|
|
7790
|
-
import { join, resolve, isAbsolute } from "path";
|
|
8044
|
+
import { join, resolve as resolve2, isAbsolute as isAbsolute2 } from "path";
|
|
7791
8045
|
async function loadJsonDefinition(filePath) {
|
|
7792
8046
|
try {
|
|
7793
|
-
const absolutePath =
|
|
8047
|
+
const absolutePath = isAbsolute2(filePath) ? filePath : resolve2(filePath);
|
|
7794
8048
|
await fs3.access(absolutePath);
|
|
7795
8049
|
const fileContent = await fs3.readFile(absolutePath, "utf-8");
|
|
7796
8050
|
return parseJsonWithLineNumbers(fileContent);
|
|
@@ -7865,7 +8119,8 @@ async function generateDocument(document, options) {
|
|
|
7865
8119
|
options?.services,
|
|
7866
8120
|
options?.fonts,
|
|
7867
8121
|
options?.warnings,
|
|
7868
|
-
resolveGenerationDate(options)
|
|
8122
|
+
resolveGenerationDate(options),
|
|
8123
|
+
options?.baseDir
|
|
7869
8124
|
);
|
|
7870
8125
|
}
|
|
7871
8126
|
async function generateFromConfig(props, components, options) {
|
|
@@ -7876,7 +8131,7 @@ async function generateFromConfig(props, components, options) {
|
|
|
7876
8131
|
};
|
|
7877
8132
|
return await generateDocument(reportComponent, options);
|
|
7878
8133
|
}
|
|
7879
|
-
async function generateDocumentWithCustomThemes(documentIn, customThemes, services, fonts, warnings, generationDate) {
|
|
8134
|
+
async function generateDocumentWithCustomThemes(documentIn, customThemes, services, fonts, warnings, generationDate, baseDir) {
|
|
7880
8135
|
const { document, theme, themeName } = resolveThemeContext(documentIn, {
|
|
7881
8136
|
customThemes,
|
|
7882
8137
|
fonts,
|
|
@@ -7892,7 +8147,8 @@ async function generateDocumentWithCustomThemes(documentIn, customThemes, servic
|
|
|
7892
8147
|
const layout = applyLayout(structure.sections, theme, themeName);
|
|
7893
8148
|
const renderedDocument = await renderDocument(structure, layout, {
|
|
7894
8149
|
bypassCache: false,
|
|
7895
|
-
services
|
|
8150
|
+
services,
|
|
8151
|
+
baseDir
|
|
7896
8152
|
});
|
|
7897
8153
|
return renderedDocument;
|
|
7898
8154
|
}
|
|
@@ -7937,7 +8193,8 @@ async function generateDocumentFromJson(jsonConfig, options) {
|
|
|
7937
8193
|
options?.services,
|
|
7938
8194
|
options?.fonts,
|
|
7939
8195
|
options?.warnings,
|
|
7940
|
-
resolveGenerationDate(options)
|
|
8196
|
+
resolveGenerationDate(options),
|
|
8197
|
+
options?.baseDir
|
|
7941
8198
|
);
|
|
7942
8199
|
}
|
|
7943
8200
|
function validateJsonSchema(jsonConfig) {
|
|
@@ -7953,7 +8210,10 @@ async function generateAndSaveFromJson(jsonConfig, filename, options) {
|
|
|
7953
8210
|
}
|
|
7954
8211
|
async function generateDocumentFromFile(filePath, options) {
|
|
7955
8212
|
const jsonDefinition = await loadJsonDefinition(filePath);
|
|
7956
|
-
return await generateDocumentFromJson(jsonDefinition,
|
|
8213
|
+
return await generateDocumentFromJson(jsonDefinition, {
|
|
8214
|
+
baseDir: dirname(resolve3(filePath)),
|
|
8215
|
+
...options
|
|
8216
|
+
});
|
|
7957
8217
|
}
|
|
7958
8218
|
async function generateBufferFromFile(filePath, options) {
|
|
7959
8219
|
const document = await generateDocumentFromFile(filePath, options);
|
|
@@ -7988,32 +8248,41 @@ var DocumentGenerator = {
|
|
|
7988
8248
|
|
|
7989
8249
|
// src/core/flattenVisuals.ts
|
|
7990
8250
|
import {
|
|
7991
|
-
clampVisualDpi as
|
|
7992
|
-
DEFAULT_VISUAL_DPI as
|
|
8251
|
+
clampVisualDpi as clampVisualDpi3,
|
|
8252
|
+
DEFAULT_VISUAL_DPI as DEFAULT_VISUAL_DPI3
|
|
7993
8253
|
} from "@json-to-office/shared";
|
|
7994
8254
|
var DEFAULT_CONCURRENCY = 4;
|
|
7995
|
-
function createLimiter(max) {
|
|
7996
|
-
let active = 0;
|
|
7997
|
-
const queue = [];
|
|
7998
|
-
const release = () => {
|
|
7999
|
-
active--;
|
|
8000
|
-
queue.shift()?.();
|
|
8001
|
-
};
|
|
8002
|
-
return async function limit(fn) {
|
|
8003
|
-
if (active >= max)
|
|
8004
|
-
await new Promise((resolve2) => queue.push(resolve2));
|
|
8005
|
-
active++;
|
|
8006
|
-
try {
|
|
8007
|
-
return await fn();
|
|
8008
|
-
} finally {
|
|
8009
|
-
release();
|
|
8010
|
-
}
|
|
8011
|
-
};
|
|
8012
|
-
}
|
|
8013
8255
|
async function flattenVisuals(doc, options) {
|
|
8256
|
+
let rasterize = options.rasterize;
|
|
8257
|
+
if (options.rasterizeBatch) {
|
|
8258
|
+
const preRasterized = await prerasterizeVisuals(
|
|
8259
|
+
doc,
|
|
8260
|
+
{
|
|
8261
|
+
render: options.rasterize,
|
|
8262
|
+
renderBatch: options.rasterizeBatch,
|
|
8263
|
+
dpi: options.dpi
|
|
8264
|
+
},
|
|
8265
|
+
{ baseDir: options.baseDir, concurrency: options.concurrency }
|
|
8266
|
+
).catch(() => /* @__PURE__ */ new Map());
|
|
8267
|
+
rasterize = async (request) => {
|
|
8268
|
+
const hit = preRasterized.get(
|
|
8269
|
+
visualRasterKey(request.presentation, request.dpi)
|
|
8270
|
+
);
|
|
8271
|
+
if (hit) {
|
|
8272
|
+
if (!hit.ok) throw new Error(hit.error);
|
|
8273
|
+
return {
|
|
8274
|
+
base64DataUri: hit.base64DataUri,
|
|
8275
|
+
width: hit.width,
|
|
8276
|
+
height: hit.height
|
|
8277
|
+
};
|
|
8278
|
+
}
|
|
8279
|
+
return options.rasterize(request);
|
|
8280
|
+
};
|
|
8281
|
+
}
|
|
8014
8282
|
const ctx = {
|
|
8015
|
-
rasterize
|
|
8283
|
+
rasterize,
|
|
8016
8284
|
dpi: options.dpi,
|
|
8285
|
+
baseDir: options.baseDir,
|
|
8017
8286
|
limit: createLimiter(
|
|
8018
8287
|
Math.max(1, options.concurrency ?? DEFAULT_CONCURRENCY)
|
|
8019
8288
|
)
|
|
@@ -8022,9 +8291,13 @@ async function flattenVisuals(doc, options) {
|
|
|
8022
8291
|
}
|
|
8023
8292
|
async function rasterizeVisual(obj, ctx) {
|
|
8024
8293
|
const props = obj.props;
|
|
8025
|
-
const dpi =
|
|
8294
|
+
const dpi = clampVisualDpi3(props.dpi ?? ctx.dpi ?? DEFAULT_VISUAL_DPI3);
|
|
8026
8295
|
const result = await ctx.limit(
|
|
8027
|
-
() => ctx.rasterize({
|
|
8296
|
+
() => ctx.rasterize({
|
|
8297
|
+
presentation: buildVisualPresentation(props),
|
|
8298
|
+
dpi,
|
|
8299
|
+
baseDir: ctx.baseDir
|
|
8300
|
+
})
|
|
8028
8301
|
);
|
|
8029
8302
|
const image = {
|
|
8030
8303
|
name: "image",
|
|
@@ -8706,7 +8979,8 @@ function createBuilderImpl(state) {
|
|
|
8706
8979
|
fonts: state.fonts,
|
|
8707
8980
|
validation: state.validation,
|
|
8708
8981
|
deterministic: state.deterministic,
|
|
8709
|
-
generatedAt: state.generatedAt
|
|
8982
|
+
generatedAt: state.generatedAt,
|
|
8983
|
+
baseDir: state.baseDir
|
|
8710
8984
|
};
|
|
8711
8985
|
return createBuilderImpl(
|
|
8712
8986
|
newState
|
|
@@ -8805,7 +9079,8 @@ function createBuilderImpl(state) {
|
|
|
8805
9079
|
const layout = applyLayout(structure.sections, modedTheme, themeName);
|
|
8806
9080
|
const generatedDocument = await renderDocument(structure, layout, {
|
|
8807
9081
|
services: state.services,
|
|
8808
|
-
bypassCache: !state.enableCache
|
|
9082
|
+
bypassCache: !state.enableCache,
|
|
9083
|
+
baseDir: options?.baseDir ?? state.baseDir
|
|
8809
9084
|
});
|
|
8810
9085
|
const preservedDefinition = preserveSet ? {
|
|
8811
9086
|
...modedRoot,
|
|
@@ -8935,7 +9210,8 @@ function createDocumentGenerator(options) {
|
|
|
8935
9210
|
fonts: options.fonts,
|
|
8936
9211
|
validation: options.validation,
|
|
8937
9212
|
deterministic: options.deterministic ?? true,
|
|
8938
|
-
generatedAt: options.generatedAt
|
|
9213
|
+
generatedAt: options.generatedAt,
|
|
9214
|
+
baseDir: options.baseDir
|
|
8939
9215
|
};
|
|
8940
9216
|
return createBuilderImpl(initialState);
|
|
8941
9217
|
}
|