Skip to content

Commit ee31499

Browse files
committed
feat(table): support any kind of data and add cellValue, cellRenderer, headerValue and headerRenderer options
1 parent 738355a commit ee31499

File tree

10 files changed

+744
-187
lines changed

10 files changed

+744
-187
lines changed

examples/table/datatable.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#!/usr/bin/env -S deno run
2+
3+
import { colors } from "../../ansi/colors.ts";
4+
import { Table } from "../../table/table.ts";
5+
6+
new Table()
7+
.data([
8+
{
9+
firstName: "Gino",
10+
lastName: "Aicheson",
11+
age: 21,
12+
13+
},
14+
{
15+
firstName: "Godfry",
16+
lastName: "Pedycan",
17+
age: 33,
18+
19+
},
20+
{
21+
firstName: "Loni",
22+
lastName: "Miller",
23+
age: 24,
24+
25+
},
26+
])
27+
.headerRenderer(colors.bold)
28+
.columns([{
29+
header: "Name",
30+
cellValue: ({ firstName, lastName }) => `${firstName} ${lastName}`,
31+
cellRenderer: colors.brightBlue.bold,
32+
}, {
33+
field: "age",
34+
header: "Age",
35+
align: "right",
36+
cellRenderer: colors.yellow,
37+
}, {
38+
field: "email",
39+
header: "Email",
40+
minWidth: 20,
41+
align: "center",
42+
cellRenderer: colors.cyan.italic,
43+
}])
44+
.border()
45+
.render();

table/cell.ts

Lines changed: 85 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,39 @@
1+
export type CellValue = unknown;
2+
13
/** Cell type */
2-
// deno-lint-ignore ban-types
3-
export type ICell = number | string | String | Cell;
4+
export type CellOrValue<TValue extends CellValue> =
5+
| TValue
6+
| Cell<TValue>;
7+
8+
export type GetCellValue<TCell extends CellOrValue<CellValue>> = TCell extends
9+
infer TCell ? TCell extends Cell<infer Value> ? Value
10+
: TCell
11+
: never;
412

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

15+
export type ValueParserResult = string | number | undefined | null;
16+
17+
export type ValueParser<in out TValue extends CellValue> = (
18+
value: TValue,
19+
) => ValueParserResult;
20+
21+
export type Renderer = (value: string) => string;
22+
723
/** Cell options. */
8-
export interface ICellOptions {
24+
export interface CellOptions<TValue extends CellValue> {
925
border?: boolean;
1026
colSpan?: number;
1127
rowSpan?: number;
1228
align?: Direction;
29+
// value?: ValueParser<TValue>;
30+
value?(value: TValue): ValueParserResult;
31+
render?: Renderer;
1332
}
1433

1534
/** Cell representation. */
16-
export class Cell {
17-
protected options: ICellOptions = {};
35+
export class Cell<TValue extends CellValue = CellValue> {
36+
protected options: CellOptions<TValue> = {};
1837

1938
/** Get cell length. */
2039
public get length(): number {
@@ -26,41 +45,54 @@ export class Cell {
2645
* will be copied to the new cell.
2746
* @param value Cell or cell value.
2847
*/
29-
public static from(value: ICell): Cell {
30-
const cell = new this(value);
48+
public static from<TValue extends CellValue>(
49+
value: CellOrValue<TValue>,
50+
): Cell<TValue> {
3151
if (value instanceof Cell) {
52+
const cell = new this(value.getValue());
3253
cell.options = { ...value.options };
54+
return cell;
3355
}
34-
return cell;
56+
57+
return new this(value);
3558
}
3659

3760
/**
3861
* Cell constructor.
39-
* @param value Cell value.
62+
* @param cellValue Cell value.
4063
*/
41-
public constructor(private value: ICell) {}
64+
public constructor(
65+
private cellValue?: TValue | undefined | null,
66+
) {}
4267

43-
/** Get cell value. */
68+
/** Get cell string value. */
4469
public toString(): string {
45-
return this.value.toString();
70+
return this.cellValue?.toString() ?? "";
71+
}
72+
73+
/** Get cell value. */
74+
public getValue(): TValue | undefined | null {
75+
return this.cellValue;
4676
}
4777

4878
/**
4979
* Set cell value.
5080
* @param value Cell or cell value.
5181
*/
52-
public setValue(value: ICell): this {
53-
this.value = value;
82+
public setValue(value: TValue | undefined | null): this {
83+
this.cellValue = value;
5484
return this;
5585
}
5686

5787
/**
5888
* Clone cell with all options.
5989
* @param value Cell or cell value.
6090
*/
61-
public clone(value?: ICell): Cell {
62-
const cell = new Cell(value ?? this);
63-
cell.options = { ...this.options };
91+
public clone<TCloneValue extends CellValue = TValue>(
92+
value: TCloneValue = this.getValue() as TCloneValue,
93+
): Cell<TCloneValue> {
94+
const cell = new Cell(value);
95+
cell.options = { ...this.options } as CellOptions<TCloneValue>;
6496
return cell;
6597
}
6698

@@ -116,13 +148,31 @@ export class Cell {
116148
return this;
117149
}
118150

151+
/**
152+
* Register cell value parser.
153+
* @param fn Value parser callback function.
154+
*/
155+
public value(fn: ValueParser<TValue>): this {
156+
this.options.value = fn;
157+
return this;
158+
}
159+
160+
/**
161+
* Register cell renderer. Will be called once for each line in the cell.
162+
* @param fn Cell renderer callback function.
163+
*/
164+
public renderer(fn: Renderer): this {
165+
this.options.render = fn;
166+
return this;
167+
}
168+
119169
/**
120170
* Getter:
121171
*/
122172

123173
/** Check if cell has border. */
124-
public getBorder(): boolean {
125-
return this.options.border === true;
174+
public getBorder(): boolean | undefined {
175+
return this.options.border;
126176
}
127177

128178
/** Get col span. */
@@ -139,8 +189,21 @@ export class Cell {
139189
: 1;
140190
}
141191

142-
/** Get row span. */
143-
public getAlign(): Direction {
144-
return this.options.align ?? "left";
192+
/** Get cell alignment. */
193+
public getAlign(): Direction | undefined {
194+
return this.options.align;
195+
}
196+
197+
/** Get value parser. */
198+
// public getValueParser(): ValueParser<TValue> | undefined {
199+
public getValueParser<TParserValue extends TValue>():
200+
| ValueParser<TParserValue>
201+
| undefined {
202+
return this.options.value;
203+
}
204+
205+
/** Get cell renderer. */
206+
public getRenderer(): Renderer | undefined {
207+
return this.options.render;
145208
}
146209
}

0 commit comments

Comments
 (0)