Skip to content
This repository was archived by the owner on Jun 28, 2021. It is now read-only.

Commit 4d0ff3d

Browse files
committed
escape: disabled when null or false
1 parent 33822b0 commit 4d0ff3d

File tree

5 files changed

+102
-48
lines changed

5 files changed

+102
-48
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212

1313
## Trunk
1414

15+
New feature:
16+
* escape: disabled when null or false
17+
1518
Project management:
1619
* travis: test node version 14
1720

lib/es5/index.js

Lines changed: 40 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,31 @@
22

33
function _wrapNativeSuper(Class) { var _cache = typeof Map === "function" ? new Map() : undefined; _wrapNativeSuper = function _wrapNativeSuper(Class) { if (Class === null || !_isNativeFunction(Class)) return Class; if (typeof Class !== "function") { throw new TypeError("Super expression must either be null or a function"); } if (typeof _cache !== "undefined") { if (_cache.has(Class)) return _cache.get(Class); _cache.set(Class, Wrapper); } function Wrapper() { return _construct(Class, arguments, _getPrototypeOf(this).constructor); } Wrapper.prototype = Object.create(Class.prototype, { constructor: { value: Wrapper, enumerable: false, writable: true, configurable: true } }); return _setPrototypeOf(Wrapper, Class); }; return _wrapNativeSuper(Class); }
44

5-
function isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
6-
7-
function _construct(Parent, args, Class) { if (isNativeReflectConstruct()) { _construct = Reflect.construct; } else { _construct = function _construct(Parent, args, Class) { var a = [null]; a.push.apply(a, args); var Constructor = Function.bind.apply(Parent, a); var instance = new Constructor(); if (Class) _setPrototypeOf(instance, Class.prototype); return instance; }; } return _construct.apply(null, arguments); }
5+
function _construct(Parent, args, Class) { if (_isNativeReflectConstruct()) { _construct = Reflect.construct; } else { _construct = function _construct(Parent, args, Class) { var a = [null]; a.push.apply(a, args); var Constructor = Function.bind.apply(Parent, a); var instance = new Constructor(); if (Class) _setPrototypeOf(instance, Class.prototype); return instance; }; } return _construct.apply(null, arguments); }
86

97
function _isNativeFunction(fn) { return Function.toString.call(fn).indexOf("[native code]") !== -1; }
108

119
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
1210

13-
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); }
11+
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
1412

15-
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); }
13+
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
1614

17-
function _iterableToArrayLimit(arr, i) { if (!(Symbol.iterator in Object(arr) || Object.prototype.toString.call(arr) === "[object Arguments]")) { return; } var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
15+
function _iterableToArrayLimit(arr, i) { if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return; var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
1816

1917
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
2018

21-
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); }
19+
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
20+
21+
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
22+
23+
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
2224

23-
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); }
25+
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter); }
2426

25-
function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); }
27+
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
2628

27-
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } }
29+
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
2830

2931
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
3032

