addSVGElementsFromJson = (data) => {
  if (typeof data === 'string') return svgdoc_.createTextNode(data)

  let shape = getElement(data.attr.id)
  // if shape is a path but we need to create a rect/ellipse, then remove the path
  const currentLayer = svgCanvas.getDrawing().getCurrentLayer()
  if (shape && data.element !== shape.tagName) {
    shape.remove()
    shape = null
  }
  if (!shape) {
    const ns = data.namespace || NS.SVG
    shape = svgdoc_.createElementNS(ns, data.element)
    if (currentLayer) {
      (svgCanvas.getCurrentGroup() || currentLayer).append(shape)
    }
  }
  const curShape = svgCanvas.getCurShape()
  if (data.curStyles) {
    assignAttributes(shape, {
      fill: curShape.fill,
      stroke: curShape.stroke,
      'stroke-width': curShape.stroke_width,
      'stroke-dasharray': curShape.stroke_dasharray,
      'stroke-linejoin': curShape.stroke_linejoin,
      'stroke-linecap': curShape.stroke_linecap,
      'stroke-opacity': curShape.stroke_opacity,
      'fill-opacity': curShape.fill_opacity,
      opacity: curShape.opacity / 2,
      style: 'pointer-events:inherit'
    }, 100)
  }
  assignAttributes(shape, data.attr, 100)
  cleanupElement(shape)

  // Children
  if (data.children) {
    data.children.forEach((child) => {
      shape.append(addSVGElementsFromJson(child))
    })
  }

  return shape
}
This should really be an intersection implementing all rather than a union.
@name module:json.addSVGElementsFromJson
@type {module:utilities.EditorContext#addSVGElementsFromJson|module:path.EditorContext#addSVGElementsFromJson}