@thegetty/quire-cli 1.0.0-rc.45 → 1.0.0-rc.47
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 +10 -27
- 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/man/quire.1 +0 -341
- package/man/quire.1.md +0 -232
- 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,445 +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
|
-
* PDF Split Module Unit Tests
|
|
8
|
-
*
|
|
9
|
-
* Tests the PDF splitting utility that extracts sections from a PDF
|
|
10
|
-
* based on a page map. Uses mocked pdf-lib to avoid needing real PDF fixtures.
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
test.beforeEach((t) => {
|
|
14
|
-
t.context.sandbox = sinon.createSandbox()
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
test.afterEach.always((t) => {
|
|
18
|
-
t.context.sandbox.restore()
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Create a mock PDFDocument with configurable page count
|
|
23
|
-
*/
|
|
24
|
-
function createMockPdfDoc(sandbox, pageCount = 10) {
|
|
25
|
-
const mockDoc = {
|
|
26
|
-
getPageCount: sandbox.stub().returns(pageCount),
|
|
27
|
-
copy: sandbox.stub(),
|
|
28
|
-
copyPages: sandbox.stub(),
|
|
29
|
-
removePage: sandbox.stub(),
|
|
30
|
-
insertPage: sandbox.stub(),
|
|
31
|
-
save: sandbox.stub().resolves(new Uint8Array([1, 2, 3]))
|
|
32
|
-
}
|
|
33
|
-
// copy() returns a new mock that shares the same page count
|
|
34
|
-
mockDoc.copy.resolves({
|
|
35
|
-
getPageCount: () => pageCount,
|
|
36
|
-
removePage: mockDoc.removePage,
|
|
37
|
-
copyPages: mockDoc.copyPages,
|
|
38
|
-
insertPage: mockDoc.insertPage,
|
|
39
|
-
save: mockDoc.save
|
|
40
|
-
})
|
|
41
|
-
mockDoc.copyPages.resolves([{ /* mock cover page */ }])
|
|
42
|
-
return mockDoc
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
46
|
-
// Basic behavior tests
|
|
47
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
48
|
-
|
|
49
|
-
test('splitPdf returns empty object when pdfConfig is null', async (t) => {
|
|
50
|
-
const { sandbox } = t.context
|
|
51
|
-
|
|
52
|
-
const { splitPdf } = await esmock('./split.js', {
|
|
53
|
-
'pdf-lib': { PDFDocument: { load: sandbox.stub() } },
|
|
54
|
-
'#lib/11ty/index.js': { paths: { getOutputDir: () => '_site' } }
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
const result = await splitPdf(Buffer.from([]), undefined, {}, null)
|
|
58
|
-
|
|
59
|
-
t.deepEqual(result, {})
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
test('splitPdf returns empty object when pdfConfig is undefined', async (t) => {
|
|
63
|
-
const { sandbox } = t.context
|
|
64
|
-
|
|
65
|
-
const { splitPdf } = await esmock('./split.js', {
|
|
66
|
-
'pdf-lib': { PDFDocument: { load: sandbox.stub() } },
|
|
67
|
-
'#lib/11ty/index.js': { paths: { getOutputDir: () => '_site' } }
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
const result = await splitPdf(Buffer.from([]), undefined, {}, undefined)
|
|
71
|
-
|
|
72
|
-
t.deepEqual(result, {})
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
test('splitPdf returns empty object when pageMap is empty', async (t) => {
|
|
76
|
-
const { sandbox } = t.context
|
|
77
|
-
const mockDoc = createMockPdfDoc(sandbox, 10)
|
|
78
|
-
|
|
79
|
-
const { splitPdf } = await esmock('./split.js', {
|
|
80
|
-
'pdf-lib': { PDFDocument: { load: sandbox.stub().resolves(mockDoc) } },
|
|
81
|
-
'#lib/11ty/index.js': { paths: { getOutputDir: () => '_site' } }
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
const pdfConfig = { filename: 'book', outputDir: '_downloads' }
|
|
85
|
-
const result = await splitPdf(Buffer.from([]), undefined, {}, pdfConfig)
|
|
86
|
-
|
|
87
|
-
t.deepEqual(result, {})
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
91
|
-
// Section extraction tests
|
|
92
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
93
|
-
|
|
94
|
-
test('splitPdf extracts single section from pageMap', async (t) => {
|
|
95
|
-
const { sandbox } = t.context
|
|
96
|
-
const mockDoc = createMockPdfDoc(sandbox, 10)
|
|
97
|
-
|
|
98
|
-
const { splitPdf } = await esmock('./split.js', {
|
|
99
|
-
'pdf-lib': { PDFDocument: { load: sandbox.stub().resolves(mockDoc) } },
|
|
100
|
-
'#lib/11ty/index.js': { paths: { getOutputDir: () => '_site' } }
|
|
101
|
-
})
|
|
102
|
-
|
|
103
|
-
const pageMap = {
|
|
104
|
-
'page-intro': { startPage: 0, endPage: 2 }
|
|
105
|
-
}
|
|
106
|
-
const pdfConfig = { filename: 'publication', outputDir: '_downloads' }
|
|
107
|
-
|
|
108
|
-
const result = await splitPdf(Buffer.from([]), undefined, pageMap, pdfConfig)
|
|
109
|
-
|
|
110
|
-
t.is(Object.keys(result).length, 1)
|
|
111
|
-
const filePath = Object.keys(result)[0]
|
|
112
|
-
t.true(filePath.includes('publication-intro.pdf'))
|
|
113
|
-
t.true(filePath.includes('_downloads'))
|
|
114
|
-
})
|
|
115
|
-
|
|
116
|
-
test('splitPdf extracts multiple sections from pageMap', async (t) => {
|
|
117
|
-
const { sandbox } = t.context
|
|
118
|
-
const mockDoc = createMockPdfDoc(sandbox, 20)
|
|
119
|
-
|
|
120
|
-
const { splitPdf } = await esmock('./split.js', {
|
|
121
|
-
'pdf-lib': { PDFDocument: { load: sandbox.stub().resolves(mockDoc) } },
|
|
122
|
-
'#lib/11ty/index.js': { paths: { getOutputDir: () => '_site' } }
|
|
123
|
-
})
|
|
124
|
-
|
|
125
|
-
const pageMap = {
|
|
126
|
-
'page-intro': { startPage: 0, endPage: 2 },
|
|
127
|
-
'page-chapter1': { startPage: 3, endPage: 8 },
|
|
128
|
-
'page-chapter2': { startPage: 9, endPage: 15 }
|
|
129
|
-
}
|
|
130
|
-
const pdfConfig = { filename: 'book', outputDir: 'pdf' }
|
|
131
|
-
|
|
132
|
-
const result = await splitPdf(Buffer.from([]), undefined, pageMap, pdfConfig)
|
|
133
|
-
|
|
134
|
-
t.is(Object.keys(result).length, 3)
|
|
135
|
-
const filePaths = Object.keys(result)
|
|
136
|
-
t.true(filePaths.some(p => p.includes('book-intro.pdf')))
|
|
137
|
-
t.true(filePaths.some(p => p.includes('book-chapter1.pdf')))
|
|
138
|
-
t.true(filePaths.some(p => p.includes('book-chapter2.pdf')))
|
|
139
|
-
})
|
|
140
|
-
|
|
141
|
-
test('splitPdf strips "page-" prefix from section IDs', async (t) => {
|
|
142
|
-
const { sandbox } = t.context
|
|
143
|
-
const mockDoc = createMockPdfDoc(sandbox, 10)
|
|
144
|
-
|
|
145
|
-
const { splitPdf } = await esmock('./split.js', {
|
|
146
|
-
'pdf-lib': { PDFDocument: { load: sandbox.stub().resolves(mockDoc) } },
|
|
147
|
-
'#lib/11ty/index.js': { paths: { getOutputDir: () => '_site' } }
|
|
148
|
-
})
|
|
149
|
-
|
|
150
|
-
const pageMap = {
|
|
151
|
-
'page-my-section': { startPage: 0, endPage: 5 }
|
|
152
|
-
}
|
|
153
|
-
const pdfConfig = { filename: 'doc', outputDir: 'out' }
|
|
154
|
-
|
|
155
|
-
const result = await splitPdf(Buffer.from([]), undefined, pageMap, pdfConfig)
|
|
156
|
-
|
|
157
|
-
const filePath = Object.keys(result)[0]
|
|
158
|
-
t.true(filePath.includes('doc-my-section.pdf'))
|
|
159
|
-
t.false(filePath.includes('page-'))
|
|
160
|
-
})
|
|
161
|
-
|
|
162
|
-
test('splitPdf removes pages outside section range', async (t) => {
|
|
163
|
-
const { sandbox } = t.context
|
|
164
|
-
const mockDoc = createMockPdfDoc(sandbox, 10)
|
|
165
|
-
const removePage = sandbox.stub()
|
|
166
|
-
mockDoc.copy.resolves({
|
|
167
|
-
getPageCount: () => 10,
|
|
168
|
-
removePage,
|
|
169
|
-
copyPages: mockDoc.copyPages,
|
|
170
|
-
insertPage: mockDoc.insertPage,
|
|
171
|
-
save: mockDoc.save
|
|
172
|
-
})
|
|
173
|
-
|
|
174
|
-
const { splitPdf } = await esmock('./split.js', {
|
|
175
|
-
'pdf-lib': { PDFDocument: { load: sandbox.stub().resolves(mockDoc) } },
|
|
176
|
-
'#lib/11ty/index.js': { paths: { getOutputDir: () => '_site' } }
|
|
177
|
-
})
|
|
178
|
-
|
|
179
|
-
const pageMap = {
|
|
180
|
-
'page-middle': { startPage: 3, endPage: 6 }
|
|
181
|
-
}
|
|
182
|
-
const pdfConfig = { filename: 'test', outputDir: 'out' }
|
|
183
|
-
|
|
184
|
-
await splitPdf(Buffer.from([]), undefined, pageMap, pdfConfig)
|
|
185
|
-
|
|
186
|
-
// Should remove pages 9, 8, 7 (after endPage=6) and pages 2, 1, 0 (before startPage=3)
|
|
187
|
-
t.true(removePage.called)
|
|
188
|
-
})
|
|
189
|
-
|
|
190
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
191
|
-
// Cover page tests
|
|
192
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
193
|
-
|
|
194
|
-
test('splitPdf inserts cover page when coverPage is specified', async (t) => {
|
|
195
|
-
const { sandbox } = t.context
|
|
196
|
-
const mockDoc = createMockPdfDoc(sandbox, 10)
|
|
197
|
-
const mockCoversDoc = createMockPdfDoc(sandbox, 5)
|
|
198
|
-
const insertPage = sandbox.stub()
|
|
199
|
-
const copyPages = sandbox.stub().resolves([{ id: 'cover-page' }])
|
|
200
|
-
|
|
201
|
-
mockDoc.copy.resolves({
|
|
202
|
-
getPageCount: () => 10,
|
|
203
|
-
removePage: sandbox.stub(),
|
|
204
|
-
copyPages,
|
|
205
|
-
insertPage,
|
|
206
|
-
save: mockDoc.save
|
|
207
|
-
})
|
|
208
|
-
|
|
209
|
-
const loadStub = sandbox.stub()
|
|
210
|
-
loadStub.onCall(0).resolves(mockDoc)
|
|
211
|
-
loadStub.onCall(1).resolves(mockCoversDoc)
|
|
212
|
-
|
|
213
|
-
const { splitPdf } = await esmock('./split.js', {
|
|
214
|
-
'pdf-lib': { PDFDocument: { load: loadStub } },
|
|
215
|
-
'#lib/11ty/index.js': { paths: { getOutputDir: () => '_site' } }
|
|
216
|
-
})
|
|
217
|
-
|
|
218
|
-
const pageMap = {
|
|
219
|
-
'page-chapter1': { startPage: 0, endPage: 5, coverPage: 2 }
|
|
220
|
-
}
|
|
221
|
-
const pdfConfig = { filename: 'book', outputDir: 'out' }
|
|
222
|
-
|
|
223
|
-
await splitPdf(Buffer.from([]), Buffer.from([]), pageMap, pdfConfig)
|
|
224
|
-
|
|
225
|
-
// Should copy cover page from covers doc
|
|
226
|
-
t.true(copyPages.calledWith(mockCoversDoc, [2]))
|
|
227
|
-
// Should insert at position 0
|
|
228
|
-
t.true(insertPage.calledWith(0, sinon.match.object))
|
|
229
|
-
})
|
|
230
|
-
|
|
231
|
-
test('splitPdf does not insert cover page when coverPage is undefined', async (t) => {
|
|
232
|
-
const { sandbox } = t.context
|
|
233
|
-
const mockDoc = createMockPdfDoc(sandbox, 10)
|
|
234
|
-
const mockCoversDoc = createMockPdfDoc(sandbox, 5)
|
|
235
|
-
const insertPage = sandbox.stub()
|
|
236
|
-
|
|
237
|
-
mockDoc.copy.resolves({
|
|
238
|
-
getPageCount: () => 10,
|
|
239
|
-
removePage: sandbox.stub(),
|
|
240
|
-
copyPages: sandbox.stub().resolves([{}]),
|
|
241
|
-
insertPage,
|
|
242
|
-
save: mockDoc.save
|
|
243
|
-
})
|
|
244
|
-
|
|
245
|
-
const loadStub = sandbox.stub()
|
|
246
|
-
loadStub.onCall(0).resolves(mockDoc)
|
|
247
|
-
loadStub.onCall(1).resolves(mockCoversDoc)
|
|
248
|
-
|
|
249
|
-
const { splitPdf } = await esmock('./split.js', {
|
|
250
|
-
'pdf-lib': { PDFDocument: { load: loadStub } },
|
|
251
|
-
'#lib/11ty/index.js': { paths: { getOutputDir: () => '_site' } }
|
|
252
|
-
})
|
|
253
|
-
|
|
254
|
-
const pageMap = {
|
|
255
|
-
'page-chapter1': { startPage: 0, endPage: 5 } // No coverPage
|
|
256
|
-
}
|
|
257
|
-
const pdfConfig = { filename: 'book', outputDir: 'out' }
|
|
258
|
-
|
|
259
|
-
await splitPdf(Buffer.from([]), Buffer.from([]), pageMap, pdfConfig)
|
|
260
|
-
|
|
261
|
-
t.false(insertPage.called)
|
|
262
|
-
})
|
|
263
|
-
|
|
264
|
-
test('splitPdf does not insert cover page when coverPage is negative', async (t) => {
|
|
265
|
-
const { sandbox } = t.context
|
|
266
|
-
const mockDoc = createMockPdfDoc(sandbox, 10)
|
|
267
|
-
const insertPage = sandbox.stub()
|
|
268
|
-
|
|
269
|
-
mockDoc.copy.resolves({
|
|
270
|
-
getPageCount: () => 10,
|
|
271
|
-
removePage: sandbox.stub(),
|
|
272
|
-
copyPages: sandbox.stub().resolves([{}]),
|
|
273
|
-
insertPage,
|
|
274
|
-
save: mockDoc.save
|
|
275
|
-
})
|
|
276
|
-
|
|
277
|
-
const { splitPdf } = await esmock('./split.js', {
|
|
278
|
-
'pdf-lib': { PDFDocument: { load: sandbox.stub().resolves(mockDoc) } },
|
|
279
|
-
'#lib/11ty/index.js': { paths: { getOutputDir: () => '_site' } }
|
|
280
|
-
})
|
|
281
|
-
|
|
282
|
-
const pageMap = {
|
|
283
|
-
'page-chapter1': { startPage: 0, endPage: 5, coverPage: -1 }
|
|
284
|
-
}
|
|
285
|
-
const pdfConfig = { filename: 'book', outputDir: 'out' }
|
|
286
|
-
|
|
287
|
-
await splitPdf(Buffer.from([]), undefined, pageMap, pdfConfig)
|
|
288
|
-
|
|
289
|
-
t.false(insertPage.called)
|
|
290
|
-
})
|
|
291
|
-
|
|
292
|
-
test('splitPdf does not insert cover page when coversFile is undefined', async (t) => {
|
|
293
|
-
const { sandbox } = t.context
|
|
294
|
-
const mockDoc = createMockPdfDoc(sandbox, 10)
|
|
295
|
-
const insertPage = sandbox.stub()
|
|
296
|
-
|
|
297
|
-
mockDoc.copy.resolves({
|
|
298
|
-
getPageCount: () => 10,
|
|
299
|
-
removePage: sandbox.stub(),
|
|
300
|
-
copyPages: sandbox.stub().resolves([{}]),
|
|
301
|
-
insertPage,
|
|
302
|
-
save: mockDoc.save
|
|
303
|
-
})
|
|
304
|
-
|
|
305
|
-
const { splitPdf } = await esmock('./split.js', {
|
|
306
|
-
'pdf-lib': { PDFDocument: { load: sandbox.stub().resolves(mockDoc) } },
|
|
307
|
-
'#lib/11ty/index.js': { paths: { getOutputDir: () => '_site' } }
|
|
308
|
-
})
|
|
309
|
-
|
|
310
|
-
const pageMap = {
|
|
311
|
-
'page-chapter1': { startPage: 0, endPage: 5, coverPage: 2 }
|
|
312
|
-
}
|
|
313
|
-
const pdfConfig = { filename: 'book', outputDir: 'out' }
|
|
314
|
-
|
|
315
|
-
// coversFile is undefined
|
|
316
|
-
await splitPdf(Buffer.from([]), undefined, pageMap, pdfConfig)
|
|
317
|
-
|
|
318
|
-
t.false(insertPage.called)
|
|
319
|
-
})
|
|
320
|
-
|
|
321
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
322
|
-
// Error handling tests
|
|
323
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
324
|
-
|
|
325
|
-
test('splitPdf throws PdfGenerationError when main PDF fails to load', async (t) => {
|
|
326
|
-
const { sandbox } = t.context
|
|
327
|
-
|
|
328
|
-
const { splitPdf } = await esmock('./split.js', {
|
|
329
|
-
'pdf-lib': {
|
|
330
|
-
PDFDocument: {
|
|
331
|
-
load: sandbox.stub().rejects(new Error('Invalid PDF structure'))
|
|
332
|
-
}
|
|
333
|
-
},
|
|
334
|
-
'#lib/11ty/index.js': { paths: { getOutputDir: () => '_site' } }
|
|
335
|
-
})
|
|
336
|
-
|
|
337
|
-
const pdfConfig = { filename: 'book', outputDir: 'out' }
|
|
338
|
-
|
|
339
|
-
const error = await t.throwsAsync(() =>
|
|
340
|
-
splitPdf(Buffer.from([]), undefined, { 'page-1': { startPage: 0, endPage: 1 } }, pdfConfig)
|
|
341
|
-
)
|
|
342
|
-
|
|
343
|
-
t.is(error.code, 'PDF_FAILED')
|
|
344
|
-
t.true(error.message.includes('load main PDF'))
|
|
345
|
-
t.true(error.message.includes('Invalid PDF structure'))
|
|
346
|
-
})
|
|
347
|
-
|
|
348
|
-
test('splitPdf throws PdfGenerationError when covers PDF fails to load', async (t) => {
|
|
349
|
-
const { sandbox } = t.context
|
|
350
|
-
const mockDoc = createMockPdfDoc(sandbox, 10)
|
|
351
|
-
|
|
352
|
-
const loadStub = sandbox.stub()
|
|
353
|
-
loadStub.onCall(0).resolves(mockDoc)
|
|
354
|
-
loadStub.onCall(1).rejects(new Error('Corrupted covers file'))
|
|
355
|
-
|
|
356
|
-
const { splitPdf } = await esmock('./split.js', {
|
|
357
|
-
'pdf-lib': { PDFDocument: { load: loadStub } },
|
|
358
|
-
'#lib/11ty/index.js': { paths: { getOutputDir: () => '_site' } }
|
|
359
|
-
})
|
|
360
|
-
|
|
361
|
-
const pdfConfig = { filename: 'book', outputDir: 'out' }
|
|
362
|
-
|
|
363
|
-
const error = await t.throwsAsync(() =>
|
|
364
|
-
splitPdf(Buffer.from([]), Buffer.from([]), { 'page-1': { startPage: 0, endPage: 1 } }, pdfConfig)
|
|
365
|
-
)
|
|
366
|
-
|
|
367
|
-
t.is(error.code, 'PDF_FAILED')
|
|
368
|
-
t.true(error.message.includes('load covers PDF'))
|
|
369
|
-
})
|
|
370
|
-
|
|
371
|
-
test('splitPdf throws PdfGenerationError when section extraction fails', async (t) => {
|
|
372
|
-
const { sandbox } = t.context
|
|
373
|
-
const mockDoc = createMockPdfDoc(sandbox, 10)
|
|
374
|
-
|
|
375
|
-
mockDoc.copy.rejects(new Error('Copy operation failed'))
|
|
376
|
-
|
|
377
|
-
const { splitPdf } = await esmock('./split.js', {
|
|
378
|
-
'pdf-lib': { PDFDocument: { load: sandbox.stub().resolves(mockDoc) } },
|
|
379
|
-
'#lib/11ty/index.js': { paths: { getOutputDir: () => '_site' } }
|
|
380
|
-
})
|
|
381
|
-
|
|
382
|
-
const pageMap = {
|
|
383
|
-
'page-chapter1': { startPage: 0, endPage: 5 }
|
|
384
|
-
}
|
|
385
|
-
const pdfConfig = { filename: 'book', outputDir: 'out' }
|
|
386
|
-
|
|
387
|
-
const error = await t.throwsAsync(() =>
|
|
388
|
-
splitPdf(Buffer.from([]), undefined, pageMap, pdfConfig)
|
|
389
|
-
)
|
|
390
|
-
|
|
391
|
-
t.is(error.code, 'PDF_FAILED')
|
|
392
|
-
t.true(error.message.includes("extract section 'page-chapter1'"))
|
|
393
|
-
})
|
|
394
|
-
|
|
395
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
396
|
-
// Output path tests
|
|
397
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
398
|
-
|
|
399
|
-
test('splitPdf uses outputDir from paths.getOutputDir()', async (t) => {
|
|
400
|
-
const { sandbox } = t.context
|
|
401
|
-
const mockDoc = createMockPdfDoc(sandbox, 10)
|
|
402
|
-
|
|
403
|
-
// Nota bene: use path.join() for cross-platform compatibility in mock return value
|
|
404
|
-
const customOutput = path.join('custom', 'output')
|
|
405
|
-
|
|
406
|
-
const { splitPdf } = await esmock('./split.js', {
|
|
407
|
-
'pdf-lib': { PDFDocument: { load: sandbox.stub().resolves(mockDoc) } },
|
|
408
|
-
'#lib/11ty/index.js': { paths: { getOutputDir: () => customOutput } }
|
|
409
|
-
})
|
|
410
|
-
|
|
411
|
-
const pageMap = {
|
|
412
|
-
'page-intro': { startPage: 0, endPage: 2 }
|
|
413
|
-
}
|
|
414
|
-
const pdfConfig = { filename: 'doc', outputDir: 'pdfs' }
|
|
415
|
-
|
|
416
|
-
const result = await splitPdf(Buffer.from([]), undefined, pageMap, pdfConfig)
|
|
417
|
-
|
|
418
|
-
const filePath = Object.keys(result)[0]
|
|
419
|
-
// Nota bene: use includes() for cross-platform compatibility (Windows vs Unix paths)
|
|
420
|
-
t.true(filePath.includes(customOutput), 'output path should include custom output directory')
|
|
421
|
-
})
|
|
422
|
-
|
|
423
|
-
test('splitPdf combines outputDir with pdfConfig.outputDir', async (t) => {
|
|
424
|
-
const { sandbox } = t.context
|
|
425
|
-
const mockDoc = createMockPdfDoc(sandbox, 10)
|
|
426
|
-
|
|
427
|
-
const { splitPdf } = await esmock('./split.js', {
|
|
428
|
-
'pdf-lib': { PDFDocument: { load: sandbox.stub().resolves(mockDoc) } },
|
|
429
|
-
'#lib/11ty/index.js': { paths: { getOutputDir: () => '_site' } }
|
|
430
|
-
})
|
|
431
|
-
|
|
432
|
-
const pageMap = {
|
|
433
|
-
'page-intro': { startPage: 0, endPage: 2 }
|
|
434
|
-
}
|
|
435
|
-
// Nota bene: use path.join() for cross-platform compatibility in assertions
|
|
436
|
-
const pdfOutputDir = path.join('_downloads', 'pdf')
|
|
437
|
-
const pdfConfig = { filename: 'mybook', outputDir: pdfOutputDir }
|
|
438
|
-
|
|
439
|
-
const result = await splitPdf(Buffer.from([]), undefined, pageMap, pdfConfig)
|
|
440
|
-
|
|
441
|
-
const filePath = Object.keys(result)[0]
|
|
442
|
-
t.true(filePath.includes('_site'))
|
|
443
|
-
t.true(filePath.includes(pdfOutputDir))
|
|
444
|
-
t.true(filePath.includes('mybook-intro.pdf'))
|
|
445
|
-
})
|
package/src/lib/platform.js
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Platform detection utilities
|
|
3
|
-
*
|
|
4
|
-
* Provides OS detection and platform-specific helpers for the CLI.
|
|
5
|
-
*
|
|
6
|
-
* @module lib/platform
|
|
7
|
-
*/
|
|
8
|
-
import os from 'node:os'
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Platform identifiers
|
|
12
|
-
* @readonly
|
|
13
|
-
* @enum {string}
|
|
14
|
-
*/
|
|
15
|
-
export const Platform = {
|
|
16
|
-
MACOS: 'macos',
|
|
17
|
-
WINDOWS: 'windows',
|
|
18
|
-
LINUX: 'linux',
|
|
19
|
-
UNKNOWN: 'unknown',
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Get the current platform identifier
|
|
24
|
-
* @returns {string} Platform identifier (macos, windows, linux, or unknown)
|
|
25
|
-
*/
|
|
26
|
-
export function getPlatform() {
|
|
27
|
-
switch (process.platform) {
|
|
28
|
-
case 'darwin':
|
|
29
|
-
return Platform.MACOS
|
|
30
|
-
case 'win32':
|
|
31
|
-
return Platform.WINDOWS
|
|
32
|
-
case 'linux':
|
|
33
|
-
return Platform.LINUX
|
|
34
|
-
default:
|
|
35
|
-
return Platform.UNKNOWN
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Get a human-readable platform name
|
|
41
|
-
* @returns {string} Human-readable OS name (e.g., "macOS 14.0", "Windows 11", "Linux")
|
|
42
|
-
*/
|
|
43
|
-
export function getPlatformName() {
|
|
44
|
-
const platform = getPlatform()
|
|
45
|
-
const release = os.release()
|
|
46
|
-
|
|
47
|
-
switch (platform) {
|
|
48
|
-
case Platform.MACOS: {
|
|
49
|
-
// Darwin kernel version to macOS version mapping (approximate)
|
|
50
|
-
const majorVersion = parseInt(release.split('.')[0], 10)
|
|
51
|
-
// Darwin 23.x = macOS 14 (Sonoma), 22.x = macOS 13, etc.
|
|
52
|
-
const macOSVersion = majorVersion >= 20 ? majorVersion - 9 : majorVersion - 4
|
|
53
|
-
return `macOS ${macOSVersion >= 14 ? macOSVersion : release}`
|
|
54
|
-
}
|
|
55
|
-
case Platform.WINDOWS:
|
|
56
|
-
return `Windows (${release})`
|
|
57
|
-
case Platform.LINUX:
|
|
58
|
-
return `Linux (${release})`
|
|
59
|
-
default:
|
|
60
|
-
return `${process.platform} (${release})`
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Check if running on macOS
|
|
66
|
-
* @returns {boolean}
|
|
67
|
-
*/
|
|
68
|
-
export function isMacOS() {
|
|
69
|
-
return process.platform === 'darwin'
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Check if running on Windows
|
|
74
|
-
* @returns {boolean}
|
|
75
|
-
*/
|
|
76
|
-
export function isWindows() {
|
|
77
|
-
return process.platform === 'win32'
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Check if running on Linux
|
|
82
|
-
* @returns {boolean}
|
|
83
|
-
*/
|
|
84
|
-
export function isLinux() {
|
|
85
|
-
return process.platform === 'linux'
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export default {
|
|
89
|
-
Platform,
|
|
90
|
-
getPlatform,
|
|
91
|
-
getPlatformName,
|
|
92
|
-
isMacOS,
|
|
93
|
-
isWindows,
|
|
94
|
-
isLinux,
|
|
95
|
-
}
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ProcessManager - Centralized subprocess lifecycle management
|
|
3
|
-
*
|
|
4
|
-
* Provides graceful shutdown for CLI subprocesses (eleventy, pagedjs, prince).
|
|
5
|
-
*
|
|
6
|
-
* @example Register a cleanup handler
|
|
7
|
-
* processManager.onShutdown('eleventy', () => eleventy.close())
|
|
8
|
-
*
|
|
9
|
-
* @example Use shared abort signal for execa
|
|
10
|
-
* execa('prince', args, { cancelSignal: processManager.signal })
|
|
11
|
-
*
|
|
12
|
-
* @module lib/process/manager
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import { logger } from '#lib/logger/index.js'
|
|
16
|
-
|
|
17
|
-
const LOG_PREFIX = '[CLI:process]'
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Timeout for individual cleanup handlers (ms)
|
|
21
|
-
*/
|
|
22
|
-
const CLEANUP_TIMEOUT = 5000
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Cleanup handlers registry
|
|
26
|
-
* @type {Map<string, Function>}
|
|
27
|
-
*/
|
|
28
|
-
const cleanupHandlers = new Map()
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Shared AbortController for subprocess cancellation
|
|
32
|
-
*/
|
|
33
|
-
const abortController = new AbortController()
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Flag to prevent multiple shutdown calls
|
|
37
|
-
*/
|
|
38
|
-
let isShuttingDown = false
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Wrap a cleanup function with a timeout
|
|
42
|
-
* @param {Function} fn - Cleanup function
|
|
43
|
-
* @param {string} name - Handler name for logging
|
|
44
|
-
* @param {number} timeout - Timeout in milliseconds
|
|
45
|
-
* @returns {Promise<void>}
|
|
46
|
-
*/
|
|
47
|
-
const withTimeout = (fn, name, timeout) => {
|
|
48
|
-
return Promise.race([
|
|
49
|
-
fn(),
|
|
50
|
-
new Promise((_, reject) =>
|
|
51
|
-
setTimeout(() => reject(new Error(`timeout after ${timeout}ms`)), timeout)
|
|
52
|
-
),
|
|
53
|
-
])
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Graceful shutdown - aborts subprocesses and runs cleanup handlers
|
|
58
|
-
* @param {string} signal - SIGINT or SIGTERM
|
|
59
|
-
*/
|
|
60
|
-
const shutdown = async (signal) => {
|
|
61
|
-
if (isShuttingDown) {
|
|
62
|
-
// Second signal = force exit
|
|
63
|
-
logger.info(`${LOG_PREFIX} force exit`)
|
|
64
|
-
process.exit(1)
|
|
65
|
-
}
|
|
66
|
-
isShuttingDown = true
|
|
67
|
-
|
|
68
|
-
logger.info(`\n${LOG_PREFIX} ${signal} received, shutting down...`)
|
|
69
|
-
|
|
70
|
-
abortController.abort()
|
|
71
|
-
|
|
72
|
-
for (const [name, cleanup] of cleanupHandlers) {
|
|
73
|
-
try {
|
|
74
|
-
logger.debug(`${LOG_PREFIX} cleanup: ${name}`)
|
|
75
|
-
await withTimeout(cleanup, name, CLEANUP_TIMEOUT)
|
|
76
|
-
} catch (error) {
|
|
77
|
-
logger.warn(`${LOG_PREFIX} cleanup error (${name}): ${error.message}`)
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
process.exit(signal === 'SIGINT' ? 130 : 143)
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// Register signal handlers
|
|
85
|
-
process.on('SIGINT', () => shutdown('SIGINT'))
|
|
86
|
-
process.on('SIGTERM', () => shutdown('SIGTERM'))
|
|
87
|
-
|
|
88
|
-
export default {
|
|
89
|
-
/**
|
|
90
|
-
* Shared abort signal for execa subprocesses
|
|
91
|
-
*/
|
|
92
|
-
signal: abortController.signal,
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Register a cleanup handler
|
|
96
|
-
* @param {string} name - Handler name (for logging)
|
|
97
|
-
* @param {Function} fn - Cleanup function
|
|
98
|
-
*/
|
|
99
|
-
onShutdown(name, fn) {
|
|
100
|
-
cleanupHandlers.set(name, fn)
|
|
101
|
-
},
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Remove a cleanup handler (call when operation completes normally)
|
|
105
|
-
* @param {string} name - Handler name
|
|
106
|
-
*/
|
|
107
|
-
onShutdownComplete(name) {
|
|
108
|
-
cleanupHandlers.delete(name)
|
|
109
|
-
},
|
|
110
|
-
}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import test from 'ava'
|
|
2
|
-
import sinon from 'sinon'
|
|
3
|
-
import esmock from 'esmock'
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* ProcessManager Unit Tests
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
test.beforeEach((t) => {
|
|
10
|
-
t.context.sandbox = sinon.createSandbox()
|
|
11
|
-
t.context.mockLogger = {
|
|
12
|
-
info: t.context.sandbox.stub(),
|
|
13
|
-
debug: t.context.sandbox.stub(),
|
|
14
|
-
error: t.context.sandbox.stub(),
|
|
15
|
-
warn: t.context.sandbox.stub(),
|
|
16
|
-
log: t.context.sandbox.stub(),
|
|
17
|
-
}
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
test.afterEach.always((t) => {
|
|
21
|
-
t.context.sandbox.restore()
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
test('processManager exports signal and handler methods', async (t) => {
|
|
25
|
-
const { mockLogger } = t.context
|
|
26
|
-
const processManager = await esmock('./manager.js', {
|
|
27
|
-
'#lib/logger/index.js': { logger: mockLogger },
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
t.truthy(processManager.default.signal)
|
|
31
|
-
t.is(typeof processManager.default.onShutdown, 'function')
|
|
32
|
-
t.is(typeof processManager.default.onShutdownComplete, 'function')
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
test('processManager.signal is an AbortSignal', async (t) => {
|
|
36
|
-
const { mockLogger } = t.context
|
|
37
|
-
const processManager = await esmock('./manager.js', {
|
|
38
|
-
'#lib/logger/index.js': { logger: mockLogger },
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
t.true(processManager.default.signal instanceof AbortSignal)
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
test('onShutdown/onShutdownComplete register and remove handlers', async (t) => {
|
|
45
|
-
const { sandbox, mockLogger } = t.context
|
|
46
|
-
const processManager = await esmock('./manager.js', {
|
|
47
|
-
'#lib/logger/index.js': { logger: mockLogger },
|
|
48
|
-
})
|
|
49
|
-
const cleanup = sandbox.stub()
|
|
50
|
-
|
|
51
|
-
// Should not throw
|
|
52
|
-
processManager.default.onShutdown('test', cleanup)
|
|
53
|
-
processManager.default.onShutdownComplete('test')
|
|
54
|
-
t.pass()
|
|
55
|
-
})
|