From 4fb3b57e6b6ed8a977fac679d5d512386b32c7c7 Mon Sep 17 00:00:00 2001 From: Simon Stone Date: Thu, 15 Nov 2018 10:44:02 +0000 Subject: [PATCH] [FAB-12852] Add fabcar contract w/ new prog model (TS) Add new FabCar contract sample using the new programming model, written in TypeScript. Add the new contract sample alongside the existing one written in the old programming model, which will be removed in a subsequent change request. Change-Id: I47e5f16b475c68f9a1c4752af2623f090fbf12c9 Signed-off-by: Simon Stone --- chaincode/fabcar/typescript/.editorconfig | 16 +++ chaincode/fabcar/typescript/.gitignore | 81 ++++++++++++ chaincode/fabcar/typescript/package.json | 62 +++++++++ chaincode/fabcar/typescript/src/car.ts | 11 ++ chaincode/fabcar/typescript/src/fabcar.ts | 153 ++++++++++++++++++++++ chaincode/fabcar/typescript/src/index.ts | 8 ++ chaincode/fabcar/typescript/tsconfig.json | 16 +++ chaincode/fabcar/typescript/tslint.json | 21 +++ 8 files changed, 368 insertions(+) create mode 100755 chaincode/fabcar/typescript/.editorconfig create mode 100644 chaincode/fabcar/typescript/.gitignore create mode 100644 chaincode/fabcar/typescript/package.json create mode 100644 chaincode/fabcar/typescript/src/car.ts create mode 100644 chaincode/fabcar/typescript/src/fabcar.ts create mode 100644 chaincode/fabcar/typescript/src/index.ts create mode 100644 chaincode/fabcar/typescript/tsconfig.json create mode 100644 chaincode/fabcar/typescript/tslint.json diff --git a/chaincode/fabcar/typescript/.editorconfig b/chaincode/fabcar/typescript/.editorconfig new file mode 100755 index 0000000000..75a13be205 --- /dev/null +++ b/chaincode/fabcar/typescript/.editorconfig @@ -0,0 +1,16 @@ +# +# SPDX-License-Identifier: Apache-2.0 +# + +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false diff --git a/chaincode/fabcar/typescript/.gitignore b/chaincode/fabcar/typescript/.gitignore new file mode 100644 index 0000000000..69d6a33bbe --- /dev/null +++ b/chaincode/fabcar/typescript/.gitignore @@ -0,0 +1,81 @@ +# +# SPDX-License-Identifier: Apache-2.0 +# + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env + +# parcel-bundler cache (https://parceljs.org/) +.cache + +# next.js build output +.next + +# nuxt.js build output +.nuxt + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless + +# Compiled TypeScript files +dist + diff --git a/chaincode/fabcar/typescript/package.json b/chaincode/fabcar/typescript/package.json new file mode 100644 index 0000000000..45e96de8a6 --- /dev/null +++ b/chaincode/fabcar/typescript/package.json @@ -0,0 +1,62 @@ +{ + "name": "fabcar", + "version": "1.0.0", + "description": "FabCar contract implemented in TypeScript", + "main": "dist/index.js", + "typings": "dist/index.d.ts", + "engines": { + "node": ">=8", + "npm": ">=5" + }, + "scripts": { + "lint": "tslint -c tslint.json 'src/**/*.ts'", + "pretest": "npm run lint", + "test": "nyc mocha -r ts-node/register src/**/*.spec.ts", + "start": "fabric-chaincode-node start", + "build": "tsc", + "build:watch": "tsc -w", + "prepublishOnly": "npm run build" + }, + "engineStrict": true, + "author": "Hyperledger", + "license": "Apache-2.0", + "dependencies": { + "fabric-contract-api": "1.4.0-beta", + "fabric-shim": "1.4.0-beta" + }, + "devDependencies": { + "@types/chai": "^4.1.4", + "@types/mocha": "^5.2.3", + "@types/node": "^10.3.6", + "@types/sinon": "^5.0.1", + "@types/sinon-chai": "^3.2.0", + "chai": "^4.1.2", + "mocha": "^5.2.0", + "nyc": "^12.0.2", + "sinon": "^6.0.0", + "sinon-chai": "^3.2.0", + "ts-node": "^7.0.0", + "tslint": "^5.10.0", + "typescript": "^2.9.2" + }, + "nyc": { + "extension": [ + ".ts", + ".tsx" + ], + "exclude": [ + "coverage/**", + "dist/**" + ], + "reporter": [ + "text-summary", + "html" + ], + "all": true, + "check-coverage": true, + "statements": 100, + "branches": 100, + "functions": 100, + "lines": 100 + } +} diff --git a/chaincode/fabcar/typescript/src/car.ts b/chaincode/fabcar/typescript/src/car.ts new file mode 100644 index 0000000000..ba1016253e --- /dev/null +++ b/chaincode/fabcar/typescript/src/car.ts @@ -0,0 +1,11 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +export class Car { + public docType?: string; + public color: string; + public make: string; + public model: string; + public owner: string; +} diff --git a/chaincode/fabcar/typescript/src/fabcar.ts b/chaincode/fabcar/typescript/src/fabcar.ts new file mode 100644 index 0000000000..de72b0394f --- /dev/null +++ b/chaincode/fabcar/typescript/src/fabcar.ts @@ -0,0 +1,153 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +import { Context, Contract } from 'fabric-contract-api'; +import { Car } from './car'; + +export class FabCar extends Contract { + + public async initLedger(ctx: Context) { + console.info('============= START : Initialize Ledger ==========='); + const cars: Car[] = [ + { + color: 'blue', + make: 'Toyota', + model: 'Prius', + owner: 'Tomoko', + }, + { + color: 'red', + make: 'Ford', + model: 'Mustang', + owner: 'Brad', + }, + { + color: 'green', + make: 'Hyundai', + model: 'Tucson', + owner: 'Jin Soo', + }, + { + color: 'yellow', + make: 'Volkswagen', + model: 'Passat', + owner: 'Max', + }, + { + color: 'black', + make: 'Tesla', + model: 'S', + owner: 'Adriana', + }, + { + color: 'purple', + make: 'Peugeot', + model: '205', + owner: 'Michel', + }, + { + color: 'white', + make: 'Chery', + model: 'S22L', + owner: 'Aarav', + }, + { + color: 'violet', + make: 'Fiat', + model: 'Punto', + owner: 'Pari', + }, + { + color: 'indigo', + make: 'Tata', + model: 'Nano', + owner: 'Valeria', + }, + { + color: 'brown', + make: 'Holden', + model: 'Barina', + owner: 'Shotaro', + }, + ]; + + for (let i = 0; i < cars.length; i++) { + cars[i].docType = 'car'; + await ctx.stub.putState('CAR' + i, Buffer.from(JSON.stringify(cars[i]))); + console.info('Added <--> ', cars[i]); + } + console.info('============= END : Initialize Ledger ==========='); + } + + public async queryCar(ctx: Context, carNumber: string): Promise { + const carAsBytes = await ctx.stub.getState(carNumber); // get the car from chaincode state + if (!carAsBytes || carAsBytes.length === 0) { + throw new Error(`${carNumber} does not exist`); + } + console.log(carAsBytes.toString()); + return carAsBytes.toString(); + } + + public async createCar(ctx: Context, carNumber: string, make: string, model: string, color: string, owner: string) { + console.info('============= START : Create Car ==========='); + + const car: Car = { + color, + docType: 'car', + make, + model, + owner, + }; + + await ctx.stub.putState(carNumber, Buffer.from(JSON.stringify(car))); + console.info('============= END : Create Car ==========='); + } + + public async queryAllCars(ctx: Context): Promise { + const startKey = 'CAR0'; + const endKey = 'CAR999'; + + const iterator = await ctx.stub.getStateByRange(startKey, endKey); + + const allResults = []; + while (true) { + const res = await iterator.next(); + + if (res.value && res.value.value.toString()) { + console.log(res.value.value.toString('utf8')); + + const Key = res.value.key; + let Record; + try { + Record = JSON.parse(res.value.value.toString('utf8')); + } catch (err) { + console.log(err); + Record = res.value.value.toString('utf8'); + } + allResults.push({ Key, Record }); + } + if (res.done) { + console.log('end of data'); + await iterator.close(); + console.info(allResults); + return JSON.stringify(allResults); + } + } + } + + public async changeCarOwner(ctx: Context, carNumber: string, newOwner: string) { + console.info('============= START : changeCarOwner ==========='); + + const carAsBytes = await ctx.stub.getState(carNumber); // get the car from chaincode state + if (!carAsBytes || carAsBytes.length === 0) { + throw new Error(`${carNumber} does not exist`); + } + const car: Car = JSON.parse(carAsBytes.toString()); + car.owner = newOwner; + + await ctx.stub.putState(carNumber, Buffer.from(JSON.stringify(car))); + console.info('============= END : changeCarOwner ==========='); + } + +} diff --git a/chaincode/fabcar/typescript/src/index.ts b/chaincode/fabcar/typescript/src/index.ts new file mode 100644 index 0000000000..c0a2fcf67c --- /dev/null +++ b/chaincode/fabcar/typescript/src/index.ts @@ -0,0 +1,8 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + +import { FabCar } from './fabcar'; +export { FabCar } from './fabcar'; + +export const contracts: any[] = [ FabCar ]; diff --git a/chaincode/fabcar/typescript/tsconfig.json b/chaincode/fabcar/typescript/tsconfig.json new file mode 100644 index 0000000000..8c96ea0719 --- /dev/null +++ b/chaincode/fabcar/typescript/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "outDir": "dist", + "target": "es2017", + "moduleResolution": "node", + "module": "commonjs", + "declaration": true, + "sourceMap": true + }, + "include": [ + "./src/**/*" + ], + "exclude": [ + "./src/**/*.spec.ts" + ] +} diff --git a/chaincode/fabcar/typescript/tslint.json b/chaincode/fabcar/typescript/tslint.json new file mode 100644 index 0000000000..33ccbf3c64 --- /dev/null +++ b/chaincode/fabcar/typescript/tslint.json @@ -0,0 +1,21 @@ +{ + "defaultSeverity": "error", + "extends": [ + "tslint:recommended" + ], + "jsRules": {}, + "rules": { + "indent": [true, "spaces", 4], + "linebreak-style": [true, "LF"], + "quotemark": [true, "single"], + "semicolon": [true, "always"], + "no-console": false, + "curly": true, + "triple-equals": true, + "no-string-throw": true, + "no-var-keyword": true, + "no-trailing-whitespace": true, + "object-literal-key-quotes": [true, "as-needed"] + }, + "rulesDirectory": [] +}