coa 0.4.1 → 1.0.3
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/LICENSE +21 -0
- package/README.md +28 -33
- package/README.ru.md +316 -0
- package/index.js +1 -1
- package/lib/arg.js +44 -161
- package/lib/cmd.js +434 -547
- package/lib/coaobject.js +100 -0
- package/lib/coaparam.js +125 -0
- package/lib/color.js +19 -22
- package/lib/completion.js +161 -119
- package/lib/index.js +14 -10
- package/lib/opt.js +130 -313
- package/lib/shell.js +13 -13
- package/package.json +21 -17
- package/.npmignore +0 -6
- package/.travis.yml +0 -11
- package/GNUmakefile +0 -34
- package/src/arg.coffee +0 -130
- package/src/cmd.coffee +0 -456
- package/src/color.coffee +0 -25
- package/src/completion.coffee +0 -158
- package/src/index.coffee +0 -5
- package/src/opt.coffee +0 -243
- package/src/shell.coffee +0 -10
- package/test/coa.js +0 -496
- package/test/common.js +0 -1
- package/test/mocha.opts +0 -3
- package/test/shell-test.js +0 -60
- package/tests/api-h.js +0 -9
- package/tests/h.js +0 -6
package/src/completion.coffee
DELETED
@@ -1,158 +0,0 @@
|
|
1
|
-
###*
|
2
|
-
Most of the code adopted from the npm package shell completion code.
|
3
|
-
See https://github.com/isaacs/npm/blob/master/lib/completion.js
|
4
|
-
###
|
5
|
-
|
6
|
-
Q = require 'q'
|
7
|
-
escape = require('./shell').escape
|
8
|
-
unescape = require('./shell').unescape
|
9
|
-
|
10
|
-
module.exports = ->
|
11
|
-
@title('Shell completion')
|
12
|
-
.helpful()
|
13
|
-
.arg()
|
14
|
-
.name('raw')
|
15
|
-
.title('Completion words')
|
16
|
-
.arr()
|
17
|
-
.end()
|
18
|
-
.act (opts, args) ->
|
19
|
-
if process.platform == 'win32'
|
20
|
-
e = new Error 'shell completion not supported on windows'
|
21
|
-
e.code = 'ENOTSUP'
|
22
|
-
e.errno = require('constants').ENOTSUP
|
23
|
-
return @reject(e)
|
24
|
-
|
25
|
-
# if the COMP_* isn't in the env, then just dump the script
|
26
|
-
if !process.env.COMP_CWORD? or !process.env.COMP_LINE? or !process.env.COMP_POINT?
|
27
|
-
return dumpScript(@_cmd._name)
|
28
|
-
|
29
|
-
console.error 'COMP_LINE: %s', process.env.COMP_LINE
|
30
|
-
console.error 'COMP_CWORD: %s', process.env.COMP_CWORD
|
31
|
-
console.error 'COMP_POINT: %s', process.env.COMP_POINT
|
32
|
-
console.error 'args: %j', args.raw
|
33
|
-
|
34
|
-
# completion opts
|
35
|
-
opts = getOpts args.raw
|
36
|
-
|
37
|
-
# cmd
|
38
|
-
{ cmd, argv } = @_cmd._parseCmd opts.partialWords
|
39
|
-
Q.when complete(cmd, opts), (compls) ->
|
40
|
-
console.error 'filtered: %j', compls
|
41
|
-
console.log compls.map(escape).join('\n')
|
42
|
-
|
43
|
-
|
44
|
-
dumpScript = (name) ->
|
45
|
-
fs = require 'fs'
|
46
|
-
path = require 'path'
|
47
|
-
defer = Q.defer()
|
48
|
-
|
49
|
-
fs.readFile path.resolve(__dirname, 'completion.sh'), 'utf8', (err, d) ->
|
50
|
-
if err then return defer.reject err
|
51
|
-
d = d.replace(/{{cmd}}/g, path.basename name).replace(/^\#\!.*?\n/, '')
|
52
|
-
|
53
|
-
onError = (err) ->
|
54
|
-
# Darwin is a real dick sometimes.
|
55
|
-
#
|
56
|
-
# This is necessary because the "source" or "." program in
|
57
|
-
# bash on OS X closes its file argument before reading
|
58
|
-
# from it, meaning that you get exactly 1 write, which will
|
59
|
-
# work most of the time, and will always raise an EPIPE.
|
60
|
-
#
|
61
|
-
# Really, one should not be tossing away EPIPE errors, or any
|
62
|
-
# errors, so casually. But, without this, `. <(cmd completion)`
|
63
|
-
# can never ever work on OS X.
|
64
|
-
if err.errno == require('constants').EPIPE
|
65
|
-
process.stdout.removeListener 'error', onError
|
66
|
-
defer.resolve()
|
67
|
-
else
|
68
|
-
defer.reject(err)
|
69
|
-
|
70
|
-
process.stdout.on 'error', onError
|
71
|
-
process.stdout.write d, -> defer.resolve()
|
72
|
-
|
73
|
-
defer.promise
|
74
|
-
|
75
|
-
|
76
|
-
getOpts = (argv) ->
|
77
|
-
# get the partial line and partial word, if the point isn't at the end
|
78
|
-
# ie, tabbing at: cmd foo b|ar
|
79
|
-
line = process.env.COMP_LINE
|
80
|
-
w = +process.env.COMP_CWORD
|
81
|
-
point = +process.env.COMP_POINT
|
82
|
-
words = argv.map unescape
|
83
|
-
word = words[w]
|
84
|
-
partialLine = line.substr 0, point
|
85
|
-
partialWords = words.slice 0, w
|
86
|
-
|
87
|
-
# figure out where in that last word the point is
|
88
|
-
partialWord = argv[w] or ''
|
89
|
-
i = partialWord.length
|
90
|
-
while partialWord.substr(0, i) isnt partialLine.substr(-1 * i) and i > 0
|
91
|
-
i--
|
92
|
-
partialWord = unescape partialWord.substr 0, i
|
93
|
-
if partialWord then partialWords.push partialWord
|
94
|
-
|
95
|
-
{
|
96
|
-
line: line
|
97
|
-
w: w
|
98
|
-
point: point
|
99
|
-
words: words
|
100
|
-
word: word
|
101
|
-
partialLine: partialLine
|
102
|
-
partialWords: partialWords
|
103
|
-
partialWord: partialWord
|
104
|
-
}
|
105
|
-
|
106
|
-
|
107
|
-
complete = (cmd, opts) ->
|
108
|
-
compls = []
|
109
|
-
|
110
|
-
# complete on cmds
|
111
|
-
if opts.partialWord.indexOf('-')
|
112
|
-
compls = Object.keys(cmd._cmdsByName)
|
113
|
-
# Complete on required opts without '-' in last partial word
|
114
|
-
# (if required not already specified)
|
115
|
-
#
|
116
|
-
# Commented out because of uselessness:
|
117
|
-
# -b, --block suggest results in '-' on cmd line;
|
118
|
-
# next completion suggest all options, because of '-'
|
119
|
-
#.concat Object.keys(cmd._optsByKey).filter (v) -> cmd._optsByKey[v]._req
|
120
|
-
else
|
121
|
-
# complete on opt values: --opt=| case
|
122
|
-
if m = opts.partialWord.match /^(--\w[\w-_]*)=(.*)$/
|
123
|
-
optWord = m[1]
|
124
|
-
optPrefix = optWord + '='
|
125
|
-
else
|
126
|
-
# complete on opts
|
127
|
-
# don't complete on opts in case of --opt=val completion
|
128
|
-
# TODO: don't complete on opts in case of unknown arg after commands
|
129
|
-
# TODO: complete only on opts with arr() or not already used
|
130
|
-
# TODO: complete only on full opts?
|
131
|
-
compls = Object.keys cmd._optsByKey
|
132
|
-
|
133
|
-
# complete on opt values: next arg case
|
134
|
-
if not (o = opts.partialWords[opts.w - 1]).indexOf '-'
|
135
|
-
optWord = o
|
136
|
-
|
137
|
-
# complete on opt values: completion
|
138
|
-
if optWord and opt = cmd._optsByKey[optWord]
|
139
|
-
if not opt._flag and opt._comp
|
140
|
-
compls = Q.all([compls, opt._comp(opts)])
|
141
|
-
.spread (c, o) ->
|
142
|
-
c.concat o.map (v) -> (optPrefix or '') + v
|
143
|
-
|
144
|
-
# TODO: complete on args values (context aware, custom completion?)
|
145
|
-
|
146
|
-
# custom completion on cmds
|
147
|
-
if cmd._comp
|
148
|
-
compls = Q.all([compls, cmd._comp(opts)])
|
149
|
-
.spread (c, o) ->
|
150
|
-
c.concat o
|
151
|
-
|
152
|
-
# TODO: context aware custom completion on cmds, opts and args
|
153
|
-
# (can depend on already entered values, especially options)
|
154
|
-
|
155
|
-
Q.when compls, (compls) ->
|
156
|
-
console.error 'partialWord: %s', opts.partialWord
|
157
|
-
console.error 'compls: %j', compls
|
158
|
-
compls.filter (c) -> c.indexOf(opts.partialWord) is 0
|
package/src/index.coffee
DELETED
package/src/opt.coffee
DELETED
@@ -1,243 +0,0 @@
|
|
1
|
-
fs = require 'fs'
|
2
|
-
Q = require 'q'
|
3
|
-
Color = require('./color').Color
|
4
|
-
Cmd = require('./cmd').Cmd
|
5
|
-
|
6
|
-
###*
|
7
|
-
Option
|
8
|
-
|
9
|
-
Named entity. Options may have short and long keys for use from command line.
|
10
|
-
@namespace
|
11
|
-
@class Presents option
|
12
|
-
###
|
13
|
-
exports.Opt = class Opt
|
14
|
-
|
15
|
-
###*
|
16
|
-
@constructs
|
17
|
-
@param {COA.Cmd} cmd parent command
|
18
|
-
###
|
19
|
-
constructor: (@_cmd) -> @_cmd._opts.push @
|
20
|
-
|
21
|
-
###*
|
22
|
-
Set a canonical option identifier to be used anywhere in the API.
|
23
|
-
@param {String} _name option name
|
24
|
-
@returns {COA.Opt} this instance (for chainability)
|
25
|
-
###
|
26
|
-
name: (@_name) -> @
|
27
|
-
|
28
|
-
###*
|
29
|
-
Set a long description for option to be used anywhere in text messages.
|
30
|
-
@param {String} _title option title
|
31
|
-
@returns {COA.Opt} this instance (for chainability)
|
32
|
-
###
|
33
|
-
title: Cmd::title
|
34
|
-
|
35
|
-
###*
|
36
|
-
Set a short key for option to be used with one hyphen from command line.
|
37
|
-
@param {String} _short
|
38
|
-
@returns {COA.Opt} this instance (for chainability)
|
39
|
-
###
|
40
|
-
short: (@_short) -> @_cmd._optsByKey['-' + _short] = @
|
41
|
-
|
42
|
-
###*
|
43
|
-
Set a short key for option to be used with double hyphens from command line.
|
44
|
-
@param {String} _long
|
45
|
-
@returns {COA.Opt} this instance (for chainability)
|
46
|
-
###
|
47
|
-
long: (@_long) -> @_cmd._optsByKey['--' + _long] = @
|
48
|
-
|
49
|
-
###*
|
50
|
-
Make an option boolean, i.e. option without value.
|
51
|
-
@returns {COA.Opt} this instance (for chainability)
|
52
|
-
###
|
53
|
-
flag: () ->
|
54
|
-
@_flag = true
|
55
|
-
@
|
56
|
-
|
57
|
-
###*
|
58
|
-
Makes an option accepts multiple values.
|
59
|
-
Otherwise, the value will be used by the latter passed.
|
60
|
-
@returns {COA.Opt} this instance (for chainability)
|
61
|
-
###
|
62
|
-
arr: ->
|
63
|
-
@_arr = true
|
64
|
-
@
|
65
|
-
|
66
|
-
###*
|
67
|
-
Makes an option required.
|
68
|
-
@returns {COA.Opt} this instance (for chainability)
|
69
|
-
###
|
70
|
-
req: ->
|
71
|
-
@_req = true
|
72
|
-
@
|
73
|
-
|
74
|
-
###*
|
75
|
-
Makes an option to act as a command,
|
76
|
-
i.e. program will exit just after option action.
|
77
|
-
@returns {COA.Opt} this instance (for chainability)
|
78
|
-
###
|
79
|
-
only: ->
|
80
|
-
@_only = true
|
81
|
-
@
|
82
|
-
|
83
|
-
###*
|
84
|
-
Set a validation (or value) function for option.
|
85
|
-
Value from command line passes through before becoming available from API.
|
86
|
-
Using for validation and convertion simple types to any values.
|
87
|
-
@param {Function} _val validating function,
|
88
|
-
invoked in the context of option instance
|
89
|
-
and has one parameter with value from command line
|
90
|
-
@returns {COA.Opt} this instance (for chainability)
|
91
|
-
###
|
92
|
-
val: (@_val) -> @
|
93
|
-
|
94
|
-
###*
|
95
|
-
Set a default value for option.
|
96
|
-
Default value passed through validation function as ordinary value.
|
97
|
-
@param {Object} _def
|
98
|
-
@returns {COA.Opt} this instance (for chainability)
|
99
|
-
###
|
100
|
-
def: (@_def) -> @
|
101
|
-
|
102
|
-
###*
|
103
|
-
Make option value inputting stream.
|
104
|
-
It's add useful validation and shortcut for STDIN.
|
105
|
-
@returns {COA.Opt} this instance (for chainability)
|
106
|
-
###
|
107
|
-
input: ->
|
108
|
-
# XXX: hack to workaround a bug in node 0.6.x,
|
109
|
-
# see https://github.com/joyent/node/issues/2130
|
110
|
-
process.stdin.pause();
|
111
|
-
|
112
|
-
@
|
113
|
-
.def(process.stdin)
|
114
|
-
.val (v) ->
|
115
|
-
if typeof v is 'string'
|
116
|
-
if v is '-'
|
117
|
-
process.stdin
|
118
|
-
else
|
119
|
-
s = fs.createReadStream v, { encoding: 'utf8' }
|
120
|
-
s.pause()
|
121
|
-
s
|
122
|
-
else v
|
123
|
-
|
124
|
-
###*
|
125
|
-
Make option value outputing stream.
|
126
|
-
It's add useful validation and shortcut for STDOUT.
|
127
|
-
@returns {COA.Opt} this instance (for chainability)
|
128
|
-
###
|
129
|
-
output: ->
|
130
|
-
@
|
131
|
-
.def(process.stdout)
|
132
|
-
.val (v) ->
|
133
|
-
if typeof v is 'string'
|
134
|
-
if v is '-'
|
135
|
-
process.stdout
|
136
|
-
else
|
137
|
-
fs.createWriteStream v, { encoding: 'utf8' }
|
138
|
-
else v
|
139
|
-
|
140
|
-
###*
|
141
|
-
Add action for current option command.
|
142
|
-
This action is performed if the current option
|
143
|
-
is present in parsed options (with any value).
|
144
|
-
@param {Function} act action function,
|
145
|
-
invoked in the context of command instance
|
146
|
-
and has the parameters:
|
147
|
-
- {Object} opts parsed options
|
148
|
-
- {Array} args parsed arguments
|
149
|
-
- {Object} res actions result accumulator
|
150
|
-
It can return rejected promise by Cmd.reject (in case of error)
|
151
|
-
or any other value treated as result.
|
152
|
-
@returns {COA.Opt} this instance (for chainability)
|
153
|
-
###
|
154
|
-
act: (act) ->
|
155
|
-
opt = @
|
156
|
-
name = @_name
|
157
|
-
@_cmd.act (opts) ->
|
158
|
-
if name of opts
|
159
|
-
res = act.apply @, arguments
|
160
|
-
if opt._only
|
161
|
-
Q.when res, (res) =>
|
162
|
-
@reject {
|
163
|
-
toString: -> res.toString()
|
164
|
-
exitCode: 0
|
165
|
-
}
|
166
|
-
else
|
167
|
-
res
|
168
|
-
@
|
169
|
-
|
170
|
-
###*
|
171
|
-
Set custom additional completion for current option.
|
172
|
-
@param {Function} completion generation function,
|
173
|
-
invoked in the context of option instance.
|
174
|
-
Accepts parameters:
|
175
|
-
- {Object} opts completion options
|
176
|
-
It can return promise or any other value treated as result.
|
177
|
-
@returns {COA.Opt} this instance (for chainability)
|
178
|
-
###
|
179
|
-
comp: Cmd::comp
|
180
|
-
|
181
|
-
_saveVal: (opts, val) ->
|
182
|
-
if @_val then val = @_val val
|
183
|
-
if @_arr
|
184
|
-
(opts[@_name] or= []).push val
|
185
|
-
else
|
186
|
-
opts[@_name] = val
|
187
|
-
val
|
188
|
-
|
189
|
-
_parse: (argv, opts) ->
|
190
|
-
@_saveVal(
|
191
|
-
opts,
|
192
|
-
if @_flag
|
193
|
-
true
|
194
|
-
else
|
195
|
-
argv.shift()
|
196
|
-
)
|
197
|
-
|
198
|
-
_checkParsed: (opts, args) -> not opts.hasOwnProperty @_name
|
199
|
-
|
200
|
-
_usage: ->
|
201
|
-
res = []
|
202
|
-
nameStr = @_name.toUpperCase()
|
203
|
-
|
204
|
-
if @_short
|
205
|
-
res.push '-', Color 'lgreen', @_short
|
206
|
-
unless @_flag then res.push ' ' + nameStr
|
207
|
-
res.push ', '
|
208
|
-
|
209
|
-
if @_long
|
210
|
-
res.push '--', Color 'green', @_long
|
211
|
-
unless @_flag then res.push '=' + nameStr
|
212
|
-
|
213
|
-
res.push ' : ', @_title
|
214
|
-
|
215
|
-
if @_req then res.push ' ', Color('lred', '(required)')
|
216
|
-
|
217
|
-
res.join ''
|
218
|
-
|
219
|
-
_requiredText: -> 'Missing required option:\n ' + @_usage()
|
220
|
-
|
221
|
-
###*
|
222
|
-
Return rejected promise with error code.
|
223
|
-
Use in .val() for return with error.
|
224
|
-
@param {Object} reject reason
|
225
|
-
You can customize toString() method and exitCode property
|
226
|
-
of reason object.
|
227
|
-
@returns {Q.promise} rejected promise
|
228
|
-
###
|
229
|
-
reject: Cmd::reject
|
230
|
-
|
231
|
-
###*
|
232
|
-
Finish chain for current option and return parent command instance.
|
233
|
-
@returns {COA.Cmd} parent command
|
234
|
-
###
|
235
|
-
end: Cmd::end
|
236
|
-
|
237
|
-
###*
|
238
|
-
Apply function with arguments in context of option instance.
|
239
|
-
@param {Function} fn
|
240
|
-
@param {Array} args
|
241
|
-
@returns {COA.Opt} this instance (for chainability)
|
242
|
-
###
|
243
|
-
apply: Cmd::apply
|
package/src/shell.coffee
DELETED
@@ -1,10 +0,0 @@
|
|
1
|
-
exports.unescape = (w) ->
|
2
|
-
w = if w.charAt(0) is '"'
|
3
|
-
w.replace(/^"|([^\\])"$/g, '$1')
|
4
|
-
else
|
5
|
-
w.replace(/\\ /g, ' ')
|
6
|
-
w.replace(/\\("|'|\$|`|\\)/g, '$1')
|
7
|
-
|
8
|
-
exports.escape = (w) ->
|
9
|
-
w = w.replace(/(["'$`\\])/g,'\\$1')
|
10
|
-
if w.match(/\s+/) then '"' + w + '"' else w
|