create-gasket-app 7.0.2-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
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import pkg from 'chalk';
|
|
2
|
+
const { bold } = pkg;
|
|
3
|
+
import action from '../action-wrapper.js';
|
|
4
|
+
import { logo } from '../../utils/index.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Logs a new line in the console
|
|
8
|
+
* @private
|
|
9
|
+
*/
|
|
10
|
+
const newline = () => {
|
|
11
|
+
console.log('');
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Converts a camelCase string to Space Case
|
|
16
|
+
* @see: https://stackoverflow.com/questions/4149276/javascript-camelcase-to-regular-form?answertab=active#tab-top
|
|
17
|
+
*
|
|
18
|
+
* @param {string} str - camelCase string to fixup
|
|
19
|
+
* @returns {string} result
|
|
20
|
+
* @private
|
|
21
|
+
*/
|
|
22
|
+
const toSpaceCase = str => str.replace(/([A-Z])/g, ' $1')
|
|
23
|
+
.replace(/^./, s => s.toUpperCase());
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Builds the report object from context
|
|
27
|
+
*
|
|
28
|
+
* @param {CreateContext} context - Create context
|
|
29
|
+
* @returns {Object} report
|
|
30
|
+
* @private
|
|
31
|
+
*/
|
|
32
|
+
function buildReport(context) {
|
|
33
|
+
const {
|
|
34
|
+
appName,
|
|
35
|
+
dest,
|
|
36
|
+
fullPresets,
|
|
37
|
+
plugins,
|
|
38
|
+
generatedFiles: generatedFilesSet,
|
|
39
|
+
messages,
|
|
40
|
+
warnings,
|
|
41
|
+
errors,
|
|
42
|
+
nextSteps
|
|
43
|
+
} = context;
|
|
44
|
+
|
|
45
|
+
const generatedFiles = Array.from(generatedFilesSet);
|
|
46
|
+
generatedFiles.sort();
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
appName,
|
|
50
|
+
output: dest,
|
|
51
|
+
presets: fullPresets,
|
|
52
|
+
plugins,
|
|
53
|
+
generatedFiles,
|
|
54
|
+
messages,
|
|
55
|
+
warnings,
|
|
56
|
+
errors,
|
|
57
|
+
nextSteps
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Outputs create command details to the console
|
|
63
|
+
|
|
64
|
+
* @param {CreateContext} context - Create context
|
|
65
|
+
*/
|
|
66
|
+
async function printReport({ context }) {
|
|
67
|
+
const report = buildReport(context);
|
|
68
|
+
const { warnings, errors } = context;
|
|
69
|
+
|
|
70
|
+
console.log(`✨Success!
|
|
71
|
+
|
|
72
|
+
Finished with ${warnings.length} warnings and ${errors.length} errors using
|
|
73
|
+
` + logo);
|
|
74
|
+
|
|
75
|
+
Object.entries(report).forEach(([k, v]) => {
|
|
76
|
+
if (!v || !v.length) return;
|
|
77
|
+
newline();
|
|
78
|
+
console.log(`${bold(toSpaceCase(k))}`);
|
|
79
|
+
if (Array.isArray(v)) {
|
|
80
|
+
v.map(o => console.log(` ${o}`));
|
|
81
|
+
} else {
|
|
82
|
+
console.log(` ${v}`);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
newline();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export default action('Print report', printReport, { startSpinner: false });
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import inquirer from 'inquirer';
|
|
2
|
+
import action from '../action-wrapper.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Initializes engine with provide preset and plugins
|
|
6
|
+
* to execute their prompt lifecycle hooks.
|
|
7
|
+
*
|
|
8
|
+
* @param {CreateContext} context - Create context
|
|
9
|
+
* @param {String[]} plugins - plugins to load
|
|
10
|
+
* @param {String} [presets] - presets to load
|
|
11
|
+
* @returns {Promise} promise
|
|
12
|
+
* @private
|
|
13
|
+
*/
|
|
14
|
+
async function execPluginPrompts(gasket, context) {
|
|
15
|
+
//
|
|
16
|
+
// @see: https://github.com/SBoudrias/Inquirer.js/#inquirercreatepromptmodule---prompt-function
|
|
17
|
+
//
|
|
18
|
+
const prompt = context.prompts ? inquirer.createPromptModule() : () => ({});
|
|
19
|
+
const nextContext = await gasket.execWaterfall('prompt', context, { prompt });
|
|
20
|
+
//
|
|
21
|
+
// Ensure the original context is transformed in case a prompt returns a new object
|
|
22
|
+
//
|
|
23
|
+
Object.assign(context, nextContext);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Executes the `prompt` hook for all registered plugins.
|
|
28
|
+
* Adds `prompt` util function for prompting features.
|
|
29
|
+
*
|
|
30
|
+
* @param {GasketEngine} gasket - Gasket API
|
|
31
|
+
* @param {CreateContext} context - Create context
|
|
32
|
+
* @returns {Promise} promise
|
|
33
|
+
*/
|
|
34
|
+
async function promptHooks({ gasket, context }) {
|
|
35
|
+
//
|
|
36
|
+
// Because `execPluginPrompts` is recursively, we need to start it
|
|
37
|
+
// with the processPlugins and presets from our initial context
|
|
38
|
+
//
|
|
39
|
+
const { plugins } = context;
|
|
40
|
+
await execPluginPrompts(gasket, context, plugins);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export default action('Plugin prompts', promptHooks, { startSpinner: false });
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import action from '../action-wrapper.js';
|
|
2
|
+
import { ConfigBuilder } from '../config-builder.js';
|
|
3
|
+
import { default as gasketUtils } from '@gasket/utils';
|
|
4
|
+
import { createRequire } from 'module';
|
|
5
|
+
const require = createRequire(import.meta.url);
|
|
6
|
+
const { dependencies } = require('../../../package.json');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Initializes the ConfigBuilder builder and adds to context.
|
|
10
|
+
*
|
|
11
|
+
* @param {CreateContext} context - Create context
|
|
12
|
+
* @returns {Promise} promise
|
|
13
|
+
*/
|
|
14
|
+
async function setupPkg({ context }) {
|
|
15
|
+
const { appName, appDescription, warnings } = context;
|
|
16
|
+
|
|
17
|
+
const pkg = ConfigBuilder.createPackageJson({
|
|
18
|
+
name: appName,
|
|
19
|
+
version: '0.0.0',
|
|
20
|
+
description: appDescription,
|
|
21
|
+
type: 'module'
|
|
22
|
+
}, { warnings });
|
|
23
|
+
|
|
24
|
+
// Add critical dependencies
|
|
25
|
+
pkg.add('dependencies', {
|
|
26
|
+
'@gasket/core': dependencies['@gasket/core'],
|
|
27
|
+
'@gasket/utils': dependencies['@gasket/utils']
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const pkgManager = new gasketUtils.PackageManager(context);
|
|
31
|
+
Object.assign(context, { pkg, pkgManager });
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export default action('Set up package.json', setupPkg, { startSpinner: false });
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { default as JSON5 } from 'json5';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { writeFile } from 'fs/promises';
|
|
4
|
+
import action from '../action-wrapper.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* writePluginImports - Write string imports as value(s)
|
|
8
|
+
* @param {string[]} plugins - Array of plugin import names
|
|
9
|
+
* @returns {string} - Array of plugin imports as string
|
|
10
|
+
*/
|
|
11
|
+
function writePluginImports(plugins) {
|
|
12
|
+
return plugins.reduce((acc, cur, index) => {
|
|
13
|
+
acc += `\t\t${cur}${index < plugins.length - 1 ? ',\n' : ''}`;
|
|
14
|
+
return acc;
|
|
15
|
+
}, '');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* writeImports - Write imports to file using key value pairs
|
|
20
|
+
* @param {{[pluginImport: string]: string}[]} imports - Array of key value pairs for imports
|
|
21
|
+
* @returns {string} - import declarations as string
|
|
22
|
+
*/
|
|
23
|
+
function writeImports(imports) {
|
|
24
|
+
if (!imports) return '';
|
|
25
|
+
return `${Object.entries(imports).map(([importDef, importPath]) => `import ${importDef} from '${importPath}';`).join('\n')}\n`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* createInjectionAssignments - replace object path with a temp string value
|
|
30
|
+
* @param {GasketConfigDefinition} config - gasket config object
|
|
31
|
+
* @param {{ [configKey]: string }} assignments - key value pairs of config keys to replace
|
|
32
|
+
* @returns {string} - string if assignments is falsy
|
|
33
|
+
*/
|
|
34
|
+
function createInjectionAssignments(config, assignments) {
|
|
35
|
+
if (!assignments) return '';
|
|
36
|
+
Object.keys(assignments).forEach((key) => {
|
|
37
|
+
const keys = key.split('.');
|
|
38
|
+
|
|
39
|
+
keys.reduce((acc, cur, index) => {
|
|
40
|
+
if (index === keys.length - 1) {
|
|
41
|
+
acc[cur] = `${key}_INJECTION_ASSIGNMENT_REPLACE`;
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
return acc[cur];
|
|
45
|
+
}, config);
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* replaceInjectionAssignments - replace temp string value with actual value
|
|
51
|
+
* @param {string} content
|
|
52
|
+
* @param {{ [configKey]: string }} assignments - key value pairs of config keys to replace
|
|
53
|
+
* @returns {string} - content with replaced values
|
|
54
|
+
*/
|
|
55
|
+
function replaceInjectionAssignments(content, assignments) {
|
|
56
|
+
if (!assignments) return content;
|
|
57
|
+
Object.keys(assignments).forEach((key) => {
|
|
58
|
+
content = content.replace(`'${key}_INJECTION_ASSIGNMENT_REPLACE'`, assignments[key]);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
return content;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* writeExpressions - Write expressions to file
|
|
66
|
+
* @param {string} expressions - programmatic expressions as string
|
|
67
|
+
* @returns {string} - expressions as string
|
|
68
|
+
*/
|
|
69
|
+
function writeExpressions(expressions) {
|
|
70
|
+
if (!expressions) return '';
|
|
71
|
+
return `${expressions.map((expression) => `${expression}`).join('\n')}\n`;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* cleanupFields - Remove fields from config object
|
|
76
|
+
* @param {GasketConfigDefinition} config - gasket config object
|
|
77
|
+
*/
|
|
78
|
+
function cleanupFields(config) {
|
|
79
|
+
delete config.fields.imports;
|
|
80
|
+
delete config.fields.pluginImports;
|
|
81
|
+
delete config.fields.expressions;
|
|
82
|
+
delete config.fields.injectionAssignments;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Writes the contents of `pkg` to the app's package.json.
|
|
87
|
+
*
|
|
88
|
+
* @param {CreateContext} context - Create context
|
|
89
|
+
* @returns {Promise} promise
|
|
90
|
+
*/
|
|
91
|
+
async function writeGasketConfig({ context }) {
|
|
92
|
+
const { dest, gasketConfig, generatedFiles } = context;
|
|
93
|
+
const fileName = context.typescript ? 'gasket.ts' : 'gasket.js';
|
|
94
|
+
const filePath = path.join(dest, fileName);
|
|
95
|
+
const plugins = gasketConfig.fields.plugins;
|
|
96
|
+
const assignments = gasketConfig.fields.injectionAssignments || null;
|
|
97
|
+
const expressions = gasketConfig.fields.expressions || null;
|
|
98
|
+
gasketConfig.fields.plugins = 'PLUGIN_REPLACE';
|
|
99
|
+
|
|
100
|
+
let contents = '';
|
|
101
|
+
contents += `import { makeGasket } from '@gasket/core';\n`;
|
|
102
|
+
contents += writeImports(gasketConfig.fields.pluginImports);
|
|
103
|
+
contents += writeImports(gasketConfig.fields.imports);
|
|
104
|
+
contents += writeExpressions(expressions);
|
|
105
|
+
createInjectionAssignments(gasketConfig.fields, assignments);
|
|
106
|
+
cleanupFields(gasketConfig);
|
|
107
|
+
|
|
108
|
+
const pluginImports = `[\n${writePluginImports(plugins)}\n\t]`;
|
|
109
|
+
contents += `\nexport default makeGasket(${JSON5.stringify(gasketConfig.fields, null, 2)});\n`;
|
|
110
|
+
contents = contents.replace('\'PLUGIN_REPLACE\'', pluginImports);
|
|
111
|
+
contents = replaceInjectionAssignments(contents, assignments);
|
|
112
|
+
|
|
113
|
+
await writeFile(filePath, contents, 'utf8');
|
|
114
|
+
generatedFiles.add(fileName);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export default action('Write gasket config', writeGasketConfig);
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { writeFile } from 'fs/promises';
|
|
3
|
+
import action from '../action-wrapper.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Writes the contents of `pkg` to the app's package.json.
|
|
7
|
+
*
|
|
8
|
+
* @param {CreateContext} context - Create context
|
|
9
|
+
* @returns {Promise} promise
|
|
10
|
+
*/
|
|
11
|
+
async function writePkg({ context }) {
|
|
12
|
+
const { dest, pkg, generatedFiles } = context;
|
|
13
|
+
const fileName = 'package.json';
|
|
14
|
+
const filePath = path.join(dest, fileName);
|
|
15
|
+
await writeFile(filePath, JSON.stringify(pkg, null, 2), 'utf8');
|
|
16
|
+
generatedFiles.add(fileName);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export default action('Write package.json', writePkg);
|