Skip to content

Confusing behavior when options.columns length doesn't match input key length #37

@griffin-rickle

Description

@griffin-rickle

This is perhaps not a bug, but at least an opportunity to improve the documentation and user experience provided by the library. When using tablemark to print some data received from a database call where some bindings were optional, I stumbled across this behavior. Consider the following code snippet:

import { tablemark } from "tablemark"

const headers = ["column1", "column2", "mismatched_column"]
const data = [{"column1": "value1", "mismatched_column": "mismatched_value"}]
console.log(tablemark(data, { columns: headers }).toString());

At first blush I had expect the following markdown table to be printed:

| column1 | column2 | mismatched_column |
| :------ | :-----  | :---------------- |
| value1  |         | mismatched_value  |

The table without the column2 column would have also made sense.

However this is what is printed:

| column1 | column2          |
| :------ | :--------------- |
| value1  | mismatched_value |

I understand that there is a note in the tablemark README stating that "The keys of the first encountered object are used for the table's headers. By default, any other keys from successive objects will be ignored, excluding those columns from the table", but I do not believe that explanation sufficiently highlights the behavior displayed here. A more apparent warning about the strategy which tablemark uses to determine which columns it prints, how it retrieves the input values based on those columns, and how those two behaviors interact specifically with the columns option would be really helpful.

For completeness, I am able to work around this by creating a defaults object and merging it with each of my data objects, like so:

import { tablemark } from "tablemark"

const headers = ["column1", "column2", "mismatched_column"]
const defaultValues = headers.reduce((acc, header) => {
  return {
    ...acc,
    [header]: ""
  }}, 
  {});
const data = [{"column1": "value1", "mismatched_column": "mismatched_value"}]
const defaultedData = data.map((entry) => { return { ...defaultValues, ...entry } });
console.log(tablemark(defaultedData, { caseHeaders: false }).toString());

This code snippet prints what I would expect:

| column1 | column2 | mismatched_column |
| :------ | :------ | :---------------- |
| value1  |         | mismatched_value  |

I'm just not sure if this is highlighted enough in the documentation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions