@thegetty/quire-cli 1.0.0-rc.35 → 1.0.0-rc.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +36 -0
- package/README.md +9 -0
- package/bin/cli.js +19 -1
- package/package.json +21 -8
- package/patches/README.md +19 -0
- package/patches/install-npm-version+1.0.9.patch +12119 -0
- package/schemas/objects.schema.json +12 -38
- package/schemas/publication.schema.json +0 -22
- package/schemas/references.schema.json +0 -1
- package/src/Command.js +26 -6
- package/src/Command.spec.js +99 -0
- package/src/commands/README.md +213 -122
- package/src/commands/build.js +46 -37
- package/src/commands/build.spec.js +113 -0
- package/src/commands/build.test.js +402 -0
- package/src/commands/clean.js +25 -19
- package/src/commands/clean.spec.js +108 -0
- package/src/commands/clean.test.js +260 -0
- package/src/commands/config.js +251 -0
- package/src/commands/config.spec.js +107 -0
- package/src/commands/config.test.js +715 -0
- package/src/commands/create.js +42 -14
- package/src/commands/create.spec.js +112 -0
- package/src/commands/create.test.js +415 -0
- package/src/commands/epub.js +59 -30
- package/src/commands/epub.spec.js +114 -0
- package/src/commands/epub.test.js +503 -0
- package/src/commands/index.js +9 -2
- package/src/commands/info.js +18 -24
- package/src/commands/info.spec.js +64 -0
- package/src/commands/info.test.js +415 -0
- package/src/commands/pdf.js +58 -84
- package/src/commands/pdf.spec.js +114 -0
- package/src/commands/pdf.test.js +464 -0
- package/src/commands/preview.js +26 -31
- package/src/commands/preview.spec.js +97 -0
- package/src/commands/preview.test.js +250 -0
- package/src/commands/use.js +56 -0
- package/src/commands/use.spec.js +61 -0
- package/src/commands/use.test.js +280 -0
- package/src/commands/validate.js +31 -19
- package/src/commands/validate.spec.js +82 -0
- package/src/commands/validate.test.js +234 -0
- package/src/commands/workflows.js +70 -0
- package/src/errors/build/build-failed-error.js +19 -0
- package/src/errors/build/config-field-missing-error.js +20 -0
- package/src/errors/build/config-file-not-found-error.js +20 -0
- package/src/errors/build/index.js +11 -0
- package/src/errors/index.js +48 -0
- package/src/errors/install/dependency-install-error.js +19 -0
- package/src/errors/install/directory-not-empty-error.js +25 -0
- package/src/errors/install/index.js +12 -0
- package/src/errors/install/invalid-path-error.js +31 -0
- package/src/errors/install/invalid-starter-error.js +27 -0
- package/src/errors/install/version-not-found-error.js +35 -0
- package/src/errors/output/epub-generation-error.js +19 -0
- package/src/errors/output/index.js +14 -0
- package/src/errors/output/invalid-epub-library-error.js +20 -0
- package/src/errors/output/invalid-pdf-library-error.js +20 -0
- package/src/errors/output/missing-build-output-error.js +21 -0
- package/src/errors/output/pdf-generation-error.js +24 -0
- package/src/errors/output/tool-not-found-error.js +37 -0
- package/src/errors/project/index.js +10 -0
- package/src/errors/project/not-in-project-error.js +20 -0
- package/src/errors/project/project-create-error.js +21 -0
- package/src/errors/quire-error.js +27 -0
- package/src/errors/validation/validation-error.js +20 -11
- package/src/helpers/clean.js +1 -1
- package/src/helpers/docs-url.js +32 -0
- package/src/helpers/test-cwd.js +5 -6
- package/src/helpers/test-cwd.test.js +192 -0
- package/src/helpers/which.js +10 -4
- package/src/lib/11ty/README.md +135 -19
- package/src/lib/11ty/api.js +176 -93
- package/src/lib/11ty/cli.js +77 -35
- package/src/lib/11ty/index.js +64 -5
- package/src/lib/11ty/index.test.js +655 -0
- package/src/lib/README.md +275 -0
- package/src/lib/commander/index.js +100 -0
- package/src/lib/commander/index.test.js +86 -0
- package/src/lib/commander/options.js +195 -0
- package/src/lib/commander/options.test.js +109 -0
- package/src/lib/conf/README.md +84 -73
- package/src/lib/conf/config.js +5 -3
- package/src/lib/conf/config.test.js +281 -0
- package/src/lib/conf/defaults.js +44 -0
- package/src/lib/conf/format.js +60 -0
- package/src/lib/conf/format.test.js +106 -0
- package/src/lib/conf/helpers.js +91 -0
- package/src/lib/conf/helpers.test.js +136 -0
- package/src/lib/conf/index.js +22 -0
- package/src/lib/conf/schema.js +53 -8
- package/src/lib/epub/README.md +133 -2
- package/src/lib/epub/engines.js +46 -0
- package/src/lib/epub/epub.js +36 -11
- package/src/lib/epub/index.js +111 -21
- package/src/lib/epub/index.test.js +518 -0
- package/src/lib/epub/pandoc.js +33 -4
- package/src/lib/epub/pandoc.test.js +122 -0
- package/src/lib/epub/schema.js +21 -0
- package/src/lib/error/README.md +170 -0
- package/src/lib/error/handler.js +107 -0
- package/src/lib/git/README.md +151 -2
- package/src/lib/git/index.js +217 -13
- package/src/lib/git/index.spec.js +80 -0
- package/src/lib/git/index.test.js +453 -0
- package/src/lib/installer/index.js +309 -0
- package/src/lib/installer/index.spec.js +83 -0
- package/src/lib/installer/index.test.js +545 -0
- package/src/lib/logger/README.md +424 -0
- package/src/lib/logger/debug.js +90 -0
- package/src/lib/logger/debug.spec.js +130 -0
- package/src/lib/logger/index.js +228 -0
- package/src/lib/logger/index.spec.js +131 -0
- package/src/lib/logger/index.test.js +477 -0
- package/src/lib/npm/README.md +127 -0
- package/src/lib/npm/index.js +198 -0
- package/src/lib/npm/index.spec.js +60 -0
- package/src/lib/npm/index.test.js +355 -0
- package/src/lib/pdf/README.md +131 -0
- package/src/lib/pdf/engines.js +46 -0
- package/src/lib/pdf/index.js +124 -21
- package/src/lib/pdf/index.test.js +708 -0
- package/src/lib/pdf/paged.js +100 -52
- package/src/lib/pdf/paged.test.js +366 -0
- package/src/lib/pdf/prince.js +115 -37
- package/src/lib/pdf/prince.test.js +202 -0
- package/src/lib/pdf/schema.js +21 -0
- package/src/lib/pdf/split.js +61 -33
- package/src/lib/pdf/split.test.js +445 -0
- package/src/lib/process/manager.js +110 -0
- package/src/lib/process/manager.test.js +55 -0
- package/src/lib/project/build.js +143 -0
- package/src/lib/project/build.test.js +253 -0
- package/src/lib/project/config.js +48 -0
- package/src/lib/project/config.test.js +134 -0
- package/src/{helpers/is-quire.js → lib/project/detect.js} +5 -3
- package/src/lib/project/detect.test.js +157 -0
- package/src/lib/project/index.js +40 -0
- package/src/lib/project/paths.js +224 -0
- package/src/lib/project/version.js +110 -0
- package/src/lib/project/version.test.js +350 -0
- package/src/lib/reporter/README.md +211 -2
- package/src/lib/reporter/index.js +512 -0
- package/src/lib/reporter/index.test.js +593 -0
- package/src/main.js +134 -47
- package/src/main.spec.js +61 -0
- package/src/main.test.js +347 -0
- package/src/validators/utils.js +2 -1
- package/src/commands/conf.js +0 -43
- package/src/commands/version.js +0 -43
- package/src/lib/11ty/paths.js +0 -103
- package/src/lib/i18n/README.md +0 -3
- package/src/lib/i18n/config.js +0 -53
- package/src/lib/i18n/index.js +0 -43
- package/src/lib/i18n/localeService.js +0 -58
- package/src/lib/quire/README.md +0 -19
- package/src/lib/quire/index.js +0 -350
|
@@ -0,0 +1,545 @@
|
|
|
1
|
+
import esmock from 'esmock'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import sinon from 'sinon'
|
|
4
|
+
import test from 'ava'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Installer Module Integration Tests
|
|
8
|
+
*
|
|
9
|
+
* Tests the installer façade module behavior with mocked dependencies.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
test.beforeEach((t) => {
|
|
13
|
+
t.context.sandbox = sinon.createSandbox()
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
test.afterEach.always((t) => {
|
|
17
|
+
t.context.sandbox.restore()
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
21
|
+
// getVersionFromPath() tests
|
|
22
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
23
|
+
|
|
24
|
+
test('getVersionFromPath() throws InvalidPathError when path does not exist', async (t) => {
|
|
25
|
+
const { sandbox } = t.context
|
|
26
|
+
|
|
27
|
+
const mockFs = {
|
|
28
|
+
existsSync: sandbox.stub().returns(false),
|
|
29
|
+
readJsonSync: sandbox.stub()
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const { getVersionFromPath } = await esmock('./index.js', {
|
|
33
|
+
'#lib/npm/index.js': { default: {} },
|
|
34
|
+
'#lib/project/index.js': {
|
|
35
|
+
getVersionsFromStarter: sandbox.stub(),
|
|
36
|
+
setVersion: sandbox.stub(),
|
|
37
|
+
writeVersionFile: sandbox.stub()
|
|
38
|
+
},
|
|
39
|
+
'#lib/git/index.js': { default: {} },
|
|
40
|
+
'fs-extra': mockFs,
|
|
41
|
+
'#helpers/is-empty.js': { isEmpty: sandbox.stub() },
|
|
42
|
+
'#src/packageConfig.js': { default: { version: '1.0.0' } }
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
const error = t.throws(() => getVersionFromPath('/nonexistent/path'))
|
|
46
|
+
|
|
47
|
+
t.is(error.code, 'INVALID_PATH', 'should throw InvalidPathError')
|
|
48
|
+
t.true(error.message.includes('/nonexistent/path'))
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
test('getVersionFromPath() throws VersionNotFoundError when package.json is missing', async (t) => {
|
|
52
|
+
const { sandbox } = t.context
|
|
53
|
+
|
|
54
|
+
const resolvedQuirePath = path.resolve('/local/quire')
|
|
55
|
+
const packageJsonPath = path.join(resolvedQuirePath, 'package.json')
|
|
56
|
+
|
|
57
|
+
const existsSyncStub = sandbox.stub()
|
|
58
|
+
existsSyncStub.withArgs(resolvedQuirePath).returns(true)
|
|
59
|
+
existsSyncStub.withArgs(packageJsonPath).returns(false)
|
|
60
|
+
|
|
61
|
+
const mockFs = {
|
|
62
|
+
existsSync: existsSyncStub,
|
|
63
|
+
readJsonSync: sandbox.stub()
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const { getVersionFromPath } = await esmock('./index.js', {
|
|
67
|
+
'#lib/npm/index.js': { default: {} },
|
|
68
|
+
'#lib/project/index.js': {
|
|
69
|
+
getVersionsFromStarter: sandbox.stub(),
|
|
70
|
+
setVersion: sandbox.stub(),
|
|
71
|
+
writeVersionFile: sandbox.stub()
|
|
72
|
+
},
|
|
73
|
+
'#lib/git/index.js': { default: {} },
|
|
74
|
+
'fs-extra': mockFs,
|
|
75
|
+
'#helpers/is-empty.js': { isEmpty: sandbox.stub() },
|
|
76
|
+
'#src/packageConfig.js': { default: { version: '1.0.0' } }
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
const error = t.throws(() => getVersionFromPath('/local/quire'))
|
|
80
|
+
|
|
81
|
+
t.is(error.code, 'VERSION_NOT_FOUND', 'should throw VersionNotFoundError')
|
|
82
|
+
t.true(error.message.includes('package.json not found'))
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
test('getVersionFromPath() throws VersionNotFoundError when package.json has no version', async (t) => {
|
|
86
|
+
const { sandbox } = t.context
|
|
87
|
+
|
|
88
|
+
const mockFs = {
|
|
89
|
+
existsSync: sandbox.stub().returns(true),
|
|
90
|
+
readJsonSync: sandbox.stub().returns({ name: '@thegetty/quire-11ty' }) // no version
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const { getVersionFromPath } = await esmock('./index.js', {
|
|
94
|
+
'#lib/npm/index.js': { default: {} },
|
|
95
|
+
'#lib/project/index.js': {
|
|
96
|
+
getVersionsFromStarter: sandbox.stub(),
|
|
97
|
+
setVersion: sandbox.stub(),
|
|
98
|
+
writeVersionFile: sandbox.stub()
|
|
99
|
+
},
|
|
100
|
+
'#lib/git/index.js': { default: {} },
|
|
101
|
+
'fs-extra': mockFs,
|
|
102
|
+
'#helpers/is-empty.js': { isEmpty: sandbox.stub() },
|
|
103
|
+
'#src/packageConfig.js': { default: { version: '1.0.0' } }
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
const error = t.throws(() => getVersionFromPath('/local/quire'))
|
|
107
|
+
|
|
108
|
+
t.is(error.code, 'VERSION_NOT_FOUND', 'should throw VersionNotFoundError')
|
|
109
|
+
t.true(error.message.includes('no version field'))
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
test('getVersionFromPath() returns version and resolved path when valid', async (t) => {
|
|
113
|
+
const { sandbox } = t.context
|
|
114
|
+
|
|
115
|
+
const mockFs = {
|
|
116
|
+
existsSync: sandbox.stub().returns(true),
|
|
117
|
+
readJsonSync: sandbox.stub().returns({ version: '1.0.0-local' })
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const { getVersionFromPath } = await esmock('./index.js', {
|
|
121
|
+
'#lib/npm/index.js': { default: {} },
|
|
122
|
+
'#lib/project/index.js': {
|
|
123
|
+
getVersionsFromStarter: sandbox.stub(),
|
|
124
|
+
setVersion: sandbox.stub(),
|
|
125
|
+
writeVersionFile: sandbox.stub()
|
|
126
|
+
},
|
|
127
|
+
'#lib/git/index.js': { default: {} },
|
|
128
|
+
'fs-extra': mockFs,
|
|
129
|
+
'#helpers/is-empty.js': { isEmpty: sandbox.stub() },
|
|
130
|
+
'#src/packageConfig.js': { default: { version: '1.0.0' } }
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
const result = getVersionFromPath('/local/quire')
|
|
134
|
+
|
|
135
|
+
t.is(result.version, '1.0.0-local')
|
|
136
|
+
t.truthy(result.resolvedPath)
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
140
|
+
// latest() tests
|
|
141
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
142
|
+
|
|
143
|
+
test('latest() returns latest version when called with "latest"', async (t) => {
|
|
144
|
+
const { sandbox } = t.context
|
|
145
|
+
|
|
146
|
+
const mockNpm = {
|
|
147
|
+
view: sandbox.stub().resolves('1.0.5'),
|
|
148
|
+
getCompatibleVersion: sandbox.stub()
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const { latest } = await esmock('./index.js', {
|
|
152
|
+
'#lib/npm/index.js': { default: mockNpm },
|
|
153
|
+
'#lib/project/index.js': {
|
|
154
|
+
getVersionsFromStarter: sandbox.stub(),
|
|
155
|
+
setVersion: sandbox.stub(),
|
|
156
|
+
writeVersionFile: sandbox.stub()
|
|
157
|
+
},
|
|
158
|
+
'#lib/git/index.js': { default: {} },
|
|
159
|
+
'fs-extra': {},
|
|
160
|
+
'#helpers/is-empty.js': { isEmpty: sandbox.stub() },
|
|
161
|
+
'#src/packageConfig.js': { default: { version: '1.0.0' } }
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
const result = await latest('latest')
|
|
165
|
+
|
|
166
|
+
t.is(result, '1.0.5')
|
|
167
|
+
t.true(mockNpm.view.calledWith('@thegetty/quire-11ty', 'version'))
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
test('latest() returns latest version when called without argument', async (t) => {
|
|
171
|
+
const { sandbox } = t.context
|
|
172
|
+
|
|
173
|
+
const mockNpm = {
|
|
174
|
+
view: sandbox.stub().resolves('1.0.5'),
|
|
175
|
+
getCompatibleVersion: sandbox.stub()
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const { latest } = await esmock('./index.js', {
|
|
179
|
+
'#lib/npm/index.js': { default: mockNpm },
|
|
180
|
+
'#lib/project/index.js': {
|
|
181
|
+
getVersionsFromStarter: sandbox.stub(),
|
|
182
|
+
setVersion: sandbox.stub(),
|
|
183
|
+
writeVersionFile: sandbox.stub()
|
|
184
|
+
},
|
|
185
|
+
'#lib/git/index.js': { default: {} },
|
|
186
|
+
'fs-extra': {},
|
|
187
|
+
'#helpers/is-empty.js': { isEmpty: sandbox.stub() },
|
|
188
|
+
'#src/packageConfig.js': { default: { version: '1.0.0' } }
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
const result = await latest()
|
|
192
|
+
|
|
193
|
+
t.is(result, '1.0.5')
|
|
194
|
+
t.true(mockNpm.view.calledWith('@thegetty/quire-11ty', 'version'))
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
test('latest() resolves semver range to compatible version', async (t) => {
|
|
198
|
+
const { sandbox } = t.context
|
|
199
|
+
|
|
200
|
+
const mockNpm = {
|
|
201
|
+
view: sandbox.stub(),
|
|
202
|
+
getCompatibleVersion: sandbox.stub().resolves('1.2.3')
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const { latest } = await esmock('./index.js', {
|
|
206
|
+
'#lib/npm/index.js': { default: mockNpm },
|
|
207
|
+
'#lib/project/index.js': {
|
|
208
|
+
getVersionsFromStarter: sandbox.stub(),
|
|
209
|
+
setVersion: sandbox.stub(),
|
|
210
|
+
writeVersionFile: sandbox.stub()
|
|
211
|
+
},
|
|
212
|
+
'#lib/git/index.js': { default: {} },
|
|
213
|
+
'fs-extra': {},
|
|
214
|
+
'#helpers/is-empty.js': { isEmpty: sandbox.stub() },
|
|
215
|
+
'#src/packageConfig.js': { default: { version: '1.0.0' } }
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
const result = await latest('^1.0.0')
|
|
219
|
+
|
|
220
|
+
t.is(result, '1.2.3')
|
|
221
|
+
t.true(mockNpm.getCompatibleVersion.calledWith('@thegetty/quire-11ty', '^1.0.0'))
|
|
222
|
+
t.false(mockNpm.view.called)
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
test('latest() throws error when no compatible version found', async (t) => {
|
|
226
|
+
const { sandbox } = t.context
|
|
227
|
+
|
|
228
|
+
const mockNpm = {
|
|
229
|
+
view: sandbox.stub(),
|
|
230
|
+
getCompatibleVersion: sandbox.stub().resolves(null)
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const { latest } = await esmock('./index.js', {
|
|
234
|
+
'#lib/npm/index.js': { default: mockNpm },
|
|
235
|
+
'#lib/project/index.js': {
|
|
236
|
+
getVersionsFromStarter: sandbox.stub(),
|
|
237
|
+
setVersion: sandbox.stub(),
|
|
238
|
+
writeVersionFile: sandbox.stub()
|
|
239
|
+
},
|
|
240
|
+
'#lib/git/index.js': { default: {} },
|
|
241
|
+
'fs-extra': {},
|
|
242
|
+
'#helpers/is-empty.js': { isEmpty: sandbox.stub() },
|
|
243
|
+
'#src/packageConfig.js': { default: { version: '1.0.0' } }
|
|
244
|
+
})
|
|
245
|
+
|
|
246
|
+
const error = await t.throwsAsync(() => latest('^99.0.0'))
|
|
247
|
+
|
|
248
|
+
t.is(error.code, 'VERSION_NOT_FOUND')
|
|
249
|
+
t.true(error.message.includes('^99.0.0'))
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
253
|
+
// versions() tests
|
|
254
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
255
|
+
|
|
256
|
+
test('versions() returns all published versions', async (t) => {
|
|
257
|
+
const { sandbox } = t.context
|
|
258
|
+
|
|
259
|
+
const mockNpm = {
|
|
260
|
+
show: sandbox.stub().resolves(['1.0.0', '1.0.1', '1.1.0'])
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const { versions } = await esmock('./index.js', {
|
|
264
|
+
'#lib/npm/index.js': { default: mockNpm },
|
|
265
|
+
'#lib/project/index.js': {
|
|
266
|
+
getVersionsFromStarter: sandbox.stub(),
|
|
267
|
+
setVersion: sandbox.stub(),
|
|
268
|
+
writeVersionFile: sandbox.stub()
|
|
269
|
+
},
|
|
270
|
+
'#lib/git/index.js': { default: {} },
|
|
271
|
+
'fs-extra': {},
|
|
272
|
+
'#helpers/is-empty.js': { isEmpty: sandbox.stub() },
|
|
273
|
+
'#src/packageConfig.js': { default: { version: '1.0.0' } }
|
|
274
|
+
})
|
|
275
|
+
|
|
276
|
+
const result = await versions()
|
|
277
|
+
|
|
278
|
+
t.deepEqual(result, ['1.0.0', '1.0.1', '1.1.0'])
|
|
279
|
+
t.true(mockNpm.show.calledWith('@thegetty/quire-11ty', 'versions'))
|
|
280
|
+
})
|
|
281
|
+
|
|
282
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
283
|
+
// initStarter() tests
|
|
284
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
285
|
+
|
|
286
|
+
test('initStarter() throws when target directory is not empty', async (t) => {
|
|
287
|
+
const { sandbox } = t.context
|
|
288
|
+
|
|
289
|
+
const mockFs = {
|
|
290
|
+
ensureDirSync: sandbox.stub(),
|
|
291
|
+
remove: sandbox.stub()
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Create a mock Git class
|
|
295
|
+
class MockGit {
|
|
296
|
+
constructor() {}
|
|
297
|
+
clone() { return Promise.resolve() }
|
|
298
|
+
init() { return Promise.resolve() }
|
|
299
|
+
add() { return Promise.resolve() }
|
|
300
|
+
commit() { return Promise.resolve() }
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
const { initStarter } = await esmock('./index.js', {
|
|
304
|
+
'#lib/npm/index.js': { default: {} },
|
|
305
|
+
'#lib/project/index.js': {
|
|
306
|
+
getVersionsFromStarter: sandbox.stub(),
|
|
307
|
+
setVersion: sandbox.stub(),
|
|
308
|
+
writeVersionFile: sandbox.stub()
|
|
309
|
+
},
|
|
310
|
+
'#lib/git/index.js': { Git: MockGit },
|
|
311
|
+
'fs-extra': mockFs,
|
|
312
|
+
'#helpers/is-empty.js': { isEmpty: sandbox.stub().returns(false) },
|
|
313
|
+
'#src/packageConfig.js': { default: { version: '1.0.0' } }
|
|
314
|
+
})
|
|
315
|
+
|
|
316
|
+
await t.throwsAsync(
|
|
317
|
+
() => initStarter('https://github.com/test/starter', '/project'),
|
|
318
|
+
{ message: /non-empty directory/ }
|
|
319
|
+
)
|
|
320
|
+
})
|
|
321
|
+
|
|
322
|
+
test('initStarter() clones starter and sets up project', async (t) => {
|
|
323
|
+
const { sandbox } = t.context
|
|
324
|
+
|
|
325
|
+
const mockFs = {
|
|
326
|
+
ensureDirSync: sandbox.stub(),
|
|
327
|
+
remove: sandbox.stub().resolves(),
|
|
328
|
+
readFileSync: sandbox.stub().returns(JSON.stringify({
|
|
329
|
+
version: '1.0.0',
|
|
330
|
+
peerDependencies: { '@thegetty/quire-11ty': '^1.0.0' }
|
|
331
|
+
})),
|
|
332
|
+
writeFileSync: sandbox.stub()
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// Create a mock Git class with spies
|
|
336
|
+
const gitSpies = {
|
|
337
|
+
clone: sandbox.stub().resolves(),
|
|
338
|
+
init: sandbox.stub().resolves(),
|
|
339
|
+
add: sandbox.stub().resolves(),
|
|
340
|
+
commit: sandbox.stub().resolves()
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
class MockGit {
|
|
344
|
+
constructor() {}
|
|
345
|
+
clone(...args) { return gitSpies.clone(...args) }
|
|
346
|
+
init(...args) { return gitSpies.init(...args) }
|
|
347
|
+
add(...args) { return gitSpies.add(...args) }
|
|
348
|
+
commit(...args) { return gitSpies.commit(...args) }
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
const mockNpm = {
|
|
352
|
+
init: sandbox.stub().resolves(),
|
|
353
|
+
getCompatibleVersion: sandbox.stub().resolves('1.2.0')
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
const { initStarter } = await esmock('./index.js', {
|
|
357
|
+
'#lib/npm/index.js': { default: mockNpm },
|
|
358
|
+
'#lib/project/index.js': {
|
|
359
|
+
getVersionsFromStarter: sandbox.stub().resolves({
|
|
360
|
+
quire11tyVersion: '^1.0.0',
|
|
361
|
+
starterVersion: '1.0.0'
|
|
362
|
+
}),
|
|
363
|
+
setVersion: sandbox.stub(),
|
|
364
|
+
writeVersionFile: sandbox.stub()
|
|
365
|
+
},
|
|
366
|
+
'#lib/git/index.js': { Git: MockGit },
|
|
367
|
+
'fs-extra': mockFs,
|
|
368
|
+
'#helpers/is-empty.js': { isEmpty: sandbox.stub().returns(true) },
|
|
369
|
+
'#src/packageConfig.js': { default: { version: '1.0.0' } }
|
|
370
|
+
})
|
|
371
|
+
|
|
372
|
+
const result = await initStarter('https://github.com/test/starter', '/project')
|
|
373
|
+
|
|
374
|
+
t.is(result, '1.2.0', 'should return resolved quire version')
|
|
375
|
+
t.true(gitSpies.clone.called, 'should clone starter repository')
|
|
376
|
+
t.true(gitSpies.init.called, 'should initialize git repository')
|
|
377
|
+
t.true(mockNpm.init.called, 'should run npm init')
|
|
378
|
+
})
|
|
379
|
+
|
|
380
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
381
|
+
// installer object export tests
|
|
382
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
383
|
+
|
|
384
|
+
test('installer object exports all required functions', async (t) => {
|
|
385
|
+
const { sandbox } = t.context
|
|
386
|
+
|
|
387
|
+
// Create a mock Git class
|
|
388
|
+
class MockGit {
|
|
389
|
+
constructor() {}
|
|
390
|
+
clone() { return Promise.resolve() }
|
|
391
|
+
init() { return Promise.resolve() }
|
|
392
|
+
add() { return Promise.resolve() }
|
|
393
|
+
commit() { return Promise.resolve() }
|
|
394
|
+
rm() { return Promise.resolve() }
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
const { installer } = await esmock('./index.js', {
|
|
398
|
+
'#lib/npm/index.js': { default: {} },
|
|
399
|
+
'#lib/project/index.js': {
|
|
400
|
+
getVersionsFromStarter: sandbox.stub(),
|
|
401
|
+
setVersion: sandbox.stub(),
|
|
402
|
+
writeVersionFile: sandbox.stub()
|
|
403
|
+
},
|
|
404
|
+
'#lib/git/index.js': { Git: MockGit },
|
|
405
|
+
'fs-extra': {},
|
|
406
|
+
'#helpers/is-empty.js': { isEmpty: sandbox.stub() },
|
|
407
|
+
'#src/packageConfig.js': { default: { version: '1.0.0' } }
|
|
408
|
+
})
|
|
409
|
+
|
|
410
|
+
t.is(typeof installer.initStarter, 'function', 'should export initStarter')
|
|
411
|
+
t.is(typeof installer.installInProject, 'function', 'should export installInProject')
|
|
412
|
+
t.is(typeof installer.latest, 'function', 'should export latest')
|
|
413
|
+
t.is(typeof installer.versions, 'function', 'should export versions')
|
|
414
|
+
})
|
|
415
|
+
|
|
416
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
417
|
+
// installInProject() quirePath validation tests
|
|
418
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
419
|
+
|
|
420
|
+
test('installInProject() throws InvalidPathError when quirePath does not exist', async (t) => {
|
|
421
|
+
const { sandbox } = t.context
|
|
422
|
+
|
|
423
|
+
// Create a mock Git class
|
|
424
|
+
class MockGit {
|
|
425
|
+
constructor() {}
|
|
426
|
+
rm() { return Promise.resolve() }
|
|
427
|
+
add() { return Promise.resolve() }
|
|
428
|
+
commit() { return Promise.resolve() }
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
const mockFs = {
|
|
432
|
+
mkdirSync: sandbox.stub(),
|
|
433
|
+
existsSync: sandbox.stub().returns(false)
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
const { installInProject } = await esmock('./index.js', {
|
|
437
|
+
'#lib/npm/index.js': { default: {} },
|
|
438
|
+
'#lib/project/index.js': {
|
|
439
|
+
getVersionsFromStarter: sandbox.stub(),
|
|
440
|
+
setVersion: sandbox.stub(),
|
|
441
|
+
writeVersionFile: sandbox.stub()
|
|
442
|
+
},
|
|
443
|
+
'#lib/git/index.js': { Git: MockGit },
|
|
444
|
+
'fs-extra': mockFs,
|
|
445
|
+
'#helpers/is-empty.js': { isEmpty: sandbox.stub() },
|
|
446
|
+
'#src/packageConfig.js': { default: { version: '1.0.0' } }
|
|
447
|
+
})
|
|
448
|
+
|
|
449
|
+
const error = await t.throwsAsync(
|
|
450
|
+
() => installInProject('/project', '1.0.0', { quirePath: '/nonexistent/path' })
|
|
451
|
+
)
|
|
452
|
+
|
|
453
|
+
t.is(error.code, 'INVALID_PATH', 'should throw InvalidPathError')
|
|
454
|
+
t.true(error.message.includes('--quire-path does not exist'))
|
|
455
|
+
t.true(error.message.includes('/nonexistent/path'))
|
|
456
|
+
})
|
|
457
|
+
|
|
458
|
+
test('installInProject() throws InvalidPathError with resolved path for relative quirePath', async (t) => {
|
|
459
|
+
const { sandbox } = t.context
|
|
460
|
+
|
|
461
|
+
// Create a mock Git class
|
|
462
|
+
class MockGit {
|
|
463
|
+
constructor() {}
|
|
464
|
+
rm() { return Promise.resolve() }
|
|
465
|
+
add() { return Promise.resolve() }
|
|
466
|
+
commit() { return Promise.resolve() }
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
const mockFs = {
|
|
470
|
+
mkdirSync: sandbox.stub(),
|
|
471
|
+
existsSync: sandbox.stub().returns(false)
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
const { installInProject } = await esmock('./index.js', {
|
|
475
|
+
'#lib/npm/index.js': { default: {} },
|
|
476
|
+
'#lib/project/index.js': {
|
|
477
|
+
getVersionsFromStarter: sandbox.stub(),
|
|
478
|
+
setVersion: sandbox.stub(),
|
|
479
|
+
writeVersionFile: sandbox.stub()
|
|
480
|
+
},
|
|
481
|
+
'#lib/git/index.js': { Git: MockGit },
|
|
482
|
+
'fs-extra': mockFs,
|
|
483
|
+
'#helpers/is-empty.js': { isEmpty: sandbox.stub() },
|
|
484
|
+
'#src/packageConfig.js': { default: { version: '1.0.0' } }
|
|
485
|
+
})
|
|
486
|
+
|
|
487
|
+
const error = await t.throwsAsync(
|
|
488
|
+
() => installInProject('/project', '1.0.0', { quirePath: '../relative/path' })
|
|
489
|
+
)
|
|
490
|
+
|
|
491
|
+
t.is(error.code, 'INVALID_PATH', 'should throw InvalidPathError')
|
|
492
|
+
t.true(error.message.includes('--quire-path does not exist'))
|
|
493
|
+
t.true(error.message.includes('../relative/path'))
|
|
494
|
+
t.true(error.message.includes('resolved to:'), 'should show resolved path for relative paths')
|
|
495
|
+
})
|
|
496
|
+
|
|
497
|
+
test('installInProject() copies from quirePath when it exists', async (t) => {
|
|
498
|
+
const { sandbox } = t.context
|
|
499
|
+
|
|
500
|
+
// Create a mock Git class
|
|
501
|
+
class MockGit {
|
|
502
|
+
constructor() {}
|
|
503
|
+
rm() { return Promise.resolve() }
|
|
504
|
+
add() { return Promise.resolve() }
|
|
505
|
+
commit() { return Promise.resolve() }
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
const cpSyncStub = sandbox.stub()
|
|
509
|
+
const rmSyncStub = sandbox.stub()
|
|
510
|
+
|
|
511
|
+
const mockFs = {
|
|
512
|
+
mkdirSync: sandbox.stub(),
|
|
513
|
+
existsSync: sandbox.stub().returns(true),
|
|
514
|
+
readJsonSync: sandbox.stub().returns({ version: '1.0.0-local' }),
|
|
515
|
+
cpSync: cpSyncStub,
|
|
516
|
+
rmSync: rmSyncStub
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
const mockNpm = {
|
|
520
|
+
install: sandbox.stub().resolves()
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
const { installInProject } = await esmock('./index.js', {
|
|
524
|
+
'#lib/npm/index.js': { default: mockNpm },
|
|
525
|
+
'#lib/project/index.js': {
|
|
526
|
+
getVersionsFromStarter: sandbox.stub(),
|
|
527
|
+
setVersion: sandbox.stub(),
|
|
528
|
+
writeVersionFile: sandbox.stub()
|
|
529
|
+
},
|
|
530
|
+
'#lib/git/index.js': { Git: MockGit },
|
|
531
|
+
'fs-extra': mockFs,
|
|
532
|
+
'#helpers/is-empty.js': { isEmpty: sandbox.stub() },
|
|
533
|
+
'#src/packageConfig.js': { default: { version: '1.0.0' } }
|
|
534
|
+
})
|
|
535
|
+
|
|
536
|
+
await installInProject('/project', '1.0.0', { quirePath: '/local/quire-11ty' })
|
|
537
|
+
|
|
538
|
+
// Should copy from local path, not download
|
|
539
|
+
t.true(cpSyncStub.called, 'should copy from local path')
|
|
540
|
+
const [srcPath] = cpSyncStub.firstCall.args
|
|
541
|
+
t.is(srcPath, path.resolve('/local/quire-11ty'), 'should use resolved quirePath as source')
|
|
542
|
+
})
|
|
543
|
+
|
|
544
|
+
// Nota bene: Version reading from local package.json is now done in initStarter
|
|
545
|
+
// via getVersionFromPath, not in installInProject. See getVersionFromPath tests above.
|