Compare commits

..

10 Commits

Author SHA1 Message Date
3e39b9c36a FIX: Criação de condição para geração de endereço para CEP e para Geolocalização.
- CSVs com CEP e numero não estavam trazendo o endereço.
-Fiz uma condição para tratar o endereço de formas diferentes caso seja CEP e numero e caso seja geolocalização.
2026-01-16 08:05:46 -03:00
tulioperdigao
5543f87348 REFACTOR: Atualiza rota de consulta por geolocalização para incluir prefixo 'viabilidade' 2026-01-15 16:16:09 -03:00
tulioperdigao
e24db52732 FEAT: Adiciona suporte à consulta de viabilidade por geolocalização e refatora lógica de processamento de CSV 2026-01-15 15:16:28 -03:00
e5b530f9a4 REFACTOR: Adicionado o parametro source no post para a API, e refatorado callback de autenticação. 2026-01-09 08:52:15 -03:00
2542bb1f44 REFACTOR: Projeto refatorado para utilizar api de contratação para efetuar as viabilidades. 2026-01-07 09:49:26 -03:00
tulioperdigao
15485bb405 FEAT: Adiciona controle de download para CSV processado e modelos, além de melhorias na lógica de upload e processamento de arquivos CSV 2025-12-30 11:37:42 -03:00
b3bca576da REFACTOR: Remoção de serviços obsoletos e implementação da nova funcionalidade de viabilidade pela API de contratação
- Removidos os arquivos não utilizados: fetchService, geocodeService, normalizeService e retryService.

- Adicionado o viabilidadeController para gerenciar consultas de viabilidade e upload de arquivos CSV.

- Criadas as viabilidadeRoutes para tratar as rotas da API relacionadas à viabilidade.

- Implementado o csvService para processamento de arquivos CSV e integração com as consultas de viabilidade.

- Criado o jobStore.service para gerenciamento do estado dos jobs durante o processamento do CSV.

- Desenvolvido o viabilidadeService para integração com a API de viabilidade.
2025-12-30 09:16:07 -03:00
0de64d4024 REFACTOR: Remoção de serviços obsoletos e implementação da nova funcionalidade de viabilidade pela API de contratação
- Removidos os arquivos não utilizados: fetchService, geocodeService, normalizeService e retryService.

- Adicionado o viabilidadeController para gerenciar consultas de viabilidade e upload de arquivos CSV.

- Criadas as viabilidadeRoutes para tratar as rotas da API relacionadas à viabilidade.

- Implementado o csvService para processamento de arquivos CSV e integração com as consultas de viabilidade.

- Criado o jobStore.service para gerenciamento do estado dos jobs durante o processamento do CSV.

- Desenvolvido o viabilidadeService para integração com a API de viabilidade.
2025-12-30 09:08:21 -03:00
equipe desenvolvimento
7fce4cf7b8 FEAT: Adiciona intruções para uso do CSV de geolocalização 2025-12-04 11:51:55 -03:00
tulioperdigao
3942864554 FEAT: Adiciona novo arquivo de modelo para análise de viabilidade por geolocalização e disponibiliza para download ao clicar em "Baixar Modelos". Pequenas alterações nos textos do front-end. 2025-11-10 14:38:01 -03:00
1287 changed files with 7644 additions and 170989 deletions

15
.env
View File

@ -1,15 +0,0 @@
GOOGLE_API_KEY="AIzaSyCTrRFGKCZSspHRmTWQiclmIEOg-LROgyo"
API_URL="https://plutao.geogridmaps.com.br/vale/api/v3/viabilidade/raio"
API_KEY="6d717e972ba17c7cf0ab731801b8bbeac2f281e5"
COKIE="PHPSESSID=6d717e972ba17c7cf0ab731801b8bbeac2f281e5"
PORT="3000"
OAUTH_CLIENT_ID=e2104cd1-d67c-4ac1-8fe2-36e8caac89b7
OAUTH_CLIENT_SECRET=sVj8Q~eSXJpnQoqjvpOwjYeesVf_DJNRqTa4ua-6
OAUTH_TENANT_ID=5cd8533a-4260-48c5-87fd-8511b1b42f9b
OAUTH_REDIRECT_URI=https://viabiliza.sothis.com.br/auth/callback
OAUTH_SCOPES=https://graph.microsoft.com/.default
SESSION_SECRET=j2633669
NODE_ENV=production
DEV_SKIP_AUTH=false

2
.gitignore vendored
View File

@ -4,3 +4,5 @@ node_modules/
.vscode/
.cache/
uploads/
.cache/
.vscode/

1
.node-version Normal file
View File

@ -0,0 +1 @@
20

713
app.js
View File

@ -1,669 +1,82 @@
require("dotenv").config();
const requireAuth = require('./middlewares/requireAuth');
const authRoutes = require('./routes/authRoutes');
const express = require('express');
const path = require('path');
const session = require('express-session');
require('dotenv').config();
const express = require("express");
const multer = require("multer");
const fs = require("fs");
const path = require("path");
const csv = require("csv-parser");
const fastCsv = require("fast-csv");
const axios = require("axios");
const cors = require("cors");
const session = require("express-session"); // adiciona session
const { geocodeWithGoogle, addressWithGoogle } = require("./service/geocodeService");
const { fetchJson } = require("./service/fetchService");
const { BASE_BACKOFF_MS, MAX_RETRIES, REQUEST_DELAY_MS, sleep } = require("./service/retryService");
const { API_URL, HEADERS } = require("./config/apiConfig");
const { normalizePartnerSigla } = require("./service/normalizeService");
const authRoutes = require("./routes/authRoutes.js");
const viabilidadeRoutes = require('./routes/viabilidadeRoutes');
function createApp() {
const upload = multer({ dest: "uploads/" });
const app = express();
const app = express();
// se estiver atrás de um reverse proxy (nginx/traefik) em produção, habilite:
app.set("trust proxy", 1);
// Basic middleware
app.use(express.json({ limit: '5mb' }));
app.use(express.urlencoded({ extended: true }));
app.use(cors());
app.use(express.json());
// Session (in-memory, fine for dev/tests)
app.use(session({
secret: process.env.SESSION_SECRET || 'dev-secret',
resave: false,
saveUninitialized: false,
cookie: { secure: false } // secure should be true behind HTTPS in prod
}));
// session TEM que vir antes das rotas que usam req.session
app.use(
session({
secret: process.env.SESSION_SECRET || "change-me",
resave: false,
saveUninitialized: false,
cookie: {
maxAge: 24 * 60 * 60 * 1000,
secure: process.env.NODE_ENV === "production",
sameSite: "lax",
},
})
);
// Registrar authRoutes primeiro (rotas de login)
app.use(authRoutes);
// -- Desenvolvimento: pular autenticação se configurado
// Para ativar: defina NODE_ENV=development e DEV_SKIP_AUTH=true no .env
if (process.env.NODE_ENV === 'development' && process.env.DEV_SKIP_AUTH === 'true') {
app.use((req, res, next) => {
// garante que exista uma sessão autenticada para facilitar testes locais
if (req.session && (!req.session.user || !req.session.user.authenticated)) {
req.session.user = { authenticated: true, dev: true };
}
next();
});
}
// Dev bypass for Microsoft auth / session (only when explicitly enabled)
// MUST come before the global protection middleware so it can insert req.session.user
if (process.env.NODE_ENV === 'development' && process.env.DEV_SKIP_AUTH === 'true') {
app.use((req, res, next) => {
if (!req.session) return next();
// note: property must be `authenticated` (with 'h') so requireAuth recognizes it
req.session.user = req.session.user || { authenticated: true, id: 'dev', name: 'developer' };
next();
});
}
// middleware que protege rotas que exigem login
function requireAuth(req, res, next) {
if (req.session?.user?.authenticated) {
// Note: static assets must be served AFTER the global protection middleware
// when you want the site to redirect to /login before delivering the UI.
// Proteção global (após static + dev bypass)
app.use((req, res, next) => {
if (
req.path.startsWith('/auth') ||
req.path === '/login' ||
req.path === '/health'
) {
return next();
}
if (req.xhr || req.headers.accept?.includes("application/json")) {
return res.status(401).json({ error: "not_authenticated" });
}
return requireAuth(req, res, next);
});
return res.redirect("/login");
}
// Serve static assets (UI) AFTER protection so the app redirects to /login first
app.use(express.static(path.join(__dirname, 'public')));
// Mount API routes
app.use('/', viabilidadeRoutes);
// proteger demais rotas (ex.: /upload, /consulta)
app.use((req, res, next) => {
// permissão liberada para rotas de auth já tratadas; proteger o resto
if (req.path.startsWith("/auth") || req.path === "/login") return next();
return requireAuth(req, res, next);
});
// Health endpoint
app.get('/health', (req, res) => res.json({ ok: true }));
// redirect raiz
app.get("/", (req, res) => {
// em dev com bypass, sirva a página diretamente (sem redirect)
// 404
app.use((req, res) => res.status(404).json({ error: 'Not found' }));
// Error handler
app.use((err, req, res, next) => {
console.error(err && (err.stack || err.message) || err);
res.status(500).json({ error: 'Internal server error' });
});
if (require.main === module) {
const port = parseInt(process.env.PORT, 10) || 3000;
app.listen(port, () => {
console.log(`Server listening on port ${port} (env=${process.env.NODE_ENV || 'production'})`);
if (process.env.NODE_ENV === 'development' && process.env.DEV_SKIP_AUTH === 'true') {
return res.sendFile(path.join(__dirname, 'public', 'index.html'));
}
if (req.session?.user?.authenticated) {
return res.redirect("/public/index.html");
}
return res.redirect("/login");
});
/////////////////////////////////////////////////////
async function getMinDistance(lat, lon) {
// tenta várias vezes com backoff exponencial; trata 429 usando Retry-After se disponível
let attempt = 0;
while (attempt < MAX_RETRIES) {
try {
// envia também o raio (em metros) - API espera esse parâmetro em várias rotas
const resp = await axios.get(API_URL, {
headers: HEADERS,
params: {
raio: 5000,
latitude: lat,
longitude: lon,
"itens[]": ["caixa"],
consultarPasta: "S",
},
timeout: 10000,
});
const data = resp.data;
const registros = data && data.registros ? data.registros : [];
// find registros that have a numeric distancia and keep original object for robust extraction
const candidates = registros
.map((r) => ({ raw: r, distanciaRaw: r && r.distancia }))
.map((o) => ({
raw: o.raw,
num:
o.distanciaRaw !== undefined &&
o.distanciaRaw !== null &&
o.distanciaRaw !== ""
? Number(o.distanciaRaw)
: null,
}))
.filter((x) => x.num !== null && !Number.isNaN(x.num));
if (candidates.length) {
candidates.sort((a, b) => a.num - b.num);
const best = candidates[0];
const r = best.raw || {};
// robust extraction of pasta sigla with fallbacks
let pastaSigla = null;
try {
if (r.pasta) {
if (typeof r.pasta === "string" && r.pasta.trim())
pastaSigla = r.pasta.trim();
else if (r.pasta.sigla && String(r.pasta.sigla).trim())
pastaSigla = String(r.pasta.sigla).trim();
else if (
r.pasta.cidade &&
r.pasta.cidade.sigla &&
String(r.pasta.cidade.sigla).trim()
)
pastaSigla = String(r.pasta.cidade.sigla).trim();
}
} catch (e) {
pastaSigla = null;
}
// if closest has no pastaSigla, try find any candidate with non-empty sigla
if (!pastaSigla) {
for (let j = 0; j < candidates.length; j++) {
const rr = candidates[j].raw || {};
try {
if (rr.pasta) {
if (typeof rr.pasta === "string" && rr.pasta.trim()) {
pastaSigla = rr.pasta.trim();
break;
}
if (rr.pasta.sigla && String(rr.pasta.sigla).trim()) {
pastaSigla = String(rr.pasta.sigla).trim();
break;
}
if (
rr.pasta.cidade &&
rr.pasta.cidade.sigla &&
String(rr.pasta.cidade.sigla).trim()
) {
pastaSigla = String(rr.pasta.cidade.sigla).trim();
break;
}
}
} catch (e) {
// continue
}
}
}
if (!pastaSigla)
console.warn(
`[WARN] Nenhuma pasta.sigla encontrada para coordenadas ${lat},${lon} (closest dist ${best.num})`
);
pastaSigla = normalizePartnerSigla(pastaSigla);
return { dist: best.num, pastaSigla };
}
// sem distancias válidas
return null;
} catch (err) {
attempt += 1;
// se for 429, tente respeitar Retry-After quando disponível
if (err.response && err.response.status === 429) {
const ra =
err.response.headers &&
(err.response.headers["retry-after"] ||
err.response.headers["Retry-After"]);
let waitMs = BASE_BACKOFF_MS * Math.pow(2, attempt - 1);
if (ra) {
const raSec = parseInt(ra, 10);
if (!isNaN(raSec)) waitMs = raSec * 1000;
}
console.warn(
`[WARN] 429 recebido para ${lat},${lon} - aguardando ${waitMs}ms e tentando novamente (attempt ${attempt}/${MAX_RETRIES})`
);
await sleep(waitMs);
continue;
}
// para outros erros de rede/timeout, aguarda backoff exponencial e tenta de novo
const waitMs = BASE_BACKOFF_MS * Math.pow(2, attempt - 1);
console.warn(
`[WARN] Erro ao consultar API para ${lat},${lon}: ${err.message} - backoff ${waitMs}ms (attempt ${attempt}/${MAX_RETRIES})`
);
await sleep(waitMs);
}
}
// exauriu tentativas
console.error(`[ERROR] Exauriu retries para ${lat},${lon}`);
return null;
}
// upload CSV endpoint
const jobs = {}; // jobId -> { status, total, processed, download, error }
app.post("/upload", upload.single("csvfile"), (req, res) => {
if (!req.file)
return res.status(400).json({ error: "Nenhum arquivo enviado" });
const filePath = req.file.path;
const jobId = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
jobs[jobId] = {
status: "queued",
total: 0,
processed: 0,
download: null,
error: null,
};
(async () => {
jobs[jobId].status = "processing";
try {
const rows = [];
await new Promise((resolve, reject) => {
fs.createReadStream(filePath)
.pipe(csv({ separator: ";" }))
.on("data", (data) => {
// ignora linhas totalmente vazias (todos os campos nulos/undefined/strings vazias)
const values = Object.values(data);
const allEmpty =
values.length === 0 ||
values.every(
(v) => v === null || v === undefined || String(v).trim() === ""
);
if (!allEmpty) rows.push(data);
})
.on("end", resolve)
.on("error", reject);
});
jobs[jobId].total = rows.length;
const coordCache = new Map();
const outRows = [];
for (let i = 0; i < rows.length; i++) {
const row = rows[i];
// normalize keys to avoid duplicates caused by different headers
const norm = {};
Object.keys(row).forEach((k) => {
// normalize header: lowercase, remove diacritics and non-alphanumeric
const kn = k
.trim()
.toLowerCase()
.normalize("NFKD")
.replace(/[\u0300-\u036f]/g, "")
.replace(/[^a-z0-9]/g, "");
norm[kn] = row[k];
});
// Input columns (from normalized map)
const rawCep = norm["cep"]
? String(norm["cep"]).replace(/\D/g, "")
: "";
const rawNumero = norm["numero"] ? String(norm["numero"]).trim() : "";
// prefer lat/lon from normalized input if available
const rawLat = norm["latitude"] || norm["lat"] || null;
const rawLon =
norm["longitude"] || norm["lon"] || norm["long"] || null;
// Prefer existing lat/lon if provided from normalized fields
let lat = null,
lon = null;
if (rawLat && rawLon) {
lat = Number(String(rawLat).replace(",", "."));
lon = Number(String(rawLon).replace(",", "."));
}
let builtAddress = "";
const googleGeocodeAddress = await addressWithGoogle(lat, lon);
if (googleGeocodeAddress) {
builtAddress = googleGeocodeAddress;
} else {
console.warn(
`Google Reverse Geocoding não retornou resultado para coords ${lat},${lon} (row ${i + 1})`
);
}
console.log(`Row ${i + 1}: CEP='${rawCep}' Número='${rawNumero}' Lat='${lat}' Lon='${lon}' BuiltAddress='${builtAddress}'`);
// If no coords, try ViaCEP -> Google
if (!Number.isFinite(lat) || !Number.isFinite(lon)) {
if (rawCep) {
const cep8 = rawCep.padStart(8, "0");
const cepRestData = await fetch(
'https://api.cep.rest/', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ cep: cep8 })
}
).then(r => r.json());
if (cepRestData && !cepRestData.erro) {
const logradouro = cepRestData.data.logradouro || "";
const bairro = cepRestData.data.bairro || "";
const cidade = cepRestData.data.localidade || "";
const uf = cepRestData.data.uf || "";
if (logradouro) {
builtAddress =
`${logradouro}, ${rawNumero}, ${bairro}, ${cidade} - ${uf}`
.replace(/, ,/g, ",")
.replace(/^,\s*/, "");
} else {
// fallback: use neighborhood/city
builtAddress = `${bairro || ""} ${
cidade ? ", " + cidade : ""
} ${uf ? "- " + uf : ""}`.trim();
}
// build addressToUse (builtAddress already assembled above)
if (!process.env.GOOGLE_API_KEY) {
console.error(
"[ERROR] GOOGLE_API_KEY não definida. Não será possível geocodificar. Defina a chave no .env ou em process.env"
);
} else {
const addressToUse =
builtAddress || `${cidade} ${uf} ${cep8}`;
const geo = await geocodeWithGoogle(addressToUse);
if (geo) {
lat = geo.lat;
lon = geo.lon;
} else
console.warn(
`Google Geocoding não retornou resultado para '${addressToUse}' (CEP ${cep8}, row ${
i + 1
})`
);
}
} else {
console.warn(`ViaCEP erro for CEP ${rawCep} (row ${i + 1})`);
}
} else {
console.log(`Row ${i + 1}: missing/invalid CEP -> '${rawCep}'`);
}
}
// Prepare explicit output row to avoid extra columns
const out = {
CEP: rawCep || "",
Número: rawNumero || "",
Endereço: builtAddress || "",
// write lat/lon as strings with dot decimal and fixed precision to avoid locale swaps
Latitude: Number.isFinite(lat) ? Number(lat).toFixed(6) : "",
Longitude: Number.isFinite(lon) ? Number(lon).toFixed(6) : "",
"Não dedicado": "",
Dedicado: "",
Distancia: "",
"Parceiro/Sothis": "",
};
if (Number.isFinite(lat) && Number.isFinite(lon)) {
const coordKey = `${lat.toFixed(6)},${lon.toFixed(6)}`;
if (coordCache.has(coordKey)) {
const cached = coordCache.get(coordKey); // cached is either null or { dist, pastaSigla }
if (cached !== null) {
const d = cached.dist;
const di = Math.round(Number(d));
out["Não dedicado"] = di <= 500 ? "viável" : "Não viável";
out["Dedicado"] = di <= 1000 ? "viável" : "Não viável";
out["Distancia"] = `${di}M`;
out["Parceiro/Sothis"] =
normalizePartnerSigla(cached.pastaSigla) || "";
} else {
out["Não dedicado"] = "Não viável";
out["Dedicado"] = "Não viável";
out["Distancia"] = "5km +";
out["Parceiro/Sothis"] = "";
}
} else {
const minResult = await getMinDistance(lat, lon); // { dist, pastaSigla } or null
coordCache.set(coordKey, minResult);
if (minResult !== null) {
const di = Math.round(Number(minResult.dist));
out["Não dedicado"] = di <= 500 ? "viável" : "Não viável";
out["Dedicado"] = di <= 1000 ? "viável" : "Não viável";
out["Distancia"] = `${di}M`;
out["Parceiro/Sothis"] =
normalizePartnerSigla(minResult.pastaSigla) || "";
} else {
out["Não dedicado"] = "Não viável";
out["Dedicado"] = "Não viável";
out["Distancia"] = "5km +";
out["Parceiro/Sothis"] = "";
}
await sleep(REQUEST_DELAY_MS);
}
} else {
// no coords available -> keep defaults
}
outRows.push(out);
jobs[jobId].processed = i + 1;
}
// write output csv - use explicit outRows and fixed header order
const outPath = path.join(__dirname, "outputs");
if (!fs.existsSync(outPath)) fs.mkdirSync(outPath);
const originalName =
req.file && req.file.originalname
? req.file.originalname
: `upload_${Date.now()}.csv`;
const parsed = path.parse(originalName);
let outBase = `${parsed.name}_output`;
let outFile = path.join(outPath, `${outBase}.csv`);
if (fs.existsSync(outFile)) {
outFile = path.join(outPath, `${outBase}_${Date.now()}.csv`);
}
const headers = [
"CEP",
"Número",
"Endereço",
"Latitude",
"Longitude",
"Não dedicado",
"Dedicado",
"Distancia",
"Parceiro/Sothis",
];
await new Promise((resolve, reject) => {
const ws = fs.createWriteStream(outFile);
ws.write("\uFEFF");
fastCsv
.write(outRows, { headers: headers, delimiter: ";" })
.pipe(ws)
.on("finish", resolve)
.on("error", reject);
});
try {
fs.unlinkSync(filePath);
} catch (e) {}
jobs[jobId].status = "done";
jobs[jobId].download = `/download/${path.basename(outFile)}`;
} catch (err) {
console.error(err);
jobs[jobId].status = "error";
jobs[jobId].error = String(err.message || err);
}
})();
return res.json({ jobId });
});
// download model endpoint
app.get("/download-model", (req, res) => {
const modelPath = path.join(__dirname, "models", "modelo.viabilidade.csv");
if (!fs.existsSync(modelPath)) return res.status(404).send("Modelo não encontrado");
return res.download(modelPath, "modelo.viabilidade.csv");
});
// download result endpoint
app.get("/download/:name", (req, res) => {
const name = req.params.name;
const p = path.join(__dirname, "outputs", name);
if (!fs.existsSync(p))
return res.status(404).send("Arquivo não encontrado");
res.download(p);
});
// job status endpoint
app.get("/status/:jobId", (req, res) => {
const job = jobs[req.params.jobId];
if (!job) return res.status(404).json({ error: "job não encontrado" });
return res.json(job);
});
// manual query endpoint
// /consulta now accepts either latitude+longitude OR cep+numero. If cep is provided we resolve ViaCEP -> Google -> Geogrid
app.get("/consulta", async (req, res) => {
const {
latitude: rawLat,
longitude: rawLon,
cep: rawCep,
numero: rawNumero,
} = req.query;
// If cep provided, use ViaCEP -> Google geocoding -> Geogrid
if (rawCep) {
const cep = String(rawCep).replace(/\D/g, "");
const numero = rawNumero ? String(rawNumero).trim() : "";
try {
const viaCepData = await fetch(
'https://api.cep.rest/', { method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ cep })
}
).then(r => r.json());
if (!viaCepData || viaCepData.erro)
return res.status(404).json({ error: "CEP não encontrado" });
const logradouro = viaCepData.data.logradouro || "";
const bairro = viaCepData.data.bairro || "";
const cidade = viaCepData.data.localidade || "";
const uf = viaCepData.data.uf || "";
const endereco =
`${logradouro}, ${numero}, ${bairro}, ${cidade} - ${uf}`
.replace(/, ,/g, ",")
.replace(/^,\s*/, "");
if (!process.env.GOOGLE_API_KEY)
return res
.status(500)
.json({ error: "GOOGLE_API_KEY não definida no servidor" });
const geo = await geocodeWithGoogle(
endereco || `${cidade} ${uf} ${cep}`
);
if (!geo)
return res
.status(404)
.json({ error: "geocode não encontrado (Google)" });
const lat = Number(geo.lat);
const lon = Number(geo.lon);
const result = await getMinDistance(lat, lon);
if (result && result.dist !== undefined) {
return res.json({
endereco,
latitude: lat,
longitude: lon,
distancia: result.dist,
parceiro: result.pastaSigla || "",
});
}
return res.json({
endereco,
latitude: lat,
longitude: lon,
distancia: "5km +",
});
} catch (err) {
console.error(err);
return res.status(500).json({ error: "Erro na consulta" });
}
}
// Otherwise require latitude+longitude
if (!rawLat || !rawLon)
return res.status(400).json({
error: "latitude e longitude são obrigatórios (ou forneça cep)",
});
const latitude = Number(String(rawLat).replace(",", "."));
const longitude = Number(String(rawLon).replace(",", "."));
if (!Number.isFinite(latitude) || !Number.isFinite(longitude)) {
console.warn(
`Consulta manual com parâmetros inválidos: lat='${rawLat}' lon='${rawLon}'`
);
return res.status(400).json({ error: "latitude ou longitude inválidos" });
}
try {
console.log(`Consulta manual: lat=${latitude} lon=${longitude}`);
const result = await getMinDistance(latitude, longitude);
console.log(`Resultado consulta manual: ${JSON.stringify(result)}`);
if (result && result.dist !== undefined) {
return res.json({
distancia: result.dist,
parceiro: result.pastaSigla || "",
});
}
return res.json({ distancia: "5km +" });
} catch (err) {
console.error(err);
return res.status(500).json({ error: "Erro na consulta" });
console.log('[START-NOAUTH] DEV_SKIP_AUTH=true — authentication is bypassed');
}
});
// manual CEP+Numero query: resolves ViaCEP -> Nominatim -> Geogrid
app.get("/consulta-cep", async (req, res) => {
const { cep: rawCep, numero: rawNumero } = req.query;
if (!rawCep) return res.status(400).json({ error: "cep é obrigatório" });
const cep = String(rawCep).replace(/\D/g, "");
const numero = rawNumero ? String(rawNumero).trim() : "";
try {
const cepRestData = await fetch(
'https://api.cep.rest/', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ cep })
}
).then(r => r.json());
if (!cepRestData || cepRestData.erro)
return res.status(404).json({ error: "CEP não encontrado" });
const logradouro = cepRestData.data.logradouro || "";
const bairro = cepRestData.data.bairro || "";
const cidade = cepRestData.data.localidade || "";
const uf = cepRestData.data.uf || "";
const endereco = `${logradouro}, ${numero}, ${bairro}, ${cidade} - ${uf}`
.replace(/, ,/g, ",")
.replace(/^,\s*/, "");
if (!process.env.GOOGLE_API_KEY)
return res
.status(500)
.json({ error: "GOOGLE_API_KEY não definida no servidor" });
const geo = await geocodeWithGoogle(endereco || `${cidade} ${uf} ${cep}`);
if (!geo)
return res
.status(404)
.json({ error: "geocode não encontrado (Google)" });
const lat = Number(geo.lat);
const lon = Number(geo.lon);
const result = await getMinDistance(lat, lon);
if (result && result.dist !== undefined) {
return res.json({
endereco,
latitude: lat,
longitude: lon,
distancia: result.dist,
parceiro: result.pastaSigla || "",
});
}
return res.json({
endereco,
latitude: lat,
longitude: lon,
distancia: "5km +",
});
} catch (err) {
console.error(err);
return res.status(500).json({ error: "erro na consulta" });
}
});
////////////////////////////////////////////////////
// Servir arquivos estáticos (index.html)
// app.use("/public", express.static(path.join(__dirname, "public")));
// Usa as rotas de autenticação
app.use("/", authRoutes);
// servir arquivos estáticos da pasta public (rotas protegidas já são tratadas pelo middleware global)
app.use(express.static(path.join(__dirname, "public")));
// rota protegida que serve o index.html
app.get("/app", requireAuth, (req, res) => {
res.sendFile(path.join(__dirname, "public", "index.html"));
});
/////////////////////////////////////////////////////
return app;
}
module.exports = {
createApp,
};
module.exports = app;

