@form8ion/project 22.0.0-beta.2 → 22.0.0-beta.20

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 (55) hide show
  1. package/README.md +70 -26
  2. package/lib/index.js +205 -104
  3. package/lib/index.js.map +1 -1
  4. package/package.json +27 -29
  5. package/src/ci-provider/index.js +1 -0
  6. package/src/ci-provider/prompt.js +17 -0
  7. package/src/ci-provider/prompt.test.js +27 -0
  8. package/src/ci-provider/scaffolder.js +27 -0
  9. package/src/ci-provider/scaffolder.test.js +68 -0
  10. package/src/ci-provider/schema.js +4 -0
  11. package/src/ci-provider/schema.test.js +43 -0
  12. package/src/contributing/scaffolder.js +2 -2
  13. package/src/contributing/scaffolder.test.js +14 -2
  14. package/src/dependency-updater/prompt.js +14 -8
  15. package/src/dependency-updater/prompt.test.js +16 -17
  16. package/src/dependency-updater/scaffolder.js +4 -2
  17. package/src/dependency-updater/scaffolder.test.js +18 -15
  18. package/src/editorconfig/index.js +1 -0
  19. package/src/editorconfig/scaffolder.js +1 -1
  20. package/src/editorconfig/tester.js +5 -0
  21. package/src/editorconfig/tester.test.js +25 -0
  22. package/src/index.js +1 -7
  23. package/src/language/prompt.js +14 -9
  24. package/src/language/prompt.test.js +15 -16
  25. package/src/language/scaffolder.js +4 -2
  26. package/src/language/scaffolder.test.js +13 -8
  27. package/src/license/lifter.js +1 -1
  28. package/src/license/scaffolder.js +2 -3
  29. package/src/license/scaffolder.test.js +5 -8
  30. package/src/license/tester.js +1 -1
  31. package/src/lift.js +6 -1
  32. package/src/lift.test.js +24 -12
  33. package/src/options-validator.js +3 -3
  34. package/src/options-validator.test.js +4 -6
  35. package/src/prompts/index.js +20 -0
  36. package/src/prompts/question-names.js +19 -5
  37. package/src/prompts/questions.js +7 -3
  38. package/src/prompts/questions.test.js +5 -6
  39. package/src/scaffolder.js +18 -17
  40. package/src/scaffolder.test.js +39 -31
  41. package/src/template-path.js +1 -1
  42. package/src/vcs/git/remotes.js +6 -7
  43. package/src/vcs/git/remotes.test.js +21 -16
  44. package/src/vcs/host/prompt.js +15 -10
  45. package/src/vcs/host/prompt.test.js +31 -25
  46. package/src/vcs/host/scaffolder.js +4 -2
  47. package/src/vcs/host/scaffolder.test.js +9 -7
  48. package/src/vcs/prompt.js +11 -9
  49. package/src/vcs/prompt.test.js +15 -12
  50. package/src/vcs/scaffolder.js +9 -11
  51. package/src/vcs/scaffolder.test.js +10 -9
  52. package/src/options-schemas.js +0 -3
  53. package/src/options-schemas.test.js +0 -20
  54. package/src/prompts/conditionals.js +0 -13
  55. package/src/prompts/conditionals.test.js +0 -51
package/README.md CHANGED
@@ -71,45 +71,89 @@ a wrapper.
71
71
  #### Import
72
72
 
73
73
  ```javascript
74
- import {lift, questionNames, scaffold} from '@form8ion/project';
74
+ import {ungroupObject} from '@form8ion/core';
75
+ import {lift, promptConstants, scaffold} from '@form8ion/project';
75
76
  ```
76
77
 
77
78
  #### Execute
78
79
 
