Skip to content

Commit 395db8d

Browse files
committed
better align with idiomatic lua - functions should return result,nil or nil,error
1 parent 3d14c35 commit 395db8d

File tree

6 files changed

+191
-147
lines changed

6 files changed

+191
-147
lines changed

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2023 V (alis.is)
3+
Copyright (c) 2025 V (alis.is)
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

hjson.lua

Lines changed: 19 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
-- MIT License - Copyright (c) 2023 V (alis.is)
1+
-- MIT License - Copyright (c) 2025 V (alis.is)
22
local decoder = require "hjson.decoder"
33
local encoder = require "hjson.encoder"
44
local encoderH = require "hjson.encoderH"
@@ -12,10 +12,11 @@ local encoderH = require "hjson.encoderH"
1212
---decodes h/json
1313
---@param str string
1414
---@param options HjsonDecoderOptions
15-
---@return any
15+
---@return any result
16+
---@return string? error
17+
---@return boolean success
1618
local function decode(str, options)
17-
local _decoder = decoder:new(options)
18-
return _decoder:decode(str)
19+
return decoder:new(options):decode(str)
1920
end
2021

2122
---@class HJsonEncodeOptions
@@ -33,20 +34,6 @@ local function preprocess_encode_options(options)
3334
return result
3435
end
3536

36-
if options.skipKeys == true then
37-
print("skipkeys is deprecated, use skip_keys instead")
38-
options.skip_keys = true
39-
end
40-
41-
if options.sortKeys == true then
42-
print("sortKeys is deprecated, use sort_keys instead")
43-
options.sort_keys = true
44-
end
45-
46-
if options.invalidObjectsAsType == true then
47-
print("invalidObjectsAsType is deprecated, use invalid_objects_as_type instead")
48-
options.invalid_objects_as_type = true
49-
end
5037
return options
5138
end
5239

@@ -55,28 +42,29 @@ end
5542
---encodes json
5643
---@param obj any
5744
---@param options HJsonEncodeOptions?
58-
---@return any
45+
---@return string? result
46+
---@return string? error
5947
local function encode_json(obj, options)
6048
options = preprocess_encode_options(options)
6149

62-
local _encoder = encoder:new(options)
63-
return _encoder:encode(obj)
50+
return encoder:new(options):encode(obj)
6451
end
6552

6653
---#DES 'hjson.encode'
6754
---
6855
---encodes hjson
6956
---@param obj any
7057
---@param options HJsonEncodeOptions?
71-
---@return any
58+
---@return string? result
59+
---@return string? error
7260
local function encode(obj, options)
7361
options = preprocess_encode_options(options) --[[@as HJsonEncodeOptions]]
7462

7563
if options.indent == "" or options.indent == false or options.indent == 0 then
7664
return encode_json(obj, options)
7765
end
78-
local _encoderH = encoderH:new(options)
79-
return _encoderH:encode(obj)
66+
67+
return encoderH:new(options):encode(obj)
8068
end
8169

8270
local hjson = {
@@ -86,23 +74,27 @@ local hjson = {
8674
---encodes hjson
8775
---@param obj any
8876
---@param options HJsonEncodeOptions?
89-
---@return any
77+
---@return string? result
78+
---@return string? error
9079
stringify = encode,
9180
encode_to_json = encode_json,
9281
---#DES 'hjson.stringify_to_json'
9382
---
9483
---encodes json
9584
---@param obj any
9685
---@param options HJsonEncodeOptions?
97-
---@return any
86+
---@return string? result
87+
---@return string? error
9888
stringify_to_json = encode_json,
9989
decode = decode,
10090
---#DES 'hjson.parse'
10191
---
10292
---decodes h/json
10393
---@param str string
10494
---@param options HjsonDecoderOptions
105-
---@return any
95+
---@return any result
96+
---@return string? error
97+
---@return boolean success
10698
parse = decode,
10799
}
108100

hjson/decoder.lua

Lines changed: 39 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
-- MIT License - Copyright (c) 2023 V (alis.is)
1+
-- MIT License - Copyright (c) 2025 V (alis.is)
22
local DEFAULT_MAX_DEPTH = 1000
33

44
local WHITESPACE = " \t\n\r"
@@ -25,7 +25,7 @@ local function charAt(s, pos)
2525
return s:sub(pos, pos)
2626
end
2727

28-
local function decodeError(str, idx, msg)
28+
local function decode_error(str, idx, msg)
2929
local line_count = 1
3030
local col_count = 1
3131
for i = 1, idx - 1 do
@@ -45,7 +45,7 @@ end
4545
---@field max_depth number?
4646

4747
---@class HjsonDecoder
48-
---@field decode fun(self: HjsonDecoder, s: string): any
48+
---@field decode fun(self: HjsonDecoder, s: string): any, string?, boolean
4949

5050
local HjsonDecoder = {}
5151
--- Hjson decoder
@@ -160,7 +160,7 @@ function HjsonDecoder:new(options)
160160
elseif n <= 0x10ffff then
161161
return string.char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128, f(n % 4096 / 64) + 128, n % 64 + 128)
162162
end
163-
decodeError(s, _end, string.format("invalid unicode codepoint '%x'", n))
163+
decode_error(s, _end, string.format("invalid unicode codepoint '%x'", n))
164164
end
165165

