Skip to content

Commit

Permalink
1756 - Fix TypeScript Namespace Import Generation (hyperledger-archiv…
Browse files Browse the repository at this point in the history
…es#1757)

* Fix copy and paste error in TypeScript generator.

* TypeScript Code Gen - Import property types that are imported from other cto files.

* TypeScript Code Gen - Code cleanup.

* TypeScript Code Gen - Fix eslint errors.

* TypeScript Code Gen - Remove spaces around imports since they break the automated tests.

* TypeScript Code Gen - Add missing semicolon from import statement.

* TypeScript Code Gen - Add unit test to test TypeScript  import generation across CTO files.

* TypeScript Code Gen - Add test for the output of the import statement that should be generated.

* TypeScript Code Gen - Remove previous tests based on pull request request.
  • Loading branch information
ScottMorris authored and Simon Stone committed Aug 30, 2017
1 parent e3d6964 commit 399df62
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const FunctionDeclaration = require('../../../introspect/functiondeclaration');
const util = require('util');

/**
* Convert the contents of a ModelManager to Go Lang code.
* Convert the contents of a ModelManager to TypeScript code.
* All generated code is placed into the 'main' package. Set a
* fileWriter property (instance of FileWriter) on the parameters
* object to control where the generated code is written to disk.
Expand Down Expand Up @@ -108,12 +108,42 @@ class TypescriptVisitor {
// so that they can be extended
if( !modelFile.isSystemModelFile() ) {
const systemTypes = modelFile.getModelManager().getSystemTypes();
systemTypes.forEach(systemType =>
parameters.fileWriter.writeLine(0, `import {${systemType.getName()}} from './org.hyperledger.composer.system';`));
}

for(let n=0; n < systemTypes.length; n++) {
const systemType = systemTypes[n];
parameters.fileWriter.writeLine(0, 'import {' + systemType.getName() + '} from \'./org.hyperledger.composer.system\';');
// Import property types that are imported from other cto files.
const dot = '.';
const properties = new Map();
modelFile.getAllDeclarations()
.filter(v => !v.isEnum())
.forEach(classDeclaration => classDeclaration.getProperties().forEach(property => {
if(!property.isPrimitive()){
const fullyQualifiedTypeName = property.getFullyQualifiedTypeName();
const lastIndexOfDot = fullyQualifiedTypeName.lastIndexOf(dot);
const propertyNamespace = fullyQualifiedTypeName.substring(0, lastIndexOfDot);
const propertyTypeName = fullyQualifiedTypeName.substring(lastIndexOfDot + 1);
if(!properties.has(propertyNamespace)) {
properties.set(propertyNamespace, new Set());
}
properties.get(propertyNamespace).add(propertyTypeName);
}
}
}));

modelFile.getImports().map(importString => {
const lastIndexOfDot = importString.lastIndexOf(dot);
const namespace = importString.substring(0, lastIndexOfDot);
return namespace;
}).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}';`);
}
});

parameters.fileWriter.writeLine(0, '// export namespace ' + modelFile.getNamespace() + '{');

modelFile.getAllDeclarations().forEach((decl) => {
Expand Down
40 changes: 25 additions & 15 deletions packages/composer-common/test/codegen/typescriptvisitor.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,22 @@ const fs = require('fs');
const path = require('path');
const sinon = require('sinon');

const initSampleNetworkModel = (mockFileWriter) => {
const carleaseModel = fs.readFileSync(path.resolve(__dirname, '../data/model/carlease.cto'), 'utf8');
const concertoModel = fs.readFileSync(path.resolve(__dirname, '../data/model/concerto.cto'), 'utf8');

// create and populate the ModelManager with a model file
let modelManager = new ModelManager();
modelManager.should.not.be.null;
modelManager.clearModelFiles();
modelManager.addModelFiles([carleaseModel,concertoModel], ['carlease.cto', 'concerto.cto']);

let visitor = new TypescriptVisitor();
let parameters = {};
parameters.fileWriter = mockFileWriter;
modelManager.accept(visitor, parameters);
};

describe('TypescriptVisitor', function(){

let mockFileWriter;
Expand All @@ -33,24 +49,18 @@ describe('TypescriptVisitor', function(){

describe('#visit', function() {
it('should generate Typescript code', function() {
initSampleNetworkModel(mockFileWriter);

const carleaseModel = fs.readFileSync(path.resolve(__dirname, '../data/model/carlease.cto'), 'utf8');
const concertoModel = fs.readFileSync(path.resolve(__dirname, '../data/model/concerto.cto'), 'utf8');

// create and populate the ModelManager with a model file
let modelManager = new ModelManager();
modelManager.should.not.be.null;
modelManager.clearModelFiles();
modelManager.addModelFiles([carleaseModel,concertoModel], ['carlease.cto', 'concerto.cto']);

let visitor = new TypescriptVisitor();
let parameters = {};
parameters.fileWriter = mockFileWriter;
modelManager.accept(visitor, parameters);

// check 3 files where generated
// check 2 files where generated
sinon.assert.calledWith(mockFileWriter.openFile, 'concerto.ts');
sinon.assert.calledWith(mockFileWriter.openFile, 'org.acme.ts');
});

it('should generate an import statement referencing the imported namespace from a separate file', function() {
initSampleNetworkModel(mockFileWriter);

// check import was generated linking to the other file/namespace
sinon.assert.calledWith(mockFileWriter.writeLine, 0 , 'import {MyParticipant} from \'./concerto\';');
});
});
});

0 comments on commit 399df62

Please sign in to comment.