Skip to content
Newer
Older
100644 134 lines (117 sloc) 3.95 KB
5a3ef1b @wdavidw Externalize the parse function into a class
authored
1
2 stream = require 'stream'
3 {EventEmitter} = require 'events'
4
5 ###
6
6784053 @wdavidw Move option docs to 'from' and 'to'; Apply h1 formating to doc
authored
7 Parsing
8 =======
a2b8f8f @wdavidw Externalize stringier code; Remove all buffer related code
authored
9
94c3834 @wdavidw Add readme important section
authored
10 The library extend the EventEmitter and emit the following events:
11
12 * *row*
13 Emitted by the parser on each line with the line content as an array of fields.
14 * *end*
15 * *error*
16
5a3ef1b @wdavidw Externalize the parse function into a class
authored
17 ###
18 Parser = (csv) ->
19 @writable = true
20 @csv = csv
21 @options = csv.options.from
22 @state = csv.state
639573d @wdavidw Split the end function into what related to the parser and the destin…
authored
23 @quoted = false
24 @commented = false
5a3ef1b @wdavidw Externalize the parse function into a class
authored
25 @
26
27 Parser.prototype.__proto__ = EventEmitter.prototype
28
6784053 @wdavidw Move option docs to 'from' and 'to'; Apply h1 formating to doc
authored
29 ###
30
31 `parse(chars)`
32 --------------
33
34 Parse a string which may hold multiple lines.
35 Private state object is enriched on each character until
36 transform is called on a new line.
37
38 ###
5a3ef1b @wdavidw Externalize the parse function into a class
authored
39 Parser.prototype.parse = (chars) ->
40 return @error new Error 'Parser is not writable' unless @writable
41 csv = @csv
42 chars = '' + chars
43 l = chars.length
44 i = 0
45 while i < l
eb631f4 @wdavidw Minor coffee formatting
authored
46 c = chars.charAt i
5a3ef1b @wdavidw Externalize the parse function into a class
authored
47 switch c
48 when @options.escape, @options.quote
639573d @wdavidw Split the end function into what related to the parser and the destin…
authored
49 break if @commented
5a3ef1b @wdavidw Externalize the parse function into a class
authored
50 isReallyEscaped = false
51 if c is @options.escape
52 # Make sure the escape is really here for escaping:
53 # if escape is same as quote, and escape is first char of a field and it's not quoted, then it is a quote
54 # next char should be an escape or a quote
eb631f4 @wdavidw Minor coffee formatting
authored
55 nextChar = chars.charAt i + 1
56 escapeIsQuote = @options.escape is @options.quote
57 isEscape = nextChar is @options.escape
58 isQuote = nextChar is @options.quote
59 if not ( escapeIsQuote and not @state.field and not @quoted ) and ( isEscape or isQuote )
5a3ef1b @wdavidw Externalize the parse function into a class
authored
60 i++
61 isReallyEscaped = true
eb631f4 @wdavidw Minor coffee formatting
authored
62 c = chars.charAt i
5a3ef1b @wdavidw Externalize the parse function into a class
authored
63 @state.field += c
64 if not isReallyEscaped and c is @options.quote
639573d @wdavidw Split the end function into what related to the parser and the destin…
authored
65 if @state.field and not @quoted
5a3ef1b @wdavidw Externalize the parse function into a class
authored
66 # Treat quote as a regular character
67 @state.field += c
68 break
639573d @wdavidw Split the end function into what related to the parser and the destin…
authored
69 if @quoted
5a3ef1b @wdavidw Externalize the parse function into a class
authored
70 # Make sure a closing quote is followed by a delimiter
71 nextChar = chars.charAt i + 1
72 if nextChar and nextChar isnt '\r' and nextChar isnt '\n' and nextChar isnt @options.delimiter
73 return @error new Error 'Invalid closing quote; found ' + JSON.stringify(nextChar) + ' instead of delimiter ' + JSON.stringify(@options.delimiter)
639573d @wdavidw Split the end function into what related to the parser and the destin…
authored
74 @quoted = false
5a3ef1b @wdavidw Externalize the parse function into a class
authored
75 else if @state.field is ''
639573d @wdavidw Split the end function into what related to the parser and the destin…
authored
76 @quoted = true
5a3ef1b @wdavidw Externalize the parse function into a class
authored
77 when @options.delimiter
639573d @wdavidw Split the end function into what related to the parser and the destin…
authored
78 break if @commented
79 if @quoted
5a3ef1b @wdavidw Externalize the parse function into a class
authored
80 @state.field += c
81 else
82 if @options.trim or @options.rtrim
83 @state.field = @state.field.trimRight()
84 @state.line.push @state.field
85 @state.field = ''
86 break
87 when '\n', '\r'
639573d @wdavidw Split the end function into what related to the parser and the destin…
authored
88 if @quoted
5a3ef1b @wdavidw Externalize the parse function into a class
authored
89 @state.field += c
90 break
91 if not @options.quoted and @state.lastC is '\r'
92 break
93 if csv.options.to.lineBreaks is null
94 # Auto-discovery of linebreaks
95 csv.options.to.lineBreaks = c + ( if c is '\r' and chars.charAt(i+1) is '\n' then '\n' else '' )
96 if @options.trim or @options.rtrim
97 @state.field = @state.field.trimRight()
98 @state.line.push @state.field
99 @state.field = ''
100 @emit 'row', @state.line
639573d @wdavidw Split the end function into what related to the parser and the destin…
authored
101 # Some cleanup for the next row
102 @state.line = []
5a3ef1b @wdavidw Externalize the parse function into a class
authored
103 when ' ', '\t'
639573d @wdavidw Split the end function into what related to the parser and the destin…
authored
104 if @quoted or (not @options.trim and not @options.ltrim ) or @state.field
5a3ef1b @wdavidw Externalize the parse function into a class
authored
105 @state.field += c
106 break
107 else
639573d @wdavidw Split the end function into what related to the parser and the destin…
authored
108 break if @commented
5a3ef1b @wdavidw Externalize the parse function into a class
authored
109 @state.field += c
110 @state.lastC = c
111 i++
112
639573d @wdavidw Split the end function into what related to the parser and the destin…
authored
113 Parser.prototype.end = ->
857bbc9 @wdavidw Un-indent parser end
authored
114 if @quoted
115 return @error new Error 'Quoted field not terminated'
116 # dump open record
117 if @state.field or @state.lastC is @options.delimiter or @state.lastC is @options.quote
118 if @options.trim or @options.rtrim
119 @state.field = @state.field.trimRight()
120 @state.line.push @state.field
121 @state.field = ''
122 if @state.line.length > 0
123 @emit 'row', @state.line
124 @emit 'end', null
639573d @wdavidw Split the end function into what related to the parser and the destin…
authored
125
5a3ef1b @wdavidw Externalize the parse function into a class
authored
126 Parser.prototype.error = (e) ->
127 @writable = false
128 @emit 'error', e
129
130 module.exports = (csv) -> new Parser csv
fc185c1 @wdavidw Export the Parser and Stringifier class
authored
131 module.exports.Parser = Parser
5a3ef1b @wdavidw Externalize the parse function into a class
authored
132
133
Something went wrong with that request. Please try again.