initial commit of actions

This commit is contained in:
Dominik Polakovics Polakovics 2026-01-31 18:56:04 +01:00
commit 949ece5785
44660 changed files with 12034344 additions and 0 deletions

View file

@ -0,0 +1,6 @@
import type { Alignment } from './types/api';
/**
* Pads a string to the left and/or right to position the subject
* text in a desired alignment within a container.
*/
export declare const alignString: (subject: string, containerWidth: number, alignment: Alignment) => string;

View file

@ -0,0 +1,59 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.alignString = void 0;
const string_width_1 = __importDefault(require("string-width"));
const utils_1 = require("./utils");
const alignLeft = (subject, width) => {
return subject + ' '.repeat(width);
};
const alignRight = (subject, width) => {
return ' '.repeat(width) + subject;
};
const alignCenter = (subject, width) => {
return ' '.repeat(Math.floor(width / 2)) + subject + ' '.repeat(Math.ceil(width / 2));
};
const alignJustify = (subject, width) => {
const spaceSequenceCount = utils_1.countSpaceSequence(subject);
if (spaceSequenceCount === 0) {
return alignLeft(subject, width);
}
const addingSpaces = utils_1.distributeUnevenly(width, spaceSequenceCount);
if (Math.max(...addingSpaces) > 3) {
return alignLeft(subject, width);
}
let spaceSequenceIndex = 0;
return subject.replace(/\s+/g, (groupSpace) => {
return groupSpace + ' '.repeat(addingSpaces[spaceSequenceIndex++]);
});
};
/**
* Pads a string to the left and/or right to position the subject
* text in a desired alignment within a container.
*/
const alignString = (subject, containerWidth, alignment) => {
const subjectWidth = string_width_1.default(subject);
if (subjectWidth === containerWidth) {
return subject;
}
if (subjectWidth > containerWidth) {
throw new Error('Subject parameter value width cannot be greater than the container width.');
}
if (subjectWidth === 0) {
return ' '.repeat(containerWidth);
}
const availableWidth = containerWidth - subjectWidth;
if (alignment === 'left') {
return alignLeft(subject, availableWidth);
}
if (alignment === 'right') {
return alignRight(subject, availableWidth);
}
if (alignment === 'justify') {
return alignJustify(subject, availableWidth);
}
return alignCenter(subject, availableWidth);
};
exports.alignString = alignString;

View file

@ -0,0 +1,2 @@
import type { BaseConfig, Row } from './types/internal';
export declare const alignTableData: (rows: Row[], config: BaseConfig) => Row[];

View file

@ -0,0 +1,13 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.alignTableData = void 0;
const alignString_1 = require("./alignString");
const alignTableData = (rows, config) => {
return rows.map((row) => {
return row.map((cell, cellIndex) => {
const { width, alignment } = config.columns[cellIndex];
return alignString_1.alignString(cell, width, alignment);
});
});
};
exports.alignTableData = alignTableData;

View file

@ -0,0 +1,4 @@
/**
* Calculates height of cell content in regard to its width and word wrapping.
*/
export declare const calculateCellHeight: (value: string, columnWidth: number, useWrapWord?: boolean) => number;

View file

@ -0,0 +1,11 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.calculateCellHeight = void 0;
const wrapCell_1 = require("./wrapCell");
/**
* Calculates height of cell content in regard to its width and word wrapping.
*/
const calculateCellHeight = (value, columnWidth, useWrapWord = false) => {
return wrapCell_1.wrapCell(value, columnWidth, useWrapWord).length;
};
exports.calculateCellHeight = calculateCellHeight;

View file

@ -0,0 +1,5 @@
import type { Cell } from './types/internal';
/**
* Calculates width of each cell contents in a row.
*/
export declare const calculateCellWidths: (cells: Cell[]) => number[];

View file

@ -0,0 +1,16 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.calculateCellWidths = void 0;
const string_width_1 = __importDefault(require("string-width"));
/**
* Calculates width of each cell contents in a row.
*/
const calculateCellWidths = (cells) => {
return cells.map((cell) => {
return Math.max(...cell.split('\n').map(string_width_1.default));
});
};
exports.calculateCellWidths = calculateCellWidths;

View file

@ -0,0 +1,6 @@
import type { Row } from './types/internal';
declare const _default: (rows: Row[]) => number[];
/**
* Produces an array of values that describe the largest value length (width) in every column.
*/
export default _default;

View file

@ -0,0 +1,16 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const calculateCellWidths_1 = require("./calculateCellWidths");
/**
* Produces an array of values that describe the largest value length (width) in every column.
*/
exports.default = (rows) => {
const columnWidths = new Array(rows[0].length).fill(0);
rows.forEach((row) => {
const cellWidths = calculateCellWidths_1.calculateCellWidths(row);
cellWidths.forEach((cellWidth, cellIndex) => {
columnWidths[cellIndex] = Math.max(columnWidths[cellIndex], cellWidth);
});
});
return columnWidths;
};

View file

@ -0,0 +1,5 @@
import type { BaseConfig, Row } from './types/internal';
/**
* Produces an array of values that describe the largest value length (height) in every row.
*/
export declare const calculateRowHeights: (rows: Row[], config: BaseConfig) => number[];

View file

