1 | 'use strict';
|
2 |
|
3 | var explicit = require('explicit'),
|
4 | fs = require('fs'),
|
5 | joi = require('joi'),
|
6 | minimist = require('minimist'),
|
7 | path = require('path');
|
8 |
|
9 | var command = joi.object({
|
10 | order: joi.number().integer().default(0).optional(),
|
11 | handler: joi.func().required(),
|
12 | filter: joi.func().optional(),
|
13 | aliases: joi.array().min(1).items(joi.string())
|
14 | }).unknown(),
|
15 | commands = joi.array().items(command),
|
16 | itemFilter = function itemFilter (scope, item) {
|
17 | return typeof item.filter === 'function' ? item.filter(scope) : true;
|
18 | },
|
19 | loadFromFolder = function loadFromFolder (folder) {
|
20 | return fs.readdirSync(folder).filter(function (file) {
|
21 | return path.extname(file) === '.js';
|
22 | }).map(function (file) {
|
23 | var name = file.substr(0, file.length - '.js'.length);
|
24 | var cmd = require(path.join(folder, name));
|
25 | if (!cmd.aliases) {
|
26 | cmd.aliases = [];
|
27 | }
|
28 | cmd.aliases.unshift(name);
|
29 | return cmd;
|
30 | });
|
31 | },
|
32 | orderSort = function orderSort(a, b) {
|
33 | var orderA = a.order || 0,
|
34 | orderB = b.order || 0;
|
35 |
|
36 | if (orderA > orderB) {
|
37 | return 1;
|
38 | } else if (orderA < orderB) {
|
39 | return -1;
|
40 | }
|
41 | return 0;
|
42 | };
|
43 |
|
44 | var Commandico = explicit({
|
45 | $one: true,
|
46 | $args: [
|
47 | joi.any().meta('scope'),
|
48 | joi.string().meta('default').required()
|
49 | ],
|
50 | $: function (scope, defaultCommand) {
|
51 | if (!(this instanceof Commandico)) {
|
52 | return new Commandico(scope, defaultCommand);
|
53 | }
|
54 | this.scope = scope;
|
55 | this.defaultCommand = defaultCommand;
|
56 | this.commands = [];
|
57 | this.modifiers = [];
|
58 | }
|
59 | }).valid;
|
60 |
|
61 | Commandico.prototype = explicit({
|
62 | loadCommands: {
|
63 | $args: [joi.string().meta('folder').required()],
|
64 | $assert: true,
|
65 | $: function (folder) {
|
66 | return this.addCommands(loadFromFolder(folder));
|
67 | }
|
68 | },
|
69 | addCommands: {
|
70 | $args: [commands.meta('commands')],
|
71 | $assert: true,
|
72 | $: function (commands) {
|
73 | commands.forEach(function (command) {
|
74 | this.commands.push(command);
|
75 | }.bind(this));
|
76 | return this;
|
77 | }
|
78 | },
|
79 | loadModifiers: {
|
80 | $args: [joi.string().meta('folder').required()],
|
81 | $assert: true,
|
82 | $: function (folder) {
|
83 | return this.addModifiers(loadFromFolder(folder));
|
84 | }
|
85 | },
|
86 | addModifiers: {
|
87 | $args: [commands.meta('modifiers')],
|
88 | $assert: true,
|
89 | $: function (modifiers) {
|
90 | modifiers.forEach(function (modifier) {
|
91 | this.modifiers.unshift(modifier);
|
92 | }.bind(this));
|
93 | return this;
|
94 | }
|
95 | },
|
96 | getCommand: {
|
97 | $args: [joi.string().meta('name').allow(null).allow(undefined)],
|
98 | $assert: true,
|
99 | $: function (name) {
|
100 | if (name === null || name === undefined) {
|
101 | return null;
|
102 | }
|
103 | var commands = this.commands.sort(orderSort);
|
104 | for (var i = commands.length - 1; i >= 0; i--) {
|
105 | var command = commands[i];
|
106 | if (!itemFilter(this.scope, command)) {
|
107 | continue;
|
108 | }
|
109 | if (command.aliases.indexOf(name) !== -1) {
|
110 | return command;
|
111 | }
|
112 | }
|
113 | return null;
|
114 | }
|
115 | },
|
116 | execute: {
|
117 | $args: [joi.array().meta('args').default([]).optional()],
|
118 | $assert: true,
|
119 | $: function (args) {
|
120 | var mode = args[0];
|
121 | var argv = minimist(args)
|
122 | , command = this.getCommand(mode) || this.getCommand(this.defaultCommand)
|
123 | , handled = false;
|
124 | this.modifiers
|
125 | .filter(itemFilter.bind(null, this.scope))
|
126 | .sort(orderSort)
|
127 | .forEach(function (item) {
|
128 | for (var i = 0; i < item.aliases.length; ++i) {
|
129 | var alias = item.aliases[i]
|
130 | , value = argv[alias];
|
131 | if (value !== undefined && value !== null) {
|
132 | item.handler(this.scope, value, alias);
|
133 | }
|
134 | }
|
135 | }.bind(this));
|
136 |
|
137 | if (!command) {
|
138 | throw new Error('default command not found');
|
139 | }
|
140 |
|
141 | command.handler(this.scope, argv._.slice(1));
|
142 | }
|
143 | }
|
144 | });
|
145 |
|
146 | module.exports = Commandico;
|