UNPKG

46.2 kBJavaScriptView Raw
1(function() {
2 var ArguMintsException = require('./exception.js').ArguMintsException;
3 var ArguMintStats = require('./stats.js').ArguMintStats;
4 var ArguMintRules = require('./rules.js').ArguMintRules;
5
6 var _ = require('underscore');
7 var fs = require('fs');
8
9 //@private
10
11 var ArguMintsExtensions = (function() {
12
13 function ArguMintsExtensions() {
14 var mintyOps = {};
15
16 ArguMintsExtensions.prototype.hasExtension = function(mintyOpStr) {
17 return mintyOps.hasOwnProperty(mintyOpStr) && mintyOps[mintyOpStr] != null;
18 }
19 ///
20 ArguMintsExtensions.prototype.addExtension = function(mintyOpStr, op) {
21 mintyOps[mintyOpStr] = op;
22 }
23
24 ArguMintsExtensions.prototype.getExtension = function(mintyOpStr) {
25 return mintyOps[mintyOpStr];
26 }
27 }
28
29 // return the function to generate new values of ArguMintsExtensions
30 return ArguMintsExtensions;
31 }());
32
33 /**
34 * Constructor
35 *
36 * @param options
37 */
38 function ArguMints(options) {
39
40 // initialize the private store for this instance.
41 // we can reference this anywhere by calling privitize
42 var _commandTable = null;
43 var _options = options;
44 var _dumpDepth = 0;
45 var _stats = new ArguMintStats();
46 var _scriptArgs = null;
47 var _userArgs = null;
48 var _nodeLocation = null;
49 var _scriptPath = null;
50 var _currRetortIndex = 0;
51 var _fileExpansionChain = null;
52 var _rules = new ArguMintRules();
53 //
54 // @private
55 function appendNumberForKey(keyStore, _opt, key, value) {
56 var called = false;
57 key = key.trim();
58
59 if (keyStore[key] === undefined) {
60 keyStore[key] = 0;
61 }
62
63 for ( var x in _opt) {
64 var f = ArguMints.extensions.getExtension(x);
65
66 if (_rules.protoName(f) == ArguMintRules.FUNC) {
67 f(keyStore, key, value);
68 called = true;
69 break;
70 }
71 }
72 if (!called) {
73 keyStore[key] += value;
74 }
75 }
76
77 // sets a value, or appends it if our options
78 // specify
79 function setKeyStoreValue(key, value) {
80
81 if (key != null && typeof key == 'string') {
82 key = key.trim();
83
84 var keyStore = _commandTable.keyStore;
85 var opt = _commandTable.opt;
86 var currValue = _commandTable.keyStore[key];
87 var pName = _rules.protoName(currValue);
88 var newPName = _rules.protoName(value);
89
90 if (opt['minty-append-dup-keys'] == true) {
91
92 if (currValue !== undefined) {
93 if (pName == ArguMintRules.ARR) {
94 if (newPName == ArguMintRules.ARR) {
95 currValue = currValue.concat(value);
96 keyStore[key] = value;
97 }
98 else {
99 // if new value isn't undefined push it on
100 if (value !== undefined) {
101 currValue.push(value);
102 }
103 // sanity
104 keyStore[key] = currValue;
105 }
106 }
107 else if (pName != ArguMintRules.UDF) {
108 if (pName == ArguMintRules.STR) {
109 if (newPName != ArguMintRules.UDF) {
110 // concat and coerce value to 'string'
111 keyStore[key] += value;
112 }
113 else {
114 //do nothing here
115 }
116 }
117 else if (pName == ArguMintRules.NUM) {
118 if (newPName == ArguMintRules.NUM) {
119 appendNumberForKey(keyStore, opt, key, value);
120 }
121 else if (newPName == ArguMintRules.STR) {
122 keyStore[key] += value;
123 }
124 else {
125 keyStore[key] = currValue;
126 }
127 }
128 else {
129 keyStore[key] = currValue;
130 }
131 }
132 else {
133 keyStore[key] = currValue;
134 }
135 }
136 else {
137 if (newPName == ArguMintRules.NUM) {
138 appendNumberForKey(keyStore, opt, key, value);
139 }
140 else {
141 keyStore[key] = value;
142 }
143 }
144 }
145 else {
146 keyStore[key] = value;
147 }
148 }
149 return this;
150 }
151
152 function copyCommandsFrom(copyFrom) {
153
154 // explodes all templates or JSON strings within
155 // this objects properties.
156 // expand for any file content in the JSON
157 expandObject(copyFrom);
158
159 // set each key value from the object
160 _.each(copyFrom, function(value, key, obj) {
161 setKeyStoreValue(key, value);
162 });
163
164 return this;
165 }
166
167 ArguMints.prototype.getStats = function() {
168 return {
169 ops : _stats.ops,
170 retorts : _stats.retorts,
171 bickerTime : _stats.bickerTime,
172 debateStart : _stats.debateStart
173 };
174 }
175
176 ArguMints.prototype.reset = function(newOptions) {
177
178 if (_rules.protoName(newOptions) == ArguMintRules.OBJ) {
179 _options = newOptions;
180 }
181 _stats.reset();
182 _commandTable = null;
183 _scriptArgs = null;
184 _userArgs = null;
185 _nodeLocation = null;
186
187 return this;
188 // NOTE: we don't kill 'options' here
189 // so the user can 'retort' again with thame options.
190 }
191 /**
192 * Internal
193 */
194 /**
195 * Dump the Command Table
196 */
197 ArguMints.prototype.argDump = function() {
198
199 var dumped = new WeakMap();
200
201 var self = this;
202 // dump the contents of the command table, up to 100 levels into the tree.
203 // this is an obscene limit, but insures no stack overflow or inifite circular print.
204 function dump(o, dMap) {
205
206 ++_dumpDepth;
207
208 var chunk = " "
209 var spacing = "";
210
211 for (var i = 0; i < _dumpDepth; ++i) {
212 spacing += chunk;
213 }
214
215 if (ArguMints.verbose) {
216 if (_rules.protoName(o) == ArguMintRules.ARR) {
217 console.log(spacing + "ArguMints.dump(" + _dumpDepth + ") - "
218 + _rules.protoName(o, true) + " - array length: " + o.length);
219 }
220 else {
221 console.log(spacing + "ArguMints.dump(" + _dumpDepth + ") - "
222 + _rules.protoName(o, true));
223 }
224 }
225 if (o === null) {
226 console.log(spacing + "null");
227 }
228 else {
229 var objtype = typeof o;
230 if (_rules.protoName(o) == ArguMintRules.ARR) {
231
232 // avoid circular reference dumping
233 if (!dMap.has(o)) {
234 dMap.set(o, true);
235
236 for (var i = 0; i < o.length; i++) {
237
238 var value = o[i];
239 var type = (typeof value);
240 var tag = ArguMints.verbose ? "[" + i + "] " : "";
241 if (type == 'object') {
242 console.log(spacing + tag + _rules.protoName(value, true) + "(" + type
243 + ")");
244 console
245 .log((spacing + chunk + "--------------------------------------------------------")
246 .substring(0, 50));
247 dump(value, dMap);
248 console
249 .log((spacing + chunk + "--------------------------------------------------------")
250 .substring(0, 50));
251
252 }
253 else {
254 if (type == 'string') {
255 console.log(spacing + tag + (value.split('\r\n').join('\r\n ' + spacing)));
256 }
257 else {
258 console.log(spacing + tag + value + "(" + type + ")");
259 }
260 }
261 }
262 }
263 }
264 else if (objtype == 'object') {
265 var cnt = 0;
266
267 if (!dMap.has(o)) {
268 dMap.set(o, true);
269 for ( var prop in o) {
270 cnt++;
271 var value = o[prop];
272 var type = (typeof value);
273 var pName = _rules.protoName(value, true);
274
275 if (type == 'object') {
276 if (pName == ArguMintRules.ARR) {
277 console.log(spacing + "[" + prop + "] " + pName + ", length: " + value.length);
278 }
279 else {
280 console.log(spacing + "[" + prop + "] " + pName + "(" + type + ")");
281 }
282 console
283 .log((spacing + chunk + "--------------------------------------------------------")
284 .substring(0, 50));
285 dump(value, dMap);
286 console
287 .log((spacing + chunk + "--------------------------------------------------------")
288 .substring(0, 50));
289
290 }
291 else {
292 console.log(spacing + prop + "=" + value + "(" + type + ")");
293 }
294 }
295 }
296
297 if (cnt == 0) {
298 console.log(spacing + "\t{}");
299 }
300 }
301 else {
302 if (type == 'string') {
303
304 console.log(spacing + '[' + (o.split('\r\n').join(spacing + ' \r\n')) + ']');
305 }
306 else {
307 console.log(spacing + '[' + o + ']');
308 }
309 }
310 }
311 --_dumpDepth;
312
313 }
314
315 dump(_commandTable, dumped);
316
317 // clear after calling
318 dumped = null;
319
320 return this;
321 }
322
323 ArguMints.prototype.getUserArgs = function() {
324 return _userArgs;
325 }
326 ArguMints.prototype.getScriptArgs = function() {
327 // always return a copy
328 return _.clone(_scriptArgs);
329 }
330
331 ArguMints.prototype.argc = function() {
332 return _commandTable.argv.length;
333 }
334 ArguMints.prototype.argv = function(atIndex) {
335 if ((typeof atIndex) == 'number' && atIndex >= 0 && atIndex < _commandTable.argv.length) {
336 return _commandTable.argv[atIndex];
337 }
338
339 return _.clone(_commandTable.argv);
340 }
341
342 ArguMints.prototype.opt = function(optName) {
343 if (_rules.protoName(optName) != ArguMintRules.UDF) {
344 if (_rules.protoName(_commandTable.opt[optName]) != ArguMintRules.UDF) {
345 return _commandTable.opt[optName];
346 }
347 return false;
348 }
349 else {
350 // never return the original object.
351 return _.clone(_commandTable.opt);
352 }
353 }
354
355 ArguMints.prototype.keyValue = function(key) {
356
357 if (_rules.protoName(key) == ArguMintRules.STR && key.length > 0) {
358 return _commandTable.keyStore[key];
359 }
360 else {
361 // key is null
362 return _.clone(_commandTable.keyStore)
363 }
364 }
365
366 ArguMints.prototype.flag = function(flag) {
367 if (flag != null && flag != '') {
368 if (_rules.protoName(_commandTable.flags[flag]) != ArguMintRules.UDF) {
369 return _commandTable.flags[flag];
370 }
371
372 return false;
373 }
374
375 return _.clone(_commandTable.flags);
376 }
377
378 function expandFile(tagInput ) {
379
380 var ret = tagInput;
381 // pass through if not a string or properly formatted, or we are not enabling file expansion
382 if (false === _options.enableFileExpansion || _rules.protoName(ret) !== ArguMintRules.STR
383 || ret.charAt(0) !== '@') {
384 return ret;
385 }
386 else {
387 if (_fileExpansionChain == null) {
388 _fileExpansionChain = [];
389 }
390
391 if (_fileExpansionChain.indexOf(tagInput) != -1) {
392 if (ArguMints.verbose) {
393 console.log("ArguMints.expandFileArg() - Expansion chain: " + _fileExpansionChain);
394 }
395
396 throw new ArguMintsException("ArguMints.expandFileArg() - Circular File Expansion Detected!: "
397 + "Expansion chain: " + _fileExpansionChain.join("->"));
398 }
399
400 _fileExpansionChain.push(tagInput);
401 var cachedValue = _rules.getFileCache(tagInput);
402
403 if (cachedValue == null) {
404 //this is a file, load it synchronously here
405 //process its contents as utf8
406 var fn = ret.substring(1);
407 if (ArguMints.verbose) console.log("ArguMints.expandFileArg(" + fn + ") - "
408 + _fileExpansionChain.join('->'));
409
410 try {
411
412 // Query the entry
413 var stats = fs.lstatSync(fn);
414 // Is it a directory?
415 var hasContent = stats.isFile() && !stats.isDirectory();
416 // overwrite our value with the data from the file and continue
417 ret = hasContent ? fs.readFileSync(fn, 'utf8') : '';
418 if (hasContent && ret != null) {
419 ret = ret.trim();
420 }
421
422 if (ArguMints.verbose) console.log("ArguMints.expandFileArg() - loaded " + fn + " containing "
423 + (ret.length > 0 ? ret.length : 'ZERO') + " characters: " + ret);
424
425 if (_commandTable.opt['minty-no-cache'] !== true) {
426 _rules.cacheFileContent(tagInput, ret);
427 }
428 else if (ArguMints.verbose) console.log("ArguMints.expandFile() not caching file at: "
429 + tagInput + ", caching is off");
430 }
431 catch (e) {
432 console.log(e);
433 }
434 }
435 else {
436 if (ArguMints.verbose) console.log("ArguMints.expandFile() - returning: " + cachedValue.length
437 + " cached chars for tag: " + tagInput);
438 ret = cachedValue;
439 }
440
441 }
442 return ret;
443 }
444
445 ArguMints.prototype.pushArg = function(moreArgOrArgs) {
446 if (_stats.isRecording() && moreArgOrArgs !== undefined) {
447 if (_rules.protoName(moreArgOrArgs) !== ArguMintRules.ARR) {
448 _userArgs[_userArgs.length] = moreArgOrArgs;
449 }
450 else {
451 _userArgs = _userArgs.concat(moreArgOrArgs);
452 }
453 }
454 return this;
455 }
456
457 ArguMints.prototype.insertArg = function(moreArgOrArgs, xArgsFromHere) {
458
459 if (_stats.isRecording() && moreArgOrArgs !== undefined) {
460 var idx = _currRetortIndex;
461 if (_rules.protoName(xArgsFromHere) === ArguMintRules.NUM) {
462 idx += xArgsFromHere;
463 }
464 if (idx <= _userArgs.length) {
465 if (_rules.protoName(moreArgOrArgs) !== ArguMintRules.ARR) {
466 _userArgs.splice(idx, 0, moreArgOrArgs);
467 }
468 else {
469 _userArgs = _userArgs.slice(0, idx).concat(moreArgOrArgs).concat(_userArgs.slice(idx));
470 }
471 }
472 }
473 return this;
474 }
475 // build the command table from the users Arguments
476 ArguMints.prototype.retort = function(moreUserArgs, onStart, onArgExpand) {
477
478 _stats.recordStart();
479 _currRetortIndex = 0;
480 // insure we always have default options
481 if (_options == null) {
482 _options = {
483 treatBoolStringsAsBoolean : true,
484 treatNullStringsAsNull : true,
485 treatRegExStringsAsRegEx : true,
486 treatNumberStringsAsNumbers : true,
487 treatUndefinedStringsAsUndefined : true,
488 enableFileExpansion : true,
489 ignoreJson : false
490 }
491 }
492
493 // keep track of arguments we've already retorted to
494 var retortIndex = 0;
495
496 // only update user args ONCE.
497 // if the user calls retort multiple times with
498 // concatenations of arguments, we'll append them to
499 // userArgs below
500 if (_userArgs == null) {
501 if (ArguMints.verbose) {
502 console.log("ArguMints.retort() - building initial ArguMints set");
503 }
504 // table of parsed input arguments.
505 _commandTable = {
506 argv : [],
507 flags : {},
508 opt : {},
509 keyStore : {}
510 };
511
512 // the second arg is always the path to our script
513 // if we're running outside of node
514 var secondArg = process.argv[1];
515
516 // if running inside of node REPL
517 // the secondArg will either be null, or will be a user argument.
518 // validate that the second argument is either 'null', or doesn't contain the location of
519 // the argumints script.
520 if (ArguMints.REPL == true) {
521 _scriptArgs = process.argv.slice(0, 1);
522
523 // path to node installation
524 _nodeLocation = _scriptArgs[0];
525
526 // we're not running a script if we get here, we're inside of node.
527 _scriptPath = null;
528
529 // any additional args
530 _userArgs = process.argv.slice(1);
531 }
532 // otherwise the first two args we always scrape
533 else {
534 _scriptArgs = process.argv.slice(0, 2);
535
536 // path to node installation
537 _nodeLocation = _scriptArgs[0];
538 // path to this script
539 _scriptPath = _scriptArgs[1];
540
541 // any additional args
542 _userArgs = process.argv.slice(2);
543 }
544
545 retortIndex = 0;
546 }
547 else {
548 if (ArguMints.verbose) {
549 console.log("ArguMints.retort() -Adding Additional arguments to existing ArguMints set");
550 }
551
552 // start from where we left off, unless reset is called.
553 retortIndex = _userArgs.length;
554 }
555
556 if (moreUserArgs != null) {
557 _userArgs = _userArgs.concat(moreUserArgs);
558 }
559
560 var uLen = _userArgs == null ? 0 : _userArgs.length;
561
562 if (onStart != null) {
563 onStart(_userArgs.concat())
564 }
565
566 if (uLen > retortIndex) {
567
568 // userArgs are split on '=' to avoid forcing order
569 // NOTE: we don't use uLen in the for loop because
570 // args may be modified mid retort!
571 for (var i = retortIndex; i < _userArgs.length; ++i) {
572
573 _currRetortIndex++;
574
575 // clear this after processing each argument
576 _fileExpansionChain = null;
577
578 // current arg, copied so it can be mangled.
579 // _userArgs[i] will never change from its orginal value.
580 var argAt = _userArgs[i];
581
582 // do the full expansion test first
583 argAt = expandString(argAt);
584
585 // if file expansion results in null or empty string,
586 // push this value onto the command args list now and short circuit.
587 if (argAt == '' || argAt == null) {
588 _commandTable.argv.push(argAt);
589
590 // invoke the expansion callback
591 if (onArgExpand != null) {
592 onArgExpand(_userArgs[i], argAt, i, _userArgs.length);
593 }
594
595 continue;
596 }
597
598 var protoStr = _rules.protoName(argAt);
599
600 // this was expanded into an object
601 if (protoStr == ArguMintRules.OBJ) {
602 if (protoStr != ArguMintRules.REGX) {
603 copyCommandsFrom(argAt);
604 }
605 else {
606 // push regexp onto the arglist
607 _commandTable.argv.push(argAt);
608 }
609
610 // invoke the expansion callback
611 if (onArgExpand != null) {
612 onArgExpand(_userArgs[i], argAt, i, _userArgs.length);
613 }
614 }
615 else if (protoStr == ArguMintRules.STR) {
616 // first index of assignment operator in argument
617 var aIdx = argAt.indexOf('=');
618 var qIdx = argAt.indexOf('"');
619
620 // if there are quotes before our assignment operator, its not really an assignment but a string
621 // value.
622 if (aIdx > qIdx && qIdx != -1) {
623 aIdx = -1;
624 }
625 // if this is NOT a 'key=value' pair
626 // its a 'flag' i.e. verbose, etc.
627 if (aIdx == -1) {
628 // supports both '--flagName' and '-f' formats
629 if (argAt.charAt(0) == '-') {
630 // set as 'true'
631 if (argAt.charAt(1) == '-') {
632
633 if (ArguMints.verbose) {
634 console
635 .log("ArguMints.retort() - add option at: " + i + ", argument: "
636 + argAt);
637 }
638
639 var sub = argAt.substring(2);
640
641 if (onArgExpand != null) {
642 onArgExpand(_userArgs[i], argAt, i, _userArgs.length);
643 }
644
645 _commandTable.opt[sub] = true;
646 }
647 else {
648 if (ArguMints.verbose) {
649 console.log("ArguMints.retort() - add flag at: " + i + ", argument: " + argAt);
650 }
651
652 // allow multiple flags in a single arg.
653 for (var x = 1; x < argAt.length; ++x) {
654
655 _commandTable.flags[argAt.charAt(x)] = true;
656
657 if (onArgExpand != null) {
658 onArgExpand(_userArgs[i], argAt.charAt(x), i, _userArgs.length);
659 }
660 }
661
662 }
663 if (_commandTable.opt['minty-verbose'] === true) {
664 ArguMints.verbose = true;
665 }
666 }
667 else {
668 argAt = expandString(argAt);
669
670 // if expansion worked.
671 if (_rules.protoName(argAt, true) !== ArguMintRules.STR) {
672 if (ArguMints.verbose) console
673 .log("ArguMints.retort() -add object formatted input, parsed..." + argAt);
674 // copy the json key/values into the command table.
675 // this allows structured input.
676 copyCommandsFrom(argAt);
677 }
678 else {
679 if (ArguMints.verbose) console.log("ArguMints.retort() -add string arg:"
680 + argAt.length + " chars to argList");
681 _commandTable.argv.push(argAt);
682 }
683
684 if (onArgExpand != null) {
685 onArgExpand(_userArgs[i], argAt, i, _userArgs.length);
686 }
687 }
688 }
689 else {
690 // key value pair
691 // substring rather than split
692 // so we don't end up splitting the
693 // '=' after the first (because that's content)
694 var pts = [ argAt.substring(0, aIdx), argAt.substring(aIdx + 1, argAt.length)
695 ];
696
697 // trim each to avoid keys with
698 // spaces in the name should folks be silly
699 setKeyStoreValue(pts[0], expandString(pts[1].trim()));
700
701 if (ArguMints.verbose) console.log("ArguMints.retort() -set final retort for" + pts[0]
702 + " to (" + _commandTable.keyStore[pts[0]] + ")");
703 }
704 }
705 else {
706 if (ArguMints.verbose) console.log("ArguMints.retort() - adding primitive retort to argList ("
707 + argAt + ")");
708 _commandTable.argv.push(argAt);
709
710 // invoke the expansion callback
711 if (onArgExpand != null) {
712 onArgExpand(_userArgs[i], argAt, i, _userArgs.length);
713 }
714 }
715
716 // clear opts on each argument expansion if these options are set
717 if (_commandTable.opt['minty-clear-opts'] == true) {
718 // all options to be cleared upon each retort
719 _commandTable.opt = {};
720 }
721
722 // clear flags on each argument expansion if these options are set
723 if (_commandTable.opt['minty-clear-flags'] == true) {
724 // all options to be cleared upon each retort
725 _commandTable.flags = {};
726 }
727
728 }
729
730 if (ArguMints.verbose === true) {
731 console.log("ArguMints.retort() completed: " + (uLen - retortIndex)
732 + " additional arguments were passed in by the user " + _userArgs.slice(retortIndex));
733 }
734 }
735
736 if (_commandTable.argv) {
737 if (_commandTable.opt['minty-match-argv'] == true) {
738 // copy the argv
739 var argv = _commandTable.argv.concat();
740 var argc = _commandTable.argv.length;
741 var filtered = [];
742 var regExps = [];
743 var curr = null;
744
745 for (var i = 0; i < argc; ++i) {
746 curr = argv[i];
747 if (_rules.protoName(curr, true) == 'RegExp') {
748 regExps[regExps.length] = curr;
749 // remove and step back
750 argv.splice(i, 1);
751 --i;
752 }
753 }
754 argc = argv.length;
755 var rLen = regExps.length;
756 //find regex values
757 for (var i = 0; i < rLen; ++i) {
758 var currRegExp = regExps[i];
759 for (var j = 0; j < argc; ++j) {
760 var currArgAsStr = String(argv[j]);
761
762 if (currArgAsStr != null && currArgAsStr != '') {
763
764 var moreResults = (currArgAsStr.match(currRegExp));
765
766 if (moreResults != null && moreResults.length > 0) {
767 filtered = filtered.concat(moreResults);
768 }
769 }
770 }
771
772 }
773
774 _commandTable.argvmatch = filtered;
775 }
776
777 if (_commandTable.opt['minty-match-kv'] == true) {
778 // copy the argv
779 var kvStore = _commandTable.keyStore;
780 var filtered = [];
781 var regExps = [];
782 var curr = null;
783 for ( var i in kvStore) {
784 curr = kvStore[i];
785 if (_rules.protoName(curr, true) == 'RegExp') {
786 regExps[regExps.length] = curr;
787 }
788 }
789
790 var rLen = regExps.length;
791 //find regex values
792 for (var i = 0; i < rLen; i++) {
793 var currRegExp = regExps[i];
794 for ( var j in kvStore) {
795 var currArgAsStr = String(kvStore[j]);
796
797 if (currArgAsStr != null && currArgAsStr != '') {
798
799 var moreResults = currArgAsStr.match(currRegExp);
800
801 if (moreResults != null && moreResults.length > 0) {
802 filtered = filtered.concat(moreResults);
803 }
804 }
805 }
806 }
807
808 _commandTable.kvmatch = filtered;
809 }
810 }
811
812 if (_commandTable.opt['minty-dump'] == true) {
813 this.argDump();
814 }
815
816 _stats.recordStop();
817 return this;
818 }
819
820 function expandRegEx(regExpStr) {
821
822 var ret = regExpStr;
823
824 if (_rules.protoName(regExpStr) == ArguMintRules.STR) {
825 regExpStr = regExpStr.trim();
826 var tLen = regExpStr.length;
827 var first = regExpStr.charAt(0);
828 var last = regExpStr.charAt(tLen - 1);
829
830 // only check for reg ex
831 // if the string starts with '/'
832 if (first == '`' && last == '`') {
833 if (ArguMints.verbose) console.log("ArguMints.expandRegEx() - checking validity of expression ("
834 + (ret.length - 2) + ") chars");
835
836 // second to last char
837 var idx = tLen - 2;
838
839 var optFlags = "";
840
841 while (idx > 0) {
842 last = regExpStr.charAt(idx--);
843 if (last == '/') {
844 break;
845 }
846 optFlags = last + optFlags;
847 }
848
849 if (idx > 1) {
850 var regExStr = regExpStr.substring(2, idx + 1);
851 ret = RegExp(regExStr, optFlags);
852 if (ArguMints.verbose) console.log("ArguMints.expandRegEx() - optFlags: " + optFlags
853 + ", regExStr: " + regExStr);
854 }
855 }
856 }
857 return ret;
858 }
859 /**
860 * Returns 'JSON Formatted string' if the string passed in is in proper JSON format.
861 */
862 function expandJSONString(mightBeJson) {
863
864
865 if (mightBeJson != null && typeof mightBeJson == 'string' && mightBeJson.length > 0) {
866
867 // insure the string has no space at the ends.
868 var trimmed = mightBeJson.trim();
869 var first = trimmed.charAt(0);
870 var last = trimmed.charAt(trimmed.length - 1);
871
872 if (ArguMints.verbose) console.log("ArguMints.expandJSONString() - maybe: " + trimmed);
873 // array or object must be the base element
874 if ((first == '{' && last == '}') || (first == '[' && last == ']')) {
875 mightBeJson = JSON.parse(trimmed);
876 if (ArguMints.verbose) console.log("ArguMints.expandJSONString() - expanded: " + mightBeJson);
877 }
878 }
879 return mightBeJson;
880 }
881 ;
882
883 function expandString(str ) {
884
885
886 if (typeof str == 'string' && str !== '') {
887 var didMangle = false;
888
889 var newValue = expandFile(str);
890
891 didMangle = newValue != str;
892 str = newValue;
893
894 var pathMatches = str.match(_rules.filePathMatcher);
895 var plen = pathMatches != null ? pathMatches.length : 0;
896 if (plen > 0) {
897 for (var i = 0; i < plen; i++) {
898 var match = pathMatches[i];
899
900 var idx = str.indexOf(match);
901
902 if (idx > -1) {
903 var actFileName = match;
904 if (actFileName.charAt(0) == '"') {
905 actFileName = actFileName.substring(2, actFileName.length - 1);
906 }
907 else {
908 actFileName = actFileName.substring(1, actFileName.length);
909 }
910
911 // inject contents
912 str = str.substring(0, idx) + expandString(actFileName)
913 + str.substring(idx + match.length, str.length);
914 }
915 }
916 }
917
918 // next attempt to build a regex
919 newValue = expandRegEx(str);
920 didMangle = newValue !== str;
921 str = newValue;
922
923 if (true !== _options.ignoreJson) {
924 // attempt to format as json
925 newValue = expandJSONString(str);
926 didMangle = newValue !== str;
927 str = newValue;
928 }
929 else {
930 if (ArguMints.verbose) {
931 console.log("Ignore JSON INPUT");
932 }
933 }
934
935 if (!isNaN(str)) {
936 if (_options.treatNumberStringsAsNumbers === true) {
937 str = Number(str);
938 didMangle = true;
939 }
940 }
941 else if (typeof str == 'string') {
942 var xVal = str.toLowerCase();
943 if (!didMangle && _options.treatBoolStringsAsBoolean) {
944 if (xVal == 'true') {
945 str = true;
946 didMangle = true;
947 }
948 else if (xVal == 'false') {
949 str = false;
950 didMangle = true;
951 }
952 }
953 if (!didMangle && _options.treatNullStringsAsNull) {
954 if (xVal == 'null') {
955 str = null;
956 didMangle = true;
957 }
958 }
959 if (!didMangle && _options.treatUndefinedStringsAsUndefined) {
960 if (xVal == ArguMintRules.UDF) {
961 str = undefined;
962 didMangle = true;
963 }
964 }
965 }
966 if (ArguMints.verbose) console.log("ArguMints.expandString() - expanded: " + str);
967 }
968
969 return str;
970 }
971
972 function expandArray(arr) {
973
974 if (ArguMints.verbose) console.log("ArguMints.expandArray(" + arr + ")");
975 var protoName = _rules.protoName(arr);
976
977 if (protoName == ArguMintRules.ARR) {
978 for (var i = 0; i < arr.length; i++) {
979 var value = arr[i];
980 var type = (typeof value);
981
982 // let inline expansion happen first, then pass through
983 value = expandString(value);
984
985 // attempt to expand it as an object
986 expandObject(value);
987
988 arr[i] = value;
989 }
990 }
991 else {
992 expandObject(value);
993 }
994
995 return this;
996 }
997 function expandObject(obj) {
998
999 // pass through
1000 if (typeof obj !== 'object') {
1001 return obj;
1002 }
1003
1004 var protoName = _rules.protoName(obj);
1005 if (protoName == ArguMintRules.ARR) {
1006 if (ArguMints.verbose) console.log("ArguMints.expandObject(" + obj + ") - ARRAY ");
1007 expandArray(obj);
1008 }
1009 else {
1010 if (ArguMints.verbose) console.log("ArguMints.expandObject(" + obj + ") - OBJECT ");
1011 // copy the keys to command table.
1012 for ( var key in obj) {
1013 var keyValue = obj[key];
1014 // inline expansion of strings will
1015 // perform the following
1016 // 1. file expansion
1017 // 2. RegExp expansion
1018 // 3. Json Expansion
1019 // 4. string expansion of values such as (i.e. -f --option key=value argv0 argv1)
1020 keyValue = expandString(keyValue);
1021
1022 if (typeof argAt == 'object' && keyValue != null) {
1023 // expand the object result
1024 // if this is an array, expandObject will direct to expandArray
1025 expandObject(keyValue);
1026 }
1027
1028 // overwrite current key
1029 obj[key] = keyValue;
1030 }
1031 }
1032 return this;
1033 }
1034
1035 ArguMints.prototype.matches = function(startIdx, endIdx) {
1036 var ret = null;
1037 if (_commandTable.opt['minty-match-argv']) {
1038 ret = _commandTable.argvmatch;
1039 }
1040 else if (_commandTable.opt['minty-match-kv']) {
1041 ret = _commandTable.kvmatch;
1042 }
1043
1044 // bail if options weren't set
1045 if (ret == null) {
1046 return [];
1047 }
1048
1049 if (ret.length == 0) {
1050 return ret.concat();
1051 }
1052
1053 if (startIdx === undefined) {
1054 startIdx = 0;
1055 }
1056 if (endIdx === undefined) {
1057 endIdx = ret.length - 1;
1058 }
1059
1060 if (startIdx == 0 && endIdx == (ret.length - 1)) {
1061 return ret.concat();
1062 }
1063
1064 // slice it up and return the sub array
1065 return ret.slice(startIdx, endIdx);
1066 }
1067
1068
1069 ArguMints.extensions = new ArguMintsExtensions();
1070
1071 ArguMints.extensions.addExtension('minty-op-add', function(keyStore, key, value) {
1072 keyStore[key.trim()] += value;
1073 return this;
1074 });
1075
1076 // add extensions
1077
1078 ArguMints.extensions.addExtension('minty-op-sub', function(keyStore, key, value) {
1079 keyStore[key.trim()] -= value;
1080
1081 return this;
1082 });
1083
1084 ArguMints.extensions.addExtension('minty-op-mul', function(keyStore, key, value) {
1085 keyStore[key.trim()] *= value;
1086 return this;
1087 });
1088
1089 ArguMints.extensions.addExtension('minty-op-div', function(keyStore, key, value) {
1090 keyStore[key.trim()] /= value;
1091 return this;
1092 });
1093
1094 ArguMints.extensions.addExtension('minty-op-sqrt', function(keyStore, key, value) {
1095 keyStore[key.trim()] += Math.sqrt(value);
1096 return this;
1097 });
1098
1099 ArguMints.extensions.addExtension('minty-op-sqr', function(keyStore, key, value) {
1100 keyStore[key.trim()] += Math.pow(value, 2);
1101 return this;
1102 });
1103
1104 ArguMints.extensions.addExtension('minty-op-ln', function(keyStore, key, value) {
1105
1106 keyStore[key.trim()] += Math.log(value);
1107 return this;
1108 });
1109
1110 ArguMints.extensions.addExtension('minty-op-cos', function(keyStore, key, value) {
1111 keyStore[key.trim()] += Math.cos(value);
1112 return this;
1113 });
1114
1115 ArguMints.extensions.addExtension('minty-op-sin', function(keyStore, key, value) {
1116 keyStore[key.trim()] += Math.sin(value);
1117 return this;
1118 });
1119
1120 ArguMints.extensions.addExtension('minty-op-tan', function(keyStore, key, value) {
1121 keyStore[key.trim()] += Math.tan(value);
1122 return this;
1123 });
1124
1125 ArguMints.extensions.addExtension('minty-op-atan', function(keyStore, key, value) {
1126 keyStore[key.trim()] += Math.atan(value);
1127 return this;
1128 });
1129
1130 ArguMints.extensions.addExtension('minty-op-exp', function(keyStore, key, value) {
1131 keyStore[key.trim()] += Math.exp(value);
1132 return this;
1133 });
1134 }
1135
1136 // Prototype Setup
1137 ArguMints.verbose = false;
1138 ArguMints.REPL = false;
1139
1140 // Export the prototype so others can create instances
1141 module.exports.ArguMints = ArguMints;
1142
1143 // Export a Default instance for anyone to use
1144 module.exports.myArguMints = new ArguMints({
1145 treatBoolStringsAsBoolean : true,
1146 treatNullStringsAsNull : true,
1147 treatRegExStringsAsRegEx : true,
1148 treatNumberStringsAsNumbers : true,
1149 treatUndefinedStringsAsUndefined : true,
1150 enableFileExpansion : true,
1151 ignoreJson : false
1152 });
1153}.call(this));