Giter VIP home page Giter VIP logo

typescript-transformer-handbook's People

Contributors

abraham avatar bendtherules avatar dependabot[bot] avatar itsdouges avatar madou avatar marionebl avatar oscard0m avatar rifler avatar tmcw avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

typescript-transformer-handbook's Issues

How can I share a custom argument from a user's `tsconfig.json` to my custom plugin?

How can I share a custom argument from a user's tsconfig.json to my custom plugin?

To install a plugin we do:

{
  "compilerOptions": {
    "plugins": [
      {
        "name": "typescript-my-plugin"
      }
    ]
  }
}

I would love to be able to write something akin to:

{
  "compilerOptions": {
    "plugins": [
      {
        "name": "typescript-my-plugin",
        "foo": "bar",
        "options": ["verbose", "production"]
      }
    ]
  }
}

or even

{
  "compilerOptions": {
    "plugins": [
      {
        "name": "typescript-my-plugin"
      }
    ],
    "foo": "bar",
    "options": ["verbose", "production"]
  }
}

I checked the Intro to the TSConfig Reference without finding what I was looking for.

I also posted this question on Stack Overflow: https://stackoverflow.com/questions/71255330/how-can-i-share-a-custom-argument-from-a-users-tsconfig-json-to-my-custom-plu

Usage question: Changing type checking of operators

I'm frequently working with symbolic mathematical expressions. Sadly, JavaScript doesn't support operator overloading, so I have to write a lot of ugly code like add(u, mul(2, v)). I would love to make a transformer that changes operators into function calls:

u + 2*v   โ†’  op_add( u, op_mul(2, v) )

This transformation alone is quite easy, I just have to find BinaryExpression(A, op, B) and turn it into CallExpression(fn, [A, B]). However I would love to use the type checking of the resulting function. In the handbook you say that:

โ€œType checking should not happen after transforming. If it does it's more than likely a bug - file an issue!โ€

Does this mean that my transformed code will still be type-checked as if it were a + b, not op_add(a, b)? Or is it just a misunderstanding on my side?

Thanks!

Question: Advanced - Following module imports

First of all; thanks for the handbook; I really appreciate it. Great work.

In the section Advanced - Following module imports you write the following:

You can also traverse the imported node as well using ts.visitChild and the like.

I really would like to know how this could be achieved. I do not understand how I get the imported node and how I can traverse it then.

As a matter of fact I would like to achieve the following:

  • I would like to finde a function call like e.g. transform(PlaygroundComponent)
  • And then I would like to find the corresponding class PlaygroundComponent (maybe imported from another file and adjust it)

I would appreciate any help. Thanks. :)

Question ts-creator

You are mentioning the following tipp:

Tip - Use ts-creator to quickly get factory functions for a piece of TypeScript source - instead of meticulously writing out an AST for a node you can write a code string and have it converted to AST for you.

Could you provide an example for e.g. inserting a node with ts-creator.

Can I determine if a class extends a class that extends class X

Is there a way to determine if a class inherits (indirectly) from another class X. I understand that I can read the heritage clause or that I can ask the type checker for the base type. But this does not seem to work recursively. I am so far only able to extract the direct parent and it seems that I would have to walk the tree two times: first to build up my class inheritance tree and second to check if a node represents a class that extends (indirectly) my class X.

Question: Can I use built-in typescript transformers?

I need to transform ES6 syntax into ES5 but keep types. So I need TypeScript ES6 to TypeScript ES5 transformer (not JS).
ts.transpile() strips all the types and essentially outputs JS (which is not what I need).
Can I use built-in typescript transformers to achieve this?

Usage question: Modify class prototype

Hi again!

I am wondering if it is possible to adjust the prototype of a class declaration? E.g. add specific properties? If anyone has an idea I would really appreciate it.

Thanks in advance.
Greets, Lukas

Improvements

General discussion about what more to add and todo items -

