diff options
Diffstat (limited to 'lib/models')
-rw-r--r-- | lib/models/__tests__/plugin.js | 29 | ||||
-rw-r--r-- | lib/models/book.js | 146 | ||||
-rw-r--r-- | lib/models/config.js | 47 | ||||
-rw-r--r-- | lib/models/file.js | 55 | ||||
-rw-r--r-- | lib/models/fs.js | 277 | ||||
-rw-r--r-- | lib/models/generator.js | 13 | ||||
-rw-r--r-- | lib/models/glossary.js | 86 | ||||
-rw-r--r-- | lib/models/glossaryEntry.js | 45 | ||||
-rw-r--r-- | lib/models/language.js | 21 | ||||
-rw-r--r-- | lib/models/languages.js | 37 | ||||
-rw-r--r-- | lib/models/page.js | 39 | ||||
-rw-r--r-- | lib/models/plugin.js | 84 | ||||
-rw-r--r-- | lib/models/readme.js | 30 | ||||
-rw-r--r-- | lib/models/summary.js | 41 | ||||
-rw-r--r-- | lib/models/summaryArticle.js | 100 | ||||
-rw-r--r-- | lib/models/summaryPart.js | 42 |
16 files changed, 1092 insertions, 0 deletions
diff --git a/lib/models/__tests__/plugin.js b/lib/models/__tests__/plugin.js new file mode 100644 index 0000000..81d9d51 --- /dev/null +++ b/lib/models/__tests__/plugin.js @@ -0,0 +1,29 @@ +jest.autoMockOff(); + +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/book.js b/lib/models/book.js new file mode 100644 index 0000000..da0deee --- /dev/null +++ b/lib/models/book.js @@ -0,0 +1,146 @@ +var path = require('path'); +var Immutable = require('immutable'); +var Ignore = require('ignore'); + +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 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() +}); + +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.getPages = function() { + return this.get('pages'); +}; + +/** + 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(); +}; + +/** + 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(); + return ignore.filter([filename]).length == 0; +}; + +/** + 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); +}; + +/** + Create a book using a filesystem + + @param {FS} fs + @return {Book} +*/ +Book.createForFS = function createForFS(fs) { + return new Book({ + fs: fs + }); +}; + +module.exports = Book; diff --git a/lib/models/config.js b/lib/models/config.js new file mode 100644 index 0000000..fd4201d --- /dev/null +++ b/lib/models/config.js @@ -0,0 +1,47 @@ +var is = require('is'); +var Immutable = require('immutable'); + +var File = require('./file'); + +var Config = Immutable.Record({ + file: File(), + values: Immutable.Map() +}); + +Config.prototype.getPath = function() { + return this.get('path'); +}; + +Config.prototype.getValues = function() { + return this.get('values'); +}; + +/** + Return a configuration value by its key path + + @param {String} key + @return {Mixed} +*/ +Config.prototype.getValue = function(keyPath, def) { + var values = this.getValues(); + if (is.string(keyPath)) keyPath = keyPath.split('.'); + + return values.getIn(keyPath) || def; +}; + +/** + Create a new config, throw error if invalid + + @param {File} file + @param {Object} values + @returns {Config} +*/ +Config.create = function(file, values) { + return new Config({ + file: file, + values: Immutable.fromJS(values) + }); +}; + + +module.exports = Config; diff --git a/lib/models/file.js b/lib/models/file.js new file mode 100644 index 0000000..ebfe629 --- /dev/null +++ b/lib/models/file.js @@ -0,0 +1,55 @@ +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'); +}; + +/** + 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 + }); +}; + + +module.exports = File; diff --git a/lib/models/fs.js b/lib/models/fs.js new file mode 100644 index 0000000..2400ff2 --- /dev/null +++ b/lib/models/fs.js @@ -0,0 +1,277 @@ +var path = require('path'); +var Immutable = require('immutable'); + +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 +}); + +/** + 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.resolve(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.resolve.apply(path, [rootPath].concat(args)); + + 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 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 + @return {Promise<List<String>>} +*/ +FS.prototype.listAllFiles = function(folder) { + var that = this; + folder = folder || '.'; + + return this.readDir(folder) + .then(function(files) { + return Promise.reduce(files, function(out, file) { + var isDirectory = pathIsFolder(file); + + if (!isDirectory) { + return out.push(file); + } + + return that.listAllFiles(path.join(folder, file)) + .then(function(inner) { + return out.concat(inner); + }); + }, Immutable.List()); + }) + .then(function(files) { + return files.map(function(file) { + return path.join(folder, file); + }); + }); +}; + +/** + Find a file in a folder (case incensitive) + 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/generator.js b/lib/models/generator.js new file mode 100644 index 0000000..afc65b1 --- /dev/null +++ b/lib/models/generator.js @@ -0,0 +1,13 @@ +var Immutable = require('immutable'); + +var Generator = Immutable.Record({ + name: String() +}); + + + +Generator.create = function(def) { + return new Generator(def); +}; + +module.exports = Generator; diff --git a/lib/models/glossary.js b/lib/models/glossary.js new file mode 100644 index 0000000..51aa370 --- /dev/null +++ b/lib/models/glossary.js @@ -0,0 +1,86 @@ +var Immutable = require('immutable'); + +var File = require('./file'); +var GlossaryEntry = require('./glossaryEntry'); + +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); +}; + +/** + 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 new file mode 100644 index 0000000..9c390c5 --- /dev/null +++ b/lib/models/glossaryEntry.js @@ -0,0 +1,45 @@ +var Immutable = require('immutable'); + +/* + 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 name.toLowerCase() + .replace(/[\/\\\?\%\*\:\;\|\"\'\\<\\>\#\$\(\)\!\.\@]/g, '') + .replace(/ /g, '_') + .trim(); +}; + + +module.exports = GlossaryEntry; diff --git a/lib/models/language.js b/lib/models/language.js new file mode 100644 index 0000000..dcefbf6 --- /dev/null +++ b/lib/models/language.js @@ -0,0 +1,21 @@ +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 new file mode 100644 index 0000000..c64857f --- /dev/null +++ b/lib/models/languages.js @@ -0,0 +1,37 @@ +var Immutable = require('immutable'); + +var File = require('./file'); + +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); +}; + +module.exports = Languages; diff --git a/lib/models/page.js b/lib/models/page.js new file mode 100644 index 0000000..1ac0d50 --- /dev/null +++ b/lib/models/page.js @@ -0,0 +1,39 @@ +var Immutable = require('immutable'); + +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() +}); + +Page.prototype.getFile = function() { + return this.get('file'); +}; + +Page.prototype.getAttributes = function() { + return this.get('attributes'); +}; + +Page.prototype.getContent = function() { + return this.get('content'); +}; + +/** + 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/plugin.js b/lib/models/plugin.js new file mode 100644 index 0000000..b6affd4 --- /dev/null +++ b/lib/models/plugin.js @@ -0,0 +1,84 @@ +var Immutable = require('immutable'); + +var PREFIX = require('../constants/pluginPrefix'); +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), + + // 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'); +}; + +/** + Return the ID on NPM for this plugin + + @return {String} +*/ +Plugin.prototype.getNpmID = function() { + return PREFIX + this.getName(); +}; + +/** + Check if a plugin is loaded + + @return {Boolean} +*/ +Plugin.prototype.isLoaded = function() { + return Boolean(this.getPackage().size > 0 && this.getContent().size > 0); +}; + +/** + 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 + }); +}; + +module.exports = Plugin; diff --git a/lib/models/readme.js b/lib/models/readme.js new file mode 100644 index 0000000..7a184c4 --- /dev/null +++ b/lib/models/readme.js @@ -0,0 +1,30 @@ +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'); +}; + +/** + Create a new readme + + @param {File} file + @param {Object} def + @return {Readme} +*/ +Readme.create = function(file, 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 new file mode 100644 index 0000000..3918df7 --- /dev/null +++ b/lib/models/summary.js @@ -0,0 +1,41 @@ +var Immutable = require('immutable'); + +var File = require('./file'); +var SummaryPart = require('./summaryPart'); + +var Summary = Immutable.Record({ + file: File(), + parts: Immutable.List() +}); + +Summary.prototype.getFile = function() { + return this.get('file'); +}; + +Summary.prototype.getParts = function() { + return this.get('parts'); +}; + + +/** + 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) { + if (part instanceof SummaryPart) { + return part; + } + + return SummaryPart.create(part); + }); + + return new Summary({ + file: file, + parts: new Immutable.List(parts) + }); +}; + +module.exports = Summary; diff --git a/lib/models/summaryArticle.js b/lib/models/summaryArticle.js new file mode 100644 index 0000000..3d642fc --- /dev/null +++ b/lib/models/summaryArticle.js @@ -0,0 +1,100 @@ +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.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'); +}; + +/** + Get path (without anchor) to the pointing file + + @return {String} +*/ +SummaryArticle.prototype.getPath = function() { + var ref = this.getRef(); + var parts = ref.split('#'); + + var pathname = (parts.length > 1? parts.slice(0, -1).join('#') : ref); + + // Normalize path to remove ('./', etc) + return location.normalize(pathname); +}; + +/** + 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] : null); + return anchor; +}; + +/** + Is article pointing to a page of an absolute url + + @return {Boolean} +*/ +SummaryArticle.prototype.isPage = function() { + return !this.isExternal() && this.getRef(); +}; + +/** + 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) { + var articles = (def.articles || []).map(function(article) { + if (article instanceof SummaryArticle) { + return article; + } + return SummaryArticle.create(article); + }); + + return new SummaryArticle({ + title: def.title, + ref: def.ref || def.path, + articles: Immutable.List(articles) + }); +}; + + +module.exports = SummaryArticle; diff --git a/lib/models/summaryPart.js b/lib/models/summaryPart.js new file mode 100644 index 0000000..4b41621 --- /dev/null +++ b/lib/models/summaryPart.js @@ -0,0 +1,42 @@ +var Immutable = require('immutable'); + +var SummaryArticle = require('./summaryArticle'); + +/* + A part represents a section in the Summary / table of Contents +*/ + +var SummaryPart = Immutable.Record({ + title: String(), + articles: Immutable.List() +}); + +SummaryPart.prototype.getTitle = function() { + return this.get('title'); +}; + +SummaryPart.prototype.getArticles = function() { + return this.get('articles'); +}; + +/** + Create a SummaryPart + + @param {Object} def + @return {SummaryPart} +*/ +SummaryPart.create = function(def) { + var articles = (def.articles || []).map(function(article) { + if (article instanceof SummaryArticle) { + return article; + } + return SummaryArticle.create(article); + }); + + return new SummaryPart({ + title: def.title, + articles: Immutable.List(articles) + }); +}; + +module.exports = SummaryPart; |