@thegetty/quire-cli 1.0.0-rc.44 → 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.
- package/CHANGELOG.md +0 -36
- package/README.md +0 -9
- package/bin/cli.js +1 -46
- package/package.json +9 -25
- 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/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,578 +0,0 @@
|
|
|
1
|
-
import esmock from 'esmock'
|
|
2
|
-
import sinon from 'sinon'
|
|
3
|
-
import test from 'ava'
|
|
4
|
-
import createLogger, { logger, LOG_LEVELS, LOG_LEVEL_ENV_VAR } from './index.js'
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Logger Module Integration Tests
|
|
8
|
-
*
|
|
9
|
-
* Tests the actual logging behavior including output formatting and level filtering.
|
|
10
|
-
*
|
|
11
|
-
* Note: loglevel captures console methods at module load time, so we can't stub
|
|
12
|
-
* console.log directly. Instead, we test the logger's behavior through its API
|
|
13
|
-
* and verify level filtering works correctly.
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
test.beforeEach((t) => {
|
|
17
|
-
t.context.sandbox = sinon.createSandbox()
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
test.afterEach.always((t) => {
|
|
21
|
-
t.context.sandbox.restore()
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
25
|
-
// Log method invocation tests
|
|
26
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
27
|
-
|
|
28
|
-
test('logger methods are callable without error', (t) => {
|
|
29
|
-
const log = createLogger('test:callable', 'silent') // Silent to avoid output
|
|
30
|
-
|
|
31
|
-
t.notThrows(() => log.trace('trace message'))
|
|
32
|
-
t.notThrows(() => log.debug('debug message'))
|
|
33
|
-
t.notThrows(() => log.info('info message'))
|
|
34
|
-
t.notThrows(() => log.warn('warn message'))
|
|
35
|
-
t.notThrows(() => log.error('error message'))
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
test('logger methods accept multiple arguments', (t) => {
|
|
39
|
-
const log = createLogger('test:multiarg', 'silent')
|
|
40
|
-
|
|
41
|
-
t.notThrows(() => log.info('message', 'arg1', 'arg2'))
|
|
42
|
-
t.notThrows(() => log.info('message', { key: 'value' }))
|
|
43
|
-
t.notThrows(() => log.info('message', 123, true, null))
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
test('logger methods accept no arguments', (t) => {
|
|
47
|
-
const log = createLogger('test:noarg', 'silent')
|
|
48
|
-
|
|
49
|
-
t.notThrows(() => log.info())
|
|
50
|
-
t.notThrows(() => log.error())
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
54
|
-
// Level filtering behavior tests
|
|
55
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
56
|
-
|
|
57
|
-
test('logger at trace level has getLevel() return 0', (t) => {
|
|
58
|
-
const log = createLogger('test:trace', 'trace')
|
|
59
|
-
t.is(log.getLevel(), LOG_LEVELS.trace)
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
test('logger at debug level has getLevel() return 1', (t) => {
|
|
63
|
-
const log = createLogger('test:debug', 'debug')
|
|
64
|
-
t.is(log.getLevel(), LOG_LEVELS.debug)
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
test('logger at info level has getLevel() return 2', (t) => {
|
|
68
|
-
const log = createLogger('test:info', 'info')
|
|
69
|
-
t.is(log.getLevel(), LOG_LEVELS.info)
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
test('logger at warn level has getLevel() return 3', (t) => {
|
|
73
|
-
const log = createLogger('test:warn', 'warn')
|
|
74
|
-
t.is(log.getLevel(), LOG_LEVELS.warn)
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
test('logger at error level has getLevel() return 4', (t) => {
|
|
78
|
-
const log = createLogger('test:error', 'error')
|
|
79
|
-
t.is(log.getLevel(), LOG_LEVELS.error)
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
test('logger at silent level has getLevel() return 5', (t) => {
|
|
83
|
-
const log = createLogger('test:silent', 'silent')
|
|
84
|
-
t.is(log.getLevel(), LOG_LEVELS.silent)
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
88
|
-
// Runtime level change tests
|
|
89
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
90
|
-
|
|
91
|
-
test('setLevel changes getLevel() return value', (t) => {
|
|
92
|
-
const log = createLogger('test:setlevel', 'info')
|
|
93
|
-
t.is(log.getLevel(), LOG_LEVELS.info)
|
|
94
|
-
|
|
95
|
-
log.setLevel('debug')
|
|
96
|
-
t.is(log.getLevel(), LOG_LEVELS.debug)
|
|
97
|
-
|
|
98
|
-
log.setLevel('error')
|
|
99
|
-
t.is(log.getLevel(), LOG_LEVELS.error)
|
|
100
|
-
|
|
101
|
-
log.setLevel('silent')
|
|
102
|
-
t.is(log.getLevel(), LOG_LEVELS.silent)
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
test('setLevel accepts numeric values', (t) => {
|
|
106
|
-
const log = createLogger('test:numeric', 'info')
|
|
107
|
-
|
|
108
|
-
log.setLevel(0)
|
|
109
|
-
t.is(log.getLevel(), 0)
|
|
110
|
-
|
|
111
|
-
log.setLevel(4)
|
|
112
|
-
t.is(log.getLevel(), 4)
|
|
113
|
-
})
|
|
114
|
-
|
|
115
|
-
test('setLevel with invalid string defaults to info', (t) => {
|
|
116
|
-
const log = createLogger('test:invalid', 'debug')
|
|
117
|
-
t.is(log.getLevel(), LOG_LEVELS.debug)
|
|
118
|
-
|
|
119
|
-
log.setLevel('not-a-level')
|
|
120
|
-
t.is(log.getLevel(), LOG_LEVELS.info)
|
|
121
|
-
})
|
|
122
|
-
|
|
123
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
124
|
-
// Independent instance tests
|
|
125
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
126
|
-
|
|
127
|
-
test('multiple loggers maintain independent levels', (t) => {
|
|
128
|
-
const log1 = createLogger('independent:one', 'debug')
|
|
129
|
-
const log2 = createLogger('independent:two', 'error')
|
|
130
|
-
|
|
131
|
-
t.is(log1.getLevel(), LOG_LEVELS.debug)
|
|
132
|
-
t.is(log2.getLevel(), LOG_LEVELS.error)
|
|
133
|
-
|
|
134
|
-
log1.setLevel('warn')
|
|
135
|
-
|
|
136
|
-
t.is(log1.getLevel(), LOG_LEVELS.warn)
|
|
137
|
-
t.is(log2.getLevel(), LOG_LEVELS.error) // Unchanged
|
|
138
|
-
})
|
|
139
|
-
|
|
140
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
141
|
-
// Singleton behavior tests
|
|
142
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
143
|
-
|
|
144
|
-
test('default singleton is functional', (t) => {
|
|
145
|
-
t.notThrows(() => logger.info('singleton test'))
|
|
146
|
-
t.is(typeof logger.getLevel(), 'number')
|
|
147
|
-
})
|
|
148
|
-
|
|
149
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
150
|
-
// Console output tests with level labels (logShowLevel: true)
|
|
151
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
152
|
-
|
|
153
|
-
test.serial('error level outputs to console.error with level label when configured', async (t) => {
|
|
154
|
-
const { sandbox } = t.context
|
|
155
|
-
const consoleErrorStub = sandbox.stub(console, 'error')
|
|
156
|
-
|
|
157
|
-
// Mock config to show level labels
|
|
158
|
-
const mockConfig = {
|
|
159
|
-
get: sandbox.stub().callsFake((key) => ({
|
|
160
|
-
logPrefix: 'quire',
|
|
161
|
-
logPrefixStyle: 'bracket',
|
|
162
|
-
logShowLevel: true,
|
|
163
|
-
logUseColor: false
|
|
164
|
-
})[key])
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
const { default: createLoggerMocked } = await esmock('./index.js', {
|
|
168
|
-
'#lib/conf/config.js': { default: mockConfig }
|
|
169
|
-
})
|
|
170
|
-
|
|
171
|
-
const log = createLoggerMocked('test:error:output', 'error')
|
|
172
|
-
log.error('Error message')
|
|
173
|
-
|
|
174
|
-
t.true(consoleErrorStub.calledOnce)
|
|
175
|
-
const output = consoleErrorStub.firstCall.args.join(' ')
|
|
176
|
-
t.true(output.includes('[quire]'))
|
|
177
|
-
t.true(output.includes('ERROR'))
|
|
178
|
-
t.true(output.includes('Error message'))
|
|
179
|
-
})
|
|
180
|
-
|
|
181
|
-
test.serial('warn level outputs to console.warn with level label when configured', async (t) => {
|
|
182
|
-
const { sandbox } = t.context
|
|
183
|
-
const consoleWarnStub = sandbox.stub(console, 'warn')
|
|
184
|
-
|
|
185
|
-
// Mock config to show level labels
|
|
186
|
-
const mockConfig = {
|
|
187
|
-
get: sandbox.stub().callsFake((key) => ({
|
|
188
|
-
logPrefix: 'quire',
|
|
189
|
-
logPrefixStyle: 'bracket',
|
|
190
|
-
logShowLevel: true,
|
|
191
|
-
logUseColor: false
|
|
192
|
-
})[key])
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
const { default: createLoggerMocked } = await esmock('./index.js', {
|
|
196
|
-
'#lib/conf/config.js': { default: mockConfig }
|
|
197
|
-
})
|
|
198
|
-
|
|
199
|
-
const log = createLoggerMocked('test:warn:output', 'warn')
|
|
200
|
-
log.warn('Warning message')
|
|
201
|
-
|
|
202
|
-
t.true(consoleWarnStub.calledOnce)
|
|
203
|
-
const output = consoleWarnStub.firstCall.args.join(' ')
|
|
204
|
-
t.true(output.includes('[quire]'))
|
|
205
|
-
t.true(output.includes('WARN'))
|
|
206
|
-
t.true(output.includes('Warning message'))
|
|
207
|
-
})
|
|
208
|
-
|
|
209
|
-
test.serial('trace level outputs to console.trace with level label when configured', async (t) => {
|
|
210
|
-
const { sandbox } = t.context
|
|
211
|
-
const consoleTraceStub = sandbox.stub(console, 'trace')
|
|
212
|
-
|
|
213
|
-
// Mock config to show level labels
|
|
214
|
-
const mockConfig = {
|
|
215
|
-
get: sandbox.stub().callsFake((key) => ({
|
|
216
|
-
logPrefix: 'quire',
|
|
217
|
-
logPrefixStyle: 'bracket',
|
|
218
|
-
logShowLevel: true,
|
|
219
|
-
logUseColor: false
|
|
220
|
-
})[key])
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
const { default: createLoggerMocked } = await esmock('./index.js', {
|
|
224
|
-
'#lib/conf/config.js': { default: mockConfig }
|
|
225
|
-
})
|
|
226
|
-
|
|
227
|
-
const log = createLoggerMocked('test:trace:output', 'trace')
|
|
228
|
-
log.trace('Trace message')
|
|
229
|
-
|
|
230
|
-
t.true(consoleTraceStub.calledOnce)
|
|
231
|
-
const output = consoleTraceStub.firstCall.args.join(' ')
|
|
232
|
-
t.true(output.includes('[quire]'))
|
|
233
|
-
t.true(output.includes('TRACE'))
|
|
234
|
-
t.true(output.includes('Trace message'))
|
|
235
|
-
})
|
|
236
|
-
|
|
237
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
238
|
-
// Prefix configuration tests
|
|
239
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
240
|
-
|
|
241
|
-
test('different prefixes create distinct loggers', (t) => {
|
|
242
|
-
const log1 = createLogger('prefix:alpha', 'debug')
|
|
243
|
-
const log2 = createLogger('prefix:beta', 'warn')
|
|
244
|
-
|
|
245
|
-
// Different levels confirm different instances
|
|
246
|
-
t.not(log1.getLevel(), log2.getLevel())
|
|
247
|
-
})
|
|
248
|
-
|
|
249
|
-
test('same prefix returns same underlying loglevel instance', (t) => {
|
|
250
|
-
const log1 = createLogger('same:prefix', 'debug')
|
|
251
|
-
const log2 = createLogger('same:prefix', 'warn')
|
|
252
|
-
|
|
253
|
-
// Setting level on one affects the other (same loglevel instance)
|
|
254
|
-
log1.setLevel('error')
|
|
255
|
-
t.is(log1.getLevel(), LOG_LEVELS.error)
|
|
256
|
-
t.is(log2.getLevel(), LOG_LEVELS.error)
|
|
257
|
-
})
|
|
258
|
-
|
|
259
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
260
|
-
// Edge case tests
|
|
261
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
262
|
-
|
|
263
|
-
test('empty prefix throws error (loglevel requirement)', (t) => {
|
|
264
|
-
t.throws(() => createLogger('', 'info'), {
|
|
265
|
-
instanceOf: TypeError,
|
|
266
|
-
message: /supply a name/
|
|
267
|
-
})
|
|
268
|
-
})
|
|
269
|
-
|
|
270
|
-
test('special characters in prefix are allowed', (t) => {
|
|
271
|
-
const log = createLogger('lib:pdf/paged.js', 'info')
|
|
272
|
-
t.notThrows(() => log.info('message'))
|
|
273
|
-
})
|
|
274
|
-
|
|
275
|
-
test('undefined level defaults to info', (t) => {
|
|
276
|
-
const log = createLogger('test:undefined')
|
|
277
|
-
t.is(log.getLevel(), LOG_LEVELS.info)
|
|
278
|
-
})
|
|
279
|
-
|
|
280
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
281
|
-
// Environment variable tests
|
|
282
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
283
|
-
|
|
284
|
-
test('LOG_LEVEL_ENV_VAR constant is exported', (t) => {
|
|
285
|
-
t.is(LOG_LEVEL_ENV_VAR, 'QUIRE_LOG_LEVEL')
|
|
286
|
-
})
|
|
287
|
-
|
|
288
|
-
test.serial('logger reads level from QUIRE_LOG_LEVEL env var', async (t) => {
|
|
289
|
-
const originalEnv = process.env[LOG_LEVEL_ENV_VAR]
|
|
290
|
-
|
|
291
|
-
try {
|
|
292
|
-
// Set env var to debug
|
|
293
|
-
process.env[LOG_LEVEL_ENV_VAR] = 'debug'
|
|
294
|
-
|
|
295
|
-
// Re-import to get fresh module that reads env var
|
|
296
|
-
// Note: We need to use a unique prefix so loglevel creates a new instance
|
|
297
|
-
const { default: freshCreateLogger } = await import('./index.js?env-debug')
|
|
298
|
-
const log = freshCreateLogger('env:debug:test')
|
|
299
|
-
|
|
300
|
-
t.is(log.getLevel(), LOG_LEVELS.debug)
|
|
301
|
-
} finally {
|
|
302
|
-
// Restore original env
|
|
303
|
-
if (originalEnv === undefined) {
|
|
304
|
-
delete process.env[LOG_LEVEL_ENV_VAR]
|
|
305
|
-
} else {
|
|
306
|
-
process.env[LOG_LEVEL_ENV_VAR] = originalEnv
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
})
|
|
310
|
-
|
|
311
|
-
test.serial('logger reads error level from QUIRE_LOG_LEVEL env var', async (t) => {
|
|
312
|
-
const originalEnv = process.env[LOG_LEVEL_ENV_VAR]
|
|
313
|
-
|
|
314
|
-
try {
|
|
315
|
-
process.env[LOG_LEVEL_ENV_VAR] = 'error'
|
|
316
|
-
|
|
317
|
-
const { default: freshCreateLogger } = await import('./index.js?env-error')
|
|
318
|
-
const log = freshCreateLogger('env:error:test')
|
|
319
|
-
|
|
320
|
-
t.is(log.getLevel(), LOG_LEVELS.error)
|
|
321
|
-
} finally {
|
|
322
|
-
if (originalEnv === undefined) {
|
|
323
|
-
delete process.env[LOG_LEVEL_ENV_VAR]
|
|
324
|
-
} else {
|
|
325
|
-
process.env[LOG_LEVEL_ENV_VAR] = originalEnv
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
})
|
|
329
|
-
|
|
330
|
-
test.serial('explicit level parameter overrides env var', async (t) => {
|
|
331
|
-
const originalEnv = process.env[LOG_LEVEL_ENV_VAR]
|
|
332
|
-
|
|
333
|
-
try {
|
|
334
|
-
process.env[LOG_LEVEL_ENV_VAR] = 'error'
|
|
335
|
-
|
|
336
|
-
const { default: freshCreateLogger } = await import('./index.js?env-override')
|
|
337
|
-
// Explicitly pass 'debug' which should override env var 'error'
|
|
338
|
-
const log = freshCreateLogger('env:override:test', 'debug')
|
|
339
|
-
|
|
340
|
-
t.is(log.getLevel(), LOG_LEVELS.debug)
|
|
341
|
-
} finally {
|
|
342
|
-
if (originalEnv === undefined) {
|
|
343
|
-
delete process.env[LOG_LEVEL_ENV_VAR]
|
|
344
|
-
} else {
|
|
345
|
-
process.env[LOG_LEVEL_ENV_VAR] = originalEnv
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
})
|
|
349
|
-
|
|
350
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
351
|
-
// Printf-style string substitution tests
|
|
352
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
353
|
-
|
|
354
|
-
test.serial('logger supports %s string substitution', async (t) => {
|
|
355
|
-
const { sandbox } = t.context
|
|
356
|
-
const consoleInfoStub = sandbox.stub(console, 'info')
|
|
357
|
-
|
|
358
|
-
const mockConfig = {
|
|
359
|
-
get: sandbox.stub().callsFake((key) => ({
|
|
360
|
-
logPrefix: 'quire',
|
|
361
|
-
logPrefixStyle: 'none',
|
|
362
|
-
logShowLevel: false,
|
|
363
|
-
logUseColor: false
|
|
364
|
-
})[key])
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
const { default: createLoggerMocked } = await esmock('./index.js', {
|
|
368
|
-
'#lib/conf/config.js': { default: mockConfig }
|
|
369
|
-
})
|
|
370
|
-
|
|
371
|
-
const log = createLoggerMocked('test:printf:string', 'info')
|
|
372
|
-
log.info('Hello %s', 'world')
|
|
373
|
-
|
|
374
|
-
t.true(consoleInfoStub.calledOnce)
|
|
375
|
-
const output = consoleInfoStub.firstCall.args.join(' ')
|
|
376
|
-
t.true(output.includes('Hello world'))
|
|
377
|
-
t.false(output.includes('%s'))
|
|
378
|
-
})
|
|
379
|
-
|
|
380
|
-
test.serial('logger supports %d number substitution', async (t) => {
|
|
381
|
-
const { sandbox } = t.context
|
|
382
|
-
const consoleInfoStub = sandbox.stub(console, 'info')
|
|
383
|
-
|
|
384
|
-
const mockConfig = {
|
|
385
|
-
get: sandbox.stub().callsFake((key) => ({
|
|
386
|
-
logPrefix: 'quire',
|
|
387
|
-
logPrefixStyle: 'none',
|
|
388
|
-
logShowLevel: false,
|
|
389
|
-
logUseColor: false
|
|
390
|
-
})[key])
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
const { default: createLoggerMocked } = await esmock('./index.js', {
|
|
394
|
-
'#lib/conf/config.js': { default: mockConfig }
|
|
395
|
-
})
|
|
396
|
-
|
|
397
|
-
const log = createLoggerMocked('test:printf:number', 'info')
|
|
398
|
-
log.info('Count: %d', 42)
|
|
399
|
-
|
|
400
|
-
t.true(consoleInfoStub.calledOnce)
|
|
401
|
-
const output = consoleInfoStub.firstCall.args.join(' ')
|
|
402
|
-
t.true(output.includes('Count: 42'))
|
|
403
|
-
t.false(output.includes('%d'))
|
|
404
|
-
})
|
|
405
|
-
|
|
406
|
-
test.serial('logger supports %O object substitution', async (t) => {
|
|
407
|
-
const { sandbox } = t.context
|
|
408
|
-
const consoleInfoStub = sandbox.stub(console, 'info')
|
|
409
|
-
|
|
410
|
-
const mockConfig = {
|
|
411
|
-
get: sandbox.stub().callsFake((key) => ({
|
|
412
|
-
logPrefix: 'quire',
|
|
413
|
-
logPrefixStyle: 'none',
|
|
414
|
-
logShowLevel: false,
|
|
415
|
-
logUseColor: false
|
|
416
|
-
})[key])
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
const { default: createLoggerMocked } = await esmock('./index.js', {
|
|
420
|
-
'#lib/conf/config.js': { default: mockConfig }
|
|
421
|
-
})
|
|
422
|
-
|
|
423
|
-
const log = createLoggerMocked('test:printf:object', 'info')
|
|
424
|
-
log.info('Data: %O', { key: 'value' })
|
|
425
|
-
|
|
426
|
-
t.true(consoleInfoStub.calledOnce)
|
|
427
|
-
const output = consoleInfoStub.firstCall.args.join(' ')
|
|
428
|
-
t.true(output.includes('key'))
|
|
429
|
-
t.true(output.includes('value'))
|
|
430
|
-
t.false(output.includes('%O'))
|
|
431
|
-
})
|
|
432
|
-
|
|
433
|
-
test.serial('logger supports multiple substitutions', async (t) => {
|
|
434
|
-
const { sandbox } = t.context
|
|
435
|
-
const consoleInfoStub = sandbox.stub(console, 'info')
|
|
436
|
-
|
|
437
|
-
const mockConfig = {
|
|
438
|
-
get: sandbox.stub().callsFake((key) => ({
|
|
439
|
-
logPrefix: 'quire',
|
|
440
|
-
logPrefixStyle: 'none',
|
|
441
|
-
logShowLevel: false,
|
|
442
|
-
logUseColor: false
|
|
443
|
-
})[key])
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
const { default: createLoggerMocked } = await esmock('./index.js', {
|
|
447
|
-
'#lib/conf/config.js': { default: mockConfig }
|
|
448
|
-
})
|
|
449
|
-
|
|
450
|
-
const log = createLoggerMocked('test:printf:multi', 'info')
|
|
451
|
-
log.info('%s is %d years old', 'Alice', 30)
|
|
452
|
-
|
|
453
|
-
t.true(consoleInfoStub.calledOnce)
|
|
454
|
-
const output = consoleInfoStub.firstCall.args.join(' ')
|
|
455
|
-
t.true(output.includes('Alice is 30 years old'))
|
|
456
|
-
t.false(output.includes('%s'))
|
|
457
|
-
t.false(output.includes('%d'))
|
|
458
|
-
})
|
|
459
|
-
|
|
460
|
-
test.serial('invalid env var value falls back to info', async (t) => {
|
|
461
|
-
const originalEnv = process.env[LOG_LEVEL_ENV_VAR]
|
|
462
|
-
|
|
463
|
-
try {
|
|
464
|
-
process.env[LOG_LEVEL_ENV_VAR] = 'not-a-valid-level'
|
|
465
|
-
|
|
466
|
-
const { default: freshCreateLogger } = await import('./index.js?env-invalid')
|
|
467
|
-
const log = freshCreateLogger('env:invalid:test')
|
|
468
|
-
|
|
469
|
-
t.is(log.getLevel(), LOG_LEVELS.info)
|
|
470
|
-
} finally {
|
|
471
|
-
if (originalEnv === undefined) {
|
|
472
|
-
delete process.env[LOG_LEVEL_ENV_VAR]
|
|
473
|
-
} else {
|
|
474
|
-
process.env[LOG_LEVEL_ENV_VAR] = originalEnv
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
})
|
|
478
|
-
|
|
479
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
480
|
-
// NO_COLOR environment variable tests
|
|
481
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
482
|
-
|
|
483
|
-
test.serial('logger disables color when NO_COLOR env var is set', async (t) => {
|
|
484
|
-
const { sandbox } = t.context
|
|
485
|
-
const consoleErrorStub = sandbox.stub(console, 'error')
|
|
486
|
-
const originalNoColor = process.env.NO_COLOR
|
|
487
|
-
|
|
488
|
-
try {
|
|
489
|
-
process.env.NO_COLOR = '1'
|
|
490
|
-
|
|
491
|
-
const mockConfig = {
|
|
492
|
-
get: sandbox.stub().callsFake((key) => ({
|
|
493
|
-
logPrefix: 'quire',
|
|
494
|
-
logPrefixStyle: 'bracket',
|
|
495
|
-
logShowLevel: true,
|
|
496
|
-
logUseColor: true, // Config says use color, but NO_COLOR overrides
|
|
497
|
-
logColorMessages: true,
|
|
498
|
-
})[key])
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
const { default: createLoggerMocked } = await esmock('./index.js', {
|
|
502
|
-
'#lib/conf/config.js': { default: mockConfig }
|
|
503
|
-
})
|
|
504
|
-
|
|
505
|
-
const log = createLoggerMocked('test:nocolor', 'error')
|
|
506
|
-
log.error('Error message')
|
|
507
|
-
|
|
508
|
-
t.true(consoleErrorStub.calledOnce)
|
|
509
|
-
const output = consoleErrorStub.firstCall.args.join(' ')
|
|
510
|
-
// Should not contain ANSI escape sequences when NO_COLOR is set
|
|
511
|
-
t.false(/\u001b\[/.test(output), 'output should not contain ANSI escape codes')
|
|
512
|
-
// Should still contain the actual text
|
|
513
|
-
t.true(output.includes('[quire]'))
|
|
514
|
-
t.true(output.includes('ERROR'))
|
|
515
|
-
t.true(output.includes('Error message'))
|
|
516
|
-
} finally {
|
|
517
|
-
if (originalNoColor === undefined) {
|
|
518
|
-
delete process.env.NO_COLOR
|
|
519
|
-
} else {
|
|
520
|
-
process.env.NO_COLOR = originalNoColor
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
|
-
})
|
|
524
|
-
|
|
525
|
-
test.serial('logger uses color when NO_COLOR env var is not set and config enables color', async (t) => {
|
|
526
|
-
const { sandbox } = t.context
|
|
527
|
-
const consoleErrorStub = sandbox.stub(console, 'error')
|
|
528
|
-
const originalNoColor = process.env.NO_COLOR
|
|
529
|
-
|
|
530
|
-
try {
|
|
531
|
-
delete process.env.NO_COLOR
|
|
532
|
-
|
|
533
|
-
const mockConfig = {
|
|
534
|
-
get: sandbox.stub().callsFake((key) => ({
|
|
535
|
-
logPrefix: 'quire',
|
|
536
|
-
logPrefixStyle: 'bracket',
|
|
537
|
-
logShowLevel: true,
|
|
538
|
-
logUseColor: true,
|
|
539
|
-
logColorMessages: true,
|
|
540
|
-
})[key])
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
// Create a mock chalk that always applies ANSI styling regardless of TTY/env
|
|
544
|
-
const ansiRed = (s) => `\u001b[91m${s}\u001b[39m`
|
|
545
|
-
const ansiRedInverse = (s) => `\u001b[91m\u001b[7m${s}\u001b[27m\u001b[39m`
|
|
546
|
-
const ansiBold = (s) => `\u001b[1m${s}\u001b[22m`
|
|
547
|
-
const mockChalk = {
|
|
548
|
-
bold: ansiBold,
|
|
549
|
-
gray: (s) => s,
|
|
550
|
-
yellow: (s) => s,
|
|
551
|
-
magenta: (s) => s,
|
|
552
|
-
red: ansiRed,
|
|
553
|
-
redBright: { inverse: ansiRedInverse },
|
|
554
|
-
'yellow.inverse': (s) => s,
|
|
555
|
-
}
|
|
556
|
-
// Support chained properties
|
|
557
|
-
mockChalk.yellow.inverse = (s) => s
|
|
558
|
-
|
|
559
|
-
const { default: createLoggerMocked } = await esmock('./index.js', {
|
|
560
|
-
'#lib/conf/config.js': { default: mockConfig },
|
|
561
|
-
'chalk': { default: mockChalk }
|
|
562
|
-
})
|
|
563
|
-
|
|
564
|
-
const log = createLoggerMocked('test:withcolor', 'error')
|
|
565
|
-
log.error('Error message')
|
|
566
|
-
|
|
567
|
-
t.true(consoleErrorStub.calledOnce)
|
|
568
|
-
const output = consoleErrorStub.firstCall.args.join(' ')
|
|
569
|
-
// Should contain ANSI escape sequences when color is enabled and NO_COLOR not set
|
|
570
|
-
t.true(/\u001b\[/.test(output), 'output should contain ANSI escape codes')
|
|
571
|
-
} finally {
|
|
572
|
-
if (originalNoColor === undefined) {
|
|
573
|
-
delete process.env.NO_COLOR
|
|
574
|
-
} else {
|
|
575
|
-
process.env.NO_COLOR = originalNoColor
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
})
|
package/src/lib/npm/README.md
DELETED
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
# NPM Façade
|
|
2
|
-
|
|
3
|
-
A façade module that abstracts npm command-line operations for the Quire CLI.
|
|
4
|
-
|
|
5
|
-
## Purpose
|
|
6
|
-
|
|
7
|
-
This module provides a unified interface for npm operations with:
|
|
8
|
-
|
|
9
|
-
- Encapsulation of npm implementation details
|
|
10
|
-
- Consistent logging prefixed with `[CLI:lib/npm]`
|
|
11
|
-
- Unified error handling
|
|
12
|
-
- Easy mockability for testing
|
|
13
|
-
|
|
14
|
-
## Usage
|
|
15
|
-
|
|
16
|
-
```javascript
|
|
17
|
-
import npm from '#lib/npm/index.js'
|
|
18
|
-
|
|
19
|
-
// Check npm availability
|
|
20
|
-
if (!npm.isAvailable()) {
|
|
21
|
-
console.error('npm is not installed')
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// Get npm version
|
|
25
|
-
// @see https://docs.npmjs.com/cli/commands/npm-version
|
|
26
|
-
const version = await npm.version()
|
|
27
|
-
|
|
28
|
-
// Initialize package.json
|
|
29
|
-
// @see https://docs.npmjs.com/cli/commands/npm-init
|
|
30
|
-
await npm.init('/path/to/project', { yes: true })
|
|
31
|
-
|
|
32
|
-
// Install dependencies
|
|
33
|
-
// @see https://docs.npmjs.com/cli/commands/npm-install
|
|
34
|
-
await npm.install('/path/to/project', {
|
|
35
|
-
saveDev: true,
|
|
36
|
-
preferOffline: true
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
// Pack a package
|
|
40
|
-
// @see https://docs.npmjs.com/cli/commands/npm-pack
|
|
41
|
-
await npm.pack('@thegetty/quire-11ty@1.0.0', '/path/to/destination', {
|
|
42
|
-
quiet: true
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
// Clean cache
|
|
46
|
-
// @see https://docs.npmjs.com/cli/commands/npm-cache
|
|
47
|
-
await npm.cacheClean()
|
|
48
|
-
|
|
49
|
-
// View package version from registry
|
|
50
|
-
// @see https://docs.npmjs.com/cli/commands/npm-view
|
|
51
|
-
const latestVersion = await npm.view('@thegetty/quire-11ty', 'version')
|
|
52
|
-
|
|
53
|
-
// Get compatible version for a range
|
|
54
|
-
// @see https://docs.npmjs.com/about-semantic-versioning
|
|
55
|
-
const compatible = await npm.getCompatibleVersion('@thegetty/quire-11ty', '^1.0.0')
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
## API
|
|
59
|
-
|
|
60
|
-
### `isAvailable()`
|
|
61
|
-
|
|
62
|
-
Check if npm is available in PATH.
|
|
63
|
-
|
|
64
|
-
### `version()`
|
|
65
|
-
|
|
66
|
-
Get the installed npm version.
|
|
67
|
-
|
|
68
|
-
### `init(cwd, options)`
|
|
69
|
-
|
|
70
|
-
Initialize a new package.json in the specified directory.
|
|
71
|
-
|
|
72
|
-
**Options:**
|
|
73
|
-
- `yes` (boolean, default: `true`) - Auto-accept defaults
|
|
74
|
-
|
|
75
|
-
### `install(cwd, options)`
|
|
76
|
-
|
|
77
|
-
Install dependencies in the specified directory.
|
|
78
|
-
|
|
79
|
-
**Options:**
|
|
80
|
-
- `preferOffline` (boolean, default: `false`) - Prefer cached packages
|
|
81
|
-
- `saveDev` (boolean, default: `false`) - Install as devDependencies
|
|
82
|
-
|
|
83
|
-
### `pack(packageSpec, destination, options)`
|
|
84
|
-
|
|
85
|
-
Download and pack a package to a tarball.
|
|
86
|
-
|
|
87
|
-
**Options:**
|
|
88
|
-
- `debug` (boolean, default: `false`) - Enable debug output
|
|
89
|
-
- `quiet` (boolean, default: `true`) - Suppress output
|
|
90
|
-
|
|
91
|
-
### `cacheClean(cwd)`
|
|
92
|
-
|
|
93
|
-
Force clean the npm cache.
|
|
94
|
-
|
|
95
|
-
### `view(packageName, field)`
|
|
96
|
-
|
|
97
|
-
Query package information from the npm registry using `npm view`.
|
|
98
|
-
|
|
99
|
-
### `show(packageName, field)`
|
|
100
|
-
|
|
101
|
-
Query package information from the npm registry using `npm show`.
|
|
102
|
-
|
|
103
|
-
### `fetchFromRegistry(packageName)`
|
|
104
|
-
|
|
105
|
-
Fetch package metadata directly from the npm registry API.
|
|
106
|
-
|
|
107
|
-
### `getCompatibleVersion(packageName, range)`
|
|
108
|
-
|
|
109
|
-
Find the latest version compatible with a semver range.
|
|
110
|
-
|
|
111
|
-
## Testing
|
|
112
|
-
|
|
113
|
-
The module exports a singleton instance which can be mocked in tests:
|
|
114
|
-
|
|
115
|
-
```javascript
|
|
116
|
-
import esmock from 'esmock'
|
|
117
|
-
|
|
118
|
-
const mockNpm = {
|
|
119
|
-
isAvailable: sandbox.stub().returns(true),
|
|
120
|
-
install: sandbox.stub().resolves(),
|
|
121
|
-
version: sandbox.stub().resolves('10.2.4')
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
const MyCommand = await esmock('./mycommand.js', {
|
|
125
|
-
'#lib/npm/index.js': { default: mockNpm }
|
|
126
|
-
})
|
|
127
|
-
```
|