@thegetty/quire-cli 1.0.0-rc.45 → 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 +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,382 +0,0 @@
|
|
|
1
|
-
import test from 'ava'
|
|
2
|
-
import { Volume, createFsFromVolume } from 'memfs'
|
|
3
|
-
import sinon from 'sinon'
|
|
4
|
-
import esmock from 'esmock'
|
|
5
|
-
|
|
6
|
-
test.beforeEach((t) => {
|
|
7
|
-
// Create sinon sandbox for mocking
|
|
8
|
-
t.context.sandbox = sinon.createSandbox()
|
|
9
|
-
|
|
10
|
-
// Create in-memory file system
|
|
11
|
-
t.context.vol = new Volume()
|
|
12
|
-
t.context.fs = createFsFromVolume(t.context.vol)
|
|
13
|
-
|
|
14
|
-
// Setup mock directory structure with build artifacts
|
|
15
|
-
t.context.vol.fromJSON({
|
|
16
|
-
'/project/_site/index.html': '<html>Quire Test </html>',
|
|
17
|
-
'/project/_site/styles.css': 'body { }',
|
|
18
|
-
'/project/content/index.md': '# Content',
|
|
19
|
-
'/project/package.json': JSON.stringify({ name: 'test-project' })
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
t.context.projectRoot = '/project'
|
|
23
|
-
|
|
24
|
-
// Stub console methods to suppress output during tests
|
|
25
|
-
// Create mock logger (no global console stubbing needed!)
|
|
26
|
-
t.context.mockLogger = {
|
|
27
|
-
info: t.context.sandbox.stub(),
|
|
28
|
-
error: t.context.sandbox.stub(),
|
|
29
|
-
debug: t.context.sandbox.stub(),
|
|
30
|
-
log: t.context.sandbox.stub(),
|
|
31
|
-
warn: t.context.sandbox.stub()
|
|
32
|
-
}
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
test.afterEach.always((t) => {
|
|
36
|
-
// Restore all mocks
|
|
37
|
-
t.context.sandbox.restore()
|
|
38
|
-
|
|
39
|
-
// Clear in-memory file system
|
|
40
|
-
t.context.vol.reset()
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
test('clean command should call clean helper with correct parameters', async (t) => {
|
|
44
|
-
const { sandbox, fs, mockLogger } = t.context
|
|
45
|
-
|
|
46
|
-
// Mock clean helper
|
|
47
|
-
const mockClean = sandbox.stub().resolves(['/project/_site'])
|
|
48
|
-
|
|
49
|
-
// Mock testcwd helper
|
|
50
|
-
const mockTestcwd = sandbox.stub()
|
|
51
|
-
|
|
52
|
-
// Use esmock to replace imports
|
|
53
|
-
const CleanCommand = await esmock('./clean.js', {
|
|
54
|
-
'#helpers/clean.js': {
|
|
55
|
-
clean: mockClean
|
|
56
|
-
},
|
|
57
|
-
'#lib/project/index.js': {
|
|
58
|
-
default: {
|
|
59
|
-
getProjectRoot: () => '/project',
|
|
60
|
-
toObject: () => ({ output: '_site' })
|
|
61
|
-
}
|
|
62
|
-
},
|
|
63
|
-
'#helpers/test-cwd.js': {
|
|
64
|
-
default: mockTestcwd
|
|
65
|
-
},
|
|
66
|
-
'#lib/logger/index.js': {
|
|
67
|
-
logger: mockLogger
|
|
68
|
-
},
|
|
69
|
-
'fs-extra': fs
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
const command = new CleanCommand()
|
|
73
|
-
command.name = sandbox.stub().returns('clean')
|
|
74
|
-
command.logger = mockLogger
|
|
75
|
-
command.debug = sandbox.stub()
|
|
76
|
-
|
|
77
|
-
// Run action
|
|
78
|
-
const options = {}
|
|
79
|
-
await command.action(options, command)
|
|
80
|
-
|
|
81
|
-
t.true(mockClean.called, 'clean should be called')
|
|
82
|
-
t.true(mockClean.calledWith('/project', { output: '_site' }, options), 'clean should be called with correct parameters')
|
|
83
|
-
|
|
84
|
-
// Verify user-visible output
|
|
85
|
-
t.true(mockLogger.info.called, 'logger.info should be called with result')
|
|
86
|
-
const output = mockLogger.info.firstCall.args[0]
|
|
87
|
-
t.true(output.includes('Deleted'), 'should report deleted files')
|
|
88
|
-
t.true(output.includes('/project/_site'), 'should list deleted paths')
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
test('clean command should handle dry-run option', async (t) => {
|
|
92
|
-
const { sandbox, fs, mockLogger } = t.context
|
|
93
|
-
|
|
94
|
-
// Mock clean helper to return paths that would be deleted
|
|
95
|
-
const mockClean = sandbox.stub().resolves(['/project/_site/index.html', '/project/_site/styles.css'])
|
|
96
|
-
|
|
97
|
-
// Mock testcwd helper
|
|
98
|
-
const mockTestcwd = sandbox.stub()
|
|
99
|
-
|
|
100
|
-
// Use esmock to replace imports
|
|
101
|
-
const CleanCommand = await esmock('./clean.js', {
|
|
102
|
-
'#helpers/clean.js': {
|
|
103
|
-
clean: mockClean
|
|
104
|
-
},
|
|
105
|
-
'#lib/project/index.js': {
|
|
106
|
-
default: {
|
|
107
|
-
getProjectRoot: () => '/project',
|
|
108
|
-
toObject: () => ({ output: '_site' })
|
|
109
|
-
}
|
|
110
|
-
},
|
|
111
|
-
'#helpers/test-cwd.js': {
|
|
112
|
-
default: mockTestcwd
|
|
113
|
-
},
|
|
114
|
-
'#lib/logger/index.js': {
|
|
115
|
-
logger: mockLogger
|
|
116
|
-
},
|
|
117
|
-
'fs-extra': fs
|
|
118
|
-
})
|
|
119
|
-
|
|
120
|
-
const command = new CleanCommand()
|
|
121
|
-
command.name = sandbox.stub().returns('clean')
|
|
122
|
-
command.logger = mockLogger
|
|
123
|
-
command.debug = sandbox.stub()
|
|
124
|
-
|
|
125
|
-
// Run action with dry-run
|
|
126
|
-
const options = { dryRun: true }
|
|
127
|
-
await command.action(options, command)
|
|
128
|
-
|
|
129
|
-
t.true(mockClean.called, 'clean should be called')
|
|
130
|
-
t.true(mockClean.calledWith('/project', { output: '_site' }, options), 'clean should receive dry-run option')
|
|
131
|
-
|
|
132
|
-
// Verify dry-run output uses "Will delete" instead of "Deleted"
|
|
133
|
-
const output = mockLogger.info.firstCall.args[0]
|
|
134
|
-
t.true(output.includes('Will delete'), 'should use future tense for dry-run')
|
|
135
|
-
})
|
|
136
|
-
|
|
137
|
-
test('clean command should call testcwd in preAction', async (t) => {
|
|
138
|
-
const { sandbox, fs, mockLogger } = t.context
|
|
139
|
-
|
|
140
|
-
// Mock clean helper
|
|
141
|
-
const mockClean = sandbox.stub().resolves([])
|
|
142
|
-
|
|
143
|
-
// Mock testcwd helper
|
|
144
|
-
const mockTestcwd = sandbox.stub()
|
|
145
|
-
|
|
146
|
-
// Use esmock to replace imports
|
|
147
|
-
const CleanCommand = await esmock('./clean.js', {
|
|
148
|
-
'#helpers/clean.js': {
|
|
149
|
-
clean: mockClean
|
|
150
|
-
},
|
|
151
|
-
'#lib/project/index.js': {
|
|
152
|
-
default: {
|
|
153
|
-
getProjectRoot: () => '/project',
|
|
154
|
-
toObject: () => ({ output: '_site' })
|
|
155
|
-
}
|
|
156
|
-
},
|
|
157
|
-
'#helpers/test-cwd.js': {
|
|
158
|
-
default: mockTestcwd
|
|
159
|
-
},
|
|
160
|
-
'#lib/logger/index.js': {
|
|
161
|
-
logger: mockLogger
|
|
162
|
-
},
|
|
163
|
-
'fs-extra': fs
|
|
164
|
-
})
|
|
165
|
-
|
|
166
|
-
const command = new CleanCommand()
|
|
167
|
-
command.name = sandbox.stub().returns('clean')
|
|
168
|
-
|
|
169
|
-
// Run preAction
|
|
170
|
-
command.preAction(command)
|
|
171
|
-
|
|
172
|
-
t.true(mockTestcwd.called, 'testcwd should be called in preAction')
|
|
173
|
-
t.true(mockTestcwd.calledWith(command), 'testcwd should be called with command object')
|
|
174
|
-
})
|
|
175
|
-
|
|
176
|
-
test('clean command should handle empty deletedPaths', async (t) => {
|
|
177
|
-
const { sandbox, fs, mockLogger } = t.context
|
|
178
|
-
|
|
179
|
-
// Mock clean helper to return empty array (no files to delete)
|
|
180
|
-
const mockClean = sandbox.stub().resolves([])
|
|
181
|
-
|
|
182
|
-
// Mock testcwd helper
|
|
183
|
-
const mockTestcwd = sandbox.stub()
|
|
184
|
-
|
|
185
|
-
// Use esmock to replace imports
|
|
186
|
-
const CleanCommand = await esmock('./clean.js', {
|
|
187
|
-
'#helpers/clean.js': {
|
|
188
|
-
clean: mockClean
|
|
189
|
-
},
|
|
190
|
-
'#lib/project/index.js': {
|
|
191
|
-
default: {
|
|
192
|
-
getProjectRoot: () => '/project',
|
|
193
|
-
toObject: () => ({ output: '_site' })
|
|
194
|
-
}
|
|
195
|
-
},
|
|
196
|
-
'#helpers/test-cwd.js': {
|
|
197
|
-
default: mockTestcwd
|
|
198
|
-
},
|
|
199
|
-
'#lib/logger/index.js': {
|
|
200
|
-
logger: mockLogger
|
|
201
|
-
},
|
|
202
|
-
'fs-extra': fs
|
|
203
|
-
})
|
|
204
|
-
|
|
205
|
-
const command = new CleanCommand()
|
|
206
|
-
command.name = sandbox.stub().returns('clean')
|
|
207
|
-
command.logger = mockLogger
|
|
208
|
-
command.debug = sandbox.stub()
|
|
209
|
-
|
|
210
|
-
// Run action
|
|
211
|
-
const options = {}
|
|
212
|
-
await command.action(options, command)
|
|
213
|
-
|
|
214
|
-
t.true(mockClean.called, 'clean should be called')
|
|
215
|
-
|
|
216
|
-
// Verify "no files" message
|
|
217
|
-
const output = mockLogger.info.firstCall.args[0]
|
|
218
|
-
t.true(output.includes('No files to delete'), 'should report no files to delete')
|
|
219
|
-
})
|
|
220
|
-
|
|
221
|
-
test('clean command should pass all options to clean helper', async (t) => {
|
|
222
|
-
const { sandbox, fs, mockLogger } = t.context
|
|
223
|
-
|
|
224
|
-
// Mock clean helper
|
|
225
|
-
const mockClean = sandbox.stub().resolves(['/project/_site'])
|
|
226
|
-
|
|
227
|
-
// Mock testcwd helper
|
|
228
|
-
const mockTestcwd = sandbox.stub()
|
|
229
|
-
|
|
230
|
-
// Use esmock to replace imports
|
|
231
|
-
const CleanCommand = await esmock('./clean.js', {
|
|
232
|
-
'#helpers/clean.js': {
|
|
233
|
-
clean: mockClean
|
|
234
|
-
},
|
|
235
|
-
'#lib/project/index.js': {
|
|
236
|
-
default: {
|
|
237
|
-
getProjectRoot: () => '/project',
|
|
238
|
-
toObject: () => ({ output: '_site' })
|
|
239
|
-
}
|
|
240
|
-
},
|
|
241
|
-
'#helpers/test-cwd.js': {
|
|
242
|
-
default: mockTestcwd
|
|
243
|
-
},
|
|
244
|
-
'#lib/logger/index.js': {
|
|
245
|
-
logger: mockLogger
|
|
246
|
-
},
|
|
247
|
-
'fs-extra': fs
|
|
248
|
-
})
|
|
249
|
-
|
|
250
|
-
const command = new CleanCommand()
|
|
251
|
-
command.name = sandbox.stub().returns('clean')
|
|
252
|
-
command.logger = mockLogger
|
|
253
|
-
command.debug = sandbox.stub()
|
|
254
|
-
|
|
255
|
-
// Run action with multiple options
|
|
256
|
-
const options = { verbose: true, dryRun: false }
|
|
257
|
-
await command.action(options, command)
|
|
258
|
-
|
|
259
|
-
t.true(mockClean.calledWith('/project', { output: '_site' }, options), 'clean should receive all options')
|
|
260
|
-
})
|
|
261
|
-
|
|
262
|
-
test('clean --status calls clearStatus for the project', async (t) => {
|
|
263
|
-
const { sandbox, fs, mockLogger } = t.context
|
|
264
|
-
|
|
265
|
-
const mockClean = sandbox.stub().resolves(['/project/_site'])
|
|
266
|
-
const mockTestcwd = sandbox.stub()
|
|
267
|
-
const mockClearStatus = sandbox.stub()
|
|
268
|
-
|
|
269
|
-
const CleanCommand = await esmock('./clean.js', {
|
|
270
|
-
'#helpers/clean.js': {
|
|
271
|
-
clean: mockClean
|
|
272
|
-
},
|
|
273
|
-
'#lib/conf/build-status.js': {
|
|
274
|
-
clearStatus: mockClearStatus
|
|
275
|
-
},
|
|
276
|
-
'#lib/project/index.js': {
|
|
277
|
-
default: {
|
|
278
|
-
getProjectRoot: () => '/project',
|
|
279
|
-
toObject: () => ({ output: '_site' })
|
|
280
|
-
}
|
|
281
|
-
},
|
|
282
|
-
'#helpers/test-cwd.js': {
|
|
283
|
-
default: mockTestcwd
|
|
284
|
-
},
|
|
285
|
-
'#lib/logger/index.js': {
|
|
286
|
-
logger: mockLogger
|
|
287
|
-
},
|
|
288
|
-
'fs-extra': fs
|
|
289
|
-
})
|
|
290
|
-
|
|
291
|
-
const command = new CleanCommand()
|
|
292
|
-
command.name = sandbox.stub().returns('clean')
|
|
293
|
-
command.logger = mockLogger
|
|
294
|
-
command.debug = sandbox.stub()
|
|
295
|
-
|
|
296
|
-
await command.action({ status: true }, command)
|
|
297
|
-
|
|
298
|
-
t.true(mockClearStatus.calledOnce, 'clearStatus should be called once')
|
|
299
|
-
t.true(mockClearStatus.calledWith('/project'), 'clearStatus should be called with project root')
|
|
300
|
-
|
|
301
|
-
const calls = mockLogger.info.args.map((a) => a[0])
|
|
302
|
-
t.true(calls.some((c) => c.includes('Cleared build status')), 'should log status cleared message')
|
|
303
|
-
})
|
|
304
|
-
|
|
305
|
-
test('clean --status does not call clearStatus during dry-run', async (t) => {
|
|
306
|
-
const { sandbox, fs, mockLogger } = t.context
|
|
307
|
-
|
|
308
|
-
const mockClean = sandbox.stub().resolves(['/project/_site'])
|
|
309
|
-
const mockTestcwd = sandbox.stub()
|
|
310
|
-
const mockClearStatus = sandbox.stub()
|
|
311
|
-
|
|
312
|
-
const CleanCommand = await esmock('./clean.js', {
|
|
313
|
-
'#helpers/clean.js': {
|
|
314
|
-
clean: mockClean
|
|
315
|
-
},
|
|
316
|
-
'#lib/conf/build-status.js': {
|
|
317
|
-
clearStatus: mockClearStatus
|
|
318
|
-
},
|
|
319
|
-
'#lib/project/index.js': {
|
|
320
|
-
default: {
|
|
321
|
-
getProjectRoot: () => '/project',
|
|
322
|
-
toObject: () => ({ output: '_site' })
|
|
323
|
-
}
|
|
324
|
-
},
|
|
325
|
-
'#helpers/test-cwd.js': {
|
|
326
|
-
default: mockTestcwd
|
|
327
|
-
},
|
|
328
|
-
'#lib/logger/index.js': {
|
|
329
|
-
logger: mockLogger
|
|
330
|
-
},
|
|
331
|
-
'fs-extra': fs
|
|
332
|
-
})
|
|
333
|
-
|
|
334
|
-
const command = new CleanCommand()
|
|
335
|
-
command.name = sandbox.stub().returns('clean')
|
|
336
|
-
command.logger = mockLogger
|
|
337
|
-
command.debug = sandbox.stub()
|
|
338
|
-
|
|
339
|
-
await command.action({ status: true, dryRun: true }, command)
|
|
340
|
-
|
|
341
|
-
t.false(mockClearStatus.called, 'clearStatus should not be called during dry-run')
|
|
342
|
-
})
|
|
343
|
-
|
|
344
|
-
test('clean --status with no files still clears status', async (t) => {
|
|
345
|
-
const { sandbox, fs, mockLogger } = t.context
|
|
346
|
-
|
|
347
|
-
const mockClean = sandbox.stub().resolves([])
|
|
348
|
-
const mockTestcwd = sandbox.stub()
|
|
349
|
-
const mockClearStatus = sandbox.stub()
|
|
350
|
-
|
|
351
|
-
const CleanCommand = await esmock('./clean.js', {
|
|
352
|
-
'#helpers/clean.js': {
|
|
353
|
-
clean: mockClean
|
|
354
|
-
},
|
|
355
|
-
'#lib/conf/build-status.js': {
|
|
356
|
-
clearStatus: mockClearStatus
|
|
357
|
-
},
|
|
358
|
-
'#lib/project/index.js': {
|
|
359
|
-
default: {
|
|
360
|
-
getProjectRoot: () => '/project',
|
|
361
|
-
toObject: () => ({ output: '_site' })
|
|
362
|
-
}
|
|
363
|
-
},
|
|
364
|
-
'#helpers/test-cwd.js': {
|
|
365
|
-
default: mockTestcwd
|
|
366
|
-
},
|
|
367
|
-
'#lib/logger/index.js': {
|
|
368
|
-
logger: mockLogger
|
|
369
|
-
},
|
|
370
|
-
'fs-extra': fs
|
|
371
|
-
})
|
|
372
|
-
|
|
373
|
-
const command = new CleanCommand()
|
|
374
|
-
command.name = sandbox.stub().returns('clean')
|
|
375
|
-
command.logger = mockLogger
|
|
376
|
-
command.debug = sandbox.stub()
|
|
377
|
-
|
|
378
|
-
await command.action({ status: true }, command)
|
|
379
|
-
|
|
380
|
-
t.true(mockClearStatus.calledOnce, 'clearStatus should be called even when no files deleted')
|
|
381
|
-
t.true(mockClearStatus.calledWith('/project'), 'clearStatus should be called with project root')
|
|
382
|
-
})
|
package/src/commands/config.js
DELETED
|
@@ -1,238 +0,0 @@
|
|
|
1
|
-
import Command from '#src/Command.js'
|
|
2
|
-
import {
|
|
3
|
-
isValidKey,
|
|
4
|
-
getValidKeys,
|
|
5
|
-
coerceValue,
|
|
6
|
-
formatValidationError,
|
|
7
|
-
getDefault,
|
|
8
|
-
formatSettings,
|
|
9
|
-
} from '#lib/conf/index.js'
|
|
10
|
-
import { UnknownConfigKeyError, UnknownConfigOperationError } from '#src/errors/index.js'
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Valid operations for the settings command
|
|
14
|
-
*/
|
|
15
|
-
const OPERATIONS = Object.freeze(['get', 'set', 'delete', 'reset', 'path'])
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Quire CLI `settings` Command
|
|
19
|
-
*
|
|
20
|
-
* Manages quire-cli configuration with explicit subcommand operations.
|
|
21
|
-
*
|
|
22
|
-
* @example
|
|
23
|
-
* // Show all settings
|
|
24
|
-
* quire settings
|
|
25
|
-
*
|
|
26
|
-
* // Get a single value
|
|
27
|
-
* quire settings get logLevel
|
|
28
|
-
*
|
|
29
|
-
* // Set a value
|
|
30
|
-
* quire settings set logLevel debug
|
|
31
|
-
*
|
|
32
|
-
* // Delete a key (reset to default)
|
|
33
|
-
* quire settings delete logLevel
|
|
34
|
-
*
|
|
35
|
-
* // Reset all settings to defaults
|
|
36
|
-
* quire settings reset
|
|
37
|
-
*
|
|
38
|
-
* // Reset a single key to default
|
|
39
|
-
* quire settings reset logLevel
|
|
40
|
-
*
|
|
41
|
-
* // Show settings file path
|
|
42
|
-
* quire settings path
|
|
43
|
-
*
|
|
44
|
-
* @class SettingsCommand
|
|
45
|
-
* @extends {Command}
|
|
46
|
-
*/
|
|
47
|
-
export default class SettingsCommand extends Command {
|
|
48
|
-
static definition = {
|
|
49
|
-
name: 'settings',
|
|
50
|
-
aliases: ['prefs', 'preferences', 'conf', 'config', 'configure'],
|
|
51
|
-
description: 'Manage Quire CLI settings.',
|
|
52
|
-
summary: 'view and modify CLI settings',
|
|
53
|
-
docsLink: 'quire-commands/',
|
|
54
|
-
helpText: `
|
|
55
|
-
Examples:
|
|
56
|
-
quire settings Show all settings
|
|
57
|
-
quire settings get <key> Get a single value
|
|
58
|
-
quire settings set <key> <value> Set a value
|
|
59
|
-
quire settings delete <key> Delete (reset to default)
|
|
60
|
-
quire settings reset [key] Reset all or single key
|
|
61
|
-
quire settings path Show settings file path
|
|
62
|
-
quire settings --json Output raw config JSON
|
|
63
|
-
quire settings get <key> --json Output single value as JSON
|
|
64
|
-
`,
|
|
65
|
-
version: '2.0.0',
|
|
66
|
-
args: [
|
|
67
|
-
['[operation]', `operation to perform (${OPERATIONS.join(', ')})`],
|
|
68
|
-
['[key]', 'configuration key'],
|
|
69
|
-
['[value]', 'value to set (for set operation)'],
|
|
70
|
-
],
|
|
71
|
-
options: [
|
|
72
|
-
['--json', 'output raw JSON'],
|
|
73
|
-
['--debug', 'enable debug output for troubleshooting'],
|
|
74
|
-
],
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
constructor() {
|
|
78
|
-
super(SettingsCommand.definition)
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Get a single configuration value
|
|
83
|
-
*
|
|
84
|
-
* @param {string} key - Configuration key
|
|
85
|
-
* @param {Object} options - Command options
|
|
86
|
-
*/
|
|
87
|
-
#getValue(key, options) {
|
|
88
|
-
if (!key) {
|
|
89
|
-
this.logger.error('Usage: quire conf get <key>')
|
|
90
|
-
return
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
if (!isValidKey(key) && !key.startsWith('__internal__')) {
|
|
94
|
-
throw new UnknownConfigKeyError(key, getValidKeys())
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const value = this.config.get(key)
|
|
98
|
-
|
|
99
|
-
if (options.json) {
|
|
100
|
-
console.log(JSON.stringify(value))
|
|
101
|
-
return
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (value === undefined) {
|
|
105
|
-
this.logger.info(`${key}: (not set)`)
|
|
106
|
-
} else {
|
|
107
|
-
this.logger.info(`${key}: ${JSON.stringify(value)}`)
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Set a configuration value
|
|
113
|
-
*
|
|
114
|
-
* @param {string} key - Configuration key
|
|
115
|
-
* @param {string} value - Value to set
|
|
116
|
-
*/
|
|
117
|
-
#setValue(key, value) {
|
|
118
|
-
if (!key || value === undefined) {
|
|
119
|
-
this.logger.error('Usage: quire conf set <key> <value>')
|
|
120
|
-
return
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
if (!isValidKey(key)) {
|
|
124
|
-
throw new UnknownConfigKeyError(key, getValidKeys())
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const coercedValue = coerceValue(key, value)
|
|
128
|
-
|
|
129
|
-
try {
|
|
130
|
-
this.config.set(key, coercedValue)
|
|
131
|
-
this.logger.info(`${key}: ${JSON.stringify(coercedValue)}`)
|
|
132
|
-
} catch {
|
|
133
|
-
this.logger.error(formatValidationError(key, coercedValue))
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Delete a configuration key (resets to default)
|
|
139
|
-
*
|
|
140
|
-
* @param {string} key - Configuration key
|
|
141
|
-
*/
|
|
142
|
-
#deleteKey(key) {
|
|
143
|
-
if (!key) {
|
|
144
|
-
this.logger.error('Usage: quire conf delete <key>')
|
|
145
|
-
return
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
if (!isValidKey(key)) {
|
|
149
|
-
throw new UnknownConfigKeyError(key, getValidKeys())
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
this.config.delete(key)
|
|
153
|
-
const defaultValue = getDefault(key)
|
|
154
|
-
this.logger.info(`${key}: reset to ${JSON.stringify(defaultValue)}`)
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Reset configuration to defaults
|
|
159
|
-
*
|
|
160
|
-
* @param {string} [key] - Optional key to reset (resets all if omitted)
|
|
161
|
-
*/
|
|
162
|
-
#reset(key) {
|
|
163
|
-
if (key) {
|
|
164
|
-
if (!isValidKey(key)) {
|
|
165
|
-
throw new UnknownConfigKeyError(key, getValidKeys())
|
|
166
|
-
}
|
|
167
|
-
this.config.reset(key)
|
|
168
|
-
const defaultValue = getDefault(key)
|
|
169
|
-
this.logger.info(`${key}: reset to ${JSON.stringify(defaultValue)}`)
|
|
170
|
-
} else {
|
|
171
|
-
this.config.clear()
|
|
172
|
-
this.logger.info('Configuration reset to defaults')
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Show all configuration values with descriptions
|
|
178
|
-
*/
|
|
179
|
-
#showAll(options) {
|
|
180
|
-
if (options.json) {
|
|
181
|
-
const store = options.debug
|
|
182
|
-
? this.config.store
|
|
183
|
-
: Object.fromEntries(
|
|
184
|
-
Object.entries(this.config.store).filter(([k]) =>
|
|
185
|
-
!k.startsWith('__internal__') && k !== 'projects'
|
|
186
|
-
)
|
|
187
|
-
)
|
|
188
|
-
console.log(JSON.stringify(store, null, 2))
|
|
189
|
-
return
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
const output = formatSettings(this.config.store, {
|
|
193
|
-
showInternal: options.debug,
|
|
194
|
-
configPath: this.config.path,
|
|
195
|
-
useColor: this.config.get('logUseColor') && !process.env.NO_COLOR,
|
|
196
|
-
})
|
|
197
|
-
this.logger.info(output)
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* Show config file path
|
|
202
|
-
*/
|
|
203
|
-
#showPath() {
|
|
204
|
-
this.logger.info(this.config.path)
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* @param {string} [operation] - Operation to perform
|
|
209
|
-
* @param {string} [key] - Configuration key
|
|
210
|
-
* @param {string} [value] - Value to set
|
|
211
|
-
* @param {Object} options - Command options
|
|
212
|
-
* @return {Promise}
|
|
213
|
-
*/
|
|
214
|
-
async action(operation, key, value, options = {}) {
|
|
215
|
-
this.debug('called with operation=%s key=%s value=%s options=%O', operation, key, value, options)
|
|
216
|
-
|
|
217
|
-
// Validate operation if provided
|
|
218
|
-
if (operation && !OPERATIONS.includes(operation)) {
|
|
219
|
-
throw new UnknownConfigOperationError(operation, [...OPERATIONS])
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// Dispatch to operation handler
|
|
223
|
-
switch (operation) {
|
|
224
|
-
case 'get':
|
|
225
|
-
return this.#getValue(key, options)
|
|
226
|
-
case 'set':
|
|
227
|
-
return this.#setValue(key, value)
|
|
228
|
-
case 'delete':
|
|
229
|
-
return this.#deleteKey(key)
|
|
230
|
-
case 'reset':
|
|
231
|
-
return this.#reset(key)
|
|
232
|
-
case 'path':
|
|
233
|
-
return this.#showPath()
|
|
234
|
-
default:
|
|
235
|
-
return this.#showAll(options)
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
}
|