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-rewire-exports

v2.3.0

Published

Babel plugin for stubbing (ES6, ES2015) module exports

Downloads

48,366

Readme

babel-plugin-rewire-exports

NPM Version NPM Downloads Build Status

Babel plugin for stubbing (ES6, ES2015) module exports. It allows to rewire the exported values in all the importing modules. Unlike babel-plugin-rewire it doesn't modify the module internals (e.g. imports and top-level variables and functions). See How it works section for implementation details.

Exports

Plugin transforms module exports in such a way that they can be stubbed (or "rewired") via the following API:

  • default export - plugin exports additional rewire(stub) function that allows to replace the original
  • named exports - for each export (e.g. export var foo) an additional function rewire$foo(stub) is exported
  • restore() function allows to restore the exports to their original values
  • if there are existing rewire or restore top-level identifiers, the generated exports will be named rewire$default and restore$rewire respectively

Example

Named export:

//------ text.js ------
export let message = 'Hello world!'

//------ logger.js ------
import {message} from './text.js'

export default function () {
  console.log(message)
}

//------ main.js ------
import {rewire$message, restore} from './text.js'
import logger from './logger.js'

logger() // 'Hello world!'
rewire$message('I am now rewired')
logger() // 'I am now rewired'
restore()
logger() // 'Hello world!'

Default export:

//------ fetch.js ------
export default function (url) {
  // perform some expensive remote call
}

//------ adapter.js ------
import fetch from './fetch.js'

export function fetchItems() {
  return fetch('/items')
}

//------ test.js ------
import {rewire, restore} from './fetch.js'
import {fetchItems} from './adapter.js'

// Jasmine example
describe('adapter', function () {
  beforeEach(function () {
    rewire(this.spy = jasmine.createSpy('fetch'))
  })
  afterAll(restore)
  
  it('should call fetch', function () {
    fetchItems()
    expect(this.spy).toHaveBeenCalledWith('/items')
  })
})

// Mocha/Chai and Sinon example
describe('adapter', function () {
  var spy

  beforeEach(function () {
    rewire(spy = sinon.spy())
  })
  after(restore)
  
  it('should call fetch', function () {
    fetchItems()
    expect(spy.withArgs('/items').calledOnce).to.be.true
  })
})

Compatibility

How it works

In ES6, imports are live read-only views on exported values:

//------ lib.js ------
export let counter = 3;
export function incCounter() {
    counter++;
}

//------ main1.js ------
import { counter, incCounter } from './lib';

// The imported value `counter` is live
console.log(counter); // 3
incCounter();
console.log(counter); // 4

// The imported value can’t be changed
counter++; // TypeError

This allows for any exports to be overwritten from within the module - and imports will be automatically updated via their bindings.

Transformations

Here's how various kinds of export declarations are transformed:

  • Literals (export default 'foo') - the original value is copied to a variable to be stubbed and restored later: export {_default as default}

  • Variables:

    • named exports (export var foo, export let bar or export {baz}) are left intact, but their initial values are similarly copied to temp variables.
    • default export (export default foo) is converted to a named export to enable live binding: export {foo as default}
  • Constants (export const foo = 'bar' or export default foo) are treated similar to variables, but their values are not modified within the module (since they are read-only) - only exported values are rewired:

    • named exports: export { _foo as foo }
    • default export: export { _default as default }

    You can use unsafeConst option to convert const to let in order to enable live binding.

  • Functions (export default function () {…} or export function foo() {…}) are converted into a function expression and exported variable by the same name. The variable initialization is hoisted to the top of the scope to preserve existing behavior.

  • Classes (export default class foo {…} or export class foo {…}) are handled similarly to functions except the variables are not hoisted (again to preserve the existing behavior).

  • Re-exports (export * from './foo.js' or export {bar} from 'baz') are ignored. They can be rewired in the original modules.

  • Immutable values such as undefined, globals and imports are copied similar to literals.

Installation

$ npm install babel-plugin-rewire-exports

Usage

Via .babelrc (Recommended)

.babelrc

// without options
{
  "plugins": ["rewire-exports"]
}

// with options
{
  "plugins": [
    ["rewire-exports", {
      "unsafeConst": true
    }]
  ]
}

Via CLI

$ babel --plugins rewire-exports script.js

Via Node API

require("@babel/core").transform("code", {
  plugins: ["rewire-exports"]
});

Options

unsafeConst

boolean, defaults to false.

Constants cannot be rewired if you're targeting ES2015+, because the plugin relies on variables being assign-able in order to work. However setting unsafeConst: true will convert export const foo = 'bar' to export let foo = 'bar'. This will allow to treat constant exports as regular variables. This is potentially unsafe if your code relies on constants being read-only.