function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
conrefsLoader = function () { if(prototype.init) { prototype.init.apply(this, arguments); } }
n/a
function createNodeFS(root) { return FS.create({ root: root, fsExists: fs.exists, fsReadFile: fs.readFile, fsStatFile: fs.stat, fsReadDir: fsReadDir, fsLoadObject: fsLoadObject, fsReadAsStream: fs.readStream }); }
n/a
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
function initBook(rootFolder) { var extension = '.md'; return fs.mkdirp(rootFolder) // Parse the summary and readme .then(function() { var fs = createNodeFS(rootFolder); var book = Book.createForFS(fs); return Parse.parseReadme(book) // Setup default readme if doesn't found one .fail(function() { var readmeFile = File.createWithFilepath('README' + extension); var readme = Readme.create(readmeFile); return book.setReadme(readme); }); }) .then(Parse.parseSummary) .then(function(book) { var logger = book.getLogger(); var summary = book.getSummary(); var summaryFile = summary.getFile(); var summaryFilename = summaryFile.getPath() || ('SUMMARY' + extension); var articles = summary.getArticlesAsList(); // Write pages return Promise.forEach(articles, function(article) { var articlePath = article.getPath(); var filePath = articlePath? path.join(rootFolder, articlePath) : null; if (!filePath) { return; } return fs.assertFile(filePath, function() { return fs.ensureFile(filePath) .then(function() { logger.info.ln('create', article.getPath()); return fs.writeFile(filePath, '# ' + article.getTitle() + '\n\n'); }); }); }) // Write summary .then(function() { var filePath = path.join(rootFolder, summaryFilename); return fs.ensureFile(filePath) .then(function() { logger.info.ln('create ' + path.basename(filePath)); return fs.writeFile(filePath, summary.toText(extension)); }); }) // Log end .then(function() { logger.info.ln('initialization is finished'); }); }); }
n/a
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
function Logger(write, logLevel) { if (!(this instanceof Logger)) return new Logger(write, logLevel); this._write = write || function(msg) { if(process.stdout) { process.stdout.write(msg); } }; this.lastChar = '\n'; this.setLevel(logLevel || 'info'); // Create easy-to-use method like "logger.debug.ln('....')" LEVELS.forEach(function(level, levelKey) { if (levelKey === 'DISABLED') { return; } levelKey = levelKey.toLowerCase(); this[levelKey] = this.log.bind(this, level); this[levelKey].ln = this.logLn.bind(this, level); this[levelKey].ok = this.ok.bind(this, level); this[levelKey].fail = this.fail.bind(this, level); this[levelKey].promise = this.promise.bind(this, level); }, this); }
n/a
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
function Q(value) { // If the object is already a Promise, return it directly. This enables // the resolve function to both be used to created references from objects, // but to tolerably coerce non-promises to promises. if (value instanceof Promise) { return value; } // assimilate thenables if (isPromiseAlike(value)) { return coerce(value); } else { return fulfill(value); } }
...
})
// Log end
.then(function(count) {
logger.info.ok(count + ' file(s) generated');
logger.debug('cleaning up... ');
return logger.debug.promise(fs.rmDir(outputFolder));
});
}
};
};
...
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
function Server() { this.running = null; this.dir = null; this.port = 0; this.sockets = []; }
n/a
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
themesLoader = function () { if(prototype.init) { prototype.init.apply(this, arguments); } }
n/a
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
function createForFS(fs) { return new Book({ fs: fs }); }
...
var extension = '.md';
return fs.mkdirp(rootFolder)
// Parse the summary and readme
.then(function() {
var fs = createNodeFS(rootFolder);
var book = Book.createForFS(fs);
return Parse.parseReadme(book)
// Setup default readme if doesn't found one
.fail(function() {
var readmeFile = File.createWithFilepath('README' + extension);
var readme = Readme.create(readmeFile);
...
function createFromParent(parent, language) { var ignore = parent.getIgnore(); var config = parent.getConfig(); // Set language in configuration config = config.setValue('language', language); return new Book({ // Inherits config. logegr and list of ignored files logger: parent.getLogger(), config: config, ignore: ignore, language: language, fs: FS.reduceScope(parent.getContentFS(), language) }); }
...
*/
function parseMultilingualBook(book) {
var languages = book.getLanguages();
var langList = languages.getList();
return Promise.reduce(langList, function(currentBook, lang) {
var langID = lang.getID();
var child = Book.createFromParent(currentBook, langID);
var ignore = currentBook.getIgnore();
return Promise(child)
.then(parseConfig)
.then(parseBookContent)
.then(function(result) {
// Ignore content of this book when generating parent book
...
addLanguageBook = function (language, book) { var books = this.getBooks(); books = books.set(language, book); return this.set('books', books); }
...
.then(parseConfig)
.then(parseBookContent)
.then(function(result) {
// Ignore content of this book when generating parent book
ignore = ignore.add(langID + '/**');
currentBook = currentBook.set('ignore', ignore);
return currentBook.addLanguageBook(langID, result);
});
}, book);
}
/**
Parse a whole book from a filesystem
...
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
getBooks = function () { return this.get('books'); }
...
logger.info.ln('Table of Contents file is', summaryFile.getPath());
}
}
function printMultingualBook(book) {
var logger = book.getLogger();
var languages = book.getLanguages();
var books = book.getBooks();
logger.info.ln(languages.size + ' languages');
languages.forEach(function(lang) {
logger.info.ln('Language:', lang.getTitle());
printBook(books.get(lang.getID()));
logger.info.ln('');
...
getConfig = function () { return this.get('config'); }
...
@param {Output} output
@param {Object} result: result from API
@return {Output}
*/
function decodeGlobal(output, result) {
var book = output.getBook();
var config = book.getConfig();
// Update config
config = decodeConfig(config, result.config);
book = book.set('config', config);
return output.set('book', book);
}
...
getContentFS = function () { var fs = this.getFS(); var config = this.getConfig(); var rootFolder = config.getValue('root'); if (rootFolder) { return FS.reduceScope(fs, rootFolder); } return fs; }
...
It's the context for page's hook, etc
@param {Output} output
@return {Object}
*/
function encodeGlobal(output) {
var book = output.getBook();
var bookFS = book.getContentFS();
var logger = output.getLogger();
var outputFolder = output.getRoot();
var plugins = output.getPlugins();
var blocks = Plugins.listBlocks(plugins);
var result = {
log: logger,
...
getContentRoot = function () { var fs = this.getContentFS(); return fs.getRoot(); }
...
/**
Resolve a file from the book root
@param {String} fileName
@return {String}
*/
resolve: function(fileName) {
return path.resolve(book.getContentRoot(), fileName);
},
/**
Resolve a page by it path
@param {String} filePath
@return {String}
...
getDefaultExt = function () { // Inferring sources var clues = [ this.getReadme(), this.getSummary(), this.getGlossary() ]; // List their extensions var exts = clues.map(function (clue) { var file = clue.getFile(); if (file.exists()) { return file.getParser().getExtensions().first(); } else { return null; } }); // Adds the general default extension exts.push('.md'); // Choose the first non null return exts.find(function (e) { return e !== null; }); }
...
/**
Infer the default path for a Readme.
@param {Boolean} [absolute=false] False for a path relative to
this book's content root
@return {String}
*/
Book.prototype.getDefaultReadmePath = function(absolute) {
var defaultPath = 'README'+this.getDefaultExt();
if (absolute) {
return path.join(this.getContentRoot(), defaultPath);
} else {
return defaultPath;
}
};
...
getDefaultGlossaryPath = function (absolute) { var defaultPath = 'GLOSSARY'+this.getDefaultExt(); if (absolute) { return path.join(this.getContentRoot(), defaultPath); } else { return defaultPath; } }
n/a
getDefaultReadmePath = function (absolute) { var defaultPath = 'README'+this.getDefaultExt(); if (absolute) { return path.join(this.getContentRoot(), defaultPath); } else { return defaultPath; } }
n/a
getDefaultSummaryPath = function (absolute) { var defaultPath = 'SUMMARY'+this.getDefaultExt(); if (absolute) { return path.join(this.getContentRoot(), defaultPath); } else { return defaultPath; } }
n/a
getFS = function () { return this.get('fs'); }
...
/**
Return FS instance to access the content
@return {FS}
*/
Book.prototype.getContentFS = function() {
var fs = this.getFS();
var config = this.getConfig();
var rootFolder = config.getValue('root');
if (rootFolder) {
return FS.reduceScope(fs, rootFolder);
}
...
getGlossary = function () { return this.get('glossary'); }
...
var summary = book.getSummary();
var summaryFile = summary.getFile();
var readme = book.getReadme();
var readmeFile = readme.getFile();
var glossary = book.getGlossary();
var glossaryFile = glossary.getFile();
if (configFile.exists()) {
logger.info.ln('Configuration file is', configFile.getPath());
}
if (readmeFile.exists()) {
...
getIgnore = function () { return this.get('ignore'); }
...
/**
Check if a file is ignore (should not being parsed, etc)
@param {String} ref
@return {Page|undefined}
*/
Book.prototype.isFileIgnored = function(filename) {
var ignore = this.getIgnore();
var language = this.getLanguage();
// Ignore is always relative to the root of the main book
if (language) {
filename = path.join(language, filename);
}
...
getLanguage = function () { return this.get('language'); }
...
Encode a book to JSON
@param {Book}
@return {Object}
*/
function encodeBookToJson(book) {
var config = book.getConfig();
var language = book.getLanguage();
var variables = config.getValue('variables', {});
return {
summary: encodeSummary(book.getSummary()),
glossary: encodeGlossary(book.getGlossary()),
readme: encodeReadme(book.getReadme()),
...
getLanguageBook = function (language) { var books = this.getBooks(); return books.get(language); }
n/a
getLanguages = function () { return this.get('languages'); }
...
format: format
});
})
// Extract ebook file
.then(function(output) {
var book = output.getBook();
var languages = book.getLanguages();
if (book.isMultilingual()) {
return Promise.forEach(languages.getList(), function(lang) {
var langID = lang.getID();
var langOutputFile = path.join(
path.dirname(outputFile),
...
getLogger = function () { return this.get('logger'); }
...
var readme = Readme.create(readmeFile);
return book.setReadme(readme);
});
})
.then(Parse.parseSummary)
.then(function(book) {
var logger = book.getLogger();
var summary = book.getSummary();
var summaryFile = summary.getFile();
var summaryFilename = summaryFile.getPath() || ('SUMMARY' + extension);
var articles = summary.getArticlesAsList();
// Write pages
...
getPage = function (ref) { return this.getPages().get(ref); }
...
/**
Resolve a page by it path
@param {String} filePath
@return {String}
*/
getPageByPath: function(filePath) {
var page = output.getPage(filePath);
if (!page) return undefined;
return encodePage(output, page);
},
/**
Render a block of text (markdown/asciidoc)
...
getReadme = function () { return this.get('readme'); }
...
var config = book.getConfig();
var configFile = config.getFile();
var summary = book.getSummary();
var summaryFile = summary.getFile();
var readme = book.getReadme();
var readmeFile = readme.getFile();
var glossary = book.getGlossary();
var glossaryFile = glossary.getFile();
if (configFile.exists()) {
logger.info.ln('Configuration file is', configFile.getPath());
...
getRoot = function () { var fs = this.getFS(); return fs.getRoot(); }
...
deprecate.field(output, 'config.options', result, 'options',
result.values, '"config.options" property is deprecated, use "config.get(key)" instead');
deprecate.field(output, 'config.options.generator', result.values, 'generator',
output.getGenerator(), '"options.generator" property is deprecated, use "output.name" instead
x27;);
deprecate.field(output, 'config.options.generator', result.values, 'output',
output.getRoot(), '"options.output" property is deprecated, use
"output.root()" instead');
return result;
}
module.exports = encodeConfig;
...
getSummary = function () { return this.get('summary'); }
...
return book.setReadme(readme);
});
})
.then(Parse.parseSummary)
.then(function(book) {
var logger = book.getLogger();
var summary = book.getSummary();
var summaryFile = summary.getFile();
var summaryFilename = summaryFile.getPath() || ('SUMMARY' + extension);
var articles = summary.getArticlesAsList();
// Write pages
return Promise.forEach(articles, function(article) {
...
isContentFileIgnored = function (filename) { var config = this.getConfig(); var rootFolder = config.getValue('root'); if (rootFolder) { filename = path.join(rootFolder, filename); } return this.isFileIgnored(filename); }
...
var exts = parsers.extensions;
return Promise.some(exts, function(ext) {
var filepath = basename + ext;
return fs.findFile(basedir, filepath)
.then(function(found) {
if (!found || book.isContentFileIgnored(found)) {
return undefined;
}
return fs.statFile(found);
});
});
}
...
isFileIgnored = function (filename) { var ignore = this.getIgnore(); var language = this.getLanguage(); // Ignore is always relative to the root of the main book if (language) { filename = path.join(language, filename); } return ignore.isFileIgnored(filename); }
...
var language = this.getLanguage();
// Ignore is always relative to the root of the main book
if (language) {
filename = path.join(language, filename);
}
return ignore.isFileIgnored(filename);
};
/**
Check if a content file is ignore (should not being parsed, etc)
@param {String} ref
@return {Page|undefined}
...
isLanguageBook = function () { return Boolean(this.getLanguage()); }
...
/**
Check if the book is a language book for a multilingual book
@return {Boolean}
*/
isLanguageBook: function() {
return book.isLanguageBook();
},
/**
Read a file from the book
@param {String} fileName
@return {Promise<Buffer>}
...
isMultilingual = function () { return (this.getLanguages().getCount() > 0); }
...
/**
Check if the book is a multilingual book
@return {Boolean}
*/
isMultilingual: function() {
return book.isMultilingual();
},
/**
Check if the book is a language book for a multilingual book
@return {Boolean}
*/
...
setConfig = function (config) { return this.set('config', config); }
...
if (result.file) {
config = config.setFile(result.file);
}
// Merge with old values
config = config.mergeValues(values);
return book.setConfig(config);
});
}
module.exports = parseConfig;
...
setIgnore = function (ignore) { return this.set('ignore', ignore); }
...
ignore = ignore.add(content.toString().split(/\r?\n/));
}, function(err) {
return Promise();
});
})
.then(function() {
return book.setIgnore(ignore);
});
}
module.exports = parseIgnore;
...
setLogLevel = function (level) { this.getLogger().setLevel(level); return this; }
...
function getBook(args, kwargs) {
var input = path.resolve(args[0] || process.cwd());
var logLevel = kwargs.log;
var fs = createNodeFS(input);
var book = Book.createForFS(fs);
return book.setLogLevel(logLevel);
}
module.exports = getBook;
...
setReadme = function (readme) { return this.set('readme', readme); }
...
return Parse.parseReadme(book)
// Setup default readme if doesn't found one
.fail(function() {
var readmeFile = File.createWithFilepath('README' + extension);
var readme = Readme.create(readmeFile);
return book.setReadme(readme);
});
})
.then(Parse.parseSummary)
.then(function(book) {
var logger = book.getLogger();
var summary = book.getSummary();
...
setSummary = function (summary) { return this.set('summary', summary); }
...
summary = SummaryModifier.unshiftArticle(summary, {
title: 'Introduction',
ref: readmeFile.getPath()
});
}
// Set new summary
return book.setSummary(summary);
});
}
module.exports = parseSummary;
...
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
create = function (file, values) { return new Config({ file: file, values: Immutable.fromJS(values) }); }
...
var book = Book.createForFS(fs);
return Parse.parseReadme(book)
// Setup default readme if doesn't found one
.fail(function() {
var readmeFile = File.createWithFilepath('README' + extension);
var readme = Readme.create(readmeFile);
return book.setReadme(readme);
});
})
.then(Parse.parseSummary)
.then(function(book) {
var logger = book.getLogger();
...
createWithValues = function (values) { return new Config({ values: Immutable.fromJS(values) }); }
...
var Immutable = require('immutable');
var Config = require('../config');
describe('Config', function() {
var config = Config.createWithValues({
hello: {
world: 1,
test: 'Hello',
isFalse: false
}
});
...
keyToKeyPath = function (keyPath) { if (is.string(keyPath)) keyPath = keyPath.split('.'); return keyPath; }
...
/**
* Return a configuration value by its key path
* @param {String} key
* @return {Mixed}
*/
Config.prototype.getValue = function(keyPath, def) {
var values = this.getValues();
keyPath = Config.keyToKeyPath(keyPath);
if (!values.hasIn(keyPath)) {
return Immutable.fromJS(def);
}
return values.getIn(keyPath);
};
...
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
getFile = function () { return this.get('file'); }
...
});
})
.then(Parse.parseSummary)
.then(function(book) {
var logger = book.getLogger();
var summary = book.getSummary();
var summaryFile = summary.getFile();
var summaryFilename = summaryFile.getPath() || ('SUMMARY' + extension);
var articles = summary.getArticlesAsList();
// Write pages
return Promise.forEach(articles, function(article) {
var articlePath = article.getPath();
...
getPluginDependencies = function () { var plugins = this.getValue('plugins'); if (is.string(plugins)) { return PluginDependency.listFromString(plugins); } else { return PluginDependency.listFromArray(plugins); } }
...
/**
* Return a plugin dependency by its name
* @param {String} name
* @return {PluginDependency}
*/
Config.prototype.getPluginDependency = function(name) {
var plugins = this.getPluginDependencies();
return plugins.find(function(dep) {
return dep.getName() === name;
});
};
/**
...
getPluginDependency = function (name) { var plugins = this.getPluginDependencies(); return plugins.find(function(dep) { return dep.getName() === name; }); }
n/a
getValue = function (keyPath, def) { var values = this.getValues(); keyPath = Config.keyToKeyPath(keyPath); if (!values.hasIn(keyPath)) { return Immutable.fromJS(def); } return values.getIn(keyPath); }
...
@param {Book}
@return {Object}
*/
function encodeBookToJson(book) {
var config = book.getConfig();
var language = book.getLanguage();
var variables = config.getValue('variables', {});
return {
summary: encodeSummary(book.getSummary()),
glossary: encodeGlossary(book.getGlossary()),
readme: encodeReadme(book.getReadme()),
config: book.getConfig().getValues().toJS(),
...
getValues = function () { return this.get('values'); }
...
@param {Output} output
@param {Config} config
@return {Object}
*/
function encodeConfig(output, config) {
var result = {
values: config.getValues().toJS(),
get: function(key, defaultValue) {
return objectPath.get(result.values, key, defaultValue);
},
set: function(key, value) {
return objectPath.set(result.values, key, value);
...
mergeValues = function (values) { var currentValues = this.getValues(); values = Immutable.fromJS(values); currentValues = currentValues.mergeDeep(values); return this.set('values', currentValues); }
...
// Set the file
if (result.file) {
config = config.setFile(result.file);
}
// Merge with old values
config = config.mergeValues(values);
return book.setConfig(config);
});
}
module.exports = parseConfig;
...
setFile = function (file) { return this.set('file', file); }
...
.then(function(result) {
var values = result? result.values : {};
values = validateConfig(values);
// Set the file
if (result.file) {
config = config.setFile(result.file);
}
// Merge with old values
config = config.mergeValues(values);
return book.setConfig(config);
});
...
setPluginDependencies = function (deps) { var plugins = PluginDependency.listToArray(deps); return this.setValue('plugins', plugins); }
...
return togglePlugin(config, pluginName, true);
}
var deps = config.getPluginDependencies();
var dep = PluginDependency.create(pluginName, version);
deps = deps.push(dep);
return config.setPluginDependencies(deps);
}
module.exports = addPlugin;
...
setValue = function (keyPath, value) { keyPath = Config.keyToKeyPath(keyPath); value = Immutable.fromJS(value); var values = this.getValues(); values = values.setIn(keyPath, value); return this.set('values', values); }
...
@return {Book}
*/
Book.createFromParent = function createFromParent(parent, language) {
var ignore = parent.getIgnore();
var config = parent.getConfig();
// Set language in configuration
config = config.setValue('language', language);
return new Book({
// Inherits config. logegr and list of ignored files
logger: parent.getLogger(),
config: config,
ignore: ignore,
...
toReducedVersion = function () { return reducedObject(configDefault, this.getValues()); }
...
};
/**
* Render config as text
* @return {Promise<String>}
*/
Config.prototype.toText = function() {
return JSON.stringify(this.toReducedVersion().toJS(), null, 4);
};
/**
* Change the file for the configuration
* @param {File} file
* @return {Config}
*/
...
toText = function () { return JSON.stringify(this.toReducedVersion().toJS(), null, 4); }
...
// Write summary
.then(function() {
var filePath = path.join(rootFolder, summaryFilename);
return fs.ensureFile(filePath)
.then(function() {
logger.info.ln('create ' + path.basename(filePath));
return fs.writeFile(filePath, summary.toText(extension));
});
})
// Log end
.then(function() {
logger.info.ln('initialization is finished');
});
...
updateValues = function (values) { values = Immutable.fromJS(values); return this.set('values', values); }
...
*/
function decodeGlobal(config, result) {
var values = result.values;
delete values.generator;
delete values.output;
return config.updateValues(values);
}
module.exports = decodeGlobal;
...
function addPlugin(config, pluginName, version) { // For default plugin, we only ensure it is enabled if (isDefaultPlugin(pluginName, version)) { return togglePlugin(config, pluginName, true); } var deps = config.getPluginDependencies(); var dep = PluginDependency.create(pluginName, version); deps = deps.push(dep); return config.setPluginDependencies(deps); }
...
return server.stop()
.then(function() {
return Parse.parseBook(book)
.then(function(resultBook) {
if (hasLiveReloading) {
// Enable livereload plugin
var config = resultBook.getConfig();
config = ConfigModifier.addPlugin(config, 'livereload');
resultBook = resultBook.set('config', config);
}
return Output.generate(Generator, resultBook, {
root: outputFolder
});
});
...
function editPlugin(config, pluginName, pluginConfig) { return config.setValue('pluginsConfig.'+pluginName, pluginConfig); }
n/a
function getPluginConfig(config, pluginName) { var pluginsConfig = config.getValues().get('pluginsConfig'); if (pluginsConfig === undefined) { return {}; } var pluginConf = pluginsConfig.get(pluginName); if (pluginConf === undefined) { return {}; } else { return pluginConf.toJS(); } }
n/a
function hasPlugin(deps, pluginName, version) { return !!deps.find(function(dep) { return dep.getName() === pluginName && (!version || dep.getVersion() === version); }); }
n/a
function isDefaultPlugin(pluginName, version) { return hasPlugin(DEFAULT_PLUGINS, pluginName, version); }
n/a
function removePlugin(config, pluginName) { var deps = config.getPluginDependencies(); // For default plugin, we have to disable it instead of removing from the list if (isDefaultPlugin(pluginName)) { return togglePlugin(config, pluginName, false); } // Remove the dependency from the list deps = deps.filterNot(function(dep) { return dep.getName() === pluginName; }); return config.setPluginDependencies(deps); }
n/a
function togglePlugin(config, pluginName, state) { var deps = config.getPluginDependencies(); // For default plugin, we should ensure it's listed first if (isDefaultPlugin(pluginName) && !hasPlugin(deps, pluginName)) { deps = deps.push(PluginDependency.create(pluginName)); } deps = deps.map(function(dep) { if (dep.getName() === pluginName) { return dep.toggle(state); } return dep; }); return config.setPluginDependencies(deps); }
n/a
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
function create(def) { return new FS(def); }
...
var book = Book.createForFS(fs);
return Parse.parseReadme(book)
// Setup default readme if doesn't found one
.fail(function() {
var readmeFile = File.createWithFilepath('README' + extension);
var readme = Readme.create(readmeFile);
return book.setReadme(readme);
});
})
.then(Parse.parseSummary)
.then(function(book) {
var logger = book.getLogger();
...
function reduceScope(fs, scope) { return fs.set('root', path.join(fs.getRoot(), scope)); }
...
*/
Book.prototype.getContentFS = function() {
var fs = this.getFS();
var config = this.getConfig();
var rootFolder = config.getValue('root');
if (rootFolder) {
return FS.reduceScope(fs, rootFolder);
}
return fs;
};
/**
Return root of the book
...
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
exists = function (filename) { var that = this; return Promise() .then(function() { filename = that.resolve(filename); var exists = that.get('fsExists'); return exists(filename); }); }
...
@return {Promise}
*/
hasFile: function(fileName, content) {
return Promise()
.then(function() {
var filePath = PathUtils.resolveInRoot(outputFolder, fileName);
return fs.exists(filePath);
});
},
/**
Write a file to the output folder,
It creates the required folder
...
findFile = function (dirname, filename) { return this.listFiles(dirname) .then(function(files) { return files.find(function(file) { return (file.toLowerCase() == filename.toLowerCase()); }); }); }
...
// Ordered list of extensions to test
var exts = parsers.extensions;
return Promise.some(exts, function(ext) {
var filepath = basename + ext;
return fs.findFile(basedir, filepath)
.then(function(found) {
if (!found || book.isContentFileIgnored(found)) {
return undefined;
}
return fs.statFile(found);
});
...
getRoot = function () { return this.get('root'); }
...
deprecate.field(output, 'config.options', result, 'options',
result.values, '"config.options" property is deprecated, use "config.get(key)" instead');
deprecate.field(output, 'config.options.generator', result.values, 'generator',
output.getGenerator(), '"options.generator" property is deprecated, use "output.name" instead
x27;);
deprecate.field(output, 'config.options.generator', result.values, 'output',
output.getRoot(), '"options.output" property is deprecated, use
"output.root()" instead');
return result;
}
module.exports = encodeConfig;
...
isInScope = function (filename) { var rootPath = this.getRoot(); filename = path.join(rootPath, filename); return PathUtil.isInRoot(rootPath, filename); }
...
*/
FS.prototype.resolve = function() {
var rootPath = this.getRoot();
var args = Array.prototype.slice.call(arguments);
var filename = path.join.apply(path, [rootPath].concat(args));
filename = path.normalize(filename);
if (!this.isInScope(filename)) {
throw error.FileOutOfScopeError({
filename: filename,
root: this.root
});
}
return filename;
...
listAllFiles = function (dirName, filterFn) { var that = this; dirName = dirName || '.'; return this.readDir(dirName) .then(function(files) { return Promise.reduce(files, function(out, file) { var isDirectory = pathIsFolder(file); var newDirName = path.join(dirName, file); if (filterFn && filterFn(newDirName) === false) { return out; } if (!isDirectory) { return out.push(newDirName); } return that.listAllFiles(newDirName, filterFn) .then(function(inner) { return out.concat(inner); }); }, Immutable.List()); }); }
...
return out;
}
if (!isDirectory) {
return out.push(newDirName);
}
return that.listAllFiles(newDirName, filterFn)
.then(function(inner) {
return out.concat(inner);
});
}, Immutable.List());
});
};
...
listFiles = function (dirname) { return this.readDir(dirname) .then(function(files) { return files.filterNot(pathIsFolder); }); }
...
Return the found filename
@param {String} dirname
@param {String} filename
@return {Promise<String>}
*/
FS.prototype.findFile = function(dirname, filename) {
return this.listFiles(dirname)
.then(function(files) {
return files.find(function(file) {
return (file.toLowerCase() == filename.toLowerCase());
});
});
};
...
loadAsObject = function (filename) { var that = this; var fsLoadObject = this.get('fsLoadObject'); return this.exists(filename) .then(function(exists) { if (!exists) { var err = new Error('Module doesn\'t exist'); err.code = 'MODULE_NOT_FOUND'; throw err; } if (fsLoadObject) { return fsLoadObject(that.resolve(filename)); } else { return that.readAsString(filename) .then(function(str) { return JSON.parse(str); }); } }); }
...
return Promise.some(CONFIG_FILES, function(filename) {
// Is this file ignored?
if (book.isFileIgnored(filename)) {
return;
}
// Try loading it
return fs.loadAsObject(filename)
.then(function(cfg) {
return fs.statFile(filename)
.then(function(file) {
return {
file: file,
values: cfg
};
...
read = function (filename) { var that = this; return Promise() .then(function() { filename = that.resolve(filename); var read = that.get('fsReadFile'); return read(filename); }); }
...
/**
Read a file from the book
@param {String} fileName
@return {Promise<Buffer>}
*/
readFile: function(fileName) {
return bookFS.read(fileName);
},
/**
Read a file from the book as a string
@param {String} fileName
@return {Promise<String>}
...
readAsStream = function (filename) { var that = this; var filepath = that.resolve(filename); var fsReadAsStream = this.get('fsReadAsStream'); if (fsReadAsStream) { return Promise(fsReadAsStream(filepath)); } return this.read(filename) .then(function(buf) { var bufferStream = new stream.PassThrough(); bufferStream.end(buf); return bufferStream; }); }
n/a
readAsString = function (filename, encoding) { encoding = encoding || 'utf8'; return this.read(filename) .then(function(buf) { return buf.toString(encoding); }); }
...
/**
Read a file from the book as a string
@param {String} fileName
@return {Promise<String>}
*/
readFileAsString: function(fileName) {
return bookFS.readAsString(fileName);
},
/**
Resolve a file from the book root
@param {String} fileName
@return {String}
...
readDir = function (dirname) { var that = this; return Promise() .then(function() { var dirpath = that.resolve(dirname); var readDir = that.get('fsReadDir'); return readDir(dirpath); }) .then(function(files) { return Immutable.List(files); }); }
...
List only files in a diretcory
Directories ends with '/'
@param {String} dirname
@return {Promise<List<String>>}
*/
FS.prototype.listFiles = function(dirname) {
return this.readDir(dirname)
.then(function(files) {
return files.filterNot(pathIsFolder);
});
};
/**
List all files in a directory
...
resolve = function () { var rootPath = this.getRoot(); var args = Array.prototype.slice.call(arguments); var filename = path.join.apply(path, [rootPath].concat(args)); filename = path.normalize(filename); if (!this.isInScope(filename)) { throw error.FileOutOfScopeError({ filename: filename, root: this.root }); } return filename; }
...
The `Book` class is the central point of GitBook, it centralize all access read methods. This class is defined in [book.js](https
://github.com/GitbookIO/gitbook/blob/master/lib/book.js).
```js
// Read configuration from book.json
var value = book.config.get('title', 'Default Value');
// Resolve a filename to an absolute path
var filepath = book.resolve('README.md');
// Render an inline markup string
book.renderInline('markdown', 'This is **Markdown**')
.then(function(str) { ... })
// Render a markup string (block mode)
book.renderBlock('markdown', '* This is **Markdown**')
...
statFile = function (filename) { var that = this; return Promise() .then(function() { var filepath = that.resolve(filename); var stat = that.get('fsStatFile'); return stat(filepath); }) .then(function(stat) { return File.createFromStat(filename, stat); }); }
...
return fs.findFile(basedir, filepath)
.then(function(found) {
if (!found || book.isContentFileIgnored(found)) {
return undefined;
}
return fs.statFile(found);
});
});
}
module.exports = findParsableFile;
...
function anonymous() { }
n/a
function anonymous() { }
n/a
function anonymous() { }
n/a
function anonymous() { }
n/a
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
function createFromStat(filepath, stat) { return new File({ path: filepath, mtime: stat.mtime }); }
...
.then(function() {
var filepath = that.resolve(filename);
var stat = that.get('fsStatFile');
return stat(filepath);
})
.then(function(stat) {
return File.createFromStat(filename, stat);
});
};
/**
List files/directories in a directory.
Directories ends with '/'
...
function createWithFilepath(filepath) { return new File({ path: filepath }); }
...
var fs = createNodeFS(rootFolder);
var book = Book.createForFS(fs);
return Parse.parseReadme(book)
// Setup default readme if doesn't found one
.fail(function() {
var readmeFile = File.createWithFilepath('README' + extension);
var readme = Readme.create(readmeFile);
return book.setReadme(readme);
});
})
.then(Parse.parseSummary)
.then(function(book) {
...
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
exists = function () { return Boolean(this.getPath()); }
...
@return {Promise}
*/
hasFile: function(fileName, content) {
return Promise()
.then(function() {
var filePath = PathUtils.resolveInRoot(outputFolder, fileName);
return fs.exists(filePath);
});
},
/**
Write a file to the output folder,
It creates the required folder
...
getExtension = function () { return path.extname(this.getPath()).toLowerCase(); }
...
/**
Return parser for this file
@return {Parser}
*/
File.prototype.getParser = function() {
return parsers.getByExt(this.getExtension());
};
/**
Create a file from stats informations
@param {String} filepath
@param {Object|fs.Stats} stat
...
getMTime = function () { return this.get('mtime'); }
...
var filePath = file.getPath();
if (!filePath) {
return undefined;
}
return {
path: filePath,
mtime: file.getMTime(),
type: file.getType()
};
}
module.exports = encodeFileToJson;
...
getParser = function () { return parsers.getByExt(this.getExtension()); }
...
this.getGlossary()
];
// List their extensions
var exts = clues.map(function (clue) {
var file = clue.getFile();
if (file.exists()) {
return file.getParser().getExtensions().first();
} else {
return null;
}
});
// Adds the general default extension
exts.push('.md');
...
getPath = function () { return this.get('path'); }
...
})
.then(Parse.parseSummary)
.then(function(book) {
var logger = book.getLogger();
var summary = book.getSummary();
var summaryFile = summary.getFile();
var summaryFilename = summaryFile.getPath() || ('SUMMARY' + extension);
var articles = summary.getArticlesAsList();
// Write pages
return Promise.forEach(articles, function(article) {
var articlePath = article.getPath();
var filePath = articlePath? path.join(rootFolder, articlePath) : null;
...
getType = function () { var parser = this.getParser(); if (parser) { return parser.getName(); } else { return undefined; } }
...
var summary = book.getSummary();
var fs = book.getContentFS();
var file = page.getFile();
// JS Page is based on the JSON output
var result = JSONUtils.encodePage(page, summary);
result.type = file.getType();
result.path = file.getPath();
result.rawPath = fs.resolve(result.path);
deprecate.field(output, 'page.progress', result, 'progress', function() {
return encodeProgress(output, page);
}, '"page.progress" property is deprecated');
...
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
function addEntry(glossary, entry) { var id = entry.getID(); var entries = glossary.getEntries(); entries = entries.set(id, entry); return glossary.set('entries', entries); }
...
*/
Glossary.addEntryByName = function addEntryByName(glossary, name, description) {
var entry = new GlossaryEntry({
name: name,
description: description
});
return Glossary.addEntry(glossary, entry);
};
/**
Create a glossary from a list of entries
@param {String} filename
@param {Array|List} entries
...
function addEntryByName(glossary, name, description) { var entry = new GlossaryEntry({ name: name, description: description }); return Glossary.addEntry(glossary, entry); }
n/a
function createFromEntries(file, entries) { entries = entries.map(function(entry) { if (!(entry instanceof GlossaryEntry)) { entry = new GlossaryEntry(entry); } return [entry.getID(), entry]; }); return new Glossary({ file: file, entries: Immutable.OrderedMap(entries) }); }
...
.spread(function(file, entries) {
if (!file) {
return book;
}
logger.debug.ln('glossary index file found at', file.getPath());
var glossary = Glossary.createFromEntries(file, entries);
return book.set('glossary', glossary);
});
}
module.exports = parseGlossary;
...
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
getEntries = function () { return this.get('entries'); }
...
Encode a glossary to JSON
@param {Glossary}
@return {Object}
*/
function encodeGlossary(glossary) {
var file = glossary.getFile();
var entries = glossary.getEntries();
return {
file: encodeFile(file),
entries: entries
.map(encodeGlossaryEntry).toJS()
};
}
...
getEntry = function (name) { var entries = this.getEntries(); var id = GlossaryEntry.nameToID(name); return entries.get(id); }
n/a
getFile = function () { return this.get('file'); }
...
});
})
.then(Parse.parseSummary)
.then(function(book) {
var logger = book.getLogger();
var summary = book.getSummary();
var summaryFile = summary.getFile();
var summaryFilename = summaryFile.getPath() || ('SUMMARY' + extension);
var articles = summary.getArticlesAsList();
// Write pages
return Promise.forEach(articles, function(article) {
var articlePath = article.getPath();
...
toText = function (parser) { var file = this.getFile(); var entries = this.getEntries(); parser = parser? parsers.getByExt(parser) : file.getParser(); if (!parser) { throw error.FileNotParsableError({ filename: file.getPath() }); } return parser.renderGlossary(entries.toJS()); }
...
// Write summary
.then(function() {
var filePath = path.join(rootFolder, summaryFilename);
return fs.ensureFile(filePath)
.then(function() {
logger.info.ln('create ' + path.basename(filePath));
return fs.writeFile(filePath, summary.toText(extension));
});
})
// Log end
.then(function() {
logger.info.ln('initialization is finished');
});
...
function generateBook(generator, book, options) { options = generator.Options(options); var state = generator.State? generator.State({}) : Immutable.Map(); var start = Date.now(); return Promise( new Output({ book: book, options: options, state: state, generator: generator.name }) ) // Cleanup output folder .then(function(output) { var logger = output.getLogger(); var rootFolder = output.getRoot(); logger.debug.ln('cleanup folder "' + rootFolder + '"'); return fs.ensureFolder(rootFolder) .thenResolve(output); }) .then(processOutput.bind(null, generator)) // Log duration and end message .then(function(output) { var logger = output.getLogger(); var end = Date.now(); var duration = (end - start)/1000; logger.info.ok('generation finished with success in ' + duration.toFixed(1) + 's !'); return output; }); }
...
var book = getBook(args, kwargs);
var logger = book.getLogger();
var Generator = Output.getGenerator('ebook');
return Parse.parseBook(book)
.then(function(resultBook) {
return Output.generate(Generator, resultBook, {
root: outputFolder,
format: format
});
})
// Extract ebook file
.then(function(output) {
...
function getGenerator(name) { return generators.find(function(generator) { return generator.name == name; }); }
...
}
};
deprecate.field(output, 'config.options', result, 'options',
result.values, '"config.options" property is deprecated, use "config.get(key)" instead');
deprecate.field(output, 'config.options.generator', result.values, 'generator',
output.getGenerator(), '"options.generator" property is deprecated
, use "output.name" instead');
deprecate.field(output, 'config.options.generator', result.values, 'output',
output.getRoot(), '"options.output" property is deprecated, use "output.root()" instead');
return result;
}
...
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
createForFile = function (file) { return new Page({ file: file }); }
...
*/
function parseFilePage(book, filePath) {
var fs = book.getContentFS();
return fs.statFile(filePath)
.then(
function(file) {
var page = Page.createForFile(file);
return parsePage(book, page);
},
function(err) {
// file doesn't exist
return null;
}
)
...
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
getAttributes = function () { return this.get('attributes'); }
...
@param {Page} page
@param {Summary} summary
@return {Object}
*/
function encodePage(page, summary) {
var file = page.getFile();
var attributes = page.getAttributes();
var article = summary.getByPath(file.getPath());
var result = attributes.toJS();
if (article) {
result.title = article.getTitle();
result.level = article.getLevel();
...
getContent = function () { return this.get('content'); }
...
@param {Output} output
@param {Page} page: page instance to edit
@param {Object} result: result from API
@return {Page}
*/
function decodePage(output, page, result) {
var originalContent = page.getContent();
// No returned value
// Existing content will be used
if (!result) {
return page;
}
...
getDir = function () { return this.get('dir'); }
...
var prevArticle = summary.getPrevArticle(article);
if (prevArticle) {
result.previous = encodeSummaryArticle(prevArticle);
}
}
result.content = page.getContent();
result.dir = page.getDir();
return result;
}
module.exports = encodePage;
...
getFile = function () { return this.get('file'); }
...
});
})
.then(Parse.parseSummary)
.then(function(book) {
var logger = book.getLogger();
var summary = book.getSummary();
var summaryFile = summary.getFile();
var summaryFilename = summaryFile.getPath() || ('SUMMARY' + extension);
var articles = summary.getArticlesAsList();
// Write pages
return Promise.forEach(articles, function(article) {
var articlePath = article.getPath();
...
getPath = function () { return this.getFile().getPath(); }
...
})
.then(Parse.parseSummary)
.then(function(book) {
var logger = book.getLogger();
var summary = book.getSummary();
var summaryFile = summary.getFile();
var summaryFilename = summaryFile.getPath() || ('SUMMARY' + extension);
var articles = summary.getArticlesAsList();
// Write pages
return Promise.forEach(articles, function(article) {
var articlePath = article.getPath();
var filePath = articlePath? path.join(rootFolder, articlePath) : null;
...
toText = function () { var attrs = this.getAttributes(); var content = this.getContent(); if (attrs.size === 0) { return content; } var frontMatter = '---\n' + yaml.safeDump(attrs.toJS(), { skipInvalid: true }) + '---\n\n'; return (frontMatter + content); }
...
// Write summary
.then(function() {
var filePath = path.join(rootFolder, summaryFilename);
return fs.ensureFile(filePath)
.then(function() {
logger.info.ln('create ' + path.basename(filePath));
return fs.writeFile(filePath, summary.toText(extension));
});
})
// Log end
.then(function() {
logger.info.ln('initialization is finished');
});
...
function listAssets(book, pages) { var fs = book.getContentFS(); var summary = book.getSummary(); var summaryFile = summary.getFile().getPath(); var glossary = book.getGlossary(); var glossaryFile = glossary.getFile().getPath(); var langs = book.getLanguages(); var langsFile = langs.getFile().getPath(); var config = book.getConfig(); var configFile = config.getFile().getPath(); function filterFile(file) { return !( file === summaryFile || file === glossaryFile || file === langsFile || file === configFile || book.isContentFileIgnored(file) || pages.has(file) ); } return timing.measure( 'parse.listAssets', fs.listAllFiles('.', filterFile) ); }
...
@return {Promise<Output>}
*/
function prepareAssets(output) {
var book = output.getBook();
var pages = output.getPages();
var logger = output.getLogger();
return Parse.listAssets(book, pages)
.then(function(assets) {
logger.info.ln('found', assets.size, 'asset files');
return output.set('assets', assets);
});
}
...
function lookupStructureFile(book, type) { var config = book.getConfig(); var fileToSearch = config.getValue(['structure', type]); return findParsableFile(book, fileToSearch); }
n/a
function parseBook(book) { return timing.measure( 'parse.book', Promise(book) .then(parseIgnore) .then(parseConfig) .then(parseLanguages) .then(function(resultBook) { if (resultBook.isMultilingual()) { return parseMultilingualBook(resultBook); } else { return parseBookContent(resultBook); } }) ); }
...
// Create temporary directory
var outputFolder = tmp.dirSync().name;
var book = getBook(args, kwargs);
var logger = book.getLogger();
var Generator = Output.getGenerator('ebook');
return Parse.parseBook(book)
.then(function(resultBook) {
return Output.generate(Generator, resultBook, {
root: outputFolder,
format: format
});
})
...
function parseConfig(book) { var fs = book.getFS(); var config = book.getConfig(); return Promise.some(CONFIG_FILES, function(filename) { // Is this file ignored? if (book.isFileIgnored(filename)) { return; } // Try loading it return fs.loadAsObject(filename) .then(function(cfg) { return fs.statFile(filename) .then(function(file) { return { file: file, values: cfg }; }); }) .fail(function(err) { if (err.code != 'MODULE_NOT_FOUND') throw(err); else return Promise(false); }); }) .then(function(result) { var values = result? result.values : {}; values = validateConfig(values); // Set the file if (result.file) { config = config.setFile(result.file); } // Merge with old values config = config.mergeValues(values); return book.setConfig(config); }); }
...
description: 'install all plugins dependencies',
options: [
options.log
],
exec: function(args, kwargs) {
var book = getBook(args, kwargs);
return Parse.parseConfig(book)
.then(function(resultBook) {
return Plugins.installPlugins(resultBook);
});
}
};
...
function parseGlossary(book) { var logger = book.getLogger(); return parseStructureFile(book, 'glossary') .spread(function(file, entries) { if (!file) { return book; } logger.debug.ln('glossary index file found at', file.getPath()); var glossary = Glossary.createFromEntries(file, entries); return book.set('glossary', glossary); }); }
...
}
return fs.readAsString(filepath)
.then(function(content) {
if (type === 'readme') {
return parser.parseReadme(content);
} else if (type === 'glossary') {
return parser.parseGlossary(content);
} else if (type === 'summary') {
return parser.parseSummary(content);
} else if (type === 'langs') {
return parser.parseLanguages(content);
} else {
throw new Error('Parsing invalid type "' + type + '"');
}
...
function parseIgnore(book) { if (book.isLanguageBook()) { return Promise.reject(new Error('Ignore files could be parsed for language books')); } var fs = book.getFS(); var ignore = book.getIgnore(); ignore = ignore.add(DEFAULT_IGNORES); return Promise.serie(IGNORE_FILES, function(filename) { return fs.readAsString(filename) .then(function(content) { ignore = ignore.add(content.toString().split(/\r?\n/)); }, function(err) { return Promise(); }); }) .then(function() { return book.setIgnore(ignore); }); }
n/a
function parseLanguages(book) { var logger = book.getLogger(); return parseStructureFile(book, 'langs') .spread(function(file, result) { if (!file) { return book; } var languages = Languages.createFromList(file, result); logger.debug.ln('languages index file found at', file.getPath()); logger.info.ln('parsing multilingual book, with', languages.getList().size, 'languages'); return book.set('languages', languages); }); }
...
if (type === 'readme') {
return parser.parseReadme(content);
} else if (type === 'glossary') {
return parser.parseGlossary(content);
} else if (type === 'summary') {
return parser.parseSummary(content);
} else if (type === 'langs') {
return parser.parseLanguages(content);
} else {
throw new Error('Parsing invalid type "' + type + '"');
}
})
.then(function(result) {
return [
file,
...
function parsePage(book, page) { var fs = book.getContentFS(); var file = page.getFile(); return fs.readAsString(file.getPath()) .then(function(content) { return parsePageFromString(page, content); }); }
...
@param {String} type
@param {String} text
@return {Promise<String>}
*/
renderBlock: function(type, text) {
var parser = parsers.get(type);
return parser.parsePage(text)
.get('content');
},
/**
Render an inline text (markdown/asciidoc)
@param {String} type
...
function parsePageFromString(page, content) { // Parse page YAML var parsed = fm(content); return page.merge({ content: parsed.body, attributes: Immutable.fromJS(parsed.attributes), dir: direction(parsed.body) }); }
n/a
function parsePagesList(book) { var summary = book.getSummary(); var glossary = book.getGlossary(); var map = Immutable.OrderedMap(); // Parse pages from summary return timing.measure( 'parse.listPages', walkSummary(summary, function(article) { if (!article.isPage()) return; var filepath = article.getPath(); // Is the page ignored? if (book.isContentFileIgnored(filepath)) return; return parseFilePage(book, filepath) .then(function(page) { // file doesn't exist if (!page) { return; } map = map.set(filepath, page); }); }) ) // Parse glossary .then(function() { var file = glossary.getFile(); if (!file.exists()) { return; } return parseFilePage(book, file.getPath()) .then(function(page) { // file doesn't exist if (!page) { return; } map = map.set(file.getPath(), page); }); }) .then(function() { return map; }); }
...
var book = output.getBook();
var logger = book.getLogger();
if (book.isMultilingual()) {
return Promise(output);
}
return Parse.parsePagesList(book)
.then(function(pages) {
logger.info.ln('found', pages.size, 'pages');
return output.set('pages', pages);
});
}
...
function parseReadme(book) { var logger = book.getLogger(); return parseStructureFile(book, 'readme') .spread(function(file, result) { if (!file) { throw new error.FileNotFoundError({ filename: 'README' }); } logger.debug.ln('readme found at', file.getPath()); var readme = Readme.create(file, result); return book.set('readme', readme); }); }
...
return fs.mkdirp(rootFolder)
// Parse the summary and readme
.then(function() {
var fs = createNodeFS(rootFolder);
var book = Book.createForFS(fs);
return Parse.parseReadme(book)
// Setup default readme if doesn't found one
.fail(function() {
var readmeFile = File.createWithFilepath('README' + extension);
var readme = Readme.create(readmeFile);
return book.setReadme(readme);
});
...
function parseSummary(book) { var readme = book.getReadme(); var logger = book.getLogger(); var readmeFile = readme.getFile(); return parseStructureFile(book, 'summary') .spread(function(file, result) { var summary; if (!file) { logger.warn.ln('no summary file in this book'); summary = Summary(); } else { logger.debug.ln('summary file found at', file.getPath()); summary = Summary.createFromParts(file, result.parts); } // Insert readme as first entry if not in SUMMARY.md var readmeArticle = summary.getByPath(readmeFile.getPath()); if (readmeFile.exists() && !readmeArticle) { summary = SummaryModifier.unshiftArticle(summary, { title: 'Introduction', ref: readmeFile.getPath() }); } // Set new summary return book.setSummary(summary); }); }
...
return fs.readAsString(filepath)
.then(function(content) {
if (type === 'readme') {
return parser.parseReadme(content);
} else if (type === 'glossary') {
return parser.parseGlossary(content);
} else if (type === 'summary') {
return parser.parseSummary(content);
} else if (type === 'langs') {
return parser.parseLanguages(content);
} else {
throw new Error('Parsing invalid type "' + type + '"');
}
})
.then(function(result) {
...
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
create = function (name, version, enabled) { if (is.undefined(enabled)) { enabled = true; } return new PluginDependency({ name: name, version: version || DEFAULT_VERSION, enabled: Boolean(enabled) }); }
...
var book = Book.createForFS(fs);
return Parse.parseReadme(book)
// Setup default readme if doesn't found one
.fail(function() {
var readmeFile = File.createWithFilepath('README' + extension);
var readme = Readme.create(readmeFile);
return book.setReadme(readme);
});
})
.then(Parse.parseSummary)
.then(function(book) {
var logger = book.getLogger();
...
createFromString = function (s) { var parts = s.split('@'); var name = parts[0]; var version = parts.slice(1).join('@'); var enabled = true; if (name[0] === '-') { enabled = false; name = name.slice(1); } return new PluginDependency({ name: name, version: version || DEFAULT_VERSION, enabled: enabled }); }
...
* @param {Array}
* @return {List<PluginDependency>}
*/
PluginDependency.listFromArray = function(arr) {
return Immutable.List(arr)
.map(function(entry) {
if (is.string(entry)) {
return PluginDependency.createFromString(entry);
} else {
return PluginDependency({
name: entry.get('name'),
version: entry.get('version')
});
}
})
...
listFromArray = function (arr) { return Immutable.List(arr) .map(function(entry) { if (is.string(entry)) { return PluginDependency.createFromString(entry); } else { return PluginDependency({ name: entry.get('name'), version: entry.get('version') }); } }) .filter(function(dep) { return Boolean(dep.getName()); }); }
...
*/
Config.prototype.getPluginDependencies = function() {
var plugins = this.getValue('plugins');
if (is.string(plugins)) {
return PluginDependency.listFromString(plugins);
} else {
return PluginDependency.listFromArray(plugins);
}
};
/**
* Return a plugin dependency by its name
* @param {String} name
* @return {PluginDependency}
...
listFromString = function (s) { var parts = s.split(','); return PluginDependency.listFromArray(parts); }
...
* Return a list of plugin dependencies
* @return {List<PluginDependency>}
*/
Config.prototype.getPluginDependencies = function() {
var plugins = this.getValue('plugins');
if (is.string(plugins)) {
return PluginDependency.listFromString(plugins);
} else {
return PluginDependency.listFromArray(plugins);
}
};
/**
* Return a plugin dependency by its name
...
listToArray = function (list) { return list .map(function(dep) { var result = ''; if (!dep.isEnabled()) { result += '-'; } result += dep.getName(); if (dep.getVersion() !== DEFAULT_VERSION) { result += '@' + dep.getVersion(); } return result; }) .toJS(); }
...
/**
* Update the list of plugins dependencies
* @param {List<PluginDependency>}
* @return {Config}
*/
Config.prototype.setPluginDependencies = function(deps) {
var plugins = PluginDependency.listToArray(deps);
return this.setValue('plugins', plugins);
};
/**
* Update values for an existing configuration
...
nameToNpmID = function (s) { return PREFIX + s; }
...
/**
* Create a PluginDependency from a dependency of gitbook
* @param {String} pluginName
* @return {PluginDependency}
*/
function createFromDependency(pluginName) {
var npmID = PluginDependency.nameToNpmID(pluginName);
var version = pkg.dependencies[npmID];
return PluginDependency.create(pluginName, version);
}
/*
* List of default plugins for all books,
...
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
getName = function () { return this.get('name'); }
...
* Return a specific parser by its name
*
* @param {String} name
* @return {Parser|undefined}
*/
function getParser(name) {
return parsers.find(function(parser) {
return parser.getName() === name;
});
}
/**
* Return a specific parser according to an extension
*
* @param {String} ext
...
getNpmID = function () { return PluginDependency.nameToNpmID(this.getName()); }
...
.then(function(version) {
if (!version) {
throw new Error('Found no satisfactory version for plugin "' + name + '" with requirement "'
; + requirement + '"');
}
logger.info.ln('install plugin "' + name +'" (' + requirement + ') from NPM with version'
;, version);
return Promise.nfcall(npmi, {
'name': plugin.getNpmID(),
'version': version,
'path': installFolder,
'npmLoad': {
'loglevel': 'silent',
'loaded': true,
'prefix': installFolder
}
...
getVersion = function () { return this.get('version'); }
...
};
/**
* Is the plugin using a git dependency
* @return {Boolean}
*/
PluginDependency.prototype.isGitDependency = function() {
return !semver.validRange(this.getVersion());
};
/**
* Create a plugin with a name and a plugin
* @param {String}
* @return {Plugin|undefined}
*/
...
isEnabled = function () { return this.get('enabled'); }
...
/**
* Toggle this plugin state
* @param {Boolean}
* @return {PluginDependency}
*/
PluginDependency.prototype.toggle = function(state) {
if (is.undef(state)) {
state = !this.isEnabled();
}
return this.set('enabled', state);
};
/**
* Return NPM ID for the dependency
...
isGitDependency = function () { return !semver.validRange(this.getVersion()); }
...
@param {PluginDependency} plugin
@return {Promise<String>}
*/
function resolveVersion(plugin) {
var npmId = Plugin.nameToNpmID(plugin.getName());
var requiredVersion = plugin.getVersion();
if (plugin.isGitDependency()) {
return Promise.resolve(requiredVersion);
}
return initNPM()
.then(function() {
return Promise.nfcall(npm.commands.view, [npmId + '@' + requiredVersion, 'engines'], true);
})
...
toggle = function (state) { if (is.undef(state)) { state = !this.isEnabled(); } return this.set('enabled', state); }
...
// For default plugin, we should ensure it's listed first
if (isDefaultPlugin(pluginName) && !hasPlugin(deps, pluginName)) {
deps = deps.push(PluginDependency.create(pluginName));
}
deps = deps.map(function(dep) {
if (dep.getName() === pluginName) {
return dep.toggle(state);
}
return dep;
});
return config.setPluginDependencies(deps);
}
...
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
function createFromParts(file, parts) { parts = parts.map(function(part, i) { if (part instanceof SummaryPart) { return part; } return SummaryPart.create(part, i + 1); }); return new Summary({ file: file, parts: new Immutable.List(parts) }); }
...
var summary;
if (!file) {
logger.warn.ln('no summary file in this book');
summary = Summary();
} else {
logger.debug.ln('summary file found at', file.getPath());
summary = Summary.createFromParts(file, result.parts);
}
// Insert readme as first entry if not in SUMMARY.md
var readmeArticle = summary.getByPath(readmeFile.getPath());
if (readmeFile.exists() && !readmeArticle) {
summary = SummaryModifier.unshiftArticle(summary, {
...
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
getArticle = function (iter, partIter) { var parts = this.getParts(); return parts.reduce(function(result, part) { if (result) return result; if (partIter && partIter(part)) return part; return SummaryArticle.findArticle(part, iter); }, null); }
...
var result = {
/**
Iterate over the summary, it stops when the "iter" returns false
@param {Function} iter
*/
walk: function (iter) {
summary.getArticle(function(article) {
var jsonArticle = encodeSummaryArticle(article, false);
return iter(jsonArticle);
});
},
/**
...
getArticlesAsList = function () { var accu = []; this.getArticle(function(article) { accu.push(article); }); return Immutable.List(accu); }
...
.then(function(book) {
var logger = book.getLogger();
var summary = book.getSummary();
var summaryFile = summary.getFile();
var summaryFilename = summaryFile.getPath() || ('SUMMARY' + extension);
var articles = summary.getArticlesAsList();
// Write pages
return Promise.forEach(articles, function(article) {
var articlePath = article.getPath();
var filePath = articlePath? path.join(rootFolder, articlePath) : null;
if (!filePath) {
return;
...
getByLevel = function (level) { function iterByLevel(article) { return (article.getLevel() === level); } return this.getArticle(iterByLevel, iterByLevel); }
...
/**
Get an article by its level
@param {String} level
@return {Object}
*/
getArticleByLevel: function(level) {
var article = summary.getByLevel(level);
return (article? encodeSummaryArticle(article) : undefined);
},
/**
Get an article by its path
@param {String} level
...
getByPath = function (filePath) { return this.getArticle(function(article) { var articlePath = article.getPath(); return ( articlePath && LocationUtils.areIdenticalPaths(articlePath, filePath) ); }); }
...
/**
Get an article by its path
@param {String} level
@return {Object}
*/
getArticleByPath: function(level) {
var article = summary.getByPath(level);
return (article? encodeSummaryArticle(article) : undefined);
}
};
return result;
}
...
getFile = function () { return this.get('file'); }
...
});
})
.then(Parse.parseSummary)
.then(function(book) {
var logger = book.getLogger();
var summary = book.getSummary();
var summaryFile = summary.getFile();
var summaryFilename = summaryFile.getPath() || ('SUMMARY' + extension);
var articles = summary.getArticlesAsList();
// Write pages
return Promise.forEach(articles, function(article) {
var articlePath = article.getPath();
...
getFirstArticle = function () { return this.getArticle(function(article) { return true; }); }
n/a
getNextArticle = function (current) { var level = is.string(current)? current : current.getLevel(); var wasPrev = false; return this.getArticle(function(article) { if (wasPrev) return true; wasPrev = article.getLevel() == level; return false; }); }
...
var result = attributes.toJS();
if (article) {
result.title = article.getTitle();
result.level = article.getLevel();
result.depth = article.getDepth();
var nextArticle = summary.getNextArticle(article);
if (nextArticle) {
result.next = encodeSummaryArticle(nextArticle);
}
var prevArticle = summary.getPrevArticle(article);
if (prevArticle) {
result.previous = encodeSummaryArticle(prevArticle);
...
getParent = function (level) { // Coerce to level level = is.string(level)? level : level.getLevel(); // Get parent level var parentLevel = getParentLevel(level); if (!parentLevel) { return null; } // Get parent of the position var parentArticle = this.getByLevel(parentLevel); return parentArticle || null; }
...
var plugins = requirements.reduce(function(result, dep) {
var name = dep.getName();
var installed = installedMap.get(name);
if (installed) {
var deps = installedMap
.filter(function(plugin) {
return plugin.getParent() === name;
})
.toArray();
result = result.concat(deps);
result.push(installed);
} else {
missing.push(name);
...
getPart = function (i) { var parts = this.getParts(); return parts.get(i); }
n/a
getParts = function () { return this.get('parts'); }
...
Encode a summary to JSON
@param {Summary}
@return {Object}
*/
function encodeSummary(summary) {
var file = summary.getFile();
var parts = summary.getParts();
return {
file: encodeFile(file),
parts: parts.map(encodeSummaryPart).toJS()
};
}
...
getPrevArticle = function (current) { var level = is.string(current)? current : current.getLevel(); var prev = undefined; this.getArticle(function(article) { if (article.getLevel() == level) { return true; } prev = article; return false; }); return prev; }
...
result.depth = article.getDepth();
var nextArticle = summary.getNextArticle(article);
if (nextArticle) {
result.next = encodeSummaryArticle(nextArticle);
}
var prevArticle = summary.getPrevArticle(article);
if (prevArticle) {
result.previous = encodeSummaryArticle(prevArticle);
}
}
result.content = page.getContent();
result.dir = page.getDir();
...
toText = function (parseExt) { var file = this.getFile(); var parts = this.getParts(); var parser = parseExt? parsers.getByExt(parseExt) : file.getParser(); if (!parser) { throw error.FileNotParsableError({ filename: file.getPath() }); } return parser.renderSummary({ parts: parts.toJS() }); }
...
// Write summary
.then(function() {
var filePath = path.join(rootFolder, summaryFilename);
return fs.ensureFile(filePath)
.then(function() {
logger.info.ln('create ' + path.basename(filePath));
return fs.writeFile(filePath, summary.toText(extension));
});
})
// Log end
.then(function() {
logger.info.ln('initialization is finished');
});
...
function editArticleRef(summary, level, newRef) { return mergeAtLevel(summary, level, { ref: newRef }); }
n/a
function editArticleTitle(summary, level, newTitle) { return mergeAtLevel(summary, level, { title: newTitle }); }
n/a
function editPartTitle(summary, index, newTitle) { var parts = summary.getParts(); var part = parts.get(index); if (!part) { return summary; } part = part.set('title', newTitle); parts = parts.set(index, part); return summary.set('parts', parts); }
n/a
function insertArticle(summary, article, level) { article = SummaryArticle(article); level = is.string(level)? level : level.getLevel(); var parent = summary.getParent(level); if (!parent) { return summary; } // Find the index to insert at var articles = parent.getArticles(); var index = getLeafIndex(level); // Insert the article at the right index articles = articles.insert(index, article); // Reindex the level from here parent = parent.set('articles', articles); parent = indexArticleLevels(parent); return mergeAtLevel(summary, parent.getLevel(), parent); }
n/a
function insertPart(summary, part, index) { part = SummaryPart(part); var parts = summary.getParts().insert(index, part); return indexLevels(summary.set('parts', parts)); }
n/a
function moveArticle(summary, origin, target) { // Coerce to level var originLevel = is.string(origin)? origin : origin.getLevel(); var targetLevel = is.string(target)? target : target.getLevel(); var article = summary.getByLevel(originLevel); // Remove first var removed = removeArticle(summary, originLevel); return insertArticle(removed, article, targetLevel); }
n/a
function moveArticleAfter(summary, origin, afterTarget) { // Coerce to level var originLevel = is.string(origin)? origin : origin.getLevel(); var afterTargetLevel = is.string(afterTarget)? afterTarget : afterTarget.getLevel(); var article = summary.getByLevel(originLevel); var targetLevel = increment(afterTargetLevel); if (targetLevel < origin) { // Remove first var removed = removeArticle(summary, originLevel); // Insert then return insertArticle(removed, article, targetLevel); } else { // Insert right after first var inserted = insertArticle(summary, article, targetLevel); // Remove old one return removeArticle(inserted, originLevel); } }
n/a
function removeArticle(summary, level) { // Coerce to level level = is.string(level)? level : level.getLevel(); var parent = summary.getParent(level); var articles = parent.getArticles(); // Find the index to remove var index = articles.findIndex(function(art) { return art.getLevel() === level; }); if (index === -1) { return summary; } // Remove from children articles = articles.remove(index); parent = parent.set('articles', articles); // Reindex the level from here parent = indexArticleLevels(parent); return mergeAtLevel(summary, parent.getLevel(), parent); }
n/a
function removePart(summary, index) { var parts = summary.getParts().remove(index); return indexLevels(summary.set('parts', parts)); }
n/a
function unshiftArticle(summary, article) { article = SummaryArticle(article); var parts = summary.getParts(); var part = parts.get(0) || SummaryPart(); var articles = part.getArticles(); articles = articles.unshift(article); part = part.set('articles', articles); parts = parts.set(0, part); summary = summary.set('parts', parts); return indexLevels(summary); }
...
summary = Summary.createFromParts(file, result.parts);
}
// Insert readme as first entry if not in SUMMARY.md
var readmeArticle = summary.getByPath(readmeFile.getPath());
if (readmeFile.exists() && !readmeArticle) {
summary = SummaryModifier.unshiftArticle(summary, {
title: 'Introduction',
ref: readmeFile.getPath()
});
}
// Set new summary
return book.setSummary(summary);
...
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
function exec(command, options) { var d = Promise.defer(); var child = childProcess.exec(command, options, function(err, stdout, stderr) { if (!err) { return d.resolve(); } err.message = stdout.toString('utf8') + stderr.toString('utf8'); d.reject(err); }); child.stdout.on('data', function (data) { d.notify(data); }); child.stderr.on('data', function (data) { d.notify(data); }); return d.promise; }
...
@param {String} command
@param {Object} options
@return {Promise}
*/
function exec(command, options) {
var d = Promise.defer();
var child = childProcess.exec(command, options, function(err, stdout, stderr) {
if (!err) {
return d.resolve();
}
err.message = stdout.toString('utf8') + stderr.toString('utf8');
d.reject(err);
});
...
function optionsToShellArgs(options) { var result = []; for (var key in options) { var value = options[key]; if (value === null || value === undefined || value === false) { continue; } if (is.bool(value)) { result.push(key); } else { result.push(key + '=' + escapeShellArg(value)); } } return result.join(' '); }
...
return getConvertOptions(output)
.then(function(options) {
var cmd = [
'ebook-convert',
path.resolve(outputFolder, SUMMARY_FILE),
path.resolve(outputFolder, 'index.' + format),
command.optionsToShellArgs(options)
].join(' ');
return command.exec(cmd)
.progress(function(data) {
logger.debug(data);
})
.fail(function(err) {
...
function spawnCmd(command, args, options) { var d = Promise.defer(); var child = spawn(command, args, options); child.on('error', function(error) { return d.reject(error); }); child.stdout.on('data', function (data) { d.notify(data); }); child.stderr.on('data', function (data) { d.notify(data); }); child.on('close', function(code) { if (code === 0) { d.resolve(); } else { d.reject(new Error('Error with command "'+command+'"')); } }); return d.promise; }
...
var fs = require('./fs');
var error = require('./error');
// Convert a svg file to a pmg
function convertSVGToPNG(source, dest, options) {
if (!fs.existsSync(source)) return Promise.reject(new error.FileNotFoundError({ filename: source }));
return command.spawn('svgexport', [source, dest])
.fail(function(err) {
if (err.code == 'ENOENT') {
err = error.RequireInstallError({
cmd: 'svgexport',
install: 'Install it using: "npm install svgexport -g"'
});
}
...
conrefsLoader = function () { if(prototype.init) { prototype.init.apply(this, arguments); } }
n/a
extend = function (name, props) { if(typeof name === 'object') { props = name; name = 'anonymous'; } return extend(new_cls, name, props); }
...
var is = require('is');
var path = require('path');
var fs = require('fs');
var expect = require('expect');
var cheerio = require('cheerio');
expect.extend({
/**
* Check that a file is created in a directory:
* expect('myFolder').toHaveFile('hello.md');
*/
toHaveFile: function(fileName) {
var filePath = path.join(this.actual, fileName);
var exists = fs.existsSync(filePath);
...
constructor = function () { if(prototype.init) { prototype.init.apply(this, arguments); } }
n/a
getSource = function (sourceURL, callback) { var that = this; this.git.resolve(sourceURL) .then(function(filepath) { // Is local file if (!filepath) { filepath = path.resolve(sourceURL); } else { if (that.logger) that.logger.debug.ln('resolve from git', sourceURL, 'to', filepath); } // Read file from absolute path return fs.readFile(filepath) .then(function(source) { source = source.toString('utf8'); if (that.transformFn) { return that.transformFn(filepath, source); } return source; }) .then(function(source) { return { src: source, path: filepath }; }); }) .nodeify(callback); }
...
// Resolve the filePath
var resolvedFilePath = loader.resolve(null, filePath);
return Promise()
.then(function() {
if (!loader.async) {
return loader.getSource(resolvedFilePath);
}
var deferred = Promise.defer();
loader.getSource(resolvedFilePath, deferred.makeNodeResolver());
return deferred.promise;
})
.then(function(result) {
...
init = function (rootFolder, transformFn, logger) { this.rootFolder = rootFolder; this.transformFn = transformFn; this.logger = logger; this.git = new Git(); }
n/a
isRelative = function (filename) { return LocationUtils.isRelative(filename); }
...
// If origin is not in the book (include from a git content ref)
return path.resolve(path.dirname(from), to);
},
// Handle all files as relative, so that nunjucks pass responsability to 'resolve'
isRelative: function(filename) {
return LocationUtils.isRelative(filename);
}
});
module.exports = ConrefsLoader;
...
resolve = function (from, to) { // If origin is in the book, we enforce result file to be in the book if (PathUtils.isInRoot(this.rootFolder, from)) { // Path of current template in the rootFolder (not absolute to fs) var fromRelative = path.relative(this.rootFolder, from); // Resolve "to" to a filepath relative to rootFolder var href = LocationUtils.toAbsolute(to, path.dirname(fromRelative), ''); // Return absolute path return PathUtils.resolveInRoot(this.rootFolder, href); } // If origin is in a git repository, we resolve file in the git repository var gitRoot = this.git.resolveRoot(from); if (gitRoot) { return PathUtils.resolveInRoot(gitRoot, to); } // If origin is not in the book (include from a git content ref) return path.resolve(path.dirname(from), to); }
...
The `Book` class is the central point of GitBook, it centralize all access read methods. This class is defined in [book.js](https
://github.com/GitbookIO/gitbook/blob/master/lib/book.js).
```js
// Read configuration from book.json
var value = book.config.get('title', 'Default Value');
// Resolve a filename to an absolute path
var filepath = book.resolve('README.md');
// Render an inline markup string
book.renderInline('markdown', 'This is **Markdown**')
.then(function(str) { ... })
// Render a markup string (block mode)
book.renderBlock('markdown', '* This is **Markdown**')
...
function disableDeprecation(key) { disabled[key] = true; }
...
// No returned value
// Existing content will be used
if (!result) {
return page;
}
deprecate.disable('page.sections');
// GitBook 3
// Use returned page.content if different from original content
if (result.content != originalContent) {
page = page.set('content', result.content);
}
...
function enableDeprecation(key) { disabled[key] = false; }
...
page = page.set('content',
result.sections.map(function(section) {
return section.content;
}).join('\n')
);
}
deprecate.enable('page.sections');
return page;
}
module.exports = decodePage;
...
function deprecateField(book, key, instance, property, value, msg) { var store = undefined; var prepare = function() { if (!is.undefined(store)) return; if (is.fn(value)) store = value(); else store = value; }; var getter = function(){ prepare(); logNotice(book, key, msg); return store; }; var setter = function(v) { prepare(); logNotice(book, key, msg); store = v; return store; }; Object.defineProperty(instance, property, { get: getter, set: setter, enumerable: true, configurable: true }); }
...
},
set: function(key, value) {
return objectPath.set(result.values, key, value);
}
};
deprecate.field(output, 'config.options', result, 'options',
result.values, '"config.options" property is deprecated, use "config.get(key)" instead');
deprecate.field(output, 'config.options.generator', result.values, 'generator',
output.getGenerator(), '"options.generator" property is deprecated, use "output.name" instead');
deprecate.field(output, 'config.options.generator', result.values, 'output',
output.getRoot(), '"options.output" property is deprecated, use "output.root()" instead');
...
function deprecateMethod(book, key, fn, msg) { return function() { logNotice(book, key, msg); return fn.apply(this, arguments); }; }
n/a
function deprecateRenamedMethod(book, key, instance, oldName, newName, msg) { msg = msg || ('"' + oldName + '" is deprecated, use "' + newName + '()" instead'); var fn = objectPath.get(instance, newName); instance[oldName] = deprecateMethod(book, key, fn, msg); }
...
gitbook: {
version: gitbook.version
}
};
// Deprecated properties
deprecate.renamedMethod(output, 'this.isSubBook', result, 'isSubBook
x27;, 'isLanguageBook');
deprecate.renamedMethod(output, 'this.contentLink', result, 'contentLink', 'output.toURL');
deprecate.field(output, 'this.generator', result, 'generator',
output.getGenerator(), '"this.generator" property is deprecated, use "this.output.name" instead'
;);
deprecate.field(output, 'this.navigation', result, 'navigation', function() {
return encodeNavigation(output);
...
function createError(cause, opts) {
/*eslint max-statements: [2, 25]*/
assert(cause, 'an error is required');
assert(isError(cause),
'WrappedError: first argument must be an error');
var causeMessage = cause.message;
if (causeMessage.indexOf('{causeMessage}') >= 0) {
// recover
causeMessage = causeMessage.replace(
causeMessageRegex,
'$INVALID_CAUSE_MESSAGE_LITERAL'
);
}
if (causeMessage.indexOf('{origMessage}') >= 0) {
causeMessage = causeMessage.replace(
origMessageRegex,
'$INVALID_ORIG_MESSAGE_LITERAL'
);
}
var nodeCause = false;
var errOptions = extend({}, opts, {
causeMessage: causeMessage,
origMessage: causeMessage
});
if (has(cause, 'code') && !has(errOptions, 'code')) {
errOptions.code = cause.code;
}
if (has(cause, 'errno') && !has(errOptions, 'errno')) {
errOptions.errno = cause.errno;
nodeCause = true;
}
if (has(cause, 'syscall') && !has(errOptions, 'syscall')) {
errOptions.syscall = cause.syscall;
nodeCause = true;
}
var causeType = cause.type;
if (!causeType && nodeCause) {
causeType = 'error.wrapped-io.' +
(cause.syscall || 'unknown') + '.' +
(cause.errno || 'unknown');
} else {
causeType = 'error.wrapped-unknown';
}
errOptions.fullType = options.type + '~!~' +
(cause.fullType || cause.type || causeType);
var err = createTypedError(errOptions);
Object.defineProperty(err, 'cause', {
value: cause,
configurable: true,
enumerable: false
});
return err;
}
...
var v = new jsonschema.Validator();
var result = v.validate(bookJson, schema, {
propertyName: 'config'
});
// Throw error
if (result.errors.length > 0) {
throw new error.ConfigurationError(new Error(result.errors[0].stack));
}
// Insert default values
var defaults = jsonSchemaDefaults(schema);
return mergeDefaults(bookJson, defaults);
}
...
function createError(cause, opts) {
/*eslint max-statements: [2, 25]*/
assert(cause, 'an error is required');
assert(isError(cause),
'WrappedError: first argument must be an error');
var causeMessage = cause.message;
if (causeMessage.indexOf('{causeMessage}') >= 0) {
// recover
causeMessage = causeMessage.replace(
causeMessageRegex,
'$INVALID_CAUSE_MESSAGE_LITERAL'
);
}
if (causeMessage.indexOf('{origMessage}') >= 0) {
causeMessage = causeMessage.replace(
origMessageRegex,
'$INVALID_ORIG_MESSAGE_LITERAL'
);
}
var nodeCause = false;
var errOptions = extend({}, opts, {
causeMessage: causeMessage,
origMessage: causeMessage
});
if (has(cause, 'code') && !has(errOptions, 'code')) {
errOptions.code = cause.code;
}
if (has(cause, 'errno') && !has(errOptions, 'errno')) {
errOptions.errno = cause.errno;
nodeCause = true;
}
if (has(cause, 'syscall') && !has(errOptions, 'syscall')) {
errOptions.syscall = cause.syscall;
nodeCause = true;
}
var causeType = cause.type;
if (!causeType && nodeCause) {
causeType = 'error.wrapped-io.' +
(cause.syscall || 'unknown') + '.' +
(cause.errno || 'unknown');
} else {
causeType = 'error.wrapped-unknown';
}
errOptions.fullType = options.type + '~!~' +
(cause.fullType || cause.type || causeType);
var err = createTypedError(errOptions);
Object.defineProperty(err, 'cause', {
value: cause,
configurable: true,
enumerable: false
});
return err;
}
...
if (err.code == 127) {
throw error.RequireInstallError({
cmd: 'ebook-convert',
install: 'Install it from Calibre: https://calibre-ebook.com'
});
}
throw error.EbookError(err);
});
})
.thenResolve(output);
}
/**
Finish the generation, generates the SUMMARY.html
...
function createError(opts) { var result = new Error(); Object.defineProperty(result, 'type', { value: result.type, enumerable: true, writable: true, configurable: true }); var options = extend({}, args, opts); if (!options.fullType) { options.fullType = options.type; } extend(result, options); if (opts && opts.message) { result.message = template(opts.message, options); } else if (message) { result.message = template(message, options); } return result; }
...
function fsExists(filePath) {
return Boolean(getFile(filePath) !== null);
}
function fsReadFile(filePath) {
var file = getFile(filePath);
if (!is.string(file)) {
throw error.FileNotFoundError({
filename: filePath
});
}
return new Buffer(file, 'utf8');
}
...
function createError(opts) { var result = new Error(); Object.defineProperty(result, 'type', { value: result.type, enumerable: true, writable: true, configurable: true }); var options = extend({}, args, opts); if (!options.fullType) { options.fullType = options.type; } extend(result, options); if (opts && opts.message) { result.message = template(opts.message, options); } else if (message) { result.message = template(message, options); } return result; }
...
Glossary.prototype.toText = function(parser) {
var file = this.getFile();
var entries = this.getEntries();
parser = parser? parsers.getByExt(parser) : file.getParser();
if (!parser) {
throw error.FileNotParsableError({
filename: file.getPath()
});
}
return parser.renderGlossary(entries.toJS());
};
...
function createError(opts) { var result = new Error(); Object.defineProperty(result, 'type', { value: result.type, enumerable: true, writable: true, configurable: true }); var options = extend({}, args, opts); if (!options.fullType) { options.fullType = options.type; } extend(result, options); if (opts && opts.message) { result.message = template(opts.message, options); } else if (message) { result.message = template(message, options); } return result; }
...
FS.prototype.resolve = function() {
var rootPath = this.getRoot();
var args = Array.prototype.slice.call(arguments);
var filename = path.join.apply(path, [rootPath].concat(args));
filename = path.normalize(filename);
if (!this.isInScope(filename)) {
throw error.FileOutOfScopeError({
filename: filename,
root: this.root
});
}
return filename;
};
...
function createError(cause, opts) {
/*eslint max-statements: [2, 25]*/
assert(cause, 'an error is required');
assert(isError(cause),
'WrappedError: first argument must be an error');
var causeMessage = cause.message;
if (causeMessage.indexOf('{causeMessage}') >= 0) {
// recover
causeMessage = causeMessage.replace(
causeMessageRegex,
'$INVALID_CAUSE_MESSAGE_LITERAL'
);
}
if (causeMessage.indexOf('{origMessage}') >= 0) {
causeMessage = causeMessage.replace(
origMessageRegex,
'$INVALID_ORIG_MESSAGE_LITERAL'
);
}
var nodeCause = false;
var errOptions = extend({}, opts, {
causeMessage: causeMessage,
origMessage: causeMessage
});
if (has(cause, 'code') && !has(errOptions, 'code')) {
errOptions.code = cause.code;
}
if (has(cause, 'errno') && !has(errOptions, 'errno')) {
errOptions.errno = cause.errno;
nodeCause = true;
}
if (has(cause, 'syscall') && !has(errOptions, 'syscall')) {
errOptions.syscall = cause.syscall;
nodeCause = true;
}
var causeType = cause.type;
if (!causeType && nodeCause) {
causeType = 'error.wrapped-io.' +
(cause.syscall || 'unknown') + '.' +
(cause.errno || 'unknown');
} else {
causeType = 'error.wrapped-unknown';
}
errOptions.fullType = options.type + '~!~' +
(cause.fullType || cause.type || causeType);
var err = createTypedError(errOptions);
Object.defineProperty(err, 'cause', {
value: cause,
configurable: true,
enumerable: false
});
return err;
}
n/a
function createError(cause, opts) {
/*eslint max-statements: [2, 25]*/
assert(cause, 'an error is required');
assert(isError(cause),
'WrappedError: first argument must be an error');
var causeMessage = cause.message;
if (causeMessage.indexOf('{causeMessage}') >= 0) {
// recover
causeMessage = causeMessage.replace(
causeMessageRegex,
'$INVALID_CAUSE_MESSAGE_LITERAL'
);
}
if (causeMessage.indexOf('{origMessage}') >= 0) {
causeMessage = causeMessage.replace(
origMessageRegex,
'$INVALID_ORIG_MESSAGE_LITERAL'
);
}
var nodeCause = false;
var errOptions = extend({}, opts, {
causeMessage: causeMessage,
origMessage: causeMessage
});
if (has(cause, 'code') && !has(errOptions, 'code')) {
errOptions.code = cause.code;
}
if (has(cause, 'errno') && !has(errOptions, 'errno')) {
errOptions.errno = cause.errno;
nodeCause = true;
}
if (has(cause, 'syscall') && !has(errOptions, 'syscall')) {
errOptions.syscall = cause.syscall;
nodeCause = true;
}
var causeType = cause.type;
if (!causeType && nodeCause) {
causeType = 'error.wrapped-io.' +
(cause.syscall || 'unknown') + '.' +
(cause.errno || 'unknown');
} else {
causeType = 'error.wrapped-unknown';
}
errOptions.fullType = options.type + '~!~' +
(cause.fullType || cause.type || causeType);
var err = createTypedError(errOptions);
Object.defineProperty(err, 'cause', {
value: cause,
configurable: true,
enumerable: false
});
return err;
}
n/a
function createError(cause, opts) {
/*eslint max-statements: [2, 25]*/
assert(cause, 'an error is required');
assert(isError(cause),
'WrappedError: first argument must be an error');
var causeMessage = cause.message;
if (causeMessage.indexOf('{causeMessage}') >= 0) {
// recover
causeMessage = causeMessage.replace(
causeMessageRegex,
'$INVALID_CAUSE_MESSAGE_LITERAL'
);
}
if (causeMessage.indexOf('{origMessage}') >= 0) {
causeMessage = causeMessage.replace(
origMessageRegex,
'$INVALID_ORIG_MESSAGE_LITERAL'
);
}
var nodeCause = false;
var errOptions = extend({}, opts, {
causeMessage: causeMessage,
origMessage: causeMessage
});
if (has(cause, 'code') && !has(errOptions, 'code')) {
errOptions.code = cause.code;
}
if (has(cause, 'errno') && !has(errOptions, 'errno')) {
errOptions.errno = cause.errno;
nodeCause = true;
}
if (has(cause, 'syscall') && !has(errOptions, 'syscall')) {
errOptions.syscall = cause.syscall;
nodeCause = true;
}
var causeType = cause.type;
if (!causeType && nodeCause) {
causeType = 'error.wrapped-io.' +
(cause.syscall || 'unknown') + '.' +
(cause.errno || 'unknown');
} else {
causeType = 'error.wrapped-unknown';
}
errOptions.fullType = options.type + '~!~' +
(cause.fullType || cause.type || causeType);
var err = createTypedError(errOptions);
Object.defineProperty(err, 'cause', {
value: cause,
configurable: true,
enumerable: false
});
return err;
}
...
}
// Load plugin JS content
if (packageMain) {
try {
content = require(packageMain);
} catch(err) {
throw new error.PluginError(err, {
plugin: name
});
}
}
// Update plugin
return plugin.merge({
...
function createError(opts) { var result = new Error(); Object.defineProperty(result, 'type', { value: result.type, enumerable: true, writable: true, configurable: true }); var options = extend({}, args, opts); if (!options.fullType) { options.fullType = options.type; } extend(result, options); if (opts && opts.message) { result.message = template(opts.message, options); } else if (message) { result.message = template(message, options); } return result; }
...
// Convert a svg file to a pmg
function convertSVGToPNG(source, dest, options) {
if (!fs.existsSync(source)) return Promise.reject(new error.FileNotFoundError({ filename: source }));
return command.spawn('svgexport', [source, dest])
.fail(function(err) {
if (err.code == 'ENOENT') {
err = error.RequireInstallError({
cmd: 'svgexport',
install: 'Install it using: "npm install svgexport -g"'
});
}
throw err;
})
.then(function() {
...
function createError(cause, opts) {
/*eslint max-statements: [2, 25]*/
assert(cause, 'an error is required');
assert(isError(cause),
'WrappedError: first argument must be an error');
var causeMessage = cause.message;
if (causeMessage.indexOf('{causeMessage}') >= 0) {
// recover
causeMessage = causeMessage.replace(
causeMessageRegex,
'$INVALID_CAUSE_MESSAGE_LITERAL'
);
}
if (causeMessage.indexOf('{origMessage}') >= 0) {
causeMessage = causeMessage.replace(
origMessageRegex,
'$INVALID_ORIG_MESSAGE_LITERAL'
);
}
var nodeCause = false;
var errOptions = extend({}, opts, {
causeMessage: causeMessage,
origMessage: causeMessage
});
if (has(cause, 'code') && !has(errOptions, 'code')) {
errOptions.code = cause.code;
}
if (has(cause, 'errno') && !has(errOptions, 'errno')) {
errOptions.errno = cause.errno;
nodeCause = true;
}
if (has(cause, 'syscall') && !has(errOptions, 'syscall')) {
errOptions.syscall = cause.syscall;
nodeCause = true;
}
var causeType = cause.type;
if (!causeType && nodeCause) {
causeType = 'error.wrapped-io.' +
(cause.syscall || 'unknown') + '.' +
(cause.errno || 'unknown');
} else {
causeType = 'error.wrapped-unknown';
}
errOptions.fullType = options.type + '~!~' +
(cause.fullType || cause.type || causeType);
var err = createTypedError(errOptions);
Object.defineProperty(err, 'cause', {
value: cause,
configurable: true,
enumerable: false
});
return err;
}
...
var deferred = Promise.defer();
loader.getSource(resolvedFilePath, deferred.makeNodeResolver());
return deferred.promise;
})
.then(function(result) {
if (!result) {
throw error.TemplateError(new Error('Not found'), {
filename: filePath
});
}
return render(engine, result.path, result.src, context);
});
...
function enforce(err) { if (is.string(err)) err = new Error(err); err.message = err.message.replace(/^Error: /, ''); return err; }
n/a
function assertFile(filePath, generator) { return fileExists(filePath) .then(function(exists) { if (exists) return; return generator(); }); }
...
return Promise.forEach(articles, function(article) {
var articlePath = article.getPath();
var filePath = articlePath? path.join(rootFolder, articlePath) : null;
if (!filePath) {
return;
}
return fs.assertFile(filePath, function() {
return fs.ensureFile(filePath)
.then(function() {
logger.info.ln('create', article.getPath());
return fs.writeFile(filePath, '# ' + article.getTitle() + '\n\n');
});
});
})
...
copy = function () { var nodeArgs = baseArgs.concat(array_slice(arguments)); var deferred = defer(); nodeArgs.push(deferred.makeNodeResolver()); Q(callback).fapply(nodeArgs).fail(deferred.reject); return deferred.promise; }
...
copyFile: function(inputFile, outputFile, content) {
return Promise()
.then(function() {
var outputFilePath = PathUtils.resolveInRoot(outputFolder, outputFile);
return fs.ensureFile(outputFilePath)
.then(function() {
return fs.copy(inputFile, outputFilePath);
});
});
}
},
gitbook: {
version: gitbook.version
...
copyDir = function () { var nodeArgs = baseArgs.concat(array_slice(arguments)); var deferred = defer(); nodeArgs.push(deferred.makeNodeResolver()); Q(callback).fapply(nodeArgs).fail(deferred.reject); return deferred.promise; }
n/a
function download(uri, dest) { return writeStream(dest, request(uri)); }
...
// We avoid generating twice the same PNG
var hash = crc.crc32(src).toString(16);
var fileName = hash + extension;
var filePath = path.join(rootFolder, fileName);
return fs.assertFile(filePath, function() {
return fs.download(src, filePath);
})
.then(function() {
// Convert to relative
src = LocationUtils.relative(currentDirectory, fileName);
$img.replaceWith('<img src="' + src + '" />');
});
...
function ensureFile(filename) { var base = path.dirname(filename); return Promise.nfcall(mkdirp, base); }
...
var articlePath = article.getPath();
var filePath = articlePath? path.join(rootFolder, articlePath) : null;
if (!filePath) {
return;
}
return fs.assertFile(filePath, function() {
return fs.ensureFile(filePath)
.then(function() {
logger.info.ln('create', article.getPath());
return fs.writeFile(filePath, '# ' + article.getTitle() + '\n\n');
});
});
})
...
function ensureFolder(rootFolder) { return rmDir(rootFolder) .fail(function() { return Promise(); }) .then(function() { return Promise.nfcall(mkdirp, rootFolder); }); }
...
// Cleanup output folder
.then(function(output) {
var logger = output.getLogger();
var rootFolder = output.getRoot();
logger.debug.ln('cleanup folder "' + rootFolder + '"');
return fs.ensureFolder(rootFolder)
.thenResolve(output);
})
.then(processOutput.bind(null, generator))
// Log duration and end message
.then(function(output) {
...
function fileExists(filename) { var d = Promise.defer(); fs.exists(filename, function(exists) { d.resolve(exists); }); return d.promise; }
...
@return {Promise}
*/
hasFile: function(fileName, content) {
return Promise()
.then(function() {
var filePath = PathUtils.resolveInRoot(outputFolder, fileName);
return fs.exists(filePath);
});
},
/**
Write a file to the output folder,
It creates the required folder
...
existsSync = function (path) { try { nullCheck(path); binding.stat(pathModule._makeLong(path), statValues); return true; } catch (e) { return false; } }
...
expect.extend({
/**
* Check that a file is created in a directory:
* expect('myFolder').toHaveFile('hello.md');
*/
toHaveFile: function(fileName) {
var filePath = path.join(this.actual, fileName);
var exists = fs.existsSync(filePath);
expect.assert(
exists,
'expected %s to have file %s',
this.actual,
fileName
);
...
mkdirp = function () { var nodeArgs = baseArgs.concat(array_slice(arguments)); var deferred = defer(); nodeArgs.push(deferred.makeNodeResolver()); Q(callback).fapply(nodeArgs).fail(deferred.reject); return deferred.promise; }
...
@param {Book}
@param {String}
@return {Promise}
*/
function initBook(rootFolder) {
var extension = '.md';
return fs.mkdirp(rootFolder)
// Parse the summary and readme
.then(function() {
var fs = createNodeFS(rootFolder);
var book = Book.createForFS(fs);
return Parse.parseReadme(book)
...
function pickFile(rootFolder, fileName) { var result = path.join(rootFolder, fileName); if (fs.existsSync(result)) { return result; } return undefined; }
...
function getCoverPath(output) {
var outputRoot = output.getRoot();
var book = output.getBook();
var config = book.getConfig();
var coverName = config.getValue('cover', 'cover.jpg');
// Resolve to absolute
var cover = fs.pickFile(outputRoot, coverName);
if (cover) {
return cover;
}
// Multilingual? try parent folder
if (book.isLanguageBook()) {
cover = fs.pickFile(path.join(outputRoot, '..'), coverName);
...
readFile = function () { var nodeArgs = baseArgs.concat(array_slice(arguments)); var deferred = defer(); nodeArgs.push(deferred.makeNodeResolver()); Q(callback).fapply(nodeArgs).fail(deferred.reject); return deferred.promise; }
...
if (!filepath) {
filepath = path.resolve(sourceURL);
} else {
if (that.logger) that.logger.debug.ln('resolve from git', sourceURL, 'to', filepath);
}
// Read file from absolute path
return fs.readFile(filepath)
.then(function(source) {
source = source.toString('utf8');
if (that.transformFn) {
return that.transformFn(filepath, source);
}
...
function createReadStream(path, options) { return new ReadStream(path, options) }
n/a
readdir = function () { var nodeArgs = baseArgs.concat(array_slice(arguments)); var deferred = defer(); nodeArgs.push(deferred.makeNodeResolver()); Q(callback).fapply(nodeArgs).fail(deferred.reject); return deferred.promise; }
...
var Immutable = require('immutable');
var fresh = require('fresh-require');
var fs = require('../utils/fs');
var FS = require('../models/fs');
function fsReadDir(folder) {
return fs.readdir(folder)
.then(function(files) {
files = Immutable.List(files);
return files
.map(function(file) {
if (file == '.' || file == '..') return;
...
function rmDir(base) { return Promise.nfcall(rmdir, base, { fs: fs }); }
...
})
// Log end
.then(function(count) {
logger.info.ok(count + ' file(s) generated');
logger.debug('cleaning up... ');
return logger.debug.promise(fs.rmDir(outputFolder));
});
}
};
};
...
stat = function () { var nodeArgs = baseArgs.concat(array_slice(arguments)); var deferred = defer(); nodeArgs.push(deferred.makeNodeResolver()); Q(callback).fapply(nodeArgs).fail(deferred.reject); return deferred.promise; }
n/a
statSync = function (path) { nullCheck(path); binding.stat(pathModule._makeLong(path), statValues); return statsFromValues(); }
...
.then(function(files) {
files = Immutable.List(files);
return files
.map(function(file) {
if (file == '.' || file == '..') return;
var stat = fs.statSync(path.join(folder, file));
if (stat.isDirectory()) file = file + path.sep;
return file;
})
.filter(function(file) {
return Boolean(file);
});
});
...
function genTmpDir(opts) { return Promise.nfcall(tmp.dir, opts) .get(0); }
n/a
function genTmpFile(opts) { return Promise.nfcall(tmp.file, opts) .get(0); }
...
throw new Error('Error converting '+source+' into '+dest);
});
}
// Convert a svg buffer to a png file
function convertSVGBufferToPNG(buf, dest) {
// Create a temporary SVG file to convert
return fs.tmpFile({
postfix: '.svg'
})
.then(function(tmpSvg) {
return fs.writeFile(tmpSvg, buf)
.then(function() {
return convertSVGToPNG(tmpSvg, dest);
});
...
function uniqueFilename(base, filename) { var ext = path.extname(filename); filename = path.resolve(base, filename); filename = path.join(path.dirname(filename), path.basename(filename, ext)); var _filename = filename+ext; var i = 0; while (fs.existsSync(filename)) { _filename = filename + '_' + i + ext; i = i + 1; } return Promise(path.relative(base, _filename)); }
n/a
writeFile = function () { var nodeArgs = baseArgs.concat(array_slice(arguments)); var deferred = defer(); nodeArgs.push(deferred.makeNodeResolver()); Q(callback).fapply(nodeArgs).fail(deferred.reject); return deferred.promise; }
...
return;
}
return fs.assertFile(filePath, function() {
return fs.ensureFile(filePath)
.then(function() {
logger.info.ln('create', article.getPath());
return fs.writeFile(filePath, '# ' + article.getTitle() + '
;\n\n');
});
});
})
// Write summary
.then(function() {
var filePath = path.join(rootFolder, summaryFilename);
...
function writeStream(filename, st) { var d = Promise.defer(); var wstream = fs.createWriteStream(filename); var cleanup = function() { destroy(wstream); wstream.removeAllListeners(); }; wstream.on('finish', function () { cleanup(); d.resolve(); }); wstream.on('error', function (err) { cleanup(); d.reject(err); }); st.on('error', function(err) { cleanup(); d.reject(err); }); st.pipe(wstream); return d.promise; }
n/a
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
function nameToID(name) { return slug(name); }
...
/**
Get identifier for this entry
@retrun {Boolean}
*/
GlossaryEntry.prototype.getID = function() {
return GlossaryEntry.nameToID(this.getName());
};
/**
Normalize a glossary entry name into a unique id
@param {String}
...
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
getDescription = function () { return this.get('description'); }
...
@param {GlossaryEntry}
@return {Object}
*/
function encodeGlossaryEntry(entry) {
return {
id: entry.getID(),
name: entry.getName(),
description: entry.getDescription()
};
}
module.exports = encodeGlossaryEntry;
...
getID = function () { return GlossaryEntry.nameToID(this.getName()); }
...
// Extract ebook file
.then(function(output) {
var book = output.getBook();
var languages = book.getLanguages();
if (book.isMultilingual()) {
return Promise.forEach(languages.getList(), function(lang) {
var langID = lang.getID();
var langOutputFile = path.join(
path.dirname(outputFile),
path.basename(outputFile, extension) + '_' + langID + extension
);
return fs.copy(
...
getName = function () { return this.get('name'); }
...
* Return a specific parser by its name
*
* @param {String} name
* @return {Parser|undefined}
*/
function getParser(name) {
return parsers.find(function(parser) {
return parser.getName() === name;
});
}
/**
* Return a specific parser according to an extension
*
* @param {String} ext
...
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
add = function (rule) { var ignore = this.getIgnore(); var newIgnore = new IgnoreMutable(); newIgnore.add(ignore); newIgnore.add(rule); return this.set('ignore', newIgnore); }
...
@param {String}
@return {Ignore}
*/
Ignore.prototype.add = function(rule) {
var ignore = this.getIgnore();
var newIgnore = new IgnoreMutable();
newIgnore.add(ignore);
newIgnore.add(rule);
return this.set('ignore', newIgnore);
};
module.exports = Ignore;
...
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
getIgnore = function () { return this.get('ignore'); }
...
/**
Check if a file is ignore (should not being parsed, etc)
@param {String} ref
@return {Page|undefined}
*/
Book.prototype.isFileIgnored = function(filename) {
var ignore = this.getIgnore();
var language = this.getLanguage();
// Ignore is always relative to the root of the main book
if (language) {
filename = path.join(language, filename);
}
...
isFileIgnored = function (filename) { var ignore = this.getIgnore(); return ignore.filter([filename]).length == 0; }
...
var language = this.getLanguage();
// Ignore is always relative to the root of the main book
if (language) {
filename = path.join(language, filename);
}
return ignore.isFileIgnored(filename);
};
/**
Check if a content file is ignore (should not being parsed, etc)
@param {String} ref
@return {Page|undefined}
...
function convertInlinePNG(source, dest) { if (!/^data\:image\/png/.test(source)) return Promise.reject(new Error('Source is not a PNG data-uri')); var base64data = source.split('data:image/png;base64,')[1]; var buf = new Buffer(base64data, 'base64'); return fs.writeFile(dest, buf) .then(function() { if (fs.existsSync(dest)) return; throw new Error('Error converting '+source+' into '+dest); }); }
...
var hash = crc.crc32(src).toString(16);
var fileName = hash + '.png';
// Result file path
var filePath = path.join(rootFolder, fileName);
return fs.assertFile(filePath, function() {
return imagesUtil.convertInlinePNG(src, filePath);
})
.then(function() {
// Convert filename to a relative filename
fileName = LocationUtils.relative(currentDirectory, fileName);
// Replace src
$img.attr('src', fileName);
...
function convertSVGBufferToPNG(buf, dest) { // Create a temporary SVG file to convert return fs.tmpFile({ postfix: '.svg' }) .then(function(tmpSvg) { return fs.writeFile(tmpSvg, buf) .then(function() { return convertSVGToPNG(tmpSvg, dest); }); }); }
n/a
function convertSVGToPNG(source, dest, options) { if (!fs.existsSync(source)) return Promise.reject(new error.FileNotFoundError({ filename: source })); return command.spawn('svgexport', [source, dest]) .fail(function(err) { if (err.code == 'ENOENT') { err = error.RequireInstallError({ cmd: 'svgexport', install: 'Install it using: "npm install svgexport -g"' }); } throw err; }) .then(function() { if (fs.existsSync(dest)) return; throw new Error('Error converting '+source+' into '+dest); }); }
n/a
function decodeGlobal(output, result) { var book = output.getBook(); var config = book.getConfig(); // Update config config = decodeConfig(config, result.config); book = book.set('config', config); return output.set('book', book); }
...
return hook.call(context, prev);
}, arg);
})
// Handle final result
.then(function(result) {
output = Api.decodeGlobal(output, context);
return handleResult(output, result);
})
);
}
module.exports = callHook;
...
function decodePage(output, page, result) { var originalContent = page.getContent(); // No returned value // Existing content will be used if (!result) { return page; } deprecate.disable('page.sections'); // GitBook 3 // Use returned page.content if different from original content if (result.content != originalContent) { page = page.set('content', result.content); } // GitBook 2 compatibility // Finally, use page.sections else if (result.sections) { page = page.set('content', result.sections.map(function(section) { return section.content; }).join('\n') ); } deprecate.enable('page.sections'); return page; }
...
name,
function(out) {
return Api.encodePage(out, page);
},
function(out, result) {
return Api.decodePage(out, page, result);
},
output
);
}
module.exports = callPageHook;
...
function encodeGlobal(output) {
var book = output.getBook();
var bookFS = book.getContentFS();
var logger = output.getLogger();
var outputFolder = output.getRoot();
var plugins = output.getPlugins();
var blocks = Plugins.listBlocks(plugins);
var result = {
log: logger,
config: encodeConfig(output, book.getConfig()),
summary: encodeSummary(output, book.getSummary()),
/**
Check if the book is a multilingual book
@return {Boolean}
*/
isMultilingual: function() {
return book.isMultilingual();
},
/**
Check if the book is a language book for a multilingual book
@return {Boolean}
*/
isLanguageBook: function() {
return book.isLanguageBook();
},
/**
Read a file from the book
@param {String} fileName
@return {Promise<Buffer>}
*/
readFile: function(fileName) {
return bookFS.read(fileName);
},
/**
Read a file from the book as a string
@param {String} fileName
@return {Promise<String>}
*/
readFileAsString: function(fileName) {
return bookFS.readAsString(fileName);
},
/**
Resolve a file from the book root
@param {String} fileName
@return {String}
*/
resolve: function(fileName) {
return path.resolve(book.getContentRoot(), fileName);
},
/**
Resolve a page by it path
@param {String} filePath
@return {String}
*/
getPageByPath: function(filePath) {
var page = output.getPage(filePath);
if (!page) return undefined;
return encodePage(output, page);
},
/**
Render a block of text (markdown/asciidoc)
@param {String} type
@param {String} text
@return {Promise<String>}
*/
renderBlock: function(type, text) {
var parser = parsers.get(type);
return parser.parsePage(text)
.get('content');
},
/**
Render an inline text (markdown/asciidoc)
@param {String} type
@param {String} text
@return {Promise<String>}
*/
renderInline: function(type, text) {
var parser = parsers.get(type);
return parser.parseInline(text)
.get('content');
},
template: {
/**
Apply a templating block and returns its result
@param {String} name
@param {Object} blockData
@return {Promise|Object}
*/
applyBlock: function(name, blockData) {
var block = blocks.get(name) || defaultBlocks.get(name);
return Promise(block.applyBlock(blockData, result));
}
},
output: {
/**
Name of the generator being used
{String}
*/
name: output.getGenerator(),
/**
Return absolute path to the root folder of output
@return {String}
*/
root: function() {
return outputFolder;
},
/**
Resolve a file from the output root
@param {String} fileName
@return {String}
*/
resolve: function(fileName) {
return path.resolve(outputFolder, fileName);
},
/**
Convert a filepath into an url
@return {String}
*/
toURL: function(filePath) {
return fileToURL(output, filePath);
},
/**
Check that a file exists.
@param {String} fileName
@return {Promise} ...
...
var logger = output.getLogger();
var plugins = output.getPlugins();
logger.debug.ln('calling hook "' + name + '"');
// Create the JS context for plugins
var context = Api.encodeGlobal(output);
return timing.measure(
'call.hook.' + name,
// Get the arguments
Promise(getArgument(output))
...
function encodePage(output, page) { var book = output.getBook(); var summary = book.getSummary(); var fs = book.getContentFS(); var file = page.getFile(); // JS Page is based on the JSON output var result = JSONUtils.encodePage(page, summary); result.type = file.getType(); result.path = file.getPath(); result.rawPath = fs.resolve(result.path); deprecate.field(output, 'page.progress', result, 'progress', function() { return encodeProgress(output, page); }, '"page.progress" property is deprecated'); deprecate.field(output, 'page.sections', result, 'sections', [ { content: result.content, type: 'normal' } ], '"sections" property is deprecated, use page.content instead'); return result; }
...
function encodePage(output, page) {
var book = output.getBook();
var summary = book.getSummary();
var fs = book.getContentFS();
var file = page.getFile();
// JS Page is based on the JSON output
var result = JSONUtils.encodePage(page, summary);
result.type = file.getType();
result.path = file.getPath();
result.rawPath = fs.resolve(result.path);
deprecate.field(output, 'page.progress', result, 'progress', function() {
return encodeProgress(output, page);
...
exec = function (args, kwargs) { var book = getBook(args, kwargs); return Parse.parseConfig(book) .then(function(resultBook) { return Plugins.installPlugins(resultBook); }); }
...
@param {String} command
@param {Object} options
@return {Promise}
*/
function exec(command, options) {
var d = Promise.defer();
var child = childProcess.exec(command, options, function(err, stdout, stderr) {
if (!err) {
return d.resolve();
}
err.message = stdout.toString('utf8') + stderr.toString('utf8');
d.reject(err);
});
...
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
getID = function () { return path.basename(this.getPath()); }
...
// Extract ebook file
.then(function(output) {
var book = output.getBook();
var languages = book.getLanguages();
if (book.isMultilingual()) {
return Promise.forEach(languages.getList(), function(lang) {
var langID = lang.getID();
var langOutputFile = path.join(
path.dirname(outputFile),
path.basename(outputFile, extension) + '_' + langID + extension
);
return fs.copy(
...
getPath = function () { return this.get('path'); }
...
})
.then(Parse.parseSummary)
.then(function(book) {
var logger = book.getLogger();
var summary = book.getSummary();
var summaryFile = summary.getFile();
var summaryFilename = summaryFile.getPath() || ('SUMMARY' + extension);
var articles = summary.getArticlesAsList();
// Write pages
return Promise.forEach(articles, function(article) {
var articlePath = article.getPath();
var filePath = articlePath? path.join(rootFolder, articlePath) : null;
...
getTitle = function () { return this.get('title'); }
...
return;
}
return fs.assertFile(filePath, function() {
return fs.ensureFile(filePath)
.then(function() {
logger.info.ln('create', article.getPath());
return fs.writeFile(filePath, '# ' + article.getTitle() + '
;\n\n');
});
});
})
// Write summary
.then(function() {
var filePath = path.join(rootFolder, summaryFilename);
...
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
createFromList = function (file, langs) { var list = Immutable.OrderedMap(); langs.forEach(function(lang) { lang = Language({ title: lang.title, path: lang.ref }); list = list.set(lang.getID(), lang); }); return Languages({ file: file, list: list }); }
...
return parseStructureFile(book, 'langs')
.spread(function(file, result) {
if (!file) {
return book;
}
var languages = Languages.createFromList(file, result);
logger.debug.ln('languages index file found at', file.getPath());
logger.info.ln('parsing multilingual book, with', languages.getList().size, 'languages');
return book.set('languages', languages);
});
}
...
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
getCount = function () { return this.getList().size; }
...
);
return fs.copy(
path.resolve(outputFolder, langID, 'index' + extension),
langOutputFile
);
})
.thenResolve(languages.getCount());
} else {
return fs.copy(
path.resolve(outputFolder, 'index' + extension),
outputFile
).thenResolve(1);
}
})
...
getDefaultLanguage = function () { return this.getList().first(); }
...
if (!book.isMultilingual()) {
return Promise(output);
}
// Get main language
var languages = book.getLanguages();
var mainLanguage = languages.getDefaultLanguage();
// Read the main JSON
return fs.readFile(path.resolve(outputRoot, mainLanguage.getID(), 'README.json'), 'utf8')
// Extend the JSON
.then(function(content) {
var json = JSON.parse(content);
...
getFile = function () { return this.get('file'); }
...
});
})
.then(Parse.parseSummary)
.then(function(book) {
var logger = book.getLogger();
var summary = book.getSummary();
var summaryFile = summary.getFile();
var summaryFilename = summaryFile.getPath() || ('SUMMARY' + extension);
var articles = summary.getArticlesAsList();
// Write pages
return Promise.forEach(articles, function(article) {
var articlePath = article.getPath();
...
getLanguage = function (lang) { return this.getList().get(lang); }
...
Encode a book to JSON
@param {Book}
@return {Object}
*/
function encodeBookToJson(book) {
var config = book.getConfig();
var language = book.getLanguage();
var variables = config.getValue('variables', {});
return {
summary: encodeSummary(book.getSummary()),
glossary: encodeGlossary(book.getGlossary()),
readme: encodeReadme(book.getReadme()),
...
getList = function () { return this.get('list'); }
...
// Extract ebook file
.then(function(output) {
var book = output.getBook();
var languages = book.getLanguages();
if (book.isMultilingual()) {
return Promise.forEach(languages.getList(), function(lang) {
var langID = lang.getID();
var langOutputFile = path.join(
path.dirname(outputFile),
path.basename(outputFile, extension) + '_' + langID + extension
);
...
function areIdenticalPaths(p1, p2) { return normalize(p1) === normalize(p2); }
...
*/
Summary.prototype.getByPath = function(filePath) {
return this.getArticle(function(article) {
var articlePath = article.getPath();
return (
articlePath &&
LocationUtils.areIdenticalPaths(articlePath, filePath)
);
});
};
/**
Return the first article
...
function flatten(href) { href = normalize(href); if (href[0] == '/') { href = normalize(href.slice(1)); } return href; }
...
}
// List all parsable extensions
var extensions = parsers
.map(function(parser) {
return parser.getExtensions();
})
.flatten();
module.exports = {
extensions: extensions,
get: getParser,
getByExt: getParserByExt,
getForFile: getParserForFile
};
...
function isAnchor(href) { try { var parsed = url.parse(href); return !!(!parsed.protocol && !parsed.path && parsed.hash); } catch(err) { return false; } }
n/a
function isDataURI(href) { try { return Boolean(url.parse(href).protocol) && (url.parse(href).protocol === 'data:'); } catch(err) { return false; } }
...
@return {Promise}
*/
function inlinePng(rootFolder, currentFile, $) {
var currentDirectory = path.dirname(currentFile);
return editHTMLElement($, 'img', function($img) {
var src = $img.attr('src');
if (!LocationUtils.isDataURI(src)) {
return;
}
// We avoid generating twice the same PNG
var hash = crc.crc32(src).toString(16);
var fileName = hash + '.png';
...
function isExternal(href) { try { return Boolean(url.parse(href).protocol) && !isDataURI(href); } catch(err) { return false; } }
...
var articlePath = article.getPath();
return {
path: articlePath,
title: article.getTitle(),
level: article.getLevel(),
exists: (articlePath && pages.has(articlePath)),
external: article.isExternal()
};
}
/**
this.navigation is a deprecated property from GitBook v2
@param {Output}
...
function isRelative(href) { return !isExternal(href); }
...
// If origin is not in the book (include from a git content ref)
return path.resolve(path.dirname(from), to);
},
// Handle all files as relative, so that nunjucks pass responsability to 'resolve'
isRelative: function(filename) {
return LocationUtils.isRelative(filename);
}
});
module.exports = ConrefsLoader;
...
function normalize(s) { return path.normalize(s).replace(/\\/g, '/'); }
...
@param {Map<String:String|Map>}
*/
function createMockFS(files) {
files = Immutable.fromJS(files);
var mtime = new Date();
function getFile(filePath) {
var parts = path.normalize(filePath).split(path.sep);
return parts.reduce(function(list, part, i) {
if (!list) return null;
var file;
if (!part || part === '.') file = list;
else file = list.get(part);
...
function relative(dir, file) { var isDirectory = file.slice(-1) === '/'; return normalize(path.relative(dir, file)) + (isDirectory? '/': ''); }
...
},
resolve: function(from, to) {
// If origin is in the book, we enforce result file to be in the book
if (PathUtils.isInRoot(this.rootFolder, from)) {
// Path of current template in the rootFolder (not absolute to fs)
var fromRelative = path.relative(this.rootFolder, from);
// Resolve "to" to a filepath relative to rootFolder
var href = LocationUtils.toAbsolute(to, path.dirname(fromRelative), '');
// Return absolute path
return PathUtils.resolveInRoot(this.rootFolder, href);
}
...
function relativeForFile(baseFile, file) { return relative(path.dirname(baseFile), file); }
n/a
function toAbsolute(_href, dir, outdir) { if (isExternal(_href) || isDataURI(_href)) { return _href; } outdir = outdir == undefined? dir : outdir; _href = normalize(_href); dir = normalize(dir); outdir = normalize(outdir); // Path "_href" inside the base folder var hrefInRoot = normalize(path.join(dir, _href)); if (_href[0] == '/') { hrefInRoot = normalize(_href.slice(1)); } // Make it relative to output _href = path.relative(outdir, hrefInRoot); // Normalize windows paths _href = normalize(_href); return _href; }
...
// If origin is in the book, we enforce result file to be in the book
if (PathUtils.isInRoot(this.rootFolder, from)) {
// Path of current template in the rootFolder (not absolute to fs)
var fromRelative = path.relative(this.rootFolder, from);
// Resolve "to" to a filepath relative to rootFolder
var href = LocationUtils.toAbsolute(to, path.dirname(fromRelative), '');
// Return absolute path
return PathUtils.resolveInRoot(this.rootFolder, href);
}
// If origin is in a git repository, we resolve file in the git repository
var gitRoot = this.git.resolveRoot(from);
...
function Logger(write, logLevel) { if (!(this instanceof Logger)) return new Logger(write, logLevel); this._write = write || function(msg) { if(process.stdout) { process.stdout.write(msg); } }; this.lastChar = '\n'; this.setLevel(logLevel || 'info'); // Create easy-to-use method like "logger.debug.ln('....')" LEVELS.forEach(function(level, levelKey) { if (levelKey === 'DISABLED') { return; } levelKey = levelKey.toLowerCase(); this[levelKey] = this.log.bind(this, level); this[levelKey].ln = this.logLn.bind(this, level); this[levelKey].ok = this.ok.bind(this, level); this[levelKey].fail = this.fail.bind(this, level); this[levelKey].promise = this.promise.bind(this, level); }, this); }
n/a
fail = function (level) { return this.log(level, color.red('ERROR') + '\n'); }
...
.then(function() {
var fs = createNodeFS(rootFolder);
var book = Book.createForFS(fs);
return Parse.parseReadme(book)
// Setup default readme if doesn't found one
.fail(function() {
var readmeFile = File.createWithFilepath('README' + extension);
var readme = Readme.create(readmeFile);
return book.setReadme(readme);
});
})
.then(Parse.parseSummary)
...
format = function () { return util.format.apply(util, arguments); }
...
a url string in it's parsed form and returns the new url as a string
@param {String} uri
@param {Function} fn
@return {String}
*/
function urlTransform(uri, fn) {
return url.format(fn(url.parse(uri)));
}
module.exports = Server;
...
getLevel = function (logLevel) { return this.logLevel; }
...
*/
function encodeArticle(pages, article) {
var articlePath = article.getPath();
return {
path: articlePath,
title: article.getTitle(),
level: article.getLevel(),
exists: (articlePath && pages.has(articlePath)),
external: article.isExternal()
};
}
/**
this.navigation is a deprecated property from GitBook v2
...
log = function (level) { if (level < this.logLevel) return; var levelKey = LEVELS.findKey(function(v) { return v === level; }); var args = Array.prototype.slice.apply(arguments, [1]); var msg = this.format.apply(this, args); if (this.lastChar == '\n') { msg = COLORS.get(levelKey)(levelKey.toLowerCase()+':')+' '+msg; } return this.write(msg); }
...
#! /usr/bin/env node
/* eslint-disable no-console */
var color = require('bash-color');
console.log(color.red('You need to install "gitbook-cli" to have access
to the gitbook command anywhere on your system.'));
console.log(color.red('If you\'ve installed this package globally, you need to uninstall it.'));
console.log(color.red('>> Run "npm uninstall -g gitbook" then "npm install -g gitbook-cli"'
;));
...
logLn = function () { if (this.lastChar != '\n') this.write('\n'); var args = Array.prototype.slice.apply(arguments); args.push('\n'); return this.log.apply(this, args); }
...
/**
Log a confirmation [OK]
*/
Logger.prototype.ok = function(level) {
var args = Array.prototype.slice.apply(arguments, [1]);
var msg = this.format.apply(this, args);
if (arguments.length > 1) {
this.logLn(level, color.green('>> ') + msg.trim().replace(/\n
/g, color.green('\n>> ')));
} else {
this.log(level, color.green('OK'), '\n');
}
};
/**
Log a "FAIL"
...
ok = function (level) { var args = Array.prototype.slice.apply(arguments, [1]); var msg = this.format.apply(this, args); if (arguments.length > 1) { this.logLn(level, color.green('>> ') + msg.trim().replace(/\n/g, color.green('\n>> '))); } else { this.log(level, color.green('OK'), '\n'); } }
...
outputFile
).thenResolve(1);
}
})
// Log end
.then(function(count) {
logger.info.ok(count + ' file(s) generated');
logger.debug('cleaning up... ');
return logger.debug.promise(fs.rmDir(outputFolder));
});
}
};
};
...
promise = function (level, p) { var that = this; return p. then(function(st) { that.ok(level); return st; }, function(err) { that.fail(level); throw err; }); }
...
})
// Log end
.then(function(count) {
logger.info.ok(count + ' file(s) generated');
logger.debug('cleaning up... ');
return logger.debug.promise(fs.rmDir(outputFolder));
});
}
};
};
...
setLevel = function (logLevel) { if (is.string(logLevel)) { logLevel = logLevel.toUpperCase(); logLevel = LEVELS.get(logLevel); } this.logLevel = logLevel; }
...
/**
Change log level
@param {String} level
@return {Book}
*/
Book.prototype.setLogLevel = function(level) {
this.getLogger().setLevel(level);
return this;
};
/**
Create a book using a filesystem
@param {FS} fs
...
write = function (msg) { msg = msg.toString(); this.lastChar = msg[msg.length - 1]; return this._write(msg); }
...
});
function Logger(write, logLevel) {
if (!(this instanceof Logger)) return new Logger(write, logLevel);
this._write = write || function(msg) {
if(process.stdout) {
process.stdout.write(msg);
}
};
this.lastChar = '\n';
this.setLevel(logLevel || 'info');
// Create easy-to-use method like "logger.debug.ln('....')"
...
writeLn = function (msg) { return this.write((msg || '')+'\n'); }
n/a
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
getAssets = function () { return this.get('assets'); }
...
Output all assets using a generator
@param {Generator} generator
@param {Output} output
@return {Promise<Output>}
*/
function generateAssets(generator, output) {
var assets = output.getAssets();
var logger = output.getLogger();
// Is generator ignoring assets?
if (!generator.onAsset) {
return Promise(output);
}
...
getBook = function () { return this.get('book'); }
...
Only the configuration can be edited by plugin's hooks
@param {Output} output
@param {Object} result: result from API
@return {Output}
*/
function decodeGlobal(output, result) {
var book = output.getBook();
var config = book.getConfig();
// Update config
config = decodeConfig(config, result.config);
book = book.set('config', config);
return output.set('book', book);
...
getGenerator = function () { return this.get('generator'); }
...
}
};
deprecate.field(output, 'config.options', result, 'options',
result.values, '"config.options" property is deprecated, use "config.get(key)" instead');
deprecate.field(output, 'config.options.generator', result.values, 'generator',
output.getGenerator(), '"options.generator" property is deprecated
, use "output.name" instead');
deprecate.field(output, 'config.options.generator', result.values, 'output',
output.getRoot(), '"options.output" property is deprecated, use "output.root()" instead');
return result;
}
...
getLogger = function () { return this.getBook().getLogger(); }
...
var readme = Readme.create(readmeFile);
return book.setReadme(readme);
});
})
.then(Parse.parseSummary)
.then(function(book) {
var logger = book.getLogger();
var summary = book.getSummary();
var summaryFile = summary.getFile();
var summaryFilename = summaryFile.getPath() || ('SUMMARY' + extension);
var articles = summary.getArticlesAsList();
// Write pages
...
getOptions = function () { return this.get('options'); }
...
*
* @param {Output}
* @return {Object}
*/
function encodeOutputToJson(output) {
var book = output.getBook();
var generator = output.getGenerator();
var options = output.getOptions();
var result = encodeBook(book);
result.output = {
name: generator
};
...
getPage = function (filePath) { filePath = LocationUtils.normalize(filePath); var pages = this.getPages(); return pages.get(filePath); }
...
/**
Resolve a page by it path
@param {String} filePath
@return {String}
*/
getPageByPath: function(filePath) {
var page = output.getPage(filePath);
if (!page) return undefined;
return encodePage(output, page);
},
/**
Render a block of text (markdown/asciidoc)
...
getPages = function () { return this.get('pages'); }
...
this.navigation is a deprecated property from GitBook v2
@param {Output}
@return {Object}
*/
function encodeNavigation(output) {
var book = output.getBook();
var pages = output.getPages();
var summary = book.getSummary();
var articles = summary.getArticlesAsList();
var navigation = articles
.map(function(article, i) {
var ref = article.getRef();
...
getPlugins = function () { return this.get('plugins'); }
...
@return {Object}
*/
function encodeGlobal(output) {
var book = output.getBook();
var bookFS = book.getContentFS();
var logger = output.getLogger();
var outputFolder = output.getRoot();
var plugins = output.getPlugins();
var blocks = Plugins.listBlocks(plugins);
var result = {
log: logger,
config: encodeConfig(output, book.getConfig()),
summary: encodeSummary(output, book.getSummary()),
...
getRoot = function () { return this.getOptions().get('root'); }
...
deprecate.field(output, 'config.options', result, 'options',
result.values, '"config.options" property is deprecated, use "config.get(key)" instead');
deprecate.field(output, 'config.options.generator', result.values, 'generator',
output.getGenerator(), '"options.generator" property is deprecated, use "output.name" instead
x27;);
deprecate.field(output, 'config.options.generator', result.values, 'output',
output.getRoot(), '"options.output" property is deprecated, use
"output.root()" instead');
return result;
}
module.exports = encodeConfig;
...
getState = function () { return this.get('state'); }
...
return;
}
var logger = book.getLogger();
var books = book.getBooks();
var outputRoot = output.getRoot();
var plugins = output.getPlugins();
var state = output.getState();
var options = output.getOptions();
return Promise.forEach(books, function(langBook) {
// Inherits plugins list, options and state
var langOptions = options.set('root', path.join(outputRoot, langBook.getLanguage()));
var langOutput = new Output({
book: langBook,
...
setOptions = function (newOptions) { return this.set('options', newOptions); }
n/a
setState = function (newState) { return this.set('state', newState); }
n/a
exec = function (args, kwargs) { var book = getBook(args, kwargs); var logger = book.getLogger(); return Parse.parseBook(book) .then(function(resultBook) { var rootFolder = book.getRoot(); var contentFolder = book.getContentRoot(); logger.info.ln('Book located in:', rootFolder); if (contentFolder != rootFolder) { logger.info.ln('Content located in:', contentFolder); } if (resultBook.isMultilingual()) { printMultingualBook(resultBook); } else { printBook(resultBook); } }); }
...
@param {String} command
@param {Object} options
@return {Promise}
*/
function exec(command, options) {
var d = Promise.defer();
var child = childProcess.exec(command, options, function(err, stdout, stderr) {
if (!err) {
return d.resolve();
}
err.message = stdout.toString('utf8') + stderr.toString('utf8');
d.reject(err);
});
...
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
create = function (name, extensions, module) { return new Parser({ name: name, extensions: Immutable.List(extensions), readme: module.readme, langs: module.langs, summary: module.summary, glossary: module.glossary, page: module.page, inline: module.inline }); }
...
var book = Book.createForFS(fs);
return Parse.parseReadme(book)
// Setup default readme if doesn't found one
.fail(function() {
var readmeFile = File.createWithFilepath('README' + extension);
var readme = Readme.create(readmeFile);
return book.setReadme(readme);
});
})
.then(Parse.parseSummary)
.then(function(book) {
var logger = book.getLogger();
...
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
getExtensions = function () { return this.get('extensions'); }
...
function getParserForFile(filename) {
return getParserByExt(path.extname(filename));
}
// List all parsable extensions
var extensions = parsers
.map(function(parser) {
return parser.getExtensions();
})
.flatten();
module.exports = {
extensions: extensions,
get: getParser,
getByExt: getParserByExt,
...
getName = function () { return this.get('name'); }
...
* Return a specific parser by its name
*
* @param {String} name
* @return {Parser|undefined}
*/
function getParser(name) {
return parsers.find(function(parser) {
return parser.getName() === name;
});
}
/**
* Return a specific parser according to an extension
*
* @param {String} ext
...
matchExtension = function (ext) { var exts = this.getExtensions(); return exts.includes(ext.toLowerCase()); }
...
* Return a specific parser according to an extension
*
* @param {String} ext
* @return {Parser|undefined}
*/
function getParserByExt(ext) {
return parsers.find(function(parser) {
return parser.matchExtension(ext);
});
}
/**
* Return parser for a file
*
* @param {String} ext
...
parseGlossary = function (content) { var glossary = this.get('glossary'); return Promise(glossary(content)); }
...
}
return fs.readAsString(filepath)
.then(function(content) {
if (type === 'readme') {
return parser.parseReadme(content);
} else if (type === 'glossary') {
return parser.parseGlossary(content);
} else if (type === 'summary') {
return parser.parseSummary(content);
} else if (type === 'langs') {
return parser.parseLanguages(content);
} else {
throw new Error('Parsing invalid type "' + type + '"');
}
...
parseInline = function (content) { var inline = this.get('inline'); return Promise(inline(content)); }
...
@param {String} type
@param {String} text
@return {Promise<String>}
*/
renderInline: function(type, text) {
var parser = parsers.get(type);
return parser.parseInline(text)
.get('content');
},
template: {
/**
Apply a templating block and returns its result
...
parseLanguages = function (content) { var langs = this.get('langs'); return Promise(langs(content)); }
...
if (type === 'readme') {
return parser.parseReadme(content);
} else if (type === 'glossary') {
return parser.parseGlossary(content);
} else if (type === 'summary') {
return parser.parseSummary(content);
} else if (type === 'langs') {
return parser.parseLanguages(content);
} else {
throw new Error('Parsing invalid type "' + type + '"');
}
})
.then(function(result) {
return [
file,
...
parsePage = function (content) { var page = this.get('page'); return Promise(page(content)); }
...
@param {String} type
@param {String} text
@return {Promise<String>}
*/
renderBlock: function(type, text) {
var parser = parsers.get(type);
return parser.parsePage(text)
.get('content');
},
/**
Render an inline text (markdown/asciidoc)
@param {String} type
...
parseReadme = function (content) { var readme = this.get('readme'); return Promise(readme(content)); }
...
return fs.mkdirp(rootFolder)
// Parse the summary and readme
.then(function() {
var fs = createNodeFS(rootFolder);
var book = Book.createForFS(fs);
return Parse.parseReadme(book)
// Setup default readme if doesn't found one
.fail(function() {
var readmeFile = File.createWithFilepath('README' + extension);
var readme = Readme.create(readmeFile);
return book.setReadme(readme);
});
...
parseSummary = function (content) { var summary = this.get('summary'); return Promise(summary(content)); }
...
return fs.readAsString(filepath)
.then(function(content) {
if (type === 'readme') {
return parser.parseReadme(content);
} else if (type === 'glossary') {
return parser.parseGlossary(content);
} else if (type === 'summary') {
return parser.parseSummary(content);
} else if (type === 'langs') {
return parser.parseLanguages(content);
} else {
throw new Error('Parsing invalid type "' + type + '"');
}
})
.then(function(result) {
...
preparePage = function (content) { var page = this.get('page'); if (!page.prepare) { return Promise(content); } return Promise(page.prepare(content)); }
...
}
// Call hook "page:before"
return callPageHook('page:before', output, resultPage)
// Escape code blocks with raw tags
.then(function(currentPage) {
return parser.preparePage(currentPage.getContent());
})
// Render templating syntax
.then(function(content) {
var absoluteFilePath = path.join(book.getContentRoot(), filePath);
return Templating.render(engine, absoluteFilePath, content, context);
})
...
renderGlossary = function (content) { var glossary = this.get('glossary'); return Promise(glossary.toText(content)); }
...
if (!parser) {
throw error.FileNotParsableError({
filename: file.getPath()
});
}
return parser.renderGlossary(entries.toJS());
};
/**
Add/Replace an entry to a glossary
@param {Glossary} glossary
...
renderLanguages = function (content) { var langs = this.get('langs'); return Promise(langs.toText(content)); }
n/a
renderSummary = function (content) { var summary = this.get('summary'); return Promise(summary.toText(content)); }
...
if (!parser) {
throw error.FileNotParsableError({
filename: file.getPath()
});
}
return parser.renderSummary({
parts: parts.toJS()
});
};
/**
Return all articles as a list
...
function getParser(name) { return parsers.find(function(parser) { return parser.getName() === name; }); }
...
#### Book instance
The `Book` class is the central point of GitBook, it centralize all access read methods. This class is defined in [book.js](https
://github.com/GitbookIO/gitbook/blob/master/lib/book.js).
```js
// Read configuration from book.json
var value = book.config.get('title', 'Default Value');
// Resolve a filename to an absolute path
var filepath = book.resolve('README.md');
// Render an inline markup string
book.renderInline('markdown', 'This is **Markdown**')
.then(function(str) { ... })
...
function getParserByExt(ext) { return parsers.find(function(parser) { return parser.matchExtension(ext); }); }
...
/**
Return parser for this file
@return {Parser}
*/
File.prototype.getParser = function() {
return parsers.getByExt(this.getExtension());
};
/**
Create a file from stats informations
@param {String} filepath
@param {Object|fs.Stats} stat
...
function getParserForFile(filename) { return getParserByExt(path.extname(filename)); }
...
* to a file for a TemplatEngine
*
* @param {List<TemplateBlock>} engine
* @param {String} filePath
* @return {List<TemplateShortcut>}
*/
function listShortcuts(blocks, filePath) {
var parser = parsers.getForFile(filePath);
if (!parser) {
return Immutable.List();
}
return blocks
.map(function(block) {
...
function isInRoot(root, filename) { root = path.normalize(root); filename = path.normalize(filename); if (root === '.') { return true; } if (root[root.length - 1] != path.sep) { root = root + path.sep; } return (filename.substr(0, root.length) === root); }
...
@param {String} filename
@return {Boolean}
*/
FS.prototype.isInScope = function(filename) {
var rootPath = this.getRoot();
filename = path.join(rootPath, filename);
return PathUtil.isInRoot(rootPath, filename);
};
/**
Resolve a file in this FS
@param {String}
@return {String}
...
function isPureRelative(filename) { return (filename.indexOf('./') === 0 || filename.indexOf('../') === 0); }
...
* @param {String} to
* @return {String|null}
*/
resolve: function(from, to) {
var searchPaths = this.searchPaths;
// Relative template like "./test.html"
if (PathUtils.isPureRelative(to) && from) {
return path.resolve(path.dirname(from), to);
}
// Determine in which search folder we currently are
var originalSearchPath = this.getSearchPath(from);
var originalFilename = this.getTemplateName(from);
...
function normalizePath(filename) { return path.normalize(filename); }
...
@param {Map<String:String|Map>}
*/
function createMockFS(files) {
files = Immutable.fromJS(files);
var mtime = new Date();
function getFile(filePath) {
var parts = path.normalize(filePath).split(path.sep);
return parts.reduce(function(list, part, i) {
if (!list) return null;
var file;
if (!part || part === '.') file = list;
else file = list.get(part);
...
function resolveInRoot(root) { var input, result; var args = Array.prototype.slice.call(arguments, 1); input = args .reduce(function(current, p) { // Handle path relative to book root ("/README.md") if (p[0] == '/' || p[0] == '\\') return p.slice(1); return current? path.join(current, p) : path.normalize(p); }, ''); result = path.resolve(root, input); if (!isInRoot(root, result)) { throw new error.FileOutOfScopeError({ filename: result, root: root }); } return result; }
...
@param {String} fileName
@return {Promise}
*/
hasFile: function(fileName, content) {
return Promise()
.then(function() {
var filePath = PathUtils.resolveInRoot(outputFolder, fileName);
return fs.exists(filePath);
});
},
/**
Write a file to the output folder,
...
function setExtension(filename, ext) { return path.join( path.dirname(filename), path.basename(filename, path.extname(filename)) + ext ); }
...
if (
path.basename(filePath, path.extname(filePath)) == 'README' ||
(fileReadme.exists() && filePath == fileReadme.getPath())
) {
filePath = path.join(path.dirname(filePath), 'index' + OUTPUT_EXTENSION);
} else {
filePath = PathUtils.setExtension(filePath, OUTPUT_EXTENSION);
}
return LocationUtils.normalize(filePath);
}
module.exports = fileToOutput;
...
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
createFromDep = function (dep) { return new Plugin({ name: dep.getName(), version: dep.getVersion() }); }
n/a
createFromString = function (s) { var parts = s.split('@'); var name = parts[0]; var version = parts.slice(1).join('@'); return new Plugin({ name: name, version: version || DEFAULT_VERSION }); }
...
* @param {Array}
* @return {List<PluginDependency>}
*/
PluginDependency.listFromArray = function(arr) {
return Immutable.List(arr)
.map(function(entry) {
if (is.string(entry)) {
return PluginDependency.createFromString(entry);
} else {
return PluginDependency({
name: entry.get('name'),
version: entry.get('version')
});
}
})
...
nameToNpmID = function (s) { return PREFIX + s; }
...
/**
* Create a PluginDependency from a dependency of gitbook
* @param {String} pluginName
* @return {PluginDependency}
*/
function createFromDependency(pluginName) {
var npmID = PluginDependency.nameToNpmID(pluginName);
var version = pkg.dependencies[npmID];
return PluginDependency.create(pluginName, version);
}
/*
* List of default plugins for all books,
...
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
getBlocks = function () { var blocks = this.getContent().get('blocks'); blocks = blocks || Immutable.Map(); return blocks .map(function(block, blockName) { return TemplateBlock.create(blockName, block); }); }
...
*/
TemplateBlock.prototype.toNunjucksExt = function(mainContext, blocksOutput) {
blocksOutput = blocksOutput || {};
var that = this;
var name = this.getName();
var endTag = this.getEndTag();
var blocks = this.getBlocks().toJS();
function Ext() {
this.tags = [name];
this.parse = function(parser, nodes) {
var lastBlockName = null;
var lastBlockArgs = null;
...
getContent = function () { return this.get('content'); }
...
@param {Output} output
@param {Page} page: page instance to edit
@param {Object} result: result from API
@return {Page}
*/
function decodePage(output, page, result) {
var originalContent = page.getContent();
// No returned value
// Existing content will be used
if (!result) {
return page;
}
...
getDepth = function () { return this.get('depth'); }
...
var article = summary.getByPath(file.getPath());
var result = attributes.toJS();
if (article) {
result.title = article.getTitle();
result.level = article.getLevel();
result.depth = article.getDepth();
var nextArticle = summary.getNextArticle(article);
if (nextArticle) {
result.next = encodeSummaryArticle(nextArticle);
}
var prevArticle = summary.getPrevArticle(article);
...
getFilters = function () { return this.getContent().get('filters'); }
...
Return a nunjucks environment from this configuration
@return {Nunjucks.Environment}
*/
TemplateEngine.prototype.toNunjucks = function(blocksOutput) {
var loader = this.getLoader();
var blocks = this.getBlocks();
var filters = this.getFilters();
var globals = this.getGlobals();
var extensions = this.getExtensions();
var context = this.getContext();
var env = new nunjucks.Environment(
loader,
{
...
getHook = function (name) { return this.getHooks().get(name); }
...
// Get the arguments
Promise(getArgument(output))
// Call the hooks in serie
.then(function(arg) {
return Promise.reduce(plugins, function(prev, plugin) {
var hook = plugin.getHook(name);
if (!hook) {
return prev;
}
return hook.call(context, prev);
}, arg);
})
...
getHooks = function () { return this.getContent().get('hooks') || Immutable.Map(); }
...
/**
* Return a specific hook
* @param {String} name
* @return {Function|undefined}
*/
Plugin.prototype.getHook = function(name) {
return this.getHooks().get(name);
};
/**
* Create a plugin from a string
* @param {String}
* @return {Plugin}
*/
...
getName = function () { return this.get('name'); }
...
* Return a specific parser by its name
*
* @param {String} name
* @return {Parser|undefined}
*/
function getParser(name) {
return parsers.find(function(parser) {
return parser.getName() === name;
});
}
/**
* Return a specific parser according to an extension
*
* @param {String} ext
...
getNpmID = function () { return PluginDependency.nameToNpmID(this.getName()); }
...
.then(function(version) {
if (!version) {
throw new Error('Found no satisfactory version for plugin "' + name + '" with requirement "'
; + requirement + '"');
}
logger.info.ln('install plugin "' + name +'" (' + requirement + ') from NPM with version'
;, version);
return Promise.nfcall(npmi, {
'name': plugin.getNpmID(),
'version': version,
'path': installFolder,
'npmLoad': {
'loglevel': 'silent',
'loaded': true,
'prefix': installFolder
}
...
getPackage = function () { return this.get('package'); }
...
};
/**
* Check if a plugin is loaded
* @return {Boolean}
*/
Plugin.prototype.isLoaded = function() {
return Boolean(this.getPackage().size > 0);
};
/**
* Check if a plugin is a theme given its name
* @return {Boolean}
*/
Plugin.prototype.isTheme = function() {
...
getParent = function () { return this.get('parent'); }
...
var plugins = requirements.reduce(function(result, dep) {
var name = dep.getName();
var installed = installedMap.get(name);
if (installed) {
var deps = installedMap
.filter(function(plugin) {
return plugin.getParent() === name;
})
.toArray();
result = result.concat(deps);
result.push(installed);
} else {
missing.push(name);
...
getPath = function () { return this.get('path'); }
...
})
.then(Parse.parseSummary)
.then(function(book) {
var logger = book.getLogger();
var summary = book.getSummary();
var summaryFile = summary.getFile();
var summaryFilename = summaryFile.getPath() || ('SUMMARY' + extension);
var articles = summary.getArticlesAsList();
// Write pages
return Promise.forEach(articles, function(article) {
var articlePath = article.getPath();
var filePath = articlePath? path.join(rootFolder, articlePath) : null;
...
getResources = function (type) { if (type != 'website' && type != 'ebook') { throw new Error('Invalid assets type ' + type); } var content = this.getContent(); return (content.get(type) || (type == 'website'? content.get('book') : null) || Immutable.Map()); }
n/a
getVersion = function () { return this.get('version'); }
...
};
/**
* Is the plugin using a git dependency
* @return {Boolean}
*/
PluginDependency.prototype.isGitDependency = function() {
return !semver.validRange(this.getVersion());
};
/**
* Create a plugin with a name and a plugin
* @param {String}
* @return {Plugin|undefined}
*/
...
isLoaded = function () { return Boolean(this.getPackage().size > 0); }
...
@param {Plugin}
@return {Promise<Plugin>}
*/
function validatePlugin(plugin) {
var packageInfos = plugin.getPackage();
var isValid = (
plugin.isLoaded() &&
packageInfos &&
packageInfos.get('name') &&
packageInfos.get('engines') &&
packageInfos.get('engines').get('gitbook')
);
if (!isValid) {
...
isTheme = function () { var name = this.getName(); return (name && name.indexOf(THEME_PREFIX) === 0); }
n/a
function promise(resolver) { if (typeof resolver !== "function") { throw new TypeError("resolver must be a function."); } var deferred = defer(); try { resolver(deferred.resolve, deferred.reject, deferred.notify); } catch (reason) { deferred.reject(reason); } return deferred.promise; }
...
})
// Log end
.then(function(count) {
logger.info.ok(count + ' file(s) generated');
logger.debug('cleaning up... ');
return logger.debug.promise(fs.rmDir(outputFolder));
});
}
};
};
...
function promise(resolver) { if (typeof resolver !== "function") { throw new TypeError("resolver must be a function."); } var deferred = defer(); try { resolver(deferred.resolve, deferred.reject, deferred.notify); } catch (reason) { deferred.reject(reason); } return deferred.promise; }
n/a
function all(promises) { return when(promises, function (promises) { var pendingCount = 0; var deferred = defer(); array_reduce(promises, function (undefined, promise, index) { var snapshot; if ( isPromise(promise) && (snapshot = promise.inspect()).state === "fulfilled" ) { promises[index] = snapshot.value; } else { ++pendingCount; when( promise, function (value) { promises[index] = value; if (--pendingCount === 0) { deferred.resolve(promises); } }, deferred.reject, function (progress) { deferred.notify({ index: index, value: progress }); } ); } }, void 0); if (pendingCount === 0) { deferred.resolve(promises); } return deferred.promise; }); }
...
* @param {Book}
* @return {Promise<OrderedMap<String:Plugin>>}
*/
function findForBook(book) {
return timing.measure(
'plugins.findForBook',
Promise.all([
findInstalled(locateRootFolder()),
findInstalled(book.getRoot())
])
// Merge all plugins
.then(function(results) {
return Immutable.List(results)
...
allResolved = function () { if (typeof console !== "undefined" && typeof console.warn === "function") { console.warn(name + " is deprecated, use " + alternative + " instead.", new Error("").stack); } return callback.apply(callback, arguments); }
n/a
function allSettled(promises) { return Q(promises).allSettled(); }
n/a
function any(promises) { if (promises.length === 0) { return Q.resolve(); } var deferred = Q.defer(); var pendingCount = 0; array_reduce(promises, function (prev, current, index) { var promise = promises[index]; pendingCount++; when(promise, onFulfilled, onRejected, onProgress); function onFulfilled(result) { deferred.resolve(result); } function onRejected() { pendingCount--; if (pendingCount === 0) { deferred.reject(new Error( "Can't get fulfillment value from any promise, all " + "promises were rejected." )); } } function onProgress(progress) { deferred.notify({ index: index, value: progress }); } }, undefined); return deferred.promise; }
n/a
function async(makeGenerator) { return function () { // when verb is "send", arg is a value // when verb is "throw", arg is an exception function continuer(verb, arg) { var result; // Until V8 3.19 / Chromium 29 is released, SpiderMonkey is the only // engine that has a deployed base of browsers that support generators. // However, SM's generators use the Python-inspired semantics of // outdated ES6 drafts. We would like to support ES6, but we'd also // like to make it possible to use generators in deployed browsers, so // we also support Python-style generators. At some point we can remove // this block. if (typeof StopIteration === "undefined") { // ES6 Generators try { result = generator[verb](arg); } catch (exception) { return reject(exception); } if (result.done) { return Q(result.value); } else { return when(result.value, callback, errback); } } else { // SpiderMonkey Generators // FIXME: Remove this case when SM does ES6 generators. try { result = generator[verb](arg); } catch (exception) { if (isStopIteration(exception)) { return Q(exception.value); } else { return reject(exception); } } return when(result, callback, errback); } } var generator = makeGenerator.apply(this, arguments); var callback = continuer.bind(continuer, "next"); var errback = continuer.bind(continuer, "throw"); return callback(); }; }
n/a
catch = function (object, rejected) { return Q(object).then(void 0, rejected); }
n/a
function defer() { // if "messages" is an "Array", that indicates that the promise has not yet // been resolved. If it is "undefined", it has been resolved. Each // element of the messages array is itself an array of complete arguments to // forward to the resolved promise. We coerce the resolution value to a // promise using the `resolve` function because it handles both fully // non-thenable values and other thenables gracefully. var messages = [], progressListeners = [], resolvedPromise; var deferred = object_create(defer.prototype); var promise = object_create(Promise.prototype); promise.promiseDispatch = function (resolve, op, operands) { var args = array_slice(arguments); if (messages) { messages.push(args); if (op === "when" && operands[1]) { // progress operand progressListeners.push(operands[1]); } } else { Q.nextTick(function () { resolvedPromise.promiseDispatch.apply(resolvedPromise, args); }); } }; // XXX deprecated promise.valueOf = function () { if (messages) { return promise; } var nearerValue = nearer(resolvedPromise); if (isPromise(nearerValue)) { resolvedPromise = nearerValue; // shorten chain } return nearerValue; }; promise.inspect = function () { if (!resolvedPromise) { return { state: "pending" }; } return resolvedPromise.inspect(); }; if (Q.longStackSupport && hasStacks) { try { throw new Error(); } catch (e) { // NOTE: don't try to use `Error.captureStackTrace` or transfer the // accessor around; that causes memory leaks as per GH-111. Just // reify the stack trace as a string ASAP. // // At the same time, cut off the first line; it's always just // "[object Promise]\n", as per the `toString`. promise.stack = e.stack.substring(e.stack.indexOf("\n") + 1); } } // NOTE: we do the checks for `resolvedPromise` in each method, instead of // consolidating them into `become`, since otherwise we'd create new // promises with the lines `become(whatever(value))`. See e.g. GH-252. function become(newPromise) { resolvedPromise = newPromise; promise.source = newPromise; array_reduce(messages, function (undefined, message) { Q.nextTick(function () { newPromise.promiseDispatch.apply(newPromise, message); }); }, void 0); messages = void 0; progressListeners = void 0; } deferred.promise = promise; deferred.resolve = function (value) { if (resolvedPromise) { return; } become(Q(value)); }; deferred.fulfill = function (value) { if (resolvedPromise) { return; } become(fulfill(value)); }; deferred.reject = function (reason) { if (resolvedPromise) { return; } become(reject(reason)); }; deferred.notify = function (progress) { if (resolvedPromise) { return; } array_reduce(progressListeners, function (undefined, progressListener) { Q.nextTick(function () { progressListener(progress); }); }, void 0); }; return deferred; }
...
var getOutputFolder = require('./getOutputFolder');
var Server = require('./server');
var watch = require('./watch');
var server, lrServer, lrPath;
function waitForCtrlC() {
var d = Promise.defer();
process.on('SIGINT', function() {
d.resolve();
});
return d.promise;
}
...
del = function (object, key) { return Q(object).dispatch("delete", [key]); }
n/a
delay = function (object, timeout) { if (timeout === void 0) { timeout = object; object = void 0; } return Q(object).delay(timeout); }
n/a
delete = function (object, key) { return Q(object).dispatch("delete", [key]); }
n/a
denodeify = function (callback) { var baseArgs = array_slice(arguments, 1); return function () { var nodeArgs = baseArgs.concat(array_slice(arguments)); var deferred = defer(); nodeArgs.push(deferred.makeNodeResolver()); Q(callback).fapply(nodeArgs).fail(deferred.reject); return deferred.promise; }; }
n/a
function dispatch(object, op, args) { return Q(object).dispatch(op, args); }
n/a
done = function (object, fulfilled, rejected, progress) { return Q(object).done(fulfilled, rejected, progress); }
n/a
fail = function (object, rejected) { return Q(object).then(void 0, rejected); }
...
.then(function() {
var fs = createNodeFS(rootFolder);
var book = Book.createForFS(fs);
return Parse.parseReadme(book)
// Setup default readme if doesn't found one
.fail(function() {
var readmeFile = File.createWithFilepath('README' + extension);
var readme = Readme.create(readmeFile);
return book.setReadme(readme);
});
})
.then(Parse.parseSummary)
...
fapply = function (object, args) { return Q(object).dispatch("apply", [void 0, args]); }
n/a
fbind = function (object) { var promise = Q(object); var args = array_slice(arguments, 1); return function fbound() { return promise.dispatch("apply", [ this, args.concat(array_slice(arguments)) ]); }; }
n/a
fcall = function (object) { return Q(object).dispatch("apply", [void 0, array_slice(arguments, 1)]); }
n/a
fin = function (object, callback) { return Q(object)["finally"](callback); }
...
return Parse.parseBook(book)
.then(function(resultBook) {
return Output.generate(Generator, resultBook, {
root: outputFolder
});
})
.fin(function() {
if (kwargs.timing) timing.dump(book.getLogger());
});
}
};
...
finally = function (object, callback) { return Q(object)["finally"](callback); }
n/a
function forEach(arr, iter) { return reduce(arr, function(val, el, key) { return iter(el, key); }); }
...
var summary = book.getSummary();
var summaryFile = summary.getFile();
var summaryFilename = summaryFile.getPath() || ('SUMMARY' + extension);
var articles = summary.getArticlesAsList();
// Write pages
return Promise.forEach(articles, function(article) {
var articlePath = article.getPath();
var filePath = articlePath? path.join(rootFolder, articlePath) : null;
if (!filePath) {
return;
}
return fs.assertFile(filePath, function() {
...
function fulfill(value) { return Promise({ "when": function () { return value; }, "get": function (name) { return value[name]; }, "set": function (name, rhs) { value[name] = rhs; }, "delete": function (name) { delete value[name]; }, "post": function (name, args) { // Mark Miller proposes that post with no name should apply a // promised function. if (name === null || name === void 0) { return value.apply(void 0, args); } else { return value[name].apply(value, args); } }, "apply": function (thisp, args) { return value.apply(thisp, args); }, "keys": function () { return object_keys(value); } }, void 0, function inspect() { return { state: "fulfilled", value: value }; }); }
n/a
get = function (object, key) { return Q(object).dispatch("get", [key]); }
...
#### Book instance
The `Book` class is the central point of GitBook, it centralize all access read methods. This class is defined in [book.js](https
://github.com/GitbookIO/gitbook/blob/master/lib/book.js).
```js
// Read configuration from book.json
var value = book.config.get('title', 'Default Value');
// Resolve a filename to an absolute path
var filepath = book.resolve('README.md');
// Render an inline markup string
book.renderInline('markdown', 'This is **Markdown**')
.then(function(str) { ... })
...
getUnhandledReasons = function () { // Make a copy so that consumers can't interfere with our internal state. return unhandledReasons.slice(); }
n/a
invoke = function (object, name) { return Q(object).dispatch("post", [name, array_slice(arguments, 2)]); }
n/a
function isFulfilled(object) { return !isPromise(object) || object.inspect().state === "fulfilled"; }
n/a
function isPending(object) { return isPromise(object) && object.inspect().state === "pending"; }
n/a
function isPromise(object) { return object instanceof Promise; }
n/a
function isPromiseAlike(object) { return isObject(object) && typeof object.then === "function"; }
...
inner = inner || {};
inner.args = inner.args || [];
inner.kwargs = inner.kwargs || {};
inner.blocks = inner.blocks || [];
var r = processFn.call(context, inner);
if (Promise.isPromiseAlike(r)) {
return r.then(this.normalizeBlockResult.bind(this));
} else {
return this.normalizeBlockResult(r);
}
};
/**
...
function isRejected(object) { return isPromise(object) && object.inspect().state === "rejected"; }
n/a
join = function (x, y) { return Q(x).join(y); }
...
var summaryFilename = summaryFile.getPath() || ('SUMMARY' + extension);
var articles = summary.getArticlesAsList();
// Write pages
return Promise.forEach(articles, function(article) {
var articlePath = article.getPath();
var filePath = articlePath? path.join(rootFolder, articlePath) : null;
if (!filePath) {
return;
}
return fs.assertFile(filePath, function() {
return fs.ensureFile(filePath)
.then(function() {
...
keys = function (object) { return Q(object).dispatch("keys", []); }
n/a
function Promise(descriptor, fallback, inspect) { if (fallback === void 0) { fallback = function (op) { return reject(new Error( "Promise does not support operation: " + op )); }; } if (inspect === void 0) { inspect = function () { return {state: "unknown"}; }; } var promise = object_create(Promise.prototype); promise.promiseDispatch = function (resolve, op, args) { var result; try { if (descriptor[op]) { result = descriptor[op].apply(promise, args); } else { result = fallback.call(promise, op, args); } } catch (exception) { result = reject(exception); } if (resolve) { resolve(result); } }; promise.inspect = inspect; // XXX deprecated `valueOf` and `exception` support if (inspect) { var inspected = inspect(); if (inspected.state === "rejected") { promise.exception = inspected.reason; } promise.valueOf = function () { var inspected = inspect(); if (inspected.state === "pending" || inspected.state === "rejected") { return promise; } return inspected.value; }; } return promise; }
n/a
function map(arr, iter) { if (Immutable.Map.isMap(arr)) { var type = 'Map'; if (Immutable.OrderedMap.isOrderedMap(arr)) { type = 'OrderedMap'; } return mapAsList(arr, function(value, key) { return Q(iter(value, key)) .then(function(result) { return [key, result]; }); }) .then(function(result) { return Immutable[type](result); }); } else { return mapAsList(arr, iter) .then(function(result) { return Immutable.List(result); }); } }
...
*/
function getParserForFile(filename) {
return getParserByExt(path.extname(filename));
}
// List all parsable extensions
var extensions = parsers
.map(function(parser) {
return parser.getExtensions();
})
.flatten();
module.exports = {
extensions: extensions,
get: getParser,
...
mapply = function (object, name, args) { return Q(object).dispatch("post", [name, args]); }
n/a
function master(object) { return Promise({ "isDef": function () {} }, function fallback(op, args) { return dispatch(object, op, args); }, function () { return Q(object).inspect(); }); }
n/a
mcall = function (object, name) { return Q(object).dispatch("post", [name, array_slice(arguments, 2)]); }
n/a
nbind = function (callback, thisp) { var baseArgs = array_slice(arguments, 2); return function () { var nodeArgs = baseArgs.concat(array_slice(arguments)); var deferred = defer(); nodeArgs.push(deferred.makeNodeResolver()); function bound() { return callback.apply(thisp, arguments); } Q(bound).fapply(nodeArgs).fail(deferred.reject); return deferred.promise; }; }
n/a
function nearer(value) { if (isPromise(value)) { var inspected = value.inspect(); if (inspected.state === "fulfilled") { return inspected.value; } } return value; }
n/a
nextTick = function (task) { tail = tail.next = { task: task, domain: isNodeJS && process.domain, next: null }; if (!flushing) { flushing = true; requestTick(); } }
n/a
nfapply = function (callback, args) { return Q(callback).nfapply(args); }
n/a
nfbind = function (callback) { var baseArgs = array_slice(arguments, 1); return function () { var nodeArgs = baseArgs.concat(array_slice(arguments)); var deferred = defer(); nodeArgs.push(deferred.makeNodeResolver()); Q(callback).fapply(nodeArgs).fail(deferred.reject); return deferred.promise; }; }
...
return Promise.nfcall(mkdirp, rootFolder);
});
}
module.exports = {
exists: fileExists,
existsSync: fs.existsSync,
mkdirp: Promise.nfbind(mkdirp),
readFile: Promise.nfbind(fs.readFile),
writeFile: Promise.nfbind(fs.writeFile),
assertFile: assertFile,
pickFile: pickFile,
stat: Promise.nfbind(fs.stat),
statSync: fs.statSync,
readdir: Promise.nfbind(fs.readdir),
...
nfcall = function (callback) { var args = array_slice(arguments, 1); return Q(callback).nfapply(args); }
...
return Promise()
.then(function() {
if (!hasWatch || !hasLiveReloading) {
return;
}
lrServer = tinylr({});
return Promise.nfcall(lrServer.listen.bind(lrServer), kwargs.lrport)
.then(function() {
console.log('Live reload server started on port:', kwargs.lrport);
console.log('Press CTRL+C to quit ...');
console.log('');
});
})
...
ninvoke = function (object, name) { var nodeArgs = array_slice(arguments, 2); var deferred = defer(); nodeArgs.push(deferred.makeNodeResolver()); Q(object).dispatch("post", [name, nodeArgs]).fail(deferred.reject); return deferred.promise; }
n/a
nmapply = function (object, name, args) { return Q(object).npost(name, args); }
n/a
nmcall = function (object, name) { var nodeArgs = array_slice(arguments, 2); var deferred = defer(); nodeArgs.push(deferred.makeNodeResolver()); Q(object).dispatch("post", [name, nodeArgs]).fail(deferred.reject); return deferred.promise; }
n/a
noConflict = function () { throw new Error("Q.noConflict only works when Q is used as a global"); }
n/a
function nodeify(object, nodeback) { return Q(object).nodeify(nodeback); }
...
}, mainContext || {});
return that.applyBlock(mainBlock, ctx);
})
.then(function(result) {
return that.blockResultToHtml(result, blocksOutput);
})
.nodeify(callback);
};
}
return Ext;
};
/**
...
npost = function (object, name, args) { return Q(object).npost(name, args); }
n/a
nsend = function (object, name) { var nodeArgs = array_slice(arguments, 2); var deferred = defer(); nodeArgs.push(deferred.makeNodeResolver()); Q(object).dispatch("post", [name, nodeArgs]).fail(deferred.reject); return deferred.promise; }
n/a
passByCopy = function (object) { //freeze(object); //passByCopies.set(object, true); return object; }
n/a
post = function (object, name, args) { return Q(object).dispatch("post", [name, args]); }
n/a
function progress(object, progressed) { return Q(object).then(void 0, void 0, progressed); }
...
'ebook-convert',
path.resolve(outputFolder, SUMMARY_FILE),
path.resolve(outputFolder, 'index.' + format),
command.optionsToShellArgs(options)
].join(' ');
return command.exec(cmd)
.progress(function(data) {
logger.debug(data);
})
.fail(function(err) {
if (err.code == 127) {
throw error.RequireInstallError({
cmd: 'ebook-convert',
install: 'Install it from Calibre: https://calibre-ebook.com'
...
function promised(callback) { return function () { return spread([this, all(arguments)], function (self, args) { return callback.apply(self, args); }); }; }
n/a
function race(answerPs) { return promise(function (resolve, reject) { // Switch to this once we can assume at least ES5 // answerPs.forEach(function (answerP) { // Q(answerP).then(resolve, reject); // }); // Use this in the meantime for (var i = 0, len = answerPs.length; i < len; i++) { Q(answerPs[i]).then(resolve, reject); } }); }
n/a
function reduce(arr, iter, base) { arr = Immutable.Iterable.isIterable(arr)? arr : Immutable.List(arr); return arr.reduce(function(prev, elem, key) { return prev .then(function(val) { return iter(val, elem, key); }); }, Q(base)); }
...
*/
function createMockFS(files) {
files = Immutable.fromJS(files);
var mtime = new Date();
function getFile(filePath) {
var parts = path.normalize(filePath).split(path.sep);
return parts.reduce(function(list, part, i) {
if (!list) return null;
var file;
if (!part || part === '.') file = list;
else file = list.get(part);
...
function reject(reason) { var rejection = Promise({ "when": function (rejected) { // note that the error has been handled if (rejected) { untrackRejection(this); } return rejected ? rejected(reason) : this; } }, function fallback() { return this; }, function inspect() { return { state: "rejected", reason: reason }; }); // Note that the reason has not been handled. trackRejection(rejection, reason); return rejection; }
...
if (!this.isRunning()) return Promise();
var d = Promise.defer();
this.running.close(function(err) {
that.running = null;
that.emit('state', false);
if (err) d.reject(err);
else d.resolve();
});
for (var i = 0; i < this.sockets.length; i++) {
this.sockets[i].destroy();
}
...
function resetUnhandledRejections() { unhandledReasons.length = 0; unhandledRejections.length = 0; if (!trackUnhandledRejections) { trackUnhandledRejections = true; } }
n/a
function Q(value) { // If the object is already a Promise, return it directly. This enables // the resolve function to both be used to created references from objects, // but to tolerably coerce non-promises to promises. if (value instanceof Promise) { return value; } // assimilate thenables if (isPromiseAlike(value)) { return coerce(value); } else { return fulfill(value); } }
...
The `Book` class is the central point of GitBook, it centralize all access read methods. This class is defined in [book.js](https
://github.com/GitbookIO/gitbook/blob/master/lib/book.js).
```js
// Read configuration from book.json
var value = book.config.get('title', 'Default Value');
// Resolve a filename to an absolute path
var filepath = book.resolve('README.md');
// Render an inline markup string
book.renderInline('markdown', 'This is **Markdown**')
.then(function(str) { ... })
// Render a markup string (block mode)
book.renderBlock('markdown', '* This is **Markdown**')
...
function _return(value) { throw new QReturnValue(value); }
n/a
send = function (object, name) { return Q(object).dispatch("post", [name, array_slice(arguments, 2)]); }
n/a
function serie(arr, iter, base) { return reduce(arr, function(before, item, key) { return Q(iter(item, key)) .then(function(r) { before.push(r); return before; }); }, []); }
...
}
var fs = book.getFS();
var ignore = book.getIgnore();
ignore = ignore.add(DEFAULT_IGNORES);
return Promise.serie(IGNORE_FILES, function(filename) {
return fs.readAsString(filename)
.then(function(content) {
ignore = ignore.add(content.toString().split(/\r?\n/));
}, function(err) {
return Promise();
});
})
...
set = function (object, key, value) { return Q(object).dispatch("set", [key, value]); }
...
*/
function decodeGlobal(output, result) {
var book = output.getBook();
var config = book.getConfig();
// Update config
config = decodeConfig(config, result.config);
book = book.set('config', config);
return output.set('book', book);
}
module.exports = decodeGlobal;
...
function some(arr, iter) { arr = Immutable.List(arr); return arr.reduce(function(prev, elem, i) { return prev.then(function(val) { if (val) return val; return iter(elem, i); }); }, Q()); }
...
var ext = path.extname(filename);
var basename = path.basename(filename, ext);
var basedir = path.dirname(filename);
// Ordered list of extensions to test
var exts = parsers.extensions;
return Promise.some(exts, function(ext) {
var filepath = basename + ext;
return fs.findFile(basedir, filepath)
.then(function(found) {
if (!found || book.isContentFileIgnored(found)) {
return undefined;
}
...
function spawn(makeGenerator) { Q.done(Q.async(makeGenerator)()); }
...
var fs = require('./fs');
var error = require('./error');
// Convert a svg file to a pmg
function convertSVGToPNG(source, dest, options) {
if (!fs.existsSync(source)) return Promise.reject(new error.FileNotFoundError({ filename: source }));
return command.spawn('svgexport', [source, dest])
.fail(function(err) {
if (err.code == 'ENOENT') {
err = error.RequireInstallError({
cmd: 'svgexport',
install: 'Install it using: "npm install svgexport -g"'
});
}
...
function spread(value, fulfilled, rejected) { return Q(value).spread(fulfilled, rejected); }
...
@param {Book} book
@return {Promise<Book>}
*/
function parseGlossary(book) {
var logger = book.getLogger();
return parseStructureFile(book, 'glossary')
.spread(function(file, entries) {
if (!file) {
return book;
}
logger.debug.ln('glossary index file found at', file.getPath());
var glossary = Glossary.createFromEntries(file, entries);
...
stopUnhandledRejectionTracking = function () { resetUnhandledRejections(); trackUnhandledRejections = false; }
n/a
tap = function (promise, callback) { return Q(promise).tap(callback); }
...
return generator.onInit(output);
})
.then(generateAssets.bind(null, generator))
.then(generatePages.bind(null, generator))
.tap(function(output) {
var book = output.getBook();
if (!book.isMultilingual()) {
return;
}
var logger = book.getLogger();
...
thenReject = function (promise, reason) { return Q(promise).thenReject(reason); }
n/a
thenResolve = function (promise, value) { return Q(promise).thenResolve(value); }
...
);
return fs.copy(
path.resolve(outputFolder, langID, 'index' + extension),
langOutputFile
);
})
.thenResolve(languages.getCount());
} else {
return fs.copy(
path.resolve(outputFolder, 'index' + extension),
outputFile
).thenResolve(1);
}
})
...
timeout = function (object, ms, error) { return Q(object).timeout(ms, error); }
n/a
try = function (object) { return Q(object).dispatch("apply", [void 0, array_slice(arguments, 1)]); }
n/a
function when(value, fulfilled, rejected, progressed) { return Q(value).then(fulfilled, rejected, progressed); }
n/a
function wrap(func) { return function() { var args = Array.prototype.slice.call(arguments, 0); return Q() .then(function() { return func.apply(null, args); }); }; }
n/a
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
create = function (file, def) { def = def || {}; return new Readme({ file: file, title: def.title || '', description: def.description || '' }); }
...
var book = Book.createForFS(fs);
return Parse.parseReadme(book)
// Setup default readme if doesn't found one
.fail(function() {
var readmeFile = File.createWithFilepath('README' + extension);
var readme = Readme.create(readmeFile);
return book.setReadme(readme);
});
})
.then(Parse.parseSummary)
.then(function(book) {
var logger = book.getLogger();
...
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
getDescription = function () { return this.get('description'); }
...
@param {GlossaryEntry}
@return {Object}
*/
function encodeGlossaryEntry(entry) {
return {
id: entry.getID(),
name: entry.getName(),
description: entry.getDescription()
};
}
module.exports = encodeGlossaryEntry;
...
getFile = function () { return this.get('file'); }
...
});
})
.then(Parse.parseSummary)
.then(function(book) {
var logger = book.getLogger();
var summary = book.getSummary();
var summaryFile = summary.getFile();
var summaryFilename = summaryFile.getPath() || ('SUMMARY' + extension);
var articles = summary.getArticlesAsList();
// Write pages
return Promise.forEach(articles, function(article) {
var articlePath = article.getPath();
...
getTitle = function () { return this.get('title'); }
...
return;
}
return fs.assertFile(filePath, function() {
return fs.ensureFile(filePath)
.then(function() {
logger.info.ln('create', article.getPath());
return fs.writeFile(filePath, '# ' + article.getTitle() + '
;\n\n');
});
});
})
// Write summary
.then(function() {
var filePath = path.join(rootFolder, summaryFilename);
...
exec = function (args, kwargs) { server = new Server(); var hasWatch = kwargs['watch']; var hasLiveReloading = kwargs['live']; return Promise() .then(function() { if (!hasWatch || !hasLiveReloading) { return; } lrServer = tinylr({}); return Promise.nfcall(lrServer.listen.bind(lrServer), kwargs.lrport) .then(function() { console.log('Live reload server started on port:', kwargs.lrport); console.log('Press CTRL+C to quit ...'); console.log(''); }); }) .then(function() { return generateBook(args, kwargs); }); }
...
@param {String} command
@param {Object} options
@return {Promise}
*/
function exec(command, options) {
var d = Promise.defer();
var child = childProcess.exec(command, options, function(err, stdout, stderr) {
if (!err) {
return d.resolve();
}
err.message = stdout.toString('utf8') + stderr.toString('utf8');
d.reject(err);
});
...
function Server() { this.running = null; this.dir = null; this.port = 0; this.sockets = []; }
n/a
function EventEmitter() { EventEmitter.init.call(this); }
n/a
isRunning = function () { return !!this.running; }
...
var browser = kwargs['browser'];
var hasWatch = kwargs['watch'];
var hasLiveReloading = kwargs['live'];
var hasOpen = kwargs['open'];
// Stop server if running
if (server.isRunning()) console.log('Stopping server');
return server.stop()
.then(function() {
return Parse.parseBook(book)
.then(function(resultBook) {
if (hasLiveReloading) {
// Enable livereload plugin
...
start = function (dir, port) { var that = this, pre = Promise(); port = port || 8004; if (that.isRunning()) pre = this.stop(); return pre .then(function() { var d = Promise.defer(); that.running = http.createServer(function(req, res){ // Render error function error(err) { res.statusCode = err.status || 500; res.end(err.message); } // Redirect to directory's index.html function redirect() { var resultURL = urlTransform(req.url, function(parsed) { parsed.pathname += '/'; return parsed; }); res.statusCode = 301; res.setHeader('Location', resultURL); res.end('Redirecting to ' + resultURL); } res.setHeader('X-Current-Location', req.url); // Send file send(req, url.parse(req.url).pathname, { root: dir }) .on('error', error) .on('directory', redirect) .pipe(res); }); that.running.on('connection', function (socket) { that.sockets.push(socket); socket.setTimeout(4000); socket.on('close', function () { that.sockets.splice(that.sockets.indexOf(socket), 1); }); }); that.running.listen(port, function(err) { if (err) return d.reject(err); that.port = port; that.dir = dir; that.emit('state', true); d.resolve(); }); return d.promise; }); }
...
root: outputFolder
});
});
})
.then(function() {
console.log();
console.log('Starting server ...');
return server.start(outputFolder, port);
})
.then(function() {
console.log('Serving book on http://localhost:'+port);
if (lrPath && hasLiveReloading) {
// trigger livereload
lrServer.changed({
...
stop = function () { var that = this; if (!this.isRunning()) return Promise(); var d = Promise.defer(); this.running.close(function(err) { that.running = null; that.emit('state', false); if (err) d.reject(err); else d.resolve(); }); for (var i = 0; i < this.sockets.length; i++) { this.sockets[i].destroy(); } return d.promise; }
...
var hasWatch = kwargs['watch'];
var hasLiveReloading = kwargs['live'];
var hasOpen = kwargs['open'];
// Stop server if running
if (server.isRunning()) console.log('Stopping server');
return server.stop()
.then(function() {
return Parse.parseBook(book)
.then(function(resultBook) {
if (hasLiveReloading) {
// Enable livereload plugin
var config = resultBook.getConfig();
config = ConfigModifier.addPlugin(config, 'livereload');
...
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
getI18n = function () { return this.get('i18n'); }
n/a
getResources = function () { return this.get('resources'); }
n/a
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
create = function (def, level) { var articles = (def.articles || []).map(function(article, i) { if (article instanceof SummaryArticle) { return article; } return SummaryArticle.create(article, [level, i + 1].join('.')); }); return new SummaryArticle({ level: level, title: def.title, ref: def.ref || def.path || '', articles: Immutable.List(articles) }); }
...
var book = Book.createForFS(fs);
return Parse.parseReadme(book)
// Setup default readme if doesn't found one
.fail(function() {
var readmeFile = File.createWithFilepath('README' + extension);
var readme = Readme.create(readmeFile);
return book.setReadme(readme);
});
})
.then(Parse.parseSummary)
.then(function(book) {
var logger = book.getLogger();
...
findArticle = function (base, iter) { var articles = base.getArticles(); return articles.reduce(function(result, article) { if (result) return result; if (iter(article)) { return article; } return SummaryArticle.findArticle(article, iter); }, null); }
...
return articles.reduce(function(result, article) {
if (result) return result;
if (iter(article)) {
return article;
}
return SummaryArticle.findArticle(article, iter);
}, null);
};
module.exports = SummaryArticle;
...
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
createChildLevel = function () { var level = this.getLevel(); var subArticles = this.getArticles(); var childLevel = level + '.' + (subArticles.size + 1); return childLevel; }
...
var SummaryArticle = require('../summaryArticle');
var File = require('../file');
describe('SummaryArticle', function() {
describe('createChildLevel', function() {
it('must create the right level', function() {
var article = SummaryArticle.create({}, '1.1');
expect(article.createChildLevel()).toBe('1.1.1');
});
it('must create the right level when has articles', function() {
var article = SummaryArticle.create({
articles: [
{
title: 'Test'
...
getAnchor = function () { var ref = this.getRef(); var parts = ref.split('#'); var anchor = (parts.length > 1? '#' + parts[parts.length - 1] : undefined); return anchor; }
...
.toJS();
}
return {
title: article.getTitle(),
level: article.getLevel(),
depth: article.getDepth(),
anchor: article.getAnchor(),
url: article.getUrl(),
path: article.getPath(),
ref: article.getRef(),
articles: articles
};
}
...
getArticles = function () { return this.get('articles'); }
...
@param {SummaryArticle}
@return {Object}
*/
function encodeSummaryArticle(article, recursive) {
var articles = undefined;
if (recursive !== false) {
articles = article.getArticles()
.map(encodeSummaryArticle)
.toJS();
}
return {
title: article.getTitle(),
level: article.getLevel(),
...
getDepth = function () { return (this.getLevel().split('.').length - 1); }
...
var article = summary.getByPath(file.getPath());
var result = attributes.toJS();
if (article) {
result.title = article.getTitle();
result.level = article.getLevel();
result.depth = article.getDepth();
var nextArticle = summary.getNextArticle(article);
if (nextArticle) {
result.next = encodeSummaryArticle(nextArticle);
}
var prevArticle = summary.getPrevArticle(article);
...
getLevel = function () { return this.get('level'); }
...
*/
function encodeArticle(pages, article) {
var articlePath = article.getPath();
return {
path: articlePath,
title: article.getTitle(),
level: article.getLevel(),
exists: (articlePath && pages.has(articlePath)),
external: article.isExternal()
};
}
/**
this.navigation is a deprecated property from GitBook v2
...
getPath = function () { if (this.isExternal()) { return undefined; } var ref = this.getRef(); if (!ref) { return undefined; } var parts = ref.split('#'); var pathname = (parts.length > 1? parts.slice(0, -1).join('#') : ref); // Normalize path to remove ('./', '/...', etc) return location.flatten(pathname); }
...
})
.then(Parse.parseSummary)
.then(function(book) {
var logger = book.getLogger();
var summary = book.getSummary();
var summaryFile = summary.getFile();
var summaryFilename = summaryFile.getPath() || ('SUMMARY' + extension);
var articles = summary.getArticlesAsList();
// Write pages
return Promise.forEach(articles, function(article) {
var articlePath = article.getPath();
var filePath = articlePath? path.join(rootFolder, articlePath) : null;
...
getRef = function () { return this.get('ref'); }
...
var pages = output.getPages();
var summary = book.getSummary();
var articles = summary.getArticlesAsList();
var navigation = articles
.map(function(article, i) {
var ref = article.getRef();
if (!ref) {
return undefined;
}
var prev = articles.get(i - 1);
var next = articles.get(i + 1);
...
getTitle = function () { return this.get('title'); }
...
return;
}
return fs.assertFile(filePath, function() {
return fs.ensureFile(filePath)
.then(function() {
logger.info.ln('create', article.getPath());
return fs.writeFile(filePath, '# ' + article.getTitle() + '
;\n\n');
});
});
})
// Write summary
.then(function() {
var filePath = path.join(rootFolder, summaryFilename);
...
getUrl = function () { return this.isExternal()? this.getRef() : undefined; }
...
}
return {
title: article.getTitle(),
level: article.getLevel(),
depth: article.getDepth(),
anchor: article.getAnchor(),
url: article.getUrl(),
path: article.getPath(),
ref: article.getRef(),
articles: articles
};
}
module.exports = encodeSummaryArticle;
...
isExternal = function () { return location.isExternal(this.getRef()); }
...
var articlePath = article.getPath();
return {
path: articlePath,
title: article.getTitle(),
level: article.getLevel(),
exists: (articlePath && pages.has(articlePath)),
external: article.isExternal()
};
}
/**
this.navigation is a deprecated property from GitBook v2
@param {Output}
...
isFile = function (file) { return ( file.getPath() === this.getPath() && this.getAnchor() === undefined ); }
...
* @param {Book|Readme} book
* @return {Boolean}
*/
SummaryArticle.prototype.isReadme = function(book) {
var readme = book.getFile? book : book.getReadme();
var file = readme.getFile();
return this.isFile(file);
};
/**
* Is article pointing to aan absolute url
*
* @return {Boolean}
*/
...
isPage = function () { return !this.isExternal() && this.getRef(); }
...
var glossary = book.getGlossary();
var map = Immutable.OrderedMap();
// Parse pages from summary
return timing.measure(
'parse.listPages',
walkSummary(summary, function(article) {
if (!article.isPage()) return;
var filepath = article.getPath();
// Is the page ignored?
if (book.isContentFileIgnored(filepath)) return;
return parseFilePage(book, filepath)
...
isReadme = function (book) { var readme = book.getFile? book : book.getReadme(); var file = readme.getFile(); return this.isFile(file); }
n/a
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
create = function (def, level) { var articles = (def.articles || []).map(function(article, i) { if (article instanceof SummaryArticle) { return article; } return SummaryArticle.create(article, [level, i + 1].join('.')); }); return new SummaryPart({ level: String(level), title: def.title, articles: Immutable.List(articles) }); }
...
var book = Book.createForFS(fs);
return Parse.parseReadme(book)
// Setup default readme if doesn't found one
.fail(function() {
var readmeFile = File.createWithFilepath('README' + extension);
var readme = Readme.create(readmeFile);
return book.setReadme(readme);
});
})
.then(Parse.parseSummary)
.then(function(book) {
var logger = book.getLogger();
...
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
createChildLevel = function () { var level = this.getLevel(); var subArticles = this.getArticles(); var childLevel = level + '.' + (subArticles.size + 1); return childLevel; }
...
var SummaryArticle = require('../summaryArticle');
var File = require('../file');
describe('SummaryArticle', function() {
describe('createChildLevel', function() {
it('must create the right level', function() {
var article = SummaryArticle.create({}, '1.1');
expect(article.createChildLevel()).toBe('1.1.1');
});
it('must create the right level when has articles', function() {
var article = SummaryArticle.create({
articles: [
{
title: 'Test'
...
getArticles = function () { return this.get('articles'); }
...
@param {SummaryArticle}
@return {Object}
*/
function encodeSummaryArticle(article, recursive) {
var articles = undefined;
if (recursive !== false) {
articles = article.getArticles()
.map(encodeSummaryArticle)
.toJS();
}
return {
title: article.getTitle(),
level: article.getLevel(),
...
getLevel = function () { return this.get('level'); }
...
*/
function encodeArticle(pages, article) {
var articlePath = article.getPath();
return {
path: articlePath,
title: article.getTitle(),
level: article.getLevel(),
exists: (articlePath && pages.has(articlePath)),
external: article.isExternal()
};
}
/**
this.navigation is a deprecated property from GitBook v2
...
getTitle = function () { return this.get('title'); }
...
return;
}
return fs.assertFile(filePath, function() {
return fs.ensureFile(filePath)
.then(function() {
logger.info.ln('create', article.getPath());
return fs.writeFile(filePath, '# ' + article.getTitle() + '
;\n\n');
});
});
})
// Write summary
.then(function() {
var filePath = path.join(rootFolder, summaryFilename);
...
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
create = function (blockName, block) { if (is.fn(block)) { block = new Immutable.Map({ process: block }); } block = new TemplateBlock(block); block = block.set('name', blockName); return block; }
...
var book = Book.createForFS(fs);
return Parse.parseReadme(book)
// Setup default readme if doesn't found one
.fail(function() {
var readmeFile = File.createWithFilepath('README' + extension);
var readme = Readme.create(readmeFile);
return book.setReadme(readme);
});
})
.then(Parse.parseSummary)
.then(function(book) {
var logger = book.getLogger();
...
applyBlock = function (inner, context) { var processFn = this.getProcess(); inner = inner || {}; inner.args = inner.args || []; inner.kwargs = inner.kwargs || {}; inner.blocks = inner.blocks || []; var r = processFn.call(context, inner); if (Promise.isPromiseAlike(r)) { return r.then(this.normalizeBlockResult.bind(this)); } else { return this.normalizeBlockResult(r); } }
...
@param {String} name
@param {Object} blockData
@return {Promise|Object}
*/
applyBlock: function(name, blockData) {
var block = blocks.get(name) || defaultBlocks.get(name);
return Promise(block.applyBlock(blockData, result));
}
},
output: {
/**
Name of the generator being used
{String}
...
blockResultToHtml = function (result, blocksOutput) { var indexedKey; var toIndex = (!result.parse) || (result.post !== undefined); if (toIndex) { indexedKey = genKey(); blocksOutput[indexedKey] = result; } // Parsable block, just return it if (result.parse) { return result.body; } // Return it as a position marker return '{{-%' + indexedKey + '%-}}'; }
...
var ctx = extend({
ctx: context
}, mainContext || {});
return that.applyBlock(mainBlock, ctx);
})
.then(function(result) {
return that.blockResultToHtml(result, blocksOutput);
})
.nodeify(callback);
};
}
return Ext;
};
...
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
getBlocks = function () { return this.get('blocks'); }
...
*/
TemplateBlock.prototype.toNunjucksExt = function(mainContext, blocksOutput) {
blocksOutput = blocksOutput || {};
var that = this;
var name = this.getName();
var endTag = this.getEndTag();
var blocks = this.getBlocks().toJS();
function Ext() {
this.tags = [name];
this.parse = function(parser, nodes) {
var lastBlockName = null;
var lastBlockArgs = null;
...
getEndTag = function () { return this.get('end') || ('end' + this.getName()); }
...
* @return {Nunjucks.Extension}
*/
TemplateBlock.prototype.toNunjucksExt = function(mainContext, blocksOutput) {
blocksOutput = blocksOutput || {};
var that = this;
var name = this.getName();
var endTag = this.getEndTag();
var blocks = this.getBlocks().toJS();
function Ext() {
this.tags = [name];
this.parse = function(parser, nodes) {
var lastBlockName = null;
...
getExtensionName = function () { return 'Block' + this.getName() + 'Extension'; }
...
// Add filters
filters.forEach(function(filterFn, filterName) {
env.addFilter(filterName, filterFn.bind(context));
});
// Add blocks
blocks.forEach(function(block) {
var extName = block.getExtensionName();
var Ext = block.toNunjucksExt(context, blocksOutput);
env.addExtension(extName, new Ext());
});
// Add globals
globals.forEach(function(globalValue, globalName) {
...
getName = function () { return this.get('name'); }
...
* Return a specific parser by its name
*
* @param {String} name
* @return {Parser|undefined}
*/
function getParser(name) {
return parsers.find(function(parser) {
return parser.getName() === name;
});
}
/**
* Return a specific parser according to an extension
*
* @param {String} ext
...
getProcess = function () { return this.get('process'); }
...
/**
* Apply a block to a content
* @param {Object} inner
* @param {Object} context
* @return {Promise<String>|String}
*/
TemplateBlock.prototype.applyBlock = function(inner, context) {
var processFn = this.getProcess();
inner = inner || {};
inner.args = inner.args || [];
inner.kwargs = inner.kwargs || {};
inner.blocks = inner.blocks || [];
var r = processFn.call(context, inner);
...
getShortcuts = function () { var shortcuts = this.get('shortcuts'); if (shortcuts.size === 0) { return undefined; } return TemplateShortcut.createForBlock(this, shortcuts); }
...
if (!parser) {
return Immutable.List();
}
return blocks
.map(function(block) {
return block.getShortcuts();
})
.filter(function(shortcuts) {
return (
shortcuts &&
shortcuts.acceptParser(parser.getName())
);
});
...
normalizeBlockResult = function (result) { if (is.string(result)) { result = { body: result }; } result.name = this.getName(); return result; }
...
inner.blocks = inner.blocks || [];
var r = processFn.call(context, inner);
if (Promise.isPromiseAlike(r)) {
return r.then(this.normalizeBlockResult.bind(this));
} else {
return this.normalizeBlockResult(r);
}
};
/**
* Normalize result from a block process function
* @param {Object|String} result
* @return {Object}
...
toNunjucksExt = function (mainContext, blocksOutput) { blocksOutput = blocksOutput || {}; var that = this; var name = this.getName(); var endTag = this.getEndTag(); var blocks = this.getBlocks().toJS(); function Ext() { this.tags = [name]; this.parse = function(parser, nodes) { var lastBlockName = null; var lastBlockArgs = null; var allBlocks = blocks.concat([endTag]); // Parse first block var tok = parser.nextToken(); lastBlockArgs = parser.parseSignature(null, true); parser.advanceAfterBlockEnd(tok.value); var args = new nodes.NodeList(); var bodies = []; var blockNamesNode = new nodes.Array(tok.lineno, tok.colno); var blockArgCounts = new nodes.Array(tok.lineno, tok.colno); // Parse while we found "end<block>" do { // Read body var currentBody = parser.parseUntilBlocks.apply(parser, allBlocks); // Handle body with previous block name and args blockNamesNode.addChild(new nodes.Literal(args.lineno, args.colno, lastBlockName)); blockArgCounts.addChild(new nodes.Literal(args.lineno, args.colno, lastBlockArgs.children.length)); bodies.push(currentBody); // Append arguments of this block as arguments of the run function lastBlockArgs.children.forEach(function(child) { args.addChild(child); }); // Read new block lastBlockName = parser.nextToken().value; // Parse signature and move to the end of the block if (lastBlockName != endTag) { lastBlockArgs = parser.parseSignature(null, true); } parser.advanceAfterBlockEnd(lastBlockName); } while (lastBlockName != endTag); args.addChild(blockNamesNode); args.addChild(blockArgCounts); args.addChild(new nodes.Literal(args.lineno, args.colno, NODE_ENDARGS)); return new nodes.CallExtensionAsync(this, 'run', args, bodies); }; this.run = function(context) { var fnArgs = Array.prototype.slice.call(arguments, 1); var args; var blocks = []; var bodies = []; var blockNames; var blockArgCounts; var callback; // Extract callback callback = fnArgs.pop(); // Detect end of arguments var endArgIndex = fnArgs.indexOf(NODE_ENDARGS); // Extract arguments and bodies args = fnArgs.slice(0, endArgIndex); bodies = fnArgs.slice(endArgIndex + 1); // Extract block counts blockArgCounts = args.pop(); blockNames = args.pop(); // Recreate list of blocks blockNames.forEach(function(name, i) { var countArgs = blockArgCounts[i]; var blockBody = bodies.shift(); var blockArgs = countArgs > 0? args.slice(0, countArgs) : []; args = args.slice(countArgs); var blockKwargs = extractKwargs(blockArgs); blocks.push({ name: name, body: blockBody(), args: blockArgs, kwargs: blockKwargs }); }); var mainBlock = blocks.shift(); mainBlock.blocks = blocks; Promise() .then(function() { var ctx = extend({ ctx: context }, mainContext || {}); return that.applyBlock(mainBlock, ctx); }) .then(function(result) { return that.blockResultToHtml(result, blocksOutput); }) .nodeify(callback); }; } return Ext; }
...
filters.forEach(function(filterFn, filterName) {
env.addFilter(filterName, filterFn.bind(context));
});
// Add blocks
blocks.forEach(function(block) {
var extName = block.getExtensionName();
var Ext = block.toNunjucksExt(context, blocksOutput);
env.addExtension(extName, new Ext());
});
// Add globals
globals.forEach(function(globalValue, globalName) {
env.addGlobal(globalName, globalValue);
...
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
create = function (def) { return new TemplateEngine({ blocks: Immutable.List(def.blocks || []), extensions: Immutable.Map(def.extensions || {}), filters: Immutable.Map(def.filters || {}), globals: Immutable.Map(def.globals || {}), context: def.context, loader: def.loader }); }
...
var book = Book.createForFS(fs);
return Parse.parseReadme(book)
// Setup default readme if doesn't found one
.fail(function() {
var readmeFile = File.createWithFilepath('README' + extension);
var readme = Readme.create(readmeFile);
return book.setReadme(readme);
});
})
.then(Parse.parseSummary)
.then(function(book) {
var logger = book.getLogger();
...
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
getBlock = function (name) { var blocks = this.getBlocks(); return blocks.find(function(block) { return block.getName() === name; }); }
n/a
getBlocks = function () { return this.get('blocks'); }
...
*/
TemplateBlock.prototype.toNunjucksExt = function(mainContext, blocksOutput) {
blocksOutput = blocksOutput || {};
var that = this;
var name = this.getName();
var endTag = this.getEndTag();
var blocks = this.getBlocks().toJS();
function Ext() {
this.tags = [name];
this.parse = function(parser, nodes) {
var lastBlockName = null;
var lastBlockArgs = null;
...
getContext = function () { return this.get('context'); }
...
*/
TemplateEngine.prototype.toNunjucks = function(blocksOutput) {
var loader = this.getLoader();
var blocks = this.getBlocks();
var filters = this.getFilters();
var globals = this.getGlobals();
var extensions = this.getExtensions();
var context = this.getContext();
var env = new nunjucks.Environment(
loader,
{
// Escaping is done after by the asciidoc/markdown parser
autoescape: false,
...
getExtensions = function () { return this.get('extensions'); }
...
function getParserForFile(filename) {
return getParserByExt(path.extname(filename));
}
// List all parsable extensions
var extensions = parsers
.map(function(parser) {
return parser.getExtensions();
})
.flatten();
module.exports = {
extensions: extensions,
get: getParser,
getByExt: getParserByExt,
...
getFilters = function () { return this.get('filters'); }
...
Return a nunjucks environment from this configuration
@return {Nunjucks.Environment}
*/
TemplateEngine.prototype.toNunjucks = function(blocksOutput) {
var loader = this.getLoader();
var blocks = this.getBlocks();
var filters = this.getFilters();
var globals = this.getGlobals();
var extensions = this.getExtensions();
var context = this.getContext();
var env = new nunjucks.Environment(
loader,
{
...
getGlobals = function () { return this.get('globals'); }
...
@return {Nunjucks.Environment}
*/
TemplateEngine.prototype.toNunjucks = function(blocksOutput) {
var loader = this.getLoader();
var blocks = this.getBlocks();
var filters = this.getFilters();
var globals = this.getGlobals();
var extensions = this.getExtensions();
var context = this.getContext();
var env = new nunjucks.Environment(
loader,
{
// Escaping is done after by the asciidoc/markdown parser
...
getLoader = function () { return this.get('loader'); }
...
/**
Return a nunjucks environment from this configuration
@return {Nunjucks.Environment}
*/
TemplateEngine.prototype.toNunjucks = function(blocksOutput) {
var loader = this.getLoader();
var blocks = this.getBlocks();
var filters = this.getFilters();
var globals = this.getGlobals();
var extensions = this.getExtensions();
var context = this.getContext();
var env = new nunjucks.Environment(
...
getShortcuts = function () { return this.get('shortcuts'); }
...
if (!parser) {
return Immutable.List();
}
return blocks
.map(function(block) {
return block.getShortcuts();
})
.filter(function(shortcuts) {
return (
shortcuts &&
shortcuts.acceptParser(parser.getName())
);
});
...
toNunjucks = function (blocksOutput) { var loader = this.getLoader(); var blocks = this.getBlocks(); var filters = this.getFilters(); var globals = this.getGlobals(); var extensions = this.getExtensions(); var context = this.getContext(); var env = new nunjucks.Environment( loader, { // Escaping is done after by the asciidoc/markdown parser autoescape: false, // Syntax tags: { blockStart: '{%', blockEnd: '%}', variableStart: '{{', variableEnd: '}}', commentStart: '{###', commentEnd: '###}' } } ); // Add filters filters.forEach(function(filterFn, filterName) { env.addFilter(filterName, filterFn.bind(context)); }); // Add blocks blocks.forEach(function(block) { var extName = block.getExtensionName(); var Ext = block.toNunjucksExt(context, blocksOutput); env.addExtension(extName, new Ext()); }); // Add globals globals.forEach(function(globalValue, globalName) { env.addGlobal(globalName, globalValue); }); // Add other extensions extensions.forEach(function(ext, extName) { env.addExtension(extName, ext); }); return env; }
...
function renderTemplate(engine, filePath, content, context) {
context = context || {};
// Mutable objects to contains all blocks requiring post-processing
var blocks = {};
// Create nunjucks environment
var env = engine.toNunjucks(blocks);
// Replace shortcuts from plugin's blocks
content = replaceShortcuts(engine.getBlocks(), filePath, content);
return timing.measure(
'template.render',
...
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
create = function (content, blocks) { return new TemplateOutput({ content: content, blocks: Immutable.fromJS(blocks) }); }
...
var book = Book.createForFS(fs);
return Parse.parseReadme(book)
// Setup default readme if doesn't found one
.fail(function() {
var readmeFile = File.createWithFilepath('README' + extension);
var readme = Readme.create(readmeFile);
return book.setReadme(readme);
});
})
.then(Parse.parseSummary)
.then(function(book) {
var logger = book.getLogger();
...
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
getBlocks = function () { return this.get('blocks'); }
...
*/
TemplateBlock.prototype.toNunjucksExt = function(mainContext, blocksOutput) {
blocksOutput = blocksOutput || {};
var that = this;
var name = this.getName();
var endTag = this.getEndTag();
var blocks = this.getBlocks().toJS();
function Ext() {
this.tags = [name];
this.parse = function(parser, nodes) {
var lastBlockName = null;
var lastBlockArgs = null;
...
getContent = function () { return this.get('content'); }
...
@param {Output} output
@param {Page} page: page instance to edit
@param {Object} result: result from API
@return {Page}
*/
function decodePage(output, page, result) {
var originalContent = page.getContent();
// No returned value
// Existing content will be used
if (!result) {
return page;
}
...
setContent = function (content) { return this.set('content', content); }
...
})
.then(function(output) {
var content = output.getContent();
return parser.parsePage(content)
.then(function(result) {
return output.setContent(result.content);
});
})
// Post processing for templating syntax
.then(function(output) {
return Templating.postRender(engine, output);
})
...
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
createForBlock = function (block, details) { details = Immutable.fromJS(details); return new TemplateShortcut({ parsers: details.get('parsers'), start: details.get('start'), end: details.get('end'), startTag: block.getName(), endTag: block.getEndTag() }); }
...
*/
TemplateBlock.prototype.getShortcuts = function() {
var shortcuts = this.get('shortcuts');
if (shortcuts.size === 0) {
return undefined;
}
return TemplateShortcut.createForBlock(this, shortcuts);
};
/**
* Return name for the nunjucks extension
* @return {String}
*/
TemplateBlock.prototype.getExtensionName = function() {
...
acceptParser = function (parser) { if (!is.string(parser)) { parser = parser.getName(); } var parserNames = this.get('parsers'); return parserNames.includes(parser); }
...
return blocks
.map(function(block) {
return block.getShortcuts();
})
.filter(function(shortcuts) {
return (
shortcuts &&
shortcuts.acceptParser(parser.getName())
);
});
}
module.exports = listShortcuts;
...
function Record(values) { if (values instanceof RecordType) { return values; } if (!(this instanceof RecordType)) { return new RecordType(values); } if (!hasInitialized) { hasInitialized = true; var keys = Object.keys(defaultValues); setProps(RecordTypePrototype, keys); RecordTypePrototype.size = keys.length; RecordTypePrototype._name = name; RecordTypePrototype._keys = keys; RecordTypePrototype._defaultValues = defaultValues; } this._map = Map(values); }
n/a
getEnd = function () { return this.get('end'); }
...
* Apply a shortcut of block to a template
* @param {String} content
* @param {Shortcut} shortcut
* @return {String}
*/
function applyShortcut(content, shortcut) {
var start = shortcut.getStart();
var end = shortcut.getEnd();
var tagStart = shortcut.getStartTag();
var tagEnd = shortcut.getEndTag();
var regex = new RegExp(
escapeStringRegexp(start) + '([\\s\\S]*?[^\\$])' + escapeStringRegexp(end),
'g'
...
getEndTag = function () { return this.get('endTag'); }
...
* @return {Nunjucks.Extension}
*/
TemplateBlock.prototype.toNunjucksExt = function(mainContext, blocksOutput) {
blocksOutput = blocksOutput || {};
var that = this;
var name = this.getName();
var endTag = this.getEndTag();
var blocks = this.getBlocks().toJS();
function Ext() {
this.tags = [name];
this.parse = function(parser, nodes) {
var lastBlockName = null;
...
getParsers = function () { return this.get('parsers'); }
n/a
getStart = function () { return this.get('start'); }
...
/**
* Apply a shortcut of block to a template
* @param {String} content
* @param {Shortcut} shortcut
* @return {String}
*/
function applyShortcut(content, shortcut) {
var start = shortcut.getStart();
var end = shortcut.getEnd();
var tagStart = shortcut.getStartTag();
var tagEnd = shortcut.getEndTag();
var regex = new RegExp(
escapeStringRegexp(start) + '([\\s\\S]*?[^\\$])' + escapeStringRegexp(end),
...
getStartTag = function () { return this.get('startTag'); }
...
* @param {Shortcut} shortcut
* @return {String}
*/
function applyShortcut(content, shortcut) {
var start = shortcut.getStart();
var end = shortcut.getEnd();
var tagStart = shortcut.getStartTag();
var tagEnd = shortcut.getEndTag();
var regex = new RegExp(
escapeStringRegexp(start) + '([\\s\\S]*?[^\\$])' + escapeStringRegexp(end),
'g'
);
return content.replace(regex, function(all, match) {
...
themesLoader = function () { if(prototype.init) { prototype.init.apply(this, arguments); } }
n/a
extend = function (name, props) { if(typeof name === 'object') { props = name; name = 'anonymous'; } return extend(new_cls, name, props); }
...
var is = require('is');
var path = require('path');
var fs = require('fs');
var expect = require('expect');
var cheerio = require('cheerio');
expect.extend({
/**
* Check that a file is created in a directory:
* expect('myFolder').toHaveFile('hello.md');
*/
toHaveFile: function(fileName) {
var filePath = path.join(this.actual, fileName);
var exists = fs.existsSync(filePath);
...
constructor = function () { if(prototype.init) { prototype.init.apply(this, arguments); } }
n/a
getSearchPath = function (filepath) { return this.searchPaths .sortBy(function(s) { return -s.length; }) .find(function(basePath) { return (filepath && filepath.indexOf(basePath) === 0); }); }
...
/**
* Get template name from a filepath
* @param {String} filepath
* @return {String} name
*/
getTemplateName: function(filepath) {
var originalSearchPath = this.getSearchPath(filepath);
return originalSearchPath? path.relative(originalSearchPath, filepath) : null;
},
/**
* Resolve a template from a current template
* @param {String|null} from
* @param {String} to
...
getSource = function (fullpath) { if (!fullpath) return null; fullpath = this.resolve(null, fullpath); var templateName = this.getTemplateName(fullpath); if(!fullpath) { return null; } var src = fs.readFileSync(fullpath, 'utf-8'); src = '{% do %}var template = template || {}; template.stack = template.stack || []; template.stack.push(template.self); template .self = ' + JSON.stringify(templateName) + '{% enddo %}\n' + src + '\n{% do %}template.self = template.stack.pop();{% enddo %}'; return { src: src, path: fullpath, noCache: true }; }
...
// Resolve the filePath
var resolvedFilePath = loader.resolve(null, filePath);
return Promise()
.then(function() {
if (!loader.async) {
return loader.getSource(resolvedFilePath);
}
var deferred = Promise.defer();
loader.getSource(resolvedFilePath, deferred.makeNodeResolver());
return deferred.promise;
})
.then(function(result) {
...
getTemplateName = function (filepath) { var originalSearchPath = this.getSearchPath(filepath); return originalSearchPath? path.relative(originalSearchPath, filepath) : null; }
...
* @param {String}
* @return {Object}
*/
getSource: function(fullpath) {
if (!fullpath) return null;
fullpath = this.resolve(null, fullpath);
var templateName = this.getTemplateName(fullpath);
if(!fullpath) {
return null;
}
var src = fs.readFileSync(fullpath, 'utf-8');
...
init = function (searchPaths) { this.searchPaths = Immutable.List(searchPaths) .map(path.normalize); }
n/a
isRelative = function () { return true; }
...
// If origin is not in the book (include from a git content ref)
return path.resolve(path.dirname(from), to);
},
// Handle all files as relative, so that nunjucks pass responsability to 'resolve'
isRelative: function(filename) {
return LocationUtils.isRelative(filename);
}
});
module.exports = ConrefsLoader;
...
resolve = function (from, to) { var searchPaths = this.searchPaths; // Relative template like "./test.html" if (PathUtils.isPureRelative(to) && from) { return path.resolve(path.dirname(from), to); } // Determine in which search folder we currently are var originalSearchPath = this.getSearchPath(from); var originalFilename = this.getTemplateName(from); // If we are including same file from a different search path // Slice the search paths to avoid including from previous ones if (originalFilename == to) { var currentIndex = searchPaths.indexOf(originalSearchPath); searchPaths = searchPaths.slice(currentIndex + 1); } // Absolute template to resolve in root folder var resultFolder = searchPaths.find(function(basePath) { var p = path.resolve(basePath, to); return ( p.indexOf(basePath) === 0 && fs.existsSync(p) ); }); if (!resultFolder) return null; return path.resolve(resultFolder, to); }
...
The `Book` class is the central point of GitBook, it centralize all access read methods. This class is defined in [book.js](https
://github.com/GitbookIO/gitbook/blob/master/lib/book.js).
```js
// Read configuration from book.json
var value = book.config.get('title', 'Default Value');
// Resolve a filename to an absolute path
var filepath = book.resolve('README.md');
// Render an inline markup string
book.renderInline('markdown', 'This is **Markdown**')
.then(function(str) { ... })
// Render a markup string (block mode)
book.renderBlock('markdown', '* This is **Markdown**')
...
function dump(logger) { var prefix = ' > '; var measured = 0; var totalDuration = Date.now() - startDate; // Enable debug logging var logLevel = logger.getLevel(); logger.setLevel('debug'); Immutable.Map(timers) .valueSeq() .sortBy(function(timer) { measured += timer.total; return timer.total; }) .forEach(function(timer) { var percent = (timer.total * 100) / totalDuration; logger.debug.ln((percent.toFixed(1)) + '% of time spent in "' + timer.type + '" (' + timer.count + ' times) :'); logger.debug.ln(prefix + 'Total: ' + time(timer.total)+ ' | Average: ' + time(timer.total / timer.count)); logger.debug.ln(prefix + 'Min: ' + time(timer.min) + ' | Max: ' + time(timer.max)); logger.debug.ln('---------------------------'); }); logger.debug.ln(time(totalDuration - measured) + ' spent in non-mesured sections'); // Rollback to previous level logger.setLevel(logLevel); }
...
return Parse.parseBook(book)
.then(function(resultBook) {
return Output.generate(Generator, resultBook, {
root: outputFolder
});
})
.fin(function() {
if (kwargs.timing) timing.dump(book.getLogger());
});
}
};
...
function measure(type, p) { timers[type] = timers[type] || { type: type, count: 0, total: 0, min: undefined, max: 0 }; var start = Date.now(); return p .fin(function() { var end = Date.now(); var duration = (end - start); timers[type].count ++; timers[type].total += duration; if (is.undefined(timers[type].min)) { timers[type].min = duration; } else { timers[type].min = Math.min(timers[type].min, duration); } timers[type].max = Math.max(timers[type].max, duration); }); }
...
var plugins = output.getPlugins();
logger.debug.ln('calling hook "' + name + '"');
// Create the JS context for plugins
var context = Api.encodeGlobal(output);
return timing.measure(
'call.hook.' + name,
// Get the arguments
Promise(getArgument(output))
// Call the hooks in serie
.then(function(arg) {
...