create-gasket-app 7.0.0-next.3 → 7.0.0-next.4

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.
@@ -1,34 +1,27 @@
1
1
  /* eslint-disable max-statements */
2
- import ora from 'ora';
3
2
  import chalk from 'chalk';
4
3
  import { makeCreateContext } from '../scaffold/create-context.js';
5
4
  import { dumpErrorContext } from '../scaffold/dump-error-context.js';
5
+ import { rm } from 'fs/promises';
6
+ import { makeGasket } from '@gasket/core';
7
+ import { defaultPlugins } from '../config/default-plugins.js';
6
8
  import {
7
- applyPresetConfig,
8
- cliVersion,
9
9
  createHooks,
10
10
  generateFiles,
11
11
  globalPrompts,
12
12
  installModules,
13
13
  linkModules,
14
- loadPkgForDebug,
15
14
  loadPreset,
16
15
  mkDir,
17
16
  postCreateHooks,
18
17
  printReport,
19
18
  presetPromptHooks,
19
+ presetConfigHooks,
20
20
  promptHooks,
21
21
  setupPkg,
22
22
  writeGasketConfig,
23
23
  writePkg
24
24
  } from '../scaffold/actions/index.js';
25
- import path from 'path';
26
- import os from 'os';
27
- import { mkdtemp, rm } from 'fs/promises';
28
- import { default as gasketUtils } from '@gasket/utils';
29
- import { makeGasket } from '@gasket/core';
30
- import { createRequire } from 'module';
31
- const require = createRequire(import.meta.url);
32
25
 
