pailingual-odata-csdl-xml
Version:
Implements reading XML metadata document for pailingual-odata
569 lines • 24.2 kB
JavaScript
"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