TODO items -

  • Check if an identifier is referenced
  • Is there a way to completely halt traversal?
  • Replacing a node with multiple nodes
  • Inserting a sibling node
  • Pushing a variable declaration to a parent scope
  • Checking if a local variable is referenced (i think we can use symbols for this?)
  • Rename a binding and its references
  • Evaluating expressions
  • Throwing a syntax error to ease the developer experience
  • Following imports when type checking is disabled

To align remove-node example with README.md

Problem

When running remove-node transformer example, the generated file with transformed code does not match with the README.md documentation

How to reproduce it

ttsc under example-transformers/remove-node

Solution

To use return undefined instead of ts.createEmptyStatement();

Usage question: Following imports

Hello,

I've been trying to implement the following imports section this so I can get all interface types from all files.
The currently example seems to be broken since using it results the following line in returning undefined:
const importSymbol = typeChecker.getSymbolAtLocation(node.moduleSpecifier);

Now my question is I've got the following code:

interface TestComponent extends Component {

}

interface TestComponent3 extends Component {

}

interface TestComponent2 extends TestComponent3 {

}

interface TestEntity extends TestComponent, Entity, TestComponent2 {

}

const testEntity: TestEntity = {}

I want to inject all interface types from all files in the testEntity constant.
It's correctly working for the current file now but it does not seem to follow any imports.
I've wasted hours trying to get the imported sourceFile AST but I can't seem to get it to work.

Any advice?

Thanks in advance!

Usage question: Adding new import declarations

Hey!

Once again I would like first of all to say that I really appreciate this repository and the provided examples. E.g. the example regarding Adding new import declarations.

Although I have a question regarding this topic. Let's assume I have the following class:

export class TestComponent {
    public greet(): string {
        return "Hello";
    }
}

The builded file with my custom TypeScript Transformer in place looks like this:

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var TestComponent = /** @class */ (function () {
    function TestComponent() {
    }
    TestComponent.prototype.greet = function () {
        return jasmine.createSpy().and.callFake(function () {
            if (!Ttransformer.isInTransformContext()) {
                return "Hello";
            }
        });
    };
    return TestComponent;
}());
exports.TestComponent = TestComponent;
//# sourceMappingURL=test.component.js.map

I would like to add an import statement to provide the Ttransformer class. Therefore I adjusted my transformer to do so. The output looks now like this:

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

// === THE FOLLOWING LINE WAS ADDED NOW ===
var ttransformer_1 = require("../ttransformer"); 
 
var TestComponent = /** @class */ (function () {
    function TestComponent() {
    }
    TestComponent.prototype.greet = function () {
        return jasmine.createSpy().and.callFake(function () {
            if (!Ttransformer.isInTransformContext()) {
                return "Hello";
            }
        });
    };
    return TestComponent;
}());
exports.TestComponent = TestComponent;
//# sourceMappingURL=test.component.js.map

I am really wondering if the resulting source code is correct. If I already import the class in the first place, like in this example...

import { Ttransformer } from "../ttransformer";
Ttransformer.isInTransformContext();

...the ouptut looks like this:

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var ttransformer_1 = require("../ttransformer");
ttransformer_1.Ttransformer.isInTransformContext();
//# sourceMappingURL=source.dev.js.map

The actual difference is shown here:

  1. Ttransformer.isInTransformContext()
    vs.
  2. ttransformer_1.Ttransformer.isInTransformContext();

Do I have to make sure in my custom transformer that ttransformer_1 get's added? I would have imagined that this happens automatically. As I said; I really like the provided example; but I am wondering how it would look like if you would try to use the actual import. Do you know what I mean?

I appreciate any thoughts, ideas and explanation. Thanks in advance.

Greets, Lukas

General question with focus on bindings

Hey!

I have a really general question which I need to ask providing an example.

Let's assume we add some kind of function with the typescript transformer. - function whatever() {}
And then I would like to use this function somewhere else, like whatever().

Should this work or would I have to consider something regarding bindings?

E.g. what's the point of adding import statements if the stuff imported can't be used. Or am I missing something here?

Thanks in advance.

TRANSLATIONS WANTED

If you have ideas of how we can get this translated to as much languages as possible - please chime in!

