Skip to content
Draft
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
2 changes: 1 addition & 1 deletion command/upgrade/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ export abstract class Provider {
);

if (versions.length > this.maxListSize) {
const table = new Table().indent(indent);
const table = new Table<Array<string>>().indent(indent);
const rowSize = Math.ceil(versions.length / maxCols);
const colSize = Math.min(versions.length, maxCols);
let versionIndex = 0;
Expand Down
6 changes: 6 additions & 0 deletions dev_deps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,9 @@ export { copy } from "https://deno.land/[email protected]/streams/conversion.ts";
/* 3rd party */
export { gt, lt } from "https://deno.land/x/[email protected]/mod.ts";
export { default as sinon } from "https://cdn.skypack.dev/[email protected]?dts";

export {
assert as assertType,
type IsAny,
type IsExact,
} from "https://deno.land/x/[email protected]/mod.ts";
45 changes: 45 additions & 0 deletions examples/table/datatable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#!/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();
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 = 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 | void;

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