UNPKG

@tsed/cli

Version:
128 lines (127 loc) 4.66 kB
import { join } from "node:path"; import { CliFs } from "@tsed/cli-core"; import { constant, context, inject, injectable, injectMany, lazyInject, logger } from "@tsed/di"; import { globby } from "globby"; import { TEMPLATE_DIR } from "../constants/index.js"; import { mapDefaultTemplateOptions } from "./mappers/mapDefaultTemplateOptions.js"; export class CliTemplatesService { constructor() { this.fs = inject(CliFs); } // readonly renderedFiles: TemplateRenderReturnType[] = []; #customTemplates; get rootDir() { return constant("project.rootDir", ""); } get srcDir() { return join(...[this.rootDir, constant("project.srcDir")].filter(Boolean)); } get templatesDir() { return join(this.rootDir, ".templates"); } $onInit() { return this.loadTemplates(); } async loadTemplates() { if (!this.#customTemplates?.length) { const files = await globby("**/*.ts", { cwd: this.templatesDir }); const promises = files.map(async (file) => { try { const modulePath = join(this.templatesDir, file); return await lazyInject(() => import(modulePath)); } catch (er) { logger().warn("Unable to load custom template %s: %s", file, er.message); } }); let customs = await Promise.all(promises); this.#customTemplates = customs .filter((template) => !!template) .map((template) => { return { ...template, label: template.label + " (custom)" }; }); } } getAll() { const templates = injectMany("CLI_TEMPLATES"); const map = (this.#customTemplates || []).concat(templates).reduce((acc, template) => { if (acc.has(template.id)) { return acc; } return acc.set(template.id, template); }, new Map()); return [...map.values()]; } find(id) { const templates = this.getAll().filter((template) => !template.hidden); if (id) { id = id?.toLowerCase(); const foundTemplates = templates.filter((template) => { return template.label.toLowerCase().includes(id) || template.id.includes(id); }); return foundTemplates.length ? foundTemplates : templates; } return templates; } get(id) { return this.getAll().find((template) => template.id === id); } async render(templateId, data) { const template = this.get(templateId); if (template) { const opts = mapDefaultTemplateOptions({ ...data, type: templateId }); const render = await template.render(opts.symbolName, opts); if (render === undefined) { return; } if (typeof render === "object") { return render; } const filePath = opts.symbolPath || template.fileName?.replace("{{symbolName}}", opts.symbolName)?.replace("{{srcDir}}", this.srcDir) || opts.symbolName; const outputPath = `${filePath}${template.ext ? "." + template.ext : ""}`; return this.pushRenderResult({ templateId, content: render, outputPath, name: opts.name, symbolName: opts.symbolName, symbolPath: opts.symbolPath, symbolPathBasename: opts.symbolPathBasename }); } else { const from = data.from || TEMPLATE_DIR; const fromPath = join(from, templateId.replace("{{srcDir}}", "src")); if (await this.fs.fileExists(fromPath)) { const content = await inject(CliFs).readFile(fromPath); return this.pushRenderResult({ templateId, content, outputPath: templateId.replace("{{srcDir}}", constant("project.srcDir", "")) }); } } } getRenderedFiles() { const $ctx = context(); if (!$ctx?.has("renderedFiles")) { $ctx?.set("renderedFiles", []); } return $ctx?.get("renderedFiles") || []; } pushRenderResult(renderedFile) { this.getRenderedFiles().push(renderedFile); return renderedFile; } } injectable(CliTemplatesService);