@taloswork/ose-shared 0.0.2 → 0.0.3

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 (124) hide show
  1. package/mcp/gen/mcp.json +26 -0
  2. package/mcp/gen-google/mcp.json +30 -0
  3. package/mcp/gen-seedance/mcp.json +30 -0
  4. package/mcp/gen-seedream/mcp.json +30 -0
  5. package/mcp/gen-veo/mcp.json +30 -0
  6. package/package.json +3 -3
  7. package/skills/document/SKILL.md +11 -7
  8. package/skills/document/assets/fonts/Anton-Regular.woff2 +0 -0
  9. package/skills/document/bin/doc-convert.cjs +983 -936
  10. package/skills/document/bin/doc-gen.cjs +52 -4
  11. package/skills/document/bin/html2pptx.cjs +34 -10
  12. package/skills/document/content-pipeline.md +4 -3
  13. package/skills/document/layouts/README.md +9 -0
  14. package/skills/document/layouts/bento.tpl +1 -1
  15. package/skills/document/layouts/big-stat.tpl +1 -1
  16. package/skills/document/layouts/blocks-2x2.tpl +3 -3
  17. package/skills/document/layouts/brand-values.tpl +1 -1
  18. package/skills/document/layouts/cards-3.tpl +1 -1
  19. package/skills/document/layouts/cards-grid.tpl +1 -1
  20. package/skills/document/layouts/chart-full.tpl +1 -1
  21. package/skills/document/layouts/chart-kpi.tpl +1 -1
  22. package/skills/document/layouts/color-palette.tpl +6 -6
  23. package/skills/document/layouts/comparison.tpl +2 -2
  24. package/skills/document/layouts/concept-hub.tpl +1 -1
  25. package/skills/document/layouts/cover-centered.tpl +1 -1
  26. package/skills/document/layouts/cover-image.tpl +1 -1
  27. package/skills/document/layouts/cover-minimal.tpl +1 -1
  28. package/skills/document/layouts/cover-statement.tpl +1 -1
  29. package/skills/document/layouts/cover.tpl +1 -1
  30. package/skills/document/layouts/data-table.tpl +1 -1
  31. package/skills/document/layouts/dos-donts.tpl +1 -1
  32. package/skills/document/layouts/editorial-panel.tpl +5 -5
  33. package/skills/document/layouts/ending-contact.tpl +1 -1
  34. package/skills/document/layouts/ending.tpl +1 -1
  35. package/skills/document/layouts/funnel.tpl +1 -1
  36. package/skills/document/layouts/gantt.tpl +2 -2
  37. package/skills/document/layouts/hero.tpl +1 -1
  38. package/skills/document/layouts/icon-row.tpl +1 -1
  39. package/skills/document/layouts/image-grid.tpl +1 -1
  40. package/skills/document/layouts/image-left.tpl +1 -1
  41. package/skills/document/layouts/list.tpl +1 -1
  42. package/skills/document/layouts/logo-guidelines.tpl +3 -3
  43. package/skills/document/layouts/map-distribution.tpl +1 -1
  44. package/skills/document/layouts/map-quad.tpl +1 -1
  45. package/skills/document/layouts/matrix-2x2.tpl +1 -1
  46. package/skills/document/layouts/numbered-brief.tpl +3 -3
  47. package/skills/document/layouts/org-tree.tpl +1 -1
  48. package/skills/document/layouts/problem-solution-banner.tpl +12 -0
  49. package/skills/document/layouts/problem-solution.tpl +2 -2
  50. package/skills/document/layouts/pyramid.tpl +1 -1
  51. package/skills/document/layouts/quote.tpl +1 -1
  52. package/skills/document/layouts/radar.tpl +1 -1
  53. package/skills/document/layouts/ring-progress.tpl +1 -1
  54. package/skills/document/layouts/section-fullbleed.tpl +8 -0
  55. package/skills/document/layouts/section-image.tpl +1 -1
  56. package/skills/document/layouts/section-stat.tpl +1 -1
  57. package/skills/document/layouts/section.tpl +1 -1
  58. package/skills/document/layouts/slots.json +763 -1
  59. package/skills/document/layouts/split-two-col.tpl +1 -1
  60. package/skills/document/layouts/stats-chart.tpl +2 -2
  61. package/skills/document/layouts/steps-serpentine.tpl +19 -0
  62. package/skills/document/layouts/steps-vertical.tpl +1 -1
  63. package/skills/document/layouts/steps.tpl +1 -1
  64. package/skills/document/layouts/team-row.tpl +6 -6
  65. package/skills/document/layouts/three-kpi.tpl +1 -1
  66. package/skills/document/layouts/timeline.tpl +1 -1
  67. package/skills/document/layouts/title-meta.tpl +1 -1
  68. package/skills/document/layouts/title.tpl +1 -1
  69. package/skills/document/layouts/toc-agenda.tpl +1 -1
  70. package/skills/document/layouts/toc-panel.tpl +3 -3
  71. package/skills/document/layouts/toc.tpl +1 -1
  72. package/skills/document/layouts/transition.tpl +1 -1
  73. package/skills/document/layouts/two-kpi.tpl +1 -1
  74. package/skills/document/layouts/type-specimen.tpl +3 -3
  75. package/skills/document/layouts/versus.tpl +1 -1
  76. package/skills/document/styles/README.md +42 -6
  77. package/skills/document/styles/_backdrops/arch.html +5 -0
  78. package/skills/document/styles/_backdrops/aurora.html +6 -0
  79. package/skills/document/styles/_backdrops/beam.html +5 -0
  80. package/skills/document/styles/_backdrops/bloom.html +5 -0
  81. package/skills/document/styles/_backdrops/duotone.html +6 -0
  82. package/skills/document/styles/_backdrops/frosted.html +4 -0
  83. package/skills/document/styles/_backdrops/rimlight.html +7 -0
  84. package/skills/document/styles/_backdrops/shared.html +5 -0
  85. package/skills/document/styles/_samples/anthropic.webp +0 -0
  86. package/skills/document/styles/_samples/apple.webp +0 -0
  87. package/skills/document/styles/_samples/black-gold.webp +0 -0
  88. package/skills/document/styles/_samples/branding.webp +0 -0
  89. package/skills/document/styles/_samples/cinereel.webp +0 -0
  90. package/skills/document/styles/_samples/cool.webp +0 -0
  91. package/skills/document/styles/_samples/hand-drawn.webp +0 -0
  92. package/skills/document/styles/_samples/ivory-gold.webp +0 -0
  93. package/skills/document/styles/_samples/magazine-ink.webp +0 -0
  94. package/skills/document/styles/_samples/mckinsey.webp +0 -0
  95. package/skills/document/styles/_samples/mono.webp +0 -0
  96. package/skills/document/styles/_samples/olive-gold.webp +0 -0
  97. package/skills/document/styles/_samples/swiss-grid.webp +0 -0
  98. package/skills/document/styles/anthropic/skin.css +1 -1
  99. package/skills/document/styles/apple/skin.css +1 -1
  100. package/skills/document/styles/black-gold/skin.css +1 -1
  101. package/skills/document/styles/cinereel/backdrop.html +2 -0
  102. package/skills/document/styles/cinereel/skin.css +133 -0
  103. package/skills/document/styles/cool/skin.css +1 -1
  104. package/skills/document/styles/hand-drawn/skin.css +1 -1
  105. package/skills/document/styles/ivory-gold/backdrop.html +15 -0
  106. package/skills/document/styles/ivory-gold/skin.css +137 -0
  107. package/skills/document/styles/magazine-ink/backdrop.html +12 -0
  108. package/skills/document/styles/magazine-ink/skin.css +121 -0
  109. package/skills/document/styles/mckinsey/skin.css +1 -1
  110. package/skills/document/styles/mono/skin.css +1 -1
  111. package/skills/document/styles/swiss-grid/backdrop.html +2 -0
  112. package/skills/document/styles/swiss-grid/skin.css +117 -0
  113. package/skills/document/themes/README.md +5 -1
  114. package/skills/document/themes/cinereel.json +24 -0
  115. package/skills/document/themes/ivory-gold.json +24 -0
  116. package/skills/document/themes/magazine-ink.json +24 -0
  117. package/skills/document/themes/swiss-grid.json +24 -0
  118. package/mcp/Linear/mcp.json +0 -17
  119. package/skills/document/styles/anthropic/backdrop-arch.html +0 -3
  120. package/skills/document/styles/anthropic/backdrop-shared.html +0 -3
  121. package/skills/document/styles/apple/backdrop-shared.html +0 -3
  122. package/skills/document/styles/cool/backdrop-spotlight.html +0 -3
  123. package/skills/document/styles/mckinsey/backdrop-shared.html +0 -3
  124. /package/skills/document/styles/{apple/backdrop-spotlight.html → _backdrops/spotlight.html} +0 -0
@@ -148977,7 +148977,7 @@ var import_node_path2 = require("node:path");
148977
148977
  var import_promises2 = require("node:fs/promises");
148978
148978
 
148979
148979
  // packages/core/dist/fs/doc-convert.js
148980
- var import_jszip2 = __toESM(require_lib3(), 1);
148980
+ var import_jszip3 = __toESM(require_lib3(), 1);
148981
148981
  var import_mammoth2 = __toESM(require_lib6(), 1);
148982
148982
 
148983
148983
  // packages/core/dist/fs/office-converter.js
