11'use strict' ;
22
33var _ = require ( 'underscore' ) ,
4+ path = require ( './path' ) ,
45 constants = require ( './constants' ) ;
56
67var options = { } ; // Initialize the options - this will be populated when the csv2json function is called.
@@ -12,42 +13,19 @@ var options = {}; // Initialize the options - this will be populated when the cs
1213 * @returns {* }
1314 */
1415var retrieveHeading = function ( lines , callback ) {
15- if ( ! lines . length ) { // If there are no lines passed in, then throw an error
16+ // If there are no lines passed in, return an error
17+ if ( ! lines . length ) {
1618 return callback ( new Error ( constants . Errors . csv2json . noDataRetrieveHeading ) ) ; // Pass an error back to the user
1719 }
1820
19- var heading = _ . map ( lines [ 0 ] . split ( options . DELIMITER . FIELD ) ,
21+ // Generate and return the heading keys
22+ return _ . map ( lines [ 0 ] . split ( options . DELIMITER . FIELD ) ,
2023 function ( headerKey , index ) {
2124 return {
2225 value : headerKey ,
2326 index : index
2427 } ;
2528 } ) ;
26- return heading ;
27- } ;
28-
29- /**
30- * Add a nested key and its value in the given document
31- * @param key String
32- * @param value String
33- * @param doc Object
34- * @returns {* }
35- */
36- var addNestedKey = function ( key , value , doc ) {
37- var subDocumentRoot = doc , // This is the document that we will be using to add the nested keys to.
38- trackerDocument = subDocumentRoot , // This is the document that will use to iterate through the subDocument, starting at the root
39- nestedKeys = key . split ( '.' ) , // Array of all keys and sub keys for the document
40- finalKey = nestedKeys . pop ( ) ; // Retrieve the last sub key.
41- _ . each ( nestedKeys , function ( nestedKey ) {
42- if ( trackerDocument [ nestedKey ] ) { // This nestedKey already exists, use an existing doc
43- trackerDocument = trackerDocument [ nestedKey ] ; // Update the trackerDocument to use the existing document
44- } else {
45- trackerDocument [ nestedKey ] = { } ; // Add document at the current subKey
46- trackerDocument = trackerDocument [ nestedKey ] ; // Update trackerDocument to be the added doc for the subKey
47- }
48- } ) ;
49- trackerDocument [ finalKey ] = value ; // Set the final layer key to the value
50- return subDocumentRoot ; // Return the document with the nested document structure setup
5129} ;
5230
5331/**
@@ -56,24 +34,26 @@ var addNestedKey = function (key, value, doc) {
5634 * @returns {boolean }
5735 */
5836var isArrayRepresentation = function ( value ) {
59- return ( value && value . indexOf ( '[' ) === 0 && value . lastIndexOf ( ']' ) === value . length - 1 ) ;
37+ // Verify that there is a value and it starts with '[' and ends with ']'
38+ return ( value && / ^ \[ .* \] $ / . test ( value ) ) ;
6039} ;
6140
6241/**
6342 * Converts the value from a CSV 'array'
6443 * @param val
6544 * @returns {Array }
6645 */
67- var convertArrayRepresentation = function ( val ) {
68- val = _ . filter ( val . substring ( 1 , val . length - 1 ) . split ( options . DELIMITER . ARRAY ) , function ( value ) {
69- return value ;
70- } ) ;
71- _ . each ( val , function ( value , indx ) {
72- if ( isArrayRepresentation ( value ) ) {
73- val [ indx ] = convertArrayRepresentation ( value ) ;
74- }
75- } ) ;
76- return val ;
46+ var convertArrayRepresentation = function ( arrayRepresentation ) {
47+ // Remove the '[' and ']' characters
48+ arrayRepresentation = arrayRepresentation . replace ( / ( \[ | \] ) / g, '' ) ;
49+
50+ // Split the arrayRepresentation into an array by the array delimiter
51+ arrayRepresentation = arrayRepresentation . split ( options . DELIMITER . ARRAY ) ;
52+
53+ // Filter out non-empty strings
54+ return _ . filter ( arrayRepresentation , function ( value ) {
55+ return value ;
56+ } ) ;
7757} ;
7858
7959/**
@@ -83,23 +63,22 @@ var convertArrayRepresentation = function (val) {
8363 * @param line String
8464 * @returns {Object } created json document
8565 */
86- var createDoc = function ( keys , line ) {
87- if ( line == '' ) { return false ; } // If we have an empty line, then return false so we can remove all blank lines (falsy values)
88- var doc = { } , // JSON document to start with and manipulate
89- val , // Temporary variable to set the current key's value to
90- line = line . trim ( ) . split ( options . DELIMITER . FIELD ) ; // Split the line using the given field delimiter after trimming whitespace
91- _ . each ( keys , function ( key , indx ) {
92- val = line [ key . index ] === '' ? null : line [ key . index ] ;
66+ var createDocument = function ( keys , line ) {
67+ var line = line . split ( options . DELIMITER . FIELD ) , // Split the line using the given field delimiter after trimming whitespace
68+ val ; // Temporary variable to set the current key's value to
69+
70+ // Reduce the keys into a JSON document representing the given line
71+ return _ . reduce ( keys , function ( document , key ) {
72+ // If there is no value (empty string) at the key's index in the line, set the value to null; otherwise the value
73+ val = ! line [ key . index ] ? null : line [ key . index ] ;
74+
75+ // If the value is an array representation, convert it
9376 if ( isArrayRepresentation ( val ) ) {
9477 val = convertArrayRepresentation ( val ) ;
9578 }
96- if ( key . value . indexOf ( '.' ) ) { // If key has '.' representing nested document
97- doc = addNestedKey ( key . value , val , doc ) ; // Update the document to add the nested key structure
98- } else { // Else we just have a straight key:value mapping
99- doc [ key ] = val ; // Set the value at the current key
100- }
101- } ) ;
102- return doc ; // Return the created document
79+ // Otherwise add the key and value to the document
80+ return path . setPath ( document , key . value , val ) ;
81+ } , { } ) ;
10382} ;
10483
10584/**
@@ -109,16 +88,20 @@ var createDoc = function (keys, line) {
10988 * @returns {Array }
11089 */
11190var convertCSV = function ( lines , callback ) {
112- var generatedHeaders = retrieveHeading ( lines , callback ) , // Retrieve the headings from the CSV, unless the user specified the keys
113- jsonDocs = [ ] , // Create an array that we can add the generated documents to
91+ var nonHeaderLines = lines . splice ( 1 ) , // All lines that are not the header line
92+ generatedHeaders = retrieveHeading ( lines , callback ) , // Retrieve the headings from the CSV
93+ // If the user specified keys, then filter the generated keys down to the user specified keys so we have the key index
11494 headers = options . KEYS ? _ . filter ( generatedHeaders , function ( headerKey ) {
11595 return _ . contains ( options . KEYS , headerKey . value ) ;
11696 } ) : generatedHeaders ;
117- lines = lines . splice ( 1 ) ; // Grab all lines except for the header
118- _ . each ( lines , function ( line ) { // For each line, create the document and add it to the array of documents
119- jsonDocs . push ( createDoc ( headers , line ) ) ;
120- } ) ;
121- return _ . filter ( jsonDocs , function ( doc ) { return doc !== false ; } ) ; // Return all non 'falsey' values to filter blank lines
97+
98+ // Reduce the nonHeaderLines into an array of documents representing the lines
99+ return _ . reduce ( nonHeaderLines , function ( jsonDocs , line ) {
100+ if ( ! line ) { return ; } // skip over empty lines
101+ var generatedDocument = createDocument ( headers , line . trim ( ) ) ;
102+ jsonDocs . push ( generatedDocument ) ;
103+ return jsonDocs ;
104+ } , [ ] ) ;
122105} ;
123106
124107module . exports = {
0 commit comments