Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@flourish/layout

Package Overview
Dependencies
Maintainers
24
Versions
87
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@flourish/layout - npm Package Compare versions

Comparing version
8.6.0
to
8.7.0
+3
-3
package.json
{
"name": "@flourish/layout",
"type": "module",
"version": "8.6.0",
"version": "8.7.0",
"private": false,

@@ -51,4 +51,4 @@ "description": "Flourish module to control layouts",

"@flourish/pocket-knife": "^2.3.0",
"@flourish/utils-color": "^2.0.0",
"@flourish/number-formatter": "^2.0.0"
"@flourish/number-formatter": "^2.0.0",
"@flourish/utils-color": "^2.0.0"
},

@@ -55,0 +55,0 @@ "exports": "./src/index.js",

@@ -0,1 +1,4 @@

# 8.7.0
* Use Visualization title for csv download filename
# 8.6.0

@@ -2,0 +5,0 @@ * Update @flourish/interpreter to v9.2.0 to improve date interpretations

@@ -197,2 +197,32 @@ import { zipSync, strToU8 } from "fflate";

function sanitizeFilename(filename) {
return (
filename
// Remove path traversal
.replace(/^\.+/, "")
// eslint-disable-next-line no-useless-escape
.replace(/[\/\\]/g, "_")
// Remove invalid characters
// eslint-disable-next-line no-control-regex
.replace(/[<>:"|?*\x00-\x1f]/g, "_")
// Handle Windows reserved names
.replace(/^(con|prn|aux|nul|com[0-9]|lpt[0-9])$/i, "_$1")
// Remove leading/trailing spaces and dots
.trim()
.replace(/[\s.]+$/, "")
// Limit length (preserve extension)
.slice(0, 255)
);
}
function generateCSVFilename(extension = "csv") {
const visualization_title = window.template?.metadata?.visualization_title;
const sanitized_title = sanitizeFilename(
visualization_title || "Untitled_Visualization",
);
const filename = `${sanitized_title}.${extension}`;
return filename;
}
async function getData() {

@@ -210,3 +240,3 @@ const zip_files = {};

const dataset_name = datasets_to_download[0];
const file_name = `Flourish-data_${dataset_name}.csv`;
const file_name = generateCSVFilename("csv");
const csv_string = generateCSVString(formatted_datasets, dataset_name);

@@ -223,3 +253,3 @@ // Add BOM to CSV string before creating the blob

const file_name = `Flourish-data.zip`;
const file_name = generateCSVFilename("zip");
const zip_data = zipSync(zip_files);

@@ -240,2 +270,3 @@ const blob = new Blob([zip_data], { type: "application/zip" });

formatData,
sanitizeFilename,
};

@@ -7,2 +7,3 @@ import { expect } from "chai";

formatData,
sanitizeFilename,
} from "./data-download.js";

@@ -433,1 +434,77 @@ import {

});
describe("sanitizeFilename", () => {
it("should replace invalid characters with underscores", () => {
expect(sanitizeFilename("My<File>Name:Test")).to.equal("My_File_Name_Test");
expect(sanitizeFilename("File|With?Invalid*Chars")).to.equal(
"File_With_Invalid_Chars",
);
expect(sanitizeFilename('File"With"Quotes')).to.equal("File_With_Quotes");
});
it("should replace forward and back slashes with underscores", () => {
expect(sanitizeFilename("path/to/file")).to.equal("path_to_file");
expect(sanitizeFilename("path\\to\\file")).to.equal("path_to_file");
expect(sanitizeFilename("C:\\Users\\data")).to.equal("C__Users_data");
});
it("should remove leading dots to prevent hidden files", () => {
expect(sanitizeFilename(".hidden")).to.equal("hidden");
expect(sanitizeFilename("..hidden")).to.equal("hidden");
expect(sanitizeFilename("...file")).to.equal("file");
});
it("should handle Windows reserved names", () => {
expect(sanitizeFilename("con")).to.equal("_con");
expect(sanitizeFilename("prn")).to.equal("_prn");
expect(sanitizeFilename("aux")).to.equal("_aux");
expect(sanitizeFilename("nul")).to.equal("_nul");
expect(sanitizeFilename("com1")).to.equal("_com1");
expect(sanitizeFilename("lpt1")).to.equal("_lpt1");
expect(sanitizeFilename("CON")).to.equal("_CON");
});
it("should trim leading and trailing spaces", () => {
expect(sanitizeFilename(" title ")).to.equal("title");
expect(sanitizeFilename(" file name ")).to.equal("file name");
});
it("should remove trailing dots and spaces to prevent issues when extension is added", () => {
expect(sanitizeFilename("title...")).to.equal("title");
expect(sanitizeFilename("title ")).to.equal("title");
expect(sanitizeFilename("title. . .")).to.equal("title");
});
it("should limit title length to 255 characters", () => {
const longTitle = "a".repeat(300);
expect(sanitizeFilename(longTitle)).to.have.lengthOf(255);
});
it("should handle control characters", () => {
expect(sanitizeFilename("file\x00name")).to.equal("file_name");
expect(sanitizeFilename("file\x1fname")).to.equal("file_name");
});
it("should handle normal titles without changes", () => {
expect(sanitizeFilename("normal_title")).to.equal("normal_title");
expect(sanitizeFilename("title-name-123")).to.equal("title-name-123");
expect(sanitizeFilename("MyVisualization2024")).to.equal(
"MyVisualization2024",
);
});
it("should handle titles that happen to contain dots", () => {
expect(sanitizeFilename("Q1.2024 Report")).to.equal("Q1.2024 Report");
expect(sanitizeFilename("Data v2.0")).to.equal("Data v2.0");
});
it("should handle complex visualization titles", () => {
expect(sanitizeFilename(" <Report>: Q1/2024 | Final* ")).to.equal(
"_Report__ Q1_2024 _ Final_",
);
expect(sanitizeFilename("..Sales\\Data|2024?")).to.equal(
"Sales_Data_2024_",
);
expect(sanitizeFilename('My "Best" Viz!')).to.equal("My _Best_ Viz!");
});
});

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display