docrev 0.8.1 → 0.8.5

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 (306) hide show
  1. package/.claude/settings.local.json +9 -0
  2. package/PLAN-tables-and-postprocess.md +850 -0
  3. package/README.md +33 -0
  4. package/bin/rev.js +12 -131
  5. package/bin/rev.ts +145 -0
  6. package/dist/bin/rev.d.ts +9 -0
  7. package/dist/bin/rev.d.ts.map +1 -0
  8. package/dist/bin/rev.js +118 -0
  9. package/dist/bin/rev.js.map +1 -0
  10. package/dist/lib/annotations.d.ts +91 -0
  11. package/dist/lib/annotations.d.ts.map +1 -0
  12. package/dist/lib/annotations.js +554 -0
  13. package/dist/lib/annotations.js.map +1 -0
  14. package/dist/lib/build.d.ts +171 -0
  15. package/dist/lib/build.d.ts.map +1 -0
  16. package/dist/lib/build.js +755 -0
  17. package/dist/lib/build.js.map +1 -0
  18. package/dist/lib/citations.d.ts +34 -0
  19. package/dist/lib/citations.d.ts.map +1 -0
  20. package/dist/lib/citations.js +140 -0
  21. package/dist/lib/citations.js.map +1 -0
  22. package/dist/lib/commands/build.d.ts +13 -0
  23. package/dist/lib/commands/build.d.ts.map +1 -0
  24. package/dist/lib/commands/build.js +678 -0
  25. package/dist/lib/commands/build.js.map +1 -0
  26. package/dist/lib/commands/citations.d.ts +11 -0
  27. package/dist/lib/commands/citations.d.ts.map +1 -0
  28. package/dist/lib/commands/citations.js +428 -0
  29. package/dist/lib/commands/citations.js.map +1 -0
  30. package/dist/lib/commands/comments.d.ts +11 -0
  31. package/dist/lib/commands/comments.d.ts.map +1 -0
  32. package/dist/lib/commands/comments.js +883 -0
  33. package/dist/lib/commands/comments.js.map +1 -0
  34. package/dist/lib/commands/context.d.ts +35 -0
  35. package/dist/lib/commands/context.d.ts.map +1 -0
  36. package/dist/lib/commands/context.js +59 -0
  37. package/dist/lib/commands/context.js.map +1 -0
  38. package/dist/lib/commands/core.d.ts +11 -0
  39. package/dist/lib/commands/core.d.ts.map +1 -0
  40. package/dist/lib/commands/core.js +246 -0
  41. package/dist/lib/commands/core.js.map +1 -0
  42. package/dist/lib/commands/doi.d.ts +11 -0
  43. package/dist/lib/commands/doi.d.ts.map +1 -0
  44. package/dist/lib/commands/doi.js +373 -0
  45. package/dist/lib/commands/doi.js.map +1 -0
  46. package/dist/lib/commands/history.d.ts +11 -0
  47. package/dist/lib/commands/history.d.ts.map +1 -0
  48. package/dist/lib/commands/history.js +245 -0
  49. package/dist/lib/commands/history.js.map +1 -0
  50. package/dist/lib/commands/index.d.ts +28 -0
  51. package/dist/lib/commands/index.d.ts.map +1 -0
  52. package/dist/lib/commands/index.js +35 -0
  53. package/dist/lib/commands/index.js.map +1 -0
  54. package/dist/lib/commands/init.d.ts +11 -0
  55. package/dist/lib/commands/init.d.ts.map +1 -0
  56. package/dist/lib/commands/init.js +209 -0
  57. package/dist/lib/commands/init.js.map +1 -0
  58. package/dist/lib/commands/response.d.ts +11 -0
  59. package/dist/lib/commands/response.d.ts.map +1 -0
  60. package/dist/lib/commands/response.js +317 -0
  61. package/dist/lib/commands/response.js.map +1 -0
  62. package/dist/lib/commands/sections.d.ts +11 -0
  63. package/dist/lib/commands/sections.d.ts.map +1 -0
  64. package/dist/lib/commands/sections.js +1071 -0
  65. package/dist/lib/commands/sections.js.map +1 -0
  66. package/dist/lib/commands/utilities.d.ts +19 -0
  67. package/dist/lib/commands/utilities.d.ts.map +1 -0
  68. package/dist/lib/commands/utilities.js +2009 -0
  69. package/dist/lib/commands/utilities.js.map +1 -0
  70. package/dist/lib/comment-realign.d.ts +50 -0
  71. package/dist/lib/comment-realign.d.ts.map +1 -0
  72. package/dist/lib/comment-realign.js +372 -0
  73. package/dist/lib/comment-realign.js.map +1 -0
  74. package/dist/lib/config.d.ts +41 -0
  75. package/dist/lib/config.d.ts.map +1 -0
  76. package/dist/lib/config.js +76 -0
  77. package/dist/lib/config.js.map +1 -0
  78. package/dist/lib/crossref.d.ts +108 -0
  79. package/dist/lib/crossref.d.ts.map +1 -0
  80. package/dist/lib/crossref.js +597 -0
  81. package/dist/lib/crossref.js.map +1 -0
  82. package/dist/lib/dependencies.d.ts +30 -0
  83. package/dist/lib/dependencies.d.ts.map +1 -0
  84. package/dist/lib/dependencies.js +95 -0
  85. package/dist/lib/dependencies.js.map +1 -0
  86. package/dist/lib/doi-cache.d.ts +29 -0
  87. package/dist/lib/doi-cache.d.ts.map +1 -0
  88. package/dist/lib/doi-cache.js +104 -0
  89. package/dist/lib/doi-cache.js.map +1 -0
  90. package/dist/lib/doi.d.ts +65 -0
  91. package/dist/lib/doi.d.ts.map +1 -0
  92. package/dist/lib/doi.js +710 -0
  93. package/dist/lib/doi.js.map +1 -0
  94. package/dist/lib/equations.d.ts +61 -0
  95. package/dist/lib/equations.d.ts.map +1 -0
  96. package/dist/lib/equations.js +445 -0
  97. package/dist/lib/equations.js.map +1 -0
  98. package/dist/lib/errors.d.ts +60 -0
  99. package/dist/lib/errors.d.ts.map +1 -0
  100. package/dist/lib/errors.js +303 -0
  101. package/dist/lib/errors.js.map +1 -0
  102. package/dist/lib/format.d.ts +104 -0
  103. package/dist/lib/format.d.ts.map +1 -0
  104. package/dist/lib/format.js +416 -0
  105. package/dist/lib/format.js.map +1 -0
  106. package/dist/lib/git.d.ts +88 -0
  107. package/dist/lib/git.d.ts.map +1 -0
  108. package/dist/lib/git.js +304 -0
  109. package/dist/lib/git.js.map +1 -0
  110. package/dist/lib/grammar.d.ts +62 -0
  111. package/dist/lib/grammar.d.ts.map +1 -0
  112. package/dist/lib/grammar.js +244 -0
  113. package/dist/lib/grammar.js.map +1 -0
  114. package/dist/lib/image-registry.d.ts +68 -0
  115. package/dist/lib/image-registry.d.ts.map +1 -0
  116. package/dist/lib/image-registry.js +112 -0
  117. package/dist/lib/image-registry.js.map +1 -0
  118. package/dist/lib/import.d.ts +184 -0
  119. package/dist/lib/import.d.ts.map +1 -0
  120. package/dist/lib/import.js +1581 -0
  121. package/dist/lib/import.js.map +1 -0
  122. package/dist/lib/journals.d.ts +55 -0
  123. package/dist/lib/journals.d.ts.map +1 -0
  124. package/dist/lib/journals.js +417 -0
  125. package/dist/lib/journals.js.map +1 -0
  126. package/dist/lib/merge.d.ts +138 -0
  127. package/dist/lib/merge.d.ts.map +1 -0
  128. package/dist/lib/merge.js +603 -0
  129. package/dist/lib/merge.js.map +1 -0
  130. package/dist/lib/orcid.d.ts +36 -0
  131. package/dist/lib/orcid.d.ts.map +1 -0
  132. package/dist/lib/orcid.js +117 -0
  133. package/dist/lib/orcid.js.map +1 -0
  134. package/dist/lib/pdf-comments.d.ts +95 -0
  135. package/dist/lib/pdf-comments.d.ts.map +1 -0
  136. package/dist/lib/pdf-comments.js +192 -0
  137. package/dist/lib/pdf-comments.js.map +1 -0
  138. package/dist/lib/pdf-import.d.ts +118 -0
  139. package/dist/lib/pdf-import.d.ts.map +1 -0
  140. package/dist/lib/pdf-import.js +397 -0
  141. package/dist/lib/pdf-import.js.map +1 -0
  142. package/dist/lib/plugins.d.ts +76 -0
  143. package/dist/lib/plugins.d.ts.map +1 -0
  144. package/dist/lib/plugins.js +235 -0
  145. package/dist/lib/plugins.js.map +1 -0
  146. package/dist/lib/postprocess.d.ts +42 -0
  147. package/dist/lib/postprocess.d.ts.map +1 -0
  148. package/dist/lib/postprocess.js +138 -0
  149. package/dist/lib/postprocess.js.map +1 -0
  150. package/dist/lib/pptx-template.d.ts +59 -0
  151. package/dist/lib/pptx-template.d.ts.map +1 -0
  152. package/dist/lib/pptx-template.js +613 -0
  153. package/dist/lib/pptx-template.js.map +1 -0
  154. package/dist/lib/pptx-themes.d.ts +80 -0
  155. package/dist/lib/pptx-themes.d.ts.map +1 -0
  156. package/dist/lib/pptx-themes.js +818 -0
  157. package/dist/lib/pptx-themes.js.map +1 -0
  158. package/dist/lib/protect-restore.d.ts +137 -0
  159. package/dist/lib/protect-restore.d.ts.map +1 -0
  160. package/dist/lib/protect-restore.js +394 -0
  161. package/dist/lib/protect-restore.js.map +1 -0
  162. package/dist/lib/rate-limiter.d.ts +27 -0
  163. package/dist/lib/rate-limiter.d.ts.map +1 -0
  164. package/dist/lib/rate-limiter.js +79 -0
  165. package/dist/lib/rate-limiter.js.map +1 -0
  166. package/dist/lib/response.d.ts +41 -0
  167. package/dist/lib/response.d.ts.map +1 -0
  168. package/dist/lib/response.js +150 -0
  169. package/dist/lib/response.js.map +1 -0
  170. package/dist/lib/review.d.ts +35 -0
  171. package/dist/lib/review.d.ts.map +1 -0
  172. package/dist/lib/review.js +263 -0
  173. package/dist/lib/review.js.map +1 -0
  174. package/dist/lib/schema.d.ts +66 -0
  175. package/dist/lib/schema.d.ts.map +1 -0
  176. package/dist/lib/schema.js +339 -0
  177. package/dist/lib/schema.js.map +1 -0
  178. package/dist/lib/scientific-words.d.ts +6 -0
  179. package/dist/lib/scientific-words.d.ts.map +1 -0
  180. package/dist/lib/scientific-words.js +66 -0
  181. package/dist/lib/scientific-words.js.map +1 -0
  182. package/dist/lib/sections.d.ts +40 -0
  183. package/dist/lib/sections.d.ts.map +1 -0
  184. package/dist/lib/sections.js +288 -0
  185. package/dist/lib/sections.js.map +1 -0
  186. package/dist/lib/slides.d.ts +86 -0
  187. package/dist/lib/slides.d.ts.map +1 -0
  188. package/dist/lib/slides.js +676 -0
  189. package/dist/lib/slides.js.map +1 -0
  190. package/dist/lib/spelling.d.ts +76 -0
  191. package/dist/lib/spelling.d.ts.map +1 -0
  192. package/dist/lib/spelling.js +272 -0
  193. package/dist/lib/spelling.js.map +1 -0
  194. package/dist/lib/templates.d.ts +30 -0
  195. package/dist/lib/templates.d.ts.map +1 -0
  196. package/dist/lib/templates.js +504 -0
  197. package/dist/lib/templates.js.map +1 -0
  198. package/dist/lib/themes.d.ts +85 -0
  199. package/dist/lib/themes.d.ts.map +1 -0
  200. package/dist/lib/themes.js +652 -0
  201. package/dist/lib/themes.js.map +1 -0
  202. package/dist/lib/trackchanges.d.ts +51 -0
  203. package/dist/lib/trackchanges.d.ts.map +1 -0
  204. package/dist/lib/trackchanges.js +202 -0
  205. package/dist/lib/trackchanges.js.map +1 -0
  206. package/dist/lib/tui.d.ts +76 -0
  207. package/dist/lib/tui.d.ts.map +1 -0
  208. package/dist/lib/tui.js +377 -0
  209. package/dist/lib/tui.js.map +1 -0
  210. package/dist/lib/types.d.ts +447 -0
  211. package/dist/lib/types.d.ts.map +1 -0
  212. package/dist/lib/types.js +6 -0
  213. package/dist/lib/types.js.map +1 -0
  214. package/dist/lib/undo.d.ts +57 -0
  215. package/dist/lib/undo.d.ts.map +1 -0
  216. package/dist/lib/undo.js +185 -0
  217. package/dist/lib/undo.js.map +1 -0
  218. package/dist/lib/utils.d.ts +16 -0
  219. package/dist/lib/utils.d.ts.map +1 -0
  220. package/dist/lib/utils.js +40 -0
  221. package/dist/lib/utils.js.map +1 -0
  222. package/dist/lib/variables.d.ts +42 -0
  223. package/dist/lib/variables.d.ts.map +1 -0
  224. package/dist/lib/variables.js +141 -0
  225. package/dist/lib/variables.js.map +1 -0
  226. package/dist/lib/word.d.ts +80 -0
  227. package/dist/lib/word.d.ts.map +1 -0
  228. package/dist/lib/word.js +360 -0
  229. package/dist/lib/word.js.map +1 -0
  230. package/dist/lib/wordcomments.d.ts +51 -0
  231. package/dist/lib/wordcomments.d.ts.map +1 -0
  232. package/dist/lib/wordcomments.js +587 -0
  233. package/dist/lib/wordcomments.js.map +1 -0
  234. package/eslint.config.js +27 -0
  235. package/lib/annotations.ts +622 -0
  236. package/lib/apply-buildup-colors.py +88 -0
  237. package/lib/build.ts +1013 -0
  238. package/lib/{citations.js → citations.ts} +38 -27
  239. package/lib/commands/{build.js → build.ts} +80 -27
  240. package/lib/commands/{citations.js → citations.ts} +36 -18
  241. package/lib/commands/{comments.js → comments.ts} +187 -54
  242. package/lib/commands/{context.js → context.ts} +18 -8
  243. package/lib/commands/{core.js → core.ts} +34 -20
  244. package/lib/commands/{doi.js → doi.ts} +32 -16
  245. package/lib/commands/{history.js → history.ts} +25 -12
  246. package/lib/commands/{index.js → index.ts} +9 -5
  247. package/lib/commands/{init.js → init.ts} +20 -8
  248. package/lib/commands/{response.js → response.ts} +47 -20
  249. package/lib/commands/{sections.js → sections.ts} +273 -68
  250. package/lib/commands/{utilities.js → utilities.ts} +338 -158
  251. package/lib/{comment-realign.js → comment-realign.ts} +117 -45
  252. package/lib/config.ts +84 -0
  253. package/lib/{crossref.js → crossref.ts} +213 -138
  254. package/lib/dependencies.ts +106 -0
  255. package/lib/doi-cache.ts +115 -0
  256. package/lib/{doi.js → doi.ts} +115 -281
  257. package/lib/{equations.js → equations.ts} +60 -64
  258. package/lib/{errors.js → errors.ts} +56 -48
  259. package/lib/{format.js → format.ts} +137 -63
  260. package/lib/{git.js → git.ts} +66 -63
  261. package/lib/{grammar.js → grammar.ts} +45 -32
  262. package/lib/image-registry.ts +180 -0
  263. package/lib/import.ts +2060 -0
  264. package/lib/journals.ts +505 -0
  265. package/lib/{merge.js → merge.ts} +185 -135
  266. package/lib/{orcid.js → orcid.ts} +17 -22
  267. package/lib/{pdf-comments.js → pdf-comments.ts} +76 -18
  268. package/lib/{pdf-import.js → pdf-import.ts} +148 -70
  269. package/lib/{plugins.js → plugins.ts} +82 -39
  270. package/lib/postprocess.ts +188 -0
  271. package/lib/pptx-color-filter.lua +37 -0
  272. package/lib/pptx-template.ts +625 -0
  273. package/lib/pptx-themes/academic.pptx +0 -0
  274. package/lib/pptx-themes/corporate.pptx +0 -0
  275. package/lib/pptx-themes/dark.pptx +0 -0
  276. package/lib/pptx-themes/default.pptx +0 -0
  277. package/lib/pptx-themes/minimal.pptx +0 -0
  278. package/lib/pptx-themes/plant.pptx +0 -0
  279. package/lib/pptx-themes.ts +896 -0
  280. package/lib/protect-restore.ts +516 -0
  281. package/lib/rate-limiter.ts +94 -0
  282. package/lib/{response.js → response.ts} +36 -21
  283. package/lib/{review.js → review.ts} +53 -43
  284. package/lib/{schema.js → schema.ts} +70 -25
  285. package/lib/{sections.js → sections.ts} +71 -76
  286. package/lib/slides.ts +793 -0
  287. package/lib/{spelling.js → spelling.ts} +43 -59
  288. package/lib/{templates.js → templates.ts} +20 -17
  289. package/lib/themes.ts +742 -0
  290. package/lib/{trackchanges.js → trackchanges.ts} +52 -23
  291. package/lib/types.ts +509 -0
  292. package/lib/{undo.js → undo.ts} +75 -52
  293. package/lib/utils.ts +41 -0
  294. package/lib/{variables.js → variables.ts} +60 -54
  295. package/lib/word.ts +428 -0
  296. package/lib/{wordcomments.js → wordcomments.ts} +94 -40
  297. package/package.json +15 -5
  298. package/skill/REFERENCE.md +67 -0
  299. package/tsconfig.json +26 -0
  300. package/lib/annotations.js +0 -414
  301. package/lib/build.js +0 -639
  302. package/lib/config.js +0 -79
  303. package/lib/import.js +0 -1145
  304. package/lib/journals.js +0 -629
  305. package/lib/word.js +0 -225
  306. /package/lib/{scientific-words.js → scientific-words.ts} +0 -0
