aardio 文档
aardio 范例: .NET 命名空间分析工具(Microsoft Learn HTML 版)
//.NET 命名空间分析工具(Microsoft Learn HTML 版)
import win.ui;
/*DSG{{*/
var winform = win.form(text=".NET Framework 命名空间分析工具";right=830;bottom=469)
winform.add(
button={cls="button";text="分析";left=673;top=7;right=820;bottom=43;anchors={top=1;right=1};z=3};
edit={cls="edit";left=15;top=54;right=816;bottom=456;anchors={left=1;top=1;right=1;bottom=1};edge=1;hscroll=1;multiline=1;vscroll=1;z=1};
editNameSpace={cls="edit";text="System.Reflection";left=177;top=12;right=546;bottom=41;anchors={top=1;right=1;bottom=1};edge=1;multiline=1;z=2};
editNetVersion={cls="edit";text="4.0";left=599;top=12;right=654;bottom=41;edge=1;z=5};
static={cls="static";text=".NET Framework 命名空间:";left=12;top=10;right=169;bottom=35;align="right";center=1;anchors={left=1;top=1};transparent=1;z=4};
static2={cls="static";text="版本:";left=549;top=10;right=597;bottom=35;align="right";center=1;transparent=1;z=6}
)
/*}}*/
winform.edit.limit = -1;
winform.button.oncommand = function(id,event){
var netNamespace = string.trim(winform.editNameSpace.text);
var netVersion = string.trim(winform.editNetVersion.text);
if(!#netNamespace){
return winform.editNameSpace.showErrorTip("请输入 .NET 命名空间")
}
if(!#netVersion){
return winform.editNetVersion.showErrorTip("请输入 .NET Framework 版本,例如 3.5、4.0、4.8")
}
winform.edit.text = "";
thread.invoke(
function(winform,netNamespace,netVersion){
winform.button.disabledText = {"✶";"✸";"✹";"✺";"✹";"✷"};
var finish = function(message,isError){
winform.button.disabledText = null;
if(message){
if(isError) winform.msgboxErr(message);
else winform.edit.print(message);
}
}
var normalizeView = function(netVersion){
netVersion = string.trim(netVersion);
if(string.match(netVersion,"^netframework\-")) return netVersion;
return "netframework-" ++ netVersion;
}
var hasMoniker = function(monikers,view){
if(!monikers) return false;
return string.indexOf(" " ++ monikers ++ " "," " ++ view ++ " ") != null;
}
var makeApiUrl = function(href){
if(!href) return null;
if(string.match(href,"^https?\://")) return href;
if(string.left(href,1) == "/") return "https://learn.microsoft.com" ++ href;
return inet.url.canonicalize("https://learn.microsoft.com/en-us/dotnet/api/" ++ href);
}
var getAssembly = function(htmlClient,typeUrl,view){
var htmlDoc,err = htmlClient.get(typeUrl);
if(!htmlDoc) return null,err || "抓取类型页失败";
for ele in htmlDoc.eachQuery(tagName="dl"){
if(!hasMoniker(ele["data-moniker"],view)) continue;
var text = string.trim(ele.innerText());
if(!string.match(text,"^Assembly\:")) continue;
var assembly;
if(ele.dd[1]) assembly = string.trim(ele.dd[1].innerText());
if(!assembly) assembly = string.match(text,"^Assembly\:\s*([^\r\n]+\.dll)");
if(assembly && string.endsWith(assembly,".dll")){
return assembly;
}
}
return null,"未在类型页找到匹配 " ++ view ++ " 的 Assembly 信息";
}
import inet.url;
import web.rest.htmlClient;
var htmlClient = web.rest.htmlClient();
var view = normalizeView(netVersion);
var namespaceUrl = "https://learn.microsoft.com/en-us/dotnet/api/"
++ string.lower(netNamespace)
++ "?view="
++ view;
winform.edit.print("正在获取命名空间数据:",netNamespace);
var namespaceDoc,err = htmlClient.get(namespaceUrl);
if(!namespaceDoc){
finish("获取命名空间数据失败:" ++ (err || namespaceUrl),true);
return;
}
var items = [];
var seen = {};
for tr in namespaceDoc.eachQuery(tagName="tr"){
if(!hasMoniker(tr["data-moniker"],view)) continue;
var a;
for ele in tr.eachQuery(tagName="a"){
if(ele.class && string.indexOf(ele.class,"xref")){
a = ele;
break;
}
}
if(a){
var typeName = string.trim(a.innerText());
var href = a.href;
if(!#typeName || !href) continue;
var apiName = netNamespace ++ "." ++ typeName;
if(seen[apiName]) continue;
seen[apiName] = true;
table.push(items,{
apiName = apiName;
href = href;
url = makeApiUrl(href);
});
}
}
if(!#items){
finish("未找到属于 " ++ view ++ ' 的类型列表。\r\n' ++ namespaceUrl,true);
return;
}
winform.edit.print("找到类型数量:",#items,",开始逐个抓取类型页分析 Assembly ...");
var map = {};
var failed = [];
for i,item in items{
var assembly,err = getAssembly(htmlClient,item.url,view);
if(assembly){
if(!map[assembly]) map[assembly] = [];
table.push(map[assembly],item.apiName);
winform.edit.updateLastLine(i,"/",#items," ",item.apiName," => ",assembly);
}
else {
table.push(failed,{apiName=item.apiName;url=item.url;err=err});
winform.edit.updateLastLine(i,"/",#items," ",item.apiName," => 跳过:",err);
}
}
import JSON;
winform.edit.text = JSON.stringify(map,true);
if(#failed){
winform.edit.print('\r\n/* 未能识别 Assembly 的项目:\r\n',JSON.stringify(failed,true),'\r\n*/');
}
winform.button.disabledText = null;
},winform,netNamespace,netVersion
)
}
winform.edit.text = /*****************
// aardio 导入 .NET 命名空间示例
import dotNet;
// 这里只是举例,System 已随 dotNet 库默认导入,不必要再重复导入。
// 存在同名标准库库的可用 import 语句导入,例如 import System;
// 访问已导入 .NET 命名空间的下级名字空间,在同一程序集内则按需自动导入。
dotNet.import("System");
// 下级命名空间不在同一程序集,但程序集在之前已加载的,aardio 也会自动导入。
// 不在同一程序集内,且所属程序集未加载的,必须用哪个导入哪个,不会覆盖已存在的父命名空间。
// 这里只是举例,mscorlib 已随 dotNet 库默认加载,通常不必重复导入。
dotNet.import("System.Security.Cryptography","mscorlib");
// 不会自动导入或替换上级命名空间,例如下面的代码不能替代 dotNet.import("System");
dotNet.import("System.Security.Cryptography.X509Certificates","System");
// .NET Framework 自带的命名空间在不同的 DLL 实现。
// 所以我们需要用这个工具,分析一个命名空间在哪个 DLL 里的成员最多。
// 就用该 DLL 导入该命名空间,可以少写 dotNet.import 语句。
*****************/
winform.show();
win.loopMessage();
Markdown 格式