From d906164972139468d9d6c95db198050d9243d3a8 Mon Sep 17 00:00:00 2001 From: Alex Caza Date: Mon, 29 Apr 2024 16:28:07 -0400 Subject: [PATCH] As blob feature (#103) * Update lockfile bun.lockb was referring to incorrect playwright version. * Add asBlob method Useful for cases where you need to have a Blob object. Like downloading using browser extension APIs. --- bun.lockb | Bin 22029 -> 24230 bytes flake.lock | 6 +++--- lib/__specs__/main.spec.ts | 22 +++++++++++++++++++++- lib/generator.ts | 35 ++++++++++++++++++++++++++--------- 4 files changed, 50 insertions(+), 13 deletions(-) diff --git a/bun.lockb b/bun.lockb index 04888e93ab10660a50d850049ea92ad2adbca7e6..546ee7ed3294816fc8b36595b55b281065c668db 100755 GIT binary patch delta 6999 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 { expect(firstLine).toBe("Test Csv 2\r"); }); + + describe("asBlob", () => { + it("should construct a valid blob based on options", async () => { + const options: ConfigOptions = { + title: "Test Csv 2", + showTitle: true, + useBom: false, + showColumnHeaders: true, + columnHeaders: ["name", "age"], + }; + + const output = generateCsv(options)(mockData); + const blob = asBlob(options)(output); + const text = await blob.text(); + + expect(blob.type).toBe("text/csv;charset=utf8;"); + expect(text.split("\n")[0]).toBe("Test Csv 2\r"); + expect(blob.size).toBe(65); + }); + }); }); diff --git a/lib/generator.ts b/lib/generator.ts index 01571b0..8f0c7f4 100644 --- a/lib/generator.ts +++ b/lib/generator.ts @@ -56,6 +56,26 @@ export const generateCsv = return output; }; +/** + * Returns the Blob representation of the CsvOutput generated + * by `generateCsv`. This is useful if you need to access the + * data for downloading in other contexts; like browser extensions. + */ +export const asBlob = + (config: ConfigOptions) => + (csvOutput: CsvOutput): Blob => { + 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 blob = new Blob([data], { + type: `text/${fileType};charset=utf8;`, + }); + + return blob; + }; + /** * * **Only supported in browser environment.** @@ -77,20 +97,17 @@ export const download = ); } - 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 blob = asBlob(config)(csvOutput); + + const withDefaults = mkConfig(config); const fileExtension = withDefaults.useTextFile ? "txt" : "csv"; - let blob = new Blob([data], { - type: `text/${fileType};charset=utf8;`, - }); + const fileName = `${withDefaults.filename}.${fileExtension}`; // 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}`; + const link = document.createElement("a"); + link.download = fileName; link.href = URL.createObjectURL(blob); // Ensure the link isn't visible to the user or cause layout shifts.