UNPKG

@odata2ts/odata2ts

Version:

Flexible generator to produce various TypeScript artefacts (from simple model interfaces to complete odata clients) from OData metadata files

158 lines 6.81 kB
import { __rest } from "tslib"; import { TypeModel } from "../TypeModel.js"; import { withNamespace } from "./DataModel.js"; const EXCEPTION_NO_NAME = "No value for required attribute [name] specified!"; const EXCEPTION_WRONG_NAME_TYPE = "Wrong type for attribute [name]! You have to supply either a plain string or a RegExp."; function createMapping() { return { names: {}, regExps: [], }; } export class ServiceConfigHelper { constructor(options) { this.propMapping = new Map(); this.propRegExps = []; this.mapping = { [TypeModel.Any]: createMapping(), [TypeModel.EntityType]: createMapping(), [TypeModel.ComplexType]: createMapping(), [TypeModel.EnumType]: createMapping(), [TypeModel.OperationType]: createMapping(), [TypeModel.OperationImportType]: createMapping(), [TypeModel.EntitySet]: createMapping(), [TypeModel.Singleton]: createMapping(), }; this.findPropConfigByName = (name) => { const stringProp = this.getPropByName(name); const reProp = this.getPropByRegExp(name); return stringProp && reProp ? Object.assign(Object.assign({}, reProp), stringProp) : stringProp || reProp; }; this.evaluateProps(options); this.evaluateEntities(options); } evaluateProps(options) { options.propertiesByName.forEach((prop) => { if (!prop.name) { throw new Error(EXCEPTION_NO_NAME); } switch (typeof prop.name) { case "string": // TODO: check for existing prop.name and throw? this.propMapping.set(prop.name, prop); break; case "object": const { source, ignoreCase } = prop.name; if (!source) { throw new Error(EXCEPTION_WRONG_NAME_TYPE); } this.propRegExps.push([new RegExp(`^${source}$`, ignoreCase ? "i" : ""), prop]); break; default: throw new Error(EXCEPTION_WRONG_NAME_TYPE); } }); } getPropByName(nameToMap) { const stringProp = this.propMapping.get(nameToMap); if (!stringProp) { return undefined; } const { name } = stringProp, attrs = __rest(stringProp, ["name"]); return Object.assign({}, attrs); } getPropByRegExp(nameToMap) { const resultList = this.propRegExps .filter(([regExp]) => regExp.test(nameToMap)) .map((_a) => { var [regExp, _b] = _a, { name, mappedName } = _b, attrs = __rest(_b, ["name", "mappedName"]); return (Object.assign({ mappedName: mappedName ? nameToMap.replace(regExp, mappedName) : undefined }, attrs)); }); return !resultList.length ? undefined : resultList.reduce((result, prop) => { return Object.assign(Object.assign({}, result), prop); }, {}); } evaluateEntities(options) { options.byTypeAndName.forEach((ent) => { if (!ent.name) { throw new Error(EXCEPTION_NO_NAME); } const mapping = this.mapping[ent.type]; switch (typeof ent.name) { case "string": // TODO: check for existing prop.name and throw? mapping.names[ent.name] = ent; break; case "object": const { source, ignoreCase } = ent.name; if (!source) { throw new Error(EXCEPTION_WRONG_NAME_TYPE); } const regExp = new RegExp(`^${source}$`, ignoreCase ? "i" : ""); mapping.regExps.push( // @ts-ignore: too generic [regExp, ent]); break; default: throw new Error(EXCEPTION_WRONG_NAME_TYPE); } }); } // get entity config by name matching: simple name or fully qualified name (alias also supported) getByName(mapping, namespace, nameToMap) { const [ns, alias] = namespace; const hayStack = Object.assign(Object.assign({}, this.mapping.Any.names), mapping); const config = hayStack[withNamespace(ns, nameToMap)] || (alias ? hayStack[withNamespace(alias, nameToMap)] : undefined) || hayStack[nameToMap]; if (!config) { return undefined; } const { name, type } = config, attrs = __rest(config, ["name", "type"]); return Object.assign({}, attrs); } getByRegExp(mapping, [mainNs, alias], nameToMap) { const fqName = `${mainNs}.${nameToMap}`; const hayStack = [...this.mapping.Any.regExps, ...mapping]; const resultList = hayStack .filter(([regExp, config]) => regExp.test(fqName)) .map((_a) => { var [regExp, _b] = _a, { name, mappedName, type } = _b, attrs = __rest(_b, ["name", "mappedName", "type"]); return (Object.assign({ mappedName: mappedName ? fqName.replace(regExp, mappedName) : undefined }, attrs)); }); return !resultList.length ? undefined : resultList.reduce((result, prop) => { return Object.assign(Object.assign({}, result), prop); }, {}); } findConfig(mapping, namespace, name) { const stringEnt = this.getByName(mapping.names, namespace, name); const reEnt = this.getByRegExp(mapping.regExps, namespace, name); return stringEnt && reEnt ? Object.assign(Object.assign({}, reEnt), stringEnt) : stringEnt || reEnt; } findEntityTypeConfig(namespace, name) { return this.findConfig(this.mapping.EntityType, namespace, name); } findComplexTypeConfig(namespace, name) { return this.findConfig(this.mapping.ComplexType, namespace, name); } findEnumTypeConfig(namespace, name) { return this.findConfig(this.mapping.EnumType, namespace, name); } findOperationTypeConfig(namespace, name) { return this.findConfig(this.mapping.OperationType, namespace, name); } findOperationImportConfig(namespace, name) { return this.findConfig(this.mapping.OperationImportType, [namespace], name); } findEntitySetConfig(namespace, name) { return this.findConfig(this.mapping.EntitySet, [namespace], name); } findSingletonConfig(namespace, name) { return this.findConfig(this.mapping.Singleton, [namespace], name); } } //# sourceMappingURL=ServiceConfigHelper.js.map