UNPKG

pailingual-odata-csdl-xml

Version:

Implements reading XML metadata document for pailingual-odata

569 lines 24.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const pailingual_odata_1 = require("pailingual-odata"); function loadFromXml(xml) { const document = new DOMParser() .parseFromString(xml, "text/xml"); return read(document); } exports.loadFromXml = loadFromXml; function copyAttributeValue(elem, attr, target, prop, convert) { const a = elem.attributes.getNamedItem(attr); if (a) target[prop] = convert ? convert(a.value) : a.value; } function convertBoolean(v) { return JSON.parse(v) === true; } function read(document) { const rootNode = document.firstElementChild; const versionAttr = rootNode.attributes.getNamedItem("Version"); if (!versionAttr) throw new Error("Version attribute not found."); const version = versionAttr.value; if (version != "4.0" && version != "4.01") throw new Error("Not supported CSDL version"); const metadataDocument = { $Version: version, $ApiRoot: "" }; for (let item of readEachChild(rootNode)) { if (item.kind == pailingual_odata_1.csdl.CsdlKind.Namespace) metadataDocument[item.name] = item.result; else if (item.kind == pailingual_odata_1.csdl.CsdlKind.Reference) { let refobj = metadataDocument.$Reference = (metadataDocument.$Reference || {}); refobj[item.name] = item.result; } } return metadataDocument; } function readActionImport(elem) { const name = elem.getAttribute("Name"); const action = elem.getAttribute("Action"); const result = { $Kind: pailingual_odata_1.csdl.CsdlKind.ActionImport, $Action: action }; copyAttributeValue(elem, "EntitySet", result, "$EntitySet"); return { name, kind: result.$Kind, result }; } function readAnnotation(elem) { const term = elem.getAttribute("Term"); let name = "@" + term; const qualifierAttr = elem.attributes.getNamedItem("Qualifier"); if (qualifierAttr) name += "#" + qualifierAttr.value; const additionalAttrs = Array.from(elem.attributes).filter(a => a.localName != "Term" && a.localName != "Qualifier"); const results = additionalAttrs.map(a => readDynamicExpression(a)[0]); let resultFromAttrs = results.length == 0 ? true : results.length == 1 ? results[0].result : results.map(r => r.result); let resultFromChieldren = []; for (var i = 0; i < elem.childElementCount; i++) { resultFromChieldren.push(...readDynamicExpression(elem.children.item(i))); } const result = resultFromChieldren.length == 0 ? resultFromAttrs : resultFromChieldren .reduce((p, c) => { if (!c.name) return c.result; p[c.name] = c.result; return p; }, {}); return { name, kind: pailingual_odata_1.csdl.CsdlKind.Annotation, result, childReaded: true }; } function readApply(elem) { const func = elem.getAttribute("Function"); const result = { $Apply: [], $Function: func }; for (var i = 0; i < elem.childElementCount; i++) { for (const item of readDynamicExpression(elem.children.item(i))) { if (item.kind == pailingual_odata_1.csdl.CsdlKind.Annotation) result[item.name] = item.result; else result.$Apply.push(item.name ? { [item.name]: item.result } : item.result); } } return { name: "", kind: undefined, result }; } function readCast(elem) { const result = {}; const operator = "$" + elem.localName; for (let i = 0; i < elem.attributes.length; i++) { const attr = elem.attributes.item(i); result["$" + attr.localName] = attr.value; } for (var i = 0; i < elem.childElementCount; i++) { let item = readDynamicExpression(elem.children.item(i))[0]; result[item.name || operator] = item.result; } return { name: "", kind: undefined, result, childReaded: true }; } function readCollection(elem) { const result = []; for (var i = 0; i < elem.childElementCount; i++) { for (const item of readDynamicExpression(elem.children.item(i))) result.push(item.result); } return { name: "", kind: undefined, result }; } function readComplexType(elem) { const name = elem.getAttribute("Name"); const result = { $Kind: pailingual_odata_1.csdl.CsdlKind.ComplexType }; copyAttributeValue(elem, "BaseType", result, "$BaseType"); copyAttributeValue(elem, "Abstract", result, "$Abstract", convertBoolean); copyAttributeValue(elem, "OpenType", result, "$OpenType", convertBoolean); for (let item of readEachChild(elem)) result[item.name] = item.result; return { name, kind: result.$Kind, result }; } function readDynamicExpression(node) { const element = node; switch (node.nodeName.toUpperCase()) { case "ANNOTATION": return [readAnnotation(element)]; case "COLLECTION": return [readCollection(element)]; case "RECORD": return [readRecord(element)]; case "LABELEDELEMENT": return [readLabeledElement(element)]; case "ANNOTATIONPATH": case "LABELEDELEMENTREFERENCE": case "MODELELEMENTPATH": case "NAVIGATIONPROPERTYPATH": case "PROPERTYPATH": case "PATH": case "BINARY": case "DATE": case "DECIMAL": case "DURATION": case "GUID": case "TIMEOFDAY": return [readPathOrConstExpression(node)]; case "DATETIMEOFFSET": return [{ name: "", kind: undefined, result: { "$DateTimeOffset": new Date(node.textContent).toISOString() } }]; case "FLOAT": return [readFloatConstExpression(node)]; case "BOOL": return [{ name: "", kind: undefined, result: convertBoolean(node.textContent.trim()) }]; case "INT": return [{ name: "", kind: undefined, result: { "$Int": parseInt(node.textContent.trim()) } }]; case "STRING": return [{ name: "", kind: undefined, result: node.textContent }]; case "NULL": return [{ name: "", kind: undefined, result: { "$Null": null } }]; case "ENUMMEMBER": let result = node.textContent .split(" ") .map(_ => _.split("/")[1]) .join(","); return [{ name: "", kind: undefined, result: { "$EnumMember": result } }]; case "PROPERTYVALUE": return readPropertyValue(element); case "APPLY": return [readApply(element)]; case "ISOF": case "CAST": return [readCast(element)]; case "URLREF": case "IF": case "AND": case "OR": case "NOT": case "EQ": case "NE": case "GT": case "GE": case "LT": case "LE": case "HAS": case "IN": case "ADD": case "SUB": case "NEG": case "MUL": case "DIV": case "DIVBY": case "MOD": return [readDynamicExpressionOperators(element)]; default: throw new Error(`Unknown element ${node.nodeName}`); } } function readDynamicExpressionOperators(elem) { const name = "$" + elem.localName; const chields = []; const result = {}; for (var i = 0; i < elem.childElementCount; i++) { const item = readDynamicExpression(elem.children.item(i))[0]; if (item.kind == pailingual_odata_1.csdl.CsdlKind.Annotation) result[item.name] = item.result; else chields.push(item.name ? { [item.name]: item.result } : item.result); } result[name] = chields.length == 1 ? chields[0] : chields; return { name: "", kind: undefined, result, childReaded: true }; } function readFloatConstExpression(node) { const content = node.textContent; const v = parseFloat(content); if (v) return { name: "", kind: undefined, result: v }; else return { name: "$Float", kind: undefined, result: content }; } function readFunctionImport(elem) { const name = elem.getAttribute("Name"); const func = elem.getAttribute("Function"); const result = { $Kind: pailingual_odata_1.csdl.CsdlKind.FunctionImport, $Function: func }; copyAttributeValue(elem, "EntitySet", result, "$EntitySet"); copyAttributeValue(elem, "IncludeInServiceDocument", result, "$IncludeInServiceDocument"); return { name, kind: result.$Kind, result }; } function readEntityContainer(elem) { const name = elem.getAttribute("Name"); const result = { $Kind: pailingual_odata_1.csdl.CsdlKind.EntityContainer }; copyAttributeValue(elem, "Extends", result, "$Extends"); for (const item of readEachChild(elem)) result[item.name] = item.result; return { name, kind: result.$Kind, result }; } function readEntitySet(elem) { const name = elem.getAttribute("Name"); const type = elem.getAttribute("EntityType"); const result = { $Kind: pailingual_odata_1.csdl.CsdlKind.EntitySet, $Type: type }; copyAttributeValue(elem, "IncludeInServiceDocument", result, "$IncludeInServiceDocument", convertBoolean); var navPropBindingsOrAnnotations = readEachChild(elem); if (navPropBindingsOrAnnotations.length > 0) { result.$NavigationPropertyBinding = {}; for (var item of navPropBindingsOrAnnotations) if (item.name[0] == "@") result[item.name] = item.result; else result.$NavigationPropertyBinding[item.name] = item.result; } return { name, kind: result.$Kind, result, childReaded: true }; } function readEntityType(elem) { const name = elem.getAttribute("Name"); const result = { $Kind: pailingual_odata_1.csdl.CsdlKind.EntityType }; copyAttributeValue(elem, "BaseType", result, "$BaseType"); copyAttributeValue(elem, "Abstract", result, "$Abstract", convertBoolean); copyAttributeValue(elem, "OpenType", result, "$OpenType", convertBoolean); copyAttributeValue(elem, "HasStream", result, "$HasStream", convertBoolean); for (let item of readEachChild(elem)) { result[item.name] = item.result; } return { name, kind: result.$Kind, result }; } function readEnumMember(elem) { const name = elem.getAttribute("Name"); const valueAttr = elem.attributes.getNamedItem("Value"); const value = valueAttr && parseInt(valueAttr.value); return { name, kind: undefined, result: value }; } function readEnumType(elem) { const name = elem.getAttribute("Name"); const result = { $Kind: pailingual_odata_1.csdl.CsdlKind.EnumType }; copyAttributeValue(elem, "UnderlyingType", result, "$UnderlyingType"); copyAttributeValue(elem, "IsFlags", result, "$IsFlags", convertBoolean); let pos = 0; for (var item of readEachChild(elem)) { if (item.kind !== pailingual_odata_1.csdl.CsdlKind.Annotation && !item.result) item.result = pos++; result[item.name] = item.result; } return { name, kind: result.$Kind, result, childReaded: true }; } function readEachChild(element) { var result = []; for (let i = 0; i < element.childElementCount; i++) { let readResult; const chield = element.children.item(i); switch (chield.localName.toUpperCase()) { case "REFERENCE": readResult = readReference(chield); break; case "INCLUDE": readResult = readInclude(chield); break; case "INCLUDEANNOTATIONS": readResult = readIncludeAnnotations(chield); break; case "DATASERVICES": result.push(...readEachChild(chield)); continue; case "SCHEMA": readResult = readSchema(chield); break; case "ENTITYTYPE": readResult = readEntityType(chield); break; case "KEY": readResult = readKey(chield); break; case "PROPERTY": readResult = readProperty(chield); break; case "NAVIGATIONPROPERTY": readResult = readNavigationProperty(chield); break; case "COMPLEXTYPE": readResult = readComplexType(chield); break; case "ENUMTYPE": readResult = readEnumType(chield); break; case "MEMBER": readResult = readEnumMember(chield); break; case "ACTION": case "FUNCTION": readResult = readOperation(chield); break; case "ENTITYCONTAINER": readResult = readEntityContainer(chield); break; case "ENTITYSET": readResult = readEntitySet(chield); break; case "SINGLETON": readResult = readSingleton(chield); break; case "NAVIGATIONPROPERTYBINDING": readResult = readNavigationPropertyBinding(chield); break; case "ACTIONIMPORT": readResult = readActionImport(chield); break; case "FUNCTIONIMPORT": readResult = readFunctionImport(chield); break; case "TYPEDEFINITION": readResult = readTypeDefinition(chield); break; case "TERM": break; case "ANNOTATION": readResult = readAnnotation(chield); break; default: throw new Error("Unknown element, " + chield.localName); } result.push(readResult); if (chield.childElementCount > 0 && readResult.childReaded !== true) { for (let item of readEachChild(chield)) if (readResult.result && typeof readResult.result == "object") readResult.result[item.name] = item.result; else result.push({ name: readResult.name + item.name, kind: item.kind, result: item.result }); } } return result; } function readInclude(elem) { const ns = elem.getAttribute("Namespace"); const result = { $Namespace: ns }; copyAttributeValue(elem, "Alias", result, "$Alias"); return { name: "$Include", kind: undefined, result }; } function readIncludeAnnotations(elem) { const termNs = elem.getAttribute("TermNamespace"); const result = { $TermNamespace: termNs }; copyAttributeValue(elem, "Qualifier", result, "$Qualifier"); copyAttributeValue(elem, "TargetNamespace", result, "$TargetNamespace"); return { name: "$IncludeAnnotations", kind: undefined, result }; } function readKey(elem) { const result = []; for (var i = 0; i < elem.childElementCount; i++) { const chield = elem.children.item(i); const name = chield.attributes.getNamedItem("Name").value; const aliasAttr = chield.attributes.getNamedItem("Alias"); result.push(aliasAttr ? { [aliasAttr.value]: name } : name); } return { name: "$Key", kind: undefined, result, childReaded: true }; } function readLabeledElement(elem) { const name = elem.getAttribute("Name"); const nodes = Array.from(elem.attributes).filter(a => a.nodeName !== "Name") .concat(Array.from(elem.children)); const result = { $LabeledElement: null, $Name: name }; for (let n of nodes) { for (const r of readDynamicExpression(n)) { if (r.kind == pailingual_odata_1.csdl.CsdlKind.Annotation) result[r.name] = r.result; else result.$LabeledElement = r.name ? { [r.name]: r.result } : r.result; } } return { name: "", kind: undefined, result }; } function readNavigationProperty(elem) { const name = elem.getAttribute("Name"); const type = elem.getAttribute("Type"); const result = { $Kind: pailingual_odata_1.csdl.CsdlKind.NavigationProperty, $Type: unwrapType(type) }; if (type !== result.$Type) result.$Collection = true; const nullableAttr = elem.attributes.getNamedItem("Nullable"); result.$Nullable = nullableAttr === undefined || nullableAttr === null || nullableAttr.value.toLowerCase() === "true"; copyAttributeValue(elem, "Partner", result, "$Partner"); copyAttributeValue(elem, "ContainsTarget", result, "$ContainsTarget", convertBoolean); for (var i = 0; i < elem.childElementCount; i++) { const chield = elem.children.item(i); if (chield.tagName.toUpperCase() === "ONDELETE") { result.$OnDelete = chield.attributes.getNamedItem("Action").value; for (let item of readEachChild(chield)) //Annotations result["$OnDelete" + item.name] = item.result; } else if (chield.tagName.toUpperCase() === "REFERENTIALCONSTRAINT") { const targ = result.$ReferentialConstraint = (result.$ReferentialConstraint || {}); const property = chield.attributes.getNamedItem("Property").value; targ[property] = chield.attributes.getNamedItem("ReferencedProperty").value; for (let item of readEachChild(chield)) //Annotations targ[property + item.name] = item.result; } } return { name, kind: result.$Kind, result, childReaded: true }; } function readNavigationPropertyBinding(elem) { const path = elem.getAttribute("Path"); const target = elem.getAttribute("Target"); return { name: path, kind: undefined, result: target }; } function readOperation(elem) { const name = elem.getAttribute("Name"); const kind = elem.tagName.toUpperCase() == "ACTION" ? pailingual_odata_1.csdl.CsdlKind.Action : pailingual_odata_1.csdl.CsdlKind.Function; const result = { $Kind: kind }; copyAttributeValue(elem, "IsBound", result, "$IsBound", convertBoolean); copyAttributeValue(elem, "EntitySetPath", result, "$EntitySetPath"); for (var i = 0; i < elem.childElementCount; i++) { const chield = elem.children.item(i); if (chield.tagName.toUpperCase() === "RETURNTYPE") { result.$ReturnType = {}; readTypeReference(chield, result.$ReturnType); for (let item of readEachChild(chield)) //Annotations result.$ReturnType[item.name] = item.result; } else if (chield.tagName.toUpperCase() === "PARAMETER") { const paramName = chield.attributes.getNamedItem("Name").value; const parameter = { $Name: paramName }; readTypeReference(chield, parameter); (result.$Parameter = (result.$Parameter || [])) .push(parameter); for (let item of readEachChild(chield)) //Annotations parameter[item.name] = item.result; } } return { name, kind, result, childReaded: true }; } function readPathOrConstExpression(node) { return { name: "", kind: undefined, result: { ["$" + node.nodeName]: node.textContent } }; } function readProperty(elem) { const name = elem.getAttribute("Name"); const result = { $Kind: pailingual_odata_1.csdl.CsdlKind.Property }; readTypeReference(elem, result); copyAttributeValue(elem, "DefaultValue", result, "$DefaultValue"); return { name, kind: result.$Kind, result }; } function readPropertyValue(elem) { const prop = elem.getAttribute("Property"); const nodes = Array.from(elem.attributes).filter(a => a.nodeName !== "Property") .concat(Array.from(elem.children)); const result = []; for (let n of nodes) { for (let r of readDynamicExpression(n)) { r.name = prop + r.name; result.push(r); } } return result; } function readRecord(elem) { const result = {}; for (var i = 0; i < elem.childElementCount; i++) { for (const item of readDynamicExpression(elem.children.item(i))) result[item.name] = item.result; } return { name: "", kind: undefined, result }; } function readReference(elem) { const name = elem.getAttribute("Uri"); const result = {}; for (let item of readEachChild(elem)) { const array = item.name === "$Include" ? (result.$Include = result.$Include || []) : (result.$IncludeAnnotations = result.$IncludeAnnotations || []); array.push(item.result); } return { name, kind: pailingual_odata_1.csdl.CsdlKind.Reference, result, childReaded: true }; } function readSchema(elem) { const name = elem.getAttribute("Namespace"); const result = {}; const aliasAttr = elem.attributes.getNamedItem("Alias"); if (aliasAttr) result.$Alias = aliasAttr.value; for (let item of readEachChild(elem)) { if (item.kind === pailingual_odata_1.csdl.CsdlKind.Action || item.kind === pailingual_odata_1.csdl.CsdlKind.Function) (result[item.name] = (result[item.name] || [])).push(item.result); else result[item.name] = item.result; } return { name, kind: pailingual_odata_1.csdl.CsdlKind.Namespace, result, childReaded: true }; } function readSingleton(elem) { const name = elem.getAttribute("Name"); const type = elem.getAttribute("Type"); const result = { $Kind: pailingual_odata_1.csdl.CsdlKind.Singleton, $Type: type }; var navPropBindings = readEachChild(elem); if (navPropBindings.length > 0) { result.$NavigationPropertyBinding = {}; for (var binding of navPropBindings) result.$NavigationPropertyBinding[binding.name] = binding.result; } return { name, kind: result.$Kind, result, childReaded: true }; } function readTypeDefinition(elem) { const name = elem.getAttribute("Name"); const underlyingType = elem.getAttribute("UnderlyingType"); const result = { $Kind: pailingual_odata_1.csdl.CsdlKind.TypeDefinition, $UnderlyingType: underlyingType }; copyAttributeValue(elem, "MaxLength", result, "$MaxLength", v => parseInt(v)); copyAttributeValue(elem, "Unicode", result, "$Unicode", convertBoolean); copyAttributeValue(elem, "Precision", result, "$Precision", v => parseInt(v)); copyAttributeValue(elem, "Scale", result, "$Scale"); copyAttributeValue(elem, "SRID", result, "$SRID"); return { name, kind: pailingual_odata_1.csdl.CsdlKind.TypeDefinition, result }; } function readTypeReference(elem, target) { let type = elem.getAttribute("Type"); target.$Type = unwrapType(type); if (type !== target.$Type) target.$Collection = true; const nullableAttr = elem.attributes.getNamedItem("Nullable"); target.$Nullable = nullableAttr === undefined || nullableAttr === null || nullableAttr.value.toLowerCase() === "true"; copyAttributeValue(elem, "MaxLength", target, "$MaxLength", parseInt); copyAttributeValue(elem, "Precision", target, "$Precision", parseInt); copyAttributeValue(elem, "Sacle", target, "$Scale"); copyAttributeValue(elem, "Unicode", target, "$Unicode", convertBoolean); copyAttributeValue(elem, "SRID", target, "$SRID"); } function unwrapType(type) { if (type.startsWith("Collection(")) { return type.substring(11, type.length - 1); } return type; } //# sourceMappingURL=index.js.map