@thegetty/quire-cli 1.0.0-rc.34 → 1.0.0-rc.36

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 (159) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.md +9 -0
  3. package/bin/cli.js +19 -1
  4. package/package.json +21 -8
  5. package/schemas/config.schema.json +194 -0
  6. package/schemas/figures.schema.json +56 -0
  7. package/schemas/layout.schema.json +5 -0
  8. package/schemas/objects.schema.json +62 -0
  9. package/schemas/publication.schema.json +140 -0
  10. package/schemas/references.schema.json +29 -0
  11. package/src/Command.js +26 -6
  12. package/src/Command.spec.js +99 -0
  13. package/src/commands/README.md +213 -122
  14. package/src/commands/build.js +46 -37
  15. package/src/commands/build.spec.js +113 -0
  16. package/src/commands/build.test.js +402 -0
  17. package/src/commands/clean.js +25 -19
  18. package/src/commands/clean.spec.js +108 -0
  19. package/src/commands/clean.test.js +260 -0
  20. package/src/commands/config.js +251 -0
  21. package/src/commands/config.spec.js +107 -0
  22. package/src/commands/config.test.js +715 -0
  23. package/src/commands/create.js +42 -14
  24. package/src/commands/create.spec.js +112 -0
  25. package/src/commands/create.test.js +415 -0
  26. package/src/commands/epub.js +59 -30
  27. package/src/commands/epub.spec.js +114 -0
  28. package/src/commands/epub.test.js +503 -0
  29. package/src/commands/index.js +9 -2
  30. package/src/commands/info.js +18 -24
  31. package/src/commands/info.spec.js +64 -0
  32. package/src/commands/info.test.js +415 -0
  33. package/src/commands/pdf.js +58 -84
  34. package/src/commands/pdf.spec.js +114 -0
  35. package/src/commands/pdf.test.js +464 -0
  36. package/src/commands/preview.js +26 -31
  37. package/src/commands/preview.spec.js +97 -0
  38. package/src/commands/preview.test.js +250 -0
  39. package/src/commands/use.js +56 -0
  40. package/src/commands/use.spec.js +61 -0
  41. package/src/commands/use.test.js +280 -0
  42. package/src/commands/validate.js +31 -19
  43. package/src/commands/validate.spec.js +82 -0
  44. package/src/commands/validate.test.js +234 -0
  45. package/src/commands/workflows.js +70 -0
  46. package/src/errors/build/build-failed-error.js +19 -0
  47. package/src/errors/build/config-field-missing-error.js +20 -0
  48. package/src/errors/build/config-file-not-found-error.js +20 -0
  49. package/src/errors/build/index.js +11 -0
  50. package/src/errors/index.js +48 -0
  51. package/src/errors/install/dependency-install-error.js +19 -0
  52. package/src/errors/install/directory-not-empty-error.js +25 -0
  53. package/src/errors/install/index.js +12 -0
  54. package/src/errors/install/invalid-path-error.js +31 -0
  55. package/src/errors/install/invalid-starter-error.js +27 -0
  56. package/src/errors/install/version-not-found-error.js +35 -0
  57. package/src/errors/output/epub-generation-error.js +19 -0
  58. package/src/errors/output/index.js +14 -0
  59. package/src/errors/output/invalid-epub-library-error.js +20 -0
  60. package/src/errors/output/invalid-pdf-library-error.js +20 -0
  61. package/src/errors/output/missing-build-output-error.js +21 -0
  62. package/src/errors/output/pdf-generation-error.js +24 -0
  63. package/src/errors/output/tool-not-found-error.js +37 -0
  64. package/src/errors/project/index.js +10 -0
  65. package/src/errors/project/not-in-project-error.js +20 -0
  66. package/src/errors/project/project-create-error.js +21 -0
  67. package/src/errors/quire-error.js +27 -0
  68. package/src/errors/validation/validation-error.js +20 -11
  69. package/src/helpers/clean.js +1 -1
  70. package/src/helpers/docs-url.js +32 -0
  71. package/src/helpers/test-cwd.js +5 -6
  72. package/src/helpers/test-cwd.test.js +192 -0
  73. package/src/helpers/which.js +10 -4
  74. package/src/lib/11ty/README.md +135 -19
  75. package/src/lib/11ty/api.js +176 -93
  76. package/src/lib/11ty/cli.js +77 -35
  77. package/src/lib/11ty/index.js +64 -5
  78. package/src/lib/11ty/index.test.js +655 -0
  79. package/src/lib/README.md +275 -0
  80. package/src/lib/commander/index.js +100 -0
  81. package/src/lib/commander/index.test.js +86 -0
  82. package/src/lib/commander/options.js +195 -0
  83. package/src/lib/commander/options.test.js +109 -0
  84. package/src/lib/conf/README.md +84 -73
  85. package/src/lib/conf/config.js +5 -3
  86. package/src/lib/conf/config.test.js +281 -0
  87. package/src/lib/conf/defaults.js +44 -0
  88. package/src/lib/conf/format.js +60 -0
  89. package/src/lib/conf/format.test.js +106 -0
  90. package/src/lib/conf/helpers.js +91 -0
  91. package/src/lib/conf/helpers.test.js +136 -0
  92. package/src/lib/conf/index.js +22 -0
  93. package/src/lib/conf/schema.js +53 -8
  94. package/src/lib/epub/README.md +133 -2
  95. package/src/lib/epub/engines.js +46 -0
  96. package/src/lib/epub/epub.js +36 -11
  97. package/src/lib/epub/index.js +111 -21
  98. package/src/lib/epub/index.test.js +518 -0
  99. package/src/lib/epub/pandoc.js +33 -4
  100. package/src/lib/epub/pandoc.test.js +122 -0
  101. package/src/lib/epub/schema.js +21 -0
  102. package/src/lib/error/README.md +170 -0
  103. package/src/lib/error/handler.js +107 -0
  104. package/src/lib/git/README.md +151 -2
  105. package/src/lib/git/index.js +217 -13
  106. package/src/lib/git/index.spec.js +80 -0
  107. package/src/lib/git/index.test.js +453 -0
  108. package/src/lib/installer/index.js +309 -0
  109. package/src/lib/installer/index.spec.js +83 -0
  110. package/src/lib/installer/index.test.js +545 -0
  111. package/src/lib/logger/README.md +424 -0
  112. package/src/lib/logger/debug.js +90 -0
  113. package/src/lib/logger/debug.spec.js +130 -0
  114. package/src/lib/logger/index.js +228 -0
  115. package/src/lib/logger/index.spec.js +131 -0
  116. package/src/lib/logger/index.test.js +477 -0
  117. package/src/lib/npm/README.md +127 -0
  118. package/src/lib/npm/index.js +198 -0
  119. package/src/lib/npm/index.spec.js +60 -0
  120. package/src/lib/npm/index.test.js +355 -0
  121. package/src/lib/pdf/README.md +131 -0
  122. package/src/lib/pdf/engines.js +46 -0
  123. package/src/lib/pdf/index.js +124 -21
  124. package/src/lib/pdf/index.test.js +708 -0
  125. package/src/lib/pdf/paged.js +100 -52
  126. package/src/lib/pdf/paged.test.js +366 -0
  127. package/src/lib/pdf/prince.js +115 -37
  128. package/src/lib/pdf/prince.test.js +202 -0
  129. package/src/lib/pdf/schema.js +21 -0
  130. package/src/lib/pdf/split.js +61 -33
  131. package/src/lib/pdf/split.test.js +445 -0
  132. package/src/lib/process/manager.js +110 -0
  133. package/src/lib/process/manager.test.js +55 -0
  134. package/src/lib/project/build.js +143 -0
  135. package/src/lib/project/build.test.js +253 -0
  136. package/src/lib/project/config.js +48 -0
  137. package/src/lib/project/config.test.js +134 -0
  138. package/src/{helpers/is-quire.js → lib/project/detect.js} +5 -3
  139. package/src/lib/project/detect.test.js +157 -0
  140. package/src/lib/project/index.js +40 -0
  141. package/src/lib/project/paths.js +224 -0
  142. package/src/lib/project/version.js +110 -0
  143. package/src/lib/project/version.test.js +350 -0
  144. package/src/lib/reporter/README.md +211 -2
  145. package/src/lib/reporter/index.js +512 -0
  146. package/src/lib/reporter/index.test.js +593 -0
  147. package/src/main.js +134 -47
  148. package/src/main.spec.js +61 -0
  149. package/src/main.test.js +347 -0
  150. package/src/validators/utils.js +2 -1
  151. package/src/commands/conf.js +0 -43
  152. package/src/commands/version.js +0 -43
  153. package/src/lib/11ty/paths.js +0 -103
  154. package/src/lib/i18n/README.md +0 -3
  155. package/src/lib/i18n/config.js +0 -53
  156. package/src/lib/i18n/index.js +0 -43
  157. package/src/lib/i18n/localeService.js +0 -58
  158. package/src/lib/quire/README.md +0 -19
  159. package/src/lib/quire/index.js +0 -350
