initial parser logic. still needs fixing for Text
This commit is contained in:
parent
71acab3e54
commit
b81ac470c5
2 changed files with 243 additions and 26 deletions
|
|
@ -8,6 +8,7 @@ export const api = new Elysia({ prefix: '/api' })
|
||||||
const releaseYear = movie.release_date.substring(0, 4);
|
const releaseYear = movie.release_date.substring(0, 4);
|
||||||
const voteAverage = movie.vote_average.toFixed(2);
|
const voteAverage = movie.vote_average.toFixed(2);
|
||||||
|
|
||||||
|
// return Gin.render("card", movie);
|
||||||
return Yuck.renderMoviePage(
|
return Yuck.renderMoviePage(
|
||||||
movie.id,
|
movie.id,
|
||||||
movie.title,
|
movie.title,
|
||||||
|
|
@ -22,6 +23,7 @@ export const api = new Elysia({ prefix: '/api' })
|
||||||
const releaseYear = movie.release_date.substring(0, 4);
|
const releaseYear = movie.release_date.substring(0, 4);
|
||||||
const voteAverage = movie.vote_average.toFixed(2);
|
const voteAverage = movie.vote_average.toFixed(2);
|
||||||
|
|
||||||
|
// return Gin.render("movie", movie);
|
||||||
return Yuck.renderMoviePage(
|
return Yuck.renderMoviePage(
|
||||||
movie.id,
|
movie.id,
|
||||||
movie.title,
|
movie.title,
|
||||||
|
|
@ -33,5 +35,6 @@ export const api = new Elysia({ prefix: '/api' })
|
||||||
})
|
})
|
||||||
.get("providers/watch/:id", async ({ params: { id } }) => {
|
.get("providers/watch/:id", async ({ params: { id } }) => {
|
||||||
const providers = await API.providers(parseInt(id));
|
const providers = await API.providers(parseInt(id));
|
||||||
|
// return Gin.render("providers", movie);
|
||||||
return Yuck.renderProviderPage()
|
return Yuck.renderProviderPage()
|
||||||
});
|
});
|
||||||
|
|
|
||||||
266
src/util/gin.ts
266
src/util/gin.ts
|
|
@ -1,39 +1,253 @@
|
||||||
// TODO: Finish template engine and parse the data like god intended
|
|
||||||
type GinNode = {
|
const example =
|
||||||
|
`Dear {{.Name}},
|
||||||
|
{{if .Attended}}
|
||||||
|
It was a pleasure to see you at the wedding.
|
||||||
|
{{- else}}
|
||||||
|
It is a shame you couldn't make it to the wedding.
|
||||||
|
{{- end}}
|
||||||
|
{{with .Gift -}}
|
||||||
|
Thank you for the lovely {{.}}.
|
||||||
|
{{end}}
|
||||||
|
Best wishes,
|
||||||
|
Josie`;
|
||||||
|
|
||||||
|
type Node = {
|
||||||
|
type: 'Text' | 'Data' | 'Conditional' | 'Marker' | 'Container' | 'Empty'
|
||||||
|
|
||||||
path: string;
|
// Text
|
||||||
children: GinNode[];
|
startIndex?: number;
|
||||||
|
endIndex?: number;
|
||||||
|
text?: string;
|
||||||
|
|
||||||
|
// Data
|
||||||
|
key?: string;
|
||||||
|
|
||||||
|
// Conditional
|
||||||
|
conditionType?: 'if' | 'with';
|
||||||
|
condition?: Node;
|
||||||
|
consequent?: Node;
|
||||||
|
alternative?: Node;
|
||||||
|
|
||||||
|
// Marker
|
||||||
|
markerType?: 'else' | 'end';
|
||||||
|
|
||||||
|
// Container
|
||||||
|
placeholders?: Node[],
|
||||||
|
|
||||||
|
// Scoping
|
||||||
|
parent?: Node;
|
||||||
|
};
|
||||||
|
|
||||||
|
function parse(text: string): Node {
|
||||||
|
let root: Node = {
|
||||||
|
type: 'Container',
|
||||||
|
placeholders: []
|
||||||
|
};
|
||||||
|
return _parse(text, root);
|
||||||
}
|
}
|
||||||
|
|
||||||
class Gin {
|
function _parse(text: string, root: Node): Node {
|
||||||
|
if (!text || text.length < 1) {
|
||||||
|
return root;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
let i = 0;
|
||||||
* Preprocess template files from a given path into some data structure that tags them and notes substitutable areas
|
const open = [];
|
||||||
*
|
let prevScope = root;
|
||||||
* @param path
|
let scope = root;
|
||||||
*/
|
|
||||||
setup(path: string) {}
|
|
||||||
|
|
||||||
/**
|
let textNode: Node = {
|
||||||
* Creates HTML string from named template and supplied data
|
type: 'Text',
|
||||||
*
|
startIndex: 0,
|
||||||
* @param name
|
endIndex: 0
|
||||||
* @param mappings
|
|
||||||
*/
|
|
||||||
render(name: string, data: Record<string, string | number>): string {
|
|
||||||
return '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs actual dependency tree. Parsing is prob gonna be some recursive business
|
let altPath = false;
|
||||||
*
|
while (i < text.length) {
|
||||||
* @param path
|
textNode.endIndex = i;
|
||||||
*/
|
|
||||||
private crawl(path: string): GinNode | undefined {
|
if (text.substring(i, i+2) == '{{') {
|
||||||
return;
|
open.push(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (text.substring(i, i+2) == '}}') {
|
||||||
|
textNode.parent = scope;
|
||||||
|
textNode.text = text.substring(textNode.startIndex!, textNode.endIndex!)
|
||||||
|
switch (scope.type) {
|
||||||
|
case 'Container':
|
||||||
|
scope.placeholders!.push(textNode)
|
||||||
|
break;
|
||||||
|
case 'Conditional':
|
||||||
|
const placeholders = (altPath) ? scope.alternative!.placeholders! : scope.consequent!.placeholders!;
|
||||||
|
placeholders.push(textNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
const j = open.pop()!;
|
||||||
|
|
||||||
|
textNode = {
|
||||||
|
type: 'Text',
|
||||||
|
startIndex: j+2,
|
||||||
|
endIndex: i
|
||||||
|
};
|
||||||
|
|
||||||
|
const command = parseCommand(text, j+2, i);
|
||||||
|
command.parent = scope;
|
||||||
|
|
||||||
|
if (command.type == 'Marker') {
|
||||||
|
switch (command.markerType) {
|
||||||
|
case 'end':
|
||||||
|
scope = prevScope;
|
||||||
|
altPath = false;
|
||||||
|
break;
|
||||||
|
case 'else':
|
||||||
|
altPath = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (command.type == 'Conditional') {
|
||||||
|
scope.placeholders!.push(command)
|
||||||
|
prevScope = scope;
|
||||||
|
scope = command!;
|
||||||
|
} else {
|
||||||
|
switch (scope.type) {
|
||||||
|
case 'Container':
|
||||||
|
scope.placeholders!.push(command)
|
||||||
|
break;
|
||||||
|
case 'Conditional':
|
||||||
|
const placeholders = (altPath) ? scope.alternative!.placeholders! : scope.consequent!.placeholders!;
|
||||||
|
placeholders.push(command);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (textNode.startIndex! < textNode.endIndex!) {
|
||||||
|
textNode.parent = scope;
|
||||||
|
textNode.text = text.substring(textNode.startIndex!, textNode.endIndex!)
|
||||||
|
scope.placeholders!.push(textNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseCommand(text: string, i: number, j: number): Node {
|
||||||
|
let node: Node = {
|
||||||
|
type: 'Empty'
|
||||||
|
};
|
||||||
|
|
||||||
|
if (i >= j) {
|
||||||
|
return node;
|
||||||
|
};
|
||||||
|
|
||||||
|
let view = text.substring(i, j);
|
||||||
|
|
||||||
|
|
||||||
|
// not supported
|
||||||
|
if (view.startsWith("- ")) {
|
||||||
|
i += 2;
|
||||||
|
view = text.substring(i, j);
|
||||||
|
}
|
||||||
|
|
||||||
|
// not supported
|
||||||
|
if (view.endsWith(" -")) {
|
||||||
|
j -= 2;
|
||||||
|
view = text.substring(i, j);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (view.startsWith('.')) {
|
||||||
|
node = parseDataText(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (view.startsWith('if') || view.trim().startsWith('with')) {
|
||||||
|
node = parseConditionalText(text, i, j);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (view == 'else' || view == 'end') {
|
||||||
|
node.type = 'Marker';
|
||||||
|
node.markerType = view;
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
};
|
||||||
|
|
||||||
|
function parseConditionalText(text: string, i: number, j: number): Node {
|
||||||
|
const view = text.substring(i, j);
|
||||||
|
|
||||||
|
let node: Node = {
|
||||||
|
type: 'Conditional',
|
||||||
|
conditionType: view.startsWith('if') ? 'if' : 'with',
|
||||||
|
consequent: {
|
||||||
|
type: 'Container',
|
||||||
|
placeholders: []
|
||||||
|
},
|
||||||
|
alternative: {
|
||||||
|
type: 'Container',
|
||||||
|
placeholders: []
|
||||||
|
},
|
||||||
|
};
|
||||||
|
node.consequent!.parent = node;
|
||||||
|
node.alternative!.parent = node;
|
||||||
|
|
||||||
|
const pipelineStart = i + view.indexOf(' ') + 1;
|
||||||
|
const pipelineView = text.substring(pipelineStart, j)
|
||||||
|
|
||||||
|
if (pipelineView.startsWith('.')) {
|
||||||
|
node.condition = {
|
||||||
|
type: 'Data',
|
||||||
|
key: pipelineView,
|
||||||
|
parent: node,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
node.condition = {
|
||||||
|
type: 'Text',
|
||||||
|
startIndex: pipelineStart,
|
||||||
|
endIndex: j,
|
||||||
|
text: pipelineView,
|
||||||
|
parent: node,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseDataText(text: string): Node {
|
||||||
|
return {
|
||||||
|
type: 'Data',
|
||||||
|
key: text.trim()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function printNode(node: Node, offset='') {
|
||||||
|
switch (node.type) {
|
||||||
|
case 'Conditional':
|
||||||
|
console.log(`${offset}${node.conditionType}`);
|
||||||
|
console.log(`${offset}Condition:\n`)
|
||||||
|
printNode(node.condition!, offset + '\t')
|
||||||
|
console.log(`${offset}Then:\n`)
|
||||||
|
printNode(node.consequent!, offset + '\t')
|
||||||
|
console.log(offset + 'Else:\n')
|
||||||
|
printNode(node.alternative!, offset + '\t')
|
||||||
|
break;
|
||||||
|
case 'Container':
|
||||||
|
console.log(offset + node.type)
|
||||||
|
for (let p of node.placeholders ?? []) {
|
||||||
|
printNode(p, offset + '|__');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'Data':
|
||||||
|
console.log(`${offset}${node.type} [key=${node.key}]`);
|
||||||
|
break;
|
||||||
|
case 'Text':
|
||||||
|
console.log(`${offset}${node.type} [text=${JSON.stringify(node.text)}]`);
|
||||||
|
default:
|
||||||
|
console.log(`${offset}${node.type}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
printNode(parse(example));
|
||||||
/**
|
/**
|
||||||
* Stopgap :(
|
* Stopgap :(
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue