create-gasket-app 7.0.0-next.8 → 7.0.0

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # create-gasket-app
2
2
 
3
- Starter Pack for creating Gasket apps.
3
+ Starter Pack for creating Gasket apps.
4
4
 
5
5
  ### Get Started Immediately
6
6
 
@@ -43,9 +43,6 @@ Options:
43
43
  -p, --presets [presets] Initial Gasket preset(s) to use.
44
44
  Can be set as short name with version (e.g. --presets nextjs@^1.0.0)
45
45
  Or other (multiple) custom presets (e.g. --presets my-gasket-preset@1.0.0.beta-1,nextjs@^1.0.0)
46
- --plugins [plugins] Additional plugin(s) to install. Can be set as
47
- multiple flags (e.g. --plugins jest --plugins zkconfig@^1.0.0)
48
- comma-separated values: --plugins=jest,zkconfig^1.0.0
49
46
  --package-manager [package-manager] Selects which package manager you would like to use during
50
47
  installation. (e.g. --package-manager yarn)
51
48
  -r, --require [require] Require module(s) before Gasket is initialized
@@ -100,38 +97,36 @@ The `prompt` lifecycle is fired using [execWaterfall] and hooks should return a
100
97
  modified `context` object.
101
98
 
102
99
  ```js
103
- module.exports = {
104
- id: 'gasket-plugin-pizza',
105
- hooks: {
106
- async prompt(gasket, context, { prompt, addPlugins }) {
107
- const answers = await prompt([
108
- {
109
- name: 'pizzaSize',
110
- message: 'Choose a pizza size:',
111
- type: 'list',
112
- choices: ['small', 'medium', 'large']
113
- },
114
- {
115
- name: 'pizzaSauce',
116
- message: 'Choose a pizza sauce:',
117
- type: 'list',
118
- choices: ['red', 'white']
119
- },
120
- {
121
- name: 'wantSoda',
122
- message: 'Do you want a soda?',
123
- type: 'confirm'
124
- }
125
- ]);
126
-
127
- if (answers.wantSoda === true) {
128
- await addPlugins('gasket-plugin-soda@^2.0.0')
100
+ // gasket-plugin-pizza.js
101
+
102
+ const name = 'gasket-plugin-pizza';
103
+ const hooks = {
104
+ async prompt(gasket, context, { prompt }) {
105
+ const answers = await prompt([
106
+ {
107
+ name: 'pizzaSize',
108
+ message: 'Choose a pizza size:',
109
+ type: 'list',
110
+ choices: ['small', 'medium', 'large']
111
+ },
112
+ {
113
+ name: 'pizzaSauce',
114
+ message: 'Choose a pizza sauce:',
115
+ type: 'list',
116
+ choices: ['red', 'white']
117
+ },
118
+ {
119
+ name: 'wantSoda',
120
+ message: 'Do you want a soda?',
121
+ type: 'confirm'
129
122
  }
123
+ ]);
130
124
 
131
- return { ...context, ...answers };
132
- }
125
+ return { ...context, ...answers };
133
126
  }
134
127
  };
128
+
129
+ export default { name, hooks };
135
130
  ```
136
131
 
137
132
  The hook is passed the following parameters:
@@ -156,29 +151,31 @@ package.json or register files and templates to be generated.
156
151
  The `create` lifecycle is fired using [exec].
157
152
 
158
153
  ```js
159
- const path = require('path');
154
+ // gasket-plugin-pizza.js
160
155
 
161
- module.exports = {
162
- id: 'gasket-plugin-pizza',
163
- hooks: {
164
- async create(gasket, context) {
165
- const { pkg, files } = context; // utils from context
166
- const { pizzaSize, pizzaSauce } = context; // data provided by prompt
156
+ import path from 'path';
167
157
 
168
- files.add(
169
- path.join(__dirname, 'generator', 'ingredients', pizzaSauce)
170
- );
158
+ const name = 'gasket-plugin-pizza';
159
+ const hooks = {
160
+ async create(gasket, context) {
161
+ const { pkg, files } = context; // utils from context
162
+ const { pizzaSize, pizzaSauce } = context; // data provided by prompt
171
163
 
172
- pkg.add('devDependencies', {
173
- 'pizza-oven': '^1.0.0'
174
- });
164
+ files.add(
165
+ path.join(__dirname, 'generator', 'ingredients', pizzaSauce)
166
+ );
175
167
 
176
- pkg.add('scripts', {
177
- bake: `pizza-oven --size ${ pizzaSize }`
178
- });
179
- }
168
+ pkg.add('devDependencies', {
169
+ 'pizza-oven': '^1.0.0'
170
+ });
171
+
172
+ pkg.add('scripts', {
173
+ bake: `pizza-oven --size ${ pizzaSize }`
174
+ });
180
175
  }
181
176
  };
177
+
178
+ export default { name, hooks };
182
179
  ```
