cevek / ttypescript

Over TypeScript tool to use custom transformers in the tsconfig.json
1.53k stars 56 forks source link

How to change source code of emitted helpers? #124

Closed wehrstedt closed 3 years ago

wehrstedt commented 3 years ago

Hi everyone. Does anybody know how to change the source code of the emitted helpers? e. g. a for of loop with downlevelIteration will result in the following helper function:

const array = ["1","2"];
for (var elem of array) {
    console.log(elem);
}

will output:

"use strict";
var __values = (this && this.__values) || function(o) {
    var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
    if (m) return m.call(o);
    if (o && typeof o.length === "number") return {
        next: function () {
            if (o && i >= o.length) o = void 0;
            return { value: o && o[i++], done: !o };
        }
    };
    throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
};
var e_1, _a;
var array = ["1", "2"];
try {
    for (var array_1 = __values(array), array_1_1 = array_1.next(); !array_1_1.done; array_1_1 = array_1.next()) {
        var elem = array_1_1.value;
        console.log(elem);
    }
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
    try {
        if (array_1_1 && !array_1_1.done && (_a = array_1.return)) _a.call(array_1);
    }
    finally { if (e_1) throw e_1.error; }
}

What i need to change is to remove (this && this.__values) || from the variable declaration, because in my execution envirenment accessing this in the global scope will result immediatelly in an exception. But i need downlevel-iteration and ES5 as a target for other reasons...

thanks for any help!

nonara commented 3 years ago

You can use an "after" transformer to work with the post compiled js code.

wehrstedt commented 3 years ago

what type do i have to specify? My current config looks like this:

{
        "transform": "../src/transformer.ts",
        "type": "raw",
        "after": true
}

but the code passed to the transformer does not contains the emitted helper function. It seems like the transformer runs before that happens

nonara commented 3 years ago

What's the output of ts.createPrinter().printFile(sourceFile); for that file?

wehrstedt commented 3 years ago

hmm ... that is actually the expected output:

"use strict";
var __values = (this && this.__values) || function(o) {
    var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
    if (m) return m.call(o);
    if (o && typeof o.length === "number") return {
        next: function () {
            if (o && i >= o.length) o = void 0;
            return { value: o && o[i++], done: !o };
        }
    };
    throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
};
var e_1, _a;
var array = ["1", "2"];
try {
    for (var array_1 = __values(array), array_1_1 = array_1.next(); !array_1_1.done; array_1_1 = array_1.next()) {
        var elem = array_1_1.value;
        console.log(elem);
    }
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
    try {
        if (array_1_1 && !array_1_1.done && (_a = array_1.return)) _a.call(array_1);
    }
    finally { if (e_1) throw e_1.error; }
}

This is my transformer, without any implementation:

const transformer: ts.TransformerFactory<ts.SourceFile> = (context) => {
    return (sourceFile) => {
        console.log(ts.createPrinter().printFile(sourceFile));
        const visitor = (node: ts.Node): ts.Node => {
                        // do stuff here ..

            return ts.visitEachChild(node, visitor, context);
        };

        return ts.visitNode(sourceFile, visitor);
    };
};
nonara commented 3 years ago

Sounds like you're on the right track. I would debug and inspect the nodes. If you want to setup a repository I can clone with your scenario, I'll take a look.

wehrstedt commented 3 years ago

Absolutely, thank you. I created a repository with current work here: https://github.com/wehrstedt/ts-transformer-scripting You can e. g. debug the code with the vs code debug terminal and running yarn test

wehrstedt commented 3 years ago

my first guess is that the visitor does not visit the emitted helper functions. I can't find any that referes to the helper function.

wehrstedt commented 3 years ago

found a workaround which seems to work for me now. I added "importHelpers": true to my tsconfig. This will cause typescript to import the helper functions from module tslib. I can now implement this module in my environment by implement the neccessary helper functions. Not what I initialy asked for, but it works

nonara commented 3 years ago

That's interesting. Looks like you're right. It must do its final transforms after the after. Anyway, glad you found a workable route.

The alternative would be to use a Program transformer via ts-patch

wehrstedt commented 3 years ago

Maybe i will give it a try. It seems like the option importHelper does not be applied on all source files. I have two source files with a for of loop. In one source file, typescript imports tslib, in the other source file typescript still emits the helper function. But thats probably a bug or a misconfiguration in typescript. Anyway, thanks for your help!