33
26
  /**
34
27
  * Parses comma separated option input to array
@@ -57,13 +50,6 @@ const createCommand = {
57
50
  Or other (multiple) custom presets (e.g. --presets my-gasket-preset@1.0.0.beta-1,nextjs@^1.0.0)`,
58
51
  parse: commasToArray
59
52
  },
60
- {
61
- name: 'plugins',
62
- description: `Additional plugin(s) to install. Can be set as
63
- multiple flags (e.g. --plugins jest --plugins zkconfig@^1.0.0)
64
- comma-separated values: --plugins=jest,zkconfig^1.0.0`,
65
- parse: commasToArray
66
- },
67
53
  {
68
54
  name: 'package-manager',
69
55
  description: `Selects which package manager you would like to use during
@@ -75,18 +61,6 @@ const createCommand = {
75
61
  description: 'Require module(s) before Gasket is initialized',
76
62
  parse: commasToArray
77
63
  },
78
- {
79
- name: 'no-bootstrap',
80
- description: '(INTERNAL) If provided, skip the bootstrap phase',
81
- type: 'boolean',
82
- hidden: true
83
- },
84
- {
85
- name: 'no-generate',
86
- description: '(INTERNAL) If provided, skip the generate phase',
87
- type: 'boolean',
88
- hidden: true
89
- },
90
64
  {
91
65
  name: 'npm-link',
92
66
  description: `(INTERNAL) Local packages to be linked. Can be set as
@@ -122,312 +96,42 @@ const createCommand = {
122
96
  ]
123
97
  };
124
98
 
125
- async function wait(ms = 50) {
126
- return new Promise(resolve => {
127
- console.log('waiting...')
128
- setTimeout(resolve, ms);
129
- });
130
- }
131
-
132
- function evaluatePreset(preset) {
133
- const parts = preset.split('@').filter(Boolean);
134
- if (parts.length > 1) {
135
- return {
136
- name: `@${parts[0]}`,
137
- version: parts[1]
138
- };
139
- } else if (parts.length === 1) {
140
- return {
141
- name: `@${parts[0]}`,
142
- version: null
143
- };
144
- }
145
-
146
- return preset;
147
- }
148
-
149
99
  createCommand.action = async function run(appname, options, command) {
150
- // temp
151
- process.env.GASKET_DEBUG_NPM = 'true';
152
- // temp
153
100
  const context = makeCreateContext([appname], options);
154
- const {
155
- presets = [],
156
- presetPath = [],
157
- } = options;
158
-
159
- const tmpDir = await mkdtemp(path.join(os.tmpdir(), `gasket-create-${context.appName}`));
160
- const modPath = path.join(tmpDir, 'node_modules');
161
- console.log(tmpDir);
162
- await globalPrompts(context);
163
-
164
- const pkgManager = new gasketUtils.PackageManager({ packageManager: context.packageManager, dest: tmpDir });
165
- const pkgVerb = pkgManager.isYarn ? 'add' : 'install';
166
-
167
- const remotePresets = await Promise.all(presets.map(async preset => {
168
- await pkgManager.exec(pkgVerb, [preset]);
169
- const pkgFile = require(path.join(modPath, preset, 'package.json'));
170
- const presetMod = await import(pkgFile.name, { from: modPath });
171
-
172
- const dependencies = Object.entries(pkgFile.dependencies || {})
173
- .filter(([name]) => name.startsWith('@gasket'))
174
- .map(([name, version]) => ({ name, version }));
175
-
176
- const plugins = await Promise.all(dependencies.map(async ({ name }) => {
177
- const mod = await import(name, { from: modPath });
178
- return mod.default || mod;
179
- }));
180
-
181
- return {
182
- pkgFile,
183
- dependencies,
184
- plugins: [
185
- presetMod.default || presetMod,
186
- ...plugins
187
- ]
188
- }
189
- }));
190
-
191
- const localPresets = await Promise.all(presetPath.map(async localPreset => {
192
- await pkgManager.exec(pkgVerb, [localPreset]);
193
- const pkgFile = require(path.join(localPreset, 'package.json'));
194
- const presetMod = await import(pkgFile.name, { from: modPath });
195
-
196
- const dependencies = Object.entries(pkgFile.dependencies || {})
197
- .filter(([name]) => name.startsWith('@gasket'))
198
- .map(([name, version]) => ({ name, version }));
199
-
200
- const plugins = await Promise.all(dependencies.map(async ({ name }) => {
201
- const mod = await import(name, { from: modPath });
202
- return mod.default || mod;
203
- }));
204
-
205
- return {
206
- module: presetMod.default || presetMod,
207
- pkgFile,
208
- dependencies,
209
- plugins
210
- };
211
- }));
212
-
213
-
214
- const configuredPresets = await Promise.all([
215
- ...remotePresets,
216
- ...localPresets
217
- ]);
218
-
219
- const presetPlugins = configuredPresets.reduce((acc, p) => {
220
- return [
221
- ...acc,
222
- p.module
223
- ];
224
- }, []);
225
-
226
- const presetGasket = makeGasket({
227
- plugins: presetPlugins
228
- });
229
-
230
- console.log(presetGasket);
231
-
232
- await presetPromptHooks(presetGasket, context);
233
- console.log(context);
234
- const presetConfig = await presetGasket.execWaterfall('presetConfig', context);
235
-
236
- console.log(configuredPresets)
237
- console.log(configuredPresets[0].dependencies)
238
- console.log(configuredPresets[0].plugins)
239
- console.log(presetConfig);
240
-
241
- // Check preset plugins vs the plugins from the presetConfig
242
-
243
-
244
101
 
245
- // await globalPrompts(context);
246
- // presetPrompt
247
- // presetConfig
248
-
249
- // const gasketPlugins = makeGasket({
250
- // // plugins
251
- // })
252
-
253
- // promptHooks
254
-
255
-
256
- // applyPresetConfig(context);
257
- // await globalPrompts(context);
258
- // await mkDir(context);
259
- // await setupPkg(context);
260
- // await writePkg(context);
261
- // await installModules(context);
262
- // await linkModules(context);
263
- // await promptHooks(gasketPlugins, context);
264
- // await createHooks(context);
265
- // await generateFiles(context);
266
- // await writeGasketConfig(context);
267
- // await writePkg.update(context);
268
- // await installModules.update(context);
269
- // await linkModules.update(context); // relink any that were messed up by re-install
270
- // await postCreateHooks(context);
271
-
272
-
273
- // download preset to os temp dir
274
- // import preset to CGA
275
- // makeGasket with preset
276
- // exec presetPrompt
277
- // exec presetConfig
278
- // makeGasket with presetConfig
279
- // exec prompt
280
- // exec create
281
-
282
- // console.log('Deleting tmp dir...')
283
- // await rm(tmpDir, { recursive: true });
102
+ try {
103
+ await loadPreset(null, context);
104
+ await globalPrompts(null, context);
105
+
106
+ const presetGasket = makeGasket({
107
+ plugins: context.presets
108
+ });
109
+
110
+ await presetPromptHooks(presetGasket, context);
111
+ await presetConfigHooks(presetGasket, context);
112
+
113
+ const pluginGasket = makeGasket({
114
+ ...context.presetConfig,
115
+ plugins: context.presets.concat(context.presetConfig.plugins, defaultPlugins)
116
+ });
117
+
118
+ await promptHooks(pluginGasket, context);
119
+ await mkDir(null, context);
120
+ await setupPkg(null, context);
121
+ await createHooks(pluginGasket, context);
122
+ await writePkg(null, context);
123
+ await generateFiles(null, context);
124
+ await writeGasketConfig(null, context);
125
+ await installModules(null, context);
126
+ await linkModules(null, context);
127
+ await postCreateHooks(pluginGasket, context);
128
+ await rm(context.tmpDir, { recursive: true });
129
+ printReport(context);
130
+ } catch (err) {
131
+ console.error(chalk.red('Exiting with errors.'));
132
+ dumpErrorContext(context, err);
133
+ throw err;
134
+ }
284
135
  }
285
136
 
286
- /**
287
- * bootstrap - Bootstrap the application
288
- * @param {CreateContext} context - Create context
289
- */
290
- // async function bootstrapHandler(context) {
291
- // await loadPreset(context);
292
- // cliVersion(context);
293
- // applyPresetConfig(context);
294
- // await globalPrompts(context);
295
- // await mkDir(context);
296
- // await setupPkg(context);
297
- // await writePkg(context);
298
- // await installModules(context);
299
- // await linkModules(context);
300
- // }
301
-
302
- /**
303
- * generate - Generate the application
304
- * @param {CreateContext} context - Create context
305
- */
306
- // async function generateHandler(context) {
307
- // await promptHooks(context);
308
- // await createHooks(context);
309
- // await generateFiles(context);
310
- // await writeGasketConfig(context);
311
- // await writePkg.update(context);
312
- // await installModules.update(context);
313
- // await linkModules.update(context); // relink any that were messed up by re-install
314
- // await postCreateHooks(context);
315
- // }
316
-
317
- /**
318
- * createCommand action
319
- * @param {string} appname Required cmd arg - name of the app to create
320
- * @param {object} options cmd options
321
- * @param {Command} command - the command instance
322
- * @returns {Promise<void>} void
323
- */
324
- // createCommand.action = async function run(appname, options, command) {
325
- // const argv = [appname];
326
- // const { bootstrap = true, generate = true } = options;
327
-
328
- // let context;
329
- // try {
330
- // context = makeCreateContext(argv, options);
331
- // } catch (error) {
332
- // console.error(chalk.red(error) + '\n');
333
- // command.help();
334
- // }
335
-
336
- // try {
337
- // if (bootstrap) {
338
- // await bootstrapHandler(context);
339
- // } else {
340
- // ora('Bootstrap phase skipped.').warn();
341
- // if (generate) {
342
- // await loadPkgForDebug(context);
343
- // }
344
- // }
345
-
346
- // if (generate) {
347
- // await generateHandler(context);
348
- // } else {
349
- // ora('Generate phase skipped.').warn();
350
- // }
351
-
352
- // printReport(context);
353
-
354
- // } catch (err) {
355
- // console.error(chalk.red('Exiting with errors.'));
356
- // dumpErrorContext(context, err);
357
- // throw err;
358
- // }
359
- // };
360
-
361
137
  export { createCommand };
