@json-to-office/core-docx 0.35.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.
@@ -1 +1 @@
1
- {"version":3,"file":"createDocumentGenerator.d.ts","sourceRoot":"","sources":["../../src/plugin/createDocumentGenerator.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAK7C,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAI9E,OAAO,KAAK,EAEV,wBAAwB,EAQxB,2BAA2B,EAC5B,MAAM,SAAS,CAAC;AAmBjB;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,kEAAkE;IAClE,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,kFAAkF;IAClF,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAC3C,4CAA4C;IAC5C,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,2BAA2B;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,qEAAqE;IACrE,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,oFAAoF;IACpF,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB;;;;OAIG;IACH,UAAU,CAAC,EAAE,2BAA2B,CAAC;IACzC,gFAAgF;IAChF,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,sDAAsD;IACtD,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAguBD;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,wBAAwB,GAChC,wBAAwB,CAAC,SAAS,EAAE,CAAC,CAiBvC"}
1
+ {"version":3,"file":"createDocumentGenerator.d.ts","sourceRoot":"","sources":["../../src/plugin/createDocumentGenerator.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAK7C,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAI9E,OAAO,KAAK,EAEV,wBAAwB,EAQxB,2BAA2B,EAC5B,MAAM,SAAS,CAAC;AAmBjB;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,kEAAkE;IAClE,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,kFAAkF;IAClF,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAC3C,4CAA4C;IAC5C,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,2BAA2B;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,qEAAqE;IACrE,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,oFAAoF;IACpF,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB;;;;OAIG;IACH,UAAU,CAAC,EAAE,2BAA2B,CAAC;IACzC,gFAAgF;IAChF,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,sDAAsD;IACtD,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAiuBD;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,wBAAwB,GAChC,wBAAwB,CAAC,SAAS,EAAE,CAAC,CAiBvC"}
@@ -2146,10 +2146,68 @@ function resolveFromBaseDir(filePath) {
2146
2146
  if (!base || isAbsolute(filePath)) return filePath;
2147
2147
  return resolve(base, filePath);
2148
2148
  }
2149
+ var warningsStorage = new AsyncLocalStorage();
2150
+ function runWithWarnings(warnings, callback) {
2151
+ return warnings === void 0 ? callback() : warningsStorage.run(warnings, callback);
2152
+ }
2153
+ function reportWarning(component, code, message, context) {
2154
+ const warnings = warningsStorage.getStore();
2155
+ if (warnings) {
2156
+ warnings.push({
2157
+ component,
2158
+ message,
2159
+ severity: "warning",
2160
+ context: { code, ...context }
2161
+ });
2162
+ return;
2163
+ }
2164
+ console.warn(`[json-to-docx] [${code}] ${message}`);
2165
+ }
2149
2166
 
2150
2167
  // src/utils/imageUtils.ts
2151
2168
  init_widthUtils();
2152
2169
  import { ImageRun } from "docx";
2170
+ var SVG_RASTER_SCALE = 3;
2171
+ var SVG_MAX_EDGE_PX = 4096;
2172
+ var SVG_MIN_EDGE_PX = 16;
2173
+ var resvgModule;
2174
+ function loadResvg() {
2175
+ resvgModule ??= import("@resvg/resvg-js");
2176
+ return resvgModule;
2177
+ }
2178
+ function toRasterPx(px) {
2179
+ return Math.min(
2180
+ SVG_MAX_EDGE_PX,
2181
+ Math.max(SVG_MIN_EDGE_PX, Math.round(px * SVG_RASTER_SCALE))
2182
+ );
2183
+ }
2184
+ async function rasterizeSvgFallback(svg, transformation) {
2185
+ let Resvg;
2186
+ try {
2187
+ ({ Resvg } = await loadResvg());
2188
+ } catch (error) {
2189
+ reportWarning(
2190
+ "image",
2191
+ "IMAGE_SVG_RASTER_FAILED",
2192
+ `Could not load the SVG rasterizer, so inline SVG keeps a fallback that only Word 2016+ can draw: ${String(error)}`
2193
+ );
2194
+ return void 0;
2195
+ }
2196
+ try {
2197
+ const markup = svg.toString("utf-8");
2198
+ const probeImage = new Resvg(markup);
2199
+ const wide = probeImage.width / probeImage.height > transformation.width / transformation.height;
2200
+ const fitTo = wide ? { mode: "height", value: toRasterPx(transformation.height) } : { mode: "width", value: toRasterPx(transformation.width) };
2201
+ return Buffer.from(new Resvg(markup, { fitTo }).render().asPng());
2202
+ } catch (error) {
2203
+ reportWarning(
2204
+ "image",
2205
+ "IMAGE_SVG_RASTER_FAILED",
2206
+ `Could not rasterize inline SVG, so its fallback only renders in Word 2016+: ${String(error)}`
2207
+ );
2208
+ return void 0;
2209
+ }
2210
+ }
2153
2211
  function parseWidthValue(width, availableWidthPx) {
2154
2212
  if (typeof width === "number") {
2155
2213
  return width;
@@ -2259,17 +2317,18 @@ function detectImageType(imagePath, responseContentType) {
2259
2317
  if (typeFromExtension) return typeFromExtension;
2260
2318
  return "png";
2261
2319
  }
2262
- function createTypedImageRun(opts) {
2320
+ async function createTypedImageRun(opts) {
2263
2321
  const base = {
2264
2322
  data: opts.data,
2265
2323
  transformation: opts.transformation,
2266
2324
  ...opts.floating && { floating: opts.floating }
2267
2325
  };
2268
2326
  if (opts.type === "svg") {
2327
+ const raster = await rasterizeSvgFallback(opts.data, opts.transformation);
2269
2328
  return new ImageRun({
2270
2329
  type: "svg",
2271
2330
  ...base,
2272
- fallback: { type: "png", data: opts.data }
2331
+ fallback: { type: "png", data: raster ?? opts.data }
2273
2332
  });
2274
2333
  }
2275
2334
  return new ImageRun({ type: opts.type, ...base });
@@ -4428,7 +4487,7 @@ async function createImage(path3, theme, themeName, options = {}) {
4428
4487
  const { mapFloatingOptions: mapFloatingOptions2 } = await Promise.resolve().then(() => (init_docxImagePositioning(), docxImagePositioning_exports));
4429
4488
  const floating = isFloating ? mapFloatingOptions2(options.floating, theme, themeName) : void 0;
4430
4489
  const imageType = detectImageType(imagePath, responseContentType);
4431
- const imageRun = createTypedImageRun({
4490
+ const imageRun = await createTypedImageRun({
4432
4491
  type: imageType,
4433
4492
  data: imageBuffer,
4434
4493
  transformation: { width: dimensions.width, height: dimensions.height },
@@ -4973,7 +5032,7 @@ async function createTable(columns, tableConfig, theme, themeName, _options = {}
4973
5032
  // fallback height
4974
5033
  );
4975
5034
  const imgType = detectImageType(imageSource, imageResult.contentType);
4976
- const imageRun = createTypedImageRun({
5035
+ const imageRun = await createTypedImageRun({
4977
5036
  type: imgType,
4978
5037
  data: imageResult.buffer,
4979
5038
  transformation: {
@@ -8224,23 +8283,26 @@ function coreProperties(metadata) {
8224
8283
  async function renderDocument(structure, layout, options) {
8225
8284
  return runWithGenerationDate(
8226
8285
  structure.metadata.date,
8227
- () => runWithBaseDir(
8228
- options?.baseDir,
8229
- () => globalBookmarkRegistry.runScoped(
8230
- () => globalRevisionIdRegistry.runScoped(
8231
- () => globalNumberingRegistry.runScoped(
8232
- () => globalSectionBookmarkRegistry.runScoped(
8233
- () => (
8234
- // Comment ids are a separate OOXML namespace from w:ins/w:del,
8235
- // but they need the same per-render isolation: outside this nest
8236
- // concurrent generations would interleave counters and an anchor
8237
- // would point at another document's comment body.
8238
- globalCommentRegistry.runScoped(
8239
- () => (
8240
- // Footnote ids are document-scoped too: a reference resolved
8241
- // against another render's counter points at the wrong body.
8242
- globalNoteRegistry.runScoped(
8243
- () => renderDocumentScoped(structure, layout, options)
8286
+ () => runWithWarnings(
8287
+ options?.warnings,
8288
+ () => runWithBaseDir(
8289
+ options?.baseDir,
8290
+ () => globalBookmarkRegistry.runScoped(
8291
+ () => globalRevisionIdRegistry.runScoped(
8292
+ () => globalNumberingRegistry.runScoped(
8293
+ () => globalSectionBookmarkRegistry.runScoped(
8294
+ () => (
8295
+ // Comment ids are a separate OOXML namespace from w:ins/w:del,
8296
+ // but they need the same per-render isolation: outside this nest
8297
+ // concurrent generations would interleave counters and an anchor
8298
+ // would point at another document's comment body.
8299
+ globalCommentRegistry.runScoped(
8300
+ () => (
8301
+ // Footnote ids are document-scoped too: a reference resolved
8302
+ // against another render's counter points at the wrong body.
8303
+ globalNoteRegistry.runScoped(
8304
+ () => renderDocumentScoped(structure, layout, options)
8305
+ )
8244
8306
  )
8245
8307
  )
8246
8308
  )
@@ -8460,7 +8522,7 @@ async function renderHeaderFooterComponents(components, theme, themeName, contex
8460
8522
  themeName
8461
8523
  );
8462
8524
  const imageType = detectImageType(imageSource, responseContentType);
8463
- const imageRun = createTypedImageRun({
8525
+ const imageRun = await createTypedImageRun({
8464
8526
  type: imageType,
8465
8527
  data: imageBuffer,
8466
8528
  transformation: {
@@ -9098,6 +9160,7 @@ function createBuilderImpl(state) {
9098
9160
  services: state.services,
9099
9161
  bypassCache: !state.enableCache,
9100
9162
  baseDir: options?.baseDir ?? state.baseDir,
9163
+ warnings,
9101
9164
  ...visualFonts.length > 0 && { visualFonts }
9102
9165
  });
9103
9166
  const preservedDefinition = preserveSet ? {