summaryrefslogtreecommitdiffstats
path: root/lib/parse
diff options
context:
space:
mode:
authorAaron O'Mullan <aaron.omullan@friendco.de>2014-03-31 01:50:21 -0700
committerAaron O'Mullan <aaron.omullan@friendco.de>2014-03-31 01:50:21 -0700
commit0af1886358e79b5e9f84fcdeb7017edbc185d3c7 (patch)
tree514da2c9e10154468d674dd35d30ee76b1bad08f /lib/parse
parentd18da55a184ef514cb996e731830cd0749ccdfe9 (diff)
downloadgitbook-0af1886358e79b5e9f84fcdeb7017edbc185d3c7.zip
gitbook-0af1886358e79b5e9f84fcdeb7017edbc185d3c7.tar.gz
gitbook-0af1886358e79b5e9f84fcdeb7017edbc185d3c7.tar.bz2
Move summary & page parsing code to lib/parse/
Diffstat (limited to 'lib/parse')
-rw-r--r--lib/parse/index.js4
-rw-r--r--lib/parse/page.js62
-rw-r--r--lib/parse/summary.js112
3 files changed, 178 insertions, 0 deletions
diff --git a/lib/parse/index.js b/lib/parse/index.js
new file mode 100644
index 0000000..2caf6a4
--- /dev/null
+++ b/lib/parse/index.js
@@ -0,0 +1,4 @@
+module.exports = {
+ summary: require('./summary'),
+ page: require('./page'),
+};
diff --git a/lib/parse/page.js b/lib/parse/page.js
new file mode 100644
index 0000000..047f3e4
--- /dev/null
+++ b/lib/parse/page.js
@@ -0,0 +1,62 @@
+var _ = require('lodash');
+var marked = require('marked');
+
+
+// Split a page up into sections (lesson, exercises, ...)
+function splitSections(nodes) {
+ var section = [];
+
+ return _.reduce(nodes, function(sections, el) {
+ if(el.type === 'hr') {
+ sections.push(section);
+ section = [];
+ } else {
+ section.push(el);
+ }
+
+ return sections;
+ }, []).concat([section]); // Add remaining nodes
+}
+
+// What is the type of this section
+function sectionType(nodes) {
+ if(_.filter(nodes, {
+ type: 'code'
+ }).length === 3) {
+ return 'exercise';
+ }
+
+ return 'normal';
+}
+
+function parsePage(src) {
+ var nodes = marked.lexer(src);
+
+ return _.chain(splitSections(nodes))
+ .map(function(section) {
+ // Detect section type
+ section.type = sectionType(section);
+ return section;
+ })
+ .map(function(section, idx) {
+ // Transform given type
+ if(section.type === 'exercise' && (idx % 2) == 1) {
+ return {
+ type: section.type,
+ };
+ }
+
+ // marked's Render expects this, we don't use it yet
+ section.links = {};
+
+ // Render normal pages
+ return {
+ type: section.type,
+ content: marked.parser(section)
+ };
+ })
+ .value();
+}
+
+// Exports
+module.exports = parsePage;
diff --git a/lib/parse/summary.js b/lib/parse/summary.js
new file mode 100644
index 0000000..8787554
--- /dev/null
+++ b/lib/parse/summary.js
@@ -0,0 +1,112 @@
+var _ = require('lodash');
+var marked = require('marked');
+
+
+// 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 marked 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) {
+ // Check if it's a link
+ var matches = marked.InlineLexer.rules.link.exec(src);
+
+ // Not a link, return plain text
+ if(!matches) {
+ return {
+ title: src,
+ path: null,
+ };
+ }
+
+ return {
+ title: matches[1],
+ path: matches[2],
+ };
+}
+
+function parseArticle(nodes) {
+ return parseTitle(_.first(nodes).text);
+}
+
+function parseChapter(nodes) {
+ return {
+ chapter: parseTitle(_.first(nodes).text),
+ articles: _.map(listSplit(filterList(nodes), 'list_item_start', 'list_item_end'), parseArticle)
+ };
+}
+
+function parseSummary(src) {
+ var nodes = marked.lexer(src);
+
+ // Get out list of chapters
+ var chapterList = filterList(nodes);
+
+ // Split out chapter sections
+ var chapters = _.chain(listSplit(chapterList, 'list_item_start', 'list_item_end'))
+ .map(parseChapter)
+ .value();
+
+ return {
+ chapters: chapters
+ };
+}
+
+
+// Exports
+module.exports = parseSummary;