362
-
363
-
364
-
365
- // fire global prompts to inform pkgmanager
366
-
367
- // const tmpDir = await mkdtemp(path.join(os.tmpdir(), `gasket-create-${context.appName}`));
368
- // console.log(tmpDir);
369
-
370
-
371
-
372
- // new PackageManager https://github.com/godaddy/gasket/blob/v7/packages/gasket-utils/lib/package-manager.js#L75
373
- // const remotePresets = context.rawPresets.map(async preset => {
374
- // const { name: presetName, version: presetVersion } = evaluatePreset(preset)
375
-
376
- // // await runShellCommand('npm', ['i', `${presetName}@${presetVersion}`], { cwd: tmpDir }, true);
377
- // const modPath = path.join(tmpDir, 'node_modules');
378
- // const pkgFile = require(path.join(modPath, presetName, 'package.json'));
379
- // const presetMod = await import(presetName, { from: modPath });
380
-
381
- // const dependencies = Object.entries(pkgFile.dependencies || {})
382
- // .filter(([name]) => name.startsWith('@gasket'))
383
- // .map(([name, version]) => ({ name, version }));
384
-
385
- // const plugins = await Promise.all(dependencies.map(async ({ name }) => {
386
- // const mod = await import(name, { from: modPath });
387
- // return mod.default || mod;
388
- // }));
389
-
390
- // console.log(plugins)
391
- // return {
392
- // // module: await import(preset, { from: modPath }),
393
- // pkgFile,
394
- // dependencies,
395
- // plugins: [
396
- // presetMod.default || presetMod,
397
- // ...plugins
398
- // ]
399
- // }
400
- // });
401
-
402
- // const localPresets = context.localPresets.map(async localPreset => {
403
- // await runShellCommand('npm', ['i', localPreset], { cwd: tmpDir }, true);
404
-
405
- // const modPath = path.join(tmpDir, 'node_modules');
406
- // const pkgFile = require(path.join(localPreset, 'package.json'));
407
- // const presetMod = await import(pkgFile.name, { from: modPath });
408
-
409
-
410
- // const dependencies = Object.entries(pkgFile.dependencies || {})
411
- // .filter(([name]) => name.startsWith('@gasket'))
412
- // .map(([name, version]) => ({ name, version }));
413
-
414
- // const plugins = await Promise.all(dependencies.map(async ({ name }) => {
415
- // const mod = await import(name, { from: modPath });
416
- // return mod.default || mod;
417
- // }));
418
-
419
- // return {
420
- // // module: await import(preset, { from: modPath }),
421
- // pkgFile,
422
- // dependencies,
423
- // plugins: [
424
- // presetMod.default || presetMod,
425
- // ...plugins
426
- // ]
427
- // }
428
- // });
429
-
430
- // const presets = await Promise.all([
431
- // ...remotePresets,
432
- // ...localPresets
433
- // ]);
@@ -1,7 +1,7 @@
1
- import pluginMetadata from '@gasket/plugin-metadata';
2
1
  import pluginGit from '@gasket/plugin-git';
2
+ import pluginLogger from '@gasket/plugin-logger';
3
3
 
4
4
  export const defaultPlugins = [
5
- pluginMetadata,
5
+ pluginLogger,
6
6
  pluginGit
7
7
  ];
package/lib/index.d.ts CHANGED
@@ -62,6 +62,12 @@ export interface ConfigBuilder<Config> {
62
62
  value: Config[Key],
63
63
  options?: { force?: boolean }
64
64
  ): void;
65
+
66
+ // TODO Document
67
+ addPlugin(pluginImport: string, pluginName: string): void;
68
+ addImport(importName: string, importPath: string, isDefault?: boolean): ConfigBuilder;
69
+ useImport(configPath: string, importName: string): void;
70
+
65
71
  }
66
72
 
