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,"\\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*****/