681
app.old.js Normal file
View File

@ -0,0 +1,681 @@
// require("dotenv").config();
// const express = require("express");
// const multer = require("multer");
// const fs = require("fs");
// const path = require("path");
// const csv = require("csv-parser");
// const fastCsv = require("fast-csv");
// const axios = require("axios");
// const cors = require("cors");
// const session = require("express-session"); // adiciona session
// const { geocodeWithGoogle, addressWithGoogle } = require("./service/geocodeService");
// const { fetchJson } = require("./service/fetchService");
// const { BASE_BACKOFF_MS, MAX_RETRIES, REQUEST_DELAY_MS, sleep } = require("./service/retryService");
// const { API_URL, HEADERS } = require("./config/apiConfig");
// const { normalizePartnerSigla } = require("./service/normalizeService");
// const authRoutes = require("./routes/authRoutes.js");
// function createApp() {
// const upload = multer({ dest: "uploads/" });
// const app = express();
// // se estiver atrás de um reverse proxy (nginx/traefik) em produção, habilite:
// app.set("trust proxy", 1);
// app.use(cors());
// app.use(express.json());
// // session TEM que vir antes das rotas que usam req.session
// app.use(
// session({
// secret: process.env.SESSION_SECRET || "change-me",
// resave: false,
// saveUninitialized: false,
// cookie: {
// maxAge: 24 * 60 * 60 * 1000,
// secure: process.env.NODE_ENV === "production",
// sameSite: "lax",
// },
// })
// );
// // -- Desenvolvimento: pular autenticação se configurado
// // Para ativar: defina NODE_ENV=development e DEV_SKIP_AUTH=true no .env
// if (process.env.NODE_ENV === 'development' && process.env.DEV_SKIP_AUTH === 'true') {
// app.use((req, res, next) => {
// // garante que exista uma sessão autenticada para facilitar testes locais
// if (req.session && (!req.session.user || !req.session.user.authenticated)) {
// req.session.user = { authenticated: true, dev: true };
// }
// next();
// });
// }
// // middleware que protege rotas que exigem login
// function requireAuth(req, res, next) {
// if (req.session?.user?.authenticated) {
// return next();
// }
// if (req.xhr || req.headers.accept?.includes("application/json")) {
// return res.status(401).json({ error: "not_authenticated" });
// }
// return res.redirect("/login");
// }
// // proteger demais rotas (ex.: /upload, /consulta)
// app.use((req, res, next) => {
// // permissão liberada para rotas de auth já tratadas; proteger o resto
// if (req.path.startsWith("/auth") || req.path === "/login") return next();
// return requireAuth(req, res, next);
// });
// // redirect raiz
// app.get("/", (req, res) => {
// // em dev com bypass, sirva a página diretamente (sem redirect)
// if (process.env.NODE_ENV === 'development' && process.env.DEV_SKIP_AUTH === 'true') {
// return res.sendFile(path.join(__dirname, 'public', 'index.html'));
// }
// if (req.session?.user?.authenticated) {
// return res.redirect("/public/index.html");
// }
// return res.redirect("/login");
// });
// /////////////////////////////////////////////////////
// async function getMinDistance(lat, lon) {
// // tenta várias vezes com backoff exponencial; trata 429 usando Retry-After se disponível
// let attempt = 0;
// while (attempt < MAX_RETRIES) {
// try {
// // envia também o raio (em metros) - API espera esse parâmetro em várias rotas
// const resp = await axios.get(API_URL, {
// headers: HEADERS,
// params: {
// raio: 5000,
// latitude: lat,
// longitude: lon,
// "itens[]": ["caixa"],
// consultarPasta: "S",
// },
// timeout: 10000,
// });
// const data = resp.data;
// const registros = data && data.registros ? data.registros : [];
// // find registros that have a numeric distancia and keep original object for robust extraction
// const candidates = registros
// .map((r) => ({ raw: r, distanciaRaw: r && r.distancia }))
// .map((o) => ({
// raw: o.raw,
// num:
// o.distanciaRaw !== undefined &&
// o.distanciaRaw !== null &&
// o.distanciaRaw !== ""
// ? Number(o.distanciaRaw)
// : null,
// }))
// .filter((x) => x.num !== null && !Number.isNaN(x.num));
// if (candidates.length) {
// candidates.sort((a, b) => a.num - b.num);
// const best = candidates[0];
// const r = best.raw || {};
// // robust extraction of pasta sigla with fallbacks
// let pastaSigla = null;
// try {
// if (r.pasta) {
// if (typeof r.pasta === "string" && r.pasta.trim())
// pastaSigla = r.pasta.trim();
// else if (r.pasta.sigla && String(r.pasta.sigla).trim())
// pastaSigla = String(r.pasta.sigla).trim();
// else if (
// r.pasta.cidade &&
// r.pasta.cidade.sigla &&
// String(r.pasta.cidade.sigla).trim()
// )
// pastaSigla = String(r.pasta.cidade.sigla).trim();
// }
// } catch (e) {
// pastaSigla = null;
// }
// // if closest has no pastaSigla, try find any candidate with non-empty sigla
// if (!pastaSigla) {
// for (let j = 0; j < candidates.length; j++) {
// const rr = candidates[j].raw || {};
// try {
// if (rr.pasta) {
// if (typeof rr.pasta === "string" && rr.pasta.trim()) {
// pastaSigla = rr.pasta.trim();
// break;
// }
// if (rr.pasta.sigla && String(rr.pasta.sigla).trim()) {
// pastaSigla = String(rr.pasta.sigla).trim();
// break;
// }
// if (
// rr.pasta.cidade &&
// rr.pasta.cidade.sigla &&
// String(rr.pasta.cidade.sigla).trim()
// ) {
// pastaSigla = String(rr.pasta.cidade.sigla).trim();
// break;
// }
// }
// } catch (e) {
// // continue
// }
// }
// }
// if (!pastaSigla)
// console.warn(
// `[WARN] Nenhuma pasta.sigla encontrada para coordenadas ${lat},${lon} (closest dist ${best.num})`
// );
// pastaSigla = normalizePartnerSigla(pastaSigla);
// return { dist: best.num, pastaSigla };
// }
// // sem distancias válidas
// return null;
// } catch (err) {
// attempt += 1;
// // se for 429, tente respeitar Retry-After quando disponível
// if (err.response && err.response.status === 429) {
// const ra =
// err.response.headers &&
// (err.response.headers["retry-after"] ||
// err.response.headers["Retry-After"]);
// let waitMs = BASE_BACKOFF_MS * Math.pow(2, attempt - 1);
// if (ra) {
// const raSec = parseInt(ra, 10);
// if (!isNaN(raSec)) waitMs = raSec * 1000;
// }
// console.warn(
// `[WARN] 429 recebido para ${lat},${lon} - aguardando ${waitMs}ms e tentando novamente (attempt ${attempt}/${MAX_RETRIES})`
// );
// await sleep(waitMs);
// continue;
// }
// // para outros erros de rede/timeout, aguarda backoff exponencial e tenta de novo
// const waitMs = BASE_BACKOFF_MS * Math.pow(2, attempt - 1);
// console.warn(
// `[WARN] Erro ao consultar API para ${lat},${lon}: ${err.message} - backoff ${waitMs}ms (attempt ${attempt}/${MAX_RETRIES})`
// );
// await sleep(waitMs);
// }
// }
// // exauriu tentativas
// console.error(`[ERROR] Exauriu retries para ${lat},${lon}`);
// return null;
// }
// // upload CSV endpoint
// const jobs = {}; // jobId -> { status, total, processed, download, error }
// app.post("/upload", upload.single("csvfile"), (req, res) => {
// if (!req.file)
// return res.status(400).json({ error: "Nenhum arquivo enviado" });
// const filePath = req.file.path;
// const jobId = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
// jobs[jobId] = {
// status: "queued",
// total: 0,
// processed: 0,
// download: null,
// error: null,
// };
// (async () => {
// jobs[jobId].status = "processing";
// try {
// const rows = [];
// await new Promise((resolve, reject) => {
// fs.createReadStream(filePath)
// .pipe(csv({ separator: ";" }))
// .on("data", (data) => {
// // ignora linhas totalmente vazias (todos os campos nulos/undefined/strings vazias)
// const values = Object.values(data);
// const allEmpty =
// values.length === 0 ||
// values.every(
// (v) => v === null || v === undefined || String(v).trim() === ""
// );
// if (!allEmpty) rows.push(data);
// })
// .on("end", resolve)
// .on("error", reject);
// });
// jobs[jobId].total = rows.length;
// const coordCache = new Map();
// const outRows = [];
// for (let i = 0; i < rows.length; i++) {
// const row = rows[i];
// // normalize keys to avoid duplicates caused by different headers
// const norm = {};
// Object.keys(row).forEach((k) => {
// // normalize header: lowercase, remove diacritics and non-alphanumeric
// const kn = k
// .trim()
// .toLowerCase()
// .normalize("NFKD")
// .replace(/[\u0300-\u036f]/g, "")
// .replace(/[^a-z0-9]/g, "");
// norm[kn] = row[k];
// });
// // Input columns (from normalized map)
// const rawCep = norm["cep"]
// ? String(norm["cep"]).replace(/\D/g, "")
// : "";
// const rawNumero = norm["numero"] ? String(norm["numero"]).trim() : "";
// // prefer lat/lon from normalized input if available
// const rawLat = norm["latitude"] || norm["lat"] || null;
// const rawLon =
// norm["longitude"] || norm["lon"] || norm["long"] || null;
// // Prefer existing lat/lon if provided from normalized fields
// let lat = null,
// lon = null;
// if (rawLat && rawLon) {
// lat = Number(String(rawLat).replace(",", "."));
// lon = Number(String(rawLon).replace(",", "."));
// }
// let builtAddress = "";
// const googleGeocodeAddress = await addressWithGoogle(lat, lon);
// if (googleGeocodeAddress) {
// builtAddress = googleGeocodeAddress;
// } else {
// console.warn(
// `Google Reverse Geocoding não retornou resultado para coords ${lat},${lon} (row ${i + 1})`
// );
// }
// console.log(`Row ${i + 1}: CEP='${rawCep}' Número='${rawNumero}' Lat='${lat}' Lon='${lon}' BuiltAddress='${builtAddress}'`);
// // If no coords, try ViaCEP -> Google
// if (!Number.isFinite(lat) || !Number.isFinite(lon)) {
// if (rawCep) {
// const cep8 = rawCep.padStart(8, "0");
// const cepRestData = await fetch(
// 'https://api.cep.rest/', {
// method: 'POST',
// headers: { 'Content-Type': 'application/json' },
// body: JSON.stringify({ cep: cep8 })
// }
// ).then(r => r.json());
// if (cepRestData && !cepRestData.erro) {
// const logradouro = cepRestData.data.logradouro || "";
// const bairro = cepRestData.data.bairro || "";
// const cidade = cepRestData.data.localidade || "";
// const uf = cepRestData.data.uf || "";
// if (logradouro) {
// builtAddress =
// `${logradouro}, ${rawNumero}, ${bairro}, ${cidade} - ${uf}`
// .replace(/, ,/g, ",")
// .replace(/^,\s*/, "");
// } else {
// // fallback: use neighborhood/city
// builtAddress = `${bairro || ""} ${
// cidade ? ", " + cidade : ""
// } ${uf ? "- " + uf : ""}`.trim();
// }
// // build addressToUse (builtAddress already assembled above)
// if (!process.env.GOOGLE_API_KEY) {
// console.error(
// "[ERROR] GOOGLE_API_KEY não definida. Não será possível geocodificar. Defina a chave no .env ou em process.env"
// );
// } else {
// const addressToUse =
// builtAddress || `${cidade} ${uf} ${cep8}`;
// const geo = await geocodeWithGoogle(addressToUse);
// if (geo) {
// lat = geo.lat;
// lon = geo.lon;
// } else
// console.warn(
// `Google Geocoding não retornou resultado para '${addressToUse}' (CEP ${cep8}, row ${
// i + 1
// })`
// );
// }
// } else {
// console.warn(`ViaCEP erro for CEP ${rawCep} (row ${i + 1})`);
// }
// } else {
// console.log(`Row ${i + 1}: missing/invalid CEP -> '${rawCep}'`);
// }
// }
// // Prepare explicit output row to avoid extra columns
// const out = {
// CEP: rawCep || "",
// Número: rawNumero || "",
// Endereço: builtAddress || "",
// // write lat/lon as strings with dot decimal and fixed precision to avoid locale swaps
// Latitude: Number.isFinite(lat) ? Number(lat).toFixed(6) : "",
// Longitude: Number.isFinite(lon) ? Number(lon).toFixed(6) : "",
// "Não dedicado": "",
// Dedicado: "",
// Distancia: "",
// "Parceiro/Sothis": "",
// };
// if (Number.isFinite(lat) && Number.isFinite(lon)) {
// const coordKey = `${lat.toFixed(6)},${lon.toFixed(6)}`;
// if (coordCache.has(coordKey)) {
// const cached = coordCache.get(coordKey); // cached is either null or { dist, pastaSigla }
// if (cached !== null) {
// const d = cached.dist;
// const di = Math.round(Number(d));
// out["Não dedicado"] = di <= 500 ? "viável" : "Não viável";
// out["Dedicado"] = di <= 1000 ? "viável" : "Não viável";
// out["Distancia"] = `${di}M`;
// out["Parceiro/Sothis"] =
// normalizePartnerSigla(cached.pastaSigla) || "";
// } else {
// out["Não dedicado"] = "Não viável";
// out["Dedicado"] = "Não viável";
// out["Distancia"] = "5km +";
// out["Parceiro/Sothis"] = "";
// }
// } else {
// const minResult = await getMinDistance(lat, lon); // { dist, pastaSigla } or null
// coordCache.set(coordKey, minResult);
// if (minResult !== null) {
// const di = Math.round(Number(minResult.dist));
// out["Não dedicado"] = di <= 500 ? "viável" : "Não viável";
// out["Dedicado"] = di <= 1000 ? "viável" : "Não viável";
// out["Distancia"] = `${di}M`;
// out["Parceiro/Sothis"] =
// normalizePartnerSigla(minResult.pastaSigla) || "";
// } else {
// out["Não dedicado"] = "Não viável";
// out["Dedicado"] = "Não viável";
// out["Distancia"] = "5km +";
// out["Parceiro/Sothis"] = "";
// }
// await sleep(REQUEST_DELAY_MS);
// }
// } else {
// // no coords available -> keep defaults
// }
// outRows.push(out);
// jobs[jobId].processed = i + 1;
// }
// // write output csv - use explicit outRows and fixed header order
// const outPath = path.join(__dirname, "outputs");
// if (!fs.existsSync(outPath)) fs.mkdirSync(outPath);
// const originalName =
// req.file && req.file.originalname
// ? req.file.originalname
// : `upload_${Date.now()}.csv`;
// const parsed = path.parse(originalName);
// let outBase = `${parsed.name}_output`;
// let outFile = path.join(outPath, `${outBase}.csv`);
// if (fs.existsSync(outFile)) {
// outFile = path.join(outPath, `${outBase}_${Date.now()}.csv`);
// }
// const headers = [
// "CEP",
// "Número",
// "Endereço",
// "Latitude",
// "Longitude",
// "Não dedicado",
// "Dedicado",
// "Distancia",
// "Parceiro/Sothis",
// ];
// await new Promise((resolve, reject) => {
// const ws = fs.createWriteStream(outFile);
// ws.write("\uFEFF");
// fastCsv
// .write(outRows, { headers: headers, delimiter: ";" })
// .pipe(ws)
// .on("finish", resolve)
// .on("error", reject);
// });
// try {
// fs.unlinkSync(filePath);
// } catch (e) {}
// jobs[jobId].status = "done";
// jobs[jobId].download = `/download/${path.basename(outFile)}`;
// } catch (err) {
// console.error(err);
// jobs[jobId].status = "error";
// jobs[jobId].error = String(err.message || err);
// }
// })();
// return res.json({ jobId });
// });
// // download model endpoint
// app.get("/download-model/:name", (req, res) => {
// const name = req.params.name;
// const safeName = path.basename(name); // evita ../
// const filePath = path.join(__dirname, "models", safeName);
// if (!fs.existsSync(filePath)) return res.status(404).send("Arquivo não encontrado");
// return res.download(filePath, safeName);
// });
// // lista os arquivos disponíveis em /models
// app.get("/download-models/list", (req, res) => {
// const modelDir = path.join(__dirname, "models");
// if (!fs.existsSync(modelDir)) return res.status(404).json({ error: "Pasta de modelos não encontrada" });
// const files = fs.readdirSync(modelDir).filter((f) => fs.statSync(path.join(modelDir, f)).isFile());
// return res.json({ files });
// });
// // download result endpoint
// app.get("/download/:name", (req, res) => {
// const name = req.params.name;
// const p = path.join(__dirname, "outputs", name);
// if (!fs.existsSync(p))
// return res.status(404).send("Arquivo não encontrado");
// res.download(p);
// });
// // job status endpoint
// app.get("/status/:jobId", (req, res) => {
// const job = jobs[req.params.jobId];
// if (!job) return res.status(404).json({ error: "job não encontrado" });
// return res.json(job);
// });
// // manual query endpoint
// // /consulta now accepts either latitude+longitude OR cep+numero. If cep is provided we resolve ViaCEP -> Google -> Geogrid
// app.get("/consulta", async (req, res) => {
// const {
// latitude: rawLat,
// longitude: rawLon,
// cep: rawCep,
// numero: rawNumero,
// } = req.query;
// // If cep provided, use ViaCEP -> Google geocoding -> Geogrid
// if (rawCep) {
// const cep = String(rawCep).replace(/\D/g, "");
// const numero = rawNumero ? String(rawNumero).trim() : "";
// try {
// const viaCepData = await fetch(
// 'https://api.cep.rest/', { method: 'POST',
// headers: { 'Content-Type': 'application/json' },
// body: JSON.stringify({ cep })
// }
// ).then(r => r.json());
// if (!viaCepData || viaCepData.erro)
// return res.status(404).json({ error: "CEP não encontrado" });
// const logradouro = viaCepData.data.logradouro || "";
// const bairro = viaCepData.data.bairro || "";
// const cidade = viaCepData.data.localidade || "";
// const uf = viaCepData.data.uf || "";
// const endereco =
// `${logradouro}, ${numero}, ${bairro}, ${cidade} - ${uf}`
// .replace(/, ,/g, ",")
// .replace(/^,\s*/, "");
// if (!process.env.GOOGLE_API_KEY)
// return res
// .status(500)
// .json({ error: "GOOGLE_API_KEY não definida no servidor" });
// const geo = await geocodeWithGoogle(
// endereco || `${cidade} ${uf} ${cep}`
// );
// if (!geo)
// return res
// .status(404)
// .json({ error: "geocode não encontrado (Google)" });
// const lat = Number(geo.lat);
// const lon = Number(geo.lon);
// const result = await getMinDistance(lat, lon);
// if (result && result.dist !== undefined) {
// return res.json({
// endereco,
// latitude: lat,
// longitude: lon,
// distancia: result.dist,
// parceiro: result.pastaSigla || "",
// });
// }
// return res.json({
// endereco,
// latitude: lat,
// longitude: lon,
// distancia: "5km +",
// });
// } catch (err) {
// console.error(err);
// return res.status(500).json({ error: "Erro na consulta" });
// }
// }
// // Otherwise require latitude+longitude
// if (!rawLat || !rawLon)
// return res.status(400).json({
// error: "latitude e longitude são obrigatórios (ou forneça cep)",
// });
// const latitude = Number(String(rawLat).replace(",", "."));
// const longitude = Number(String(rawLon).replace(",", "."));
// if (!Number.isFinite(latitude) || !Number.isFinite(longitude)) {
// console.warn(
// `Consulta manual com parâmetros inválidos: lat='${rawLat}' lon='${rawLon}'`
// );
// return res.status(400).json({ error: "latitude ou longitude inválidos" });
// }
// try {
// console.log(`Consulta manual: lat=${latitude} lon=${longitude}`);
// const result = await getMinDistance(latitude, longitude);
// console.log(`Resultado consulta manual: ${JSON.stringify(result)}`);
// if (result && result.dist !== undefined) {
// return res.json({
// distancia: result.dist,
// parceiro: result.pastaSigla || "",
// });
// }
// return res.json({ distancia: "5km +" });
// } catch (err) {
// console.error(err);
// return res.status(500).json({ error: "Erro na consulta" });
// }
// });
// // manual CEP+Numero query: resolves ViaCEP -> Nominatim -> Geogrid
// app.get("/consulta-cep", async (req, res) => {
// const { cep: rawCep, numero: rawNumero } = req.query;
// if (!rawCep) return res.status(400).json({ error: "cep é obrigatório" });
// const cep = String(rawCep).replace(/\D/g, "");
// const numero = rawNumero ? String(rawNumero).trim() : "";
// try {
// const cepRestData = await fetch(
// 'https://api.cep.rest/', {
// method: 'POST',
// headers: { 'Content-Type': 'application/json' },
// body: JSON.stringify({ cep })
// }
// ).then(r => r.json());
// if (!cepRestData || cepRestData.erro)
// return res.status(404).json({ error: "CEP não encontrado" });
// const logradouro = cepRestData.data.logradouro || "";
// const bairro = cepRestData.data.bairro || "";
// const cidade = cepRestData.data.localidade || "";
// const uf = cepRestData.data.uf || "";
// const endereco = `${logradouro}, ${numero}, ${bairro}, ${cidade} - ${uf}`
// .replace(/, ,/g, ",")
// .replace(/^,\s*/, "");
// if (!process.env.GOOGLE_API_KEY)
// return res
// .status(500)
// .json({ error: "GOOGLE_API_KEY não definida no servidor" });
// const geo = await geocodeWithGoogle(endereco || `${cidade} ${uf} ${cep}`);
// if (!geo)
// return res
// .status(404)
// .json({ error: "geocode não encontrado (Google)" });
// const lat = Number(geo.lat);
// const lon = Number(geo.lon);
// const result = await getMinDistance(lat, lon);
// if (result && result.dist !== undefined) {
// return res.json({
// endereco,
// latitude: lat,
// longitude: lon,
// distancia: result.dist,
// parceiro: result.pastaSigla || "",
// });
// }
// return res.json({
// endereco,
// latitude: lat,
// longitude: lon,
// distancia: "5km +",
// });
// } catch (err) {
// console.error(err);
// return res.status(500).json({ error: "erro na consulta" });
// }
// });
// ////////////////////////////////////////////////////
// // Servir arquivos estáticos (index.html)
// // app.use("/public", express.static(path.join(__dirname, "public")));
// // Usa as rotas de autenticação
// app.use("/", authRoutes);
// // servir arquivos estáticos da pasta public (rotas protegidas já são tratadas pelo middleware global)
// app.use(express.static(path.join(__dirname, "public")));
// // rota protegida que serve o index.html
// app.get("/app", requireAuth, (req, res) => {
// res.sendFile(path.join(__dirname, "public", "index.html"));
// });
// /////////////////////////////////////////////////////
// return app;
// }
// module.exports = {
// createApp,
// };

View File

@ -19,4 +19,8 @@ const apiConfig = {
COOKIE,
HEADERS
};
module.exports = apiConfig;
const apiViabilidadeUrl = process.env.API_VIABILIDADE_URL;
const apiUrlBase = process.env.API_URL_BASE;
module.exports = { apiConfig, apiViabilidadeUrl, apiUrlBase };

View File

@ -0,0 +1,175 @@
const { consultarViabilidade, discoverDataType } = require('../service/viabilidadeService');
const { processCsvFile, countValidLines } = require('../service/csvService');
const { getJob, createJob } = require('../service/jobStore.service');
const fs = require('fs');
const path = require('path');
// Controlador para consultar viabilidade
async function consultarViabilidadeController(req, res) {
try {
const data = req.body;
data.source = 'viabiliza.sothis.com.br';
const result = await consultarViabilidade(data);
res.json(result);
} catch (error) {
console.error("Erro ao consultar viabilidade:", error && (error.message || error));
res.status(500).json({ error: "Erro ao consultar viabilidade" });
}
}
// Controlador para consultar viabilidade via geolocalização
async function consultarViaGeolocalizacaoController(req, res) {
try {
const data = req.body;
data.source = 'viabiliza.sothis.com.br';
const result = await consultarViabilidade(data);
res.json(result);
} catch (error) {
console.error("Erro ao consultar viabilidade por geolocalização:", error && (error.message || error));
res.status(500).json({ error: "Erro ao consultar viabilidade por geolocalização" });
}
}
async function uploadCsvFile(req, res) {
try {
// validação simples: verifica se multer populou req.file
if (!req.file) {
return res.status(400).json({ error: 'Nenhum arquivo enviado. Campo do form deve ser "csvfile".' });
}
const filePath = req.file.path;
const originalName = req.file.originalname || req.file.filename || 'input.csv';
// Verifica o tipo de dados do CSV
const dataType = await discoverDataType(filePath);
if (dataType === 'unknown') {
return res.status(400).json({ error: 'Formato de CSV inválido. Deve conter colunas CEP e Número ou Latitude e Longitude.' });
}
// Conta as linhas válidas primeiro
const total = await countValidLines(filePath);
if (total === 0) {
return res.status(400).json({ error: 'Nenhuma linha válida encontrada no CSV. Verifique se há colunas CEP e Número.' });
}
// Cria o job
const jobId = createJob(total);
// Inicia o processamento em background (não aguarda)
processCsvFile(jobId, filePath, originalName).catch(err => {
console.error('Erro no processamento em background:', err);
// Em caso de erro, marca o job como falhado
require('../service/jobStore.service').failJob(jobId, err.message);
});
// Retorna o jobId imediatamente para acompanhamento em tempo real
return res.json({ jobId });
} catch (error) {
console.error("Erro ao iniciar processamento do CSV:", error && (error.message || error));
return res.status(500).json({ error: 'Erro ao iniciar processamento do CSV' });
}
}
async function getJobController(req, res) {
try {
const jobId = req.params.jobId;
const job = getJob(jobId);
if (!job) {
return res.status(404).json({ error: 'Job não encontrado' });
}
res.json(job);
} catch (error) {
console.error("Erro ao obter job:", error && (error.message || error));
return res.status(500).json({ error: 'Erro ao obter job' });
}
}
// Controlador para download do CSV processado
// Verifica se o job está concluído e serve o arquivo para download
async function downloadCsvController(req, res) {
try {
const jobId = req.params.jobId;
const job = getJob(jobId);
// Verifica se o job existe, está concluído e tem um link de download
if (!job) {
return res.status(404).json({ error: 'Job não encontrado' });
}
if (job.status !== 'done') {
return res.status(400).json({ error: 'Processamento ainda não concluído' });
}
if (!job.download) {
return res.status(404).json({ error: 'Arquivo de download não disponível' });
}
// Extrai o nome do arquivo do campo download (ex: '/download/processed_123.csv' -> 'processed_123.csv')
const filename = path.basename(job.download);
const filePath = path.join(__dirname, '..', 'outputs', filename);
// Verifica se o arquivo existe no sistema de arquivos
if (!fs.existsSync(filePath)) {
return res.status(404).json({ error: 'Arquivo não encontrado no servidor' });
}
// Inicia o download do arquivo
res.download(filePath, filename, (err) => {
if (err) {
console.error("Erro ao fazer download do arquivo:", err);
// Se o download falhar, envia erro (mas headers já podem ter sido enviados)
if (!res.headersSent) {
res.status(500).json({ error: 'Erro ao fazer download do arquivo' });
}
}
});
} catch (error) {
console.error("Erro no controlador de download:", error && (error.message || error));
if (!res.headersSent) {
res.status(500).json({ error: 'Erro interno no servidor' });
}
}
}
// Controlador para download dos modelos de CSV
// Aceita parâmetro :type ('cep' ou 'geo') para escolher qual modelo baixar
async function downloadModelController(req, res) {
try {
const type = req.params.type;
let filename;
// Define o nome do arquivo baseado no tipo
if (type === 'cep') {
filename = 'modelo.viabilidade-cep.csv';
} else if (type === 'geo') {
filename = 'modelo.viabilidade-geolocalizacao.csv';
} else {
return res.status(400).json({ error: 'Tipo de modelo inválido. Use "cep" ou "geo".' });
}
const filePath = path.join(__dirname, '..', 'models', filename);
// Verifica se o arquivo existe
if (!fs.existsSync(filePath)) {
return res.status(404).json({ error: 'Arquivo de modelo não encontrado' });
}
// Inicia o download do arquivo
res.download(filePath, filename, (err) => {
if (err) {
console.error("Erro ao fazer download do modelo:", err);
if (!res.headersSent) {
res.status(500).json({ error: 'Erro ao fazer download do modelo' });
}
}
});
} catch (error) {
console.error("Erro no controlador de download de modelo:", error && (error.message || error));
if (!res.headersSent) {
res.status(500).json({ error: 'Erro interno no servidor' });
}
}
}
module.exports = { consultarViabilidadeController, uploadCsvFile, getJobController, downloadCsvController, downloadModelController, consultarViaGeolocalizacaoController };

View File

@ -0,0 +1,12 @@
module.exports = function requireAuth(req, res, next) {
if (req.session?.user?.authenticated) {
return next();
}
// chamadas AJAX / API
if (req.xhr || req.headers.accept?.includes('application/json')) {
return res.status(401).json({ error: 'not_authenticated' });
}
return res.redirect('/login');
};

File diff suppressed because it is too large Load Diff

16
node_modules/.bin/csv-parser generated vendored
View File

@ -1,16 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../csv-parser/bin/csv-parser" "$@"
else
exec node "$basedir/../csv-parser/bin/csv-parser" "$@"
fi

17
node_modules/.bin/csv-parser.cmd generated vendored
View File

@ -1,17 +0,0 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\csv-parser\bin\csv-parser" %*

28
node_modules/.bin/csv-parser.ps1 generated vendored
View File

@ -1,28 +0,0 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../csv-parser/bin/csv-parser" $args
} else {
& "$basedir/node$exe" "$basedir/../csv-parser/bin/csv-parser" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../csv-parser/bin/csv-parser" $args
} else {
& "node$exe" "$basedir/../csv-parser/bin/csv-parser" $args
}
$ret=$LASTEXITCODE
}
exit $ret

16
node_modules/.bin/mime generated vendored
View File

@ -1,16 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../mime/cli.js" "$@"
else
exec node "$basedir/../mime/cli.js" "$@"
fi

17
node_modules/.bin/mime.cmd generated vendored
View File

