2012-12-26 79 views
14

我想在C#中編寫一個函數,它接受一個包含typescript代碼的字符串並返回一個包含JavaScript代碼的字符串。有這樣的庫函數嗎?以編程方式編譯C#中的打字稿?

+0

你可以自動執行命令l ine編譯器... – SWeko

+0

可以看看:[這個答案](http://stackoverflow.com/a/3182411/1344760) – RichardTowers

+0

@Sekeko:我在看'tsc',但我什麼都沒看到這將採取TS和輸出JS。它只適用於我所能看到的文件。 – mpen

回答

5

也許你可以使用JavaScript解釋器如JavaScriptDotNet來從C#運行打字稿編譯器tsc.js

喜歡的東西:

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); 
} 

顯然,這代碼將需要一些嚴肅的工作。如果這確實變得可行,我肯定會對結果感興趣。

你也可能想要修改tsc,以便它可以在內存中的字符串上運行,而不需要文件IO。

+0

哦..你的意思是通過JavaScriptDotNet運行'tsc'編譯器,而不是輸出。還是相當迂迴的做法,但理論上我認爲它應該工作... – mpen

+2

是的,對不起更清晰的抱歉。很難同時談論三種語言! – RichardTowers

2

TypeScript編譯器文件在node.js或Windows Script Host上正式運行 - 它是用TypeScript本身編寫的(並轉換爲JavaScript)。它需要一個可以訪問文件系統的腳本主機。

因此,基本上,只要您可以將其包裝在支持所需文件系統操作的腳本引擎中,就可以從任何語言運行TypeScript。

如果您想純粹用C#將TypeScript編譯爲JavaScript,您最終會編寫一個編譯器的C#克隆。

11

您可以使用Process來調用編譯器,指定爲臨時文件夾並讀取編譯文件的內容。

我做了一個小的應用程序做到這一點:

使用

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

要獲得例子和評論JS string

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

完整的源:

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) 
     { 

     } 
    } 
} 
+0

這可能是最好的解決方案,但我真的希望我可以將它全部保存在內存中(輸入和輸出)。 – mpen

+0

偉大的答案我希望我能雙倍upvote! – Glenn

+0

我遇到一個'File not found'的Win32Exception,但是我的TS文件的路徑是正確的。我認爲這是TSC編譯器的不正確路徑。你有一次面對這個問題嗎? 編輯:我直接指定我的TSC編譯器的路徑,現在我有這樣的消息:「指定的可執行文件不是這個操作系統平臺的有效應用程序。」 –