import web.mshtml; import fsys.codepage; import string.html; import inet.http; namespace web; var wb; class turndown{ ctor(...){ if(!wb){ wb = ..web.mshtml(); wb.loadcode(`
`,{js=$"~\lib\web\turndown\turndown.js"}) } if(type.isString(...)){ this = wb.jsNew("TurndownService",wb.eval(...) ); } else { this = wb.jsNew("TurndownService",... ) } this[["turndownEx"]] = this.turndown; this[["addRuleEx"]] = this.addRule; }; addRule = function(name,rule){ this.addRuleEx(name,wb.eval(rule)); }; turndownGfm = function(html){ //合并代码块, 外层有 才会转换为多行代码块
html = ..string.replace(html,`\]*)\>\]*\>(.+?)\<\/code\>\<\/pre\>`,function(preProp,code){
var code = ..string.replace(code,"\<<@@br@>!\W[^\>]*\>[\t ]*\r?\n",'\n');
var code = ..string.replace(code,"\<<@@br@>!\W[^\>]*\>",'\n');
code = ..string.replace(code,"```","{{{--BACKTICK--}}}");
//首尾添加换行,turndown.js 生成的代码块前后可能缺少换行导致格式错乱
code = "
" + ..string.replace(code,"\<\/code\>\",'\n') + "
";
return code;
})
//修复 turndown.js 生成的表格不符合 Markdown 语法
var html = ..string.replace(html
,"(\<<@@table@>\s+[^\>]+\>)(.+?)(\<\/<@@table@>\>)"
,function(tbBegin,tbContent,tbEnd){
var b = ..string.replace(tbContent,"(\<<@@blockquote@>[^\>]*\>)(.+?)(\<\/<@@blockquote@>\>)"
,lambda(b,c,e) "" + c + "
")
var b = ..string.replace(b,"(\<<@@div@>[^\>]*\>)(.+?)(\<\/<@@div@>\>)"
,lambda(b,c,e) "" + c + "
")
b = ..string.replace(b,"(\<<@@tr@>[^\>]*\>)(.+?)(\<\/<@@tr@>\>)"
,function(trBegin,trContent,trEnd){
var trContent,count = ..string.replace(trContent,"(\<<@@td@>[^\>]*\>)(.+?)(\<\/<@@td@>\>)"
,function(tdBegin,tdContent,tdEnd){
return "" + tdContent + " "
})
if(count){
return trBegin ++ trContent ++ trEnd;
}
},1
)
//暂时替换 h1,h2,h3 ... 为特殊占位符号,以避免转为 markdown 后出现换行
b = ..string.replace(b,"\<[hH](\d)[^\>]*\>(.+?)\<\/[hH]\1\>"
,"{---{H\1{--\2--}H\1}---}"
)
b = ..string.replace(b,'\n','');
b = ..string.replace(b,'\r','');
b = ..string.replace(b,"\
",'{{{--BR--}}}');
b = ..string.replace(b,"\<<@@br@>\s*\>",'{{{--BR--}}}');
b = ..string.replace(b,"\<<@@p@>\s*[^\>]*\>",'{{{--PB--}}}');
b = ..string.replace(b,"\<@@p@>\s*\>",'{{{--PE--}}}');
return tbBegin++b++tbEnd;
})
var md = this[["turndownEx"]](html);
if(md){
md = ..string.replace(md,"\{\{\{--BR--\}\}\}","
");
md = ..string.replace(md,"\{\{\{--PB--\}\}\}","");
md = ..string.replace(md,"\{\{\{--PE--\}\}\}","
");
md = ..string.replace(md,"\{\{\{--BACKTICK--\}\}\}","```");
md = ..string.replace(md,"\*\*```","```");
md = ..string.replace(md,"```\*\*","```");
md = ..string.replace(md,"\{---\{H(\d)\{--(.+?)--\}H\1\}---\}","\2 ");
return md;
}
}
turndownFile = function(path){
var str = ..fsys.codepage.load(path);
if( str ) return this.turndown(str);
};
turndownUrl = function(url,conv){
if(!webView) webView = ..web[["view"]] ? ..web.view() : ..web.mshtml();
webView.go(url);
webView.waitDoc();
webView.doScript( `
var hiddenElements = document.querySelectorAll('[aria-hidden="true"]');
for (var i = 0; i < hiddenElements.length; i++) {
hiddenElements[i].parentNode.removeChild(hiddenElements[i]);
}
var allElements = document.querySelectorAll('*');
for (var j = 0; j < allElements.length; j++) {
if (window.getComputedStyle(allElements[j]).display === 'none') {
allElements[j].parentNode.removeChild(allElements[j]);
}
}` );
var html = webView.html;
if(conv){ html = conv(html) };
return this.turndown(html);
};
useGfm = function(...){
wb.doScript($"~\lib\web\turndown\gfm.js")
var keys = {...}
if(!#keys){
this.use( wb.eval("turndownPluginGfm.gfm") )
}
else {
for(i,k in keys){
this.use( wb.eval("turndownPluginGfm."+k) )
}
}
this[["turndown"]] = this.turndownGfm;
};
}
turndown.default = function(){
var turndownService = web.turndown( codeBlockStyle = "fenced" );
turndownService.remove('script');
turndownService.remove('style');
turndownService.remove('noscript');
//启用 gfm(GitHub Flavored Markdown)插件。
turndownService.useGfm()
// 添加自定义规则处理带类名的代码块
turndownService.addRule('codeBlock', "{
filter: function(node) {
return node.nodeName === 'PRE' && node.classList.contains('code');
},
replacement: function(content, node) {
var language = node.classList.item(1) || '';
language = language.replace(/^language-/, '');
return '```' + language + '\n' + content.trim() + '\n```';
}
}");
return turndownService;
}
turndown.httpGet = function(url){
if(type(url)==="table" && #url){
url = url[1];
url = url[["url"]] || url;
if(url && ..string.find(url,"(https?\://?aardio\.com/zh\-cn/doc/?$") ){
url = url[2] || url;
}
}
var snippet;
if(url[["url"]]){
if(url[["text"]]){
return url[["text"]],"text",url[["url"]];
}
snippet = url[["snippet"]];
}
url = url[["url"]] || url;
if(!#url) return;
var docUrl = ..string.match(url,"(https?\://?aardio\.com/zh\-cn/doc/\S+)\.|")
if( docUrl ){
url = docUrl + ".html.md";
var r,e = ..inet.http.get(url);
if(r) return r,,url;
return null,e;
}
else{
var html,err = ..inet.http.get(url);
if(html){
if(!_WIN10_LATER) return ..string.html.toText(html),"text",url;
var md;
try {
var turndownService = ..web.turndown.default();
md = turndownService.turndown(
html
);
}
catch(e){
err = e;
}
if(#md) return md,,url
}
if(snippet){
return snippet,"text",url;
}
return null,err;
}
}
/*****intellisense()
web.turndown() = 创建 TurndownService 对象,用于将 HTML 转换为 Markdown。\n参数 @1 可用 aardio 表对象指定选项,\n也可用字符串参数指定包含描述 JS 选项对象的 JS 代码。\n!stdWebTurndown.
web.turndown.default() = 使用默认设置创建 TurndownService 对象,用于将 HTML 转换为 Markdown。\n启用围栏样式代码块,默认移除 script,style,noscript 等节点。\n!stdWebTurndown.
web.turndown.httpGet(__) = 获取参数 @1 指定网址的内容并转换为 Markdown 格式或者文本格式。\n参数 @1 也可以指定包含 url 字段的对象,或这样的对象数组。\n参数为 包含 url 字段的对象时如果同时包含 text 字段,则直接自 text 字段获取网页文本。\n如果指定数组参数,则仅取第一个数组成员作为参数。\n如果参数为空数组、空字符串、null 则返回 null。\n\n低于 Win10 的系统返回文本格式,第二个返回值为 "text",\n否则返回 Markdown 格式内容。\n如果成功转换为 Markdown,则第二个返回值为 null,第三个返回值为实际抓取的 URL。\n此函数执行失败返回 null,错误信息 。
end intellisense*****/
/*****intellisense(!stdWebTurndown)
turndown(__) = 将参数 @1 指定的 HTML 代码转换为 Markdown 文本。
turndownFile(__) = 将参数 @1 指定的 HTML 代码文件转换为 Markdown 文本。
turndownUrl(__) = 将参数 @1 指定网址的 HTML 代码文件转换为 Markdown 文本。\n可选用参数 @2 指定预处理 HTML 代码的回调函数,该回调函数接受一个参数以获取 HTML 并返回新的 HTML。\n如果之前已导入 web.view 则使用 web.view 打开网址并获取 HTML。
useGfm() = 启用 gfm(GitHub Flavored Markdown) 插件,\n可选用一个或多个字符串参数指定要启用的插件名称。
addRule(.(key,jsRule) = 添加规则。\n参数 @key 为字符串,\n参数 @jsRule 用包含 JS 代码的字符串指定规则。\n注意 JS 必须兼容 IE 内核,不要使用箭头函数这些。
end intellisense*****/