@ -1,17 +0,0 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\mime\cli.js" %*

28
node_modules/.bin/mime.ps1 generated vendored
View File

@ -1,28 +0,0 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../mime/cli.js" $args
} else {
& "$basedir/node$exe" "$basedir/../mime/cli.js" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../mime/cli.js" $args
} else {
& "node$exe" "$basedir/../mime/cli.js" $args
}
$ret=$LASTEXITCODE
}
exit $ret

16
node_modules/.bin/mkdirp generated vendored
View File

@ -1,16 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../mkdirp/bin/cmd.js" "$@"
else
exec node "$basedir/../mkdirp/bin/cmd.js" "$@"
fi

17
node_modules/.bin/mkdirp.cmd generated vendored
View File

@ -1,17 +0,0 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\mkdirp\bin\cmd.js" %*

28
node_modules/.bin/mkdirp.ps1 generated vendored
View File

@ -1,28 +0,0 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../mkdirp/bin/cmd.js" $args
} else {
& "$basedir/node$exe" "$basedir/../mkdirp/bin/cmd.js" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../mkdirp/bin/cmd.js" $args
} else {
& "node$exe" "$basedir/../mkdirp/bin/cmd.js" $args
}
$ret=$LASTEXITCODE
}
exit $ret

1213
node_modules/.package-lock.json generated vendored

File diff suppressed because it is too large Load Diff

View File

