index.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. /*!
  2. * split-string <https://github.com/jonschlinkert/split-string>
  3. *
  4. * Copyright (c) 2015-2017, Jon Schlinkert.
  5. * Released under the MIT License.
  6. */
  7. 'use strict';
  8. var extend = require('extend-shallow');
  9. module.exports = function(str, options, fn) {
  10. if (typeof str !== 'string') {
  11. throw new TypeError('expected a string');
  12. }
  13. if (typeof options === 'function') {
  14. fn = options;
  15. options = null;
  16. }
  17. // allow separator to be defined as a string
  18. if (typeof options === 'string') {
  19. options = { sep: options };
  20. }
  21. var opts = extend({sep: '.'}, options);
  22. var quotes = opts.quotes || ['"', "'", '`'];
  23. var brackets;
  24. if (opts.brackets === true) {
  25. brackets = {
  26. '<': '>',
  27. '(': ')',
  28. '[': ']',
  29. '{': '}'
  30. };
  31. } else if (opts.brackets) {
  32. brackets = opts.brackets;
  33. }
  34. var tokens = [];
  35. var stack = [];
  36. var arr = [''];
  37. var sep = opts.sep;
  38. var len = str.length;
  39. var idx = -1;
  40. var closeIdx;
  41. function expected() {
  42. if (brackets && stack.length) {
  43. return brackets[stack[stack.length - 1]];
  44. }
  45. }
  46. while (++idx < len) {
  47. var ch = str[idx];
  48. var next = str[idx + 1];
  49. var tok = { val: ch, idx: idx, arr: arr, str: str };
  50. tokens.push(tok);
  51. if (ch === '\\') {
  52. tok.val = keepEscaping(opts, str, idx) === true ? (ch + next) : next;
  53. tok.escaped = true;
  54. if (typeof fn === 'function') {
  55. fn(tok);
  56. }
  57. arr[arr.length - 1] += tok.val;
  58. idx++;
  59. continue;
  60. }
  61. if (brackets && brackets[ch]) {
  62. stack.push(ch);
  63. var e = expected();
  64. var i = idx + 1;
  65. if (str.indexOf(e, i + 1) !== -1) {
  66. while (stack.length && i < len) {
  67. var s = str[++i];
  68. if (s === '\\') {
  69. s++;
  70. continue;
  71. }
  72. if (quotes.indexOf(s) !== -1) {
  73. i = getClosingQuote(str, s, i + 1);
  74. continue;
  75. }
  76. e = expected();
  77. if (stack.length && str.indexOf(e, i + 1) === -1) {
  78. break;
  79. }
  80. if (brackets[s]) {
  81. stack.push(s);
  82. continue;
  83. }
  84. if (e === s) {
  85. stack.pop();
  86. }
  87. }
  88. }
  89. closeIdx = i;
  90. if (closeIdx === -1) {
  91. arr[arr.length - 1] += ch;
  92. continue;
  93. }
  94. ch = str.slice(idx, closeIdx + 1);
  95. tok.val = ch;
  96. tok.idx = idx = closeIdx;
  97. }
  98. if (quotes.indexOf(ch) !== -1) {
  99. closeIdx = getClosingQuote(str, ch, idx + 1);
  100. if (closeIdx === -1) {
  101. arr[arr.length - 1] += ch;
  102. continue;
  103. }
  104. if (keepQuotes(ch, opts) === true) {
  105. ch = str.slice(idx, closeIdx + 1);
  106. } else {
  107. ch = str.slice(idx + 1, closeIdx);
  108. }
  109. tok.val = ch;
  110. tok.idx = idx = closeIdx;
  111. }
  112. if (typeof fn === 'function') {
  113. fn(tok, tokens);
  114. ch = tok.val;
  115. idx = tok.idx;
  116. }
  117. if (tok.val === sep && tok.split !== false) {
  118. arr.push('');
  119. continue;
  120. }
  121. arr[arr.length - 1] += tok.val;
  122. }
  123. return arr;
  124. };
  125. function getClosingQuote(str, ch, i, brackets) {
  126. var idx = str.indexOf(ch, i);
  127. if (str.charAt(idx - 1) === '\\') {
  128. return getClosingQuote(str, ch, idx + 1);
  129. }
  130. return idx;
  131. }
  132. function keepQuotes(ch, opts) {
  133. if (opts.keepDoubleQuotes === true && ch === '"') return true;
  134. if (opts.keepSingleQuotes === true && ch === "'") return true;
  135. return opts.keepQuotes;
  136. }
  137. function keepEscaping(opts, str, idx) {
  138. if (typeof opts.keepEscaping === 'function') {
  139. return opts.keepEscaping(str, idx);
  140. }
  141. return opts.keepEscaping === true || str[idx + 1] === '\\';
  142. }