adapt-cli 3.0.2 → 3.0.6

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 (78) 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 +260 -260
  28. package/lib/cli.js +69 -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 +9 -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/integration/AdaptFramework/build.js +42 -42
  46. package/lib/integration/AdaptFramework/clone.js +27 -27
  47. package/lib/integration/AdaptFramework/deleteSrcCore.js +9 -9
  48. package/lib/integration/AdaptFramework/deleteSrcCourse.js +9 -9
  49. package/lib/integration/AdaptFramework/download.js +21 -21
  50. package/lib/integration/AdaptFramework/erase.js +34 -34
  51. package/lib/integration/AdaptFramework/getLatestVersion.js +79 -79
  52. package/lib/integration/AdaptFramework/npmInstall.js +21 -21
  53. package/lib/integration/AdaptFramework.js +19 -19
  54. package/lib/integration/Plugin.js +404 -404
  55. package/lib/integration/PluginManagement/autenticate.js +56 -56
  56. package/lib/integration/PluginManagement/install.js +224 -224
  57. package/lib/integration/PluginManagement/print.js +52 -52
  58. package/lib/integration/PluginManagement/register.js +130 -130
  59. package/lib/integration/PluginManagement/rename.js +101 -101
  60. package/lib/integration/PluginManagement/schemas.js +8 -8
  61. package/lib/integration/PluginManagement/search.js +46 -46
  62. package/lib/integration/PluginManagement/uninstall.js +141 -141
  63. package/lib/integration/PluginManagement/unregister.js +101 -101
  64. package/lib/integration/PluginManagement/update.js +224 -224
  65. package/lib/integration/PluginManagement.js +21 -21
  66. package/lib/integration/Project.js +146 -146
  67. package/lib/integration/Target.js +299 -299
  68. package/lib/integration/getBowerRegistryConfig.js +34 -34
  69. package/lib/logger.js +28 -28
  70. package/lib/util/JSONReadValidate.js +34 -34
  71. package/lib/util/constants.js +38 -38
  72. package/lib/util/createPromptTask.js +7 -7
  73. package/lib/util/download.js +45 -45
  74. package/lib/util/errors.js +58 -58
  75. package/lib/util/extract.js +24 -24
  76. package/lib/util/getDirNameFromImportMeta.js +6 -6
  77. package/lib/util/promises.js +36 -36
  78. package/package.json +74 -40
@@ -1,56 +1,56 @@
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 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,224 +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
- : 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
- }
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
+ }