@ -1,73 +0,0 @@
# Change Log
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [4.3.5](https://github.com/C2FO/fast-csv/compare/v4.3.4...v4.3.5) (2020-11-03)
### Bug Fixes
* **formatting,#446:** Do not quote fields that do not contain a quote ([13e688c](https://github.com/C2FO/fast-csv/commit/13e688cb38dcb67c7182211968c794146be54692)), closes [#446](https://github.com/C2FO/fast-csv/issues/446)
## [4.3.4](https://github.com/C2FO/fast-csv/compare/v4.3.3...v4.3.4) (2020-11-03)
### Bug Fixes
* **formatter,#503:** Do not ignore rows when headers is false ([1560564](https://github.com/C2FO/fast-csv/commit/1560564819c8b1254ca4ad43487830a4296570f6)), closes [#503](https://github.com/C2FO/fast-csv/issues/503)
## [4.3.3](https://github.com/C2FO/fast-csv/compare/v4.3.2...v4.3.3) (2020-10-30)
**Note:** Version bump only for package @fast-csv/format
## [4.3.1](https://github.com/C2FO/fast-csv/compare/v4.3.0...v4.3.1) (2020-06-23)
**Note:** Version bump only for package @fast-csv/format
# [4.3.0](https://github.com/C2FO/fast-csv/compare/v4.2.0...v4.3.0) (2020-05-27)
**Note:** Version bump only for package @fast-csv/format
# [4.2.0](https://github.com/C2FO/fast-csv/compare/v4.1.6...v4.2.0) (2020-05-19)
### Features
* **parsing:** Less restrictive row parsing type [#356](https://github.com/C2FO/fast-csv/issues/356) ([87d74ec](https://github.com/C2FO/fast-csv/commit/87d74ecd2cb16f3700b1942ebbbec221afe38790))
## [4.1.5](https://github.com/C2FO/fast-csv/compare/v4.1.4...v4.1.5) (2020-05-15)
**Note:** Version bump only for package @fast-csv/format
## [4.1.4](https://github.com/C2FO/fast-csv/compare/v4.1.3...v4.1.4) (2020-05-15)
**Note:** Version bump only for package @fast-csv/format

View File

@ -1,21 +0,0 @@
The MIT License
Copyright (c) 2011-2019 C2FO
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -1,20 +0,0 @@
<p align="center">
<a href="https://c2fo.io/fast-csv" target="blank"><img src="https://c2fo.io/fast-csv/img/logo.svg" width="200" alt="fast-csv Logo" /></a>
</p>
[![npm version](https://img.shields.io/npm/v/@fast-csv/format.svg)](https://www.npmjs.org/package/@fast-csv/format)
[![Build Status](https://travis-ci.org/C2FO/fast-csv.svg?branch=master)](https://travis-ci.org/C2FO/fast-csv)
[![Coverage Status](https://coveralls.io/repos/github/C2FO/fast-csv/badge.svg?branch=master)](https://coveralls.io/github/C2FO/fast-csv?branch=master)
[![Known Vulnerabilities](https://snyk.io/test/github/C2FO/fast-csv/badge.svg?targetFile=packages/format/package.json)](https://snyk.io/test/github/C2FO/fast-csv?targetFile=packages/format/package.json)
# `@fast-csv/format`
`fast-csv` package to format CSVs.
## Installation
[Install Guide](https://c2fo.io/fast-csv/docs/introduction/install)
## Usage
To get started with `@fast-csv/format` [check out the docs](https://c2fo.io/fast-csv/docs/formatting/getting-started)

View File

@ -1,13 +0,0 @@
/// <reference types="node" />
import { Transform, TransformCallback } from 'stream';
import { FormatterOptions } from './FormatterOptions';
import { Row, RowTransformFunction } from './types';
export declare class CsvFormatterStream<I extends Row, O extends Row> extends Transform {
private formatterOptions;
private rowFormatter;
private hasWrittenBOM;
constructor(formatterOptions: FormatterOptions<I, O>);
transform(transformFunction: RowTransformFunction<I, O>): CsvFormatterStream<I, O>;
_transform(row: I, encoding: string, cb: TransformCallback): void;
_flush(cb: TransformCallback): void;
}

View File

@ -1,63 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CsvFormatterStream = void 0;
const stream_1 = require("stream");
const formatter_1 = require("./formatter");
class CsvFormatterStream extends stream_1.Transform {
constructor(formatterOptions) {
super({ writableObjectMode: formatterOptions.objectMode });
this.hasWrittenBOM = false;
this.formatterOptions = formatterOptions;
this.rowFormatter = new formatter_1.RowFormatter(formatterOptions);
// if writeBOM is false then set to true
// if writeBOM is true then set to false by default so it is written out
this.hasWrittenBOM = !formatterOptions.writeBOM;
}
transform(transformFunction) {
this.rowFormatter.rowTransform = transformFunction;
return this;
}
_transform(row, encoding, cb) {
let cbCalled = false;
try {
if (!this.hasWrittenBOM) {
this.push(this.formatterOptions.BOM);
this.hasWrittenBOM = true;
}
this.rowFormatter.format(row, (err, rows) => {
if (err) {
cbCalled = true;
return cb(err);
}
if (rows) {
rows.forEach((r) => {
this.push(Buffer.from(r, 'utf8'));
});
}
cbCalled = true;
return cb();
});
}
catch (e) {
if (cbCalled) {
throw e;
}
cb(e);
}
}
_flush(cb) {
this.rowFormatter.finish((err, rows) => {
if (err) {
return cb(err);
}
if (rows) {
rows.forEach((r) => {
this.push(Buffer.from(r, 'utf8'));
});
}
return cb();
});
}
}
exports.CsvFormatterStream = CsvFormatterStream;
//# sourceMappingURL=CsvFormatterStream.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"CsvFormatterStream.js","sourceRoot":"","sources":["../../src/CsvFormatterStream.ts"],"names":[],"mappings":";;;AAAA,mCAAsD;AAGtD,2CAA2C;AAE3C,MAAa,kBAAiD,SAAQ,kBAAS;IAO3E,YAAmB,gBAAwC;QACvD,KAAK,CAAC,EAAE,kBAAkB,EAAE,gBAAgB,CAAC,UAAU,EAAE,CAAC,CAAC;QAHvD,kBAAa,GAAG,KAAK,CAAC;QAI1B,IAAI,CAAC,gBAAgB,GAAG,gBAAgB,CAAC;QACzC,IAAI,CAAC,YAAY,GAAG,IAAI,wBAAY,CAAC,gBAAgB,CAAC,CAAC;QACvD,wCAAwC;QACxC,wEAAwE;QACxE,IAAI,CAAC,aAAa,GAAG,CAAC,gBAAgB,CAAC,QAAQ,CAAC;IACpD,CAAC;IAEM,SAAS,CAAC,iBAA6C;QAC1D,IAAI,CAAC,YAAY,CAAC,YAAY,GAAG,iBAAiB,CAAC;QACnD,OAAO,IAAI,CAAC;IAChB,CAAC;IAEM,UAAU,CAAC,GAAM,EAAE,QAAgB,EAAE,EAAqB;QAC7D,IAAI,QAAQ,GAAG,KAAK,CAAC;QACrB,IAAI;YACA,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE;gBACrB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC;gBACrC,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;aAC7B;YACD,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,IAAI,EAAQ,EAAE;gBAC9C,IAAI,GAAG,EAAE;oBACL,QAAQ,GAAG,IAAI,CAAC;oBAChB,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC;iBAClB;gBACD,IAAI,IAAI,EAAE;oBACN,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAQ,EAAE;wBACrB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;oBACtC,CAAC,CAAC,CAAC;iBACN;gBACD,QAAQ,GAAG,IAAI,CAAC;gBAChB,OAAO,EAAE,EAAE,CAAC;YAChB,CAAC,CAAC,CAAC;SACN;QAAC,OAAO,CAAC,EAAE;YACR,IAAI,QAAQ,EAAE;gBACV,MAAM,CAAC,CAAC;aACX;YACD,EAAE,CAAC,CAAC,CAAC,CAAC;SACT;IACL,CAAC;IAEM,MAAM,CAAC,EAAqB;QAC/B,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,IAAI,EAAQ,EAAE;YACzC,IAAI,GAAG,EAAE;gBACL,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC;aAClB;YACD,IAAI,IAAI,EAAE;gBACN,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAQ,EAAE;oBACrB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;gBACtC,CAAC,CAAC,CAAC;aACN;YACD,OAAO,EAAE,EAAE,CAAC;QAChB,CAAC,CAAC,CAAC;IACP,CAAC;CACJ;AA9DD,gDA8DC"}

View File

@ -1,39 +0,0 @@
import { Row, RowTransformFunction } from './types';
interface QuoteColumnMap {
[s: string]: boolean;
}
declare type QuoteColumns = boolean | boolean[] | QuoteColumnMap;
export interface FormatterOptionsArgs<I extends Row, O extends Row> {
objectMode?: boolean;
delimiter?: string;
rowDelimiter?: string;
quote?: string | boolean;
escape?: string;
quoteColumns?: QuoteColumns;
quoteHeaders?: QuoteColumns;
headers?: null | boolean | string[];
writeHeaders?: boolean;
includeEndRowDelimiter?: boolean;
writeBOM?: boolean;
transform?: RowTransformFunction<I, O>;
alwaysWriteHeaders?: boolean;
}
export declare class FormatterOptions<I extends Row, O extends Row> {
readonly objectMode: boolean;
readonly delimiter: string;
readonly rowDelimiter: string;
readonly quote: string;
readonly escape: string;
readonly quoteColumns: QuoteColumns;
readonly quoteHeaders: QuoteColumns;
readonly headers: null | string[];
readonly includeEndRowDelimiter: boolean;
readonly transform?: RowTransformFunction<I, O>;
readonly shouldWriteHeaders: boolean;
readonly writeBOM: boolean;
readonly escapedQuote: string;
readonly BOM: string;
readonly alwaysWriteHeaders: boolean;
constructor(opts?: FormatterOptionsArgs<I, O>);
}
export {};

View File

@ -1,38 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FormatterOptions = void 0;
class FormatterOptions {
constructor(opts = {}) {
var _a;
this.objectMode = true;
this.delimiter = ',';
this.rowDelimiter = '\n';
this.quote = '"';
this.escape = this.quote;
this.quoteColumns = false;
this.quoteHeaders = this.quoteColumns;
this.headers = null;
this.includeEndRowDelimiter = false;
this.writeBOM = false;
this.BOM = '\ufeff';
this.alwaysWriteHeaders = false;
Object.assign(this, opts || {});
if (typeof (opts === null || opts === void 0 ? void 0 : opts.quoteHeaders) === 'undefined') {
this.quoteHeaders = this.quoteColumns;
}
if ((opts === null || opts === void 0 ? void 0 : opts.quote) === true) {
this.quote = '"';
}
else if ((opts === null || opts === void 0 ? void 0 : opts.quote) === false) {
this.quote = '';
}
if (typeof (opts === null || opts === void 0 ? void 0 : opts.escape) !== 'string') {
this.escape = this.quote;
}
this.shouldWriteHeaders = !!this.headers && ((_a = opts.writeHeaders) !== null && _a !== void 0 ? _a : true);
this.headers = Array.isArray(this.headers) ? this.headers : null;
this.escapedQuote = `${this.escape}${this.quote}`;
}
}
exports.FormatterOptions = FormatterOptions;
//# sourceMappingURL=FormatterOptions.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"FormatterOptions.js","sourceRoot":"","sources":["../../src/FormatterOptions.ts"],"names":[],"mappings":";;;AAwBA,MAAa,gBAAgB;IA+BzB,YAAmB,OAAmC,EAAE;;QA9BxC,eAAU,GAAY,IAAI,CAAC;QAE3B,cAAS,GAAW,GAAG,CAAC;QAExB,iBAAY,GAAW,IAAI,CAAC;QAE5B,UAAK,GAAW,GAAG,CAAC;QAEpB,WAAM,GAAW,IAAI,CAAC,KAAK,CAAC;QAE5B,iBAAY,GAAiB,KAAK,CAAC;QAEnC,iBAAY,GAAiB,IAAI,CAAC,YAAY,CAAC;QAE/C,YAAO,GAAoB,IAAI,CAAC;QAEhC,2BAAsB,GAAY,KAAK,CAAC;QAMxC,aAAQ,GAAY,KAAK,CAAC;QAI1B,QAAG,GAAW,QAAQ,CAAC;QAEvB,uBAAkB,GAAY,KAAK,CAAC;QAGhD,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;QAEhC,IAAI,QAAO,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,YAAY,CAAA,KAAK,WAAW,EAAE;YAC3C,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC;SACzC;QACD,IAAI,CAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,KAAK,MAAK,IAAI,EAAE;YACtB,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC;SACpB;aAAM,IAAI,CAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,KAAK,MAAK,KAAK,EAAE;YAC9B,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;SACnB;QACD,IAAI,QAAO,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,MAAM,CAAA,KAAK,QAAQ,EAAE;YAClC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC;SAC5B;QACD,IAAI,CAAC,kBAAkB,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,IAAI,OAAC,IAAI,CAAC,YAAY,mCAAI,IAAI,CAAC,CAAC;QACxE,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;QACjE,IAAI,CAAC,YAAY,GAAG,GAAG,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;IACtD,CAAC;CACJ;AAjDD,4CAiDC"}

View File

@ -1,13 +0,0 @@
import { FormatterOptions } from '../FormatterOptions';
import { Row } from '../types';
export declare class FieldFormatter<I extends Row, O extends Row> {
private readonly formatterOptions;
private _headers;
private readonly REPLACE_REGEXP;
private readonly ESCAPE_REGEXP;
constructor(formatterOptions: FormatterOptions<I, O>);
set headers(headers: string[]);
private shouldQuote;
format(field: string, fieldIndex: number, isHeader: boolean): string;
private quoteField;
}

View File

@ -1,58 +0,0 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.FieldFormatter = void 0;
const lodash_isboolean_1 = __importDefault(require("lodash.isboolean"));
const lodash_isnil_1 = __importDefault(require("lodash.isnil"));
const lodash_escaperegexp_1 = __importDefault(require("lodash.escaperegexp"));
class FieldFormatter {
constructor(formatterOptions) {
this._headers = null;
this.formatterOptions = formatterOptions;
if (formatterOptions.headers !== null) {
this.headers = formatterOptions.headers;
}
this.REPLACE_REGEXP = new RegExp(formatterOptions.quote, 'g');
const escapePattern = `[${formatterOptions.delimiter}${lodash_escaperegexp_1.default(formatterOptions.rowDelimiter)}|\r|\n]`;
this.ESCAPE_REGEXP = new RegExp(escapePattern);
}
set headers(headers) {
this._headers = headers;
}
shouldQuote(fieldIndex, isHeader) {
const quoteConfig = isHeader ? this.formatterOptions.quoteHeaders : this.formatterOptions.quoteColumns;
if (lodash_isboolean_1.default(quoteConfig)) {
return quoteConfig;
}
if (Array.isArray(quoteConfig)) {
return quoteConfig[fieldIndex];
}
if (this._headers !== null) {
return quoteConfig[this._headers[fieldIndex]];
}
return false;
}
format(field, fieldIndex, isHeader) {
const preparedField = `${lodash_isnil_1.default(field) ? '' : field}`.replace(/\0/g, '');
const { formatterOptions } = this;
if (formatterOptions.quote !== '') {
const shouldEscape = preparedField.indexOf(formatterOptions.quote) !== -1;
if (shouldEscape) {
return this.quoteField(preparedField.replace(this.REPLACE_REGEXP, formatterOptions.escapedQuote));
}
}
const hasEscapeCharacters = preparedField.search(this.ESCAPE_REGEXP) !== -1;
if (hasEscapeCharacters || this.shouldQuote(fieldIndex, isHeader)) {
return this.quoteField(preparedField);
}
return preparedField;
}
quoteField(field) {
const { quote } = this.formatterOptions;
return `${quote}${field}${quote}`;
}
}
exports.FieldFormatter = FieldFormatter;
//# sourceMappingURL=FieldFormatter.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"FieldFormatter.js","sourceRoot":"","sources":["../../../src/formatter/FieldFormatter.ts"],"names":[],"mappings":";;;;;;AAAA,wEAAyC;AACzC,gEAAiC;AACjC,8EAA+C;AAI/C,MAAa,cAAc;IASvB,YAAmB,gBAAwC;QANnD,aAAQ,GAAoB,IAAI,CAAC;QAOrC,IAAI,CAAC,gBAAgB,GAAG,gBAAgB,CAAC;QACzC,IAAI,gBAAgB,CAAC,OAAO,KAAK,IAAI,EAAE;YACnC,IAAI,CAAC,OAAO,GAAG,gBAAgB,CAAC,OAAO,CAAC;SAC3C;QACD,IAAI,CAAC,cAAc,GAAG,IAAI,MAAM,CAAC,gBAAgB,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAC9D,MAAM,aAAa,GAAG,IAAI,gBAAgB,CAAC,SAAS,GAAG,6BAAY,CAAC,gBAAgB,CAAC,YAAY,CAAC,SAAS,CAAC;QAC5G,IAAI,CAAC,aAAa,GAAG,IAAI,MAAM,CAAC,aAAa,CAAC,CAAC;IACnD,CAAC;IAED,IAAW,OAAO,CAAC,OAAiB;QAChC,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC;IAC5B,CAAC;IAEO,WAAW,CAAC,UAAkB,EAAE,QAAiB;QACrD,MAAM,WAAW,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,YAAY,CAAC;QACvG,IAAI,0BAAS,CAAC,WAAW,CAAC,EAAE;YACxB,OAAO,WAAW,CAAC;SACtB;QACD,IAAI,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE;YAC5B,OAAO,WAAW,CAAC,UAAU,CAAC,CAAC;SAClC;QACD,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,EAAE;YACxB,OAAO,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC;SACjD;QACD,OAAO,KAAK,CAAC;IACjB,CAAC;IAEM,MAAM,CAAC,KAAa,EAAE,UAAkB,EAAE,QAAiB;QAC9D,MAAM,aAAa,GAAG,GAAG,sBAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACxE,MAAM,EAAE,gBAAgB,EAAE,GAAG,IAAI,CAAC;QAClC,IAAI,gBAAgB,CAAC,KAAK,KAAK,EAAE,EAAE;YAC/B,MAAM,YAAY,GAAG,aAAa,CAAC,OAAO,CAAC,gBAAgB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;YAC1E,IAAI,YAAY,EAAE;gBACd,OAAO,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,cAAc,EAAE,gBAAgB,CAAC,YAAY,CAAC,CAAC,CAAC;aACrG;SACJ;QACD,MAAM,mBAAmB,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;QAC5E,IAAI,mBAAmB,IAAI,IAAI,CAAC,WAAW,CAAC,UAAU,EAAE,QAAQ,CAAC,EAAE;YAC/D,OAAO,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;SACzC;QACD,OAAO,aAAa,CAAC;IACzB,CAAC;IAEO,UAAU,CAAC,KAAa;QAC5B,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,gBAAgB,CAAC;QACxC,OAAO,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,EAAE,CAAC;IACtC,CAAC;CACJ;AAzDD,wCAyDC"}

View File

@ -1,25 +0,0 @@
import { FormatterOptions } from '../FormatterOptions';
import { Row, RowArray, RowTransformFunction } from '../types';
declare type RowFormatterCallback = (error: Error | null, data?: RowArray) => void;
export declare class RowFormatter<I extends Row, O extends Row> {
private static isRowHashArray;
private static isRowArray;
private static gatherHeaders;
private static createTransform;
private readonly formatterOptions;
private readonly fieldFormatter;
private readonly shouldWriteHeaders;
private _rowTransform?;
private headers;
private hasWrittenHeaders;
private rowCount;
constructor(formatterOptions: FormatterOptions<I, O>);
set rowTransform(transformFunction: RowTransformFunction<I, O>);
format(row: I, cb: RowFormatterCallback): void;
finish(cb: RowFormatterCallback): void;
private checkHeaders;
private gatherColumns;
private callTransformer;
private formatColumns;
}
export {};

View File

@ -1,168 +0,0 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.RowFormatter = void 0;
const lodash_isfunction_1 = __importDefault(require("lodash.isfunction"));
const lodash_isequal_1 = __importDefault(require("lodash.isequal"));
const FieldFormatter_1 = require("./FieldFormatter");
const types_1 = require("../types");
class RowFormatter {
constructor(formatterOptions) {
this.rowCount = 0;
this.formatterOptions = formatterOptions;
this.fieldFormatter = new FieldFormatter_1.FieldFormatter(formatterOptions);
this.headers = formatterOptions.headers;
this.shouldWriteHeaders = formatterOptions.shouldWriteHeaders;
this.hasWrittenHeaders = false;
if (this.headers !== null) {
this.fieldFormatter.headers = this.headers;
}
if (formatterOptions.transform) {
this.rowTransform = formatterOptions.transform;
}
}
static isRowHashArray(row) {
if (Array.isArray(row)) {
return Array.isArray(row[0]) && row[0].length === 2;
}
return false;
}
static isRowArray(row) {
return Array.isArray(row) && !this.isRowHashArray(row);
}
// get headers from a row item
static gatherHeaders(row) {
if (RowFormatter.isRowHashArray(row)) {
// lets assume a multi-dimesional array with item 0 being the header
return row.map((it) => it[0]);
}
if (Array.isArray(row)) {
return row;
}
return Object.keys(row);
}
// eslint-disable-next-line @typescript-eslint/no-shadow
static createTransform(transformFunction) {
if (types_1.isSyncTransform(transformFunction)) {
return (row, cb) => {
let transformedRow = null;
try {
transformedRow = transformFunction(row);
}
catch (e) {
return cb(e);
}
return cb(null, transformedRow);
};
}
return (row, cb) => {
transformFunction(row, cb);
};
}
set rowTransform(transformFunction) {
if (!lodash_isfunction_1.default(transformFunction)) {
throw new TypeError('The transform should be a function');
}
this._rowTransform = RowFormatter.createTransform(transformFunction);
}
format(row, cb) {
this.callTransformer(row, (err, transformedRow) => {
if (err) {
return cb(err);
}
if (!row) {
return cb(null);
}
const rows = [];
if (transformedRow) {
const { shouldFormatColumns, headers } = this.checkHeaders(transformedRow);
if (this.shouldWriteHeaders && headers && !this.hasWrittenHeaders) {
rows.push(this.formatColumns(headers, true));
this.hasWrittenHeaders = true;
}
if (shouldFormatColumns) {
const columns = this.gatherColumns(transformedRow);
rows.push(this.formatColumns(columns, false));
}
}
return cb(null, rows);
});
}
finish(cb) {
const rows = [];
// check if we should write headers and we didnt get any rows
if (this.formatterOptions.alwaysWriteHeaders && this.rowCount === 0) {
if (!this.headers) {
return cb(new Error('`alwaysWriteHeaders` option is set to true but `headers` option not provided.'));
}
rows.push(this.formatColumns(this.headers, true));
}
if (this.formatterOptions.includeEndRowDelimiter) {
rows.push(this.formatterOptions.rowDelimiter);
}
return cb(null, rows);
}
// check if we need to write header return true if we should also write a row
// could be false if headers is true and the header row(first item) is passed in
checkHeaders(row) {
if (this.headers) {
// either the headers were provided by the user or we have already gathered them.
return { shouldFormatColumns: true, headers: this.headers };
}
const headers = RowFormatter.gatherHeaders(row);
this.headers = headers;
this.fieldFormatter.headers = headers;
if (!this.shouldWriteHeaders) {
// if we are not supposed to write the headers then
// always format the columns
return { shouldFormatColumns: true, headers: null };
}
// if the row is equal to headers dont format
return { shouldFormatColumns: !lodash_isequal_1.default(headers, row), headers };
}
// todo change this method to unknown[]
gatherColumns(row) {
if (this.headers === null) {
throw new Error('Headers is currently null');
}
if (!Array.isArray(row)) {
return this.headers.map((header) => row[header]);
}
if (RowFormatter.isRowHashArray(row)) {
return this.headers.map((header, i) => {
const col = row[i];
if (col) {
return col[1];
}
return '';
});
}
// if its a one dimensional array and headers were not provided
// then just return the row
if (RowFormatter.isRowArray(row) && !this.shouldWriteHeaders) {
return row;
}
return this.headers.map((header, i) => row[i]);
}
callTransformer(row, cb) {
if (!this._rowTransform) {
return cb(null, row);
}
return this._rowTransform(row, cb);
}
formatColumns(columns, isHeadersRow) {
const formattedCols = columns
.map((field, i) => this.fieldFormatter.format(field, i, isHeadersRow))
.join(this.formatterOptions.delimiter);
const { rowCount } = this;
this.rowCount += 1;
if (rowCount) {
return [this.formatterOptions.rowDelimiter, formattedCols].join('');
}
return formattedCols;
}
}
exports.RowFormatter = RowFormatter;
//# sourceMappingURL=RowFormatter.js.map

File diff suppressed because one or more lines are too long

View File

@ -1,2 +0,0 @@
export { RowFormatter } from './RowFormatter';
export { FieldFormatter } from './FieldFormatter';

View File

@ -1,8 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FieldFormatter = exports.RowFormatter = void 0;
var RowFormatter_1 = require("./RowFormatter");
Object.defineProperty(exports, "RowFormatter", { enumerable: true, get: function () { return RowFormatter_1.RowFormatter; } });
var FieldFormatter_1 = require("./FieldFormatter");
Object.defineProperty(exports, "FieldFormatter", { enumerable: true, get: function () { return FieldFormatter_1.FieldFormatter; } });
//# sourceMappingURL=index.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/formatter/index.ts"],"names":[],"mappings":";;;AAAA,+CAA8C;AAArC,4GAAA,YAAY,OAAA;AACrB,mDAAkD;AAAzC,gHAAA,cAAc,OAAA"}

View File

@ -1,14 +0,0 @@
/// <reference types="node" />
import * as fs from 'fs';
import { Row } from './types';
import { FormatterOptionsArgs } from './FormatterOptions';
import { CsvFormatterStream } from './CsvFormatterStream';
export * from './types';
export { CsvFormatterStream } from './CsvFormatterStream';
export { FormatterOptions, FormatterOptionsArgs } from './FormatterOptions';
export declare const format: <I extends Row, O extends Row>(options?: FormatterOptionsArgs<I, O> | undefined) => CsvFormatterStream<I, O>;
export declare const write: <I extends Row, O extends Row>(rows: I[], options?: FormatterOptionsArgs<I, O> | undefined) => CsvFormatterStream<I, O>;
export declare const writeToStream: <T extends NodeJS.WritableStream, I extends Row, O extends Row>(ws: T, rows: I[], options?: FormatterOptionsArgs<I, O> | undefined) => T;
export declare const writeToBuffer: <I extends Row, O extends Row>(rows: I[], opts?: FormatterOptionsArgs<I, O>) => Promise<Buffer>;
export declare const writeToString: <I extends Row, O extends Row>(rows: I[], options?: FormatterOptionsArgs<I, O> | undefined) => Promise<string>;
export declare const writeToPath: <I extends Row, O extends Row>(path: string, rows: I[], options?: FormatterOptionsArgs<I, O> | undefined) => fs.WriteStream;

View File

@ -1,68 +0,0 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.writeToPath = exports.writeToString = exports.writeToBuffer = exports.writeToStream = exports.write = exports.format = exports.FormatterOptions = exports.CsvFormatterStream = void 0;
const util_1 = require("util");
const stream_1 = require("stream");
const fs = __importStar(require("fs"));
const FormatterOptions_1 = require("./FormatterOptions");
const CsvFormatterStream_1 = require("./CsvFormatterStream");
__exportStar(require("./types"), exports);
var CsvFormatterStream_2 = require("./CsvFormatterStream");
Object.defineProperty(exports, "CsvFormatterStream", { enumerable: true, get: function () { return CsvFormatterStream_2.CsvFormatterStream; } });
var FormatterOptions_2 = require("./FormatterOptions");
Object.defineProperty(exports, "FormatterOptions", { enumerable: true, get: function () { return FormatterOptions_2.FormatterOptions; } });
exports.format = (options) => new CsvFormatterStream_1.CsvFormatterStream(new FormatterOptions_1.FormatterOptions(options));
exports.write = (rows, options) => {
const csvStream = exports.format(options);
const promiseWrite = util_1.promisify((row, cb) => {
csvStream.write(row, undefined, cb);
});
rows.reduce((prev, row) => prev.then(() => promiseWrite(row)), Promise.resolve())
.then(() => csvStream.end())
.catch((err) => {
csvStream.emit('error', err);
});
return csvStream;
};
exports.writeToStream = (ws, rows, options) => exports.write(rows, options).pipe(ws);
exports.writeToBuffer = (rows, opts = {}) => {
const buffers = [];
const ws = new stream_1.Writable({
write(data, enc, writeCb) {
buffers.push(data);
writeCb();
},
});
return new Promise((res, rej) => {
ws.on('error', rej).on('finish', () => res(Buffer.concat(buffers)));
exports.write(rows, opts).pipe(ws);
});
};
exports.writeToString = (rows, options) => exports.writeToBuffer(rows, options).then((buffer) => buffer.toString());
exports.writeToPath = (path, rows, options) => {
const stream = fs.createWriteStream(path, { encoding: 'utf8' });
return exports.write(rows, options).pipe(stream);
};
//# sourceMappingURL=index.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAAA,+BAAiC;AACjC,mCAAkC;AAClC,uCAAyB;AAEzB,yDAA4E;AAC5E,6DAA0D;AAE1D,0CAAwB;AACxB,2DAA0D;AAAjD,wHAAA,kBAAkB,OAAA;AAC3B,uDAA4E;AAAnE,oHAAA,gBAAgB,OAAA;AAEZ,QAAA,MAAM,GAAG,CAA+B,OAAoC,EAA4B,EAAE,CACnH,IAAI,uCAAkB,CAAC,IAAI,mCAAgB,CAAC,OAAO,CAAC,CAAC,CAAC;AAE7C,QAAA,KAAK,GAAG,CACjB,IAAS,EACT,OAAoC,EACZ,EAAE;IAC1B,MAAM,SAAS,GAAG,cAAM,CAAC,OAAO,CAAC,CAAC;IAClC,MAAM,YAAY,GAAG,gBAAS,CAAC,CAAC,GAAM,EAAE,EAAkC,EAAQ,EAAE;QAChF,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IACH,IAAI,CAAC,MAAM,CACP,CAAC,IAAmB,EAAE,GAAM,EAAiB,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAkB,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,EACjG,OAAO,CAAC,OAAO,EAAE,CACpB;SACI,IAAI,CAAC,GAAS,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC;SACjC,KAAK,CAAC,CAAC,GAAG,EAAQ,EAAE;QACjB,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;IACP,OAAO,SAAS,CAAC;AACrB,CAAC,CAAC;AAEW,QAAA,aAAa,GAAG,CACzB,EAAK,EACL,IAAS,EACT,OAAoC,EACnC,EAAE,CAAC,aAAK,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAEzB,QAAA,aAAa,GAAG,CACzB,IAAS,EACT,OAAmC,EAAE,EACtB,EAAE;IACjB,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,EAAE,GAAG,IAAI,iBAAQ,CAAC;QACpB,KAAK,CAAC,IAAI,EAAE,GAAG,EAAE,OAAO;YACpB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACnB,OAAO,EAAE,CAAC;QACd,CAAC;KACJ,CAAC,CAAC;IACH,OAAO,IAAI,OAAO,CAAC,CAAC,GAAG,EAAE,GAAG,EAAQ,EAAE;QAClC,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAS,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAC1E,aAAK,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;AACP,CAAC,CAAC;AAEW,QAAA,aAAa,GAAG,CACzB,IAAS,EACT,OAAoC,EACrB,EAAE,CAAC,qBAAa,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAU,EAAE,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;AAElF,QAAA,WAAW,GAAG,CACvB,IAAY,EACZ,IAAS,EACT,OAAoC,EACtB,EAAE;IAChB,MAAM,MAAM,GAAG,EAAE,CAAC,iBAAiB,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;IAChE,OAAO,aAAK,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC7C,CAAC,CAAC"}

View File

@ -1,9 +0,0 @@
export declare type RowMap<V = any> = Record<string, V>;
export declare type RowHashArray<V = any> = [string, V][];
export declare type RowArray = string[];
export declare type Row = RowArray | RowHashArray | RowMap;
export declare type RowTransformCallback<R extends Row> = (error?: Error | null, row?: R) => void;
export declare type SyncRowTransform<I extends Row, O extends Row> = (row: I) => O;
export declare type AsyncRowTransform<I extends Row, O extends Row> = (row: I, cb: RowTransformCallback<O>) => void;
export declare type RowTransformFunction<I extends Row, O extends Row> = SyncRowTransform<I, O> | AsyncRowTransform<I, O>;
export declare const isSyncTransform: <I extends Row, O extends Row>(transform: RowTransformFunction<I, O>) => transform is SyncRowTransform<I, O>;

View File

@ -1,6 +0,0 @@
"use strict";
/* eslint-disable @typescript-eslint/no-explicit-any */
Object.defineProperty(exports, "__esModule", { value: true });
exports.isSyncTransform = void 0;
exports.isSyncTransform = (transform) => transform.length === 1;
//# sourceMappingURL=types.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":";AAAA,uDAAuD;;;AAY1C,QAAA,eAAe,GAAG,CAC3B,SAAqC,EACF,EAAE,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,CAAC"}

View File

@ -1,55 +0,0 @@
{
"name": "@fast-csv/format",
"version": "4.3.5",
"description": "fast-csv formatting module",
"keywords": [
"csv",
"format",
"write"
],
"author": "doug-martin <doug@dougamartin.com>",
"homepage": "http://c2fo.github.com/fast-csv/packages/format",
"license": "MIT",
"main": "build/src/index.js",
"types": "build/src/index.d.ts",
"directories": {
"lib": "src",
"test": "__tests__"
},
"files": [
"build/src/**"
],
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "git+https://github.com/C2FO/fast-csv.git",
"directory": "packages/format"
},
"scripts": {
"prepublishOnly": "npm run build",
"build": "npm run clean && npm run compile",
"clean": "rm -rf ./build && rm -rf tsconfig.tsbuildinfo",
"compile": "tsc"
},
"bugs": {
"url": "https://github.com/C2FO/fast-csv/issues"
},
"dependencies": {
"@types/node": "^14.0.1",
"lodash.escaperegexp": "^4.1.2",
"lodash.isboolean": "^3.0.3",
"lodash.isequal": "^4.5.0",
"lodash.isfunction": "^3.0.9",
"lodash.isnil": "^4.0.0"
},
"devDependencies": {
"@types/lodash.escaperegexp": "4.1.6",
"@types/lodash.isboolean": "3.0.6",
"@types/lodash.isequal": "4.5.5",
"@types/lodash.isfunction": "3.0.6",
"@types/lodash.isnil": "4.0.6"
},
"gitHead": "b908170cb49398ae12847d050af5c8e5b0dc812f"
}

View File

@ -1,87 +0,0 @@
# Change Log
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [4.3.6](https://github.com/C2FO/fast-csv/compare/v4.3.5...v4.3.6) (2020-12-04)
### Bug Fixes
* Simplify empty row check by removing complex regex ([4bbd39f](https://github.com/C2FO/fast-csv/commit/4bbd39f26a8cd7382151ab4f5fb102234b2f829e))
## [4.3.3](https://github.com/C2FO/fast-csv/compare/v4.3.2...v4.3.3) (2020-10-30)
**Note:** Version bump only for package @fast-csv/parse
## [4.3.2](https://github.com/C2FO/fast-csv/compare/v4.3.1...v4.3.2) (2020-09-02)
### Bug Fixes
* **parsing, #423:** Prevent callback from being called multiple times ([040febe](https://github.com/C2FO/fast-csv/commit/040febe17f5fe763a00f45b1d83c5acd47bbbe0b)), closes [#423](https://github.com/C2FO/fast-csv/issues/423)
## [4.3.1](https://github.com/C2FO/fast-csv/compare/v4.3.0...v4.3.1) (2020-06-23)
### Bug Fixes
* **parsing:** Pass errors through callbacks ([84ecdf6](https://github.com/C2FO/fast-csv/commit/84ecdf6ed18b15d68b4ed3e2bfec7eb41b438ad8))
# [4.3.0](https://github.com/C2FO/fast-csv/compare/v4.2.0...v4.3.0) (2020-05-27)
**Note:** Version bump only for package @fast-csv/parse
# [4.2.0](https://github.com/C2FO/fast-csv/compare/v4.1.6...v4.2.0) (2020-05-19)
### Features
* **parsing:** Less restrictive row parsing type [#356](https://github.com/C2FO/fast-csv/issues/356) ([87d74ec](https://github.com/C2FO/fast-csv/commit/87d74ecd2cb16f3700b1942ebbbec221afe38790))
## [4.1.6](https://github.com/C2FO/fast-csv/compare/v4.1.5...v4.1.6) (2020-05-15)
### Bug Fixes
* **parse:** Handle escaped escape properly [#340](https://github.com/C2FO/fast-csv/issues/340) ([78d9b16](https://github.com/C2FO/fast-csv/commit/78d9b160152ee399f31086cc6b5f66a7ca7f9e24))
## [4.1.5](https://github.com/C2FO/fast-csv/compare/v4.1.4...v4.1.5) (2020-05-15)
**Note:** Version bump only for package @fast-csv/parse
## [4.1.4](https://github.com/C2FO/fast-csv/compare/v4.1.3...v4.1.4) (2020-05-15)
**Note:** Version bump only for package @fast-csv/parse

21
node_modules/@fast-csv/parse/LICENSE generated vendored
View File

@ -1,21 +0,0 @@
The MIT License
Copyright (c) 2011-2019 C2FO
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -1,20 +0,0 @@
<p align="center">
<a href="https://c2fo.io/fast-csv" target="blank"><img src="https://c2fo.io/fast-csv/img/logo.svg" width="200" alt="fast-csv Logo" /></a>
</p>
[![npm version](https://img.shields.io/npm/v/@fast-csv/parse.svg)](https://www.npmjs.org/package/@fast-csv/parse)
[![Build Status](https://travis-ci.org/C2FO/fast-csv.svg?branch=master)](https://travis-ci.org/C2FO/fast-csv)
[![Coverage Status](https://coveralls.io/repos/github/C2FO/fast-csv/badge.svg?branch=master)](https://coveralls.io/github/C2FO/fast-csv?branch=master)
[![Known Vulnerabilities](https://snyk.io/test/github/C2FO/fast-csv/badge.svg?targetFile=packages/parse/package.json)](https://snyk.io/test/github/C2FO/fast-csv?targetFile=packages/parse/package.json)
# `@fast-csv/parse`
`fast-csv` package to parse CSVs.
## Installation
[Install Guide](https://c2fo.io/fast-csv/docs/introduction/install)
## Usage
To get started with `@fast-csv/parse` [check out the docs](https://c2fo.io/fast-csv/docs/parsing/getting-started)

View File

@ -1,33 +0,0 @@
/// <reference types="node" />
import { Transform, TransformCallback } from 'stream';
import { ParserOptions } from './ParserOptions';
import { Row, RowTransformFunction, RowValidate } from './types';
export declare class CsvParserStream<I extends Row, O extends Row> extends Transform {
private readonly parserOptions;
private readonly decoder;
private readonly parser;
private readonly headerTransformer;
private readonly rowTransformerValidator;
private lines;
private rowCount;
private parsedRowCount;
private parsedLineCount;
private endEmitted;
private headersEmitted;
constructor(parserOptions: ParserOptions);
private get hasHitRowLimit();
private get shouldEmitRows();
private get shouldSkipLine();
transform(transformFunction: RowTransformFunction<I, O>): CsvParserStream<I, O>;
validate(validateFunction: RowValidate<O>): CsvParserStream<I, O>;
emit(event: string | symbol, ...rest: any[]): boolean;
_transform(data: Buffer, encoding: string, done: TransformCallback): void;
_flush(done: TransformCallback): void;
private parse;
private processRows;
private transformRow;
private checkAndEmitHeaders;
private skipRow;
private pushRow;
private static wrapDoneCallback;
}

View File

@ -1,212 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CsvParserStream = void 0;
const string_decoder_1 = require("string_decoder");
const stream_1 = require("stream");
const transforms_1 = require("./transforms");
const parser_1 = require("./parser");
class CsvParserStream extends stream_1.Transform {
constructor(parserOptions) {
super({ objectMode: parserOptions.objectMode });
this.lines = '';
this.rowCount = 0;
this.parsedRowCount = 0;
this.parsedLineCount = 0;
this.endEmitted = false;
this.headersEmitted = false;
this.parserOptions = parserOptions;
this.parser = new parser_1.Parser(parserOptions);
this.headerTransformer = new transforms_1.HeaderTransformer(parserOptions);
this.decoder = new string_decoder_1.StringDecoder(parserOptions.encoding);
this.rowTransformerValidator = new transforms_1.RowTransformerValidator();
}
get hasHitRowLimit() {
return this.parserOptions.limitRows && this.rowCount >= this.parserOptions.maxRows;
}
get shouldEmitRows() {
return this.parsedRowCount > this.parserOptions.skipRows;
}
get shouldSkipLine() {
return this.parsedLineCount <= this.parserOptions.skipLines;
}
transform(transformFunction) {
this.rowTransformerValidator.rowTransform = transformFunction;
return this;
}
validate(validateFunction) {
this.rowTransformerValidator.rowValidator = validateFunction;
return this;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
emit(event, ...rest) {
if (event === 'end') {
if (!this.endEmitted) {
this.endEmitted = true;
super.emit('end', this.rowCount);
}
return false;
}
return super.emit(event, ...rest);
}
_transform(data, encoding, done) {
// if we have hit our maxRows parsing limit then skip parsing
if (this.hasHitRowLimit) {
return done();
}
const wrappedCallback = CsvParserStream.wrapDoneCallback(done);
try {
const { lines } = this;
const newLine = lines + this.decoder.write(data);
const rows = this.parse(newLine, true);
return this.processRows(rows, wrappedCallback);
}
catch (e) {
return wrappedCallback(e);
}
}
_flush(done) {
const wrappedCallback = CsvParserStream.wrapDoneCallback(done);
// if we have hit our maxRows parsing limit then skip parsing
if (this.hasHitRowLimit) {
return wrappedCallback();
}
try {
const newLine = this.lines + this.decoder.end();
const rows = this.parse(newLine, false);
return this.processRows(rows, wrappedCallback);
}
catch (e) {
return wrappedCallback(e);
}
}
parse(data, hasMoreData) {
if (!data) {
return [];
}
const { line, rows } = this.parser.parse(data, hasMoreData);
this.lines = line;
return rows;
}
processRows(rows, cb) {
const rowsLength = rows.length;
const iterate = (i) => {
const callNext = (err) => {
if (err) {
return cb(err);
}
if (i % 100 === 0) {
// incase the transform are sync insert a next tick to prevent stack overflow
setImmediate(() => iterate(i + 1));
return undefined;
}
return iterate(i + 1);
};
this.checkAndEmitHeaders();
// if we have emitted all rows or we have hit the maxRows limit option
// then end
if (i >= rowsLength || this.hasHitRowLimit) {
return cb();
}
this.parsedLineCount += 1;
if (this.shouldSkipLine) {
return callNext();
}
const row = rows[i];
this.rowCount += 1;
this.parsedRowCount += 1;
const nextRowCount = this.rowCount;
return this.transformRow(row, (err, transformResult) => {
if (err) {
this.rowCount -= 1;
return callNext(err);
}
if (!transformResult) {
return callNext(new Error('expected transform result'));
}
if (!transformResult.isValid) {
this.emit('data-invalid', transformResult.row, nextRowCount, transformResult.reason);
}
else if (transformResult.row) {
return this.pushRow(transformResult.row, callNext);
}
return callNext();
});
};
iterate(0);
}
transformRow(parsedRow, cb) {
try {
this.headerTransformer.transform(parsedRow, (err, withHeaders) => {
if (err) {
return cb(err);
}
if (!withHeaders) {
return cb(new Error('Expected result from header transform'));
}
if (!withHeaders.isValid) {
if (this.shouldEmitRows) {
return cb(null, { isValid: false, row: parsedRow });
}
// skipped because of skipRows option remove from total row count
return this.skipRow(cb);
}
if (withHeaders.row) {
if (this.shouldEmitRows) {
return this.rowTransformerValidator.transformAndValidate(withHeaders.row, cb);
}
// skipped because of skipRows option remove from total row count
return this.skipRow(cb);
}
// this is a header row dont include in the rowCount or parsedRowCount
this.rowCount -= 1;
this.parsedRowCount -= 1;
return cb(null, { row: null, isValid: true });
});
}
catch (e) {
cb(e);
}
}
checkAndEmitHeaders() {
if (!this.headersEmitted && this.headerTransformer.headers) {
this.headersEmitted = true;
this.emit('headers', this.headerTransformer.headers);
}
}
skipRow(cb) {
// skipped because of skipRows option remove from total row count
this.rowCount -= 1;
return cb(null, { row: null, isValid: true });
}
pushRow(row, cb) {
try {
if (!this.parserOptions.objectMode) {
this.push(JSON.stringify(row));
}
else {
this.push(row);
}
cb();
}
catch (e) {
cb(e);
}
}
static wrapDoneCallback(done) {
let errorCalled = false;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return (err, ...args) => {
if (err) {
if (errorCalled) {
throw err;
}
errorCalled = true;
done(err);
return;
}
done(...args);
};
}
}
exports.CsvParserStream = CsvParserStream;
//# sourceMappingURL=CsvParserStream.js.map

File diff suppressed because one or more lines are too long

View File

@ -1,47 +0,0 @@
/// <reference types="node" />
import { HeaderArray, HeaderTransformFunction } from './types';
export interface ParserOptionsArgs {
objectMode?: boolean;
delimiter?: string;
quote?: string | null;
escape?: string;
headers?: boolean | HeaderTransformFunction | HeaderArray;
renameHeaders?: boolean;
ignoreEmpty?: boolean;
comment?: string;
strictColumnHandling?: boolean;
discardUnmappedColumns?: boolean;
trim?: boolean;
ltrim?: boolean;
rtrim?: boolean;
encoding?: string;
maxRows?: number;
skipLines?: number;
skipRows?: number;
}
export declare class ParserOptions {
readonly escapedDelimiter: string;
readonly objectMode: boolean;
readonly delimiter: string;
readonly ignoreEmpty: boolean;
readonly quote: string | null;
readonly escape: string | null;
readonly escapeChar: string | null;
readonly comment: string | null;
readonly supportsComments: boolean;
readonly ltrim: boolean;
readonly rtrim: boolean;
readonly trim: boolean;
readonly headers: boolean | HeaderTransformFunction | HeaderArray | null;
readonly renameHeaders: boolean;
readonly strictColumnHandling: boolean;
readonly discardUnmappedColumns: boolean;
readonly carriageReturn: string;
readonly NEXT_TOKEN_REGEXP: RegExp;
readonly encoding: BufferEncoding;
readonly limitRows: boolean;
readonly maxRows: number;
readonly skipLines: number;
readonly skipRows: number;
constructor(opts?: ParserOptionsArgs);
}

View File

@ -1,47 +0,0 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ParserOptions = void 0;
const lodash_escaperegexp_1 = __importDefault(require("lodash.escaperegexp"));
const lodash_isnil_1 = __importDefault(require("lodash.isnil"));
class ParserOptions {
constructor(opts) {
var _a;
this.objectMode = true;
this.delimiter = ',';
this.ignoreEmpty = false;
this.quote = '"';
this.escape = null;
this.escapeChar = this.quote;
this.comment = null;
this.supportsComments = false;
this.ltrim = false;
this.rtrim = false;
this.trim = false;
this.headers = null;
this.renameHeaders = false;
this.strictColumnHandling = false;
this.discardUnmappedColumns = false;
this.carriageReturn = '\r';
this.encoding = 'utf8';
this.limitRows = false;
this.maxRows = 0;
this.skipLines = 0;
this.skipRows = 0;
Object.assign(this, opts || {});
if (this.delimiter.length > 1) {
throw new Error('delimiter option must be one character long');
}
this.escapedDelimiter = lodash_escaperegexp_1.default(this.delimiter);
this.escapeChar = (_a = this.escape) !== null && _a !== void 0 ? _a : this.quote;
this.supportsComments = !lodash_isnil_1.default(this.comment);
this.NEXT_TOKEN_REGEXP = new RegExp(`([^\\s]|\\r\\n|\\n|\\r|${this.escapedDelimiter})`);
if (this.maxRows > 0) {
this.limitRows = true;
}
}
}
exports.ParserOptions = ParserOptions;
//# sourceMappingURL=ParserOptions.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"ParserOptions.js","sourceRoot":"","sources":["../../src/ParserOptions.ts"],"names":[],"mappings":";;;;;;AAAA,8EAA+C;AAC/C,gEAAiC;AAuBjC,MAAa,aAAa;IA+CtB,YAAmB,IAAwB;;QA5C3B,eAAU,GAAY,IAAI,CAAC;QAE3B,cAAS,GAAW,GAAG,CAAC;QAExB,gBAAW,GAAY,KAAK,CAAC;QAE7B,UAAK,GAAkB,GAAG,CAAC;QAE3B,WAAM,GAAkB,IAAI,CAAC;QAE7B,eAAU,GAAkB,IAAI,CAAC,KAAK,CAAC;QAEvC,YAAO,GAAkB,IAAI,CAAC;QAE9B,qBAAgB,GAAY,KAAK,CAAC;QAElC,UAAK,GAAY,KAAK,CAAC;QAEvB,UAAK,GAAY,KAAK,CAAC;QAEvB,SAAI,GAAY,KAAK,CAAC;QAEtB,YAAO,GAA2D,IAAI,CAAC;QAEvE,kBAAa,GAAY,KAAK,CAAC;QAE/B,yBAAoB,GAAY,KAAK,CAAC;QAEtC,2BAAsB,GAAY,KAAK,CAAC;QAExC,mBAAc,GAAW,IAAI,CAAC;QAI9B,aAAQ,GAAmB,MAAM,CAAC;QAElC,cAAS,GAAY,KAAK,CAAC;QAE3B,YAAO,GAAW,CAAC,CAAC;QAEpB,cAAS,GAAW,CAAC,CAAC;QAEtB,aAAQ,GAAW,CAAC,CAAC;QAGjC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;QAChC,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE;YAC3B,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;SAClE;QACD,IAAI,CAAC,gBAAgB,GAAG,6BAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACrD,IAAI,CAAC,UAAU,SAAG,IAAI,CAAC,MAAM,mCAAI,IAAI,CAAC,KAAK,CAAC;QAC5C,IAAI,CAAC,gBAAgB,GAAG,CAAC,sBAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC7C,IAAI,CAAC,iBAAiB,GAAG,IAAI,MAAM,CAAC,0BAA0B,IAAI,CAAC,gBAAgB,GAAG,CAAC,CAAC;QAExF,IAAI,IAAI,CAAC,OAAO,GAAG,CAAC,EAAE;YAClB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;SACzB;IACL,CAAC;CACJ;AA7DD,sCA6DC"}

View File

@ -1,11 +0,0 @@
/// <reference types="node" />
import { ParserOptionsArgs } from './ParserOptions';
import { CsvParserStream } from './CsvParserStream';
import { Row } from './types';
export * from './types';
export { CsvParserStream } from './CsvParserStream';
export { ParserOptions, ParserOptionsArgs } from './ParserOptions';
export declare const parse: <I extends Row<any>, O extends Row<any>>(args?: ParserOptionsArgs | undefined) => CsvParserStream<I, O>;
export declare const parseStream: <I extends Row<any>, O extends Row<any>>(stream: NodeJS.ReadableStream, options?: ParserOptionsArgs | undefined) => CsvParserStream<I, O>;
export declare const parseFile: <I extends Row<any>, O extends Row<any>>(location: string, options?: ParserOptionsArgs) => CsvParserStream<I, O>;
export declare const parseString: <I extends Row<any>, O extends Row<any>>(string: string, options?: ParserOptionsArgs | undefined) => CsvParserStream<I, O>;

View File

@ -1,44 +0,0 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseString = exports.parseFile = exports.parseStream = exports.parse = exports.ParserOptions = exports.CsvParserStream = void 0;
const fs = __importStar(require("fs"));
const stream_1 = require("stream");
const ParserOptions_1 = require("./ParserOptions");
const CsvParserStream_1 = require("./CsvParserStream");
__exportStar(require("./types"), exports);
var CsvParserStream_2 = require("./CsvParserStream");
Object.defineProperty(exports, "CsvParserStream", { enumerable: true, get: function () { return CsvParserStream_2.CsvParserStream; } });
var ParserOptions_2 = require("./ParserOptions");
Object.defineProperty(exports, "ParserOptions", { enumerable: true, get: function () { return ParserOptions_2.ParserOptions; } });
exports.parse = (args) => new CsvParserStream_1.CsvParserStream(new ParserOptions_1.ParserOptions(args));
exports.parseStream = (stream, options) => stream.pipe(new CsvParserStream_1.CsvParserStream(new ParserOptions_1.ParserOptions(options)));
exports.parseFile = (location, options = {}) => fs.createReadStream(location).pipe(new CsvParserStream_1.CsvParserStream(new ParserOptions_1.ParserOptions(options)));
exports.parseString = (string, options) => {
const rs = new stream_1.Readable();
rs.push(string);
rs.push(null);
return rs.pipe(new CsvParserStream_1.CsvParserStream(new ParserOptions_1.ParserOptions(options)));
};
//# sourceMappingURL=index.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAAA,uCAAyB;AACzB,mCAAkC;AAClC,mDAAmE;AACnE,uDAAoD;AAGpD,0CAAwB;AACxB,qDAAoD;AAA3C,kHAAA,eAAe,OAAA;AACxB,iDAAmE;AAA1D,8GAAA,aAAa,OAAA;AAET,QAAA,KAAK,GAAG,CAA+B,IAAwB,EAAyB,EAAE,CACnG,IAAI,iCAAe,CAAC,IAAI,6BAAa,CAAC,IAAI,CAAC,CAAC,CAAC;AAEpC,QAAA,WAAW,GAAG,CACvB,MAA6B,EAC7B,OAA2B,EACN,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,iCAAe,CAAC,IAAI,6BAAa,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAE5E,QAAA,SAAS,GAAG,CACrB,QAAgB,EAChB,UAA6B,EAAE,EACV,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,iCAAe,CAAC,IAAI,6BAAa,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAEnG,QAAA,WAAW,GAAG,CACvB,MAAc,EACd,OAA2B,EACN,EAAE;IACvB,MAAM,EAAE,GAAG,IAAI,iBAAQ,EAAE,CAAC;IAC1B,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAChB,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACd,OAAO,EAAE,CAAC,IAAI,CAAC,IAAI,iCAAe,CAAC,IAAI,6BAAa,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACpE,CAAC,CAAC"}

View File

@ -1,15 +0,0 @@
import { ParserOptions } from '../ParserOptions';
export interface ParseResult {
line: string;
rows: string[][];
}
export declare class Parser {
private static removeBOM;
private readonly parserOptions;
private readonly rowParser;
constructor(parserOptions: ParserOptions);
parse(line: string, hasMoreData: boolean): ParseResult;
private parseWithoutComments;
private parseWithComments;
private parseRow;
}

View File

@ -1,76 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Parser = void 0;
const Scanner_1 = require("./Scanner");
const RowParser_1 = require("./RowParser");
const Token_1 = require("./Token");
class Parser {
constructor(parserOptions) {
this.parserOptions = parserOptions;
this.rowParser = new RowParser_1.RowParser(this.parserOptions);
}
static removeBOM(line) {
// Catches EFBBBF (UTF-8 BOM) because the buffer-to-string
// conversion translates it to FEFF (UTF-16 BOM)
if (line && line.charCodeAt(0) === 0xfeff) {
return line.slice(1);
}
return line;
}
parse(line, hasMoreData) {
const scanner = new Scanner_1.Scanner({
line: Parser.removeBOM(line),
parserOptions: this.parserOptions,
hasMoreData,
});
if (this.parserOptions.supportsComments) {
return this.parseWithComments(scanner);
}
return this.parseWithoutComments(scanner);
}
parseWithoutComments(scanner) {
const rows = [];
let shouldContinue = true;
while (shouldContinue) {
shouldContinue = this.parseRow(scanner, rows);
}
return { line: scanner.line, rows };
}
parseWithComments(scanner) {
const { parserOptions } = this;
const rows = [];
for (let nextToken = scanner.nextCharacterToken; nextToken !== null; nextToken = scanner.nextCharacterToken) {
if (Token_1.Token.isTokenComment(nextToken, parserOptions)) {
const cursor = scanner.advancePastLine();
if (cursor === null) {
return { line: scanner.lineFromCursor, rows };
}
if (!scanner.hasMoreCharacters) {
return { line: scanner.lineFromCursor, rows };
}
scanner.truncateToCursor();
}
else if (!this.parseRow(scanner, rows)) {
break;
}
}
return { line: scanner.line, rows };
}
parseRow(scanner, rows) {
const nextToken = scanner.nextNonSpaceToken;
if (!nextToken) {
return false;
}
const row = this.rowParser.parse(scanner);
if (row === null) {
return false;
}
if (this.parserOptions.ignoreEmpty && RowParser_1.RowParser.isEmptyRow(row)) {
return true;
}
rows.push(row);
return true;
}
}
exports.Parser = Parser;
//# sourceMappingURL=Parser.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"Parser.js","sourceRoot":"","sources":["../../../src/parser/Parser.ts"],"names":[],"mappings":"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"}

View File

@ -1,12 +0,0 @@
import { Scanner } from './Scanner';
import { ParserOptions } from '../ParserOptions';
import { RowArray } from '../types';
export declare class RowParser {
static isEmptyRow(row: RowArray): boolean;
private readonly parserOptions;
private readonly columnParser;
constructor(parserOptions: ParserOptions);
parse(scanner: Scanner): RowArray | null;
private getStartToken;
private shouldSkipColumnParse;
}

View File

@ -1,76 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RowParser = void 0;
const column_1 = require("./column");
const Token_1 = require("./Token");
const EMPTY_STRING = '';
class RowParser {
constructor(parserOptions) {
this.parserOptions = parserOptions;
this.columnParser = new column_1.ColumnParser(parserOptions);
}
static isEmptyRow(row) {
return row.join(EMPTY_STRING).replace(/\s+/g, EMPTY_STRING) === EMPTY_STRING;
}
parse(scanner) {
const { parserOptions } = this;
const { hasMoreData } = scanner;
const currentScanner = scanner;
const columns = [];
let currentToken = this.getStartToken(currentScanner, columns);
while (currentToken) {
if (Token_1.Token.isTokenRowDelimiter(currentToken)) {
currentScanner.advancePastToken(currentToken);
// if ends with CR and there is more data, keep unparsed due to possible
// coming LF in CRLF
if (!currentScanner.hasMoreCharacters &&
Token_1.Token.isTokenCarriageReturn(currentToken, parserOptions) &&
hasMoreData) {
return null;
}
currentScanner.truncateToCursor();
return columns;
}
if (!this.shouldSkipColumnParse(currentScanner, currentToken, columns)) {
const item = this.columnParser.parse(currentScanner);
if (item === null) {
return null;
}
columns.push(item);
}
currentToken = currentScanner.nextNonSpaceToken;
}
if (!hasMoreData) {
currentScanner.truncateToCursor();
return columns;
}
return null;
}
getStartToken(scanner, columns) {
const currentToken = scanner.nextNonSpaceToken;
if (currentToken !== null && Token_1.Token.isTokenDelimiter(currentToken, this.parserOptions)) {
columns.push('');
return scanner.nextNonSpaceToken;
}
return currentToken;
}
shouldSkipColumnParse(scanner, currentToken, columns) {
const { parserOptions } = this;
if (Token_1.Token.isTokenDelimiter(currentToken, parserOptions)) {
scanner.advancePastToken(currentToken);
// if the delimiter is at the end of a line
const nextToken = scanner.nextCharacterToken;
if (!scanner.hasMoreCharacters || (nextToken !== null && Token_1.Token.isTokenRowDelimiter(nextToken))) {
columns.push('');
return true;
}
if (nextToken !== null && Token_1.Token.isTokenDelimiter(nextToken, parserOptions)) {
columns.push('');
return true;
}
}
return false;
}
}
exports.RowParser = RowParser;
//# sourceMappingURL=RowParser.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"RowParser.js","sourceRoot":"","sources":["../../../src/parser/RowParser.ts"],"names":[],"mappings":"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"}

View File

@ -1,25 +0,0 @@
import { ParserOptions } from '../ParserOptions';
import { MaybeToken, Token } from './Token';
export interface ScannerArgs {
line: string;
parserOptions: ParserOptions;
hasMoreData: boolean;
cursor?: number;
}
export declare class Scanner {
line: string;
private readonly parserOptions;
lineLength: number;
readonly hasMoreData: boolean;
cursor: number;
constructor(args: ScannerArgs);
get hasMoreCharacters(): boolean;
get nextNonSpaceToken(): MaybeToken;
get nextCharacterToken(): MaybeToken;
get lineFromCursor(): string;
advancePastLine(): Scanner | null;
advanceTo(cursor: number): Scanner;
advanceToToken(token: Token): Scanner;
advancePastToken(token: Token): Scanner;
truncateToCursor(): Scanner;
}

View File

@ -1,82 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Scanner = void 0;
const Token_1 = require("./Token");
const ROW_DELIMITER = /((?:\r\n)|\n|\r)/;
class Scanner {
constructor(args) {
this.cursor = 0;
this.line = args.line;
this.lineLength = this.line.length;
this.parserOptions = args.parserOptions;
this.hasMoreData = args.hasMoreData;
this.cursor = args.cursor || 0;
}
get hasMoreCharacters() {
return this.lineLength > this.cursor;
}
get nextNonSpaceToken() {
const { lineFromCursor } = this;
const regex = this.parserOptions.NEXT_TOKEN_REGEXP;
if (lineFromCursor.search(regex) === -1) {
return null;
}
const match = regex.exec(lineFromCursor);
if (match == null) {
return null;
}
const token = match[1];
const startCursor = this.cursor + (match.index || 0);
return new Token_1.Token({
token,
startCursor,
endCursor: startCursor + token.length - 1,
});
}
get nextCharacterToken() {
const { cursor, lineLength } = this;
if (lineLength <= cursor) {
return null;
}
return new Token_1.Token({
token: this.line[cursor],
startCursor: cursor,
endCursor: cursor,
});
}
get lineFromCursor() {
return this.line.substr(this.cursor);
}
advancePastLine() {
const match = ROW_DELIMITER.exec(this.lineFromCursor);
if (!match) {
if (this.hasMoreData) {
return null;
}
this.cursor = this.lineLength;
return this;
}
this.cursor += (match.index || 0) + match[0].length;
return this;
}
advanceTo(cursor) {
this.cursor = cursor;
return this;
}
advanceToToken(token) {
this.cursor = token.startCursor;
return this;
}
advancePastToken(token) {
this.cursor = token.endCursor + 1;
return this;
}
truncateToCursor() {
this.line = this.lineFromCursor;
this.lineLength = this.line.length;
this.cursor = 0;
return this;
}
}
exports.Scanner = Scanner;
//# sourceMappingURL=Scanner.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"Scanner.js","sourceRoot":"","sources":["../../../src/parser/Scanner.ts"],"names":[],"mappings":"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"}

View File

@ -1,19 +0,0 @@
import { ParserOptions } from '../ParserOptions';
export declare type MaybeToken = Token | null;
export interface TokenArgs {
token: string;
startCursor: number;
endCursor: number;
}
export declare class Token {
static isTokenRowDelimiter(token: Token): boolean;
static isTokenCarriageReturn(token: Token, parserOptions: ParserOptions): boolean;
static isTokenComment(token: Token, parserOptions: ParserOptions): boolean;
static isTokenEscapeCharacter(token: Token, parserOptions: ParserOptions): boolean;
static isTokenQuote(token: Token, parserOptions: ParserOptions): boolean;
static isTokenDelimiter(token: Token, parserOptions: ParserOptions): boolean;
readonly token: string;
readonly startCursor: number;
readonly endCursor: number;
constructor(tokenArgs: TokenArgs);
}

View File

@ -1,31 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Token = void 0;
class Token {
constructor(tokenArgs) {
this.token = tokenArgs.token;
this.startCursor = tokenArgs.startCursor;
this.endCursor = tokenArgs.endCursor;
}
static isTokenRowDelimiter(token) {
const content = token.token;
return content === '\r' || content === '\n' || content === '\r\n';
}
static isTokenCarriageReturn(token, parserOptions) {
return token.token === parserOptions.carriageReturn;
}
static isTokenComment(token, parserOptions) {
return parserOptions.supportsComments && !!token && token.token === parserOptions.comment;
}
static isTokenEscapeCharacter(token, parserOptions) {
return token.token === parserOptions.escapeChar;
}
static isTokenQuote(token, parserOptions) {
return token.token === parserOptions.quote;
}
static isTokenDelimiter(token, parserOptions) {
return token.token === parserOptions.delimiter;
}
}
exports.Token = Token;
//# sourceMappingURL=Token.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"Token.js","sourceRoot":"","sources":["../../../src/parser/Token.ts"],"names":[],"mappings":";;;AAUA,MAAa,KAAK;IAgCd,YAAmB,SAAoB;QACnC,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC;QAC7B,IAAI,CAAC,WAAW,GAAG,SAAS,CAAC,WAAW,CAAC;QACzC,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC,SAAS,CAAC;IACzC,CAAC;IAnCM,MAAM,CAAC,mBAAmB,CAAC,KAAY;QAC1C,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC;QAC5B,OAAO,OAAO,KAAK,IAAI,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,KAAK,MAAM,CAAC;IACtE,CAAC;IAEM,MAAM,CAAC,qBAAqB,CAAC,KAAY,EAAE,aAA4B;QAC1E,OAAO,KAAK,CAAC,KAAK,KAAK,aAAa,CAAC,cAAc,CAAC;IACxD,CAAC;IAEM,MAAM,CAAC,cAAc,CAAC,KAAY,EAAE,aAA4B;QACnE,OAAO,aAAa,CAAC,gBAAgB,IAAI,CAAC,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,KAAK,aAAa,CAAC,OAAO,CAAC;IAC9F,CAAC;IAEM,MAAM,CAAC,sBAAsB,CAAC,KAAY,EAAE,aAA4B;QAC3E,OAAO,KAAK,CAAC,KAAK,KAAK,aAAa,CAAC,UAAU,CAAC;IACpD,CAAC;IAEM,MAAM,CAAC,YAAY,CAAC,KAAY,EAAE,aAA4B;QACjE,OAAO,KAAK,CAAC,KAAK,KAAK,aAAa,CAAC,KAAK,CAAC;IAC/C,CAAC;IAEM,MAAM,CAAC,gBAAgB,CAAC,KAAY,EAAE,aAA4B;QACrE,OAAO,KAAK,CAAC,KAAK,KAAK,aAAa,CAAC,SAAS,CAAC;IACnD,CAAC;CAaJ;AArCD,sBAqCC"}

View File

@ -1,5 +0,0 @@
import { ParserOptions } from '../../ParserOptions';
export declare class ColumnFormatter {
readonly format: (col: string) => string;
constructor(parserOptions: ParserOptions);
}

View File

@ -1,21 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ColumnFormatter = void 0;
class ColumnFormatter {
constructor(parserOptions) {
if (parserOptions.trim) {
this.format = (col) => col.trim();
}
else if (parserOptions.ltrim) {
this.format = (col) => col.trimLeft();
}
else if (parserOptions.rtrim) {
this.format = (col) => col.trimRight();
}
else {
this.format = (col) => col;
}
}
}
exports.ColumnFormatter = ColumnFormatter;
//# sourceMappingURL=ColumnFormatter.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"ColumnFormatter.js","sourceRoot":"","sources":["../../../../src/parser/column/ColumnFormatter.ts"],"names":[],"mappings":";;;AAEA,MAAa,eAAe;IAGxB,YAAmB,aAA4B;QAC3C,IAAI,aAAa,CAAC,IAAI,EAAE;YACpB,IAAI,CAAC,MAAM,GAAG,CAAC,GAAW,EAAU,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;SACrD;aAAM,IAAI,aAAa,CAAC,KAAK,EAAE;YAC5B,IAAI,CAAC,MAAM,GAAG,CAAC,GAAW,EAAU,EAAE,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;SACzD;aAAM,IAAI,aAAa,CAAC,KAAK,EAAE;YAC5B,IAAI,CAAC,MAAM,GAAG,CAAC,GAAW,EAAU,EAAE,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;SAC1D;aAAM;YACH,IAAI,CAAC,MAAM,GAAG,CAAC,GAAW,EAAU,EAAE,CAAC,GAAG,CAAC;SAC9C;IACL,CAAC;CACJ;AAdD,0CAcC"}

View File

@ -1,11 +0,0 @@
import { ParserOptions } from '../../ParserOptions';
import { NonQuotedColumnParser } from './NonQuotedColumnParser';
import { QuotedColumnParser } from './QuotedColumnParser';
import { Scanner } from '../Scanner';
export declare class ColumnParser {
private readonly parserOptions;
readonly nonQuotedColumnParser: NonQuotedColumnParser;
readonly quotedColumnParser: QuotedColumnParser;
constructor(parserOptions: ParserOptions);
parse(scanner: Scanner): string | null;
}

View File

@ -1,23 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ColumnParser = void 0;
const NonQuotedColumnParser_1 = require("./NonQuotedColumnParser");
const QuotedColumnParser_1 = require("./QuotedColumnParser");
const Token_1 = require("../Token");
class ColumnParser {
constructor(parserOptions) {
this.parserOptions = parserOptions;
this.quotedColumnParser = new QuotedColumnParser_1.QuotedColumnParser(parserOptions);
this.nonQuotedColumnParser = new NonQuotedColumnParser_1.NonQuotedColumnParser(parserOptions);
}
parse(scanner) {
const { nextNonSpaceToken } = scanner;
if (nextNonSpaceToken !== null && Token_1.Token.isTokenQuote(nextNonSpaceToken, this.parserOptions)) {
scanner.advanceToToken(nextNonSpaceToken);
return this.quotedColumnParser.parse(scanner);
}
return this.nonQuotedColumnParser.parse(scanner);
}
}
exports.ColumnParser = ColumnParser;
//# sourceMappingURL=ColumnParser.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"ColumnParser.js","sourceRoot":"","sources":["../../../../src/parser/column/ColumnParser.ts"],"names":[],"mappings":";;;AACA,mEAAgE;AAChE,6DAA0D;AAE1D,oCAAiC;AAEjC,MAAa,YAAY;IAOrB,YAAmB,aAA4B;QAC3C,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;QACnC,IAAI,CAAC,kBAAkB,GAAG,IAAI,uCAAkB,CAAC,aAAa,CAAC,CAAC;QAChE,IAAI,CAAC,qBAAqB,GAAG,IAAI,6CAAqB,CAAC,aAAa,CAAC,CAAC;IAC1E,CAAC;IAEM,KAAK,CAAC,OAAgB;QACzB,MAAM,EAAE,iBAAiB,EAAE,GAAG,OAAO,CAAC;QACtC,IAAI,iBAAiB,KAAK,IAAI,IAAI,aAAK,CAAC,YAAY,CAAC,iBAAiB,EAAE,IAAI,CAAC,aAAa,CAAC,EAAE;YACzF,OAAO,CAAC,cAAc,CAAC,iBAAiB,CAAC,CAAC;YAC1C,OAAO,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;SACjD;QACD,OAAO,IAAI,CAAC,qBAAqB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACrD,CAAC;CACJ;AArBD,oCAqBC"}

View File

@ -1,8 +0,0 @@
import { ParserOptions } from '../../ParserOptions';
import { Scanner } from '../Scanner';
export declare class NonQuotedColumnParser {
private readonly parserOptions;
private readonly columnFormatter;
constructor(parserOptions: ParserOptions);
parse(scanner: Scanner): string | null;
}

View File

@ -1,29 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.NonQuotedColumnParser = void 0;
const ColumnFormatter_1 = require("./ColumnFormatter");
const Token_1 = require("../Token");
class NonQuotedColumnParser {
constructor(parserOptions) {
this.parserOptions = parserOptions;
this.columnFormatter = new ColumnFormatter_1.ColumnFormatter(parserOptions);
}
parse(scanner) {
if (!scanner.hasMoreCharacters) {
return null;
}
const { parserOptions } = this;
const characters = [];
let nextToken = scanner.nextCharacterToken;
for (; nextToken; nextToken = scanner.nextCharacterToken) {
if (Token_1.Token.isTokenDelimiter(nextToken, parserOptions) || Token_1.Token.isTokenRowDelimiter(nextToken)) {
break;
}
characters.push(nextToken.token);
scanner.advancePastToken(nextToken);
}
return this.columnFormatter.format(characters.join(''));
}
}
exports.NonQuotedColumnParser = NonQuotedColumnParser;
//# sourceMappingURL=NonQuotedColumnParser.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"NonQuotedColumnParser.js","sourceRoot":"","sources":["../../../../src/parser/column/NonQuotedColumnParser.ts"],"names":[],"mappings":";;;AACA,uDAAoD;AAEpD,oCAAiC;AAEjC,MAAa,qBAAqB;IAK9B,YAAmB,aAA4B;QAC3C,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;QACnC,IAAI,CAAC,eAAe,GAAG,IAAI,iCAAe,CAAC,aAAa,CAAC,CAAC;IAC9D,CAAC;IAEM,KAAK,CAAC,OAAgB;QACzB,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE;YAC5B,OAAO,IAAI,CAAC;SACf;QACD,MAAM,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC;QAC/B,MAAM,UAAU,GAAG,EAAE,CAAC;QACtB,IAAI,SAAS,GAAG,OAAO,CAAC,kBAAkB,CAAC;QAC3C,OAAO,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,kBAAkB,EAAE;YACtD,IAAI,aAAK,CAAC,gBAAgB,CAAC,SAAS,EAAE,aAAa,CAAC,IAAI,aAAK,CAAC,mBAAmB,CAAC,SAAS,CAAC,EAAE;gBAC1F,MAAM;aACT;YACD,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;YACjC,OAAO,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC;SACvC;QACD,OAAO,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IAC5D,CAAC;CACJ;AA1BD,sDA0BC"}

View File

@ -1,10 +0,0 @@
import { ParserOptions } from '../../ParserOptions';
import { Scanner } from '../Scanner';
export declare class QuotedColumnParser {
private readonly parserOptions;
private readonly columnFormatter;
constructor(parserOptions: ParserOptions);
parse(scanner: Scanner): string | null;
private gatherDataBetweenQuotes;
private checkForMalformedColumn;
}

View File

@ -1,97 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.QuotedColumnParser = void 0;
const ColumnFormatter_1 = require("./ColumnFormatter");
const Token_1 = require("../Token");
class QuotedColumnParser {
constructor(parserOptions) {
this.parserOptions = parserOptions;
this.columnFormatter = new ColumnFormatter_1.ColumnFormatter(parserOptions);
}
parse(scanner) {
if (!scanner.hasMoreCharacters) {
return null;
}
const originalCursor = scanner.cursor;
const { foundClosingQuote, col } = this.gatherDataBetweenQuotes(scanner);
if (!foundClosingQuote) {
// reset the cursor to the original
scanner.advanceTo(originalCursor);
// if we didnt find a closing quote but we potentially have more data then skip the parsing
// and return the original scanner.
if (!scanner.hasMoreData) {
throw new Error(`Parse Error: missing closing: '${this.parserOptions.quote || ''}' in line: at '${scanner.lineFromCursor.replace(/[\r\n]/g, "\\n'")}'`);
}
return null;
}
this.checkForMalformedColumn(scanner);
return col;
}
gatherDataBetweenQuotes(scanner) {
const { parserOptions } = this;
let foundStartingQuote = false;
let foundClosingQuote = false;
const characters = [];
let nextToken = scanner.nextCharacterToken;
for (; !foundClosingQuote && nextToken !== null; nextToken = scanner.nextCharacterToken) {
const isQuote = Token_1.Token.isTokenQuote(nextToken, parserOptions);
// ignore first quote
if (!foundStartingQuote && isQuote) {
foundStartingQuote = true;
}
else if (foundStartingQuote) {
if (Token_1.Token.isTokenEscapeCharacter(nextToken, parserOptions)) {
// advance past the escape character so we can get the next one in line
scanner.advancePastToken(nextToken);
const tokenFollowingEscape = scanner.nextCharacterToken;
// if the character following the escape is a quote character then just add
// the quote and advance to that character
if (tokenFollowingEscape !== null &&
(Token_1.Token.isTokenQuote(tokenFollowingEscape, parserOptions) ||
Token_1.Token.isTokenEscapeCharacter(tokenFollowingEscape, parserOptions))) {
characters.push(tokenFollowingEscape.token);
nextToken = tokenFollowingEscape;
}
else if (isQuote) {
// if the escape is also a quote then we found our closing quote and finish early
foundClosingQuote = true;
}
else {
// other wise add the escape token to the characters since it wast escaping anything
characters.push(nextToken.token);
}
}
else if (isQuote) {
// we found our closing quote!
foundClosingQuote = true;
}
else {
// add the token to the characters
characters.push(nextToken.token);
}
}
scanner.advancePastToken(nextToken);
}
return { col: this.columnFormatter.format(characters.join('')), foundClosingQuote };
}
checkForMalformedColumn(scanner) {
const { parserOptions } = this;
const { nextNonSpaceToken } = scanner;
if (nextNonSpaceToken) {
const isNextTokenADelimiter = Token_1.Token.isTokenDelimiter(nextNonSpaceToken, parserOptions);
const isNextTokenARowDelimiter = Token_1.Token.isTokenRowDelimiter(nextNonSpaceToken);
if (!(isNextTokenADelimiter || isNextTokenARowDelimiter)) {
// if the final quote was NOT followed by a column (,) or row(\n) delimiter then its a bad column
// tldr: only part of the column was quoted
const linePreview = scanner.lineFromCursor.substr(0, 10).replace(/[\r\n]/g, "\\n'");
throw new Error(`Parse Error: expected: '${parserOptions.escapedDelimiter}' OR new line got: '${nextNonSpaceToken.token}'. at '${linePreview}`);
}
scanner.advanceToToken(nextNonSpaceToken);
}
else if (!scanner.hasMoreData) {
scanner.advancePastLine();
}
}
}
exports.QuotedColumnParser = QuotedColumnParser;
//# sourceMappingURL=QuotedColumnParser.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"QuotedColumnParser.js","sourceRoot":"","sources":["../../../../src/parser/column/QuotedColumnParser.ts"],"names":[],"mappings":"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"}

View File

@ -1,4 +0,0 @@
export { ColumnParser } from './ColumnParser';
export { NonQuotedColumnParser } from './NonQuotedColumnParser';
export { QuotedColumnParser } from './QuotedColumnParser';
export { ColumnFormatter } from './ColumnFormatter';

View File

@ -1,12 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ColumnFormatter = exports.QuotedColumnParser = exports.NonQuotedColumnParser = exports.ColumnParser = void 0;
var ColumnParser_1 = require("./ColumnParser");
Object.defineProperty(exports, "ColumnParser", { enumerable: true, get: function () { return ColumnParser_1.ColumnParser; } });
var NonQuotedColumnParser_1 = require("./NonQuotedColumnParser");
Object.defineProperty(exports, "NonQuotedColumnParser", { enumerable: true, get: function () { return NonQuotedColumnParser_1.NonQuotedColumnParser; } });
var QuotedColumnParser_1 = require("./QuotedColumnParser");
Object.defineProperty(exports, "QuotedColumnParser", { enumerable: true, get: function () { return QuotedColumnParser_1.QuotedColumnParser; } });
var ColumnFormatter_1 = require("./ColumnFormatter");
Object.defineProperty(exports, "ColumnFormatter", { enumerable: true, get: function () { return ColumnFormatter_1.ColumnFormatter; } });
//# sourceMappingURL=index.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/parser/column/index.ts"],"names":[],"mappings":";;;AAAA,+CAA8C;AAArC,4GAAA,YAAY,OAAA;AACrB,iEAAgE;AAAvD,8HAAA,qBAAqB,OAAA;AAC9B,2DAA0D;AAAjD,wHAAA,kBAAkB,OAAA;AAC3B,qDAAoD;AAA3C,kHAAA,eAAe,OAAA"}

View File

@ -1,5 +0,0 @@
export { Parser } from './Parser';
export { RowParser } from './RowParser';
export { Scanner } from './Scanner';
export { Token, MaybeToken } from './Token';
export { ColumnParser, NonQuotedColumnParser, QuotedColumnParser } from './column';

View File

@ -1,16 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.QuotedColumnParser = exports.NonQuotedColumnParser = exports.ColumnParser = exports.Token = exports.Scanner = exports.RowParser = exports.Parser = void 0;
var Parser_1 = require("./Parser");
Object.defineProperty(exports, "Parser", { enumerable: true, get: function () { return Parser_1.Parser; } });
var RowParser_1 = require("./RowParser");
Object.defineProperty(exports, "RowParser", { enumerable: true, get: function () { return RowParser_1.RowParser; } });
var Scanner_1 = require("./Scanner");
Object.defineProperty(exports, "Scanner", { enumerable: true, get: function () { return Scanner_1.Scanner; } });
var Token_1 = require("./Token");
Object.defineProperty(exports, "Token", { enumerable: true, get: function () { return Token_1.Token; } });
var column_1 = require("./column");
Object.defineProperty(exports, "ColumnParser", { enumerable: true, get: function () { return column_1.ColumnParser; } });
Object.defineProperty(exports, "NonQuotedColumnParser", { enumerable: true, get: function () { return column_1.NonQuotedColumnParser; } });
Object.defineProperty(exports, "QuotedColumnParser", { enumerable: true, get: function () { return column_1.QuotedColumnParser; } });
//# sourceMappingURL=index.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/parser/index.ts"],"names":[],"mappings":";;;AAAA,mCAAkC;AAAzB,gGAAA,MAAM,OAAA;AACf,yCAAwC;AAA/B,sGAAA,SAAS,OAAA;AAClB,qCAAoC;AAA3B,kGAAA,OAAO,OAAA;AAChB,iCAA4C;AAAnC,8FAAA,KAAK,OAAA;AACd,mCAAmF;AAA1E,sGAAA,YAAY,OAAA;AAAE,+GAAA,qBAAqB,OAAA;AAAE,4GAAA,kBAAkB,OAAA"}

View File

@ -1,17 +0,0 @@
import { ParserOptions } from '../ParserOptions';
import { HeaderArray, Row, RowArray, RowValidatorCallback } from '../types';
export declare class HeaderTransformer<O extends Row> {
private readonly parserOptions;
headers: HeaderArray | null;
private receivedHeaders;
private readonly shouldUseFirstRow;
private processedFirstRow;
private headersLength;
private readonly headersTransform?;
constructor(parserOptions: ParserOptions);
transform(row: RowArray, cb: RowValidatorCallback<O>): void;
private shouldMapRow;
private processRow;
private mapHeaders;
private setHeaders;
}

View File

@ -1,115 +0,0 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.HeaderTransformer = void 0;
const lodash_isundefined_1 = __importDefault(require("lodash.isundefined"));
const lodash_isfunction_1 = __importDefault(require("lodash.isfunction"));
const lodash_uniq_1 = __importDefault(require("lodash.uniq"));
const lodash_groupby_1 = __importDefault(require("lodash.groupby"));
class HeaderTransformer {
constructor(parserOptions) {
this.headers = null;
this.receivedHeaders = false;
this.shouldUseFirstRow = false;
this.processedFirstRow = false;
this.headersLength = 0;
this.parserOptions = parserOptions;
if (parserOptions.headers === true) {
this.shouldUseFirstRow = true;
}
else if (Array.isArray(parserOptions.headers)) {
this.setHeaders(parserOptions.headers);
}
else if (lodash_isfunction_1.default(parserOptions.headers)) {
this.headersTransform = parserOptions.headers;
}
}
transform(row, cb) {
if (!this.shouldMapRow(row)) {
return cb(null, { row: null, isValid: true });
}
return cb(null, this.processRow(row));
}
shouldMapRow(row) {
const { parserOptions } = this;
if (!this.headersTransform && parserOptions.renameHeaders && !this.processedFirstRow) {
if (!this.receivedHeaders) {
throw new Error('Error renaming headers: new headers must be provided in an array');
}
this.processedFirstRow = true;
return false;
}
if (!this.receivedHeaders && Array.isArray(row)) {
if (this.headersTransform) {
this.setHeaders(this.headersTransform(row));
}
else if (this.shouldUseFirstRow) {
this.setHeaders(row);
}
else {
// dont do anything with the headers if we didnt receive a transform or shouldnt use the first row.
return true;
}
return false;
}
return true;
}
processRow(row) {
if (!this.headers) {
return { row: row, isValid: true };
}
const { parserOptions } = this;
if (!parserOptions.discardUnmappedColumns && row.length > this.headersLength) {
if (!parserOptions.strictColumnHandling) {
throw new Error(`Unexpected Error: column header mismatch expected: ${this.headersLength} columns got: ${row.length}`);
}
return {
row: row,
isValid: false,
reason: `Column header mismatch expected: ${this.headersLength} columns got: ${row.length}`,
};
}
if (parserOptions.strictColumnHandling && row.length < this.headersLength) {
return {
row: row,
isValid: false,
reason: `Column header mismatch expected: ${this.headersLength} columns got: ${row.length}`,
};
}
return { row: this.mapHeaders(row), isValid: true };
}
mapHeaders(row) {
const rowMap = {};
const { headers, headersLength } = this;
for (let i = 0; i < headersLength; i += 1) {
const header = headers[i];
if (!lodash_isundefined_1.default(header)) {
const val = row[i];
// eslint-disable-next-line no-param-reassign
if (lodash_isundefined_1.default(val)) {
rowMap[header] = '';
}
else {
rowMap[header] = val;
}
}
}
return rowMap;
}
setHeaders(headers) {
var _a;
const filteredHeaders = headers.filter((h) => !!h);
if (lodash_uniq_1.default(filteredHeaders).length !== filteredHeaders.length) {
const grouped = lodash_groupby_1.default(filteredHeaders);
const duplicates = Object.keys(grouped).filter((dup) => grouped[dup].length > 1);
throw new Error(`Duplicate headers found ${JSON.stringify(duplicates)}`);
}
this.headers = headers;
this.receivedHeaders = true;
this.headersLength = ((_a = this.headers) === null || _a === void 0 ? void 0 : _a.length) || 0;
}
}
exports.HeaderTransformer = HeaderTransformer;
//# sourceMappingURL=HeaderTransformer.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"HeaderTransformer.js","sourceRoot":"","sources":["../../../src/transforms/HeaderTransformer.ts"],"names":[],"mappings":"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"}

View File

@ -1,12 +0,0 @@
import { Row, RowTransformFunction, RowValidatorCallback, RowValidate } from '../types';
export declare class RowTransformerValidator<I extends Row, O extends Row> {
private static createTransform;
private static createValidator;
private _rowTransform;
private _rowValidator;
set rowTransform(transformFunction: RowTransformFunction<I, O>);
set rowValidator(validateFunction: RowValidate<O>);
transformAndValidate(row: I, cb: RowValidatorCallback<O>): void;
private callTransformer;
private callValidator;
}

View File

@ -1,93 +0,0 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.RowTransformerValidator = void 0;
const lodash_isfunction_1 = __importDefault(require("lodash.isfunction"));
const types_1 = require("../types");
class RowTransformerValidator {
constructor() {
this._rowTransform = null;
this._rowValidator = null;
}
// eslint-disable-next-line @typescript-eslint/no-shadow
static createTransform(transformFunction) {
if (types_1.isSyncTransform(transformFunction)) {
return (row, cb) => {
let transformed = null;
try {
transformed = transformFunction(row);
}
catch (e) {
return cb(e);
}
return cb(null, transformed);
};
}
return transformFunction;
}
static createValidator(validateFunction) {
if (types_1.isSyncValidate(validateFunction)) {
return (row, cb) => {
cb(null, { row, isValid: validateFunction(row) });
};
}
return (row, cb) => {
validateFunction(row, (err, isValid, reason) => {
if (err) {
return cb(err);
}
if (isValid) {
return cb(null, { row, isValid, reason });
}
return cb(null, { row, isValid: false, reason });
});
};
}
set rowTransform(transformFunction) {
if (!lodash_isfunction_1.default(transformFunction)) {
throw new TypeError('The transform should be a function');
}
this._rowTransform = RowTransformerValidator.createTransform(transformFunction);
}
set rowValidator(validateFunction) {
if (!lodash_isfunction_1.default(validateFunction)) {
throw new TypeError('The validate should be a function');
}
this._rowValidator = RowTransformerValidator.createValidator(validateFunction);
}
transformAndValidate(row, cb) {
return this.callTransformer(row, (transformErr, transformedRow) => {
if (transformErr) {
return cb(transformErr);
}
if (!transformedRow) {
return cb(null, { row: null, isValid: true });
}
return this.callValidator(transformedRow, (validateErr, validationResult) => {
if (validateErr) {
return cb(validateErr);
}
if (validationResult && !validationResult.isValid) {
return cb(null, { row: transformedRow, isValid: false, reason: validationResult.reason });
}
return cb(null, { row: transformedRow, isValid: true });
});
});
}
callTransformer(row, cb) {
if (!this._rowTransform) {
return cb(null, row);
}
return this._rowTransform(row, cb);
}
callValidator(row, cb) {
if (!this._rowValidator) {
return cb(null, { row, isValid: true });
}
return this._rowValidator(row, cb);
}
}
exports.RowTransformerValidator = RowTransformerValidator;
//# sourceMappingURL=RowTransformerValidator.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"RowTransformerValidator.js","sourceRoot":"","sources":["../../../src/transforms/RowTransformerValidator.ts"],"names":[],"mappings":"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"}

View File

@ -1,2 +0,0 @@
export { RowTransformerValidator } from './RowTransformerValidator';
export { HeaderTransformer } from './HeaderTransformer';

View File

@ -1,8 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.HeaderTransformer = exports.RowTransformerValidator = void 0;
var RowTransformerValidator_1 = require("./RowTransformerValidator");
Object.defineProperty(exports, "RowTransformerValidator", { enumerable: true, get: function () { return RowTransformerValidator_1.RowTransformerValidator; } });
var HeaderTransformer_1 = require("./HeaderTransformer");
Object.defineProperty(exports, "HeaderTransformer", { enumerable: true, get: function () { return HeaderTransformer_1.HeaderTransformer; } });
//# sourceMappingURL=index.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/transforms/index.ts"],"names":[],"mappings":";;;AAAA,qEAAoE;AAA3D,kIAAA,uBAAuB,OAAA;AAChC,yDAAwD;AAA/C,sHAAA,iBAAiB,OAAA"}

View File

@ -1,21 +0,0 @@
export declare type RowMap<V = any> = Record<string, V>;
export declare type RowArray<V = any> = V[];
export declare type Row<V = any> = RowMap<V> | RowArray<V>;
export interface RowValidationResult<R extends Row> {
row: R | null;
isValid: boolean;
reason?: string;
}
export declare type RowValidatorCallback<R extends Row> = (error: Error | null, result?: RowValidationResult<R>) => void;
export declare type RowTransformCallback<R extends Row> = (error?: Error | null, row?: R) => void;
export declare type SyncRowTransform<I extends Row, O extends Row> = (row: I) => O;
export declare type AsyncRowTransform<I extends Row, O extends Row> = (row: I, cb: RowTransformCallback<O>) => void;
export declare type RowTransformFunction<I extends Row, O extends Row> = SyncRowTransform<I, O> | AsyncRowTransform<I, O>;
export declare const isSyncTransform: <I extends Row<any>, O extends Row<any>>(transform: RowTransformFunction<I, O>) => transform is SyncRowTransform<I, O>;
export declare type RowValidateCallback = (error?: Error | null, isValid?: boolean, reason?: string) => void;
export declare type SyncRowValidate<R extends Row> = (row: R) => boolean;
export declare type AsyncRowValidate<R extends Row> = (row: R, cb: RowValidateCallback) => void;
export declare type RowValidate<R extends Row> = AsyncRowValidate<R> | SyncRowValidate<R>;
export declare const isSyncValidate: <R extends Row<any>>(validate: RowValidate<R>) => validate is SyncRowValidate<R>;
export declare type HeaderArray = (string | undefined | null)[];
export declare type HeaderTransformFunction = (headers: HeaderArray) => HeaderArray;

View File

@ -1,6 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isSyncValidate = exports.isSyncTransform = void 0;
exports.isSyncTransform = (transform) => transform.length === 1;
exports.isSyncValidate = (validate) => validate.length === 1;
//# sourceMappingURL=types.js.map

View File

@ -1 +0,0 @@
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":";;;AAoBa,QAAA,eAAe,GAAG,CAC3B,SAAqC,EACF,EAAE,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,CAAC;AAQpD,QAAA,cAAc,GAAG,CAAgB,QAAwB,EAAkC,EAAE,CACtG,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC"}

View File

@ -1,62 +0,0 @@
{
"name": "@fast-csv/parse",
"version": "4.3.6",
"description": "fast-csv parsing package",
"keywords": [
"csv",
"parse",
"fast-csv",
"parser"
],
"author": "doug-martin <doug@dougamartin.com>",
"homepage": "http://c2fo.github.com/fast-csv/packages/parse",
"license": "MIT",
"main": "build/src/index.js",
"types": "build/src/index.d.ts",
"directories": {
"lib": "src",
"test": "__tests__"
},
"files": [
"build/src/**"
],
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "git+https://github.com/C2FO/fast-csv.git",
"directory": "packages/parse"
},
"scripts": {
"prepublishOnly": "npm run build",
"build": "npm run clean && npm run compile",
"clean": "rm -rf ./build && rm -rf tsconfig.tsbuildinfo",
"compile": "tsc"
},
"bugs": {
"url": "https://github.com/C2FO/fast-csv/issues"
},
"dependencies": {
"@types/node": "^14.0.1",
"lodash.escaperegexp": "^4.1.2",
"lodash.groupby": "^4.6.0",
"lodash.isfunction": "^3.0.9",
"lodash.isnil": "^4.0.0",
"lodash.isundefined": "^3.0.1",
"lodash.uniq": "^4.5.0"
},
"devDependencies": {
"@types/lodash.escaperegexp": "4.1.6",
"@types/lodash.groupby": "4.6.6",
"@types/lodash.isfunction": "3.0.6",
"@types/lodash.isnil": "4.0.6",
"@types/lodash.isundefined": "3.0.6",
"@types/lodash.partition": "4.6.6",
"@types/lodash.uniq": "4.5.6",
"@types/sinon": "9.0.9",
"lodash.partition": "4.6.0",
"sinon": "9.2.1"
},
"gitHead": "3dc859edb19924b315051e4c87d6273808a0de73"
}

Some files were not shown because too many files have changed in this diff Show More