create-gasket-app 7.2.1 → 7.2.3

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.
@@ -4,23 +4,21 @@ import { makeCreateContext } from '../scaffold/create-context.js';
4
4
  import { dumpErrorContext } from '../scaffold/dump-error-context.js';
5
5
  import { rm } from 'fs/promises';
6
6
  import { makeGasket } from '@gasket/core';
7
- import {
8
- createHooks,
9
- generateFiles,
10
- globalPrompts,
11
- installModules,
12
- linkModules,
13
- loadPreset,
14
- mkDir,
15
- postCreateHooks,
16
- printReport,
17
- presetPromptHooks,
18
- presetConfigHooks,
19
- promptHooks,
20
- setupPkg,
21
- writeGasketConfig,
22
- writePkg
23
- } from '../scaffold/actions/index.js';
7
+ import globalPrompts from '../scaffold/actions/global-prompts.js';
8
+ import loadPreset from '../scaffold/actions/load-preset.js';
9
+ import presetPromptHooks from '../scaffold/actions/preset-prompt-hooks.js';
10
+ import presetConfigHooks from '../scaffold/actions/preset-config-hooks.js';
11
+ import promptHooks from '../scaffold/actions/prompt-hooks.js';
12
+ import mkDir from '../scaffold/actions/mkdir.js';
13
+ import setupPkg from '../scaffold/actions/setup-pkg.js';
14
+ import createHooks from '../scaffold/actions/create-hooks.js';
15
+ import writePkg from '../scaffold/actions/write-pkg.js';
16
+ import generateFiles from '../scaffold/actions/generate-files.js';
17
+ import writeGasketConfig from '../scaffold/actions/write-gasket-config.js';
18
+ import installModules from '../scaffold/actions/install-modules.js';
19
+ import linkModules from '../scaffold/actions/link-modules.js';
20
+ import postCreateHooks from '../scaffold/actions/post-create-hooks.js';
21
+ import printReport from '../scaffold/actions/print-report.js';
24
22
 
25
23
  /**
26
24
  * Parses comma separated option input to array
@@ -94,9 +92,10 @@ const createCommand = {
94
92
 
95
93
  /**
96
94
  * createCommand action
97
- * @type {import('../index').createCommandAction}
95
+ * @type {import('create-gasket-app').createCommandAction}
98
96
  */