183
180
 
184
181
  The hook is passed the following parameters:
@@ -189,7 +186,7 @@ The hook is passed the following parameters:
189
186
  | `context` | The CreateContext with data from flags, prompts, etc |
190
187
  | `context.pkg` | Commonly used in create to add to package.json |
191
188
  | `context.file` | Commonly used to add files and templates for the app |
192
- | `context.gasketConfig` | Used to add config to the generated gasket.config.js |
189
+ | `context.gasketConfig` | Used to add config to the generated gasket.js |
193
190
  | `context.messages` | non-error/warning messages to report |
194
191
  | `context.warnings` | warnings messages to report |
195
192
  | `context.errors` | error messages to report but do not exit process |
@@ -206,9 +203,10 @@ generated. This is useful to use in conjunction with any scripts added in the
206
203
  The `postCreate` lifecycle is fired by [exec]:
207
204
 
208
205
  ```js
209
- module.exports = {
210
- id: 'totally-a-good-idea',
211
- hooks: {
206
+ // totally-a-good-idea.js
207
+
208
+ const name = 'totally-a-good-idea';
209
+ const hooks = {
212
210
  async create(gasket, context) {
213
211
  const { pkg } = context;
214
212
 
@@ -221,6 +219,8 @@ module.exports = {
221
219
  }
222
220
  }
223
221
  };
222
+
223
+ export default { name, hooks };
224
224
  ```
225
225
 
226
226
  The hook is passed the following parameters:
