Skip to content

Commit

Permalink
feat(std/encoding/csv): Add stringify functionality (denoland#8408)
Browse files Browse the repository at this point in the history
  • Loading branch information
jsejcksn authored Nov 25, 2020
1 parent d40b071 commit ed11eb6
Show file tree
Hide file tree
Showing 4 changed files with 737 additions and 6 deletions.
189 changes: 183 additions & 6 deletions std/encoding/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,24 @@ writeVarbig(w: Deno.Writer, x: bigint, o: VarbigOptions = {}): Promise<number>

### API

#### `readMatrix(reader: BufReader, opt: ReadOptions = { comma: ",", trimLeadingSpace: false, lazyQuotes: false }): Promise<string[][]>`
#### `readMatrix`

```ts
(reader: BufReader, opt: ReadOptions = {
comma: ",",
trimLeadingSpace: false,
lazyQuotes: false,
}): Promise<string[][]>
```
Parse the CSV from the `reader` with the options provided and return
`string[][]`.
#### `parse(input: string | BufReader, opt: ParseOptions = { skipFirstRow: false }): Promise<unknown[]>`:
#### `parse`
```ts
(input: string | BufReader, opt: ParseOptions = { skipFirstRow: false }): Promise<unknown[]>
```
Parse the CSV string/buffer with the options provided. The result of this
function is as follows:
Expand Down Expand Up @@ -70,16 +82,120 @@ function is as follows:
##### `ReadOptions`
- **`comma?: string;`**: Character which separates values. Default: `','`.
- **`comment?: string;`**: Character to start a comment. Default: `'#'`.
- **`comma?: string;`**: Character which separates values. Default: `","`.
- **`comment?: string;`**: Character to start a comment. Default: `"#"`.
- **`trimLeadingSpace?: boolean;`**: Flag to trim the leading space of the
value. Default: `false`.
- **`lazyQuotes?: boolean;`**: Allow unquoted quote in a quoted field or non
double quoted quotes in quoted field. Default: `false`.
- **`fieldsPerRecord?`**: Enabling the check of fields for each row. If == 0,
first row is used as referral for the number of fields.
### Usage
#### `stringify`
```ts
(data: DataItem[], columns: Column[], options?: StringifyOptions): Promise<string>
```
- **`data`** is the source data to stringify. It's an array of items which are
plain objects or arrays.
`DataItem: Record<string, unknown> | unknown[]`
```ts
const data = [
{
name: "Deno",
repo: { org: "denoland", name: "deno" },
runsOn: ["Rust", "TypeScript"],
},
];
```
- **`columns`** is 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.
`Column`:
- The most essential aspect of a column is accessing the property holding the
data for that column on each object in the data array. If that member is at
the top level, `Column` can simply be a property accessor, which is either a
`string` (if it's a plain object) or a `number` (if it's an array).
```ts
const columns = [
"name",
];
```
Each property accessor will be used as the header for the column:
| name |
| :--: |
| Deno |
- If the required data is not at the top level (it's nested in other
objects/arrays), then a simple property accessor won't work, so an array of
them will be required.
```ts
const columns = [
["repo", "name"],
["repo", "org"],
];
```
When using arrays of property accessors, the header names inherit the value
of the last accessor in each array:
| name | org |
| :--: | :------: |
| deno | denoland |
- If the data is not already in the required output format, or a different
column header is desired, then a `ColumnDetails` object type can be used for
each column:
- **`fn?: (value: any) => string | Promise<string>`** is an optional
function to transform the targeted data into the desired format
- **`header?: string`** is the optional value to use for the column header
name
- **`prop: PropertyAccessor | PropertyAccessor[]`** is the property accessor
(`string` or `number`) or array of property accessors used to access the
data on each object
```ts
const columns = [
"name",
{
prop: ["runsOn", 0],
header: "language 1",
fn: (str: string) => str.toLowerCase(),
},
{
prop: ["runsOn", 1],
header: "language 2",
fn: (str: string) => str.toLowerCase(),
},
];
```

| name | language 1 | language 2 |
| :--: | :--------: | :--------: |
| Deno | rust | typescript |

- **`options`** are options for the delimiter-seprated output.

- **`headers?: boolean`**: Whether or not to include the row of headers.
Default: `true`

- **`separator?: string`**: Delimiter used to separate values. Examples:
- `","` _comma_ (Default)
- `"\t"` _tab_
- `"|"` _pipe_
- etc.

### Basic Usage

```ts
import { parse } from "https://deno.land/std@$STD_VERSION/encoding/csv.ts";
Expand All @@ -94,6 +210,67 @@ console.log(
// [["a", "b", "c"], ["d", "e", "f"]]
```

```ts
import {
Column,
stringify,
} from "https://deno.land/std@$STD_VERSION/encoding/csv.ts";
type Character = {
age: number;
name: {
first: string;
last: string;
};
};
const data: Character[] = [
{
age: 70,
name: {
first: "Rick",
last: "Sanchez",
},
},
{
age: 14,
name: {
first: "Morty",
last: "Smith",
},
},
];
let columns: Column[] = [
["name", "first"],
"age",
];
console.log(await stringify(data, columns));
// first,age
// Rick,70
// Morty,14
//
columns = [
{
prop: "name",
fn: (name: Character["name"]) => `${name.first} ${name.last}`,
},
{
prop: "age",
header: "is_adult",
fn: (age: Character["age"]) => String(age >= 18),
},
];
console.log(await stringify(data, columns, { separator: "\t" }));
// name is_adult
// Rick Sanchez true
// Morty Smith false
//
```

## TOML

This module parse TOML files. It follows as much as possible the
Expand Down Expand Up @@ -231,7 +408,7 @@ console.log(tomlObject);

YAML parser / dumper for Deno.

Heavily inspired from [js-yaml].
Heavily inspired from [`js-yaml`](https://github.com/nodeca/js-yaml).

### Basic usage

Expand Down
9 changes: 9 additions & 0 deletions std/encoding/csv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,15 @@ import { TextProtoReader } from "../textproto/mod.ts";
import { StringReader } from "../io/readers.ts";
import { assert } from "../_util/assert.ts";

export { NEWLINE, stringify, StringifyError } from "./csv_stringify.ts";

export type {
Column,
ColumnDetails,
DataItem,
StringifyOptions,
} from "./csv_stringify.ts";

const INVALID_RUNE = ["\r", "\n", '"'];

export const ERR_BARE_QUOTE = 'bare " in non-quoted-field';
Expand Down
Loading

0 comments on commit ed11eb6

Please sign in to comment.