67
73
  export interface PackageJsonBuilder extends ConfigBuilder<PackageJson> {
@@ -10,14 +10,13 @@ import { Files } from '../files.js';
10
10
  * @param {CreateContext} context - Create context
11
11
  * @returns {Promise} promise
12
12
  */
13
- async function createHooks(context) {
13
+ async function createHooks(gasket, context) {
14
14
  const { dest, presets = [], plugins = [], warnings } = context;
15
15
 
16
16
  const files = new Files();
17
- const gasketConfig = ConfigBuilder.create({}, { orderBy: ['plugins'], warnings });
17
+ const gasketConfig = ConfigBuilder.create({}, { orderBy: ['plugins'], warnings, plugins });
18
18
  Object.assign(context, { files, gasketConfig });
19
19
 
20
- const gasket = await createEngine(plugins);
21
20
  await gasket.execApply('create', async function applyCreate(plugin, handler) {
22
21
  await handler(context.runWith(plugin));
23
22
  });
@@ -164,7 +164,7 @@ async function performGenerate(context, descriptors) {
164
164
  * @param {Spinner} spinner - Spinner
165
165
  * @returns {Promise} promise
166
166
  */
167
- async function generateFiles(context, spinner) {
167
+ async function generateFiles(gasket, context, spinner) {
168
168
  const { files } = context;
169
169
 
170
170
  if (!files.globSets.length) {
@@ -75,16 +75,17 @@ async function chooseTestPlugin(context, prompt) {
75
75
  const { presetInfos = [], plugins = [] } = context;
76
76
 
77
77
  // Flatten all plugins from presets and concat short names with cli plugins
78
- const allPlugins = flattenPresets(presetInfos)
79
- .map((presetInfo) => presetInfo.plugins || [])
80
- .reduce((acc, arr) => acc.concat(arr), [])
81
- .map((pluginInfo) => pluginIdentifier(pluginInfo.name).shortName)
82
- .concat(plugins);
78
+ // const allPlugins = flattenPresets(presetInfos)
79
+ // .map((presetInfo) => presetInfo.plugins || [])
80
+ // .reduce((acc, arr) => acc.concat(arr), [])
81
+ // .map((pluginInfo) => pluginIdentifier(pluginInfo.name).shortName)
82
+ // .concat(plugins);
83
83
 
84
- const knownTestPlugins = { mocha: '@gasket/mocha', jest: '@gasket/jest', cypress: '@gasket/cypress' };
84
+ const knownTestPlugins = { mocha: '@gasket/plugin-mocha', jest: '@gasket/plugin-jest', cypress: '@gasket/plugin-cypress' };
85
85
 
86
86
  if (!('testPlugin' in context)) {
87
- let testPlugin = Object.values(knownTestPlugins).find((p) => allPlugins.includes(p));
87
+ // let testPlugin = Object.values(knownTestPlugins).find((p) => allPlugins.includes(p));
88
+ let testPlugin;
88
89
 
89
90
  if ('testSuite' in context) {
90
91
  testPlugin = knownTestPlugins[context.testSuite];
@@ -98,16 +99,16 @@ async function chooseTestPlugin(context, prompt) {
98
99
  type: 'list',
99
100
  choices: [
100
101
  { name: 'none (not recommended)', value: 'none' },
101
- { name: 'mocha + nyc + sinon + chai', value: '@gasket/mocha' },
102
- { name: 'jest', value: '@gasket/jest' },
103
- { name: 'cypress', value: '@gasket/cypress' }
102
+ { name: 'mocha + nyc + sinon + chai', value: '@gasket/plugin-mocha' },
103
+ { name: 'jest', value: '@gasket/plugin-jest' },
104
+ { name: 'cypress', value: '@gasket/plugin-cypress' }
104
105
  ]
105
106
  }
106
107
  ]));
107
108
  }
108
109
 
109
110
  if (testPlugin && testPlugin !== 'none') {
110
- addPluginsToContext([testPlugin], context);
111
+ // addPluginsToContext([testPlugin], context);
111
112
  Object.assign(context, { testPlugin });
112
113
  }
113
114
  }
@@ -150,7 +151,7 @@ export const questions = [
150
151
  * @param {CreateContext} context - Create context
151
152
  * @returns {Promise} promise
152
153
  */
153
- async function globalPrompts(context) {
154
+ async function globalPrompts(gasket, context) {
154
155
  const prompt = context.prompts ? inquirer.prompt : () => ({});
155
156
  for (var fn of questions) {
156
157
  await fn(context, prompt);
@@ -9,6 +9,7 @@ import linkModules, { linkModulesUpdate } from './link-modules.js';
9
9
  import writeGasketConfig from './write-gasket-config.js';
10
10
  import loadPkgForDebug from './load-pkg-for-debug.js';
11
11
  import presetPromptHooks from './preset-prompt-hooks.js';
12
+ import presetConfigHooks from './preset-config-hooks.js';
12
13
  import promptHooks from './prompt-hooks.js';
13
14
  import createHooks from './create-hooks.js';
14
15
  import generateFiles from './generate-files.js';
@@ -31,6 +32,7 @@ export {
31
32
  writeGasketConfig,
32
33
  loadPkgForDebug,
33
34
  presetPromptHooks,
35
+ presetConfigHooks,
34
36
  promptHooks,
35
37
  createHooks,
36
38
  postCreateHooks,
@@ -6,7 +6,7 @@ import action from '../action-wrapper.js';
6
6
  * @param {CreateContext} context - Create context
7
7
  * @returns {Promise} promise
8
8
  */
9
- async function installModules(context) {
9
+ async function installModules(gasket, context) {
10
10
  const { pkgManager } = context;
11
11
 
12
12
  await pkgManager.install();
@@ -7,7 +7,7 @@ import action from '../action-wrapper.js';
7
7
  * @param {Spinner} spinner - Spinner
8
8
  * @returns {Promise} promise
9
9
  */
10
- async function linkModules(context, spinner) {
10
+ async function linkModules(gasket, context, spinner) {
11
11
  const { pkgLinks, pkgManager } = context;
12
12
 
13
13
  if (pkgLinks && pkgLinks.length) {
@@ -1,83 +1,36 @@
1
1
  import path from 'path';
2
+ import os from 'os';
2
3
  import action from '../action-wrapper.js';
3
- import { PackageFetcher } from '../fetcher.js';
4
- import { presetIdentifier, Loader } from '@gasket/resolve';
5
-
6
- const loader = new Loader();
7
-
8
- /**
9
- * Fetches the preset packages and loads PresetInfos
10
- *
11
- * @param {[String]} rawPresets - Presets names
12
- * @param {String} cwd - Root path
13
- * @param {Object} npmconfig - Config
14
- * @param {String} from from
15
- * @returns {PresetInfo[]} loaded presetInfos
16
- * @private
17
- */
18
- async function remotePresets(rawPresets, cwd, npmconfig, from) {
19
- if (!rawPresets) { return []; }
20
-
21
- const allRemotePresets = await Promise.all(rawPresets.map(async rawName => {
22
- const packageName = presetIdentifier(rawName).full;
23
- const fetcher = new PackageFetcher({ cwd, npmconfig, packageName });
24
- const pkgPath = await fetcher.clone();
25
-
26
- const presetInfo = await loader.loadPreset(pkgPath, { from: from, rawName }, { shallow: true });
27
- const { name: presetName, dependencies } = presetInfo.package;
28
- if (!dependencies) {
29
- return presetInfo;
30
- }
31
-
32
- const presetDeps = Object.keys(dependencies).filter(k => presetIdentifier.isValidFullName(k));
33
- const rawPresetsDeps = presetDeps.map(presetDep => `${presetDep}@${dependencies[presetDep]}`);
34
-
35
- const presetInfoDeps = await remotePresets(rawPresetsDeps, cwd, npmconfig, presetName);
36
- return {
37
- ...presetInfo,
38
- presets: presetInfoDeps
39
- };
40
- }));
41
-
42
- return allRemotePresets;
43
- }
44
-
45
- /**
46
- * Loads PresetInfo from local preset package
47
- *
48
- * @param {CreateContext} context - Create context
49
- * @returns {PresetInfo[]} loaded presetInfos
50
- * @private
51
- */
52
- function localPreset(context) {
53
- const { cwd, localPresets = [] } = context;
54
- if (!localPresets) { return []; }
55
-
56
- const presetInfos = [];
57
- localPresets.forEach(async localPresetPath => {
58
- const pkgPath = path.resolve(cwd, localPresetPath);
59
- const presetInfo = await loader.loadPreset(pkgPath, { from: 'cli' }, { shallow: false });
60
- presetInfo.rawName = `${presetInfo.package.name}@file:${pkgPath}`;
61
- presetInfos.push(presetInfo);
4
+ import { default as gasketUtils } from '@gasket/utils';
5
+ import { mkdtemp } from 'fs/promises';
6
+ import { createRequire } from 'module';
7
+ const require = createRequire(import.meta.url);
8
+
9
+ async function loadPresets(gasket, context) {
10
+ const tmpDir = await mkdtemp(path.join(os.tmpdir(), `gasket-create-${context.appName}`));
11
+ context.tmpDir = tmpDir;
12
+
13
+ const modPath = path.join(tmpDir, 'node_modules');
14
+ const pkgManager = new gasketUtils.PackageManager({ packageManager: context.packageManager, dest: tmpDir });
15
+ const pkgVerb = pkgManager.isYarn ? 'add' : 'install';
16
+
17
+ const remotePresets = context.rawPresets.map(async preset => {
18
+ const parts = /@([0-9]\.|[0-9]).+/.test(preset) && preset.split('@').filter(Boolean);
19
+ const name = parts ? `@${parts[0]}` : preset;
20
+ const version = parts ? `@${parts[1]}` : '@latest';
21
+ await pkgManager.exec(pkgVerb, [`${name}${version}`]);
22
+ const mod = await import(name, { from: modPath });
23
+ return mod.default || mod;
62
24
  });
63
25
 
64
- return presetInfos;
65
- }
66
-
67
- /**
68
- * Downloads the target preset package and adds the package.json
69
- * contents and plugins dependencies to context.
70
- *
71
- * @param {CreateContext} context - Create context
72
- * @returns {Promise} promise
73
- */
74
- async function loadPreset(context) {
75
- const { rawPresets = [], cwd, npmconfig } = context;
76
- let presetInfos = await remotePresets(rawPresets, cwd, npmconfig, 'cli');
77
- presetInfos = presetInfos.concat(localPreset(context));
26
+ const localPresets = context.localPresets.map(async localPresetPath => {
27
+ await pkgManager.exec(pkgVerb, [localPresetPath]);
28
+ const pkgFile = require(path.join(localPresetPath, 'package.json'));
29
+ const mod = await import(pkgFile.name, { from: modPath });
30
+ return mod.default || mod;
31
+ });
78
32
 
79
- const presets = presetInfos.map(p => presetIdentifier(p.rawName).shortName);
80
- Object.assign(context, { presets, presetInfos });
33
+ context.presets = await Promise.all([...remotePresets, ...localPresets]);
81
34
  }
82
35
 
83
- export default action('Load presets', loadPreset);
36
+ export default action('Load presets', loadPresets);
@@ -10,7 +10,7 @@ import action from '../action-wrapper.js';
10
10
  * @param {Spinner} spinner - Spinner
11
11
  * @returns {Promise} promise
12
12
  */
13
- async function mkDir(context, spinner) {
13
+ async function mkDir(gasket, context, spinner) {
14
14
  const { dest, relDest, extant, destOverride } = context;
15
15
 
16
16
  // At this point, either the directory does not exist, or the user has
@@ -8,7 +8,7 @@ import { runShellCommand } from '@gasket/utils';
8
8
  * @param {CreateContext} context - Create context
9
9
  * @returns {Promise} promise
10
10
  */
11
- async function postCreateHooks(context) {
11
+ async function postCreateHooks(gasket, context) {
12
12
  const { dest, presets = [], plugins = [] } = context;
13
13
 
14
14
  /**
@@ -25,8 +25,6 @@ async function postCreateHooks(context) {
25
25
  * in future is easy.
26
26
  */
27
27
  const utils = { runScript };
28
-
29
- const gasket = await createEngine(plugins);
30
28
  await gasket.exec('postCreate', context, utils);
31
29
  }
32
30
 
@@ -0,0 +1,13 @@
1
+ import action from '../action-wrapper.js';
2
+
3
+ async function presetConfigHooks(gasket, context) {
4
+ if (!context.presetConig) {
5
+ context.presetConfig = {};
6
+ }
7
+
8
+ const config = await gasket.execWaterfall('presetConfig', context);
9
+
10
+ Object.assign(context.presetConfig, config);
11
+ }
12
+
13
+ export default action('Preset Config', presetConfigHooks, { startSpinner: false });
@@ -3,7 +3,6 @@ import action from '../action-wrapper.js';
3
3
 
4
4
 
5
5
  async function presetPromptHooks(gasket, context) {
6
- console.log(context.prompts)
7
6
  const prompt = context.prompts ? inquirer.createPromptModule() : () => ({});
8
7
 
9
8
  const nextContext = await gasket.execWaterfall('presetPrompt', context, { prompt });
@@ -53,10 +53,7 @@ const createAddPlugins = context => {
53
53
  * @returns {Promise} promise
54
54
  * @private
55
55
  */
56
- async function execPluginPrompts(context, plugins = [], presets = []) {
57
- const { dest } = context;
58
- const gasket = await createEngine({ dest, presets, plugins });
59
-
56
+ async function execPluginPrompts(gasket, context, plugins = [], presets = []) {
60
57
  //
61
58
  // @see: https://github.com/SBoudrias/Inquirer.js/#inquirercreatepromptmodule---prompt-function
62
59
  //
@@ -82,8 +79,8 @@ async function promptHooks(gasket, context) {
82
79
  // Because `execPluginPrompts` is recursively, we need to start it
83
80
  // with the processPlugins and presets from our initial context
84
81
  //
85
- const { presets, plugins } = context;
86
- await execPluginPrompts(context, plugins, presets);
82
+ const { plugins } = context;
83
+ await execPluginPrompts(gasket, context, plugins);
87
84
  }
88
85
 
89
86
  export default action('Plugin prompts', promptHooks, { startSpinner: false });
@@ -10,7 +10,7 @@ import { presetIdentifier } from '@gasket/resolve';
10
10
  * @param {CreateContext} context - Create context
11
11
  * @returns {Promise} promise
12
12
  */
13
- async function setupPkg(context) {
13
+ async function setupPkg(gasket, context) {
14
14
  // console.log(context);
15
15
  // throw new Error('Not implemented');
16
16
  const { appName, appDescription, presetInfos = [], rawPlugins = [], cliVersionRequired, warnings } = context;
@@ -19,21 +19,21 @@ async function setupPkg(context) {
19
19
  name: appName,
20
20
  version: '0.0.0',
21
21
  description: appDescription,
22
- // type: 'module' // commented out for now
22
+ type: context.typescript ? 'commonjs' : 'module'
23
23
  }, { warnings });
24
24
 
25
25
  // The preset package itself must be included in the dependencies
26
26
  // of the `pkg` to be bootstrapped.
27
- pkg.add('dependencies', presetInfos.reduce((acc, presetInfo) => {
28
- // Use rawName in case version or file path was set in cli args
29
- // Otherwise fallback to resolved version
30
- const { fullName, version } = presetIdentifier(presetInfo.rawName).withVersion(`^${presetInfo.version}`);
27
+ // pkg.add('dependencies', presetInfos.reduce((acc, presetInfo) => {
28
+ // // Use rawName in case version or file path was set in cli args
29
+ // // Otherwise fallback to resolved version
30
+ // const { fullName, version } = presetIdentifier(presetInfo.rawName).withVersion(`^${presetInfo.version}`);
31
31
 
32
- acc[fullName] = version;
33
- return acc;
34
- }, {
35
- '@gasket/cli': cliVersionRequired
36
- }));
32
+ // acc[fullName] = version;
33
+ // return acc;
34
+ // }, {
35
+ // // '@gasket/cli': cliVersionRequired
36
+ // }));
37
37
 
38
38
  const pkgManager = new gasketUtils.PackageManager(context);
39
39
  const pluginIds = await getPluginsWithVersions(rawPlugins, pkgManager);
@@ -3,27 +3,81 @@ import path from 'path';
3
3
  import { writeFile } from 'fs/promises';
4
4
  import action from '../action-wrapper.js';
5
5
 
6
+ function writePluginImports(plugins) {
7
+ return plugins.reduce((acc, cur, index) => {
8
+ acc += `\t\t${cur}${index < plugins.length - 1 ? ',\n' : ''}`;
9
+ return acc;
10
+ }, '');
11
+ }
12
+
13
+ function writeImports(imports) {
14
+ if (!imports) return '';
15
+ return `${Object.entries(imports).map(([importDef, path]) => `import ${importDef} from '${path}';`).join('\n')}\n`;
16
+ }
17
+
18
+ function createInjectionAssignments(config, assignments) {
19
+ if (!assignments) return '';
20
+ Object.keys(assignments).forEach((key) => {
21
+ const keys = key.split('.');
22
+
23
+ keys.reduce((acc, cur, index) => {
24
+ if (index === keys.length - 1) {
25
+ acc[cur] = `${key}_INJECTION_ASSIGNMENT_REPLACE`;
26
+ return;
27
+ }
28
+ return acc[cur];
29
+ }, config);
30
+ });
31
+ }
32
+
33
+ function replaceInjectionAssignments(content, assignments) {
34
+ if (!assignments) return '';
35
+ Object.keys(assignments).forEach((key) => {
36
+ content = content.replace(`\'${key}_INJECTION_ASSIGNMENT_REPLACE\'`, assignments[key]);
37
+ });
38
+
39
+ return content;
40
+ }
41
+
42
+ function writeExpressions(expressions) {
43
+ if (!expressions) return '';
44
+ return `${expressions.map((expression) => `${expression}`).join('\n')}\n`;
45
+ }
46
+
47
+ function cleanupFields(config) {
48
+ delete config.fields.imports;
49
+ delete config.fields.pluginImports;
50
+ delete config.fields.expressions;
51
+ delete config.fields.injectionAssignments;
52
+ }
53
+
6
54
  /**
7
55
  * Writes the contents of `pkg` to the app's package.json.
8
56
  *
9
57
  * @param {CreateContext} context - Create context
10
58
  * @returns {Promise} promise
11
59
  */
12
- async function writeGasketConfig(context) {
13
- const { dest, gasketConfig, presets, plugins, generatedFiles } = context;
14
- const fileName = 'gasket.config.js';
60
+ async function writeGasketConfig(gasket, context) {
61
+ const { dest, gasketConfig, generatedFiles } = context;
62
+ const fileName = context.typescript ? 'gasket.ts' : 'gasket.js';
15
63
  const filePath = path.join(dest, fileName);
64
+ const plugins = gasketConfig.fields.plugins;
65
+ const assignments = gasketConfig.fields.injectionAssignments || null;
66
+ const expressions = gasketConfig.fields.expressions || null;
67
+ gasketConfig.fields.plugins = 'PLUGIN_REPLACE';
16
68
 
17
- gasketConfig.add('plugins', {
18
- presets,
19
- ...(plugins && plugins.length ? { add: plugins } : {})
20
- });
69
+ let contents = '';
70
+ contents += `import { makeGasket } from '@gasket/core';\n`;
71
+ contents += writeImports(gasketConfig.fields.pluginImports);
72
+ contents += writeImports(gasketConfig.fields.imports);
73
+ contents += writeExpressions(expressions);
74
+ createInjectionAssignments(gasketConfig.fields, assignments);
75
+ cleanupFields(gasketConfig);
21
76
 
22
- //
23
- // Use JSON5 to stringify the config and add export for CommonJS
24
- //
25
- const contents = 'module.exports = ' +
26
- JSON5.stringify(gasketConfig, null, 2) + ';\n';
77
+ const pluginImports = `[\n${writePluginImports(plugins)}\n\t]`;
78
+ contents += `\nexport default makeGasket(${JSON5.stringify(gasketConfig.fields, null, 2)});\n`;
79
+ contents = contents.replace('\'PLUGIN_REPLACE\'', pluginImports);
80
+ contents = replaceInjectionAssignments(contents, assignments);
27
81
 
28
82
  await writeFile(filePath, contents, 'utf8');
29
83
  generatedFiles.add(fileName);
@@ -9,7 +9,7 @@ import action from '../action-wrapper.js';
9
9
  * @param {Boolean} update - Is an update step
10
10
  * @returns {Promise} promise
11
11
  */
12
- async function writePkg(context) {
12
+ async function writePkg(gasket, context) {
13
13
  const { dest, pkg, generatedFiles } = context;
14
14
  const fileName = 'package.json';
15
15
  const filePath = path.join(dest, fileName);
@@ -190,19 +190,19 @@ export class ConfigBuilder {
190
190
  throw new Error(`${key} must be an object. Received ${value}`);
191
191
  }
192
192
 
193
- // if (Array.isArray(this.semverFields) && this.semverFields.includes(key)) {
194
- // if (!existing) this.fields[key] = {};
193
+ if (Array.isArray(this.semverFields) && this.semverFields.includes(key)) {
194
+ if (!existing) this.fields[key] = {};
195
195
 
196
- // this.semanticMerge({
197
- // key,
198
- // value,
199
- // existing: this.fields[key],
200
- // name,
201
- // ...options
202
- // });
196
+ this.semanticMerge({
197
+ key,
198
+ value,
199
+ existing: this.fields[key],
200
+ name,
201
+ ...options
202
+ });
203
203
 
204
- // return;
205
- // }
204
+ return;
205
+ }
206
206
 
207
207
  if (!existing) {
208
208
  this.fields[key] = Object.assign({}, value);
@@ -227,6 +227,26 @@ export class ConfigBuilder {
227
227
  }
228
228
  }
229
229
 
230
+ /** TODO document */
231
+ addPlugin(pluginImport, pluginName) {
232
+ this.add('plugins', [`${pluginImport}`]);
233
+ this.add('pluginImports', { [pluginImport]: pluginName });
234
+ }
235
+
236
+ addImport(importName, importPath) {
237
+ this.add('imports', { [importName]: importPath });
238
+ return this;
239
+ }
240
+
241
+ addExpression(expression) {
242
+ this.add('expressions', [expression.trim()]);
243
+ return this;
244
+ }
245
+
246
+ injectValue(configKey, injectedValue) {
247
+ this.add('injectionAssignments', { [configKey]: injectedValue });
248
+ }
249
+
230
250
  /**
231
251
  * Checks if a dependency has been already added
232
252
  * @param {String} key Dependency bucket
@@ -61,7 +61,7 @@ function flatten(acc, values) {
61
61
  *
62
62
  * @type {CreateContext}
63
63
  *
64
- * -- Added by command args and flags
64
+ * -- Added by command args and options
65
65
  *
66
66
  * @property {String} appName - Short name of the app
67
67
  * @property {String} cwd - Current work directory
@@ -70,7 +70,7 @@ function flatten(acc, values) {
70
70
  * @property {Boolean} extant - Whether or not target directory already exists
71
71
  * @property {[String]} localPresets - paths to the local presets packages
72
72
  * @property {PresetDesc[]} rawPresets - Raw preset desc from args. Can include version constraint. Added by load-preset if using localPresets.
73
- * @property {PluginDesc[]} rawPlugins - Raw plugin desc from flags, prompts, etc. Can include constraints.
73
+ * @property {PluginDesc[]} rawPlugins - Raw plugin desc from options, prompts, etc. Can include constraints.
74
74
  * @property {PluginName[]} plugins - Short names of plugins
75
75
  * @property {String[]} pkgLinks - Local packages that should be linked
76
76
  * @property {String} npmconfig - Path to npmconfig file
@@ -127,28 +127,25 @@ export class CreateContext {
127
127
  * Makes the initial context used through the create command flow.
128
128
  *
129
129
  * @param {String[]} argv - Commands args
130
- * @param {Object} flags - Command flags
130
+ * @param {Object} options - Command options
131
131
  * @returns {CreateContext} context
132
132
  */
133
- export function makeCreateContext(argv = [], flags = {}) {
133
+ export function makeCreateContext(argv = [], options = {}) {
134
134
  const appName = argv[0] || 'templated-app';
135
135
  const {
136
- // npmconfig,
137
- // plugins = [],
138
- // presets = [],
136
+ presets = [],
139
137
  npmLink = [],
140
- // presetPath = [],
138
+ presetPath = [],
141
139
  packageManager,
142
140
  prompts,
143
141
  config,
144
142
  configFile
145
- } = flags;
143
+ } = options;
146
144
 
147
145
  // Flatten the array of array created by the plugins flag – it
148
146
  // supports both multiple instances as well as comma-separated lists.
149
- // const rawPresets = presets.reduce(flatten, []);
150
- // const localPresets = presetPath.reduce(flatten, []);
151
- // const rawPlugins = plugins.reduce(flatten, []);
147
+ const rawPresets = presets.reduce(flatten, []);
148
+ const localPresets = presetPath.reduce(flatten, []);
152
149
  const pkgLinks = npmLink.reduce(flatten, []);
153
150
  const cwd = process.cwd();
154
151
  const dest = path.join(cwd, appName);
@@ -169,8 +166,8 @@ export function makeCreateContext(argv = [], flags = {}) {
169
166
  extant,
170
167
  // npmconfig: npmconfig && ensureAbsolute(npmconfig),
171
168
  pkgLinks,
172
- // localPresets,
173
- // rawPresets,
169
+ localPresets,
170
+ rawPresets,
174
171
  messages: [],
175
172
  warnings: [],
176
173
  errors: [],
@@ -188,8 +185,6 @@ export function makeCreateContext(argv = [], flags = {}) {
188
185
  context.appName = appName;
189
186
  }
190
187
 
191
- // addPluginsToContext(rawPlugins, context);
192
-
193
188
  return context;
194
189
  };
195
190
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-gasket-app",
3
- "version": "7.0.0-next.3",
3
+ "version": "7.0.0-next.4",
4
4
  "description": "starter pack for creating a gasket app",
5
5
  "main": "lib",
6
6
  "bin": {
@@ -32,14 +32,14 @@
32
32
  },
33
33
  "homepage": "https://github.com/godaddy/gasket/tree/main/packages/create-gasket-app",
34
34
  "dependencies": {
35
- "@gasket/engine": "^7.0.0-next.3",
36
- "@gasket/plugin-git": "^7.0.0-next.3",
37
- "@gasket/plugin-lifecycle": "^7.0.0-next.3",
38
- "@gasket/plugin-logger": "^7.0.0-next.3",
39
- "@gasket/plugin-metadata": "^7.0.0-next.3",
40
- "@gasket/plugin-start": "^7.0.0-next.3",
41
- "@gasket/resolve": "^7.0.0-next.3",
42
- "@gasket/utils": "^7.0.0-next.3",
35
+ "@gasket/engine": "^7.0.0-next.4",
36
+ "@gasket/plugin-git": "^7.0.0-next.4",
37
+ "@gasket/plugin-lifecycle": "^7.0.0-next.4",
38
+ "@gasket/plugin-logger": "^7.0.0-next.4",
39
+ "@gasket/plugin-metadata": "^7.0.0-next.4",
40
+ "@gasket/plugin-start": "^7.0.0-next.4",
41
+ "@gasket/resolve": "^7.0.0-next.4",
42
+ "@gasket/utils": "^7.0.0-next.4",
43
43
  "commander": "^12.0.0",
44
44
  "deepmerge": "^4.3.1",
45
45
  "handlebars": "^4.7.8",
@@ -78,5 +78,5 @@
78
78
  "eslintIgnore": [
79
79
  "test/fixtures"
80
80
  ],
81
- "gitHead": "f4849afd9241977ad5b485cdb6a8fec9c44fc402"
81
+ "gitHead": "5a76c18917da4d37c2aa2f9b9a70e2514ee81398"
82
82
  }