close enough for a parse fix
This commit is contained in:
parent
10003a1167
commit
435103a304
2 changed files with 169 additions and 42 deletions
|
|
@ -1,17 +1,3 @@
|
||||||
|
|
||||||
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 Node = {
|
||||||
type: 'Text' | 'Data' | 'Conditional' | 'Marker' | 'Container' | 'Empty'
|
type: 'Text' | 'Data' | 'Conditional' | 'Marker' | 'Container' | 'Empty'
|
||||||
|
|
||||||
|
|
@ -39,13 +25,11 @@ type Node = {
|
||||||
parent?: Node;
|
parent?: Node;
|
||||||
};
|
};
|
||||||
|
|
||||||
function parse(text: string): Node {
|
type Template = {
|
||||||
let root: Node = {
|
name: string;
|
||||||
type: 'Container',
|
root: Node;
|
||||||
placeholders: []
|
};
|
||||||
};
|
|
||||||
return _parse(text, root);
|
|
||||||
}
|
|
||||||
|
|
||||||
function _parse(text: string, root: Node): Node {
|
function _parse(text: string, root: Node): Node {
|
||||||
if (!text || text.length < 1) {
|
if (!text || text.length < 1) {
|
||||||
|
|
@ -130,7 +114,7 @@ function _parse(text: string, root: Node): Node {
|
||||||
|
|
||||||
if (textNode.startIndex! < textNode.endIndex!) {
|
if (textNode.startIndex! < textNode.endIndex!) {
|
||||||
textNode.parent = scope;
|
textNode.parent = scope;
|
||||||
textNode.text = text.substring(textNode.startIndex!, textNode.endIndex!)
|
textNode.text = text.substring(textNode.startIndex!, textNode.endIndex! + 1)
|
||||||
scope.placeholders!.push(textNode);
|
scope.placeholders!.push(textNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -223,7 +207,65 @@ function parseDataText(text: string): Node {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function printNode(node: Node, offset='') {
|
function _execute(node: Node, data: Record<string, any> | string, build: string): string {
|
||||||
|
if (!node) {
|
||||||
|
return build;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (node.type) {
|
||||||
|
case 'Container':
|
||||||
|
return build + node.placeholders!.map(p => _execute(p, data, '')).join('');
|
||||||
|
case 'Conditional':
|
||||||
|
const condEval = _execute(node.condition!, data, '');
|
||||||
|
let value = condEval;
|
||||||
|
try {
|
||||||
|
value = JSON.parse(value);
|
||||||
|
} catch (e) {}
|
||||||
|
if (node.conditionType == 'if') {
|
||||||
|
// BREH JS BS (without the parenthesis it includes build in its ternary condition -.-)
|
||||||
|
return build + (!!value ?
|
||||||
|
_execute(node.consequent!, data, '') :
|
||||||
|
_execute(node.alternative!, data, ''))
|
||||||
|
} else {
|
||||||
|
// BREH JS BS
|
||||||
|
return build + (!!value ?
|
||||||
|
_execute(node.consequent!, value, '') :
|
||||||
|
_execute(node.alternative!, value, ''))
|
||||||
|
}
|
||||||
|
case 'Data':
|
||||||
|
if (node.key == ".") {
|
||||||
|
if (typeof data === 'string') {
|
||||||
|
return build + data
|
||||||
|
} else {
|
||||||
|
return build + JSON.stringify(data);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (typeof data === 'object') {
|
||||||
|
const inner = data[node.key!.substring(1)]
|
||||||
|
if (typeof inner === 'string') {
|
||||||
|
return build + inner
|
||||||
|
}
|
||||||
|
return build + JSON.stringify(inner);
|
||||||
|
}
|
||||||
|
throw new Error('huh?')
|
||||||
|
}
|
||||||
|
case 'Text':
|
||||||
|
return node.text!;
|
||||||
|
default:
|
||||||
|
return build + '[NOT_IMPLEMENTED]'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export namespace Gin {
|
||||||
|
export function parse(text: string): Node {
|
||||||
|
let root: Node = {
|
||||||
|
type: 'Container',
|
||||||
|
placeholders: []
|
||||||
|
};
|
||||||
|
return _parse(text, root);
|
||||||
|
};
|
||||||
|
|
||||||
|
export function printNode(node: Node, offset='') {
|
||||||
switch (node.type) {
|
switch (node.type) {
|
||||||
case 'Conditional':
|
case 'Conditional':
|
||||||
console.log(`${offset}${node.conditionType}`);
|
console.log(`${offset}${node.conditionType}`);
|
||||||
|
|
@ -249,9 +291,13 @@ function printNode(node: Node, offset='') {
|
||||||
default:
|
default:
|
||||||
console.log(`${offset}${node.type}`);
|
console.log(`${offset}${node.type}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function execute(template: Template, data: Record<string, any>) {
|
||||||
|
return _execute(template.root, data, '');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
printNode(parse(example));
|
|
||||||
/**
|
/**
|
||||||
* Stopgap :(
|
* Stopgap :(
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
81
test/util/gin.test.ts
Normal file
81
test/util/gin.test.ts
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
import { describe, it, expect } from 'bun:test'
|
||||||
|
import { Gin } from '../../src/util/gin'
|
||||||
|
|
||||||
|
describe('Gin template porting test', () => {
|
||||||
|
it('parse', async () => {
|
||||||
|
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`;
|
||||||
|
|
||||||
|
const template = {
|
||||||
|
name: 'example',
|
||||||
|
root: Gin.parse(example)
|
||||||
|
};
|
||||||
|
|
||||||
|
const data = [
|
||||||
|
{
|
||||||
|
Name: 'Aunt Mildred',
|
||||||
|
Gift: 'bone china tea set',
|
||||||
|
Attended: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: 'Uncle John',
|
||||||
|
Gift: 'moleskin pants',
|
||||||
|
Attended: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: 'Cousin Rodney',
|
||||||
|
Gift: '',
|
||||||
|
Attended: false,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const expected =
|
||||||
|
`Dear Aunt Mildred,
|
||||||
|
|
||||||
|
It was a pleasure to see you at the wedding.
|
||||||
|
Thank you for the lovely bone china tea set.
|
||||||
|
|
||||||
|
Best wishes,
|
||||||
|
Josie
|
||||||
|
|
||||||
|
Dear Uncle John,
|
||||||
|
|
||||||
|
It is a shame you couldn't make it to the wedding.
|
||||||
|
Thank you for the lovely moleskin pants.
|
||||||
|
|
||||||
|
Best wishes,
|
||||||
|
Josie
|
||||||
|
|
||||||
|
Dear Cousin Rodney,
|
||||||
|
|
||||||
|
It is a shame you couldn't make it to the wedding.
|
||||||
|
|
||||||
|
Best wishes,
|
||||||
|
Josie`
|
||||||
|
|
||||||
|
const actual = data.map(r => Gin.execute(template, r)).join('\n');
|
||||||
|
console.log(actual)
|
||||||
|
expect(actual).toEqual(expected);
|
||||||
|
})
|
||||||
|
|
||||||
|
// it('parseGlob', async () => {
|
||||||
|
// const gin = new Gin();
|
||||||
|
// const paths = await gin.parseGlob('public/**/*html');
|
||||||
|
// })
|
||||||
|
|
||||||
|
// it('parseHTML', async () => {
|
||||||
|
// const gin = new Gin();
|
||||||
|
// const text = await gin.parseHTML('public/pages/movie.html');
|
||||||
|
// console.log(text);
|
||||||
|
// })
|
||||||
|
})
|
||||||
Loading…
Add table
Add a link
Reference in a new issue