Skip to content

Commit

Permalink
feat(typescript):alias import for codegen (#124)
Browse files Browse the repository at this point in the history
* feat(i114): updated the property type-resolution

Signed-off-by: Jaskeerat Singh Saluja <[email protected]>

* feat(csharp-alias-import): minor bug fixed

- Earlier non-imported types gave error.

Signed-off-by: Jaskeerat Singh Saluja <[email protected]>

* feat(i114): test cases added and minor bug fixed

Signed-off-by: Jaskeerat Singh Saluja <[email protected]>

* feat(i114): Java visitor updated for aliased import

Signed-off-by: Jaskeerat Singh Saluja <[email protected]>

* feat(alias-import):updating changes

Signed-off-by: Jaskeerat Singh Saluja <[email protected]>

* feat(alias-import): Test cases for java-visitor added

Signed-off-by: Jaskeerat Singh Saluja <[email protected]>

* feat(import-alias): concerto-core version updated and minor changes

Signed-off-by: Jaskeerat Singh Saluja <[email protected]>

* feat(alias-import):Minor bug fixed

Signed-off-by: Jaskeerat Singh Saluja <[email protected]>

* feat(alias-import): Pr suggestions

Signed-off-by: Jaskeerat Singh Saluja <[email protected]>

* feat(alias-import): visit function updated

visitModelFile and visitClassDeclaration updated for the typescriptvisitor.js

Signed-off-by: Jaskeerat Singh Saluja <[email protected]>

* feat(alias-import): fixing code

Signed-off-by: Jaskeerat Singh Saluja <[email protected]>

* feat(alias-import): Typescript Codegen fixed

Signed-off-by: Jaskeerat Singh Saluja <[email protected]>

* feat(alias-import): test-cases

Signed-off-by: Jaskeerat Singh Saluja <[email protected]>

* feat(import-alias):Test case updated

Signed-off-by: Jaskeerat Singh Saluja <[email protected]>

* feat(import-alias): Code refactored

Signed-off-by: Jaskeerat Singh Saluja <[email protected]>

* feat(alias-import):Pr refactoring

Signed-off-by: Jaskeerat Singh Saluja <[email protected]>

* feat(alias-import):Test cases added

Signed-off-by: Jaskeerat Singh Saluja <[email protected]>

---------

Signed-off-by: Jaskeerat Singh Saluja <[email protected]>
Signed-off-by: Jaskeerat Singh Saluja <[email protected]>
Co-authored-by: Jaskeerat Singh Saluja <[email protected]>
  • Loading branch information
salujajaskeerat and Jaskeerat Singh Saluja authored Sep 18, 2024
1 parent e4968a6 commit b1122fe
Show file tree
Hide file tree
Showing 2 changed files with 131 additions and 18 deletions.
49 changes: 34 additions & 15 deletions lib/codegen/fromcto/typescript/typescriptvisitor.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,15 @@ class TypescriptVisitor {
// Compute the types we need to import (based on all the types of the properites
// as well as all the super types) for all the classes in this model file
parameters.fileWriter.writeLine(0, '\n// imports');
const aliasedTypesMap = new Map();
modelFile.imports.forEach((imp) => {
if (imp.$class === '[email protected]' && imp.aliasedTypes) {
imp.aliasedTypes.forEach(type => {
aliasedTypesMap.set(`${imp.namespace}.I${type.name}`, `I${type.aliasedName}`);
});
}
});

const properties = new Map();
modelFile.getAllDeclarations()
.filter(declaration => !declaration.isScalarDeclaration?.())
Expand Down Expand Up @@ -138,17 +147,25 @@ class TypescriptVisitor {

});

modelFile.getImports().map(importString => ModelUtil.getNamespace(importString)).filter(namespace => namespace !== modelFile.getNamespace()) // Skip own namespace.
.filter((v, i, a) => a.indexOf(v) === i) // Remove any duplicates from direct imports
.forEach(namespace => {
const propertyTypeNames = properties.get(namespace);
if (propertyTypeNames) {
const csvPropertyTypeNames = Array.from(propertyTypeNames).join();
parameters.fileWriter.writeLine(0, `import {${csvPropertyTypeNames}} from './${namespace}';`);
}
});
const uniqueNamespaces = new Set(
modelFile.getImports()
.map(importString => ModelUtil.getNamespace(importString))
.filter(namespace => namespace !== modelFile.getNamespace())
);
uniqueNamespaces.forEach(namespace => {
const propertyTypeNames = properties.get(namespace);
if (propertyTypeNames) {
const csvPropertyTypeNames = Array.from(propertyTypeNames).map(type => {
const fqnType = `${namespace}.${type}`;
return aliasedTypesMap.has(fqnType) ? `${type} as ${aliasedTypesMap.get(fqnType)}` : type;
}).join(',');

parameters.fileWriter.writeLine(0, `import {${csvPropertyTypeNames}} from './${namespace}';`);
}
});

parameters.fileWriter.writeLine(0, '\n// interfaces');
parameters.aliasedTypesMap = aliasedTypesMap;
modelFile.getAllDeclarations()
.filter(declaration => !declaration.isScalarDeclaration?.()).forEach((decl) => {
decl.accept(this, parameters);
Expand Down Expand Up @@ -187,13 +204,15 @@ class TypescriptVisitor {
*/
visitClassDeclaration(classDeclaration, parameters) {

let superType = ' ';
if (classDeclaration.getSuperType()) {
superType = ` extends I${ModelUtil.getShortName(classDeclaration.getSuperType())} `;
let superType = '';
const type = classDeclaration.getSuperType();
if (type) {
const namespace = ModelUtil.getNamespace(type);
const shortName = `I${ModelUtil.getShortName(type)}`;
const fullType = `${namespace}.${shortName}`;
superType = ` extends ${parameters.aliasedTypesMap.get(fullType) || shortName}`;
}

parameters.fileWriter.writeLine(0, 'export interface I' + classDeclaration.getName() + superType + '{');

parameters.fileWriter.writeLine(0, `export interface I${classDeclaration.getName()}${superType} {`);
if(!classDeclaration.getSuperType()) {
parameters.fileWriter.writeLine(1, '$class: string;');
}
Expand Down
100 changes: 97 additions & 3 deletions test/codegen/fromcto/typescript/typescriptvisitor.js
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ describe('TypescriptVisitor', function () {
'super.Property3',
'super.Parent'
]);
mockModelFile.imports= [];

typescriptVisitor.visitModelFile(mockModelFile, param);

Expand Down Expand Up @@ -302,7 +303,7 @@ describe('TypescriptVisitor', function () {
'org.org2.Import1'
]);
mockModelFile.getModelManager.returns(mockModelManager);

mockModelFile.imports= [];
typescriptVisitor.visitModelFile(mockModelFile, param);

param.fileWriter.openFile.withArgs('org.acme.ts').calledOnce.should.be.ok;
Expand Down Expand Up @@ -358,7 +359,7 @@ describe('TypescriptVisitor', function () {
]);
mockModelFile.getImports.returns([]);
mockModelFile.getModelManager.returns(mockModelManager);

mockModelFile.imports = [];
typescriptVisitor.visitModelFile(mockModelFile, param);

param.fileWriter.openFile.withArgs('org.acme.ts').calledOnce.should.be.ok;
Expand All @@ -373,6 +374,71 @@ describe('TypescriptVisitor', function () {

acceptSpy.withArgs(typescriptVisitor, param).calledOnce.should.be.ok;
});

it('should write lines for the aliased imports from other namespace ', () => {

let property1 = {
isPrimitive: () => {
return false;
},
getFullyQualifiedTypeName: () => {
return 'org.test.basic.file';
}
};

let property2 = {
isPrimitive: () => {
return false;
},
getFullyQualifiedTypeName: () => {
return 'org.test.complex.file';
}
};

let mockClassDeclaration = sinon.createStubInstance(ClassDeclaration);

mockClassDeclaration.isClassDeclaration.returns(true);
mockClassDeclaration.getProperties.returns([property1, property2]);
mockClassDeclaration.getNamespace.returns('org.test.collection');
mockClassDeclaration.getName.returns('folder');

mockClassDeclaration.getDirectSubclasses.returns([]);

let mockModelFile = sinon.createStubInstance(ModelFile);
mockModelFile.getNamespace.returns('org.test.collection');
mockModelFile.imports = [
{
'$class': '[email protected]',
types: ['document', 'file'],
namespace: 'org.test.basic',
aliasedTypes: [
{
name: 'file',
aliasedName: 'f'
}
]
},
{
'$class': '[email protected]',
types: ['file'],
namespace: 'org.test.complex',
}
];

mockModelFile.getAllDeclarations.returns([mockClassDeclaration]);
mockModelFile.getImports.returns(['org.test.basic.file', 'org.test.basic.document', 'org.test.complex.file']);
typescriptVisitor.visitModelFile(mockModelFile,param);

param.fileWriter.writeLine.callCount.should.deep.equal(6);
param.fileWriter.writeLine.getCall(0).args.should.deep.equal([0, '/* eslint-disable @typescript-eslint/no-empty-interface */']);
param.fileWriter.writeLine.getCall(1).args.should.deep.equal([0, '// Generated code for namespace: org.test.collection']);
param.fileWriter.writeLine.getCall(2).args.should.deep.equal([0, '\n// imports']);
param.fileWriter.writeLine.getCall(3).args.should.deep.equal([0, 'import {Ifile as If} from \'./org.test.basic\';']);
param.fileWriter.writeLine.getCall(4).args.should.deep.equal([0, 'import {Ifile} from \'./org.test.complex\';']);
param.fileWriter.writeLine.getCall(5).args.should.deep.equal([0, '\n// interfaces']);
param.fileWriter.closeFile.calledOnce.should.be.ok;

});
});

describe('visitEnumDeclaration', () => {
Expand Down Expand Up @@ -444,7 +510,7 @@ describe('TypescriptVisitor', function () {
mockClassDeclaration.getName.returns('Bob');
mockClassDeclaration.isAbstract.returns(true);
mockClassDeclaration.getSuperType.returns('org.acme.Person');

param.aliasedTypesMap=new Map();
typescriptVisitor.visitClassDeclaration(mockClassDeclaration, param);

param.fileWriter.writeLine.callCount.should.deep.equal(2);
Expand Down Expand Up @@ -512,6 +578,34 @@ describe('TypescriptVisitor', function () {
param.fileWriter.writeLine.getCall(1).args.should.deep.equal([1, '$class: string;']);
param.fileWriter.writeLine.getCall(2).args.should.deep.equal([0, '}\n']);
});

it('should write lines for the extending class declaration using aliased types ', () => {

let property = {
isPrimitive: () => {
return false;
},
getFullyQualifiedTypeName: () => {
return 'org.test.basic.file';
}
};

let mockClassDeclaration = sinon.createStubInstance(ClassDeclaration);

mockClassDeclaration.isClassDeclaration.returns(true);
mockClassDeclaration.getProperties.returns([property]);
mockClassDeclaration.getNamespace.returns('org.test.collection');
mockClassDeclaration.getName.returns('bigFile');
mockClassDeclaration.getSuperType.returns('org.basic.file');
mockClassDeclaration.isScalarDeclaration.returns(false);
mockClassDeclaration.getDirectSubclasses.returns([]);
mockClassDeclaration.getOwnProperties.returns([]);
param.aliasedTypesMap = new Map([['org.basic.Ifile', 'If']]);
typescriptVisitor.visitClassDeclaration(mockClassDeclaration,param);

param.fileWriter.writeLine.callCount.should.deep.equal(2);
param.fileWriter.writeLine.getCall(0).args.should.deep.equal([0, 'export interface IbigFile extends If {']);
});
});

describe('visitField', () => {
Expand Down

0 comments on commit b1122fe

Please sign in to comment.