Skip to content

Commit

Permalink
fix(shell): throw error unless commands an object
Browse files Browse the repository at this point in the history
  • Loading branch information
wdavidw committed Feb 24, 2022
1 parent b9daeb2 commit 96ef828
Show file tree
Hide file tree
Showing 28 changed files with 201 additions and 181 deletions.
2 changes: 1 addition & 1 deletion docs/content/api/compile.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ const app = shell(
description: "Web server listen port" } } } } })
```

Called with only the `config` option, the `compile` method convert a literal object into a shell command:
Called with only the `config` option, the `compile` method convert an object literal into a shell command:

```javascript
app.compile({
Expand Down
23 changes: 1 addition & 22 deletions docs/content/api/help.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,25 +63,4 @@ The same apply to every commands:

Internally, an `help` command is registered if at least another command is defined:

```js
const assert = require("assert")
const shell = require("shell")

assert.deepStrictEqual(
shell({
commands: [ { name: 'secret' } ]
}).config.commands.help
, {
name: 'help',
description: 'Display help information about myapp',
main: {
name: 'name', description: 'Help about a specific command'
},
help: true,
strict: false,
shortcuts: {},
command: 'command',
options: {},
commands: {}
} )
```
`embed:api/help/command.js`
25 changes: 3 additions & 22 deletions docs/content/api/parse.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,36 +21,17 @@ Convert an arguments list to data.

## Description

The method convert an array containing the command line arguments into a literal object in flatten mode or an array in extended mode.
The method convert an array containing the command line arguments into an object literal in flatten mode or an array in extended mode.

Only pass the data without the script name when providing an argument list in the form of an array or a string. It obtains the arguments from `process.argv` when `arguments` is not provided or is the [Node.js process](https://nodejs.org/api/process.html).

## Examples

Considering a "server" application containing a "start" command and initialised with the following configuration:

```js
require("should")
const shell = require("shell")
const app = shell(
{ name: "server",
description: "Manage a web server",
options:
{ "config":
{ shortcut: "c" } },
commands:
{ "start":
{ description: "Start a web server",
options:
{ "host":
{ shortcut: "h",
description: "Web server listen host"},
"port":
{ shortcut: "p", type: "integer",
description: "Web server listen port" } } } } })
```
`embed:api/parse/example.js`

Called with only the `--config` argument, the `parse` method convert the shell command into a literal object:
Called with only the `--config` argument, the `parse` method convert the shell command into an object literal:

```js
app.parse([
Expand Down
3 changes: 2 additions & 1 deletion docs/src/utils/typography.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ const theme = {
marginBottom: `${rhythm(1)}`,
},
'main .display-embed-file-highlight pre': {
marginBottom: '0',
marginBottom: '2px',
},
'main .display-embed-file': {
textAlign: 'right',
Expand All @@ -82,6 +82,7 @@ const theme = {
padding: '.3rem .5rem',
marginRight: '.5rem',
fontWeight: '300',
borderTop: '3px solid rgba(45,45,45,1)',
borderRight: '1px solid rgba(255,255,255,.2)',
borderBottom: '1px solid rgba(255,255,255,.2)',
borderLeft: '1px solid rgba(255,255,255,.2)',
Expand Down
4 changes: 2 additions & 2 deletions packages/grpc_server/dist/cjs/index.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ const get_handlers = function(definition) {
},
config: function(call, callback) {
var config;
config = this.confx(call.request.command).get();
config = this.config(call.request.command).get();
return callback(null, {
config: config
});
Expand Down Expand Up @@ -120,7 +120,7 @@ const grpc_start = function(callback) {
if (this._server && this._server.started) {
throw shell.utils.error('GRPC Server Already Started');
}
const appconfig = this.confx().get();
const appconfig = this.config().get();
// Load the definition
const packageDefinition = proto__default["default"].loadSync();
const shell_definition = grpc__default["default"].loadPackageDefinition(packageDefinition).shell;
Expand Down
4 changes: 2 additions & 2 deletions packages/grpc_server/dist/esm/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ const get_handlers = function(definition) {
},
config: function(call, callback) {
var config;
config = this.confx(call.request.command).get();
config = this.config(call.request.command).get();
return callback(null, {
config: config
});
Expand Down Expand Up @@ -113,7 +113,7 @@ const grpc_start = function(callback) {
if (this._server && this._server.started) {
throw utils.error('GRPC Server Already Started');
}
const appconfig = this.confx().get();
const appconfig = this.config().get();
// Load the definition
const packageDefinition = proto.loadSync();
const shell_definition = grpc.loadPackageDefinition(packageDefinition).shell;
Expand Down
4 changes: 2 additions & 2 deletions packages/grpc_server/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ const get_handlers = function(definition) {
},
config: function(call, callback) {
var config;
config = this.confx(call.request.command).get();
config = this.config(call.request.command).get();
return callback(null, {
config: config
});
Expand Down Expand Up @@ -123,7 +123,7 @@ const grpc_start = function(callback) {
if (this._server && this._server.started) {
throw utils.error('GRPC Server Already Started');
}
const appconfig = this.confx().get();
const appconfig = this.config().get();
// Load the definition
const packageDefinition = proto.loadSync();
const shell_definition = grpc.loadPackageDefinition(packageDefinition).shell;
Expand Down
2 changes: 1 addition & 1 deletion packages/grpc_server/test/config.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ describe 'grpc_server.config', ->
app = shell
plugins: [grpc_server]
grpc: {}
app.confx().get().grpc
app.config().get().grpc
.should.eql
'address': '127.0.0.1'
'command_protobuf': false
Expand Down
60 changes: 31 additions & 29 deletions packages/shell/dist/cjs/index.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ const route = function(context = {}, ...args) {
} else if (!mixme.is_object_literal(context)) {
throw error(['Invalid Router Arguments:', 'first argument must be a context object or the argv array,', `got ${JSON.stringify(context)}`]);
}
const appconfig = this.confx().get();
const appconfig = this.config().get();
const route_load = (handler) => {
if (typeof handler === 'string') {
return this.load(handler);
Expand All @@ -180,7 +180,7 @@ const route = function(context = {}, ...args) {
}
};
const route_call = (handler, command, params, err, args) => {
const config = this.confx().get();
const config = this.config().get();
context = {
argv: process.argv.slice(2),
command: command,
Expand Down Expand Up @@ -222,7 +222,7 @@ const route = function(context = {}, ...args) {
const route_error = (err, command) => {
context.argv = command.length ? ['help', ...command] : ['--help'];
const params = this.parse(context.argv);
const handler = route_load(this.config.router.handler);
const handler = route_load(this._config.router.handler);
if (handler.then){
return handler
.then(function(handler){
Expand Down Expand Up @@ -292,7 +292,7 @@ const route = function(context = {}, ...args) {
command.push[appconfig.command];
}
}
const config = this.confx(command).get();
const config = this.config(command).get();
return route_from_config(config, command || [], params);
}
};
Expand All @@ -305,18 +305,18 @@ var configPlugin = {
hooks: {
'shell:init': function({shell}){
shell.collision = {};
shell.confx = confx.bind(shell);
shell.config = config.bind(shell);
}
}
};

const confx = function(command = []) {
const config = function(command = []) {
const ctx = this;
if (typeof command === 'string') {
command = [command];
}
// command = [...pcommand, ...command]
let lconfig = this.config;
let lconfig = this._config;
for (const name of command) {
// A new command doesn't have a config registered yet
if(!lconfig.commands[name]) lconfig.commands[name] = {};
Expand All @@ -326,7 +326,7 @@ const confx = function(command = []) {
main: builder_main.call(this, command),
options: builder_options.call(this, command),
get: function() {
let source = ctx.config;
let source = ctx._config;
const strict = source.strict;
for (const name of command) {
if (!source.commands[name]) {
Expand All @@ -350,7 +350,7 @@ const confx = function(command = []) {
config.command = command;
}
for (const name in config.commands) {
config.commands[name] = ctx.confx([...command, name]).get();
config.commands[name] = ctx.config([...command, name]).get();
}
config.options = this.options.show();
config.shortcuts = {};
Expand All @@ -376,7 +376,7 @@ const confx = function(command = []) {
} else {
throw error(['Invalid Commands Set Arguments:', 'expect 1 or 2 arguments, got 0']);
}
lconfig = ctx.config;
lconfig = ctx._config;
for (const name of command) {
// A new command doesn't have a config registered yet
lconfig = lconfig.commands[name];
Expand Down Expand Up @@ -423,6 +423,8 @@ const confx = function(command = []) {
}
if (config.commands == null) {
config.commands = {};
}else if (!mixme.is_object_literal(config.commands)){
throw error(['Invalid Command Configuration', 'commands must be an object,', `got ${JSON.stringify(config.commands)}`])
}
if (config.options == null) {
config.options = {};
Expand All @@ -434,7 +436,7 @@ const confx = function(command = []) {
this.options(key).set(config.options[key]);
}
for (const key in config.commands) {
ctx.confx([...command, key]).set(config.commands[key]);
ctx.config([...command, key]).set(config.commands[key]);
}
return this.main.set(config.main);
}
Expand All @@ -451,11 +453,11 @@ const builder_main = function(commands) {
const ctx = this;
const builder = {
get: function() {
const config = ctx.confx(commands).raw();
const config = ctx.config(commands).raw();
return mixme.clone(config.main);
},
set: function(value) {
const config = ctx.confx(commands).raw();
const config = ctx.config(commands).raw();
if (value === void 0) {
// Do nothing if value is undefined
return builder;
Expand All @@ -475,7 +477,7 @@ const builder_main = function(commands) {
}
// Ensure there is no conflict with command
// Get root configuration to extract command name
if (value.name === ctx.confx([]).raw().command) {
if (value.name === ctx.config([]).raw().command) {
throw error(['Conflicting Main Value:', 'main name is conflicting with the command name,', `got \`${JSON.stringify(value.name)}\``]);
}
config.main = value;
Expand Down Expand Up @@ -506,11 +508,11 @@ const builder_options = function(commands) {
return copy;
},
remove: function(name) {
const config = ctx.confx(commands).raw();
const config = ctx.config(commands).raw();
return delete config.options[name];
},
set: function() {
const config = ctx.confx(commands).raw();
const config = ctx.config(commands).raw();
let values = null;
if (arguments.length === 2) {
values = {
Expand All @@ -525,7 +527,7 @@ const builder_options = function(commands) {
throw error(['Invalid Options:', `expect an object, got ${JSON.stringify(config.options)}`]);
}
const option = config.options[name] = mixme.merge(config.options[name], values);
if (!ctx.config.extended) {
if (!ctx._config.extended) {
if (!option.disabled && commands.length) {
// Compare the current command with the options previously registered
const collide = ctx.collision[name] && ctx.collision[name].filter(function(cmd, i) {
Expand Down Expand Up @@ -560,7 +562,7 @@ const builder_options = function(commands) {
builder.__proto__ = {
get_cascaded: function() {
const options = {};
let config = ctx.confx().raw();
let config = ctx.config().raw();
for (let i=0; i<commands.length; i++) {
const command = commands[i];
for (const name in config.options) {
Expand All @@ -586,7 +588,7 @@ const builder_options = function(commands) {
option.transient = true;
}
// Get app/command configuration
const config = ctx.confx(commands).raw();
const config = ctx.config(commands).raw();
// Merge cascaded with local options
options = mixme.merge(options, config.options);
for (const name in options) {
Expand Down Expand Up @@ -617,7 +619,7 @@ var args = {
// Method `parse([arguments])`
// https://shell.js.org/api/parse/
const parse = function(argv = process, options = {}) {
const appconfig = this.confx().get();
const appconfig = this.config().get();
if (options.extended == null) {
options.extended = appconfig.extended;
}
Expand Down Expand Up @@ -819,7 +821,7 @@ const parse = function(argv = process, options = {}) {
// https://shell.js.org/api/compile/
const compile = function(data, options = {}) {
let argv = options.script ? [process.execPath, options.script] : [];
const appconfig = this.confx().get();
const appconfig = this.config().get();
if (!mixme.is_object_literal(options)) {
throw error(['Invalid Compile Arguments:', '2nd argument option must be an object,', `got ${JSON.stringify(options)}`]);
}
Expand Down Expand Up @@ -1018,7 +1020,7 @@ var help = {
// https://shell.js.org/api/helping/
const helping = function(params, options = {}) {
params = mixme.clone(params);
const appconfig = this.confx().get();
const appconfig = this.config().get();
let commands;
if (options.extended == null) {
options.extended = appconfig.extended;
Expand Down Expand Up @@ -1119,7 +1121,7 @@ const help$1 = function(commands = [], options = {}) {
if (!Array.isArray(commands)) {
throw error(['Invalid Help Arguments:', 'expect commands to be an array as first argument,', `got ${JSON.stringify(commands)}`]);
}
const appconfig = this.confx().get();
const appconfig = this.config().get();
let config = appconfig;
const configs = [config];
for (const i in commands) {
Expand Down Expand Up @@ -1343,12 +1345,12 @@ const Shell = function(config) {
for(const plugin of config.plugins){
this.plugins.register(plugin);
}
this.config = config;
this._config = config;
this.plugins.call_sync({
args: {shell: this},
name: 'shell:init'
});
this.confx().set(this.config);
this.config().set(this._config);
return this;
};

Expand All @@ -1359,15 +1361,15 @@ Shell.prototype.load = async function(module, namespace = 'default') {
throw error(['Invalid Load Argument:', 'load is expecting string,', `got ${JSON.stringify(module)}`].join(' '));
}
// Custom loader defined in the configuration
if (this.config.load) {
if (this._config.load) {
// Provided by the user as a module path
if (typeof this.config.load === 'string') {
if (typeof this._config.load === 'string') {
// todo, shall be async and return module.default
const loader = await load(this.config.load /* `, this.config.load.namespace` */);
const loader = await load(this._config.load /* `, this._config.load.namespace` */);
return loader(module, namespace);
// Provided by the user as a function
} else {
return await this.config.load(module, namespace);
return await this._config.load(module, namespace);
}
} else {
return await load(module, namespace);
Expand Down
Loading

0 comments on commit 96ef828

Please sign in to comment.