UNPKG

odatafy-parser

Version:

generate odatafy ast from odata query parameters

228 lines (213 loc) 9.61 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.processExpandOptionsUnprocessedNode = void 0; const peggy_1 = __importDefault(require("peggy")); const querystring_1 = __importDefault(require("querystring")); const errors_1 = require("../types/errors"); const nodes_1 = require("../types/nodes"); const utils_1 = require("../utils"); const computeParser_1 = __importDefault(require("./computeParser")); const filterParser_1 = __importDefault(require("./filterParser")); const levelsParser_1 = __importDefault(require("./levelsParser")); const orderbyParser_1 = __importDefault(require("./orderbyParser")); const searchParser_1 = __importDefault(require("./searchParser")); const selectParser_1 = __importDefault(require("./selectParser")); const skipParser_1 = __importDefault(require("./skipParser")); const topParser_1 = __importDefault(require("./topParser")); const expandParser = peggy_1.default.generate(` { function ExpandNodeHelper(value) { return { nodeType: "ExpandNode", value: value.filter(expandItem => expandItem != undefined) } } function ExpandPathNodeHelper(value, expOps) { return expOps && expOps.value != ""?{ nodeType: "ExpandPathNodeWithOptions", value: value.filter(expandPathItem => expandPathItem != undefined), options:expOps } : { nodeType: "ExpandPathNode", value: value.filter(expandPathItem => expandPathItem != undefined) } } function ExpandIdentifierNodeHelper(value, flag) { return { nodeType: "ExpandIdentifierNode", value: value, ...(flag && {flag: flag}) } } function ExpandFunctionNodeHelper(func, args) { return { nodeType: "ExpandFunctionNode", func: func, args: args } } function ExpandOptionsUnprocessedNodeHelper(expandOptionsString, type) { return { nodeType: "ExpandOptionsUnprocessedNode", value: expandOptionsString, type: type } } function ExpandStarNodeHelper(options) { return { nodeType: "ExpandStarNode", ...(options && {options: options}) } } function ExpandValueNodeHelper() { return { nodeType: "ExpandValueNode" } } } start = head:expandItem tail:(COMMA @expandItem)* {return ExpandNodeHelper([head, ...tail])} expandItem = "$value" {return ExpandPathNodeHelper([ExpandValueNodeHelper()])} / identNode:odataIdentifierWithNamespace !("/" / "(") {return ExpandPathNodeHelper([identNode])} / identNode:odataIdentifier !("/" / "." / "(") {return ExpandPathNodeHelper([identNode])} / expandPath //if there is a dollar sign, dont read the ident here so that it can be read later expandPath = path1: ( @( odataIdentifierWithNamespace / odataIdentifier ) "/" !"$")* path2: ( STAR options:( ref {return {ref: true}} / OPEN levels:levels CLOSE {return {levels: levels}} )? {return {path: [ExpandStarNodeHelper(options)]}} / ident1:(odataIdentifier / odataAnnotation) ident2:( "/" @(odataIdentifierWithNamespace/odataIdentifier) )? expOps:( type:(ref {return "ref"} / count {return "count"} / "" &OPEN {return "default"}) optionString:expandOptions? {return ExpandOptionsUnprocessedNodeHelper(optionString, type)} )? {return {path: [ident1, ident2], expOps: expOps}} ) {return ExpandPathNodeHelper([...path1, ...path2.path], path2.expOps)} count = "/$count" ref = "/$ref" odataAnnotation = AT identNode:(odataIdentifierWithNamespace / odataIdentifier) {return {...identNode, flag: "Annotation"}} expandOptions = OPEN expandOptionString:$textUntilTerminator CLOSE {return expandOptionString} textUntilTerminator = ( &haveTerminatorAhead .)* haveTerminatorAhead = . ( !")" . )* ")" levels = ( "$levels" / "levels" ) EQ value:( oneToNine DIGIT* / "max" ) {return value} odataIdentifierWithNamespace = value:$(odataIdentifier ( "." odataIdentifier )+) {return ExpandIdentifierNodeHelper(value)} odataIdentifier = value:$(identifierLeadingCharacter identifierCharacter*) {return ExpandIdentifierNodeHelper(value)} identifierLeadingCharacter = ALPHA / "_" identifierCharacter = ALPHA / "_" / DIGIT oneToNine = "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9" AT = "@" / "%40" ALPHA = [a-zA-Z] DIGIT = [0-9] COMMA = "," / "%2C" STAR = "*" / "%2A" EQ = "=" OPEN = "(" / "%28" CLOSE = ")" / "%29" RWS = ( SP / HTAB / "%20" / "%09" )+ BWS = ( SP / HTAB / "%20" / "%09" )* SP = ' ' HTAB = ' ' `, { trace: false }); function parseExpand(expr) { let ast; try { ast = expandParser.parse(expr); } catch (e) { throw (0, utils_1.getOdatafyParserError)('malformed expand expression', errors_1.OdatafyQueryOptions.Expand); } try { for (const expandItem of ast.value) { if (expandItem.nodeType == nodes_1.NodeTypes.ExpandPathNodeWithOptions) { const expandOptions = processExpandOptionsUnprocessedNode(expandItem.options); expandItem.options = expandOptions.value; expandItem.optionType = expandOptions.type; } } return ast; } catch (e) { throw (0, utils_1.getOdatafyParserError)('malformed expand options', errors_1.OdatafyQueryOptions.Expand); } } function processExpandOptionsUnprocessedNode(expandOptionsUnprocessedNode) { const parsedOptions = querystring_1.default.parse(expandOptionsUnprocessedNode.value, ';'); const options = {}; //parse options with $ if (parsedOptions.$filter && typeof parsedOptions.$filter == 'string') { options.filter = filterParser_1.default.parse(parsedOptions.$filter); } if (parsedOptions.$orderby && typeof parsedOptions.$orderby == 'string') { options.orderby = orderbyParser_1.default.parse(parsedOptions.$orderby); } if (parsedOptions.$skip && typeof parsedOptions.$skip == 'string') { options.skip = skipParser_1.default.parse(parsedOptions.$skip); } if (parsedOptions.$top && typeof parsedOptions.$top == 'string') { options.top = topParser_1.default.parse(parsedOptions.$top); } if (parsedOptions.$select && typeof parsedOptions.$select == 'string') { options.select = selectParser_1.default.parse(parsedOptions.$select); } if (parsedOptions.$compute && typeof parsedOptions.$compute == 'string') { options.compute = computeParser_1.default.parse(parsedOptions.$compute); } if (parsedOptions.$expand && typeof parsedOptions.$expand == 'string') { options.expand = parseExpand(parsedOptions.$expand); } if (parsedOptions.$count && typeof parsedOptions.$count == 'string') { options.count = true; } if (parsedOptions.$search && typeof parsedOptions.$search == 'string') { options.search = searchParser_1.default.parse(parsedOptions.$search); } if (parsedOptions.$levels && typeof parsedOptions.$levels == 'string') { options.levels = levelsParser_1.default.parse(parsedOptions.$levels); } //parse options without $ if (parsedOptions.filter && typeof parsedOptions.filter == 'string') { options.filter = filterParser_1.default.parse(parsedOptions.filter); } if (parsedOptions.orderby && typeof parsedOptions.orderby == 'string') { options.orderby = orderbyParser_1.default.parse(parsedOptions.orderby); } if (parsedOptions.skip && typeof parsedOptions.skip == 'string') { options.skip = skipParser_1.default.parse(parsedOptions.skip); } if (parsedOptions.top && typeof parsedOptions.top == 'string') { options.top = topParser_1.default.parse(parsedOptions.top); } if (parsedOptions.select && typeof parsedOptions.select == 'string') { options.select = selectParser_1.default.parse(parsedOptions.select); } if (parsedOptions.compute && typeof parsedOptions.compute == 'string') { options.compute = computeParser_1.default.parse(parsedOptions.compute); } if (parsedOptions.expand && typeof parsedOptions.expand == 'string') { options.expand = parseExpand(parsedOptions.expand); } if (parsedOptions.count && typeof parsedOptions.count == 'string') { options.count = true; } if (parsedOptions.search && typeof parsedOptions.search == 'string') { options.search = searchParser_1.default.parse(parsedOptions.search); } if (parsedOptions.levels && typeof parsedOptions.levels == 'string') { options.levels = levelsParser_1.default.parse(parsedOptions.levels); } //TODO search return { value: options, type: expandOptionsUnprocessedNode.type }; } exports.processExpandOptionsUnprocessedNode = processExpandOptionsUnprocessedNode; exports.default = { /** * Parser for expand expressions * @param expr expand expression as string * @example expandParser.parse("Items/$ref") * @returns Abstract Syntax Tree (AST) of type ExpandNode */ parse: parseExpand };