Comparing version 5.1.4 to 6.0.0
{ | ||
"name": "one", | ||
"version": "5.1.4", | ||
"version": "6.0.0", | ||
"description": "Browser application cache. It guarantees entity uniqueness across the entire cache.", | ||
"main": "lib/index.js", | ||
"typings": "lib/index", | ||
"files": [ | ||
"lib/" | ||
], | ||
"directories": { | ||
"test": "test" | ||
}, | ||
"scripts": { | ||
"test": "jest", | ||
"clean": "rimraf lib dist coverage", | ||
"test": "istanbul cover ./node_modules/mocha/bin/_mocha --report lcovonly -- -R spec && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage", | ||
"cov": "istanbul cover ./node_modules/mocha/bin/_mocha -- -R spec", | ||
"build:js": "webpack --config webpack.config.js", | ||
"build:js:min": "webpack --config webpack.config.production.js", | ||
"build:lib": "babel src --out-dir lib", | ||
"build:lib": "tsc --rootDir src --outDir lib", | ||
"build": "npm run build:lib && npm run build:js && npm run build:js:min", | ||
"tt": "webpack --config webpack.tt.config.js && webpack --config webpack.st.config.js", | ||
"prepub": "npm run clean && npm run build" | ||
@@ -27,2 +32,17 @@ }, | ||
], | ||
"jest": { | ||
"transform": { | ||
"^.+\\.tsx?$": "<rootDir>/node_modules/ts-jest/preprocessor.js" | ||
}, | ||
"testRegex": "(\\.(test|spec))\\.(ts|js)$", | ||
"moduleFileExtensions": [ | ||
"ts", | ||
"js", | ||
"json" | ||
], | ||
"moduleDirectories": [ | ||
"node_modules" | ||
], | ||
"testEnvironment": "node" | ||
}, | ||
"author": "Dan Maier", | ||
@@ -36,24 +56,26 @@ "license": "MIT", | ||
"devDependencies": { | ||
"babel-cli": "^6.16.0", | ||
"babel-core": "^6.9.1", | ||
"@types/jest": "^20.0.2", | ||
"babel-core": "^6.14.0", | ||
"babel-loader": "^6.2.5", | ||
"babel-polyfill": "^6.13.0", | ||
"babel-preset-es2015": "^6.9.0", | ||
"babel-register": "^6.9.0", | ||
"babel-runtime": "^6.9.2", | ||
"chai": "^3.4.1", | ||
"coveralls": "^2.11.9", | ||
"istanbul": "^1.0.0-alpha.2", | ||
"mocha": "^2.3.4", | ||
"mocha-babel": "^3 .0.0", | ||
"mocha-lcov-reporter": "^1.2.0", | ||
"node-jsdom": "^3.1.5", | ||
"rimraf": "^2.5.0", | ||
"sinon": "^1.17.3", | ||
"sinon-chai": "^2.8.0", | ||
"strip-loader": "^0.1.1", | ||
"wallaby-webpack": "0.0.22", | ||
"webpack": "^1.12.9", | ||
"webpack-merge": "^0.3.0" | ||
"babel-polyfill": "^6.16.0", | ||
"babel-preset-es2015": "6.9.0", | ||
"babel-preset-stage-0": "^6.5.0", | ||
"eslint": "^4.0.0", | ||
"eslint-config-standard": "^10.2.1", | ||
"eslint-plugin-import": "^2.6.0", | ||
"eslint-plugin-jest": "^20.0.3", | ||
"eslint-plugin-node": "^5.0.0", | ||
"eslint-plugin-promise": "^3.5.0", | ||
"eslint-plugin-standard": "^3.0.1", | ||
"jest": "^20.0.4", | ||
"path": "^0.12.7", | ||
"rimraf": "^2.5.4", | ||
"ts-jest": "^20.0.6", | ||
"ts-loader": "^1.2.2", | ||
"typescript": "^2.3.4", | ||
"typescript-eslint-parser": "^3.0.0", | ||
"webpack": "^1.13.2", | ||
"webpack-dev-middleware": "^1.8.2", | ||
"webpack-dev-server": "^1.16.1" | ||
} | ||
} |
185
README.md
@@ -1,2 +0,2 @@ | ||
![One logo](https://lh3.googleusercontent.com/5CBS5xCZm0BQQ9GaE8SfDnomFNWkr5jU-ZPRi_Cdptj7__GSyRPCeQbQA1OBxt0OZ3LNs-a_eGiyBSCtOM4=s100 "One logo") | ||
![One logo](https://lh3.googleusercontent.com/5CBS5xCZm0BQQ9GaE8SfDnomFNWkr5jU-ZPRi_Cdptj7__GSyRPCeQbQA1OBxt0OZ3LNs-a_eGiyBSCtOM4=s100 "One logo") | ||
@@ -7,74 +7,81 @@ # **ONE** # | ||
[![Npm Status](https://badge.fury.io/js/one.svg)](https://npmjs.com/package/one) [![Build Status](https://travis-ci.org/maierson/one.svg)](https://travis-ci.org/maierson/one) [![Coverage Status](https://coveralls.io/repos/github/maierson/one/badge.svg?branch=master)](https://coveralls.io/github/maierson/one?branch=master) | ||
[![Npm Status](https://badge.fury.io/js/one.svg)](https://npmjs.com/package/one-typescript) [![Build Status](https://travis-ci.org/maierson/one.svg)](https://travis-ci.org/maierson/one) [![Coverage Status](https://coveralls.io/repos/github/maierson/one/badge.svg?branch=master)](https://coveralls.io/github/maierson/one?branch=master) | ||
Each entity tracked for uniqueness must have a unique id. There is precisely ONE distinct entity in the cache | ||
Each entity tracked for uniqueness must have a unique id. There is precisely ONE distinct entity in the cache | ||
for each unique id. Entities that do not have a unique id are still cached but not tracked for uniqueness. | ||
###Usage | ||
- [Changes](#changes) | ||
- [Api](#api) | ||
- [Usage](#usage) | ||
- [Immutable](#immutable) | ||
- [Configuration](#configuration) | ||
- [Motivation](#motivation) | ||
- [Performance](#performance-considerations) | ||
- [Data shape](#data-shape) | ||
``` | ||
npm install one --save | ||
``` | ||
### __Changes__ | ||
1. Complete rewrite in typescript. | ||
2. Fix some subtle bugs related to object structure (ie modifiying arrays would sometimes behave unpredictably based on the parent's structure). | ||
3. Remove the need for ```babel-polyfill``` | ||
4. __Breaking api changes:__ Simplified minimal api. You really only need the commands in the table below. There are a couple of other options mostly for debugging (see the Api section for the development api list). | ||
```js | ||
import * as One from 'one'; | ||
| Command | Action | | ||
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| __getCache__ | Create or access a specific version of the cache. There can be multiple concurrent versions of the cache in case distinct versions of the same entity are needed (for example if display and edit data need to be different until a user commits changes). ```One.getCache('edit') ``` would create a cache dedicated to edit operations. | | ||
| __put__ | Add an entity to the cache and make it immutable. | | ||
| __get__ | Retrieve an entity from the cache. This is a fast hash map locator. | | ||
| __getEdit__ | Get a shallow editable version of the entity from the cache. Inner nested entities are still immutable. This is in order to make efficient use of trie structures. | | ||
| __evict__ | Remove an entity from the cache. Evicts it from all parents as well. | | ||
// get a hold of an instance | ||
let one = One.getCache(); | ||
// or with debugging options | ||
let one = One.getCache(true); | ||
### __Api__ | ||
In addition to the 5 production api commands there are 4 options intended for development: | ||
// you can then use the instance | ||
one.put(item); | ||
| Command | Action | | ||
| ---------- | :--------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| __reset__ | Resets the cache to empty. Useful for testing. | | ||
| __length__ | Number of nodes in the current cache. Each node contains one atomic change to the cache so moving between nodes gives you time travelling. | | ||
| __size__ | Number of entities cached on the current node (the size of the node). | | ||
| __print__ | Provides a printable representation of the entire cache that can be passed on to a logger. Slow. For debugging only. Do not use in production. | | ||
// One.getCache() is a singleton so you can also do this | ||
One.getCache().put(item); | ||
``` | ||
Or simply put ```one.min.js``` on your page to access the ```One``` global variable from anywhere. In this case the instance is created for you and you can access it directly (no need to call ```getCache()```). | ||
### __Usage__ | ||
```js | ||
npm install one --save | ||
``` | ||
#!javascript | ||
One.put(item) | ||
or | ||
```js | ||
yarn add one | ||
``` | ||
Use it | ||
```js | ||
import * as One from 'one' | ||
####A word about javascript versions compatibility | ||
ES6 introduced Maps which are supposed to be up to 3 times more efficient than using Object for storing and retrieving keyed items. | ||
```One``` uses Maps by default. However for older browsers that do not support the standard you will need to compile the library with the babel-polyfill. The caveat is that it bumps up the size of the minified lib from ~16kb go ~100kb. | ||
// get a hold of an instance | ||
let one = One.getCache() | ||
To compile with polyfill: | ||
// you can then use the instance to cache items | ||
one.put(item) | ||
1. Uncomment this line in index.js | ||
``` | ||
#!javascript | ||
// One.getCache() is a singleton so you can also do this | ||
One.getCache().put(item) | ||
//import 'babel-polyfill'; | ||
// or if you are only using the default instance of the cache | ||
One.put(item) | ||
``` | ||
2. Run this line in terminal from the One folder: | ||
Or simply put ```one.min.js``` on your page to access the ```One``` global variable from anywhere. In this case the instance is created for you and you can access it directly. | ||
``` | ||
#!javascript | ||
npm run prepub | ||
```js | ||
One.put(item) | ||
``` | ||
That's it. The compiled versions are added to the dist folder. | ||
###Api | ||
There are three significant operation types to be aware of: | ||
* **[put](https://maierson.gitbooks.io/one/content/put.html) / [get](https://maierson.gitbooks.io/one/content/get.html) / [evict](https://maierson.gitbooks.io/one/content/evict.html)** - items go into the cache with a ```put``` operation and come out with a ```get``` call. Use ```evict``` to force items out of the cache. | ||
* **[queue](https://maierson.gitbooks.io/one/content/queue.html)** - fast input to bypass uniqueness tracking | ||
* **[time travel](https://maierson.gitbooks.io/one/content/time_travel.html)** - ```undo()``` and ```redo()``` to go back and forth in time | ||
Some code | ||
```js | ||
let item1 = {uid:1} | ||
let item2 = {uid:2, ref:item1} | ||
let item1 = { uid:1 } | ||
let item2 = { uid:2, ref:item1 } | ||
One.put(item2) | ||
@@ -89,7 +96,7 @@ | ||
###Immutable | ||
All data is immutable. Once an item enters the cache it freezes and cannot change. This is to enable quick identity checks against immutable entities (ie React identity check). | ||
### __Immutable__ | ||
All data is immutable. Once an item enters the cache it freezes and cannot change. This is to enable quick identity checks against immutable entities (ie React / Redux identity check). | ||
```js | ||
let item = {uid:1} | ||
let item = { uid:1 } | ||
Object.isFrozen(item) // false | ||
@@ -107,3 +114,3 @@ | ||
```js | ||
let item = {uid:1} | ||
let item = { uid:1 } | ||
One.put(item) | ||
@@ -122,9 +129,32 @@ | ||
``` | ||
__Important__ Edit clones are shallow. If you want to edit a nested child that also has a uid you must get an editable copy of the child. | ||
```js | ||
const item1 = { uid:1 } // uid item cached separately | ||
const item2 = { value: 'test' } // item has no uid - it will be cloned for edit | ||
const item = { | ||
uid: 1, | ||
item1, | ||
item2 | ||
} | ||
one.put(item) | ||
const editable = one.getEdit(item) | ||
Object.isFrozen(editable.item1) // true - item1 has a uid - not cloned | ||
item1 === editable.item1 // true | ||
Object.isFrozen(editable.item2) // false item2 has no uid - it will be cloned | ||
item2 === editable.item2 // false | ||
``` | ||
Editing an item changes all its instances in the cache: | ||
```js | ||
let item = {uid:1} | ||
let item2 = {uid:1, child:item} | ||
let item = { uid:1 } | ||
let item2 = { uid:2, child:item } | ||
One.put(item2) | ||
One.get(1) === item // true | ||
@@ -141,11 +171,24 @@ One.get(2) === item2 // true | ||
``` | ||
### __Configuration__ | ||
###Motivation | ||
More an more applications are giving users the ability to edit data in the browser. | ||
With a normalized data model various instances of an entity can exist at the same time in different locations. This depends on how data is received from the server and added to the local model / store. | ||
For existing code bases the name of the `uid` property can be configured via a config object passed as a second argument to the `.getCache()` method. In order for this to work correctly the values held by the configured property must be unique across all instances. | ||
This is inconvenient because: | ||
* Keeping all the instances in sync can be a daunting task. | ||
* It can make debugging hard. | ||
* It requires tracking each instance and makes reasoning about data complicated. | ||
```js | ||
const one = One.getCache('test', { uidName:'id' }) | ||
const item = { id:'unique_id_value' } | ||
one.put(item) | ||
one.get('unique_id_value') !== undefined // true (works) | ||
``` | ||
### __Motivation__ | ||
More an more applications are giving users the ability to edit data in the browser. | ||
With a normalized data model various instances of an entity can exist at the same time in different locations. This depends on how data is received from the server and added to the local model / store. | ||
This is inconvenient because: | ||
* Keeping all the instances in sync can be a daunting task. | ||
* It can make debugging hard. | ||
* It requires tracking each instance and makes reasoning about data complicated. | ||
* It can make the application structure needlessly complex. | ||
@@ -155,19 +198,9 @@ | ||
###Performance considerations | ||
Yes there is a performance cost in analyzing each entity deeply to track its dependencies. ```One``` offers a couple of ways to mitigate this: **Read optimization** and **Queuing**. | ||
* **Read optimized**: the penalty is incurred on write operations only. These happen a lot less frequently than read ops. Read ops are super fast (a simple key lookup). | ||
* **Queuing** allows the developer to choose when to perform the write operation. ```One``` defers the write analysis when writing to the queue. The queue can commit between render operations. This way the UI remains fluid. | ||
If you were to track all instances of an entity on each update the write penalty could end up being comparably high. This is besides the added complexity introduced by such tracking management. | ||
### __Performance considerations__ | ||
###Data shape | ||
This is not currently designed to work with cyclical data. It is best for non-cyclical objects received from the server in the form of json (or other non-cyclical fomats). | ||
It might happen later if there's a need. | ||
* __Read optimized__: Yes there is a performance cost in analyzing each entity deeply to track its dependencies. ```One``` mitigates this by being read optimized. The penalty is incurred on write operations only. These happen a lot less frequently than read ops. Read ops are super fast (a simple key lookup). | ||
* __Trie structures__: Data is stored in a trie like structure. This way all entities are referenced (not copied) and minimal changes are performed on every put or getEdit operation. | ||
###Documentation | ||
* [Immutable data](https://maierson.gitbooks.io/one/content/immutable_data.html) | ||
* Api | ||
* [Put](https://maierson.gitbooks.io/one/content/put.html) | ||
* [Get](https://maierson.gitbooks.io/one/content/get.html) | ||
* [Evict](https://maierson.gitbooks.io/one/content/evict.html) | ||
* [Time travel](https://maierson.gitbooks.io/one/content/time_travel.html) | ||
* [Release Notes](https://maierson.gitbooks.io/one/content/release_notes.html) | ||
### __Data shape__ | ||
This is not currently designed to work with cyclical data. It is best for non-cyclical objects received from the server in the form of json (or other non-cyclical fomats). | ||
It might happen later if there's a need. |
Empty package
Supply chain riskPackage does not contain any code. It may be removed, is name squatting, or the result of a faulty package publish.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
200
11914
23
2
0
2