aboutsummaryrefslogtreecommitdiffstats
path: root/runtime/ui-react/src/utils/CsvToJson.js
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/ui-react/src/utils/CsvToJson.js')
-rw-r--r--runtime/ui-react/src/utils/CsvToJson.js358
1 files changed, 179 insertions, 179 deletions
diff --git a/runtime/ui-react/src/utils/CsvToJson.js b/runtime/ui-react/src/utils/CsvToJson.js
index 5ec19c9e2..6d95b3119 100644
--- a/runtime/ui-react/src/utils/CsvToJson.js
+++ b/runtime/ui-react/src/utils/CsvToJson.js
@@ -22,183 +22,183 @@
export default function CsvToJson(rawCsvData, delimiter, internalDelimiter, csvHeaderNames, jsonKeyNames, mandatory) {
- let printDictKeys = '';
- let result = { jsonObjArray: [], errorMessages: '' };
-
- // Validate that all parallel arrays passed in have same number of elements;
- // this would be a developer error.
-
- let checkLength = csvHeaderNames.length;
-
- if (checkLength !== jsonKeyNames.length || checkLength !== mandatory.length) {
- result.errorMessages = 'interanl error: csvHeaderNames, jsonKeyNames, and mandatory arrays parameters are not the same length';
- return result;
- }
-
- if (checkLength < 1) {
- result.errorMessages = 'interanl error: csvHeaderNames, jsonKeyNames, and mandatory arrays have no entries';
- return result;
- }
-
- // Make a nice string to print in the error case to tell user what is the
- // required heaer row format
-
- for (let i=0; i < csvHeaderNames.length; ++i) {
- if (i === 0) {
- printDictKeys = csvHeaderNames[i];
- } else {
- printDictKeys += ',' + csvHeaderNames[i];
- }
- }
-
- let dictElems = rawCsvData.split('\n');
- let numColumns = 0;
- let filteredDictElems = [];
-
- // The task of the following loop is to convert raw CSV rows into easily parseable
- // and streamlined versions of the rows with an internalDelimiter replacing the standard
- // comma; it is presumed (and checked) that the internalDelimiter cannot exist as a valid
- // sequence of characters in the user's data.
-
- // This conversion process also strips leading and trailing whitespace from each row,
- // discards empty rows, correctly interprets and removes all double quotes that programs like
- // Excel use to support user columns that contain special characters, most notably, the comma
- // delimiter. A double-quote that is contained within a double-quoted column value
- // must appear in this raw data as a sequence of two double quotes. Furthermore, any column
- // value in the raw CSV data that does not contain a delimiter may or may not be enclosed in
- // double quotes. It is the Excel convention to not use double qoutes unless necessary, and
- // there is no reasonable way to tell Excel to surround every column value with double quotes.
- // Any files that were directly "exported" by CLAMP itself from the Managing Dictionaries
- // capability, surround all columns with double quotes.
-
- for (let i = 0; i < dictElems.length; i++) {
-
- let oneRow = dictElems[i].trim();
- let j = 0;
- let inQuote = false
- let nextChar = undefined;
- let prevChar = null;
-
-
- if (oneRow === '') {
- continue; // Skip blank rows
- } else if (oneRow.indexOf(internalDelimiter) !== -1) {
- result.errorMessages += '\nRow #' + i + ' contains illegal sequence of characters (' + internalDelimiter + ')';
- break;
- } else {
- nextChar = oneRow[1];
- }
-
- let newStr = '';
- numColumns = 1;
-
- // This "while loop" performs the very meticulous task of removing double quotes that
- // are used by Excel to encase special characters as user string value data,
- // and manages to correctly identify columns that are defined with or without
- // double quotes and to process the comma delimiter correctly when encountered
- // as a user value within a column. Such a column would have to be encased in
- // double quotes; a comma found outside double quotes IS a delimiter.
-
- while (j < oneRow.length) {
- if (oneRow[j] === '"') {
- if (inQuote === false) {
- if (prevChar !== delimiter && prevChar !== null) {
- result.errorMessages += '\nMismatched double quotes or illegal whitespace around delimiter at row #' + (i + 1) + ' near column #' + numColumns;
- break;
- } else {
- inQuote = true;
- }
- } else {
- if (nextChar === '"') {
- newStr += '"';
- ++j;
- } else if ((nextChar !== delimiter) && (nextChar !== undefined)) {
- result.errorMessages += '\nRow #' + (i + 1) + ' is badly formatted at column #' + numColumns + '. Perhaps an unescaped double quote.';
- break;
- } else if (nextChar === delimiter) {
- ++numColumns;
- inQuote = false;
- newStr += internalDelimiter;
- prevChar = delimiter;
- j += 2;
- nextChar = oneRow[j+1];
- continue;
- } else {
- ++numColumns;
- inQuote = false;
- break;
- }
- }
- } else {
- if (oneRow[j] === delimiter && inQuote === false) {
- newStr += internalDelimiter;
- ++numColumns;
- } else {
- newStr += oneRow[j];
- }
- }
- prevChar = oneRow[j];
- ++j;
- nextChar = oneRow[j+1]; // can result in undefined at the end
- }
-
- if (result.errorMessages === '' && inQuote !== false) {
- result.errorMessages += '\nMismatched double quotes at row #' + (i + 1);
- break;
- } else if (result.errorMessages === '' && numColumns < jsonKeyNames.length) {
- result.errorMessages += '\nNot enough columns (' + jsonKeyNames.length + ') at row #' + (i + 1);
- break;
- }
-
- filteredDictElems.push(newStr);
- }
-
- if (result.errorMessages !== '') {
- return result;
- }
-
- // Perform further checks on data that is now in JSON form
- if (filteredDictElems.length < 2) {
- result.errorMessages += '\nNot enough row data found in import file. Need at least a header row and one row of data';
- return result;
- }
-
- // Now that we have something reliably parsed into sanitized columns lets run some checks
- // and convert it all into an array of JSON objects to push to the back end if all the
- // checks pass.
-
- let headers = filteredDictElems[0].split(internalDelimiter);
-
- // check that headers are included in proper order
- for (let i=0; i < jsonKeyNames.length; ++i) {
- if (csvHeaderNames[i] !== headers[i]) {
- result.errorMessages += 'Row 1 header key at column #' + (i + 1) + ' is a mismatch. Expected row header must contain at least:\n' + printDictKeys;
- return result;
- }
- }
-
- // Convert the ASCII rows of data into an array of JSON obects that omit the header
- // row which is not sent to the back end.
-
- for (let i = 1; i < filteredDictElems.length; i++) {
- let data = filteredDictElems[i].split(internalDelimiter);
- let obj = {};
- for (let j = 0; j < data.length && j < jsonKeyNames.length; j++) {
- let value = data[j].trim();
- if (mandatory[j] === true && value === '') {
- result.errorMessages += '\n' + csvHeaderNames[j] + ' at row #' + (i+1) + ' is empty but requires a value.';
- }
- obj[jsonKeyNames[j]] = value;
- }
- result.jsonObjArray.push(obj);
- }
-
- if (result.errorMessages !== '') {
- // If we have errors, return empty parse result even though some things
- // may have parsed properly. We do not want to encourage the caller
- // to think the data is good for use.
- result.jsonObjArray = [];
- }
-
- return result;
+ let printDictKeys = '';
+ let result = { jsonObjArray: [], errorMessages: '' };
+
+ // Validate that all parallel arrays passed in have same number of elements;
+ // this would be a developer error.
+
+ let checkLength = csvHeaderNames.length;
+
+ if (checkLength !== jsonKeyNames.length || checkLength !== mandatory.length) {
+ result.errorMessages = 'interanl error: csvHeaderNames, jsonKeyNames, and mandatory arrays parameters are not the same length';
+ return result;
+ }
+
+ if (checkLength < 1) {
+ result.errorMessages = 'interanl error: csvHeaderNames, jsonKeyNames, and mandatory arrays have no entries';
+ return result;
+ }
+
+ // Make a nice string to print in the error case to tell user what is the
+ // required heaer row format
+
+ for (let i = 0; i < csvHeaderNames.length; ++i) {
+ if (i === 0) {
+ printDictKeys = csvHeaderNames[i];
+ } else {
+ printDictKeys += ',' + csvHeaderNames[i];
+ }
+ }
+
+ let dictElems = rawCsvData.split('\n');
+ let numColumns = 0;
+ let filteredDictElems = [];
+
+ // The task of the following loop is to convert raw CSV rows into easily parseable
+ // and streamlined versions of the rows with an internalDelimiter replacing the standard
+ // comma; it is presumed (and checked) that the internalDelimiter cannot exist as a valid
+ // sequence of characters in the user's data.
+
+ // This conversion process also strips leading and trailing whitespace from each row,
+ // discards empty rows, correctly interprets and removes all double quotes that programs like
+ // Excel use to support user columns that contain special characters, most notably, the comma
+ // delimiter. A double-quote that is contained within a double-quoted column value
+ // must appear in this raw data as a sequence of two double quotes. Furthermore, any column
+ // value in the raw CSV data that does not contain a delimiter may or may not be enclosed in
+ // double quotes. It is the Excel convention to not use double qoutes unless necessary, and
+ // there is no reasonable way to tell Excel to surround every column value with double quotes.
+ // Any files that were directly "exported" by CLAMP itself from the Managing Dictionaries
+ // capability, surround all columns with double quotes.
+
+ for (let i = 0; i < dictElems.length; i++) {
+
+ let oneRow = dictElems[i].trim();
+ let j = 0;
+ let inQuote = false
+ let nextChar = undefined;
+ let prevChar = null;
+
+
+ if (oneRow === '') {
+ continue; // Skip blank rows
+ } else if (oneRow.indexOf(internalDelimiter) !== -1) {
+ result.errorMessages += '\nRow #' + i + ' contains illegal sequence of characters (' + internalDelimiter + ')';
+ break;
+ } else {
+ nextChar = oneRow[1];
+ }
+
+ let newStr = '';
+ numColumns = 1;
+
+ // This "while loop" performs the very meticulous task of removing double quotes that
+ // are used by Excel to encase special characters as user string value data,
+ // and manages to correctly identify columns that are defined with or without
+ // double quotes and to process the comma delimiter correctly when encountered
+ // as a user value within a column. Such a column would have to be encased in
+ // double quotes; a comma found outside double quotes IS a delimiter.
+
+ while (j < oneRow.length) {
+ if (oneRow[j] === '"') {
+ if (inQuote === false) {
+ if (prevChar !== delimiter && prevChar !== null) {
+ result.errorMessages += '\nMismatched double quotes or illegal whitespace around delimiter at row #' + (i + 1) + ' near column #' + numColumns;
+ break;
+ } else {
+ inQuote = true;
+ }
+ } else {
+ if (nextChar === '"') {
+ newStr += '"';
+ ++j;
+ } else if ((nextChar !== delimiter) && (nextChar !== undefined)) {
+ result.errorMessages += '\nRow #' + (i + 1) + ' is badly formatted at column #' + numColumns + '. Perhaps an unescaped double quote.';
+ break;
+ } else if (nextChar === delimiter) {
+ ++numColumns;
+ inQuote = false;
+ newStr += internalDelimiter;
+ prevChar = delimiter;
+ j += 2;
+ nextChar = oneRow[j + 1];
+ continue;
+ } else {
+ ++numColumns;
+ inQuote = false;
+ break;
+ }
+ }
+ } else {
+ if (oneRow[j] === delimiter && inQuote === false) {
+ newStr += internalDelimiter;
+ ++numColumns;
+ } else {
+ newStr += oneRow[j];
+ }
+ }
+ prevChar = oneRow[j];
+ ++j;
+ nextChar = oneRow[j + 1]; // can result in undefined at the end
+ }
+
+ if (result.errorMessages === '' && inQuote !== false) {
+ result.errorMessages += '\nMismatched double quotes at row #' + (i + 1);
+ break;
+ } else if (result.errorMessages === '' && numColumns < jsonKeyNames.length) {
+ result.errorMessages += '\nNot enough columns (' + jsonKeyNames.length + ') at row #' + (i + 1);
+ break;
+ }
+
+ filteredDictElems.push(newStr);
+ }
+
+ if (result.errorMessages !== '') {
+ return result;
+ }
+
+ // Perform further checks on data that is now in JSON form
+ if (filteredDictElems.length < 2) {
+ result.errorMessages += '\nNot enough row data found in import file. Need at least a header row and one row of data';
+ return result;
+ }
+
+ // Now that we have something reliably parsed into sanitized columns lets run some checks
+ // and convert it all into an array of JSON objects to push to the back end if all the
+ // checks pass.
+
+ let headers = filteredDictElems[0].split(internalDelimiter);
+
+ // check that headers are included in proper order
+ for (let i = 0; i < jsonKeyNames.length; ++i) {
+ if (csvHeaderNames[i] !== headers[i]) {
+ result.errorMessages += 'Row 1 header key at column #' + (i + 1) + ' is a mismatch. Expected row header must contain at least:\n' + printDictKeys;
+ return result;
+ }
+ }
+
+ // Convert the ASCII rows of data into an array of JSON obects that omit the header
+ // row which is not sent to the back end.
+
+ for (let i = 1; i < filteredDictElems.length; i++) {
+ let data = filteredDictElems[i].split(internalDelimiter);
+ let obj = {};
+ for (let j = 0; j < data.length && j < jsonKeyNames.length; j++) {
+ let value = data[j].trim();
+ if (mandatory[j] === true && value === '') {
+ result.errorMessages += '\n' + csvHeaderNames[j] + ' at row #' + (i + 1) + ' is empty but requires a value.';
+ }
+ obj[jsonKeyNames[j]] = value;
+ }
+ result.jsonObjArray.push(obj);
+ }
+
+ if (result.errorMessages !== '') {
+ // If we have errors, return empty parse result even though some things
+ // may have parsed properly. We do not want to encourage the caller
+ // to think the data is good for use.
+ result.jsonObjArray = [];
+ }
+
+ return result;
}