Is there a way to hook up to the TypeScript compiler and emit some custom JavaScript code based on the TypeScipt code model?

Topics: General
Jan 17, 2014 at 2:00 AM
I am wondering if I can somehow extend or hook up to the TypeScript compiler and generate some functions based on the declaration of the TypeScript interfaces in my code. Basically these functions would validate the data objects that are coming from the server to comply with the TypeScript interfaces the objects are supposed to implement. I was thinking to have a special interface-marker and I wish my hook to the compiler was triggered by such interface. Once that marker-interface is detected I would analyze the members of that interface and generate the code that would validate a given object against the data-contract defined by that interface. Is there a way to do that? Can anyone give some directions?
Jan 18, 2014 at 5:08 PM
I think if you dig around the code you'll find it pretty clear that the TS team has invested a lot of time and effort in making the compiler extensible and toolable.

I've been exploring the compiler and services in the last couple of months in my free time. I may be able to point you in the right direction(s), but I encourage you to take my advice with a grain of salt.

I think there are two different paths for accessing the model of your compiled code:

1) Creating an instance of TypeScriptCompiler directly and interacting with it
2) Obtaining an instance of ILanguageService and asking it questions about your code

I have only explored the second avenue, as I've been looking to create some IDE tools. The language service allows you to ask TypeScript interesting questions about code and it offers support for editing on-the-fly.

What I've done is implemented ILanguageServiceShimHost. With an instance of that, you can ask TypeScriptServicesFactory to create you a language service shim (ILanguageServiceShim).

Note that the language service shim has an instance of ILanguageService attached to it, and that instance will have some more methods than the shim.

You can call "addScript" on the service shim to add your code units. Once you've done that, you can interact with the language service and begin asking it questions. In my case, I need access to the syntax trees of my code units. The language service has a private instance of a TypeScriptCompiler. I am temporarily taking a trip to any-town and grabbing that private var (yuck!).

Maybe a TypeScript dev can answer this: Given a constructed and operational language service, what's the correct/best way to get access to the underlying compiler instance?

With an instance of TypeScriptCompiler, it's easy to get the syntax trees for your code units. Once you have the trees, you can walk them to extract the information you desire, which I imagine in your case are classes and their properties, and the comments associated with them (e.g. to find your markers).

Also, there may be an easier way to get the symbolic declarations you're after. Check the "pullGetXXX" methods on TypeScriptCompiler - they may offer an simpler route to the declarations/definitions.

In my case, I'm mapping and analyzing the code itself, so walking the trees is a must. I'm doing something similar to what you're aiming for though: I'm emitting custom code and metadata for various reasons, including documentation and API verification.

It may be worth noting that I'm building a standalone tool, and this means another compiler pass. If you wish to actually integrate with or modify the compiler-as-a-tool, I'm sure that will be quite easy as well - again, the TypeScript team has done an amazing job and the compiler and related services are elegant and easy to work with.

Hope this helps!