Usage question: Adding a child node

Hello again!

Sorry for using this channel again asking a general usage question. But I really appreciated your help the last time.

How can I or how would you add a child node to a given node?

E.g. add static instances = []; to class Test {}.

I know that I can find the class declaration with ts.isClassDeclaration(node) but how would you proceed then?

Do I really have to provide a new class declaration node (like in the code snippet) or is there a more "elegant" way?

if (ts.isClassDeclaration(node) {
   // createInstancesProperty ==> custom fn to create "static instances = [];"
   const extendedMembers = ts.createNodeArray([createInstancesProperty(symbol.name), ...node.members]);
   return ts.createClassDeclaration(node.decorators, node.modifiers, node.name, node.typeParameters, node.heritageClauses, extendedMembers);

}

I am wondering what's the best approach if I would like to do something (on) ...

  1. Add a static property to the class || e.g. static instances = [];

  2. ts.isConstructorDeclaration

  • add content to the constructor if there is one || e.g. ClassName.instances.push(this)
  • add the constructor and the content if there is none
  1. ts.isMethodDeclaration

  2. ts.isPropertyDeclaration

I really enjoy using the visitor pattern approach but I do not know how to use it in combination with my desired tasks 1) and 2).

Any help appreciated. Thanks in advance.

Question: Replacing a call expression with multiple nodes

Hey, I want to replace a call expression ( someFn() ) with multiple nodes (a NodeArray full with statements), but I'm getting the error:

Error: Debug Failure. False expression: Too many nodes written to output.

How can I make it work? The call expression itself comes from an ExpressionStatement. Also, I'd like to replace the call expression with statements, ex. (const a = 5).

Is there any way to ignore errors like that, I'm attempting to write a macro system in TS, but these errors are stopping me.

Usage question: Modifying Nodes & Symbols

Hey!

Let's assume that I want to modify specific classes with my custom typescript transformer. The actual use case does not matter for this question but e.g. changing all method declarations to property declarations.

Therefore I collect all the targeted class declaration symbols before the actual transformation starts. I already achieved this. Therefore I do not want to get into detail here. Just assume that there is an array of symbols representing the transformer targets - class declaration symbols.

With this setup I can do something like the following in my visitor:

if (ts.isClassDeclaration(node) && isTransformerTarget(node)) {
   if (ts.isMethodDeclaration(node)) {
      // return new property declaration instead
   }
}

Now asking the actual question: Does the symbol of the class declaration change after modify the corresponding class declaration?

I am asking because my setup gets a little bit more specific: I am composing multiple transformers like explained in the handbook. And actually I am doing a similar thing in the next transformer. The real use case does not matter again. But for the sake of the example let's assume modifying the constructor of the class declaration with the next transformer.

if (ts.isClassDeclaration(node) && isTransformerTarget(node)) {
   if (ts.isConstructorDeclaration(node)) {
      // add something to the constructor and return the updated node 
   }
}

Here the previously asked question gets visible for me. I am not able to enter the first if-statement anymore. Exploring my source code lead me to the assumption that the symbol must have changed after applying the first transformer. Therefore the function isTransformerTarget(node) would return false now. This is maybe responsible for not entering the block anymore. Do do know what I mean?

Therefore again summarizing the actual questions:

  • Does the symbol of a node change after modifying the corresponding node (or children)?
  • Would there be a way to prevent this? E.g. I would assume that functions like ts.updateClassDeclaration would not change the symbol? Or does it make sense that the symbol changes and a check like symbol1 === symbol2 does not succeed anymore? I maybe would guess so.
  • But is it simply wrong then to compare the whole symbol in my custom function isTransformerTarget - like symbol1 === symbol2. I saw that this was done in the transformer handbook. Therefore I also tried this approach. Maybe I just have to compare a property indicating uniqueness of the symbol - like id. Any thoughts/ideas on this?

Hopefully my explanation and questions make any sense. I would appreciate any thoughts on this topic considering symbols.

Thanks in advance,
Lukas

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.