'use strict';
const fs = require('fs-extra');
const path = require('path');
const merge = require('merge');
const auto = require('run-auto');
const section = require('./section').section;
const Language = require('./language').Language;
class File {
constructor(project, filename, contents) {
this.project = project;
this.filename = filename;
this.path = filename;
this.contents = contents;
this.index = false;
this.sections = [];
this.html = '';
this.default_template_data = merge(this.project.default_template_data, {});
}
preprocess_file(data, callback) {
callback(null, data);
}
split_lines(data, callback) {
var lines = data.split(/\r?\n/);
callback(null, lines);
}
detect_language(data, callback) {
this.language = new Language(this.project, this);
callback(null, this.language);
}
parse_lines(data, lang, callback) {
var sections = [];
var scope = this;
function add_section() {
if(sections.length == 0 || !current_section().is_empty()) {
sections.push(section.create(scope.project, scope, lang));
}
}
add_section();
function current_section() {
return sections[sections.length-1];
}
var in_comment = false,
in_multi = false,
line,
comment,
i;
for(i=0; i<data.length; i++) {
line = data[i];
if(lang.is_comment(line) || in_multi) {
if(lang.starts_multi_comment(line) && !lang.ends_multi_comment(line))
in_multi = true;
else if(lang.ends_multi_comment(line))
in_multi = false;
comment = lang.strip_comment(line);
if(!in_comment)
add_section();
current_section().comment += comment + '\n';
in_comment = true;
} else {
in_comment = false;
in_multi = false;
if(sections.length == 1 && !current_section().code.trim() && !line.trim()) continue;
if(!current_section().code.trim() && !line.trim()) continue;
current_section().code += line + '\n';
}
};
for(i=0; i<sections.length; i++) {
sections[i].done();
}
this.sections = sections;
callback(null, sections);
}
get_rel_path() {
return './' + path.relative('/' + this.get_link(), '/');
}
get_rel_link(link) {
return path.relative(this.get_rel_path(), link);
}
render(sections, language, callback) {
if(!language) language = this.language;
for(i=0; i<this.sections.length; i++) {
this.sections[i].done();
}
var i;
this.default_template_data.path = this.get_rel_path();
var filenames = this.project.get_link_filenames(this);
var md = null;
if(this.sections.length == 1 && this.sections[0].code_is_markdown) {
md = this.sections[0].code_highlighted;
}
var classes = [];
if(this.index) classes.push('index');
if(md) classes.push('markdown');
else classes.push('code');
var html_sections = '';
for(i=0; i<this.sections.length; i++) {
html_sections += this.sections[i].render();
}
var html_filenames = '';
for(i=0; i<filenames.length; i++) {
html_filenames += this.project.templates.file.render(merge(this.default_template_data, filenames[i]));
}
var html_links = '';
var links = Object.keys(this.project.options.links).sort();
var type_names = {
github: {
name: "GitHub",
desc: "View on GitHub"
},
twitter: {
name: "Twitter",
desc: "Follow on Twitter"
},
home: {
name: "Homepage",
desc: "Project homepage"
}
};
for(i=0; i<links.length; i++) {
var type = links[i]
var link = this.project.options.links[type];
if(!(type in type_names)) {
this.project.fire('link-type-unknown', type);
continue;
}
html_links += this.project.templates.link.render({
url: link,
name: type_names[type].name,
desc: type_names[type].desc,
type: type
});
}
this.html = this.project.templates.page.render(merge(this.default_template_data, {
title: (this.index ? this.project.options.name : this.filename),
version: this.project.options.version,
language: this.language.name.human,
markdown: md,
index: this.index,
filename: this.filename,
files: html_filenames,
classes: classes.join(' '),
sections: html_sections,
links: html_links
}));
callback(null, this.html);
}
get_output_filename() {
return path.join(this.project.options.output, this.path, 'index.html');
}
get_link() {
if(this.index) return './';
return path.join(this.path, '/');
}
write(callback) {
var filename = this.get_output_filename();
var scope = this;
fs.mkdirs(path.dirname(filename), function (err) {
if(err) {
callback(err, null);
return;
}
fs.writeFile(filename, scope.html, function(err) {
if(err) {
callback(err, null);
return;
}
callback(null, null);
});
});
}
parse_file(err, data, callback) {
var scope = this;
if(err) {
callback(err, this);
return;
}
auto({
preprocess: function(next) {
scope.preprocess_file.call(scope, data, function(err, data) {
next(err, data);
});
},
split_lines: ['preprocess', function(next, results) {
scope.split_lines.call(scope, results.preprocess, function(err, data) {
next(err, data);
});
}],
language: ['preprocess', function(next, results) {
scope.detect_language.call(scope, results.preprocess, function(err, data) {
next(err, data);
});
}],
parse_lines: ['split_lines', 'language', function(next, results) {
scope.parse_lines.call(scope, results.split_lines, results.language, function(err, data) {
next(err, data);
});
}],
render: ['parse_lines', 'language', function(next, results) {
scope.render.call(scope, results.parse_lines, results.language, function(err, data) {
scope.html = data;
next(err, data);
});
}],
write: ['render', function(next, results) {
scope.write.call(scope, function(err, data) {
next(err, data);
});
}]
}, function(err, results) {
callback(err, scope);
});
}
parse(callback) {
var scope = this;
if(this.contents) {
this.parse_file(null, this.contents, callback);
} else {
fs.readFile(this.filename, 'utf8', function(err, data) {
scope.parse_file.call(scope, err, data, callback);
});
}
}
run(callback) {
this.parse(callback);
}
}
exports.File = File;