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.
Files changed (37) hide show
  1. package/README.md +336 -281
  2. package/package.json +6 -6
  3. package/src/cli/commands/build.js +32 -31
  4. package/src/cli/commands/debug.js +25 -24
  5. package/src/cli/commands/extract.js +23 -21
  6. package/src/cli/commands/inspect.js +25 -23
  7. package/src/cli/commands/validate.js +19 -17
  8. package/src/cli/index.js +45 -43
  9. package/src/core/OutputWriter.js +81 -78
  10. package/src/core/PPTXTemplater.js +859 -274
  11. package/src/core/TemplateEngine.js +69 -71
  12. package/src/core/ValidationEngine.js +246 -0
  13. package/src/index.js +51 -15
  14. package/src/managers/ChartManager.js +197 -70
  15. package/src/managers/ContentTypesManager.js +51 -45
  16. package/src/managers/HyperlinkManager.js +148 -142
  17. package/src/managers/ImageManager.js +336 -0
  18. package/src/managers/MediaManager.js +64 -81
  19. package/src/managers/RelationshipManager.js +102 -96
  20. package/src/managers/ShapeManager.js +340 -0
  21. package/src/managers/SlideManager.js +410 -311
  22. package/src/managers/TableManager.js +981 -262
  23. package/src/managers/TextManager.js +197 -0
  24. package/src/managers/ZipManager.js +71 -69
  25. package/src/managers/charts/ChartCacheGenerator.js +77 -58
  26. package/src/managers/charts/ChartParser.js +11 -13
  27. package/src/managers/charts/ChartRelationshipManager.js +14 -10
  28. package/src/managers/charts/ChartWorkbookUpdater.js +61 -56
  29. package/src/parsers/XMLParser.js +50 -49
  30. package/src/templates/blankPptx.js +3 -1
  31. package/src/templates/slideTemplate.js +31 -32
  32. package/src/utils/contentTypesHelper.js +41 -53
  33. package/src/utils/errors.js +33 -23
  34. package/src/utils/idUtils.js +23 -15
  35. package/src/utils/logger.js +21 -15
  36. package/src/utils/relationshipUtils.js +28 -22
  37. package/src/utils/xmlUtils.js +37 -29
@@ -18,16 +18,16 @@
18
18
  * generateRelationshipId(['rId1', 'rId3']) // → 'rId4'
19
19
  * generateRelationshipId([]) // → 'rId1'
20
20
  */
21
- export function generateRelationshipId(existingIds) {
22
- if (!existingIds || existingIds.length === 0) return 'rId1';
21
+ function generateRelationshipId(existingIds) {
22
+ if (!existingIds || existingIds.length === 0) return 'rId1'
23
23
 
24
24
  const maxNum = existingIds.reduce((max, id) => {
25
- const match = /^rId(\d+)$/.exec(id);
26
- if (!match) return max;
27
- return Math.max(max, parseInt(match[1], 10));
28
- }, 0);
25
+ const match = /^rId(\d+)$/.exec(id)
26
+ if (!match) return max
27
+ return Math.max(max, parseInt(match[1], 10))
28
+ }, 0)
29
29
 
30
- return `rId${maxNum + 1}`;
30
+ return `rId${maxNum + 1}`
31
31
  }
32
32
 
33
33
  /**
@@ -40,9 +40,9 @@ export function generateRelationshipId(existingIds) {
40
40
  * parseRelationshipId('rId5') // → 5
41
41
  * parseRelationshipId('foo') // → -1
42
42
  */
