168 lines
3.9 KiB
JavaScript
168 lines
3.9 KiB
JavaScript
'use strict';
|
||
|
||
Object.defineProperty(exports, '__esModule', { value: true });
|
||
|
||
/**
|
||
* Methods for consuming quoted values
|
||
*/
|
||
|
||
const SINGLE_QUOTE = 39; // '
|
||
const DOUBLE_QUOTE = 34; // "
|
||
|
||
const defaultOptions = {
|
||
escape: 92, // \ character
|
||
throws: false
|
||
};
|
||
|
||
/**
|
||
* Consumes 'single' or "double"-quoted string from given string, if possible
|
||
* @param {StreamReader} stream
|
||
* @param {Number} options.escape A character code of quote-escape symbol
|
||
* @param {Boolean} options.throws Throw error if quotes string can’t be properly consumed
|
||
* @return {Boolean} `true` if quoted string was consumed. The contents
|
||
* of quoted string will be availabe as `stream.current()`
|
||
*/
|
||
var eatQuoted = function(stream, options) {
|
||
options = options ? Object.assign({}, defaultOptions, options) : defaultOptions;
|
||
const start = stream.pos;
|
||
const quote = stream.peek();
|
||
|
||
if (stream.eat(isQuote)) {
|
||
while (!stream.eof()) {
|
||
switch (stream.next()) {
|
||
case quote:
|
||
stream.start = start;
|
||
return true;
|
||
|
||
case options.escape:
|
||
stream.next();
|
||
break;
|
||
}
|
||
}
|
||
|
||
// If we’re here then stream wasn’t properly consumed.
|
||
// Revert stream and decide what to do
|
||
stream.pos = start;
|
||
|
||
if (options.throws) {
|
||
throw stream.error('Unable to consume quoted string');
|
||
}
|
||
}
|
||
|
||
return false;
|
||
};
|
||
|
||
function isQuote(code) {
|
||
return code === SINGLE_QUOTE || code === DOUBLE_QUOTE;
|
||
}
|
||
|
||
/**
|
||
* Check if given code is a number
|
||
* @param {Number} code
|
||
* @return {Boolean}
|
||
*/
|
||
function isNumber(code) {
|
||
return code > 47 && code < 58;
|
||
}
|
||
|
||
/**
|
||
* Check if given character code is alpha code (letter through A to Z)
|
||
* @param {Number} code
|
||
* @param {Number} [from]
|
||
* @param {Number} [to]
|
||
* @return {Boolean}
|
||
*/
|
||
function isAlpha(code, from, to) {
|
||
from = from || 65; // A
|
||
to = to || 90; // Z
|
||
code &= ~32; // quick hack to convert any char code to uppercase char code
|
||
|
||
return code >= from && code <= to;
|
||
}
|
||
|
||
/**
|
||
* Check if given character code is alpha-numeric (letter through A to Z or number)
|
||
* @param {Number} code
|
||
* @return {Boolean}
|
||
*/
|
||
function isAlphaNumeric(code) {
|
||
return isNumber(code) || isAlpha(code);
|
||
}
|
||
|
||
function isWhiteSpace(code) {
|
||
return code === 32 /* space */
|
||
|| code === 9 /* tab */
|
||
|| code === 160; /* non-breaking space */
|
||
}
|
||
|
||
/**
|
||
* Check if given character code is a space
|
||
* @param {Number} code
|
||
* @return {Boolean}
|
||
*/
|
||
function isSpace(code) {
|
||
return isWhiteSpace(code)
|
||
|| code === 10 /* LF */
|
||
|| code === 13; /* CR */
|
||
}
|
||
|
||
const defaultOptions$1 = {
|
||
escape: 92, // \ character
|
||
throws: false
|
||
};
|
||
|
||
/**
|
||
* Eats paired characters substring, for example `(foo)` or `[bar]`
|
||
* @param {StreamReader} stream
|
||
* @param {Number} open Character code of pair openinig
|
||
* @param {Number} close Character code of pair closing
|
||
* @param {Object} [options]
|
||
* @return {Boolean} Returns `true` if chacarter pair was successfully
|
||
* consumed, it’s content will be available as `stream.current()`
|
||
*/
|
||
function eatPair(stream, open, close, options) {
|
||
options = options ? Object.assign({}, defaultOptions$1, options) : defaultOptions$1;
|
||
const start = stream.pos;
|
||
|
||
if (stream.eat(open)) {
|
||
let stack = 1, ch;
|
||
|
||
while (!stream.eof()) {
|
||
if (eatQuoted(stream, options)) {
|
||
continue;
|
||
}
|
||
|
||
ch = stream.next();
|
||
if (ch === open) {
|
||
stack++;
|
||
} else if (ch === close) {
|
||
stack--;
|
||
if (!stack) {
|
||
stream.start = start;
|
||
return true;
|
||
}
|
||
} else if (ch === options.escape) {
|
||
stream.next();
|
||
}
|
||
}
|
||
|
||
// If we’re here then paired character can’t be consumed
|
||
stream.pos = start;
|
||
|
||
if (options.throws) {
|
||
throw stream.error(`Unable to find matching pair for ${String.fromCharCode(open)}`);
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
exports.eatQuoted = eatQuoted;
|
||
exports.isQuote = isQuote;
|
||
exports.isAlpha = isAlpha;
|
||
exports.isNumber = isNumber;
|
||
exports.isAlphaNumeric = isAlphaNumeric;
|
||
exports.isSpace = isSpace;
|
||
exports.isWhiteSpace = isWhiteSpace;
|
||
exports.eatPair = eatPair;
|