diff options
Diffstat (limited to 'lib')
33 files changed, 453 insertions, 224 deletions
diff --git a/lib/browser.js b/lib/browser.js index 7329d74..87a4dc4 100644 --- a/lib/browser.js +++ b/lib/browser.js @@ -6,6 +6,7 @@ module.exports = { // Models Book: require('./models/book'), FS: require('./models/fs'), + File: require('./models/file'), Summary: require('./models/summary'), Glossary: require('./models/glossary'), Config: require('./models/config'), diff --git a/lib/cli/serve.js b/lib/cli/serve.js index 4ba5148..5340851 100644 --- a/lib/cli/serve.js +++ b/lib/cli/serve.js @@ -1,6 +1,7 @@ /* eslint-disable no-console */ var tinylr = require('tiny-lr'); +var open = require('open'); var Parse = require('../parse'); var Output = require('../output'); @@ -32,9 +33,11 @@ function generateBook(args, kwargs) { var outputFolder = getOutputFolder(args); var book = getBook(args, kwargs); var Generator = Output.getGenerator(kwargs.format); + 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'); @@ -71,6 +74,10 @@ function generateBook(args, kwargs) { } }); } + + if (hasOpen) { + open('http://localhost:'+port, browser); + } }) .then(function() { if (!hasWatch) { @@ -112,6 +119,16 @@ module.exports = { description: 'Enable live reloading', defaults: true }, + { + name: 'open', + description: 'Enable opening book in browser', + defaults: false + }, + { + name: 'browser', + description: 'Specify browser for opening book', + defaults: '' + }, options.log, options.format ], diff --git a/lib/constants/configSchema.js b/lib/constants/configSchema.js index e693977..d2126c6 100644 --- a/lib/constants/configSchema.js +++ b/lib/constants/configSchema.js @@ -18,6 +18,10 @@ module.exports = { 'type': 'string', 'title': 'ISBN for published book' }, + 'language': { + 'type': 'string', + 'title': 'Language of the book' + }, 'author': { 'type': 'string', 'title': 'Name of the author' diff --git a/lib/json/encodeBookWithPage.js b/lib/json/encodeBookWithPage.js index 5600a82..1c5c7a3 100644 --- a/lib/json/encodeBookWithPage.js +++ b/lib/json/encodeBookWithPage.js @@ -3,12 +3,12 @@ var encodePage = require('./encodePage'); var encodeFile = require('./encodeFile'); /** - Return a JSON representation of a book with a specific file - - @param {Book} output - @param {Page} page - @return {Object} -*/ + * Return a JSON representation of a book with a specific file + * + * @param {Book} output + * @param {Page} page + * @return {Object} + */ function encodeBookWithPage(book, page) { var file = page.getFile(); diff --git a/lib/json/encodeOutput.js b/lib/json/encodeOutput.js index 9054124..7347e57 100644 --- a/lib/json/encodeOutput.js +++ b/lib/json/encodeOutput.js @@ -1,11 +1,11 @@ var encodeBook = require('./encodeBook'); /** - Encode an output to JSON - - @param {Output} - @return {Object} -*/ + * Encode an output to JSON + * + * @param {Output} + * @return {Object} + */ function encodeOutputToJson(output) { var book = output.getBook(); var generator = output.getGenerator(); diff --git a/lib/json/encodeOutputWithPage.js b/lib/json/encodeOutputWithPage.js new file mode 100644 index 0000000..8b21e3d --- /dev/null +++ b/lib/json/encodeOutputWithPage.js @@ -0,0 +1,23 @@ +var encodeOutput = require('./encodeOutput'); +var encodePage = require('./encodePage'); +var encodeFile = require('./encodeFile'); + +/** + * Return a JSON representation of a book with a specific file + * + * @param {Book} output + * @param {Page} page + * @return {Object} + */ +function encodeOutputWithPage(output, page) { + var file = page.getFile(); + var book = output.getBook(); + + var result = encodeOutput(output); + result.page = encodePage(page, book.getSummary()); + result.file = encodeFile(file); + + return result; +} + +module.exports = encodeOutputWithPage; diff --git a/lib/json/index.js b/lib/json/index.js index 4387ae0..3b68f5e 100644 --- a/lib/json/index.js +++ b/lib/json/index.js @@ -2,6 +2,7 @@ module.exports = { encodeOutput: require('./encodeOutput'), encodeBookWithPage: require('./encodeBookWithPage'), + encodeOutputWithPage: require('./encodeOutputWithPage'), encodeBook: require('./encodeBook'), encodeFile: require('./encodeFile'), encodePage: require('./encodePage'), diff --git a/lib/models/__tests__/summaryArticle.js b/lib/models/__tests__/summaryArticle.js index 7c4bc57..22a7a20 100644 --- a/lib/models/__tests__/summaryArticle.js +++ b/lib/models/__tests__/summaryArticle.js @@ -1,4 +1,5 @@ var SummaryArticle = require('../summaryArticle'); +var File = require('../file'); describe('SummaryArticle', function() { describe('createChildLevel', function() { @@ -18,6 +19,35 @@ describe('SummaryArticle', function() { expect(article.createChildLevel()).toBe('1.1.2'); }); }); + + describe('isFile', function() { + it('must return true when exactly the file', function() { + var article = SummaryArticle.create({ + ref: 'hello.md' + }, '1.1'); + var file = File.createWithFilepath('hello.md'); + + expect(article.isFile(file)).toBe(true); + }); + + it('must return true when path is not normalized', function() { + var article = SummaryArticle.create({ + ref: '/hello.md' + }, '1.1'); + var file = File.createWithFilepath('hello.md'); + + expect(article.isFile(file)).toBe(true); + }); + + it('must return false when has anchor', function() { + var article = SummaryArticle.create({ + ref: 'hello.md#world' + }, '1.1'); + var file = File.createWithFilepath('hello.md'); + + expect(article.isFile(file)).toBe(false); + }); + }); }); diff --git a/lib/models/summaryArticle.js b/lib/models/summaryArticle.js index 9b5b653..6da8d1d 100644 --- a/lib/models/summaryArticle.js +++ b/lib/models/summaryArticle.js @@ -40,7 +40,8 @@ SummaryArticle.prototype.getDepth = function() { }; /** - * Get path (without anchor) to the pointing file + * Get path (without anchor) to the pointing file. + * It also normalizes the file path. * * @return {String} */ @@ -58,8 +59,8 @@ SummaryArticle.prototype.getPath = function() { var pathname = (parts.length > 1? parts.slice(0, -1).join('#') : ref); - // Normalize path to remove ('./', etc) - return location.normalize(pathname); + // Normalize path to remove ('./', '/...', etc) + return location.flatten(pathname); }; /** @@ -107,6 +108,32 @@ SummaryArticle.prototype.isPage = function() { }; /** + * Check if this article is a file (exatcly) + * + * @param {File} file + * @return {Boolean} + */ +SummaryArticle.prototype.isFile = function(file) { + return ( + file.getPath() === this.getPath() + && this.getAnchor() === undefined + ); +}; + +/** + * Check if this article is the introduction of the book + * + * @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} diff --git a/lib/modifiers/config/editPlugin.js b/lib/modifiers/config/editPlugin.js index f9b6551..a792acd 100644 --- a/lib/modifiers/config/editPlugin.js +++ b/lib/modifiers/config/editPlugin.js @@ -7,7 +7,7 @@ * @return {Config} */ function editPlugin(config, pluginName, pluginConfig) { - return config.set('pluginsConfig.'+pluginName, pluginConfig); + return config.setValue('pluginsConfig.'+pluginName, pluginConfig); } module.exports = editPlugin; diff --git a/lib/modifiers/config/getPluginConfig.js b/lib/modifiers/config/getPluginConfig.js new file mode 100644 index 0000000..ae76de8 --- /dev/null +++ b/lib/modifiers/config/getPluginConfig.js @@ -0,0 +1,20 @@ +/** + * Return the configuration for a plugin + * @param {Config} config + * @param {String} pluginName + * @return {Object} + */ +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(); + } +} + +module.exports = getPluginConfig; diff --git a/lib/modifiers/config/index.js b/lib/modifiers/config/index.js index 5705dbb..b3de0b0 100644 --- a/lib/modifiers/config/index.js +++ b/lib/modifiers/config/index.js @@ -5,5 +5,6 @@ module.exports = { togglePlugin: require('./togglePlugin'), editPlugin: require('./editPlugin'), hasPlugin: require('./hasPlugin'), + getPluginConfig: require('./getPluginConfig'), isDefaultPlugin: require('./isDefaultPlugin') }; diff --git a/lib/output/__tests__/createMock.js b/lib/output/__tests__/createMock.js new file mode 100644 index 0000000..f21c544 --- /dev/null +++ b/lib/output/__tests__/createMock.js @@ -0,0 +1,38 @@ +var Immutable = require('immutable'); + +var Output = require('../../models/output'); +var Book = require('../../models/book'); +var parseBook = require('../../parse/parseBook'); +var createMockFS = require('../../fs/mock'); +var preparePlugins = require('../preparePlugins'); + +/** + * Create an output using a generator + * + * FOR TESTING PURPOSE ONLY + * + * @param {Generator} generator + * @param {Map<String:String|Map>} files + * @return {Promise<Output>} + */ +function createMockOutput(generator, files, options) { + var fs = createMockFS(files); + var book = Book.createForFS(fs); + var state = generator.State? generator.State({}) : Immutable.Map(); + + book = book.setLogLevel('disabled'); + options = generator.Options(options); + + return parseBook(book) + .then(function(resultBook) { + return new Output({ + book: resultBook, + options: options, + state: state, + generator: generator.name + }); + }) + .then(preparePlugins); +} + +module.exports = createMockOutput; diff --git a/lib/output/__tests__/ebook.js b/lib/output/__tests__/ebook.js index bcac990..9266e9f 100644 --- a/lib/output/__tests__/ebook.js +++ b/lib/output/__tests__/ebook.js @@ -1,4 +1,4 @@ -var generateMock = require('../generateMock'); +var generateMock = require('./generateMock'); var EbookGenerator = require('../ebook'); describe('EbookGenerator', function() { diff --git a/lib/output/generateMock.js b/lib/output/__tests__/generateMock.js index ac1e193..691ee2d 100644 --- a/lib/output/generateMock.js +++ b/lib/output/__tests__/generateMock.js @@ -1,21 +1,20 @@ var tmp = require('tmp'); -var Book = require('../models/book'); -var createMockFS = require('../fs/mock'); -var parseBook = require('../parse/parseBook'); -var generateBook = require('./generateBook'); - +var Book = require('../../models/book'); +var createMockFS = require('../../fs/mock'); +var parseBook = require('../../parse/parseBook'); +var generateBook = require('../generateBook'); /** - Generate a book using JSON generator - And returns the path to the output dir. - - FOR TESTING PURPOSE ONLY - - @param {Generator} - @param {Map<String:String|Map>} files - @return {Promise<String>} -*/ + * Generate a book using a generator + * And returns the path to the output dir. + * + * FOR TESTING PURPOSE ONLY + * + * @param {Generator} + * @param {Map<String:String|Map>} files + * @return {Promise<String>} + */ function generateMock(Generator, files) { var fs = createMockFS(files); var book = Book.createForFS(fs); diff --git a/lib/output/__tests__/json.js b/lib/output/__tests__/json.js index 9897813..12ab567 100644 --- a/lib/output/__tests__/json.js +++ b/lib/output/__tests__/json.js @@ -1,4 +1,4 @@ -var generateMock = require('../generateMock'); +var generateMock = require('./generateMock'); var JSONGenerator = require('../json'); describe('JSONGenerator', function() { diff --git a/lib/output/__tests__/website.js b/lib/output/__tests__/website.js index 501503a..1f8c3c0 100644 --- a/lib/output/__tests__/website.js +++ b/lib/output/__tests__/website.js @@ -1,5 +1,5 @@ var fs = require('fs'); -var generateMock = require('../generateMock'); +var generateMock = require('./generateMock'); var WebsiteGenerator = require('../website'); describe('WebsiteGenerator', function() { diff --git a/lib/output/generateBook.js b/lib/output/generateBook.js index 3c10b1a..46712bd 100644 --- a/lib/output/generateBook.js +++ b/lib/output/generateBook.js @@ -13,13 +13,12 @@ var generateAssets = require('./generateAssets'); var generatePages = require('./generatePages'); /** - Process an output to generate the book - - @param {Generator} generator - @param {Output} output - - @return {Promise<Output>} -*/ + * Process an output to generate the book + * + * @param {Generator} generator + * @param {Output} output + * @return {Promise<Output>} + */ function processOutput(generator, startOutput) { return Promise(startOutput) .then(preparePlugins) @@ -133,27 +132,26 @@ function processOutput(generator, startOutput) { } /** - Generate a book using a generator. - - The overall process is: - 1. List and load plugins for this book - 2. Call hook "config" - 3. Call hook "init" - 4. Initialize generator - 5. List all assets and pages - 6. Copy all assets to output - 7. Generate all pages - 8. Call hook "finish:before" - 9. Finish generation - 10. Call hook "finish" - - - @param {Generator} generator - @param {Book} book - @param {Object} options - - @return {Promise<Output>} -*/ + * Generate a book using a generator. + * + * The overall process is: + * 1. List and load plugins for this book + * 2. Call hook "config" + * 3. Call hook "init" + * 4. Initialize generator + * 5. List all assets and pages + * 6. Copy all assets to output + * 7. Generate all pages + * 8. Call hook "finish:before" + * 9. Finish generation + * 10. Call hook "finish" + * + * + * @param {Generator} generator + * @param {Book} book + * @param {Object} options + * @return {Promise<Output>} + */ function generateBook(generator, book, options) { options = generator.Options(options); var state = generator.State? generator.State({}) : Immutable.Map(); diff --git a/lib/output/generatePage.js b/lib/output/generatePage.js index fa6fc0e..090a870 100644 --- a/lib/output/generatePage.js +++ b/lib/output/generatePage.js @@ -10,12 +10,12 @@ var createTemplateEngine = require('./createTemplateEngine'); var callPageHook = require('./callPageHook'); /** - Prepare and generate HTML for a page - - @param {Output} output - @param {Page} page - @return {Promise<Page>} -*/ + * Prepare and generate HTML for a page + * + * @param {Output} output + * @param {Page} page + * @return {Promise<Page>} + */ function generatePage(output, page) { var book = output.getBook(); var engine = createTemplateEngine(output); @@ -27,7 +27,7 @@ function generatePage(output, page) { var file = resultPage.getFile(); var filePath = file.getPath(); var parser = file.getParser(); - var context = JSONUtils.encodeBookWithPage(book, resultPage); + var context = JSONUtils.encodeOutputWithPage(output, resultPage); if (!parser) { return Promise.reject(error.FileNotParsableError({ diff --git a/lib/output/getModifiers.js b/lib/output/getModifiers.js index 66fbc1a..bb44e80 100644 --- a/lib/output/getModifiers.js +++ b/lib/output/getModifiers.js @@ -9,11 +9,11 @@ var fileToOutput = require('./helper/fileToOutput'); var CODEBLOCK = 'code'; /** - Return default modifier to prepare a page for - rendering. - - @return {Array<Modifier>} -*/ + * Return default modifier to prepare a page for + * rendering. + * + * @return {Array<Modifier>} + */ function getModifiers(output, page) { var book = output.getBook(); var plugins = output.getPlugins(); diff --git a/lib/output/helper/fileToOutput.js b/lib/output/helper/fileToOutput.js index 9673162..361c6eb 100644 --- a/lib/output/helper/fileToOutput.js +++ b/lib/output/helper/fileToOutput.js @@ -6,12 +6,12 @@ var LocationUtils = require('../../utils/location'); var OUTPUT_EXTENSION = '.html'; /** - Convert a filePath (absolute) to a filename for output - - @param {Output} output - @param {String} filePath - @return {String} -*/ + * Convert a filePath (absolute) to a filename for output + * + * @param {Output} output + * @param {String} filePath + * @return {String} + */ function fileToOutput(output, filePath) { var book = output.getBook(); var readme = book.getReadme(); diff --git a/lib/output/helper/resolveFileToURL.js b/lib/output/helper/resolveFileToURL.js index 026b0e5..3f52713 100644 --- a/lib/output/helper/resolveFileToURL.js +++ b/lib/output/helper/resolveFileToURL.js @@ -3,12 +3,12 @@ var LocationUtils = require('../../utils/location'); var fileToURL = require('./fileToURL'); /** - Resolve an absolute path (extracted from a link) - - @param {Output} output - @param {String} filePath - @return {String} -*/ + * Resolve an absolute path (extracted from a link) + * + * @param {Output} output + * @param {String} filePath + * @return {String} + */ function resolveFileToURL(output, filePath) { // Convert /test.png -> test.png filePath = LocationUtils.toAbsolute(filePath, '', ''); diff --git a/lib/output/json/onPage.js b/lib/output/json/onPage.js index fece540..2315ba0 100644 --- a/lib/output/json/onPage.js +++ b/lib/output/json/onPage.js @@ -7,11 +7,11 @@ var getModifiers = require('../getModifiers'); var JSON_VERSION = '3'; /** - Write a page as a json file - - @param {Output} output - @param {Page} page -*/ + * Write a page as a json file + * + * @param {Output} output + * @param {Page} page + */ function onPage(output, page) { var file = page.getFile(); var readme = output.getBook().getReadme().getFile(); diff --git a/lib/output/modifiers/annotateText.js b/lib/output/modifiers/annotateText.js index 2b4b439..490c228 100644 --- a/lib/output/modifiers/annotateText.js +++ b/lib/output/modifiers/annotateText.js @@ -59,19 +59,18 @@ function replaceText($, el, search, replace, text_only ) { } /** - Annotate text using a list of GlossaryEntry - - @param {List<GlossaryEntry>} - @param {String} glossaryFilePath - @param {HTMLDom} $ -*/ + * Annotate text using a list of GlossaryEntry + * + * @param {List<GlossaryEntry>} + * @param {String} glossaryFilePath + * @param {HTMLDom} $ + */ function annotateText(entries, glossaryFilePath, $) { entries.forEach(function(entry) { - var entryId = entry.getID(); - var name = entry.getName(); + var entryId = entry.getID(); + var name = entry.getName(); var description = entry.getDescription(); - - var searchRegex = new RegExp( '\\b(' + pregQuote(name.toLowerCase()) + ')\\b' , 'gi' ); + var searchRegex = new RegExp( '\\b(' + pregQuote(name.toLowerCase()) + ')\\b' , 'gi' ); $('*').each(function() { var $this = $(this); diff --git a/lib/output/preparePlugins.js b/lib/output/preparePlugins.js index 54837ed..5c4be93 100644 --- a/lib/output/preparePlugins.js +++ b/lib/output/preparePlugins.js @@ -2,11 +2,11 @@ var Plugins = require('../plugins'); var Promise = require('../utils/promise'); /** - Load and setup plugins - - @param {Output} - @return {Promise<Output>} -*/ + * Load and setup plugins + * + * @param {Output} + * @return {Promise<Output>} + */ function preparePlugins(output) { var book = output.getBook(); diff --git a/lib/output/website/__tests__/i18n.js b/lib/output/website/__tests__/i18n.js new file mode 100644 index 0000000..fd610fb --- /dev/null +++ b/lib/output/website/__tests__/i18n.js @@ -0,0 +1,38 @@ +var createMockOutput = require('../../__tests__/createMock'); +var prepareI18n = require('../prepareI18n'); +var createTemplateEngine = require('../createTemplateEngine'); + +var WebsiteGenerator = require('../'); + +describe('i18n', function() { + it('should correctly use english as default language', function() { + return createMockOutput(WebsiteGenerator, { + 'README.md': 'Hello World' + }) + .then(function(output) { + return prepareI18n(output); + }) + .then(function(output) { + var engine = createTemplateEngine(output, 'README.md'); + var t = engine.getFilters().get('t'); + + expect(t('SUMMARY_INTRODUCTION')).toEqual('Introduction'); + }); + }); + + it('should correctly use language from book.json', function() { + return createMockOutput(WebsiteGenerator, { + 'README.md': 'Hello World', + 'book.json': JSON.stringify({ language: 'fr' }) + }) + .then(function(output) { + return prepareI18n(output); + }) + .then(function(output) { + var engine = createTemplateEngine(output, 'README.md'); + var t = engine.getFilters().get('t'); + + expect(t('GITBOOK_LINK')).toEqual('PubliƩ avec GitBook'); + }); + }); +}); diff --git a/lib/output/website/createTemplateEngine.js b/lib/output/website/createTemplateEngine.js index c60b3a1..02ec796 100644 --- a/lib/output/website/createTemplateEngine.js +++ b/lib/output/website/createTemplateEngine.js @@ -18,19 +18,19 @@ var fileToURL = require('../helper/fileToURL'); var resolveFileToURL = require('../helper/resolveFileToURL'); /** - Directory for a theme with the templates -*/ + * Directory for a theme with the templates + */ function templateFolder(dir) { return path.join(dir, templatesFolder); } /** - Create templating engine to render themes - - @param {Output} output - @param {String} currentFile - @return {TemplateEngine} -*/ + * Create templating engine to render themes + * + * @param {Output} output + * @param {String} currentFile + * @return {TemplateEngine} + */ function createTemplateEngine(output, currentFile) { var book = output.getBook(); var state = output.getState(); @@ -47,18 +47,17 @@ function createTemplateEngine(output, currentFile) { var loader = new Templating.ThemesLoader(tplSearchPaths); // Get languages - var language = config.get('language'); + var language = config.getValue('language'); // Create API context var context = Api.encodeGlobal(output); /** - Check if a file exists - - @param {String} fileName - @return {Boolean} - */ + * Check if a file exists + * @param {String} fileName + * @return {Boolean} + */ function fileExists(fileName) { if (!fileName) { return false; @@ -69,11 +68,10 @@ function createTemplateEngine(output, currentFile) { } /** - Return an article by its path - - @param {String} filePath - @return {Object|undefined} - */ + * Return an article by its path + * @param {String} filePath + * @return {Object|undefined} + */ function getArticleByPath(filePath) { var article = summary.getByPath(filePath); if (!article) return undefined; @@ -82,11 +80,10 @@ function createTemplateEngine(output, currentFile) { } /** - Return a page by its path - - @param {String} filePath - @return {Object|undefined} - */ + * Return a page by its path + * @param {String} filePath + * @return {Object|undefined} + */ function getPageByPath(filePath) { var page = output.getPage(filePath); if (!page) return undefined; @@ -94,7 +91,6 @@ function createTemplateEngine(output, currentFile) { return JSONUtils.encodePage(page, summary); } - return TemplateEngine.create({ loader: loader, @@ -108,17 +104,17 @@ function createTemplateEngine(output, currentFile) { filters: defaultFilters.merge({ /** - Translate a sentence - */ + * Translate a sentence + */ t: function t(s) { return i18n.t(language, s); }, /** - Resolve an absolute file path into a - relative path. - it also resolve pages - */ + * Resolve an absolute file path into a + * relative path. + * it also resolve pages + */ resolveFile: function(filePath) { filePath = resolveFileToURL(output, filePath); return LocationUtils.relativeForFile(currentFile, filePath); diff --git a/lib/output/website/onPage.js b/lib/output/website/onPage.js index 14c7b22..5fb40a7 100644 --- a/lib/output/website/onPage.js +++ b/lib/output/website/onPage.js @@ -12,11 +12,11 @@ var createTemplateEngine = require('./createTemplateEngine'); var fileToOutput = require('../helper/fileToOutput'); /** - Write a page as a json file - - @param {Output} output - @param {Page} page -*/ + * Write a page as a json file + * + * @param {Output} output + * @param {Page} page + */ function onPage(output, page) { var options = output.getOptions(); var prefix = options.get('prefix'); @@ -40,7 +40,7 @@ function onPage(output, page) { return Modifiers.modifyHTML(page, getModifiers(output, page)) .then(function(resultPage) { // Generate the context - var context = JSONUtils.encodeBookWithPage(output.getBook(), resultPage); + var context = JSONUtils.encodeOutputWithPage(output, resultPage); context.plugins = { resources: Plugins.listResources(plugins, resources).toJS() }; diff --git a/lib/output/website/prepareI18n.js b/lib/output/website/prepareI18n.js index b57d178..cedd3b9 100644 --- a/lib/output/website/prepareI18n.js +++ b/lib/output/website/prepareI18n.js @@ -5,11 +5,11 @@ var Promise = require('../../utils/promise'); var listSearchPaths = require('./listSearchPaths'); /** - Prepare i18n, load translations from plugins and book - - @param {Output} - @return {Promise<Output>} -*/ + * Prepare i18n, load translations from plugins and book + * + * @param {Output} + * @return {Promise<Output>} + */ function prepareI18n(output) { var state = output.getState(); var i18n = state.getI18n(); diff --git a/lib/utils/__tests__/location.js b/lib/utils/__tests__/location.js index 2d01714..822338e 100644 --- a/lib/utils/__tests__/location.js +++ b/lib/utils/__tests__/location.js @@ -39,6 +39,21 @@ describe('LocationUtils', function() { }); }); + describe('.flatten', function() { + it('should remove leading slash', function() { + expect(LocationUtils.flatten('/test.md')).toBe('test.md'); + expect(LocationUtils.flatten('/hello/cool.md')).toBe('hello/cool.md'); + }); + + it('should remove leading slashes', function() { + expect(LocationUtils.flatten('///test.md')).toBe('test.md'); + }); + + it('should not break paths', function() { + expect(LocationUtils.flatten('hello/cool.md')).toBe('hello/cool.md'); + }); + }); + describe('.toAbsolute', function() { it('should correctly transform as absolute', function() { expect(LocationUtils.toAbsolute('http://google.fr')).toBe('http://google.fr'); diff --git a/lib/utils/location.js b/lib/utils/location.js index 17edc00..00d8004 100644 --- a/lib/utils/location.js +++ b/lib/utils/location.js @@ -40,13 +40,28 @@ function normalize(s) { } /** - Convert a relative path to absolute + * Flatten a path, it removes the leading "/" + * + * @param {String} href + * @return {String} + */ +function flatten(href) { + href = normalize(href); + if (href[0] == '/') { + href = normalize(href.slice(1)); + } + + return href; +} - @param {String} href - @param {String} dir: directory parent of the file currently in rendering process - @param {String} outdir: directory parent from the html output - @return {String} -*/ +/** + * Convert a relative path to absolute + * + * @param {String} href + * @param {String} dir: directory parent of the file currently in rendering process + * @param {String} outdir: directory parent from the html output + * @return {String} + */ function toAbsolute(_href, dir, outdir) { if (isExternal(_href) || isDataURI(_href)) { return _href; @@ -74,50 +89,51 @@ function toAbsolute(_href, dir, outdir) { } /** - Convert an absolute path to a relative path for a specific folder (dir) - ('test/', 'hello.md') -> '../hello.md' - - @param {String} dir: current directory - @param {String} file: absolute path of file - @return {String} -*/ + * Convert an absolute path to a relative path for a specific folder (dir) + * ('test/', 'hello.md') -> '../hello.md' + * + * @param {String} dir: current directory + * @param {String} file: absolute path of file + * @return {String} + */ function relative(dir, file) { var isDirectory = file.slice(-1) === '/'; return normalize(path.relative(dir, file)) + (isDirectory? '/': ''); } /** - Convert an absolute path to a relative path for a specific folder (dir) - ('test/test.md', 'hello.md') -> '../hello.md' - - @param {String} baseFile: current file - @param {String} file: absolute path of file - @return {String} -*/ + * Convert an absolute path to a relative path for a specific folder (dir) + * ('test/test.md', 'hello.md') -> '../hello.md' + * + * @param {String} baseFile: current file + * @param {String} file: absolute path of file + * @return {String} + */ function relativeForFile(baseFile, file) { return relative(path.dirname(baseFile), file); } /** - Compare two paths, return true if they are identical - ('README.md', './README.md') -> true - - @param {String} p1: first path - @param {String} p2: second path - @return {Boolean} -*/ + * Compare two paths, return true if they are identical + * ('README.md', './README.md') -> true + * + * @param {String} p1: first path + * @param {String} p2: second path + * @return {Boolean} + */ function areIdenticalPaths(p1, p2) { return normalize(p1) === normalize(p2); } module.exports = { areIdenticalPaths: areIdenticalPaths, - isDataURI: isDataURI, - isExternal: isExternal, - isRelative: isRelative, - isAnchor: isAnchor, - normalize: normalize, - toAbsolute: toAbsolute, - relative: relative, - relativeForFile: relativeForFile + isDataURI: isDataURI, + isExternal: isExternal, + isRelative: isRelative, + isAnchor: isAnchor, + normalize: normalize, + toAbsolute: toAbsolute, + relative: relative, + relativeForFile: relativeForFile, + flatten: flatten }; diff --git a/lib/utils/promise.js b/lib/utils/promise.js index 138546b..b5cca4b 100644 --- a/lib/utils/promise.js +++ b/lib/utils/promise.js @@ -2,34 +2,35 @@ var Q = require('q'); var Immutable = require('immutable'); // Debugging for long stack traces -if (global.__DEV__ || process.env.DEBUG) { +if (process.env.DEBUG || process.env.CI) { Q.longStackSupport = true; } /** - Reduce an array to a promise - - @param {Array|List} arr - @param {Function(value, element, index)} - @return {Promise<Mixed>} -*/ + * Reduce an array to a promise + * + * @param {Array|List} arr + * @param {Function(value, element, index)} + * @return {Promise<Mixed>} + */ 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 prev + .then(function(val) { return iter(val, elem, key); }); }, Q(base)); } /** - Iterate over an array using an async iter - - @param {Array|List} arr - @param {Function(value, element, index)} - @return {Promise} -*/ + * Iterate over an array using an async iter + * + * @param {Array|List} arr + * @param {Function(value, element, index)} + * @return {Promise} + */ function forEach(arr, iter) { return reduce(arr, function(val, el, key) { return iter(el, key); @@ -37,12 +38,12 @@ function forEach(arr, iter) { } /** - Transform an array - - @param {Array|List} arr - @param {Function(value, element, index)} - @return {Promise} -*/ + * Transform an array + * + * @param {Array|List} arr + * @param {Function(value, element, index)} + * @return {Promise} + */ function serie(arr, iter, base) { return reduce(arr, function(before, item, key) { return Q(iter(item, key)) @@ -54,12 +55,12 @@ function serie(arr, iter, base) { } /** - Iter over an array and return first result (not null) - - @param {Array|List} arr - @param {Function(element, index)} - @return {Promise<Mixed>} -*/ + * Iter over an array and return first result (not null) + * + * @param {Array|List} arr + * @param {Function(element, index)} + * @return {Promise<Mixed>} + */ function some(arr, iter) { arr = Immutable.List(arr); @@ -73,12 +74,12 @@ function some(arr, iter) { } /** - Map an array using an async (promised) iterator - - @param {Array|List} arr - @param {Function(element, index)} - @return {Promise<List>} -*/ + * Map an array using an async (promised) iterator + * + * @param {Array|List} arr + * @param {Function(element, index)} + * @return {Promise<List>} + */ function mapAsList(arr, iter) { return reduce(arr, function(prev, entry, i) { return Q(iter(entry, i)) @@ -90,12 +91,12 @@ function mapAsList(arr, iter) { } /** - Map an array or map - - @param {Array|List|Map|OrderedMap} arr - @param {Function(element, key)} - @return {Promise<List|Map|OrderedMap>} -*/ + * Map an array or map + * + * @param {Array|List|Map|OrderedMap} arr + * @param {Function(element, key)} + * @return {Promise<List|Map|OrderedMap>} + */ function map(arr, iter) { if (Immutable.Map.isMap(arr)) { var type = 'Map'; @@ -122,11 +123,11 @@ function map(arr, iter) { /** - Wrap a function in a promise - - @param {Function} func - @return {Funciton} -*/ + * Wrap a function in a promise + * + * @param {Function} func + * @return {Funciton} + */ function wrap(func) { return function() { var args = Array.prototype.slice.call(arguments, 0); diff --git a/lib/utils/reducedObject.js b/lib/utils/reducedObject.js index fa5d32c..7bcfd5b 100644 --- a/lib/utils/reducedObject.js +++ b/lib/utils/reducedObject.js @@ -4,8 +4,13 @@ var Immutable = require('immutable'); * Reduce the difference between a map and its default version * @param {Map} defaultVersion * @param {Map} currentVersion + * @return {Map} The properties of currentVersion that differs from defaultVersion */ function reducedObject(defaultVersion, currentVersion) { + if(defaultVersion === undefined) { + return currentVersion; + } + return currentVersion.reduce(function(result, value, key) { var defaultValue = defaultVersion.get(key); |