日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > asp.net >内容正文

asp.net

typescript get方法_.NET手撸绘制TypeScript类图——上篇

發(fā)布時(shí)間:2025/3/12 asp.net 53 豆豆
生活随笔 收集整理的這篇文章主要介紹了 typescript get方法_.NET手撸绘制TypeScript类图——上篇 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

.NET手?jǐn)]繪制TypeScript類圖——上篇

近年來(lái)隨著交互界面的精細(xì)化,TypeScript越來(lái)越流行,前端的設(shè)計(jì)也越來(lái)復(fù)雜,而類圖正是用簡(jiǎn)單的箭頭和方塊,反映對(duì)象與對(duì)象之間關(guān)系/依賴的好方式。許多工具都能生成C#類圖,有些工具也能生成TypeScript類圖,如tsuml,但存在一些局限性。

我們都是.NET開(kāi)發(fā),為啥不干脆就用.NET擼一個(gè)TypeScript類圖呢?

說(shuō)干就干!為了搞到類圖,一共分兩步走:

  • 解析.ts文件,生成抽象語(yǔ)法樹(shù)(AST),并轉(zhuǎn)換為簡(jiǎn)單的類、屬性、方法等對(duì)象
  • 將這個(gè)對(duì)象繪制出來(lái)
  • 本文將分上下兩部分,上篇將介紹我移植的一個(gè).NET Standard 2.0的TypeScript解析庫(kù),下篇將介紹如何將AST轉(zhuǎn)換為真正的圖,并實(shí)現(xiàn)一些基本的交互。

    .ts文件生成抽象語(yǔ)法樹(shù)

    正常來(lái)說(shuō)編譯原理挺難的,但好在有人趕在了我的前頭 。

    TypeScript解析庫(kù)

    我在Github上找到了一個(gè)叫TypeScriptAST的項(xiàng)目,它剛好就能將.ts文件轉(zhuǎn)換為AST。但它僅提供了.NET Framework版本。我看了一下實(shí)現(xiàn)方式,它是從微軟官方的TypeScript倉(cāng)庫(kù)按源代碼翻譯的。其中Parse.cs高達(dá)近8000行代碼,能把如此巨大的工作翻譯完成,可見(jiàn)作者花了不少時(shí)間。

    我拿了過(guò)來(lái),稍微改造了一下,移植到了.NET Core。NuGet包地址為:

    https://www.nuget.org/packages/Sdcb.TypeScriptAST/

    我移植的這個(gè)版本源代碼也開(kāi)放到了Github,使用相同的Apache-2.0協(xié)議開(kāi)源,開(kāi)源項(xiàng)目鏈接如下:

    https://github.com/sdcb/TypeScriptAST

    雖然不知道是不是第一個(gè)移植的,但可以確定的是今后.NET Core也能解析TypeScript了:)

    注意:官方?jīng)]有提供TypeScript的.NET解析工具,也沒(méi)建議用.NET,使用ts解析是正常做法,官方的包用起來(lái)顯然也更有自信——但這就是騷操作,不挑戰(zhàn)一下怎么知道極限在哪呢?

    簡(jiǎn)單使用

    假如有如下TypeScript代碼:

    class Class1 {td: number = 3;ts: string = 'hello';doWork(): string {return `${3+this.td}-${this.ts}`;} }var tc = new Class1();

    我們可以使用TypeScriptAST的類進(jìn)行分析,只需使用TypeScriptAST類:

    var ast = new TypeScriptAST(source: tsSourceStringContent);

    該類有許多對(duì)象,提供了豐富的解析方式,使用如下代碼,即可將代碼中的類抽出來(lái):

    var classAsts = ast.OfKind(SyntaxKind.ClassDeclaration);

    由于AST中的屬性太多,我們調(diào)試時(shí)抽重要的顯示出來(lái),并轉(zhuǎn)換為JSON:

    JsonSerializer.Serialize(classAsts.Select(c => new {c.IdentifierStr,Children = c.Children.Skip(1).Select(x => x.IdentifierStr), }), new JsonSerializerOptions { WriteIndented = true}).Dump();

    結(jié)果如下:

    [{"IdentifierStr": "Class1","Children": ["td","ts","doWork"]} ]

    有了這個(gè),我們即可定義一些類型,用于后續(xù)繪制AST:

    class ClassDef {public string Name { get; set; }public List<PropertyDef> Properties { get; set; }public List<MethodDef> Methods { get; set; } }class PropertyDef {public string Name { get; set; }public bool IsPublic { get; set; }public bool IsStatic { get; set; }public string Type { get; set; }public override string ToString() => (IsPublic ? "+" : "-") + $" {Name}: " + (String.IsNullOrWhiteSpace(Type) ? "any" : Type); }class MethodDef {public string Name { get; set; }public bool IsPublic { get; set; }public bool IsStatic { get; set; }public List<ParameterDef> Parameters { get; set; }public string ReturnType { get; set; }public override string ToString() => (IsPublic ? "+" : "-")+ $" {Name}({String.Join(", ", Parameters)})"+ (Name == ".ctor" ? "" : $": {ReturnType}"); }class ParameterDef {public string Name { get; set; }public string Type { get; set; }public override string ToString() => $"{Name}: {Type}"; }

    借助于.NET強(qiáng)大的LINQ,可以將代碼寫得特別精練,最后可以達(dá)到“一行代碼*”完成.ts到AST的轉(zhuǎn)換:

    static Dictionary<string, ClassDef> ParseFiles(IEnumerable<string> files) => files.Select(x => new TypeScriptAST(File.ReadAllText(x), x)).SelectMany(x => x.OfKind(SyntaxKind.ClassDeclaration)).Select(x => new ClassDef{Name = x.OfKind(SyntaxKind.Identifier).FirstOrDefault().GetText(),Properties = x.OfKind(SyntaxKind.PropertyDeclaration).Select(x => new PropertyDef{Name = x.IdentifierStr,IsPublic = x.First.Kind != SyntaxKind.PrivateKeyword,IsStatic = x.OfKind(SyntaxKind.StaticKeyword).Any(),Type = GetType(x),}).ToList(),Methods = x.OfKind(SyntaxKind.Constructor).Concat(x.OfKind(SyntaxKind.MethodDeclaration)).Select(x => new MethodDef{Name = x is ConstructorDeclaration ctor ? ".ctor" : x.IdentifierStr,IsPublic = x.First.Kind != SyntaxKind.PrivateKeyword,IsStatic = x.OfKind(SyntaxKind.StaticKeyword).Any(),Parameters = ((ISignatureDeclaration)x).Parameters.Select(x => new ParameterDef{Name = x.OfKind(SyntaxKind.Identifier).FirstOrDefault().GetText(),Type = GetType(x),}).ToList(),ReturnType = GetReturnType(x),}).ToList(),}).ToDictionary(x => x.Name, v => v);

    兩個(gè)函數(shù)稍微提取一下,代碼能更精練:

    static string GetReturnType(Node node) => node.Children.OfType<TypeNode>().FirstOrDefault()?.GetText();static string GetType(Node node) => node switch {var x when x.OfKind(SyntaxKind.TypeReference).Any() => x.OfKind(SyntaxKind.TypeReference).First().GetText(),_ => node.Last switch{LiteralExpression literal => literal.Kind.ToString()[..^7].ToLower() switch{"numeric" => "number",var x => x,},var x => x.GetText(),}, };

    使用

    我對(duì)這個(gè)ShootR項(xiàng)目進(jìn)行了分析,分析代碼如下:

    ParseFiles(Directory.EnumerateFiles(path: @"C:Usersdotnet-loversourcereposShootRShootRShootRClientShips", "*.ts")).Dump();

    分析結(jié)果:

    成功找到了完整的7個(gè)類,并將類名、字段名、字段類型、方法名、方法參數(shù)和返回值等信息都解析出來(lái)了。本還能做得更詳細(xì)的,但這些可以留給讀者完成。

    總結(jié)

    在本篇我們介紹了如何使用.NET解析TypeScript,并推薦了我移植的一個(gè)NuGet包:Sdcb.TypeScriptAST。

    下篇將在這篇的基礎(chǔ)上,介紹如何使用代碼將類圖渲染出來(lái)。

    本文所用到的完整代碼,可以在我的Github倉(cāng)庫(kù)中下載: https://github.com/sdcb/blog-data/tree/master/2019/20191113-ts-uml-with-dotnet

    喜歡的朋友 請(qǐng)關(guān)注我的微信公眾號(hào):【DotNet騷操作】

    總結(jié)

    以上是生活随笔為你收集整理的typescript get方法_.NET手撸绘制TypeScript类图——上篇的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。