@paulof25/emoji-separated-values
Version:
emoji-separated-values (or simply ESV) is your new favorite npm package for handling text-based data. Forget about boring commas — we use emojis as delimiters. Because why not?
110 lines (89 loc) • 3.49 kB
text/typescript
import { type EsvRow } from "../../core/entities/EsvRow.ts";
import ReadLine from "readline";
import fs from "fs";
export class FileSystemEsvRepository {
//le o arquivo e retorna um stream
async readEsvFile(filePath: string) {
const stream = fs.createReadStream(filePath, { encoding: "utf-8" });
const reader = ReadLine.createInterface({
input: stream,
crlfDelay: Infinity,
});
return reader;
}
//cria um stream de escrita
getFileWriteStream(filePath: string, flags: string = "a") {
const stream = fs.createWriteStream(filePath, { encoding: "utf-8", flags: flags });
return stream;
}
//escreve um arquivo
async writeEsvFile(filePath: string, data: EsvRow[], separator: string, flags: string = "a") {
const fileExists = await this.fileExists(filePath);
const stream = fs.createWriteStream(filePath, { encoding: "utf-8", flags: flags });
let lineCount = 0;
if (!fileExists && data.length > 0) {
const header = Object.keys(data[0]);
const headerLine = header.map(this.escapeField).join(separator);
stream.write(headerLine + "\n");
}
for (const record of data) {
const values = Object.values(record).map((value) => this.escapeField(String(value)));
const line = values.join(separator);
stream.write(line + "\n");
lineCount++;
}
stream.end();
return new Promise<void>((resolve, reject) => {
stream.on("finish", () => {
console.log("Esv file written successfully");
return resolve();
});
stream.on("error", (error) => {
return reject(error);
});
});
}
//funcao que renomeia um arquivo
renameFile(oldPath: string, newPath: string) {
fs.renameSync(oldPath, newPath);
}
//funcao que deleta um arquivo
deleteFile(filePath: string) {
fs.unlinkSync(filePath);
}
//funcao que escapa um campo que contenha as seguintes carateres: ", \n
escapeField(valor: string): string {
if (/[",\n]/.test(valor)) {
return `"${valor.replace(/"/g, '""')}"`;
}
return valor;
}
//função que divide uma linha em campos usando o emoji como separador
splitEsvLine(line: string, separator: string): string[] {
return line.split(separator);
}
//transforma uma linha em um objeto EsvRecord
parseEsvLine(line: string, header: string[], separator: string): EsvRow {
const values = this.splitEsvLine(line, separator);
const record: EsvRow = {};
for (let i = 0; i < header.length; i++) {
record[header[i]] = values[i];
}
return record;
}
//funcao que normaliza um valor sem acento
normalizeValue(value: string): string | number | boolean {
const trimmedValue = value.trim();
const normalized = trimmedValue.normalize("NFD").replace(/[\u0300-\u036f]/g, "");
return normalized;
}
//funcao que verifica se um arquivo existe
async fileExists(filePath: string): Promise<boolean> {
try {
fs.accessSync(filePath);
return true;
} catch {
return false;
}
}
}