Socket
Socket
Sign inDemoInstall

export-to-csv

Package Overview
Dependencies
0
Maintainers
1
Versions
13
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 1.0.0 to 1.1.0

bun.lockb

174

output/index.js

@@ -1,173 +0,1 @@

const defaults = {
fieldSeparator: ",",
decimalSeparator: ".",
quoteStrings: true,
quoteCharacter: '"',
showTitle: false,
title: "My Generated Report",
filename: "generated",
showColumnHeaders: true,
useTextFile: false,
useBom: true,
columnHeaders: [],
useKeysAsHeaders: false,
boolDisplay: { true: "TRUE", false: "FALSE" },
};
const endOfLine = "\r\n";
const byteOrderMark = "\ufeff";
const mkConfig = (opts) => Object.assign({}, defaults, opts);
class CsvGenerationError extends Error {
constructor(message) {
super(message);
this.name = "CsvGenerationError";
}
}
class EmptyHeadersError extends Error {
constructor(message) {
super(message);
this.name = "EmptyHeadersError";
}
}
class CsvDownloadEnvironmentError extends Error {
constructor(message) {
super(message);
this.name = "CsvDownloadEnvironmentError";
}
}
const pack = (value) => value;
const unpack = (newtype) => newtype;
const mkCsvOutput = (pack);
const mkCsvRow = (pack);
const thread = (initialValue, ...fns) => fns.reduce((r, fn) => fn(r), initialValue);
const addBOM = (config) => (output) => config.useBom ? mkCsvOutput(unpack(output) + byteOrderMark) : output;
const addTitle = (config) => (output) => config.showTitle ? mkCsvOutput(unpack(output) + config.title) : output;
const addEndOfLine = (output) => (row) => mkCsvOutput(unpack(output) + unpack(row) + endOfLine);
const buildRow = (config) => (row, data) => addFieldSeparator(config)(mkCsvRow(row + data));
const addFieldSeparator = (config) => (output) => pack(unpack(output) + config.fieldSeparator);
const addHeaders = (config, headers) => (output) => {
if (!config.showColumnHeaders) {
return output;
}
if (headers.length < 1) {
throw new EmptyHeadersError("Option to show headers but none supplied. Make sure there are keys in your collection or that you've supplied headers through the config options.");
}
let row = mkCsvRow("");
for (let keyPos = 0; keyPos < headers.length; keyPos++) {
row = buildRow(config)(row, headers[keyPos]);
}
row = mkCsvRow(unpack(row).slice(0, -1));
return addEndOfLine(output)(row);
};
const addBody = (config, headers, bodyData) => (output) => {
let body = output;
for (var i = 0; i < bodyData.length; i++) {
let row = mkCsvRow("");
for (let keyPos = 0; keyPos < headers.length; keyPos++) {
const header = headers[keyPos];
row = buildRow(config)(row, formatData(config, bodyData[i][header]));
}
// Remove trailing comma
row = mkCsvRow(unpack(row).slice(0, -1));
body = addEndOfLine(body)(row);
}
return body;
};
/**
*
* Convert CsvOutput => string for the typechecker.
*
* Useful if you need to take the return value and
* treat is as a string in the rest of your program.
*/
const asString = (unpack);
const isFloat = (input) => +input === input && (!isFinite(input) || Boolean(input % 1));
const formatData = (config, data) => {
if (config.decimalSeparator === "locale" && isFloat(data)) {
return data.toLocaleString();
}
if (config.decimalSeparator !== "." && isFloat(data)) {
return data.toString().replace(".", config.decimalSeparator);
}
if (typeof data === "string") {
let val = data;
if (config.quoteStrings ||
data.indexOf(config.fieldSeparator) > -1 ||
data.indexOf("\n") > -1 ||
data.indexOf("\r") > -1) {
val = config.quoteCharacter + data + config.quoteCharacter;
}
return val;
}
if (typeof data === "boolean") {
// Convert to string to use as lookup in config
const asStr = data ? "true" : "false";
// Return the custom boolean display if set
return config.boolDisplay[asStr];
}
return data;
};
/**
*
* Generates CsvOutput data from JSON collection using
* ConfigOptions given.
*
* To comfortably use the data as a string around your
* application, look at {@link asString}.
*
* @throws {CsvGenerationError | EmptyHeadersError}
*/
const generateCsv = (config) => (data) => {
const withDefaults = mkConfig(config);
const headers = withDefaults.useKeysAsHeaders
? Object.keys(data[0])
: withDefaults.columnHeaders;
// Build csv output starting with an empty string
let output = thread(mkCsvOutput(""), addBOM(withDefaults), addTitle(withDefaults), addHeaders(withDefaults, headers), addBody(withDefaults, headers, data));
if (unpack(output).length < 1) {
throw new CsvGenerationError("Output is empty. Is your data formatted correctly?");
}
return output;
};
/**
*
* **Only supported in browser environment.**
*
* Will create a hidden anchor link in the page with the
* download attribute set to a blob version of the CsvOutput data.
*
* @throws {CsvDownloadEnvironmentError}
*/
const download = (config) => (csvOutput) => {
// Downloading is only supported in a browser environment.
// Node users can simply write the output from generateCsv
// to disk.
if (!window) {
throw new CsvDownloadEnvironmentError("Downloading only supported in a browser environment.");
}
const withDefaults = mkConfig(config);
const data = unpack(csvOutput);
// Create blob from CsvOutput either as text or csv file.
const fileType = withDefaults.useTextFile ? "plain" : "csv";
const fileExtension = withDefaults.useTextFile ? "txt" : "csv";
let blob = new Blob([data], {
type: `text/${fileType};charset=utf8;`,
});
// Create link element in the browser and set the download
// attribute to the blob that was created.
let link = document.createElement("a");
link.download = `${withDefaults.filename}.${fileExtension}`;
link.href = URL.createObjectURL(blob);
// Ensure the link isn't visible to the user or cause layout shifts.
link.setAttribute("visibility", "hidden");
// Add to document body, click and remove it.
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
};
export { asString, download, generateCsv, mkConfig };
//# sourceMappingURL=index.js.map
var O={fieldSeparator:",",decimalSeparator:".",quoteStrings:!0,quoteCharacter:'"',showTitle:!1,title:"My Generated Report",filename:"generated",showColumnHeaders:!0,useTextFile:!1,useBom:!0,columnHeaders:[],useKeysAsHeaders:!1,boolDisplay:{true:"TRUE",false:"FALSE"},replaceUndefinedWith:""},_="\r\n",G="\uFEFF",S=(x)=>Object.assign({},O,x);class W extends Error{constructor(x){super(x);this.name="CsvGenerationError"}}class X extends Error{constructor(x){super(x);this.name="EmptyHeadersError"}}class Y extends Error{constructor(x){super(x);this.name="CsvDownloadEnvironmentError"}}var U=(x)=>x,A=(x)=>x,N=U,Q=U;var H=(x,...$)=>$.reduce((j,q)=>q(j),x),M=(x)=>($)=>x.useBom?N(A($)+G):$,T=(x)=>($)=>x.showTitle?N(A($)+x.title):$,V=(x)=>($)=>N(A(x)+A($)+_),F=(x)=>($,j)=>b(x)(Q($+j)),b=(x)=>($)=>U(A($)+x.fieldSeparator),L=(x,$)=>(j)=>{if(!x.showColumnHeaders)return j;if($.length<1)throw new X("Option to show headers but none supplied. Make sure there are keys in your collection or that you've supplied headers through the config options.");let q=Q("");for(let z=0;z<$.length;z++)q=F(x)(q,P(x,$[z]));return q=Q(A(q).slice(0,-1)),V(j)(q)},R=(x,$,j)=>(q)=>{let z=q;for(var K=0;K<j.length;K++){let J=Q("");for(let I=0;I<$.length;I++){const Z=$[I],E=typeof j[K][Z]==="undefined"?x.replaceUndefinedWith:j[K][Z];J=F(x)(J,P(x,E))}J=Q(A(J).slice(0,-1)),z=V(z)(J)}return z},m=A,B=(x)=>+x===x&&(!isFinite(x)||Boolean(x%1)),P=(x,$)=>{if(x.decimalSeparator==="locale"&&B($))return $.toLocaleString();if(x.decimalSeparator!=="."&&B($))return $.toString().replace(".",x.decimalSeparator);if(typeof $==="string"){let j=$;if(x.quoteStrings||x.fieldSeparator&&$.indexOf(x.fieldSeparator)>-1||$.indexOf("\n")>-1||$.indexOf("\r")>-1)j=x.quoteCharacter+$+x.quoteCharacter;return j}if(typeof $==="boolean"&&x.boolDisplay){const j=$?"true":"false";return x.boolDisplay[j]}return $};var o=(x)=>($)=>{const j=S(x),q=j.useKeysAsHeaders?Object.keys($[0]):j.columnHeaders;let z=H(N(""),M(j),T(j),L(j,q),R(j,q,$));if(A(z).length<1)throw new W("Output is empty. Is your data formatted correctly?");return z},t=(x)=>($)=>{if(!window)throw new Y("Downloading only supported in a browser environment.");const j=S(x),q=A($),z=j.useTextFile?"plain":"csv",K=j.useTextFile?"txt":"csv";let J=new Blob([q],{type:`text/${z};charset=utf8;`}),I=document.createElement("a");I.download=`${j.filename}.${K}`,I.href=URL.createObjectURL(J),I.setAttribute("visibility","hidden"),document.body.appendChild(I),I.click(),document.body.removeChild(I)};export{S as mkConfig,o as generateCsv,t as download,m as asString};

