GithubHelp home page GithubHelp logo

larswaechter / voici.js Goto Github PK

View Code? Open in Web Editor NEW
331.0 331.0 4.0 640 KB

A Node.js library for pretty printing your data on the terminal🎨

Home Page: https://voici.larswaechter.dev

License: MIT License

TypeScript 100.00%
console data-science javascript shell terminal tty typescript

voici.js's Introduction

Hello there 👋

software engineering, artificial intelligence & blogging

voici.js's People

Contributors

larswaechter avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

voici.js's Issues

Remove leading space after line break

(Leading) empty spaces in a cell should be removed. That happens especially if the next character after a line break is an empty space.

An example:

const data = [['abcdefghijklmnopqrstu', 'abcdefghijklmno pqrstu']];

const table = new Table(data, {
  header: {
    width: 15
  }
});

table.print();

Output: (wrong)

  0                  1                
======================================
  abcdefghijklmno    abcdefghijklmno  
  pqrstu              pqrstu          

As you can see, the empty space before 'p' should be removed.

Correct:

  0                  1                
======================================
  abcdefghijklmno    abcdefghijklmno  
  pqrstu             pqrstu           

Add "fillEmpty" config option

An fillEmpty option might be useful for dynamically filling empty values.

An example

const data = [
  { firstname: 'Homer', lastname: 'Simpson', age: 39 },
  { firstname: 'Marge', lastname: '', age: 36 },
  { firstname: 'Bart', lastname: 'Simpson', age: 10 },
  { firstname: 'Lisa', lastname: undefined, age: 8 },
  { firstname: 'Maggie', lastname: null, age: 1 }
];

const table = new Table(data, {
  body: {
    fillEmpty: {
      lastname: (row) => 'Simpson'
    }
  }
});
table.print();

Output:

  firstname    lastname    age  
================================
  Homer        Simpson     39   
  Marge        Simpson     36   
  Bart         Simpson     10   
  Lisa         Simpson     8    
  Maggie       Simpson     1    

The method getDataCell should provide the filled value as well:

console.log(table.getDataCell(1, 'lastname')); // Simpson

Add `columns` and `shape` getters

The following public getters should be added to the Table class:

  • columns => returns an array including all table columns
  • shape => returns the number of rows and columns

Option for displaying only the top / bottom "n" rows

In order to display large datasets clearer, there should be an option for displaying only the top / bottom n rows of the dataset. Notice that still all rows are considered for calculations, like accumulations for example. They are just not displayed.

Example 1

Setting peek to an fixed integer, only the top and bottom n rows should be printed

const data  = [
  { firstname: 'Homer', lastname: 'Simpson', age: 39 },
  { firstname: 'Marge', lastname: 'Simpson', age: 36 },
  { firstname: 'Bart', lastname: 'Simpson', age: 10 },
  { firstname: 'Lisa', lastname: 'Simpson', age: 8 },
  { firstname: 'Maggie', lastname: 'Simpson', age: 1 }
];

const table = new Table(data, {
  body: {
    peek: 2
  }
});
table.print();

Output:

  firstname    lastname    age  
================================
  Homer        Simpson     39   
  Marge        Simpson     36   
    <---------------------->    
  Lisa         Simpson     8    
  Maggie       Simpson     1    

Example 2

Setting peek to an array, like [1, 3], only the top 1 and bottom 3 rows should be displayed:

  firstname    lastname    age  
================================
  Homer        Simpson     39   
    <---------------------->    
  Bart         Simpson     10   
  Lisa         Simpson     8    
  Maggie       Simpson     1   

Example 3

You can also display only the top or bottom n rows using [n, 0] or [0, n]. For example peek=[2, 0].

  firstname    lastname    age  
================================
  Homer        Simpson     39   
  Marge        Simpson     36   

Remove external dependencies

In order to remove the total package size, the following npm dependencies should be removed:

  • fast-csv
  • text2png
  • JSONStream

including all methods that use these dependencies. I think they are very rarely used and users should be able to implement them by their own if they are really needed. Read more here.

Allow sorting by dynamic columns

Currently it's not possible to sort the table by dynamic columns. The main reason is because they are stored separately and are not part of the dataset.

Sorting happens based on the rows and columns in dataset:

  private sort() {
    const { columns, directions } = this.config.sort;
    if (columns.length !== directions.length)
      throw new Error(
        `Number of columns (${columns.length}) does not match number of directions (${directions.length})`
      );
    this.dataset = orderBy(this.dataset, columns, directions) as TRow[];
  }

The rows of the dynamic columns are stored in:

private dynamicColumns: Map<InferDynamicAttribute<TDColumns>, unknown[]> = new Map();

The problem here is that you actually have to sort both: dataset and dynamicColumns.

Improve Type System

The goal is to improve the library's type system. Especially for the Config type.

An example:

When creating a config, you should only to be allowed to refer to the attributes defined in IData. For example when setting the sort's columns attribute, only the following values should be allowed: firstname, lastname and age, because they are attributes of IData.

