Skip to content

Commit 63f5f1d

Browse files
committed
Merge pull request #25 from doug-martin/master
v0.2.2
2 parents dea9a9d + 4b489d2 commit 63f5f1d

File tree

3 files changed

+205
-6
lines changed

3 files changed

+205
-6
lines changed

lib/parser.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ function createParser(options) {
1414
VALUE_REGEXP = new RegExp("([^" + delimiter + "'\"\\s\\\\]*(?:\\s+[^" + delimiter + "'\"\\s\\\\]+)*)"),
1515
SEARCH_REGEXP = new RegExp("(?:\\n|\\r|" + delimiter + ")"),
1616
ESCAPE_CHAR = options.escape || '"',
17-
NEXT_TOKEN_REGEXP = new RegExp("([^\\s]|\\n|\\r|" + delimiter + ")"),
18-
LINE_BREAK = /[\r\n]/;
17+
NEXT_TOKEN_REGEXP = new RegExp("([^\\s]|\\r\\n|\\n|\\r|" + delimiter + ")"),
18+
LINE_BREAK = /(\r\n|\n|\r)/;
1919

2020
function formatItem(item) {
2121
if (doTrim) {
@@ -112,9 +112,10 @@ function createParser(options) {
112112
}
113113

114114
function getNextToken(line, cursor) {
115-
var token, nextIndex;
116-
if ((nextIndex = line.substr(cursor).search(NEXT_TOKEN_REGEXP)) !== -1) {
115+
var token, nextIndex, subStr = line.substr(cursor);
116+
if ((nextIndex = subStr.search(NEXT_TOKEN_REGEXP)) !== -1) {
117117
token = line[cursor += nextIndex];
118+
cursor += subStr.match(NEXT_TOKEN_REGEXP)[1].length - 1;
118119
}
119120
return {token: token, cursor: cursor};
120121
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "fast-csv",
3-
"version": "0.2.1",
3+
"version": "0.2.2",
44
"description": "CSV parser and writer",
55
"main": "index.js",
66
"scripts": {

test/parser.test.js

Lines changed: 199 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,6 @@ it.describe("fast-csv parser", function (it) {
200200
});
201201
});
202202
});
203-
204203
});
205204