@@ -149052,722 +149052,244 @@ function imageRefsFromRels(relsXml) {
149052
149052
  return [...relsXml.matchAll(/Type="[^"]*\/image"\s+Target="([^"]+)"/g)].map((m) => m[1]);
149053
149053
  }
149054
149054
 
149055
- // packages/core/dist/fs/doc-theme.js
149056
- var DEFAULT_THEME = {
149057
- bestFor: "",
149058
- fonts: { heading: "", body: "" },
149059
- // empty → engine's built-in stack
149060
- colors: {
149061
- primary: "#1a1a1a",
149062
- accent: "#1a1a1a",
149063
- // kept in sync with primary when the theme defines neither
149064
- secondary: "#666666",
149065
- // kept in sync with muted when the theme defines neither
149066
- text: "#1a1a1a",
149067
- muted: "#666666",
149068
- tableHeaderBg: "#f3f3f3",
149069
- tableBorder: "#bbbbbb"
149070
- },
149071
- page: { size: "A4", margin: "20mm", header: "", footer: "" },
149072
- heading: {
149073
- h1: { size: 20, color: "text", bold: true, spaceAfter: 12 },
149074
- h2: { size: 15, color: "text", bold: true, spaceAfter: 8 },
149075
- h3: { size: 13, color: "text", bold: true, spaceAfter: 6 },
149076
- h4: { size: 11, color: "text", bold: true, spaceAfter: 6 }
149077
- },
149078
- body: { size: 11, lineHeight: 1.6, justify: true },
149079
- cover: { enabled: false, subtitle: "", date: "", logo: "" },
149080
- pptx: {
149081
- background: "#ffffff",
149082
- titleColor: "#1a1a1a",
149083
- textColor: "",
149084
- titleSize: 24,
149085
- bodySize: 16,
149086
- logo: "",
149087
- logoPos: { x: 12.2, y: 0.25, w: 0.8, h: 0.8 },
149088
- footer: "",
149089
- slideNumber: false,
149090
- motif: "none",
149091
- bgWash: false,
149092
- depth: false
149055
+ // node_modules/docx/dist/index.mjs
149056
+ var __create2 = Object.create;
149057
+ var __defProp2 = Object.defineProperty;
149058
+ var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
149059
+ var __getOwnPropNames2 = Object.getOwnPropertyNames;
149060
+ var __getProtoOf2 = Object.getPrototypeOf;
149061
+ var __hasOwnProp2 = Object.prototype.hasOwnProperty;
149062
+ var __esmMin = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
149063
+ var __commonJSMin = (cb2, mod) => () => (mod || (cb2((mod = { exports: {} }).exports, mod), cb2 = null), mod.exports);
149064
+ var __copyProps2 = (to, from, except, desc) => {
149065
+ if (from && typeof from === "object" || typeof from === "function") for (var keys2 = __getOwnPropNames2(from), i = 0, n = keys2.length, key; i < n; i++) {
149066
+ key = keys2[i];
149067
+ if (!__hasOwnProp2.call(to, key) && key !== except) __defProp2(to, key, {
149068
+ get: ((k) => from[k]).bind(null, key),
149069
+ enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable
149070
+ });
149093
149071
  }
149072
+ return to;
149094
149073
  };
149095
- var HEX_RE = /^#[0-9a-fA-F]{6}$/;
149096
- var CSS_LEN_RE = /^\d+(\.\d+)?(mm|cm|in|pt|px)$/;
149097
- function isFiniteNum(v) {
149098
- return typeof v === "number" && Number.isFinite(v);
149074
+ var __toESM2 = (mod, isNodeMode, target) => (target = mod != null ? __create2(__getProtoOf2(mod)) : {}, __copyProps2(isNodeMode || !mod || !mod.__esModule ? __defProp2(target, "default", {
149075
+ value: mod,
149076
+ enumerable: true
149077
+ }) : target, mod));
149078
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, { get: (a, b) => (typeof require !== "undefined" ? require : a)[b] }) : x)(function(x) {
149079
+ if (typeof require !== "undefined") return require.apply(this, arguments);
149080
+ throw Error('Calling `require` for "' + x + "\" in an environment that doesn't expose the `require` function. See https://rolldown.rs/in-depth/bundling-cjs#require-external-modules for more details.");
149081
+ });
149082
+ function _typeof(o) {
149083
+ "@babel/helpers - typeof";
149084
+ return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o2) {
149085
+ return typeof o2;
149086
+ } : function(o2) {
149087
+ return o2 && "function" == typeof Symbol && o2.constructor === Symbol && o2 !== Symbol.prototype ? "symbol" : typeof o2;
149088
+ }, _typeof(o);
149099
149089
  }
149100
- function resolveColor(theme, ref) {
149101
- if (HEX_RE.test(ref))
149102
- return ref;
149103
- const palette = theme.colors;
149104
- return palette[ref] ?? theme.colors.text;
149090
+ function toPrimitive(t, r) {
149091
+ if ("object" != _typeof(t) || !t) return t;
149092
+ var e = t[Symbol.toPrimitive];
149093
+ if (void 0 !== e) {
149094
+ var i = e.call(t, r || "default");
149095
+ if ("object" != _typeof(i)) return i;
149096
+ throw new TypeError("@@toPrimitive must return a primitive value.");
149097
+ }
149098
+ return ("string" === r ? String : Number)(t);
149105
149099
  }
149106
- function resolveTheme(raw) {
149107
- const warnings = [];
149108
- const t = structuredClone(DEFAULT_THEME);
149109
- t.warnings = warnings;
149110
- if (raw == null)
149111
- return t;
149112
- if (typeof raw !== "object" || Array.isArray(raw)) {
149113
- warnings.push("theme must be a JSON object; using defaults");
149114
- return t;
149100
+ function toPropertyKey(t) {
149101
+ var i = toPrimitive(t, "string");
149102
+ return "symbol" == _typeof(i) ? i : i + "";
149103
+ }
149104
+ function _defineProperty(e, r, t) {
149105
+ return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
149106
+ value: t,
149107
+ enumerable: true,
149108
+ configurable: true,
149109
+ writable: true
149110
+ }) : e[r] = t, e;
149111
+ }
149112
+ var BaseXmlComponent = class {
149113
+ /**
149114
+ * Creates a new BaseXmlComponent with the specified XML element name.
149115
+ *
149116
+ * @param rootKey - The XML element name (e.g., "w:p", "w:r", "w:t")
149117
+ */
149118
+ constructor(rootKey) {
149119
+ _defineProperty(
149120
+ this,
149121
+ /** The XML element name for this component (e.g., "w:p" for paragraph). */
149122
+ "rootKey",
149123
+ void 0
149124
+ );
149125
+ this.rootKey = rootKey;
149115
149126
  }
149116
- const src = raw;
149117
- const str = (v, path) => {
149118
- if (v === void 0)
149119
- return void 0;
149120
- if (typeof v === "string")
149121
- return v;
149122
- warnings.push(`${path}: expected string`);
149123
- return void 0;
149124
- };
149125
- const color = (v, path) => {
149126
- const s = str(v, path);
149127
- if (s === void 0)
149128
- return void 0;
149129
- if (HEX_RE.test(s) || /^[a-zA-Z][a-zA-Z]*$/.test(s))
149130
- return s;
149131
- warnings.push(`${path}: expected "#rrggbb" or a palette key`);
149132
- return void 0;
149133
- };
149134
- const num = (v, path, min2, max2) => {
149135
- if (v === void 0)
149136
- return void 0;
149137
- if (isFiniteNum(v) && v >= min2 && v <= max2)
149138
- return v;
149139
- warnings.push(`${path}: expected number in [${min2}, ${max2}]`);
149140
- return void 0;
149141
- };
149142
- const bool = (v, path) => {
149143
- if (v === void 0)
149144
- return void 0;
149145
- if (typeof v === "boolean")
149146
- return v;
149147
- warnings.push(`${path}: expected boolean`);
149148
- return void 0;
149149
- };
149150
- t.bestFor = str(src.bestFor, "bestFor") ?? t.bestFor;
149151
- t.fonts.heading = str(src.fonts?.heading, "fonts.heading") ?? t.fonts.heading;
149152
- t.fonts.body = str(src.fonts?.body, "fonts.body") ?? t.fonts.body;
149153
- const colorSet = /* @__PURE__ */ new Set();
149154
- for (const k of ["primary", "accent", "secondary", "text", "muted", "tableHeaderBg", "tableBorder"]) {
149155
- const v = src.colors?.[k];
149156
- if (v === void 0)
149157
- continue;
149158
- if (typeof v === "string" && HEX_RE.test(v)) {
149159
- t.colors[k] = v;
149160
- colorSet.add(k);
149161
- } else
149162
- warnings.push(`colors.${k}: expected "#rrggbb"`);
149127
+ };
149128
+ var EMPTY_OBJECT = Object.seal({});
149129
+ var XmlComponent = class extends BaseXmlComponent {
149130
+ /**
149131
+ * Creates a new XmlComponent.
149132
+ *
149133
+ * @param rootKey - The XML element name (e.g., "w:p", "w:r", "w:t")
149134
+ */
149135
+ constructor(rootKey) {
149136
+ super(rootKey);
149137
+ _defineProperty(
149138
+ this,
149139
+ /**
149140
+ * Array of child components, text nodes, and attributes.
149141
+ *
149142
+ * This array forms the content of the XML element. It can contain other
149143
+ * XmlComponents, string values (text nodes), or attribute components.
149144
+ */
149145
+ "root",
149146
+ void 0
149147
+ );
149148
+ this.root = new Array();
149163
149149
  }
149164
- if (!colorSet.has("accent"))
149165
- t.colors.accent = t.colors.primary;
149166
- if (!colorSet.has("secondary"))
149167
- t.colors.secondary = t.colors.muted;
149168
- if (src.page?.size !== void 0) {
149169
- if (src.page.size === "A4" || src.page.size === "Letter")
149170
- t.page.size = src.page.size;
149171
- else
149172
- warnings.push('page.size: expected "A4" | "Letter"');
149150
+ /**
149151
+ * Prepares this component and its children for XML serialization.
149152
+ *
149153
+ * This method is called by the Formatter to convert the component tree into
149154
+ * an object structure compatible with the xml library (https://www.npmjs.com/package/xml).
149155
+ * It recursively processes all children and handles special cases like
149156
+ * attribute-only elements and empty elements.
149157
+ *
149158
+ * The method can be overridden by subclasses to customize XML representation
149159
+ * or execute side effects during serialization (e.g., creating relationships).
149160
+ *
149161
+ * @param context - The serialization context containing document state
149162
+ * @returns The XML-serializable object, or undefined to exclude from output
149163
+ *
149164
+ * @example
149165
+ * ```typescript
149166
+ * // Override to add custom serialization logic
149167
+ * prepForXml(context: IContext): IXmlableObject | undefined {
149168
+ * // Custom logic here
149169
+ * return super.prepForXml(context);
149170
+ * }
149171
+ * ```
149172
+ */
149173
+ prepForXml(context) {
149174
+ var _children$;
149175
+ context.stack.push(this);
149176
+ const children = this.root.map((comp) => {
149177
+ if (comp instanceof BaseXmlComponent) return comp.prepForXml(context);
149178
+ return comp;
149179
+ }).filter((comp) => comp !== void 0);
149180
+ context.stack.pop();
149181
+ return { [this.rootKey]: children.length ? children.length === 1 && ((_children$ = children[0]) === null || _children$ === void 0 ? void 0 : _children$._attr) ? children[0] : children : EMPTY_OBJECT };
149173
149182
  }
149174
- if (src.page?.margin !== void 0) {
149175
- if (typeof src.page.margin === "string" && CSS_LEN_RE.test(src.page.margin))
149176
- t.page.margin = src.page.margin;
149177
- else
149178
- warnings.push('page.margin: expected a CSS length like "20mm"');
149183
+ /**
149184
+ * Adds a child element to this component.
149185
+ *
149186
+ * @deprecated Do not use this method. It is only used internally by the library. It will be removed in a future version.
149187
+ * @param child - The child component or text string to add
149188
+ * @returns This component (for chaining)
149189
+ */
149190
+ addChildElement(child) {
149191
+ this.root.push(child);
149192
+ return this;
149179
149193
  }
149180
- t.page.header = str(src.page?.header, "page.header") ?? t.page.header;
149181
- t.page.footer = str(src.page?.footer, "page.footer") ?? t.page.footer;
149182
- for (const lvl of ["h1", "h2", "h3", "h4"]) {
149183
- const h = src.heading?.[lvl];
149184
- if (h === void 0)
149185
- continue;
149186
- if (typeof h !== "object" || h === null) {
149187
- warnings.push(`heading.${lvl}: expected object`);
149188
- continue;
149189
- }
149190
- t.heading[lvl].size = num(h.size, `heading.${lvl}.size`, 6, 96) ?? t.heading[lvl].size;
149191
- t.heading[lvl].color = color(h.color, `heading.${lvl}.color`) ?? t.heading[lvl].color;
149192
- t.heading[lvl].bold = bool(h.bold, `heading.${lvl}.bold`) ?? t.heading[lvl].bold;
149193
- t.heading[lvl].spaceAfter = num(h.spaceAfter, `heading.${lvl}.spaceAfter`, 0, 96) ?? t.heading[lvl].spaceAfter;
149194
+ };
149195
+ var IgnoreIfEmptyXmlComponent = class extends XmlComponent {
149196
+ constructor(rootKey, includeIfEmpty) {
149197
+ super(rootKey);
149198
+ _defineProperty(this, "includeIfEmpty", void 0);
149199
+ this.includeIfEmpty = includeIfEmpty;
149194
149200
  }
149195
- t.body.size = num(src.body?.size, "body.size", 6, 48) ?? t.body.size;
149196
- t.body.lineHeight = num(src.body?.lineHeight, "body.lineHeight", 1, 3) ?? t.body.lineHeight;
149197
- t.body.justify = bool(src.body?.justify, "body.justify") ?? t.body.justify;
149198
- t.cover.enabled = bool(src.cover?.enabled, "cover.enabled") ?? t.cover.enabled;
149199
- t.cover.subtitle = str(src.cover?.subtitle, "cover.subtitle") ?? t.cover.subtitle;
149200
- t.cover.date = str(src.cover?.date, "cover.date") ?? t.cover.date;
149201
- t.cover.logo = str(src.cover?.logo, "cover.logo") ?? t.cover.logo;
149202
- const p = src.pptx;
149203
- if (p !== void 0) {
149204
- if (typeof p !== "object" || p === null)
149205
- warnings.push("pptx: expected object");
149206
- else {
149207
- for (const k of ["background", "titleColor", "textColor"]) {
149208
- const v = p[k];
149209
- if (v === void 0)
149210
- continue;
149211
- if (typeof v === "string" && HEX_RE.test(v))
149212
- t.pptx[k] = v;
149213
- else
149214
- warnings.push(`pptx.${k}: expected "#rrggbb"`);
149215
- }
149216
- t.pptx.titleSize = num(p.titleSize, "pptx.titleSize", 8, 60) ?? t.pptx.titleSize;
149217
- t.pptx.bodySize = num(p.bodySize, "pptx.bodySize", 8, 48) ?? t.pptx.bodySize;
149218
- t.pptx.logo = str(p.logo, "pptx.logo") ?? t.pptx.logo;
149219
- if (p.logoPos !== void 0) {
149220
- const lp = p.logoPos;
149221
- if (lp && [lp.x, lp.y, lp.w, lp.h].every((v) => isFiniteNum(v) && v >= 0 && v <= 14)) {
149222
- t.pptx.logoPos = { x: lp.x, y: lp.y, w: lp.w, h: lp.h };
149223
- } else
149224
- warnings.push("pptx.logoPos: expected {x,y,w,h} inches within the slide");
149225
- }
149226
- t.pptx.footer = str(p.footer, "pptx.footer") ?? t.pptx.footer;
149227
- t.pptx.slideNumber = bool(p.slideNumber, "pptx.slideNumber") ?? t.pptx.slideNumber;
149228
- if (p.motif !== void 0) {
149229
- if (p.motif === "none" || p.motif === "corner" || p.motif === "sidebar")
149230
- t.pptx.motif = p.motif;
149231
- else
149232
- warnings.push('pptx.motif: expected "none" | "corner" | "sidebar"');
149233
- }
149234
- t.pptx.bgWash = bool(p.bgWash, "pptx.bgWash") ?? t.pptx.bgWash;
149235
- t.pptx.depth = bool(p.depth, "pptx.depth") ?? t.pptx.depth;
149236
- }
149201
+ /**
149202
+ * Prepares the component for XML serialization, excluding it if empty.
149203
+ *
149204
+ * @param context - The serialization context
149205
+ * @returns The XML-serializable object, or undefined if empty
149206
+ */
149207
+ prepForXml(context) {
149208
+ const result2 = super.prepForXml(context);
149209
+ if (this.includeIfEmpty) return result2;
149210
+ if (result2 && (typeof result2[this.rootKey] !== "object" || Object.keys(result2[this.rootKey]).length)) return result2;
149211
+ }
149212
+ };
149213
+ function ownKeys(e, r) {
149214
+ var t = Object.keys(e);
149215
+ if (Object.getOwnPropertySymbols) {
149216
+ var o = Object.getOwnPropertySymbols(e);
149217
+ r && (o = o.filter(function(r2) {
149218
+ return Object.getOwnPropertyDescriptor(e, r2).enumerable;
149219
+ })), t.push.apply(t, o);
149237
149220
  }
149238
149221
  return t;
149239
149222
  }
149240
- function interpolateTitle(template2, title) {
149241
- return template2.replaceAll("{title}", title ?? "");
149242
- }
149243
- function asTheme(themeInput) {
149244
- return themeInput && typeof themeInput === "object" && "warnings" in themeInput ? themeInput : resolveTheme(themeInput);
149245
- }
149246
-
149247
- // packages/core/dist/fs/doc-html.js
149248
- var FONT_STACK = 'TalosCJK, "Helvetica Neue", Helvetica, Arial, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans CJK SC", "Source Han Sans SC", "WenQuanYi Zen Hei", sans-serif';
149249
-
149250
- // packages/core/dist/fs/doc-convert.js
149251
- var PRINT_STYLE = `
149252
- @page { size: A4; margin: 20mm 18mm; }
149253
- * { box-sizing: border-box; }
149254
- html { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
149255
- body { font-family: ${FONT_STACK}; font-size: 11pt; line-height: 1.55; color: #1a1a1a; margin: 0; }
149256
- h1 { font-size: 20pt; margin: 0 0 10pt; line-height: 1.3; }
149257
- h2 { font-size: 15.5pt; margin: 14pt 0 6pt; }
149258
- h3 { font-size: 13pt; margin: 12pt 0 5pt; }
149259
- h4, h5, h6 { font-size: 11.5pt; margin: 10pt 0 4pt; }
149260
- p { margin: 0 0 7pt; overflow-wrap: break-word; }
149261
- ul, ol { margin: 0 0 7pt; padding-left: 22pt; }
149262
- li { margin: 0 0 3pt; }
149263
- table { border-collapse: collapse; width: 100%; margin: 8pt 0; font-size: 10.5pt; }
149264
- th, td { border: 1px solid #b9b9b9; padding: 4pt 8pt; text-align: left; vertical-align: top; }
149265
- th { background: #f2f2f2; font-weight: 700; }
149266
- img { max-width: 100%; }
149267
- .slide { page-break-after: always; }
149268
- .slide:last-child { page-break-after: auto; }
149269
- .slide-no { color: #999; font-size: 8pt; margin: 0 0 6pt; }
149270
- `.trim();
149271
- function htmlShell(bodyHtml, title) {
149272
- const head = `<meta charset="utf-8">` + (title ? `<title>${escapeHtml(title)}</title>` : "") + `<style>${PRINT_STYLE}</style>`;
149273
- return `<!doctype html><html lang="zh"><head>${head}</head><body>${bodyHtml}</body></html>`;
149274
- }
149275
- function escapeHtml(s) {
149276
- return s.replace(/[&<>"]/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;" })[c]);
149277
- }
149278
- function titleFromFilename(filename) {
149279
- const base = filename.split(/[\\/]/).pop() ?? filename;
149280
- const stem = base.replace(/\.[^.]+$/, "").trim();
149281
- return stem || void 0;
149282
- }
149283
- function htmlToParagraphs(html) {
149284
- const text = html.replace(/<\/(h[1-6]|p|li|tr)>/gi, "\n").replace(/<br[^>]*\/?>/gi, "\n").replace(/<\/t[dh]>/gi, " ").replace(/<[^>]+>/g, "").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&amp;/g, "&").replace(/&nbsp;/g, " ");
149285
- return text.split(/\n+/).map((line) => line.replace(/\t+/g, " ").trim()).filter((line) => line.length > 0);
149286
- }
149287
- async function convertDocxToHtml(buffer, filename) {
149288
- const result2 = await import_mammoth2.default.convertToHtml({ buffer: Buffer.from(buffer) }, {
149289
- convertImage: import_mammoth2.default.images.imgElement(async (image) => ({
149290
- src: `data:${image.contentType};base64,${await image.read("base64")}`
149291
- }))
149292
- });
149293
- const bodyHtml = result2.value;
149294
- return {
149295
- kind: "docx",
149296
- html: htmlShell(bodyHtml, titleFromFilename(filename)),
149297
- fallbackSpec: { title: titleFromFilename(filename), paragraphs: htmlToParagraphs(bodyHtml) },
149298
- warnings: (result2.messages ?? []).map((m) => `${m.type ?? "warning"}: ${m.message ?? ""}`)
149299
- };
149300
- }
149301
- async function convertPptxToHtml(buffer, filename) {
149302
- const zip = await import_jszip2.default.loadAsync(buffer);
149303
- const slideFiles = Object.keys(zip.files).filter((f) => /^ppt\/slides\/slide\d+\.xml$/.test(f)).sort((a, b) => slideNumber(a) - slideNumber(b));
149304
- const sections = [];
149305
- const fallbackParagraphs = [];
149306
- for (const slidePath of slideFiles) {
149307
- const num = slideNumber(slidePath);
149308
- const xml = await zip.file(slidePath).async("string");
149309
- const paragraphs = extractSlideText(xml).split("\n").filter(Boolean);
149310
- const imgs = [];
149311
- const relsPath = `ppt/slides/_rels/slide${num}.xml.rels`;
149312
- const relsFile = zip.file(relsPath);
149313
- if (relsFile) {
149314
- for (const ref of imageRefsFromRels(await relsFile.async("string"))) {
149315
- const mediaPath = resolveRelTarget(relsPath, ref);
149316
- const media = zip.file(mediaPath);
149317
- if (!media)
149318
- continue;
149319
- imgs.push(`<img src="data:${mimeFromPath(mediaPath)};base64,${await media.async("base64")}" alt="">`);
149320
- }
149321
- }
149322
- sections.push(`<section class="slide"><div class="slide-no">${num} / ${slideFiles.length}</div>` + paragraphs.map((p) => `<p>${escapeHtml(p)}</p>`).join("") + imgs.join("") + `</section>`);
149323
- fallbackParagraphs.push(`[\u5E7B\u706F\u7247 ${num}]`, ...paragraphs);
149223
+ function _objectSpread2(e) {
149224
+ for (var r = 1; r < arguments.length; r++) {
149225
+ var t = null != arguments[r] ? arguments[r] : {};
149226
+ r % 2 ? ownKeys(Object(t), true).forEach(function(r2) {
149227
+ _defineProperty(e, r2, t[r2]);
149228
+ }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function(r2) {
149229
+ Object.defineProperty(e, r2, Object.getOwnPropertyDescriptor(t, r2));
149230
+ });
149324
149231
  }
149325
- return {
149326
- kind: "pptx",
149327
- html: htmlShell(sections.join("\n"), titleFromFilename(filename)),
149328
- fallbackSpec: { title: titleFromFilename(filename), paragraphs: fallbackParagraphs },
149329
- warnings: ["pptx conversion is one page per slide (text + images); in-slide layout is not reproduced"]
149330
- };
149232
+ return e;
149331
149233
  }
149332
- async function convertOfficeToPrintable(buffer, filename) {
149333
- if (buffer.byteLength < 4)
149334
- return { error: `\u65E0\u6CD5\u8BC6\u522B ${filename} \u7684\u6587\u4EF6\u683C\u5F0F\uFF08\u6587\u4EF6\u8FC7\u5C0F\uFF09` };
149335
- if (isCompoundDocMagic(buffer)) {
149336
- return { error: `\u4E0D\u652F\u6301\u65E7\u7248 .doc/.ppt\uFF0C\u8BF7\u5148\u5728\u5BF9\u5E94\u5E94\u7528\u4E2D\u53E6\u5B58\u4E3A .docx/.pptx \u518D\u8F6C\u6362` };
149234
+ var XmlAttributeComponent = class extends BaseXmlComponent {
149235
+ /**
149236
+ * Creates a new attribute component.
149237
+ *
149238
+ * @param root - The attribute data object
149239
+ */
149240
+ constructor(root2) {
149241
+ super("_attr");
149242
+ _defineProperty(this, "root", void 0);
149243
+ _defineProperty(
149244
+ this,
149245
+ /** Optional mapping from property names to XML attribute names. */
149246
+ "xmlKeys",
149247
+ void 0
149248
+ );
149249
+ this.root = root2;
149337
149250
  }
149338
- if (!isZipMagic(buffer))
149339
- return { error: `\u4E0D\u652F\u6301 ${filename} \u7684\u6587\u4EF6\u683C\u5F0F\uFF08doc-convert \u53EA\u652F\u6301 .docx/.pptx\uFF09` };
149340
- let zip;
149341
- try {
149342
- zip = await import_jszip2.default.loadAsync(buffer);
149343
- } catch {
149344
- return { error: `\u65E0\u6CD5\u89E3\u6790 ${filename}\uFF1AZIP \u7ED3\u6784\u635F\u574F` };
149251
+ /**
149252
+ * Converts the attribute data to an XML-serializable object.
149253
+ *
149254
+ * This method transforms the property names using xmlKeys (if defined)
149255
+ * and filters out undefined values.
149256
+ *
149257
+ * @param _ - Context (unused for attributes)
149258
+ * @returns Object with _attr key containing the mapped attributes
149259
+ */
149260
+ prepForXml(_4) {
149261
+ const attrs = {};
149262
+ Object.entries(this.root).forEach(([key, value]) => {
149263
+ if (value !== void 0) {
149264
+ const newKey = this.xmlKeys && this.xmlKeys[key] || key;
149265
+ attrs[newKey] = value;
149266
+ }
149267
+ });
149268
+ return { _attr: attrs };
149345
149269
  }
149346
- const format = await detectZipFormat(zip);
149347
- try {
149348
- if (format === "docx")
149349
- return await convertDocxToHtml(buffer, filename);
149350
- if (format === "pptx")
149351
- return await convertPptxToHtml(buffer, filename);
149352
- } catch (e) {
149353
- return { error: `\u8F6C\u6362 ${filename} \u5931\u8D25\uFF1A${String(e)}` };
149270
+ };
149271
+ var NextAttributeComponent = class extends BaseXmlComponent {
149272
+ /**
149273
+ * Creates a new NextAttributeComponent.
149274
+ *
149275
+ * @param root - Attribute payload with explicit key-value mappings
149276
+ */
149277
+ constructor(root2) {
149278
+ super("_attr");
149279
+ _defineProperty(this, "root", void 0);
149280
+ this.root = root2;
149354
149281
  }
149355
- if (format === "xlsx") {
149356
- return { error: `.xlsx \u65E0 HTML \u515C\u5E95\uFF1Axlsx\u2192PDF \u9700 LibreOffice\uFF08\u672C\u673A\u6216 sidecar\uFF09\uFF0C\u6570\u636E\u67E5\u8BE2\u7528 xlsx-query\u3001\u4EA7\u51FA\u62A5\u544A\u7528 doc-gen` };
149357
- }
149358
- return { error: `\u4E0D\u652F\u6301 ${filename} \u7684\u6587\u4EF6\u683C\u5F0F\uFF08doc-convert \u53EA\u652F\u6301 .docx/.pptx\uFF09` };
149359
- }
149360
-
149361
- // packages/core/dist/fs/soffice.js
149362
- var import_node_child_process = require("node:child_process");
149363
- var import_node_fs = require("node:fs");
149364
- var import_promises = require("node:fs/promises");
149365
- var import_node_os = require("node:os");
149366
- var import_node_path = require("node:path");
149367
- var import_node_url = require("node:url");
149368
- var MAC_CANDIDATES = ["/Applications/LibreOffice.app/Contents/MacOS/soffice"];
149369
- var WIN_CANDIDATES = [
149370
- "C:\\Program Files\\LibreOffice\\program\\soffice.com",
149371
- "C:\\Program Files (x86)\\LibreOffice\\program\\soffice.com"
149372
- ];
149373
- var PATH_NAMES = {
149374
- win32: ["soffice.com", "soffice.exe"],
149375
- darwin: ["soffice"],
149376
- linux: ["soffice", "libreoffice"]
149377
- };
149378
- var SOFFICE_DISABLE_VALUES = /* @__PURE__ */ new Set(["off", "none", "0", "false", "disabled"]);
149379
- function resolveSoffice(deps = {}) {
149380
- const env2 = deps.env ?? process.env;
149381
- const platform = deps.platform ?? process.platform;
149382
- const exists = deps.exists ?? import_node_fs.existsSync;
149383
- const override = env2.TALOS_SOFFICE;
149384
- if (override && SOFFICE_DISABLE_VALUES.has(override.trim().toLowerCase()))
149385
- return null;
149386
- if (override && exists(override))
149387
- return override;
149388
- const installed = platform === "darwin" ? MAC_CANDIDATES : platform === "win32" ? WIN_CANDIDATES : [];
149389
- for (const c of installed)
149390
- if (exists(c))
149391
- return c;
149392
- const pathMod = platform === "win32" ? import_node_path.win32 : import_node_path.posix;
149393
- const names = PATH_NAMES[platform] ?? PATH_NAMES.linux;
149394
- for (const dir of (env2.PATH ?? "").split(pathMod.delimiter)) {
149395
- if (!dir)
149396
- continue;
149397
- for (const name of names) {
149398
- const p = pathMod.join(dir, name);
149399
- if (exists(p))
149400
- return p;
149401
- }
149402
- }
149403
- return null;
149404
- }
149405
- var PDF_FILTER_BY_EXT = {
149406
- ".docx": "writer_pdf_Export",
149407
- ".doc": "writer_pdf_Export",
149408
- ".odt": "writer_pdf_Export",
149409
- ".rtf": "writer_pdf_Export",
149410
- ".txt": "writer_pdf_Export",
149411
- ".html": "writer_pdf_Export",
149412
- ".htm": "writer_pdf_Export",
149413
- ".pptx": "impress_pdf_Export",
149414
- ".ppt": "impress_pdf_Export",
149415
- ".odp": "impress_pdf_Export",
149416
- ".xlsx": "calc_pdf_Export",
149417
- ".xls": "calc_pdf_Export",
149418
- ".ods": "calc_pdf_Export",
149419
- ".csv": "calc_pdf_Export"
149420
- };
149421
- var PDF_EXPORT_FILTER_DATA = { EmbedStandardFonts: { type: "boolean", value: "true" } };
149422
- function pdfExportArg(inputPath) {
149423
- const filter2 = PDF_FILTER_BY_EXT[(0, import_node_path.extname)(inputPath).toLowerCase()];
149424
- if (!filter2)
149425
- return "pdf";
149426
- return `pdf:${filter2}:${JSON.stringify(PDF_EXPORT_FILTER_DATA)}`;
149427
- }
149428
- function sofficeTimeoutMs(bytes) {
149429
- const base = 9e4;
149430
- const perMb = 12e3;
149431
- const mb = Math.max(0, bytes) / (1024 * 1024);
149432
- return Math.min(6e5, Math.round(base + mb * perMb));
149433
- }
149434
- function pickConvertedPdf(pdfNames, inputPath) {
149435
- if (pdfNames.length === 0)
149436
- return null;
149437
- const stem = (0, import_node_path.basename)(inputPath, (0, import_node_path.extname)(inputPath)).toLowerCase();
149438
- const nameStem = (n) => (0, import_node_path.basename)(n, (0, import_node_path.extname)(n)).toLowerCase();
149439
- const exact = pdfNames.find((n) => nameStem(n) === stem);
149440
- if (exact)
149441
- return exact;
149442
- if (pdfNames.length === 1)
149443
- return pdfNames[0];
149444
- const related = pdfNames.find((n) => nameStem(n).startsWith(stem) || stem.startsWith(nameStem(n)));
149445
- return related ?? [...pdfNames].sort()[0];
149446
- }
149447
- async function convertToPdfViaSoffice(inputPath, options = {}) {
149448
- const soffice = options.sofficePath ?? resolveSoffice();
149449
- if (!soffice)
149450
- throw new Error("LibreOffice (soffice) not found");
149451
- if (!(0, import_node_fs.existsSync)(inputPath))
149452
- throw new Error(`input not found: ${inputPath}`);
149453
- const profileDir = await (0, import_promises.mkdtemp)((0, import_node_path.join)((0, import_node_os.tmpdir)(), "talos-lo-profile-"));
149454
- const outDir = await (0, import_promises.mkdtemp)((0, import_node_path.join)((0, import_node_os.tmpdir)(), "talos-lo-out-"));
149455
- try {
149456
- await runSoffice(soffice, [
149457
- "--headless",
149458
- "--norestore",
149459
- "--nolockcheck",
149460
- "--nodefault",
149461
- "--nofirststartwizard",
149462
- `-env:UserInstallation=${(0, import_node_url.pathToFileURL)(profileDir).href}`,
149463
- "--convert-to",
149464
- pdfExportArg(inputPath),
149465
- "--outdir",
149466
- outDir,
149467
- inputPath
149468
- ], options.timeoutMs ?? sofficeTimeoutMs((0, import_node_fs.statSync)(inputPath).size));
149469
- const pdfs = (await (0, import_promises.readdir)(outDir)).filter((f) => f.toLowerCase().endsWith(".pdf"));
149470
- const chosen = pickConvertedPdf(pdfs, inputPath);
149471
- if (!chosen)
149472
- throw new Error("LibreOffice produced no PDF (unsupported input?)");
149473
- return await (0, import_promises.readFile)((0, import_node_path.join)(outDir, chosen));
149474
- } finally {
149475
- await (0, import_promises.rm)(profileDir, { recursive: true, force: true }).catch(() => {
149476
- });
149477
- await (0, import_promises.rm)(outDir, { recursive: true, force: true }).catch(() => {
149478
- });
149479
- }
149480
- }
149481
- function runSoffice(bin, args, timeoutMs) {
149482
- return new Promise((resolve, reject2) => {
149483
- const child = (0, import_node_child_process.spawn)(bin, args, { stdio: ["ignore", "pipe", "pipe"] });
149484
- let stderr = "";
149485
- const timer = setTimeout(() => {
149486
- child.kill("SIGKILL");
149487
- reject2(new Error(`LibreOffice timed out after ${timeoutMs}ms`));
149488
- }, timeoutMs);
149489
- child.stderr?.on("data", (c) => {
149490
- if (stderr.length < 4096)
149491
- stderr += String(c);
149492
- });
149493
- child.on("error", (err) => {
149494
- clearTimeout(timer);
149495
- reject2(err);
149496
- });
149497
- child.on("close", (code) => {
149498
- clearTimeout(timer);
149499
- if (code === 0)
149500
- resolve();
149501
- else
149502
- reject2(new Error(`LibreOffice exited ${code}${stderr ? `: ${stderr.trim()}` : ""}`));
149503
- });
149504
- });
149505
- }
149506
-
149507
- // packages/core/dist/fs/office-service.js
149508
- async function convertViaOfficeService(bytes, filename, url, options = {}) {
149509
- const doFetch = options.fetchImpl ?? fetch;
149510
- const view = bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes);
149511
- const part = new Uint8Array(view.byteLength);
149512
- part.set(view);
149513
- const form = new FormData();
149514
- form.append("files", new Blob([part]), filename);
149515
- const controller = new AbortController();
149516
- const timer = options.timeoutMs && options.timeoutMs > 0 ? setTimeout(() => controller.abort(), options.timeoutMs) : void 0;
149517
- try {
149518
- const res = await doFetch(url, {
149519
- method: "POST",
149520
- headers: options.token ? { authorization: `Bearer ${options.token}` } : {},
149521
- body: form,
149522
- signal: controller.signal
149523
- });
149524
- if (!res.ok)
149525
- throw new Error(`office service HTTP ${res.status}`);
149526
- return new Uint8Array(await res.arrayBuffer());
149527
- } finally {
149528
- if (timer)
149529
- clearTimeout(timer);
149530
- }
149531
- }
149532
-
149533
- // node_modules/docx/dist/index.mjs
149534
- var __create2 = Object.create;
149535
- var __defProp2 = Object.defineProperty;
149536
- var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
149537
- var __getOwnPropNames2 = Object.getOwnPropertyNames;
149538
- var __getProtoOf2 = Object.getPrototypeOf;
149539
- var __hasOwnProp2 = Object.prototype.hasOwnProperty;
149540
- var __esmMin = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
149541
- var __commonJSMin = (cb2, mod) => () => (mod || (cb2((mod = { exports: {} }).exports, mod), cb2 = null), mod.exports);
149542
- var __copyProps2 = (to, from, except, desc) => {
149543
- if (from && typeof from === "object" || typeof from === "function") for (var keys2 = __getOwnPropNames2(from), i = 0, n = keys2.length, key; i < n; i++) {
149544
- key = keys2[i];
149545
- if (!__hasOwnProp2.call(to, key) && key !== except) __defProp2(to, key, {
149546
- get: ((k) => from[k]).bind(null, key),
149547
- enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable
149548
- });
149549
- }
149550
- return to;
149551
- };
149552
- var __toESM2 = (mod, isNodeMode, target) => (target = mod != null ? __create2(__getProtoOf2(mod)) : {}, __copyProps2(isNodeMode || !mod || !mod.__esModule ? __defProp2(target, "default", {
149553
- value: mod,
149554
- enumerable: true
149555
- }) : target, mod));
149556
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, { get: (a, b) => (typeof require !== "undefined" ? require : a)[b] }) : x)(function(x) {
149557
- if (typeof require !== "undefined") return require.apply(this, arguments);
149558
- throw Error('Calling `require` for "' + x + "\" in an environment that doesn't expose the `require` function. See https://rolldown.rs/in-depth/bundling-cjs#require-external-modules for more details.");
149559
- });
149560
- function _typeof(o) {
149561
- "@babel/helpers - typeof";
149562
- return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o2) {
149563
- return typeof o2;
149564
- } : function(o2) {
149565
- return o2 && "function" == typeof Symbol && o2.constructor === Symbol && o2 !== Symbol.prototype ? "symbol" : typeof o2;
149566
- }, _typeof(o);
149567
- }
149568
- function toPrimitive(t, r) {
149569
- if ("object" != _typeof(t) || !t) return t;
149570
- var e = t[Symbol.toPrimitive];
149571
- if (void 0 !== e) {
149572
- var i = e.call(t, r || "default");
149573
- if ("object" != _typeof(i)) return i;
149574
- throw new TypeError("@@toPrimitive must return a primitive value.");
149575
- }
149576
- return ("string" === r ? String : Number)(t);
149577
- }
149578
- function toPropertyKey(t) {
149579
- var i = toPrimitive(t, "string");
149580
- return "symbol" == _typeof(i) ? i : i + "";
149581
- }
149582
- function _defineProperty(e, r, t) {
149583
- return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
149584
- value: t,
149585
- enumerable: true,
149586
- configurable: true,
149587
- writable: true
149588
- }) : e[r] = t, e;
149589
- }
149590
- var BaseXmlComponent = class {
149591
- /**
149592
- * Creates a new BaseXmlComponent with the specified XML element name.
149593
- *
149594
- * @param rootKey - The XML element name (e.g., "w:p", "w:r", "w:t")
149595
- */
149596
- constructor(rootKey) {
149597
- _defineProperty(
149598
- this,
149599
- /** The XML element name for this component (e.g., "w:p" for paragraph). */
149600
- "rootKey",
149601
- void 0
149602
- );
149603
- this.rootKey = rootKey;
149604
- }
149605
- };
149606
- var EMPTY_OBJECT = Object.seal({});
149607
- var XmlComponent = class extends BaseXmlComponent {
149608
- /**
149609
- * Creates a new XmlComponent.
149610
- *
149611
- * @param rootKey - The XML element name (e.g., "w:p", "w:r", "w:t")
149612
- */
149613
- constructor(rootKey) {
149614
- super(rootKey);
149615
- _defineProperty(
149616
- this,
149617
- /**
149618
- * Array of child components, text nodes, and attributes.
149619
- *
149620
- * This array forms the content of the XML element. It can contain other
149621
- * XmlComponents, string values (text nodes), or attribute components.
149622
- */
149623
- "root",
149624
- void 0
149625
- );
149626
- this.root = new Array();
149627
- }
149628
- /**
149629
- * Prepares this component and its children for XML serialization.
149630
- *
149631
- * This method is called by the Formatter to convert the component tree into
149632
- * an object structure compatible with the xml library (https://www.npmjs.com/package/xml).
149633
- * It recursively processes all children and handles special cases like
149634
- * attribute-only elements and empty elements.
149635
- *
149636
- * The method can be overridden by subclasses to customize XML representation
149637
- * or execute side effects during serialization (e.g., creating relationships).
149638
- *
149639
- * @param context - The serialization context containing document state
149640
- * @returns The XML-serializable object, or undefined to exclude from output
149641
- *
149642
- * @example
149643
- * ```typescript
149644
- * // Override to add custom serialization logic
149645
- * prepForXml(context: IContext): IXmlableObject | undefined {
149646
- * // Custom logic here
149647
- * return super.prepForXml(context);
149648
- * }
149649
- * ```
149650
- */
149651
- prepForXml(context) {
149652
- var _children$;
149653
- context.stack.push(this);
149654
- const children = this.root.map((comp) => {
149655
- if (comp instanceof BaseXmlComponent) return comp.prepForXml(context);
149656
- return comp;
149657
- }).filter((comp) => comp !== void 0);
149658
- context.stack.pop();
149659
- return { [this.rootKey]: children.length ? children.length === 1 && ((_children$ = children[0]) === null || _children$ === void 0 ? void 0 : _children$._attr) ? children[0] : children : EMPTY_OBJECT };
149660
- }
149661
- /**
149662
- * Adds a child element to this component.
149663
- *
149664
- * @deprecated Do not use this method. It is only used internally by the library. It will be removed in a future version.
149665
- * @param child - The child component or text string to add
149666
- * @returns This component (for chaining)
149667
- */
149668
- addChildElement(child) {
149669
- this.root.push(child);
149670
- return this;
149671
- }
149672
- };
149673
- var IgnoreIfEmptyXmlComponent = class extends XmlComponent {
149674
- constructor(rootKey, includeIfEmpty) {
149675
- super(rootKey);
149676
- _defineProperty(this, "includeIfEmpty", void 0);
149677
- this.includeIfEmpty = includeIfEmpty;
149678
- }
149679
- /**
149680
- * Prepares the component for XML serialization, excluding it if empty.
149681
- *
149682
- * @param context - The serialization context
149683
- * @returns The XML-serializable object, or undefined if empty
149684
- */
149685
- prepForXml(context) {
149686
- const result2 = super.prepForXml(context);
149687
- if (this.includeIfEmpty) return result2;
149688
- if (result2 && (typeof result2[this.rootKey] !== "object" || Object.keys(result2[this.rootKey]).length)) return result2;
149689
- }
149690
- };
149691
- function ownKeys(e, r) {
149692
- var t = Object.keys(e);
149693
- if (Object.getOwnPropertySymbols) {
149694
- var o = Object.getOwnPropertySymbols(e);
149695
- r && (o = o.filter(function(r2) {
149696
- return Object.getOwnPropertyDescriptor(e, r2).enumerable;
149697
- })), t.push.apply(t, o);
149698
- }
149699
- return t;
149700
- }
149701
- function _objectSpread2(e) {
149702
- for (var r = 1; r < arguments.length; r++) {
149703
- var t = null != arguments[r] ? arguments[r] : {};
149704
- r % 2 ? ownKeys(Object(t), true).forEach(function(r2) {
149705
- _defineProperty(e, r2, t[r2]);
149706
- }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function(r2) {
149707
- Object.defineProperty(e, r2, Object.getOwnPropertyDescriptor(t, r2));
149708
- });
149709
- }
149710
- return e;
149711
- }
149712
- var XmlAttributeComponent = class extends BaseXmlComponent {
149713
- /**
149714
- * Creates a new attribute component.
149715
- *
149716
- * @param root - The attribute data object
149717
- */
149718
- constructor(root2) {
149719
- super("_attr");
149720
- _defineProperty(this, "root", void 0);
149721
- _defineProperty(
149722
- this,
149723
- /** Optional mapping from property names to XML attribute names. */
149724
- "xmlKeys",
149725
- void 0
149726
- );
149727
- this.root = root2;
149728
- }
149729
- /**
149730
- * Converts the attribute data to an XML-serializable object.
149731
- *
149732
- * This method transforms the property names using xmlKeys (if defined)
149733
- * and filters out undefined values.
149734
- *
149735
- * @param _ - Context (unused for attributes)
149736
- * @returns Object with _attr key containing the mapped attributes
149737
- */
149738
- prepForXml(_4) {
149739
- const attrs = {};
149740
- Object.entries(this.root).forEach(([key, value]) => {
149741
- if (value !== void 0) {
149742
- const newKey = this.xmlKeys && this.xmlKeys[key] || key;
149743
- attrs[newKey] = value;
149744
- }
149745
- });
149746
- return { _attr: attrs };
149747
- }
149748
- };
149749
- var NextAttributeComponent = class extends BaseXmlComponent {
149750
- /**
149751
- * Creates a new NextAttributeComponent.
149752
- *
149753
- * @param root - Attribute payload with explicit key-value mappings
149754
- */
149755
- constructor(root2) {
149756
- super("_attr");
149757
- _defineProperty(this, "root", void 0);
149758
- this.root = root2;
149759
- }
149760
- /**
149761
- * Converts the attribute payload to an XML-serializable object.
149762
- *
149763
- * Extracts the key and value from each property and filters out
149764
- * undefined values.
149765
- *
149766
- * @param _ - Context (unused for attributes)
149767
- * @returns Object with _attr key containing the attributes
149768
- */
149769
- prepForXml(_4) {
149770
- return { _attr: Object.values(this.root).filter(({ value }) => value !== void 0).reduce((acc, { key, value }) => _objectSpread2(_objectSpread2({}, acc), {}, { [key]: value }), {}) };
149282
+ /**
149283
+ * Converts the attribute payload to an XML-serializable object.
149284
+ *
149285
+ * Extracts the key and value from each property and filters out
149286
+ * undefined values.
149287
+ *
149288
+ * @param _ - Context (unused for attributes)
149289
+ * @returns Object with _attr key containing the attributes
149290
+ */
149291
+ prepForXml(_4) {
149292
+ return { _attr: Object.values(this.root).filter(({ value }) => value !== void 0).reduce((acc, { key, value }) => _objectSpread2(_objectSpread2({}, acc), {}, { [key]: value }), {}) };
149771
149293
  }
149772
149294
  };
149773
149295
  var Attributes = class extends XmlAttributeComponent {
@@ -168581,11 +168103,203 @@ var findPatchKeys = (text) => {
168581
168103
 
168582
168104
  // packages/core/dist/fs/doc-gen.js
168583
168105
  var import_exceljs = __toESM(require_excel(), 1);
168584
- var import_jszip3 = __toESM(require_lib3(), 1);
168106
+ var import_jszip2 = __toESM(require_lib3(), 1);
168585
168107
  var import_pptxgenjs = __toESM(require_pptxgen_cjs(), 1);
168586
168108
  var import_pdf_lib = __toESM(require_cjs(), 1);
168587
168109
  var import_fontkit = __toESM(require_fontkit_umd(), 1);
168588
- var import_node_fs2 = require("node:fs");
168110
+ var import_node_fs = require("node:fs");
168111
+
168112
+ // packages/core/dist/fs/doc-theme.js
168113
+ var DEFAULT_THEME = {
168114
+ bestFor: "",
168115
+ fonts: { heading: "", body: "" },
168116
+ // empty → engine's built-in stack
168117
+ colors: {
168118
+ primary: "#1a1a1a",
168119
+ accent: "#1a1a1a",
168120
+ // kept in sync with primary when the theme defines neither
168121
+ secondary: "#666666",
168122
+ // kept in sync with muted when the theme defines neither
168123
+ text: "#1a1a1a",
168124
+ muted: "#666666",
168125
+ tableHeaderBg: "#f3f3f3",
168126
+ tableBorder: "#bbbbbb"
168127
+ },
168128
+ page: { size: "A4", margin: "20mm", header: "", footer: "" },
168129
+ heading: {
168130
+ h1: { size: 20, color: "text", bold: true, spaceAfter: 12 },
168131
+ h2: { size: 15, color: "text", bold: true, spaceAfter: 8 },
168132
+ h3: { size: 13, color: "text", bold: true, spaceAfter: 6 },
168133
+ h4: { size: 11, color: "text", bold: true, spaceAfter: 6 }
168134
+ },
168135
+ body: { size: 11, lineHeight: 1.6, justify: true },
168136
+ cover: { enabled: false, subtitle: "", date: "", logo: "" },
168137
+ pptx: {
168138
+ background: "#ffffff",
168139
+ titleColor: "#1a1a1a",
168140
+ textColor: "",
168141
+ titleSize: 24,
168142
+ bodySize: 16,
168143
+ logo: "",
168144
+ logoPos: { x: 12.2, y: 0.25, w: 0.8, h: 0.8 },
168145
+ footer: "",
168146
+ slideNumber: false,
168147
+ motif: "none",
168148
+ bgWash: false,
168149
+ depth: false
168150
+ }
168151
+ };
168152
+ var HEX_RE = /^#[0-9a-fA-F]{6}$/;
168153
+ var CSS_LEN_RE = /^\d+(\.\d+)?(mm|cm|in|pt|px)$/;
168154
+ function isFiniteNum(v) {
168155
+ return typeof v === "number" && Number.isFinite(v);
168156
+ }
168157
+ function resolveColor(theme, ref) {
168158
+ if (HEX_RE.test(ref))
168159
+ return ref;
168160
+ const palette = theme.colors;
168161
+ return palette[ref] ?? theme.colors.text;
168162
+ }
168163
+ function resolveTheme(raw) {
168164
+ const warnings = [];
168165
+ const t = structuredClone(DEFAULT_THEME);
168166
+ t.warnings = warnings;
168167
+ if (raw == null)
168168
+ return t;
168169
+ if (typeof raw !== "object" || Array.isArray(raw)) {
168170
+ warnings.push("theme must be a JSON object; using defaults");
168171
+ return t;
168172
+ }
168173
+ const src = raw;
168174
+ const str = (v, path) => {
168175
+ if (v === void 0)
168176
+ return void 0;
168177
+ if (typeof v === "string")
168178
+ return v;
168179
+ warnings.push(`${path}: expected string`);
168180
+ return void 0;
168181
+ };
168182
+ const color = (v, path) => {
168183
+ const s = str(v, path);
168184
+ if (s === void 0)
168185
+ return void 0;
168186
+ if (HEX_RE.test(s) || /^[a-zA-Z][a-zA-Z]*$/.test(s))
168187
+ return s;
168188
+ warnings.push(`${path}: expected "#rrggbb" or a palette key`);
168189
+ return void 0;
168190
+ };
168191
+ const num = (v, path, min2, max2) => {
168192
+ if (v === void 0)
168193
+ return void 0;
168194
+ if (isFiniteNum(v) && v >= min2 && v <= max2)
168195
+ return v;
168196
+ warnings.push(`${path}: expected number in [${min2}, ${max2}]`);
168197
+ return void 0;
168198
+ };
168199
+ const bool = (v, path) => {
168200
+ if (v === void 0)
168201
+ return void 0;
168202
+ if (typeof v === "boolean")
168203
+ return v;
168204
+ warnings.push(`${path}: expected boolean`);
168205
+ return void 0;
168206
+ };
168207
+ t.bestFor = str(src.bestFor, "bestFor") ?? t.bestFor;
168208
+ t.fonts.heading = str(src.fonts?.heading, "fonts.heading") ?? t.fonts.heading;
168209
+ t.fonts.body = str(src.fonts?.body, "fonts.body") ?? t.fonts.body;
168210
+ const colorSet = /* @__PURE__ */ new Set();
168211
+ for (const k of ["primary", "accent", "secondary", "text", "muted", "tableHeaderBg", "tableBorder"]) {
168212
+ const v = src.colors?.[k];
168213
+ if (v === void 0)
168214
+ continue;
168215
+ if (typeof v === "string" && HEX_RE.test(v)) {
168216
+ t.colors[k] = v;
168217
+ colorSet.add(k);
168218
+ } else
168219
+ warnings.push(`colors.${k}: expected "#rrggbb"`);
168220
+ }
168221
+ if (!colorSet.has("accent"))
168222
+ t.colors.accent = t.colors.primary;
168223
+ if (!colorSet.has("secondary"))
168224
+ t.colors.secondary = t.colors.muted;
168225
+ if (src.page?.size !== void 0) {
168226
+ if (src.page.size === "A4" || src.page.size === "Letter")
168227
+ t.page.size = src.page.size;
168228
+ else
168229
+ warnings.push('page.size: expected "A4" | "Letter"');
168230
+ }
168231
+ if (src.page?.margin !== void 0) {
168232
+ if (typeof src.page.margin === "string" && CSS_LEN_RE.test(src.page.margin))
168233
+ t.page.margin = src.page.margin;
168234
+ else
168235
+ warnings.push('page.margin: expected a CSS length like "20mm"');
168236
+ }
168237
+ t.page.header = str(src.page?.header, "page.header") ?? t.page.header;
168238
+ t.page.footer = str(src.page?.footer, "page.footer") ?? t.page.footer;
168239
+ for (const lvl of ["h1", "h2", "h3", "h4"]) {
168240
+ const h = src.heading?.[lvl];
168241
+ if (h === void 0)
168242
+ continue;
168243
+ if (typeof h !== "object" || h === null) {
168244
+ warnings.push(`heading.${lvl}: expected object`);
168245
+ continue;
168246
+ }
168247
+ t.heading[lvl].size = num(h.size, `heading.${lvl}.size`, 6, 96) ?? t.heading[lvl].size;
168248
+ t.heading[lvl].color = color(h.color, `heading.${lvl}.color`) ?? t.heading[lvl].color;
168249
+ t.heading[lvl].bold = bool(h.bold, `heading.${lvl}.bold`) ?? t.heading[lvl].bold;
168250
+ t.heading[lvl].spaceAfter = num(h.spaceAfter, `heading.${lvl}.spaceAfter`, 0, 96) ?? t.heading[lvl].spaceAfter;
168251
+ }
168252
+ t.body.size = num(src.body?.size, "body.size", 6, 48) ?? t.body.size;
168253
+ t.body.lineHeight = num(src.body?.lineHeight, "body.lineHeight", 1, 3) ?? t.body.lineHeight;
168254
+ t.body.justify = bool(src.body?.justify, "body.justify") ?? t.body.justify;
168255
+ t.cover.enabled = bool(src.cover?.enabled, "cover.enabled") ?? t.cover.enabled;
168256
+ t.cover.subtitle = str(src.cover?.subtitle, "cover.subtitle") ?? t.cover.subtitle;
168257
+ t.cover.date = str(src.cover?.date, "cover.date") ?? t.cover.date;
168258
+ t.cover.logo = str(src.cover?.logo, "cover.logo") ?? t.cover.logo;
168259
+ const p = src.pptx;
168260
+ if (p !== void 0) {
168261
+ if (typeof p !== "object" || p === null)
168262
+ warnings.push("pptx: expected object");
168263
+ else {
168264
+ for (const k of ["background", "titleColor", "textColor"]) {
168265
+ const v = p[k];
168266
+ if (v === void 0)
168267
+ continue;
168268
+ if (typeof v === "string" && HEX_RE.test(v))
168269
+ t.pptx[k] = v;
168270
+ else
168271
+ warnings.push(`pptx.${k}: expected "#rrggbb"`);
168272
+ }
168273
+ t.pptx.titleSize = num(p.titleSize, "pptx.titleSize", 8, 60) ?? t.pptx.titleSize;
168274
+ t.pptx.bodySize = num(p.bodySize, "pptx.bodySize", 8, 48) ?? t.pptx.bodySize;
168275
+ t.pptx.logo = str(p.logo, "pptx.logo") ?? t.pptx.logo;
168276
+ if (p.logoPos !== void 0) {
168277
+ const lp = p.logoPos;
168278
+ if (lp && [lp.x, lp.y, lp.w, lp.h].every((v) => isFiniteNum(v) && v >= 0 && v <= 14)) {
168279
+ t.pptx.logoPos = { x: lp.x, y: lp.y, w: lp.w, h: lp.h };
168280
+ } else
168281
+ warnings.push("pptx.logoPos: expected {x,y,w,h} inches within the slide");
168282
+ }
168283
+ t.pptx.footer = str(p.footer, "pptx.footer") ?? t.pptx.footer;
168284
+ t.pptx.slideNumber = bool(p.slideNumber, "pptx.slideNumber") ?? t.pptx.slideNumber;
168285
+ if (p.motif !== void 0) {
168286
+ if (p.motif === "none" || p.motif === "corner" || p.motif === "sidebar")
168287
+ t.pptx.motif = p.motif;
168288
+ else
168289
+ warnings.push('pptx.motif: expected "none" | "corner" | "sidebar"');
168290
+ }
168291
+ t.pptx.bgWash = bool(p.bgWash, "pptx.bgWash") ?? t.pptx.bgWash;
168292
+ t.pptx.depth = bool(p.depth, "pptx.depth") ?? t.pptx.depth;
168293
+ }
168294
+ }
168295
+ return t;
168296
+ }
168297
+ function interpolateTitle(template2, title) {
168298
+ return template2.replaceAll("{title}", title ?? "");
168299
+ }
168300
+ function asTheme(themeInput) {
168301
+ return themeInput && typeof themeInput === "object" && "warnings" in themeInput ? themeInput : resolveTheme(themeInput);
168302
+ }
168589
168303
 
168590
168304
  // packages/core/dist/fs/doc-palette.js
168591
168305
  var PALETTE_LIBRARY = [
@@ -168883,6 +168597,13 @@ function iconSvgDataUri(name, colorHex) {
168883
168597
  function bareHex(c) {
168884
168598
  return c.replace("#", "").toUpperCase();
168885
168599
  }
168600
+ function assertTextDocumentSpec(spec) {
168601
+ if (!spec || typeof spec !== "object")
168602
+ return;
168603
+ if (Object.prototype.hasOwnProperty.call(spec, "section")) {
168604
+ throw new Error("unsupported document field: section (use blocks for DOCX/PDF content; section is PPTX-only)");
168605
+ }
168606
+ }
168886
168607
  var HEADINGS = [HeadingLevel.HEADING_1, HeadingLevel.HEADING_2, HeadingLevel.HEADING_3, HeadingLevel.HEADING_4];
168887
168608
  var ORDERED_REF = "ol";
168888
168609
  var DOCX_TABLE_WIDTH_TWIPS = 9026;
@@ -168960,6 +168681,7 @@ function westFont(name) {
168960
168681
  return name ? { font: { ascii: name, hAnsi: name, cs: name } } : {};
168961
168682
  }
168962
168683
  async function generateDocx(spec, themeInput) {
168684
+ assertTextDocumentSpec(spec);
168963
168685
  const theme = asTheme(themeInput);
168964
168686
  const children = [];
168965
168687
  if (theme.cover.enabled && spec.title) {
@@ -169826,7 +169548,7 @@ function shiftHex(hex, amt) {
169826
169548
  }
169827
169549
  async function injectMasterBranding(bytes, backgroundHex, opts = {}) {
169828
169550
  const { bgWash = false, depth = false, primaryHex } = opts;
169829
- const zip = await import_jszip3.default.loadAsync(Buffer.from(bytes));
169551
+ const zip = await import_jszip2.default.loadAsync(Buffer.from(bytes));
169830
169552
  const fill = bgWash ? `<a:gradFill><a:gsLst><a:gs pos="0"><a:srgbClr val="${backgroundHex}"/></a:gs><a:gs pos="100000"><a:srgbClr val="${shiftHex(backgroundHex, 0.12)}"/></a:gs></a:gsLst><a:lin ang="5400000" scaled="1"/></a:gradFill>` : `<a:solidFill><a:srgbClr val="${backgroundHex}"/></a:solidFill>`;
169831
169553
  const bgXml = `<p:bg><p:bgPr>${fill}<a:effectLst/></p:bgPr></p:bg>`;
169832
169554
  const bgRe = /<p:bg>[\s\S]*?<\/p:bg>/;
@@ -169863,257 +169585,582 @@ async function injectMasterBranding(bytes, backgroundHex, opts = {}) {
169863
169585
  }
169864
169586
  }
169865
169587
  }
169866
- const out = await zip.generateAsync({ type: "nodebuffer", compression: "DEFLATE" });
169867
- return new Uint8Array(out);
169868
- }
169869
- async function finalizePptx(bytes) {
169870
- return stripDanglingOverrides(await normalizeChartParts(bytes));
169588
+ const out = await zip.generateAsync({ type: "nodebuffer", compression: "DEFLATE" });
169589
+ return new Uint8Array(out);
169590
+ }
169591
+ async function finalizePptx(bytes) {
169592
+ return stripDanglingOverrides(await normalizeChartParts(bytes));
169593
+ }
169594
+ async function normalizeChartParts(bytes) {
169595
+ const zip = await import_jszip2.default.loadAsync(Buffer.from(bytes));
169596
+ const pres = zip.file("ppt/presentation.xml");
169597
+ if (pres) {
169598
+ let xml = await pres.async("string");
169599
+ const notes = xml.match(/<p:notesMasterIdLst>[\s\S]*?<\/p:notesMasterIdLst>/);
169600
+ const sldIdx = xml.indexOf("<p:sldIdLst>");
169601
+ if (notes && sldIdx >= 0 && xml.indexOf(notes[0]) > sldIdx) {
169602
+ xml = xml.replace(notes[0], "");
169603
+ xml = xml.replace("<p:sldIdLst>", `${notes[0]}<p:sldIdLst>`);
169604
+ zip.file("ppt/presentation.xml", xml);
169605
+ }
169606
+ }
169607
+ const parts = Object.keys(zip.files).filter((n) => /^(ppt|word|xl)\/charts\/chart\d+\.xml$/.test(n));
169608
+ if (!parts.length && !pres)
169609
+ return bytes;
169610
+ for (const name of parts) {
169611
+ let xml = await zip.file(name).async("string");
169612
+ const isLineArea = /<c:(line|area)Chart>/.test(xml);
169613
+ for (const ct of ["lineChart", "areaChart"]) {
169614
+ xml = xml.replace(new RegExp(`<c:${ct}>(?!\\s*<c:grouping)`, "g"), `<c:${ct}><c:grouping val="standard"/>`);
169615
+ }
169616
+ if (isLineArea) {
169617
+ xml = xml.replace(/<c:invertIfNegative[^>]*\/>/g, "");
169618
+ xml = xml.replace(/<c:ser>[\s\S]*?<\/c:ser>/g, (ser) => {
169619
+ const m = ser.match(/<c:marker>[\s\S]*?<\/c:marker>|<c:marker\s*\/>/);
169620
+ const dpos = ser.indexOf("<c:dLbls");
169621
+ if (!m || dpos < 0 || ser.indexOf(m[0]) < dpos)
169622
+ return ser;
169623
+ const without = ser.replace(m[0], "");
169624
+ const at = without.indexOf("<c:dLbls");
169625
+ return without.slice(0, at) + m[0] + without.slice(at);
169626
+ });
169627
+ }
169628
+ xml = xml.replace(/<c:ser>[\s\S]*?<\/c:ser>/g, (ser) => {
169629
+ const dPts = ser.match(/<c:dPt>[\s\S]*?<\/c:dPt>/g);
169630
+ if (!dPts)
169631
+ return ser;
169632
+ const stripped = ser.replace(/<c:dPt>[\s\S]*?<\/c:dPt>/g, "");
169633
+ for (const anchor of ["<c:dLbls", "<c:trendline", "<c:errBars", "<c:cat>", "<c:val>", "</c:ser>"]) {
169634
+ const pos = stripped.indexOf(anchor);
169635
+ if (pos >= 0)
169636
+ return stripped.slice(0, pos) + dPts.join("") + stripped.slice(pos);
169637
+ }
169638
+ return ser;
169639
+ });
169640
+ const declared = new Set([...xml.matchAll(/<c:(?:catAx|valAx|serAx|dateAx)>\s*<c:axId val="(\d+)"\/>/g)].map((m) => m[1]));
169641
+ xml = xml.replace(/<c:axId val="(\d+)"\/>/g, (m, id) => declared.has(id) ? m : "");
169642
+ zip.file(name, xml);
169643
+ }
169644
+ const out = await zip.generateAsync({ type: "nodebuffer", compression: "DEFLATE" });
169645
+ return new Uint8Array(out);
169646
+ }
169647
+ async function stripDanglingOverrides(bytes) {
169648
+ const zip = await import_jszip2.default.loadAsync(Buffer.from(bytes));
169649
+ const ctFile = zip.file("[Content_Types].xml");
169650
+ if (!ctFile)
169651
+ return bytes;
169652
+ const ct = await ctFile.async("string");
169653
+ const cleaned = ct.replace(/<Override\b[^>]*PartName="\/([^"]+)"[^>]*\/>/g, (m, part) => zip.file(part) ? m : "");
169654
+ if (cleaned === ct)
169655
+ return bytes;
169656
+ zip.file("[Content_Types].xml", cleaned);
169657
+ return new Uint8Array(await zip.generateAsync({ type: "nodebuffer", compression: "DEFLATE" }));
169658
+ }
169659
+ function dataUri(b64) {
169660
+ return b64.startsWith("data:") ? b64 : `data:image/png;base64,${b64}`;
169661
+ }
169662
+ var SYSTEM_UNICODE_FONTS = [
169663
+ "/System/Library/Fonts/Supplemental/Arial Unicode.ttf",
169664
+ // macOS — broad CJK
169665
+ "C:\\Windows\\Fonts\\arialuni.ttf",
169666
+ "C:\\Windows\\Fonts\\msyh.ttc",
169667
+ "C:\\Windows\\Fonts\\simsun.ttc",
169668
+ "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc",
169669
+ "/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc"
169670
+ ];
169671
+ function resolveUnicodeFontPath(spec) {
169672
+ const explicit = spec.fontPath || process.env.TALOS_PDF_FONT;
169673
+ if (explicit)
169674
+ return explicit;
169675
+ return SYSTEM_UNICODE_FONTS.find((p) => (0, import_node_fs.existsSync)(p));
169676
+ }
169677
+ function canEncode(font, text) {
169678
+ try {
169679
+ font.encodeText(text);
169680
+ return true;
169681
+ } catch {
169682
+ return false;
169683
+ }
169684
+ }
169685
+ var PAGE_W = 595.28;
169686
+ var PAGE_H = 841.89;
169687
+ var MARGIN = 56;
169688
+ var CONTENT_W = PAGE_W - MARGIN * 2;
169689
+ function isCjk(cp) {
169690
+ return cp >= 11904 && cp <= 12351 || cp >= 12352 && cp <= 12543 || cp >= 13312 && cp <= 19903 || cp >= 19968 && cp <= 40959 || cp >= 63744 && cp <= 64255 || cp >= 65280 && cp <= 65519 || cp >= 131072 && cp <= 195103;
169691
+ }
169692
+ function foldFullwidthAlnum(s) {
169693
+ return s.replace(/[0-9A-Za-z]/g, (c) => String.fromCharCode(c.charCodeAt(0) - 65248)).replace(/ /g, " ");
169694
+ }
169695
+ function atomize(text) {
169696
+ const chars = [...text];
169697
+ const atoms = [];
169698
+ for (let i = 0; i < chars.length; ) {
169699
+ const ch = chars[i];
169700
+ if (ch === " " || ch === " ") {
169701
+ atoms.push({ kind: "space" });
169702
+ i++;
169703
+ continue;
169704
+ }
169705
+ if (isCjk(ch.codePointAt(0))) {
169706
+ atoms.push({ kind: "cjk", text: ch });
169707
+ i++;
169708
+ continue;
169709
+ }
169710
+ let j = i;
169711
+ while (j < chars.length && chars[j] !== " " && chars[j] !== " " && !isCjk(chars[j].codePointAt(0)))
169712
+ j++;
169713
+ atoms.push({ kind: "latin", text: chars.slice(i, j).join("") });
169714
+ i = j;
169715
+ }
169716
+ return atoms;
169717
+ }
169718
+ function layoutSegment(segment, style, fonts) {
169719
+ const latin = style.bold ? fonts.latinBold : fonts.latin;
169720
+ const w = (t, f) => f.widthOfTextAtSize(t, style.size);
169721
+ const pick = (a) => a.kind === "cjk" ? fonts.cjk ?? latin : fonts.cjk && !canEncode(latin, a.text) ? fonts.cjk : latin;
169722
+ const lines = [];
169723
+ let cur = [];
169724
+ let curW = 0;
169725
+ const flush = () => {
169726
+ lines.push(cur);
169727
+ cur = [];
169728
+ curW = 0;
169729
+ };
169730
+ const add = (t, f) => {
169731
+ const width = w(t, f);
169732
+ const last2 = cur[cur.length - 1];
169733
+ if (last2 && last2.font === f) {
169734
+ last2.text += t;
169735
+ last2.width += width;
169736
+ } else
169737
+ cur.push({ text: t, font: f, width });
169738
+ curW += width;
169739
+ };
169740
+ for (const a of atomize(segment)) {
169741
+ if (a.kind === "space") {
169742
+ if (curW === 0)
169743
+ continue;
169744
+ const sw = w(" ", latin);
169745
+ if (curW + sw > CONTENT_W) {
169746
+ flush();
169747
+ continue;
169748
+ }
169749
+ add(" ", latin);
169750
+ continue;
169751
+ }
169752
+ const f = pick(a);
169753
+ if (curW > 0 && curW + w(a.text, f) > CONTENT_W)
169754
+ flush();
169755
+ add(a.text, f);
169756
+ }
169757
+ flush();
169758
+ return lines;
169759
+ }
169760
+ function hexRgb(c) {
169761
+ const n = parseInt(c.replace("#", ""), 16);
169762
+ return (0, import_pdf_lib.rgb)((n >> 16 & 255) / 255, (n >> 8 & 255) / 255, (n & 255) / 255);
169763
+ }
169764
+ async function generatePdf(spec, themeInput) {
169765
+ assertTextDocumentSpec(spec);
169766
+ const theme = asTheme(themeInput);
169767
+ const doc = await import_pdf_lib.PDFDocument.create();
169768
+ const fonts = {
169769
+ latin: await doc.embedFont(import_pdf_lib.StandardFonts.Helvetica),
169770
+ latinBold: await doc.embedFont(import_pdf_lib.StandardFonts.HelveticaBold)
169771
+ };
169772
+ const headingStyle = {
169773
+ size: theme.heading.h1.size,
169774
+ bold: theme.heading.h1.bold,
169775
+ lineHeight: Math.round(theme.heading.h1.size * 1.35),
169776
+ spaceAfter: theme.heading.h1.spaceAfter
169777
+ };
169778
+ const bodyStyle = {
169779
+ size: theme.body.size,
169780
+ bold: false,
169781
+ lineHeight: Math.round(theme.body.size * theme.body.lineHeight),
169782
+ spaceAfter: 8
169783
+ };
169784
+ const headingColor = hexRgb(resolveColor(theme, theme.heading.h1.color));
169785
+ const textColor = hexRgb(theme.colors.text);
169786
+ const blocks = [];
169787
+ if (spec.title)
169788
+ blocks.push({ text: foldFullwidthAlnum(String(spec.title)), style: headingStyle, color: headingColor });
169789
+ for (const p of spec.paragraphs ?? [])
169790
+ blocks.push({ text: foldFullwidthAlnum(String(p)), style: bodyStyle, color: textColor });
169791
+ for (const block of spec.blocks ?? []) {
169792
+ switch (block.type) {
169793
+ case "heading": {
169794
+ const level = Math.min(Math.max(block.level ?? 1, 1), 4);
169795
+ const key = `h${level}`;
169796
+ const h = theme.heading[key];
169797
+ blocks.push({
169798
+ text: foldFullwidthAlnum(String(block.text)),
169799
+ style: { size: h.size, bold: h.bold, lineHeight: Math.round(h.size * 1.35), spaceAfter: h.spaceAfter },
169800
+ color: hexRgb(resolveColor(theme, h.color))
169801
+ });
169802
+ break;
169803
+ }
169804
+ case "paragraph":
169805
+ blocks.push({ text: foldFullwidthAlnum(String(block.text)), style: { ...bodyStyle, bold: Boolean(block.bold) }, color: textColor });
169806
+ break;
169807
+ case "list":
169808
+ for (const [index, item] of (block.items ?? []).entries()) {
169809
+ blocks.push({
169810
+ // Use an ASCII marker here: the fallback may have no Unicode font
169811
+ // available, while the Chromium HTML path renders real list markers.
169812
+ text: foldFullwidthAlnum(`${block.ordered ? `${index + 1}.` : "-"} ${String(item)}`),
169813
+ style: bodyStyle,
169814
+ color: textColor
169815
+ });
169816
+ }
169817
+ break;
169818
+ case "table":
169819
+ for (const row of block.rows ?? []) {
169820
+ blocks.push({ text: foldFullwidthAlnum(row.map(String).join(" ")), style: bodyStyle, color: textColor });
169821
+ }
169822
+ break;
169823
+ case "image":
169824
+ break;
169825
+ default:
169826
+ throw new Error(`unhandled block type: ${block.type}`);
169827
+ }
169828
+ }
169829
+ const segments = blocks.flatMap((b) => b.text.split(/\r?\n/));
169830
+ if (segments.some((s) => !canEncode(fonts.latin, s))) {
169831
+ const fontPath = resolveUnicodeFontPath(spec);
169832
+ if (!fontPath) {
169833
+ throw new Error("PDF text needs a Unicode font (non-Latin / CJK) but none was found. Set TALOS_PDF_FONT (or spec.fontPath) to a .ttf/.otf covering it, or generate a .docx instead.");
169834
+ }
169835
+ let bytes;
169836
+ try {
169837
+ bytes = (0, import_node_fs.readFileSync)(fontPath);
169838
+ } catch (e) {
169839
+ throw new Error(`cannot read PDF font at ${fontPath}: ${e.message}`);
169840
+ }
169841
+ doc.registerFontkit(import_fontkit.default);
169842
+ fonts.cjk = await doc.embedFont(bytes, { subset: true });
169843
+ }
169844
+ let page = doc.addPage([PAGE_W, PAGE_H]);
169845
+ let y = PAGE_H - MARGIN;
169846
+ for (const block of blocks) {
169847
+ for (const seg of block.text.split(/\r?\n/)) {
169848
+ for (const runs of layoutSegment(seg, block.style, fonts)) {
169849
+ if (y - block.style.lineHeight < MARGIN) {
169850
+ page = doc.addPage([PAGE_W, PAGE_H]);
169851
+ y = PAGE_H - MARGIN;
169852
+ }
169853
+ let x = MARGIN;
169854
+ const baseline = y - block.style.size;
169855
+ for (const run of runs) {
169856
+ page.drawText(run.text, { x, y: baseline, size: block.style.size, font: run.font, color: block.color });
169857
+ x += run.width;
169858
+ }
169859
+ y -= block.style.lineHeight;
169860
+ }
169861
+ }
169862
+ y -= block.style.spaceAfter;
169863
+ }
169864
+ return doc.save();
169871
169865
  }
169872
- async function normalizeChartParts(bytes) {
169873
- const zip = await import_jszip3.default.loadAsync(Buffer.from(bytes));
169874
- const pres = zip.file("ppt/presentation.xml");
169875
- if (pres) {
169876
- let xml = await pres.async("string");
169877
- const notes = xml.match(/<p:notesMasterIdLst>[\s\S]*?<\/p:notesMasterIdLst>/);
169878
- const sldIdx = xml.indexOf("<p:sldIdLst>");
169879
- if (notes && sldIdx >= 0 && xml.indexOf(notes[0]) > sldIdx) {
169880
- xml = xml.replace(notes[0], "");
169881
- xml = xml.replace("<p:sldIdLst>", `${notes[0]}<p:sldIdLst>`);
169882
- zip.file("ppt/presentation.xml", xml);
169883
- }
169884
- }
169885
- const parts = Object.keys(zip.files).filter((n) => /^(ppt|word|xl)\/charts\/chart\d+\.xml$/.test(n));
169886
- if (!parts.length && !pres)
169887
- return bytes;
169888
- for (const name of parts) {
169889
- let xml = await zip.file(name).async("string");
169890
- const isLineArea = /<c:(line|area)Chart>/.test(xml);
169891
- for (const ct of ["lineChart", "areaChart"]) {
169892
- xml = xml.replace(new RegExp(`<c:${ct}>(?!\\s*<c:grouping)`, "g"), `<c:${ct}><c:grouping val="standard"/>`);
169893
- }
169894
- if (isLineArea) {
169895
- xml = xml.replace(/<c:invertIfNegative[^>]*\/>/g, "");
169896
- xml = xml.replace(/<c:ser>[\s\S]*?<\/c:ser>/g, (ser) => {
169897
- const m = ser.match(/<c:marker>[\s\S]*?<\/c:marker>|<c:marker\s*\/>/);
169898
- const dpos = ser.indexOf("<c:dLbls");
169899
- if (!m || dpos < 0 || ser.indexOf(m[0]) < dpos)
169900
- return ser;
169901
- const without = ser.replace(m[0], "");
169902
- const at = without.indexOf("<c:dLbls");
169903
- return without.slice(0, at) + m[0] + without.slice(at);
169904
- });
169905
- }
169906
- xml = xml.replace(/<c:ser>[\s\S]*?<\/c:ser>/g, (ser) => {
169907
- const dPts = ser.match(/<c:dPt>[\s\S]*?<\/c:dPt>/g);
169908
- if (!dPts)
169909
- return ser;
169910
- const stripped = ser.replace(/<c:dPt>[\s\S]*?<\/c:dPt>/g, "");
169911
- for (const anchor of ["<c:dLbls", "<c:trendline", "<c:errBars", "<c:cat>", "<c:val>", "</c:ser>"]) {
169912
- const pos = stripped.indexOf(anchor);
169913
- if (pos >= 0)
169914
- return stripped.slice(0, pos) + dPts.join("") + stripped.slice(pos);
169915
- }
169916
- return ser;
169917
- });
169918
- const declared = new Set([...xml.matchAll(/<c:(?:catAx|valAx|serAx|dateAx)>\s*<c:axId val="(\d+)"\/>/g)].map((m) => m[1]));
169919
- xml = xml.replace(/<c:axId val="(\d+)"\/>/g, (m, id) => declared.has(id) ? m : "");
169920
- zip.file(name, xml);
169866
+ async function generateDocument(kind, spec, theme) {
169867
+ switch (kind) {
169868
+ case "docx":
169869
+ return generateDocx(spec, theme);
169870
+ case "xlsx":
169871
+ return generateXlsx(spec);
169872
+ case "pptx":
169873
+ return generatePptx(spec, theme);
169874
+ case "pdf":
169875
+ return generatePdf(spec, theme);
169876
+ default:
169877
+ throw new Error(`unsupported kind: ${String(kind)}`);
169921
169878
  }
169922
- const out = await zip.generateAsync({ type: "nodebuffer", compression: "DEFLATE" });
169923
- return new Uint8Array(out);
169924
169879
  }
169925
- async function stripDanglingOverrides(bytes) {
169926
- const zip = await import_jszip3.default.loadAsync(Buffer.from(bytes));
169927
- const ctFile = zip.file("[Content_Types].xml");
169928
- if (!ctFile)
169929
- return bytes;
169930
- const ct = await ctFile.async("string");
169931
- const cleaned = ct.replace(/<Override\b[^>]*PartName="\/([^"]+)"[^>]*\/>/g, (m, part) => zip.file(part) ? m : "");
169932
- if (cleaned === ct)
169933
- return bytes;
169934
- zip.file("[Content_Types].xml", cleaned);
169935
- return new Uint8Array(await zip.generateAsync({ type: "nodebuffer", compression: "DEFLATE" }));
169880
+
169881
+ // packages/core/dist/fs/doc-html.js
169882
+ var FONT_STACK = 'TalosCJK, "Helvetica Neue", Helvetica, Arial, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans CJK SC", "Source Han Sans SC", "WenQuanYi Zen Hei", sans-serif';
169883
+
169884
+ // packages/core/dist/fs/doc-convert.js
169885
+ var PRINT_STYLE = `
169886
+ @page { size: A4; margin: 20mm 18mm; }
169887
+ * { box-sizing: border-box; }
169888
+ html { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
169889
+ body { font-family: ${FONT_STACK}; font-size: 11pt; line-height: 1.55; color: #1a1a1a; margin: 0; }
169890
+ h1 { font-size: 20pt; margin: 0 0 10pt; line-height: 1.3; }
169891
+ h2 { font-size: 15.5pt; margin: 14pt 0 6pt; }
169892
+ h3 { font-size: 13pt; margin: 12pt 0 5pt; }
169893
+ h4, h5, h6 { font-size: 11.5pt; margin: 10pt 0 4pt; }
169894
+ p { margin: 0 0 7pt; overflow-wrap: break-word; }
169895
+ ul, ol { margin: 0 0 7pt; padding-left: 22pt; }
169896
+ li { margin: 0 0 3pt; }
169897
+ table { border-collapse: collapse; width: 100%; margin: 8pt 0; font-size: 10.5pt; }
169898
+ th, td { border: 1px solid #b9b9b9; padding: 4pt 8pt; text-align: left; vertical-align: top; }
169899
+ th { background: #f2f2f2; font-weight: 700; }
169900
+ img { max-width: 100%; }
169901
+ .slide { page-break-after: always; }
169902
+ .slide:last-child { page-break-after: auto; }
169903
+ .slide-no { color: #999; font-size: 8pt; margin: 0 0 6pt; }
169904
+ `.trim();
169905
+ function htmlShell(bodyHtml, title) {
169906
+ const head = `<meta charset="utf-8">` + (title ? `<title>${escapeHtml(title)}</title>` : "") + `<style>${PRINT_STYLE}</style>`;
169907
+ return `<!doctype html><html lang="zh"><head>${head}</head><body>${bodyHtml}</body></html>`;
169936
169908
  }
169937
- function dataUri(b64) {
169938
- return b64.startsWith("data:") ? b64 : `data:image/png;base64,${b64}`;
169909
+ function escapeHtml(s) {
169910
+ return s.replace(/[&<>"]/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;" })[c]);
169939
169911
  }
169940
- var SYSTEM_UNICODE_FONTS = [
169941
- "/System/Library/Fonts/Supplemental/Arial Unicode.ttf",
169942
- // macOS — broad CJK
169943
- "C:\\Windows\\Fonts\\arialuni.ttf",
169944
- "C:\\Windows\\Fonts\\msyh.ttc",
169945
- "C:\\Windows\\Fonts\\simsun.ttc",
169946
- "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc",
169947
- "/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc"
169948
- ];
169949
- function resolveUnicodeFontPath(spec) {
169950
- const explicit = spec.fontPath || process.env.TALOS_PDF_FONT;
169951
- if (explicit)
169952
- return explicit;
169953
- return SYSTEM_UNICODE_FONTS.find((p) => (0, import_node_fs2.existsSync)(p));
169912
+ function titleFromFilename(filename) {
169913
+ const base = filename.split(/[\\/]/).pop() ?? filename;
169914
+ const stem = base.replace(/\.[^.]+$/, "").trim();
169915
+ return stem || void 0;
169954
169916
  }
169955
- function canEncode(font, text) {
169917
+ function htmlToParagraphs(html) {
169918
+ const text = html.replace(/<\/(h[1-6]|p|li|tr)>/gi, "\n").replace(/<br[^>]*\/?>/gi, "\n").replace(/<\/t[dh]>/gi, " ").replace(/<[^>]+>/g, "").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&amp;/g, "&").replace(/&nbsp;/g, " ");
169919
+ return text.split(/\n+/).map((line) => line.replace(/\t+/g, " ").trim()).filter((line) => line.length > 0);
169920
+ }
169921
+ async function convertDocxToHtml(buffer, filename) {
169922
+ const result2 = await import_mammoth2.default.convertToHtml({ buffer: Buffer.from(buffer) }, {
169923
+ convertImage: import_mammoth2.default.images.imgElement(async (image) => ({
169924
+ src: `data:${image.contentType};base64,${await image.read("base64")}`
169925
+ }))
169926
+ });
169927
+ const bodyHtml = result2.value;
169928
+ return {
169929
+ kind: "docx",
169930
+ html: htmlShell(bodyHtml, titleFromFilename(filename)),
169931
+ fallbackSpec: { title: titleFromFilename(filename), paragraphs: htmlToParagraphs(bodyHtml) },
169932
+ warnings: (result2.messages ?? []).map((m) => `${m.type ?? "warning"}: ${m.message ?? ""}`)
169933
+ };
169934
+ }
169935
+ async function convertPptxToHtml(buffer, filename) {
169936
+ const zip = await import_jszip3.default.loadAsync(buffer);
169937
+ const slideFiles = Object.keys(zip.files).filter((f) => /^ppt\/slides\/slide\d+\.xml$/.test(f)).sort((a, b) => slideNumber(a) - slideNumber(b));
169938
+ const sections = [];
169939
+ const fallbackParagraphs = [];
169940
+ for (const slidePath of slideFiles) {
169941
+ const num = slideNumber(slidePath);
169942
+ const xml = await zip.file(slidePath).async("string");
169943
+ const paragraphs = extractSlideText(xml).split("\n").filter(Boolean);
169944
+ const imgs = [];
169945
+ const relsPath = `ppt/slides/_rels/slide${num}.xml.rels`;
169946
+ const relsFile = zip.file(relsPath);
169947
+ if (relsFile) {
169948
+ for (const ref of imageRefsFromRels(await relsFile.async("string"))) {
169949
+ const mediaPath = resolveRelTarget(relsPath, ref);
169950
+ const media = zip.file(mediaPath);
169951
+ if (!media)
169952
+ continue;
169953
+ imgs.push(`<img src="data:${mimeFromPath(mediaPath)};base64,${await media.async("base64")}" alt="">`);
169954
+ }
169955
+ }
169956
+ sections.push(`<section class="slide"><div class="slide-no">${num} / ${slideFiles.length}</div>` + paragraphs.map((p) => `<p>${escapeHtml(p)}</p>`).join("") + imgs.join("") + `</section>`);
169957
+ fallbackParagraphs.push(`[\u5E7B\u706F\u7247 ${num}]`, ...paragraphs);
169958
+ }
169959
+ return {
169960
+ kind: "pptx",
169961
+ html: htmlShell(sections.join("\n"), titleFromFilename(filename)),
169962
+ fallbackSpec: { title: titleFromFilename(filename), paragraphs: fallbackParagraphs },
169963
+ warnings: ["pptx conversion is one page per slide (text + images); in-slide layout is not reproduced"]
169964
+ };
169965
+ }
169966
+ async function convertOfficeToPrintable(buffer, filename) {
169967
+ if (buffer.byteLength < 4)
169968
+ return { error: `\u65E0\u6CD5\u8BC6\u522B ${filename} \u7684\u6587\u4EF6\u683C\u5F0F\uFF08\u6587\u4EF6\u8FC7\u5C0F\uFF09` };
169969
+ if (isCompoundDocMagic(buffer)) {
169970
+ return { error: `\u4E0D\u652F\u6301\u65E7\u7248 .doc/.ppt\uFF0C\u8BF7\u5148\u5728\u5BF9\u5E94\u5E94\u7528\u4E2D\u53E6\u5B58\u4E3A .docx/.pptx \u518D\u8F6C\u6362` };
169971
+ }
169972
+ if (!isZipMagic(buffer))
169973
+ return { error: `\u4E0D\u652F\u6301 ${filename} \u7684\u6587\u4EF6\u683C\u5F0F\uFF08doc-convert \u53EA\u652F\u6301 .docx/.pptx\uFF09` };
169974
+ let zip;
169956
169975
  try {
169957
- font.encodeText(text);
169958
- return true;
169976
+ zip = await import_jszip3.default.loadAsync(buffer);
169959
169977
  } catch {
169960
- return false;
169978
+ return { error: `\u65E0\u6CD5\u89E3\u6790 ${filename}\uFF1AZIP \u7ED3\u6784\u635F\u574F` };
169961
169979
  }
169980
+ const format = await detectZipFormat(zip);
169981
+ try {
169982
+ if (format === "docx")
169983
+ return await convertDocxToHtml(buffer, filename);
169984
+ if (format === "pptx")
169985
+ return await convertPptxToHtml(buffer, filename);
169986
+ } catch (e) {
169987
+ return { error: `\u8F6C\u6362 ${filename} \u5931\u8D25\uFF1A${String(e)}` };
169988
+ }
169989
+ if (format === "xlsx") {
169990
+ return { error: `.xlsx \u65E0 HTML \u515C\u5E95\uFF1Axlsx\u2192PDF \u9700 LibreOffice\uFF08\u672C\u673A\u6216 sidecar\uFF09\uFF0C\u6570\u636E\u67E5\u8BE2\u7528 xlsx-query\u3001\u4EA7\u51FA\u62A5\u544A\u7528 doc-gen` };
169991
+ }
169992
+ return { error: `\u4E0D\u652F\u6301 ${filename} \u7684\u6587\u4EF6\u683C\u5F0F\uFF08doc-convert \u53EA\u652F\u6301 .docx/.pptx\uFF09` };
169962
169993
  }
169963
- var PAGE_W = 595.28;
169964
- var PAGE_H = 841.89;
169965
- var MARGIN = 56;
169966
- var CONTENT_W = PAGE_W - MARGIN * 2;
169967
- function isCjk(cp) {
169968
- return cp >= 11904 && cp <= 12351 || cp >= 12352 && cp <= 12543 || cp >= 13312 && cp <= 19903 || cp >= 19968 && cp <= 40959 || cp >= 63744 && cp <= 64255 || cp >= 65280 && cp <= 65519 || cp >= 131072 && cp <= 195103;
169969
- }
169970
- function foldFullwidthAlnum(s) {
169971
- return s.replace(/[0-9A-Za-z]/g, (c) => String.fromCharCode(c.charCodeAt(0) - 65248)).replace(/ /g, " ");
169972
- }
169973
- function atomize(text) {
169974
- const chars = [...text];
169975
- const atoms = [];
169976
- for (let i = 0; i < chars.length; ) {
169977
- const ch = chars[i];
169978
- if (ch === " " || ch === " ") {
169979
- atoms.push({ kind: "space" });
169980
- i++;
169981
- continue;
169982
- }
169983
- if (isCjk(ch.codePointAt(0))) {
169984
- atoms.push({ kind: "cjk", text: ch });
169985
- i++;
169994
+
169995
+ // packages/core/dist/fs/soffice.js
169996
+ var import_node_child_process = require("node:child_process");
169997
+ var import_node_fs2 = require("node:fs");
169998
+ var import_promises = require("node:fs/promises");
169999
+ var import_node_os = require("node:os");
170000
+ var import_node_path = require("node:path");
170001
+ var import_node_url = require("node:url");
170002
+ var MAC_CANDIDATES = ["/Applications/LibreOffice.app/Contents/MacOS/soffice"];
170003
+ var WIN_CANDIDATES = [
170004
+ "C:\\Program Files\\LibreOffice\\program\\soffice.com",
170005
+ "C:\\Program Files (x86)\\LibreOffice\\program\\soffice.com"
170006
+ ];
170007
+ var PATH_NAMES = {
170008
+ win32: ["soffice.com", "soffice.exe"],
170009
+ darwin: ["soffice"],
170010
+ linux: ["soffice", "libreoffice"]
170011
+ };
170012
+ var SOFFICE_DISABLE_VALUES = /* @__PURE__ */ new Set(["off", "none", "0", "false", "disabled"]);
170013
+ function resolveSoffice(deps = {}) {
170014
+ const env2 = deps.env ?? process.env;
170015
+ const platform = deps.platform ?? process.platform;
170016
+ const exists = deps.exists ?? import_node_fs2.existsSync;
170017
+ const override = env2.TALOS_SOFFICE;
170018
+ if (override && SOFFICE_DISABLE_VALUES.has(override.trim().toLowerCase()))
170019
+ return null;
170020
+ if (override && exists(override))
170021
+ return override;
170022
+ const installed = platform === "darwin" ? MAC_CANDIDATES : platform === "win32" ? WIN_CANDIDATES : [];
170023
+ for (const c of installed)
170024
+ if (exists(c))
170025
+ return c;
170026
+ const pathMod = platform === "win32" ? import_node_path.win32 : import_node_path.posix;
170027
+ const names = PATH_NAMES[platform] ?? PATH_NAMES.linux;
170028
+ for (const dir of (env2.PATH ?? "").split(pathMod.delimiter)) {
170029
+ if (!dir)
169986
170030
  continue;
170031
+ for (const name of names) {
170032
+ const p = pathMod.join(dir, name);
170033
+ if (exists(p))
170034
+ return p;
169987
170035
  }
169988
- let j = i;
169989
- while (j < chars.length && chars[j] !== " " && chars[j] !== " " && !isCjk(chars[j].codePointAt(0)))
169990
- j++;
169991
- atoms.push({ kind: "latin", text: chars.slice(i, j).join("") });
169992
- i = j;
169993
170036
  }
169994
- return atoms;
170037
+ return null;
169995
170038
  }
169996
- function layoutSegment(segment, style, fonts) {
169997
- const latin = style.bold ? fonts.latinBold : fonts.latin;
169998
- const w = (t, f) => f.widthOfTextAtSize(t, style.size);
169999
- const pick = (a) => a.kind === "cjk" ? fonts.cjk ?? latin : fonts.cjk && !canEncode(latin, a.text) ? fonts.cjk : latin;
170000
- const lines = [];
170001
- let cur = [];
170002
- let curW = 0;
170003
- const flush = () => {
170004
- lines.push(cur);
170005
- cur = [];
170006
- curW = 0;
170007
- };
170008
- const add = (t, f) => {
170009
- const width = w(t, f);
170010
- const last2 = cur[cur.length - 1];
170011
- if (last2 && last2.font === f) {
170012
- last2.text += t;
170013
- last2.width += width;
170014
- } else
170015
- cur.push({ text: t, font: f, width });
170016
- curW += width;
170017
- };
170018
- for (const a of atomize(segment)) {
170019
- if (a.kind === "space") {
170020
- if (curW === 0)
170021
- continue;
170022
- const sw = w(" ", latin);
170023
- if (curW + sw > CONTENT_W) {
170024
- flush();
170025
- continue;
170026
- }
170027
- add(" ", latin);
170028
- continue;
170029
- }
170030
- const f = pick(a);
170031
- if (curW > 0 && curW + w(a.text, f) > CONTENT_W)
170032
- flush();
170033
- add(a.text, f);
170034
- }
170035
- flush();
170036
- return lines;
170039
+ var PDF_FILTER_BY_EXT = {
170040
+ ".docx": "writer_pdf_Export",
170041
+ ".doc": "writer_pdf_Export",
170042
+ ".odt": "writer_pdf_Export",
170043
+ ".rtf": "writer_pdf_Export",
170044
+ ".txt": "writer_pdf_Export",
170045
+ ".html": "writer_pdf_Export",
170046
+ ".htm": "writer_pdf_Export",
170047
+ ".pptx": "impress_pdf_Export",
170048
+ ".ppt": "impress_pdf_Export",
170049
+ ".odp": "impress_pdf_Export",
170050
+ ".xlsx": "calc_pdf_Export",
170051
+ ".xls": "calc_pdf_Export",
170052
+ ".ods": "calc_pdf_Export",
170053
+ ".csv": "calc_pdf_Export"
170054
+ };
170055
+ var PDF_EXPORT_FILTER_DATA = { EmbedStandardFonts: { type: "boolean", value: "true" } };
170056
+ function pdfExportArg(inputPath) {
170057
+ const filter2 = PDF_FILTER_BY_EXT[(0, import_node_path.extname)(inputPath).toLowerCase()];
170058
+ if (!filter2)
170059
+ return "pdf";
170060
+ return `pdf:${filter2}:${JSON.stringify(PDF_EXPORT_FILTER_DATA)}`;
170037
170061
  }
170038
- function hexRgb(c) {
170039
- const n = parseInt(c.replace("#", ""), 16);
170040
- return (0, import_pdf_lib.rgb)((n >> 16 & 255) / 255, (n >> 8 & 255) / 255, (n & 255) / 255);
170062
+ function sofficeTimeoutMs(bytes) {
170063
+ const base = 9e4;
170064
+ const perMb = 12e3;
170065
+ const mb = Math.max(0, bytes) / (1024 * 1024);
170066
+ return Math.min(6e5, Math.round(base + mb * perMb));
170041
170067
  }
170042
- async function generatePdf(spec, themeInput) {
170043
- const theme = asTheme(themeInput);
170044
- const doc = await import_pdf_lib.PDFDocument.create();
170045
- const fonts = {
170046
- latin: await doc.embedFont(import_pdf_lib.StandardFonts.Helvetica),
170047
- latinBold: await doc.embedFont(import_pdf_lib.StandardFonts.HelveticaBold)
170048
- };
170049
- const headingStyle = {
170050
- size: theme.heading.h1.size,
170051
- bold: theme.heading.h1.bold,
170052
- lineHeight: Math.round(theme.heading.h1.size * 1.35),
170053
- spaceAfter: theme.heading.h1.spaceAfter
170054
- };
170055
- const bodyStyle = {
170056
- size: theme.body.size,
170057
- bold: false,
170058
- lineHeight: Math.round(theme.body.size * theme.body.lineHeight),
170059
- spaceAfter: 8
170060
- };
170061
- const headingColor = hexRgb(resolveColor(theme, theme.heading.h1.color));
170062
- const textColor = hexRgb(theme.colors.text);
170063
- const blocks = [];
170064
- if (spec.title)
170065
- blocks.push({ text: foldFullwidthAlnum(String(spec.title)), style: headingStyle, color: headingColor });
170066
- for (const p of spec.paragraphs ?? [])
170067
- blocks.push({ text: foldFullwidthAlnum(String(p)), style: bodyStyle, color: textColor });
170068
- const segments = blocks.flatMap((b) => b.text.split(/\r?\n/));
170069
- if (segments.some((s) => !canEncode(fonts.latin, s))) {
170070
- const fontPath = resolveUnicodeFontPath(spec);
170071
- if (!fontPath) {
170072
- throw new Error("PDF text needs a Unicode font (non-Latin / CJK) but none was found. Set TALOS_PDF_FONT (or spec.fontPath) to a .ttf/.otf covering it, or generate a .docx instead.");
170073
- }
170074
- let bytes;
170075
- try {
170076
- bytes = (0, import_node_fs2.readFileSync)(fontPath);
170077
- } catch (e) {
170078
- throw new Error(`cannot read PDF font at ${fontPath}: ${e.message}`);
170079
- }
170080
- doc.registerFontkit(import_fontkit.default);
170081
- fonts.cjk = await doc.embedFont(bytes, { subset: true });
170082
- }
170083
- let page = doc.addPage([PAGE_W, PAGE_H]);
170084
- let y = PAGE_H - MARGIN;
170085
- for (const block of blocks) {
170086
- for (const seg of block.text.split(/\r?\n/)) {
170087
- for (const runs of layoutSegment(seg, block.style, fonts)) {
170088
- if (y - block.style.lineHeight < MARGIN) {
170089
- page = doc.addPage([PAGE_W, PAGE_H]);
170090
- y = PAGE_H - MARGIN;
170091
- }
170092
- let x = MARGIN;
170093
- const baseline = y - block.style.size;
170094
- for (const run of runs) {
170095
- page.drawText(run.text, { x, y: baseline, size: block.style.size, font: run.font, color: block.color });
170096
- x += run.width;
170097
- }
170098
- y -= block.style.lineHeight;
170099
- }
170100
- }
170101
- y -= block.style.spaceAfter;
170068
+ function pickConvertedPdf(pdfNames, inputPath) {
170069
+ if (pdfNames.length === 0)
170070
+ return null;
170071
+ const stem = (0, import_node_path.basename)(inputPath, (0, import_node_path.extname)(inputPath)).toLowerCase();
170072
+ const nameStem = (n) => (0, import_node_path.basename)(n, (0, import_node_path.extname)(n)).toLowerCase();
170073
+ const exact = pdfNames.find((n) => nameStem(n) === stem);
170074
+ if (exact)
170075
+ return exact;
170076
+ if (pdfNames.length === 1)
170077
+ return pdfNames[0];
170078
+ const related = pdfNames.find((n) => nameStem(n).startsWith(stem) || stem.startsWith(nameStem(n)));
170079
+ return related ?? [...pdfNames].sort()[0];
170080
+ }
170081
+ async function convertToPdfViaSoffice(inputPath, options = {}) {
170082
+ const soffice = options.sofficePath ?? resolveSoffice();
170083
+ if (!soffice)
170084
+ throw new Error("LibreOffice (soffice) not found");
170085
+ if (!(0, import_node_fs2.existsSync)(inputPath))
170086
+ throw new Error(`input not found: ${inputPath}`);
170087
+ const profileDir = await (0, import_promises.mkdtemp)((0, import_node_path.join)((0, import_node_os.tmpdir)(), "talos-lo-profile-"));
170088
+ const outDir = await (0, import_promises.mkdtemp)((0, import_node_path.join)((0, import_node_os.tmpdir)(), "talos-lo-out-"));
170089
+ try {
170090
+ await runSoffice(soffice, [
170091
+ "--headless",
170092
+ "--norestore",
170093
+ "--nolockcheck",
170094
+ "--nodefault",
170095
+ "--nofirststartwizard",
170096
+ `-env:UserInstallation=${(0, import_node_url.pathToFileURL)(profileDir).href}`,
170097
+ "--convert-to",
170098
+ pdfExportArg(inputPath),
170099
+ "--outdir",
170100
+ outDir,
170101
+ inputPath
170102
+ ], options.timeoutMs ?? sofficeTimeoutMs((0, import_node_fs2.statSync)(inputPath).size));
170103
+ const pdfs = (await (0, import_promises.readdir)(outDir)).filter((f) => f.toLowerCase().endsWith(".pdf"));
170104
+ const chosen = pickConvertedPdf(pdfs, inputPath);
170105
+ if (!chosen)
170106
+ throw new Error("LibreOffice produced no PDF (unsupported input?)");
170107
+ return await (0, import_promises.readFile)((0, import_node_path.join)(outDir, chosen));
170108
+ } finally {
170109
+ await (0, import_promises.rm)(profileDir, { recursive: true, force: true }).catch(() => {
170110
+ });
170111
+ await (0, import_promises.rm)(outDir, { recursive: true, force: true }).catch(() => {
170112
+ });
170102
170113
  }
170103
- return doc.save();
170104
170114
  }
170105
- async function generateDocument(kind, spec, theme) {
170106
- switch (kind) {
170107
- case "docx":
170108
- return generateDocx(spec, theme);
170109
- case "xlsx":
170110
- return generateXlsx(spec);
170111
- case "pptx":
170112
- return generatePptx(spec, theme);
170113
- case "pdf":
170114
- return generatePdf(spec, theme);
170115
- default:
170116
- throw new Error(`unsupported kind: ${String(kind)}`);
170115
+ function runSoffice(bin, args, timeoutMs) {
170116
+ return new Promise((resolve, reject2) => {
170117
+ const child = (0, import_node_child_process.spawn)(bin, args, { stdio: ["ignore", "pipe", "pipe"] });
170118
+ let stderr = "";
170119
+ const timer = setTimeout(() => {
170120
+ child.kill("SIGKILL");
170121
+ reject2(new Error(`LibreOffice timed out after ${timeoutMs}ms`));
170122
+ }, timeoutMs);
170123
+ child.stderr?.on("data", (c) => {
170124
+ if (stderr.length < 4096)
170125
+ stderr += String(c);
170126
+ });
170127
+ child.on("error", (err) => {
170128
+ clearTimeout(timer);
170129
+ reject2(err);
170130
+ });
170131
+ child.on("close", (code) => {
170132
+ clearTimeout(timer);
170133
+ if (code === 0)
170134
+ resolve();
170135
+ else
170136
+ reject2(new Error(`LibreOffice exited ${code}${stderr ? `: ${stderr.trim()}` : ""}`));
170137
+ });
170138
+ });
170139
+ }
170140
+
170141
+ // packages/core/dist/fs/office-service.js
170142
+ async function convertViaOfficeService(bytes, filename, url, options = {}) {
170143
+ const doFetch = options.fetchImpl ?? fetch;
170144
+ const view = bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes);
170145
+ const part = new Uint8Array(view.byteLength);
170146
+ part.set(view);
170147
+ const form = new FormData();
170148
+ form.append("files", new Blob([part]), filename);
170149
+ const controller = new AbortController();
170150
+ const timer = options.timeoutMs && options.timeoutMs > 0 ? setTimeout(() => controller.abort(), options.timeoutMs) : void 0;
170151
+ try {
170152
+ const res = await doFetch(url, {
170153
+ method: "POST",
170154
+ headers: options.token ? { authorization: `Bearer ${options.token}` } : {},
170155
+ body: form,
170156
+ signal: controller.signal
170157
+ });
170158
+ if (!res.ok)
170159
+ throw new Error(`office service HTTP ${res.status}`);
170160
+ return new Uint8Array(await res.arrayBuffer());
170161
+ } finally {
170162
+ if (timer)
170163
+ clearTimeout(timer);
170117
170164
  }
170118
170165
  }
170119
170166