mirror of
https://github.com/KOP-XIAO/QuantumultX.git
synced 2026-01-26 05:45:09 +00:00
support clash type (proxy&rule provider)
This commit is contained in:
@@ -1,17 +1,17 @@
|
|||||||
/**
|
/**
|
||||||
☑️ 资源解析器 ©𝐒𝐡𝐚𝐰𝐧 ⟦2020-08-20 13:29⟧
|
☑️ 资源解析器 ©𝐒𝐡𝐚𝐰𝐧 ⟦2020-08-23 22:29⟧
|
||||||
----------------------------------------------------------
|
----------------------------------------------------------
|
||||||
🛠 发现 𝐁𝐔𝐆 请反馈: @Shawn_KOP_bot
|
🛠 发现 𝐁𝐔𝐆 请反馈: @Shawn_KOP_bot
|
||||||
⛳️ 关注 🆃🅶 相关频道: https://t.me/QuanX_API
|
⛳️ 关注 🆃🅶 相关频道: https://t.me/QuanX_API
|
||||||
🗣 🆃🄷🄰🄽🄺🅂 🆃🄾 @Jamie CHIEN, @M**F**, @c0lada, @Peng-YM
|
🗣 🆃🄷🄰🄽🄺🅂 🆃🄾 @Jamie CHIEN, @M**F**, @c0lada, @Peng-YM
|
||||||
|
|
||||||
🤖 主要功能:
|
🤖 主要功能:
|
||||||
❶ 将各格式的服务器订阅解析成 𝐐𝐮𝐚𝐧𝐭𝐮𝐦𝐮𝐥𝐭 𝐗 格式
|
❶ 将其它格式的服务器订阅解析成 𝐐𝐮𝐚𝐧𝐭𝐮𝐦𝐮𝐥𝐭 𝐗 格式
|
||||||
☑︎ 支持 𝗩𝗺𝗲𝘀𝘀/𝗦𝗦(𝗥/𝗗)/𝗧𝗿𝗼𝗷𝗮𝗻/𝗤𝘂𝗮𝗻𝘁𝘂𝗺𝘂𝗹𝘁(𝗫)/𝗦𝘂𝗿𝗴𝗲/𝗛𝗧𝗧𝗣(𝗦)
|
☑︎ 支持 𝗩𝗺𝗲𝘀𝘀/𝗦𝗦(𝗥/𝗗)/𝗧𝗿𝗼𝗷𝗮𝗻/𝗤𝘂𝗮𝗻𝘁𝘂𝗺𝘂𝗹𝘁(𝗫)/𝗦𝘂𝗿𝗴𝗲/𝐂𝐥𝐚𝐬𝐡/𝗛𝗧𝗧𝗣(𝗦) 格式
|
||||||
☑︎ 提供说明 1⃣️ 中的可选个性化参数(筛选、重命名 等)
|
☑︎ 提供说明 1⃣️ 中的可选个性化参数(筛选、重命名 等)
|
||||||
❷ 𝗿𝗲𝘄𝗿𝗶𝘁𝗲(重写) & 𝗳𝗶𝗹𝘁𝗲𝗿(分流) 的 转换&筛选
|
❷ 𝗿𝗲𝘄𝗿𝗶𝘁𝗲(重写) & 𝗳𝗶𝗹𝘁𝗲𝗿(分流) 的 转换&筛选
|
||||||
☑︎ 用于禁用远程引用中某(几)项 𝗿𝗲𝘄𝗿𝗶𝘁𝗲/𝗵𝗼𝘀𝘁𝗻𝗮𝗺𝗲/𝗳𝗶𝗹𝘁𝗲𝗿
|
☑︎ 用于禁用远程引用中某(几)项 𝗿𝗲𝘄𝗿𝗶𝘁𝗲/𝗵𝗼𝘀𝘁𝗻𝗮𝗺𝗲/𝗳𝗶𝗹𝘁𝗲𝗿
|
||||||
☑︎ 𝐒𝐮𝐫𝐠𝐞 类型规则 𝗹𝗶𝘀𝘁 与 模块 𝐦𝐨𝐝𝐮𝐥𝐞 的解析使用
|
☑︎ 𝐒𝐮𝐫𝐠𝐞/𝐂𝐥𝐚𝐬𝐡 类型规则 𝗹𝗶𝘀𝘁 与 模块 𝐦𝐨𝐝𝐮𝐥𝐞 的解析使用
|
||||||
----------------------------------------------------------
|
----------------------------------------------------------
|
||||||
0️⃣ ⟦原始链接⟧ 后加 "#" 使用, 不同参数用 "&" 连接:
|
0️⃣ ⟦原始链接⟧ 后加 "#" 使用, 不同参数用 "&" 连接:
|
||||||
⚠️ ☞ 𝐡𝐭𝐭𝐩𝐬://𝐦𝐲𝐬𝐮𝐛.𝐜𝐨𝐦#𝙚𝙢𝙤𝙟𝙞=1&𝙩𝙛𝙤=1&𝙞𝙣=香港+台湾
|
⚠️ ☞ 𝐡𝐭𝐭𝐩𝐬://𝐦𝐲𝐬𝐮𝐛.𝐜𝐨𝐦#𝙚𝙢𝙤𝙟𝙞=1&𝙩𝙛𝙤=1&𝙞𝙣=香港+台湾
|
||||||
@@ -138,6 +138,7 @@ var pfi = Pin0 ? "in=" + Pin0.join(", ") + ", " : ""
|
|||||||
var pfo = Pout0 ? "out=" + Pout0.join(", ") : ""
|
var pfo = Pout0 ? "out=" + Pout0.join(", ") : ""
|
||||||
var pfihn = Phin0 ? "inhn=" + Phin0.join(", ") + ", " : ""
|
var pfihn = Phin0 ? "inhn=" + Phin0.join(", ") + ", " : ""
|
||||||
var pfohn = Phout0 ? "outhn=" + Phout0.join(", ") : ""
|
var pfohn = Phout0 ? "outhn=" + Phout0.join(", ") : ""
|
||||||
|
var Pcnt = para1.indexOf("cnt=") != -1 ? para1.split("cnt=")[1].split("&")[0] : 0;
|
||||||
var flow = "";
|
var flow = "";
|
||||||
var exptime = "";
|
var exptime = "";
|
||||||
//$notify(type0)
|
//$notify(type0)
|
||||||
@@ -170,7 +171,7 @@ if (type0 == "Subs-B64Encode") {
|
|||||||
total = SubsEd2QX(content0, Pudp0, Ptfo0, Pcert0, PTls13);
|
total = SubsEd2QX(content0, Pudp0, Ptfo0, Pcert0, PTls13);
|
||||||
} else if (type0 == "Subs") {
|
} else if (type0 == "Subs") {
|
||||||
total = Subs2QX(content0, Pudp0, Ptfo0, Pcert0, PTls13);
|
total = Subs2QX(content0, Pudp0, Ptfo0, Pcert0, PTls13);
|
||||||
} else if (type0 == "QuanX") {
|
} else if (type0 == "QuanX" || type0 == "Clash") {
|
||||||
total = isQuanX(content0);
|
total = isQuanX(content0);
|
||||||
} else if (type0 == "Surge") {
|
} else if (type0 == "Surge") {
|
||||||
total = Surge2QX(content0);
|
total = Surge2QX(content0);
|
||||||
@@ -236,6 +237,7 @@ if (flag == 1) { //server 类型统一处理
|
|||||||
total = QXSort(total, Psort0);
|
total = QXSort(total, Psort0);
|
||||||
}
|
}
|
||||||
total = TagCheck_QX(total) //节点名检查
|
total = TagCheck_QX(total) //节点名检查
|
||||||
|
if (Pcnt == 1) {$notify("final content" , "Nodes", total)}
|
||||||
if (flag == 1) { total = Base64.encode(total.join("\n")) } //强制节点类型 base64 加密后再导入 Quantumult X
|
if (flag == 1) { total = Base64.encode(total.join("\n")) } //强制节点类型 base64 加密后再导入 Quantumult X
|
||||||
$done({ content: total });
|
$done({ content: total });
|
||||||
} else { $done({ content: total });}
|
} else { $done({ content: total });}
|
||||||
@@ -276,6 +278,7 @@ function Type_Check(subs) {
|
|||||||
var DomainK = ["domain-set,"]
|
var DomainK = ["domain-set,"]
|
||||||
var QuanXK = ["shadowsocks=", "trojan=", "vmess=", "http="];
|
var QuanXK = ["shadowsocks=", "trojan=", "vmess=", "http="];
|
||||||
var SurgeK = ["=ss,", "=vmess,", "=trojan,", "=http,", "=custom,", "=https,", "=shadowsocks", "=shadowsocksr"];
|
var SurgeK = ["=ss,", "=vmess,", "=trojan,", "=http,", "=custom,", "=https,", "=shadowsocks", "=shadowsocksr"];
|
||||||
|
var ClashK = ["proxies:"]
|
||||||
var SubK = ["dm1lc3M", "c3NyOi8v", "dHJvamFu", "c3M6Ly", "c3NkOi8v", "c2hhZG93"];
|
var SubK = ["dm1lc3M", "c3NyOi8v", "dHJvamFu", "c3M6Ly", "c3NkOi8v", "c2hhZG93"];
|
||||||
var RewriteK = [" url "]
|
var RewriteK = [" url "]
|
||||||
var SubK2 = ["ss://", "vmess://", "ssr://", "trojan://", "ssd://"];
|
var SubK2 = ["ss://", "vmess://", "ssr://", "trojan://", "ssd://"];
|
||||||
@@ -298,6 +301,11 @@ function Type_Check(subs) {
|
|||||||
type = "Surge"; // Surge Profiles
|
type = "Surge"; // Surge Profiles
|
||||||
} else if (SurgeK.some(NodeCheck)) {
|
} else if (SurgeK.some(NodeCheck)) {
|
||||||
type = "Subs" // Surge proxy list
|
type = "Subs" // Surge proxy list
|
||||||
|
} else if (ClashK.some(NodeCheck)){ // Clash 类型节点转换
|
||||||
|
type = "Clash";
|
||||||
|
console.log(type)
|
||||||
|
content0 = Clash2QX(subs)
|
||||||
|
console.log("waht"+content0)
|
||||||
} else if (subi.indexOf("[Script]") != -1 || subi.indexOf("[Rule]") != -1 || subs.indexOf("[URL Rewrite]") != -1 || subs.indexOf("[Map Local]") != -1 || para1.indexOf("dst=regex") != -1) { // Surge module /rule-set(url-regex) 类型
|
} else if (subi.indexOf("[Script]") != -1 || subi.indexOf("[Rule]") != -1 || subs.indexOf("[URL Rewrite]") != -1 || subs.indexOf("[Map Local]") != -1 || para1.indexOf("dst=regex") != -1) { // Surge module /rule-set(url-regex) 类型
|
||||||
type = "sgmodule"
|
type = "sgmodule"
|
||||||
} else if (subi.indexOf("hostname=") != -1 || RewriteK.some(RewriteCheck)) {
|
} else if (subi.indexOf("hostname=") != -1 || RewriteK.some(RewriteCheck)) {
|
||||||
@@ -547,11 +555,11 @@ function Rule_Handle(subs, Pout, Pin) {
|
|||||||
if (Tout != "" && Tout != null) { // 有 out 参数时
|
if (Tout != "" && Tout != null) { // 有 out 参数时
|
||||||
var dlist = [];
|
var dlist = [];
|
||||||
for (var i = 0; i < cnt.length; i++) {
|
for (var i = 0; i < cnt.length; i++) {
|
||||||
cc = cnt[i]
|
cc = cnt[i].indexOf(" - ") != -1? cnt[i].split(" - ")[1].trim() : cnt[i].trim()
|
||||||
const exclude = (item) => cc.indexOf(item) != -1; // 删除项
|
const exclude = (item) => cc.indexOf(item) != -1; // 删除项
|
||||||
const RuleCheck = (item) => cc.indexOf(item) != -1; //无视注释行
|
const RuleCheck = (item) => cc.indexOf(item) != -1; //无视注释行
|
||||||
if (Tout.some(exclude) && !RuleK.some(RuleCheck)) {
|
if (Tout.some(exclude) && !RuleK.some(RuleCheck)) {
|
||||||
dlist.push(Rule_Policy("-" + cnt[i]))
|
dlist.push(Rule_Policy("-" + cc))
|
||||||
} else if (!RuleK.some(RuleCheck) && cc) { //if Pout.some, 不操作注释项
|
} else if (!RuleK.some(RuleCheck) && cc) { //if Pout.some, 不操作注释项
|
||||||
dd = Rule_Policy(cc);
|
dd = Rule_Policy(cc);
|
||||||
if (Tin != "" && Tin != null) {
|
if (Tin != "" && Tin != null) {
|
||||||
@@ -586,7 +594,7 @@ function Rule_Handle(subs, Pout, Pin) {
|
|||||||
} else if (Tin != "" && Tin != null) { //if Tout
|
} else if (Tin != "" && Tin != null) { //if Tout
|
||||||
var dlist = [];
|
var dlist = [];
|
||||||
for (var i = 0; i < cnt.length; i++) {
|
for (var i = 0; i < cnt.length; i++) {
|
||||||
cc = cnt[i]
|
cc = cnt[i].indexOf(" - ") != -1? cnt[i].split(" - ")[1].trim() : cnt[i].trim()
|
||||||
const RuleCheck = (item) => cc.indexOf(item) != -1; //无视注释行
|
const RuleCheck = (item) => cc.indexOf(item) != -1; //无视注释行
|
||||||
if (!RuleK.some(RuleCheck) && cc) { //if Pout.some, 不操作注释项
|
if (!RuleK.some(RuleCheck) && cc) { //if Pout.some, 不操作注释项
|
||||||
dd = Rule_Policy(cc);
|
dd = Rule_Policy(cc);
|
||||||
@@ -609,7 +617,7 @@ function Rule_Handle(subs, Pout, Pin) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Rule_Policy(content) { //增加、替换 policy
|
function Rule_Policy(content) { //增加、替换 policy
|
||||||
var cnt = content.split(",");
|
var cnt = content.replace(/ - /g,"").trim().split(",");
|
||||||
var RuleK = ["//", "#", ";"];
|
var RuleK = ["//", "#", ";"];
|
||||||
var RuleK1 = ["host", "domain", "ip-cidr", "geoip", "user-agent", "ip6-cidr"];
|
var RuleK1 = ["host", "domain", "ip-cidr", "geoip", "user-agent", "ip6-cidr"];
|
||||||
const RuleCheck = (item) => cnt[0].toLowerCase().indexOf(item) != -1; //无视注释行
|
const RuleCheck = (item) => cnt[0].toLowerCase().indexOf(item) != -1; //无视注释行
|
||||||
@@ -1449,6 +1457,99 @@ function LoonSSR2QX(cnt) {
|
|||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clash parser
|
||||||
|
function Clash2QX(cnt) {
|
||||||
|
const yaml = new YAML()
|
||||||
|
var aa = JSON.stringify(yaml.parse(cnt))
|
||||||
|
var bb = JSON.parse(aa).proxies
|
||||||
|
console.log(bb)
|
||||||
|
var nl = bb.length
|
||||||
|
var nodelist=[]
|
||||||
|
var node=""
|
||||||
|
for (i=0; i<nl; i++){
|
||||||
|
node=bb[i]
|
||||||
|
typec = node.type
|
||||||
|
if (typec == "ss") {
|
||||||
|
node = CSS2QX(node,1,1)
|
||||||
|
} else if (typec == "vmess"){
|
||||||
|
node = CV2QX(node,1,1)
|
||||||
|
} else if (typec == "trojan"){
|
||||||
|
node = CT2QX(node,1,1)
|
||||||
|
} else if (typec == "http"){
|
||||||
|
node = CH2QX(node)
|
||||||
|
}
|
||||||
|
nodelist.push(node)
|
||||||
|
}
|
||||||
|
return nodelist.join("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
//Clash ss type server
|
||||||
|
function CSS2QX(cnt,pudp,ptfo) {
|
||||||
|
tag = "tag="+cnt.name.replace(/\\U.+?\s{1}/gi,"")
|
||||||
|
ipt = cnt.server+":"+cnt.port
|
||||||
|
pwd = "password=" + cnt.password
|
||||||
|
mtd = "method="+ cnt.cipher
|
||||||
|
udp = cnt.udp ? "udp-relay=true" : "udp-relay=false"
|
||||||
|
tfo = cnt.tfo ? "fast-open=true" : "fast-open=false"
|
||||||
|
obfs = cnt.plugin == "obfs"? "obfs=" + cnt["plugin-opts"].mode : ""
|
||||||
|
ohost = cnt.plugin == "obfs"? "obfs-host=" + cnt["plugin-opts"].host : ""
|
||||||
|
node = "shadowsocks="+[ipt, pwd, mtd, udp, tfo, obfs, ohost, tag].filter(Boolean).join(", ")
|
||||||
|
console.log(node)
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
|
//Clash vmess type server
|
||||||
|
function CV2QX(cnt,pudp,ptfo) {
|
||||||
|
tag = "tag="+cnt.name.replace(/\\U.+?\s{1}/gi," ")
|
||||||
|
ipt = cnt.server+":"+cnt.port
|
||||||
|
pwd = "password=" + cnt.uuid
|
||||||
|
mtd = "method="+ "aes-128-gcm" //cnt.cipher
|
||||||
|
udp = cnt.udp ? "udp-relay=true" : "udp-relay=false"
|
||||||
|
tfo = cnt.tfo ? "fast-open=true" : "fast-open=false"
|
||||||
|
obfs = ""
|
||||||
|
if (cnt.network == "ws" && cnt.tls) {
|
||||||
|
obfs = "obfs=wss"
|
||||||
|
} else if (cnt.network == "ws"){
|
||||||
|
obfs = "obfs=ws"
|
||||||
|
} else if (cnt.tls){
|
||||||
|
obfs = "obfs=over-tls"
|
||||||
|
}
|
||||||
|
ohost = cnt["ws-headers"]? "obfs-host=" + cnt["ws-headers"]["Host"] : ""
|
||||||
|
ouri = cnt["ws-path"]? "obfs-uri="+cnt["ws-path"] : ""
|
||||||
|
cert = cnt["skip-cert-verify"] && cnt.tls ? "tls-verification=false" : ""
|
||||||
|
node = "vmess="+[ipt, pwd, mtd, udp, tfo, obfs, ohost, ouri, cert, tag].filter(Boolean).join(", ")
|
||||||
|
console.log(node)
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
|
//Clash Trojan
|
||||||
|
function CT2QX(cnt,pudp,ptfo) {
|
||||||
|
tag = "tag="+cnt.name.replace(/\\U.+?\s{1}/gi," ")
|
||||||
|
ipt = cnt.server+":"+cnt.port
|
||||||
|
pwd = "password=" + cnt.password
|
||||||
|
otls = "over-tls=true"
|
||||||
|
cert = cnt["skip-cert-verify"] ? "tls-verification=false" : "tls-verification=true"
|
||||||
|
udp = cnt.udp ? "udp-relay=true" : "udp-relay=false"
|
||||||
|
tfo = cnt.tfo ? "fast-open=true" : "fast-open=false"
|
||||||
|
node = "trojan="+[ipt, pwd, otls, cert, udp, tfo, tag].filter(Boolean).join(", ")
|
||||||
|
console.log(node)
|
||||||
|
return node
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clash http
|
||||||
|
function CH2QX(cnt){
|
||||||
|
tag = "tag="+cnt.name.replace(/\\U.+?\s{1}/gi," ")
|
||||||
|
ipt = cnt.server+":"+cnt.port
|
||||||
|
uname = cnt.username ? "username=" + cnt.username : ""
|
||||||
|
pwd = cnt.password ? "password=" + cnt.password : ""
|
||||||
|
tls = cnt.tls ? "over-tls=true" : ""
|
||||||
|
cert = cnt["skip-cert-verify"] && cnt.tls ? "tls-verification=false" : ""
|
||||||
|
node = "http="+[ipt, uname, pwd, tls, cert, tag].filter(Boolean).join(", ")
|
||||||
|
console.log(node)
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
// UDP/TFO 参数 (强制 surge/quanx 类型转换)
|
// UDP/TFO 参数 (强制 surge/quanx 类型转换)
|
||||||
function XUDP(cnt,pudp) {
|
function XUDP(cnt,pudp) {
|
||||||
var udp = pudp == 1? "udp-relay=true, " : "udp-relay=false, "
|
var udp = pudp == 1? "udp-relay=true, " : "udp-relay=false, "
|
||||||
@@ -1621,6 +1722,441 @@ function Base64Code() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
YAML parser for Javascript
|
||||||
|
Author: Diogo Costa
|
||||||
|
|
||||||
|
This program is released under the MIT License as follows:
|
||||||
|
|
||||||
|
Copyright (c) 2011 Diogo Costa (costa.h4evr@gmail.com)
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
function YAML() {
|
||||||
|
var errors = [],
|
||||||
|
reference_blocks = [],
|
||||||
|
processing_time = 0,
|
||||||
|
regex =
|
||||||
|
{
|
||||||
|
"regLevel" : new RegExp("^([\\s\\-]+)"),
|
||||||
|
"invalidLine" : new RegExp("^\\-\\-\\-|^\\.\\.\\.|^\\s*#.*|^\\s*$"),
|
||||||
|
"dashesString" : new RegExp("^\\s*\\\"([^\\\"]*)\\\"\\s*$"),
|
||||||
|
"quotesString" : new RegExp("^\\s*\\\'([^\\\']*)\\\'\\s*$"),
|
||||||
|
"float" : new RegExp("^[+-]?[0-9]+\\.[0-9]+(e[+-]?[0-9]+(\\.[0-9]+)?)?$"),
|
||||||
|
"integer" : new RegExp("^[+-]?[0-9]+$"),
|
||||||
|
"array" : new RegExp("\\[\\s*(.*)\\s*\\]"),
|
||||||
|
"map" : new RegExp("\\{\\s*(.*)\\s*\\}"),
|
||||||
|
"key_value" : new RegExp("([a-z0-9_-][ a-z0-9_-]*):( .+)", "i"),
|
||||||
|
"single_key_value" : new RegExp("^([a-z0-9_-][ a-z0-9_-]*):( .+?)$", "i"),
|
||||||
|
"key" : new RegExp("([a-z0-9_-][ a-z0-9_-]+):( .+)?", "i"),
|
||||||
|
"item" : new RegExp("^-\\s+"),
|
||||||
|
"trim" : new RegExp("^\\s+|\\s+$"),
|
||||||
|
"comment" : new RegExp("([^\\\'\\\"#]+([\\\'\\\"][^\\\'\\\"]*[\\\'\\\"])*)*(#.*)?")
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class A block of lines of a given level.
|
||||||
|
* @param {int} lvl The block's level.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function Block(lvl) {
|
||||||
|
return {
|
||||||
|
/* The block's parent */
|
||||||
|
parent: null,
|
||||||
|
/* Number of children */
|
||||||
|
length: 0,
|
||||||
|
/* Block's level */
|
||||||
|
level: lvl,
|
||||||
|
/* Lines of code to process */
|
||||||
|
lines: [],
|
||||||
|
/* Blocks with greater level */
|
||||||
|
children : [],
|
||||||
|
/* Add a block to the children collection */
|
||||||
|
addChild : function(obj) {
|
||||||
|
this.children.push(obj);
|
||||||
|
obj.parent = this;
|
||||||
|
++this.length;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// function to create an XMLHttpClient in a cross-browser manner
|
||||||
|
|
||||||
|
function fromURL(src, ondone) {
|
||||||
|
var client = createXMLHTTPRequest();
|
||||||
|
client.onreadystatechange = function() {
|
||||||
|
if (this.readyState == 4 || this.status == 200) {
|
||||||
|
var txt = this.responseText;
|
||||||
|
ondone(YAML.eval0(txt));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
client.open('GET', src);
|
||||||
|
client.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
function parser(str) {
|
||||||
|
var regLevel = regex["regLevel"];
|
||||||
|
var invalidLine = regex["invalidLine"];
|
||||||
|
var lines = str.split("\n");
|
||||||
|
var m;
|
||||||
|
var level = 0, curLevel = 0;
|
||||||
|
|
||||||
|
var blocks = [];
|
||||||
|
|
||||||
|
var result = new Block(-1);
|
||||||
|
var currentBlock = new Block(0);
|
||||||
|
result.addChild(currentBlock);
|
||||||
|
var levels = [];
|
||||||
|
var line = "";
|
||||||
|
|
||||||
|
blocks.push(currentBlock);
|
||||||
|
levels.push(level);
|
||||||
|
|
||||||
|
for(var i = 0, len = lines.length; i < len; ++i) {
|
||||||
|
line = lines[i];
|
||||||
|
|
||||||
|
if(line.match(invalidLine)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(m = regLevel.exec(line)) {
|
||||||
|
level = m[1].length;
|
||||||
|
} else
|
||||||
|
level = 0;
|
||||||
|
|
||||||
|
if(level > curLevel) {
|
||||||
|
var oldBlock = currentBlock;
|
||||||
|
currentBlock = new Block(level);
|
||||||
|
oldBlock.addChild(currentBlock);
|
||||||
|
blocks.push(currentBlock);
|
||||||
|
levels.push(level);
|
||||||
|
} else if(level < curLevel) {
|
||||||
|
var added = false;
|
||||||
|
|
||||||
|
var k = levels.length - 1;
|
||||||
|
for(; k >= 0; --k) {
|
||||||
|
if(levels[k] == level) {
|
||||||
|
currentBlock = new Block(level);
|
||||||
|
blocks.push(currentBlock);
|
||||||
|
levels.push(level);
|
||||||
|
if(blocks[k].parent!= null)
|
||||||
|
blocks[k].parent.addChild(currentBlock);
|
||||||
|
added = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!added) {
|
||||||
|
errors.push("Error: Invalid indentation at line " + i + ": " + line);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
currentBlock.lines.push(line.replace(regex["trim"], ""));
|
||||||
|
curLevel = level;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function processValue(val) {
|
||||||
|
val = val.replace(regex["trim"], "");
|
||||||
|
var m = null;
|
||||||
|
|
||||||
|
if(val == 'true') {
|
||||||
|
return true;
|
||||||
|
} else if(val == 'false') {
|
||||||
|
return false;
|
||||||
|
} else if(val == '.NaN') {
|
||||||
|
return Number.NaN;
|
||||||
|
} else if(val == 'null') {
|
||||||
|
return null;
|
||||||
|
} else if(val == '.inf') {
|
||||||
|
return Number.POSITIVE_INFINITY;
|
||||||
|
} else if(val == '-.inf') {
|
||||||
|
return Number.NEGATIVE_INFINITY;
|
||||||
|
} else if(m = val.match(regex["dashesString"])) {
|
||||||
|
return m[1];
|
||||||
|
} else if(m = val.match(regex["quotesString"])) {
|
||||||
|
return m[1];
|
||||||
|
} else if(m = val.match(regex["float"])) {
|
||||||
|
return parseFloat(m[0]);
|
||||||
|
} else if(m = val.match(regex["integer"])) {
|
||||||
|
return parseInt(m[0]);
|
||||||
|
} else if( !isNaN(m = Date.parse(val))) {
|
||||||
|
return new Date(m);
|
||||||
|
} else if(m = val.match(regex["single_key_value"])) {
|
||||||
|
var res = {};
|
||||||
|
res[m[1]] = processValue(m[2]);
|
||||||
|
return res;
|
||||||
|
} else if(m = val.match(regex["array"])){
|
||||||
|
var count = 0, c = ' ';
|
||||||
|
var res = [];
|
||||||
|
var content = "";
|
||||||
|
var str = false;
|
||||||
|
for(var j = 0, lenJ = m[1].length; j < lenJ; ++j) {
|
||||||
|
c = m[1][j];
|
||||||
|
if(c == '\'' || c == '"') {
|
||||||
|
if(str === false) {
|
||||||
|
str = c;
|
||||||
|
content += c;
|
||||||
|
continue;
|
||||||
|
} else if((c == '\'' && str == '\'') || (c == '"' && str == '"')) {
|
||||||
|
str = false;
|
||||||
|
content += c;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else if(str === false && (c == '[' || c == '{')) {
|
||||||
|
++count;
|
||||||
|
} else if(str === false && (c == ']' || c == '}')) {
|
||||||
|
--count;
|
||||||
|
} else if(str === false && count == 0 && c == ',') {
|
||||||
|
res.push(processValue(content));
|
||||||
|
content = "";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
content += c;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(content.length > 0)
|
||||||
|
res.push(processValue(content));
|
||||||
|
return res;
|
||||||
|
} else if(m = val.match(regex["map"])){
|
||||||
|
var count = 0, c = ' ';
|
||||||
|
var res = [];
|
||||||
|
var content = "";
|
||||||
|
var str = false;
|
||||||
|
for(var j = 0, lenJ = m[1].length; j < lenJ; ++j) {
|
||||||
|
c = m[1][j];
|
||||||
|
if(c == '\'' || c == '"') {
|
||||||
|
if(str === false) {
|
||||||
|
str = c;
|
||||||
|
content += c;
|
||||||
|
continue;
|
||||||
|
} else if((c == '\'' && str == '\'') || (c == '"' && str == '"')) {
|
||||||
|
str = false;
|
||||||
|
content += c;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else if(str === false && (c == '[' || c == '{')) {
|
||||||
|
++count;
|
||||||
|
} else if(str === false && (c == ']' || c == '}')) {
|
||||||
|
--count;
|
||||||
|
} else if(str === false && count == 0 && c == ',') {
|
||||||
|
res.push(content);
|
||||||
|
content = "";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
content += c;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(content.length > 0)
|
||||||
|
res.push(content);
|
||||||
|
|
||||||
|
var newRes = {};
|
||||||
|
for(var j = 0, lenJ = res.length; j < lenJ; ++j) {
|
||||||
|
if(m = res[j].match(regex["key_value"])) {
|
||||||
|
newRes[m[1]] = processValue(m[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return newRes;
|
||||||
|
} else
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
function processFoldedBlock(block) {
|
||||||
|
var lines = block.lines;
|
||||||
|
var children = block.children;
|
||||||
|
var str = lines.join(" ");
|
||||||
|
var chunks = [str];
|
||||||
|
for(var i = 0, len = children.length; i < len; ++i) {
|
||||||
|
chunks.push(processFoldedBlock(children[i]));
|
||||||
|
}
|
||||||
|
return chunks.join("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
function processLiteralBlock(block) {
|
||||||
|
var lines = block.lines;
|
||||||
|
var children = block.children;
|
||||||
|
var str = lines.join("\n");
|
||||||
|
for(var i = 0, len = children.length; i < len; ++i) {
|
||||||
|
str += processLiteralBlock(children[i]);
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
function processBlock(blocks) {
|
||||||
|
var m = null;
|
||||||
|
var res = {};
|
||||||
|
var lines = null;
|
||||||
|
var children = null;
|
||||||
|
var currentObj = null;
|
||||||
|
|
||||||
|
var level = -1;
|
||||||
|
|
||||||
|
var processedBlocks = [];
|
||||||
|
|
||||||
|
var isMap = true;
|
||||||
|
|
||||||
|
for(var j = 0, lenJ = blocks.length; j < lenJ; ++j) {
|
||||||
|
|
||||||
|
if(level != -1 && level != blocks[j].level)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
processedBlocks.push(j);
|
||||||
|
|
||||||
|
level = blocks[j].level;
|
||||||
|
lines = blocks[j].lines;
|
||||||
|
children = blocks[j].children;
|
||||||
|
currentObj = null;
|
||||||
|
|
||||||
|
for(var i = 0, len = lines.length; i < len; ++i) {
|
||||||
|
var line = lines[i];
|
||||||
|
|
||||||
|
if(m = line.match(regex["key"])) {
|
||||||
|
var key = m[1];
|
||||||
|
|
||||||
|
if(key[0] == '-') {
|
||||||
|
key = key.replace(regex["item"], "");
|
||||||
|
if (isMap) {
|
||||||
|
isMap = false;
|
||||||
|
if (typeof(res.length) === "undefined") {
|
||||||
|
res = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(currentObj != null) res.push(currentObj);
|
||||||
|
currentObj = {};
|
||||||
|
isMap = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(typeof m[2] != "undefined") {
|
||||||
|
var value = m[2].replace(regex["trim"], "");
|
||||||
|
if(value[0] == '&') {
|
||||||
|
var nb = processBlock(children);
|
||||||
|
if(currentObj != null) currentObj[key] = nb;
|
||||||
|
else res[key] = nb;
|
||||||
|
reference_blocks[value.substr(1)] = nb;
|
||||||
|
} else if(value[0] == '|') {
|
||||||
|
if(currentObj != null) currentObj[key] = processLiteralBlock(children.shift());
|
||||||
|
else res[key] = processLiteralBlock(children.shift());
|
||||||
|
} else if(value[0] == '*') {
|
||||||
|
var v = value.substr(1);
|
||||||
|
var no = {};
|
||||||
|
|
||||||
|
if(typeof reference_blocks[v] == "undefined") {
|
||||||
|
errors.push("Reference '" + v + "' not found!");
|
||||||
|
} else {
|
||||||
|
for(var k in reference_blocks[v]) {
|
||||||
|
no[k] = reference_blocks[v][k];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(currentObj != null) currentObj[key] = no;
|
||||||
|
else res[key] = no;
|
||||||
|
}
|
||||||
|
} else if(value[0] == '>') {
|
||||||
|
if(currentObj != null) currentObj[key] = processFoldedBlock(children.shift());
|
||||||
|
else res[key] = processFoldedBlock(children.shift());
|
||||||
|
} else {
|
||||||
|
if(currentObj != null) currentObj[key] = processValue(value);
|
||||||
|
else res[key] = processValue(value);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(currentObj != null) currentObj[key] = processBlock(children);
|
||||||
|
else res[key] = processBlock(children);
|
||||||
|
}
|
||||||
|
} else if(line.match(/^-\s*$/)) {
|
||||||
|
if (isMap) {
|
||||||
|
isMap = false;
|
||||||
|
if (typeof(res.length) === "undefined") {
|
||||||
|
res = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(currentObj != null) res.push(currentObj);
|
||||||
|
currentObj = {};
|
||||||
|
isMap = true;
|
||||||
|
continue;
|
||||||
|
} else if(m = line.match(/^-\s*(.*)/)) {
|
||||||
|
if(currentObj != null)
|
||||||
|
currentObj.push(processValue(m[1]));
|
||||||
|
else {
|
||||||
|
if (isMap) {
|
||||||
|
isMap = false;
|
||||||
|
if (typeof(res.length) === "undefined") {
|
||||||
|
res = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res.push(processValue(m[1]));
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(currentObj != null) {
|
||||||
|
if (isMap) {
|
||||||
|
isMap = false;
|
||||||
|
if (typeof(res.length) === "undefined") {
|
||||||
|
res = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res.push(currentObj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(var j = processedBlocks.length - 1; j >= 0; --j) {
|
||||||
|
blocks.splice.call(blocks, processedBlocks[j], 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
function semanticAnalysis(blocks) {
|
||||||
|
var res = processBlock(blocks.children);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
function preProcess(src) {
|
||||||
|
var m;
|
||||||
|
var lines = src.split("\n");
|
||||||
|
|
||||||
|
var r = regex["comment"];
|
||||||
|
|
||||||
|
for(var i in lines) {
|
||||||
|
if(m = lines[i].match(r)) {
|
||||||
|
/* var cmt = "";
|
||||||
|
if(typeof m[3] != "undefined")
|
||||||
|
lines[i] = m[1];
|
||||||
|
else if(typeof m[3] != "undefined")
|
||||||
|
lines[i] = m[3];
|
||||||
|
else
|
||||||
|
lines[i] = "";
|
||||||
|
*/
|
||||||
|
if(typeof m[3] !== "undefined") {
|
||||||
|
lines[i] = m[0].substr(0, m[0].length - m[3].length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines.join("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.parse = function eval0(str) {
|
||||||
|
errors = [];
|
||||||
|
reference_blocks = [];
|
||||||
|
processing_time = (new Date()).getTime();
|
||||||
|
var pre = preProcess(str)
|
||||||
|
var doc = parser(pre);
|
||||||
|
var res = semanticAnalysis(doc);
|
||||||
|
processing_time = (new Date()).getTime() - processing_time;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************************************/
|
/***********************************************************************************************/
|
||||||
function Tools() {
|
function Tools() {
|
||||||
const filter = (src, ...regex) => {
|
const filter = (src, ...regex) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user