reclass-doc
Version:
Reclass model documentation generator.
857 lines (856 loc) • 33.5 kB
JavaScript
"use strict";
/**
* Reclass doc generator
*
* @author Jiri Hybek <jiri@hybek.cz>
* @license Apache-2.0 (c) 2017 Jiri Hybek
*/
Object.defineProperty(exports, "__esModule", { value: true });
var fs = require("fs");
var fsExtra = require("fs-extra");
var pug = require("pug");
var markdownIt = require("markdown-it");
var hljs = require("highlight.js");
var Resolver_1 = require("./Resolver");
var YamlTokenizer_1 = require("./YamlTokenizer");
var Util_1 = require("./Util");
/**
* Renderer class
*/
var Renderer = (function () {
/**
* Renderer constructor
*
* @param config Renderer config
* @param logger Logger facility
*/
function Renderer(config, inventory, logger) {
/** Inventory item cache - path => fingerprint */
this.cache = {};
this.tplCache = {};
this.outputDir = config.outputDir;
this.classesDir = config.classesDir || '/classes';
this.nodesDir = config.nodesDir || '/nodes';
this.sourcePostfix = config.sourcePostfix || '.source';
this.templateDir = config.templateDir;
this.assetsSrcDir = config.assetsSrcDir || '/assets/dist';
this.assetsOutDir = config.assetsOutDir || '/assets';
this.mediaSrcDir = config.mediaSrcDir || '/media';
this.mediaOutDir = config.mediaOutDir || '/media';
this.globals = config.globals || {};
this.options = config.options || {
pretty: true
};
this.globals.siteTitle = config.title || 'Reclass reference';
this.globals.siteLogo = config.logoUrl || null;
this.inventory = inventory;
this.logger = logger;
this.markdown = new markdownIt({
highlight: function (str, lang) {
if (lang && hljs.getLanguage(lang)) {
try {
return hljs.highlight(lang, str).value;
}
catch (__) { }
}
return ''; // use external default escaping
}
});
}
/**
* Filters output html
*
* @param html Rendered html
* @param path Current path
*/
Renderer.prototype.filterOutput = function (html, path) {
var _path = path.split("/");
var basePathParts = [];
if (path != "") {
_path.pop();
for (var i in _path)
if (_path[i].trim() != "")
basePathParts.push("..");
}
var basePath = basePathParts.length > 0 ? "./" + basePathParts.join("/") : ".";
html = html.replace(/{{base}}/g, basePath);
html = html.replace(/{{media}}/g, basePath + "/" + this.mediaOutDir);
return html;
};
/**
* Renders template
*
* @param templateName Template name
* @param locals Local vars
*/
Renderer.prototype.renderTpl = function (templateName, locals) {
if (locals === void 0) { locals = {}; }
var tpl = this.tplCache[templateName];
if (!tpl)
tpl = this.tplCache[templateName] = pug.compileFile(this.templateDir + "/" + templateName + ".pug", this.options);
return tpl(Util_1.merge(this.globals, locals));
};
/**
* Generates link to class page
*
* @param className Class name
*/
Renderer.prototype.getClassLink = function (className) {
var prefixDir = (className.type == Util_1.CLASS_TYPE.NODE ? this.nodesDir : this.classesDir);
var classPath, localName;
if (className.type == Util_1.CLASS_TYPE.CLASS) {
classPath = className.fullName.split(".");
localName = classPath.pop();
}
else {
classPath = className.fullName.split("/");
localName = classPath.pop();
}
return "{{base}}" + prefixDir + (classPath.length > 0 ? "/" + classPath.join("/") : "") + (className.isInit ? "/" + localName + "/index.html" : "/class." + localName + ".html");
};
/**
* Generates link to class source page
*
* @param className Class name
*/
Renderer.prototype.getClassSourceLink = function (className) {
var prefixDir = (className.type == Util_1.CLASS_TYPE.NODE ? this.nodesDir : this.classesDir);
var classPath, localName;
if (className.type == Util_1.CLASS_TYPE.CLASS) {
classPath = className.fullName.split(".");
localName = classPath.pop();
}
else {
classPath = className.fullName.split("/");
localName = classPath.pop();
}
return "{{base}}" + prefixDir + (classPath.length > 0 ? "/" + classPath.join("/") : "") + (className.isInit ? "/" + localName + "/init.source.html" : "/class." + localName + ".source.html");
};
/**
* Generates document link
*
* @param path Directory path
* @param name Document name
*/
Renderer.prototype.getDocumentLink = function (path, name) {
return "{{base}}" + path + "/doc." + name + ".html";
};
/**
* Generates document link
*
* @param path Directory path
* @param name Document name
*/
Renderer.prototype.getDocumentSourceLink = function (path) {
return "{{base}}" + path + ".source.html";
};
/**
* Generates link to directory index
*
* @param path Path
*/
Renderer.prototype.getDirectoryLink = function (path) {
return "{{base}}" + path + "/index.html";
};
/**
* Prepares navigation tree for template
*
* @param index Inventory index
* @param path Relative path
*/
Renderer.prototype.prepareTree = function (index, path) {
if (path === void 0) { path = ''; }
//Create nav item
var item = {
type: (index.classes['init'] ? 'class' : 'directory'),
label: index.name,
link: "{{base}}" + path + "/index.html",
id: "dir:" + path,
items: [],
flags: {},
fulltext: [index.name, path, path.replace(/\//g, ' ')].join(" ")
};
if ((index.classes['init'] && index.classes['init'].error) || (index.docs['README'] && index.docs['README'].error))
item.flags['error'] = true;
//Add classes
for (var i in index.classes)
if (i !== 'init')
item.items.push({
type: 'class',
label: index.classes[i].name.name,
link: this.getClassLink(index.classes[i].name),
id: "class:" + index.classes[i].name.fullName,
items: null,
flags: (index.classes[i].error ? { "error": true } : {}),
fulltext: [index.classes[i].name.fullName, index.classes[i].name.fullName.replace(/(\.|_)/g, ' '), path, path.replace(/\//g, ' ')].join(" ")
});
for (var i in index.docs)
if (i !== 'README')
item.items.push({
type: 'document',
label: index.docs[i].name,
link: this.getDocumentLink(path, index.docs[i].name),
id: "doc:" + path + "/doc." + index.docs[i].name,
items: null,
flags: (index.docs[i].error ? { "error": true } : {}),
fulltext: [index.docs[i].name, index.docs[i].name.replace(/(\.|_)/g, ' '), path, path.replace(/\//g, ' ')].join(" ")
});
for (var i in index.dirs)
item.items.push(this.prepareTree(index.dirs[i], path + "/" + index.dirs[i].name));
//Sort
item.items.sort(function (a, b) {
return a.label.localeCompare(b.label);
});
//Return
return item;
};
/**
* Prepares document section
*
* @param doc Inventory document
* @param path Current path
*/
Renderer.prototype.prepareDocument = function (doc, path) {
var section = {
title: doc.name,
type: 'document',
contents: null,
sourceLink: (doc.contents ? this.getDocumentSourceLink(path) : null),
errors: (doc.error ? [doc.error] : [])
};
section.contents = this.markdown.render(String(doc.contents));
return section;
};
/**
* Prepares class section
*
* @param class Inventory class
* @param path Current path
*/
Renderer.prototype.prepareClass = function (iClass, path) {
var _this = this;
//Create section
var section = {
title: iClass.name.fullName,
class: null,
type: 'class',
sourceLink: this.getClassSourceLink(iClass.name),
errors: iClass.error ? [iClass.error] : []
};
//Skip if class was not resolved
if (!iClass.class)
return section;
//Create class
var _class = {
className: iClass.name.fullName,
dependencies: [],
dependents: [],
applications: [],
props: null
};
//Add dependencies
var createClassLink = function (dClass) {
var _ref = _this.inventory.getClassRef(dClass.name);
var _link = {
className: dClass.name,
link: (_ref ? _this.getClassLink(_ref.name) : null),
dependencies: [],
flags: (dClass.error ? { error: true } : {})
};
for (var i = 0; i < dClass.classes.length; i++)
_link.dependencies.push(createClassLink(dClass.classes[i]));
return _link;
};
for (var i = 0; i < iClass.class.classes.length; i++)
_class.dependencies.push(createClassLink(iClass.class.classes[i]));
//Add dependants
for (var i in iClass.class.dependents) {
var _ref = void 0;
if (iClass.class.dependents[i].type == Util_1.CLASS_TYPE.CLASS)
_ref = this.inventory.getClassRef(iClass.class.dependents[i].name);
else
_ref = this.inventory.getNodeRef(iClass.class.dependents[i].name);
_class.dependents.push({
className: iClass.class.dependents[i].name,
link: (_ref ? this.getClassLink(_ref.name) : null),
dependencies: [],
flags: {}
});
}
//Add applications
for (var i in iClass.class.applications) {
var _app = iClass.class.applications[i];
var app = {
name: i,
sources: [],
comment: [],
ownProp: false
};
for (var j = 0; j < _app.sources.length; j++) {
var _ref = void 0;
if (_app.sources[j].classType == Util_1.CLASS_TYPE.CLASS)
_ref = this.inventory.getClassRef(_app.sources[j].className);
else
_ref = this.inventory.getNodeRef(_app.sources[j].className);
app.sources.push({
className: _app.sources[j].className,
classLink: (_ref ? this.getClassLink(_ref.name) : null),
sourceLink: (_ref ? this.getClassSourceLink(_ref.name) : null),
comment: _app.sources[j].comment.join("\n")
});
if (_app.sources[j].comment.length > 0)
app.comment.unshift(_app.sources[j].comment.join("\n"));
if (j === _app.sources.length - 1) {
if (_ref == iClass)
app.ownProp = true;
}
}
_class.applications.unshift(app);
}
//Prepare props
var type2str = function (type) {
switch (type) {
case YamlTokenizer_1.TOKEN_TYPE.MAP: return 'map';
case YamlTokenizer_1.TOKEN_TYPE.SEQUENCE: return 'sequence';
case YamlTokenizer_1.TOKEN_TYPE.VALUE: return 'value';
}
};
var merge2str = function (type) {
switch (type) {
case Resolver_1.MERGE_TYPE.MERGED: return 'merged';
case Resolver_1.MERGE_TYPE.REPLACED: return 'replaced';
case Resolver_1.MERGE_TYPE.ORIGIN: return 'origin';
}
};
var prepareProp = function (name, param, prefix) {
if (prefix === void 0) { prefix = null; }
//Prepare prop
var prop = {
id: (prefix !== null ? prefix + ":" : "") + (name !== null ? name : "param"),
name: name,
type: type2str(param.type),
ownProp: false,
value: null,
ref: null,
comment: [],
sources: [],
fulltext: null
};
var fulltext = [prop.id.substr(6).replace(/\:/g, '.')];
if (prop.name) {
fulltext.push(prop.name);
fulltext.push(prop.name.replace(/_/g, ' '));
}
//Add sources
for (var i = 0; i < param.sources.length; i++) {
var _source = param.sources[i];
var _sourceRef = void 0;
if (_source.classType === Util_1.CLASS_TYPE.CLASS)
_sourceRef = _this.inventory.getClassRef(_source.className);
else
_sourceRef = _this.inventory.getNodeRef(_source.className);
var source = {
className: _source.className,
classLink: (_sourceRef ? _this.getClassLink(_sourceRef.name) + "#" + prop.id : null),
sourceLink: (_sourceRef ? _this.getClassSourceLink(_sourceRef.name) + "#line:" + (_source.token.line + 1) : null),
mergeType: merge2str(_source.mergeType),
type: type2str(_source.type),
value: _source.value,
comment: _source.comment.join("\n")
};
prop.sources.unshift(source);
if (prop.comment.indexOf(source.comment) < 0)
prop.comment.unshift(source.comment);
if (i === param.sources.length - 1) {
if (_sourceRef == iClass)
prop.ownProp = true;
}
if (fulltext.indexOf(source.value) < 0)
fulltext.push(source.value);
if (fulltext.indexOf(source.comment) < 0)
fulltext.push(source.comment);
}
//Set value
if (param.value !== null) {
if (param.type === YamlTokenizer_1.TOKEN_TYPE.MAP) {
prop.value = {};
for (var i in param.value)
prop.value[i] = prepareProp(i, param.value[i], prop.id);
}
else if (param.type === YamlTokenizer_1.TOKEN_TYPE.SEQUENCE) {
prop.value = new Array(param.value.length);
for (var i = 0; i < param.value.length; i++)
prop.value[i] = prepareProp(String(i), param.value[i], prop.id);
}
else if (String(param.value).substr(0, 7) == "#!ref!#") {
prop.type = 'ref';
prop.value = "#param:" + String(param.value).substr(7);
fulltext.push(String(param.value).substr(7));
}
else {
prop.value = param.value;
fulltext.push(prop.value);
}
}
//Set refs
if (param.ref) {
prop.ref = [];
for (var i = 0; i < param.ref.length; i++) {
prop.ref.push({
name: param.ref[i].substr(2, param.ref[i].length - 3),
link: "#param:" + param.ref[i].substr(2, param.ref[i].length - 3)
});
fulltext.push(param.ref[i].substr(2, param.ref[i].length - 3));
}
}
prop.fulltext = fulltext.join(" ");
return prop;
};
if (iClass.class.params)
_class.props = prepareProp(null, iClass.class.params, null);
section.class = _class;
return section;
};
/**
* Prepares class list section
*
* @param index Inventory index
* @param path Current path
*/
Renderer.prototype.prepareClassList = function (index, path) {
var section = {
type: 'class-list',
classes: []
};
for (var i in index.classes) {
if (i == 'init')
continue;
section.classes.push({
label: index.classes[i].name.fullName,
link: this.getClassLink(index.classes[i].name),
flags: (index.classes[i].error ? { error: true } : {})
});
}
for (var i in index.dirs) {
var _index = index.dirs[i];
section.classes.push({
label: _index.classes['init'] ? _index.classes['init'].name.fullName : _index.name,
link: this.getDirectoryLink(path + "/" + _index.name),
flags: (_index.classes['init'] && _index.classes['init'].error ? { error: true } : {})
});
}
return section;
};
/**
* Prepares source code section
*
* @param filename Filename
*/
Renderer.prototype.prepareSource = function (filename, lang) {
var section = {
type: 'source',
title: filename.split("/").pop(),
contents: null
};
if (!hljs.getLanguage(lang))
throw new Error("Unsupported source language: " + lang);
var code = fs.readFileSync(filename, { encoding: 'utf-8' });
var html = hljs.highlight(lang, code).value;
var lines = html.split("\n");
section.contents = '';
for (var i = 0; i < lines.length; i++)
section.contents += '<div class="code-line" id="line:' + (i + 1) + '"><span class="code-line-nr">' + (i + 1) + '</span>' + lines[i] + '</div>';
//section.contents = this.markdown.render('```' + lang + '\n' + code + '\n```');
return section;
};
/**
* Renders index page
*
* @param index Inventory index
*/
Renderer.prototype.renderIndex = function (index) {
//Prepare page
var page = {
type: 'overview',
label: 'Overview',
title: 'Overview',
crumbs: [],
sections: {},
id: 'overview'
};
var _crumbs = [];
_crumbs.push({
label: "Overview",
link: "{{base}}/index.html"
});
//Add readme
if (index.docs['README']) {
page.sections['readme'] = this.prepareDocument(index.docs['README'], "/README");
this.renderSource(index.docs['README'].filename, "/README", _crumbs, 'markdown');
}
//Add nodes
if (index.dirs['nodes'])
page.sections['nodes'] = this.prepareClassList(index.dirs['nodes'], this.nodesDir);
//Add classes
if (index.dirs['classes'])
page.sections['classes'] = this.prepareClassList(index.dirs['classes'], this.classesDir);
var outputFilename = this.outputDir + '/index.html';
try {
this.logger.info("Rendering index to '" + outputFilename + "'...");
var html = this.renderTpl("index", {
title: page.title,
page: page
});
html = this.filterOutput(html, '');
fs.writeFileSync(outputFilename, html, { encoding: 'utf-8' });
}
catch (err) {
this.logger.warn("Failed to render index:", err);
}
};
/**
* Renders source code
*
* @param filename Source filename
* @param path Index path
* @param crumbs Previous index crumbs
* @param lang Code language
*/
Renderer.prototype.renderSource = function (filename, path, crumbs, lang) {
if (crumbs === void 0) { crumbs = []; }
//Prepare page
var page = {
type: 'source',
label: filename.split("/").pop(),
title: 'File ' + filename.split("/").pop(),
crumbs: crumbs,
sections: [],
id: "source:" + path
};
//Add source section
page.sections.push(this.prepareSource(filename, lang));
//Render page
try {
var outputFilename = this.outputDir + path + ".source.html";
this.logger.info("Rendering source page to '" + outputFilename + "'...");
var html = this.renderTpl("page", {
title: page.title,
page: page
});
html = this.filterOutput(html, path);
fs.writeFileSync(outputFilename, html, { encoding: 'utf-8' });
}
catch (err) {
this.logger.warn("Failed to render source page:", err);
}
};
/**
* Renders document
*
* @param doc Inventory document
* @param path Index path
* @param crumbs Previous index crumbs
* @param force If to ignore cache
*/
Renderer.prototype.renderDocument = function (doc, path, crumbs, force) {
if (crumbs === void 0) { crumbs = []; }
if (force === void 0) { force = false; }
//Prepare page
if (this.cache[path] != doc.fingerprint || force) {
this.cache[path] = doc.fingerprint;
//Update crumbs
var _crumbs = crumbs.slice();
_crumbs.push({
label: doc.name,
link: "{{base}}" + path + ".html"
});
var page = {
type: 'document',
title: doc.name,
label: doc.name,
crumbs: crumbs,
sections: [],
id: "doc:" + path
};
//Add content
page.sections.push(this.prepareDocument(doc, path));
this.renderSource(doc.filename, path, _crumbs, 'markdown');
//Render page
try {
var outputFilename = this.outputDir + path + ".html";
this.logger.info("Rendering document page to '" + outputFilename + "'...");
var html = this.renderTpl("page", {
title: page.title,
page: page
});
html = this.filterOutput(html, path);
fs.writeFileSync(outputFilename, html, { encoding: 'utf-8' });
}
catch (err) {
this.logger.warn("Failed to render document page:", err);
}
}
};
/**
* Renders class
*
* @param doc Inventory class
* @param path Index path
* @param crumbs Previous index crumbs
* @param force If to ignore cache
*/
Renderer.prototype.renderClass = function (rClass, path, crumbs, force) {
if (crumbs === void 0) { crumbs = []; }
if (force === void 0) { force = false; }
//Prepare page
if ((rClass.class && this.cache[path] != rClass.class.fingerprint) || force) {
if (rClass.class)
this.cache[path] = rClass.class.fingerprint;
//Update crumbs
var _crumbs = crumbs.slice();
_crumbs.push({
label: rClass.name.fullName,
link: this.getClassLink(rClass.name)
});
var page = {
type: 'class',
title: 'Class ' + rClass.name.fullName,
label: rClass.name.name,
crumbs: crumbs,
sections: [],
id: "class:" + rClass.name.fullName
};
//Add content
page.sections.push(this.prepareClass(rClass, path));
this.renderSource(rClass.filename, path, _crumbs, 'yaml');
//Render page
try {
var outputFilename = this.outputDir + path + ".html";
this.logger.info("Rendering class page to '" + outputFilename + "'...");
var html = this.renderTpl("page", {
title: page.title,
page: page
});
html = this.filterOutput(html, path);
fs.writeFileSync(outputFilename, html, { encoding: 'utf-8' });
}
catch (err) {
this.logger.warn("Failed to render class page:", err);
}
}
};
/**
* Renders index (directory)
*
* @param index Inventory index
* @param path Index path
* @param crumbs Previous index crumbs
* @param force If to ignore cache
*/
Renderer.prototype.renderDirectory = function (index, path, crumbs, force) {
if (crumbs === void 0) { crumbs = []; }
if (force === void 0) { force = false; }
//Check directory
var outputDir = this.outputDir + path;
if (!fs.existsSync(outputDir)) {
this.logger.info("Creating directory '" + outputDir + "'...");
fs.mkdirSync(outputDir);
}
//Update crumbs
var _crumbs = crumbs.slice();
_crumbs.push({
label: index.name,
link: this.getDirectoryLink(path)
});
//Prepare page
if (this.cache[path] != index.contentFingerprint || force) {
this.cache[path] = index.contentFingerprint;
var page = {
type: (index.classes['init'] ? 'class' : 'directory'),
title: (index.classes['init'] ? 'Class ' + index.classes['init'].name.fullName : 'Directory ' + index.name),
label: index.name,
crumbs: crumbs,
sections: [],
id: "dir:" + path
};
//Add readme
if (index.docs['README']) {
page.sections.push(this.prepareDocument(index.docs['README'], path + "/README"));
this.renderSource(index.docs['README'].filename, path + "/README", _crumbs, 'markdown');
}
//Add subclasses
if ((index.classes['init'] && Object.keys(index.classes).length > 1) || (!index.classes['init'] && Object.keys(index.classes).length > 0) || Object.keys(index.dirs).length > 0)
page.sections.push(this.prepareClassList(index, path));
//Add class
if (index.classes['init']) {
page.sections.push(this.prepareClass(index.classes['init'], path + "/init"));
this.renderSource(index.classes['init'].filename, path + "/init", _crumbs, 'yaml');
}
//Render page
try {
var outputFilename = this.outputDir + path + "/index.html";
this.logger.info("Rendering dir page to '" + outputFilename + "'...");
var html = this.renderTpl("page", {
title: page.title,
page: page
});
html = this.filterOutput(html, path + "/");
fs.writeFileSync(outputFilename, html, { encoding: 'utf-8' });
}
catch (err) {
this.logger.warn("Failed to render dir page:", err);
}
}
//Render classes
for (var i in index.classes) {
if (i == "init")
continue;
try {
this.renderClass(index.classes[i], path + "/class." + index.classes[i].name.name, _crumbs, force);
}
catch (err) {
this.logger.error("Failed to render '" + path + "/class." + index.classes[i].name.name + "':", err);
}
}
//Render documents
for (var i in index.docs) {
if (i == "README")
continue;
try {
this.renderDocument(index.docs[i], path + "/doc." + index.docs[i].name, _crumbs, force);
}
catch (err) {
this.logger.error("Failed to render '" + path + "/doc." + index.docs[i].name + "':", err);
}
}
//Render sub directories
for (var i in index.dirs) {
try {
this.renderDirectory(index.dirs[i], path + "/" + i, _crumbs, force);
}
catch (err) {
this.logger.error("Failed to render '" + (path + "/" + i) + "':", err);
}
}
};
/**
* Copy assets from template to output for given directory
*
* @param path Path
*/
Renderer.prototype.copyAssets = function (srcDir, dstDir, path) {
var realPath = srcDir + path;
var dstPath = this.outputDir + dstDir + path;
this.logger.debug("Checking assets in '" + realPath + "'...");
//Check output dir
if (!fs.existsSync(dstPath)) {
this.logger.info("Creating directory '" + dstPath + "'...");
fs.mkdirSync(dstPath);
}
//Read dir
var files = fs.readdirSync(realPath);
for (var i in files) {
var file = files[i];
if (file == "." || file == ".." || file.substr(0, 1) == ".")
continue;
var srcFilename = srcDir + path + "/" + file;
var dstFilename = this.outputDir + dstDir + path + "/" + file;
var assetId = "__assets__" + srcDir + path + "/" + file;
var stat = fs.statSync(srcFilename);
if (stat.isDirectory()) {
try {
this.copyAssets(srcDir, dstDir, path + "/" + file);
}
catch (err) {
this.logger.error("Failed to create asset directory '" + dstFilename + "':", err);
}
}
else {
if (this.cache[assetId] == String(stat.mtime.getTime())) {
this.logger.debug("Asset file '" + dstFilename + "' up to date, skiping...");
continue;
}
this.logger.info("Copying asset file '" + dstFilename + "'...");
//Copy file
try {
fsExtra.copySync(srcFilename, dstFilename, {
overwrite: true
});
}
catch (err) {
this.logger.error("Failed to copy asset file '" + srcFilename + "' to '" + dstFilename + "':", err);
}
this.cache[assetId] = String(stat.mtime.getTime());
}
}
};
/**
* Returns if template file has changed
*
* @param name Template name
* @param updateCache If to update cached value
*/
Renderer.prototype.hasTemplateChanged = function (path) {
var files = fs.readdirSync(path);
for (var i in files) {
var file = files[i];
var filename = path + "/" + file;
var stat = fs.statSync(filename);
if (stat.isDirectory()) {
var res = this.hasTemplateChanged(path + "/" + file);
if (res)
return true;
}
else {
if (file.substr(file.length - 4, 4) !== ".pug")
continue;
if (this.cache['__template__/' + path] != String(stat.mtime.getTime())) {
this.cache['__template__/' + path] = String(stat.mtime.getTime());
return true;
}
}
}
return false;
};
/**
* Renders all items in inventory
*
* @param index Inventory index
*/
Renderer.prototype.render = function (index, treeHash) {
//Check output directory
if (!fs.existsSync(this.outputDir)) {
this.logger.info("Creating output directory '" + this.outputDir + "'...");
fsExtra.mkdirpSync(this.outputDir);
}
//Copy assets
this.copyAssets(this.templateDir + this.assetsSrcDir, this.assetsOutDir, "");
//Copy media files
if (fs.existsSync(this.mediaSrcDir))
this.copyAssets(this.mediaSrcDir, this.mediaOutDir, "");
//Check if template has changed
var tplChanged = this.hasTemplateChanged(this.templateDir);
if (tplChanged) {
this.tplCache = {};
this.logger.debug("Template changed, will rebuild all...");
}
//Update globals
this.globals['navTree'] = {
classes: this.prepareTree(index.dirs['classes'], this.classesDir),
nodes: this.prepareTree(index.dirs['nodes'], this.nodesDir)
};
//Render index
if (this.cache[index.path] !== index.fingerprint)
this.renderIndex(index);
var crumbs = [{
label: "Overview",
link: "{{base}}/index.html"
}];
//Render nodes
this.renderDirectory(index.dirs['nodes'], this.nodesDir, crumbs, tplChanged);
//Render classes
this.renderDirectory(index.dirs['classes'], this.classesDir, crumbs, tplChanged);
};
return Renderer;
}());
exports.Renderer = Renderer;