-- ------------------------------------------------------------------------------ -- -- TradeSkillMaster -- -- https://tradeskillmaster.com -- -- All Rights Reserved - Detailed license information included with addon. -- -- ------------------------------------------------------------------------------ -- local TSM = select(2, ...) ---@type TSM local CSV = TSM.Init("Util.CSV") ---@class Util.CSV local TempTable = TSM.Include("Util.TempTable") local String = TSM.Include("Util.String") local private = {} -- ============================================================================ -- Module Functions -- ============================================================================ ---Creates a CSV encoding context for the specified keys. ---@param keys string[] The keys which are being encoded ---@return table @The CSV encoding context function CSV.EncodeStart(keys) local context = TempTable.Acquire() context.keys = keys context.lines = TempTable.Acquire() context.lineParts = TempTable.Acquire() tinsert(context.lines, table.concat(keys, ",")) return context end ---Adds a row to the CSV encoding context. ---@param context table The CSV encoding context ---@param data table The data for the row function CSV.EncodeAddRowData(context, data) wipe(context.lineParts) for _, key in ipairs(context.keys) do tinsert(context.lineParts, data[key] or "") end tinsert(context.lines, table.concat(context.lineParts, ",")) end ---Adds a raw row to the CSV encoding context. ---@param context table The CSV encoding context ---@param ... string The raw data for the row function CSV.EncodeAddRowDataRaw(context, ...) tinsert(context.lines, strjoin(",", ...)) end ---Ends a CSV encoding context and returns the resulting CSV string. ---@param context table The CSV encoding context ---@return string @The CSV encoded data function CSV.EncodeEnd(context) local result = table.concat(context.lines, "\n") TempTable.Release(context.lineParts) TempTable.Release(context.lines) TempTable.Release(context) return result end ---Encodes the specified data to a CSV string. ---@param keys string[] The list of keys to encode ---@param data table The data to encode ---@return string @The CSV encoded data function CSV.Encode(keys, data) local context = CSV.EncodeStart(keys) for _, row in ipairs(data) do CSV.EncodeAddRowData(context, row) end return CSV.EncodeEnd(context) end ---Creates a CSV decoding context for the specified fields. ---@param str string The CSV encoded data ---@param fields string[] The fields which are being decoded ---@return table @The CSV decoding context function CSV.DecodeStart(str, fields) local context = TempTable.Acquire() context.numFields = #fields context.result = true context.index = 1 String.SafeSplit(str, "\n", context) if context[1] ~= table.concat(fields, ",") then CSV.DecodeEnd(context) return end return context end ---Iterates over the CSV encoded data. ---@param context table The CSV decoding context ---@return fun(): ... @An iterator with fields matching the decoded values function CSV.DecodeIterator(context) return private.DecodeIteratorHelper, context end ---Ends a CSV decoding context and returns whether or not the data was fully decoded successfully. ---@param context table The CSV decoding context ---@return boolean @The result function CSV.DecodeEnd(context) local result = context.result TempTable.Release(context) return result end -- ============================================================================ -- Private Helper Functions -- ============================================================================ function private.DecodeIteratorHelper(context) context.index = context.index + 1 if context.index > #context then return end return private.DecodeIteratorHelper2(context, strsplit(",", context[context.index])) end function private.DecodeIteratorHelper2(context, ...) if select("#", ...) ~= context.numFields then context.result = false return end return ... end