Skip to content

Instantly share code, notes, and snippets.

@daviesesiro
Created January 9, 2021 17:55
Show Gist options
  • Save daviesesiro/47ed33090ec584a42e33f57762fbdce2 to your computer and use it in GitHub Desktop.
Save daviesesiro/47ed33090ec584a42e33f57762fbdce2 to your computer and use it in GitHub Desktop.
const express = require("express");
const { get } = require("axios").default;
const { randomBytes } = require("crypto");
const app = express();
app.use(express.json());
const CSVtoJson = (csvStr = "", selected = []) => {
var parsedRows = [];
var quote = false; // inside quotes?
for (var row = 0, col = 0, i = 0; i < csvStr.length; i++) {
let currentChar = csvStr[i],
nextChar = csvStr[i + 1];
parsedRows[row] = parsedRows[row] || []; // Create a new row if necessary
parsedRows[row][col] = parsedRows[row][col] || ""; // Create a new column if necessary
if (currentChar == '"' && quote && nextChar == '"') {
parsedRows[row][col] += currentChar;
++i;
continue;
}
if (currentChar == '"') {
quote = !quote;
continue;
}
if (currentChar == "," && !quote) {
++col;
continue;
}
if (currentChar == "\r" && nextChar == "\n" && !quote) {
++row;
col = 0;
++i;
continue;
}
if ((currentChar == "\n" || currentChar == "\r") && !quote) {
++row;
col = 0;
continue;
}
parsedRows[row][col] += currentChar;
}
return tranformParsedArray(parsedRows, selected);
};
const tranformParsedArray = (arr, selected) => {
const result = [];
const heads = trimArrItems(arr[0]);
const errors = [];
// validate csv
arr.forEach(item => {
if (item.length != arr[0].length)
errors.push(genError("Not a valid CSV file"));
});
if (errors.length > 0) return { errors };
const selectedHeadsIdx = selected.map(selectedItem => {
const match = heads.findIndex(
item => selectedItem.toLowerCase() == item.toLowerCase()
);
if (match == -1) {
errors.push({ [selectedItem]: "Not a valid column in csv" });
} else {
return match;
}
});
arr.forEach((rowArr, rowIdx) => {
let temp = {};
if (rowIdx == 0) return;
trimArrItems(rowArr).forEach((item, itemIdx) => {
if (selected.length < 1) {
temp[heads[itemIdx]] = item;
return;
}
if (selectedHeadsIdx.some(e => e === itemIdx)) {
temp[heads[itemIdx]] = item;
}
});
result.push(temp);
});
return { result, errors };
};
//helpers
const trimArrItems = arr => {
return arr.map(e => e.trim());
};
const genError = msg => ({
error: msg
});
const fetchCSV = async url => (await get(url)).data;
app.get("/", async (req, res) => {
res.send("Please use a POST method instead");
});
app.post("/", async (req, res) => {
const { select_fields, url } = req.body.csv || {};
if (!url) {
res.json(genError("Please enter a url"));
}
let csv = "";
try {
csv = await fetchCSV(url);
} catch (err) {
res.status(400).json(genError("url is probably invalid"));
}
const { errors, result } = CSVtoJson(csv, select_fields);
if (errors && errors.length > 0) {
res.status(400).json(genError(errors));
} else {
res.json({
conversion_key: randomBytes(10).toString("hex"),
json: result
});
}
});
const listener = app.listen(process.env.PORT, () => {
console.log("Your app is listening on port " + listener.address().port);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment