From 8d6affb99fa8254c176936435cc6979543610548 Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Mon, 29 Aug 2022 23:24:20 +0300 Subject: [PATCH] NearContract base class deleted --- examples/src/counter.js | 8 +- lib/build-tools/near-bindgen-exporter.js | 53 ++++++------- lib/index.d.ts | 5 +- lib/index.js | 5 +- lib/near-bindgen.d.ts | 9 ++- lib/near-bindgen.js | 32 +++++--- lib/near-contract.d.ts | 8 -- lib/near-contract.js | 31 -------- src/build-tools/near-bindgen-exporter.js | 95 ++++++++++-------------- src/index.ts | 6 +- src/near-bindgen.ts | 45 +++++++---- src/near-contract.ts | 38 ---------- 12 files changed, 134 insertions(+), 201 deletions(-) delete mode 100644 lib/near-contract.d.ts delete mode 100644 lib/near-contract.js delete mode 100644 src/near-contract.ts diff --git a/examples/src/counter.js b/examples/src/counter.js index fac5a9e8a..a7ea3e7eb 100644 --- a/examples/src/counter.js +++ b/examples/src/counter.js @@ -1,10 +1,10 @@ -import { NearContract, NearBindgen, near, call, view } from 'near-sdk-js' +import { NearBindgen, near, call, view, initialize } from 'near-sdk-js' import { isUndefined } from 'lodash-es' @NearBindgen -class Counter extends NearContract { - constructor({ initial = 0 }) { - super() +class Counter { + @initialize + init({ initial = 0 }) { this.count = initial } diff --git a/lib/build-tools/near-bindgen-exporter.js b/lib/build-tools/near-bindgen-exporter.js index d086d3ca7..0909e209e 100644 --- a/lib/build-tools/near-bindgen-exporter.js +++ b/lib/build-tools/near-bindgen-exporter.js @@ -17,38 +17,39 @@ export default function () { let viewMethod = child.key.name; contractMethods[viewMethod] = 'view'; } + else if (child.decorators[0].expression.name == 'initialize') { + let initMethod = child.key.name; + contractMethods[initMethod] = 'initialize'; + } } } for (let method of Object.keys(contractMethods)) { path.insertAfter(t.exportNamedDeclaration(t.functionDeclaration(t.identifier(method), [], t.blockStatement([ - // let _contract = ContractClass._get() - t.variableDeclaration('let', [t.variableDeclarator(t.identifier('_contract'), t.callExpression(t.memberExpression(classId, t.identifier('_get')), []))]), - // _contract.deserialize() - t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('_contract'), t.identifier('deserialize')), [])), - // let args = _contract.constructor.deserializeArgs() - t.variableDeclaration('let', [t.variableDeclarator(t.identifier('args'), t.callExpression(t.memberExpression(t.memberExpression(t.identifier('_contract'), t.identifier('constructor')), t.identifier('deserializeArgs')), []))]), - // let ret = _contract.method(args) - t.variableDeclaration('let', [t.variableDeclarator(t.identifier('ret'), t.callExpression(t.memberExpression(t.identifier('_contract'), t.identifier(method)), [t.identifier('args')]))]), - contractMethods[method] == 'call' ? - // _contract.serialize() - t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('_contract'), t.identifier('serialize')), [])) + // const _state = Counter._getState(); + t.variableDeclaration('let', [t.variableDeclarator(t.identifier('_state'), t.callExpression(t.memberExpression(classId, t.identifier('_getState')), []))]), + contractMethods[method] == 'initialize' ? + // if (_state) { throw new Error('Counter already initialized'); } + t.ifStatement(t.identifier('_state'), t.throwStatement(t.newExpression(t.identifier('Error'), [t.stringLiteral('Contract already initialized')]))) + : t.emptyStatement(), + // let _contract = Counter._create(); + t.variableDeclaration('let', [t.variableDeclarator(t.identifier('_contract'), t.callExpression(t.memberExpression(classId, t.identifier('_create')), []))]), + // Object.assign(_contract, state); + t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('Object'), t.identifier('assign')), [t.identifier('_contract'), t.identifier('_state')])), + // let _args = Counter._getArgs(); + t.variableDeclaration('let', [t.variableDeclarator(t.identifier('_args'), t.callExpression(t.memberExpression(classId, t.identifier('_getArgs')), []))]), + // let _result = _contract.method(args); + t.variableDeclaration('let', [t.variableDeclarator(t.identifier('_result'), t.callExpression(t.memberExpression(t.identifier('_contract'), t.identifier(method)), [t.identifier('_args')]))]), + contractMethods[method] == 'initialize' || contractMethods[method] == 'call' ? + // _contract._saveToStorage(); + t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('_contract'), t.identifier('_saveToStorage')), [])) : t.emptyStatement(), - // if (ret !== undefined) - t.ifStatement(t.binaryExpression('!==', t.identifier('ret'), t.identifier('undefined')), - // env.value_return(_contract.constructor.serializeReturn(ret)) - t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('env'), t.identifier('value_return')), [ - t.callExpression(t.memberExpression(t.memberExpression(t.identifier('_contract'), t.identifier('constructor')), t.identifier('serializeReturn')), [t.identifier('ret')]) - ]))) - ])), [t.exportSpecifier(t.identifier(method), t.identifier(method))])); - path.scope.registerDeclaration(path.getSibling(path.key + 1)); + // if (_result !== undefined) near.valueReturn(_contract._serialize(result)); + t.ifStatement(t.binaryExpression('!==', t.identifier('_result'), t.identifier('undefined')), t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('near'), t.identifier('valueReturn')), [t.callExpression(t.memberExpression(t.identifier('_contract'), t.identifier('_serialize')), [t.identifier('_result')])]))), + ])))); + console.log('Near bindgen export done'); } - path.insertAfter(t.exportNamedDeclaration(t.functionDeclaration(t.identifier('init'), [], t.blockStatement([ - t.expressionStatement(t.callExpression(t.memberExpression(classId, t.identifier('_init')), [])), - ])), [t.exportSpecifier(t.identifier('init'), t.identifier('init'))])); - path.scope.registerDeclaration(path.getSibling(path.key + 1)); - console.log('Near bindgen export done'); } - }, - }, + } + } }; } diff --git a/lib/index.d.ts b/lib/index.d.ts index 3e3000f0c..972642e71 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -1,6 +1,5 @@ -import { call, view, NearBindgen } from "./near-bindgen"; -import { NearContract } from "./near-contract"; +import { call, view, initialize, NearBindgen } from "./near-bindgen"; import * as near from "./api"; import { LookupMap, Vector, LookupSet, UnorderedMap, UnorderedSet } from "./collections"; import { bytes, Bytes, assert } from "./utils"; -export { call, view, NearBindgen, NearContract, near, LookupMap, Vector, LookupSet, UnorderedMap, UnorderedSet, bytes, Bytes, assert, }; +export { call, view, initialize, NearBindgen, near, LookupMap, Vector, LookupSet, UnorderedMap, UnorderedSet, bytes, Bytes, assert, }; diff --git a/lib/index.js b/lib/index.js index bc19a391a..c5861a788 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,6 +1,5 @@ -import { call, view, NearBindgen } from "./near-bindgen"; -import { NearContract } from "./near-contract"; +import { call, view, initialize, NearBindgen } from "./near-bindgen"; import * as near from "./api"; import { LookupMap, Vector, LookupSet, UnorderedMap, UnorderedSet, } from "./collections"; import { bytes, assert } from "./utils"; -export { call, view, NearBindgen, NearContract, near, LookupMap, Vector, LookupSet, UnorderedMap, UnorderedSet, bytes, assert, }; +export { call, view, initialize, NearBindgen, near, LookupMap, Vector, LookupSet, UnorderedMap, UnorderedSet, bytes, assert, }; diff --git a/lib/near-bindgen.d.ts b/lib/near-bindgen.d.ts index a26512d4d..36d3a55ad 100644 --- a/lib/near-bindgen.d.ts +++ b/lib/near-bindgen.d.ts @@ -1,9 +1,14 @@ +export declare function initialize(target: Object, key: string | symbol, descriptor: TypedPropertyDescriptor): void; export declare function call(target: Object, key: string | symbol, descriptor: TypedPropertyDescriptor): void; export declare function view(target: Object, key: string | symbol, descriptor: TypedPropertyDescriptor): void; export declare function NearBindgen(target: T): { new (...args: any[]): {}; - _init(): {}; - _get(): any; + _create(): {}; + _getState(): Object; + _saveToStorage(): void; + _getArgs(): JSON; + _serialize(value: Object): string; + _deserialize(value: string): Object; } & T; diff --git a/lib/near-bindgen.js b/lib/near-bindgen.js index 6145f87c0..01791e6e1 100644 --- a/lib/near-bindgen.js +++ b/lib/near-bindgen.js @@ -1,22 +1,30 @@ +import * as near from "./api"; +export function initialize(target, key, descriptor) { +} export function call(target, key, descriptor) { } export function view(target, key, descriptor) { } export function NearBindgen(target) { return class extends target { - static _init() { - // @ts-ignore - let args = target.deserializeArgs(); - let ret = new target(args); - // @ts-ignore - ret.init(); - // @ts-ignore - ret.serialize(); - return ret; + static _create() { + return new target(); + } + static _getState() { + const rawState = near.storageRead("STATE"); + return rawState ? this._deserialize(rawState) : null; + } + static _saveToStorage() { + near.storageWrite("STATE", this._serialize(this)); + } + static _getArgs() { + return JSON.parse(near.input() || "{}"); + } + static _serialize(value) { + return JSON.stringify(value); } - static _get() { - let ret = Object.create(target.prototype); - return ret; + static _deserialize(value) { + return JSON.parse(value); } }; } diff --git a/lib/near-contract.d.ts b/lib/near-contract.d.ts deleted file mode 100644 index 6ebb4963b..000000000 --- a/lib/near-contract.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -export declare abstract class NearContract { - deserialize(): void; - serialize(): void; - static deserializeArgs(): any; - static serializeReturn(ret: any): string; - abstract default(): any; - init(): any; -} diff --git a/lib/near-contract.js b/lib/near-contract.js deleted file mode 100644 index 13a117830..000000000 --- a/lib/near-contract.js +++ /dev/null @@ -1,31 +0,0 @@ -import * as near from "./api"; -export class NearContract { - deserialize() { - const rawState = near.storageRead("STATE"); - if (rawState) { - const state = JSON.parse(rawState); - // reconstruction of the contract class object from plain object - let c = this.default(); - Object.assign(this, state); - for (const item in c) { - if (c[item].constructor?.deserialize !== undefined) { - this[item] = c[item].constructor.deserialize(this[item]); - } - } - } - else { - throw new Error("Contract state is empty"); - } - } - serialize() { - near.storageWrite("STATE", JSON.stringify(this)); - } - static deserializeArgs() { - let args = near.input(); - return JSON.parse(args || "{}"); - } - static serializeReturn(ret) { - return JSON.stringify(ret); - } - init() { } -} diff --git a/src/build-tools/near-bindgen-exporter.js b/src/build-tools/near-bindgen-exporter.js index 6fdae41d9..e97922d05 100644 --- a/src/build-tools/near-bindgen-exporter.js +++ b/src/build-tools/near-bindgen-exporter.js @@ -1,70 +1,55 @@ import * as t from "@babel/types"; - export default function () { return { visitor: { ClassDeclaration(path) { - let classNode = path.node + let classNode = path.node; if (classNode.decorators && classNode.decorators[0].expression.name == 'NearBindgen') { - let classId = classNode.id - let contractMethods = {} - - for(let child of classNode.body.body) { + let classId = classNode.id; + let contractMethods = {}; + for (let child of classNode.body.body) { if (child.type == 'ClassMethod' && child.kind == 'method' && child.decorators) { if (child.decorators[0].expression.name == 'call') { - let callMethod = child.key.name - contractMethods[callMethod] = 'call' - } else if (child.decorators[0].expression.name == 'view') { - let viewMethod = child.key.name - contractMethods[viewMethod] = 'view' + let callMethod = child.key.name; + contractMethods[callMethod] = 'call'; + } + else if (child.decorators[0].expression.name == 'view') { + let viewMethod = child.key.name; + contractMethods[viewMethod] = 'view'; + } + else if (child.decorators[0].expression.name == 'initialize') { + let initMethod = child.key.name; + contractMethods[initMethod] = 'initialize'; } } } - for (let method of Object.keys(contractMethods)) { - path.insertAfter( - t.exportNamedDeclaration( - t.functionDeclaration(t.identifier(method), [], t.blockStatement([ - // let _contract = ContractClass._get() - t.variableDeclaration('let', [t.variableDeclarator(t.identifier('_contract'), - t.callExpression(t.memberExpression(classId, t.identifier('_get')), []))]), - // _contract.deserialize() - t.expressionStatement( - t.callExpression(t.memberExpression(t.identifier('_contract'), t.identifier('deserialize')), [])), - // let args = _contract.constructor.deserializeArgs() - t.variableDeclaration('let', [t.variableDeclarator(t.identifier('args'), - t.callExpression(t.memberExpression(t.memberExpression(t.identifier('_contract'), t.identifier('constructor')), t.identifier('deserializeArgs')), []))]), - // let ret = _contract.method(args) - t.variableDeclaration('let', [t.variableDeclarator(t.identifier('ret'), - t.callExpression(t.memberExpression(t.identifier('_contract'), t.identifier(method)), [t.identifier('args')]))]), - contractMethods[method] == 'call' ? - // _contract.serialize() - t.expressionStatement( - t.callExpression(t.memberExpression(t.identifier('_contract'), t.identifier('serialize')), [])) - : t.emptyStatement(), - // if (ret !== undefined) - t.ifStatement(t.binaryExpression('!==', t.identifier('ret'), t.identifier('undefined')), - // env.value_return(_contract.constructor.serializeReturn(ret)) - t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('env'), t.identifier('value_return')), [ - t.callExpression(t.memberExpression(t.memberExpression(t.identifier('_contract'), t.identifier('constructor')), t.identifier('serializeReturn')), [t.identifier('ret')]) - ])) - ) - ])), - [t.exportSpecifier(t.identifier(method), t.identifier(method))])) - path.scope.registerDeclaration(path.getSibling(path.key + 1)) + path.insertAfter(t.exportNamedDeclaration(t.functionDeclaration(t.identifier(method), [], t.blockStatement([ + // const _state = Counter._getState(); + t.variableDeclaration('let', [t.variableDeclarator(t.identifier('_state'), t.callExpression(t.memberExpression(classId, t.identifier('_getState')), []))]), + contractMethods[method] == 'initialize' ? + // if (_state) { throw new Error('Counter already initialized'); } + t.ifStatement(t.identifier('_state'), t.throwStatement(t.newExpression(t.identifier('Error'), [t.stringLiteral('Contract already initialized')]))) + : t.emptyStatement(), + // let _contract = Counter._create(); + t.variableDeclaration('let', [t.variableDeclarator(t.identifier('_contract'), t.callExpression(t.memberExpression(classId, t.identifier('_create')), []))]), + // Object.assign(_contract, state); + t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('Object'), t.identifier('assign')), [t.identifier('_contract'), t.identifier('_state')])), + // let _args = Counter._getArgs(); + t.variableDeclaration('let', [t.variableDeclarator(t.identifier('_args'), t.callExpression(t.memberExpression(classId, t.identifier('_getArgs')), []))]), + // let _result = _contract.method(args); + t.variableDeclaration('let', [t.variableDeclarator(t.identifier('_result'), t.callExpression(t.memberExpression(t.identifier('_contract'), t.identifier(method)), [t.identifier('_args')]))]), + contractMethods[method] == 'initialize' || contractMethods[method] == 'call' ? + // _contract._saveToStorage(); + t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('_contract'), t.identifier('_saveToStorage')), [])) + : t.emptyStatement(), + // if (_result !== undefined) near.valueReturn(_contract._serialize(result)); + t.ifStatement(t.binaryExpression('!==', t.identifier('_result'), t.identifier('undefined')), t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('near'), t.identifier('valueReturn')), [t.callExpression(t.memberExpression(t.identifier('_contract'), t.identifier('_serialize')), [t.identifier('_result')])]))), + ])))); + console.log('Near bindgen export done'); } - - path.insertAfter( - t.exportNamedDeclaration( - t.functionDeclaration(t.identifier('init'), [], t.blockStatement([ - t.expressionStatement(t.callExpression(t.memberExpression(classId, t.identifier('_init')), [])), - ])), - [t.exportSpecifier(t.identifier('init'), t.identifier('init'))])) - path.scope.registerDeclaration(path.getSibling(path.key + 1)) - - console.log('Near bindgen export done') } - }, - }, - } + } + } + }; } diff --git a/src/index.ts b/src/index.ts index 813ad3920..9eceedd5c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,4 @@ -import { call, view, NearBindgen } from "./near-bindgen"; - -import { NearContract } from "./near-contract"; +import { call, view, initialize, NearBindgen } from "./near-bindgen"; import * as near from "./api"; import { @@ -16,8 +14,8 @@ import { bytes, Bytes, assert } from "./utils"; export { call, view, + initialize, NearBindgen, - NearContract, near, LookupMap, Vector, diff --git a/src/near-bindgen.ts b/src/near-bindgen.ts index 855433747..4482e22f6 100644 --- a/src/near-bindgen.ts +++ b/src/near-bindgen.ts @@ -1,26 +1,41 @@ -export function call (target: Object, key: string | symbol, descriptor: TypedPropertyDescriptor): void { +import * as near from "./api"; + +export function initialize(target: Object, key: string | symbol, descriptor: TypedPropertyDescriptor): void { +} + +export function call(target: Object, key: string | symbol, descriptor: TypedPropertyDescriptor): void { } -export function view (target: Object, key: string | symbol, descriptor: TypedPropertyDescriptor): void { +export function view(target: Object, key: string | symbol, descriptor: TypedPropertyDescriptor): void { } -export function NearBindgen(target: T) { +export function NearBindgen(target: T) { return class extends target { - static _init() { - // @ts-ignore - let args = target.deserializeArgs() - let ret = new target(args) - // @ts-ignore - ret.init() - // @ts-ignore - ret.serialize() - return ret + static _create() { + return new target(); + } + + static _getState(): Object { + const rawState = near.storageRead("STATE"); + return rawState ? this._deserialize(rawState) : null; + } + + static _saveToStorage(): void { + near.storageWrite("STATE", this._serialize(this)); + } + + static _getArgs(): JSON { + return JSON.parse(near.input() || "{}"); } - static _get() { - let ret = Object.create(target.prototype) - return ret + static _serialize(value: Object): string { + return JSON.stringify(value); + } + + static _deserialize(value: string): Object { + return JSON.parse(value); } } } + diff --git a/src/near-contract.ts b/src/near-contract.ts deleted file mode 100644 index 76afcb31c..000000000 --- a/src/near-contract.ts +++ /dev/null @@ -1,38 +0,0 @@ -import * as near from "./api"; - -export abstract class NearContract { - deserialize() { - const rawState = near.storageRead("STATE"); - if (rawState) { - const state = JSON.parse(rawState) - // reconstruction of the contract class object from plain object - let c = this.default() - Object.assign(this, state); - for (const item in c) { - if (c[item].constructor?.deserialize !== undefined) { - this[item] = c[item].constructor.deserialize(this[item]) - } - } - } else { - throw new Error("Contract state is empty"); - } - } - - serialize() { - near.storageWrite("STATE", JSON.stringify(this)); - } - - static deserializeArgs(): any { - let args = near.input(); - return JSON.parse(args || "{}"); - } - - static serializeReturn(ret: any) { - return JSON.stringify(ret); - } - - // needed for deserialization of the contract class object from plain object - abstract default() - - init(): any {} -}