Skip to content

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

@dlongley

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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions