UNPKG

4 kBJavaScriptView Raw
1'use strict';
2
3var explicit = require('explicit'),
4 fs = require('fs'),
5 joi = require('joi'),
6 minimist = require('minimist'),
7 path = require('path');
8
9var 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
44var 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
61Commandico.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
146module.exports = Commandico;