166166
local function parseString(s, _end)
@@ -176,7 +176,7 @@ function HjsonDecoder:new(options)
176176
local function scan_string()
177177
local content, terminator = s:match('(.-)([\'"\\%z\001-\031])', _end)
178178
if not content then
179-
decodeError(s, begin, "Unterminated string")
179+
decode_error(s, begin, "Unterminated string")
180180
end
181181

182182
_end = _end + #content + #terminator
@@ -189,22 +189,22 @@ function HjsonDecoder:new(options)
189189
return -- continue
190190
elseif terminator ~= "\\" then
191191
if options.strict then
192-
decodeError(s, begin, "Invalid control character " .. terminator)
192+
decode_error(s, begin, "Invalid control character " .. terminator)
193193
else
194194
chunks = chunks .. terminator
195195
return -- continue
196196
end
197197
end
198198

199199
if #s < _end then
200-
decodeError(s, _end, "Unterminated string")
200+
decode_error(s, _end, "Unterminated string")
201201
end
202202

203203
local chars
204204
local esc = charAt(s, _end)
205205
if esc ~= "u" then
206206
if not esc or not BACKSLASH[esc] then
207-
decodeError(s, _end, "Invalid \\X escape sequence")
207+
decode_error(s, _end, "Invalid \\X escape sequence")
208208
end
209209
chars = BACKSLASH[esc]
210210
_end = _end + 1
@@ -213,7 +213,7 @@ function HjsonDecoder:new(options)
213213
local msg = "Invalid \\uXXXX escape sequence"
214214
esc = s:sub(_end + 1, _end + 4)
215215
if #esc ~= 4 or not esc:find("%x%x%x%x") then
216-
decodeError(s, _end - 1, msg)
216+
decode_error(s, _end - 1, msg)
217217
end
218218
_end = _end + 5
219219
if esc:find("^[dD][89aAbB]") and s:sub(_end, _end + 1) == "\\u" then
@@ -259,7 +259,7 @@ function HjsonDecoder:new(options)
259259
local function scan_mlstring()
260260
ch = charAt(s, _end)
261261
if ch == "" then
262-
decodeError(s, _end, "Bad multiline string")
262+
decode_error(s, _end, "Bad multiline string")
263263
end
264264
if ch == "'" then
265265
triple = triple + 1
@@ -302,7 +302,7 @@ function HjsonDecoder:new(options)
302302
local chf, begin = getNext(s, _end)
303303
_end = begin
304304
if PUNCTUATOR:find(chf, 1, true) then
305-
decodeError(s, _end, "Found a punctuator character when expecting a quoteless string (check your syntax)")
305+
decode_error(s, _end, "Found a punctuator character when expecting a quoteless string (check your syntax)")
306306
end
307307

