diff --git a/lib/build-tools/near-bindgen-exporter.d.ts b/lib/build-tools/near-bindgen-exporter.d.ts index ac80da65c..2623a9660 100644 --- a/lib/build-tools/near-bindgen-exporter.d.ts +++ b/lib/build-tools/near-bindgen-exporter.d.ts @@ -1,5 +1,4 @@ export default function _default(): { - visitor: { - ClassDeclaration(path: any): void; - }; + /** @type {import('@babel/traverse').Visitor} */ + visitor: import('@babel/traverse').Visitor; }; diff --git a/lib/build-tools/near-bindgen-exporter.js b/lib/build-tools/near-bindgen-exporter.js index c58821083..b2f3aa76b 100644 --- a/lib/build-tools/near-bindgen-exporter.js +++ b/lib/build-tools/near-bindgen-exporter.js @@ -1,3 +1,4 @@ +"use strict"; import * as t from "@babel/types"; const methodTypes = ["call", "view", "initialize"]; function throwError(message) { @@ -56,61 +57,60 @@ function executePromise(classId) { t.callExpression(t.memberExpression(classId, t.identifier("_serialize")), [t.identifier("_result"), t.booleanLiteral(true)]), ])))); } +function createDeclaration(classId, methodName, methodType) { + return t.exportNamedDeclaration(t.functionDeclaration(t.identifier(methodName), [], t.blockStatement([ + // Read the state of the contract from storage. + // const _state = Counter._getState(); + readState(classId), + // Throw if initialized on any subsequent init function calls. + // if (_state) { throw new Error('Contract already initialized'); } + preventDoubleInit(methodType), + // Throw if NOT initialized on any non init function calls. + // if (!_state) { throw new Error('Contract must be initialized'); } + ensureInitBeforeCall(classId, methodType), + // Create instance of contract by calling _create function. + // let _contract = Counter._create(); + initializeContractClass(classId), + // Reconstruct the contract with the state if the state is valid. + // if (_state) { Counter._reconstruct(_contract, _state); } + reconstructState(classId, methodType), + // Collect the arguments sent to the function. + // const _args = Counter._getArgs(); + collectArguments(classId), + // Perform the actual function call to the appropriate contract method. + // const _result = _contract.method(args); + callContractMethod(methodName), + // If the method called is either an initialize or call method type, save the changes to storage. + // Counter._saveToStorage(_contract); + saveToStorage(classId, methodType), + // If a NearPromise is returned from the function call the onReturn method to execute the promise. + // if (_result !== undefined) + // if (_result && _result.constructor && _result.constructor.name === 'NearPromise') + // _result.onReturn(); + // else + // near.valueReturn(_contract._serialize(result)); + executePromise(classId), + ]))); +} export default function () { return { + /** @type {import('@babel/traverse').Visitor} */ visitor: { ClassDeclaration(path) { const classNode = path.node; if (classNode.decorators && classNode.decorators[0].expression.callee.name === "NearBindgen") { - const classId = classNode.id; - const contractMethods = {}; - for (let child of classNode.body.body) { + classNode.body.body.forEach((child) => { if (child.type === "ClassMethod" && child.kind === "method" && child.decorators) { const methodType = child.decorators[0].expression.callee.name; if (methodTypes.includes(methodType)) { - contractMethods[child.key.name] = methodType; + path.insertAfter(createDeclaration(classNode.id, child.key.name, methodType)); + console.log(`Babel ${child.key.name} method export done`); } } - } - for (let methodName of Object.keys(contractMethods)) { - path.insertAfter(t.exportNamedDeclaration(t.functionDeclaration(t.identifier(methodName), [], t.blockStatement([ - // Read the state of the contract from storage. - // const _state = Counter._getState(); - readState(classId), - // Throw if initialized on any subsequent init function calls. - // if (_state) { throw new Error('Contract already initialized'); } - preventDoubleInit(contractMethods[methodName]), - // Throw if NOT initialized on any non init function calls. - // if (!_state) { throw new Error('Contract must be initialized'); } - ensureInitBeforeCall(classId, contractMethods[methodName]), - // Create instance of contract by calling _create function. - // let _contract = Counter._create(); - initializeContractClass(classId), - // Reconstruct the contract with the state if the state is valid. - // if (_state) { Counter._reconstruct(_contract, _state); } - reconstructState(classId, contractMethods[methodName]), - // Collect the arguments sent to the function. - // const _args = Counter._getArgs(); - collectArguments(classId), - // Perform the actual function call to the appropriate contract method. - // const _result = _contract.method(args); - callContractMethod(methodName), - // If the method called is either an initialize or call method type, save the changes to storage. - // Counter._saveToStorage(_contract); - saveToStorage(classId, contractMethods[methodName]), - // If a NearPromise is returned from the function call the onReturn method to execute the promise. - // if (_result !== undefined) - // if (_result && _result.constructor && _result.constructor.name === 'NearPromise') - // _result.onReturn(); - // else - // near.valueReturn(_contract._serialize(result)); - executePromise(classId), - ])))); - console.log(`Babel ${methodName} method export done`); - } + }); } }, }, diff --git a/lib/near-bindgen.d.ts b/lib/near-bindgen.d.ts index 14d66f979..c0f9c4bcf 100644 --- a/lib/near-bindgen.d.ts +++ b/lib/near-bindgen.d.ts @@ -1,12 +1,12 @@ declare type EmptyParameterObject = Record; declare type AnyObject = Record; -declare type AnyFunction = (...args: unknown[]) => unknown; -export declare function initialize(_empty: EmptyParameterObject): (_target: unknown, _key: string | symbol, _descriptor: TypedPropertyDescriptor) => void; +declare type DecoratorFunction = any>(target: object, key: string | symbol, descriptor: TypedPropertyDescriptor) => void; +export declare function initialize(_empty: EmptyParameterObject): DecoratorFunction; +export declare function view(_empty: EmptyParameterObject): DecoratorFunction; export declare function call({ privateFunction, payableFunction, }: { privateFunction?: boolean; payableFunction?: boolean; -}): (_target: unknown, _key: string | symbol, descriptor: TypedPropertyDescriptor) => void; -export declare function view(_empty: EmptyParameterObject): (_target: unknown, _key: string | symbol, _descriptor: TypedPropertyDescriptor) => void; +}): DecoratorFunction; export declare function NearBindgen({ requireInit, serializer, deserializer, }: { requireInit?: boolean; serializer?(value: unknown): string; diff --git a/lib/near-bindgen.js b/lib/near-bindgen.js index 77e617e54..144f321e2 100644 --- a/lib/near-bindgen.js +++ b/lib/near-bindgen.js @@ -1,18 +1,19 @@ import * as near from "./api"; import { deserialize, serialize } from "./utils"; -// type DecoratorFunction = ( -// target: AnyObject, -// key: string | symbol, -// descriptor: TypedPropertyDescriptor -// ) => void; export function initialize(_empty) { - /* eslint-disable @typescript-eslint/no-empty-function */ - return function (_target, _key, _descriptor) { }; - /* eslint-enable @typescript-eslint/no-empty-function */ + return function (_target, _key, _descriptor + // eslint-disable-next-line @typescript-eslint/no-empty-function + ) { }; +} +export function view(_empty) { + return function (_target, _key, _descriptor + // eslint-disable-next-line @typescript-eslint/no-empty-function + ) { }; } export function call({ privateFunction = false, payableFunction = false, }) { return function (_target, _key, descriptor) { const originalMethod = descriptor.value; + // @ts-ignore descriptor.value = function (...args) { if (privateFunction && near.predecessorAccountId() !== near.currentAccountId()) { @@ -25,11 +26,6 @@ export function call({ privateFunction = false, payableFunction = false, }) { }; }; } -export function view(_empty) { - /* eslint-disable @typescript-eslint/no-empty-function */ - return function (_target, _key, _descriptor) { }; - /* eslint-enable @typescript-eslint/no-empty-function */ -} export function NearBindgen({ requireInit = false, serializer = serialize, deserializer = deserialize, }) { // eslint-disable-next-line @typescript-eslint/no-explicit-any return (target) => { diff --git a/src/build-tools/near-bindgen-exporter.js b/src/build-tools/near-bindgen-exporter.js index 42b3a6808..f2a730ce9 100644 --- a/src/build-tools/near-bindgen-exporter.js +++ b/src/build-tools/near-bindgen-exporter.js @@ -1,3 +1,4 @@ +"use strict"; import * as t from "@babel/types"; const methodTypes = ["call", "view", "initialize"]; @@ -165,8 +166,51 @@ function executePromise(classId) { ); } +function createDeclaration(classId, methodName, methodType) { + return t.exportNamedDeclaration( + t.functionDeclaration( + t.identifier(methodName), + [], + t.blockStatement([ + // Read the state of the contract from storage. + // const _state = Counter._getState(); + readState(classId), + // Throw if initialized on any subsequent init function calls. + // if (_state) { throw new Error('Contract already initialized'); } + preventDoubleInit(methodType), + // Throw if NOT initialized on any non init function calls. + // if (!_state) { throw new Error('Contract must be initialized'); } + ensureInitBeforeCall(classId, methodType), + // Create instance of contract by calling _create function. + // let _contract = Counter._create(); + initializeContractClass(classId), + // Reconstruct the contract with the state if the state is valid. + // if (_state) { Counter._reconstruct(_contract, _state); } + reconstructState(classId, methodType), + // Collect the arguments sent to the function. + // const _args = Counter._getArgs(); + collectArguments(classId), + // Perform the actual function call to the appropriate contract method. + // const _result = _contract.method(args); + callContractMethod(methodName), + // If the method called is either an initialize or call method type, save the changes to storage. + // Counter._saveToStorage(_contract); + saveToStorage(classId, methodType), + // If a NearPromise is returned from the function call the onReturn method to execute the promise. + // if (_result !== undefined) + // if (_result && _result.constructor && _result.constructor.name === 'NearPromise') + // _result.onReturn(); + // else + // near.valueReturn(_contract._serialize(result)); + executePromise(classId), + ]) + ) + ); +} + export default function () { return { + /** @type {import('@babel/traverse').Visitor} */ visitor: { ClassDeclaration(path) { const classNode = path.node; @@ -175,10 +219,7 @@ export default function () { classNode.decorators && classNode.decorators[0].expression.callee.name === "NearBindgen" ) { - const classId = classNode.id; - const contractMethods = {}; - - for (let child of classNode.body.body) { + classNode.body.body.forEach((child) => { if ( child.type === "ClassMethod" && child.kind === "method" && @@ -187,55 +228,14 @@ export default function () { const methodType = child.decorators[0].expression.callee.name; if (methodTypes.includes(methodType)) { - contractMethods[child.key.name] = methodType; + path.insertAfter( + createDeclaration(classNode.id, child.key.name, methodType) + ); + + console.log(`Babel ${child.key.name} method export done`); } } - } - - for (let methodName of Object.keys(contractMethods)) { - path.insertAfter( - t.exportNamedDeclaration( - t.functionDeclaration( - t.identifier(methodName), - [], - t.blockStatement([ - // Read the state of the contract from storage. - // const _state = Counter._getState(); - readState(classId), - // Throw if initialized on any subsequent init function calls. - // if (_state) { throw new Error('Contract already initialized'); } - preventDoubleInit(contractMethods[methodName]), - // Throw if NOT initialized on any non init function calls. - // if (!_state) { throw new Error('Contract must be initialized'); } - ensureInitBeforeCall(classId, contractMethods[methodName]), - // Create instance of contract by calling _create function. - // let _contract = Counter._create(); - initializeContractClass(classId), - // Reconstruct the contract with the state if the state is valid. - // if (_state) { Counter._reconstruct(_contract, _state); } - reconstructState(classId, contractMethods[methodName]), - // Collect the arguments sent to the function. - // const _args = Counter._getArgs(); - collectArguments(classId), - // Perform the actual function call to the appropriate contract method. - // const _result = _contract.method(args); - callContractMethod(methodName), - // If the method called is either an initialize or call method type, save the changes to storage. - // Counter._saveToStorage(_contract); - saveToStorage(classId, contractMethods[methodName]), - // If a NearPromise is returned from the function call the onReturn method to execute the promise. - // if (_result !== undefined) - // if (_result && _result.constructor && _result.constructor.name === 'NearPromise') - // _result.onReturn(); - // else - // near.valueReturn(_contract._serialize(result)); - executePromise(classId), - ]) - ) - ) - ); - console.log(`Babel ${methodName} method export done`); - } + }); } }, }, diff --git a/src/near-bindgen.ts b/src/near-bindgen.ts index 602b1c66a..2217bc728 100644 --- a/src/near-bindgen.ts +++ b/src/near-bindgen.ts @@ -3,21 +3,28 @@ import { deserialize, serialize } from "./utils"; type EmptyParameterObject = Record; type AnyObject = Record; -type AnyFunction = (...args: unknown[]) => unknown; -// type DecoratorFunction = ( -// target: AnyObject, -// key: string | symbol, -// descriptor: TypedPropertyDescriptor -// ) => void; - -export function initialize(_empty: EmptyParameterObject) { - /* eslint-disable @typescript-eslint/no-empty-function */ - return function ( - _target: unknown, +type DecoratorFunction = any>( + target: object, + key: string | symbol, + descriptor: TypedPropertyDescriptor +) => void; + +export function initialize(_empty: EmptyParameterObject): DecoratorFunction { + return function any>( + _target: object, _key: string | symbol, - _descriptor: TypedPropertyDescriptor + _descriptor: TypedPropertyDescriptor + // eslint-disable-next-line @typescript-eslint/no-empty-function + ): void {}; +} + +export function view(_empty: EmptyParameterObject): DecoratorFunction { + return function any>( + _target: object, + _key: string | symbol, + _descriptor: TypedPropertyDescriptor + // eslint-disable-next-line @typescript-eslint/no-empty-function ): void {}; - /* eslint-enable @typescript-eslint/no-empty-function */ } export function call({ @@ -26,39 +33,34 @@ export function call({ }: { privateFunction?: boolean; payableFunction?: boolean; -}) { - return function ( - _target: unknown, +}): DecoratorFunction { + return function any>( + _target: object, _key: string | symbol, - descriptor: TypedPropertyDescriptor + descriptor: TypedPropertyDescriptor ): void { const originalMethod = descriptor.value; - descriptor.value = function (...args: unknown[]) { + // @ts-ignore + descriptor.value = function ( + ...args: Parameters + ): ReturnType { if ( privateFunction && near.predecessorAccountId() !== near.currentAccountId() ) { - throw Error("Function is private"); + throw new Error("Function is private"); } - if (!payableFunction && near.attachedDeposit() > BigInt(0)) { - throw Error("Function is not payable"); + + if (!payableFunction && near.attachedDeposit() > 0n) { + throw new Error("Function is not payable"); } + return originalMethod.apply(this, args); }; }; } -export function view(_empty: EmptyParameterObject) { - /* eslint-disable @typescript-eslint/no-empty-function */ - return function ( - _target: unknown, - _key: string | symbol, - _descriptor: TypedPropertyDescriptor - ): void {}; - /* eslint-enable @typescript-eslint/no-empty-function */ -} - export function NearBindgen({ requireInit = false, serializer = serialize,