@ -0,0 +1,18 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.calculateRowHeights = void 0;
const calculateCellHeight_1 = require("./calculateCellHeight");
/**
* Produces an array of values that describe the largest value length (height) in every row.
*/
const calculateRowHeights = (rows, config) => {
return rows.map((row) => {
let rowHeight = 1;
row.forEach((cell, cellIndex) => {
const cellHeight = calculateCellHeight_1.calculateCellHeight(cell, config.columns[cellIndex].width, config.columns[cellIndex].wrapWord);
rowHeight = Math.max(rowHeight, cellHeight);
});
return rowHeight;
});
};
exports.calculateRowHeights = calculateRowHeights;

View file

@ -0,0 +1,2 @@
import type { StreamUserConfig, WritableStream } from './types/api';
export declare const createStream: (userConfig: StreamUserConfig) => WritableStream;

View file

@ -0,0 +1,72 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createStream = void 0;
const alignTableData_1 = require("./alignTableData");
const calculateRowHeights_1 = require("./calculateRowHeights");
const drawBorder_1 = require("./drawBorder");
const drawRow_1 = require("./drawRow");
const makeStreamConfig_1 = require("./makeStreamConfig");
const mapDataUsingRowHeights_1 = require("./mapDataUsingRowHeights");
const padTableData_1 = require("./padTableData");
const stringifyTableData_1 = require("./stringifyTableData");
const truncateTableData_1 = require("./truncateTableData");
const prepareData = (data, config) => {
let rows = stringifyTableData_1.stringifyTableData(data);
rows = truncateTableData_1.truncateTableData(rows, config);
const rowHeights = calculateRowHeights_1.calculateRowHeights(rows, config);
rows = mapDataUsingRowHeights_1.mapDataUsingRowHeights(rows, rowHeights, config);
rows = alignTableData_1.alignTableData(rows, config);
rows = padTableData_1.padTableData(rows, config);
return rows;
};
const create = (row, columnWidths, config) => {
const rows = prepareData([row], config);
const body = rows.map((literalRow) => {
return drawRow_1.drawRow(literalRow, config);
}).join('');
let output;
output = '';
output += drawBorder_1.drawBorderTop(columnWidths, config);
output += body;
output += drawBorder_1.drawBorderBottom(columnWidths, config);
output = output.trimEnd();
process.stdout.write(output);
};
const append = (row, columnWidths, config) => {
const rows = prepareData([row], config);
const body = rows.map((literalRow) => {
return drawRow_1.drawRow(literalRow, config);
}).join('');
let output = '';
const bottom = drawBorder_1.drawBorderBottom(columnWidths, config);
if (bottom !== '\n') {
output = '\r\u001B[K';
}
output += drawBorder_1.drawBorderJoin(columnWidths, config);
output += body;
output += bottom;
output = output.trimEnd();
process.stdout.write(output);
};
const createStream = (userConfig) => {
const config = makeStreamConfig_1.makeStreamConfig(userConfig);
const columnWidths = Object.values(config.columns).map((column) => {
return column.width + column.paddingLeft + column.paddingRight;
});
let empty = true;
return {
write: (row) => {
if (row.length !== config.columnCount) {
throw new Error('Row cell count does not match the config.columnCount.');
}
if (empty) {
empty = false;
create(row, columnWidths, config);
}
else {
append(row, columnWidths, config);
}
},
};
};
exports.createStream = createStream;

View file

@ -0,0 +1,26 @@
import type { DrawVerticalLine } from './types/api';
import type { TableConfig, SeparatorGetter, TopBorderConfig, JoinBorderConfig, BottomBorderConfig } from './types/internal';
declare type Separator = {
readonly left: string;
readonly right: string;
readonly body: string;
readonly join: string;
};
declare const drawBorder: (columnWidths: number[], config: {
separator: Separator;
drawVerticalLine: DrawVerticalLine;
}) => string;
declare const drawBorderTop: (columnWidths: number[], config: {
border: TopBorderConfig;
drawVerticalLine: DrawVerticalLine;
}) => string;
declare const drawBorderJoin: (columnWidths: number[], config: {
border: JoinBorderConfig;
drawVerticalLine: DrawVerticalLine;
}) => string;
declare const drawBorderBottom: (columnWidths: number[], config: {
border: BottomBorderConfig;
drawVerticalLine: DrawVerticalLine;
}) => string;
export declare const createTableBorderGetter: (columnWidths: number[], config: TableConfig) => SeparatorGetter;
export { drawBorder, drawBorderBottom, drawBorderJoin, drawBorderTop, };

View file

