UNPKG

@tsed/json-mapper

Version:
137 lines (136 loc) 3.92 kB
/** * 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(); } }