| 
					
				 | 
			
			
				@@ -19,15 +19,15 @@ export const NOT_SPREADSHEET = "NOT_SPREADSHEET"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 export const VALID_SPREADSHEET = "VALID_SPREADSHEET"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 type ParseSpreadsheetResult = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  | { type: typeof NOT_SPREADSHEET } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  | { type: typeof NOT_SPREADSHEET; reason: string } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   | { type: typeof VALID_SPREADSHEET; spreadsheet: Spreadsheet }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 const tryParseNumber = (s: string): number | null => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  const match = /^[$€£¥₩]?([0-9]+(\.[0-9]+)?)$/.exec(s); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const match = /^[$€£¥₩]?([0-9,]+(\.[0-9]+)?)$/.exec(s); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (!match) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     return null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  return parseFloat(match[1]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return parseFloat(match[1].replace(/,/g, "")); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 const isNumericColumn = (lines: string[][], columnIndex: number) => 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -37,12 +37,12 @@ const tryParseCells = (cells: string[][]): ParseSpreadsheetResult => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   const numCols = cells[0].length; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (numCols > 2) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    return { type: NOT_SPREADSHEET }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return { type: NOT_SPREADSHEET, reason: "More than 2 columns" }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (numCols === 1) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if (!isNumericColumn(cells, 0)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      return { type: NOT_SPREADSHEET }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return { type: NOT_SPREADSHEET, reason: "Value is not numeric" }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     const hasHeader = tryParseNumber(cells[0][0]) === null; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -51,7 +51,7 @@ const tryParseCells = (cells: string[][]): ParseSpreadsheetResult => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if (values.length < 2) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      return { type: NOT_SPREADSHEET }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return { type: NOT_SPREADSHEET, reason: "Less than two rows" }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     return { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -67,7 +67,7 @@ const tryParseCells = (cells: string[][]): ParseSpreadsheetResult => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   const valueColumnIndex = isNumericColumn(cells, 0) ? 0 : 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (!isNumericColumn(cells, valueColumnIndex)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    return { type: NOT_SPREADSHEET }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return { type: NOT_SPREADSHEET, reason: "Value is not numeric" }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   const labelColumnIndex = (valueColumnIndex + 1) % 2; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -75,7 +75,7 @@ const tryParseCells = (cells: string[][]): ParseSpreadsheetResult => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   const rows = hasHeader ? cells.slice(1) : cells; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (rows.length < 2) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    return { type: NOT_SPREADSHEET }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return { type: NOT_SPREADSHEET, reason: "Less than 2 rows" }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   return { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -104,13 +104,13 @@ export const tryParseSpreadsheet = (text: string): ParseSpreadsheetResult => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   // Copy/paste from excel, spreadhseets, tsv, csv. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   // For now we only accept 2 columns with an optional header 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  // Check for tab separeted values 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // Check for tab separated values 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   let lines = text 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     .trim() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     .split("\n") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     .map((line) => line.trim().split("\t")); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  // Check for comma separeted files 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // Check for comma separated files 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (lines.length && lines[0].length !== 2) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     lines = text 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       .trim() 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -119,14 +119,17 @@ export const tryParseSpreadsheet = (text: string): ParseSpreadsheetResult => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (lines.length === 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    return { type: NOT_SPREADSHEET }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return { type: NOT_SPREADSHEET, reason: "No values" }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   const numColsFirstLine = lines[0].length; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   const isSpreadsheet = lines.every((line) => line.length === numColsFirstLine); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (!isSpreadsheet) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    return { type: NOT_SPREADSHEET }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      type: NOT_SPREADSHEET, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      reason: "All rows don't have same number of columns", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   const result = tryParseCells(lines); 
			 |