@form8ion/javascript 1.1.0 → 2.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -11
- package/lib/index.cjs.js +1350 -41
- package/lib/index.cjs.js.map +1 -1
- package/lib/index.es.js +1345 -42
- package/lib/index.es.js.map +1 -1
- package/package.json +36 -13
- package/templates/.eslintrc.yml +3 -0
- package/templates/example.mustache +3 -0
package/lib/index.es.js
CHANGED
|
@@ -1,13 +1,27 @@
|
|
|
1
|
+
import { questionNames as questionNames$2, questions } from '@travi/language-scaffolder-prompts';
|
|
1
2
|
import deepmerge from 'deepmerge';
|
|
2
|
-
import { validateOptions, scaffoldChoice } from '@form8ion/javascript-core';
|
|
3
|
+
import { validateOptions, scaffoldChoice, dialects, projectTypes, packageManagers } from '@form8ion/javascript-core';
|
|
4
|
+
import { scaffold as scaffold$1 } from '@form8ion/codecov';
|
|
3
5
|
import { promises } from 'fs';
|
|
4
6
|
import * as joi from '@hapi/joi';
|
|
5
7
|
import { Separator } from 'inquirer';
|
|
6
|
-
import { prompt } from '@form8ion/overridable-prompts';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
import { prompt as prompt$1 } from '@form8ion/overridable-prompts';
|
|
9
|
+
import { warn, info } from '@travi/cli-messages';
|
|
10
|
+
import { lift } from '@form8ion/lift-javascript';
|
|
11
|
+
import { scaffold as scaffold$5 } from '@form8ion/commit-convention';
|
|
12
|
+
import hoek from '@hapi/hoek';
|
|
13
|
+
import execa from 'execa';
|
|
14
|
+
import { stringify } from 'ini';
|
|
15
|
+
import { EOL } from 'os';
|
|
16
|
+
import validatePackageName from 'validate-npm-package-name';
|
|
17
|
+
import { scaffold as scaffold$2 } from '@form8ion/rollup';
|
|
18
|
+
import mustache from 'mustache';
|
|
19
|
+
import camelcase from 'camelcase';
|
|
20
|
+
import makeDir from 'make-dir';
|
|
21
|
+
import touch from 'touch';
|
|
22
|
+
import { resolve } from 'path';
|
|
23
|
+
import { scaffold as scaffold$4 } from '@form8ion/husky';
|
|
24
|
+
import { scaffold as scaffold$3 } from '@form8ion/eslint';
|
|
11
25
|
|
|
12
26
|
function ownKeys(object, enumerableOnly) {
|
|
13
27
|
var keys = Object.keys(object);
|
|
@@ -62,31 +76,21 @@ function _defineProperty(obj, key, value) {
|
|
|
62
76
|
return obj;
|
|
63
77
|
}
|
|
64
78
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
status: {
|
|
81
|
-
coverage: {
|
|
82
|
-
img: `https://img.shields.io/codecov/c/${vcs.host}/${vcs.owner}/${vcs.name}.svg`,
|
|
83
|
-
link: `https://codecov.io/${vcs.host}/${vcs.owner}/${vcs.name}`,
|
|
84
|
-
text: 'Codecov'
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
});
|
|
89
|
-
}
|
|
79
|
+
const questionNames$1 = {
|
|
80
|
+
UNIT_TEST_FRAMEWORK: 'unitTestFramework',
|
|
81
|
+
NODE_VERSION_CATEGORY: 'nodeVersionCategory',
|
|
82
|
+
PACKAGE_MANAGER: 'packageManager',
|
|
83
|
+
PROJECT_TYPE: 'projectType',
|
|
84
|
+
PROJECT_TYPE_CHOICE: 'projectTypeChoice',
|
|
85
|
+
SHOULD_BE_SCOPED: 'shouldBeScoped',
|
|
86
|
+
SCOPE: 'scope',
|
|
87
|
+
AUTHOR_NAME: 'authorName',
|
|
88
|
+
AUTHOR_EMAIL: 'authorEmail',
|
|
89
|
+
AUTHOR_URL: 'authorUrl',
|
|
90
|
+
HOST: 'host',
|
|
91
|
+
CONFIGURE_LINTING: 'configureLint',
|
|
92
|
+
DIALECT: 'dialect'
|
|
93
|
+
};
|
|
90
94
|
|
|
91
95
|
async function scaffoldC8 ({
|
|
92
96
|
projectRoot
|
|
@@ -116,7 +120,7 @@ async function scaffoldCoverage ({
|
|
|
116
120
|
}) {
|
|
117
121
|
return deepmerge(await scaffoldC8({
|
|
118
122
|
projectRoot
|
|
119
|
-
}), scaffold({
|
|
123
|
+
}), await scaffold$1({
|
|
120
124
|
vcs,
|
|
121
125
|
visibility
|
|
122
126
|
}));
|
|
@@ -126,25 +130,21 @@ const unitTestFrameworksSchema = joi.object().required().pattern(/^/, joi.object
|
|
|
126
130
|
scaffolder: joi.func().arity(1).required()
|
|
127
131
|
}));
|
|
128
132
|
|
|
129
|
-
const questionNames = {
|
|
130
|
-
UNIT_TEST_FRAMEWORK: 'unitTestFramework'
|
|
131
|
-
};
|
|
132
|
-
|
|
133
133
|
async function chooseFramework ({
|
|
134
134
|
frameworks,
|
|
135
135
|
decisions
|
|
136
136
|
}) {
|
|
137
137
|
if (!Object.keys(frameworks).length) return 'Other';
|
|
138
|
-
const answers = await prompt([{
|
|
139
|
-
name: questionNames.UNIT_TEST_FRAMEWORK,
|
|
138
|
+
const answers = await prompt$1([{
|
|
139
|
+
name: questionNames$1.UNIT_TEST_FRAMEWORK,
|
|
140
140
|
type: 'list',
|
|
141
141
|
message: 'Which type of unit testing framework should be used?',
|
|
142
142
|
choices: [...Object.keys(frameworks), new Separator(), 'Other']
|
|
143
143
|
}], decisions);
|
|
144
|
-
return answers[questionNames.UNIT_TEST_FRAMEWORK];
|
|
144
|
+
return answers[questionNames$1.UNIT_TEST_FRAMEWORK];
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
-
async function
|
|
147
|
+
async function scaffoldUnitTesting ({
|
|
148
148
|
projectRoot,
|
|
149
149
|
frameworks,
|
|
150
150
|
decisions,
|
|
@@ -164,10 +164,1313 @@ async function unit ({
|
|
|
164
164
|
})]);
|
|
165
165
|
return deepmerge.all([{
|
|
166
166
|
scripts: {
|
|
167
|
-
'test:unit': 'cross-env NODE_ENV=test
|
|
167
|
+
'test:unit': 'cross-env NODE_ENV=test c8 run-s test:unit:base'
|
|
168
168
|
}
|
|
169
169
|
}, framework, coverage]);
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
-
|
|
172
|
+
function validate(options) {
|
|
173
|
+
const schema = joi.object().required().keys({
|
|
174
|
+
projectRoot: joi.string().required(),
|
|
175
|
+
projectName: joi.string().regex(/^@\w*\//, {
|
|
176
|
+
invert: true
|
|
177
|
+
}).required(),
|
|
178
|
+
visibility: joi.string().valid('Public', 'Private').required(),
|
|
179
|
+
license: joi.string().required(),
|
|
180
|
+
description: joi.string(),
|
|
181
|
+
pathWithinParent: joi.string()
|
|
182
|
+
}).keys({
|
|
183
|
+
vcs: joi.object({
|
|
184
|
+
host: joi.string().required(),
|
|
185
|
+
owner: joi.string().required(),
|
|
186
|
+
name: joi.string().required()
|
|
187
|
+
})
|
|
188
|
+
}).keys({
|
|
189
|
+
configs: joi.object({
|
|
190
|
+
eslint: joi.object({
|
|
191
|
+
scope: joi.string().regex(/^@[a-z0-9-]+$/i, 'scope').required()
|
|
192
|
+
}),
|
|
193
|
+
typescript: joi.object({
|
|
194
|
+
scope: joi.string().regex(/^@[a-z0-9-]+$/i, 'scope').required()
|
|
195
|
+
}),
|
|
196
|
+
commitlint: joi.object({
|
|
197
|
+
packageName: joi.string().required(),
|
|
198
|
+
name: joi.string().required()
|
|
199
|
+
}),
|
|
200
|
+
babelPreset: joi.object({
|
|
201
|
+
packageName: joi.string().required(),
|
|
202
|
+
name: joi.string().required()
|
|
203
|
+
}),
|
|
204
|
+
remark: joi.string()
|
|
205
|
+
}).default({})
|
|
206
|
+
}).keys({
|
|
207
|
+
overrides: joi.object({
|
|
208
|
+
npmAccount: joi.string(),
|
|
209
|
+
author: joi.object({
|
|
210
|
+
name: joi.string().required(),
|
|
211
|
+
email: joi.string().email(),
|
|
212
|
+
url: joi.string().uri()
|
|
213
|
+
})
|
|
214
|
+
}).default({})
|
|
215
|
+
}).keys({
|
|
216
|
+
ciServices: joi.object().pattern(/^/, joi.object({
|
|
217
|
+
scaffolder: joi.func().arity(1).required(),
|
|
218
|
+
public: joi.boolean(),
|
|
219
|
+
private: joi.boolean()
|
|
220
|
+
})).default({})
|
|
221
|
+
}).keys({
|
|
222
|
+
hosts: joi.object().pattern(/^/, joi.object({
|
|
223
|
+
scaffolder: joi.func().arity(1).required(),
|
|
224
|
+
projectTypes: joi.array().items(joi.string().valid('static', 'node')).default([])
|
|
225
|
+
})).default({})
|
|
226
|
+
}).keys({
|
|
227
|
+
applicationTypes: joi.object().pattern(/^/, joi.object({
|
|
228
|
+
scaffolder: joi.func().arity(1).required()
|
|
229
|
+
})).default({}),
|
|
230
|
+
packageTypes: joi.object().pattern(/^/, joi.object({
|
|
231
|
+
scaffolder: joi.func().arity(1).required()
|
|
232
|
+
})).default({}),
|
|
233
|
+
monorepoTypes: joi.object().pattern(/^/, joi.object({
|
|
234
|
+
scaffolder: joi.func().arity(1).required()
|
|
235
|
+
}))
|
|
236
|
+
}).keys({
|
|
237
|
+
decisions: joi.object()
|
|
238
|
+
}).keys({
|
|
239
|
+
unitTestFrameworks: unitTestFrameworksSchema
|
|
240
|
+
}).keys({
|
|
241
|
+
registries: joi.object().pattern(joi.string(), joi.string().uri())
|
|
242
|
+
});
|
|
243
|
+
const {
|
|
244
|
+
error,
|
|
245
|
+
value
|
|
246
|
+
} = schema.validate(options);
|
|
247
|
+
hoek.assert(!error, error);
|
|
248
|
+
return value;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const npmConf = require('npm-conf');
|
|
252
|
+
|
|
253
|
+
var npmConfFactory = npmConf;
|
|
254
|
+
|
|
255
|
+
function buildDialectChoices ({
|
|
256
|
+
babelPreset,
|
|
257
|
+
typescript
|
|
258
|
+
}) {
|
|
259
|
+
return [{
|
|
260
|
+
name: 'Common JS (no transpilation)',
|
|
261
|
+
value: dialects.COMMON_JS,
|
|
262
|
+
short: 'cjs'
|
|
263
|
+
}, ...(babelPreset ? [{
|
|
264
|
+
name: 'Modern JavaScript (transpiled)',
|
|
265
|
+
value: dialects.BABEL,
|
|
266
|
+
short: 'modern'
|
|
267
|
+
}] : []), {
|
|
268
|
+
name: 'ESM-only (no transpilation)',
|
|
269
|
+
value: dialects.ESM,
|
|
270
|
+
short: 'esm'
|
|
271
|
+
}, ...(typescript ? [{
|
|
272
|
+
name: 'TypeScript',
|
|
273
|
+
value: dialects.TYPESCRIPT,
|
|
274
|
+
short: 'ts'
|
|
275
|
+
}] : [])];
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function projectIsPackage(answers) {
|
|
279
|
+
return projectTypes.PACKAGE === answers[questionNames$1.PROJECT_TYPE];
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function projectIsCLI(answers) {
|
|
283
|
+
return projectTypes.CLI === answers[questionNames$1.PROJECT_TYPE];
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function projectIsApplication(answers) {
|
|
287
|
+
return projectTypes.APPLICATION === answers[questionNames$1.PROJECT_TYPE];
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function packageShouldBeScoped(visibility, answers) {
|
|
291
|
+
return 'Private' === visibility || answers[questionNames$1.SHOULD_BE_SCOPED];
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function willBePublishedToNpm(answers) {
|
|
295
|
+
return projectIsPackage(answers) || projectIsCLI(answers);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
function shouldBeScopedPromptShouldBePresented(answers) {
|
|
299
|
+
return willBePublishedToNpm(answers);
|
|
300
|
+
}
|
|
301
|
+
function scopePromptShouldBePresentedFactory(visibility) {
|
|
302
|
+
return answers => willBePublishedToNpm(answers) && packageShouldBeScoped(visibility, answers);
|
|
303
|
+
}
|
|
304
|
+
function lintingPromptShouldBePresented({
|
|
305
|
+
[questionNames$2.UNIT_TESTS]: unitTested,
|
|
306
|
+
[questionNames$2.INTEGRATION_TESTS]: integrationTested
|
|
307
|
+
}) {
|
|
308
|
+
return !unitTested && !integrationTested;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function scope(visibility) {
|
|
312
|
+
return input => {
|
|
313
|
+
if (!input && 'Private' === visibility) {
|
|
314
|
+
return 'Private packages must be scoped (https://docs.npmjs.com/private-modules/intro#setting-up-your-package)';
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
return true;
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function authorQuestions({
|
|
322
|
+
name,
|
|
323
|
+
email,
|
|
324
|
+
url
|
|
325
|
+
}) {
|
|
326
|
+
return [{
|
|
327
|
+
name: questionNames$1.AUTHOR_NAME,
|
|
328
|
+
message: 'What is the author\'s name?',
|
|
329
|
+
default: name
|
|
330
|
+
}, {
|
|
331
|
+
name: questionNames$1.AUTHOR_EMAIL,
|
|
332
|
+
message: 'What is the author\'s email?',
|
|
333
|
+
default: email
|
|
334
|
+
}, {
|
|
335
|
+
name: questionNames$1.AUTHOR_URL,
|
|
336
|
+
message: 'What is the author\'s website url?',
|
|
337
|
+
default: url
|
|
338
|
+
}];
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
async function prompt({
|
|
342
|
+
npmAccount,
|
|
343
|
+
author
|
|
344
|
+
}, ciServices, hosts, visibility, vcs, decisions, configs, pathWithinParent) {
|
|
345
|
+
const npmConf = npmConfFactory();
|
|
346
|
+
let maybeLoggedInNpmUsername;
|
|
347
|
+
|
|
348
|
+
try {
|
|
349
|
+
maybeLoggedInNpmUsername = (await execa('npm', ['whoami'])).stdout;
|
|
350
|
+
} catch (failedExecutionResult) {
|
|
351
|
+
if (!decisions[questionNames$1.SCOPE]) {
|
|
352
|
+
warn('No logged in user found with `npm whoami`. Login with `npm login` ' + 'to use your npm account name as the package scope default.');
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
const {
|
|
357
|
+
[questionNames$2.UNIT_TESTS]: unitTested,
|
|
358
|
+
[questionNames$2.INTEGRATION_TESTS]: integrationTested,
|
|
359
|
+
[questionNames$1.PROJECT_TYPE]: projectType,
|
|
360
|
+
[questionNames$2.CI_SERVICE]: ci,
|
|
361
|
+
[questionNames$1.HOST]: chosenHost,
|
|
362
|
+
[questionNames$1.SCOPE]: scope$1,
|
|
363
|
+
[questionNames$1.NODE_VERSION_CATEGORY]: nodeVersionCategory,
|
|
364
|
+
[questionNames$1.AUTHOR_NAME]: authorName,
|
|
365
|
+
[questionNames$1.AUTHOR_EMAIL]: authorEmail,
|
|
366
|
+
[questionNames$1.AUTHOR_URL]: authorUrl,
|
|
367
|
+
[questionNames$1.CONFIGURE_LINTING]: configureLinting,
|
|
368
|
+
[questionNames$1.PACKAGE_MANAGER]: packageManager,
|
|
369
|
+
[questionNames$1.DIALECT]: dialect
|
|
370
|
+
} = await prompt$1([{
|
|
371
|
+
name: questionNames$1.DIALECT,
|
|
372
|
+
message: 'Which JavaScript dialect should this project follow?',
|
|
373
|
+
type: 'list',
|
|
374
|
+
choices: buildDialectChoices(configs),
|
|
375
|
+
default: 'babel'
|
|
376
|
+
}, ...(pathWithinParent ? [] : [{
|
|
377
|
+
name: questionNames$1.NODE_VERSION_CATEGORY,
|
|
378
|
+
message: 'What node.js version should be used?',
|
|
379
|
+
type: 'list',
|
|
380
|
+
choices: ['LTS', 'Latest'],
|
|
381
|
+
default: 'LTS'
|
|
382
|
+
}]), {
|
|
383
|
+
name: questionNames$1.PACKAGE_MANAGER,
|
|
384
|
+
message: 'Which package manager will be used with this project?',
|
|
385
|
+
type: 'list',
|
|
386
|
+
choices: Object.values(packageManagers),
|
|
387
|
+
default: packageManagers.NPM
|
|
388
|
+
}, {
|
|
389
|
+
name: questionNames$1.PROJECT_TYPE,
|
|
390
|
+
message: 'What type of JavaScript project is this?',
|
|
391
|
+
type: 'list',
|
|
392
|
+
choices: [...Object.values(projectTypes), new Separator(), 'Other'],
|
|
393
|
+
default: projectTypes.PACKAGE
|
|
394
|
+
}, ...('Private' === visibility ? [] : [{
|
|
395
|
+
name: questionNames$1.SHOULD_BE_SCOPED,
|
|
396
|
+
message: 'Should this package be scoped?',
|
|
397
|
+
type: 'confirm',
|
|
398
|
+
when: shouldBeScopedPromptShouldBePresented,
|
|
399
|
+
default: true
|
|
400
|
+
}]), {
|
|
401
|
+
name: questionNames$1.SCOPE,
|
|
402
|
+
message: 'What is the scope?',
|
|
403
|
+
when: scopePromptShouldBePresentedFactory(visibility),
|
|
404
|
+
validate: scope(visibility),
|
|
405
|
+
default: npmAccount || maybeLoggedInNpmUsername
|
|
406
|
+
}, ...authorQuestions(author || {
|
|
407
|
+
name: npmConf.get('init.author.name'),
|
|
408
|
+
email: npmConf.get('init.author.email'),
|
|
409
|
+
url: npmConf.get('init.author.url')
|
|
410
|
+
}), ...questions({
|
|
411
|
+
vcs,
|
|
412
|
+
ciServices,
|
|
413
|
+
visibility,
|
|
414
|
+
pathWithinParent
|
|
415
|
+
}), {
|
|
416
|
+
name: questionNames$1.CONFIGURE_LINTING,
|
|
417
|
+
message: 'Will there be source code that should be linted?',
|
|
418
|
+
type: 'confirm',
|
|
419
|
+
when: lintingPromptShouldBePresented
|
|
420
|
+
}, {
|
|
421
|
+
name: questionNames$1.HOST,
|
|
422
|
+
type: 'list',
|
|
423
|
+
message: 'Where will the application be hosted?',
|
|
424
|
+
when: projectIsApplication,
|
|
425
|
+
choices: [...Object.keys(hosts), new Separator(), 'Other']
|
|
426
|
+
}], decisions);
|
|
427
|
+
return {
|
|
428
|
+
tests: {
|
|
429
|
+
unit: unitTested,
|
|
430
|
+
integration: integrationTested
|
|
431
|
+
},
|
|
432
|
+
projectType,
|
|
433
|
+
ci,
|
|
434
|
+
chosenHost,
|
|
435
|
+
scope: scope$1,
|
|
436
|
+
nodeVersionCategory,
|
|
437
|
+
author: {
|
|
438
|
+
name: authorName,
|
|
439
|
+
email: authorEmail,
|
|
440
|
+
url: authorUrl
|
|
441
|
+
},
|
|
442
|
+
configureLinting: false !== configureLinting,
|
|
443
|
+
packageManager,
|
|
444
|
+
dialect
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
async function scaffoldBabel ({
|
|
449
|
+
projectRoot,
|
|
450
|
+
preset,
|
|
451
|
+
tests,
|
|
452
|
+
buildDirectory
|
|
453
|
+
}) {
|
|
454
|
+
if (!preset) {
|
|
455
|
+
throw new Error('No babel preset provided. Cannot configure babel transpilation');
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
await promises.writeFile(`${projectRoot}/.babelrc`, JSON.stringify(_objectSpread2({
|
|
459
|
+
presets: [preset.name],
|
|
460
|
+
ignore: [`./${buildDirectory}/`]
|
|
461
|
+
}, tests.unit && {
|
|
462
|
+
env: {
|
|
463
|
+
test: {
|
|
464
|
+
plugins: ['istanbul']
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
})));
|
|
468
|
+
return {
|
|
469
|
+
devDependencies: ['@babel/register', preset.packageName, ...(tests.unit ? ['babel-plugin-istanbul'] : [])],
|
|
470
|
+
eslint: {}
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
async function scaffoldTypescript ({
|
|
475
|
+
config,
|
|
476
|
+
projectType,
|
|
477
|
+
projectRoot,
|
|
478
|
+
testFilenamePattern
|
|
479
|
+
}) {
|
|
480
|
+
const eslintConfigs = ['typescript'];
|
|
481
|
+
const shareableTsConfigPackage = `${config.scope}/tsconfig`;
|
|
482
|
+
await promises.writeFile(`${projectRoot}/tsconfig.json`, JSON.stringify(_objectSpread2({
|
|
483
|
+
$schema: 'https://json.schemastore.org/tsconfig',
|
|
484
|
+
extends: shareableTsConfigPackage,
|
|
485
|
+
compilerOptions: _objectSpread2({
|
|
486
|
+
rootDir: 'src'
|
|
487
|
+
}, projectTypes.PACKAGE === projectType && {
|
|
488
|
+
outDir: 'lib',
|
|
489
|
+
declaration: true
|
|
490
|
+
}),
|
|
491
|
+
include: ['src/**/*.ts']
|
|
492
|
+
}, testFilenamePattern && {
|
|
493
|
+
exclude: [testFilenamePattern]
|
|
494
|
+
})));
|
|
495
|
+
return {
|
|
496
|
+
eslint: {
|
|
497
|
+
configs: eslintConfigs
|
|
498
|
+
},
|
|
499
|
+
eslintConfigs,
|
|
500
|
+
devDependencies: ['typescript', shareableTsConfigPackage],
|
|
501
|
+
packageProperties: {
|
|
502
|
+
types: 'lib/index.d.ts'
|
|
503
|
+
},
|
|
504
|
+
vcsIgnore: {
|
|
505
|
+
files: ['tsconfig.tsbuildinfo']
|
|
506
|
+
}
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
function scaffoldEsm () {
|
|
511
|
+
return {
|
|
512
|
+
packageProperties: {
|
|
513
|
+
engines: {
|
|
514
|
+
node: '>=12.20'
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
function scaffoldDialect ({
|
|
521
|
+
dialect,
|
|
522
|
+
projectType,
|
|
523
|
+
projectRoot,
|
|
524
|
+
configs,
|
|
525
|
+
tests,
|
|
526
|
+
buildDirectory,
|
|
527
|
+
testFilenamePattern
|
|
528
|
+
}) {
|
|
529
|
+
switch (dialect) {
|
|
530
|
+
case dialects.BABEL:
|
|
531
|
+
return scaffoldBabel({
|
|
532
|
+
preset: configs.babelPreset,
|
|
533
|
+
projectRoot,
|
|
534
|
+
tests,
|
|
535
|
+
buildDirectory
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
case dialects.TYPESCRIPT:
|
|
539
|
+
return scaffoldTypescript({
|
|
540
|
+
config: configs.typescript,
|
|
541
|
+
projectType,
|
|
542
|
+
projectRoot,
|
|
543
|
+
testFilenamePattern
|
|
544
|
+
});
|
|
545
|
+
|
|
546
|
+
case dialects.ESM:
|
|
547
|
+
return scaffoldEsm();
|
|
548
|
+
|
|
549
|
+
default:
|
|
550
|
+
return {
|
|
551
|
+
eslint: {}
|
|
552
|
+
};
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
function projectWillNotBeConsumed(projectType) {
|
|
557
|
+
return projectTypes.APPLICATION === projectType || projectTypes.CLI === projectType;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
async function scaffoldNpmConfig ({
|
|
561
|
+
projectRoot,
|
|
562
|
+
projectType,
|
|
563
|
+
registries
|
|
564
|
+
}) {
|
|
565
|
+
await promises.writeFile(`${projectRoot}/.npmrc`, stringify(_objectSpread2(_objectSpread2({
|
|
566
|
+
'update-notifier': false,
|
|
567
|
+
'engine-strict': true
|
|
568
|
+
}, projectWillNotBeConsumed(projectType) && {
|
|
569
|
+
'save-exact': true
|
|
570
|
+
}), registries && Object.fromEntries(Object.entries(registries).map(([scope, url]) => [`@${scope}:registry`, url])))));
|
|
571
|
+
return {
|
|
572
|
+
scripts: {
|
|
573
|
+
'lint:peer': 'npm ls >/dev/null'
|
|
574
|
+
}
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
function buildDocumentationCommand (packageManager) {
|
|
579
|
+
if (packageManagers.NPM === packageManager) return 'npm run generate:md';
|
|
580
|
+
if (packageManagers.YARN === packageManager) return 'yarn generate:md';
|
|
581
|
+
throw new Error(`The ${packageManager} package manager is currently not supported. ` + `Only ${Object.values(packageManagers).join(' and ')} are currently supported.`);
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
function scaffoldDocumentation ({
|
|
585
|
+
projectTypeResults,
|
|
586
|
+
packageManager
|
|
587
|
+
}) {
|
|
588
|
+
return _objectSpread2(_objectSpread2({
|
|
589
|
+
toc: `Run \`${buildDocumentationCommand(packageManager)}\` to generate a table of contents`
|
|
590
|
+
}, projectTypeResults.documentation), {}, {
|
|
591
|
+
contributing: `### Dependencies
|
|
592
|
+
|
|
593
|
+
\`\`\`sh
|
|
594
|
+
$ nvm install
|
|
595
|
+
$ ${packageManager} install
|
|
596
|
+
\`\`\`
|
|
597
|
+
|
|
598
|
+
### Verification
|
|
599
|
+
|
|
600
|
+
\`\`\`sh
|
|
601
|
+
$ ${packageManager} test
|
|
602
|
+
\`\`\``
|
|
603
|
+
});
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
async function determineLatestVersionOf(nodeVersionCategory) {
|
|
607
|
+
info('Determining version of node', {
|
|
608
|
+
level: 'secondary'
|
|
609
|
+
});
|
|
610
|
+
const {
|
|
611
|
+
stdout: nvmLsOutput
|
|
612
|
+
} = await execa(`. ~/.nvm/nvm.sh && nvm ls-remote${'LTS' === nodeVersionCategory ? ' --lts' : ''}`, {
|
|
613
|
+
shell: true
|
|
614
|
+
});
|
|
615
|
+
const lsLines = nvmLsOutput.split('\n');
|
|
616
|
+
const lsLine = lsLines[lsLines.length - 2];
|
|
617
|
+
return lsLine.match(/(v[0-9]+)\.[0-9]+\.[0-9]+/)[1];
|
|
618
|
+
}
|
|
619
|
+
function install(nodeVersionCategory) {
|
|
620
|
+
info(`Installing ${nodeVersionCategory} version of node using nvm`, {
|
|
621
|
+
level: 'secondary'
|
|
622
|
+
});
|
|
623
|
+
const subprocess = execa('. ~/.nvm/nvm.sh && nvm install', {
|
|
624
|
+
shell: true
|
|
625
|
+
});
|
|
626
|
+
subprocess.stdout.pipe(process.stdout);
|
|
627
|
+
return subprocess;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
async function scaffoldNodeVersion ({
|
|
631
|
+
projectRoot,
|
|
632
|
+
nodeVersionCategory
|
|
633
|
+
}) {
|
|
634
|
+
if (!nodeVersionCategory) return undefined;
|
|
635
|
+
const lowerCaseCategory = nodeVersionCategory.toLowerCase();
|
|
636
|
+
info(`Configuring ${lowerCaseCategory} version of node`);
|
|
637
|
+
const version = await determineLatestVersionOf(nodeVersionCategory);
|
|
638
|
+
await promises.writeFile(`${projectRoot}/.nvmrc`, version);
|
|
639
|
+
await install(nodeVersionCategory);
|
|
640
|
+
return version;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
function buildBadgesDetails (contributors) {
|
|
644
|
+
return deepmerge.all(contributors).badges;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
function buildVcsIgnoreLists (vcsIgnoreLists = {}) {
|
|
648
|
+
return {
|
|
649
|
+
files: vcsIgnoreLists.files || [],
|
|
650
|
+
directories: ['/node_modules/', ...(vcsIgnoreLists.directories || [])]
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
function projectWillBeTested(scripts) {
|
|
655
|
+
return Object.keys(scripts).find(scriptName => scriptName.startsWith('test:'));
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
function projectShouldBeBuiltForVerification(scripts) {
|
|
659
|
+
return 'run-s build' === scripts['pregenerate:md'];
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
function defineScripts(scripts) {
|
|
663
|
+
return {
|
|
664
|
+
test: `npm-run-all --print-label${projectShouldBeBuiltForVerification(scripts) ? ' build' : ''} --parallel lint:*${projectWillBeTested(scripts) ? ' --parallel test:*' : ''}`
|
|
665
|
+
};
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
function defineVcsHostDetails(vcs, packageType, packageName, pathWithinParent) {
|
|
669
|
+
return vcs && 'github' === vcs.host && {
|
|
670
|
+
repository: pathWithinParent ? {
|
|
671
|
+
type: 'git',
|
|
672
|
+
url: `https://github.com/${vcs.owner}/${vcs.name}.git`,
|
|
673
|
+
directory: pathWithinParent
|
|
674
|
+
} : `${vcs.owner}/${vcs.name}`,
|
|
675
|
+
bugs: `https://github.com/${vcs.owner}/${vcs.name}/issues`,
|
|
676
|
+
homepage: projectTypes.PACKAGE === packageType ? `https://npm.im/${packageName}` : `https://github.com/${vcs.owner}/${vcs.name}#readme`
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
function buildPackageDetails ({
|
|
681
|
+
packageName,
|
|
682
|
+
projectType,
|
|
683
|
+
dialect,
|
|
684
|
+
license,
|
|
685
|
+
vcs,
|
|
686
|
+
author,
|
|
687
|
+
description,
|
|
688
|
+
scripts,
|
|
689
|
+
packageProperties,
|
|
690
|
+
pathWithinParent
|
|
691
|
+
}) {
|
|
692
|
+
return _objectSpread2(_objectSpread2(_objectSpread2({
|
|
693
|
+
name: packageName,
|
|
694
|
+
description,
|
|
695
|
+
license,
|
|
696
|
+
type: dialects.ESM === dialect ? 'module' : 'commonjs'
|
|
697
|
+
}, packageProperties), defineVcsHostDetails(vcs, projectType, packageName, pathWithinParent)), {}, {
|
|
698
|
+
author: `${author.name}${author.email ? ` <${author.email}>` : ''}${author.url ? ` (${author.url})` : ''}`,
|
|
699
|
+
scripts: defineScripts(scripts)
|
|
700
|
+
});
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
async function scaffoldPackage ({
|
|
704
|
+
projectRoot,
|
|
705
|
+
projectType,
|
|
706
|
+
dialect,
|
|
707
|
+
scripts,
|
|
708
|
+
packageName,
|
|
709
|
+
license,
|
|
710
|
+
vcs,
|
|
711
|
+
author,
|
|
712
|
+
description,
|
|
713
|
+
packageProperties,
|
|
714
|
+
pathWithinParent
|
|
715
|
+
}) {
|
|
716
|
+
info('Configuring package.json');
|
|
717
|
+
const packageData = await buildPackageDetails({
|
|
718
|
+
packageName,
|
|
719
|
+
projectType,
|
|
720
|
+
dialect,
|
|
721
|
+
license,
|
|
722
|
+
vcs,
|
|
723
|
+
author,
|
|
724
|
+
description,
|
|
725
|
+
scripts,
|
|
726
|
+
packageProperties,
|
|
727
|
+
pathWithinParent
|
|
728
|
+
});
|
|
729
|
+
await promises.writeFile(`${projectRoot}/package.json`, JSON.stringify(packageData));
|
|
730
|
+
return {
|
|
731
|
+
homepage: packageData.homepage
|
|
732
|
+
};
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
function buildPackageName (projectName, scope) {
|
|
736
|
+
const name = `${scope ? `@${scope}/` : ''}${projectName}`;
|
|
737
|
+
const {
|
|
738
|
+
validForNewPackages,
|
|
739
|
+
errors
|
|
740
|
+
} = validatePackageName(name);
|
|
741
|
+
if (validForNewPackages) return name;
|
|
742
|
+
if (1 === errors.length && errors.includes('name cannot start with a period')) return projectName.slice(1);
|
|
743
|
+
throw new Error(`The package name ${name} is invalid:${EOL}\t* ${errors.join(`${EOL}\t* `)}`);
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
async function chooseApplicationType ({
|
|
747
|
+
types,
|
|
748
|
+
projectType,
|
|
749
|
+
decisions
|
|
750
|
+
}) {
|
|
751
|
+
if (!Object.keys(types).length) return 'Other';
|
|
752
|
+
const answers = await prompt$1([{
|
|
753
|
+
name: questionNames$1.PROJECT_TYPE_CHOICE,
|
|
754
|
+
type: 'list',
|
|
755
|
+
message: `What type of ${projectType} is this?`,
|
|
756
|
+
choices: [...Object.keys(types), new Separator(), 'Other']
|
|
757
|
+
}], decisions);
|
|
758
|
+
return answers[questionNames$1.PROJECT_TYPE_CHOICE];
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
function getInstallationCommand(packageManager) {
|
|
762
|
+
if (packageManagers.NPM === packageManager) return 'npm install';
|
|
763
|
+
if (packageManagers.YARN === packageManager) return 'yarn add';
|
|
764
|
+
throw new Error(`The ${packageManager} package manager is currently not supported. ` + `Only ${Object.values(packageManagers).join(' and ')} are currently supported.`);
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
function scaffoldPackageDocumentation ({
|
|
768
|
+
scope,
|
|
769
|
+
packageName,
|
|
770
|
+
packageManager,
|
|
771
|
+
visibility
|
|
772
|
+
}) {
|
|
773
|
+
return {
|
|
774
|
+
usage: `### Installation
|
|
775
|
+
${'Private' === visibility ? `
|
|
776
|
+
:warning: this is a private package, so you will need to use an npm token with
|
|
777
|
+
access to private packages under \`@${scope}\`
|
|
778
|
+
` : ''}
|
|
779
|
+
\`\`\`sh
|
|
780
|
+
$ ${getInstallationCommand(packageManager)} ${packageName}
|
|
781
|
+
\`\`\`
|
|
782
|
+
|
|
783
|
+
### Example
|
|
784
|
+
|
|
785
|
+
run \`${buildDocumentationCommand(packageManager)}\` to inject the usage example`
|
|
786
|
+
};
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
function defineBadges (packageName, visibility) {
|
|
790
|
+
return {
|
|
791
|
+
consumer: _objectSpread2({}, 'Public' === visibility && {
|
|
792
|
+
npm: {
|
|
793
|
+
img: `https://img.shields.io/npm/v/${packageName}.svg`,
|
|
794
|
+
text: 'npm',
|
|
795
|
+
link: `https://www.npmjs.com/package/${packageName}`
|
|
796
|
+
}
|
|
797
|
+
}),
|
|
798
|
+
status: {}
|
|
799
|
+
};
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
function determinePathToTemplateFile (fileName) {
|
|
803
|
+
return resolve(__dirname, '..', 'templates', fileName);
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
const defaultBuildDirectory$2 = 'lib';
|
|
807
|
+
|
|
808
|
+
async function createExample(projectRoot, projectName) {
|
|
809
|
+
return promises.writeFile(`${projectRoot}/example.js`, mustache.render(await promises.readFile(determinePathToTemplateFile('example.mustache'), 'utf8'), {
|
|
810
|
+
projectName: camelcase(projectName)
|
|
811
|
+
}));
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
async function buildDetailsForCommonJsProject({
|
|
815
|
+
projectRoot,
|
|
816
|
+
projectName
|
|
817
|
+
}) {
|
|
818
|
+
await Promise.all([touch(`${projectRoot}/index.js`), promises.writeFile(`${projectRoot}/example.js`, `const ${camelcase(projectName)} = require('.');\n`)]);
|
|
819
|
+
return {};
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
async function buildDetails ({
|
|
823
|
+
projectRoot,
|
|
824
|
+
projectName,
|
|
825
|
+
visibility,
|
|
826
|
+
packageName,
|
|
827
|
+
dialect
|
|
828
|
+
}) {
|
|
829
|
+
if (dialects.COMMON_JS === dialect) return buildDetailsForCommonJsProject({
|
|
830
|
+
projectRoot,
|
|
831
|
+
projectName
|
|
832
|
+
});
|
|
833
|
+
const pathToCreatedSrcDirectory = await makeDir(`${projectRoot}/src`);
|
|
834
|
+
const [rollupResults] = await Promise.all([scaffold$2({
|
|
835
|
+
projectRoot,
|
|
836
|
+
dialect,
|
|
837
|
+
projectType: projectTypes.PACKAGE
|
|
838
|
+
}), await createExample(projectRoot, projectName), touch(`${pathToCreatedSrcDirectory}/index.js`)]);
|
|
839
|
+
return deepmerge(rollupResults, {
|
|
840
|
+
devDependencies: ['rimraf'],
|
|
841
|
+
scripts: {
|
|
842
|
+
clean: `rimraf ./${defaultBuildDirectory$2}`,
|
|
843
|
+
prebuild: 'run-s clean',
|
|
844
|
+
build: 'npm-run-all --print-label --parallel build:*',
|
|
845
|
+
prepack: 'run-s build'
|
|
846
|
+
},
|
|
847
|
+
vcsIgnore: {
|
|
848
|
+
directories: [`/${defaultBuildDirectory$2}/`]
|
|
849
|
+
},
|
|
850
|
+
buildDirectory: defaultBuildDirectory$2,
|
|
851
|
+
badges: {
|
|
852
|
+
consumer: _objectSpread2({}, 'Public' === visibility && {
|
|
853
|
+
runkit: {
|
|
854
|
+
img: `https://badge.runkitcdn.com/${packageName}.svg`,
|
|
855
|
+
text: `Try ${packageName} on RunKit`,
|
|
856
|
+
link: `https://npm.runkit.com/${packageName}`
|
|
857
|
+
}
|
|
858
|
+
})
|
|
859
|
+
}
|
|
860
|
+
});
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
async function scaffoldPackageType ({
|
|
864
|
+
projectRoot,
|
|
865
|
+
projectName,
|
|
866
|
+
packageName,
|
|
867
|
+
packageManager,
|
|
868
|
+
visibility,
|
|
869
|
+
scope,
|
|
870
|
+
packageTypes,
|
|
871
|
+
tests,
|
|
872
|
+
decisions,
|
|
873
|
+
dialect
|
|
874
|
+
}) {
|
|
875
|
+
info('Scaffolding Package Details');
|
|
876
|
+
const detailsForBuild = await buildDetails({
|
|
877
|
+
projectRoot,
|
|
878
|
+
projectName,
|
|
879
|
+
visibility,
|
|
880
|
+
packageName,
|
|
881
|
+
dialect
|
|
882
|
+
});
|
|
883
|
+
|
|
884
|
+
const details = _objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2({}, dialects.BABEL === dialect && _objectSpread2({
|
|
885
|
+
packageProperties: {
|
|
886
|
+
main: 'lib/index.cjs.js',
|
|
887
|
+
module: 'lib/index.es.js',
|
|
888
|
+
sideEffects: false,
|
|
889
|
+
files: ['lib/']
|
|
890
|
+
}
|
|
891
|
+
}, detailsForBuild)), dialects.ESM === dialect && _objectSpread2({
|
|
892
|
+
packageProperties: {
|
|
893
|
+
main: 'lib/index.es.js',
|
|
894
|
+
sideEffects: false,
|
|
895
|
+
files: ['lib/']
|
|
896
|
+
}
|
|
897
|
+
}, detailsForBuild)), dialects.TYPESCRIPT === dialect && _objectSpread2({
|
|
898
|
+
packageProperties: {
|
|
899
|
+
main: 'lib/index.cjs.js',
|
|
900
|
+
module: 'lib/index.es.js',
|
|
901
|
+
sideEffects: false,
|
|
902
|
+
files: ['lib/']
|
|
903
|
+
}
|
|
904
|
+
}, detailsForBuild)), dialects.COMMON_JS === dialect && _objectSpread2({
|
|
905
|
+
packageProperties: {
|
|
906
|
+
files: ['index.js']
|
|
907
|
+
}
|
|
908
|
+
}, detailsForBuild));
|
|
909
|
+
|
|
910
|
+
const chosenType = await chooseApplicationType({
|
|
911
|
+
types: packageTypes,
|
|
912
|
+
projectType: 'package',
|
|
913
|
+
decisions
|
|
914
|
+
});
|
|
915
|
+
const results = await scaffoldChoice(packageTypes, chosenType, {
|
|
916
|
+
projectRoot,
|
|
917
|
+
projectName,
|
|
918
|
+
packageName,
|
|
919
|
+
tests,
|
|
920
|
+
scope
|
|
921
|
+
});
|
|
922
|
+
return deepmerge.all([{
|
|
923
|
+
packageProperties: _objectSpread2({
|
|
924
|
+
files: ['example.js'],
|
|
925
|
+
publishConfig: {
|
|
926
|
+
access: 'Public' === visibility ? 'public' : 'restricted'
|
|
927
|
+
}
|
|
928
|
+
}, 'Public' === visibility && {
|
|
929
|
+
runkitExampleFilename: './example.js'
|
|
930
|
+
}),
|
|
931
|
+
documentation: scaffoldPackageDocumentation({
|
|
932
|
+
packageName,
|
|
933
|
+
visibility,
|
|
934
|
+
scope,
|
|
935
|
+
packageManager
|
|
936
|
+
}),
|
|
937
|
+
eslintConfigs: [],
|
|
938
|
+
nextSteps: [{
|
|
939
|
+
summary: 'Add the appropriate `save` flag to the installation instructions in the README'
|
|
940
|
+
}, {
|
|
941
|
+
summary: 'Publish pre-release versions to npm until package is stable enough to publish v1.0.0'
|
|
942
|
+
}],
|
|
943
|
+
scripts: {},
|
|
944
|
+
badges: defineBadges(packageName, visibility)
|
|
945
|
+
}, results, details]);
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
const defaultBuildDirectory$1 = 'lib';
|
|
949
|
+
async function scaffoldApplicationType ({
|
|
950
|
+
applicationTypes,
|
|
951
|
+
projectRoot,
|
|
952
|
+
projectName,
|
|
953
|
+
packageName,
|
|
954
|
+
packageManager,
|
|
955
|
+
tests,
|
|
956
|
+
decisions
|
|
957
|
+
}) {
|
|
958
|
+
info('Scaffolding Application Details');
|
|
959
|
+
const chosenType = await chooseApplicationType({
|
|
960
|
+
types: applicationTypes,
|
|
961
|
+
projectType: 'application',
|
|
962
|
+
decisions
|
|
963
|
+
});
|
|
964
|
+
const results = await scaffoldChoice(applicationTypes, chosenType, {
|
|
965
|
+
projectRoot,
|
|
966
|
+
projectName,
|
|
967
|
+
packageName,
|
|
968
|
+
packageManager,
|
|
969
|
+
tests
|
|
970
|
+
});
|
|
971
|
+
const buildDirectory = results.buildDirectory || defaultBuildDirectory$1;
|
|
972
|
+
return deepmerge({
|
|
973
|
+
scripts: {
|
|
974
|
+
clean: `rimraf ./${buildDirectory}`,
|
|
975
|
+
start: `node ./${buildDirectory}/index.js`,
|
|
976
|
+
prebuild: 'run-s clean'
|
|
977
|
+
},
|
|
978
|
+
dependencies: [],
|
|
979
|
+
devDependencies: ['rimraf'],
|
|
980
|
+
vcsIgnore: {
|
|
981
|
+
files: ['.env'],
|
|
982
|
+
directories: [`/${buildDirectory}/`]
|
|
983
|
+
},
|
|
984
|
+
buildDirectory,
|
|
985
|
+
packageProperties: {
|
|
986
|
+
private: true
|
|
987
|
+
},
|
|
988
|
+
eslintConfigs: [],
|
|
989
|
+
nextSteps: []
|
|
990
|
+
}, results);
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
async function scaffoldMonorepoType ({
|
|
994
|
+
monorepoTypes,
|
|
995
|
+
projectRoot,
|
|
996
|
+
packageManager,
|
|
997
|
+
decisions
|
|
998
|
+
}) {
|
|
999
|
+
info('Scaffolding Monorepo Details');
|
|
1000
|
+
const chosenType = await chooseApplicationType({
|
|
1001
|
+
types: monorepoTypes,
|
|
1002
|
+
projectType: projectTypes.MONOREPO,
|
|
1003
|
+
decisions
|
|
1004
|
+
});
|
|
1005
|
+
const results = await scaffoldChoice(monorepoTypes, chosenType, {
|
|
1006
|
+
projectRoot,
|
|
1007
|
+
packageManager
|
|
1008
|
+
});
|
|
1009
|
+
return deepmerge({
|
|
1010
|
+
eslintConfigs: [],
|
|
1011
|
+
packageProperties: {
|
|
1012
|
+
private: true
|
|
1013
|
+
},
|
|
1014
|
+
nextSteps: [{
|
|
1015
|
+
summary: 'Add packages to your new monorepo',
|
|
1016
|
+
description: 'Leverage [@form8ion/add-package-to-monorepo](https://npm.im/@form8ion/add-package-to-monorepo)' + ' to scaffold new packages into your new monorepo'
|
|
1017
|
+
}]
|
|
1018
|
+
}, results);
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
const defaultBuildDirectory = 'bin';
|
|
1022
|
+
async function scaffoldCliType ({
|
|
1023
|
+
packageName,
|
|
1024
|
+
visibility,
|
|
1025
|
+
projectRoot,
|
|
1026
|
+
dialect
|
|
1027
|
+
}) {
|
|
1028
|
+
const rollupResults = await scaffold$2({
|
|
1029
|
+
projectRoot,
|
|
1030
|
+
dialect,
|
|
1031
|
+
projectType: projectTypes.CLI
|
|
1032
|
+
});
|
|
1033
|
+
return deepmerge(rollupResults, {
|
|
1034
|
+
scripts: {
|
|
1035
|
+
clean: `rimraf ./${defaultBuildDirectory}`,
|
|
1036
|
+
prebuild: 'run-s clean',
|
|
1037
|
+
build: 'npm-run-all --print-label --parallel build:*',
|
|
1038
|
+
prepack: 'run-s build'
|
|
1039
|
+
},
|
|
1040
|
+
dependencies: ['update-notifier'],
|
|
1041
|
+
devDependencies: ['rimraf'],
|
|
1042
|
+
vcsIgnore: {
|
|
1043
|
+
files: [],
|
|
1044
|
+
directories: [`/${defaultBuildDirectory}/`]
|
|
1045
|
+
},
|
|
1046
|
+
buildDirectory: defaultBuildDirectory,
|
|
1047
|
+
badges: defineBadges(packageName, visibility),
|
|
1048
|
+
packageProperties: {
|
|
1049
|
+
version: '0.0.0-semantically-released',
|
|
1050
|
+
bin: {},
|
|
1051
|
+
files: [`${defaultBuildDirectory}/`],
|
|
1052
|
+
publishConfig: {
|
|
1053
|
+
access: 'Public' === visibility ? 'public' : 'restricted'
|
|
1054
|
+
}
|
|
1055
|
+
},
|
|
1056
|
+
eslintConfigs: [],
|
|
1057
|
+
nextSteps: []
|
|
1058
|
+
});
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
async function scaffoldProjectType ({
|
|
1062
|
+
projectType,
|
|
1063
|
+
projectRoot,
|
|
1064
|
+
projectName,
|
|
1065
|
+
packageName,
|
|
1066
|
+
packageManager,
|
|
1067
|
+
visibility,
|
|
1068
|
+
applicationTypes,
|
|
1069
|
+
packageTypes,
|
|
1070
|
+
monorepoTypes,
|
|
1071
|
+
scope,
|
|
1072
|
+
tests,
|
|
1073
|
+
vcs,
|
|
1074
|
+
decisions,
|
|
1075
|
+
dialect
|
|
1076
|
+
}) {
|
|
1077
|
+
switch (projectType) {
|
|
1078
|
+
case projectTypes.PACKAGE:
|
|
1079
|
+
return scaffoldPackageType({
|
|
1080
|
+
projectRoot,
|
|
1081
|
+
projectName,
|
|
1082
|
+
packageName,
|
|
1083
|
+
packageManager,
|
|
1084
|
+
visibility,
|
|
1085
|
+
scope,
|
|
1086
|
+
packageTypes,
|
|
1087
|
+
tests,
|
|
1088
|
+
vcs,
|
|
1089
|
+
decisions,
|
|
1090
|
+
dialect
|
|
1091
|
+
});
|
|
1092
|
+
|
|
1093
|
+
case projectTypes.APPLICATION:
|
|
1094
|
+
return scaffoldApplicationType({
|
|
1095
|
+
projectRoot,
|
|
1096
|
+
projectName,
|
|
1097
|
+
packageName,
|
|
1098
|
+
packageManager,
|
|
1099
|
+
applicationTypes,
|
|
1100
|
+
tests,
|
|
1101
|
+
decisions
|
|
1102
|
+
});
|
|
1103
|
+
|
|
1104
|
+
case projectTypes.CLI:
|
|
1105
|
+
return scaffoldCliType({
|
|
1106
|
+
packageName,
|
|
1107
|
+
visibility,
|
|
1108
|
+
projectRoot,
|
|
1109
|
+
dialect
|
|
1110
|
+
});
|
|
1111
|
+
|
|
1112
|
+
case projectTypes.MONOREPO:
|
|
1113
|
+
return scaffoldMonorepoType({
|
|
1114
|
+
monorepoTypes,
|
|
1115
|
+
projectRoot,
|
|
1116
|
+
packageManager,
|
|
1117
|
+
decisions
|
|
1118
|
+
});
|
|
1119
|
+
|
|
1120
|
+
case 'Other':
|
|
1121
|
+
return {
|
|
1122
|
+
eslintConfigs: []
|
|
1123
|
+
};
|
|
1124
|
+
|
|
1125
|
+
default:
|
|
1126
|
+
throw new Error(`The project-type of ${projectType} is invalid`);
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
async function scaffoldTesting ({
|
|
1131
|
+
projectRoot,
|
|
1132
|
+
visibility,
|
|
1133
|
+
tests: {
|
|
1134
|
+
unit,
|
|
1135
|
+
integration
|
|
1136
|
+
},
|
|
1137
|
+
vcs,
|
|
1138
|
+
unitTestFrameworks,
|
|
1139
|
+
decisions,
|
|
1140
|
+
dialect
|
|
1141
|
+
}) {
|
|
1142
|
+
const unitResults = unit ? await scaffoldUnitTesting({
|
|
1143
|
+
projectRoot,
|
|
1144
|
+
visibility,
|
|
1145
|
+
vcs,
|
|
1146
|
+
frameworks: unitTestFrameworks,
|
|
1147
|
+
decisions,
|
|
1148
|
+
dialect
|
|
1149
|
+
}) : {};
|
|
1150
|
+
return deepmerge({
|
|
1151
|
+
devDependencies: [...(unit || integration ? ['@travi/any'] : [])],
|
|
1152
|
+
eslint: [],
|
|
1153
|
+
eslintConfigs: []
|
|
1154
|
+
}, unitResults);
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
async function scaffoldEslint ({
|
|
1158
|
+
config,
|
|
1159
|
+
projectRoot,
|
|
1160
|
+
buildDirectory,
|
|
1161
|
+
additionalConfiguration
|
|
1162
|
+
}) {
|
|
1163
|
+
const {
|
|
1164
|
+
scope
|
|
1165
|
+
} = config;
|
|
1166
|
+
const {
|
|
1167
|
+
ignore
|
|
1168
|
+
} = additionalConfiguration;
|
|
1169
|
+
const ignores = deepmerge(ignore, {
|
|
1170
|
+
directories: [`/${buildDirectory}/`]
|
|
1171
|
+
});
|
|
1172
|
+
return scaffold$3({
|
|
1173
|
+
scope,
|
|
1174
|
+
projectRoot,
|
|
1175
|
+
ignore: {
|
|
1176
|
+
directories: ignores.directories
|
|
1177
|
+
}
|
|
1178
|
+
});
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
async function scaffoldRemark ({
|
|
1182
|
+
config,
|
|
1183
|
+
projectRoot,
|
|
1184
|
+
projectType,
|
|
1185
|
+
vcs,
|
|
1186
|
+
dialect
|
|
1187
|
+
}) {
|
|
1188
|
+
await promises.writeFile(`${projectRoot}/.remarkrc.json`, JSON.stringify({
|
|
1189
|
+
settings: {
|
|
1190
|
+
listItemIndent: 1,
|
|
1191
|
+
emphasis: '_',
|
|
1192
|
+
strong: '_',
|
|
1193
|
+
bullet: '*',
|
|
1194
|
+
incrementListMarker: false
|
|
1195
|
+
},
|
|
1196
|
+
plugins: [config, ['remark-toc', {
|
|
1197
|
+
tight: true
|
|
1198
|
+
}], ...(projectTypes.PACKAGE === projectType ? [['remark-usage', {
|
|
1199
|
+
heading: 'example'
|
|
1200
|
+
}]] : []), ...(!vcs ? [['validate-links', {
|
|
1201
|
+
repository: false
|
|
1202
|
+
}]] : [])]
|
|
1203
|
+
}));
|
|
1204
|
+
return deepmerge({
|
|
1205
|
+
devDependencies: [config, 'remark-cli', 'remark-toc'],
|
|
1206
|
+
scripts: {
|
|
1207
|
+
'lint:md': 'remark . --frail',
|
|
1208
|
+
'generate:md': 'remark . --output'
|
|
1209
|
+
}
|
|
1210
|
+
}, _objectSpread2({}, projectTypes.PACKAGE === projectType && _objectSpread2({
|
|
1211
|
+
devDependencies: ['remark-usage']
|
|
1212
|
+
}, dialects.COMMON_JS !== dialect && {
|
|
1213
|
+
scripts: {
|
|
1214
|
+
'pregenerate:md': 'run-s build'
|
|
1215
|
+
}
|
|
1216
|
+
})));
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
function scaffoldBanSensitiveFiles () {
|
|
1220
|
+
return {
|
|
1221
|
+
scripts: {
|
|
1222
|
+
'lint:sensitive': 'ban'
|
|
1223
|
+
},
|
|
1224
|
+
devDependencies: ['ban-sensitive-files']
|
|
1225
|
+
};
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
function determineLockfilePathFor(packageManager) {
|
|
1229
|
+
if (packageManagers.NPM === packageManager) return 'package-lock.json';
|
|
1230
|
+
if (packageManagers.YARN === packageManager) return 'yarn.lock';
|
|
1231
|
+
throw new Error(`The ${packageManager} package manager is currently not supported. ` + `Only ${Object.values(packageManagers).join(' and ')} are currently supported.`);
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
async function scaffoldLockfileLint ({
|
|
1235
|
+
projectRoot,
|
|
1236
|
+
packageManager,
|
|
1237
|
+
registries
|
|
1238
|
+
}) {
|
|
1239
|
+
await promises.writeFile(`${projectRoot}/.lockfile-lintrc.json`, JSON.stringify({
|
|
1240
|
+
path: determineLockfilePathFor(packageManager),
|
|
1241
|
+
type: packageManager,
|
|
1242
|
+
'validate-https': true,
|
|
1243
|
+
'allowed-hosts': [packageManager, ...(registries ? Object.values(registries) : [])]
|
|
1244
|
+
}));
|
|
1245
|
+
return {
|
|
1246
|
+
devDependencies: ['lockfile-lint'],
|
|
1247
|
+
scripts: {
|
|
1248
|
+
'lint:lockfile': 'lockfile-lint'
|
|
1249
|
+
}
|
|
1250
|
+
};
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
async function scaffoldLinting ({
|
|
1254
|
+
projectRoot,
|
|
1255
|
+
projectType,
|
|
1256
|
+
packageManager,
|
|
1257
|
+
dialect,
|
|
1258
|
+
registries,
|
|
1259
|
+
configs,
|
|
1260
|
+
vcs,
|
|
1261
|
+
configureLinting,
|
|
1262
|
+
buildDirectory,
|
|
1263
|
+
eslint
|
|
1264
|
+
}) {
|
|
1265
|
+
return deepmerge.all(await Promise.all([scaffoldLockfileLint({
|
|
1266
|
+
projectRoot,
|
|
1267
|
+
packageManager,
|
|
1268
|
+
registries
|
|
1269
|
+
}), configs.eslint && configureLinting ? scaffoldEslint({
|
|
1270
|
+
projectRoot,
|
|
1271
|
+
config: configs.eslint,
|
|
1272
|
+
buildDirectory,
|
|
1273
|
+
additionalConfiguration: eslint
|
|
1274
|
+
}) : {}, scaffoldRemark({
|
|
1275
|
+
projectRoot,
|
|
1276
|
+
projectType,
|
|
1277
|
+
dialect,
|
|
1278
|
+
vcs,
|
|
1279
|
+
config: configs.remark || '@form8ion/remark-lint-preset'
|
|
1280
|
+
}), vcs ? scaffoldBanSensitiveFiles() : {}]));
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
async function scaffoldVerification({
|
|
1284
|
+
projectRoot,
|
|
1285
|
+
projectType,
|
|
1286
|
+
dialect,
|
|
1287
|
+
visibility,
|
|
1288
|
+
packageManager,
|
|
1289
|
+
vcs,
|
|
1290
|
+
configs,
|
|
1291
|
+
registries,
|
|
1292
|
+
configureLinting,
|
|
1293
|
+
tests,
|
|
1294
|
+
unitTestFrameworks,
|
|
1295
|
+
decisions,
|
|
1296
|
+
buildDirectory,
|
|
1297
|
+
eslintConfigs
|
|
1298
|
+
}) {
|
|
1299
|
+
const [testingResults, huskyResults] = await Promise.all([scaffoldTesting({
|
|
1300
|
+
projectRoot,
|
|
1301
|
+
tests,
|
|
1302
|
+
visibility,
|
|
1303
|
+
vcs,
|
|
1304
|
+
unitTestFrameworks,
|
|
1305
|
+
decisions,
|
|
1306
|
+
dialect
|
|
1307
|
+
}), scaffold$4({
|
|
1308
|
+
projectRoot,
|
|
1309
|
+
packageManager
|
|
1310
|
+
})]);
|
|
1311
|
+
const lintingResults = await scaffoldLinting({
|
|
1312
|
+
projectRoot,
|
|
1313
|
+
projectType,
|
|
1314
|
+
packageManager,
|
|
1315
|
+
dialect,
|
|
1316
|
+
configs,
|
|
1317
|
+
registries,
|
|
1318
|
+
vcs,
|
|
1319
|
+
configureLinting,
|
|
1320
|
+
buildDirectory,
|
|
1321
|
+
eslint: deepmerge.all([testingResults.eslint, {
|
|
1322
|
+
configs: testingResults.eslintConfigs
|
|
1323
|
+
}, {
|
|
1324
|
+
configs: eslintConfigs
|
|
1325
|
+
}])
|
|
1326
|
+
});
|
|
1327
|
+
return deepmerge.all([testingResults, lintingResults, huskyResults]);
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
async function scaffold(options) {
|
|
1331
|
+
info('Initializing JavaScript project');
|
|
1332
|
+
const {
|
|
1333
|
+
projectRoot,
|
|
1334
|
+
projectName,
|
|
1335
|
+
visibility,
|
|
1336
|
+
license,
|
|
1337
|
+
vcs,
|
|
1338
|
+
description,
|
|
1339
|
+
configs,
|
|
1340
|
+
overrides,
|
|
1341
|
+
ciServices,
|
|
1342
|
+
hosts,
|
|
1343
|
+
applicationTypes,
|
|
1344
|
+
packageTypes,
|
|
1345
|
+
monorepoTypes,
|
|
1346
|
+
decisions,
|
|
1347
|
+
unitTestFrameworks,
|
|
1348
|
+
pathWithinParent,
|
|
1349
|
+
registries
|
|
1350
|
+
} = validate(options);
|
|
1351
|
+
const {
|
|
1352
|
+
tests,
|
|
1353
|
+
projectType,
|
|
1354
|
+
ci,
|
|
1355
|
+
chosenHost,
|
|
1356
|
+
scope,
|
|
1357
|
+
nodeVersionCategory,
|
|
1358
|
+
author,
|
|
1359
|
+
configureLinting,
|
|
1360
|
+
packageManager,
|
|
1361
|
+
dialect
|
|
1362
|
+
} = await prompt(overrides, ciServices, hosts, visibility, vcs, decisions, configs, pathWithinParent);
|
|
1363
|
+
info('Writing project files', {
|
|
1364
|
+
level: 'secondary'
|
|
1365
|
+
});
|
|
1366
|
+
const packageName = buildPackageName(projectName, scope);
|
|
1367
|
+
const projectTypeResults = await scaffoldProjectType({
|
|
1368
|
+
projectType,
|
|
1369
|
+
projectRoot,
|
|
1370
|
+
projectName,
|
|
1371
|
+
packageName,
|
|
1372
|
+
packageManager,
|
|
1373
|
+
visibility,
|
|
1374
|
+
applicationTypes,
|
|
1375
|
+
packageTypes,
|
|
1376
|
+
monorepoTypes,
|
|
1377
|
+
scope,
|
|
1378
|
+
tests,
|
|
1379
|
+
vcs,
|
|
1380
|
+
decisions,
|
|
1381
|
+
dialect
|
|
1382
|
+
});
|
|
1383
|
+
const verificationResults = await scaffoldVerification({
|
|
1384
|
+
projectRoot,
|
|
1385
|
+
projectType,
|
|
1386
|
+
dialect,
|
|
1387
|
+
packageManager,
|
|
1388
|
+
visibility,
|
|
1389
|
+
vcs,
|
|
1390
|
+
configs,
|
|
1391
|
+
registries,
|
|
1392
|
+
configureLinting,
|
|
1393
|
+
tests,
|
|
1394
|
+
unitTestFrameworks,
|
|
1395
|
+
decisions,
|
|
1396
|
+
buildDirectory: projectTypeResults.buildDirectory,
|
|
1397
|
+
eslintConfigs: projectTypeResults.eslintConfigs
|
|
1398
|
+
});
|
|
1399
|
+
const [nodeVersion, npmResults, dialectResults] = await Promise.all([scaffoldNodeVersion({
|
|
1400
|
+
projectRoot,
|
|
1401
|
+
nodeVersionCategory
|
|
1402
|
+
}), scaffoldNpmConfig({
|
|
1403
|
+
projectType,
|
|
1404
|
+
projectRoot,
|
|
1405
|
+
registries
|
|
1406
|
+
}), scaffoldDialect({
|
|
1407
|
+
dialect,
|
|
1408
|
+
configs,
|
|
1409
|
+
projectRoot,
|
|
1410
|
+
projectType,
|
|
1411
|
+
tests,
|
|
1412
|
+
buildDirectory: projectTypeResults.buildDirectory,
|
|
1413
|
+
testFilenamePattern: verificationResults.testFilenamePattern
|
|
1414
|
+
})]);
|
|
1415
|
+
const mergedContributions = deepmerge.all([...(await Promise.all([scaffoldChoice(hosts, chosenHost, {
|
|
1416
|
+
buildDirectory: `./${projectTypeResults.buildDirectory}`,
|
|
1417
|
+
projectRoot,
|
|
1418
|
+
projectName,
|
|
1419
|
+
nodeVersion
|
|
1420
|
+
}), scaffoldChoice(ciServices, ci, {
|
|
1421
|
+
projectRoot,
|
|
1422
|
+
vcs,
|
|
1423
|
+
visibility,
|
|
1424
|
+
projectType,
|
|
1425
|
+
projectName,
|
|
1426
|
+
nodeVersion,
|
|
1427
|
+
tests
|
|
1428
|
+
}), scaffold$5({
|
|
1429
|
+
projectRoot,
|
|
1430
|
+
projectType,
|
|
1431
|
+
configs,
|
|
1432
|
+
pathWithinParent
|
|
1433
|
+
})])), projectTypeResults, verificationResults, npmResults, dialectResults]);
|
|
1434
|
+
const {
|
|
1435
|
+
homepage: projectHomepage
|
|
1436
|
+
} = await scaffoldPackage({
|
|
1437
|
+
projectRoot,
|
|
1438
|
+
projectType,
|
|
1439
|
+
dialect,
|
|
1440
|
+
packageName,
|
|
1441
|
+
license,
|
|
1442
|
+
vcs,
|
|
1443
|
+
author,
|
|
1444
|
+
description,
|
|
1445
|
+
packageProperties: mergedContributions.packageProperties,
|
|
1446
|
+
scripts: mergedContributions.scripts,
|
|
1447
|
+
pathWithinParent
|
|
1448
|
+
});
|
|
1449
|
+
const liftResults = await lift({
|
|
1450
|
+
results: deepmerge({
|
|
1451
|
+
devDependencies: ['npm-run-all'],
|
|
1452
|
+
packageManager
|
|
1453
|
+
}, mergedContributions),
|
|
1454
|
+
projectRoot,
|
|
1455
|
+
configs
|
|
1456
|
+
});
|
|
1457
|
+
return {
|
|
1458
|
+
badges: buildBadgesDetails([mergedContributions, liftResults]),
|
|
1459
|
+
documentation: scaffoldDocumentation({
|
|
1460
|
+
projectTypeResults,
|
|
1461
|
+
packageManager
|
|
1462
|
+
}),
|
|
1463
|
+
tags: projectTypeResults.tags,
|
|
1464
|
+
vcsIgnore: buildVcsIgnoreLists(mergedContributions.vcsIgnore),
|
|
1465
|
+
verificationCommand: `${buildDocumentationCommand(packageManager)} && ${packageManager} test`,
|
|
1466
|
+
projectDetails: _objectSpread2({}, projectHomepage && {
|
|
1467
|
+
homepage: projectHomepage
|
|
1468
|
+
}),
|
|
1469
|
+
nextSteps: mergedContributions.nextSteps
|
|
1470
|
+
};
|
|
1471
|
+
}
|
|
1472
|
+
|
|
1473
|
+
const questionNames = _objectSpread2(_objectSpread2({}, questionNames$2), questionNames$1);
|
|
1474
|
+
|
|
1475
|
+
export { questionNames, scaffold, scaffoldUnitTesting };
|
|
173
1476
|
//# sourceMappingURL=index.es.js.map
|