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 }