shell-split
Version:
A lighterweight alternative to shell-quote
165 lines (134 loc) • 4.92 kB
JavaScript
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
define([], factory);
} else if (typeof module === 'object' && module.exports) {
module.exports = factory();
} else {
root.shellSplit = factory();
}
})(this, function(){
function UnterminatedSingleQuoteError() {
this.message = "Unterminated single-quoted string";
var error = new Error(this.message);
this.stack = error.stack;
}
UnterminatedSingleQuoteError.prototype = new Error();
UnterminatedSingleQuoteError.prototype.name =
UnterminatedSingleQuoteError.name;
UnterminatedSingleQuoteError.prototype.constructor =
UnterminatedSingleQuoteError;
function UnterminatedDoubleQuoteError() {
this.message = "Unterminated double-quoted string";
var error = new Error(this.message);
this.stack = error.stack;
}
UnterminatedDoubleQuoteError.prototype = new Error();
UnterminatedDoubleQuoteError.prototype.name =
UnterminatedDoubleQuoteError.name;
UnterminatedDoubleQuoteError.prototype.constructor =
UnterminatedDoubleQuoteError;
function UnterminatedEscapeError() {
this.message = "Unterminated backslash-escape";
var error = new Error(this.message);
this.stack = error.stack;
}
UnterminatedEscapeError.prototype = new Error();
UnterminatedEscapeError.prototype.name =
UnterminatedEscapeError.name;
UnterminatedEscapeError.prototype.constructor =
UnterminatedEscapeError;
function split(str) {
var rest = str.replace(/^\s+/,'');
if (!rest) return [];
var results = [''];
var position = 0;
var dq = false;
var match;
while (rest) {
// in double-quoted context
if (dq) {
match = /["\\]/.exec(rest);
if (!match) throw new UnterminatedDoubleQuoteError();
results[position] += rest.slice(0, match.index);
// append backslash escapes
if (match[0] == "\\") {
if (rest.length - match.index < 2)
throw new UnterminatedEscapeError();
// don't append escaped newlines
if (rest.charAt(1) != '\n')
results[position] += rest.charAt(match.index + 1);
rest = rest.slice(match.index + 2);
// for the other recognized decision point ("), exit double-quoting
} else {
rest = rest.slice(match.index + 1);
dq = false;
}
// out of double-quoted context
} else {
// split at any whitespace out of quoted context
match = /^\s+/.exec(rest);
if (match) {
rest = rest.slice(match[0].length);
// if there is remaining non-whitespace
if (rest) {
results[++position] = '';
}
}
// find the next decision point
match = /[\s'"\\]/.exec(rest);
// if there is an upcoming split or context switch
if (match) {
results[position] += rest.slice(0, match.index);
rest = rest.slice(match.index);
// append backslash escapes
if (match[0] == "\\") {
if (rest.length < 2) throw new UnterminatedEscapeError();
// don't append escaped newlines
if (rest.charAt(1) != '\n')
results[position] += rest.charAt(1);
rest = rest.slice(2);
// append single-quoted strings
} else if (match[0] == "'") {
match = rest.indexOf("'", 1);
if (match == -1) throw new UnterminatedSingleQuoteError();
results[position] += rest.slice(1, match);
rest = rest.slice(match + 1);
// enter double-quoted context
} else if (match[0] == '"') {
// move into double-quoted string
rest = rest.slice(1);
dq = true;
} // otherwise, we assume it's whitespace and will reiterate
// if we won't be entering any more contexts
} else {
// finish results
results[position] += rest;
rest = '';
}
}
}
return results;
}
function quoteEscape(str) {
str = String(str).replace(/[\\'"`${}[\]|&;<>()*?!]/g,'\\$&');
return /^$|^~|\s/.test(str) ? '"' + str + '"' : str;
}
function quote(args) {
return Array.isArray(args) ?
args.map(quoteEscape).join(' ') : quoteEscape(args);
}
// create a special clone of the split instance to attach exports to
var exported = split.bind(null);
exported.split = split;
exported.unquote = split;
exported.unescape = split;
exported.parse = split;
exported.quote = quote;
exported.join = quote;
exported.escape = quote;
exported.stringify = quote;
exported.UnterminatedSingleQuoteError = UnterminatedSingleQuoteError;
exported.UnterminatedDoubleQuoteError = UnterminatedSingleQuoteError;
exported.UnterminatedEscapeError = UnterminatedEscapeError;
return exported;
});