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/src/parsers/XMLParser.js
CHANGED
|
@@ -20,11 +20,8 @@
|
|
|
20
20
|
* mc: — Markup Compatibility
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
|
-
const { XMLParser: FastXMLParser, XMLBuilder } = require('fast-xml-parser')
|
|
24
|
-
const {
|
|
25
|
-
const { PPTXError } = require('../utils/errors.js');
|
|
26
|
-
|
|
27
|
-
const logger = createLogger('XMLParser');
|
|
23
|
+
const { XMLParser: FastXMLParser, XMLBuilder } = require('fast-xml-parser')
|
|
24
|
+
const { PPTXError } = require('../utils/errors.js')
|
|
28
25
|
|
|
29
26
|
/**
|
|
30
27
|
* Parser configuration for fast-xml-parser.
|
|
@@ -67,10 +64,10 @@ const PARSER_OPTIONS = {
|
|
|
67
64
|
'Default',
|
|
68
65
|
'p14:sldId',
|
|
69
66
|
'p14:section',
|
|
70
|
-
]
|
|
71
|
-
return alwaysArrayPaths.some(path => jpath.endsWith(path) || name === path.split('.').pop())
|
|
67
|
+
]
|
|
68
|
+
return alwaysArrayPaths.some(path => jpath.endsWith(path) || name === path.split('.').pop())
|
|
72
69
|
},
|
|
73
|
-
}
|
|
70
|
+
}
|
|
74
71
|
|
|
75
72
|
/**
|
|
76
73
|
* Builder configuration for XMLBuilder.
|
|
@@ -85,7 +82,7 @@ const BUILDER_OPTIONS = {
|
|
|
85
82
|
suppressEmptyNode: false,
|
|
86
83
|
format: false, // No extra whitespace — PPTX is sensitive to whitespace in some cases
|
|
87
84
|
processEntities: true,
|
|
88
|
-
}
|
|
85
|
+
}
|
|
89
86
|
|
|
90
87
|
/**
|
|
91
88
|
* @class XMLParser
|
|
@@ -96,17 +93,17 @@ class XMLParser {
|
|
|
96
93
|
* @private
|
|
97
94
|
* @type {FastXMLParser}
|
|
98
95
|
*/
|
|
99
|
-
#parser
|
|
96
|
+
#parser
|
|
100
97
|
|
|
101
98
|
/**
|
|
102
99
|
* @private
|
|
103
100
|
* @type {XMLBuilder}
|
|
104
101
|
*/
|
|
105
|
-
#builder
|
|
102
|
+
#builder
|
|
106
103
|
|
|
107
104
|
constructor() {
|
|
108
|
-
this.#parser = new FastXMLParser(PARSER_OPTIONS)
|
|
109
|
-
this.#builder = new XMLBuilder(BUILDER_OPTIONS)
|
|
105
|
+
this.#parser = new FastXMLParser(PARSER_OPTIONS)
|
|
106
|
+
this.#builder = new XMLBuilder(BUILDER_OPTIONS)
|
|
110
107
|
}
|
|
111
108
|
|
|
112
109
|
/**
|
|
@@ -123,13 +120,13 @@ class XMLParser {
|
|
|
123
120
|
*/
|
|
124
121
|
parse(xmlString, context = '') {
|
|
125
122
|
if (!xmlString || typeof xmlString !== 'string') {
|
|
126
|
-
throw new PPTXError(`Invalid XML input${context ? ` (${context})` : ''}`)
|
|
123
|
+
throw new PPTXError(`Invalid XML input${context ? ` (${context})` : ''}`)
|
|
127
124
|
}
|
|
128
125
|
|
|
129
126
|
try {
|
|
130
|
-
return this.#parser.parse(xmlString)
|
|
127
|
+
return this.#parser.parse(xmlString)
|
|
131
128
|
} catch (err) {
|
|
132
|
-
throw new PPTXError(`XML parse error${context ? ` in ${context}` : ''}: ${err.message}`, err)
|
|
129
|
+
throw new PPTXError(`XML parse error${context ? ` in ${context}` : ''}: ${err.message}`, err)
|
|
133
130
|
}
|
|
134
131
|
}
|
|
135
132
|
|
|
@@ -145,10 +142,10 @@ class XMLParser {
|
|
|
145
142
|
*/
|
|
146
143
|
build(obj, xmlDeclaration = '') {
|
|
147
144
|
try {
|
|
148
|
-
const xml = this.#builder.build(obj)
|
|
149
|
-
return xmlDeclaration ? `${xmlDeclaration}\n${xml}` : xml
|
|
145
|
+
const xml = this.#builder.build(obj)
|
|
146
|
+
return xmlDeclaration ? `${xmlDeclaration}\n${xml}` : xml
|
|
150
147
|
} catch (err) {
|
|
151
|
-
throw new PPTXError(`XML build error: ${err.message}`, err)
|
|
148
|
+
throw new PPTXError(`XML build error: ${err.message}`, err)
|
|
152
149
|
}
|
|
153
150
|
}
|
|
154
151
|
|
|
@@ -159,8 +156,8 @@ class XMLParser {
|
|
|
159
156
|
* @returns {string} Declaration line or empty string.
|
|
160
157
|
*/
|
|
161
158
|
extractDeclaration(xmlString) {
|
|
162
|
-
const match = xmlString.match(/^<\?xml[^>]+\?>/)
|
|
163
|
-
return match ? match[0] : '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
|
|
159
|
+
const match = xmlString.match(/^<\?xml[^>]+\?>/)
|
|
160
|
+
return match ? match[0] : '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
|
|
164
161
|
}
|
|
165
162
|
|
|
166
163
|
/**
|
|
@@ -171,7 +168,7 @@ class XMLParser {
|
|
|
171
168
|
* @returns {Object} Deep clone.
|
|
172
169
|
*/
|
|
173
170
|
deepClone(obj) {
|
|
174
|
-
return JSON.parse(JSON.stringify(obj))
|
|
171
|
+
return JSON.parse(JSON.stringify(obj))
|
|
175
172
|
}
|
|
176
173
|
|
|
177
174
|
/**
|
|
@@ -186,25 +183,25 @@ class XMLParser {
|
|
|
186
183
|
* const runs = parser.findAll(slideObj, 'p:cSld.p:spTree.p:sp.p:txBody.a:p.a:r');
|
|
187
184
|
*/
|
|
188
185
|
findAll(obj, path) {
|
|
189
|
-
const keys = path.split('.')
|
|
190
|
-
let current = [obj]
|
|
186
|
+
const keys = path.split('.')
|
|
187
|
+
let current = [obj]
|
|
191
188
|
|
|
192
189
|
for (const key of keys) {
|
|
193
|
-
const next = []
|
|
190
|
+
const next = []
|
|
194
191
|
for (const node of current) {
|
|
195
192
|
if (node && typeof node === 'object') {
|
|
196
|
-
const val = node[key]
|
|
193
|
+
const val = node[key]
|
|
197
194
|
if (Array.isArray(val)) {
|
|
198
|
-
next.push(...val)
|
|
195
|
+
next.push(...val)
|
|
199
196
|
} else if (val !== undefined) {
|
|
200
|
-
next.push(val)
|
|
197
|
+
next.push(val)
|
|
201
198
|
}
|
|
202
199
|
}
|
|
203
200
|
}
|
|
204
|
-
current = next
|
|
201
|
+
current = next
|
|
205
202
|
}
|
|
206
203
|
|
|
207
|
-
return current
|
|
204
|
+
return current
|
|
208
205
|
}
|
|
209
206
|
|
|
210
207
|
/**
|
|
@@ -215,7 +212,7 @@ class XMLParser {
|
|
|
215
212
|
* @returns {*} First matching node or undefined.
|
|
216
213
|
*/
|
|
217
214
|
getNode(obj, path) {
|
|
218
|
-
return this.findAll(obj, path)[0]
|
|
215
|
+
return this.findAll(obj, path)[0]
|
|
219
216
|
}
|
|
220
217
|
|
|
221
218
|
/**
|
|
@@ -227,18 +224,18 @@ class XMLParser {
|
|
|
227
224
|
* @param {*} value - Value to set.
|
|
228
225
|
*/
|
|
229
226
|
setNode(obj, path, value) {
|
|
230
|
-
const keys = path.split('.')
|
|
231
|
-
let current = obj
|
|
227
|
+
const keys = path.split('.')
|
|
228
|
+
let current = obj
|
|
232
229
|
|
|
233
230
|
for (let i = 0; i < keys.length - 1; i++) {
|
|
234
|
-
const key = keys[i]
|
|
231
|
+
const key = keys[i]
|
|
235
232
|
if (!current[key] || typeof current[key] !== 'object') {
|
|
236
|
-
current[key] = {}
|
|
233
|
+
current[key] = {}
|
|
237
234
|
}
|
|
238
|
-
current = Array.isArray(current[key]) ? current[key][0] : current[key]
|
|
235
|
+
current = Array.isArray(current[key]) ? current[key][0] : current[key]
|
|
239
236
|
}
|
|
240
237
|
|
|
241
|
-
current[keys[keys.length - 1]] = value
|
|
238
|
+
current[keys[keys.length - 1]] = value
|
|
242
239
|
}
|
|
243
240
|
|
|
244
241
|
/**
|
|
@@ -252,9 +249,9 @@ class XMLParser {
|
|
|
252
249
|
* @returns {string} Modified XML string.
|
|
253
250
|
*/
|
|
254
251
|
replaceInXml(xmlString, search, replace, all = true) {
|
|
255
|
-
const escaped = search.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
256
|
-
const flags = all ? 'g' : ''
|
|
257
|
-
return xmlString.replace(new RegExp(escaped, flags), replace)
|
|
252
|
+
const escaped = search.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
253
|
+
const flags = all ? 'g' : ''
|
|
254
|
+
return xmlString.replace(new RegExp(escaped, flags), replace)
|
|
258
255
|
}
|
|
259
256
|
|
|
260
257
|
/**
|
|
@@ -265,13 +262,13 @@ class XMLParser {
|
|
|
265
262
|
* @returns {string[]} Array of text strings found in the slide.
|
|
266
263
|
*/
|
|
267
264
|
extractTextContent(xmlString) {
|
|
268
|
-
const texts = []
|
|
269
|
-
const textPattern = /<a:t>([^<]*)<\/a:t>/g
|
|
270
|
-
let match
|
|
265
|
+
const texts = []
|
|
266
|
+
const textPattern = /<a:t>([^<]*)<\/a:t>/g
|
|
267
|
+
let match
|
|
271
268
|
while ((match = textPattern.exec(xmlString)) !== null) {
|
|
272
|
-
if (match[1].trim()) texts.push(match[1])
|
|
269
|
+
if (match[1].trim()) texts.push(match[1])
|
|
273
270
|
}
|
|
274
|
-
return texts
|
|
271
|
+
return texts
|
|
275
272
|
}
|
|
276
273
|
|
|
277
274
|
/**
|
|
@@ -282,14 +279,14 @@ class XMLParser {
|
|
|
282
279
|
*/
|
|
283
280
|
validate(xmlString) {
|
|
284
281
|
try {
|
|
285
|
-
this.parse(xmlString)
|
|
286
|
-
return { valid: true, error: null }
|
|
282
|
+
this.parse(xmlString)
|
|
283
|
+
return { valid: true, error: null }
|
|
287
284
|
} catch (err) {
|
|
288
|
-
return { valid: false, error: err.message }
|
|
285
|
+
return { valid: false, error: err.message }
|
|
289
286
|
}
|
|
290
287
|
}
|
|
291
288
|
}
|
|
292
289
|
|
|
293
290
|
module.exports = {
|
|
294
|
-
XMLParser
|
|
295
|
-
}
|
|
291
|
+
XMLParser,
|
|
292
|
+
}
|