assemblyscript
assemblyscript copied to clipboard
How to make function decorator with transfrom?
Hello,
I am trying to write a transform class for custom function decoration.
What I want is to take this:
@handler
export function handle(Request req): Response {}
And turn it into something like:
import {processRequest} from 'sdk';
// Ideally name handle to something like inner_handler and remove export just in case
export function handle(requestPtr: usize, requestSize: usize): usize {
processRequest(requestPtr: usize, requestSize: usize, inner_handler);
}
Basically:
- Transform should remove
export
fromhandle
- Rename
handle
to sayinner_handle
- add a simple wrapper function which will import request data from the host
- Call decorated function with the new
inner_handle
name - Export wrapper function instead of the one user wrote.
It is tough to find any information online. Can you recommend any examples or a small code snippet? The way I see it:
- Find decorated FucntionPrototype
- Rename it and remove the export flag
- Add a new FunctionPrototype with the body I need
- Add this prototype to the body.
There are some helper lib (however a little bit outdated) with useful examples: https://github.com/willemneal/visitor-as
I hope this helps
Thanks @MaxGraey ! But to be honest not so much. I was able to find the element I did which I assume this library helping with? Like so:
afterInitialize(program) {
program.elementsByName.forEach((el) => {
if (!(el instanceof FunctionPrototype)) {
return;
}
if (!this.hasDecorator(el, 'handler')) {
return;
}
But now, it is not clear how can to inject the code I need into the program. I checked as-json sources but they adding new method to decorated class while I need to inject a function into program and modify they one which is decorated.
For your case you should use afterParse(parser) {...}
and manipulate with AST
Github has a lot of examples. Ask project for example: https://github.com/ask-lang/ask/blob/main/ts-packages/transform/src/visitors/transform.ts#L207
Thanks a lot @MaxGraey it seems I am getting close!
This works (not sure if it's the best way to do it but it works):
import { ClassPrototype, IdentifierExpression } from "assemblyscript"
import { Transform } from "assemblyscript/transform"
let decoratorCallbacks = {}
function processDecorators(program) {
program.elementsByName.forEach((element) => {
if (!(element instanceof ClassPrototype)) return
if (!element.decoratorNodes) return
// Loop over all the decorators
for (const node of element.decoratorNodes) {
if (!(node.name instanceof IdentifierExpression)) continue
const name = node.name.text
if (decoratorCallbacks[name]) {
decoratorCallbacks[name](element)
}
}
})
}
decoratorCallbacks["reverse"] = function (element) {
console.log("Reversing", element.name)
element.instanceMembers = new Map(Array.from(element.instanceMembers).reverse())
}
class MyTransform extends Transform {
afterInitialize (program) {
processDecorators(program)
}
}
export default MyTransform
This is for classes but it should hopefully by useful
This issue has been automatically marked as stale because it has not had recent activity. It will be closed in one week if no further activity occurs. Thank you for your contributions!
@Umenokin did you figure this out in the end?