statigen
Version:
A static site generator that supports html, ejs, and markdown source files
212 lines • 8.9 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Project = void 0;
const PluginManager_1 = require("./PluginManager");
const InternalPlugin_1 = require("./InternalPlugin");
const diagnosticUtils_1 = require("./diagnosticUtils");
const path = require("path");
const util_1 = require("./util");
const DiagnosticMessages_1 = require("./DiagnosticMessages");
const Tree_1 = require("./Tree");
const fsExtra = require("fs-extra");
class Project {
constructor(options) {
this.pluginManager = new PluginManager_1.default();
/**
* Map of all files in the project, indexed by absolute path
*/
this.files = new Map();
this.pluginManager.add(new InternalPlugin_1.InternalPlugin());
this.setOptions(options);
}
/**
* Get the diagnostics from all files
*/
getDiagnostics() {
const result = [];
for (const file of this.files.values()) {
result.push(...file.diagnostics);
}
return result;
}
/**
* Get the file with the specified path
*/
getFile(filePath) {
filePath = path.resolve(this.options.sourceDir, filePath).replace(/[\\\/]/g, path.sep);
return this.files.get(filePath);
}
/**
* Get a tree of all the html files based on their output paths
*/
getTree() {
if (!this.cache.tree) {
this.cache.tree = new Tree_1.Tree(undefined, undefined, undefined);
for (let file of this.files.values()) {
const filename = path.basename(file.outPath);
//skip files starting with underscore, and skip all non-html files
if (filename.startsWith('_') || !filename.toLowerCase().endsWith('.html')) {
continue;
}
const relativePath = file.outPath.replace(this.options.outDir + path.sep, '').replace(/\.\w$/, '');
this.cache.tree.add(relativePath, file);
}
this.cache.tree.sort();
}
return this.cache.tree;
}
setFile(param) {
var _a;
let srcPath;
let outPath;
if (typeof param === 'string') {
srcPath = path.resolve(this.options.sourceDir, param);
outPath = (0, util_1.replacePath)(path.resolve(this.options.outDir, param), this.options.sourceDir, this.options.outDir);
}
else {
srcPath = path.resolve(this.options.sourceDir, param.src);
outPath = path.resolve(this.options.outDir, param.dest);
}
let file = this.files.get(srcPath);
//add the file
if (!file) {
file = this.pluginManager.getFirst('provideFile', {
project: this,
srcPath: srcPath,
outPath: outPath
});
//link this project to the file
file.project = this;
this.files.set(srcPath, file);
this.pluginManager.emit('onFileAdd', { project: this, file: file });
}
this.pluginManager.emit('beforeFileLoad', { project: this, file: file });
//if the file has a load function
(_a = file.load) === null || _a === void 0 ? void 0 : _a.call(file);
this.pluginManager.emit('afterFileLoad', { project: this, file: file });
return file;
}
/**
* Remove a file from the project
*/
removeFile(srcPath) {
srcPath = path.resolve(this.options.sourceDir, srcPath);
const file = this.files.get(srcPath);
if (file) {
this.pluginManager.emit('onFileRemove', { project: this, file: file });
this.files.delete(srcPath);
//delete the file from the outDir too
if (fsExtra.pathExistsSync(file.outPath)) {
fsExtra.removeSync(file.outPath);
}
}
}
/**
* Validate the entire project
*/
validate() {
var _a, _b;
for (const file of this.files.values()) {
file.diagnostics = [];
this.pluginManager.emit('beforeFileValidate', { project: this, file: file });
(_a = file.validate) === null || _a === void 0 ? void 0 : _a.call(file);
this.pluginManager.emit('afterFileValidate', { project: this, file: file });
for (const diagnostic of (_b = file.diagnostics) !== null && _b !== void 0 ? _b : []) {
(0, diagnosticUtils_1.printDiagnostic)(diagnostic);
}
}
}
/**
* Determine if the given file exists somewhere within the sourceDir
*/
fileResidesInSourceDir(file) {
return file.srcPath.startsWith(this.options.sourceDir);
}
/**
* Get the template file for a given file
*/
getTemplateFile(file) {
var _a;
//if the file specified a template, use that file (even if it doesn't exist...)
if (file.attributes.template) {
const templateSrcPath = (0, util_1.standardizePath)(path.dirname(file.srcPath), file.attributes.template);
if (!this.files.has(templateSrcPath)) {
file.diagnostics.push(Object.assign({ file: file }, DiagnosticMessages_1.DiagnosticMessages.missingTemplate(templateSrcPath)));
}
return this.files.get(templateSrcPath);
//files outside of sourceDir
}
else if (!this.fileResidesInSourceDir(file)) {
return (_a = this.files.get((0, util_1.standardizePath)(path.dirname(file.srcPath), '_template.html'))) !== null && _a !== void 0 ? _a : this.files.get((0, util_1.standardizePath)(path.dirname(file.srcPath), '_template.ejs'));
//files inside sourceDir
}
else {
//walk up the directory tree and use the closest _template.{ejs,html} file
let dir = file.srcPath.replace(this.options.sourceDir + path.sep, '');
// eslint-disable-next-line no-cond-assign
while (dir = path.dirname(dir)) {
for (const ext of ['.ejs', '.html']) {
const templatePath = path.resolve(this.options.sourceDir, path.normalize(path.join(dir, '_template' + ext)));
if (this.files.has(templatePath)) {
return this.files.get(templatePath);
}
}
//quit the loop if we didn't find a template
if (dir === '.') {
return;
}
}
}
}
/**
* Given a file, look up its template and then generate the output text
* using the ejs templating engine.
* If the template could not be found, the content is returned as-is
*/
generateWithTemplate(file, content) {
var _a;
const templateFile = this.getTemplateFile(file);
if (templateFile === null || templateFile === void 0 ? void 0 : templateFile.renderAsTemplate) {
//return template rendered (or empty string)
return (_a = templateFile.renderAsTemplate(file, content)) !== null && _a !== void 0 ? _a : '';
}
else {
//no template was found. return the content as-is (or empty string)
return content !== null && content !== void 0 ? content : '';
}
}
publish() {
var _a;
this.cache = {};
for (const file of this.files.values()) {
this.pluginManager.emit('beforeFilePublish', { project: this, file: file });
const startsWithUnderscore = path.basename(file.srcPath).startsWith('_');
//skip publishing if the file starts with an underscore, or if the
if (!startsWithUnderscore) {
(_a = file.publish) === null || _a === void 0 ? void 0 : _a.call(file);
}
this.pluginManager.emit('afterFilePublish', { project: this, file: file });
}
}
/**
* Sanitize the given options in-place
*/
setOptions(options) {
var _a;
this.options = {};
this.options.cwd = (0, util_1.standardizePath)(process.cwd(), options.cwd).replace(/[\\\/]+$/, '');
this.options.sourceDir = this.resolvePath(options.sourceDir, 'src').replace(/[\\\/]+$/, '');
this.options.outDir = this.resolvePath(options.outDir, 'dist').replace(/[\\\/]+$/, '');
this.options.files = (_a = options.files) !== null && _a !== void 0 ? _a : ['**/*'];
this.options.watch = options.watch === true;
return options;
}
/**
* Given a path, convert to an absolute path and use the current OS path.sep
*/
resolvePath(thePath, defaultValue) {
return path.normalize(path.resolve(this.options.cwd, thePath !== null && thePath !== void 0 ? thePath : defaultValue)).replace(/[\\\/]/g, path.sep);
}
}
exports.Project = Project;
//# sourceMappingURL=Project.js.map