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

babel-plugin-transform-private-to-weakmap

v1.0.3

Published

Transforms class properties prefixed with an underscore to weakmaps.

Downloads

12

Readme

Introduction

The goal of this plugin is to add more 'real' privacy to properties in classes. Sometimes just using underscores isn't enough because using Object.keys() will still return them and break some automation logic where private properties end up being leaked.

This plugin makes use of closure and weakmaps to completely remove any desired properties from a class. The WeakMap holds all the values for all the instances of a class, where the instances are the key and an object containing all the properties is the value.

This is not perfect, but it added just the privacy I needed to my classes while allowing me to continue to write code the same way without bloating it with symbols or weird references.

Acknowledgment

Know that you can still view the private properties by accessing the static property Classname.private of your classes, but that means there is less of a chance of them being leaked than the original method (using underscore prefix) and you would require the instance itself as a key to access the values anyways.

It also means it's easy to debug the values (just log them in the terminal/console).

Requirements

This plugins works by transforming class properties. That means you need to have the class properties proposal plugin installed, which requires babel 7+.

Packages

| Package | Version | Reason of requirement | | :-- | :---: | :-- | | @babel/core | ^7.1.6 | The minimum required to run babel | | @babel/preset-env | ^7.1.6 | Optional, recommended. Includes most of the nice ESNext features | | @babel/plugin-proposal-class-properties | ^7.1.0 | Adds the class properties syntax support |

npm install --save-dev @babel/core @babel/preset-env @babel/plugin-proposal-class-properties

Installation

This plugin can be installed directly from NPM:

npm install --save-dev babel-plugin-transform-private-to-weakmap

Once it's installed, you can add it to your .babelrc file:

{
  "presets": [ "@babel/preset-env" ],
  "plugins": [
    "@babel/plugin-proposal-class-properties",
    "babel-plugin-transform-private-to-weakmap"
  ]
}

How to use

Any class properties which are defined with a starting underscore will be transformed. Once weakmap per class is generated.

NOTE: The private properties only require an underscore when they are defined, they do not take any underscore when they are referenced in the code.

Example

class Person {
  _firstname;
  _lastname;
  age;
  
  constructor(first, last, age) {
    this.firstname = first;
    this.lastname = last;
    this.age = age;
  }
  
  get name() { return this.firstname + ' ' + this.lastname; }
  
  present() {
    console.log(`Hi! I am ${this.name} and I am ${this.age} years old.`);
  }
} 

let bob = new Person('Bob', 'Holton', 26);
bob.present();
console.log(bob);

The above outputs:

Hi! I am Bob Holton and I am 26 years old.
Person { age: 26 }

Compiled

Here is how the above looks after the transformation:

class Person {
  age;
  
  constructor(first, last, age) {
    Person.private.set(this, {});
    Person.private.get(this).firstname = first;
    Person.private.get(this).lastname = last;
    this.age = age;
  }
  
  get name() {
    return Person.private.get(this).firstname
     + ' '
     + Person.private.get(this).lastname;
  }
  
  present() {
    console.log(`Hi! I am ${this.name} and I am ${this.age} years old.`);
  }
} 
Person.private = new WeakMap();

let bob = new Person('Bob', 'Holton', 26);
bob.present();
console.log(bob);

Keep in mind

Initializing private properties

You are allowed to initialize your private properties as expected:

Source
class Point {
  _x=0; _y=1;
  constructor(x=null, y=null) {
    if(x !== null) this.x = x;
    if(y !== null) this.y = y;
  }
}
Output
class Point {
  constructor(x=null, y=null) {
    Point.private.set(this, {
      x: 0,
      y: 1
    });
    if(x !== null) Point.private.get(this).x = x;
    if(y !== null) Point.private.get(this).y = y;
  }
}
Point.private = new WeakMap();

Classes without a constructor

If your class does not have a constructor, one will automatically be added:

Source
class Test {
  _name = 'Test';
  test() {
    console.log(this.name);
  }
}
Output
class Test {
  constructor() {
    Test.private.set(this, { name: 'Test' });
  }
  test() {
    console.log(Test.private.get(this).name);
  }
}

Extending classes without constructor

If your class does not have a constructor and it extends another class, then this transform plugin will not be able to automatically call super() with the proper arguments. In that case, please take the time to add a proper constructor to your classes. This is a known limitation of this plugin.