308308
while true do
@@ -359,14 +359,14 @@ function HjsonDecoder:new(options)
359359
while true do
360360
ch = charAt(s, _end)
361361
if ch == "" then
362-
decodeError(s, _end, "Bad key name (eof)")
362+
decode_error(s, _end, "Bad key name (eof)")
363363
end
364364
if ch == ":" then
365365
if begin == _end then
366-
decodeError(s, begin, "Found ':' but no key name (for an empty key name use quotes)")
366+
decode_error(s, begin, "Found ':' but no key name (for an empty key name use quotes)")
367367
elseif space >= 0 then
368368
if space ~= _end - 1 then
369-
decodeError(s, _end, "Found whitespace in your key name (use quotes to include)")
369+
decode_error(s, _end, "Found whitespace in your key name (use quotes to include)")
370370
end
371371
return trim(s:sub(begin, _end - 1)), _end
372372
else
@@ -377,7 +377,7 @@ function HjsonDecoder:new(options)
377377
space = _end
378378
end
379379
elseif ch == "{" or ch == "}" or ch == "[" or ch == "]" or ch == "," then
380-
decodeError(
380+
decode_error(
381381
s,
382382
begin,
383383
"Found '" ..
@@ -441,7 +441,7 @@ function HjsonDecoder:new(options)
441441

442442
ch, _end = getNext(s, _end)
443443
if ch ~= ":" then
444-
decodeError(s, _end, "Expecting ':' delimiter")
444+
decode_error(s, _end, "Expecting ':' delimiter")
445445
end
446446

447447
ch, _end = getNext(s, _end + 1)
@@ -485,7 +485,7 @@ function HjsonDecoder:new(options)
485485
ch, _end = getNext(s, _end)
486486

487487
if ch == "" then
488-
decodeError(s, _end, "End of input while parsing an array (did you forget a closing ']'?)")
488+
decode_error(s, _end, "End of input while parsing an array (did you forget a closing ']'?)")
489489
end
490490
-- Look-ahead for trivial empty array
491491
if ch == "]" then
@@ -517,12 +517,12 @@ function HjsonDecoder:new(options)
517517
end
518518
depth = depth + 1
519519
if depth > options.max_depth then
520-
decodeError(string, idx, "Exceeded max depth")
520+
decode_error(string, idx, "Exceeded max depth")
521521
end
522522

523523
local ch = charAt(string, idx)
524524
if not ch then
525-
decodeError(string, idx, "Expecting value")
525+
decode_error(string, idx, "Expecting value")
526526
end
527527

528528
if ch == '"' or ch == "'" then
@@ -541,7 +541,7 @@ function HjsonDecoder:new(options)
541541

542542
local function scan_once(string, idx)
543543
if idx <= 0 then
544-
decodeError(string, idx, "Expecting value")
544+
decode_error(string, idx, "expecting value")
545545
end
546546
local status, result, _end = pcall(_scan_once, string, idx)
547547
memo = {}
@@ -554,7 +554,7 @@ function HjsonDecoder:new(options)
554554

555555
local function scan_object_once(string, idx)
556556
if idx <= 0 then
557-
decodeError(string, idx, "Expecting value")
557+
decode_error(string, idx, "expecting value")
558558
end
559559
local status, result, _end = pcall(parse_object, {s = string, _end = idx}, _scan_once, true)
560560
memo = {}
@@ -577,29 +577,39 @@ function HjsonDecoder:new(options)
577577
return hd
578578
end
579579

580+
---@param s any
581+
---@return any, string?, boolean
580582
function HjsonDecoder:decode(s)
581583
--[[
582584
Returns the Lua representation of ``s`` (a ``ascii`` or ``utf-8`` string
583585
instance containing a JSON document)
584586
]]
585-
local ch
586-
local obj, _end = self:raw_decode(s)
587-
ch, _end = self.get_next(s, _end)
588-
if _end ~= #s + 1 then
589-
decodeError(s, _end, "Extra data")
587+
assert(type(s) == "string", "HjsonDecoder:decode expects a string as input")
588+
589+
local status, objOrError = pcall(function()
590+
local obj, _end = self:__raw_decode(s)
591+
_, _end = self.get_next(s, _end)
592+
if _end ~= #s + 1 then
593+
decode_error(s, _end, "extra data")
594+
end
595+
return obj
596+
end)
597+
598+
if not status then
599+
return nil, objOrError, false
590600
end
591601

592-
return obj
602+
return objOrError, nil, true
593603
end
594604

595-
function HjsonDecoder:raw_decode(s, idx)
605+
function HjsonDecoder:__raw_decode(s, idx)
596606
local ch
597607
if idx == nil then
598608
idx = 1
599609
end
600610

601611
if idx <= 0 then
602-
decodeError(s, idx, "Expecting value")
612+
decode_error(s, idx, "expecting value")
603613
end
604614

605615
-- Strip UTF-8 bom

0 commit comments

Comments
 (0)