npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

literal-map

v0.2.2

Published

A Map that acts like an object literal to better reflect Python dictionaries in JS

Downloads

172

Readme

literal-map

Social Media Photo by Pisit Heng on Unsplash

build Coverage Status

A Map that acts like an object literal to better reflect Python dictionaries in JS or allow literal to Map or Map to literals migrations.

import LiteralMap from 'literal-map';

// create Map like instances
const lm = new LiteralMap([['a', 1], ['b', 2]]);

lm instanceof Map;        // true
lm instanceof LiteralMap; // true

// access properties like object literals
// or just like Python dictionaries
lm.a === 1;               // true
lm.get('a') === 1;        // true

// set new properties or remove these
delete lm.b;
lm.c = 3;

// destructor or spread like literals
JSON.stringify({...lm, b:2}); // {"a":1,"c":3,"b":2}

// serialize like literals
JSON.stringify(lm);       // {"a":1,"c":3}

// array spread like Map
[...lm];                  // [['a',1],['c',3]]

API Details

  • the class returns a Proxy of a map with a handler that simplifies access to, and manipulation of, the underlying data as object literal
  • all explicitly set fields/properties are stored in the map
  • special descriptors are also directly stored in the map and, if enumerable, spread as literal too
  • overriding Map inherited methods or properties is allowed, the same as one can override hasOwnProperty in any object literal. If deleted, inherited fields will work again as before.
  • structuredClone cannot work with Proxy out of the box, but:
    • structuredClone({...lm}) works
    • structuredClone([...lm]) works
    • structuredClone(new Map(lm)) also works

Differently from Python dictionaries

In Python, there is a difference when dict.get(...) is accessed VS dict["get"]:

  • the former will always use the inherited method even if dict["get"] = 123 was previously used
  • the latter will result into JSON field and it's accessed as such, not as the method

In this regard, Python dictionaries are less surprise prone if a dictionary is created as:

obj = {"get": 1, "set": 2}

# test
obj["get"]      # 1
obj["set"]      # 2

# valid and working!
obj.get("get")  # 1

Unfortunately in JS it's not possible to disambiguate between direct access and square-brackets access, but because an object literal can be defined as such, some method might be shadowed:

const obj = new LiteralMap(
  Object.entries({"get": 1, "set": 2})
);

// test
obj["get"];     // 1
obj["set"];     // 2

// unexpected thrown error
obj.get("get"); // obj.get is not a function

Explicit Workaround

When explicit usage of underlying inherited method or fields is meant, and the instance is known to be a Python dictionary, it's always possible to forward through the class itself inherited utilities:

// at runtime or trapped once: it's the same!
const { get, set, size } = LiteralMap;

const obj = new LiteralMap(
  Object.entries({"get": 1, "set": 2})
);

// test
obj.get;        // 1
obj.set;        // 2

// valid and working!
size(obj);          // 2

get(obj, "get");    // 1
set(obj, "get", 3); // obj

obj.get;            // 3

While ergonomics are not perfect with the suggested workaround, it is possible when non object literals are meant or expected to always do the right thing underneath and without penalizing performance in a relevant way.

The internal map is also meant to never leak in the wild, so that undesired operations that could break expectations should never happen.