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/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-pptx-templater",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "Low-level PowerPoint OpenXML template engine for Node.js — generate and edit PPTX files directly through XML manipulation without relying on PowerPoint generation libraries.",
|
|
5
5
|
"main": "./src/index.js",
|
|
6
|
-
"type": "
|
|
6
|
+
"type": "commonjs",
|
|
7
7
|
"exports": {
|
|
8
8
|
".": {
|
|
9
|
-
"
|
|
9
|
+
"require": "./src/index.js"
|
|
10
10
|
}
|
|
11
11
|
},
|
|
12
12
|
"bin": {
|
|
@@ -65,8 +65,8 @@
|
|
|
65
65
|
"jszip": "^3.10.1",
|
|
66
66
|
"fs-extra": "^11.2.0",
|
|
67
67
|
"commander": "^12.0.0",
|
|
68
|
-
"chalk": "^
|
|
69
|
-
"ora": "^
|
|
68
|
+
"chalk": "^4.1.2",
|
|
69
|
+
"ora": "^5.4.1"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
72
|
"vitest": "^1.6.0",
|
|
@@ -80,4 +80,4 @@
|
|
|
80
80
|
"LICENSE",
|
|
81
81
|
"CHANGELOG.md"
|
|
82
82
|
]
|
|
83
|
-
}
|
|
83
|
+
}
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
* @fileoverview `build` CLI command — builds a PPTX from a template + JSON data.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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.
|
|
@@ -15,65 +15,66 @@ import { PPTXTemplater } from '../../index.js';
|
|
|
15
15
|
* @param {string} outputPath - Path for the generated PPTX.
|
|
16
16
|
* @param {Object} opts - CLI options.
|
|
17
17
|
*/
|
|
18
|
-
|
|
19
|
-
const spinner = ora(`Loading template: ${templatePath}`).start()
|
|
18
|
+
async function buildCommand(templatePath, outputPath, opts) {
|
|
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
|
}
|
|
79
|
+
|
|
80
|
+
module.exports = { buildCommand }
|
|
@@ -1,46 +1,47 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview `debug` CLI command — diagnoses and repairs corrupted PPTX files.
|
|
3
3
|
*/
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
import { PPTXTemplater } from '../../index.js';
|
|
4
|
+
const chalk = require('chalk')
|
|
5
|
+
const ora = require('ora')
|
|
6
|
+
const { resolve } = require('path')
|
|
7
|
+
const { PPTXTemplater } = require('../../index.js')
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
const spinner = ora(`Loading PPTX for debug: ${filePath}`).start()
|
|
9
|
+
async function debugCommand(filePath, opts) {
|
|
10
|
+
const spinner = ora(`Loading PPTX for debug: ${filePath}`).start()
|
|
12
11
|
|
|
13
12
|
try {
|
|
14
|
-
const ppt = await PPTXTemplater.load(resolve(filePath))
|
|
15
|
-
spinner.succeed('Loaded successfully')
|
|
13
|
+
const ppt = await PPTXTemplater.load(resolve(filePath))
|
|
14
|
+
spinner.succeed('Loaded successfully')
|
|
16
15
|
|
|
17
|
-
const result = ppt.validate()
|
|
16
|
+
const result = ppt.validate()
|
|
18
17
|
|
|
19
|
-
console.log(chalk.bold.cyan('\n═══ Debug Report ═══\n'))
|
|
20
|
-
console.log(chalk.bold('Validation:'))
|
|
18
|
+
console.log(chalk.bold.cyan('\n═══ Debug Report ═══\n'))
|
|
19
|
+
console.log(chalk.bold('Validation:'))
|
|
21
20
|
|
|
22
21
|
if (result.valid) {
|
|
23
|
-
console.log(chalk.green(' ✓ Structure is valid'))
|
|
22
|
+
console.log(chalk.green(' ✓ Structure is valid'))
|
|
24
23
|
} else {
|
|
25
|
-
console.log(chalk.red(` ✗ ${result.errors.length} error(s) found`))
|
|
26
|
-
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}`)))
|
|
27
26
|
}
|
|
28
27
|
|
|
29
28
|
if (result.warnings.length > 0) {
|
|
30
|
-
console.log(chalk.yellow(`\n ${result.warnings.length} warning(s):`))
|
|
31
|
-
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}`)))
|
|
32
31
|
}
|
|
33
32
|
|
|
34
33
|
if (opts.fix && opts.out) {
|
|
35
|
-
spinner.start('Attempting repairs...')
|
|
36
|
-
await ppt.saveToFile(resolve(opts.out))
|
|
37
|
-
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}`))
|
|
38
37
|
}
|
|
39
38
|
|
|
40
|
-
console.log('')
|
|
39
|
+
console.log('')
|
|
41
40
|
} catch (err) {
|
|
42
|
-
spinner.fail(chalk.red(`Debug failed: ${err.message}`))
|
|
43
|
-
if (process.env.PPTX_LOG_LEVEL === 'debug') console.error(err.stack)
|
|
44
|
-
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)
|
|
45
44
|
}
|
|
46
45
|
}
|
|
46
|
+
|
|
47
|
+
module.exports = { debugCommand }
|
|
@@ -1,42 +1,44 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview `extract` CLI command — extracts XML parts from a PPTX.
|
|
3
3
|
*/
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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 = (
|
|
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
|
+
|
|
44
|
+
module.exports = { extractCommand }
|
|
@@ -1,39 +1,41 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview `inspect` CLI command — detailed PPTX structure inspection.
|
|
3
3
|
*/
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
const chalk = require('chalk')
|
|
5
|
+
const ora = require('ora')
|
|
6
|
+
const { resolve } = require('path')
|
|
7
|
+
const { PPTXTemplater } = require('../../index.js')
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
const showAll = opts.all
|
|
11
|
-
const spinner = ora(`Inspecting: ${filePath}`).start()
|
|
9
|
+
async function inspectCommand(filePath, opts) {
|
|
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
|
+
|
|
41
|
+
module.exports = { inspectCommand }
|
|
@@ -1,36 +1,38 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview `validate` CLI command.
|
|
3
3
|
*/
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
const chalk = require('chalk')
|
|
5
|
+
const ora = require('ora')
|
|
6
|
+
const { resolve } = require('path')
|
|
7
|
+
const { PPTXTemplater } = require('../../index.js')
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
const spinner = ora(`Validating: ${filePath}`).start()
|
|
9
|
+
async function validateCommand(filePath, opts) {
|
|
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
|
+
|
|
38
|
+
module.exports = { validateCommand }
|
package/src/cli/index.js
CHANGED
|
@@ -18,45 +18,43 @@
|
|
|
18
18
|
* node-pptx-templater --help
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
import { inspectCommand } from './commands/inspect.js';
|
|
31
|
-
import { extractCommand } from './commands/extract.js';
|
|
32
|
-
import { debugCommand } from './commands/debug.js';
|
|
33
|
-
|
|
34
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
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')
|
|
35
30
|
|
|
36
31
|
// Read version from package.json
|
|
37
|
-
const pkg = JSON.parse(
|
|
38
|
-
readFileSync(resolve(__dirname, '../../package.json'), 'utf-8')
|
|
39
|
-
);
|
|
32
|
+
const pkg = JSON.parse(readFileSync(resolve(__dirname, '../../package.json'), 'utf-8'))
|
|
40
33
|
|
|
41
34
|
/**
|
|
42
35
|
* CLI banner displayed on startup.
|
|
43
36
|
*/
|
|
44
37
|
function printBanner() {
|
|
45
|
-
console.log(
|
|
38
|
+
console.log(
|
|
39
|
+
chalk.bold.cyan(`
|
|
46
40
|
╔═══════════════════════════════════════════════╗
|
|
47
41
|
║ node-pptx-templater v${pkg.version.padEnd(17)}║
|
|
48
42
|
║ Low-level OpenXML PowerPoint template engine ║
|
|
49
43
|
╚═══════════════════════════════════════════════╝
|
|
50
|
-
`)
|
|
44
|
+
`)
|
|
45
|
+
)
|
|
51
46
|
}
|
|
52
47
|
|
|
53
|
-
const program = new Command()
|
|
48
|
+
const program = new Command()
|
|
54
49
|
|
|
55
50
|
program
|
|
56
51
|
.name('node-pptx-templater')
|
|
57
52
|
.description('Low-level PowerPoint OpenXML template engine for Node.js')
|
|
58
53
|
.version(pkg.version, '-v, --version', 'Display version number')
|
|
59
|
-
.addHelpText(
|
|
54
|
+
.addHelpText(
|
|
55
|
+
'before',
|
|
56
|
+
chalk.bold.cyan('\nnode-pptx-templater — PowerPoint XML manipulation engine\n')
|
|
57
|
+
)
|
|
60
58
|
|
|
61
59
|
// ─── build command ─────────────────────────────────────────────────────────
|
|
62
60
|
program
|
|
@@ -66,9 +64,9 @@ program
|
|
|
66
64
|
.option('-s, --slide <numbers>', 'Comma-separated slide numbers to include (e.g., 1,3,5)')
|
|
67
65
|
.option('--no-banner', 'Suppress the banner')
|
|
68
66
|
.action(async (template, output, opts) => {
|
|
69
|
-
if (!opts.noBanner) printBanner()
|
|
70
|
-
await buildCommand(template, output, opts)
|
|
71
|
-
})
|
|
67
|
+
if (!opts.noBanner) printBanner()
|
|
68
|
+
await buildCommand(template, output, opts)
|
|
69
|
+
})
|
|
72
70
|
|
|
73
71
|
// ─── validate command ───────────────────────────────────────────────────────
|
|
74
72
|
program
|
|
@@ -76,9 +74,9 @@ program
|
|
|
76
74
|
.description('Validate the structure of a PPTX file')
|
|
77
75
|
.option('--strict', 'Exit with error code on warnings too')
|
|
78
76
|
.action(async (file, opts) => {
|
|
79
|
-
printBanner()
|
|
80
|
-
await validateCommand(file, opts)
|
|
81
|
-
})
|
|
77
|
+
printBanner()
|
|
78
|
+
await validateCommand(file, opts)
|
|
79
|
+
})
|
|
82
80
|
|
|
83
81
|
// ─── inspect command ────────────────────────────────────────────────────────
|
|
84
82
|
program
|
|
@@ -91,9 +89,9 @@ program
|
|
|
91
89
|
.option('--rels', 'Show relationship tree')
|
|
92
90
|
.option('--all', 'Show everything')
|
|
93
91
|
.action(async (file, opts) => {
|
|
94
|
-
printBanner()
|
|
95
|
-
await inspectCommand(file, opts)
|
|
96
|
-
})
|
|
92
|
+
printBanner()
|
|
93
|
+
await inspectCommand(file, opts)
|
|
94
|
+
})
|
|
97
95
|
|
|
98
96
|
// ─── extract command ────────────────────────────────────────────────────────
|
|
99
97
|
program
|
|
@@ -104,8 +102,8 @@ program
|
|
|
104
102
|
.option('--chart <name>', 'Extract chart XML by name')
|
|
105
103
|
.option('--rels', 'Extract relationship files')
|
|
106
104
|
.action(async (file, opts) => {
|
|
107
|
-
await extractCommand(file, opts)
|
|
108
|
-
})
|
|
105
|
+
await extractCommand(file, opts)
|
|
106
|
+
})
|
|
109
107
|
|
|
110
108
|
// ─── debug command ──────────────────────────────────────────────────────────
|
|
111
109
|
program
|
|
@@ -114,19 +112,23 @@ program
|
|
|
114
112
|
.option('--fix', 'Attempt automatic repairs')
|
|
115
113
|
.option('-o, --out <path>', 'Output repaired file path')
|
|
116
114
|
.action(async (file, opts) => {
|
|
117
|
-
printBanner()
|
|
118
|
-
await debugCommand(file, opts)
|
|
119
|
-
})
|
|
115
|
+
printBanner()
|
|
116
|
+
await debugCommand(file, opts)
|
|
117
|
+
})
|
|
120
118
|
|
|
121
119
|
// ─── Global error handling ──────────────────────────────────────────────────
|
|
122
|
-
program.exitOverride()
|
|
120
|
+
program.exitOverride()
|
|
123
121
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
122
|
+
async function main() {
|
|
123
|
+
try {
|
|
124
|
+
await program.parseAsync(process.argv)
|
|
125
|
+
} catch (err) {
|
|
126
|
+
if (err.code === 'commander.helpDisplayed' || err.code === 'commander.version') {
|
|
127
|
+
process.exit(0)
|
|
128
|
+
}
|
|
129
|
+
console.error(chalk.red(`\n✗ Error: ${err.message}\n`))
|
|
130
|
+
process.exit(1)
|
|
129
131
|
}
|
|
130
|
-
console.error(chalk.red(`\n✗ Error: ${err.message}\n`));
|
|
131
|
-
process.exit(1);
|
|
132
132
|
}
|
|
133
|
+
|
|
134
|
+
main()
|