@ -0,0 +1,100 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.drawBorderTop = exports.drawBorderJoin = exports.drawBorderBottom = exports.drawBorder = exports.createTableBorderGetter = void 0;
const drawContent_1 = require("./drawContent");
const drawBorder = (columnWidths, config) => {
const { separator, drawVerticalLine } = config;
const columns = columnWidths.map((size) => {
return config.separator.body.repeat(size);
});
return drawContent_1.drawContent(columns, {
drawSeparator: drawVerticalLine,
separatorGetter: (index, columnCount) => {
if (index === 0) {
return separator.left;
}
if (index === columnCount) {
return separator.right;
}
return separator.join;
},
}) + '\n';
};
exports.drawBorder = drawBorder;
const drawBorderTop = (columnWidths, config) => {
const result = drawBorder(columnWidths, {
...config,
separator: {
body: config.border.topBody,
join: config.border.topJoin,
left: config.border.topLeft,
right: config.border.topRight,
},
});
if (result === '\n') {
return '';
}
return result;
};
exports.drawBorderTop = drawBorderTop;
const drawBorderJoin = (columnWidths, config) => {
return drawBorder(columnWidths, {
...config,
separator: {
body: config.border.joinBody,
join: config.border.joinJoin,
left: config.border.joinLeft,
right: config.border.joinRight,
},
});
};
exports.drawBorderJoin = drawBorderJoin;
const drawBorderBottom = (columnWidths, config) => {
return drawBorder(columnWidths, {
...config,
separator: {
body: config.border.bottomBody,
join: config.border.bottomJoin,
left: config.border.bottomLeft,
right: config.border.bottomRight,
},
});
};
exports.drawBorderBottom = drawBorderBottom;
const createTableBorderGetter = (columnWidths, config) => {
return (index, size) => {
if (!config.header) {
if (index === 0) {
return drawBorderTop(columnWidths, config);
}
if (index === size) {
return drawBorderBottom(columnWidths, config);
}
return drawBorderJoin(columnWidths, config);
}
// Deal with the header
if (index === 0) {
return drawBorderTop(columnWidths, {
...config,
border: {
...config.border,
topJoin: config.border.topBody,
},
});
}
if (index === 1) {
return drawBorderJoin(columnWidths, {
...config,
border: {
...config.border,
joinJoin: config.border.headerJoin,
},
});
}
if (index === size) {
return drawBorderBottom(columnWidths, config);
}
return drawBorderJoin(columnWidths, config);
};
};
exports.createTableBorderGetter = createTableBorderGetter;

View file

@ -0,0 +1,9 @@
declare type SeparatorConfig = {
drawSeparator: (index: number, size: number) => boolean;
separatorGetter: (index: number, size: number) => string;
};
/**
* Shared function to draw horizontal borders, rows or the entire table
*/
export declare const drawContent: (contents: string[], separatorConfig: SeparatorConfig) => string;
export {};

View file

@ -0,0 +1,26 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.drawContent = void 0;
/**
* Shared function to draw horizontal borders, rows or the entire table
*/
const drawContent = (contents, separatorConfig) => {
const { separatorGetter, drawSeparator } = separatorConfig;
const contentSize = contents.length;
const result = [];
if (drawSeparator(0, contentSize)) {
result.push(separatorGetter(0, contentSize));
}
contents.forEach((content, contentIndex) => {
result.push(content);
// Only append the middle separator if the content is not the last
if (contentIndex + 1 < contentSize && drawSeparator(contentIndex + 1, contentSize)) {
result.push(separatorGetter(contentIndex + 1, contentSize));
}
});
if (drawSeparator(contentSize, contentSize)) {
result.push(separatorGetter(contentSize, contentSize));
}
return result.join('');
};
exports.drawContent = drawContent;

View file

@ -0,0 +1,2 @@
import type { TableConfig } from './types/internal';
export declare const drawHeader: (width: number, config: TableConfig) => string;

View file

@ -0,0 +1,29 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.drawHeader = void 0;
const alignString_1 = require("./alignString");
const drawRow_1 = require("./drawRow");
const padTableData_1 = require("./padTableData");
const truncateTableData_1 = require("./truncateTableData");
const wrapCell_1 = require("./wrapCell");
const drawHeader = (width, config) => {
if (!config.header) {
throw new Error('Can not draw header without header configuration');
}
const { alignment, paddingRight, paddingLeft, wrapWord } = config.header;
let content = config.header.content;
content = truncateTableData_1.truncateString(content, config.header.truncate);
const headerLines = wrapCell_1.wrapCell(content, width, wrapWord);
return headerLines.map((headerLine) => {
let line = alignString_1.alignString(headerLine, width, alignment);
line = padTableData_1.padString(line, paddingLeft, paddingRight);
return drawRow_1.drawRow([line], {
...config,
drawVerticalLine: (index) => {
const columnCount = config.columns.length;
return config.drawVerticalLine(index === 0 ? 0 : columnCount, columnCount);
},
});
}).join('');
};
exports.drawHeader = drawHeader;

View file

@ -0,0 +1,6 @@
import type { DrawVerticalLine } from './types/api';
import type { BodyBorderConfig, Row } from './types/internal';
export declare const drawRow: (row: Row, config: {
border: BodyBorderConfig;
drawVerticalLine: DrawVerticalLine;
}) => string;

View file

@ -0,0 +1,20 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.drawRow = void 0;
const drawContent_1 = require("./drawContent");
const drawRow = (row, config) => {
const { border, drawVerticalLine } = config;
return drawContent_1.drawContent(row, {
drawSeparator: drawVerticalLine,
separatorGetter: (index, columnCount) => {
if (index === 0) {
return border.bodyLeft;
}
if (index === columnCount) {
return border.bodyRight;
}
return border.bodyJoin;
},
}) + '\n';
};
exports.drawRow = drawRow;

View file

@ -0,0 +1,2 @@
import type { TableConfig, Row } from './types/internal';
export declare const drawTable: (rows: Row[], columnWidths: number[], rowHeights: number[], config: TableConfig) => string;

View file

