From 1c9f1bd875af5308ff44295b284329c1ef7c5311 Mon Sep 17 00:00:00 2001 From: Heinrich Lukas Weil Date: Tue, 18 Jul 2023 12:23:07 +0200 Subject: [PATCH] use attachmembers for improved javascript transpilation --- package.json | 1 + src/FsSpreadsheet.ExcelIO/FsExtensions.fs | 2 +- .../FsSparseMatrix.fs | 3 +- .../FsSpreadsheet.Interactive.fsproj | 1 + src/FsSpreadsheet/Cells/FsCell.fs | 16 +-- src/FsSpreadsheet/FsColumn.fs | 21 +-- src/FsSpreadsheet/FsRow.fs | 19 ++- src/FsSpreadsheet/FsSpreadsheet.fsproj | 5 +- src/FsSpreadsheet/FsWorkbook.fs | 54 ++++--- src/FsSpreadsheet/FsWorksheet.fs | 38 ++--- src/FsSpreadsheet/Ranges/FsRange.fs | 2 +- src/FsSpreadsheet/Ranges/FsRangeAddress.fs | 4 +- src/FsSpreadsheet/Ranges/FsRangeBase.fs | 7 +- src/FsSpreadsheet/Ranges/FsRangeColumn.fs | 2 +- src/FsSpreadsheet/Ranges/FsRangeRow.fs | 2 +- src/FsSpreadsheet/SheetBuilder.fs | 2 +- src/FsSpreadsheet/Tables/FsTable.fs | 133 ++++++++---------- src/FsSpreadsheet/Tables/FsTableField.fs | 2 +- .../FsSpreadsheet.ExcelIO.Tests.fsproj | 8 +- tests/FsSpreadsheet.ExcelIO.Tests/Main.fs | 2 +- tests/FsSpreadsheet.Tests/FsColumn.fs | 12 +- .../FsSpreadsheet.Tests.fsproj | 4 + tests/FsSpreadsheet.Tests/FsTable.fs | 8 +- 23 files changed, 176 insertions(+), 172 deletions(-) rename src/{FsSpreadsheet => FsSpreadsheet.Interactive}/FsSparseMatrix.fs (98%) diff --git a/package.json b/package.json index 8b711ad5..a5298d0d 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "description": "Spreadsheet creation and manipulation in FSharp", "type": "module", "scripts": { + "fable-js": "dotnet fable ./src/FsSpreadsheet -o ./js", "pretest": "dotnet fable tests/FsSpreadsheet.Tests -o tests/FsSpreadsheet.JsNativeTests/fable", "test": "mocha tests/FsSpreadsheet.JsNativeTests/fable", "posttest": "mocha tests/FsSpreadsheet.JsNativeTests" diff --git a/src/FsSpreadsheet.ExcelIO/FsExtensions.fs b/src/FsSpreadsheet.ExcelIO/FsExtensions.fs index d7f46374..07ab48c0 100644 --- a/src/FsSpreadsheet.ExcelIO/FsExtensions.fs +++ b/src/FsSpreadsheet.ExcelIO/FsExtensions.fs @@ -56,7 +56,7 @@ module FsExtensions = member self.ToXlsxTable(cells : FsCellsCollection) = let columns = - self.FieldNames(cells) + self.GetFieldNames(cells) |> Seq.map (fun kv -> Table.TableColumn.create (1 + kv.Value.Index |> uint) kv.Value.Name ) diff --git a/src/FsSpreadsheet/FsSparseMatrix.fs b/src/FsSpreadsheet.Interactive/FsSparseMatrix.fs similarity index 98% rename from src/FsSpreadsheet/FsSparseMatrix.fs rename to src/FsSpreadsheet.Interactive/FsSparseMatrix.fs index d52ad880..d88272c9 100644 --- a/src/FsSpreadsheet/FsSparseMatrix.fs +++ b/src/FsSpreadsheet.Interactive/FsSparseMatrix.fs @@ -1,5 +1,6 @@ -namespace FsSpreadsheet +namespace FsSpreadsheet.Interactive +open FsSpreadsheet /// A FsSparseMatrix type FsSparseMatrix<'T>(defaultEmptyValue: 'T,sparseValues : 'T array, sparseRowOffsets : int array, ncols:int, columnValues: int array) = diff --git a/src/FsSpreadsheet.Interactive/FsSpreadsheet.Interactive.fsproj b/src/FsSpreadsheet.Interactive/FsSpreadsheet.Interactive.fsproj index c351fc32..f0297251 100644 --- a/src/FsSpreadsheet.Interactive/FsSpreadsheet.Interactive.fsproj +++ b/src/FsSpreadsheet.Interactive/FsSpreadsheet.Interactive.fsproj @@ -30,6 +30,7 @@ + diff --git a/src/FsSpreadsheet/Cells/FsCell.fs b/src/FsSpreadsheet/Cells/FsCell.fs index dba7fcd1..b084118d 100644 --- a/src/FsSpreadsheet/Cells/FsCell.fs +++ b/src/FsSpreadsheet/Cells/FsCell.fs @@ -40,29 +40,23 @@ type DataType = /// /// Creates an FsCell of `DataType` dataType, with value of type `string`, and `FsAddress` address. /// -type FsCell (value : IConvertible, dataType : DataType, address : FsAddress) = +type FsCell (value : IConvertible, ?dataType : DataType, ?address : FsAddress) = // TODO: Maybe save as IConvertible let mutable _cellValue = string value - let mutable _dataType = dataType + let mutable _dataType = dataType |> Option.defaultValue DataType.String let mutable _comment = "" let mutable _hyperlink = "" let mutable _richText = "" let mutable _formulaA1 = "" let mutable _formulaR1C1 = "" - let mutable _rowIndex : int = address.RowNumber - let mutable _columnIndex : int = address.ColumnNumber + let mutable _rowIndex : int = address |> Option.map (fun a -> a.RowNumber) |> Option.defaultValue 0 + let mutable _columnIndex : int = address |> Option.map (fun a -> a.ColumnNumber) |> Option.defaultValue 0 - // ------------------------ - // ALTERNATIVE CONSTRUCTORS - // ------------------------ - - new (value : IConvertible) = FsCell (string value, DataType.String, FsAddress(0,0)) - ///// Creates an empty FsCell, set at row 1, column 1 (1-based). - //new () = FsCell ("", DataType.Empty, FsAddress(0,0)) + static member empty () = FsCell ("", DataType.Empty, FsAddress(0,0)) ///// Creates an FsCell of `DataType` `Number`, with the given value, set at row 1, column 1 (1-based). //new (value : int) = FsCell (string value, DataType.Number, FsAddress(0,0)) diff --git a/src/FsSpreadsheet/FsColumn.fs b/src/FsSpreadsheet/FsColumn.fs index 439321df..849c866a 100644 --- a/src/FsSpreadsheet/FsColumn.fs +++ b/src/FsSpreadsheet/FsColumn.fs @@ -3,26 +3,31 @@ open System.Collections.Generic open System.Collections - +open Fable.Core // Type based on the type XLRow used in ClosedXml /// /// Creates an FsColumn from the given FsRangeAddress, consisting of FsCells within a given FsCellsCollection, and a styleValue. /// /// The FsCellsCollection must only cover 1 column! /// if given FsCellsCollection has more than 1 column. +[] type FsColumn (rangeAddress : FsRangeAddress, cells : FsCellsCollection)= - inherit FsRangeBase(rangeAddress, null) + inherit FsRangeBase(rangeAddress) let cells = cells - new() = FsColumn (FsRangeAddress(FsAddress(0,0),FsAddress(0,0)),FsCellsCollection()) + // ---------- + // Creation + // ---------- + + static member empty() = FsColumn (FsRangeAddress(FsAddress(0,0),FsAddress(0,0)),FsCellsCollection()) /// /// Create an FsColumn from a given FsCellsCollection and an columnColumn. /// /// The appropriate range of the cells (i.e. minimum colIndex and maximum colIndex) is derived from the FsCells with the matching rowIndex. - new(index, (cells : FsCellsCollection)) = + static member createAt(index : int32, (cells : FsCellsCollection)) = let getIndexBy (f : (FsCell -> int) -> seq -> FsCell) = match cells.GetCellsInColumn index |> Seq.length with | 0 -> 1 @@ -35,8 +40,6 @@ type FsColumn (rangeAddress : FsRangeAddress, cells : FsCellsCollection)= let maxRowIndex = getIndexBy Seq.maxBy FsColumn (FsRangeAddress(FsAddress(minRowIndex, index),FsAddress(maxRowIndex, index)), cells) - new (columnRange : FsRangeColumn, cells : FsCellsCollection) = FsColumn(columnRange.RangeAddress,cells) - interface IEnumerable with member this.GetEnumerator() : System.Collections.Generic.IEnumerator = this.Cells.GetEnumerator() @@ -100,9 +103,9 @@ type FsColumn (rangeAddress : FsRangeAddress, cells : FsCellsCollection)= static member item rowIndex (column : FsColumn) = column.Item(rowIndex) - /// - /// Inserts the value at columnIndex as an FsCell. If there is an FsCell at the position, this FsCells and all the ones right to it are shifted to the right. - /// + ///// + ///// Inserts the value at columnIndex as an FsCell. If there is an FsCell at the position, this FsCells and all the ones /right /to it are shifted to the right. + ///// //member this.InsertValueAt(colIndex, (value : 'a)) = // let cell = FsCell(value) // cells.Add(int32 this.Index, int32 colIndex, cell) diff --git a/src/FsSpreadsheet/FsRow.fs b/src/FsSpreadsheet/FsRow.fs index c49eebda..88620a36 100644 --- a/src/FsSpreadsheet/FsRow.fs +++ b/src/FsSpreadsheet/FsRow.fs @@ -3,26 +3,31 @@ open System.Collections.Generic open System.Collections - +open Fable.Core // Type based on the type XLRow used in ClosedXml /// /// Creates an FsRow from the given FsRangeAddress, consisting of FsCells within a given FsCellsCollection, and a styleValue. /// /// The FsCellsCollection must only cover 1 row! /// if given FsCellsCollection has more than 1 row. -type FsRow (rangeAddress : FsRangeAddress, cells : FsCellsCollection, styleValue)= +[] +type FsRow (rangeAddress : FsRangeAddress, cells : FsCellsCollection)= - inherit FsRangeBase(rangeAddress, styleValue) + inherit FsRangeBase(rangeAddress) let cells = cells - new() = FsRow (FsRangeAddress(FsAddress(0,0),FsAddress(0,0)),FsCellsCollection(),null) + // ---------- + // Creation + // ---------- + + static member empty() = FsRow (FsRangeAddress(FsAddress(0,0),FsAddress(0,0)),FsCellsCollection()) /// /// Create an FsRow from a given FsCellsCollection and an rowIndex. /// /// The appropriate range of the cells (i.e. minimum colIndex and maximum colIndex) is derived from the FsCells with the matching rowIndex. - new(index, (cells : FsCellsCollection)) = + static member createAt(index, (cells : FsCellsCollection)) = let getIndexBy (f : (FsCell -> int) -> seq -> FsCell) = match cells.GetCellsInRow index |> Seq.length with | 0 -> 1 @@ -33,7 +38,7 @@ type FsRow (rangeAddress : FsRangeAddress, cells : FsCellsCollection, styleValue ).Address.ColumnNumber let minColIndex = getIndexBy Seq.minBy let maxColIndex = getIndexBy Seq.maxBy - FsRow (FsRangeAddress(FsAddress(index, minColIndex),FsAddress(index, maxColIndex)), cells, null) + FsRow (FsRangeAddress(FsAddress(index, minColIndex),FsAddress(index, maxColIndex)), cells) interface IEnumerable with member this.GetEnumerator() : System.Collections.Generic.IEnumerator = this.Cells.GetEnumerator() @@ -71,7 +76,7 @@ type FsRow (rangeAddress : FsRangeAddress, cells : FsCellsCollection, styleValue let cells = self.Cells |> Seq.map (fun c -> c.Copy()) let fcc = FsCellsCollection() fcc.Add cells - FsRow(ra, fcc, null) + FsRow(ra, fcc) /// /// Returns a deep copy of a given FsRow. diff --git a/src/FsSpreadsheet/FsSpreadsheet.fsproj b/src/FsSpreadsheet/FsSpreadsheet.fsproj index 10581d63..0376e21d 100644 --- a/src/FsSpreadsheet/FsSpreadsheet.fsproj +++ b/src/FsSpreadsheet/FsSpreadsheet.fsproj @@ -6,7 +6,6 @@ - @@ -52,4 +51,8 @@ + + + + diff --git a/src/FsSpreadsheet/FsWorkbook.fs b/src/FsSpreadsheet/FsWorkbook.fs index fe2eff0b..267c2091 100644 --- a/src/FsSpreadsheet/FsWorkbook.fs +++ b/src/FsSpreadsheet/FsWorkbook.fs @@ -1,9 +1,11 @@ namespace FsSpreadsheet - +open Fable.Core /// /// Creates an empty FsWorkbook. /// + +[] type FsWorkbook() = let mutable _worksheets = [] @@ -39,15 +41,15 @@ type FsWorkbook() = /// /// Adds an empty FsWorksheet with given name to the FsWorkbook. /// - member self.AddWorksheet(name : string) = + member self.InitWorksheet(name : string) = let sheet = FsWorksheet name _worksheets <- List.append _worksheets [sheet] /// /// Adds an empty FsWorksheet with given name to an FsWorkbook. /// - static member addWorksheetWithName (name : string) (workbook : FsWorkbook) = - workbook.AddWorksheet name + static member initWorksheet (name : string) (workbook : FsWorkbook) = + workbook.InitWorksheet name workbook @@ -93,6 +95,34 @@ type FsWorkbook() = static member getWorksheets (workbook : FsWorkbook) = workbook.GetWorksheets() + /// + /// Returns the FsWorksheet with the given 1 based index if it exists. Else returns None. + /// + member self.TryGetWorksheetAt(index : int) = + _worksheets |> List.tryItem (index - 1) + + /// + /// Returns the FsWorksheet with the given 1 based index if it exists in a given FsWorkbook. Else returns None. + /// + static member tryGetWorksheetAt (index : int) (workbook : FsWorkbook) = + workbook.TryGetWorksheetAt index + + /// + /// Returns the FsWorksheet with the given 1 based index. + /// + /// if FsWorksheet with at position is not present in the FsWorkkbook. + member self.GetWorksheetAt(index : int) = + match self.TryGetWorksheetAt index with + | Some w -> w + | None -> failwith $"FsWorksheet at position {index} is not present in the FsWorkbook." + + /// + /// Returns the FsWorksheet with the given the given 1 based indexk. + /// + /// if FsWorksheet with at position is not present in the FsWorkkbook. + static member getWorksheetAt (index : int) (workbook : FsWorkbook) = + workbook.GetWorksheetAt index + /// /// Returns the FsWorksheet with the given name if it exists in the FsWorkbook. Else returns None. /// @@ -134,24 +164,10 @@ type FsWorkbook() = /// /// Removes an FsWorksheet with given name from an FsWorkbook. /// - static member removeWorksheetByName (name : string) (workbook : FsWorkbook) = + static member removeWorksheet (name : string) (workbook : FsWorkbook) = workbook.RemoveWorksheet name workbook - /// - /// Removes a given FsWorksheet. - /// - /// if FsWorksheet with given name is not present in the FsWorkkbook. - member self.RemoveWorksheet(sheet : FsWorksheet) = - self.RemoveWorksheet(sheet.Name) - - /// - /// Removes a given FsWorksheet from an FsWorkbook. - /// - static member removeWorksheet (sheet : FsWorksheet) (workbook : FsWorkbook) = - workbook.RemoveWorksheet sheet - workbook - /// /// Returns all FsTables from the FsWorkbook. /// diff --git a/src/FsSpreadsheet/FsWorksheet.fs b/src/FsSpreadsheet/FsWorksheet.fs index 1665c6d8..a5139cbf 100644 --- a/src/FsSpreadsheet/FsWorksheet.fs +++ b/src/FsSpreadsheet/FsWorksheet.fs @@ -1,29 +1,26 @@ namespace FsSpreadsheet +open Fable.Core + // Type based on the type XLWorksheet used in ClosedXml /// /// Creates an FsWorksheet with the given name, FsRows, FsTables, and FsCellsCollection. /// -type FsWorksheet (name, fsRows, fsTables, fsCellsCollection) = +[] +type FsWorksheet (name, ?fsRows, ?fsTables, ?fsCellsCollection) = let mutable _name = name - let mutable _rows : FsRow list = fsRows - - let mutable _tables : FsTable list = fsTables + let mutable _rows : FsRow list = fsRows |> Option.defaultValue [] - let mutable _cells : FsCellsCollection = fsCellsCollection + let mutable _tables : FsTable list = fsTables |> Option.defaultValue [] - /// - /// Creates an empty FsWorksheet. - /// - new () = - FsWorksheet("") + let mutable _cells : FsCellsCollection = fsCellsCollection |> Option.defaultValue (FsCellsCollection()) /// /// Creates an empty FsWorksheet with the given name. /// - new (name) = + static member init (name) = FsWorksheet(name, [], [], FsCellsCollection()) // TO DO: finish @@ -131,14 +128,14 @@ type FsWorksheet (name, fsRows, fsTables, fsCellsCollection) = | Some row -> row | None -> - let row = FsRow(rowIndex,self.CellCollection) + let row = FsRow.createAt(rowIndex,self.CellCollection) _rows <- List.append _rows [row] row /// /// Returns the FsRow at the given FsRangeAddress. If it does not exist, it is created and appended first. /// - member self.Row(rangeAddress : FsRangeAddress) = + member self.RowWithRange(rangeAddress : FsRangeAddress) = if rangeAddress.FirstAddress.RowNumber <> rangeAddress.LastAddress.RowNumber then failwithf "Row may not have a range address spanning over different row indices" self.Row(rangeAddress.FirstAddress.RowNumber).RangeAddress <- rangeAddress @@ -357,7 +354,7 @@ type FsWorksheet (name, fsRows, fsTables, fsCellsCollection) = | Some row -> row.RangeAddress <- newRange | None -> - self.Row(newRange) + self.RowWithRange(newRange) ) @@ -369,12 +366,12 @@ type FsWorksheet (name, fsRows, fsTables, fsCellsCollection) = /// /// Returns the FsColumn at the given index. If it does not exist, it is created and appended first. /// - member self.Column(columnIndex : int32) = FsColumn(columnIndex,self.CellCollection) + member self.Column(columnIndex : int32) = FsColumn.createAt(columnIndex,self.CellCollection) /// /// Returns the FsColumn at the given FsRangeAddress. If it does not exist, it is created and appended first. /// - member self.Column(rangeAddress : FsRangeAddress) = + member self.ColumnWithRange(rangeAddress : FsRangeAddress) = if rangeAddress.FirstAddress.ColumnNumber <> rangeAddress.LastAddress.ColumnNumber then failwithf "Column may not have a range address spanning over different column indices" self.Column(rangeAddress.FirstAddress.ColumnNumber).RangeAddress <- rangeAddress @@ -408,7 +405,8 @@ type FsWorksheet (name, fsRows, fsTables, fsCellsCollection) = /// Returns the FsTable with the given tableName, rangeAddress, and showHeaderRow parameters. If it does not exist yet, it gets created and appended first. /// // TO DO: Ask HLW: Is this really a good name for the method? - member self.Table(tableName,rangeAddress,showHeaderRow) = + member self.Table(tableName,rangeAddress,?showHeaderRow : bool) = + let showHeaderRow = defaultArg showHeaderRow true match _tables |> List.tryFind (fun table -> table.Name = name) with | Some table -> table @@ -416,12 +414,6 @@ type FsWorksheet (name, fsRows, fsTables, fsCellsCollection) = let table = FsTable(tableName,rangeAddress,showHeaderRow) _tables <- List.append _tables [table] table - - /// - /// Returns the FsTable with the given tableName and rangeAddress parameters. If it does not exist yet, it gets created first. ShowHeaderRow is true by default. - /// - member self.Table(tableName,rangeAddress) = - self.Table(tableName,rangeAddress,true) /// /// Returns the FsTable of the given name from an FsWorksheet if it exists. Else returns None. diff --git a/src/FsSpreadsheet/Ranges/FsRange.fs b/src/FsSpreadsheet/Ranges/FsRange.fs index ff2f6aa0..2705d59d 100644 --- a/src/FsSpreadsheet/Ranges/FsRange.fs +++ b/src/FsSpreadsheet/Ranges/FsRange.fs @@ -3,7 +3,7 @@ type FsRange(rangeAddress : FsRangeAddress, styleValue) = - inherit FsRangeBase(rangeAddress, styleValue) + inherit FsRangeBase(rangeAddress) new (rangeAddress : FsRangeAddress) = FsRange(rangeAddress, null) new (rangeBase : FsRangeBase) = FsRange(rangeBase.RangeAddress, null) diff --git a/src/FsSpreadsheet/Ranges/FsRangeAddress.fs b/src/FsSpreadsheet/Ranges/FsRangeAddress.fs index 0aee0d44..25a6d704 100644 --- a/src/FsSpreadsheet/Ranges/FsRangeAddress.fs +++ b/src/FsSpreadsheet/Ranges/FsRangeAddress.fs @@ -210,9 +210,9 @@ type FsRangeAddress(firstAddress : FsAddress, lastAddress : FsAddress) = override self.ToString() = self.Range - member self.FirstAddress = _firstAddress + member self.FirstAddress : FsAddress = _firstAddress - member self.LastAddress = _lastAddress + member self.LastAddress : FsAddress = _lastAddress member self.Union(rangeAddress : FsRangeAddress) = self.Extend(rangeAddress.FirstAddress) diff --git a/src/FsSpreadsheet/Ranges/FsRangeBase.fs b/src/FsSpreadsheet/Ranges/FsRangeBase.fs index 4cb41bde..52bc643c 100644 --- a/src/FsSpreadsheet/Ranges/FsRangeBase.fs +++ b/src/FsSpreadsheet/Ranges/FsRangeBase.fs @@ -1,7 +1,7 @@ namespace FsSpreadsheet [][] -type FsRangeBase (rangeAddress : FsRangeAddress, styleValue) = +type FsRangeBase (rangeAddress : FsRangeAddress) = //: XLStylizedBase, IXLRangeBase, IXLStylized @@ -9,15 +9,12 @@ type FsRangeBase (rangeAddress : FsRangeAddress, styleValue) = let mutable _sortColumns = null let mutable _rangeAddress = rangeAddress - let mutable _styleValue = styleValue static let mutable IdCounter = 0; let _id = IdCounter <- IdCounter + 1 IdCounter - new (rangeAddress) = FsRangeBase(rangeAddress, null) - //abstract member OnRangeAddressChanged : FsRangeAddress*FsRangeAddress -> unit //default self.OnRangeAddressChanged (oldAddress, newAddress) = @@ -78,7 +75,7 @@ type FsRangeBase (rangeAddress : FsRangeAddress, styleValue) = member self.Cells(cells : FsCellsCollection) = cells.GetCells(self.RangeAddress.FirstAddress, self.RangeAddress.LastAddress) - member self.Cells(cells : FsCellsCollection, predicate : FsCell -> bool) = + member self.CellsSelect(cells : FsCellsCollection, predicate : FsCell -> bool) = cells.GetCells(self.RangeAddress.FirstAddress, self.RangeAddress.LastAddress, predicate) member self.ColumnCount() = diff --git a/src/FsSpreadsheet/Ranges/FsRangeColumn.fs b/src/FsSpreadsheet/Ranges/FsRangeColumn.fs index a7489bb2..3be5a76a 100644 --- a/src/FsSpreadsheet/Ranges/FsRangeColumn.fs +++ b/src/FsSpreadsheet/Ranges/FsRangeColumn.fs @@ -3,7 +3,7 @@ [] type FsRangeColumn(rangeAddress) = - inherit FsRangeBase(rangeAddress, null) + inherit FsRangeBase(rangeAddress) //new () = // let range = FsRangeAddress(FsAddress(0,0),FsAddress(0,0)) diff --git a/src/FsSpreadsheet/Ranges/FsRangeRow.fs b/src/FsSpreadsheet/Ranges/FsRangeRow.fs index 2cab4eba..0631ba7b 100644 --- a/src/FsSpreadsheet/Ranges/FsRangeRow.fs +++ b/src/FsSpreadsheet/Ranges/FsRangeRow.fs @@ -3,7 +3,7 @@ [] type FsRangeRow(rangeAddress) = - inherit FsRangeBase(rangeAddress, null) + inherit FsRangeBase(rangeAddress) //new () = // let range = FsRangeAddress(FsAddress(0,0),FsAddress(0,0)) diff --git a/src/FsSpreadsheet/SheetBuilder.fs b/src/FsSpreadsheet/SheetBuilder.fs index f6af1df3..6ed7135e 100644 --- a/src/FsSpreadsheet/SheetBuilder.fs +++ b/src/FsSpreadsheet/SheetBuilder.fs @@ -227,7 +227,7 @@ module SheetBuilder = type FsWorkbook with member self.Populate<'T>(name : string, data : seq<'T>, fields : FieldMap<'T> list) : unit = - self.AddWorksheet(name) + self.InitWorksheet(name) let sheet = self.GetWorksheets() |> Seq.find (fun s -> s.Name = name) FsWorksheet.populate(sheet, data, fields) diff --git a/src/FsSpreadsheet/Tables/FsTable.fs b/src/FsSpreadsheet/Tables/FsTable.fs index 3427e98a..d47855d7 100644 --- a/src/FsSpreadsheet/Tables/FsTable.fs +++ b/src/FsSpreadsheet/Tables/FsTable.fs @@ -2,33 +2,25 @@ open System.Collections.Generic +open Fable.Core + /// /// Creates an FsTable from the given name and FsRangeAddres, with totals row shown and header row shown or not, accordingly. /// -type FsTable (name : string, rangeAddress, showTotalsRow, showHeaderRow) = +[] +type FsTable (name : string, rangeAddress : FsRangeAddress, ?showTotalsRow : bool, ?showHeaderRow : bool) = - inherit FsRangeBase(rangeAddress, null) + inherit FsRangeBase(rangeAddress) let mutable _name = name let mutable _lastRangeAddress = rangeAddress - let mutable _showTotalsRow : bool = showTotalsRow - let mutable _showHeaderRow : bool = showHeaderRow + let mutable _showTotalsRow : bool = Option.defaultValue false showTotalsRow + let mutable _showHeaderRow : bool = Option.defaultValue true showHeaderRow let mutable _fieldNames : Dictionary = Dictionary() let _uniqueNames : HashSet = HashSet() - /// - /// Creates an FsTable from the given name and FsRangeAddres, with header row shown or not, accordingly. - /// - /// `showTotalsRow` is false by default. - new (name, rangeAddress, showHeaderRow) = FsTable (name, rangeAddress, false, showHeaderRow) - - /// - /// Creates an FsTable from the given name and FsRangeAddres. - /// - /// `showTotalsRow` is false and `showHeaderRow` true, by default. - new (name, rangeAddress) = FsTable (name, rangeAddress, false, true) /// /// The name of the FsTable. @@ -39,25 +31,23 @@ type FsTable (name : string, rangeAddress, showTotalsRow, showHeaderRow) = /// /// Returns all fieldnames as `fieldname*FsTableField` dictionary. /// - member self.FieldNames - with get(cellsCollection) = - if (_fieldNames <> null && _lastRangeAddress <> null && _lastRangeAddress.Equals(self.RangeAddress)) then - _fieldNames; - else - _lastRangeAddress <- self.RangeAddress + member self.GetFieldNames (cellsCollection : FsCellsCollection) = + if (_fieldNames <> null && _lastRangeAddress <> null && _lastRangeAddress.Equals(self.RangeAddress)) then + _fieldNames; + else + _lastRangeAddress <- self.RangeAddress - //self.RescanFieldNames(cellsCollection) + //self.RescanFieldNames(cellsCollection) - _fieldNames; + _fieldNames; /// /// The FsTableFields of this FsTable. /// - member self.Fields - with get(cellsCollection) = - let columnCount = base.ColumnCount() - //let offset = base.RangeAddress.FirstAddress.ColumnNumber - Seq.init columnCount (fun i -> self.GetField(i, cellsCollection)) + member self.GetFields (cellsCollection : FsCellsCollection) = + let columnCount = base.ColumnCount() + //let offset = base.RangeAddress.FirstAddress.ColumnNumber + Seq.init columnCount (fun i -> self.GetFieldAt(i, cellsCollection)) /// /// Gets or sets if the header row is shown. @@ -66,38 +56,25 @@ type FsTable (name : string, rangeAddress, showTotalsRow, showHeaderRow) = with get () = _showHeaderRow and set(showHeaderRow) = _showHeaderRow <- showHeaderRow - /// - /// Returns the header row as FsRangeRow. Scans for fieldnames if `scanForNewFieldsNames` is true. - /// - member self.HeadersRow(scanForNewFieldsNames : bool) = - if (not self.ShowHeaderRow) then null; - - else - //if (scanForNewFieldsNames) then - - // let tempResult = this.FieldNames; - // () - - FsRange(base.RangeAddress).FirstRow(); - /// /// Returns the header row as FsRangeRow. Scans for new fieldnames. /// member self.HeadersRow() = - self.HeadersRow(true) + if (not self.ShowHeaderRow) then null; + else + FsRange(base.RangeAddress).FirstRow(); /// /// Returns the columns from the table. /// - member self.Columns - with get(cellsCollection : FsCellsCollection) = - seq { - for i = self.RangeAddress.FirstAddress.ColumnNumber to self.RangeAddress.LastAddress.ColumnNumber do - let firstAddress = FsAddress(self.RangeAddress.FirstAddress.RowNumber,i) - let lastAddress = FsAddress(self.RangeAddress.LastAddress.RowNumber,i) - let range = FsRangeAddress (firstAddress,lastAddress) - FsColumn(range,cellsCollection) - } + member self.GetColumns (cellsCollection : FsCellsCollection) = + seq { + for i = self.RangeAddress.FirstAddress.ColumnNumber to self.RangeAddress.LastAddress.ColumnNumber do + let firstAddress = FsAddress(self.RangeAddress.FirstAddress.RowNumber,i) + let lastAddress = FsAddress(self.RangeAddress.LastAddress.RowNumber,i) + let range = FsRangeAddress (firstAddress,lastAddress) + FsColumn(range,cellsCollection) + } /// Takes the respective FsCellsCollection for this FsTable and creates a new _fieldNames dictionary if the current one does not match. // TO DO: maybe HLW can specify above description a bit... @@ -108,7 +85,7 @@ type FsTable (name : string, rangeAddress, showTotalsRow, showHeaderRow) = if self.ShowHeaderRow then let oldFieldNames = _fieldNames _fieldNames <- new Dictionary() - let headersRow = self.HeadersRow(false); + let headersRow = self.HeadersRow(); let mutable cellPos = 0 for cell in headersRow.Cells(cellsCollection) do let mutable name = cell.Value //GetString(); @@ -189,7 +166,7 @@ type FsTable (name : string, rangeAddress, showTotalsRow, showHeaderRow) = /// /// Creates and adds FsTableFields from a sequence of field names to the FsTable. /// - member this.AddFields(fieldNames : seq) = + member this.InitFields(fieldNames : seq) = // _fieldNames = new Dictionary(); // let's _not_ do it this way. //let rangeCols = FsRangeAddress.toRangeColumns base.RangeAddress fieldNames @@ -202,8 +179,8 @@ type FsTable (name : string, rangeAddress, showTotalsRow, showHeaderRow) = /// /// Creates and adds FsTableFields from a sequence of field names to a given FsTable. /// - static member addFieldsFromNames (fieldNames : seq) (table : FsTable) = - table.AddFields fieldNames + static member initFields (fieldNames : seq) (table : FsTable) = + table.InitFields fieldNames table /// @@ -255,7 +232,7 @@ type FsTable (name : string, rangeAddress, showTotalsRow, showHeaderRow) = /// if the header row has no field with the given name. member self.GetField(name : string, cellsCollection : FsCellsCollection) = let name = name.Replace("\r\n", "\n") - try self.FieldNames(cellsCollection).Item name + try self.GetFieldNames(cellsCollection).Item name with _ -> failwith <| "The header row doesn't contain field name '" + name + "'." /// @@ -263,7 +240,7 @@ type FsTable (name : string, rangeAddress, showTotalsRow, showHeaderRow) = /// FsTable) and returns the respective FsTableField. /// /// if the header row has no field with the given name. - static member getFieldByName (name : string) (cellsCollection : FsCellsCollection) (table : FsTable) = + static member getField (name : string) (cellsCollection : FsCellsCollection) (table : FsTable) = table.GetField(name, cellsCollection) /// @@ -271,9 +248,9 @@ type FsTable (name : string, rangeAddress, showTotalsRow, showHeaderRow) = /// this FsTable) and returns the respective FsTableField. /// /// if the FsTable has no FsTableField with the given index. - member self.GetField(index, cellsCollection) = + member self.GetFieldAt(index, cellsCollection) = try - self.FieldNames(cellsCollection).Values + self.GetFieldNames(cellsCollection).Values |> Seq.find (fun ftf -> ftf.Index = index) with _ -> failwith $"FsTableField with index {index} does not exist in the FsTable." @@ -308,7 +285,7 @@ type FsTable (name : string, rangeAddress, showTotalsRow, showHeaderRow) = /// /// Returns the header cell from a given FsCellsCollection with the given colum index if the cell exists. Else returns None. /// - member this.TryGetHeaderCellOfColumn(cellsCollection : FsCellsCollection, colIndex : int) = + member this.TryGetHeaderCellOfColumnAt(cellsCollection : FsCellsCollection, colIndex : int) = let fstRowIndex = this.RangeAddress.FirstAddress.RowNumber cellsCollection.GetCellsInColumn colIndex |> Seq.tryFind (fun c -> c.RowNumber = fstRowIndex) @@ -317,14 +294,14 @@ type FsTable (name : string, rangeAddress, showTotalsRow, showHeaderRow) = /// Returns the header cell from a given FsCellsCollection with the given column index in a given FsTable if the cell exists. Else /// returns None. /// - static member tryGetHeaderCellOfColumnIndex cellsCollection (colIndex : int) (table : FsTable) = - table.TryGetHeaderCellOfColumn(cellsCollection, colIndex) + static member tryGetHeaderCellOfColumnIndexAt cellsCollection (colIndex : int) (table : FsTable) = + table.TryGetHeaderCellOfColumnAt(cellsCollection, colIndex) /// /// Returns the header cell of a given FsRangeColumn from a given FsCellsCollection if the cell exists. Else returns None. /// member this.TryGetHeaderCellOfColumn(cellsCollection : FsCellsCollection, column : FsRangeColumn) = - this.TryGetHeaderCellOfColumn(cellsCollection, column.Index) + this.TryGetHeaderCellOfColumnAt(cellsCollection, column.Index) /// /// Returns the header cell of a given FsRangeColumn from a given FsCellsCollection in a given FsTable if the cell exists. @@ -337,15 +314,15 @@ type FsTable (name : string, rangeAddress, showTotalsRow, showHeaderRow) = /// Returns the header cell from a given FsCellsCollection with the given colum index. /// /// if the FsCell cannot be found. - member this.GetHeaderCellOfColumn(cellsCollection, colIndex : int) = - this.TryGetHeaderCellOfColumn(cellsCollection, colIndex).Value + member this.GetHeaderCellOfColumnAt(cellsCollection, colIndex : int) = + this.TryGetHeaderCellOfColumnAt(cellsCollection, colIndex).Value /// /// Returns the header cell from a given FsCellsCollection with the given colum index in a given FsTable. /// /// if the FsCell cannot be found. - static member getHeaderCellOfColumnIndex cellsCollection (colIndex : int) (table : FsTable) = - table.GetHeaderCellOfColumn(cellsCollection, colIndex) + static member getHeaderCellOfColumnIndexAt cellsCollection (colIndex : int) (table : FsTable) = + table.GetHeaderCellOfColumnAt(cellsCollection, colIndex) /// /// Returns the header cell of a given FsRangeColumn from a given FsCellsCollection. @@ -377,7 +354,7 @@ type FsTable (name : string, rangeAddress, showTotalsRow, showHeaderRow) = /// Returns the header cell from an FsTableField with the given index using a given FsCellsCollection if the cell exists. /// Else returns None. /// - member this.TryGetHeaderCellOfTableField(cellsCollection, tableFieldIndex : int) = + member this.TryGetHeaderCellOfTableFieldAt(cellsCollection, tableFieldIndex : int) = _fieldNames.Values |> Seq.tryPick ( fun tf -> @@ -390,22 +367,22 @@ type FsTable (name : string, rangeAddress, showTotalsRow, showHeaderRow) = /// Returns the header cell from an FsTableField with the given index using a given FsCellsCollection if the cell exists /// in a given FsTable. Else returns None. /// - static member tryGetHeaderCellOfTableFieldIndex cellsCollection (tableFieldIndex : int) (table : FsTable) = - table.TryGetHeaderCellOfTableField(cellsCollection, tableFieldIndex) + static member tryGetHeaderCellOfTableFieldIndexAt cellsCollection (tableFieldIndex : int) (table : FsTable) = + table.TryGetHeaderCellOfTableFieldAt(cellsCollection, tableFieldIndex) /// /// Returns the header cell from an FsTableField with the given index using a given FsCellsCollection. /// /// if the FsCell cannot be found. - member this.GetHeaderCellOfTableField(cellsCollection, tableFieldIndex : int) = - this.TryGetHeaderCellOfTableField(cellsCollection, tableFieldIndex).Value + member this.GetHeaderCellOfTableFieldAt(cellsCollection, tableFieldIndex : int) = + this.TryGetHeaderCellOfTableFieldAt(cellsCollection, tableFieldIndex).Value /// /// Returns the header cell from an FsTableField with the given index using a given FsCellsCollection in a given FsTable. /// /// if the FsCell cannot be found. - static member getHeaderCellOfTableFieldIndex cellsCollection (tableFieldIndex : int) (table : FsTable) = - table.GetHeaderCellOfTableField(cellsCollection, tableFieldIndex) + static member getHeaderCellOfTableFieldIndexAt cellsCollection (tableFieldIndex : int) (table : FsTable) = + table.GetHeaderCellOfTableFieldAt(cellsCollection, tableFieldIndex) /// /// Returns the header cell from an FsTableField with the given name using an FsCellsCollection in the FsTable if the cell exists. @@ -427,7 +404,7 @@ type FsTable (name : string, rangeAddress, showTotalsRow, showHeaderRow) = /// Returns the data cells from a given FsCellsCollection with the given colum index. /// /// Column index must fit the FsCellsCollection, not the FsTable! - member this.GetDataCellsOfColumn(cellsCollection : FsCellsCollection, colIndex) = + member this.GetDataCellsOfColumnAt(cellsCollection : FsCellsCollection, colIndex) = let fstRowIndex = this.RangeAddress.FirstAddress.RowNumber let lstRowIndex = this.RangeAddress.LastAddress.RowNumber [fstRowIndex + 1 .. lstRowIndex] @@ -439,8 +416,8 @@ type FsTable (name : string, rangeAddress, showTotalsRow, showHeaderRow) = /// Returns the data cells from a given FsCellsCollection with the given colum index in a given FsTable. /// /// Column index must fit the FsCellsCollection, not the FsTable! - static member getDataCellsOfColumnIndex cellsCollection (colIndex : int) (table : FsTable) = - table.GetDataCellsOfColumn(cellsCollection, colIndex) + static member getDataCellsOfColumnIndexAt cellsCollection (colIndex : int) (table : FsTable) = + table.GetDataCellsOfColumnAt(cellsCollection, colIndex) // TO DO: add equivalents of the other methods regarding header cell for data cells. diff --git a/src/FsSpreadsheet/Tables/FsTableField.fs b/src/FsSpreadsheet/Tables/FsTableField.fs index ebd1c68c..742ebcbb 100644 --- a/src/FsSpreadsheet/Tables/FsTableField.fs +++ b/src/FsSpreadsheet/Tables/FsTableField.fs @@ -132,7 +132,7 @@ type FsTableField (name : string, index : int, column : FsRangeColumn, totalsRow // TO DO: Ask HLW: isn't this predicate pointless? If showHeaderRow is false, the code breaks as soon as trying to call .HeaderCell //let predicate cell = (not showHeaderRow) && (this.HeaderCell(cellsCollection, showHeaderRow) <> cell) let predicate = fun _ -> true - this.Column.Cells(cellsCollection, predicate) + this.Column.CellsSelect(cellsCollection, predicate) |> Seq.skip 1 // ClosedXML implementation never shows header cell /// diff --git a/tests/FsSpreadsheet.ExcelIO.Tests/FsSpreadsheet.ExcelIO.Tests.fsproj b/tests/FsSpreadsheet.ExcelIO.Tests/FsSpreadsheet.ExcelIO.Tests.fsproj index 46b4c422..f4abf273 100644 --- a/tests/FsSpreadsheet.ExcelIO.Tests/FsSpreadsheet.ExcelIO.Tests.fsproj +++ b/tests/FsSpreadsheet.ExcelIO.Tests/FsSpreadsheet.ExcelIO.Tests.fsproj @@ -1,4 +1,4 @@ - + net6.0 @@ -16,10 +16,14 @@ - + + + + + \ No newline at end of file diff --git a/tests/FsSpreadsheet.ExcelIO.Tests/Main.fs b/tests/FsSpreadsheet.ExcelIO.Tests/Main.fs index 0fdfbe2a..1a9c6352 100644 --- a/tests/FsSpreadsheet.ExcelIO.Tests/Main.fs +++ b/tests/FsSpreadsheet.ExcelIO.Tests/Main.fs @@ -3,4 +3,4 @@ open Expecto [] let main argv = - Tests.runTestsInAssembly defaultConfig argv \ No newline at end of file + Tests.runTestsInAssemblyWithCLIArgs [] argv \ No newline at end of file diff --git a/tests/FsSpreadsheet.Tests/FsColumn.fs b/tests/FsSpreadsheet.Tests/FsColumn.fs index f3b8627f..1ba84c5c 100644 --- a/tests/FsSpreadsheet.Tests/FsColumn.fs +++ b/tests/FsSpreadsheet.Tests/FsColumn.fs @@ -39,7 +39,7 @@ let main = ] testList "ColumnFromIndex" [ let dummyWorkSheet = getDummyWorkSheet() - let column = FsColumn(2, dummyWorkSheet.CellCollection) + let column = FsColumn.createAt(2, dummyWorkSheet.CellCollection) testCase "CorrectIndex" <| fun _ -> Expect.equal column.Index 2 "Column index is not correct" testCase "CorrectRange" <| fun _ -> @@ -56,16 +56,22 @@ let main = let dummyWorkSheet = getDummyWorkSheet() testCase "CorrectColumnCount" <| fun _ -> Expect.equal (dummyWorkSheet.Columns |> Seq.length) 3 "Column count is not correct" + testCase "DoesNotFail" <| fun _ -> + let c = dummyWorkSheet.Column(2) + Expect.equal 1 1 "Failed when retreiving column" + testCase "HasRangeAddress" <| fun _ -> + let c = dummyWorkSheet.Column(2) + Expect.equal c.RangeAddress.Range "B1:B3" "Column range is not correct" testCase "CorrectIndex" <| fun _ -> Expect.equal (dummyWorkSheet.Column(2).Index) 2 "Column index is not correct" ] testList "FromTableRetrieval" [ testCase "CorrectColumnCount" <| fun _ -> - let columns = FsTable.dummyFsTable.Columns(FsTable.dummyFsCellsCollection) + let columns = FsTable.dummyFsTable.GetColumns(FsTable.dummyFsCellsCollection) Expect.equal (columns |> Seq.length) (FsTable.dummyFsTable.ColumnCount()) "Column count is not correct" testCase "Correct values" <| fun _ -> - let columns = FsTable.dummyFsTable.Columns(FsTable.dummyFsCellsCollection) + let columns = FsTable.dummyFsTable.GetColumns(FsTable.dummyFsCellsCollection) let expectedValues = ["Name";"John Doe";"Jane Doe";"Jack Doe"] Expect.mySequenceEqual (Seq.item 0 columns |> Seq.map FsCell.getValueAs) expectedValues "Values are not correct" ] diff --git a/tests/FsSpreadsheet.Tests/FsSpreadsheet.Tests.fsproj b/tests/FsSpreadsheet.Tests/FsSpreadsheet.Tests.fsproj index 78fb9c4b..92e163d6 100644 --- a/tests/FsSpreadsheet.Tests/FsSpreadsheet.Tests.fsproj +++ b/tests/FsSpreadsheet.Tests/FsSpreadsheet.Tests.fsproj @@ -31,4 +31,8 @@ + + + + diff --git a/tests/FsSpreadsheet.Tests/FsTable.fs b/tests/FsSpreadsheet.Tests/FsTable.fs index d80be497..2e4dd034 100644 --- a/tests/FsSpreadsheet.Tests/FsTable.fs +++ b/tests/FsSpreadsheet.Tests/FsTable.fs @@ -85,7 +85,7 @@ let main = let testFsTable = FsTable("testFsTable", FsRangeAddress(dummyFsCellsCollectionFirstAddress, dummyFsCellsCollectionLastAddress)) testFsTable.AddFields dummyFsTableFields |> ignore let testNames, testIndeces = - testFsTable.Fields dummyFsCellsCollection + testFsTable.GetFields(dummyFsCellsCollection) |> Seq.map (fun tf -> tf.Name, tf.Index) |> Seq.toArray |> Array.unzip @@ -102,7 +102,7 @@ let main = ] testList "TryGetHeaderCellOfColumn" [ testList "cellsCollection : FsCellsCollection, colIndex : int" [ - let testHeaderCell = dummyFsTable.TryGetHeaderCellOfColumn(dummyFsCellsCollection, 3) + let testHeaderCell = dummyFsTable.TryGetHeaderCellOfColumnAt(dummyFsCellsCollection, 3) testCase "Is Some" <| fun _ -> Expect.isSome testHeaderCell "Is None" testCase "Has correct value" <| fun _ -> @@ -122,7 +122,7 @@ let main = testList "cellsCollection : FsCellsCollection, tableFieldIndex : int" [ let testFsTable = FsTable("testFsTable", FsRangeAddress(dummyFsCellsCollectionFirstAddress, dummyFsCellsCollectionLastAddress)) testFsTable.AddFields dummyFsTableFields - let testHeaderCell = testFsTable.TryGetHeaderCellOfTableField(dummyFsCellsCollection, 1) + let testHeaderCell = testFsTable.TryGetHeaderCellOfTableFieldAt(dummyFsCellsCollection, 1) testCase "Is Some" <| fun _ -> Expect.isSome testHeaderCell "Is None" testCase "Has correct value" <| fun _ -> @@ -156,7 +156,7 @@ let main = testList "cellsCollection : FsCellsCollection, fieldName : FsTableField" [ let testFsTable = FsTable("testFsTable", FsRangeAddress(dummyFsCellsCollectionFirstAddress, dummyFsCellsCollectionLastAddress)) testFsTable.AddFields dummyFsTableFields - let testDataCells = testFsTable.GetDataCellsOfColumn(dummyFsCellsCollection, 2) + let testDataCells = testFsTable.GetDataCellsOfColumnAt(dummyFsCellsCollection, 2) testCase "Is Some" <| fun _ -> Expect.isNonEmpty testDataCells "Seq is empty" testCase "Has correct values" <| fun _ ->