@@ -1,27 +1,52 @@
1
1
  import { ManifestToEpub } from 'epubjs-cli'
2
2
  import fs from 'fs-extra'
3
3
  import { pathToFileURL } from 'node:url'
4
+ import { EpubGenerationError } from '#src/errors/index.js'
5
+ import createDebug from '#debug'
6
+ import ENGINES from './engines.js'
7
+
8
+ const debug = createDebug('lib:epub:epubjs')
9
+
10
+ /** Re-export engine metadata from central registry */
11
+ export const metadata = ENGINES.epubjs
4
12
 
5
13
  /**
6
14
  * A façade module for the EPUB.js library
7
15
  * @see https://github.com/futurepress/epubjs-cli
16
+ *
17
+ * @param {string} input - Path to the input directory containing manifest.json
18
+ * @param {string} output - Path where the EPUB should be written
19
+ * @param {Object} [options={}] - Generation options
20
+ * @returns {Promise<void>}
8
21
  */
9
22
  export default async (input, output, options = {}) => {
10
- try {
11
- console.info(`[CLI:lib/epub/epubjs] Generating ePub from ${input}`)
23
+ debug('input: %s', input)
24
+ debug('output: %s', output)
12
25
 
13
- const url = pathToFileURL(`${input}/manifest.json`).toString()
26
+ const url = pathToFileURL(`${input}/manifest.json`).toString()
14
27
 
15
- const epub = await new ManifestToEpub(url)
16
- .catch((error) => console.error(error))
28
+ let epub
29
+ try {
30
+ epub = await new ManifestToEpub(url)
31
+ } catch (error) {
32
+ throw new EpubGenerationError('Epub.js', 'manifest loading', error.message)
33
+ }
17
34
 
18
- const file = await epub.save()
19
- .catch((error) => console.error(error))
35
+ let file
36
+ try {
37
+ file = await epub.save()
38
+ } catch (error) {
39
+ throw new EpubGenerationError('Epub.js', 'file generation', error.message)
40
+ }
20
41
 
21
- if (file && output) {
22
- fs.writeFile(output, file, (error) => { if (error) throw error })
42
+ if (file && output) {
43
+ debug('writing EPUB to %s', output)
44
+ try {
45
+ await fs.writeFile(output, file)
46
+ } catch (error) {
47
+ throw new EpubGenerationError('Epub.js', 'file write', error.message)
23
48
  }
24
- } catch (ERR_FILE_NOT_FOUND) {
25
- console.error(`[CLI:lib/epub/epubjs] file not found ${input}`)
26
49
  }
50
+
51
+ debug('complete')
27
52
  }
@@ -1,40 +1,130 @@
1
1
  import { dynamicImport } from '#helpers/os-utils.js'
2
+ import which from '#helpers/which.js'
2
3
  import { fileURLToPath } from 'node:url'
3
4
  import path from 'node:path'
5
+ import fs from 'fs-extra'
6
+ import paths from '#lib/project/index.js'
7
+ import reporter from '#lib/reporter/index.js'
8
+ import { InvalidEpubLibraryError } from '#src/errors/index.js'
9
+ import createDebug from '#debug'
10
+ import ENGINE_METADATA from './engines.js'
11
+ import { ENGINES } from './schema.js'
12
+
13
+ export { ENGINES }
4
14
 
5
15
  const __filename = fileURLToPath(import.meta.url)
6
16
  const __dirname = path.dirname(__filename)
7
17
 
18
+ const debug = createDebug('lib:epub')
19
+
8
20
  /**
9
- * A façade delegation module for EPUB libraries
21
+ * Resolve the EPUB library implementation
22
+ *
23
+ * @param {string} name - Library name to resolve
24
+ * @returns {Object} Resolved engine with absolute module path
25
+ * @throws {InvalidEpubLibraryError} When library name is not recognized
10
26
  */
11
- export default async (name = 'epubjs', options = {}) => {
12
- const lib = { name, options, path }
13
-
27
+ function resolveLibrary(name) {
14
28
  const normalizedName = name.replace(/[-_.\s]/g, '').toLowerCase()
15
29
 
16
30
  switch (normalizedName) {
17
- case 'epubjs': {
18
- lib.name = 'Epub.js'
19
- lib.options = {}
20
- lib.path = path.join(__dirname, 'epub.js')
21
- break
22
- }
23
- case 'pandoc': {
24
- lib.name = 'Pandoc'
25
- lib.options = {}
26
- lib.path = path.join(__dirname, 'pandoc.js')
27
- break
28
- }
31
+ case 'epubjs':
32
+ case 'epub':
33
+ return { ...ENGINE_METADATA.epubjs, path: path.join(__dirname, ENGINE_METADATA.epubjs.module) }
34
+ case 'pandoc':
35
+ return { ...ENGINE_METADATA.pandoc, path: path.join(__dirname, ENGINE_METADATA.pandoc.module) }
29
36
  default:
30
- console.error(`[CLI:lib/pdf] Unrecognized EPUB library '${name}'`)
31
- return
37
+ throw new InvalidEpubLibraryError(name)
38
+ }
39
+ }
40
+
41
+ /**
42
+ * Check if the required binary for an engine is available
43
+ *
44
+ * @param {Object} engine - Engine definition from ENGINES
45
+ * @throws {ToolNotFoundError} When required binary is not in PATH
46
+ */
47
+ function checkEngineAvailable(engine) {
48
+ if (!engine.requiresBinary) {
49
+ return // No binary required (e.g., epubjs uses Node.js)
32
50
  }
33
51
 
52
+ const result = which(engine.requiresBinary, engine.toolInfo)
53
+ debug('found %s at %s', engine.requiresBinary, result)
54
+ }
55
+
56
+ /**
57
+ * Construct the default output path for the EPUB
58
+ */
59
+ function getOutputPath(projectRoot, libName) {
60
+ return path.join(projectRoot, `${libName}.epub`)
61
+ }
62
+
63
+ /**
64
+ * Resolve a custom output path, handling relative paths and ensuring .epub extension
65
+ *
66
+ * @param {string} customOutput - User-provided output path
67
+ * @param {string} projectRoot - Project root directory
68
+ * @returns {string} Resolved absolute path with .epub extension
69
+ */
70
+ function resolveOutputPath(customOutput, projectRoot) {
71
+ // Resolve relative paths against project root
72
+ const resolved = path.isAbsolute(customOutput)
73
+ ? customOutput
74
+ : path.join(projectRoot, customOutput)
75
+
76
+ // Ensure .epub extension
77
+ return resolved.endsWith('.epub') ? resolved : `${resolved}.epub`
78
+ }
79
+
80
+ /**
81
+ * Generate an EPUB from the built publication
82
+ *
83
+ * @param {Object} options - Generation options
84
+ * @param {string} [options.lib='epubjs'] - EPUB library to use ('epubjs' or 'pandoc')
85
+ * @param {string} [options.output] - Custom output path (relative to project root or absolute)
86
+ * @param {boolean} [options.debug] - Enable debug output
87
+ * @returns {Promise<string>} Absolute path to the generated EPUB file
88
+ */
89
+ export default async function generateEpub(options = {}) {
90
+ const libName = options.lib || 'epubjs'
91
+ const lib = resolveLibrary(libName)
92
+
93
+ debug('resolved library: %s → %s', libName, lib.name)
94
+
95
+ // Check engine availability BEFORE starting reporter (fail fast with clean error)
96
+ checkEngineAvailable(lib)
97
+
98
+ const projectRoot = paths.getProjectRoot()
99
+ const inputDir = path.join(projectRoot, paths.getEpubDir())
100
+
101
+ // Resolve output path from user option or default to {libName}.epub
102
+ const epubPath = options.output
103
+ ? resolveOutputPath(options.output, projectRoot)
104
+ : getOutputPath(projectRoot, libName)
105
+
106
+ // Ensure parent directory exists (epub generators use fs.writeFile directly)
107
+ const epubDir = path.dirname(epubPath)
108
+ if (!fs.existsSync(epubDir)) {
109
+ fs.mkdirSync(epubDir, { recursive: true })
110
+ }
111
+
112
+ debug('input: %s', inputDir)
113
+ debug('output: %s', epubPath)
114
+
34
115
  const { default: epubLib } = await dynamicImport(lib.path)
35
116
 
36
- return async (input, output) => {
37
- console.info(`[CLI:lib/epub] generating EPUB using ${lib.name}`)
38
- return await epubLib(input, output, lib.options)
117
+ reporter.start(`Generating EPUB using ${lib.name}...`, { showElapsed: true })
118
+ reporter.detail(`Input: ${inputDir}`)
119
+ reporter.detail(`Output: ${epubPath}`)
120
+
121
+ try {
122
+ await epubLib(inputDir, epubPath, options)
123
+ reporter.succeed(`EPUB saved to ${epubPath}`)
124
+ } catch (error) {
125
+ reporter.fail(`EPUB generation failed`)
126
+ throw error
39
127
  }
128
+
129
+ return epubPath
40
130
  }