Skip to content

Commit

Permalink
feat: add cfwf writer
Browse files Browse the repository at this point in the history
  • Loading branch information
badele committed Nov 7, 2023
1 parent 1f01928 commit 4ad8a88
Show file tree
Hide file tree
Showing 12 changed files with 468 additions and 38 deletions.
75 changes: 57 additions & 18 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,76 @@ name: CI
on: [push, pull_request, workflow_dispatch]

jobs:
cog_check_job:
check_requirements:
runs-on: ubuntu-latest
name: Check CI requirements
steps:
- name: check requirements
run: |
test -n "${{ secrets.CODECOV_TOKEN }}" || (echo "Please define CODECOV_TOKEN into github repo setting"; exit 1)
lint:
runs-on: ubuntu-latest
name: check conventional commit compliance
steps:
- uses: actions/checkout@main
with:
fetch-depth: 0

- name: Conventional commits check
uses: oknozor/cocogitto-action@v3

build:
runs-on: ubuntu-latest
- uses: taiki-e/install-action@v2
with:
tool: just@1.14.0

- uses: denoland/setup-deno@v1
with:
deno-version: v1.36.0

- name: Format
run: deno fmt --check

- name: Lint
run: just lint

- name: coverage
run: just coverage

- name: Upload coverage
uses: codecov/codecov-action@v3
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
with:
files: ./.coverage/cov.lcov

test:
runs-on: ${{ matrix.os }}
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
deno: [1.37.0, 1.36.0, 1.35.0]
name: Test with Deno ${{ matrix.deno }}

deno:
- v1.x
- canary
os:
- ubuntu-22.04
- windows-2022
- macOS-12
steps:
- uses: actions/checkout@main

- name: Setup Deno
uses: denolib/setup-deno@master
- uses: taiki-e/install-action@v2
with:
deno-version: ${{ matrix.deno }}
tool: just@1.14.0

- name: Print deno version
run: deno --version
- uses: denoland/setup-deno@v1
with:
deno-version: v1.36.0

