[Pkg-javascript-commits] [node-split-string] 01/01: New upstream version 5.0.4

Julien Puydt julien.puydt at laposte.net
Sun Mar 11 19:26:49 UTC 2018


This is an automated email from the git hooks/post-receive script.

jpuydt-guest pushed a commit to annotated tag upstream/5.0.4
in repository node-split-string.

commit 2d851d388787c8f6b050ee2de18d7a1318d5fc79
Author: Julien Puydt <julien.puydt at laposte.net>
Date:   Fri Feb 23 12:09:49 2018 +0100

    New upstream version 5.0.4
---
 .eslintrc.json          |  13 ++
 .gitignore              |   1 +
 .travis.yml             |   4 -
 .verb.md                |  96 ++++++++-------
 CHANGELOG.md            | 119 +++++++++++++++++++
 LICENSE                 |   2 +-
 README.md               | 105 +++++++++-------
 example.js              |  42 +++++--
 index.js                | 309 ++++++++++++++++++++++++++++--------------------
 package.json            |  18 ++-
 test.js                 | 178 ----------------------------
 test/custom-function.js |  50 ++++++++
 test/options.js         | 121 +++++++++++++++++++
 test/test.js            |  62 ++++++++++
 14 files changed, 708 insertions(+), 412 deletions(-)

diff --git a/.eslintrc.json b/.eslintrc.json
index 61e8895..24b8984 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -1,4 +1,8 @@
 {
+  "extends": [
+    "eslint:recommended"
+  ],
+
   "env": {
     "browser": false,
     "es6": true,
@@ -6,6 +10,15 @@
     "mocha": true
   },
 
+  "parserOptions":{
+    "ecmaVersion": 9,
+    "sourceType": "module",
+    "ecmaFeatures": {
+      "modules": true,
+      "experimentalObjectRestSpread": true
+    }
+  },
+
   "globals": {
     "document": false,
     "navigator": false,
diff --git a/.gitignore b/.gitignore
index 4bf0a60..f969a2c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,7 @@
 # always ignore files
 *.DS_Store
 .idea
+.vscode
 *.sublime-*
 
 # test related, or directories generated by tests
diff --git a/.travis.yml b/.travis.yml
index 1686664..1fd107d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -9,7 +9,3 @@ node_js:
   - '8'
   - '7'
   - '6'
-  - '5'
-  - '4'
-  - '0.12'
-  - '0.10'
diff --git a/.verb.md b/.verb.md
index 3179632..9d21d2a 100644
--- a/.verb.md
+++ b/.verb.md
@@ -13,7 +13,7 @@ console.log('a.b.c'.split('.'));
 
 It's more challenging to split a string whilst respecting escaped or quoted characters.
 
-**Bad**
+**This is bad**
 
 ```js
 console.log('a\\.b.c'.split('.'));
@@ -23,7 +23,7 @@ console.log('"a.b.c".d'.split('.'));
 //=> ['"a', 'b', 'c"', 'd']
 ```
 
-**Good**
+**This is good**
 
 ```js
 var split = require('{%= name %}');
@@ -105,29 +105,13 @@ split('a.{b.c}', {brackets: true});
 split('a.{b.{c.d}.e}.f', {brackets: true});
 //=> [ 'a', '{b.{c.d}.e}', 'f' ]
 
-// support only the specified brackets
-split('[a.b].(c.d)', {brackets: {'[': ']'}});
-//=> [ '[a.b]', '(c', 'd)' ]
+// support only the specified bracket types
+split('«a.b».⟨c.d⟩', {brackets: {'«': '»', '⟨': '⟩'}});
+//=> [ '«a.b»', '⟨c.d⟩' ]
+split('a.{a.[{b.c}].d}.e', {brackets: {'[': ']'}});
+//=> [ 'a', '{a', '[{b.c}]', 'd}', 'e' ]
 ```
 
-### options.sep
-
-**Type**: `string`
-
-**Default**: `.`
-
-The separator/character to split on.
-
-**Example**
-
-```js
-split('a.b,c', {sep: ','});
-//=> ['a.b', 'c']
-
-// you can also pass the separator as string as the last argument
-split('a.b,c', ',');
-//=> ['a.b', 'c']
-```
 
 ### options.keepEscaping
 
@@ -204,41 +188,73 @@ split('a.\'b.c.d\'.e', {keepSingleQuotes: true});
 //=> ['a', '\'b.c.d\'', 'e']
 ```
 
+### options.separator
+
+**Type**: `string`
+
+**Default**: `.`
 
-## Customizer
+The separator/character to split on. Aliased as `options.sep` for backwards compatibility with versions <4.0.
+
+**Example**
+
+```js
+split('a.b,c', {separator: ','});
+//=> ['a.b', 'c']
+
+// you can also pass the separator as a string as the last argument
+split('a.b,c', ',');
+//=> ['a.b', 'c']
+```
+
+### options.split
 
 **Type**: `function`
 
-**Default**: `undefined`
+**Default**: the default function returns `true`
 
-Pass a function as the last argument to customize how tokens are added to the array.
+Pass a custom function to be called each time a separator is encountered. If the function returns `false` the string will not be split on that separator. 
 
 **Example**
 
 ```js
-var arr = split('a.b', function(tok) {
-  if (tok.arr[tok.arr.length - 1] === 'a') {
-    tok.split = false;
+const arr = split('a.b.c', {
+  split: function() {
+    const prev = this.prev();
+    if (prev && prev.value === 'a') {
+      return false;
+    }
+    return true;
   }
 });
 console.log(arr);
-//=> ['a.b']
+//=> ['a.b', 'c']
 ```
 
-**Properties**
+Note that the [snapdragon-lexer][] instance is exposed as `this` inside the function. See `snapdragon-lexer` for more information and complete API documentation.
+
+## Split function
 
-The `tok` object has the following properties:
+**Type**: `function`
 
-- `tok.val` (string) The current value about to be pushed onto the result array
-- `tok.idx` (number) the current index in the string
-- `tok.str` (string) the entire string
-- `tok.arr` (array) the result array
+**Default**: `undefined`
 
+Pass a custom function as the last argument to customize how and when the string should be split. The function will be called each time a separator is encountered. 
 
-## Release history
+To avoid splitting on a specific separator, add a `token.split()` function to the token and return `false`.
 
-### v3.0.0 - 2017-06-17
 
-**Added**
+**Example**
+
+```js
+const arr = split('a.b.c', function(token) {
+  const prev = this.prev();
+  if (prev && prev.value === 'a') {
+    token.split = () => false;
+  }
+});
+console.log(arr);
+//=> ['a.b', 'c']
+```
 
-- adds support for brackets
+Note that the [snapdragon-lexer][] instance is exposed as `this` inside the function. See `snapdragon-lexer` for more information and complete API documentation.
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..6094999
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,119 @@
+# Release history
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
+and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
+
+<details>
+  <summary><strong>Guiding Principles</strong></summary>
+
+- Changelogs are for humans, not machines.
+- There should be an entry for every single version.
+- The same types of changes should be grouped.
+- Versions and sections should be linkable.
+- The latest version comes first.
+- The release date of each versions is displayed.
+- Mention whether you follow Semantic Versioning.
+
+</details>
+
+<details>
+  <summary><strong>Types of changes</strong></summary>
+
+Changelog entries are classified using the following labels _(from [keep-a-changelog](http://keepachangelog.com/)_):
+
+- `Added` for new features.
+- `Changed` for changes in existing functionality.
+- `Deprecated` for soon-to-be removed features.
+- `Removed` for now removed features.
+- `Fixed` for any bug fixes.
+- `Security` in case of vulnerabilities.
+
+</details>
+
+## [5.0.1] - 2018-01-08
+
+- update engine versions
+
+## [5.0.0] - 2018-01-08
+
+- tweak quotes handling
+- refactor to use snapdragon-lexer
+- Merge pull request #5 from jonschlinkert/refactor
+
+## [4.0.0] - 2017-11-22
+
+- allow options.quotes to be an object
+- Merge pull request #4 from jonschlinkert/quotes-object
+
+## [3.1.0] - 2017-11-19
+
+- support `keepEscaping` as a function
+- run `lint-deps` to upgrade deps
+
+## [3.0.2] - 2017-06-21
+
+- fix examples
+
+## [3.0.1] - 2017-06-15
+
+- fix examples
+- remove unnecessary brackets
+
+## [3.0.0] - 2017-06-15
+
+- support brackets
+- support nested brackets
+- update release history, run verb
+
+## [2.1.1] - 2017-05-30
+
+- call custom function on escaped tokens
+
+## [2.1.0] - 2017-04-27
+
+- support backticks
+- update docs
+
+## [2.0.0] - 2017-04-11
+
+- example callback
+- adds support for a sync callback
+- update docs, run verb
+
+## [1.0.1] - 2017-04-11
+
+- fix error message for unclosed quote
+- allow disabling strict closing of quotes
+- add tests for errors and strict option
+- Merge pull request #2 from jonschlinkert/strict
+- add documentation on options.strict
+
+## [1.0.0] - 2017-02-21
+
+- refactor
+- update docs, run `verb`
+
+## [0.1.1] - 2015-08-27
+
+- first commit
+- only use 1 nonchar instead of entire array
+- Merge pull request #1 from doowb/master
+
+[5.0.1]: https://github.com/jonschlinkert/split-string/compare/5.0.0...5.0.1
+[5.0.0]: https://github.com/jonschlinkert/split-string/compare/4.0.0...5.0.0
+[4.0.0]: https://github.com/jonschlinkert/split-string/compare/3.1.0...4.0.0
+[3.1.0]: https://github.com/jonschlinkert/split-string/compare/3.0.2...3.1.0
+[3.0.2]: https://github.com/jonschlinkert/split-string/compare/3.0.1...3.0.2
+[3.0.1]: https://github.com/jonschlinkert/split-string/compare/3.0.0...3.0.1
+[3.0.0]: https://github.com/jonschlinkert/split-string/compare/2.1.1...3.0.0
+[2.1.1]: https://github.com/jonschlinkert/split-string/compare/2.1.0...2.1.1
+[2.1.0]: https://github.com/jonschlinkert/split-string/compare/2.0.0...2.1.0
+[2.0.0]: https://github.com/jonschlinkert/split-string/compare/1.0.1...2.0.0
+[1.0.1]: https://github.com/jonschlinkert/split-string/compare/1.0.0...1.0.1
+[1.0.0]: https://github.com/jonschlinkert/split-string/compare/0.1.1...1.0.0
+
+[Unreleased]: https://github.com/jonschlinkert/split-string/compare/0.1.1...HEAD
+[keep-a-changelog]: https://github.com/olivierlacan/keep-a-changelog
+
diff --git a/LICENSE b/LICENSE
index e33d14b..f8de063 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
 The MIT License (MIT)
 
-Copyright (c) 2015-2017, Jon Schlinkert.
+Copyright (c) 2015-2018, Jon Schlinkert.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
diff --git a/README.md b/README.md
index 26a6ae1..a6259d1 100644
--- a/README.md
+++ b/README.md
@@ -28,7 +28,7 @@ console.log('a.b.c'.split('.'));
 
 It's more challenging to split a string whilst respecting escaped or quoted characters.
 
-**Bad**
+**This is bad**
 
 ```js
 console.log('a\\.b.c'.split('.'));
@@ -38,7 +38,7 @@ console.log('"a.b.c".d'.split('.'));
 //=> ['"a', 'b', 'c"', 'd']
 ```
 
-**Good**
+**This is good**
 
 ```js
 var split = require('split-string');
@@ -119,28 +119,11 @@ split('a.{b.c}', {brackets: true});
 split('a.{b.{c.d}.e}.f', {brackets: true});
 //=> [ 'a', '{b.{c.d}.e}', 'f' ]
 
-// support only the specified brackets
-split('[a.b].(c.d)', {brackets: {'[': ']'}});
-//=> [ '[a.b]', '(c', 'd)' ]
-```
-
-### options.sep
-
-**Type**: `string`
-
-**Default**: `.`
-
-The separator/character to split on.
-
-**Example**
-
-```js
-split('a.b,c', {sep: ','});
-//=> ['a.b', 'c']
-
-// you can also pass the separator as string as the last argument
-split('a.b,c', ',');
-//=> ['a.b', 'c']
+// support only the specified bracket types
+split('«a.b».⟨c.d⟩', {brackets: {'«': '»', '⟨': '⟩'}});
+//=> [ '«a.b»', '⟨c.d⟩' ]
+split('a.{a.[{b.c}].d}.e', {brackets: {'[': ']'}});
+//=> [ 'a', '{a', '[{b.c}]', 'd}', 'e' ]
 ```
 
 ### options.keepEscaping
@@ -218,42 +201,75 @@ split('a.\'b.c.d\'.e', {keepSingleQuotes: true});
 //=> ['a', '\'b.c.d\'', 'e']
 ```
 
-## Customizer
+### options.separator
+
+**Type**: `string`
+
+**Default**: `.`
+
+The separator/character to split on. Aliased as `options.sep` for backwards compatibility with versions <4.0.
+
+**Example**
+
+```js
+split('a.b,c', {separator: ','});
+//=> ['a.b', 'c']
+
+// you can also pass the separator as a string as the last argument
+split('a.b,c', ',');
+//=> ['a.b', 'c']
+```
+
+### options.split
 
 **Type**: `function`
 
-**Default**: `undefined`
+**Default**: the default function returns `true`
 
-Pass a function as the last argument to customize how tokens are added to the array.
+Pass a custom function to be called each time a separator is encountered. If the function returns `false` the string will not be split on that separator.
 
 **Example**
 
 ```js
-var arr = split('a.b', function(tok) {
-  if (tok.arr[tok.arr.length - 1] === 'a') {
-    tok.split = false;
+const arr = split('a.b.c', {
+  split: function() {
+    const prev = this.prev();
+    if (prev && prev.value === 'a') {
+      return false;
+    }
+    return true;
   }
 });
 console.log(arr);
-//=> ['a.b']
+//=> ['a.b', 'c']
 ```
 
-**Properties**
+Note that the [snapdragon-lexer](https://github.com/here-be/snapdragon-lexer) instance is exposed as `this` inside the function. See `snapdragon-lexer` for more information and complete API documentation.
 
-The `tok` object has the following properties:
+## Split function
 
-* `tok.val` (string) The current value about to be pushed onto the result array
-* `tok.idx` (number) the current index in the string
-* `tok.str` (string) the entire string
-* `tok.arr` (array) the result array
+**Type**: `function`
 
-## Release history
+**Default**: `undefined`
+
+Pass a custom function as the last argument to customize how and when the string should be split. The function will be called each time a separator is encountered.
 
-### v3.0.0 - 2017-06-17
+To avoid splitting on a specific separator, add a `token.split()` function to the token and return `false`.
 
-**Added**
+**Example**
+
+```js
+const arr = split('a.b.c', function(token) {
+  const prev = this.prev();
+  if (prev && prev.value === 'a') {
+    token.split = () => false;
+  }
+});
+console.log(arr);
+//=> ['a.b', 'c']
+```
 
-* adds support for brackets
+Note that the [snapdragon-lexer](https://github.com/here-be/snapdragon-lexer) instance is exposed as `this` inside the function. See `snapdragon-lexer` for more information and complete API documentation.
 
 ## About
 
@@ -301,21 +317,22 @@ You might also be interested in these projects:
 
 | **Commits** | **Contributor** | 
 | --- | --- |
-| 34 | [jonschlinkert](https://github.com/jonschlinkert) |
+| 49 | [jonschlinkert](https://github.com/jonschlinkert) |
 | 10 | [doowb](https://github.com/doowb) |
 
 ### Author
 
 **Jon Schlinkert**
 
+* [linkedin/in/jonschlinkert](https://linkedin.com/in/jonschlinkert)
 * [github/jonschlinkert](https://github.com/jonschlinkert)
 * [twitter/jonschlinkert](https://twitter.com/jonschlinkert)
 
 ### License
 
-Copyright © 2017, [Jon Schlinkert](https://github.com/jonschlinkert).
+Copyright © 2018, [Jon Schlinkert](https://github.com/jonschlinkert).
 Released under the [MIT License](LICENSE).
 
 ***
 
-_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.6.0, on November 22, 2017._
\ No newline at end of file
+_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.6.0, on February 16, 2018._
\ No newline at end of file
diff --git a/example.js b/example.js
index 37cd1ee..c4eb0b6 100644
--- a/example.js
+++ b/example.js
@@ -1,13 +1,29 @@
-var split = require('./');
-// var arr = split('a.b', function(tok) {
-//   if (tok.arr[tok.arr.length - 1] === 'a') {
-//     tok.split = false;
-//   }
-// });
-// console.log(arr);
-//=> ['a.b']
-
-var brackets = split('a.{a.{b.c}.}.c', {brackets: true});
-var brackets = split('a.{a.{b.c.}.c', {brackets: true});
-console.log(brackets);
-//=> ['a.b']
+const split = require('./');
+
+console.log(split('a.{a.[{b.c}].d}.e', {brackets: {'[': ']'}}));
+//=> [ 'a', '{a', '[{b.c}]', 'd}', 'e' ]
+
+console.log(split('a.{a.{b.c.d}.c}', {brackets: true}));
+//=> [ 'a', '{a.{b.c.d}.c}' ]
+
+const stash1 = split('a.b.c', function(token) {
+  const prev = this.prev();
+  if (prev && prev.value === 'a') {
+    token.split = () => false;
+  }
+});
+console.log(stash1);
+//=> ['a.b', 'c']
+
+const stash2 = split('a.b.c', {
+  split: function(token) {
+    const prev = this.prev();
+    if (prev && prev.value === 'a') {
+      return false;
+    }
+    return true;
+  }
+});
+console.log(stash2);
+//=> ['a.b', 'c']
+
diff --git a/index.js b/index.js
index b440a82..1290587 100644
--- a/index.js
+++ b/index.js
@@ -1,13 +1,18 @@
 /*!
  * split-string <https://github.com/jonschlinkert/split-string>
  *
- * Copyright (c) 2015-2017, Jon Schlinkert.
+ * Copyright (c) 2015-2018, Jon Schlinkert.
  * Released under the MIT License.
  */
 
 'use strict';
 
-var extend = require('extend-shallow');
+const Lexer = require('snapdragon-lexer');
+const union = require('arr-union');
+const defaults = {
+  brackets: { '<': '>', '(': ')', '[': ']', '{': '}' },
+  quotes: { '"': '"', "'": "'", '`': '`', '“': '”' }
+};
 
 module.exports = function(str, options, fn) {
   if (typeof str !== 'string') {
@@ -19,165 +24,215 @@ module.exports = function(str, options, fn) {
     options = null;
   }
 
-  // allow separator to be defined as a string
-  if (typeof options === 'string') {
-    options = { sep: options };
-  }
+  const opts = Object.assign({ separator: '.' }, options);
+  const sep = opts.sep || opts.separator;
+  const lexer = new Lexer(str, opts);
 
-  var opts = extend({sep: '.'}, options);
-  var quotes = opts.quotes || {
-    '"': '"',
-    "'": "'",
-    '`': '`',
-    '“': '”'
-  };
+  /**
+   * Setup brackets and quotes characters and regex based on options
+   */
 
-  if (Array.isArray(quotes)) {
-    quotes = quotes.reduce(function(acc, ele) {
-      acc[ele] = ele;
-      return acc;
-    }, {});
-  }
+  const brackets = opts.brackets === true ? defaults.brackets : opts.brackets;
+  const quotes = opts.quotes === true || typeof opts.quotes === 'undefined'
+    ? defaults.quotes
+    : opts.quotes;
 
-  var brackets;
-  if (opts.brackets === true) {
-    brackets = {
-      '<': '>',
-      '(': ')',
-      '[': ']',
-      '{': '}'
-    };
-  } else if (opts.brackets) {
-    brackets = opts.brackets;
-  }
+  // brackets
+  const openChars = brackets ? Object.keys(brackets) : [];
+  const closeChars = brackets ? values(brackets) : [];
+  const openStr = brackets ? escape(openChars) : '';
+  const closeStr = brackets ? escape(closeChars) : '';
+
+  // quotes
+  const quoteChars = union(Object.keys(quotes), values(quotes));
+  const quoteStr = quotes ? escape(quoteChars) : '';
+
+  // regex for "text" handler
+  const textRegex = new RegExp('^[^\\\\' + sep + openStr + closeStr + quoteStr + ']+');
 
-  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]];
+  /**
+   * Listener
+   */
+
+  lexer.on('token', token => fn && fn.call(lexer, token));
+  lexer.split = function(token) {
+    if (typeof token.split === 'function') {
+      return token.split.call(this);
     }
-  }
+    if (typeof this.options.split === 'function') {
+      return this.options.split.call(this, token);
+    }
+    return true;
+  };
 
-  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;
+  /**
+   * Handlers
+   */
+
+  lexer.capture('escape', /^\\(.)/, function(token) {
+    const keep = token.keepEscaping === true || opts.keepEscaping === true;
+    if (keep === false && token.value !== '\\\\') {
+      token.value = token.value.slice(1);
     }
+    return token;
+  });
 
-    if (brackets && brackets[ch]) {
-      stack.push(ch);
-      var e = expected();
-      var i = idx + 1;
+  lexer.capture('separator', toRegex(escape(sep.split(''))), function(token) {
+    if (this.split(token) === false || this.isInside('quote') || this.isInside('bracket')) {
+      return token;
+    }
 
-      if (str.indexOf(e, i + 1) !== -1) {
-        while (stack.length && i < len) {
-          var s = str[++i];
-          if (s === '\\') {
-            s++;
-            continue;
-          }
+    const prev = this.prev();
+    if (prev && prev.type === 'separator') {
+      this.stash.push('');
+    }
 
-          if (quotes[s]) {
-            i = getClosingQuote(str, quotes[s], i + 1);
-            continue;
-          }
+    token.value = '';
+    if (!this.stack.length && this.stash.last() !== '') {
+      this.stash.push(token.value);
+    }
+    return token;
+  });
 
-          e = expected();
-          if (stack.length && str.indexOf(e, i + 1) === -1) {
-            break;
-          }
+  lexer.capture('text', textRegex);
 
-          if (brackets[s]) {
-            stack.push(s);
-            continue;
-          }
+  if (quotes) {
+    lexer.capture('quote', toRegex(quoteStr), function(token) {
+      if (this.isInside('bracket')) return token;
 
-          if (e === s) {
-            stack.pop();
-          }
-        }
-      }
+      const val = token.match[0];
+      token.append = false;
 
-      closeIdx = i;
-      if (closeIdx === -1) {
-        arr[arr.length - 1] += ch;
-        continue;
+      if (!keepQuotes(val, opts)) {
+        token.value = '';
       }
 
-      ch = str.slice(idx, closeIdx + 1);
-      tok.val = ch;
-      tok.idx = idx = closeIdx;
-    }
+      if (this.isClose(val)) {
+        const open = this.stack.pop();
+        open.closed = true;
+        this.unwind(open, true);
+        this.append(token.value);
 
-    if (quotes[ch]) {
-      closeIdx = getClosingQuote(str, quotes[ch], idx + 1);
-      if (closeIdx === -1) {
-        arr[arr.length - 1] += ch;
-        continue;
+      } else {
+        token.queue = [];
+        token.isClose = value => value === quotes[val];
+        this.stack.push(token);
       }
+      return token;
+    });
+  }
 
-      if (keepQuotes(ch, opts) === true) {
-        ch = str.slice(idx, closeIdx + 1);
-      } else {
-        ch = str.slice(idx + 1, closeIdx);
+  if (brackets) {
+    lexer.capture('bracket', toRegex(openStr), function(token) {
+      token.append = false;
+      token.queue = [];
+      token.isClose = value => value === brackets[token.value];
+      this.stack.push(token);
+      return token;
+    });
+    lexer.capture('bracket.close', toRegex(closeStr), function(token) {
+      if (this.isClose(token.value)) {
+        const open = this.stack.pop();
+        open.value += open.queue.join('');
+        this.append(open.value);
       }
+      return token;
+    });
+  }
+
+  /**
+   * Custom lexer methods
+   */
 
-      tok.val = ch;
-      tok.idx = idx = closeIdx;
+  lexer.isClose = function(ch) {
+    const open = this.stack.last();
+    if (open && typeof open.isClose === 'function') {
+      return open.isClose(ch);
     }
+  };
 
-    if (typeof fn === 'function') {
-      fn(tok, tokens);
-      ch = tok.val;
-      idx = tok.idx;
+  lexer.append = function(val) {
+    if (!val) return;
+    const last = this.stack.last();
+    if (last && Array.isArray(last.queue)) {
+      last.queue.push(val);
+    } else {
+      this.stash[this.stash.length - 1] += val;
     }
+  };
+
+  // add queued strings back to the stash
+  lexer.unwind = function(token, append) {
+    switch (token && token.type) {
+      case 'bracket':
+        const segs = token.queue.join('').split(sep);
+        this.append(token.value);
+        this.append(segs.shift());
+        this.stash = this.stash.concat(segs);
+        break;
+      case 'quote':
+        const quote = token.closed && !keepQuotes(token.match[0], opts) ? '' : token.match[0];
+        this.append(quote);
+        this.append(token.queue.shift());
+
+        while (token.queue.length) {
+          const val = token.queue.shift();
+          if (append) {
+            this.append(val);
+            continue;
+          }
 
-    if (tok.val === sep && tok.split !== false) {
-      arr.push('');
-      continue;
+          if (val !== sep) {
+            this.stash.push(val);
+          }
+        }
+        break;
+      default: {
+        break;
+      }
     }
+  };
 
-    arr[arr.length - 1] += tok.val;
+  // start tokenizing
+  lexer.tokenize(str);
+
+  // ensure the stack is empty
+  if (lexer.options.strict === true) {
+    lexer.fail();
   }
 
-  return arr;
+  lexer.unwind(lexer.stack.pop());
+  lexer.fail();
+  return lexer.stash;
 };
 
-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 toRegex(str) {
+  return new RegExp('^(?=.)[' + str + ']');
 }
 
-function keepQuotes(ch, opts) {
-  if (opts.keepDoubleQuotes === true && (ch === '"' || ch === '“' || ch === '”')) return true;
-  if (opts.keepSingleQuotes === true && ch === "'") return true;
-  return opts.keepQuotes;
+function escape(arr) {
+  return '\\' + arr.join('\\');
 }
 
-function keepEscaping(opts, str, idx) {
-  if (typeof opts.keepEscaping === 'function') {
-    return opts.keepEscaping(str, idx);
+function values(obj) {
+  const arr = [];
+  for (const key of Object.keys(obj)) arr.push(obj[key]);
+  return arr;
+}
+
+function keepQuotes(ch, opts) {
+  if (opts.keepQuotes === true) return true;
+  if (opts.keepSmartQuotes === true && (ch === '“' || ch === '”')) {
+    return true;
+  }
+  if (opts.keepDoubleQuotes === true && ch === '"') {
+    return true;
+  }
+  if (opts.keepSingleQuotes === true && ch === '\'') {
+    return true;
+  }
+  if (opts.keepBackticks === true && ch === '`') {
+    return true;
   }
-  return opts.keepEscaping === true || str[idx + 1] === '\\';
+  return false;
 }
diff --git a/package.json b/package.json
index c0f2cc3..eac658a 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
 {
   "name": "split-string",
   "description": "Split a string on a character except when the character is escaped.",
-  "version": "4.0.0",
+  "version": "5.0.4",
   "homepage": "https://github.com/jonschlinkert/split-string",
   "author": "Jon Schlinkert (https://github.com/jonschlinkert)",
   "contributors": [
@@ -18,17 +18,19 @@
   ],
   "main": "index.js",
   "engines": {
-    "node": ">=0.10.0"
+    "node": ">=8"
   },
   "scripts": {
-    "test": "mocha"
+    "test": "nyc mocha"
   },
   "dependencies": {
-    "extend-shallow": "^3.0.0"
+    "arr-union": "^3.1.0",
+    "snapdragon-lexer": "^3.1.0"
   },
   "devDependencies": {
     "gulp-format-md": "^1.0.0",
-    "mocha": "^3.5.3"
+    "mocha": "^3.5.3",
+    "nyc": "^11.4.1"
   },
   "keywords": [
     "character",
@@ -36,6 +38,12 @@
     "split",
     "string"
   ],
+  "nyc": {
+    "reporter": [
+      "lcov",
+      "text-summary"
+    ]
+  },
   "verb": {
     "toc": false,
     "layout": "default",
diff --git a/test.js b/test.js
deleted file mode 100644
index 02a3d07..0000000
--- a/test.js
+++ /dev/null
@@ -1,178 +0,0 @@
-'use strict';
-
-require('mocha');
-var assert = require('assert');
-var split = require('./');
-
-describe('split-string', function() {
-  describe('split-string', function() {
-    it('should split a string on the given character:', function() {
-      assert.deepEqual(split('a/b/c', '/'), ['a', 'b', 'c']);
-    });
-
-    it('should not split on an escaped character:', function() {
-      assert.deepEqual(split('a/b/c\\/d', '/'), ['a', 'b', 'c/d']);
-    });
-
-    it('should split a string on dots by default:', function() {
-      assert.deepEqual(split('a.b.c'), ['a', 'b', 'c']);
-    });
-
-    it('should respect double-quoted strings', function() {
-      assert.deepEqual(split('"b.c"'), ['b.c']);
-      assert.deepEqual(split('a."b.c"'), ['a', 'b.c']);
-      assert.deepEqual(split('a".b.c"'), ['a.b.c']);
-      assert.deepEqual(split('a."b.c".d'), ['a', 'b.c', 'd']);
-      assert.deepEqual(split('a."b.c".d.".e.f.g.".h'), ['a', 'b.c', 'd', '.e.f.g.', 'h']);
-    });
-
-    it('should respect singlequoted strings', function() {
-      assert.deepEqual(split('\'b.c\''), ['b.c']);
-      assert.deepEqual(split('a.\'b.c\''), ['a', 'b.c']);
-      assert.deepEqual(split('a.\'b.c\'.d'), ['a', 'b.c', 'd']);
-      assert.deepEqual(split('a.\'b.c\'.d.\'.e.f.g.\'.h'), ['a', 'b.c', 'd', '.e.f.g.', 'h']);
-    });
-
-    it('should respect strings in backticks', function() {
-      assert.deepEqual(split('`b.c`'), ['b.c']);
-      assert.deepEqual(split('a.`b.c`'), ['a', 'b.c']);
-      assert.deepEqual(split('a.`b.c`.d'), ['a', 'b.c', 'd']);
-      assert.deepEqual(split('a.`b.c`.d.`.e.f.g.`.h'), ['a', 'b.c', 'd', '.e.f.g.', 'h']);
-    });
-
-    it('should respect strings in “” double quotes', function() {
-      assert.deepEqual(split('“b.c”'), ['b.c']);
-      assert.deepEqual(split('a.“b.c”'), ['a', 'b.c']);
-      assert.deepEqual(split('a.“b.c”.d'), ['a', 'b.c', 'd']);
-      assert.deepEqual(split('a.“b.c”.d.“.e.f.g.”.h'), ['a', 'b.c', 'd', '.e.f.g.', 'h']);
-    });
-
-    it('should not split on escaped dots:', function() {
-      assert.deepEqual(split('a.b.c\\.d'), ['a', 'b', 'c.d']);
-    });
-
-    it('should keep escaping when followed by a backslash:', function() {
-      assert.deepEqual(split('a.b.c\\\\.d'), ['a', 'b', 'c\\\\', 'd']);
-      assert.deepEqual(split('a.b.c\\\\d'), ['a', 'b', 'c\\\\d']);
-    });
-
-    it('should retain unclosed double quotes in the results', function() {
-      assert.deepEqual(split('a."b.c'), ['a', '"b', 'c']);
-    });
-
-    it('should retain unclosed single quotes in the results', function() {
-      assert.deepEqual(split('brian\'s'), ['brian\'s']);
-      assert.deepEqual(split('a.\'b.c'), ['a', '\'b', 'c']);
-    });
-  });
-
-  describe('options', function() {
-    it('should keep double quotes', function() {
-      assert.deepEqual(split('a."b.c".d', {keepDoubleQuotes: true}), ['a', '"b.c"', 'd']);
-    });
-
-    it('should keep “” double quotes', function() {
-      assert.deepEqual(split('a.“b.c”.d', {keepDoubleQuotes: true}), ['a', '“b.c”', 'd']);
-    });
-
-    it('should not split inside brackets', function() {
-      var opts = { brackets: true };
-      assert.deepEqual(split('a.(b.c).d', opts), ['a', '(b.c)', 'd']);
-      assert.deepEqual(split('a.[(b.c)].d', opts), ['a', '[(b.c)]', 'd']);
-      assert.deepEqual(split('a.[b.c].d', opts), ['a', '[b.c]', 'd']);
-      assert.deepEqual(split('a.{b.c}.d', opts), ['a', '{b.c}', 'd']);
-      assert.deepEqual(split('a.<b.c>.d', opts), ['a', '<b.c>', 'd']);
-    });
-
-    it('should support nested brackets', function() {
-      var opts = { brackets: true };
-      assert.deepEqual(split('a.{b.{c}.d}.e', opts), ['a', '{b.{c}.d}', 'e']);
-      assert.deepEqual(split('a.{b.{c.d}.e}.f', opts), ['a', '{b.{c.d}.e}', 'f']);
-      assert.deepEqual(split('a.{[b.{{c.d}}.e]}.f', opts), ['a', '{[b.{{c.d}}.e]}', 'f']);
-    });
-
-    it('should support escaped brackets', function() {
-      var opts = { brackets: true };
-      assert.deepEqual(split('a.\\{b.{c.c}.d}.e', opts), ['a', '{b', '{c.c}', 'd}', 'e']);
-      assert.deepEqual(split('a.{b.c}.\\{d.e}.f', opts), ['a', '{b.c}', '{d', 'e}', 'f']);
-    });
-
-    it('should support quoted brackets', function() {
-      var opts = { brackets: true };
-      assert.deepEqual(split('a.{b.c}."{d.e}".f', opts), ['a', '{b.c}', '{d.e}', 'f']);
-      assert.deepEqual(split('a.{b.c}.{"d.e"}.f', opts), ['a', '{b.c}', '{"d.e"}', 'f']);
-    });
-
-    it('should ignore imbalanced brackets', function() {
-      var opts = { brackets: true };
-      assert.deepEqual(split('a.{b.c', opts), ['a', '{b', 'c']);
-      assert.deepEqual(split('a.{a.{b.c}.d', opts), ['a', '{a.{b.c}', 'd']);
-    });
-
-    it('should keep single quotes', function() {
-      assert.deepEqual(split('a.\'b.c\'.d', {keepSingleQuotes: true}), ['a', '\'b.c\'', 'd']);
-    });
-
-    it('should keep escape characters', function() {
-      assert.deepEqual(split('a.b\\.c', {keepEscaping: true}), ['a', 'b\\.c']);
-    });
-
-    it('should split on a custom separator', function() {
-      assert.deepEqual(split('a,b,c', {sep: ','}), ['a', 'b', 'c']);
-    });
-
-    it('should allow custom quotes array', function() {
-      assert.deepEqual(split('a.^b.c^', {quotes: ['^']}), ['a', 'b.c']);
-    });
-
-    it('should allow custom quotes object', function() {
-      assert.deepEqual(split('a.^b.c$', {quotes: {'^': '$'}}), ['a', 'b.c']);
-    });
-  });
-
-  describe('function', function() {
-    it('should call a custom function on every token', function() {
-      function fn(tok, tokens) {
-        if (tok.escaped && tok.val === 'b') {
-          tok.val = '\\b';
-          return;
-        }
-
-        if (!/[@!*+]/.test(tok.val)) return;
-        var stack = [];
-        var val = tok.val;
-        var str = tok.str;
-        var i = tok.idx;
-
-        while (++i < str.length) {
-          var ch = str[i];
-          if (ch === '(') {
-            stack.push(ch);
-          }
-
-          if (ch === ')') {
-            stack.pop();
-            if (!stack.length) {
-              val += ch;
-              break;
-            }
-          }
-          val += ch;
-        }
-
-        tok.split = false;
-        tok.val = val;
-        tok.idx = i;
-      }
-
-      var opts = {sep: ',', brackets: null};
-      assert.deepEqual(split('a,(\\b,c)', opts, fn), ['a', '(\\b', 'c)']);
-      assert.deepEqual(split('a,(b,c)', opts, fn), ['a', '(b', 'c)']);
-      assert.deepEqual(split('a,@(b,c)', opts, fn), ['a', '@(b,c)']);
-      assert.deepEqual(split('a,@(b,(a,b)c)', opts, fn), ['a', '@(b,(a,b)c)']);
-      assert.deepEqual(split('a,@(b,(a,b)c),z', opts, fn), ['a', '@(b,(a,b)c)', 'z']);
-      assert.deepEqual(split('a,+(b,c)', opts, fn), ['a', '+(b,c)']);
-      assert.deepEqual(split('a,*(b|c,d)', opts, fn), ['a', '*(b|c,d)']);
-    });
-  });
-});
diff --git a/test/custom-function.js b/test/custom-function.js
new file mode 100644
index 0000000..d096fd5
--- /dev/null
+++ b/test/custom-function.js
@@ -0,0 +1,50 @@
+'use strict';
+
+require('mocha');
+const assert = require('assert');
+const split = require('..');
+
+describe('function', function() {
+  it('should call a custom function on every token', function() {
+    function fn(tok) {
+      if (tok.type === 'escape' && tok.match[0] === '\\b') {
+        tok.keepEscaping = true;
+        return;
+      }
+
+      if (!/[@!*+]/.test(tok.value)) return;
+      const stack = [];
+      const str = this.string;
+      let i = -1;
+
+      while (++i < str.length) {
+        const ch = str[i];
+        if (ch === '(') {
+          stack.push(ch);
+        }
+
+        if (ch === ')') {
+          stack.pop();
+          if (!stack.length) {
+            this.consume(1);
+            tok.value += ch;
+            break;
+          }
+        }
+        this.consume(1);
+        tok.value += ch;
+      }
+    }
+
+    const opts = { separator: ',', brackets: false };
+    assert.deepEqual(split('a.@(b,c)', fn), ['a', '@(b,c)']);
+    assert.deepEqual(split('a,@(b,c)', opts, fn), ['a', '@(b,c)']);
+    assert.deepEqual(split('a,(\\b,c)', opts, fn), ['a', '(\\b', 'c)']);
+    assert.deepEqual(split('a,(b,c)', opts, fn), ['a', '(b', 'c)']);
+    assert.deepEqual(split('a,@(b,(c,d)e)', opts, fn), ['a', '@(b,(c,d)e)']);
+    assert.deepEqual(split('a,@(b,(c,d)e)z', opts, fn), ['a', '@(b,(c,d)e)z']);
+    assert.deepEqual(split('a,@(b,(a,b)c),z', opts, fn), ['a', '@(b,(a,b)c)', 'z']);
+    assert.deepEqual(split('a,+(b,c)', opts, fn), ['a', '+(b,c)']);
+    assert.deepEqual(split('a,*(b|c,d)', opts, fn), ['a', '*(b|c,d)']);
+  });
+});
diff --git a/test/options.js b/test/options.js
new file mode 100644
index 0000000..4790ccf
--- /dev/null
+++ b/test/options.js
@@ -0,0 +1,121 @@
+'use strict';
+
+require('mocha');
+var assert = require('assert');
+var split = require('..');
+
+describe('options', function() {
+  describe('separator', function() {
+    it('should split on a custom separator', function() {
+      assert.deepEqual(split('a/b/c', {separator: '/'}), ['a', 'b', 'c']);
+      assert.deepEqual(split('a,b,c', {separator: ','}), ['a', 'b', 'c']);
+    });
+
+    it('should not split on an escaped custom separator:', function() {
+      assert.deepEqual(split('a/b/c\\/d', {separator: '/'}), ['a', 'b', 'c/d']);
+    });
+
+    it('should take a custom function for splitting', function() {
+      const stash = split('a.b.c', function(token) {
+        const prev = this.prev();
+        if (prev && prev.value === 'a') {
+          token.split = () => false;
+        }
+      });
+      assert.deepEqual(stash, ['a.b', 'c']);
+    });
+
+    it('should take a custom options.split function for splitting', function() {
+      const stash = split('a.b.c', {
+        split: function(token) {
+          const prev = this.prev();
+          if (prev && prev.value === 'a') {
+            return false;
+          }
+          return true;
+        }
+      });
+      assert.deepEqual(stash, ['a.b', 'c']);
+    });
+  });
+
+  describe('quotes', function() {
+    it('should disable quotes support', function() {
+      assert.deepEqual(split('a.\'b.c\'."d"', {quotes: false}), ['a', '\'b', 'c\'', '"d"']);
+    });
+
+    it('should keep single quotes', function() {
+      assert.deepEqual(split('a.\'b.c\'."d"', {keepSingleQuotes: true}), ['a', '\'b.c\'', 'd']);
+      assert.deepEqual(split('a.\'b.c\'."d"', {keepQuotes: true}), ['a', '\'b.c\'', '"d"']);
+    });
+
+    it('should keep double quotes', function() {
+      assert.deepEqual(split('a."b.c".d', {keepDoubleQuotes: true}), ['a', '"b.c"', 'd']);
+      assert.deepEqual(split('a."b.c".d', {keepQuotes: true}), ['a', '"b.c"', 'd']);
+    });
+
+    it('should keep “” double quotes', function() {
+      assert.deepEqual(split('a.“b.c”.d', {keepSmartQuotes: true}), ['a', '“b.c”', 'd']);
+      assert.deepEqual(split('a.“b.c”.d', {keepQuotes: true}), ['a', '“b.c”', 'd']);
+    });
+
+    it('should keep backticks', function() {
+      assert.deepEqual(split('a.`b.c`.d', {keepBackticks: true}), ['a', '`b.c`', 'd']);
+      assert.deepEqual(split('a.`b.c`.d', {keepQuotes: true}), ['a', '`b.c`', 'd']);
+    });
+
+    it('should allow custom quotes object', function() {
+      assert.deepEqual(split('a.^b.c$', {quotes: {'^': '$'}}), ['a', 'b.c']);
+      assert.deepEqual(split('a.^b.c^', {quotes: {'^': '^'}}), ['a', 'b.c']);
+      assert.deepEqual(split('a.~b.c~', {quotes: {'~': '~'}}), ['a', 'b.c']);
+    });
+  });
+
+  describe('keepEscaping', function() {
+    it('should keep escape characters', function() {
+      assert.deepEqual(split('a.b\\.c', {keepEscaping: true}), ['a', 'b\\.c']);
+    });
+  });
+
+  describe('brackets', function() {
+    it('should throw when brackets are unclosed', function() {
+      assert.throws(function() {
+        split('a.{a.{b.c.}.c', {brackets: true, strict: true});
+      }, /unclosed/);
+    });
+
+    it('should not split inside brackets', function() {
+      var opts = { brackets: true };
+      assert.deepEqual(split('a.(b.c).d', opts), ['a', '(b.c)', 'd']);
+      assert.deepEqual(split('a.[(b.c)].d', opts), ['a', '[(b.c)]', 'd']);
+      assert.deepEqual(split('a.[b.c].d', opts), ['a', '[b.c]', 'd']);
+      assert.deepEqual(split('a.{b.c}.d', opts), ['a', '{b.c}', 'd']);
+      assert.deepEqual(split('a.<b.c>.d', opts), ['a', '<b.c>', 'd']);
+    });
+
+    it('should support nested brackets', function() {
+      var opts = { brackets: true };
+      assert.deepEqual(split('a.{b.{c}.d}.e', opts), ['a', '{b.{c}.d}', 'e']);
+      assert.deepEqual(split('a.{b.{c.d}.e}.f', opts), ['a', '{b.{c.d}.e}', 'f']);
+      assert.deepEqual(split('a.{[b.{{c.d}}.e]}.f', opts), ['a', '{[b.{{c.d}}.e]}', 'f']);
+    });
+
+    it('should support escaped brackets', function() {
+      var opts = { brackets: true };
+      assert.deepEqual(split('a.\\{b.{c.c}.d}.e', opts), ['a', '{b', '{c.c}', 'd}', 'e']);
+      assert.deepEqual(split('a.{b.c}.\\{d.e}.f', opts), ['a', '{b.c}', '{d', 'e}', 'f']);
+    });
+
+    it('should support quoted brackets', function() {
+      var opts = { brackets: true };
+      assert.deepEqual(split('a.{b.c}."{d.e}".f', opts), ['a', '{b.c}', '{d.e}', 'f']);
+      assert.deepEqual(split('a.{b.c}.{"d.e"}.f', opts), ['a', '{b.c}', '{"d.e"}', 'f']);
+    });
+
+    it('should ignore imbalanced brackets', function() {
+      var opts = { brackets: true };
+      assert.deepEqual(split('a.{b.c', opts), ['a', '{b', 'c']);
+      assert.deepEqual(split('a.{a.{b.c}.d', opts), ['a', '{a', '{b', 'c}', 'd']);
+    });
+  });
+});
diff --git a/test/test.js b/test/test.js
new file mode 100644
index 0000000..e1d4eb0
--- /dev/null
+++ b/test/test.js
@@ -0,0 +1,62 @@
+'use strict';
+
+require('mocha');
+var assert = require('assert');
+var split = require('..');
+
+describe('defaults', function() {
+  it('should throw an error when arguments are invalid', function() {
+    assert.throws(() => split(), /expected/);
+  });
+
+  it('should not split on escaped dots:', function() {
+    assert.deepEqual(split('a.b.c\\.d'), ['a', 'b', 'c.d']);
+  });
+
+  it('should keep escaping when followed by a backslash:', function() {
+    assert.deepEqual(split('a.b.c\\\\.d'), ['a', 'b', 'c\\\\', 'd']);
+    assert.deepEqual(split('a.b.c\\\\d'), ['a', 'b', 'c\\\\d']);
+  });
+
+  it('should split a string on dots by default:', function() {
+    assert.deepEqual(split('a.b.c'), ['a', 'b', 'c']);
+  });
+
+  it('should respect double-quoted strings', function() {
+    assert.deepEqual(split('"b.c"'), ['b.c']);
+    assert.deepEqual(split('a."b.c"'), ['a', 'b.c']);
+    assert.deepEqual(split('a".b.c"'), ['a.b.c']);
+    assert.deepEqual(split('a."b.c".d'), ['a', 'b.c', 'd']);
+    assert.deepEqual(split('a."b.c".d.".e.f.g.".h'), ['a', 'b.c', 'd', '.e.f.g.', 'h']);
+  });
+
+  it('should respect singlequoted strings', function() {
+    assert.deepEqual(split('\'b.c\''), ['b.c']);
+    assert.deepEqual(split('a.\'b.c\''), ['a', 'b.c']);
+    assert.deepEqual(split('a.\'b.c\'.d'), ['a', 'b.c', 'd']);
+    assert.deepEqual(split('a.\'b.c\'.d.\'.e.f.g.\'.h'), ['a', 'b.c', 'd', '.e.f.g.', 'h']);
+  });
+
+  it('should respect strings in backticks', function() {
+    assert.deepEqual(split('`b.c`'), ['b.c']);
+    assert.deepEqual(split('a.`b.c`'), ['a', 'b.c']);
+    assert.deepEqual(split('a.`b.c`.d'), ['a', 'b.c', 'd']);
+    assert.deepEqual(split('a.`b.c`.d.`.e.f.g.`.h'), ['a', 'b.c', 'd', '.e.f.g.', 'h']);
+  });
+
+  it('should respect strings in double smart-quotes: “”', function() {
+    assert.deepEqual(split('“b.c”'), ['b.c']);
+    assert.deepEqual(split('a.“b.c”'), ['a', 'b.c']);
+    assert.deepEqual(split('a.“b.c”.d'), ['a', 'b.c', 'd']);
+    assert.deepEqual(split('a.“b.c”.d.“.e.f.g.”.h'), ['a', 'b.c', 'd', '.e.f.g.', 'h']);
+  });
+
+  it('should retain unclosed double quotes in the results', function() {
+    assert.deepEqual(split('a."b.c'), ['a', '"b', 'c']);
+  });
+
+  it('should retain unclosed single quotes in the results', function() {
+    assert.deepEqual(split('brian\'s'), ['brian\'s']);
+    assert.deepEqual(split('a.\'b.c'), ['a', '\'b', 'c']);
+  });
+});

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-split-string.git



More information about the Pkg-javascript-commits mailing list