UNPKG

@tripsnek/tmf

Version:

TypeScript Modeling Framework - A TypeScript port of the Eclipse Modeling Framework (EMF)

544 lines (532 loc) 21.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.TGeneratorGen = void 0; const tgen_utils_1 = require("./tgen-utils"); const tutils_1 = require("../tutils"); const ereference_impl_1 = require("../metamodel/ereference-impl"); const eclass_impl_1 = require("../metamodel/eclass-impl"); /** * Source code generation for *gen.ts files for EClasses. * * @author dtuohy */ class TGeneratorGen { _pkg; _packageName; /** * Generates a template string containing all source code for the *gen.ts * file for the given EClass. * * @param eClass * @param toImport * @param genToImport * @param pkgToImport */ generate(eClass, toImport, genToImport, pkgToImport) { this._pkg = eClass.getEPackage(); this._packageName = tgen_utils_1.TGenUtils.genPackageClassName(this._pkg); const genClassName = tgen_utils_1.TGenUtils.genGenClassName(eClass); const apiClassName = eClass.getName(); return `${this.generateAllImportStatements(eClass, toImport, genToImport, pkgToImport)} /** * This file is source-code generated and should never be edited. It implements * the core TMF functionality for ${eClass.getName()}. */ export abstract class ${genClassName} ${this.generateExtends(eClass)} implements ${apiClassName} { /** feature declarations */ ${this.genFeatureDeclarations(eClass)} ${this.genConstructor(eClass)} ${this.genGettersAndSetters(eClass)} ${this.genEoperations(eClass)} //====================================================================== // Standard EObject behavior ${this.genEGet(eClass)} ${this.genESet(eClass)} ${this.genEIsSet(eClass)} ${this.genEUnset(eClass)} ${this.genBasicSetters(eClass)} ${this.genEInverseAdd(eClass)} ${this.genEInverseRemove(eClass)} //====================================================================== // eClass() public override eClass(): EClass { return ${this._packageName}.Literals.${tgen_utils_1.TGenUtils.snakeUpperCase(eClass.getName())}; } }`; } /** * Generates import statements for all APIs, Gen classes * and packages to import. * * @param eClass * @param toImport * @param genToImport * @param pkgToImport */ generateAllImportStatements(eClass, toImport, genToImport, pkgToImport, async) { let className = eClass.getName(); if (async) className += 'Async'; const isEcore = eClass.getEPackage().getName() == 'ecore'; let result = `${isEcore ? tgen_utils_1.TGenUtils.ECORE_DEFAULT_IMPORTS : tgen_utils_1.TGenUtils.DEFAULT_IMPORTS} ${tgen_utils_1.TGenUtils.genApiImports(eClass, toImport, `..${tgen_utils_1.TGenUtils.API_PATH}`)} import { ${this._packageName} } from '../${tgen_utils_1.TGenUtils.genPackageFileName(this._pkg)}'; import { ${className} } from '..${tgen_utils_1.TGenUtils.API_PATH}/${tgen_utils_1.TGenUtils.genClassApiName(eClass, async)}'; `; //gen and impl classes that need to be imported for (const ec of genToImport) { if (ec) { let pathToImport = './'; //only import Gen and Impl if it is an EClass (not an EEnum) if (ec instanceof eclass_impl_1.EClassImpl) { if (ec.getEPackage() !== eClass.getEPackage()) { //if root package is shared, the classes are assumed to exist in the same lib, and can be imported with relative paths if (ec.getRootPackage() === eClass.getRootPackage()) { pathToImport = `${tgen_utils_1.TGenUtils.getPathToTypeInOtherPkg(eClass, ec)}/`; result += `import { ${ec.getName()}Gen } from '${pathToImport + 'gen/' + tgen_utils_1.TGenUtils.genClassGenName(ec)}';\n`; result += `import { ${ec.getName()}Impl } from '${pathToImport + 'impl/' + tgen_utils_1.TGenUtils.genClassImplName(ec)}';\n`; } //otherwise, use non-relative paths else { console.log('WARNING: CROSS-PACKAGE IMPORTS NOT SUPPORTED'); } } else { result += `import { ${ec.getName()}Gen } from './${tgen_utils_1.TGenUtils.genClassGenName(ec)}';\n`; result += `import { ${ec.getName()}Impl } from '../impl/${tgen_utils_1.TGenUtils.genClassImplName(ec)}';\n`; } } } } //add package imports (e.g. for references to types in external packages) result += tgen_utils_1.TGenUtils.generateImportStatementsForExternalPackages(pkgToImport, this._pkg, '../'); return result; } generateExtends(eclass) { if (eclass.getName() == 'EObject') return ''; let result = `extends EObjectImpl`; let sti = 0; for (const superType of eclass.getESuperTypes()) { //TODO: Add support for multiple-inheritance on implementation class? if (sti === 0) { if (!superType.isInterface()) { result = ` extends ${superType.getName()}Impl`; } } sti++; } return result; } genFeatureDeclarations(eclass) { let sourceContent = ``; for (const f of eclass.getEStructuralFeatures()) { const typeName = tgen_utils_1.TGenUtils.getTypeName(f); let initializer = ''; if (f.isMany()) { //get feature ID for inverse reference, if specified let inverseFeatureId = 'undefined'; if (f instanceof ereference_impl_1.EReferenceImpl) { if (f.getEOpposite()) { const oppRef = f.getEOpposite(); if (oppRef) { inverseFeatureId = `${tgen_utils_1.TGenUtils.genPackageClassName(oppRef.getEContainingClass().getEPackage())}.${tgen_utils_1.TGenUtils.genFeatureIdFieldName(oppRef)}`; } } } //list is initialized with information about owning object, the //field it represents, and any inverse field initializer += ` = new Basic${typeName}( undefined, this, ${this._packageName}.${tgen_utils_1.TGenUtils.genFeatureIdFieldName(f)}, ${inverseFeatureId} )`; } //TODO: only add '!' is feature is marked as required (lowerBound = 1) let optionalityOperator = f.isMany() ? '' : '!'; sourceContent += ` protected ${f.getName()}${optionalityOperator}: ${typeName}${initializer};\n`; } return sourceContent; } genConstructor(eClass) { // Build sorted list of all constructor arguments let argFields = []; // Build sorted list constructor arguments from possible superType const superFields = []; let result = ''; if (argFields.length > 0) { // Now build up the constructor code... result += ` //====================================================================== // Constructor public constructor(`; for (const field of argFields) { if (field.isMany()) { const type = tutils_1.TUtils.getTypescriptName(field.getEType()); result += `_${field.getName()}?: EList<${type}>, `; } else { const type = tutils_1.TUtils.getTypescriptName(field.getEType()); result += `_${field.getName()}?: ${type}, `; } } result += ') {'; // Deal with invoking 'super(....)' if necessary if (superFields) { result += 'super('; for (const field of superFields) { result += `_${field.getName()}, `; } result += ');'; argFields = argFields.filter((f) => !superFields.includes(f)); } else { result += 'super();'; } // Deal with setting the remaining (locally defined) fields for (const field of argFields) { if (field.isMany()) { const eListVar = field.getName() + 'EList'; result += `if (_${field.getName()}) { const ${eListVar} = this.${tgen_utils_1.TGenUtils.getterName(field)}(); for(const val of _${field.getName()}) { ${eListVar}.add(val); } }`; } else { result += `this.${tgen_utils_1.TGenUtils.setterName(field)}(_${field.getName()});`; } } result += '}'; } return result; } genGettersAndSetters(eClass) { let result = ` //====================================================================== // Getters and Setters `; for (const field of eClass.getEStructuralFeatures()) { result += this.genGetter(eClass, field); result += this.genSetter(eClass, field); } return result; } genGetter(eClass, field) { const visibility = 'public'; let result = ` ${visibility} ${tgen_utils_1.TGenUtils.getterSig(field)} {`; if (field.isVolatile()) { result += ` throw new Error( 'Unsupported operation on volatile field. Override in ${eClass.getName()}Impl.' );`; } else { result += ` return this.${field.getName()};`; } result += ` }`; // End of Getter definition return result; } genSetter(eClass, field) { let result = ``; if (!field.isMany()) { const paramName = tgen_utils_1.TGenUtils.setterParamName(field); const visibility = field.isChangeable() ? 'public' : 'private'; result += ` ${visibility} ${tgen_utils_1.TGenUtils.setterSig(field)} {`; if (field.isVolatile()) { result += ` throw new Error( 'Unsupported operation on volatile field. Override in ${eClass.getName()}Impl.' );`; } else { //handle containment enforcement if appropriate if (field instanceof ereference_impl_1.EReferenceImpl && field.isContainment()) { const oldVar = 'old' + tgen_utils_1.TGenUtils.capitalize(field.getName()); result += ` const ${oldVar} = this.${field.getName()}; if (${oldVar}) ${oldVar}.setEContainer(undefined, undefined); if (${paramName}) ${paramName}.setEContainer(this, ${tgen_utils_1.TGenUtils.genPackageClassName(this._pkg)}.${tgen_utils_1.TGenUtils.genFeatureIdFieldName(field)});`; } //handle inverse references if appropriate if (field instanceof ereference_impl_1.EReferenceImpl && field.getEOpposite()) { //TODO: handle opposites in other packages? const oppositeIdField = `${this._packageName}.${tgen_utils_1.TGenUtils.genFeatureIdFieldName(field.getEOpposite())}`; result += ` if (this.${field.getName()} !== ${paramName}) { if (this.${field.getName()}) { this.${field.getName()}.eInverseRemove(this, ${oppositeIdField}); } if (${paramName}) { ${paramName}.eInverseAdd(this, ${oppositeIdField}); } }`; } result += ` this.basic${tgen_utils_1.TGenUtils.capitalize(tgen_utils_1.TGenUtils.setterName(field))}(${paramName});`; // sourceContent += `this.${f.getName()} = ${paramName};}`; } result += ` }`; // End of Setter definition } return result; } genBasicSetters(eClass) { let result = ` //====================================================================== // Basic setters (allow EOpposite enforcement without triggering infinite cycles) `; for (const field of eClass.getEStructuralFeatures()) { //only include basic setters for internal references if (!field.isMany() && !field.isVolatile()) { const visibility = field.isChangeable() ? 'public' : 'private'; const paramName = tgen_utils_1.TGenUtils.setterParamName(field); result += ` ${visibility} basic${tgen_utils_1.TGenUtils.capitalize(tgen_utils_1.TGenUtils.setterSig(field))} {`; if (field instanceof ereference_impl_1.EReferenceImpl && field.getEOpposite() && field.getEOpposite().isContainment()) { result += ` this.eBasicSetContainer(${paramName}, ${tgen_utils_1.TGenUtils.genPackageClassName(eClass.getEPackage())}.${tgen_utils_1.TGenUtils.genFeatureIdFieldName(field.getEOpposite())});`; } result += ` this.${field.getName()} = ${paramName}; }`; } } return result; } genEoperations(eClass) { let result = ` //====================================================================== // API Operations `; for (const eop of eClass.getEOperations()) { result += ` public ${tgen_utils_1.TGenUtils.eopSignature(eop)} { throw new Error('Not implemented'); }`; } //if this class directly inherits from an interface, need to add implementations of those as well for (const st of eClass.getESuperTypes()) { if (st.isInterface()) { for (const eop of st.getEOperations()) { result += ` public ${tgen_utils_1.TGenUtils.eopSignature(eop)} { throw new Error('Not implemented'); }`; } } } return result; } genEGet(eClass) { let result = ` /** * eGet() - provides reflective access to all features. */ public override eGet(feature: number | EStructuralFeature): any { const featureID: number = typeof feature === 'number' ? feature : (<EStructuralFeature>feature).getFeatureID(); switch (featureID) {`; for (const feature of eClass.getEStructuralFeatures()) { const featureIdField = tgen_utils_1.TGenUtils.genFeatureIdFieldName(feature); result += ` case ${this._packageName}.${featureIdField}: return this.${tgen_utils_1.TGenUtils.getterName(feature)}();`; } result += ` } return super.eGet(featureID); }`; return result; } genESet(eClass) { let result = ` /** * eSet() - provides ability to reflectively set all features. */ public override eSet(feature: number | EStructuralFeature, newValue: any): void { const featureID: number = typeof feature === 'number' ? feature : (<EStructuralFeature>feature).getFeatureID(); switch (featureID) {`; for (const feature of eClass.getEStructuralFeatures()) { const featureIdField = tgen_utils_1.TGenUtils.genFeatureIdFieldName(feature); result += ` case ${this._packageName}.${featureIdField}:`; if (!feature.isMany()) { result += ` this.${tgen_utils_1.TGenUtils.setterName(feature)}(newValue); return;`; } else { const getter = tgen_utils_1.TGenUtils.getterName(feature); result += ` this.${getter}().clear(); this.${getter}().addAll(newValue); return;`; } } result += ` } return super.eSet(featureID, newValue); }`; return result; } genEIsSet(eClass) { let result = ` /** * eIsSet() - provides ability to reflectively check if any feature is set. */ public override eIsSet(feature: number | EStructuralFeature): boolean { const featureID: number = typeof feature === 'number' ? feature : (<EStructuralFeature>feature).getFeatureID(); switch (featureID) {`; for (const feature of eClass.getEStructuralFeatures()) { const featureIdField = tgen_utils_1.TGenUtils.genFeatureIdFieldName(feature); result += ` case ${this._packageName}.${featureIdField}:`; if (!feature.isMany()) { result += ` return this.${tgen_utils_1.TGenUtils.getterName(feature)}() != null;`; } else { const getter = tgen_utils_1.TGenUtils.getterName(feature); result += ` return !this.${getter}().isEmpty();`; } } result += ` } return super.eIsSet(featureID); }`; return result; } genEUnset(eClass) { let result = ` /** * eUnset() - provides ability to reflectively unset any feature. */ public override eUnset(feature: number | EStructuralFeature): void { const featureID: number = typeof feature === 'number' ? feature : (<EStructuralFeature>feature).getFeatureID(); switch (featureID) {`; for (const feature of eClass.getEStructuralFeatures()) { const featureIdField = tgen_utils_1.TGenUtils.genFeatureIdFieldName(feature); result += ` case ${this._packageName}.${featureIdField}:`; if (!feature.isMany()) { result += ` this.${tgen_utils_1.TGenUtils.setterName(feature)}(undefined!); return;`; } else { const getter = tgen_utils_1.TGenUtils.getterName(feature); result += ` this.${getter}().clear(); return;`; } } result += ` } return super.eUnset(featureID); }`; return result; } genEInverseAdd(eClass) { let result = ` //====================================================================== // Inverse Adders (if needed)`; let numSwitches = 0; for (const f of eClass.getEStructuralFeatures()) { if (f instanceof ereference_impl_1.EReferenceImpl) { if (!f.isVolatile() && f.getEOpposite()) { if (numSwitches === 0) { result += ` public override eInverseAdd(otherEnd: EObject, featureID: number): void { switch (featureID) {`; } //TODO: Do I also need to do a basic remove from container if this sets a new container? result += ` case ${this._packageName}.${tgen_utils_1.TGenUtils.genFeatureIdFieldName(f)}:`; if (f.isMany()) { result += ` return (<EList<EObject>>this.${tgen_utils_1.TGenUtils.getterName(f)}()).basicAdd(otherEnd);`; } else { if (f.getEOpposite()) { const oppositeFeatureField = `${this._packageName}.${tgen_utils_1.TGenUtils.genFeatureIdFieldName(f.getEOpposite())}`; result += ` if (this.${f.getName()}) this.${f.getName()}.eInverseRemove( this, ${oppositeFeatureField} );`; } result += ` return this.basic${tgen_utils_1.TGenUtils.capitalize(tgen_utils_1.TGenUtils.setterName(f))}(<${f .getEType() .getName()}>otherEnd);`; } numSwitches++; } } } if (numSwitches > 0) { result += ` } return super.eInverseAdd(otherEnd, featureID); }`; } return result; } genEInverseRemove(eClass) { let result = ` //====================================================================== // Inverse Removers (if needed)`; let numSwitches = 0; for (const f of eClass.getEStructuralFeatures()) { if (f instanceof ereference_impl_1.EReferenceImpl) { if (!f.isVolatile() && f.getEOpposite()) { if (numSwitches === 0) { result += ` public override eInverseRemove(otherEnd: EObject, featureID: number): void { switch (featureID) {`; } result += ` case ${this._packageName}.${tgen_utils_1.TGenUtils.genFeatureIdFieldName(f)}:`; if (f.isMany()) { result += ` return (<EList<EObject>>this.${tgen_utils_1.TGenUtils.getterName(f)}()).basicRemove(otherEnd);`; } else { result += ` return this.basic${tgen_utils_1.TGenUtils.capitalize(tgen_utils_1.TGenUtils.setterName(f))}(undefined!);`; } numSwitches++; } } } if (numSwitches > 0) { result += ` } return super.eInverseRemove(otherEnd, featureID); }`; } return result; } } exports.TGeneratorGen = TGeneratorGen; //# sourceMappingURL=tgenerator-gen.js.map