mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-06-27 21:05:53 +00:00
Initial commit for converting FrankerFaceZ to TypeScript.
This commit is contained in:
parent
ba72969c51
commit
b9d23accf0
86 changed files with 8673 additions and 5005 deletions
145
src/utilities/path-parser.ts
Normal file
145
src/utilities/path-parser.ts
Normal file
|
@ -0,0 +1,145 @@
|
|||
'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));
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue