@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.
Files changed (158) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.md +9 -0
  3. package/bin/cli.js +19 -1
  4. package/package.json +21 -8
  5. package/patches/README.md +19 -0
  6. package/patches/install-npm-version+1.0.9.patch +12119 -0
  7. package/schemas/objects.schema.json +12 -38
  8. package/schemas/publication.schema.json +0 -22
  9. package/schemas/references.schema.json +0 -1
  10. package/src/Command.js +26 -6
  11. package/src/Command.spec.js +99 -0
  12. package/src/commands/README.md +213 -122
  13. package/src/commands/build.js +46 -37
  14. package/src/commands/build.spec.js +113 -0
  15. package/src/commands/build.test.js +402 -0
  16. package/src/commands/clean.js +25 -19
  17. package/src/commands/clean.spec.js +108 -0
  18. package/src/commands/clean.test.js +260 -0
  19. package/src/commands/config.js +251 -0
  20. package/src/commands/config.spec.js +107 -0
  21. package/src/commands/config.test.js +715 -0
  22. package/src/commands/create.js +42 -14
  23. package/src/commands/create.spec.js +112 -0
  24. package/src/commands/create.test.js +415 -0
  25. package/src/commands/epub.js +59 -30
  26. package/src/commands/epub.spec.js +114 -0
  27. package/src/commands/epub.test.js +503 -0
  28. package/src/commands/index.js +9 -2
  29. package/src/commands/info.js +18 -24
  30. package/src/commands/info.spec.js +64 -0
  31. package/src/commands/info.test.js +415 -0
  32. package/src/commands/pdf.js +58 -84
  33. package/src/commands/pdf.spec.js +114 -0
  34. package/src/commands/pdf.test.js +464 -0
  35. package/src/commands/preview.js +26 -31
  36. package/src/commands/preview.spec.js +97 -0
  37. package/src/commands/preview.test.js +250 -0
  38. package/src/commands/use.js +56 -0
  39. package/src/commands/use.spec.js +61 -0
  40. package/src/commands/use.test.js +280 -0
  41. package/src/commands/validate.js +31 -19
  42. package/src/commands/validate.spec.js +82 -0
  43. package/src/commands/validate.test.js +234 -0
  44. package/src/commands/workflows.js +70 -0
  45. package/src/errors/build/build-failed-error.js +19 -0
  46. package/src/errors/build/config-field-missing-error.js +20 -0
  47. package/src/errors/build/config-file-not-found-error.js +20 -0
  48. package/src/errors/build/index.js +11 -0
  49. package/src/errors/index.js +48 -0
  50. package/src/errors/install/dependency-install-error.js +19 -0
  51. package/src/errors/install/directory-not-empty-error.js +25 -0
  52. package/src/errors/install/index.js +12 -0
  53. package/src/errors/install/invalid-path-error.js +31 -0
  54. package/src/errors/install/invalid-starter-error.js +27 -0
  55. package/src/errors/install/version-not-found-error.js +35 -0
  56. package/src/errors/output/epub-generation-error.js +19 -0
  57. package/src/errors/output/index.js +14 -0
  58. package/src/errors/output/invalid-epub-library-error.js +20 -0
  59. package/src/errors/output/invalid-pdf-library-error.js +20 -0
  60. package/src/errors/output/missing-build-output-error.js +21 -0
  61. package/src/errors/output/pdf-generation-error.js +24 -0
  62. package/src/errors/output/tool-not-found-error.js +37 -0
  63. package/src/errors/project/index.js +10 -0
  64. package/src/errors/project/not-in-project-error.js +20 -0
  65. package/src/errors/project/project-create-error.js +21 -0
  66. package/src/errors/quire-error.js +27 -0
  67. package/src/errors/validation/validation-error.js +20 -11
  68. package/src/helpers/clean.js +1 -1
  69. package/src/helpers/docs-url.js +32 -0
  70. package/src/helpers/test-cwd.js +5 -6
  71. package/src/helpers/test-cwd.test.js +192 -0
  72. package/src/helpers/which.js +10 -4
  73. package/src/lib/11ty/README.md +135 -19
  74. package/src/lib/11ty/api.js +176 -93
  75. package/src/lib/11ty/cli.js +77 -35
  76. package/src/lib/11ty/index.js +64 -5
  77. package/src/lib/11ty/index.test.js +655 -0
  78. package/src/lib/README.md +275 -0
  79. package/src/lib/commander/index.js +100 -0
  80. package/src/lib/commander/index.test.js +86 -0
  81. package/src/lib/commander/options.js +195 -0
  82. package/src/lib/commander/options.test.js +109 -0
  83. package/src/lib/conf/README.md +84 -73
  84. package/src/lib/conf/config.js +5 -3
  85. package/src/lib/conf/config.test.js +281 -0
  86. package/src/lib/conf/defaults.js +44 -0
  87. package/src/lib/conf/format.js +60 -0
  88. package/src/lib/conf/format.test.js +106 -0
  89. package/src/lib/conf/helpers.js +91 -0
  90. package/src/lib/conf/helpers.test.js +136 -0
  91. package/src/lib/conf/index.js +22 -0
  92. package/src/lib/conf/schema.js +53 -8
  93. package/src/lib/epub/README.md +133 -2
  94. package/src/lib/epub/engines.js +46 -0
  95. package/src/lib/epub/epub.js +36 -11
  96. package/src/lib/epub/index.js +111 -21
  97. package/src/lib/epub/index.test.js +518 -0
  98. package/src/lib/epub/pandoc.js +33 -4
  99. package/src/lib/epub/pandoc.test.js +122 -0
  100. package/src/lib/epub/schema.js +21 -0
  101. package/src/lib/error/README.md +170 -0
  102. package/src/lib/error/handler.js +107 -0
  103. package/src/lib/git/README.md +151 -2
  104. package/src/lib/git/index.js +217 -13
  105. package/src/lib/git/index.spec.js +80 -0
  106. package/src/lib/git/index.test.js +453 -0
  107. package/src/lib/installer/index.js +309 -0
  108. package/src/lib/installer/index.spec.js +83 -0
  109. package/src/lib/installer/index.test.js +545 -0
  110. package/src/lib/logger/README.md +424 -0
  111. package/src/lib/logger/debug.js +90 -0
  112. package/src/lib/logger/debug.spec.js +130 -0
  113. package/src/lib/logger/index.js +228 -0
  114. package/src/lib/logger/index.spec.js +131 -0
  115. package/src/lib/logger/index.test.js +477 -0
  116. package/src/lib/npm/README.md +127 -0
  117. package/src/lib/npm/index.js +198 -0
  118. package/src/lib/npm/index.spec.js +60 -0
  119. package/src/lib/npm/index.test.js +355 -0
  120. package/src/lib/pdf/README.md +131 -0
  121. package/src/lib/pdf/engines.js +46 -0
  122. package/src/lib/pdf/index.js +124 -21
  123. package/src/lib/pdf/index.test.js +708 -0
  124. package/src/lib/pdf/paged.js +100 -52
  125. package/src/lib/pdf/paged.test.js +366 -0
  126. package/src/lib/pdf/prince.js +115 -37
  127. package/src/lib/pdf/prince.test.js +202 -0
  128. package/src/lib/pdf/schema.js +21 -0
  129. package/src/lib/pdf/split.js +61 -33
  130. package/src/lib/pdf/split.test.js +445 -0
  131. package/src/lib/process/manager.js +110 -0
  132. package/src/lib/process/manager.test.js +55 -0
  133. package/src/lib/project/build.js +143 -0
  134. package/src/lib/project/build.test.js +253 -0
  135. package/src/lib/project/config.js +48 -0
  136. package/src/lib/project/config.test.js +134 -0
  137. package/src/{helpers/is-quire.js → lib/project/detect.js} +5 -3
  138. package/src/lib/project/detect.test.js +157 -0
  139. package/src/lib/project/index.js +40 -0
  140. package/src/lib/project/paths.js +224 -0
  141. package/src/lib/project/version.js +110 -0
  142. package/src/lib/project/version.test.js +350 -0
  143. package/src/lib/reporter/README.md +211 -2
  144. package/src/lib/reporter/index.js +512 -0
  145. package/src/lib/reporter/index.test.js +593 -0
  146. package/src/main.js +134 -47
  147. package/src/main.spec.js +61 -0
  148. package/src/main.test.js +347 -0
  149. package/src/validators/utils.js +2 -1
  150. package/src/commands/conf.js +0 -43
  151. package/src/commands/version.js +0 -43
  152. package/src/lib/11ty/paths.js +0 -103
  153. package/src/lib/i18n/README.md +0 -3
  154. package/src/lib/i18n/config.js +0 -53
  155. package/src/lib/i18n/index.js +0 -43
  156. package/src/lib/i18n/localeService.js +0 -58
  157. package/src/lib/quire/README.md +0 -19
  158. package/src/lib/quire/index.js +0 -350
