@cola1900/dsh-ppt 0.1.2

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 (730) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +57 -0
  3. package/THIRD_PARTY_NOTICES.md +29 -0
  4. package/UPSTREAM.md +17 -0
  5. package/cordis.patch.yml +8 -0
  6. package/lib/bin.js +4070 -0
  7. package/lib/catalog.js +3 -0
  8. package/lib/client.js +916 -0
  9. package/lib/index.js +3688 -0
  10. package/lib/invariant.js +13 -0
  11. package/lib/pptd-2VqVzr_T.js +2173 -0
  12. package/lib/pptd.js +2 -0
  13. package/lib/preview-assets.js +59 -0
  14. package/lib/preview-manifest.js +2 -0
  15. package/lib/text-wrap.js +20 -0
  16. package/lib/types/bin.d.ts +12 -0
  17. package/lib/types/client/OfficePptHero.d.ts +42 -0
  18. package/lib/types/client/curated-previews.d.ts +3 -0
  19. package/lib/types/client/curated-previews.generated.d.ts +2 -0
  20. package/lib/types/client/index.d.ts +6 -0
  21. package/lib/types/client/locales.d.ts +15 -0
  22. package/lib/types/client/rpc.d.ts +23 -0
  23. package/lib/types/client/standard.d.ts +31 -0
  24. package/lib/types/client.d.ts +1 -0
  25. package/lib/types/data-series.d.ts +31 -0
  26. package/lib/types/index.d.ts +25 -0
  27. package/lib/types/invariant.d.ts +8 -0
  28. package/lib/types/layouts.d.ts +54 -0
  29. package/lib/types/planning.d.ts +35 -0
  30. package/lib/types/ppt-ppt-skill.d.ts +6 -0
  31. package/lib/types/ppt-reference-semantics.generated.d.ts +2 -0
  32. package/lib/types/ppt-rpc.d.ts +5 -0
  33. package/lib/types/ppt-service.d.ts +34 -0
  34. package/lib/types/ppt-store.d.ts +47 -0
  35. package/lib/types/ppt-template-catalog.generated.d.ts +2 -0
  36. package/lib/types/ppt-template-definitions.d.ts +1 -0
  37. package/lib/types/ppt-tools.d.ts +10 -0
  38. package/lib/types/pptd-colors.d.ts +15 -0
  39. package/lib/types/pptd-convert.d.ts +21 -0
  40. package/lib/types/pptd-preview.d.ts +6 -0
  41. package/lib/types/pptd-publish.d.ts +8 -0
  42. package/lib/types/pptd-repair.d.ts +18 -0
  43. package/lib/types/pptd-tools.d.ts +5 -0
  44. package/lib/types/pptd.d.ts +89 -0
  45. package/lib/types/protocol.d.ts +547 -0
  46. package/lib/types/template-reference.d.ts +28 -0
  47. package/lib/types/template-semantics.d.ts +12 -0
  48. package/lib/types/templates.d.ts +2 -0
  49. package/lib/types/text-layout.d.ts +37 -0
  50. package/lib/validation.js +84 -0
  51. package/licenses/composer-NOTICES.md +29 -0
  52. package/licenses/dsh-desktop-LICENSE +21 -0
  53. package/licenses/html-anything/LICENSE +202 -0
  54. package/licenses/html-anything/deck-blueprint.md +22 -0
  55. package/licenses/html-anything/deck-course-module.md +23 -0
  56. package/licenses/zara/LICENSE +21 -0
  57. package/licenses/zara/templates/blue-professional/design.md +701 -0
  58. package/licenses/zara/templates/blue-professional/template.html +1423 -0
  59. package/licenses/zara/templates/blue-professional/template.json +43 -0
  60. package/licenses/zara/templates/broadside/design.md +493 -0
  61. package/licenses/zara/templates/broadside/template.html +2144 -0
  62. package/licenses/zara/templates/broadside/template.json +48 -0
  63. package/licenses/zara/templates/cartesian/design.md +513 -0
  64. package/licenses/zara/templates/cartesian/template.html +1136 -0
  65. package/licenses/zara/templates/cartesian/template.json +46 -0
  66. package/licenses/zara/templates/editorial-forest/design.md +497 -0
  67. package/licenses/zara/templates/editorial-forest/template.html +843 -0
  68. package/licenses/zara/templates/editorial-forest/template.json +44 -0
  69. package/licenses/zara/templates/monochrome/design.md +482 -0
  70. package/licenses/zara/templates/monochrome/template.html +2596 -0
  71. package/licenses/zara/templates/monochrome/template.json +49 -0
  72. package/licenses/zara/templates/neo-grid-bold/design.md +534 -0
  73. package/licenses/zara/templates/neo-grid-bold/template.html +865 -0
  74. package/licenses/zara/templates/neo-grid-bold/template.json +46 -0
  75. package/licenses/zara/templates/playful/design.md +480 -0
  76. package/licenses/zara/templates/playful/template.html +1355 -0
  77. package/licenses/zara/templates/playful/template.json +42 -0
  78. package/licenses/zara/templates/sakura-chroma/design.md +632 -0
  79. package/licenses/zara/templates/sakura-chroma/template.html +1405 -0
  80. package/licenses/zara/templates/sakura-chroma/template.json +53 -0
  81. package/licenses/zara/templates/signal/design.md +517 -0
  82. package/licenses/zara/templates/signal/template.html +2558 -0
  83. package/licenses/zara/templates/signal/template.json +49 -0
  84. package/licenses/zara/templates/soft-editorial/design.md +615 -0
  85. package/licenses/zara/templates/soft-editorial/template.html +1183 -0
  86. package/licenses/zara/templates/soft-editorial/template.json +46 -0
  87. package/package.json +107 -0
  88. package/skills/dsh-ppt/SKILL.md +36 -0
  89. package/skills/dsh-ppt/references/academic/dsh-course-workshop/design.md +61 -0
  90. package/skills/dsh-ppt/references/academic/dsh-course-workshop/metadata.json +2886 -0
  91. package/skills/dsh-ppt/references/academic/dsh-course-workshop/pages/01.jpg +0 -0
  92. package/skills/dsh-ppt/references/academic/dsh-course-workshop/pages/02.jpg +0 -0
  93. package/skills/dsh-ppt/references/academic/dsh-course-workshop/pages/03.jpg +0 -0
  94. package/skills/dsh-ppt/references/academic/dsh-course-workshop/pages/04.jpg +0 -0
  95. package/skills/dsh-ppt/references/academic/dsh-course-workshop/pages/05.jpg +0 -0
  96. package/skills/dsh-ppt/references/academic/dsh-course-workshop/pages/06.jpg +0 -0
  97. package/skills/dsh-ppt/references/academic/dsh-course-workshop/pages/07.jpg +0 -0
  98. package/skills/dsh-ppt/references/academic/dsh-course-workshop/pages/08.jpg +0 -0
  99. package/skills/dsh-ppt/references/academic/dsh-course-workshop/pages/09.jpg +0 -0
  100. package/skills/dsh-ppt/references/academic/dsh-course-workshop/pages/10.jpg +0 -0
  101. package/skills/dsh-ppt/references/academic/dsh-course-workshop/pages/11.jpg +0 -0
  102. package/skills/dsh-ppt/references/academic/dsh-course-workshop/pages/12.jpg +0 -0
  103. package/skills/dsh-ppt/references/academic/dsh-course-workshop/source/deck.pptd +21 -0
  104. package/skills/dsh-ppt/references/academic/dsh-course-workshop/source/pages/01.page +142 -0
  105. package/skills/dsh-ppt/references/academic/dsh-course-workshop/source/pages/02.page +382 -0
  106. package/skills/dsh-ppt/references/academic/dsh-course-workshop/source/pages/03.page +817 -0
  107. package/skills/dsh-ppt/references/academic/dsh-course-workshop/source/pages/04.page +408 -0
  108. package/skills/dsh-ppt/references/academic/dsh-course-workshop/source/pages/05.page +407 -0
  109. package/skills/dsh-ppt/references/academic/dsh-course-workshop/source/pages/06.page +760 -0
  110. package/skills/dsh-ppt/references/academic/dsh-course-workshop/source/pages/07.page +551 -0
  111. package/skills/dsh-ppt/references/academic/dsh-course-workshop/source/pages/08.page +339 -0
  112. package/skills/dsh-ppt/references/academic/dsh-course-workshop/source/pages/09.page +297 -0
  113. package/skills/dsh-ppt/references/academic/dsh-course-workshop/source/pages/10.page +365 -0
  114. package/skills/dsh-ppt/references/academic/dsh-course-workshop/source/pages/11.page +575 -0
  115. package/skills/dsh-ppt/references/academic/dsh-course-workshop/source/pages/12.page +130 -0
  116. package/skills/dsh-ppt/references/academic/dsh-course-workshop/source-zh/deck.pptd +21 -0
  117. package/skills/dsh-ppt/references/academic/dsh-course-workshop/source-zh/pages/01.page +142 -0
  118. package/skills/dsh-ppt/references/academic/dsh-course-workshop/source-zh/pages/02.page +382 -0
  119. package/skills/dsh-ppt/references/academic/dsh-course-workshop/source-zh/pages/03.page +817 -0
  120. package/skills/dsh-ppt/references/academic/dsh-course-workshop/source-zh/pages/04.page +408 -0
  121. package/skills/dsh-ppt/references/academic/dsh-course-workshop/source-zh/pages/05.page +407 -0
  122. package/skills/dsh-ppt/references/academic/dsh-course-workshop/source-zh/pages/06.page +760 -0
  123. package/skills/dsh-ppt/references/academic/dsh-course-workshop/source-zh/pages/07.page +551 -0
  124. package/skills/dsh-ppt/references/academic/dsh-course-workshop/source-zh/pages/08.page +339 -0
  125. package/skills/dsh-ppt/references/academic/dsh-course-workshop/source-zh/pages/09.page +297 -0
  126. package/skills/dsh-ppt/references/academic/dsh-course-workshop/source-zh/pages/10.page +365 -0
  127. package/skills/dsh-ppt/references/academic/dsh-course-workshop/source-zh/pages/11.page +575 -0
  128. package/skills/dsh-ppt/references/academic/dsh-course-workshop/source-zh/pages/12.page +130 -0
  129. package/skills/dsh-ppt/references/academic/dsh-monochrome/design.md +61 -0
  130. package/skills/dsh-ppt/references/academic/dsh-monochrome/metadata.json +2989 -0
  131. package/skills/dsh-ppt/references/academic/dsh-monochrome/pages/01.jpg +0 -0
  132. package/skills/dsh-ppt/references/academic/dsh-monochrome/pages/02.jpg +0 -0
  133. package/skills/dsh-ppt/references/academic/dsh-monochrome/pages/03.jpg +0 -0
  134. package/skills/dsh-ppt/references/academic/dsh-monochrome/pages/04.jpg +0 -0
  135. package/skills/dsh-ppt/references/academic/dsh-monochrome/pages/05.jpg +0 -0
  136. package/skills/dsh-ppt/references/academic/dsh-monochrome/pages/06.jpg +0 -0
  137. package/skills/dsh-ppt/references/academic/dsh-monochrome/pages/07.jpg +0 -0
  138. package/skills/dsh-ppt/references/academic/dsh-monochrome/pages/08.jpg +0 -0
  139. package/skills/dsh-ppt/references/academic/dsh-monochrome/pages/09.jpg +0 -0
  140. package/skills/dsh-ppt/references/academic/dsh-monochrome/pages/10.jpg +0 -0
  141. package/skills/dsh-ppt/references/academic/dsh-monochrome/pages/11.jpg +0 -0
  142. package/skills/dsh-ppt/references/academic/dsh-monochrome/pages/12.jpg +0 -0
  143. package/skills/dsh-ppt/references/academic/dsh-monochrome/source/deck.pptd +21 -0
  144. package/skills/dsh-ppt/references/academic/dsh-monochrome/source/pages/01.page +86 -0
  145. package/skills/dsh-ppt/references/academic/dsh-monochrome/source/pages/02.page +382 -0
  146. package/skills/dsh-ppt/references/academic/dsh-monochrome/source/pages/03.page +479 -0
  147. package/skills/dsh-ppt/references/academic/dsh-monochrome/source/pages/04.page +551 -0
  148. package/skills/dsh-ppt/references/academic/dsh-monochrome/source/pages/05.page +817 -0
  149. package/skills/dsh-ppt/references/academic/dsh-monochrome/source/pages/06.page +760 -0
  150. package/skills/dsh-ppt/references/academic/dsh-monochrome/source/pages/07.page +576 -0
  151. package/skills/dsh-ppt/references/academic/dsh-monochrome/source/pages/08.page +339 -0
  152. package/skills/dsh-ppt/references/academic/dsh-monochrome/source/pages/09.page +295 -0
  153. package/skills/dsh-ppt/references/academic/dsh-monochrome/source/pages/10.page +407 -0
  154. package/skills/dsh-ppt/references/academic/dsh-monochrome/source/pages/11.page +575 -0
  155. package/skills/dsh-ppt/references/academic/dsh-monochrome/source/pages/12.page +86 -0
  156. package/skills/dsh-ppt/references/academic/dsh-monochrome/source-zh/deck.pptd +21 -0
  157. package/skills/dsh-ppt/references/academic/dsh-monochrome/source-zh/pages/01.page +86 -0
  158. package/skills/dsh-ppt/references/academic/dsh-monochrome/source-zh/pages/02.page +382 -0
  159. package/skills/dsh-ppt/references/academic/dsh-monochrome/source-zh/pages/03.page +479 -0
  160. package/skills/dsh-ppt/references/academic/dsh-monochrome/source-zh/pages/04.page +551 -0
  161. package/skills/dsh-ppt/references/academic/dsh-monochrome/source-zh/pages/05.page +817 -0
  162. package/skills/dsh-ppt/references/academic/dsh-monochrome/source-zh/pages/06.page +760 -0
  163. package/skills/dsh-ppt/references/academic/dsh-monochrome/source-zh/pages/07.page +576 -0
  164. package/skills/dsh-ppt/references/academic/dsh-monochrome/source-zh/pages/08.page +339 -0
  165. package/skills/dsh-ppt/references/academic/dsh-monochrome/source-zh/pages/09.page +295 -0
  166. package/skills/dsh-ppt/references/academic/dsh-monochrome/source-zh/pages/10.page +407 -0
  167. package/skills/dsh-ppt/references/academic/dsh-monochrome/source-zh/pages/11.page +575 -0
  168. package/skills/dsh-ppt/references/academic/dsh-monochrome/source-zh/pages/12.page +86 -0
  169. package/skills/dsh-ppt/references/business/dsh-blue-professional/design.md +53 -0
  170. package/skills/dsh-ppt/references/business/dsh-blue-professional/metadata.json +3152 -0
  171. package/skills/dsh-ppt/references/business/dsh-blue-professional/pages/01.jpg +0 -0
  172. package/skills/dsh-ppt/references/business/dsh-blue-professional/pages/02.jpg +0 -0
  173. package/skills/dsh-ppt/references/business/dsh-blue-professional/pages/03.jpg +0 -0
  174. package/skills/dsh-ppt/references/business/dsh-blue-professional/pages/04.jpg +0 -0
  175. package/skills/dsh-ppt/references/business/dsh-blue-professional/pages/05.jpg +0 -0
  176. package/skills/dsh-ppt/references/business/dsh-blue-professional/pages/06.jpg +0 -0
  177. package/skills/dsh-ppt/references/business/dsh-blue-professional/pages/07.jpg +0 -0
  178. package/skills/dsh-ppt/references/business/dsh-blue-professional/pages/08.jpg +0 -0
  179. package/skills/dsh-ppt/references/business/dsh-blue-professional/pages/09.jpg +0 -0
  180. package/skills/dsh-ppt/references/business/dsh-blue-professional/pages/10.jpg +0 -0
  181. package/skills/dsh-ppt/references/business/dsh-blue-professional/pages/11.jpg +0 -0
  182. package/skills/dsh-ppt/references/business/dsh-blue-professional/pages/12.jpg +0 -0
  183. package/skills/dsh-ppt/references/business/dsh-blue-professional/source/deck.pptd +21 -0
  184. package/skills/dsh-ppt/references/business/dsh-blue-professional/source/pages/01.page +100 -0
  185. package/skills/dsh-ppt/references/business/dsh-blue-professional/source/pages/02.page +310 -0
  186. package/skills/dsh-ppt/references/business/dsh-blue-professional/source/pages/03.page +381 -0
  187. package/skills/dsh-ppt/references/business/dsh-blue-professional/source/pages/04.page +853 -0
  188. package/skills/dsh-ppt/references/business/dsh-blue-professional/source/pages/05.page +436 -0
  189. package/skills/dsh-ppt/references/business/dsh-blue-professional/source/pages/06.page +732 -0
  190. package/skills/dsh-ppt/references/business/dsh-blue-professional/source/pages/07.page +574 -0
  191. package/skills/dsh-ppt/references/business/dsh-blue-professional/source/pages/08.page +767 -0
  192. package/skills/dsh-ppt/references/business/dsh-blue-professional/source/pages/09.page +282 -0
  193. package/skills/dsh-ppt/references/business/dsh-blue-professional/source/pages/10.page +350 -0
  194. package/skills/dsh-ppt/references/business/dsh-blue-professional/source/pages/11.page +462 -0
  195. package/skills/dsh-ppt/references/business/dsh-blue-professional/source/pages/12.page +86 -0
  196. package/skills/dsh-ppt/references/business/dsh-blue-professional/source-zh/deck.pptd +21 -0
  197. package/skills/dsh-ppt/references/business/dsh-blue-professional/source-zh/pages/01.page +100 -0
  198. package/skills/dsh-ppt/references/business/dsh-blue-professional/source-zh/pages/02.page +310 -0
  199. package/skills/dsh-ppt/references/business/dsh-blue-professional/source-zh/pages/03.page +381 -0
  200. package/skills/dsh-ppt/references/business/dsh-blue-professional/source-zh/pages/04.page +853 -0
  201. package/skills/dsh-ppt/references/business/dsh-blue-professional/source-zh/pages/05.page +436 -0
  202. package/skills/dsh-ppt/references/business/dsh-blue-professional/source-zh/pages/06.page +732 -0
  203. package/skills/dsh-ppt/references/business/dsh-blue-professional/source-zh/pages/07.page +574 -0
  204. package/skills/dsh-ppt/references/business/dsh-blue-professional/source-zh/pages/08.page +769 -0
  205. package/skills/dsh-ppt/references/business/dsh-blue-professional/source-zh/pages/09.page +282 -0
  206. package/skills/dsh-ppt/references/business/dsh-blue-professional/source-zh/pages/10.page +350 -0
  207. package/skills/dsh-ppt/references/business/dsh-blue-professional/source-zh/pages/11.page +462 -0
  208. package/skills/dsh-ppt/references/business/dsh-blue-professional/source-zh/pages/12.page +86 -0
  209. package/skills/dsh-ppt/references/business/dsh-neo-grid-bold/design.md +61 -0
  210. package/skills/dsh-ppt/references/business/dsh-neo-grid-bold/metadata.json +3883 -0
  211. package/skills/dsh-ppt/references/business/dsh-neo-grid-bold/pages/01.jpg +0 -0
  212. package/skills/dsh-ppt/references/business/dsh-neo-grid-bold/pages/02.jpg +0 -0
  213. package/skills/dsh-ppt/references/business/dsh-neo-grid-bold/pages/03.jpg +0 -0
  214. package/skills/dsh-ppt/references/business/dsh-neo-grid-bold/pages/04.jpg +0 -0
  215. package/skills/dsh-ppt/references/business/dsh-neo-grid-bold/pages/05.jpg +0 -0
  216. package/skills/dsh-ppt/references/business/dsh-neo-grid-bold/pages/06.jpg +0 -0
  217. package/skills/dsh-ppt/references/business/dsh-neo-grid-bold/pages/07.jpg +0 -0
  218. package/skills/dsh-ppt/references/business/dsh-neo-grid-bold/pages/08.jpg +0 -0
  219. package/skills/dsh-ppt/references/business/dsh-neo-grid-bold/pages/09.jpg +0 -0
  220. package/skills/dsh-ppt/references/business/dsh-neo-grid-bold/pages/10.jpg +0 -0
  221. package/skills/dsh-ppt/references/business/dsh-neo-grid-bold/pages/11.jpg +0 -0
  222. package/skills/dsh-ppt/references/business/dsh-neo-grid-bold/pages/12.jpg +0 -0
  223. package/skills/dsh-ppt/references/business/dsh-neo-grid-bold/source/deck.pptd +21 -0
  224. package/skills/dsh-ppt/references/business/dsh-neo-grid-bold/source/pages/01.page +355 -0
  225. package/skills/dsh-ppt/references/business/dsh-neo-grid-bold/source/pages/02.page +452 -0
  226. package/skills/dsh-ppt/references/business/dsh-neo-grid-bold/source/pages/03.page +561 -0
  227. package/skills/dsh-ppt/references/business/dsh-neo-grid-bold/source/pages/04.page +830 -0
  228. package/skills/dsh-ppt/references/business/dsh-neo-grid-bold/source/pages/05.page +887 -0
  229. package/skills/dsh-ppt/references/business/dsh-neo-grid-bold/source/pages/06.page +646 -0
  230. package/skills/dsh-ppt/references/business/dsh-neo-grid-bold/source/pages/07.page +881 -0
  231. package/skills/dsh-ppt/references/business/dsh-neo-grid-bold/source/pages/08.page +788 -0
  232. package/skills/dsh-ppt/references/business/dsh-neo-grid-bold/source/pages/09.page +365 -0
  233. package/skills/dsh-ppt/references/business/dsh-neo-grid-bold/source/pages/10.page +617 -0
  234. package/skills/dsh-ppt/references/business/dsh-neo-grid-bold/source/pages/11.page +645 -0
  235. package/skills/dsh-ppt/references/business/dsh-neo-grid-bold/source/pages/12.page +86 -0
  236. package/skills/dsh-ppt/references/business/dsh-neo-grid-bold/source-zh/deck.pptd +21 -0
  237. package/skills/dsh-ppt/references/business/dsh-neo-grid-bold/source-zh/pages/01.page +354 -0
  238. package/skills/dsh-ppt/references/business/dsh-neo-grid-bold/source-zh/pages/02.page +452 -0
  239. package/skills/dsh-ppt/references/business/dsh-neo-grid-bold/source-zh/pages/03.page +561 -0
  240. package/skills/dsh-ppt/references/business/dsh-neo-grid-bold/source-zh/pages/04.page +830 -0
  241. package/skills/dsh-ppt/references/business/dsh-neo-grid-bold/source-zh/pages/05.page +887 -0
  242. package/skills/dsh-ppt/references/business/dsh-neo-grid-bold/source-zh/pages/06.page +646 -0
  243. package/skills/dsh-ppt/references/business/dsh-neo-grid-bold/source-zh/pages/07.page +881 -0
  244. package/skills/dsh-ppt/references/business/dsh-neo-grid-bold/source-zh/pages/08.page +788 -0
  245. package/skills/dsh-ppt/references/business/dsh-neo-grid-bold/source-zh/pages/09.page +365 -0
  246. package/skills/dsh-ppt/references/business/dsh-neo-grid-bold/source-zh/pages/10.page +617 -0
  247. package/skills/dsh-ppt/references/business/dsh-neo-grid-bold/source-zh/pages/11.page +645 -0
  248. package/skills/dsh-ppt/references/business/dsh-neo-grid-bold/source-zh/pages/12.page +86 -0
  249. package/skills/dsh-ppt/references/composition.md +19 -0
  250. package/skills/dsh-ppt/references/consulting/curated-swiss-signal-grid/design.md +124 -0
  251. package/skills/dsh-ppt/references/consulting/curated-swiss-signal-grid/metadata.json +1930 -0
  252. package/skills/dsh-ppt/references/consulting/curated-swiss-signal-grid/pages/01.jpg +0 -0
  253. package/skills/dsh-ppt/references/consulting/curated-swiss-signal-grid/pages/02.jpg +0 -0
  254. package/skills/dsh-ppt/references/consulting/curated-swiss-signal-grid/pages/03.jpg +0 -0
  255. package/skills/dsh-ppt/references/consulting/curated-swiss-signal-grid/pages/04.jpg +0 -0
  256. package/skills/dsh-ppt/references/consulting/curated-swiss-signal-grid/pages/05.jpg +0 -0
  257. package/skills/dsh-ppt/references/consulting/curated-swiss-signal-grid/pages/06.jpg +0 -0
  258. package/skills/dsh-ppt/references/consulting/curated-swiss-signal-grid/pages/07.jpg +0 -0
  259. package/skills/dsh-ppt/references/consulting/curated-swiss-signal-grid/pages/08.jpg +0 -0
  260. package/skills/dsh-ppt/references/consulting/curated-swiss-signal-grid/pages/09.jpg +0 -0
  261. package/skills/dsh-ppt/references/consulting/curated-swiss-signal-grid/pages/10.jpg +0 -0
  262. package/skills/dsh-ppt/references/consulting/curated-swiss-signal-grid/pages/11.jpg +0 -0
  263. package/skills/dsh-ppt/references/consulting/curated-swiss-signal-grid/pages/12.jpg +0 -0
  264. package/skills/dsh-ppt/references/consulting/curated-swiss-signal-grid/source/deck.pptd +91 -0
  265. package/skills/dsh-ppt/references/consulting/curated-swiss-signal-grid/source/pages/01.page +259 -0
  266. package/skills/dsh-ppt/references/consulting/curated-swiss-signal-grid/source/pages/02.page +325 -0
  267. package/skills/dsh-ppt/references/consulting/curated-swiss-signal-grid/source/pages/03.page +511 -0
  268. package/skills/dsh-ppt/references/consulting/curated-swiss-signal-grid/source/pages/04.page +398 -0
  269. package/skills/dsh-ppt/references/consulting/curated-swiss-signal-grid/source/pages/05.page +439 -0
  270. package/skills/dsh-ppt/references/consulting/curated-swiss-signal-grid/source/pages/06.page +493 -0
  271. package/skills/dsh-ppt/references/consulting/curated-swiss-signal-grid/source/pages/07.page +194 -0
  272. package/skills/dsh-ppt/references/consulting/curated-swiss-signal-grid/source/pages/08.page +422 -0
  273. package/skills/dsh-ppt/references/consulting/curated-swiss-signal-grid/source/pages/09.page +458 -0
  274. package/skills/dsh-ppt/references/consulting/curated-swiss-signal-grid/source/pages/10.page +746 -0
  275. package/skills/dsh-ppt/references/consulting/curated-swiss-signal-grid/source/pages/11.page +604 -0
  276. package/skills/dsh-ppt/references/consulting/curated-swiss-signal-grid/source/pages/12.page +343 -0
  277. package/skills/dsh-ppt/references/consulting/curated-swiss-signal-grid/source-zh/deck.pptd +91 -0
  278. package/skills/dsh-ppt/references/consulting/curated-swiss-signal-grid/source-zh/pages/01.page +259 -0
  279. package/skills/dsh-ppt/references/consulting/curated-swiss-signal-grid/source-zh/pages/02.page +325 -0
  280. package/skills/dsh-ppt/references/consulting/curated-swiss-signal-grid/source-zh/pages/03.page +511 -0
  281. package/skills/dsh-ppt/references/consulting/curated-swiss-signal-grid/source-zh/pages/04.page +398 -0
  282. package/skills/dsh-ppt/references/consulting/curated-swiss-signal-grid/source-zh/pages/05.page +439 -0
  283. package/skills/dsh-ppt/references/consulting/curated-swiss-signal-grid/source-zh/pages/06.page +493 -0
  284. package/skills/dsh-ppt/references/consulting/curated-swiss-signal-grid/source-zh/pages/07.page +194 -0
  285. package/skills/dsh-ppt/references/consulting/curated-swiss-signal-grid/source-zh/pages/08.page +417 -0
  286. package/skills/dsh-ppt/references/consulting/curated-swiss-signal-grid/source-zh/pages/09.page +458 -0
  287. package/skills/dsh-ppt/references/consulting/curated-swiss-signal-grid/source-zh/pages/10.page +746 -0
  288. package/skills/dsh-ppt/references/consulting/curated-swiss-signal-grid/source-zh/pages/11.page +604 -0
  289. package/skills/dsh-ppt/references/consulting/curated-swiss-signal-grid/source-zh/pages/12.page +343 -0
  290. package/skills/dsh-ppt/references/consulting/dsh-cartesian/design.md +61 -0
  291. package/skills/dsh-ppt/references/consulting/dsh-cartesian/metadata.json +3196 -0
  292. package/skills/dsh-ppt/references/consulting/dsh-cartesian/pages/01.jpg +0 -0
  293. package/skills/dsh-ppt/references/consulting/dsh-cartesian/pages/02.jpg +0 -0
  294. package/skills/dsh-ppt/references/consulting/dsh-cartesian/pages/03.jpg +0 -0
  295. package/skills/dsh-ppt/references/consulting/dsh-cartesian/pages/04.jpg +0 -0
  296. package/skills/dsh-ppt/references/consulting/dsh-cartesian/pages/05.jpg +0 -0
  297. package/skills/dsh-ppt/references/consulting/dsh-cartesian/pages/06.jpg +0 -0
  298. package/skills/dsh-ppt/references/consulting/dsh-cartesian/pages/07.jpg +0 -0
  299. package/skills/dsh-ppt/references/consulting/dsh-cartesian/pages/08.jpg +0 -0
  300. package/skills/dsh-ppt/references/consulting/dsh-cartesian/pages/09.jpg +0 -0
  301. package/skills/dsh-ppt/references/consulting/dsh-cartesian/pages/10.jpg +0 -0
  302. package/skills/dsh-ppt/references/consulting/dsh-cartesian/pages/11.jpg +0 -0
  303. package/skills/dsh-ppt/references/consulting/dsh-cartesian/pages/12.jpg +0 -0
  304. package/skills/dsh-ppt/references/consulting/dsh-cartesian/source/deck.pptd +21 -0
  305. package/skills/dsh-ppt/references/consulting/dsh-cartesian/source/pages/01.page +98 -0
  306. package/skills/dsh-ppt/references/consulting/dsh-cartesian/source/pages/02.page +382 -0
  307. package/skills/dsh-ppt/references/consulting/dsh-cartesian/source/pages/03.page +817 -0
  308. package/skills/dsh-ppt/references/consulting/dsh-cartesian/source/pages/04.page +479 -0
  309. package/skills/dsh-ppt/references/consulting/dsh-cartesian/source/pages/05.page +576 -0
  310. package/skills/dsh-ppt/references/consulting/dsh-cartesian/source/pages/06.page +760 -0
  311. package/skills/dsh-ppt/references/consulting/dsh-cartesian/source/pages/07.page +339 -0
  312. package/skills/dsh-ppt/references/consulting/dsh-cartesian/source/pages/08.page +718 -0
  313. package/skills/dsh-ppt/references/consulting/dsh-cartesian/source/pages/09.page +295 -0
  314. package/skills/dsh-ppt/references/consulting/dsh-cartesian/source/pages/10.page +547 -0
  315. package/skills/dsh-ppt/references/consulting/dsh-cartesian/source/pages/11.page +575 -0
  316. package/skills/dsh-ppt/references/consulting/dsh-cartesian/source/pages/12.page +86 -0
  317. package/skills/dsh-ppt/references/consulting/dsh-cartesian/source-zh/deck.pptd +21 -0
  318. package/skills/dsh-ppt/references/consulting/dsh-cartesian/source-zh/pages/01.page +98 -0
  319. package/skills/dsh-ppt/references/consulting/dsh-cartesian/source-zh/pages/02.page +382 -0
  320. package/skills/dsh-ppt/references/consulting/dsh-cartesian/source-zh/pages/03.page +817 -0
  321. package/skills/dsh-ppt/references/consulting/dsh-cartesian/source-zh/pages/04.page +479 -0
  322. package/skills/dsh-ppt/references/consulting/dsh-cartesian/source-zh/pages/05.page +576 -0
  323. package/skills/dsh-ppt/references/consulting/dsh-cartesian/source-zh/pages/06.page +760 -0
  324. package/skills/dsh-ppt/references/consulting/dsh-cartesian/source-zh/pages/07.page +339 -0
  325. package/skills/dsh-ppt/references/consulting/dsh-cartesian/source-zh/pages/08.page +718 -0
  326. package/skills/dsh-ppt/references/consulting/dsh-cartesian/source-zh/pages/09.page +295 -0
  327. package/skills/dsh-ppt/references/consulting/dsh-cartesian/source-zh/pages/10.page +547 -0
  328. package/skills/dsh-ppt/references/consulting/dsh-cartesian/source-zh/pages/11.page +575 -0
  329. package/skills/dsh-ppt/references/consulting/dsh-cartesian/source-zh/pages/12.page +86 -0
  330. package/skills/dsh-ppt/references/consulting/dsh-signal/design.md +61 -0
  331. package/skills/dsh-ppt/references/consulting/dsh-signal/metadata.json +3172 -0
  332. package/skills/dsh-ppt/references/consulting/dsh-signal/pages/01.jpg +0 -0
  333. package/skills/dsh-ppt/references/consulting/dsh-signal/pages/02.jpg +0 -0
  334. package/skills/dsh-ppt/references/consulting/dsh-signal/pages/03.jpg +0 -0
  335. package/skills/dsh-ppt/references/consulting/dsh-signal/pages/04.jpg +0 -0
  336. package/skills/dsh-ppt/references/consulting/dsh-signal/pages/05.jpg +0 -0
  337. package/skills/dsh-ppt/references/consulting/dsh-signal/pages/06.jpg +0 -0
  338. package/skills/dsh-ppt/references/consulting/dsh-signal/pages/07.jpg +0 -0
  339. package/skills/dsh-ppt/references/consulting/dsh-signal/pages/08.jpg +0 -0
  340. package/skills/dsh-ppt/references/consulting/dsh-signal/pages/09.jpg +0 -0
  341. package/skills/dsh-ppt/references/consulting/dsh-signal/pages/10.jpg +0 -0
  342. package/skills/dsh-ppt/references/consulting/dsh-signal/pages/11.jpg +0 -0
  343. package/skills/dsh-ppt/references/consulting/dsh-signal/pages/12.jpg +0 -0
  344. package/skills/dsh-ppt/references/consulting/dsh-signal/source/deck.pptd +21 -0
  345. package/skills/dsh-ppt/references/consulting/dsh-signal/source/pages/01.page +100 -0
  346. package/skills/dsh-ppt/references/consulting/dsh-signal/source/pages/02.page +382 -0
  347. package/skills/dsh-ppt/references/consulting/dsh-signal/source/pages/03.page +817 -0
  348. package/skills/dsh-ppt/references/consulting/dsh-signal/source/pages/04.page +760 -0
  349. package/skills/dsh-ppt/references/consulting/dsh-signal/source/pages/05.page +576 -0
  350. package/skills/dsh-ppt/references/consulting/dsh-signal/source/pages/06.page +718 -0
  351. package/skills/dsh-ppt/references/consulting/dsh-signal/source/pages/07.page +295 -0
  352. package/skills/dsh-ppt/references/consulting/dsh-signal/source/pages/08.page +551 -0
  353. package/skills/dsh-ppt/references/consulting/dsh-signal/source/pages/09.page +339 -0
  354. package/skills/dsh-ppt/references/consulting/dsh-signal/source/pages/10.page +547 -0
  355. package/skills/dsh-ppt/references/consulting/dsh-signal/source/pages/11.page +575 -0
  356. package/skills/dsh-ppt/references/consulting/dsh-signal/source/pages/12.page +86 -0
  357. package/skills/dsh-ppt/references/consulting/dsh-signal/source-zh/deck.pptd +21 -0
  358. package/skills/dsh-ppt/references/consulting/dsh-signal/source-zh/pages/01.page +100 -0
  359. package/skills/dsh-ppt/references/consulting/dsh-signal/source-zh/pages/02.page +382 -0
  360. package/skills/dsh-ppt/references/consulting/dsh-signal/source-zh/pages/03.page +817 -0
  361. package/skills/dsh-ppt/references/consulting/dsh-signal/source-zh/pages/04.page +760 -0
  362. package/skills/dsh-ppt/references/consulting/dsh-signal/source-zh/pages/05.page +576 -0
  363. package/skills/dsh-ppt/references/consulting/dsh-signal/source-zh/pages/06.page +718 -0
  364. package/skills/dsh-ppt/references/consulting/dsh-signal/source-zh/pages/07.page +295 -0
  365. package/skills/dsh-ppt/references/consulting/dsh-signal/source-zh/pages/08.page +551 -0
  366. package/skills/dsh-ppt/references/consulting/dsh-signal/source-zh/pages/09.page +339 -0
  367. package/skills/dsh-ppt/references/consulting/dsh-signal/source-zh/pages/10.page +547 -0
  368. package/skills/dsh-ppt/references/consulting/dsh-signal/source-zh/pages/11.page +575 -0
  369. package/skills/dsh-ppt/references/consulting/dsh-signal/source-zh/pages/12.page +86 -0
  370. package/skills/dsh-ppt/references/editorial/dsh-editorial-notebook/design.md +61 -0
  371. package/skills/dsh-ppt/references/editorial/dsh-editorial-notebook/metadata.json +3091 -0
  372. package/skills/dsh-ppt/references/editorial/dsh-editorial-notebook/pages/01.jpg +0 -0
  373. package/skills/dsh-ppt/references/editorial/dsh-editorial-notebook/pages/02.jpg +0 -0
  374. package/skills/dsh-ppt/references/editorial/dsh-editorial-notebook/pages/03.jpg +0 -0
  375. package/skills/dsh-ppt/references/editorial/dsh-editorial-notebook/pages/04.jpg +0 -0
  376. package/skills/dsh-ppt/references/editorial/dsh-editorial-notebook/pages/05.jpg +0 -0
  377. package/skills/dsh-ppt/references/editorial/dsh-editorial-notebook/pages/06.jpg +0 -0
  378. package/skills/dsh-ppt/references/editorial/dsh-editorial-notebook/pages/07.jpg +0 -0
  379. package/skills/dsh-ppt/references/editorial/dsh-editorial-notebook/pages/08.jpg +0 -0
  380. package/skills/dsh-ppt/references/editorial/dsh-editorial-notebook/pages/09.jpg +0 -0
  381. package/skills/dsh-ppt/references/editorial/dsh-editorial-notebook/pages/10.jpg +0 -0
  382. package/skills/dsh-ppt/references/editorial/dsh-editorial-notebook/pages/11.jpg +0 -0
  383. package/skills/dsh-ppt/references/editorial/dsh-editorial-notebook/pages/12.jpg +0 -0
  384. package/skills/dsh-ppt/references/editorial/dsh-editorial-notebook/source/deck.pptd +21 -0
  385. package/skills/dsh-ppt/references/editorial/dsh-editorial-notebook/source/pages/01.page +124 -0
  386. package/skills/dsh-ppt/references/editorial/dsh-editorial-notebook/source/pages/02.page +382 -0
  387. package/skills/dsh-ppt/references/editorial/dsh-editorial-notebook/source/pages/03.page +479 -0
  388. package/skills/dsh-ppt/references/editorial/dsh-editorial-notebook/source/pages/04.page +365 -0
  389. package/skills/dsh-ppt/references/editorial/dsh-editorial-notebook/source/pages/05.page +817 -0
  390. package/skills/dsh-ppt/references/editorial/dsh-editorial-notebook/source/pages/06.page +760 -0
  391. package/skills/dsh-ppt/references/editorial/dsh-editorial-notebook/source/pages/07.page +576 -0
  392. package/skills/dsh-ppt/references/editorial/dsh-editorial-notebook/source/pages/08.page +295 -0
  393. package/skills/dsh-ppt/references/editorial/dsh-editorial-notebook/source/pages/09.page +339 -0
  394. package/skills/dsh-ppt/references/editorial/dsh-editorial-notebook/source/pages/10.page +547 -0
  395. package/skills/dsh-ppt/references/editorial/dsh-editorial-notebook/source/pages/11.page +575 -0
  396. package/skills/dsh-ppt/references/editorial/dsh-editorial-notebook/source/pages/12.page +135 -0
  397. package/skills/dsh-ppt/references/editorial/dsh-editorial-notebook/source-zh/deck.pptd +21 -0
  398. package/skills/dsh-ppt/references/editorial/dsh-editorial-notebook/source-zh/pages/01.page +124 -0
  399. package/skills/dsh-ppt/references/editorial/dsh-editorial-notebook/source-zh/pages/02.page +384 -0
  400. package/skills/dsh-ppt/references/editorial/dsh-editorial-notebook/source-zh/pages/03.page +479 -0
  401. package/skills/dsh-ppt/references/editorial/dsh-editorial-notebook/source-zh/pages/04.page +365 -0
  402. package/skills/dsh-ppt/references/editorial/dsh-editorial-notebook/source-zh/pages/05.page +817 -0
  403. package/skills/dsh-ppt/references/editorial/dsh-editorial-notebook/source-zh/pages/06.page +760 -0
  404. package/skills/dsh-ppt/references/editorial/dsh-editorial-notebook/source-zh/pages/07.page +576 -0
  405. package/skills/dsh-ppt/references/editorial/dsh-editorial-notebook/source-zh/pages/08.page +295 -0
  406. package/skills/dsh-ppt/references/editorial/dsh-editorial-notebook/source-zh/pages/09.page +341 -0
  407. package/skills/dsh-ppt/references/editorial/dsh-editorial-notebook/source-zh/pages/10.page +547 -0
  408. package/skills/dsh-ppt/references/editorial/dsh-editorial-notebook/source-zh/pages/11.page +575 -0
  409. package/skills/dsh-ppt/references/editorial/dsh-editorial-notebook/source-zh/pages/12.page +135 -0
  410. package/skills/dsh-ppt/references/editorial/dsh-soft-editorial/design.md +61 -0
  411. package/skills/dsh-ppt/references/editorial/dsh-soft-editorial/metadata.json +3119 -0
  412. package/skills/dsh-ppt/references/editorial/dsh-soft-editorial/pages/01.jpg +0 -0
  413. package/skills/dsh-ppt/references/editorial/dsh-soft-editorial/pages/02.jpg +0 -0
  414. package/skills/dsh-ppt/references/editorial/dsh-soft-editorial/pages/03.jpg +0 -0
  415. package/skills/dsh-ppt/references/editorial/dsh-soft-editorial/pages/04.jpg +0 -0
  416. package/skills/dsh-ppt/references/editorial/dsh-soft-editorial/pages/05.jpg +0 -0
  417. package/skills/dsh-ppt/references/editorial/dsh-soft-editorial/pages/06.jpg +0 -0
  418. package/skills/dsh-ppt/references/editorial/dsh-soft-editorial/pages/07.jpg +0 -0
  419. package/skills/dsh-ppt/references/editorial/dsh-soft-editorial/pages/08.jpg +0 -0
  420. package/skills/dsh-ppt/references/editorial/dsh-soft-editorial/pages/09.jpg +0 -0
  421. package/skills/dsh-ppt/references/editorial/dsh-soft-editorial/pages/10.jpg +0 -0
  422. package/skills/dsh-ppt/references/editorial/dsh-soft-editorial/pages/11.jpg +0 -0
  423. package/skills/dsh-ppt/references/editorial/dsh-soft-editorial/pages/12.jpg +0 -0
  424. package/skills/dsh-ppt/references/editorial/dsh-soft-editorial/source/deck.pptd +21 -0
  425. package/skills/dsh-ppt/references/editorial/dsh-soft-editorial/source/pages/01.page +117 -0
  426. package/skills/dsh-ppt/references/editorial/dsh-soft-editorial/source/pages/02.page +382 -0
  427. package/skills/dsh-ppt/references/editorial/dsh-soft-editorial/source/pages/03.page +479 -0
  428. package/skills/dsh-ppt/references/editorial/dsh-soft-editorial/source/pages/04.page +817 -0
  429. package/skills/dsh-ppt/references/editorial/dsh-soft-editorial/source/pages/05.page +760 -0
  430. package/skills/dsh-ppt/references/editorial/dsh-soft-editorial/source/pages/06.page +295 -0
  431. package/skills/dsh-ppt/references/editorial/dsh-soft-editorial/source/pages/07.page +365 -0
  432. package/skills/dsh-ppt/references/editorial/dsh-soft-editorial/source/pages/08.page +576 -0
  433. package/skills/dsh-ppt/references/editorial/dsh-soft-editorial/source/pages/09.page +408 -0
  434. package/skills/dsh-ppt/references/editorial/dsh-soft-editorial/source/pages/10.page +547 -0
  435. package/skills/dsh-ppt/references/editorial/dsh-soft-editorial/source/pages/11.page +575 -0
  436. package/skills/dsh-ppt/references/editorial/dsh-soft-editorial/source/pages/12.page +86 -0
  437. package/skills/dsh-ppt/references/editorial/dsh-soft-editorial/source-zh/deck.pptd +21 -0
  438. package/skills/dsh-ppt/references/editorial/dsh-soft-editorial/source-zh/pages/01.page +117 -0
  439. package/skills/dsh-ppt/references/editorial/dsh-soft-editorial/source-zh/pages/02.page +384 -0
  440. package/skills/dsh-ppt/references/editorial/dsh-soft-editorial/source-zh/pages/03.page +479 -0
  441. package/skills/dsh-ppt/references/editorial/dsh-soft-editorial/source-zh/pages/04.page +817 -0
  442. package/skills/dsh-ppt/references/editorial/dsh-soft-editorial/source-zh/pages/05.page +760 -0
  443. package/skills/dsh-ppt/references/editorial/dsh-soft-editorial/source-zh/pages/06.page +295 -0
  444. package/skills/dsh-ppt/references/editorial/dsh-soft-editorial/source-zh/pages/07.page +365 -0
  445. package/skills/dsh-ppt/references/editorial/dsh-soft-editorial/source-zh/pages/08.page +576 -0
  446. package/skills/dsh-ppt/references/editorial/dsh-soft-editorial/source-zh/pages/09.page +408 -0
  447. package/skills/dsh-ppt/references/editorial/dsh-soft-editorial/source-zh/pages/10.page +547 -0
  448. package/skills/dsh-ppt/references/editorial/dsh-soft-editorial/source-zh/pages/11.page +575 -0
  449. package/skills/dsh-ppt/references/editorial/dsh-soft-editorial/source-zh/pages/12.page +86 -0
  450. package/skills/dsh-ppt/references/pptd.md +55 -0
  451. package/skills/dsh-ppt/references/promotion/dsh-broadside/design.md +53 -0
  452. package/skills/dsh-ppt/references/promotion/dsh-broadside/metadata.json +2329 -0
  453. package/skills/dsh-ppt/references/promotion/dsh-broadside/pages/01.jpg +0 -0
  454. package/skills/dsh-ppt/references/promotion/dsh-broadside/pages/02.jpg +0 -0
  455. package/skills/dsh-ppt/references/promotion/dsh-broadside/pages/03.jpg +0 -0
  456. package/skills/dsh-ppt/references/promotion/dsh-broadside/pages/04.jpg +0 -0
  457. package/skills/dsh-ppt/references/promotion/dsh-broadside/pages/05.jpg +0 -0
  458. package/skills/dsh-ppt/references/promotion/dsh-broadside/pages/06.jpg +0 -0
  459. package/skills/dsh-ppt/references/promotion/dsh-broadside/pages/07.jpg +0 -0
  460. package/skills/dsh-ppt/references/promotion/dsh-broadside/pages/08.jpg +0 -0
  461. package/skills/dsh-ppt/references/promotion/dsh-broadside/pages/09.jpg +0 -0
  462. package/skills/dsh-ppt/references/promotion/dsh-broadside/pages/10.jpg +0 -0
  463. package/skills/dsh-ppt/references/promotion/dsh-broadside/pages/11.jpg +0 -0
  464. package/skills/dsh-ppt/references/promotion/dsh-broadside/pages/12.jpg +0 -0
  465. package/skills/dsh-ppt/references/promotion/dsh-broadside/source/deck.pptd +21 -0
  466. package/skills/dsh-ppt/references/promotion/dsh-broadside/source/pages/01.page +72 -0
  467. package/skills/dsh-ppt/references/promotion/dsh-broadside/source/pages/02.page +156 -0
  468. package/skills/dsh-ppt/references/promotion/dsh-broadside/source/pages/03.page +350 -0
  469. package/skills/dsh-ppt/references/promotion/dsh-broadside/source/pages/04.page +210 -0
  470. package/skills/dsh-ppt/references/promotion/dsh-broadside/source/pages/05.page +436 -0
  471. package/skills/dsh-ppt/references/promotion/dsh-broadside/source/pages/06.page +420 -0
  472. package/skills/dsh-ppt/references/promotion/dsh-broadside/source/pages/07.page +480 -0
  473. package/skills/dsh-ppt/references/promotion/dsh-broadside/source/pages/08.page +294 -0
  474. package/skills/dsh-ppt/references/promotion/dsh-broadside/source/pages/09.page +210 -0
  475. package/skills/dsh-ppt/references/promotion/dsh-broadside/source/pages/10.page +392 -0
  476. package/skills/dsh-ppt/references/promotion/dsh-broadside/source/pages/11.page +560 -0
  477. package/skills/dsh-ppt/references/promotion/dsh-broadside/source/pages/12.page +58 -0
  478. package/skills/dsh-ppt/references/promotion/dsh-broadside/source-zh/deck.pptd +21 -0
  479. package/skills/dsh-ppt/references/promotion/dsh-broadside/source-zh/pages/01.page +72 -0
  480. package/skills/dsh-ppt/references/promotion/dsh-broadside/source-zh/pages/02.page +156 -0
  481. package/skills/dsh-ppt/references/promotion/dsh-broadside/source-zh/pages/03.page +350 -0
  482. package/skills/dsh-ppt/references/promotion/dsh-broadside/source-zh/pages/04.page +210 -0
  483. package/skills/dsh-ppt/references/promotion/dsh-broadside/source-zh/pages/05.page +436 -0
  484. package/skills/dsh-ppt/references/promotion/dsh-broadside/source-zh/pages/06.page +420 -0
  485. package/skills/dsh-ppt/references/promotion/dsh-broadside/source-zh/pages/07.page +480 -0
  486. package/skills/dsh-ppt/references/promotion/dsh-broadside/source-zh/pages/08.page +294 -0
  487. package/skills/dsh-ppt/references/promotion/dsh-broadside/source-zh/pages/09.page +210 -0
  488. package/skills/dsh-ppt/references/promotion/dsh-broadside/source-zh/pages/10.page +392 -0
  489. package/skills/dsh-ppt/references/promotion/dsh-broadside/source-zh/pages/11.page +560 -0
  490. package/skills/dsh-ppt/references/promotion/dsh-broadside/source-zh/pages/12.page +58 -0
  491. package/skills/dsh-ppt/references/promotion/dsh-playful/design.md +61 -0
  492. package/skills/dsh-ppt/references/promotion/dsh-playful/metadata.json +3070 -0
  493. package/skills/dsh-ppt/references/promotion/dsh-playful/pages/01.jpg +0 -0
  494. package/skills/dsh-ppt/references/promotion/dsh-playful/pages/02.jpg +0 -0
  495. package/skills/dsh-ppt/references/promotion/dsh-playful/pages/03.jpg +0 -0
  496. package/skills/dsh-ppt/references/promotion/dsh-playful/pages/04.jpg +0 -0
  497. package/skills/dsh-ppt/references/promotion/dsh-playful/pages/05.jpg +0 -0
  498. package/skills/dsh-ppt/references/promotion/dsh-playful/pages/06.jpg +0 -0
  499. package/skills/dsh-ppt/references/promotion/dsh-playful/pages/07.jpg +0 -0
  500. package/skills/dsh-ppt/references/promotion/dsh-playful/pages/08.jpg +0 -0
  501. package/skills/dsh-ppt/references/promotion/dsh-playful/pages/09.jpg +0 -0
  502. package/skills/dsh-ppt/references/promotion/dsh-playful/pages/10.jpg +0 -0
  503. package/skills/dsh-ppt/references/promotion/dsh-playful/pages/11.jpg +0 -0
  504. package/skills/dsh-ppt/references/promotion/dsh-playful/pages/12.jpg +0 -0
  505. package/skills/dsh-ppt/references/promotion/dsh-playful/source/deck.pptd +21 -0
  506. package/skills/dsh-ppt/references/promotion/dsh-playful/source/pages/01.page +101 -0
  507. package/skills/dsh-ppt/references/promotion/dsh-playful/source/pages/02.page +410 -0
  508. package/skills/dsh-ppt/references/promotion/dsh-playful/source/pages/03.page +436 -0
  509. package/skills/dsh-ppt/references/promotion/dsh-playful/source/pages/04.page +845 -0
  510. package/skills/dsh-ppt/references/promotion/dsh-playful/source/pages/05.page +579 -0
  511. package/skills/dsh-ppt/references/promotion/dsh-playful/source/pages/06.page +367 -0
  512. package/skills/dsh-ppt/references/promotion/dsh-playful/source/pages/07.page +519 -0
  513. package/skills/dsh-ppt/references/promotion/dsh-playful/source/pages/08.page +323 -0
  514. package/skills/dsh-ppt/references/promotion/dsh-playful/source/pages/09.page +604 -0
  515. package/skills/dsh-ppt/references/promotion/dsh-playful/source/pages/10.page +575 -0
  516. package/skills/dsh-ppt/references/promotion/dsh-playful/source/pages/11.page +603 -0
  517. package/skills/dsh-ppt/references/promotion/dsh-playful/source/pages/12.page +86 -0
  518. package/skills/dsh-ppt/references/promotion/dsh-playful/source-zh/deck.pptd +21 -0
  519. package/skills/dsh-ppt/references/promotion/dsh-playful/source-zh/pages/01.page +100 -0
  520. package/skills/dsh-ppt/references/promotion/dsh-playful/source-zh/pages/02.page +410 -0
  521. package/skills/dsh-ppt/references/promotion/dsh-playful/source-zh/pages/03.page +436 -0
  522. package/skills/dsh-ppt/references/promotion/dsh-playful/source-zh/pages/04.page +845 -0
  523. package/skills/dsh-ppt/references/promotion/dsh-playful/source-zh/pages/05.page +579 -0
  524. package/skills/dsh-ppt/references/promotion/dsh-playful/source-zh/pages/06.page +367 -0
  525. package/skills/dsh-ppt/references/promotion/dsh-playful/source-zh/pages/07.page +519 -0
  526. package/skills/dsh-ppt/references/promotion/dsh-playful/source-zh/pages/08.page +323 -0
  527. package/skills/dsh-ppt/references/promotion/dsh-playful/source-zh/pages/09.page +604 -0
  528. package/skills/dsh-ppt/references/promotion/dsh-playful/source-zh/pages/10.page +575 -0
  529. package/skills/dsh-ppt/references/promotion/dsh-playful/source-zh/pages/11.page +603 -0
  530. package/skills/dsh-ppt/references/promotion/dsh-playful/source-zh/pages/12.page +86 -0
  531. package/skills/dsh-ppt/references/promotion/dsh-sakura-chroma/design.md +61 -0
  532. package/skills/dsh-ppt/references/promotion/dsh-sakura-chroma/metadata.json +3203 -0
  533. package/skills/dsh-ppt/references/promotion/dsh-sakura-chroma/pages/01.jpg +0 -0
  534. package/skills/dsh-ppt/references/promotion/dsh-sakura-chroma/pages/02.jpg +0 -0
  535. package/skills/dsh-ppt/references/promotion/dsh-sakura-chroma/pages/03.jpg +0 -0
  536. package/skills/dsh-ppt/references/promotion/dsh-sakura-chroma/pages/04.jpg +0 -0
  537. package/skills/dsh-ppt/references/promotion/dsh-sakura-chroma/pages/05.jpg +0 -0
  538. package/skills/dsh-ppt/references/promotion/dsh-sakura-chroma/pages/06.jpg +0 -0
  539. package/skills/dsh-ppt/references/promotion/dsh-sakura-chroma/pages/07.jpg +0 -0
  540. package/skills/dsh-ppt/references/promotion/dsh-sakura-chroma/pages/08.jpg +0 -0
  541. package/skills/dsh-ppt/references/promotion/dsh-sakura-chroma/pages/09.jpg +0 -0
  542. package/skills/dsh-ppt/references/promotion/dsh-sakura-chroma/pages/10.jpg +0 -0
  543. package/skills/dsh-ppt/references/promotion/dsh-sakura-chroma/pages/11.jpg +0 -0
  544. package/skills/dsh-ppt/references/promotion/dsh-sakura-chroma/pages/12.jpg +0 -0
  545. package/skills/dsh-ppt/references/promotion/dsh-sakura-chroma/source/deck.pptd +21 -0
  546. package/skills/dsh-ppt/references/promotion/dsh-sakura-chroma/source/pages/01.page +173 -0
  547. package/skills/dsh-ppt/references/promotion/dsh-sakura-chroma/source/pages/02.page +424 -0
  548. package/skills/dsh-ppt/references/promotion/dsh-sakura-chroma/source/pages/03.page +450 -0
  549. package/skills/dsh-ppt/references/promotion/dsh-sakura-chroma/source/pages/04.page +593 -0
  550. package/skills/dsh-ppt/references/promotion/dsh-sakura-chroma/source/pages/05.page +521 -0
  551. package/skills/dsh-ppt/references/promotion/dsh-sakura-chroma/source/pages/06.page +533 -0
  552. package/skills/dsh-ppt/references/promotion/dsh-sakura-chroma/source/pages/07.page +618 -0
  553. package/skills/dsh-ppt/references/promotion/dsh-sakura-chroma/source/pages/08.page +381 -0
  554. package/skills/dsh-ppt/references/promotion/dsh-sakura-chroma/source/pages/09.page +337 -0
  555. package/skills/dsh-ppt/references/promotion/dsh-sakura-chroma/source/pages/10.page +407 -0
  556. package/skills/dsh-ppt/references/promotion/dsh-sakura-chroma/source/pages/11.page +617 -0
  557. package/skills/dsh-ppt/references/promotion/dsh-sakura-chroma/source/pages/12.page +145 -0
  558. package/skills/dsh-ppt/references/promotion/dsh-sakura-chroma/source-zh/deck.pptd +21 -0
  559. package/skills/dsh-ppt/references/promotion/dsh-sakura-chroma/source-zh/pages/01.page +173 -0
  560. package/skills/dsh-ppt/references/promotion/dsh-sakura-chroma/source-zh/pages/02.page +424 -0
  561. package/skills/dsh-ppt/references/promotion/dsh-sakura-chroma/source-zh/pages/03.page +450 -0
  562. package/skills/dsh-ppt/references/promotion/dsh-sakura-chroma/source-zh/pages/04.page +593 -0
  563. package/skills/dsh-ppt/references/promotion/dsh-sakura-chroma/source-zh/pages/05.page +521 -0
  564. package/skills/dsh-ppt/references/promotion/dsh-sakura-chroma/source-zh/pages/06.page +533 -0
  565. package/skills/dsh-ppt/references/promotion/dsh-sakura-chroma/source-zh/pages/07.page +618 -0
  566. package/skills/dsh-ppt/references/promotion/dsh-sakura-chroma/source-zh/pages/08.page +381 -0
  567. package/skills/dsh-ppt/references/promotion/dsh-sakura-chroma/source-zh/pages/09.page +337 -0
  568. package/skills/dsh-ppt/references/promotion/dsh-sakura-chroma/source-zh/pages/10.page +407 -0
  569. package/skills/dsh-ppt/references/promotion/dsh-sakura-chroma/source-zh/pages/11.page +617 -0
  570. package/skills/dsh-ppt/references/promotion/dsh-sakura-chroma/source-zh/pages/12.page +145 -0
  571. package/skills/dsh-ppt/references/work/curated-modular-logistics-system/design.md +122 -0
  572. package/skills/dsh-ppt/references/work/curated-modular-logistics-system/metadata.json +1659 -0
  573. package/skills/dsh-ppt/references/work/curated-modular-logistics-system/pages/01.jpg +0 -0
  574. package/skills/dsh-ppt/references/work/curated-modular-logistics-system/pages/02.jpg +0 -0
  575. package/skills/dsh-ppt/references/work/curated-modular-logistics-system/pages/03.jpg +0 -0
  576. package/skills/dsh-ppt/references/work/curated-modular-logistics-system/pages/04.jpg +0 -0
  577. package/skills/dsh-ppt/references/work/curated-modular-logistics-system/pages/05.jpg +0 -0
  578. package/skills/dsh-ppt/references/work/curated-modular-logistics-system/pages/06.jpg +0 -0
  579. package/skills/dsh-ppt/references/work/curated-modular-logistics-system/pages/07.jpg +0 -0
  580. package/skills/dsh-ppt/references/work/curated-modular-logistics-system/pages/08.jpg +0 -0
  581. package/skills/dsh-ppt/references/work/curated-modular-logistics-system/pages/09.jpg +0 -0
  582. package/skills/dsh-ppt/references/work/curated-modular-logistics-system/pages/10.jpg +0 -0
  583. package/skills/dsh-ppt/references/work/curated-modular-logistics-system/pages/11.jpg +0 -0
  584. package/skills/dsh-ppt/references/work/curated-modular-logistics-system/pages/12.jpg +0 -0
  585. package/skills/dsh-ppt/references/work/curated-modular-logistics-system/source/deck.pptd +105 -0
  586. package/skills/dsh-ppt/references/work/curated-modular-logistics-system/source/pages/01.page +499 -0
  587. package/skills/dsh-ppt/references/work/curated-modular-logistics-system/source/pages/02.page +499 -0
  588. package/skills/dsh-ppt/references/work/curated-modular-logistics-system/source/pages/03.page +577 -0
  589. package/skills/dsh-ppt/references/work/curated-modular-logistics-system/source/pages/04.page +408 -0
  590. package/skills/dsh-ppt/references/work/curated-modular-logistics-system/source/pages/05.page +660 -0
  591. package/skills/dsh-ppt/references/work/curated-modular-logistics-system/source/pages/06.page +641 -0
  592. package/skills/dsh-ppt/references/work/curated-modular-logistics-system/source/pages/07.page +415 -0
  593. package/skills/dsh-ppt/references/work/curated-modular-logistics-system/source/pages/08.page +606 -0
  594. package/skills/dsh-ppt/references/work/curated-modular-logistics-system/source/pages/09.page +567 -0
  595. package/skills/dsh-ppt/references/work/curated-modular-logistics-system/source/pages/10.page +595 -0
  596. package/skills/dsh-ppt/references/work/curated-modular-logistics-system/source/pages/11.page +555 -0
  597. package/skills/dsh-ppt/references/work/curated-modular-logistics-system/source/pages/12.page +895 -0
  598. package/skills/dsh-ppt/references/work/curated-modular-logistics-system/source-zh/deck.pptd +105 -0
  599. package/skills/dsh-ppt/references/work/curated-modular-logistics-system/source-zh/pages/01.page +499 -0
  600. package/skills/dsh-ppt/references/work/curated-modular-logistics-system/source-zh/pages/02.page +499 -0
  601. package/skills/dsh-ppt/references/work/curated-modular-logistics-system/source-zh/pages/03.page +577 -0
  602. package/skills/dsh-ppt/references/work/curated-modular-logistics-system/source-zh/pages/04.page +408 -0
  603. package/skills/dsh-ppt/references/work/curated-modular-logistics-system/source-zh/pages/05.page +660 -0
  604. package/skills/dsh-ppt/references/work/curated-modular-logistics-system/source-zh/pages/06.page +641 -0
  605. package/skills/dsh-ppt/references/work/curated-modular-logistics-system/source-zh/pages/07.page +415 -0
  606. package/skills/dsh-ppt/references/work/curated-modular-logistics-system/source-zh/pages/08.page +606 -0
  607. package/skills/dsh-ppt/references/work/curated-modular-logistics-system/source-zh/pages/09.page +567 -0
  608. package/skills/dsh-ppt/references/work/curated-modular-logistics-system/source-zh/pages/10.page +595 -0
  609. package/skills/dsh-ppt/references/work/curated-modular-logistics-system/source-zh/pages/11.page +555 -0
  610. package/skills/dsh-ppt/references/work/curated-modular-logistics-system/source-zh/pages/12.page +895 -0
  611. package/skills/dsh-ppt/references/work/curated-nordic-operating-report/design.md +111 -0
  612. package/skills/dsh-ppt/references/work/curated-nordic-operating-report/metadata.json +1712 -0
  613. package/skills/dsh-ppt/references/work/curated-nordic-operating-report/pages/01.jpg +0 -0
  614. package/skills/dsh-ppt/references/work/curated-nordic-operating-report/pages/02.jpg +0 -0
  615. package/skills/dsh-ppt/references/work/curated-nordic-operating-report/pages/03.jpg +0 -0
  616. package/skills/dsh-ppt/references/work/curated-nordic-operating-report/pages/04.jpg +0 -0
  617. package/skills/dsh-ppt/references/work/curated-nordic-operating-report/pages/05.jpg +0 -0
  618. package/skills/dsh-ppt/references/work/curated-nordic-operating-report/pages/06.jpg +0 -0
  619. package/skills/dsh-ppt/references/work/curated-nordic-operating-report/pages/07.jpg +0 -0
  620. package/skills/dsh-ppt/references/work/curated-nordic-operating-report/pages/08.jpg +0 -0
  621. package/skills/dsh-ppt/references/work/curated-nordic-operating-report/pages/09.jpg +0 -0
  622. package/skills/dsh-ppt/references/work/curated-nordic-operating-report/pages/10.jpg +0 -0
  623. package/skills/dsh-ppt/references/work/curated-nordic-operating-report/pages/11.jpg +0 -0
  624. package/skills/dsh-ppt/references/work/curated-nordic-operating-report/pages/12.jpg +0 -0
  625. package/skills/dsh-ppt/references/work/curated-nordic-operating-report/source/deck.pptd +93 -0
  626. package/skills/dsh-ppt/references/work/curated-nordic-operating-report/source/pages/01.page +395 -0
  627. package/skills/dsh-ppt/references/work/curated-nordic-operating-report/source/pages/02.page +574 -0
  628. package/skills/dsh-ppt/references/work/curated-nordic-operating-report/source/pages/03.page +307 -0
  629. package/skills/dsh-ppt/references/work/curated-nordic-operating-report/source/pages/04.page +359 -0
  630. package/skills/dsh-ppt/references/work/curated-nordic-operating-report/source/pages/05.page +443 -0
  631. package/skills/dsh-ppt/references/work/curated-nordic-operating-report/source/pages/06.page +437 -0
  632. package/skills/dsh-ppt/references/work/curated-nordic-operating-report/source/pages/07.page +181 -0
  633. package/skills/dsh-ppt/references/work/curated-nordic-operating-report/source/pages/08.page +557 -0
  634. package/skills/dsh-ppt/references/work/curated-nordic-operating-report/source/pages/09.page +337 -0
  635. package/skills/dsh-ppt/references/work/curated-nordic-operating-report/source/pages/10.page +732 -0
  636. package/skills/dsh-ppt/references/work/curated-nordic-operating-report/source/pages/11.page +589 -0
  637. package/skills/dsh-ppt/references/work/curated-nordic-operating-report/source/pages/12.page +385 -0
  638. package/skills/dsh-ppt/references/work/curated-nordic-operating-report/source-zh/deck.pptd +93 -0
  639. package/skills/dsh-ppt/references/work/curated-nordic-operating-report/source-zh/pages/01.page +395 -0
  640. package/skills/dsh-ppt/references/work/curated-nordic-operating-report/source-zh/pages/02.page +574 -0
  641. package/skills/dsh-ppt/references/work/curated-nordic-operating-report/source-zh/pages/03.page +307 -0
  642. package/skills/dsh-ppt/references/work/curated-nordic-operating-report/source-zh/pages/04.page +359 -0
  643. package/skills/dsh-ppt/references/work/curated-nordic-operating-report/source-zh/pages/05.page +443 -0
  644. package/skills/dsh-ppt/references/work/curated-nordic-operating-report/source-zh/pages/06.page +437 -0
  645. package/skills/dsh-ppt/references/work/curated-nordic-operating-report/source-zh/pages/07.page +181 -0
  646. package/skills/dsh-ppt/references/work/curated-nordic-operating-report/source-zh/pages/08.page +557 -0
  647. package/skills/dsh-ppt/references/work/curated-nordic-operating-report/source-zh/pages/09.page +337 -0
  648. package/skills/dsh-ppt/references/work/curated-nordic-operating-report/source-zh/pages/10.page +732 -0
  649. package/skills/dsh-ppt/references/work/curated-nordic-operating-report/source-zh/pages/11.page +589 -0
  650. package/skills/dsh-ppt/references/work/curated-nordic-operating-report/source-zh/pages/12.page +385 -0
  651. package/skills/dsh-ppt/references/work/dsh-editorial-forest/design.md +61 -0
  652. package/skills/dsh-ppt/references/work/dsh-editorial-forest/metadata.json +3338 -0
  653. package/skills/dsh-ppt/references/work/dsh-editorial-forest/pages/01.jpg +0 -0
  654. package/skills/dsh-ppt/references/work/dsh-editorial-forest/pages/02.jpg +0 -0
  655. package/skills/dsh-ppt/references/work/dsh-editorial-forest/pages/03.jpg +0 -0
  656. package/skills/dsh-ppt/references/work/dsh-editorial-forest/pages/04.jpg +0 -0
  657. package/skills/dsh-ppt/references/work/dsh-editorial-forest/pages/05.jpg +0 -0
  658. package/skills/dsh-ppt/references/work/dsh-editorial-forest/pages/06.jpg +0 -0
  659. package/skills/dsh-ppt/references/work/dsh-editorial-forest/pages/07.jpg +0 -0
  660. package/skills/dsh-ppt/references/work/dsh-editorial-forest/pages/08.jpg +0 -0
  661. package/skills/dsh-ppt/references/work/dsh-editorial-forest/pages/09.jpg +0 -0
  662. package/skills/dsh-ppt/references/work/dsh-editorial-forest/pages/10.jpg +0 -0
  663. package/skills/dsh-ppt/references/work/dsh-editorial-forest/pages/11.jpg +0 -0
  664. package/skills/dsh-ppt/references/work/dsh-editorial-forest/pages/12.jpg +0 -0
  665. package/skills/dsh-ppt/references/work/dsh-editorial-forest/source/deck.pptd +21 -0
  666. package/skills/dsh-ppt/references/work/dsh-editorial-forest/source/pages/01.page +87 -0
  667. package/skills/dsh-ppt/references/work/dsh-editorial-forest/source/pages/02.page +382 -0
  668. package/skills/dsh-ppt/references/work/dsh-editorial-forest/source/pages/03.page +760 -0
  669. package/skills/dsh-ppt/references/work/dsh-editorial-forest/source/pages/04.page +718 -0
  670. package/skills/dsh-ppt/references/work/dsh-editorial-forest/source/pages/05.page +479 -0
  671. package/skills/dsh-ppt/references/work/dsh-editorial-forest/source/pages/06.page +576 -0
  672. package/skills/dsh-ppt/references/work/dsh-editorial-forest/source/pages/07.page +551 -0
  673. package/skills/dsh-ppt/references/work/dsh-editorial-forest/source/pages/08.page +295 -0
  674. package/skills/dsh-ppt/references/work/dsh-editorial-forest/source/pages/09.page +811 -0
  675. package/skills/dsh-ppt/references/work/dsh-editorial-forest/source/pages/10.page +547 -0
  676. package/skills/dsh-ppt/references/work/dsh-editorial-forest/source/pages/11.page +575 -0
  677. package/skills/dsh-ppt/references/work/dsh-editorial-forest/source/pages/12.page +86 -0
  678. package/skills/dsh-ppt/references/work/dsh-editorial-forest/source-zh/deck.pptd +21 -0
  679. package/skills/dsh-ppt/references/work/dsh-editorial-forest/source-zh/pages/01.page +87 -0
  680. package/skills/dsh-ppt/references/work/dsh-editorial-forest/source-zh/pages/02.page +382 -0
  681. package/skills/dsh-ppt/references/work/dsh-editorial-forest/source-zh/pages/03.page +760 -0
  682. package/skills/dsh-ppt/references/work/dsh-editorial-forest/source-zh/pages/04.page +718 -0
  683. package/skills/dsh-ppt/references/work/dsh-editorial-forest/source-zh/pages/05.page +479 -0
  684. package/skills/dsh-ppt/references/work/dsh-editorial-forest/source-zh/pages/06.page +576 -0
  685. package/skills/dsh-ppt/references/work/dsh-editorial-forest/source-zh/pages/07.page +551 -0
  686. package/skills/dsh-ppt/references/work/dsh-editorial-forest/source-zh/pages/08.page +295 -0
  687. package/skills/dsh-ppt/references/work/dsh-editorial-forest/source-zh/pages/09.page +811 -0
  688. package/skills/dsh-ppt/references/work/dsh-editorial-forest/source-zh/pages/10.page +547 -0
  689. package/skills/dsh-ppt/references/work/dsh-editorial-forest/source-zh/pages/11.page +575 -0
  690. package/skills/dsh-ppt/references/work/dsh-editorial-forest/source-zh/pages/12.page +86 -0
  691. package/skills/dsh-ppt/references/work/dsh-engineering-blueprint/design.md +61 -0
  692. package/skills/dsh-ppt/references/work/dsh-engineering-blueprint/metadata.json +3147 -0
  693. package/skills/dsh-ppt/references/work/dsh-engineering-blueprint/pages/01.jpg +0 -0
  694. package/skills/dsh-ppt/references/work/dsh-engineering-blueprint/pages/02.jpg +0 -0
  695. package/skills/dsh-ppt/references/work/dsh-engineering-blueprint/pages/03.jpg +0 -0
  696. package/skills/dsh-ppt/references/work/dsh-engineering-blueprint/pages/04.jpg +0 -0
  697. package/skills/dsh-ppt/references/work/dsh-engineering-blueprint/pages/05.jpg +0 -0
  698. package/skills/dsh-ppt/references/work/dsh-engineering-blueprint/pages/06.jpg +0 -0
  699. package/skills/dsh-ppt/references/work/dsh-engineering-blueprint/pages/07.jpg +0 -0
  700. package/skills/dsh-ppt/references/work/dsh-engineering-blueprint/pages/08.jpg +0 -0
  701. package/skills/dsh-ppt/references/work/dsh-engineering-blueprint/pages/09.jpg +0 -0
  702. package/skills/dsh-ppt/references/work/dsh-engineering-blueprint/pages/10.jpg +0 -0
  703. package/skills/dsh-ppt/references/work/dsh-engineering-blueprint/pages/11.jpg +0 -0
  704. package/skills/dsh-ppt/references/work/dsh-engineering-blueprint/pages/12.jpg +0 -0
  705. package/skills/dsh-ppt/references/work/dsh-engineering-blueprint/source/deck.pptd +21 -0
  706. package/skills/dsh-ppt/references/work/dsh-engineering-blueprint/source/pages/01.page +390 -0
  707. package/skills/dsh-ppt/references/work/dsh-engineering-blueprint/source/pages/02.page +1082 -0
  708. package/skills/dsh-ppt/references/work/dsh-engineering-blueprint/source/pages/03.page +1511 -0
  709. package/skills/dsh-ppt/references/work/dsh-engineering-blueprint/source/pages/04.page +1227 -0
  710. package/skills/dsh-ppt/references/work/dsh-engineering-blueprint/source/pages/05.page +1517 -0
  711. package/skills/dsh-ppt/references/work/dsh-engineering-blueprint/source/pages/06.page +1460 -0
  712. package/skills/dsh-ppt/references/work/dsh-engineering-blueprint/source/pages/07.page +1276 -0
  713. package/skills/dsh-ppt/references/work/dsh-engineering-blueprint/source/pages/08.page +1039 -0
  714. package/skills/dsh-ppt/references/work/dsh-engineering-blueprint/source/pages/09.page +995 -0
  715. package/skills/dsh-ppt/references/work/dsh-engineering-blueprint/source/pages/10.page +1275 -0
  716. package/skills/dsh-ppt/references/work/dsh-engineering-blueprint/source/pages/11.page +1275 -0
  717. package/skills/dsh-ppt/references/work/dsh-engineering-blueprint/source/pages/12.page +125 -0
  718. package/skills/dsh-ppt/references/work/dsh-engineering-blueprint/source-zh/deck.pptd +21 -0
  719. package/skills/dsh-ppt/references/work/dsh-engineering-blueprint/source-zh/pages/01.page +390 -0
  720. package/skills/dsh-ppt/references/work/dsh-engineering-blueprint/source-zh/pages/02.page +1084 -0
  721. package/skills/dsh-ppt/references/work/dsh-engineering-blueprint/source-zh/pages/03.page +1511 -0
  722. package/skills/dsh-ppt/references/work/dsh-engineering-blueprint/source-zh/pages/04.page +1227 -0
  723. package/skills/dsh-ppt/references/work/dsh-engineering-blueprint/source-zh/pages/05.page +1517 -0
  724. package/skills/dsh-ppt/references/work/dsh-engineering-blueprint/source-zh/pages/06.page +1460 -0
  725. package/skills/dsh-ppt/references/work/dsh-engineering-blueprint/source-zh/pages/07.page +1276 -0
  726. package/skills/dsh-ppt/references/work/dsh-engineering-blueprint/source-zh/pages/08.page +1041 -0
  727. package/skills/dsh-ppt/references/work/dsh-engineering-blueprint/source-zh/pages/09.page +995 -0
  728. package/skills/dsh-ppt/references/work/dsh-engineering-blueprint/source-zh/pages/10.page +1275 -0
  729. package/skills/dsh-ppt/references/work/dsh-engineering-blueprint/source-zh/pages/11.page +1275 -0
  730. package/skills/dsh-ppt/references/work/dsh-engineering-blueprint/source-zh/pages/12.page +125 -0
