@json-to-office/core-docx 5.3.0 → 6.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.
@@ -1038,7 +1038,7 @@ var init_vermilion_docx_theme = __esm({
1038
1038
  },
1039
1039
  actionTitle: {
1040
1040
  type: "display",
1041
- color: "primary"
1041
+ color: "accent"
1042
1042
  },
1043
1043
  keyTakeaways: {
1044
1044
  type: "label",
@@ -1067,7 +1067,7 @@ var init_vermilion_docx_theme = __esm({
1067
1067
  },
1068
1068
  cover: {
1069
1069
  type: "display",
1070
- color: "primary",
1070
+ color: "accent",
1071
1071
  rule: {
1072
1072
  weightPt: 4,
1073
1073
  color: "accent"
@@ -5433,12 +5433,15 @@ function applyThemeOverrides(theme, overrides) {
5433
5433
  init_defaults();
5434
5434
  import {
5435
5435
  designCanvas,
5436
+ resolveMotif,
5436
5437
  resolveTypeRoles,
5437
5438
  validateDesignColors
5438
5439
  } from "@json-to-office/shared";
5439
5440
  function resolveDocxDesignSystem(theme) {
5440
5441
  validateDesignColors(theme, getThemeColors(theme));
5441
- if (!theme.typography && !theme.spacing) return theme;
5442
+ const motif = resolveMotif(theme.motif);
5443
+ if (!theme.typography && !theme.spacing)
5444
+ return motif === theme.motif ? theme : withMotif(theme, motif);
5442
5445
  const canvas = designCanvas("docx", theme.page.size);
5443
5446
  const roles = resolveTypeRoles(theme, canvas, theme.fonts.body.size ?? 11);
5444
5447
  const styles = { ...theme.styles };
@@ -5478,7 +5481,7 @@ function resolveDocxDesignSystem(theme) {
5478
5481
  const space = theme.spacing?.canvas?.[canvas];
5479
5482
  const safe = space?.safeAreaIn;
5480
5483
  return {
5481
- ...theme,
5484
+ ...withMotif(theme, motif),
5482
5485
  styles,
5483
5486
  page: {
5484
5487
  ...theme.page,
@@ -5495,6 +5498,12 @@ function resolveDocxDesignSystem(theme) {
5495
5498
  }
5496
5499
  };
5497
5500
  }
5501
+ function withMotif(theme, motif) {
5502
+ if (motif !== void 0) return { ...theme, motif };
5503
+ const rest = { ...theme };
5504
+ delete rest.motif;
5505
+ return rest;
5506
+ }
5498
5507
 
5499
5508
  // src/core/generationContext.ts
5500
5509
  function defaultNamedThemeLookup(themeName, customThemes, warnings) {
@@ -5771,7 +5780,10 @@ import {
5771
5780
  import {
5772
5781
  clampVisualDpi,
5773
5782
  DEFAULT_VISUAL_DPI,
5774
- MAX_RASTERIZE_BATCH_SLIDES
5783
+ MAX_RASTERIZE_BATCH_SLIDES,
5784
+ createLimiter,
5785
+ resolveServiceUrl as resolveServiceUrl2,
5786
+ postJsonToService as postJsonToService2
5775
5787
  } from "@json-to-office/shared";
5776
5788
  import {
5777
5789
  isNativeVisualProps
@@ -5785,54 +5797,8 @@ function isNodeEnvironment() {
5785
5797
  return typeof process !== "undefined" && process.versions != null && process.versions.node != null && typeof process.versions.node === "string";
5786
5798
  }
5787
5799
 
5788
- // src/utils/serviceClient.ts
5789
- var DEFAULT_TIMEOUT_MS = 3e4;
5790
- function resolveServiceUrl(propsUrl, servicesUrl, defaultUrl) {
5791
- const raw = (propsUrl || servicesUrl || defaultUrl).trim();
5792
- const withScheme = /^https?:\/\//i.test(raw) ? raw : `http://${raw}`;
5793
- return withScheme.replace(/\/+$/, "");
5794
- }
5795
- var SERVICE_UNAVAILABLE_CODE = "SERVICE_UNAVAILABLE";
5796
- function serviceUnavailable(message) {
5797
- return Object.assign(new Error(message), { code: SERVICE_UNAVAILABLE_CODE });
5798
- }
5799
- async function postJsonToService(opts) {
5800
- const resolvedHeaders = typeof opts.headers === "function" ? await opts.headers(opts.body) : opts.headers;
5801
- const headers = {
5802
- "Content-Type": "application/json",
5803
- ...resolvedHeaders
5804
- };
5805
- const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
5806
- const controller = new AbortController();
5807
- const timer = setTimeout(() => controller.abort(), timeoutMs);
5808
- let response;
5809
- try {
5810
- response = await fetch(`${opts.url}${opts.path}`, {
5811
- method: "POST",
5812
- headers,
5813
- body: JSON.stringify(opts.body),
5814
- signal: controller.signal
5815
- });
5816
- } catch (error) {
5817
- if (error?.name === "AbortError") {
5818
- throw serviceUnavailable(
5819
- `${opts.serviceLabel} timed out after ${timeoutMs}ms at ${opts.url}.`
5820
- );
5821
- }
5822
- const cause = error instanceof Error ? error.message : String(error);
5823
- throw serviceUnavailable(opts.onUnreachable(opts.url, cause));
5824
- } finally {
5825
- clearTimeout(timer);
5826
- }
5827
- if (!response.ok) {
5828
- throw new Error(
5829
- `${opts.serviceLabel} returned ${response.status}: ${response.statusText}`
5830
- );
5831
- }
5832
- return response;
5833
- }
5834
-
5835
5800
  // src/components/visual.ts
5801
+ import { resolveServiceUrl, postJsonToService } from "@json-to-office/shared";
5836
5802
  var DEFAULT_RASTERIZE_SERVER_URL = "http://localhost:7802";
5837
5803
  var PIXELS_PER_INCH = 96;
5838
5804
  function buildVisualPresentation(props) {
@@ -5934,26 +5900,6 @@ Cause: ${cause}`
5934
5900
  return result;
5935
5901
  }
5936
5902
 
5937
- // src/utils/promiseLimiter.ts
5938
- function createLimiter(max) {
5939
- let active = 0;
5940
- const queue = [];
5941
- const release = () => {
5942
- active--;
5943
- queue.shift()?.();
5944
- };
5945
- return async function limit(fn) {
5946
- while (active >= max)
5947
- await new Promise((resolve2) => queue.push(resolve2));
5948
- active++;
5949
- try {
5950
- return await fn();
5951
- } finally {
5952
- release();
5953
- }
5954
- };
5955
- }
5956
-
5957
5903
  // src/core/prerasterizeVisuals.ts
5958
5904
  var DEFAULT_FALLBACK_CONCURRENCY = 4;
5959
5905
  var BATCH_TIMEOUT_BASE_MS = 3e4;
@@ -6122,7 +6068,7 @@ async function prerasterizeVisuals(root, serviceConfig, options = {}) {
6122
6068
  await rasterizeIndividually(unique);
6123
6069
  return map;
6124
6070
  }
6125
- const serverUrl = resolveServiceUrl(
6071
+ const serverUrl = resolveServiceUrl2(
6126
6072
  void 0,
6127
6073
  serviceConfig?.serverUrl,
6128
6074
  DEFAULT_RASTERIZE_SERVER_URL
@@ -6130,7 +6076,7 @@ async function prerasterizeVisuals(root, serviceConfig, options = {}) {
6130
6076
  const postBatch = async (chunk, fonts) => {
6131
6077
  let response;
6132
6078
  try {
6133
- response = await postJsonToService({
6079
+ response = await postJsonToService2({
6134
6080
  url: serverUrl,
6135
6081
  path: "/rasterize/batch",
6136
6082
  body: {
@@ -6256,7 +6202,8 @@ function containsComponent(root, name) {
6256
6202
  // src/core/desugarExternals.ts
6257
6203
  import {
6258
6204
  clampVisualDpi as clampVisualDpi2,
6259
- DEFAULT_VISUAL_DPI as DEFAULT_VISUAL_DPI2
6205
+ DEFAULT_VISUAL_DPI as DEFAULT_VISUAL_DPI2,
6206
+ limitChartRequest
6260
6207
  } from "@json-to-office/shared";
6261
6208
  import {
6262
6209
  isNativeVisualProps as isNativeVisualProps2
@@ -6272,30 +6219,42 @@ import {
6272
6219
  chartPointsPerPixel,
6273
6220
  POINTS_PER_PIXEL_96DPI,
6274
6221
  withChartFontFaceCss,
6275
- withChartTypography
6222
+ withChartTypography,
6223
+ resolveServiceUrl as resolveServiceUrl3,
6224
+ postJsonToService as postJsonToService3,
6225
+ chartRequestKey,
6226
+ dedupeChartRequest,
6227
+ recordChartRetry
6276
6228
  } from "@json-to-office/shared";
6277
6229
  var DEFAULT_EXPORT_SERVER_URL = "http://localhost:7801";
6230
+ function effectiveChartServerUrl(props, servicesConfig) {
6231
+ return resolveServiceUrl3(
6232
+ props.serverUrl,
6233
+ servicesConfig?.serverUrl,
6234
+ DEFAULT_EXPORT_SERVER_URL
6235
+ );
6236
+ }
6278
6237
  function assertExportServerAllowed(serverUrl, servicesConfig, warnings) {
6279
6238
  const notice = remoteExportNotice(serverUrl, servicesConfig?.allowRemote);
6280
- if (notice)
6281
- warnings?.push({
6282
- component: "highcharts",
6283
- severity: "warning",
6284
- message: notice,
6285
- context: { code: REMOTE_EXPORT_WARNING, serverUrl }
6286
- });
6239
+ if (!notice || !warnings) return;
6240
+ const alreadySaid = warnings.some(
6241
+ (warning) => warning.context?.code === REMOTE_EXPORT_WARNING && warning.context?.serverUrl === serverUrl
6242
+ );
6243
+ if (alreadySaid) return;
6244
+ warnings.push({
6245
+ component: "highcharts",
6246
+ severity: "warning",
6247
+ message: notice,
6248
+ context: { code: REMOTE_EXPORT_WARNING, serverUrl }
6249
+ });
6287
6250
  }
6288
- async function generateChart(config, servicesConfig, warnings) {
6251
+ async function generateChart(config, servicesConfig, warnings, cache) {
6289
6252
  if (!isNodeEnvironment()) {
6290
6253
  throw new Error(
6291
6254
  "Highcharts export server requires a Node.js environment. Chart generation is not available in browser environments."
6292
6255
  );
6293
6256
  }
6294
- const serverUrl = resolveServiceUrl(
6295
- config.serverUrl,
6296
- servicesConfig?.serverUrl,
6297
- DEFAULT_EXPORT_SERVER_URL
6298
- );
6257
+ const serverUrl = effectiveChartServerUrl(config, servicesConfig);
6299
6258
  assertExportServerAllowed(serverUrl, servicesConfig, warnings);
6300
6259
  const requestBody = {
6301
6260
  infile: config.options,
@@ -6306,11 +6265,21 @@ async function generateChart(config, servicesConfig, warnings) {
6306
6265
  // byte-identical to before for callers that omit it.
6307
6266
  ...config.resources ? { resources: config.resources } : {}
6308
6267
  };
6309
- const response = await postJsonToService({
6268
+ return dedupeChartRequest(
6269
+ cache,
6270
+ chartRequestKey(serverUrl, requestBody),
6271
+ () => postChart(serverUrl, requestBody, config, servicesConfig)
6272
+ );
6273
+ }
6274
+ async function postChart(serverUrl, requestBody, config, servicesConfig) {
6275
+ const response = await postJsonToService3({
6310
6276
  url: serverUrl,
6311
6277
  path: "/export",
6312
6278
  body: requestBody,
6313
6279
  headers: servicesConfig?.headers,
6280
+ timeoutMs: servicesConfig?.timeoutMs,
6281
+ retries: servicesConfig?.retries,
6282
+ onRetry: recordChartRetry,
6314
6283
  serviceLabel: "Highcharts export server",
6315
6284
  onUnreachable: (url, cause) => `Highcharts Export Server is not running at ${url}. Start it with: npx highcharts-export-server --enableServer true
6316
6285
  Cause: ${cause}`
@@ -6409,13 +6378,13 @@ function withChartFontFaces(config, theme, faces) {
6409
6378
  theme.fonts.heading.family
6410
6379
  ]);
6411
6380
  }
6412
- async function renderChartToImageProps(props, theme, servicesConfig, chartFonts, warnings) {
6381
+ async function renderChartToImageProps(props, theme, servicesConfig, chartFonts, warnings, cache) {
6413
6382
  const config = withChartFontFaces(
6414
6383
  withThemeTypography(withThemeColors(props, theme), theme),
6415
6384
  theme,
6416
6385
  chartFonts
6417
6386
  );
6418
- const chart = await generateChart(config, servicesConfig, warnings);
6387
+ const chart = await generateChart(config, servicesConfig, warnings, cache);
6419
6388
  const hasConfigDimensions = config.width !== void 0 || config.height !== void 0;
6420
6389
  return {
6421
6390
  base64: chart.base64DataUri,
@@ -6435,6 +6404,7 @@ async function desugarExternals(document, options) {
6435
6404
  ...options.visualFonts ? { fonts: options.visualFonts } : {}
6436
6405
  }
6437
6406
  ).catch(() => /* @__PURE__ */ new Map());
6407
+ const chartCache = /* @__PURE__ */ new Map();
6438
6408
  return transformComponents(document, async (node) => {
6439
6409
  if (node.enabled === false) return void 0;
6440
6410
  if (node.name === "visual") {
@@ -6449,14 +6419,21 @@ async function desugarExternals(document, options) {
6449
6419
  });
6450
6420
  }
6451
6421
  if (node.name === "highcharts") {
6422
+ const props = node.props;
6423
+ const chartConfig = options.services?.highcharts;
6452
6424
  return withNodeIdentity(node, {
6453
6425
  name: "image",
6454
- props: await renderChartToImageProps(
6455
- node.props,
6456
- options.theme,
6457
- options.services?.highcharts,
6458
- options.chartFonts,
6459
- options.warnings
6426
+ props: await limitChartRequest(
6427
+ effectiveChartServerUrl(props, chartConfig),
6428
+ chartConfig?.concurrency,
6429
+ () => renderChartToImageProps(
6430
+ props,
6431
+ options.theme,
6432
+ chartConfig,
6433
+ options.chartFonts,
6434
+ options.warnings,
6435
+ chartCache
6436
+ )
6460
6437
  )
6461
6438
  });
6462
6439
  }
@@ -9705,7 +9682,7 @@ function compileParagraph(component, scope) {
9705
9682
  MARKDOWN_LIST_LEVELS[markdown.type]
9706
9683
  );
9707
9684
  }
9708
- const styleId = paragraphStyleId(props.themeStyle);
9685
+ const styleId = definedParagraphStyleId(props.themeStyle, ctx.theme);
9709
9686
  if (styleId && !ctx.styleIds.has(styleId)) ctx.styleIds.add(styleId);
9710
9687
  const children = compileRuns(props, text, ctx, path3);
9711
9688
  const bookmarkName = typeof props.id === "string" ? props.id : void 0;
@@ -11050,6 +11027,22 @@ function paragraphStyleId(themeStyle) {
11050
11027
  if (heading) return `JTD_HeadingText${heading[1]}`;
11051
11028
  return themeStyle;
11052
11029
  }
11030
+ function definedParagraphStyleId(themeStyle, theme) {
11031
+ const id = paragraphStyleId(themeStyle);
11032
+ if (id === void 0) return void 0;
11033
+ if (ALWAYS_EMITTED_PARAGRAPH_STYLE_IDS.has(id)) return id;
11034
+ const styles = theme.styles;
11035
+ const name = themeStyle;
11036
+ return styles && (styles[name] ?? styles[name.toLowerCase()]) ? id : void 0;
11037
+ }
11038
+ var ALWAYS_EMITTED_PARAGRAPH_STYLE_IDS = /* @__PURE__ */ new Set([
11039
+ "Normal",
11040
+ "Title",
11041
+ "Subtitle",
11042
+ "Header",
11043
+ "Footer",
11044
+ ...Array.from({ length: 6 }, (_, i) => `JTD_HeadingText${i + 1}`)
11045
+ ]);
11053
11046
  function customOutlineLevel(themeStyle, theme) {
11054
11047
  if (typeof themeStyle !== "string" || !themeStyle) return void 0;
11055
11048
  if (/^heading[1-6]$/.test(themeStyle.toLowerCase())) return void 0;