Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

boxed-immutable

Package Overview
Dependencies
Maintainers
1
Versions
29
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

boxed-immutable - npm Package Compare versions

Comparing version 0.1.3 to 0.1.4

lib/boxed-on-demand.js

5

index.js
'use strict';
const boxed = require('./lib/boxed-immutable');
const boxedOnDemand = require('./lib/boxed-on-demand');
exports._$ = boxed.box;
exports.createBox = boxed.createBox;
exports.boxedOnDemand = boxedOnDemand.boxedOnDemand;
// mostly for texting
// mostly for testing
exports.Boxed = boxed.Boxed;
exports.BoxedOnDemand = boxedOnDemand.BoxedOnDemand;
exports.BOXED_GET_THIS = boxed.BOXED_GET_THIS;

34

lib/boxed-immutable.js

@@ -49,2 +49,8 @@ /** internal

},
default: {
get: function () {return this.setDefaultValue;},
set: function (value) {return this.setDefaultValue(value);},
delete: function () {return false;},
ownPropertyDescriptor: function () {return { value: this.value, writable: true, /*enumerable: false, configurable: false, get:UNDEFINED, set:UNDEFINED,*/ };},
},
"": { // $boxed with after stripping off prefix/suffix _$

@@ -292,2 +298,5 @@ get: function () {return this.proxiedThis;},

let boxed = new Boxed(value, this, prop), BoxedHandler;
if (this.modifiedProps.hasOwnProperty(prop)) {
boxed.isCopy = true;
}
this.boxedProps[prop] = boxed;

@@ -455,13 +464,13 @@ boxedProxy(boxed);

this.value = value;
this.isCopy = true;
this.isFullCopy = true;
// detach all boxed props and clear modified props, we don't need them.
this.detachAllProps();
this.modifiedProps = {};
if (this.parent && this.prop) {
// set in parent so we are invalidated
this.parent.set(this.prop, value);
} else {
this.value = value;
this.isCopy = true;
this.isFullCopy = true;
// detach all boxed props and clear modified props, we don't need them.
this.detachAllProps();
this.modifiedProps = {};
this.parent.set(this.prop, value, this);
}

@@ -496,2 +505,7 @@ }

// only set value if undefined
Boxed.prototype.setDefaultValue = function (value) {
return this.value !== UNDEFINED || value === UNDEFINED || this.setValueOf(value);
};
// if value is object or array: return only first level children that were modified or UNDEFINED if no mods

@@ -786,2 +800,3 @@ // if otherwise same as valueOfModified return value if modified or UNDEFINED if not modified

function boxedProxy(boxed) {
boxed.setDefaultValue = boxed.setDefaultValue.bind(boxed);
boxed.boxedWith = boxed.boxedWith.bind(boxed);

@@ -832,2 +847,3 @@ boxed.boxedWith[BOXED_GET_THIS] = boxed;

context.globalBox = globalBoxKey;
box.boxedContext = context;
return box;

@@ -834,0 +850,0 @@ }

