Skip to content

Commit a736b1e

Browse files
committed
use parse directly in url, without using parseString
1 parent 33cc312 commit a736b1e

3 files changed

Lines changed: 18 additions & 19 deletions

File tree

src/parser.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ export function* parse(input: string, options: ParseOptions & {
2020
quoteChar,
2121
escapeChar,
2222
} = validateAndSetDefaultParseOptions(options)
23-
// TODO(SL): allow passing no options?
2423
const ignoreLastRow = options.ignoreLastRow ?? false
2524

2625
// We don't need to compute some of these every time parse() is called,

src/url.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { fetchChunk } from './fetch'
22
import { checkIntegerGreaterOrEqualThan } from './options/check'
33
import { defaultChunkSize } from './options/constants'
44
import { type DelimiterError, type ParseOptions, validateAndGuessParseOptions } from './options/parseOptions'
5-
import { parseString } from './string'
5+
import { parse } from './parser'
66
import type { ParseResult } from './types'
77
import { testEmptyLine } from './utils'
88

@@ -12,7 +12,7 @@ interface FetchOptions {
1212
lastByte?: number
1313
requestInit?: RequestInit
1414
fetchChunk?: typeof fetchChunk
15-
parseString?: typeof parseString
15+
parse?: typeof parse
1616
}
1717
interface ParseUrlOptions extends ParseOptions, FetchOptions {
1818
skipEmptyLines?: boolean | 'greedy'
@@ -28,7 +28,7 @@ interface ParseUrlOptions extends ParseOptions, FetchOptions {
2828
* @param options.lastByte The last byte parsed (inclusive). It must be a non-negative integer. Default is the end of the file.
2929
* @param options.requestInit Optional fetch request initialization parameters.
3030
* @param options.fetchChunk Optional custom fetchChunk function for fetching chunks.
31-
* @param options.parseString Optional custom parseString function for parsing a string.
31+
* @param options.parse Optional custom parse function for parsing a string.
3232
* @param options.delimiter The delimiter used in the CSV data. Defaults to ','.
3333
* @param options.newline The newline used in the CSV data. Defaults to '\n'.
3434
* @param options.quoteChar The quote character used in the CSV data. Defaults to '"'.
@@ -96,13 +96,11 @@ export async function* parseUrl(
9696
delimiterError = result.error
9797
}
9898

99-
for (const result of (options.parseString ?? parseString)(input, {
99+
for (const result of (options.parse ?? parse)(input, {
100100
// the remaining bytes may not contain a full last row
101101
ignoreLastRow: true,
102102
// pass other options
103103
...parseOptions,
104-
// handle the empty lines here, to avoid issues when guessing delimiter/newline + to get the correct offsets
105-
skipEmptyLines: false,
106104
})) {
107105
consumedBytes += result.meta.byteCount
108106
if (consumedBytes > bytes.length) {
@@ -148,14 +146,16 @@ export async function* parseUrl(
148146
// Parse remaining bytes, if any
149147
if (bytes.length > 0) {
150148
const input = decoder.decode(bytes)
151-
for (const result of (options.parseString ?? parseString)(input, {
149+
for (const result of (options.parse ?? parse)(input, {
152150
// parse until the last byte
153151
ignoreLastRow: false,
154152
// pass other options
155153
...parseOptions,
156-
// TODO(SL): should we skip the empty lines here as well?
157-
skipEmptyLines,
158154
})) {
155+
if (skipEmptyLines && testEmptyLine(result.row, skipEmptyLines)) {
156+
// TODO(SL) how to report the skipped lines in the metadata?
157+
continue
158+
}
159159
yield {
160160
...result,
161161
meta: {

tests/url.test.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { parseUrl } from '../src/url'
55
import { toUrl } from '../src/utils'
66
import { PARSE_TESTS } from './cases'
77

8-
function* parseStringMock(input: string): Generator<ParseResult, void, unknown> {
8+
function* parseMock(input: string): Generator<ParseResult, void, unknown> {
99
const encoder = new TextEncoder()
1010
const bytes = encoder.encode(input)
1111
yield {
@@ -29,7 +29,7 @@ describe('parseUrl, while mocking parseString, ', () => {
2929
let result = ''
3030
let bytes = 0
3131
// passing 'to: fileSize - 1' for Node.js bug: https://github.com/nodejs/node/issues/60382
32-
for await (const { row, meta: { offset, byteCount } } of parseUrl(url, { chunkSize, lastByte: fileSize - 1, parseString: parseStringMock })) {
32+
for await (const { row, meta: { offset, byteCount } } of parseUrl(url, { chunkSize, lastByte: fileSize - 1, parse: parseMock })) {
3333
result += row
3434
expect(offset).toBe(bytes)
3535
bytes += byteCount
@@ -58,7 +58,7 @@ describe('parseUrl, while mocking parseString, ', () => {
5858
const { url, revoke } = toUrl(text)
5959
let result = ''
6060
// implicit assertation in the loop: no exceptions thrown
61-
for await (const { row } of parseUrl(url, { firstByte, lastByte, parseString: parseStringMock })) {
61+
for await (const { row } of parseUrl(url, { firstByte, lastByte, parse: parseMock })) {
6262
result += row[0]
6363
}
6464
revoke()
@@ -96,7 +96,7 @@ describe('parseUrl, while mocking parseString, ', () => {
9696
it('keeps bytes between iterations, and might not consume all the bytes', async () => {
9797
const text = 'hello, csvremote!!!'
9898
const { url, fileSize, revoke } = toUrl(text)
99-
function* parseStringMock(input: string) {
99+
function* parseMock(input: string) {
100100
// only yield the first two bytes, decoded as text
101101
const encoder = new TextEncoder()
102102
const bytes = encoder.encode(input)
@@ -122,7 +122,7 @@ describe('parseUrl, while mocking parseString, ', () => {
122122
for await (const { row, meta: { offset, byteCount } } of parseUrl(url, {
123123
chunkSize: 5,
124124
lastByte: fileSize - 1,
125-
parseString: parseStringMock,
125+
parse: parseMock,
126126
})) {
127127
i++
128128
result += row[0]
@@ -137,7 +137,7 @@ describe('parseUrl, while mocking parseString, ', () => {
137137
it('keeps bytes between iterations and might consume all the bytes', async () => {
138138
const text = 'hello, csvremote!!!'
139139
const { url, fileSize, revoke } = toUrl(text)
140-
function* parseStringMock(text: string) {
140+
function* parseMock(text: string) {
141141
// only process up to the first comma
142142
const splits = text.split(',')
143143
const firstPart = splits[0] + (splits.length > 1 ? ',' : '')
@@ -163,7 +163,7 @@ describe('parseUrl, while mocking parseString, ', () => {
163163
for await (const { row, meta: { offset, byteCount } } of parseUrl(url, {
164164
chunkSize: 10,
165165
lastByte: fileSize - 1,
166-
parseString: parseStringMock,
166+
parse: parseMock,
167167
})) {
168168
expect(offset).toBe(bytes)
169169
if (i === 0) {
@@ -184,7 +184,7 @@ describe('parseUrl, while mocking parseString, ', () => {
184184
it('throws if parseString yields more bytes than provided', async () => {
185185
const text = 'hello, csvremote!!!'
186186
const { url, revoke } = toUrl(text)
187-
function* parseStringMock(text: string) {
187+
function* parseMock(text: string) {
188188
// yield more bytes than provided
189189
yield {
190190
row: [],
@@ -201,7 +201,7 @@ describe('parseUrl, while mocking parseString, ', () => {
201201
}
202202
const iterator = parseUrl(url, {
203203
chunkSize: 5,
204-
parseString: parseStringMock,
204+
parse: parseMock,
205205
})
206206
await expect(iterator.next()).rejects.toThrow()
207207
revoke()

0 commit comments

Comments
 (0)