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/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-pptx-templater",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.0.4",
|
|
4
|
+
"description": "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
5
|
"main": "./src/index.js",
|
|
6
6
|
"type": "commonjs",
|
|
7
7
|
"exports": {
|
|
@@ -43,7 +43,16 @@
|
|
|
43
43
|
"report",
|
|
44
44
|
"generator",
|
|
45
45
|
"nodejs",
|
|
46
|
-
"
|
|
46
|
+
"powerpoint-automation",
|
|
47
|
+
"pptx-template-engine",
|
|
48
|
+
"merge-cells",
|
|
49
|
+
"table-merge",
|
|
50
|
+
"chart-update",
|
|
51
|
+
"dynamic-slides",
|
|
52
|
+
"mail-merge",
|
|
53
|
+
"report-generator",
|
|
54
|
+
"xml-manipulation",
|
|
55
|
+
"pptx-editor"
|
|
47
56
|
],
|
|
48
57
|
"author": {
|
|
49
58
|
"name": "node-pptx-templater contributors"
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
* @fileoverview `build` CLI command — builds a PPTX from a template + JSON data.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
const chalk = require('chalk')
|
|
6
|
-
const ora = require('ora')
|
|
7
|
-
const { readFileSync } = require('fs')
|
|
8
|
-
const { resolve } = require('path')
|
|
9
|
-
const { PPTXTemplater } = require('../../index.js')
|
|
5
|
+
const chalk = require('chalk')
|
|
6
|
+
const ora = require('ora')
|
|
7
|
+
const { readFileSync } = require('fs')
|
|
8
|
+
const { resolve } = require('path')
|
|
9
|
+
const { PPTXTemplater } = require('../../index.js')
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Executes the `build` CLI command.
|
|
@@ -16,66 +16,65 @@ const { PPTXTemplater } = require('../../index.js');
|
|
|
16
16
|
* @param {Object} opts - CLI options.
|
|
17
17
|
*/
|
|
18
18
|
async function buildCommand(templatePath, outputPath, opts) {
|
|
19
|
-
const spinner = ora(`Loading template: ${templatePath}`).start()
|
|
19
|
+
const spinner = ora(`Loading template: ${templatePath}`).start()
|
|
20
20
|
|
|
21
21
|
try {
|
|
22
22
|
// Load the template
|
|
23
|
-
const ppt = await PPTXTemplater.load(resolve(templatePath))
|
|
24
|
-
spinner.succeed(`Loaded template (${ppt.slideCount} slides)`)
|
|
23
|
+
const ppt = await PPTXTemplater.load(resolve(templatePath))
|
|
24
|
+
spinner.succeed(`Loaded template (${ppt.slideCount} slides)`)
|
|
25
25
|
|
|
26
26
|
// Apply slide filter if provided
|
|
27
27
|
if (opts.slide) {
|
|
28
|
-
const slideNumbers = opts.slide.split(',').map(n => parseInt(n.trim(), 10))
|
|
29
|
-
ppt.useSlide(...slideNumbers)
|
|
30
|
-
console.log(chalk.cyan(` → Using slides: ${slideNumbers.join(', ')}`))
|
|
28
|
+
const slideNumbers = opts.slide.split(',').map(n => parseInt(n.trim(), 10))
|
|
29
|
+
ppt.useSlide(...slideNumbers)
|
|
30
|
+
console.log(chalk.cyan(` → Using slides: ${slideNumbers.join(', ')}`))
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
// Apply data from JSON file if provided
|
|
34
34
|
if (opts.data) {
|
|
35
|
-
spinner.start(`Loading data: ${opts.data}`)
|
|
36
|
-
const data = JSON.parse(readFileSync(resolve(opts.data), 'utf-8'))
|
|
35
|
+
spinner.start(`Loading data: ${opts.data}`)
|
|
36
|
+
const data = JSON.parse(readFileSync(resolve(opts.data), 'utf-8'))
|
|
37
37
|
|
|
38
38
|
// Apply text replacements
|
|
39
39
|
if (data.text) {
|
|
40
|
-
ppt.replaceText(data.text)
|
|
41
|
-
console.log(chalk.cyan(` → Replaced ${Object.keys(data.text).length} text placeholder(s)`))
|
|
40
|
+
ppt.replaceText(data.text)
|
|
41
|
+
console.log(chalk.cyan(` → Replaced ${Object.keys(data.text).length} text placeholder(s)`))
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
// Apply chart updates
|
|
45
45
|
if (data.charts) {
|
|
46
46
|
for (const [chartId, chartData] of Object.entries(data.charts)) {
|
|
47
|
-
ppt.updateChart(chartId, chartData)
|
|
48
|
-
console.log(chalk.cyan(` → Updated chart: ${chartId}`))
|
|
47
|
+
ppt.updateChart(chartId, chartData)
|
|
48
|
+
console.log(chalk.cyan(` → Updated chart: ${chartId}`))
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
// Apply table updates
|
|
53
53
|
if (data.tables) {
|
|
54
54
|
for (const [tableId, tableData] of Object.entries(data.tables)) {
|
|
55
|
-
ppt.updateTable(tableId, tableData)
|
|
56
|
-
console.log(chalk.cyan(` → Updated table: ${tableId}`))
|
|
55
|
+
ppt.updateTable(tableId, tableData)
|
|
56
|
+
console.log(chalk.cyan(` → Updated table: ${tableId}`))
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
spinner.succeed('Data applied')
|
|
60
|
+
spinner.succeed('Data applied')
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
// Save output
|
|
64
|
-
spinner.start(`Saving to: ${outputPath}`)
|
|
65
|
-
await ppt.saveToFile(resolve(outputPath))
|
|
66
|
-
spinner.succeed(chalk.green(`✓ Saved: ${outputPath}`))
|
|
67
|
-
|
|
68
|
-
console.log(chalk.dim(`\n Slides: ${ppt.slideCount}`));
|
|
69
|
-
console.log(chalk.dim(` Template: ${templatePath}`));
|
|
70
|
-
console.log(chalk.dim(` Output: ${outputPath}\n`));
|
|
64
|
+
spinner.start(`Saving to: ${outputPath}`)
|
|
65
|
+
await ppt.saveToFile(resolve(outputPath))
|
|
66
|
+
spinner.succeed(chalk.green(`✓ Saved: ${outputPath}`))
|
|
71
67
|
|
|
68
|
+
console.log(chalk.dim(`\n Slides: ${ppt.slideCount}`))
|
|
69
|
+
console.log(chalk.dim(` Template: ${templatePath}`))
|
|
70
|
+
console.log(chalk.dim(` Output: ${outputPath}\n`))
|
|
72
71
|
} catch (err) {
|
|
73
|
-
spinner.fail(chalk.red(`Build failed: ${err.message}`))
|
|
72
|
+
spinner.fail(chalk.red(`Build failed: ${err.message}`))
|
|
74
73
|
if (process.env.PPTX_LOG_LEVEL === 'debug') {
|
|
75
|
-
console.error(err.stack)
|
|
74
|
+
console.error(err.stack)
|
|
76
75
|
}
|
|
77
|
-
process.exit(1)
|
|
76
|
+
process.exit(1)
|
|
78
77
|
}
|
|
79
78
|
}
|
|
80
79
|
|
|
81
|
-
module.exports = { buildCommand }
|
|
80
|
+
module.exports = { buildCommand }
|
|
@@ -1,47 +1,47 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview `debug` CLI command — diagnoses and repairs corrupted PPTX files.
|
|
3
3
|
*/
|
|
4
|
-
const chalk = require('chalk')
|
|
5
|
-
const ora = require('ora')
|
|
6
|
-
const { resolve } = require('path')
|
|
7
|
-
const { PPTXTemplater } = require('../../index.js')
|
|
4
|
+
const chalk = require('chalk')
|
|
5
|
+
const ora = require('ora')
|
|
6
|
+
const { resolve } = require('path')
|
|
7
|
+
const { PPTXTemplater } = require('../../index.js')
|
|
8
8
|
|
|
9
9
|
async function debugCommand(filePath, opts) {
|
|
10
|
-
const spinner = ora(`Loading PPTX for debug: ${filePath}`).start()
|
|
10
|
+
const spinner = ora(`Loading PPTX for debug: ${filePath}`).start()
|
|
11
11
|
|
|
12
12
|
try {
|
|
13
|
-
const ppt = await PPTXTemplater.load(resolve(filePath))
|
|
14
|
-
spinner.succeed('Loaded successfully')
|
|
13
|
+
const ppt = await PPTXTemplater.load(resolve(filePath))
|
|
14
|
+
spinner.succeed('Loaded successfully')
|
|
15
15
|
|
|
16
|
-
const result = ppt.validate()
|
|
16
|
+
const result = ppt.validate()
|
|
17
17
|
|
|
18
|
-
console.log(chalk.bold.cyan('\n═══ Debug Report ═══\n'))
|
|
19
|
-
console.log(chalk.bold('Validation:'))
|
|
18
|
+
console.log(chalk.bold.cyan('\n═══ Debug Report ═══\n'))
|
|
19
|
+
console.log(chalk.bold('Validation:'))
|
|
20
20
|
|
|
21
21
|
if (result.valid) {
|
|
22
|
-
console.log(chalk.green(' ✓ Structure is valid'))
|
|
22
|
+
console.log(chalk.green(' ✓ Structure is valid'))
|
|
23
23
|
} else {
|
|
24
|
-
console.log(chalk.red(` ✗ ${result.errors.length} error(s) found`))
|
|
25
|
-
result.errors.forEach(e => console.log(chalk.red(` • ${e}`)))
|
|
24
|
+
console.log(chalk.red(` ✗ ${result.errors.length} error(s) found`))
|
|
25
|
+
result.errors.forEach(e => console.log(chalk.red(` • ${e}`)))
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
if (result.warnings.length > 0) {
|
|
29
|
-
console.log(chalk.yellow(`\n ${result.warnings.length} warning(s):`))
|
|
30
|
-
result.warnings.forEach(w => console.log(chalk.yellow(` • ${w}`)))
|
|
29
|
+
console.log(chalk.yellow(`\n ${result.warnings.length} warning(s):`))
|
|
30
|
+
result.warnings.forEach(w => console.log(chalk.yellow(` • ${w}`)))
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
if (opts.fix && opts.out) {
|
|
34
|
-
spinner.start('Attempting repairs...')
|
|
35
|
-
await ppt.saveToFile(resolve(opts.out))
|
|
36
|
-
spinner.succeed(chalk.green(`✓ Repaired PPTX saved to: ${opts.out}`))
|
|
34
|
+
spinner.start('Attempting repairs...')
|
|
35
|
+
await ppt.saveToFile(resolve(opts.out))
|
|
36
|
+
spinner.succeed(chalk.green(`✓ Repaired PPTX saved to: ${opts.out}`))
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
console.log('')
|
|
39
|
+
console.log('')
|
|
40
40
|
} catch (err) {
|
|
41
|
-
spinner.fail(chalk.red(`Debug failed: ${err.message}`))
|
|
42
|
-
if (process.env.PPTX_LOG_LEVEL === 'debug') console.error(err.stack)
|
|
43
|
-
process.exit(1)
|
|
41
|
+
spinner.fail(chalk.red(`Debug failed: ${err.message}`))
|
|
42
|
+
if (process.env.PPTX_LOG_LEVEL === 'debug') console.error(err.stack)
|
|
43
|
+
process.exit(1)
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
module.exports = { debugCommand }
|
|
47
|
+
module.exports = { debugCommand }
|
|
@@ -1,44 +1,44 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview `extract` CLI command — extracts XML parts from a PPTX.
|
|
3
3
|
*/
|
|
4
|
-
const chalk = require('chalk')
|
|
5
|
-
const { resolve } = require('path')
|
|
6
|
-
const { writeFileSync } = require('fs')
|
|
7
|
-
const { PPTXTemplater } = require('../../index.js')
|
|
4
|
+
const chalk = require('chalk')
|
|
5
|
+
const { resolve } = require('path')
|
|
6
|
+
const { writeFileSync } = require('fs')
|
|
7
|
+
const { PPTXTemplater } = require('../../index.js')
|
|
8
8
|
|
|
9
9
|
async function extractCommand(filePath, opts) {
|
|
10
10
|
try {
|
|
11
|
-
const ppt = await PPTXTemplater.load(resolve(filePath))
|
|
11
|
+
const ppt = await PPTXTemplater.load(resolve(filePath))
|
|
12
12
|
|
|
13
13
|
if (opts.slide) {
|
|
14
|
-
const slideNum = parseInt(opts.slide, 10)
|
|
14
|
+
const slideNum = parseInt(opts.slide, 10)
|
|
15
15
|
// Access internal zip via the engine's buffer
|
|
16
|
-
const buffer = await ppt.toBuffer()
|
|
17
|
-
const JSZip = require('jszip')
|
|
18
|
-
const zip = await JSZip.loadAsync(buffer)
|
|
19
|
-
const slideFile = zip.file(`ppt/slides/slide${slideNum}.xml`)
|
|
16
|
+
const buffer = await ppt.toBuffer()
|
|
17
|
+
const JSZip = require('jszip')
|
|
18
|
+
const zip = await JSZip.loadAsync(buffer)
|
|
19
|
+
const slideFile = zip.file(`ppt/slides/slide${slideNum}.xml`)
|
|
20
20
|
|
|
21
21
|
if (!slideFile) {
|
|
22
|
-
console.error(chalk.red(`Slide ${slideNum} not found`))
|
|
23
|
-
process.exit(1)
|
|
22
|
+
console.error(chalk.red(`Slide ${slideNum} not found`))
|
|
23
|
+
process.exit(1)
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
const xml = await slideFile.async('text')
|
|
26
|
+
const xml = await slideFile.async('text')
|
|
27
27
|
|
|
28
28
|
if (opts.out) {
|
|
29
|
-
writeFileSync(resolve(opts.out), xml, 'utf-8')
|
|
30
|
-
console.log(chalk.green(`✓ Extracted slide ${slideNum} to ${opts.out}`))
|
|
29
|
+
writeFileSync(resolve(opts.out), xml, 'utf-8')
|
|
30
|
+
console.log(chalk.green(`✓ Extracted slide ${slideNum} to ${opts.out}`))
|
|
31
31
|
} else {
|
|
32
|
-
console.log(xml)
|
|
32
|
+
console.log(xml)
|
|
33
33
|
}
|
|
34
34
|
} else {
|
|
35
|
-
console.log(chalk.yellow('Specify --slide <number> to extract'))
|
|
36
|
-
process.exit(1)
|
|
35
|
+
console.log(chalk.yellow('Specify --slide <number> to extract'))
|
|
36
|
+
process.exit(1)
|
|
37
37
|
}
|
|
38
38
|
} catch (err) {
|
|
39
|
-
console.error(chalk.red(`Extract failed: ${err.message}`))
|
|
40
|
-
process.exit(1)
|
|
39
|
+
console.error(chalk.red(`Extract failed: ${err.message}`))
|
|
40
|
+
process.exit(1)
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
module.exports = { extractCommand }
|
|
44
|
+
module.exports = { extractCommand }
|
|
@@ -1,41 +1,41 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview `inspect` CLI command — detailed PPTX structure inspection.
|
|
3
3
|
*/
|
|
4
|
-
const chalk = require('chalk')
|
|
5
|
-
const ora = require('ora')
|
|
6
|
-
const { resolve } = require('path')
|
|
7
|
-
const { PPTXTemplater } = require('../../index.js')
|
|
4
|
+
const chalk = require('chalk')
|
|
5
|
+
const ora = require('ora')
|
|
6
|
+
const { resolve } = require('path')
|
|
7
|
+
const { PPTXTemplater } = require('../../index.js')
|
|
8
8
|
|
|
9
9
|
async function inspectCommand(filePath, opts) {
|
|
10
|
-
const showAll = opts.all
|
|
11
|
-
const spinner = ora(`Inspecting: ${filePath}`).start()
|
|
10
|
+
const showAll = opts.all
|
|
11
|
+
const spinner = ora(`Inspecting: ${filePath}`).start()
|
|
12
12
|
|
|
13
13
|
try {
|
|
14
|
-
const ppt = await PPTXTemplater.load(resolve(filePath))
|
|
15
|
-
const info = ppt.getInfo()
|
|
16
|
-
spinner.stop()
|
|
14
|
+
const ppt = await PPTXTemplater.load(resolve(filePath))
|
|
15
|
+
const info = ppt.getInfo()
|
|
16
|
+
spinner.stop()
|
|
17
17
|
|
|
18
|
-
console.log(chalk.bold.cyan('\n═══ PPTX Inspection Report ═══\n'))
|
|
19
|
-
console.log(chalk.bold('General:'))
|
|
20
|
-
console.log(` Title: ${info.title || chalk.dim('(none)')}`)
|
|
21
|
-
console.log(` Author: ${info.author || chalk.dim('(none)')}`)
|
|
22
|
-
console.log(` Created: ${info.created || chalk.dim('(unknown)')}`)
|
|
23
|
-
console.log(` Slides: ${chalk.cyan(info.slideCount)}`)
|
|
24
|
-
console.log(` Media: ${chalk.cyan(info.mediaCount)} files`)
|
|
18
|
+
console.log(chalk.bold.cyan('\n═══ PPTX Inspection Report ═══\n'))
|
|
19
|
+
console.log(chalk.bold('General:'))
|
|
20
|
+
console.log(` Title: ${info.title || chalk.dim('(none)')}`)
|
|
21
|
+
console.log(` Author: ${info.author || chalk.dim('(none)')}`)
|
|
22
|
+
console.log(` Created: ${info.created || chalk.dim('(unknown)')}`)
|
|
23
|
+
console.log(` Slides: ${chalk.cyan(info.slideCount)}`)
|
|
24
|
+
console.log(` Media: ${chalk.cyan(info.mediaCount)} files`)
|
|
25
25
|
|
|
26
26
|
if (opts.slides || showAll) {
|
|
27
|
-
console.log(chalk.bold('\nSlides:'))
|
|
27
|
+
console.log(chalk.bold('\nSlides:'))
|
|
28
28
|
for (const slide of info.slides) {
|
|
29
|
-
const tags = slide.tags.length > 0 ? chalk.dim(` [${slide.tags.join(', ')}]`) : ''
|
|
30
|
-
console.log(` ${chalk.cyan(slide.index.toString().padStart(2))}. ${slide.zipPath}${tags}`)
|
|
29
|
+
const tags = slide.tags.length > 0 ? chalk.dim(` [${slide.tags.join(', ')}]`) : ''
|
|
30
|
+
console.log(` ${chalk.cyan(slide.index.toString().padStart(2))}. ${slide.zipPath}${tags}`)
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
console.log('')
|
|
34
|
+
console.log('')
|
|
35
35
|
} catch (err) {
|
|
36
|
-
spinner.fail(chalk.red(`Inspect failed: ${err.message}`))
|
|
37
|
-
process.exit(1)
|
|
36
|
+
spinner.fail(chalk.red(`Inspect failed: ${err.message}`))
|
|
37
|
+
process.exit(1)
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
module.exports = { inspectCommand }
|
|
41
|
+
module.exports = { inspectCommand }
|
|
@@ -1,38 +1,38 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview `validate` CLI command.
|
|
3
3
|
*/
|
|
4
|
-
const chalk = require('chalk')
|
|
5
|
-
const ora = require('ora')
|
|
6
|
-
const { resolve } = require('path')
|
|
7
|
-
const { PPTXTemplater } = require('../../index.js')
|
|
4
|
+
const chalk = require('chalk')
|
|
5
|
+
const ora = require('ora')
|
|
6
|
+
const { resolve } = require('path')
|
|
7
|
+
const { PPTXTemplater } = require('../../index.js')
|
|
8
8
|
|
|
9
9
|
async function validateCommand(filePath, opts) {
|
|
10
|
-
const spinner = ora(`Validating: ${filePath}`).start()
|
|
10
|
+
const spinner = ora(`Validating: ${filePath}`).start()
|
|
11
11
|
try {
|
|
12
|
-
const ppt = await PPTXTemplater.load(resolve(filePath))
|
|
13
|
-
const result = ppt.validate()
|
|
14
|
-
spinner.stop()
|
|
12
|
+
const ppt = await PPTXTemplater.load(resolve(filePath))
|
|
13
|
+
const result = ppt.validate()
|
|
14
|
+
spinner.stop()
|
|
15
15
|
|
|
16
16
|
if (result.valid && result.warnings.length === 0) {
|
|
17
|
-
console.log(chalk.green(`\n✓ Valid PPTX (${ppt.slideCount} slides)\n`))
|
|
17
|
+
console.log(chalk.green(`\n✓ Valid PPTX (${ppt.slideCount} slides)\n`))
|
|
18
18
|
} else {
|
|
19
19
|
if (result.errors.length > 0) {
|
|
20
|
-
console.log(chalk.red(`\n✗ Validation errors (${result.errors.length}):\n`))
|
|
21
|
-
result.errors.forEach(e => console.log(chalk.red(` • ${e}`)))
|
|
20
|
+
console.log(chalk.red(`\n✗ Validation errors (${result.errors.length}):\n`))
|
|
21
|
+
result.errors.forEach(e => console.log(chalk.red(` • ${e}`)))
|
|
22
22
|
}
|
|
23
23
|
if (result.warnings.length > 0) {
|
|
24
|
-
console.log(chalk.yellow(`\n⚠ Warnings (${result.warnings.length}):\n`))
|
|
25
|
-
result.warnings.forEach(w => console.log(chalk.yellow(` • ${w}`)))
|
|
24
|
+
console.log(chalk.yellow(`\n⚠ Warnings (${result.warnings.length}):\n`))
|
|
25
|
+
result.warnings.forEach(w => console.log(chalk.yellow(` • ${w}`)))
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
if (!result.valid || (opts.strict && result.warnings.length > 0)) {
|
|
30
|
-
process.exit(1)
|
|
30
|
+
process.exit(1)
|
|
31
31
|
}
|
|
32
32
|
} catch (err) {
|
|
33
|
-
spinner.fail(chalk.red(`Validation failed: ${err.message}`))
|
|
34
|
-
process.exit(1)
|
|
33
|
+
spinner.fail(chalk.red(`Validation failed: ${err.message}`))
|
|
34
|
+
process.exit(1)
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
module.exports = { validateCommand }
|
|
38
|
+
module.exports = { validateCommand }
|
package/src/cli/index.js
CHANGED
|
@@ -18,40 +18,43 @@
|
|
|
18
18
|
* node-pptx-templater --help
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
|
-
const { Command } = require('commander')
|
|
22
|
-
const chalk = require('chalk')
|
|
23
|
-
const { readFileSync } = require('fs')
|
|
24
|
-
const { resolve } = require('path')
|
|
25
|
-
const { buildCommand } = require('./commands/build.js')
|
|
26
|
-
const { validateCommand } = require('./commands/validate.js')
|
|
27
|
-
const { inspectCommand } = require('./commands/inspect.js')
|
|
28
|
-
const { extractCommand } = require('./commands/extract.js')
|
|
29
|
-
const { debugCommand } = require('./commands/debug.js')
|
|
21
|
+
const { Command } = require('commander')
|
|
22
|
+
const chalk = require('chalk')
|
|
23
|
+
const { readFileSync } = require('fs')
|
|
24
|
+
const { resolve } = require('path')
|
|
25
|
+
const { buildCommand } = require('./commands/build.js')
|
|
26
|
+
const { validateCommand } = require('./commands/validate.js')
|
|
27
|
+
const { inspectCommand } = require('./commands/inspect.js')
|
|
28
|
+
const { extractCommand } = require('./commands/extract.js')
|
|
29
|
+
const { debugCommand } = require('./commands/debug.js')
|
|
30
30
|
|
|
31
31
|
// Read version from package.json
|
|
32
|
-
const pkg = JSON.parse(
|
|
33
|
-
readFileSync(resolve(__dirname, '../../package.json'), 'utf-8')
|
|
34
|
-
);
|
|
32
|
+
const pkg = JSON.parse(readFileSync(resolve(__dirname, '../../package.json'), 'utf-8'))
|
|
35
33
|
|
|
36
34
|
/**
|
|
37
35
|
* CLI banner displayed on startup.
|
|
38
36
|
*/
|
|
39
37
|
function printBanner() {
|
|
40
|
-
console.log(
|
|
38
|
+
console.log(
|
|
39
|
+
chalk.bold.cyan(`
|
|
41
40
|
╔═══════════════════════════════════════════════╗
|
|
42
41
|
║ node-pptx-templater v${pkg.version.padEnd(17)}║
|
|
43
42
|
║ Low-level OpenXML PowerPoint template engine ║
|
|
44
43
|
╚═══════════════════════════════════════════════╝
|
|
45
|
-
`)
|
|
44
|
+
`)
|
|
45
|
+
)
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
const program = new Command()
|
|
48
|
+
const program = new Command()
|
|
49
49
|
|
|
50
50
|
program
|
|
51
51
|
.name('node-pptx-templater')
|
|
52
52
|
.description('Low-level PowerPoint OpenXML template engine for Node.js')
|
|
53
53
|
.version(pkg.version, '-v, --version', 'Display version number')
|
|
54
|
-
.addHelpText(
|
|
54
|
+
.addHelpText(
|
|
55
|
+
'before',
|
|
56
|
+
chalk.bold.cyan('\nnode-pptx-templater — PowerPoint XML manipulation engine\n')
|
|
57
|
+
)
|
|
55
58
|
|
|
56
59
|
// ─── build command ─────────────────────────────────────────────────────────
|
|
57
60
|
program
|
|
@@ -61,9 +64,9 @@ program
|
|
|
61
64
|
.option('-s, --slide <numbers>', 'Comma-separated slide numbers to include (e.g., 1,3,5)')
|
|
62
65
|
.option('--no-banner', 'Suppress the banner')
|
|
63
66
|
.action(async (template, output, opts) => {
|
|
64
|
-
if (!opts.noBanner) printBanner()
|
|
65
|
-
await buildCommand(template, output, opts)
|
|
66
|
-
})
|
|
67
|
+
if (!opts.noBanner) printBanner()
|
|
68
|
+
await buildCommand(template, output, opts)
|
|
69
|
+
})
|
|
67
70
|
|
|
68
71
|
// ─── validate command ───────────────────────────────────────────────────────
|
|
69
72
|
program
|
|
@@ -71,9 +74,9 @@ program
|
|
|
71
74
|
.description('Validate the structure of a PPTX file')
|
|
72
75
|
.option('--strict', 'Exit with error code on warnings too')
|
|
73
76
|
.action(async (file, opts) => {
|
|
74
|
-
printBanner()
|
|
75
|
-
await validateCommand(file, opts)
|
|
76
|
-
})
|
|
77
|
+
printBanner()
|
|
78
|
+
await validateCommand(file, opts)
|
|
79
|
+
})
|
|
77
80
|
|
|
78
81
|
// ─── inspect command ────────────────────────────────────────────────────────
|
|
79
82
|
program
|
|
@@ -86,9 +89,9 @@ program
|
|
|
86
89
|
.option('--rels', 'Show relationship tree')
|
|
87
90
|
.option('--all', 'Show everything')
|
|
88
91
|
.action(async (file, opts) => {
|
|
89
|
-
printBanner()
|
|
90
|
-
await inspectCommand(file, opts)
|
|
91
|
-
})
|
|
92
|
+
printBanner()
|
|
93
|
+
await inspectCommand(file, opts)
|
|
94
|
+
})
|
|
92
95
|
|
|
93
96
|
// ─── extract command ────────────────────────────────────────────────────────
|
|
94
97
|
program
|
|
@@ -99,8 +102,8 @@ program
|
|
|
99
102
|
.option('--chart <name>', 'Extract chart XML by name')
|
|
100
103
|
.option('--rels', 'Extract relationship files')
|
|
101
104
|
.action(async (file, opts) => {
|
|
102
|
-
await extractCommand(file, opts)
|
|
103
|
-
})
|
|
105
|
+
await extractCommand(file, opts)
|
|
106
|
+
})
|
|
104
107
|
|
|
105
108
|
// ─── debug command ──────────────────────────────────────────────────────────
|
|
106
109
|
program
|
|
@@ -109,23 +112,23 @@ program
|
|
|
109
112
|
.option('--fix', 'Attempt automatic repairs')
|
|
110
113
|
.option('-o, --out <path>', 'Output repaired file path')
|
|
111
114
|
.action(async (file, opts) => {
|
|
112
|
-
printBanner()
|
|
113
|
-
await debugCommand(file, opts)
|
|
114
|
-
})
|
|
115
|
+
printBanner()
|
|
116
|
+
await debugCommand(file, opts)
|
|
117
|
+
})
|
|
115
118
|
|
|
116
119
|
// ─── Global error handling ──────────────────────────────────────────────────
|
|
117
|
-
program.exitOverride()
|
|
120
|
+
program.exitOverride()
|
|
118
121
|
|
|
119
122
|
async function main() {
|
|
120
123
|
try {
|
|
121
|
-
await program.parseAsync(process.argv)
|
|
124
|
+
await program.parseAsync(process.argv)
|
|
122
125
|
} catch (err) {
|
|
123
126
|
if (err.code === 'commander.helpDisplayed' || err.code === 'commander.version') {
|
|
124
|
-
process.exit(0)
|
|
127
|
+
process.exit(0)
|
|
125
128
|
}
|
|
126
|
-
console.error(chalk.red(`\n✗ Error: ${err.message}\n`))
|
|
127
|
-
process.exit(1)
|
|
129
|
+
console.error(chalk.red(`\n✗ Error: ${err.message}\n`))
|
|
130
|
+
process.exit(1)
|
|
128
131
|
}
|
|
129
132
|
}
|
|
130
133
|
|
|
131
|
-
main()
|
|
134
|
+
main()
|