@@ -38,15 +40,19 @@ function _defineProperties(target, props) { for (var i = 0; i < props.length; i+
3840

3941
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
4042

43+
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
44+
45+
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
46+
47+
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
48+
4149
function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
4250

4351
function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
4452

45-
function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
46-
47-
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
53+
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
4854

49-
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
55+
function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
5056

5157
/*
5258
CSV Parse
@@ -69,16 +75,18 @@ var bom_utf8 = Buffer.from([239, 187, 191]);
6975
var Parser = /*#__PURE__*/function (_Transform) {
7076
_inherits(Parser, _Transform);
7177

78+
var _super = _createSuper(Parser);
79+
7280
function Parser() {
7381
var _this;
7482

7583
var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
7684

7785
_classCallCheck(this, Parser);
7886

79-
_this = _possibleConstructorReturn(this, _getPrototypeOf(Parser).call(this, _objectSpread({}, {
87+
_this = _super.call(this, _objectSpread(_objectSpread({}, {
8088
readableObjectMode: true
81-
}, {}, opts)));
89+
}), opts));
8290
var options = {}; // Merge with user options
8391

8492
for (var opt in opts) {
@@ -177,18 +185,22 @@ var Parser = /*#__PURE__*/function (_Transform) {
177185
return delimiter;
178186
}); // Normalize option `escape`
179187

180-
if (options.escape === undefined || options.escape === null) {
188+
if (options.escape === undefined || options.escape === true) {
181189
options.escape = Buffer.from('"');
182190
} else if (typeof options.escape === 'string') {
183191
options.escape = Buffer.from(options.escape);
192+
} else if (options.escape === null || options.escape === false) {
193+
options.escape = null;
184194
}
185195

186-
if (!Buffer.isBuffer(options.escape)) {
187-
throw new Error("Invalid Option: escape must be a buffer or a string, got ".concat(JSON.stringify(options.escape)));
188-
} else if (options.escape.length !== 1) {
189-
throw new Error("Invalid Option Length: escape must be one character, got ".concat(options.escape.length));
190-
} else {
191-
options.escape = options.escape[0];
196+
if (options.escape !== null) {
197+
if (!Buffer.isBuffer(options.escape)) {
198+
throw new Error("Invalid Option: escape must be a buffer, a string or a boolean, got ".concat(JSON.stringify(options.escape)));
199+
} else if (options.escape.length !== 1) {
200+
throw new Error("Invalid Option Length: escape must be one character, got ".concat(options.escape.length));
201+
} else {
202+
options.escape = options.escape[0];
203+
}
192204
} // Normalize option `from`
193205

194206

@@ -608,7 +620,7 @@ var Parser = /*#__PURE__*/function (_Transform) {
608620
} else {
609621
// Escape is only active inside quoted fields
610622
// We are quoting, the char is an escape chr and there is a chr to escape
611-
if (this.state.quoting === true && chr === escape && pos + 1 < bufLen) {
623+
if (escape !== null && this.state.quoting === true && chr === escape && pos + 1 < bufLen) {
612624
if (escapeIsQuote) {
613625
if (buf[pos + 1] === quote) {
614626
this.state.escaping = true;
@@ -637,7 +649,7 @@ var Parser = /*#__PURE__*/function (_Transform) {
637649
// Treat next char as a regular character
638650
// TODO: need to compare bytes instead of single char
639651

640-
if (chr === escape && nextChr === quote) {
652+
if (escape !== null && chr === escape && nextChr === quote) {
641653
pos++;
642654
} else if (!nextChr || isNextChrDelimiter || isNextChrRowDelimiter || isNextChrComment || isNextChrTrimable) {
643655
this.state.quoting = false;
@@ -1309,13 +1321,15 @@ var parse = function parse() {
13091321
var CsvError = /*#__PURE__*/function (_Error) {
13101322
_inherits(CsvError, _Error);
13111323

1324+
var _super2 = _createSuper(CsvError);
1325+
13121326
function CsvError(code, message) {
13131327
var _this2;
13141328

13151329
_classCallCheck(this, CsvError);
13161330

13171331
if (Array.isArray(message)) message = message.join(' ');
1318-
_this2 = _possibleConstructorReturn(this, _getPrototypeOf(CsvError).call(this, message));
1332+
_this2 = _super2.call(this, message);
13191333

13201334
if (Error.captureStackTrace !== undefined) {
13211335
Error.captureStackTrace(_assertThisInitialized(_this2), CsvError);

lib/index.js

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -131,17 +131,21 @@ class Parser extends Transform {
131131
return delimiter
132132
})
133133
// Normalize option `escape`
134-
if(options.escape === undefined || options.escape === null){
134+
if(options.escape === undefined || options.escape === true){
135135
options.escape = Buffer.from('"')
136136
}else if(typeof options.escape === 'string'){
137137
options.escape = Buffer.from(options.escape)
138-
}
139-
if(!Buffer.isBuffer(options.escape)){
140-
throw new Error(`Invalid Option: escape must be a buffer or a string, got ${JSON.stringify(options.escape)}`)
141-
}else if(options.escape.length !== 1){
142-
throw new Error(`Invalid Option Length: escape must be one character, got ${options.escape.length}`)
143-
}else{
144-
options.escape = options.escape[0]
138+
}else if (options.escape === null || options.escape === false){
139+
options.escape = null
140+
}
141+
if(options.escape !== null){
142+
if(!Buffer.isBuffer(options.escape)){
143+
throw new Error(`Invalid Option: escape must be a buffer, a string or a boolean, got ${JSON.stringify(options.escape)}`)
144+
}else if(options.escape.length !== 1){
145+
throw new Error(`Invalid Option Length: escape must be one character, got ${options.escape.length}`)
146+
}else{
147+
options.escape = options.escape[0]
148+
}
145149
}
146150
// Normalize option `from`
147151
if(options.from === undefined || options.from === null){
@@ -494,7 +498,7 @@ class Parser extends Transform {
494498
}else{
495499
// Escape is only active inside quoted fields
496500
// We are quoting, the char is an escape chr and there is a chr to escape
497-
if(this.state.quoting === true && chr === escape && pos + 1 < bufLen){
501+
if(escape !== null && this.state.quoting === true && chr === escape && pos + 1 < bufLen){
498502
if(escapeIsQuote){
499503
if(buf[pos+1] === quote){
500504
this.state.escaping = true
@@ -518,7 +522,7 @@ class Parser extends Transform {
518522
// Escape a quote
519523
// Treat next char as a regular character
520524
// TODO: need to compare bytes instead of single char
521-
if(chr === escape && nextChr === quote){
525+
if(escape !== null && chr === escape && nextChr === quote){
522526
pos++
523527
}else if(!nextChr || isNextChrDelimiter || isNextChrRowDelimiter || isNextChrComment || isNextChrTrimable){
524528
this.state.quoting = false

samples/option.escape.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
const parse = require('../lib/sync')
2+
const assert = require('assert')
3+
4+
const data = `a,"b""c",d`
5+
const records = parse(data)
6+
console.log(records)
7+
assert.deepEqual(records, [
8+
[ 'a', 'b"c', 'd' ]
9+
])

test/option.escape.coffee

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,43 @@
22
parse = require '../lib'
33

44
describe 'Option `escape`', ->
5+
6+
describe 'normalisation, coercion & validation', ->
7+
8+
it 'default', ->
9+
parse().options.escape.should.eql Buffer.from('"')[0]
10+
parse(escape: undefined).options.escape.should.eql Buffer.from('"')[0]
11+
parse(escape: true).options.escape.should.eql Buffer.from('"')[0]
12+
13+
it 'custom', ->
14+
parse(escape: '\\').options.escape.should.eql Buffer.from('\\')[0]
15+
parse(escape: Buffer.from('\\')).options.escape.should.eql Buffer.from('\\')[0]
516

6-
it 'validation', ->
7-
parse '', escape: '\\', (->)
8-
parse '', escape: Buffer.from('\\'), (->)
9-
parse '', escape: null, (->)
10-
parse '', escape: undefined, (->)
11-
(->
12-
parse '', escape: false, (->)
13-
).should.throw 'Invalid Option: escape must be a buffer or a string, got false'
14-
(->
15-
parse '', escape: true, (->)
16-
).should.throw 'Invalid Option: escape must be a buffer or a string, got true'
17+
it 'disabled', ->
18+
(parse(escape: null).options.escape is null).should.be.true()
19+
(parse(escape: false).options.escape is null).should.be.true()
1720

21+
it 'invalid', ->
22+
(->
23+
parse escape: 1
24+
).should.throw 'Invalid Option: escape must be a buffer, a string or a boolean, got 1'
25+
(->
26+
parse escape: 'abc'
27+
).should.throw 'Invalid Option Length: escape must be one character, got 3'
28+
29+
describe 'disabled', ->
30+
31+
it 'when null', (next) ->
32+
parse '''
33+
a"b
34+
'1"2'
35+
''', escape: null, quote: '\'', (err, data) ->
36+
return next err if err
37+
data.should.eql [
38+
[ 'a"b' ],[ '1"2' ]
39+
]
40+
next()
41+
1842
describe 'same as quote', ->
1943

2044
it 'is same as quote', (next) ->
@@ -28,7 +52,7 @@ describe 'Option `escape`', ->
2852
[ 'f"g','h','i1"i2' ]
2953
]
3054
next()
31-
55+
3256
describe 'different than quote', ->
3357

3458
it 'apply to quote char', (next) ->

0 commit comments

Comments
 (0)