Skip to content

Replace jsonpointer.dict() with Map implementation to avoid creating hidden classes #91

Description

@dlongley

Something like this:

import jsonpointer from 'json-pointer';

export function toJsonPointerMap(obj) {
  const map = new Map();
  jsonpointer.walk(obj, (value, pointer) => {
    map.set(pointer, value);
  });
  return map;
}

Generating a more useful structure might entail (to/from):

export function fromJsonPointerMap({map} = {}) {
  assert(map, 'map', Map);
  return _fromPointers({map});
}

// produces a map of deep pointers to primitives and sets; the values in each
// set share the same pointer value and if any value in the set is an object,
// it becomes a new map of deep pointers from that starting place; the pointer
// value for an empty objects will be an empty map
export function toJsonPointerMap({obj, flat = false} = {}) {
  assert(obj, 'obj', 'object');
  return _toPointers({cursor: obj, map: new Map(), flat});
}

export function _fromPointers({map} = {}) {
  const result = {};

  for(const [pointer, value] of map) {
    // convert any non-primitive values
    let val = value;
    if(value instanceof Map) {
      val = _fromPointers({map: value});
    } else if(value instanceof Set) {
      val = [...value].map(e => e instanceof Map ?
        _fromPointers({map: e}) : e);
    }

    // if root pointer is used, `value` is result
    if(pointer === '/') {
      return val;
    }

    jsonpointer.set(result, pointer, val);
  }

  return result;
}

function _toPointers({
  cursor, map, tokens = [], pointer = '/', flat = false
}) {
  if(!flat && Array.isArray(cursor)) {
    const set = new Set();
    // when `map` is not set, case is array of arrays; return a new map
    const result = map ? set : (map = new Map());
    map.set(pointer, set);
    for(const element of cursor) {
      // reset map, tokens, and pointer for array elements
      set.add(_toPointers({cursor: element, flat}));
    }
    return result;
  }
  if(cursor !== null && typeof cursor === 'object') {
    map = map ?? new Map();
    const entries = Object.entries(cursor);
    if(entries.length === 0) {
      // ensure empty object / array case is represented
      map.set(pointer, Array.isArray(cursor) ? new Set() : new Map());
    }
    for(const [token, value] of entries) {
      tokens.push(String(token));
      pointer = jsonpointer.compile(tokens);
      _toPointers({cursor: value, map, tokens, pointer, flat});
      tokens.pop();
    }
    return map;
  }
  map?.set(pointer, cursor);
  return cursor;
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions