Add nodes with render and transform

This commit is contained in:
Misode
2020-05-24 02:40:14 +02:00
parent 135b229265
commit d96949c605
6 changed files with 129 additions and 2 deletions

View File

@@ -6,7 +6,9 @@
<title>Document</title>
</head>
<body>
<div id="root"></div>
<div id="view"></div>
<hr>
<div id="source"></div>
<script src="./build/bundle.js"></script>
</body>
</html>

View File

@@ -1 +1,43 @@
document!.getElementById('root')!.textContent = 'Hello world!';
import { EnumNode } from '../nodes/EnumNode'
import { ObjectNode } from '../nodes/ObjectNode'
import { StringNode } from '../nodes/StringNode'
const EntityCollection = ['sheep', 'pig']
const predicateTree = {
id: 'predicate',
fields: {
condition: new EnumNode(['foo', 'bar'], {
transform: (s: string) => (s === 'foo') ? {predicate: 'baz'} : s
}),
predicate: new ObjectNode({
type: new EnumNode(EntityCollection, {}),
nbt: new StringNode()
})
}
};
function renderTree(tree: any, data: any) {
return Object.keys(tree.fields).map(f =>
tree.fields[f].render(f, data[f])
).join('<br>');
}
function serializeTree(tree: any, data: any) {
let res: any = {}
Object.keys(tree.fields).forEach(f =>
res[f] = tree.fields[f].transform(data[f])
)
return JSON.stringify(res);
}
let dummyData = {
condition: 'foo',
chance: 0.4,
predicate: {
nbt: 'hi'
}
}
document!.getElementById('view')!.innerHTML = renderTree(predicateTree, dummyData)
document!.getElementById('source')!.textContent = serializeTree(predicateTree, dummyData)

33
src/nodes/AbstractNode.ts Normal file
View File

@@ -0,0 +1,33 @@
export interface INode<T> {
setParent: (parent: INode<any>) => void
transform: (value: T) => any
render: (field: string, value: T) => string
}
export interface NodeChildren {
[name: string]: INode<any>
}
export interface NodeMods<T> {
transform?: (value: T) => any
}
export abstract class AbstractNode<T> implements INode<T> {
private transformMod = (v: T) => v
protected parent?: INode<any>
constructor(mods?: NodeMods<T>) {
if (mods?.transform) this.transformMod = mods.transform
}
setParent(parent: INode<any>) {
this.parent = parent
}
transform(value: T) {
return this.transformMod(value)
}
abstract render(field: string, value: T): string
}

17
src/nodes/EnumNode.ts Normal file
View File

@@ -0,0 +1,17 @@
import { AbstractNode, NodeMods } from './AbstractNode'
export class EnumNode extends AbstractNode<string> {
private options: string[]
constructor(options: string[], mods?: NodeMods<string>) {
super(mods)
this.options = options
}
render (field: string, value: string) {
return `<span>${field}</span>
<select value="${value}">
${this.options.map(o => `<option>${o}</option>`)}
</select>`
}
}

22
src/nodes/ObjectNode.ts Normal file
View File

@@ -0,0 +1,22 @@
import { AbstractNode, NodeChildren, NodeMods } from './AbstractNode'
export class ObjectNode extends AbstractNode<any> {
private fields: NodeChildren
constructor(fields: NodeChildren, mods?: NodeMods<any>) {
super(mods)
this.fields = fields
Object.values(fields).forEach(child => {
child.setParent(this)
})
}
render(field: string, value: any) {
value = value || {}
return `<span>${field}:</span><div>
${Object.keys(this.fields).map(f => {
return '> ' + this.fields[f].render(f, value[f])
}).join('<br>')}
</div>`
}
}

11
src/nodes/StringNode.ts Normal file
View File

@@ -0,0 +1,11 @@
import { AbstractNode, NodeMods } from './AbstractNode'
export class StringNode extends AbstractNode<string> {
constructor(mods?: NodeMods<string>) {
super(mods)
}
render(field: string, value: string) {
return `<span>${field}</span> <span>${value || ''}</span>`
}
}