Skip to content

Instantly share code, notes, and snippets.

@Steve-xmh
Created May 15, 2021 14:19
Show Gist options
  • Save Steve-xmh/e385a04116df59fc49e156b1f1f6dbf5 to your computer and use it in GitHub Desktop.
Save Steve-xmh/e385a04116df59fc49e156b1f1f6dbf5 to your computer and use it in GitHub Desktop.
CQCode Parser and stringifier
// ==ClosureCompiler==
// @output_file_name default.js
// @compilation_level ADVANCED_OPTIMIZATIONS
// @language_out ECMASCRIPT_2018
// ==/ClosureCompiler==
"use strict";
var cqRegExp = /^\[CQ:(?<type>\w+?)(?<params>(?:,(?:\w+?)=(?:[^\[\]\$\,]+?))*)?\]$/;
/**
* @param {string} cqcode
* @returns {*}
*/
function parseOne(cqcode) {
var matchResult = cqcode.match(cqRegExp);
if (matchResult && matchResult.groups) {
var data = {};
if (typeof matchResult.groups.params === 'string') {
var params = matchResult.groups.params.substring(1).split(',');
for (var paramPair of params) {
var equalPos = paramPair.indexOf('=');
var key = paramPair.substring(0, equalPos);
var value = paramPair.substring(equalPos + 1);
data[key] = unescapeString(value);
}
}
return {
type: matchResult.groups.type,
data
};
}
else {
throw new Error('Input isn\'t a single cqcode.');
}
}
/**
* @param {string} cqcode
* @returns {*}
*/
function parse(cqcode) {
var result = [];
let str = cqcode;
while (str.length) {
var nextLeft = str.search(/\[CQ:/);
if (nextLeft === -1) { // No more cqcode, push them as text
result.push({
type: 'text',
data: { text: unescapeString(str) }
});
str = '';
}
else {
if (nextLeft > 0) {
result.push({
type: 'text',
data: { text: unescapeString(str.substring(0, nextLeft)) }
});
}
var nextRight = str.search(']');
var cqcode = str.substring(nextLeft, nextRight + 1);
result.push(parseOne(cqcode));
str = str.substring(nextRight + 1);
}
}
return result;
}
/**
* @param {string} cqcode
* @returns {*}
*/
function tryParse(cqcode) {
try {
return parse(cqcode);
}
catch {
return [];
}
}
var cqEscapes = {
'&': '&amp;',
',': '&#44',
'[': '&#91;',
']': '&#93;'
};
/**
* @param {string} data
* @returns {string}
*/
function escapeString(data) {
let result = data;
for (var key in cqEscapes) {
result = result.replaceAll(key, cqEscapes[key]);
}
return result;
}
/**
* @param {string} data
* @returns {string}
*/
function unescapeString(data) {
let result = data;
for (var key in cqEscapes) {
result = result.replaceAll(cqEscapes[key], key);
}
return result;
}
/**
* @param {Array<*>} cqcode
* @returns {string}
*/
function stringifyOne(cqcode) {
return `[CQ:${cqcode.type}${cqcode.data ? `,${Object.entries(cqcode.data).map(v => {
if (!['string', 'number'].includes(typeof v[1]))
return '';
let a = v[0] + '=' + escapeString(v[1]);
return a;
}).join(',')}` : ''}]`;
}
/**
* @param {*} cqcode
* @returns {string}
*/
function stringify(cqcodes) {
var result = [];
for (var cqcode of cqcodes) {
if (cqcode.type === 'text' && cqcode.data?.text) {
result.push(cqcode.data.text);
}
else {
result.push(stringifyOne(cqcode));
}
}
return result.join('');
}
module.exports = {
'parseOne': parseOne,
'parse': parse,
'tryParse': tryParse,
'escapeString': escapeString,
'unescapeString': unescapeString,
'stringifyOne': stringifyOne,
'stringify': stringify,
}
'use strict';var e=/^\[CQ:(?<type>\w+?)(?<params>(?:,(?:\w+?)=(?:[^\[\]\$,]+?))*)?\]$/;function f(a){if((a=a.match(e))&&a.groups){var b={};if("string"===typeof a.groups.g){var c=a.groups.g.substring(1).split(","),d;for(d of c)c=d.indexOf("="),b[d.substring(0,c)]=g(d.substring(c+1))}return{type:a.groups.type,data:b}}throw Error("Input isn't a single cqcode.");}
function h(a){var b=[];let c=a;for(;c.length;)if(a=c.search(/\[CQ:/),-1===a)b.push({type:"text",data:{text:g(c)}}),c="";else{0<a&&b.push({type:"text",data:{text:g(c.substring(0,a))}});var d=c.search("]");a=c.substring(a,d+1);b.push(f(a));c=c.substring(d+1)}return b}var k={"&":"&amp;",",":"&#44","[":"&#91;","]":"&#93;"};function l(a){for(var b in k)a=a.h(b,k[b]);return a}function g(a){for(var b in k)a=a.h(k[b],b);return a}
function m(a){return`[CQ:${a.type}${a.data?`,${Object.entries(a.data).map(b=>["string","number"].includes(typeof b[1])?b[0]+"="+l(b[1]):"").join(",")}`:""}]`}module.exports={parseOne:f,parse:h,tryParse:function(a){try{return h(a)}catch(b){return[]}},escapeString:l,unescapeString:g,stringifyOne:m,stringify:function(a){var b=[],c;for(c of a){let d;"text"===c.type&&(null==(d=c.data)?0:d.text)?b.push(c.data.text):b.push(m(c))}return b.join("")}};
type CQMessage = any
const cqRegExp = /^\[CQ:(?<type>\w+?)(?<params>(?:,(?:\w+?)=(?:[^\[\]\$\,]+?))*)?\]$/
export function parseOne(cqcode: string): CQMessage {
const matchResult = cqcode.match(cqRegExp)
if (matchResult && matchResult.groups) {
const data: { [_: string]: string } = {}
if (typeof matchResult.groups.params === 'string') {
const params = matchResult.groups.params.substring(1).split(',')
for (const paramPair of params) {
const equalPos = paramPair.indexOf('=')
const key = paramPair.substring(0, equalPos)
const value = paramPair.substring(equalPos + 1)
data[key] = unescapeString(value)
}
}
return {
type: matchResult.groups.type,
data
}
} else {
throw new Error('Input isn\'t a single cqcode.')
}
}
export function parse(cqcode: string): CQMessage[] {
const result = []
let str = cqcode
while (str.length) {
const nextLeft = str.search(/\[CQ:/)
if (nextLeft === -1) { // No more cqcode, push them as text
result.push({
type: 'text',
data: { text: unescapeString(str) }
})
str = ''
} else {
if (nextLeft > 0) {
result.push({
type: 'text',
data: { text: unescapeString(str.substring(0, nextLeft)) }
})
}
const nextRight = str.search(']')
const cqcode = str.substring(nextLeft, nextRight + 1)
result.push(parseOne(cqcode))
str = str.substring(nextRight + 1)
}
}
return result
}
export function tryParse(cqcode: string): CQMessage[] {
try {
return parse(cqcode)
} catch {
return []
}
}
const cqEscapes: { [char: string]: string } = {
'&': '&amp;',
',': '&#44',
'[': '&#91;',
']': '&#93;'
}
export function escapeString(data: string) {
let result = data
for (const key in cqEscapes) {
result = result.replaceAll(key, cqEscapes[key])
}
return result
}
export function unescapeString(data: string) {
let result = data
for (const key in cqEscapes) {
result = result.replaceAll(cqEscapes[key], key)
}
return result
}
export function stringifyOne(cqcode: CQMessage) {
return `[CQ:${cqcode.type}${cqcode.data ? `,${Object.entries(cqcode.data).map(v => {
if (!['string', 'number'].includes(typeof v[1])) return ''
let a = v[0] + '=' + escapeString(v[1] as string)
return a
}).join(',')
}` : ''}]`
}
export function stringify(cqcodes: CQMessage[]) {
const result = []
for (const cqcode of cqcodes) {
if (cqcode.type === 'text' && cqcode.data?.text) {
result.push(cqcode.data.text)
} else {
result.push(stringifyOne(cqcode))
}
}
return result.join('')
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment