adapt-cli 3.0.0 → 3.0.7

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 (79) hide show
  1. package/.bowerrc +2 -2
  2. package/.eslintignore +1 -1
  3. package/.eslintrc.json +14 -14
  4. package/.github/CONTRIBUTING.md +8 -0
  5. package/.github/ISSUE_TEMPLATE.md +17 -0
  6. package/.github/pull_request_template.md +25 -0
  7. package/.github/workflows/addtomainproject.yml +19 -0
  8. package/.github/workflows/releases.yml +25 -0
  9. package/.travis.yml +46 -46
  10. package/README.md +266 -266
  11. package/bin/adapt.js +3 -3
  12. package/json/help-create/component.json +9 -9
  13. package/json/help-create/course.json +9 -9
  14. package/json/help-create/question.json +9 -9
  15. package/json/help-create.json +12 -12
  16. package/json/help-devinstall.json +9 -9
  17. package/json/help-install.json +10 -10
  18. package/json/help-ls.json +7 -7
  19. package/json/help-register.json +7 -7
  20. package/json/help-rename.json +7 -7
  21. package/json/help-search.json +8 -8
  22. package/json/help-uninstall.json +7 -7
  23. package/json/help-unregister.json +8 -8
  24. package/json/help-update.json +12 -12
  25. package/json/help-version.json +7 -7
  26. package/json/help.json +19 -19
  27. package/lib/api.js +273 -260
  28. package/lib/cli.js +70 -69
  29. package/lib/commands/authenticate.js +18 -18
  30. package/lib/commands/create/component.js +64 -64
  31. package/lib/commands/create/course.js +26 -26
  32. package/lib/commands/create/question.js +18 -18
  33. package/lib/commands/create.js +94 -85
  34. package/lib/commands/devinstall.js +35 -35
  35. package/lib/commands/help.js +31 -31
  36. package/lib/commands/install.js +16 -16
  37. package/lib/commands/ls.js +35 -9
  38. package/lib/commands/register.js +11 -11
  39. package/lib/commands/rename.js +14 -14
  40. package/lib/commands/search.js +11 -11
  41. package/lib/commands/uninstall.js +9 -9
  42. package/lib/commands/unregister.js +12 -12
  43. package/lib/commands/update.js +12 -12
  44. package/lib/commands/version.js +13 -13
  45. package/lib/econnreset.js +8 -0
  46. package/lib/integration/AdaptFramework/build.js +42 -39
  47. package/lib/integration/AdaptFramework/clone.js +27 -27
  48. package/lib/integration/AdaptFramework/deleteSrcCore.js +9 -9
  49. package/lib/integration/AdaptFramework/deleteSrcCourse.js +9 -9
  50. package/lib/integration/AdaptFramework/download.js +21 -21
  51. package/lib/integration/AdaptFramework/erase.js +34 -34
  52. package/lib/integration/AdaptFramework/getLatestVersion.js +74 -79
  53. package/lib/integration/AdaptFramework/npmInstall.js +21 -21
  54. package/lib/integration/AdaptFramework.js +19 -19
  55. package/lib/integration/Plugin.js +404 -403
  56. package/lib/integration/PluginManagement/autenticate.js +47 -56
  57. package/lib/integration/PluginManagement/install.js +224 -222
  58. package/lib/integration/PluginManagement/print.js +52 -52
  59. package/lib/integration/PluginManagement/register.js +130 -130
  60. package/lib/integration/PluginManagement/rename.js +95 -101
  61. package/lib/integration/PluginManagement/schemas.js +8 -8
  62. package/lib/integration/PluginManagement/search.js +37 -46
  63. package/lib/integration/PluginManagement/uninstall.js +141 -141
  64. package/lib/integration/PluginManagement/unregister.js +91 -101
  65. package/lib/integration/PluginManagement/update.js +224 -224
  66. package/lib/integration/PluginManagement.js +21 -21
  67. package/lib/integration/Project.js +146 -146
  68. package/lib/integration/Target.js +299 -296
  69. package/lib/integration/getBowerRegistryConfig.js +34 -34
  70. package/lib/logger.js +28 -28
  71. package/lib/util/JSONReadValidate.js +34 -34
  72. package/lib/util/constants.js +38 -38
  73. package/lib/util/createPromptTask.js +7 -7
  74. package/lib/util/download.js +45 -45
  75. package/lib/util/errors.js +58 -58
  76. package/lib/util/extract.js +24 -24
  77. package/lib/util/getDirNameFromImportMeta.js +6 -6
  78. package/lib/util/promises.js +36 -36
  79. package/package.json +74 -40