@@ -103,21 +103,23 @@ const createCommand = {
103
103
  * @returns {Promise<void>} void
104
104
  */
105
105
  createCommand.action = async function run(appname, options, command) {
106
+ process.env.GASKET_ENV = 'create';
106
107
  const context = makeCreateContext([appname], options);
107
108
  const { rawPresets, localPresets } = context;
108
109
 
109
110
  try {
110
- await globalPrompts(null, context);
111
+ await globalPrompts({ context });
111
112
 
112
113
  if (rawPresets.length || localPresets.length) {
113
- await loadPreset(null, context);
114
+
115
+ await loadPreset({ context });
114
116
 
115
117
  const presetGasket = makeGasket({
116
118
  plugins: context.presets
117
119
  });
118
120
 
119
- await presetPromptHooks(presetGasket, context);
120
- await presetConfigHooks(presetGasket, context);
121
+ await presetPromptHooks({ gasket: presetGasket, context });
122
+ await presetConfigHooks({ gasket: presetGasket, context });
121
123
  }
122
124
 
123
125
  const pluginGasket = makeGasket({
@@ -125,18 +127,18 @@ createCommand.action = async function run(appname, options, command) {
125
127
  plugins: context.presets.concat(context.presetConfig.plugins, defaultPlugins)
126
128
  });
127
129
 
128
- await promptHooks(pluginGasket, context);
129
- await mkDir(null, context);
130
- await setupPkg(null, context);
131
- await createHooks(pluginGasket, context);
132
- await writePkg(null, context);
133
- await generateFiles(null, context);
134
- await writeGasketConfig(null, context);
135
- await installModules(null, context);
136
- await linkModules(null, context);
137
- await postCreateHooks(pluginGasket, context);
130
+ await promptHooks({ gasket: pluginGasket, context });
131
+ await mkDir({ context });
132
+ await setupPkg({ context });
133
+ await createHooks({ gasket: pluginGasket, context });
134
+ await writePkg({ context });
135
+ await generateFiles({ context });
136
+ await writeGasketConfig({ context });
137
+ await installModules({ context });
138
+ await linkModules({ context });
139
+ await postCreateHooks({ gasket: pluginGasket, context });
138
140
  if (context.tmpDir) await rm(context.tmpDir, { recursive: true });
139
- printReport(null, context);
141
+ printReport({ context });
140
142
  } catch (err) {
141
143
  console.error(chalk.red('Exiting with errors.'));
142
144
  dumpErrorContext(context, err);
@@ -1,7 +1,15 @@
1
1
  import pluginGit from '@gasket/plugin-git';
2
2
  import pluginLogger from '@gasket/plugin-logger';
3
+ import pluginMetadata from '@gasket/plugin-metadata';
4
+ import pluginCommand from '@gasket/plugin-command';
5
+ import pluginDocs from '@gasket/plugin-docs';
6
+ import pluginDocusaurus from '@gasket/plugin-docusaurus';
3
7
 
4
8
  export const defaultPlugins = [
5
9
  pluginLogger,
6
- pluginGit
10
+ pluginGit,
11
+ pluginMetadata,
12
+ pluginCommand,
13
+ pluginDocs,
14
+ pluginDocusaurus
7
15
  ];
package/lib/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
- import type { GasketConfigDefinition, MaybeAsync } from '@gasket/engine';
1
+ import type { GasketConfigDefinition, MaybeAsync, Plugin, GasketEngine } from '@gasket/core';
2
2
  import type { PackageManager } from '@gasket/utils';
3
+ import type { PromptModule } from 'inquirer';
3
4
 
4
5
  export interface Dependencies {
5
6
  dependencies?: Record<string, string>;
@@ -9,7 +10,7 @@ export interface Dependencies {
9
10
 
10
11
  export interface PackageJson extends Dependencies {
11
12
  name: string;
12
- version: string;
13
+ version?: string;
13
14
  description?: string;
14
15
  license?: string;
15
16
  repository?:
@@ -20,6 +21,7 @@ export interface PackageJson extends Dependencies {
20
21
  };
21
22
  scripts?: Record<string, string>;
22
23
  optionalDependencies?: Record<string, string>;
24
+ homepage?: string;
23
25
  }
24
26
 
25
27
  export interface ModuleInfo {
@@ -30,13 +32,16 @@ export interface ModuleInfo {
30
32
  version?: string;
31
33
  }
32
34
 
33
- export interface PresetInfo extends ModuleInfo {
34
- }
35
+ export interface PresetInfo extends ModuleInfo { }
35
36
 
36
- export interface PluginInfo extends ModuleInfo {
37
- }
37
+ export interface PluginInfo extends ModuleInfo { }
38
38
 
39
39
  export interface ConfigBuilder<Config> {
40
+ /**
41
+ * fields object
42
+ */
43
+ fields: { [key: string]: any };
44
+
40
45
  /**
41
46
  * Adds all `[key, value]` pairs in the `fields` provided.
42
47
  * @param fields - Object to merge. Can be a function that accepts the current fields and object to merge.
@@ -95,7 +100,7 @@ export interface ConfigBuilder<Config> {
95
100
  * import { readFileSync } from 'fs';
96
101
  * import fs from 'fs';
97
102
  */
98
- addImport(importName: string, importPath: string): ConfigBuilder;
103
+ addImport(importName: string, importPath: string): ConfigBuilder<Config>;
99
104
 
100
105
  /**
101
106
  * addExpression - add programmatic expression to the gasket file
@@ -110,7 +115,7 @@ export interface ConfigBuilder<Config> {
110
115
  * import fs from 'fs';
111
116
  * const file = fs.readFileSync('./file.txt');
112
117
  */
113
- addExpression(expression: string): ConfigBuilder;
118
+ addExpression(expression: string): ConfigBuilder<Config>;
114
119
 
115
120
  /**
116
121
  * injectValue - Inject a value into the gasket config object
@@ -127,120 +132,168 @@ export interface ConfigBuilder<Config> {
127
132
  * }
128
133
  * });
129
134
  */
130
- injectValue(configKey: string, injectedValue: any): void;
135
+ injectValue(configKey: string, injectedValue: string): void;
131
136
  }
132
137
 
133
138
  export interface PackageJsonBuilder extends ConfigBuilder<PackageJson> {
134
139
  /**
135
- * Checks if a dependency has been already added
136
- * @param key - Dependency bucket
137
- * @param value - Dependency to search
138
- * @returns True if the dependency exists on the bucket
140
+ * Checks if a property exists on the package.json fields.
141
+ * @param key - Field to search
142
+ * @param value - Value to search for
143
+ * @returns True if the property exists and matches the value
139
144
  */
140
- has(key: keyof Dependencies, value: string): boolean;
145
+ has(key: keyof PackageJson, value: string): boolean;
141
146
  }
142
147
 
143
148
  export interface Files {
144
- add(...args: string[]): void
149
+ add(...args: string[]): void;
150
+ }
151
+
152
+ export interface Readme {
153
+ /** Markdown content to be injected into the app readme */
154
+ markdown: string[];
155
+
156
+ /** Links to be added to the footer */
157
+ links: string[];
158
+
159
+ /** Add a markdown heading */
160
+ heading(content: string, level?: number): Readme;
161
+
162
+ /** Add a markdown sub-heading */
163
+ subHeading(content: string): Readme;
164
+
165
+ /** Add markdown content */
166
+ content(markdown: string);
167
+
168
+ /** Add a markdown list */
169
+ list(items: string[]): Readme;
170
+
171
+ /** Add a markdown link - printed in footer */
172
+ link(content: string, href: string): Readme;
173
+
174
+ /** Add a markdown code block */
175
+ codeBlock(content: string, syntax?: string): Readme;
176
+
177
+ /** Add markdown file */
178
+ markdownFile(path: string): Promise<Readme>;
145
179
  }
146
180
 
147
- export interface CreateContext {
148
- /** Short name of the app */
149
- appName: string;
181
+ export type CreatePrompt = PromptModule;
182
+
183
+ declare module 'create-gasket-app' {
184
+ export interface CreateContext {
185
+ /** Short name of the app */
186
+ appName: string;
150
187
 
151
- /** Current work directory */
152
- cwd: string;
188
+ /** Current work directory */
189
+ cwd: string;
153
190
 
154
- /** Path to the target app (Default: cwd/appName) */
155
- dest: string;
191
+ /** Path to the target app (Default: cwd/appName) */
192
+ dest: string;
156
193
 
157
- /** Relative path to the target app */
158
- relDest: string;
194
+ /** Relative path to the target app */
195
+ relDest: string;
159
196
 
160
- /** Whether or not target directory already exists */
161
- extant: boolean;
197
+ /** Whether or not target directory already exists */
198
+ extant: boolean;
162
199
 
163
- /** paths to the local presets packages */
164
- localPresets: Array<string>;
200
+ /** paths to the local presets packages */
201
+ localPresets: Array<string>;
165
202
 
166
- /** Raw preset desc from args. Can include version constraint. Added by
167
- * load-preset if using localPresets. */
168
- rawPresets: Array<string>;
203
+ /** Raw preset desc from args. Can include version constraint. Added by
204
+ * load-preset if using localPresets. */
205
+ rawPresets: Array<string>;
169
206
 
170
- /** Local packages that should be linked */
171
- pkgLinks: Array<string>;
207
+ /** Local packages that should be linked */
208
+ pkgLinks: Array<string>;
172
209
 
173
- /** non-error/warning messages to report */
174
- messages: Array<string>;
210
+ /** non-error/warning messages to report */
211
+ messages: Array<string>;
175
212
 
176
- /** warnings messages to report */
177
- warnings: Array<string>;
213
+ /** warnings messages to report */
214
+ warnings: Array<string>;
178
215
 
179
- /** error messages to report but do not exit process */
180
- errors: Array<string>;
216
+ /** error messages to report but do not exit process */
217
+ errors: Array<string>;
181
218
 
182
- /** any next steps to report for user */
183
- nextSteps: Array<string>;
219
+ /** any next steps to report for user */
220
+ nextSteps: Array<string>;
184
221
 
185
- /** any generated files to show in report */
186
- generatedFiles: Set<string>;
222
+ /** any generated files to show in report */
223
+ generatedFiles: Set<string>;
187
224
 
188
- /** Default empty array, populated by load-preset with actual imports */
189
- presets: Array<any>;
225
+ /** Default empty array, populated by load-preset with actual imports */
226
+ presets: Array<Plugin>;
190
227
 
191
- /** Default to object w/empty plugins array to be populated by `presetConfig` hook */
192
- presetConfig: GasketConfigDefinition;
228
+ /** Default to object w/empty plugins array to be populated by `presetConfig` hook */
229
+ presetConfig: GasketConfigDefinition;
193
230
 
194
- // Added by `global-prompts`
231
+ // Added by `global-prompts`
195
232
 
196
- /** Description of app */
197
- appDescription: string;
233
+ /** Description of app */
234
+ appDescription: string;
198
235
 
199
- /** Should a git repo be initialized and first commit */
200
- gitInit: boolean;
236
+ /** Should a git repo be initialized and first commit */
237
+ gitInit: boolean;
201
238
 
202
- /** Name of the plugin for unit tests */
203
- testPlugin: string;
239
+ /** Names of the plugins that add unit and integration tests */
240
+ testPlugins: Array<string>;
204
241
 
205
- /** Which package manager to use (Default: 'npm') */
206
- packageManager: string;
242
+ /** Which package manager to use (Default: 'npm') */
243
+ packageManager: string;
207
244
 
208
- /** Derived install command (Default: 'npm install') */
209
- installCmd: string;
245
+ /** Derived install command (Default: 'npm install') */
246
+ installCmd: string;
210
247
 
211
- /** Derived local run command (Default: 'npx gasket local') */
212
- localCmd: string;
248
+ /** Derived local run command (Default: 'npx gasket local') */
249
+ localCmd: string;
213
250
 
214
- /** Whether or not the user wants to override an extant directory */
215
- destOverride: boolean;
251
+ /** Whether or not the user wants to override an extant directory */
252
+ destOverride: boolean;
216
253
 
217
- // Added by `setup-pkg`
254
+ // Added by `setup-pkg`
218
255
 
219
- /** package.json builder */
220
- pkg: PackageJsonBuilder;
256
+ /** package.json builder */
257
+ pkg: PackageJsonBuilder;
221
258
 
222
- /** manager to execute npm or yarn commands */
223
- pkgManager: PackageManager;
259
+ /** manager to execute npm or yarn commands */
260
+ pkgManager: PackageManager;
224
261
 
225
- // Added by `setup-gasket-config`
262
+ // Added by `setup-gasket-config`
226
263
 
227
- /** gasket.config builder */
228
- gasketConfig: ConfigBuilder<GasketConfigDefinition>;
264
+ /** gasket.config builder */
265
+ gasketConfig: ConfigBuilder<GasketConfigDefinition>;
229
266
 
230
- // Added by `create-hooks`
267
+ // Added by `create-hooks`
231
268
 
232
- /** Use to add files and templates to generate */
233
- files: Files;
269
+ /** Use to add files and templates to generate */
270
+ files: Files;
271
+
272
+ /** Use to add content to the README.md */
273
+ readme: Readme;
274
+ }
234
275
  }
235
276
 
236
- declare module '@gasket/engine' {
277
+ export interface ActionWrapperParams {
278
+ gasket: GasketEngine;
279
+ context: CreateContext;
280
+ spinner?: any;
281
+ }
282
+
283
+ declare module '@gasket/core' {
284
+
237
285
  export interface HookExecTypes {
238
- presetPrompt(context: CreateContext): Promise<void>;
239
- presetConfig(context: CreateContext): Promise<void>;
286
+ presetPrompt(
287
+ context: CreateContext,
288
+ utils: {
289
+ prompt: CreatePrompt;
290
+ }
291
+ ): Promise<void>;
292
+ presetConfig(context: CreateContext): Promise<CreateContext['presetConfig']>;
240
293
  prompt(
241
294
  context: CreateContext,
242
295
  utils: {
243
- prompt: (prompts: Array<Record<string, any>>) => Promise<Record<string, any>>,
296
+ prompt: CreatePrompt;
244
297
  }
245
298
  ): MaybeAsync<CreateContext>;
246
299
 
@@ -249,7 +302,8 @@ declare module '@gasket/engine' {
249
302
  postCreate(
250
303
  context: CreateContext,
251
304
  utils: {
252
- runScript: (script: string) => Promise<void>
253
- }): MaybeAsync<void>;
305
+ runScript: (script: string) => Promise<void>;
306
+ }
307
+ ): MaybeAsync<void>;
254
308
  }
255
309
  }
package/lib/index.js CHANGED
@@ -2,7 +2,8 @@
2
2
  import { Command } from 'commander';
3
3
  import { createRequire } from 'module';
4
4
  import { createCommand } from './commands/create.js';
5
- import { processCommand, logo, warnIfOutdated } from './utils/index.js';
5
+ import { processCommand, logo } from './utils/index.js';
6
+ import { warnIfOutdated } from '@gasket/utils';
6
7
 
7
8
  const require = createRequire(import.meta.url);
8
9
  const pkg = require('../package.json');
@@ -14,14 +14,16 @@ export default function withSpinner(label, fn, { startSpinner = true } = {}) {
14
14
  /**
15
15
  * Decorated function
16
16
  *
17
- * @param {CreateContext} context - Create context
17
+ * @param {ActionWrapperParams} params - ActionWrapperParams
18
+ * @param {GasketEngine} params.gasket - Gasket config
19
+ * @param {CreateContext} params.context - Create context
18
20
  * @returns {Promise} promise
19
21
  */
20
- async function wrapper(gasket = {}, context) {
22
+ async function wrapper({ gasket = {}, context }) {
21
23
  const spinner = ora(label);
22
24
  if (startSpinner) spinner.start();
23
25
  try {
24
- await fn(gasket, context, spinner);
26
+ await fn({ gasket, context, spinner });
25
27
  if (spinner.isSpinning) spinner.succeed();
26
28
  } catch (err) {
27
29
  spinner.fail();
@@ -1,20 +1,23 @@
1
1
  import action from '../action-wrapper.js';
2
2
  import { ConfigBuilder } from '../config-builder.js';
3
3
  import { Files } from '../files.js';
4
+ import Readme from '../readme.js';
4
5
 
5
6
  /**
6
7
  * Executes the `create` hook for all registered plugins.
7
8
  * Adds `files` to context for plugins to add their files and templates.
8
9
  *
10
+ * @param {GasketEngine} gasket - Gasket API
9
11
  * @param {CreateContext} context - Create context
10
12
  * @returns {Promise} promise
11
13
  */
12
- async function createHooks(gasket, context) {
14
+ async function createHooks({ gasket, context }) {
13
15
  const { plugins = [], warnings } = context;
14
16
 
15
17
  const files = new Files();
18
+ const readme = new Readme();
16
19
  const gasketConfig = ConfigBuilder.create({}, { orderBy: ['plugins'], warnings, plugins });
17
- Object.assign(context, { files, gasketConfig });
20
+ Object.assign(context, { files, readme, gasketConfig });
18
21
 
19
22
  await gasket.execApply('create', async function applyCreate(plugin, handler) {
20
23
  await handler(context.runWith(plugin));
@@ -109,6 +109,10 @@ async function performGenerate(context, descriptors) {
109
109
  handlebars.registerHelper('jspretty', (data) => {
110
110
  return JSON.stringify(data).replace(/"/g, '\'');
111
111
  });
112
+ handlebars.registerHelper('eq', (a, b) => a === b);
113
+ handlebars.registerHelper('markdownCompile', (data) => {
114
+ return handlebars.compile(data)(context);
115
+ });
112
116
 
113
117
  debug('descriptors', JSON.stringify(descriptors, null, 2));
114
118
 
@@ -164,7 +168,7 @@ async function performGenerate(context, descriptors) {
164
168
  * @param {Spinner} spinner - Spinner
165
169
  * @returns {Promise} promise
166
170
  */
167
- async function generateFiles(_, context, spinner) {
171
+ async function generateFiles({ context, spinner }) {
168
172
  const { files } = context;
169
173
 
170
174
  if (!files.globSets.length) {