package/lib/bin.js ADDED
@@ -0,0 +1,4070 @@
1
+ #!/usr/bin/env node
2
+ import { wrapTextLines } from "./text-wrap.js";
3
+ import { access, link, lstat, mkdir, open, readFile, readdir, realpath, rename, rm, unlink, writeFile } from "node:fs/promises";
4
+ import path from "node:path";
5
+ import { pathToFileURL } from "node:url";
6
+ import { createHash, randomUUID } from "node:crypto";
7
+ import { RECOMMENDED_ZIP_LIMITS, buildPresentation, parseZip, serializePresentation } from "@aiden0z/pptx-renderer";
8
+ import { JSDOM } from "jsdom";
9
+ import yaml from "js-yaml";
10
+ import sharp from "sharp";
11
+ import PptxGenJSImport from "pptxgenjs";
12
+ const MISPLACED_TEXT_STYLE_FIELDS = new Set(["fontFamily", "fontSize", "bold", "italic", "color", "lineHeight", "letterSpacing", "wrap", "align", "verticalAlign", "textDirection", "style"]);
13
+ //#region src/pptd-convert.ts
14
+ /** Bounded PPTX to PPTD v2 conversion used by the local CLI. */
15
+ const CSS_PIXEL_TO_POINT = 72 / 96;
16
+ function record$4(value) {
17
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
18
+ }
19
+ const PRESET_COLORS = {
20
+ black: "000000",
21
+ white: "FFFFFF",
22
+ red: "FF0000",
23
+ green: "008000",
24
+ blue: "0000FF",
25
+ yellow: "FFFF00",
26
+ gray: "808080",
27
+ grey: "808080",
28
+ orange: "FFA500",
29
+ purple: "800080"
30
+ };
31
+ function childElement(element, localName) {
32
+ return element === void 0 ? void 0 : [...element.children].find((child) => child.localName === localName);
33
+ }
34
+ function descendantElement(element, localName) {
35
+ return element === void 0 ? void 0 : [...element.getElementsByTagNameNS("*", localName)][0];
36
+ }
37
+ function safeElement(value) {
38
+ return value?.element ?? void 0;
39
+ }
40
+ function themeForSlide(presentation, slideIndex) {
41
+ const layout = presentation.slideToLayout.get(slideIndex);
42
+ const master = layout === void 0 ? void 0 : presentation.layoutToMaster.get(layout);
43
+ const theme = master === void 0 ? void 0 : presentation.masterToTheme.get(master);
44
+ return theme === void 0 ? void 0 : presentation.themes.get(theme);
45
+ }
46
+ function resolvedTypeface(value, theme) {
47
+ if (value === void 0 || value === "") return void 0;
48
+ if (value.startsWith("+mj")) return theme?.majorFont.ea || theme?.majorFont.latin || "MiSans";
49
+ if (value.startsWith("+mn")) return theme?.minorFont.ea || theme?.minorFont.latin || "MiSans";
50
+ return value;
51
+ }
52
+ function applyLuminance(hex, colorNode) {
53
+ const luminanceModifier = Number(descendantElement(colorNode, "lumMod")?.getAttribute("val") ?? 1e5) / 1e5;
54
+ const luminanceOffset = Number(descendantElement(colorNode, "lumOff")?.getAttribute("val") ?? 0) / 1e5;
55
+ return [
56
+ 0,
57
+ 2,
58
+ 4
59
+ ].map((index) => Number.parseInt(hex.slice(index, index + 2), 16)).map((value) => Math.max(0, Math.min(255, Math.round(value * luminanceModifier + 255 * luminanceOffset))).toString(16).padStart(2, "0")).join("").toUpperCase();
60
+ }
61
+ function ooxmlColor(element, theme) {
62
+ if (element === void 0) return void 0;
63
+ const colorNode = [
64
+ "srgbClr",
65
+ "schemeClr",
66
+ "sysClr",
67
+ "prstClr"
68
+ ].map((name) => descendantElement(element, name)).find((value) => value !== void 0);
69
+ if (colorNode === void 0) return void 0;
70
+ const name = colorNode.localName;
71
+ const raw = colorNode.getAttribute("val") ?? "";
72
+ const base = name === "srgbClr" ? raw : name === "schemeClr" ? theme?.colorScheme.get({
73
+ tx1: "dk1",
74
+ tx2: "dk2",
75
+ bg1: "lt1",
76
+ bg2: "lt2"
77
+ }[raw] ?? raw) : name === "sysClr" ? colorNode.getAttribute("lastClr") ?? raw : PRESET_COLORS[raw.toLowerCase()];
78
+ if (base === void 0 || !/^[0-9a-f]{6}$/iu.test(base)) return void 0;
79
+ const alpha = Number(descendantElement(colorNode, "alpha")?.getAttribute("val") ?? 1e5) / 1e5;
80
+ const opacity = Math.max(0, Math.min(255, Math.round(alpha * 255))).toString(16).padStart(2, "0").toUpperCase();
81
+ return `#${applyLuminance(base.toUpperCase(), colorNode)}${opacity === "FF" ? "" : opacity}`;
82
+ }
83
+ function convertedFill(value, theme) {
84
+ const fill = safeElement(value);
85
+ if (fill === void 0 || fill.localName === "noFill") return void 0;
86
+ if (fill.localName === "solidFill") {
87
+ const resolved = ooxmlColor(fill, theme);
88
+ return resolved === void 0 ? void 0 : {
89
+ type: "solid",
90
+ color: resolved
91
+ };
92
+ }
93
+ if (fill.localName === "gradFill") {
94
+ const stops = [...fill.getElementsByTagNameNS("*", "gs")].map((stop) => ({
95
+ position: Number(stop.getAttribute("pos") ?? 0) / 1e5,
96
+ color: ooxmlColor(stop, theme)
97
+ })).filter((stop) => stop.color !== void 0);
98
+ if (stops.length < 2) return void 0;
99
+ const pathNode = childElement(fill, "path");
100
+ const angle = Number(childElement(fill, "lin")?.getAttribute("ang") ?? 0) / 6e4;
101
+ return {
102
+ type: "gradient",
103
+ gradientType: pathNode === void 0 ? "linear" : "radial",
104
+ angle,
105
+ stops
106
+ };
107
+ }
108
+ }
109
+ function convertedBorder(value, theme) {
110
+ const line = safeElement(value);
111
+ if (line === void 0 || childElement(line, "noFill") !== void 0) return void 0;
112
+ const color = ooxmlColor(line, theme);
113
+ if (color === void 0 || color.endsWith("00")) return void 0;
114
+ const dashValue = childElement(line, "prstDash")?.getAttribute("val") ?? "solid";
115
+ return {
116
+ style: dashValue.includes("dot") ? "dot" : dashValue === "solid" ? "solid" : "dash",
117
+ width: Math.max(.1, Number(line.getAttribute("w") ?? 12700) / 12700),
118
+ color
119
+ };
120
+ }
121
+ function points(value) {
122
+ return Number((value * CSS_PIXEL_TO_POINT).toFixed(3));
123
+ }
124
+ function safeId(value, fallback) {
125
+ return (value.normalize("NFKC").replace(/[^A-Za-z0-9._-]+/gu, "-").replace(/^-+|-+$/gu, "") || fallback).slice(0, 96);
126
+ }
127
+ function htmlEscape(value) {
128
+ return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\"", "&quot;");
129
+ }
130
+ function bounds(node, offsetX = 0, offsetY = 0) {
131
+ return [
132
+ points(node.position.x + offsetX),
133
+ points(node.position.y + offsetY),
134
+ points(node.size.w),
135
+ points(node.size.h)
136
+ ];
137
+ }
138
+ function textRunStyle(properties, theme) {
139
+ const color = ooxmlColor(properties, theme);
140
+ const latin = descendantElement(properties, "latin")?.getAttribute("typeface") ?? void 0;
141
+ const fontFamily = resolvedTypeface((descendantElement(properties, "ea")?.getAttribute("typeface") ?? void 0) || latin, theme);
142
+ const fontSizeRaw = Number(properties?.getAttribute("sz"));
143
+ return {
144
+ ...Number.isFinite(fontSizeRaw) && fontSizeRaw > 0 ? { fontSize: fontSizeRaw / 100 } : {},
145
+ ...fontFamily === void 0 ? {} : { fontFamily },
146
+ ...color === void 0 ? {} : { color },
147
+ ...properties?.getAttribute("b") === "1" ? { bold: true } : {},
148
+ ...properties?.getAttribute("i") === "1" ? { italic: true } : {}
149
+ };
150
+ }
151
+ function runMarkup(text, style) {
152
+ const declarations = [];
153
+ if (typeof style.color === "string") declarations.push(`color:${style.color}`);
154
+ if (typeof style.fontSize === "number") declarations.push(`font-size:${style.fontSize}px`);
155
+ if (typeof style.fontFamily === "string") declarations.push(`font-family:${style.fontFamily}`);
156
+ if (style.bold === true) declarations.push("font-weight:700");
157
+ if (style.italic === true) declarations.push("font-style:italic");
158
+ const escaped = htmlEscape(text).replaceAll("\n", "<br/>");
159
+ return declarations.length === 0 ? escaped : `<span style="${declarations.join(";")}">${escaped}</span>`;
160
+ }
161
+ function convertedText(node, textBody, theme) {
162
+ const body = safeElement(textBody?.bodyProperties);
163
+ const paragraphs = textBody?.paragraphs ?? [];
164
+ const firstParagraph = paragraphs[0];
165
+ const base = textRunStyle(safeElement(paragraphs.flatMap((paragraph) => paragraph.runs).find((run) => run.text.trim() !== "")?.properties), theme);
166
+ const paragraphAlignment = safeElement(firstParagraph?.properties)?.getAttribute("algn");
167
+ const horizontal = paragraphAlignment === "ctr" ? "center" : paragraphAlignment === "r" ? "right" : paragraphAlignment === "just" || paragraphAlignment === "dist" ? "justify" : "left";
168
+ const anchor = body?.getAttribute("anchor");
169
+ const vertical = anchor === "ctr" ? "middle" : anchor === "b" ? "bottom" : "top";
170
+ const markup = paragraphs.length === 0 ? (node.textBody?.paragraphs ?? []).map((paragraph) => `<p>${htmlEscape(paragraph.text).replaceAll("\n", "<br/>")}</p>`).join("") : paragraphs.map((paragraph) => {
171
+ const properties = safeElement(paragraph.properties);
172
+ const bullet = descendantElement(properties, "buChar")?.getAttribute("char") ?? (descendantElement(properties, "buAutoNum") === void 0 ? "" : "•");
173
+ const content = paragraph.runs.map((run) => runMarkup(run.text, textRunStyle(safeElement(run.properties), theme))).join("");
174
+ return `<p>${bullet === "" ? "" : `${htmlEscape(bullet)} `}${content}</p>`;
175
+ }).join("");
176
+ return {
177
+ markup,
178
+ content: {
179
+ fontFamily: typeof base.fontFamily === "string" ? base.fontFamily : theme?.minorFont.ea || theme?.minorFont.latin || "MiSans",
180
+ fontSize: typeof base.fontSize === "number" ? base.fontSize : 18,
181
+ color: typeof base.color === "string" ? base.color : "#000000",
182
+ align: [horizontal, vertical],
183
+ wrap: body?.getAttribute("wrap") !== "none",
184
+ text: markup
185
+ }
186
+ };
187
+ }
188
+ function lineElement(node, elementId, offsetX, offsetY, raw, theme) {
189
+ const width = Math.max(.001, points(node.size.w));
190
+ const height = Math.max(.001, points(node.size.h));
191
+ const flipHorizontal = node.flipH;
192
+ const flipVertical = node.flipV;
193
+ return {
194
+ elementId,
195
+ elementType: "line",
196
+ bounds: bounds(node, offsetX, offsetY),
197
+ viewBox: [width, height],
198
+ points: `${flipHorizontal ? width : 0},${flipVertical ? height : 0} ${flipHorizontal ? 0 : width},${flipVertical ? 0 : height}`,
199
+ border: convertedBorder(raw?.line, theme) ?? {
200
+ style: "solid",
201
+ width: 1,
202
+ color: "#000000"
203
+ },
204
+ ...node.rotation === 0 ? {} : { rotation: node.rotation }
205
+ };
206
+ }
207
+ function shapeElements(node, elementId, offsetX, offsetY, raw, theme) {
208
+ if (node.presetGeometry === "line") return [lineElement(node, elementId, offsetX, offsetY, raw, theme)];
209
+ const fill = convertedFill(raw?.fill, theme);
210
+ const border = convertedBorder(raw?.line, theme);
211
+ const text = convertedText(node, raw?.textBody, theme);
212
+ const items = [];
213
+ if (fill !== void 0 || border !== void 0 || text.markup === "") items.push({
214
+ elementId: text.markup === "" ? elementId : `${elementId}-shape`,
215
+ elementType: "shape",
216
+ bounds: bounds(node, offsetX, offsetY),
217
+ shapeName: node.presetGeometry ?? "rect",
218
+ ...fill === void 0 ? {} : { fill },
219
+ ...border === void 0 ? {} : { border },
220
+ ...node.rotation === 0 ? {} : { rotation: node.rotation },
221
+ ...!node.flipH && !node.flipV ? {} : { flip: [node.flipH, node.flipV] }
222
+ });
223
+ if (text.markup !== "") items.push({
224
+ elementId: items.length === 0 ? elementId : `${elementId}-text`,
225
+ elementType: "text",
226
+ bounds: bounds(node, offsetX, offsetY),
227
+ ...node.rotation === 0 ? {} : { rotation: node.rotation },
228
+ ...!node.flipH && !node.flipV ? {} : { flip: [node.flipH, node.flipV] },
229
+ content: text.content
230
+ });
231
+ return items;
232
+ }
233
+ function mediaType$1(file, bytes) {
234
+ const extension = path.extname(file).toLowerCase();
235
+ if (extension === ".png" && bytes[0] === 137 && bytes[1] === 80) return "image/png";
236
+ if ((extension === ".jpg" || extension === ".jpeg") && bytes[0] === 255 && bytes[1] === 216) return "image/jpeg";
237
+ if (extension === ".gif" && Buffer.from(bytes.subarray(0, 3)).toString("ascii") === "GIF") return "image/gif";
238
+ if (extension === ".webp" && Buffer.from(bytes.subarray(8, 12)).toString("ascii") === "WEBP") return "image/webp";
239
+ if (extension === ".svg" && Buffer.from(bytes.subarray(0, 512)).toString("utf8").includes("<svg")) return "image/svg+xml";
240
+ }
241
+ function normalizedRelationshipTarget(slidePath, target) {
242
+ if (target.startsWith("/")) return target.slice(1);
243
+ return path.posix.normalize(path.posix.join(path.posix.dirname(slidePath), target));
244
+ }
245
+ function chartValues(root, containerName) {
246
+ const container = root.getElementsByTagName(containerName)[0];
247
+ if (container === void 0) return [];
248
+ return [...container.getElementsByTagName("c:v")].map((node) => node.textContent ?? "");
249
+ }
250
+ function chartSeriesType(element) {
251
+ let current = element.parentElement;
252
+ while (current !== null) {
253
+ const name = current.localName;
254
+ if (name.endsWith("Chart")) {
255
+ if (name === "barChart") return "bar";
256
+ if (name === "lineChart") return "line";
257
+ if (name === "areaChart") return "area";
258
+ if (name === "pieChart" || name === "doughnutChart") return "pie";
259
+ if (name === "radarChart") return "radar";
260
+ if (name === "scatterChart") return "scatter";
261
+ if (name === "bubbleChart") return "bubble";
262
+ }
263
+ current = current.parentElement;
264
+ }
265
+ }
266
+ function chartContainer(element) {
267
+ let current = element.parentElement;
268
+ while (current !== null) {
269
+ if (current.localName.endsWith("Chart")) return current;
270
+ current = current.parentElement;
271
+ }
272
+ }
273
+ function convertedChart(node, xml, elementId, offsetX, offsetY, theme) {
274
+ const document = new DOMParser().parseFromString(xml, "application/xml");
275
+ if (document.querySelector("parsererror") !== null) return void 0;
276
+ const seriesNodes = [...document.getElementsByTagName("c:ser")];
277
+ if (seriesNodes.length === 0) return void 0;
278
+ const valueAxes = [...document.getElementsByTagName("c:valAx")];
279
+ const categoryAxis = [...document.getElementsByTagName("c:catAx")][0];
280
+ const categoryAxisReversed = descendantElement(categoryAxis, "orientation")?.getAttribute("val") === "maxMin";
281
+ const valueAxisIds = valueAxes.map((axis) => childElement(axis, "axId")?.getAttribute("val") ?? "");
282
+ const axisConfig = (axis) => {
283
+ const scaling = childElement(axis, "scaling");
284
+ const minimum = Number(childElement(scaling, "min")?.getAttribute("val"));
285
+ const maximum = Number(childElement(scaling, "max")?.getAttribute("val"));
286
+ const title = descendantElement(childElement(axis, "title"), "t")?.textContent?.trim();
287
+ return {
288
+ ...Number.isFinite(minimum) ? { min: minimum } : {},
289
+ ...Number.isFinite(maximum) ? { max: maximum } : {},
290
+ ...title === void 0 || title === "" ? {} : { title }
291
+ };
292
+ };
293
+ const convertedAxes = valueAxes.map(axisConfig);
294
+ const outputSeries = [];
295
+ const valuesBySeries = [];
296
+ let categories = [];
297
+ for (const [index, seriesNode] of seriesNodes.entries()) {
298
+ const type = chartSeriesType(seriesNode);
299
+ if (type === void 0) return void 0;
300
+ const container = chartContainer(seriesNode);
301
+ const horizontal = type === "bar" && childElement(container, "barDir")?.getAttribute("val") === "bar";
302
+ const sourceCategoryValues = type === "scatter" || type === "bubble" ? chartValues(seriesNode, "c:xVal") : chartValues(seriesNode, "c:cat");
303
+ const categoryValues = horizontal && !categoryAxisReversed ? [...sourceCategoryValues].reverse() : sourceCategoryValues;
304
+ if (categoryValues.length > categories.length) categories = categoryValues;
305
+ const sourceValues = type === "scatter" || type === "bubble" ? chartValues(seriesNode, "c:yVal") : chartValues(seriesNode, "c:val");
306
+ const values = horizontal && !categoryAxisReversed ? [...sourceValues].reverse() : sourceValues;
307
+ valuesBySeries.push(values);
308
+ const name = chartValues(seriesNode, "c:tx")[0] ?? `Series ${index + 1}`;
309
+ const valueColumn = `series_${index + 1}`;
310
+ const seriesColor = ooxmlColor(childElement(seriesNode, "spPr") ?? seriesNode, theme);
311
+ const pointColors = [...seriesNode.getElementsByTagName("c:dPt")].map((point) => ({
312
+ index: Number(childElement(point, "idx")?.getAttribute("val") ?? 0),
313
+ color: ooxmlColor(point, theme)
314
+ })).filter((point) => point.color !== void 0).sort((left, right) => left.index - right.index).map((point) => point.color);
315
+ const dataLabels = descendantElement(container, "dLbls");
316
+ const showValue = descendantElement(dataLabels, "showVal")?.getAttribute("val") === "1";
317
+ const showPercent = descendantElement(dataLabels, "showPercent")?.getAttribute("val") === "1";
318
+ const grouping = childElement(container, "grouping")?.getAttribute("val");
319
+ const containerAxisIds = container === void 0 ? [] : [...container.children].filter((child) => child.localName === "axId").map((child) => child.getAttribute("val") ?? "");
320
+ const valueAxisIndex = valueAxisIds.findIndex((axisId) => containerAxisIds.includes(axisId));
321
+ outputSeries.push({
322
+ type,
323
+ encode: type === "pie" ? {
324
+ category: "category",
325
+ value: valueColumn
326
+ } : type === "radar" ? {
327
+ category: "category",
328
+ y: valueColumn
329
+ } : horizontal ? {
330
+ x: valueColumn,
331
+ y: "category"
332
+ } : {
333
+ x: "category",
334
+ y: valueColumn
335
+ },
336
+ name,
337
+ ...pointColors.length > 0 && type === "pie" ? { fill: pointColors } : seriesColor === void 0 ? {} : type === "line" || type === "area" || type === "radar" ? { lineColor: seriesColor } : { fill: seriesColor },
338
+ ...showValue || showPercent ? { dataLabels: {
339
+ show: true,
340
+ ...showPercent ? { content: "percentage" } : {}
341
+ } } : {},
342
+ ...valueAxisIndex > 0 && !horizontal ? { yAxisIndex: valueAxisIndex } : {},
343
+ ...grouping === "stacked" ? { stack: "value" } : grouping === "percentStacked" ? { stack: "percent" } : {},
344
+ ...type === "pie" && seriesNode.parentElement?.localName === "doughnutChart" ? { innerRadius: .5 } : {}
345
+ });
346
+ }
347
+ const length = Math.max(categories.length, ...valuesBySeries.map((values) => values.length));
348
+ const rows = Array.from({ length }, (_value, row) => [categories[row] ?? String(row + 1), ...valuesBySeries.map((values) => values[row] === void 0 || values[row] === "" ? null : Number(values[row]))]);
349
+ return {
350
+ elementId,
351
+ elementType: "chart",
352
+ bounds: bounds(node, offsetX, offsetY),
353
+ data: {
354
+ cols: ["category", ...valuesBySeries.map((_values, index) => `series_${index + 1}`)],
355
+ rows
356
+ },
357
+ series: outputSeries,
358
+ legend: outputSeries.length > 1,
359
+ fontFamily: "MiSans",
360
+ ...outputSeries.some((item) => record$4(item.encode)?.y === "category") ? convertedAxes[0] === void 0 || Object.keys(convertedAxes[0]).length === 0 ? {} : { xAxis: convertedAxes[0] } : convertedAxes.length === 0 ? {} : { yAxis: convertedAxes.length === 1 ? convertedAxes[0] : convertedAxes }
361
+ };
362
+ }
363
+ function convertedTable(node, elementId, offsetX, offsetY, raw, theme) {
364
+ const columns = node.columns ?? [];
365
+ const rows = node.rows ?? [];
366
+ const totalWidth = columns.reduce((sum, value) => sum + value, 0) || 1;
367
+ const totalHeight = rows.reduce((sum, row) => sum + row.height, 0) || 1;
368
+ return {
369
+ elementId,
370
+ elementType: "table",
371
+ bounds: bounds(node, offsetX, offsetY),
372
+ columnWidths: columns.map((value) => Number((value / totalWidth).toFixed(6))),
373
+ rowHeights: rows.map((row) => Number((row.height / totalHeight).toFixed(6))),
374
+ rows: rows.map((row, rowIndex) => row.cells.map((cell, columnIndex) => {
375
+ const rawCell = raw?.rows[rowIndex]?.cells[columnIndex];
376
+ const properties = safeElement(rawCell?.properties);
377
+ const fillElement = [
378
+ "solidFill",
379
+ "gradFill",
380
+ "noFill"
381
+ ].map((name) => childElement(properties, name)).find((value) => value !== void 0);
382
+ const lineElement = [
383
+ "ln",
384
+ "lnL",
385
+ "lnR",
386
+ "lnT",
387
+ "lnB"
388
+ ].map((name) => childElement(properties, name)).find((value) => value !== void 0);
389
+ const text = convertedText({
390
+ ...node,
391
+ textBody: {
392
+ paragraphs: [{
393
+ level: 0,
394
+ text: cell.text
395
+ }],
396
+ totalText: cell.text
397
+ }
398
+ }, rawCell?.textBody, theme);
399
+ const align = Array.isArray(text.content.align) ? text.content.align : void 0;
400
+ return {
401
+ text: cell.text,
402
+ ...cell.gridSpan > 1 ? { colSpan: cell.gridSpan } : {},
403
+ ...cell.rowSpan > 1 ? { rowSpan: cell.rowSpan } : {},
404
+ ...fillElement === void 0 ? {} : { fill: convertedFill({ element: fillElement }, theme) },
405
+ ...lineElement === void 0 ? {} : { border: convertedBorder({ element: lineElement }, theme) },
406
+ ...typeof text.content.fontFamily === "string" ? { fontFamily: text.content.fontFamily } : {},
407
+ ...typeof text.content.fontSize === "number" ? { fontSize: text.content.fontSize } : {},
408
+ ...typeof text.content.color === "string" ? { color: text.content.color } : {},
409
+ ...text.content.bold === true ? { bold: true } : {},
410
+ ...text.content.italic === true ? { italic: true } : {},
411
+ ...align === void 0 ? {} : { align }
412
+ };
413
+ }))
414
+ };
415
+ }
416
+ function yamlText(value) {
417
+ return yaml.dump(value, {
418
+ schema: yaml.JSON_SCHEMA,
419
+ noRefs: true,
420
+ lineWidth: -1,
421
+ sortKeys: false
422
+ });
423
+ }
424
+ function installDomParser() {
425
+ const previous = globalThis.DOMParser;
426
+ const window = new JSDOM("").window;
427
+ Object.defineProperty(globalThis, "DOMParser", {
428
+ configurable: true,
429
+ writable: true,
430
+ value: window.DOMParser
431
+ });
432
+ return () => {
433
+ window.close();
434
+ if (previous === void 0) Reflect.deleteProperty(globalThis, "DOMParser");
435
+ else Object.defineProperty(globalThis, "DOMParser", {
436
+ configurable: true,
437
+ writable: true,
438
+ value: previous
439
+ });
440
+ };
441
+ }
442
+ /** Convert one bounded PPTX package into an editable, self-contained PPTD v2 project. */
443
+ async function convertPptxToPptd(bytes, fileName) {
444
+ const restoreDomParser = installDomParser();
445
+ try {
446
+ const files = await parseZip(bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength), RECOMMENDED_ZIP_LIMITS);
447
+ const presentation = buildPresentation(files);
448
+ const serialized = serializePresentation(presentation);
449
+ const diagnostics = [];
450
+ const pages = /* @__PURE__ */ new Map();
451
+ const assets = /* @__PURE__ */ new Map();
452
+ let sourceNodeCount = 0;
453
+ let outputElementCount = 0;
454
+ for (const slide of serialized.slides) {
455
+ const sourceSlide = presentation.slides[slide.index];
456
+ if (sourceSlide === void 0) continue;
457
+ const theme = themeForSlide(presentation, slide.index);
458
+ const output = [];
459
+ const convertNode = (node, offsetX = 0, offsetY = 0, rawNode) => {
460
+ sourceNodeCount += 1;
461
+ const elementId = safeId(node.name, `slide-${slide.index + 1}-node-${node.id}`);
462
+ if (node.nodeType === "group") {
463
+ diagnostics.push({
464
+ level: "normalized",
465
+ slide: slide.index + 1,
466
+ nodeId: node.id,
467
+ feature: "group",
468
+ message: "组合对象已展开为顺序 PPTD 元素。"
469
+ });
470
+ for (const child of node.children ?? []) convertNode(child, offsetX + node.position.x, offsetY + node.position.y);
471
+ return;
472
+ }
473
+ if (node.nodeType === "shape") {
474
+ const rawShape = rawNode?.nodeType === "shape" ? rawNode : void 0;
475
+ const elements = shapeElements(node, elementId, offsetX, offsetY, rawShape, theme);
476
+ output.push(...elements);
477
+ outputElementCount += elements.length;
478
+ if (rawShape?.customGeometry !== void 0 || descendantElement(safeElement(rawShape?.source), "effectLst") !== void 0) diagnostics.push({
479
+ level: "normalized",
480
+ slide: slide.index + 1,
481
+ nodeId: node.id,
482
+ feature: "shape-style",
483
+ message: "PPTX 形状保留几何、显式填充、边框和富文本;自定义几何或效果进入标准 PPTD 样式。"
484
+ });
485
+ return;
486
+ }
487
+ if (node.nodeType === "table") {
488
+ output.push(convertedTable(node, elementId, offsetX, offsetY, rawNode?.nodeType === "table" ? rawNode : void 0, theme));
489
+ outputElementCount += 1;
490
+ return;
491
+ }
492
+ if (node.nodeType === "chart" && node.chartPath !== void 0) {
493
+ const chartXml = files.charts.get(node.chartPath) ?? files.charts.get(node.chartPath.replace(/^\//u, ""));
494
+ const chart = chartXml === void 0 ? void 0 : convertedChart(node, chartXml, elementId, offsetX, offsetY, theme);
495
+ if (chart === void 0) diagnostics.push({
496
+ level: "unsupported",
497
+ slide: slide.index + 1,
498
+ nodeId: node.id,
499
+ feature: "chart",
500
+ message: "该 PPTX 图表没有可转换的缓存数据。"
501
+ });
502
+ else {
503
+ output.push(chart);
504
+ outputElementCount += 1;
505
+ diagnostics.push({
506
+ level: "normalized",
507
+ slide: slide.index + 1,
508
+ nodeId: node.id,
509
+ feature: "chart-style",
510
+ message: "PPTX 图表数据和类型已保留,复杂 OOXML 样式进入标准 PPTD 图表主题。"
511
+ });
512
+ }
513
+ return;
514
+ }
515
+ if (node.nodeType === "picture" && node.blipEmbed !== void 0) {
516
+ const rawPicture = rawNode?.nodeType === "picture" ? rawNode : void 0;
517
+ const relationship = sourceSlide.rels.get(node.blipEmbed);
518
+ const mediaPath = relationship === void 0 ? void 0 : normalizedRelationshipTarget(sourceSlide.slidePath, relationship.target);
519
+ const media = mediaPath === void 0 ? void 0 : files.media.get(mediaPath);
520
+ const type = mediaPath === void 0 || media === void 0 ? void 0 : mediaType$1(mediaPath, media);
521
+ if (mediaPath === void 0 || media === void 0 || type === void 0) {
522
+ diagnostics.push({
523
+ level: "unsupported",
524
+ slide: slide.index + 1,
525
+ nodeId: node.id,
526
+ feature: "picture",
527
+ message: "图片资源格式或关系无法转换。"
528
+ });
529
+ return;
530
+ }
531
+ const digest = createHash("sha256").update(media).digest("hex");
532
+ const extension = type === "image/jpeg" ? ".jpg" : type === "image/svg+xml" ? ".svg" : `.${type.slice(6)}`;
533
+ const assetPath = `media/${digest.slice(0, 24)}${extension}`;
534
+ assets.set(assetPath, {
535
+ path: assetPath,
536
+ mediaType: type,
537
+ bytes: media,
538
+ sha256: digest
539
+ });
540
+ output.push({
541
+ elementId,
542
+ elementType: "image",
543
+ bounds: bounds(node, offsetX, offsetY),
544
+ src: assetPath,
545
+ fit: { mode: "fill" },
546
+ ...!node.flipH && !node.flipV ? {} : { flip: [node.flipH, node.flipV] },
547
+ ...node.rotation === 0 ? {} : { rotation: node.rotation },
548
+ ...rawPicture?.presetGeometry === void 0 || rawPicture.presetGeometry === "rect" ? {} : { cropShape: { shapeName: rawPicture.presetGeometry } },
549
+ ...convertedBorder(rawPicture?.line, theme) === void 0 ? {} : { border: convertedBorder(rawPicture?.line, theme) }
550
+ });
551
+ outputElementCount += 1;
552
+ if (rawPicture?.crop !== void 0) diagnostics.push({
553
+ level: "normalized",
554
+ slide: slide.index + 1,
555
+ nodeId: node.id,
556
+ feature: "picture-crop",
557
+ message: "图片资源和边界已保留,OOXML 百分比裁剪进入 PPTD 填充模式。"
558
+ });
559
+ return;
560
+ }
561
+ diagnostics.push({
562
+ level: "unsupported",
563
+ slide: slide.index + 1,
564
+ nodeId: node.id,
565
+ feature: node.nodeType,
566
+ message: "该 PPTX 节点类型尚未映射到 PPTD。"
567
+ });
568
+ };
569
+ for (const node of slide.nodes) convertNode(node, 0, 0, sourceSlide.nodes.find((candidate) => candidate.id === node.id && candidate.nodeType === node.nodeType));
570
+ const pagePath = `pages/page-${slide.index + 1}.page`;
571
+ const backgroundContainer = safeElement(sourceSlide.background);
572
+ const backgroundFillElement = backgroundContainer === void 0 ? void 0 : [
573
+ "solidFill",
574
+ "gradFill",
575
+ "noFill"
576
+ ].map((name) => descendantElement(backgroundContainer, name)).find((value) => value !== void 0);
577
+ const background = backgroundFillElement === void 0 ? void 0 : convertedFill({ element: backgroundFillElement }, theme);
578
+ pages.set(pagePath, yamlText({
579
+ pageType: slide.index === 0 ? "cover" : "content",
580
+ background: background ?? {
581
+ type: "solid",
582
+ color: "#FFFFFF"
583
+ },
584
+ elements: output
585
+ }));
586
+ }
587
+ return {
588
+ source: {
589
+ entryName: "deck.pptd",
590
+ manifest: yamlText({
591
+ version: "v2",
592
+ title: (serialized.slides[0]?.nodes.find((node) => node.textBody?.totalText.trim() !== "")?.textBody?.totalText.trim())?.split(/\r?\n/u)[0]?.slice(0, 160) || path.basename(fileName, path.extname(fileName)),
593
+ size: [points(serialized.width), points(serialized.height)],
594
+ theme: {
595
+ colors: {
596
+ primary: "#1F2937",
597
+ accent: "#2563EB",
598
+ text: "#111827",
599
+ muted: "#6B7280",
600
+ background: "#FFFFFF"
601
+ },
602
+ textStyles: {
603
+ title: {
604
+ fontFamily: "MiSans",
605
+ fontSize: 36,
606
+ bold: true,
607
+ color: "$text"
608
+ },
609
+ body: {
610
+ fontFamily: "MiSans",
611
+ fontSize: 18,
612
+ color: "$text"
613
+ }
614
+ }
615
+ },
616
+ pages: [...pages.keys()]
617
+ }),
618
+ pages,
619
+ assets
620
+ },
621
+ slideCount: serialized.slideCount,
622
+ sourceNodeCount,
623
+ outputElementCount,
624
+ extractedAssetCount: assets.size,
625
+ diagnostics
626
+ };
627
+ } finally {
628
+ restoreDomParser();
629
+ }
630
+ }
631
+ //#endregion
632
+ //#region src/pptd-colors.ts
633
+ /** Deterministic series palette used when a chart series omits an explicit color. */
634
+ const PPTD_CHART_SERIES_PALETTE = [
635
+ "#2563EB",
636
+ "#F59E0B",
637
+ "#10B981",
638
+ "#EF4444",
639
+ "#8B5CF6",
640
+ "#06B6D4"
641
+ ];
642
+ function record$3(value) {
643
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
644
+ }
645
+ function themeColors(project) {
646
+ return record$3(project.theme.colors) ?? {};
647
+ }
648
+ /** Resolve a literal or theme-referenced PPTD color without applying a silent fallback. */
649
+ function resolvePptdColor(project, value) {
650
+ let current = value;
651
+ const colors = themeColors(project);
652
+ for (let depth = 0; depth < 8 && typeof current === "string" && current.startsWith("$"); depth += 1) current = colors[current.slice(1)];
653
+ return typeof current === "string" && /^#[0-9a-f]{6}(?:[0-9a-f]{2})?$/iu.test(current) ? current : void 0;
654
+ }
655
+ /**
656
+ * Normalize chart-series colors from either color scalars or solid paint objects.
657
+ * Pie series may supply an array; unsupported paints and invalid colors return undefined.
658
+ */
659
+ function resolvePptdChartSeriesColors(project, value) {
660
+ if (value === void 0) return void 0;
661
+ const values = Array.isArray(value) ? value : [value];
662
+ if (values.length === 0) return void 0;
663
+ const resolved = values.map((item) => {
664
+ const paint = record$3(item);
665
+ return resolvePptdColor(project, paint === void 0 ? item : paint.type === "solid" ? paint.color : void 0);
666
+ });
667
+ return resolved.every((item) => item !== void 0) ? resolved : void 0;
668
+ }
669
+ //#endregion
670
+ //#region src/pptd-preview.ts
671
+ /** Deterministic local SVG/PNG preview renderer for PPTD CLI screenshot workflows. */
672
+ function record$2(value) {
673
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
674
+ }
675
+ function number$1(value) {
676
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
677
+ }
678
+ function string$1(value) {
679
+ return typeof value === "string" ? value : void 0;
680
+ }
681
+ function tuple$1(value, size) {
682
+ if (!Array.isArray(value) || value.length !== size) return void 0;
683
+ const values = value.map(number$1);
684
+ return values.every((item) => item !== void 0) ? values : void 0;
685
+ }
686
+ function escapeXml(value) {
687
+ return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\"", "&quot;");
688
+ }
689
+ function themeMap$1(project, key) {
690
+ return record$2(project.theme[key]) ?? {};
691
+ }
692
+ function color(project, value, fallback = "#000000") {
693
+ return resolvePptdColor(project, value) ?? fallback;
694
+ }
695
+ function chartSeriesColor(project, value, fallback) {
696
+ return resolvePptdChartSeriesColors(project, value)?.[0] ?? fallback;
697
+ }
698
+ function chartSeriesPaint(series) {
699
+ const type = string$1(series.type) ?? "bar";
700
+ return type === "line" || type === "area" || type === "radar" ? series.lineColor ?? series.areaColor : series.fill;
701
+ }
702
+ function plainText$1(value) {
703
+ return value.replace(/<br\s*\/?\s*>/giu, "\n").replace(/<\/p\s*>/giu, "\n").replace(/<li(?:\s[^>]*)?>/giu, "• ").replace(/<\/li\s*>/giu, "\n").replace(/<[^>]+>/gu, "").replace(/&lt;/gu, "<").replace(/&gt;/gu, ">").replace(/&amp;/gu, "&").replace(/&quot;/gu, "\"").replace(/\n{3,}/gu, "\n\n").trim();
704
+ }
705
+ function frame$1(element) {
706
+ const values = tuple$1(element.bounds, 4) ?? [
707
+ 0,
708
+ 0,
709
+ 0,
710
+ 0
711
+ ];
712
+ return [
713
+ values[0] ?? 0,
714
+ values[1] ?? 0,
715
+ values[2] ?? 0,
716
+ values[3] ?? 0
717
+ ];
718
+ }
719
+ function transform(element, x, y, width, height) {
720
+ const operations = [];
721
+ const rotation = number$1(element.rotation) ?? 0;
722
+ if (rotation !== 0) operations.push(`rotate(${rotation} ${x + width / 2} ${y + height / 2})`);
723
+ const flip = Array.isArray(element.flip) ? element.flip : [];
724
+ if (flip[0] === true) operations.push(`translate(${2 * x + width} 0) scale(-1 1)`);
725
+ if (flip[1] === true) operations.push(`translate(0 ${2 * y + height}) scale(1 -1)`);
726
+ return operations.length === 0 ? "" : ` transform="${operations.join(" ")}"`;
727
+ }
728
+ function fillPaint(project, fillValue, definitions) {
729
+ const fill = record$2(fillValue);
730
+ if (fill?.type === "gradient" && Array.isArray(fill.stops) && fill.stops.length >= 2) {
731
+ const id = definitions.next("gradient");
732
+ const stops = fill.stops.map((rawStop) => {
733
+ const stop = record$2(rawStop) ?? {};
734
+ const value = color(project, stop.color);
735
+ const alpha = value.length === 9 ? Number.parseInt(value.slice(7, 9), 16) / 255 : 1;
736
+ return `<stop offset="${Math.round(Math.max(0, Math.min(1, number$1(stop.position) ?? 0)) * 100)}%" stop-color="${value.slice(0, 7)}" stop-opacity="${alpha}"/>`;
737
+ }).join("");
738
+ if (fill.gradientType === "radial") definitions.definitions.push(`<radialGradient id="${id}">${stops}</radialGradient>`);
739
+ else definitions.definitions.push(`<linearGradient id="${id}" x1="0" y1="0.5" x2="1" y2="0.5" gradientTransform="rotate(${number$1(fill.angle) ?? 0} 0.5 0.5)">${stops}</linearGradient>`);
740
+ return `url(#${id})`;
741
+ }
742
+ if (fill?.type === "solid") return color(project, fill.color);
743
+ return "none";
744
+ }
745
+ function strokePaint(project, value) {
746
+ const border = record$2(value);
747
+ if (border === void 0) return "stroke=\"none\"";
748
+ const dash = border.style === "dot" ? " stroke-dasharray=\"1 2\"" : border.style === "dash" ? " stroke-dasharray=\"5 4\"" : "";
749
+ return `stroke="${color(project, border.color)}" stroke-width="${number$1(border.width) ?? 1}"${dash}`;
750
+ }
751
+ function renderShape$1(project, element, definitions) {
752
+ const [x, y, width, height] = frame$1(element);
753
+ const common = `fill="${fillPaint(project, element.fill, definitions)}" ${strokePaint(project, element.border)}${transform(element, x, y, width, height)}`;
754
+ const shape = string$1(element.shapeName) ?? "rect";
755
+ if (shape === "custom") {
756
+ const viewBox = tuple$1(element.viewBox, 2) ?? [width, height];
757
+ return `<svg x="${x}" y="${y}" width="${width}" height="${height}" viewBox="0 0 ${viewBox[0] ?? width} ${viewBox[1] ?? height}" overflow="visible"><path d="${escapeXml(string$1(element.path) ?? "")}" fill-rule="evenodd" ${common}/></svg>`;
758
+ }
759
+ if (shape === "ellipse" || shape === "donut") return `<ellipse cx="${x + width / 2}" cy="${y + height / 2}" rx="${width / 2}" ry="${height / 2}" ${common}/>`;
760
+ if (shape === "triangle") return `<path d="M ${x + width / 2} ${y} L ${x + width} ${y + height} L ${x} ${y + height} Z" ${common}/>`;
761
+ if (shape === "diamond") return `<path d="M ${x + width / 2} ${y} L ${x + width} ${y + height / 2} L ${x + width / 2} ${y + height} L ${x} ${y + height / 2} Z" ${common}/>`;
762
+ if (shape.includes("Arrow")) return `<path d="M ${x} ${y + height * .3} H ${x + width * .65} V ${y} L ${x + width} ${y + height / 2} L ${x + width * .65} ${y + height} V ${y + height * .7} H ${x} Z" ${common}/>`;
763
+ return `<rect x="${x}" y="${y}" width="${width}" height="${height}" rx="${shape === "roundRect" || shape.startsWith("round") ? Math.min(width, height) * .12 : 0}" ${common}/>`;
764
+ }
765
+ function renderLine$1(project, element, definitions) {
766
+ const [x, y, width, height] = frame$1(element);
767
+ const viewBox = tuple$1(element.viewBox, 2) ?? [width || 1, height || 1];
768
+ const [first = [0, 0], ...rest] = (string$1(element.points) ?? "").trim().split(/\s+/u).map((value) => value.split(",").map(Number));
769
+ const scaleX = width / (viewBox[0] || 1);
770
+ const scaleY = height / (viewBox[1] || 1);
771
+ const projected = (point) => `${x + (point[0] ?? 0) * scaleX} ${y + (point[1] ?? 0) * scaleY}`;
772
+ const pathData = rest.length === 3 ? `M ${projected(first)} C ${rest.map(projected).join(" ")}` : `M ${projected(first)} ${rest.map((point) => `L ${projected(point)}`).join(" ")}`;
773
+ const arrow = Array.isArray(element.arrow) ? element.arrow : [];
774
+ const marker = (kind) => {
775
+ const id = definitions.next("arrow");
776
+ if (kind === null || kind === void 0) return "";
777
+ definitions.definitions.push(`<marker id="${id}" markerWidth="8" markerHeight="8" refX="7" refY="4" orient="auto"><path d="M0,0 L8,4 L0,8 Z" fill="context-stroke"/></marker>`);
778
+ return id;
779
+ };
780
+ const start = marker(arrow[0]);
781
+ const end = marker(arrow[1]);
782
+ return `<path d="${pathData}" fill="none" ${strokePaint(project, element.border)}${start === "" ? "" : ` marker-start="url(#${start})"`}${end === "" ? "" : ` marker-end="url(#${end})"`}${transform(element, x, y, width, height)}/>`;
783
+ }
784
+ function glyphWidth$1(character, fontSize) {
785
+ if (/\s/u.test(character)) return fontSize * .33;
786
+ if (/^[\u0000-\u00ff]$/u.test(character)) {
787
+ if (/[A-Z@#%&]/u.test(character)) return fontSize * .7;
788
+ if (/[a-z0-9]/u.test(character)) return fontSize * .55;
789
+ return fontSize * .45;
790
+ }
791
+ return fontSize;
792
+ }
793
+ function wrappedLines(text, width, fontSize, wrap) {
794
+ return wrapTextLines(text, width * .95, text => Array.from(text).reduce((sum, ch) => sum + glyphWidth$1(ch, fontSize), 0), wrap);
795
+ }
796
+
797
+ function renderText$1(project, element, definitions) {
798
+ const [x, y, width, height] = frame$1(element);
799
+ const content = record$2(element.content) ?? {};
800
+ const style = {
801
+ ...typeof content.style === "string" && content.style.startsWith("$") ? record$2(themeMap$1(project, "textStyles")[content.style.slice(1)]) ?? {} : {},
802
+ ...content
803
+ };
804
+ const fontSize = number$1(style.fontSize) ?? 18;
805
+ const lineHeight = number$1(style.lineHeightPx) ?? fontSize * (number$1(style.lineHeight) ?? 1.15);
806
+ const align = Array.isArray(style.align) ? style.align : [];
807
+ const anchor = align[0] === "center" ? "middle" : align[0] === "right" ? "end" : "start";
808
+ const startX = anchor === "middle" ? x + width / 2 : anchor === "end" ? x + width : x;
809
+ const lines = wrappedLines(plainText$1(string$1(content.text) ?? ""), width, fontSize, style.wrap !== false);
810
+ const totalHeight = Math.max(lineHeight, lines.length * lineHeight);
811
+ const startY = align[1] === "middle" ? y + (height - totalHeight) / 2 + fontSize : align[1] === "bottom" ? y + height - totalHeight + fontSize : y + fontSize;
812
+ const pair = record$2(style.fontFamily);
813
+ const eastAsian = /[\u2e80-\u9fff\uf900-\ufaff]/u.test(string$1(content.text) ?? "");
814
+ const ea = process.platform === "darwin" ? pair?.mac ?? pair?.ea : process.platform === "win32" ? pair?.win ?? pair?.ea : pair?.ea;
815
+ const family = typeof style.fontFamily === "string" ? style.fontFamily : eastAsian ? string$1(ea) ?? "sans-serif" : string$1(pair?.latin) ?? "Arial";
816
+ const opacity = number$1(element.opacity) ?? 1;
817
+ const clipId = definitions.next("text-clip");
818
+ definitions.definitions.push(`<clipPath id="${clipId}"><rect x="${x}" y="${y}" width="${Math.max(0, width)}" height="${Math.max(0, height)}"/></clipPath>`);
819
+ return `<g clip-path="url(#${clipId})"><text x="${startX}" y="${startY}" text-anchor="${anchor}" font-family="${escapeXml(family)}" font-size="${fontSize}" font-weight="${style.bold === true ? 700 : 400}" font-style="${style.italic === true ? "italic" : "normal"}" fill="${color(project, style.color)}" opacity="${opacity}"${transform(element, x, y, width, height)}>${lines.map((line, index) => `<tspan x="${startX}" dy="${index === 0 ? 0 : lineHeight}">${escapeXml(line)}</tspan>`).join("")}</text></g>`;
820
+ }
821
+ function renderImage$1(project, element, definitions) {
822
+ const [x, y, width, height] = frame$1(element);
823
+ const asset = typeof element.src === "string" ? project.source.assets.get(element.src.replace(/^\.\//u, "")) : void 0;
824
+ if (asset === void 0) return "";
825
+ const fit = string$1(record$2(element.fit)?.mode) ?? "cover";
826
+ const preserve = fit === "contain" ? "xMidYMid meet" : fit === "fill" ? "none" : "xMidYMid slice";
827
+ const clipId = definitions.next("image-clip");
828
+ const cropShape = record$2(element.cropShape);
829
+ const clip = cropShape?.shapeName === "ellipse" ? `<ellipse cx="${x + width / 2}" cy="${y + height / 2}" rx="${width / 2}" ry="${height / 2}"/>` : `<rect x="${x}" y="${y}" width="${width}" height="${height}" rx="${cropShape?.shapeName === "roundRect" ? Math.min(width, height) * .12 : 0}"/>`;
830
+ definitions.definitions.push(`<clipPath id="${clipId}">${clip}</clipPath>`);
831
+ return `<image x="${x}" y="${y}" width="${width}" height="${height}" href="${`data:${asset.mediaType};base64,${Buffer.from(asset.bytes).toString("base64")}`}" preserveAspectRatio="${preserve}" clip-path="url(#${clipId})" opacity="${number$1(element.opacity) ?? 1}"${transform(element, x, y, width, height)}/>`;
832
+ }
833
+ function renderTable$1(project, element) {
834
+ const [x, y, width, height] = frame$1(element);
835
+ const columns = Array.isArray(element.columnWidths) ? element.columnWidths.map((value) => number$1(value) ?? 0) : [];
836
+ const rowHeights = Array.isArray(element.rowHeights) ? element.rowHeights.map((value) => number$1(value) ?? 0) : [];
837
+ const rows = Array.isArray(element.rows) ? element.rows : [];
838
+ const occupied = Array.from({ length: rows.length }, () => Array.from({ length: columns.length }, () => false));
839
+ const parts = [];
840
+ for (const [rowIndex, rawRow] of rows.entries()) {
841
+ if (!Array.isArray(rawRow)) continue;
842
+ let columnIndex = 0;
843
+ for (const rawCell of rawRow) {
844
+ while (occupied[rowIndex]?.[columnIndex] === true) columnIndex += 1;
845
+ const cell = record$2(rawCell) ?? { text: String(rawCell ?? "") };
846
+ const colSpan = number$1(cell.colSpan) ?? 1;
847
+ const rowSpan = number$1(cell.rowSpan) ?? 1;
848
+ const cellX = x + columns.slice(0, columnIndex).reduce((sum, value) => sum + value, 0) * width;
849
+ const cellY = y + rowHeights.slice(0, rowIndex).reduce((sum, value) => sum + value, 0) * height;
850
+ const cellWidth = columns.slice(columnIndex, columnIndex + colSpan).reduce((sum, value) => sum + value, 0) * width;
851
+ const cellHeight = rowHeights.slice(rowIndex, rowIndex + rowSpan).reduce((sum, value) => sum + value, 0) * height;
852
+ for (let row = rowIndex; row < rowIndex + rowSpan; row += 1) {
853
+ const occupiedRow = occupied[row];
854
+ if (occupiedRow === void 0) continue;
855
+ for (let column = columnIndex; column < columnIndex + colSpan; column += 1) occupiedRow[column] = true;
856
+ }
857
+ const fill = fillPaint(project, cell.fill, {
858
+ definitions: [],
859
+ next: () => ""
860
+ });
861
+ parts.push(`<rect x="${cellX}" y="${cellY}" width="${cellWidth}" height="${cellHeight}" fill="${fill === "none" ? "#FFFFFF" : fill}" ${strokePaint(project, cell.border ?? {
862
+ color: "#D1D5DB",
863
+ width: 1
864
+ })}/>`);
865
+ parts.push(`<text x="${cellX + cellWidth / 2}" y="${cellY + cellHeight / 2}" text-anchor="middle" dominant-baseline="middle" font-family="MiSans" font-size="${number$1(cell.fontSize) ?? 11}" fill="${color(project, cell.color)}">${escapeXml(plainText$1(string$1(cell.text) ?? ""))}</text>`);
866
+ columnIndex += colSpan;
867
+ }
868
+ }
869
+ return parts.join("");
870
+ }
871
+ function renderChart$1(project, element) {
872
+ const [x, y, width, height] = frame$1(element);
873
+ const data = record$2(element.data) ?? {};
874
+ const columns = Array.isArray(data.cols) ? data.cols.map(String) : [];
875
+ const rows = Array.isArray(data.rows) ? data.rows : [];
876
+ const seriesDefaults = record$2(element.seriesDefaults) ?? {};
877
+ const series = (Array.isArray(element.series) ? element.series.map(record$2).filter((item) => item !== void 0) : []).map((item) => ({
878
+ ...record$2(seriesDefaults[string$1(item.type) ?? ""]) ?? {},
879
+ ...item
880
+ }));
881
+ const colors = PPTD_CHART_SERIES_PALETTE;
882
+ const firstEncode = record$2(series[0]?.encode) ?? {};
883
+ const firstXIndex = columns.indexOf(string$1(firstEncode.x) ?? "");
884
+ const firstYIndex = columns.indexOf(string$1(firstEncode.y) ?? "");
885
+ const firstXValues = rows.map((row) => row[firstXIndex]);
886
+ const firstYValues = rows.map((row) => row[firstYIndex]);
887
+ const firstXNumeric = firstXIndex >= 0 && firstXValues.every((value) => Number.isFinite(Number(value)));
888
+ const firstYNumeric = firstYIndex >= 0 && firstYValues.every((value) => Number.isFinite(Number(value)));
889
+ const horizontalBars = string$1(series[0]?.type) === "bar" && firstXNumeric && !firstYNumeric;
890
+ const padding = {
891
+ left: horizontalBars ? 68 : 42,
892
+ right: 24,
893
+ top: 16,
894
+ bottom: 36
895
+ };
896
+ const plotX = x + padding.left;
897
+ const plotY = y + padding.top;
898
+ const plotW = Math.max(1, width - padding.left - padding.right);
899
+ const plotH = Math.max(1, height - padding.top - padding.bottom);
900
+ const parts = [`<rect x="${x}" y="${y}" width="${width}" height="${height}" fill="none" stroke="#D1D5DB"/>`];
901
+ if ((string$1(series[0]?.type) ?? "bar") === "pie") {
902
+ const encode = record$2(series[0]?.encode) ?? {};
903
+ const valueIndex = columns.indexOf(string$1(encode.value) ?? columns[1] ?? "");
904
+ const categoryIndex = columns.indexOf(string$1(encode.category) ?? columns[0] ?? "");
905
+ const values = rows.map((row) => Math.max(0, Number(row[valueIndex] ?? 0)));
906
+ const total = values.reduce((sum, value) => sum + value, 0) || 1;
907
+ const cx = plotX + plotW / 2;
908
+ const cy = plotY + plotH / 2;
909
+ const radius = Math.min(plotW, plotH) * .38;
910
+ let angle = -Math.PI / 2;
911
+ const configuredColors = resolvePptdChartSeriesColors(project, series[0]?.fill) ?? [];
912
+ values.forEach((value, index) => {
913
+ const next = angle + value / total * Math.PI * 2;
914
+ const large = next - angle > Math.PI ? 1 : 0;
915
+ const x1 = cx + Math.cos(angle) * radius;
916
+ const y1 = cy + Math.sin(angle) * radius;
917
+ const x2 = cx + Math.cos(next) * radius;
918
+ const y2 = cy + Math.sin(next) * radius;
919
+ const sliceColor = (configuredColors.length === 0 ? void 0 : configuredColors[index % configuredColors.length]) ?? colors[index % colors.length] ?? "#2563EB";
920
+ parts.push(`<path d="M ${cx} ${cy} L ${x1} ${y1} A ${radius} ${radius} 0 ${large} 1 ${x2} ${y2} Z" fill="${sliceColor}"/>`);
921
+ const labelAngle = (angle + next) / 2;
922
+ parts.push(`<text x="${cx + Math.cos(labelAngle) * radius * .65}" y="${cy + Math.sin(labelAngle) * radius * .65}" text-anchor="middle" dominant-baseline="middle" font-size="10" fill="#FFFFFF">${escapeXml(String(rows[index]?.[categoryIndex] ?? ""))}</text>`);
923
+ angle = next;
924
+ });
925
+ const innerRadius = number$1(series[0]?.innerRadius) ?? 0;
926
+ if (innerRadius > 0) parts.push(`<circle cx="${cx}" cy="${cy}" r="${radius * Math.min(.95, innerRadius)}" fill="#FFFFFF"/>`);
927
+ return parts.join("");
928
+ }
929
+ if (horizontalBars) {
930
+ const prepared = series.map((item, index) => {
931
+ const encode = record$2(item.encode) ?? {};
932
+ const valueIndex = columns.indexOf(string$1(encode.x) ?? "");
933
+ const categoryIndex = columns.indexOf(string$1(encode.y) ?? "");
934
+ return {
935
+ item,
936
+ values: rows.map((row) => Number(row[valueIndex] ?? 0)),
937
+ categories: rows.map((row) => String(row[categoryIndex] ?? "")),
938
+ color: chartSeriesColor(project, chartSeriesPaint(item), colors[index % colors.length] ?? "#2563EB")
939
+ };
940
+ });
941
+ const allValues = prepared.flatMap((item) => item.values);
942
+ const minimum = Math.min(0, ...allValues);
943
+ const maximum = Math.max(1, ...allValues);
944
+ const scaleX = (value) => plotX + (value - minimum) / (maximum - minimum || 1) * plotW;
945
+ const zeroX = scaleX(0);
946
+ const slot = plotH / Math.max(1, rows.length);
947
+ parts.push(`<line x1="${zeroX}" y1="${plotY}" x2="${zeroX}" y2="${plotY + plotH}" stroke="#9CA3AF"/>`);
948
+ rows.forEach((_, rowIndex) => {
949
+ const label = prepared[0]?.categories[rowIndex] ?? "";
950
+ parts.push(`<text x="${plotX - 6}" y="${plotY + slot * (rowIndex + .5)}" text-anchor="end" dominant-baseline="middle" font-size="9" fill="#4B5563">${escapeXml(label)}</text>`);
951
+ });
952
+ for (const [seriesIndex, preparedSeries] of prepared.entries()) preparedSeries.values.forEach((value, rowIndex) => {
953
+ const barHeight = slot * .68 / Math.max(1, prepared.length);
954
+ const barY = plotY + slot * rowIndex + slot * .16 + seriesIndex * barHeight;
955
+ const valueX = scaleX(value);
956
+ parts.push(`<rect x="${Math.min(valueX, zeroX)}" y="${barY}" width="${Math.max(1, Math.abs(valueX - zeroX))}" height="${barHeight}" fill="${preparedSeries.color}"/>`);
957
+ if (record$2(preparedSeries.item.dataLabels)?.show === true) parts.push(`<text x="${valueX + (value >= 0 ? 4 : -4)}" y="${barY + barHeight / 2}" text-anchor="${value >= 0 ? "start" : "end"}" dominant-baseline="middle" font-size="${number$1(record$2(preparedSeries.item.dataLabels)?.fontSize) ?? 9}" fill="#374151">${escapeXml(String(value))}</text>`);
958
+ });
959
+ if (record$2(element.legend)?.show === true && prepared.length > 1) prepared.forEach((item, index) => parts.push(`<rect x="${plotX + index * 120}" y="${y + height - 14}" width="8" height="8" fill="${item.color}"/><text x="${plotX + index * 120 + 12}" y="${y + height - 7}" font-size="8" fill="#4B5563">${escapeXml(string$1(item.item.name) ?? `Series ${index + 1}`)}</text>`));
960
+ return parts.join("");
961
+ }
962
+ const allValues = [];
963
+ const prepared = series.map((item, index) => {
964
+ const encode = record$2(item.encode) ?? {};
965
+ const valueColumn = string$1(encode.y) ?? string$1(encode.value) ?? columns[1] ?? "";
966
+ const valueIndex = columns.indexOf(valueColumn);
967
+ const values = rows.map((row) => Number(row[valueIndex] ?? 0));
968
+ const xIndex = columns.indexOf(string$1(encode.x) ?? columns[0] ?? "");
969
+ const xValues = rows.map((row) => row[xIndex]);
970
+ allValues.push(...values);
971
+ const fallbackColor = colors[index % colors.length] ?? "#2563EB";
972
+ return {
973
+ item,
974
+ values,
975
+ xValues,
976
+ color: chartSeriesColor(project, chartSeriesPaint(item), fallbackColor)
977
+ };
978
+ });
979
+ const minimum = Math.min(0, ...allValues);
980
+ const maximum = Math.max(1, ...allValues);
981
+ const scaleY = (value) => plotY + plotH - (value - minimum) / (maximum - minimum || 1) * plotH;
982
+ parts.push(`<line x1="${plotX}" y1="${plotY + plotH}" x2="${plotX + plotW}" y2="${plotY + plotH}" stroke="#9CA3AF"/>`);
983
+ for (const [seriesIndex, preparedSeries] of prepared.entries()) {
984
+ const type = string$1(preparedSeries.item.type) ?? "bar";
985
+ const slot = plotW / Math.max(1, rows.length);
986
+ if (type === "line" || type === "area" || type === "scatter") {
987
+ const numericX = preparedSeries.xValues.every((value) => Number.isFinite(Number(value)));
988
+ const xNumbers = preparedSeries.xValues.map(Number);
989
+ const minX = numericX ? Math.min(...xNumbers) : 0;
990
+ const maxX = numericX ? Math.max(...xNumbers) : Math.max(1, rows.length - 1);
991
+ const pointX = (index) => {
992
+ if (!numericX) return plotX + slot * (index + .5);
993
+ return plotX + ((xNumbers[index] ?? minX) - minX) / (maxX - minX || 1) * plotW;
994
+ };
995
+ const path = preparedSeries.values.map((value, index) => `${index === 0 ? "M" : "L"} ${pointX(index)} ${scaleY(value)}`).join(" ");
996
+ if (type === "area") parts.push(`<path d="${path} L ${plotX + slot * (preparedSeries.values.length - .5)} ${scaleY(0)} L ${plotX + slot * .5} ${scaleY(0)} Z" fill="${preparedSeries.color}" opacity="0.3"/>`);
997
+ if (type === "scatter") preparedSeries.values.forEach((value, index) => parts.push(`<circle cx="${pointX(index)}" cy="${scaleY(value)}" r="3" fill="${preparedSeries.color}"/>`));
998
+ else parts.push(`<path d="${path}" fill="none" stroke="${preparedSeries.color}" stroke-width="2"/>`);
999
+ continue;
1000
+ }
1001
+ preparedSeries.values.forEach((value, index) => {
1002
+ const barWidth = slot * .72 / Math.max(1, prepared.length);
1003
+ const barX = plotX + slot * index + slot * .14 + seriesIndex * barWidth;
1004
+ const barY = scaleY(Math.max(value, 0));
1005
+ const zeroY = scaleY(0);
1006
+ parts.push(`<rect x="${barX}" y="${Math.min(barY, zeroY)}" width="${barWidth}" height="${Math.max(1, Math.abs(zeroY - barY))}" fill="${preparedSeries.color}"/>`);
1007
+ if (record$2(preparedSeries.item.dataLabels)?.show === true) parts.push(`<text x="${barX + barWidth / 2}" y="${barY - 3}" text-anchor="middle" font-size="${number$1(record$2(preparedSeries.item.dataLabels)?.fontSize) ?? 9}" fill="#374151">${escapeXml(String(value))}</text>`);
1008
+ });
1009
+ }
1010
+ const categoryLabels = prepared[0]?.xValues ?? [];
1011
+ if (categoryLabels.some((value) => !Number.isFinite(Number(value)))) categoryLabels.forEach((value, index) => parts.push(`<text x="${plotX + plotW / Math.max(1, rows.length) * (index + .5)}" y="${plotY + plotH + 13}" text-anchor="middle" font-size="8" fill="#4B5563">${escapeXml(String(value))}</text>`));
1012
+ return parts.join("");
1013
+ }
1014
+ function renderElement$1(project, element, definitions) {
1015
+ if (element.elementType === "shape") return renderShape$1(project, element, definitions);
1016
+ if (element.elementType === "line") return renderLine$1(project, element, definitions);
1017
+ if (element.elementType === "text") return renderText$1(project, element, definitions);
1018
+ if (element.elementType === "image") return renderImage$1(project, element, definitions);
1019
+ if (element.elementType === "table") return renderTable$1(project, element);
1020
+ if (element.elementType === "chart") return renderChart$1(project, element);
1021
+ if (element.elementType === "icon") {
1022
+ const [x, y, width, height] = frame$1(element);
1023
+ return `<circle cx="${x + width / 2}" cy="${y + height / 2}" r="${Math.min(width, height) / 2}" fill="${color(project, record$2(element.fill)?.color)}"/><text x="${x + width / 2}" y="${y + height / 2}" text-anchor="middle" dominant-baseline="middle" font-size="${Math.min(width, height) * .35}" fill="#FFFFFF">${escapeXml(string$1(element.iconName) ?? "icon")}</text>`;
1024
+ }
1025
+ return "";
1026
+ }
1027
+ /** Render one PPTD page to a standalone SVG string without network access. */
1028
+ function renderPptdPageSvg(project, pageIndex) {
1029
+ const page = project.pages[pageIndex];
1030
+ if (page === void 0) throw new Error(`PPTD page ${pageIndex + 1} does not exist`);
1031
+ let counter = 0;
1032
+ const definitions = {
1033
+ definitions: [],
1034
+ next(prefix) {
1035
+ counter += 1;
1036
+ return `${prefix}-${pageIndex + 1}-${counter}`;
1037
+ }
1038
+ };
1039
+ const background = fillPaint(project, page.background ?? {
1040
+ type: "solid",
1041
+ color: "#FFFFFF"
1042
+ }, definitions);
1043
+ const content = page.elements.map((element) => renderElement$1(project, element, definitions)).join("");
1044
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="${project.width}" height="${project.height}" viewBox="0 0 ${project.width} ${project.height}"><defs>${definitions.definitions.join("")}</defs><rect width="${project.width}" height="${project.height}" fill="${background === "none" ? "#FFFFFF" : background}"/>${content}</svg>`;
1045
+ }
1046
+ /** Render one PPTD page to PNG bytes through the bundled local SVG rasterizer. */
1047
+ async function renderPptdPagePng(project, pageIndex, scale = 2) {
1048
+ if (!Number.isFinite(scale) || scale <= 0 || scale > 8) throw new Error("screenshot scale must be greater than 0 and at most 8");
1049
+ const svg = renderPptdPageSvg(project, pageIndex);
1050
+ const bytes = await sharp(Buffer.from(svg)).resize({ width: Math.round(project.width * scale) }).png().toBuffer();
1051
+ return new Uint8Array(bytes);
1052
+ }
1053
+ //#endregion
1054
+ //#region src/pptd-publish.ts
1055
+ /** Atomic, non-overwriting publication primitives shared by PPTD CLI and model tools. */
1056
+ async function pathExists(target) {
1057
+ try {
1058
+ await access(target);
1059
+ return true;
1060
+ } catch {
1061
+ return false;
1062
+ }
1063
+ }
1064
+ function validateDirectoryTarget(target) {
1065
+ const resolved = path.resolve(target);
1066
+ if (resolved === path.parse(resolved).root) throw new Error("Output directory cannot be a filesystem root");
1067
+ return resolved;
1068
+ }
1069
+ /** Atomically publish one file, preserving an existing target unless replacement was explicitly requested. */
1070
+ async function publishPptdFile(target, bytes, replace) {
1071
+ const resolved = path.resolve(target);
1072
+ await mkdir(path.dirname(resolved), { recursive: true });
1073
+ const temporary = path.join(path.dirname(resolved), `.${path.basename(resolved)}.${randomUUID()}.tmp`);
1074
+ const handle = await open(temporary, "wx", 384);
1075
+ try {
1076
+ await handle.writeFile(bytes);
1077
+ await handle.sync();
1078
+ } finally {
1079
+ await handle.close();
1080
+ }
1081
+ try {
1082
+ if (replace) await rename(temporary, resolved);
1083
+ else {
1084
+ await link(temporary, resolved);
1085
+ await unlink(temporary);
1086
+ }
1087
+ } catch (error) {
1088
+ await rm(temporary, { force: true });
1089
+ if (!replace && error.code === "EEXIST") throw new Error(`Output already exists: ${resolved}`);
1090
+ throw error;
1091
+ }
1092
+ }
1093
+ /** Atomically publish one directory, preserving an existing target unless replacement was explicitly requested. */
1094
+ async function publishPptdDirectory(target, replace, writer) {
1095
+ const resolved = validateDirectoryTarget(target);
1096
+ await mkdir(path.dirname(resolved), { recursive: true });
1097
+ const stage = path.join(path.dirname(resolved), `.${path.basename(resolved)}.${randomUUID()}.stage`);
1098
+ const backup = path.join(path.dirname(resolved), `.${path.basename(resolved)}.${randomUUID()}.backup`);
1099
+ await mkdir(stage, {
1100
+ recursive: false,
1101
+ mode: 448
1102
+ });
1103
+ try {
1104
+ await writer(stage);
1105
+ if (!replace) {
1106
+ try {
1107
+ await rename(stage, resolved);
1108
+ } catch (error) {
1109
+ if (error.code === "EEXIST" || error.code === "ENOTEMPTY") throw new Error(`Output directory already exists: ${resolved}`);
1110
+ throw error;
1111
+ }
1112
+ return;
1113
+ }
1114
+ const exists = await pathExists(resolved);
1115
+ if (exists) await rename(resolved, backup);
1116
+ try {
1117
+ await rename(stage, resolved);
1118
+ if (exists) await rm(backup, {
1119
+ recursive: true,
1120
+ force: true
1121
+ });
1122
+ } catch (error) {
1123
+ if (exists && await pathExists(backup) && !await pathExists(resolved)) await rename(backup, resolved);
1124
+ throw error;
1125
+ }
1126
+ } finally {
1127
+ await rm(stage, {
1128
+ recursive: true,
1129
+ force: true
1130
+ });
1131
+ await rm(backup, {
1132
+ recursive: true,
1133
+ force: true
1134
+ });
1135
+ }
1136
+ }
1137
+ function safeOutputRelative(value) {
1138
+ if (value === "" || path.isAbsolute(value) || value.includes("\\")) throw new Error(`Unsafe generated path: ${value}`);
1139
+ const normalized = path.posix.normalize(value);
1140
+ if (normalized === ".." || normalized.startsWith("../") || normalized.startsWith("/")) throw new Error(`Unsafe generated path: ${value}`);
1141
+ return normalized;
1142
+ }
1143
+ /** Materialize a confined, self-contained PPTD source plane inside an empty staging directory. */
1144
+ async function writePptdProjectSource(directory, source) {
1145
+ const manifest = safeOutputRelative(source.entryName);
1146
+ await writeFile(path.join(directory, ...manifest.split("/")), source.manifest, {
1147
+ encoding: "utf8",
1148
+ mode: 384
1149
+ });
1150
+ for (const [relative, content] of source.pages) {
1151
+ const safe = safeOutputRelative(relative);
1152
+ const target = path.join(directory, ...safe.split("/"));
1153
+ await mkdir(path.dirname(target), {
1154
+ recursive: true,
1155
+ mode: 448
1156
+ });
1157
+ await writeFile(target, content, {
1158
+ encoding: "utf8",
1159
+ mode: 384
1160
+ });
1161
+ }
1162
+ for (const asset of source.assets.values()) {
1163
+ const safe = safeOutputRelative(asset.path);
1164
+ const target = path.join(directory, ...safe.split("/"));
1165
+ await mkdir(path.dirname(target), {
1166
+ recursive: true,
1167
+ mode: 448
1168
+ });
1169
+ await writeFile(target, asset.bytes, { mode: 384 });
1170
+ }
1171
+ }
1172
+ //#endregion
1173
+ //#region src/text-layout.ts
1174
+ /** Deterministic text-box capacity estimates shared by template references and PPT renderers. */
1175
+ const WIDTH_RESERVE = .95;
1176
+ const DEFAULT_LINE_HEIGHT = 1.15;
1177
+ function positive(value, fallback) {
1178
+ return value !== void 0 && Number.isFinite(value) && value > 0 ? value : fallback;
1179
+ }
1180
+ function glyphWidth(character) {
1181
+ if (/\p{Mark}/u.test(character)) return 0;
1182
+ if (/\s/u.test(character)) return .33;
1183
+ if (/^[ilI1|.,'`:;!]$/u.test(character)) return .3;
1184
+ if (/^[mwMW@%&]$/u.test(character)) return .82;
1185
+ if (/^[A-Z]$/u.test(character)) return .68;
1186
+ if (/^[\u0000-\u00ff]$/u.test(character)) return .56;
1187
+ if (/\p{Extended_Pictographic}/u.test(character)) return 1;
1188
+ return 1;
1189
+ }
1190
+ function lineWidth(text, fontSize, letterSpacing, bold) {
1191
+ const characters = Array.from(text);
1192
+ const glyphs = characters.reduce((sum, character) => sum + glyphWidth(character), 0);
1193
+ const spacing = Math.max(0, characters.length - 1) * letterSpacing;
1194
+ return glyphs * fontSize * (bold ? 1.04 : 1) + spacing;
1195
+ }
1196
+ /**
1197
+ * Estimate native text wrapping while retaining the authored font size.
1198
+ * @param input - Text, box geometry, and effective text style in PowerPoint points.
1199
+ * @returns Estimated line use and overflow state.
1200
+ */
1201
+ function measureTextLayout(input) {
1202
+ const fontSize = positive(input.fontSize, 18);
1203
+ const lineHeight = positive(input.lineHeight, DEFAULT_LINE_HEIGHT);
1204
+ const letterSpacing = typeof input.letterSpacing === "number" && Number.isFinite(input.letterSpacing) ? input.letterSpacing : 0;
1205
+ const availableLineWidth = Math.max(0, input.width) * WIDTH_RESERVE;
1206
+ const paragraphWidths = input.text.length === 0 ? [] : input.text.split("\n").map((line) => lineWidth(line, fontSize, letterSpacing, input.bold === true));
1207
+ const widestLine = Math.max(0, ...paragraphWidths);
1208
+ const wrap = input.wrap !== false;
1209
+ const lineCount = paragraphWidths.reduce((sum, width) => {
1210
+ if (!wrap || availableLineWidth === 0) return sum + 1;
1211
+ return sum + Math.max(1, Math.ceil(width / availableLineWidth));
1212
+ }, 0);
1213
+ const requiredHeight = lineCount * fontSize * lineHeight;
1214
+ const maxLineCount = Math.max(0, Math.floor(Math.max(0, input.height) / (fontSize * lineHeight)));
1215
+ const horizontalOverflow = !wrap && widestLine > availableLineWidth;
1216
+ return {
1217
+ lineCount,
1218
+ maxLineCount,
1219
+ requiredHeight,
1220
+ availableLineWidth,
1221
+ widestLine,
1222
+ horizontalOverflow,
1223
+ overflow: horizontalOverflow || lineCount > maxLineCount
1224
+ };
1225
+ }
1226
+ //#endregion
1227
+ //#region src/pptd.ts
1228
+ /** Local PPTD v2 parser, checker, loader, and native editable PPTX renderer. */
1229
+ const PptxGenJS = typeof PptxGenJSImport === "function" ? PptxGenJSImport : PptxGenJSImport.default;
1230
+ const POINTS_PER_INCH = 72;
1231
+ const MAX_MANIFEST_BYTES = 512 * 1024;
1232
+ const MAX_PAGE_BYTES = 2 * 1024 * 1024;
1233
+ const MAX_ASSET_BYTES = 32 * 1024 * 1024;
1234
+ const MAX_TOTAL_ASSET_BYTES = 256 * 1024 * 1024;
1235
+ const MAX_PAGES = 200;
1236
+ const MAX_ELEMENTS_PER_PAGE = 2e3;
1237
+ function record$1(value) {
1238
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
1239
+ }
1240
+ function string(value) {
1241
+ return typeof value === "string" ? value : void 0;
1242
+ }
1243
+ function number(value) {
1244
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
1245
+ }
1246
+ function boolean(value) {
1247
+ return typeof value === "boolean" ? value : void 0;
1248
+ }
1249
+ const NATIVE_CHART_TYPES = new Set([
1250
+ "bar",
1251
+ "line",
1252
+ "area",
1253
+ "scatter",
1254
+ "bubble",
1255
+ "pie",
1256
+ "radar"
1257
+ ]);
1258
+ const UNSUPPORTED_CHART_TYPES = new Set([
1259
+ "candlestick",
1260
+ "waterfall",
1261
+ "heatmap",
1262
+ "treemap",
1263
+ "sunburst",
1264
+ "sankey"
1265
+ ]);
1266
+ const NATIVE_SHAPE_NAMES = new Set(Object.values(new PptxGenJS().ShapeType));
1267
+ const MANIFEST_FIELDS$1 = new Set([
1268
+ "version",
1269
+ "title",
1270
+ "size",
1271
+ "template",
1272
+ "theme",
1273
+ "pages"
1274
+ ]);
1275
+ const TEMPLATE_FIELDS = new Set([
1276
+ "id",
1277
+ "name",
1278
+ "sourceFile",
1279
+ "sourceSha256"
1280
+ ]);
1281
+ const PAGE_FIELDS$1 = new Set([
1282
+ "pageType",
1283
+ "templateReference",
1284
+ "background",
1285
+ "notes",
1286
+ "elements"
1287
+ ]);
1288
+ const TEMPLATE_REFERENCE_FIELDS = new Set([
1289
+ "sourceSlideNumber",
1290
+ "rationale",
1291
+ "contentRelationship"
1292
+ ]);
1293
+ const TEMPLATE_RELATIONSHIPS = new Set([
1294
+ "statement",
1295
+ "independent",
1296
+ "comparison",
1297
+ "process",
1298
+ "timeline",
1299
+ "overlap",
1300
+ "data",
1301
+ "generic"
1302
+ ]);
1303
+ const ELEMENT_BASE_FIELDS = [
1304
+ "elementId",
1305
+ "elementType",
1306
+ "bounds"
1307
+ ];
1308
+ const ELEMENT_FIELDS$1 = {
1309
+ text: new Set([
1310
+ ...ELEMENT_BASE_FIELDS,
1311
+ "rotation",
1312
+ "opacity",
1313
+ "flip",
1314
+ "content"
1315
+ ]),
1316
+ shape: new Set([
1317
+ ...ELEMENT_BASE_FIELDS,
1318
+ "rotation",
1319
+ "opacity",
1320
+ "flip",
1321
+ "shapeName",
1322
+ "adjustments",
1323
+ "viewBox",
1324
+ "path",
1325
+ "fill",
1326
+ "border",
1327
+ "shadow"
1328
+ ]),
1329
+ line: new Set([
1330
+ ...ELEMENT_BASE_FIELDS,
1331
+ "rotation",
1332
+ "opacity",
1333
+ "flip",
1334
+ "viewBox",
1335
+ "points",
1336
+ "curve",
1337
+ "arrow",
1338
+ "border",
1339
+ "shadow"
1340
+ ]),
1341
+ image: new Set([
1342
+ ...ELEMENT_BASE_FIELDS,
1343
+ "rotation",
1344
+ "opacity",
1345
+ "flip",
1346
+ "src",
1347
+ "cropShape",
1348
+ "fit",
1349
+ "crop",
1350
+ "border",
1351
+ "shadow"
1352
+ ]),
1353
+ icon: new Set([
1354
+ ...ELEMENT_BASE_FIELDS,
1355
+ "rotation",
1356
+ "opacity",
1357
+ "flip",
1358
+ "iconName",
1359
+ "color",
1360
+ "fill",
1361
+ "border",
1362
+ "shadow"
1363
+ ]),
1364
+ table: new Set([
1365
+ ...ELEMENT_BASE_FIELDS,
1366
+ "columnWidths",
1367
+ "rowHeights",
1368
+ "rows",
1369
+ "style",
1370
+ "fill",
1371
+ "shadow"
1372
+ ]),
1373
+ chart: new Set([
1374
+ ...ELEMENT_BASE_FIELDS,
1375
+ "data",
1376
+ "series",
1377
+ "seriesDefaults",
1378
+ "xAxis",
1379
+ "yAxis",
1380
+ "barWidth",
1381
+ "barGap",
1382
+ "categoryGap",
1383
+ "spokeAxis",
1384
+ "title",
1385
+ "legend",
1386
+ "dataLabels",
1387
+ "fontFamily",
1388
+ "fill",
1389
+ "border",
1390
+ "shadow"
1391
+ ])
1392
+ };
1393
+ function unknownFields(value, allowed) {
1394
+ return Object.keys(value).filter((key) => !allowed.has(key));
1395
+ }
1396
+ function compatibilitySummary(project) {
1397
+ const summary = {
1398
+ native: 0,
1399
+ normalized: 0,
1400
+ vectorFallback: 0,
1401
+ rasterFallback: 0,
1402
+ unsupported: 0
1403
+ };
1404
+ const recordLevel = (level) => {
1405
+ if (level === "native") summary.native += 1;
1406
+ else if (level === "normalized") summary.normalized += 1;
1407
+ else if (level === "vector-fallback") summary.vectorFallback += 1;
1408
+ else if (level === "raster-fallback") summary.rasterFallback += 1;
1409
+ else summary.unsupported += 1;
1410
+ };
1411
+ for (const page of project.pages) for (const element of page.elements) {
1412
+ const type = string(element.elementType);
1413
+ if (type === "icon") {
1414
+ recordLevel("normalized");
1415
+ continue;
1416
+ }
1417
+ if (type === "shape" && element.shapeName === "custom") {
1418
+ recordLevel("vector-fallback");
1419
+ continue;
1420
+ }
1421
+ if (type === "line" && (string(element.curve) === "smooth" || (string(element.points)?.trim().split(/\s+/u).length ?? 0) > 2)) {
1422
+ recordLevel("vector-fallback");
1423
+ continue;
1424
+ }
1425
+ if (type === "image" && record$1(element.cropShape)?.shapeName === "custom") {
1426
+ recordLevel("raster-fallback");
1427
+ continue;
1428
+ }
1429
+ if (type === "chart") {
1430
+ const chartTypes = (Array.isArray(element.series) ? element.series.map(record$1).filter((item) => item !== void 0) : []).map((item) => string(item.type)).filter((item) => item !== void 0);
1431
+ if (chartTypes.some((item) => UNSUPPORTED_CHART_TYPES.has(item))) {
1432
+ recordLevel("unsupported");
1433
+ continue;
1434
+ }
1435
+ if (chartTypes.some((item) => !NATIVE_CHART_TYPES.has(item))) {
1436
+ recordLevel("unsupported");
1437
+ continue;
1438
+ }
1439
+ }
1440
+ const fill = record$1(element.fill);
1441
+ const content = record$1(element.content);
1442
+ recordLevel(fill?.type === "gradient" || fill?.type === "image" || content?.gradient !== void 0 || content?.shadow !== void 0 || element.shadow !== void 0 || element.adjustments !== void 0 || element.crop !== void 0 || element.cropShape !== void 0 ? "normalized" : "native");
1443
+ }
1444
+ return summary;
1445
+ }
1446
+ function tuple(value, size) {
1447
+ if (!Array.isArray(value) || value.length !== size) return void 0;
1448
+ const values = value.map(number);
1449
+ return values.every((item) => item !== void 0) ? values : void 0;
1450
+ }
1451
+ function safeProjectPath(value) {
1452
+ if (value === "" || path.isAbsolute(value) || value.includes("\\")) return void 0;
1453
+ const normalized = path.posix.normalize(value);
1454
+ return normalized === ".." || normalized.startsWith("../") || normalized.startsWith("/") ? void 0 : normalized;
1455
+ }
1456
+ function parseYaml(content, file, issues) {
1457
+ try {
1458
+ const value = record$1(yaml.load(content, {
1459
+ schema: yaml.JSON_SCHEMA,
1460
+ json: true
1461
+ }));
1462
+ if (value !== void 0) return value;
1463
+ issues.push({
1464
+ code: "yaml-root",
1465
+ severity: "error",
1466
+ file,
1467
+ message: `${file} 的 YAML 根节点必须是对象。`
1468
+ });
1469
+ } catch (error) {
1470
+ issues.push({
1471
+ code: "yaml-syntax",
1472
+ severity: "error",
1473
+ file,
1474
+ message: `${file} 无法解析:${error instanceof Error ? error.message : String(error)}`
1475
+ });
1476
+ }
1477
+ }
1478
+ /** Parse a bounded in-memory PPTD v2 project into a renderer-independent AST. */
1479
+ function parsePptdProject(source) {
1480
+ const issues = [...source.issues ?? []];
1481
+ const manifest = parseYaml(source.manifest, source.entryName, issues) ?? {};
1482
+ for (const field of unknownFields(manifest, MANIFEST_FIELDS$1)) issues.push({
1483
+ code: "unknown-field",
1484
+ severity: "error",
1485
+ file: source.entryName,
1486
+ message: `PPTD 包含未知字段 ${field}。`
1487
+ });
1488
+ if (manifest.version !== "v2") issues.push({
1489
+ code: "version",
1490
+ severity: "error",
1491
+ file: source.entryName,
1492
+ message: "PPTD version 必须为 v2。"
1493
+ });
1494
+ const size = tuple(manifest.size, 2);
1495
+ const pageWidth = size?.[0];
1496
+ const pageHeight = size?.[1];
1497
+ if (pageWidth === void 0 || pageHeight === void 0 || pageWidth <= 0 || pageHeight <= 0) issues.push({
1498
+ code: "page-size",
1499
+ severity: "error",
1500
+ file: source.entryName,
1501
+ message: "PPTD size 必须是两个正数。"
1502
+ });
1503
+ const template = manifest.template === void 0 ? void 0 : record$1(manifest.template);
1504
+ if (manifest.template !== void 0 && template === void 0) issues.push({
1505
+ code: "template",
1506
+ severity: "error",
1507
+ file: source.entryName,
1508
+ message: "PPTD template 必须是对象。"
1509
+ });
1510
+ if (template !== void 0) {
1511
+ for (const field of unknownFields(template, TEMPLATE_FIELDS)) issues.push({
1512
+ code: "unknown-field",
1513
+ severity: "error",
1514
+ file: source.entryName,
1515
+ message: `PPTD template 包含未知字段 ${field}。`
1516
+ });
1517
+ if (typeof template.id !== "string" || typeof template.name !== "string") issues.push({
1518
+ code: "template",
1519
+ severity: "error",
1520
+ file: source.entryName,
1521
+ message: "PPTD template.id 和 template.name 必须是字符串。"
1522
+ });
1523
+ if (template.sourceFile !== void 0 && typeof template.sourceFile !== "string") issues.push({
1524
+ code: "template",
1525
+ severity: "error",
1526
+ file: source.entryName,
1527
+ message: "PPTD template.sourceFile 必须是字符串。"
1528
+ });
1529
+ if (template.sourceSha256 !== void 0 && (typeof template.sourceSha256 !== "string" || !/^[0-9a-f]{64}$/iu.test(template.sourceSha256))) issues.push({
1530
+ code: "template",
1531
+ severity: "error",
1532
+ file: source.entryName,
1533
+ message: "PPTD template.sourceSha256 必须是 SHA-256。"
1534
+ });
1535
+ }
1536
+ const pageRefs = Array.isArray(manifest.pages) ? manifest.pages : [];
1537
+ if (!Array.isArray(manifest.pages) || pageRefs.length === 0 || pageRefs.length > MAX_PAGES) issues.push({
1538
+ code: "pages",
1539
+ severity: "error",
1540
+ file: source.entryName,
1541
+ message: `PPTD pages 必须包含 1 到 ${MAX_PAGES} 个页面路径。`
1542
+ });
1543
+ const pages = [];
1544
+ const seen = /* @__PURE__ */ new Set();
1545
+ for (const [index, rawRef] of pageRefs.slice(0, MAX_PAGES).entries()) {
1546
+ const ref = typeof rawRef === "string" ? safeProjectPath(rawRef) : void 0;
1547
+ if (ref === void 0 || !ref.endsWith(".page")) {
1548
+ issues.push({
1549
+ code: "page-path",
1550
+ severity: "error",
1551
+ page: index + 1,
1552
+ message: `第 ${index + 1} 个页面路径无效。`
1553
+ });
1554
+ continue;
1555
+ }
1556
+ if (seen.has(ref)) {
1557
+ issues.push({
1558
+ code: "duplicate-page",
1559
+ severity: "error",
1560
+ file: ref,
1561
+ page: index + 1,
1562
+ message: `页面 ${ref} 被重复引用。`
1563
+ });
1564
+ continue;
1565
+ }
1566
+ seen.add(ref);
1567
+ const content = source.pages.get(ref);
1568
+ if (content === void 0) {
1569
+ issues.push({
1570
+ code: "missing-page",
1571
+ severity: "error",
1572
+ file: ref,
1573
+ page: index + 1,
1574
+ message: `找不到页面文件 ${ref}。`
1575
+ });
1576
+ continue;
1577
+ }
1578
+ const parsed = parseYaml(content, ref, issues);
1579
+ if (parsed === void 0) continue;
1580
+ for (const field of unknownFields(parsed, PAGE_FIELDS$1)) issues.push({
1581
+ code: "unknown-field",
1582
+ severity: "error",
1583
+ file: ref,
1584
+ page: index + 1,
1585
+ message: `页面包含未知字段 ${field}。`
1586
+ });
1587
+ const elements = Array.isArray(parsed.elements) ? parsed.elements.map(record$1).filter((item) => item !== void 0) : [];
1588
+ if (!Array.isArray(parsed.elements) || elements.length > MAX_ELEMENTS_PER_PAGE) issues.push({
1589
+ code: "elements",
1590
+ severity: "error",
1591
+ file: ref,
1592
+ page: index + 1,
1593
+ message: `页面 elements 必须是数组且不超过 ${MAX_ELEMENTS_PER_PAGE} 个元素。`
1594
+ });
1595
+ const background = record$1(parsed.background);
1596
+ const templateReference = parsed.templateReference === void 0 ? void 0 : record$1(parsed.templateReference);
1597
+ if (parsed.templateReference !== void 0 && templateReference === void 0) issues.push({
1598
+ code: "template-reference",
1599
+ severity: "error",
1600
+ file: ref,
1601
+ page: index + 1,
1602
+ message: "页面 templateReference 必须是对象。"
1603
+ });
1604
+ if (templateReference !== void 0) {
1605
+ for (const field of unknownFields(templateReference, TEMPLATE_REFERENCE_FIELDS)) issues.push({
1606
+ code: "unknown-field",
1607
+ severity: "error",
1608
+ file: ref,
1609
+ page: index + 1,
1610
+ message: `页面 templateReference 包含未知字段 ${field}。`
1611
+ });
1612
+ if (!Number.isInteger(templateReference.sourceSlideNumber) || Number(templateReference.sourceSlideNumber) <= 0) issues.push({
1613
+ code: "template-reference",
1614
+ severity: "error",
1615
+ file: ref,
1616
+ page: index + 1,
1617
+ message: "页面 templateReference.sourceSlideNumber 必须是正整数。"
1618
+ });
1619
+ if (typeof templateReference.rationale !== "string" || templateReference.rationale.trim() === "") issues.push({
1620
+ code: "template-reference",
1621
+ severity: "error",
1622
+ file: ref,
1623
+ page: index + 1,
1624
+ message: "页面 templateReference.rationale 必须说明源页选择理由。"
1625
+ });
1626
+ if (templateReference.contentRelationship !== void 0 && (typeof templateReference.contentRelationship !== "string" || !TEMPLATE_RELATIONSHIPS.has(templateReference.contentRelationship))) issues.push({
1627
+ code: "template-reference",
1628
+ severity: "error",
1629
+ file: ref,
1630
+ page: index + 1,
1631
+ message: "页面 templateReference.contentRelationship 必须是受支持的内容关系。"
1632
+ });
1633
+ }
1634
+ for (const element of elements) {
1635
+ const type = string(element.elementType);
1636
+ const allowed = type === void 0 ? void 0 : ELEMENT_FIELDS$1[type];
1637
+ if (allowed === void 0) continue;
1638
+ for (const field of unknownFields(element, allowed)) issues.push({
1639
+ code: type === "text" && MISPLACED_TEXT_STYLE_FIELDS.has(field) ? "misplaced-text-style" : "unknown-field",
1640
+ severity: "error",
1641
+ file: ref,
1642
+ page: index + 1,
1643
+ ...typeof element.elementId === "string" ? { elementId: element.elementId } : {},
1644
+ message: type === "text" && MISPLACED_TEXT_STYLE_FIELDS.has(field) ? `文本属性 ${field} 应放在 content 内,请修正 YAML 缩进。` : `元素包含未知字段 ${field}。`
1645
+ });
1646
+ }
1647
+ pages.push({
1648
+ file: ref,
1649
+ ...typeof parsed.pageType === "string" ? { pageType: parsed.pageType } : {},
1650
+ ...templateReference === void 0 || !Number.isInteger(templateReference.sourceSlideNumber) || typeof templateReference.rationale !== "string" ? {} : { templateReference: {
1651
+ sourceSlideNumber: Number(templateReference.sourceSlideNumber),
1652
+ rationale: templateReference.rationale,
1653
+ ...typeof templateReference.contentRelationship === "string" && TEMPLATE_RELATIONSHIPS.has(templateReference.contentRelationship) ? { contentRelationship: templateReference.contentRelationship } : {}
1654
+ } },
1655
+ ...background === void 0 ? {} : { background },
1656
+ notes: typeof parsed.notes === "string" ? parsed.notes : "",
1657
+ elements: elements.slice(0, MAX_ELEMENTS_PER_PAGE)
1658
+ });
1659
+ }
1660
+ return {
1661
+ source,
1662
+ title: typeof manifest.title === "string" ? manifest.title : path.basename(source.entryName, ".pptd"),
1663
+ width: pageWidth ?? 960,
1664
+ height: pageHeight ?? 540,
1665
+ ...template === void 0 ? {} : { template },
1666
+ theme: record$1(manifest.theme) ?? {},
1667
+ pages,
1668
+ parseIssues: issues
1669
+ };
1670
+ }
1671
+ function projectDigest(project) {
1672
+ const hash = createHash("sha256").update(project.source.manifest);
1673
+ for (const page of project.pages) hash.update(page.file).update(project.source.pages.get(page.file) ?? "");
1674
+ for (const asset of [...project.source.assets.values()].sort((left, right) => left.path.localeCompare(right.path))) hash.update(asset.path).update(asset.sha256);
1675
+ return hash.digest("hex");
1676
+ }
1677
+ function themeMap(project, key) {
1678
+ return record$1(project.theme[key]) ?? {};
1679
+ }
1680
+ function themeReferenceIssue(project, value, mapName, file, page, elementId) {
1681
+ if (typeof value !== "string" || !value.startsWith("$")) return void 0;
1682
+ const key = value.slice(1);
1683
+ if (key !== "" && key in themeMap(project, mapName)) return void 0;
1684
+ return {
1685
+ code: "invalid-theme",
1686
+ severity: "error",
1687
+ file,
1688
+ ...page === void 0 ? {} : { page },
1689
+ ...elementId === void 0 ? {} : { elementId },
1690
+ message: `主题引用 ${value} 不存在于 theme.${mapName}。`
1691
+ };
1692
+ }
1693
+ function colorThemeIssues(project, value, file, page, elementId) {
1694
+ const issues = [];
1695
+ const visited = /* @__PURE__ */ new WeakSet();
1696
+ const visit = (current, field) => {
1697
+ if (typeof current === "string") {
1698
+ if (field === "color" || field === "backgroundColor" || field === "lineColor" || field === "areaColor" || field === "fill") {
1699
+ const issue = themeReferenceIssue(project, current, "colors", file, page, elementId);
1700
+ if (issue !== void 0) issues.push(issue);
1701
+ }
1702
+ return;
1703
+ }
1704
+ if (Array.isArray(current)) {
1705
+ if (visited.has(current)) return;
1706
+ visited.add(current);
1707
+ for (const item of current) visit(item, field);
1708
+ return;
1709
+ }
1710
+ const object = record$1(current);
1711
+ if (object === void 0) return;
1712
+ if (visited.has(object)) return;
1713
+ visited.add(object);
1714
+ for (const [key, child] of Object.entries(object)) visit(child, key === "fill" ? "fill" : key);
1715
+ };
1716
+ visit(value);
1717
+ return issues;
1718
+ }
1719
+ function themeColorChainIssues(project) {
1720
+ const colors = themeMap(project, "colors");
1721
+ const issues = [];
1722
+ const reportedCycles = /* @__PURE__ */ new Set();
1723
+ const reportedInvalidTerminals = /* @__PURE__ */ new Set();
1724
+ for (const start of Object.keys(colors)) {
1725
+ const path = [];
1726
+ let key = start;
1727
+ while (true) {
1728
+ const cycleIndex = path.indexOf(key);
1729
+ if (cycleIndex >= 0) {
1730
+ const cycle = path.slice(cycleIndex);
1731
+ const signature = [...cycle].sort().join("\0");
1732
+ if (!reportedCycles.has(signature)) {
1733
+ reportedCycles.add(signature);
1734
+ issues.push({
1735
+ code: "invalid-theme",
1736
+ severity: "error",
1737
+ file: project.source.entryName,
1738
+ message: `theme.colors 存在循环引用:${[...cycle, key].map((item) => `$${item}`).join(" -> ")}。`
1739
+ });
1740
+ }
1741
+ break;
1742
+ }
1743
+ path.push(key);
1744
+ const value = colors[key];
1745
+ if (typeof value !== "string" || !value.startsWith("$")) {
1746
+ if (key !== start && (typeof value !== "string" || !/^#[0-9a-f]{6}(?:[0-9a-f]{2})?$/iu.test(value))) {
1747
+ if (!reportedInvalidTerminals.has(key)) {
1748
+ reportedInvalidTerminals.add(key);
1749
+ issues.push({
1750
+ code: "invalid-theme",
1751
+ severity: "error",
1752
+ file: project.source.entryName,
1753
+ message: `theme.colors.${start} 最终指向无效颜色 theme.colors.${key}。`
1754
+ });
1755
+ }
1756
+ }
1757
+ break;
1758
+ }
1759
+ const next = value.slice(1);
1760
+ if (!(next in colors)) break;
1761
+ key = next;
1762
+ }
1763
+ }
1764
+ return issues;
1765
+ }
1766
+ function resolveThemeReference(value, map) {
1767
+ if (typeof value !== "string" || !value.startsWith("$")) return value;
1768
+ return map[value.slice(1)];
1769
+ }
1770
+ function resolveColorValue(project, value, fallback = "#000000") {
1771
+ return resolvePptdColor(project, value) ?? fallback;
1772
+ }
1773
+ function colorOptions(project, value, opacity = 1) {
1774
+ const resolved = resolveColorValue(project, value);
1775
+ const alpha = resolved.length === 9 ? Number.parseInt(resolved.slice(7, 9), 16) / 255 : 1;
1776
+ const transparency = Math.round((1 - Math.max(0, Math.min(1, alpha * opacity))) * 100);
1777
+ return {
1778
+ color: resolved.slice(1, 7).toUpperCase(),
1779
+ ...transparency === 0 ? {} : { transparency }
1780
+ };
1781
+ }
1782
+ function readableForeground(background) {
1783
+ const red = Number.parseInt(background.slice(0, 2), 16) / 255;
1784
+ const green = Number.parseInt(background.slice(2, 4), 16) / 255;
1785
+ const blue = Number.parseInt(background.slice(4, 6), 16) / 255;
1786
+ return red * .2126 + green * .7152 + blue * .0722 < .5 ? "E2E8F0" : "1F2937";
1787
+ }
1788
+ function textStyle(project, content) {
1789
+ return {
1790
+ ...record$1(resolveThemeReference(content.style, themeMap(project, "textStyles"))) ?? {},
1791
+ ...content
1792
+ };
1793
+ }
1794
+ function plainText(value) {
1795
+ return value.replace(/<br\s*\/?\s*>/giu, "\n").replace(/<\/p\s*>/giu, "\n").replace(/<li(?:\s[^>]*)?>/giu, "• ").replace(/<\/li\s*>/giu, "\n").replace(/<[^>]+>/gu, "").replace(/&lt;/gu, "<").replace(/&gt;/gu, ">").replace(/&amp;/gu, "&").replace(/&quot;/gu, "\"").replace(/\n{3,}/gu, "\n\n").trimEnd();
1796
+ }
1797
+ function textLayout(project, element) {
1798
+ // Fix structural errors before estimating layout with fallback styles.
1799
+ if (unknownFields(element, ELEMENT_FIELDS.text).length > 0) return void 0;
1800
+ const bounds = tuple(element.bounds, 4);
1801
+ const content = record$1(element.content);
1802
+ if (bounds === void 0 || content === void 0 || typeof content.text !== "string" || plainText(content.text).trim() === "") return void 0;
1803
+ const style = textStyle(project, content);
1804
+ const fontSize = number(style.fontSize) ?? 18;
1805
+ const inlineSizes = Array.from(content.text.matchAll(/font-size\s*:\s*(\d+(?:\.\d+)?)px/giu), (match) => Number(match[1]));
1806
+ const vertical = style.textDirection === "vertical";
1807
+ const lineHeight = number(style.lineHeight);
1808
+ const letterSpacing = number(style.letterSpacing);
1809
+ const wrap = boolean(style.wrap);
1810
+ return measureTextLayout({
1811
+ text: plainText(content.text),
1812
+ width: bounds[vertical ? 3 : 2] ?? 0,
1813
+ height: bounds[vertical ? 2 : 3] ?? 0,
1814
+ fontSize: Math.max(fontSize, ...inlineSizes),
1815
+ bold: boolean(style.bold) === true || /<(?:b|strong)(?:\s|>)/iu.test(content.text),
1816
+ ...lineHeight === void 0 ? {} : { lineHeight },
1817
+ ...letterSpacing === void 0 ? {} : { letterSpacing },
1818
+ ...wrap === void 0 ? {} : { wrap }
1819
+ });
1820
+ }
1821
+ function localAssetPath(value) {
1822
+ if (typeof value !== "string" || /^https?:\/\//iu.test(value)) return void 0;
1823
+ return safeProjectPath(value);
1824
+ }
1825
+ function elementContext(page, element) {
1826
+ return {
1827
+ page,
1828
+ ...typeof element.elementId === "string" ? { elementId: element.elementId } : {}
1829
+ };
1830
+ }
1831
+ function compatibilityIssue(page, context, level, feature) {
1832
+ const severity = level === "unsupported" ? "error" : "warning";
1833
+ return {
1834
+ code: `compatibility-${level}`,
1835
+ severity,
1836
+ file: page.file,
1837
+ ...context,
1838
+ message: `${feature} 的渲染兼容级别为 ${level}。`
1839
+ };
1840
+ }
1841
+ function validTableGrid(element) {
1842
+ const rows = Array.isArray(element.rows) ? element.rows : [];
1843
+ const columnWidths = Array.isArray(element.columnWidths) ? element.columnWidths.map(number) : [];
1844
+ const rowHeights = Array.isArray(element.rowHeights) ? element.rowHeights.map(number) : [];
1845
+ const columnCount = columnWidths.length;
1846
+ const rowCount = rowHeights.length;
1847
+ if (rowCount === 0 || columnCount === 0 || rows.length !== rowCount) return false;
1848
+ if (columnWidths.some((value) => value === void 0 || value < 0 || value > 1) || rowHeights.some((value) => value === void 0 || value < 0 || value > 1)) return false;
1849
+ const nearOne = (values) => {
1850
+ const total = values.reduce((sum, value) => sum + (value ?? 0), 0);
1851
+ return Math.abs(total - 1) < .001;
1852
+ };
1853
+ if (!nearOne(columnWidths) || !nearOne(rowHeights)) return false;
1854
+ const occupied = Array.from({ length: rowCount }, () => Array.from({ length: columnCount }, () => false));
1855
+ for (const [rowIndex, rawRow] of rows.entries()) {
1856
+ if (!Array.isArray(rawRow)) return false;
1857
+ let columnIndex = 0;
1858
+ for (const rawCell of rawRow) {
1859
+ while (columnIndex < columnCount && occupied[rowIndex]?.[columnIndex] === true) columnIndex += 1;
1860
+ const cell = record$1(rawCell) ?? {};
1861
+ const rowSpan = number(cell.rowSpan) ?? 1;
1862
+ const colSpan = number(cell.colSpan) ?? 1;
1863
+ if (!Number.isInteger(rowSpan) || !Number.isInteger(colSpan) || rowSpan < 1 || colSpan < 1 || rowIndex + rowSpan > rowCount || columnIndex + colSpan > columnCount) return false;
1864
+ for (let row = rowIndex; row < rowIndex + rowSpan; row += 1) {
1865
+ const occupiedRow = occupied[row];
1866
+ if (occupiedRow === void 0) return false;
1867
+ for (let column = columnIndex; column < columnIndex + colSpan; column += 1) {
1868
+ if (occupiedRow[column] === true) return false;
1869
+ occupiedRow[column] = true;
1870
+ }
1871
+ }
1872
+ columnIndex += colSpan;
1873
+ }
1874
+ if (occupied[rowIndex]?.some((value) => !value) === true) return false;
1875
+ }
1876
+ return true;
1877
+ }
1878
+ function checkElement(project, page, pageNumber, element, ids) {
1879
+ const issues = [];
1880
+ const context = elementContext(pageNumber, element);
1881
+ const id = string(element.elementId);
1882
+ issues.push(...colorThemeIssues(project, element, page.file, pageNumber, id));
1883
+ if (id === void 0 || id.trim() === "") issues.push({
1884
+ code: "element-id",
1885
+ severity: "error",
1886
+ file: page.file,
1887
+ ...context,
1888
+ message: "元素缺少 elementId。"
1889
+ });
1890
+ else if (ids.has(id)) issues.push({
1891
+ code: "duplicate-id",
1892
+ severity: "error",
1893
+ file: page.file,
1894
+ ...context,
1895
+ message: `元素 ID ${id} 重复。`
1896
+ });
1897
+ else ids.add(id);
1898
+ const bounds = tuple(element.bounds, 4);
1899
+ const [x = 0, y = 0, width = -1, height = -1] = bounds ?? [];
1900
+ if (bounds === void 0 || width < 0 || height < 0) issues.push({
1901
+ code: "bounds",
1902
+ severity: "error",
1903
+ file: page.file,
1904
+ ...context,
1905
+ message: "元素 bounds 必须是 [x, y, width, height]。"
1906
+ });
1907
+ else if (x < 0 || y < 0 || x + width > project.width + .01 || y + height > project.height + .01) issues.push({
1908
+ code: "out-of-bounds",
1909
+ severity: "error",
1910
+ file: page.file,
1911
+ ...context,
1912
+ message: "元素超出 PPTD 页面边界。"
1913
+ });
1914
+ const type = string(element.elementType);
1915
+ if (![
1916
+ "text",
1917
+ "shape",
1918
+ "line",
1919
+ "image",
1920
+ "icon",
1921
+ "table",
1922
+ "chart"
1923
+ ].includes(type ?? "")) {
1924
+ issues.push({
1925
+ code: "element-type",
1926
+ severity: "error",
1927
+ file: page.file,
1928
+ ...context,
1929
+ message: `不支持的 elementType:${type ?? "missing"}。`
1930
+ });
1931
+ return issues;
1932
+ }
1933
+ if (type === "text") {
1934
+ const content = record$1(element.content);
1935
+ const styleIssue = themeReferenceIssue(project, content?.style, "textStyles", page.file, pageNumber, id);
1936
+ if (styleIssue !== void 0) issues.push(styleIssue);
1937
+ if (content === void 0 || typeof content.text !== "string") issues.push({
1938
+ code: "text-content",
1939
+ severity: "error",
1940
+ file: page.file,
1941
+ ...context,
1942
+ message: "文本元素需要 content.text。"
1943
+ });
1944
+ else {
1945
+ const layout = textLayout(project, element);
1946
+ if (layout?.overflow === true) {
1947
+ const message = layout.horizontalOverflow ? `文本设置为不换行,但预计宽度 ${Math.ceil(layout.widestLine)}pt 超过文本框可用宽度 ${Math.floor(layout.availableLineWidth)}pt;请缩短文案或增大文本框。` : `文本预计需要 ${layout.lineCount} 行,当前文本框可容纳 ${layout.maxLineCount} 行;请缩短文案、增大文本框或拆分页面。`;
1948
+ issues.push({
1949
+ code: "text-overflow",
1950
+ severity: "error",
1951
+ file: page.file,
1952
+ ...context,
1953
+ message
1954
+ });
1955
+ }
1956
+ }
1957
+ if (content !== void 0 && (content.gradient !== void 0 || content.shadow !== void 0)) issues.push(compatibilityIssue(page, context, "normalized", "文本渐变或阴影"));
1958
+ if (typeof content?.text === "string" && /<(?:u|s|sup|sub|a|ol)(?:\s|>)/iu.test(content.text)) issues.push(compatibilityIssue(page, context, "normalized", "高级富文本标签"));
1959
+ }
1960
+ if (type === "shape") {
1961
+ const name = string(element.shapeName);
1962
+ if (name === void 0) issues.push({
1963
+ code: "shape-name",
1964
+ severity: "error",
1965
+ file: page.file,
1966
+ ...context,
1967
+ message: "形状元素需要 shapeName。"
1968
+ });
1969
+ else if (name === "custom") if (tuple(element.viewBox, 2) === void 0 || typeof element.path !== "string") issues.push({
1970
+ code: "custom-shape",
1971
+ severity: "error",
1972
+ file: page.file,
1973
+ ...context,
1974
+ message: "自定义形状需要 viewBox 和 SVG path。"
1975
+ });
1976
+ else issues.push(compatibilityIssue(page, context, "vector-fallback", "自定义 SVG 形状"));
1977
+ else if (!NATIVE_SHAPE_NAMES.has(name)) issues.push({
1978
+ code: "shape-name",
1979
+ severity: "error",
1980
+ file: page.file,
1981
+ ...context,
1982
+ message: `未知的内置形状:${name}。`
1983
+ });
1984
+ if (element.adjustments !== void 0) issues.push(compatibilityIssue(page, context, "normalized", "形状 adjustments"));
1985
+ const fill = record$1(element.fill);
1986
+ if (fill?.type === "gradient" || fill?.type === "image") issues.push(compatibilityIssue(page, context, "normalized", "形状渐变或图片填充"));
1987
+ if (element.shadow !== void 0) issues.push(compatibilityIssue(page, context, "normalized", "形状阴影"));
1988
+ }
1989
+ if (type === "line") {
1990
+ const points = typeof element.points === "string" ? element.points.trim().split(/\s+/u) : [];
1991
+ const invalidPoint = points.some((point) => !/^-?\d+(?:\.\d+)?,-?\d+(?:\.\d+)?$/u.test(point));
1992
+ if (tuple(element.viewBox, 2) === void 0 || points.length < 2 || invalidPoint) issues.push({
1993
+ code: "line-path",
1994
+ severity: "error",
1995
+ file: page.file,
1996
+ ...context,
1997
+ message: "线条元素需要有效的 viewBox 和至少两个 points。"
1998
+ });
1999
+ else if (points.length > 2 || element.curve === "smooth") issues.push(compatibilityIssue(page, context, "vector-fallback", "贝塞尔曲线"));
2000
+ if (element.shadow !== void 0) issues.push(compatibilityIssue(page, context, "normalized", "线条阴影"));
2001
+ }
2002
+ if (type === "image") {
2003
+ if (typeof element.src !== "string") issues.push({
2004
+ code: "image-src",
2005
+ severity: "error",
2006
+ file: page.file,
2007
+ ...context,
2008
+ message: "图片元素需要 src。"
2009
+ });
2010
+ else if (/^https?:\/\//iu.test(element.src)) issues.push({
2011
+ code: "remote-image",
2012
+ severity: "error",
2013
+ file: page.file,
2014
+ ...context,
2015
+ message: "本地 PPTD 渲染器不访问网络图片,请先将图片放入项目目录。"
2016
+ });
2017
+ else {
2018
+ const assetPath = localAssetPath(element.src);
2019
+ if (assetPath === void 0 || !project.source.assets.has(assetPath)) issues.push({
2020
+ code: "missing-asset",
2021
+ severity: "error",
2022
+ file: page.file,
2023
+ ...context,
2024
+ message: `找不到图片资源 ${element.src}。`
2025
+ });
2026
+ }
2027
+ const fit = record$1(element.fit);
2028
+ if (fit !== void 0 && ![
2029
+ "fill",
2030
+ "contain",
2031
+ "cover"
2032
+ ].includes(string(fit.mode) ?? "")) issues.push({
2033
+ code: "image-fit",
2034
+ severity: "error",
2035
+ file: page.file,
2036
+ ...context,
2037
+ message: "图片 fit.mode 必须是 fill、contain 或 cover。"
2038
+ });
2039
+ if (element.crop !== void 0 || element.cropShape !== void 0 || element.shadow !== void 0 || element.border !== void 0) {
2040
+ const cropShape = record$1(element.cropShape);
2041
+ issues.push(compatibilityIssue(page, context, cropShape?.shapeName === "custom" ? "raster-fallback" : "normalized", "图片裁剪、边框或阴影"));
2042
+ }
2043
+ }
2044
+ if (type === "table") {
2045
+ if (typeof element.style === "string") {
2046
+ const styleIssue = themeReferenceIssue(project, element.style, "tableStyles", page.file, pageNumber, id);
2047
+ if (styleIssue !== void 0) issues.push(styleIssue);
2048
+ }
2049
+ const rows = Array.isArray(element.rows) ? element.rows : [];
2050
+ for (const rawRow of rows) for (const rawCell of Array.isArray(rawRow) ? rawRow : []) {
2051
+ const styleIssue = themeReferenceIssue(project, record$1(rawCell)?.textStyle, "textStyles", page.file, pageNumber, id);
2052
+ if (styleIssue !== void 0) issues.push(styleIssue);
2053
+ }
2054
+ if (!validTableGrid(element)) issues.push({
2055
+ code: "table-data",
2056
+ severity: "error",
2057
+ file: page.file,
2058
+ ...context,
2059
+ message: "表格网格、宽高比例或合并区域无效。"
2060
+ });
2061
+ }
2062
+ if (type === "chart") {
2063
+ const data = record$1(element.data);
2064
+ const cols = Array.isArray(data?.cols) ? data.cols : [];
2065
+ const rows = Array.isArray(data?.rows) ? data.rows : [];
2066
+ const series = Array.isArray(element.series) ? element.series.map(record$1).filter((item) => item !== void 0) : [];
2067
+ const validRows = rows.every((row) => Array.isArray(row) && row.length === cols.length);
2068
+ const validSeries = series.length > 0 && series.every((item) => {
2069
+ const encode = record$1(item.encode);
2070
+ const refs = encode === void 0 ? [] : Object.values(encode).filter((value) => typeof value === "string");
2071
+ return typeof item.type === "string" && refs.length >= 2 && refs.every((ref) => cols.includes(ref));
2072
+ });
2073
+ if (cols.length < 2 || rows.length === 0 || !validRows || !validSeries) issues.push({
2074
+ code: "chart-data",
2075
+ severity: "error",
2076
+ file: page.file,
2077
+ ...context,
2078
+ message: "图表 data/series/encode 结构不完整。"
2079
+ });
2080
+ const chartTypes = series.map((item) => string(item.type)).filter((item) => item !== void 0);
2081
+ const unknownTypes = chartTypes.filter((item) => !NATIVE_CHART_TYPES.has(item) && !UNSUPPORTED_CHART_TYPES.has(item));
2082
+ if (unknownTypes.length > 0) issues.push({
2083
+ code: "chart-type",
2084
+ severity: "error",
2085
+ file: page.file,
2086
+ ...context,
2087
+ message: `未知的图表类型:${[...new Set(unknownTypes)].join("、")}。`
2088
+ });
2089
+ const unsupportedTypes = chartTypes.filter((item) => UNSUPPORTED_CHART_TYPES.has(item));
2090
+ if (unsupportedTypes.length > 0) issues.push(compatibilityIssue(page, context, "unsupported", `图表类型 ${[...new Set(unsupportedTypes)].join("、")}`));
2091
+ const seriesDefaults = record$1(element.seriesDefaults) ?? {};
2092
+ for (const [seriesIndex, item] of series.entries()) {
2093
+ const chartType = string(item.type) ?? "bar";
2094
+ const effective = {
2095
+ ...record$1(seriesDefaults[chartType]) ?? {},
2096
+ ...item
2097
+ };
2098
+ const paint = chartType === "line" || chartType === "area" || chartType === "radar" ? effective.lineColor ?? effective.areaColor : effective.fill;
2099
+ if (paint === void 0) continue;
2100
+ const multipleColors = Array.isArray(paint);
2101
+ const validColors = resolvePptdChartSeriesColors(project, paint) !== void 0;
2102
+ if (multipleColors && chartType !== "pie" || !validColors) issues.push({
2103
+ code: "chart-series-color",
2104
+ severity: "error",
2105
+ file: page.file,
2106
+ ...context,
2107
+ message: `图表序列 ${seriesIndex + 1} 的颜色需要使用 #RRGGBB、#RRGGBBAA、主题颜色引用或 solid 填充;饼图同时接受颜色数组。`
2108
+ });
2109
+ }
2110
+ }
2111
+ if (type === "icon") if (typeof element.iconName !== "string") issues.push({
2112
+ code: "icon-name",
2113
+ severity: "error",
2114
+ file: page.file,
2115
+ ...context,
2116
+ message: "图标元素需要 iconName。"
2117
+ });
2118
+ else issues.push(compatibilityIssue(page, context, "normalized", "Font Awesome 图标"));
2119
+ return issues;
2120
+ }
2121
+ function textLayerIssues(project, page, pageNumber) {
2122
+ const issues = [];
2123
+ const overlap = (left, right) => {
2124
+ const rightEdge = Math.min((left[0] ?? 0) + (left[2] ?? 0), (right[0] ?? 0) + (right[2] ?? 0));
2125
+ const leftEdge = Math.max(left[0] ?? 0, right[0] ?? 0);
2126
+ const bottomEdge = Math.min((left[1] ?? 0) + (left[3] ?? 0), (right[1] ?? 0) + (right[3] ?? 0));
2127
+ const topEdge = Math.max(left[1] ?? 0, right[1] ?? 0);
2128
+ const width = Math.max(0, rightEdge - leftEdge);
2129
+ return {
2130
+ area: width * Math.max(0, bottomEdge - topEdge),
2131
+ width
2132
+ };
2133
+ };
2134
+ for (const [index, element] of page.elements.entries()) {
2135
+ if (element.elementType !== "text") continue;
2136
+ const textBounds = tuple(element.bounds, 4);
2137
+ if (textBounds === void 0 || (textBounds[2] ?? 0) <= 0 || (textBounds[3] ?? 0) <= 0) continue;
2138
+ const textArea = (textBounds[2] ?? 0) * (textBounds[3] ?? 0);
2139
+ const estimatedBottom = (textBounds[1] ?? 0) + (textLayout(project, element)?.requiredHeight ?? 0);
2140
+ for (const earlier of page.elements.slice(0, index)) {
2141
+ if (earlier.elementType !== "table" && earlier.elementType !== "chart") continue;
2142
+ const earlierBounds = tuple(earlier.bounds, 4);
2143
+ if (earlierBounds === void 0) continue;
2144
+ if (overlap(textBounds, earlierBounds).area / textArea >= .15) {
2145
+ issues.push({
2146
+ code: "text-occlusion",
2147
+ severity: "warning",
2148
+ file: page.file,
2149
+ page: pageNumber,
2150
+ ...typeof element.elementId === "string" ? { elementId: element.elementId } : {},
2151
+ message: `文本与 ${string(earlier.elementId) ?? earlier.elementType} 的内容区域重叠。`
2152
+ });
2153
+ break;
2154
+ }
2155
+ }
2156
+ for (const later of page.elements.slice(index + 1)) {
2157
+ if (later.elementType === "line" || number(later.opacity) === 0) continue;
2158
+ const laterBounds = tuple(later.bounds, 4);
2159
+ if (laterBounds === void 0) continue;
2160
+ const intersection = overlap(textBounds, laterBounds);
2161
+ if (intersection.area / textArea >= .15) {
2162
+ issues.push({
2163
+ code: "text-occlusion",
2164
+ severity: "warning",
2165
+ file: page.file,
2166
+ page: pageNumber,
2167
+ ...typeof element.elementId === "string" ? { elementId: element.elementId } : {},
2168
+ message: `文本可能被后绘制元素 ${string(later.elementId) ?? later.elementType ?? "unknown"} 遮挡。`
2169
+ });
2170
+ break;
2171
+ }
2172
+ const laterTop = laterBounds[1] ?? 0;
2173
+ if (laterTop > (textBounds[1] ?? 0) && laterTop < (textBounds[1] ?? 0) + (textBounds[3] ?? 0) && estimatedBottom > laterTop && intersection.width / (textBounds[2] ?? 1) >= .3) {
2174
+ issues.push({
2175
+ code: "text-drift",
2176
+ severity: "warning",
2177
+ file: page.file,
2178
+ page: pageNumber,
2179
+ ...typeof element.elementId === "string" ? { elementId: element.elementId } : {},
2180
+ message: `文本可能跨入下方元素 ${string(later.elementId) ?? later.elementType ?? "unknown"} 的边界。`
2181
+ });
2182
+ break;
2183
+ }
2184
+ }
2185
+ }
2186
+ return issues;
2187
+ }
2188
+ function isCompositionBookend(page) {
2189
+ return /^(?:cover|title|opening|section|closing|final)$/iu.test(page.pageType?.trim() ?? "");
2190
+ }
2191
+ function visibleTextSizes(project, page) {
2192
+ return page.elements.flatMap((element) => {
2193
+ if (element.elementType !== "text") return [];
2194
+ const content = record$1(element.content);
2195
+ if (content === void 0 || typeof content.text !== "string" || plainText(content.text).trim() === "") return [];
2196
+ return [number(textStyle(project, content).fontSize) ?? 18];
2197
+ });
2198
+ }
2199
+ function coverFocusIssues(project) {
2200
+ const canvasArea = project.width * project.height;
2201
+ return project.pages.flatMap((page, index) => {
2202
+ if (!/^(?:cover|title|opening)$/iu.test(page.pageType?.trim() ?? "")) return [];
2203
+ if (page.elements.reduce((largest, element) => {
2204
+ if (![
2205
+ "image",
2206
+ "chart",
2207
+ "table"
2208
+ ].includes(string(element.elementType) ?? "")) return largest;
2209
+ const bounds = tuple(element.bounds, 4);
2210
+ if (bounds === void 0 || canvasArea <= 0) return largest;
2211
+ return Math.max(largest, (bounds[2] ?? 0) * (bounds[3] ?? 0) / canvasArea);
2212
+ }, 0) >= .25) return [];
2213
+ const sizes = visibleTextSizes(project, page).sort((left, right) => left - right);
2214
+ if (sizes.length < 3) return [];
2215
+ const middle = Math.floor(sizes.length / 2);
2216
+ const median = sizes.length % 2 === 1 ? sizes[middle] ?? 0 : ((sizes[middle - 1] ?? 0) + (sizes[middle] ?? 0)) / 2;
2217
+ const largest = sizes.at(-1) ?? 0;
2218
+ if (median > 0 && largest / median >= 3) return [];
2219
+ return [{
2220
+ code: "cover-focus",
2221
+ severity: "warning",
2222
+ file: page.file,
2223
+ page: index + 1,
2224
+ message: "封面需要更明确的首读焦点:让一张图片、图表或表格占据至少 25% 画布,或让最大标题达到可见文字中位字号的 3 倍。"
2225
+ }];
2226
+ });
2227
+ }
2228
+ function compositionFamily(element) {
2229
+ const type = string(element.elementType);
2230
+ if (type === "text" || type === "icon") return "text";
2231
+ if (type === "image" || type === "chart" || type === "table") return "visual";
2232
+ if (type === "shape") return "shape";
2233
+ }
2234
+ function layoutSignature(project, page) {
2235
+ const canvasArea = project.width * project.height;
2236
+ const landmarks = /* @__PURE__ */ new Set();
2237
+ for (const element of page.elements) {
2238
+ const family = compositionFamily(element);
2239
+ const bounds = tuple(element.bounds, 4);
2240
+ if (family === void 0 || bounds === void 0 || canvasArea <= 0) continue;
2241
+ const [x = 0, y = 0, width = 0, height = 0] = bounds;
2242
+ if (width <= 0 || height <= 0) continue;
2243
+ const areaShare = width * height / canvasArea;
2244
+ if (family === "shape" && (areaShare < .01 || areaShare > .85)) continue;
2245
+ const column = Math.max(0, Math.min(3, Math.floor((x + width / 2) / project.width * 4)));
2246
+ const row = Math.max(0, Math.min(3, Math.floor((y + height / 2) / project.height * 4)));
2247
+ const scale = areaShare >= .25 ? "large" : areaShare >= .08 ? "medium" : "small";
2248
+ landmarks.add(`${family}:${column}:${row}:${scale}`);
2249
+ }
2250
+ return [...landmarks].sort().join("|");
2251
+ }
2252
+ function layoutRepetitionIssues(project) {
2253
+ const issues = [];
2254
+ let runStart = 0;
2255
+ let runSignature;
2256
+ const finishRun = (end) => {
2257
+ if (runSignature === void 0 || end - runStart < 3) return;
2258
+ const first = project.pages[runStart];
2259
+ if (first === void 0) return;
2260
+ issues.push({
2261
+ code: "layout-repetition",
2262
+ severity: "warning",
2263
+ file: first.file,
2264
+ page: runStart + 1,
2265
+ message: `第 ${runStart + 1}–${end} 页连续使用相同构图轮廓。调整主视觉位置、尺度或内容分组,并重新预览这组页面;固定指标序列可以保留重复。`
2266
+ });
2267
+ };
2268
+ for (const [index, page] of project.pages.entries()) {
2269
+ const signature = isCompositionBookend(page) ? "" : layoutSignature(project, page);
2270
+ if (signature === "") {
2271
+ finishRun(index);
2272
+ runStart = index + 1;
2273
+ runSignature = void 0;
2274
+ continue;
2275
+ }
2276
+ if (signature === runSignature) continue;
2277
+ finishRun(index);
2278
+ runStart = index;
2279
+ runSignature = signature;
2280
+ }
2281
+ finishRun(project.pages.length);
2282
+ return issues;
2283
+ }
2284
+ function compositionIssues(project) {
2285
+ return [...coverFocusIssues(project), ...layoutRepetitionIssues(project)];
2286
+ }
2287
+ /** Check structure, renderability, and measurable composition signals without external effects. */
2288
+ function checkPptdProject(project) {
2289
+ const issues = [...project.parseIssues];
2290
+ issues.push(...colorThemeIssues(project, project.theme, project.source.entryName));
2291
+ for (const [key, value] of Object.entries(themeMap(project, "colors"))) {
2292
+ const referenceIssue = themeReferenceIssue(project, value, "colors", project.source.entryName);
2293
+ if (referenceIssue !== void 0) issues.push(referenceIssue);
2294
+ if (typeof value !== "string" || !value.startsWith("$") && !/^#[0-9a-f]{6}(?:[0-9a-f]{2})?$/iu.test(value)) issues.push({
2295
+ code: "invalid-theme",
2296
+ severity: "error",
2297
+ file: project.source.entryName,
2298
+ message: `theme.colors.${key} 必须是颜色或颜色主题引用。`
2299
+ });
2300
+ }
2301
+ issues.push(...themeColorChainIssues(project));
2302
+ for (const [index, page] of project.pages.entries()) {
2303
+ const ids = /* @__PURE__ */ new Set();
2304
+ issues.push(...colorThemeIssues(project, page.background, page.file, index + 1));
2305
+ for (const element of page.elements) issues.push(...checkElement(project, page, index + 1, element, ids));
2306
+ issues.push(...textLayerIssues(project, page, index + 1));
2307
+ }
2308
+ issues.push(...compositionIssues(project));
2309
+ const errorCount = issues.filter((item) => item.severity === "error").length;
2310
+ const warningCount = issues.filter((item) => item.severity === "warning").length;
2311
+ return {
2312
+ status: errorCount > 0 ? "fail" : warningCount > 0 ? "warning" : "pass",
2313
+ digest: projectDigest(project),
2314
+ pageCount: project.pages.length,
2315
+ nativeObjectCount: project.pages.reduce((sum, page) => sum + page.elements.length, 0),
2316
+ warningCount,
2317
+ errorCount,
2318
+ issues,
2319
+ compatibility: compatibilitySummary(project)
2320
+ };
2321
+ }
2322
+ function inches(value) {
2323
+ return value / POINTS_PER_INCH;
2324
+ }
2325
+ function frame(element) {
2326
+ const [x = 0, y = 0, width = 0, height = 0] = tuple(element.bounds, 4) ?? [
2327
+ 0,
2328
+ 0,
2329
+ 0,
2330
+ 0
2331
+ ];
2332
+ return {
2333
+ x: inches(x),
2334
+ y: inches(y),
2335
+ w: inches(width),
2336
+ h: inches(height)
2337
+ };
2338
+ }
2339
+ function fontFace(value, fallback = "Arial") {
2340
+ if (typeof value === "string") return value;
2341
+ const font = record$1(value);
2342
+ return string(font?.ea) ?? string(font?.latin) ?? fallback;
2343
+ }
2344
+ function inlineStyle(project, raw) {
2345
+ const options = {};
2346
+ for (const declaration of raw?.split(";") ?? []) {
2347
+ const [name, ...rest] = declaration.split(":");
2348
+ const value = rest.join(":").trim();
2349
+ if (name?.trim() === "color") options.color = colorOptions(project, value).color;
2350
+ if (name?.trim() === "font-size" && /^\d+(?:\.\d+)?px$/u.test(value)) options.fontSize = Number.parseFloat(value);
2351
+ if (name?.trim() === "font-family" && value !== "") {
2352
+ const face = value.replace(/^['"]|['"]$/gu, "").split(",")[0]?.trim();
2353
+ if (face !== void 0) options.fontFace = face;
2354
+ }
2355
+ if (name?.trim() === "background-color") options.highlight = colorOptions(project, value).color;
2356
+ if (name?.trim() === "font-weight" && (value === "bold" || Number(value) >= 600)) options.bold = true;
2357
+ if (name?.trim() === "font-style" && value === "italic") options.italic = true;
2358
+ }
2359
+ return options;
2360
+ }
2361
+ function richRuns(project, value) {
2362
+ const runs = [];
2363
+ const stack = [{
2364
+ tag: "root",
2365
+ options: {}
2366
+ }];
2367
+ const currentOptions = () => stack.at(-1)?.options ?? {};
2368
+ for (const token of value.split(/(<[^>]+>)/gu)) {
2369
+ if (token === "") continue;
2370
+ if (!token.startsWith("<")) {
2371
+ const decoded = plainText(token);
2372
+ if (decoded !== "") runs.push({
2373
+ text: decoded,
2374
+ options: { ...currentOptions() }
2375
+ });
2376
+ continue;
2377
+ }
2378
+ const closing = /^<\/([a-z0-9]+)/iu.exec(token);
2379
+ if (closing !== null) {
2380
+ const tag = closing[1]?.toLowerCase();
2381
+ if (tag === void 0) continue;
2382
+ if (tag === "p" || tag === "li") runs.push({
2383
+ text: "\n",
2384
+ options: { ...currentOptions() }
2385
+ });
2386
+ while (stack.length > 1) if (stack.pop()?.tag === tag) break;
2387
+ continue;
2388
+ }
2389
+ const opening = /^<([a-z0-9]+)/iu.exec(token);
2390
+ if (opening === null) continue;
2391
+ const tag = opening[1]?.toLowerCase();
2392
+ if (tag === void 0) continue;
2393
+ if (tag === "br") {
2394
+ runs.push({
2395
+ text: "\n",
2396
+ options: { ...currentOptions() }
2397
+ });
2398
+ continue;
2399
+ }
2400
+ if (tag === "li") runs.push({
2401
+ text: "• ",
2402
+ options: { ...currentOptions() }
2403
+ });
2404
+ const style = /\sstyle=(?:"([^"]*)"|'([^']*)')/iu.exec(token);
2405
+ const options = {
2406
+ ...currentOptions(),
2407
+ ...inlineStyle(project, style?.[1] ?? style?.[2])
2408
+ };
2409
+ if (tag === "strong") options.bold = true;
2410
+ if (tag === "em") options.italic = true;
2411
+ if (tag === "u") options.underline = { style: "sng" };
2412
+ if (tag === "s") options.strike = "sngStrike";
2413
+ if (tag === "sup") options.superscript = true;
2414
+ if (tag === "sub") options.subscript = true;
2415
+ if (tag === "a") {
2416
+ const href = /\shref=(?:"([^"]*)"|'([^']*)')/iu.exec(token)?.slice(1).find((item) => item !== void 0);
2417
+ if (href !== void 0 && /^(?:https?:|mailto:)/iu.test(href)) options.hyperlink = { url: href };
2418
+ }
2419
+ stack.push({
2420
+ tag,
2421
+ options
2422
+ });
2423
+ }
2424
+ while (runs.at(-1)?.text === "\n") runs.pop();
2425
+ return runs;
2426
+ }
2427
+ function flipOptions(element) {
2428
+ const flip = Array.isArray(element.flip) ? element.flip : [];
2429
+ return {
2430
+ ...typeof flip[0] === "boolean" ? { flipH: flip[0] } : {},
2431
+ ...typeof flip[1] === "boolean" ? { flipV: flip[1] } : {}
2432
+ };
2433
+ }
2434
+ function shadowOptions(project, value) {
2435
+ const shadow = record$1(value);
2436
+ if (shadow === void 0 || number(shadow.blur) === void 0 || typeof shadow.color !== "string") return void 0;
2437
+ const resolved = resolveColorValue(project, shadow.color);
2438
+ const alpha = resolved.length === 9 ? Number.parseInt(resolved.slice(7, 9), 16) / 255 : 1;
2439
+ const [offsetX = 0, offsetY = 0] = tuple(shadow.offset, 2) ?? [0, 0];
2440
+ const angle = (Math.atan2(-offsetY, offsetX) * 180 / Math.PI + 360) % 360;
2441
+ return {
2442
+ type: "outer",
2443
+ color: resolved.slice(1, 7).toUpperCase(),
2444
+ opacity: alpha,
2445
+ blur: number(shadow.blur) ?? 0,
2446
+ offset: Math.hypot(offsetX, offsetY),
2447
+ angle
2448
+ };
2449
+ }
2450
+ function dash(value) {
2451
+ return value === "dash" || value === "dot" ? value : "solid";
2452
+ }
2453
+ function border(project, value) {
2454
+ const config = record$1(value);
2455
+ if (config === void 0) return void 0;
2456
+ const style = dash(config.style);
2457
+ return {
2458
+ color: colorOptions(project, config.color).color,
2459
+ width: number(config.width) ?? 1,
2460
+ ...style === "solid" ? {} : { dash: style }
2461
+ };
2462
+ }
2463
+ function horizontalAlign(value, fallback) {
2464
+ return value === "center" || value === "right" || value === "justify" ? value : fallback;
2465
+ }
2466
+ function verticalAlign(value, fallback) {
2467
+ return value === "middle" || value === "bottom" ? value : fallback;
2468
+ }
2469
+ function renderText(project, slide, element) {
2470
+ const content = record$1(element.content) ?? {};
2471
+ const style = textStyle(project, content);
2472
+ const align = Array.isArray(style.align) ? style.align : [];
2473
+ const raw = string(content.text) ?? "";
2474
+ const runs = /<[^>]+>/u.test(raw) ? richRuns(project, raw) : raw;
2475
+ const textColor = colorOptions(project, style.color).color;
2476
+ const objectName = string(element.elementId);
2477
+ const charSpacing = number(style.letterSpacing);
2478
+ const horizontal = horizontalAlign(align[0], "left");
2479
+ const vertical = verticalAlign(align[1], "top");
2480
+ const textShadow = shadowOptions(project, style.shadow);
2481
+ slide.addText(runs, {
2482
+ ...frame(element),
2483
+ ...objectName === void 0 ? {} : { objectName },
2484
+ fontFace: fontFace(style.fontFamily, "MiSans"),
2485
+ fontSize: number(style.fontSize) ?? 18,
2486
+ color: textColor,
2487
+ bold: boolean(style.bold) ?? false,
2488
+ italic: boolean(style.italic) ?? false,
2489
+ align: horizontal,
2490
+ valign: vertical,
2491
+ margin: 0,
2492
+ breakLine: false,
2493
+ wrap: boolean(style.wrap) ?? true,
2494
+ textDirection: style.textDirection === "vertical" ? "vert" : "horz",
2495
+ rotate: number(element.rotation) ?? 0,
2496
+ ...flipOptions(element),
2497
+ transparency: Math.round((1 - (number(element.opacity) ?? 1)) * 100),
2498
+ ...textShadow === void 0 ? {} : { shadow: textShadow },
2499
+ ...charSpacing === void 0 ? {} : { charSpacing }
2500
+ });
2501
+ }
2502
+ function solidFill(project, value, opacity = 1) {
2503
+ const fill = record$1(value);
2504
+ if (fill === void 0) return void 0;
2505
+ if (fill.type === "solid") return colorOptions(project, fill.color, opacity);
2506
+ if (fill.type === "gradient" && Array.isArray(fill.stops)) {
2507
+ const first = record$1(fill.stops[0]);
2508
+ return first === void 0 ? void 0 : colorOptions(project, first.color, opacity);
2509
+ }
2510
+ }
2511
+ function shapeType(pptx, value) {
2512
+ const name = typeof value === "string" ? value : "rect";
2513
+ const shape = pptx.ShapeType[name];
2514
+ if (shape === void 0) throw new Error(`Unsupported PPTD preset shape: ${name}`);
2515
+ return shape;
2516
+ }
2517
+ function xmlEscape(value) {
2518
+ return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\"", "&quot;");
2519
+ }
2520
+ function svgPaint(project, fillValue, opacity) {
2521
+ const fill = record$1(fillValue);
2522
+ if (fill?.type === "gradient" && Array.isArray(fill.stops) && fill.stops.length >= 2) {
2523
+ const id = "pptd-gradient";
2524
+ const stops = fill.stops.map((rawStop) => {
2525
+ const stop = record$1(rawStop) ?? {};
2526
+ const color = colorOptions(project, stop.color, opacity);
2527
+ return `<stop offset="${Math.round(Math.max(0, Math.min(1, number(stop.position) ?? 0)) * 100)}%" stop-color="#${color.color}"${color.transparency === void 0 ? "" : ` stop-opacity="${1 - color.transparency / 100}"`}/>`;
2528
+ }).join("");
2529
+ if (fill.gradientType === "radial") return {
2530
+ paint: `url(#${id})`,
2531
+ definition: `<radialGradient id="${id}">${stops}</radialGradient>`
2532
+ };
2533
+ const angle = number(fill.angle) ?? 0;
2534
+ return {
2535
+ paint: `url(#${id})`,
2536
+ definition: `<linearGradient id="${id}" x1="0" y1="0.5" x2="1" y2="0.5" gradientTransform="rotate(${angle} 0.5 0.5)">${stops}</linearGradient>`
2537
+ };
2538
+ }
2539
+ return {
2540
+ paint: `#${colorOptions(project, fill?.type === "solid" ? fill.color : "#000000", opacity).color}`,
2541
+ definition: ""
2542
+ };
2543
+ }
2544
+ function svgData(svg) {
2545
+ return `data:image/svg+xml;base64,${Buffer.from(svg).toString("base64")}`;
2546
+ }
2547
+ function renderCustomShape(project, slide, element) {
2548
+ const viewBox = tuple(element.viewBox, 2) ?? [1, 1];
2549
+ const pathData = string(element.path) ?? "";
2550
+ const opacity = number(element.opacity) ?? 1;
2551
+ const fill = svgPaint(project, element.fill, opacity);
2552
+ const line = border(project, element.border);
2553
+ const shadow = shadowOptions(project, element.shadow);
2554
+ const shadowAngle = shadow?.angle ?? 0;
2555
+ const shadowOffset = shadow?.offset ?? 0;
2556
+ const shadowBlur = shadow?.blur ?? 0;
2557
+ const objectName = string(element.elementId);
2558
+ const [width = 1, height = 1] = viewBox;
2559
+ const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${width} ${height}"><defs>${[fill.definition, shadow === void 0 ? "" : [
2560
+ "<filter id=\"pptd-shadow\" x=\"-50%\" y=\"-50%\" width=\"200%\" height=\"200%\">",
2561
+ `<feDropShadow dx="${Math.cos(shadowAngle * Math.PI / 180) * shadowOffset}" dy="${-Math.sin(shadowAngle * Math.PI / 180) * shadowOffset}" stdDeviation="${shadowBlur / 2}" flood-color="#${shadow?.color ?? "000000"}" flood-opacity="${shadow?.opacity ?? 1}"/>`,
2562
+ "</filter>"
2563
+ ].join("")].join("")}</defs><path d="${xmlEscape(pathData)}" fill="${fill.paint}" fill-rule="evenodd"${line === void 0 ? " stroke=\"none\"" : ` stroke="#${line.color}" stroke-width="${line.width}"${line.dash === void 0 ? "" : ` stroke-dasharray="${line.dash === "dot" ? "1 2" : "4 3"}"`}`}${shadow === void 0 ? "" : " filter=\"url(#pptd-shadow)\""}/></svg>`;
2564
+ slide.addImage({
2565
+ ...frame(element),
2566
+ data: svgData(svg),
2567
+ ...objectName === void 0 ? {} : { objectName },
2568
+ rotate: number(element.rotation) ?? 0,
2569
+ ...flipOptions(element)
2570
+ });
2571
+ }
2572
+ function renderShape(project, pptx, slide, element) {
2573
+ if (element.shapeName === "custom") {
2574
+ renderCustomShape(project, slide, element);
2575
+ return;
2576
+ }
2577
+ const opacity = number(element.opacity) ?? 1;
2578
+ const fill = solidFill(project, element.fill, opacity);
2579
+ const line = border(project, element.border);
2580
+ const objectName = string(element.elementId);
2581
+ const shapeShadow = shadowOptions(project, element.shadow);
2582
+ slide.addShape(shapeType(pptx, element.shapeName), {
2583
+ ...frame(element),
2584
+ ...objectName === void 0 ? {} : { objectName },
2585
+ rotate: number(element.rotation) ?? 0,
2586
+ ...flipOptions(element),
2587
+ ...fill === void 0 ? { fill: {
2588
+ color: "FFFFFF",
2589
+ transparency: 100
2590
+ } } : { fill },
2591
+ line: line === void 0 ? {
2592
+ color: "FFFFFF",
2593
+ transparency: 100
2594
+ } : line,
2595
+ ...shapeShadow === void 0 ? {} : { shadow: shapeShadow }
2596
+ });
2597
+ }
2598
+ function renderCurvedLine(project, slide, element, points) {
2599
+ const [width = 1, height = 1] = tuple(element.viewBox, 2) ?? [1, 1];
2600
+ const [first = [0, 0], ...rest] = points;
2601
+ const [startX = 0, startY = 0] = first;
2602
+ const pathData = rest.length === 3 ? `M ${startX} ${startY} C ${rest.map((point) => point.join(" ")).join(" ")}` : `M ${startX} ${startY} ${rest.map((point) => `L ${point[0] ?? 0} ${point[1] ?? 0}`).join(" ")}`;
2603
+ const line = border(project, element.border) ?? {
2604
+ color: "000000",
2605
+ width: 1
2606
+ };
2607
+ const arrow = Array.isArray(element.arrow) ? element.arrow : [];
2608
+ const marker = (id, kind) => kind === null || kind === void 0 ? "" : [
2609
+ `<marker id="${id}" markerWidth="8" markerHeight="8" refX="7" refY="4" orient="auto" markerUnits="strokeWidth">`,
2610
+ kind === "oval" ? "<circle cx=\"4\" cy=\"4\" r=\"3\" fill=\"context-stroke\"/>" : kind === "diamond" ? "<path d=\"M0,4 L4,0 L8,4 L4,8 Z\" fill=\"context-stroke\"/>" : "<path d=\"M0,0 L8,4 L0,8 Z\" fill=\"context-stroke\"/>",
2611
+ "</marker>"
2612
+ ].join("");
2613
+ const dash = line.dash === void 0 ? "" : ` stroke-dasharray="${line.dash === "dot" ? "1 2" : "4 3"}"`;
2614
+ const markerStart = arrow[0] === void 0 || arrow[0] === null ? "" : " marker-start=\"url(#start)\"";
2615
+ const markerEnd = arrow[1] === void 0 || arrow[1] === null ? "" : " marker-end=\"url(#end)\"";
2616
+ const svg = [
2617
+ `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${width} ${height}">`,
2618
+ `<defs>${marker("start", arrow[0])}${marker("end", arrow[1])}</defs>`,
2619
+ `<path d="${pathData}" fill="none" stroke="#${line.color}" stroke-width="${line.width}"`,
2620
+ `${dash}${markerStart}${markerEnd}/></svg>`
2621
+ ].join("");
2622
+ const objectName = string(element.elementId);
2623
+ slide.addImage({
2624
+ ...frame(element),
2625
+ data: svgData(svg),
2626
+ ...objectName === void 0 ? {} : { objectName },
2627
+ rotate: number(element.rotation) ?? 0,
2628
+ ...flipOptions(element)
2629
+ });
2630
+ }
2631
+ function renderLine(project, pptx, slide, element) {
2632
+ const points = (string(element.points) ?? "").trim().split(/\s+/u).map((value) => value.split(",").map(Number));
2633
+ if (points.length > 2 || element.curve === "smooth") {
2634
+ renderCurvedLine(project, slide, element, points);
2635
+ return;
2636
+ }
2637
+ const viewBox = tuple(element.viewBox, 2) ?? [1, 1];
2638
+ const bounds = frame(element);
2639
+ const first = points[0] ?? [0, 0];
2640
+ const last = points.at(-1) ?? [viewBox[0] ?? 1, viewBox[1] ?? 1];
2641
+ const x1 = bounds.x + (first[0] ?? 0) / (viewBox[0] ?? 1) * bounds.w;
2642
+ const y1 = bounds.y + (first[1] ?? 0) / (viewBox[1] ?? 1) * bounds.h;
2643
+ const x2 = bounds.x + (last[0] ?? 0) / (viewBox[0] ?? 1) * bounds.w;
2644
+ const y2 = bounds.y + (last[1] ?? 0) / (viewBox[1] ?? 1) * bounds.h;
2645
+ const line = border(project, element.border) ?? {
2646
+ color: "000000",
2647
+ width: 1
2648
+ };
2649
+ const arrow = Array.isArray(element.arrow) ? element.arrow : [];
2650
+ const objectName = string(element.elementId);
2651
+ const lineShadow = shadowOptions(project, element.shadow);
2652
+ slide.addShape(pptx.ShapeType.line, {
2653
+ x: Math.min(x1, x2),
2654
+ y: Math.min(y1, y2),
2655
+ w: Math.abs(x2 - x1),
2656
+ h: Math.abs(y2 - y1),
2657
+ ...objectName === void 0 ? {} : { objectName },
2658
+ flipH: x2 < x1,
2659
+ flipV: y2 < y1,
2660
+ rotate: number(element.rotation) ?? 0,
2661
+ line: {
2662
+ ...line,
2663
+ ...arrow[0] === void 0 || arrow[0] === null ? {} : { beginArrowType: arrow[0] },
2664
+ ...arrow[1] === void 0 || arrow[1] === null ? {} : { endArrowType: arrow[1] }
2665
+ },
2666
+ ...lineShadow === void 0 ? {} : { shadow: lineShadow }
2667
+ });
2668
+ }
2669
+ function renderImage(project, slide, element) {
2670
+ const assetPath = localAssetPath(element.src);
2671
+ const asset = assetPath === void 0 ? void 0 : project.source.assets.get(assetPath);
2672
+ if (asset === void 0) throw new Error(`PPTD image ${String(element.src)} is unavailable`);
2673
+ const objectName = string(element.elementId);
2674
+ const mode = string(record$1(element.fit)?.mode) ?? "cover";
2675
+ const bounds = frame(element);
2676
+ const cropShape = record$1(element.cropShape);
2677
+ const imageShadow = shadowOptions(project, element.shadow);
2678
+ slide.addImage({
2679
+ ...bounds,
2680
+ ...objectName === void 0 ? {} : { objectName },
2681
+ data: `data:${asset.mediaType};base64,${Buffer.from(asset.bytes).toString("base64")}`,
2682
+ rotate: number(element.rotation) ?? 0,
2683
+ ...flipOptions(element),
2684
+ transparency: Math.round((1 - (number(element.opacity) ?? 1)) * 100),
2685
+ ...mode === "fill" ? {} : { sizing: {
2686
+ type: mode,
2687
+ w: bounds.w,
2688
+ h: bounds.h
2689
+ } },
2690
+ ...cropShape?.shapeName === "ellipse" ? { rounding: true } : {},
2691
+ ...imageShadow === void 0 ? {} : { shadow: imageShadow }
2692
+ });
2693
+ const imageBorder = border(project, element.border);
2694
+ if (imageBorder !== void 0) slide.addShape(cropShape?.shapeName === "ellipse" ? "ellipse" : "rect", {
2695
+ ...bounds,
2696
+ objectName: `${objectName ?? "image"}-border`,
2697
+ fill: {
2698
+ color: "FFFFFF",
2699
+ transparency: 100
2700
+ },
2701
+ line: imageBorder,
2702
+ rotate: number(element.rotation) ?? 0,
2703
+ ...flipOptions(element)
2704
+ });
2705
+ }
2706
+ function mergeCellStyle(project, table, row, column, rowCount, columnCount, cell) {
2707
+ const tableTheme = record$1(resolveThemeReference(table.style, themeMap(project, "tableStyles"))) ?? {};
2708
+ const baseline = record$1(tableTheme.cellStyle) ?? {};
2709
+ const bodyStyles = Array.isArray(tableTheme.bodyStyles) ? tableTheme.bodyStyles.map(record$1).filter((item) => item !== void 0) : [];
2710
+ const body = row > 0 && row < rowCount - 1 && bodyStyles.length > 0 ? bodyStyles[(row - 1) % bodyStyles.length] ?? {} : {};
2711
+ const rowStyle = row === 0 ? record$1(tableTheme.firstRowStyle) ?? {} : row === rowCount - 1 ? record$1(tableTheme.lastRowStyle) ?? {} : body;
2712
+ const columnStyle = column === 0 ? record$1(tableTheme.firstColumnStyle) ?? {} : column === columnCount - 1 ? record$1(tableTheme.lastColumnStyle) ?? {} : {};
2713
+ return boolean(tableTheme.rowOverColumn) === false ? {
2714
+ ...baseline,
2715
+ ...rowStyle,
2716
+ ...columnStyle,
2717
+ ...cell
2718
+ } : {
2719
+ ...baseline,
2720
+ ...columnStyle,
2721
+ ...rowStyle,
2722
+ ...cell
2723
+ };
2724
+ }
2725
+ function tableBorder(project, value) {
2726
+ const none = {
2727
+ color: "FFFFFF",
2728
+ pt: 0
2729
+ };
2730
+ const one = (item) => {
2731
+ const parsed = border(project, item);
2732
+ return parsed === void 0 ? none : {
2733
+ color: parsed.color,
2734
+ pt: parsed.width,
2735
+ ...parsed.dash === void 0 ? {} : { dash: parsed.dash }
2736
+ };
2737
+ };
2738
+ if (value === null) return [
2739
+ none,
2740
+ none,
2741
+ none,
2742
+ none
2743
+ ];
2744
+ if (Array.isArray(value)) {
2745
+ if (value.length === 2) return [
2746
+ one(value[0]),
2747
+ one(value[1]),
2748
+ one(value[0]),
2749
+ one(value[1])
2750
+ ];
2751
+ if (value.length === 4) return [
2752
+ one(value[0]),
2753
+ one(value[1]),
2754
+ one(value[2]),
2755
+ one(value[3])
2756
+ ];
2757
+ }
2758
+ return record$1(value) === void 0 ? void 0 : one(value);
2759
+ }
2760
+ function renderTable(project, slide, element) {
2761
+ const rows = element.rows;
2762
+ const rowCount = rows.length;
2763
+ const columnCount = Array.isArray(element.columnWidths) ? element.columnWidths.length : rows[0]?.length ?? 0;
2764
+ const tableRows = rows.map((row, rowIndex) => row.map((rawCell, columnIndex) => {
2765
+ const cell = record$1(rawCell) ?? { text: typeof rawCell === "string" || typeof rawCell === "number" ? String(rawCell) : "" };
2766
+ const style = {
2767
+ ...record$1(resolveThemeReference(cell.textStyle, themeMap(project, "textStyles"))) ?? {},
2768
+ ...mergeCellStyle(project, element, rowIndex, columnIndex, rowCount, columnCount, cell)
2769
+ };
2770
+ const align = Array.isArray(style.align) ? style.align : [];
2771
+ const horizontal = horizontalAlign(align[0], "center");
2772
+ const vertical = verticalAlign(align[1], "middle");
2773
+ const fill = solidFill(project, style.fill);
2774
+ const cellBorder = tableBorder(project, style.border);
2775
+ const rowSpan = number(cell.rowSpan);
2776
+ const colSpan = number(cell.colSpan);
2777
+ const options = {
2778
+ fontFace: fontFace(style.fontFamily, "MiSans"),
2779
+ fontSize: number(style.fontSize) ?? 10,
2780
+ color: colorOptions(project, style.color).color,
2781
+ bold: boolean(style.bold) ?? false,
2782
+ italic: boolean(style.italic) ?? false,
2783
+ align: horizontal,
2784
+ valign: vertical,
2785
+ margin: .03,
2786
+ ...rowSpan === void 0 ? {} : { rowspan: rowSpan },
2787
+ ...colSpan === void 0 ? {} : { colspan: colSpan },
2788
+ ...fill === void 0 ? {} : { fill },
2789
+ ...cellBorder === void 0 ? {} : { border: cellBorder }
2790
+ };
2791
+ return {
2792
+ text: plainText(string(cell.text) ?? ""),
2793
+ options
2794
+ };
2795
+ }));
2796
+ const bounds = frame(element);
2797
+ const colRatios = Array.isArray(element.columnWidths) ? element.columnWidths.map(number).filter((item) => item !== void 0) : [];
2798
+ const rowRatios = Array.isArray(element.rowHeights) ? element.rowHeights.map(number).filter((item) => item !== void 0) : [];
2799
+ const colW = colRatios.length === columnCount ? colRatios.map((value) => value * bounds.w) : void 0;
2800
+ const rowH = rowRatios.length === rowCount ? rowRatios.map((value) => value * bounds.h) : void 0;
2801
+ const objectName = string(element.elementId);
2802
+ slide.addTable(tableRows, {
2803
+ ...bounds,
2804
+ ...objectName === void 0 ? {} : { objectName },
2805
+ autoPage: false,
2806
+ ...colW === void 0 ? {} : { colW },
2807
+ ...rowH === void 0 ? {} : { rowH },
2808
+ border: {
2809
+ color: "FFFFFF",
2810
+ pt: 0
2811
+ },
2812
+ margin: 0
2813
+ });
2814
+ }
2815
+ function legendPosition(value) {
2816
+ return {
2817
+ bottom: "b",
2818
+ left: "l",
2819
+ right: "r",
2820
+ top: "t",
2821
+ topRight: "tr"
2822
+ }[string(value) ?? ""] ?? "r";
2823
+ }
2824
+ function valueAxisOptions(project, axis) {
2825
+ const label = record$1(axis.label) ?? {};
2826
+ const grid = record$1(axis.gridLine);
2827
+ const minimum = number(axis.min);
2828
+ const maximum = number(axis.max);
2829
+ const fontSize = number(label.fontSize);
2830
+ const title = string(axis.title);
2831
+ return {
2832
+ ...minimum === void 0 ? {} : { valAxisMinVal: minimum },
2833
+ ...maximum === void 0 ? {} : { valAxisMaxVal: maximum },
2834
+ ...fontSize === void 0 ? {} : { valAxisLabelFontSize: fontSize },
2835
+ ...title === void 0 ? {} : {
2836
+ showValAxisTitle: true,
2837
+ valAxisTitle: title
2838
+ },
2839
+ ...axis.gridLine === false ? { valGridLine: { style: "none" } } : grid === void 0 ? {} : { valGridLine: {
2840
+ color: colorOptions(project, grid.color, 1).color,
2841
+ style: dash(grid.style)
2842
+ } }
2843
+ };
2844
+ }
2845
+ function chartAxisOptions(project, element, horizontal = false) {
2846
+ const xAxis = Array.isArray(element.xAxis) ? record$1(element.xAxis[0]) ?? {} : record$1(element.xAxis) ?? {};
2847
+ const yAxis = (Array.isArray(element.yAxis) ? element.yAxis.map(record$1).filter((item) => item !== void 0) : [record$1(element.yAxis) ?? {}])[0] ?? {};
2848
+ const valueAxis = horizontal ? xAxis : yAxis;
2849
+ const categoryAxis = horizontal ? yAxis : xAxis;
2850
+ const categoryLabel = record$1(categoryAxis.label) ?? {};
2851
+ return {
2852
+ ...valueAxisOptions(project, valueAxis),
2853
+ ...number(categoryLabel.fontSize) === void 0 ? {} : { catAxisLabelFontSize: number(categoryLabel.fontSize) },
2854
+ ...number(categoryLabel.rotate) === void 0 ? {} : { catAxisLabelRotate: number(categoryLabel.rotate) },
2855
+ ...categoryAxis.gridLine === false ? { catGridLine: { style: "none" } } : {}
2856
+ };
2857
+ }
2858
+ function renderChart(project, pptx, slide, element, foregroundColor) {
2859
+ const data = record$1(element.data) ?? {};
2860
+ const columns = (Array.isArray(data.cols) ? data.cols : []).map((value) => String(value));
2861
+ const rows = Array.isArray(data.rows) ? data.rows : [];
2862
+ const columnIsNumeric = (column) => {
2863
+ if (column === void 0) return false;
2864
+ const columnIndex = columns.indexOf(column);
2865
+ if (columnIndex < 0) return false;
2866
+ const values = rows.map((row) => row[columnIndex]).filter((value) => value !== void 0 && value !== null && value !== "");
2867
+ return values.length > 0 && values.every((value) => {
2868
+ if (typeof value === "number") return Number.isFinite(value);
2869
+ return typeof value === "string" && value.trim() !== "" && Number.isFinite(Number(value));
2870
+ });
2871
+ };
2872
+ const seriesDefaults = record$1(element.seriesDefaults) ?? {};
2873
+ const xAxis = Array.isArray(element.xAxis) ? record$1(element.xAxis[0]) ?? {} : record$1(element.xAxis) ?? {};
2874
+ const yAxes = Array.isArray(element.yAxis) ? element.yAxis.map(record$1).filter((item) => item !== void 0) : [record$1(element.yAxis) ?? {}];
2875
+ const mergeSeries = (raw) => {
2876
+ const defaults = record$1(seriesDefaults[string(raw.type) ?? ""]) ?? {};
2877
+ const merged = {
2878
+ ...defaults,
2879
+ ...raw
2880
+ };
2881
+ for (const key of [
2882
+ "marker",
2883
+ "dataLabels",
2884
+ "border",
2885
+ "upBars",
2886
+ "downBars",
2887
+ "totalBars",
2888
+ "increaseBars",
2889
+ "decreaseBars"
2890
+ ]) {
2891
+ const base = record$1(defaults[key]);
2892
+ const specific = record$1(raw[key]);
2893
+ if (base !== void 0 || specific !== void 0) merged[key] = {
2894
+ ...base ?? {},
2895
+ ...specific ?? {}
2896
+ };
2897
+ }
2898
+ return merged;
2899
+ };
2900
+ const series = (Array.isArray(element.series) ? element.series : []).map(record$1).filter((item) => item !== void 0).map(mergeSeries);
2901
+ const types = [];
2902
+ const mergeableGroups = /* @__PURE__ */ new Map();
2903
+ for (const [index, item] of series.entries()) {
2904
+ const encode = record$1(item.encode) ?? {};
2905
+ const chartTypeName = string(item.type) ?? "bar";
2906
+ const xColumn = string(encode.x);
2907
+ const yColumn = string(encode.y);
2908
+ const horizontal = chartTypeName === "bar" && columnIsNumeric(xColumn) && !columnIsNumeric(yColumn);
2909
+ const categoryColumn = string(chartTypeName === "pie" || chartTypeName === "radar" ? encode.category : horizontal ? encode.y : encode.x) ?? columns[0] ?? "category";
2910
+ const valueColumn = string(chartTypeName === "pie" ? encode.value : horizontal ? encode.x : encode.y) ?? columns[1] ?? "value";
2911
+ const categoryIndex = columns.indexOf(categoryColumn);
2912
+ const valueIndex = columns.indexOf(valueColumn);
2913
+ const selectedRows = (() => {
2914
+ const filter = record$1(item.dataFilter);
2915
+ const filterColumn = string(filter?.col);
2916
+ if (filterColumn === void 0) return rows;
2917
+ const filterIndex = columns.indexOf(filterColumn);
2918
+ return rows.filter((row) => row[filterIndex] === filter?.value);
2919
+ })();
2920
+ const filteredRows = horizontal ? [...selectedRows].reverse() : selectedRows;
2921
+ const filteredLabels = filteredRows.map((row) => {
2922
+ const value = row[categoryIndex];
2923
+ return typeof value === "string" || typeof value === "number" || typeof value === "boolean" ? String(value) : "";
2924
+ });
2925
+ const values = filteredRows.map((row) => Number(row[valueIndex] ?? 0));
2926
+ const type = chartTypeName === "line" ? pptx.ChartType.line : chartTypeName === "area" ? pptx.ChartType.area : chartTypeName === "scatter" ? pptx.ChartType.scatter : chartTypeName === "bubble" ? pptx.ChartType.bubble : chartTypeName === "radar" ? pptx.ChartType.radar : chartTypeName === "pie" && (number(item.innerRadius) ?? 0) > 0 ? pptx.ChartType.doughnut : chartTypeName === "pie" ? pptx.ChartType.pie : pptx.ChartType.bar;
2927
+ const chartColors = (resolvePptdChartSeriesColors(project, chartTypeName === "line" || chartTypeName === "area" || chartTypeName === "radar" ? item.lineColor ?? item.areaColor : item.fill) ?? [PPTD_CHART_SERIES_PALETTE[index % PPTD_CHART_SERIES_PALETTE.length] ?? "#2563EB"]).map((value) => colorOptions(project, value, 1).color);
2928
+ const labelsConfig = record$1(item.dataLabels);
2929
+ const showLabels = boolean(labelsConfig?.show) === true;
2930
+ const showPercent = labelsConfig?.content === "percentage";
2931
+ const dataLabelFontSize = number(labelsConfig?.fontSize);
2932
+ const dataLabelColor = labelsConfig?.color === void 0 ? foregroundColor : colorOptions(project, labelsConfig.color).color;
2933
+ const axisIndex = Math.max(0, Math.trunc(number(item.yAxisIndex) ?? 0));
2934
+ const valueAxis = horizontal ? xAxis : yAxes[axisIndex] ?? yAxes[0] ?? {};
2935
+ const valueAxisLabel = record$1(valueAxis.label) ?? {};
2936
+ const valueAxisGrid = record$1(valueAxis.gridLine);
2937
+ const valueAxisMin = number(valueAxis.min);
2938
+ const valueAxisMax = number(valueAxis.max);
2939
+ const valueAxisLabelFontSize = number(valueAxisLabel.fontSize);
2940
+ const valueAxisTitle = string(valueAxis.title);
2941
+ const groupOptions = {
2942
+ ...horizontal ? { barDir: "bar" } : chartTypeName === "bar" ? { barDir: "col" } : {},
2943
+ ...axisIndex === 1 ? { secondaryValAxis: true } : {},
2944
+ ...valueAxisMin === void 0 ? {} : { valAxisMinVal: valueAxisMin },
2945
+ ...valueAxisMax === void 0 ? {} : { valAxisMaxVal: valueAxisMax },
2946
+ ...valueAxisLabelFontSize === void 0 ? {} : { valAxisLabelFontSize: valueAxisLabelFontSize },
2947
+ ...valueAxisTitle === void 0 ? {} : {
2948
+ showValAxisTitle: true,
2949
+ valAxisTitle: valueAxisTitle
2950
+ },
2951
+ ...valueAxis.gridLine === false ? { valGridLine: { style: "none" } } : valueAxisGrid === void 0 ? {} : { valGridLine: {
2952
+ color: colorOptions(project, valueAxisGrid.color, 1).color,
2953
+ style: dash(valueAxisGrid.style)
2954
+ } },
2955
+ ...showLabels && !showPercent ? { showValue: true } : {},
2956
+ ...showLabels && showPercent ? { showPercent: true } : {},
2957
+ dataLabelColor,
2958
+ ...dataLabelFontSize === void 0 ? {} : {
2959
+ dataLabelFontSize,
2960
+ dataLabelPosition: "outEnd"
2961
+ },
2962
+ ...chartTypeName === "line" ? {
2963
+ lineSize: number(item.width) ?? 2,
2964
+ lineDataSymbol: "circle"
2965
+ } : {},
2966
+ ...chartTypeName === "area" ? { lineSize: number(item.width) ?? 2 } : {},
2967
+ ...chartTypeName === "radar" ? { radarStyle: item.areaColor === void 0 ? "marker" : "filled" } : {},
2968
+ ...(chartTypeName === "line" || chartTypeName === "area") && item.marker === false ? { lineDataSymbol: "none" } : {},
2969
+ ...(chartTypeName === "line" || chartTypeName === "area") && record$1(item.marker) !== void 0 ? {
2970
+ lineDataSymbol: record$1(item.marker)?.shape === "rect" ? "square" : string(record$1(item.marker)?.shape) ?? "circle",
2971
+ lineDataSymbolSize: number(record$1(item.marker)?.size) ?? 6
2972
+ } : {},
2973
+ ...item.stack === "percent" ? { barGrouping: "percentStacked" } : item.stack === "value" || item.stack === "stream" ? { barGrouping: "stacked" } : chartTypeName === "bar" ? { barGrouping: "clustered" } : {},
2974
+ ...item.nullHandling === "gap" ? { displayBlanksAs: "gap" } : { displayBlanksAs: "span" },
2975
+ ...type === pptx.ChartType.doughnut ? { holeSize: Math.round((number(item.innerRadius) ?? .5) * 100) } : {}
2976
+ };
2977
+ const dataSeries = {
2978
+ name: string(item.name) ?? valueColumn ?? `Series ${index + 1}`,
2979
+ labels: filteredLabels,
2980
+ values,
2981
+ ...chartTypeName === "bubble" ? { sizes: filteredRows.map((row) => Number(row[columns.indexOf(string(encode.size) ?? "")] ?? 0)) } : {}
2982
+ };
2983
+ const mergeable = type !== pptx.ChartType.pie && type !== pptx.ChartType.doughnut;
2984
+ const groupKey = chartTypeName === "bar" ? `${type}:${horizontal ? "horizontal" : "vertical"}:${axisIndex}:${String(groupOptions.barGrouping)}` : `${type}:${JSON.stringify(groupOptions)}`;
2985
+ const existing = mergeable ? mergeableGroups.get(groupKey) : void 0;
2986
+ if (existing === void 0) {
2987
+ const chartGroup = {
2988
+ type,
2989
+ data: [dataSeries],
2990
+ options: {
2991
+ ...groupOptions,
2992
+ chartColors
2993
+ }
2994
+ };
2995
+ types.push(chartGroup);
2996
+ if (mergeable) mergeableGroups.set(groupKey, chartGroup);
2997
+ continue;
2998
+ }
2999
+ existing.data.push(dataSeries);
3000
+ existing.options.chartColors = [...existing.options.chartColors ?? [], ...chartColors];
3001
+ if (groupOptions.showValue === true) existing.options.showValue = true;
3002
+ if (groupOptions.showPercent === true) existing.options.showPercent = true;
3003
+ if (existing.options.dataLabelFontSize === void 0 && groupOptions.dataLabelFontSize !== void 0) existing.options.dataLabelFontSize = groupOptions.dataLabelFontSize;
3004
+ }
3005
+ const legend = typeof element.legend === "boolean" ? { show: element.legend } : record$1(element.legend) ?? {};
3006
+ const font = fontFace(element.fontFamily, "MiSans");
3007
+ const objectName = string(element.elementId);
3008
+ const title = typeof element.title === "string" ? { text: element.title } : record$1(element.title) ?? {};
3009
+ const chartFill = solidFill(project, element.fill);
3010
+ const chartBorder = border(project, element.border);
3011
+ const legendFontSize = number(legend.fontSize);
3012
+ const titleFontSize = number(title.fontSize);
3013
+ const titleText = string(title.text);
3014
+ const barGap = number(element.barGap);
3015
+ const valAxes = series.some((item) => Math.trunc(number(item.yAxisIndex) ?? 0) === 1) ? [valueAxisOptions(project, yAxes[0] ?? {}), valueAxisOptions(project, yAxes[1] ?? {})] : void 0;
3016
+ const common = {
3017
+ ...frame(element),
3018
+ ...objectName === void 0 ? {} : { objectName },
3019
+ showLegend: boolean(legend.show) ?? series.some((item) => ![
3020
+ "waterfall",
3021
+ "heatmap",
3022
+ "treemap",
3023
+ "sunburst",
3024
+ "sankey"
3025
+ ].includes(string(item.type) ?? "")),
3026
+ legendPos: legendPosition(legend.position),
3027
+ legendFontFace: fontFace(legend.fontFamily, font),
3028
+ legendColor: colorOptions(project, legend.color ?? `#${foregroundColor}`).color,
3029
+ ...legendFontSize === void 0 ? {} : { legendFontSize },
3030
+ catAxisLabelFontFace: font,
3031
+ catAxisLabelColor: foregroundColor,
3032
+ catAxisLineColor: foregroundColor,
3033
+ valAxisLabelFontFace: font,
3034
+ valAxisLabelColor: foregroundColor,
3035
+ valAxisLineColor: foregroundColor,
3036
+ showTitle: titleText !== void 0,
3037
+ ...titleText === void 0 ? {} : { title: titleText },
3038
+ titleFontFace: fontFace(title.fontFamily, font),
3039
+ titleColor: colorOptions(project, title.color ?? `#${foregroundColor}`).color,
3040
+ ...titleFontSize === void 0 ? {} : { titleFontSize },
3041
+ showValue: false,
3042
+ chartArea: {
3043
+ border: chartBorder === void 0 ? {
3044
+ color: "FFFFFF",
3045
+ pt: 0
3046
+ } : {
3047
+ color: chartBorder.color,
3048
+ pt: chartBorder.width
3049
+ },
3050
+ fill: chartFill ?? {
3051
+ color: "FFFFFF",
3052
+ transparency: 100
3053
+ }
3054
+ },
3055
+ plotArea: {
3056
+ border: {
3057
+ color: "FFFFFF",
3058
+ pt: 0
3059
+ },
3060
+ fill: {
3061
+ color: "FFFFFF",
3062
+ transparency: 100
3063
+ }
3064
+ },
3065
+ ...barGap === void 0 ? {} : { barGapWidthPct: Math.round(barGap * 100) },
3066
+ ...valAxes === void 0 ? {} : { valAxes },
3067
+ ...chartAxisOptions(project, element, series.some((item) => {
3068
+ const encode = record$1(item.encode) ?? {};
3069
+ return string(item.type) === "bar" && columnIsNumeric(string(encode.x)) && !columnIsNumeric(string(encode.y));
3070
+ }))
3071
+ };
3072
+ slide.addChart(types, common);
3073
+ }
3074
+ function renderIcon(project, slide, element) {
3075
+ const color = colorOptions(project, element.color).color;
3076
+ const objectName = string(element.elementId);
3077
+ slide.addText(string(element.iconName) ?? "●", {
3078
+ ...frame(element),
3079
+ ...objectName === void 0 ? {} : { objectName },
3080
+ fontFace: "Arial",
3081
+ fontSize: 18,
3082
+ color,
3083
+ margin: 0,
3084
+ align: "center",
3085
+ valign: "middle",
3086
+ fit: "shrink"
3087
+ });
3088
+ }
3089
+ function renderElement(project, pptx, slide, element, foregroundColor) {
3090
+ if (element.elementType === "text") {
3091
+ renderText(project, slide, element);
3092
+ return;
3093
+ }
3094
+ if (element.elementType === "shape") {
3095
+ renderShape(project, pptx, slide, element);
3096
+ return;
3097
+ }
3098
+ if (element.elementType === "line") {
3099
+ renderLine(project, pptx, slide, element);
3100
+ return;
3101
+ }
3102
+ if (element.elementType === "image") {
3103
+ renderImage(project, slide, element);
3104
+ return;
3105
+ }
3106
+ if (element.elementType === "table") {
3107
+ renderTable(project, slide, element);
3108
+ return;
3109
+ }
3110
+ if (element.elementType === "chart") {
3111
+ renderChart(project, pptx, slide, element, foregroundColor);
3112
+ return;
3113
+ }
3114
+ if (element.elementType === "icon") {
3115
+ renderIcon(project, slide, element);
3116
+ return;
3117
+ }
3118
+ }
3119
+ /** Render one checked PPTD AST to editable native PowerPoint objects. */
3120
+ async function renderPptdProject(project) {
3121
+ const check = checkPptdProject(project);
3122
+ if (check.status === "fail") {
3123
+ const details = check.issues.filter((issue) => issue.severity === "error").slice(0, 3).map((issue) => `${issue.code}${issue.elementId === void 0 ? "" : `(${issue.elementId})`}: ${issue.message}`).join("; ");
3124
+ throw new Error(`PPTD rendering requires a passing check; received ${check.errorCount} errors${details === "" ? "" : `: ${details}`}`);
3125
+ }
3126
+ const pptx = new PptxGenJS();
3127
+ const layoutName = `DSH_PPTD_${project.width}x${project.height}`;
3128
+ pptx.defineLayout({
3129
+ name: layoutName,
3130
+ width: inches(project.width),
3131
+ height: inches(project.height)
3132
+ });
3133
+ pptx.layout = layoutName;
3134
+ pptx.author = "DSH PPTD";
3135
+ pptx.company = "DeepSeek Harness";
3136
+ pptx.subject = "Local PPTD v2 editable rendering";
3137
+ pptx.title = project.title;
3138
+ const textStyles = themeMap(project, "textStyles");
3139
+ const titleStyle = record$1(textStyles.title) ?? {};
3140
+ const bodyStyle = record$1(textStyles.body) ?? {};
3141
+ pptx.theme = {
3142
+ headFontFace: fontFace(titleStyle.fontFamily, "MiSans"),
3143
+ bodyFontFace: fontFace(bodyStyle.fontFamily, "MiSans")
3144
+ };
3145
+ for (const page of project.pages) {
3146
+ const slide = pptx.addSlide();
3147
+ const background = solidFill(project, page.background);
3148
+ slide.background = background ?? { color: "FFFFFF" };
3149
+ const foregroundColor = readableForeground(background?.color ?? "FFFFFF");
3150
+ for (const element of page.elements) renderElement(project, pptx, slide, element, foregroundColor);
3151
+ if (page.notes.trim() !== "") slide.addNotes(page.notes);
3152
+ }
3153
+ const output = await pptx.write({
3154
+ outputType: "nodebuffer",
3155
+ compression: true
3156
+ });
3157
+ return {
3158
+ bytes: new Uint8Array(output),
3159
+ nativeObjectCount: check.nativeObjectCount,
3160
+ check
3161
+ };
3162
+ }
3163
+ function mediaType(file, bytes) {
3164
+ const extension = path.extname(file).toLowerCase();
3165
+ if (extension === ".png" && bytes[0] === 137 && bytes[1] === 80) return "image/png";
3166
+ if ((extension === ".jpg" || extension === ".jpeg") && bytes[0] === 255 && bytes[1] === 216) return "image/jpeg";
3167
+ if (extension === ".gif" && Buffer.from(bytes.subarray(0, 3)).toString("ascii") === "GIF") return "image/gif";
3168
+ if (extension === ".webp" && Buffer.from(bytes.subarray(8, 12)).toString("ascii") === "WEBP") return "image/webp";
3169
+ if (extension === ".svg" && Buffer.from(bytes.subarray(0, 512)).toString("utf8").includes("<svg")) return "image/svg+xml";
3170
+ }
3171
+ async function confinedFile(root, relative, maximumBytes) {
3172
+ const safe = safeProjectPath(relative);
3173
+ if (safe === void 0) throw new Error(`PPTD path is not project-relative: ${relative}`);
3174
+ const target = await realpath(path.join(root, ...safe.split("/")));
3175
+ if (target !== root && !target.startsWith(`${root}${path.sep}`)) throw new Error(`PPTD path escapes the project root: ${relative}`);
3176
+ const metadata = await lstat(target);
3177
+ if (!metadata.isFile() || metadata.size > maximumBytes) throw new Error(`PPTD file is invalid or too large: ${relative}`);
3178
+ return {
3179
+ real: target,
3180
+ bytes: await readFile(target)
3181
+ };
3182
+ }
3183
+ /** Resolve a PPTD entry file from either the entry itself or its project directory. */
3184
+ async function resolvePptdEntry(inputPath) {
3185
+ const input = await realpath(path.resolve(inputPath));
3186
+ const metadata = await lstat(input);
3187
+ if (metadata.isFile()) {
3188
+ if (!input.endsWith(".pptd")) throw new Error("PPTD entry must use the .pptd extension");
3189
+ return input;
3190
+ }
3191
+ if (!metadata.isDirectory()) throw new Error("PPTD input must be an entry file or project directory");
3192
+ const entries = (await readdir(input, { withFileTypes: true })).filter((entry) => entry.isFile() && entry.name.endsWith(".pptd")).map((entry) => entry.name).sort();
3193
+ if (entries.length !== 1) throw new Error(`PPTD project directory must contain exactly one .pptd entry; found ${entries.length}`);
3194
+ const entry = entries.at(0);
3195
+ if (entry === void 0) throw new Error("PPTD project directory must contain one .pptd entry");
3196
+ return path.join(input, entry);
3197
+ }
3198
+ /** Load a confined local PPTD project. Network resources stay disabled. */
3199
+ async function loadPptdProject(entryPath) {
3200
+ const entry = await resolvePptdEntry(entryPath);
3201
+ const metadata = await lstat(entry);
3202
+ if (!metadata.isFile() || metadata.size > MAX_MANIFEST_BYTES) throw new Error("PPTD entry is invalid or too large");
3203
+ const root = path.dirname(entry);
3204
+ const manifest = await readFile(entry, "utf8");
3205
+ const raw = parseYaml(manifest, path.basename(entry), []);
3206
+ if (raw === void 0) return parsePptdProject({
3207
+ entryName: path.basename(entry),
3208
+ manifest,
3209
+ pages: /* @__PURE__ */ new Map(),
3210
+ assets: /* @__PURE__ */ new Map()
3211
+ });
3212
+ const refs = Array.isArray(raw.pages) ? raw.pages.slice(0, MAX_PAGES) : [];
3213
+ const pages = /* @__PURE__ */ new Map();
3214
+ const loadIssues = [];
3215
+ for (const rawRef of refs) {
3216
+ const ref = typeof rawRef === "string" ? safeProjectPath(rawRef) : void 0;
3217
+ if (ref === void 0) continue;
3218
+ try {
3219
+ const file = await confinedFile(root, ref, MAX_PAGE_BYTES);
3220
+ pages.set(ref, Buffer.from(file.bytes).toString("utf8"));
3221
+ } catch (error) {
3222
+ loadIssues.push({
3223
+ code: "file-read",
3224
+ severity: "error",
3225
+ file: ref,
3226
+ message: `无法读取页面文件 ${ref}:${error instanceof Error ? error.message : String(error)}`
3227
+ });
3228
+ }
3229
+ }
3230
+ const partial = parsePptdProject({
3231
+ entryName: path.basename(entry),
3232
+ manifest,
3233
+ pages,
3234
+ assets: /* @__PURE__ */ new Map(),
3235
+ issues: loadIssues
3236
+ });
3237
+ const refsToLoad = /* @__PURE__ */ new Set();
3238
+ for (const page of partial.pages) for (const element of page.elements) if (element.elementType === "image") {
3239
+ const ref = localAssetPath(element.src);
3240
+ if (ref !== void 0) refsToLoad.add(ref);
3241
+ }
3242
+ const assets = /* @__PURE__ */ new Map();
3243
+ let totalBytes = 0;
3244
+ for (const ref of refsToLoad) {
3245
+ let file;
3246
+ try {
3247
+ file = await confinedFile(root, ref, MAX_ASSET_BYTES);
3248
+ } catch (error) {
3249
+ loadIssues.push({
3250
+ code: "file-read",
3251
+ severity: "error",
3252
+ file: ref,
3253
+ message: `无法读取资源 ${ref}:${error instanceof Error ? error.message : String(error)}`
3254
+ });
3255
+ continue;
3256
+ }
3257
+ totalBytes += file.bytes.byteLength;
3258
+ if (totalBytes > MAX_TOTAL_ASSET_BYTES) throw new Error("PPTD image resources exceed the aggregate byte limit");
3259
+ const type = mediaType(ref, file.bytes);
3260
+ if (type === void 0) {
3261
+ loadIssues.push({
3262
+ code: "invalid-resource",
3263
+ severity: "error",
3264
+ file: ref,
3265
+ message: `图片资源格式或内容无效:${ref}`
3266
+ });
3267
+ continue;
3268
+ }
3269
+ assets.set(ref, {
3270
+ path: ref,
3271
+ mediaType: type,
3272
+ bytes: file.bytes,
3273
+ sha256: createHash("sha256").update(file.bytes).digest("hex")
3274
+ });
3275
+ }
3276
+ return parsePptdProject({
3277
+ entryName: path.basename(entry),
3278
+ manifest,
3279
+ pages,
3280
+ assets,
3281
+ issues: loadIssues
3282
+ });
3283
+ }
3284
+ //#endregion
3285
+ //#region src/pptd-repair.ts
3286
+ /** Deterministic, explicitly requested PPTD source repairs for `check --level auto`. */
3287
+ const ELEMENT_TYPES = new Set([
3288
+ "text",
3289
+ "shape",
3290
+ "line",
3291
+ "image",
3292
+ "icon",
3293
+ "table",
3294
+ "chart"
3295
+ ]);
3296
+ const MANIFEST_FIELDS = new Set([
3297
+ "version",
3298
+ "title",
3299
+ "size",
3300
+ "theme",
3301
+ "pages"
3302
+ ]);
3303
+ const PAGE_FIELDS = new Set([
3304
+ "pageType",
3305
+ "background",
3306
+ "notes",
3307
+ "elements"
3308
+ ]);
3309
+ const BASE_FIELDS = [
3310
+ "elementId",
3311
+ "elementType",
3312
+ "bounds"
3313
+ ];
3314
+ const ELEMENT_FIELDS = {
3315
+ text: new Set([
3316
+ ...BASE_FIELDS,
3317
+ "rotation",
3318
+ "opacity",
3319
+ "flip",
3320
+ "content"
3321
+ ]),
3322
+ shape: new Set([
3323
+ ...BASE_FIELDS,
3324
+ "rotation",
3325
+ "opacity",
3326
+ "flip",
3327
+ "shapeName",
3328
+ "adjustments",
3329
+ "viewBox",
3330
+ "path",
3331
+ "fill",
3332
+ "border",
3333
+ "shadow"
3334
+ ]),
3335
+ line: new Set([
3336
+ ...BASE_FIELDS,
3337
+ "rotation",
3338
+ "opacity",
3339
+ "flip",
3340
+ "viewBox",
3341
+ "points",
3342
+ "curve",
3343
+ "arrow",
3344
+ "border",
3345
+ "shadow"
3346
+ ]),
3347
+ image: new Set([
3348
+ ...BASE_FIELDS,
3349
+ "rotation",
3350
+ "opacity",
3351
+ "flip",
3352
+ "src",
3353
+ "cropShape",
3354
+ "fit",
3355
+ "crop",
3356
+ "border",
3357
+ "shadow"
3358
+ ]),
3359
+ icon: new Set([
3360
+ ...BASE_FIELDS,
3361
+ "rotation",
3362
+ "opacity",
3363
+ "flip",
3364
+ "iconName",
3365
+ "fill",
3366
+ "border",
3367
+ "shadow"
3368
+ ]),
3369
+ table: new Set([
3370
+ ...BASE_FIELDS,
3371
+ "columnWidths",
3372
+ "rowHeights",
3373
+ "rows",
3374
+ "style",
3375
+ "fill",
3376
+ "shadow"
3377
+ ]),
3378
+ chart: new Set([
3379
+ ...BASE_FIELDS,
3380
+ "data",
3381
+ "series",
3382
+ "seriesDefaults",
3383
+ "xAxis",
3384
+ "yAxis",
3385
+ "barWidth",
3386
+ "barGap",
3387
+ "categoryGap",
3388
+ "spokeAxis",
3389
+ "title",
3390
+ "legend",
3391
+ "dataLabels",
3392
+ "fontFamily",
3393
+ "fill",
3394
+ "border",
3395
+ "shadow"
3396
+ ])
3397
+ };
3398
+ function record(value) {
3399
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
3400
+ }
3401
+ function action(actions, file, element, kind, field, message) {
3402
+ const elementId = typeof element?.elementId === "string" ? element.elementId : void 0;
3403
+ actions.push({
3404
+ file,
3405
+ ...elementId === void 0 ? {} : { elementId },
3406
+ kind,
3407
+ field,
3408
+ message
3409
+ });
3410
+ }
3411
+ function finiteNumber(value) {
3412
+ if (typeof value === "number" && Number.isFinite(value)) return value;
3413
+ if (typeof value === "string" && value.trim() !== "" && Number.isFinite(Number(value))) return Number(value);
3414
+ }
3415
+ function booleanValue(value) {
3416
+ if (typeof value === "boolean") return value;
3417
+ if (value === "true") return true;
3418
+ if (value === "false") return false;
3419
+ }
3420
+ function normalizeNumber(owner, field, actions, file, element, range) {
3421
+ if (!(field in owner)) return;
3422
+ const before = owner[field];
3423
+ const converted = finiteNumber(before);
3424
+ if (converted !== void 0 && (range === void 0 || range(converted))) {
3425
+ if (before !== converted) {
3426
+ owner[field] = converted;
3427
+ action(actions, file, element, "convert-type", field, `${field} 已转换为数字。`);
3428
+ }
3429
+ return;
3430
+ }
3431
+ Reflect.deleteProperty(owner, field);
3432
+ action(actions, file, element, "delete-optional-field", field, `${field} 不是有效的可选数字,已删除。`);
3433
+ }
3434
+ function normalizeBoolean(owner, field, actions, file, element) {
3435
+ if (!(field in owner)) return;
3436
+ const before = owner[field];
3437
+ const converted = booleanValue(before);
3438
+ if (converted !== void 0) {
3439
+ if (before !== converted) {
3440
+ owner[field] = converted;
3441
+ action(actions, file, element, "convert-type", field, `${field} 已转换为布尔值。`);
3442
+ }
3443
+ return;
3444
+ }
3445
+ Reflect.deleteProperty(owner, field);
3446
+ action(actions, file, element, "delete-optional-field", field, `${field} 不是有效的可选布尔值,已删除。`);
3447
+ }
3448
+ function normalizeTuple(owner, field, size, actions, file, element, required) {
3449
+ const before = owner[field];
3450
+ if (!Array.isArray(before) || before.length !== size) {
3451
+ if (!required && field in owner) {
3452
+ Reflect.deleteProperty(owner, field);
3453
+ action(actions, file, element, "delete-optional-field", field, `${field} 不是长度为 ${size} 的数字数组,已删除。`);
3454
+ }
3455
+ return false;
3456
+ }
3457
+ const converted = before.map(finiteNumber);
3458
+ if (converted.some((value) => value === void 0)) {
3459
+ if (!required) {
3460
+ Reflect.deleteProperty(owner, field);
3461
+ action(actions, file, element, "delete-optional-field", field, `${field} 包含无效数字,已删除。`);
3462
+ }
3463
+ return false;
3464
+ }
3465
+ if (before.some((value, index) => value !== converted[index])) {
3466
+ owner[field] = converted;
3467
+ action(actions, file, element, "convert-type", field, `${field} 中的数字字符串已转换。`);
3468
+ }
3469
+ return true;
3470
+ }
3471
+ function normalizeBooleanTuple(owner, field, size, actions, file, element) {
3472
+ const before = owner[field];
3473
+ if (!(field in owner)) return;
3474
+ if (!Array.isArray(before) || before.length !== size) {
3475
+ Reflect.deleteProperty(owner, field);
3476
+ action(actions, file, element, "delete-optional-field", field, `${field} 不是长度为 ${size} 的布尔数组,已删除。`);
3477
+ return;
3478
+ }
3479
+ const converted = before.map(booleanValue);
3480
+ if (converted.some((value) => value === void 0)) {
3481
+ Reflect.deleteProperty(owner, field);
3482
+ action(actions, file, element, "delete-optional-field", field, `${field} 包含无效布尔值,已删除。`);
3483
+ return;
3484
+ }
3485
+ if (before.some((value, index) => value !== converted[index])) {
3486
+ owner[field] = converted;
3487
+ action(actions, file, element, "convert-type", field, `${field} 中的布尔字符串已转换。`);
3488
+ }
3489
+ }
3490
+ function normalizeCrop(owner, actions, file, element) {
3491
+ if (!("crop" in owner)) return;
3492
+ const crop = record(owner.crop);
3493
+ if (crop === void 0) {
3494
+ Reflect.deleteProperty(owner, "crop");
3495
+ action(actions, file, element, "delete-optional-field", "crop", "crop 不是裁剪对象,已删除。");
3496
+ return;
3497
+ }
3498
+ for (const field of [
3499
+ "left",
3500
+ "top",
3501
+ "right",
3502
+ "bottom"
3503
+ ]) normalizeNumber(crop, field, actions, file, element);
3504
+ }
3505
+ function normalizeString(owner, field, actions, file, element) {
3506
+ const before = owner[field];
3507
+ if (typeof before === "string") return true;
3508
+ if (typeof before === "number" || typeof before === "boolean") {
3509
+ owner[field] = String(before);
3510
+ action(actions, file, element, "convert-type", field, `${field} 已转换为字符串。`);
3511
+ return true;
3512
+ }
3513
+ return false;
3514
+ }
3515
+ function normalizeStyle(style, actions, file, element) {
3516
+ for (const field of [
3517
+ "fontSize",
3518
+ "lineHeight",
3519
+ "letterSpacing",
3520
+ "paragraphSpacing",
3521
+ "opacity"
3522
+ ]) normalizeNumber(style, field, actions, file, element, field === "opacity" ? (value) => value >= 0 && value <= 1 : (value) => value >= 0);
3523
+ for (const field of [
3524
+ "bold",
3525
+ "italic",
3526
+ "wrap",
3527
+ "strike"
3528
+ ]) normalizeBoolean(style, field, actions, file, element);
3529
+ }
3530
+ function normalizeElement(element, actions, file) {
3531
+ if (!normalizeString(element, "elementId", actions, file, element) || String(element.elementId).trim() === "") return false;
3532
+ if (typeof element.elementType !== "string" || !ELEMENT_TYPES.has(element.elementType)) return false;
3533
+ const allowed = ELEMENT_FIELDS[element.elementType];
3534
+ if (allowed !== void 0) for (const field of Object.keys(element)) {
3535
+ if (allowed.has(field)) continue;
3536
+ Reflect.deleteProperty(element, field);
3537
+ action(actions, file, element, "delete-optional-field", field, `未知字段 ${field} 已删除。`);
3538
+ }
3539
+ if (!normalizeTuple(element, "bounds", 4, actions, file, element, true)) return false;
3540
+ const bounds = element.bounds;
3541
+ if ((bounds[2] ?? -1) < 0 || (bounds[3] ?? -1) < 0) return false;
3542
+ for (const field of ["rotation", "opacity"]) normalizeNumber(element, field, actions, file, element, field === "opacity" ? (value) => value >= 0 && value <= 1 : void 0);
3543
+ normalizeBooleanTuple(element, "flip", 2, actions, file, element);
3544
+ normalizeCrop(element, actions, file, element);
3545
+ const type = element.elementType;
3546
+ if (type === "text") {
3547
+ const content = record(element.content);
3548
+ if (content === void 0 || !normalizeString(content, "text", actions, file, element)) return false;
3549
+ normalizeStyle(content, actions, file, element);
3550
+ }
3551
+ if (type === "shape") {
3552
+ if (typeof element.shapeName !== "string") return false;
3553
+ if (element.shapeName === "custom" && (!normalizeTuple(element, "viewBox", 2, actions, file, element, true) || typeof element.path !== "string")) return false;
3554
+ }
3555
+ if (type === "line") {
3556
+ if (!normalizeTuple(element, "viewBox", 2, actions, file, element, true) || typeof element.points !== "string") return false;
3557
+ }
3558
+ if (type === "image" && typeof element.src !== "string") return false;
3559
+ if (type === "icon" && typeof element.iconName !== "string") return false;
3560
+ if (type === "table") {
3561
+ if (!Array.isArray(element.rows) || !Array.isArray(element.columnWidths) || !Array.isArray(element.rowHeights)) return false;
3562
+ const normalizeRatios = (field) => {
3563
+ const values = element[field].map(finiteNumber);
3564
+ if (values.length === 0 || values.some((value) => value === void 0 || value < 0 || value > 1)) return false;
3565
+ const numeric = values;
3566
+ const sum = numeric.reduce((total, value) => total + value, 0);
3567
+ if (sum <= 0) return false;
3568
+ const normalized = Math.abs(sum - 1) < 1e-9 ? numeric : numeric.map((value) => value / sum);
3569
+ const output = Math.abs(sum - 1) < 1e-9 ? normalized : normalized.map((value, index) => index === normalized.length - 1 ? 1 - normalized.slice(0, -1).reduce((total, item) => total + item, 0) : value);
3570
+ if (element[field].some((value, index) => value !== output[index])) {
3571
+ element[field] = output;
3572
+ action(actions, file, element, "convert-type", field, `${field} 已转换为总和为 1 的数字比例。`);
3573
+ }
3574
+ return true;
3575
+ };
3576
+ if (!normalizeRatios("columnWidths") || !normalizeRatios("rowHeights")) return false;
3577
+ }
3578
+ if (type === "chart") {
3579
+ const data = record(element.data);
3580
+ if (data === void 0 || !Array.isArray(data.cols) || !Array.isArray(data.rows) || !Array.isArray(element.series)) return false;
3581
+ }
3582
+ return true;
3583
+ }
3584
+ function parseYamlObject(content, file) {
3585
+ const object = record(yaml.load(content, {
3586
+ schema: yaml.JSON_SCHEMA,
3587
+ json: true
3588
+ }));
3589
+ if (object === void 0) throw new Error(`${file} YAML root must be an object before auto repair`);
3590
+ return object;
3591
+ }
3592
+ function dumpYaml(value) {
3593
+ return yaml.dump(value, {
3594
+ schema: yaml.JSON_SCHEMA,
3595
+ noRefs: true,
3596
+ lineWidth: -1,
3597
+ sortKeys: false
3598
+ });
3599
+ }
3600
+ async function writeTextAtomic(target, content) {
3601
+ await mkdir(path.dirname(target), { recursive: true });
3602
+ const temporary = path.join(path.dirname(target), `.${path.basename(target)}.${randomUUID()}.tmp`);
3603
+ const handle = await open(temporary, "wx", 384);
3604
+ try {
3605
+ await handle.writeFile(content, "utf8");
3606
+ await handle.sync();
3607
+ } finally {
3608
+ await handle.close();
3609
+ }
3610
+ try {
3611
+ await rename(temporary, target);
3612
+ } finally {
3613
+ await rm(temporary, { force: true });
3614
+ }
3615
+ }
3616
+ /** Apply bounded deterministic repairs to the selected source pages and recheck the project. */
3617
+ async function repairPptdProject(inputPath, selectedPages) {
3618
+ const entry = await resolvePptdEntry(inputPath);
3619
+ const root = path.dirname(entry);
3620
+ const entryName = path.basename(entry);
3621
+ const actions = [];
3622
+ const changed = /* @__PURE__ */ new Map();
3623
+ const manifestContent = await readFile(entry, "utf8");
3624
+ const manifest = parseYamlObject(manifestContent, entryName);
3625
+ const manifestActionStart = actions.length;
3626
+ for (const field of Object.keys(manifest)) {
3627
+ if (MANIFEST_FIELDS.has(field)) continue;
3628
+ Reflect.deleteProperty(manifest, field);
3629
+ action(actions, entryName, void 0, "delete-optional-field", field, `未知字段 ${field} 已删除。`);
3630
+ }
3631
+ normalizeString(manifest, "title", actions, entryName);
3632
+ normalizeTuple(manifest, "size", 2, actions, entryName, void 0, false);
3633
+ const textStyles = record(record(manifest.theme)?.textStyles);
3634
+ if (textStyles !== void 0) {
3635
+ const styles = Object.values(textStyles).map(record).filter((value) => value !== void 0);
3636
+ for (const style of styles) normalizeStyle(style, actions, entryName);
3637
+ }
3638
+ const repairedManifest = dumpYaml(manifest);
3639
+ if (actions.length > manifestActionStart && repairedManifest !== manifestContent) changed.set(entry, repairedManifest);
3640
+ const pageRefs = Array.isArray(manifest.pages) ? manifest.pages : [];
3641
+ for (const [index, rawRef] of pageRefs.entries()) {
3642
+ if (selectedPages !== void 0 && !selectedPages.has(index + 1)) continue;
3643
+ if (typeof rawRef !== "string" || path.isAbsolute(rawRef) || rawRef.includes("\\") || rawRef.startsWith("../")) continue;
3644
+ const target = path.join(root, ...path.posix.normalize(rawRef).split("/"));
3645
+ let content;
3646
+ try {
3647
+ content = await readFile(target, "utf8");
3648
+ } catch {
3649
+ continue;
3650
+ }
3651
+ const page = parseYamlObject(content, rawRef);
3652
+ const pageActionStart = actions.length;
3653
+ for (const field of Object.keys(page)) {
3654
+ if (PAGE_FIELDS.has(field)) continue;
3655
+ Reflect.deleteProperty(page, field);
3656
+ action(actions, rawRef, void 0, "delete-optional-field", field, `未知字段 ${field} 已删除。`);
3657
+ }
3658
+ if (normalizeString(page, "notes", actions, rawRef) === false && page.notes !== void 0) {
3659
+ Reflect.deleteProperty(page, "notes");
3660
+ action(actions, rawRef, void 0, "delete-optional-field", "notes", "notes 不是可转换的字符串,已删除。");
3661
+ }
3662
+ const elements = Array.isArray(page.elements) ? page.elements : [];
3663
+ const repairedElements = [];
3664
+ for (const [elementIndex, rawElement] of elements.entries()) {
3665
+ const element = record(rawElement);
3666
+ if (element !== void 0 && normalizeElement(element, actions, rawRef)) repairedElements.push(element);
3667
+ else action(actions, rawRef, element, "delete-invalid-element", `elements[${elementIndex}]`, "元素缺少无法安全修复的必填结构,已删除。");
3668
+ }
3669
+ page.elements = repairedElements;
3670
+ const repaired = dumpYaml(page);
3671
+ if (actions.length > pageActionStart && repaired !== content) changed.set(target, repaired);
3672
+ }
3673
+ for (const [target, content] of changed) await writeTextAtomic(target, content);
3674
+ const project = await loadPptdProject(entry);
3675
+ return {
3676
+ changedFiles: [...changed.keys()].map((target) => path.relative(root, target) || entryName),
3677
+ actions,
3678
+ check: checkPptdProject(project)
3679
+ };
3680
+ }
3681
+ //#endregion
3682
+ //#region src/bin.ts
3683
+ /** Local, bounded command line interface for the local PPTD v2 toolchain. */
3684
+ const MAX_PPTX_BYTES = 512 * 1024 * 1024;
3685
+ function usage() {
3686
+ return [
3687
+ "Usage:",
3688
+ " dsh-pptd convert <deck.pptx> [-o <project-directory>] [--strict] [--force] [--json]",
3689
+ " dsh-pptd check <project-directory|deck.pptd> [-p <pages>] [-s <severity>] [--level keep|auto] [--json]",
3690
+ " dsh-pptd inspect <project-directory|deck.pptd> [-p <pages>] [--json]",
3691
+ " dsh-pptd screenshot <project-directory|deck.pptd> [-p <pages>] [-o <directory>] [--scale <number>] [--force] [--json]",
3692
+ " dsh-pptd render <project-directory|deck.pptd> [-p <pages>] [-o <deck.pptx>] [--strict] [--force] [--json]",
3693
+ " dsh-pptd package <project-directory|deck.pptd> [...render options]",
3694
+ " dsh-pptd export <project-directory|deck.pptd> [...render options]",
3695
+ "",
3696
+ "Page specs are 1-based and support 3, 1,3,5, and 2-10.",
3697
+ "Severity specs support all, error, warning, one issue code, or comma-separated issue codes.",
3698
+ "Strict conversion refuses to publish a PPTD project when any source feature is normalized or unsupported.",
3699
+ "PPTD and local resources stay confined to the project directory. Network resources are disabled."
3700
+ ].join("\n");
3701
+ }
3702
+ function optionValue(argv, index, name) {
3703
+ const value = argv[index + 1];
3704
+ if (value === void 0 || value.startsWith("-")) throw new Error(`${name} requires a value`);
3705
+ return value;
3706
+ }
3707
+ function parseArgs(argv) {
3708
+ const positional = [];
3709
+ let output;
3710
+ let page;
3711
+ let severity = "all";
3712
+ let level = "keep";
3713
+ let scale = 2;
3714
+ let json = false;
3715
+ let force = false;
3716
+ let strict = false;
3717
+ let help = false;
3718
+ let version = false;
3719
+ for (let index = 0; index < argv.length; index += 1) {
3720
+ const value = argv[index];
3721
+ if (value === void 0) continue;
3722
+ if (value === "--json") {
3723
+ json = true;
3724
+ continue;
3725
+ }
3726
+ if (value === "--force") {
3727
+ force = true;
3728
+ continue;
3729
+ }
3730
+ if (value === "--strict") {
3731
+ strict = true;
3732
+ continue;
3733
+ }
3734
+ if (value === "--help" || value === "-h") {
3735
+ help = true;
3736
+ continue;
3737
+ }
3738
+ if (value === "--version" || value === "-v") {
3739
+ version = true;
3740
+ continue;
3741
+ }
3742
+ if (value === "--output" || value === "-o") {
3743
+ output = optionValue(argv, index, value);
3744
+ index += 1;
3745
+ continue;
3746
+ }
3747
+ if (value === "--page" || value === "-p") {
3748
+ page = optionValue(argv, index, value);
3749
+ index += 1;
3750
+ continue;
3751
+ }
3752
+ if (value === "--severity" || value === "-s") {
3753
+ const selectors = optionValue(argv, index, value).split(",").map((item) => item.trim());
3754
+ if (selectors.some((item) => item === "" || !/^[a-z][a-z0-9_-]*$/iu.test(item))) throw new Error("--severity must contain all, error, warning, or comma-separated issue codes");
3755
+ severity = selectors.join(",");
3756
+ index += 1;
3757
+ continue;
3758
+ }
3759
+ if (value === "--level") {
3760
+ const raw = optionValue(argv, index, value);
3761
+ if (raw !== "keep" && raw !== "auto") throw new Error("--level must be keep or auto");
3762
+ level = raw;
3763
+ index += 1;
3764
+ continue;
3765
+ }
3766
+ if (value === "--scale") {
3767
+ const raw = optionValue(argv, index, value);
3768
+ scale = Number(raw);
3769
+ if (!Number.isFinite(scale) || scale <= 0 || scale > 8) throw new Error("--scale must be greater than 0 and at most 8");
3770
+ index += 1;
3771
+ continue;
3772
+ }
3773
+ if (value.startsWith("-")) throw new Error(`Unknown option: ${value}`);
3774
+ positional.push(value);
3775
+ }
3776
+ if (positional.length > 2) throw new Error(`Unexpected argument: ${positional[2]}`);
3777
+ return {
3778
+ ...positional[0] === void 0 ? {} : { command: positional[0] },
3779
+ ...positional[1] === void 0 ? {} : { input: positional[1] },
3780
+ ...output === void 0 ? {} : { output },
3781
+ ...page === void 0 ? {} : { page },
3782
+ severity,
3783
+ level,
3784
+ scale,
3785
+ json,
3786
+ force,
3787
+ strict,
3788
+ help,
3789
+ version
3790
+ };
3791
+ }
3792
+ async function packageVersion() {
3793
+ const content = await readFile(new URL("../package.json", import.meta.url), "utf8");
3794
+ const parsed = JSON.parse(content);
3795
+ if (typeof parsed.version !== "string") throw new Error("package.json does not declare a version");
3796
+ return parsed.version;
3797
+ }
3798
+ function writeLine(stream, value) {
3799
+ stream.write(`${value}\n`);
3800
+ }
3801
+ function printValue(io, value, _json) {
3802
+ if (typeof value === "string") writeLine(io.stdout, value);
3803
+ else writeLine(io.stdout, JSON.stringify(value, null, 2));
3804
+ }
3805
+ function pageNumbers(spec, count) {
3806
+ if (count < 1) return [];
3807
+ if (spec === void 0) return Array.from({ length: count }, (_value, index) => index + 1);
3808
+ const selected = /* @__PURE__ */ new Set();
3809
+ for (const rawPart of spec.split(",")) {
3810
+ const part = rawPart.trim();
3811
+ if (/^\d+$/u.test(part)) {
3812
+ selected.add(Number(part));
3813
+ continue;
3814
+ }
3815
+ const range = /^(\d+)-(\d+)$/u.exec(part);
3816
+ if (range === null) throw new Error(`Invalid page spec: ${part}`);
3817
+ const start = Number(range[1]);
3818
+ const end = Number(range[2]);
3819
+ if (start > end) throw new Error(`Invalid descending page range: ${part}`);
3820
+ for (let value = start; value <= end; value += 1) selected.add(value);
3821
+ }
3822
+ const values = [...selected].sort((left, right) => left - right);
3823
+ const invalid = values.find((value) => !Number.isInteger(value) || value < 1 || value > count);
3824
+ if (invalid !== void 0) throw new Error(`Page ${invalid} is outside the available range 1-${count}`);
3825
+ if (values.length === 0) throw new Error("Page spec selects no pages");
3826
+ return values;
3827
+ }
3828
+ function selectedProject(project, pages) {
3829
+ if (pages.length === project.pages.length && pages.every((page, index) => page === index + 1)) return project;
3830
+ const selected = new Set(pages);
3831
+ return {
3832
+ ...project,
3833
+ pages: pages.flatMap((page) => {
3834
+ const selectedPage = project.pages[page - 1];
3835
+ return selectedPage === void 0 ? [] : [selectedPage];
3836
+ }),
3837
+ parseIssues: project.parseIssues.filter((issue) => issue.page === void 0 || selected.has(issue.page))
3838
+ };
3839
+ }
3840
+ function issueMatchesSeverity(issue, severity) {
3841
+ const selectors = severity.split(",").map((value) => value.trim().toLowerCase());
3842
+ if (selectors.includes("all")) return true;
3843
+ return selectors.some((selector) => selector === issue.severity || selector === issue.code.toLowerCase());
3844
+ }
3845
+ function checkedForPages(project, pages, severity) {
3846
+ const subset = selectedProject(project, pages);
3847
+ const raw = checkPptdProject(subset);
3848
+ const issues = raw.issues.map((issue) => {
3849
+ if (issue.page === void 0 || subset === project) return issue;
3850
+ const originalPage = pages[issue.page - 1];
3851
+ return originalPage === void 0 ? issue : {
3852
+ ...issue,
3853
+ page: originalPage
3854
+ };
3855
+ });
3856
+ const displayedIssues = issues.filter((issue) => issueMatchesSeverity(issue, severity));
3857
+ return {
3858
+ ...raw,
3859
+ issues,
3860
+ displayedIssues
3861
+ };
3862
+ }
3863
+ function humanCheck(checked) {
3864
+ const lines = (checked.displayedIssues ?? checked.issues).map((issue) => [
3865
+ "[fixed: false]",
3866
+ `[${issue.severity === "error" ? "Needs revision" : "Suggestion"}:${issue.code}]`,
3867
+ issue.file ?? "",
3868
+ issue.page === void 0 ? "" : `page=${issue.page}`,
3869
+ issue.elementId === void 0 ? "" : `id="${issue.elementId}"`,
3870
+ issue.message
3871
+ ].filter(Boolean).join(" "));
3872
+ lines.push(`${checked.status.toUpperCase()}: ${checked.errorCount} error(s), ${checked.warningCount} warning(s), ${checked.pageCount} page(s)`);
3873
+ return lines.join("\n");
3874
+ }
3875
+ function humanRepairs(actions) {
3876
+ return actions.map((item) => [
3877
+ "[fixed: true]",
3878
+ `[Repair:${item.kind}]`,
3879
+ item.file,
3880
+ item.elementId === void 0 ? "" : `id="${item.elementId}"`,
3881
+ item.message
3882
+ ].filter(Boolean).join(" ")).join("\n");
3883
+ }
3884
+ function inspectProject(project, pages, checked) {
3885
+ const elementTypes = {};
3886
+ const resources = {
3887
+ assets: project.source.assets.size,
3888
+ bytes: 0
3889
+ };
3890
+ for (const asset of project.source.assets.values()) resources.bytes += asset.bytes.byteLength;
3891
+ for (const pageNumber of pages) {
3892
+ const page = project.pages[pageNumber - 1];
3893
+ if (page === void 0) continue;
3894
+ for (const element of page.elements) {
3895
+ const type = typeof element.elementType === "string" ? element.elementType : "unknown";
3896
+ elementTypes[type] = (elementTypes[type] ?? 0) + 1;
3897
+ }
3898
+ }
3899
+ return {
3900
+ title: project.title,
3901
+ size: [project.width, project.height],
3902
+ selectedPages: pages,
3903
+ elementTypes,
3904
+ resources,
3905
+ compatibility: checked.compatibility,
3906
+ check: checked
3907
+ };
3908
+ }
3909
+ function defaultConvertOutput(input) {
3910
+ const resolved = path.resolve(input);
3911
+ return path.join(path.dirname(resolved), path.basename(resolved, path.extname(resolved)));
3912
+ }
3913
+ async function projectRoot(input) {
3914
+ const entry = await resolvePptdEntry(input);
3915
+ return {
3916
+ entry,
3917
+ root: path.dirname(entry)
3918
+ };
3919
+ }
3920
+ async function defaultScreenshotOutput(input) {
3921
+ const { root } = await projectRoot(input);
3922
+ return path.join(path.dirname(root), `${path.basename(root)}-screenshots`);
3923
+ }
3924
+ async function defaultRenderOutput(input) {
3925
+ const { entry, root } = await projectRoot(input);
3926
+ return (await lstat(path.resolve(input))).isDirectory() ? path.join(path.dirname(root), `${path.basename(root)}.pptx`) : path.join(root, `${path.basename(entry, ".pptd")}.pptx`);
3927
+ }
3928
+ async function commandConvert(args, io) {
3929
+ const input = path.resolve(args.input);
3930
+ const metadata = await lstat(input);
3931
+ if (!metadata.isFile() || path.extname(input).toLowerCase() !== ".pptx") throw new Error("convert input must be a .pptx file");
3932
+ if (metadata.size > MAX_PPTX_BYTES) throw new Error(`PPTX exceeds the ${MAX_PPTX_BYTES} byte limit`);
3933
+ const converted = await convertPptxToPptd(await readFile(input), path.basename(input));
3934
+ const normalizedCount = converted.diagnostics.filter((item) => item.level === "normalized").length;
3935
+ const unsupportedCount = converted.diagnostics.filter((item) => item.level === "unsupported").length;
3936
+ if (args.strict && converted.diagnostics.length > 0) throw new Error(`strict conversion requires lossless coverage; received ${normalizedCount} normalized and ${unsupportedCount} unsupported diagnostic(s)`);
3937
+ const output = path.resolve(args.output ?? defaultConvertOutput(input));
3938
+ await publishPptdDirectory(output, args.force, (stage) => writePptdProjectSource(stage, converted.source));
3939
+ printValue(io, {
3940
+ status: converted.diagnostics.length > 0 ? "warning" : "pass",
3941
+ input,
3942
+ output,
3943
+ slideCount: converted.slideCount,
3944
+ sourceNodeCount: converted.sourceNodeCount,
3945
+ outputElementCount: converted.outputElementCount,
3946
+ extractedAssetCount: converted.extractedAssetCount,
3947
+ normalizedCount,
3948
+ unsupportedCount,
3949
+ diagnostics: converted.diagnostics
3950
+ }, args.json);
3951
+ return 0;
3952
+ }
3953
+ async function commandPptd(args, io) {
3954
+ if (args.level === "auto" && args.command !== "check") throw new Error("--level auto is supported only by check");
3955
+ let project = await loadPptdProject(args.input);
3956
+ const pages = pageNumbers(args.page, project.pages.length);
3957
+ const repaired = args.level === "auto" ? await repairPptdProject(args.input, new Set(pages)) : void 0;
3958
+ if (repaired !== void 0) project = await loadPptdProject(args.input);
3959
+ const checked = checkedForPages(project, pages, args.severity);
3960
+ if (args.command === "check") {
3961
+ printValue(io, args.json ? {
3962
+ ...checked,
3963
+ repair: repaired === void 0 ? void 0 : {
3964
+ changedFiles: repaired.changedFiles,
3965
+ actions: repaired.actions
3966
+ }
3967
+ } : [repaired === void 0 ? "" : humanRepairs(repaired.actions), humanCheck(checked)].filter(Boolean).join("\n"), args.json);
3968
+ return checked.status === "fail" ? 1 : 0;
3969
+ }
3970
+ if (args.command === "inspect") {
3971
+ printValue(io, inspectProject(project, pages, checked), args.json);
3972
+ return checked.status === "fail" ? 1 : 0;
3973
+ }
3974
+ if (checked.status === "fail" || args.strict && checked.status !== "pass") {
3975
+ printValue(io, { ...checked, exported: false, status: "needs_revision" }, args.json,
3976
+ "No output produced; validation needs revision.\n" + humanCheck(checked));
3977
+ return 1;
3978
+ }
3979
+ if (args.command === "screenshot") {
3980
+ const output = path.resolve(args.output ?? await defaultScreenshotOutput(args.input));
3981
+ await publishPptdDirectory(output, args.force, async (stage) => {
3982
+ await mkdir(path.join(stage, "pages"), {
3983
+ recursive: true,
3984
+ mode: 448
3985
+ });
3986
+ const manifest = [];
3987
+ for (const page of pages) {
3988
+ const bytes = await renderPptdPagePng(project, page - 1, args.scale);
3989
+ const file = `pages/page-${page}.png`;
3990
+ await writeFile(path.join(stage, ...file.split("/")), bytes, { mode: 384 });
3991
+ manifest.push({
3992
+ page,
3993
+ file,
3994
+ bytes: bytes.byteLength
3995
+ });
3996
+ }
3997
+ const index = `${JSON.stringify({
3998
+ title: project.title,
3999
+ scale: args.scale,
4000
+ pages: manifest
4001
+ }, null, 2)}\n`;
4002
+ await writeFile(path.join(stage, "index.json"), index, { mode: 384 });
4003
+ });
4004
+ printValue(io, {
4005
+ status: checked.status,
4006
+ input: path.resolve(args.input),
4007
+ output,
4008
+ pages,
4009
+ scale: args.scale,
4010
+ warnings: checked.warningCount
4011
+ }, args.json);
4012
+ return 0;
4013
+ }
4014
+ const output = path.resolve(args.output ?? await defaultRenderOutput(args.input));
4015
+ const rendered = await renderPptdProject(selectedProject(project, pages));
4016
+ await publishPptdFile(output, rendered.bytes, args.force);
4017
+ printValue(io, {
4018
+ status: checked.status,
4019
+ input: path.resolve(args.input),
4020
+ output,
4021
+ pages,
4022
+ pageCount: pages.length,
4023
+ nativeObjectCount: rendered.nativeObjectCount,
4024
+ sizeBytes: rendered.bytes.byteLength,
4025
+ digest: checked.digest,
4026
+ warnings: checked.warningCount,
4027
+ compatibility: checked.compatibility
4028
+ }, args.json);
4029
+ return 0;
4030
+ }
4031
+ /** Execute the CLI without terminating the host process. */
4032
+ async function runCli(argv, io = process) {
4033
+ try {
4034
+ const args = parseArgs(argv);
4035
+ if (args.version) {
4036
+ writeLine(io.stdout, await packageVersion());
4037
+ return 0;
4038
+ }
4039
+ if (args.help || args.command === void 0) {
4040
+ writeLine(io.stdout, usage());
4041
+ return args.help ? 0 : 2;
4042
+ }
4043
+ if (args.input === void 0) throw new Error(`${args.command} requires an input path\n${usage()}`);
4044
+ const command = args.command === "package" || args.command === "export" ? "render" : args.command;
4045
+ const normalized = {
4046
+ ...args,
4047
+ command,
4048
+ input: args.input
4049
+ };
4050
+ if (command === "convert") return await commandConvert(normalized, io);
4051
+ if (![
4052
+ "check",
4053
+ "inspect",
4054
+ "screenshot",
4055
+ "render"
4056
+ ].includes(command)) throw new Error(`Unknown command: ${args.command}\n${usage()}`);
4057
+ return await commandPptd(normalized, io);
4058
+ } catch (error) {
4059
+ writeLine(io.stderr, error instanceof Error ? error.message : String(error));
4060
+ return 1;
4061
+ }
4062
+ }
4063
+ async function main() {
4064
+ process.exitCode = await runCli(process.argv.slice(2), process);
4065
+ }
4066
+ const invoked = process.argv[1];
4067
+ // npm installs .bin symlinks on POSIX; compare canonical paths so that entry runs too.
4068
+ if (invoked !== void 0 && pathToFileURL(await realpath(path.resolve(invoked)).catch(() => path.resolve(invoked))).href === import.meta.url) await main();
4069
+ //#endregion
4070
+ export { runCli };