deep-storage
Advanced tools
Comparing version 3.0.1 to 4.0.0
@@ -1,9 +0,17 @@ | ||
// jest.config.js | ||
module.exports = { | ||
rootDir: 'src', | ||
moduleFileExtensions: ['js', 'jsx', 'json', 'ts', 'tsx'], | ||
transform: { | ||
'^.+\\.(ts|tsx)$': '<rootDir>/../preprocessor.js' | ||
"roots": [ | ||
"<rootDir>/src" | ||
], | ||
"transform": { | ||
"^.+\\.tsx?$": "ts-jest" | ||
}, | ||
testMatch: ['**/__tests__/*.(ts|tsx|js)'] | ||
}; | ||
"testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$", | ||
"moduleFileExtensions": [ | ||
"ts", | ||
"tsx", | ||
"js", | ||
"jsx", | ||
"json", | ||
"node" | ||
], | ||
} |
@@ -35,4 +35,4 @@ "use strict"; | ||
while (_) try { | ||
if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t; | ||
if (y = 0, t) op = [0, t.value]; | ||
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; | ||
if (y = 0, t) op = [op[0] & 2, t.value]; | ||
switch (op[0]) { | ||
@@ -58,2 +58,3 @@ case 0: case 1: t = op; break; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var index_1 = require("./index"); | ||
var AsyncStatus; | ||
@@ -168,15 +169,10 @@ (function (AsyncStatus) { | ||
exports.DefaultDeepAsync = DefaultDeepAsync; | ||
exports.deepAsync = function (storage, process) { return __awaiter(_this, void 0, void 0, function () { | ||
exports.deepAsync = function (process) { return __awaiter(_this, void 0, void 0, function () { | ||
var storage; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, storage.set({ | ||
status: AsyncStatus.Created | ||
})]; | ||
case 1: | ||
_a.sent(); | ||
return [2 /*return*/, new DefaultDeepAsync(storage, process)]; | ||
} | ||
storage = index_1.deepStorage({ | ||
status: AsyncStatus.Created | ||
}); | ||
return [2 /*return*/, new DefaultDeepAsync(storage, process)]; | ||
}); | ||
}); }; | ||
exports.default = exports.deepAsync; | ||
//# sourceMappingURL=async.js.map |
301
lib/index.js
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
var __generator = (this && this.__generator) || function (thisArg, body) { | ||
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; | ||
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; | ||
function verb(n) { return function (v) { return step([n, v]); }; } | ||
function step(op) { | ||
if (f) throw new TypeError("Generator is already executing."); | ||
while (_) try { | ||
if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t; | ||
if (y = 0, t) op = [0, t.value]; | ||
switch (op[0]) { | ||
case 0: case 1: t = op; break; | ||
case 4: _.label++; return { value: op[1], done: false }; | ||
case 5: _.label++; y = op[1]; op = [0]; continue; | ||
case 7: op = _.ops.pop(); _.trys.pop(); continue; | ||
default: | ||
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } | ||
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } | ||
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } | ||
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } | ||
if (t[2]) _.ops.pop(); | ||
_.trys.pop(); continue; | ||
} | ||
op = body.call(thisArg, _); | ||
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } | ||
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; | ||
} | ||
}; | ||
function __export(m) { | ||
@@ -42,266 +7,2 @@ for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; | ||
__export(require("./async")); | ||
/** | ||
* Is one array a prefix on another e.g. | ||
* | ||
* [] is a prefix of any array | ||
* ['asdf'] is a prefix of ['asdf', ...] | ||
* | ||
* etc. | ||
* | ||
* @param stateChangePath the full array to check, must not be null | ||
* @param subscriptionPath the partial array to check | ||
*/ | ||
function isPathMatch(stateChangePath, subscriptionPath) { | ||
for (var i = 0; i < Math.min(subscriptionPath.length, stateChangePath.length); i++) { | ||
if (stateChangePath[i] !== subscriptionPath[i]) | ||
return false; | ||
} | ||
return true; | ||
} | ||
exports.isPathMatch = isPathMatch; | ||
var DefaultDeepStorage = /** @class */ (function () { | ||
function DefaultDeepStorage(state) { | ||
var _this = this; | ||
this.state = state; | ||
this.id = 0; | ||
this.subscriptions = {}; | ||
this.update = function (callback) { | ||
return _this.updateIn()(callback); | ||
}; | ||
this.updateProperty = function (key, callback) { | ||
return _this.updateIn(key)(callback); | ||
}; | ||
this.set = function (newValue) { | ||
return _this.updateIn()(function () { return newValue; }); | ||
}; | ||
this.setIn = function () { | ||
var path = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
path[_i] = arguments[_i]; | ||
} | ||
return function (newValue) { | ||
return _this.updateIn.apply(_this, path)(function () { return newValue; }); | ||
}; | ||
}; | ||
this.merge = function (partial) { | ||
_this.update(function (oldState) { | ||
for (var key in partial) { | ||
oldState[key] = partial[key]; | ||
} | ||
return oldState; | ||
}); | ||
}; | ||
this.updateIn = function () { | ||
var path = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
path[_i] = arguments[_i]; | ||
} | ||
return function (callback) { return __awaiter(_this, void 0, void 0, function () { | ||
var oldState, newState, stateChangePath, subscriberId, subscriber; | ||
return __generator(this, function (_a) { | ||
oldState = this.stateIn.apply(this, path); | ||
newState = callback(oldState); | ||
if (path.length === 0) { | ||
this.state = newState; | ||
} | ||
else { | ||
// todo: this will no doubt cause some bugs... better to replace all the | ||
// parent objects too so that reference equality checks work in react | ||
this.stateIn.apply(this, path.slice(0, path.length - 1))[path[path.length - 1]] = newState; | ||
} | ||
stateChangePath = path; | ||
for (subscriberId in this.subscriptions) { | ||
subscriber = this.subscriptions[subscriberId]; | ||
// check to see if we have any matches | ||
if (subscriber.paths.some(function (subscriberPath) { return isPathMatch(stateChangePath, subscriberPath); })) { | ||
subscriber.callback(stateChangePath, newState, oldState); | ||
} | ||
} | ||
return [2 /*return*/, newState]; | ||
}); | ||
}); }; | ||
}; | ||
this.stateIn = function () { | ||
var path = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
path[_i] = arguments[_i]; | ||
} | ||
var currentState = _this.state; | ||
var pathSoFar = []; | ||
for (var _a = 0, path_1 = path; _a < path_1.length; _a++) { | ||
var p = path_1[_a]; | ||
pathSoFar.push(p); | ||
if (!(p in currentState)) { | ||
currentState[p] = {}; | ||
} | ||
currentState = currentState[p]; | ||
} | ||
return currentState; | ||
}; | ||
this.deep = function () { | ||
var path = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
path[_i] = arguments[_i]; | ||
} | ||
return new NestedDeepStorage(path, _this); | ||
}; | ||
this.subscription = function (callback) { | ||
var subscriberId = _this.id++; | ||
_this.subscriptions[subscriberId] = { | ||
callback: callback, | ||
paths: [] | ||
}; | ||
var cancel = function () { | ||
delete _this.subscriptions[subscriberId]; | ||
}; | ||
return { | ||
subscribeTo: function () { | ||
var path = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
path[_i] = arguments[_i]; | ||
} | ||
if (subscriberId in _this.subscriptions) { | ||
_this.subscriptions[subscriberId].paths.push(path); | ||
} | ||
}, | ||
cancel: cancel | ||
}; | ||
}; | ||
this.root = function () { return _this; }; | ||
this.path = []; | ||
} | ||
Object.defineProperty(DefaultDeepStorage.prototype, "props", { | ||
get: function () { | ||
var result = {}; | ||
for (var _i = 0, _a = Object.keys(this.state); _i < _a.length; _i++) { | ||
var key = _a[_i]; | ||
result[key] = this.deep(key); | ||
} | ||
return result; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
return DefaultDeepStorage; | ||
}()); | ||
exports.DefaultDeepStorage = DefaultDeepStorage; | ||
var NestedDeepStorage = /** @class */ (function () { | ||
function NestedDeepStorage(path, rootStorage) { | ||
var _this = this; | ||
this.path = path; | ||
this.rootStorage = rootStorage; | ||
this.setIn = function () { | ||
var path = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
path[_i] = arguments[_i]; | ||
} | ||
return function (newValue) { | ||
return (_a = _this.rootStorage).setIn.apply(_a, _this.path.concat(path))(newValue); | ||
var _a; | ||
}; | ||
}; | ||
this.set = function (newValue) { | ||
return (_a = _this.rootStorage).setIn.apply(_a, _this.path)(newValue); | ||
var _a; | ||
}; | ||
this.update = function (callback) { | ||
return (_a = _this.rootStorage).updateIn.apply(_a, _this.path)(callback); | ||
var _a; | ||
}; | ||
this.updateIn = function () { | ||
var path = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
path[_i] = arguments[_i]; | ||
} | ||
return function (callback) { | ||
return (_a = _this.rootStorage).updateIn.apply(_a, _this.path.concat(path))(callback); | ||
var _a; | ||
}; | ||
}; | ||
this.updateProperty = function (key, callback) { | ||
return (_a = _this.rootStorage).updateIn.apply(_a, _this.path.concat(key))(callback); | ||
var _a; | ||
}; | ||
this.stateIn = function () { | ||
var path = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
path[_i] = arguments[_i]; | ||
} | ||
return (_a = _this.rootStorage).stateIn.apply(_a, _this.path.concat(path)); | ||
var _a; | ||
}; | ||
this.deep = function () { | ||
var path = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
path[_i] = arguments[_i]; | ||
} | ||
return (_a = _this.rootStorage).deep.apply(_a, _this.path.concat(path)); | ||
var _a; | ||
}; | ||
this.subscription = function (callback) { | ||
var rootSubscription = _this.rootStorage.subscription(function (path, newState, oldState) { | ||
callback(path.slice(path.length - _this.path.length, path.length), newState, oldState); | ||
}); | ||
return { | ||
subscribeTo: function () { | ||
var path = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
path[_i] = arguments[_i]; | ||
} | ||
return rootSubscription.subscribeTo.apply(rootSubscription, _this.path.concat(path)); | ||
}, | ||
cancel: rootSubscription.cancel | ||
}; | ||
}; | ||
this.root = function () { return _this.rootStorage; }; | ||
} | ||
Object.defineProperty(NestedDeepStorage.prototype, "state", { | ||
get: function () { | ||
return (_a = this.rootStorage).stateIn.apply(_a, this.path); | ||
var _a; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
Object.defineProperty(NestedDeepStorage.prototype, "props", { | ||
get: function () { | ||
var result = {}; | ||
for (var _i = 0, _a = Object.keys(this.state); _i < _a.length; _i++) { | ||
var key = _a[_i]; | ||
result[key] = this.deep(key); | ||
} | ||
return result; | ||
}, | ||
enumerable: true, | ||
configurable: true | ||
}); | ||
return NestedDeepStorage; | ||
}()); | ||
exports.NestedDeepStorage = NestedDeepStorage; | ||
function numberOrString(value) { | ||
var parsed = parseInt(value); | ||
return parsed.toString() === value ? parsed : value; | ||
} | ||
function parsePath(path) { | ||
if (path instanceof Array) { | ||
return path; | ||
} | ||
else if (typeof path === 'number') { | ||
return [path]; | ||
} | ||
else if (typeof path === 'string') { | ||
return path.split('/').map(numberOrString); | ||
} | ||
} | ||
exports.parsePath = parsePath; | ||
function parsePaths(paths) { | ||
var result = {}; | ||
for (var key in paths) { | ||
result[key] = parsePath(paths[key]); | ||
} | ||
return result; | ||
} | ||
exports.parsePaths = parsePaths; | ||
exports.deepStorage = function (s) { return new DefaultDeepStorage(s); }; | ||
exports.default = exports.deepStorage; | ||
//# sourceMappingURL=index.js.map | ||
__export(require("./storage")); |
{ | ||
"name": "deep-storage", | ||
"version": "3.0.1", | ||
"version": "4.0.0", | ||
"description": "Simple observable state management for reactive applications", | ||
@@ -12,8 +12,7 @@ "main": "./lib/index.js", | ||
"devDependencies": { | ||
"@types/jest": "^21.1.10", | ||
"jest": "^22.0.4", | ||
"@types/jest": "^23.1.4", | ||
"jest": "^23.3.0", | ||
"rimraf": "^2.6.2", | ||
"typescript": "^2.6.2", | ||
"webpack": "^3.10.0", | ||
"webpack-dev-server": "^2.9.7" | ||
"ts-jest": "^23.0.0", | ||
"typescript": "^2.9.2" | ||
}, | ||
@@ -23,5 +22,5 @@ "scripts": { | ||
"build": "rimraf lib *.d.ts && tsc -p tsconfig.prod.json", | ||
"publish-patch": "yarn build && git commit -am 'build' && git push && npm version patch && git push", | ||
"publish-minor": "yarn build && git commit -am 'build' && git push && npm version minor && git push", | ||
"publish-major": "yarn build && git commit -am 'build' && git push && npm version major && git push" | ||
"publish:patch": "yarn build && git commit -am 'build' && git push && npm version patch && git push", | ||
"publish:minor": "yarn build && git commit -am 'build' && git push && npm version minor && git push", | ||
"publish:major": "yarn build && git commit -am 'build' && git push && npm version major && git push" | ||
}, | ||
@@ -28,0 +27,0 @@ "dependencies": {}, |
@@ -1,6 +0,5 @@ | ||
import {deepAsync, deepStorage, AsyncStatus} from '../'; | ||
import { deepAsync, AsyncStatus } from "../"; | ||
test('deepAsync', async () => { | ||
const storage = deepStorage({}); | ||
const value = await deepAsync(storage.deep('test'), async () => 'test'); | ||
test("deepAsync", async () => { | ||
const value = await deepAsync(async () => "test"); | ||
expect(value.started).toBeFalsy(); | ||
@@ -11,3 +10,3 @@ expect(value.status).toBe(AsyncStatus.Created); | ||
expect(value.status).toBe(AsyncStatus.Succeeded); | ||
expect(value.data).toBe('test'); | ||
}); | ||
expect(value.data).toBe("test"); | ||
}); |
@@ -1,2 +0,2 @@ | ||
import { DeepStorage } from "./index"; | ||
import { deepStorage, DeepStorage } from "./index"; | ||
@@ -23,3 +23,3 @@ export enum AsyncStatus { | ||
run(): Promise<DeepAsyncState<Response>>; | ||
update(updater: (prevState: Response) => Response): Promise<DeepAsyncState<Response>>; | ||
update(updater: (prevState?: Response) => Response): Promise<DeepAsyncState<Response>>; | ||
storage: DeepStorage<DeepAsyncState<Response>>; | ||
@@ -50,3 +50,3 @@ } | ||
} | ||
update = async (updater: (prevState: Response) => Response): Promise<DeepAsyncState<Response>> => { | ||
update = async (updater: (prevState?: Response) => Response): Promise<DeepAsyncState<Response>> => { | ||
await this.storage.update( | ||
@@ -73,6 +73,5 @@ (state: DeepAsyncState<Response>) => | ||
export const deepAsync = async <Response>( | ||
storage: DeepStorage<DeepAsyncState<Response>>, | ||
process: () => Promise<Response> | ||
) => { | ||
await storage.set({ | ||
const storage = deepStorage({ | ||
status: AsyncStatus.Created | ||
@@ -82,3 +81,1 @@ }); | ||
} | ||
export default deepAsync; |
280
src/index.ts
@@ -1,278 +0,2 @@ | ||
export * from './async'; | ||
export type StateUpdateCallback = <DeepState>(path: Path, newState: DeepState, oldState: DeepState) => void; | ||
export interface DeepSubscriptions { | ||
/** | ||
* Returns a new subscription that can subscribeTo paths in state. Note, | ||
* the subscription must be cancelled when no longer in use. | ||
*/ | ||
subscription: (callback: StateUpdateCallback) => DeepSubscription; | ||
} | ||
export interface DeepStorage<State, RootState = {}> extends DeepSubscriptions { | ||
/** | ||
* sets a value in deep storage by path and notifies subscribers. shortcut for | ||
* updateIn where the old value is ignored | ||
*/ | ||
setIn: (...path: Path) => <DeepState>(newValue: DeepState) => Promise<DeepState>; | ||
/** | ||
* sets a value in deep storage and notifies subscribers. shortcut for | ||
* update where the old value is ignored | ||
*/ | ||
set: (newValue: State) => Promise<State>; | ||
/** | ||
* Updates the whole state and notifies subscribers | ||
*/ | ||
update: (callback: (s: State) => State) => Promise<State>; | ||
/** | ||
* Updates a value in deep storage by path and notifies subscribers. Must not | ||
* mutate the oldValue | ||
*/ | ||
updateIn: (...path: Path) => <DeepState>(callback: (s: DeepState) => DeepState) => Promise<DeepState>; | ||
/** | ||
* Updates a property of the current state and notifies subscribers. | ||
*/ | ||
updateProperty: <Key extends keyof State>(key: Key, callback: (s: State[Key]) => State[Key]) => Promise<State[Key]>; | ||
/** | ||
* Returns the state that this deep storage is managing | ||
*/ | ||
state: State; | ||
/** | ||
* Returns state by a path | ||
*/ | ||
stateIn: <DeepState>(...path: Path) => DeepState; | ||
/** | ||
* Creates a new DeepStorage at this point in the object path | ||
*/ | ||
deep: <DeepState>(...path: Path) => DeepStorage<DeepState>; | ||
/** | ||
* Gets the root deep storage | ||
*/ | ||
root: () => DeepStorage<RootState>; | ||
/** | ||
* The path from the root to this storage | ||
*/ | ||
path: Path; | ||
/** | ||
* Returns an object with keys from State and values of | ||
* DeepStorage for that key | ||
*/ | ||
props: {[P in keyof State]: DeepStorage<State[P]>} | ||
} | ||
/** | ||
* Is one array a prefix on another e.g. | ||
* | ||
* [] is a prefix of any array | ||
* ['asdf'] is a prefix of ['asdf', ...] | ||
* | ||
* etc. | ||
* | ||
* @param stateChangePath the full array to check, must not be null | ||
* @param subscriptionPath the partial array to check | ||
*/ | ||
export function isPathMatch<T>(stateChangePath: T[], subscriptionPath: T[]) { | ||
for (let i = 0; i < Math.min(subscriptionPath.length, stateChangePath.length); i++) { | ||
if (stateChangePath[i] !== subscriptionPath[i]) return false; | ||
} | ||
return true; | ||
} | ||
/** | ||
* A cancelable way to subscribe to paths in state | ||
*/ | ||
export interface DeepSubscription { | ||
subscribeTo: (...path: Path) => void; | ||
cancel: () => void; | ||
} | ||
export interface UsesDeepStorage<State> { | ||
storage: DeepStorage<State>; | ||
} | ||
export type stringOrNumber = string | number; | ||
export type Path = stringOrNumber[]; | ||
export class DefaultDeepStorage<State> implements DeepStorage<State, State> { | ||
private id: number = 0; | ||
private subscriptions: { [key: number]: { paths: Path[], callback: StateUpdateCallback } } = {}; | ||
constructor(public state: State) { | ||
} | ||
update = (callback: (s: State) => State): Promise<State> => { | ||
return this.updateIn()(callback); | ||
} | ||
updateProperty = <Key extends keyof State>(key: Key, callback: (s: State[Key]) => State[Key]): Promise<State[Key]> => { | ||
return this.updateIn(key)(callback); | ||
} | ||
set = (newValue: State) => { | ||
return this.updateIn()(() => newValue); | ||
} | ||
setIn = (...path: Path) => <DeepState>(newValue: DeepState) => { | ||
return this.updateIn(...path)(() => newValue); | ||
} | ||
merge = (partial: {[P in keyof State]?: State[P]}) => { | ||
this.update(oldState => { | ||
for (let key in partial) { | ||
oldState[key] = partial[key]; | ||
} | ||
return oldState; | ||
}); | ||
} | ||
updateIn = (...path: Path) => async <DeepState>(callback: (s: DeepState) => DeepState): Promise<DeepState> => { | ||
const oldState = this.stateIn<DeepState>(...path); | ||
const newState = callback(oldState); | ||
if (path.length === 0) { | ||
this.state = newState as any; | ||
} else { | ||
// todo: this will no doubt cause some bugs... better to replace all the | ||
// parent objects too so that reference equality checks work in react | ||
this.stateIn(...path.slice(0, path.length - 1))[path[path.length - 1]] = newState; | ||
} | ||
const stateChangePath = path; | ||
for (let subscriberId in this.subscriptions) { | ||
const subscriber = this.subscriptions[subscriberId]; | ||
// check to see if we have any matches | ||
if (subscriber.paths.some(subscriberPath => isPathMatch(stateChangePath, subscriberPath))) { | ||
subscriber.callback(stateChangePath, newState, oldState) | ||
} | ||
} | ||
return newState; | ||
} | ||
stateIn = <DeepState>(...path: Path) => { | ||
let currentState: any = this.state; | ||
let pathSoFar = []; | ||
for (let p of path) { | ||
pathSoFar.push(p); | ||
if (!(p in currentState)) { | ||
currentState[p] = {}; | ||
} | ||
currentState = currentState[p]; | ||
} | ||
return currentState; | ||
} | ||
deep = <DeepState>(...path: Path): DeepStorage<DeepState> => { | ||
return new NestedDeepStorage<DeepState, State>(path, this); | ||
} | ||
subscription = (callback: StateUpdateCallback) => { | ||
const subscriberId = this.id++; | ||
this.subscriptions[subscriberId] = { | ||
callback, | ||
paths: [] | ||
} as any; | ||
const cancel = () => { | ||
delete this.subscriptions[subscriberId]; | ||
} | ||
return { | ||
subscribeTo: (...path: Path) => { | ||
if (subscriberId in this.subscriptions) { | ||
this.subscriptions[subscriberId].paths.push(path); | ||
} | ||
}, | ||
cancel | ||
} | ||
} | ||
root = () => this; | ||
path: Path = []; | ||
get props() { | ||
const result: any = {}; | ||
for (let key of Object.keys(this.state)) { | ||
result[key] = this.deep(key); | ||
} | ||
return result as {[P in keyof State]: DeepStorage<State[P]>}; | ||
} | ||
} | ||
export class NestedDeepStorage<State, RootState> implements DeepStorage<State, RootState> { | ||
constructor(public path: Path, public rootStorage: DeepStorage<RootState, RootState>) { | ||
} | ||
setIn = (...path: stringOrNumber[]) => <DeepState>(newValue: DeepState): Promise<DeepState> => { | ||
return this.rootStorage.setIn(...this.path.concat(path))(newValue); | ||
} | ||
set = (newValue: State): Promise<State> => { | ||
return this.rootStorage.setIn(...this.path)(newValue); | ||
} | ||
update = (callback: (s: State) => State): Promise<State> => { | ||
return this.rootStorage.updateIn(...this.path)(callback); | ||
} | ||
updateIn = (...path: stringOrNumber[]) => <DeepState>(callback: (s: DeepState) => DeepState): Promise<DeepState> => { | ||
return this.rootStorage.updateIn(...this.path.concat(path))(callback); | ||
} | ||
updateProperty = <Key extends keyof State>(key: Key, callback: (s: State[Key]) => State[Key]): Promise<State[Key]> => { | ||
return this.rootStorage.updateIn(...this.path.concat(key))(callback); | ||
} | ||
get state() { return this.rootStorage.stateIn<State>(...this.path); } | ||
stateIn = <DeepState>(...path: stringOrNumber[]): DeepState => { | ||
return this.rootStorage.stateIn(...this.path.concat(path)); | ||
} | ||
deep = <DeepState>(...path: stringOrNumber[]): DeepStorage<DeepState> => { | ||
return this.rootStorage.deep(...this.path.concat(path)); | ||
} | ||
subscription = (callback: StateUpdateCallback): DeepSubscription => { | ||
const rootSubscription = this.rootStorage.subscription((path, newState, oldState) => { | ||
callback(path.slice(path.length - this.path.length, path.length), newState, oldState); | ||
}); | ||
return { | ||
subscribeTo: (...path: Path) => { | ||
return rootSubscription.subscribeTo(...this.path.concat(path)); | ||
}, | ||
cancel: rootSubscription.cancel | ||
} | ||
} | ||
root = () => this.rootStorage; | ||
get props() { | ||
const result: any = {}; | ||
for (let key of Object.keys(this.state)) { | ||
result[key] = this.deep(key); | ||
} | ||
return result as {[P in keyof State]: DeepStorage<State[P]>}; | ||
} | ||
} | ||
function numberOrString(value: string): stringOrNumber { | ||
const parsed = parseInt(value); | ||
return parsed.toString() === value ? parsed : value; | ||
} | ||
export function parsePath(path: Path | stringOrNumber): Path { | ||
if (path instanceof Array) { | ||
return path; | ||
} else if (typeof path === 'number') { | ||
return [path]; | ||
} else if (typeof path === 'string') { | ||
return path.split('/').map(numberOrString); | ||
} | ||
} | ||
export function parsePaths(paths: { [key: string]: Path | stringOrNumber }): { [key: string]: Path } { | ||
const result: { [key: string]: Path } = {}; | ||
for (let key in paths) { | ||
result[key] = parsePath(paths[key]); | ||
} | ||
return result; | ||
} | ||
export const deepStorage = <State>(s: State): DeepStorage<State> => new DefaultDeepStorage(s); | ||
export default deepStorage; | ||
export * from "./async"; | ||
export * from "./storage"; |
{ | ||
"compilerOptions": { | ||
"outDir": "./lib/", | ||
"sourceMap": true, | ||
"noImplicitAny": true, | ||
"module": "commonjs", | ||
"target": "es5", | ||
"jsx": "react", | ||
"declaration": true, | ||
"declarationDir": ".", | ||
"lib": [ | ||
"es6", | ||
"dom" | ||
] | ||
}, | ||
"include": [ | ||
"./src/**/*" | ||
] | ||
"compilerOptions": { | ||
/* Basic Options */ | ||
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */ | ||
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ | ||
"lib": ["es2015"], /* Specify library files to be included in the compilation. */ | ||
// "allowJs": true, /* Allow javascript files to be compiled. */ | ||
// "checkJs": true, /* Report errors in .js files. */ | ||
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ | ||
// "declaration": true, /* Generates corresponding '.d.ts' file. */ | ||
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ | ||
// "sourceMap": true, /* Generates corresponding '.map' file. */ | ||
// "outFile": "./", /* Concatenate and emit output to single file. */ | ||
"outDir": "./lib", /* Redirect output structure to the directory. */ | ||
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ | ||
// "composite": true, /* Enable project compilation */ | ||
// "removeComments": true, /* Do not emit comments to output. */ | ||
// "noEmit": true, /* Do not emit outputs. */ | ||
// "importHelpers": true, /* Import emit helpers from 'tslib'. */ | ||
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ | ||
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ | ||
/* Strict Type-Checking Options */ | ||
"strict": true, /* Enable all strict type-checking options. */ | ||
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ | ||
// "strictNullChecks": true, /* Enable strict null checks. */ | ||
// "strictFunctionTypes": true, /* Enable strict checking of function types. */ | ||
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ | ||
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ | ||
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ | ||
/* Additional Checks */ | ||
// "noUnusedLocals": true, /* Report errors on unused locals. */ | ||
// "noUnusedParameters": true, /* Report errors on unused parameters. */ | ||
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ | ||
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ | ||
/* Module Resolution Options */ | ||
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ | ||
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ | ||
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ | ||
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ | ||
// "typeRoots": [], /* List of folders to include type definitions from. */ | ||
// "types": [], /* Type declaration files to be included in compilation. */ | ||
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ | ||
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ | ||
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ | ||
/* Source Map Options */ | ||
// "sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ | ||
// "mapRoot": "./", /* Specify the location where debugger should locate map files instead of generated locations. */ | ||
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ | ||
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ | ||
/* Experimental Options */ | ||
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ | ||
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
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
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
5
173177
17
1044
1