will-mutate
v1.3.0
Published
Runtime test to that detects mutations to objects
Downloads
8
Maintainers
Readme
Will Mutate
Runtime test to that detects mutations to objects
Description
Detect when and where mutations occur in your code. It may seem cool, but it's not a replacement for strict typings or tests. It is currently a proof-of-concept and a debugging tool.
Why did this property change?! I didn't do that!!!
Features
- Detect any proxy-compatible mutation as it happens
- Throws a stack trace of the code that caused the mutation
- Includes a property path to the mutation in the object
Usage as a Utility Function
Installation
npm install will-mutate
Code
const proxify = require("will-mutate/proxify");
function foo () {
// Setup
const target = {
array: [],
};
const targetProxy = proxify(target, {deep: true});
// Mutation
targetProxy.array.push("Test");
}
// Run
foo();
Errors
The below error is taken from running the above code snippet. You can see that the array
property was pushed to.
The native code for .push()
assigns "Test"
to the first index, so we see an error from the set
(assignment operator) trap inside the foo
function in the foo.js
module.
Error: Mutation assertion failed. `set` trap triggered on `target.array[0]`.
at Object.handler.<computed> [as set] (proxify.js:152:10)
at Proxy.push (<anonymous>)
at Object.handler.<computed> [as apply] (proxify.js:175:24)
at foo (foo.js:10:20)
at Object.<anonymous> (foo.js:13:1)
API
proxyify(target, [options])
Create a Will Mutate mutation proxy for a target object.
Returns: Proxy
- The function or object passed as target
but as an ES6 Proxy
| Parameter | Type | Description |
| --------- | --------------------------------- | ----------------------------------------------------------- |
| target | Function
| Object
| Array
| Function, array, or other object to watch mutations on |
| [options] | Object
| Options that controls how the proxy acts and when it errors |
options
| Option | Type | Default | Description |
| --------- | --------- | ------- | ----------------------------------------------------------- |
| deep | boolean
| false
| If the proxy should recursively wrap the entire object |
| prototype | boolean
| false
| If the proxy should recursively wrap the object's prototype |
Usage as a Babel Plugin
Installation
npm install will-mutate @babel/core@^7.0.0 --save-dev
Code
Add the $shouldNotMutate
function call directly above any function declaration or expression with the name of any variable in-scope at the beginning of the function body.
// In this example, we're asserting that the argument `foo` will not mutate
$shouldNotMutate(["foo"]);
function bar (foo, other) {
foo.prop = "Test";
other.prop = "Don't change me";
}
Errors
The below error is taken from running the above code snippet with node ./bar.js
after compilation with Babel. You can see that the prop
property was changed using set
(assignment operator) inside the bar
function in the bar.js
module.
Error: Mutation assertion failed. `set` trap triggered on `target.prop`.
at Object.handler.<computed> [as set] (bar.js:148:13)
at bar (bar.js:194:31)
at Object.<anonymous> (bar.js:211:1)
Babel Config
You must also add Will Mutate to your Babel config. If you intend to leave the functions in your codebase you can use noop
to run whenever you do not want runtime errors (e.g. production).
babel.config.js
module.exports = {
plugins: [
process.env.NODE_ENV === "development"
? "will-mutate"
: "will-mutate/noop",
],
};
Understanding Traps
If you see a trap you do not understand, MDN has a list of proxy traps where you can understand the conditions it will trigger under. Every trap related to mutations is implemented.
Alternatives
- TypeScript or Flow typings
- mutation-sentinel
License
Copyright Evelyn Hathaway and Corbin Crutchley, MIT License