diff options
Diffstat (limited to 'lib/models')
33 files changed, 0 insertions, 3622 deletions
diff --git a/lib/models/__tests__/config.js b/lib/models/__tests__/config.js deleted file mode 100644 index abad754..0000000 --- a/lib/models/__tests__/config.js +++ /dev/null @@ -1,90 +0,0 @@ -var Immutable = require('immutable'); -var Config = require('../config'); - -describe('Config', function() { - var config = Config.createWithValues({ - hello: { - world: 1, - test: 'Hello', - isFalse: false - } - }); - - describe('getValue', function() { - it('must return value as immutable', function() { - var value = config.getValue('hello'); - expect(Immutable.Map.isMap(value)).toBeTruthy(); - }); - - it('must return deep value', function() { - var value = config.getValue('hello.world'); - expect(value).toBe(1); - }); - - it('must return default value if non existant', function() { - var value = config.getValue('hello.nonExistant', 'defaultValue'); - expect(value).toBe('defaultValue'); - }); - - it('must not return default value for falsy values', function() { - var value = config.getValue('hello.isFalse', 'defaultValue'); - expect(value).toBe(false); - }); - }); - - describe('setValue', function() { - it('must set value as immutable', function() { - var testConfig = config.setValue('hello', { - 'cool': 1 - }); - var value = testConfig.getValue('hello'); - - expect(Immutable.Map.isMap(value)).toBeTruthy(); - expect(value.size).toBe(1); - expect(value.has('cool')).toBeTruthy(); - }); - - it('must set deep value', function() { - var testConfig = config.setValue('hello.world', 2); - var hello = testConfig.getValue('hello'); - var world = testConfig.getValue('hello.world'); - - expect(Immutable.Map.isMap(hello)).toBeTruthy(); - expect(hello.size).toBe(3); - - expect(world).toBe(2); - }); - }); - - describe('toReducedVersion', function() { - it('must only return diffs for simple values', function() { - var _config = Config.createWithValues({ - gitbook: '3.0.0' - }); - - var reducedVersion = _config.toReducedVersion(); - - expect(reducedVersion.toJS()).toEqual({ - gitbook: '3.0.0' - }); - }); - - it('must only return diffs for deep values', function() { - var _config = Config.createWithValues({ - structure: { - readme: 'intro.md' - } - }); - - var reducedVersion = _config.toReducedVersion(); - - expect(reducedVersion.toJS()).toEqual({ - structure: { - readme: 'intro.md' - } - }); - }); - }); -}); - - diff --git a/lib/models/__tests__/glossary.js b/lib/models/__tests__/glossary.js deleted file mode 100644 index 5bf64dc..0000000 --- a/lib/models/__tests__/glossary.js +++ /dev/null @@ -1,40 +0,0 @@ -var File = require('../file'); -var Glossary = require('../glossary'); -var GlossaryEntry = require('../glossaryEntry'); - -describe('Glossary', function() { - var glossary = Glossary.createFromEntries(File(), [ - { - name: 'Hello World', - description: 'Awesome!' - }, - { - name: 'JavaScript', - description: 'This is a cool language' - } - ]); - - describe('createFromEntries', function() { - it('must add all entries', function() { - var entries = glossary.getEntries(); - expect(entries.size).toBe(2); - }); - - it('must add entries as GlossaryEntries', function() { - var entries = glossary.getEntries(); - var entry = entries.get('hello-world'); - expect(entry instanceof GlossaryEntry).toBeTruthy(); - }); - }); - - describe('toText', function() { - it('return as markdown', function() { - return glossary.toText('.md') - .then(function(text) { - expect(text).toContain('# Glossary'); - }); - }); - }); -}); - - diff --git a/lib/models/__tests__/glossaryEntry.js b/lib/models/__tests__/glossaryEntry.js deleted file mode 100644 index 833115d..0000000 --- a/lib/models/__tests__/glossaryEntry.js +++ /dev/null @@ -1,15 +0,0 @@ -var GlossaryEntry = require('../glossaryEntry'); - -describe('GlossaryEntry', function() { - describe('getID', function() { - it('must return a normalized ID', function() { - var entry = new GlossaryEntry({ - name: 'Hello World' - }); - - expect(entry.getID()).toBe('hello-world'); - }); - }); -}); - - diff --git a/lib/models/__tests__/page.js b/lib/models/__tests__/page.js deleted file mode 100644 index 479d276..0000000 --- a/lib/models/__tests__/page.js +++ /dev/null @@ -1,28 +0,0 @@ -var Immutable = require('immutable'); -var Page = require('../page'); - -describe('Page', function() { - - describe('toText', function() { - it('must not prepend frontmatter if no attributes', function() { - var page = Page().merge({ - content: 'Hello World' - }); - - expect(page.toText()).toBe('Hello World'); - }); - - it('must prepend frontmatter if attributes', function() { - var page = Page().merge({ - content: 'Hello World', - attributes: Immutable.fromJS({ - hello: 'world' - }) - }); - - expect(page.toText()).toBe('---\nhello: world\n---\n\nHello World'); - }); - }); -}); - - diff --git a/lib/models/__tests__/plugin.js b/lib/models/__tests__/plugin.js deleted file mode 100644 index b229664..0000000 --- a/lib/models/__tests__/plugin.js +++ /dev/null @@ -1,27 +0,0 @@ -describe('Plugin', function() { - var Plugin = require('../plugin'); - - describe('createFromString', function() { - it('must parse name', function() { - var plugin = Plugin.createFromString('hello'); - expect(plugin.getName()).toBe('hello'); - expect(plugin.getVersion()).toBe('*'); - }); - - it('must parse version', function() { - var plugin = Plugin.createFromString('hello@1.0.0'); - expect(plugin.getName()).toBe('hello'); - expect(plugin.getVersion()).toBe('1.0.0'); - }); - }); - - describe('isLoaded', function() { - it('must return false for empty plugin', function() { - var plugin = Plugin.createFromString('hello'); - expect(plugin.isLoaded()).toBe(false); - }); - - }); -}); - - diff --git a/lib/models/__tests__/pluginDependency.js b/lib/models/__tests__/pluginDependency.js deleted file mode 100644 index cb04cf2..0000000 --- a/lib/models/__tests__/pluginDependency.js +++ /dev/null @@ -1,80 +0,0 @@ -var Immutable = require('immutable'); -var PluginDependency = require('../pluginDependency'); - -describe('PluginDependency', function() { - describe('createFromString', function() { - it('must parse name', function() { - var plugin = PluginDependency.createFromString('hello'); - expect(plugin.getName()).toBe('hello'); - expect(plugin.getVersion()).toBe('*'); - }); - - it('must parse state', function() { - var plugin = PluginDependency.createFromString('-hello'); - expect(plugin.getName()).toBe('hello'); - expect(plugin.isEnabled()).toBe(false); - }); - - describe('Version', function() { - it('must parse version', function() { - var plugin = PluginDependency.createFromString('hello@1.0.0'); - expect(plugin.getName()).toBe('hello'); - expect(plugin.getVersion()).toBe('1.0.0'); - }); - - it('must parse semver', function() { - var plugin = PluginDependency.createFromString('hello@>=4.0.0'); - expect(plugin.getName()).toBe('hello'); - expect(plugin.getVersion()).toBe('>=4.0.0'); - }); - }); - - describe('GIT Version', function() { - it('must handle HTTPS urls', function() { - var plugin = PluginDependency.createFromString('hello@git+https://github.com/GitbookIO/plugin-ga.git'); - expect(plugin.getName()).toBe('hello'); - expect(plugin.getVersion()).toBe('git+https://github.com/GitbookIO/plugin-ga.git'); - }); - - it('must handle SSH urls', function() { - var plugin = PluginDependency.createFromString('hello@git+ssh://samy@github.com/GitbookIO/plugin-ga.git'); - expect(plugin.getName()).toBe('hello'); - expect(plugin.getVersion()).toBe('git+ssh://samy@github.com/GitbookIO/plugin-ga.git'); - }); - }); - - describe('listToArray', function() { - it('must create an array from a list of plugin dependencies', function() { - var list = PluginDependency.listToArray(Immutable.List([ - PluginDependency.createFromString('hello@1.0.0'), - PluginDependency.createFromString('noversion'), - PluginDependency.createFromString('-disabled') - ])); - - expect(list).toEqual([ - 'hello@1.0.0', - 'noversion', - '-disabled' - ]); - }); - }); - - describe('listFromArray', function() { - it('must create an array from a list of plugin dependencies', function() { - var arr = Immutable.fromJS([ - 'hello@1.0.0', - { - 'name': 'plugin-ga', - 'version': 'git+ssh://samy@github.com/GitbookIO/plugin-ga.git' - } - ]); - var list = PluginDependency.listFromArray(arr); - - expect(list.first().getName()).toBe('hello'); - expect(list.first().getVersion()).toBe('1.0.0'); - expect(list.last().getName()).toBe('plugin-ga'); - expect(list.last().getVersion()).toBe('git+ssh://samy@github.com/GitbookIO/plugin-ga.git'); - }); - }); - }); -}); diff --git a/lib/models/__tests__/summary.js b/lib/models/__tests__/summary.js deleted file mode 100644 index 29c9330..0000000 --- a/lib/models/__tests__/summary.js +++ /dev/null @@ -1,94 +0,0 @@ - -describe('Summary', function() { - var File = require('../file'); - var Summary = require('../summary'); - - var summary = Summary.createFromParts(File(), [ - { - articles: [ - { - title: 'My First Article', - ref: 'README.md' - }, - { - title: 'My Second Article', - ref: 'article.md' - }, - { - title: 'Article without ref' - }, - { - title: 'Article with absolute ref', - ref: 'https://google.fr' - } - ] - }, - { - title: 'Test' - } - ]); - - describe('createFromEntries', function() { - it('must add all parts', function() { - var parts = summary.getParts(); - expect(parts.size).toBe(2); - }); - }); - - describe('getByLevel', function() { - it('can return a Part', function() { - var part = summary.getByLevel('1'); - - expect(part).toBeDefined(); - expect(part.getArticles().size).toBe(4); - }); - - it('can return a Part (2)', function() { - var part = summary.getByLevel('2'); - - expect(part).toBeDefined(); - expect(part.getTitle()).toBe('Test'); - expect(part.getArticles().size).toBe(0); - }); - - it('can return an Article', function() { - var article = summary.getByLevel('1.1'); - - expect(article).toBeDefined(); - expect(article.getTitle()).toBe('My First Article'); - }); - }); - - describe('getByPath', function() { - it('return correct article', function() { - var article = summary.getByPath('README.md'); - - expect(article).toBeDefined(); - expect(article.getTitle()).toBe('My First Article'); - }); - - it('return correct article', function() { - var article = summary.getByPath('article.md'); - - expect(article).toBeDefined(); - expect(article.getTitle()).toBe('My Second Article'); - }); - - it('return undefined if not found', function() { - var article = summary.getByPath('NOT_EXISTING.md'); - - expect(article).toBeFalsy(); - }); - }); - - describe('toText', function() { - it('return as markdown', function() { - return summary.toText('.md') - .then(function(text) { - expect(text).toContain('# Summary'); - }); - }); - }); -}); - - diff --git a/lib/models/__tests__/summaryArticle.js b/lib/models/__tests__/summaryArticle.js deleted file mode 100644 index 22a7a20..0000000 --- a/lib/models/__tests__/summaryArticle.js +++ /dev/null @@ -1,53 +0,0 @@ -var SummaryArticle = require('../summaryArticle'); -var File = require('../file'); - -describe('SummaryArticle', function() { - describe('createChildLevel', function() { - it('must create the right level', function() { - var article = SummaryArticle.create({}, '1.1'); - expect(article.createChildLevel()).toBe('1.1.1'); - }); - - it('must create the right level when has articles', function() { - var article = SummaryArticle.create({ - articles: [ - { - title: 'Test' - } - ] - }, '1.1'); - 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/__tests__/summaryPart.js b/lib/models/__tests__/summaryPart.js deleted file mode 100644 index 8ee50b6..0000000 --- a/lib/models/__tests__/summaryPart.js +++ /dev/null @@ -1,23 +0,0 @@ -var SummaryPart = require('../summaryPart'); - -describe('SummaryPart', function() { - describe('createChildLevel', function() { - it('must create the right level', function() { - var article = SummaryPart.create({}, '1'); - expect(article.createChildLevel()).toBe('1.1'); - }); - - it('must create the right level when has articles', function() { - var article = SummaryPart.create({ - articles: [ - { - title: 'Test' - } - ] - }, '1'); - expect(article.createChildLevel()).toBe('1.2'); - }); - }); -}); - - diff --git a/lib/models/__tests__/templateBlock.js b/lib/models/__tests__/templateBlock.js deleted file mode 100644 index e5f7666..0000000 --- a/lib/models/__tests__/templateBlock.js +++ /dev/null @@ -1,205 +0,0 @@ -var nunjucks = require('nunjucks'); -var Immutable = require('immutable'); -var Promise = require('../../utils/promise'); - -describe('TemplateBlock', function() { - var TemplateBlock = require('../templateBlock'); - - describe('create', function() { - it('must initialize a simple TemplateBlock from a function', function() { - var templateBlock = TemplateBlock.create('sayhello', function(block) { - return { - body: '<p>Hello, World!</p>', - parse: true - }; - }); - - // Check basic templateBlock properties - expect(templateBlock.getName()).toBe('sayhello'); - expect(templateBlock.getEndTag()).toBe('endsayhello'); - expect(templateBlock.getBlocks().size).toBe(0); - expect(templateBlock.getExtensionName()).toBe('BlocksayhelloExtension'); - - // Check result of applying block - return Promise() - .then(function() { - return templateBlock.applyBlock(); - }) - .then(function(result) { - expect(result.name).toBe('sayhello'); - expect(result.body).toBe('<p>Hello, World!</p>'); - }); - }); - }); - - describe('getShortcuts', function() { - it('must return undefined if no shortcuts', function() { - var templateBlock = TemplateBlock.create('sayhello', function(block) { - return { - body: '<p>Hello, World!</p>', - parse: true - }; - }); - - expect(templateBlock.getShortcuts()).toNotExist(); - }); - - it('must return complete shortcut', function() { - var templateBlock = TemplateBlock.create('sayhello', { - process: function(block) { - return '<p>Hello, World!</p>'; - }, - shortcuts: { - parsers: ['markdown'], - start: '$', - end: '-' - } - }); - - var shortcut = templateBlock.getShortcuts(); - - expect(shortcut).toBeDefined(); - expect(shortcut.getStart()).toEqual('$'); - expect(shortcut.getEnd()).toEqual('-'); - expect(shortcut.getStartTag()).toEqual('sayhello'); - expect(shortcut.getEndTag()).toEqual('endsayhello'); - }); - }); - - describe('toNunjucksExt()', function() { - it('should replace by block anchor', function() { - var templateBlock = TemplateBlock.create('sayhello', function(block) { - return 'Hello'; - }); - - var blocks = {}; - - // Create a fresh Nunjucks environment - var env = new nunjucks.Environment(null, { autoescape: false }); - - // Add template block to environement - var Ext = templateBlock.toNunjucksExt({}, blocks); - env.addExtension(templateBlock.getExtensionName(), new Ext()); - - // Render a template using the block - var src = '{% sayhello %}{% endsayhello %}'; - return Promise.nfcall(env.renderString.bind(env), src) - .then(function(res) { - blocks = Immutable.fromJS(blocks); - expect(blocks.size).toBe(1); - - var blockId = blocks.keySeq().get(0); - var block = blocks.get(blockId); - - expect(res).toBe('{{-%' + blockId + '%-}}'); - expect(block.get('body')).toBe('Hello'); - expect(block.get('name')).toBe('sayhello'); - }); - }); - - it('must create a valid nunjucks extension', function() { - var templateBlock = TemplateBlock.create('sayhello', function(block) { - return { - body: '<p>Hello, World!</p>', - parse: true - }; - }); - - // Create a fresh Nunjucks environment - var env = new nunjucks.Environment(null, { autoescape: false }); - - // Add template block to environement - var Ext = templateBlock.toNunjucksExt(); - env.addExtension(templateBlock.getExtensionName(), new Ext()); - - // Render a template using the block - var src = '{% sayhello %}{% endsayhello %}'; - return Promise.nfcall(env.renderString.bind(env), src) - .then(function(res) { - expect(res).toBe('<p>Hello, World!</p>'); - }); - }); - - it('must apply block arguments correctly', function() { - var templateBlock = TemplateBlock.create('sayhello', function(block) { - return { - body: '<'+block.kwargs.tag+'>Hello, '+block.kwargs.name+'!</'+block.kwargs.tag+'>', - parse: true - }; - }); - - // Create a fresh Nunjucks environment - var env = new nunjucks.Environment(null, { autoescape: false }); - - // Add template block to environement - var Ext = templateBlock.toNunjucksExt(); - env.addExtension(templateBlock.getExtensionName(), new Ext()); - - // Render a template using the block - var src = '{% sayhello name="Samy", tag="p" %}{% endsayhello %}'; - return Promise.nfcall(env.renderString.bind(env), src) - .then(function(res) { - expect(res).toBe('<p>Hello, Samy!</p>'); - }); - }); - - it('must accept an async function', function() { - var templateBlock = TemplateBlock.create('sayhello', function(block) { - return Promise() - .then(function() { - return { - body: 'Hello ' + block.body, - parse: true - }; - }); - }); - - // Create a fresh Nunjucks environment - var env = new nunjucks.Environment(null, { autoescape: false }); - - // Add template block to environement - var Ext = templateBlock.toNunjucksExt(); - env.addExtension(templateBlock.getExtensionName(), new Ext()); - - // Render a template using the block - var src = '{% sayhello %}Samy{% endsayhello %}'; - return Promise.nfcall(env.renderString.bind(env), src) - .then(function(res) { - expect(res).toBe('Hello Samy'); - }); - }); - - it('must handle nested blocks', function() { - var templateBlock = new TemplateBlock({ - name: 'yoda', - blocks: Immutable.List(['start', 'end']), - process: function(block) { - var nested = {}; - - block.blocks.forEach(function(blk) { - nested[blk.name] = blk.body.trim(); - }); - - return { - body: '<p class="yoda">'+nested.end+' '+nested.start+'</p>', - parse: true - }; - } - }); - - // Create a fresh Nunjucks environment - var env = new nunjucks.Environment(null, { autoescape: false }); - - // Add template block to environement - var Ext = templateBlock.toNunjucksExt(); - env.addExtension(templateBlock.getExtensionName(), new Ext()); - - // Render a template using the block - var src = '{% yoda %}{% start %}this sentence should be{% end %}inverted{% endyoda %}'; - return Promise.nfcall(env.renderString.bind(env), src) - .then(function(res) { - expect(res).toBe('<p class="yoda">inverted this sentence should be</p>'); - }); - }); - }); -});
\ No newline at end of file diff --git a/lib/models/__tests__/templateEngine.js b/lib/models/__tests__/templateEngine.js deleted file mode 100644 index 6f18b18..0000000 --- a/lib/models/__tests__/templateEngine.js +++ /dev/null @@ -1,51 +0,0 @@ - -describe('TemplateBlock', function() { - var TemplateEngine = require('../templateEngine'); - - describe('create', function() { - it('must initialize with a list of filters', function() { - var engine = TemplateEngine.create({ - filters: { - hello: function(name) { - return 'Hello ' + name + '!'; - } - } - }); - var env = engine.toNunjucks(); - var res = env.renderString('{{ "Luke"|hello }}'); - - expect(res).toBe('Hello Luke!'); - }); - - it('must initialize with a list of globals', function() { - var engine = TemplateEngine.create({ - globals: { - hello: function(name) { - return 'Hello ' + name + '!'; - } - } - }); - var env = engine.toNunjucks(); - var res = env.renderString('{{ hello("Luke") }}'); - - expect(res).toBe('Hello Luke!'); - }); - - it('must pass context to filters and blocks', function() { - var engine = TemplateEngine.create({ - filters: { - hello: function(name) { - return 'Hello ' + name + ' ' + this.lastName + '!'; - } - }, - context: { - lastName: 'Skywalker' - } - }); - var env = engine.toNunjucks(); - var res = env.renderString('{{ "Luke"|hello }}'); - - expect(res).toBe('Hello Luke Skywalker!'); - }); - }); -});
\ No newline at end of file diff --git a/lib/models/book.js b/lib/models/book.js deleted file mode 100644 index f774ee8..0000000 --- a/lib/models/book.js +++ /dev/null @@ -1,364 +0,0 @@ -var path = require('path'); -var Immutable = require('immutable'); - -var Logger = require('../utils/logger'); - -var FS = require('./fs'); -var Config = require('./config'); -var Readme = require('./readme'); -var Summary = require('./summary'); -var Glossary = require('./glossary'); -var Languages = require('./languages'); -var Ignore = require('./ignore'); - -var Book = Immutable.Record({ - // Logger for outptu message - logger: Logger(), - - // Filesystem binded to the book scope to read files/directories - fs: FS(), - - // Ignore files parser - ignore: Ignore(), - - // Structure files - config: Config(), - readme: Readme(), - summary: Summary(), - glossary: Glossary(), - languages: Languages(), - - // ID of the language for language books - language: String(), - - // List of children, if multilingual (String -> Book) - books: Immutable.OrderedMap() -}); - -Book.prototype.getLogger = function() { - return this.get('logger'); -}; - -Book.prototype.getFS = function() { - return this.get('fs'); -}; - -Book.prototype.getIgnore = function() { - return this.get('ignore'); -}; - -Book.prototype.getConfig = function() { - return this.get('config'); -}; - -Book.prototype.getReadme = function() { - return this.get('readme'); -}; - -Book.prototype.getSummary = function() { - return this.get('summary'); -}; - -Book.prototype.getGlossary = function() { - return this.get('glossary'); -}; - -Book.prototype.getLanguages = function() { - return this.get('languages'); -}; - -Book.prototype.getBooks = function() { - return this.get('books'); -}; - -Book.prototype.getLanguage = function() { - return this.get('language'); -}; - -/** - Return FS instance to access the content - - @return {FS} -*/ -Book.prototype.getContentFS = function() { - var fs = this.getFS(); - var config = this.getConfig(); - var rootFolder = config.getValue('root'); - - if (rootFolder) { - return FS.reduceScope(fs, rootFolder); - } - - return fs; -}; - -/** - Return root of the book - - @return {String} -*/ -Book.prototype.getRoot = function() { - var fs = this.getFS(); - return fs.getRoot(); -}; - -/** - Return root for content of the book - - @return {String} -*/ -Book.prototype.getContentRoot = function() { - var fs = this.getContentFS(); - return fs.getRoot(); -}; - -/** - Check if a file is ignore (should not being parsed, etc) - - @param {String} ref - @return {Page|undefined} -*/ -Book.prototype.isFileIgnored = function(filename) { - var ignore = this.getIgnore(); - var language = this.getLanguage(); - - // Ignore is always relative to the root of the main book - if (language) { - filename = path.join(language, filename); - } - - return ignore.isFileIgnored(filename); -}; - -/** - Check if a content file is ignore (should not being parsed, etc) - - @param {String} ref - @return {Page|undefined} -*/ -Book.prototype.isContentFileIgnored = function(filename) { - var config = this.getConfig(); - var rootFolder = config.getValue('root'); - - if (rootFolder) { - filename = path.join(rootFolder, filename); - } - - return this.isFileIgnored(filename); -}; - -/** - Return a page from a book by its path - - @param {String} ref - @return {Page|undefined} -*/ -Book.prototype.getPage = function(ref) { - return this.getPages().get(ref); -}; - -/** - Is this book the parent of language's books - - @return {Boolean} -*/ -Book.prototype.isMultilingual = function() { - return (this.getLanguages().getCount() > 0); -}; - -/** - Return true if book is associated to a language - - @return {Boolean} -*/ -Book.prototype.isLanguageBook = function() { - return Boolean(this.getLanguage()); -}; - -/** - Return a languages book - - @param {String} language - @return {Book} -*/ -Book.prototype.getLanguageBook = function(language) { - var books = this.getBooks(); - return books.get(language); -}; - -/** - Add a new language book - - @param {String} language - @param {Book} book - @return {Book} -*/ -Book.prototype.addLanguageBook = function(language, book) { - var books = this.getBooks(); - books = books.set(language, book); - - return this.set('books', books); -}; - -/** - Set the summary for this book - - @param {Summary} - @return {Book} -*/ -Book.prototype.setSummary = function(summary) { - return this.set('summary', summary); -}; - -/** - Set the readme for this book - - @param {Readme} - @return {Book} -*/ -Book.prototype.setReadme = function(readme) { - return this.set('readme', readme); -}; - -/** - Set the configuration for this book - - @param {Config} - @return {Book} -*/ -Book.prototype.setConfig = function(config) { - return this.set('config', config); -}; - -/** - Set the ignore instance for this book - - @param {Ignore} - @return {Book} -*/ -Book.prototype.setIgnore = function(ignore) { - return this.set('ignore', ignore); -}; - -/** - Change log level - - @param {String} level - @return {Book} -*/ -Book.prototype.setLogLevel = function(level) { - this.getLogger().setLevel(level); - return this; -}; - -/** - Create a book using a filesystem - - @param {FS} fs - @return {Book} -*/ -Book.createForFS = function createForFS(fs) { - return new Book({ - fs: fs - }); -}; - -/** - Infers the default extension for files - @return {String} -*/ -Book.prototype.getDefaultExt = function() { - // Inferring sources - var clues = [ - this.getReadme(), - this.getSummary(), - this.getGlossary() - ]; - - // List their extensions - var exts = clues.map(function (clue) { - var file = clue.getFile(); - if (file.exists()) { - return file.getParser().getExtensions().first(); - } else { - return null; - } - }); - // Adds the general default extension - exts.push('.md'); - - // Choose the first non null - return exts.find(function (e) { return e !== null; }); -}; - -/** - Infer the default path for a Readme. - @param {Boolean} [absolute=false] False for a path relative to - this book's content root - @return {String} -*/ -Book.prototype.getDefaultReadmePath = function(absolute) { - var defaultPath = 'README'+this.getDefaultExt(); - if (absolute) { - return path.join(this.getContentRoot(), defaultPath); - } else { - return defaultPath; - } -}; - -/** - Infer the default path for a Summary. - @param {Boolean} [absolute=false] False for a path relative to - this book's content root - @return {String} -*/ -Book.prototype.getDefaultSummaryPath = function(absolute) { - var defaultPath = 'SUMMARY'+this.getDefaultExt(); - if (absolute) { - return path.join(this.getContentRoot(), defaultPath); - } else { - return defaultPath; - } -}; - -/** - Infer the default path for a Glossary. - @param {Boolean} [absolute=false] False for a path relative to - this book's content root - @return {String} -*/ -Book.prototype.getDefaultGlossaryPath = function(absolute) { - var defaultPath = 'GLOSSARY'+this.getDefaultExt(); - if (absolute) { - return path.join(this.getContentRoot(), defaultPath); - } else { - return defaultPath; - } -}; - -/** - Create a language book from a parent - - @param {Book} parent - @param {String} language - @return {Book} -*/ -Book.createFromParent = function createFromParent(parent, language) { - var ignore = parent.getIgnore(); - var config = parent.getConfig(); - - // Set language in configuration - config = config.setValue('language', language); - - return new Book({ - // Inherits config. logegr and list of ignored files - logger: parent.getLogger(), - config: config, - ignore: ignore, - - language: language, - fs: FS.reduceScope(parent.getContentFS(), language) - }); -}; - -module.exports = Book; diff --git a/lib/models/config.js b/lib/models/config.js deleted file mode 100644 index 6de52f9..0000000 --- a/lib/models/config.js +++ /dev/null @@ -1,181 +0,0 @@ -var is = require('is'); -var Immutable = require('immutable'); - -var File = require('./file'); -var PluginDependency = require('./pluginDependency'); -var configDefault = require('../constants/configDefault'); -var reducedObject = require('../utils/reducedObject'); - -var Config = Immutable.Record({ - file: File(), - values: configDefault -}, 'Config'); - -Config.prototype.getFile = function() { - return this.get('file'); -}; - -Config.prototype.getValues = function() { - return this.get('values'); -}; - -/** - * Return minimum version of configuration, - * Basically it returns the current config minus the default one - * @return {Map} - */ -Config.prototype.toReducedVersion = function() { - return reducedObject(configDefault, this.getValues()); -}; - -/** - * Render config as text - * @return {Promise<String>} - */ -Config.prototype.toText = function() { - return JSON.stringify(this.toReducedVersion().toJS(), null, 4); -}; - -/** - * Change the file for the configuration - * @param {File} file - * @return {Config} - */ -Config.prototype.setFile = function(file) { - return this.set('file', file); -}; - -/** - * Return a configuration value by its key path - * @param {String} key - * @return {Mixed} - */ -Config.prototype.getValue = function(keyPath, def) { - var values = this.getValues(); - keyPath = Config.keyToKeyPath(keyPath); - - if (!values.hasIn(keyPath)) { - return Immutable.fromJS(def); - } - - return values.getIn(keyPath); -}; - -/** - * Update a configuration value - * @param {String} key - * @param {Mixed} value - * @return {Config} - */ -Config.prototype.setValue = function(keyPath, value) { - keyPath = Config.keyToKeyPath(keyPath); - - value = Immutable.fromJS(value); - - var values = this.getValues(); - values = values.setIn(keyPath, value); - - return this.set('values', values); -}; - -/** - * Return a list of plugin dependencies - * @return {List<PluginDependency>} - */ -Config.prototype.getPluginDependencies = function() { - var plugins = this.getValue('plugins'); - - if (is.string(plugins)) { - return PluginDependency.listFromString(plugins); - } else { - return PluginDependency.listFromArray(plugins); - } -}; - -/** - * Return a plugin dependency by its name - * @param {String} name - * @return {PluginDependency} - */ -Config.prototype.getPluginDependency = function(name) { - var plugins = this.getPluginDependencies(); - - return plugins.find(function(dep) { - return dep.getName() === name; - }); -}; - -/** - * Update the list of plugins dependencies - * @param {List<PluginDependency>} - * @return {Config} - */ -Config.prototype.setPluginDependencies = function(deps) { - var plugins = PluginDependency.listToArray(deps); - - return this.setValue('plugins', plugins); -}; - - -/** - * Update values for an existing configuration - * @param {Object} values - * @returns {Config} - */ -Config.prototype.updateValues = function(values) { - values = Immutable.fromJS(values); - - return this.set('values', values); -}; - -/** - * Update values for an existing configuration - * @param {Config} config - * @param {Object} values - * @returns {Config} - */ -Config.prototype.mergeValues = function(values) { - var currentValues = this.getValues(); - values = Immutable.fromJS(values); - - currentValues = currentValues.mergeDeep(values); - - return this.set('values', currentValues); -}; - -/** - * Create a new config for a file - * @param {File} file - * @param {Object} values - * @returns {Config} - */ -Config.create = function(file, values) { - return new Config({ - file: file, - values: Immutable.fromJS(values) - }); -}; - -/** - * Create a new config - * @param {Object} values - * @returns {Config} - */ -Config.createWithValues = function(values) { - return new Config({ - values: Immutable.fromJS(values) - }); -}; - - -/** - * Convert a keyPath to an array of keys - * @param {String|Array} - * @return {Array} - */ -Config.keyToKeyPath = function(keyPath) { - if (is.string(keyPath)) keyPath = keyPath.split('.'); - return keyPath; -}; - -module.exports = Config; diff --git a/lib/models/file.js b/lib/models/file.js deleted file mode 100644 index 8ddd4af..0000000 --- a/lib/models/file.js +++ /dev/null @@ -1,89 +0,0 @@ -var path = require('path'); -var Immutable = require('immutable'); - -var parsers = require('../parsers'); - -var File = Immutable.Record({ - // Path of the file, relative to the FS - path: String(), - - // Time when file data last modified - mtime: Date() -}); - -File.prototype.getPath = function() { - return this.get('path'); -}; - -File.prototype.getMTime = function() { - return this.get('mtime'); -}; - -/** - Does the file exists / is set - - @return {Boolean} -*/ -File.prototype.exists = function() { - return Boolean(this.getPath()); -}; - -/** - Return type of file ('markdown' or 'asciidoc') - - @return {String} -*/ -File.prototype.getType = function() { - var parser = this.getParser(); - if (parser) { - return parser.getName(); - } else { - return undefined; - } -}; - -/** - Return extension of this file (lowercased) - - @return {String} -*/ -File.prototype.getExtension = function() { - return path.extname(this.getPath()).toLowerCase(); -}; - -/** - Return parser for this file - - @return {Parser} -*/ -File.prototype.getParser = function() { - return parsers.getByExt(this.getExtension()); -}; - -/** - Create a file from stats informations - - @param {String} filepath - @param {Object|fs.Stats} stat - @return {File} -*/ -File.createFromStat = function createFromStat(filepath, stat) { - return new File({ - path: filepath, - mtime: stat.mtime - }); -}; - -/** - Create a file with only a path - - @param {String} filepath - @return {File} -*/ -File.createWithFilepath = function createWithFilepath(filepath) { - return new File({ - path: filepath - }); -}; - -module.exports = File; diff --git a/lib/models/fs.js b/lib/models/fs.js deleted file mode 100644 index 16bd4ea..0000000 --- a/lib/models/fs.js +++ /dev/null @@ -1,307 +0,0 @@ -var path = require('path'); -var Immutable = require('immutable'); -var stream = require('stream'); - -var File = require('./file'); -var Promise = require('../utils/promise'); -var error = require('../utils/error'); -var PathUtil = require('../utils/path'); - -var FS = Immutable.Record({ - root: String(), - - fsExists: Function(), - fsReadFile: Function(), - fsStatFile: Function(), - fsReadDir: Function(), - - fsLoadObject: null, - fsReadAsStream: null -}); - -/** - Return path to the root - - @return {String} -*/ -FS.prototype.getRoot = function() { - return this.get('root'); -}; - -/** - Verify that a file is in the fs scope - - @param {String} filename - @return {Boolean} -*/ -FS.prototype.isInScope = function(filename) { - var rootPath = this.getRoot(); - filename = path.join(rootPath, filename); - - return PathUtil.isInRoot(rootPath, filename); -}; - -/** - Resolve a file in this FS - - @param {String} - @return {String} -*/ -FS.prototype.resolve = function() { - var rootPath = this.getRoot(); - var args = Array.prototype.slice.call(arguments); - var filename = path.join.apply(path, [rootPath].concat(args)); - filename = path.normalize(filename); - - if (!this.isInScope(filename)) { - throw error.FileOutOfScopeError({ - filename: filename, - root: this.root - }); - } - - return filename; -}; - -/** - Check if a file exists, run a Promise(true) if that's the case, Promise(false) otherwise - - @param {String} filename - @return {Promise<Boolean>} -*/ -FS.prototype.exists = function(filename) { - var that = this; - - return Promise() - .then(function() { - filename = that.resolve(filename); - var exists = that.get('fsExists'); - - return exists(filename); - }); -}; - -/** - Read a file and returns a promise with the content as a buffer - - @param {String} filename - @return {Promise<Buffer>} -*/ -FS.prototype.read = function(filename) { - var that = this; - - return Promise() - .then(function() { - filename = that.resolve(filename); - var read = that.get('fsReadFile'); - - return read(filename); - }); -}; - -/** - Read a file as a string (utf-8) - - @param {String} filename - @return {Promise<String>} -*/ -FS.prototype.readAsString = function(filename, encoding) { - encoding = encoding || 'utf8'; - - return this.read(filename) - .then(function(buf) { - return buf.toString(encoding); - }); -}; - -/** - Read file as a stream - - @param {String} filename - @return {Promise<Stream>} -*/ -FS.prototype.readAsStream = function(filename) { - var that = this; - var filepath = that.resolve(filename); - var fsReadAsStream = this.get('fsReadAsStream'); - - if (fsReadAsStream) { - return Promise(fsReadAsStream(filepath)); - } - - return this.read(filename) - .then(function(buf) { - var bufferStream = new stream.PassThrough(); - bufferStream.end(buf); - - return bufferStream; - }); -}; - -/** - Read stat infos about a file - - @param {String} filename - @return {Promise<File>} -*/ -FS.prototype.statFile = function(filename) { - var that = this; - - return Promise() - .then(function() { - var filepath = that.resolve(filename); - var stat = that.get('fsStatFile'); - - return stat(filepath); - }) - .then(function(stat) { - return File.createFromStat(filename, stat); - }); -}; - -/** - List files/directories in a directory. - Directories ends with '/' - - @param {String} dirname - @return {Promise<List<String>>} -*/ -FS.prototype.readDir = function(dirname) { - var that = this; - - return Promise() - .then(function() { - var dirpath = that.resolve(dirname); - var readDir = that.get('fsReadDir'); - - return readDir(dirpath); - }) - .then(function(files) { - return Immutable.List(files); - }); -}; - -/** - List only files in a diretcory - Directories ends with '/' - - @param {String} dirname - @return {Promise<List<String>>} -*/ -FS.prototype.listFiles = function(dirname) { - return this.readDir(dirname) - .then(function(files) { - return files.filterNot(pathIsFolder); - }); -}; - -/** - List all files in a directory - - @param {String} dirName - @param {Function(dirName)} filterFn: call it for each file/directory to test if it should stop iterating - @return {Promise<List<String>>} -*/ -FS.prototype.listAllFiles = function(dirName, filterFn) { - var that = this; - dirName = dirName || '.'; - - return this.readDir(dirName) - .then(function(files) { - return Promise.reduce(files, function(out, file) { - var isDirectory = pathIsFolder(file); - var newDirName = path.join(dirName, file); - - if (filterFn && filterFn(newDirName) === false) { - return out; - } - - if (!isDirectory) { - return out.push(newDirName); - } - - return that.listAllFiles(newDirName, filterFn) - .then(function(inner) { - return out.concat(inner); - }); - }, Immutable.List()); - }); -}; - -/** - Find a file in a folder (case insensitive) - Return the found filename - - @param {String} dirname - @param {String} filename - @return {Promise<String>} -*/ -FS.prototype.findFile = function(dirname, filename) { - return this.listFiles(dirname) - .then(function(files) { - return files.find(function(file) { - return (file.toLowerCase() == filename.toLowerCase()); - }); - }); -}; - -/** - Load a JSON file - By default, fs only supports JSON - - @param {String} filename - @return {Promise<Object>} -*/ -FS.prototype.loadAsObject = function(filename) { - var that = this; - var fsLoadObject = this.get('fsLoadObject'); - - return this.exists(filename) - .then(function(exists) { - if (!exists) { - var err = new Error('Module doesn\'t exist'); - err.code = 'MODULE_NOT_FOUND'; - - throw err; - } - - if (fsLoadObject) { - return fsLoadObject(that.resolve(filename)); - } else { - return that.readAsString(filename) - .then(function(str) { - return JSON.parse(str); - }); - } - }); -}; - -/** - Create a FS instance - - @param {Object} def - @return {FS} -*/ -FS.create = function create(def) { - return new FS(def); -}; - -/** - Create a new FS instance with a reduced scope - - @param {FS} fs - @param {String} scope - @return {FS} -*/ -FS.reduceScope = function reduceScope(fs, scope) { - return fs.set('root', path.join(fs.getRoot(), scope)); -}; - - -// .readdir return files/folder as a list of string, folder ending with '/' -function pathIsFolder(filename) { - var lastChar = filename[filename.length - 1]; - return lastChar == '/' || lastChar == '\\'; -} - -module.exports = FS;
\ No newline at end of file diff --git a/lib/models/glossary.js b/lib/models/glossary.js deleted file mode 100644 index 0033248..0000000 --- a/lib/models/glossary.js +++ /dev/null @@ -1,109 +0,0 @@ -var Immutable = require('immutable'); - -var error = require('../utils/error'); -var File = require('./file'); -var GlossaryEntry = require('./glossaryEntry'); -var parsers = require('../parsers'); - -var Glossary = Immutable.Record({ - file: File(), - entries: Immutable.OrderedMap() -}); - -Glossary.prototype.getFile = function() { - return this.get('file'); -}; - -Glossary.prototype.getEntries = function() { - return this.get('entries'); -}; - -/** - Return an entry by its name - - @param {String} name - @return {GlossaryEntry} -*/ -Glossary.prototype.getEntry = function(name) { - var entries = this.getEntries(); - var id = GlossaryEntry.nameToID(name); - - return entries.get(id); -}; - -/** - Render glossary as text - - @return {Promise<String>} -*/ -Glossary.prototype.toText = function(parser) { - var file = this.getFile(); - var entries = this.getEntries(); - - parser = parser? parsers.getByExt(parser) : file.getParser(); - - if (!parser) { - throw error.FileNotParsableError({ - filename: file.getPath() - }); - } - - return parser.renderGlossary(entries.toJS()); -}; - - -/** - Add/Replace an entry to a glossary - - @param {Glossary} glossary - @param {GlossaryEntry} entry - @return {Glossary} -*/ -Glossary.addEntry = function addEntry(glossary, entry) { - var id = entry.getID(); - var entries = glossary.getEntries(); - - entries = entries.set(id, entry); - return glossary.set('entries', entries); -}; - -/** - Add/Replace an entry to a glossary by name/description - - @param {Glossary} glossary - @param {GlossaryEntry} entry - @return {Glossary} -*/ -Glossary.addEntryByName = function addEntryByName(glossary, name, description) { - var entry = new GlossaryEntry({ - name: name, - description: description - }); - - return Glossary.addEntry(glossary, entry); -}; - -/** - Create a glossary from a list of entries - - @param {String} filename - @param {Array|List} entries - @return {Glossary} -*/ -Glossary.createFromEntries = function createFromEntries(file, entries) { - entries = entries.map(function(entry) { - if (!(entry instanceof GlossaryEntry)) { - entry = new GlossaryEntry(entry); - } - - return [entry.getID(), entry]; - }); - - return new Glossary({ - file: file, - entries: Immutable.OrderedMap(entries) - }); -}; - - -module.exports = Glossary; diff --git a/lib/models/glossaryEntry.js b/lib/models/glossaryEntry.js deleted file mode 100644 index 10791db..0000000 --- a/lib/models/glossaryEntry.js +++ /dev/null @@ -1,43 +0,0 @@ -var Immutable = require('immutable'); -var slug = require('github-slugid'); - -/* - A definition represents an entry in the glossary -*/ - -var GlossaryEntry = Immutable.Record({ - name: String(), - description: String() -}); - -GlossaryEntry.prototype.getName = function() { - return this.get('name'); -}; - -GlossaryEntry.prototype.getDescription = function() { - return this.get('description'); -}; - - -/** - Get identifier for this entry - - @retrun {Boolean} -*/ -GlossaryEntry.prototype.getID = function() { - return GlossaryEntry.nameToID(this.getName()); -}; - - -/** - Normalize a glossary entry name into a unique id - - @param {String} - @return {String} -*/ -GlossaryEntry.nameToID = function nameToID(name) { - return slug(name); -}; - - -module.exports = GlossaryEntry; diff --git a/lib/models/ignore.js b/lib/models/ignore.js deleted file mode 100644 index 499195e..0000000 --- a/lib/models/ignore.js +++ /dev/null @@ -1,42 +0,0 @@ -var Immutable = require('immutable'); -var IgnoreMutable = require('ignore'); - -/* - Immutable version of node-ignore -*/ -var Ignore = Immutable.Record({ - ignore: new IgnoreMutable() -}, 'Ignore'); - -Ignore.prototype.getIgnore = function() { - return this.get('ignore'); -}; - -/** - Test if a file is ignored by these rules - - @param {String} filePath - @return {Boolean} -*/ -Ignore.prototype.isFileIgnored = function(filename) { - var ignore = this.getIgnore(); - return ignore.filter([filename]).length == 0; -}; - -/** - Add rules - - @param {String} - @return {Ignore} -*/ -Ignore.prototype.add = function(rule) { - var ignore = this.getIgnore(); - var newIgnore = new IgnoreMutable(); - - newIgnore.add(ignore); - newIgnore.add(rule); - - return this.set('ignore', newIgnore); -}; - -module.exports = Ignore; diff --git a/lib/models/language.js b/lib/models/language.js deleted file mode 100644 index dcefbf6..0000000 --- a/lib/models/language.js +++ /dev/null @@ -1,21 +0,0 @@ -var path = require('path'); -var Immutable = require('immutable'); - -var Language = Immutable.Record({ - title: String(), - path: String() -}); - -Language.prototype.getTitle = function() { - return this.get('title'); -}; - -Language.prototype.getPath = function() { - return this.get('path'); -}; - -Language.prototype.getID = function() { - return path.basename(this.getPath()); -}; - -module.exports = Language; diff --git a/lib/models/languages.js b/lib/models/languages.js deleted file mode 100644 index 42f05f9..0000000 --- a/lib/models/languages.js +++ /dev/null @@ -1,71 +0,0 @@ -var Immutable = require('immutable'); - -var File = require('./file'); -var Language = require('./language'); - -var Languages = Immutable.Record({ - file: File(), - list: Immutable.OrderedMap() -}); - -Languages.prototype.getFile = function() { - return this.get('file'); -}; - -Languages.prototype.getList = function() { - return this.get('list'); -}; - -/** - Get default languages - - @return {Language} -*/ -Languages.prototype.getDefaultLanguage = function() { - return this.getList().first(); -}; - -/** - Get a language by its ID - - @param {String} lang - @return {Language} -*/ -Languages.prototype.getLanguage = function(lang) { - return this.getList().get(lang); -}; - -/** - Return count of langs - - @return {Number} -*/ -Languages.prototype.getCount = function() { - return this.getList().size; -}; - -/** - Create a languages list from a JS object - - @param {File} - @param {Array} - @return {Language} -*/ -Languages.createFromList = function(file, langs) { - var list = Immutable.OrderedMap(); - - langs.forEach(function(lang) { - lang = Language({ - title: lang.title, - path: lang.ref - }); - list = list.set(lang.getID(), lang); - }); - - return Languages({ - file: file, - list: list - }); -}; - -module.exports = Languages; diff --git a/lib/models/output.js b/lib/models/output.js deleted file mode 100644 index 0f008ec..0000000 --- a/lib/models/output.js +++ /dev/null @@ -1,107 +0,0 @@ -var Immutable = require('immutable'); - -var Book = require('./book'); -var LocationUtils = require('../utils/location'); - -var Output = Immutable.Record({ - book: Book(), - - // Name of the generator being used - generator: String(), - - // Map of plugins to use (String -> Plugin) - plugins: Immutable.OrderedMap(), - - // Map pages to generation (String -> Page) - pages: Immutable.OrderedMap(), - - // List assets (String) - assets: Immutable.List(), - - // Option for the generation - options: Immutable.Map(), - - // Internal state for the generation - state: Immutable.Map() -}); - -Output.prototype.getBook = function() { - return this.get('book'); -}; - -Output.prototype.getGenerator = function() { - return this.get('generator'); -}; - -Output.prototype.getPlugins = function() { - return this.get('plugins'); -}; - -Output.prototype.getPages = function() { - return this.get('pages'); -}; - -Output.prototype.getOptions = function() { - return this.get('options'); -}; - -Output.prototype.getAssets = function() { - return this.get('assets'); -}; - -Output.prototype.getState = function() { - return this.get('state'); -}; - -/** - Return a page byt its file path - - @param {String} filePath - @return {Page|undefined} -*/ -Output.prototype.getPage = function(filePath) { - filePath = LocationUtils.normalize(filePath); - - var pages = this.getPages(); - return pages.get(filePath); -}; - -/** - Get root folder for output - - @return {String} -*/ -Output.prototype.getRoot = function() { - return this.getOptions().get('root'); -}; - -/** - Update state of output - - @param {Map} newState - @return {Output} -*/ -Output.prototype.setState = function(newState) { - return this.set('state', newState); -}; - -/** - Update options - - @param {Map} newOptions - @return {Output} -*/ -Output.prototype.setOptions = function(newOptions) { - return this.set('options', newOptions); -}; - -/** - Return logegr for this output (same as book) - - @return {Logger} -*/ -Output.prototype.getLogger = function() { - return this.getBook().getLogger(); -}; - -module.exports = Output; diff --git a/lib/models/page.js b/lib/models/page.js deleted file mode 100644 index 275a034..0000000 --- a/lib/models/page.js +++ /dev/null @@ -1,70 +0,0 @@ -var Immutable = require('immutable'); -var yaml = require('js-yaml'); - -var File = require('./file'); - -var Page = Immutable.Record({ - file: File(), - - // Attributes extracted from the YAML header - attributes: Immutable.Map(), - - // Content of the page - content: String(), - - // Direction of the text - dir: String('ltr') -}); - -Page.prototype.getFile = function() { - return this.get('file'); -}; - -Page.prototype.getAttributes = function() { - return this.get('attributes'); -}; - -Page.prototype.getContent = function() { - return this.get('content'); -}; - -Page.prototype.getDir = function() { - return this.get('dir'); -}; - -/** - * Return page as text - * @return {String} -*/ -Page.prototype.toText = function() { - var attrs = this.getAttributes(); - var content = this.getContent(); - - if (attrs.size === 0) { - return content; - } - - var frontMatter = '---\n' + yaml.safeDump(attrs.toJS(), { skipInvalid: true }) + '---\n\n'; - return (frontMatter + content); -}; - -/** - * Return path of the page - * @return {String} -*/ -Page.prototype.getPath = function() { - return this.getFile().getPath(); -}; - -/** - * Create a page for a file - * @param {File} file - * @return {Page} -*/ -Page.createForFile = function(file) { - return new Page({ - file: file - }); -}; - -module.exports = Page; diff --git a/lib/models/parser.js b/lib/models/parser.js deleted file mode 100644 index d64542f..0000000 --- a/lib/models/parser.js +++ /dev/null @@ -1,122 +0,0 @@ -var Immutable = require('immutable'); -var Promise = require('../utils/promise'); - -var Parser = Immutable.Record({ - name: String(), - - // List of extensions that can be processed using this parser - extensions: Immutable.List(), - - // Parsing functions - readme: Function(), - langs: Function(), - summary: Function(), - glossary: Function(), - page: Function(), - inline: Function() -}); - -Parser.prototype.getName = function() { - return this.get('name'); -}; - -Parser.prototype.getExtensions = function() { - return this.get('extensions'); -}; - -// PARSE - -Parser.prototype.parseReadme = function(content) { - var readme = this.get('readme'); - return Promise(readme(content)); -}; - -Parser.prototype.parseSummary = function(content) { - var summary = this.get('summary'); - return Promise(summary(content)); -}; - -Parser.prototype.parseGlossary = function(content) { - var glossary = this.get('glossary'); - return Promise(glossary(content)); -}; - -Parser.prototype.preparePage = function(content) { - var page = this.get('page'); - if (!page.prepare) { - return Promise(content); - } - - return Promise(page.prepare(content)); -}; - -Parser.prototype.parsePage = function(content) { - var page = this.get('page'); - return Promise(page(content)); -}; - -Parser.prototype.parseInline = function(content) { - var inline = this.get('inline'); - return Promise(inline(content)); -}; - -Parser.prototype.parseLanguages = function(content) { - var langs = this.get('langs'); - return Promise(langs(content)); -}; - -Parser.prototype.parseInline = function(content) { - var inline = this.get('inline'); - return Promise(inline(content)); -}; - -// TO TEXT - -Parser.prototype.renderLanguages = function(content) { - var langs = this.get('langs'); - return Promise(langs.toText(content)); -}; - -Parser.prototype.renderSummary = function(content) { - var summary = this.get('summary'); - return Promise(summary.toText(content)); -}; - -Parser.prototype.renderGlossary = function(content) { - var glossary = this.get('glossary'); - return Promise(glossary.toText(content)); -}; - -/** - Test if this parser matches an extension - - @param {String} ext - @return {Boolean} -*/ -Parser.prototype.matchExtension = function(ext) { - var exts = this.getExtensions(); - return exts.includes(ext.toLowerCase()); -}; - -/** - Create a new parser using a module (gitbook-markdown, etc) - - @param {String} name - @param {Array<String>} extensions - @param {Object} module - @return {Parser} -*/ -Parser.create = function(name, extensions, module) { - return new Parser({ - name: name, - extensions: Immutable.List(extensions), - readme: module.readme, - langs: module.langs, - summary: module.summary, - glossary: module.glossary, - page: module.page, - inline: module.inline - }); -}; - -module.exports = Parser; diff --git a/lib/models/plugin.js b/lib/models/plugin.js deleted file mode 100644 index acabba9..0000000 --- a/lib/models/plugin.js +++ /dev/null @@ -1,169 +0,0 @@ -var Immutable = require('immutable'); - -var TemplateBlock = require('./templateBlock'); -var PluginDependency = require('./pluginDependency'); -var THEME_PREFIX = require('../constants/themePrefix'); - -var DEFAULT_VERSION = '*'; - -var Plugin = Immutable.Record({ - name: String(), - - // Requirement version (ex: ">1.0.0") - version: String(DEFAULT_VERSION), - - // Path to load this plugin - path: String(), - - // Depth of this plugin in the dependency tree - depth: Number(0), - - // Parent depending on this plugin - parent: String(), - - // Content of the "package.json" - package: Immutable.Map(), - - // Content of the package itself - content: Immutable.Map() -}, 'Plugin'); - -Plugin.prototype.getName = function() { - return this.get('name'); -}; - -Plugin.prototype.getPath = function() { - return this.get('path'); -}; - -Plugin.prototype.getVersion = function() { - return this.get('version'); -}; - -Plugin.prototype.getPackage = function() { - return this.get('package'); -}; - -Plugin.prototype.getContent = function() { - return this.get('content'); -}; - -Plugin.prototype.getDepth = function() { - return this.get('depth'); -}; - -Plugin.prototype.getParent = function() { - return this.get('parent'); -}; - -/** - * Return the ID on NPM for this plugin - * @return {String} - */ -Plugin.prototype.getNpmID = function() { - return PluginDependency.nameToNpmID(this.getName()); -}; - -/** - * Check if a plugin is loaded - * @return {Boolean} - */ -Plugin.prototype.isLoaded = function() { - return Boolean(this.getPackage().size > 0); -}; - -/** - * Check if a plugin is a theme given its name - * @return {Boolean} - */ -Plugin.prototype.isTheme = function() { - var name = this.getName(); - return (name && name.indexOf(THEME_PREFIX) === 0); -}; - -/** - * Return map of hooks - * @return {Map<String:Function>} - */ -Plugin.prototype.getHooks = function() { - return this.getContent().get('hooks') || Immutable.Map(); -}; - -/** - * Return infos about resources for a specific type - * @param {String} type - * @return {Map<String:Mixed>} - */ -Plugin.prototype.getResources = function(type) { - if (type != 'website' && type != 'ebook') { - throw new Error('Invalid assets type ' + type); - } - - var content = this.getContent(); - return (content.get(type) - || (type == 'website'? content.get('book') : null) - || Immutable.Map()); -}; - -/** - * Return map of filters - * @return {Map<String:Function>} - */ -Plugin.prototype.getFilters = function() { - return this.getContent().get('filters'); -}; - -/** - * Return map of blocks - * @return {Map<String:TemplateBlock>} - */ -Plugin.prototype.getBlocks = function() { - var blocks = this.getContent().get('blocks'); - blocks = blocks || Immutable.Map(); - - return blocks - .map(function(block, blockName) { - return TemplateBlock.create(blockName, block); - }); -}; - -/** - * Return a specific hook - * @param {String} name - * @return {Function|undefined} - */ -Plugin.prototype.getHook = function(name) { - return this.getHooks().get(name); -}; - -/** - * Create a plugin from a string - * @param {String} - * @return {Plugin} - */ -Plugin.createFromString = function(s) { - var parts = s.split('@'); - var name = parts[0]; - var version = parts.slice(1).join('@'); - - return new Plugin({ - name: name, - version: version || DEFAULT_VERSION - }); -}; - -/** - * Create a plugin from a dependency - * @param {PluginDependency} - * @return {Plugin} - */ -Plugin.createFromDep = function(dep) { - return new Plugin({ - name: dep.getName(), - version: dep.getVersion() - }); -}; - -Plugin.nameToNpmID = PluginDependency.nameToNpmID; - -module.exports = Plugin; diff --git a/lib/models/pluginDependency.js b/lib/models/pluginDependency.js deleted file mode 100644 index 8866294..0000000 --- a/lib/models/pluginDependency.js +++ /dev/null @@ -1,168 +0,0 @@ -var is = require('is'); -var semver = require('semver'); -var Immutable = require('immutable'); - -var PREFIX = require('../constants/pluginPrefix'); -var DEFAULT_VERSION = '*'; - -/* - * PluginDependency represents the informations about a plugin - * stored in config.plugins - */ -var PluginDependency = Immutable.Record({ - name: String(), - - // Requirement version (ex: ">1.0.0") - version: String(DEFAULT_VERSION), - - // Is this plugin enabled or disabled? - enabled: Boolean(true) -}, 'PluginDependency'); - -PluginDependency.prototype.getName = function() { - return this.get('name'); -}; - -PluginDependency.prototype.getVersion = function() { - return this.get('version'); -}; - -PluginDependency.prototype.isEnabled = function() { - return this.get('enabled'); -}; - -/** - * Toggle this plugin state - * @param {Boolean} - * @return {PluginDependency} - */ -PluginDependency.prototype.toggle = function(state) { - if (is.undef(state)) { - state = !this.isEnabled(); - } - - return this.set('enabled', state); -}; - -/** - * Return NPM ID for the dependency - * @return {String} - */ -PluginDependency.prototype.getNpmID = function() { - return PluginDependency.nameToNpmID(this.getName()); -}; - -/** - * Is the plugin using a git dependency - * @return {Boolean} - */ -PluginDependency.prototype.isGitDependency = function() { - return !semver.validRange(this.getVersion()); -}; - -/** - * Create a plugin with a name and a plugin - * @param {String} - * @return {Plugin|undefined} - */ -PluginDependency.create = function(name, version, enabled) { - if (is.undefined(enabled)) { - enabled = true; - } - - return new PluginDependency({ - name: name, - version: version || DEFAULT_VERSION, - enabled: Boolean(enabled) - }); -}; - -/** - * Create a plugin from a string - * @param {String} - * @return {Plugin|undefined} - */ -PluginDependency.createFromString = function(s) { - var parts = s.split('@'); - var name = parts[0]; - var version = parts.slice(1).join('@'); - var enabled = true; - - if (name[0] === '-') { - enabled = false; - name = name.slice(1); - } - - return new PluginDependency({ - name: name, - version: version || DEFAULT_VERSION, - enabled: enabled - }); -}; - -/** - * Create a PluginDependency from a string - * @param {String} - * @return {List<PluginDependency>} - */ -PluginDependency.listFromString = function(s) { - var parts = s.split(','); - return PluginDependency.listFromArray(parts); -}; - -/** - * Create a PluginDependency from an array - * @param {Array} - * @return {List<PluginDependency>} - */ -PluginDependency.listFromArray = function(arr) { - return Immutable.List(arr) - .map(function(entry) { - if (is.string(entry)) { - return PluginDependency.createFromString(entry); - } else { - return PluginDependency({ - name: entry.get('name'), - version: entry.get('version') - }); - } - }) - .filter(function(dep) { - return Boolean(dep.getName()); - }); -}; - -/** - * Export plugin dependencies as an array - * @param {List<PluginDependency>} list - * @return {Array<String>} - */ -PluginDependency.listToArray = function(list) { - return list - .map(function(dep) { - var result = ''; - - if (!dep.isEnabled()) { - result += '-'; - } - - result += dep.getName(); - if (dep.getVersion() !== DEFAULT_VERSION) { - result += '@' + dep.getVersion(); - } - - return result; - }) - .toJS(); -}; - -/** - * Return NPM id for a plugin name - * @param {String} - * @return {String} - */ -PluginDependency.nameToNpmID = function(s) { - return PREFIX + s; -}; - -module.exports = PluginDependency; diff --git a/lib/models/readme.js b/lib/models/readme.js deleted file mode 100644 index c655c82..0000000 --- a/lib/models/readme.js +++ /dev/null @@ -1,40 +0,0 @@ -var Immutable = require('immutable'); - -var File = require('./file'); - -var Readme = Immutable.Record({ - file: File(), - title: String(), - description: String() -}); - -Readme.prototype.getFile = function() { - return this.get('file'); -}; - -Readme.prototype.getTitle = function() { - return this.get('title'); -}; - -Readme.prototype.getDescription = function() { - return this.get('description'); -}; - -/** - Create a new readme - - @param {File} file - @param {Object} def - @return {Readme} -*/ -Readme.create = function(file, def) { - def = def || {}; - - return new Readme({ - file: file, - title: def.title || '', - description: def.description || '' - }); -}; - -module.exports = Readme; diff --git a/lib/models/summary.js b/lib/models/summary.js deleted file mode 100644 index 70f0535..0000000 --- a/lib/models/summary.js +++ /dev/null @@ -1,228 +0,0 @@ -var is = require('is'); -var Immutable = require('immutable'); - -var error = require('../utils/error'); -var LocationUtils = require('../utils/location'); -var File = require('./file'); -var SummaryPart = require('./summaryPart'); -var SummaryArticle = require('./summaryArticle'); -var parsers = require('../parsers'); - -var Summary = Immutable.Record({ - file: File(), - parts: Immutable.List() -}, 'Summary'); - -Summary.prototype.getFile = function() { - return this.get('file'); -}; - -Summary.prototype.getParts = function() { - return this.get('parts'); -}; - -/** - Return a part by its index - - @param {Number} - @return {Part} -*/ -Summary.prototype.getPart = function(i) { - var parts = this.getParts(); - return parts.get(i); -}; - -/** - Return an article using an iterator to find it. - if "partIter" is set, it can also return a Part. - - @param {Function} iter - @param {Function} partIter - @return {Article|Part} -*/ -Summary.prototype.getArticle = function(iter, partIter) { - var parts = this.getParts(); - - return parts.reduce(function(result, part) { - if (result) return result; - - if (partIter && partIter(part)) return part; - return SummaryArticle.findArticle(part, iter); - }, null); -}; - - -/** - Return a part/article by its level - - @param {String} level - @return {Article|Part} -*/ -Summary.prototype.getByLevel = function(level) { - function iterByLevel(article) { - return (article.getLevel() === level); - } - - return this.getArticle(iterByLevel, iterByLevel); -}; - -/** - Return an article by its path - - @param {String} filePath - @return {Article} -*/ -Summary.prototype.getByPath = function(filePath) { - return this.getArticle(function(article) { - var articlePath = article.getPath(); - - return ( - articlePath && - LocationUtils.areIdenticalPaths(articlePath, filePath) - ); - }); -}; - -/** - Return the first article - - @return {Article} -*/ -Summary.prototype.getFirstArticle = function() { - return this.getArticle(function(article) { - return true; - }); -}; - -/** - Return next article of an article - - @param {Article} current - @return {Article} -*/ -Summary.prototype.getNextArticle = function(current) { - var level = is.string(current)? current : current.getLevel(); - var wasPrev = false; - - return this.getArticle(function(article) { - if (wasPrev) return true; - - wasPrev = article.getLevel() == level; - return false; - }); -}; - -/** - Return previous article of an article - - @param {Article} current - @return {Article} -*/ -Summary.prototype.getPrevArticle = function(current) { - var level = is.string(current)? current : current.getLevel(); - var prev = undefined; - - this.getArticle(function(article) { - if (article.getLevel() == level) { - return true; - } - - prev = article; - return false; - }); - - return prev; -}; - -/** - Return the parent article, or parent part of an article - - @param {String|Article} current - @return {Article|Part|Null} -*/ -Summary.prototype.getParent = function (level) { - // Coerce to level - level = is.string(level)? level : level.getLevel(); - - // Get parent level - var parentLevel = getParentLevel(level); - if (!parentLevel) { - return null; - } - - // Get parent of the position - var parentArticle = this.getByLevel(parentLevel); - return parentArticle || null; -}; - -/** - Render summary as text - - @param {String} parseExt Extension of the parser to use - @return {Promise<String>} -*/ -Summary.prototype.toText = function(parseExt) { - var file = this.getFile(); - var parts = this.getParts(); - - var parser = parseExt? parsers.getByExt(parseExt) : file.getParser(); - - if (!parser) { - throw error.FileNotParsableError({ - filename: file.getPath() - }); - } - - return parser.renderSummary({ - parts: parts.toJS() - }); -}; - -/** - Return all articles as a list - - @return {List<Article>} -*/ -Summary.prototype.getArticlesAsList = function() { - var accu = []; - - this.getArticle(function(article) { - accu.push(article); - }); - - return Immutable.List(accu); -}; - -/** - Create a new summary for a list of parts - - @param {Lust|Array} parts - @return {Summary} -*/ -Summary.createFromParts = function createFromParts(file, parts) { - parts = parts.map(function(part, i) { - if (part instanceof SummaryPart) { - return part; - } - - return SummaryPart.create(part, i + 1); - }); - - return new Summary({ - file: file, - parts: new Immutable.List(parts) - }); -}; - -/** - Returns parent level of a level - - @param {String} level - @return {String} -*/ -function getParentLevel(level) { - var parts = level.split('.'); - return parts.slice(0, -1).join('.'); -} - -module.exports = Summary; diff --git a/lib/models/summaryArticle.js b/lib/models/summaryArticle.js deleted file mode 100644 index 6da8d1d..0000000 --- a/lib/models/summaryArticle.js +++ /dev/null @@ -1,189 +0,0 @@ -var Immutable = require('immutable'); - -var location = require('../utils/location'); - -/* - An article represents an entry in the Summary / table of Contents -*/ - -var SummaryArticle = Immutable.Record({ - level: String(), - title: String(), - ref: String(), - articles: Immutable.List() -}, 'SummaryArticle'); - -SummaryArticle.prototype.getLevel = function() { - return this.get('level'); -}; - -SummaryArticle.prototype.getTitle = function() { - return this.get('title'); -}; - -SummaryArticle.prototype.getRef = function() { - return this.get('ref'); -}; - -SummaryArticle.prototype.getArticles = function() { - return this.get('articles'); -}; - -/** - * Return how deep the article is. - * The README has a depth of 1 - * - * @return {Number} - */ -SummaryArticle.prototype.getDepth = function() { - return (this.getLevel().split('.').length - 1); -}; - -/** - * Get path (without anchor) to the pointing file. - * It also normalizes the file path. - * - * @return {String} - */ -SummaryArticle.prototype.getPath = function() { - if (this.isExternal()) { - return undefined; - } - - var ref = this.getRef(); - if (!ref) { - return undefined; - } - - var parts = ref.split('#'); - - var pathname = (parts.length > 1? parts.slice(0, -1).join('#') : ref); - - // Normalize path to remove ('./', '/...', etc) - return location.flatten(pathname); -}; - -/** - * Return url if article is external - * - * @return {String} - */ -SummaryArticle.prototype.getUrl = function() { - return this.isExternal()? this.getRef() : undefined; -}; - -/** - * Get anchor for this article (or undefined) - * - * @return {String} - */ -SummaryArticle.prototype.getAnchor = function() { - var ref = this.getRef(); - var parts = ref.split('#'); - - var anchor = (parts.length > 1? '#' + parts[parts.length - 1] : undefined); - return anchor; -}; - -/** - * Create a new level for a new child article - * - * @return {String} - */ -SummaryArticle.prototype.createChildLevel = function() { - var level = this.getLevel(); - var subArticles = this.getArticles(); - var childLevel = level + '.' + (subArticles.size + 1); - - return childLevel; -}; - -/** - * Is article pointing to a page of an absolute url - * - * @return {Boolean} - */ -SummaryArticle.prototype.isPage = function() { - return !this.isExternal() && this.getRef(); -}; - -/** - * 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} - */ -SummaryArticle.prototype.isExternal = function() { - return location.isExternal(this.getRef()); -}; - -/** - * Create a SummaryArticle - * - * @param {Object} def - * @return {SummaryArticle} - */ -SummaryArticle.create = function(def, level) { - var articles = (def.articles || []).map(function(article, i) { - if (article instanceof SummaryArticle) { - return article; - } - return SummaryArticle.create(article, [level, i + 1].join('.')); - }); - - return new SummaryArticle({ - level: level, - title: def.title, - ref: def.ref || def.path || '', - articles: Immutable.List(articles) - }); -}; - -/** - * Find an article from a base one - * - * @param {Article|Part} base - * @param {Function(article)} iter - * @return {Article} - */ -SummaryArticle.findArticle = function(base, iter) { - var articles = base.getArticles(); - - return articles.reduce(function(result, article) { - if (result) return result; - - if (iter(article)) { - return article; - } - - return SummaryArticle.findArticle(article, iter); - }, null); -}; - - -module.exports = SummaryArticle; diff --git a/lib/models/summaryPart.js b/lib/models/summaryPart.js deleted file mode 100644 index f0e6f57..0000000 --- a/lib/models/summaryPart.js +++ /dev/null @@ -1,61 +0,0 @@ -var Immutable = require('immutable'); - -var SummaryArticle = require('./summaryArticle'); - -/* - A part represents a section in the Summary / table of Contents -*/ - -var SummaryPart = Immutable.Record({ - level: String(), - title: String(), - articles: Immutable.List() -}); - -SummaryPart.prototype.getLevel = function() { - return this.get('level'); -}; - -SummaryPart.prototype.getTitle = function() { - return this.get('title'); -}; - -SummaryPart.prototype.getArticles = function() { - return this.get('articles'); -}; - -/** - * Create a new level for a new child article - * - * @return {String} - */ -SummaryPart.prototype.createChildLevel = function() { - var level = this.getLevel(); - var subArticles = this.getArticles(); - var childLevel = level + '.' + (subArticles.size + 1); - - return childLevel; -}; - -/** - * Create a SummaryPart - * - * @param {Object} def - * @return {SummaryPart} - */ -SummaryPart.create = function(def, level) { - var articles = (def.articles || []).map(function(article, i) { - if (article instanceof SummaryArticle) { - return article; - } - return SummaryArticle.create(article, [level, i + 1].join('.')); - }); - - return new SummaryPart({ - level: String(level), - title: def.title, - articles: Immutable.List(articles) - }); -}; - -module.exports = SummaryPart; diff --git a/lib/models/templateBlock.js b/lib/models/templateBlock.js deleted file mode 100644 index 458f084..0000000 --- a/lib/models/templateBlock.js +++ /dev/null @@ -1,281 +0,0 @@ -var is = require('is'); -var extend = require('extend'); -var Immutable = require('immutable'); - -var Promise = require('../utils/promise'); -var genKey = require('../utils/genKey'); -var TemplateShortcut = require('./templateShortcut'); - -var NODE_ENDARGS = '%%endargs%%'; - -var TemplateBlock = Immutable.Record({ - // Name of block, also the start tag - name: String(), - - // End tag, default to "end<name>" - end: String(), - - // Function to process the block content - process: Function(), - - // List of String, for inner block tags - blocks: Immutable.List(), - - // List of shortcuts to replace with this block - shortcuts: Immutable.Map() -}, 'TemplateBlock'); - -TemplateBlock.prototype.getName = function() { - return this.get('name'); -}; - -TemplateBlock.prototype.getEndTag = function() { - return this.get('end') || ('end' + this.getName()); -}; - -TemplateBlock.prototype.getProcess = function() { - return this.get('process'); -}; - -TemplateBlock.prototype.getBlocks = function() { - return this.get('blocks'); -}; - - -/** - * Return shortcuts associated with this block or undefined - * @return {TemplateShortcut|undefined} - */ -TemplateBlock.prototype.getShortcuts = function() { - var shortcuts = this.get('shortcuts'); - if (shortcuts.size === 0) { - return undefined; - } - - return TemplateShortcut.createForBlock(this, shortcuts); -}; - -/** - * Return name for the nunjucks extension - * @return {String} - */ -TemplateBlock.prototype.getExtensionName = function() { - return 'Block' + this.getName() + 'Extension'; -}; - -/** - * Return a nunjucks extension to represents this block - * @return {Nunjucks.Extension} - */ -TemplateBlock.prototype.toNunjucksExt = function(mainContext, blocksOutput) { - blocksOutput = blocksOutput || {}; - - var that = this; - var name = this.getName(); - var endTag = this.getEndTag(); - var blocks = this.getBlocks().toJS(); - - function Ext() { - this.tags = [name]; - - this.parse = function(parser, nodes) { - var lastBlockName = null; - var lastBlockArgs = null; - var allBlocks = blocks.concat([endTag]); - - // Parse first block - var tok = parser.nextToken(); - lastBlockArgs = parser.parseSignature(null, true); - parser.advanceAfterBlockEnd(tok.value); - - var args = new nodes.NodeList(); - var bodies = []; - var blockNamesNode = new nodes.Array(tok.lineno, tok.colno); - var blockArgCounts = new nodes.Array(tok.lineno, tok.colno); - - // Parse while we found "end<block>" - do { - // Read body - var currentBody = parser.parseUntilBlocks.apply(parser, allBlocks); - - // Handle body with previous block name and args - blockNamesNode.addChild(new nodes.Literal(args.lineno, args.colno, lastBlockName)); - blockArgCounts.addChild(new nodes.Literal(args.lineno, args.colno, lastBlockArgs.children.length)); - bodies.push(currentBody); - - // Append arguments of this block as arguments of the run function - lastBlockArgs.children.forEach(function(child) { - args.addChild(child); - }); - - // Read new block - lastBlockName = parser.nextToken().value; - - // Parse signature and move to the end of the block - if (lastBlockName != endTag) { - lastBlockArgs = parser.parseSignature(null, true); - } - - parser.advanceAfterBlockEnd(lastBlockName); - } while (lastBlockName != endTag); - - args.addChild(blockNamesNode); - args.addChild(blockArgCounts); - args.addChild(new nodes.Literal(args.lineno, args.colno, NODE_ENDARGS)); - - return new nodes.CallExtensionAsync(this, 'run', args, bodies); - }; - - this.run = function(context) { - var fnArgs = Array.prototype.slice.call(arguments, 1); - - var args; - var blocks = []; - var bodies = []; - var blockNames; - var blockArgCounts; - var callback; - - // Extract callback - callback = fnArgs.pop(); - - // Detect end of arguments - var endArgIndex = fnArgs.indexOf(NODE_ENDARGS); - - // Extract arguments and bodies - args = fnArgs.slice(0, endArgIndex); - bodies = fnArgs.slice(endArgIndex + 1); - - // Extract block counts - blockArgCounts = args.pop(); - blockNames = args.pop(); - - // Recreate list of blocks - blockNames.forEach(function(name, i) { - var countArgs = blockArgCounts[i]; - var blockBody = bodies.shift(); - - var blockArgs = countArgs > 0? args.slice(0, countArgs) : []; - args = args.slice(countArgs); - var blockKwargs = extractKwargs(blockArgs); - - blocks.push({ - name: name, - body: blockBody(), - args: blockArgs, - kwargs: blockKwargs - }); - }); - - var mainBlock = blocks.shift(); - mainBlock.blocks = blocks; - - Promise() - .then(function() { - var ctx = extend({ - ctx: context - }, mainContext || {}); - - return that.applyBlock(mainBlock, ctx); - }) - .then(function(result) { - return that.blockResultToHtml(result, blocksOutput); - }) - .nodeify(callback); - }; - } - - return Ext; -}; - -/** - * Apply a block to a content - * @param {Object} inner - * @param {Object} context - * @return {Promise<String>|String} - */ -TemplateBlock.prototype.applyBlock = function(inner, context) { - var processFn = this.getProcess(); - - inner = inner || {}; - inner.args = inner.args || []; - inner.kwargs = inner.kwargs || {}; - inner.blocks = inner.blocks || []; - - var r = processFn.call(context, inner); - - if (Promise.isPromiseAlike(r)) { - return r.then(this.normalizeBlockResult.bind(this)); - } else { - return this.normalizeBlockResult(r); - } -}; - -/** - * Normalize result from a block process function - * @param {Object|String} result - * @return {Object} - */ -TemplateBlock.prototype.normalizeBlockResult = function(result) { - if (is.string(result)) { - result = { body: result }; - } - result.name = this.getName(); - - return result; -}; - -/** - * Convert a block result to HTML - * @param {Object} result - * @param {Object} blocksOutput: stored post processing blocks in this object - * @return {String} - */ -TemplateBlock.prototype.blockResultToHtml = function(result, blocksOutput) { - var indexedKey; - var toIndex = (!result.parse) || (result.post !== undefined); - - if (toIndex) { - indexedKey = genKey(); - blocksOutput[indexedKey] = result; - } - - // Parsable block, just return it - if (result.parse) { - return result.body; - } - - // Return it as a position marker - return '{{-%' + indexedKey + '%-}}'; - -}; - -/** - * Create a template block from a function or an object - * @param {String} blockName - * @param {Object} block - * @return {TemplateBlock} - */ -TemplateBlock.create = function(blockName, block) { - if (is.fn(block)) { - block = new Immutable.Map({ - process: block - }); - } - - block = new TemplateBlock(block); - block = block.set('name', blockName); - return block; -}; - -/** - * Extract kwargs from an arguments array - * @param {Array} args - * @return {Object} - */ -function extractKwargs(args) { - var last = args[args.length - 1]; - return (is.object(last) && last.__keywords)? args.pop() : {}; -} - -module.exports = TemplateBlock; diff --git a/lib/models/templateEngine.js b/lib/models/templateEngine.js deleted file mode 100644 index 5724d55..0000000 --- a/lib/models/templateEngine.js +++ /dev/null @@ -1,139 +0,0 @@ -var nunjucks = require('nunjucks'); -var Immutable = require('immutable'); - -var TemplateEngine = Immutable.Record({ - // Map of {TemplateBlock} - blocks: Immutable.Map(), - - // Map of Extension - extensions: Immutable.Map(), - - // Map of filters: {String} name -> {Function} fn - filters: Immutable.Map(), - - // Map of globals: {String} name -> {Mixed} - globals: Immutable.Map(), - - // Context for filters / blocks - context: Object(), - - // Nunjucks loader - loader: nunjucks.FileSystemLoader('views') -}, 'TemplateEngine'); - -TemplateEngine.prototype.getBlocks = function() { - return this.get('blocks'); -}; - -TemplateEngine.prototype.getGlobals = function() { - return this.get('globals'); -}; - -TemplateEngine.prototype.getFilters = function() { - return this.get('filters'); -}; - -TemplateEngine.prototype.getShortcuts = function() { - return this.get('shortcuts'); -}; - -TemplateEngine.prototype.getLoader = function() { - return this.get('loader'); -}; - -TemplateEngine.prototype.getContext = function() { - return this.get('context'); -}; - -TemplateEngine.prototype.getExtensions = function() { - return this.get('extensions'); -}; - -/** - Return a block by its name (or undefined) - - @param {String} name - @return {TemplateBlock} -*/ -TemplateEngine.prototype.getBlock = function(name) { - var blocks = this.getBlocks(); - return blocks.find(function(block) { - return block.getName() === name; - }); -}; - -/** - Return a nunjucks environment from this configuration - - @return {Nunjucks.Environment} -*/ -TemplateEngine.prototype.toNunjucks = function(blocksOutput) { - var loader = this.getLoader(); - var blocks = this.getBlocks(); - var filters = this.getFilters(); - var globals = this.getGlobals(); - var extensions = this.getExtensions(); - var context = this.getContext(); - - var env = new nunjucks.Environment( - loader, - { - // Escaping is done after by the asciidoc/markdown parser - autoescape: false, - - // Syntax - tags: { - blockStart: '{%', - blockEnd: '%}', - variableStart: '{{', - variableEnd: '}}', - commentStart: '{###', - commentEnd: '###}' - } - } - ); - - // Add filters - filters.forEach(function(filterFn, filterName) { - env.addFilter(filterName, filterFn.bind(context)); - }); - - // Add blocks - blocks.forEach(function(block) { - var extName = block.getExtensionName(); - var Ext = block.toNunjucksExt(context, blocksOutput); - - env.addExtension(extName, new Ext()); - }); - - // Add globals - globals.forEach(function(globalValue, globalName) { - env.addGlobal(globalName, globalValue); - }); - - // Add other extensions - extensions.forEach(function(ext, extName) { - env.addExtension(extName, ext); - }); - - return env; -}; - -/** - Create a template engine - - @param {Object} def - @return {TemplateEngine} -*/ -TemplateEngine.create = function(def) { - return new TemplateEngine({ - blocks: Immutable.List(def.blocks || []), - extensions: Immutable.Map(def.extensions || {}), - filters: Immutable.Map(def.filters || {}), - globals: Immutable.Map(def.globals || {}), - context: def.context, - loader: def.loader - }); -}; - -module.exports = TemplateEngine; diff --git a/lib/models/templateOutput.js b/lib/models/templateOutput.js deleted file mode 100644 index ae63c06..0000000 --- a/lib/models/templateOutput.js +++ /dev/null @@ -1,42 +0,0 @@ -var Immutable = require('immutable'); - -var TemplateOutput = Immutable.Record({ - // Text content of the template - content: String(), - - // Map of blocks to replace / post process - blocks: Immutable.Map() -}, 'TemplateOutput'); - -TemplateOutput.prototype.getContent = function() { - return this.get('content'); -}; - -TemplateOutput.prototype.getBlocks = function() { - return this.get('blocks'); -}; - -/** - * Update content of this output - * @param {String} content - * @return {TemplateContent} - */ -TemplateOutput.prototype.setContent = function(content) { - return this.set('content', content); -}; - -/** - * Create a TemplateOutput from a text content - * and an object containing block definition - * @param {String} content - * @param {Object} blocks - * @return {TemplateOutput} - */ -TemplateOutput.create = function(content, blocks) { - return new TemplateOutput({ - content: content, - blocks: Immutable.fromJS(blocks) - }); -}; - -module.exports = TemplateOutput; diff --git a/lib/models/templateShortcut.js b/lib/models/templateShortcut.js deleted file mode 100644 index 309fa6d..0000000 --- a/lib/models/templateShortcut.js +++ /dev/null @@ -1,73 +0,0 @@ -var Immutable = require('immutable'); -var is = require('is'); - -/* - A TemplateShortcut is defined in plugin's template blocks - to replace content with a templating block using delimiters. -*/ -var TemplateShortcut = Immutable.Record({ - // List of parser names accepting this shortcut - parsers: Immutable.Map(), - - start: String(), - end: String(), - - startTag: String(), - endTag: String() -}, 'TemplateShortcut'); - -TemplateShortcut.prototype.getStart = function() { - return this.get('start'); -}; - -TemplateShortcut.prototype.getEnd = function() { - return this.get('end'); -}; - -TemplateShortcut.prototype.getStartTag = function() { - return this.get('startTag'); -}; - -TemplateShortcut.prototype.getEndTag = function() { - return this.get('endTag'); -}; - -TemplateShortcut.prototype.getParsers = function() { - return this.get('parsers'); -}; - -/** - Test if this shortcut accept a parser - - @param {Parser|String} parser - @return {Boolean} -*/ -TemplateShortcut.prototype.acceptParser = function(parser) { - if (!is.string(parser)) { - parser = parser.getName(); - } - - var parserNames = this.get('parsers'); - return parserNames.includes(parser); -}; - -/** - Create a shortcut for a block - - @param {TemplateBlock} block - @param {Map} details - @return {TemplateShortcut} -*/ -TemplateShortcut.createForBlock = function(block, details) { - details = Immutable.fromJS(details); - - return new TemplateShortcut({ - parsers: details.get('parsers'), - start: details.get('start'), - end: details.get('end'), - startTag: block.getName(), - endTag: block.getEndTag() - }); -}; - -module.exports = TemplateShortcut; |