21

I'm trying to write a function in C# that takes in a string containing typescript code and returns a string containing JavaScript code. Is there a library function for this?

11
  • You could automate the command line compiler... Commented Dec 26, 2012 at 21:02
  • Could have a look at: this answer Commented Dec 26, 2012 at 21:08
  • @SWeko: I'm looking at tsc but I don't see anything that will take in TS and output JS. It only works with files as far as I can see. Commented Dec 26, 2012 at 21:09
  • @RichardTowers: Huh? What's that got to do with TypeScript? I don't see a single mention of TS. Commented Dec 26, 2012 at 21:10
  • 3
    Well, save to ts file -> compile to js file -> File.ReadAllText... Commented Dec 26, 2012 at 21:18

3 Answers 3

13

You can use Process to invoke the compiler, specify --out file.js to a temporary folder and read the contents of the compiled file.

I made a little app to do that:

Usage

TypeScriptCompiler.Compile(@"C:\tmp\test.ts");

To get the JS string

string javascriptSource = File.ReadAllText(@"C:\tmp\test.js");

Full source with example and comments:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                // compiles a TS file
                TypeScriptCompiler.Compile(@"C:\tmp\test.ts");

                // if no errors were found, read the contents of the compile file
                string javascriptSource = File.ReadAllText(@"C:\tmp\test.js");
            }
            catch (InvalidTypeScriptFileException ex)
            {
                // there was a compiler error, show the compiler output
                Console.WriteLine(ex.Message);
            }

            Console.ReadKey();
        }
    }

    public static class TypeScriptCompiler
    {
        // helper class to add parameters to the compiler
        public class Options
        {
            private static Options @default;
            public static Options Default
            {
                get
                {
                    if (@default == null)
                        @default = new Options();

                    return @default;
                }
            }

            public enum Version
            {
                ES5,
                ES3,
            }

            public bool EmitComments { get; set; }
            public bool GenerateDeclaration { get; set; }
            public bool GenerateSourceMaps { get; set; }
            public string OutPath { get; set; }
            public Version TargetVersion { get; set; }

            public Options() { }

            public Options(bool emitComments = false
                , bool generateDeclaration = false
                , bool generateSourceMaps = false
                , string outPath = null
                , Version targetVersion = Version.ES5)
            {
                EmitComments = emitComments;
                GenerateDeclaration = generateDeclaration;
                GenerateSourceMaps = generateSourceMaps;
                OutPath = outPath;
                TargetVersion = targetVersion;
            }
        }

        public static void Compile(string tsPath, Options options = null)
        {
            if (options == null)
                options = Options.Default;

            var d = new Dictionary<string,string>();

            if (options.EmitComments)
                d.Add("-c", null);

            if (options.GenerateDeclaration)
                d.Add("-d", null);

            if (options.GenerateSourceMaps)
                d.Add("--sourcemap", null);

            if (!String.IsNullOrEmpty(options.OutPath))
                d.Add("--out", options.OutPath);

            d.Add("--target", options.TargetVersion.ToString());

            // this will invoke `tsc` passing the TS path and other
            // parameters defined in Options parameter
            Process p = new Process();

            ProcessStartInfo psi = new ProcessStartInfo("tsc", tsPath + " " + String.Join(" ", d.Select(o => o.Key + " " + o.Value)));

            // run without showing console windows
            psi.CreateNoWindow = true;
            psi.UseShellExecute = false;

            // redirects the compiler error output, so we can read
            // and display errors if any
            psi.RedirectStandardError = true;

            p.StartInfo = psi;

            p.Start();

            // reads the error output
            var msg = p.StandardError.ReadToEnd();

            // make sure it finished executing before proceeding 
            p.WaitForExit();

            // if there were errors, throw an exception
            if (!String.IsNullOrEmpty(msg))
                throw new InvalidTypeScriptFileException(msg);
        }
    }

    public class InvalidTypeScriptFileException : Exception
    {
        public InvalidTypeScriptFileException() : base()
        {

        }
        public InvalidTypeScriptFileException(string message) : base(message)
        {

        }
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

This is probably the best solution, although I really wish I could keep it all in memory (input and output).
I face with a 'File not found' with a Win32Exception, but my path for my TS file is correct. I think it's tha path to the TSC compiler which is not correct. Have you faced with this issue one time ? EDIT: I specify directly the path for my TSC compiler, now I have this message : "The specified executable is not a valid application for this operating system platform."
5

Perhaps you could use a JavaScript interpreter like JavaScriptDotNet to run the typescript compiler tsc.js from C#.

Something like:

string tscJs = File.ReadAllText("tsc.js");

using (var context = new JavascriptContext())
{
    // Some trivial typescript:
    var typescriptSource = "window.alert('hello world!');";
    context.SetParameter("typescriptSource", typescriptSource);
    context.SetParameter("result", "");

    // Build some js to execute:
    string script = tscJs + @"
result = TypeScript.compile(""typescriptSource"")";

    // Execute the js
    context.Run(script);

    // Retrieve the result (which should be the compiled JS)
    var js = context.GetParameter("result");
    Assert.AreEqual(typescriptSource, js);
}

Obviously that code would need some serious work. If this did turn out to be feasible, I'd certainly be interested in the result.

You'd also probably want to modify tsc so that it could operate on strings in memory rather than requiring file IO.

2 Comments

Oh..you meant run the tsc compiler via JavaScriptDotNet, not the output. Still quite a roundabout way of doing it, but in theory I guess it should work...
Yep, sorry for not being clearer. It's difficult talking about three languages at once!
3

The TypeScript compiler file officially runs on either node.js or Windows Script Host - it is written in TypeScript itself (and transpiled to JavaScript). It requires a script host that can access the file system.

So essentially, you can run TypeScript from any language as long as you can wrap it in a script engine that supports the file system operations required.

If you wanted to compile TypeScript to JavaScript purely in C#, you would end up writing a C# clone of the compiler.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.