Skip to content

Commit

Permalink
feat(table): support any kind of data and add cellValue, `cellRende…
Browse files Browse the repository at this point in the history
…rer`, `headerValue` and `headerRenderer` options
  • Loading branch information
c4spar committed Mar 12, 2023
1 parent 738355a commit 9dc20cc
Show file tree
Hide file tree
Showing 10 changed files with 794 additions and 187 deletions.
95 changes: 95 additions & 0 deletions examples/table/datatable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#!/usr/bin/env -S deno run

import { colors } from "../../ansi/colors.ts";
import { Table } from "../../table/table.ts";

new Table()
.data([
{
firstName: "Gino",
lastName: "Aicheson",
age: 21,
email: "[email protected]",
},
{
firstName: "Godfry",
lastName: "Pedycan",
age: 33,
email: "[email protected]",
},
{
firstName: "Loni",
lastName: "Miller",
age: 24,
email: "[email protected]",
},
])
.headerRenderer(colors.bold)
.columns([{
header: "Name",
cellValue: ({ firstName, lastName }) => `${firstName} ${lastName}`,
cellRenderer: colors.brightBlue.bold,
}, {
field: "age",
header: "Age",
align: "right",
cellRenderer: colors.yellow,
}, {
field: "email",
header: "Email",
minWidth: 20,
align: "center",
cellRenderer: colors.cyan.italic,
}])
.border()
.render();

// new Table()
// // .cellValue(value => (value + " 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123").trim())
// // .cellRenderer(value => colors.bold.magenta(value))
// // .header([1, "12"])
// .header("123")
// .fillRows()
// // .header(["123", new Cell(""), 3])
// .body([
// // foo1,
// // foo2,
// // new Cell("foo"),
// // new Row(new Cell("foo"), new Cell("bar"))
// // { name: "foo", age: 21, email: "foo@example.com" },
// // ["foo", "ff", "gggg"],
// { name: "bar", age: 33, email: "bar@example.com" },
// { name: "baz", age: 24, email: "baz@example.com" },
// // [{ name: "foo", age: 21, email: "foo@example.com" }],
// // [{ name: "bar", age: 33, email: "bar@example.com" }],
// // [{ name: "baz", age: 24, email: "baz@example.com" }],
// // ["foo"],
// // [undefined],
// ])
// // .fromJson([{foo: 1, bar: "2"}])
// .columns([{
// field: "name",
// // header: "Name",
// border: true,
// maxWidth: 10,
// }, {
// // field: "age",
// // header: "Age",
// minWidth: 10,
// maxWidth: 15,
// align: "center",
// // headerValue: (value) => value?.toString().toUpperCase(),
// headerValue: (value) => "value.age" ?? "-",
// cellValue: (value) => value.age ?? "-",
// // headerRenderer: colors.yellow,
// // cellRenderer: colors.blue,
// }, {
// // field: "email",
// // header: "Email",
// border: true,
// maxWidth: 10,
// align: "right",
// // headerValue: (value) => value?.toString().toUpperCase(),
// // cellRenderer: colors.green,
// }])
// .render();
107 changes: 85 additions & 22 deletions table/cell.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,39 @@
export type CellValue = unknown;

/** Cell type */
// deno-lint-ignore ban-types
export type ICell = number | string | String | Cell;
export type CellOrValue<TValue extends CellValue> =
| TValue
| Cell<TValue>;

export type GetCellValue<TCell extends CellOrValue<CellValue>> = TCell extends
infer TCell ? TCell extends Cell<infer Value> ? Value
: TCell
: never;

export type Direction = "left" | "right" | "center";

export type ValueParserResult = string | number | undefined | null;

export type ValueParser<in out TValue extends CellValue> = (
value: TValue,
) => ValueParserResult;

export type Renderer = (value: string) => string;

/** Cell options. */
export interface ICellOptions {
export interface CellOptions<TValue extends CellValue> {
border?: boolean;
colSpan?: number;
rowSpan?: number;
align?: Direction;
// value?: ValueParser<TValue>;
value?(value: TValue): ValueParserResult;
render?: Renderer;
}

/** Cell representation. */
export class Cell {
protected options: ICellOptions = {};
export class Cell<TValue extends CellValue = CellValue> {
protected options: CellOptions<TValue> = {};

/** Get cell length. */
public get length(): number {
Expand All @@ -26,41 +45,54 @@ export class Cell {
* will be copied to the new cell.
* @param value Cell or cell value.
*/
public static from(value: ICell): Cell {
const cell = new this(value);
public static from<TValue extends CellValue>(
value: CellOrValue<TValue>,
): Cell<TValue> {
if (value instanceof Cell) {
const cell = new this(value.getValue());
cell.options = { ...value.options };
return cell;
}
return cell;

return new this(value);
}

/**
* Cell constructor.
* @param value Cell value.
* @param cellValue Cell value.
*/
public constructor(private value: ICell) {}
public constructor(
private cellValue?: TValue | undefined | null,
) {}

/** Get cell value. */
/** Get cell string value. */
public toString(): string {
return this.value.toString();
return this.cellValue?.toString() ?? "";
}

/** Get cell value. */
public getValue(): TValue | undefined | null {
return this.cellValue;
}

/**
* Set cell value.
* @param value Cell or cell value.
*/
public setValue(value: ICell): this {
this.value = value;
public setValue(value: TValue | undefined | null): this {
this.cellValue = value;
return this;
}

/**
* Clone cell with all options.
* @param value Cell or cell value.
*/
public clone(value?: ICell): Cell {
const cell = new Cell(value ?? this);
cell.options = { ...this.options };
public clone<TCloneValue extends CellValue = TValue>(
value: TCloneValue = this.getValue() as TCloneValue,
): Cell<TCloneValue> {
const cell = new Cell(value);
cell.options = { ...this.options } as CellOptions<TCloneValue>;
return cell;
}

Expand Down Expand Up @@ -116,13 +148,31 @@ export class Cell {
return this;
}

/**
* Register cell value parser.
* @param fn Value parser callback function.
*/
public value(fn: ValueParser<TValue>): this {
this.options.value = fn;
return this;
}

/**
* Register cell renderer. Will be called once for each line in the cell.
* @param fn Cell renderer callback function.
*/
public renderer(fn: Renderer): this {
this.options.render = fn;
return this;
}

/**
* Getter:
*/

/** Check if cell has border. */
public getBorder(): boolean {
return this.options.border === true;
public getBorder(): boolean | undefined {
return this.options.border;
}

/** Get col span. */
Expand All @@ -139,8 +189,21 @@ export class Cell {
: 1;
}

/** Get row span. */
public getAlign(): Direction {
return this.options.align ?? "left";
/** Get cell alignment. */
public getAlign(): Direction | undefined {
return this.options.align;
}

/** Get value parser. */
// public getValueParser(): ValueParser<TValue> | undefined {
public getValueParser<TParserValue extends TValue>():
| ValueParser<TParserValue>
| undefined {
return this.options.value;
}

/** Get cell renderer. */
public getRenderer(): Renderer | undefined {
return this.options.render;
}
}
Loading

0 comments on commit 9dc20cc

Please sign in to comment.