Skip to content

Commit

Permalink
docs(csv): complete documentation (#4163)
Browse files Browse the repository at this point in the history
  • Loading branch information
iuioiua committed Jan 11, 2024
1 parent f5b6774 commit b1aeecf
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 25 deletions.
34 changes: 22 additions & 12 deletions csv/_io.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
import { assert } from "../assert/assert.ts";

/** Options for {@linkcode parseRecord}. */
export interface ReadOptions {
/** Character which separates values.
*
Expand Down Expand Up @@ -223,6 +224,7 @@ export class ParseError extends SyntaxError {
/** Column (rune index) where the error occurred */
column: number | null;

/** Constructs a new instance. */
constructor(
start: number,
line: number,
Expand Down Expand Up @@ -268,22 +270,30 @@ export function convertRowToObject(
return out;
}

// deno-fmt-ignore
/** Options for {@linkcode parse} and {@linkcode CsvParseStream}. */
export type ParseResult<ParseOptions, T> =
// If `columns` option is specified, the return type is Record type.
T extends ParseOptions & { columns: readonly (infer C extends string)[] }
? RecordWithColumn<C>[]
// If `skipFirstRow` option is specified, the return type is Record type.
: T extends ParseOptions & { skipFirstRow: true }
? Record<string, string | undefined>[]
// If `columns` and `skipFirstRow` option is _not_ specified, the return type is string[][].
: T extends ParseOptions & { columns?: undefined; skipFirstRow?: false | undefined }
? string[][]
// else, the return type is Record type or string[][].
: Record<string, string | undefined>[] | string[][];
// If `skipFirstRow` option is specified, the return type is Record type.
: T extends ParseOptions & { skipFirstRow: true }
? Record<string, string | undefined>[]
// If `columns` and `skipFirstRow` option is _not_ specified, the return type is string[][].
: T extends
ParseOptions & { columns?: undefined; skipFirstRow?: false | undefined }
? string[][]
// else, the return type is Record type or string[][].
: Record<string, string | undefined>[] | string[][];

// RecordWithColumn<"aaa"|"bbb"> => Record<"aaa"|"bbb", string>
// RecordWithColumn<string> => Record<string, string | undefined>
type RecordWithColumn<C extends string> = string extends C
/**
* Record type with column type.
*
* @example
* ```
* type RecordWithColumn<"aaa"|"bbb"> => Record<"aaa"|"bbb", string>
* type RecordWithColumn<string> => Record<string, string | undefined>
* ```
*/
export type RecordWithColumn<C extends string> = string extends C
? Record<string, string | undefined>
: Record<C, string>;
13 changes: 9 additions & 4 deletions csv/csv_parse_stream.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
} from "../csv/_io.ts";
import { TextDelimiterStream } from "../streams/text_delimiter_stream.ts";

/** Options for {@linkcode CsvParseStream}. */
export interface CsvParseStreamOptions extends ReadOptions {
/**
* If you provide `skipFirstRow: true` and `columns`, the first line will be
Expand Down Expand Up @@ -54,15 +55,16 @@ function stripLastCR(s: string): string {
return s.endsWith("\r") ? s.slice(0, -1) : s;
}

type RowType<T> = T extends undefined ? string[]
/** Row return type. */
export type RowType<T> = T extends undefined ? string[]
: ParseResult<CsvParseStreamOptions, T>[number];

/**
* Read data from a CSV-encoded stream or file.
* Provides an auto/custom mapper for columns.
* Read data from a CSV-encoded stream or file. Provides an auto/custom mapper
* for columns.
*
* A `CsvParseStream` expects input conforming to
* [RFC 4180](https://rfc-editor.org/rfc/rfc4180.html).
* {@link https://tools.ietf.org/html/rfc4180 | RFC 4180}.
*
* @example
* ```ts
Expand All @@ -87,6 +89,7 @@ export class CsvParseStream<

#headers: readonly string[] = [];

/** Construct a new instance. */
constructor(options?: T) {
this.#options = {
...defaultReadOptions,
Expand Down Expand Up @@ -167,10 +170,12 @@ export class CsvParseStream<
}
}

/** The instance's {@linkcode ReadableStream}. */
get readable(): ReadableStream<RowType<T>> {
return this.#readable as ReadableStream<RowType<T>>;
}

/** The instance's {@linkcode WritableStream}. */
get writable(): WritableStream<string> {
return this.#lines.writable;
}
Expand Down
2 changes: 2 additions & 0 deletions csv/csv_stringify_stream.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
import { stringify } from "./stringify.ts";

/** Options for {@linkcode CsvStringifyStream}. */
export interface CsvStringifyStreamOptions {
/**
* Delimiter used to separate values.
Expand Down Expand Up @@ -43,6 +44,7 @@ export class CsvStringifyStream<TOptions extends CsvStringifyStreamOptions>
: Array<unknown>,
string
> {
/** Construct a new instance. */
constructor(options?: TOptions) {
const {
separator,
Expand Down
2 changes: 1 addition & 1 deletion csv/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
/** Reads and writes comma-separated values (CSV) files.
*
* There are many kinds of CSV files; this module supports the format described
* in [RFC 4180](https://www.rfc-editor.org/rfc/rfc4180.html).
* in {@link https://tools.ietf.org/html/rfc4180 | RFC 4180}.
*
* A csv file contains zero or more records of one or more fields per record.
* Each record is separated by the newline character. The final record may
Expand Down
27 changes: 26 additions & 1 deletion csv/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ import {
ParseError,
type ParseResult,
type ReadOptions,
type RecordWithColumn,
} from "./_io.ts";
import { assert } from "../assert/assert.ts";

export { ParseError, type ParseResult, ReadOptions };
export { ParseError, type ParseResult, ReadOptions, type RecordWithColumn };

const BYTE_ORDER_MARK = "\ufeff";

Expand Down Expand Up @@ -280,6 +281,7 @@ class Parser {
}
}

/** Options for {@linkcode parse}. */
export interface ParseOptions extends ReadOptions {
/**
* If you provide `skipFirstRow: true` and `columns`, the first line will be
Expand Down Expand Up @@ -317,6 +319,29 @@ export interface ParseOptions extends ReadOptions {
* If you provide `opt.skipFirstRow` or `opt.columns`, it returns `Record<string, unknown>[]`.
*/
export function parse(input: string, opt?: undefined): string[][];
/**
* Csv parse helper to manipulate data.
* Provides an auto/custom mapper for columns.
*
* @example
* ```ts
* import { parse } from "https://deno.land/std@$STD_VERSION/csv/parse.ts";
* const string = "a,b,c\nd,e,f";
*
* console.log(
* await parse(string, {
* skipFirstRow: false,
* }),
* );
* // output:
* // [["a", "b", "c"], ["d", "e", "f"]]
* ```
*
* @param input Input to parse.
* @param opt options of the parser.
* @returns If you don't provide `opt.skipFirstRow` and `opt.columns`, it returns `string[][]`.
* If you provide `opt.skipFirstRow` or `opt.columns`, it returns `Record<string, unknown>[]`.
*/
export function parse<const T extends ParseOptions>(
input: string,
opt: T,
Expand Down
20 changes: 13 additions & 7 deletions csv/stringify.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
// This module is browser compatible.

type PropertyAccessor = number | string;
type ObjectWithStringPropertyKeys = Record<string, unknown>;
/** Array index or record key corresponding to a value for a data object. */
export type PropertyAccessor = number | string;

/**
* Column information.
*
* @param header Explicit column header name. If omitted,
* the (final) property accessor is used for this value.
*
Expand Down Expand Up @@ -82,8 +84,9 @@ export type ColumnDetails = {
export type Column = ColumnDetails | PropertyAccessor | PropertyAccessor[];

/** An object (plain or array) */
export type DataItem = ObjectWithStringPropertyKeys | unknown[];
export type DataItem = Record<string, unknown> | unknown[];

/** Options for {@linkcode stringify}. */
export type StringifyOptions = {
/** Whether to include the row of headers or not.
*
Expand Down Expand Up @@ -165,8 +168,13 @@ function normalizeColumn(column: Column): NormalizedColumn {
return { header, prop };
}

/** Error thrown in {@linkcode stringify}. */
export class StringifyError extends Error {
override readonly name = "StringifyError";
/** Construct a new instance. */
constructor(message?: string) {
super(message);
this.name = "StringifyError";
}
}

/**
Expand All @@ -193,7 +201,7 @@ function getValuesFromItem(
);
}
} // I think this assertion is safe. Confirm?
else value = (value as ObjectWithStringPropertyKeys)[prop];
else value = (value as Record<string, unknown>)[prop];
}

values.push(value);
Expand Down Expand Up @@ -273,8 +281,6 @@ function getValuesFromItem(
* // Rick,70
* // Morty,14
* ```
*
* @param options Output formatting options
*/
export function stringify(
data: DataItem[],
Expand Down

0 comments on commit b1aeecf

Please sign in to comment.