Comparing version 2.2.0 to 3.0.0
CHANGELOG | ||
=== | ||
3.0.0 | ||
-- | ||
New Features | ||
- | ||
Crated bootstrapping optional parameters with state freezing option. | ||
2.3.0 | ||
-- | ||
New Features | ||
- | ||
Used tsc code restrictions. | ||
2.2.0 | ||
@@ -4,0 +20,0 @@ -- |
@@ -7,2 +7,2 @@ import * as s from './src/store'; | ||
export { debugCallbackType } from './src/debug'; | ||
export declare let bootstrap: (defaultState: s.IState, renderCallback: () => void, debugCallback?: d.debugCallbackType, subStateSeparator?: string) => void; | ||
export declare let bootstrap: (defaultState: s.IState, renderCallback: () => void, debugCallback?: d.debugCallbackType | undefined, subStateSeparator?: string) => void; |
10
index.js
@@ -11,8 +11,6 @@ "use strict"; | ||
__export(require('./src/helpers')); | ||
exports.bootstrap = function (defaultState, renderCallback, debugCallback, subStateSeparator) { | ||
if (debugCallback === void 0) { debugCallback = undefined; } | ||
if (subStateSeparator === void 0) { subStateSeparator = '.'; } | ||
debugCallback && d.bootstrap(function (m, p) { return debugCallback("fun-model -> " + m, p); }); | ||
s.bootstrap(defaultState, subStateSeparator); | ||
af.bootstrap(renderCallback); | ||
exports.bootstrap = function (defaultState, onStateChanged, params) { | ||
params.debugCallback && d.bootstrap(function (m, p) { return params.debugCallback && params.debugCallback("fun-model -> " + m, p); }); | ||
s.bootstrap(defaultState, params.withStateFreezing, params.subStateSeparator); | ||
af.bootstrap(onStateChanged); | ||
}; |
14
index.ts
@@ -10,6 +10,12 @@ import * as s from './src/store'; | ||
export let bootstrap = (defaultState: s.IState, renderCallback: () => void, debugCallback: d.debugCallbackType = undefined, subStateSeparator: string = '.') => { | ||
debugCallback && d.bootstrap((m, p) => debugCallback(`fun-model -> ${m}`, p)); | ||
s.bootstrap(defaultState, subStateSeparator); | ||
af.bootstrap(renderCallback); | ||
export interface IBootstrapParams { | ||
debugCallback?: d.debugCallbackType; | ||
withStateFreezing?: boolean | (() => boolean); | ||
subStateSeparator?: string; | ||
} | ||
export const bootstrap = (defaultState: s.IState, onStateChanged: () => void, params: IBootstrapParams) => { | ||
params.debugCallback && d.bootstrap((m, p) => params.debugCallback && params.debugCallback(`fun-model -> ${m}`, p)); | ||
s.bootstrap(defaultState, params.withStateFreezing, params.subStateSeparator); | ||
af.bootstrap(onStateChanged); | ||
}; |
{ | ||
"name": "fun-model", | ||
"version": "2.2.0", | ||
"version": "3.0.0", | ||
"description": "fun-model is pure functional implementation of FLUX architecture.", | ||
@@ -5,0 +5,0 @@ "main": "./index.js", |
@@ -34,3 +34,3 @@ "use strict"; | ||
} | ||
}, function (state, params) { return params.todo; }); | ||
}, function (_state, params) { return params.todo; }); | ||
testAction({ index: 1, todo: { done: false, name: 'New second todo' } }); | ||
@@ -44,3 +44,3 @@ expect(getTodos()[1].done).toBeFalsy(); | ||
}); | ||
var testAction = af.createAction({ create: function (index) { return { key: "todos." + index + ".done" }; } }, function (state) { return true; }); | ||
var testAction = af.createAction({ create: function (index) { return { key: "todos." + index + ".done" }; } }, function () { return true; }); | ||
testAction(1); | ||
@@ -64,3 +64,3 @@ expect(getTodos()[1].done).toBeTruthy(); | ||
expect(function () { | ||
var testAction = af.createAction(NestedCursorTestFixture, function (state) { return { state: 'new nested state' }; }); | ||
var testAction = af.createAction(NestedCursorTestFixture, function () { return { state: 'new nested state' }; }); | ||
testAction(); | ||
@@ -84,3 +84,3 @@ }).toThrow('Render callback must be set before first usage through bootstrap(defaultState, () => { yourRenderCallback(); }).'); | ||
givenStore(aState('nestedStateValue')); | ||
af.createAction(NestedCursorTestFixture, function (state) { return newState; })(); | ||
af.createAction(NestedCursorTestFixture, function () { return newState; })(); | ||
expect(debugCallback).toHaveBeenCalledWith('Global state has been changed.', undefined); | ||
@@ -96,3 +96,3 @@ }); | ||
givenStore(aState('nestedStateValue')); | ||
var testAction = af.createAction(NestedCursorTestFixture, function (state) { return { state: 'newValue' }; }); | ||
var testAction = af.createAction(NestedCursorTestFixture, function () { return { state: 'newValue' }; }); | ||
testAction(); | ||
@@ -110,3 +110,3 @@ expect(renderCallback).toHaveBeenCalled(); | ||
}); | ||
af.createAction(NestedCursorTestFixture, function (state) { | ||
af.createAction(NestedCursorTestFixture, function () { | ||
nestedAction(); | ||
@@ -178,3 +178,3 @@ return { state: 'newValue' }; | ||
cursor: NestedCursorTestFixture, | ||
handler: function (state) { return { state: 'newNestedStateValue' }; } | ||
handler: function () { return { state: 'newNestedStateValue' }; } | ||
}); | ||
@@ -197,3 +197,3 @@ testAction(); | ||
expect(function () { | ||
var testAction = af.createAsyncAction(NestedCursorTestFixture, function (state) { return { state: 'new nested state' }; }); | ||
var testAction = af.createAsyncAction(NestedCursorTestFixture, function () { return { state: 'new nested state' }; }); | ||
testAction(); | ||
@@ -220,3 +220,3 @@ jasmine.clock().tick(1); | ||
givenStore(aState('nestedStateValue')); | ||
var testAction = af.createAsyncAction(NestedCursorTestFixture, function (state) { return newState; }); | ||
var testAction = af.createAsyncAction(NestedCursorTestFixture, function () { return newState; }); | ||
testAction(); | ||
@@ -235,3 +235,3 @@ jasmine.clock().tick(1); | ||
givenStore(aState('nestedStateValue')); | ||
var testAction = af.createAsyncAction(NestedCursorTestFixture, function (state) { return { state: 'newValue' }; }); | ||
var testAction = af.createAsyncAction(NestedCursorTestFixture, function () { return { state: 'newValue' }; }); | ||
testAction(); | ||
@@ -244,3 +244,3 @@ jasmine.clock().tick(1); | ||
var newState = { state: 'newValue' }; | ||
var testAction = af.createAsyncAction(NestedCursorTestFixture, function (state) { return newState; }); | ||
var testAction = af.createAsyncAction(NestedCursorTestFixture, function () { return newState; }); | ||
testAction() | ||
@@ -262,4 +262,5 @@ .then(function (r) { | ||
} | ||
function resetStore() { | ||
s.bootstrap({ some: { nested: { state: null } } }); | ||
function resetStore(withFreezing) { | ||
if (withFreezing === void 0) { withFreezing = false; } | ||
s.bootstrap({ some: { nested: { state: null } } }, withFreezing); | ||
} | ||
@@ -266,0 +267,0 @@ function aState(nestedState, state) { |
@@ -39,7 +39,7 @@ import * as s from '../src/store'; | ||
{ | ||
create: (params) => { | ||
create: (params: tds.ITodoParams) => { | ||
return { key: `todos.${params.index}` }; | ||
} | ||
}, | ||
(state, params) => { return params.todo } | ||
(_state: tds.ITodo, params: tds.ITodoParams) => { return params.todo } | ||
); | ||
@@ -57,3 +57,3 @@ testAction({ index: 1, todo: { done: false, name: 'New second todo' } }); | ||
let testAction = af.createAction<boolean, number>({ create: (index) => { return { key: `todos.${index}.done` } } }, (state) => { return true; }); | ||
let testAction = af.createAction<boolean, number>({ create: (index) => { return { key: `todos.${index}.done` } } }, () => { return true; }); | ||
testAction(1); | ||
@@ -82,3 +82,3 @@ | ||
expect(() => { | ||
let testAction = af.createAction(NestedCursorTestFixture, (state: INestedState) => { return { state: 'new nested state' }; }); | ||
let testAction = af.createAction(NestedCursorTestFixture, () => { return { state: 'new nested state' }; }); | ||
testAction(); | ||
@@ -109,3 +109,3 @@ }).toThrow('Render callback must be set before first usage through bootstrap(defaultState, () => { yourRenderCallback(); }).'); | ||
af.createAction(NestedCursorTestFixture, (state: INestedState) => newState)(); | ||
af.createAction(NestedCursorTestFixture, () => newState)(); | ||
@@ -127,3 +127,3 @@ expect(debugCallback).toHaveBeenCalledWith('Global state has been changed.', undefined); | ||
let testAction = af.createAction(NestedCursorTestFixture, (state: INestedState) => { return { state: 'newValue' }; }) | ||
let testAction = af.createAction(NestedCursorTestFixture, () => { return { state: 'newValue' }; }) | ||
testAction(); | ||
@@ -146,3 +146,3 @@ | ||
af.createAction(NestedCursorTestFixture, (state: INestedState) => { | ||
af.createAction(NestedCursorTestFixture, () => { | ||
nestedAction(); | ||
@@ -230,3 +230,3 @@ return { state: 'newValue' }; | ||
cursor: NestedCursorTestFixture, | ||
handler: (state: INestedState): INestedState => { return { state: 'newNestedStateValue' }; } | ||
handler: (): INestedState => { return { state: 'newNestedStateValue' }; } | ||
}); | ||
@@ -253,3 +253,3 @@ testAction(); | ||
expect(() => { | ||
let testAction = af.createAsyncAction(NestedCursorTestFixture, (state: INestedState) => { return { state: 'new nested state' }; }); | ||
let testAction = af.createAsyncAction(NestedCursorTestFixture, () => { return { state: 'new nested state' }; }); | ||
testAction(); | ||
@@ -283,3 +283,3 @@ jasmine.clock().tick(1); | ||
let testAction = af.createAsyncAction(NestedCursorTestFixture, (state: INestedState) => newState); | ||
let testAction = af.createAsyncAction(NestedCursorTestFixture, () => newState); | ||
testAction(); | ||
@@ -304,3 +304,3 @@ jasmine.clock().tick(1); | ||
let testAction = af.createAsyncAction(NestedCursorTestFixture, (state: INestedState) => { return { state: 'newValue' }; }); | ||
let testAction = af.createAsyncAction(NestedCursorTestFixture, () => { return { state: 'newValue' }; }); | ||
testAction(); | ||
@@ -312,7 +312,7 @@ jasmine.clock().tick(1); | ||
it('returns new state in resolve', (done) => { | ||
it('returns new state in resolve', (done: Function) => { | ||
givenStore(aState('nestedStateValue')); | ||
let newState = { state: 'newValue' }; | ||
let testAction = af.createAsyncAction(NestedCursorTestFixture, (state: INestedState) => newState); | ||
let testAction = af.createAsyncAction(NestedCursorTestFixture, () => newState); | ||
testAction() | ||
@@ -337,4 +337,4 @@ .then(r => { | ||
function resetStore() { | ||
s.bootstrap({ some: { nested: { state: null } } }); | ||
function resetStore(withFreezing: boolean = false) { | ||
s.bootstrap({ some: { nested: { state: null } } }, withFreezing); | ||
} | ||
@@ -341,0 +341,0 @@ |
@@ -80,3 +80,3 @@ "use strict"; | ||
describe('deepFreeze', function () { | ||
var state = null; | ||
var state; | ||
beforeEach(function () { | ||
@@ -83,0 +83,0 @@ state = { |
@@ -99,3 +99,3 @@ import * as h from '../src/helpers'; | ||
describe('deepFreeze', () => { | ||
let state: IDummyState = null; | ||
let state: IDummyState; | ||
@@ -102,0 +102,0 @@ beforeEach(() => { |
@@ -46,6 +46,2 @@ "use strict"; | ||
}); | ||
it('throws if cursor key is null', function () { | ||
expect(function () { return s.getState({ key: null }); }) | ||
.toThrow('Cursor key cannot be null.'); | ||
}); | ||
}); | ||
@@ -83,8 +79,4 @@ describe('with booting and dynamic/array cursor', function () { | ||
beforeEach(function () { | ||
s.bootstrap({ key: null }); | ||
s.bootstrap({ key: null }, true); | ||
}); | ||
it('throws if cursor key is null', function () { | ||
expect(function () { return s.setState({ key: null }, {}); }) | ||
.toThrow('Cursor key cannot be null.'); | ||
}); | ||
it('creates empty object if cursor has not existing key', function () { | ||
@@ -101,3 +93,2 @@ var cursor = { key: 'invalid' }; | ||
it('freezes state', function () { | ||
d.bootstrap(jasmine.createSpy('debugCallback')); | ||
givenStore({ some: { nested: { state: 'value' } } }); | ||
@@ -108,9 +99,2 @@ var state = { nested: { state: 'newValue' } }; | ||
}); | ||
it('does not freeze state in no debug mode', function () { | ||
d.bootstrap(undefined); | ||
givenStore({ some: { nested: { state: 'value' } } }); | ||
var state = { nested: { state: 'newValue' } }; | ||
s.setState({ key: 'some' }, state); | ||
expect(Object.isFrozen(state)).toBeFalsy(); | ||
}); | ||
it('sets nested state by cursor', function () { | ||
@@ -184,5 +168,6 @@ givenStore({ some: { nested: { state: 'value' } } }); | ||
} | ||
function resetStore() { | ||
s.bootstrap(null); | ||
function resetStore(withFreezing) { | ||
if (withFreezing === void 0) { withFreezing = false; } | ||
s.bootstrap(null, withFreezing); | ||
} | ||
}); |
@@ -60,7 +60,2 @@ import * as s from '../src/store'; | ||
}); | ||
it('throws if cursor key is null', () => { | ||
expect(() => s.getState<s.IState>({ key: null })) | ||
.toThrow('Cursor key cannot be null.'); | ||
}); | ||
}); | ||
@@ -84,3 +79,3 @@ | ||
const state = s.getState<tds.ITodosState>(tds.todosCursor); | ||
const state = s.getState<tds.ITodo[]>(tds.todosCursor); | ||
@@ -110,10 +105,5 @@ expect(state[0].done).toBeFalsy(); | ||
beforeEach(() => { | ||
s.bootstrap({ key: null }); | ||
s.bootstrap({ key: null }, true); | ||
}); | ||
it('throws if cursor key is null', () => { | ||
expect(() => s.setState({ key: null }, {})) | ||
.toThrow('Cursor key cannot be null.'); | ||
}); | ||
it('creates empty object if cursor has not existing key', () => { | ||
@@ -134,3 +124,2 @@ const cursor = { key: 'invalid' }; | ||
it('freezes state', () => { | ||
d.bootstrap(jasmine.createSpy('debugCallback')); | ||
givenStore({ some: { nested: { state: 'value' } } }); | ||
@@ -144,12 +133,2 @@ | ||
it('does not freeze state in no debug mode', () => { | ||
d.bootstrap(undefined); | ||
givenStore({ some: { nested: { state: 'value' } } }); | ||
let state = { nested: { state: 'newValue' } }; | ||
s.setState({ key: 'some' }, state); | ||
expect(Object.isFrozen(state)).toBeFalsy(); | ||
}); | ||
it('sets nested state by cursor', () => { | ||
@@ -252,4 +231,5 @@ givenStore({ some: { nested: { state: 'value' } } }); | ||
function resetStore() { | ||
s.bootstrap(null); | ||
function resetStore(withFreezing: boolean = false) { | ||
s.bootstrap(null, withFreezing); | ||
} | ||
@@ -256,0 +236,0 @@ }); |
import * as s from './store'; | ||
export declare let bootstrap: (renderCallback: () => void) => void; | ||
export declare let bootstrap: (renderCallback: (() => void) | null) => void; | ||
export interface IAction<T> { | ||
@@ -9,3 +9,4 @@ (param?: T): void; | ||
} | ||
export declare let createAction: <TState extends s.IState, TParams>(cursor: s.ICursor<TState> | s.ICursorFactory<TState, TParams>, handler: (state: TState, t?: TParams) => TState) => IAction<TParams>; | ||
export declare type IActionHandler<TState extends s.IState, TParams> = (state: TState, t?: TParams) => TState; | ||
export declare const createAction: <TState extends s.IState, TParams>(cursor: s.ICursor<TState> | s.ICursorFactory<TState, TParams>, handler: (state: TState, t?: TParams | undefined) => TState) => IAction<TParams>; | ||
export interface IPair<TState extends s.IState, TParam> { | ||
@@ -15,3 +16,3 @@ cursor: s.ICursor<TState>; | ||
} | ||
export declare let createActions: <TState extends s.IState, TParams>(...pairs: IPair<TState, TParams>[]) => IAction<TParams>; | ||
export declare let createAsyncAction: <TState extends s.IState, TParams>(cursor: s.ICursor<TState> | s.ICursorFactory<TState, TParams>, handler: (state: TState, t?: TParams) => TState) => IAsyncAction<TParams, TState>; | ||
export declare const createActions: <TState extends s.IState, TParams>(...pairs: IPair<TState, TParams>[]) => IAction<TParams>; | ||
export declare const createAsyncAction: <TState extends s.IState, TParams>(cursor: s.ICursor<TState> | s.ICursorFactory<TState, TParams>, handler: (state: TState, t?: TParams | undefined) => TState) => IAsyncAction<TParams, TState>; |
@@ -12,3 +12,4 @@ "use strict"; | ||
return (function (params) { | ||
validateRenderCallback(); | ||
if (render === null) | ||
throw 'Render callback must be set before first usage through bootstrap(defaultState, () => { yourRenderCallback(); }).'; | ||
if (changeStateWithQueue(unifyCursor(cursor, params), handler, params)) { | ||
@@ -29,3 +30,4 @@ render(); | ||
return (function (params) { | ||
validateRenderCallback(); | ||
if (render === null) | ||
throw 'Render callback must be set before first usage through bootstrap(defaultState, () => { yourRenderCallback(); }).'; | ||
var changed = false; | ||
@@ -43,5 +45,6 @@ for (var i in pairs) | ||
return (function (params) { | ||
return new Promise(function (f, r) { | ||
return new Promise(function (f) { | ||
setTimeout(function () { | ||
validateRenderCallback(); | ||
if (render === null) | ||
throw 'Render callback must be set before first usage through bootstrap(defaultState, () => { yourRenderCallback(); }).'; | ||
var c = unifyCursor(cursor, params); | ||
@@ -57,6 +60,2 @@ if (changeStateWithQueue(c, handler, params)) { | ||
}; | ||
function validateRenderCallback() { | ||
if (render === null) | ||
throw 'Render callback must be set before first usage through bootstrap(defaultState, () => { yourRenderCallback(); }).'; | ||
} | ||
var queueOfHandlers = []; | ||
@@ -66,3 +65,3 @@ function changeStateWithQueue(cursor, handler, params) { | ||
if (queueOfHandlers.length > 1) | ||
return; | ||
return false; | ||
var isStateChanged = false; | ||
@@ -69,0 +68,0 @@ while (queueOfHandlers.length > 0) { |
import * as s from './store'; | ||
import * as d from './debug'; | ||
let render: () => void = null; | ||
let render: (() => void) | null = null; | ||
export let bootstrap = (renderCallback: () => void) => { | ||
export let bootstrap = (renderCallback: (() => void) | null) => { | ||
render = renderCallback; | ||
@@ -25,3 +25,5 @@ queueOfHandlers = []; | ||
return <IAction<TParams>>((params?: TParams): void => { | ||
validateRenderCallback(); | ||
if (render === null) | ||
throw 'Render callback must be set before first usage through bootstrap(defaultState, () => { yourRenderCallback(); }).'; | ||
if (changeStateWithQueue(unifyCursor<TState, TParams>(cursor, params), handler, params)) { | ||
@@ -34,3 +36,3 @@ render(); | ||
function unifyCursor<TState extends s.IState, TParams>(cursor: s.ICursor<TState> | s.ICursorFactory<TState, TParams>, params: TParams): s.ICursor<TState> { | ||
function unifyCursor<TState extends s.IState, TParams>(cursor: s.ICursor<TState> | s.ICursorFactory<TState, TParams>, params: TParams | undefined): s.ICursor<TState> { | ||
return (<s.ICursorFactory<TState, TParams>>cursor).create instanceof Function ? (<s.ICursorFactory<TState, TParams>>cursor).create(params) : <s.ICursor<TState>>cursor; | ||
@@ -46,3 +48,4 @@ } | ||
return <IAction<TParams>>((params?: TParams) => { | ||
validateRenderCallback(); | ||
if (render === null) | ||
throw 'Render callback must be set before first usage through bootstrap(defaultState, () => { yourRenderCallback(); }).'; | ||
let changed = false; | ||
@@ -62,5 +65,6 @@ for (var i in pairs) | ||
return <IAsyncAction<TParams, TState>>((params?: TParams): Promise<TState> => { | ||
return new Promise<TState>((f, r) => { | ||
return new Promise<TState>((f) => { | ||
setTimeout(() => { | ||
validateRenderCallback(); | ||
if (render === null) | ||
throw 'Render callback must be set before first usage through bootstrap(defaultState, () => { yourRenderCallback(); }).'; | ||
let c = unifyCursor<TState, TParams>(cursor, params); | ||
@@ -77,7 +81,2 @@ if (changeStateWithQueue(c, handler, params)) { | ||
function validateRenderCallback() { | ||
if (render === null) | ||
throw 'Render callback must be set before first usage through bootstrap(defaultState, () => { yourRenderCallback(); }).'; | ||
} | ||
interface IQueuedHandling<TState extends s.IState, TParams> { | ||
@@ -94,3 +93,3 @@ cursor: s.ICursor<TState>; | ||
if (queueOfHandlers.length > 1) | ||
return; | ||
return false; | ||
let isStateChanged = false; | ||
@@ -97,0 +96,0 @@ while (queueOfHandlers.length > 0) { |
export declare type debugCallbackType = (message: string, params?: any) => void; | ||
export declare let bootstrap: (debugCallback: debugCallbackType) => void; | ||
export declare function log(message: string, params?: any): void; | ||
export declare let debug: debugCallbackType | undefined; | ||
export declare const bootstrap: (debugCallback: debugCallbackType | undefined) => void; | ||
export declare const isDebuggingEnabled: () => boolean; | ||
export declare const log: (message: string, params?: any) => void; |
@@ -6,7 +6,4 @@ "use strict"; | ||
}; | ||
exports.isDebuggingEnabled = function () { | ||
return !!exports.debug; | ||
}; | ||
exports.log = function (message, params) { | ||
exports.debug && exports.debug(message, params); | ||
}; |
export type debugCallbackType = (message: string, params?: any) => void | ||
export let debug: debugCallbackType = undefined; | ||
export let debug: debugCallbackType | undefined = undefined; | ||
export const bootstrap = (debugCallback: debugCallbackType) => { | ||
export const bootstrap = (debugCallback: debugCallbackType | undefined) => { | ||
debug = debugCallback; | ||
}; | ||
export const isDebuggingEnabled = (): boolean => { | ||
return !!debug; | ||
} | ||
export const log = (message: string, params?: any) => { | ||
debug && debug(message, params); | ||
} |
export declare function shallowCopy<T>(source: T, callback?: (target: T) => void | T): T; | ||
export declare function deepFreeze(o: any): any; |
@@ -12,3 +12,3 @@ "use strict"; | ||
function objectShallowCopy(source, callback) { | ||
if (callback === void 0) { callback = function (t) { }; } | ||
if (callback === void 0) { callback = function (_t) { }; } | ||
var target = {}; | ||
@@ -23,23 +23,29 @@ for (var property in source) | ||
; | ||
// function objectShallowCopy<T>(source: T, callback?: (target: T) => void | T): T { | ||
// const target = <T>{}; | ||
// export function deepFreeze(source: any) { | ||
// Object.freeze(source); | ||
// for (var property in source) | ||
// if (source.hasOwnProperty(property)) | ||
// target[property] = source[property]; | ||
// const result = callback ? callback(source) : undefined; | ||
// return <T>result || target; | ||
// if (source.hasOwnProperty(property) | ||
// && source[property] !== null | ||
// && (typeof source[property] === "object" || typeof source[property] === "function") | ||
// && !Object.isFrozen(source[property])) | ||
// deepFreeze(source[property]); | ||
// return source; | ||
// }; | ||
function deepFreeze(o) { | ||
Object.freeze(o); | ||
Object.getOwnPropertyNames(o).forEach(function (prop) { | ||
if (o.hasOwnProperty(prop) | ||
&& o[prop] !== null | ||
&& (typeof o[prop] === "object" || typeof o[prop] === "function") | ||
&& !Object.isFrozen(o[prop])) { | ||
deepFreeze(o[prop]); | ||
} | ||
}); | ||
return o; | ||
function deepFreeze(source) { | ||
Object.freeze(source); | ||
for (var property in source) { | ||
var sourceProperty = source[property]; | ||
if (source.hasOwnProperty(property) | ||
&& sourceProperty !== null | ||
&& (typeof sourceProperty === "object" || typeof sourceProperty === "function") | ||
&& !Object.isFrozen(sourceProperty)) | ||
deepFreeze(sourceProperty); | ||
} | ||
return source; | ||
} | ||
exports.deepFreeze = deepFreeze; | ||
; | ||
function isFunction(val) { | ||
return typeof val == "function"; | ||
} | ||
exports.isFunction = isFunction; |
@@ -13,7 +13,8 @@ | ||
export function objectShallowCopy<T>(source: T, callback: (target: T) => void | T = (t: T) => { }): T { | ||
export function objectShallowCopy<T>(source: T, callback: (target: T) => void | T = (_t: T) => { }): T { | ||
const target = <T>{}; | ||
for (var property in source) | ||
if (source.hasOwnProperty(property)) | ||
target[property] = source[property]; | ||
(<any>target)[property] = (<any>source)[property]; | ||
const result = callback(target); | ||
@@ -23,22 +24,29 @@ return <T>result || target; | ||
// function objectShallowCopy<T>(source: T, callback?: (target: T) => void | T): T { | ||
// const target = <T>{}; | ||
// export function deepFreeze(source: any) { | ||
// Object.freeze(source); | ||
// for (var property in source) | ||
// if (source.hasOwnProperty(property)) | ||
// target[property] = source[property]; | ||
// const result = callback ? callback(source) : undefined; | ||
// return <T>result || target; | ||
// if (source.hasOwnProperty(property) | ||
// && source[property] !== null | ||
// && (typeof source[property] === "object" || typeof source[property] === "function") | ||
// && !Object.isFrozen(source[property])) | ||
// deepFreeze(source[property]); | ||
// return source; | ||
// }; | ||
export function deepFreeze(o) { | ||
Object.freeze(o); | ||
Object.getOwnPropertyNames(o).forEach(function (prop) { | ||
if (o.hasOwnProperty(prop) | ||
&& o[prop] !== null | ||
&& (typeof o[prop] === "object" || typeof o[prop] === "function") | ||
&& !Object.isFrozen(o[prop])) { | ||
deepFreeze(o[prop]); | ||
} | ||
}); | ||
return o; | ||
}; | ||
export function deepFreeze<T extends Object>(source: T): T { | ||
Object.freeze(source); | ||
for (var property in source) { | ||
const sourceProperty = (<any>source)[property]; | ||
if (source.hasOwnProperty(property) | ||
&& sourceProperty !== null | ||
&& (typeof sourceProperty === "object" || typeof sourceProperty === "function") | ||
&& !Object.isFrozen(sourceProperty)) | ||
deepFreeze(sourceProperty); | ||
} | ||
return source; | ||
}; | ||
export function isFunction(val: any): val is Function { | ||
return typeof val == "function"; | ||
} |
@@ -7,7 +7,7 @@ export interface IState { | ||
export interface ICursorFactory<TState, TParms> { | ||
create(data: TParms): ICursor<TState>; | ||
create(data?: TParms): ICursor<TState>; | ||
} | ||
export declare let rootCursor: ICursor<IState>; | ||
export declare let bootstrap: (defaultState: IState, subStateSeparator?: string) => void; | ||
export declare let getState: <TState extends IState>(cursor: ICursor<TState>) => TState; | ||
export declare let setState: <TState extends IState>(cursor: ICursor<TState>, updatedState: TState) => void; | ||
export declare const rootCursor: ICursor<IState>; | ||
export declare const bootstrap: (defaultState: IState | null, subStateSeparator?: string) => void; | ||
export declare const getState: <TState extends IState>(cursor: ICursor<TState>) => TState; | ||
export declare const setState: <TState extends IState>(cursor: ICursor<TState>, updatedState: TState) => void; |
@@ -6,2 +6,3 @@ "use strict"; | ||
var stateSeparator = '.'; | ||
var freezing = false; | ||
var rootStateKey = ''; | ||
@@ -11,6 +12,8 @@ exports.rootCursor = { | ||
}; | ||
exports.bootstrap = function (defaultState, subStateSeparator) { | ||
exports.bootstrap = function (defaultState, withStateFreezing, subStateSeparator) { | ||
if (withStateFreezing === void 0) { withStateFreezing = false; } | ||
if (subStateSeparator === void 0) { subStateSeparator = '.'; } | ||
stateSeparator = subStateSeparator; | ||
state = defaultState; | ||
freezing = withStateFreezing; | ||
}; | ||
@@ -22,2 +25,4 @@ exports.getState = function (cursor) { | ||
var subPath = path.shift(); | ||
if (!subPath) | ||
return innerState; | ||
checkSubstate(innerState, subPath, cursor.key); | ||
@@ -29,3 +34,6 @@ var prop = innerState[subPath]; | ||
}; | ||
checkDefaultStateAndCursor(cursor); | ||
if (state === null) | ||
throw 'Default state must be set before first usage through bootstrap(defaultState, () => { yourRenderCallback(); }).'; | ||
if (cursor.key === null) | ||
throw 'Cursor key cannot be null.'; | ||
return (cursor.key === rootStateKey | ||
@@ -40,3 +48,5 @@ ? state | ||
var subPath = path.shift(); | ||
createSubstate(innerState, subPath, cursor.key); | ||
if (!subPath) | ||
return updatedState; | ||
createSubstate(innerState, subPath); | ||
var prop = innerState[subPath]; | ||
@@ -57,3 +67,6 @@ var newSubState = null; | ||
}; | ||
checkDefaultStateAndCursor(cursor); | ||
if (state === null) | ||
throw 'Default state must be set before first usage through bootstrap(defaultState, () => { yourRenderCallback(); }).'; | ||
if (cursor.key === null) | ||
throw 'Cursor key cannot be null.'; | ||
state = | ||
@@ -63,3 +76,3 @@ cursor.key === rootStateKey | ||
: setInnerState(state, cursor.key.split(stateSeparator)); | ||
if (d.isDebuggingEnabled()) | ||
if (h.isFunction(freezing) ? freezing() : freezing) | ||
h.deepFreeze(state); | ||
@@ -72,11 +85,5 @@ d.log('Current state:', state); | ||
} | ||
function createSubstate(s, subPath, cursorKey) { | ||
function createSubstate(s, subPath) { | ||
if (s[subPath] === undefined) | ||
s[subPath] = {}; | ||
} | ||
function checkDefaultStateAndCursor(cursor) { | ||
if (state === null) | ||
throw 'Default state must be set before first usage through bootstrap(defaultState, () => { yourRenderCallback(); }).'; | ||
if (cursor.key === null) | ||
throw 'Cursor key cannot be null.'; | ||
} |
@@ -9,10 +9,12 @@ import * as h from './helpers'; | ||
key: string; | ||
_?: TState; | ||
} | ||
export interface ICursorFactory<TState, TParms> { | ||
create(data: TParms): ICursor<TState>; | ||
create(data?: TParms): ICursor<TState>; | ||
} | ||
let state: IState = null; | ||
let state: IState | null = null; | ||
let stateSeparator = '.'; | ||
let freezing: boolean | (() => boolean) = false; | ||
const rootStateKey = ''; | ||
@@ -24,5 +26,6 @@ | ||
export const bootstrap = (defaultState: IState, subStateSeparator: string = '.') => { | ||
export const bootstrap = (defaultState: IState | null, withStateFreezing: boolean | (() => boolean) = false, subStateSeparator: string = '.') => { | ||
stateSeparator = subStateSeparator; | ||
state = defaultState; | ||
freezing = withStateFreezing; | ||
}; | ||
@@ -35,4 +38,6 @@ | ||
const subPath = path.shift(); | ||
if (!subPath) | ||
return innerState; | ||
checkSubstate(innerState, subPath, cursor.key); | ||
const prop = innerState[subPath]; | ||
const prop = (<any>innerState)[subPath]; | ||
return Array.isArray(prop) && path.length > 0 | ||
@@ -42,3 +47,9 @@ ? getInnerState(prop[Number(path.shift())], path) | ||
}; | ||
checkDefaultStateAndCursor(cursor); | ||
if (state === null) | ||
throw 'Default state must be set before first usage through bootstrap(defaultState, () => { yourRenderCallback(); }).'; | ||
if (cursor.key === null) | ||
throw 'Cursor key cannot be null.'; | ||
return <TState>(cursor.key === rootStateKey | ||
@@ -54,9 +65,12 @@ ? state | ||
const subPath = path.shift(); | ||
createSubstate(innerState, subPath, cursor.key); | ||
const prop = innerState[subPath]; | ||
let newSubState = null; | ||
if (!subPath) | ||
return <any>updatedState; | ||
createSubstate(innerState, subPath); | ||
const prop = (<any>innerState)[subPath]; | ||
let newSubState: Object | Array<IState> | null = null; | ||
if (Array.isArray(prop) && path.length > 0) { | ||
let index = Number(path.shift()); | ||
newSubState = [...prop]; | ||
newSubState[index] = setInnerState(newSubState[index], path); | ||
(<any>newSubState)[index] = setInnerState((<any>newSubState)[index], path); | ||
} | ||
@@ -70,8 +84,12 @@ else | ||
const newState = h.shallowCopy(innerState); | ||
newState[subPath] = newSubState; | ||
(<any>newState)[subPath] = newSubState; | ||
return newState; | ||
}; | ||
checkDefaultStateAndCursor(cursor); | ||
if (state === null) | ||
throw 'Default state must be set before first usage through bootstrap(defaultState, () => { yourRenderCallback(); }).'; | ||
if (cursor.key === null) | ||
throw 'Cursor key cannot be null.'; | ||
state = | ||
@@ -81,3 +99,3 @@ cursor.key === rootStateKey | ||
: setInnerState(state, cursor.key.split(stateSeparator)); | ||
if (d.isDebuggingEnabled()) | ||
if (h.isFunction(freezing) ? freezing() : freezing) | ||
h.deepFreeze(state); | ||
@@ -88,17 +106,9 @@ d.log('Current state:', state); | ||
function checkSubstate(s: IState, subPath: string, cursorKey: string) { | ||
if (s[subPath] === undefined) | ||
if ((<any>s)[subPath] === undefined) | ||
throw `State for cursor key (${cursorKey}) does not exist.`; | ||
} | ||
function createSubstate(s: IState, subPath: string, cursorKey: string) { | ||
if (s[subPath] === undefined) | ||
s[subPath] = {}; | ||
function createSubstate(s: IState, subPath: string) { | ||
if ((<any>s)[subPath] === undefined) | ||
(<any>s)[subPath] = {}; | ||
} | ||
function checkDefaultStateAndCursor<TState extends IState>(cursor: ICursor<TState>) { | ||
if (state === null) | ||
throw 'Default state must be set before first usage through bootstrap(defaultState, () => { yourRenderCallback(); }).'; | ||
if (cursor.key === null) | ||
throw 'Cursor key cannot be null.'; | ||
} |
233656
1650