@@ -1,56 +1,47 @@
1
- import chalk from 'chalk'
2
- import inquirer from 'inquirer'
3
- import request from 'request'
4
- import getBowerRegistryConfig from '../getBowerRegistryConfig.js'
5
- import path from 'path'
6
-
7
- export default async function authenticate ({
8
- pluginName,
9
- cwd = process.cwd()
10
- } = {}) {
11
- cwd = path.resolve(process.cwd(), cwd)
12
- const BOWER_REGISTRY_CONFIG = getBowerRegistryConfig({ cwd })
13
- // check if github, do github device oauth workflow
14
- // if not github, send request to repo anyway
15
- const questions = [
16
- {
17
- name: 'username',
18
- message: chalk.cyan('GitHub username')
19
- },
20
- {
21
- name: 'token',
22
- message: chalk.cyan('GitHub personal access token (with public_repo access)'),
23
- type: 'password',
24
- mask: '*'
25
- }
26
- ]
27
- if (!pluginName) {
28
- questions.unshift({
29
- name: 'pluginName',
30
- message: chalk.cyan('Plugin name'),
31
- default: pluginName
32
- })
33
- }
34
- const confirmation = await inquirer.prompt(questions)
35
- if (!pluginName) {
36
- ({ pluginName } = confirmation)
37
- }
38
- const { username, token } = confirmation
39
- return new Promise((resolve, reject) => {
40
- request({
41
- uri: `${BOWER_REGISTRY_CONFIG.register}authenticate/${username}/${pluginName}?access_token=${token}`,
42
- method: 'GET',
43
- headers: { 'User-Agent': 'adapt-cli' },
44
- followRedirect: false
45
- }, (err, res, body) => {
46
- if (err) return reject(err)
47
- if (res.statusCode !== 200) reject(new Error(`The server responded with ${res.statusCode}`))
48
- try {
49
- const bodyJSON = JSON.parse(body)
50
- resolve({ username, token, pluginName, ...bodyJSON })
51
- } catch (err) {
52
- reject(err)
53
- }
54
- })
55
- })
56
- }
1
+ import chalk from 'chalk'
2
+ import inquirer from 'inquirer'
3
+ import fetch from 'node-fetch'
4
+ import getBowerRegistryConfig from '../getBowerRegistryConfig.js'
5
+ import path from 'path'
6
+
7
+ export default async function authenticate ({
8
+ pluginName,
9
+ cwd = process.cwd()
10
+ } = {}) {
11
+ cwd = path.resolve(process.cwd(), cwd)
12
+ const BOWER_REGISTRY_CONFIG = getBowerRegistryConfig({ cwd })
13
+ // check if github, do github device oauth workflow
14
+ // if not github, send request to repo anyway
15
+ const questions = [
16
+ {
17
+ name: 'username',
18
+ message: chalk.cyan('GitHub username')
19
+ },
20
+ {
21
+ name: 'token',
22
+ message: chalk.cyan('GitHub personal access token (with public_repo access)'),
23
+ type: 'password',
24
+ mask: '*'
25
+ }
26
+ ]
27
+ if (!pluginName) {
28
+ questions.unshift({
29
+ name: 'pluginName',
30
+ message: chalk.cyan('Plugin name'),
31
+ default: pluginName
32
+ })
33
+ }
34
+ const confirmation = await inquirer.prompt(questions)
35
+ if (!pluginName) {
36
+ ({ pluginName } = confirmation)
37
+ }
38
+ const { username, token } = confirmation
39
+ const response = await fetch(`${BOWER_REGISTRY_CONFIG.register}authenticate/${username}/${pluginName}?access_token=${token}`, {
40
+ headers: { 'User-Agent': 'adapt-cli' },
41
+ followRedirect: false,
42
+ method: 'GET'
43
+ })
44
+ if (response.status !== 200) throw new Error(`The server responded with ${response.status}`)
45
+ const body = await response.json()
46
+ return { username, token, pluginName, ...body }
47
+ }
@@ -1,222 +1,224 @@
1
- import chalk from 'chalk'
2
- import { eachOfSeries } from 'async'
3
- import { createPromptTask } from '../../util/createPromptTask.js'
4
- import { errorPrinter, packageNamePrinter, versionPrinter } from './print.js'
5
- import { eachOfLimitProgress, eachOfSeriesProgress } from '../../util/promises.js'
6
- import Project from '../Project.js'
7
- import Target from '../Target.js'
8
- import bower from 'bower'
9
- import { difference } from 'lodash-es'
10
- import path from 'path'
11
-
12
- export default async function install ({
13
- plugins,
14
- dev = false,
15
- isInteractive = true,
16
- isDryRun = false, // whether to summarise installation without modifying anything
17
- isCompatibleEnabled = false,
18
- isClean = false,
19
- cwd = process.cwd(),
20
- logger = null
21
- }) {
22
- cwd = path.resolve(process.cwd(), cwd)
23
- isClean && await new Promise(resolve => bower.commands.cache.clean().on('end', resolve))
24
- const project = new Project({ cwd, logger })
25
- project.tryThrowInvalidPath()
26
-
27
- logger?.log(chalk.cyan(`${dev ? 'cloning' : 'installing'} adapt dependencies...`))
28
-
29
- const targets = await getInstallTargets({ logger, project, plugins, isCompatibleEnabled })
30
- if (!targets?.length) return targets
31
-
32
- await loadPluginData({ logger, project, targets })
33
- await conflictResolution({ logger, targets, isInteractive, dev })
34
- if (isDryRun) {
35
- await summariseDryRun({ logger, targets })
36
- return targets
37
- }
38
- const installTargetsToBeInstalled = targets.filter(target => target.isToBeInstalled)
39
- if (installTargetsToBeInstalled.length) {
40
- await eachOfSeriesProgress(
41
- installTargetsToBeInstalled,
42
- target => target.install({ clone: dev }),
43
- percentage => logger?.logProgress?.(`${chalk.bold.cyan('<info>')} Installing plugins ${percentage}% complete`)
44
- )
45
- logger?.log(`${chalk.bold.cyan('<info>')} Installing plugins 100% complete`)
46
- const manifestDependencies = await project.getManifestDependencies()
47
- await updateManifest({ logger, project, targets, manifestDependencies, isInteractive })
48
- }
49
- await summariseInstallation({ logger, targets, dev })
50
- return targets
51
- }
52
-
53
- /**
54
- * @param {Object} options
55
- * @param {Project} options.project
56
- * @param {[string]} options.plugins
57
- */
58
- async function getInstallTargets ({ logger, project, plugins, isCompatibleEnabled }) {
59
- if (typeof plugins === 'string') plugins = [plugins]
60
- /** whether adapt.json is being used to compile the list of plugins to install */
61
- const isEmpty = !plugins?.length
62
- /** a list of plugin name/version pairs */
63
- const itinerary = isEmpty
64
- ? await project.getManifestDependencies()
65
- : plugins.reduce((itinerary, arg) => {
66
- const [name, version = '*'] = arg.split(/[#@]/)
67
- // Duplicates are removed by assigning to object properties
68
- itinerary[name] = version
69
- return itinerary
70
- }, {})
71
- const pluginNames = Object.entries(itinerary).map(([name, version]) => `${name}#${version}`)
72
-
73
- /**
74
- * @type {[Target]}
75
- */
76
- const targets = pluginNames.length
77
- ? pluginNames.map(nameVersion => {
78
- const [name, requestedVersion] = nameVersion.split(/[#@]/)
79
- return new Target({ name, requestedVersion, isCompatibleEnabled, project, logger })
80
- })
81
- : await project.getInstallTargets()
82
- return targets
83
- }
84
-
85
- /**
86
- * @param {Object} options
87
- * @param {Project} options.project
88
- * @param {[Target]} options.targets
89
- */
90
- async function loadPluginData ({ logger, project, targets }) {
91
- const frameworkVersion = project.version
92
- await eachOfLimitProgress(
93
- targets,
94
- target => target.fetchSourceInfo(),
95
- percentage => logger?.logProgress?.(`${chalk.bold.cyan('<info>')} Getting plugin info ${percentage}% complete`)
96
- )
97
- logger?.log(`${chalk.bold.cyan('<info>')} Getting plugin info 100% complete`)
98
- await eachOfLimitProgress(
99
- targets,
100
- target => target.findCompatibleVersion(frameworkVersion),
101
- percentage => logger?.logProgress?.(`${chalk.bold.cyan('<info>')} Finding compatible source versions ${percentage}% complete`)
102
- )
103
- logger?.log(`${chalk.bold.cyan('<info>')} Finding compatible source versions 100% complete`)
104
- await eachOfLimitProgress(
105
- targets,
106
- target => target.markInstallable(),
107
- percentage => logger?.logProgress?.(`${chalk.bold.cyan('<info>')} Marking installable ${percentage}% complete`)
108
- )
109
- logger?.log(`${chalk.bold.cyan('<info>')} Marking installable 100% complete`)
110
- }
111
-
112
- /**
113
- * @param {Object} options
114
- * @param {[Target]} options.targets
115
- */
116
- async function conflictResolution ({ logger, targets, isInteractive, dev }) {
117
- /** @param {Target} target */
118
- async function checkVersion (target) {
119
- const canApplyRequested = target.hasValidRequestVersion &&
120
- (target.hasFrameworkCompatibleVersion
121
- ? (target.latestCompatibleSourceVersion !== target.matchedVersion)
122
- : (target.latestSourceVersion !== target.matchedVersion))
123
- if (!isInteractive) {
124
- if (canApplyRequested) return target.markRequestedForInstallation()
125
- return target.markSkipped()
126
- }
127
- const choices = [
128
- dev && { name: 'master [master]', value: 'm' },
129
- canApplyRequested && { name: `requested version [${target.matchedVersion}]`, value: 'r' },
130
- target.hasFrameworkCompatibleVersion
131
- ? { name: `latest compatible version [${target.latestCompatibleSourceVersion}]`, value: 'l' }
132
- : { name: `latest version [${target.latestSourceVersion}]`, value: 'l' },
133
- { name: 'skip', value: 's' }
134
- ].filter(Boolean)
135
- const result = await createPromptTask({ message: chalk.reset(target.packageName), choices, type: 'list', default: 's' })
136
- const installMasterBranch = (result === 'm')
137
- const installRequested = (result === 'r')
138
- const installLatest = result === 'l'
139
- const skipped = result === 's'
140
- if (installMasterBranch) target.markMasterForInstallation()
141
- if (installRequested) target.markRequestedForInstallation()
142
- if (installLatest && target.hasFrameworkCompatibleVersion) target.markLatestCompatibleForInstallation()
143
- if (installLatest && !target.hasFrameworkCompatibleVersion) target.markLatestForInstallation()
144
- if (skipped) target.markSkipped()
145
- }
146
- function add (list, header, prompt) {
147
- if (!list.length) return
148
- return {
149
- header: chalk.cyan('<info> ') + header,
150
- list,
151
- prompt
152
- }
153
- }
154
- const allQuestions = [
155
- add(targets.filter(target => !target.hasFrameworkCompatibleVersion), 'There is no compatible version of the following plugins:', checkVersion),
156
- add(targets.filter(target => target.hasFrameworkCompatibleVersion && !target.hasValidRequestVersion), 'The version requested is invalid, there are newer compatible versions of the following plugins:', checkVersion),
157
- add(targets.filter(target => target.hasFrameworkCompatibleVersion && target.hasValidRequestVersion && !target.isApplyLatestCompatibleVersion), 'There are newer compatible versions of the following plugins:', checkVersion)
158
- ].filter(Boolean)
159
- if (allQuestions.length === 0) return
160
- for (const question of allQuestions) {
161
- logger?.log(question.header)
162
- await eachOfSeries(question.list, question.prompt)
163
- }
164
- }
165
-
166
- /**
167
- * @param {Object} options
168
- * @param {Project} options.project
169
- * @param {[Target]} options.targets
170
- */
171
- async function updateManifest ({ project, targets, manifestDependencies, isInteractive }) {
172
- if (targets.filter(target => target.isInstallSuccessful).length === 0) return
173
- if (difference(targets.filter(target => target.isInstallSuccessful).map(target => target.packageName), Object.keys(manifestDependencies)).length === 0) return
174
- if (isInteractive) {
175
- const shouldUpdate = await createPromptTask({
176
- message: chalk.white('Update the manifest (adapt.json)?'),
177
- type: 'confirm',
178
- default: true
179
- })
180
- if (!shouldUpdate) return
181
- }
182
- targets.forEach(target => target.isInstallSuccessful && project.add(target))
183
- }
184
-
185
- /**
186
- * @param {Object} options
187
- * @param {[Target]} options.targets
188
- */
189
- function summariseDryRun ({ logger, targets }) {
190
- const toBeInstalled = targets.filter(target => target.isToBeInstalled)
191
- const toBeSkipped = targets.filter(target => !target.isToBeInstalled || target.isSkipped)
192
- const missing = targets.filter(target => target.isMissing)
193
- summarise(logger, toBeSkipped, packageNamePrinter, 'The following plugins will be skipped:')
194
- summarise(logger, missing, packageNamePrinter, 'There was a problem locating the following plugins:')
195
- summarise(logger, toBeInstalled, versionPrinter, 'The following plugins will be installed:')
196
- }
197
-
198
- /**
199
- * @param {Object} options
200
- * @param {[Target]} options.targets
201
- */
202
- function summariseInstallation ({ logger, targets, dev }) {
203
- const installSucceeded = targets.filter(target => target.isInstallSuccessful)
204
- const installSkipped = targets.filter(target => !target.isToBeInstalled || target.isSkipped)
205
- const installErrored = targets.filter(target => target.isInstallFailure)
206
- const missing = targets.filter(target => target.isMissing)
207
- const noneInstalled = (installSucceeded.length === 0)
208
- const allInstalledSuccessfully = (installErrored.length === 0 && missing.length === 0)
209
- const someInstalledSuccessfully = (!noneInstalled && !allInstalledSuccessfully)
210
- summarise(logger, installSkipped, packageNamePrinter, 'The following plugins were skipped:')
211
- summarise(logger, missing, packageNamePrinter, 'There was a problem locating the following plugins:')
212
- summarise(logger, installErrored, errorPrinter, 'The following plugins could not be installed:')
213
- if (noneInstalled) logger?.log(chalk.cyanBright('None of the requested plugins could be installed'))
214
- else if (allInstalledSuccessfully) summarise(logger, installSucceeded, dev ? packageNamePrinter : versionPrinter, 'All requested plugins were successfully installed. Summary of installation:')
215
- else if (someInstalledSuccessfully) summarise(logger, installSucceeded, dev ? packageNamePrinter : versionPrinter, 'The following plugins were successfully installed:')
216
- }
217
-
218
- function summarise (logger, list, iterator, header) {
219
- if (!list || !iterator || list.length === 0) return
220
- logger?.log(chalk.cyanBright(header))
221
- list.forEach(item => iterator(item, logger))
222
- }
1
+ import chalk from 'chalk'
2
+ import { eachOfSeries } from 'async'
3
+ import { createPromptTask } from '../../util/createPromptTask.js'
4
+ import { errorPrinter, packageNamePrinter, versionPrinter } from './print.js'
5
+ import { eachOfLimitProgress, eachOfSeriesProgress } from '../../util/promises.js'
6
+ import Project from '../Project.js'
7
+ import Target from '../Target.js'
8
+ import bower from 'bower'
9
+ import { difference } from 'lodash-es'
10
+ import path from 'path'
11
+
12
+ export default async function install ({
13
+ plugins,
14
+ dev = false,
15
+ isInteractive = true,
16
+ isDryRun = false, // whether to summarise installation without modifying anything
17
+ isCompatibleEnabled = false,
18
+ isClean = false,
19
+ cwd = process.cwd(),
20
+ logger = null
21
+ }) {
22
+ cwd = path.resolve(process.cwd(), cwd)
23
+ isClean && await new Promise(resolve => bower.commands.cache.clean().on('end', resolve))
24
+ const project = new Project({ cwd, logger })
25
+ project.tryThrowInvalidPath()
26
+
27
+ logger?.log(chalk.cyan(`${dev ? 'cloning' : 'installing'} adapt dependencies...`))
28
+
29
+ const targets = await getInstallTargets({ logger, project, plugins, isCompatibleEnabled })
30
+ if (!targets?.length) return targets
31
+
32
+ await loadPluginData({ logger, project, targets })
33
+ await conflictResolution({ logger, targets, isInteractive, dev })
34
+ if (isDryRun) {
35
+ await summariseDryRun({ logger, targets })
36
+ return targets
37
+ }
38
+ const installTargetsToBeInstalled = targets.filter(target => target.isToBeInstalled)
39
+ if (installTargetsToBeInstalled.length) {
40
+ await eachOfSeriesProgress(
41
+ installTargetsToBeInstalled,
42
+ target => target.install({ clone: dev }),
43
+ percentage => logger?.logProgress?.(`${chalk.bold.cyan('<info>')} Installing plugins ${percentage}% complete`)
44
+ )
45
+ logger?.log(`${chalk.bold.cyan('<info>')} Installing plugins 100% complete`)
46
+ const manifestDependencies = await project.getManifestDependencies()
47
+ await updateManifest({ logger, project, targets, manifestDependencies, isInteractive })
48
+ }
49
+ await summariseInstallation({ logger, targets, dev })
50
+ return targets
51
+ }
52
+
53
+ /**
54
+ * @param {Object} options
55
+ * @param {Project} options.project
56
+ * @param {[string]} options.plugins
57
+ */
58
+ async function getInstallTargets ({ logger, project, plugins, isCompatibleEnabled }) {
59
+ if (typeof plugins === 'string') plugins = [plugins]
60
+ /** whether adapt.json is being used to compile the list of plugins to install */
61
+ const isEmpty = !plugins?.length
62
+ /** a list of plugin name/version pairs */
63
+ const itinerary = isEmpty
64
+ ? await project.getManifestDependencies()
65
+ : plugins.reduce((itinerary, arg) => {
66
+ const [name, version = '*'] = arg.split(/[#@]/)
67
+ // Duplicates are removed by assigning to object properties
68
+ itinerary[name] = version
69
+ return itinerary
70
+ }, {})
71
+ const pluginNames = Object.entries(itinerary).map(([name, version]) => `${name}#${version}`)
72
+
73
+ /**
74
+ * @type {[Target]}
75
+ */
76
+ const targets = pluginNames.length
77
+ ? pluginNames.map(nameVersion => {
78
+ const [name, requestedVersion] = nameVersion.split(/[#@]/)
79
+ return new Target({ name, requestedVersion, isCompatibleEnabled, project, logger })
80
+ })
81
+ : await project.getInstallTargets()
82
+ return targets
83
+ }
84
+
85
+ /**
86
+ * @param {Object} options
87
+ * @param {Project} options.project
88
+ * @param {[Target]} options.targets
89
+ */
90
+ async function loadPluginData ({ logger, project, targets }) {
91
+ const frameworkVersion = project.version
92
+ await eachOfLimitProgress(
93
+ targets,
94
+ target => target.fetchSourceInfo(),
95
+ percentage => logger?.logProgress?.(`${chalk.bold.cyan('<info>')} Getting plugin info ${percentage}% complete`)
96
+ )
97
+ logger?.log(`${chalk.bold.cyan('<info>')} Getting plugin info 100% complete`)
98
+ await eachOfLimitProgress(
99
+ targets,
100
+ target => target.findCompatibleVersion(frameworkVersion),
101
+ percentage => logger?.logProgress?.(`${chalk.bold.cyan('<info>')} Finding compatible source versions ${percentage}% complete`)
102
+ )
103
+ logger?.log(`${chalk.bold.cyan('<info>')} Finding compatible source versions 100% complete`)
104
+ await eachOfLimitProgress(
105
+ targets,
106
+ target => target.markInstallable(),
107
+ percentage => logger?.logProgress?.(`${chalk.bold.cyan('<info>')} Marking installable ${percentage}% complete`)
108
+ )
109
+ logger?.log(`${chalk.bold.cyan('<info>')} Marking installable 100% complete`)
110
+ }
111
+
112
+ /**
113
+ * @param {Object} options
114
+ * @param {[Target]} options.targets
115
+ */
116
+ async function conflictResolution ({ logger, targets, isInteractive, dev }) {
117
+ /** @param {Target} target */
118
+ async function checkVersion (target) {
119
+ const canApplyRequested = target.hasValidRequestVersion &&
120
+ (target.hasFrameworkCompatibleVersion
121
+ ? (target.latestCompatibleSourceVersion !== target.matchedVersion)
122
+ : (target.latestSourceVersion !== target.matchedVersion))
123
+ if (!isInteractive) {
124
+ if (canApplyRequested) return target.markRequestedForInstallation()
125
+ return target.markSkipped()
126
+ }
127
+ const choices = [
128
+ dev && { name: 'master [master]', value: 'm' },
129
+ canApplyRequested && { name: `requested version [${target.matchedVersion}]`, value: 'r' },
130
+ target.hasFrameworkCompatibleVersion
131
+ ? { name: `latest compatible version [${target.latestCompatibleSourceVersion}]`, value: 'l' }
132
+ : target.latestSourceVersion
133
+ ? { name: `latest version [${target.latestSourceVersion}]`, value: 'l' }
134
+ : { name: 'master [master]', value: 'm' },
135
+ { name: 'skip', value: 's' }
136
+ ].filter(Boolean)
137
+ const result = await createPromptTask({ message: chalk.reset(target.packageName), choices, type: 'list', default: 's' })
138
+ const installMasterBranch = (result === 'm')
139
+ const installRequested = (result === 'r')
140
+ const installLatest = result === 'l'
141
+ const skipped = result === 's'
142
+ if (installMasterBranch) target.markMasterForInstallation()
143
+ if (installRequested) target.markRequestedForInstallation()
144
+ if (installLatest && target.hasFrameworkCompatibleVersion) target.markLatestCompatibleForInstallation()
145
+ if (installLatest && !target.hasFrameworkCompatibleVersion) target.markLatestForInstallation()
146
+ if (skipped) target.markSkipped()
147
+ }
148
+ function add (list, header, prompt) {
149
+ if (!list.length) return
150
+ return {
151
+ header: chalk.cyan('<info> ') + header,
152
+ list,
153
+ prompt
154
+ }
155
+ }
156
+ const allQuestions = [
157
+ add(targets.filter(target => !target.hasFrameworkCompatibleVersion), 'There is no compatible version of the following plugins:', checkVersion),
158
+ add(targets.filter(target => target.hasFrameworkCompatibleVersion && !target.hasValidRequestVersion), 'The version requested is invalid, there are newer compatible versions of the following plugins:', checkVersion),
159
+ add(targets.filter(target => target.hasFrameworkCompatibleVersion && target.hasValidRequestVersion && !target.isApplyLatestCompatibleVersion), 'There are newer compatible versions of the following plugins:', checkVersion)
160
+ ].filter(Boolean)
161
+ if (allQuestions.length === 0) return
162
+ for (const question of allQuestions) {
163
+ logger?.log(question.header)
164
+ await eachOfSeries(question.list, question.prompt)
165
+ }
166
+ }
167
+
168
+ /**
169
+ * @param {Object} options
170
+ * @param {Project} options.project
171
+ * @param {[Target]} options.targets
172
+ */
173
+ async function updateManifest ({ project, targets, manifestDependencies, isInteractive }) {
174
+ if (targets.filter(target => target.isInstallSuccessful).length === 0) return
175
+ if (difference(targets.filter(target => target.isInstallSuccessful).map(target => target.packageName), Object.keys(manifestDependencies)).length === 0) return
176
+ if (isInteractive) {
177
+ const shouldUpdate = await createPromptTask({
178
+ message: chalk.white('Update the manifest (adapt.json)?'),
179
+ type: 'confirm',
180
+ default: true
181
+ })
182
+ if (!shouldUpdate) return
183
+ }
184
+ targets.forEach(target => target.isInstallSuccessful && project.add(target))
185
+ }
186
+
187
+ /**
188
+ * @param {Object} options
189
+ * @param {[Target]} options.targets
190
+ */
191
+ function summariseDryRun ({ logger, targets }) {
192
+ const toBeInstalled = targets.filter(target => target.isToBeInstalled)
193
+ const toBeSkipped = targets.filter(target => !target.isToBeInstalled || target.isSkipped)
194
+ const missing = targets.filter(target => target.isMissing)
195
+ summarise(logger, toBeSkipped, packageNamePrinter, 'The following plugins will be skipped:')
196
+ summarise(logger, missing, packageNamePrinter, 'There was a problem locating the following plugins:')
197
+ summarise(logger, toBeInstalled, versionPrinter, 'The following plugins will be installed:')
198
+ }
199
+
200
+ /**
201
+ * @param {Object} options
202
+ * @param {[Target]} options.targets
203
+ */
204
+ function summariseInstallation ({ logger, targets, dev }) {
205
+ const installSucceeded = targets.filter(target => target.isInstallSuccessful)
206
+ const installSkipped = targets.filter(target => !target.isToBeInstalled || target.isSkipped)
207
+ const installErrored = targets.filter(target => target.isInstallFailure)
208
+ const missing = targets.filter(target => target.isMissing)
209
+ const noneInstalled = (installSucceeded.length === 0)
210
+ const allInstalledSuccessfully = (installErrored.length === 0 && missing.length === 0)
211
+ const someInstalledSuccessfully = (!noneInstalled && !allInstalledSuccessfully)
212
+ summarise(logger, installSkipped, packageNamePrinter, 'The following plugins were skipped:')
213
+ summarise(logger, missing, packageNamePrinter, 'There was a problem locating the following plugins:')
214
+ summarise(logger, installErrored, errorPrinter, 'The following plugins could not be installed:')
215
+ if (noneInstalled) logger?.log(chalk.cyanBright('None of the requested plugins could be installed'))
216
+ else if (allInstalledSuccessfully) summarise(logger, installSucceeded, dev ? packageNamePrinter : versionPrinter, 'All requested plugins were successfully installed. Summary of installation:')
217
+ else if (someInstalledSuccessfully) summarise(logger, installSucceeded, dev ? packageNamePrinter : versionPrinter, 'The following plugins were successfully installed:')
218
+ }
219
+
220
+ function summarise (logger, list, iterator, header) {
221
+ if (!list || !iterator || list.length === 0) return
222
+ logger?.log(chalk.cyanBright(header))
223
+ list.forEach(item => iterator(item, logger))
224
+ }