@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.
- package/CHANGELOG.md +0 -36
- package/README.md +0 -9
- package/bin/cli.js +1 -46
- package/package.json +10 -27
- package/src/Command.js +6 -26
- package/src/commands/README.md +122 -213
- package/src/commands/build.js +37 -45
- package/src/commands/clean.js +19 -33
- package/src/commands/conf.js +43 -0
- package/src/commands/create.js +14 -42
- package/src/commands/epub.js +31 -67
- package/src/commands/index.js +2 -9
- package/src/commands/info.js +86 -88
- package/src/commands/pdf.js +82 -63
- package/src/commands/preview.js +31 -32
- package/src/commands/validate.js +20 -64
- package/src/commands/version.js +43 -0
- package/src/errors/validation/validation-error.js +11 -20
- package/src/helpers/clean.js +1 -1
- package/src/helpers/is-quire.js +31 -0
- package/src/helpers/test-cwd.js +6 -5
- package/src/helpers/which.js +4 -10
- package/src/lib/11ty/README.md +19 -135
- package/src/lib/11ty/api.js +93 -235
- package/src/lib/11ty/cli.js +37 -112
- package/src/lib/11ty/index.js +5 -64
- package/src/lib/11ty/paths.js +103 -0
- package/src/lib/README.md +0 -330
- package/src/lib/conf/README.md +69 -86
- package/src/lib/conf/config.js +3 -5
- package/src/lib/conf/defaults.js +0 -65
- package/src/lib/conf/schema.js +9 -103
- package/src/lib/epub/README.md +2 -133
- package/src/lib/epub/epub.js +11 -36
- package/src/lib/epub/index.js +21 -111
- package/src/lib/epub/pandoc.js +4 -33
- package/src/lib/git/README.md +2 -151
- package/src/lib/git/index.js +13 -217
- package/src/lib/i18n/README.md +3 -0
- package/src/lib/i18n/config.js +53 -0
- package/src/lib/i18n/index.js +43 -0
- package/src/lib/i18n/localeService.js +58 -0
- package/src/lib/pdf/README.md +0 -131
- package/src/lib/pdf/index.js +21 -124
- package/src/lib/pdf/paged.js +52 -100
- package/src/lib/pdf/prince.js +37 -115
- package/src/lib/pdf/split.js +33 -61
- package/src/lib/quire/README.md +19 -0
- package/src/lib/quire/index.js +353 -0
- package/src/lib/reporter/README.md +2 -211
- package/src/lib/reporter/index.js +0 -607
- package/src/main.js +48 -221
- package/src/packageConfig.js +0 -17
- package/src/validators/utils.js +1 -2
- package/man/quire.1 +0 -341
- package/man/quire.1.md +0 -232
- package/schemas/config.schema.json +0 -194
- package/schemas/figures.schema.json +0 -56
- package/schemas/layout.schema.json +0 -5
- package/schemas/objects.schema.json +0 -62
- package/schemas/publication.schema.json +0 -140
- package/schemas/references.schema.json +0 -29
- package/src/Command.spec.js +0 -99
- package/src/commands/build.spec.js +0 -113
- package/src/commands/build.test.js +0 -397
- package/src/commands/clean.spec.js +0 -118
- package/src/commands/clean.test.js +0 -382
- package/src/commands/config.js +0 -238
- package/src/commands/config.spec.js +0 -107
- package/src/commands/config.test.js +0 -845
- package/src/commands/create.spec.js +0 -112
- package/src/commands/create.test.js +0 -415
- package/src/commands/doctor.js +0 -251
- package/src/commands/doctor.spec.js +0 -115
- package/src/commands/doctor.test.js +0 -1409
- package/src/commands/epub.spec.js +0 -114
- package/src/commands/epub.test.js +0 -503
- package/src/commands/help.js +0 -60
- package/src/commands/help.test.js +0 -132
- package/src/commands/info.spec.js +0 -72
- package/src/commands/info.test.js +0 -512
- package/src/commands/pdf.spec.js +0 -114
- package/src/commands/pdf.test.js +0 -464
- package/src/commands/preview.spec.js +0 -97
- package/src/commands/preview.test.js +0 -250
- package/src/commands/use.js +0 -56
- package/src/commands/use.spec.js +0 -61
- package/src/commands/use.test.js +0 -280
- package/src/commands/validate.spec.js +0 -90
- package/src/commands/validate.test.js +0 -378
- package/src/commands/workflows.js +0 -70
- package/src/errors/build/build-failed-error.js +0 -19
- package/src/errors/build/config-field-missing-error.js +0 -20
- package/src/errors/build/config-file-not-found-error.js +0 -20
- package/src/errors/build/index.js +0 -11
- package/src/errors/help/help-topic-not-found-error.js +0 -30
- package/src/errors/help/index.js +0 -8
- package/src/errors/index.js +0 -58
- package/src/errors/input/index.js +0 -8
- package/src/errors/input/invalid-input-error.js +0 -21
- package/src/errors/install/dependency-install-error.js +0 -19
- package/src/errors/install/directory-not-empty-error.js +0 -25
- package/src/errors/install/index.js +0 -12
- package/src/errors/install/invalid-path-error.js +0 -31
- package/src/errors/install/invalid-starter-error.js +0 -27
- package/src/errors/install/version-not-found-error.js +0 -35
- package/src/errors/output/epub-generation-error.js +0 -19
- package/src/errors/output/index.js +0 -14
- package/src/errors/output/invalid-epub-library-error.js +0 -20
- package/src/errors/output/invalid-pdf-library-error.js +0 -20
- package/src/errors/output/missing-build-output-error.js +0 -21
- package/src/errors/output/pdf-generation-error.js +0 -24
- package/src/errors/output/tool-not-found-error.js +0 -37
- package/src/errors/project/index.js +0 -10
- package/src/errors/project/not-in-project-error.js +0 -20
- package/src/errors/project/project-create-error.js +0 -21
- package/src/errors/quire-error.js +0 -27
- package/src/errors/validation/index.js +0 -3
- package/src/errors/validation/unknown-config-key-error.js +0 -27
- package/src/errors/validation/unknown-config-operation-error.js +0 -24
- package/src/helpers/docs-url.js +0 -32
- package/src/helpers/pager.js +0 -59
- package/src/helpers/pager.test.js +0 -85
- package/src/helpers/suggest-similar.js +0 -124
- package/src/helpers/suggest-similar.test.js +0 -108
- package/src/helpers/test-cwd.test.js +0 -192
- package/src/lib/11ty/index.test.js +0 -655
- package/src/lib/commander/index.js +0 -103
- package/src/lib/commander/index.test.js +0 -86
- package/src/lib/commander/options.js +0 -237
- package/src/lib/commander/options.test.js +0 -205
- package/src/lib/conf/build-status.js +0 -103
- package/src/lib/conf/build-status.test.js +0 -247
- package/src/lib/conf/config.test.js +0 -281
- package/src/lib/conf/format.js +0 -60
- package/src/lib/conf/format.test.js +0 -106
- package/src/lib/conf/helpers.js +0 -91
- package/src/lib/conf/helpers.test.js +0 -136
- package/src/lib/conf/index.js +0 -22
- package/src/lib/constants.js +0 -28
- package/src/lib/doctor/README.md +0 -667
- package/src/lib/doctor/checks/environment/cli-version.js +0 -62
- package/src/lib/doctor/checks/environment/cli-version.test.js +0 -132
- package/src/lib/doctor/checks/environment/git-available.js +0 -77
- package/src/lib/doctor/checks/environment/git-available.test.js +0 -52
- package/src/lib/doctor/checks/environment/index.js +0 -13
- package/src/lib/doctor/checks/environment/node-version.js +0 -66
- package/src/lib/doctor/checks/environment/node-version.test.js +0 -17
- package/src/lib/doctor/checks/environment/npm-available.js +0 -66
- package/src/lib/doctor/checks/environment/npm-available.test.js +0 -52
- package/src/lib/doctor/checks/environment/os-info.js +0 -48
- package/src/lib/doctor/checks/environment/os-info.test.js +0 -81
- package/src/lib/doctor/checks/environment/runtime-info.js +0 -51
- package/src/lib/doctor/checks/environment/runtime-info.test.js +0 -132
- package/src/lib/doctor/checks/outputs/epub-output.js +0 -119
- package/src/lib/doctor/checks/outputs/epub-output.test.js +0 -277
- package/src/lib/doctor/checks/outputs/index.js +0 -10
- package/src/lib/doctor/checks/outputs/pdf-output.js +0 -144
- package/src/lib/doctor/checks/outputs/pdf-output.test.js +0 -377
- package/src/lib/doctor/checks/outputs/stale-build.js +0 -122
- package/src/lib/doctor/checks/outputs/stale-build.test.js +0 -282
- package/src/lib/doctor/checks/project/data-files.js +0 -56
- package/src/lib/doctor/checks/project/data-files.test.js +0 -125
- package/src/lib/doctor/checks/project/dependencies.js +0 -53
- package/src/lib/doctor/checks/project/dependencies.test.js +0 -71
- package/src/lib/doctor/checks/project/index.js +0 -11
- package/src/lib/doctor/checks/project/quire-11ty.js +0 -98
- package/src/lib/doctor/checks/project/quire-11ty.test.js +0 -170
- package/src/lib/doctor/checks/project/quire-project.js +0 -38
- package/src/lib/doctor/checks/project/quire-project.test.js +0 -47
- package/src/lib/doctor/checks/tools/index.js +0 -10
- package/src/lib/doctor/checks/tools/pandoc-available.js +0 -82
- package/src/lib/doctor/checks/tools/pandoc-available.test.js +0 -73
- package/src/lib/doctor/checks/tools/prince-available.js +0 -81
- package/src/lib/doctor/checks/tools/prince-available.test.js +0 -73
- package/src/lib/doctor/constants.js +0 -39
- package/src/lib/doctor/formatDuration.js +0 -108
- package/src/lib/doctor/formatDuration.test.js +0 -76
- package/src/lib/doctor/formatters/human.js +0 -257
- package/src/lib/doctor/formatters/human.test.js +0 -463
- package/src/lib/doctor/formatters/index.js +0 -8
- package/src/lib/doctor/formatters/json.js +0 -78
- package/src/lib/doctor/formatters/json.test.js +0 -174
- package/src/lib/doctor/formatters/shared.js +0 -129
- package/src/lib/doctor/formatters/shared.test.js +0 -194
- package/src/lib/doctor/index.js +0 -271
- package/src/lib/doctor/index.test.js +0 -797
- package/src/lib/epub/engines.js +0 -46
- package/src/lib/epub/index.test.js +0 -518
- package/src/lib/epub/pandoc.test.js +0 -122
- package/src/lib/epub/schema.js +0 -21
- package/src/lib/error/README.md +0 -170
- package/src/lib/error/handler.js +0 -107
- package/src/lib/git/index.spec.js +0 -80
- package/src/lib/git/index.test.js +0 -453
- package/src/lib/help/frontmatter.js +0 -77
- package/src/lib/help/frontmatter.test.js +0 -139
- package/src/lib/help/index.js +0 -146
- package/src/lib/help/index.test.js +0 -188
- package/src/lib/help/topics/configuration.md +0 -77
- package/src/lib/help/topics/debugging.md +0 -69
- package/src/lib/help/topics/epub.md +0 -74
- package/src/lib/help/topics/pdf.md +0 -74
- package/src/lib/help/topics/publishing.md +0 -80
- package/src/lib/help/topics/workflows.md +0 -50
- package/src/lib/installer/index.js +0 -309
- package/src/lib/installer/index.spec.js +0 -83
- package/src/lib/installer/index.test.js +0 -545
- package/src/lib/logger/README.md +0 -424
- package/src/lib/logger/debug.js +0 -132
- package/src/lib/logger/debug.spec.js +0 -130
- package/src/lib/logger/debug.test.js +0 -128
- package/src/lib/logger/index.js +0 -228
- package/src/lib/logger/index.spec.js +0 -131
- package/src/lib/logger/index.test.js +0 -578
- package/src/lib/npm/README.md +0 -127
- package/src/lib/npm/index.js +0 -198
- package/src/lib/npm/index.spec.js +0 -60
- package/src/lib/npm/index.test.js +0 -355
- package/src/lib/pdf/engines.js +0 -46
- package/src/lib/pdf/index.test.js +0 -708
- package/src/lib/pdf/paged.test.js +0 -366
- package/src/lib/pdf/prince.test.js +0 -202
- package/src/lib/pdf/schema.js +0 -21
- package/src/lib/pdf/split.test.js +0 -445
- package/src/lib/platform.js +0 -95
- package/src/lib/process/manager.js +0 -110
- package/src/lib/process/manager.test.js +0 -55
- package/src/lib/project/build.js +0 -162
- package/src/lib/project/build.test.js +0 -275
- package/src/lib/project/config.js +0 -48
- package/src/lib/project/config.test.js +0 -134
- package/src/lib/project/detect.js +0 -47
- package/src/lib/project/detect.test.js +0 -157
- package/src/lib/project/index.js +0 -56
- package/src/lib/project/output-paths.js +0 -87
- package/src/lib/project/output-paths.test.js +0 -66
- package/src/lib/project/paths.js +0 -272
- package/src/lib/project/version.js +0 -110
- package/src/lib/project/version.test.js +0 -350
- package/src/lib/reporter/index.test.js +0 -862
- package/src/main.spec.js +0 -61
- package/src/main.test.js +0 -347
- package/src/validators/validate-data-files.js +0 -154
- package/src/validators/validate-data-files.test.js +0 -217
|
@@ -1,607 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Reporter module for CLI progress feedback
|
|
3
|
-
*
|
|
4
|
-
* Provides a consistent interface for progress indicators (spinners) with
|
|
5
|
-
* unified handling of quiet/verbose modes and testability. Follows the
|
|
6
|
-
* singleton pattern like lib/logger.js for easy mocking in tests.
|
|
7
|
-
*
|
|
8
|
-
* ## Output Modes
|
|
9
|
-
*
|
|
10
|
-
* The reporter supports three output modes controlled by command options:
|
|
11
|
-
*
|
|
12
|
-
* | Mode | Flag | Behavior |
|
|
13
|
-
* |------|------|----------|
|
|
14
|
-
* | Default | (none) | Show spinner with basic status |
|
|
15
|
-
* | Quiet | `-q, --quiet` | Suppress all output (for CI/scripts) |
|
|
16
|
-
* | Verbose | `-v, --verbose` | Show detailed progress with paths, timing |
|
|
17
|
-
* | Reduced Motion | `--reduced-motion` | Static text, no animation, no line overwriting |
|
|
18
|
-
*
|
|
19
|
-
* Note: `--debug` is handled separately and enables DEBUG namespace logging,
|
|
20
|
-
* not reporter output. Use verbose mode for detailed user-facing output.
|
|
21
|
-
*
|
|
22
|
-
* ## Reduced Motion
|
|
23
|
-
*
|
|
24
|
-
* When reduced motion is enabled (via `--reduced-motion` flag, `REDUCED_MOTION`
|
|
25
|
-
* environment variable, or `reducedMotion` config setting), the reporter:
|
|
26
|
-
* - Prints static text instead of animated spinners
|
|
27
|
-
* - Outputs each stage on a new line (no line overwriting)
|
|
28
|
-
* - Still shows status symbols (✔ ✖ ⚠ ℹ) for completion states
|
|
29
|
-
*
|
|
30
|
-
* This mode is designed for screen reader users and environments where
|
|
31
|
-
* terminal animation is problematic.
|
|
32
|
-
*
|
|
33
|
-
* ## Config Defaults
|
|
34
|
-
*
|
|
35
|
-
* Users can set default values via `quire settings`:
|
|
36
|
-
* - `quire settings set verbose true` - Always run in verbose mode
|
|
37
|
-
* - `quire settings set reducedMotion true` - Disable spinner animation
|
|
38
|
-
*
|
|
39
|
-
* CLI flags override config settings. Use `--no-verbose` to disable verbose
|
|
40
|
-
* mode even when enabled in config.
|
|
41
|
-
*
|
|
42
|
-
* @example Production usage
|
|
43
|
-
* import reporter from '#lib/reporter/index.js'
|
|
44
|
-
* reporter.start('Building site...')
|
|
45
|
-
* await build()
|
|
46
|
-
* reporter.succeed('Build complete')
|
|
47
|
-
*
|
|
48
|
-
* @example Multi-phase operation
|
|
49
|
-
* reporter.start('Cloning starter...')
|
|
50
|
-
* await git.clone()
|
|
51
|
-
* reporter.update('Installing dependencies...')
|
|
52
|
-
* await npm.install()
|
|
53
|
-
* reporter.succeed('Project created')
|
|
54
|
-
*
|
|
55
|
-
* @example Error handling
|
|
56
|
-
* reporter.start('Generating PDF...')
|
|
57
|
-
* try {
|
|
58
|
-
* await generatePdf()
|
|
59
|
-
* reporter.succeed()
|
|
60
|
-
* } catch (error) {
|
|
61
|
-
* reporter.fail('PDF generation failed')
|
|
62
|
-
* throw error
|
|
63
|
-
* }
|
|
64
|
-
*
|
|
65
|
-
* @example Verbose mode with details
|
|
66
|
-
* reporter.configure({ verbose: true })
|
|
67
|
-
* reporter.start('Building site...')
|
|
68
|
-
* reporter.detail('Output: _site/')
|
|
69
|
-
* reporter.detail('Pages: 45')
|
|
70
|
-
* reporter.succeed('Build complete')
|
|
71
|
-
* // Shows:
|
|
72
|
-
* // ⠋ Building site...
|
|
73
|
-
* // Output: _site/
|
|
74
|
-
* // Pages: 45
|
|
75
|
-
* // ✔ Build complete
|
|
76
|
-
*
|
|
77
|
-
* @example Test mocking
|
|
78
|
-
* const mockReporter = {
|
|
79
|
-
* start: sandbox.stub(),
|
|
80
|
-
* succeed: sandbox.stub(),
|
|
81
|
-
* fail: sandbox.stub(),
|
|
82
|
-
* configure: sandbox.stub(),
|
|
83
|
-
* }
|
|
84
|
-
* const MyCommand = await esmock('./mycommand.js', {
|
|
85
|
-
* '#lib/reporter/index.js': { default: mockReporter }
|
|
86
|
-
* })
|
|
87
|
-
*
|
|
88
|
-
* @see https://github.com/sindresorhus/ora
|
|
89
|
-
* @module lib/reporter
|
|
90
|
-
*/
|
|
91
|
-
import ora from 'ora'
|
|
92
|
-
import createDebug from '#debug'
|
|
93
|
-
import config from '#lib/conf/config.js'
|
|
94
|
-
|
|
95
|
-
const debug = createDebug('lib:reporter')
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Status symbols for reduced motion output
|
|
99
|
-
*
|
|
100
|
-
* These match the symbols used by ora for visual consistency,
|
|
101
|
-
* ensuring the same information is conveyed with or without animation.
|
|
102
|
-
* @private
|
|
103
|
-
*/
|
|
104
|
-
const STATUS_SYMBOLS = {
|
|
105
|
-
start: '–',
|
|
106
|
-
succeed: '✔',
|
|
107
|
-
fail: '✖',
|
|
108
|
-
warn: '⚠',
|
|
109
|
-
info: 'ℹ',
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Reporter class for CLI progress feedback
|
|
114
|
-
*
|
|
115
|
-
* Wraps ora spinner with additional features:
|
|
116
|
-
* - Respects --quiet and --json flags
|
|
117
|
-
* - Supports reduced motion (static text, no line overwriting)
|
|
118
|
-
* - Supports elapsed time display
|
|
119
|
-
* - Provides consistent API across commands
|
|
120
|
-
*/
|
|
121
|
-
class Reporter {
|
|
122
|
-
/** @type {import('ora').Ora|null} */
|
|
123
|
-
#spinner = null
|
|
124
|
-
|
|
125
|
-
/** @type {boolean} */
|
|
126
|
-
#quiet = false
|
|
127
|
-
|
|
128
|
-
/** @type {boolean} */
|
|
129
|
-
#json = false
|
|
130
|
-
|
|
131
|
-
/** @type {boolean} */
|
|
132
|
-
#verbose = false
|
|
133
|
-
|
|
134
|
-
/** @type {number|null} */
|
|
135
|
-
#startTime = null
|
|
136
|
-
|
|
137
|
-
/** @type {NodeJS.Timeout|null} */
|
|
138
|
-
#elapsedInterval = null
|
|
139
|
-
|
|
140
|
-
/** @type {string} */
|
|
141
|
-
#baseText = ''
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Check if reduced motion mode is active
|
|
145
|
-
*
|
|
146
|
-
* Reduced motion disables spinner animation and line overwriting.
|
|
147
|
-
* Reads from the REDUCED_MOTION environment variable, which is set by:
|
|
148
|
-
* - `--reduced-motion` CLI flag (via preAction hook)
|
|
149
|
-
* - `REDUCED_MOTION=1` shell environment variable
|
|
150
|
-
* - `reducedMotion: true` config setting (via bin/cli.js)
|
|
151
|
-
*
|
|
152
|
-
* @private
|
|
153
|
-
* @returns {boolean}
|
|
154
|
-
*/
|
|
155
|
-
#isReducedMotion() {
|
|
156
|
-
return Boolean(process.env.REDUCED_MOTION)
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* Configure reporter for current command context
|
|
161
|
-
*
|
|
162
|
-
* Call this at the start of command action() to respect command options.
|
|
163
|
-
* CLI flags take precedence over config settings.
|
|
164
|
-
*
|
|
165
|
-
* @param {Object} options - Command options
|
|
166
|
-
* @param {boolean} [options.quiet] - Suppress all output (no config default)
|
|
167
|
-
* @param {boolean} [options.json] - JSON output mode (suppress spinner)
|
|
168
|
-
* @param {boolean} [options.verbose] - Verbose output mode (falls back to config.verbose)
|
|
169
|
-
* @returns {Reporter} this instance for chaining
|
|
170
|
-
*
|
|
171
|
-
* @example
|
|
172
|
-
* async action(options) {
|
|
173
|
-
* reporter.configure(options)
|
|
174
|
-
* reporter.start('Working...')
|
|
175
|
-
* }
|
|
176
|
-
*/
|
|
177
|
-
configure(options = {}) {
|
|
178
|
-
this.#quiet = options.quiet || false
|
|
179
|
-
this.#json = options.json || false
|
|
180
|
-
// CLI flag takes precedence, then config setting, then default false
|
|
181
|
-
this.#verbose = options.verbose ?? config.get('verbose') ?? false
|
|
182
|
-
debug('configured: quiet=%s, json=%s, verbose=%s, reducedMotion=%s',
|
|
183
|
-
this.#quiet, this.#json, this.#verbose, this.#isReducedMotion())
|
|
184
|
-
return this
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* Check if output should be suppressed
|
|
189
|
-
* @private
|
|
190
|
-
* @returns {boolean}
|
|
191
|
-
*/
|
|
192
|
-
#shouldSuppress() {
|
|
193
|
-
// Suppress if quiet mode, JSON mode, or not a TTY
|
|
194
|
-
return this.#quiet || this.#json || !process.stdout.isTTY
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* Start a new spinner
|
|
199
|
-
*
|
|
200
|
-
* @param {string} text - Initial spinner text
|
|
201
|
-
* @param {Object} [options] - Spinner options
|
|
202
|
-
* @param {boolean} [options.showElapsed=false] - Show elapsed time (e.g., "Building... (12s)")
|
|
203
|
-
* @returns {Reporter} this instance for chaining
|
|
204
|
-
*
|
|
205
|
-
* @example
|
|
206
|
-
* reporter.start('Building site...')
|
|
207
|
-
*
|
|
208
|
-
* @example With elapsed time
|
|
209
|
-
* reporter.start('Building site...', { showElapsed: true })
|
|
210
|
-
* // Shows: ⠋ Building site... (12s)
|
|
211
|
-
*/
|
|
212
|
-
start(text, options = {}) {
|
|
213
|
-
// Stop any existing spinner
|
|
214
|
-
this.stop()
|
|
215
|
-
|
|
216
|
-
this.#baseText = text
|
|
217
|
-
this.#startTime = Date.now()
|
|
218
|
-
|
|
219
|
-
if (this.#shouldSuppress()) {
|
|
220
|
-
debug('spinner suppressed: %s', text)
|
|
221
|
-
return this
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
// Reduced motion: print static text on a new line, no spinner
|
|
225
|
-
if (this.#isReducedMotion()) {
|
|
226
|
-
debug('spinner start (reduced motion): %s', text)
|
|
227
|
-
console.log(`${STATUS_SYMBOLS.start} ${text}`)
|
|
228
|
-
return this
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
debug('spinner start: %s', text)
|
|
232
|
-
this.#spinner = ora({
|
|
233
|
-
text,
|
|
234
|
-
// Use 'dots' spinner for consistency across platforms
|
|
235
|
-
spinner: 'dots',
|
|
236
|
-
}).start()
|
|
237
|
-
|
|
238
|
-
// Start elapsed time updates if requested
|
|
239
|
-
if (options.showElapsed) {
|
|
240
|
-
this.#startElapsedTimer()
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
return this
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* Start interval timer to update elapsed time display
|
|
248
|
-
* @private
|
|
249
|
-
*/
|
|
250
|
-
#startElapsedTimer() {
|
|
251
|
-
this.#elapsedInterval = setInterval(() => {
|
|
252
|
-
if (this.#spinner && this.#startTime) {
|
|
253
|
-
const elapsed = Math.floor((Date.now() - this.#startTime) / 1000)
|
|
254
|
-
this.#spinner.text = `${this.#baseText} (${elapsed}s)`
|
|
255
|
-
}
|
|
256
|
-
}, 1000)
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
/**
|
|
260
|
-
* Stop elapsed time timer
|
|
261
|
-
* @private
|
|
262
|
-
*/
|
|
263
|
-
#stopElapsedTimer() {
|
|
264
|
-
if (this.#elapsedInterval) {
|
|
265
|
-
clearInterval(this.#elapsedInterval)
|
|
266
|
-
this.#elapsedInterval = null
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
/**
|
|
271
|
-
* Update spinner text while running
|
|
272
|
-
*
|
|
273
|
-
* @param {string} text - New spinner text
|
|
274
|
-
* @returns {Reporter} this instance for chaining
|
|
275
|
-
*
|
|
276
|
-
* @example
|
|
277
|
-
* reporter.start('Step 1...')
|
|
278
|
-
* await step1()
|
|
279
|
-
* reporter.update('Step 2...')
|
|
280
|
-
* await step2()
|
|
281
|
-
* reporter.succeed('All steps complete')
|
|
282
|
-
*/
|
|
283
|
-
update(text) {
|
|
284
|
-
this.#baseText = text
|
|
285
|
-
|
|
286
|
-
if (this.#shouldSuppress()) {
|
|
287
|
-
debug('spinner update (suppressed): %s', text)
|
|
288
|
-
return this
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
// Reduced motion: print new line instead of overwriting
|
|
292
|
-
if (this.#isReducedMotion()) {
|
|
293
|
-
debug('spinner update (reduced motion): %s', text)
|
|
294
|
-
console.log(`${STATUS_SYMBOLS.start} ${text}`)
|
|
295
|
-
return this
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
if (this.#spinner) {
|
|
299
|
-
debug('spinner update: %s', text)
|
|
300
|
-
this.#spinner.text = text
|
|
301
|
-
} else {
|
|
302
|
-
// If no spinner running, start one
|
|
303
|
-
this.start(text)
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
return this
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
/**
|
|
310
|
-
* Mark operation as successful
|
|
311
|
-
*
|
|
312
|
-
* @param {string} [text] - Optional success message (defaults to current text)
|
|
313
|
-
* @returns {Reporter} this instance for chaining
|
|
314
|
-
*
|
|
315
|
-
* @example
|
|
316
|
-
* reporter.start('Building...')
|
|
317
|
-
* await build()
|
|
318
|
-
* reporter.succeed('Build complete')
|
|
319
|
-
*
|
|
320
|
-
* @example Using current text
|
|
321
|
-
* reporter.start('Building site...')
|
|
322
|
-
* await build()
|
|
323
|
-
* reporter.succeed() // Shows: ✔ Building site...
|
|
324
|
-
*/
|
|
325
|
-
succeed(text) {
|
|
326
|
-
this.#stopElapsedTimer()
|
|
327
|
-
|
|
328
|
-
const message = text || this.#baseText
|
|
329
|
-
|
|
330
|
-
if (this.#shouldSuppress()) {
|
|
331
|
-
debug('spinner succeed (suppressed): %s', message)
|
|
332
|
-
this.#spinner = null
|
|
333
|
-
return this
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
// Reduced motion: print static success line
|
|
337
|
-
if (this.#isReducedMotion()) {
|
|
338
|
-
debug('spinner succeed (reduced motion): %s', message)
|
|
339
|
-
console.log(`${STATUS_SYMBOLS.succeed} ${message}`)
|
|
340
|
-
return this
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
if (this.#spinner) {
|
|
344
|
-
debug('spinner succeed: %s', message)
|
|
345
|
-
this.#spinner.succeed(message)
|
|
346
|
-
this.#spinner = null
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
return this
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
/**
|
|
353
|
-
* Mark operation as failed
|
|
354
|
-
*
|
|
355
|
-
* @param {string} [text] - Optional failure message (defaults to current text)
|
|
356
|
-
* @returns {Reporter} this instance for chaining
|
|
357
|
-
*
|
|
358
|
-
* @example
|
|
359
|
-
* reporter.start('Generating PDF...')
|
|
360
|
-
* try {
|
|
361
|
-
* await generatePdf()
|
|
362
|
-
* reporter.succeed()
|
|
363
|
-
* } catch (error) {
|
|
364
|
-
* reporter.fail('PDF generation failed')
|
|
365
|
-
* throw error
|
|
366
|
-
* }
|
|
367
|
-
*/
|
|
368
|
-
fail(text) {
|
|
369
|
-
this.#stopElapsedTimer()
|
|
370
|
-
|
|
371
|
-
const message = text || this.#baseText
|
|
372
|
-
|
|
373
|
-
if (this.#shouldSuppress()) {
|
|
374
|
-
debug('spinner fail (suppressed): %s', message)
|
|
375
|
-
this.#spinner = null
|
|
376
|
-
return this
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
// Reduced motion: print static failure line
|
|
380
|
-
if (this.#isReducedMotion()) {
|
|
381
|
-
debug('spinner fail (reduced motion): %s', message)
|
|
382
|
-
console.log(`${STATUS_SYMBOLS.fail} ${message}`)
|
|
383
|
-
return this
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
if (this.#spinner) {
|
|
387
|
-
debug('spinner fail: %s', message)
|
|
388
|
-
this.#spinner.fail(message)
|
|
389
|
-
this.#spinner = null
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
return this
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
/**
|
|
396
|
-
* Mark operation with a warning
|
|
397
|
-
*
|
|
398
|
-
* @param {string} [text] - Optional warning message (defaults to current text)
|
|
399
|
-
* @returns {Reporter} this instance for chaining
|
|
400
|
-
*
|
|
401
|
-
* @example
|
|
402
|
-
* reporter.start('Checking dependencies...')
|
|
403
|
-
* if (outdatedDeps.length > 0) {
|
|
404
|
-
* reporter.warn('Some dependencies are outdated')
|
|
405
|
-
* } else {
|
|
406
|
-
* reporter.succeed('All dependencies up to date')
|
|
407
|
-
* }
|
|
408
|
-
*/
|
|
409
|
-
warn(text) {
|
|
410
|
-
this.#stopElapsedTimer()
|
|
411
|
-
|
|
412
|
-
const message = text || this.#baseText
|
|
413
|
-
|
|
414
|
-
if (this.#shouldSuppress()) {
|
|
415
|
-
debug('spinner warn (suppressed): %s', message)
|
|
416
|
-
this.#spinner = null
|
|
417
|
-
return this
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
// Reduced motion: print static warning line
|
|
421
|
-
if (this.#isReducedMotion()) {
|
|
422
|
-
debug('spinner warn (reduced motion): %s', message)
|
|
423
|
-
console.log(`${STATUS_SYMBOLS.warn} ${message}`)
|
|
424
|
-
return this
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
if (this.#spinner) {
|
|
428
|
-
debug('spinner warn: %s', message)
|
|
429
|
-
this.#spinner.warn(message)
|
|
430
|
-
this.#spinner = null
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
return this
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
/**
|
|
437
|
-
* Display an info message (non-spinner)
|
|
438
|
-
*
|
|
439
|
-
* @param {string} text - Info message
|
|
440
|
-
* @returns {Reporter} this instance for chaining
|
|
441
|
-
*
|
|
442
|
-
* @example
|
|
443
|
-
* reporter.info('Using cached dependencies')
|
|
444
|
-
*/
|
|
445
|
-
info(text) {
|
|
446
|
-
this.#stopElapsedTimer()
|
|
447
|
-
|
|
448
|
-
if (this.#shouldSuppress()) {
|
|
449
|
-
debug('spinner info (suppressed): %s', text)
|
|
450
|
-
this.#spinner = null
|
|
451
|
-
return this
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
// Reduced motion: print static info line
|
|
455
|
-
if (this.#isReducedMotion()) {
|
|
456
|
-
debug('spinner info (reduced motion): %s', text)
|
|
457
|
-
console.log(`${STATUS_SYMBOLS.info} ${text}`)
|
|
458
|
-
return this
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
if (this.#spinner) {
|
|
462
|
-
debug('spinner info: %s', text)
|
|
463
|
-
this.#spinner.info(text)
|
|
464
|
-
this.#spinner = null
|
|
465
|
-
} else {
|
|
466
|
-
// Create temporary spinner just to show info
|
|
467
|
-
ora().info(text)
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
return this
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
/**
|
|
474
|
-
* Display a detail line (only shown in verbose mode)
|
|
475
|
-
*
|
|
476
|
-
* Use this to provide additional context that's useful for users
|
|
477
|
-
* who want more information but isn't essential for normal operation.
|
|
478
|
-
*
|
|
479
|
-
* @param {string} text - Detail text to display
|
|
480
|
-
* @returns {Reporter} this instance for chaining
|
|
481
|
-
*
|
|
482
|
-
* @example
|
|
483
|
-
* reporter.configure({ verbose: true })
|
|
484
|
-
* reporter.start('Building site...')
|
|
485
|
-
* reporter.detail('Output: _site/')
|
|
486
|
-
* reporter.detail('Processing 45 pages')
|
|
487
|
-
* reporter.succeed('Build complete')
|
|
488
|
-
*/
|
|
489
|
-
detail(text) {
|
|
490
|
-
// Only show details in verbose mode
|
|
491
|
-
if (!this.#verbose || this.#shouldSuppress()) {
|
|
492
|
-
debug('detail (suppressed): %s', text)
|
|
493
|
-
return this
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
// Reduced motion: print detail directly (no spinner to stop/restart)
|
|
497
|
-
if (this.#isReducedMotion()) {
|
|
498
|
-
console.log(` ${text}`)
|
|
499
|
-
debug('detail (reduced motion): %s', text)
|
|
500
|
-
return this
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
// Print detail with indentation below spinner
|
|
504
|
-
if (this.#spinner) {
|
|
505
|
-
// Temporarily stop spinner to print detail
|
|
506
|
-
const wasSpinning = this.#spinner.isSpinning
|
|
507
|
-
if (wasSpinning) {
|
|
508
|
-
this.#spinner.stop()
|
|
509
|
-
}
|
|
510
|
-
console.log(` ${text}`)
|
|
511
|
-
if (wasSpinning) {
|
|
512
|
-
this.#spinner.start()
|
|
513
|
-
}
|
|
514
|
-
} else {
|
|
515
|
-
console.log(` ${text}`)
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
debug('detail: %s', text)
|
|
519
|
-
return this
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
/**
|
|
523
|
-
* Check if verbose mode is enabled
|
|
524
|
-
*
|
|
525
|
-
* @returns {boolean} True if verbose mode is enabled
|
|
526
|
-
*/
|
|
527
|
-
isVerbose() {
|
|
528
|
-
return this.#verbose
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
/**
|
|
532
|
-
* Stop spinner without status indicator
|
|
533
|
-
*
|
|
534
|
-
* Use this when an operation is interrupted or when you need
|
|
535
|
-
* to clear the spinner before other output.
|
|
536
|
-
*
|
|
537
|
-
* @returns {Reporter} this instance for chaining
|
|
538
|
-
*
|
|
539
|
-
* @example
|
|
540
|
-
* reporter.start('Processing...')
|
|
541
|
-
* if (shouldAbort) {
|
|
542
|
-
* reporter.stop()
|
|
543
|
-
* return
|
|
544
|
-
* }
|
|
545
|
-
*/
|
|
546
|
-
stop() {
|
|
547
|
-
this.#stopElapsedTimer()
|
|
548
|
-
|
|
549
|
-
if (this.#spinner) {
|
|
550
|
-
debug('spinner stop')
|
|
551
|
-
this.#spinner.stop()
|
|
552
|
-
this.#spinner = null
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
return this
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
/**
|
|
559
|
-
* Check if spinner is currently active
|
|
560
|
-
*
|
|
561
|
-
* @returns {boolean} True if a spinner is running
|
|
562
|
-
*
|
|
563
|
-
* @example
|
|
564
|
-
* if (reporter.isSpinning()) {
|
|
565
|
-
* reporter.stop()
|
|
566
|
-
* }
|
|
567
|
-
*/
|
|
568
|
-
isSpinning() {
|
|
569
|
-
return this.#spinner !== null && this.#spinner.isSpinning
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
/**
|
|
573
|
-
* Get elapsed time since spinner started
|
|
574
|
-
*
|
|
575
|
-
* @returns {number|null} Elapsed time in milliseconds, or null if not started
|
|
576
|
-
*/
|
|
577
|
-
getElapsed() {
|
|
578
|
-
if (this.#startTime === null) {
|
|
579
|
-
return null
|
|
580
|
-
}
|
|
581
|
-
return Date.now() - this.#startTime
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
/**
|
|
585
|
-
* Reset reporter state
|
|
586
|
-
*
|
|
587
|
-
* Useful for testing or when reusing reporter across multiple operations.
|
|
588
|
-
*
|
|
589
|
-
* @returns {Reporter} this instance for chaining
|
|
590
|
-
*/
|
|
591
|
-
reset() {
|
|
592
|
-
this.stop()
|
|
593
|
-
this.#quiet = false
|
|
594
|
-
this.#json = false
|
|
595
|
-
this.#verbose = false
|
|
596
|
-
this.#startTime = null
|
|
597
|
-
this.#baseText = ''
|
|
598
|
-
debug('reporter reset')
|
|
599
|
-
return this
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
// Export singleton instance
|
|
604
|
-
export default new Reporter()
|
|
605
|
-
|
|
606
|
-
// Export class for testing
|
|
607
|
-
export { Reporter }
|