-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement toCsv #1
Changes from 3 commits
d25fb08
8422072
22fa547
90a5c72
e15d88f
bccb86d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { toString } from "micro-dash"; | ||
|
||
export function toCsv(data: any[][]) { | ||
return data | ||
.map((row) => row.map((cell) => escape(cell)).join(",")) | ||
.join("\n"); | ||
} | ||
|
||
function escape(value: any) { | ||
const string = toString(value); | ||
|
||
if (/["|,|\n|\r]/.test(string)) { | ||
return wrapWithQuotes(string.replace(/"/g, `""`)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
} else { | ||
return string; | ||
} | ||
} | ||
|
||
function wrapWithQuotes(string: string) { | ||
return `"${string}"`; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import { toCsv } from "./to-csv"; | ||
|
||
describe("toCsv()", () => { | ||
it("works", () => { | ||
expect(toCsv([["a", "b", "c"], ["d", "e", "f"], ["g", "h", "i"]])).toBe( | ||
"a,b,c\nd,e,f\ng,h,i", | ||
); | ||
}); | ||
|
||
it("handles empty cells properly", () => { | ||
expect( | ||
toCsv([ | ||
["middle", "", "empty"], | ||
["", "start", "empty"], | ||
["end", "empty", ""], | ||
]), | ||
).toBe("middle,,empty\n,start,empty\nend,empty,"); | ||
}); | ||
|
||
it("handles empty rows properly", () => { | ||
expect(toCsv([["row"], [], ["another row"], []])).toBe( | ||
"row\n\nanother row\n", | ||
); | ||
}); | ||
|
||
it("properly escapes double quotes", () => { | ||
expect(toCsv([["escape", "csv", `"quotes"`]])).toBe( | ||
`escape,csv,"""quotes"""`, | ||
); | ||
}); | ||
|
||
it("properly escapes commas", () => { | ||
expect( | ||
toCsv([["eats shoots and leaves", "eats, shoots, and leaves"]]), | ||
).toBe(`eats shoots and leaves,"eats, shoots, and leaves"`); | ||
}); | ||
|
||
it("properly escapes new lines", () => { | ||
expect( | ||
toCsv([["one", "1"], ["two", "1\n2"], ["three", "1\n2\n3"]]), | ||
).toBe(`one,1\ntwo,"1\n2"\nthree,"1\n2\n3"`); | ||
expect( | ||
toCsv([["one", "1"], ["two", "1\r2"], ["three", "1\r2\r3"]]), | ||
).toBe(`one,1\ntwo,"1\r2"\nthree,"1\r2\r3"`); | ||
expect( | ||
toCsv([["one", "1"], ["two", "1\r\n2"], ["three", "1\r\n2\r\n3"]]), | ||
).toBe(`one,1\ntwo,"1\r\n2"\nthree,"1\r\n2\r\n3"`); | ||
}); | ||
|
||
it("escapes properly if there are multiple special things", () => { | ||
expect( | ||
toCsv([ | ||
["one", "with, comma"], | ||
["another", "with\nnewline"], | ||
["last", `with "quotes"`], | ||
]), | ||
).toBe( | ||
`one,"with, comma"\nanother,"with\nnewline"\nlast,"with ""quotes"""`, | ||
); | ||
}); | ||
|
||
it("handles things that aren't strings", () => { | ||
expect( | ||
toCsv([ | ||
[undefined, null], | ||
[true, false], | ||
[1, 2, 3], | ||
[{}, { hi: "there" }], | ||
]), | ||
).toBe(",\ntrue,false\n1,2,3\n[object Object],[object Object]"); | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[green]
Maybe "content" instead of "data"?