206205
it.describe("with \\r", function (it) {
@@ -402,4 +401,203 @@ it.describe("fast-csv parser", function (it) {
402401

403402
});
404403

404+
it.describe("with \\r\\n", function (it) {
405+
406+
it.describe("unescaped data", function (it) {
407+
408+
it.should("parse a block of CSV text", function () {
409+
var data = "first_name,last_name,email_address\r\nFirst1,Last1,[email protected]";
410+
var myParser = parser({delimiter: ","});
411+
assert.deepEqual(myParser(data, false), {"line": "", "rows": [
412+
["first_name", "last_name", "email_address"],
413+
["First1", "Last1", "[email protected]"]
414+
]});
415+
});
416+
417+
it.should("return the rest of the line if there is more data", function () {
418+
var data = "first_name,last_name,email_address\r\nFirst1,Last1,[email protected]";
419+
var myParser = parser({delimiter: ","});
420+
assert.deepEqual(myParser(data, true), {
421+
"line": "First1,Last1,[email protected]",
422+
"rows": [
423+
["first_name", "last_name", "email_address"]
424+
]
425+
});
426+
});
427+
428+
it.should("accept new data and return the result", function () {
429+
var data = "first_name,last_name,email_address\r\nFirst1,Last1,[email protected],";
430+
var myParser = parser({delimiter: ","});
431+
var parsedData = myParser(data, true);
432+
assert.deepEqual(parsedData, {
433+
"line": "First1,Last1,[email protected],",
434+
"rows": [
435+
["first_name", "last_name", "email_address"]
436+
]
437+
});
438+
assert.deepEqual(myParser(parsedData.line + "\r\nFirst2,Last2,[email protected]", false), {"line": "", "rows": [
439+
["First1", "Last1", "[email protected]"],
440+
["First2", "Last2", "[email protected]"]
441+
]});
442+
});
443+
444+
it.should("not parse a row if a new line is not found and there is more data", function () {
445+
var data = "first_name,last_name,email_address";
446+
var myParser = parser({delimiter: ","});
447+
var parsedData = myParser(data, true);
448+
assert.deepEqual(parsedData, {
449+
"line": "first_name,last_name,email_address",
450+
"rows": []
451+
});
452+
});
453+
454+
it.should("not parse a row if there is a trailing delimiter and there is more data", function () {
455+
var data = "first_name,last_name,email_address,";
456+
var myParser = parser({delimiter: ","});
457+
var parsedData = myParser(data, true);
458+
assert.deepEqual(parsedData, {
459+
"line": "first_name,last_name,email_address,",
460+
"rows": []
461+
});
462+
});
463+
464+
it.should("parse a row if a new line is found and there is more data", function () {
465+
var data = "first_name,last_name,email_address\r\n";
466+
var myParser = parser({delimiter: ","});
467+
var parsedData = myParser(data, true);
468+
assert.deepEqual(parsedData, {
469+
"line": "",
470+
"rows": [
471+
["first_name", "last_name", "email_address"]
472+
]
473+
});
474+
});
475+
476+
});
477+
478+
it.describe("escaped values", function (it) {
479+
480+
it.should("parse a block of CSV text", function () {
481+
var data = 'first_name,last_name,email_address\r\n"First,1","Last,1","[email protected]"';
482+
var myParser = parser({delimiter: ","});
483+
assert.deepEqual(myParser(data, false), {"line": "", "rows": [
484+
["first_name", "last_name", "email_address"],
485+
["First,1", "Last,1", "[email protected]"]
486+
]});
487+
});
488+
489+
it.should("parse a block of CSV text with escaped escaped char", function () {
490+
var data = 'first_name,last_name,email_address\r\n"First,""1""","Last,""1""","[email protected]"';
491+
var myParser = parser({delimiter: ","});
492+
assert.deepEqual(myParser(data, false), {"line": "", "rows": [
493+
["first_name", "last_name", "email_address"],
494+
["First,\"1\"", "Last,\"1\"", "[email protected]"]
495+
]});
496+
});
497+
498+
it.should("parse a block of CSV text with alternate escape char", function () {
499+
var data = 'first_name,last_name,email_address\r\n"First,\\"1\\"","Last,\\"1\\"","[email protected]"';
500+
var myParser = parser({delimiter: ",", escape: "\\"});
501+
assert.deepEqual(myParser(data, false), {"line": "", "rows": [
502+
["first_name", "last_name", "email_address"],
503+
["First,\"1\"", "Last,\"1\"", "[email protected]"]
504+
]});
505+
});
506+
507+
it.should("return the rest of the line if a complete value is not found", function () {
508+
var data = 'first_name,last_name,email_address\r\n"First,""1""","Last,""1""","[email protected]';
509+
var myParser = parser({delimiter: ","});
510+
assert.deepEqual(myParser(data, true), {
511+
"line": '"First,""1""","Last,""1""","[email protected]',
512+
"rows": [
513+
["first_name", "last_name", "email_address"]
514+
]
515+
});
516+
});
517+
518+
it.should("accept more data appended to the returned line with escaped values", function () {
519+
var data = 'first_name,last_name,email_address\r\n"First,""1""","Last,""1""","[email protected]';
520+
var myParser = parser({delimiter: ","}),
521+
parsedData = myParser(data, true);
522+
assert.deepEqual(parsedData, {
523+
"line": '"First,""1""","Last,""1""","[email protected]',
524+
"rows": [
525+
["first_name", "last_name", "email_address"]
526+
]
527+
});
528+
assert.deepEqual(myParser(parsedData.line + '"\r\n"First,""2""","Last,""2""","[email protected]"', false), {
529+
line: "",
530+
rows: [
531+
["First,\"1\"", "Last,\"1\"", "[email protected]"],
532+
["First,\"2\"", "Last,\"2\"", "[email protected]"]
533+
]
534+
});
535+
});
536+
537+
it.should("throw an error if there is not more data and there is an invalid escape sequence", function () {
538+
var data = 'first_name,last_name,email_address\r\n"First,""1""","Last,""1""","[email protected]';
539+
var myParser = parser({delimiter: ","}),
540+
parsedData = myParser(data, true);
541+
assert.deepEqual(parsedData, {
542+
"line": '"First,""1""","Last,""1""","[email protected]',
543+
"rows": [
544+
["first_name", "last_name", "email_address"]
545+
]
546+
});
547+
assert.throws(function () {
548+
assert.deepEqual(myParser(parsedData.line + '\r\n"First,"",2""","Last""2""","[email protected]"', false), {
549+
line: "",
550+
rows: [
551+
["First,\"1\"", "Last,\"1\"", "[email protected]"],
552+
["First,\"2\"", "Last,\"2\"", "[email protected]"]
553+
]
554+
});
555+
}, Error, ' Parse Error: expected: \'"\' got: \'F\'. at \'First,""2""","Last""2""","[email protected]"');
556+
});
557+
558+
it.should("handle empty values properly", function () {
559+
var data = '"","",""\r\n,Last4,[email protected]';
560+
var myParser = parser({delimiter: ","}),
561+
parsedData = myParser(data, false);
562+
assert.deepEqual(parsedData, {"line": "", "rows": [
563+
["", "", ""],
564+
["", "Last4", "[email protected]"]
565+
]});
566+
});
567+
568+
it.should("not parse a row if a new line is not found and there is more data", function () {
569+
var data = '"first_name","last_name","email_address"';
570+
var myParser = parser({delimiter: ","});
571+
var parsedData = myParser(data, true);
572+
assert.deepEqual(parsedData, {
573+
"line": '"first_name","last_name","email_address"',
574+
"rows": []
575+
});
576+
});
577+
578+
it.should("not parse a row if there is a trailing delimiter and there is more data", function () {
579+
var data = '"first_name","last_name","email_address",';
580+
var myParser = parser({delimiter: ","});
581+
var parsedData = myParser(data, true);
582+
assert.deepEqual(parsedData, {
583+
"line": '"first_name","last_name","email_address",',
584+
"rows": []
585+
});
586+
});
587+
588+
it.should("parse a row if a new line is found and there is more data", function () {
589+
var data = '"first_name","last_name","email_address"\r\n';
590+
var myParser = parser({delimiter: ","});
591+
var parsedData = myParser(data, true);
592+
assert.deepEqual(parsedData, {
593+
"line": "",
594+
"rows": [
595+
["first_name", "last_name", "email_address"]
596+
]
597+
});
598+
});
599+
});
600+
601+
});
602+
405603
});

0 commit comments

Comments
 (0)