Files
gitbook/lib/parse/summary.js
T
2014-07-31 08:43:57 -07:00

149 lines
3.5 KiB
JavaScript

var _ = require('lodash');
var kramed = require('kramed');
// Utility function for splitting a list into groups
function splitBy(list, starter, ender) {
var starts = 0;
var ends = 0;
var group = [];
// Groups
return _.reduce(list, function(groups, value) {
// Ignore start and end delimiters in resulted groups
if(starter(value)) {
starts++;
} else if(ender(value)) {
ends++;
}
// Add current value to group
group.push(value);
// We've got a matching
if(starts === ends && starts !== 0) {
// Add group to end groups
// (remove starter and ender token)
groups.push(group.slice(1, -1));
// Reset group
group = [];
}
return groups;
}, []);
}
function listSplit(nodes, start_type, end_type) {
return splitBy(nodes, function(el) {
return el.type === start_type;
}, function(el) {
return el.type === end_type;
});
}
// Get the biggest list
// out of a list of kramed nodes
function filterList(nodes) {
return _.chain(nodes)
.toArray()
.rest(function(el) {
// Get everything after list_start
return el.type !== 'list_start';
})
.reverse()
.rest(function(el) {
// Get everything after list_end (remember we're reversed)
return el.type !== 'list_end';
})
.reverse()
.value().slice(1, -1);
}
// Parses an Article or Chapter title
// supports extracting links
function parseTitle(src, nums) {
// Check if it's a link
var matches = kramed.InlineLexer.rules.link.exec(src);
var level = nums.join('.');
// Not a link, return plain text
if(!matches) {
return {
title: src,
level: level,
path: null,
};
}
return {
title: matches[1],
level: level,
// Normalize path
// 1. Convert Window's "\" to "/"
// 2. Remove leading "/" if exists
path: matches[2].replace(/\\/g, '/').replace(/^\/+/, ''),
};
}
function parseChapter(nodes, nums) {
// Convert single number to an array
nums = _.isArray(nums) ? nums : [nums];
return _.extend(parseTitle(_.first(nodes).text, nums), {
articles: _.map(listSplit(filterList(nodes), 'list_item_start', 'list_item_end'), function(nodes, i) {
return parseChapter(nodes, nums.concat(i + 1));
})
});
}
function defaultChapterList(chapterList) {
var first = _.first(chapterList);
// Check if introduction node was specified in SUMMARY.md
if (first) {
var chapter = parseChapter(first, [0]);
// Already have README node, we're good to go
if(chapter.path === 'README.md') {
return chapterList;
}
}
// It wasn't specified, so add in default
return [
[ { type: 'text', text: '[Introduction](README.md)' } ]
].concat(chapterList);
}
function listGroups(src) {
var nodes = kramed.lexer(src);
// Get out groups of lists
return listSplit(
filterList(nodes),
'list_item_start', 'list_item_end'
);
}
function parseSummary(src) {
// Split out chapter sections
var chapters = defaultChapterList(listGroups(src))
.map(parseChapter);
return {
chapters: chapters
};
}
function parseEntries (src) {
return listGroups(src).map(parseChapter);
}
// Exports
module.exports = parseSummary;
module.exports.entries = parseEntries;