Skip to content
This repository was archived by the owner on Feb 7, 2023. It is now read-only.

Commit

Permalink
Allow asset type to be specified (contributes to #89) (#98)
Browse files Browse the repository at this point in the history
Signed-off-by: Simon Stone <sstone1@uk.ibm.com>
  • Loading branch information
Simon Stone authored and cazfletch committed Apr 25, 2019
1 parent b8804dc commit 64d6234
Show file tree
Hide file tree
Showing 14 changed files with 253 additions and 220 deletions.
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
#

coverage
generators/*/templates/**
tmp
20 changes: 20 additions & 0 deletions generators/contract/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

'use strict';

const camelcase = require('camelcase');
const decamelize = require('decamelize');
const Generator = require('yeoman-generator');
const path = require('path');
const process = require('process');
Expand Down Expand Up @@ -47,15 +49,33 @@ module.exports = class extends Generator {
name : 'license',
message : 'Please specify the contract license:',
when : () => !this.options.license
}, {
type: 'input',
name: 'asset',
message: 'Please specify the asset type:',
when: () => !this.options.asset
}];
const answers = await this.prompt(questions);
Object.assign(this.options, answers);
this.options.spdxAndLicense = `SPDX-License-Identifier: ${this.options.license}`;
this.options.assetCamelCase = camelcase(this.options.asset);
this.options.assetPascalCase = camelcase(this.options.asset, { pascalCase: true });
this.options.assetDashSeparator = decamelize(this.options.assetCamelCase, '-');
this.options.assetSpaceSeparator = decamelize(this.options.assetCamelCase, ' ');
}

async writing () {
console.log('Generating files...');
this.fs.copyTpl(this.templatePath(this.options.language), this._getDestination(), this.options, undefined, {globOptions : {dot : true}});
if (this.options.language === 'javascript') {
this.fs.move(this.destinationPath('lib/my-contract.js'), this.destinationPath(`lib/${this.options.assetDashSeparator}-contract.js`));
this.fs.move(this.destinationPath('test/my-contract.js'), this.destinationPath(`test/${this.options.assetDashSeparator}-contract.js`));
}
if (this.options.language === 'typescript') {
this.fs.move(this.destinationPath('src/my-asset.ts'), this.destinationPath(`src/${this.options.assetDashSeparator}.ts`));
this.fs.move(this.destinationPath('src/my-contract.ts'), this.destinationPath(`src/${this.options.assetDashSeparator}-contract.ts`));
this.fs.move(this.destinationPath('src/my-contract.spec.ts'), this.destinationPath(`src/${this.options.assetDashSeparator}-contract.spec.ts`));
}
// npm install does dumb stuff and renames our gitignore to npmignore, so rename it back!
this.fs.move(this.destinationPath('.gitignore-hidefromnpm'), this.destinationPath('.gitignore'));
this.fs.move(this.destinationPath('.npmignore-hidefromnpm'), this.destinationPath('.npmignore'));
Expand Down
6 changes: 3 additions & 3 deletions generators/contract/templates/javascript/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

'use strict';

const MyContract = require('./lib/my-contract');
const <%= assetPascalCase %>Contract = require('./lib/<%= assetDashSeparator %>-contract');

module.exports.MyContract = MyContract;
module.exports.contracts = [ MyContract ];
module.exports.<%= assetPascalCase %>Contract = <%= assetPascalCase %>Contract;
module.exports.contracts = [ <%= assetPascalCase %>Contract ];
40 changes: 20 additions & 20 deletions generators/contract/templates/javascript/lib/my-contract.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,51 +6,51 @@

const { Contract } = require('fabric-contract-api');

class MyContract extends Contract {
class <%= assetPascalCase %>Contract extends Contract {

async assetExists(ctx, assetId) {
const buffer = await ctx.stub.getState(assetId);
async <%= assetCamelCase %>Exists(ctx, <%= assetCamelCase %>Id) {
const buffer = await ctx.stub.getState(<%= assetCamelCase %>Id);
return (!!buffer && buffer.length > 0);
}

async createAsset(ctx, assetId, value) {
const exists = await this.assetExists(ctx, assetId);
async create<%= assetPascalCase %>(ctx, <%= assetCamelCase %>Id, value) {
const exists = await this.<%= assetCamelCase %>Exists(ctx, <%= assetCamelCase %>Id);
if (exists) {
throw new Error(`The asset ${assetId} already exists`);
throw new Error(`The <%= assetSpaceSeparator %> ${<%= assetCamelCase %>Id} already exists`);
}
const asset = { value };
const buffer = Buffer.from(JSON.stringify(asset));
await ctx.stub.putState(assetId, buffer);
await ctx.stub.putState(<%= assetCamelCase %>Id, buffer);
}
async readAsset(ctx, assetId) {
const exists = await this.assetExists(ctx, assetId);
async read<%= assetPascalCase %>(ctx, <%= assetCamelCase %>Id) {
const exists = await this.<%= assetCamelCase %>Exists(ctx, <%= assetCamelCase %>Id);
if (!exists) {
throw new Error(`The asset ${assetId} does not exist`);
throw new Error(`The <%= assetSpaceSeparator %> ${<%= assetCamelCase %>Id} does not exist`);
}
const buffer = await ctx.stub.getState(assetId);
const buffer = await ctx.stub.getState(<%= assetCamelCase %>Id);
const asset = JSON.parse(buffer.toString());
return asset;
}

async updateAsset(ctx, assetId, newValue) {
const exists = await this.assetExists(ctx, assetId);
async update<%= assetPascalCase %>(ctx, <%= assetCamelCase %>Id, newValue) {
const exists = await this.<%= assetCamelCase %>Exists(ctx, <%= assetCamelCase %>Id);
if (!exists) {
throw new Error(`The asset ${assetId} does not exist`);
throw new Error(`The <%= assetSpaceSeparator %> ${<%= assetCamelCase %>Id} does not exist`);
}
const asset = { value: newValue };
const buffer = Buffer.from(JSON.stringify(asset));
await ctx.stub.putState(assetId, buffer);
await ctx.stub.putState(<%= assetCamelCase %>Id, buffer);
}
async deleteAsset(ctx, assetId) {
const exists = await this.assetExists(ctx, assetId);
async delete<%= assetPascalCase %>(ctx, <%= assetCamelCase %>Id) {
const exists = await this.<%= assetCamelCase %>Exists(ctx, <%= assetCamelCase %>Id);
if (!exists) {
throw new Error(`The asset ${assetId} does not exist`);
throw new Error(`The <%= assetSpaceSeparator %> ${<%= assetCamelCase %>Id} does not exist`);
}
await ctx.stub.deleteState(assetId);
await ctx.stub.deleteState(<%= assetCamelCase %>Id);
}

}

module.exports = MyContract;
module.exports = <%= assetPascalCase %>Contract;
64 changes: 32 additions & 32 deletions generators/contract/templates/javascript/test/my-contract.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
'use strict';

const { ChaincodeStub, ClientIdentity } = require('fabric-shim');
const { MyContract } = require('..');
const { <%= assetPascalCase %>Contract } = require('..');
const winston = require('winston');

const chai = require('chai');
Expand All @@ -30,77 +30,77 @@ class TestContext {

}

describe('MyContract', () => {
describe('<%= assetPascalCase %>Contract', () => {

let contract;
let ctx;

beforeEach(() => {
contract = new MyContract();
contract = new <%= assetPascalCase %>Contract();
ctx = new TestContext();
ctx.stub.getState.withArgs('1001').resolves(Buffer.from('{"value":"asset 1001 value"}'));
ctx.stub.getState.withArgs('1002').resolves(Buffer.from('{"value":"asset 1002 value"}'));
ctx.stub.getState.withArgs('1001').resolves(Buffer.from('{"value":"<%= assetSpaceSeparator %> 1001 value"}'));
ctx.stub.getState.withArgs('1002').resolves(Buffer.from('{"value":"<%= assetSpaceSeparator %> 1002 value"}'));
});

describe('#assetExists', () => {
describe('#<%= assetCamelCase %>Exists', () => {

it('should return true for an asset', async () => {
await contract.assetExists(ctx, '1001').should.eventually.be.true;
it('should return true for a <%= assetSpaceSeparator %>', async () => {
await contract.<%= assetCamelCase %>Exists(ctx, '1001').should.eventually.be.true;
});

it('should return false for an asset that does not exist', async () => {
await contract.assetExists(ctx, '1003').should.eventually.be.false;
it('should return false for a <%= assetSpaceSeparator %> that does not exist', async () => {
await contract.<%= assetCamelCase %>Exists(ctx, '1003').should.eventually.be.false;
});

});

describe('#createAsset', () => {
describe('#create<%= assetPascalCase %>', () => {

it('should create an asset', async () => {
await contract.createAsset(ctx, '1003', 'asset 1003 value');
ctx.stub.putState.should.have.been.calledOnceWithExactly('1003', Buffer.from('{"value":"asset 1003 value"}'));
it('should create a <%= assetSpaceSeparator %>', async () => {
await contract.create<%= assetPascalCase %>(ctx, '1003', '<%= assetSpaceSeparator %> 1003 value');
ctx.stub.putState.should.have.been.calledOnceWithExactly('1003', Buffer.from('{"value":"<%= assetSpaceSeparator %> 1003 value"}'));
});

it('should throw an error for an asset that already exists', async () => {
await contract.createAsset(ctx, '1001', 'myvalue').should.be.rejectedWith(/The asset 1001 already exists/);
it('should throw an error for a <%= assetSpaceSeparator %> that already exists', async () => {
await contract.create<%= assetPascalCase %>(ctx, '1001', 'myvalue').should.be.rejectedWith(/The <%= assetSpaceSeparator %> 1001 already exists/);
});

});

describe('#readAsset', () => {
describe('#read<%= assetPascalCase %>', () => {

it('should return an asset', async () => {
await contract.readAsset(ctx, '1001').should.eventually.deep.equal({ value: 'asset 1001 value' });
it('should return a <%= assetSpaceSeparator %>', async () => {
await contract.read<%= assetPascalCase %>(ctx, '1001').should.eventually.deep.equal({ value: '<%= assetSpaceSeparator %> 1001 value' });
});

it('should throw an error for an asset that does not exist', async () => {
await contract.readAsset(ctx, '1003').should.be.rejectedWith(/The asset 1003 does not exist/);
it('should throw an error for a <%= assetSpaceSeparator %> that does not exist', async () => {
await contract.read<%= assetPascalCase %>(ctx, '1003').should.be.rejectedWith(/The <%= assetSpaceSeparator %> 1003 does not exist/);
});

});

describe('#updateAsset', () => {
describe('#update<%= assetPascalCase %>', () => {

it('should update an asset', async () => {
await contract.updateAsset(ctx, '1001', 'asset 1001 new value');
ctx.stub.putState.should.have.been.calledOnceWithExactly('1001', Buffer.from('{"value":"asset 1001 new value"}'));
it('should update a <%= assetSpaceSeparator %>', async () => {
await contract.update<%= assetPascalCase %>(ctx, '1001', '<%= assetSpaceSeparator %> 1001 new value');
ctx.stub.putState.should.have.been.calledOnceWithExactly('1001', Buffer.from('{"value":"<%= assetSpaceSeparator %> 1001 new value"}'));
});

it('should throw an error for an asset that does not exist', async () => {
await contract.updateAsset(ctx, '1003', 'asset 1003 new value').should.be.rejectedWith(/The asset 1003 does not exist/);
it('should throw an error for a <%= assetSpaceSeparator %> that does not exist', async () => {
await contract.update<%= assetPascalCase %>(ctx, '1003', '<%= assetSpaceSeparator %> 1003 new value').should.be.rejectedWith(/The <%= assetSpaceSeparator %> 1003 does not exist/);
});

});

describe('#deleteAsset', () => {
describe('#delete<%= assetPascalCase %>', () => {

it('should delete an asset', async () => {
await contract.deleteAsset(ctx, '1001');
it('should delete a <%= assetSpaceSeparator %>', async () => {
await contract.delete<%= assetPascalCase %>(ctx, '1001');
ctx.stub.deleteState.should.have.been.calledOnceWithExactly('1001');
});

it('should throw an error for an asset that does not exist', async () => {
await contract.deleteAsset(ctx, '1003').should.be.rejectedWith(/The asset 1003 does not exist/);
it('should throw an error for a <%= assetSpaceSeparator %> that does not exist', async () => {
await contract.delete<%= assetPascalCase %>(ctx, '1003').should.be.rejectedWith(/The <%= assetSpaceSeparator %> 1003 does not exist/);
});

});
Expand Down
6 changes: 3 additions & 3 deletions generators/contract/templates/typescript/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* <%= spdxAndLicense // SPDX-License-Identifier: Apache-2.0 %>
*/

import { MyContract } from './my-contract';
export { MyContract } from './my-contract';
import { <%= assetPascalCase %>Contract } from './<%= assetDashSeparator %>-contract';
export { <%= assetPascalCase %>Contract } from './<%= assetDashSeparator %>-contract';

export const contracts: any[] = [ MyContract ];
export const contracts: any[] = [ <%= assetPascalCase %>Contract ];
2 changes: 1 addition & 1 deletion generators/contract/templates/typescript/src/my-asset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import { Object, Property } from 'fabric-contract-api';

@Object()
export class MyAsset {
export class <%= assetPascalCase %> {

@Property()
public value: string;
Expand Down
66 changes: 33 additions & 33 deletions generators/contract/templates/typescript/src/my-contract.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import { Context } from 'fabric-contract-api';
import { ChaincodeStub, ClientIdentity } from 'fabric-shim';
import { MyContract } from '.';
import { <%= assetPascalCase %>Contract } from '.';

import * as chai from 'chai';
import * as chaiAsPromised from 'chai-as-promised';
Expand All @@ -25,77 +25,77 @@ class TestContext implements Context {
};
}

describe('MyContract', () => {
describe('<%= assetPascalCase %>Contract', () => {

let contract: MyContract;
let contract: <%= assetPascalCase %>Contract;
let ctx: TestContext;

beforeEach(() => {
contract = new MyContract();
contract = new <%= assetPascalCase %>Contract();
ctx = new TestContext();
ctx.stub.getState.withArgs('1001').resolves(Buffer.from('{"value":"asset 1001 value"}'));
ctx.stub.getState.withArgs('1002').resolves(Buffer.from('{"value":"asset 1002 value"}'));
ctx.stub.getState.withArgs('1001').resolves(Buffer.from('{"value":"<%= assetSpaceSeparator %> 1001 value"}'));
ctx.stub.getState.withArgs('1002').resolves(Buffer.from('{"value":"<%= assetSpaceSeparator %> 1002 value"}'));
});

describe('#assetExists', () => {
describe('#<%= assetCamelCase %>Exists', () => {

it('should return true for an asset', async () => {
await contract.assetExists(ctx, '1001').should.eventually.be.true;
it('should return true for a <%= assetSpaceSeparator %>', async () => {
await contract.<%= assetCamelCase %>Exists(ctx, '1001').should.eventually.be.true;
});

it('should return false for an asset that does not exist', async () => {
await contract.assetExists(ctx, '1003').should.eventually.be.false;
it('should return false for a <%= assetSpaceSeparator %> that does not exist', async () => {
await contract.<%= assetCamelCase %>Exists(ctx, '1003').should.eventually.be.false;
});

});

describe('#createAsset', () => {
describe('#create<%= assetPascalCase %>', () => {

it('should create an asset', async () => {
await contract.createAsset(ctx, '1003', 'asset 1003 value');
ctx.stub.putState.should.have.been.calledOnceWithExactly('1003', Buffer.from('{"value":"asset 1003 value"}'));
it('should create a <%= assetSpaceSeparator %>', async () => {
await contract.create<%= assetPascalCase %>(ctx, '1003', '<%= assetSpaceSeparator %> 1003 value');
ctx.stub.putState.should.have.been.calledOnceWithExactly('1003', Buffer.from('{"value":"<%= assetSpaceSeparator %> 1003 value"}'));
});

it('should throw an error for an asset that already exists', async () => {
await contract.createAsset(ctx, '1001', 'myvalue').should.be.rejectedWith(/The asset 1001 already exists/);
it('should throw an error for a <%= assetSpaceSeparator %> that already exists', async () => {
await contract.create<%= assetPascalCase %>(ctx, '1001', 'myvalue').should.be.rejectedWith(/The <%= assetSpaceSeparator %> 1001 already exists/);
});

});

describe('#readAsset', () => {
describe('#read<%= assetPascalCase %>', () => {

it('should return an asset', async () => {
await contract.readAsset(ctx, '1001').should.eventually.deep.equal({ value: 'asset 1001 value' });
it('should return a <%= assetSpaceSeparator %>', async () => {
await contract.read<%= assetPascalCase %>(ctx, '1001').should.eventually.deep.equal({ value: '<%= assetSpaceSeparator %> 1001 value' });
});

it('should throw an error for an asset that does not exist', async () => {
await contract.readAsset(ctx, '1003').should.be.rejectedWith(/The asset 1003 does not exist/);
it('should throw an error for a <%= assetSpaceSeparator %> that does not exist', async () => {
await contract.read<%= assetPascalCase %>(ctx, '1003').should.be.rejectedWith(/The <%= assetSpaceSeparator %> 1003 does not exist/);
});

});

describe('#updateAsset', () => {
describe('#update<%= assetPascalCase %>', () => {

it('should update an asset', async () => {
await contract.updateAsset(ctx, '1001', 'asset 1001 new value');
ctx.stub.putState.should.have.been.calledOnceWithExactly('1001', Buffer.from('{"value":"asset 1001 new value"}'));
it('should update a <%= assetSpaceSeparator %>', async () => {
await contract.update<%= assetPascalCase %>(ctx, '1001', '<%= assetSpaceSeparator %> 1001 new value');
ctx.stub.putState.should.have.been.calledOnceWithExactly('1001', Buffer.from('{"value":"<%= assetSpaceSeparator %> 1001 new value"}'));
});

it('should throw an error for an asset that does not exist', async () => {
await contract.updateAsset(ctx, '1003', 'asset 1003 new value').should.be.rejectedWith(/The asset 1003 does not exist/);
it('should throw an error for a <%= assetSpaceSeparator %> that does not exist', async () => {
await contract.update<%= assetPascalCase %>(ctx, '1003', '<%= assetSpaceSeparator %> 1003 new value').should.be.rejectedWith(/The <%= assetSpaceSeparator %> 1003 does not exist/);
});

});

describe('#deleteAsset', () => {
describe('#delete<%= assetPascalCase %>', () => {

it('should delete an asset', async () => {
await contract.deleteAsset(ctx, '1001');
it('should delete a <%= assetSpaceSeparator %>', async () => {
await contract.delete<%= assetPascalCase %>(ctx, '1001');
ctx.stub.deleteState.should.have.been.calledOnceWithExactly('1001');
});

it('should throw an error for an asset that does not exist', async () => {
await contract.deleteAsset(ctx, '1003').should.be.rejectedWith(/The asset 1003 does not exist/);
it('should throw an error for a <%= assetSpaceSeparator %> that does not exist', async () => {
await contract.delete<%= assetPascalCase %>(ctx, '1003').should.be.rejectedWith(/The <%= assetSpaceSeparator %> 1003 does not exist/);
});

});
Expand Down
Loading

0 comments on commit 64d6234

Please sign in to comment.