@thegetty/quire-cli 1.0.0-rc.44 → 1.0.0-rc.46

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (243) hide show
  1. package/CHANGELOG.md +0 -36
  2. package/README.md +0 -9
  3. package/bin/cli.js +1 -46
  4. package/package.json +9 -25
  5. package/src/Command.js +6 -26
  6. package/src/commands/README.md +122 -213
  7. package/src/commands/build.js +37 -45
  8. package/src/commands/clean.js +19 -33
  9. package/src/commands/conf.js +43 -0
  10. package/src/commands/create.js +14 -42
  11. package/src/commands/epub.js +31 -67
  12. package/src/commands/index.js +2 -9
  13. package/src/commands/info.js +86 -88
  14. package/src/commands/pdf.js +82 -63
  15. package/src/commands/preview.js +31 -32
  16. package/src/commands/validate.js +20 -64
  17. package/src/commands/version.js +43 -0
  18. package/src/errors/validation/validation-error.js +11 -20
  19. package/src/helpers/clean.js +1 -1
  20. package/src/helpers/is-quire.js +31 -0
  21. package/src/helpers/test-cwd.js +6 -5
  22. package/src/helpers/which.js +4 -10
  23. package/src/lib/11ty/README.md +19 -135
  24. package/src/lib/11ty/api.js +93 -235
  25. package/src/lib/11ty/cli.js +37 -112
  26. package/src/lib/11ty/index.js +5 -64
  27. package/src/lib/11ty/paths.js +103 -0
  28. package/src/lib/README.md +0 -330
  29. package/src/lib/conf/README.md +69 -86
  30. package/src/lib/conf/config.js +3 -5
  31. package/src/lib/conf/defaults.js +0 -65
  32. package/src/lib/conf/schema.js +9 -103
  33. package/src/lib/epub/README.md +2 -133
  34. package/src/lib/epub/epub.js +11 -36
  35. package/src/lib/epub/index.js +21 -111
  36. package/src/lib/epub/pandoc.js +4 -33
  37. package/src/lib/git/README.md +2 -151
  38. package/src/lib/git/index.js +13 -217
  39. package/src/lib/i18n/README.md +3 -0
  40. package/src/lib/i18n/config.js +53 -0
  41. package/src/lib/i18n/index.js +43 -0
  42. package/src/lib/i18n/localeService.js +58 -0
  43. package/src/lib/pdf/README.md +0 -131
  44. package/src/lib/pdf/index.js +21 -124
  45. package/src/lib/pdf/paged.js +52 -100
  46. package/src/lib/pdf/prince.js +37 -115
  47. package/src/lib/pdf/split.js +33 -61
  48. package/src/lib/quire/README.md +19 -0
  49. package/src/lib/quire/index.js +353 -0
  50. package/src/lib/reporter/README.md +2 -211
  51. package/src/lib/reporter/index.js +0 -607
  52. package/src/main.js +48 -221
  53. package/src/packageConfig.js +0 -17
  54. package/src/validators/utils.js +1 -2
  55. package/schemas/config.schema.json +0 -194
  56. package/schemas/figures.schema.json +0 -56
  57. package/schemas/layout.schema.json +0 -5
  58. package/schemas/objects.schema.json +0 -62
  59. package/schemas/publication.schema.json +0 -140
  60. package/schemas/references.schema.json +0 -29
  61. package/src/Command.spec.js +0 -99
  62. package/src/commands/build.spec.js +0 -113
  63. package/src/commands/build.test.js +0 -397
  64. package/src/commands/clean.spec.js +0 -118
  65. package/src/commands/clean.test.js +0 -382
  66. package/src/commands/config.js +0 -238
  67. package/src/commands/config.spec.js +0 -107
  68. package/src/commands/config.test.js +0 -845
  69. package/src/commands/create.spec.js +0 -112
  70. package/src/commands/create.test.js +0 -415
  71. package/src/commands/doctor.js +0 -251
  72. package/src/commands/doctor.spec.js +0 -115
  73. package/src/commands/doctor.test.js +0 -1409
  74. package/src/commands/epub.spec.js +0 -114
  75. package/src/commands/epub.test.js +0 -503
  76. package/src/commands/help.js +0 -60
  77. package/src/commands/help.test.js +0 -132
  78. package/src/commands/info.spec.js +0 -72
  79. package/src/commands/info.test.js +0 -512
  80. package/src/commands/pdf.spec.js +0 -114
  81. package/src/commands/pdf.test.js +0 -464
  82. package/src/commands/preview.spec.js +0 -97
  83. package/src/commands/preview.test.js +0 -250
  84. package/src/commands/use.js +0 -56
  85. package/src/commands/use.spec.js +0 -61
  86. package/src/commands/use.test.js +0 -280
  87. package/src/commands/validate.spec.js +0 -90
  88. package/src/commands/validate.test.js +0 -378
  89. package/src/commands/workflows.js +0 -70
  90. package/src/errors/build/build-failed-error.js +0 -19
  91. package/src/errors/build/config-field-missing-error.js +0 -20
  92. package/src/errors/build/config-file-not-found-error.js +0 -20
  93. package/src/errors/build/index.js +0 -11
  94. package/src/errors/help/help-topic-not-found-error.js +0 -30
  95. package/src/errors/help/index.js +0 -8
  96. package/src/errors/index.js +0 -58
  97. package/src/errors/input/index.js +0 -8
  98. package/src/errors/input/invalid-input-error.js +0 -21
  99. package/src/errors/install/dependency-install-error.js +0 -19
  100. package/src/errors/install/directory-not-empty-error.js +0 -25
  101. package/src/errors/install/index.js +0 -12
  102. package/src/errors/install/invalid-path-error.js +0 -31
  103. package/src/errors/install/invalid-starter-error.js +0 -27
  104. package/src/errors/install/version-not-found-error.js +0 -35
  105. package/src/errors/output/epub-generation-error.js +0 -19
  106. package/src/errors/output/index.js +0 -14
  107. package/src/errors/output/invalid-epub-library-error.js +0 -20
  108. package/src/errors/output/invalid-pdf-library-error.js +0 -20
  109. package/src/errors/output/missing-build-output-error.js +0 -21
  110. package/src/errors/output/pdf-generation-error.js +0 -24
  111. package/src/errors/output/tool-not-found-error.js +0 -37
  112. package/src/errors/project/index.js +0 -10
  113. package/src/errors/project/not-in-project-error.js +0 -20
  114. package/src/errors/project/project-create-error.js +0 -21
  115. package/src/errors/quire-error.js +0 -27
  116. package/src/errors/validation/index.js +0 -3
  117. package/src/errors/validation/unknown-config-key-error.js +0 -27
  118. package/src/errors/validation/unknown-config-operation-error.js +0 -24
  119. package/src/helpers/docs-url.js +0 -32
  120. package/src/helpers/pager.js +0 -59
  121. package/src/helpers/pager.test.js +0 -85
  122. package/src/helpers/suggest-similar.js +0 -124
  123. package/src/helpers/suggest-similar.test.js +0 -108
  124. package/src/helpers/test-cwd.test.js +0 -192
  125. package/src/lib/11ty/index.test.js +0 -655
  126. package/src/lib/commander/index.js +0 -103
  127. package/src/lib/commander/index.test.js +0 -86
  128. package/src/lib/commander/options.js +0 -237
  129. package/src/lib/commander/options.test.js +0 -205
  130. package/src/lib/conf/build-status.js +0 -103
  131. package/src/lib/conf/build-status.test.js +0 -247
  132. package/src/lib/conf/config.test.js +0 -281
  133. package/src/lib/conf/format.js +0 -60
  134. package/src/lib/conf/format.test.js +0 -106
  135. package/src/lib/conf/helpers.js +0 -91
  136. package/src/lib/conf/helpers.test.js +0 -136
  137. package/src/lib/conf/index.js +0 -22
  138. package/src/lib/constants.js +0 -28
  139. package/src/lib/doctor/README.md +0 -667
  140. package/src/lib/doctor/checks/environment/cli-version.js +0 -62
  141. package/src/lib/doctor/checks/environment/cli-version.test.js +0 -132
  142. package/src/lib/doctor/checks/environment/git-available.js +0 -77
  143. package/src/lib/doctor/checks/environment/git-available.test.js +0 -52
  144. package/src/lib/doctor/checks/environment/index.js +0 -13
  145. package/src/lib/doctor/checks/environment/node-version.js +0 -66
  146. package/src/lib/doctor/checks/environment/node-version.test.js +0 -17
  147. package/src/lib/doctor/checks/environment/npm-available.js +0 -66
  148. package/src/lib/doctor/checks/environment/npm-available.test.js +0 -52
  149. package/src/lib/doctor/checks/environment/os-info.js +0 -48
  150. package/src/lib/doctor/checks/environment/os-info.test.js +0 -81
  151. package/src/lib/doctor/checks/environment/runtime-info.js +0 -51
  152. package/src/lib/doctor/checks/environment/runtime-info.test.js +0 -132
  153. package/src/lib/doctor/checks/outputs/epub-output.js +0 -119
  154. package/src/lib/doctor/checks/outputs/epub-output.test.js +0 -277
  155. package/src/lib/doctor/checks/outputs/index.js +0 -10
  156. package/src/lib/doctor/checks/outputs/pdf-output.js +0 -144
  157. package/src/lib/doctor/checks/outputs/pdf-output.test.js +0 -377
  158. package/src/lib/doctor/checks/outputs/stale-build.js +0 -122
  159. package/src/lib/doctor/checks/outputs/stale-build.test.js +0 -282
  160. package/src/lib/doctor/checks/project/data-files.js +0 -56
  161. package/src/lib/doctor/checks/project/data-files.test.js +0 -125
  162. package/src/lib/doctor/checks/project/dependencies.js +0 -53
  163. package/src/lib/doctor/checks/project/dependencies.test.js +0 -71
  164. package/src/lib/doctor/checks/project/index.js +0 -11
  165. package/src/lib/doctor/checks/project/quire-11ty.js +0 -98
  166. package/src/lib/doctor/checks/project/quire-11ty.test.js +0 -170
  167. package/src/lib/doctor/checks/project/quire-project.js +0 -38
  168. package/src/lib/doctor/checks/project/quire-project.test.js +0 -47
  169. package/src/lib/doctor/checks/tools/index.js +0 -10
  170. package/src/lib/doctor/checks/tools/pandoc-available.js +0 -82
  171. package/src/lib/doctor/checks/tools/pandoc-available.test.js +0 -73
  172. package/src/lib/doctor/checks/tools/prince-available.js +0 -81
  173. package/src/lib/doctor/checks/tools/prince-available.test.js +0 -73
  174. package/src/lib/doctor/constants.js +0 -39
  175. package/src/lib/doctor/formatDuration.js +0 -108
  176. package/src/lib/doctor/formatDuration.test.js +0 -76
  177. package/src/lib/doctor/formatters/human.js +0 -257
  178. package/src/lib/doctor/formatters/human.test.js +0 -463
  179. package/src/lib/doctor/formatters/index.js +0 -8
  180. package/src/lib/doctor/formatters/json.js +0 -78
  181. package/src/lib/doctor/formatters/json.test.js +0 -174
  182. package/src/lib/doctor/formatters/shared.js +0 -129
  183. package/src/lib/doctor/formatters/shared.test.js +0 -194
  184. package/src/lib/doctor/index.js +0 -271
  185. package/src/lib/doctor/index.test.js +0 -797
  186. package/src/lib/epub/engines.js +0 -46
  187. package/src/lib/epub/index.test.js +0 -518
  188. package/src/lib/epub/pandoc.test.js +0 -122
  189. package/src/lib/epub/schema.js +0 -21
  190. package/src/lib/error/README.md +0 -170
  191. package/src/lib/error/handler.js +0 -107
  192. package/src/lib/git/index.spec.js +0 -80
  193. package/src/lib/git/index.test.js +0 -453
  194. package/src/lib/help/frontmatter.js +0 -77
  195. package/src/lib/help/frontmatter.test.js +0 -139
  196. package/src/lib/help/index.js +0 -146
  197. package/src/lib/help/index.test.js +0 -188
  198. package/src/lib/help/topics/configuration.md +0 -77
  199. package/src/lib/help/topics/debugging.md +0 -69
  200. package/src/lib/help/topics/epub.md +0 -74
  201. package/src/lib/help/topics/pdf.md +0 -74
  202. package/src/lib/help/topics/publishing.md +0 -80
  203. package/src/lib/help/topics/workflows.md +0 -50
  204. package/src/lib/installer/index.js +0 -309
  205. package/src/lib/installer/index.spec.js +0 -83
  206. package/src/lib/installer/index.test.js +0 -545
  207. package/src/lib/logger/README.md +0 -424
  208. package/src/lib/logger/debug.js +0 -132
  209. package/src/lib/logger/debug.spec.js +0 -130
  210. package/src/lib/logger/debug.test.js +0 -128
  211. package/src/lib/logger/index.js +0 -228
  212. package/src/lib/logger/index.spec.js +0 -131
  213. package/src/lib/logger/index.test.js +0 -578
  214. package/src/lib/npm/README.md +0 -127
  215. package/src/lib/npm/index.js +0 -198
  216. package/src/lib/npm/index.spec.js +0 -60
  217. package/src/lib/npm/index.test.js +0 -355
  218. package/src/lib/pdf/engines.js +0 -46
  219. package/src/lib/pdf/index.test.js +0 -708
  220. package/src/lib/pdf/paged.test.js +0 -366
  221. package/src/lib/pdf/prince.test.js +0 -202
  222. package/src/lib/pdf/schema.js +0 -21
  223. package/src/lib/pdf/split.test.js +0 -445
  224. package/src/lib/platform.js +0 -95
  225. package/src/lib/process/manager.js +0 -110
  226. package/src/lib/process/manager.test.js +0 -55
  227. package/src/lib/project/build.js +0 -162
  228. package/src/lib/project/build.test.js +0 -275
  229. package/src/lib/project/config.js +0 -48
  230. package/src/lib/project/config.test.js +0 -134
  231. package/src/lib/project/detect.js +0 -47
  232. package/src/lib/project/detect.test.js +0 -157
  233. package/src/lib/project/index.js +0 -56
  234. package/src/lib/project/output-paths.js +0 -87
  235. package/src/lib/project/output-paths.test.js +0 -66
  236. package/src/lib/project/paths.js +0 -272
  237. package/src/lib/project/version.js +0 -110
  238. package/src/lib/project/version.test.js +0 -350
  239. package/src/lib/reporter/index.test.js +0 -862
  240. package/src/main.spec.js +0 -61
  241. package/src/main.test.js +0 -347
  242. package/src/validators/validate-data-files.js +0 -154
  243. package/src/validators/validate-data-files.test.js +0 -217