79
80
  ```javascript
80
- await scaffold({
81
- decisions: {
82
- [questionNames.PROJECT_NAME]: 'my-project',
83
- [questionNames.LICENSE]: 'MIT',
84
- [questionNames.VISIBILITY]: 'Public',
85
- [questionNames.DESCRIPTION]: 'My project',
86
- [questionNames.GIT_REPO]: false,
87
- [questionNames.COPYRIGHT_HOLDER]: 'John Smith',
88
- [questionNames.COPYRIGHT_YEAR]: '2022',
89
- [questionNames.PROJECT_LANGUAGE]: 'foo'
81
+ const plugins = {
82
+ dependencyUpdaters: {
83
+ bar: {scaffold: options => options}
90
84
  },
91
- plugins: {
92
- dependencyUpdaters: {
93
- bar: {scaffold: options => options}
94
- },
95
- languages: {
96
- foo: {scaffold: options => options}
97
- },
98
- vcsHosts: {
99
- baz: {
100
- scaffold: options => options,
101
- prompt: () => ({repoOwner: 'form8ion'})
102
- }
85
+ languages: {
86
+ foo: {scaffold: options => options}
87
+ },
88
+ vcsHosts: {
89
+ baz: {
90
+ scaffold: options => options,
91
+ prompt: () => ({repoOwner: 'form8ion'})
103
92
  }
104
93
  }
105
- });
94
+ };
95
+ const logger = {
96
+ info: () => undefined,
97
+ success: () => undefined,
98
+ warn: () => undefined,
99
+ error: () => undefined
100
+ };
101
+
102
+ await scaffold(
103
+ {plugins},
104
+ {
105
+ prompt: async ({id}) => {
106
+ const {questionNames, ids} = promptConstants;
107
+ const {
108
+ BASE_DETAILS: baseDetailsPromptId,
109
+ GIT_REPOSITORY: gitRepositoryPromptId,
110
+ PROJECT_LANGUAGE: projectLanguagePromptId
111
+ } = ids;
112
+
113
+ switch (id) {
114
+ case baseDetailsPromptId: {
115
+ const {
116
+ PROJECT_NAME,
117
+ LICENSE,
118
+ VISIBILITY,
119
+ DESCRIPTION,
120
+ COPYRIGHT_HOLDER,
121
+ COPYRIGHT_YEAR
122
+ } = questionNames[baseDetailsPromptId];
123
+
124
+ return {
125
+ [PROJECT_NAME]: 'my-project',
126
+ [LICENSE]: 'MIT',
127
+ [VISIBILITY]: 'OSS',
128
+ [DESCRIPTION]: 'My project',
129
+ [COPYRIGHT_HOLDER]: 'John Smith',
130
+ [COPYRIGHT_YEAR]: '2022'
131
+ };
132
+ }
133
+ case gitRepositoryPromptId: {
134
+ const {GIT_REPO} = questionNames[gitRepositoryPromptId];
135
+
136
+ return {[GIT_REPO]: false};
137
+ }
138
+ case projectLanguagePromptId: {
139
+ const {PROJECT_LANGUAGE} = questionNames[projectLanguagePromptId];
140
+
141
+ return {[PROJECT_LANGUAGE]: 'foo'};
142
+ }
143
+ default:
144
+ throw new Error(`Unknown prompt with ID: ${id}`);
145
+ }
146
+ },
147
+ logger
148
+ }
149
+ );
106
150
 
107
151
  await lift({
108
152
  projectRoot: process.cwd(),
109
153
  results: {},
110
- enhancers: {foo: {test: () => true, lift: () => ({})}},
154
+ enhancers: ungroupObject(plugins),
111
155
  vcs: {}
112
- });
156
+ }, {logger});
113
157
  ```
114
158
 
115
159
  ### API
package/lib/index.js CHANGED
@@ -1,14 +1,11 @@
1
- import { fileExists, questionsForBaseDetails, optionsSchemas, validateOptions, applyEnhancers, questionNames as questionNames$2 } from '@form8ion/core';
2
1
  import deepmerge from 'deepmerge';
3
2
  import { execa } from 'execa';
4
- import { reportResults } from '@form8ion/results-reporter';
3
+ import { questionNames as questionNames$1, fileExists, questionsForBaseDetails, optionsSchemas, validateOptions, applyEnhancers } from '@form8ion/core';
5
4
  import { lift as lift$1, scaffold as scaffold$2 } from '@form8ion/readme';
