@rsql/emitter
Version:
RSQL Emitter
225 lines (217 loc) • 6.65 kB
JavaScript
(function (global, factory) {
typeof exports === "object" && typeof module !== "undefined"
? factory(exports)
: typeof define === "function" && define.amd
? define(["exports"], factory)
: ((global = global || self), factory((global.RSQLEmitter = {})));
})(this, function (exports) {
"use strict";
var EQ = "==";
var NEQ = "!=";
var LE = "<=";
var GE = ">=";
var LT = "<";
var GT = ">";
var IN = "=in=";
var OUT = "=out=";
var LE_VERBOSE = "=le=";
var GE_VERBOSE = "=ge=";
var LT_VERBOSE = "=lt=";
var GT_VERBOSE = "=gt=";
function mapToCanonicalComparisonOperator(operator) {
switch (operator) {
case LE_VERBOSE:
return LE;
case LT_VERBOSE:
return LT;
case GE_VERBOSE:
return GE;
case GT_VERBOSE:
return GT;
default:
return operator;
}
}
var CUSTOM_OPERATOR_REGEXP = /^=[a-z]+=$/;
function isCustomComparisonOperator(candidate) {
return candidate.length > 2 && CUSTOM_OPERATOR_REGEXP.test(candidate);
}
function isComparisonOperator(candidate, operator) {
switch (candidate) {
case EQ:
case NEQ:
case LE:
case GE:
case LT:
case GT:
case IN:
case OUT:
case LE_VERBOSE:
case GE_VERBOSE:
case LT_VERBOSE:
case GT_VERBOSE:
return (
operator === undefined ||
mapToCanonicalComparisonOperator(candidate) === mapToCanonicalComparisonOperator(operator)
);
default:
if (isCustomComparisonOperator(candidate)) {
return operator === undefined || candidate === operator;
} else {
return false;
}
}
}
var AND = ";";
var OR = ",";
var AND_VERBOSE = "and";
var OR_VERBOSE = "or";
function mapToCanonicalLogicOperator(operator) {
switch (operator) {
case AND_VERBOSE:
return AND;
case OR_VERBOSE:
return OR;
default:
return operator;
}
}
function isLogicOperator(candidate, operator) {
switch (candidate) {
case AND:
case OR:
case AND_VERBOSE:
case OR_VERBOSE:
return (
operator === undefined || mapToCanonicalLogicOperator(candidate) === mapToCanonicalLogicOperator(operator)
);
default:
return false;
}
}
var ReservedChars = ['"', "'", "(", ")", ";", ",", "=", "!", "~", "<", ">", " ", "\n", "\t", "\r"];
var NodeType = {
SELECTOR: "SELECTOR",
VALUE: "VALUE",
COMPARISON: "COMPARISON",
LOGIC: "LOGIC",
};
function isNode(candidate) {
return candidate !== undefined && candidate !== null && Object.prototype.hasOwnProperty.call(candidate, "type");
}
function isComparisonNode(candidate, operator) {
return (
isNode(candidate) &&
candidate.type === NodeType.COMPARISON &&
(operator === undefined || isComparisonOperator(candidate.operator, operator))
);
}
function isLogicNode(candidate, operator) {
return (
isNode(candidate) &&
candidate.type === NodeType.LOGIC &&
(operator === undefined || isLogicOperator(candidate.operator, operator))
);
}
var DEFAULT_EMIT_OPTIONS = {
preferredQuote: '"',
optimizeQuotes: true,
};
var NEEDS_ESCAPING = {
'"': /"|\\/g,
"'": /'|\\/g,
};
function escapeQuotes(value, quote) {
return value.replace(NEEDS_ESCAPING[quote], "\\$&");
}
function countQuote(value, quote) {
var count = 0;
for (var i = 0; i < value.length; ++i) {
if (value[i] === quote) {
count++;
}
}
return count;
}
function selectQuote(value, _a) {
var _b = _a.preferredQuote,
preferredQuote = _b === void 0 ? DEFAULT_EMIT_OPTIONS.preferredQuote : _b,
_c = _a.optimizeQuotes,
optimizeQuotes = _c === void 0 ? DEFAULT_EMIT_OPTIONS.optimizeQuotes : _c;
if (optimizeQuotes) {
var otherQuote = preferredQuote === '"' ? "'" : '"';
return countQuote(value, otherQuote) < countQuote(value, preferredQuote) ? otherQuote : preferredQuote;
} else {
return preferredQuote;
}
}
function escapeValue(value, options) {
if (
value === "" ||
ReservedChars.some(function (reservedChar) {
return value.includes(reservedChar);
})
) {
var quote = selectQuote(value, options);
return "" + quote + escapeQuotes(value, quote) + quote;
}
return value;
}
function emitSelector(node) {
return node.selector;
}
function emitValue(node, options) {
return Array.isArray(node.value)
? "(" +
node.value
.map(function (value) {
return escapeValue(value, options);
})
.join(",") +
")"
: escapeValue(node.value, options);
}
function emitComparison(node, options) {
return "" + emitSelector(node.left) + node.operator + emitValue(node.right, options);
}
function emitLogic(node, options) {
var left = emitWithoutOptionsValidation(node.left, options);
var right = emitWithoutOptionsValidation(node.right, options);
// handle operator precedence - as it's only the case for AND operator, we don't need a generic logic for that
if (isLogicOperator(node.operator, AND)) {
if (isLogicNode(node.left, OR)) {
left = "(" + left + ")";
}
if (isLogicNode(node.right, OR)) {
right = "(" + right + ")";
}
}
// for verbose operator add space before and after operator
var operator =
node.operator === AND_VERBOSE || node.operator === OR_VERBOSE ? " " + node.operator + " " : node.operator;
return "" + left + operator + right;
}
function emitWithoutOptionsValidation(expression, options) {
if (isComparisonNode(expression)) {
return emitComparison(expression, options);
} else if (isLogicNode(expression)) {
return emitLogic(expression, options);
}
throw new TypeError('The "expression" has to be a valid "ExpressionNode", ' + String(expression) + " passed.");
}
function emit(expression, options) {
if (options === void 0) {
options = {};
}
if (options.preferredQuote !== undefined && options.preferredQuote !== '"' && options.preferredQuote !== "'") {
throw new TypeError(
'Invalid "preferredQuote" option: ' +
options.preferredQuote +
". Must be either \" (the ASCII double quote character) or ' (the ASCII single quote character)."
);
}
return emitWithoutOptionsValidation(expression, options);
}
exports.emit = emit;
Object.defineProperty(exports, "__esModule", { value: true });
});