43
- export function parseRelationshipId(rId) {
44
- const match = /^rId(\d+)$/.exec(rId);
45
- return match ? parseInt(match[1], 10) : -1;
43
+ function parseRelationshipId(rId) {
44
+ const match = /^rId(\d+)$/.exec(rId)
45
+ return match ? parseInt(match[1], 10) : -1
46
46
  }
47
47
 
48
48
  /**
@@ -51,8 +51,8 @@ export function parseRelationshipId(rId) {
51
51
  * @param {string} str
52
52
  * @returns {boolean}
53
53
  */
54
- export function isValidRelationshipId(str) {
55
- return /^rId\d+$/.test(str);
54
+ function isValidRelationshipId(str) {
55
+ return /^rId\d+$/.test(str)
56
56
  }
57
57
 
58
58
  /**
@@ -66,24 +66,30 @@ export function isValidRelationshipId(str) {
66
66
  * @example
67
67
  * remapRelationshipIds(xml, new Map([['rId1', 'rId5'], ['rId2', 'rId6']]));
68
68
  */
69
- export function remapRelationshipIds(xml, idMap) {
70
- let updated = xml;
69
+ function remapRelationshipIds(xml, idMap) {
70
+ let updated = xml
71
71
 
72
72
  // Sort by length descending to avoid partial replacements (e.g., rId1 replacing part of rId10)
73
- const sortedEntries = Array.from(idMap.entries())
74
- .sort(([a], [b]) => b.length - a.length);
73
+ const sortedEntries = Array.from(idMap.entries()).sort(([a], [b]) => b.length - a.length)
75
74
 
76
75
  for (const [oldId, newId] of sortedEntries) {
77
76
  // Replace rId references in attribute values: r:id="rId1", r:embed="rId1"
78
- const pattern = new RegExp(`(r:[a-zA-Z]+=")${oldId}(")|rId="${oldId}(")`, 'g');
77
+ const pattern = new RegExp(`(r:[a-zA-Z]+=")${oldId}(")|rId="${oldId}(")`, 'g')
79
78
  updated = updated.replace(pattern, (match, pre, post) => {
80
- if (pre) return `${pre}${newId}${post}`;
81
- return match.replace(oldId, newId);
82
- });
79
+ if (pre) return `${pre}${newId}${post}`
80
+ return match.replace(oldId, newId)
81
+ })
83
82
 
84
83
  // Simple global replace as fallback
85
- updated = updated.split(`"${oldId}"`).join(`"${newId}"`);
84
+ updated = updated.split(`"${oldId}"`).join(`"${newId}"`)
86
85
  }
87
86
 
88
- return updated;
87
+ return updated
88
+ }
89
+
90
+ module.exports = {
91
+ generateRelationshipId,
92
+ parseRelationshipId,
93
+ isValidRelationshipId,
94
+ remapRelationshipIds,
89
95
  }
@@ -5,9 +5,9 @@
5
5
  * attempt automatic repairs for common PPTX corruption issues.
6
6
  */
7
7
 
8
- import { XMLParser } from '../parsers/XMLParser.js';
8
+ const { XMLParser } = require('../parsers/XMLParser.js')
9
9
 
10
- const parser = new XMLParser();
10
+ const parser = new XMLParser()
11
11
 
12
12
  /**
13
13
  * Validates that an XML string is well-formed.
@@ -19,8 +19,8 @@ const parser = new XMLParser();
19
19
  * const { valid, error } = validateXML(xml);
20
20
  * if (!valid) console.error('XML error:', error);
21
21
  */
22
- export function validateXML(xmlString) {
23
- return parser.validate(xmlString);
22
+ function validateXML(xmlString) {
23
+ return parser.validate(xmlString)
24
24
  }
25
25
 
26
26
  /**
@@ -38,40 +38,40 @@ export function validateXML(xmlString) {
38
38
  * const { xml, repaired, changes } = repairXML(brokenXml);
39
39
  * if (repaired) console.log('Repaired:', changes);
40
40
  */
41
- export function repairXML(xmlString) {
42
- const changes = [];
43
- let xml = xmlString;
41
+ function repairXML(xmlString) {
42
+ const changes = []
43
+ let xml = xmlString
44
44
 
45
45
  // Fix 1: Remove invalid XML control characters
46
- const before = xml;
47
- xml = xml.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F]/g, '');
48
- if (xml !== before) changes.push('Removed invalid control characters');
46
+ const before = xml
47
+ xml = xml.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F]/g, '')
48
+ if (xml !== before) changes.push('Removed invalid control characters')
49
49
 