99
97
  createCommand.action = async function run(appname, options, command) {
98
+ // eslint-disable-next-line no-process-env
100
99
  process.env.GASKET_ENV = 'create';
101
100
  const context = makeCreateContext([appname], options);
102
101
  const { rawPresets, localPresets } = context;
@@ -105,7 +104,6 @@ createCommand.action = async function run(appname, options, command) {
105
104
  await globalPrompts({ context });
106
105
 
107
106
  if (rawPresets.length || localPresets.length) {
108
-
109
107
  await loadPreset({ context });
110
108
 
111
109
  const presetGasket = makeGasket({
@@ -118,7 +116,7 @@ createCommand.action = async function run(appname, options, command) {
118
116
 
119
117
  const pluginGasket = makeGasket({
120
118
  ...context.presetConfig,
121
- plugins: context.presets.concat(context.presetConfig.plugins)
119
+ plugins: context.presetConfig.plugins.concat(context.presets)
122
120
  });
123
121
 
124
122
  await promptHooks({ gasket: pluginGasket, context });
@@ -134,6 +132,7 @@ createCommand.action = async function run(appname, options, command) {
134
132
  if (context.tmpDir) await rm(context.tmpDir, { recursive: true });
135
133
  printReport({ context });
136
134
  } catch (err) {
135
+ // eslint-disable-next-line no-console
137
136
  console.error(chalk.red('Exiting with errors.'));
138
137
  dumpErrorContext(context, err);
139
138
  throw err;
package/lib/index.d.ts CHANGED
@@ -1,7 +1,9 @@
1
- import type { GasketConfigDefinition, MaybeAsync, Plugin, GasketEngine } from '@gasket/core';
1
+ /* eslint-disable no-use-before-define */
2
+ import type { GasketConfigDefinition, MaybeAsync, Plugin, GasketEngine, CreateContext } from '@gasket/core';
2
3
  import type { PackageManager } from '@gasket/utils';
3
4
  import type { PromptModule } from 'inquirer';
4
5
  import type ora from 'ora';
6
+ import type { Command } from 'commander';
5
7
 
6
8
  export interface Dependencies {
7
9
  dependencies?: Record<string, string>;
@@ -48,14 +50,14 @@ interface CommandOption {
48
50
  export function createCommandAction(
49
51
  appname: string,
50
52
  options: CreateCommandOptions,
51
- command: Command
53
+ command: Command
52
54
  ): Promise<void>;
53
55
 
54
56
  export interface CreateCommand {
55
57
  id: string;
56
58
  description: string;
57
59
  args: CommandArgument[];
58
- action?: createGasketAction;
60
+ action?: typeof createCommandAction;
59
61
  options: CommandOption[];
60
62
  hidden?: boolean;
61
63
  default?: boolean;
@@ -100,7 +102,6 @@ export interface ConfigBuilder<Config> {
100
102
  /**
101
103
  * Performs an intelligent, domain-aware merge of the `value` for
102
104
  * the given `key` into the package.json fields associated with this instance.
103
- *
104
105
  * @param key - Field in package.json to add or extend.
105
106
  * @param value - Target value to set for key provided.
106
107
  * @param source - Plugin to blame if conflicts arise from this operation.
@@ -118,6 +119,11 @@ export interface ConfigBuilder<Config> {
118
119
  ): void;
119
120
  add(key: string, value: object, options?: object): void;
120
121
 
122
+ /** Remove a key from fields
123
+ * @param {string[]} path - Array of strings representing the path to the field to remove
124
+ */
125
+ remove(path: string[]): void;
126
+
121
127
  /**
122
128
  * addPlugin - Add plugin import to the gasket file and use the value in the plugins array
123
129
  * @param {string} pluginImport - name of the import used as a value - `import pluginImport...`
@@ -136,6 +142,44 @@ export interface ConfigBuilder<Config> {
136
142
  */
137
143
  addPlugin(pluginImport: string, pluginName: string): void;
138
144
 
145
+ /**
146
+ * addEnvironment - Add environments to the gasket file
147
+ * @param {string} key - name of the environment - `local.analyze`
148
+ * @param {object} value - configuration for the environment - `{
149
+ * dynamicPlugins: [
150
+ * '@gasket/plugin-analyze',
151
+ * ]
152
+ * }`
153
+ * @example
154
+ * environments: {
155
+ * 'local.analyze': {
156
+ * dynamicPlugins: [
157
+ * '@gasket/plugin-analyze',
158
+ * ]
159
+ * }
160
+ * },
161
+ */
162
+ addEnvironment(key:string, value: object): void;
163
+
164
+ /**
165
+ * addCommand - Add commands to the gasket file
166
+ * @param {string} key - name of the command - `docs`
167
+ * @param {object} value - configuration for the command - `{
168
+ * dynamicPlugins: [
169
+ * '@gasket/plugin-docs',
170
+ * ]
171
+ * }`
172
+ * @example
173
+ * commands: {
174
+ * 'docs': {
175
+ * dynamicPlugins: [
176
+ * '@gasket/plugin-docs',
177
+ * ]
178
+ * }
179
+ * },
180
+ */
181
+ addCommand(key:string, value: object): void;
182
+
139
183
  /**
140
184
  * addImport - Add a non-plugin import to the gasket file
141
185
  * @param {string} importName - name of the import used as a value - `import fs...`
@@ -214,9 +258,9 @@ interface Files {
214
258
  /**
215
259
  * Adds the specified `globby` compatible patterns, `globs`,
216
260
  * into the set of all sources for this set of files.
217
- * @param {Object} params - Object containing `globs` and `source`.
261
+ * @param {object} params - Object containing `globs` and `source`.
218
262
  * @param {string[]} params.globs - `globby` compatible patterns.
219
- * @param {Object} params.source - Plugin to blame if conflicts arise from this operation.
263
+ * @param {object} params.source - Plugin to blame if conflicts arise from this operation.
220
264
  */
221
265
  add(params: { globs: string[], source: object }): void;
222
266
  add(...globs: string[]): void;
@@ -275,7 +319,7 @@ interface Files {
275
319
  force?: boolean;
276
320
  }): void;
277
321
 
278
- /**
322
+ /**
279
323
  * Normalizes a potential semver range into a semver string
280
324
  * and returns the newest version
281
325
  * @param {string} r1 Semver string (potentially invalid).
@@ -287,7 +331,7 @@ interface Files {
287
331
  */
288
332
  tryGetNewerRange(r1: string, r2: string): string | undefined;
289
333
 
290
- /**
334
+ /**
291
335
  * Performs a naive attempt to take a transform a semver range
292
336
  * into a concrete version that may be used for "newness"
293
337
  * comparison.
@@ -301,9 +345,9 @@ interface Files {
301
345
  * the `orderFields` options having their keys sorted.
302
346
  * @returns {object} Ready to be serialized JavaScript object.
303
347
  */
304
- toJSON(): object;
348
+ toJSON(): object;
305
349
 
306
- /**
350
+ /**
307
351
  * Orders the given object, `obj`, applying any (optional)
308
352
  * key order specified via `orderBy`. If no `orderBy` is provided
309
353
  * keys are ordered lexographically.
@@ -384,8 +428,10 @@ declare module 'create-gasket-app' {
384
428
  /** paths to the local presets packages */
385
429
  localPresets: Array<string>;
386
430
 
387
- /** Raw preset desc from args. Can include version constraint. Added by
388
- * load-preset if using localPresets. */
431
+ /**
432
+ * Raw preset desc from args. Can include version constraint. Added by
433
+ * load-preset if using localPresets.
434
+ */
389
435
  rawPresets: Array<string>;
390
436
 
391
437
  /** Local packages that should be linked */
@@ -461,8 +507,8 @@ declare module 'create-gasket-app' {
461
507
 
462
508
  /** Use to add content to the README.md */
463
509
  readme: Readme;
464
-
465
- constructor(initContext?: Partial<T>);
510
+
511
+ constructor(initContext?: Partial<CreateContext>);
466
512
  runWith(plugin: Plugin): Proxy<CreateContext>;
467
513
  typescript?: boolean;
468
514
  }
package/lib/internal.d.ts CHANGED
@@ -1,14 +1,14 @@
1
- import { Gasket } from '@gasket/core';
2
1
  import type {
3
2
  CreateContext,
4
3
  CreatePrompt,
5
4
  ConfigBuilder,
6
5
  CreateCommand,
7
6
  CommandArgument,
8
- CommandOption
9
- } from './index';
10
- import type { GasketEngine, Plugin } from '@gasket/core';
11
- import type ora from 'ora';
7
+ CommandOption,
8
+ CreateCommandOptions
9
+ } from 'create-gasket-app';
10
+ import type { GasketEngine, Plugin, Gasket } from '@gasket/core';
11
+ import type { Ora } from 'ora';
12
12
  import type { Command, Option } from 'commander';
13
13
 
14
14
 
@@ -29,47 +29,91 @@ export function makeCreateContext(argv?: string[], options?: CreateCommandOption
29
29
 
30
30
  export function makeCreateRuntime(context: PartialCreateContext, source: Plugin): Proxy<CreateContext>;
31
31
 
32
- export function spinnerAction({ gasket, context, spinner } : {
33
- gasket?: GasketEngine;
34
- context?: CreateContext;
35
- spinner?: ora.Ora
36
- }): Promise<void>;
37
- export function withSpinnerWrapper({ gasket, context } : { gasket: GasketEngine, context: CreateContext }): Promise<void>;
32
+ /**
33
+ * Represents the execution context for a task.
34
+ */
35
+ export interface SpinnerContext {
36
+ gasket?: Gasket;
37
+ context: PartialCreateContext;
38
+ spinner: Ora;
39
+ }
40
+
41
+ /**
42
+ * Task function type that runs within a spinner wrapper.
43
+ */
44
+ export type SpinnerTask = (params: SpinnerContext) => Promise<void>;
45
+
46
+ /**
47
+ * Options for the spinner wrapper.
48
+ */
49
+ export interface SpinnerOptions {
50
+ startSpinner?: boolean;
51
+ }
52
+
53
+ /**
54
+ * Wraps a task with a spinner, handling success and failure states.
55
+ */
56
+ export function wrapWithSpinner(
57
+ label: string,
58
+ task: SpinnerTask,
59
+ options?: SpinnerOptions
60
+ ): (context: { context: SpinnerContext['context'] } & {
61
+ errors?: Error[]
62
+ }) => Promise<void>;
63
+
64
+ /**
65
+ * Wraps a task with a spinner, using both gasket and context.
66
+ */
67
+ export function withGasketSpinner(
68
+ label: string,
69
+ task: SpinnerTask,
70
+ options?: SpinnerOptions
71
+ ): (context: { gasket: any; context: SpinnerContext['context'] }) => Promise<void>;
72
+
73
+ /**
74
+ * Wraps a task with a spinner, using only context.
75
+ */
38
76
  export function withSpinner(
39
77
  label: string,
40
- fn: spinnerAction,
41
- options?: { startSpinner?: boolean }
42
- ): withSpinnerWrapper
78
+ task: SpinnerTask,
79
+ options?: SpinnerOptions
80
+ ): (context: { context: SpinnerContext['context'] }) => Promise<void>;
81
+
82
+ export function spinnerAction(params: {
83
+ gasket?: GasketEngine;
84
+ context: PartialCreateContext;
85
+ spinner?: Ora
86
+ }): Promise<void>;
87
+
88
+ export function execute(params: { gasket: Gasket, context: PartialCreateContext } & {
89
+ errors?: Error[]
90
+ }): Promise<void>;
43
91
 
44
92
  /** sacaffold/actions */
45
93
 
46
- export function createHooks({ gasket, context } : { gasket: GasketEngine; context: CreateContext }): Promise<void>;
94
+ export function createHooks(params: { gasket?: Gasket; context: PartialCreateContext }): Promise<void>;
47
95
 
48
- export function chooseAppDescription(context: CreateContext, prompt: CreatePrompt): Promise<void>;
49
- export function choosePackageManager(context: CreateContext, prompt: CreatePrompt): Promise<void>;
50
- export function chooseTestPlugins(context: CreateContext, prompt: CreatePrompt): Promise<void>;
96
+ export function chooseAppDescription(context: PartialCreateContext, prompt: CreatePrompt): Promise<void>;
97
+ export function choosePackageManager(context: PartialCreateContext, prompt: CreatePrompt): Promise<void>;
98
+ export function chooseTestPlugins(context: PartialCreateContext, prompt: CreatePrompt): Promise<void>;
51
99
  export function promptForTestPlugin(
52
- prompt: CreatePrompt,
53
- message: string,
100
+ prompt: CreatePrompt,
101
+ message: string,
54
102
  choices: { name: string; value: string; }[]
55
103
  ): Promise<string | null>;
56
- export function allowExtantOverwriting(context: CreateContext, prompt: CreatePrompt): Promise<void>;
57
- export function globalPrompts({ context } : { context: CreateContext }): Promise<void>;
58
-
59
- export function loadPresets({ context } : { context: CreateContext }): Promise<void>;
60
-
61
- export function presetPromptHooks({ gasket, context }: { gasket: GasketEngine; context: CreateContext }): Promise<void>;
104
+ export function allowExtantOverwriting(context: PartialCreateContext, prompt: CreatePrompt): Promise<void>;
105
+ export function globalPrompts(params: { context: PartialCreateContext }): Promise<void>;
106
+ export function loadPresets(params: { context: PartialCreateContext }): Promise<void>;
107
+ export function presetPromptHooks(params: { gasket?: Gasket; context: PartialCreateContext }): Promise<void>;
108
+ export function presetConfigHooks(params: { gasket?: Gasket; context: PartialCreateContext }): Promise<void>;
109
+ export function promptHooks(params: { gasket?: Gasket; context: PartialCreateContext }): Promise<void>;
110
+ export function execPluginPrompts(gasket: Gasket, context: PartialCreateContext): Promise<void>;
62
111
 
63
- export function presetConfigHooks({ gasket, context }: { gasket: GasketEngine; context: CreateContext }): Promise<void>;
112
+ export function mkDir({ context, spinner }: { context: CreateContext, spinner: Ora }): Promise<void>;
64
113
 
65
- export function promptHooks({ gasket, context }: { gasket: GasketEngine; context: CreateContext }): Promise<void>;
66
- export function execPluginPrompts(gasket: GasketEngine, context: CreateContext): Promise<void>;
114
+ export function setupPkg(params: { context: PartialCreateContext }): Promise<void>;
67
115
 
68
- export function mkDir({ context, spinner }: { context: CreateContext, spinner: ora.Ora }): Promise<void>;
69
-
70
- export function setupPkg({ context }: { context: CreateContext }): Promise<void>;
71
-
72
- export function writePkg({ context }: { context: CreateContext }): Promise<void>;
116
+ export function writePkg(params: { context: PartialCreateContext }): Promise<void>;
73
117
 
74
118
  export type Descriptior = {
75
119
  pattern: string;
@@ -80,13 +124,13 @@ export type Descriptior = {
80
124
  from: string;
81
125
  overrides?: string;
82
126
  }
83
- export function generateFiles({ context, spinner }: { context: CreateContext, spinner: ora.Ora }): Promise<void>;
127
+ export function generateFiles({ context, spinner }: { context: CreateContext, spinner: Ora }): Promise<void>;
84
128
  export function performGenerate(context: CreateContext, descriptors: Descriptior[]): boolean[];
85
129
  export function getDescriptors(context: CreateContext): Promise<Descriptior[]>;
86
- export function assembleDescriptors(dest: string, from: string, pattern: string, srcPaths: sring[]): Descriptior[];
130
+ export function assembleDescriptors(dest: string, from: string, pattern: string, srcPaths: string[]): Descriptior[];
87
131
  export function reduceDescriptors(descriptors: Descriptior[]): Descriptior[];
88
132
 
89
- export function writeGasketConfig({ context }: { context: CreateContext }): Promise<void>;
133
+ export function writeGasketConfig(params: { context: PartialCreateContext }): Promise<void>;
90
134
  export function writeImports(imports: object | null): string;
91
135
  export function writeExpressions(expressions: string[] | null): string;
92
136
  export function createInjectionAssignments(config: object, assignments: (object | null)): string;
@@ -94,14 +138,16 @@ export function cleanupFields(config: ConfigBuilder): void;
94
138
  export function writePluginImports(plugins: string[]): string;
95
139
  export function replaceInjectionAssignments(content: string, assignments: (object | null)): string;
96
140
 
97
- export function installModules({ context }: { context: CreateContext }): Promise<void>;
141
+ export function installModules(params: { context: PartialCreateContext }): Promise<void>;
98
142
 
99
- export function linkModules({context, spinner}: { context: CreateContext, spinner: ora.Ora }): Promise<void>;
143
+ export function linkModules(params: { context: CreateContext, spinner: Ora }): Promise<void>;
100
144
 
101
- export function postCreateHooks({ gasket, context }: { gasket: GasketEngine, context: CreateContext }): Promise<void>;
145
+ export function postCreateHooks(params: { gasket?: Gasket, context: PartialCreateContext }): Promise<void>;
102
146
 
103
- export function printReport({ context }: { context: CreateContext }): Promise<void>;
104
- export function buildReport(context: CreateContext): {
147
+ export function printReport(params: {
148
+ context: PartialCreateContext
149
+ }): Promise<void>;
150
+ export function buildReport(context: PartialCreateContext): {
105
151
  appName?: string;
106
152
  output?: string;
107
153
  generatedFiles?: string[];
@@ -119,15 +165,14 @@ export function isValidCommand(command: CreateCommand): boolean;
119
165
  export function processArgs(args: CommandArgument[]): [string, string?, any?][];
120
166
  export function isValidArg(arg: CommandArgument): boolean;
121
167
 
122
- interface OptionDefinition {
168
+ interface OptionDefinition {
123
169
  options: [string, string];
124
170
  conflicts: CommandOption['conflicts'];
125
171
  hidden: CommandOption['hidden'];
126
172
  required: CommandOption['required'];
127
173
  defaultValue: CommandOption['default'];
128
174
  parse: CommandOption['parse']
129
- };
175
+ }
130
176
  export function isValidOption(option: CommandOption): boolean;
131
- export function processOptions(options: CommandOption[]): OptionDefinition[]
132
-
133
- export function createOption(definition: OptionDefinition): Option
177
+ export function processOptions(options: CommandOption[]): OptionDefinition[];
178
+ export function createOption(definition: OptionDefinition): Option;
@@ -1,4 +1,4 @@
1
- import action from '../action-wrapper.js';
1
+ import { withGasketSpinner } from '../with-spinner.js';
2
2
  import { ConfigBuilder } from '../config-builder.js';
3
3
  import { Files } from '../files.js';
4
4
  import Readme from '../readme.js';
@@ -20,4 +20,4 @@ async function createHooks({ gasket, context }) {
20
20
  });
21
21
  }
22
22
 
23
- export default action('Execute create hooks', createHooks);
23
+ export default withGasketSpinner('Execute create hooks', createHooks);
@@ -7,7 +7,7 @@ import path from 'path';
7
7
  import mkdirp from 'mkdirp';
8
8
  import chalk from 'chalk';
9
9
  const { dim } = chalk;
10
- import action from '../action-wrapper.js';
10
+ import { withSpinner } from '../with-spinner.js';
11
11
  import * as syncGlob from 'glob';
12
12
  const glob = promisify(syncGlob.default);
13
13
 
@@ -168,7 +168,7 @@ async function generateFiles({ context, spinner }) {
168
168
  if (hasError) spinner.fail();
169
169
  }
170
170
 
171
- export default action('Generate app contents', generateFiles);
171
+ export default withSpinner('Generate app contents', generateFiles);
172
172
  // exported for unit testing
173
173
  export const _getDescriptors = getDescriptors;
174
174
  export const _assembleDescriptors = assembleDescriptors;
@@ -1,5 +1,5 @@
1
1
  import inquirer from 'inquirer';
2
- import action from '../action-wrapper.js';
2
+ import { withSpinner } from '../with-spinner.js';
3
3
 
4
4
  /**
5
5
  * What is your app description?
@@ -150,4 +150,4 @@ async function globalPrompts({ context }) {
150
150
  }
151
151
  }
152
152
 
153
- export default action('Global prompts', globalPrompts, { startSpinner: false });
153
+ export default withSpinner('Global prompts', globalPrompts, { startSpinner: false });
@@ -1,4 +1,4 @@
1
- import action from '../action-wrapper.js';
1
+ import { withSpinner } from '../with-spinner.js';
2
2
 
3
3
  /**
4
4
  * Installs node_modules using the selected package manager
@@ -10,4 +10,4 @@ async function installModules({ context }) {
10
10
  await pkgManager.install();
11
11
  }
12
12
 
13
- export default action('Install node modules', installModules);
13
+ export default withSpinner('Install node modules', installModules);
@@ -1,4 +1,4 @@
1
- import action from '../action-wrapper.js';
1
+ import { withSpinner } from '../with-spinner.js';
2
2
 
3
3
  /**
4
4
  * Links local packages using the selected package manager
@@ -13,4 +13,4 @@ async function linkModules({ context, spinner }) {
13
13
  }
14
14
  }
15
15
 
16
- export default action('Link node modules', linkModules, { startSpinner: false });
16
+ export default withSpinner('Link node modules', linkModules, { startSpinner: false });
@@ -1,6 +1,6 @@
1
1
  import path from 'path';
2
2
  import os from 'os';
3
- import action from '../action-wrapper.js';
3
+ import { withSpinner } from '../with-spinner.js';
4
4
  import { PackageManager } from '@gasket/utils';
5
5
  import { mkdtemp } from 'fs/promises';
6
6
  import { createRequire } from 'module';
@@ -57,4 +57,4 @@ async function loadPresets({ context }) {
57
57
  context.presets = await Promise.all([...remotePresets, ...localPresets]);
58
58
  }
59
59
 
60
- export default action('Load presets', loadPresets);
60
+ export default withSpinner('Load presets', loadPresets);
@@ -1,5 +1,5 @@
1
1
  import { mkdir } from 'fs/promises';
2
- import action from '../action-wrapper.js';
2
+ import { withSpinner } from '../with-spinner.js';
3
3
 
4
4
  /**
5
5
  * Validates this instance can execute without common blockers:
@@ -24,4 +24,4 @@ async function mkDir({ context, spinner }) {
24
24
  }
25
25
  }
26
26
 
27
- export default action('Set up directory', mkDir);
27
+ export default withSpinner('Set up directory', mkDir);
@@ -1,4 +1,4 @@
1
- import action from '../action-wrapper.js';
1
+ import { withGasketSpinner } from '../with-spinner.js';
2
2
  import { runShellCommand } from '@gasket/utils';
3
3
 
4
4
  /**
@@ -25,4 +25,4 @@ async function postCreateHooks({ gasket, context }) {
25
25
  await gasket.exec('postCreate', context, utils);
26
26
  }
27
27
 
28
- export default action('Execute postCreate hooks', postCreateHooks);
28
+ export default withGasketSpinner('Execute postCreate hooks', postCreateHooks);
@@ -1,4 +1,4 @@
1
- import action from '../action-wrapper.js';
1
+ import { withGasketSpinner } from '../with-spinner.js';
2
2
 
3
3
  /**
4
4
  * presetConfigHooks - exec `presetConfig` hook
@@ -9,4 +9,4 @@ async function presetConfigHooks({ gasket, context }) {
9
9
  Object.assign(context.presetConfig, config);
10
10
  }
11
11
 
12
- export default action('Preset Config', presetConfigHooks, { startSpinner: false });
12
+ export default withGasketSpinner('Preset Config', presetConfigHooks, { startSpinner: false });
@@ -1,5 +1,5 @@
1
1
  import inquirer from 'inquirer';
2
- import action from '../action-wrapper.js';
2
+ import { withGasketSpinner } from '../with-spinner.js';
3
3
 
4
4
  /**
5
5
  * presetPromptHooks - exec `presetPrompt` hook
@@ -13,4 +13,4 @@ async function presetPromptHooks({ gasket, context }) {
13
13
  Object.assign(context, nextContext);
14
14
  }
15
15
 
16
- export default action('Preset prompts', presetPromptHooks, { startSpinner: false });
16
+ export default withGasketSpinner('Preset prompts', presetPromptHooks, { startSpinner: false });
@@ -1,6 +1,6 @@
1
1
  import pkg from 'chalk';
2
2
  const { bold } = pkg;
3
- import action from '../action-wrapper.js';
3
+ import { withSpinner } from '../with-spinner.js';
4
4
  import { logo } from '../../utils/index.js';
5
5
 
6
6
  /**
@@ -8,6 +8,7 @@ import { logo } from '../../utils/index.js';
8
8
  * @private
9
9
  */
10
10
  const newline = () => {
11
+ // eslint-disable-next-line no-console
11
12
  console.log('');
12
13
  };
13
14
 
@@ -58,6 +59,7 @@ async function printReport({ context }) {
58
59
  const report = buildReport(context);
59
60
  const { warnings, errors } = context;
60
61
 
62
+ // eslint-disable-next-line no-console
61
63
  console.log(`✨Success!
62
64
 
63
65
  Finished with ${warnings.length} warnings and ${errors.length} errors using
@@ -66,10 +68,13 @@ Finished with ${warnings.length} warnings and ${errors.length} errors using
66
68
  Object.entries(report).forEach(([k, v]) => {
67
69
  if (!v || !v.length) return;
68
70
  newline();
71
+ // eslint-disable-next-line no-console
69
72
  console.log(`${bold(toSpaceCase(k))}`);
70
73
  if (Array.isArray(v)) {
74
+ // eslint-disable-next-line no-console
71
75
  v.map(o => console.log(` ${o}`));
72
76
  } else {
77
+ // eslint-disable-next-line no-console
73
78
  console.log(` ${v}`);
74
79
  }
75
80
  });
@@ -77,4 +82,4 @@ Finished with ${warnings.length} warnings and ${errors.length} errors using
77
82
  newline();
78
83
  }
79
84
 
80
- export default action('Print report', printReport, { startSpinner: false });
85
+ export default withSpinner('Print report', printReport, { startSpinner: false });
@@ -1,5 +1,5 @@
1
1
  import inquirer from 'inquirer';
2
- import action from '../action-wrapper.js';
2
+ import { withGasketSpinner } from '../with-spinner.js';
3
3
 
4
4
  /**
5
5
  * Initializes engine with provide preset and plugins
@@ -31,4 +31,4 @@ async function promptHooks({ gasket, context }) {
31
31
  await execPluginPrompts(gasket, context);
32
32
  }
33
33
 
34
- export default action('Plugin prompts', promptHooks, { startSpinner: false });
34
+ export default withGasketSpinner('Plugin prompts', promptHooks, { startSpinner: false });
@@ -1,4 +1,4 @@
1
- import action from '../action-wrapper.js';
1
+ import { withSpinner } from '../with-spinner.js';
2
2
  import { ConfigBuilder } from '../config-builder.js';
3
3
  import { PackageManager } from '@gasket/utils';
4
4
  import { createRequire } from 'module';
@@ -30,4 +30,4 @@ async function setupPkg({ context }) {
30
30
  Object.assign(context, { pkg, pkgManager });
31
31
  }
32
32
 
33
- export default action('Set up package.json', setupPkg, { startSpinner: false });
33
+ export default withSpinner('Set up package.json', setupPkg, { startSpinner: false });
@@ -1,7 +1,7 @@
1
1
  import { default as JSON5 } from 'json5';
2
2
  import path from 'path';
3
3
  import { writeFile } from 'fs/promises';
4
- import action from '../action-wrapper.js';
4
+ import { withSpinner } from '../with-spinner.js';
5
5
 
6
6
  /**
7
7
  * writePluginImports - Write string imports as value(s)
@@ -107,4 +107,4 @@ async function writeGasketConfig({ context }) {
107
107
  generatedFiles.add(fileName);
108
108
  }
109
109
 
110
- export default action('Write gasket config', writeGasketConfig);
110
+ export default withSpinner('Write gasket config', writeGasketConfig);
@@ -1,6 +1,6 @@
1
1
  import path from 'path';
2
2
  import { writeFile } from 'fs/promises';
3
- import action from '../action-wrapper.js';
3
+ import { withSpinner } from '../with-spinner.js';
4
4
 
5
5
  /**
6
6
  * Writes the contents of `pkg` to the app's package.json.
@@ -14,4 +14,4 @@ async function writePkg({ context }) {
14
14
  generatedFiles.add(fileName);
15
15
  }
16
16
 
17
- export default action('Write package.json', writePkg);
17
+ export default withSpinner('Write package.json', writePkg);
@@ -52,7 +52,7 @@ function isValidVersion(v) {
52
52
  /**
53
53
  * ConfigBuilder is an extensible data structure for **specifically**
54
54
  * managing `package.json` data.
55
- * @type {import('../index').ConfigBuilder}
55
+ * @type {import('create-gasket-app').ConfigBuilder}
56
56
  */
57
57
  export class ConfigBuilder {
58
58
  /**
@@ -217,6 +217,29 @@ export class ConfigBuilder {
217
217
  }
218
218
  }
219
219
 
220
+ /** Remove a key from fields
221
+ * @param {string[]} path - Array of strings representing the path to the field to remove
222
+ */
223
+ remove(path) {
224
+ if (!Array.isArray(path) || path.length === 0) {
225
+ throw new Error('Path must be a non-empty array of strings');
226
+ }
227
+
228
+ let current = this.fields;
229
+ for (let i = 0; i < path.length - 1; i++) {
230
+ if (Object.prototype.hasOwnProperty.call(current, path[i])) {
231
+ current = current[path[i]];
232
+ } else {
233
+ return; // Path does not exist
234
+ }
235
+ }
236
+
237
+ const key = path[path.length - 1];
238
+ if (Object.prototype.hasOwnProperty.call(current, key)) {
239
+ delete current[key];
240
+ }
241
+ }
242
+
220
243
  /**
221
244
  * addPlugin - Add plugin import to the gasket file and use the value in the plugins array
222
245
  * @param {string} pluginImport - name of the import used as a value - `import pluginImport...`
@@ -238,6 +261,52 @@ export class ConfigBuilder {
238
261
  this.add('pluginImports', { [pluginImport]: pluginName });
239
262
  }
240
263
 
264
+ /**
265
+ * addEnvironment - Add environments to the gasket file
266
+ * @param {string} key - name of the environment - `local.analyze`
267
+ * @param {object} value - configuration for the environment - `{
268
+ * dynamicPlugins: [
269
+ * '@gasket/plugin-analyze',
270
+ * ]
271
+ * }`
272
+ * @example
273
+ * environments: {
274
+ * 'local.analyze': {
275
+ * dynamicPlugins: [
276
+ * '@gasket/plugin-analyze',
277
+ * ]
278
+ * }
279
+ * },
280
+ */
281
+ addEnvironment(key, value) {
282
+ this.add('environments', {
283
+ [key]: value
284
+ });
285
+ }
286
+
287
+ /**
288
+ * addCommand - Add commands to the gasket file
289
+ * @param {string} key - name of the command - `docs`
290
+ * @param {object} value - configuration for the command - `{
291
+ * dynamicPlugins: [
292
+ * '@gasket/plugin-docs',
293
+ * ]
294
+ * }`
295
+ * @example
296
+ * commands: {
297
+ * 'docs': {
298
+ * dynamicPlugins: [
299
+ * '@gasket/plugin-docs',
300
+ * ]
301
+ * }
302
+ * },
303
+ */
304
+ addCommand(key, value) {
305
+ this.add('commands', {
306
+ [key]: value
307
+ });
308
+ }
309
+
241
310
  /**
242
311
  * addImport - Add a non-plugin import to the gasket file
243
312
  * @param {string} importName - name of the import used as a value - `import fs...`
@@ -31,6 +31,9 @@ function makeCreateRuntime(context, source) {
31
31
 
32
32
  has(key, value) {
33
33
  return context.pkg.has(key, value);
34
+ },
35
+ remove(path) {
36
+ context.pkg.remove(path);
34
37
  }
35
38
  }
36
39
  };
@@ -90,7 +93,7 @@ export function makeCreateContext(argv = [], options = {}) {
90
93
  /**
91
94
  * Input context which will be appended by prompts and passed to create hooks
92
95
  * @type {import('../internal').PartialCreateContext}
93
- */
96
+ */
94
97
  const context = new CreateContext({
95
98
  destOverride: true,
96
99
  cwd,
@@ -1,13 +1,13 @@
1
1
  /**
2
2
  * Utility for plugins to add files and templates for generating
3
- * @type {import('../index').Files}
3
+ * @type {import('create-gasket-app').Files}
4
4
  */
5
5
  export class Files {
6
6
  constructor() {
7
- /**
8
- * Array of glob sets, each containing an array of globs and a source object.
9
- * @type {Array<{globs: string[], source: object}>}
10
- */
7
+ /**
8
+ * Array of glob sets, each containing an array of globs and a source object.
9
+ * @type {Array<{globs: string[], source: object}>}
10
+ */
11
11
  this.globSets = [];
12
12
  }
13
13
 
@@ -1,6 +1,6 @@
1
1
  import { readFile } from 'fs/promises';
2
2
 
3
- /** @type {import('../index').Readme} */
3
+ /** @type {import('create-gasket-app').Readme} */
4
4
  export default class Readme {
5
5
  constructor() {
6
6
  this.markdown = [];
@@ -0,0 +1,48 @@
1
+ import ora from 'ora';
2
+
3
+ /**
4
+ * Base function to handle spinner logic
5
+ * @type {import('../internal').wrapWithSpinner}
6
+ */
7
+ function wrapWithSpinner(label, task, { startSpinner = true } = {}) {
8
+ /** @type {import('../internal').execute} */
9
+ async function execute(context) {
10
+ const spinner = ora(label);
11
+ if (startSpinner) spinner.start();
12
+
13
+ try {
14
+ await task({ ...context, spinner });
15
+ if (spinner.isSpinning) spinner.succeed();
16
+ } catch (error) {
17
+ spinner.fail();
18
+ context.errors = context.errors || [];
19
+ context.errors.push(error.stack);
20
+ throw error;
21
+ }
22
+ }
23
+
24
+ execute.wrapped = task;
25
+ return execute;
26
+ }
27
+
28
+ /**
29
+ * Wrap a task with a spinner, including gasket and context.
30
+ * @type {import('../internal').withGasketSpinner}
31
+ */
32
+ export function withGasketSpinner(label, task, options) {
33
+ return wrapWithSpinner(label, ({ gasket, context, spinner }) =>
34
+ task({ gasket, context, spinner }),
35
+ options
36
+ );
37
+ }
38
+
39
+ /**
40
+ * Wrap a task with a spinner, using only context.
41
+ * @type {import('../internal').withSpinner}
42
+ */
43
+ export function withSpinner(label, task, options) {
44
+ return wrapWithSpinner(label, ({ context, spinner }) =>
45
+ task({ context, spinner }),
46
+ options
47
+ );
48
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-gasket-app",
3
- "version": "7.2.1",
3
+ "version": "7.2.3",
4
4
  "description": "starter pack for creating a gasket app",
5
5
  "type": "module",
6
6
  "bin": {
@@ -35,16 +35,16 @@
35
35
  },
36
36
  "homepage": "https://github.com/godaddy/gasket/tree/main/packages/create-gasket-app",
37
37
  "dependencies": {
38
- "@gasket/core": "^7.2.1",
39
- "@gasket/plugin-command": "^7.2.1",
40
- "@gasket/plugin-docs": "^7.2.1",
41
- "@gasket/plugin-docusaurus": "^7.2.1",
42
- "@gasket/plugin-dynamic-plugins": "^7.2.1",
43
- "@gasket/plugin-git": "^7.2.1",
44
- "@gasket/plugin-logger": "^7.2.1",
45
- "@gasket/plugin-metadata": "^7.2.1",
46
- "@gasket/request": "^7.2.0",
47
- "@gasket/utils": "^7.2.1",
38
+ "@gasket/core": "^7.2.3",
39
+ "@gasket/plugin-command": "^7.2.3",
40
+ "@gasket/plugin-docs": "^7.2.3",
41
+ "@gasket/plugin-docusaurus": "^7.2.3",
42
+ "@gasket/plugin-dynamic-plugins": "^7.2.3",
43
+ "@gasket/plugin-git": "^7.2.3",
44
+ "@gasket/plugin-logger": "^7.2.3",
45
+ "@gasket/plugin-metadata": "^7.2.3",
46
+ "@gasket/request": "^7.2.3",
47
+ "@gasket/utils": "^7.2.3",
48
48
  "commander": "^12.0.0",
49
49
  "deepmerge": "^4.3.1",
50
50
  "diagnostics": "^2.0.2",
@@ -63,8 +63,8 @@
63
63
  "dotenv": "^16.4.5",
64
64
  "eslint": "^8.56.0",
65
65
  "eslint-config-godaddy": "^7.1.1",
66
+ "eslint-config-godaddy-typescript": "^4.0.3",
66
67
  "eslint-plugin-jest": "^28.6.0",
67
- "eslint-plugin-json": "^3.1.0",
68
68
  "eslint-plugin-unicorn": "^55.0.0",
69
69
  "jest": "^29.7.0",
70
70
  "typescript": "^5.4.5"
@@ -81,7 +81,20 @@
81
81
  ],
82
82
  "rules": {
83
83
  "unicorn/filename-case": "error"
84
- }
84
+ },
85
+ "overrides": [
86
+ {
87
+ "files": [
88
+ "lib/*.ts"
89
+ ],
90
+ "extends": [
91
+ "godaddy-typescript"
92
+ ],
93
+ "rules": {
94
+ "jsdoc/*": "off"
95
+ }
96
+ }
97
+ ]
85
98
  },
86
99
  "eslintIgnore": [
87
100
  "test/fixtures"
@@ -89,5 +102,5 @@
89
102
  "jest": {
90
103
  "transform": {}
91
104
  },
92
- "gitHead": "8af41663d838cb00344ffbdabf64fc535b78dd3d"
105
+ "gitHead": "3fb21dbc6f75b8b9619a1e70073a504f84a29943"
93
106
  }
@@ -1,29 +0,0 @@
1
- import ora from 'ora';
2
-
3
- /**
4
- * Decorate a create action with spinner.
5
- * If an action throws, a fail spinner will render for the step, regardless of
6
- * if the spinner was started or not.
7
- * @type {import('../internal').withSpinner}
8
- */
9
- export default function withSpinner(label, fn, { startSpinner = true } = {}) {
10
- /**
11
- * Decorated function
12
- * @type {import('../internal').withSpinnerWrapper}
13
- */
14
- async function wrapper({ gasket = {}, context }) {
15
- const spinner = ora(label);
16
- if (startSpinner) spinner.start();
17
- try {
18
- await fn({ gasket, context, spinner });
19
- if (spinner.isSpinning) spinner.succeed();
20
- } catch (err) {
21
- spinner.fail();
22
- context.errors.push(err.stack);
23
- throw err;
24
- }
25
- }
26
-
27
- wrapper.wrapped = fn;
28
- return wrapper;
29
- }
@@ -1,33 +0,0 @@
1
- import mkDir from './mkdir.js';
2
- import loadPreset from './load-preset.js';
3
- import globalPrompts from './global-prompts.js';
4
- import setupPkg from './setup-pkg.js';
5
- import writePkg from './write-pkg.js';
6
- import installModules from './install-modules.js';
7
- import linkModules from './link-modules.js';
8
- import writeGasketConfig from './write-gasket-config.js';
9
- import presetPromptHooks from './preset-prompt-hooks.js';
10
- import presetConfigHooks from './preset-config-hooks.js';
11
- import promptHooks from './prompt-hooks.js';
12
- import createHooks from './create-hooks.js';
13
- import generateFiles from './generate-files.js';
14
- import postCreateHooks from './post-create-hooks.js';
15
- import printReport from './print-report.js';
16
-
17
- export {
18
- mkDir,
19
- loadPreset,
20
- globalPrompts,
21
- setupPkg,
22
- writePkg,
23
- installModules,
24
- linkModules,
25
- writeGasketConfig,
26
- presetPromptHooks,
27
- presetConfigHooks,
28
- promptHooks,
29
- createHooks,
30
- postCreateHooks,
31
- generateFiles,
32
- printReport
33
- };