@json-to-office/jto 1.6.0 → 1.11.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.
Files changed (36) hide show
  1. package/dist/cli.js +73 -21
  2. package/dist/cli.js.map +1 -1
  3. package/dist/client/assets/HomePage-r7ryeW_v.js +106 -0
  4. package/dist/client/assets/HomePage-r7ryeW_v.js.map +1 -0
  5. package/dist/client/assets/{JsonEditorPage-4LrF2fB9.js → JsonEditorPage-BxUyYH8Z.js} +3 -3
  6. package/dist/client/assets/{JsonEditorPage-4LrF2fB9.js.map → JsonEditorPage-BxUyYH8Z.js.map} +1 -1
  7. package/dist/client/assets/MonacoPluginProvider-CGvtVJKz.js +3 -0
  8. package/dist/client/assets/MonacoPluginProvider-CGvtVJKz.js.map +1 -0
  9. package/dist/client/assets/{editor-D-REaAU9.js → editor-gT4UjmPk.js} +2 -2
  10. package/dist/client/assets/{editor-D-REaAU9.js.map → editor-gT4UjmPk.js.map} +1 -1
  11. package/dist/client/assets/{editor-monaco-json-BgziSLMV.js → editor-monaco-json-BYUK4OUI.js} +2 -2
  12. package/dist/client/assets/{editor-monaco-json-BgziSLMV.js.map → editor-monaco-json-BYUK4OUI.js.map} +1 -1
  13. package/dist/client/assets/{editor-refs-store-vzLK2-Zo.js → editor-refs-store-ChL2fzuX.js} +2 -2
  14. package/dist/client/assets/{editor-refs-store-vzLK2-Zo.js.map → editor-refs-store-ChL2fzuX.js.map} +1 -1
  15. package/dist/client/assets/{index-B7bDnXoC.js → index-CgCY8SiY.js} +4 -4
  16. package/dist/client/assets/index-CgCY8SiY.js.map +1 -0
  17. package/dist/client/assets/preview-ZqhmQZJG.js +2 -0
  18. package/dist/client/assets/preview-ZqhmQZJG.js.map +1 -0
  19. package/dist/client/assets/{useQualityAnalysis-CowAaoA9.js → useQualityAnalysis-eKT8VcIt.js} +2 -2
  20. package/dist/client/assets/{useQualityAnalysis-CowAaoA9.js.map → useQualityAnalysis-eKT8VcIt.js.map} +1 -1
  21. package/dist/client/index.html +1 -1
  22. package/dist/client/templates/minimalist-pitch-deck.pptx.json +431 -7
  23. package/dist/client/templates/modern-annual-report-1.docx.json +4128 -168
  24. package/dist/client/templates/modern-annual-report-2.docx.json +5122 -4648
  25. package/dist/client/templates/modern-annual-report-3.docx.json +4540 -2755
  26. package/dist/client/templates/standard-annual-report.docx.json +6609 -234
  27. package/dist/client/templates/tech-report.docx.json +6404 -213
  28. package/dist/client/templates/vermilion-annual-report.docx.json +726 -106
  29. package/package.json +7 -7
  30. package/dist/client/assets/HomePage-CeUQIXch.js +0 -106
  31. package/dist/client/assets/HomePage-CeUQIXch.js.map +0 -1
  32. package/dist/client/assets/MonacoPluginProvider-Bx_V_FaE.js +0 -3
  33. package/dist/client/assets/MonacoPluginProvider-Bx_V_FaE.js.map +0 -1
  34. package/dist/client/assets/index-B7bDnXoC.js.map +0 -1
  35. package/dist/client/assets/preview-BGqIip90.js +0 -2
  36. package/dist/client/assets/preview-BGqIip90.js.map +0 -1
package/dist/cli.js CHANGED
@@ -249,6 +249,18 @@ function toQualityWarnings(diagnostics) {
249
249
  }
250
250
  }));
251
251
  }
252
+ function documentTitle(config2) {
253
+ const props = config2?.props;
254
+ const metadata = props?.metadata;
255
+ const title = metadata?.title ?? props?.title;
256
+ return typeof title === "string" ? title : void 0;
257
+ }
258
+ function documentFilenameBase(config2) {
259
+ const title = documentTitle(config2);
260
+ if (title === void 0) return void 0;
261
+ const base = title.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, MAX_FILENAME_BASE);
262
+ return /^[._]*$/.test(base) ? void 0 : base;
263
+ }
252
264
  function collectReferencedNames(config2, customThemes, adapterName) {
253
265
  const collect = adapterName === "docx" ? collectFontNamesFromDocx : collectFontNamesFromPptx;
254
266
  const names = /* @__PURE__ */ new Set();
@@ -395,12 +407,13 @@ function autoGoogleFontEntries(names, skipFamilies, referencedWeights, reference
395
407
  }
396
408
  return entries;
397
409
  }
