From 366e3804715d6be0231909531e14ca9b6d488099 Mon Sep 17 00:00:00 2001 From: Nam Hoang Le Date: Sat, 24 Apr 2021 21:08:51 +0700 Subject: [PATCH] refactor: share drawing logic (#162) Co-authored-by: Nam Hoang Le --- src/drawBorder.ts | 10 +++++-- src/drawContent.ts | 35 +++++++++++++++++++++++++ src/drawHorizontalContent.ts | 32 ---------------------- src/drawRow.ts | 19 +++++++------- src/drawTable.ts | 51 ++++++++++++++---------------------- 5 files changed, 72 insertions(+), 75 deletions(-) create mode 100644 src/drawContent.ts delete mode 100644 src/drawHorizontalContent.ts diff --git a/src/drawBorder.ts b/src/drawBorder.ts index ce0c882..6aac445 100644 --- a/src/drawBorder.ts +++ b/src/drawBorder.ts @@ -1,4 +1,4 @@ -import drawHorizontalContent from './drawHorizontalContent'; +import drawContent from './drawContent'; import type { DrawVerticalLine, } from './types/api'; @@ -17,11 +17,17 @@ type Separator = { const drawBorder = (columnSizeIndex: number[], config: {separator: Separator, drawVerticalLine: DrawVerticalLine, }): string => { + const {separator, drawVerticalLine} = config; const columns = columnSizeIndex.map((size) => { return config.separator.body.repeat(size); }); - return drawHorizontalContent(columns, config); + return drawContent(columns, { + drawSeparator: drawVerticalLine, + endSeparator: separator.right, + middleSeparator: separator.join, + startSeparator: separator.left, + }) + '\n'; }; const drawBorderTop = (columnSizeIndex: number[], diff --git a/src/drawContent.ts b/src/drawContent.ts new file mode 100644 index 0000000..f603e76 --- /dev/null +++ b/src/drawContent.ts @@ -0,0 +1,35 @@ +type SeparatorConfig = { + drawSeparator: (index: number, size: number) => boolean, + startSeparator: string, + middleSeparator: string, + endSeparator: string, +}; + +/** + * Shared function to draw horizontal borders, rows or the entire table + */ + +export default function drawContent (contents: string[], separatorConfig: SeparatorConfig): string { + const {startSeparator, middleSeparator, endSeparator, drawSeparator} = separatorConfig; + const contentSize = contents.length; + const result: string[] = []; + + if (drawSeparator(0, contentSize)) { + result.push(startSeparator); + } + + contents.forEach((content, index) => { + result.push(content); + + // Only append the middle separator if the content is not the last + if (index + 1 < contentSize && drawSeparator(index + 1, contentSize)) { + result.push(middleSeparator); + } + }); + + if (drawSeparator(contentSize, contentSize)) { + result.push(endSeparator); + } + + return result.join(''); +} diff --git a/src/drawHorizontalContent.ts b/src/drawHorizontalContent.ts deleted file mode 100644 index 4ea7cc4..0000000 --- a/src/drawHorizontalContent.ts +++ /dev/null @@ -1,32 +0,0 @@ -import type { - DrawVerticalLine, -} from './types/api'; - -type Separator = { - readonly left: string, - readonly right: string, - readonly join: string, -}; - -export default function drawHorizontalContent (contents: string[], - config: {separator: Separator, drawVerticalLine: DrawVerticalLine, }): string { - const {separator, drawVerticalLine} = config; - const contentSize = contents.length; - const result: string[] = []; - - result.push(drawVerticalLine(0, contentSize) ? separator.left : ''); - - contents.forEach((content, index) => { - result.push(content); - - // Only append the join separator if it is not the last content - if (index + 1 < contentSize) { - result.push(drawVerticalLine(index + 1, contentSize) ? separator.join : ''); - } - }); - - result.push(drawVerticalLine(contentSize, contentSize) ? separator.right : ''); - - return result.join('') + '\n'; -} - diff --git a/src/drawRow.ts b/src/drawRow.ts index 7efa572..7bde01e 100644 --- a/src/drawRow.ts +++ b/src/drawRow.ts @@ -1,5 +1,4 @@ -import drawHorizontalContent, { -} from './drawHorizontalContent'; +import drawContent from './drawContent'; import type { DrawVerticalLine, } from './types/api'; @@ -11,12 +10,12 @@ export default (row: Row, config: { border: BodyBorderConfig, drawVerticalLine: DrawVerticalLine, }): string => { - return drawHorizontalContent(row, { - ...config, - separator: { - join: config.border.bodyJoin, - left: config.border.bodyLeft, - right: config.border.bodyRight, - }, - }); + const {border, drawVerticalLine} = config; + + return drawContent(row, { + drawSeparator: drawVerticalLine, + endSeparator: border.bodyRight, + middleSeparator: border.bodyJoin, + startSeparator: border.bodyLeft, + }) + '\n'; }; diff --git a/src/drawTable.ts b/src/drawTable.ts index 7d84fd4..d40dc90 100644 --- a/src/drawTable.ts +++ b/src/drawTable.ts @@ -1,6 +1,7 @@ import { drawBorderTop, drawBorderJoin, drawBorderBottom, } from './drawBorder'; +import drawContent from './drawContent'; import drawRow from './drawRow'; import type { TableConfig, Row, @@ -10,56 +11,44 @@ import type { * Group the array into sub-arrays by sizes. * * @example - * chunkBySizes(['a', 'b', 'c', 'd', 'e'], [2, 1, 2]) = [ ['a', 'b'], ['c'], ['d', 'e'] ] + * groupBySizes(['a', 'b', 'c', 'd', 'e'], [2, 1, 2]) = [ ['a', 'b'], ['c'], ['d', 'e'] ] */ const groupBySizes = (array: T[], sizes: number[]): T[][] => { let startIndex = 0; - return sizes.map((rowHeight) => { - const chunk = array.slice(startIndex, startIndex + rowHeight); + return sizes.map((size) => { + const group = array.slice(startIndex, startIndex + size); - startIndex += rowHeight; + startIndex += size; - return chunk; + return group; }); }; -const shouldDrawBorderJoin = (rowIndex: number, rowCount: number, config: TableConfig): boolean => { - const {singleLine, drawHorizontalLine} = config; - - return !singleLine && rowIndex + 1 < rowCount && drawHorizontalLine(rowIndex + 1, rowCount); -}; - export default (rows: Row[], columnWidths: number[], rowHeights: number[], config: TableConfig): string => { const { drawHorizontalLine, + singleLine, } = config; - const groupedRows = groupBySizes(rows, rowHeights).map((group) => { + const contents = groupBySizes(rows, rowHeights).map((group) => { return group.map((row) => { return drawRow(row, config); }).join(''); }); - const rowCount = groupedRows.length; - let output = ''; - - if (drawHorizontalLine(0, rowCount)) { - output += drawBorderTop(columnWidths, config); - } - - groupedRows.forEach((row, rowIndex) => { - output += row; - - if (shouldDrawBorderJoin(rowIndex, rowCount, config)) { - output += drawBorderJoin(columnWidths, config); - } + return drawContent(contents, { + drawSeparator: (index, size) => { + // Top/bottom border + if (index === 0 || index === size) { + return drawHorizontalLine(index, size); + } + + return !singleLine && drawHorizontalLine(index, size); + }, + endSeparator: drawBorderBottom(columnWidths, config), + middleSeparator: drawBorderJoin(columnWidths, config), + startSeparator: drawBorderTop(columnWidths, config), }); - - if (drawHorizontalLine(rowCount, rowCount)) { - output += drawBorderBottom(columnWidths, config); - } - - return output; };