Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs(csv): complete documentation #4163

Merged
merged 1 commit into from
Jan 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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