mythix 2.4.13 → 2.4.14

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
@@ -314,11 +314,9 @@ module.exports = defineModel('Product', ({ Parent, Type, Relation }) => {
314
314
 
315
315
  The `mythix-cli` can load commands from `mythix`, as well as custom commands you define. For example, if you create a command named `deploy`, then that command can be ran like so: `mythix-cli deploy`. Commands can inherit from other commands in `mythix`, including commands built directly into `mythix`.
316
316
 
317
- Your command class needs to have a `static definition` string specified, or your command will not show up in `mythix-cli --help`.
317
+ A `static commandArguments` method is used to define the `help` for your command, and to define a `Runner` to gather arguments for your command. This `Runner` is a [CMDed](https://www.npmjs.com/package/cmded) `Runner`, so please refer to the [CMDed](https://www.npmjs.com/package/cmded) documentation for how to properly create a `Runner` for your command.
318
318
 
319
- `mythix` handles all the command line arguments for you. All you need to do is define a `static commandArguments` string on your command class to list your command arguments. Command arguments use the [simple-yargs](https://www.npmjs.com/package/simple-yargs) module to parse command line arguments.
320
-
321
- You can optionally define a `static nodeArguments` array of strings, which define the arguments for node that will be used when spawning this command via the CLI.
319
+ You can optionally define a `static runtimeArguments` object, defining an array of strings arguments for each `runtime`. A `runtime` would be something like `node`, `ts-node`, or `babel-node`.
322
320
 
323
321
  There is also the static property `static applicationConfig` which can be an object specifying the options for your `Application` class, or, if this is a method, should return the options for your `Application` class. If this is a method, then the options it returns are the *only* options that will be passed to your `Application` class upon instantiation. If this is an object, then the `mythix-cli` will deliberately merge other options in (such as `{ httpServer: false, runTasks: false, autoReload: false }`), as most commands don't want an HTTP server, tasks, or auto-reloading running.
324
322
 
@@ -331,8 +329,28 @@ const { defineCommand } = require('mythix');
331
329
 
332
330
  module.exports = defineCommand('deploy', ({ Parent }) => {
333
331
  return class DeployCommand extends Parent {
334
- static definition = 'Deploy application to servers';
335
- static commandArguments = '<-target:string(Target server to deploy to)';
332
+ static runtimeArguments = {
333
+ 'node': [ '--inspect' ],
334
+ };
335
+
336
+ static commandArguments() {
337
+ return {
338
+ // CMDed help
339
+ help: {
340
+ '@usage': 'mythix-cli deploy [options]',
341
+ '@title': 'Deploy the application to the specified target servers',
342
+ '-t={target} | -t {target} | --target={target} | --target {target}': 'Target server to deploy to',
343
+ },
344
+ // CMDed runner
345
+ runner: ({ $, store, Types }) => {
346
+ $('--target', Types.STRING(), { name: 'target' })
347
+ || $('-t', Types.STRING(), { name: 'target' })
348
+ || store({ target: 'production' }); // Default value
349
+
350
+ return true;
351
+ },
352
+ };
353
+ }
336
354
 
337
355
  async execute(args) {
338
356
  // args contains all your command line arguments parsed
@@ -474,12 +492,12 @@ When the `mythix-cli` is invoked, it will always pass a `{ cli: true }` option t
474
492
 
475
493
  A little bit should be mentioned about how the `mythix-cli` command works. When it is invoked, the first thing it does is search for your `Application` class. When it finds it, it will then create an instance of your application to fetch all your application defined paths. Once it has the paths you specified for your application, it will then load all commands it finds (both internal 'mythix' commands, and any custom commands you have defined).
476
494
 
477
- When a command is invoked, the `mythix-cli` will deliberately launch a new `node` process to execute the command specified. This is so that each command can specify its own custom `nodeArguments` (if desired).
495
+ When a command is invoked, the `mythix-cli` will deliberately launch a new process using the specified `runtime` (default is `node`) to execute the command specified. This is so that each command can specify its own custom `runtimeArguments` (if desired).
478
496
 
479
497
  Because of the way this works, your application will be instantiated twice:
480
498
 
481
499
  * Once, and first, to load your application configuration (specifically your defined paths). This part of the process will *not* start your application, but simply instantiate it.
482
- * Second, your application will be instantiated again in the new spawned `node` process, and this time your application will also be started. Once your application has been successfully instantiated and started, then the command will run.
500
+ * Second, your application will be instantiated again in the new spawned `runtime` (default `node`) process, and this time your application will also be started. Once your application has been successfully instantiated and started, then the command will run.
483
501
 
484
502
  Most commands by default will start your application with the options `{ httpServer: false, autoReload: false, runTasks: false }`. This informs your application NOT to start the web-server, NOT to start the task worker, and to NOT auto-reload files on change (which often isn't desired for many commands).
485
503
 
@@ -620,7 +638,7 @@ Create a new command class, giving your command the name specified by the `comma
620
638
  #### Static Class Properties
621
639
 
622
640
  * static **description** *`<string>`* - The description to give to this command. If this is not provided, then your command's "help" will not be shown when you run `mythix-cli --help`.
623
- * static **nodeArguments** *`<Array[<string>]>`* - An array of string arguments to use as command line arguments when invoking your command with `node`. These are NOT your command's arguments, but rather the arguments to give to `node`.
641
+ * static **runtimeArguments** *`{ [key: string]: <Array[<string>]> }`* - An object containing runtime name keys, where each key value is an array of string arguments to use as command line arguments when invoking your command with the specified runtime. These are NOT your command's arguments, but rather the arguments to give to the specified runtime. For example, for the default `node` runtime, this might look something like `{ node: [ '--inspect' ] }`.
624
642
  * static **commandArguments** *`<string>`* - A string containing your command arguments, their descriptions, their types, and their default values. [simple-yargs](https://www.npmjs.com/package/simple-yargs) is used to parse these command argument strings, so refer to its documentation for how to define your command arguments.
625
643
  * static **applicationConfig** *`<object> | <function>`* - Define the options passed to your `Application.constructor`. If this is a simple object, then the `mythix-cli` will inject some default options that make sense for most commands. If this is a function, then it should return an options object. When this is a function, the `mythix-cli` will not inject any arguments, but instead will pass your options directly to `Application.constructor` without modification.
626
644
 
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "mythix",
3
- "version": "2.4.13",
3
+ "version": "2.4.14",
4
4
  "description": "Mythix is a NodeJS web-app framework",
5
- "main": "src/index.js",
5
+ "main": "src/index",
6
6
  "scripts": {
7
7
  "test": "node ./node_modules/.bin/jasmine",
8
8
  "test-watch": "watch 'clear ; node --trace-warnings ./node_modules/.bin/jasmine' . --wait=3 --interval=1"
@@ -27,6 +27,7 @@
27
27
  },
28
28
  "dependencies": {
29
29
  "chokidar": "^3.5.3",
30
+ "cmded": "^1.2.1",
30
31
  "express": "^4.17.3",
31
32
  "express-busboy": "github:th317erd/express-busboy#0754a570d7979097b31e48655b80d3fcd628d4e4",
32
33
  "form-data": "^4.0.0",
@@ -13,7 +13,7 @@ const { ModelModule } = require('./models/model-module');
13
13
  const { HTTPServerModule } = require('./http-server/http-server-module');
14
14
  const { ControllerModule } = require('./controllers/controller-module');
15
15
  const { TaskModule } = require('./tasks/task-module');
16
- const { FileWatcherModule } = require('./modules/file-watcher-module.js');
16
+ const { FileWatcherModule } = require('./modules/file-watcher-module');
17
17
  const { wrapConfig } = require('./utils');
18
18
 
19
19
  // Trace what is requesting the application exit
@@ -12,24 +12,30 @@ const {
12
12
  fileNameWithoutExtension,
13
13
  } = require('../utils/file-utils');
14
14
 
15
+ const { CMDed } = require('cmded');
16
+
15
17
  class CommandBase {
16
- constructor(application, argv) {
18
+ constructor(application, options) {
17
19
  Object.defineProperties(this, {
18
20
  'application': {
19
21
  writable: false,
20
- enumberable: false,
22
+ enumerable: false,
21
23
  configurable: true,
22
24
  value: application,
23
25
  },
24
- 'argv': {
26
+ 'options': {
25
27
  writable: false,
26
- enumberable: false,
28
+ enumerable: false,
27
29
  configurable: true,
28
- value: argv,
30
+ value: options,
29
31
  },
30
32
  });
31
33
  }
32
34
 
35
+ getOptions() {
36
+ return this.options;
37
+ }
38
+
33
39
  getApplication() {
34
40
  return this.application;
35
41
  }
@@ -47,17 +53,12 @@ class CommandBase {
47
53
 
48
54
  let loadingAllCommandsInProgress = false;
49
55
 
50
- CommandBase.defaultArguments = `
51
- [-e,-env:string(Environment to use)=$NODE_ENV|development(Default "development")]
52
- [--mythixConfig:string(Path to .mythix-config.js)=$MYTHIX_CONFIG_PATH]
53
- `.trim();
54
-
55
56
  function defineCommand(_commandName, definer, _parent) {
56
57
  if (!CommandBase.commands) {
57
58
  Object.defineProperties(CommandBase, {
58
59
  'commands': {
59
60
  writable: false,
60
- enumberable: false,
61
+ enumerable: false,
61
62
  configurable: true,
62
63
  value: {},
63
64
  },
@@ -81,7 +82,6 @@ function defineCommand(_commandName, definer, _parent) {
81
82
  let mythixApplicationCommandsPath = process.env['MYTHIX_APPLICATION_COMMANDS'];
82
83
  if (mythixCommandPath && mythixApplicationCommandsPath)
83
84
  loadCommands(mythixApplicationCommandsPath, [ mythixCommandPath ]);
84
-
85
85
  }
86
86
 
87
87
  if (Nife.instanceOf(parent, 'string')) {
@@ -102,20 +102,6 @@ function defineCommand(_commandName, definer, _parent) {
102
102
  throw new Error(`Error while defining command ${commandName}: "execute" method is required`);
103
103
 
104
104
  Klass.commandName = commandName;
105
- if (!Klass.commandArguments)
106
- Klass.commandArguments = '';
107
-
108
- if (!Klass.description)
109
- Klass.description = '';
110
-
111
- if (Klass.commandArguments.indexOf(CommandBase.defaultArguments) < 0)
112
- Klass.commandArguments = `${Klass.commandArguments} ${CommandBase.defaultArguments}`.trim();
113
- else
114
- Klass.commandArguments = Klass.commandArguments.trim();
115
-
116
- Klass.commandString = `${commandName}(${Klass.description}) ${(Klass.commandArguments) ? Klass.commandArguments : ''}`.trim();
117
-
118
- //console.log('COMMAND STRING: ', name, Klass.commandString.replace(/\n/gm, ' '));
119
105
 
120
106
  // Executor method. This gets invoked in a separate node process
121
107
  // The command script is executed directly via node when the
@@ -123,74 +109,86 @@ function defineCommand(_commandName, definer, _parent) {
123
109
  // "executeCommand" below, which spawns a node process that
124
110
  // targets this command script.
125
111
  Klass.execute = async function() {
126
- let yargsPath = process.env['MYTHIX_YARGS_PATH'];
127
- if (!yargsPath)
128
- yargsPath = Path.dirname(require.resolve('yargs'));
112
+ // eslint-disable-next-line new-cap
113
+ let commandContext = CMDed((context) => {
114
+ let { $, Types, store, scope } = context;
115
+
116
+ // Parse these even though they are no longer needed
117
+ // so that we ensure they are "consumed".
118
+ $('--config', Types.STRING({
119
+ format: Path.resolve,
120
+ })) || store({ config: (Nife.isNotEmpty(process.env.MYTHIX_CONFIG_PATH)) ? Path.resolve(process.env.MYTHIX_CONFIG_PATH) : Path.join(process.env.PWD, '.mythix-config.js') });
121
+
122
+ $('--runtime', Types.STRING());
123
+
124
+ $('-e', Types.STRING(), { name: 'environment' });
125
+ $('--env', Types.STRING(), { name: 'environment' });
129
126
 
130
- let simpleYargsPath = process.env['MYTHIX_SIMPLE_YARGS_PATH'];
131
- if (!simpleYargsPath)
132
- simpleYargsPath = Path.dirname(require.resolve('simple-yargs', '..'));
127
+ let runner = null;
133
128
 
134
- let yargs = require(Path.resolve(yargsPath, 'yargs'));
135
- let { hideBin } = require(Path.resolve(yargsPath, 'helpers'));
136
- const SimpleYargs = require(simpleYargsPath);
137
- let argv = hideBin(process.argv).concat('');
138
- let rootCommand = yargs(argv);
129
+ if (typeof Klass.commandArguments === 'function') {
130
+ let result = (Klass.commandArguments() || {});
131
+ runner = result.runner;
132
+ }
139
133
 
140
- rootCommand = SimpleYargs.buildCommands(rootCommand, async function(command, args) {
141
- let application;
134
+ return scope(commandName, (context) => {
135
+ if (typeof runner === 'function')
136
+ return runner(context);
142
137
 
143
- try {
144
- let PWD = process.env['PWD'];
145
- let mythixConfigPath = args.mythixConfig;
138
+ return true;
139
+ });
140
+ });
146
141
 
147
- if (Nife.isEmpty(mythixConfigPath))
148
- mythixConfigPath = process.env['MYTHIX_CONFIG_PATH'];
142
+ if (!commandContext)
143
+ return;
149
144
 
150
- if (Nife.isEmpty(mythixConfigPath))
151
- mythixConfigPath = PWD;
145
+ let application;
152
146
 
153
- let config = loadMythixConfig(mythixConfigPath);
154
- let Application = config.getApplicationClass(config);
155
- let applicationConfig = Klass.applicationConfig;
147
+ try {
148
+ let PWD = process.env['PWD'];
149
+ let mythixConfigPath = commandContext.config || process.env['MYTHIX_CONFIG_PATH'];
156
150
 
157
- if (typeof applicationConfig === 'function')
158
- applicationConfig = applicationConfig(config, Application);
159
- else if (applicationConfig)
160
- applicationConfig = Nife.extend(true, { httpServer: false, autoReload: false, logger: { level: Logger.LEVEL_WARN }, runTasks: false }, applicationConfig);
151
+ if (Nife.isEmpty(mythixConfigPath))
152
+ mythixConfigPath = PWD;
161
153
 
154
+ let config = loadMythixConfig(mythixConfigPath);
155
+ let Application = config.getApplicationClass(config);
156
+ let applicationConfig = Klass.applicationConfig;
162
157
 
163
- if (!applicationConfig)
164
- applicationConfig = { httpServer: false, autoReload: false, logger: { level: Logger.LEVEL_WARN }, runTasks: false };
158
+ if (typeof applicationConfig === 'function')
159
+ applicationConfig = applicationConfig(config, Application);
160
+ else if (applicationConfig)
161
+ applicationConfig = Nife.extend(true, { httpServer: false, autoReload: false, logger: { level: Logger.LEVEL_WARN }, runTasks: false }, applicationConfig);
165
162
 
166
- let doStartApplication = (applicationConfig.autoStart !== false);
163
+ if (!applicationConfig)
164
+ applicationConfig = { httpServer: false, autoReload: false, logger: { level: Logger.LEVEL_WARN }, runTasks: false };
167
165
 
168
- delete applicationConfig.autoStart;
166
+ let doStartApplication = (applicationConfig.autoStart !== false);
169
167
 
170
- application = await createApplication(Application, Object.assign({ exitOnShutdown: 1 }, applicationConfig), false);
168
+ delete applicationConfig.autoStart;
171
169
 
172
- let environment = args.env;
173
- if (Nife.isEmpty(environment))
174
- environment = application.getConfigValue('environment', 'development');
170
+ application = await createApplication(Application, Object.assign({ exitOnShutdown: 1 }, applicationConfig), false);
175
171
 
176
- application.setConfig({ environment: environment });
172
+ let environment = commandContext.environment;
173
+ if (Nife.isEmpty(environment))
174
+ environment = application.getConfigValue('environment', 'development');
177
175
 
178
- if (doStartApplication)
179
- await application.start();
176
+ application.setConfig({ environment: environment });
180
177
 
181
- let commandInstance = new Klass(application, args);
182
- let result = await commandInstance.execute.call(commandInstance, args);
178
+ if (doStartApplication)
179
+ await application.start();
183
180
 
184
- await application.stop(result || 0);
185
- } catch (error) {
186
- console.log(`Error while executing command "${command}"`, error);
181
+ let commandOptions = commandContext[commandName] || {};
182
+ let commandInstance = new Klass(application, commandOptions);
183
+ let result = await commandInstance.execute.call(commandInstance, commandOptions);
187
184
 
188
- if (application)
189
- await application.stop(1);
190
- }
191
- }, [ Klass.commandString ]);
185
+ await application.stop(result || 0);
186
+ } catch (error) {
187
+ console.log(`Error while executing command "${commandName}"`, error);
192
188
 
193
- rootCommand.parse();
189
+ if (application)
190
+ await application.stop(1);
191
+ }
194
192
  };
195
193
 
196
194
  CommandBase.commands[commandName] = Klass;
@@ -203,7 +201,6 @@ function defineCommand(_commandName, definer, _parent) {
203
201
  });
204
202
  }
205
203
 
206
-
207
204
  return Klass;
208
205
  }
209
206
 
@@ -292,7 +289,7 @@ function loadMythixConfig(_mythixConfigPath, _appRootPath) {
292
289
  try {
293
290
  let stats = FileSystem.statSync(mythixConfigPath);
294
291
  if (stats.isDirectory())
295
- configPath = Path.resolve(mythixConfigPath, '.mythix-config.js');
292
+ configPath = Path.resolve(mythixConfigPath, '.mythix-config');
296
293
  else if (stats.isFile(mythixConfigPath))
297
294
  mythixConfigPath = Path.dirname(mythixConfigPath);
298
295
  } catch (error) {
@@ -309,7 +306,7 @@ function loadMythixConfig(_mythixConfigPath, _appRootPath) {
309
306
  let defaultConfig = {
310
307
  runtime: process.env.MYTHIX_RUNTIME || 'node',
311
308
  runtimeArgs: (process.env.MYTHIX_RUNTIME_ARGS || '').split(/\s+/g).filter(Boolean),
312
- applicationPath: (config) => Path.resolve(config.appRootPath, 'application.js'),
309
+ applicationPath: (config) => Path.resolve(config.appRootPath, 'application'),
313
310
  getApplicationClass: (config) => {
314
311
  let Application = require(config.applicationPath);
315
312
  if (Application && typeof Application !== 'function' && typeof Application.Application === 'function')
@@ -367,27 +364,34 @@ function spawnCommand(args, options, _config) {
367
364
  });
368
365
  }
369
366
 
370
- async function executeCommand(configPath, applicationCommandsPath, yargsPath, simpleYargsPath, argv, commandPath, command, _config) {
367
+ async function executeCommand(_config, appOptions, commandContext, CommandKlass, argv) {
368
+ let command = commandContext.command;
369
+
371
370
  try {
372
- let config = _config || {};
373
- let Klass = CommandBase.commands[command];
374
- let nodeArguments = ((config.runtime || 'node') === 'node') ? (Klass.nodeArguments || []) : [];
375
- let args = nodeArguments.concat([ commandPath ], argv);
371
+ let config = _config || {};
372
+ let configPath = commandContext.config;
373
+ let commandPath = CommandKlass.path;
374
+ let commandsPath = appOptions.commandsPath;
375
+ let runtime = commandContext.runtime || config.runtime || process.env.MYTHIX_RUNTIME || 'node';
376
+ let runtimeArguments = ((CommandKlass.runtimeArguments || {})[runtime]) || [];
377
+ let args = runtimeArguments.concat([ commandPath ], argv);
376
378
 
377
379
  let code = await spawnCommand(
378
380
  args,
379
381
  {
380
382
  env: {
381
- MYTHIX_RUNTIME: config.runtime || process.env.MYTHIX_RUNTIME || 'node',
383
+ NODE_ENV: commandContext.environment || '',
384
+ MYTHIX_RUNTIME: runtime,
382
385
  MYTHIX_CONFIG_PATH: configPath,
383
386
  MYTHIX_COMMAND_PATH: commandPath,
384
- MYTHIX_APPLICATION_COMMANDS: applicationCommandsPath,
385
- MYTHIX_YARGS_PATH: yargsPath,
386
- MYTHIX_SIMPLE_YARGS_PATH: simpleYargsPath,
387
+ MYTHIX_APPLICATION_COMMANDS: commandsPath,
387
388
  MYTHIX_EXECUTE_COMMAND: command,
388
389
  },
389
390
  },
390
- config,
391
+ {
392
+ ...config,
393
+ ...commandContext,
394
+ },
391
395
  );
392
396
 
393
397
  process.exit(code);
@@ -37,15 +37,16 @@ ${postCode}
37
37
 
38
38
  module.exports = defineCommand('makemigrations', ({ Parent }) => {
39
39
  return class MakeMigrationsCommand extends Parent {
40
- static description = 'Create migration for current model schema';
41
-
42
- // static nodeArguments = [ '--inspect-brk' ];
43
-
44
- static commandArguments = `
45
- [-p,-preview:boolean(Preview what the generated migration would look like without migrating anything)]
46
- [-n,-name:string(Specify a name for your migration)]
47
- [-c,-comment:string(Specify a comment for your migration)]
48
- `;
40
+ static commandArguments() {
41
+ return {
42
+ help: {
43
+ // eslint-disable-next-line key-spacing
44
+ '@usage': 'mythix-cli makemigrations [options]',
45
+ '@title': 'Generate a migration file',
46
+ '-n={name} | -n {name} | --name={name} | --name {name}': 'Specify the name of the generated migration file',
47
+ },
48
+ };
49
+ }
49
50
 
50
51
  getRevisionNumber() {
51
52
  let date = new Date();
@@ -1120,8 +1121,6 @@ module.exports = defineCommand('makemigrations', ({ Parent }) => {
1120
1121
  let models = dbSchema.models;
1121
1122
  let dbTableSchema = dbSchema.dbTableSchema;
1122
1123
 
1123
- debugger;
1124
-
1125
1124
  // Now create migration
1126
1125
  for (let i = 0, il = schemaDiff.length; i < il; i++) {
1127
1126
  let thisDiff = schemaDiff[i];
@@ -10,13 +10,25 @@ const MILLISECONDS_PER_SECOND = 1000.0;
10
10
 
11
11
  module.exports = defineCommand('migrate', ({ Parent }) => {
12
12
  return class MigrateCommand extends Parent {
13
- static description = 'Run all migrations that have not yet been ran';
13
+ static commandArguments() {
14
+ return {
15
+ help: {
16
+ /* eslint-disable key-spacing */
17
+ '@usage': 'mythix-cli migrate [options]',
18
+ '@title': 'Run or rollback migrations',
19
+ '-r={revision number} | -r {revision number} | --revision={revision number} | --revision {revision number}': 'Start operation at revision specified. For rollbacks, this specifies the revision to stop at (inclusive).',
20
+ '--rollback': 'Rollback migrations to the revision number specified, or rollback the last migration if no revision number is specified.',
21
+ },
22
+ runner: ({ $, Types }) => {
23
+ $('-r', Types.STRING(), { name: 'revision' });
24
+ $('--revision', Types.STRING(), { name: 'revision' });
25
+
26
+ $('--rollback', Types.STRING());
14
27
 
15
- static commandArguments = `
16
- [-r,-revision:string(Start operation at revision specified. For rollbacks, this specifies the revision to stop at [inclusive])]
17
- [-rollback:boolean(Reverse migration order, rolling back each migration from latest to specified revision)=false(Default is false)]
18
- [-transaction:boolean(Use a DB transaction for migrations)=false(Default is false)]
19
- `;
28
+ return true;
29
+ },
30
+ };
31
+ }
20
32
 
21
33
  getMigrationFiles(migrationsPath) {
22
34
  try {
@@ -8,9 +8,16 @@ const TAB_SIZE = 8;
8
8
 
9
9
  module.exports = defineCommand('routes', ({ Parent }) => {
10
10
  return class RoutesCommand extends Parent {
11
- static description = 'List application routes';
12
-
13
- static applicationConfig = { database: false, logger: { level: Logger.LEVEL_ERROR } };
11
+ static applicationConfig = { database: false, logger: { level: Logger.LEVEL_ERROR } };
12
+
13
+ static commandArguments() {
14
+ return {
15
+ help: {
16
+ '@usage': 'mythix-cli routes',
17
+ '@title': 'List application routes',
18
+ },
19
+ };
20
+ }
14
21
 
15
22
  buildRoutes(httpServer, routes) {
16
23
  let application = this.getApplication();
@@ -5,12 +5,36 @@ const { defineCommand } = require('./cli-utils');
5
5
 
6
6
  module.exports = defineCommand('serve', ({ Parent }) => {
7
7
  return class ServeCommand extends Parent {
8
- static description = 'Start application and HTTP server';
9
-
10
- static commandArguments = '[--host:string(Specify hostname or IP to listen on)] [--port:integer(Specify port to listen on)]';
11
-
12
8
  static applicationConfig = () => ({ autoStart: false, exitOnShutdown: 0 });
13
9
 
10
+ static commandArguments() {
11
+ return {
12
+ help: {
13
+ /* eslint-disable key-spacing */
14
+ '@usage': 'mythix-cli serve [options]',
15
+ '@title': 'Start application and HTTP server',
16
+ '--host={hostname or IP} | --host {hostname or IP}': 'Specify hostname or IP to listen on.',
17
+ '--port={port number} | --port {port number}': 'Specify port to listen on.',
18
+ },
19
+ runner: ({ $, Types }) => {
20
+ $('--host', Types.STRING());
21
+ $('--port', Types.INTEGER({
22
+ validate: (value) => {
23
+ // eslint-disable-next-line no-magic-numbers
24
+ if (value < 0 || value > 65535) {
25
+ console.error('Invalid "--port" specified... must be in the range 0-65535');
26
+ return false;
27
+ }
28
+
29
+ return true;
30
+ },
31
+ }));
32
+
33
+ return true;
34
+ },
35
+ };
36
+ }
37
+
14
38
  execute(args) {
15
39
  // eslint-disable-next-line no-async-promise-executor
16
40
  return new Promise(async (resolve, reject) => {
@@ -13,9 +13,18 @@ const {
13
13
 
14
14
  module.exports = defineCommand('shell', ({ Parent }) => {
15
15
  return class ShellCommand extends Parent {
16
- static description = 'Drop into an application shell to execute commands directly';
16
+ static runtimeArguments = {
17
+ 'node': [ '--experimental-repl-await', '--experimental-top-level-await' ],
18
+ };
17
19
 
18
- static nodeArguments = [ '--experimental-repl-await', '--experimental-top-level-await' ];
20
+ static commandArguments() {
21
+ return {
22
+ help: {
23
+ '@usage': 'mythix-cli shell',
24
+ '@title': 'Drop into an server shell to execute commands directly',
25
+ },
26
+ };
27
+ }
19
28
 
20
29
  constructor(...args) {
21
30
  super(...args);
@@ -23,13 +32,13 @@ module.exports = defineCommand('shell', ({ Parent }) => {
23
32
  Object.defineProperties(this, {
24
33
  'defaultHeaders': {
25
34
  writable: true,
26
- enumberable: false,
35
+ enumerable: false,
27
36
  configurable: true,
28
37
  value: {},
29
38
  },
30
39
  'defaultURL': {
31
40
  writable: true,
32
- enumberable: false,
41
+ enumerable: false,
33
42
  configurable: true,
34
43
  value: null,
35
44
  },
@@ -8,36 +8,36 @@ class ControllerBase {
8
8
  Object.defineProperties(this, {
9
9
  'application': {
10
10
  writable: false,
11
- enumberable: false,
11
+ enumerable: false,
12
12
  configurable: true,
13
13
  value: application,
14
14
  },
15
15
  'request': {
16
16
  writable: false,
17
- enumberable: false,
17
+ enumerable: false,
18
18
  configurable: true,
19
19
  value: request,
20
20
  },
21
21
  'response': {
22
22
  writable: false,
23
- enumberable: false,
23
+ enumerable: false,
24
24
  configurable: true,
25
25
  value: response,
26
26
  },
27
27
  'logger': {
28
28
  writable: true,
29
- enumberable: false,
29
+ enumerable: false,
30
30
  configurable: true,
31
31
  value: logger,
32
32
  },
33
33
  'route': {
34
34
  writable: true,
35
- enumberable: false,
35
+ enumerable: false,
36
36
  configurable: true,
37
37
  value: null,
38
38
  },
39
39
  'method': {
40
- enumberable: false,
40
+ enumerable: false,
41
41
  configurable: true,
42
42
  get: () => {
43
43
  if (!this.request)
@@ -48,7 +48,7 @@ class ControllerBase {
48
48
  set: () => {},
49
49
  },
50
50
  'contentType': {
51
- enumberable: false,
51
+ enumerable: false,
52
52
  configurable: true,
53
53
  get: () => {
54
54
  if (!this.request)
@@ -60,7 +60,7 @@ class ControllerBase {
60
60
  },
61
61
  'responseStatusCode': {
62
62
  writable: true,
63
- enumberable: false,
63
+ enumerable: false,
64
64
  configurable: true,
65
65
  value: 200,
66
66
  },
@@ -38,7 +38,7 @@ class ControllerModule extends BaseModule {
38
38
  Object.defineProperties(application, {
39
39
  'getController': {
40
40
  writable: true,
41
- enumberable: false,
41
+ enumerable: false,
42
42
  configurable: true,
43
43
  value: this.getController.bind(this),
44
44
  },
@@ -54,13 +54,13 @@ function buildPatternMatcher(_patterns, _opts) {
54
54
  Object.defineProperties(matchFunc, {
55
55
  'regexp': {
56
56
  writable: false,
57
- enumberable: false,
57
+ enumerable: false,
58
58
  configurable: false,
59
59
  value: matchRE,
60
60
  },
61
61
  'directPatterns': {
62
62
  writable: false,
63
- enumberable: false,
63
+ enumerable: false,
64
64
  configurable: false,
65
65
  value: undefined,
66
66
  },
@@ -118,13 +118,13 @@ function buildPatternMatcher(_patterns, _opts) {
118
118
  Object.defineProperties(matchFunc, {
119
119
  'regexp': {
120
120
  writable: false,
121
- enumberable: false,
121
+ enumerable: false,
122
122
  configurable: false,
123
123
  value: matchRE,
124
124
  },
125
125
  'directPatterns': {
126
126
  writable: false,
127
- enumberable: false,
127
+ enumerable: false,
128
128
  configurable: false,
129
129
  value: directPatterns,
130
130
  },
@@ -252,19 +252,19 @@ function buildPathMatcher(routeName, customParserTypes) {
252
252
  Object.defineProperties(matchFunc, {
253
253
  'regexp': {
254
254
  writable: false,
255
- enumberable: false,
255
+ enumerable: false,
256
256
  configurable: false,
257
257
  value: matcherRE,
258
258
  },
259
259
  'params': {
260
260
  writable: false,
261
- enumberable: false,
261
+ enumerable: false,
262
262
  configurable: false,
263
263
  value: params,
264
264
  },
265
265
  'sanitizedPath': {
266
266
  writable: false,
267
- enumberable: false,
267
+ enumerable: false,
268
268
  configurable: false,
269
269
  value: sanitizedPath,
270
270
  },
@@ -117,19 +117,19 @@ function nodeRequestHandler(routeName, requestOptions) {
117
117
  Object.defineProperties(data, {
118
118
  '__response': {
119
119
  writable: true,
120
- enumberable: false,
120
+ enumerable: false,
121
121
  configurable: true,
122
122
  value: response,
123
123
  },
124
124
  '__statusCode': {
125
125
  writable: true,
126
- enumberable: false,
126
+ enumerable: false,
127
127
  configurable: true,
128
128
  value: response.status,
129
129
  },
130
130
  '__statusText': {
131
131
  writable: true,
132
- enumberable: false,
132
+ enumerable: false,
133
133
  configurable: true,
134
134
  value: response.statusText,
135
135
  },
@@ -230,19 +230,19 @@ function browserRequestHandler(routeName, requestOptions) {
230
230
  Object.defineProperties(data, {
231
231
  '__response': {
232
232
  writable: true,
233
- enumberable: false,
233
+ enumerable: false,
234
234
  configurable: true,
235
235
  value: response,
236
236
  },
237
237
  '__statusCode': {
238
238
  writable: true,
239
- enumberable: false,
239
+ enumerable: false,
240
240
  configurable: true,
241
241
  value: response.status,
242
242
  },
243
243
  '__statusText': {
244
244
  writable: true,
245
- enumberable: false,
245
+ enumerable: false,
246
246
  configurable: true,
247
247
  value: response.statusText,
248
248
  },
@@ -579,7 +579,7 @@ function generateAPIInterface(routes, _options) {
579
579
 
580
580
  function assignHelp(func, methodName, help) {
581
581
  Object.defineProperty(func, 'help', {
582
- enumberable: false,
582
+ enumerable: false,
583
583
  configurable: false,
584
584
  get: () => {
585
585
  if (!help || !help.description) {
@@ -38,13 +38,13 @@ class HTTPServerModule extends BaseModule {
38
38
  Object.defineProperties(application, {
39
39
  'getHTTPServer': {
40
40
  writable: true,
41
- enumberable: false,
41
+ enumerable: false,
42
42
  configurable: true,
43
43
  value: this.getHTTPServer.bind(this),
44
44
  },
45
45
  'getHTTPServerConfig': {
46
46
  writable: true,
47
- enumberable: false,
47
+ enumerable: false,
48
48
  configurable: true,
49
49
  value: this.getHTTPServerConfig.bind(this),
50
50
  },
@@ -50,19 +50,19 @@ class HTTPServer {
50
50
  Object.defineProperties(this, {
51
51
  'application': {
52
52
  writable: false,
53
- enumberable: false,
53
+ enumerable: false,
54
54
  configurable: true,
55
55
  value: application,
56
56
  },
57
57
  'server': {
58
58
  writable: true,
59
- enumberable: false,
59
+ enumerable: false,
60
60
  configurable: true,
61
61
  value: null,
62
62
  },
63
63
  'options': {
64
64
  writable: false,
65
- enumberable: false,
65
+ enumerable: false,
66
66
  configurable: true,
67
67
  value: opts,
68
68
  },
@@ -30,13 +30,13 @@ class ModelModule extends BaseModule {
30
30
  Object.defineProperties(application, {
31
31
  'getModel': {
32
32
  writable: true,
33
- enumberable: false,
33
+ enumerable: false,
34
34
  configurable: true,
35
35
  value: this.getModel.bind(this),
36
36
  },
37
37
  'getModels': {
38
38
  writable: true,
39
- enumberable: false,
39
+ enumerable: false,
40
40
  configurable: true,
41
41
  value: this.getModels.bind(this),
42
42
  },
@@ -63,7 +63,7 @@ class Model extends _Model {
63
63
  Object.defineProperties(this, {
64
64
  [name]: {
65
65
  writable: true,
66
- enumberable: false,
66
+ enumerable: false,
67
67
  configurable: true,
68
68
  value: boundMethod,
69
69
  },
@@ -9,7 +9,7 @@ class BaseModule {
9
9
  Object.defineProperties(this, {
10
10
  'application': {
11
11
  writable: false,
12
- enumberable: false,
12
+ enumerable: false,
13
13
  configurable: true,
14
14
  value: application,
15
15
  },
@@ -38,19 +38,19 @@ class DatabaseModule extends BaseModule {
38
38
  Object.defineProperties(application, {
39
39
  'getDBTablePrefix': {
40
40
  writable: true,
41
- enumberable: false,
41
+ enumerable: false,
42
42
  configurable: true,
43
43
  value: this.getTablePrefix.bind(this),
44
44
  },
45
45
  'getDBConnection': {
46
46
  writable: true,
47
- enumberable: false,
47
+ enumerable: false,
48
48
  configurable: true,
49
49
  value: this.getConnection.bind(this),
50
50
  },
51
51
  'getDBConfig': {
52
52
  writable: true,
53
- enumberable: false,
53
+ enumerable: false,
54
54
  configurable: true,
55
55
  value: this.getConfig.bind(this),
56
56
  },
@@ -38,7 +38,7 @@ class FileWatcherModule extends BaseModule {
38
38
  Object.defineProperties(application, {
39
39
  'autoReload': {
40
40
  writable: true,
41
- enumberable: false,
41
+ enumerable: false,
42
42
  configurable: true,
43
43
  value: this.autoReload.bind(this),
44
44
  },
@@ -5,19 +5,19 @@ class TaskBase {
5
5
  Object.defineProperties(this, {
6
6
  'application': {
7
7
  writable: false,
8
- enumberable: false,
8
+ enumerable: false,
9
9
  configurable: true,
10
10
  value: application,
11
11
  },
12
12
  'logger': {
13
13
  writable: true,
14
- enumberable: false,
14
+ enumerable: false,
15
15
  configurable: true,
16
16
  value: logger,
17
17
  },
18
18
  'runID': {
19
19
  writable: false,
20
- enumberable: false,
20
+ enumerable: false,
21
21
  configurable: true,
22
22
  value: runID,
23
23
  },
@@ -257,7 +257,7 @@ class TaskModule extends BaseModule {
257
257
  Object.defineProperties(this.tasks, {
258
258
  '_intervalTimerID': {
259
259
  writable: true,
260
- enumberable: false,
260
+ enumerable: false,
261
261
  configurable: true,
262
262
  value: setInterval(this.runTasks.bind(this), 1 * MILLISECONDS_PER_SECOND),
263
263
  },
@@ -16,25 +16,25 @@ class TimeHelpers {
16
16
  Object.defineProperties(this, {
17
17
  '_days': {
18
18
  writable: true,
19
- enumberable: false,
19
+ enumerable: false,
20
20
  configurable: true,
21
21
  value: _days || 0,
22
22
  },
23
23
  '_hours': {
24
24
  writable: true,
25
- enumberable: false,
25
+ enumerable: false,
26
26
  configurable: true,
27
27
  value: _hours || 0,
28
28
  },
29
29
  '_minutes': {
30
30
  writable: true,
31
- enumberable: false,
31
+ enumerable: false,
32
32
  configurable: true,
33
33
  value: _minutes || 0,
34
34
  },
35
35
  '_seconds': {
36
36
  writable: true,
37
- enumberable: false,
37
+ enumerable: false,
38
38
  configurable: true,
39
39
  value: _seconds || 0,
40
40
  },
@@ -12,13 +12,13 @@ class HTTPInterface {
12
12
  Object.defineProperties(this, {
13
13
  'defaultURL': {
14
14
  writable: true,
15
- enumberable: false,
15
+ enumerable: false,
16
16
  configurable: true,
17
17
  value: null,
18
18
  },
19
19
  'defaultHeaders': {
20
20
  writable: true,
21
- enumberable: false,
21
+ enumerable: false,
22
22
  configurable: true,
23
23
  value: {},
24
24
  },
@@ -37,7 +37,7 @@ class TestHTTPServerModule extends HTTPServerModule {
37
37
  Object.defineProperties(this, {
38
38
  'host': {
39
39
  writable: true,
40
- enumberable: false,
40
+ enumerable: false,
41
41
  configurable: true,
42
42
  value: {
43
43
  hostname: httpServerConfig.host,
@@ -81,7 +81,7 @@ function createTestApplication(Application) {
81
81
  Object.defineProperties(this, {
82
82
  'httpInterface': {
83
83
  writable: true,
84
- enumberable: false,
84
+ enumerable: false,
85
85
  configurable: true,
86
86
  value: new HTTPInterface(),
87
87
  },