@tsed/cli
Version:
CLI to bootstrap your Ts.ED project
163 lines (162 loc) • 6 kB
JavaScript
import { __decorate } from "tslib";
import "../utils/hbs/index.js";
import { basename, dirname, join, relative } from "node:path";
import { CliFs } from "@tsed/cli-core";
import { isString } from "@tsed/core";
import { constant, inject, Injectable } from "@tsed/di";
import { normalizePath } from "@tsed/normalize-path";
import Consolidate from "consolidate";
import fs from "fs-extra";
import { globby } from "globby";
import handlebars from "handlebars";
import { Observable } from "rxjs";
import { insertAfter } from "../utils/renderer/insertAfter.js";
import { insertImport } from "../utils/renderer/insertImport.js";
export class Renderer {
constructor() {
this.templateDir = constant("templateDir", "");
this.fs = inject(CliFs);
this.cache = new Set();
}
async loadPartials(cwd) {
if (this.cache.has(cwd)) {
return;
}
const files = await globby("**/_partials/*.hbs", {
cwd
});
files.forEach((filename) => {
let template = this.fs.readFileSync(join(cwd, filename), "utf8");
const name = basename(filename).replace(".hbs", "");
handlebars.registerPartial(name, template);
});
this.cache.add(cwd);
}
async render(path, data, options = {}) {
const { output, templateDir, rootDir } = this.mapOptions(path, options);
let content = "";
const file = normalizePath(join(templateDir, path));
options.baseDir && (await this.loadPartials(join(templateDir, options.baseDir)));
if (path.endsWith(".hbs")) {
content = await Consolidate.handlebars(file, data);
}
else {
content = await this.fs.readFile(file, { encoding: "utf8" });
}
return this.write(content, { output, rootDir });
}
renderAll(paths, data, options = {}) {
let count = 0;
const mapOptions = (opts) => {
if (isString(opts)) {
return { ...options, path: opts };
}
return {
...options,
...opts
};
};
return new Observable((observer) => {
observer.next(`[${count}/${paths.length}] Rendering files...`);
const promises = paths
.filter(Boolean)
.map(mapOptions)
.map(async ({ path, ...opts }) => {
await this.render(path, data, opts);
count++;
observer.next(`[${count}/${paths.length}] Rendering files...`);
});
Promise.all(promises)
.then(() => {
observer.next(`[${count}/${paths.length}] Rendering files...`);
observer.complete();
})
.catch((err) => {
observer.error(err);
});
});
}
async write(content, options) {
const { output, rootDir = this.rootDir } = options;
const outputFile = join(...[rootDir, output].filter(Boolean));
await this.fs.ensureDir(dirname(outputFile));
return this.fs.writeFile(outputFile, content, { encoding: "utf8" });
}
templateExists(path, options = {}) {
const { templateDir } = this.mapOptions(path, options);
return fs.existsSync(join(templateDir, path));
}
async scan(pattern, options = {}) {
const result = await globby(pattern.map((s) => normalizePath(s)), {
...options,
objectMode: true,
cwd: this.rootDir
});
return result.map((entry) => entry.path);
}
relativeFrom(path) {
return relative(dirname(join(this.rootDir, path)), this.rootDir);
}
async update(path, actions) {
path = join(this.rootDir, path);
if (!this.fs.exists(path)) {
return;
}
const content = actions.reduce((fileContent, action) => {
switch (action.type) {
case "import":
return insertImport(fileContent, action.content);
case "insert-after":
return insertAfter(fileContent, action.content, action.pattern);
default:
break;
}
return fileContent;
}, await this.fs.readFile(path, { encoding: "utf8" }));
return this.fs.writeFile(path, content, { encoding: "utf8" });
}
mapOptions(path, options) {
const { templateDir = this.templateDir, rootDir = this.rootDir } = options;
let { output = path } = options;
if (options.baseDir) {
output = normalizePath(join("/", relative(options.baseDir, path)));
}
if (options.basename) {
output = normalizePath(join(dirname(output), options.basename));
}
output = output.replace(/\.hbs$/, "");
if (options.replaces) {
options.replaces.filter(Boolean).forEach((replace) => {
output = output.replace(replace, "");
});
}
return { output, templateDir, rootDir };
}
}
let RootRendererService = class RootRendererService extends Renderer {
get rootDir() {
return constant("project.rootDir", "");
}
};
RootRendererService = __decorate([
Injectable()
], RootRendererService);
export { RootRendererService };
let SrcRendererService = class SrcRendererService extends Renderer {
get rootDir() {
return join(...[constant("project.rootDir"), constant("project.srcDir")].filter(Boolean));
}
};
SrcRendererService = __decorate([
Injectable()
], SrcRendererService);
export { SrcRendererService };
let ScriptsRendererService = class ScriptsRendererService extends Renderer {
get rootDir() {
return join(...[constant("project.rootDir"), constant("project.scriptsDir")].filter(Boolean));
}
};
ScriptsRendererService = __decorate([
Injectable()
], ScriptsRendererService);
export { ScriptsRendererService };