@@ -0,0 +1,613 @@
1
+ /**
2
+ * PPTX post-processing
3
+ *
4
+ * Injects logos into each slide of a generated PPTX to match ref.pptx styling.
5
+ * Uses ref.pptx as-is for --reference-doc, then post-processes to add logos.
6
+ */
7
+ import { existsSync, readFileSync, writeFileSync, unlinkSync } from 'node:fs';
8
+ import { join, dirname } from 'node:path';
9
+ import { execSync } from 'node:child_process';
10
+ /**
11
+ * Extract PPTX to directory
12
+ */
13
+ async function extractPptx(pptxPath, destDir) {
14
+ if (process.platform === 'win32') {
15
+ const zipPath = pptxPath.replace(/\.pptx$/i, '.zip');
16
+ const content = readFileSync(pptxPath);
17
+ writeFileSync(zipPath, content);
18
+ try {
19
+ execSync(`powershell -Command "Expand-Archive -LiteralPath '${zipPath}' -DestinationPath '${destDir}' -Force"`, { stdio: 'pipe' });
20
+ }
21
+ finally {
22
+ try {
23
+ unlinkSync(zipPath);
24
+ }
25
+ catch { /* ignore */ }
26
+ }
27
+ }
28
+ else {
29
+ execSync(`unzip -q "${pptxPath}" -d "${destDir}"`, { stdio: 'pipe' });
30
+ }
31
+ }
32
+ /**
33
+ * Create PPTX from directory
34
+ * Uses same compression settings as the original file
35
+ */
36
+ async function createPptx(srcDir, pptxPath) {
37
+ const scriptPath = join(dirname(pptxPath), '.zip-create.py');
38
+ const script = `import zipfile, os, sys
39
+
40
+ src, dst = sys.argv[1], sys.argv[2]
41
+
42
+ # Collect all files
43
+ files_to_add = []
44
+ for root, dirs, files in os.walk(src):
45
+ for f in files:
46
+ fp = os.path.join(root, f)
47
+ arcname = os.path.relpath(fp, src).replace(os.sep, '/')
48
+ files_to_add.append((fp, arcname))
49
+
50
+ # Write ZIP with DEFLATED compression
51
+ with zipfile.ZipFile(dst, 'w', zipfile.ZIP_DEFLATED, compresslevel=6) as zf:
52
+ for fp, arcname in files_to_add:
53
+ zf.write(fp, arcname)
54
+ `;
55
+ writeFileSync(scriptPath, script);
56
+ try {
57
+ const pythonCmd = process.platform === 'win32' ? 'python' : 'python3';
58
+ execSync(`${pythonCmd} "${scriptPath}" "${srcDir}" "${pptxPath}"`, { stdio: 'pipe' });
59
+ }
60
+ finally {
61
+ try {
62
+ unlinkSync(scriptPath);
63
+ }
64
+ catch { /* ignore */ }
65
+ }
66
+ }
67
+ /**
68
+ * Recursively remove directory
69
+ */
70
+ function rmSync(path, options) {
71
+ const fs = require('node:fs');
72
+ if (fs.rmSync) {
73
+ fs.rmSync(path, options);
74
+ }
75
+ else {
76
+ const items = fs.readdirSync(path);
77
+ for (const item of items) {
78
+ const itemPath = join(path, item);
79
+ if (fs.statSync(itemPath).isDirectory()) {
80
+ rmSync(itemPath, options);
81
+ }
82
+ else {
83
+ fs.unlinkSync(itemPath);
84
+ }
85
+ }
86
+ fs.rmdirSync(path);
87
+ }
88
+ }
89
+ /**
90
+ * Inject slide numbers into each slide of a PPTX
91
+ * Only adds slide numbers to slides that have a footer (i.e., slides with the green banner).
92
+ * Title slides, section slides, cover slides don't have the banner so they don't get numbers.
93
+ * Uses in-place ZIP modification to preserve file structure.
94
+ */
95
+ export async function injectSlideNumbers(pptxPath) {
96
+ if (!existsSync(pptxPath))
97
+ return;
98
+ const scriptPath = join(dirname(pptxPath), '.inject-slidenum.py');
99
+ const script = `import zipfile, sys, re, os
100
+
101
+ pptx_path = sys.argv[1]
102
+ temp_path = pptx_path + '.tmp'
103
+
104
+ # Slide number XML template with manual number (white text, 16pt)
105
+ def get_slidenum_xml(max_id, num):
106
+ return f'<p:sp><p:nvSpPr><p:cNvPr id="{max_id}" name="Slide Number Placeholder {max_id}"/><p:cNvSpPr><a:spLocks noGrp="1"/></p:cNvSpPr><p:nvPr><p:ph type="sldNum" sz="quarter" idx="12"/></p:nvPr></p:nvSpPr><p:spPr><a:xfrm><a:off x="8610600" y="6581838"/><a:ext cx="2743200" cy="319024"/></a:xfrm><a:prstGeom prst="rect"><a:avLst/></a:prstGeom></p:spPr><p:txBody><a:bodyPr/><a:lstStyle><a:lvl1pPr><a:defRPr sz="1600"><a:solidFill><a:srgbClr val="FFFFFF"/></a:solidFill></a:defRPr></a:lvl1pPr></a:lstStyle><a:p><a:r><a:rPr lang="en-GB" sz="1600" dirty="0"><a:solidFill><a:srgbClr val="FFFFFF"/></a:solidFill></a:rPr><a:t>{num}</a:t></a:r></a:p></p:txBody></p:sp>'
107
+
108
+ def is_content_slide(text):
109
+ """Check if slide is a content slide (has footer AND body placeholder)"""
110
+ has_footer = 'type="ftr"' in text
111
+ has_body = 'idx="1"' in text or 'type="body"' in text
112
+ return has_footer and has_body
113
+
114
+ # First pass: identify content slides and assign sequential numbers
115
+ with zipfile.ZipFile(pptx_path, 'r') as zin:
116
+ slide_numbers = {} # filename -> sequential number
117
+ content_num = 1
118
+
119
+ # Get all slide files sorted by number
120
+ slide_files = sorted([f for f in zin.namelist()
121
+ if f.startswith('ppt/slides/slide') and f.endswith('.xml')],
122
+ key=lambda x: int(re.search(r'slide(\\d+)', x).group(1)))
123
+
124
+ for fname in slide_files:
125
+ text = zin.read(fname).decode('utf-8')
126
+ if is_content_slide(text) and 'type="sldNum"' not in text:
127
+ slide_numbers[fname] = content_num
128
+ content_num += 1
129
+
130
+ # Second pass: inject numbers
131
+ with zipfile.ZipFile(pptx_path, 'r') as zin:
132
+ with zipfile.ZipFile(temp_path, 'w') as zout:
133
+ for item in zin.infolist():
134
+ content = zin.read(item.filename)
135
+
136
+ if item.filename in slide_numbers:
137
+ text = content.decode('utf-8')
138
+ # Find max id
139
+ ids = [int(m) for m in re.findall(r'id="(\\d+)"', text)]
140
+ max_id = max(ids) + 1 if ids else 100
141
+
142
+ # Insert slide number with sequential count
143
+ slidenum_xml = get_slidenum_xml(max_id, slide_numbers[item.filename])
144
+ text = text.replace('</p:spTree>', slidenum_xml + '</p:spTree>')
145
+ content = text.encode('utf-8')
146
+
147
+ zout.writestr(item, content)
148
+
149
+ os.replace(temp_path, pptx_path)
150
+ `;
151
+ writeFileSync(scriptPath, script);
152
+ try {
153
+ const pythonCmd = process.platform === 'win32' ? 'python' : 'python3';
154
+ execSync(`${pythonCmd} "${scriptPath}" "${pptxPath}"`, { stdio: 'pipe' });
155
+ }
156
+ finally {
157
+ try {
158
+ unlinkSync(scriptPath);
159
+ }
160
+ catch { /* ignore */ }
161
+ }
162
+ }
163
+ /**
164
+ * Inject logos into cover slide of a PPTX (matching ref.pptx style)
165
+ * Uses in-place ZIP modification to preserve file structure.
166
+ */
167
+ export async function injectLogosIntoSlides(pptxPath, mediaDir) {
168
+ if (!mediaDir || !existsSync(mediaDir) || !existsSync(pptxPath))
169
+ return;
170
+ // Check for logo files
171
+ const logoLeft = join(mediaDir, 'logo-left.png');
172
+ const logoRight = join(mediaDir, 'logo-right.png');
173
+ const hasLeft = existsSync(logoLeft);
174
+ const hasRight = existsSync(logoRight);
175
+ if (!hasLeft && !hasRight)
176
+ return;
177
+ // Read logo files as base64
178
+ const logoLeftData = hasLeft ? readFileSync(logoLeft).toString('base64') : '';
179
+ const logoRightData = hasRight ? readFileSync(logoRight).toString('base64') : '';
180
+ const scriptPath = join(dirname(pptxPath), '.inject-logos.py');
181
+ const script = `import zipfile, sys, re, os, base64
182
+
183
+ pptx_path = sys.argv[1]
184
+ has_left = ${hasLeft ? 'True' : 'False'}
185
+ has_right = ${hasRight ? 'True' : 'False'}
186
+ logo_left_b64 = """${logoLeftData}"""
187
+ logo_right_b64 = """${logoRightData}"""
188
+
189
+ temp_path = pptx_path + '.tmp'
190
+
191
+ # Find next available image number
192
+ def get_next_image_num(zf):
193
+ max_num = 0
194
+ for name in zf.namelist():
195
+ m = re.match(r'ppt/media/image(\\d+)\\.', name)
196
+ if m:
197
+ max_num = max(max_num, int(m.group(1)))
198
+ return max_num + 1
199
+
200
+ with zipfile.ZipFile(pptx_path, 'r') as zin:
201
+ next_img = get_next_image_num(zin)
202
+ right_img_name = f'ppt/media/image{next_img}.png' if has_right else None
203
+ left_img_name = f'ppt/media/image{next_img + 1}.png' if has_left else None
204
+
205
+ with zipfile.ZipFile(temp_path, 'w') as zout:
206
+ for item in zin.infolist():
207
+ content = zin.read(item.filename)
208
+
209
+ # Update [Content_Types].xml to include png if needed
210
+ if item.filename == '[Content_Types].xml':
211
+ text = content.decode('utf-8')
212
+ if 'Extension="png"' not in text:
213
+ text = text.replace('</Types>', '<Default Extension="png" ContentType="image/png"/></Types>')
214
+ content = text.encode('utf-8')
215
+
216
+ # Update slide1.xml.rels to add image relationships
217
+ if item.filename == 'ppt/slides/_rels/slide1.xml.rels':
218
+ text = content.decode('utf-8')
219
+ # Find max rId
220
+ rids = [int(m) for m in re.findall(r'Id="rId(\\d+)"', text)]
221
+ max_rid = max(rids) if rids else 0
222
+
223
+ new_rels = []
224
+ right_rid = None
225
+ left_rid = None
226
+
227
+ if has_right:
228
+ max_rid += 1
229
+ right_rid = f'rId{max_rid}'
230
+ new_rels.append(f'<Relationship Id="{right_rid}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="../media/image{next_img}.png"/>')
231
+
232
+ if has_left:
233
+ max_rid += 1
234
+ left_rid = f'rId{max_rid}'
235
+ new_rels.append(f'<Relationship Id="{left_rid}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="../media/image{next_img + 1}.png"/>')
236
+
237
+ if new_rels:
238
+ text = text.replace('</Relationships>', ''.join(new_rels) + '</Relationships>')
239
+ content = text.encode('utf-8')
240
+
241
+ # Store rIds for slide1 modification
242
+ zout.right_rid = right_rid
243
+ zout.left_rid = left_rid
244
+
245
+ # Update slide1.xml to add picture elements
246
+ if item.filename == 'ppt/slides/slide1.xml':
247
+ text = content.decode('utf-8')
248
+ # Find max id
249
+ ids = [int(m) for m in re.findall(r'id="(\\d+)"', text)]
250
+ max_id = max(ids) if ids else 0
251
+
252
+ pics = []
253
+ right_rid = getattr(zout, 'right_rid', None)
254
+ left_rid = getattr(zout, 'left_rid', None)
255
+
256
+ if has_right and right_rid:
257
+ max_id += 1
258
+ pics.append(f'<p:pic><p:nvPicPr><p:cNvPr id="{max_id}" name="Picture {max_id}"/><p:cNvPicPr><a:picLocks noChangeAspect="1"/></p:cNvPicPr><p:nvPr/></p:nvPicPr><p:blipFill><a:blip r:embed="{right_rid}"/><a:stretch><a:fillRect/></a:stretch></p:blipFill><p:spPr><a:xfrm><a:off x="9492000" y="5742001"/><a:ext cx="2700000" cy="1115999"/></a:xfrm><a:prstGeom prst="rect"><a:avLst/></a:prstGeom></p:spPr></p:pic>')
259
+
260
+ if has_left and left_rid:
261
+ max_id += 1
262
+ pics.append(f'<p:pic><p:nvPicPr><p:cNvPr id="{max_id}" name="Picture {max_id}"/><p:cNvPicPr><a:picLocks noChangeAspect="1"/></p:cNvPicPr><p:nvPr/></p:nvPicPr><p:blipFill><a:blip r:embed="{left_rid}"/><a:srcRect t="22495" b="27262"/><a:stretch/></p:blipFill><p:spPr><a:xfrm><a:off x="0" y="5904608"/><a:ext cx="3794408" cy="954349"/></a:xfrm><a:prstGeom prst="rect"><a:avLst/></a:prstGeom></p:spPr></p:pic>')
263
+
264
+ if pics:
265
+ text = text.replace('</p:spTree>', ''.join(pics) + '</p:spTree>')
266
+ content = text.encode('utf-8')
267
+
268
+ zout.writestr(item, content)
269
+
270
+ # Add logo image files
271
+ if has_right:
272
+ zout.writestr(right_img_name, base64.b64decode(logo_right_b64))
273
+ if has_left:
274
+ zout.writestr(left_img_name, base64.b64decode(logo_left_b64))
275
+
276
+ os.replace(temp_path, pptx_path)
277
+ `;
278
+ writeFileSync(scriptPath, script);
279
+ try {
280
+ const pythonCmd = process.platform === 'win32' ? 'python' : 'python3';
281
+ execSync(`${pythonCmd} "${scriptPath}" "${pptxPath}"`, { stdio: 'pipe' });
282
+ }
283
+ finally {
284
+ try {
285
+ unlinkSync(scriptPath);
286
+ }
287
+ catch { /* ignore */ }
288
+ }
289
+ }
290
+ // Legacy exports for compatibility
291
+ export async function generatePptxTemplate(options) {
292
+ // No longer modifying template - just return the base template path
293
+ const { baseTemplate, outputPath } = options;
294
+ if (baseTemplate && existsSync(baseTemplate)) {
295
+ // Copy base template to output
296
+ writeFileSync(outputPath, readFileSync(baseTemplate));
297
+ return outputPath;
298
+ }
299
+ return null;
300
+ }
301
+ export function templateNeedsRegeneration(templatePath, mediaDir, baseTemplate) {
302
+ return false; // No template regeneration needed - we use ref.pptx as-is
303
+ }
304
+ export async function injectMediaIntoPptx(pptxPath, mediaDir) {
305
+ // Redirect to the new function
306
+ return injectLogosIntoSlides(pptxPath, mediaDir);
307
+ }
308
+ /**
309
+ * Apply theme fonts to all text in a PPTX
310
+ * Pandoc generates slides with hardcoded fonts; this replaces them with theme font references.
311
+ * Uses in-place ZIP modification to preserve file structure.
312
+ */
313
+ export async function applyThemeFonts(pptxPath, theme) {
314
+ if (!existsSync(pptxPath) || !theme || !theme.fonts)
315
+ return;
316
+ const { major, minor } = theme.fonts;
317
+ if (!major && !minor)
318
+ return;
319
+ const scriptPath = join(dirname(pptxPath), '.apply-fonts.py');
320
+ const script = `import zipfile, sys, re, os
321
+
322
+ pptx_path = sys.argv[1]
323
+ temp_path = pptx_path + '.tmp'
324
+
325
+ # Fonts to replace with theme fonts
326
+ default_fonts = ['Calibri', 'Arial', 'Helvetica', 'Times New Roman', 'Cambria']
327
+
328
+ with zipfile.ZipFile(pptx_path, 'r') as zin:
329
+ with zipfile.ZipFile(temp_path, 'w') as zout:
330
+ for item in zin.infolist():
331
+ content = zin.read(item.filename)
332
+
333
+ # Process slide XML files
334
+ if item.filename.startswith('ppt/slides/slide') and item.filename.endswith('.xml'):
335
+ text = content.decode('utf-8')
336
+
337
+ # Replace common pandoc fonts with theme minor font reference
338
+ for font in default_fonts:
339
+ text = re.sub(rf'(<a:latin\\s+typeface="){font}(")', r'\\1+mn-lt\\2', text)
340
+
341
+ content = text.encode('utf-8')
342
+
343
+ zout.writestr(item, content)
344
+
345
+ os.replace(temp_path, pptx_path)
346
+ `;
347
+ writeFileSync(scriptPath, script);
348
+ try {
349
+ const pythonCmd = process.platform === 'win32' ? 'python' : 'python3';
350
+ execSync(`${pythonCmd} "${scriptPath}" "${pptxPath}"`, { stdio: 'pipe' });
351
+ }
352
+ finally {
353
+ try {
354
+ unlinkSync(scriptPath);
355
+ }
356
+ catch { /* ignore */ }
357
+ }
358
+ }
359
+ /**
360
+ * Apply vertical centering to slides that have the .center class
361
+ * Uses in-place ZIP modification to preserve file structure.
362
+ */
363
+ export async function applyCentering(pptxPath, centeredSlideIndices) {
364
+ if (!existsSync(pptxPath) || !centeredSlideIndices || centeredSlideIndices.length === 0)
365
+ return;
366
+ const scriptPath = join(dirname(pptxPath), '.apply-centering.py');
367
+ const indicesJson = JSON.stringify(centeredSlideIndices);
368
+ const script = `import zipfile, sys, re, os, json
369
+
370
+ pptx_path = sys.argv[1]
371
+ centered_indices = json.loads('${indicesJson}')
372
+ temp_path = pptx_path + '.tmp'
373
+
374
+ # Build set of slide filenames to center
375
+ centered_files = {f'ppt/slides/slide{i}.xml' for i in centered_indices}
376
+
377
+ with zipfile.ZipFile(pptx_path, 'r') as zin:
378
+ with zipfile.ZipFile(temp_path, 'w') as zout:
379
+ for item in zin.infolist():
380
+ content = zin.read(item.filename)
381
+
382
+ # Process centered slides
383
+ if item.filename in centered_files:
384
+ text = content.decode('utf-8')
385
+
386
+ # Process each shape (<p:sp>) separately to skip footer and slide number
387
+ def process_shape(shape_match):
388
+ shape = shape_match.group(0)
389
+ # Skip footer and slide number placeholders
390
+ if 'type="sldNum"' in shape or 'type="ftr"' in shape:
391
+ return shape
392
+
393
+ # Add algn="ctr" to existing <a:pPr> elements
394
+ # Handle both <a:pPr ...> and <a:pPr ... /> (self-closing)
395
+ def add_center_align(match):
396
+ before, attrs, closing = match.groups()
397
+ attrs = attrs.rstrip()
398
+ is_self_closing = '/' in closing
399
+
400
+ if attrs.endswith('/'):
401
+ attrs = attrs[:-1].rstrip()
402
+ is_self_closing = True
403
+
404
+ if 'algn=' not in attrs:
405
+ attrs += ' algn="ctr"'
406
+ else:
407
+ attrs = re.sub(r'algn="[^"]*"', 'algn="ctr"', attrs)
408
+
409
+ return before + attrs + (' />' if is_self_closing else '>')
410
+
411
+ shape = re.sub(r'(<a:pPr)((?:[^/>]|/(?!>))*)(\\s*/?>)', add_center_align, shape)
412
+
413
+ # Add <a:pPr algn="ctr"/> to paragraphs without pPr
414
+ shape = re.sub(r'(<a:p>)(<a:r>)', r'\\1<a:pPr algn="ctr"/>\\2', shape)
415
+
416
+ return shape
417
+
418
+ # Process all shapes
419
+ text = re.sub(r'<p:sp>.*?</p:sp>', process_shape, text, flags=re.DOTALL)
420
+
421
+ content = text.encode('utf-8')
422
+
423
+ zout.writestr(item, content)
424
+
425
+ os.replace(temp_path, pptx_path)
426
+ `;
427
+ writeFileSync(scriptPath, script);
428
+ try {
429
+ const pythonCmd = process.platform === 'win32' ? 'python' : 'python3';
430
+ execSync(`${pythonCmd} "${scriptPath}" "${pptxPath}"`, { stdio: 'pipe' });
431
+ }
432
+ finally {
433
+ try {
434
+ unlinkSync(scriptPath);
435
+ }
436
+ catch { /* ignore */ }
437
+ }
438
+ }
439
+ /**
440
+ * Apply buildup greying to slides with buildup content
441
+ * Greys out all bullet items except the last one, which gets the accent color.
442
+ * Only affects actual bullet items (not intro text with buNone).
443
+ * Uses in-place ZIP modification to preserve file structure.
444
+ */
445
+ export async function applyBuildupColors(pptxPath, config = {}) {
446
+ if (!existsSync(pptxPath))
447
+ return;
448
+ // Check if buildup colors are disabled
449
+ if (config.enabled === false)
450
+ return;
451
+ // Get colors from config with defaults
452
+ const defaultColor = (config.default || '608C32').replace(/^#/, '');
453
+ const titleColor = (config.title || defaultColor).replace(/^#/, '');
454
+ const greyColor = (config.grey || '888888').replace(/^#/, '');
455
+ const accentColor = (config.accent || defaultColor).replace(/^#/, '');
456
+ const scriptPath = join(dirname(pptxPath), '.apply-buildup.py');
457
+ const script = `import zipfile
458
+ import sys
459
+ import re
460
+ import os
461
+
462
+ pptx_path = sys.argv[1]
463
+ temp_path = pptx_path + '.tmp'
464
+
465
+ DEFAULT = '${defaultColor}'
466
+ TITLE = '${titleColor}'
467
+ GREY = '${greyColor}'
468
+ ACCENT = '${accentColor}'
469
+
470
+ def get_bullet_paragraphs(body):
471
+ """Return indices of paragraphs that are actual bullet items (have lvl="0" but NOT buNone)"""
472
+ paras = list(re.finditer(r'<a:p>.*?</a:p>', body, re.DOTALL))
473
+ bullet_indices = []
474
+
475
+ for i, p in enumerate(paras):
476
+ para_text = p.group(0)
477
+ if 'lvl="0"' in para_text and '<a:buNone' not in para_text:
478
+ bullet_indices.append(i)
479
+
480
+ return bullet_indices, paras
481
+
482
+
483
+ def apply_color_to_para(para, color):
484
+ """Apply a color to all text runs in a paragraph"""
485
+ new_para = re.sub(
486
+ r'<a:rPr\\s*/>',
487
+ f'<a:rPr><a:solidFill><a:srgbClr val="{color}"/></a:solidFill></a:rPr>',
488
+ para
489
+ )
490
+
491
+ def fix_rpr_with_attrs(m):
492
+ attrs = m.group(1).strip()
493
+ return f'<a:rPr {attrs}><a:solidFill><a:srgbClr val="{color}"/></a:solidFill></a:rPr>'
494
+
495
+ new_para = re.sub(
496
+ r'<a:rPr\\s+([^>]+?)\\s*/>',
497
+ fix_rpr_with_attrs,
498
+ new_para
499
+ )
500
+
501
+ return new_para
502
+
503
+
504
+ def is_buildup_slide(xml):
505
+ """Check if slide has buildup marker (animEffect with filter=wipe)"""
506
+ # Buildup slides have animation effects from pandoc's incremental lists
507
+ return 'animEffect' in xml or '<a:bldLst>' in xml
508
+
509
+
510
+ def color_content_placeholder(xml):
511
+ """Apply colors to all text in content placeholder.
512
+
513
+ For buildup slides: grey previous bullet items, accent on last bullet item.
514
+ For all text (bullets and non-bullets): apply default color unless overridden by buildup.
515
+ """
516
+
517
+ pattern = r'(<p:sp>.*?<p:ph idx="1"[^/]*/?>.*?<p:txBody>)(.*?)(</p:txBody>.*?</p:sp>)'
518
+ match = re.search(pattern, xml, re.DOTALL)
519
+
520
+ if not match:
521
+ return xml
522
+
523
+ before_body = match.group(1)
524
+ body = match.group(2)
525
+ after_body = match.group(3)
526
+
527
+ bullet_indices, paras = get_bullet_paragraphs(body)
528
+ is_buildup = is_buildup_slide(xml)
529
+
530
+ new_body = body
531
+ offset = 0
532
+
533
+ for i, para_match in enumerate(paras):
534
+ start = para_match.start() + offset
535
+ end = para_match.end() + offset
536
+ para = para_match.group(0)
537
+
538
+ # Determine color for this paragraph
539
+ if i in bullet_indices and is_buildup:
540
+ # Buildup bullet: grey all but last, accent on last
541
+ if i == bullet_indices[-1]:
542
+ color = ACCENT
543
+ else:
544
+ color = GREY
545
+ else:
546
+ # Non-bullet text OR non-buildup slide: use default color
547
+ color = DEFAULT
548
+
549
+ new_para = apply_color_to_para(para, color)
550
+ new_body = new_body[:start] + new_para + new_body[end:]
551
+ offset += len(new_para) - len(para)
552
+
553
+ return xml[:match.start()] + before_body + new_body + after_body + xml[match.end():]
554
+
555
+
556
+ def color_title_placeholder(xml):
557
+ """Apply title color to title placeholder (type='title' or type='ctrTitle')."""
558
+
559
+ # Match title placeholders: type="title" or type="ctrTitle"
560
+ pattern = r'(<p:sp>.*?<p:ph[^>]*type="(?:title|ctrTitle)"[^/]*/?>.*?<p:txBody>)(.*?)(</p:txBody>.*?</p:sp>)'
561
+ match = re.search(pattern, xml, re.DOTALL)
562
+
563
+ if not match:
564
+ return xml
565
+
566
+ before_body = match.group(1)
567
+ body = match.group(2)
568
+ after_body = match.group(3)
569
+
570
+ paras = list(re.finditer(r'<a:p>.*?</a:p>', body, re.DOTALL))
571
+
572
+ new_body = body
573
+ offset = 0
574
+
575
+ for para_match in paras:
576
+ start = para_match.start() + offset
577
+ end = para_match.end() + offset
578
+ para = para_match.group(0)
579
+
580
+ new_para = apply_color_to_para(para, TITLE)
581
+ new_body = new_body[:start] + new_para + new_body[end:]
582
+ offset += len(new_para) - len(para)
583
+
584
+ return xml[:match.start()] + before_body + new_body + after_body + xml[match.end():]
585
+
586
+ with zipfile.ZipFile(pptx_path, 'r') as zin:
587
+ with zipfile.ZipFile(temp_path, 'w') as zout:
588
+ for item in zin.infolist():
589
+ content = zin.read(item.filename)
590
+
591
+ if item.filename.startswith('ppt/slides/slide') and item.filename.endswith('.xml'):
592
+ text = content.decode('utf-8')
593
+ text = color_content_placeholder(text)
594
+ text = color_title_placeholder(text)
595
+ content = text.encode('utf-8')
596
+
597
+ zout.writestr(item, content)
598
+
599
+ os.replace(temp_path, pptx_path)
600
+ `;
601
+ writeFileSync(scriptPath, script);
602
+ try {
603
+ const pythonCmd = process.platform === 'win32' ? 'python' : 'python3';
604
+ execSync(`${pythonCmd} "${scriptPath}" "${pptxPath}"`, { stdio: 'pipe' });
605
+ }
606
+ finally {
607
+ try {
608
+ unlinkSync(scriptPath);
609
+ }
610
+ catch { /* ignore */ }
611
+ }
612
+ }
613
+ //# sourceMappingURL=pptx-template.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pptx-template.js","sourceRoot":"","sources":["../../lib/pptx-template.ts"],"names":[],"mappings":"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"}