UNPKG

pailingual-odata

Version:

TypeScript client for OData v4 services

342 lines 16.1 kB
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; (function (factory) { if (typeof module === "object" && typeof module.exports === "object") { var v = factory(require, exports); if (v !== undefined) module.exports = v; } else if (typeof define === "function" && define.amd) { define(["require", "exports", "./utils"], factory); } })(function (require, exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const utils_1 = require("./utils"); const COLLECTION_TYPE_PREFIX = "Collection("; var EdmTypes; (function (EdmTypes) { EdmTypes["Int32"] = "Edm.Int32"; EdmTypes["Int16"] = "Edm.Int16"; EdmTypes["Boolean"] = "Edm.Boolean"; EdmTypes["String"] = "Edm.String"; EdmTypes["Single"] = "Edm.Single"; EdmTypes["Guid"] = "Edm.Guid"; EdmTypes["DateTimeOffset"] = "Edm.DateTimeOffset"; EdmTypes["Date"] = "Edm.Date"; EdmTypes["Double"] = "Edm.Double"; EdmTypes["TimeOfDay"] = "Edm.TimeOfDay"; EdmTypes["Decimal"] = "Edm.Decimal"; EdmTypes["Unknown"] = "Unknown"; })(EdmTypes = exports.EdmTypes || (exports.EdmTypes = {})); class EdmEntityType { constructor(name, properties, navProperties = {}, keys, baseType, openType) { this.name = name; this.properties = properties; this.navProperties = navProperties; this.keys = keys; this.baseType = baseType; this.openType = openType; this.getFullName = () => getFullName(this); } } exports.EdmEntityType = EdmEntityType; class EdmComplexType extends EdmEntityType { } exports.EdmComplexType = EdmComplexType; class EdmEnumType { constructor(name, members) { this.name = name; this.members = members; this.getFullName = () => getFullName(this); } } exports.EdmEnumType = EdmEnumType; class EdmEntityTypeReference { constructor(type, nullable = true, collection = false) { this.type = type; this.nullable = nullable; this.collection = collection; } static fromTypeReference(typeReference) { if (typeReference.type instanceof EdmEntityType) { return typeReference; } throw new Error("Instance must be reference to EdmEntityType"); } } exports.EdmEntityTypeReference = EdmEntityTypeReference; class EdmTypeReference { constructor(type, nullable = true, collection = false) { this.type = type; this.nullable = nullable; this.collection = collection; } } exports.EdmTypeReference = EdmTypeReference; ; class OperationMetadata { constructor(name, isAction, parameters, returnType, bindingTo) { this.name = name; this.isAction = isAction; this.parameters = parameters; this.returnType = returnType; this.bindingTo = bindingTo; this.getFullName = () => getFullName(this); } } exports.OperationMetadata = OperationMetadata; function getFullName(obj) { if (obj.namespace) return [obj.namespace.name, obj.name].join("."); return obj.name; } class Namespace { constructor(name) { this.name = name; this.operations = []; this.types = {}; } addTypes(...types) { for (let type of types) { type.namespace = this; this.types[type.name] = type; } } addOperations(...operations) { for (let operation of operations) { operation.namespace = this; this.operations.push(operation); } } } exports.Namespace = Namespace; ; var __metadataCache = {}; function loadMetadata(apiRoot, options, cache = true) { if (utils_1.endsWith(apiRoot, "/")) apiRoot = apiRoot.substr(0, apiRoot.length - 1); const normalizedApiRoot = apiRoot.toLowerCase(), res = __metadataCache[normalizedApiRoot]; if (res == null || !cache) { return ApiMetadata.loadAsync(apiRoot, options) .then(md => { if (cache) __metadataCache[normalizedApiRoot] = md; return md; }); } return Promise.resolve(res); } exports.loadMetadata = loadMetadata; class ApiMetadata { constructor(apiRoot, containerName, namespaces = {}, entitySets = {}, singletons = {}) { this.apiRoot = apiRoot; this.containerName = containerName; this.namespaces = namespaces; this.entitySets = entitySets; this.singletons = singletons; } static loadFromXml(apiRoot, metadataXml) { const parser = new DOMParser(); const metadataDoc = parser.parseFromString(metadataXml, "text/xml"); const namespaces = ApiMetadata.parseEntityTypes(metadataDoc); const entitySets = {}; const singletons = {}; const container = metadataDoc.querySelector("Schema>EntityContainer"); const containerName = container && getRequiredAttributeValue(container, "Name"); if (container) { const list = container.querySelectorAll("EntitySet,Singleton"); for (var i = 0; i < list.length; i++) { const e = list.item(i); const isSingleton = e.tagName.toUpperCase() === "SINGLETON"; let name = getRequiredAttributeValue(e, "Name"); let typeName = getRequiredAttributeValue(e, isSingleton ? "Type" : "EntityType"); const target = isSingleton ? singletons : entitySets; target[name] = ApiMetadata.getEntitySetMetadata(typeName, namespaces); } } const list3 = metadataDoc.querySelectorAll("Schema>Function,Schema>Action"); for (var i = 0; i < list3.length; i++) { const e = list3.item(i); const metadata = ApiMetadata.parseOperationMetadata(e, namespaces); const namespaceName = getRequiredAttributeValue(e.parentElement, "Namespace"); if (!namespaces[namespaceName]) namespaces[namespaceName] = new Namespace(namespaceName); namespaces[namespaceName].addOperations(metadata); } return new ApiMetadata(apiRoot, containerName, namespaces, entitySets, singletons); } static loadAsync(apiRoot, options) { return __awaiter(this, void 0, void 0, function* () { const uri = apiRoot + "/$metadata"; const opt = options || {}; const fetchApi = opt.fetch || fetch; const credentials = opt.credentials; const response = yield fetchApi(uri, { credentials }); return this.loadFromXml(apiRoot, yield response.text()); }); } static parseEntityTypes(metadataDoc) { let namespaces = {}; let entityTypes = []; const list = metadataDoc.querySelectorAll("Schema>ComplexType,Schema>EntityType,Schema>EnumType"); for (var i = 0; i < list.length; i++) { const e = list.item(i); const getOrAddEdmEntityType = function (namespace, name) { let namespaceMD = namespaces[namespace]; if (!namespaceMD) namespaces[namespace] = namespaceMD = new Namespace(namespace); let typeMetadata = namespaceMD.types[name]; if (!typeMetadata) { typeMetadata = e.tagName.toLowerCase() == "complextype" ? new EdmComplexType(name, {}) : new EdmEntityType(name, {}); namespaceMD.addTypes(typeMetadata); } return typeMetadata; }; let ns = getRequiredAttributeValue(e.parentElement, "Namespace"); let name = getRequiredAttributeValue(e, "Name"); if (!(ns in namespaces)) namespaces[ns] = new Namespace(ns); if (e.tagName.toLowerCase() === "enumtype") { const enumType = new EdmEnumType(name, ApiMetadata.parseEnumMembers(e)); namespaces[ns].addTypes(enumType); } else { let typeMetadata = getOrAddEdmEntityType(ns, name); typeMetadata.openType = getAttributeBoolValue(e, "OpenType"); const baseType = getAttributeValue(e, "BaseType"); if (baseType) { const baseTypeNS = baseType.substring(0, baseType.lastIndexOf(".")); const baseTypeName = baseType.substr(baseTypeNS.length + 1); let bt = getOrAddEdmEntityType(baseTypeNS, baseTypeName); typeMetadata.baseType = bt; } entityTypes.push({ element: e, typeMetadata }); } } for (let e of entityTypes) { Object.assign(e.typeMetadata, ApiMetadata.getEntityTypeProperties(e.element, namespaces)); e.typeMetadata.keys = this.parseEntityKeys(e.element); } return namespaces; } static parseEntityKeys(typeElement) { var res = new Array(); var list = typeElement.querySelectorAll("Key>PropertyRef"); for (var i = 0; i < list.length; i++) { res.push(getRequiredAttributeValue(list.item(i), "Name")); } return res; } static parseEnumMembers(element) { const res = {}; var list = element.querySelectorAll("Member"); for (var i = 0; i < list.length; i++) { const e = list.item(i); const name = getRequiredAttributeValue(e, "Name"); const rawValue = getRequiredAttributeValue(e, "Value"); res[name] = (rawValue.match(/\d/)) ? parseInt(rawValue) : rawValue; } return res; } static getEntityTypeProperties(typeElement, namespaces) { let properties = {}; let navProperties = {}; var list = typeElement.querySelectorAll("Property,NavigationProperty"); for (var i = 0; i < list.length; i++) { const e = list.item(i); const name = getRequiredAttributeValue(e, "Name"); let metadata = ApiMetadata.parseType(e, namespaces); if (e.tagName.toLowerCase() == "property") properties[name] = metadata; else navProperties[name] = EdmEntityTypeReference.fromTypeReference(metadata); } return { properties, navProperties }; } getEntitySetMetadata(typeName) { return ApiMetadata.getEntitySetMetadata(typeName, this.namespaces); } static getEntitySetMetadata(typeName, namespaces) { const res = ApiMetadata.getEdmTypeMetadata(typeName, namespaces); if (res instanceof EdmEntityType) return res; throw new Error("EntitySet item type must be entity"); } getEdmTypeMetadata(typeName) { return ApiMetadata.getEdmTypeMetadata(typeName, this.namespaces); } static getEdmTypeMetadata(typeName, namespaces) { if (utils_1.startsWith(typeName, COLLECTION_TYPE_PREFIX)) typeName = typeName.substring(COLLECTION_TYPE_PREFIX.length, typeName.length - 1); const namespace = typeName.substring(0, typeName.lastIndexOf(".")); const typeNameNoNs = typeName.substr(namespace.length + 1); if (namespace == "Edm") { let t = EdmTypes[typeNameNoNs]; if (!t) throw new Error("Not registred Edm type: " + typeNameNoNs); return t; } const nsMeta = namespaces[namespace]; if (!nsMeta) throw new Error(`Namespace '${namespace}' not found`); let typeElement = nsMeta.types[typeNameNoNs]; return typeElement; } static parseOperationMetadata(operationElement, namespaces) { const isAction = operationElement.tagName.toLowerCase() === "action"; const name = getRequiredAttributeValue(operationElement, "Name"); const returnTypeElement = operationElement.querySelector("ReturnType"); const returnType = returnTypeElement ? ApiMetadata.parseType(returnTypeElement, namespaces) : undefined; const parameters = new Array(); let bindingTo; const list = operationElement.querySelectorAll("Parameter"); for (var i = 0; i < list.length; i++) { const e = list.item(i); const type = ApiMetadata.parseType(e, namespaces); const name = getRequiredAttributeValue(e, "Name"); if (getAttributeBoolValue(operationElement, "IsBound") && !bindingTo) bindingTo = EdmEntityTypeReference.fromTypeReference(type); else parameters.push({ name, type }); } return new OperationMetadata(name, isAction, parameters, returnType, bindingTo); } static parseType(element, namespaces) { let typeName = getRequiredAttributeValue(element, "Type"); let collection = utils_1.startsWith(typeName, COLLECTION_TYPE_PREFIX); if (collection) typeName = typeName.substring(COLLECTION_TYPE_PREFIX.length, typeName.length - 1); const typeMetadata = ApiMetadata.getEdmTypeMetadata(typeName, namespaces); const res = new EdmTypeReference(typeMetadata, true, collection); res.nullable = getAttributeBoolValue(element, "Nullable") != false; return res; } } exports.ApiMetadata = ApiMetadata; function getRequiredAttributeValue(element, attrName) { return getAttributeValue(element, attrName) || (() => { throw new Error(`Metadata: Attribute '${attrName}' in element '${element.tagName}' not found `); })(); } function getAttributeBoolValue(element, attrName) { var r = getAttributeValue(element, attrName); if (r != undefined) return r.toLowerCase() == "true"; } function getAttributeValue(element, attrName) { var attr = element.attributes.getNamedItem(attrName); if (attr) return attr.value; } }); //# sourceMappingURL=metadata.js.map