node-pptx-templater 1.0.5 → 1.0.6

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.
package/README.md CHANGED
@@ -1,38 +1,44 @@
1
- # node-pptx-templater
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/jsuyog2/node-pptx-templater/main/docs/logo.svg" alt="PPTXForge Logo" width="550" max-width="100%">
3
+ </p>
2
4
 
3
- > High-performance, low-level PowerPoint (PPTX) OpenXML template engine for Node.js. Dynamically replace text, insert images, update charts (with Excel workbook data caching), and merge table cells without PowerPoint corruption or Repair Mode prompts.
5
+ <h1 align="center">node-pptx-templater (PPTXForge Engine)</h1>
4
6
 
5
- [![npm version](https://img.shields.io/npm/v/node-pptx-templater.svg?style=flat-square&color=blue)](https://www.npmjs.com/package/node-pptx-templater)
6
- [![CI Build Status](https://img.shields.io/github/actions/workflow/status/jsuyog2/node-pptx-templater/ci.yml?branch=main&style=flat-square)](https://github.com/jsuyog2/node-pptx-templater/actions/workflows/ci.yml)
7
- [![Bundle Size](https://img.shields.io/bundlephobia/min/node-pptx-templater?style=flat-square&color=brightgreen)](https://bundlephobia.com/package/node-pptx-templater)
8
- [![Downloads](https://img.shields.io/npm/dm/node-pptx-templater.svg?style=flat-square&color=orange)](https://www.npmjs.com/package/node-pptx-templater)
9
- [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg?style=flat-square)](./LICENSE)
10
- [![Node.js Version](https://img.shields.io/badge/node-%3E%3D18.0.0-brightgreen?style=flat-square)](https://nodejs.org)
7
+ <p align="center">
8
+ <strong>The High-Performance, Secure OpenXML PowerPoint Template Engine for Node.js</strong>
9
+ </p>
10
+
11
+ <p align="center">
12
+ <a href="https://www.npmjs.com/package/node-pptx-templater"><img src="https://img.shields.io/npm/v/node-pptx-templater.svg?style=flat-square&color=6366f1" alt="npm version"></a>
13
+ <a href="https://github.com/jsuyog2/node-pptx-templater/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/jsuyog2/node-pptx-templater/ci.yml?branch=main&style=flat-square&color=34d399" alt="CI Build Status"></a>
14
+ <a href="https://bundlephobia.com/package/node-pptx-templater"><img src="https://img.shields.io/bundlephobia/min/node-pptx-templater?style=flat-square&color=ec4899" alt="Bundle Size"></a>
15
+ <a href="https://www.npmjs.com/package/node-pptx-templater"><img src="https://img.shields.io/npm/dm/node-pptx-templater.svg?style=flat-square&color=a855f7" alt="Downloads"></a>
16
+ <a href="./LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square" alt="License: MIT"></a>
17
+ <a href="https://nodejs.org"><img src="https://img.shields.io/badge/node-%3E%3D18.0.0-brightgreen?style=flat-square" alt="Node.js Version"></a>
18
+ </p>
11
19
 
12
20
  ---
13
21
 
14
- ## ⚡ Why node-pptx-templater?
22
+ ## ⚡ Why PPTXForge (`node-pptx-templater`)?
15
23
 
16
- Traditional PowerPoint generation libraries require building slides from scratch in code, which is verbose, hard to maintain, and strips away the power of visual design tools.
24
+ Traditional slide deck automation requires assembling slides shape-by-shape in verbose code blocks. This is fragile, difficult to maintain, and strips away the power of visual design tools like Microsoft PowerPoint, Keynote, or Google Slides.
17
25
 
18
- `node-pptx-templater` takes a different approach: **Design visually in PowerPoint, populate dynamically in Node.js.**
26
+ **PPTXForge takes a visual-first approach: Design visually in PowerPoint, populate dynamically in Node.js.**
19
27
 
20
- You create slide decks using PowerPoint, Google Slides, or Keynote, set your formatting, themes, animations, and layouts, and place placeholders like `{{company}}` or `{{revenue-chart}}`. `node-pptx-templater` parses the template and updates text, injects images, replaces chart values (updating both Excel workbook data caches and XML shapes), and merges tables dynamically while keeping the presentation 100% compliant with standard OpenXML guidelines.
28
+ You design your layouts, tables, fonts, brand styles, charts, and animations inside PowerPoint, and insert placeholders like `{{customer_name}}`, `{{revenue_chart}}`, or `{{team_table}}`. The PPTXForge engine parses the OpenXML presentation, heals broken text run segmentations, updates Excel data workbook caches, merges drawing cells, and scales slides securely in pure JavaScript with zero external office dependencies.
21
29
 
22
30
  ---
23
31
 
24
- ## ✨ Features
32
+ ## ✨ Enterprise-Grade Core Features
25
33
 
26
- - 🏗️ **Zero Native Office/Java Dependencies**: Runs on pure Javascript/Node.js, making it ideal for high-throughput cloud environments, Lambda, or serverless runtimes.
27
- - 🔁 **Fragmented Placeholder Resolution**: PowerPoint often splits text runs like `{{company}}` into `<a:r>` nodes. Our engine merges and resolves fragmented tags automatically.
28
- - 📊 **Full Chart Engine Integration**: Supports Bar, Column, Line, Pie, Doughnut, Area, Scatter, and Bubble charts. Automatically synchronizes chart XML properties and coordinates with the embedded Excel sheets (`ppt/embeddings/`).
29
- - 📋 **Flexible Table Merging & Templating**:
30
- - Horizontal column merge (`gridSpan` & `hMerge`), vertical row merge (`rowSpan` & `vMerge`), and rectangular block merges.
31
- - Formats cells dynamically with inline options (`align`, `fontSize`, `fill`).
32
- - Automatically handles slide table duplicates by generating unique `<a16:rowId>` 32-bit hashes to **prevent PowerPoint Repair Mode** screens.
33
- - 🎨 **Shape & Image Manipulation**: Find shapes, clone layout blocks with offsets, replace image sources while keeping exact positions, or delete elements.
34
- - 🎯 **Slide Management Operations**: Duplicate, reorder, delete, and import slides from external templates with automatic media asset deduplication.
35
- - 🔍 **Deep Packaging Integrity Validation**: Real-time checking of relationships, XML schemas, table column numbers, and override duplicates.
34
+ * 🚀 **Zero Native/Office/Java Dependencies**: Pure CommonJS JavaScript implementation. Runs efficiently on AWS Lambda, Vercel Edge, Netlify, and Cloudflare Workers.
35
+ * 🛡️ **Hardened XML Security**: Fully immune to Billion Laughs (XML bombs), XXE (XML External Entity Injection), and parser crashes due to oversized expansions.
36
+ * 🧩 **Text Run Fragmentation Healing**: Solves the split-tag issue. PowerPoint splits `{{placeholders}}` into fragmented `<a:r>` nodes; our parser unifies and replaces them while keeping original formatting intact.
37
+ * 📊 **Excel Cache Synchronized Charting**: Supports Bar, Line, Pie, Doughnut, Area, and Scatter charts. Not only updates the visual XML coordinates but also synchronizes data points inside the underlying embedded Excel spreadsheets (`ppt/embeddings/`) to bypass PowerPoint's "Update Data" warnings.
38
+ * 📋 **DrawingML Table Cell Merging**: Easily configure horizontal spans (`gridSpan`/`hMerge`), vertical spans (`rowSpan`/`vMerge`), and rectangular blocks. Injects unique `rowId` hashes to maintain relationship integrity.
39
+ * 🥞 **Z-Order Layer Stacking**: Reorder shapes, images, charts, and tables programmatically. Simulates PowerPoint's "Bring to Front" and "Send to Back" commands directly in the slide's `<p:spTree>`.
40
+ * 🎛️ **Slide Management**: Duplicate, delete, reorder slides, or import slides from external decks with automatic media and theme deduplication.
41
+ * 🔍 **OPC Package Verification**: Comprehensive check suite for content type overrides, relationship integrity, and XML structure before final output.
36
42
 
37
43
  ---
38
44
 
@@ -44,317 +50,1260 @@ npm install node-pptx-templater
44
50
 
45
51
  ---
46
52
 
47
- ## 🚀 Quick Start
53
+ ## 🚀 Quick Start Guide
48
54
 
49
- Get up and running in under 60 seconds with this simple template rendering example:
55
+ Generate a formatted presentation report from a visually designed template in under 60 seconds:
50
56
 
51
- ```js
57
+ ```javascript
52
58
  const { PPTXTemplater } = require('node-pptx-templater');
53
59
 
54
- async function main() {
55
- // 1. Load your PowerPoint presentation template
60
+ async function generateReport() {
61
+ // 1. Load the presentation template
56
62
  const ppt = await PPTXTemplater.load('monthly_report_template.pptx');
57
63
 
58
- // 2. Select slide 1 and execute operations
64
+ // 2. Select slide 1 and execute standard text replacements
59
65
  ppt.useSlide(1)
60
- .replaceTextByTag('title', 'Quarterly Earnings Report')
66
+ .replaceTextByTag('title', 'Q2 Business Overview')
61
67
  .replaceMultiple({
62
- company: 'Acme Corporation',
63
- year: '2026'
68
+ client: 'Acme Corporation',
69
+ analyst: 'Sarah Jenkins',
70
+ date: 'June 2026'
64
71
  });
65
72
 
66
- // 3. Update chart series data on Slide 2
73
+ // 3. Update Excel-backed chart data on Slide 2
67
74
  ppt.useSlide(2)
68
- .updateChartData('sales-chart', {
69
- categories: ['Q1', 'Q2', 'Q3', 'Q4'],
75
+ .updateChartData('revenue-chart', {
76
+ categories: ['April', 'May', 'June'],
70
77
  series: [
71
- { name: 'Target', values: [100, 120, 140, 160] },
72
- { name: 'Revenue', values: [105, 118, 145, 172] }
78
+ { name: 'Target', values: [120000, 150000, 180000] },
79
+ { name: 'Actual', values: [125000, 162000, 195000] }
73
80
  ]
74
81
  });
75
82
 
76
- // 4. Update table with cell merging and formatting on Slide 3
83
+ // 4. Update table structure with cell merges and colors on Slide 3
77
84
  ppt.useSlide(3)
78
- .updateTable('sales-table', [
79
- ['Region', 'Q1 Actual', 'Q2 Actual', 'Status'],
80
- ['North', '120k', '140k', { value: 'On Track', align: 'ctr', fill: '10b981' }],
81
- ['South', '95k', '110k', { value: 'Review', align: 'ctr', fill: 'f59e0b' }]
85
+ .updateTable('performance-table', [
86
+ ['Region', 'Growth Metric', { value: 'Status / Notes', colSpan: 2 }],
87
+ ['North Region', '+12.4%', { value: 'Exceeded Target', align: 'ctr', fill: '10b981' }, ''],
88
+ ['South Region', '-3.1%', { value: 'Under Review', align: 'ctr', fill: 'f59e0b' }, '']
82
89
  ]);
83
90
 
84
- // 5. Save the non-corrupted PPTX back to disk
85
- await ppt.saveToFile('./output/annual_earnings.pptx');
91
+ // 5. Duplicate a layout and bring an overlay element to the front
92
+ ppt.duplicateSlide(3, 4);
93
+ ppt.useSlide(4)
94
+ .bringToFront('OverlayLogo')
95
+ .replaceTextByTag('title', 'Duplicate Region Report');
96
+
97
+ // 6. Save package without PowerPoint Repair Warnings
98
+ await ppt.saveToFile('./output/q2_business_report.pptx');
99
+ console.log('Report generated successfully!');
86
100
  }
87
101
 
88
- main().catch(err => console.error(err));
102
+ generateReport().catch(console.error);
89
103
  ```
90
104
 
91
105
  ---
92
106
 
93
- ## 🏗️ OpenXML Architecture & Internals
94
-
95
- A `.pptx` file is an OPC (Open Packaging Convention) ZIP archive containing structured XML documents and asset folders:
107
+ ## 📋 OpenXML Presentation Architecture
108
+
109
+ A `.pptx` file is an Open Packaging Convention (OPC) ZIP package containing structured XML schemas:
110
+
111
+ ```text
112
+ PPTX Archive Structure:
113
+ ├── [Content_Types].xml # MIME type registry for all zip contents
114
+ ├── _rels/
115
+ │ └── .rels # Package-level relationship mappings
116
+ └── ppt/
117
+ ├── presentation.xml # Global presentation slide order and layouts
118
+ ├── slides/
119
+ │ ├── slide1.xml # DrawingML elements, text runs, and shapes
120
+ │ └── _rels/
121
+ │ └── slide1.xml.rels # Resource mappings (images, charts, tables)
122
+ ├── media/ # Image and SVG database
123
+ └── embeddings/ # Embedded Excel books backing charts
124
+ ```
96
125
 
97
- - `[Content_Types].xml` Global manifest declaring content MIME types for every file part in the ZIP.
98
- - `_rels/.rels` Root-level package relationship index.
99
- - `ppt/presentation.xml` – Root presentation settings and slide inventory (`sldIdLst`).
100
- - `ppt/slides/slideN.xml` Main slide canvas storing shapes, lines, tables, text runs, and layout components.
101
- - `ppt/slides/_rels/slideN.xml.rels` – Relationship indexes mapping slide XML components to charts, layouts, and image assets.
126
+ ### Unifying Text Run Segmentations
127
+ Under the hood, slide template text is represented as runs of text (`<a:r>`). PowerPoint's parser often breaks a single tag `{{name}}` into separate segments:
128
+ ```xml
129
+ <!-- Split layout generated by PowerPoint -->
130
+ <a:r><a:t>{{n</a:t></a:r>
131
+ <a:r><a:t>ame}}</a:t></a:r>
132
+ ```
133
+ PPTXForge parses the XML structure, identifies layout boundaries, merges text nodes back into a single element, and applies replacements while preserving font sizes, colors, and styling rules.
102
134
 
103
- ### Preventing PowerPoint Table Repair Errors
104
- PowerPoint slide tables utilize unique 32-bit identifiers inside `<a16:rowId>` nodes for collaborative edits. Duplicating rows using naive array copy operations results in overlapping IDs, triggering Microsoft PowerPoint's **"PowerPoint found a problem with content"** repair screen on open.
105
- `node-pptx-templater` intercepts all table operations (adding, cloning, inserting, or merging rows) and dynamically injects newly generated unique `rowId` hashes, ensuring a seamless, warning-free loading experience in:
106
- - Microsoft PowerPoint (Desktop, Mac, Online)
107
- - Google Slides
108
- - LibreOffice Impress
135
+ ### Preventing PPTX "Repair Presentation" Warnings
136
+ Naively duplicating rows in slide tables can leave duplicate `rowId` values or break cell mappings, causing PowerPoint to crash or prompt a repair screen. PPTXForge automatically re-allocates unique `rowId` hashes and formats `gridSpan` / `rowSpan` coordinates in compliance with standard Office OpenXML (OOXML) regulations.
109
137
 
110
138
  ---
111
139
 
112
140
  ## 📊 Feature Comparison Matrix
113
141
 
114
- | Feature / Library | `node-pptx-templater` | `pptxgenjs` | `pptx-template` | `pptx-automizer` | `officegen` |
115
- |:---|:---:|:---:|:---:|:---:|:---:|
116
- | **Approach** | **Template-based** | Code-based | Template-based | Template-based | Code-based |
117
- | **No PPTX Corruption / Repair Warnings** | **Yes** (Automatic Metadata Sync) | Yes | No (Fragile row duplication) | Yes | Yes (Limited layouts) |
118
- | **Text Run Fragmentation Resolution** | **Yes** (Dynamic merging) | N/A | No (Placeholder breaks) | Yes | N/A |
119
- | **Chart Data Workbook Sync** | **Yes** (Direct excel caching) | Yes | No (Only raw XML text) | Yes | Yes |
120
- | **Horizontal & Vertical Cell Merge** | **Yes** (gridSpan, rowSpan, hMerge, vMerge) | Yes | No | No | No |
121
- | **Slide Duplication & Reordering** | **Yes** | No | No | Yes | No |
122
- | **External Slide Imports** | **Yes** (With asset deduplication) | No | No | Yes | No |
123
- | **Dependencies** | **Zero Native Dependencies** | Zero | Zero | Zero | Node-zip, xmlbuilder |
142
+ Compare PPTXForge with other popular PowerPoint automation libraries:
124
143
 
125
- ---
144
+ | Feature / Metric | **node-pptx-templater** (PPTXForge) | **pptxgenjs** | **pptx-template** | **pptx-automizer** | **officegen** |
145
+ | :--- | :---: | :---: | :---: | :---: | :---: |
146
+ | **Automation Flow** | **Template-based** | Code-based | Template-based | Template-based | Code-based |
147
+ | **No Office/Java Dependency** | **Yes** (Pure JS) | Yes | Yes | Yes | Yes |
148
+ | **Bypass Corruption/Repair Alerts** | **Yes** (RowId sync) | Yes | No (Row duplicate breaks) | Yes | Yes |
149
+ | **Heal Text Run Fragmentation** | **Yes** | N/A | No (Tags break) | Yes | N/A |
150
+ | **Synchronized Excel Chart Updates** | **Yes** (Direct sync) | Yes | No (Text updates only) | Yes | Yes |
151
+ | **Horizontal & Vertical Cell Merge** | **Yes** (gridSpan/rowSpan) | Yes | No | No | No |
152
+ | **Z-Order Layer Reordering** | **Yes** (Front/Back) | No | No | Yes | No |
153
+ | **External Slide Imports** | **Yes** (Deduplicated) | No | No | Yes | No |
154
+
155
+ <!-- API_REFERENCE_START -->
156
+
157
+ ### Tables API
158
+
159
+ #### `updateTable(tableId, rows)`
160
+ Replaces table rows with new data in the selected slide(s). Preserves borders, merged cells, fonts, colors, and alignment from the template.
161
+
162
+ * **Arguments**:
163
+ * `tableId` (`string`): Table name or shape ID.
164
+ * `rows` (`string[][]`): 2D array of cell values (row × col).
165
+ * **Returns**: `PPTXTemplater` - this (chainable)
166
+
167
+ ```javascript
168
+ ppt.useSlide(1).updateTable('summary-table', [
169
+ ['Item', 'Value'],
170
+ ['Widgets', '1,200'],
171
+ ['Gadgets', '850']
172
+ ]);
173
+ ```
174
+
175
+ #### `addTableRow(())`
176
+ Delegates core actions to slide element sub-managers.
126
177
 
127
- ## 📚 API Reference
178
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
128
179
 
129
- ### Slide Operations
180
+ ```javascript
181
+ ppt.useSlide(1).addTableRow('data-table', ['John Doe', 'Sales Manager', '$120k']);
182
+ ```
183
+
184
+ #### `removeTableRow(())`
185
+ Delegates core actions to slide element sub-managers.
186
+
187
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
188
+
189
+ ```javascript
190
+ ppt.useSlide(1).removeTableRow('data-table', 2);
191
+ ```
192
+
193
+ #### `insertTableRow(())`
194
+ Delegates core actions to slide element sub-managers.
195
+
196
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
130
197
 
131
- #### `duplicateSlide(slideIndex, atPosition)`
132
- Duplicates a slide.
133
- ```js
134
- ppt.duplicateSlide(1, 2); // Duplicate Slide 1 and insert it at position 2
198
+ ```javascript
199
+ ppt.useSlide(1).insertTableRow(());
135
200
  ```
136
201
 
137
- #### `deleteSlide(slideIndex)`
138
- Deletes a slide from the deck.
139
- ```js
140
- ppt.deleteSlide(3); // Delete Slide 3
202
+ #### `cloneTableRow(())`
203
+ Delegates core actions to slide element sub-managers.
204
+
205
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
206
+
207
+ ```javascript
208
+ ppt.useSlide(1).cloneTableRow(());
141
209
  ```
142
210
 
143
- #### `moveSlide(fromIndex, toIndex)`
144
- Moves a slide to a new position.
145
- ```js
146
- ppt.moveSlide(1, 3); // Move Slide 1 to position 3
211
+ #### `updateCell(())`
212
+ Delegates core actions to slide element sub-managers.
213
+
214
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
215
+
216
+ ```javascript
217
+ ppt.useSlide(1).updateCell(());
147
218
  ```
148
219
 
149
- #### `importSlideFrom(sourcePresentation, sourceSlideIndex)`
150
- Deep-copies a slide from another loaded presentation, automatically remapping layouts, shapes, charts, and deduplicating media assets.
151
- ```js
152
- const source = await PPTXTemplater.load('marketing_slides.pptx');
153
- await ppt.importSlideFrom(source, 2); // Import Slide 2 of marketing deck
220
+ #### `mergeCells(())`
221
+ Delegates core actions to slide element sub-managers.
222
+
223
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
224
+
225
+ ```javascript
226
+ ppt.useSlide(1).mergeCells('metrics-table', 1, 1, 2, 2);
227
+ ```
228
+
229
+ #### `unmergeCells(())`
230
+ Delegates core actions to slide element sub-managers.
231
+
232
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
233
+
234
+ ```javascript
235
+ ppt.useSlide(1).unmergeCells('metrics-table', 1, 1, 2, 2);
236
+ ```
237
+
238
+ #### `getMergedCells(())`
239
+ Delegates core actions to slide element sub-managers.
240
+
241
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
242
+
243
+ ```javascript
244
+ ppt.useSlide(1).getMergedCells(());
245
+ ```
246
+
247
+ #### `validateMergeRegion(())`
248
+ Delegates core actions to slide element sub-managers.
249
+
250
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
251
+
252
+ ```javascript
253
+ ppt.useSlide(1).validateMergeRegion(());
254
+ ```
255
+
256
+ #### `isMergedCell(())`
257
+ Delegates core actions to slide element sub-managers.
258
+
259
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
260
+
261
+ ```javascript
262
+ ppt.useSlide(1).isMergedCell(());
263
+ ```
264
+
265
+ #### `getMergeParent(())`
266
+ Delegates core actions to slide element sub-managers.
267
+
268
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
269
+
270
+ ```javascript
271
+ ppt.useSlide(1).getMergeParent(());
272
+ ```
273
+
274
+ #### `getMergeRegion(())`
275
+ Delegates core actions to slide element sub-managers.
276
+
277
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
278
+
279
+ ```javascript
280
+ ppt.useSlide(1).getMergeRegion(());
281
+ ```
282
+
283
+ #### `splitMergedRegion(())`
284
+ Delegates core actions to slide element sub-managers.
285
+
286
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
287
+
288
+ ```javascript
289
+ ppt.useSlide(1).splitMergedRegion(());
290
+ ```
291
+
292
+ #### `cloneMergedRegion(())`
293
+ Delegates core actions to slide element sub-managers.
294
+
295
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
296
+
297
+ ```javascript
298
+ ppt.useSlide(1).cloneMergedRegion(());
299
+ ```
300
+
301
+ #### `autoFitTable(())`
302
+ Delegates core actions to slide element sub-managers.
303
+
304
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
305
+
306
+ ```javascript
307
+ ppt.useSlide(1).autoFitTable(());
308
+ ```
309
+
310
+ #### `resizeTable(())`
311
+ Delegates core actions to slide element sub-managers.
312
+
313
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
314
+
315
+ ```javascript
316
+ ppt.useSlide(1).resizeTable(());
317
+ ```
318
+
319
+ #### `getTables(())`
320
+ Delegates core actions to slide element sub-managers.
321
+
322
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
323
+
324
+ ```javascript
325
+ ppt.useSlide(1).getTables(());
154
326
  ```
155
327
 
156
328
  ---
157
329
 
158
- ### Table Manipulation
330
+ ### Charts API
159
331
 
160
- #### `updateTable(tableId, data)`
161
- Updates a table with rows data, merge rules, and cell styles.
162
- ```js
163
- ppt.updateTable('revenue-table', [
164
- ['Year', 'Revenue', 'Profit'],
165
- ['2025', '120k', '40k'],
166
- ['2026', '150k', { value: '60k', fill: '10b981', align: 'ctr' }]
167
- ]);
332
+ #### `updateChart(chartId, data)`
333
+ Updates chart data in the selected slide(s). Finds charts by their name/ID and updates categories, series, and values. Preserves original chart styles, themes, and formatting.
334
+
335
+ * **Arguments**:
336
+ * `chartId` (`string`): Chart name or relationship ID.
337
+ * `data` (`ChartData`): New chart data.
338
+ * `data.categories` (`string[]`): Category labels (X-axis).
339
+ * `data.series` (`SeriesData[]`): Data series array.
340
+ * `data.series[].name` (`string`): Series name.
341
+ * `data.series[].values` (`number[]`): Data values.
342
+ * **Returns**: `PPTXTemplater` - this (chainable)
343
+
344
+ ```javascript
345
+ ppt.useSlide(1).updateChart(chartId, data);
168
346
  ```
169
347
 
170
- #### `mergeCells(options)`
171
- Merges a rectangular block of cells. Supports horizontal, vertical, and block merging, concatenating all text from the merged region into the top-left cell.
172
- ```js
173
- ppt.mergeCells({
174
- tableId: 'sales-table',
175
- startRow: 1,
176
- startCol: 1,
177
- endRow: 2,
178
- endCol: 2
179
- });
348
+ #### `validateCharts()`
349
+ Validates all charts in the presentation to ensure they are not corrupted. Checks XML, caches, and embedded workbook references.
350
+
351
+ * **Returns**: `Promise<Object>` - Validation results for charts.
352
+
353
+ ```javascript
354
+ ppt.useSlide(1).validateCharts();
355
+ ```
356
+
357
+ #### `repairCharts()`
358
+ Repairs common chart corruption issues such as broken caches, missing embedded workbooks, or orphan nodes.
359
+
360
+ * **Returns**: `Promise<PPTXTemplater>` - this
361
+
362
+ ```javascript
363
+ ppt.useSlide(1).repairCharts();
180
364
  ```
181
365
 
182
- #### `unmergeCells(options)`
183
- Splits a merged region back to its original individual cells, removing `gridSpan`, `rowSpan`, `hMerge`, and `vMerge` attributes.
184
- ```js
185
- ppt.unmergeCells({
186
- tableId: 'sales-table',
187
- row: 1,
188
- col: 1
366
+ #### `updateChartData(())`
367
+ Delegates core actions to slide element sub-managers.
368
+
369
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
370
+
371
+ ```javascript
372
+ ppt.useSlide(1).updateChartData('sales-chart', {
373
+ categories: ['Q1', 'Q2'],
374
+ series: [{ name: 'Actual', values: [100, 150] }]
189
375
  });
190
376
  ```
191
377
 
378
+ #### `replaceChartSeries(())`
379
+ Delegates core actions to slide element sub-managers.
380
+
381
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
382
+
383
+ ```javascript
384
+ ppt.useSlide(1).replaceChartSeries(());
385
+ ```
386
+
387
+ #### `updateChartTitle(())`
388
+ Delegates core actions to slide element sub-managers.
389
+
390
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
391
+
392
+ ```javascript
393
+ ppt.useSlide(1).updateChartTitle('sales-chart', 'Quarterly Metrics Overview');
394
+ ```
395
+
396
+ #### `updateChartCategories(())`
397
+ Delegates core actions to slide element sub-managers.
398
+
399
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
400
+
401
+ ```javascript
402
+ ppt.useSlide(1).updateChartCategories(());
403
+ ```
404
+
405
+ #### `getCharts(())`
406
+ Delegates core actions to slide element sub-managers.
407
+
408
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
409
+
410
+ ```javascript
411
+ ppt.useSlide(1).getCharts(());
412
+ ```
413
+
192
414
  ---
193
415
 
194
- ### Chart Integration
416
+ ### Slides API
195
417
 
196
- #### `updateChartData(chartId, data)`
197
- Overwrites chart categories and series values. Updates the embedded Excel spreadsheet to ensure the chart matches perfectly on refresh.
198
- ```js
199
- ppt.updateChartData('sales-chart', {
200
- categories: ['Q1', 'Q2', 'Q3', 'Q4'],
201
- series: [
202
- { name: 'Revenue', values: [100, 150, 180, 220] }
203
- ]
204
- });
418
+ #### `useSlide(...slideRefs)`
419
+ Selects one or more slides to work on. All subsequent operations (replaceText, updateChart, etc.) apply to these slides. If not called, operations apply to ALL slides.
420
+
421
+ * **Arguments**:
422
+ * `slideRefs` (`...number|string`): Slide numbers (1-based), IDs, or tags.
423
+ * **Returns**: `PPTXTemplater` - this (chainable)
424
+
425
+ ```javascript
426
+ ppt.useSlide(1).useSlide(...slideRefs);
427
+ ```
428
+
429
+ #### `useAllSlides()`
430
+ Selects all slides.
431
+
432
+ * **Returns**: `PPTXTemplater` - this (chainable)
433
+
434
+ ```javascript
435
+ ppt.useSlide(1).useAllSlides();
436
+ ```
437
+
438
+ #### `addSlide(options = {})`
439
+ Adds a new slide to the presentation. Automatically generates required XML and relationship entries.
440
+
441
+ * **Arguments**:
442
+ * `options` (`NewSlideOptions`): Slide definition.
443
+ * `[options.title]` (`string`): Slide title text.
444
+ * `[options.layout]` (`string`): Layout name to use (default: 'blank').
445
+ * `[options.elements]` (`SlideElement[]`): Elements to add to the slide.
446
+ * **Returns**: `PPTXTemplater` - this (chainable)
447
+
448
+ ```javascript
449
+ ppt.useSlide(1).addSlide(options = {});
450
+ ```
451
+
452
+ #### `cloneSlide(sourceSlideNumber, atPosition)`
453
+ Clones an existing slide and appends it to the end (or at a position).
454
+
455
+ * **Arguments**:
456
+ * `sourceSlideNumber` (`number`): 1-based source slide number.
457
+ * `[atPosition]` (`number`): Optional position to insert (1-based). Default: append.
458
+ * **Returns**: `PPTXTemplater` - this (chainable)
459
+
460
+ ```javascript
461
+ ppt.useSlide(1).cloneSlide(sourceSlideNumber, atPosition);
462
+ ```
463
+
464
+ #### `removeSlide(slideNumber)`
465
+ Removes a slide from the presentation.
466
+
467
+ * **Arguments**:
468
+ * `slideNumber` (`number`): 1-based slide number to remove.
469
+ * **Returns**: `PPTXTemplater` - this (chainable)
470
+
471
+ ```javascript
472
+ ppt.useSlide(1).removeSlide(slideNumber);
473
+ ```
474
+
475
+ #### `reorderSlides(order)`
476
+ Reorders slides in the presentation.
477
+
478
+ * **Arguments**:
479
+ * `order` (`number[]`): Array of 1-based slide numbers in desired order.
480
+ * **Returns**: `PPTXTemplater` - this (chainable)
481
+
482
+ ```javascript
483
+ ppt.useSlide(1).reorderSlides(order);
484
+ ```
485
+
486
+ #### `tagSlide(slideNumber, tag)`
487
+ Tags a slide with a custom string identifier for later selection.
488
+
489
+ * **Arguments**:
490
+ * `slideNumber` (`number`): 1-based slide number.
491
+ * `tag` (`string`): Custom tag string.
492
+ * **Returns**: `PPTXTemplater` - this (chainable)
493
+
494
+ ```javascript
495
+ ppt.useSlide(1).tagSlide(slideNumber, tag);
496
+ ```
497
+
498
+ #### `exportSlides(...slideNumbers)`
499
+ Exports selected slides to a new standalone PPTX engine. Useful for creating "slide decks" from a master template.
500
+
501
+ * **Arguments**:
502
+ * `slideNumbers` (`...number`): 1-based slide numbers to export.
503
+ * **Returns**: `Promise<PPTXTemplater>` - New engine with only the selected slides.
504
+
505
+ ```javascript
506
+ ppt.useSlide(1).exportSlides(...slideNumbers);
205
507
  ```
206
508
 
207
- #### `updateChartTitle(chartId, title)`
208
- ```js
209
- ppt.updateChartTitle('sales-chart', 'Revenue Growth (2026)');
509
+ #### `importSlideFrom(sourceEngine, slideRef)`
510
+ Imports a single slide from another PPTXTemplater instance into this presentation. Preserves all slide layouts, charts, relationships, and embedded media.
511
+
512
+ * **Arguments**:
513
+ * `sourceEngine` (`PPTXTemplater`): Source PPTXTemplater instance.
514
+ * `slideRef` (`number|string`): Slide index (1-based), ID, or custom tag.
515
+ * **Returns**: `Promise<PPTXTemplater>` - this (chainable)
516
+
517
+ ```javascript
518
+ const source = await PPTXTemplater.load('template2.pptx');
519
+ await ppt.importSlideFrom(source, 1);
520
+ ```
521
+
522
+ #### `importSlides(slideIndices)`
523
+ Imports selected slides from the current template, discarding the rest. The remaining slides are reordered to match the provided array. Preserves all layouts, themes, relationships, and embedded media.
524
+
525
+ * **Arguments**:
526
+ * `slideIndices` (`number[]`): Array of 1-based slide indices to keep.
527
+ * **Returns**: `PPTXTemplater` - this (chainable)
528
+
529
+ ```javascript
530
+ ppt.useSlide(1).importSlides(slideIndices);
531
+ ```
532
+
533
+ #### `duplicateSlide(())`
534
+ Delegates core actions to slide element sub-managers.
535
+
536
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
537
+
538
+ ```javascript
539
+ ppt.duplicateSlide(1, 2);
540
+ ```
541
+
542
+ #### `deleteSlide(())`
543
+ Delegates core actions to slide element sub-managers.
544
+
545
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
546
+
547
+ ```javascript
548
+ ppt.useSlide(1).deleteSlide(());
549
+ ```
550
+
551
+ #### `moveSlide(())`
552
+ Delegates core actions to slide element sub-managers.
553
+
554
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
555
+
556
+ ```javascript
557
+ ppt.useSlide(1).moveSlide(());
558
+ ```
559
+
560
+ #### `insertSlide(())`
561
+ Delegates core actions to slide element sub-managers.
562
+
563
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
564
+
565
+ ```javascript
566
+ ppt.useSlide(1).insertSlide(());
567
+ ```
568
+
569
+ #### `getSlides(())`
570
+ Delegates core actions to slide element sub-managers.
571
+
572
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
573
+
574
+ ```javascript
575
+ ppt.useSlide(1).getSlides(());
210
576
  ```
211
577
 
212
578
  ---
213
579
 
214
- ### Z-Order (Layer Management)
580
+ ### Text API
581
+
582
+ #### `replaceText(replacements)`
583
+ Replaces template placeholders (e.g., {{key}}) with values in the selected slides. Works inside text boxes, titles, grouped shapes, tables, and shapes.
215
584
 
216
- Control the stacking order of shapes, images, charts, tables, groups, and connectors on any slide — just like PowerPoint's **Bring Forward / Send Backward** panel. The Z-order directly maps to the XML element order inside the slide's `<p:spTree>`, which is what PowerPoint reads when rendering.
585
+ * **Arguments**:
586
+ * `replacements` (`Object.<string, string>`): Map of placeholder → replacement value.
587
+ * **Returns**: `PPTXTemplater` - this (chainable)
217
588
 
218
- All operations accept either an **options object** with a `slide` key or can be chained after `useSlide()`:
589
+ ```javascript
590
+ ppt.useSlide(1).replaceText(replacements);
591
+ ```
219
592
 
220
- ```js
221
- // Option A explicit slide number
222
- ppt.bringForward({ slide: 2, objectId: 'logo' });
593
+ #### `addHyperlink(options)`
594
+ Adds or replaces a hyperlink on a text run or shape.
223
595
 
224
- // Option B — fluent chain
225
- ppt.useSlide(2).bringForward('logo');
596
+ * **Arguments**:
597
+ * `options` (`HyperlinkOptions`): Hyperlink configuration.
598
+ * `options.text` (`string`): Text to find and make clickable.
599
+ * `options.url` (`string`): Target URL.
600
+ * `[options.tooltip]` (`string`): Optional tooltip.
601
+ * **Returns**: `PPTXTemplater` - this (chainable)
602
+
603
+ ```javascript
604
+ ppt.useSlide(1).addHyperlink(options);
226
605
  ```
227
606
 
228
- #### `getObjectOrder(slideIndex)`
229
- Returns a sorted array describing every drawing element on the slide, bottom-to-top.
230
- ```js
231
- const layers = ppt.getObjectOrder(1);
232
- // [{ id: 'Background', type: 'shape', zIndex: 1 }, ...]
607
+ #### `addSlideLink(options)`
608
+ Adds an inter-slide hyperlink to a specific text element.
609
+
610
+ * **Arguments**:
611
+ * `options` (`Object`): Link configuration.
612
+ * `options.sourceSlide` (`number`): Source slide number (1-based).
613
+ * `options.targetSlide` (`number`): Destination slide number (1-based).
614
+ * `options.element` (`string`): Text element to make clickable.
615
+ * **Returns**: `PPTXTemplater` - this (chainable)
616
+
617
+ ```javascript
618
+ ppt.useSlide(1).addSlideLink(options);
233
619
  ```
234
620
 
235
- #### `bringForward(options)` / `sendBackward(options)`
236
- Move an object one layer up or down.
237
- ```js
238
- ppt.bringForward({ slide: 1, objectId: 'logo' });
239
- ppt.sendBackward({ slide: 1, objectId: 'logo' });
621
+ #### `addImageLink(options)`
622
+ Adds an inter-slide hyperlink to an image.
623
+
624
+ * **Arguments**:
625
+ * `options` (`Object`):
626
+ * `options.slide` (`number`): Source slide number.
627
+ * `options.imageId` (`string`): Image name/id to make clickable.
628
+ * `options.targetSlide` (`number`): Destination slide number.
629
+ * **Returns**: `PPTXTemplater` - this
630
+
631
+ ```javascript
632
+ ppt.useSlide(1).addImageLink(options);
240
633
  ```
241
634
 
242
- #### `bringToFront(options)` / `sendToBack(options)`
243
- Move an object to the very top or very bottom of the stack.
244
- ```js
245
- ppt.bringToFront({ slide: 1, objectId: 'logo' });
246
- ppt.sendToBack({ slide: 1, objectId: 'background' });
635
+ #### `addShapeLink(options)`
636
+ Adds an inter-slide hyperlink to a shape.
637
+
638
+ * **Arguments**:
639
+ * `options` (`Object`):
640
+ * `options.slide` (`number`): Source slide number.
641
+ * `options.shapeId` (`string`): Shape name/id to make clickable.
642
+ * `options.targetSlide` (`number`): Destination slide number.
643
+ * **Returns**: `PPTXTemplater` - this
644
+
645
+ ```javascript
646
+ ppt.useSlide(1).addShapeLink(options);
247
647
  ```
248
648
 
249
- #### `setZIndex(options)`
250
- Place an object at an exact 1-based stacking position.
251
- ```js
252
- ppt.setZIndex({ slide: 1, objectId: 'logo', zIndex: 3 });
649
+ #### `addTextNavigationLink(options)`
650
+ Adds a special navigation link (next, previous, first, last slide) to a text element.
651
+
652
+ * **Arguments**:
653
+ * `options` (`Object`):
654
+ * `options.slide` (`number`): Source slide number (1-based).
655
+ * `options.element` (`string`): Text element to make clickable.
656
+ * `options.action` (`'next'|'previous'|'first'|'last'`): Navigation action type.
657
+ * **Returns**: `PPTXTemplater` - this (chainable)
658
+
659
+ ```javascript
660
+ ppt.useSlide(1).addTextNavigationLink(options);
253
661
  ```
254
662
 
255
- #### `moveObjectBefore(options)` / `moveObjectAfter(options)`
256
- Position an object immediately below or above a specific target.
257
- ```js
258
- ppt.moveObjectBefore({ slide: 1, objectId: 'overlay', targetId: 'chart' });
259
- ppt.moveObjectAfter({ slide: 1, objectId: 'label', targetId: 'chart' });
663
+ #### `addShapeNavigationLink(options)`
664
+ Adds a special navigation link (next, previous, first, last slide) to a shape or image.
665
+
666
+ * **Arguments**:
667
+ * `options` (`Object`):
668
+ * `options.slide` (`number`): Source slide number (1-based).
669
+ * `options.shapeId` (`string`): Shape name/id to make clickable.
670
+ * `options.action` (`'next'|'previous'|'first'|'last'`): Navigation action type.
671
+ * **Returns**: `PPTXTemplater` - this (chainable)
672
+
673
+ ```javascript
674
+ ppt.useSlide(1).addShapeNavigationLink(options);
260
675
  ```
261
676
 
262
- #### `reorderObjects(options)`
263
- Bulk-reorder the entire slide stack by specifying all object names in desired bottom-to-top order.
264
- ```js
265
- ppt.reorderObjects({
266
- slide: 1,
267
- order: ['background', 'chart', 'logo', 'title']
268
- });
677
+ #### `replaceTextByTag(())`
678
+ Delegates core actions to slide element sub-managers.
679
+
680
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
681
+
682
+ ```javascript
683
+ ppt.useSlide(1).replaceTextByTag('company', 'Acme Corp');
269
684
  ```
270
685
 
271
- #### `applyZOrder(slideIndex, configs)`
272
- Apply multiple stacking rules in a single call. Operations are executed sequentially.
273
- ```js
274
- ppt.applyZOrder(1, [
275
- { id: 'background', sendToBack: true },
276
- { id: 'overlay', zIndex: 2 },
277
- { id: 'logo', bringToFront: true },
278
- ]);
686
+ #### `replaceMultiple(())`
687
+ Delegates core actions to slide element sub-managers.
688
+
689
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
690
+
691
+ ```javascript
692
+ ppt.useSlide(1).replaceMultiple(());
279
693
  ```
280
694
 
281
- #### `swapObjects(slideIndex, objectId1, objectId2)`
282
- Exchange the stacking positions of two objects.
283
- ```js
284
- ppt.swapObjects(1, 'logo', 'chart');
695
+ #### `findText(())`
696
+ Delegates core actions to slide element sub-managers.
697
+
698
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
699
+
700
+ ```javascript
701
+ ppt.useSlide(1).findText(());
285
702
  ```
286
703
 
287
- #### `sortObjects(slideIndex, compareFn)`
288
- Sort the layer stack using a custom comparator (receives `{ id, type, zIndex }` objects).
289
- ```js
290
- // Alphabetical ascending by name
291
- ppt.sortObjects(1, (a, b) => a.id.localeCompare(b.id));
704
+ #### `getTextElements(())`
705
+ Delegates core actions to slide element sub-managers.
706
+
707
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
708
+
709
+ ```javascript
710
+ ppt.useSlide(1).getTextElements(());
292
711
  ```
293
712
 
294
- #### `getTopMostObject(slideIndex)` / `getBottomMostObject(slideIndex)`
295
- Retrieve metadata for the topmost or bottommost element.
296
- ```js
297
- const top = ppt.getTopMostObject(1); // { id: 'logo', type: 'image', zIndex: 5 }
298
- const bottom = ppt.getBottomMostObject(1); // { id: 'background', type: 'shape', zIndex: 1 }
713
+ ---
714
+
715
+ ### Images API
716
+
717
+ #### `replaceImage(())`
718
+ Delegates core actions to slide element sub-managers.
719
+
720
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
721
+
722
+ ```javascript
723
+ await ppt.useSlide(1).replaceImage('logo-img', './new-logo.png');
299
724
  ```
300
725
 
301
- #### `normalizeZOrder(slideIndex)`
302
- Re-derives the Z-order directly from the current XML element order. Useful after manual XML edits or imports to reset the internal ordering state.
303
- ```js
304
- ppt.normalizeZOrder(1);
726
+ #### `addImage(())`
727
+ Delegates core actions to slide element sub-managers.
728
+
729
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
730
+
731
+ ```javascript
732
+ ppt.useSlide(1).addImage(());
733
+ ```
734
+
735
+ #### `removeImage(())`
736
+ Delegates core actions to slide element sub-managers.
737
+
738
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
739
+
740
+ ```javascript
741
+ ppt.useSlide(1).removeImage(());
305
742
  ```
306
743
 
307
- **Supported element types:**
744
+ #### `getImages(())`
745
+ Delegates core actions to slide element sub-managers.
746
+
747
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
308
748
 
309
- | PowerPoint Type | XML Tag | `type` Value |
310
- |:---|:---|:---|
311
- | Shape / Text Box | `p:sp` | `shape` / `text` |
312
- | Image | `p:pic` | `image` |
313
- | Chart | `p:graphicFrame` + chart URI | `chart` |
314
- | Table | `p:graphicFrame` + table URI | `table` |
315
- | SmartArt | `p:graphicFrame` + diagram URI | `smartart` |
316
- | Group | `p:grpSp` | `group` |
317
- | Connector | `p:cxnSp` | `connector` |
749
+ ```javascript
750
+ ppt.useSlide(1).getImages(());
751
+ ```
318
752
 
319
753
  ---
320
754
 
321
- ## Performance Benchmarks
755
+ ### Shapes API
756
+
757
+ #### `updateShapeText(())`
758
+ Delegates core actions to slide element sub-managers.
759
+
760
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
761
+
762
+ ```javascript
763
+ ppt.useSlide(1).updateShapeText(());
764
+ ```
765
+
766
+ #### `cloneShape(())`
767
+ Delegates core actions to slide element sub-managers.
322
768
 
323
- Tested on a standard 50-slide enterprise presentation template:
769
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
770
+
771
+ ```javascript
772
+ ppt.useSlide(1).cloneShape('card-bg', 'card-bg-2');
773
+ ```
324
774
 
325
- | Operation | Execution Duration |
326
- |:---|:---|
327
- | Load PPTX Template | ~110ms |
328
- | Find & Replace 20 Text Placeholders | ~2.5ms |
329
- | XML Schema & Integrity Validation Check | ~14ms |
330
- | Dynamic Row Insertion & Merging (15 rows) | ~3ms |
331
- | Save and Re-package to PPTX ZIP | ~78ms |
775
+ #### `deleteShape(())`
776
+ Delegates core actions to slide element sub-managers.
777
+
778
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
779
+
780
+ ```javascript
781
+ ppt.useSlide(1).deleteShape(());
782
+ ```
783
+
784
+ #### `getShapes(())`
785
+ Delegates core actions to slide element sub-managers.
786
+
787
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
788
+
789
+ ```javascript
790
+ ppt.useSlide(1).getShapes(());
791
+ ```
332
792
 
333
793
  ---
334
794
 
335
- ## FAQ & Troubleshooting
795
+ ### Layer Stacking (Z-Order)
336
796
 
337
- ### PowerPoint displays a "Repair" prompt when opening my generated file
338
- This is commonly caused by:
339
- 1. **Missing overridden content type**: A new slide or chart XML was added but not registered in `[Content_Types].xml`.
340
- 2. **Duplicate row identifiers**: If table rows are duplicated without generating a new unique `rowId` under `<a16:rowId>`.
341
- 3. **Invalid relationship mapping**: An asset (like an image or worksheet) is referenced in slide XML but is missing from the slide's `.rels` file.
797
+ #### `bringForward(optionsOrId)`
798
+ Moves slide element one layer forward.
342
799
 
343
- *Fix*: Ensure you always use the public `saveToFile()` or `toBuffer()` helper functions, which automatically execute structural verification passes and update relationship chains.
344
800
 
345
- ### My text placeholders are not replacing
346
- PowerPoint text editors segment formatting runs into separate XML elements. The text `{{title}}` may look normal in PowerPoint, but in XML it could be split into `<a:t>{{ti</a:t><a:t>tle}}</a:t>`.
347
- *Fix*: You can enable logger output to see split tags:
348
- ```bash
349
- PPTX_LOG_LEVEL=debug node app.js
801
+ ```javascript
802
+ ppt.useSlide(1).bringForward(optionsOrId);
803
+ ```
804
+
805
+ #### `sendBackward(optionsOrId)`
806
+ Moves slide element one layer backward.
807
+
808
+
809
+ ```javascript
810
+ ppt.useSlide(1).sendBackward(optionsOrId);
811
+ ```
812
+
813
+ #### `bringToFront(optionsOrId)`
814
+ Moves slide element above all other objects.
815
+
816
+
817
+ ```javascript
818
+ ppt.useSlide(1).bringToFront('OverlayLogo');
350
819
  ```
351
- To fix this in PowerPoint, highlight the entire placeholder block, cut it, and paste it back as "Keep Text Only" to unify the XML text runs.
820
+
821
+ #### `sendToBack(optionsOrId)`
822
+ Moves slide element behind all other objects.
823
+
824
+
825
+ ```javascript
826
+ ppt.useSlide(1).sendToBack(optionsOrId);
827
+ ```
828
+
829
+ #### `setZIndex(optionsOrId, zIndex)`
830
+ Moves slide element to the specific 1-based stacking position.
831
+
832
+
833
+ ```javascript
834
+ ppt.useSlide(1).setZIndex(optionsOrId, zIndex);
835
+ ```
836
+
837
+ #### `moveObjectBefore(optionsOrId, targetId)`
838
+ Moves slide element directly before (below) a target element.
839
+
840
+
841
+ ```javascript
842
+ ppt.useSlide(1).moveObjectBefore(optionsOrId, targetId);
843
+ ```
844
+
845
+ #### `moveObjectAfter(optionsOrId, targetId)`
846
+ Moves slide element directly after (above) a target element.
847
+
848
+
849
+ ```javascript
850
+ ppt.useSlide(1).moveObjectAfter(optionsOrId, targetId);
851
+ ```
852
+
853
+ #### `reorderObjects(optionsOrOrder)`
854
+ Reorders slide objects exactly as specified in the array.
855
+
856
+
857
+ ```javascript
858
+ ppt.useSlide(1).reorderObjects(optionsOrOrder);
859
+ ```
860
+
861
+ #### `getObjectOrder(slideIndex)`
862
+ Gets the ordered metadata of all objects on the slide.
863
+
864
+
865
+ ```javascript
866
+ ppt.useSlide(1).getObjectOrder(slideIndex);
867
+ ```
868
+
869
+ #### `applyZOrder(slideOrConfigs, configsOption)`
870
+ Applies bulk template configurations for slide elements stacking layers.
871
+
872
+
873
+ ```javascript
874
+ ppt.useSlide(1).applyZOrder(slideOrConfigs, configsOption);
875
+ ```
876
+
877
+ #### `getTopMostObject(slideIndex)`
878
+ Retrieves the info of the top-most object on the slide.
879
+
880
+
881
+ ```javascript
882
+ ppt.useSlide(1).getTopMostObject(slideIndex);
883
+ ```
884
+
885
+ #### `getBottomMostObject(slideIndex)`
886
+ Retrieves the info of the bottom-most object on the slide.
887
+
888
+
889
+ ```javascript
890
+ ppt.useSlide(1).getBottomMostObject(slideIndex);
891
+ ```
892
+
893
+ #### `swapObjects(slideIndexOrId1, id1OrId2, id2)`
894
+ Swaps stacking positions of two slide objects.
895
+
896
+
897
+ ```javascript
898
+ ppt.useSlide(1).swapObjects(slideIndexOrId1, id1OrId2, id2);
899
+ ```
900
+
901
+ #### `sortObjects(slideIndexOrCompareFn, compareFnOption)`
902
+ Sorts stacking order using a custom comparison function.
903
+
904
+
905
+ ```javascript
906
+ ppt.useSlide(1).sortObjects(slideIndexOrCompareFn, compareFnOption);
907
+ ```
908
+
909
+ #### `normalizeZOrder(slideIndex)`
910
+ Cleans up and normalizes stacking order consistency.
911
+
912
+
913
+ ```javascript
914
+ ppt.useSlide(1).normalizeZOrder(slideIndex);
915
+ ```
916
+
917
+ ---
918
+
919
+ ### Utilities & Validation
920
+
921
+ #### `const()`
922
+ This is the primary public API. It coordinates all sub-managers (ZipManager, SlideManager, ChartManager, etc.) and exposes a fluent, chainable interface for template manipulation. OpenXML PPTX Structure: ├── [Content_Types].xml — lists all parts and their MIME types ├── _rels/.rels — root relationships (points to presentation) ├── ppt/ │ ├── presentation.xml — slide order, slide masters references │ ├── _rels/presentation.xml.rels │ ├── slides/ │ │ ├── slide1.xml — individual slide content │ │ └── _rels/slide1.xml.rels │ ├── slideLayouts/ — layout templates (title, content, etc.) │ ├── slideMasters/ — master slide designs │ ├── theme/ — color/font themes │ ├── charts/ — embedded chart XML │ └── media/ — embedded images/videos └── docProps/ ├── core.xml — author, title, etc. └── app.xml — application metadata
923
+
924
+
925
+ ```javascript
926
+ ppt.useSlide(1).const();
927
+ ```
928
+
929
+ #### `class()`
930
+
931
+
932
+
933
+ ```javascript
934
+ ppt.useSlide(1).class();
935
+ ```
936
+
937
+ #### `static()`
938
+ Loads a PPTX template from a file path or buffer. @static @throws {PPTXError} If the file cannot be read or is not a valid PPTX.
939
+
940
+ * **Arguments**:
941
+ * `source` (`string|Buffer`): Path to PPTX file or Buffer containing PPTX data.
942
+ * **Returns**: `Promise<PPTXTemplater>` - Initialized engine instance.
943
+
944
+ ```javascript
945
+ ppt.useSlide(1).static();
946
+ ```
947
+
948
+ #### `getInfo()`
949
+ Returns presentation metadata (title, author, slide count, etc.)
950
+
951
+ * **Returns**: `PresentationInfo` - Metadata object.
952
+
953
+ ```javascript
954
+ ppt.useSlide(1).getInfo();
955
+ ```
956
+
957
+ #### `validate()`
958
+ Validates the XML structure of the current PPTX. Reports issues with relationship IDs, missing parts, etc.
959
+
960
+ * **Returns**: `ValidationResult` - Object with `valid`, `errors`, and `warnings` arrays.
961
+
962
+ ```javascript
963
+ ppt.useSlide(1).validate();
964
+ ```
965
+
966
+ #### `repair()`
967
+ Repairs corrupted OpenXML structure, relationships, and content types. Removes orphan relationships, rebuilds slide references, and fixes missing entries.
968
+
969
+ * **Returns**: `Promise<PPTXTemplater>` - this (chainable)
970
+
971
+ ```javascript
972
+ ppt.useSlide(1).repair();
973
+ ```
974
+
975
+ #### `debugRelationships()`
976
+ Logs all relationships across the presentation to the console for debugging.
977
+
978
+ * **Returns**: `PPTXTemplater` - this (chainable)
979
+
980
+ ```javascript
981
+ ppt.useSlide(1).debugRelationships();
982
+ ```
983
+
984
+ #### `inspectSlide(slideIndex)`
985
+ Inspects a specific slide's structure and relationships.
986
+
987
+ * **Arguments**:
988
+ * `slideIndex` (`number`): 1-based slide index.
989
+ * **Returns**: `PPTXTemplater` - this (chainable)
990
+
991
+ ```javascript
992
+ ppt.useSlide(1).inspectSlide(slideIndex);
993
+ ```
994
+
995
+ #### `inspectXML(xmlPath)`
996
+ Inspects and logs the raw XML of any file in the ZIP.
997
+
998
+ * **Arguments**:
999
+ * `xmlPath` (`string`): Path inside the ZIP (e.g., 'ppt/slides/slide1.xml')
1000
+ * **Returns**: `Promise<PPTXTemplater>` - this (chainable)
1001
+
1002
+ ```javascript
1003
+ ppt.useSlide(1).inspectXML(xmlPath);
1004
+ ```
1005
+
1006
+ #### `inspectChart(chartId)`
1007
+ Inspects a specific chart's metadata and structure.
1008
+
1009
+ * **Arguments**:
1010
+ * `chartId` (`string`):
1011
+
1012
+ ```javascript
1013
+ ppt.useSlide(1).inspectChart(chartId);
1014
+ ```
1015
+
1016
+ #### `inspectChartXML(chartFileName)`
1017
+ Inspects and logs the raw XML of a chart file.
1018
+
1019
+ * **Arguments**:
1020
+ * `chartFileName` (`string`):
1021
+
1022
+ ```javascript
1023
+ ppt.useSlide(1).inspectChartXML(chartFileName);
1024
+ ```
1025
+
1026
+ #### `debugChartRelationships()`
1027
+ Logs all chart relationships.
1028
+
1029
+
1030
+ ```javascript
1031
+ ppt.useSlide(1).debugChartRelationships();
1032
+ ```
1033
+
1034
+ #### `saveToFile(filePath, options = {})`
1035
+ Saves the modified PPTX to a file on disk.
1036
+
1037
+ * **Arguments**:
1038
+ * `filePath` (`string`): Output file path.
1039
+ * `[options]` (`Object`): Save options.
1040
+ * `[options.strict=false]` (`boolean`): Throw error on validation failure.
1041
+ * **Returns**: `Promise<void>` -
1042
+
1043
+ ```javascript
1044
+ ppt.useSlide(1).saveToFile(filePath, options = {});
1045
+ ```
1046
+
1047
+ #### `toBuffer()`
1048
+ Returns the PPTX content as a Node.js Buffer.
1049
+
1050
+ * **Returns**: `Promise<Buffer>` -
1051
+
1052
+ ```javascript
1053
+ ppt.useSlide(1).toBuffer();
1054
+ ```
1055
+
1056
+ #### `toStream()`
1057
+ Returns the PPTX content as a readable Node.js Stream.
1058
+
1059
+ * **Returns**: `Promise<NodeJS.ReadableStream>` -
1060
+
1061
+ ```javascript
1062
+ ppt.useSlide(1).toStream();
1063
+ ```
1064
+
1065
+ #### `slideCount()`
1066
+ Returns the total number of slides in the loaded presentation. @type {number}
1067
+
1068
+
1069
+ ```javascript
1070
+ ppt.useSlide(1).slideCount();
1071
+ ```
1072
+
1073
+ #### `function()`
1074
+ OpenXML relationship IDs follow the format rId1, rId2, rId3, ... They must be unique within each .rels file. These utilities generate collision-free IDs when adding new relationships. / /** Generates the next available relationship ID given an array of existing IDs. Always uses the format "rId{N}" where N is the next integer after the max.
1075
+
1076
+ * **Arguments**:
1077
+ * `existingIds` (`string[]`): Array of existing rId strings (e.g., ['rId1', 'rId2']).
1078
+ * **Returns**: `string` - New relationship ID (e.g., 'rId3').
1079
+
1080
+ ```javascript
1081
+ ppt.useSlide(1).function();
1082
+ ```
1083
+
1084
+ #### `validatePresentation(())`
1085
+ Delegates core actions to slide element sub-managers.
1086
+
1087
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
1088
+
1089
+ ```javascript
1090
+ ppt.useSlide(1).validatePresentation(());
1091
+ ```
1092
+
1093
+ #### `validateSlide(())`
1094
+ Delegates core actions to slide element sub-managers.
1095
+
1096
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
1097
+
1098
+ ```javascript
1099
+ ppt.useSlide(1).validateSlide(());
1100
+ ```
1101
+
1102
+ #### `validateTable(())`
1103
+ Delegates core actions to slide element sub-managers.
1104
+
1105
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
1106
+
1107
+ ```javascript
1108
+ ppt.useSlide(1).validateTable(());
1109
+ ```
1110
+
1111
+ #### `validateRelationships(())`
1112
+ Delegates core actions to slide element sub-managers.
1113
+
1114
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
1115
+
1116
+ ```javascript
1117
+ ppt.useSlide(1).validateRelationships(());
1118
+ ```
1119
+
1120
+ #### `zipManager(())`
1121
+ Delegates core actions to slide element sub-managers.
1122
+
1123
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
1124
+
1125
+ ```javascript
1126
+ ppt.useSlide(1).zipManager(());
1127
+ ```
1128
+
1129
+ #### `xmlParser(())`
1130
+ Delegates core actions to slide element sub-managers.
1131
+
1132
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
1133
+
1134
+ ```javascript
1135
+ ppt.useSlide(1).xmlParser(());
1136
+ ```
1137
+
1138
+ #### `contentTypesManager(())`
1139
+ Delegates core actions to slide element sub-managers.
1140
+
1141
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
1142
+
1143
+ ```javascript
1144
+ ppt.useSlide(1).contentTypesManager(());
1145
+ ```
1146
+
1147
+ #### `relationshipManager(())`
1148
+ Delegates core actions to slide element sub-managers.
1149
+
1150
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
1151
+
1152
+ ```javascript
1153
+ ppt.useSlide(1).relationshipManager(());
1154
+ ```
1155
+
1156
+ #### `slideManager(())`
1157
+ Delegates core actions to slide element sub-managers.
1158
+
1159
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
1160
+
1161
+ ```javascript
1162
+ ppt.useSlide(1).slideManager(());
1163
+ ```
1164
+
1165
+ #### `chartManager(())`
1166
+ Delegates core actions to slide element sub-managers.
1167
+
1168
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
1169
+
1170
+ ```javascript
1171
+ ppt.useSlide(1).chartManager(());
1172
+ ```
1173
+
1174
+ #### `tableManager(())`
1175
+ Delegates core actions to slide element sub-managers.
1176
+
1177
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
1178
+
1179
+ ```javascript
1180
+ ppt.useSlide(1).tableManager(());
1181
+ ```
1182
+
1183
+ #### `shapeManager(())`
1184
+ Delegates core actions to slide element sub-managers.
1185
+
1186
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
1187
+
1188
+ ```javascript
1189
+ ppt.useSlide(1).shapeManager(());
1190
+ ```
1191
+
1192
+ #### `imageManager(())`
1193
+ Delegates core actions to slide element sub-managers.
1194
+
1195
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
1196
+
1197
+ ```javascript
1198
+ ppt.useSlide(1).imageManager(());
1199
+ ```
1200
+
1201
+ #### `textManager(())`
1202
+ Delegates core actions to slide element sub-managers.
1203
+
1204
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
1205
+
1206
+ ```javascript
1207
+ ppt.useSlide(1).textManager(());
1208
+ ```
1209
+
1210
+ #### `hyperlinkManager(())`
1211
+ Delegates core actions to slide element sub-managers.
1212
+
1213
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
1214
+
1215
+ ```javascript
1216
+ ppt.useSlide(1).hyperlinkManager(());
1217
+ ```
1218
+
1219
+ #### `mediaManager(())`
1220
+ Delegates core actions to slide element sub-managers.
1221
+
1222
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
1223
+
1224
+ ```javascript
1225
+ ppt.useSlide(1).mediaManager(());
1226
+ ```
1227
+
1228
+ #### `load(())`
1229
+ Delegates core actions to slide element sub-managers.
1230
+
1231
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
1232
+
1233
+ ```javascript
1234
+ const ppt = await PPTXTemplater.load('./my_template.pptx');
1235
+ ```
1236
+
1237
+ #### `create(())`
1238
+ Delegates core actions to slide element sub-managers.
1239
+
1240
+ * **Returns**: `PPTXTemplater` - The fluent engine instance.
1241
+
1242
+ ```javascript
1243
+ ppt.useSlide(1).create(());
1244
+ ```
1245
+
1246
+ ---
1247
+
1248
+ <!-- API_REFERENCE_END -->
1249
+
1250
+ ---
1251
+
1252
+ ## 🔒 Advanced XML Security
1253
+
1254
+ PPTXForge uses a secure XML parser that defends your application servers against common XML vulnerabilities.
1255
+
1256
+ ### Built-in Protections
1257
+ 1. **XML Bombs & Billion Laughs Mitigation**: Instantly rejects any XML payload containing `<!DOCTYPE>` or `<!ENTITY>` definitions, preventing parser lockups.
1258
+ 2. **XXE Injection Defenses**: Completely blocks external entities referencing local files or external resources (e.g., `SYSTEM` or `PUBLIC`).
1259
+ 3. **Decoupled Entity Expansion Limits**: Evaluates code points and standard characters (`&amp;`, `&lt;`, etc.) via a single-level parser, avoiding recursive parsing loops.
1260
+
1261
+ ### Custom Security & Parsing API
1262
+ Use the safe-parsing helpers to validate user-uploaded templates manually:
1263
+ ```javascript
1264
+ const { validateXml, safeParseXml } = require('node-pptx-templater');
1265
+
1266
+ const schema = validateXml(userInputXml);
1267
+ if (!schema.valid) {
1268
+ console.error(`Invalid XML format: ${schema.error} on Line ${schema.line}`);
1269
+ }
1270
+ ```
1271
+
1272
+ ---
1273
+
1274
+ ## ⚡ Performance Benchmarks
1275
+
1276
+ Below are benchmark results compiled on a standard Intel Core i7 system processing a 50-slide presentation template:
1277
+
1278
+ | Operation | Average Duration |
1279
+ | :--- | :--- |
1280
+ | Load Template | ~110 ms |
1281
+ | Scan & Replace 20 Text Tag Placeholders | ~2.5 ms |
1282
+ | Validate XML Schemas & Relationship Integrity | ~14 ms |
1283
+ | Table Row Cloning & Grid Merges (15 rows) | ~3 ms |
1284
+ | Z-Order Re-indexing & Packaging Output | ~78 ms |
1285
+
1286
+ ---
1287
+
1288
+ ## ❓ FAQ & Developer Troubleshooting
1289
+
1290
+ ### Q: PowerPoint displays a "Repair Presentation" alert when opening generated files.
1291
+ * **Root Cause**: This is usually caused by:
1292
+ 1. A missing relationship entry inside `.rels` maps (e.g., a slide refers to a chart file that isn't declared).
1293
+ 2. Duplicate `<a16:rowId>` elements on a slide (caused by cloning rows raw without updating hashes).
1294
+ * **Fix**: Ensure you always use the built-in `saveToFile()` or `toBuffer()` methods, which automatically execute validation checks, repair relationship indexes, and sanitize content structures.
1295
+
1296
+ ### Q: A text placeholder is not replacing. How do I debug it?
1297
+ * **Root Cause**: PowerPoint might have split your placeholder into multiple runs (e.g., `{{` and `placeholder}}`).
1298
+ * **Fix**:
1299
+ 1. Enable debug logging to locate the fragment: `PPTX_LOG_LEVEL=debug node app.js`.
1300
+ 2. In PowerPoint, select the placeholder text box, cut it, and paste it back using the **"Keep Text Only"** option. This unifies the run.
352
1301
 
353
1302
  ---
354
1303
 
355
1304
  ## 🤝 Contributing
356
1305
 
357
- We welcome contributions! Please check out [CONTRIBUTING.md](./CONTRIBUTING.md) to get started.
1306
+ We welcome contributions from the community. Please read our [CONTRIBUTING.md](./CONTRIBUTING.md) to set up the development environment, format code, and submit Pull Requests.
358
1307
 
359
1308
  ```bash
360
1309
  git clone https://github.com/jsuyog2/node-pptx-templater.git
@@ -367,4 +1316,4 @@ npm test
367
1316
 
368
1317
  ## 📄 License
369
1318
 
370
- Licensed under the MIT License. © [node-pptx-templater contributors](./LICENSE)
1319
+ Licensed under the MIT License. © node-pptx-templater contributors.