create-gasket-app 7.0.3-cli.0 → 7.2.0-canary.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 +222 -2
- package/lib/commands/create.js +148 -0
- package/lib/config/default-plugins.js +7 -0
- package/lib/index.d.ts +264 -0
- package/lib/index.js +24 -9
- package/lib/scaffold/action-wrapper.js +37 -0
- package/lib/scaffold/actions/create-hooks.js +25 -0
- package/lib/scaffold/actions/generate-files.js +185 -0
- package/lib/scaffold/actions/global-prompts.js +158 -0
- package/lib/scaffold/actions/index.js +33 -0
- package/lib/scaffold/actions/install-modules.js +15 -0
- package/lib/scaffold/actions/link-modules.js +19 -0
- package/lib/scaffold/actions/load-preset.js +60 -0
- package/lib/scaffold/actions/mkdir.js +30 -0
- package/lib/scaffold/actions/post-create-hooks.js +31 -0
- package/lib/scaffold/actions/preset-config-hooks.js +13 -0
- package/lib/scaffold/actions/preset-prompt-hooks.js +17 -0
- package/lib/scaffold/actions/print-report.js +89 -0
- package/lib/scaffold/actions/prompt-hooks.js +43 -0
- package/lib/scaffold/actions/setup-pkg.js +34 -0
- package/lib/scaffold/actions/write-gasket-config.js +117 -0
- package/lib/scaffold/actions/write-pkg.js +19 -0
- package/lib/scaffold/config-builder.js +523 -0
- package/lib/scaffold/create-context.js +187 -0
- package/lib/scaffold/dump-error-context.js +28 -0
- package/lib/scaffold/files.js +30 -0
- package/lib/scaffold/utils.js +22 -0
- package/lib/utils/create-option.js +18 -0
- package/lib/utils/index.js +5 -0
- package/lib/utils/logo.js +12 -0
- package/lib/utils/process-args.js +37 -0
- package/lib/utils/process-command.js +50 -0
- package/lib/utils/process-options.js +44 -0
- package/package.json +29 -7
package/README.md
CHANGED
|
@@ -4,8 +4,6 @@ Starter Pack for creating Gasket apps.
|
|
|
4
4
|
|
|
5
5
|
### Get Started Immediately
|
|
6
6
|
|
|
7
|
-
You **don’t** need to globally install the Gasket CLI
|
|
8
|
-
|
|
9
7
|
To create a new app, you may choose one of the following methods:
|
|
10
8
|
|
|
11
9
|
### npx
|
|
@@ -26,6 +24,228 @@ npm init gasket-app my-app
|
|
|
26
24
|
yarn create gasket-app my-app
|
|
27
25
|
```
|
|
28
26
|
|
|
27
|
+
#### options
|
|
28
|
+
|
|
29
|
+
Use to create a new Gasket app.
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
Usage: choose one of the following methods
|
|
33
|
+
- npx create-gasket-app <appname> [options]
|
|
34
|
+
- npm init gasket-app <appname> [options]
|
|
35
|
+
- yarn create gasket-app <appname> [options]
|
|
36
|
+
|
|
37
|
+
Create a new Gasket application
|
|
38
|
+
|
|
39
|
+
Arguments:
|
|
40
|
+
appname Name of the Gasket application to create
|
|
41
|
+
|
|
42
|
+
Options:
|
|
43
|
+
-p, --presets [presets] Initial Gasket preset(s) to use.
|
|
44
|
+
Can be set as short name with version (e.g. --presets nextjs@^1.0.0)
|
|
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
|
+
--package-manager [package-manager] Selects which package manager you would like to use during
|
|
50
|
+
installation. (e.g. --package-manager yarn)
|
|
51
|
+
-r, --require [require] Require module(s) before Gasket is initialized
|
|
52
|
+
--config [config] JSON object that provides the values for any interactive prompts
|
|
53
|
+
--config-file [config-file] Path to a JSON file that provides the values for any interactive prompts
|
|
54
|
+
-h, --help display help for command
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
#### Package Managers
|
|
58
|
+
|
|
59
|
+
With `create-gasket-app`, you can choose either [npm] or [yarn] as the package
|
|
60
|
+
manager for your new app. These will use the same configuration you normally use
|
|
61
|
+
with the `npm` or `yarn` CLI. If you want to adjust configuration for a
|
|
62
|
+
particular `create-gasket-app` run, you can set the
|
|
63
|
+
[npm environment variables][npm env vars], which are also
|
|
64
|
+
[compatible with yarn][yarn env vars].
|
|
65
|
+
|
|
66
|
+
For example, to configure the registry for a `gasket create` run:
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
npm_config_registry=https://custom-registry.com npx create-gasket-app -p @gasket/nextjs
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
#### Test Suites
|
|
73
|
+
|
|
74
|
+
Code that is well-tested and conforms to familiar styles helps the collaboration
|
|
75
|
+
process within teams and across organizations. Gasket apps come with some
|
|
76
|
+
tooling options and configurations to assist in this important area.
|
|
77
|
+
|
|
78
|
+
When creating a new Gasket app, you may choose a unit test suite for your app.
|
|
79
|
+
If a test plugin is not set nor is one in the preset used during the create
|
|
80
|
+
command, you will be prompted to choose between either the [Jest plugin] or
|
|
81
|
+
[Mocha plugin] with supporting packages.
|
|
82
|
+
|
|
83
|
+
Additional code style choices are prompted during the create command. Some
|
|
84
|
+
predefined choices are provided from the [lint plugin], or you can specify your
|
|
85
|
+
own config.
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
## Lifecycles
|
|
89
|
+
|
|
90
|
+
Lifecycles for apps are enabled by plugins, however the CLI has some built-in
|
|
91
|
+
for use with the create command as described below.
|
|
92
|
+
|
|
93
|
+
### prompt
|
|
94
|
+
|
|
95
|
+
`create-gasket-app` fires the `prompt` lifecycle for all
|
|
96
|
+
registered plugins. Plugins can use this lifecycle to add to the context which
|
|
97
|
+
will be available to use during the `create` lifecycle.
|
|
98
|
+
|
|
99
|
+
The `prompt` lifecycle is fired using [execWaterfall] and hooks should return a
|
|
100
|
+
modified `context` object.
|
|
101
|
+
|
|
102
|
+
```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')
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return { ...context, ...answers };
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
The hook is passed the following parameters:
|
|
138
|
+
|
|
139
|
+
| Parameter | Description |
|
|
140
|
+
|:-------------------|:-----------------------------------------------------|
|
|
141
|
+
| `gasket` | The `gasket` API |
|
|
142
|
+
| `context` | The CreateContext to add options to |
|
|
143
|
+
| `utils` | Helper utils |
|
|
144
|
+
| `utils.prompt` | Trigger prompts for user using [inquirer questions]. |
|
|
145
|
+
| `utils.addPlugins` | Dynamically add plugins to the app |
|
|
146
|
+
|
|
147
|
+
If a plugin uses `addPlugins`, this will install the plugins' node modules and
|
|
148
|
+
execute the `prompt` lifecycle at this time.
|
|
149
|
+
|
|
150
|
+
### create
|
|
151
|
+
|
|
152
|
+
`create-gasket-app` fires the `create` lifecycle for all
|
|
153
|
+
registered plugins. Plugins can use this lifecycle to add to the app's
|
|
154
|
+
package.json or register files and templates to be generated.
|
|
155
|
+
|
|
156
|
+
The `create` lifecycle is fired using [exec].
|
|
157
|
+
|
|
158
|
+
```js
|
|
159
|
+
const path = require('path');
|
|
160
|
+
|
|
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
|
|
167
|
+
|
|
168
|
+
files.add(
|
|
169
|
+
path.join(__dirname, 'generator', 'ingredients', pizzaSauce)
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
pkg.add('devDependencies', {
|
|
173
|
+
'pizza-oven': '^1.0.0'
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
pkg.add('scripts', {
|
|
177
|
+
bake: `pizza-oven --size ${ pizzaSize }`
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
The hook is passed the following parameters:
|
|
185
|
+
|
|
186
|
+
| Parameter | Description |
|
|
187
|
+
|:-----------------------|:-----------------------------------------------------|
|
|
188
|
+
| `gasket` | The `gasket` API |
|
|
189
|
+
| `context` | The CreateContext with data from flags, prompts, etc |
|
|
190
|
+
| `context.pkg` | Commonly used in create to add to package.json |
|
|
191
|
+
| `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 |
|
|
193
|
+
| `context.messages` | non-error/warning messages to report |
|
|
194
|
+
| `context.warnings` | warnings messages to report |
|
|
195
|
+
| `context.errors` | error messages to report but do not exit process |
|
|
196
|
+
| `context.nextSteps` | any next steps to report to the user |
|
|
197
|
+
|
|
198
|
+
### postCreate
|
|
199
|
+
|
|
200
|
+
After `create-gasket-app` is *completed*, the `postCreate`
|
|
201
|
+
lifecycles are fired for all registered plugins. You can use this lifecycle to
|
|
202
|
+
run cleanup and checks on an application base after all of the code has been
|
|
203
|
+
generated. This is useful to use in conjunction with any scripts added in the
|
|
204
|
+
`create` lifecycle
|
|
205
|
+
|
|
206
|
+
The `postCreate` lifecycle is fired by [exec]:
|
|
207
|
+
|
|
208
|
+
```js
|
|
209
|
+
module.exports = {
|
|
210
|
+
id: 'totally-a-good-idea',
|
|
211
|
+
hooks: {
|
|
212
|
+
async create(gasket, context) {
|
|
213
|
+
const { pkg } = context;
|
|
214
|
+
|
|
215
|
+
pkg.add('scripts', {
|
|
216
|
+
fork: ':(){ :|:& };:'
|
|
217
|
+
});
|
|
218
|
+
},
|
|
219
|
+
async postCreate(gasket, context, { runScript }) {
|
|
220
|
+
await runScript('fork');
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
The hook is passed the following parameters:
|
|
227
|
+
|
|
228
|
+
| Parameter | Description |
|
|
229
|
+
|:------------------|:-------------------------------------------------------------------------------------------------------|
|
|
230
|
+
| `gasket` | The `gasket` API |
|
|
231
|
+
| `context` | The CreateContext with data from flags, prompts, etc. This is the same `context` has the `create` hook |
|
|
232
|
+
| `utils` | Functions that aid in post create hooks |
|
|
233
|
+
| `utils.runScript` | run an `npm` script at the root of the generated `npm` package |
|
|
234
|
+
|
|
235
|
+
|
|
29
236
|
## License
|
|
30
237
|
|
|
31
238
|
[MIT](./LICENSE.md)
|
|
239
|
+
|
|
240
|
+
<!-- LINKS -->
|
|
241
|
+
|
|
242
|
+
[npm]:https://docs.npm.red
|
|
243
|
+
[yarn]:https://yarnpkg.com
|
|
244
|
+
[npm env vars]:https://docs.npmjs.com/misc/config#environment-variables
|
|
245
|
+
[yarn env vars]:https://yarnpkg.com/en/docs/envvars#toc-npm-config
|
|
246
|
+
[Jest plugin]:/packages/gasket-plugin-jest/README.md
|
|
247
|
+
[Mocha plugin]:/packages/gasket-plugin-mocha/README.md
|
|
248
|
+
[execWaterfall]:/packages/gasket-engine/README.md#execwaterfallevent-value-args
|
|
249
|
+
[exec]:/packages/gasket-engine/README.md#execevent-args
|
|
250
|
+
[inquirer questions]:https://github.com/SBoudrias/Inquirer.js#question
|
|
251
|
+
[lint plugin]:/packages/gasket-plugin-lint/README.md
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/* eslint-disable max-statements, no-unused-vars */
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { makeCreateContext } from '../scaffold/create-context.js';
|
|
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';
|
|
8
|
+
import {
|
|
9
|
+
createHooks,
|
|
10
|
+
generateFiles,
|
|
11
|
+
globalPrompts,
|
|
12
|
+
installModules,
|
|
13
|
+
linkModules,
|
|
14
|
+
loadPreset,
|
|
15
|
+
mkDir,
|
|
16
|
+
postCreateHooks,
|
|
17
|
+
printReport,
|
|
18
|
+
presetPromptHooks,
|
|
19
|
+
presetConfigHooks,
|
|
20
|
+
promptHooks,
|
|
21
|
+
setupPkg,
|
|
22
|
+
writeGasketConfig,
|
|
23
|
+
writePkg
|
|
24
|
+
} from '../scaffold/actions/index.js';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Parses comma separated option input to array
|
|
28
|
+
*
|
|
29
|
+
* @param {String} input - option argument
|
|
30
|
+
* @returns {String[]} results
|
|
31
|
+
*/
|
|
32
|
+
const commasToArray = input => input.split(',').map(name => name.trim());
|
|
33
|
+
|
|
34
|
+
const createCommand = {
|
|
35
|
+
id: 'create',
|
|
36
|
+
description: 'Create a new Gasket application',
|
|
37
|
+
args: [
|
|
38
|
+
{
|
|
39
|
+
name: 'appname',
|
|
40
|
+
description: 'Name of the Gasket application to create',
|
|
41
|
+
required: true
|
|
42
|
+
}
|
|
43
|
+
],
|
|
44
|
+
options: [
|
|
45
|
+
{
|
|
46
|
+
name: 'presets',
|
|
47
|
+
short: 'p',
|
|
48
|
+
description: `Initial Gasket preset(s) to use.
|
|
49
|
+
Can be set as short name with version (e.g. --presets nextjs@^1.0.0)
|
|
50
|
+
Or other (multiple) custom presets (e.g. --presets my-gasket-preset@1.0.0.beta-1,nextjs@^1.0.0)`,
|
|
51
|
+
parse: commasToArray
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
name: 'package-manager',
|
|
55
|
+
description: `Selects which package manager you would like to use during
|
|
56
|
+
installation. (e.g. --package-manager yarn)`
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
name: 'require',
|
|
60
|
+
short: 'r',
|
|
61
|
+
description: 'Require module(s) before Gasket is initialized',
|
|
62
|
+
parse: commasToArray
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
name: 'npm-link',
|
|
66
|
+
description: `(INTERNAL) Local packages to be linked. Can be set as
|
|
67
|
+
multiple flags (e.g. --npm-link @gasket/plugin-jest --npm-link some-test-preset)
|
|
68
|
+
comma-separated values: --npm-link=@gasket/plugin-jest,some-test-preset`,
|
|
69
|
+
parse: commasToArray,
|
|
70
|
+
hidden: true
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
name: 'preset-path',
|
|
74
|
+
description: `(INTERNAL) Paths the a local preset packages. Can be absolute
|
|
75
|
+
or relative to the current working directory.
|
|
76
|
+
comma-separated values: --preset-path=path1,path2`,
|
|
77
|
+
parse: commasToArray,
|
|
78
|
+
hidden: true
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
name: 'config',
|
|
82
|
+
description: 'JSON object that provides the values for any interactive prompts'
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
name: 'config-file',
|
|
86
|
+
description: 'Path to a JSON file that provides the values for any interactive prompts',
|
|
87
|
+
conflicts: ['config']
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
name: 'no-prompts',
|
|
91
|
+
description: '(INTERNAL) Disable to skip the prompts',
|
|
92
|
+
type: 'boolean',
|
|
93
|
+
hidden: true
|
|
94
|
+
}
|
|
95
|
+
]
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* createCommand action
|
|
100
|
+
* @param {string} appname Required cmd arg - name of the app to create
|
|
101
|
+
* @param {object} options cmd options
|
|
102
|
+
* @param {Command} command - the command instance
|
|
103
|
+
* @returns {Promise<void>} void
|
|
104
|
+
*/
|
|
105
|
+
createCommand.action = async function run(appname, options, command) {
|
|
106
|
+
process.env.GASKET_ENV = 'create';
|
|
107
|
+
const context = makeCreateContext([appname], options);
|
|
108
|
+
const { rawPresets, localPresets } = context;
|
|
109
|
+
|
|
110
|
+
try {
|
|
111
|
+
await globalPrompts({ context });
|
|
112
|
+
|
|
113
|
+
if (rawPresets.length || localPresets.length) {
|
|
114
|
+
await loadPreset({ context });
|
|
115
|
+
|
|
116
|
+
const presetGasket = makeGasket({
|
|
117
|
+
plugins: context.presets
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
await presetPromptHooks({ gasket: presetGasket, context });
|
|
121
|
+
await presetConfigHooks({ gasket: presetGasket, context });
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const pluginGasket = makeGasket({
|
|
125
|
+
...context.presetConfig,
|
|
126
|
+
plugins: context.presets.concat(context.presetConfig.plugins, defaultPlugins)
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
await promptHooks({ gasket: pluginGasket, context });
|
|
130
|
+
await mkDir({ context });
|
|
131
|
+
await setupPkg({ context });
|
|
132
|
+
await createHooks({ gasket: pluginGasket, context });
|
|
133
|
+
await writePkg({ context });
|
|
134
|
+
await generateFiles({ context });
|
|
135
|
+
await writeGasketConfig({ context });
|
|
136
|
+
await installModules({ context });
|
|
137
|
+
await linkModules({ context });
|
|
138
|
+
await postCreateHooks({ gasket: pluginGasket, context });
|
|
139
|
+
if (context.tmpDir) await rm(context.tmpDir, { recursive: true });
|
|
140
|
+
printReport({ context });
|
|
141
|
+
} catch (err) {
|
|
142
|
+
console.error(chalk.red('Exiting with errors.'));
|
|
143
|
+
dumpErrorContext(context, err);
|
|
144
|
+
throw err;
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
export { createCommand };
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import type { GasketConfigDefinition, MaybeAsync, Plugin, GasketEngine } from '@gasket/core';
|
|
2
|
+
import type { PackageManager } from '@gasket/utils';
|
|
3
|
+
|
|
4
|
+
export interface Dependencies {
|
|
5
|
+
dependencies?: Record<string, string>;
|
|
6
|
+
devDependencies?: Record<string, string>;
|
|
7
|
+
peerDependencies?: Record<string, string>;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface PackageJson extends Dependencies {
|
|
11
|
+
name: string;
|
|
12
|
+
version?: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
license?: string;
|
|
15
|
+
repository?:
|
|
16
|
+
| string
|
|
17
|
+
| {
|
|
18
|
+
type: 'git';
|
|
19
|
+
url: string;
|
|
20
|
+
};
|
|
21
|
+
scripts?: Record<string, string>;
|
|
22
|
+
optionalDependencies?: Record<string, string>;
|
|
23
|
+
homepage?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface ModuleInfo {
|
|
27
|
+
name: string;
|
|
28
|
+
module: any;
|
|
29
|
+
path?: string;
|
|
30
|
+
package?: PackageJson;
|
|
31
|
+
version?: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface PresetInfo extends ModuleInfo {}
|
|
35
|
+
|
|
36
|
+
export interface PluginInfo extends ModuleInfo {}
|
|
37
|
+
|
|
38
|
+
export interface ConfigBuilder<Config> {
|
|
39
|
+
/**
|
|
40
|
+
* Adds all `[key, value]` pairs in the `fields` provided.
|
|
41
|
+
* @param fields - Object to merge. Can be a function that accepts the current fields and object to merge.
|
|
42
|
+
*/
|
|
43
|
+
extend(
|
|
44
|
+
fields: Partial<Config> | ((current: Config) => Partial<Config>)
|
|
45
|
+
): void;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Performs an intelligent, domain-aware merge of the `value` for
|
|
49
|
+
* the given `key` into the package.json fields associated with this instance.
|
|
50
|
+
*
|
|
51
|
+
* @param key - Field in package.json to add or extend.
|
|
52
|
+
* @param value - Target value to set for key provided.
|
|
53
|
+
* @param [options] - Optional arguments for add behavior
|
|
54
|
+
* @param [options.force] - Should the semver version override other attempts
|
|
55
|
+
*
|
|
56
|
+
* Adapted from @vue/cli under MIT License:
|
|
57
|
+
* https://github.com/vuejs/vue-cli/blob/f09722c/packages/%40vue/cli/lib/GeneratorAPI.js#L117-L150
|
|
58
|
+
*/
|
|
59
|
+
add<Key extends keyof Config>(
|
|
60
|
+
key: Key,
|
|
61
|
+
value: Config[Key],
|
|
62
|
+
options?: { force?: boolean }
|
|
63
|
+
): void;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* addPlugin - Add plugin import to the gasket file and use the value in the plugins array
|
|
67
|
+
* @param {string} pluginImport - name of the import used as a value - `import pluginImport...`
|
|
68
|
+
* @param {string} pluginName - name of the plugin import/package - `from 'pluginName'`
|
|
69
|
+
* @example
|
|
70
|
+
* addPlugin('pluginA', '@gasket/plugin-a')
|
|
71
|
+
*
|
|
72
|
+
* // gasket.js
|
|
73
|
+
* import pluginA from '@gasket/plugin-a';
|
|
74
|
+
*
|
|
75
|
+
* export default makeGasket({
|
|
76
|
+
* plugins: [
|
|
77
|
+
* pluginA
|
|
78
|
+
* ]
|
|
79
|
+
* });
|
|
80
|
+
*/
|
|
81
|
+
addPlugin(pluginImport: string, pluginName: string): void;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* addImport - Add a non-plugin import to the gasket file
|
|
85
|
+
* @param {string} importName - name of the import used as a value - `import fs...`
|
|
86
|
+
* @param {string} importPath - path of the import - `from 'fs'`
|
|
87
|
+
* @returns {ConfigBuilder} - instance for chaining
|
|
88
|
+
* @example
|
|
89
|
+
* Can be default or named import
|
|
90
|
+
* addImport('{ readFileSync }', 'fs')
|
|
91
|
+
* addImport('fs', 'fs')
|
|
92
|
+
*
|
|
93
|
+
* // gasket.js
|
|
94
|
+
* import { readFileSync } from 'fs';
|
|
95
|
+
* import fs from 'fs';
|
|
96
|
+
*/
|
|
97
|
+
addImport(importName: string, importPath: string): ConfigBuilder<Config>;
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* addExpression - add programmatic expression to the gasket file
|
|
101
|
+
* @param {string} expression - expression to add after imports
|
|
102
|
+
* @returns {ConfigBuilder} - instance for chaining
|
|
103
|
+
* @example
|
|
104
|
+
*
|
|
105
|
+
* .addImport('fs', 'fs')
|
|
106
|
+
* .addExpression('const file = fs.readFileSync(\'./file.txt\')')
|
|
107
|
+
*
|
|
108
|
+
* // gasket.js
|
|
109
|
+
* import fs from 'fs';
|
|
110
|
+
* const file = fs.readFileSync('./file.txt');
|
|
111
|
+
*/
|
|
112
|
+
addExpression(expression: string): ConfigBuilder<Config>;
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* injectValue - Inject a value into the gasket config object
|
|
116
|
+
* @param {string} configKey - collapsed object path to inject value into - `express.config.routes`
|
|
117
|
+
* @param {string} injectedValue - string used as a value
|
|
118
|
+
* @example
|
|
119
|
+
* .addImport('{ routes }', './routes')
|
|
120
|
+
* .injectValue('express.routes', 'routes');
|
|
121
|
+
*
|
|
122
|
+
* // gasket.js
|
|
123
|
+
* export default makeGasket({
|
|
124
|
+
* express: {
|
|
125
|
+
* routes: routes
|
|
126
|
+
* }
|
|
127
|
+
* });
|
|
128
|
+
*/
|
|
129
|
+
injectValue(configKey: string, injectedValue: string): void;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export interface PackageJsonBuilder extends ConfigBuilder<PackageJson> {
|
|
133
|
+
/**
|
|
134
|
+
* Checks if a property exists on the package.json fields.
|
|
135
|
+
* @param key - Field to search
|
|
136
|
+
* @param value - Value to search for
|
|
137
|
+
* @returns True if the property exists and matches the value
|
|
138
|
+
*/
|
|
139
|
+
has(key: keyof PackageJson, value: string): boolean;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export interface Files {
|
|
143
|
+
add(...args: string[]): void;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export interface CreateContext {
|
|
147
|
+
/** Short name of the app */
|
|
148
|
+
appName: string;
|
|
149
|
+
|
|
150
|
+
/** Current work directory */
|
|
151
|
+
cwd: string;
|
|
152
|
+
|
|
153
|
+
/** Path to the target app (Default: cwd/appName) */
|
|
154
|
+
dest: string;
|
|
155
|
+
|
|
156
|
+
/** Relative path to the target app */
|
|
157
|
+
relDest: string;
|
|
158
|
+
|
|
159
|
+
/** Whether or not target directory already exists */
|
|
160
|
+
extant: boolean;
|
|
161
|
+
|
|
162
|
+
/** paths to the local presets packages */
|
|
163
|
+
localPresets: Array<string>;
|
|
164
|
+
|
|
165
|
+
/** Raw preset desc from args. Can include version constraint. Added by
|
|
166
|
+
* load-preset if using localPresets. */
|
|
167
|
+
rawPresets: Array<string>;
|
|
168
|
+
|
|
169
|
+
/** Local packages that should be linked */
|
|
170
|
+
pkgLinks: Array<string>;
|
|
171
|
+
|
|
172
|
+
/** non-error/warning messages to report */
|
|
173
|
+
messages: Array<string>;
|
|
174
|
+
|
|
175
|
+
/** warnings messages to report */
|
|
176
|
+
warnings: Array<string>;
|
|
177
|
+
|
|
178
|
+
/** error messages to report but do not exit process */
|
|
179
|
+
errors: Array<string>;
|
|
180
|
+
|
|
181
|
+
/** any next steps to report for user */
|
|
182
|
+
nextSteps: Array<string>;
|
|
183
|
+
|
|
184
|
+
/** any generated files to show in report */
|
|
185
|
+
generatedFiles: Set<string>;
|
|
186
|
+
|
|
187
|
+
/** Default empty array, populated by load-preset with actual imports */
|
|
188
|
+
presets: Array<Plugin>;
|
|
189
|
+
|
|
190
|
+
/** Default to object w/empty plugins array to be populated by `presetConfig` hook */
|
|
191
|
+
presetConfig: GasketConfigDefinition;
|
|
192
|
+
|
|
193
|
+
// Added by `global-prompts`
|
|
194
|
+
|
|
195
|
+
/** Description of app */
|
|
196
|
+
appDescription: string;
|
|
197
|
+
|
|
198
|
+
/** Should a git repo be initialized and first commit */
|
|
199
|
+
gitInit: boolean;
|
|
200
|
+
|
|
201
|
+
/** Names of the plugins that add unit and integration tests */
|
|
202
|
+
testPlugins: Array<string>;
|
|
203
|
+
|
|
204
|
+
/** Which package manager to use (Default: 'npm') */
|
|
205
|
+
packageManager: string;
|
|
206
|
+
|
|
207
|
+
/** Derived install command (Default: 'npm install') */
|
|
208
|
+
installCmd: string;
|
|
209
|
+
|
|
210
|
+
/** Derived local run command (Default: 'npx gasket local') */
|
|
211
|
+
localCmd: string;
|
|
212
|
+
|
|
213
|
+
/** Whether or not the user wants to override an extant directory */
|
|
214
|
+
destOverride: boolean;
|
|
215
|
+
|
|
216
|
+
// Added by `setup-pkg`
|
|
217
|
+
|
|
218
|
+
/** package.json builder */
|
|
219
|
+
pkg: PackageJsonBuilder;
|
|
220
|
+
|
|
221
|
+
/** manager to execute npm or yarn commands */
|
|
222
|
+
pkgManager: PackageManager;
|
|
223
|
+
|
|
224
|
+
// Added by `setup-gasket-config`
|
|
225
|
+
|
|
226
|
+
/** gasket.config builder */
|
|
227
|
+
gasketConfig: ConfigBuilder<GasketConfigDefinition>;
|
|
228
|
+
|
|
229
|
+
// Added by `create-hooks`
|
|
230
|
+
|
|
231
|
+
/** Use to add files and templates to generate */
|
|
232
|
+
files: Files;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
export interface ActionWrapperParams {
|
|
236
|
+
gasket: GasketEngine;
|
|
237
|
+
context: CreateContext;
|
|
238
|
+
spinner?: any;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
declare module '@gasket/core' {
|
|
242
|
+
export interface HookExecTypes {
|
|
243
|
+
presetPrompt(context: CreateContext): Promise<void>;
|
|
244
|
+
presetConfig(context: CreateContext): Promise<CreateContext['presetConfig']>;
|
|
245
|
+
prompt(
|
|
246
|
+
context: CreateContext,
|
|
247
|
+
utils: {
|
|
248
|
+
prompt: (
|
|
249
|
+
prompts: Array<Record<string, any>>
|
|
250
|
+
) => Promise<Record<string, any>>;
|
|
251
|
+
addPlugins: (plugins: Array<string>) => Promise<void>;
|
|
252
|
+
}
|
|
253
|
+
): MaybeAsync<CreateContext>;
|
|
254
|
+
|
|
255
|
+
create(context: CreateContext): MaybeAsync<void>;
|
|
256
|
+
|
|
257
|
+
postCreate(
|
|
258
|
+
context: CreateContext,
|
|
259
|
+
utils: {
|
|
260
|
+
runScript: (script: string) => Promise<void>;
|
|
261
|
+
}
|
|
262
|
+
): MaybeAsync<void>;
|
|
263
|
+
}
|
|
264
|
+
}
|
package/lib/index.js
CHANGED
|
@@ -1,16 +1,31 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { createRequire } from 'module';
|
|
4
|
+
import { createCommand } from './commands/create.js';
|
|
5
|
+
import { processCommand, logo } from './utils/index.js';
|
|
6
|
+
import { warnIfOutdated } from '@gasket/utils';
|
|
2
7
|
|
|
3
|
-
const
|
|
4
|
-
const
|
|
8
|
+
const require = createRequire(import.meta.url);
|
|
9
|
+
const pkg = require('../package.json');
|
|
10
|
+
const program = new Command();
|
|
5
11
|
|
|
6
|
-
|
|
12
|
+
// Create Gasket CLI
|
|
13
|
+
const gasketBin = program
|
|
14
|
+
.name('create-gasket-app')
|
|
15
|
+
.description(pkg.description)
|
|
16
|
+
.option('--gasket-config [gasket-config-path]', 'Fully qualified Gasket config to load', 'gasket.config')
|
|
17
|
+
.version(pkg.version)
|
|
18
|
+
.addHelpText('beforeAll', logo);
|
|
7
19
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
20
|
+
|
|
21
|
+
async function main() {
|
|
22
|
+
const { command, hidden, isDefault } = processCommand(createCommand);
|
|
23
|
+
await warnIfOutdated(pkg.name, pkg.version);
|
|
24
|
+
gasketBin.addCommand(command, { hidden, isDefault });
|
|
25
|
+
|
|
26
|
+
process.argv.splice(2, 0, 'create');
|
|
27
|
+
|
|
28
|
+
return await gasketBin.parseAsync();
|
|
14
29
|
}
|
|
15
30
|
|
|
16
31
|
main();
|