node-pptx-templater 1.0.1 β 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +336 -281
- package/package.json +6 -6
- package/src/cli/commands/build.js +32 -31
- package/src/cli/commands/debug.js +25 -24
- package/src/cli/commands/extract.js +23 -21
- package/src/cli/commands/inspect.js +25 -23
- package/src/cli/commands/validate.js +19 -17
- package/src/cli/index.js +45 -43
- package/src/core/OutputWriter.js +81 -78
- package/src/core/PPTXTemplater.js +859 -274
- package/src/core/TemplateEngine.js +69 -71
- package/src/core/ValidationEngine.js +246 -0
- package/src/index.js +51 -15
- package/src/managers/ChartManager.js +197 -70
- package/src/managers/ContentTypesManager.js +51 -45
- package/src/managers/HyperlinkManager.js +148 -142
- package/src/managers/ImageManager.js +336 -0
- package/src/managers/MediaManager.js +64 -81
- package/src/managers/RelationshipManager.js +102 -96
- package/src/managers/ShapeManager.js +340 -0
- package/src/managers/SlideManager.js +410 -311
- package/src/managers/TableManager.js +981 -262
- package/src/managers/TextManager.js +197 -0
- package/src/managers/ZipManager.js +71 -69
- package/src/managers/charts/ChartCacheGenerator.js +77 -58
- package/src/managers/charts/ChartParser.js +11 -13
- package/src/managers/charts/ChartRelationshipManager.js +14 -10
- package/src/managers/charts/ChartWorkbookUpdater.js +61 -56
- package/src/parsers/XMLParser.js +50 -49
- package/src/templates/blankPptx.js +3 -1
- package/src/templates/slideTemplate.js +31 -32
- package/src/utils/contentTypesHelper.js +41 -53
- package/src/utils/errors.js +33 -23
- package/src/utils/idUtils.js +23 -15
- package/src/utils/logger.js +21 -15
- package/src/utils/relationshipUtils.js +28 -22
- package/src/utils/xmlUtils.js +37 -29
package/README.md
CHANGED
|
@@ -7,25 +7,18 @@
|
|
|
7
7
|
[](https://codecov.io/gh/jsuyog2/node-pptx-templater)
|
|
8
8
|
[](./LICENSE)
|
|
9
9
|
[](https://nodejs.org)
|
|
10
|
-
[](https://nodejs.org/api/esm.html)
|
|
11
10
|
|
|
12
11
|
---
|
|
13
12
|
|
|
14
13
|
## β¨ Features
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
| β **Add new slides** | Text, images, shapes with auto-generated XML |
|
|
24
|
-
| π― **Slide selection** | By number, ID, or custom tags |
|
|
25
|
-
| π€ **Multiple outputs** | `saveToFile()`, `toBuffer()`, `toStream()` |
|
|
26
|
-
| π **Validation** | Structure validation with error reporting |
|
|
27
|
-
| π οΈ **CLI** | `build`, `validate`, `inspect`, `extract`, `debug` |
|
|
28
|
-
| β‘ **Performance** | Lazy loading, media deduplication, async/await |
|
|
15
|
+
- ποΈ **Zero PPTX Library Dependencies**: Operates entirely via low-level XML/ZIP manipulation.
|
|
16
|
+
- π **Advanced Text Replacement**: Handles fragmented runs seamlessly (`{{placeholders}}`).
|
|
17
|
+
- π **Comprehensive Chart Support**: Bar, Column, Line, Pie, Doughnut, Area, Scatterβpreserves original themes.
|
|
18
|
+
- π **Safe Table Updates**: Fully manages row insertion, deletion, merging, resizing, and cell formatting while maintaining PowerPoint integrity (prevents repair warnings by generating unique row IDs).
|
|
19
|
+
- π¨ **Shape & Image Manipulation**: Update text, clone, position, replace, or delete slide components.
|
|
20
|
+
- π― **Slide Operations**: Duplicate, reorder, insert, or delete slide parts on the fly.
|
|
21
|
+
- π **Deep Integrity Validation**: Live validation of relationships, XML schema consistency, table columns, and duplicates prior to saving.
|
|
29
22
|
|
|
30
23
|
---
|
|
31
24
|
|
|
@@ -35,372 +28,434 @@
|
|
|
35
28
|
npm install node-pptx-templater
|
|
36
29
|
```
|
|
37
30
|
|
|
38
|
-
**Requirements:** Node.js β₯ 18.0.0, ES Modules (`"type": "module"`)
|
|
39
|
-
|
|
40
31
|
---
|
|
41
32
|
|
|
42
33
|
## π Quick Start
|
|
43
34
|
|
|
44
35
|
```js
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
36
|
+
const { PPTXTemplater } = require('node-pptx-templater');
|
|
37
|
+
|
|
38
|
+
async function run() {
|
|
39
|
+
// Load presentation template
|
|
40
|
+
const ppt = await PPTXTemplater.load('template.pptx');
|
|
41
|
+
|
|
42
|
+
// Use Slide 1 and replace text placeholders
|
|
43
|
+
ppt.useSlide(1)
|
|
44
|
+
.replaceTextByTag('title', 'Annual Sales Report')
|
|
45
|
+
.replaceMultiple({ company: 'Google DeepMind', year: '2026' });
|
|
46
|
+
|
|
47
|
+
// Update chart data on Slide 2
|
|
48
|
+
ppt.useSlide(2)
|
|
49
|
+
.updateChartData('sales-chart', {
|
|
50
|
+
categories: ['Q1', 'Q2', 'Q3', 'Q4'],
|
|
51
|
+
series: [{ name: 'Revenue', values: [100, 150, 180, 220] }]
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// Save the result (validates structural integrity automatically)
|
|
55
|
+
await ppt.saveToFile('output.pptx');
|
|
56
|
+
}
|
|
57
|
+
run();
|
|
58
|
+
```
|
|
49
59
|
|
|
50
|
-
|
|
51
|
-
ppt.useSlide(1);
|
|
60
|
+
---
|
|
52
61
|
|
|
53
|
-
|
|
54
|
-
ppt.replaceText({
|
|
55
|
-
'{{title}}': 'Quarterly Report',
|
|
56
|
-
'{{year}}': '2026',
|
|
57
|
-
'{{company}}': 'Acme Corp',
|
|
58
|
-
});
|
|
62
|
+
## ποΈ Architecture & OpenXML Internals
|
|
59
63
|
|
|
60
|
-
|
|
61
|
-
ppt.updateChart('sales-chart', {
|
|
62
|
-
categories: ['Jan', 'Feb', 'Mar'],
|
|
63
|
-
series: [{ name: 'Revenue', values: [120, 150, 180] }],
|
|
64
|
-
});
|
|
64
|
+
A PPTX file is an OPC (Open Packaging Convention) ZIP containing XML parts:
|
|
65
65
|
|
|
66
|
-
|
|
67
|
-
ppt.
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
['Bob', 'Designer', 'Product'],
|
|
71
|
-
]);
|
|
66
|
+
- `/ppt/presentation.xml` β The slides inventory (`sldIdLst`) and masters.
|
|
67
|
+
- `/ppt/slides/slideN.xml` β Slide elements (shapes, images, tables).
|
|
68
|
+
- `/ppt/slides/_rels/slideN.xml.rels` β Relationship links (`rId`).
|
|
69
|
+
- `[Content_Types].xml` β Declares MIME types for slide parts, charts, and media.
|
|
72
70
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
// Or get a Buffer (for HTTP responses, emails, etc.)
|
|
77
|
-
const buffer = await ppt.toBuffer();
|
|
78
|
-
```
|
|
71
|
+
### The rowId Table Corruption Bug
|
|
72
|
+
Microsoft PowerPoint assigns an `<a16:rowId>` identifier to each row to facilitate collaborative editing. Duplicate row IDs trigger the PowerPoint **Repair Mode**, causing slide elements and styles to break.
|
|
73
|
+
`node-pptx-templater` generates unique 32-bit unsigned integers for `<a16:rowId>` whenever a table row is cloned, appended, or inserted, ensuring output documents open flawlessly in MS PowerPoint, Google Slides, and LibreOffice.
|
|
79
74
|
|
|
80
75
|
---
|
|
81
76
|
|
|
82
77
|
## π API Reference
|
|
83
78
|
|
|
84
|
-
|
|
79
|
+
Here is the complete reference of all public APIs.
|
|
85
80
|
|
|
86
|
-
|
|
81
|
+
### Slide Features
|
|
87
82
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
83
|
+
#### `duplicateSlide(slideIndex, atPosition)`
|
|
84
|
+
Duplicates a slide.
|
|
85
|
+
```js
|
|
86
|
+
ppt.duplicateSlide(1, 2); // Duplicate Slide 1 and insert it as Slide 2
|
|
87
|
+
```
|
|
92
88
|
|
|
93
|
-
####
|
|
89
|
+
#### `deleteSlide(slideIndex)`
|
|
90
|
+
Deletes a slide from the deck.
|
|
91
|
+
```js
|
|
92
|
+
ppt.deleteSlide(3); // Delete Slide 3
|
|
93
|
+
```
|
|
94
94
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
95
|
+
#### `moveSlide(fromIndex, toIndex)`
|
|
96
|
+
Moves a slide to a new position.
|
|
97
|
+
```js
|
|
98
|
+
ppt.moveSlide(1, 3); // Move Slide 1 to position 3
|
|
99
|
+
```
|
|
100
100
|
|
|
101
|
-
####
|
|
101
|
+
#### `insertSlide(slideIndex, options)`
|
|
102
|
+
Inserts a new blank slide at a specific position.
|
|
103
|
+
```js
|
|
104
|
+
ppt.insertSlide(2, { title: 'New Layout Slide' });
|
|
105
|
+
```
|
|
102
106
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
| `.linkSlideNumber(options)` | Make slide reference navigate to another slide |
|
|
107
|
+
#### `getSlides()`
|
|
108
|
+
Returns metadata about all slides in the deck.
|
|
109
|
+
```js
|
|
110
|
+
const slides = ppt.getSlides();
|
|
111
|
+
console.log(slides);
|
|
112
|
+
```
|
|
110
113
|
|
|
111
|
-
|
|
114
|
+
---
|
|
112
115
|
|
|
113
|
-
|
|
114
|
-
|---|---|
|
|
115
|
-
| `.addSlide(options)` | Add a new slide with elements |
|
|
116
|
-
| `.cloneSlide(num, atPos?)` | Duplicate an existing slide |
|
|
117
|
-
| `.removeSlide(num)` | Delete a slide |
|
|
118
|
-
| `.reorderSlides(order)` | Reorder slides |
|
|
119
|
-
| `.exportSlides(...nums)` | Export subset to new engine |
|
|
116
|
+
### Table Features
|
|
120
117
|
|
|
121
|
-
####
|
|
118
|
+
#### `addTableRow(tableId, rowData)`
|
|
119
|
+
Appends a new row to the table.
|
|
120
|
+
```js
|
|
121
|
+
ppt.addTableRow('sales-table', ['Q4', '150', '210', '190', '250']);
|
|
122
|
+
```
|
|
122
123
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
124
|
+
#### `removeTableRow(tableId, rowIndex)`
|
|
125
|
+
Removes a table row.
|
|
126
|
+
```js
|
|
127
|
+
ppt.removeTableRow('sales-table', 1); // Delete 2nd row (0-based)
|
|
128
|
+
```
|
|
128
129
|
|
|
129
|
-
####
|
|
130
|
+
#### `insertTableRow(tableId, rowIndex, rowData)`
|
|
131
|
+
Inserts a row at a specific index.
|
|
132
|
+
```js
|
|
133
|
+
ppt.insertTableRow('sales-table', 2, ['Q3', '100', '120', '140', '160']);
|
|
134
|
+
```
|
|
130
135
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
+
#### `cloneTableRow(tableId, sourceRowIndex, targetRowIndex)`
|
|
137
|
+
Clones a row style/data and inserts it.
|
|
138
|
+
```js
|
|
139
|
+
ppt.cloneTableRow('sales-table', 1, 3);
|
|
140
|
+
```
|
|
136
141
|
|
|
137
|
-
|
|
142
|
+
#### `updateCell(tableId, rowIndex, colIndex, value, options)`
|
|
143
|
+
Updates a specific cell value and styling.
|
|
144
|
+
```js
|
|
145
|
+
ppt.updateCell('sales-table', 1, 0, 'New Product Name', {
|
|
146
|
+
fill: 'FF0000', // HEX background color
|
|
147
|
+
align: 'ctr', // Text alignment: 'l', 'ctr', 'r', 'just'
|
|
148
|
+
fontSize: 14 // Font size in points
|
|
149
|
+
});
|
|
150
|
+
```
|
|
138
151
|
|
|
139
|
-
|
|
152
|
+
#### `mergeCells(options)` or `mergeCells(tableId, startRow, startCol, endRow, endCol)`
|
|
153
|
+
Merges a rectangular range of cells. Supports horizontal, vertical, and block merges, moving cell texts to the origin cell (concatenated with newlines) and setting correct OpenXML `gridSpan` and `rowSpan` attributes.
|
|
154
|
+
```js
|
|
155
|
+
// Config object signature (Recommended)
|
|
156
|
+
ppt.mergeCells({
|
|
157
|
+
slide: 3,
|
|
158
|
+
tableId: 'sales-table',
|
|
159
|
+
startRow: 1,
|
|
160
|
+
startCol: 1,
|
|
161
|
+
endRow: 3,
|
|
162
|
+
endCol: 3
|
|
163
|
+
});
|
|
140
164
|
|
|
165
|
+
// Legacy positional signature
|
|
166
|
+
ppt.mergeCells('sales-table', 1, 1, 3, 3);
|
|
141
167
|
```
|
|
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
|
-
```
|
|
155
|
-
|
|
156
|
-
### OpenXML PPTX Structure
|
|
157
168
|
|
|
158
|
-
|
|
169
|
+
#### `unmergeCells(options)` or `unmergeCells(tableId, startRow, startCol, endRow, endCol)`
|
|
170
|
+
Unmerges cells, restoring original XML cell structures.
|
|
171
|
+
```js
|
|
172
|
+
// Cell-coordinate coordinate signature (Recommended)
|
|
173
|
+
ppt.unmergeCells({
|
|
174
|
+
slide: 3,
|
|
175
|
+
tableId: 'sales-table',
|
|
176
|
+
row: 2,
|
|
177
|
+
col: 2
|
|
178
|
+
});
|
|
159
179
|
|
|
160
|
-
|
|
161
|
-
|
|
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
|
|
180
|
+
// Legacy positional signature
|
|
181
|
+
ppt.unmergeCells('sales-table', 1, 1, 3, 3);
|
|
179
182
|
```
|
|
180
183
|
|
|
181
|
-
|
|
184
|
+
#### `getMergedCells(tableId)`
|
|
185
|
+
Scans the slide table and returns all active merged regions.
|
|
186
|
+
```js
|
|
187
|
+
const merges = ppt.getMergedCells('sales-table');
|
|
188
|
+
// Output: [ { startRow: 1, startCol: 1, endRow: 3, endCol: 3 } ]
|
|
189
|
+
```
|
|
182
190
|
|
|
191
|
+
#### `validateMergeRegion(tableId, startRow, startCol, endRow, endCol)`
|
|
192
|
+
Checks bounds and overlaps, returning detailed validation errors.
|
|
193
|
+
```js
|
|
194
|
+
const report = ppt.validateMergeRegion('sales-table', 1, 1, 3, 3);
|
|
195
|
+
console.log(report.valid); // true or false
|
|
196
|
+
console.log(report.errors); // Array of error strings
|
|
183
197
|
```
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
ββ[rId3]βββΊ media/image1.png
|
|
190
|
-
ββ[rId4]βββΊ https://example.com (external)
|
|
198
|
+
|
|
199
|
+
#### `isMergedCell(tableId, row, col)`
|
|
200
|
+
Returns `true` if the cell at `(row, col)` is part of any merged region.
|
|
201
|
+
```js
|
|
202
|
+
const merged = ppt.isMergedCell('sales-table', 2, 2);
|
|
191
203
|
```
|
|
192
204
|
|
|
193
|
-
|
|
205
|
+
#### `getMergeParent(tableId, row, col)`
|
|
206
|
+
Returns the coordinates `{ row, col }` of the top-left origin cell of the merge region containing `(row, col)`.
|
|
207
|
+
```js
|
|
208
|
+
const parent = ppt.getMergeParent('sales-table', 2, 2); // { row: 1, col: 1 }
|
|
209
|
+
```
|
|
194
210
|
|
|
195
|
-
|
|
211
|
+
#### `getMergeRegion(tableId, row, col)`
|
|
212
|
+
Returns the merged region object `{ startRow, startCol, endRow, endCol }` containing `(row, col)`.
|
|
213
|
+
```js
|
|
214
|
+
const region = ppt.getMergeRegion('sales-table', 2, 2);
|
|
215
|
+
```
|
|
196
216
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
217
|
+
#### `splitMergedRegion(tableId, row, col)`
|
|
218
|
+
Splits the merged region containing cell `(row, col)`.
|
|
219
|
+
```js
|
|
220
|
+
ppt.splitMergedRegion('sales-table', 2, 2);
|
|
221
|
+
```
|
|
200
222
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
223
|
+
#### `cloneMergedRegion(tableId, row, col, targetRow, targetCol)`
|
|
224
|
+
Clones a merged region to another starting position, preserving cell text and formatting.
|
|
225
|
+
```js
|
|
226
|
+
ppt.cloneMergedRegion('sales-table', 1, 1, 4, 1);
|
|
204
227
|
```
|
|
205
228
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
229
|
+
#### Template-driven cell merges
|
|
230
|
+
Support cell merging inside template updates dynamically via `colSpan`/`rowSpan` or `merge` arrays:
|
|
231
|
+
```js
|
|
232
|
+
ppt.updateTable('sales-table', {
|
|
233
|
+
rows: [
|
|
234
|
+
['Header 1', 'Header 2', 'Header 3'],
|
|
235
|
+
['Row 1 Col 1', { value: 'Spanned Cell', colSpan: 2 }],
|
|
236
|
+
['Row 2 Col 1', 'Row 2 Col 2', { value: 'Spanned V', rowSpan: 2 }]
|
|
237
|
+
],
|
|
238
|
+
merge: [
|
|
239
|
+
{ startRow: 0, startCol: 0, endRow: 0, endCol: 2 }
|
|
240
|
+
]
|
|
241
|
+
});
|
|
242
|
+
```
|
|
211
243
|
|
|
212
|
-
|
|
244
|
+
#### `autoFitTable(tableId)`
|
|
245
|
+
Resizes columns to fit text width.
|
|
246
|
+
```js
|
|
247
|
+
ppt.autoFitTable('sales-table');
|
|
248
|
+
```
|
|
213
249
|
|
|
214
|
-
|
|
250
|
+
#### `resizeTable(tableId, width, height)`
|
|
251
|
+
Resizes the bounding frame of the table. Width/height can be in EMUs or inches.
|
|
252
|
+
```js
|
|
253
|
+
ppt.resizeTable('sales-table', 8.5, 4.2); // Dimensions in inches
|
|
254
|
+
```
|
|
215
255
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
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
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
### Data JSON format for `build` command
|
|
237
|
-
|
|
238
|
-
```json
|
|
239
|
-
{
|
|
240
|
-
"text": {
|
|
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
|
-
}
|
|
256
|
+
#### `getTables()`
|
|
257
|
+
Lists tables in the current slide.
|
|
258
|
+
```js
|
|
259
|
+
const tables = ppt.getTables();
|
|
260
260
|
```
|
|
261
261
|
|
|
262
262
|
---
|
|
263
263
|
|
|
264
|
-
|
|
264
|
+
### Chart Features
|
|
265
265
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
| `c:radarChart` | Radar / Spider |
|
|
275
|
-
| `c:bubbleChart` | Bubble |
|
|
266
|
+
#### `updateChartData(chartId, data)`
|
|
267
|
+
Updates a chart's categories, series, values, and embedded Excel workbook.
|
|
268
|
+
```js
|
|
269
|
+
ppt.updateChartData('sales-chart', {
|
|
270
|
+
categories: ['Q1', 'Q2', 'Q3'],
|
|
271
|
+
series: [{ name: 'Sales', values: [100, 120, 150] }]
|
|
272
|
+
});
|
|
273
|
+
```
|
|
276
274
|
|
|
277
|
-
|
|
275
|
+
#### `replaceChartSeries(chartId, seriesIndex, newSeriesData)`
|
|
276
|
+
Replaces values and name of a single series.
|
|
277
|
+
```js
|
|
278
|
+
ppt.replaceChartSeries('sales-chart', 0, {
|
|
279
|
+
name: 'Updated Series Name',
|
|
280
|
+
values: [80, 95, 110]
|
|
281
|
+
});
|
|
282
|
+
```
|
|
278
283
|
|
|
279
|
-
|
|
284
|
+
#### `updateChartTitle(chartId, title)`
|
|
285
|
+
Updates the chart's title.
|
|
286
|
+
```js
|
|
287
|
+
ppt.updateChartTitle('sales-chart', 'Quarterly Revenue Performance');
|
|
288
|
+
```
|
|
280
289
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
| Chart update | ~5ms |
|
|
287
|
-
| Table update | ~3ms |
|
|
290
|
+
#### `updateChartCategories(chartId, categories)`
|
|
291
|
+
Updates the chart categories.
|
|
292
|
+
```js
|
|
293
|
+
ppt.updateChartCategories('sales-chart', ['Jan', 'Feb', 'Mar']);
|
|
294
|
+
```
|
|
288
295
|
|
|
289
|
-
|
|
296
|
+
#### `getCharts()`
|
|
297
|
+
Returns chart metadata from the slide.
|
|
298
|
+
```js
|
|
299
|
+
const charts = ppt.getCharts();
|
|
300
|
+
```
|
|
290
301
|
|
|
291
302
|
---
|
|
292
303
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
### Placeholders not being replaced
|
|
304
|
+
### Text Features
|
|
296
305
|
|
|
297
|
-
|
|
298
|
-
|
|
306
|
+
#### `replaceTextByTag(tag, value, options)`
|
|
307
|
+
Replaces placeholders with custom values.
|
|
308
|
+
```js
|
|
309
|
+
ppt.replaceTextByTag('username', 'Alice Cooper');
|
|
310
|
+
```
|
|
299
311
|
|
|
300
|
-
|
|
301
|
-
|
|
312
|
+
#### `replaceMultiple(replacements, options)`
|
|
313
|
+
Performs multiple text tag replacements.
|
|
314
|
+
```js
|
|
315
|
+
ppt.replaceMultiple({
|
|
316
|
+
'date': '2026-06-02',
|
|
317
|
+
'location': 'New York'
|
|
318
|
+
});
|
|
302
319
|
```
|
|
303
320
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
321
|
+
#### `findText(text)`
|
|
322
|
+
Searches for text in slide shape runs.
|
|
323
|
+
```js
|
|
324
|
+
const matches = ppt.findText('DeepMind');
|
|
307
325
|
```
|
|
308
326
|
|
|
309
|
-
|
|
327
|
+
#### `getTextElements()`
|
|
328
|
+
Gets all raw text segments in the selected slide.
|
|
329
|
+
```js
|
|
330
|
+
const elements = ppt.getTextElements();
|
|
331
|
+
```
|
|
310
332
|
|
|
311
|
-
|
|
333
|
+
---
|
|
312
334
|
|
|
313
|
-
|
|
314
|
-
Use `--inspect --charts` to see all chart names:
|
|
335
|
+
### Shape Features
|
|
315
336
|
|
|
316
|
-
|
|
317
|
-
|
|
337
|
+
#### `updateShapeText(shapeId, text)`
|
|
338
|
+
Updates text inside a shapes run.
|
|
339
|
+
```js
|
|
340
|
+
ppt.updateShapeText('HeaderShape', 'Updated Slide Header');
|
|
318
341
|
```
|
|
319
342
|
|
|
320
|
-
|
|
343
|
+
#### `cloneShape(shapeId, newShapeId, options)`
|
|
344
|
+
Clones a shape and places it with offsets.
|
|
345
|
+
```js
|
|
346
|
+
ppt.cloneShape('HeaderShape', 'HeaderShapeCopy', {
|
|
347
|
+
offsetX: 1.0, // Offset X in inches
|
|
348
|
+
offsetY: 0.5, // Offset Y in inches
|
|
349
|
+
width: 5.0, // Resize width
|
|
350
|
+
height: 2.0 // Resize height
|
|
351
|
+
});
|
|
352
|
+
```
|
|
321
353
|
|
|
322
|
-
|
|
354
|
+
#### `deleteShape(shapeId)`
|
|
355
|
+
Deletes a shape.
|
|
356
|
+
```js
|
|
357
|
+
ppt.deleteShape('HeaderShapeCopy');
|
|
358
|
+
```
|
|
323
359
|
|
|
324
|
-
|
|
325
|
-
|
|
360
|
+
#### `getShapes()`
|
|
361
|
+
Lists shapes on the slide.
|
|
362
|
+
```js
|
|
363
|
+
const shapes = ppt.getShapes();
|
|
326
364
|
```
|
|
327
365
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
- Invalid XML characters in replacement values
|
|
366
|
+
---
|
|
367
|
+
|
|
368
|
+
### Image Features
|
|
332
369
|
|
|
333
|
-
|
|
370
|
+
#### `replaceImage(imageIdOrName, sourcePathOrBuffer)`
|
|
371
|
+
Replaces an image file binary, keeping the layout.
|
|
372
|
+
```js
|
|
373
|
+
await ppt.replaceImage('LogoImage', 'path/to/new-logo.png');
|
|
374
|
+
```
|
|
334
375
|
|
|
335
|
-
|
|
336
|
-
|
|
376
|
+
#### `addImage(sourcePathOrBuffer, options)`
|
|
377
|
+
Embeds a new image with layout options.
|
|
378
|
+
```js
|
|
379
|
+
await ppt.addImage('path/to/badge.png', {
|
|
380
|
+
x: 2.0, // Position X (inches)
|
|
381
|
+
y: 1.5, // Position Y (inches)
|
|
382
|
+
width: 3.0, // Width (inches)
|
|
383
|
+
height: 3.0 // Height (inches)
|
|
384
|
+
});
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
#### `removeImage(imageIdOrName)`
|
|
388
|
+
Deletes an image.
|
|
389
|
+
```js
|
|
390
|
+
ppt.removeImage('Picture 1002');
|
|
337
391
|
```
|
|
338
392
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
393
|
+
#### `getImages()`
|
|
394
|
+
Lists images inside the slide.
|
|
395
|
+
```js
|
|
396
|
+
const images = ppt.getImages();
|
|
397
|
+
```
|
|
343
398
|
|
|
344
399
|
---
|
|
345
400
|
|
|
346
|
-
|
|
401
|
+
### Validation System
|
|
347
402
|
|
|
348
|
-
|
|
403
|
+
#### `validatePresentation()`
|
|
404
|
+
Audits the complete presentation.
|
|
405
|
+
```js
|
|
406
|
+
const report = await ppt.validatePresentation();
|
|
407
|
+
console.log('Errors:', report.errors);
|
|
408
|
+
console.log('Warnings:', report.warnings);
|
|
409
|
+
```
|
|
349
410
|
|
|
411
|
+
#### `validateSlide(slideIndex)`
|
|
412
|
+
Validates slide XML structure.
|
|
350
413
|
```js
|
|
351
|
-
|
|
414
|
+
const report = await ppt.validateSlide(1);
|
|
415
|
+
```
|
|
352
416
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
this.useSlide(slideNum);
|
|
417
|
+
#### `validateTable(tableId)`
|
|
418
|
+
Audits columns and duplicate rowIds in a table.
|
|
419
|
+
```js
|
|
420
|
+
const report = await ppt.validateTable('sales-table');
|
|
421
|
+
```
|
|
359
422
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
423
|
+
#### `validateRelationships(partPath)`
|
|
424
|
+
Audits `.rels` relationship references.
|
|
425
|
+
```js
|
|
426
|
+
const report = ppt.validateRelationships('ppt/slides/slide1.xml');
|
|
427
|
+
```
|
|
364
428
|
|
|
365
|
-
|
|
429
|
+
---
|
|
366
430
|
|
|
367
|
-
|
|
368
|
-
this.updateChart(data.chart.id, data.chart);
|
|
369
|
-
}
|
|
431
|
+
## β‘ Performance Benchmarks
|
|
370
432
|
|
|
371
|
-
|
|
372
|
-
}
|
|
373
|
-
}
|
|
433
|
+
Tested on a 50-slide presentation template:
|
|
374
434
|
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
```
|
|
435
|
+
| Operation | Average Duration |
|
|
436
|
+
|---|---|
|
|
437
|
+
| Load presentation | ~120ms |
|
|
438
|
+
| Replace 20 text tags | ~2ms |
|
|
439
|
+
| Audit presentation structure | ~15ms |
|
|
440
|
+
| Update table rows (10 rows) | ~3ms |
|
|
441
|
+
| Rebuild ZIP and Save | ~80ms |
|
|
383
442
|
|
|
384
443
|
---
|
|
385
444
|
|
|
386
|
-
##
|
|
445
|
+
## β FAQ
|
|
446
|
+
|
|
447
|
+
#### Why use this over libraries like pptxgenjs or officegen?
|
|
448
|
+
Those libraries generate presentations from scratch in code. `node-pptx-templater` is a **templating** engine. You create a beautiful template inside MS PowerPoint (applying themes, layout grids, animations, or styling), and then use this library to dynamically populate slides, update tables, and refresh chart values while preserving the design.
|
|
387
449
|
|
|
388
|
-
|
|
389
|
-
-
|
|
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)
|
|
450
|
+
#### How is chart styling preserved?
|
|
451
|
+
We update only the `<c:cat>` (categories), `<c:val>` (values) XML nodes, and the underlying data sheet inside the embedded Excel workbook. PowerPoint reads these updated values and uses the template's pre-configured colors, font layouts, labels, and axes.
|
|
396
452
|
|
|
397
453
|
---
|
|
398
454
|
|
|
399
455
|
## π€ Contributing
|
|
400
456
|
|
|
401
|
-
See [CONTRIBUTING.md](./CONTRIBUTING.md)
|
|
457
|
+
See [CONTRIBUTING.md](./CONTRIBUTING.md).
|
|
402
458
|
|
|
403
|
-
Quick steps:
|
|
404
459
|
```bash
|
|
405
460
|
git clone https://github.com/jsuyog2/node-pptx-templater.git
|
|
406
461
|
cd node-pptx-templater
|
|
@@ -412,4 +467,4 @@ npm test
|
|
|
412
467
|
|
|
413
468
|
## π License
|
|
414
469
|
|
|
415
|
-
MIT
|
|
470
|
+
MIT Β© [node-pptx-templater contributors](./LICENSE)
|