'use strict'; var typeOf = require('kind-of'); var extend = require('extend-shallow'); /** * Parse sections in `input` with the given `options`. * * ```js * var sections = require('{%= name %}'); * var result = sections(input, options); * // { content: 'Content before sections', sections: [] } * ``` * @param {String|Buffer|Object} `input` If input is an object, it's `content` property must be a string or buffer. * @param {Object} options * @return {Object} Returns an object with a `content` string and an array of `sections` objects. * @api public */ module.exports = function(input, options) { if (typeof options === 'function') { options = { parse: options }; } var file = toObject(input); var defaults = {section_delimiter: '---', parse: identity}; var opts = extend({}, defaults, options); var delim = opts.section_delimiter; var lines = file.content.split(/\r?\n/); var sections = null; var section = createSection(); var content = []; var stack = []; function initSections(val) { file.content = val; sections = []; content = []; } function closeSection(val) { if (stack.length) { section.key = getKey(stack[0], delim); section.content = val; opts.parse(section, sections); sections.push(section); section = createSection(); content = []; stack = []; } } for (var i = 0; i < lines.length; i++) { var line = lines[i]; var len = stack.length; var ln = line.trim(); if (isDelimiter(ln, delim)) { if (ln.length === 3 && i !== 0) { if (len === 0 || len === 2) { content.push(line); continue; } stack.push(ln); section.data = content.join('\n'); content = []; continue; } if (sections === null) { initSections(content.join('\n')); } if (len === 2) { closeSection(content.join('\n')); } stack.push(ln); continue; } content.push(line); } if (sections === null) { initSections(content.join('\n')); } else { closeSection(content.join('\n')); } file.sections = sections; return file; }; function isDelimiter(line, delim) { if (line.slice(0, delim.length) !== delim) { return false; } if (line.charAt(delim.length + 1) === delim.slice(-1)) { return false; } return true; } function toObject(input) { if (typeOf(input) !== 'object') { input = { content: input }; } if (typeof input.content !== 'string' && !isBuffer(input.content)) { throw new TypeError('expected a buffer or string'); } input.content = input.content.toString(); input.sections = []; return input; } function getKey(val, delim) { return val ? val.slice(delim.length).trim() : ''; } function createSection() { return { key: '', data: '', content: '' }; } function identity(val) { return val; } function isBuffer(val) { if (val && val.constructor && typeof val.constructor.isBuffer === 'function') { return val.constructor.isBuffer(val); } return false; }