1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-06-27 12:55:55 +00:00
FrankerFaceZ/src/utilities/path-parser.ts

145 lines
No EOL
2.3 KiB
TypeScript

'use strict';
export function parse(path: string) {
return parseAST({
path,
i: 0
});
}
type ParseContext = {
path: string;
i: number;
}
export type PathNode = {
title: string;
key: string;
page: boolean;
tab: boolean;
}
function parseAST(ctx: ParseContext) {
const path = ctx.path,
length = path.length,
out = [];
let token: PathNode | null = null,
raw: string | null = null;
let old_tab = false,
old_page = false;
while ( ctx.i < length ) {
const start = ctx.i,
char = path[start],
next = path[start + 1];
if ( ! token )
token = {} as PathNode;
if ( ! raw )
raw = '';
// JSON
if ( char === '@' && next === '{') {
ctx.i++;
const tag = parseJSON(ctx);
if ( tag )
Object.assign(token, tag);
continue;
}
// Segment End?
const tab = char === `~` && next === '>',
page = char === '>' && next === '>',
segment = ! page && char === '>';
if ( ! segment && ! page && ! tab ) {
raw += char;
ctx.i++;
continue;
}
// We're at the end of a segment, so push
// the token out.
if ( tab || page )
ctx.i++;
token.title = raw.trim();
token.key = token.title.toSnakeCase();
token.page = old_page;
token.tab = old_tab;
old_page = page;
old_tab = tab;
out.push(token);
token = raw = null;
ctx.i++;
}
if ( token && raw ) {
token.title = raw.trim();
token.key = token.title.toSnakeCase();
token.page = old_page;
token.tab = old_tab;
out.push(token);
}
return out;
}
function parseJSON(ctx: ParseContext) {
const path = ctx.path,
length = path.length,
start = ctx.i;
ctx.i++;
const stack = ['{'];
let string: string | boolean = false;
while ( ctx.i < length && stack.length ) {
const start = ctx.i,
char = path[start];
if ( string ) {
if ( char === '\\' ) {
ctx.i++;
continue;
}
if ( (char === '"' || char === "'") && char === string ) {
stack.pop();
string = false;
}
} else {
if ( char === '"' || char === "'" ) {
string = char;
stack.push(char);
}
if ( char === '{' || char === '[' )
stack.push(char);
if ( char === ']' ) {
if ( stack.pop() !== '[' )
throw new SyntaxError('Invalid JSON');
}
if ( char === '}' ) {
if ( stack.pop() !== '{' )
throw new SyntaxError('Invalid JSON');
}
}
ctx.i++;
}
return JSON.parse(path.slice(start, ctx.i));
}