{
"name": "boxed-immutable",
"version": "0.1.3",
"version": "0.1.4",
"private": false,

@@ -5,0 +5,0 @@ "description": "Immutable proxy wrapper with auto-vivification",

@@ -97,4 +97,4 @@ # boxed-immutable

empty["_$"] = 5;
empty[_$] = 5;
empty._$ = 5; // if you know its empty can also do empty[0] however if you are wrong then the latter will overwrite the value at 0
empty[_$] = 5; // may not work, depends on how functions is converted to string
empty._$ = 5; // simplest and safest alternative
// result: [5]

@@ -143,6 +143,7 @@

// the same can be achieved with, without having to increment the index
let obj = _$({});
obj.prop = "a";
obj[_$] = 5;
obj[_$] = 15;
obj[_$] = 25;
obj._$ = 5;
obj._$ = 15;
obj._$ = 25;
```

@@ -166,5 +167,5 @@

obj.$_field_$.subField = 4;
obj.$_prop_$[$__$] = "a";
obj.$_prop_$[$__$] = "b";
obj.$_prop_$[$__$] = "c";
obj.$_prop_$.$__$ = "a";
obj.$_prop_$.$__$ = "b";
obj.$_prop_$.$__$ = "c";

@@ -198,2 +199,4 @@ let result = obj.$_unboxed$_$;

### boxed-immutable box
Change `_$` to your combination of prefix/suffix if modifying defaults.

@@ -212,2 +215,3 @@

| `modified$_$` | value if modified else undefined | same as above | same as above | error |
| `default$_$` | function | set value if it is undefined, otherwise do nothing | error | error |
| `delta$_$` | modified properties of first level, full props thereafter: shallow delta | do shallow delta update of properties, all properties after first level will be changed | error | error |

@@ -235,5 +239,5 @@ | `deepDelta$_$` | modified properties only of all levels: deep delta | do deep delta update with value, only modified properties of all levels are changed. | error | error |

:warning: When a value is set on the parent collection it orphans the boxed state for
all the properties of the parent for which you kept reference. These detached properties will
still work but only on their own copy of the data since they are now detached from the root.
:warning: When a value is set on the parent collection it orphans the boxed state for all the
properties of the parent for which you kept reference. These detached properties will still work
but only on their own copy of the data since they are now detached from the root.

@@ -246,5 +250,5 @@ For example this will happen when you do something like:

let nested = boxed.level1_$.level2_$.level3_$;
nested[_$] = 0;
nested[_$] = 1;
nested[_$] = 2;
nested._$ = 0;
nested._$ = 1;
nested._$ = 2;
// boxed is now: { level1: { level2: { level3: [0,1,2]}}};

@@ -254,5 +258,5 @@

nested[_$] = 3;
nested[_$] = 4;
nested[_$] = 5;
nested._$ = 3;
nested._$ = 4;
nested._$ = 5;
// nested is [0,1,2,3,4,5]

@@ -262,2 +266,88 @@ // boxed is still: { level1: { level2: { level3: [0,1,2]}}};

### boxed-immutable boxedOnDemand
Provides a boxed proxy to immutable state, with `.save()` and `.cancel()` methods for saving or
canceling state changes. With minimal code this allows transparent access to current state
without the callers worrying about stale data or how to apply the changes back to the state
holder.
```javascript
const boxedOnDemand = require('boxed-immutable').boxedOnDemand;
// your current function for returning immutable state object
function getSimpleState() {
}
let stateHolder;
// your current function for setting a new state
function saveState(newState) {
// 1. update state
// 2. regardless of how this function is called, cancel the boxed on demand so next access will be forced to get a fresh state
stateHolder.cancel();
}
// wrap in proxy so boxed state can be provided automatically
// use in new getState to get boxed on demand
stateHolder = boxedOnDemand(undefined, () => {
return getSimpleState();
}, (modified, boxed) => {
// call the save state function to apply changes in full
saveState(modified);
// or if your saveState can handle delta
//saveState(boxed.delta$_$);
// or anything else without having to change the users of your state API
});
// use new function to provide access to now boxed immutable state
function getState() {
return stateHolder;
}
// somewhere in the code.
let state = getState();
// can use state as before or as boxed state, except now there is no need to get a new state
// every time. The same state will reflect latest changes. Make a copy if you need immutable state
// NOTE: now it is not immutable, make a copy of its .unboxed$_$ property if you need an immutable copy
// make changes
// saving is handled by the provider instead of having the caller know how to update state
state.save(); // save changes
state.cancel(); // discard changes
// next access to any properties of the boxed state will get a fresh copy to eliminate invalid state content after update/cancel
```
| Property | Get | Set | Delete | Call |
|:---------|:---------|:------|:-------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `save` | function | error | error | calls the saveState callback passed to boxedOnDemand function, returns value returned from callback, callback only called if there were changes made to boxed object |
| `cancel` | function | error | error | cancels any changes and destroys the boxed object, it is recreated on next access with a fresh copy of the immutable state |
#### boxedOnDemand(getState, saveState, options)
```javascript
const boxedOnDemand = require('boxed-immutable').boxedOnDemand;
const onDemandState = boxedOnDemand();
```
Used to construct a new boxed on demand proxy.
| argument | default | Description |
|:------------|:--------|:-----------------------------------------------------------------------------------------------------------------------------------------|
| `getState` | none | callback to call to obtain the current state |
| `saveState` | none | callback to call on save operation, returned result passed back to caller of `save()`. |
| `options` | box | options to use. Can be a box as provided by boxedImmutable.box or boxedImmutable.createBox(), then all other options are set to defaults |
| Option | Default | Description |
|:-------------------|:-----------|:-------------------------------------------------------------------------------------------------------------------------------------------------|
| `box`: | global box | Which box creation to use for each new boxed state object |
| `saveBoxedProp`: | 'save' | name of the `save` property to use, allows changing of the function to 'commit' or something that will not conflict with your state's properties |
| `cancelBoxedProp`: | 'cancel' | name of the `cancel` property to use, allows changing of the function to something that will not conflict with your state's properties |
| `wrapProps`: | false | if true will wrap the saveBoxedProp and cancelBoxedProp the same as magical properties of the boxed object created from the box |
## License

@@ -264,0 +354,0 @@

@@ -230,1 +230,84 @@ "use strict";

describe('Multiple modifications of same field', () => {
let origVal;
let boxedVal;
let boxedProxy;
let expectedValue;
let deltaValue;
let deepDeltaValue;
beforeAll(() => {
let vals = createBoxed({field: ""});
origVal = vals.origVal;
boxedVal = vals.boxedVal;
boxedProxy = vals.boxedProxy;
boxedProxy.field_$ = 1;
boxedProxy.field_$ = 2;
boxedProxy.field_$ = 3;
expectedValue = {field: 3};
deepDeltaValue = deltaValue = expectedValue;
});
test('value == modified', () => {
const value = boxedVal.value;
expect(value).toEqual(expectedValue);
});
test('modified$_$ is value', () => {
expect(boxedProxy.modified$_$).toEqual(boxedVal.value);
});
test('delta$_$ == delta', () => {
expect(boxedProxy.delta$_$).toEqual(deltaValue);
});
test('deepDelta$_$ == deepDelta', () => {
expect(boxedProxy.deepDelta$_$).toEqual(deepDeltaValue);
});
});
describe('Default Value setting', () => {
let origVal;
let boxedVal;
let boxedProxy;
let expectedValue;
let deltaValue;
let deepDeltaValue;
beforeAll(() => {
let vals = createBoxed({field1: ""});
origVal = vals.origVal;
boxedVal = vals.boxedVal;
boxedProxy = vals.boxedProxy;
boxedProxy.field1_$.default$_$ = 1;
boxedProxy.field2_$.default$_$ = 2;
boxedProxy.field2_$.default$_$ = 3;
boxedProxy.field3_$.default$_$(1);
boxedProxy.field3_$.default$_$(2);
boxedProxy.field3_$.default$_$(3);
expectedValue = {field1: "", field2: 2, field3:1, };
deepDeltaValue = deltaValue = {field2: 2, field3:1, };
});
test('value == modified', () => {
const value = boxedVal.value;
expect(value).toEqual(expectedValue);
});
test('modified$_$ is value', () => {
expect(boxedProxy.modified$_$).toEqual(boxedVal.value);
});
test('delta$_$ == delta', () => {
expect(boxedProxy.delta$_$).toEqual(deltaValue);
});
test('deepDelta$_$ == deepDelta', () => {
expect(boxedProxy.deepDelta$_$).toEqual(deepDeltaValue);
});
});

@@ -6,2 +6,3 @@ # Version History

- [0.1.4](#014)
- [0.1.3](#013)

@@ -13,2 +14,11 @@ - [0.1.2](#012)

## 0.1.4
* Fix: deep delta would not include properties for which proxy was created after the property
was already modified in the parent.
* Add: `default$_$` magic property which only changes value if it is `undefined`, otherwise a
noop. Use: `boxed.field_$.default$_$ = value;` or `boxed.field_$.default$_$(value)`
* Add: `boxedOnDemand` proxy wrapper to allow creating a boxed state with `save()` and
`cancel()` methods. It provides a new copy of the state if it has changed from last access.
## 0.1.3

@@ -15,0 +25,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc