diff options
Diffstat (limited to 'lib/output')
67 files changed, 0 insertions, 2956 deletions
diff --git a/lib/output/__tests__/createMock.js b/lib/output/__tests__/createMock.js deleted file mode 100644 index f21c544..0000000 --- a/lib/output/__tests__/createMock.js +++ /dev/null @@ -1,38 +0,0 @@ -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 deleted file mode 100644 index 9266e9f..0000000 --- a/lib/output/__tests__/ebook.js +++ /dev/null @@ -1,16 +0,0 @@ -var generateMock = require('./generateMock'); -var EbookGenerator = require('../ebook'); - -describe('EbookGenerator', function() { - - it('should generate a SUMMARY.html', function() { - return generateMock(EbookGenerator, { - 'README.md': 'Hello World' - }) - .then(function(folder) { - expect(folder).toHaveFile('SUMMARY.html'); - expect(folder).toHaveFile('index.html'); - }); - }); -}); - diff --git a/lib/output/__tests__/generateMock.js b/lib/output/__tests__/generateMock.js deleted file mode 100644 index 691ee2d..0000000 --- a/lib/output/__tests__/generateMock.js +++ /dev/null @@ -1,40 +0,0 @@ -var tmp = require('tmp'); - -var Book = require('../../models/book'); -var createMockFS = require('../../fs/mock'); -var parseBook = require('../../parse/parseBook'); -var generateBook = require('../generateBook'); - -/** - * 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); - var dir; - - try { - dir = tmp.dirSync(); - } catch(err) { - throw err; - } - - book = book.setLogLevel('disabled'); - - return parseBook(book) - .then(function(resultBook) { - return generateBook(Generator, resultBook, { - root: dir.name - }); - }) - .thenResolve(dir.name); -} - -module.exports = generateMock; diff --git a/lib/output/__tests__/json.js b/lib/output/__tests__/json.js deleted file mode 100644 index 12ab567..0000000 --- a/lib/output/__tests__/json.js +++ /dev/null @@ -1,46 +0,0 @@ -var generateMock = require('./generateMock'); -var JSONGenerator = require('../json'); - -describe('JSONGenerator', function() { - - it('should generate a README.json', function() { - return generateMock(JSONGenerator, { - 'README.md': 'Hello World' - }) - .then(function(folder) { - expect(folder).toHaveFile('README.json'); - }); - }); - - it('should generate a json file for each articles', function() { - return generateMock(JSONGenerator, { - 'README.md': 'Hello World', - 'SUMMARY.md': '# Summary\n\n* [Page](test/page.md)', - 'test': { - 'page.md': 'Hello 2' - } - }) - .then(function(folder) { - expect(folder).toHaveFile('README.json'); - expect(folder).toHaveFile('test/page.json'); - }); - }); - - it('should generate a multilingual book', function() { - return generateMock(JSONGenerator, { - 'LANGS.md': '# Languages\n\n* [en](en)\n* [fr](fr)', - 'en': { - 'README.md': 'Hello' - }, - 'fr': { - 'README.md': 'Bonjour' - } - }) - .then(function(folder) { - expect(folder).toHaveFile('en/README.json'); - expect(folder).toHaveFile('fr/README.json'); - expect(folder).toHaveFile('README.json'); - }); - }); -}); - diff --git a/lib/output/__tests__/website.js b/lib/output/__tests__/website.js deleted file mode 100644 index 1f8c3c0..0000000 --- a/lib/output/__tests__/website.js +++ /dev/null @@ -1,144 +0,0 @@ -var fs = require('fs'); -var generateMock = require('./generateMock'); -var WebsiteGenerator = require('../website'); - -describe('WebsiteGenerator', function() { - - it('should generate an index.html', function() { - return generateMock(WebsiteGenerator, { - 'README.md': 'Hello World' - }) - .then(function(folder) { - expect(folder).toHaveFile('index.html'); - }); - }); - - describe('Glossary', function() { - var folder; - - before(function() { - return generateMock(WebsiteGenerator, { - 'README.md': 'Hello World', - 'SUMMARY.md': '* [Deep](folder/page.md)', - 'folder': { - 'page.md': 'Hello World' - }, - 'GLOSSARY.md': '# Glossary\n\n## Hello\n\nHello World' - }) - .then(function(_folder) { - folder = _folder; - }); - }); - - it('should generate a GLOSSARY.html', function() { - expect(folder).toHaveFile('GLOSSARY.html'); - }); - - it('should correctly resolve glossary links in README', function() { - var html = fs.readFileSync(folder + '/index.html', 'utf8'); - expect(html).toHaveDOMElement('.page-inner a[href="GLOSSARY.html#hello"]'); - }); - - it('should correctly resolve glossary links in directory', function() { - var html = fs.readFileSync(folder + '/folder/page.html', 'utf8'); - expect(html).toHaveDOMElement('.page-inner a[href="../GLOSSARY.html#hello"]'); - }); - - it('should accept a custom glossary file', function() { - return generateMock(WebsiteGenerator, { - 'README.md': 'Hello World', - 'book.json': '{ "structure": { "glossary": "custom.md" } }', - 'custom.md': '# Glossary\n\n## Hello\n\nHello World' - }) - .then(function(folder) { - expect(folder).toHaveFile('custom.html'); - expect(folder).toNotHaveFile('GLOSSARY.html'); - - var html = fs.readFileSync(folder + '/index.html', 'utf8'); - expect(html).toHaveDOMElement('.page-inner a[href="custom.html#hello"]'); - }); - }); - }); - - - it('should copy asset files', function() { - return generateMock(WebsiteGenerator, { - 'README.md': 'Hello World', - 'myJsFile.js': 'var a = "test";', - 'folder': { - 'AnotherAssetFile.md': '# Even md' - } - }) - .then(function(folder) { - expect(folder).toHaveFile('index.html'); - expect(folder).toHaveFile('myJsFile.js'); - expect(folder).toHaveFile('folder/AnotherAssetFile.md'); - }); - }); - - it('should generate an index.html for AsciiDoc', function() { - return generateMock(WebsiteGenerator, { - 'README.adoc': 'Hello World' - }) - .then(function(folder) { - expect(folder).toHaveFile('index.html'); - }); - }); - - it('should generate an HTML file for each articles', function() { - return generateMock(WebsiteGenerator, { - 'README.md': 'Hello World', - 'SUMMARY.md': '# Summary\n\n* [Page](test/page.md)', - 'test': { - 'page.md': 'Hello 2' - } - }) - .then(function(folder) { - expect(folder).toHaveFile('index.html'); - expect(folder).toHaveFile('test/page.html'); - }); - }); - - it('should not generate file if entry file doesn\'t exist', function() { - return generateMock(WebsiteGenerator, { - 'README.md': 'Hello World', - 'SUMMARY.md': '# Summary\n\n* [Page 1](page.md)\n* [Page 2](test/page.md)', - 'test': { - 'page.md': 'Hello 2' - } - }) - .then(function(folder) { - expect(folder).toHaveFile('index.html'); - expect(folder).toNotHaveFile('page.html'); - expect(folder).toHaveFile('test/page.html'); - }); - }); - - it('should generate a multilingual book', function() { - return generateMock(WebsiteGenerator, { - 'LANGS.md': '# Languages\n\n* [en](en)\n* [fr](fr)', - 'en': { - 'README.md': 'Hello' - }, - 'fr': { - 'README.md': 'Bonjour' - } - }) - .then(function(folder) { - // It should generate languages - expect(folder).toHaveFile('en/index.html'); - expect(folder).toHaveFile('fr/index.html'); - - // Should not copy languages as assets - expect(folder).toNotHaveFile('en/README.md'); - expect(folder).toNotHaveFile('fr/README.md'); - - // Should copy assets only once - expect(folder).toHaveFile('gitbook/style.css'); - expect(folder).toNotHaveFile('en/gitbook/style.css'); - - expect(folder).toHaveFile('index.html'); - }); - }); -}); - diff --git a/lib/output/callHook.js b/lib/output/callHook.js deleted file mode 100644 index 4914e52..0000000 --- a/lib/output/callHook.js +++ /dev/null @@ -1,60 +0,0 @@ -var Promise = require('../utils/promise'); -var timing = require('../utils/timing'); -var Api = require('../api'); - -function defaultGetArgument() { - return undefined; -} - -function defaultHandleResult(output, result) { - return output; -} - -/** - Call a "global" hook for an output - - @param {String} name - @param {Function(Output) -> Mixed} getArgument - @param {Function(Output, result) -> Output} handleResult - @param {Output} output - @return {Promise<Output>} -*/ -function callHook(name, getArgument, handleResult, output) { - getArgument = getArgument || defaultGetArgument; - handleResult = handleResult || defaultHandleResult; - - 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)) - - // 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); - }) - - // Handle final result - .then(function(result) { - output = Api.decodeGlobal(output, context); - return handleResult(output, result); - }) - ); -} - -module.exports = callHook; diff --git a/lib/output/callPageHook.js b/lib/output/callPageHook.js deleted file mode 100644 index c66cef0..0000000 --- a/lib/output/callPageHook.js +++ /dev/null @@ -1,28 +0,0 @@ -var Api = require('../api'); -var callHook = require('./callHook'); - -/** - Call a hook for a specific page - - @param {String} name - @param {Output} output - @param {Page} page - @return {Promise<Page>} -*/ -function callPageHook(name, output, page) { - return callHook( - name, - - function(out) { - return Api.encodePage(out, page); - }, - - function(out, result) { - return Api.decodePage(out, page, result); - }, - - output - ); -} - -module.exports = callPageHook; diff --git a/lib/output/createTemplateEngine.js b/lib/output/createTemplateEngine.js deleted file mode 100644 index 8cf320e..0000000 --- a/lib/output/createTemplateEngine.js +++ /dev/null @@ -1,45 +0,0 @@ -var Templating = require('../templating'); -var TemplateEngine = require('../models/templateEngine'); - -var Api = require('../api'); -var Plugins = require('../plugins'); - -var defaultBlocks = require('../constants/defaultBlocks'); -var defaultFilters = require('../constants/defaultFilters'); - -/** - Create template engine for an output. - It adds default filters/blocks, then add the ones from plugins - - @param {Output} output - @return {TemplateEngine} -*/ -function createTemplateEngine(output) { - var plugins = output.getPlugins(); - var book = output.getBook(); - var rootFolder = book.getContentRoot(); - var logger = book.getLogger(); - - var filters = Plugins.listFilters(plugins); - var blocks = Plugins.listBlocks(plugins); - - // Extend with default - blocks = defaultBlocks.merge(blocks); - filters = defaultFilters.merge(filters); - - // Create loader - var transformFn = Templating.replaceShortcuts.bind(null, blocks); - var loader = new Templating.ConrefsLoader(rootFolder, transformFn, logger); - - // Create API context - var context = Api.encodeGlobal(output); - - return new TemplateEngine({ - filters: filters, - blocks: blocks, - loader: loader, - context: context - }); -} - -module.exports = createTemplateEngine; diff --git a/lib/output/ebook/getConvertOptions.js b/lib/output/ebook/getConvertOptions.js deleted file mode 100644 index bc80493..0000000 --- a/lib/output/ebook/getConvertOptions.js +++ /dev/null @@ -1,73 +0,0 @@ -var extend = require('extend'); - -var Promise = require('../../utils/promise'); -var getPDFTemplate = require('./getPDFTemplate'); -var getCoverPath = require('./getCoverPath'); - -/** - Generate options for ebook-convert - - @param {Output} - @return {Promise<Object>} -*/ -function getConvertOptions(output) { - var options = output.getOptions(); - var format = options.get('format'); - - var book = output.getBook(); - var config = book.getConfig(); - - return Promise() - .then(function() { - var coverPath = getCoverPath(output); - var options = { - '--cover': coverPath, - '--title': config.getValue('title'), - '--comments': config.getValue('description'), - '--isbn': config.getValue('isbn'), - '--authors': config.getValue('author'), - '--language': book.getLanguage() || config.getValue('language'), - '--book-producer': 'GitBook', - '--publisher': 'GitBook', - '--chapter': 'descendant-or-self::*[contains(concat(\' \', normalize-space(@class), \' \'), \' book-chapter \')]', - '--level1-toc': 'descendant-or-self::*[contains(concat(\' \', normalize-space(@class), \' \'), \' book-chapter-1 \')]', - '--level2-toc': 'descendant-or-self::*[contains(concat(\' \', normalize-space(@class), \' \'), \' book-chapter-2 \')]', - '--level3-toc': 'descendant-or-self::*[contains(concat(\' \', normalize-space(@class), \' \'), \' book-chapter-3 \')]', - '--max-levels': '1', - '--no-chapters-in-toc': true, - '--breadth-first': true, - '--dont-split-on-page-breaks': format === 'epub'? true : undefined - }; - - if (format !== 'pdf') { - return options; - } - - return Promise.all([ - getPDFTemplate(output, 'header'), - getPDFTemplate(output, 'footer') - ]) - .spread(function(headerTpl, footerTpl) { - var pdfOptions = config.getValue('pdf').toJS(); - - return options = extend(options, { - '--chapter-mark': String(pdfOptions.chapterMark), - '--page-breaks-before': String(pdfOptions.pageBreaksBefore), - '--margin-left': String(pdfOptions.margin.left), - '--margin-right': String(pdfOptions.margin.right), - '--margin-top': String(pdfOptions.margin.top), - '--margin-bottom': String(pdfOptions.margin.bottom), - '--pdf-default-font-size': String(pdfOptions.fontSize), - '--pdf-mono-font-size': String(pdfOptions.fontSize), - '--paper-size': String(pdfOptions.paperSize), - '--pdf-page-numbers': Boolean(pdfOptions.pageNumbers), - '--pdf-sans-family': String(pdfOptions.fontFamily), - '--pdf-header-template': headerTpl, - '--pdf-footer-template': footerTpl - }); - }); - }); -} - - -module.exports = getConvertOptions; diff --git a/lib/output/ebook/getCoverPath.js b/lib/output/ebook/getCoverPath.js deleted file mode 100644 index ab6b579..0000000 --- a/lib/output/ebook/getCoverPath.js +++ /dev/null @@ -1,30 +0,0 @@ -var path = require('path'); -var fs = require('../../utils/fs'); - -/** - Resolve path to cover file to use - - @param {Output} - @return {String} -*/ -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); - } - - return cover; -} - -module.exports = getCoverPath; diff --git a/lib/output/ebook/getPDFTemplate.js b/lib/output/ebook/getPDFTemplate.js deleted file mode 100644 index b767daf..0000000 --- a/lib/output/ebook/getPDFTemplate.js +++ /dev/null @@ -1,41 +0,0 @@ -var juice = require('juice'); - -var WebsiteGenerator = require('../website'); -var JSONUtils = require('../../json'); -var Templating = require('../../templating'); -var Promise = require('../../utils/promise'); - - -/** - Generate PDF header/footer templates - - @param {Output} output - @param {String} type - @return {String} -*/ -function getPDFTemplate(output, type) { - var filePath = 'pdf_' + type + '.html'; - var outputRoot = output.getRoot(); - var engine = WebsiteGenerator.createTemplateEngine(output, filePath); - - // Generate context - var context = JSONUtils.encodeOutput(output); - context.page = { - num: '_PAGENUM_', - title: '_SECTION_' - }; - - // Render the theme - return Templating.renderFile(engine, 'ebook/' + filePath, context) - - // Inline css and assets - .then(function(tplOut) { - return Promise.nfcall(juice.juiceResources, tplOut.getContent(), { - webResources: { - relativeTo: outputRoot - } - }); - }); -} - -module.exports = getPDFTemplate; diff --git a/lib/output/ebook/index.js b/lib/output/ebook/index.js deleted file mode 100644 index 786a10a..0000000 --- a/lib/output/ebook/index.js +++ /dev/null @@ -1,9 +0,0 @@ -var extend = require('extend'); -var WebsiteGenerator = require('../website'); - -module.exports = extend({}, WebsiteGenerator, { - name: 'ebook', - Options: require('./options'), - onPage: require('./onPage'), - onFinish: require('./onFinish') -}); diff --git a/lib/output/ebook/onFinish.js b/lib/output/ebook/onFinish.js deleted file mode 100644 index 7f21548..0000000 --- a/lib/output/ebook/onFinish.js +++ /dev/null @@ -1,91 +0,0 @@ -var path = require('path'); - -var WebsiteGenerator = require('../website'); -var JSONUtils = require('../../json'); -var Templating = require('../../templating'); -var Promise = require('../../utils/promise'); -var error = require('../../utils/error'); -var command = require('../../utils/command'); -var writeFile = require('../helper/writeFile'); - -var getConvertOptions = require('./getConvertOptions'); -var SUMMARY_FILE = 'SUMMARY.html'; - -/** - Write the SUMMARY.html - - @param {Output} - @return {Output} -*/ -function writeSummary(output) { - var options = output.getOptions(); - var prefix = options.get('prefix'); - - var filePath = SUMMARY_FILE; - var engine = WebsiteGenerator.createTemplateEngine(output, filePath); - var context = JSONUtils.encodeOutput(output); - - // Render the theme - return Templating.renderFile(engine, prefix + '/summary.html', context) - - // Write it to the disk - .then(function(tplOut) { - return writeFile(output, filePath, tplOut.getContent()); - }); -} - -/** - Generate the ebook file as "index.pdf" - - @param {Output} - @return {Output} -*/ -function runEbookConvert(output) { - var logger = output.getLogger(); - var options = output.getOptions(); - var format = options.get('format'); - var outputFolder = output.getRoot(); - - if (!format) { - return Promise(output); - } - - 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) { - 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 - - @param {Output} - @return {Output} -*/ -function onFinish(output) { - return writeSummary(output) - .then(runEbookConvert); -} - -module.exports = onFinish; diff --git a/lib/output/ebook/onPage.js b/lib/output/ebook/onPage.js deleted file mode 100644 index b7b9b42..0000000 --- a/lib/output/ebook/onPage.js +++ /dev/null @@ -1,24 +0,0 @@ -var WebsiteGenerator = require('../website'); -var Modifiers = require('../modifiers'); - -/** - Write a page for ebook output - - @param {Output} output - @param {Output} -*/ -function onPage(output, page) { - var options = output.getOptions(); - - // Inline assets - return Modifiers.modifyHTML(page, [ - Modifiers.inlineAssets(options.get('root'), page.getFile().getPath()) - ]) - - // Write page using website generator - .then(function(resultPage) { - return WebsiteGenerator.onPage(output, resultPage); - }); -} - -module.exports = onPage; diff --git a/lib/output/ebook/options.js b/lib/output/ebook/options.js deleted file mode 100644 index ea7b8b4..0000000 --- a/lib/output/ebook/options.js +++ /dev/null @@ -1,17 +0,0 @@ -var Immutable = require('immutable'); - -var Options = Immutable.Record({ - // Root folder for the output - root: String(), - - // Prefix for generation - prefix: String('ebook'), - - // Format to generate using ebook-convert - format: String(), - - // Force use of absolute urls ("index.html" instead of "/") - directoryIndex: Boolean(false) -}); - -module.exports = Options; diff --git a/lib/output/generateAssets.js b/lib/output/generateAssets.js deleted file mode 100644 index 7a6e104..0000000 --- a/lib/output/generateAssets.js +++ /dev/null @@ -1,26 +0,0 @@ -var Promise = require('../utils/promise'); - -/** - 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); - } - - return Promise.reduce(assets, function(out, assetFile) { - logger.debug.ln('copy asset "' + assetFile + '"'); - - return generator.onAsset(out, assetFile); - }, output); -} - -module.exports = generateAssets; diff --git a/lib/output/generateBook.js b/lib/output/generateBook.js deleted file mode 100644 index 46712bd..0000000 --- a/lib/output/generateBook.js +++ /dev/null @@ -1,193 +0,0 @@ -var path = require('path'); -var Immutable = require('immutable'); - -var Output = require('../models/output'); -var Promise = require('../utils/promise'); -var fs = require('../utils/fs'); - -var callHook = require('./callHook'); -var preparePlugins = require('./preparePlugins'); -var preparePages = require('./preparePages'); -var prepareAssets = require('./prepareAssets'); -var generateAssets = require('./generateAssets'); -var generatePages = require('./generatePages'); - -/** - * 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) - .then(preparePages) - .then(prepareAssets) - - .then( - callHook.bind(null, - 'config', - function(output) { - var book = output.getBook(); - var config = book.getConfig(); - var values = config.getValues(); - - return values.toJS(); - }, - function(output, result) { - var book = output.getBook(); - var config = book.getConfig(); - - config = config.updateValues(result); - book = book.set('config', config); - return output.set('book', book); - } - ) - ) - - .then( - callHook.bind(null, - 'init', - function(output) { - return {}; - }, - function(output) { - return output; - } - ) - ) - - .then(function(output) { - if (!generator.onInit) { - return output; - } - - 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(); - 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, - options: langOptions, - state: state, - generator: generator.name, - plugins: plugins - }); - - logger.info.ln(''); - logger.info.ln('generating language "' + langBook.getLanguage() + '"'); - return processOutput(generator, langOutput); - }); - }) - - .then(callHook.bind(null, - 'finish:before', - function(output) { - return {}; - }, - function(output) { - return output; - } - ) - ) - - .then(function(output) { - if (!generator.onFinish) { - return output; - } - - return generator.onFinish(output); - }) - - .then(callHook.bind(null, - 'finish', - function(output) { - return {}; - }, - function(output) { - return 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(); - 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; - }); -} - -module.exports = generateBook; diff --git a/lib/output/generatePage.js b/lib/output/generatePage.js deleted file mode 100644 index 090a870..0000000 --- a/lib/output/generatePage.js +++ /dev/null @@ -1,79 +0,0 @@ -var path = require('path'); - -var Promise = require('../utils/promise'); -var error = require('../utils/error'); -var timing = require('../utils/timing'); - -var Templating = require('../templating'); -var JSONUtils = require('../json'); -var createTemplateEngine = require('./createTemplateEngine'); -var callPageHook = require('./callPageHook'); - -/** - * 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); - - return timing.measure( - 'page.generate', - Promise(page) - .then(function(resultPage) { - var file = resultPage.getFile(); - var filePath = file.getPath(); - var parser = file.getParser(); - var context = JSONUtils.encodeOutputWithPage(output, resultPage); - - if (!parser) { - return Promise.reject(error.FileNotParsableError({ - filename: filePath - })); - } - - // 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); - }) - - .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); - }) - - // Return new page - .then(function(content) { - return resultPage.set('content', content); - }) - - // Call final hook - .then(function(currentPage) { - return callPageHook('page', output, currentPage); - }); - }) - ); -} - -module.exports = generatePage; diff --git a/lib/output/generatePages.js b/lib/output/generatePages.js deleted file mode 100644 index 73c5c09..0000000 --- a/lib/output/generatePages.js +++ /dev/null @@ -1,36 +0,0 @@ -var Promise = require('../utils/promise'); -var generatePage = require('./generatePage'); - -/** - Output all pages using a generator - - @param {Generator} generator - @param {Output} output - @return {Promise<Output>} -*/ -function generatePages(generator, output) { - var pages = output.getPages(); - var logger = output.getLogger(); - - // Is generator ignoring assets? - if (!generator.onPage) { - return Promise(output); - } - - return Promise.reduce(pages, function(out, page) { - var file = page.getFile(); - - logger.debug.ln('generate page "' + file.getPath() + '"'); - - return generatePage(out, page) - .then(function(resultPage) { - return generator.onPage(out, resultPage); - }) - .fail(function(err) { - logger.error.ln('error while generating page "' + file.getPath() + '":'); - throw err; - }); - }, output); -} - -module.exports = generatePages; diff --git a/lib/output/getModifiers.js b/lib/output/getModifiers.js deleted file mode 100644 index bb44e80..0000000 --- a/lib/output/getModifiers.js +++ /dev/null @@ -1,73 +0,0 @@ -var Modifiers = require('./modifiers'); -var resolveFileToURL = require('./helper/resolveFileToURL'); -var Api = require('../api'); -var Plugins = require('../plugins'); -var Promise = require('../utils/promise'); -var defaultBlocks = require('../constants/defaultBlocks'); -var fileToOutput = require('./helper/fileToOutput'); - -var CODEBLOCK = 'code'; - -/** - * Return default modifier to prepare a page for - * rendering. - * - * @return {Array<Modifier>} - */ -function getModifiers(output, page) { - var book = output.getBook(); - var plugins = output.getPlugins(); - var glossary = book.getGlossary(); - var file = page.getFile(); - - // Glossary entries - var entries = glossary.getEntries(); - var glossaryFile = glossary.getFile(); - var glossaryFilename = fileToOutput(output, glossaryFile.getPath()); - - // Current file path - var currentFilePath = file.getPath(); - - // Get TemplateBlock for highlighting - var blocks = Plugins.listBlocks(plugins); - var code = blocks.get(CODEBLOCK) || defaultBlocks.get(CODEBLOCK); - - // Current context - var context = Api.encodeGlobal(output); - - return [ - // Normalize IDs on headings - Modifiers.addHeadingId, - - // Annotate text with glossary entries - Modifiers.annotateText.bind(null, entries, glossaryFilename), - - // Resolve images - Modifiers.resolveImages.bind(null, currentFilePath), - - // Resolve links (.md -> .html) - Modifiers.resolveLinks.bind(null, - currentFilePath, - resolveFileToURL.bind(null, output) - ), - - // Highlight code blocks using "code" block - Modifiers.highlightCode.bind(null, function(lang, source) { - return Promise(code.applyBlock({ - body: source, - kwargs: { - language: lang - } - }, context)) - .then(function(result) { - if (result.html === false) { - return { text: result.body }; - } else { - return { html: result.body }; - } - }); - }) - ]; -} - -module.exports = getModifiers; diff --git a/lib/output/helper/fileToOutput.js b/lib/output/helper/fileToOutput.js deleted file mode 100644 index 361c6eb..0000000 --- a/lib/output/helper/fileToOutput.js +++ /dev/null @@ -1,32 +0,0 @@ -var path = require('path'); - -var PathUtils = require('../../utils/path'); -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} - */ -function fileToOutput(output, filePath) { - var book = output.getBook(); - var readme = book.getReadme(); - var fileReadme = readme.getFile(); - - 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; diff --git a/lib/output/helper/fileToURL.js b/lib/output/helper/fileToURL.js deleted file mode 100644 index 44ad2d8..0000000 --- a/lib/output/helper/fileToURL.js +++ /dev/null @@ -1,31 +0,0 @@ -var path = require('path'); -var LocationUtils = require('../../utils/location'); - -var fileToOutput = require('./fileToOutput'); - -/** - Convert a filePath (absolute) to an url (without hostname). - It returns an absolute path. - - "README.md" -> "/" - "test/hello.md" -> "test/hello.html" - "test/README.md" -> "test/" - - @param {Output} output - @param {String} filePath - @return {String} -*/ -function fileToURL(output, filePath) { - var options = output.getOptions(); - var directoryIndex = options.get('directoryIndex'); - - filePath = fileToOutput(output, filePath); - - if (directoryIndex && path.basename(filePath) == 'index.html') { - filePath = path.dirname(filePath) + '/'; - } - - return LocationUtils.normalize(filePath); -} - -module.exports = fileToURL; diff --git a/lib/output/helper/index.js b/lib/output/helper/index.js deleted file mode 100644 index f8bc109..0000000 --- a/lib/output/helper/index.js +++ /dev/null @@ -1,2 +0,0 @@ - -module.exports = {}; diff --git a/lib/output/helper/resolveFileToURL.js b/lib/output/helper/resolveFileToURL.js deleted file mode 100644 index 3f52713..0000000 --- a/lib/output/helper/resolveFileToURL.js +++ /dev/null @@ -1,26 +0,0 @@ -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} - */ -function resolveFileToURL(output, filePath) { - // Convert /test.png -> test.png - filePath = LocationUtils.toAbsolute(filePath, '', ''); - - var page = output.getPage(filePath); - - // if file is a page, return correct .html url - if (page) { - filePath = fileToURL(output, filePath); - } - - return LocationUtils.normalize(filePath); -} - -module.exports = resolveFileToURL; diff --git a/lib/output/helper/writeFile.js b/lib/output/helper/writeFile.js deleted file mode 100644 index a6d4645..0000000 --- a/lib/output/helper/writeFile.js +++ /dev/null @@ -1,23 +0,0 @@ -var path = require('path'); -var fs = require('../../utils/fs'); - -/** - Write a file to the output folder - - @param {Output} output - @param {String} filePath - @param {Buffer|String} content - @return {Promise} -*/ -function writeFile(output, filePath, content) { - var rootFolder = output.getRoot(); - filePath = path.join(rootFolder, filePath); - - return fs.ensureFile(filePath) - .then(function() { - return fs.writeFile(filePath, content); - }) - .thenResolve(output); -} - -module.exports = writeFile; diff --git a/lib/output/index.js b/lib/output/index.js deleted file mode 100644 index 9b8ec17..0000000 --- a/lib/output/index.js +++ /dev/null @@ -1,24 +0,0 @@ -var Immutable = require('immutable'); - -var generators = Immutable.List([ - require('./json'), - require('./website'), - require('./ebook') -]); - -/** - Return a specific generator by its name - - @param {String} - @return {Generator} -*/ -function getGenerator(name) { - return generators.find(function(generator) { - return generator.name == name; - }); -} - -module.exports = { - generate: require('./generateBook'), - getGenerator: getGenerator -}; diff --git a/lib/output/json/index.js b/lib/output/json/index.js deleted file mode 100644 index 361da06..0000000 --- a/lib/output/json/index.js +++ /dev/null @@ -1,7 +0,0 @@ - -module.exports = { - name: 'json', - Options: require('./options'), - onPage: require('./onPage'), - onFinish: require('./onFinish') -}; diff --git a/lib/output/json/onFinish.js b/lib/output/json/onFinish.js deleted file mode 100644 index d41d778..0000000 --- a/lib/output/json/onFinish.js +++ /dev/null @@ -1,47 +0,0 @@ -var path = require('path'); - -var Promise = require('../../utils/promise'); -var fs = require('../../utils/fs'); -var JSONUtils = require('../../json'); - -/** - Finish the generation - - @param {Output} - @return {Output} -*/ -function onFinish(output) { - var book = output.getBook(); - var outputRoot = output.getRoot(); - - 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); - - json.languages = JSONUtils.encodeLanguages(languages); - - return json; - }) - - .then(function(json) { - return fs.writeFile( - path.resolve(outputRoot, 'README.json'), - JSON.stringify(json, null, 4) - ); - }) - - .thenResolve(output); -} - -module.exports = onFinish; diff --git a/lib/output/json/onPage.js b/lib/output/json/onPage.js deleted file mode 100644 index 2315ba0..0000000 --- a/lib/output/json/onPage.js +++ /dev/null @@ -1,43 +0,0 @@ -var JSONUtils = require('../../json'); -var PathUtils = require('../../utils/path'); -var Modifiers = require('../modifiers'); -var writeFile = require('../helper/writeFile'); -var getModifiers = require('../getModifiers'); - -var JSON_VERSION = '3'; - -/** - * 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(); - - return Modifiers.modifyHTML(page, getModifiers(output, page)) - .then(function(resultPage) { - // Generate the JSON - var json = JSONUtils.encodeBookWithPage(output.getBook(), resultPage); - - // Delete some private properties - delete json.config; - - // Specify JSON output version - json.version = JSON_VERSION; - - // File path in the output folder - var filePath = file.getPath() == readme.getPath()? 'README.json' : file.getPath(); - filePath = PathUtils.setExtension(filePath, '.json'); - - // Write it to the disk - return writeFile( - output, - filePath, - JSON.stringify(json, null, 4) - ); - }); -} - -module.exports = onPage; diff --git a/lib/output/json/options.js b/lib/output/json/options.js deleted file mode 100644 index 79167b1..0000000 --- a/lib/output/json/options.js +++ /dev/null @@ -1,8 +0,0 @@ -var Immutable = require('immutable'); - -var Options = Immutable.Record({ - // Root folder for the output - root: String() -}); - -module.exports = Options; diff --git a/lib/output/modifiers/__tests__/addHeadingId.js b/lib/output/modifiers/__tests__/addHeadingId.js deleted file mode 100644 index a3b1d81..0000000 --- a/lib/output/modifiers/__tests__/addHeadingId.js +++ /dev/null @@ -1,26 +0,0 @@ -var cheerio = require('cheerio'); -var addHeadingId = require('../addHeadingId'); - -describe('addHeadingId', function() { - it('should add an ID if none', function() { - var $ = cheerio.load('<h1>Hello World</h1><h2>Cool !!</h2>'); - - return addHeadingId($) - .then(function() { - var html = $.html(); - expect(html).toBe('<h1 id="hello-world">Hello World</h1><h2 id="cool-">Cool !!</h2>'); - }); - }); - - it('should not change existing IDs', function() { - var $ = cheerio.load('<h1 id="awesome">Hello World</h1>'); - - return addHeadingId($) - .then(function() { - var html = $.html(); - expect(html).toBe('<h1 id="awesome">Hello World</h1>'); - }); - }); -}); - - diff --git a/lib/output/modifiers/__tests__/annotateText.js b/lib/output/modifiers/__tests__/annotateText.js deleted file mode 100644 index 67e7a10..0000000 --- a/lib/output/modifiers/__tests__/annotateText.js +++ /dev/null @@ -1,46 +0,0 @@ -var Immutable = require('immutable'); -var cheerio = require('cheerio'); -var GlossaryEntry = require('../../../models/glossaryEntry'); -var annotateText = require('../annotateText'); - -describe('annotateText', function() { - var entries = Immutable.List([ - GlossaryEntry({ name: 'Word' }), - GlossaryEntry({ name: 'Multiple Words' }) - ]); - - it('should annotate text', function() { - var $ = cheerio.load('<p>This is a word, and multiple words</p>'); - - annotateText(entries, 'GLOSSARY.md', $); - - var links = $('a'); - expect(links.length).toBe(2); - - var word = $(links.get(0)); - expect(word.attr('href')).toBe('/GLOSSARY.md#word'); - expect(word.text()).toBe('word'); - expect(word.hasClass('glossary-term')).toBeTruthy(); - - var words = $(links.get(1)); - expect(words.attr('href')).toBe('/GLOSSARY.md#multiple-words'); - expect(words.text()).toBe('multiple words'); - expect(words.hasClass('glossary-term')).toBeTruthy(); - }); - - it('should not annotate scripts', function() { - var $ = cheerio.load('<script>This is a word, and multiple words</script>'); - - annotateText(entries, 'GLOSSARY.md', $); - expect($('a').length).toBe(0); - }); - - it('should not annotate when has class "no-glossary"', function() { - var $ = cheerio.load('<p class="no-glossary">This is a word, and multiple words</p>'); - - annotateText(entries, 'GLOSSARY.md', $); - expect($('a').length).toBe(0); - }); -}); - - diff --git a/lib/output/modifiers/__tests__/fetchRemoteImages.js b/lib/output/modifiers/__tests__/fetchRemoteImages.js deleted file mode 100644 index bc1704d..0000000 --- a/lib/output/modifiers/__tests__/fetchRemoteImages.js +++ /dev/null @@ -1,40 +0,0 @@ -var cheerio = require('cheerio'); -var tmp = require('tmp'); -var path = require('path'); - -var URL = 'https://upload.wikimedia.org/wikipedia/commons/thumb/4/47/PNG_transparency_demonstration_1.png/280px-PNG_transparency_demonstration_1.png'; - -describe('fetchRemoteImages', function() { - var dir; - var fetchRemoteImages = require('../fetchRemoteImages'); - - beforeEach(function() { - dir = tmp.dirSync(); - }); - - it('should download image file', function() { - var $ = cheerio.load('<img src="' + URL + '" />'); - - return fetchRemoteImages(dir.name, 'index.html', $) - .then(function() { - var $img = $('img'); - var src = $img.attr('src'); - - expect(dir.name).toHaveFile(src); - }); - }); - - it('should download image file and replace with relative path', function() { - var $ = cheerio.load('<img src="' + URL + '" />'); - - return fetchRemoteImages(dir.name, 'test/index.html', $) - .then(function() { - var $img = $('img'); - var src = $img.attr('src'); - - expect(dir.name).toHaveFile(path.join('test', src)); - }); - }); -}); - - diff --git a/lib/output/modifiers/__tests__/highlightCode.js b/lib/output/modifiers/__tests__/highlightCode.js deleted file mode 100644 index 75d9902..0000000 --- a/lib/output/modifiers/__tests__/highlightCode.js +++ /dev/null @@ -1,60 +0,0 @@ -var cheerio = require('cheerio'); -var Promise = require('../../../utils/promise'); -var highlightCode = require('../highlightCode'); - -describe('highlightCode', function() { - function doHighlight(lang, code) { - return { - text: '' + (lang || '') + '$' + code - }; - } - - function doHighlightAsync(lang, code) { - return Promise() - .then(function() { - return doHighlight(lang, code); - }); - } - - it('should call it for normal code element', function() { - var $ = cheerio.load('<p>This is a <code>test</code></p>'); - - return highlightCode(doHighlight, $) - .then(function() { - var $code = $('code'); - expect($code.text()).toBe('$test'); - }); - }); - - it('should call it for markdown code block', function() { - var $ = cheerio.load('<pre><code class="lang-js">test</code></pre>'); - - return highlightCode(doHighlight, $) - .then(function() { - var $code = $('code'); - expect($code.text()).toBe('js$test'); - }); - }); - - it('should call it for asciidoc code block', function() { - var $ = cheerio.load('<pre><code class="language-python">test</code></pre>'); - - return highlightCode(doHighlight, $) - .then(function() { - var $code = $('code'); - expect($code.text()).toBe('python$test'); - }); - }); - - it('should accept async highlighter', function() { - var $ = cheerio.load('<pre><code class="language-python">test</code></pre>'); - - return highlightCode(doHighlightAsync, $) - .then(function() { - var $code = $('code'); - expect($code.text()).toBe('python$test'); - }); - }); -}); - - diff --git a/lib/output/modifiers/__tests__/inlinePng.js b/lib/output/modifiers/__tests__/inlinePng.js deleted file mode 100644 index 0073cff..0000000 --- a/lib/output/modifiers/__tests__/inlinePng.js +++ /dev/null @@ -1,25 +0,0 @@ -var cheerio = require('cheerio'); -var tmp = require('tmp'); -var inlinePng = require('../inlinePng'); - -describe('inlinePng', function() { - var dir; - - beforeEach(function() { - dir = tmp.dirSync(); - }); - - it('should write an inline PNG using data URI as a file', function() { - var $ = cheerio.load('<img alt="GitBook Logo 20x20" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUEAYAAADdGcFOAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAACXBIWXMAAAsTAAALEwEAmpwYAAABWWlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNS40LjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyI+CiAgICAgICAgIDx0aWZmOk9yaWVudGF0aW9uPjE8L3RpZmY6T3JpZW50YXRpb24+CiAgICAgIDwvcmRmOkRlc2NyaXB0aW9uPgogICA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgpMwidZAAAF+klEQVRIDY3Wf5CVVR3H8c9z791fyI9dQwdQ4TTI7wEWnQZZAa/mJE4Z0OaKUuN1KoaykZxUGGHay+iIVFMoEYrUPhDCKEKW2ChT8dA0RCSxWi6EW3sYYpcfxq5C+4O9957O+7m7O/qHQ9/XzH1+nHuec57z8wkWTsKw0y6N/LxXN6KzTnEUHi8eP/l3YStSU/MdsYvBbGh8six2YXcbcgc++QkfTQkWz/81KtqDA0hlUoWnsX+5uxe5X365BB9my2bjrHNHccLk16BpS9CExjcmXMDbD6wehdyEjxbjz1uK1zn9qga6dcfnMLXeXY/qjuQqTF4W1MKke8ZgeNhjMCxMPIWSd4OF78C55CFI/1kF6WwXpMqjkAZ/CKniNDrCsmU4lE1YbPlgR2x7R39FF23D4mq3A1+Z35PGTNs1E1XhxcGQOh6HNPwXkK56BVJhOaRg/pvoHXNxHFw410B25EYE2RMvI0i/twFJvXcrFObykEa+DmnQGLwYqR0l2a6JqItaj8C/4E2QxtZCofkC8tF1t8HZc/fAZaLnIF2xEsoEtW1w7vBSSFtfhDTnCki9cSi81Ain1uko2Ld+Dmf2rkUq0/5t+PYbFtPQdkjzNiAXTWtDEF49FgkzJInAVPwNyhzcDOmrdZCm/Rn+ebWtcPs+/U24hmg2XL0rRkPPELh9R8fDtXR2oC/VuZbGaci79Ajkb6lZgfyYtyzy/X9s6T/pO/ZfN/RdNxxIwTWM2wbX8KVmuIaEqmKm6zEondwGpd0SyOy5DrJ//TFkX9kMhd3XQHbEVCSsm4OECV5HIv2p15CwfWPSntoHRbv2Q1HzSvSlSqZwATIuBxk/zZBOBbdB+u9hSKU3Q7pwAjInZkFm6U8hu7MSMqe/Dqn8fUj5GVCmpxK+4N/F1LMa0p5eSOPqIPP7NGSunAI/+R6GnzQzIBt8A1LC/QZ+6HwLst1rITv0n5CtXgSZ78yFTNkR+FdeDZneJkip3fAtsQ5Scilkek7CH9dAmjIWvkK7IXXOh6/IzZDNPQdZXR1TQmdjKv0ZfEu0YKDpNflpyG5aDtnRv8VAuu3dBV+huyBbvgdS97tQNLQc0mfugKy5Cb4BipPIXvsUpK5N8Mvao/Bd3QDZRH9Rrtj3Cl6FHwPFMLmNkKrj8BnHoT+XX6f2wl+XxFS4Ab7C72Dgf7bi+5DpTkNm8kQMpCs/BzIlz8LfPxnzLdh3EjwMX4GX4Ju4GNb9A1L7k/D3J8b6kv2LFCtmCmcgUzoJsr2z4MfwFsh87xikZefg188fYaAhpPUxm3ge/vFnYkoED0HqeQiyJYcwkNGWnoNv6s9C1p1Bf/389VYoCjohW7UfMms3wXdpBv7+FEiPLIHs4DIMNERUNhbSpY3wk6QOsqlCDVx2xCrInMpBmfNPQOnzKxBkkrugdOl9GKigSZZCUWIm/GqwDtLUI5D+WAOlb9wKP0YvQLbjZSjsaYaL/n0/FA3fDtnCGihK5UYjCK+ZDr+TDIKLdm2Fs1UOzo76F5wO74XSZj0S6d7RCMLkCshcXALZxaWQRjXDZQ62oRAdCeG/Ju5HELX2QFH3C0hkRy6GovyfwF58AoVbguOxyB2H7/I34Gf11yANnQSp7Vr4MbQH0vg7kbNNp5AM3UrIVDchnz56B1Jm573wW9gZSFVPwO/hefg5FsIvN09CchtQCIOFw/F5U8ii3CZn4cqo7C8YlXEPYkx9cacZl00+iwnprrtwVdj1Q/gXmAs/pu6LZc9XQOGgSvh19n2cDZN341g2EcfxTEGwH/RewqlMsUfbbWIGLjUG+j/j9nokD1beiOvLS5dhjr30Gu6ZnivgdtM/6VJvY1+6pBHbH+h9CX84vfMxNJtisYVFlys+WNCIZJNmIsjohlhNSQC3f8R55H+y/hjkN8GPR9ndCLJxT4/3n0Px51ay8XQnNrYfDJHf//Fc0oMrEZSeeQGJ7+Z+gKCgLbHNWgXnB9FlYt5JaN38JIINC95EakjtAqQeuUx21c5B6tEFf0fSfbEFQf28Z6D6y+X/H0jf40QQJhYwAAAAAElFTkSuQmCC"/>'); - - return inlinePng(dir.name, 'index.html', $) - .then(function() { - var $img = $('img'); - var src = $img.attr('src'); - - expect(dir.name).toHaveFile(src); - }); - }); -}); - - diff --git a/lib/output/modifiers/__tests__/resolveLinks.js b/lib/output/modifiers/__tests__/resolveLinks.js deleted file mode 100644 index 8904c11..0000000 --- a/lib/output/modifiers/__tests__/resolveLinks.js +++ /dev/null @@ -1,104 +0,0 @@ -var path = require('path'); -var cheerio = require('cheerio'); -var resolveLinks = require('../resolveLinks'); - -describe('resolveLinks', function() { - function resolveFileBasic(href) { - return 'fakeDir/' + href; - } - - function resolveFileCustom(href) { - if (path.extname(href) == '.md') { - return href.slice(0, -3) + '.html'; - } - - return href; - } - - describe('Absolute path', function() { - var TEST = '<p>This is a <a href="/test/cool.md"></a></p>'; - - it('should resolve path starting by "/" in root directory', function() { - var $ = cheerio.load(TEST); - - return resolveLinks('hello.md', resolveFileBasic, $) - .then(function() { - var link = $('a'); - expect(link.attr('href')).toBe('fakeDir/test/cool.md'); - }); - }); - - it('should resolve path starting by "/" in child directory', function() { - var $ = cheerio.load(TEST); - - return resolveLinks('afolder/hello.md', resolveFileBasic, $) - .then(function() { - var link = $('a'); - expect(link.attr('href')).toBe('../fakeDir/test/cool.md'); - }); - }); - }); - - describe('Anchor', function() { - it('should prevent anchors in resolution', function() { - var TEST = '<p>This is a <a href="test/cool.md#an-anchor"></a></p>'; - var $ = cheerio.load(TEST); - - return resolveLinks('hello.md', resolveFileCustom, $) - .then(function() { - var link = $('a'); - expect(link.attr('href')).toBe('test/cool.html#an-anchor'); - }); - }); - - it('should ignore pure anchor links', function() { - var TEST = '<p>This is a <a href="#an-anchor"></a></p>'; - var $ = cheerio.load(TEST); - - return resolveLinks('hello.md', resolveFileCustom, $) - .then(function() { - var link = $('a'); - expect(link.attr('href')).toBe('#an-anchor'); - }); - }); - }); - - describe('Custom Resolver', function() { - var TEST = '<p>This is a <a href="/test/cool.md"></a> <a href="afile.png"></a></p>'; - - it('should resolve path correctly for absolute path', function() { - var $ = cheerio.load(TEST); - - return resolveLinks('hello.md', resolveFileCustom, $) - .then(function() { - var link = $('a').first(); - expect(link.attr('href')).toBe('test/cool.html'); - }); - }); - - it('should resolve path correctly for absolute path (2)', function() { - var $ = cheerio.load(TEST); - - return resolveLinks('afodler/hello.md', resolveFileCustom, $) - .then(function() { - var link = $('a').first(); - expect(link.attr('href')).toBe('../test/cool.html'); - }); - }); - }); - - describe('External link', function() { - var TEST = '<p>This is a <a href="http://www.github.com">external link</a></p>'; - - it('should have target="_blank" attribute', function() { - var $ = cheerio.load(TEST); - - return resolveLinks('hello.md', resolveFileBasic, $) - .then(function() { - var link = $('a'); - expect(link.attr('target')).toBe('_blank'); - }); - }); - }); - -}); diff --git a/lib/output/modifiers/__tests__/svgToImg.js b/lib/output/modifiers/__tests__/svgToImg.js deleted file mode 100644 index 5fe9796..0000000 --- a/lib/output/modifiers/__tests__/svgToImg.js +++ /dev/null @@ -1,25 +0,0 @@ -var cheerio = require('cheerio'); -var tmp = require('tmp'); - -describe('svgToImg', function() { - var dir; - var svgToImg = require('../svgToImg'); - - beforeEach(function() { - dir = tmp.dirSync(); - }); - - it('should write svg as a file', function() { - var $ = cheerio.load('<svg xmlns="http://www.w3.org/2000/svg" width="200" height="100" version="1.1"><rect width="200" height="100" stroke="black" stroke-width="6" fill="green"/></svg>'); - - return svgToImg(dir.name, 'index.html', $) - .then(function() { - var $img = $('img'); - var src = $img.attr('src'); - - expect(dir.name).toHaveFile(src); - }); - }); -}); - - diff --git a/lib/output/modifiers/__tests__/svgToPng.js b/lib/output/modifiers/__tests__/svgToPng.js deleted file mode 100644 index dbb3502..0000000 --- a/lib/output/modifiers/__tests__/svgToPng.js +++ /dev/null @@ -1,33 +0,0 @@ -var cheerio = require('cheerio'); -var tmp = require('tmp'); -var path = require('path'); - -var svgToImg = require('../svgToImg'); -var svgToPng = require('../svgToPng'); - -describe('svgToPng', function() { - var dir; - - beforeEach(function() { - dir = tmp.dirSync(); - }); - - it('should write svg as png file', function() { - var $ = cheerio.load('<svg xmlns="http://www.w3.org/2000/svg" width="200" height="100" version="1.1"><rect width="200" height="100" stroke="black" stroke-width="6" fill="green"/></svg>'); - var fileName = 'index.html'; - - return svgToImg(dir.name, fileName, $) - .then(function() { - return svgToPng(dir.name, fileName, $); - }) - .then(function() { - var $img = $('img'); - var src = $img.attr('src'); - - expect(dir.name).toHaveFile(src); - expect(path.extname(src)).toBe('.png'); - }); - }); -}); - - diff --git a/lib/output/modifiers/addHeadingId.js b/lib/output/modifiers/addHeadingId.js deleted file mode 100644 index e2e2720..0000000 --- a/lib/output/modifiers/addHeadingId.js +++ /dev/null @@ -1,23 +0,0 @@ -var slug = require('github-slugid'); -var editHTMLElement = require('./editHTMLElement'); - -/** - Add ID to an heading - - @param {HTMLElement} heading -*/ -function addId(heading) { - if (heading.attr('id')) return; - heading.attr('id', slug(heading.text())); -} - -/** - Add ID to all headings - - @param {HTMLDom} $ -*/ -function addHeadingId($) { - return editHTMLElement($, 'h1,h2,h3,h4,h5,h6', addId); -} - -module.exports = addHeadingId; diff --git a/lib/output/modifiers/annotateText.js b/lib/output/modifiers/annotateText.js deleted file mode 100644 index 490c228..0000000 --- a/lib/output/modifiers/annotateText.js +++ /dev/null @@ -1,94 +0,0 @@ -var escape = require('escape-html'); - -// Selector to ignore -var ANNOTATION_IGNORE = '.no-glossary,code,pre,a,script,h1,h2,h3,h4,h5,h6'; - -function pregQuote( str ) { - return (str+'').replace(/([\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g, '\\$1'); -} - -function replaceText($, el, search, replace, text_only ) { - return $(el).each(function(){ - var node = this.firstChild, - val, - new_val, - - // Elements to be removed at the end. - remove = []; - - // Only continue if firstChild exists. - if ( node ) { - - // Loop over all childNodes. - while (node) { - - // Only process text nodes. - if ( node.nodeType === 3 ) { - - // The original node value. - val = node.nodeValue; - - // The new value. - new_val = val.replace( search, replace ); - - // Only replace text if the new value is actually different! - if ( new_val !== val ) { - - if ( !text_only && /</.test( new_val ) ) { - // The new value contains HTML, set it in a slower but far more - // robust way. - $(node).before( new_val ); - - // Don't remove the node yet, or the loop will lose its place. - remove.push( node ); - } else { - // The new value contains no HTML, so it can be set in this - // very fast, simple way. - node.nodeValue = new_val; - } - } - } - - node = node.nextSibling; - } - } - - // Time to remove those elements! - if (remove.length) $(remove).remove(); - }); -} - -/** - * 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 description = entry.getDescription(); - var searchRegex = new RegExp( '\\b(' + pregQuote(name.toLowerCase()) + ')\\b' , 'gi' ); - - $('*').each(function() { - var $this = $(this); - - if ( - $this.is(ANNOTATION_IGNORE) || - $this.parents(ANNOTATION_IGNORE).length > 0 - ) return; - - replaceText($, this, searchRegex, function(match) { - return '<a href="/' + glossaryFilePath + '#' + entryId + '" ' - + 'class="glossary-term" title="' + escape(description) + '">' - + match - + '</a>'; - }); - }); - - }); -} - -module.exports = annotateText; diff --git a/lib/output/modifiers/editHTMLElement.js b/lib/output/modifiers/editHTMLElement.js deleted file mode 100644 index 755598e..0000000 --- a/lib/output/modifiers/editHTMLElement.js +++ /dev/null @@ -1,15 +0,0 @@ -var Promise = require('../../utils/promise'); - -/** - Edit all elements matching a selector -*/ -function editHTMLElement($, selector, fn) { - var $elements = $(selector); - - return Promise.forEach($elements, function(el) { - var $el = $(el); - return fn($el); - }); -} - -module.exports = editHTMLElement; diff --git a/lib/output/modifiers/fetchRemoteImages.js b/lib/output/modifiers/fetchRemoteImages.js deleted file mode 100644 index ef868b9..0000000 --- a/lib/output/modifiers/fetchRemoteImages.js +++ /dev/null @@ -1,44 +0,0 @@ -var path = require('path'); -var crc = require('crc'); - -var editHTMLElement = require('./editHTMLElement'); -var fs = require('../../utils/fs'); -var LocationUtils = require('../../utils/location'); - -/** - Fetch all remote images - - @param {String} rootFolder - @param {String} currentFile - @param {HTMLDom} $ - @return {Promise} -*/ -function fetchRemoteImages(rootFolder, currentFile, $) { - var currentDirectory = path.dirname(currentFile); - - return editHTMLElement($, 'img', function($img) { - var src = $img.attr('src'); - var extension = path.extname(src); - - if (!LocationUtils.isExternal(src)) { - return; - } - - // 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 + '" />'); - }); - }); -} - -module.exports = fetchRemoteImages; diff --git a/lib/output/modifiers/highlightCode.js b/lib/output/modifiers/highlightCode.js deleted file mode 100644 index 5d397bb..0000000 --- a/lib/output/modifiers/highlightCode.js +++ /dev/null @@ -1,58 +0,0 @@ -var is = require('is'); -var Immutable = require('immutable'); - -var Promise = require('../../utils/promise'); -var editHTMLElement = require('./editHTMLElement'); - -/** - Return language for a code blocks from a list of class names - - @param {Array<String>} - @return {String} -*/ -function getLanguageForClass(classNames) { - return Immutable.List(classNames) - .map(function(cl) { - // Markdown - if (cl.search('lang-') === 0) { - return cl.slice('lang-'.length); - } - - // Asciidoc - if (cl.search('language-') === 0) { - return cl.slice('language-'.length); - } - - return null; - }) - .find(function(cl) { - return Boolean(cl); - }); -} - - -/** - Highlight all code elements - - @param {Function(lang, body) -> String} highlight - @param {HTMLDom} $ - @return {Promise} -*/ -function highlightCode(highlight, $) { - return editHTMLElement($, 'code', function($code) { - var classNames = ($code.attr('class') || '').split(' '); - var lang = getLanguageForClass(classNames); - var source = $code.text(); - - return Promise(highlight(lang, source)) - .then(function(r) { - if (is.string(r.html)) { - $code.html(r.html); - } else { - $code.text(r.text); - } - }); - }); -} - -module.exports = highlightCode; diff --git a/lib/output/modifiers/index.js b/lib/output/modifiers/index.js deleted file mode 100644 index f1daa2b..0000000 --- a/lib/output/modifiers/index.js +++ /dev/null @@ -1,15 +0,0 @@ - -module.exports = { - modifyHTML: require('./modifyHTML'), - inlineAssets: require('./inlineAssets'), - - // HTML transformations - addHeadingId: require('./addHeadingId'), - svgToImg: require('./svgToImg'), - fetchRemoteImages: require('./fetchRemoteImages'), - svgToPng: require('./svgToPng'), - resolveLinks: require('./resolveLinks'), - resolveImages: require('./resolveImages'), - annotateText: require('./annotateText'), - highlightCode: require('./highlightCode') -}; diff --git a/lib/output/modifiers/inlineAssets.js b/lib/output/modifiers/inlineAssets.js deleted file mode 100644 index 7cd874b..0000000 --- a/lib/output/modifiers/inlineAssets.js +++ /dev/null @@ -1,29 +0,0 @@ -var svgToImg = require('./svgToImg'); -var svgToPng = require('./svgToPng'); -var inlinePng = require('./inlinePng'); -var resolveImages = require('./resolveImages'); -var fetchRemoteImages = require('./fetchRemoteImages'); - -var Promise = require('../../utils/promise'); - -/** - Inline all assets in a page - - @param {String} rootFolder -*/ -function inlineAssets(rootFolder, currentFile) { - return function($) { - return Promise() - - // Resolving images and fetching external images should be - // done before svg conversion - .then(resolveImages.bind(null, currentFile, $)) - .then(fetchRemoteImages.bind(null, rootFolder, currentFile, $)) - - .then(svgToImg.bind(null, rootFolder, currentFile, $)) - .then(svgToPng.bind(null, rootFolder, currentFile, $)) - .then(inlinePng.bind(null, rootFolder, currentFile, $)); - }; -} - -module.exports = inlineAssets; diff --git a/lib/output/modifiers/inlinePng.js b/lib/output/modifiers/inlinePng.js deleted file mode 100644 index 161f164..0000000 --- a/lib/output/modifiers/inlinePng.js +++ /dev/null @@ -1,47 +0,0 @@ -var crc = require('crc'); -var path = require('path'); - -var imagesUtil = require('../../utils/images'); -var fs = require('../../utils/fs'); -var LocationUtils = require('../../utils/location'); - -var editHTMLElement = require('./editHTMLElement'); - -/** - Convert all inline PNG images to PNG file - - @param {String} rootFolder - @param {HTMLDom} $ - @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'; - - // 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); - }); - }); -} - - -module.exports = inlinePng; diff --git a/lib/output/modifiers/modifyHTML.js b/lib/output/modifiers/modifyHTML.js deleted file mode 100644 index cd3d6e5..0000000 --- a/lib/output/modifiers/modifyHTML.js +++ /dev/null @@ -1,25 +0,0 @@ -var cheerio = require('cheerio'); -var Promise = require('../../utils/promise'); - -/** - Apply a list of operations to a page and - output the new page. - - @param {Page} - @param {List|Array<Transformation>} - @return {Promise<Page>} -*/ -function modifyHTML(page, operations) { - var html = page.getContent(); - var $ = cheerio.load(html); - - return Promise.forEach(operations, function(op) { - return op($); - }) - .then(function() { - var resultHTML = $.html(); - return page.set('content', resultHTML); - }); -} - -module.exports = modifyHTML; diff --git a/lib/output/modifiers/resolveImages.js b/lib/output/modifiers/resolveImages.js deleted file mode 100644 index cc25cfa..0000000 --- a/lib/output/modifiers/resolveImages.js +++ /dev/null @@ -1,33 +0,0 @@ -var path = require('path'); - -var LocationUtils = require('../../utils/location'); -var editHTMLElement = require('./editHTMLElement'); - -/** - Resolve all HTML images: - - /test.png in hello -> ../test.html - - @param {String} currentFile - @param {HTMLDom} $ -*/ -function resolveImages(currentFile, $) { - var currentDirectory = path.dirname(currentFile); - - return editHTMLElement($, 'img', function($img) { - var src = $img.attr('src'); - - if (LocationUtils.isExternal(src) || LocationUtils.isDataURI(src)) { - return; - } - - // Calcul absolute path for this - src = LocationUtils.toAbsolute(src, currentDirectory, '.'); - - // Convert back to relative - src = LocationUtils.relative(currentDirectory, src); - - $img.attr('src', src); - }); -} - -module.exports = resolveImages; diff --git a/lib/output/modifiers/resolveLinks.js b/lib/output/modifiers/resolveLinks.js deleted file mode 100644 index 9d15e5e..0000000 --- a/lib/output/modifiers/resolveLinks.js +++ /dev/null @@ -1,53 +0,0 @@ -var path = require('path'); -var url = require('url'); - -var LocationUtils = require('../../utils/location'); -var editHTMLElement = require('./editHTMLElement'); - -/** - Resolve all HTML links: - - /test.md in hello -> ../test.html - - @param {String} currentFile - @param {Function(String) -> String} resolveFile - @param {HTMLDom} $ -*/ -function resolveLinks(currentFile, resolveFile, $) { - var currentDirectory = path.dirname(currentFile); - - return editHTMLElement($, 'a', function($a) { - var href = $a.attr('href'); - - // Don't change a tag without href - if (!href) { - return; - } - - if (LocationUtils.isExternal(href)) { - $a.attr('target', '_blank'); - return; - } - - // Split anchor - var parsed = url.parse(href); - href = parsed.pathname || ''; - - if (href) { - // Calcul absolute path for this - href = LocationUtils.toAbsolute(href, currentDirectory, '.'); - - // Resolve file - href = resolveFile(href); - - // Convert back to relative - href = LocationUtils.relative(currentDirectory, href); - } - - // Add back anchor - href = href + (parsed.hash || ''); - - $a.attr('href', href); - }); -} - -module.exports = resolveLinks; diff --git a/lib/output/modifiers/svgToImg.js b/lib/output/modifiers/svgToImg.js deleted file mode 100644 index f31b06d..0000000 --- a/lib/output/modifiers/svgToImg.js +++ /dev/null @@ -1,56 +0,0 @@ -var path = require('path'); -var crc = require('crc'); -var domSerializer = require('dom-serializer'); - -var editHTMLElement = require('./editHTMLElement'); -var fs = require('../../utils/fs'); -var LocationUtils = require('../../utils/location'); - -/** - Render a cheerio DOM as html - - @param {HTMLDom} $ - @param {HTMLElement} dom - @param {Object} - @return {String} -*/ -function renderDOM($, dom, options) { - if (!dom && $._root && $._root.children) { - dom = $._root.children; - } - options = options|| dom.options || $._options; - return domSerializer(dom, options); -} - -/** - Replace SVG tag by IMG - - @param {String} baseFolder - @param {HTMLDom} $ -*/ -function svgToImg(baseFolder, currentFile, $) { - var currentDirectory = path.dirname(currentFile); - - return editHTMLElement($, 'svg', function($svg) { - var content = '<?xml version="1.0" encoding="UTF-8"?>' + - renderDOM($, $svg); - - // We avoid generating twice the same PNG - var hash = crc.crc32(content).toString(16); - var fileName = hash + '.svg'; - var filePath = path.join(baseFolder, fileName); - - // Write the svg to the file - return fs.assertFile(filePath, function() { - return fs.writeFile(filePath, content, 'utf8'); - }) - - // Return as image - .then(function() { - var src = LocationUtils.relative(currentDirectory, fileName); - $svg.replaceWith('<img src="' + src + '" />'); - }); - }); -} - -module.exports = svgToImg; diff --git a/lib/output/modifiers/svgToPng.js b/lib/output/modifiers/svgToPng.js deleted file mode 100644 index 1093106..0000000 --- a/lib/output/modifiers/svgToPng.js +++ /dev/null @@ -1,53 +0,0 @@ -var crc = require('crc'); -var path = require('path'); - -var imagesUtil = require('../../utils/images'); -var fs = require('../../utils/fs'); -var LocationUtils = require('../../utils/location'); - -var editHTMLElement = require('./editHTMLElement'); - -/** - Convert all SVG images to PNG - - @param {String} rootFolder - @param {HTMLDom} $ - @return {Promise} -*/ -function svgToPng(rootFolder, currentFile, $) { - var currentDirectory = path.dirname(currentFile); - - return editHTMLElement($, 'img', function($img) { - var src = $img.attr('src'); - if (path.extname(src) !== '.svg') { - return; - } - - // Calcul absolute path for this - src = LocationUtils.toAbsolute(src, currentDirectory, '.'); - - // We avoid generating twice the same PNG - var hash = crc.crc32(src).toString(16); - var fileName = hash + '.png'; - - // Input file path - var inputPath = path.join(rootFolder, src); - - // Result file path - var filePath = path.join(rootFolder, fileName); - - return fs.assertFile(filePath, function() { - return imagesUtil.convertSVGToPNG(inputPath, filePath); - }) - .then(function() { - // Convert filename to a relative filename - fileName = LocationUtils.relative(currentDirectory, fileName); - - // Replace src - $img.attr('src', fileName); - }); - }); -} - - -module.exports = svgToPng; diff --git a/lib/output/prepareAssets.js b/lib/output/prepareAssets.js deleted file mode 100644 index ae9b55a..0000000 --- a/lib/output/prepareAssets.js +++ /dev/null @@ -1,22 +0,0 @@ -var Parse = require('../parse'); - -/** - List all assets in the book - - @param {Output} - @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); - }); -} - -module.exports = prepareAssets; diff --git a/lib/output/preparePages.js b/lib/output/preparePages.js deleted file mode 100644 index 83944ed..0000000 --- a/lib/output/preparePages.js +++ /dev/null @@ -1,26 +0,0 @@ -var Parse = require('../parse'); -var Promise = require('../utils/promise'); - -/** - List and prepare all pages - - @param {Output} - @return {Promise<Output>} -*/ -function preparePages(output) { - 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); - }); -} - -module.exports = preparePages; diff --git a/lib/output/preparePlugins.js b/lib/output/preparePlugins.js deleted file mode 100644 index 5c4be93..0000000 --- a/lib/output/preparePlugins.js +++ /dev/null @@ -1,36 +0,0 @@ -var Plugins = require('../plugins'); -var Promise = require('../utils/promise'); - -/** - * Load and setup plugins - * - * @param {Output} - * @return {Promise<Output>} - */ -function preparePlugins(output) { - var book = output.getBook(); - - return Promise() - - // Only load plugins for main book - .then(function() { - if (book.isLanguageBook()) { - return output.getPlugins(); - } else { - return Plugins.loadForBook(book); - } - }) - - // Update book's configuration using the plugins - .then(function(plugins) { - return Plugins.validateConfig(book, plugins) - .then(function(newBook) { - return output.merge({ - book: newBook, - plugins: plugins - }); - }); - }); -} - -module.exports = preparePlugins; diff --git a/lib/output/website/__tests__/i18n.js b/lib/output/website/__tests__/i18n.js deleted file mode 100644 index fd610fb..0000000 --- a/lib/output/website/__tests__/i18n.js +++ /dev/null @@ -1,38 +0,0 @@ -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/copyPluginAssets.js b/lib/output/website/copyPluginAssets.js deleted file mode 100644 index 9150636..0000000 --- a/lib/output/website/copyPluginAssets.js +++ /dev/null @@ -1,117 +0,0 @@ -var path = require('path'); - -var ASSET_FOLDER = require('../../constants/pluginAssetsFolder'); -var Promise = require('../../utils/promise'); -var fs = require('../../utils/fs'); - -/** - Copy all assets from plugins. - Assets are files stored in "_assets" - nd resources declared in the plugin itself. - - @param {Output} - @return {Promise} -*/ -function copyPluginAssets(output) { - var book = output.getBook(); - - // Don't copy plugins assets for language book - // It'll be resolved to the parent folder - if (book.isLanguageBook()) { - return Promise(output); - } - - var plugins = output.getPlugins() - - // We reverse the order of plugins to copy - // so that first plugins can replace assets from other plugins. - .reverse(); - - return Promise.forEach(plugins, function(plugin) { - return copyAssets(output, plugin) - .then(function() { - return copyResources(output, plugin); - }); - }) - .thenResolve(output); -} - -/** - Copy assets from a plugin - - @param {Plugin} - @return {Promise} -*/ -function copyAssets(output, plugin) { - var logger = output.getLogger(); - var pluginRoot = plugin.getPath(); - var options = output.getOptions(); - - var outputRoot = options.get('root'); - var assetOutputFolder = path.join(outputRoot, 'gitbook'); - var prefix = options.get('prefix'); - - var assetFolder = path.join(pluginRoot, ASSET_FOLDER, prefix); - - if (!fs.existsSync(assetFolder)) { - return Promise(); - } - - logger.debug.ln('copy assets from theme', assetFolder); - return fs.copyDir( - assetFolder, - assetOutputFolder, - { - deleteFirst: false, - overwrite: true, - confirm: true - } - ); -} - -/** - Copy resources from a plugin - - @param {Plugin} - @return {Promise} -*/ -function copyResources(output, plugin) { - var logger = output.getLogger(); - - var options = output.getOptions(); - var outputRoot = options.get('root'); - - var state = output.getState(); - var resources = state.getResources(); - - var pluginRoot = plugin.getPath(); - var pluginResources = resources.get(plugin.getName()); - - var assetsFolder = pluginResources.get('assets'); - var assetOutputFolder = path.join(outputRoot, 'gitbook', plugin.getNpmID()); - - if (!assetsFolder) { - return Promise(); - } - - // Resolve assets folder - assetsFolder = path.resolve(pluginRoot, assetsFolder); - if (!fs.existsSync(assetsFolder)) { - logger.warn.ln('assets folder for plugin "' + plugin.getName() + '" doesn\'t exist'); - return Promise(); - } - - logger.debug.ln('copy resources from plugin', assetsFolder); - - return fs.copyDir( - assetsFolder, - assetOutputFolder, - { - deleteFirst: false, - overwrite: true, - confirm: true - } - ); -} - -module.exports = copyPluginAssets; diff --git a/lib/output/website/createTemplateEngine.js b/lib/output/website/createTemplateEngine.js deleted file mode 100644 index 02ec796..0000000 --- a/lib/output/website/createTemplateEngine.js +++ /dev/null @@ -1,151 +0,0 @@ -var path = require('path'); -var nunjucks = require('nunjucks'); -var DoExtension = require('nunjucks-do')(nunjucks); - -var Api = require('../../api'); -var deprecate = require('../../api/deprecate'); -var JSONUtils = require('../../json'); -var LocationUtils = require('../../utils/location'); -var fs = require('../../utils/fs'); -var PathUtils = require('../../utils/path'); -var TemplateEngine = require('../../models/templateEngine'); -var templatesFolder = require('../../constants/templatesFolder'); -var defaultFilters = require('../../constants/defaultFilters'); -var Templating = require('../../templating'); -var listSearchPaths = require('./listSearchPaths'); - -var fileToURL = require('../helper/fileToURL'); -var resolveFileToURL = require('../helper/resolveFileToURL'); - -/** - * 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} - */ -function createTemplateEngine(output, currentFile) { - var book = output.getBook(); - var state = output.getState(); - var i18n = state.getI18n(); - var config = book.getConfig(); - var summary = book.getSummary(); - var outputFolder = output.getRoot(); - - // Search paths for templates - var searchPaths = listSearchPaths(output); - var tplSearchPaths = searchPaths.map(templateFolder); - - // Create loader - var loader = new Templating.ThemesLoader(tplSearchPaths); - - // Get languages - var language = config.getValue('language'); - - // Create API context - var context = Api.encodeGlobal(output); - - - /** - * Check if a file exists - * @param {String} fileName - * @return {Boolean} - */ - function fileExists(fileName) { - if (!fileName) { - return false; - } - - var filePath = PathUtils.resolveInRoot(outputFolder, fileName); - return fs.existsSync(filePath); - } - - /** - * Return an article by its path - * @param {String} filePath - * @return {Object|undefined} - */ - function getArticleByPath(filePath) { - var article = summary.getByPath(filePath); - if (!article) return undefined; - - return JSONUtils.encodeSummaryArticle(article); - } - - /** - * Return a page by its path - * @param {String} filePath - * @return {Object|undefined} - */ - function getPageByPath(filePath) { - var page = output.getPage(filePath); - if (!page) return undefined; - - return JSONUtils.encodePage(page, summary); - } - - return TemplateEngine.create({ - loader: loader, - - context: context, - - globals: { - getArticleByPath: getArticleByPath, - getPageByPath: getPageByPath, - fileExists: fileExists - }, - - filters: defaultFilters.merge({ - /** - * 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 - */ - resolveFile: function(filePath) { - filePath = resolveFileToURL(output, filePath); - return LocationUtils.relativeForFile(currentFile, filePath); - }, - - resolveAsset: function(filePath) { - filePath = LocationUtils.toAbsolute(filePath, '', ''); - filePath = path.join('gitbook', filePath); - filePath = LocationUtils.relativeForFile(currentFile, filePath); - - // Use assets from parent if language book - if (book.isLanguageBook()) { - filePath = path.join('../', filePath); - } - - return LocationUtils.normalize(filePath); - }, - - - fileExists: deprecate.method(book, 'fileExists', fileExists, 'Filter "fileExists" is deprecated, use "fileExists(filename)" '), - getArticleByPath: deprecate.method(book, 'getArticleByPath', fileExists, 'Filter "getArticleByPath" is deprecated, use "getArticleByPath(filename)" '), - - contentURL: function(filePath) { - return fileToURL(output, filePath); - } - }), - - extensions: { - 'DoExtension': new DoExtension() - } - }); -} - -module.exports = createTemplateEngine; diff --git a/lib/output/website/index.js b/lib/output/website/index.js deleted file mode 100644 index 7818a28..0000000 --- a/lib/output/website/index.js +++ /dev/null @@ -1,11 +0,0 @@ - -module.exports = { - name: 'website', - State: require('./state'), - Options: require('./options'), - onInit: require('./onInit'), - onFinish: require('./onFinish'), - onPage: require('./onPage'), - onAsset: require('./onAsset'), - createTemplateEngine: require('./createTemplateEngine') -}; diff --git a/lib/output/website/listSearchPaths.js b/lib/output/website/listSearchPaths.js deleted file mode 100644 index c45f39c..0000000 --- a/lib/output/website/listSearchPaths.js +++ /dev/null @@ -1,23 +0,0 @@ - -/** - List search paths for templates / i18n, etc - - @param {Output} output - @return {List<String>} -*/ -function listSearchPaths(output) { - var book = output.getBook(); - var plugins = output.getPlugins(); - - var searchPaths = plugins - .valueSeq() - .map(function(plugin) { - return plugin.getPath(); - }) - .toList(); - - return searchPaths.unshift(book.getContentRoot()); -} - - -module.exports = listSearchPaths; diff --git a/lib/output/website/onAsset.js b/lib/output/website/onAsset.js deleted file mode 100644 index 69dfc4f..0000000 --- a/lib/output/website/onAsset.js +++ /dev/null @@ -1,28 +0,0 @@ -var path = require('path'); -var fs = require('../../utils/fs'); - -/** - Copy an asset to the output folder - - @param {Output} output - @param {Page} page -*/ -function onAsset(output, asset) { - var book = output.getBook(); - var options = output.getOptions(); - var bookFS = book.getContentFS(); - - var outputFolder = options.get('root'); - var outputPath = path.resolve(outputFolder, asset); - - return fs.ensureFile(outputPath) - .then(function() { - return bookFS.readAsStream(asset) - .then(function(stream) { - return fs.writeStream(outputPath, stream); - }); - }) - .thenResolve(output); -} - -module.exports = onAsset; diff --git a/lib/output/website/onFinish.js b/lib/output/website/onFinish.js deleted file mode 100644 index 5267458..0000000 --- a/lib/output/website/onFinish.js +++ /dev/null @@ -1,35 +0,0 @@ -var Promise = require('../../utils/promise'); -var JSONUtils = require('../../json'); -var Templating = require('../../templating'); -var writeFile = require('../helper/writeFile'); -var createTemplateEngine = require('./createTemplateEngine'); - -/** - Finish the generation, write the languages index - - @param {Output} - @return {Output} -*/ -function onFinish(output) { - var book = output.getBook(); - var options = output.getOptions(); - var prefix = options.get('prefix'); - - if (!book.isMultilingual()) { - return Promise(output); - } - - var filePath = 'index.html'; - var engine = createTemplateEngine(output, filePath); - var context = JSONUtils.encodeOutput(output); - - // Render the theme - return Templating.renderFile(engine, prefix + '/languages.html', context) - - // Write it to the disk - .then(function(tplOut) { - return writeFile(output, filePath, tplOut.getContent()); - }); -} - -module.exports = onFinish; diff --git a/lib/output/website/onInit.js b/lib/output/website/onInit.js deleted file mode 100644 index 3465eef..0000000 --- a/lib/output/website/onInit.js +++ /dev/null @@ -1,20 +0,0 @@ -var Promise = require('../../utils/promise'); - -var copyPluginAssets = require('./copyPluginAssets'); -var prepareI18n = require('./prepareI18n'); -var prepareResources = require('./prepareResources'); - -/** - Initialize the generator - - @param {Output} - @return {Output} -*/ -function onInit(output) { - return Promise(output) - .then(prepareI18n) - .then(prepareResources) - .then(copyPluginAssets); -} - -module.exports = onInit; diff --git a/lib/output/website/onPage.js b/lib/output/website/onPage.js deleted file mode 100644 index 5fb40a7..0000000 --- a/lib/output/website/onPage.js +++ /dev/null @@ -1,76 +0,0 @@ -var path = require('path'); -var omit = require('omit-keys'); - -var Templating = require('../../templating'); -var Plugins = require('../../plugins'); -var JSONUtils = require('../../json'); -var LocationUtils = require('../../utils/location'); -var Modifiers = require('../modifiers'); -var writeFile = require('../helper/writeFile'); -var getModifiers = require('../getModifiers'); -var createTemplateEngine = require('./createTemplateEngine'); -var fileToOutput = require('../helper/fileToOutput'); - -/** - * 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'); - - var file = page.getFile(); - - var book = output.getBook(); - var plugins = output.getPlugins(); - var state = output.getState(); - var resources = state.getResources(); - - var engine = createTemplateEngine(output, page.getPath()); - - // Output file path - var filePath = fileToOutput(output, file.getPath()); - - // Calcul relative path to the root - var outputDirName = path.dirname(filePath); - var basePath = LocationUtils.normalize(path.relative(outputDirName, './')); - - return Modifiers.modifyHTML(page, getModifiers(output, page)) - .then(function(resultPage) { - // Generate the context - var context = JSONUtils.encodeOutputWithPage(output, resultPage); - context.plugins = { - resources: Plugins.listResources(plugins, resources).toJS() - }; - - context.template = { - getJSContext: function() { - return { - page: omit(context.page, 'content'), - config: context.config, - file: context.file, - gitbook: context.gitbook, - basePath: basePath, - book: { - language: book.getLanguage() - } - }; - } - }; - - // We should probabbly move it to "template" or a "site" namespace - context.basePath = basePath; - - // Render the theme - return Templating.renderFile(engine, prefix + '/page.html', context) - - // Write it to the disk - .then(function(tplOut) { - return writeFile(output, filePath, tplOut.getContent()); - }); - }); -} - -module.exports = onPage; diff --git a/lib/output/website/options.js b/lib/output/website/options.js deleted file mode 100644 index ac9cdad..0000000 --- a/lib/output/website/options.js +++ /dev/null @@ -1,14 +0,0 @@ -var Immutable = require('immutable'); - -var Options = Immutable.Record({ - // Root folder for the output - root: String(), - - // Prefix for generation - prefix: String('website'), - - // Use directory index url instead of "index.html" - directoryIndex: Boolean(true) -}); - -module.exports = Options; diff --git a/lib/output/website/prepareI18n.js b/lib/output/website/prepareI18n.js deleted file mode 100644 index cedd3b9..0000000 --- a/lib/output/website/prepareI18n.js +++ /dev/null @@ -1,30 +0,0 @@ -var path = require('path'); - -var fs = require('../../utils/fs'); -var Promise = require('../../utils/promise'); -var listSearchPaths = require('./listSearchPaths'); - -/** - * Prepare i18n, load translations from plugins and book - * - * @param {Output} - * @return {Promise<Output>} - */ -function prepareI18n(output) { - var state = output.getState(); - var i18n = state.getI18n(); - var searchPaths = listSearchPaths(output); - - searchPaths - .reverse() - .forEach(function(searchPath) { - var i18nRoot = path.resolve(searchPath, '_i18n'); - - if (!fs.existsSync(i18nRoot)) return; - i18n.load(i18nRoot); - }); - - return Promise(output); -} - -module.exports = prepareI18n; diff --git a/lib/output/website/prepareResources.js b/lib/output/website/prepareResources.js deleted file mode 100644 index 4e6835d..0000000 --- a/lib/output/website/prepareResources.js +++ /dev/null @@ -1,54 +0,0 @@ -var is = require('is'); -var Immutable = require('immutable'); -var Promise = require('../../utils/promise'); - -var Api = require('../../api'); - -/** - Prepare plugins resources, add all output corresponding type resources - - @param {Output} - @return {Promise<Output>} -*/ -function prepareResources(output) { - var plugins = output.getPlugins(); - var options = output.getOptions(); - var type = options.get('prefix'); - var state = output.getState(); - var context = Api.encodeGlobal(output); - - var result = Immutable.Map(); - - return Promise.forEach(plugins, function(plugin) { - var pluginResources = plugin.getResources(type); - - return Promise() - .then(function() { - // Apply resources if is a function - if (is.fn(pluginResources)) { - return Promise() - .then(pluginResources.bind(context)); - } - else { - return pluginResources; - } - }) - .then(function(resources) { - result = result.set(plugin.getName(), Immutable.Map(resources)); - }); - }) - .then(function() { - // Set output resources - state = state.merge({ - resources: result - }); - - output = output.merge({ - state: state - }); - - return output; - }); -} - -module.exports = prepareResources;
\ No newline at end of file diff --git a/lib/output/website/state.js b/lib/output/website/state.js deleted file mode 100644 index cb8f750..0000000 --- a/lib/output/website/state.js +++ /dev/null @@ -1,19 +0,0 @@ -var I18n = require('i18n-t'); -var Immutable = require('immutable'); - -var GeneratorState = Immutable.Record({ - i18n: I18n(), - - // List of plugins' resources - resources: Immutable.Map() -}); - -GeneratorState.prototype.getI18n = function() { - return this.get('i18n'); -}; - -GeneratorState.prototype.getResources = function() { - return this.get('resources'); -}; - -module.exports = GeneratorState; |