@ -0,0 +1,38 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.drawTable = void 0;
const string_width_1 = __importDefault(require("string-width"));
const drawBorder_1 = require("./drawBorder");
const drawContent_1 = require("./drawContent");
const drawHeader_1 = require("./drawHeader");
const drawRow_1 = require("./drawRow");
const utils_1 = require("./utils");
const drawTable = (rows, columnWidths, rowHeights, config) => {
const { drawHorizontalLine, singleLine, } = config;
const contents = utils_1.groupBySizes(rows, rowHeights).map((group) => {
return group.map((row) => {
return drawRow_1.drawRow(row, config);
}).join('');
});
if (config.header) {
// assume that topLeft/right border have width = 1
const headerWidth = string_width_1.default(drawRow_1.drawRow(rows[0], config)) - 2 -
config.header.paddingLeft - config.header.paddingRight;
const header = drawHeader_1.drawHeader(headerWidth, config);
contents.unshift(header);
}
return drawContent_1.drawContent(contents, {
drawSeparator: (index, size) => {
// Top/bottom border
if (index === 0 || index === size) {
return drawHorizontalLine(index, size);
}
return !singleLine && drawHorizontalLine(index, size);
},
separatorGetter: drawBorder_1.createTableBorderGetter(columnWidths, config),
});
};
exports.drawTable = drawTable;

View file

@ -0,0 +1,13 @@
declare function validate43(data: any, { instancePath, parentData, parentDataProperty, rootData }?: {
instancePath?: string | undefined;
parentData: any;
parentDataProperty: any;
rootData?: any;
}): boolean;
declare function validate76(data: any, { instancePath, parentData, parentDataProperty, rootData }?: {
instancePath?: string | undefined;
parentData: any;
parentDataProperty: any;
rootData?: any;
}): boolean;
export { validate43 as _config_json, validate76 as _streamConfig_json };

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,2 @@
import type { BorderConfig } from './types/api';
export declare const getBorderCharacters: (name: string) => BorderConfig;

View file

@ -0,0 +1,88 @@
"use strict";
/* eslint-disable sort-keys-fix/sort-keys-fix */
Object.defineProperty(exports, "__esModule", { value: true });
exports.getBorderCharacters = void 0;
const getBorderCharacters = (name) => {
if (name === 'honeywell') {
return {
topBody: '═',
topJoin: '╤',
topLeft: '╔',
topRight: '╗',
bottomBody: '═',
bottomJoin: '╧',
bottomLeft: '╚',
bottomRight: '╝',
bodyLeft: '║',
bodyRight: '║',
bodyJoin: '│',
headerJoin: '┬',
joinBody: '─',
joinLeft: '╟',
joinRight: '╢',
joinJoin: '┼',
};
}
if (name === 'norc') {
return {
topBody: '─',
topJoin: '┬',
topLeft: '┌',
topRight: '┐',
bottomBody: '─',
bottomJoin: '┴',
bottomLeft: '└',
bottomRight: '┘',
bodyLeft: '│',
bodyRight: '│',
bodyJoin: '│',
headerJoin: '┬',
joinBody: '─',
joinLeft: '├',
joinRight: '┤',
joinJoin: '┼',
};
}
if (name === 'ramac') {
return {
topBody: '-',
topJoin: '+',
topLeft: '+',
topRight: '+',
bottomBody: '-',
bottomJoin: '+',
bottomLeft: '+',
bottomRight: '+',
bodyLeft: '|',
bodyRight: '|',
bodyJoin: '|',
headerJoin: '+',
joinBody: '-',
joinLeft: '|',
joinRight: '|',
joinJoin: '|',
};
}
if (name === 'void') {
return {
topBody: '',
topJoin: '',
topLeft: '',
topRight: '',
bottomBody: '',
bottomJoin: '',
bottomLeft: '',
bottomRight: '',
bodyLeft: '',
bodyRight: '',
bodyJoin: '',
headerJoin: '',
joinBody: '',
joinLeft: '',
joinRight: '',
joinJoin: '',
};
}
throw new Error('Unknown border template "' + name + '".');
};
exports.getBorderCharacters = getBorderCharacters;

View file

@ -0,0 +1,5 @@
import { createStream } from './createStream';
import { getBorderCharacters } from './getBorderCharacters';
import { table } from './table';
export { table, createStream, getBorderCharacters, };
export * from './types/api';

View file

@ -0,0 +1,20 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getBorderCharacters = exports.createStream = exports.table = void 0;
const createStream_1 = require("./createStream");
Object.defineProperty(exports, "createStream", { enumerable: true, get: function () { return createStream_1.createStream; } });
const getBorderCharacters_1 = require("./getBorderCharacters");
Object.defineProperty(exports, "getBorderCharacters", { enumerable: true, get: function () { return getBorderCharacters_1.getBorderCharacters; } });
const table_1 = require("./table");
Object.defineProperty(exports, "table", { enumerable: true, get: function () { return table_1.table; } });
__exportStar(require("./types/api"), exports);

View file

@ -0,0 +1,7 @@
import type { StreamUserConfig } from './types/api';
import type { StreamConfig } from './types/internal';
/**
* Makes a new configuration object out of the userConfig object
* using default values for the missing configuration properties.
*/
export declare const makeStreamConfig: (userConfig: StreamUserConfig) => StreamConfig;

View file