@@ -1,512 +0,0 @@
1
- import test from 'ava'
2
- import sinon from 'sinon'
3
- import esmock from 'esmock'
4
-
5
- test.beforeEach((t) => {
6
- // Create sinon sandbox for mocking
7
- t.context.sandbox = sinon.createSandbox()
8
-
9
- // Create mock logger
10
- t.context.mockLogger = {
11
- info: t.context.sandbox.stub(),
12
- error: t.context.sandbox.stub(),
13
- debug: t.context.sandbox.stub(),
14
- log: t.context.sandbox.stub(),
15
- warn: t.context.sandbox.stub()
16
- }
17
-
18
- // Mock config
19
- t.context.mockConfig = {
20
- get: t.context.sandbox.stub().returns('./.quire-version')
21
- }
22
-
23
- // Mock testcwd helper
24
- t.context.mockTestcwd = t.context.sandbox.stub()
25
-
26
- // Mock packageConfig binPath
27
- t.context.mockBinPath = t.context.sandbox.stub().returns('/usr/local/bin/quire')
28
-
29
- // Mock fs module
30
- t.context.mockFs = {
31
- readFileSync: t.context.sandbox.stub(),
32
- writeFileSync: t.context.sandbox.stub(),
33
- existsSync: t.context.sandbox.stub().returns(true)
34
- }
35
-
36
- // Default version file content
37
- t.context.versionFileContent = JSON.stringify({
38
- cli: '1.0.0-rc.33',
39
- starter: 'https://github.com/thegetty/quire-starter-default'
40
- })
41
-
42
- // Default package.json content
43
- t.context.packageJsonContent = JSON.stringify({
44
- name: 'test-project',
45
- version: '1.0.0'
46
- })
47
-
48
- // Setup default readFileSync behavior - stub returns different content based on file path
49
- t.context.mockFs.readFileSync.callsFake((filePath, options) => {
50
- if (filePath === './.quire-version') {
51
- return t.context.versionFileContent
52
- }
53
- if (filePath === './package.json') {
54
- return t.context.packageJsonContent
55
- }
56
- // For any other file, return empty string
57
- return ''
58
- })
59
- })
60
-
61
- test.afterEach.always((t) => {
62
- // Restore all mocks
63
- t.context.sandbox.restore()
64
- })
65
-
66
- test('info command should validate Quire project in preAction', async (t) => {
67
- const { sandbox, mockLogger, mockTestcwd, mockConfig, mockBinPath, mockFs } = t.context
68
-
69
- const { default: InfoCommand } = await esmock('./info.js', {
70
- '#helpers/test-cwd.js': {
71
- default: mockTestcwd
72
- },
73
- '#src/packageConfig.js': {
74
- binPath: mockBinPath
75
- },
76
- 'node:fs': mockFs
77
- }, {
78
- '#lib/logger/index.js': {
79
- default: () => mockLogger
80
- }
81
- })
82
-
83
- const command = new InfoCommand()
84
- command.config = mockConfig
85
- command.logger = mockLogger
86
- command.debug = sandbox.stub()
87
-
88
- // Mock Commander.js command object
89
- const mockCommand = {
90
- name: () => 'info',
91
- opts: () => ({})
92
- }
93
-
94
- // Call preAction
95
- command.preAction(mockCommand)
96
-
97
- t.true(mockTestcwd.called, 'testcwd should be called in preAction')
98
- t.true(mockTestcwd.calledWith(mockCommand), 'testcwd should be called with command')
99
- })
100
-
101
- test('info command should display project version information', async (t) => {
102
- const { sandbox, mockLogger, mockConfig, mockTestcwd, mockBinPath, mockFs } = t.context
103
-
104
- const { default: InfoCommand } = await esmock('./info.js', {
105
- '#helpers/test-cwd.js': {
106
- default: mockTestcwd
107
- },
108
- '#src/packageConfig.js': {
109
- binPath: mockBinPath
110
- },
111
- 'node:fs': mockFs
112
- }, {
113
- '#lib/logger/index.js': {
114
- default: () => mockLogger
115
- }
116
- })
117
-
118
- const command = new InfoCommand()
119
- command.config = mockConfig
120
- command.logger = mockLogger
121
- command.debug = sandbox.stub()
122
-
123
- await command.action({}, {})
124
-
125
- // Verify logger.info was called with project information
126
- t.true(mockLogger.info.called, 'logger.info should be called')
127
-
128
- // Check for project header
129
- const calls = mockLogger.info.getCalls()
130
- const hasProjectInfo = calls.some((call) =>
131
- call.args[0] && call.args[0].includes('Project:')
132
- )
133
- t.true(hasProjectInfo, 'should display project header')
134
-
135
- // Check for quire-cli version in output
136
- const hasCliVersion = calls.some((call) =>
137
- call.args[0] && call.args[0].includes('quire-cli') && call.args[0].includes('1.0.0-rc.33')
138
- )
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')
152
- })
153
-
154
- test('info command should display starter version when available', async (t) => {
155
- const { sandbox, mockLogger, mockConfig, mockTestcwd, mockBinPath, mockFs } = t.context
156
-
157
- const { default: InfoCommand } = await esmock('./info.js', {
158
- '#helpers/test-cwd.js': {
159
- default: mockTestcwd
160
- },
161
- '#src/packageConfig.js': {
162
- binPath: mockBinPath
163
- },
164
- 'node:fs': mockFs
165
- }, {
166
- '#lib/logger/index.js': {
167
- default: () => mockLogger
168
- }
169
- })
170
-
171
- const command = new InfoCommand()
172
- command.config = mockConfig
173
- command.logger = mockLogger
174
- command.debug = sandbox.stub()
175
-
176
- await command.action({}, {})
177
-
178
- // Verify logger.info was called
179
- t.true(mockLogger.info.called, 'logger.info should be called')
180
-
181
- // Check for starter version in output (from version file)
182
- const calls = mockLogger.info.getCalls()
183
- const hasStarterVersion = calls.some((call) =>
184
- call.args[0] && call.args[0].includes('starter')
185
- )
186
- t.true(hasStarterVersion, 'should display starter version when available')
187
- })
188
-
189
- test('info command --debug shows installation paths', async (t) => {
190
- const { sandbox, mockLogger, mockConfig, mockTestcwd, mockBinPath, mockFs } = t.context
191
-
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')
218
- })
219
-
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)
225
-
226
- const { default: InfoCommand } = await esmock('./info.js', {
227
- '#helpers/test-cwd.js': {
228
- default: mockTestcwd
229
- },
230
- '#src/packageConfig.js': {
231
- binPath: mockBinPathNotFound
232
- },
233
- 'node:fs': mockFs
234
- }, {
235
- '#lib/logger/index.js': {
236
- default: () => mockLogger
237
- }
238
- })
239
-
240
- const command = new InfoCommand()
241
- command.config = mockConfig
242
- command.logger = mockLogger
243
- command.debug = sandbox.stub()
244
-
245
- await command.action({ debug: true }, {})
246
-
247
- const calls = mockLogger.info.getCalls()
248
- const output = calls.map((call) => call.args[0]).join('\n')
249
-
250
- t.true(output.includes('not found in PATH'), 'should show not found message for quire-cli')
251
- })
252
-
253
- test('info command should handle missing version file', async (t) => {
254
- const { sandbox, mockLogger, mockConfig, mockTestcwd, mockBinPath, mockFs } = t.context
255
-
256
- // Setup mockFs to throw error for missing version file (simulating file not found)
257
- mockFs.readFileSync.callsFake((filePath, options) => {
258
- if (filePath === './.quire-version') {
259
- throw new Error('ENOENT: no such file')
260
- }
261
- if (filePath === './package.json') {
262
- return t.context.packageJsonContent
263
- }
264
- return ''
265
- })
266
-
267
- const { default: InfoCommand } = await esmock('./info.js', {
268
- '#helpers/test-cwd.js': {
269
- default: mockTestcwd
270
- },
271
- '#src/packageConfig.js': {
272
- binPath: mockBinPath
273
- },
274
- 'node:fs': mockFs
275
- }, {
276
- '#lib/logger/index.js': {
277
- default: () => mockLogger
278
- }
279
- })
280
-
281
- const command = new InfoCommand()
282
- command.config = mockConfig
283
- command.logger = mockLogger
284
- command.debug = sandbox.stub()
285
-
286
- await command.action({}, {})
287
-
288
- // Verify warning was logged about old version
289
- t.true(mockLogger.warn.called, 'logger.warn should be called for missing version file')
290
- t.true(
291
- mockLogger.warn.calledWith(sinon.match(/prior to version 1.0.0.rc-8/)),
292
- 'should warn about old project version'
293
- )
294
-
295
- // Verify version file was created
296
- t.true(mockFs.writeFileSync.called, 'writeFileSync should be called to create version file')
297
- })
298
-
299
- test('info command should handle malformed version file', async (t) => {
300
- const { sandbox, mockLogger, mockConfig, mockTestcwd, mockBinPath, mockFs } = t.context
301
-
302
- // Setup mockFs to return malformed JSON (simulating corrupted file)
303
- mockFs.readFileSync.callsFake((filePath, options) => {
304
- if (filePath === './.quire-version') {
305
- return 'invalid json{'
306
- }
307
- if (filePath === './package.json') {
308
- return t.context.packageJsonContent
309
- }
310
- return ''
311
- })
312
-
313
- const { default: InfoCommand } = await esmock('./info.js', {
314
- '#helpers/test-cwd.js': {
315
- default: mockTestcwd
316
- },
317
- '#src/packageConfig.js': {
318
- binPath: mockBinPath
319
- },
320
- 'node:fs': mockFs
321
- }, {
322
- '#lib/logger/index.js': {
323
- default: () => mockLogger
324
- }
325
- })
326
-
327
- const command = new InfoCommand()
328
- command.config = mockConfig
329
- command.logger = mockLogger
330
- command.debug = sandbox.stub()
331
-
332
- await command.action({}, {})
333
-
334
- // Verify warning was logged
335
- t.true(mockLogger.warn.called, 'logger.warn should be called for malformed version file')
336
-
337
- // Verify version file was overwritten with valid JSON
338
- t.true(mockFs.writeFileSync.called, 'writeFileSync should be called to fix malformed version file')
339
-
340
- // Check that the content written is valid JSON
341
- const writeCall = mockFs.writeFileSync.getCall(0)
342
- if (writeCall) {
343
- const writtenContent = writeCall.args[1]
344
- t.notThrows(() => JSON.parse(writtenContent), 'written content should be valid JSON')
345
- }
346
- })
347
-
348
- test('info command should read quire-11ty version from package.json', async (t) => {
349
- const { sandbox, mockLogger, mockConfig, mockTestcwd, mockBinPath, mockFs } = t.context
350
-
351
- // Override package.json to have specific version
352
- mockFs.readFileSync.callsFake((filePath, options) => {
353
- if (filePath === './.quire-version') {
354
- return t.context.versionFileContent
355
- }
356
- if (filePath === './package.json') {
357
- return JSON.stringify({
358
- name: 'test-project',
359
- version: '2.5.3'
360
- })
361
- }
362
- return ''
363
- })
364
-
365
- const { default: InfoCommand } = await esmock('./info.js', {
366
- '#helpers/test-cwd.js': {
367
- default: mockTestcwd
368
- },
369
- '#src/packageConfig.js': {
370
- binPath: mockBinPath
371
- },
372
- 'node:fs': mockFs
373
- }, {
374
- '#lib/logger/index.js': {
375
- default: () => mockLogger
376
- }
377
- })
378
-
379
- const command = new InfoCommand()
380
- command.config = mockConfig
381
- command.logger = mockLogger
382
- command.debug = sandbox.stub()
383
-
384
- await command.action({}, {})
385
-
386
- // Verify logger.info was called
387
- t.true(mockLogger.info.called, 'logger.info should be called')
388
-
389
- // Check for quire-11ty version from package.json
390
- const calls = mockLogger.info.getCalls()
391
- const hasEleventyVersion = calls.some((call) =>
392
- call.args[0] && call.args[0].includes('quire-11ty') && call.args[0].includes('2.5.3')
393
- )
394
- t.true(hasEleventyVersion, 'should display quire-11ty version from package.json')
395
- })
396
-
397
- test('info command should log debug information', async (t) => {
398
- const { sandbox, mockLogger, mockConfig, mockTestcwd, mockBinPath, mockFs } = t.context
399
-
400
- const mockDebug = sandbox.stub()
401
-
402
- const { default: InfoCommand } = await esmock('./info.js', {
403
- '#helpers/test-cwd.js': {
404
- default: mockTestcwd
405
- },
406
- '#src/packageConfig.js': {
407
- binPath: mockBinPath
408
- },
409
- 'node:fs': mockFs
410
- }, {
411
- '#lib/logger/index.js': {
412
- default: () => mockLogger
413
- }
414
- })
415
-
416
- const command = new InfoCommand()
417
- command.config = mockConfig
418
- command.logger = mockLogger
419
- command.debug = mockDebug
420
-
421
- await command.action({}, {})
422
-
423
- // Verify debug was called
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')
512
- })
@@ -1,114 +0,0 @@
1
- import { Command, Option } from 'commander'
2
- import program from '#src/main.js'
3
- import test from 'ava'
4
-
5
- /**
6
- * Command Contract/Interface Tests
7
- *
8
- * Verifies the command's public API and Commander.js integration.
9
- * @see docs/testing-commands.md
10
- */
11
-
12
- test.before((t) => {
13
- // Get the registered command (from program.commands) once and share across all tests
14
- t.context.command = program.commands.find((cmd) => cmd.name() === 'pdf')
15
- })
16
-
17
- test('command is registered in CLI program', (t) => {
18
- const { command } = t.context
19
-
20
- t.truthy(command, 'command "pdf" should be registered in program')
21
- t.true(command instanceof Command, 'registered command should be Commander.js Command instance')
22
- })
23
-
24
- test('registered command has correct metadata', (t) => {
25
- const { command } = t.context
26
-
27
- t.is(command.name(), 'pdf')
28
- t.truthy(command.description())
29
- t.is(typeof command._actionHandler, 'function', 'command should have action handler')
30
- })
31
-
32
- test('registered command has no arguments', (t) => {
33
- const { command } = t.context
34
- const registeredArguments = command.registeredArguments
35
-
36
- t.is(registeredArguments.length, 0, 'pdf command should have no arguments')
37
- })
38
-
39
- test('registered command has correct options', (t) => {
40
- const { command } = t.context
41
-
42
- // Get all options
43
- const engineOption = command.options.find((opt) => opt.long === '--engine')
44
- const libOption = command.options.find((opt) => opt.long === '--lib')
45
- const buildOption = command.options.find((opt) => opt.long === '--build')
46
- const openOption = command.options.find((opt) => opt.long === '--open')
47
- const quietOption = command.options.find((opt) => opt.long === '--quiet')
48
- const verboseOption = command.options.find((opt) => opt.long === '--verbose')
49
- const debugOption = command.options.find((opt) => opt.long === '--debug')
50
-
51
- // Verify all options exist
52
- t.truthy(engineOption, '--engine option should exist')
53
- t.truthy(libOption, '--lib option should exist (deprecated alias)')
54
- t.truthy(buildOption, '--build option should exist')
55
- t.truthy(openOption, '--open option should exist')
56
- t.truthy(quietOption, '--quiet option should exist')
57
- t.truthy(verboseOption, '--verbose option should exist')
58
- t.truthy(debugOption, '--debug option should exist')
59
-
60
- // Verify they are Option instances
61
- t.true(engineOption instanceof Option, '--engine should be Option instance')
62
- t.true(libOption instanceof Option, '--lib should be Option instance')
63
- t.true(buildOption instanceof Option, '--build should be Option instance')
64
- t.true(openOption instanceof Option, '--open should be Option instance')
65
- t.true(quietOption instanceof Option, '--quiet should be Option instance')
66
- t.true(verboseOption instanceof Option, '--verbose should be Option instance')
67
- t.true(debugOption instanceof Option, '--debug should be Option instance')
68
-
69
- // Verify --engine option properties
70
- t.is(engineOption.long, '--engine')
71
- t.truthy(engineOption.description)
72
- t.true(engineOption.required, '--engine should require a value')
73
-
74
- // Verify --lib is hidden (deprecated alias)
75
- t.is(libOption.long, '--lib')
76
- t.true(libOption.hidden, '--lib should be hidden (deprecated)')
77
-
78
- t.is(buildOption.long, '--build')
79
- t.truthy(buildOption.description)
80
- t.false(buildOption.required, '--build should not require a value')
81
-
82
- t.is(openOption.long, '--open')
83
- t.truthy(openOption.description)
84
- t.false(openOption.required, '--open should not require a value')
85
-
86
- t.is(quietOption.long, '--quiet')
87
- t.is(quietOption.short, '-q', '--quiet should have -q short flag')
88
- t.truthy(quietOption.description)
89
- t.false(quietOption.required, '--quiet should not require a value')
90
-
91
- t.is(verboseOption.long, '--verbose')
92
- t.is(verboseOption.short, '-v', '--verbose should have -v short flag')
93
- t.truthy(verboseOption.description)
94
- t.false(verboseOption.required, '--verbose should not require a value')
95
-
96
- t.is(debugOption.long, '--debug')
97
- t.truthy(debugOption.description)
98
- t.false(debugOption.required, '--debug should not require a value')
99
- })
100
-
101
- test('command options are accessible via public API', (t) => {
102
- const { command } = t.context
103
-
104
- // Test that options can be accessed the way Commander.js does
105
- const optionNames = command.options.map((opt) => opt.long)
106
-
107
- t.true(optionNames.includes('--engine'))
108
- t.true(optionNames.includes('--lib')) // deprecated alias still exists
109
- t.true(optionNames.includes('--build'))
110
- t.true(optionNames.includes('--open'))
111
- t.true(optionNames.includes('--quiet'))
112
- t.true(optionNames.includes('--verbose'))
113
- t.true(optionNames.includes('--debug'))
114
- })