@juspay/neurolink 8.31.2 → 8.31.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## [8.31.3](https://github.com/juspay/neurolink/compare/v8.31.2...v8.31.3) (2026-01-05)
2
+
3
+ ### Bug Fixes
4
+
5
+ - **(csv):** standardize rowCount to exclude empty lines across all formats (CSV-025) ([c898521](https://github.com/juspay/neurolink/commit/c8985212ff6bb43a6cefbf7a5551ed603b32bc55)), closes [#390](https://github.com/juspay/neurolink/issues/390)
6
+
1
7
  ## [8.31.2](https://github.com/juspay/neurolink/compare/v8.31.1...v8.31.2) (2026-01-05)
2
8
 
3
9
  ### Bug Fixes
@@ -44,6 +44,7 @@ export type FileProcessingResult = {
44
44
  filename?: string;
45
45
  extension?: string | null;
46
46
  rowCount?: number;
47
+ totalLines?: number;
47
48
  columnCount?: number;
48
49
  columnNames?: string[];
49
50
  sampleData?: string | unknown[];
@@ -85,8 +85,12 @@ export class CSVProcessor {
85
85
  : lines;
86
86
  const limitedLines = csvLines.slice(0, 1 + maxRows); // header + data rows
87
87
  const limitedCSV = limitedLines.join("\n");
88
- const rowCount = limitedLines.length - 1; // Subtract header
89
- const originalRowCount = csvLines.length - 1; // Subtract header from original
88
+ const rowCount = limitedLines
89
+ .slice(1)
90
+ .filter((line) => line.trim() !== "").length;
91
+ const originalRowCount = csvLines
92
+ .slice(1)
93
+ .filter((line) => line.trim() !== "").length;
90
94
  const wasTruncated = rowCount < originalRowCount;
91
95
  if (wasTruncated) {
92
96
  logger.warn(`[CSVProcessor] CSV data truncated: showing ${rowCount} of ${originalRowCount} rows (limit: ${maxRows})`);
@@ -110,6 +114,7 @@ export class CSVProcessor {
110
114
  confidence: 100,
111
115
  size: content.length,
112
116
  rowCount,
117
+ totalLines: limitedLines.length,
113
118
  columnCount: (limitedLines[0] || "").split(",").length,
114
119
  extension,
115
120
  },
@@ -121,12 +126,26 @@ export class CSVProcessor {
121
126
  maxRows,
122
127
  });
123
128
  const rows = await this.parseCSVString(csvString, maxRows);
129
+ // Filter out empty rows (empty objects or rows with only whitespace values from blank lines)
130
+ const nonEmptyRows = rows.filter((row) => {
131
+ if (!row || typeof row !== "object") {
132
+ return false;
133
+ }
134
+ const keys = Object.keys(row);
135
+ if (keys.length === 0) {
136
+ return false;
137
+ }
138
+ // Check if all values are empty or whitespace-only
139
+ return !Object.values(row).every((val) => val === "" || (typeof val === "string" && val.trim() === ""));
140
+ });
124
141
  // Extract metadata from parsed results
125
- const rowCount = rows.length;
126
- const columnNames = rows.length > 0 ? Object.keys(rows[0]) : [];
142
+ const rowCount = nonEmptyRows.length;
143
+ const columnNames = nonEmptyRows.length > 0
144
+ ? Object.keys(nonEmptyRows[0])
145
+ : [];
127
146
  const columnCount = columnNames.length;
128
147
  const hasEmptyColumns = columnNames.some((col) => !col || col.trim() === "");
129
- const sampleRows = rows.slice(0, 3);
148
+ const sampleRows = nonEmptyRows.slice(0, 3);
130
149
  const sampleData = this.formatSampleData(sampleRows, sampleDataFormat, includeHeaders);
131
150
  if (hasEmptyColumns) {
132
151
  logger.warn("[CSVProcessor] CSV contains empty or blank column headers", {
@@ -138,7 +157,7 @@ export class CSVProcessor {
138
157
  }
139
158
  // Format parsed data
140
159
  logger.debug(`[CSVProcessor] Converting ${rowCount} rows to ${formatStyle} format`);
141
- const formatted = this.formatForLLM(rows, formatStyle, includeHeaders);
160
+ const formatted = this.formatForLLM(nonEmptyRows, formatStyle, includeHeaders);
142
161
  logger.info("[CSVProcessor] ✅ Processed CSV file", {
143
162
  formatStyle,
144
163
  rowCount,
@@ -44,6 +44,7 @@ export type FileProcessingResult = {
44
44
  filename?: string;
45
45
  extension?: string | null;
46
46
  rowCount?: number;
47
+ totalLines?: number;
47
48
  columnCount?: number;
48
49
  columnNames?: string[];
49
50
  sampleData?: string | unknown[];
@@ -85,8 +85,12 @@ export class CSVProcessor {
85
85
  : lines;
86
86
  const limitedLines = csvLines.slice(0, 1 + maxRows); // header + data rows
87
87
  const limitedCSV = limitedLines.join("\n");
88
- const rowCount = limitedLines.length - 1; // Subtract header
89
- const originalRowCount = csvLines.length - 1; // Subtract header from original
88
+ const rowCount = limitedLines
89
+ .slice(1)
90
+ .filter((line) => line.trim() !== "").length;
91
+ const originalRowCount = csvLines
92
+ .slice(1)
93
+ .filter((line) => line.trim() !== "").length;
90
94
  const wasTruncated = rowCount < originalRowCount;
91
95
  if (wasTruncated) {
92
96
  logger.warn(`[CSVProcessor] CSV data truncated: showing ${rowCount} of ${originalRowCount} rows (limit: ${maxRows})`);
@@ -110,6 +114,7 @@ export class CSVProcessor {
110
114
  confidence: 100,
111
115
  size: content.length,
112
116
  rowCount,
117
+ totalLines: limitedLines.length,
113
118
  columnCount: (limitedLines[0] || "").split(",").length,
114
119
  extension,
115
120
  },
@@ -121,12 +126,26 @@ export class CSVProcessor {
121
126
  maxRows,
122
127
  });
123
128
  const rows = await this.parseCSVString(csvString, maxRows);
129
+ // Filter out empty rows (empty objects or rows with only whitespace values from blank lines)
130
+ const nonEmptyRows = rows.filter((row) => {
131
+ if (!row || typeof row !== "object") {
132
+ return false;
133
+ }
134
+ const keys = Object.keys(row);
135
+ if (keys.length === 0) {
136
+ return false;
137
+ }
138
+ // Check if all values are empty or whitespace-only
139
+ return !Object.values(row).every((val) => val === "" || (typeof val === "string" && val.trim() === ""));
140
+ });
124
141
  // Extract metadata from parsed results
125
- const rowCount = rows.length;
126
- const columnNames = rows.length > 0 ? Object.keys(rows[0]) : [];
142
+ const rowCount = nonEmptyRows.length;
143
+ const columnNames = nonEmptyRows.length > 0
144
+ ? Object.keys(nonEmptyRows[0])
145
+ : [];
127
146
  const columnCount = columnNames.length;
128
147
  const hasEmptyColumns = columnNames.some((col) => !col || col.trim() === "");
129
- const sampleRows = rows.slice(0, 3);
148
+ const sampleRows = nonEmptyRows.slice(0, 3);
130
149
  const sampleData = this.formatSampleData(sampleRows, sampleDataFormat, includeHeaders);
131
150
  if (hasEmptyColumns) {
132
151
  logger.warn("[CSVProcessor] CSV contains empty or blank column headers", {
@@ -138,7 +157,7 @@ export class CSVProcessor {
138
157
  }
139
158
  // Format parsed data
140
159
  logger.debug(`[CSVProcessor] Converting ${rowCount} rows to ${formatStyle} format`);
141
- const formatted = this.formatForLLM(rows, formatStyle, includeHeaders);
160
+ const formatted = this.formatForLLM(nonEmptyRows, formatStyle, includeHeaders);
142
161
  logger.info("[CSVProcessor] ✅ Processed CSV file", {
143
162
  formatStyle,
144
163
  rowCount,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juspay/neurolink",
3
- "version": "8.31.2",
3
+ "version": "8.31.3",
4
4
  "description": "Universal AI Development Platform with working MCP integration, multi-provider support, and professional CLI. Built-in tools operational, 58+ external MCP servers discoverable. Connect to filesystem, GitHub, database operations, and more. Build, test, and deploy AI applications with 13 providers: OpenAI, Anthropic, Google AI, AWS Bedrock, Azure, Hugging Face, Ollama, and Mistral AI.",
5
5
  "author": {
6
6
  "name": "Juspay Technologies",