@ -0,0 +1,47 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.makeStreamConfig = void 0;
const lodash_clonedeep_1 = __importDefault(require("lodash.clonedeep"));
const utils_1 = require("./utils");
const validateConfig_1 = require("./validateConfig");
/**
* Creates a configuration for every column using default
* values for the missing configuration properties.
*/
const makeColumnsConfig = (columnCount, columns = {}, columnDefault) => {
return Array.from({ length: columnCount }).map((_, index) => {
return {
alignment: 'left',
paddingLeft: 1,
paddingRight: 1,
truncate: Number.POSITIVE_INFINITY,
verticalAlignment: 'top',
wrapWord: false,
...columnDefault,
...columns[index],
};
});
};
/**
* Makes a new configuration object out of the userConfig object
* using default values for the missing configuration properties.
*/
const makeStreamConfig = (userConfig) => {
validateConfig_1.validateConfig('streamConfig.json', userConfig);
const config = lodash_clonedeep_1.default(userConfig);
if (config.columnDefault.width === undefined) {
throw new Error('Must provide config.columnDefault.width when creating a stream.');
}
return {
drawVerticalLine: () => {
return true;
},
...config,
border: utils_1.makeBorderConfig(config.border),
columns: makeColumnsConfig(config.columnCount, config.columns, config.columnDefault),
};
};
exports.makeStreamConfig = makeStreamConfig;

View file

@ -0,0 +1,7 @@
import type { TableUserConfig } from './types/api';
import type { Row, TableConfig } from './types/internal';
/**
* Makes a new configuration object out of the userConfig object
* using default values for the missing configuration properties.
*/
export declare const makeTableConfig: (rows: Row[], userConfig?: TableUserConfig) => TableConfig;

View file

@ -0,0 +1,66 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.makeTableConfig = void 0;
const lodash_clonedeep_1 = __importDefault(require("lodash.clonedeep"));
const calculateColumnWidths_1 = __importDefault(require("./calculateColumnWidths"));
const utils_1 = require("./utils");
const validateConfig_1 = require("./validateConfig");
/**
* Creates a configuration for every column using default
* values for the missing configuration properties.
*/
const makeColumnsConfig = (rows, columns, columnDefault) => {
const columnWidths = calculateColumnWidths_1.default(rows);
return rows[0].map((_, columnIndex) => {
return {
alignment: 'left',
paddingLeft: 1,
paddingRight: 1,
truncate: Number.POSITIVE_INFINITY,
verticalAlignment: 'top',
width: columnWidths[columnIndex],
wrapWord: false,
...columnDefault,
...columns === null || columns === void 0 ? void 0 : columns[columnIndex],
};
});
};
const makeHeaderConfig = (config) => {
if (!config.header) {
return undefined;
}
return {
alignment: 'center',
paddingLeft: 1,
paddingRight: 1,
truncate: Number.POSITIVE_INFINITY,
wrapWord: false,
...config.header,
};
};
/**
* Makes a new configuration object out of the userConfig object
* using default values for the missing configuration properties.
*/
const makeTableConfig = (rows, userConfig = {}) => {
var _a, _b, _c;
validateConfig_1.validateConfig('config.json', userConfig);
const config = lodash_clonedeep_1.default(userConfig);
return {
...config,
border: utils_1.makeBorderConfig(config.border),
columns: makeColumnsConfig(rows, config.columns, config.columnDefault),
drawHorizontalLine: (_a = config.drawHorizontalLine) !== null && _a !== void 0 ? _a : (() => {
return true;
}),
drawVerticalLine: (_b = config.drawVerticalLine) !== null && _b !== void 0 ? _b : (() => {
return true;
}),
header: makeHeaderConfig(config),
singleLine: (_c = config.singleLine) !== null && _c !== void 0 ? _c : false,
};
};
exports.makeTableConfig = makeTableConfig;

View file

@ -0,0 +1,2 @@
import type { BaseConfig, Row } from './types/internal';
export declare const mapDataUsingRowHeights: (unmappedRows: Row[], rowHeights: number[], config: BaseConfig) => Row[];

View file

@ -0,0 +1,44 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.mapDataUsingRowHeights = void 0;
const wrapCell_1 = require("./wrapCell");
const createEmptyStrings = (length) => {
return new Array(length).fill('');
};
const padCellVertically = (lines, rowHeight, columnConfig) => {
const { verticalAlignment } = columnConfig;
const availableLines = rowHeight - lines.length;
if (verticalAlignment === 'top') {
return [...lines, ...createEmptyStrings(availableLines)];
}
if (verticalAlignment === 'bottom') {
return [...createEmptyStrings(availableLines), ...lines];
}
return [
...createEmptyStrings(Math.floor(availableLines / 2)),
...lines,
...createEmptyStrings(Math.ceil(availableLines / 2)),
];
};
const flatten = (array) => {
return [].concat(...array);
};
const mapDataUsingRowHeights = (unmappedRows, rowHeights, config) => {
const tableWidth = unmappedRows[0].length;
const mappedRows = unmappedRows.map((unmappedRow, unmappedRowIndex) => {
const outputRowHeight = rowHeights[unmappedRowIndex];
const outputRow = Array.from({ length: outputRowHeight }, () => {
return new Array(tableWidth).fill('');
});
unmappedRow.forEach((cell, cellIndex) => {
const cellLines = wrapCell_1.wrapCell(cell, config.columns[cellIndex].width, config.columns[cellIndex].wrapWord);
const paddedCellLines = padCellVertically(cellLines, outputRowHeight, config.columns[cellIndex]);
paddedCellLines.forEach((cellLine, cellLineIndex) => {
outputRow[cellLineIndex][cellIndex] = cellLine;
});
});
return outputRow;
});
return flatten(mappedRows);
};
exports.mapDataUsingRowHeights = mapDataUsingRowHeights;

