hikaru-coffee
Version:
A static site generator that generates routes based on directories naturally.
317 lines (287 loc) • 9.96 kB
JavaScript
// Generated by CoffeeScript 2.3.1
(function() {
var Router, dateStrCompare, fm, fse, getAbsPathFn, getURLFn, glob, isCurrentPathFn, moment, path, yaml;
path = require("path");
fm = require("front-matter");
fse = require("fs-extra");
yaml = require("js-yaml");
glob = require("glob");
moment = require("moment");
({dateStrCompare, getAbsPathFn, getURLFn, isCurrentPathFn} = require("./utils"));
module.exports = Router = class Router {
constructor(logger, renderer, generator, translator, site) {
// fn: param site, change site.
this.register = this.register.bind(this);
this.readData = this.readData.bind(this);
this.writeData = this.writeData.bind(this);
this.loadThemeAssets = this.loadThemeAssets.bind(this);
this.loadTemplates = this.loadTemplates.bind(this);
this.loadSrcs = this.loadSrcs.bind(this);
this.renderAssets = this.renderAssets.bind(this);
this.renderTemplates = this.renderTemplates.bind(this);
this.renderPosts = this.renderPosts.bind(this);
this.renderPages = this.renderPages.bind(this);
this.generateData = this.generateData.bind(this);
this.generatePosts = this.generatePosts.bind(this);
this.generatePages = this.generatePages.bind(this);
this.saveAssets = this.saveAssets.bind(this);
this.savePosts = this.savePosts.bind(this);
this.savePages = this.savePages.bind(this);
this.saveData = this.saveData.bind(this);
this.route = this.route.bind(this);
this.logger = logger;
this.renderer = renderer;
this.generator = generator;
this.translator = translator;
this.site = site;
this.store = {
"beforeGenerating": [],
"afterGenerating": []
};
this.getURL = getURLFn(this.site["siteConfig"]["baseURL"], this.site["siteConfig"]["rootDir"]);
this.getAbsPath = getAbsPathFn(this.site["siteConfig"]["rootDir"]);
}
register(type, fn) {
if (!(type in this.store)) {
return;
}
if (fn instanceof Function) {
return this.store[type].push(fn);
}
}
matchFiles(pattern, options) {
return new Promise(function(resolve, reject) {
return glob(pattern, options, function(err, res) {
if (err) {
return reject(err);
}
return resolve(res);
});
});
}
readData(srcDir, srcPath) {
this.logger.debug(`Hikaru is reading \`${path.join(srcDir, srcPath)}\`...`);
return fse.readFile(path.join(srcDir, srcPath), "utf8").then(function(raw) {
return {
"srcPath": srcPath,
"srcDir": srcDir,
"text": raw,
"raw": raw
};
});
}
writeData(srcDir, data) {
this.logger.debug(`Hikaru is writing \`${path.join(this.site["docDir"], data["docPath"])}\`...`);
if (data["content"] != null) {
return fse.outputFile(path.join(this.site["docDir"], data["docPath"]), data["content"]);
}
return fse.copy(path.join(srcDir, data["srcPath"]), path.join(this.site["docDir"], data["docPath"]));
}
loadThemeAssets() {
return this.matchFiles(path.join("**", "*"), {
"nodir": true,
"dot": true,
"cwd": this.site["themeSrcDir"]
}).then((themeSrcs) => {
return Promise.all(themeSrcs.filter(function(srcPath) {
// Asset is in sub dir.
return path.dirname(srcPath) !== ".";
}).map((srcPath) => {
return this.readData(this.site["themeSrcDir"], srcPath).then((data) => {
return this.site["assets"].push(data);
});
}));
});
}
loadTemplates() {
return this.matchFiles("*", {
"nodir": true,
"dot": true,
"cwd": this.site["themeSrcDir"]
}).then((templates) => {
return Promise.all(templates.map((srcPath) => {
return this.readData(this.site["themeSrcDir"], srcPath).then((data) => {
data["key"] = path.basename(srcPath, path.extname(srcPath));
return this.site["templates"][data["key"]] = data;
});
}));
});
}
loadSrcs() {
return this.matchFiles(path.join("**", "*"), {
"nodir": true,
"dot": true,
"cwd": this.site["srcDir"]
}).then((srcs) => {
return Promise.all(srcs.map((srcPath) => {
return this.readData(this.site["srcDir"], srcPath).then((data) => {
var parsed;
if (typeof data["raw"] === "string") {
parsed = fm(data["raw"]);
data["text"] = parsed["body"];
data = Object.assign(data, parsed["attributes"]);
if (data["text"] !== data["raw"]) {
if (data["title"] != null) {
data["title"] = data["title"].toString();
}
if (data["layout"] === "post") {
return this.site["posts"].push(data);
} else {
// Need load templates first.
if (!(data["layout"] in this.site["templates"])) {
data["layout"] = "page";
}
return this.site["pages"].push(data);
}
} else {
return this.site["assets"].push(data);
}
}
});
}));
});
}
renderAssets() {
return Promise.all(this.site["assets"].map((asset) => {
return this.renderer.render(asset);
}));
}
renderTemplates() {
return Promise.all(Object.values(this.site["templates"]).map((template) => {
return this.renderer.render(template);
}));
}
renderPosts() {
return Promise.all(this.site["posts"].map((post) => {
return this.renderer.render(post);
}));
}
renderPages() {
return Promise.all(this.site["pages"].map((page) => {
return this.renderer.render(page);
}));
}
generateData(p) {
var err, lang, language;
lang = p["language"] || this.site["siteConfig"]["language"];
if (!(lang in this.translator.list())) {
try {
language = yaml.safeLoad(fse.readFileSync(path.join(this.site["themeDir"], "languages", `${lang}.yml`)));
this.translator.register(lang, language);
} catch (error) {
err = error;
null;
}
}
p = this.generator.generate(p, this.site["posts"], {
"site": this.site,
"siteConfig": this.site["siteConfig"],
"themeConfig": this.site["themeConfig"],
"moment": moment,
"getURL": this.getURL,
"getAbsPath": this.getAbsPath,
"isCurrentPath": isCurrentPathFn(this.site["siteConfig"]["rootDir"], p["docPath"]),
"__": this.translator.getTranslateFn(lang)
});
if (!(p instanceof Array)) {
return [p];
}
return p;
}
generatePosts() {
var generated, i, j, k, len, p, ref, ref1, results;
this.site["posts"].sort(dateStrCompare);
generated = [];
ref = this.site["posts"];
for (j = 0, len = ref.length; j < len; j++) {
p = ref[j];
p = this.generateData(p);
generated = generated.concat(p);
}
this.site["posts"] = generated;
results = [];
for (i = k = 0, ref1 = this.site["posts"].length; (0 <= ref1 ? k < ref1 : k > ref1); i = 0 <= ref1 ? ++k : --k) {
if (i > 0) {
this.site["posts"][i]["next"] = this.site["posts"][i - 1];
}
if (i < this.site["posts"].length - 1) {
results.push(this.site["posts"][i]["prev"] = this.site["posts"][i + 1]);
} else {
results.push(void 0);
}
}
return results;
}
generatePages() {
var generated, j, len, p, ref;
generated = [];
ref = this.site["pages"];
for (j = 0, len = ref.length; j < len; j++) {
p = ref[j];
p = this.generateData(p);
generated = generated.concat(p);
}
return this.site["pages"] = generated;
}
saveAssets() {
return this.site["assets"].map((asset) => {
this.writeData(asset["srcDir"], asset);
return asset;
});
}
savePosts() {
return this.site["posts"].map((post) => {
this.site["templates"][post["layout"]]["content"](post).then((content) => {
post["content"] = content;
return this.writeData(this.site["srcDir"], post);
});
return post;
});
}
savePages() {
return this.site["pages"].map((page) => {
this.site["templates"][page["layout"]]["content"](page).then((content) => {
page["content"] = content;
return this.writeData(this.site["srcDir"], page);
});
return page;
});
}
saveData() {
return this.site["data"].map((data) => {
this.writeData(null, data);
return data;
});
}
route() {
return Promise.all([
this.loadThemeAssets(),
this.loadTemplates().then(() => {
return this.loadSrcs();
})
]).then(() => {
this.renderAssets().then(() => {
return this.saveAssets();
});
return Promise.all([this.renderTemplates(), this.renderPages(), this.renderPosts()]);
}).then(() => {
var fn, j, k, len, len1, ref, ref1;
ref = this.store["beforeGenerating"];
for (j = 0, len = ref.length; j < len; j++) {
fn = ref[j];
this.site = fn(this.site);
}
this.generatePosts();
this.generatePages();
ref1 = this.store["afterGenerating"];
for (k = 0, len1 = ref1.length; k < len1; k++) {
fn = ref1[k];
this.site = fn(this.site);
}
this.savePosts();
this.savePages();
return this.saveData();
});
}
};
}).call(this);