@thegetty/quire-cli 1.0.0-rc.44 → 1.0.0-rc.46
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 +0 -36
- package/README.md +0 -9
- package/bin/cli.js +1 -46
- package/package.json +9 -25
- package/src/Command.js +6 -26
- package/src/commands/README.md +122 -213
- package/src/commands/build.js +37 -45
- package/src/commands/clean.js +19 -33
- package/src/commands/conf.js +43 -0
- package/src/commands/create.js +14 -42
- package/src/commands/epub.js +31 -67
- package/src/commands/index.js +2 -9
- package/src/commands/info.js +86 -88
- package/src/commands/pdf.js +82 -63
- package/src/commands/preview.js +31 -32
- package/src/commands/validate.js +20 -64
- package/src/commands/version.js +43 -0
- package/src/errors/validation/validation-error.js +11 -20
- package/src/helpers/clean.js +1 -1
- package/src/helpers/is-quire.js +31 -0
- package/src/helpers/test-cwd.js +6 -5
- package/src/helpers/which.js +4 -10
- package/src/lib/11ty/README.md +19 -135
- package/src/lib/11ty/api.js +93 -235
- package/src/lib/11ty/cli.js +37 -112
- package/src/lib/11ty/index.js +5 -64
- package/src/lib/11ty/paths.js +103 -0
- package/src/lib/README.md +0 -330
- package/src/lib/conf/README.md +69 -86
- package/src/lib/conf/config.js +3 -5
- package/src/lib/conf/defaults.js +0 -65
- package/src/lib/conf/schema.js +9 -103
- package/src/lib/epub/README.md +2 -133
- package/src/lib/epub/epub.js +11 -36
- package/src/lib/epub/index.js +21 -111
- package/src/lib/epub/pandoc.js +4 -33
- package/src/lib/git/README.md +2 -151
- package/src/lib/git/index.js +13 -217
- package/src/lib/i18n/README.md +3 -0
- package/src/lib/i18n/config.js +53 -0
- package/src/lib/i18n/index.js +43 -0
- package/src/lib/i18n/localeService.js +58 -0
- package/src/lib/pdf/README.md +0 -131
- package/src/lib/pdf/index.js +21 -124
- package/src/lib/pdf/paged.js +52 -100
- package/src/lib/pdf/prince.js +37 -115
- package/src/lib/pdf/split.js +33 -61
- package/src/lib/quire/README.md +19 -0
- package/src/lib/quire/index.js +353 -0
- package/src/lib/reporter/README.md +2 -211
- package/src/lib/reporter/index.js +0 -607
- package/src/main.js +48 -221
- package/src/packageConfig.js +0 -17
- package/src/validators/utils.js +1 -2
- package/schemas/config.schema.json +0 -194
- package/schemas/figures.schema.json +0 -56
- package/schemas/layout.schema.json +0 -5
- package/schemas/objects.schema.json +0 -62
- package/schemas/publication.schema.json +0 -140
- package/schemas/references.schema.json +0 -29
- package/src/Command.spec.js +0 -99
- package/src/commands/build.spec.js +0 -113
- package/src/commands/build.test.js +0 -397
- package/src/commands/clean.spec.js +0 -118
- package/src/commands/clean.test.js +0 -382
- package/src/commands/config.js +0 -238
- package/src/commands/config.spec.js +0 -107
- package/src/commands/config.test.js +0 -845
- package/src/commands/create.spec.js +0 -112
- package/src/commands/create.test.js +0 -415
- package/src/commands/doctor.js +0 -251
- package/src/commands/doctor.spec.js +0 -115
- package/src/commands/doctor.test.js +0 -1409
- package/src/commands/epub.spec.js +0 -114
- package/src/commands/epub.test.js +0 -503
- package/src/commands/help.js +0 -60
- package/src/commands/help.test.js +0 -132
- package/src/commands/info.spec.js +0 -72
- package/src/commands/info.test.js +0 -512
- package/src/commands/pdf.spec.js +0 -114
- package/src/commands/pdf.test.js +0 -464
- package/src/commands/preview.spec.js +0 -97
- package/src/commands/preview.test.js +0 -250
- package/src/commands/use.js +0 -56
- package/src/commands/use.spec.js +0 -61
- package/src/commands/use.test.js +0 -280
- package/src/commands/validate.spec.js +0 -90
- package/src/commands/validate.test.js +0 -378
- package/src/commands/workflows.js +0 -70
- package/src/errors/build/build-failed-error.js +0 -19
- package/src/errors/build/config-field-missing-error.js +0 -20
- package/src/errors/build/config-file-not-found-error.js +0 -20
- package/src/errors/build/index.js +0 -11
- package/src/errors/help/help-topic-not-found-error.js +0 -30
- package/src/errors/help/index.js +0 -8
- package/src/errors/index.js +0 -58
- package/src/errors/input/index.js +0 -8
- package/src/errors/input/invalid-input-error.js +0 -21
- package/src/errors/install/dependency-install-error.js +0 -19
- package/src/errors/install/directory-not-empty-error.js +0 -25
- package/src/errors/install/index.js +0 -12
- package/src/errors/install/invalid-path-error.js +0 -31
- package/src/errors/install/invalid-starter-error.js +0 -27
- package/src/errors/install/version-not-found-error.js +0 -35
- package/src/errors/output/epub-generation-error.js +0 -19
- package/src/errors/output/index.js +0 -14
- package/src/errors/output/invalid-epub-library-error.js +0 -20
- package/src/errors/output/invalid-pdf-library-error.js +0 -20
- package/src/errors/output/missing-build-output-error.js +0 -21
- package/src/errors/output/pdf-generation-error.js +0 -24
- package/src/errors/output/tool-not-found-error.js +0 -37
- package/src/errors/project/index.js +0 -10
- package/src/errors/project/not-in-project-error.js +0 -20
- package/src/errors/project/project-create-error.js +0 -21
- package/src/errors/quire-error.js +0 -27
- package/src/errors/validation/index.js +0 -3
- package/src/errors/validation/unknown-config-key-error.js +0 -27
- package/src/errors/validation/unknown-config-operation-error.js +0 -24
- package/src/helpers/docs-url.js +0 -32
- package/src/helpers/pager.js +0 -59
- package/src/helpers/pager.test.js +0 -85
- package/src/helpers/suggest-similar.js +0 -124
- package/src/helpers/suggest-similar.test.js +0 -108
- package/src/helpers/test-cwd.test.js +0 -192
- package/src/lib/11ty/index.test.js +0 -655
- package/src/lib/commander/index.js +0 -103
- package/src/lib/commander/index.test.js +0 -86
- package/src/lib/commander/options.js +0 -237
- package/src/lib/commander/options.test.js +0 -205
- package/src/lib/conf/build-status.js +0 -103
- package/src/lib/conf/build-status.test.js +0 -247
- package/src/lib/conf/config.test.js +0 -281
- package/src/lib/conf/format.js +0 -60
- package/src/lib/conf/format.test.js +0 -106
- package/src/lib/conf/helpers.js +0 -91
- package/src/lib/conf/helpers.test.js +0 -136
- package/src/lib/conf/index.js +0 -22
- package/src/lib/constants.js +0 -28
- package/src/lib/doctor/README.md +0 -667
- package/src/lib/doctor/checks/environment/cli-version.js +0 -62
- package/src/lib/doctor/checks/environment/cli-version.test.js +0 -132
- package/src/lib/doctor/checks/environment/git-available.js +0 -77
- package/src/lib/doctor/checks/environment/git-available.test.js +0 -52
- package/src/lib/doctor/checks/environment/index.js +0 -13
- package/src/lib/doctor/checks/environment/node-version.js +0 -66
- package/src/lib/doctor/checks/environment/node-version.test.js +0 -17
- package/src/lib/doctor/checks/environment/npm-available.js +0 -66
- package/src/lib/doctor/checks/environment/npm-available.test.js +0 -52
- package/src/lib/doctor/checks/environment/os-info.js +0 -48
- package/src/lib/doctor/checks/environment/os-info.test.js +0 -81
- package/src/lib/doctor/checks/environment/runtime-info.js +0 -51
- package/src/lib/doctor/checks/environment/runtime-info.test.js +0 -132
- package/src/lib/doctor/checks/outputs/epub-output.js +0 -119
- package/src/lib/doctor/checks/outputs/epub-output.test.js +0 -277
- package/src/lib/doctor/checks/outputs/index.js +0 -10
- package/src/lib/doctor/checks/outputs/pdf-output.js +0 -144
- package/src/lib/doctor/checks/outputs/pdf-output.test.js +0 -377
- package/src/lib/doctor/checks/outputs/stale-build.js +0 -122
- package/src/lib/doctor/checks/outputs/stale-build.test.js +0 -282
- package/src/lib/doctor/checks/project/data-files.js +0 -56
- package/src/lib/doctor/checks/project/data-files.test.js +0 -125
- package/src/lib/doctor/checks/project/dependencies.js +0 -53
- package/src/lib/doctor/checks/project/dependencies.test.js +0 -71
- package/src/lib/doctor/checks/project/index.js +0 -11
- package/src/lib/doctor/checks/project/quire-11ty.js +0 -98
- package/src/lib/doctor/checks/project/quire-11ty.test.js +0 -170
- package/src/lib/doctor/checks/project/quire-project.js +0 -38
- package/src/lib/doctor/checks/project/quire-project.test.js +0 -47
- package/src/lib/doctor/checks/tools/index.js +0 -10
- package/src/lib/doctor/checks/tools/pandoc-available.js +0 -82
- package/src/lib/doctor/checks/tools/pandoc-available.test.js +0 -73
- package/src/lib/doctor/checks/tools/prince-available.js +0 -81
- package/src/lib/doctor/checks/tools/prince-available.test.js +0 -73
- package/src/lib/doctor/constants.js +0 -39
- package/src/lib/doctor/formatDuration.js +0 -108
- package/src/lib/doctor/formatDuration.test.js +0 -76
- package/src/lib/doctor/formatters/human.js +0 -257
- package/src/lib/doctor/formatters/human.test.js +0 -463
- package/src/lib/doctor/formatters/index.js +0 -8
- package/src/lib/doctor/formatters/json.js +0 -78
- package/src/lib/doctor/formatters/json.test.js +0 -174
- package/src/lib/doctor/formatters/shared.js +0 -129
- package/src/lib/doctor/formatters/shared.test.js +0 -194
- package/src/lib/doctor/index.js +0 -271
- package/src/lib/doctor/index.test.js +0 -797
- package/src/lib/epub/engines.js +0 -46
- package/src/lib/epub/index.test.js +0 -518
- package/src/lib/epub/pandoc.test.js +0 -122
- package/src/lib/epub/schema.js +0 -21
- package/src/lib/error/README.md +0 -170
- package/src/lib/error/handler.js +0 -107
- package/src/lib/git/index.spec.js +0 -80
- package/src/lib/git/index.test.js +0 -453
- package/src/lib/help/frontmatter.js +0 -77
- package/src/lib/help/frontmatter.test.js +0 -139
- package/src/lib/help/index.js +0 -146
- package/src/lib/help/index.test.js +0 -188
- package/src/lib/help/topics/configuration.md +0 -77
- package/src/lib/help/topics/debugging.md +0 -69
- package/src/lib/help/topics/epub.md +0 -74
- package/src/lib/help/topics/pdf.md +0 -74
- package/src/lib/help/topics/publishing.md +0 -80
- package/src/lib/help/topics/workflows.md +0 -50
- package/src/lib/installer/index.js +0 -309
- package/src/lib/installer/index.spec.js +0 -83
- package/src/lib/installer/index.test.js +0 -545
- package/src/lib/logger/README.md +0 -424
- package/src/lib/logger/debug.js +0 -132
- package/src/lib/logger/debug.spec.js +0 -130
- package/src/lib/logger/debug.test.js +0 -128
- package/src/lib/logger/index.js +0 -228
- package/src/lib/logger/index.spec.js +0 -131
- package/src/lib/logger/index.test.js +0 -578
- package/src/lib/npm/README.md +0 -127
- package/src/lib/npm/index.js +0 -198
- package/src/lib/npm/index.spec.js +0 -60
- package/src/lib/npm/index.test.js +0 -355
- package/src/lib/pdf/engines.js +0 -46
- package/src/lib/pdf/index.test.js +0 -708
- package/src/lib/pdf/paged.test.js +0 -366
- package/src/lib/pdf/prince.test.js +0 -202
- package/src/lib/pdf/schema.js +0 -21
- package/src/lib/pdf/split.test.js +0 -445
- package/src/lib/platform.js +0 -95
- package/src/lib/process/manager.js +0 -110
- package/src/lib/process/manager.test.js +0 -55
- package/src/lib/project/build.js +0 -162
- package/src/lib/project/build.test.js +0 -275
- package/src/lib/project/config.js +0 -48
- package/src/lib/project/config.test.js +0 -134
- package/src/lib/project/detect.js +0 -47
- package/src/lib/project/detect.test.js +0 -157
- package/src/lib/project/index.js +0 -56
- package/src/lib/project/output-paths.js +0 -87
- package/src/lib/project/output-paths.test.js +0 -66
- package/src/lib/project/paths.js +0 -272
- package/src/lib/project/version.js +0 -110
- package/src/lib/project/version.test.js +0 -350
- package/src/lib/reporter/index.test.js +0 -862
- package/src/main.spec.js +0 -61
- package/src/main.test.js +0 -347
- package/src/validators/validate-data-files.js +0 -154
- package/src/validators/validate-data-files.test.js +0 -217
package/src/lib/pdf/index.js
CHANGED
|
@@ -1,145 +1,42 @@
|
|
|
1
1
|
import { dynamicImport } from '#helpers/os-utils.js'
|
|
2
|
-
import which from '#helpers/which.js'
|
|
3
2
|
import { fileURLToPath } from 'node:url'
|
|
4
3
|
import path from 'node:path'
|
|
5
|
-
import fs from 'fs-extra'
|
|
6
|
-
import paths, { loadProjectConfig } from '#lib/project/index.js'
|
|
7
|
-
import reporter from '#lib/reporter/index.js'
|
|
8
|
-
import { InvalidPdfLibraryError, MissingBuildOutputError } from '#src/errors/index.js'
|
|
9
|
-
import ENGINE_METADATA from './engines.js'
|
|
10
|
-
import createDebug from '#debug'
|
|
11
|
-
import { ENGINES } from './schema.js'
|
|
12
|
-
|
|
13
|
-
export { ENGINES }
|
|
14
4
|
|
|
15
5
|
const __filename = fileURLToPath(import.meta.url)
|
|
16
6
|
const __dirname = path.dirname(__filename)
|
|
17
7
|
|
|
18
|
-
const debug = createDebug('lib:pdf')
|
|
19
|
-
|
|
20
8
|
/**
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* @param {string} name - Library name to resolve
|
|
24
|
-
* @returns {Object} Resolved engine with absolute module path
|
|
25
|
-
* @throws {InvalidPdfLibraryError} When library name is not recognized
|
|
9
|
+
* A façade delegation module for PDF generation libraries
|
|
26
10
|
*/
|
|
27
|
-
|
|
11
|
+
export default async (name = 'pagedjs', options = {}) => {
|
|
12
|
+
const lib = { name, options, path }
|
|
13
|
+
|
|
28
14
|
const normalizedName = name.replace(/[-_.\s]/g, '').toLowerCase()
|
|
29
15
|
|
|
30
16
|
switch (normalizedName) {
|
|
31
17
|
case 'paged':
|
|
32
|
-
case 'pagedjs':
|
|
33
|
-
|
|
18
|
+
case 'pagedjs': {
|
|
19
|
+
lib.name = 'Paged.js'
|
|
20
|
+
lib.options = options
|
|
21
|
+
lib.path = path.join(__dirname, 'paged.js')
|
|
22
|
+
break
|
|
23
|
+
}
|
|
34
24
|
case 'prince':
|
|
35
|
-
case 'princexml':
|
|
36
|
-
|
|
25
|
+
case 'princexml': {
|
|
26
|
+
lib.name = 'Prince'
|
|
27
|
+
lib.options = options
|
|
28
|
+
lib.path = path.join(__dirname, 'prince.js')
|
|
29
|
+
break
|
|
30
|
+
}
|
|
37
31
|
default:
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Check if the required binary for an engine is available
|
|
44
|
-
*
|
|
45
|
-
* @param {Object} engine - Engine definition from ENGINES
|
|
46
|
-
* @throws {ToolNotFoundError} When required binary is not in PATH
|
|
47
|
-
*/
|
|
48
|
-
function checkEngineAvailable(engine) {
|
|
49
|
-
if (!engine.requiresBinary) {
|
|
50
|
-
return // No binary required (e.g., pagedjs uses Node.js)
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const result = which(engine.requiresBinary, engine.toolInfo)
|
|
54
|
-
debug('found %s at %s', engine.requiresBinary, result)
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Construct the default output path for the PDF from project config
|
|
59
|
-
*
|
|
60
|
-
* @param {string} projectRoot - Project root directory
|
|
61
|
-
* @param {string} outputDir - Build output directory
|
|
62
|
-
* @param {Object} [pdfConfig] - PDF configuration from project config
|
|
63
|
-
* @param {string} libName - Library name for fallback filename
|
|
64
|
-
* @returns {string} Default output path
|
|
65
|
-
*/
|
|
66
|
-
function getDefaultOutputPath(projectRoot, outputDir, pdfConfig, libName) {
|
|
67
|
-
if (pdfConfig) {
|
|
68
|
-
return path.join(projectRoot, outputDir, pdfConfig.outputDir, `${pdfConfig.filename}.pdf`)
|
|
69
|
-
}
|
|
70
|
-
return path.join(projectRoot, `${libName}.pdf`)
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Resolve the final output path, allowing CLI override
|
|
75
|
-
*
|
|
76
|
-
* @param {string} [userOutput] - User-specified output path from --output option
|
|
77
|
-
* @param {string} defaultPath - Default path from project config
|
|
78
|
-
* @param {string} projectRoot - Project root for resolving relative paths
|
|
79
|
-
* @returns {string} Resolved absolute output path
|
|
80
|
-
*/
|
|
81
|
-
function resolveOutputPath(userOutput, defaultPath, projectRoot) {
|
|
82
|
-
if (!userOutput) {
|
|
83
|
-
return defaultPath
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Resolve relative paths against project root
|
|
87
|
-
if (path.isAbsolute(userOutput)) {
|
|
88
|
-
return userOutput
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
return path.join(projectRoot, userOutput)
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Generate a PDF from the built publication
|
|
96
|
-
*
|
|
97
|
-
* @param {Object} options - Generation options
|
|
98
|
-
* @param {string} [options.lib='pagedjs'] - PDF library to use ('pagedjs' or 'prince')
|
|
99
|
-
* @param {string} [options.output] - Custom output path (overrides project config)
|
|
100
|
-
* @param {boolean} [options.debug] - Enable debug output
|
|
101
|
-
* @returns {Promise<string>} Absolute path to the generated PDF file
|
|
102
|
-
*/
|
|
103
|
-
export default async function generatePdf(options = {}) {
|
|
104
|
-
const libName = options.lib || 'pagedjs'
|
|
105
|
-
const lib = resolveLibrary(libName)
|
|
106
|
-
|
|
107
|
-
debug('resolved library: %s → %s', libName, lib.name)
|
|
108
|
-
|
|
109
|
-
// Check engine availability BEFORE starting reporter (fail fast with clean error)
|
|
110
|
-
checkEngineAvailable(lib)
|
|
111
|
-
|
|
112
|
-
const projectRoot = paths.getProjectRoot()
|
|
113
|
-
const buildOutputDir = paths.getOutputDir()
|
|
114
|
-
const config = await loadProjectConfig(projectRoot)
|
|
115
|
-
|
|
116
|
-
const publicationInput = path.join(projectRoot, buildOutputDir, 'pdf.html')
|
|
117
|
-
const coversInput = path.join(projectRoot, buildOutputDir, 'pdf-covers.html')
|
|
118
|
-
|
|
119
|
-
debug('input: %s', publicationInput)
|
|
120
|
-
debug('covers: %s', coversInput)
|
|
121
|
-
|
|
122
|
-
if (!fs.existsSync(publicationInput)) {
|
|
123
|
-
throw new MissingBuildOutputError('pdf.html', publicationInput)
|
|
32
|
+
console.error(`[CLI:lib/pdf] Unrecognized PDF library '${name}'`)
|
|
33
|
+
return
|
|
124
34
|
}
|
|
125
35
|
|
|
126
|
-
const defaultPath = getDefaultOutputPath(projectRoot, buildOutputDir, config.pdf, libName)
|
|
127
|
-
const pdfPath = resolveOutputPath(options.output, defaultPath, projectRoot)
|
|
128
|
-
debug('output: %s (user: %s, default: %s)', pdfPath, options.output || 'none', defaultPath)
|
|
129
|
-
|
|
130
36
|
const { default: pdfLib } = await dynamicImport(lib.path)
|
|
131
37
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
try {
|
|
137
|
-
await pdfLib(publicationInput, coversInput, pdfPath, { ...options, pdfConfig: config.pdf })
|
|
138
|
-
reporter.succeed(`PDF saved to ${pdfPath}`)
|
|
139
|
-
} catch (error) {
|
|
140
|
-
reporter.fail(`PDF generation failed`)
|
|
141
|
-
throw error
|
|
38
|
+
return async (publicationInput, coversInput, output) => {
|
|
39
|
+
console.info(`[CLI:lib/pdf] generating PDF using ${lib.name}`)
|
|
40
|
+
return await pdfLib(publicationInput, coversInput, output, lib.options)
|
|
142
41
|
}
|
|
143
|
-
|
|
144
|
-
return pdfPath
|
|
145
42
|
}
|
package/src/lib/pdf/paged.js
CHANGED
|
@@ -4,39 +4,25 @@ import fs from 'fs-extra'
|
|
|
4
4
|
import path from 'node:path'
|
|
5
5
|
import { fileURLToPath } from 'node:url'
|
|
6
6
|
|
|
7
|
-
import processManager from '#lib/process/manager.js'
|
|
8
|
-
import reporter from '#lib/reporter/index.js'
|
|
9
7
|
import { splitPdf } from './split.js'
|
|
10
|
-
import { PdfGenerationError } from '#src/errors/index.js'
|
|
11
|
-
import ENGINES from './engines.js'
|
|
12
|
-
import createDebug from '#debug'
|
|
13
8
|
|
|
14
9
|
const __filename = fileURLToPath(import.meta.url)
|
|
15
10
|
const __dirname = path.dirname(__filename)
|
|
16
11
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
/** Re-export engine metadata from central registry */
|
|
20
|
-
export const metadata = ENGINES.pagedjs
|
|
12
|
+
// FIXME: This module swallows errors currently.
|
|
21
13
|
|
|
22
14
|
/**
|
|
23
|
-
* A façade module for interacting with Paged.js and pagedjs-cli
|
|
15
|
+
* A façade module for interacting with Paged.js and pagedjs-cli
|
|
24
16
|
* @see https://gitlab.coko.foundation/pagedjs/
|
|
25
|
-
*
|
|
26
|
-
* @param {string} publicationInput - Path to the publication HTML file
|
|
27
|
-
* @param {string} coversInput - Path to the covers HTML file
|
|
28
|
-
* @param {string} pdfPath - Path where the PDF should be written
|
|
29
|
-
* @param {Object} [options={}] - Generation options
|
|
30
|
-
* @returns {Promise<string>} Path to the generated PDF file
|
|
31
17
|
*/
|
|
32
|
-
export default async (publicationInput, coversInput,
|
|
18
|
+
export default async (publicationInput, coversInput, output, options = {}) => {
|
|
33
19
|
/**
|
|
34
20
|
* Configure the Paged.js Printer options
|
|
35
21
|
* @see https://gitlab.coko.foundation/pagedjs/pagedjs-cli/-/blob/main/src/cli.js
|
|
36
22
|
*/
|
|
37
23
|
|
|
38
24
|
let additionalScripts = []
|
|
39
|
-
|
|
25
|
+
|
|
40
26
|
const { pdfConfig } = options
|
|
41
27
|
|
|
42
28
|
additionalScripts.push( path.join(__dirname, 'pagedPlugin.js') )
|
|
@@ -49,35 +35,25 @@ export default async (publicationInput, coversInput, pdfPath, options = {}) => {
|
|
|
49
35
|
additionalScripts,
|
|
50
36
|
}
|
|
51
37
|
|
|
52
|
-
|
|
38
|
+
if (options.debug) {
|
|
39
|
+
const optionsOutput = JSON.stringify(printerOptions, null, 2)
|
|
40
|
+
console.debug(`[CLI:lib/pdf/pagedjs] Printer options\n${optionsOutput}`)
|
|
41
|
+
}
|
|
53
42
|
|
|
54
43
|
let printer = new Printer(printerOptions)
|
|
55
44
|
|
|
56
|
-
|
|
57
|
-
processManager.onShutdown('pagedjs', () => {
|
|
58
|
-
debug('closing printer')
|
|
59
|
-
printer.close()
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
printer.on('page', (page, pageElement, breakToken) => {
|
|
45
|
+
printer.on('page', (page,pageElement,breakToken) => {
|
|
63
46
|
if (page.position === 0) {
|
|
64
|
-
|
|
65
|
-
}
|
|
47
|
+
console.info(`[CLI:lib/pdf/pagedjs] loaded`)
|
|
48
|
+
}
|
|
66
49
|
})
|
|
67
50
|
|
|
68
51
|
printer.on('rendered', (msg) => {
|
|
69
|
-
|
|
52
|
+
console.info(`[CLI:lib/pdf/pagedjs] ${msg}`)
|
|
70
53
|
})
|
|
71
54
|
|
|
72
55
|
printer.on('postprocessing', () => {
|
|
73
|
-
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
// Capture browser console messages for debugging
|
|
77
|
-
printer.on('console', (type, ...args) => {
|
|
78
|
-
if (type === 'warning' || type === 'error') {
|
|
79
|
-
debug('browser %s: %s', type, args.join(' '))
|
|
80
|
-
}
|
|
56
|
+
console.info(`[CLI:lib/pdf/pagedjs] post-processing`)
|
|
81
57
|
})
|
|
82
58
|
|
|
83
59
|
/**
|
|
@@ -85,31 +61,29 @@ export default async (publicationInput, coversInput, pdfPath, options = {}) => {
|
|
|
85
61
|
* @see
|
|
86
62
|
*
|
|
87
63
|
* @todo verify options before setting them
|
|
64
|
+
* @todo catch errors thrown by the printer
|
|
88
65
|
*/
|
|
89
66
|
const pdfOptions = {
|
|
90
67
|
outlineTags: options.outlineTags || ['h1'],
|
|
91
68
|
}
|
|
92
69
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
70
|
+
if (options.debug) {
|
|
71
|
+
const optionsOutput = JSON.stringify(pdfOptions, null, 2)
|
|
72
|
+
console.debug(`[CLI:lib/pdf/pagedjs] PDF options\n${optionsOutput}`)
|
|
73
|
+
}
|
|
97
74
|
|
|
98
|
-
let file
|
|
99
75
|
try {
|
|
100
|
-
|
|
101
|
-
} catch (error) {
|
|
102
|
-
throw new PdfGenerationError('Paged.js', 'PDF rendering', error.message)
|
|
103
|
-
}
|
|
76
|
+
console.info(`[CLI:lib/pdf/pagedjs] printing ${publicationInput}`)
|
|
104
77
|
|
|
105
|
-
|
|
78
|
+
const file = await printer.pdf(publicationInput, pdfOptions)
|
|
79
|
+
.catch((error) => console.error(error))
|
|
106
80
|
|
|
107
|
-
|
|
108
|
-
let coversFile
|
|
81
|
+
let pageMap
|
|
109
82
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
83
|
+
// Now it's printed, create the pageMap by running JS in the printer's context
|
|
84
|
+
let coversFile
|
|
85
|
+
|
|
86
|
+
console.info(`[CLI:lib/pdf/pagedjs] generating page map`)
|
|
113
87
|
const pages = await printer.browser.pages()
|
|
114
88
|
|
|
115
89
|
if (pages.length > 0) {
|
|
@@ -118,24 +92,15 @@ export default async (publicationInput, coversInput, pdfPath, options = {}) => {
|
|
|
118
92
|
return window.pageMap ?? {} // eslint-disable-line no-undef
|
|
119
93
|
})
|
|
120
94
|
}
|
|
121
|
-
} catch (error) {
|
|
122
|
-
throw new PdfGenerationError('Paged.js', 'page map extraction', error.message)
|
|
123
|
-
}
|
|
124
95
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
reporter.update('Rendering cover pages...')
|
|
96
|
+
if ( pdfConfig?.pagePDF?.coverPage===true && fs.existsSync(coversInput) ) {
|
|
97
|
+
console.info(`[CLI:lib/pdf/pagedjs] printing ${coversInput}`)
|
|
128
98
|
|
|
129
|
-
|
|
99
|
+
const coverPrinter = new Printer(printerOptions)
|
|
130
100
|
|
|
131
|
-
try {
|
|
132
101
|
coversFile = await coverPrinter.pdf(coversInput, pdfOptions)
|
|
133
|
-
|
|
134
|
-
coverPrinter.close()
|
|
135
|
-
throw new PdfGenerationError('Paged.js', 'cover PDF rendering', error.message)
|
|
136
|
-
}
|
|
102
|
+
.catch((error) => console.error(error))
|
|
137
103
|
|
|
138
|
-
try {
|
|
139
104
|
const coverPages = await coverPrinter.browser.pages()
|
|
140
105
|
|
|
141
106
|
if (coverPages.length > 0) {
|
|
@@ -146,53 +111,40 @@ export default async (publicationInput, coversInput, pdfPath, options = {}) => {
|
|
|
146
111
|
|
|
147
112
|
Object.values(coversMap).forEach( cov => {
|
|
148
113
|
if (cov.id in pageMap) {
|
|
149
|
-
pageMap[cov.id].coverPage = cov.startPage
|
|
114
|
+
pageMap[cov.id].coverPage = cov.startPage
|
|
150
115
|
}
|
|
151
116
|
})
|
|
152
|
-
}
|
|
153
|
-
} catch (error) {
|
|
154
|
-
coverPrinter.close()
|
|
155
|
-
throw new PdfGenerationError('Paged.js', 'cover page map extraction', error.message)
|
|
156
|
-
}
|
|
157
117
|
|
|
158
|
-
|
|
159
|
-
}
|
|
118
|
+
}
|
|
160
119
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
printer.close()
|
|
164
|
-
}
|
|
120
|
+
coverPrinter.close()
|
|
121
|
+
}
|
|
165
122
|
|
|
166
|
-
|
|
167
|
-
|
|
123
|
+
// Leave the printer open for debug logs
|
|
124
|
+
if (!options.debug) {
|
|
125
|
+
printer.close()
|
|
126
|
+
}
|
|
168
127
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
reporter.update('Writing PDF files...')
|
|
128
|
+
if (file && output) {
|
|
129
|
+
console.info(`[CLI:lib/pdf/pagedjs] writing file(s)`)
|
|
172
130
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
if (!fs.existsSync(dir)) {
|
|
131
|
+
const { dir } = path.parse(output)
|
|
132
|
+
if (!fs.existsSync(dir)) {
|
|
176
133
|
fs.mkdirsSync(dir)
|
|
177
134
|
}
|
|
178
135
|
|
|
179
|
-
await fs.promises.writeFile(
|
|
180
|
-
|
|
181
|
-
throw new PdfGenerationError('Paged.js', 'PDF file write', error.message)
|
|
182
|
-
}
|
|
136
|
+
await fs.promises.writeFile(output, file)
|
|
137
|
+
.catch((error) => console.error(error))
|
|
183
138
|
|
|
184
|
-
|
|
185
|
-
const files = await splitPdf(file, coversFile, pageMap, options.pdfConfig)
|
|
139
|
+
const files = await splitPdf(file,coversFile,pageMap,options.pdfConfig)
|
|
186
140
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
)
|
|
192
|
-
} catch (error) {
|
|
193
|
-
throw new PdfGenerationError('Paged.js', 'PDF splitting', error.message)
|
|
141
|
+
Object.entries(files).forEach( async ([filePath,pagePdf]) => {
|
|
142
|
+
await fs.promises.writeFile(filePath,pagePdf)
|
|
143
|
+
.catch((error) => console.error(error))
|
|
144
|
+
})
|
|
194
145
|
}
|
|
195
|
-
}
|
|
196
146
|
|
|
197
|
-
|
|
147
|
+
} catch (ERR_FILE_NOT_FOUND) {
|
|
148
|
+
console.error(`[CLI:lib/pdf/pagedjs] file not found ${publicationInput}`)
|
|
149
|
+
}
|
|
198
150
|
}
|
package/src/lib/pdf/prince.js
CHANGED
|
@@ -5,53 +5,33 @@ import { fileURLToPath } from 'node:url'
|
|
|
5
5
|
import { splitPdf } from './split.js'
|
|
6
6
|
import fs from 'fs-extra'
|
|
7
7
|
|
|
8
|
-
import
|
|
9
|
-
import reporter from '#lib/reporter/index.js'
|
|
10
|
-
import { PdfGenerationError } from '#src/errors/index.js'
|
|
11
|
-
import createDebug from '#debug'
|
|
12
|
-
import ENGINES from './engines.js'
|
|
8
|
+
import which from '#helpers/which.js'
|
|
13
9
|
|
|
14
10
|
const __filename = fileURLToPath(import.meta.url)
|
|
15
11
|
const __dirname = path.dirname(__filename)
|
|
16
12
|
|
|
17
|
-
const debug = createDebug('lib:pdf:prince')
|
|
18
|
-
|
|
19
|
-
/** Re-export engine metadata from central registry */
|
|
20
|
-
export const metadata = ENGINES.prince
|
|
21
|
-
|
|
22
13
|
/**
|
|
23
14
|
* A façade module for interacting with the Prince CLI.
|
|
24
15
|
* @see https://www.princexml.com/doc/command-line/
|
|
25
|
-
*
|
|
26
|
-
* Prince availability is checked by the parent façade (lib/pdf/index.js)
|
|
27
|
-
* before this module is loaded, so we can assume prince is in PATH.
|
|
28
|
-
*
|
|
29
|
-
* @param {string} publicationInput - Path to the publication HTML file
|
|
30
|
-
* @param {string} coversInput - Path to the covers HTML file
|
|
31
|
-
* @param {string} pdfPath - Path where the PDF should be written
|
|
32
|
-
* @param {Object} [options={}] - Generation options
|
|
33
|
-
* @returns {Promise<string>} Path to the generated PDF file
|
|
34
16
|
*/
|
|
35
|
-
export default async (publicationInput, coversInput,
|
|
36
|
-
|
|
37
|
-
debug('covers: %s', coversInput)
|
|
38
|
-
debug('output: %s', pdfPath)
|
|
17
|
+
export default async (publicationInput, coversInput, output, options = {}) => {
|
|
18
|
+
which('prince')
|
|
39
19
|
|
|
40
20
|
/**
|
|
41
21
|
* @see https://www.princexml.com/doc/command-line/#options
|
|
42
22
|
*/
|
|
43
|
-
|
|
23
|
+
|
|
44
24
|
const { pdfConfig } = options
|
|
45
25
|
|
|
46
26
|
// These options run once to get the map pages to essays
|
|
47
27
|
const pageMapOptions = [
|
|
48
28
|
`--script=${ path.join(__dirname, 'princePlugin.js') }`,
|
|
49
|
-
`--output=${
|
|
29
|
+
`--output=${output}`,
|
|
50
30
|
]
|
|
51
31
|
|
|
52
32
|
// These options are for the actual user-facing PDF
|
|
53
33
|
const cmdOptions = [
|
|
54
|
-
`--output=${
|
|
34
|
+
`--output=${output}`,
|
|
55
35
|
`--pdf-profile=PDF/UA-1`,
|
|
56
36
|
]
|
|
57
37
|
|
|
@@ -59,118 +39,60 @@ export default async (publicationInput, coversInput, pdfPath, options = {}) => {
|
|
|
59
39
|
pageMapOptions.push('--debug')
|
|
60
40
|
cmdOptions.push('--debug')
|
|
61
41
|
}
|
|
62
|
-
|
|
42
|
+
|
|
63
43
|
if (options.verbose) {
|
|
64
44
|
pageMapOptions.push('--verbose')
|
|
65
45
|
cmdOptions.push('--verbose')
|
|
66
46
|
}
|
|
67
47
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
try {
|
|
72
|
-
const { dir } = path.parse(pdfPath)
|
|
73
|
-
if (!fs.existsSync(dir)) {
|
|
74
|
-
fs.mkdirsSync(dir)
|
|
75
|
-
}
|
|
76
|
-
} catch (error) {
|
|
77
|
-
throw new PdfGenerationError('Prince', 'output directory creation', error.message)
|
|
48
|
+
const { dir } = path.parse(output)
|
|
49
|
+
if (!fs.existsSync(dir)) {
|
|
50
|
+
fs.mkdirsSync(dir)
|
|
78
51
|
}
|
|
79
|
-
|
|
80
|
-
// Execute page
|
|
81
|
-
debug('analyzing document structure')
|
|
82
|
-
reporter.update('Analyzing document structure...')
|
|
52
|
+
|
|
53
|
+
// Execute the page mapping PDF build
|
|
83
54
|
let pageMap = {}
|
|
84
55
|
try {
|
|
85
|
-
const pageMapOutput = await execa('prince', [...pageMapOptions, publicationInput]
|
|
86
|
-
cancelSignal: processManager.signal,
|
|
87
|
-
gracefulCancel: true
|
|
88
|
-
})
|
|
56
|
+
const pageMapOutput = await execa('prince', [...pageMapOptions, publicationInput])
|
|
89
57
|
pageMap = JSON.parse(pageMapOutput.stdout)
|
|
90
|
-
} catch (
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
reporter.warn('PDF generation cancelled')
|
|
94
|
-
return
|
|
95
|
-
}
|
|
96
|
-
throw new PdfGenerationError('Prince', 'page map generation', error.stderr)
|
|
58
|
+
} catch (err) {
|
|
59
|
+
console.error(`Generating the PDF page map failed with the error ${err.stderr}`)
|
|
60
|
+
process.exit(1)
|
|
97
61
|
}
|
|
98
|
-
debug('page map generated: %d entries', Object.keys(pageMap).length)
|
|
99
62
|
|
|
100
63
|
let coversData
|
|
101
64
|
|
|
102
65
|
if (pdfConfig?.pagePDF?.coverPage === true && fs.existsSync(coversInput)) {
|
|
103
|
-
debug('generating cover page map')
|
|
104
|
-
reporter.update('Rendering cover pages...')
|
|
105
|
-
try {
|
|
106
|
-
const coversPageMapOutput = await execa('prince', [...pageMapOptions, coversInput], {
|
|
107
|
-
cancelSignal: processManager.signal,
|
|
108
|
-
gracefulCancel: true
|
|
109
|
-
})
|
|
110
|
-
const coversMap = JSON.parse(coversPageMapOutput.stdout)
|
|
111
|
-
|
|
112
|
-
for (const pageId of Object.keys(coversMap)) {
|
|
113
|
-
if (pageId in pageMap) {
|
|
114
|
-
pageMap[pageId].coverPage = coversMap[pageId].startPage
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
66
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
67
|
+
const coversPageMapOutput = await execa('prince', [...pageMapOptions, coversInput])
|
|
68
|
+
const coversMap = JSON.parse(coversPageMapOutput.stdout)
|
|
69
|
+
|
|
70
|
+
for (const pageId of Object.keys(coversMap)) {
|
|
71
|
+
if (pageId in pageMap) {
|
|
72
|
+
pageMap[pageId].coverPage = coversMap[pageId].startPage
|
|
124
73
|
}
|
|
125
|
-
throw new PdfGenerationError('Prince', 'cover page map generation', error.stderr || error.message)
|
|
126
74
|
}
|
|
127
|
-
debug('cover page map merged')
|
|
128
|
-
}
|
|
129
75
|
|
|
130
|
-
|
|
131
|
-
reporter.update('Rendering PDF...')
|
|
76
|
+
coversData = fs.readFileSync(output,null)
|
|
132
77
|
|
|
133
|
-
try {
|
|
134
|
-
const { stderr } = await execa('prince', [...cmdOptions, publicationInput], {
|
|
135
|
-
cancelSignal: processManager.signal,
|
|
136
|
-
gracefulCancel: true
|
|
137
|
-
})
|
|
138
|
-
// Prince may emit warnings to stderr even on success (CSS warnings, font substitutions, etc.)
|
|
139
|
-
if (stderr) {
|
|
140
|
-
debug('prince warnings: %s', stderr)
|
|
141
|
-
}
|
|
142
|
-
} catch (error) {
|
|
143
|
-
if (error.isCanceled) {
|
|
144
|
-
debug('PDF printing cancelled')
|
|
145
|
-
reporter.warn('PDF generation cancelled')
|
|
146
|
-
return
|
|
147
|
-
}
|
|
148
|
-
throw new PdfGenerationError('Prince', 'PDF printing', error.stderr)
|
|
149
78
|
}
|
|
150
|
-
debug('PDF printed')
|
|
151
79
|
|
|
152
|
-
let
|
|
153
|
-
try {
|
|
154
|
-
pdfData = fs.readFileSync(pdfPath, null)
|
|
155
|
-
} catch (error) {
|
|
156
|
-
throw new PdfGenerationError('Prince', 'PDF file read', error.message)
|
|
157
|
-
}
|
|
80
|
+
let stderror,stdout
|
|
158
81
|
|
|
159
|
-
debug('splitting PDF')
|
|
160
|
-
reporter.update('Writing PDF files...')
|
|
161
82
|
try {
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
Object.entries(files).map(([filePath, pagePdf]) =>
|
|
167
|
-
fs.promises.writeFile(filePath, pagePdf)
|
|
168
|
-
)
|
|
169
|
-
)
|
|
170
|
-
} catch (error) {
|
|
171
|
-
throw new PdfGenerationError('Prince', 'PDF splitting', error.message)
|
|
83
|
+
({ stderror, stdout } = await execa('prince', [...cmdOptions, publicationInput]))
|
|
84
|
+
} catch (err) {
|
|
85
|
+
console.error(`Printing the PDF failed with the error ${err.stderr}`)
|
|
86
|
+
process.exit(1)
|
|
172
87
|
}
|
|
173
88
|
|
|
174
|
-
|
|
175
|
-
|
|
89
|
+
const pdfData = fs.readFileSync(output,null)
|
|
90
|
+
|
|
91
|
+
let files = await splitPdf(pdfData,coversData,pageMap,pdfConfig)
|
|
92
|
+
Object.entries(files).forEach( async ([filePath,pagePdf]) => {
|
|
93
|
+
await fs.promises.writeFile(filePath,pagePdf)
|
|
94
|
+
.catch((error) => console.error(error))
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
return { stderror, stdout }
|
|
176
98
|
}
|