l0bsterssg

node.js static responsive blog post generator
Log | Files | Refs | README

index.js (3082B)


      1 'use strict';
      2 
      3 var typeOf = require('kind-of');
      4 var extend = require('extend-shallow');
      5 
      6 /**
      7  * Parse sections in `input` with the given `options`.
      8  *
      9  * ```js
     10  * var sections = require('{%= name %}');
     11  * var result = sections(input, options);
     12  * // { content: 'Content before sections', sections: [] }
     13  * ```
     14  * @param {String|Buffer|Object} `input` If input is an object, it's `content` property must be a string or buffer.
     15  * @param {Object} options
     16  * @return {Object} Returns an object with a `content` string and an array of `sections` objects.
     17  * @api public
     18  */
     19 
     20 module.exports = function(input, options) {
     21   if (typeof options === 'function') {
     22     options = { parse: options };
     23   }
     24 
     25   var file = toObject(input);
     26   var defaults = {section_delimiter: '---', parse: identity};
     27   var opts = extend({}, defaults, options);
     28   var delim = opts.section_delimiter;
     29   var lines = file.content.split(/\r?\n/);
     30   var sections = null;
     31   var section = createSection();
     32   var content = [];
     33   var stack = [];
     34 
     35   function initSections(val) {
     36     file.content = val;
     37     sections = [];
     38     content = [];
     39   }
     40 
     41   function closeSection(val) {
     42     if (stack.length) {
     43       section.key = getKey(stack[0], delim);
     44       section.content = val;
     45       opts.parse(section, sections);
     46       sections.push(section);
     47       section = createSection();
     48       content = [];
     49       stack = [];
     50     }
     51   }
     52 
     53   for (var i = 0; i < lines.length; i++) {
     54     var line = lines[i];
     55     var len = stack.length;
     56     var ln = line.trim();
     57 
     58     if (isDelimiter(ln, delim)) {
     59       if (ln.length === 3 && i !== 0) {
     60         if (len === 0 || len === 2) {
     61           content.push(line);
     62           continue;
     63         }
     64         stack.push(ln);
     65         section.data = content.join('\n');
     66         content = [];
     67         continue;
     68       }
     69 
     70       if (sections === null) {
     71         initSections(content.join('\n'));
     72       }
     73 
     74       if (len === 2) {
     75         closeSection(content.join('\n'));
     76       }
     77 
     78       stack.push(ln);
     79       continue;
     80     }
     81 
     82     content.push(line);
     83   }
     84 
     85   if (sections === null) {
     86     initSections(content.join('\n'));
     87   } else {
     88     closeSection(content.join('\n'));
     89   }
     90 
     91   file.sections = sections;
     92   return file;
     93 };
     94 
     95 function isDelimiter(line, delim) {
     96   if (line.slice(0, delim.length) !== delim) {
     97     return false;
     98   }
     99   if (line.charAt(delim.length + 1) === delim.slice(-1)) {
    100     return false;
    101   }
    102   return true;
    103 }
    104 
    105 function toObject(input) {
    106   if (typeOf(input) !== 'object') {
    107     input = { content: input };
    108   }
    109 
    110   if (typeof input.content !== 'string' && !isBuffer(input.content)) {
    111     throw new TypeError('expected a buffer or string');
    112   }
    113 
    114   input.content = input.content.toString();
    115   input.sections = [];
    116   return input;
    117 }
    118 
    119 function getKey(val, delim) {
    120   return val ? val.slice(delim.length).trim() : '';
    121 }
    122 
    123 function createSection() {
    124   return { key: '', data: '', content: '' };
    125 }
    126 
    127 function identity(val) {
    128   return val;
    129 }
    130 
    131 function isBuffer(val) {
    132   if (val && val.constructor && typeof val.constructor.isBuffer === 'function') {
    133     return val.constructor.isBuffer(val);
    134   }
    135   return false;
    136 }