- name: Check format
run: deno fmt --check **/*.ts
- name: coverage
run: just coverage

- name: Run tests
run: deno test
- name: Upload coverage
uses: codecov/codecov-action@v3
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
with:
files: ./.coverage/cov.lcov
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
.direnv
.coverage
5 changes: 4 additions & 1 deletion deps.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
// Add your dependencies in here
export { bold } from "https://deno.land/std@v0.203.0/fmt/colors.ts";
import * as modfmt from "https://deno.land/std@0.204.0/fmt/printf.ts";
import filget, { text } from "https://deno.land/x/deno_figlet@1.0.0/mod.ts";

export { filget, modfmt, text };
6 changes: 5 additions & 1 deletion flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,19 @@
nodePackages.markdownlint-cli
pre-commit

just
bkt

deno
lcov
];
shellHook = ''
export PROJ="cfwf"
echo ""
echo "⭐ Welcome to the $PROJ project ⭐"
echo ""
hello
just
echo ""
'';
};
Expand Down
38 changes: 38 additions & 0 deletions justfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/usr/bin/env just -f

BROWSER := "chromium"

# This help
@help:
just -lu --list-heading=$'{{ file_name(justfile()) }} commands:\n'

# Check conventional commits
@conventional-check:
cog check

# Execute test tasks
@test:
rm -rf ./.coverage
deno test --doc --unstable --allow-all --parallel --coverage=./.coverage --trace-ops

# Lint code
@lint:
deno lint

# Format code
@fmt:
deno fmt

# Execute coverage
@coverage: test
deno coverage ./.coverage/ --lcov --output=./.coverage/cov.lcov

# Browse localy coverage
coverage-browse browser="chromium": coverage
genhtml -o ./.coverage/html_cov ./.coverage/cov.lcov
{{ browser }} ./.coverage/html_cov/index.html


# Run command interactively, view the result in realtime
@view:
just --choose --chooser="fzf --margin 0% --reverse --preview-window=right,80% --preview='bkt --ttl=15m --stale=15s -- just {}'"
3 changes: 1 addition & 2 deletions mod.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
export { bold } from "./deps.ts";
export { getHelloWorld } from "./src/hello.ts";
export { Align, arrayToCFWF } from "./src/cfwf_writer.ts";
20 changes: 20 additions & 0 deletions sample.cfwf
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@

_____ _
/ __ \ | |
| / \/ _ __ _ _ _ __ | |_ ___ ___ _ _ _ __ _ __ ___ _ __ ___ _ _
| | | '__|| | | || '_ \ | __| / _ \ / __|| | | || '__|| '__| / _ \| '_ \ / __|| | | |
| \__/\| | | |_| || |_) || |_ | (_) || (__ | |_| || | | | | __/| | | || (__ | |_| |
\____/|_| \__, || .__/ \__| \___/ \___| \__,_||_| |_| \___||_| |_| \___| \__, |
__/ || | __/ |
|___/ |_| |___/

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
date provider ticker title price cur trend value trend percent
────────── ──────── ───────── ───────────────────────────────────────────────── ────────────── ─── ────────────── ─────────────
2023-11-04 yahoo ADA-EUR Cardano EUR 0.30382475 EUR 0.0089045465 3.02
2023-11-04 yahoo BTC-EUR Bitcoin EUR 32382.29300000 EUR 523.8554700000 1.64
2023-11-04 yahoo DOGE-EUR Dogecoin EUR 0.06409328 EUR 0.0016048551 2.57
2023-11-04 yahoo ETH-EUR Ethereum EUR 1715.40040000 EUR 50.5688480000 3.04
2023-11-04 yahoo MATIC-EUR Polygon EUR 0.62594900 EUR 0.0191679000 3.16
2023-11-04 yahoo 500.PA Amundi Index Solutions - Amundi S&P 500 UCITS ETF 78.79000000 EUR 0.3099975600 0.40
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
179 changes: 179 additions & 0 deletions src/cfwf_writer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
import { modfmt, text } from "../deps.ts";

export enum Align {
Left,
Center,
Right,
}

function max(a: number, b: number): number {
return (a > b) ? a : b;
}

function align(align: Align, text: string, maxsize: number): string {
switch (align) {
case Align.Center: {
const begin = (maxsize - text.length) / 2;
return text.padStart(begin + text.length).padEnd(maxsize);
}
case Align.Right:
return text.padStart(maxsize);

case Align.Left:
return text.padEnd(maxsize);
}
}

export type exportOptions = {
headers?: string[];
aligns?: Align[];
padding?: number;
charlinetop?: string;
charlinemiddle?: string;
charlinebottom?: string;
title?: string;
};

export async function arrayToCFWF(
// deno-lint-ignore no-explicit-any
rows: any,
{
headers = [],
aligns = [],
padding = 3,
charlinetop = "━",
charlinemiddle = "─",
charlinebottom = "━",
title = "",
}: exportOptions = {},
): Promise<string> {
if (rows.length == 0) return "";
if (rows[0].length != headers.length) {
throw new Error(
`They have ${
rows[0].length
} columns and ${headers.length} header columns`,
);
}
if (aligns.length != headers.length) {
throw new Error(
`They have ${headers.length} columns and ${aligns.length} aligns`,
);
}

//search the needed number of float size for each columns
const colnbfloat: Record<number, number> = {};
// deno-lint-ignore no-explicit-any
rows.forEach((row: any) => {
for (let idx = 0; idx < row.length; idx++) {
const col = row[idx];
if (typeof col === "number") {
const colvalue = col.toString();
const dotpos = colvalue.indexOf(".");
colnbfloat[idx] = max(
colnbfloat[idx],
(dotpos != -1) ? colvalue.length - dotpos - 1 : 0,
);
}
}
});

// convert all entries to string
// deno-lint-ignore no-explicit-any
const srows: any[] = [];
// deno-lint-ignore no-explicit-any
rows.forEach((row: any) => {
// deno-lint-ignore no-explicit-any
const cols: any[] = [];
for (let idx = 0; idx < row.length; idx++) {
const col = row[idx];
if (typeof col === "number" && colnbfloat[idx] > 0) {
cols.push(modfmt.sprintf("%.*f", colnbfloat[idx], col));
} else {
cols.push(col.toString());
}
}
srows.push(cols);
});
const lines: string[] = [];
const columnssize: number[] = [];

// Init columns size with the header size
for (let idx = 0; idx < headers.length; idx++) {
columnssize.push(headers[idx].length);
}

// compute the content columns size
for (let rowidx = 0; rowidx < srows.length; rowidx++) {
const itemrow = srows[rowidx];
for (let colidx = 0; colidx < itemrow.length; colidx++) {
const content = itemrow[colidx];
columnssize[colidx] = max(content.length, columnssize[colidx]);
}
}

// compute total line size
let headerlinesize = 0;
for (let idx = 0; idx < headers.length; idx++) {
if (idx > 0) headerlinesize += padding;
headerlinesize += columnssize[idx];
}

// Add top line header
if (charlinetop) lines.push(charlinetop.repeat(headerlinesize));

// add header columns
const header: string[] = [];
const middlelineheader: string[] = [];
for (let idx = 0; idx < headers.length; idx++) {
const cname = headers[idx];
const csize = columnssize[idx];

if (idx > 0) {
header.push(" ".repeat(padding));
middlelineheader.push(" ".repeat(padding));
}

header.push(align(aligns[idx], cname, csize));
middlelineheader.push(charlinemiddle.repeat(csize));
}
lines.push(header.join(""));
lines.push(middlelineheader.join(""));

// Add rows datas
for (let rowidx = 0; rowidx < srows.length; rowidx++) {
const line = [];
const coldata = srows[rowidx];

for (let colidx = 0; colidx < coldata.length; colidx++) {
const csize = columnssize[colidx];

if (colidx > 0) line.push(" ".repeat(padding));
// line.push(coldata[colidx].padEnd(csize));
line.push(align(aligns[colidx], coldata[colidx], csize));
}
lines.push(line.join(""));
}

// Add bottom line header
if (charlinebottom) lines.push(charlinebottom.repeat(headerlinesize));

// add title
if (title) {
const txttitle = await text(title, "doom");
const atitle = txttitle.split("\n");
let maxtitlesize = 0;
let titlepadding = 0;
for (let idx = 0; idx < atitle.length; idx++) {
maxtitlesize = max(atitle[idx].length, maxtitlesize);
titlepadding = headerlinesize - maxtitlesize;
}

for (let idx = 0; idx < atitle.length; idx++) {
atitle[idx] = atitle[idx].padStart(headerlinesize - (titlepadding / 2));
}
lines.unshift(atitle.join("\n"));
}

return lines.join("\n");
}
Loading

0 comments on commit 4ad8a88

Please sign in to comment.