@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
|
@@ -1,366 +0,0 @@
|
|
|
1
|
-
import esmock from 'esmock'
|
|
2
|
-
import path from 'node:path'
|
|
3
|
-
import sinon from 'sinon'
|
|
4
|
-
import test from 'ava'
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Paged.js PDF Engine Integration Tests
|
|
8
|
-
*
|
|
9
|
-
* Tests error handling paths that are difficult to trigger in E2E tests.
|
|
10
|
-
* The happy path is covered by E2E tests with real Paged.js/Puppeteer.
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Create a cross-platform absolute path for testing
|
|
15
|
-
* @param {...string} segments - Path segments to join
|
|
16
|
-
* @returns {string} Platform-appropriate absolute path
|
|
17
|
-
*/
|
|
18
|
-
function testPath(...segments) {
|
|
19
|
-
const root = process.platform === 'win32' ? 'C:\\' : '/'
|
|
20
|
-
return path.join(root, ...segments)
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
test.beforeEach((t) => {
|
|
24
|
-
t.context.sandbox = sinon.createSandbox()
|
|
25
|
-
|
|
26
|
-
// Mock reporter
|
|
27
|
-
t.context.mockReporter = {
|
|
28
|
-
update: t.context.sandbox.stub(),
|
|
29
|
-
warn: t.context.sandbox.stub()
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// Mock processManager
|
|
33
|
-
t.context.mockProcessManager = {
|
|
34
|
-
onShutdown: t.context.sandbox.stub(),
|
|
35
|
-
onShutdownComplete: t.context.sandbox.stub()
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Mock fs-extra
|
|
39
|
-
t.context.mockFs = {
|
|
40
|
-
existsSync: t.context.sandbox.stub().returns(true),
|
|
41
|
-
mkdirsSync: t.context.sandbox.stub(),
|
|
42
|
-
promises: {
|
|
43
|
-
writeFile: t.context.sandbox.stub().resolves()
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
test.afterEach.always((t) => {
|
|
49
|
-
t.context.sandbox.restore()
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Create a mock Printer instance
|
|
54
|
-
*/
|
|
55
|
-
function createMockPrinter(sandbox, options = {}) {
|
|
56
|
-
const mockPrinter = {
|
|
57
|
-
on: sandbox.stub(),
|
|
58
|
-
close: sandbox.stub(),
|
|
59
|
-
pdf: options.pdf || sandbox.stub().resolves(Buffer.from([1, 2, 3])),
|
|
60
|
-
browser: {
|
|
61
|
-
pages: options.pages || sandbox.stub().resolves([{
|
|
62
|
-
evaluate: sandbox.stub().resolves({})
|
|
63
|
-
}])
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
return mockPrinter
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
70
|
-
// Error handling tests
|
|
71
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
72
|
-
|
|
73
|
-
test('throws PdfGenerationError when PDF rendering fails', async (t) => {
|
|
74
|
-
const { sandbox, mockReporter, mockProcessManager, mockFs } = t.context
|
|
75
|
-
|
|
76
|
-
const mockPrinter = createMockPrinter(sandbox, {
|
|
77
|
-
pdf: sandbox.stub().rejects(new Error('Puppeteer crashed: out of memory'))
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
const MockPrinter = sandbox.stub().returns(mockPrinter)
|
|
81
|
-
|
|
82
|
-
const paged = await esmock('./paged.js', {
|
|
83
|
-
'pagedjs-cli': MockPrinter,
|
|
84
|
-
'fs-extra': mockFs,
|
|
85
|
-
'#lib/reporter/index.js': { default: mockReporter },
|
|
86
|
-
'#lib/process/manager.js': { default: mockProcessManager }
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
const error = await t.throwsAsync(() =>
|
|
90
|
-
paged.default(testPath('input.html'), testPath('covers.html'), testPath('output.pdf'), {})
|
|
91
|
-
)
|
|
92
|
-
|
|
93
|
-
t.is(error.code, 'PDF_FAILED')
|
|
94
|
-
t.true(error.message.includes('Paged.js'))
|
|
95
|
-
t.true(error.message.includes('PDF rendering'))
|
|
96
|
-
t.true(error.message.includes('out of memory'))
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
test('throws PdfGenerationError when page map extraction fails', async (t) => {
|
|
100
|
-
const { sandbox, mockReporter, mockProcessManager, mockFs } = t.context
|
|
101
|
-
|
|
102
|
-
const mockPrinter = createMockPrinter(sandbox, {
|
|
103
|
-
pages: sandbox.stub().rejects(new Error('Browser context destroyed'))
|
|
104
|
-
})
|
|
105
|
-
|
|
106
|
-
const MockPrinter = sandbox.stub().returns(mockPrinter)
|
|
107
|
-
|
|
108
|
-
const paged = await esmock('./paged.js', {
|
|
109
|
-
'pagedjs-cli': MockPrinter,
|
|
110
|
-
'fs-extra': mockFs,
|
|
111
|
-
'#lib/reporter/index.js': { default: mockReporter },
|
|
112
|
-
'#lib/process/manager.js': { default: mockProcessManager }
|
|
113
|
-
})
|
|
114
|
-
|
|
115
|
-
const error = await t.throwsAsync(() =>
|
|
116
|
-
paged.default(testPath('input.html'), testPath('covers.html'), testPath('output.pdf'), {})
|
|
117
|
-
)
|
|
118
|
-
|
|
119
|
-
t.is(error.code, 'PDF_FAILED')
|
|
120
|
-
t.true(error.message.includes('Paged.js'))
|
|
121
|
-
t.true(error.message.includes('page map extraction'))
|
|
122
|
-
t.true(error.message.includes('Browser context destroyed'))
|
|
123
|
-
})
|
|
124
|
-
|
|
125
|
-
test('throws PdfGenerationError when cover PDF rendering fails', async (t) => {
|
|
126
|
-
const { sandbox, mockReporter, mockProcessManager, mockFs } = t.context
|
|
127
|
-
|
|
128
|
-
// Main printer succeeds
|
|
129
|
-
const mainPrinter = createMockPrinter(sandbox)
|
|
130
|
-
|
|
131
|
-
// Cover printer fails
|
|
132
|
-
const coverPrinter = createMockPrinter(sandbox, {
|
|
133
|
-
pdf: sandbox.stub().rejects(new Error('Cover page timeout'))
|
|
134
|
-
})
|
|
135
|
-
|
|
136
|
-
let printerCallCount = 0
|
|
137
|
-
const MockPrinter = sandbox.stub().callsFake(() => {
|
|
138
|
-
printerCallCount++
|
|
139
|
-
return printerCallCount === 1 ? mainPrinter : coverPrinter
|
|
140
|
-
})
|
|
141
|
-
|
|
142
|
-
const paged = await esmock('./paged.js', {
|
|
143
|
-
'pagedjs-cli': MockPrinter,
|
|
144
|
-
'fs-extra': mockFs,
|
|
145
|
-
'#lib/reporter/index.js': { default: mockReporter },
|
|
146
|
-
'#lib/process/manager.js': { default: mockProcessManager }
|
|
147
|
-
})
|
|
148
|
-
|
|
149
|
-
// Enable cover page generation
|
|
150
|
-
const options = {
|
|
151
|
-
pdfConfig: { pagePDF: { coverPage: true } }
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
const error = await t.throwsAsync(() =>
|
|
155
|
-
paged.default(testPath('input.html'), testPath('covers.html'), testPath('output.pdf'), options)
|
|
156
|
-
)
|
|
157
|
-
|
|
158
|
-
t.is(error.code, 'PDF_FAILED')
|
|
159
|
-
t.true(error.message.includes('Paged.js'))
|
|
160
|
-
t.true(error.message.includes('cover PDF rendering'))
|
|
161
|
-
t.true(error.message.includes('Cover page timeout'))
|
|
162
|
-
// Verify cover printer was closed on error
|
|
163
|
-
t.true(coverPrinter.close.called)
|
|
164
|
-
})
|
|
165
|
-
|
|
166
|
-
test('throws PdfGenerationError when cover page map extraction fails', async (t) => {
|
|
167
|
-
const { sandbox, mockReporter, mockProcessManager, mockFs } = t.context
|
|
168
|
-
|
|
169
|
-
// Main printer succeeds
|
|
170
|
-
const mainPrinter = createMockPrinter(sandbox)
|
|
171
|
-
|
|
172
|
-
// Cover printer PDF succeeds but pages() fails
|
|
173
|
-
const coverPrinter = createMockPrinter(sandbox, {
|
|
174
|
-
pages: sandbox.stub().rejects(new Error('Cover browser crashed'))
|
|
175
|
-
})
|
|
176
|
-
|
|
177
|
-
let printerCallCount = 0
|
|
178
|
-
const MockPrinter = sandbox.stub().callsFake(() => {
|
|
179
|
-
printerCallCount++
|
|
180
|
-
return printerCallCount === 1 ? mainPrinter : coverPrinter
|
|
181
|
-
})
|
|
182
|
-
|
|
183
|
-
const paged = await esmock('./paged.js', {
|
|
184
|
-
'pagedjs-cli': MockPrinter,
|
|
185
|
-
'fs-extra': mockFs,
|
|
186
|
-
'#lib/reporter/index.js': { default: mockReporter },
|
|
187
|
-
'#lib/process/manager.js': { default: mockProcessManager }
|
|
188
|
-
})
|
|
189
|
-
|
|
190
|
-
const options = {
|
|
191
|
-
pdfConfig: { pagePDF: { coverPage: true } }
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
const error = await t.throwsAsync(() =>
|
|
195
|
-
paged.default(testPath('input.html'), testPath('covers.html'), testPath('output.pdf'), options)
|
|
196
|
-
)
|
|
197
|
-
|
|
198
|
-
t.is(error.code, 'PDF_FAILED')
|
|
199
|
-
t.true(error.message.includes('Paged.js'))
|
|
200
|
-
t.true(error.message.includes('cover page map extraction'))
|
|
201
|
-
t.true(error.message.includes('Cover browser crashed'))
|
|
202
|
-
t.true(coverPrinter.close.called)
|
|
203
|
-
})
|
|
204
|
-
|
|
205
|
-
test('throws PdfGenerationError when PDF file write fails', async (t) => {
|
|
206
|
-
const { sandbox, mockReporter, mockProcessManager } = t.context
|
|
207
|
-
|
|
208
|
-
const mockPrinter = createMockPrinter(sandbox)
|
|
209
|
-
const MockPrinter = sandbox.stub().returns(mockPrinter)
|
|
210
|
-
|
|
211
|
-
const mockFs = {
|
|
212
|
-
existsSync: sandbox.stub().returns(false),
|
|
213
|
-
mkdirsSync: sandbox.stub().throws(new Error('EACCES: permission denied')),
|
|
214
|
-
promises: { writeFile: sandbox.stub() }
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
const paged = await esmock('./paged.js', {
|
|
218
|
-
'pagedjs-cli': MockPrinter,
|
|
219
|
-
'fs-extra': mockFs,
|
|
220
|
-
'#lib/reporter/index.js': { default: mockReporter },
|
|
221
|
-
'#lib/process/manager.js': { default: mockProcessManager }
|
|
222
|
-
})
|
|
223
|
-
|
|
224
|
-
const error = await t.throwsAsync(() =>
|
|
225
|
-
paged.default(testPath('input.html'), testPath('covers.html'), testPath('restricted', 'output.pdf'), {})
|
|
226
|
-
)
|
|
227
|
-
|
|
228
|
-
t.is(error.code, 'PDF_FAILED')
|
|
229
|
-
t.true(error.message.includes('Paged.js'))
|
|
230
|
-
t.true(error.message.includes('PDF file write'))
|
|
231
|
-
t.true(error.message.includes('permission denied'))
|
|
232
|
-
})
|
|
233
|
-
|
|
234
|
-
test('closes printer on successful completion when not in debug mode', async (t) => {
|
|
235
|
-
const { sandbox, mockReporter, mockProcessManager, mockFs } = t.context
|
|
236
|
-
|
|
237
|
-
const mockPrinter = createMockPrinter(sandbox)
|
|
238
|
-
const MockPrinter = sandbox.stub().returns(mockPrinter)
|
|
239
|
-
|
|
240
|
-
const paged = await esmock('./paged.js', {
|
|
241
|
-
'pagedjs-cli': MockPrinter,
|
|
242
|
-
'fs-extra': mockFs,
|
|
243
|
-
'#lib/reporter/index.js': { default: mockReporter },
|
|
244
|
-
'#lib/process/manager.js': { default: mockProcessManager },
|
|
245
|
-
'./split.js': { splitPdf: sandbox.stub().resolves({}) }
|
|
246
|
-
})
|
|
247
|
-
|
|
248
|
-
await paged.default(testPath('input.html'), testPath('covers.html'), testPath('output.pdf'), { debug: false })
|
|
249
|
-
|
|
250
|
-
t.true(mockPrinter.close.called)
|
|
251
|
-
t.true(mockProcessManager.onShutdownComplete.calledWith('pagedjs'))
|
|
252
|
-
})
|
|
253
|
-
|
|
254
|
-
test('keeps printer open when in debug mode', async (t) => {
|
|
255
|
-
const { sandbox, mockReporter, mockProcessManager, mockFs } = t.context
|
|
256
|
-
|
|
257
|
-
const mockPrinter = createMockPrinter(sandbox)
|
|
258
|
-
const MockPrinter = sandbox.stub().returns(mockPrinter)
|
|
259
|
-
|
|
260
|
-
const paged = await esmock('./paged.js', {
|
|
261
|
-
'pagedjs-cli': MockPrinter,
|
|
262
|
-
'fs-extra': mockFs,
|
|
263
|
-
'#lib/reporter/index.js': { default: mockReporter },
|
|
264
|
-
'#lib/process/manager.js': { default: mockProcessManager },
|
|
265
|
-
'./split.js': { splitPdf: sandbox.stub().resolves({}) }
|
|
266
|
-
})
|
|
267
|
-
|
|
268
|
-
await paged.default(testPath('input.html'), testPath('covers.html'), testPath('output.pdf'), { debug: true })
|
|
269
|
-
|
|
270
|
-
t.false(mockPrinter.close.called)
|
|
271
|
-
})
|
|
272
|
-
|
|
273
|
-
test('registers console event handler for browser warnings and errors', async (t) => {
|
|
274
|
-
const { sandbox, mockReporter, mockProcessManager, mockFs } = t.context
|
|
275
|
-
|
|
276
|
-
const mockPrinter = createMockPrinter(sandbox)
|
|
277
|
-
const MockPrinter = sandbox.stub().returns(mockPrinter)
|
|
278
|
-
|
|
279
|
-
const mockDebug = sandbox.stub()
|
|
280
|
-
const mockCreateDebug = sandbox.stub().returns(mockDebug)
|
|
281
|
-
|
|
282
|
-
const paged = await esmock('./paged.js', {
|
|
283
|
-
'pagedjs-cli': MockPrinter,
|
|
284
|
-
'fs-extra': mockFs,
|
|
285
|
-
'#lib/reporter/index.js': { default: mockReporter },
|
|
286
|
-
'#lib/process/manager.js': { default: mockProcessManager },
|
|
287
|
-
'#debug': { default: mockCreateDebug },
|
|
288
|
-
'./split.js': { splitPdf: sandbox.stub().resolves({}) }
|
|
289
|
-
})
|
|
290
|
-
|
|
291
|
-
await paged.default(testPath('input.html'), testPath('covers.html'), testPath('output.pdf'), {})
|
|
292
|
-
|
|
293
|
-
// Verify console handler was registered
|
|
294
|
-
const consoleHandler = mockPrinter.on.getCalls().find(call => call.args[0] === 'console')
|
|
295
|
-
t.truthy(consoleHandler, 'console event handler should be registered')
|
|
296
|
-
|
|
297
|
-
// Simulate console warning
|
|
298
|
-
const handler = consoleHandler.args[1]
|
|
299
|
-
handler('warning', 'CSS property not supported')
|
|
300
|
-
|
|
301
|
-
t.true(mockDebug.calledWith('browser %s: %s', 'warning', 'CSS property not supported'))
|
|
302
|
-
})
|
|
303
|
-
|
|
304
|
-
test('logs browser errors via debug', async (t) => {
|
|
305
|
-
const { sandbox, mockReporter, mockProcessManager, mockFs } = t.context
|
|
306
|
-
|
|
307
|
-
const mockPrinter = createMockPrinter(sandbox)
|
|
308
|
-
const MockPrinter = sandbox.stub().returns(mockPrinter)
|
|
309
|
-
|
|
310
|
-
const mockDebug = sandbox.stub()
|
|
311
|
-
const mockCreateDebug = sandbox.stub().returns(mockDebug)
|
|
312
|
-
|
|
313
|
-
const paged = await esmock('./paged.js', {
|
|
314
|
-
'pagedjs-cli': MockPrinter,
|
|
315
|
-
'fs-extra': mockFs,
|
|
316
|
-
'#lib/reporter/index.js': { default: mockReporter },
|
|
317
|
-
'#lib/process/manager.js': { default: mockProcessManager },
|
|
318
|
-
'#debug': { default: mockCreateDebug },
|
|
319
|
-
'./split.js': { splitPdf: sandbox.stub().resolves({}) }
|
|
320
|
-
})
|
|
321
|
-
|
|
322
|
-
await paged.default(testPath('input.html'), testPath('covers.html'), testPath('output.pdf'), {})
|
|
323
|
-
|
|
324
|
-
// Get console handler
|
|
325
|
-
const consoleHandler = mockPrinter.on.getCalls().find(call => call.args[0] === 'console')
|
|
326
|
-
const handler = consoleHandler.args[1]
|
|
327
|
-
|
|
328
|
-
// Simulate console error
|
|
329
|
-
handler('error', 'Script error:', 'undefined is not a function')
|
|
330
|
-
|
|
331
|
-
t.true(mockDebug.calledWith('browser %s: %s', 'error', 'Script error: undefined is not a function'))
|
|
332
|
-
})
|
|
333
|
-
|
|
334
|
-
test('ignores non-warning/error console messages', async (t) => {
|
|
335
|
-
const { sandbox, mockReporter, mockProcessManager, mockFs } = t.context
|
|
336
|
-
|
|
337
|
-
const mockPrinter = createMockPrinter(sandbox)
|
|
338
|
-
const MockPrinter = sandbox.stub().returns(mockPrinter)
|
|
339
|
-
|
|
340
|
-
const mockDebug = sandbox.stub()
|
|
341
|
-
const mockCreateDebug = sandbox.stub().returns(mockDebug)
|
|
342
|
-
|
|
343
|
-
const paged = await esmock('./paged.js', {
|
|
344
|
-
'pagedjs-cli': MockPrinter,
|
|
345
|
-
'fs-extra': mockFs,
|
|
346
|
-
'#lib/reporter/index.js': { default: mockReporter },
|
|
347
|
-
'#lib/process/manager.js': { default: mockProcessManager },
|
|
348
|
-
'#debug': { default: mockCreateDebug },
|
|
349
|
-
'./split.js': { splitPdf: sandbox.stub().resolves({}) }
|
|
350
|
-
})
|
|
351
|
-
|
|
352
|
-
await paged.default(testPath('input.html'), testPath('covers.html'), testPath('output.pdf'), {})
|
|
353
|
-
|
|
354
|
-
// Get console handler
|
|
355
|
-
const consoleHandler = mockPrinter.on.getCalls().find(call => call.args[0] === 'console')
|
|
356
|
-
const handler = consoleHandler.args[1]
|
|
357
|
-
|
|
358
|
-
// Reset debug stub to check only calls after handler invocation
|
|
359
|
-
mockDebug.resetHistory()
|
|
360
|
-
|
|
361
|
-
// Simulate console log (should be ignored)
|
|
362
|
-
handler('log', 'Debug info')
|
|
363
|
-
|
|
364
|
-
// Should not have logged this message (info/log messages are ignored)
|
|
365
|
-
t.false(mockDebug.calledWith('browser %s: %s', 'log', 'Debug info'))
|
|
366
|
-
})
|
|
@@ -1,202 +0,0 @@
|
|
|
1
|
-
import esmock from 'esmock'
|
|
2
|
-
import path from 'node:path'
|
|
3
|
-
import sinon from 'sinon'
|
|
4
|
-
import test from 'ava'
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Prince PDF Engine Integration Tests
|
|
8
|
-
*
|
|
9
|
-
* Tests error handling paths that are difficult to trigger in E2E tests.
|
|
10
|
-
* The happy path is covered by E2E tests with real Prince installation.
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Create a cross-platform absolute path for testing
|
|
15
|
-
* @param {...string} segments - Path segments to join
|
|
16
|
-
* @returns {string} Platform-appropriate absolute path
|
|
17
|
-
*/
|
|
18
|
-
function testPath(...segments) {
|
|
19
|
-
const root = process.platform === 'win32' ? 'C:\\' : '/'
|
|
20
|
-
return path.join(root, ...segments)
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
test.beforeEach((t) => {
|
|
24
|
-
t.context.sandbox = sinon.createSandbox()
|
|
25
|
-
|
|
26
|
-
// Mock reporter to prevent actual console output
|
|
27
|
-
t.context.mockReporter = {
|
|
28
|
-
update: t.context.sandbox.stub(),
|
|
29
|
-
warn: t.context.sandbox.stub()
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// Mock processManager
|
|
33
|
-
t.context.mockProcessManager = {
|
|
34
|
-
signal: new AbortController().signal
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Mock fs-extra
|
|
38
|
-
t.context.mockFs = {
|
|
39
|
-
existsSync: t.context.sandbox.stub().returns(true),
|
|
40
|
-
mkdirsSync: t.context.sandbox.stub(),
|
|
41
|
-
readFileSync: t.context.sandbox.stub().returns(Buffer.from([1, 2, 3])),
|
|
42
|
-
promises: {
|
|
43
|
-
writeFile: t.context.sandbox.stub().resolves()
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
test.afterEach.always((t) => {
|
|
49
|
-
t.context.sandbox.restore()
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
53
|
-
// Error handling tests
|
|
54
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
55
|
-
|
|
56
|
-
test('throws PdfGenerationError when page map generation fails', async (t) => {
|
|
57
|
-
const { sandbox, mockReporter, mockProcessManager, mockFs } = t.context
|
|
58
|
-
|
|
59
|
-
const execaError = new Error('Prince failed')
|
|
60
|
-
execaError.stderr = 'error: invalid HTML at line 42'
|
|
61
|
-
|
|
62
|
-
const prince = await esmock('./prince.js', {
|
|
63
|
-
execa: { execa: sandbox.stub().rejects(execaError) },
|
|
64
|
-
'fs-extra': mockFs,
|
|
65
|
-
'#lib/reporter/index.js': { default: mockReporter },
|
|
66
|
-
'#lib/process/manager.js': { default: mockProcessManager }
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
const error = await t.throwsAsync(() =>
|
|
70
|
-
prince.default(testPath('input.html'), testPath('covers.html'), testPath('output.pdf'), {})
|
|
71
|
-
)
|
|
72
|
-
|
|
73
|
-
t.is(error.code, 'PDF_FAILED')
|
|
74
|
-
t.true(error.message.includes('Prince'))
|
|
75
|
-
t.true(error.message.includes('page map generation'))
|
|
76
|
-
t.true(error.message.includes('invalid HTML at line 42'))
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
test('throws PdfGenerationError when PDF printing fails', async (t) => {
|
|
80
|
-
const { sandbox, mockReporter, mockProcessManager, mockFs } = t.context
|
|
81
|
-
|
|
82
|
-
// First call (page map) succeeds, second call (print) fails
|
|
83
|
-
const execaStub = sandbox.stub()
|
|
84
|
-
execaStub.onCall(0).resolves({ stdout: '{}' }) // page map succeeds
|
|
85
|
-
const printError = new Error('Prince print failed')
|
|
86
|
-
printError.stderr = 'error: out of memory'
|
|
87
|
-
execaStub.onCall(1).rejects(printError)
|
|
88
|
-
|
|
89
|
-
const prince = await esmock('./prince.js', {
|
|
90
|
-
execa: { execa: execaStub },
|
|
91
|
-
'fs-extra': mockFs,
|
|
92
|
-
'#lib/reporter/index.js': { default: mockReporter },
|
|
93
|
-
'#lib/process/manager.js': { default: mockProcessManager }
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
const error = await t.throwsAsync(() =>
|
|
97
|
-
prince.default(testPath('input.html'), testPath('covers.html'), testPath('output.pdf'), {})
|
|
98
|
-
)
|
|
99
|
-
|
|
100
|
-
t.is(error.code, 'PDF_FAILED')
|
|
101
|
-
t.true(error.message.includes('Prince'))
|
|
102
|
-
t.true(error.message.includes('PDF printing'))
|
|
103
|
-
t.true(error.message.includes('out of memory'))
|
|
104
|
-
})
|
|
105
|
-
|
|
106
|
-
test('throws PdfGenerationError when cover page map generation fails', async (t) => {
|
|
107
|
-
const { sandbox, mockReporter, mockProcessManager, mockFs } = t.context
|
|
108
|
-
|
|
109
|
-
// First call (page map) succeeds, second call (covers) fails
|
|
110
|
-
const execaStub = sandbox.stub()
|
|
111
|
-
execaStub.onCall(0).resolves({ stdout: '{"page-1": {"startPage": 0}}' })
|
|
112
|
-
const coversError = new Error('Prince covers failed')
|
|
113
|
-
coversError.stderr = 'error: covers file corrupt'
|
|
114
|
-
execaStub.onCall(1).rejects(coversError)
|
|
115
|
-
|
|
116
|
-
const prince = await esmock('./prince.js', {
|
|
117
|
-
execa: { execa: execaStub },
|
|
118
|
-
'fs-extra': mockFs,
|
|
119
|
-
'#lib/reporter/index.js': { default: mockReporter },
|
|
120
|
-
'#lib/process/manager.js': { default: mockProcessManager }
|
|
121
|
-
})
|
|
122
|
-
|
|
123
|
-
// Enable cover page generation
|
|
124
|
-
const options = {
|
|
125
|
-
pdfConfig: { pagePDF: { coverPage: true } }
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
const error = await t.throwsAsync(() =>
|
|
129
|
-
prince.default(testPath('input.html'), testPath('covers.html'), testPath('output.pdf'), options)
|
|
130
|
-
)
|
|
131
|
-
|
|
132
|
-
t.is(error.code, 'PDF_FAILED')
|
|
133
|
-
t.true(error.message.includes('Prince'))
|
|
134
|
-
t.true(error.message.includes('cover page map generation'))
|
|
135
|
-
t.true(error.message.includes('covers file corrupt'))
|
|
136
|
-
})
|
|
137
|
-
|
|
138
|
-
test('warns and returns when page map generation is cancelled', async (t) => {
|
|
139
|
-
const { sandbox, mockReporter, mockProcessManager, mockFs } = t.context
|
|
140
|
-
|
|
141
|
-
const cancelError = new Error('Cancelled')
|
|
142
|
-
cancelError.isCanceled = true
|
|
143
|
-
|
|
144
|
-
const prince = await esmock('./prince.js', {
|
|
145
|
-
execa: { execa: sandbox.stub().rejects(cancelError) },
|
|
146
|
-
'fs-extra': mockFs,
|
|
147
|
-
'#lib/reporter/index.js': { default: mockReporter },
|
|
148
|
-
'#lib/process/manager.js': { default: mockProcessManager }
|
|
149
|
-
})
|
|
150
|
-
|
|
151
|
-
const result = await prince.default(testPath('input.html'), testPath('covers.html'), testPath('output.pdf'), {})
|
|
152
|
-
|
|
153
|
-
t.is(result, undefined)
|
|
154
|
-
t.true(mockReporter.warn.calledWith('PDF generation cancelled'))
|
|
155
|
-
})
|
|
156
|
-
|
|
157
|
-
test('warns and returns when PDF printing is cancelled', async (t) => {
|
|
158
|
-
const { sandbox, mockReporter, mockProcessManager, mockFs } = t.context
|
|
159
|
-
|
|
160
|
-
const execaStub = sandbox.stub()
|
|
161
|
-
execaStub.onCall(0).resolves({ stdout: '{}' }) // page map succeeds
|
|
162
|
-
const cancelError = new Error('Cancelled')
|
|
163
|
-
cancelError.isCanceled = true
|
|
164
|
-
execaStub.onCall(1).rejects(cancelError)
|
|
165
|
-
|
|
166
|
-
const prince = await esmock('./prince.js', {
|
|
167
|
-
execa: { execa: execaStub },
|
|
168
|
-
'fs-extra': mockFs,
|
|
169
|
-
'#lib/reporter/index.js': { default: mockReporter },
|
|
170
|
-
'#lib/process/manager.js': { default: mockProcessManager }
|
|
171
|
-
})
|
|
172
|
-
|
|
173
|
-
const result = await prince.default(testPath('input.html'), testPath('covers.html'), testPath('output.pdf'), {})
|
|
174
|
-
|
|
175
|
-
t.is(result, undefined)
|
|
176
|
-
t.true(mockReporter.warn.calledWith('PDF generation cancelled'))
|
|
177
|
-
})
|
|
178
|
-
|
|
179
|
-
test('throws PdfGenerationError when output directory creation fails', async (t) => {
|
|
180
|
-
const { sandbox, mockReporter, mockProcessManager } = t.context
|
|
181
|
-
|
|
182
|
-
const mockFs = {
|
|
183
|
-
existsSync: sandbox.stub().returns(false),
|
|
184
|
-
mkdirsSync: sandbox.stub().throws(new Error('EACCES: permission denied'))
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
const prince = await esmock('./prince.js', {
|
|
188
|
-
execa: { execa: sandbox.stub() },
|
|
189
|
-
'fs-extra': mockFs,
|
|
190
|
-
'#lib/reporter/index.js': { default: mockReporter },
|
|
191
|
-
'#lib/process/manager.js': { default: mockProcessManager }
|
|
192
|
-
})
|
|
193
|
-
|
|
194
|
-
const error = await t.throwsAsync(() =>
|
|
195
|
-
prince.default(testPath('input.html'), testPath('covers.html'), testPath('restricted', 'output.pdf'), {})
|
|
196
|
-
)
|
|
197
|
-
|
|
198
|
-
t.is(error.code, 'PDF_FAILED')
|
|
199
|
-
t.true(error.message.includes('Prince'))
|
|
200
|
-
t.true(error.message.includes('output directory creation'))
|
|
201
|
-
t.true(error.message.includes('permission denied'))
|
|
202
|
-
})
|
package/src/lib/pdf/schema.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* PDF engine schema definition
|
|
3
|
-
*
|
|
4
|
-
* This module has NO imports to avoid circular dependencies.
|
|
5
|
-
* It serves as the single source of truth for PDF engine options.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Supported PDF engines
|
|
10
|
-
* @type {string[]}
|
|
11
|
-
*/
|
|
12
|
-
export const ENGINES = ['pagedjs', 'prince']
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Schema definition for pdfEngine config property
|
|
16
|
-
*/
|
|
17
|
-
export const schema = {
|
|
18
|
-
type: 'string',
|
|
19
|
-
enum: ENGINES,
|
|
20
|
-
description: 'Default PDF engine to use (pagedjs, prince)'
|
|
21
|
-
}
|