@tsed/json-mapper
Version:
Json mapper module for Ts.ED Framework
137 lines (136 loc) • 3.92 kB
JavaScript
/**
* Tiny utility used by the mapper compilers to build executable arrow functions as strings.
* It provides helpers for scoping, branching, and composing mapper fragments before `eval`.
*/
export class Writer {
static { this.object = {
assign(...args) {
return `{ ${args.filter(Boolean).join(", ")} }`;
}
}; }
constructor(root) {
this.body = [];
this._indent = false;
this._root = root;
}
static indent(lines) {
return lines.map((p) => `\t${p}`);
}
static mapper(mapperId, key, options) {
return `execMapper('${mapperId}', ${key}, ${options})`;
}
static mapperFrom(key, options) {
return `execMapper(nameOf(classOf(${key})), ${key}, ${options})`;
}
static options(...args) {
args = args.filter(Boolean);
return !args.length ? "options" : Writer.object.assign("...options", ...args);
}
add(...lines) {
lines = lines.filter((line) => line !== undefined);
lines.length && this.body.push(...lines);
return this;
}
arrow(...args) {
this.add(`(${args.join(", ")}) => {`);
const writer = this.new();
this.add("}");
return writer;
}
build() {
const result = this.body.flatMap((line) => {
return line instanceof Writer ? line.build() : line;
});
return this._indent ? result.map((item) => "\t" + item) : result;
}
callMapper(id, key, ...options) {
return this.set(key, Writer.mapper(id, key, Writer.options(...options)));
}
returnCallMapper(id, key, ...options) {
return this.return(Writer.mapper(id, key, Writer.options(...options)));
}
const(name, line) {
this.add(`const ${name} = ${line};`);
return this;
}
each(iterable, args = []) {
const writer = this.add(iterable + ".forEach((" + args.join(", ") + ") => {").new();
this.add("});");
return writer;
}
if(condition) {
const writer = new IfWriter(condition, this);
this.add(writer);
return writer;
}
switch(input) {
const sw = new SwitchWriter(input);
this.add(sw);
return sw;
}
indent(indent) {
this._indent = indent;
return this;
}
new(indent = true) {
const writer = new Writer(this.root());
writer.indent(indent);
this.add(writer);
return writer;
}
return(line) {
this.add(`return ${line};`);
return this.root();
}
root() {
return this._root || this;
}
set(left, right) {
this.add(`${left} = ${right};`);
return this;
}
toString() {
return this.build().join("\n");
}
}
class IfWriter extends Writer {
constructor(condition, root) {
super();
this.condition = condition;
this._root = root;
}
else() {
const writer = new Writer(this._root);
this.elseWriter = writer;
return writer;
}
build() {
return [
`if (${this.condition}) {`,
...Writer.indent(super.build()),
"}",
this.elseWriter ? [`else {`, ...Writer.indent(this.elseWriter.build()), "}"] : []
].flat();
}
}
class SwitchWriter extends Writer {
#map = new Map();
constructor(input) {
super();
this.input = input;
}
case(condition) {
const writer = new Writer();
this.#map.set(condition, writer);
return writer;
}
build() {
return [
`switch (${this.input}) {`,
...Writer.indent(Array.from(this.#map.entries()).flatMap(([condition, writer]) => {
return [condition === "default" ? `${condition}:` : `case ${condition}:`, ...Writer.indent(writer.build())];
})),
"}"
].flat();
}
}