在 C# 中以编程方式编译打字稿?

Posted

技术标签:

【中文标题】在 C# 中以编程方式编译打字稿?【英文标题】:Programmatically compile typescript in C#? 【发布时间】:2012-12-12 08:14:03 【问题描述】:

我正在尝试用 C# 编写一个函数,该函数接受一个包含打字稿代码的字符串并返回一个包含 javascript 代码的字符串。有这个库函数吗?

【问题讨论】:

你可以自动化命令行编译器... 可以看看:this answer @SWeko:我正在查看tsc,但我看不到任何可以接受 TS 和输出 JS 的东西。据我所知,它只适用于文件。 @RichardTowers:嗯?这与 TypeScript 有什么关系?我没有看到任何提及 TS。 嗯,保存到ts文件->编译成js文件-> File.ReadAllText... 【参考方案1】:

您可以使用Process 调用编译器,将--out file.js 指定到一个临时文件夹并读取编译文件的内容。

为此我制作了一个小应用程序:

用法

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

获取JS string

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

带有示例和 cmets 的完整源代码:

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)
        

        
    

【讨论】:

这可能是最好的解决方案,虽然我真的希望我能把它全部保存在内存中(输入和输出)。 我遇到带有 Win32Exception 的“找不到文件”,但我的 TS 文件路径是正确的。我认为这是不正确的 TSC 编译器路径。你曾经遇到过这个问题吗?编辑:我直接为我的 TSC 编译器指定路径,现在我收到这条消息:“指定的可执行文件不是此操作系统平台的有效应用程序。”【参考方案2】:

也许您可以使用像 JavaScriptDotNet 这样的 JavaScript 解释器从 C# 运行 typescript 编译器 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。

【讨论】:

哦..你的意思是通过 JavaScriptDotNet 运行 tsc 编译器,而不是输出。仍然是一种迂回的方式,但理论上我想它应该可以工作...... 是的,很抱歉没有更清楚。很难同时说三种语言!【参考方案3】:

TypeScript 编译器文件在 node.js 或 Windows Script Host 上正式运行 - 它是用 TypeScript 本身编写的(并转译为 JavaScript)。它需要一个可以访问文件系统的脚本主机。

所以本质上,你可以从任何语言运行 TypeScript,只要你可以将它包装在支持所需文件系统操作的脚本引擎中。

如果你想纯粹在 C# 中将 TypeScript 编译为 JavaScript,你最终会编写编译器的 C# 克隆。

【讨论】:

以上是关于在 C# 中以编程方式编译打字稿?的主要内容,如果未能解决你的问题,请参考以下文章

用c#以编程方式编译生成的.cpp文件?

更改打字稿目标会影响编译性能吗?

git merge 后打字稿更改未编译

无法在 Docker 中编译打字稿

如何从 git 中排除打字稿编译的文件

无法使用 tsc 节点模块编译打字稿