6
- import { warn, info } from '@travi/cli-messages';
7
- import { prompt } from '@form8ion/overridable-prompts';
8
5
  import * as gitPlugin from '@form8ion/git';
9
6
  import { test, scaffold as scaffold$1 } from '@form8ion/git';
10
7
  import { simpleGit } from 'simple-git';
11
- import hostedGitInfo from 'hosted-git-info';
8
+ import parseGitUrl from 'git-url-parse';
12
9
  import { promises } from 'fs';
13
10
  import wrap from 'word-wrap';
14
11
  import mustache from 'mustache';
@@ -18,25 +15,46 @@ import { promises as promises$1 } from 'node:fs';
18
15
  import { resolve } from 'path';
19
16
  import filedirname from 'filedirname';
20
17
 
21
- const questionNames$1 = {
22
- GIT_REPO: 'gitRepo',
23
- REPO_HOST: 'repoHost',
24
- REPO_OWNER: 'repoOwner',
25
- PROJECT_LANGUAGE: 'projectLanguage',
26
- DEPENDENCY_UPDATER: 'dependencyUpdater'
18
+ const questionNames = {
19
+ BASE_DETAILS: questionNames$1,
20
+ GIT_REPOSITORY: {
21
+ GIT_REPO: 'gitRepo'
22
+ },
23
+ REPOSITORY_HOST: {
24
+ REPO_HOST: 'repoHost',
25
+ REPO_OWNER: 'repoOwner'
26
+ },
27
+ PROJECT_LANGUAGE: {
28
+ PROJECT_LANGUAGE: 'projectLanguage'
29
+ },
30
+ DEPENDENCY_UPDATER: {
31
+ DEPENDENCY_UPDATER: 'dependencyUpdater'
32
+ },
33
+ CI_PROVIDER: {
34
+ CI_PROVIDER: 'ciProvider'
35
+ }
27
36
  };
28
37
 
29
- function promptForLanguageDetails (languages, decisions) {
30
- return prompt([{
31
- name: questionNames$1.PROJECT_LANGUAGE,
32
- type: 'list',
33
- message: 'What type of project is this?',
34
- choices: [...Object.keys(languages), 'Other']
35
- }], decisions);
38
+ const PROJECT_LANGUAGE_PROMPT_ID = 'PROJECT_LANGUAGE';
39
+
40
+ const {PROJECT_LANGUAGE: PROJECT_LANGUAGE$1} = questionNames.PROJECT_LANGUAGE;
41
+
42
+ function promptForProjectLanguage(languages, {prompt}) {
43
+ return prompt({
44
+ id: PROJECT_LANGUAGE_PROMPT_ID,
45
+ questions: [{
46
+ name: PROJECT_LANGUAGE$1,
47
+ type: 'list',
48
+ message: 'What type of project is this?',
49
+ choices: [...Object.keys(languages), 'Other']
50
+ }]
51
+ });
36
52
  }
37
53
 
38
- async function scaffoldLanguage (languagePlugins, decisions, options) {
39
- const {[questionNames$1.PROJECT_LANGUAGE]: chosenLanguage} = await promptForLanguageDetails(languagePlugins, decisions);
54
+ const {PROJECT_LANGUAGE} = questionNames.PROJECT_LANGUAGE;
55
+
56
+ async function scaffoldLanguage(languagePlugins, options, {prompt}) {
57
+ const {[PROJECT_LANGUAGE]: chosenLanguage} = await promptForProjectLanguage(languagePlugins, {prompt});
40
58
 
41
59
  const plugin = languagePlugins[chosenLanguage];
42
60
 
@@ -45,16 +63,20 @@ async function scaffoldLanguage (languagePlugins, decisions, options) {
45
63
  return undefined;
46
64
  }
47
65
 
48
- async function promptForRepoCreation(decisions) {
49
- const {[questionNames$1.GIT_REPO]: gitRepoShouldBeCreated} = await prompt(
50
- [{
51
- name: questionNames$1.GIT_REPO,
66
+ const GIT_REPOSITORY_PROMPT_ID = 'GIT_REPOSITORY';
67
+
68
+ const {GIT_REPO} = questionNames.GIT_REPOSITORY;
69
+
70
+ async function promptForRepoCreation({prompt}) {
71
+ const {[GIT_REPO]: gitRepoShouldBeCreated} = await prompt({
72
+ id: GIT_REPOSITORY_PROMPT_ID,
73
+ questions: [{
74
+ name: GIT_REPO,
52
75
  type: 'confirm',
53
76
  default: true,
54
77
  message: 'Should a git repository be initialized?'
55
- }],
56
- decisions
57
- );
78
+ }]
79
+ });
58
80
 
59
81
  return gitRepoShouldBeCreated;
60
82
  }
@@ -74,14 +96,14 @@ async function getExistingRemotes(git) {
74
96
  async function determineExistingVcsDetails({projectRoot}) {
75
97
  const git = simpleGit({baseDir: projectRoot});
76
98
  const remoteOrigin = await git.remote(['get-url', 'origin']);
77
- const {user, project, type} = hostedGitInfo.fromUrl(remoteOrigin);
99
+ const {owner, name, host} = parseGitUrl(remoteOrigin.trimEnd());
78
100
 
79
- return {vcs: {owner: user, name: project, host: type}};
101
+ return {vcs: {owner, name, host}};
80
102
  }
81
103
 
82
- async function defineRemoteOrigin(projectRoot, sshUrl) {
104
+ async function defineRemoteOrigin(projectRoot, sshUrl, {logger}) {
83
105
  if (!sshUrl) {
84
- warn('URL not available to configure remote `origin`');
106
+ logger.warn('URL not available to configure remote `origin`');
85
107
 
86
108
  return {nextSteps: []};
87
109
  }
@@ -90,7 +112,7 @@ async function defineRemoteOrigin(projectRoot, sshUrl) {
90
112
  const existingRemotes = await getExistingRemotes(git);
91
113
 
92
114
  if (existingRemotes.includes('origin')) {
93
- warn('The `origin` remote is already defined for this repository');
115
+ logger.warn('The `origin` remote is already defined for this repository');
94
116
 
95
117
  return {nextSteps: []};
96
118
  }
@@ -107,20 +129,29 @@ async function defineRemoteOrigin(projectRoot, sshUrl) {
107
129
  return {nextSteps: [{summary: 'Set local `master` branch to track upstream `origin/master`'}]};
108
130
  }
109
131
 
110
- async function promptForVcsHostDetails (hosts, decisions) {
111
- const answers = await prompt([{
112
- name: questionNames$1.REPO_HOST,
113
- type: 'list',
114
- message: 'Where will the repository be hosted?',
115
- choices: Object.keys(hosts)
116
- }], decisions);
117
- const host = hosts[answers[questionNames$1.REPO_HOST]];
132
+ const REPOSITORY_HOST_PROMPT_ID = 'REPOSITORY_HOST';
133
+
134
+ const {REPO_HOST: REPO_HOST$1} = questionNames.REPOSITORY_HOST;
135
+
136
+ async function promptForVcsHostChoice(hosts, {prompt}) {
137
+ const answers = await prompt({
138
+ id: REPOSITORY_HOST_PROMPT_ID,
139
+ questions: [{
140
+ name: REPO_HOST$1,
141
+ type: 'list',
142
+ message: 'Where will the repository be hosted?',
143
+ choices: Object.keys(hosts)
144
+ }]
145
+ });
146
+ const host = hosts[answers[REPO_HOST$1]];
118
147
 
119
148
  return {...answers, ...host};
120
149
  }
121
150
 
122
- async function scaffoldVcsHost(hosts, decisions, options) {
123
- const {[questionNames$1.REPO_HOST]: chosenHost} = await promptForVcsHostDetails(hosts, decisions);
151
+ const {REPO_HOST} = questionNames.REPOSITORY_HOST;
152
+
153
+ async function scaffoldVcsHost(hosts, options, {prompt}) {
154
+ const {[REPO_HOST]: chosenHost} = await promptForVcsHostChoice(hosts, {prompt});
124
155
 
125
156
  const lowercasedHosts = Object.fromEntries(
126
157
  Object.entries(hosts).map(([name, details]) => [name.toLowerCase(), details])
@@ -132,24 +163,23 @@ async function scaffoldVcsHost(hosts, decisions, options) {
132
163
  return {vcs: {}};
133
164
  }
134
165
 
135
- async function scaffoldVcs({projectRoot, projectName, decisions, vcsHosts, visibility, description}) {
136
- if (await promptForRepoCreation(decisions)) {
166
+ async function scaffoldVcs(
167
+ {projectRoot, projectName, vcsHosts, visibility, description},
168
+ {prompt, logger}
169
+ ) {
170
+ if (await promptForRepoCreation({prompt})) {
137
171
  if (await test({projectRoot})) {
138
- info('Git repository already exists');
172
+ logger.info('Git repository already exists');
139
173
 
140
- return {vcs: await determineExistingVcsDetails({projectRoot})};
174
+ return determineExistingVcsDetails({projectRoot});
141
175
  }
142
176
 
143
177
  const [{vcs: {host, owner, name, sshUrl}}] = await Promise.all([
144
- scaffoldVcsHost(
145
- vcsHosts,
146
- decisions,
147
- {projectName, projectRoot, description, visibility}
148
- ),
178
+ scaffoldVcsHost(vcsHosts, {projectName, projectRoot, description, visibility}, {prompt}),
149
179
  scaffold$1({projectRoot})
150
180
  ]);
151
181
 
152
- const remoteOriginResults = await defineRemoteOrigin(projectRoot, sshUrl);
182
+ const remoteOriginResults = await defineRemoteOrigin(projectRoot, sshUrl, {logger});
153
183
 
154
184
  return {
155
185
  vcs: {host, owner, name},
@@ -160,9 +190,9 @@ async function scaffoldVcs({projectRoot, projectName, decisions, vcsHosts, visib
160
190
  return {};
161
191
  }
162
192
 
163
- async function scaffoldLicense ({projectRoot, license, copyright}) {
193
+ async function scaffoldLicense({projectRoot, license, copyright}, {logger}) {
164
194
  if (license) {
165
- info('Generating License');
195
+ logger.info('Generating License');
166
196
 
167
197
  const licenseContent = spdxLicenseList[license].licenseText;
168
198
 
@@ -178,7 +208,7 @@ async function scaffoldLicense ({projectRoot, license, copyright}) {
178
208
  return {};
179
209
  }
180
210
 
181
- function tester ({projectRoot}) {
211
+ function licenseDefined({projectRoot}) {
182
212
  return fileExists(`${projectRoot}/LICENSE`);
183
213
  }
184
214
 
@@ -186,7 +216,7 @@ function repositoryIsHostedOnGithub(vcs) {
186
216
  return vcs && 'github' === vcs.host;
187
217
  }
188
218
 
189
- function lifter ({vcs}) {
219
+ function liftLicense({vcs}) {
190
220
  return {
191
221
  ...repositoryIsHostedOnGithub(vcs) && {
192
222
  badges: {
@@ -204,25 +234,34 @@ function lifter ({vcs}) {
204
234
 
205
235
  var licensePlugin = /*#__PURE__*/Object.freeze({
206
236
  __proto__: null,
207
- lift: lifter,
237
+ lift: liftLicense,
208
238
  scaffold: scaffoldLicense,
209
- test: tester
239
+ test: licenseDefined
210
240
  });
211
241
 
212
- async function promptForDependencyUpdaterChoice(updaters, decisions) {
213
- return prompt([{
214
- name: questionNames$1.DEPENDENCY_UPDATER,
215
- type: 'list',
216
- message: 'Which dependency-update service do you want to manage this project?',
217
- choices: [...Object.keys(updaters), 'Other']
218
- }], decisions);
242
+ const DEPENDENCY_UPDATER_PROMPT_ID = 'DEPENDENCY_UPDATER';
243
+
244
+ const {DEPENDENCY_UPDATER: DEPENDENCY_UPDATER$1} = questionNames.DEPENDENCY_UPDATER;
245
+
246
+ async function promptForDependencyUpdaterChoice(updaters, {prompt}) {
247
+ return prompt({
248
+ id: DEPENDENCY_UPDATER_PROMPT_ID,
249
+ questions: [{
250
+ name: DEPENDENCY_UPDATER$1,
251
+ type: 'list',
252
+ message: 'Which dependency-update service do you want to manage this project?',
253
+ choices: [...Object.keys(updaters), 'Other']
254
+ }]
255
+ });
219
256
  }
220
257
 
221
- async function scaffoldDependencyUpdater (plugins, decisions, options) {
258
+ const {DEPENDENCY_UPDATER} = questionNames.DEPENDENCY_UPDATER;
259
+
260
+ async function scaffoldDependencyUpdater(plugins, options, {prompt}) {
222
261
  if (!Object.keys(plugins).length) return undefined;
223
262
 
224
263
  const plugin = plugins[
225
- (await promptForDependencyUpdaterChoice(plugins, decisions))[questionNames$1.DEPENDENCY_UPDATER]
264
+ (await promptForDependencyUpdaterChoice(plugins, {prompt}))[DEPENDENCY_UPDATER]
226
265
  ];
227
266
 
228
267
  if (plugin) return plugin.scaffold(options);
@@ -230,8 +269,54 @@ async function scaffoldDependencyUpdater (plugins, decisions, options) {
230
269
  return undefined;
231
270
  }
232
271
 
233
- function promptForBaseDetails(projectRoot, decisions) {
234
- return prompt(questionsForBaseDetails(decisions, projectRoot), decisions);
272
+ const CI_PROVIDER_PROMPT_ID = 'CI_PROVIDER';
273
+
274
+ const {CI_PROVIDER: CI_PROVIDER$1} = questionNames.CI_PROVIDER;
275
+
276
+ function promptForCiProvider(providers, {prompt}) {
277
+ return prompt({
278
+ id: CI_PROVIDER_PROMPT_ID,
279
+ questions: [{
280
+ name: CI_PROVIDER$1,
281
+ type: 'list',
282
+ message: 'Which CI service do you want use with this project?',
283
+ choices: [...Object.keys(providers), 'Other']
284
+ }]
285
+ });
286
+ }
287
+
288
+ const {CI_PROVIDER} = questionNames.CI_PROVIDER;
289
+
290
+ async function scaffoldCiProvider(plugins, options, {prompt}) {
291
+ if (!Object.keys(plugins).length) return undefined;
292
+
293
+ const {projectRoot} = options;
294
+
295
+ const qualifiedPlugins = Object.fromEntries(
296
+ (await Promise.all(
297
+ Object.entries(plugins).map(async ([name, plugin]) => [
298
+ name,
299
+ plugin,
300
+ plugin.qualify ? await plugin.qualify({projectRoot}) : true
301
+ ])
302
+ )).filter(([, , qualified]) => qualified).map(([name, plugin]) => [name, plugin])
303
+ );
304
+
305
+ const chosen = (await promptForCiProvider(qualifiedPlugins, {prompt}))[CI_PROVIDER];
306
+ const plugin = qualifiedPlugins[chosen];
307
+
308
+ if (plugin) return plugin.scaffold(options);
309
+
310
+ return {};
311
+ }
312
+
313
+ const BASE_DETAILS_PROMPT_ID = 'BASE_DETAILS';
314
+
315
+ function promptForBaseDetails(projectRoot, {prompt}) {
316
+ return prompt({
317
+ id: BASE_DETAILS_PROMPT_ID,
318
+ questions: questionsForBaseDetails(projectRoot)
319
+ });
235
320
  }
236
321
 
237
322
  var languagePluginsSchema = joi.object().pattern(/^/, optionsSchemas.form8ionPlugin).default({});
@@ -240,31 +325,35 @@ var vcsHostPluginsSchema = joi.object().pattern(/^/, optionsSchemas.form8ionPlug
240
325
 
241
326
  var dependencyUpdaterPluginsSchema = joi.object().pattern(joi.string(), optionsSchemas.form8ionPlugin).default({});
242
327
 
243
- const decisionsSchema = joi.object();
328
+ var ciProviderPluginsSchema = joi.object().pattern(joi.string(), optionsSchemas.form8ionPlugin).default({});
244
329
 
245
330
  function validate(options) {
246
331
  return validateOptions(joi.object({
247
- decisions: decisionsSchema,
248
332
  plugins: joi.object({
249
333
  dependencyUpdaters: dependencyUpdaterPluginsSchema,
250
334
  languages: languagePluginsSchema,
251
- vcsHosts: vcsHostPluginsSchema
335
+ vcsHosts: vcsHostPluginsSchema,
336
+ ciProviders: ciProviderPluginsSchema
252
337
  })
253
338
  }), options) || {};
254
339
  }
255
340
 
256
- function determinePathToTemplateFile (fileName) {
341
+ function determinePathToTemplate(fileName) {
257
342
  const [, __dirname] = filedirname();
258
343
 
259
344
  return resolve(__dirname, '..', 'templates', fileName);
260
345
  }
261
346
 
262
- function scaffoldEditorConfig ({projectRoot}) {
263
- return promises$1.copyFile(determinePathToTemplateFile('editorconfig.ini'), `${projectRoot}/.editorconfig`);
347
+ function scaffoldEditorConfig({projectRoot}) {
348
+ return promises$1.copyFile(determinePathToTemplate('editorconfig.ini'), `${projectRoot}/.editorconfig`);
264
349
  }
265
350
 
266
- function scaffoldContributing ({visibility}) {
267
- if ('Public' === visibility) {
351
+ function editorconfigInUse({projectRoot}) {
352
+ return fileExists(`${projectRoot}/.editorconfig`);
353
+ }
354
+
355
+ function scaffoldContribution({visibility}) {
356
+ if (['OSS', 'ISS'].includes(visibility)) {
268
357
  return {
269
358
  badges: {
270
359
  contribution: {
@@ -281,7 +370,11 @@ function scaffoldContributing ({visibility}) {
281
370
  return {};
282
371
  }
283
372
 
284
- async function lift ({projectRoot, results, enhancers, vcs, dependencies}) {
373
+ async function lift({projectRoot, results, enhancers, vcs}, dependencies) {
374
+ if (!await editorconfigInUse({projectRoot})) {
375
+ await scaffoldEditorConfig({projectRoot});
376
+ }
377
+
285
378
  const enhancerResults = await applyEnhancers({
286
379
  results,
287
380
  enhancers: {...enhancers, gitPlugin, licensePlugin},
@@ -294,38 +387,40 @@ async function lift ({projectRoot, results, enhancers, vcs, dependencies}) {
294
387
  return enhancerResults;
295
388
  }
296
389
 
297
- async function scaffold(options) {
390
+ async function scaffold(options, dependencies) {
298
391
  const projectRoot = process.cwd();
299
- const {decisions, plugins: {dependencyUpdaters, languages, vcsHosts = {}}} = validate(options);
392
+ const {plugins: {dependencyUpdaters, ciProviders, languages, vcsHosts = {}}} = validate(options);
393
+ const {prompt, logger} = dependencies;
300
394
 
301
395
  const {
302
- [questionNames$2.PROJECT_NAME]: projectName,
303
- [questionNames$2.LICENSE]: chosenLicense,
304
- [questionNames$2.VISIBILITY]: visibility,
305
- [questionNames$2.DESCRIPTION]: description,
306
- [questionNames$2.COPYRIGHT_YEAR]: copyrightYear,
307
- [questionNames$2.COPYRIGHT_HOLDER]: copyHolder
308
- } = await promptForBaseDetails(projectRoot, decisions);
396
+ [questionNames$1.PROJECT_NAME]: projectName,
397
+ [questionNames$1.LICENSE]: chosenLicense,
398
+ [questionNames$1.VISIBILITY]: visibility,
399
+ [questionNames$1.DESCRIPTION]: description,
400
+ [questionNames$1.COPYRIGHT_YEAR]: copyrightYear,
401
+ [questionNames$1.COPYRIGHT_HOLDER]: copyHolder
402
+ } = await promptForBaseDetails(projectRoot, {prompt});
309
403
  const copyright = {year: copyrightYear, holder: copyHolder};
310
404
 
311
405
  const [vcsResults, contributing, license] = await Promise.all([
312
- scaffoldVcs({projectRoot, projectName, decisions, vcsHosts, visibility, description}),
313
- scaffoldContributing({visibility}),
314
- scaffoldLicense({projectRoot, license: chosenLicense, copyright}),
406
+ scaffoldVcs({projectRoot, projectName, vcsHosts, visibility, description}, {prompt, logger}),
407
+ scaffoldContribution({visibility}),
408
+ scaffoldLicense({projectRoot, license: chosenLicense, copyright}, {logger}),
315
409
  scaffold$2({projectName, projectRoot, description}),
316
410
  scaffoldEditorConfig({projectRoot})
317
411
  ]);
318
412
 
319
- const dependencyUpdaterResults = vcsResults.vcs && await scaffoldDependencyUpdater(
320
- dependencyUpdaters,
321
- decisions,
322
- {projectRoot}
323
- );
413
+ const [dependencyUpdaterResults] = vcsResults.vcs
414
+ ? await Promise.all([
415
+ scaffoldDependencyUpdater(dependencyUpdaters, {projectRoot}, {prompt}),
416
+ scaffoldCiProvider(ciProviders, {projectRoot}, {prompt})
417
+ ])
418
+ : [];
324
419
 
325
420
  const language = await scaffoldLanguage(
326
421
  languages,
327
- decisions,
328
- {projectRoot, projectName, vcs: vcsResults.vcs, visibility, license: chosenLicense || 'UNLICENSED', description}
422
+ {projectRoot, projectName, vcs: vcsResults.vcs, visibility, license: chosenLicense || 'UNLICENSED', description},
423
+ {prompt}
329
424
  );
330
425
 
331
426
  const mergedResults = deepmerge.all([
@@ -341,23 +436,29 @@ async function scaffold(options) {
341
436
  vcs: vcsResults.vcs,
342
437
  results: mergedResults,
343
438
  enhancers: {...dependencyUpdaters, ...languages, ...vcsHosts}
344
- });
439
+ }, dependencies);
345
440
 
346
441
  if (language && language.verificationCommand) {
347
- info('Verifying the generated project');
442
+ logger.info('Verifying the generated project');
348
443
 
349
444
  const subprocess = execa(language.verificationCommand, {shell: true});
350
445
  subprocess.stdout.pipe(process.stdout);
351
446
  await subprocess;
352
447
  }
353
448
 
354
- reportResults(mergedResults);
449
+ return mergedResults;
355
450
  }
356
451
 
357
- const questionNames = {
358
- ...questionNames$2,
359
- ...questionNames$1
452
+ const ids = {
453
+ BASE_DETAILS: BASE_DETAILS_PROMPT_ID,
454
+ GIT_REPOSITORY: GIT_REPOSITORY_PROMPT_ID,
455
+ REPOSITORY_HOST: REPOSITORY_HOST_PROMPT_ID,
456
+ PROJECT_LANGUAGE: PROJECT_LANGUAGE_PROMPT_ID,
457
+ DEPENDENCY_UPDATER: DEPENDENCY_UPDATER_PROMPT_ID,
458
+ CI_PROVIDER: CI_PROVIDER_PROMPT_ID
360
459
  };
361
460
 
362
- export { lift, questionNames, scaffold };
461
+ const constants = {ids, questionNames};
462
+
463
+ export { lift, constants as promptConstants, scaffold };
363
464
  //# sourceMappingURL=index.js.map