Skip to content

Commit

Permalink
io: refactor BufReader/Writer interfaces to be more idiomatic (denola…
Browse files Browse the repository at this point in the history
…nd/std#444)

Thanks Vincent Le Goff (@zekth) for porting over the CSV reader
implementation.

Fixes: denoland/std#436

Original: denoland/std@0ee6334
  • Loading branch information
piscisaureus committed May 29, 2019
1 parent 5b37b56 commit b95f79d
Show file tree
Hide file tree
Showing 14 changed files with 761 additions and 634 deletions.
47 changes: 18 additions & 29 deletions encoding/csv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// https://github.com/golang/go/blob/go1.12.5/src/encoding/csv/
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.

import { BufReader, BufState } from "../io/bufio.ts";
import { BufReader, EOF } from "../io/bufio.ts";
import { TextProtoReader } from "../textproto/mod.ts";

const INVALID_RUNE = ["\r", "\n", '"'];
Expand All @@ -25,30 +25,29 @@ export interface ParseOptions {
fieldsPerRecord?: number;
}

function chkOptions(opt: ParseOptions): Error | null {
function chkOptions(opt: ParseOptions): void {
if (
INVALID_RUNE.includes(opt.comma) ||
INVALID_RUNE.includes(opt.comment) ||
opt.comma === opt.comment
) {
return Error("Invalid Delimiter");
throw new Error("Invalid Delimiter");
}
return null;
}

export async function read(
Startline: number,
reader: BufReader,
opt: ParseOptions = { comma: ",", comment: "#", trimLeadingSpace: false }
): Promise<[string[], BufState]> {
): Promise<string[] | EOF> {
const tp = new TextProtoReader(reader);
let err: BufState;
let line: string;
let result: string[] = [];
let lineIndex = Startline;

[line, err] = await tp.readLine();

const r = await tp.readLine();
if (r === EOF) return EOF;
line = r;
// Normalize \r\n to \n on all input lines.
if (
line.length >= 2 &&
Expand All @@ -61,12 +60,12 @@ export async function read(

const trimmedLine = line.trimLeft();
if (trimmedLine.length === 0) {
return [[], err];
return [];
}

// line starting with comment character is ignored
if (opt.comment && trimmedLine[0] === opt.comment) {
return [result, err];
return [];
}

result = line.split(opt.comma);
Expand All @@ -92,12 +91,9 @@ export async function read(
}
);
if (quoteError) {
return [
[],
new ParseError(Startline, lineIndex, 'bare " in non-quoted-field')
];
throw new ParseError(Startline, lineIndex, 'bare " in non-quoted-field');
}
return [result, err];
return result;
}

export async function readAll(
Expand All @@ -107,19 +103,18 @@ export async function readAll(
trimLeadingSpace: false,
lazyQuotes: false
}
): Promise<[string[][], BufState]> {
): Promise<string[][]> {
const result: string[][] = [];
let _nbFields: number;
let err: BufState;
let lineResult: string[];
let first = true;
let lineIndex = 0;
err = chkOptions(opt);
if (err) return [result, err];
chkOptions(opt);

for (;;) {
[lineResult, err] = await read(lineIndex, reader, opt);
if (err) break;
const r = await read(lineIndex, reader, opt);
if (r === EOF) break;
lineResult = r;
lineIndex++;
// If fieldsPerRecord is 0, Read sets it to
// the number of fields in the first record
Expand All @@ -136,16 +131,10 @@ export async function readAll(

if (lineResult.length > 0) {
if (_nbFields && _nbFields !== lineResult.length) {
return [
null,
new ParseError(lineIndex, lineIndex, "wrong number of fields")
];
throw new ParseError(lineIndex, lineIndex, "wrong number of fields");
}
result.push(lineResult);
}
}
if (err !== "EOF") {
return [result, err];
}
return [result, null];
return result;
}
35 changes: 23 additions & 12 deletions encoding/csv_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -437,20 +437,31 @@ for (const t of testCases) {
if (t.LazyQuotes) {
lazyquote = t.LazyQuotes;
}
const actual = await readAll(new BufReader(new StringReader(t.Input)), {
comma: comma,
comment: comment,
trimLeadingSpace: trim,
fieldsPerRecord: fieldsPerRec,
lazyQuotes: lazyquote
});
let actual;
if (t.Error) {
assert(!!actual[1]);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const e: any = actual[1];
assertEquals(e.message, t.Error);
let err;
try {
actual = await readAll(new BufReader(new StringReader(t.Input)), {
comma: comma,
comment: comment,
trimLeadingSpace: trim,
fieldsPerRecord: fieldsPerRec,
lazyQuotes: lazyquote
});
} catch (e) {
err = e;
}
assert(err);
assertEquals(err.message, t.Error);
} else {
const expected = [t.Output, null];
actual = await readAll(new BufReader(new StringReader(t.Input)), {
comma: comma,
comment: comment,
trimLeadingSpace: trim,
fieldsPerRecord: fieldsPerRec,
lazyQuotes: lazyquote
});
const expected = t.Output;
assertEquals(actual, expected);
}
}
Expand Down
8 changes: 4 additions & 4 deletions http/file_server_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const { readFile, run } = Deno;

import { test } from "../testing/mod.ts";
import { assert, assertEquals } from "../testing/asserts.ts";
import { BufReader } from "../io/bufio.ts";
import { BufReader, EOF } from "../io/bufio.ts";
import { TextProtoReader } from "../textproto/mod.ts";

let fileServer;
Expand All @@ -22,10 +22,10 @@ async function startFileServer(): Promise<void> {
});
// Once fileServer is ready it will write to its stdout.
const r = new TextProtoReader(new BufReader(fileServer.stdout));
const [s, err] = await r.readLine();
assert(err == null);
assert(s.includes("server listening"));
const s = await r.readLine();
assert(s !== EOF && s.includes("server listening"));
}

function killFileServer(): void {
fileServer.close();
fileServer.stdout.close();
Expand Down
14 changes: 7 additions & 7 deletions http/racing_server_test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
const { dial, run } = Deno;

import { test } from "../testing/mod.ts";
import { test, runIfMain } from "../testing/mod.ts";
import { assert, assertEquals } from "../testing/asserts.ts";
import { BufReader } from "../io/bufio.ts";
import { BufReader, EOF } from "../io/bufio.ts";
import { TextProtoReader } from "../textproto/mod.ts";

let server;
Expand All @@ -13,9 +13,8 @@ async function startServer(): Promise<void> {
});
// Once fileServer is ready it will write to its stdout.
const r = new TextProtoReader(new BufReader(server.stdout));
const [s, err] = await r.readLine();
assert(err == null);
assert(s.includes("Racing server listening..."));
const s = await r.readLine();
assert(s !== EOF && s.includes("Racing server listening..."));
}
function killServer(): void {
server.close();
Expand Down Expand Up @@ -57,9 +56,10 @@ test(async function serverPipelineRace(): Promise<void> {
const outLines = output.split("\n");
// length - 1 to disregard last empty line
for (let i = 0; i < outLines.length - 1; i++) {
const [s, err] = await r.readLine();
assert(!err);
const s = await r.readLine();
assertEquals(s, outLines[i]);
}
killServer();
});

runIfMain(import.meta);
Loading

0 comments on commit b95f79d

Please sign in to comment.