| /*! |
| * split-string <https://github.com/jonschlinkert/split-string> |
| * |
| * Copyright (c) 2015-2017, Jon Schlinkert. |
| * Released under the MIT License. |
| */ |
| |
| 'use strict'; |
| |
| var extend = require('extend-shallow'); |
| |
| module.exports = function(str, options, fn) { |
| if (typeof str !== 'string') { |
| throw new TypeError('expected a string'); |
| } |
| |
| if (typeof options === 'function') { |
| fn = options; |
| options = null; |
| } |
| |
| // allow separator to be defined as a string |
| if (typeof options === 'string') { |
| options = { sep: options }; |
| } |
| |
| var opts = extend({sep: '.'}, options); |
| var quotes = opts.quotes || ['"', "'", '`']; |
| var brackets; |
| |
| if (opts.brackets === true) { |
| brackets = { |
| '<': '>', |
| '(': ')', |
| '[': ']', |
| '{': '}' |
| }; |
| } else if (opts.brackets) { |
| brackets = opts.brackets; |
| } |
| |
| var tokens = []; |
| var stack = []; |
| var arr = ['']; |
| var sep = opts.sep; |
| var len = str.length; |
| var idx = -1; |
| var closeIdx; |
| |
| function expected() { |
| if (brackets && stack.length) { |
| return brackets[stack[stack.length - 1]]; |
| } |
| } |
| |
| while (++idx < len) { |
| var ch = str[idx]; |
| var next = str[idx + 1]; |
| var tok = { val: ch, idx: idx, arr: arr, str: str }; |
| tokens.push(tok); |
| |
| if (ch === '\\') { |
| tok.val = keepEscaping(opts, str, idx) === true ? (ch + next) : next; |
| tok.escaped = true; |
| if (typeof fn === 'function') { |
| fn(tok); |
| } |
| arr[arr.length - 1] += tok.val; |
| idx++; |
| continue; |
| } |
| |
| if (brackets && brackets[ch]) { |
| stack.push(ch); |
| var e = expected(); |
| var i = idx + 1; |
| |
| if (str.indexOf(e, i + 1) !== -1) { |
| while (stack.length && i < len) { |
| var s = str[++i]; |
| if (s === '\\') { |
| s++; |
| continue; |
| } |
| |
| if (quotes.indexOf(s) !== -1) { |
| i = getClosingQuote(str, s, i + 1); |
| continue; |
| } |
| |
| e = expected(); |
| if (stack.length && str.indexOf(e, i + 1) === -1) { |
| break; |
| } |
| |
| if (brackets[s]) { |
| stack.push(s); |
| continue; |
| } |
| |
| if (e === s) { |
| stack.pop(); |
| } |
| } |
| } |
| |
| closeIdx = i; |
| if (closeIdx === -1) { |
| arr[arr.length - 1] += ch; |
| continue; |
| } |
| |
| ch = str.slice(idx, closeIdx + 1); |
| tok.val = ch; |
| tok.idx = idx = closeIdx; |
| } |
| |
| if (quotes.indexOf(ch) !== -1) { |
| closeIdx = getClosingQuote(str, ch, idx + 1); |
| if (closeIdx === -1) { |
| arr[arr.length - 1] += ch; |
| continue; |
| } |
| |
| if (keepQuotes(ch, opts) === true) { |
| ch = str.slice(idx, closeIdx + 1); |
| } else { |
| ch = str.slice(idx + 1, closeIdx); |
| } |
| |
| tok.val = ch; |
| tok.idx = idx = closeIdx; |
| } |
| |
| if (typeof fn === 'function') { |
| fn(tok, tokens); |
| ch = tok.val; |
| idx = tok.idx; |
| } |
| |
| if (tok.val === sep && tok.split !== false) { |
| arr.push(''); |
| continue; |
| } |
| |
| arr[arr.length - 1] += tok.val; |
| } |
| |
| return arr; |
| }; |
| |
| function getClosingQuote(str, ch, i, brackets) { |
| var idx = str.indexOf(ch, i); |
| if (str.charAt(idx - 1) === '\\') { |
| return getClosingQuote(str, ch, idx + 1); |
| } |
| return idx; |
| } |
| |
| function keepQuotes(ch, opts) { |
| if (opts.keepDoubleQuotes === true && ch === '"') return true; |
| if (opts.keepSingleQuotes === true && ch === "'") return true; |
| return opts.keepQuotes; |
| } |
| |
| function keepEscaping(opts, str, idx) { |
| if (typeof opts.keepEscaping === 'function') { |
| return opts.keepEscaping(str, idx); |
| } |
| return opts.keepEscaping === true || str[idx + 1] === '\\'; |
| } |