View file

@ -0,0 +1,3 @@
import type { BaseConfig, Row } from './types/internal';
export declare const padString: (input: string, paddingLeft: number, paddingRight: number) => string;
export declare const padTableData: (rows: Row[], config: BaseConfig) => Row[];

View file

@ -0,0 +1,16 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.padTableData = exports.padString = void 0;
const padString = (input, paddingLeft, paddingRight) => {
return ' '.repeat(paddingLeft) + input + ' '.repeat(paddingRight);
};
exports.padString = padString;
const padTableData = (rows, config) => {
return rows.map((cells) => {
return cells.map((cell, cellIndex) => {
const { paddingLeft, paddingRight } = config.columns[cellIndex];
return exports.padString(cell, paddingLeft, paddingRight);
});
});
};
exports.padTableData = padTableData;

View file

@ -0,0 +1,2 @@
import type { Row } from './types/internal';
export declare const stringifyTableData: (rows: unknown[][]) => Row[];

View file

@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.stringifyTableData = void 0;
const utils_1 = require("./utils");
const stringifyTableData = (rows) => {
return rows.map((cells) => {
return cells.map((cell) => {
return utils_1.normalizeString(String(cell));
});
});
};
exports.stringifyTableData = stringifyTableData;

View file

@ -0,0 +1,2 @@
import type { TableUserConfig } from './types/api';
export declare const table: (data: unknown[][], userConfig?: TableUserConfig) => string;

View file

@ -0,0 +1,26 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.table = void 0;
const alignTableData_1 = require("./alignTableData");
const calculateCellWidths_1 = require("./calculateCellWidths");
const calculateRowHeights_1 = require("./calculateRowHeights");
const drawTable_1 = require("./drawTable");
const makeTableConfig_1 = require("./makeTableConfig");
const mapDataUsingRowHeights_1 = require("./mapDataUsingRowHeights");
const padTableData_1 = require("./padTableData");
const stringifyTableData_1 = require("./stringifyTableData");
const truncateTableData_1 = require("./truncateTableData");
const validateTableData_1 = require("./validateTableData");
const table = (data, userConfig = {}) => {
validateTableData_1.validateTableData(data);
let rows = stringifyTableData_1.stringifyTableData(data);
const config = makeTableConfig_1.makeTableConfig(rows, userConfig);
rows = truncateTableData_1.truncateTableData(rows, config);
const rowHeights = calculateRowHeights_1.calculateRowHeights(rows, config);
rows = mapDataUsingRowHeights_1.mapDataUsingRowHeights(rows, rowHeights, config);
rows = alignTableData_1.alignTableData(rows, config);
rows = padTableData_1.padTableData(rows, config);
const cellWidths = calculateCellWidths_1.calculateCellWidths(rows[0]);
return drawTable_1.drawTable(rows, cellWidths, rowHeights, config);
};
exports.table = table;

View file

@ -0,0 +1,6 @@
import type { BaseConfig, Row } from './types/internal';
export declare const truncateString: (input: string, length: number) => string;
/**
* @todo Make it work with ASCII content.
*/
export declare const truncateTableData: (rows: Row[], config: BaseConfig) => Row[];

View file

@ -0,0 +1,23 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.truncateTableData = exports.truncateString = void 0;
const lodash_truncate_1 = __importDefault(require("lodash.truncate"));
const truncateString = (input, length) => {
return lodash_truncate_1.default(input, { length,
omission: '…' });
};
exports.truncateString = truncateString;
/**
* @todo Make it work with ASCII content.
*/
const truncateTableData = (rows, config) => {
return rows.map((cells) => {
return cells.map((cell, cellIndex) => {
return exports.truncateString(cell, config.columns[cellIndex].truncate);
});
});
};
exports.truncateTableData = truncateTableData;

View file

