Skip to content

Commit

Permalink
feat: implement multi-table sheet layout params
Browse files Browse the repository at this point in the history
  • Loading branch information
ChronicStone committed Dec 6, 2023
1 parent f0e1bca commit 9b49c17
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 25 deletions.
47 changes: 28 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,35 +102,44 @@ const assessmentExport = ExcelSchemaBuilder
```ts
import { ExcelBuilder } from '@chronicstone/typed-xlsx'

const arrayBuffer = ExcelBuilder
const buffer = ExcelBuilder
.create()
.sheet('Users - full', {
.sheet('Users - full')
.addTable({
data: users,
schema: assessmentExport,
context: {
'group:org': organizations
}
context: { 'group:org': organizations },
})
.sheet('Users - partial', {
.addTable({
data: users,
schema: assessmentExport,
select: {
firstName: true,
lastName: true,
email: true
}
select: { firstName: true, lastName: true, email: true },
})
.sheet('User - neg partial', {
.sheet('Users - partial')
.addTable({
data: users,
schema: assessmentExport,
select: {
firstName: false,
lastName: false,
email: false,
},
select: { firstName: true, lastName: true, email: true, },
})
.sheet('User - neg partial')
.addTable({
data: users,
schema: assessmentExport,
select: { firstName: false, lastName: false, email: false, },
context: {
'group:org': organizations
}
'group:org': organizations,
},
})
.sheet('User - Multiple tables')
.addTable({
data: users.filter((_, i) => i < 10),
schema: assessmentExport,
select: { firstName: true, lastName: true, email: true },
})
.addTable({
data: users.filter((_, i) => i < 10),
schema: assessmentExport,
select: { firstName: true, lastName: true, email: true },
})
.build({ output: 'buffer' })

Expand Down
Binary file modified example.xlsx
Binary file not shown.
19 changes: 16 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable ts/ban-types */
import XLSX, { type CellStyle, type WorkSheet, utils } from 'xlsx-js-style'
import { deepmerge } from 'deepmerge-ts'
import type { CellValue, Column, ColumnGroup, ExcelBuildOutput, ExcelBuildParams, ExcelSchema, GenericObject, NestedPaths, Not, SchemaColumnKeys, SheetConfig, SheetTable, SheetTableBuilder, TOutputType, TableSummary, TransformersMap } from './types'
import type { CellValue, Column, ColumnGroup, ExcelBuildOutput, ExcelBuildParams, ExcelSchema, GenericObject, NestedPaths, Not, SchemaColumnKeys, SheetConfig, SheetParams, SheetTable, SheetTableBuilder, TOutputType, TableSummary, TransformersMap } from './types'
import { buildSheetConfig, getCellDataType, getColumnHeaderStyle, getWorksheetColumnWidths } from './utils'

export class ExcelSchemaBuilder<
Expand Down Expand Up @@ -105,11 +105,12 @@ export class ExcelBuilder<UsedSheetKeys extends string = never> {

public sheet<Key extends string>(
key: Not<Key, UsedSheetKeys>,
params?: SheetParams,
): SheetTableBuilder<ExcelBuilder<UsedSheetKeys | Key>, UsedSheetKeys | Key> {
if (this.sheets.some(s => s.sheetKey === key))
throw new Error(`Sheet with key '${key}' already exists.`)

this.sheets.push({ sheetKey: key, tables: [] })
this.sheets.push({ sheetKey: key, params: params ?? {}, tables: [] })
return {
addTable: table => this.defineTable(key, table as any),
sheet: key => this.sheet(key as any),
Expand Down Expand Up @@ -146,7 +147,7 @@ export class ExcelBuilder<UsedSheetKeys extends string = never> {
const _sheets = buildSheetConfig(this.sheets)
const workbook = utils.book_new()

const TABLE_CELL_OFFSET = 2
const TABLE_CELL_OFFSET = 1

_sheets.forEach((sheetConfig) => {
const worksheet: WorkSheet = {}
Expand Down Expand Up @@ -260,6 +261,15 @@ export class ExcelBuilder<UsedSheetKeys extends string = never> {
return Math.max(acc, table.content.length + (hasSummary ? 2 : 1))
}, 0)

const colSeparatorIndexes = sheetConfig.tables.map((table, index) => {
if (index === sheetConfig.tables.length - 1)
return []

const tableConfig = sheetConfig.tables[index]
const colsCount = tableConfig.columns.length
return Array.from({ length: TABLE_CELL_OFFSET }, (_, i) => colsCount + i)
}).flat()

worksheet['!ref'] = `A1:${utils.encode_cell({ c: totalCols, r: maxRows })}`

worksheet['!rows'] = Array.from(
Expand All @@ -268,6 +278,9 @@ export class ExcelBuilder<UsedSheetKeys extends string = never> {
)

worksheet['!cols'] = getWorksheetColumnWidths(worksheet, params?.extraLength ?? 5)
.map(({ wch }, index) => ({
wch: colSeparatorIndexes.includes(index) ? sheetConfig.params?.tableSeparatorWidth ?? 25 : wch,
}))

utils.book_append_sheet(workbook, worksheet, sheetConfig.sheet)
})
Expand Down
7 changes: 7 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,15 @@ export interface SheetTableBuilder<
build: Builder['build']
}

export interface SheetParams {
tableSeparatorWidth?: number
tablesPerRow?: number

}

export interface SheetConfig {
sheetKey: string
params: SheetParams
tables: Array<SheetTable<GenericObject, ExcelSchema<any, any, any, any>, any, any, any, any, any>>
}

Expand Down
1 change: 1 addition & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export function getCellDataType(value: CellValue): ExcelDataType {
export function buildSheetConfig(sheets: Array<SheetConfig>) {
return sheets.map(sheet => ({
sheet: sheet.sheetKey,
params: sheet.params,
tables: sheet.tables.map(table => ({
content: table.data,
summary: table.schema.summary,
Expand Down
15 changes: 12 additions & 3 deletions test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,7 @@ describe('should generate the example excel', () => {
.addTable({
data: users,
schema: assessmentExport,
context: {
'group:org': organizations,
},
select: { firstName: true, lastName: true, email: true },
})
.sheet('Users - partial')
.addTable({
Expand All @@ -139,6 +137,17 @@ describe('should generate the example excel', () => {
'group:org': organizations,
},
})
.sheet('User - Multiple tables')
.addTable({
data: users.filter((_, i) => i < 10),
schema: assessmentExport,
select: { firstName: true, lastName: true, email: true },
})
.addTable({
data: users.filter((_, i) => i < 10),
schema: assessmentExport,
select: { firstName: true, lastName: true, email: true },
})
.build({ output: 'buffer' })

fs.writeFileSync('example.xlsx', buffer)
Expand Down

0 comments on commit 9b49c17

Please sign in to comment.