@@ -0,0 +1,309 @@
1
+ /**
2
+ * Installer module
3
+ *
4
+ * Handles installation of quire-11ty into Quire projects,
5
+ * including starter project initialization and dependency setup.
6
+ *
7
+ * @module lib/installer
8
+ */
9
+ import { execa } from 'execa'
10
+ import { fileURLToPath } from 'node:url'
11
+ import { isEmpty } from '#helpers/is-empty.js'
12
+ import fs from 'fs-extra'
13
+ import { Git, validateCloneSource } from '#lib/git/index.js'
14
+ import npm from '#lib/npm/index.js'
15
+ import packageConfig from '#src/packageConfig.js'
16
+ import path from 'node:path'
17
+ import {
18
+ getVersionsFromStarter,
19
+ setVersion,
20
+ writeVersionFile,
21
+ } from '#lib/project/index.js'
22
+ import { DirectoryNotEmptyError, InvalidPathError, InvalidStarterError, VersionNotFoundError } from '#src/errors/index.js'
23
+ import { logger } from '#lib/logger/index.js'
24
+ import reporter from '#lib/reporter/index.js'
25
+ import createDebug from '#debug'
26
+
27
+ const __filename = fileURLToPath(import.meta.url)
28
+ const __dirname = path.dirname(__filename)
29
+
30
+ const debug = createDebug('lib:installer')
31
+
32
+ const PACKAGE_NAME = '@thegetty/quire-11ty'
33
+
34
+ /**
35
+ * Read the version from a local quire-11ty package
36
+ *
37
+ * @param {string} quirePath - Path to local quire-11ty package (will be resolved)
38
+ * @returns {{ version: string, resolvedPath: string }} Version and resolved path
39
+ * @throws {InvalidPathError} When the path does not exist
40
+ * @throws {VersionNotFoundError} When the package.json is missing or has no version
41
+ */
42
+ export function getVersionFromPath(quirePath) {
43
+ const resolvedPath = path.resolve(quirePath)
44
+ debug('reading version from local path: %s (resolved: %s)', quirePath, resolvedPath)
45
+
46
+ if (!fs.existsSync(resolvedPath)) {
47
+ throw new InvalidPathError(quirePath, resolvedPath)
48
+ }
49
+
50
+ const localPackageJsonPath = path.join(resolvedPath, 'package.json')
51
+ if (!fs.existsSync(localPackageJsonPath)) {
52
+ throw new VersionNotFoundError(resolvedPath, 'package.json not found')
53
+ }
54
+
55
+ try {
56
+ const localPackage = fs.readJsonSync(localPackageJsonPath)
57
+ if (!localPackage.version) {
58
+ throw new VersionNotFoundError(resolvedPath, 'package.json has no version field')
59
+ }
60
+ return { version: localPackage.version, resolvedPath }
61
+ } catch (error) {
62
+ if (error.code === 'VERSION_NOT_FOUND') {
63
+ throw error
64
+ }
65
+ throw new VersionNotFoundError(
66
+ resolvedPath,
67
+ `Failed to read package.json: ${error.message}`
68
+ )
69
+ }
70
+ }
71
+
72
+ /**
73
+ * Retrieve latest published version of the quire-11ty package
74
+ * or the latest compatible version with the provided semantic version string
75
+ *
76
+ * @param {string} version - A semantic version string, e.g. `^1.0.0-pre-release.0`
77
+ * @returns {Promise<string>} quire-11ty semantic version string
78
+ */
79
+ export async function latest(version) {
80
+ let quireVersion
81
+ if (!version || version === 'latest') {
82
+ quireVersion = await npm.view(PACKAGE_NAME, 'version')
83
+ } else {
84
+ quireVersion = await npm.getCompatibleVersion(PACKAGE_NAME, version)
85
+ }
86
+ if (!quireVersion) {
87
+ throw new VersionNotFoundError(PACKAGE_NAME, version)
88
+ }
89
+ return quireVersion
90
+ }
91
+
92
+ /**
93
+ * Get an array of published quire-11ty package versions
94
+ *
95
+ * @returns {Promise<Array<string>>} Published versions
96
+ */
97
+ export async function versions() {
98
+ return await npm.show(PACKAGE_NAME, 'versions')
99
+ }
100
+
101
+ /**
102
+ * Clone or copy a Quire starter project
103
+ *
104
+ * @param {string} starter - A repository URL or an absolute path to local starter
105
+ * @param {string} projectPath - Absolute system path to the project root
106
+ * @param {Object} options - Installation options
107
+ * @returns {Promise<string>} quireVersion - The quire-11ty version for the new project
108
+ */
109
+ export async function initStarter(starter, projectPath, options = {}) {
110
+ projectPath = projectPath || process.cwd()
111
+
112
+ /**
113
+ * Validate arguments before any side effects (directory creation, cloning)
114
+ */
115
+
116
+ // Validate starter is a valid clone source (URL or local git repo)
117
+ const starterValidation = validateCloneSource(starter)
118
+ if (!starterValidation.valid) {
119
+ throw new InvalidStarterError(starter, starterValidation.reason)
120
+ }
121
+
122
+ // Validate --quire-path points to a valid local quire-11ty package
123
+ let localQuire11tyInfo
124
+ if (options.quirePath) {
125
+ localQuire11tyInfo = getVersionFromPath(options.quirePath)
126
+ }
127
+
128
+ // Ensure that the target path exists
129
+ fs.ensureDirSync(projectPath)
130
+
131
+ // If the target directory exists it must be empty
132
+ if (!isEmpty(projectPath)) {
133
+ throw new DirectoryNotEmptyError(projectPath)
134
+ }
135
+
136
+ const fullPath = path.join(__dirname, projectPath)
137
+ debug(`init-starter\n project: ${fullPath}\n starter: ${starter}`)
138
+
139
+ /**
140
+ * Clone starter project repository
141
+ */
142
+ reporter.start('Cloning starter project...')
143
+ const repository = new Git(projectPath)
144
+ await repository.clone(starter, '.')
145
+
146
+ /**
147
+ * Determine the quire-11ty version to use in the new project:
148
+ * 1. If --quire-path is provided, use the version from the local package (already validated)
149
+ * 2. Otherwise, use --quire-version option or the version required by the starter
150
+ *
151
+ * Uses 'latest' to get the latest semantic version compatible with version ranges
152
+ */
153
+ reporter.update('Resolving quire-11ty version...')
154
+ const { quire11tyVersion, starterVersion } = await getVersionsFromStarter(projectPath)
155
+
156
+ let quireVersion
157
+ if (localQuire11tyInfo) {
158
+ // Use the pre-validated local quire-11ty package
159
+ const { version, resolvedPath } = localQuire11tyInfo
160
+ quireVersion = version
161
+ logger.info(`Using local quire-11ty: ${version} from ${resolvedPath}`)
162
+ } else {
163
+ quireVersion = await latest(options.quireVersion || quire11tyVersion)
164
+ }
165
+
166
+ setVersion(quireVersion, projectPath)
167
+
168
+ /**
169
+ * Write quire-11ty, quire-cli, starter versions to the version file
170
+ */
171
+ const versionInfo = {
172
+ cli: packageConfig.version,
173
+ starter: `${starter}@${starterVersion}`,
174
+ }
175
+ writeVersionFile(projectPath, versionInfo)
176
+
177
+ // Re-initialize project directory as a new git repository
178
+ reporter.update('Initializing git repository...')
179
+ await fs.remove(path.join(projectPath, '.git'))
180
+
181
+ /**
182
+ * Remove the starter repository package config file
183
+ * and create a new package config for the project
184
+ * (this is necessary for Eleventy to resolve project paths)
185
+ */
186
+ await fs.remove(path.join(projectPath, 'package.json'))
187
+ await npm.init(projectPath)
188
+
189
+ /**
190
+ * Create an initial commit of files in new repository
191
+ * Using '.' respects .gitignore and avoids attempting to add ignored directories
192
+ */
193
+ await repository.init()
194
+ await repository.add('.')
195
+ await repository.commit('Initial Commit')
196
+ return quireVersion
197
+ }
198
+
199
+ /**
200
+ * Install quire-11ty directly into a Quire project
201
+ *
202
+ * @param {string} projectPath - Absolute system path to the project root
203
+ * @param {string} quireVersion - quire-11ty version to install
204
+ * @param {Object} options - Installation options
205
+ * @param {string} [options.quirePath] - Local path to quire-11ty package
206
+ * @param {boolean} [options.debug] - Enable debug output
207
+ * @param {boolean} [options.cleanCache] - Force clean npm cache before install
208
+ * @returns {Promise<void>}
209
+ */
210
+ export async function installInProject(projectPath, quireVersion, options = {}) {
211
+ const { quirePath } = options
212
+ const quire11tyPackage = `${PACKAGE_NAME}@${quireVersion}`
213
+
214
+ debug('installing %s into %s', quire11tyPackage, projectPath)
215
+
216
+ /**
217
+ * Delete the starter project package configuration so that it can be replaced
218
+ * with the @thegetty/quire-11ty configuration
219
+ */
220
+ const repository = new Git(projectPath)
221
+ try {
222
+ await repository.rm(['package.json'])
223
+ } catch (error) {
224
+ debug('error removing package.json: %O', error)
225
+ }
226
+
227
+ const temp11tyDirectory = '.temp'
228
+ const tempDir = path.join(projectPath, temp11tyDirectory)
229
+ fs.mkdirSync(tempDir)
230
+
231
+ // Copy if passed a path, otherwise attempt to download the tarball
232
+ if (quirePath) {
233
+ // Normalize the path to handle relative paths and `..` segments
234
+ // Nota bene: Path validation is done in initStarter via getVersionFromPath,
235
+ // but we validate again here to support direct calls to installInProject
236
+ const resolvedPath = path.resolve(quirePath)
237
+ debug('using local quire-11ty path: %s (resolved: %s)', quirePath, resolvedPath)
238
+
239
+ if (!fs.existsSync(resolvedPath)) {
240
+ throw new InvalidPathError(quirePath, resolvedPath)
241
+ }
242
+
243
+ reporter.update('Copying local quire-11ty package...')
244
+ fs.cpSync(resolvedPath, tempDir, { recursive: true })
245
+ } else {
246
+ reporter.update(`Downloading quire-11ty ${quireVersion}...`)
247
+ await npm.pack(quire11tyPackage, tempDir, { debug: options.debug, quiet: !options.debug })
248
+
249
+ // Extract only the package dir from the archive and strip it from the extracted path
250
+ // Nota bene: Use array-based execa() to prevent command injection via path variables
251
+ reporter.update('Extracting package...')
252
+ const tarballPath = path.join(tempDir, `thegetty-quire-11ty-${quireVersion}.tgz`)
253
+ await execa('tar', ['-xzf', tarballPath, '-C', tempDir, '--strip-components=1', 'package/'])
254
+
255
+ fs.rmSync(tarballPath)
256
+ }
257
+
258
+ // Copy `.temp` to projectPath
259
+ fs.cpSync(tempDir, projectPath, { recursive: true })
260
+
261
+ debug('installing dev dependencies into quire project')
262
+
263
+ /**
264
+ * Manually install necessary dev dependencies to run 11ty;
265
+ * these must be devDependencies so that they are not bundled into
266
+ * the final _site package when running `quire build`
267
+ *
268
+ * Installing with --prefer-offline prioritizes local cache,
269
+ * falling back to network only when necessary.
270
+ */
271
+ reporter.update('Installing dependencies (this may take a few minutes)...')
272
+ try {
273
+ if (options.cleanCache) {
274
+ // Nota bene: cache is self-healing, this should not be necessary.
275
+ await npm.cacheClean(projectPath)
276
+ }
277
+ await npm.install(projectPath, { saveDev: true, preferOffline: true })
278
+ } catch (error) {
279
+ logger.warn('Failed to install dependencies')
280
+ debug('install error: %O', error)
281
+ // Nota bene: Auto-deletion of projectPath is disabled to prevent accidental data loss.
282
+ // The project directory may contain user content that predates this install attempt.
283
+ // TODO: Implement safe cleanup that tracks whether we created the directory.
284
+ throw error
285
+ }
286
+
287
+ // Remove temporary 11ty install directory before committing
288
+ // to avoid including install artifacts in the commit
289
+ fs.rmSync(path.join(projectPath, temp11tyDirectory), { recursive: true })
290
+
291
+ /**
292
+ * Create an additional commit of new @thegetty/quire-11ty files in repository
293
+ * Using '.' respects .gitignore and avoids attempting to add ignored directories
294
+ */
295
+ reporter.update('Finalizing project...')
296
+ await repository.add('.')
297
+ await repository.commit('Adds `@thegetty/quire-11ty` files')
298
+ }
299
+
300
+ /**
301
+ * Export installer functions
302
+ */
303
+ export const installer = {
304
+ getVersionFromPath,
305
+ initStarter,
306
+ installInProject,
307
+ latest,
308
+ versions,
309
+ }
@@ -0,0 +1,83 @@
1
+ import test from 'ava'
2
+ import { installer, getVersionFromPath, initStarter, installInProject, latest, versions } from './index.js'
3
+
4
+ /**
5
+ * Installer Module Unit Tests
6
+ *
7
+ * Tests the installer module interface and API contract.
8
+ * These tests verify the module exports and method signatures
9
+ * without actually executing the installer operations.
10
+ */
11
+
12
+ // Module export tests
13
+ test('installer module exports installer object', (t) => {
14
+ t.truthy(installer, 'installer should be exported')
15
+ t.is(typeof installer, 'object', 'installer should be an object')
16
+ })
17
+
18
+ test('installer module exports initStarter function', (t) => {
19
+ t.truthy(initStarter, 'initStarter should be exported')
20
+ t.is(typeof initStarter, 'function', 'initStarter should be a function')
21
+ })
22
+
23
+ test('installer module exports installInProject function', (t) => {
24
+ t.truthy(installInProject, 'installInProject should be exported')
25
+ t.is(typeof installInProject, 'function', 'installInProject should be a function')
26
+ })
27
+
28
+ test('installer module exports latest function', (t) => {
29
+ t.truthy(latest, 'latest should be exported')
30
+ t.is(typeof latest, 'function', 'latest should be a function')
31
+ })
32
+
33
+ test('installer module exports versions function', (t) => {
34
+ t.truthy(versions, 'versions should be exported')
35
+ t.is(typeof versions, 'function', 'versions should be a function')
36
+ })
37
+
38
+ test('installer module exports getVersionFromPath function', (t) => {
39
+ t.truthy(getVersionFromPath, 'getVersionFromPath should be exported')
40
+ t.is(typeof getVersionFromPath, 'function', 'getVersionFromPath should be a function')
41
+ })
42
+
43
+ // installer object methods tests
44
+ test('installer object has initStarter method', (t) => {
45
+ t.is(typeof installer.initStarter, 'function', 'initStarter should be a function')
46
+ })
47
+
48
+ test('installer object has installInProject method', (t) => {
49
+ t.is(typeof installer.installInProject, 'function', 'installInProject should be a function')
50
+ })
51
+
52
+ test('installer object has latest method', (t) => {
53
+ t.is(typeof installer.latest, 'function', 'latest should be a function')
54
+ })
55
+
56
+ test('installer object has versions method', (t) => {
57
+ t.is(typeof installer.versions, 'function', 'versions should be a function')
58
+ })
59
+
60
+ test('installer object has getVersionFromPath method', (t) => {
61
+ t.is(typeof installer.getVersionFromPath, 'function', 'getVersionFromPath should be a function')
62
+ })
63
+
64
+ // Verify exported functions match installer object methods
65
+ test('exported initStarter matches installer.initStarter', (t) => {
66
+ t.is(initStarter, installer.initStarter, 'initStarter export should match installer.initStarter')
67
+ })
68
+
69
+ test('exported installInProject matches installer.installInProject', (t) => {
70
+ t.is(installInProject, installer.installInProject, 'installInProject export should match installer.installInProject')
71
+ })
72
+
73
+ test('exported latest matches installer.latest', (t) => {
74
+ t.is(latest, installer.latest, 'latest export should match installer.latest')
75
+ })
76
+
77
+ test('exported versions matches installer.versions', (t) => {
78
+ t.is(versions, installer.versions, 'versions export should match installer.versions')
79
+ })
80
+
81
+ test('exported getVersionFromPath matches installer.getVersionFromPath', (t) => {
82
+ t.is(getVersionFromPath, installer.getVersionFromPath, 'getVersionFromPath export should match installer.getVersionFromPath')
83
+ })