summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSamy Pessé <samypesse@gmail.com>2016-01-28 16:27:29 +0100
committerSamy Pessé <samypesse@gmail.com>2016-01-28 16:27:29 +0100
commita063cc1a53bede0a869b184f5ec4793ce300ae01 (patch)
tree15b960ffaf0e3058cf7c5cc6e272ae4ad8f56731
parent36f2f5d52e54c03036f05225df3f58e9833f3e71 (diff)
downloadgitbook-a063cc1a53bede0a869b184f5ec4793ce300ae01.zip
gitbook-a063cc1a53bede0a869b184f5ec4793ce300ae01.tar.gz
gitbook-a063cc1a53bede0a869b184f5ec4793ce300ae01.tar.bz2
Add base for langs parsing
-rw-r--r--lib/backbone/glossary.js3
-rw-r--r--lib/backbone/langs.js54
-rw-r--r--lib/book.js51
-rw-r--r--lib/output.js7
4 files changed, 108 insertions, 7 deletions
diff --git a/lib/backbone/glossary.js b/lib/backbone/glossary.js
index 22c4d42..9aed1ac 100644
--- a/lib/backbone/glossary.js
+++ b/lib/backbone/glossary.js
@@ -32,6 +32,9 @@ GlossaryEntry.prototype.getId = function() {
};
+/*
+A glossary is a list of entries stored in a GLOSSARY.md file
+*/
function Glossary() {
BackboneFile.apply(this, arguments);
diff --git a/lib/backbone/langs.js b/lib/backbone/langs.js
index 2818519..a40bd80 100644
--- a/lib/backbone/langs.js
+++ b/lib/backbone/langs.js
@@ -1,15 +1,65 @@
+var _ = require('lodash');
+var path = require('path');
+var util = require('util');
+var BackboneFile = require('./file');
+function Language(title, folder) {
+ var that = this;
+
+ this.title = title;
+ this.folder = folder;
+
+ Object.defineProperty(this, 'id', {
+ get: function() {
+ return path.basename(that.folder);
+ }
+ });
+}
+
+/*
+A Langs is a list of languages stored in a LANGS.md file
+*/
function Langs() {
- if (!(this instanceof Langs)) return new Langs();
+ BackboneFile.apply(this, arguments);
this.languages = [];
}
+util.inherits(Langs, BackboneFile);
Langs.prototype.type = 'langs';
+// Parse the readme content
+Langs.prototype.parse = function(content) {
+ var that = this;
+
+ return this.parser.langs(content)
+ .then(function(langs) {
+ that.languages = _.map(langs, function(entry) {
+ return new Language(entry.title, entry.path);
+ });
+ });
+};
+
+// Return the list of languages
+Langs.prototype.list = function() {
+ return this.languages;
+};
+
+// Return default/main language for the book
+Langs.prototype.getDefault = function() {
+ return _.first(this.languages);
+};
+
+// Return true if a language is the default one
+// "lang" cam be a string (id) or a Language entry
+Langs.prototype.isDefault = function(lang) {
+ lang = lang.id || lang;
+ return (this.cound() > 0 && this.getDefault().id == lang);
+};
+
// Return the count of languages
Langs.prototype.count = function() {
- return this.languages.length;
+ return _.size(this.languages);
};
module.exports = Langs;
diff --git a/lib/book.js b/lib/book.js
index 77539ce..73a43ec 100644
--- a/lib/book.js
+++ b/lib/book.js
@@ -97,9 +97,27 @@ Book.prototype.prepareConfig = function() {
};
// Resolve a path in the book source
-// Enforce that the output path in the root folder
+// Enforce that the output path is in the scope
Book.prototype.resolve = function() {
- return pathUtil.resolveInRoot.apply(null, [this.root].concat(_.toArray(arguments)));
+ var filename = path.resolve.apply([this.root].concat(_.toArray(arguments)));
+ if (!this.isFileInScope(filename)) {
+ var err = new Error('EACCESS: "' + filename + '" not in "' + this.root + '"');
+ err.code = 'EACCESS';
+ throw err;
+ }
+
+ return filename;
+};
+
+// Return false if a file is outside the book' scope
+Book.prototype.isFileInScope = function(filename) {
+ filename = path.resolve(this.root, filename);
+
+ // Is the file in the scope of the parent?
+ if (this.parent && this.parent.isFileInScope(filename)) return true;
+
+ // Is file in the root folder?
+ return pathUtil.isInRoot(this.root, filename);
};
// Parse .gitignore, etc to extract rules
@@ -133,8 +151,25 @@ Book.prototype.parse = function() {
.then(function() {
if (that.isMultilingual()) {
+ if (that.isLanguageBook()) {
+ throw new Error('A multilingual book as a language book is forbidden');
+ }
+
that.log.info.ln('Parsing multilingual book, with', that.langs.count(), 'languages');
- return;
+
+ // Create a new book for each language and parse it
+ return Promise.serial(that.langs.list(), function(lang) {
+ that.log.debug.ln('Preparing book for language', lang.id);
+ var langBook = new Book({
+ fs: that.fs,
+ parent: that,
+ root: that.resolve(lang.id)
+ });
+
+ that.books.push(langBook);
+
+ return langBook.parse();
+ });
}
return Promise()
@@ -229,4 +264,14 @@ Book.prototype.isMultilingual = function() {
return this.langs.count() > 0;
};
+// Return true if file is in the scope of a child book
+Book.prototype.isInLanguageBook = function(filename) {
+ return _.some(this.langs.list(), function(lang) {
+ return pathUtil.isInRoot(
+ this.resolve(lang.id),
+ this.resolve(filename)
+ );
+ });
+};
+
module.exports = Book;
diff --git a/lib/output.js b/lib/output.js
index 2e5bc65..d09f29d 100644
--- a/lib/output.js
+++ b/lib/output.js
@@ -19,6 +19,7 @@ Output.prototype.writeFile = function(filename, buf) {
// Start the generation, for a parsed book
Output.prototype.generate = function() {
var that = this;
+ var isMultilingual = this.isMultilingual();
return Promise()
@@ -33,9 +34,11 @@ Output.prototype.generate = function() {
})
.then(function(files) {
return Promise.serie(files, function(filename) {
- var isPage = that.book.hasPage(filename);
+ // Ignore file present in a language book
+ if (isMultilingual && that.book.isInLanguageBook(filename)) return;
- if (isPage) {
+ // Process file as page or asset
+ if (that.book.hasPage(filename)) {
return that.generator.writePage(that.book.getPage(filename));
} else {
return that.generator.writeAsset(filename);