UNPKG

@compas/code-gen

Version:

Generate various boring parts of your server

70 lines (61 loc) 1.99 kB
import { isNil } from "@compas/stdlib"; import { cleanTemplateOutput } from "../utils.js"; const MAX_COLLECT_LOOP = 13; /** * @callback StateFn * @param {import("../../generated/common/types").CodeGenTemplateState} state * @returns {boolean|number|string|undefined|StateFn|Function} */ /** * @param {TemplateStringsArray | string[]} strings * @param {...((StateFn|string|any) | (StateFn|string|any)[])} args * @returns {string} */ export function js(strings, ...args) { /** * @type {import("../../generated/common/types").CodeGenTemplateState} */ const state = { phase: "init", }; for (let i = 0; i < MAX_COLLECT_LOOP + 2; i++) { let changed = false; for (let i = 0; i < args.length; i++) { if (typeof args[i] === "function") { const result = args[i](state); // If function returns any value, replace it // This works for strings, but also allows functions to replace themselves with // another oen if (!isNil(result)) { args[i] = result; changed = true; } } } if (state.phase === "init") { // init phase only has one iteration state.phase = "collect"; } else if (state.phase === "finish") { // finish phase only has one iteration break; } else if (!changed && state.phase === "collect") { // Move on if nothing changed state.phase = "finish"; } else if (i === MAX_COLLECT_LOOP && state.phase === "collect") { // Move on if we are out of loop budget state.phase = "finish"; } } // Combine plain strings with the resulting args const result = [strings[0]]; for (let i = 0; i < args.length; ++i) { if (Array.isArray(args[i])) { result.push(args[i].join("\n"), strings[i + 1]); } else if (typeof args[i] === "function") { result.push(strings[i + 1]); } else { result.push(args[i] ?? "", strings[i + 1]); } } return cleanTemplateOutput(result.join("")); }