1#![cfg(feature = "wasm")]
6
7use std::collections::HashSet;
8use serde::Serialize;
9use wasm_bindgen::prelude::*;
10
11use super::domain::check_domain;
12use crate::error::{error_json, error_to_json};
13
14#[derive(Serialize)]
15struct ParsedCsv {
16 headers: Vec<String>,
17 data: Vec<serde_json::Map<String, serde_json::Value>>,
18 numeric_columns: Vec<String>,
19}
20
21#[wasm_bindgen]
45pub fn parse_csv(content: &str) -> String {
46 if let Err(e) = check_domain() {
47 return error_to_json(&e);
48 }
49
50 let mut reader = csv::ReaderBuilder::new()
51 .has_headers(true)
52 .flexible(true)
53 .from_reader(content.as_bytes());
54
55 let headers: Vec<String> = match reader.headers() {
57 Ok(h) => h.iter().map(|s| s.to_string()).collect(),
58 Err(e) => return error_json(&format!("Failed to read headers: {}", e)),
59 };
60
61 let mut data = Vec::new();
62 let mut numeric_col_set = HashSet::new();
63
64 for result in reader.records() {
65 let record = match result {
66 Ok(r) => r,
67 Err(e) => return error_json(&format!("Failed to parse CSV record: {}", e)),
68 };
69
70 if record.len() != headers.len() {
71 continue;
72 }
73
74 let mut row_map = serde_json::Map::new();
75
76 for (i, field) in record.iter().enumerate() {
77 if i >= headers.len() {
78 continue;
79 }
80
81 let header = &headers[i];
82 let val_trimmed = field.trim();
83
84 if let Ok(num) = val_trimmed.parse::<f64>() {
86 if num.is_finite() {
87 row_map.insert(
88 header.clone(),
89 serde_json::Value::Number(serde_json::Number::from_f64(num).unwrap()),
90 );
91 numeric_col_set.insert(header.clone());
92 continue;
93 }
94 }
95
96 row_map.insert(
98 header.clone(),
99 serde_json::Value::String(val_trimmed.to_string()),
100 );
101 }
102 data.push(row_map);
103 }
104
105 let mut numeric_columns: Vec<String> = numeric_col_set.into_iter().collect();
106 numeric_columns.sort();
107
108 let output = ParsedCsv {
109 headers,
110 data,
111 numeric_columns,
112 };
113
114 serde_json::to_string(&output).unwrap_or_else(|_| error_json("Failed to serialize CSV output"))
115}