@thegetty/quire-cli 1.0.0-rc.45 → 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 (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,667 +0,0 @@
1
- # Doctor Module
2
-
3
- Diagnostic checks for Quire environment and project health.
4
-
5
- ## Command Usage
6
-
7
- ```bash
8
- quire doctor # Run all diagnostic checks
9
- quire doctor --check environment # Check environment section only
10
- quire doctor --check node,npm # Check specific items
11
- quire doctor --verbose # Show additional details
12
- quire doctor --errors # Show only failed checks
13
- quire doctor --warnings # Show only warnings
14
- quire doctor --json # Output as JSON to stdout
15
- quire doctor --json report.json # Save JSON to file
16
- ```
17
-
18
- ### CI/Scripting
19
-
20
- The `--quiet` flag suppresses all console output, useful for CI pipelines and scripts.
21
-
22
- **Exit code only** (gate a CI step on environment health):
23
- ```bash
24
- quire doctor --check environment --quiet || exit 1
25
- ```
26
-
27
- **Save JSON report silently** (for CI artifacts):
28
- ```bash
29
- quire doctor --quiet --json reports/doctor.json
30
- ```
31
-
32
- **Exit codes:**
33
- - `0` - All checks passed (warnings don't affect exit code)
34
- - `1` - One or more checks failed
35
-
36
- ### Output Formats
37
-
38
- | Format | Flag | Use Case |
39
- |--------|------|----------|
40
- | Human | (default) | Interactive terminal use |
41
- | JSON | `--json` | Programmatic consumption, CI artifacts |
42
- | Quiet | `--quiet` | Exit code only, no output |
43
-
44
- ## Architecture
45
-
46
- ```
47
- doctor/
48
- ├── index.js # Barrel export, runners, checkSections
49
- ├── index.test.js # Integration tests for runners
50
- ├── constants.js # Re-exports from #lib/constants.js + stale thresholds
51
- ├── formatDuration.js # Human-readable time formatting
52
- ├── formatDuration.test.js # Duration formatting tests
53
- ├── README.md # This file
54
- └── checks/ # Domain-organized check modules
55
- ├── environment/ # System prerequisites
56
- │ ├── index.js # Barrel export
57
- │ ├── os-info.js # Operating system info
58
- │ ├── os-info.test.js
59
- │ ├── cli-version.js # CLI version check
60
- │ ├── cli-version.test.js
61
- │ ├── node-version.js # Node.js version check (OS-specific remediation)
62
- │ ├── node-version.test.js
63
- │ ├── npm-available.js # npm availability check (OS-specific remediation)
64
- │ ├── npm-available.test.js
65
- │ ├── git-available.js # Git availability check (OS-specific remediation)
66
- │ ├── git-available.test.js
67
- │ ├── prince-available.js # PrinceXML availability check (optional engine)
68
- │ ├── prince-available.test.js
69
- │ ├── pandoc-available.js # Pandoc availability check (optional engine)
70
- │ └── pandoc-available.test.js
71
- ├── project/ # Project configuration
72
- │ ├── index.js # Barrel export
73
- │ ├── quire-project.js # Project detection check
74
- │ ├── quire-project.test.js
75
- │ ├── dependencies.js # node_modules check
76
- │ ├── dependencies.test.js
77
- │ ├── quire-11ty.js # Version check
78
- │ ├── quire-11ty.test.js
79
- │ ├── data-files.js # YAML validation check
80
- │ └── data-files.test.js
81
- └── outputs/ # Build artifacts
82
- ├── index.js # Barrel export
83
- ├── stale-build.js # Stale build detection
84
- ├── stale-build.test.js
85
- ├── pdf-output.js # PDF output check
86
- ├── pdf-output.test.js
87
- ├── epub-output.js # EPUB output check
88
- └── epub-output.test.js
89
- ```
90
-
91
- ## Dependency Graph
92
-
93
- ```
94
- ┌─────────────────────────────────────────────────────────────────────────────┐
95
- │ doctor/index.js │
96
- │ Imports checks from domain submodules, defines checkSections, runners │
97
- └────────────────────────────────────┬────────────────────────────────────────┘
98
-
99
- ┌───────────────────────────┼───────────────────────────┐
100
- │ │ │
101
- ▼ ▼ ▼
102
- ┌─────────────────────┐ ┌─────────────────────┐ ┌─────────────────────┐
103
- │ checks/environment/ │ │ checks/project/ │ │ checks/outputs/ │
104
- │ │ │ │ │ │
105
- │ • checkOsInfo │ │ • checkQuireProject │ │ • checkStaleBuild │
106
- │ • checkCliVersion │ │ • checkDependencies │ │ • checkPdfOutput │
107
- │ • checkNodeVersion │ │ • checkOutdated... │ │ • checkEpubOutput │
108
- │ • checkNpmAvailable │ │ • checkDataFiles │ │ │
109
- │ • checkGitAvailable │ │ │ │ │
110
- │ • checkPrince... │ │ │ │ │
111
- │ • checkPandoc... │ │ │ │ │
112
- └──────────┬──────────┘ └──────────┬──────────┘ └──────────┬──────────┘
113
- │ │ │
114
- ▼ ▼ ▼
115
- ┌──────────────┐ ┌───────────────────┐ ┌──────────────────┐
116
- ┌──────────────┐ ┌───────────────────┐ ┌──────────────────┐
117
- │ constants.js │ │ validators/ │ │ #lib/project/ │
118
- │ │ │ validate-data- │ │ SOURCE_DIRS │
119
- │ DOCS_BASE_URL│ │ files.js │ │ │
120
- │ NODE_VERSION │ └───────────────────┘ └──────────────────┘
121
- │ QUIRE_11TY_ │
122
- │ PACKAGE │
123
- │ STALE_ │
124
- │ THRESHOLDS │
125
- └──────────────┘
126
- ```
127
-
128
- ## Dependencies
129
-
130
- | Module | Purpose |
131
- |--------|---------|
132
- | `#lib/platform.js` | OS detection utilities (getPlatform, Platform enum) |
133
- | `#lib/project/` | Project constants (`DATA_DIR`, `PROJECT_MARKERS`, `SOURCE_DIRECTORIES`) |
134
- | `#lib/git/` | Git availability check |
135
- | `#lib/npm/` | npm availability and registry queries |
136
- | `#lib/conf/config.js` | Configuration (updateChannel for version check, staleThreshold for output checks) |
137
- | `#src/packageConfig.js` | CLI package.json for version info |
138
- | `#src/validators/validate-data-files.js` | YAML validation logic |
139
- | `update-notifier` | Cached CLI update check info |
140
- | `semver` | Semantic version comparison |
141
- | `#lib/doctor/constants.js` | Re-exports from `#lib/constants.js` (DOCS_BASE_URL, REQUIRED_NODE_VERSION, QUIRE_11TY_PACKAGE) + STALE_THRESHOLDS, resolveStaleThreshold |
142
- | `#lib/doctor/formatDuration.js` | Human-readable time formatting |
143
-
144
- ## Check Result Type
145
-
146
- All check functions return a `CheckResult` object:
147
-
148
- ```javascript
149
- /**
150
- * @typedef {Object} CheckResult
151
- * @property {boolean} ok - Whether the check passed
152
- * @property {'error'|'warn'} [level] - Severity level (default: 'error')
153
- * @property {string|null} message - Optional message with details
154
- * @property {string|null} [remediation] - Steps to fix the issue
155
- * @property {string|null} [docsUrl] - Link to relevant documentation
156
- */
157
- ```
158
-
159
- ### Examples
160
-
161
- **Passing check:**
162
- ```javascript
163
- {
164
- ok: true,
165
- message: 'v22.0.0 (>= 22 required)'
166
- }
167
- ```
168
-
169
- **Failing check (error):**
170
- ```javascript
171
- {
172
- ok: false,
173
- message: 'npm not found in PATH',
174
- remediation: 'npm is included with Node.js...',
175
- docsUrl: 'https://quire.getty.edu/docs-v1/install-uninstall/'
176
- }
177
- ```
178
-
179
- **Failing check (warning):**
180
- ```javascript
181
- {
182
- ok: false,
183
- level: 'warn',
184
- message: 'Build output is 2 weeks older than source files',
185
- remediation: 'Run "quire build" to regenerate...',
186
- docsUrl: 'https://quire.getty.edu/docs-v1/quire-commands/'
187
- }
188
- ```
189
-
190
- ## Available Checks
191
-
192
- ### Environment Section
193
-
194
- | Check | Function | Module | Description |
195
- |-------|----------|--------|-------------|
196
- | Operating system | `checkOsInfo()` | `checks/environment/os-info.js` | Reports OS name, version, and architecture |
197
- | Quire CLI version | `checkCliVersion()` | `checks/environment/cli-version.js` | Reports CLI version and available updates |
198
- | Node.js version | `checkNodeVersion()` | `checks/environment/node-version.js` | Verifies Node.js >= 22 (OS-specific remediation) |
199
- | npm available | `checkNpmAvailable()` | `checks/environment/npm-available.js` | Verifies npm in PATH (OS-specific remediation) |
200
- | Git available | `checkGitAvailable()` | `checks/environment/git-available.js` | Verifies git in PATH (OS-specific remediation) |
201
- | PrinceXML | `checkPrinceAvailable()` | `checks/environment/prince-available.js` | Optional PDF engine (warn if missing) |
202
- | Pandoc | `checkPandocAvailable()` | `checks/environment/pandoc-available.js` | Optional EPUB engine (warn if missing) |
203
-
204
- ### Project Section
205
-
206
- | Check | Function | Module | Description |
207
- |-------|----------|--------|-------------|
208
- | Quire project | `checkQuireProject()` | `checks/project/quire-project.js` | Detects project marker files |
209
- | Dependencies | `checkDependencies()` | `checks/project/dependencies.js` | Verifies node_modules exists |
210
- | quire-11ty version | `checkOutdatedQuire11ty()` | `checks/project/quire-11ty.js` | Checks for newer quire-11ty versions |
211
- | Data files | `checkDataFiles()` | `checks/project/data-files.js` | Validates YAML files in content/_data/ |
212
-
213
- ### Outputs Section
214
-
215
- | Check | Function | Module | Description |
216
- |-------|----------|--------|-------------|
217
- | Build status | `checkStaleBuild()` | `checks/outputs/stale-build.js` | Compares source vs build timestamps |
218
- | PDF output | `checkPdfOutput()` | `checks/outputs/pdf-output.js` | Checks PDF freshness vs _site |
219
- | EPUB output | `checkEpubOutput()` | `checks/outputs/epub-output.js` | Checks EPUB freshness vs _site |
220
-
221
- ## Check Behaviors
222
-
223
- ### checkOsInfo
224
-
225
- | Scenario | Result |
226
- |----------|--------|
227
- | macOS | `ok: true` - "macOS 14 (arm64)" |
228
- | Windows | `ok: true` - "Windows (10.0.22621) (x64) - Git for Windows recommended" |
229
- | Linux | `ok: true` - "Linux (5.15.0) (x64)" |
230
-
231
- ### checkCliVersion
232
-
233
- | Scenario | Result |
234
- |----------|--------|
235
- | Up to date | `ok: true` - "v1.0.0-rc.33 (up to date)" |
236
- | Update available | `ok: false, level: warn` - "v1.0.0-rc.30 installed, v1.0.0-rc.33 available" |
237
- | No cached update info | `ok: true` - "v1.0.0-rc.33" (no "up to date" suffix) |
238
-
239
- ### checkNodeVersion
240
-
241
- | Scenario | Result |
242
- |----------|--------|
243
- | Node.js >= 22 | `ok: true` - "v22.0.0 (>= 22 required)" |
244
- | Node.js < 22 | `ok: false` - with OS-specific installation instructions |
245
-
246
- Remediation varies by platform:
247
- - **macOS**: nvm, Homebrew, or nodejs.org
248
- - **Windows**: nvm-windows, winget, or nodejs.org
249
- - **Linux**: nvm, apt, or nodejs.org
250
-
251
- ### checkNpmAvailable
252
-
253
- | Scenario | Result |
254
- |----------|--------|
255
- | npm in PATH | `ok: true` - no message |
256
- | npm not found | `ok: false` - "npm not found in PATH" with OS-specific troubleshooting |
257
-
258
- Remediation varies by platform:
259
- - **macOS**: nvm use, brew reinstall
260
- - **Windows**: Check PATH includes %APPDATA%\npm
261
- - **Linux**: nvm use, check PATH
262
-
263
- ### checkGitAvailable
264
-
265
- | Scenario | Result |
266
- |----------|--------|
267
- | git in PATH | `ok: true` - no message |
268
- | git not found | `ok: false` - "Git not found in PATH" with OS-specific installation |
269
-
270
- Remediation and docs URL vary by platform:
271
- - **macOS**: xcode-select --install or Homebrew
272
- - **Windows**: git-scm.com/download/win or winget
273
- - **Linux**: apt, dnf, or pacman
274
-
275
- ### checkPrinceAvailable (Optional Engine)
276
-
277
- | Scenario | Result |
278
- |----------|--------|
279
- | prince in PATH | `ok: true` - "installed" with path details |
280
- | prince not found | `ok: false, level: warn` - "not found (optional)" with OS-specific installation |
281
-
282
- Remediation varies by platform:
283
- - **macOS**: `brew install --cask prince` or princexml.com
284
- - **Windows**: `winget install` or princexml.com
285
- - **Linux**: Download from princexml.com
286
-
287
- ### checkPandocAvailable (Optional Engine)
288
-
289
- | Scenario | Result |
290
- |----------|--------|
291
- | pandoc in PATH | `ok: true` - "installed" with path details |
292
- | pandoc not found | `ok: false, level: warn` - "not found (optional)" with OS-specific installation |
293
-
294
- Remediation varies by platform:
295
- - **macOS**: `brew install pandoc` or pandoc.org
296
- - **Windows**: `winget install` or pandoc.org
297
- - **Linux**: `apt install pandoc`, `dnf install pandoc`, or pandoc.org
298
-
299
- ### checkQuireProject
300
-
301
- | Scenario | Result |
302
- |----------|--------|
303
- | Marker file found | `ok: true` - "Detected via .quire" |
304
- | No marker files | `ok: false` - "No Quire project marker found" |
305
-
306
- ### checkDependencies
307
-
308
- | Scenario | Result |
309
- |----------|--------|
310
- | No package.json | `ok: true` - "No package.json (not in project directory)" |
311
- | Has node_modules | `ok: true` - no message |
312
- | Missing node_modules | `ok: false` - "node_modules not found" |
313
-
314
- ### checkOutdatedQuire11ty
315
-
316
- | Scenario | Result |
317
- |----------|--------|
318
- | Not in project | `ok: true` - "quire-11ty not installed (not in project)" |
319
- | Up to date | `ok: true` - "v1.0.0-rc.33 (up to date)" |
320
- | Outdated | `ok: false, level: warn` - "v1.0.0-rc.30 installed, v1.0.0-rc.33 available" |
321
- | Can't read version | `ok: false, level: warn` - "Could not read installed quire-11ty version" |
322
- | Network error | `ok: true` - "v1.0.0-rc.30 (could not check for updates)" |
323
-
324
- ### checkDataFiles
325
-
326
- | Scenario | Result |
327
- |----------|--------|
328
- | Not in project | `ok: true` - "No content/_data directory (not in project)" |
329
- | All files valid | `ok: true` - "3 files validated" |
330
- | Missing required file | `ok: false, level: warn` - "1 issue in data files" |
331
- | YAML syntax error | `ok: false, level: warn` - with error details |
332
- | Duplicate IDs | `ok: false, level: warn` - with duplicate ID list |
333
-
334
- ### checkStaleBuild
335
-
336
- Staleness is determined by comparing source file timestamps against the `_site` build directory. A warning is only triggered when the time difference exceeds the configured `staleThreshold` setting (default: `HOURLY` = 60 minutes).
337
-
338
- | Scenario | Result |
339
- |----------|--------|
340
- | No _site directory | `ok: true` - "No build output yet (run quire build)" |
341
- | Build up to date | `ok: true` - "Build output is up to date" |
342
- | Build stale within threshold | `ok: true` - "Build output is up to date" |
343
- | Build stale beyond threshold | `ok: false, level: warn` - "Build output is 2 weeks older than source files" |
344
-
345
- ### checkPdfOutput
346
-
347
- Uses the same `staleThreshold` setting to compare PDF timestamps against `_site`. Loads project config to resolve config-aware PDF output paths.
348
-
349
- | Scenario | Result |
350
- |----------|--------|
351
- | No PDF files exist | `ok: true` - "No PDF output (run quire pdf to generate)" |
352
- | PDF exists, no _site | `ok: true` - "pagedjs.pdf exists (no _site to compare)" |
353
- | PDF up to date | `ok: true` - "pagedjs.pdf up to date" |
354
- | PDF stale within threshold | `ok: true` - "pagedjs.pdf up to date" |
355
- | PDF stale beyond threshold | `ok: false, level: warn` - "pagedjs.pdf is 2 hours older than _site" |
356
-
357
- ### checkEpubOutput
358
-
359
- Uses the same `staleThreshold` setting to compare EPUB timestamps against `_site`.
360
-
361
- | Scenario | Result |
362
- |----------|--------|
363
- | No EPUB files exist | `ok: true` - "No EPUB output (run quire epub to generate)" |
364
- | EPUB exists, no _site | `ok: true` - "epubjs.epub exists (no _site to compare)" |
365
- | EPUB up to date | `ok: true` - "epubjs.epub up to date" |
366
- | EPUB stale within threshold | `ok: true` - "epubjs.epub up to date" |
367
- | EPUB stale beyond threshold | `ok: false, level: warn` - "epubjs.epub is 2 hours older than _site" |
368
-
369
- ### Stale Threshold Configuration
370
-
371
- All output checks share the `staleThreshold` setting from `#lib/conf/config.js`. The threshold determines how much time difference is tolerated before flagging an output as stale.
372
-
373
- | Setting | Duration | Use Case |
374
- |---------|----------|----------|
375
- | `ZERO` | 0 minutes | Any time difference triggers a warning |
376
- | `SHORT` | 5 minutes | Quick iteration workflows |
377
- | `HOURLY` | 60 minutes | Default — within-session tolerance |
378
- | `DAILY` | 12 hours | Multi-session or batch workflows |
379
- | `NEVER` | Disabled | Never warn about stale outputs |
380
-
381
- ```sh
382
- ❯ quire config set staleThreshold DAILY
383
- ```
384
-
385
- The threshold is resolved by `resolveStaleThreshold()` in `constants.js`, which maps the setting name to milliseconds and falls back to `HOURLY` for unrecognized values.
386
-
387
- ## Exports
388
-
389
- ```javascript
390
- // Individual check functions (re-exported from domain modules)
391
- export { checkOsInfo }
392
- export { checkCliVersion }
393
- export { checkNodeVersion }
394
- export { checkNpmAvailable }
395
- export { checkGitAvailable }
396
- export { checkPrinceAvailable }
397
- export { checkPandocAvailable }
398
- export { checkQuireProject }
399
- export { checkDependencies }
400
- export { checkOutdatedQuire11ty }
401
- export { checkDataFiles }
402
- export { checkStaleBuild }
403
- export { checkPdfOutput }
404
- export { checkEpubOutput }
405
-
406
- // Constants
407
- export { DOCS_BASE_URL, REQUIRED_NODE_VERSION, QUIRE_11TY_PACKAGE }
408
- export { STALE_THRESHOLDS, resolveStaleThreshold }
409
-
410
- // Check collections
411
- export { checks } // Flat array of all checks (14 checks)
412
- export { checkSections } // Checks organized by section (3 sections)
413
-
414
- // Runners
415
- export { runAllChecks } // Run all, return flat results
416
- export { runAllChecksWithSections } // Run all, return by section
417
- ```
418
-
419
- ## Adding a New Check
420
-
421
- ### 1. Determine the domain
422
-
423
- - **environment/**: System prerequisites (OS info, CLI version, Node.js, npm, Git)
424
- - **project/**: Project configuration and dependencies
425
- - **outputs/**: Build artifacts and generated files
426
-
427
- ### 2. Create the check file
428
-
429
- ```javascript
430
- // checks/project/my-check.js
431
- import { DOCS_BASE_URL } from '#lib/doctor/constants.js'
432
- import createDebug from '#debug'
433
-
434
- const debug = createDebug('lib:doctor:my-check')
435
-
436
- /**
437
- * Check description here
438
- * @returns {import('../../index.js').CheckResult}
439
- */
440
- export function checkMyThing() {
441
- debug('Running my check')
442
-
443
- // Perform check logic
444
- const ok = /* condition */
445
-
446
- if (ok) {
447
- return {
448
- ok: true,
449
- message: 'Success message or null',
450
- }
451
- }
452
-
453
- return {
454
- ok: false,
455
- level: 'warn', // Optional: 'warn' for non-blocking issues
456
- message: 'What went wrong',
457
- remediation: `How to fix:\n • Step 1\n • Step 2`,
458
- docsUrl: `${DOCS_BASE_URL}/relevant-page/`,
459
- }
460
- }
461
-
462
- export default checkMyThing
463
- ```
464
-
465
- ### 3. Create the test file
466
-
467
- ```javascript
468
- // checks/project/my-check.test.js
469
- import test from 'ava'
470
- import sinon from 'sinon'
471
- import esmock from 'esmock'
472
-
473
- test.beforeEach((t) => {
474
- t.context.sandbox = sinon.createSandbox()
475
- })
476
-
477
- test.afterEach.always((t) => {
478
- t.context.sandbox.restore()
479
- })
480
-
481
- test('checkMyThing returns ok when condition met', async (t) => {
482
- const { checkMyThing } = await esmock('./my-check.js', {
483
- // Mock dependencies
484
- })
485
-
486
- const result = checkMyThing()
487
-
488
- t.true(result.ok)
489
- })
490
-
491
- test('checkMyThing returns not ok when condition fails', async (t) => {
492
- const { checkMyThing } = await esmock('./my-check.js', {
493
- // Mock dependencies for failure case
494
- })
495
-
496
- const result = checkMyThing()
497
-
498
- t.false(result.ok)
499
- t.truthy(result.remediation)
500
- t.truthy(result.docsUrl)
501
- })
502
- ```
503
-
504
- ### 4. Export from domain barrel
505
-
506
- ```javascript
507
- // checks/project/index.js
508
- export { checkQuireProject } from './quire-project.js'
509
- export { checkDependencies } from './dependencies.js'
510
- export { checkOutdatedQuire11ty } from './quire-11ty.js'
511
- export { checkDataFiles } from './data-files.js'
512
- export { checkMyThing } from './my-check.js' // Add new export
513
- ```
514
-
515
- ### 5. Add to main index.js
516
-
517
- ```javascript
518
- // In imports
519
- import {
520
- checkQuireProject,
521
- checkDependencies,
522
- checkOutdatedQuire11ty,
523
- checkDataFiles,
524
- checkMyThing, // Add new import
525
- } from './checks/project/index.js'
526
-
527
- // In re-exports
528
- export {
529
- // ... existing exports
530
- checkMyThing,
531
- }
532
-
533
- // In checkSections
534
- export const checkSections = [
535
- // ...
536
- {
537
- name: 'Project',
538
- checks: [
539
- // ... existing checks
540
- { name: 'My thing', check: checkMyThing },
541
- ],
542
- },
543
- ]
544
-
545
- // In checks (flat list)
546
- export const checks = [
547
- // ... existing checks
548
- { name: 'My thing', check: checkMyThing },
549
- ]
550
-
551
- // In default export
552
- export default {
553
- // ... existing exports
554
- checkMyThing,
555
- }
556
- ```
557
-
558
- ### 6. Update test count in index.test.js
559
-
560
- Update the assertions for check counts if needed.
561
-
562
- ## Design Principles
563
-
564
- ### Domain Organization
565
-
566
- Checks are organized by domain rather than technical concern:
567
- - **environment**: "Do I have what I need to run Quire?"
568
- - **project**: "Is my project properly configured?"
569
- - **outputs**: "Are my build outputs valid?"
570
-
571
- ### Check Independence
572
-
573
- Each check should be independent and not depend on the results of other checks. The runner executes all checks regardless of previous failures.
574
-
575
- ### Co-located Tests
576
-
577
- Each check file has its corresponding test file in the same directory:
578
- ```
579
- my-check.js
580
- my-check.test.js
581
- ```
582
-
583
- ### Graceful Degradation
584
-
585
- Checks should handle missing directories/files gracefully:
586
-
587
- ```javascript
588
- // Skip check if not in a project
589
- if (!fs.existsSync(DATA_DIR)) {
590
- return {
591
- ok: true,
592
- message: 'No content/_data directory (not in project)',
593
- }
594
- }
595
- ```
596
-
597
- ### Actionable Remediation
598
-
599
- Every failing check should include:
600
- 1. **Clear message** - What's wrong
601
- 2. **Remediation steps** - How to fix it
602
- 3. **Documentation link** - Where to learn more
603
-
604
- ## Testing
605
-
606
- Tests use AVA with esmock for ESM module mocking.
607
-
608
- ### Running Tests
609
-
610
- ```bash
611
- # All doctor tests
612
- npx ava 'src/lib/doctor/**/*.test.js'
613
-
614
- # Main integration tests
615
- npx ava src/lib/doctor/index.test.js
616
-
617
- # Domain-specific tests
618
- npx ava src/lib/doctor/checks/environment/*.test.js
619
- npx ava src/lib/doctor/checks/project/*.test.js
620
- npx ava src/lib/doctor/checks/outputs/*.test.js
621
-
622
- # Duration formatting tests
623
- npx ava src/lib/doctor/formatDuration.test.js
624
-
625
- # Related validator tests
626
- npx ava src/validators/validate-data-files.test.js
627
- ```
628
-
629
- ### Test Patterns
630
-
631
- **Mocking dependencies in domain checks:**
632
- ```javascript
633
- const { checkDataFiles } = await esmock('./data-files.js', {
634
- '#src/validators/validate-data-files.js': {
635
- validateDataFiles: sandbox.stub().returns({
636
- valid: true,
637
- errors: [],
638
- fileCount: 1,
639
- files: [],
640
- }),
641
- },
642
- })
643
- ```
644
-
645
- **Mocking filesystem:**
646
- ```javascript
647
- const { checkStaleBuild } = await esmock('./stale-build.js', {
648
- 'node:fs': {
649
- existsSync: sandbox.stub().returns(true),
650
- statSync: sandbox.stub().returns({ mtimeMs: Date.now() }),
651
- readdirSync: sandbox.stub().returns([]),
652
- },
653
- })
654
- ```
655
-
656
- ## Files Summary
657
-
658
- | File | Description |
659
- |------|-------------|
660
- | `index.js` | Barrel export, runners, checkSections |
661
- | `index.test.js` | Integration tests for runners and sections |
662
- | `constants.js` | Re-exports from `#lib/constants.js` + STALE_THRESHOLDS, resolveStaleThreshold |
663
- | `formatDuration.js` | Time duration formatting utility |
664
- | `formatDuration.test.js` | Duration formatting tests |
665
- | `checks/environment/` | Environment prerequisite checks (7 checks: os-info, cli-version, node-version, npm-available, git-available, prince-available, pandoc-available) |
666
- | `checks/project/` | Project configuration checks (4 checks) |
667
- | `checks/outputs/` | Build artifact checks (3 checks: stale-build, pdf-output, epub-output) |