@schalkneethling/miyagi-core 4.3.0 → 4.4.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 +48 -1
- package/bin/miyagi.js +9 -1
- package/index.js +2 -2
- package/lib/cli/component.js +23 -5
- package/lib/cli/doctor.js +153 -0
- package/lib/cli/drupal-assets.js +44 -7
- package/lib/cli/index.js +2 -0
- package/lib/cli/lint.js +71 -27
- package/lib/cli/run.js +281 -0
- package/lib/config.js +10 -0
- package/lib/default-config.js +1 -1
- package/lib/errors.js +31 -0
- package/lib/index.js +7 -151
- package/lib/init/args.js +161 -93
- package/lib/init/engines.js +13 -4
- package/lib/init/index.js +26 -10
- package/lib/init/watcher.js +15 -12
- package/lib/state/helpers.js +14 -9
- package/package.json +3 -3
package/lib/cli/run.js
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import { t } from "../i18n/index.js";
|
|
2
|
+
import initRendering from "../init/rendering.js";
|
|
3
|
+
import log from "../logger.js";
|
|
4
|
+
import mockGenerator from "../generator/mocks.js";
|
|
5
|
+
import getConfig from "../config.js";
|
|
6
|
+
import createCli from "../init/args.js";
|
|
7
|
+
import {
|
|
8
|
+
lint,
|
|
9
|
+
component as createComponentViaCli,
|
|
10
|
+
drupalAssets,
|
|
11
|
+
doctor,
|
|
12
|
+
} from "./index.js";
|
|
13
|
+
import { EXIT_CODES, MiyagiError } from "../errors.js";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @returns {object}
|
|
17
|
+
*/
|
|
18
|
+
function createSuccessResult() {
|
|
19
|
+
return {
|
|
20
|
+
success: true,
|
|
21
|
+
code: EXIT_CODES.SUCCESS,
|
|
22
|
+
shouldExit: true,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @param {string} message
|
|
28
|
+
* @param {number} [code]
|
|
29
|
+
* @returns {object}
|
|
30
|
+
*/
|
|
31
|
+
function createFailureResult(message, code = EXIT_CODES.GENERAL_ERROR) {
|
|
32
|
+
log("error", message);
|
|
33
|
+
return {
|
|
34
|
+
success: false,
|
|
35
|
+
code,
|
|
36
|
+
shouldExit: true,
|
|
37
|
+
message,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @param {number} code
|
|
43
|
+
* @param {string[]} argv
|
|
44
|
+
* @returns {void}
|
|
45
|
+
*/
|
|
46
|
+
function maybeLogDoctorHint(code, argv) {
|
|
47
|
+
if (code !== EXIT_CODES.CONFIG_ERROR) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (argv.includes("doctor")) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
log("info", "Run `miyagi doctor` for a setup check.");
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* @param {object} args
|
|
60
|
+
* @param {boolean} [isBuild]
|
|
61
|
+
* @param {boolean} [isComponentGenerator]
|
|
62
|
+
* @returns {Promise<object>}
|
|
63
|
+
*/
|
|
64
|
+
async function loadCliConfig(args, isBuild = false, isComponentGenerator = false) {
|
|
65
|
+
global.config = await getConfig(args, isBuild, isComponentGenerator);
|
|
66
|
+
|
|
67
|
+
if (!global.config.components.folder && !global.config.docs.folder) {
|
|
68
|
+
return createFailureResult(
|
|
69
|
+
"Please specify at least either components.folder or docs.folder in your configuration file.",
|
|
70
|
+
EXIT_CODES.CONFIG_ERROR,
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
success: true,
|
|
76
|
+
config: global.config,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* @param {object} args
|
|
82
|
+
* @returns {void}
|
|
83
|
+
*/
|
|
84
|
+
function applyCliEnv(args) {
|
|
85
|
+
if (args.verbose) {
|
|
86
|
+
process.env.VERBOSE = String(args.verbose);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* @param {object} args
|
|
92
|
+
* @param {object} [options]
|
|
93
|
+
* @param {string} [options.defaultNodeEnv]
|
|
94
|
+
* @param {string} [options.forcedNodeEnv]
|
|
95
|
+
* @param {boolean} [options.isBuild]
|
|
96
|
+
* @param {boolean} [options.isComponentGenerator]
|
|
97
|
+
* @param {Function} run
|
|
98
|
+
* @returns {Promise<object>}
|
|
99
|
+
*/
|
|
100
|
+
async function withCliConfig(args, options = {}, run) {
|
|
101
|
+
applyCliEnv(args);
|
|
102
|
+
|
|
103
|
+
if (options.forcedNodeEnv) {
|
|
104
|
+
process.env.NODE_ENV = options.forcedNodeEnv;
|
|
105
|
+
} else if (options.defaultNodeEnv && !process.env.NODE_ENV) {
|
|
106
|
+
process.env.NODE_ENV = options.defaultNodeEnv;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const configResult = await loadCliConfig(
|
|
110
|
+
args,
|
|
111
|
+
options.isBuild,
|
|
112
|
+
options.isComponentGenerator,
|
|
113
|
+
);
|
|
114
|
+
if (!configResult.success) {
|
|
115
|
+
return configResult;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return await run(configResult.config);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* @param {object} args
|
|
123
|
+
* @returns {Promise<object>}
|
|
124
|
+
*/
|
|
125
|
+
async function runStartCommand(args) {
|
|
126
|
+
return await withCliConfig(
|
|
127
|
+
args,
|
|
128
|
+
{ defaultNodeEnv: "development" },
|
|
129
|
+
async (config) => {
|
|
130
|
+
log(
|
|
131
|
+
"info",
|
|
132
|
+
t("serverStarting").replace("{{node_env}}", process.env.NODE_ENV),
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
return await initRendering(config);
|
|
136
|
+
},
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* @param {object} args
|
|
142
|
+
* @returns {Promise<object>}
|
|
143
|
+
*/
|
|
144
|
+
async function runBuildCommand(args) {
|
|
145
|
+
return await withCliConfig(
|
|
146
|
+
args,
|
|
147
|
+
{ forcedNodeEnv: "production", isBuild: true },
|
|
148
|
+
async (config) => {
|
|
149
|
+
log("info", t("buildStarting"));
|
|
150
|
+
return await initRendering(config);
|
|
151
|
+
},
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* @param {object} args
|
|
157
|
+
* @returns {Promise<object>}
|
|
158
|
+
*/
|
|
159
|
+
async function runComponentCommand(args) {
|
|
160
|
+
return await withCliConfig(
|
|
161
|
+
args,
|
|
162
|
+
{ defaultNodeEnv: "development", isComponentGenerator: true },
|
|
163
|
+
async () => {
|
|
164
|
+
log("info", t("generator.starting"));
|
|
165
|
+
return await createComponentViaCli(args);
|
|
166
|
+
},
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* @param {object} args
|
|
172
|
+
* @returns {Promise<object>}
|
|
173
|
+
*/
|
|
174
|
+
async function runMocksCommand(args) {
|
|
175
|
+
return await withCliConfig(
|
|
176
|
+
args,
|
|
177
|
+
{ defaultNodeEnv: "development" },
|
|
178
|
+
async (config) => {
|
|
179
|
+
const result = await mockGenerator(args.component, config.files);
|
|
180
|
+
if (result?.message) {
|
|
181
|
+
log(result.message.type, result.message.text, result.message.verbose);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return {
|
|
185
|
+
success: result.success,
|
|
186
|
+
code: result.success ? EXIT_CODES.SUCCESS : EXIT_CODES.GENERAL_ERROR,
|
|
187
|
+
shouldExit: true,
|
|
188
|
+
message: result.message?.text,
|
|
189
|
+
};
|
|
190
|
+
},
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* @param {object} args
|
|
196
|
+
* @returns {Promise<object>}
|
|
197
|
+
*/
|
|
198
|
+
async function runLintCommand(args) {
|
|
199
|
+
applyCliEnv(args);
|
|
200
|
+
return await lint(args);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* @param {object} args
|
|
205
|
+
* @returns {Promise<object>}
|
|
206
|
+
*/
|
|
207
|
+
async function runDrupalAssetsCommand(args) {
|
|
208
|
+
return await withCliConfig(
|
|
209
|
+
args,
|
|
210
|
+
{ forcedNodeEnv: "development" },
|
|
211
|
+
async () => await drupalAssets(args),
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* @param {object} args
|
|
217
|
+
* @returns {Promise<object>}
|
|
218
|
+
*/
|
|
219
|
+
async function runDoctorCommand(args) {
|
|
220
|
+
applyCliEnv(args);
|
|
221
|
+
return await doctor(args);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* @param {Error|MiyagiError|string} error
|
|
226
|
+
* @param {string[]} argv
|
|
227
|
+
* @returns {object}
|
|
228
|
+
*/
|
|
229
|
+
function normalizeCliError(error, argv) {
|
|
230
|
+
if (error instanceof MiyagiError) {
|
|
231
|
+
if (!error.logged) {
|
|
232
|
+
log("error", error.message);
|
|
233
|
+
}
|
|
234
|
+
maybeLogDoctorHint(error.code, argv);
|
|
235
|
+
|
|
236
|
+
return {
|
|
237
|
+
success: false,
|
|
238
|
+
code: error.code,
|
|
239
|
+
shouldExit: true,
|
|
240
|
+
message: error.message,
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
245
|
+
log("error", message);
|
|
246
|
+
maybeLogDoctorHint(EXIT_CODES.GENERAL_ERROR, argv);
|
|
247
|
+
return {
|
|
248
|
+
success: false,
|
|
249
|
+
code: EXIT_CODES.GENERAL_ERROR,
|
|
250
|
+
shouldExit: true,
|
|
251
|
+
message,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* @param {string[]} [argv]
|
|
257
|
+
* @returns {Promise<object>}
|
|
258
|
+
*/
|
|
259
|
+
export async function runCli(argv = process.argv) {
|
|
260
|
+
const { cli, getResult } = createCli(
|
|
261
|
+
{
|
|
262
|
+
start: runStartCommand,
|
|
263
|
+
build: runBuildCommand,
|
|
264
|
+
new: runComponentCommand,
|
|
265
|
+
mocks: runMocksCommand,
|
|
266
|
+
lint: runLintCommand,
|
|
267
|
+
drupalAssets: runDrupalAssetsCommand,
|
|
268
|
+
doctor: runDoctorCommand,
|
|
269
|
+
},
|
|
270
|
+
argv,
|
|
271
|
+
);
|
|
272
|
+
|
|
273
|
+
try {
|
|
274
|
+
await cli.parseAsync();
|
|
275
|
+
const result = getResult() || createSuccessResult();
|
|
276
|
+
maybeLogDoctorHint(result.code, argv);
|
|
277
|
+
return result;
|
|
278
|
+
} catch (error) {
|
|
279
|
+
return normalizeCliError(error, argv);
|
|
280
|
+
}
|
|
281
|
+
}
|
package/lib/config.js
CHANGED
|
@@ -62,6 +62,16 @@ function getCliArgs(args) {
|
|
|
62
62
|
|
|
63
63
|
delete cliArgs._;
|
|
64
64
|
delete cliArgs.$0;
|
|
65
|
+
delete cliArgs.component;
|
|
66
|
+
delete cliArgs.verbose;
|
|
67
|
+
delete cliArgs.skip;
|
|
68
|
+
delete cliArgs.only;
|
|
69
|
+
delete cliArgs.engine;
|
|
70
|
+
delete cliArgs.config;
|
|
71
|
+
delete cliArgs.libraries;
|
|
72
|
+
delete cliArgs.components;
|
|
73
|
+
delete cliArgs.ignorePrefixes;
|
|
74
|
+
delete cliArgs.dryRun;
|
|
65
75
|
|
|
66
76
|
if (cliArgs.folder) {
|
|
67
77
|
buildArgs.folder = cliArgs.folder;
|
package/lib/default-config.js
CHANGED
package/lib/errors.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI/process exit codes used by miyagi.
|
|
3
|
+
*
|
|
4
|
+
* Keep this list small and coarse-grained. The goal is predictable automation,
|
|
5
|
+
* not a unique code for every possible failure.
|
|
6
|
+
*/
|
|
7
|
+
export const EXIT_CODES = Object.freeze({
|
|
8
|
+
SUCCESS: 0,
|
|
9
|
+
GENERAL_ERROR: 1,
|
|
10
|
+
CLI_USAGE_ERROR: 2,
|
|
11
|
+
CONFIG_ERROR: 3,
|
|
12
|
+
VALIDATION_ERROR: 4,
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export class MiyagiError extends Error {
|
|
16
|
+
/**
|
|
17
|
+
* @param {string} message
|
|
18
|
+
* @param {object} [options]
|
|
19
|
+
* @param {number} [options.code] Exit code from `EXIT_CODES`.
|
|
20
|
+
* @param {boolean} [options.logged] True if this error was already sent to the logger and should not be logged again at the CLI boundary.
|
|
21
|
+
*/
|
|
22
|
+
constructor(
|
|
23
|
+
message,
|
|
24
|
+
{ code = EXIT_CODES.GENERAL_ERROR, logged = false } = {},
|
|
25
|
+
) {
|
|
26
|
+
super(message);
|
|
27
|
+
this.name = "MiyagiError";
|
|
28
|
+
this.code = code;
|
|
29
|
+
this.logged = logged;
|
|
30
|
+
}
|
|
31
|
+
}
|
package/lib/index.js
CHANGED
|
@@ -6,81 +6,11 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { t } from "./i18n/index.js";
|
|
9
|
-
import initRendering from "./init/rendering.js";
|
|
10
9
|
import log from "./logger.js";
|
|
11
|
-
import yargs from "./init/args.js";
|
|
12
|
-
import mockGenerator from "./generator/mocks.js";
|
|
13
10
|
import getConfig from "./config.js";
|
|
14
|
-
import {
|
|
15
|
-
lint,
|
|
16
|
-
component as createComponentViaCli,
|
|
17
|
-
drupalAssets,
|
|
18
|
-
} from "./cli/index.js";
|
|
11
|
+
import { EXIT_CODES } from "./errors.js";
|
|
19
12
|
import apiApp from "../api/app.js";
|
|
20
13
|
|
|
21
|
-
/**
|
|
22
|
-
* Checks if miyagi was started with "mocks" command
|
|
23
|
-
* @param {object} args - the cli args
|
|
24
|
-
* @returns {boolean} is true if the miyagi was started with "mocks"
|
|
25
|
-
*/
|
|
26
|
-
function argsIncludeMockGenerator(args) {
|
|
27
|
-
return args._.includes("mocks");
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Checks if miyagi was started with "new" command
|
|
32
|
-
* @param {object} args - the cli args
|
|
33
|
-
* @returns {boolean} is true if the miyagi was started with "new"
|
|
34
|
-
*/
|
|
35
|
-
function argsIncludeComponentGenerator(args) {
|
|
36
|
-
return args._.includes("new");
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Checks if miyagi was started with "build" command
|
|
41
|
-
* @param {object} args - the cli args
|
|
42
|
-
* @returns {boolean} is true if the miyagi was started with "new"
|
|
43
|
-
*/
|
|
44
|
-
function argsIncludeBuild(args) {
|
|
45
|
-
return args._.includes("build");
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Checks if miyagi was started with "start" command
|
|
50
|
-
* @param {object} args - the cli args
|
|
51
|
-
* @returns {boolean} is true if the miyagi was started with "start"
|
|
52
|
-
*/
|
|
53
|
-
function argsIncludeServer(args) {
|
|
54
|
-
return args._.includes("start");
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Checks if miyagi was started with "lint" command
|
|
59
|
-
* @param {object} args
|
|
60
|
-
* @returns {boolean}
|
|
61
|
-
*/
|
|
62
|
-
function argsIncludeLint(args) {
|
|
63
|
-
return args._.includes("lint");
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* @param {object} args
|
|
68
|
-
* @returns {boolean}
|
|
69
|
-
*/
|
|
70
|
-
function argsIncludeDrupalAssets(args) {
|
|
71
|
-
return args._.includes("drupal-assets");
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Runs the mock generator
|
|
76
|
-
* @param {object} config - the user configuration object
|
|
77
|
-
* @param {object} args - the cli args
|
|
78
|
-
* @returns {Promise}
|
|
79
|
-
*/
|
|
80
|
-
function runMockGenerator(config, args) {
|
|
81
|
-
return mockGenerator(args._.slice(1)[0], config.files).catch(() => {});
|
|
82
|
-
}
|
|
83
|
-
|
|
84
14
|
/**
|
|
85
15
|
* @param {object} config
|
|
86
16
|
* @returns {Promise<object>}
|
|
@@ -105,85 +35,11 @@ export default async function Miyagi(cmd, { isBuild: isApiBuild } = {}) {
|
|
|
105
35
|
return await initApi(global.config);
|
|
106
36
|
}
|
|
107
37
|
|
|
108
|
-
let args;
|
|
109
|
-
let isServer;
|
|
110
|
-
let isBuild;
|
|
111
|
-
let isComponentGenerator;
|
|
112
|
-
let isMockGenerator;
|
|
113
|
-
let isLinter;
|
|
114
|
-
let isDrupalAssets;
|
|
115
|
-
|
|
116
|
-
if (cmd) {
|
|
117
|
-
isBuild = cmd === "build";
|
|
118
|
-
} else {
|
|
119
|
-
args = await yargs.argv;
|
|
120
|
-
isServer = argsIncludeServer(args);
|
|
121
|
-
isBuild = argsIncludeBuild(args);
|
|
122
|
-
isComponentGenerator = argsIncludeComponentGenerator(args);
|
|
123
|
-
isMockGenerator = argsIncludeMockGenerator(args);
|
|
124
|
-
isLinter = argsIncludeLint(args);
|
|
125
|
-
isDrupalAssets = argsIncludeDrupalAssets(args);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
if (args && args.verbose) {
|
|
129
|
-
process.env.VERBOSE = String(args.verbose);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
if (isLinter) {
|
|
133
|
-
return lint(args);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
if (isDrupalAssets) {
|
|
137
|
-
process.env.NODE_ENV = "development";
|
|
138
|
-
global.config = await getConfig(args);
|
|
139
|
-
await drupalAssets(args);
|
|
140
|
-
process.exit();
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
if (isBuild || isComponentGenerator || isServer || isMockGenerator) {
|
|
144
|
-
if (isBuild) {
|
|
145
|
-
process.env.NODE_ENV = "production";
|
|
146
|
-
log("info", t("buildStarting"));
|
|
147
|
-
} else {
|
|
148
|
-
if (!process.env.NODE_ENV) {
|
|
149
|
-
process.env.NODE_ENV = "development";
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
if (isComponentGenerator) {
|
|
153
|
-
log("info", t("generator.starting"));
|
|
154
|
-
} else if (isServer) {
|
|
155
|
-
log(
|
|
156
|
-
"info",
|
|
157
|
-
t("serverStarting").replace("{{node_env}}", process.env.NODE_ENV),
|
|
158
|
-
);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
global.config = await getConfig(args, isBuild, isComponentGenerator);
|
|
163
|
-
|
|
164
|
-
if (!global.config.components.folder && !global.config.docs.folder) {
|
|
165
|
-
log(
|
|
166
|
-
"error",
|
|
167
|
-
"Please specify at least either components.folder or docs.folder in your configuration file.",
|
|
168
|
-
);
|
|
169
|
-
process.exit(1);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
if (isMockGenerator) {
|
|
173
|
-
await runMockGenerator(global.config, args);
|
|
174
|
-
// Force-exit in case imported user config has active resources preventing Node.js from exiting.
|
|
175
|
-
process.exit();
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
if (isComponentGenerator) {
|
|
179
|
-
await createComponentViaCli(args);
|
|
180
|
-
// Force-exit in case imported user config has active resources preventing Node.js from exiting.
|
|
181
|
-
process.exit();
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
return initRendering(global.config);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
38
|
log("error", t("commandNotFound"));
|
|
188
|
-
|
|
39
|
+
return {
|
|
40
|
+
success: false,
|
|
41
|
+
code: EXIT_CODES.CLI_USAGE_ERROR,
|
|
42
|
+
shouldExit: true,
|
|
43
|
+
message: t("commandNotFound"),
|
|
44
|
+
};
|
|
189
45
|
}
|