typescript get方法_.NET手撸绘制TypeScript类图——上篇
.NET手擼繪制TypeScript類圖——上篇
近年來隨著交互界面的精細化,TypeScript越來越流行,前端的設計也越來復雜,而類圖正是用簡單的箭頭和方塊,反映對象與對象之間關(guān)系/依賴的好方式。許多工具都能生成C#類圖,有些工具也能生成TypeScript類圖,如tsuml,但存在一些局限性。
我們都是.NET開發(fā),為啥不干脆就用.NET擼一個TypeScript類圖呢?
說干就干!為了搞到類圖,一共分兩步走:
本文將分上下兩部分,上篇將介紹我移植的一個.NET Standard 2.0的TypeScript解析庫,下篇將介紹如何將AST轉(zhuǎn)換為真正的圖,并實現(xiàn)一些基本的交互。
.ts文件生成抽象語法樹
正常來說編譯原理挺難的,但好在有人趕在了我的前頭 。
TypeScript解析庫
我在Github上找到了一個叫TypeScriptAST的項目,它剛好就能將.ts文件轉(zhuǎn)換為AST。但它僅提供了.NET Framework版本。我看了一下實現(xiàn)方式,它是從微軟官方的TypeScript倉庫按源代碼翻譯的。其中Parse.cs高達近8000行代碼,能把如此巨大的工作翻譯完成,可見作者花了不少時間。
我拿了過來,稍微改造了一下,移植到了.NET Core。NuGet包地址為:
https://www.nuget.org/packages/Sdcb.TypeScriptAST/我移植的這個版本源代碼也開放到了Github,使用相同的Apache-2.0協(xié)議開源,開源項目鏈接如下:
https://github.com/sdcb/TypeScriptAST雖然不知道是不是第一個移植的,但可以確定的是今后.NET Core也能解析TypeScript了:)
注意:官方?jīng)]有提供TypeScript的.NET解析工具,也沒建議用.NET,使用ts解析是正常做法,官方的包用起來顯然也更有自信——但這就是騷操作,不挑戰(zhàn)一下怎么知道極限在哪呢?簡單使用
假如有如下TypeScript代碼:
class Class1 {td: number = 3;ts: string = 'hello';doWork(): string {return `${3+this.td}-${this.ts}`;} }var tc = new Class1();我們可以使用TypeScriptAST的類進行分析,只需使用TypeScriptAST類:
var ast = new TypeScriptAST(source: tsSourceStringContent);該類有許多對象,提供了豐富的解析方式,使用如下代碼,即可將代碼中的類抽出來:
var classAsts = ast.OfKind(SyntaxKind.ClassDeclaration);由于AST中的屬性太多,我們調(diào)試時抽重要的顯示出來,并轉(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"]} ]有了這個,我們即可定義一些類型,用于后續(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強大的LINQ,可以將代碼寫得特別精練,最后可以達到“一行代碼*”完成.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);兩個函數(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(),}, };使用
我對這個ShootR項目進行了分析,分析代碼如下:
ParseFiles(Directory.EnumerateFiles(path: @"C:Usersdotnet-loversourcereposShootRShootRShootRClientShips", "*.ts")).Dump();分析結(jié)果:
成功找到了完整的7個類,并將類名、字段名、字段類型、方法名、方法參數(shù)和返回值等信息都解析出來了。本還能做得更詳細的,但這些可以留給讀者完成。
總結(jié)
在本篇我們介紹了如何使用.NET解析TypeScript,并推薦了我移植的一個NuGet包:Sdcb.TypeScriptAST。
下篇將在這篇的基礎上,介紹如何使用代碼將類圖渲染出來。
本文所用到的完整代碼,可以在我的Github倉庫中下載: https://github.com/sdcb/blog-data/tree/master/2019/20191113-ts-uml-with-dotnet
喜歡的朋友 請關(guān)注我的微信公眾號:【DotNet騷操作】
總結(jié)
以上是生活随笔為你收集整理的typescript get方法_.NET手撸绘制TypeScript类图——上篇的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python批量音频转格式_python
- 下一篇: 内蒙古工业大学计算机科学与技术,计算机科