Skip to content

fix(csv): add columns options type for array items #6363

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

Closed
wants to merge 14 commits into from
141 changes: 110 additions & 31 deletions csv/unstable_stringify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,43 @@ export type ColumnDetails = {
*/
export type Column = ColumnDetails | PropertyAccessor | PropertyAccessor[];

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

/** Options for {@linkcode stringify}. */
export type StringifyOptions = {
/** Options for {@linkcode stringify} with an array of of arrays as data. */
export type ArrayStringifyOptions = {
/** Whether to include the row of headers or not.
*
* @default {true}
*/
headers?: boolean;
/**
* Delimiter used to separate values. Examples:
* - `","` _comma_
* - `"\t"` _tab_
* - `"|"` _pipe_
* - etc.
*
* @default {","}
*/
separator?: string;
/**
* A list of instructions for how to target and transform the data for each
* column of output. This is also where you can provide an explicit header
* name for the column.
*
* @default {undefined}
*/
columns?: readonly number[] | undefined;
/**
* Whether to add a
* {@link https://en.wikipedia.org/wiki/Byte_order_mark | byte-order mark} to the
* beginning of the file content. Required by software such as MS Excel to
* properly display Unicode text.
*
* @default {false}
*/
bom?: boolean;
};
/** Options for {@linkcode stringify} with an array of of objects as data. */
export type ObjectStringifyOptions = {
/** Whether to include the row of headers or not.
*
* @default {true}
Expand Down Expand Up @@ -123,21 +155,23 @@ export type StringifyOptions = {
*/
bom?: boolean;
};
/** Options for {@linkcode stringify}. */
export type StringifyOptions = ArrayStringifyOptions | ObjectStringifyOptions;

/**
* Converts an array of objects into a CSV string.
*
* @example Default options
* @example Give an array of objects without specifying columns
* ```ts
* import { stringify } from "@std/csv/unstable-stringify";
* import { assertEquals } from "@std/assert/equals";
*
* const data = [
* ["Rick", 70],
* ["Morty", 14],
* { name: "Rick", age: 70 },
* { name: "Morty", age: 14 },
* ];
*
* assertEquals(stringify(data), `Rick,70\r\nMorty,14\r\n`);
* assertEquals(stringify(data), `name,age\r\nRick,70\r\nMorty,14\r\n`);
* ```
*
* @example Give an array of objects and specify columns
Expand All @@ -155,19 +189,6 @@ export type StringifyOptions = {
* assertEquals(stringify(data, { columns }), `name,age\r\nRick,70\r\nMorty,14\r\n`);
* ```
*
* @example Give an array of objects without specifying columns
* ```ts
* import { stringify } from "@std/csv/unstable-stringify";
* import { assertEquals } from "@std/assert/equals";
*
* const data = [
* { name: "Rick", age: 70 },
* { name: "Morty", age: 14 },
* ];
*
* assertEquals(stringify(data), `name,age\r\nRick,70\r\nMorty,14\r\n`);
* ```
*
* @example Give an array of objects and specify columns with `headers: false`
* ```ts
* import { stringify } from "@std/csv/unstable-stringify";
Expand All @@ -178,10 +199,8 @@ export type StringifyOptions = {
* { name: "Morty", age: 14 },
* ];
*
* const columns = ["name", "age"];
*
* assertEquals(
* stringify(data, { columns, headers: false }),
* stringify(data, { headers: false }),
* `Rick,70\r\nMorty,14\r\n`,
* );
* ```
Expand Down Expand Up @@ -280,9 +299,21 @@ export type StringifyOptions = {
* );
* ```
*
* @param data The source data to stringify. It's an array of items which are
* plain objects or arrays.
* @param options Options for the stringification.
* @returns A CSV string.
*/
export function stringify(
data: Record<string, unknown>[],
options?: ObjectStringifyOptions,
): string;
/**
* Converts an array of arrays into a CSV string.
*
* @example Give an array of string arrays and specify columns with renaming
* ```ts
* import { stringify } from "@std/csv/unstable-stringify";
* import { stringify } from "@std/csv/stringify";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this example doesn't pass type checking anymore. Why do you change the specifier here to the stable version?

* import { assertEquals } from "@std/assert/equals";
*
* const data = [
Expand All @@ -303,7 +334,7 @@ export type StringifyOptions = {
*
* @example Emit TSV (tab-separated values) with `separator: "\t"`
* ```ts
* import { stringify } from "@std/csv/unstable-stringify";
* import { stringify } from "@std/csv/stringify";
* import { assertEquals } from "@std/assert/equals";
*
* const data = [
Expand All @@ -316,7 +347,7 @@ export type StringifyOptions = {
*
* @example Prepend a byte-order mark with `bom: true`
* ```ts
* import { stringify } from "@std/csv/unstable-stringify";
* import { stringify } from "@std/csv/stringify";
* import { assertEquals } from "@std/assert/equals";
*
* const data = [["Rick", 70]];
Expand All @@ -330,8 +361,54 @@ export type StringifyOptions = {
* @returns A CSV string.
*/
export function stringify(
data: readonly DataItem[],
options?: StringifyOptions,
data: unknown[][],
options?: ArrayStringifyOptions,
): string;
/**
* Converts an array of objects or arrays into a CSV string.
*
* @example Give an array of objects without specifying columns
* ```ts
* import { stringify } from "@std/csv/unstable-stringify";
* import { assertEquals } from "@std/assert/equals";
*
* const data = [
* { name: "Rick", age: 70 },
* { name: "Morty", age: 14 },
* ];
*
* assertEquals(stringify(data), `name,age\r\nRick,70\r\nMorty,14\r\n`);
* ```
*
* @example Give an array of string arrays and specify columns with renaming
* ```ts
* import { stringify } from "@std/csv/stringify";
* import { assertEquals } from "@std/assert/equals";
*
* const data = [
* ["Rick", 70],
* ["Morty", 14],
* ];
*
* const columns = [
* { prop: 0, header: "name" },
* { prop: 1, header: "age" },
* ];
*
* assertEquals(
* stringify(data, { columns }),
* `name,age\r\nRick,70\r\nMorty,14\r\n`,
* );
* ```
*
* @param data The source data to stringify. It's an array of items which are
* plain objects or arrays.
* @param options Options for the stringification.
* @returns A CSV string.
*/
export function stringify(
data: unknown[][] | Record<string, unknown>[],
options?: StringifyOptions | ArrayStringifyOptions,
): string {
let { columns } = options ?? {};

Expand All @@ -349,7 +426,9 @@ export function stringify(
/**
* Infers the columns from the first object element of the given array.
*/
function inferColumns(data: readonly DataItem[]): string[] {
function inferColumns(
data: unknown[][] | Record<string, unknown>[],
): string[] {
const firstElement = data.at(0);
if (
firstElement &&
Expand Down
Loading