50
50
  // Fix 2: Fix unescaped ampersands in text content (not in entities)
51
51
  // Match & not followed by valid entity patterns
52
- const fixedAmp = xml.replace(/&(?!amp;|lt;|gt;|quot;|apos;|#\d+;|#x[0-9a-fA-F]+;)/g, '&');
52
+ const fixedAmp = xml.replace(/&(?!amp;|lt;|gt;|quot;|apos;|#\d+;|#x[0-9a-fA-F]+;)/g, '&')
53
53
  if (fixedAmp !== xml) {
54
- xml = fixedAmp;
55
- changes.push('Escaped unescaped ampersands');
54
+ xml = fixedAmp
55
+ changes.push('Escaped unescaped ampersands')
56
56
  }
57
57
 
58
58
  // Fix 3: Replace null bytes
59
59
  if (xml.includes('\x00')) {
60
- xml = xml.replace(/\x00/g, '');
61
- changes.push('Removed null bytes');
60
+ xml = xml.replace(/\x00/g, '')
61
+ changes.push('Removed null bytes')
62
62
  }
63
63
 
64
64
  // Fix 4: Ensure XML declaration is present
65
65
  if (!xml.trimStart().startsWith('<?xml')) {
66
- xml = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n' + xml;
67
- changes.push('Added missing XML declaration');
66
+ xml = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n' + xml
67
+ changes.push('Added missing XML declaration')
68
68
  }
69
69
 
70
70
  return {
71
71
  xml,
72
72
  repaired: changes.length > 0,
73
73
  changes,
74
- };
74
+ }
75
75
  }
76
76
 
77
77
  /**
@@ -81,8 +81,8 @@ export function repairXML(xmlString) {
81
81
  * @param {string} elementName - Element tag name (e.g., 'a:tbl').
82
82
  * @returns {boolean}
83
83
  */
84
- export function xmlContainsElement(xmlString, elementName) {
85
- return xmlString.includes(`<${elementName}`) || xmlString.includes(`<${elementName}>`);
84
+ function xmlContainsElement(xmlString, elementName) {
85
+ return xmlString.includes(`<${elementName}`) || xmlString.includes(`<${elementName}>`)
86
86
  }
87
87
 
88
88
  /**
@@ -92,9 +92,9 @@ export function xmlContainsElement(xmlString, elementName) {
92
92
  * @param {string} elementName
93
93
  * @returns {number}
94
94
  */
95
- export function countElements(xmlString, elementName) {
96
- const pattern = new RegExp(`<${elementName}[\\s>/]`, 'g');
97
- return (xmlString.match(pattern) || []).length;
95
+ function countElements(xmlString, elementName) {
96
+ const pattern = new RegExp(`<${elementName}[\\s>/]`, 'g')
97
+ return (xmlString.match(pattern) || []).length
98
98
  }
99
99
 
100
100
  /**
@@ -104,12 +104,20 @@ export function countElements(xmlString, elementName) {
104
104
  * @param {string} attrName - Attribute name (e.g., 'r:id', 'name').
105
105
  * @returns {string[]} Array of attribute values found.
106
106
  */
107
- export function extractAttributeValues(xmlString, attrName) {
108
- const pattern = new RegExp(`${attrName.replace(':', '\\:')}="([^"]*)"`, 'g');
109
- const values = [];
110
- let match;
107
+ function extractAttributeValues(xmlString, attrName) {
108
+ const pattern = new RegExp(`${attrName.replace(':', '\\:')}="([^"]*)"`, 'g')
109
+ const values = []
110
+ let match
111
111
  while ((match = pattern.exec(xmlString)) !== null) {
112
- values.push(match[1]);
112
+ values.push(match[1])
113
113
  }
114
- return values;
114
+ return values
115
+ }
116
+
117
+ module.exports = {
118
+ validateXML,
119
+ repairXML,
120
+ xmlContainsElement,
121
+ countElements,
122
+ extractAttributeValues,
115
123
  }