@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,10 +1,6 @@
1
1
  import Command from '#src/Command.js'
2
- import { Option } from 'commander'
3
- import { withOutputModes } from '#lib/commander/index.js'
4
2
  import fs from 'fs-extra'
5
- import { installer } from '#lib/installer/index.js'
6
- import { DirectoryNotEmptyError, ProjectCreateError } from '#src/errors/index.js'
7
- import reporter from '#lib/reporter/index.js'
3
+ import { quire } from '#src/lib/quire/index.js'
8
4
 
9
5
  /**
10
6
  * Quire CLI `new` Command
@@ -17,17 +13,10 @@ import reporter from '#lib/reporter/index.js'
17
13
  * @extends {Command}
18
14
  */
19
15
  export default class CreateCommand extends Command {
20
- static definition = withOutputModes({
16
+ static definition = {
21
17
  name: 'new',
22
18
  description: 'Start a new Quire project from a template.',
23
19
  summary: 'create a new project',
24
- docsLink: 'quire-commands/#start-and-preview-projects',
25
- helpText: `
26
- Examples:
27
- quire new my-project Use default starter
28
- quire new my-project --quire-version 1.0.0 Pin quire-11ty version
29
- quire new my-project --verbose Create with detailed progress
30
- `,
31
20
  version: '1.0.0',
32
21
  args: [
33
22
  [ '[projectPath]', 'local path to the new project', '.' ],
@@ -36,10 +25,10 @@ Examples:
36
25
  options: [
37
26
  [ '--quire-path <path>', 'local path to quire-11ty package' ],
38
27
  [ '--quire-version <version>', 'quire-11ty version to install' ],
39
- // Use Option object syntax to configure this as a hidden option
40
- new Option('--clean-cache', 'force clean the npm cache').default(false).hideHelp(),
28
+ // [ '--eject', 'install quire-11ty into the project directory', true ],
29
+ [ '--debug', 'debug the `quire new` command', false ],
41
30
  ],
42
- })
31
+ }
43
32
 
44
33
  constructor() {
45
34
  super(CreateCommand.definition)
@@ -52,16 +41,15 @@ Examples:
52
41
  * @return {Promise}
53
42
  */
54
43
  async action(projectPath, starter, options = {}) {
55
- this.debug('called with options %O', options)
56
-
57
- // Configure reporter for this command
58
- reporter.configure({ quiet: options.quiet, verbose: options.verbose })
44
+ if (options.debug) {
45
+ console.info('Command \'%s\' called with options %o', CreateCommand.name, options)
46
+ }
59
47
 
60
48
  starter = starter || this.config.get('projectTemplate')
61
49
 
62
50
  if (!projectPath && !starter) {
63
51
  // @TODO implement this case of interactively selecting starter templates
64
- // from available subtrees in `lib/installer` module
52
+ // from available subtrees in `lib/quire` module
65
53
 
66
54
  // await interactivePrompt()
67
55
  // list sub-repositories in '@thegetty/quire/packages/starters'
@@ -77,30 +65,14 @@ Examples:
77
65
  */
78
66
  let quireVersion
79
67
  try {
80
- quireVersion = await installer.initStarter(starter, projectPath, options)
68
+ quireVersion = await quire.initStarter(starter, projectPath, options)
81
69
  } catch (error) {
82
- reporter.fail('Failed to initialize project')
83
- this.logger.error(error.message)
84
- /**
85
- * Nota bene: Auto-deletion of projectPath is disabled to prevent accidental data loss.
86
- * @TODO implement safe cleaup that either tracks whether quire created the directory,
87
- * or prompt the user for confirmation before deleting any files.
88
- */
89
- // if (!(error instanceof DirectoryNotEmptyError)) {
90
- // fs.removeSync(projectPath)
91
- // }
92
- throw new ProjectCreateError(projectPath, error.message)
93
- }
94
-
95
- // Check if initStarter returned without a version
96
- if (!quireVersion) {
97
- // Nota bene: Auto-deletion disabled - see comment above
98
- // fs.removeSync(projectPath)
99
- throw new ProjectCreateError(projectPath, 'Failed to determine Quire version')
70
+ console.error(error.message)
71
+ fs.removeSync(projectPath)
72
+ return
100
73
  }
101
74
 
102
- await installer.installInProject(projectPath, quireVersion, options)
103
- reporter.succeed('Project created successfully')
75
+ await quire.installInProject(projectPath, quireVersion, options)
104
76
  }
105
77
  }
106
78
  }
@@ -1,17 +1,12 @@
1
1
  import Command from '#src/Command.js'
2
- import { withOutputModes } from '#lib/commander/index.js'
3
- import paths, { hasEpubOutput } from '#lib/project/index.js'
4
- import eleventy from '#lib/11ty/index.js'
2
+ import { paths, projectRoot } from '#lib/11ty/index.js'
5
3
  import fs from 'fs-extra'
6
- import generateEpub, { ENGINES } from '#lib/epub/index.js'
4
+ import libEpub from '#lib/epub/index.js'
7
5
  import open from 'open'
8
- import { recordStatus } from '#lib/conf/build-status.js'
9
- import reporter from '#lib/reporter/index.js'
10
- import testcwd from '#helpers/test-cwd.js'
11
- import { MissingBuildOutputError } from '#src/errors/index.js'
6
+ import path from 'node:path'
12
7
 
13
8
  /**
14
- * Quire CLI `epub` Command
9
+ * Quire CLI `build epub` Command
15
10
  *
16
11
  * Generate EPUB from Eleventy `build` output.
17
12
  *
@@ -19,84 +14,53 @@ import { MissingBuildOutputError } from '#src/errors/index.js'
19
14
  * @extends {Command}
20
15
  */
21
16
  export default class EpubCommand extends Command {
22
- static definition = withOutputModes({
17
+ static definition = {
23
18
  name: 'epub',
24
19
  description: 'Generate publication EPUB',
25
- summary: 'generate EPUB e-book',
26
- docsLink: 'quire-commands/#output-files',
27
- helpText: `
28
- Examples:
29
- quire epub Generate EPUB using default engine
30
- quire epub --engine pandoc Generate EPUB using Pandoc
31
- quire epub --open Generate and open EPUB
32
- quire epub --build Build site first, then generate EPUB
33
- quire epub --output my-book.epub Generate EPUB with custom output path
34
- `,
20
+ summary: 'run build epub',
35
21
  version: '1.0.0',
22
+ args: [],
36
23
  options: [
37
- [ '--build', 'run build first if output is missing' ],
38
- [ '--open', 'open EPUB in default application' ],
39
- [ '-o, --output <path>', 'output file path (default: {engine}.epub)' ],
40
- [
41
- '--engine <name>', 'EPUB engine to use (default: from config or epubjs)',
42
- { choices: ENGINES }
43
- ],
44
24
  [
45
- '--lib <name>', 'deprecated alias for --engine option',
46
- { hidden: true, choices: ENGINES, conflicts: 'engine' }
25
+ '--lib <module>', 'use the specified epub library', 'epubjs',
26
+ { choices: ['epubjs', 'pandoc'], default: 'epubjs' }
47
27
  ],
28
+ [ '--open', 'open EPUB in default application' ],
29
+ [ '--debug', 'run epub with debug output' ],
48
30
  ],
49
- })
31
+ }
50
32
 
51
33
  constructor() {
52
34
  super(EpubCommand.definition)
53
35
  }
54
36
 
55
37
  async action(options, command) {
56
- this.debug('called with options %O', options)
57
-
58
- // Configure reporter for this command
59
- reporter.configure({ quiet: options.quiet, verbose: options.verbose })
60
-
61
- // Resolve engine: CLI --engine > deprecated --lib > config epubEngine > default
62
- if (!options.engine) {
63
- if (options.lib) {
64
- // Support deprecated --lib option
65
- options.engine = options.lib
66
- } else {
67
- // Use config setting or fallback to default
68
- options.engine = this.config.get('epubEngine') || 'epubjs'
69
- }
38
+ if (options.debug) {
39
+ console.debug('[CLI] Command \'%s\' called with options %o', this.name(), options)
70
40
  }
71
41
 
72
- // Run build first if --build flag is set and output is missing
73
- if (options.build && !hasEpubOutput()) {
74
- this.debug('running build before epub generation')
75
- reporter.start('Building site...', { showElapsed: true })
76
- await eleventy.build({ debug: options.debug })
77
- }
42
+ const input = path.join(projectRoot, paths.epub)
78
43
 
79
- // Check for build output (will throw if missing)
80
- // TODO: Add interactive prompt when build output missing and --build not used
81
- if (!hasEpubOutput()) {
82
- throw new MissingBuildOutputError('EPUB', paths.getEpubDir())
44
+ if (!fs.existsSync(input)) {
45
+ console.error(`Unable to find Epub input at ${input}\nPlease first run the 'quire build' command.`)
46
+ return
83
47
  }
84
48
 
85
- // Pass engine as lib (matching lib/pdf interface)
86
- // Reporter lifecycle is owned by the façade (lib/epub/index.js)
87
- const epubOptions = { ...options, lib: options.engine }
49
+ const output = path.join(projectRoot, `${options.lib}.epub`)
88
50
 
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
- }
51
+ const epubLib = await libEpub(options.lib, { debug: options.debug })
52
+ await epubLib(input, output)
53
+
54
+ if (fs.existsSync(output) && options.open) open(output)
97
55
  }
98
56
 
99
- preAction(thisCommand, actionCommand) {
100
- testcwd(thisCommand)
57
+ /**
58
+ * @todo test if build site has already be run and output can be reused
59
+ */
60
+ preAction(command) {
61
+ const options = command.opts()
62
+ if (options.debug) {
63
+ console.debug('[CLI] Calling \'epub\' command pre-action with options', options)
64
+ }
101
65
  }
102
66
  }
@@ -8,21 +8,14 @@ const __dirname = path.dirname(__filename)
8
8
 
9
9
  const thisfile = path.basename(__filename)
10
10
 
11
- /**
12
- * Filter out files that are not command modules
13
- * @param directory entry
14
- * @returns Boolean
15
- */
16
- const filterEntries = (entry) => entry !== thisfile && entry.match(/^.*(?<!spec|test)\.js$/)
17
-
18
11
  /**
19
12
  * Dynamically import command modules in parallel
20
13
  * and call the class constuctor for each command
21
14
  */
22
15
  const commands = await Promise.all(
23
16
  fs.readdirSync(__dirname)
24
- .filter((entry) => filterEntries(entry))
25
- .map(async (entry) => await dynamicImport(path.resolve(__dirname, entry)))
17
+ .filter((file) => file !== thisfile && file.match(/^.*\.js$/))
18
+ .map(async (file) => await dynamicImport(path.resolve(__dirname, file)))
26
19
  ).then((modules) => {
27
20
  return modules.map(({ default: CommandClass }) => new CommandClass())
28
21
  })
@@ -1,59 +1,44 @@
1
1
  import Command from '#src/Command.js'
2
- import { withOutputModes } from '#lib/commander/index.js'
3
- import { binPath } from '#src/packageConfig.js'
2
+ import { execaCommand } from 'execa'
4
3
  import fs from 'node:fs'
4
+ import os from 'node:os'
5
5
  import path from 'node:path'
6
6
  import testcwd from '#helpers/test-cwd.js'
7
7
 
8
8
  /**
9
9
  * Quire CLI `info` Command
10
10
  *
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.
11
+ * Runs the Eleventy `info` command to list the quire-cli, quire-11ty, node, and npm versions.
20
12
  *
21
13
  * @class InfoCommand
22
14
  * @extends {Command}
23
15
  */
24
16
  export default class InfoCommand extends Command {
25
- static definition = withOutputModes({
17
+ static definition = {
26
18
  name: 'info',
27
- description: 'Display version information for the current project',
28
- summary: 'show project version information',
29
- docsLink: 'quire-commands/#get-help',
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
-
39
- Example:
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
44
- `,
19
+ description: 'List Quire cli, quire-11ty, and node versions',
20
+ summary: 'list info',
45
21
  version: '1.0.0',
22
+ args: [],
46
23
  options: [
47
- ['--json', 'output version information as JSON'],
24
+ ['--debug', 'include os versions in output']
48
25
  ],
49
- })
26
+ }
50
27
 
51
28
  constructor() {
52
29
  super(InfoCommand.definition)
53
30
  }
54
31
 
55
32
  async action(options, command) {
56
- this.debug('called with options %O', options)
33
+ if (options.debug) {
34
+ console.debug(
35
+ '[CLI] Command \'%s\' called with options %o',
36
+ this.name(),
37
+ options
38
+ )
39
+ } else {
40
+ console.debug('[CLI] Command \'%s\' called', this.name())
41
+ }
57
42
 
58
43
  // Load filename from config with a default constraint if it doesn't exist
59
44
  const versionFileName = this.config.get('versionFile')
@@ -61,72 +46,85 @@ Example:
61
46
 
62
47
  try {
63
48
  const versionFileData = fs.readFileSync(versionFileName, { encoding: 'utf8' })
64
- versionInfo = JSON.parse(versionFileData)
49
+
50
+ versionInfo = JSON.parse(versionFileData)
65
51
  } catch (error) {
66
- this.logger.warn(
52
+ console.warn(
67
53
  `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.`
68
54
  )
55
+
69
56
  fs.writeFileSync(versionFileName, JSON.stringify(versionInfo))
70
57
  }
71
58
 
72
59
  const { name: projectDirectory } = path.parse(process.cwd())
73
60
 
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}`,
61
+ const versions = [
62
+ {
63
+ title: `[${projectDirectory}]`,
64
+ items: [
65
+ {
66
+ name: 'quire-cli',
67
+ get: () => versionInfo.cli,
68
+ },
69
+ {
70
+ name: 'quire-11ty',
71
+ get: () => {
72
+ const { version } = JSON.parse(fs.readFileSync('./package.json'))
73
+ return version
74
+ },
75
+ },
76
+ {
77
+ name: 'starter',
78
+ get: () => versionInfo.starter,
79
+ },
80
+ ],
81
+ },
82
+ {
83
+ title: '[System]',
84
+ items: [
85
+ {
86
+ name: 'quire-cli',
87
+ get: async () => {
88
+ const { stdout } = await execaCommand('quire --version')
89
+ return stdout
90
+ },
91
+ },
92
+ {
93
+ debug: true,
94
+ name: 'node',
95
+ get: () => process.version,
96
+ },
97
+ {
98
+ debug: true,
99
+ name: 'npm',
100
+ get: async () => {
101
+ const { stdout } = await execaCommand('npm --version')
102
+ return stdout
103
+ },
104
+ },
105
+ {
106
+ debug: true,
107
+ name: 'os',
108
+ get: () => `${os.type()} ${os.release()}`,
109
+ },
110
+ ],
111
+ },
101
112
  ]
102
113
 
103
- if (versionInfo.starter) {
104
- lines.push(` starter ${versionInfo.starter}`)
105
- }
106
-
107
- if (options.debug) {
108
- lines.push('')
109
- lines.push(this.resolveCliPath())
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'
114
+ /**
115
+ * Filter the command output based on `debug` settings
116
+ */
117
+ versions.forEach(async ({ items, title }) => {
118
+ const versions = await Promise.all(
119
+ items
120
+ .filter(({ debug }) => !debug || (options.debug && debug))
121
+ .map(async ({ name, get }) => `${name} ${await get()}`)
122
+ )
123
+ console.info(`${title}\n ${versions.join('\n ')}`)
124
+ })
127
125
  }
128
126
 
129
- preAction(thisCommand, actionCommand) {
130
- testcwd(thisCommand)
127
+ preAction(command) {
128
+ testcwd(command)
131
129
  }
132
130
  }
@@ -1,14 +1,50 @@
1
+ import { paths, projectRoot } from '#lib/11ty/index.js'
1
2
  import Command from '#src/Command.js'
2
- import { withOutputModes } from '#lib/commander/index.js'
3
- import paths, { hasSiteOutput } from '#lib/project/index.js'
4
- import eleventy from '#lib/11ty/index.js'
5
- import generatePdf, { ENGINES } from '#lib/pdf/index.js'
3
+ import fs from 'fs-extra'
4
+ import libPdf from '#lib/pdf/index.js'
6
5
  import open from 'open'
7
6
  import path from 'node:path'
8
- import { recordStatus } from '#lib/conf/build-status.js'
9
- import reporter from '#lib/reporter/index.js'
10
- import testcwd from '#helpers/test-cwd.js'
11
- import { MissingBuildOutputError } from '#src/errors/index.js'
7
+ import { pathToFileURL } from 'node:url'
8
+ import yaml from 'js-yaml'
9
+
10
+ /**
11
+ * @function loadConfig(path) - loads and validates quire config, returns an empty object if not found
12
+ *
13
+ * @param {path} string - file path to config file
14
+ *
15
+ * @return {Object|undefined} User configuration object or undefined
16
+ *
17
+ * @todo consider hardcoding a version check against .quire / project's package.json ver
18
+ */
19
+ async function loadConfig(configPath) {
20
+ if (!fs.existsSync(configPath)) {
21
+ return undefined
22
+ }
23
+
24
+ const data = fs.readFileSync(configPath)
25
+ let config = yaml.load(data)
26
+
27
+ // NB: Schemas and validators are specific to the 11ty version of the project being built
28
+ const schemaPath = path.join(projectRoot,'_plugins','schemas','config.json')
29
+ const validatorPath = path.join(projectRoot, '_plugins', 'globalData', 'validator.js')
30
+
31
+ if (fs.existsSync(schemaPath) && fs.existsSync(validatorPath)) {
32
+
33
+ const { validateUserConfig } = await import(pathToFileURL(validatorPath))
34
+
35
+ const schemaJSON = fs.readFileSync(schemaPath)
36
+ const schema = JSON.parse(schemaJSON)
37
+
38
+ try {
39
+ config = validateUserConfig('config', config, { config: schema })
40
+ } catch (error) {
41
+ console.error(error)
42
+ process.exit(1)
43
+ }
44
+ }
45
+
46
+ return config
47
+ }
12
48
 
13
49
  /**
14
50
  * Quire CLI `pdf` Command
@@ -19,83 +55,66 @@ import { MissingBuildOutputError } from '#src/errors/index.js'
19
55
  * @extends {Command}
20
56
  */
21
57
  export default class PDFCommand extends Command {
22
- static definition = withOutputModes({
58
+ static definition = {
23
59
  name: 'pdf',
24
60
  description: 'Generate publication PDF',
25
- summary: 'generate print-ready PDF',
26
- docsLink: 'quire-commands/#output-files',
27
- helpText: `
28
- Examples:
29
- quire pdf Generate PDF using default engine
30
- quire pdf --engine prince Generate PDF using PrinceXML
31
- quire pdf --build Build site first, then generate PDF
32
- quire pdf --output my-book.pdf Generate PDF with custom output path
33
- quire pdf --verbose Generate with detailed progress
34
- `,
61
+ summary: 'run build pdf',
35
62
  version: '1.0.0',
63
+ args: [
64
+ ],
36
65
  options: [
37
- [ '--build', 'run build first if output is missing' ],
38
- [ '--open', 'open PDF in default application' ],
39
- [ '-o, --output <path>', 'output file path (default: from project config)' ],
40
66
  [
41
- '--engine <name>', 'PDF engine to use (default: from config or pagedjs)',
42
- { choices: ENGINES }
43
- ],
44
- [
45
- '--lib <name>', 'deprecated alias for --engine option',
46
- { hidden: true, choices: ENGINES, conflicts: 'engine' }
67
+ '--lib <module>', 'use the specified pdf module', 'pagedjs',
68
+ { choices: ['pagedjs', 'prince'], default: 'pagedjs' }
47
69
  ],
70
+ [ '--open', 'open PDF in default application' ],
71
+ [ '--debug', 'run build with debug output to console' ],
48
72
  ],
49
- })
73
+ }
50
74
 
51
75
  constructor() {
52
76
  super(PDFCommand.definition)
53
77
  }
54
78
 
55
79
  async action(options, command) {
56
- this.debug('called with options %O', options)
57
- /**
58
- * Configure reporter for this command
59
- * reporter lifecycle (start/succeed/fail) is handled by the façade,
60
- * not by the command.
61
- */
62
- reporter.configure({ quiet: options.quiet, verbose: options.verbose })
63
-
64
- // Resolve engine: CLI --engine > deprecated --lib > config pdfEngine > default
65
- if (!options.engine) {
66
- if (options.lib) {
67
- // Support deprecated --lib option
68
- options.engine = options.lib
69
- } else {
70
- // Use config setting or fallback to default
71
- options.engine = this.config.get('pdfEngine') || 'pagedjs'
72
- }
80
+ if (options.debug) {
81
+ console.debug('[CLI] Command \'%s\' called with options %o', this.name(), options)
82
+ }
83
+
84
+ const publicationInput = path.join(projectRoot, paths.output, 'pdf.html')
85
+ const coversInput = path.join(projectRoot, paths.output, 'pdf-covers.html')
86
+
87
+ const quireConfig = await loadConfig(path.join(projectRoot,'content','_data','config.yaml'))
88
+
89
+ if (quireConfig === undefined) {
90
+ console.error(`[quire pdf]: ERROR Unable to find a configuration file at ${path.join(projectRoot,'content','_data','config.yaml')}\nIs the command being run in a quire project?`)
91
+ process.exit(1)
73
92
  }
74
93
 
75
- // Run build first if --build flag is set and output is missing
76
- if (options.build && !hasSiteOutput()) {
77
- this.debug('running build before pdf generation')
78
- reporter.start('Building site...', { showElapsed: true })
79
- await eleventy.build({ debug: options.debug })
80
- reporter.succeed('Build complete')
94
+ if (!fs.existsSync(publicationInput)) {
95
+ console.error(`[quire pdf]: ERROR Unable to find PDF input at ${publicationInput}\nPlease first run the 'quire build' command.`)
96
+ process.exit(1)
81
97
  }
82
98
 
83
- // Generate PDF - façade handles validation, progress, and errors
84
- const pdfOptions = { ...options, lib: options.engine }
99
+ const output = quireConfig.pdf !== undefined
100
+ ? path.join(paths.output, quireConfig.pdf.outputDir, `${quireConfig.pdf.filename}.pdf`)
101
+ : path.join(projectRoot, `${options.lib}.pdf`)
102
+
103
+ const pdfLib = await libPdf(options.lib, { ...options, pdfConfig: quireConfig.pdf })
104
+ await pdfLib(publicationInput, coversInput, output)
85
105
 
86
106
  try {
87
- const output = await generatePdf(pdfOptions)
88
- recordStatus(paths.getProjectRoot(), 'pdf', 'ok')
89
- if (options.open) {
90
- open(output)
91
- }
107
+ if (fs.existsSync(output) && options.open) open(output)
92
108
  } catch (error) {
93
- recordStatus(paths.getProjectRoot(), 'pdf', 'failed')
94
- throw error
109
+ console.error(`[quire pdf]: ERROR`,error)
110
+ process.exit(1)
95
111
  }
96
112
  }
97
113
 
98
- preAction(thisCommand, actionCommand) {
99
- testcwd(thisCommand)
114
+ /**
115
+ * @todo test if build has already be run and output can be reused
116
+ */
117
+ preAction(command) {
118
+ // testcwd(command)
100
119
  }
101
120
  }