做网站用的一些素材,wordpress 目录主题,最新网页游戏开服时间表,免费网络直播软件.NET手撸绘制TypeScript类图——上篇近年来随着交互界面的精细化#xff0c; TypeScript越来越流行#xff0c;前端的设计也越来复杂#xff0c;而 类图正是用简单的箭头和方块#xff0c;反映对象与对象之间关系/依赖的好方式。许多工具都能生成 C#类图#xff0c;有些工… .NET手撸绘制TypeScript类图——上篇近年来随着交互界面的精细化 TypeScript越来越流行前端的设计也越来复杂而 类图正是用简单的箭头和方块反映对象与对象之间关系/依赖的好方式。许多工具都能生成 C#类图有些工具也能生成 TypeScript类图如 tsuml但存在一些局限性。我们都是 .NET开发为啥不干脆就用 .NET撸一个 TypeScript类图呢说干就干为了搞到类图一共分两步走解析 .ts文件生成抽象语法树( AST)并转换为简单的 类、 属性、 方法等对象将这个对象绘制出来本文将分上下两篇上篇将介绍我移植的一个.NET Standard 2.0的TypeScript解析库下篇将介绍如何将AST转换为真正的图并实现一些基本的交互。.ts文件生成抽象语法树正常来说编译原理挺难的但好在有人赶在了我的前头。TypeScript解析库我在 Github上找到了一个叫 TypeScriptAST的项目它刚好就能将 .ts文件转换为 AST。但它仅提供了 .NETFramework版本。我看了一下实现方式它是从微软官方的TypeScript仓库按源代码翻译的。其中 Parse.cs高达近 8000行代码能把如此巨大的工作翻译完成可见作者花了不少时间。我拿了过来稍微改造了一下移植到了 .NETCore。 NuGet包地址为https://www.nuget.org/packages/Sdcb.TypeScriptAST/我移植的这个版本源代码也开放到了 Github使用相同的 Apache-2.0协议开源开源项目链接如下https://github.com/sdcb/TypeScriptAST虽然不知道是不是第一个移植的但可以确定的是今后 .NETCore也能解析 TypeScript了:)注意官方没有提供 TypeScript的 .NET解析工具也没建议用 .NET使用 ts解析是正常做法官方的包用起来显然也更有自信——但这就是 骚操作不挑战一下怎么知道极限在哪呢简单使用假如有如下 TypeScript代码class Class1
{ td: number 3; ts: string hello; doWork(): string { return ${3this.td}-${ts}; }
}
var tc new Class1();我们可以使用 TypeScriptAST的类进行分析只需使用 TypeScriptAST类var ast new TypeScriptAST(source: tsSourceStringContent);该类有许多对象提供了丰富的解析方式使用如下代码即可将代码中的类抽出来var classAsts ast.OfKind(SyntaxKind.ClassDeclaration);由于 AST中的属性太多我们调试时抽重要的显示出来并转换为 JSONJsonSerializer.Serialize(classAsts.Select(c new
{ c.IdentifierStr, Children c.Children.Skip(1).Select(x x.IdentifierStr),
}), new JsonSerializerOptions { WriteIndented true}).Dump();结果如下[ { IdentifierStr: Class1, Children: [ td, ts, doWork ] }
]有了这个我们即可定义一些类型用于后续绘制 ASTclass ClassDef
{ public string Name { get; set; } public ListPropertyDef Properties { get; set; } public ListMethodDef 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 ListParameterDef 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的转换static Dictionarystring, ClassDef ParseFiles(IEnumerablestring 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);两个函数稍微提取一下代码能更精练static string GetReturnType(Node node) node.Children.OfTypeTypeNode().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:\Users\dotnet-lover\source\repos\ShootR\ShootR\ShootR\Client\Ships, *.ts) ).Dump();分析结果 成功找到了完整的 7个类并将 类名、 字段名、 字段类型、 方法名、 方法参数和 返回值等信息都解析出来了。总结在本篇我们介绍了如何使用 .NET解析 TypeScript并推荐了我移植的一个 NuGet包 Sdcb.TypeScriptAST。下篇将在这篇的基础上介绍如何使用代码将类图渲染出来。本文所用到的完整代码可以在我的 Github仓库中下载https://github.com/sdcb/blog-data/tree/master/2019/20191113-ts-uml-with-dotnet微信可能无法评论有想法的朋友可以前往博客园点赞/评论https://www.cnblogs.com/sdflysha/p/20191113-ts-uml-with-dotnet-1.html