import { Config, Table } from './';

interface IData {
  firstname: string;
  lastname: string;
  age: number;
}

const data: IData[] = [
  { firstname: 'Homer', lastname: 'Simpson', age: 39 },
  { firstname: 'Marge', lastname: 'Simpson', age: 36 },
  { firstname: 'Bart', lastname: 'Simpson', age: 10 },
  { firstname: 'Lisa', lastname: 'Simpson', age: 8 },
  { firstname: 'Maggie', lastname: 'Simpson', age: 1 }
];

const config: Config<IData> = {
  sort: {
    columns: ['age'], // only allow 'firstname', 'lastname' and 'age'
    directions: ['asc']
  }
};

const table = new Table(data, config);
table.print();

Unfortunately, this won't work for dynamic columns as these are not be defined in IData usually. That's why we have to pass the dynamic columns' names as generic type:

In this case, we are allowed to pick the fullname column for sorting.

interface IDynamicAttr {
  fullname: string;
}

const config: Config<IData, IDynamicAttr> = { // pass in 'IDynamicAttr'
  header: {
    dynamic: [
      {
        name: 'fullname',
        func: (row) => row.firstname + ' ' + row.lastname  // return value must match with interface
      }
    ]
  },
  sort: {
    columns: ['fullname'], // allow 'fullname' as well
    directions: ['asc']
  }
};

JS error when the terminal width is short

Reproduce:

https://github.com/Jinjiang/reproductions/tree/voici-20230503

I guess the trigger is when the header name of a column is longer than its content.

The error log:

/Users/....../reproductions/node_modules/.pnpm/[email protected]/node_modules/voici.js/dist/table.js:173
        return this.config.padding.char.repeat(size);
                                        ^

RangeError: Invalid count value
    at String.repeat (<anonymous>)
    at Table.getPadding (/Users/....../reproductions/node_modules/.pnpm/[email protected]/node_modules/voici.js/dist/table.js:173:41)
    at Table.buildCellContent (/Users/....../reproductions/node_modules/.pnpm/[email protected]/node_modules/voici.js/dist/table.js:348:54)
    at Table.buildHeaderCell (/Users/....../reproductions/node_modules/.pnpm/[email protected]/node_modules/voici.js/dist/table.js:487:32)
    at Table.buildHeader (/Users/....../reproductions/node_modules/.pnpm/[email protected]/node_modules/voici.js/dist/table.js:501:40)
    at Table.toString (/Users/....../reproductions/node_modules/.pnpm/[email protected]/node_modules/voici.js/dist/table.js:96:22)
    at Table.print (/Users/....../reproductions/node_modules/.pnpm/[email protected]/node_modules/voici.js/dist/table.js:121:26)
    at Object.<anonymous> (/Users/....../reproductions/index.js:18:7)
    at Module._compile (node:internal/modules/cjs/loader:1105:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1159:10)

Thanks.

Combine dataset with dynamic columns

The dynamic columns' values should not be stored separately. Instead, they should be stored within the dataset. This will make the code cleaner and remove some explicit assertions. In general, the type system should be much clearer afterwards.

Moreover, the methods appendRow and removeRow should be removed. These actions should be done by the user before passing the dataset to voici.

Error: Cannot find module 'source-map-support/register'

Not sure what to add here but that's the error I get. Here's the entirety of the code:

process.loadEnvFile();

import { Table } from 'voici.js';

const API_KEY = process.env.GOOGLE_AI_KEY;

(async () => {
	let modelReq = await fetch(`https://generativelanguage.googleapis.com/v1beta/models?key=${API_KEY}`);
	let models = await modelReq.json();
	const table = new Table(models);
	table.print();
})();

Full stacktrace:

node:internal/modules/cjs/loader:1142
  const err = new Error(message);
              ^

Error: Cannot find module 'source-map-support/register'
Require stack:
- /home/ray/projects/ai-testingzone/get_google_models/node_modules/voici.js/dist/index.js
    at Module._resolveFilename (node:internal/modules/cjs/loader:1142:15)
    at Module._load (node:internal/modules/cjs/loader:983:27)
    at Module.require (node:internal/modules/cjs/loader:1230:19)
    at require (node:internal/modules/helpers:179:18)
    at Object.<anonymous> (/home/ray/projects/ai-testingzone/get_google_models/node_modules/voici.js/dist/index.js:4:1)
    at Module._compile (node:internal/modules/cjs/loader:1368:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1426:10)
    at Module.load (node:internal/modules/cjs/loader:1205:32)
    at Module._load (node:internal/modules/cjs/loader:1021:12)
    at cjsLoader (node:internal/modules/esm/translators:366:17) {
  code: 'MODULE_NOT_FOUND',
  requireStack: [
    '/home/ray/projects/ai-testingzone/get_google_models/node_modules/voici.js/dist/index.js'
  ]
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.