Skip to content

Commit 04717e5

Browse files
authored
Merge pull request #263 from petarvujovic98/develop
[RFC] feat: Middlewares addition
2 parents fd6db41 + 3672a68 commit 04717e5

File tree

12 files changed

+268
-15
lines changed

12 files changed

+268
-15
lines changed

lib/build-tools/near-bindgen-exporter.js

Lines changed: 5 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/cli/cli.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/cli/utils.js

Lines changed: 7 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/near-bindgen.d.ts

Lines changed: 17 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/near-bindgen.js

Lines changed: 23 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/build-tools/near-bindgen-exporter.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import { PluginPass } from "@babel/core";
22
import { Node, Visitor } from "@babel/traverse";
33
import * as t from "@babel/types";
4+
import signal from "signale";
5+
6+
const { Signale } = signal;
47

58
/**
69
* A list of supported method types/decorators.
@@ -388,7 +391,9 @@ export default function (): { visitor: Visitor } {
388391
);
389392

390393
if (verbose) {
391-
console.log(`Babel ${child.key.name} method export done`);
394+
new Signale({
395+
scope: "near-bindgen-exporter",
396+
}).info(`Babel ${child.key.name} method export done.`);
392397
}
393398
}
394399
}

src/cli/cli.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export async function buildCom(
4343
const TARGET_DIR = dirname(target);
4444
const TARGET_EXT = target.split(".").pop();
4545
const TARGET_FILE_NAME = basename(target, `.${TARGET_EXT}`);
46-
const signale = new Signale({ scope: "build", interactive: true });
46+
const signale = new Signale({ scope: "build", interactive: !verbose });
4747

4848
if (TARGET_EXT !== "wasm") {
4949
signale.error(
@@ -143,7 +143,9 @@ async function createMethodsHeaderFile(rollupTarget: string, verbose = false) {
143143
const buildPath = path.dirname(rollupTarget);
144144

145145
if (verbose) {
146-
console.log(rollupTarget);
146+
new Signale({scope: "method-header"}).info(
147+
rollupTarget
148+
)
147149
}
148150

149151
const mod = await import(`${PROJECT_DIR}/${rollupTarget}`);

src/cli/utils.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,35 @@
11
import childProcess from "child_process";
22
import { promisify } from "util";
3+
import signal from "signale"
4+
5+
const {Signale} = signal;
36

47
const exec = promisify(childProcess.exec);
58

69
export async function executeCommand(
710
command: string,
811
verbose = false
912
): Promise<string> {
13+
const signale = new Signale({scope: "exec", interactive: !verbose})
14+
1015
if (verbose) {
11-
console.log(command);
16+
signale.info(`Running command: ${command}`);
1217
}
1318

1419
try {
1520
const { stdout, stderr } = await exec(command);
1621

1722
if (stderr && verbose) {
18-
console.error(stderr);
23+
signale.error(stderr);
1924
}
2025

2126
if (verbose) {
22-
console.log(stdout);
27+
signale.info(`Command output: ${stdout}`);
2328
}
2429

2530
return stdout.trim();
2631
} catch (error) {
27-
console.log(error);
32+
signale.error(error);
2833
process.exit(1);
2934
}
3035
}

src/near-bindgen.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,50 @@ export function call({
8989
};
9090
}
9191

92+
/**
93+
* The interface that a middleware has to implement in order to be used as a middleware function/class.
94+
*/
95+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
96+
interface Middleware<Arguments extends Array<any>> {
97+
/**
98+
* The method that gets called with the same arguments that are passed to the function it is wrapping.
99+
*
100+
* @param args - Arguments that will be passed to the function - immutable.
101+
*/
102+
(...args: Arguments): void;
103+
}
104+
105+
/**
106+
* Tells the SDK to apply an array of passed in middleware to the function execution.
107+
*
108+
* @param middlewares - The middlewares to be executed.
109+
*/
110+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
111+
export function middleware<Arguments extends Array<any>>(
112+
...middlewares: Middleware<Arguments>[]
113+
): DecoratorFunction {
114+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
115+
return function <AnyFunction extends (...args: Arguments) => any>(
116+
_target: object,
117+
_key: string | symbol,
118+
descriptor: TypedPropertyDescriptor<AnyFunction>
119+
): void {
120+
const originalMethod = descriptor.value;
121+
122+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
123+
// @ts-ignore
124+
descriptor.value = function (...args: Arguments): ReturnType<AnyFunction> {
125+
try {
126+
middlewares.forEach((middleware) => middleware(...args));
127+
} catch (error) {
128+
throw new Error(error);
129+
}
130+
131+
return originalMethod.apply(this, args);
132+
};
133+
};
134+
}
135+
92136
/**
93137
* Extends this class with the methods needed to make the contract storable/serializable and readable/deserializable to and from the blockchain.
94138
* Also tells the SDK to capture and expose all view, call and initialize functions.
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import { Worker } from "near-workspaces";
2+
import test from "ava";
3+
4+
test.beforeEach(async (t) => {
5+
// Init the worker and start a Sandbox server
6+
const worker = await Worker.init();
7+
8+
// Prepare sandbox for tests, create accounts, deploy contracts, etx.
9+
const root = worker.rootAccount;
10+
11+
// Deploy the contract.
12+
const middlewares = await root.devDeploy("build/middlewares.wasm");
13+
14+
// Create the init args.
15+
const args = JSON.stringify({ randomData: "anything" });
16+
// Capture the result of the init function call.
17+
const result = await middlewares.callRaw(middlewares, "init", args);
18+
19+
// Extract the logs.
20+
const { logs } = result.result.receipts_outcome[0].outcome;
21+
// Create the expected logs.
22+
const expectedLogs = [`Log from middleware: ${args}`];
23+
24+
// Check for correct logs.
25+
t.deepEqual(logs, expectedLogs);
26+
27+
// Create test users
28+
const ali = await root.createSubAccount("ali");
29+
30+
// Save state for test runs
31+
t.context.worker = worker;
32+
t.context.accounts = { root, middlewares, ali };
33+
});
34+
35+
test.afterEach.always(async (t) => {
36+
await t.context.worker.tearDown().catch((error) => {
37+
console.log("Failed to tear down the worker:", error);
38+
});
39+
});
40+
41+
test("The middleware logs with call functions", async (t) => {
42+
const { ali, middlewares } = t.context.accounts;
43+
44+
// Create the arguments which will be passed to the function.
45+
const args = JSON.stringify({ id: "1", text: "hello" });
46+
// Call the function.
47+
const result = await ali.callRaw(middlewares, "add", args);
48+
// Extract the logs.
49+
const { logs } = result.result.receipts_outcome[0].outcome;
50+
// Create the expected logs.
51+
const expectedLogs = [`Log from middleware: ${args}`];
52+
53+
t.deepEqual(logs, expectedLogs);
54+
});
55+
56+
test("The middleware logs with view functions", async (t) => {
57+
const { ali, middlewares } = t.context.accounts;
58+
59+
// Create the arguments which will be passed to the function.
60+
const args = JSON.stringify({ id: "1", accountId: "hello" });
61+
// Call the function.
62+
const result = await ali.callRaw(middlewares, "get", args);
63+
// Extract the logs.
64+
const { logs } = result.result.receipts_outcome[0].outcome;
65+
// Create the expected logs.
66+
const expectedLogs = [`Log from middleware: ${args}`];
67+
68+
t.deepEqual(logs, expectedLogs);
69+
});
70+
71+
test("The middleware logs with two middleware functions", async (t) => {
72+
const { ali, middlewares } = t.context.accounts;
73+
74+
// Create the arguments which will be passed to the function.
75+
const args = JSON.stringify({ id: "1", accountId: "hello" });
76+
// Call the function.
77+
const result = await ali.callRaw(middlewares, "get_two", args);
78+
// Extract the logs.
79+
const { logs } = result.result.receipts_outcome[0].outcome;
80+
// Create the expected logs.
81+
const expectedLogs = [`Log from middleware: ${args}`, "Second log!"];
82+
83+
t.deepEqual(logs, expectedLogs);
84+
});
85+
86+
test("The middleware logs with private functions", async (t) => {
87+
const { ali, middlewares } = t.context.accounts;
88+
89+
// Create the arguments which will be passed to the function.
90+
const args = { id: "test", accountId: "tset" };
91+
// Call the function.
92+
const result = await ali.callRaw(middlewares, "get_private", "");
93+
// Extract the logs.
94+
const { logs } = result.result.receipts_outcome[0].outcome;
95+
// Create the expected logs.
96+
const expectedLogs = [`Log from middleware: ${args}`];
97+
98+
t.deepEqual(logs, expectedLogs);
99+
});

0 commit comments

Comments
 (0)