@shko.online/dataverse-odata
Version:
This package will help parse OData strings (only the Microsoft Dataverse subset). It can be used as a validator, or you can build some javascript library which consumes the output of this library.
122 lines (120 loc) • 3.51 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getExpandFromParser = void 0;
var _getSelectFromParser = require("./getSelectFromParser");
var _atMostOnce = require("./validators/atMostOnce");
const option = '$expand';
/**
* Parses the {@link ODataExpand.$expand $expand} query
* @returns Returns `false` when the parse has an error
*/
const getExpandFromParser = (parser, result) => {
const value = parser.getAll(option);
if (value.length === 0) {
return true;
}
if (!(0, _atMostOnce.atMostOnce)(option, value, result)) {
return false;
}
result.$expand = {};
if (!extractExpand(value[0], result)) {
return false;
}
return true;
};
exports.getExpandFromParser = getExpandFromParser;
const extractExpand = (value, $expand) => {
const match = value.match(/^\s*(\w(\w|\d|_)*)\s*(,|\(|\))?\s*/);
if (match === null || match[0].length < value.length && match[3] === null || match[0].length === value.length && match[3] !== undefined) {
$expand.error = {
code: '0x0',
message: `Term '${value}' is not valid in a $select or $expand expression.`
};
return false;
}
let matchSeparator = match[3];
let matchLength = match[0].length;
if (matchSeparator !== '(') {
if ($expand.$expand !== undefined) {
$expand.$expand[match[1]] = {
$select: []
};
}
} else {
const {
index,
error
} = getClosingBracket(value.substring(matchLength));
if (error) {
$expand.error = {
code: '0x0',
message: error
};
return false;
}
if ($expand.$expand !== undefined) {
const innerExpand = {};
const parser = new URLSearchParams('?' + value.substring(matchLength, matchLength + index));
if (!(0, _getSelectFromParser.getSelectFromParser)(parser, innerExpand)) {
$expand.error = innerExpand.error;
return false;
}
if (!getExpandFromParser(parser, innerExpand)) {
$expand.error = innerExpand.error;
return false;
}
if (innerExpand.$expand === undefined && innerExpand.$select === undefined) {
$expand.error = {
code: '0x0',
message: `Missing expand option on navigation property '${match[1]}'. If a parenthesis expression follows an expanded navigation property, then at least one expand option must be provided.`
};
return false;
}
$expand.$expand[match[1]] = innerExpand;
}
matchLength = matchLength + index;
const secondMatch = value.substring(matchLength + 1).match(/\s*(,?)\s*d/);
if (secondMatch !== null) {
matchLength = matchLength + secondMatch[0].length;
if (secondMatch[1] !== null) {
matchSeparator = ',';
}
}
}
if (matchSeparator === ',') {
if (!extractExpand(value.substring(matchLength), $expand)) {
return false;
}
}
return true;
};
const getClosingBracket = value => {
let depth = 1;
let startAt = 0;
while (depth > 0) {
const match = value.substring(startAt).match(/\(|\)/);
if (match === null) {
return {
error: 'Found an unbalanced bracket expression.',
index: -1
};
}
if (match[0] === ')') {
depth -= 1;
if (depth === 0) {
return {
index: match.index || 0
};
}
} else {
depth += 1;
}
startAt += (match.index || 0) + 1;
}
return {
error: 'Found an unbalanced bracket expression.',
index: -1
};
};