@ -0,0 +1,114 @@
export declare type DrawLinePredicate = (index: number, size: number) => boolean;
export declare type DrawVerticalLine = DrawLinePredicate;
export declare type DrawHorizontalLine = DrawLinePredicate;
export declare type BorderUserConfig = {
readonly topLeft?: string;
readonly topRight?: string;
readonly topBody?: string;
readonly topJoin?: string;
readonly bottomLeft?: string;
readonly bottomRight?: string;
readonly bottomBody?: string;
readonly bottomJoin?: string;
readonly joinLeft?: string;
readonly joinRight?: string;
readonly joinBody?: string;
readonly joinJoin?: string;
readonly headerJoin?: string;
readonly bodyRight?: string;
readonly bodyLeft?: string;
readonly bodyJoin?: string;
};
export declare type BorderConfig = Required<BorderUserConfig>;
export declare type Alignment = 'center' | 'justify' | 'left' | 'right';
export declare type VerticalAlignment = 'bottom' | 'middle' | 'top';
export declare type ColumnUserConfig = {
/**
* Cell content horizontal alignment (default: left)
*/
readonly alignment?: Alignment;
/**
* Cell content vertical alignment (default: top)
*/
readonly verticalAlignment?: VerticalAlignment;
/**
* Column width (default: auto calculation based on the cell content)
*/
readonly width?: number;
/**
* Number of characters are which the content will be truncated (default: Infinity)
*/
readonly truncate?: number;
/**
* Cell content padding width left (default: 1)
*/
readonly paddingLeft?: number;
/**
* Cell content padding width right (default: 1)
*/
readonly paddingRight?: number;
/**
* If true, the text is broken at the nearest space or one of the special characters: "\|/_.,;-"
*/
readonly wrapWord?: boolean;
};
export declare type HeaderUserConfig = Omit<ColumnUserConfig, 'verticalAlignment' | 'width'> & {
readonly content: string;
};
export declare type BaseUserConfig = {
/**
* Custom border
*/
readonly border?: BorderUserConfig;
/**
* Default values for all columns. Column specific settings overwrite the default values.
*/
readonly columnDefault?: ColumnUserConfig;
/**
* Column specific configuration.
*/
readonly columns?: Indexable<ColumnUserConfig>;
/**
* Used to tell whether to draw a vertical line.
* This callback is called for each non-content line of the table.
* The default behavior is to always return true.
*/
readonly drawVerticalLine?: DrawVerticalLine;
};
export declare type TableUserConfig = BaseUserConfig & {
/**
* The header configuration
*/
readonly header?: HeaderUserConfig;
/**
* Used to tell whether to draw a horizontal line.
* This callback is called for each non-content line of the table.
* The default behavior is to always return true.
*/
readonly drawHorizontalLine?: DrawHorizontalLine;
/**
* Horizontal lines inside the table are not drawn.
*/
readonly singleLine?: boolean;
};
export declare type StreamUserConfig = BaseUserConfig & {
/**
* The number of columns
*/
readonly columnCount: number;
/**
* Default values for all columns. Column specific settings overwrite the default values.
*/
readonly columnDefault: ColumnUserConfig & {
/**
* The default width for each column
*/
readonly width: number;
};
};
export declare type WritableStream = {
readonly write: (rows: string[]) => void;
};
export declare type Indexable<T> = {
readonly [index: number]: T;
};

View file

@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

View file

@ -0,0 +1 @@
export {};

View file

@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

View file

@ -0,0 +1 @@
export {};

View file

