@thegetty/quire-cli 1.0.0-rc.45 → 1.0.0-rc.47

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (245) 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 +10 -27
  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/man/quire.1 +0 -341
  56. package/man/quire.1.md +0 -232
  57. package/schemas/config.schema.json +0 -194
  58. package/schemas/figures.schema.json +0 -56
  59. package/schemas/layout.schema.json +0 -5
  60. package/schemas/objects.schema.json +0 -62
  61. package/schemas/publication.schema.json +0 -140
  62. package/schemas/references.schema.json +0 -29
  63. package/src/Command.spec.js +0 -99
  64. package/src/commands/build.spec.js +0 -113
  65. package/src/commands/build.test.js +0 -397
  66. package/src/commands/clean.spec.js +0 -118
  67. package/src/commands/clean.test.js +0 -382
  68. package/src/commands/config.js +0 -238
  69. package/src/commands/config.spec.js +0 -107
  70. package/src/commands/config.test.js +0 -845
  71. package/src/commands/create.spec.js +0 -112
  72. package/src/commands/create.test.js +0 -415
  73. package/src/commands/doctor.js +0 -251
  74. package/src/commands/doctor.spec.js +0 -115
  75. package/src/commands/doctor.test.js +0 -1409
  76. package/src/commands/epub.spec.js +0 -114
  77. package/src/commands/epub.test.js +0 -503
  78. package/src/commands/help.js +0 -60
  79. package/src/commands/help.test.js +0 -132
  80. package/src/commands/info.spec.js +0 -72
  81. package/src/commands/info.test.js +0 -512
  82. package/src/commands/pdf.spec.js +0 -114
  83. package/src/commands/pdf.test.js +0 -464
  84. package/src/commands/preview.spec.js +0 -97
  85. package/src/commands/preview.test.js +0 -250
  86. package/src/commands/use.js +0 -56
  87. package/src/commands/use.spec.js +0 -61
  88. package/src/commands/use.test.js +0 -280
  89. package/src/commands/validate.spec.js +0 -90
  90. package/src/commands/validate.test.js +0 -378
  91. package/src/commands/workflows.js +0 -70
  92. package/src/errors/build/build-failed-error.js +0 -19
  93. package/src/errors/build/config-field-missing-error.js +0 -20
  94. package/src/errors/build/config-file-not-found-error.js +0 -20
  95. package/src/errors/build/index.js +0 -11
  96. package/src/errors/help/help-topic-not-found-error.js +0 -30
  97. package/src/errors/help/index.js +0 -8
  98. package/src/errors/index.js +0 -58
  99. package/src/errors/input/index.js +0 -8
  100. package/src/errors/input/invalid-input-error.js +0 -21
  101. package/src/errors/install/dependency-install-error.js +0 -19
  102. package/src/errors/install/directory-not-empty-error.js +0 -25
  103. package/src/errors/install/index.js +0 -12
  104. package/src/errors/install/invalid-path-error.js +0 -31
  105. package/src/errors/install/invalid-starter-error.js +0 -27
  106. package/src/errors/install/version-not-found-error.js +0 -35
  107. package/src/errors/output/epub-generation-error.js +0 -19
  108. package/src/errors/output/index.js +0 -14
  109. package/src/errors/output/invalid-epub-library-error.js +0 -20
  110. package/src/errors/output/invalid-pdf-library-error.js +0 -20
  111. package/src/errors/output/missing-build-output-error.js +0 -21
  112. package/src/errors/output/pdf-generation-error.js +0 -24
  113. package/src/errors/output/tool-not-found-error.js +0 -37
  114. package/src/errors/project/index.js +0 -10
  115. package/src/errors/project/not-in-project-error.js +0 -20
  116. package/src/errors/project/project-create-error.js +0 -21
  117. package/src/errors/quire-error.js +0 -27
  118. package/src/errors/validation/index.js +0 -3
  119. package/src/errors/validation/unknown-config-key-error.js +0 -27
  120. package/src/errors/validation/unknown-config-operation-error.js +0 -24
  121. package/src/helpers/docs-url.js +0 -32
  122. package/src/helpers/pager.js +0 -59
  123. package/src/helpers/pager.test.js +0 -85
  124. package/src/helpers/suggest-similar.js +0 -124
  125. package/src/helpers/suggest-similar.test.js +0 -108
  126. package/src/helpers/test-cwd.test.js +0 -192
  127. package/src/lib/11ty/index.test.js +0 -655
  128. package/src/lib/commander/index.js +0 -103
  129. package/src/lib/commander/index.test.js +0 -86
  130. package/src/lib/commander/options.js +0 -237
  131. package/src/lib/commander/options.test.js +0 -205
  132. package/src/lib/conf/build-status.js +0 -103
  133. package/src/lib/conf/build-status.test.js +0 -247
  134. package/src/lib/conf/config.test.js +0 -281
  135. package/src/lib/conf/format.js +0 -60
  136. package/src/lib/conf/format.test.js +0 -106
  137. package/src/lib/conf/helpers.js +0 -91
  138. package/src/lib/conf/helpers.test.js +0 -136
  139. package/src/lib/conf/index.js +0 -22
  140. package/src/lib/constants.js +0 -28
  141. package/src/lib/doctor/README.md +0 -667
  142. package/src/lib/doctor/checks/environment/cli-version.js +0 -62
  143. package/src/lib/doctor/checks/environment/cli-version.test.js +0 -132
  144. package/src/lib/doctor/checks/environment/git-available.js +0 -77
  145. package/src/lib/doctor/checks/environment/git-available.test.js +0 -52
  146. package/src/lib/doctor/checks/environment/index.js +0 -13
  147. package/src/lib/doctor/checks/environment/node-version.js +0 -66
  148. package/src/lib/doctor/checks/environment/node-version.test.js +0 -17
  149. package/src/lib/doctor/checks/environment/npm-available.js +0 -66
  150. package/src/lib/doctor/checks/environment/npm-available.test.js +0 -52
  151. package/src/lib/doctor/checks/environment/os-info.js +0 -48
  152. package/src/lib/doctor/checks/environment/os-info.test.js +0 -81
  153. package/src/lib/doctor/checks/environment/runtime-info.js +0 -51
  154. package/src/lib/doctor/checks/environment/runtime-info.test.js +0 -132
  155. package/src/lib/doctor/checks/outputs/epub-output.js +0 -119
  156. package/src/lib/doctor/checks/outputs/epub-output.test.js +0 -277
  157. package/src/lib/doctor/checks/outputs/index.js +0 -10
  158. package/src/lib/doctor/checks/outputs/pdf-output.js +0 -144
  159. package/src/lib/doctor/checks/outputs/pdf-output.test.js +0 -377
  160. package/src/lib/doctor/checks/outputs/stale-build.js +0 -122
  161. package/src/lib/doctor/checks/outputs/stale-build.test.js +0 -282
  162. package/src/lib/doctor/checks/project/data-files.js +0 -56
  163. package/src/lib/doctor/checks/project/data-files.test.js +0 -125
  164. package/src/lib/doctor/checks/project/dependencies.js +0 -53
  165. package/src/lib/doctor/checks/project/dependencies.test.js +0 -71
  166. package/src/lib/doctor/checks/project/index.js +0 -11
  167. package/src/lib/doctor/checks/project/quire-11ty.js +0 -98
  168. package/src/lib/doctor/checks/project/quire-11ty.test.js +0 -170
  169. package/src/lib/doctor/checks/project/quire-project.js +0 -38
  170. package/src/lib/doctor/checks/project/quire-project.test.js +0 -47
  171. package/src/lib/doctor/checks/tools/index.js +0 -10
  172. package/src/lib/doctor/checks/tools/pandoc-available.js +0 -82
  173. package/src/lib/doctor/checks/tools/pandoc-available.test.js +0 -73
  174. package/src/lib/doctor/checks/tools/prince-available.js +0 -81
  175. package/src/lib/doctor/checks/tools/prince-available.test.js +0 -73
  176. package/src/lib/doctor/constants.js +0 -39
  177. package/src/lib/doctor/formatDuration.js +0 -108
  178. package/src/lib/doctor/formatDuration.test.js +0 -76
  179. package/src/lib/doctor/formatters/human.js +0 -257
  180. package/src/lib/doctor/formatters/human.test.js +0 -463
  181. package/src/lib/doctor/formatters/index.js +0 -8
  182. package/src/lib/doctor/formatters/json.js +0 -78
  183. package/src/lib/doctor/formatters/json.test.js +0 -174
  184. package/src/lib/doctor/formatters/shared.js +0 -129
  185. package/src/lib/doctor/formatters/shared.test.js +0 -194
  186. package/src/lib/doctor/index.js +0 -271
  187. package/src/lib/doctor/index.test.js +0 -797
  188. package/src/lib/epub/engines.js +0 -46
  189. package/src/lib/epub/index.test.js +0 -518
  190. package/src/lib/epub/pandoc.test.js +0 -122
  191. package/src/lib/epub/schema.js +0 -21
  192. package/src/lib/error/README.md +0 -170
  193. package/src/lib/error/handler.js +0 -107
  194. package/src/lib/git/index.spec.js +0 -80
  195. package/src/lib/git/index.test.js +0 -453
  196. package/src/lib/help/frontmatter.js +0 -77
  197. package/src/lib/help/frontmatter.test.js +0 -139
  198. package/src/lib/help/index.js +0 -146
  199. package/src/lib/help/index.test.js +0 -188
  200. package/src/lib/help/topics/configuration.md +0 -77
  201. package/src/lib/help/topics/debugging.md +0 -69
  202. package/src/lib/help/topics/epub.md +0 -74
  203. package/src/lib/help/topics/pdf.md +0 -74
  204. package/src/lib/help/topics/publishing.md +0 -80
  205. package/src/lib/help/topics/workflows.md +0 -50
  206. package/src/lib/installer/index.js +0 -309
  207. package/src/lib/installer/index.spec.js +0 -83
  208. package/src/lib/installer/index.test.js +0 -545
  209. package/src/lib/logger/README.md +0 -424
  210. package/src/lib/logger/debug.js +0 -132
  211. package/src/lib/logger/debug.spec.js +0 -130
  212. package/src/lib/logger/debug.test.js +0 -128
  213. package/src/lib/logger/index.js +0 -228
  214. package/src/lib/logger/index.spec.js +0 -131
  215. package/src/lib/logger/index.test.js +0 -578
  216. package/src/lib/npm/README.md +0 -127
  217. package/src/lib/npm/index.js +0 -198
  218. package/src/lib/npm/index.spec.js +0 -60
  219. package/src/lib/npm/index.test.js +0 -355
  220. package/src/lib/pdf/engines.js +0 -46
  221. package/src/lib/pdf/index.test.js +0 -708
  222. package/src/lib/pdf/paged.test.js +0 -366
  223. package/src/lib/pdf/prince.test.js +0 -202
  224. package/src/lib/pdf/schema.js +0 -21
  225. package/src/lib/pdf/split.test.js +0 -445
  226. package/src/lib/platform.js +0 -95
  227. package/src/lib/process/manager.js +0 -110
  228. package/src/lib/process/manager.test.js +0 -55
  229. package/src/lib/project/build.js +0 -162
  230. package/src/lib/project/build.test.js +0 -275
  231. package/src/lib/project/config.js +0 -48
  232. package/src/lib/project/config.test.js +0 -134
  233. package/src/lib/project/detect.js +0 -47
  234. package/src/lib/project/detect.test.js +0 -157
  235. package/src/lib/project/index.js +0 -56
  236. package/src/lib/project/output-paths.js +0 -87
  237. package/src/lib/project/output-paths.test.js +0 -66
  238. package/src/lib/project/paths.js +0 -272
  239. package/src/lib/project/version.js +0 -110
  240. package/src/lib/project/version.test.js +0 -350
  241. package/src/lib/reporter/index.test.js +0 -862
  242. package/src/main.spec.js +0 -61
  243. package/src/main.test.js +0 -347
  244. package/src/validators/validate-data-files.js +0 -154
  245. 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
- })