2
2
// https://github.com/golang/go/blob/master/LICENSE
3
3
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
4
4
5
+ // This module is browser compatible.
6
+
5
7
/** Port of the Go
6
8
* [encoding/csv](https://github.com/golang/go/blob/go1.12.5/src/encoding/csv/)
7
9
* library.
8
10
*
9
11
* @module
10
12
*/
11
13
12
- import { BufReader } from "../io/buffer.ts" ;
13
- import { TextProtoReader } from "../textproto/mod.ts" ;
14
- import { StringReader } from "../io/readers.ts" ;
15
14
import { assert } from "../_util/assert.ts" ;
16
- import {
17
- ERR_FIELD_COUNT ,
18
- ERR_INVALID_DELIM ,
19
- ParseError ,
20
- readRecord ,
21
- } from "./csv/_io.ts" ;
22
- import type { LineReader , ReadOptions } from "./csv/_io.ts" ;
15
+ import type { ReadOptions } from "./csv/_io.ts" ;
16
+ import { Parser } from "./csv/_parser.ts" ;
23
17
24
18
export {
25
19
ERR_BARE_QUOTE ,
@@ -38,111 +32,6 @@ export type {
38
32
StringifyOptions ,
39
33
} from "./csv_stringify.ts" ;
40
34
41
- class TextProtoLineReader implements LineReader {
42
- #tp: TextProtoReader ;
43
- constructor ( bufReader : BufReader ) {
44
- this . #tp = new TextProtoReader ( bufReader ) ;
45
- }
46
-
47
- async readLine ( ) {
48
- let line : string ;
49
- const r = await this . #tp. readLine ( ) ;
50
- if ( r === null ) return null ;
51
- line = r ;
52
-
53
- // For backwards compatibility, drop trailing \r before EOF.
54
- if (
55
- ( await this . isEOF ( ) ) && line . length > 0 && line [ line . length - 1 ] === "\r"
56
- ) {
57
- line = line . substring ( 0 , line . length - 1 ) ;
58
- }
59
-
60
- // Normalize \r\n to \n on all input lines.
61
- if (
62
- line . length >= 2 &&
63
- line [ line . length - 2 ] === "\r" &&
64
- line [ line . length - 1 ] === "\n"
65
- ) {
66
- line = line . substring ( 0 , line . length - 2 ) ;
67
- line = line + "\n" ;
68
- }
69
-
70
- return line ;
71
- }
72
-
73
- async isEOF ( ) {
74
- return ( await this . #tp. r . peek ( 0 ) ) === null ;
75
- }
76
- }
77
-
78
- const INVALID_RUNE = [ "\r" , "\n" , '"' ] ;
79
-
80
- function chkOptions ( opt : ReadOptions ) : void {
81
- if ( ! opt . separator ) {
82
- opt . separator = "," ;
83
- }
84
- if ( ! opt . trimLeadingSpace ) {
85
- opt . trimLeadingSpace = false ;
86
- }
87
- if (
88
- INVALID_RUNE . includes ( opt . separator ) ||
89
- ( typeof opt . comment === "string" && INVALID_RUNE . includes ( opt . comment ) ) ||
90
- opt . separator === opt . comment
91
- ) {
92
- throw new Error ( ERR_INVALID_DELIM ) ;
93
- }
94
- }
95
-
96
- /**
97
- * Parse the CSV from the `reader` with the options provided and return `string[][]`.
98
- *
99
- * @param reader provides the CSV data to parse
100
- * @param opt controls the parsing behavior
101
- */
102
- export async function readMatrix (
103
- reader : BufReader ,
104
- opt : ReadOptions = {
105
- separator : "," ,
106
- trimLeadingSpace : false ,
107
- lazyQuotes : false ,
108
- } ,
109
- ) : Promise < string [ ] [ ] > {
110
- const result : string [ ] [ ] = [ ] ;
111
- let _nbFields : number | undefined ;
112
- let lineResult : string [ ] ;
113
- let first = true ;
114
- let lineIndex = 0 ;
115
- chkOptions ( opt ) ;
116
-
117
- const lineReader = new TextProtoLineReader ( reader ) ;
118
- for ( ; ; ) {
119
- const r = await readRecord ( lineIndex , lineReader , opt ) ;
120
- if ( r === null ) break ;
121
- lineResult = r ;
122
- lineIndex ++ ;
123
- // If fieldsPerRecord is 0, Read sets it to
124
- // the number of fields in the first record
125
- if ( first ) {
126
- first = false ;
127
- if ( opt . fieldsPerRecord !== undefined ) {
128
- if ( opt . fieldsPerRecord === 0 ) {
129
- _nbFields = lineResult . length ;
130
- } else {
131
- _nbFields = opt . fieldsPerRecord ;
132
- }
133
- }
134
- }
135
-
136
- if ( lineResult . length > 0 ) {
137
- if ( _nbFields && _nbFields !== lineResult . length ) {
138
- throw new ParseError ( lineIndex , lineIndex , null , ERR_FIELD_COUNT ) ;
139
- }
140
- result . push ( lineResult ) ;
141
- }
142
- }
143
- return result ;
144
- }
145
-
146
35
/**
147
36
* Parse the CSV string/buffer with the options provided.
148
37
*
@@ -173,46 +62,43 @@ export interface ParseOptions extends ReadOptions {
173
62
/**
174
63
* Csv parse helper to manipulate data.
175
64
* Provides an auto/custom mapper for columns.
176
- * @param input Input to parse. Can be a string or BufReader.
65
+ * @param input Input to parse.
177
66
* @param opt options of the parser.
178
67
* @returns If you don't provide `opt.skipFirstRow` and `opt.columns`, it returns `string[][]`.
179
68
* If you provide `opt.skipFirstRow` or `opt.columns`, it returns `Record<string, unkown>[]`.
180
69
*/
181
- export async function parse (
182
- input : string | BufReader ,
183
- ) : Promise < string [ ] [ ] > ;
184
- export async function parse (
185
- input : string | BufReader ,
70
+ export function parse (
71
+ input : string ,
72
+ ) : string [ ] [ ] ;
73
+ export function parse (
74
+ input : string ,
186
75
opt : Omit < ParseOptions , "columns" | "skipFirstRow" > ,
187
- ) : Promise < string [ ] [ ] > ;
188
- export async function parse (
189
- input : string | BufReader ,
76
+ ) : string [ ] [ ] ;
77
+ export function parse (
78
+ input : string ,
190
79
opt : Omit < ParseOptions , "columns" > & {
191
80
columns : string [ ] | ColumnOptions [ ] ;
192
81
} ,
193
- ) : Promise < Record < string , unknown > [ ] > ;
194
- export async function parse (
195
- input : string | BufReader ,
82
+ ) : Record < string , unknown > [ ] ;
83
+ export function parse (
84
+ input : string ,
196
85
opt : Omit < ParseOptions , "skipFirstRow" > & {
197
86
skipFirstRow : true ;
198
87
} ,
199
- ) : Promise < Record < string , unknown > [ ] > ;
200
- export async function parse (
201
- input : string | BufReader ,
88
+ ) : Record < string , unknown > [ ] ;
89
+ export function parse (
90
+ input : string ,
202
91
opt : ParseOptions ,
203
- ) : Promise < string [ ] [ ] | Record < string , unknown > [ ] > ;
204
- export async function parse (
205
- input : string | BufReader ,
92
+ ) : string [ ] [ ] | Record < string , unknown > [ ] ;
93
+ export function parse (
94
+ input : string ,
206
95
opt : ParseOptions = {
207
96
skipFirstRow : false ,
208
97
} ,
209
- ) : Promise < string [ ] [ ] | Record < string , unknown > [ ] > {
210
- let r : string [ ] [ ] ;
211
- if ( input instanceof BufReader ) {
212
- r = await readMatrix ( input , opt ) ;
213
- } else {
214
- r = await readMatrix ( new BufReader ( new StringReader ( input ) ) , opt ) ;
215
- }
98
+ ) : string [ ] [ ] | Record < string , unknown > [ ] {
99
+ const parser = new Parser ( opt ) ;
100
+ const r = parser . parse ( input ) ;
101
+
216
102
if ( opt . skipFirstRow || opt . columns ) {
217
103
let headers : ColumnOptions [ ] = [ ] ;
218
104
let i = 0 ;
0 commit comments