From c62c5b307ec907b78f309dbbe90b6569fe91a3f8 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Thu, 18 Mar 2021 12:57:25 +0100 Subject: util.datamapper: Add initial support for parsing arrays --- spec/util_datamapper_spec.lua | 25 ++++++++++++++++++- teal-src/util/datamapper.tl | 56 ++++++++++++++++++++++++++++++++++++------- util/datamapper.lua | 56 ++++++++++++++++++++++++++++++++++++------- 3 files changed, 118 insertions(+), 19 deletions(-) diff --git a/spec/util_datamapper_spec.lua b/spec/util_datamapper_spec.lua index 7f5b71de..aacaf995 100644 --- a/spec/util_datamapper_spec.lua +++ b/spec/util_datamapper_spec.lua @@ -46,6 +46,11 @@ describe("util.datampper", function() type = "string"; xml = {name = "origin-id"; namespace = "urn:xmpp:sid:0"; x_single_attribute = "id"}; }; + reactions = { + type = "array"; + xml = {namespace = "urn:xmpp:reactions:0"; wrapped = true}; + items = {type = "string"; xml = {name = "reaction"}}; + }; }; }; @@ -57,6 +62,10 @@ describe("util.datampper", function() + + 👋 + 🐢 + ]]; @@ -71,6 +80,10 @@ describe("util.datampper", function() state = "active"; fallback = true; origin_id = "qgkmMdPB"; + reactions = { + "👋", + "🐢", + }; }; end); @@ -85,11 +98,21 @@ describe("util.datampper", function() local u = map.unparse(s, d); assert.equal("message", u.name); assert.same(x.attr, u.attr); - assert.equal(#x.tags-1, #u.tags) assert.equal(x:get_child_text("body"), u:get_child_text("body")); assert.equal(x:get_child_text("delay", "urn:xmpp:delay"), u:get_child_text("delay", "urn:xmpp:delay")); assert.same(x:get_child("delay", "urn:xmpp:delay").attr, u:get_child("delay", "urn:xmpp:delay").attr); assert.same(x:get_child("origin-id", "urn:xmpp:sid:0").attr, u:get_child("origin-id", "urn:xmpp:sid:0").attr); + for _, tag in ipairs(x.tags) do + if tag.name ~= "UNRELATED" and tag.name ~= "reactions" then + assert.truthy(u:get_child(tag.name, tag.attr.xmlns) or u:get_child(tag.name), tag:top_tag()) + end + end + assert.equal(#x.tags-2, #u.tags) + + pending("arrays", function () + assert.truthy(u:get_child("reactions", "urn:xmpp:reactions:0")) + end); + end); end); end) diff --git a/teal-src/util/datamapper.tl b/teal-src/util/datamapper.tl index 055ddabd..76370ed9 100644 --- a/teal-src/util/datamapper.tl +++ b/teal-src/util/datamapper.tl @@ -49,6 +49,7 @@ local enum value_goes "in_attribute" "in_single_attribute" "in_children" + "in_wrapper" end local function unpack_propschema( propschema : js.schema_t | js.schema_t.type_e, propname : string, current_ns : string ) @@ -67,6 +68,10 @@ local function unpack_propschema( propschema : js.schema_t | js.schema_t.type_e, proptype = propschema end + if proptype == "object" or proptype == "array" then + value_where = "in_children" + end + if propschema is js.schema_t then local xml = propschema.xml if xml then @@ -79,8 +84,9 @@ local function unpack_propschema( propschema : js.schema_t | js.schema_t.type_e, if xml.prefix then prefix = xml.prefix end - - if xml.attribute then + if proptype == "array" and xml.wrapped then + value_where = "in_wrapper" + elseif xml.attribute then value_where = "in_attribute" elseif xml.text then value_where = "in_text" @@ -98,15 +104,13 @@ local function unpack_propschema( propschema : js.schema_t | js.schema_t.type_e, end end - if proptype == "object" or proptype == "array" then - value_where = "in_children" - end - return proptype, value_where, name, namespace, prefix, single_attribute, enums end +local parse_object : function (schema : js.schema_t, s : st.stanza_t) : { string : any } +local parse_array : function (schema : js.schema_t, s : st.stanza_t) : { any } -local function parse_object (schema : js.schema_t, s : st.stanza_t) : table +function parse_object (schema : js.schema_t, s : st.stanza_t) : { string : any } local out : { string : any } = {} if schema.properties then for prop, propschema in pairs(schema.properties) do @@ -153,10 +157,22 @@ local function parse_object (schema : js.schema_t, s : st.stanza_t) : table if c then out[prop] = parse_object(propschema, c); end - -- else TODO + elseif proptype == "array" then + out[prop] = parse_array(propschema, s); + else + error "unreachable" end + elseif value_where == "in_wrapper" and propschema is js.schema_t and proptype == "array" then + local wrapper = s:get_child(name, namespace); + if wrapper then + out[prop] = parse_array(propschema, wrapper); + else + error "unreachable" + end + else + error "unreachable" end - if value_where ~= "in_children" then + if value_where ~= "in_children" and value_where ~= "in_wrapper" then out[prop] = totype(proptype, value) end end @@ -165,9 +181,31 @@ local function parse_object (schema : js.schema_t, s : st.stanza_t) : table return out end +function parse_array (schema : js.schema_t, s : st.stanza_t) : { any } + local proptype, value_where, child_name, namespace = unpack_propschema(schema.items, nil, s.attr.xmlns) + local out : { any } = {} + for c in s:childtags(child_name, namespace) do + local value : string; + if value_where == "in_text_tag" then + value = c:get_text(); + else + error "NYI" + end + + if value ~= nil then + table.insert(out, value); + end + end + return out; +end + local function parse (schema : js.schema_t, s : st.stanza_t) : table if schema.type == "object" then return parse_object(schema, s) + elseif schema.type == "array" then + return parse_array(schema, s) + else + error "top-level scalars unsupported" end end diff --git a/util/datamapper.lua b/util/datamapper.lua index da46d072..a208dd7e 100644 --- a/util/datamapper.lua +++ b/util/datamapper.lua @@ -38,6 +38,10 @@ local function unpack_propschema(propschema, propname, current_ns) proptype = propschema end + if proptype == "object" or proptype == "array" then + value_where = "in_children" + end + if type(propschema) == "table" then local xml = propschema.xml if xml then @@ -50,8 +54,9 @@ local function unpack_propschema(propschema, propname, current_ns) if xml.prefix then prefix = xml.prefix end - - if xml.attribute then + if proptype == "array" and xml.wrapped then + value_where = "in_wrapper" + elseif xml.attribute then value_where = "in_attribute" elseif xml.text then value_where = "in_text" @@ -69,14 +74,13 @@ local function unpack_propschema(propschema, propname, current_ns) end end - if proptype == "object" or proptype == "array" then - value_where = "in_children" - end - return proptype, value_where, name, namespace, prefix, single_attribute, enums end -local function parse_object(schema, s) +local parse_object +local parse_array + +function parse_object(schema, s) local out = {} if schema.properties then for prop, propschema in pairs(schema.properties) do @@ -123,10 +127,22 @@ local function parse_object(schema, s) if c then out[prop] = parse_object(propschema, c); end - + elseif proptype == "array" then + out[prop] = parse_array(propschema, s); + else + error("unreachable") + end + elseif value_where == "in_wrapper" and type(propschema) == "table" and proptype == "array" then + local wrapper = s:get_child(name, namespace); + if wrapper then + out[prop] = parse_array(propschema, wrapper); + else + error("unreachable") end + else + error("unreachable") end - if value_where ~= "in_children" then + if value_where ~= "in_children" and value_where ~= "in_wrapper" then out[prop] = totype(proptype, value) end end @@ -135,9 +151,31 @@ local function parse_object(schema, s) return out end +function parse_array(schema, s) + local proptype, value_where, child_name, namespace = unpack_propschema(schema.items, nil, s.attr.xmlns) + local out = {} + for c in s:childtags(child_name, namespace) do + local value; + if value_where == "in_text_tag" then + value = c:get_text(); + else + error("NYI") + end + + if value ~= nil then + table.insert(out, value); + end + end + return out +end + local function parse(schema, s) if schema.type == "object" then return parse_object(schema, s) + elseif schema.type == "array" then + return parse_array(schema, s) + else + error("top-level scalars unsupported") end end -- cgit v1.2.3