398
- var GeneratorService;
410
+ var MAX_FILENAME_BASE, GeneratorService;
399
411
  var init_generator = __esm({
400
412
  "src/server/services/generator.ts"() {
401
413
  "use strict";
402
414
  init_esm_shims();
403
415
  init_logger();
416
+ MAX_FILENAME_BASE = 100;
404
417
  GeneratorService = class {
405
418
  adapter;
406
419
  cacheService;
@@ -468,6 +481,7 @@ var init_generator = __esm({
468
481
  const bypassCache = options?.bypassCache === true || extraEntries.length > 0 || declaresRegistry;
469
482
  const baseDir = typeof options?.baseDir === "string" ? options.baseDir : void 0;
470
483
  const renderer = typeof options?.renderer === "string" ? options.renderer : void 0;
484
+ const svgRasterFallback = typeof options?.svgRasterFallback === "boolean" ? options.svgRasterFallback : void 0;
471
485
  const resolvedFonts = [];
472
486
  const coreWarnings = [];
473
487
  const needsFontOpts = extraEntries.length > 0 || declaresRegistry || fontMode !== void 0 || fontSubstitution !== void 0 || callerStrict !== void 0;
@@ -528,16 +542,18 @@ var init_generator = __esm({
528
542
  baseDir: baseDir ?? null,
529
543
  // Same document, different backend → different bytes. Without this,
530
544
  // switching backends would serve the other one's cached buffer.
531
- renderer: renderer ?? null
545
+ renderer: renderer ?? null,
546
+ // Skipping the fallback changes the bytes, so it has to change the key.
547
+ svgRasterFallback: svgRasterFallback ?? null
532
548
  };
533
549
  const cacheKey = this.cacheService.generateCacheKey(cacheKeyData);
534
550
  const hasDynamicContent = this.cacheService.hasDynamicContent(config2);
535
551
  if (!bypassCache && !hasDynamicContent) {
536
552
  const cached = this.cacheService.get(cacheKey);
537
553
  if (cached) {
538
- logger.info("Served from cache", { title: config2.metadata?.title });
554
+ logger.info("Served from cache", { title: documentTitle(config2) });
539
555
  return {
540
- filename: `${config2.metadata?.title || this.adapter.label}${this.adapter.extension}`,
556
+ filename: `${documentFilenameBase(config2) || this.adapter.label}${this.adapter.extension}`,
541
557
  fileId: Date.now().toString(),
542
558
  buffer: cached.buffer,
543
559
  // Render warnings ride with bytes. Quality is request policy, so it
@@ -548,7 +564,7 @@ var init_generator = __esm({
548
564
  }
549
565
  }
550
566
  logger.info(`Generating ${this.adapter.label}`, {
551
- title: config2.metadata?.title
567
+ title: documentTitle(config2)
552
568
  });
553
569
  let buffer;
554
570
  if (registry.hasPlugins()) {
@@ -558,6 +574,7 @@ var init_generator = __esm({
558
574
  fonts: fontOpts,
559
575
  baseDir,
560
576
  renderer,
577
+ ...svgRasterFallback !== void 0 && { svgRasterFallback },
561
578
  warnings: coreWarnings,
562
579
  quality
563
580
  });
@@ -568,6 +585,7 @@ var init_generator = __esm({
568
585
  fonts: fontOpts,
569
586
  baseDir,
570
587
  renderer,
588
+ ...svgRasterFallback !== void 0 && { svgRasterFallback },
571
589
  warnings: coreWarnings,
572
590
  quality,
573
591
  prepared
@@ -608,7 +626,7 @@ var init_generator = __esm({
608
626
  { bypassCache: bypassCache || hasDynamicContent }
609
627
  );
610
628
  return {
611
- filename: `${config2.metadata?.title || this.adapter.label}${this.adapter.extension}`,
629
+ filename: `${documentFilenameBase(config2) || this.adapter.label}${this.adapter.extension}`,
612
630
  fileId: Date.now().toString(),
613
631
  buffer,
614
632
  cached: false,
@@ -1968,7 +1986,9 @@ function isInlineCandidate(source) {
1968
1986
  return true;
1969
1987
  }
1970
1988
  }
1971
- async function toDataUrl(source, baseDir, state) {
1989
+ async function toDataUrl(source, baseDir, state, mimeByExtension) {
1990
+ const mime = mimeByExtension[path4.extname(source).toLowerCase()];
1991
+ if (!mime) return null;
1972
1992
  let cacheKey = source;
1973
1993
  let result = null;
1974
1994
  try {
@@ -1978,14 +1998,11 @@ async function toDataUrl(source, baseDir, state) {
1978
1998
  if (cached !== void 0) return cached;
1979
1999
  const contained = resolved === state.baseDirReal || resolved.startsWith(state.baseDirReal + path4.sep);
1980
2000
  if (contained) {
1981
- const mime = MIME_BY_EXTENSION[path4.extname(resolved).toLowerCase()];
1982
- if (mime) {
1983
- const stat = await fs2.stat(resolved);
1984
- if (stat.isFile() && stat.size <= state.maxFileBytes && stat.size <= state.totalBudget) {
1985
- const buffer = await fs2.readFile(resolved);
1986
- state.totalBudget -= buffer.length;
1987
- result = `data:${mime};base64,${buffer.toString("base64")}`;
1988
- }
2001
+ const stat = await fs2.stat(resolved);
2002
+ if (stat.isFile() && stat.size <= state.maxFileBytes && stat.size <= state.totalBudget) {
2003
+ const buffer = await fs2.readFile(resolved);
2004
+ state.totalBudget -= buffer.length;
2005
+ result = `data:${mime};base64,${buffer.toString("base64")}`;
1989
2006
  }
1990
2007
  }
1991
2008
  } catch {
@@ -2003,14 +2020,37 @@ async function visit2(value, containerKey, baseDir, state, seen) {
2003
2020
  return;
2004
2021
  }
2005
2022
  const record = value;
2023
+ if (record.kind === "file" && typeof record.path === "string" && isInlineCandidate(record.path)) {
2024
+ const inlined = await toDataUrl(
2025
+ record.path,
2026
+ baseDir,
2027
+ state,
2028
+ FONT_MIME_BY_EXTENSION
2029
+ );
2030
+ if (inlined !== null) {
2031
+ record.kind = "data";
2032
+ record.data = inlined;
2033
+ delete record.path;
2034
+ }
2035
+ }
2006
2036
  const componentName = typeof record.name === "string" ? record.name.toLowerCase() : void 0;
2007
2037
  const props = isRecord2(record.props) ? record.props : void 0;
2008
2038
  if (componentName === "image" && props && typeof props.path === "string" && isInlineCandidate(props.path)) {
2009
- const inlined = await toDataUrl(props.path, baseDir, state);
2039
+ const inlined = await toDataUrl(
2040
+ props.path,
2041
+ baseDir,
2042
+ state,
2043
+ IMAGE_MIME_BY_EXTENSION
2044
+ );
2010
2045
  if (inlined !== null) props.path = inlined;
2011
2046
  }
2012
2047
  if (containerKey === "image" && typeof record.path === "string" && isInlineCandidate(record.path)) {
2013
- const inlined = await toDataUrl(record.path, baseDir, state);
2048
+ const inlined = await toDataUrl(
2049
+ record.path,
2050
+ baseDir,
2051
+ state,
2052
+ IMAGE_MIME_BY_EXTENSION
2053
+ );
2014
2054
  if (inlined !== null) record.path = inlined;
2015
2055
  }
2016
2056
  for (const [key, child] of Object.entries(record)) {
@@ -2044,12 +2084,12 @@ async function inlineTemplateMedia(jsonDefinition, baseDir, options = {}) {
2044
2084
  await visit2(clone, void 0, baseDir, state, /* @__PURE__ */ new WeakSet());
2045
2085
  return clone;
2046
2086
  }
2047
- var MIME_BY_EXTENSION;
2087
+ var IMAGE_MIME_BY_EXTENSION, FONT_MIME_BY_EXTENSION;
2048
2088
  var init_template_media_inliner = __esm({
2049
2089
  "src/server/services/template-media-inliner.ts"() {
2050
2090
  "use strict";
2051
2091
  init_esm_shims();
2052
- MIME_BY_EXTENSION = {
2092
+ IMAGE_MIME_BY_EXTENSION = {
2053
2093
  ".png": "image/png",
2054
2094
  ".jpg": "image/jpeg",
2055
2095
  ".jpeg": "image/jpeg",
@@ -2060,6 +2100,12 @@ var init_template_media_inliner = __esm({
2060
2100
  ".tiff": "image/tiff",
2061
2101
  ".tif": "image/tiff"
2062
2102
  };
2103
+ FONT_MIME_BY_EXTENSION = {
2104
+ ".ttf": "font/ttf",
2105
+ ".otf": "font/otf",
2106
+ ".woff": "font/woff",
2107
+ ".woff2": "font/woff2"
2108
+ };
2063
2109
  }
2064
2110
  });
2065
2111
 
@@ -2459,7 +2505,13 @@ function createFormatRouter(adapter) {
2459
2505
  // (#255).
2460
2506
  ...options?.renderer !== void 0 && {
2461
2507
  renderer: options.renderer
2462
- }
2508
+ },
2509
+ // The answer to this request is a PDF. LibreOffice draws the
2510
+ // vector, so the raster fallback each inline SVG carries for Word
2511
+ // before 2016 is never read — and on a document whose artwork is
2512
+ // hundreds of small SVGs, producing it was most of the wait
2513
+ // (tech-report: 56s, against 2s without).
2514
+ svgRasterFallback: false
2463
2515
  }
2464
2516
  });
2465
2517
  const pdfBuffer = await libreOfficeService.convertToPdf(
@@ -4329,7 +4381,7 @@ function createDevCommand(adapter) {
4329
4381
  }
4330
4382
 
4331
4383
  // src/cli.ts
4332
- var PACKAGE_VERSION = true ? "1.6.0" : "dev-mode";
4384
+ var PACKAGE_VERSION = true ? "1.11.0" : "dev-mode";
4333
4385
  var program = new Command2();
4334
4386
  program.name("jto").description("JSON to Office CLI - Generate .docx and .pptx from JSON").version(PACKAGE_VERSION);
4335
4387
  registerCoreCommands(program, {