@thegetty/quire-cli 1.0.0-rc.37 → 1.0.0-rc.38
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/package.json +3 -2
- package/src/commands/build.js +13 -6
- package/src/commands/clean.js +10 -2
- package/src/commands/clean.spec.js +10 -0
- package/src/commands/clean.test.js +122 -0
- package/src/commands/config.js +3 -1
- package/src/commands/config.test.js +42 -1
- package/src/commands/doctor.js +251 -0
- package/src/commands/doctor.spec.js +115 -0
- package/src/commands/doctor.test.js +1409 -0
- package/src/commands/epub.js +9 -2
- package/src/commands/info.js +79 -71
- package/src/commands/info.spec.js +8 -0
- package/src/commands/info.test.js +173 -76
- package/src/commands/pdf.js +10 -3
- package/src/commands/validate.js +39 -7
- package/src/commands/validate.spec.js +8 -0
- package/src/commands/validate.test.js +144 -0
- package/src/lib/README.md +77 -22
- package/src/lib/conf/README.md +6 -0
- package/src/lib/conf/build-status.js +103 -0
- package/src/lib/conf/build-status.test.js +247 -0
- package/src/lib/conf/defaults.js +14 -0
- package/src/lib/conf/format.js +1 -1
- package/src/lib/conf/schema.js +46 -1
- package/src/lib/constants.js +28 -0
- package/src/lib/doctor/README.md +667 -0
- package/src/lib/doctor/checks/environment/cli-version.js +62 -0
- package/src/lib/doctor/checks/environment/cli-version.test.js +132 -0
- package/src/lib/doctor/checks/environment/git-available.js +77 -0
- package/src/lib/doctor/checks/environment/git-available.test.js +52 -0
- package/src/lib/doctor/checks/environment/index.js +13 -0
- package/src/lib/doctor/checks/environment/node-version.js +66 -0
- package/src/lib/doctor/checks/environment/node-version.test.js +17 -0
- package/src/lib/doctor/checks/environment/npm-available.js +66 -0
- package/src/lib/doctor/checks/environment/npm-available.test.js +52 -0
- package/src/lib/doctor/checks/environment/os-info.js +48 -0
- package/src/lib/doctor/checks/environment/os-info.test.js +81 -0
- package/src/lib/doctor/checks/environment/runtime-info.js +51 -0
- package/src/lib/doctor/checks/environment/runtime-info.test.js +132 -0
- package/src/lib/doctor/checks/outputs/epub-output.js +119 -0
- package/src/lib/doctor/checks/outputs/epub-output.test.js +277 -0
- package/src/lib/doctor/checks/outputs/index.js +10 -0
- package/src/lib/doctor/checks/outputs/pdf-output.js +144 -0
- package/src/lib/doctor/checks/outputs/pdf-output.test.js +377 -0
- package/src/lib/doctor/checks/outputs/stale-build.js +122 -0
- package/src/lib/doctor/checks/outputs/stale-build.test.js +282 -0
- package/src/lib/doctor/checks/project/data-files.js +56 -0
- package/src/lib/doctor/checks/project/data-files.test.js +125 -0
- package/src/lib/doctor/checks/project/dependencies.js +53 -0
- package/src/lib/doctor/checks/project/dependencies.test.js +71 -0
- package/src/lib/doctor/checks/project/index.js +11 -0
- package/src/lib/doctor/checks/project/quire-11ty.js +98 -0
- package/src/lib/doctor/checks/project/quire-11ty.test.js +170 -0
- package/src/lib/doctor/checks/project/quire-project.js +38 -0
- package/src/lib/doctor/checks/project/quire-project.test.js +47 -0
- package/src/lib/doctor/checks/tools/index.js +10 -0
- package/src/lib/doctor/checks/tools/pandoc-available.js +82 -0
- package/src/lib/doctor/checks/tools/pandoc-available.test.js +73 -0
- package/src/lib/doctor/checks/tools/prince-available.js +81 -0
- package/src/lib/doctor/checks/tools/prince-available.test.js +73 -0
- package/src/lib/doctor/constants.js +39 -0
- package/src/lib/doctor/formatDuration.js +108 -0
- package/src/lib/doctor/formatDuration.test.js +76 -0
- package/src/lib/doctor/formatters/human.js +257 -0
- package/src/lib/doctor/formatters/human.test.js +463 -0
- package/src/lib/doctor/formatters/index.js +8 -0
- package/src/lib/doctor/formatters/json.js +78 -0
- package/src/lib/doctor/formatters/json.test.js +174 -0
- package/src/lib/doctor/formatters/shared.js +129 -0
- package/src/lib/doctor/formatters/shared.test.js +194 -0
- package/src/lib/doctor/index.js +271 -0
- package/src/lib/doctor/index.test.js +797 -0
- package/src/lib/platform.js +95 -0
- package/src/lib/project/build.js +44 -25
- package/src/lib/project/build.test.js +30 -8
- package/src/lib/project/detect.js +16 -2
- package/src/lib/project/index.js +18 -2
- package/src/lib/project/output-paths.js +87 -0
- package/src/lib/project/output-paths.test.js +66 -0
- package/src/lib/project/paths.js +48 -0
- package/src/main.js +24 -2
- package/src/packageConfig.js +17 -0
- package/src/validators/validate-data-files.js +154 -0
- package/src/validators/validate-data-files.test.js +217 -0
package/src/commands/epub.js
CHANGED
|
@@ -5,6 +5,7 @@ import eleventy from '#lib/11ty/index.js'
|
|
|
5
5
|
import fs from 'fs-extra'
|
|
6
6
|
import generateEpub, { ENGINES } from '#lib/epub/index.js'
|
|
7
7
|
import open from 'open'
|
|
8
|
+
import { recordStatus } from '#lib/conf/build-status.js'
|
|
8
9
|
import reporter from '#lib/reporter/index.js'
|
|
9
10
|
import testcwd from '#helpers/test-cwd.js'
|
|
10
11
|
import { MissingBuildOutputError } from '#src/errors/index.js'
|
|
@@ -84,9 +85,15 @@ Examples:
|
|
|
84
85
|
// Pass engine as lib (matching lib/pdf interface)
|
|
85
86
|
// Reporter lifecycle is owned by the façade (lib/epub/index.js)
|
|
86
87
|
const epubOptions = { ...options, lib: options.engine }
|
|
87
|
-
const output = await generateEpub(epubOptions)
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
try {
|
|
90
|
+
const output = await generateEpub(epubOptions)
|
|
91
|
+
recordStatus(paths.getProjectRoot(), 'epub', 'ok')
|
|
92
|
+
if (fs.existsSync(output) && options.open) open(output)
|
|
93
|
+
} catch (error) {
|
|
94
|
+
recordStatus(paths.getProjectRoot(), 'epub', 'failed')
|
|
95
|
+
throw error
|
|
96
|
+
}
|
|
90
97
|
}
|
|
91
98
|
|
|
92
99
|
preAction(thisCommand, actionCommand) {
|
package/src/commands/info.js
CHANGED
|
@@ -1,34 +1,52 @@
|
|
|
1
1
|
import Command from '#src/Command.js'
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
2
|
+
import { withOutputModes } from '#lib/commander/index.js'
|
|
3
|
+
import { binPath } from '#src/packageConfig.js'
|
|
4
4
|
import fs from 'node:fs'
|
|
5
|
-
import os from 'node:os'
|
|
6
5
|
import path from 'node:path'
|
|
7
6
|
import testcwd from '#helpers/test-cwd.js'
|
|
8
7
|
|
|
9
8
|
/**
|
|
10
9
|
* Quire CLI `info` Command
|
|
11
10
|
*
|
|
12
|
-
*
|
|
11
|
+
* Display version information for the current Quire project.
|
|
12
|
+
* Shows the versions of quire-cli and quire-11ty that the project was
|
|
13
|
+
* created with, plus the starter template version.
|
|
14
|
+
*
|
|
15
|
+
* With --debug, also shows the full filesystem path to the quire-cli
|
|
16
|
+
* executable.
|
|
17
|
+
*
|
|
18
|
+
* For system environment information (OS, Node.js, npm, Git),
|
|
19
|
+
* use the `quire doctor` command instead.
|
|
13
20
|
*
|
|
14
21
|
* @class InfoCommand
|
|
15
22
|
* @extends {Command}
|
|
16
23
|
*/
|
|
17
24
|
export default class InfoCommand extends Command {
|
|
18
|
-
static definition = {
|
|
25
|
+
static definition = withOutputModes({
|
|
19
26
|
name: 'info',
|
|
20
|
-
description: '
|
|
21
|
-
summary: 'show version information',
|
|
27
|
+
description: 'Display version information for the current project',
|
|
28
|
+
summary: 'show project version information',
|
|
22
29
|
docsLink: 'quire-commands/#get-help',
|
|
23
30
|
helpText: `
|
|
31
|
+
Shows the versions used when this project was created:
|
|
32
|
+
• quire-cli version that created the project
|
|
33
|
+
• quire-11ty version installed in the project
|
|
34
|
+
• starter template version (if available)
|
|
35
|
+
|
|
36
|
+
For system environment checks (OS, Node.js, npm, Git),
|
|
37
|
+
use 'quire doctor' instead.
|
|
38
|
+
|
|
24
39
|
Example:
|
|
25
|
-
quire info
|
|
40
|
+
quire info Show project versions
|
|
41
|
+
quire info --debug Include installation paths
|
|
42
|
+
quire info --json Output version information as JSON
|
|
43
|
+
quire doctor Check environment and project health
|
|
26
44
|
`,
|
|
27
45
|
version: '1.0.0',
|
|
28
46
|
options: [
|
|
29
|
-
['--
|
|
47
|
+
['--json', 'output version information as JSON'],
|
|
30
48
|
],
|
|
31
|
-
}
|
|
49
|
+
})
|
|
32
50
|
|
|
33
51
|
constructor() {
|
|
34
52
|
super(InfoCommand.definition)
|
|
@@ -43,79 +61,69 @@ Example:
|
|
|
43
61
|
|
|
44
62
|
try {
|
|
45
63
|
const versionFileData = fs.readFileSync(versionFileName, { encoding: 'utf8' })
|
|
46
|
-
|
|
47
|
-
versionInfo = JSON.parse(versionFileData)
|
|
64
|
+
versionInfo = JSON.parse(versionFileData)
|
|
48
65
|
} catch (error) {
|
|
49
66
|
this.logger.warn(
|
|
50
67
|
`This project was generated with the quire-cli prior to version 1.0.0.rc-8. Updating the version file to the new format, though this project's version file will not contain specific starter version information.`
|
|
51
68
|
)
|
|
52
|
-
|
|
53
69
|
fs.writeFileSync(versionFileName, JSON.stringify(versionInfo))
|
|
54
70
|
}
|
|
55
71
|
|
|
56
72
|
const { name: projectDirectory } = path.parse(process.cwd())
|
|
57
73
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
const { stdout } = await execa('quire', ['--version'])
|
|
86
|
-
return stdout
|
|
87
|
-
},
|
|
88
|
-
},
|
|
89
|
-
{
|
|
90
|
-
debug: true,
|
|
91
|
-
name: 'node',
|
|
92
|
-
get: () => process.version,
|
|
93
|
-
},
|
|
94
|
-
{
|
|
95
|
-
debug: true,
|
|
96
|
-
name: 'npm',
|
|
97
|
-
get: async () => await npm.version(),
|
|
98
|
-
},
|
|
99
|
-
{
|
|
100
|
-
debug: true,
|
|
101
|
-
name: 'os',
|
|
102
|
-
get: () => `${os.type()} ${os.release()}`,
|
|
103
|
-
},
|
|
104
|
-
],
|
|
105
|
-
},
|
|
74
|
+
// Read quire-11ty version from project's package.json
|
|
75
|
+
let quire11tyVersion = 'unknown'
|
|
76
|
+
try {
|
|
77
|
+
const packageJson = JSON.parse(fs.readFileSync('./package.json', 'utf8'))
|
|
78
|
+
quire11tyVersion = packageJson.version
|
|
79
|
+
} catch {
|
|
80
|
+
this.debug('Could not read package.json')
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (options.json) {
|
|
84
|
+
const result = {
|
|
85
|
+
project: {
|
|
86
|
+
directory: projectDirectory,
|
|
87
|
+
cli: versionInfo.cli,
|
|
88
|
+
quire11ty: quire11tyVersion,
|
|
89
|
+
starter: versionInfo.starter || null,
|
|
90
|
+
},
|
|
91
|
+
}
|
|
92
|
+
console.log(JSON.stringify(result, null, 2))
|
|
93
|
+
return
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const lines = [
|
|
97
|
+
`Project: ${projectDirectory}`,
|
|
98
|
+
'',
|
|
99
|
+
` quire-cli ${versionInfo.cli || 'unknown'}`,
|
|
100
|
+
` quire-11ty ${quire11tyVersion}`,
|
|
106
101
|
]
|
|
107
102
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
.map(async ({ name, get }) => `${name} ${await get()}`)
|
|
116
|
-
)
|
|
117
|
-
this.logger.info(`${title}\n ${versionList.join('\n ')}`)
|
|
103
|
+
if (versionInfo.starter) {
|
|
104
|
+
lines.push(` starter ${versionInfo.starter}`)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (options.debug) {
|
|
108
|
+
lines.push('')
|
|
109
|
+
lines.push(this.resolveCliPath())
|
|
118
110
|
}
|
|
111
|
+
|
|
112
|
+
lines.push('')
|
|
113
|
+
lines.push('Tip: Run \'quire doctor\' for system environment checks')
|
|
114
|
+
|
|
115
|
+
this.logger.info(lines.join('\n'))
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Resolve the full filesystem path to the quire CLI executable
|
|
120
|
+
* @returns {string} Formatted path line
|
|
121
|
+
*/
|
|
122
|
+
resolveCliPath() {
|
|
123
|
+
const resolved = binPath()
|
|
124
|
+
return resolved
|
|
125
|
+
? ` quire-cli ${resolved}`
|
|
126
|
+
: ' quire-cli not found in PATH'
|
|
119
127
|
}
|
|
120
128
|
|
|
121
129
|
preAction(thisCommand, actionCommand) {
|
|
@@ -40,15 +40,22 @@ test('registered command has correct options', (t) => {
|
|
|
40
40
|
const { command } = t.context
|
|
41
41
|
|
|
42
42
|
// Get all options
|
|
43
|
+
const jsonOption = command.options.find((opt) => opt.long === '--json')
|
|
43
44
|
const debugOption = command.options.find((opt) => opt.long === '--debug')
|
|
44
45
|
|
|
45
46
|
// Verify all options exist
|
|
47
|
+
t.truthy(jsonOption, '--json option should exist')
|
|
46
48
|
t.truthy(debugOption, '--debug option should exist')
|
|
47
49
|
|
|
48
50
|
// Verify they are Option instances
|
|
51
|
+
t.true(jsonOption instanceof Option, '--json should be Option instance')
|
|
49
52
|
t.true(debugOption instanceof Option, '--debug should be Option instance')
|
|
50
53
|
|
|
51
54
|
// Verify option properties
|
|
55
|
+
t.is(jsonOption.long, '--json')
|
|
56
|
+
t.truthy(jsonOption.description)
|
|
57
|
+
t.false(jsonOption.required, '--json should not require a value')
|
|
58
|
+
|
|
52
59
|
t.is(debugOption.long, '--debug')
|
|
53
60
|
t.truthy(debugOption.description)
|
|
54
61
|
t.false(debugOption.required, '--debug should not require a value')
|
|
@@ -60,5 +67,6 @@ test('command options are accessible via public API', (t) => {
|
|
|
60
67
|
// Test that options can be accessed the way Commander.js does
|
|
61
68
|
const optionNames = command.options.map((opt) => opt.long)
|
|
62
69
|
|
|
70
|
+
t.true(optionNames.includes('--json'))
|
|
63
71
|
t.true(optionNames.includes('--debug'))
|
|
64
72
|
})
|
|
@@ -23,16 +23,8 @@ test.beforeEach((t) => {
|
|
|
23
23
|
// Mock testcwd helper
|
|
24
24
|
t.context.mockTestcwd = t.context.sandbox.stub()
|
|
25
25
|
|
|
26
|
-
// Mock
|
|
27
|
-
t.context.
|
|
28
|
-
t.context.mockExecaCommand.withArgs('quire --version').resolves({ stdout: '1.0.0-rc.33' })
|
|
29
|
-
t.context.mockExecaCommand.withArgs('npm --version').resolves({ stdout: '10.2.4' })
|
|
30
|
-
|
|
31
|
-
// Mock os module
|
|
32
|
-
t.context.mockOs = {
|
|
33
|
-
type: t.context.sandbox.stub().returns('Darwin'),
|
|
34
|
-
release: t.context.sandbox.stub().returns('23.0.0')
|
|
35
|
-
}
|
|
26
|
+
// Mock packageConfig binPath
|
|
27
|
+
t.context.mockBinPath = t.context.sandbox.stub().returns('/usr/local/bin/quire')
|
|
36
28
|
|
|
37
29
|
// Mock fs module
|
|
38
30
|
t.context.mockFs = {
|
|
@@ -72,16 +64,15 @@ test.afterEach.always((t) => {
|
|
|
72
64
|
})
|
|
73
65
|
|
|
74
66
|
test('info command should validate Quire project in preAction', async (t) => {
|
|
75
|
-
const { sandbox, mockLogger, mockTestcwd, mockConfig,
|
|
67
|
+
const { sandbox, mockLogger, mockTestcwd, mockConfig, mockBinPath, mockFs } = t.context
|
|
76
68
|
|
|
77
69
|
const { default: InfoCommand } = await esmock('./info.js', {
|
|
78
70
|
'#helpers/test-cwd.js': {
|
|
79
71
|
default: mockTestcwd
|
|
80
72
|
},
|
|
81
|
-
'
|
|
82
|
-
|
|
73
|
+
'#src/packageConfig.js': {
|
|
74
|
+
binPath: mockBinPath
|
|
83
75
|
},
|
|
84
|
-
'node:os': mockOs,
|
|
85
76
|
'node:fs': mockFs
|
|
86
77
|
}, {
|
|
87
78
|
'#lib/logger/index.js': {
|
|
@@ -108,16 +99,15 @@ test('info command should validate Quire project in preAction', async (t) => {
|
|
|
108
99
|
})
|
|
109
100
|
|
|
110
101
|
test('info command should display project version information', async (t) => {
|
|
111
|
-
const { sandbox, mockLogger, mockConfig, mockTestcwd,
|
|
102
|
+
const { sandbox, mockLogger, mockConfig, mockTestcwd, mockBinPath, mockFs } = t.context
|
|
112
103
|
|
|
113
104
|
const { default: InfoCommand } = await esmock('./info.js', {
|
|
114
105
|
'#helpers/test-cwd.js': {
|
|
115
106
|
default: mockTestcwd
|
|
116
107
|
},
|
|
117
|
-
'
|
|
118
|
-
|
|
108
|
+
'#src/packageConfig.js': {
|
|
109
|
+
binPath: mockBinPath
|
|
119
110
|
},
|
|
120
|
-
'node:os': mockOs,
|
|
121
111
|
'node:fs': mockFs
|
|
122
112
|
}, {
|
|
123
113
|
'#lib/logger/index.js': {
|
|
@@ -135,31 +125,42 @@ test('info command should display project version information', async (t) => {
|
|
|
135
125
|
// Verify logger.info was called with project information
|
|
136
126
|
t.true(mockLogger.info.called, 'logger.info should be called')
|
|
137
127
|
|
|
138
|
-
// Check for project
|
|
128
|
+
// Check for project header
|
|
139
129
|
const calls = mockLogger.info.getCalls()
|
|
140
130
|
const hasProjectInfo = calls.some((call) =>
|
|
141
|
-
call.args[0] && call.args[0].includes('
|
|
131
|
+
call.args[0] && call.args[0].includes('Project:')
|
|
142
132
|
)
|
|
143
|
-
t.true(hasProjectInfo, 'should display project
|
|
133
|
+
t.true(hasProjectInfo, 'should display project header')
|
|
144
134
|
|
|
145
135
|
// Check for quire-cli version in output
|
|
146
136
|
const hasCliVersion = calls.some((call) =>
|
|
147
137
|
call.args[0] && call.args[0].includes('quire-cli') && call.args[0].includes('1.0.0-rc.33')
|
|
148
138
|
)
|
|
149
139
|
t.true(hasCliVersion, 'should display quire-cli version')
|
|
140
|
+
|
|
141
|
+
// Check for quire-11ty version in output
|
|
142
|
+
const has11tyVersion = calls.some((call) =>
|
|
143
|
+
call.args[0] && call.args[0].includes('quire-11ty')
|
|
144
|
+
)
|
|
145
|
+
t.true(has11tyVersion, 'should display quire-11ty version')
|
|
146
|
+
|
|
147
|
+
// Check for doctor tip
|
|
148
|
+
const hasDoctorTip = calls.some((call) =>
|
|
149
|
+
call.args[0] && call.args[0].includes('quire doctor')
|
|
150
|
+
)
|
|
151
|
+
t.true(hasDoctorTip, 'should display doctor tip')
|
|
150
152
|
})
|
|
151
153
|
|
|
152
|
-
test('info command should display
|
|
153
|
-
const { sandbox, mockLogger, mockConfig, mockTestcwd,
|
|
154
|
+
test('info command should display starter version when available', async (t) => {
|
|
155
|
+
const { sandbox, mockLogger, mockConfig, mockTestcwd, mockBinPath, mockFs } = t.context
|
|
154
156
|
|
|
155
157
|
const { default: InfoCommand } = await esmock('./info.js', {
|
|
156
158
|
'#helpers/test-cwd.js': {
|
|
157
159
|
default: mockTestcwd
|
|
158
160
|
},
|
|
159
|
-
'
|
|
160
|
-
|
|
161
|
+
'#src/packageConfig.js': {
|
|
162
|
+
binPath: mockBinPath
|
|
161
163
|
},
|
|
162
|
-
'node:os': mockOs,
|
|
163
164
|
'node:fs': mockFs
|
|
164
165
|
}, {
|
|
165
166
|
'#lib/logger/index.js': {
|
|
@@ -172,42 +173,63 @@ test('info command should display system information with debug flag', async (t)
|
|
|
172
173
|
command.logger = mockLogger
|
|
173
174
|
command.debug = sandbox.stub()
|
|
174
175
|
|
|
175
|
-
await command.action({
|
|
176
|
+
await command.action({}, {})
|
|
176
177
|
|
|
177
178
|
// Verify logger.info was called
|
|
178
179
|
t.true(mockLogger.info.called, 'logger.info should be called')
|
|
179
180
|
|
|
180
|
-
// Check for
|
|
181
|
+
// Check for starter version in output (from version file)
|
|
181
182
|
const calls = mockLogger.info.getCalls()
|
|
182
|
-
const
|
|
183
|
-
call.args[0] && call.args[0].includes('
|
|
183
|
+
const hasStarterVersion = calls.some((call) =>
|
|
184
|
+
call.args[0] && call.args[0].includes('starter')
|
|
184
185
|
)
|
|
185
|
-
t.true(
|
|
186
|
+
t.true(hasStarterVersion, 'should display starter version when available')
|
|
187
|
+
})
|
|
186
188
|
|
|
187
|
-
|
|
188
|
-
const
|
|
189
|
-
call.args[0] && call.args[0].includes('node')
|
|
190
|
-
)
|
|
191
|
-
t.true(hasNodeVersion, 'should display node version with debug flag')
|
|
189
|
+
test('info command --debug shows installation paths', async (t) => {
|
|
190
|
+
const { sandbox, mockLogger, mockConfig, mockTestcwd, mockBinPath, mockFs } = t.context
|
|
192
191
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
192
|
+
const { default: InfoCommand } = await esmock('./info.js', {
|
|
193
|
+
'#helpers/test-cwd.js': {
|
|
194
|
+
default: mockTestcwd
|
|
195
|
+
},
|
|
196
|
+
'#src/packageConfig.js': {
|
|
197
|
+
binPath: mockBinPath
|
|
198
|
+
},
|
|
199
|
+
'node:fs': mockFs
|
|
200
|
+
}, {
|
|
201
|
+
'#lib/logger/index.js': {
|
|
202
|
+
default: () => mockLogger
|
|
203
|
+
}
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
const command = new InfoCommand()
|
|
207
|
+
command.config = mockConfig
|
|
208
|
+
command.logger = mockLogger
|
|
209
|
+
command.debug = sandbox.stub()
|
|
210
|
+
|
|
211
|
+
await command.action({ debug: true }, {})
|
|
212
|
+
|
|
213
|
+
const calls = mockLogger.info.getCalls()
|
|
214
|
+
const output = calls.map((call) => call.args[0]).join('\n')
|
|
215
|
+
|
|
216
|
+
// Check for quire-cli path
|
|
217
|
+
t.true(output.includes('/usr/local/bin/quire'), 'should display quire-cli path')
|
|
198
218
|
})
|
|
199
219
|
|
|
200
|
-
test('info command
|
|
201
|
-
const { sandbox, mockLogger, mockConfig, mockTestcwd,
|
|
220
|
+
test('info command --debug handles missing quire-cli in PATH', async (t) => {
|
|
221
|
+
const { sandbox, mockLogger, mockConfig, mockTestcwd, mockFs } = t.context
|
|
222
|
+
|
|
223
|
+
// binPath returns null when executable is not found
|
|
224
|
+
const mockBinPathNotFound = sandbox.stub().returns(null)
|
|
202
225
|
|
|
203
226
|
const { default: InfoCommand } = await esmock('./info.js', {
|
|
204
227
|
'#helpers/test-cwd.js': {
|
|
205
228
|
default: mockTestcwd
|
|
206
229
|
},
|
|
207
|
-
'
|
|
208
|
-
|
|
230
|
+
'#src/packageConfig.js': {
|
|
231
|
+
binPath: mockBinPathNotFound
|
|
209
232
|
},
|
|
210
|
-
'node:os': mockOs,
|
|
211
233
|
'node:fs': mockFs
|
|
212
234
|
}, {
|
|
213
235
|
'#lib/logger/index.js': {
|
|
@@ -220,23 +242,16 @@ test('info command should hide system details without debug flag', async (t) =>
|
|
|
220
242
|
command.logger = mockLogger
|
|
221
243
|
command.debug = sandbox.stub()
|
|
222
244
|
|
|
223
|
-
await command.action({}, {})
|
|
224
|
-
|
|
225
|
-
// Verify logger.info was called
|
|
226
|
-
t.true(mockLogger.info.called, 'logger.info should be called')
|
|
245
|
+
await command.action({ debug: true }, {})
|
|
227
246
|
|
|
228
|
-
// Check that system details are NOT shown without debug flag
|
|
229
247
|
const calls = mockLogger.info.getCalls()
|
|
248
|
+
const output = calls.map((call) => call.args[0]).join('\n')
|
|
230
249
|
|
|
231
|
-
|
|
232
|
-
const hasNodeVersion = calls.some((call) =>
|
|
233
|
-
call.args[0] && call.args[0].toLowerCase().includes('node') && !call.args[0].includes('quire')
|
|
234
|
-
)
|
|
235
|
-
t.false(hasNodeVersion, 'should not display node version without debug flag')
|
|
250
|
+
t.true(output.includes('not found in PATH'), 'should show not found message for quire-cli')
|
|
236
251
|
})
|
|
237
252
|
|
|
238
253
|
test('info command should handle missing version file', async (t) => {
|
|
239
|
-
const { sandbox, mockLogger, mockConfig, mockTestcwd,
|
|
254
|
+
const { sandbox, mockLogger, mockConfig, mockTestcwd, mockBinPath, mockFs } = t.context
|
|
240
255
|
|
|
241
256
|
// Setup mockFs to throw error for missing version file (simulating file not found)
|
|
242
257
|
mockFs.readFileSync.callsFake((filePath, options) => {
|
|
@@ -253,10 +268,9 @@ test('info command should handle missing version file', async (t) => {
|
|
|
253
268
|
'#helpers/test-cwd.js': {
|
|
254
269
|
default: mockTestcwd
|
|
255
270
|
},
|
|
256
|
-
'
|
|
257
|
-
|
|
271
|
+
'#src/packageConfig.js': {
|
|
272
|
+
binPath: mockBinPath
|
|
258
273
|
},
|
|
259
|
-
'node:os': mockOs,
|
|
260
274
|
'node:fs': mockFs
|
|
261
275
|
}, {
|
|
262
276
|
'#lib/logger/index.js': {
|
|
@@ -283,7 +297,7 @@ test('info command should handle missing version file', async (t) => {
|
|
|
283
297
|
})
|
|
284
298
|
|
|
285
299
|
test('info command should handle malformed version file', async (t) => {
|
|
286
|
-
const { sandbox, mockLogger, mockConfig, mockTestcwd,
|
|
300
|
+
const { sandbox, mockLogger, mockConfig, mockTestcwd, mockBinPath, mockFs } = t.context
|
|
287
301
|
|
|
288
302
|
// Setup mockFs to return malformed JSON (simulating corrupted file)
|
|
289
303
|
mockFs.readFileSync.callsFake((filePath, options) => {
|
|
@@ -300,10 +314,9 @@ test('info command should handle malformed version file', async (t) => {
|
|
|
300
314
|
'#helpers/test-cwd.js': {
|
|
301
315
|
default: mockTestcwd
|
|
302
316
|
},
|
|
303
|
-
'
|
|
304
|
-
|
|
317
|
+
'#src/packageConfig.js': {
|
|
318
|
+
binPath: mockBinPath
|
|
305
319
|
},
|
|
306
|
-
'node:os': mockOs,
|
|
307
320
|
'node:fs': mockFs
|
|
308
321
|
}, {
|
|
309
322
|
'#lib/logger/index.js': {
|
|
@@ -333,7 +346,7 @@ test('info command should handle malformed version file', async (t) => {
|
|
|
333
346
|
})
|
|
334
347
|
|
|
335
348
|
test('info command should read quire-11ty version from package.json', async (t) => {
|
|
336
|
-
const { sandbox, mockLogger, mockConfig, mockTestcwd,
|
|
349
|
+
const { sandbox, mockLogger, mockConfig, mockTestcwd, mockBinPath, mockFs } = t.context
|
|
337
350
|
|
|
338
351
|
// Override package.json to have specific version
|
|
339
352
|
mockFs.readFileSync.callsFake((filePath, options) => {
|
|
@@ -353,10 +366,9 @@ test('info command should read quire-11ty version from package.json', async (t)
|
|
|
353
366
|
'#helpers/test-cwd.js': {
|
|
354
367
|
default: mockTestcwd
|
|
355
368
|
},
|
|
356
|
-
'
|
|
357
|
-
|
|
369
|
+
'#src/packageConfig.js': {
|
|
370
|
+
binPath: mockBinPath
|
|
358
371
|
},
|
|
359
|
-
'node:os': mockOs,
|
|
360
372
|
'node:fs': mockFs
|
|
361
373
|
}, {
|
|
362
374
|
'#lib/logger/index.js': {
|
|
@@ -382,8 +394,8 @@ test('info command should read quire-11ty version from package.json', async (t)
|
|
|
382
394
|
t.true(hasEleventyVersion, 'should display quire-11ty version from package.json')
|
|
383
395
|
})
|
|
384
396
|
|
|
385
|
-
test('info command should log debug information
|
|
386
|
-
const { sandbox, mockLogger, mockConfig, mockTestcwd,
|
|
397
|
+
test('info command should log debug information', async (t) => {
|
|
398
|
+
const { sandbox, mockLogger, mockConfig, mockTestcwd, mockBinPath, mockFs } = t.context
|
|
387
399
|
|
|
388
400
|
const mockDebug = sandbox.stub()
|
|
389
401
|
|
|
@@ -391,10 +403,9 @@ test('info command should log debug information when debug flag is set', async (
|
|
|
391
403
|
'#helpers/test-cwd.js': {
|
|
392
404
|
default: mockTestcwd
|
|
393
405
|
},
|
|
394
|
-
'
|
|
395
|
-
|
|
406
|
+
'#src/packageConfig.js': {
|
|
407
|
+
binPath: mockBinPath
|
|
396
408
|
},
|
|
397
|
-
'node:os': mockOs,
|
|
398
409
|
'node:fs': mockFs
|
|
399
410
|
}, {
|
|
400
411
|
'#lib/logger/index.js': {
|
|
@@ -407,9 +418,95 @@ test('info command should log debug information when debug flag is set', async (
|
|
|
407
418
|
command.logger = mockLogger
|
|
408
419
|
command.debug = mockDebug
|
|
409
420
|
|
|
410
|
-
await command.action({
|
|
421
|
+
await command.action({}, {})
|
|
411
422
|
|
|
412
423
|
// Verify debug was called
|
|
413
|
-
t.true(mockDebug.called, 'debug should be called
|
|
414
|
-
t.true(mockDebug.calledWith('called with options %O', {
|
|
424
|
+
t.true(mockDebug.called, 'debug should be called')
|
|
425
|
+
t.true(mockDebug.calledWith('called with options %O', {}))
|
|
426
|
+
})
|
|
427
|
+
|
|
428
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
429
|
+
// JSON output tests
|
|
430
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
431
|
+
|
|
432
|
+
test.serial('info --json should output valid JSON with project versions', async (t) => {
|
|
433
|
+
const { sandbox, mockLogger, mockConfig, mockTestcwd, mockBinPath, mockFs } = t.context
|
|
434
|
+
const consoleLogStub = sandbox.stub(console, 'log')
|
|
435
|
+
|
|
436
|
+
const { default: InfoCommand } = await esmock('./info.js', {
|
|
437
|
+
'#helpers/test-cwd.js': {
|
|
438
|
+
default: mockTestcwd
|
|
439
|
+
},
|
|
440
|
+
'#src/packageConfig.js': {
|
|
441
|
+
binPath: mockBinPath
|
|
442
|
+
},
|
|
443
|
+
'node:fs': mockFs
|
|
444
|
+
}, {
|
|
445
|
+
'#lib/logger/index.js': {
|
|
446
|
+
default: () => mockLogger
|
|
447
|
+
}
|
|
448
|
+
})
|
|
449
|
+
|
|
450
|
+
const command = new InfoCommand()
|
|
451
|
+
command.config = mockConfig
|
|
452
|
+
command.logger = mockLogger
|
|
453
|
+
command.debug = sandbox.stub()
|
|
454
|
+
|
|
455
|
+
await command.action({ json: true }, {})
|
|
456
|
+
|
|
457
|
+
// Should output via console.log, not logger.info
|
|
458
|
+
t.true(consoleLogStub.calledOnce, 'console.log should be called once')
|
|
459
|
+
t.false(mockLogger.info.called, 'logger.info should not be called in JSON mode')
|
|
460
|
+
|
|
461
|
+
// Parse and validate the JSON structure
|
|
462
|
+
const output = JSON.parse(consoleLogStub.firstCall.args[0])
|
|
463
|
+
|
|
464
|
+
t.truthy(output.project, 'JSON should have project section')
|
|
465
|
+
|
|
466
|
+
// Project section
|
|
467
|
+
t.is(output.project.cli, '1.0.0-rc.33')
|
|
468
|
+
t.is(output.project.quire11ty, '1.0.0')
|
|
469
|
+
t.is(output.project.starter, 'https://github.com/thegetty/quire-starter-default')
|
|
470
|
+
t.is(typeof output.project.directory, 'string')
|
|
471
|
+
})
|
|
472
|
+
|
|
473
|
+
test.serial('info --json should set starter to null when not available', async (t) => {
|
|
474
|
+
const { sandbox, mockLogger, mockConfig, mockTestcwd, mockBinPath, mockFs } = t.context
|
|
475
|
+
const consoleLogStub = sandbox.stub(console, 'log')
|
|
476
|
+
|
|
477
|
+
// Version file without starter
|
|
478
|
+
t.context.mockFs.readFileSync.callsFake((filePath, options) => {
|
|
479
|
+
if (filePath === './.quire-version') {
|
|
480
|
+
return JSON.stringify({ cli: '1.0.0-rc.33' })
|
|
481
|
+
}
|
|
482
|
+
if (filePath === './package.json') {
|
|
483
|
+
return t.context.packageJsonContent
|
|
484
|
+
}
|
|
485
|
+
return ''
|
|
486
|
+
})
|
|
487
|
+
|
|
488
|
+
const { default: InfoCommand } = await esmock('./info.js', {
|
|
489
|
+
'#helpers/test-cwd.js': {
|
|
490
|
+
default: mockTestcwd
|
|
491
|
+
},
|
|
492
|
+
'#src/packageConfig.js': {
|
|
493
|
+
binPath: mockBinPath
|
|
494
|
+
},
|
|
495
|
+
'node:fs': mockFs
|
|
496
|
+
}, {
|
|
497
|
+
'#lib/logger/index.js': {
|
|
498
|
+
default: () => mockLogger
|
|
499
|
+
}
|
|
500
|
+
})
|
|
501
|
+
|
|
502
|
+
const command = new InfoCommand()
|
|
503
|
+
command.config = mockConfig
|
|
504
|
+
command.logger = mockLogger
|
|
505
|
+
command.debug = sandbox.stub()
|
|
506
|
+
|
|
507
|
+
await command.action({ json: true }, {})
|
|
508
|
+
|
|
509
|
+
const output = JSON.parse(consoleLogStub.firstCall.args[0])
|
|
510
|
+
|
|
511
|
+
t.is(output.project.starter, null, 'starter should be null when not in version file')
|
|
415
512
|
})
|
package/src/commands/pdf.js
CHANGED
|
@@ -5,6 +5,7 @@ import eleventy from '#lib/11ty/index.js'
|
|
|
5
5
|
import generatePdf, { ENGINES } from '#lib/pdf/index.js'
|
|
6
6
|
import open from 'open'
|
|
7
7
|
import path from 'node:path'
|
|
8
|
+
import { recordStatus } from '#lib/conf/build-status.js'
|
|
8
9
|
import reporter from '#lib/reporter/index.js'
|
|
9
10
|
import testcwd from '#helpers/test-cwd.js'
|
|
10
11
|
import { MissingBuildOutputError } from '#src/errors/index.js'
|
|
@@ -81,10 +82,16 @@ Examples:
|
|
|
81
82
|
|
|
82
83
|
// Generate PDF - façade handles validation, progress, and errors
|
|
83
84
|
const pdfOptions = { ...options, lib: options.engine }
|
|
84
|
-
const output = await generatePdf(pdfOptions)
|
|
85
85
|
|
|
86
|
-
|
|
87
|
-
|
|
86
|
+
try {
|
|
87
|
+
const output = await generatePdf(pdfOptions)
|
|
88
|
+
recordStatus(paths.getProjectRoot(), 'pdf', 'ok')
|
|
89
|
+
if (options.open) {
|
|
90
|
+
open(output)
|
|
91
|
+
}
|
|
92
|
+
} catch (error) {
|
|
93
|
+
recordStatus(paths.getProjectRoot(), 'pdf', 'failed')
|
|
94
|
+
throw error
|
|
88
95
|
}
|
|
89
96
|
}
|
|
90
97
|
|