@odata2ts/odata2ts
Version:
Flexible generator to produce various TypeScript artefacts (from simple model interfaces to complete odata clients) from OData metadata files
213 lines • 9.59 kB
JavaScript
import path from "path";
import { ODataVersions } from "@odata2ts/odata-core";
import { ClientApiImports, CoreImports, LIB_MODULES, ServiceImports, VERSIONED_CORE_IMPORTS, VERSIONED_SERVICE_IMPORTS, } from "./import/ImportObjects.js";
import { ImportedNameValidator } from "./ImportedNameValidator.js";
/**
* Handles all the import statements for a given file.
*
* Features a renaming mechanism, so that when the import name conflicts with an existing import a new
* name is generated and returned.
*
* Map<string,string>
*/
export class ImportContainer {
constructor(path, fileName, dataModel, mainFileNames, bundledFileGeneration, reservedNames) {
this.path = path;
this.fileName = fileName;
this.dataModel = dataModel;
this.mainFileNames = mainFileNames;
this.bundledFileGeneration = bundledFileGeneration;
this.reservedNames = reservedNames;
// mapping of a custom defined type to a primitive type
this.customTypes = {
regular: new Map(),
typeOnly: new Map(),
};
// imports to generated artefacts
this.internalImports = {
regular: new Map(),
typeOnly: new Map(),
};
this.libs = {
core: { regular: new Map(), typeOnly: new Map() },
qObject: { regular: new Map(), typeOnly: new Map() },
clientApi: { regular: new Map(), typeOnly: new Map() },
service: { regular: new Map(), typeOnly: new Map() },
};
this.importedNameValidator = new ImportedNameValidator(reservedNames);
}
addCoreLib(odataVersion, coreLib) {
const isVersioned = VERSIONED_CORE_IMPORTS.includes(coreLib);
const name = CoreImports[coreLib] + (isVersioned ? ODataVersions[odataVersion] : "");
const importName = this.importedNameValidator.validateName(LIB_MODULES.core, name);
// TODO: currently only types are imported, however enums could potentially be imported too
this.libs.core.typeOnly.set(name, importName);
return importName;
}
addFromQObject(name, typeOnlyImport = false) {
const importName = this.importedNameValidator.validateName(LIB_MODULES.qObject, name);
const imports = this.libs.qObject;
if (typeOnlyImport) {
if (!imports.regular.has(name)) {
imports.typeOnly.set(name, importName);
}
}
else {
if (imports.typeOnly.has(name)) {
imports.typeOnly.delete(name);
}
imports.regular.set(name, importName);
}
return importName;
}
addQObject(qObject) {
return this.addFromQObject(qObject);
}
addQObjectType(qObject) {
return this.addFromQObject(qObject, true);
}
addClientApi(clientApi) {
const name = ClientApiImports[clientApi];
const importName = this.importedNameValidator.validateName(LIB_MODULES.clientApi, name);
// complete client api consists only of types
this.libs.clientApi.typeOnly.set(name, importName);
return importName;
}
addServiceObject(odataVersion, serviceObject) {
const isVersioned = VERSIONED_SERVICE_IMPORTS.includes(serviceObject);
const name = ServiceImports[serviceObject] + (isVersioned ? ODataVersions[odataVersion] : "");
const importName = this.importedNameValidator.validateName(LIB_MODULES.service, name);
// only regular imports for the service package
this.libs.service.regular.set(name, importName);
return importName;
}
// TODO: make sure that regular imports win over additional typeOnly imports
addCustomType(moduleName, typeName, isTypeOnly = false) {
const importName = this.importedNameValidator.validateName(moduleName, typeName);
const imports = isTypeOnly ? this.customTypes.typeOnly : this.customTypes.regular;
let importList = imports.get(moduleName);
if (!importList) {
importList = new Map();
imports.set(moduleName, importList);
}
importList.set(typeName, importName);
return importName;
}
pathAndFile(filePath, fileName) {
return filePath ? `${filePath}/${fileName}` : fileName;
}
isDifferentFile(filePath, fileName) {
return this.pathAndFile(this.path, this.fileName) !== this.pathAndFile(filePath, fileName);
}
addGeneratedImport(folderPath, fileName, name, isTypeOnly = false) {
var _a, _b, _c;
// imports are only relevant for different files
if (!this.isDifferentFile(folderPath, fileName)) {
return name;
}
const moduleName = this.pathAndFile(folderPath, fileName);
const importName = this.importedNameValidator.validateName(moduleName, name);
const imports = isTypeOnly ? this.internalImports.typeOnly : this.internalImports.regular;
if (isTypeOnly && ((_a = this.internalImports.regular.get(moduleName)) === null || _a === void 0 ? void 0 : _a.has(name))) {
return importName;
}
if (!isTypeOnly && ((_b = this.internalImports.typeOnly.get(moduleName)) === null || _b === void 0 ? void 0 : _b.has(name))) {
(_c = this.internalImports.typeOnly.get(moduleName)) === null || _c === void 0 ? void 0 : _c.delete(name);
}
const importList = imports.get(moduleName) || new Map();
importList.set(name, importName);
imports.set(moduleName, importList);
return importName;
}
addGeneratedModel(fqName, name, isTypeOnly = true) {
if (this.bundledFileGeneration) {
return this.addGeneratedImport("", this.mainFileNames.model, name, isTypeOnly);
}
else {
const model = this.dataModel.getModel(fqName);
if (!model && fqName !== "") {
throw new Error(`Cannot find model by its fully qualified name: ${fqName}!`);
}
const folderPath = model ? model.folderPath : "";
const modelName = model ? model.modelName : this.mainFileNames.model;
return this.addGeneratedImport(folderPath, modelName, name, isTypeOnly);
}
}
addGeneratedQObject(fqName, name, isTypeOnly = false) {
if (this.bundledFileGeneration) {
return this.addGeneratedImport("", this.mainFileNames.qObject, name, isTypeOnly);
}
else {
const model = this.dataModel.getModel(fqName);
if (!model && fqName !== "") {
throw new Error(`Cannot find q-object by its fully qualified name: ${fqName}!`);
}
const folderPath = model ? model.folderPath : "";
const qName = model ? model.qName : this.mainFileNames.qObject;
return this.addGeneratedImport(folderPath, qName, name, isTypeOnly);
}
}
addGeneratedService(fqName, name) {
if (this.bundledFileGeneration) {
return this.addGeneratedImport("", this.mainFileNames.service, name);
}
else {
const model = this.dataModel.getModel(fqName);
return this.addGeneratedImport(model.folderPath, model.serviceName, name);
}
}
createImportDecl(module, toImport, isTypeOnly = false) {
return {
namedImports: this.getNamedImports(toImport),
moduleSpecifier: module,
isTypeOnly,
};
}
getImportDeclarations() {
return [
...Object.entries(this.libs).reduce((result, [moduleName, toImport]) => {
const module = LIB_MODULES[moduleName];
if (toImport.typeOnly.size) {
result.push(this.createImportDecl(module, toImport.typeOnly, true));
}
if (toImport.regular.size) {
result.push(this.createImportDecl(module, toImport.regular));
}
return result;
}, []),
...[...this.customTypes.typeOnly]
.filter(([moduleName, toImport]) => toImport.size > 0)
.map(([moduleName, toImport]) => {
return this.createImportDecl(moduleName, toImport, true);
}),
...[...this.customTypes.regular]
.filter(([moduleName, toImport]) => toImport.size > 0)
.map(([moduleName, toImport]) => {
return this.createImportDecl(moduleName, toImport);
}),
...[...this.internalImports.typeOnly]
.filter(([_, toImport]) => toImport.size > 0)
.map(([key, toImport]) => {
const module = this.getModuleSpecifier(key);
return this.createImportDecl(module, toImport, true);
}),
...[...this.internalImports.regular]
.filter(([_, toImport]) => toImport.size > 0)
.map(([key, toImport]) => {
const module = this.getModuleSpecifier(key);
return this.createImportDecl(module, toImport);
}),
];
}
getNamedImports(toImport) {
return [...toImport.entries()].map(([name, alias]) => ({
name,
alias: alias !== name ? alias : undefined,
}));
}
getModuleSpecifier(filePath) {
const relativePath = path.relative(this.path, filePath).replaceAll(path.sep, "/");
return !relativePath.startsWith(".") ? "./" + relativePath : relativePath;
}
}
//# sourceMappingURL=ImportContainer.js.map