Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ There are a few parsing options available that are passed in the the `options` p
tinytoml.parse("a=2024-10-31T12:49:00Z", {load_from_string=true, type_conversion=type_conversion})
```

- `encode_datetime_as` (default `string`)
- `parse_datetime_as` (default `string`)

Allows encoding datetime either as a `string` or a `table`. The `table` will take all the individual fields and place them in a table.
This can be used in conjunction with `type_conversion` - either the string or table representation would be passed into whatever function is
Expand All @@ -88,14 +88,15 @@ There are a few parsing options available that are passed in the the `options` p
```

```lua
-- with the option: { encode_datetime_as = "string" }
-- with the option: { parse_datetime_as = "string" }
{
offset_datetime = "1979-05-27T07:32:00Z",
local_datetime = "1979-05-27T07:32:00",
local_time = "07:32:00",
local_date = "1979-05-27"
}
-- with the option: { encode_datetime_as = "table" }

-- with the option: { parse_datetime_as = "table" }
{
offset_datetime = {year = 1979, month = 05, day = 27, hour = 7, min = 32, sec = 0, msec = 0, time_offset = "00:00"},
local_datetime = {year = 1979, month = 05, day = 27, hour = 7, min = 32, sec = 0, msec = 0},
Expand Down
44 changes: 44 additions & 0 deletions tests/date_testing.tl
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
local tested = require("tested")
local tinytoml = require("tinytoml")

tested.test("encode date as string", function()

local date_toml = [[offset_datetime = 1979-05-27T07:32:00Z
local_datetime = 1979-05-27T07:32:00
local_time = 07:32:00
local_date = 1979-05-27]]

local expected = {
offset_datetime = "1979-05-27T07:32:00Z",
local_datetime = "1979-05-27T07:32:00",
local_time = "07:32:00",
local_date = "1979-05-27"
}

local parsed_dates = tinytoml.parse(date_toml, {load_from_string=true, parse_datetime_as="string"})

tested.assert({given="toml with dates", should="parse dates as strings", expected=expected, actual=parsed_dates})

end)

tested.test("encode date as table", function()

local date_toml = [[offset_datetime = 1979-05-27T07:32:00Z
local_datetime = 1979-05-27T07:32:00
local_time = 07:32:00
local_date = 1979-05-27]]

local expected = {
offset_datetime = {year = 1979, month = 05, day = 27, hour = 7, min = 32, sec = 0, msec = 0, time_offset = "00:00"},
local_datetime = {year = 1979, month = 05, day = 27, hour = 7, min = 32, sec = 0, msec = 0},
local_time = {hour = 7, min = 32, sec = 0, msec = 0},
local_date = {year = 1979, month = 05, day = 27}
}

local parsed_dates = tinytoml.parse(date_toml, {load_from_string=true, parse_datetime_as="table"})

tested.assert({given="toml with dates", should="parse dates as tables", expected=expected, actual=parsed_dates})

end)

return tested
54 changes: 54 additions & 0 deletions tests/max_nesting_depth.tl
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
local tinytoml = require("tinytoml")
local tested = require("tested")

tested.test("max nesting depth", function()
local crazy_toml = {"e="}
for i = 1, 2000 do
table.insert(crazy_toml, "{e=")
end

table.insert(crazy_toml, "{}")
for i = 1, 2000 do
table.insert(crazy_toml, "}")
end

local ok, err = pcall(tinytoml.parse, table.concat(crazy_toml), {load_from_string=true})

tested.assert({given="too much nesting", should="raies an error", expected=false, actual=ok})
tested.assert({given="too much nesting", should="error includes max_nesting_depth", expected=true, actual=err:find("'max_nesting_depth'") ~= nil})

end)

tested.test("at max nesting depth", function()
local crazy_toml = {"e="}
for i = 1, 998 do
table.insert(crazy_toml, "{e=")
end

table.insert(crazy_toml, "{}")
for i = 1, 998 do
table.insert(crazy_toml, "}")
end

local ok, err = pcall(tinytoml.parse, table.concat(crazy_toml), {load_from_string=true})

tested.assert({given="edge of nesting", should="does not raise an error", expected=true, actual=ok})
end)

tested.test("slightly above max nesting depth", function()
local crazy_toml = {"e="}
for i = 1, 1500 do
table.insert(crazy_toml, "{e=")
end

table.insert(crazy_toml, "{}")
for i = 1, 1500 do
table.insert(crazy_toml, "}")
end

local ok, err = pcall(tinytoml.parse, table.concat(crazy_toml), {load_from_string=true, max_nesting_depth=2000})

tested.assert({given="edge of nesting", should="does not raise an error", expected=true, actual=ok})
end)

return tested
21 changes: 11 additions & 10 deletions tinytoml.lua
Original file line number Diff line number Diff line change
Expand Up @@ -633,7 +633,7 @@ end

local function assign_time_local(sm, match, hour, min, sec, msec)
sm.value_type = "time-local"
if sm.options.encode_datetime_as == "string" then
if sm.options.parse_datetime_as == "string" then
sm.value = sm.options.type_conversion[sm.value_type](match)
else
sm.value = sm.options.type_conversion[sm.value_type]({ hour = hour, min = min, sec = sec, msec = msec })
Expand All @@ -642,7 +642,7 @@ end

local function assign_date_local(sm, match, year, month, day)
sm.value_type = "date-local"
if sm.options.encode_datetime_as == "string" then
if sm.options.parse_datetime_as == "string" then
sm.value = sm.options.type_conversion[sm.value_type](match)
else
sm.value = sm.options.type_conversion[sm.value_type]({ year = year, month = month, day = day })
Expand All @@ -651,7 +651,7 @@ end

local function assign_datetime_local(sm, match, year, month, day, hour, min, sec, msec)
sm.value_type = "datetime-local"
if sm.options.encode_datetime_as == "string" then
if sm.options.parse_datetime_as == "string" then
sm.value = sm.options.type_conversion[sm.value_type](match)
else
sm.value = sm.options.type_conversion[sm.value_type]({ year = year, month = month, day = day, hour = hour, min = min, sec = sec, msec = msec or 0 })
Expand All @@ -665,7 +665,7 @@ local function assign_datetime(sm, match, year, month, day, hour, min, sec, msec
validate_hours_minutes(sm, _tointeger(hour_s), _tointeger(min_s), "offset-date-time")
end
sm.value_type = "datetime"
if sm.options.encode_datetime_as == "string" then
if sm.options.parse_datetime_as == "string" then
sm.value = sm.options.type_conversion[sm.value_type](match)
else
sm.value = sm.options.type_conversion[sm.value_type]({ year = year, month = month, day = day, hour = hour, min = min, sec = sec, msec = msec or 0, time_offset = tz or "00:00" })
Expand Down Expand Up @@ -739,7 +739,8 @@ local function validate_datetime(sm, value)
local temp_ext
sm._, sm._, sec_s, temp_ext = sm.ext:find("^:(%d%d)(.*)$")
if sec_s then
validate_seconds(sm, _tointeger(sec_s), "local-time")
sec = _tointeger(sec_s)
validate_seconds(sm, sec, "local-time")
sm.match = sm.match .. ":" .. sec_s
sm.ext = temp_ext
else
Expand Down Expand Up @@ -1162,7 +1163,7 @@ function tinytoml.parse(filename, options)
max_nesting_depth = 1000,
max_filesize = 100000000,
load_from_string = false,
encode_datetime_as = "string",
parse_datetime_as = "string",
type_conversion = {
["datetime"] = generic_type_conversion,
["datetime-local"] = generic_type_conversion,
Expand All @@ -1185,8 +1186,8 @@ function tinytoml.parse(filename, options)
assert(type(options.load_from_string) == "boolean", "the tinytoml option 'load_from_string' takes in a 'function'. You passed in the value '" .. tostring(options.load_from_string) .. "' of type '" .. type(options.load_from_string) .. "'")
end

if options.encode_datetime_as ~= nil then
assert(type(options.encode_datetime_as) == "string", "the tinytoml option 'encode_datetime_as' takes in either the 'string' or 'table' (as type 'string'). You passed in the value '" .. tostring(options.encode_datetime_as) .. "' of type '" .. type(options.encode_datetime_as) .. "'")
if options.parse_datetime_as ~= nil then
assert(type(options.parse_datetime_as) == "string", "the tinytoml option 'parse_datetime_as' takes in either the 'string' or 'table' (as type 'string'). You passed in the value '" .. tostring(options.parse_datetime_as) .. "' of type '" .. type(options.parse_datetime_as) .. "'")
end

if options.type_conversion ~= nil then
Expand All @@ -1204,7 +1205,7 @@ function tinytoml.parse(filename, options)
options.max_nesting_depth = options.max_nesting_depth or default_options.max_nesting_depth
options.max_filesize = options.max_filesize or default_options.max_filesize
options.load_from_string = options.load_from_string or default_options.load_from_string
options.encode_datetime_as = options.encode_datetime_as or default_options.encode_datetime_as
options.parse_datetime_as = options.parse_datetime_as or default_options.parse_datetime_as
options.type_conversion = options.type_conversion or default_options.type_conversion


Expand Down Expand Up @@ -1351,7 +1352,7 @@ local function escape_string(str, multiline, is_key)
["date-local"] = generic_type_conversion,
["time-local"] = generic_type_conversion,
}
sm.options.encode_datetime_as = "string"
sm.options.parse_datetime_as = "string"


sm._, sm.end_seq, sm.match = sm.input:find("^([^ #\r\n,%[{%]}]+)", sm.i)
Expand Down
23 changes: 12 additions & 11 deletions tinytoml.tl
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ end
local record TinyTomlOptions
load_from_string: boolean
type_conversion: {TomlConversionType:function<T>(raw_value: string | table):T}
encode_datetime_as: DateTimeEncode
parse_datetime_as: DateTimeEncode
max_filesize: integer
max_nesting_depth: integer
end
Expand Down Expand Up @@ -633,7 +633,7 @@ end

local function assign_time_local(sm: StateMachine, match: string, hour: integer, min: integer, sec: integer, msec: integer)
sm.value_type = "time-local"
if sm.options.encode_datetime_as == "string" then
if sm.options.parse_datetime_as == "string" then
sm.value = sm.options.type_conversion[sm.value_type as TomlConversionType](match)
else
sm.value = sm.options.type_conversion[sm.value_type as TomlConversionType]({hour=hour, min=min, sec=sec, msec=msec})
Expand All @@ -642,7 +642,7 @@ end

local function assign_date_local(sm: StateMachine, match: string, year: integer, month: integer, day: integer)
sm.value_type = "date-local"
if sm.options.encode_datetime_as == "string" then
if sm.options.parse_datetime_as == "string" then
sm.value = sm.options.type_conversion[sm.value_type as TomlConversionType](match)
else
sm.value = sm.options.type_conversion[sm.value_type as TomlConversionType]({year=year, month=month, day=day})
Expand All @@ -651,7 +651,7 @@ end

local function assign_datetime_local(sm: StateMachine, match: string, year: integer, month: integer, day: integer, hour: integer, min: integer, sec: integer, msec?: integer)
sm.value_type = "datetime-local"
if sm.options.encode_datetime_as == "string" then
if sm.options.parse_datetime_as == "string" then
sm.value = sm.options.type_conversion[sm.value_type as TomlConversionType](match)
else
sm.value = sm.options.type_conversion[sm.value_type as TomlConversionType]({year=year, month=month, day=day, hour=hour, min=min, sec=sec, msec=msec or 0})
Expand All @@ -665,7 +665,7 @@ local function assign_datetime(sm: StateMachine, match: string, year: integer, m
validate_hours_minutes(sm, _tointeger(hour_s), _tointeger(min_s), "offset-date-time")
end
sm.value_type = "datetime"
if sm.options.encode_datetime_as == "string" then
if sm.options.parse_datetime_as == "string" then
sm.value = sm.options.type_conversion[sm.value_type as TomlConversionType](match)
else
sm.value = sm.options.type_conversion[sm.value_type as TomlConversionType]({year=year, month=month, day=day, hour=hour, min=min, sec=sec, msec=msec or 0, time_offset=tz or "00:00"})
Expand Down Expand Up @@ -739,7 +739,8 @@ local function validate_datetime(sm: StateMachine, value: string): boolean
local temp_ext: string
sm._, sm._, sec_s, temp_ext = sm.ext:find("^:(%d%d)(.*)$") as (integer, integer, string, string)
if sec_s then
validate_seconds(sm, _tointeger(sec_s), "local-time")
sec = _tointeger(sec_s)
validate_seconds(sm, sec, "local-time")
sm.match = sm.match .. ":" .. sec_s
sm.ext = temp_ext
else
Expand Down Expand Up @@ -1162,7 +1163,7 @@ function tinytoml.parse(filename: string, options?: TinyTomlOptions): {string:an
max_nesting_depth = 1000,
max_filesize = 100000000,
load_from_string = false,
encode_datetime_as = "string",
parse_datetime_as = "string",
type_conversion = {
["datetime"] = generic_type_conversion,
["datetime-local"] = generic_type_conversion,
Expand All @@ -1185,8 +1186,8 @@ function tinytoml.parse(filename: string, options?: TinyTomlOptions): {string:an
assert(type(options.load_from_string) == "boolean", "the tinytoml option 'load_from_string' takes in a 'function'. You passed in the value '" .. tostring(options.load_from_string) .. "' of type '" .. type(options.load_from_string) .. "'")
end

if options.encode_datetime_as ~= nil then
assert(type(options.encode_datetime_as) == "string", "the tinytoml option 'encode_datetime_as' takes in either the 'string' or 'table' (as type 'string'). You passed in the value '" .. tostring(options.encode_datetime_as) .. "' of type '" .. type(options.encode_datetime_as) .. "'")
if options.parse_datetime_as ~= nil then
assert(type(options.parse_datetime_as) == "string", "the tinytoml option 'parse_datetime_as' takes in either the 'string' or 'table' (as type 'string'). You passed in the value '" .. tostring(options.parse_datetime_as) .. "' of type '" .. type(options.parse_datetime_as) .. "'")
end

if options.type_conversion ~= nil then
Expand All @@ -1204,7 +1205,7 @@ function tinytoml.parse(filename: string, options?: TinyTomlOptions): {string:an
options.max_nesting_depth = options.max_nesting_depth or default_options.max_nesting_depth
options.max_filesize = options.max_filesize or default_options.max_filesize
options.load_from_string = options.load_from_string or default_options.load_from_string
options.encode_datetime_as = options.encode_datetime_as or default_options.encode_datetime_as
options.parse_datetime_as = options.parse_datetime_as or default_options.parse_datetime_as
options.type_conversion = options.type_conversion or default_options.type_conversion

-- verify/setup the last couple of things
Expand Down Expand Up @@ -1351,7 +1352,7 @@ local function escape_string(str: string, multiline: boolean, is_key: boolean):
["date-local"] = generic_type_conversion,
["time-local"] = generic_type_conversion
}
sm.options.encode_datetime_as = "string"
sm.options.parse_datetime_as = "string"

-- performing the same setup as in close_other_value, should set values correctly to run validate_datetime
sm._, sm.end_seq, sm.match = sm.input:find("^([^ #\r\n,%[{%]}]+)", sm.i)
Expand Down
Loading