@ -0,0 +1,92 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.distributeUnevenly = exports.countSpaceSequence = exports.groupBySizes = exports.makeBorderConfig = exports.splitAnsi = exports.normalizeString = void 0;
const slice_ansi_1 = __importDefault(require("slice-ansi"));
const string_width_1 = __importDefault(require("string-width"));
const strip_ansi_1 = __importDefault(require("strip-ansi"));
const getBorderCharacters_1 = require("./getBorderCharacters");
/**
* Converts Windows-style newline to Unix-style
*
* @internal
*/
const normalizeString = (input) => {
return input.replace(/\r\n/g, '\n');
};
exports.normalizeString = normalizeString;
/**
* Splits ansi string by newlines
*
* @internal
*/
const splitAnsi = (input) => {
const lengths = strip_ansi_1.default(input).split('\n').map(string_width_1.default);
const result = [];
let startIndex = 0;
lengths.forEach((length) => {
result.push(length === 0 ? '' : slice_ansi_1.default(input, startIndex, startIndex + length));
// Plus 1 for the newline character itself
startIndex += length + 1;
});
return result;
};
exports.splitAnsi = splitAnsi;
/**
* Merges user provided border characters with the default border ("honeywell") characters.
*
* @internal
*/
const makeBorderConfig = (border) => {
return {
...getBorderCharacters_1.getBorderCharacters('honeywell'),
...border,
};
};
exports.makeBorderConfig = makeBorderConfig;
/**
* Groups the array into sub-arrays by sizes.
*
* @internal
* @example
* groupBySizes(['a', 'b', 'c', 'd', 'e'], [2, 1, 2]) = [ ['a', 'b'], ['c'], ['d', 'e'] ]
*/
const groupBySizes = (array, sizes) => {
let startIndex = 0;
return sizes.map((size) => {
const group = array.slice(startIndex, startIndex + size);
startIndex += size;
return group;
});
};
exports.groupBySizes = groupBySizes;
/**
* Counts the number of continuous spaces in a string
*
* @internal
* @example
* countGroupSpaces('a bc de f') = 3
*/
const countSpaceSequence = (input) => {
var _a, _b;
return (_b = (_a = input.match(/\s+/g)) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
};
exports.countSpaceSequence = countSpaceSequence;
/**
* Creates the non-increasing number array given sum and length
* whose the difference between maximum and minimum is not greater than 1
*
* @internal
* @example
* distributeUnevenly(6, 3) = [2, 2, 2]
* distributeUnevenly(8, 3) = [3, 3, 2]
*/
const distributeUnevenly = (sum, length) => {
const result = Array.from({ length }).fill(Math.floor(sum / length));
return result.map((element, index) => {
return element + (index < sum % length ? 1 : 0);
});
};
exports.distributeUnevenly = distributeUnevenly;

View file

@ -0,0 +1,2 @@
import type { TableUserConfig } from './types/api';
export declare const validateConfig: (schemaId: 'config.json' | 'streamConfig.json', config: TableUserConfig) => void;

View file

@ -0,0 +1,25 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.validateConfig = void 0;
const validators_1 = __importDefault(require("./generated/validators"));
const validateConfig = (schemaId, config) => {
const validate = validators_1.default[schemaId];
if (!validate(config) && validate.errors) {
const errors = validate.errors.map((error) => {
return {
message: error.message,
params: error.params,
schemaPath: error.schemaPath,
};
});
/* eslint-disable no-console */
console.log('config', config);
console.log('errors', errors);
/* eslint-enable no-console */
throw new Error('Invalid config.');
}
};
exports.validateConfig = validateConfig;

View file

@ -0,0 +1 @@
export declare const validateTableData: (rows: unknown[][]) => void;

View file

@ -0,0 +1,31 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.validateTableData = void 0;
const utils_1 = require("./utils");
const validateTableData = (rows) => {
if (!Array.isArray(rows)) {
throw new TypeError('Table data must be an array.');
}
if (rows.length === 0) {
throw new Error('Table must define at least one row.');
}
if (rows[0].length === 0) {
throw new Error('Table must define at least one column.');
}
const columnNumber = rows[0].length;
for (const row of rows) {
if (!Array.isArray(row)) {
throw new TypeError('Table row data must be an array.');
}
if (row.length !== columnNumber) {
throw new Error('Table must have a consistent number of cells.');
}
for (const cell of row) {
// eslint-disable-next-line no-control-regex
if (/[\u0001-\u0006\u0008\u0009\u000B-\u001A]/.test(utils_1.normalizeString(String(cell)))) {
throw new Error('Table data must not contain control characters.');
}
}
}
};
exports.validateTableData = validateTableData;

View file

@ -0,0 +1,8 @@
/**
* Wrap a single cell value into a list of lines
*
* Always wraps on newlines, for the remainder uses either word or string wrapping
* depending on user configuration.
*
*/
export declare const wrapCell: (cellValue: string, cellWidth: number, useWrapWord: boolean) => string[];

View file

@ -0,0 +1,32 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.wrapCell = void 0;
const utils_1 = require("./utils");
const wrapString_1 = require("./wrapString");
const wrapWord_1 = require("./wrapWord");
/**
* Wrap a single cell value into a list of lines
*
* Always wraps on newlines, for the remainder uses either word or string wrapping
* depending on user configuration.
*
*/
const wrapCell = (cellValue, cellWidth, useWrapWord) => {
// First split on literal newlines
const cellLines = utils_1.splitAnsi(cellValue);
// Then iterate over the list and word-wrap every remaining line if necessary.
for (let lineNr = 0; lineNr < cellLines.length;) {
let lineChunks;
if (useWrapWord) {
lineChunks = wrapWord_1.wrapWord(cellLines[lineNr], cellWidth);
}
else {
lineChunks = wrapString_1.wrapString(cellLines[lineNr], cellWidth);
}
// Replace our original array element with whatever the wrapping returned
cellLines.splice(lineNr, 1, ...lineChunks);
lineNr += lineChunks.length;
}
return cellLines;
};
exports.wrapCell = wrapCell;

View file

@ -0,0 +1,9 @@
/**
* Creates an array of strings split into groups the length of size.
* This function works with strings that contain ASCII characters.
*
* wrapText is different from would-be "chunk" implementation
* in that whitespace characters that occur on a chunk size limit are trimmed.
*
*/
export declare const wrapString: (subject: string, size: number) => string[];

View file

@ -0,0 +1,26 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.wrapString = void 0;
const slice_ansi_1 = __importDefault(require("slice-ansi"));
const string_width_1 = __importDefault(require("string-width"));
/**
* Creates an array of strings split into groups the length of size.
* This function works with strings that contain ASCII characters.
*
* wrapText is different from would-be "chunk" implementation
* in that whitespace characters that occur on a chunk size limit are trimmed.
*
*/
const wrapString = (subject, size) => {
let subjectSlice = subject;
const chunks = [];
do {
chunks.push(slice_ansi_1.default(subjectSlice, 0, size));
subjectSlice = slice_ansi_1.default(subjectSlice, size).trim();
} while (string_width_1.default(subjectSlice));
return chunks;
};
exports.wrapString = wrapString;

View file

@ -0,0 +1 @@
export declare const wrapWord: (input: string, size: number) => string[];

View file

@ -0,0 +1,41 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.wrapWord = void 0;
const slice_ansi_1 = __importDefault(require("slice-ansi"));
const strip_ansi_1 = __importDefault(require("strip-ansi"));
const calculateStringLengths = (input, size) => {
let subject = strip_ansi_1.default(input);
const chunks = [];
// https://regex101.com/r/gY5kZ1/1
const re = new RegExp('(^.{1,' + String(size) + '}(\\s+|$))|(^.{1,' + String(size - 1) + '}(\\\\|/|_|\\.|,|;|-))');
do {
let chunk;
const match = re.exec(subject);
if (match) {
chunk = match[0];
subject = subject.slice(chunk.length);
const trimmedLength = chunk.trim().length;
const offset = chunk.length - trimmedLength;
chunks.push([trimmedLength, offset]);
}
else {
chunk = subject.slice(0, size);
subject = subject.slice(size);
chunks.push([chunk.length, 0]);
}
} while (subject.length);
return chunks;
};
const wrapWord = (input, size) => {
const result = [];
let startIndex = 0;
calculateStringLengths(input, size).forEach(([length, offset]) => {
result.push(slice_ansi_1.default(input, startIndex, startIndex + length));
startIndex += length + offset;
});
return result;
};
exports.wrapWord = wrapWord;