@@ -0,1 +1,2 @@

/// <reference lib="dom" />
import { CsvOutput, ConfigOptions, IO } from "./types";

@@ -2,0 +3,0 @@ /**

@@ -23,2 +23,3 @@ export type Newtype<URI, A> = {

};
replaceUndefinedWith?: string | boolean | null;
};

@@ -25,0 +26,0 @@ export interface CsvOutput extends Newtype<{

{
"name": "export-to-csv",
"version": "1.0.0",
"version": "1.1.0",
"description": "Easily create CSV data from json collection",

@@ -11,9 +11,8 @@ "type": "module",

"scripts": {
"build": "rm -rf output && rollup -c rollup.config.mjs",
"e2e": "rm -rf integration/export-to-csv.js && npm run build && cp output/index.js integration/export-to-csv.js && playwright test",
"e2e-ci": "rm -rf integration/export-to-csv.js && npm run build && cp output/index.js integration/export-to-csv.js && npx playwright install --with-deps && playwright test",
"e2e-server": "npx http-server ./integration -p 3000",
"test": "jest",
"dev": "tsc --watch",
"prepublishOnly": "npm run build"
"build": "rm -rf output && bun build index.ts --outdir ./output --minify && tsc index.ts --declaration --emitDeclarationOnly --outdir ./output",
"e2e": "rm -rf integration/export-to-csv.js && bun run build && cp output/index.js integration/export-to-csv.js && playwright test",
"e2e-ci": "rm -rf integration/export-to-csv.js && bun run build && cp output/index.js integration/export-to-csv.js && bunx playwright install --with-deps && playwright test",
"e2e-server": "bunx http-server ./integration -p 3000",
"test": "bun test lib/__specs__/",
"prepublishOnly": "bun run build"
},

@@ -47,6 +46,6 @@ "keywords": [

"babel-jest": "^29.6.4",
"bun-types": "^1.0.3",
"http-server": "^14.1.1",
"jest": "^29.6.4",
"prettier": "3.0.3",
"rollup": "^3.28.1",
"bun": "~1.0.3",
"tslib": "^2.6.2",

@@ -53,0 +52,0 @@ "typescript": "~5.2.2"

@@ -23,2 +23,4 @@ # export-to-csv | Export to CSV Mini Library

### In-browser
```typescript

@@ -58,19 +60,57 @@ import { mkConfig, generateCsv, download } from "export-to-csv";

### Node.js
```typescript
import { mkConfig, generateCsv, asString } from "./output/index.js";
import { writeFile } from "node:fs";
import { Buffer } from "node:buffer";
// mkConfig merges your options with the defaults
// and returns WithDefaults<ConfigOptions>
const csvConfig = mkConfig({ useKeysAsHeaders: true });
const mockData = [
{
name: "Rouky",
date: "2023-09-01",
percentage: 0.4,
quoted: '"Pickles"',
},
{
name: "Keiko",
date: "2023-09-01",
percentage: 0.9,
quoted: '"Cactus"',
},
];
// Converts your Array<Object> to a CsvOutput string based on the configs
const csv = generateCsv(csvConfig)(mockData);
const filename = `${csvConfig.filename}.csv`;
const csvBuffer = new Uint8Array(Buffer.from(asString(csv)));
// Write the csv file to disk
writeFile(filename, csvBuffer, (err) => {
if (err) throw err;
console.log("file saved: ", filename);
});
```
## API
| Option | Default | Type | Description |
| ----------------- | ------------------------------ | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| fieldSeparator | "," | string | Defines the field separator character |
| filename | "generated" | string | Sets the name of the file creates from the `download` function |
| quoteStrings | false | boolean | Determines whether or not to quote strings (using `quoteCharacter`'s value). Whether or not this is set, `\r`, `\n`, and `fieldSeparator` will be quoted. |
| quoteCharacter | '"' | string | Sets the quote character to use. |
| decimalSeparator | "." | string | Defines the decimal separator character (default is .). If set to "locale", it uses the [language sensitive representation of the number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString). |
| showTitle | false | boolean | Sets whether or not to add the value of `title` to the start of the CSV. (This is not supported by all CSV readers) |
| title | "My Generated Report" | string | The title to display as the first line of the CSV file. (This **is not** the name of the file [see `filename`]) |
| showColumnHeaders | true | boolean | Determines if columns should have headers. When set to `false`, the first row of the CSV will be data. |
| columnHeaders | [] | Array<string> | **Use this option if column/header order is important!** Determines the headers to use as the first line of the CSV data. Items in the array _must match key names of objects in your input collection._ |
| useKeysAsHeaders | false | boolean | If set, the CSV will use the key names in your collection as headers. **Warning: `headers` recommended for large collections. If set, it'll override the `headers` option. Column/header order also not guaranteed. Use `headers` only if order is important!** |
| boolDisplay | {true: "TRUE", false: "FALSE"} | {true: string, false: string} | Determines how to display boolean values in the CSV. **This only works for `true` and `false`. `1` and `0` will not be coerced and will display as `1` and `0`.** |
| useBom | true | boolean | Adds a [byte order mark](https://en.wikipedia.org/wiki/Byte_order_mark) which is required by Excel to display CSVs, despite is not being necessary with UTF-8 🤷‍♂️ |
| useTextFile | false | boolean | Will download the file as `text/plain` instead of `text/csv` and use a `.txt` vs `.csv` file-extension. |
| Option | Default | Type | Description |
| ------------------- | -------------------------------- | ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `fieldSeparator` | `","` | `string` | Defines the field separator character |
| `filename` | `"generated"` | `string` | Sets the name of the file creates from the `download` function |
| `quoteStrings` | `false` | `boolean` | Determines whether or not to quote strings (using `quoteCharacter`'s value). Whether or not this is set, `\r`, `\n`, and `fieldSeparator` will be quoted. |
| `quoteCharacter` | `'"'` | `string` | Sets the quote character to use. |
| `decimalSeparator` | `"."` | `string` | Defines the decimal separator character (default is .). If set to "locale", it uses the [language sensitive representation of the number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString). |
| `showTitle` | `false` | `boolean` | Sets whether or not to add the value of `title` to the start of the CSV. (This is not supported by all CSV readers) |
| `title` | `"My Generated Report"` | `string` | The title to display as the first line of the CSV file. (This **is not** the name of the file [see `filename`]) |
| `showColumnHeaders` | `true` | `boolean` | Determines if columns should have headers. When set to `false`, the first row of the CSV will be data. |
| `columnHeaders` | `[]` | `Array<string>` | **Use this option if column/header order is important!** Determines the headers to use as the first line of the CSV data. Items in the array _must match key names of objects in your input collection._ |
| `useKeysAsHeaders` | `false` | `boolean` | If set, the CSV will use the key names in your collection as headers. **Warning: `headers` recommended for large collections. If set, it'll override the `headers` option. Column/header order also not guaranteed. Use `headers` only if order is important!** |
| `boolDisplay` | `{true: "TRUE", false: "FALSE"}` | `{true: string, false: string}` | Determines how to display boolean values in the CSV. **This only works for `true` and `false`. `1` and `0` will not be coerced and will display as `1` and `0`.** |
| `useBom` | `true` | `boolean` | Adds a [byte order mark](https://en.wikipedia.org/wiki/Byte_order_mark) which is required by Excel to display CSVs, despite is not being necessary with UTF-8 🤷‍♂️ |
| `useTextFile` | `false` | `boolean` | Will download the file as `text/plain` instead of `text/csv` and use a `.txt` vs `.csv` file-extension. |

@@ -77,0 +117,0 @@ # Alternatives

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc