split-string
Advanced tools
Comparing version 4.0.0 to 5.0.0
293
index.js
/*! | ||
* 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. | ||
@@ -10,3 +10,8 @@ */ | ||
var extend = require('extend-shallow'); | ||
const Lexer = require('snapdragon-lexer'); | ||
const union = require('arr-union'); | ||
const defaults = { | ||
brackets: { '<': '>', '(': ')', '[': ']', '{': '}' }, | ||
quotes: { '"': '"', "'": "'", '`': '`', '“': '”' } | ||
}; | ||
@@ -23,163 +28,197 @@ module.exports = function(str, options, fn) { | ||
// allow separator to be defined as a string | ||
if (typeof options === 'string') { | ||
options = { sep: options }; | ||
} | ||
var opts = extend({sep: '.'}, options); | ||
var quotes = opts.quotes || { | ||
'"': '"', | ||
"'": "'", | ||
'`': '`', | ||
'“': '”' | ||
const opts = Object.assign({ separator: '.' }, options); | ||
const sep = opts.sep || opts.separator; | ||
const lexer = new Lexer(str, opts); | ||
lexer.split = (token) => { | ||
if (typeof lexer.options.split === 'function') { | ||
return lexer.options.split.call(lexer, token); | ||
} | ||
return true; | ||
}; | ||
if (Array.isArray(quotes)) { | ||
quotes = quotes.reduce(function(acc, ele) { | ||
acc[ele] = ele; | ||
return acc; | ||
}, {}); | ||
} | ||
// brackets support | ||
const brackets = opts.brackets === true ? defaults.brackets : opts.brackets; | ||
var brackets; | ||
if (opts.brackets === true) { | ||
brackets = { | ||
'<': '>', | ||
'(': ')', | ||
'[': ']', | ||
'{': '}' | ||
}; | ||
} else if (opts.brackets) { | ||
brackets = opts.brackets; | ||
} | ||
// quotes support | ||
const quotes = opts.quotes === true || typeof opts.quotes === 'undefined' | ||
? defaults.quotes | ||
: opts.quotes; | ||
var tokens = []; | ||
var stack = []; | ||
var arr = ['']; | ||
var sep = opts.sep; | ||
var len = str.length; | ||
var idx = -1; | ||
var closeIdx; | ||
const openChars = brackets ? Object.keys(brackets) : []; | ||
const closeChars = brackets ? Object.values(brackets) : []; | ||
const quoteChars = union(Object.keys(quotes), Object.values(quotes)); | ||
const openStr = brackets ? escape(openChars) : ''; | ||
const closeStr = brackets ? escape(closeChars) : ''; | ||
const quoteStr = quotes ? escape(quoteChars) : ''; | ||
const textRegexp = new RegExp(`^[^\\\\${sep + openStr + closeStr + quoteStr}]+`); | ||
function expected() { | ||
if (brackets && stack.length) { | ||
return brackets[stack[stack.length - 1]]; | ||
/** | ||
* Handlers | ||
*/ | ||
lexer.capture('escape', /^\\(.)/, function(token) { | ||
token.escaped = true; | ||
if (opts.keepEscaping !== true && token.value !== '\\\\') { | ||
token.value = token.value.slice(1); | ||
} | ||
} | ||
if (fn) fn.call(this, token); | ||
return token; | ||
}); | ||
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); | ||
lexer.capture('separator', toRegexp(escape(sep.split(''))), function(token) { | ||
if (fn) fn.call(this, token); | ||
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 (typeof token.split === 'function' && token.split() === false) { | ||
return token; | ||
} | ||
if (lexer.split(token) === false) { | ||
return token; | ||
} | ||
if (brackets && brackets[ch]) { | ||
stack.push(ch); | ||
var e = expected(); | ||
var i = idx + 1; | ||
if (!this.stack.length && this.last(this.stash) !== '') { | ||
this.stash.push(''); | ||
} | ||
if (!this.isInside('quote') && !this.isInside('bracket')) { | ||
token.value = ''; | ||
} | ||
return token; | ||
}); | ||
if (str.indexOf(e, i + 1) !== -1) { | ||
while (stack.length && i < len) { | ||
var s = str[++i]; | ||
if (s === '\\') { | ||
s++; | ||
continue; | ||
} | ||
lexer.capture('text', textRegexp, (token) => { | ||
if (fn) fn.call(lexer, token); | ||
return token; | ||
}); | ||
if (quotes[s]) { | ||
i = getClosingQuote(str, quotes[s], i + 1); | ||
continue; | ||
} | ||
if (quotes) { | ||
lexer.capture('quote', toRegexp(quoteStr), function(token) { | ||
if (this.isInside('bracket')) return token; | ||
e = expected(); | ||
if (stack.length && str.indexOf(e, i + 1) === -1) { | ||
break; | ||
} | ||
let val = token.match[0]; | ||
token.append = false; | ||
if (brackets[s]) { | ||
stack.push(s); | ||
continue; | ||
} | ||
if (e === s) { | ||
stack.pop(); | ||
} | ||
} | ||
if (!keepQuotes(val, opts)) { | ||
token.value = ''; | ||
} | ||
closeIdx = i; | ||
if (closeIdx === -1) { | ||
arr[arr.length - 1] += ch; | ||
continue; | ||
} | ||
if (this.isClose(val)) { | ||
const open = this.stack.pop(); | ||
open.closed = true; | ||
this.unwind(open, true); | ||
this.append(token.value); | ||
ch = str.slice(idx, closeIdx + 1); | ||
tok.val = ch; | ||
tok.idx = idx = closeIdx; | ||
} | ||
if (quotes[ch]) { | ||
closeIdx = getClosingQuote(str, quotes[ch], idx + 1); | ||
if (closeIdx === -1) { | ||
arr[arr.length - 1] += ch; | ||
continue; | ||
} else { | ||
token.isClose = value => value === quotes[val]; | ||
token.queue = []; | ||
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', toRegexp(openStr), function(token) { | ||
token.isClose = value => value === brackets[token.value]; | ||
token.append = false; | ||
token.queue = []; | ||
this.stack.push(token); | ||
return token; | ||
}); | ||
lexer.capture('bracket.close', toRegexp(closeStr), function(token) { | ||
if (this.isClose(token.value)) { | ||
const open = this.stack.pop(); | ||
open.value += open.queue.join(''); | ||
this.append(open.value); | ||
} | ||
return token; | ||
}); | ||
} | ||
tok.val = ch; | ||
tok.idx = idx = closeIdx; | ||
/** | ||
* Custom lexer methods | ||
*/ | ||
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; | ||
} | ||
}; | ||
if (tok.val === sep && tok.split !== false) { | ||
arr.push(''); | ||
continue; | ||
// add queued strings back to the stash | ||
lexer.unwind = function(token, append) { | ||
switch (token && token.type) { | ||
case 'bracket': | ||
const segs = token.queue.join('').split('.'); | ||
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 (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 toRegexp(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 keepQuotes(ch, opts) { | ||
if (opts.keepSmartQuotes === true && (ch === '“' || ch === '”')) { | ||
return true; | ||
} | ||
return opts.keepEscaping === true || str[idx + 1] === '\\'; | ||
if (opts.keepDoubleQuotes === true && ch === '"') { | ||
return true; | ||
} | ||
if (opts.keepSingleQuotes === true && ch === '\'') { | ||
return true; | ||
} | ||
if (opts.keepBackticks === true && ch === '`') { | ||
return true; | ||
} | ||
return opts.keepQuotes; | ||
} |
{ | ||
"name": "split-string", | ||
"description": "Split a string on a character except when the character is escaped.", | ||
"version": "4.0.0", | ||
"version": "5.0.0", | ||
"homepage": "https://github.com/jonschlinkert/split-string", | ||
@@ -24,10 +24,12 @@ "author": "Jon Schlinkert (https://github.com/jonschlinkert)", | ||
"scripts": { | ||
"test": "mocha" | ||
"test": "nyc mocha" | ||
}, | ||
"dependencies": { | ||
"extend-shallow": "^3.0.0" | ||
"arr-union": "^3.1.0", | ||
"snapdragon-lexer": "^2.0.0" | ||
}, | ||
"devDependencies": { | ||
"mocha": "^3.5.3", | ||
"gulp-format-md": "^1.0.0", | ||
"mocha": "^3.5.3" | ||
"nyc": "^11.4.1" | ||
}, | ||
@@ -40,2 +42,8 @@ "keywords": [ | ||
], | ||
"nyc": { | ||
"reporter": [ | ||
"lcov", | ||
"text-summary" | ||
] | ||
}, | ||
"verb": { | ||
@@ -42,0 +50,0 @@ "toc": false, |
@@ -31,3 +31,3 @@ # split-string [![NPM version](https://img.shields.io/npm/v/split-string.svg?style=flat)](https://www.npmjs.com/package/split-string) [![NPM monthly downloads](https://img.shields.io/npm/dm/split-string.svg?style=flat)](https://npmjs.org/package/split-string) [![NPM total downloads](https://img.shields.io/npm/dt/split-string.svg?style=flat)](https://npmjs.org/package/split-string) [![Linux Build Status](https://img.shields.io/travis/jonschlinkert/split-string.svg?style=flat&label=Travis)](https://travis-ci.org/jonschlinkert/split-string) | ||
**Bad** | ||
**This is bad** | ||
@@ -42,3 +42,3 @@ ```js | ||
**Good** | ||
**This is good** | ||
@@ -124,8 +124,10 @@ ```js | ||
// 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 | ||
### options.separator | ||
@@ -136,3 +138,3 @@ **Type**: `string` | ||
The separator/character to split on. | ||
The separator/character to split on. Aliased as `options.sep` for backwards compatibility with versions <4.0. | ||
@@ -142,6 +144,6 @@ **Example** | ||
```js | ||
split('a.b,c', {sep: ','}); | ||
split('a.b,c', {separator: ','}); | ||
//=> ['a.b', 'c'] | ||
// you can also pass the separator as string as the last argument | ||
// you can also pass the separator as a string as the last argument | ||
split('a.b,c', ','); | ||
@@ -237,8 +239,8 @@ //=> ['a.b', 'c'] | ||
```js | ||
var arr = split('a.b', function(tok) { | ||
if (tok.arr[tok.arr.length - 1] === 'a') { | ||
tok.split = false; | ||
var res = split('a.b', function(token) { | ||
if (token.tokens[0] === 'a') { | ||
token.split = false; | ||
} | ||
}); | ||
console.log(arr); | ||
console.log(res); | ||
//=> ['a.b'] | ||
@@ -249,11 +251,17 @@ ``` | ||
The `tok` object has the following properties: | ||
The `token` object has the following properties: | ||
* `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 | ||
* `token.val` (string) The current value about to be pushed onto the result array | ||
* `token.index` (number) the current index in the string | ||
* `token.input` (string) the entire input string | ||
* `token.tokens` (array) the result array | ||
## Release history | ||
### v4.0.0 - 2017-11-22 | ||
**Changed** | ||
* `options.quotes` should now be formatted as an object | ||
### v3.0.0 - 2017-06-17 | ||
@@ -284,3 +292,2 @@ | ||
</details> | ||
<details> | ||
@@ -312,3 +319,3 @@ <summary><strong>Building docs</strong></summary> | ||
| --- | --- | | ||
| 34 | [jonschlinkert](https://github.com/jonschlinkert) | | ||
| 36 | [jonschlinkert](https://github.com/jonschlinkert) | | ||
| 10 | [doowb](https://github.com/doowb) | | ||
@@ -320,2 +327,3 @@ | ||
* [linkedin/in/jonschlinkert](https://linkedin.com/in/jonschlinkert) | ||
* [github/jonschlinkert](https://github.com/jonschlinkert) | ||
@@ -326,3 +334,3 @@ * [twitter/jonschlinkert](https://twitter.com/jonschlinkert) | ||
Copyright © 2017, [Jon Schlinkert](https://github.com/jonschlinkert). | ||
Copyright © 2018, [Jon Schlinkert](https://github.com/jonschlinkert). | ||
Released under the [MIT License](LICENSE). | ||
@@ -332,2 +340,2 @@ | ||
_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.6.0, on November 22, 2017._ | ||
_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.6.0, on January 08, 2018._ |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
16272
190
329
2
3
1
+ Addedarr-union@^3.1.0
+ Addedsnapdragon-lexer@^2.0.0
+ Added@sellside/emitter@1.2.1(transitive)
+ Addedarr-union@3.1.0(transitive)
+ Addedkind-of@6.0.3(transitive)
+ Addedsnapdragon-handlers@1.0.0(transitive)
+ Addedsnapdragon-lexer@2.0.0(transitive)
+ Addedsnapdragon-stack@1.0.1(transitive)
+ Addedsnapdragon-token@3.0.1(transitive)
+ Addeduse@3.1.1(transitive)
- Removedextend-shallow@^3.0.0
- Removedassign-symbols@1.0.0(transitive)
- Removedextend-shallow@3.0.2(transitive)
- Removedis-extendable@1.0.1(transitive)
- Removedis-plain-object@2.0.4(transitive)
- Removedisobject@3.0.1(transitive)