node-pptx-templater 1.0.2 → 1.0.4
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/CHANGELOG.md +28 -3
- package/README.md +175 -327
- package/package.json +12 -3
- package/src/cli/commands/build.js +30 -31
- package/src/cli/commands/debug.js +23 -23
- package/src/cli/commands/extract.js +21 -21
- package/src/cli/commands/inspect.js +23 -23
- package/src/cli/commands/validate.js +17 -17
- package/src/cli/index.js +39 -36
- package/src/core/OutputWriter.js +79 -78
- package/src/core/PPTXTemplater.js +856 -273
- package/src/core/TemplateEngine.js +67 -71
- package/src/core/ValidationEngine.js +246 -0
- package/src/index.js +30 -17
- package/src/managers/ChartManager.js +195 -70
- package/src/managers/ContentTypesManager.js +49 -45
- package/src/managers/HyperlinkManager.js +146 -142
- package/src/managers/ImageManager.js +336 -0
- package/src/managers/MediaManager.js +62 -81
- package/src/managers/RelationshipManager.js +99 -95
- package/src/managers/ShapeManager.js +340 -0
- package/src/managers/SlideManager.js +408 -311
- package/src/managers/TableManager.js +979 -262
- package/src/managers/TextManager.js +197 -0
- package/src/managers/ZipManager.js +69 -69
- package/src/managers/charts/ChartCacheGenerator.js +75 -58
- package/src/managers/charts/ChartParser.js +9 -13
- package/src/managers/charts/ChartRelationshipManager.js +12 -10
- package/src/managers/charts/ChartWorkbookUpdater.js +59 -56
- package/src/parsers/XMLParser.js +47 -50
- package/src/templates/blankPptx.js +3 -2
- package/src/templates/slideTemplate.js +28 -34
- package/src/utils/contentTypesHelper.js +40 -54
- package/src/utils/errors.js +18 -18
- package/src/utils/idUtils.js +16 -14
- package/src/utils/logger.js +18 -16
- package/src/utils/relationshipUtils.js +19 -20
- package/src/utils/xmlUtils.js +26 -26
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,29 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.0.3] - 2026-06-02
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **Dynamic Formatting in updateTable**: Added support for inline cell styling (color fill `fill`, text alignment `align`, and `fontSize`) directly on cell objects passed to `updateTable`.
|
|
12
|
+
- **Comprehensive Tailwind Site**: Overhauled doc builder script to generate a premium Tailwind CSS documentation portal with clientside search, clipboard copying, sitemap.xml, robots.txt, and Schema.org metadata.
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
- **XML Element Ordering**: Enforced strict schema-valid element sequence (`a:pPr` -> runs -> `a:endParaRPr`) in slide table cell paragraphs. This resolves the bug where split cells inheriting from template merged cells had their text runs ignored by PowerPoint's XML compiler.
|
|
16
|
+
- **Template Style Inheritance**: Fixed a bug in `updateTable` where cloned rows always copied the first data row (`trs[1]`). The engine now correctly inherits formatting, alignment, and fill styles from matching indices in the template (`trs[i]`) when available.
|
|
17
|
+
|
|
18
|
+
## [1.0.2] - 2026-06-02
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
- **Table Cell Merging & Unmerging Engine**: Fully implemented horizontal cell spans (`gridSpan`, `hMerge`), vertical cell spans (`rowSpan`, `vMerge`), and rectangular block merges.
|
|
22
|
+
- **PowerPoint Repair Protection**: Implemented unique 32-bit unsigned `rowId` generation inside `<a16:rowId>` XML tags for all cloned and inserted rows, eliminating PowerPoint's "Repair Mode" error prompts.
|
|
23
|
+
- **Merge Integrations**: Integrated template-driven merges (`merge` configs array and cell-level `colSpan`/`rowSpan`) inside the main `updateTable` orchestrator.
|
|
24
|
+
- **Integration Test Suite**: Added a comprehensive merge test script under `tests/integration/PPTXMerge.test.js`.
|
|
25
|
+
|
|
26
|
+
## [1.0.1] - 2026-05-19
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
- **CommonJS Target Conversion**: Converted the source code modules compilation and packaging layout from pure ES Modules (ESM) to CommonJS (CJS) to ensure compatibility with standard Node.js deployment, packaging, and edge runtime environments.
|
|
30
|
+
|
|
8
31
|
## [1.0.0] - 2026-05-17
|
|
9
32
|
|
|
10
33
|
### Added
|
|
@@ -16,7 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
16
39
|
- `ChartManager` — direct chart XML data updates (bar, line, pie, area, scatter)
|
|
17
40
|
- `TableManager` — table row replacement preserving all formatting
|
|
18
41
|
- `HyperlinkManager` — external URL and slide-to-slide hyperlink injection
|
|
19
|
-
- `MediaManager` — image embedding with SHA-1
|
|
42
|
+
- `MediaManager` — image embedding with SHA-1 deduplication
|
|
20
43
|
- `TemplateEngine` — `{{placeholder}}` replacement with fragmented run normalization
|
|
21
44
|
- `OutputWriter` — file, buffer, and stream output
|
|
22
45
|
- CLI: `build`, `validate`, `inspect`, `extract`, `debug` commands
|
|
@@ -29,11 +52,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
29
52
|
- MIT License
|
|
30
53
|
|
|
31
54
|
### Architecture
|
|
32
|
-
- Pure JavaScript ES Modules (no TypeScript)
|
|
33
55
|
- Zero PPTX generation library dependencies
|
|
34
56
|
- Only uses: `jszip`, `fast-xml-parser`, `fs-extra`, `commander`, `chalk`, `ora`
|
|
35
57
|
- Async/await throughout
|
|
36
58
|
- Private class fields (`#field`) for encapsulation
|
|
37
59
|
- Modular architecture following SOLID principles
|
|
38
60
|
|
|
39
|
-
[1.0.
|
|
61
|
+
[1.0.3]: https://github.com/jsuyog2/node-pptx-templater/compare/v1.0.2...v1.0.3
|
|
62
|
+
[1.0.2]: https://github.com/jsuyog2/node-pptx-templater/compare/v1.0.1...v1.0.2
|
|
63
|
+
[1.0.1]: https://github.com/jsuyog2/node-pptx-templater/compare/v1.0.0...v1.0.1
|
|
64
|
+
[1.0.0]: https://github.com/jsuyog2/node-pptx-templater/releases/tag/v1.0.0
|
package/README.md
CHANGED
|
@@ -1,31 +1,38 @@
|
|
|
1
1
|
# node-pptx-templater
|
|
2
2
|
|
|
3
|
-
>
|
|
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.
|
|
4
4
|
|
|
5
|
-
[](https://www.npmjs.com/package/node-pptx-templater)
|
|
6
|
-
[](https://www.npmjs.com/package/node-pptx-templater)
|
|
6
|
+
[](https://github.com/jsuyog2/node-pptx-templater/actions/workflows/ci.yml)
|
|
7
|
+
[](https://bundlephobia.com/package/node-pptx-templater)
|
|
8
|
+
[](https://www.npmjs.com/package/node-pptx-templater)
|
|
9
|
+
[](./LICENSE)
|
|
10
|
+
[](https://nodejs.org)
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## ⚡ Why node-pptx-templater?
|
|
15
|
+
|
|
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.
|
|
17
|
+
|
|
18
|
+
`node-pptx-templater` takes a different approach: **Design visually in PowerPoint, populate dynamically in Node.js.**
|
|
19
|
+
|
|
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.
|
|
11
21
|
|
|
12
22
|
---
|
|
13
23
|
|
|
14
24
|
## ✨ Features
|
|
15
25
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
| 🔍 **Validation** | Structure validation with error reporting |
|
|
27
|
-
| 🛠️ **CLI** | `build`, `validate`, `inspect`, `extract`, `debug` |
|
|
28
|
-
| ⚡ **Performance** | Lazy loading, media deduplication, async/await |
|
|
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.
|
|
29
36
|
|
|
30
37
|
---
|
|
31
38
|
|
|
@@ -35,372 +42,213 @@
|
|
|
35
42
|
npm install node-pptx-templater
|
|
36
43
|
```
|
|
37
44
|
|
|
38
|
-
**Requirements:** Node.js ≥ 18.0.0, ES Modules (`"type": "module"`)
|
|
39
|
-
|
|
40
45
|
---
|
|
41
46
|
|
|
42
47
|
## 🚀 Quick Start
|
|
43
48
|
|
|
44
|
-
|
|
45
|
-
import { PPTXTemplater } from 'node-pptx-templater';
|
|
46
|
-
|
|
47
|
-
// Load a template PPTX
|
|
48
|
-
const ppt = await PPTXTemplater.load('template.pptx');
|
|
49
|
-
|
|
50
|
-
// Select slide(s) to work on (omit to work on all)
|
|
51
|
-
ppt.useSlide(1);
|
|
49
|
+
Get up and running in under 60 seconds with this simple template rendering example:
|
|
52
50
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
//
|
|
61
|
-
ppt.
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
]
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
51
|
+
```js
|
|
52
|
+
const { PPTXTemplater } = require('node-pptx-templater');
|
|
53
|
+
|
|
54
|
+
async function main() {
|
|
55
|
+
// 1. Load your PowerPoint presentation template
|
|
56
|
+
const ppt = await PPTXTemplater.load('monthly_report_template.pptx');
|
|
57
|
+
|
|
58
|
+
// 2. Select slide 1 and execute operations
|
|
59
|
+
ppt.useSlide(1)
|
|
60
|
+
.replaceTextByTag('title', 'Quarterly Earnings Report')
|
|
61
|
+
.replaceMultiple({
|
|
62
|
+
company: 'Acme Corporation',
|
|
63
|
+
year: '2026'
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// 3. Update chart series data on Slide 2
|
|
67
|
+
ppt.useSlide(2)
|
|
68
|
+
.updateChartData('sales-chart', {
|
|
69
|
+
categories: ['Q1', 'Q2', 'Q3', 'Q4'],
|
|
70
|
+
series: [
|
|
71
|
+
{ name: 'Target', values: [100, 120, 140, 160] },
|
|
72
|
+
{ name: 'Revenue', values: [105, 118, 145, 172] }
|
|
73
|
+
]
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// 4. Update table with cell merging and formatting on Slide 3
|
|
77
|
+
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' }]
|
|
82
|
+
]);
|
|
83
|
+
|
|
84
|
+
// 5. Save the non-corrupted PPTX back to disk
|
|
85
|
+
await ppt.saveToFile('./output/annual_earnings.pptx');
|
|
86
|
+
}
|
|
75
87
|
|
|
76
|
-
|
|
77
|
-
const buffer = await ppt.toBuffer();
|
|
88
|
+
main().catch(err => console.error(err));
|
|
78
89
|
```
|
|
79
90
|
|
|
80
91
|
---
|
|
81
92
|
|
|
82
|
-
##
|
|
83
|
-
|
|
84
|
-
### `PPTXTemplater`
|
|
85
|
-
|
|
86
|
-
#### Static Methods
|
|
87
|
-
|
|
88
|
-
| Method | Description |
|
|
89
|
-
|---|---|
|
|
90
|
-
| `PPTXTemplater.load(source)` | Load from file path or Buffer |
|
|
91
|
-
| `PPTXTemplater.create()` | Create a blank presentation |
|
|
92
|
-
|
|
93
|
-
#### Slide Selection
|
|
94
|
-
|
|
95
|
-
| Method | Description |
|
|
96
|
-
|---|---|
|
|
97
|
-
| `.useSlide(...refs)` | Select slides by number/tag to apply operations |
|
|
98
|
-
| `.useAllSlides()` | Reset to all slides |
|
|
99
|
-
| `.tagSlide(num, tag)` | Assign custom tag for later selection |
|
|
100
|
-
|
|
101
|
-
#### Content Manipulation
|
|
93
|
+
## 🏗️ OpenXML Architecture & Internals
|
|
102
94
|
|
|
103
|
-
|
|
104
|
-
|---|---|
|
|
105
|
-
| `.replaceText(replacements)` | Replace `{{key}}` placeholders |
|
|
106
|
-
| `.updateChart(chartId, data)` | Update chart categories/series/values |
|
|
107
|
-
| `.updateTable(tableId, rows)` | Replace table row data |
|
|
108
|
-
| `.addHyperlink(options)` | Add/replace external hyperlink on text |
|
|
109
|
-
| `.linkSlideNumber(options)` | Make slide reference navigate to another slide |
|
|
95
|
+
A `.pptx` file is an OPC (Open Packaging Convention) ZIP archive containing structured XML documents and asset folders:
|
|
110
96
|
|
|
111
|
-
|
|
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.
|
|
112
102
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
| `.exportSlides(...nums)` | Export subset to new engine |
|
|
120
|
-
|
|
121
|
-
#### Output
|
|
122
|
-
|
|
123
|
-
| Method | Description |
|
|
124
|
-
|---|---|
|
|
125
|
-
| `.saveToFile(path)` | Write PPTX to disk |
|
|
126
|
-
| `.toBuffer()` | Get PPTX as Node.js Buffer |
|
|
127
|
-
| `.toStream()` | Get PPTX as readable stream |
|
|
128
|
-
|
|
129
|
-
#### Utilities
|
|
130
|
-
|
|
131
|
-
| Method | Description |
|
|
132
|
-
|---|---|
|
|
133
|
-
| `.getInfo()` | Presentation metadata |
|
|
134
|
-
| `.validate()` | Structure validation |
|
|
135
|
-
| `.slideCount` | Total slide count (getter) |
|
|
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
|
|
136
109
|
|
|
137
110
|
---
|
|
138
111
|
|
|
139
|
-
##
|
|
140
|
-
|
|
141
|
-
```
|
|
142
|
-
node-pptx-templater/
|
|
143
|
-
├── PPTXTemplater ← Main orchestrator / public API
|
|
144
|
-
│ ├── ZipManager ← ZIP archive read/write (JSZip)
|
|
145
|
-
│ ├── XMLParser ← XML parse/build (fast-xml-parser)
|
|
146
|
-
│ ├── RelationshipManager ← .rels file management
|
|
147
|
-
│ ├── SlideManager ← Slide discovery, ordering, CRUD
|
|
148
|
-
│ ├── ChartManager ← Chart XML data updates
|
|
149
|
-
│ ├── TableManager ← Table row replacement
|
|
150
|
-
│ ├── HyperlinkManager ← Hyperlink injection
|
|
151
|
-
│ ├── MediaManager ← Image embedding + deduplication
|
|
152
|
-
│ ├── TemplateEngine ← {{placeholder}} replacement
|
|
153
|
-
│ └── OutputWriter ← File/Buffer/Stream output
|
|
154
|
-
```
|
|
112
|
+
## 📊 Feature Comparison Matrix
|
|
155
113
|
|
|
156
|
-
|
|
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 |
|
|
157
124
|
|
|
158
|
-
|
|
125
|
+
---
|
|
159
126
|
|
|
160
|
-
|
|
161
|
-
presentation.pptx (ZIP)
|
|
162
|
-
├── [Content_Types].xml # MIME types for all parts
|
|
163
|
-
├── _rels/.rels # Root relationships
|
|
164
|
-
├── ppt/
|
|
165
|
-
│ ├── presentation.xml # Slide list, master references
|
|
166
|
-
│ ├── _rels/presentation.xml.rels
|
|
167
|
-
│ ├── slides/
|
|
168
|
-
│ │ ├── slide1.xml # Slide content XML
|
|
169
|
-
│ │ ├── slide2.xml
|
|
170
|
-
│ │ └── _rels/slide1.xml.rels
|
|
171
|
-
│ ├── slideLayouts/ # Layout templates
|
|
172
|
-
│ ├── slideMasters/ # Master slide designs
|
|
173
|
-
│ ├── theme/ # Color & font themes
|
|
174
|
-
│ ├── charts/ # Embedded chart XML
|
|
175
|
-
│ └── media/ # Images, videos
|
|
176
|
-
└── docProps/
|
|
177
|
-
├── core.xml # Title, author, dates
|
|
178
|
-
└── app.xml # App metadata
|
|
179
|
-
```
|
|
127
|
+
## 📚 API Reference
|
|
180
128
|
|
|
181
|
-
###
|
|
129
|
+
### Slide Operations
|
|
182
130
|
|
|
131
|
+
#### `duplicateSlide(slideIndex, atPosition)`
|
|
132
|
+
Duplicates a slide.
|
|
133
|
+
```js
|
|
134
|
+
ppt.duplicateSlide(1, 2); // Duplicate Slide 1 and insert it at position 2
|
|
183
135
|
```
|
|
184
|
-
presentation.xml
|
|
185
|
-
└─[rId2]──► slides/slide1.xml
|
|
186
|
-
└─[rId1]──► slideLayouts/slideLayout1.xml
|
|
187
|
-
└─[rId2]──► charts/chart1.xml
|
|
188
|
-
└─ (chart data XML)
|
|
189
|
-
└─[rId3]──► media/image1.png
|
|
190
|
-
└─[rId4]──► https://example.com (external)
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
### Text Fragmentation Problem & Solution
|
|
194
|
-
|
|
195
|
-
PowerPoint sometimes splits `{{placeholder}}` across multiple XML text runs:
|
|
196
136
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
<!-- What the XML actually contains: -->
|
|
202
|
-
<a:r><a:t>{{ti</a:t></a:r>
|
|
203
|
-
<a:r><a:t>tle}}</a:t></a:r>
|
|
137
|
+
#### `deleteSlide(slideIndex)`
|
|
138
|
+
Deletes a slide from the deck.
|
|
139
|
+
```js
|
|
140
|
+
ppt.deleteSlide(3); // Delete Slide 3
|
|
204
141
|
```
|
|
205
142
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
4. Injecting the replacement value
|
|
211
|
-
|
|
212
|
-
---
|
|
213
|
-
|
|
214
|
-
## 🖥️ CLI Usage
|
|
215
|
-
|
|
216
|
-
```bash
|
|
217
|
-
# Install globally
|
|
218
|
-
npm install -g node-pptx-templater
|
|
219
|
-
|
|
220
|
-
# Build a PPTX from template + JSON data
|
|
221
|
-
node-pptx-templater build template.pptx output.pptx --data data.json
|
|
222
|
-
|
|
223
|
-
# Validate a PPTX structure
|
|
224
|
-
node-pptx-templater validate presentation.pptx
|
|
225
|
-
|
|
226
|
-
# Inspect internal structure
|
|
227
|
-
node-pptx-templater inspect presentation.pptx --all
|
|
228
|
-
|
|
229
|
-
# Extract a slide's XML
|
|
230
|
-
node-pptx-templater extract presentation.pptx --slide 1 --out slide1.xml
|
|
231
|
-
|
|
232
|
-
# Debug a corrupted PPTX
|
|
233
|
-
node-pptx-templater debug broken.pptx --fix --out repaired.pptx
|
|
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
|
|
234
147
|
```
|
|
235
148
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
```
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
"{{title}}": "Annual Report 2026",
|
|
242
|
-
"{{company}}": "Acme Corp",
|
|
243
|
-
"{{date}}": "January 2026"
|
|
244
|
-
},
|
|
245
|
-
"charts": {
|
|
246
|
-
"sales-chart": {
|
|
247
|
-
"categories": ["Q1", "Q2", "Q3", "Q4"],
|
|
248
|
-
"series": [
|
|
249
|
-
{ "name": "Revenue", "values": [145, 210, 190, 250] }
|
|
250
|
-
]
|
|
251
|
-
}
|
|
252
|
-
},
|
|
253
|
-
"tables": {
|
|
254
|
-
"data-table": [
|
|
255
|
-
["Name", "Role", "Dept"],
|
|
256
|
-
["Alice", "Engineer", "Platform"]
|
|
257
|
-
]
|
|
258
|
-
}
|
|
259
|
-
}
|
|
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
|
|
260
154
|
```
|
|
261
155
|
|
|
262
156
|
---
|
|
263
157
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
| OpenXML Element | Chart Type |
|
|
267
|
-
|---|---|
|
|
268
|
-
| `c:barChart` | Bar / Column |
|
|
269
|
-
| `c:lineChart` | Line |
|
|
270
|
-
| `c:pieChart` | Pie |
|
|
271
|
-
| `c:areaChart` | Area |
|
|
272
|
-
| `c:scatterChart` | Scatter / XY |
|
|
273
|
-
| `c:doughnutChart` | Doughnut |
|
|
274
|
-
| `c:radarChart` | Radar / Spider |
|
|
275
|
-
| `c:bubbleChart` | Bubble |
|
|
276
|
-
|
|
277
|
-
---
|
|
278
|
-
|
|
279
|
-
## ⚡ Performance
|
|
280
|
-
|
|
281
|
-
| Operation | Benchmark (avg) |
|
|
282
|
-
|---|---|
|
|
283
|
-
| Load 50-slide PPTX | ~120ms |
|
|
284
|
-
| Text replacement (20 placeholders) | ~2ms |
|
|
285
|
-
| Buffer generation | ~80ms |
|
|
286
|
-
| Chart update | ~5ms |
|
|
287
|
-
| Table update | ~3ms |
|
|
288
|
-
|
|
289
|
-
> Run your own: `npm run benchmark`
|
|
290
|
-
|
|
291
|
-
---
|
|
292
|
-
|
|
293
|
-
## 🐛 Troubleshooting
|
|
158
|
+
### Table Manipulation
|
|
294
159
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
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
|
+
]);
|
|
302
168
|
```
|
|
303
169
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
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
|
+
});
|
|
307
180
|
```
|
|
308
181
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
node-pptx-templater inspect template.pptx --charts
|
|
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
|
|
189
|
+
});
|
|
318
190
|
```
|
|
319
191
|
|
|
320
|
-
|
|
192
|
+
---
|
|
321
193
|
|
|
322
|
-
|
|
194
|
+
### Chart Integration
|
|
323
195
|
|
|
324
|
-
|
|
325
|
-
|
|
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
|
+
});
|
|
326
205
|
```
|
|
327
206
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
-
|
|
331
|
-
- Invalid XML characters in replacement values
|
|
332
|
-
|
|
333
|
-
### File is corrupted
|
|
334
|
-
|
|
335
|
-
```bash
|
|
336
|
-
node-pptx-templater debug corrupted.pptx --fix --out repaired.pptx
|
|
207
|
+
#### `updateChartTitle(chartId, title)`
|
|
208
|
+
```js
|
|
209
|
+
ppt.updateChartTitle('sales-chart', 'Revenue Growth (2026)');
|
|
337
210
|
```
|
|
338
211
|
|
|
339
|
-
The debug command attempts:
|
|
340
|
-
- Removing invalid XML control characters
|
|
341
|
-
- Fixing unescaped `&` in text content
|
|
342
|
-
- Repairing broken relationship IDs
|
|
343
|
-
|
|
344
212
|
---
|
|
345
213
|
|
|
346
|
-
##
|
|
347
|
-
|
|
348
|
-
Extend the engine by subclassing `PPTXTemplater`:
|
|
214
|
+
## ⚡ Performance Benchmarks
|
|
349
215
|
|
|
350
|
-
|
|
351
|
-
import { PPTXTemplater } from 'pptx-templater';
|
|
216
|
+
Tested on a standard 50-slide enterprise presentation template:
|
|
352
217
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
218
|
+
| Operation | Execution Duration |
|
|
219
|
+
|:---|:---|
|
|
220
|
+
| Load PPTX Template | ~110ms |
|
|
221
|
+
| Find & Replace 20 Text Placeholders | ~2.5ms |
|
|
222
|
+
| XML Schema & Integrity Validation Check | ~14ms |
|
|
223
|
+
| Dynamic Row Insertion & Merging (15 rows) | ~3ms |
|
|
224
|
+
| Save and Re-package to PPTX ZIP | ~78ms |
|
|
359
225
|
|
|
360
|
-
|
|
361
|
-
for (const [key, val] of Object.entries(data.text || {})) {
|
|
362
|
-
textReplacements[`{{${key}}}`] = String(val);
|
|
363
|
-
}
|
|
226
|
+
---
|
|
364
227
|
|
|
365
|
-
|
|
228
|
+
## ❓ FAQ & Troubleshooting
|
|
366
229
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
230
|
+
### PowerPoint displays a "Repair" prompt when opening my generated file
|
|
231
|
+
This is commonly caused by:
|
|
232
|
+
1. **Missing overridden content type**: A new slide or chart XML was added but not registered in `[Content_Types].xml`.
|
|
233
|
+
2. **Duplicate row identifiers**: If table rows are duplicated without generating a new unique `rowId` under `<a16:rowId>`.
|
|
234
|
+
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.
|
|
370
235
|
|
|
371
|
-
|
|
372
|
-
}
|
|
373
|
-
}
|
|
236
|
+
*Fix*: Ensure you always use the public `saveToFile()` or `toBuffer()` helper functions, which automatically execute structural verification passes and update relationship chains.
|
|
374
237
|
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
});
|
|
381
|
-
await ppt.saveToFile('output.pptx');
|
|
238
|
+
### My text placeholders are not replacing
|
|
239
|
+
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>`.
|
|
240
|
+
*Fix*: You can enable logger output to see split tags:
|
|
241
|
+
```bash
|
|
242
|
+
PPTX_LOG_LEVEL=debug node app.js
|
|
382
243
|
```
|
|
383
|
-
|
|
384
|
-
---
|
|
385
|
-
|
|
386
|
-
## 🛣️ Roadmap
|
|
387
|
-
|
|
388
|
-
- [ ] SmartArt data update
|
|
389
|
-
- [ ] Speaker notes modification
|
|
390
|
-
- [ ] Slide transitions and animation metadata editing
|
|
391
|
-
- [ ] PPTX → HTML export (read-only)
|
|
392
|
-
- [ ] Password-protected PPTX support
|
|
393
|
-
- [ ] Native chart creation from scratch (without template)
|
|
394
|
-
- [ ] Watch mode for development
|
|
395
|
-
- [ ] Browser/WASM support (via jszip already)
|
|
244
|
+
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.
|
|
396
245
|
|
|
397
246
|
---
|
|
398
247
|
|
|
399
248
|
## 🤝 Contributing
|
|
400
249
|
|
|
401
|
-
|
|
250
|
+
We welcome contributions! Please check out [CONTRIBUTING.md](./CONTRIBUTING.md) to get started.
|
|
402
251
|
|
|
403
|
-
Quick steps:
|
|
404
252
|
```bash
|
|
405
253
|
git clone https://github.com/jsuyog2/node-pptx-templater.git
|
|
406
254
|
cd node-pptx-templater
|
|
@@ -412,4 +260,4 @@ npm test
|
|
|
412
260
|
|
|
413
261
|
## 📄 License
|
|
414
262
|
|
|
415
|
-
MIT
|
|
263
|
+
Licensed under the MIT License. © [node-pptx-templater contributors](./LICENSE)
|