jgm / pandoc

Universal markup converter
https://pandoc.org
Other
34.69k stars 3.39k forks source link

Pandoc Writer - JSON encoder not respecting array type #10079

Closed somonek closed 3 months ago

somonek commented 3 months ago

The issue is with the pandoc json encoder. If you have an empty object, which is supposed to become an array, but never gets any elements inserted, when encoded to json, the output is {} instead of [].

my-writer.lua code:

function Writer(doc, opts)
    local shouldBeAnArray = {}
    setmetatable(shouldBeAnArray, { __isarray = true })

    return pandoc.json.encode(shouldBeAnArray)
end

cli command: pandoc my-doc.ext -t my-writer.lua

Pandoc version:

pandoc 3.3
Features: +server +lua
Scripting engine: Lua 5.4
tarleb commented 3 months ago

Use pandoc.List to force a list:

% pandoc lua -e 'print(pandoc.json.encode({}))'
{}

% pandoc lua -e 'print(pandoc.json.encode(pandoc.List{}))'
[]

We could consider to check the __isarray field of the metatable. Are there JSON libraries that do this?

bluebergscientific commented 3 months ago

thanks @tarleb . Was not aware of pandoc.List{}. Exactly what I needed.

tarleb commented 3 months ago

I did a quick check, and it looks like cjson uses a heuristic and never checks the metatable, while dkjson allows to set __jsontype to either array or object. I'll consider to modify the hslua-aeson library to implement something similar.

There may be cases where it's not possible to use pandoc.List, in which case one has to implement the __tojson metamethod:

% pandoc lua                                           
Lua 5.4.6  Copyright (C) 1994-2023 Lua.org, PUC-Rio
Embedded in pandoc 3.2.1  Copyright (C) 2006-2024 John MacFarlane
> my_metatable = {__tojson = function (x)
>>   return '[' ..
>>     table.concat(pandoc.List.map(x, pandoc.json.encode), ',') ..
>>     ']'
>> end}
> pandoc.json.encode(setmetatable({}, my_metatable))
[]

Closing here for now.