aglio-theme-tanda
Version:
Tanda theme for the Aglio API Blueprint renderer
742 lines (714 loc) • 26.1 kB
JavaScript
// Generated by CoffeeScript 1.10.0
(function() {
var ROOT, benchmark, cache, compileTemplate, crypto, decorate, errMsg, fs, getCached, getCss, getTemplate, highlight, hljs, jade, less, markdownIt, modifyUriTemplate, moment, path, querystring, renderExample, renderSchema, sha1, slug;
crypto = require('crypto');
fs = require('fs');
hljs = require('highlight.js');
jade = require('jade');
less = require('less');
markdownIt = require('markdown-it');
moment = require('moment');
path = require('path');
querystring = require('querystring');
renderExample = require('./example');
renderSchema = require('./schema');
ROOT = path.dirname(__dirname);
cache = {};
benchmark = {
start: function(message) {
if (process.env.BENCHMARK) {
return console.time(message);
}
},
end: function(message) {
if (process.env.BENCHMARK) {
return console.timeEnd(message);
}
}
};
errMsg = function(message, err) {
err.message = message + ": " + err.message;
return err;
};
sha1 = function(value) {
return crypto.createHash('sha1').update(value.toString()).digest('hex');
};
slug = function(cache, value, unique) {
var sluggified;
if (cache == null) {
cache = {};
}
if (value == null) {
value = '';
}
if (unique == null) {
unique = false;
}
sluggified = value.toLowerCase().replace(/[ \t\n\\<>"'=:\/]/g, '-').replace(/-+/g, '-').replace(/^-/, '');
if (unique) {
while (cache[sluggified]) {
if (sluggified.match(/\d+$/)) {
sluggified = sluggified.replace(/\d+$/, function(value) {
return parseInt(value) + 1;
});
} else {
sluggified = sluggified + '-1';
}
}
}
cache[sluggified] = true;
return sluggified;
};
highlight = function(code, lang, subset) {
var response;
benchmark.start("highlight " + lang);
response = (function() {
switch (lang) {
case 'no-highlight':
return code;
case void 0:
case null:
case '':
return hljs.highlightAuto(code, subset).value;
default:
return hljs.highlight(lang, code).value;
}
})();
benchmark.end("highlight " + lang);
return response.trim();
};
getCached = function(key, compiledPath, sources, load, done) {
var compiledStats, err, error, error1, i, len, loadErr, source, sourceStats;
if (process.env.NOCACHE) {
return done(null);
}
if (cache[key]) {
return done(null, cache[key]);
}
try {
if (fs.existsSync(compiledPath)) {
compiledStats = fs.statSync(compiledPath);
for (i = 0, len = sources.length; i < len; i++) {
source = sources[i];
sourceStats = fs.statSync(source);
if (sourceStats.mtime > compiledStats.mtime) {
return done(null);
}
}
try {
return load(compiledPath, function(err, item) {
if (err) {
return done(errMsg('Error loading cached resource', err));
}
cache[key] = item;
return done(null, cache[key]);
});
} catch (error) {
loadErr = error;
return done(errMsg('Error loading cached resource', loadErr));
}
} else {
return done(null);
}
} catch (error1) {
err = error1;
return done(err);
}
};
getCss = function(variables, styles, verbose, done) {
var compiledPath, customPath, defaultVariablePath, i, item, j, key, len, len1, load, sources, stylePaths, variablePaths;
key = "css-" + variables + "-" + styles;
if (cache[key]) {
return done(null, cache[key]);
}
compiledPath = path.join(ROOT, 'cache', (sha1(key)) + ".css");
defaultVariablePath = path.join(ROOT, 'styles', 'variables-default.less');
sources = [defaultVariablePath];
if (!Array.isArray(variables)) {
variables = [variables];
}
if (!Array.isArray(styles)) {
styles = [styles];
}
variablePaths = [defaultVariablePath];
for (i = 0, len = variables.length; i < len; i++) {
item = variables[i];
if (item !== 'default') {
customPath = path.join(ROOT, 'styles', "variables-" + item + ".less");
if (!fs.existsSync(customPath)) {
customPath = item;
if (!fs.existsSync(customPath)) {
return done(new Error(customPath + " does not exist!"));
}
}
variablePaths.push(customPath);
sources.push(customPath);
}
}
stylePaths = [];
for (j = 0, len1 = styles.length; j < len1; j++) {
item = styles[j];
customPath = path.join(ROOT, 'styles', "layout-" + item + ".less");
if (!fs.existsSync(customPath)) {
customPath = item;
if (!fs.existsSync(customPath)) {
return done(new Error(customPath + " does not exist!"));
}
}
stylePaths.push(customPath);
sources.push(customPath);
}
load = function(filename, loadDone) {
return fs.readFile(filename, 'utf-8', loadDone);
};
if (verbose) {
console.log("Using variables " + variablePaths);
console.log("Using styles " + stylePaths);
console.log("Checking cache " + compiledPath);
}
return getCached(key, compiledPath, sources, load, function(err, css) {
var k, l, len2, len3, tmp;
if (err) {
return done(err);
}
if (css) {
if (verbose) {
console.log('Cached version loaded');
}
return done(null, css);
}
if (verbose) {
console.log('Not cached or out of date. Generating CSS...');
}
tmp = '';
for (k = 0, len2 = variablePaths.length; k < len2; k++) {
customPath = variablePaths[k];
tmp += "@import \"" + customPath + "\";\n";
}
for (l = 0, len3 = stylePaths.length; l < len3; l++) {
customPath = stylePaths[l];
tmp += "@import \"" + customPath + "\";\n";
}
benchmark.start('less-compile');
return less.render(tmp, {
compress: true
}, function(err, result) {
var error, writeErr;
if (err) {
return done(msgErr('Error processing LESS -> CSS', err));
}
try {
css = result.css;
fs.writeFileSync(compiledPath, css, 'utf-8');
} catch (error) {
writeErr = error;
return done(errMsg('Error writing cached CSS to file', writeErr));
}
benchmark.end('less-compile');
cache[key] = css;
return done(null, cache[key]);
});
});
};
compileTemplate = function(filename, options) {
var compiled;
return compiled = "var jade = require('jade/runtime');\n" + (jade.compileFileClient(filename, options)) + "\nmodule.exports = compiledFunc;";
};
getTemplate = function(name, verbose, done) {
var builtin, compiledPath, key, load;
builtin = path.join(ROOT, 'templates', name + ".jade");
if (!fs.existsSync(name) && fs.existsSync(builtin)) {
name = builtin;
}
key = "template-" + name;
if (cache[key]) {
return done(null, cache[key]);
}
compiledPath = path.join(ROOT, 'cache', (sha1(key)) + ".js");
load = function(filename, loadDone) {
var error, loadErr, loaded;
try {
loaded = require(filename);
} catch (error) {
loadErr = error;
return loadDone(errMsg('Unable to load template', loadErr));
}
return loadDone(null, require(filename));
};
if (verbose) {
console.log("Using template " + name);
console.log("Checking cache " + compiledPath);
}
return getCached(key, compiledPath, [name], load, function(err, template) {
var compileErr, compileOptions, compiled, error, error1, error2, writeErr;
if (err) {
return done(err);
}
if (template) {
if (verbose) {
console.log('Cached version loaded');
}
return done(null, template);
}
if (verbose) {
console.log('Not cached or out of date. Generating template JS...');
}
benchmark.start('jade-compile');
compileOptions = {
filename: name,
name: 'compiledFunc',
self: true,
compileDebug: false
};
try {
compiled = compileTemplate(name, compileOptions);
} catch (error) {
compileErr = error;
return done(errMsg('Error compiling template', compileErr));
}
if (compiled.indexOf('self.') === -1) {
compileOptions.self = false;
try {
compiled = compileTemplate(name, compileOptions);
} catch (error1) {
compileErr = error1;
return done(errMsg('Error compiling template', compileErr));
}
}
try {
fs.writeFileSync(compiledPath, compiled, 'utf-8');
} catch (error2) {
writeErr = error2;
return done(errMsg('Error writing cached template file', writeErr));
}
benchmark.end('jade-compile');
cache[key] = require(compiledPath);
return done(null, cache[key]);
});
};
modifyUriTemplate = function(templateUri, parameters, colorize) {
var block, closeIndex, index, lastIndex, param, parameterBlocks, parameterNames, parameterSet, parameterValidator;
parameterValidator = function(b) {
return parameterNames.indexOf(querystring.unescape(b.replace(/^\*|\*$/, ''))) !== -1;
};
parameterNames = (function() {
var i, len, results;
results = [];
for (i = 0, len = parameters.length; i < len; i++) {
param = parameters[i];
results.push(param.name);
}
return results;
})();
parameterBlocks = [];
lastIndex = index = 0;
while ((index = templateUri.indexOf("{", index)) !== -1) {
parameterBlocks.push(templateUri.substring(lastIndex, index));
block = {};
closeIndex = templateUri.indexOf("}", index);
block.querySet = templateUri.indexOf("{?", index) === index;
block.formSet = templateUri.indexOf("{&", index) === index;
block.reservedSet = templateUri.indexOf("{+", index) === index;
lastIndex = closeIndex + 1;
index++;
if (block.querySet || block.formSet || block.reservedSet) {
index++;
}
parameterSet = templateUri.substring(index, closeIndex);
block.parameters = parameterSet.split(",").filter(parameterValidator);
if (block.parameters.length) {
parameterBlocks.push(block);
}
}
parameterBlocks.push(templateUri.substring(lastIndex, templateUri.length));
return parameterBlocks.reduce(function(uri, v) {
var segment;
if (typeof v === "string") {
uri.push(v);
} else {
segment = !colorize ? ["{"] : [];
if (v.querySet) {
segment.push("?");
}
if (v.formSet) {
segment.push("&");
}
if (v.reservedSet && !colorize) {
segment.push("+");
}
segment.push(v.parameters.map(function(name) {
if (!colorize) {
return name;
} else {
name = name.replace(/^\*|\*$/, '');
param = parameters[parameterNames.indexOf(querystring.unescape(name))];
if (v.querySet || v.formSet) {
return ("<span class=\"hljs-attribute\">" + name + "=</span>") + ("<span class=\"hljs-literal\">" + (param.example || '') + "</span>");
} else {
return "<span class=\"hljs-attribute\" title=\"" + name + "\">" + (param.example || name) + "</span>";
}
}
}).join(colorize ? '&' : ','));
if (!colorize) {
segment.push("}");
}
uri.push(segment.join(""));
}
return uri;
}, []).join('').replace(/\/+/g, '/').replace(/\/$/, '');
};
decorate = function(api, md, slugCache, verbose) {
var action, category, content_sections, dataStructure, dataStructures, err, example, findListsAndRender, fn, i, item, j, k, knownParams, l, len, len1, len2, len3, len4, m, meta, name, newParams, param, ref, ref1, ref2, ref3, ref4, resource, resourceGroup, results, reversed, schema, section, slugify;
slugify = slug.bind(slug, slugCache);
dataStructures = {};
ref = api.content || [];
for (i = 0, len = ref.length; i < len; i++) {
category = ref[i];
ref1 = category.content || [];
for (j = 0, len1 = ref1.length; j < len1; j++) {
item = ref1[j];
if (item.element === 'dataStructure') {
dataStructure = item.content[0];
dataStructures[dataStructure.meta.id] = dataStructure;
}
}
}
if (verbose) {
console.log("Known data structures: " + (Object.keys(dataStructures)));
}
findListsAndRender = function(content) {
var finalHtml, k, l, len2, len3, ref2, ref3, section, section2;
finalHtml = '';
ref2 = content.split('# STARTLIST');
for (k = 0, len2 = ref2.length; k < len2; k++) {
section = ref2[k];
ref3 = section.split('# ENDLIST');
for (l = 0, len3 = ref3.length; l < len3; l++) {
section2 = ref3[l];
finalHtml += md.render(section2);
slugCache._nav.push(['ENDLIST']);
}
slugCache._nav.pop();
slugCache._nav.push(['STARTLIST']);
}
slugCache._nav.pop();
return finalHtml;
};
if (api.description) {
content_sections = api.description.split('# LHSCONTENT');
api.descriptionHtml = [];
slugCache._nav = [];
api.descriptionHtml.push([findListsAndRender(content_sections[0])]);
ref2 = content_sections.slice(1);
fn = function() {
var ref3, rest, side, sides, sidesContent;
sides = section.split('# RHSCONTENT');
ref3 = sides[1].split('# ENDCONTENT'), sides[1] = ref3[0], rest = ref3[1];
sidesContent = (function() {
var l, len3, results;
results = [];
for (l = 0, len3 = sides.length; l < len3; l++) {
side = sides[l];
results.push(findListsAndRender(side));
}
return results;
})();
api.descriptionHtml.push(sidesContent);
return api.descriptionHtml.push([findListsAndRender(rest)]);
};
for (k = 0, len2 = ref2.length; k < len2; k++) {
section = ref2[k];
fn();
}
api.navItems = slugCache._nav;
slugCache._nav = [];
}
ref3 = api.metadata || [];
for (l = 0, len3 = ref3.length; l < len3; l++) {
meta = ref3[l];
if (meta.name === 'HOST') {
api.host = meta.value;
}
}
ref4 = api.resourceGroups || [];
results = [];
for (m = 0, len4 = ref4.length; m < len4; m++) {
resourceGroup = ref4[m];
resourceGroup.elementId = slugify(resourceGroup.name, true);
resourceGroup.elementLink = "#" + resourceGroup.elementId;
if (resourceGroup.description) {
resourceGroup.descriptionHtml = md.render(resourceGroup.description);
resourceGroup.navItems = slugCache._nav;
slugCache._nav = [];
}
results.push((function() {
var len5, n, ref5, results1;
ref5 = resourceGroup.resources || [];
results1 = [];
for (n = 0, len5 = ref5.length; n < len5; n++) {
resource = ref5[n];
resource.elementId = slugify(resourceGroup.name + "-" + resource.name, true);
resource.elementLink = "#" + resource.elementId;
results1.push((function() {
var len6, len7, o, p, ref6, results2;
ref6 = resource.actions || [];
results2 = [];
for (o = 0, len6 = ref6.length; o < len6; o++) {
action = ref6[o];
action.elementId = slugify(resourceGroup.name + "-" + resource.name + "-" + action.method, true);
action.elementLink = "#" + action.elementId;
action.methodLower = action.method.toLowerCase();
if (!(action.attributes || {}).uriTemplate) {
if (!action.parameters || !action.parameters.length) {
action.parameters = resource.parameters;
} else if (resource.parameters) {
action.parameters = resource.parameters.concat(action.parameters);
}
}
knownParams = {};
newParams = [];
reversed = (action.parameters || []).concat([]).reverse();
for (p = 0, len7 = reversed.length; p < len7; p++) {
param = reversed[p];
if (knownParams[param.name]) {
continue;
}
knownParams[param.name] = true;
newParams.push(param);
}
action.parameters = newParams.reverse();
action.uriTemplate = modifyUriTemplate((action.attributes || {}).uriTemplate || resource.uriTemplate || '', action.parameters);
action.colorizedUriTemplate = modifyUriTemplate((action.attributes || {}).uriTemplate || resource.uriTemplate || '', action.parameters, true);
action.hasRequest = false;
results2.push((function() {
var len8, q, ref7, results3;
ref7 = action.examples || [];
results3 = [];
for (q = 0, len8 = ref7.length; q < len8; q++) {
example = ref7[q];
results3.push((function() {
var len9, r, ref8, results4;
ref8 = ['requests', 'responses'];
results4 = [];
for (r = 0, len9 = ref8.length; r < len9; r++) {
name = ref8[r];
results4.push((function() {
var error, error1, error2, len10, len11, len12, ref10, ref11, ref9, results5, s, t, u;
ref9 = example[name] || [];
results5 = [];
for (s = 0, len10 = ref9.length; s < len10; s++) {
item = ref9[s];
if (name === 'requests' && !action.hasRequest) {
action.hasRequest = true;
}
if (!item.schema && item.content) {
ref10 = item.content;
for (t = 0, len11 = ref10.length; t < len11; t++) {
dataStructure = ref10[t];
if (dataStructure.element === 'dataStructure') {
try {
schema = renderSchema(dataStructure.content[0], dataStructures);
schema['$schema'] = 'http://json-schema.org/draft-04/schema#';
item.schema = JSON.stringify(schema, null, 2);
} catch (error) {
err = error;
if (verbose) {
console.log(JSON.stringify(dataStructure.content[0], null, 2));
console.log(err);
}
}
}
}
}
if (item.content && !process.env.DRAFTER_EXAMPLES) {
ref11 = item.content;
for (u = 0, len12 = ref11.length; u < len12; u++) {
dataStructure = ref11[u];
if (dataStructure.element === 'dataStructure') {
try {
item.body = JSON.stringify(renderExample(dataStructure.content[0], dataStructures), null, 2);
} catch (error1) {
err = error1;
if (verbose) {
console.log(JSON.stringify(dataStructure.content[0], null, 2));
console.log(err);
}
}
}
}
}
item.hasContent = item.description || Object.keys(item.headers).length || item.body || item.schema;
try {
if (item.body) {
item.body = JSON.stringify(JSON.parse(item.body), null, 2);
}
if (item.schema) {
results5.push(item.schema = JSON.stringify(JSON.parse(item.schema), null, 2));
} else {
results5.push(void 0);
}
} catch (error2) {
err = error2;
results5.push(false);
}
}
return results5;
})());
}
return results4;
})());
}
return results3;
})());
}
return results2;
})());
}
return results1;
})());
}
return results;
};
exports.getConfig = function() {
return {
formats: ['1A'],
options: [
{
name: 'variables',
description: 'Color scheme name or path to custom variables',
"default": 'default'
}, {
name: 'condense-nav',
description: 'Condense navigation links',
boolean: true,
"default": true
}, {
name: 'full-width',
description: 'Use full window width',
boolean: true,
"default": false
}, {
name: 'template',
description: 'Template name or path to custom template',
"default": 'default'
}, {
name: 'style',
description: 'Layout style name or path to custom stylesheet'
}, {
name: 'emoji',
description: 'Enable support for emoticons',
boolean: true,
"default": true
}
]
};
};
exports.render = function(input, options, done) {
var md, slugCache, themeStyle, themeVariables, verbose;
if (done == null) {
done = options;
options = {};
}
if (process.env.NOCACHE) {
cache = {};
}
if (options.condenseNav) {
options.themeCondenseNav = options.condenseNav;
}
if (options.fullWidth) {
options.themeFullWidth = options.fullWidth;
}
if (options.themeVariables == null) {
options.themeVariables = 'default';
}
if (options.themeStyle == null) {
options.themeStyle = 'default';
}
if (options.themeTemplate == null) {
options.themeTemplate = 'default';
}
if (options.themeCondenseNav == null) {
options.themeCondenseNav = true;
}
if (options.themeFullWidth == null) {
options.themeFullWidth = false;
}
if (options.themeTemplate === 'default') {
options.themeTemplate = path.join(ROOT, 'templates', 'index.jade');
}
slugCache = {
_nav: []
};
md = markdownIt({
html: true,
linkify: true,
typographer: true,
highlight: highlight
}).use(require('markdown-it-anchor'), {
slugify: function(value) {
var output;
output = "header-" + (slug(slugCache, value, true));
slugCache._nav.push([value, "#" + output]);
return output;
},
permalink: true,
permalinkClass: 'permalink'
}).use(require('markdown-it-checkbox')).use(require('markdown-it-container'), 'note').use(require('markdown-it-container'), 'warning');
if (options.themeEmoji) {
md.use(require('markdown-it-emoji'));
}
md.renderer.rules.code_block = md.renderer.rules.fence;
benchmark.start('decorate');
decorate(input, md, slugCache, options.verbose);
benchmark.end('decorate');
benchmark.start('css-total');
themeVariables = options.themeVariables, themeStyle = options.themeStyle, verbose = options.verbose;
return getCss(themeVariables, themeStyle, verbose, function(err, css) {
var key, locals, ref, value;
if (err) {
return done(errMsg('Could not get CSS', err));
}
benchmark.end('css-total');
locals = {
api: input,
condenseNav: options.themeCondenseNav,
css: css,
fullWidth: options.themeFullWidth,
date: moment,
hash: function(value) {
return crypto.createHash('md5').update(value.toString()).digest('hex');
},
highlight: highlight,
markdown: function(content) {
return md.render(content);
},
slug: slug.bind(slug, slugCache),
urldec: function(value) {
return querystring.unescape(value);
}
};
ref = options.locals || {};
for (key in ref) {
value = ref[key];
locals[key] = value;
}
benchmark.start('get-template');
return getTemplate(options.themeTemplate, verbose, function(getTemplateErr, renderer) {
var error, html;
if (getTemplateErr) {
return done(errMsg('Could not get template', getTemplateErr));
}
benchmark.end('get-template');
benchmark.start('call-template');
try {
html = renderer(locals);
} catch (error) {
err = error;
return done(errMsg('Error calling template during rendering', err));
}
benchmark.end('call-template');
return done(null, html);
});
});
};
}).call(this);