@tsed/cli
Version:
CLI to bootstrap your Ts.ED project
128 lines (127 loc) • 4.66 kB
JavaScript
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);