├── .travis.yml ├── .gitignore ├── packages ├── base │ ├── .babelrc │ ├── .gitignore │ ├── src │ │ ├── lib │ │ │ ├── index.ts │ │ │ ├── types.ts │ │ │ └── createActionCreator.ts │ │ └── specs │ │ │ └── createActionCreator.spec.ts │ ├── tsconfig.json │ ├── package.json │ └── readme.md ├── trackable │ ├── .babelrc │ ├── .gitignore │ ├── src │ │ ├── lib │ │ │ ├── index.ts │ │ │ ├── track-enhancer.ts │ │ │ ├── util.ts │ │ │ ├── trackable.ts │ │ │ ├── record.ts │ │ │ ├── map.ts │ │ │ └── array.ts │ │ └── specs │ │ │ ├── track-enhancer.spec.ts │ │ │ ├── record.spec.ts │ │ │ ├── array.spec.ts │ │ │ └── map.spec.ts │ ├── tsconfig.json │ ├── package.json │ ├── readme.md │ └── package-lock.json ├── batch-enhancer │ ├── .babelrc │ ├── src │ │ ├── lib │ │ │ ├── index.ts │ │ │ └── batchEnhancer.ts │ │ └── specs │ │ │ └── batchEnhancer.spec.ts │ ├── .gitignore │ ├── tsconfig.json │ ├── package.json │ └── readme.md ├── mapped-reducer │ ├── .babelrc │ ├── .gitignore │ ├── src │ │ ├── lib │ │ │ ├── types.ts │ │ │ ├── index.ts │ │ │ ├── util.ts │ │ │ ├── MappedReducer.ts │ │ │ └── MappedPipeReducer.ts │ │ └── specs │ │ │ ├── util.spec.ts │ │ │ ├── MappedReducer.spec.ts │ │ │ └── MappedPipeReducer.spec.ts │ ├── tsconfig.json │ ├── package.json │ └── readme.md └── typed-redux-kit │ ├── .babelrc │ ├── .gitignore │ ├── src │ ├── lib │ │ └── index.ts │ └── specs │ │ └── basic-usage.spec.ts │ ├── tsconfig.json │ ├── readme.md │ └── package.json ├── lerna.json ├── .vscode ├── tasks.json └── launch.json ├── jest.json ├── tslint.json ├── package.json └── readme.md /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "8" 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /coverage 3 | /build 4 | /node-build 5 | /typings 6 | .DS_Store 7 | *.log 8 | -------------------------------------------------------------------------------- /packages/base/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "transform-es2015-modules-commonjs" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /packages/trackable/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "transform-es2015-modules-commonjs" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /packages/batch-enhancer/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "transform-es2015-modules-commonjs" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /packages/mapped-reducer/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "transform-es2015-modules-commonjs" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /packages/typed-redux-kit/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "transform-es2015-modules-commonjs" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "lerna": "2.1.2", 3 | "packages": [ 4 | "packages/*" 5 | ], 6 | "version": "independent" 7 | } 8 | -------------------------------------------------------------------------------- /packages/base/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Legacy 2 | /build 3 | /node-build 4 | /typings 5 | 6 | # Dependencies 7 | /node_modules 8 | -------------------------------------------------------------------------------- /packages/batch-enhancer/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | import { batchEnhancer } from './batchEnhancer' 2 | 3 | export default batchEnhancer 4 | -------------------------------------------------------------------------------- /packages/trackable/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Legacy 2 | /build 3 | /node-build 4 | /typings 5 | 6 | # Dependencies 7 | /node_modules 8 | -------------------------------------------------------------------------------- /packages/batch-enhancer/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Legacy 2 | /build 3 | /node-build 4 | /typings 5 | 6 | # Dependencies 7 | /node_modules 8 | -------------------------------------------------------------------------------- /packages/mapped-reducer/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Legacy 2 | /build 3 | /node-build 4 | /typings 5 | 6 | # Dependencies 7 | /node_modules 8 | -------------------------------------------------------------------------------- /packages/typed-redux-kit/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Legacy 2 | /build 3 | /node-build 4 | /typings 5 | 6 | # Dependencies 7 | /node_modules 8 | -------------------------------------------------------------------------------- /packages/base/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | export { Action, PureAction, PayloadAction } from './types' 2 | export { createActionCreator } from './createActionCreator' 3 | -------------------------------------------------------------------------------- /packages/mapped-reducer/src/lib/types.ts: -------------------------------------------------------------------------------- 1 | export interface MappedReducerOptions { 2 | initialState?: S 3 | } 4 | export type Reducer = (state: STATE, action: ACTION) => STATE 5 | -------------------------------------------------------------------------------- /packages/mapped-reducer/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | export { MappedReducer } from './MappedReducer' 2 | export { MappedPipeReducer } from './MappedPipeReducer' 3 | export { Reducer, MappedReducerOptions } from './types' 4 | -------------------------------------------------------------------------------- /packages/trackable/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | export { default as TrackableMap } from './map' 2 | export { TrackableRecord } from './record' 3 | export { trackEnhancer } from './track-enhancer' 4 | export { TrackableArray } from './array' 5 | -------------------------------------------------------------------------------- /packages/typed-redux-kit/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | export * from 'typed-redux-kit.base' 2 | export { default as batchEnhancer } from 'typed-redux-kit.batch-enhancer' 3 | export * from 'typed-redux-kit.mapped-reducer' 4 | export * from 'typed-redux-kit.trackable' 5 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "0.1.0", 5 | "command": "tsc", 6 | "isShellCommand": true, 7 | "args": ["-w", "-p", "."], 8 | "showOutput": "silent", 9 | "isBackground": true, 10 | "problemMatcher": "$tsc-watch" 11 | } -------------------------------------------------------------------------------- /packages/base/src/lib/types.ts: -------------------------------------------------------------------------------- 1 | import * as Redux from 'redux' 2 | 3 | export interface PureAction extends Redux.Action { 4 | readonly type: ACTION_TYPE 5 | } 6 | 7 | export interface PayloadAction extends Redux.Action { 8 | readonly type: ACTION_TYPE 9 | readonly payload: PAYLOAD 10 | } 11 | 12 | export type Action = PureAction | PayloadAction 13 | -------------------------------------------------------------------------------- /jest.json: -------------------------------------------------------------------------------- 1 | { 2 | "transform": { 3 | "^.+\\.js$": "babel-jest" 4 | }, 5 | "coverageThreshold": { 6 | "global": { 7 | "branches": 100, 8 | "functions": 100, 9 | "lines": 100, 10 | "statements": 100 11 | } 12 | }, 13 | "setupTestFrameworkScriptFile": "source-map-support/register", 14 | "testMatch": [ 15 | "/build/specs/**/?(*.)(spec|test).js?(x)" 16 | ] 17 | } -------------------------------------------------------------------------------- /packages/base/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "es6", 5 | "allowJs": false, 6 | "jsx": "preserve", 7 | "baseUrl": "./src", 8 | "outDir": "build", 9 | "moduleResolution": "node", 10 | "inlineSourceMap": true, 11 | "noImplicitAny": true, 12 | "plugins": [ 13 | { 14 | "name": "tslint-language-service", 15 | "ignoreDefinitionFiles": true 16 | } 17 | ] 18 | }, 19 | "include": [ 20 | "src/**/*" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /packages/trackable/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2017", 4 | "module": "es6", 5 | "allowJs": false, 6 | "jsx": "preserve", 7 | "baseUrl": "./src", 8 | "outDir": "build", 9 | "moduleResolution": "node", 10 | "inlineSourceMap": true, 11 | "noImplicitAny": true, 12 | "plugins": [ 13 | { 14 | "name": "tslint-language-service", 15 | "ignoreDefinitionFiles": true 16 | } 17 | ] 18 | }, 19 | "include": [ 20 | "src/**/*" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /packages/batch-enhancer/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2017", 4 | "module": "es6", 5 | "allowJs": false, 6 | "jsx": "preserve", 7 | "baseUrl": "./src", 8 | "outDir": "build", 9 | "moduleResolution": "node", 10 | "inlineSourceMap": true, 11 | "noImplicitAny": true, 12 | "plugins": [ 13 | { 14 | "name": "tslint-language-service", 15 | "ignoreDefinitionFiles": true 16 | } 17 | ] 18 | }, 19 | "include": [ 20 | "src/**/*" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /packages/mapped-reducer/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2017", 4 | "module": "es6", 5 | "allowJs": false, 6 | "jsx": "preserve", 7 | "baseUrl": "./src", 8 | "outDir": "build", 9 | "moduleResolution": "node", 10 | "inlineSourceMap": true, 11 | "noImplicitAny": true, 12 | "plugins": [ 13 | { 14 | "name": "tslint-language-service", 15 | "ignoreDefinitionFiles": true 16 | } 17 | ] 18 | }, 19 | "include": [ 20 | "src/**/*" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /packages/typed-redux-kit/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "es6", 5 | "allowJs": false, 6 | "jsx": "preserve", 7 | "baseUrl": "./src", 8 | "outDir": "build", 9 | "moduleResolution": "node", 10 | "inlineSourceMap": true, 11 | "noImplicitAny": true, 12 | "plugins": [ 13 | { 14 | "name": "tslint-language-service", 15 | "ignoreDefinitionFiles": true 16 | } 17 | ] 18 | }, 19 | "include": [ 20 | "src/**/*" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /packages/trackable/src/lib/track-enhancer.ts: -------------------------------------------------------------------------------- 1 | import { Trackable } from './trackable' 2 | import * as Redux from 'redux' 3 | 4 | const terminalProcessor = (reducer: Redux.Reducer) => { 5 | return (state: S, action: Redux.Action): S => { 6 | const reducedState: Trackable = reducer(state, action) as any 7 | 8 | return reducedState.$trackable && reducedState.$trackable.isChanged 9 | ? reducedState.clone() 10 | : reducedState 11 | } 12 | } 13 | 14 | export const trackEnhancer: Redux.GenericStoreEnhancer = (createStore: Redux.StoreEnhancerStoreCreator): Redux.StoreEnhancerStoreCreator => (reducer, preloadedState) => { 15 | return createStore(terminalProcessor(reducer), preloadedState) 16 | } 17 | -------------------------------------------------------------------------------- /packages/base/src/lib/createActionCreator.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Action, 3 | PayloadAction, 4 | PureAction, 5 | } from './types' 6 | 7 | export function createActionCreator >(type: ACTION['type']): (payload: ACTION['payload']) => ACTION 8 | export function createActionCreator >(type: ACTION['type']): () => ACTION 9 | export function createActionCreator (type: ACTION['type']) { 10 | return (payload: ACTION['payload']) => ( 11 | payload == null 12 | ? ({ 13 | type, 14 | } as ACTION) 15 | : ({ 16 | type, 17 | payload, 18 | } as ACTION) 19 | ) 20 | } 21 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.1.0", 3 | "configurations": [ 4 | { 5 | "name": "Debug tests", 6 | "type": "node", 7 | "protocol": "inspector", 8 | "request": "launch", 9 | "cwd": "${workspaceRoot}", 10 | "runtimeArgs": [ 11 | "--inspect-brk", 12 | "./node_modules/jest-cli/bin/jest.js", 13 | "-i", 14 | "--no-cache", "--runInBand", "--config", "jest.json" 15 | // , "record.spec.js" 16 | // , "map.spec.js" 17 | ], 18 | "env": { 19 | "NODE_ENV": "development" 20 | }, 21 | "outFiles": ["${workspaceRoot}/build/**/*.js"], 22 | "console": "integratedTerminal", 23 | "port": 9229, 24 | "sourceMaps": true, 25 | "smartStep": true 26 | } 27 | ] 28 | } -------------------------------------------------------------------------------- /packages/mapped-reducer/src/specs/util.spec.ts: -------------------------------------------------------------------------------- 1 | import * as Util from '../lib/util' 2 | 3 | describe('Util.getActionTypes', () => { 4 | it('gets an action from string', () => { 5 | const input = 'Tango' 6 | 7 | const actionTypes = Util.getActionTypes(input) 8 | 9 | expect(actionTypes).toEqual(['Tango']) 10 | }) 11 | 12 | it('gets actions from array', () => { 13 | const input = ['Tango', 'Tango2'] 14 | 15 | const actionTypes = Util.getActionTypes(input) 16 | 17 | expect(actionTypes).toEqual(['Tango', 'Tango2']) 18 | }) 19 | 20 | it('gets actioins from string enum', () => { 21 | enum ActionTypes { 22 | Tango = 'Tango', 23 | Tango2 = 'Tango2', 24 | } 25 | 26 | const actionTypes = Util.getActionTypes(ActionTypes) 27 | 28 | expect(actionTypes).toEqual(['Tango', 'Tango2']) 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /packages/typed-redux-kit/readme.md: -------------------------------------------------------------------------------- 1 | # Typed Redux Kit 2 | 3 | Toolkit for Redux with Typescript. 4 | 5 | Check the below links. 6 | 7 | - [Home](https://github.com/Revisolution/typed-redux-kit/) 8 | - [Base](https://github.com/Revisolution/typed-redux-kit/tree/master/packages/base) 9 | - [Mapped Reducer](https://github.com/Revisolution/typed-redux-kit/tree/master/packages/mapped-reducer) 10 | - [Batch Enhancer](https://github.com/Revisolution/typed-redux-kit/tree/master/packages/batch-enhancer) 11 | - [Trackable](https://github.com/Revisolution/typed-redux-kit/tree/master/packages/trackable) 12 | 13 | ## Install 14 | 15 | ```sh 16 | npm i typed-redux-kit 17 | ``` 18 | 19 | ## Authors 20 | 21 | - [Stuart Schechter](https://github.com/UppaJung) 22 | - [Junyoung Choi](https://github.com/rokt33r) : Maintainer 23 | - [Joseph Stein](https://github.com/josephstein) 24 | 25 | ## License & Copyright 26 | 27 | Licensed under MIT 28 | Copyright 2017 Revisolution 29 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "tslint:recommended" 4 | ],"rules": { 5 | "indent": [true, "spaces", 2], 6 | "semicolon": [true, "never"], 7 | "quotemark": [true, "single"], 8 | "object-literal-sort-keys": false, 9 | "max-line-length": [false], 10 | "interface-name": [false], 11 | "no-namespace": false, 12 | "curly": [true, "ignore-same-line"], 13 | "array-type": [false], 14 | "max-classes-per-file": [false], 15 | "no-empty-interface": false, 16 | "ordered-imports": false, 17 | "arrow-parens": false, 18 | "space-before-function-paren": false, 19 | "callable-types": false, 20 | "member-ordering": false, 21 | "trailing-comma": [ 22 | true, 23 | { 24 | "singleline": "never", 25 | "multiline": { 26 | "objects": "always", 27 | "arrays": "always", 28 | "functions": "always", 29 | "typeLiterals": "never" 30 | } 31 | } 32 | ] 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "node-build/lib/index.js", 3 | "types": "typings/lib/index.d.js", 4 | "module": "build/lib/index.js", 5 | "author": "Junyoung Choi (https://github.com/Rokt33r/)", 6 | "contributors": [ 7 | "Stuart Schechter (https://github.com/UppaJung/)", 8 | "Joseph Stein (https://github.com/josephstein)" 9 | ], 10 | "license": "MIT", 11 | "scripts": { 12 | "postinstall": "lerna bootstrap", 13 | "build": "lerna run build", 14 | "test": "lerna run test", 15 | "deploy": "lerna publish" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "git+https://github.com/Revisolution/typed-redux-kit.git" 20 | }, 21 | "keywords": [ 22 | "typescript", 23 | "redux" 24 | ], 25 | "bugs": { 26 | "url": "https://github.com/Revisolution/typed-redux-kit/issues" 27 | }, 28 | "homepage": "https://github.com/Revisolution/typed-redux-kit#readme", 29 | "devDependencies": { 30 | "lerna": "^2.1.2" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /packages/mapped-reducer/src/lib/util.ts: -------------------------------------------------------------------------------- 1 | export const getValues = Object.values 2 | 3 | export function isPlainObject (value: any) { 4 | if (value === null || typeof value !== 'object') return false 5 | const proto = Object.getPrototypeOf(value) 6 | return proto === Object.prototype || proto === null 7 | } 8 | 9 | /** 10 | * Get action types from type, type array and type enum 11 | * 12 | * @export 13 | * @template ACTION_TYPE 14 | * @param {(ACTION_TYPE | ACTION_TYPE[] | {[key: number]: ACTION_TYPE} | {[key: string]: ACTION_TYPE})} actionTypeOrActionTypes 15 | * @returns {ACTION_TYPE[]} 16 | */ 17 | export function getActionTypes (actionTypeOrActionTypes: ACTION_TYPE | ACTION_TYPE[] | {[key: number]: ACTION_TYPE} | {[key: string]: ACTION_TYPE}): ACTION_TYPE[] { 18 | return Array.isArray(actionTypeOrActionTypes) 19 | ? actionTypeOrActionTypes 20 | : isPlainObject(actionTypeOrActionTypes) 21 | ? getValues(actionTypeOrActionTypes as object) 22 | : [actionTypeOrActionTypes] 23 | } 24 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | This project is archived as there is nobody to maintain it and keep up with the security updates. Feel free to fork and maintain. 2 | 3 | # Typed Redux Kit 4 | 5 | Toolkit for Redux with Typescript 6 | 7 | ## What the heck is this? 8 | 9 | In this package, you can find several neat tricks. 10 | 11 | - [Base](./packages/base) : Basic usage of redux 12 | - [Mapped Reducer](./packages/mapped-reducer) : Reducer with ES6Map for efficient switching and scalability. 13 | - [Batch Enhancer](./packages/batch-enhancer) : Allows dispatch array of actions. Also it support redux-saga. 14 | - [Trackable](./packages/trackable) : Allows mutable change to deal with deep state. 15 | 16 | [basic-usage.spec.ts](./packages/typed-redux-kit/src/specs/basic-usage.spec.ts) presents how to combine all of toolkit. 17 | 18 | ## Install 19 | 20 | ```sh 21 | npm i typed-redux-kit 22 | ``` 23 | 24 | ## Authors 25 | 26 | - [Stuart Schechter](https://github.com/UppaJung) 27 | - [Junyoung Choi](https://github.com/rokt33r) : Maintainer 28 | - [Joseph Stein](https://github.com/josephstein) 29 | 30 | ## License & Copyright 31 | 32 | Licensed under MIT 33 | Copyright 2017 Revisolution 34 | -------------------------------------------------------------------------------- /packages/trackable/src/lib/util.ts: -------------------------------------------------------------------------------- 1 | export const getEntries = Object.entries 2 | export const getValues = Object.values 3 | 4 | export const resolveEntryFromIterable = (entryIterableOrObject: Iterable<[K, T[K]]> | T) => { 5 | return !!(entryIterableOrObject as Iterable<[K, T[K]]>)[Symbol.iterator] 6 | ? (entryIterableOrObject as Iterable<[K, T[K]]>) 7 | : Object.entries(entryIterableOrObject) as Array<[K, T[K]]> 8 | } 9 | 10 | export const convertIterableToArray = (iterable: Iterable): V[] => { 11 | const array = [] 12 | for (const item of iterable) { 13 | array.push(item) 14 | } 15 | return array 16 | } 17 | 18 | export function isPlainObject (value: any) { 19 | if (value === null || typeof value !== 'object') return false 20 | const proto = Object.getPrototypeOf(value) 21 | return proto === Object.prototype || proto === null 22 | } 23 | 24 | export function getActionTypes (actionTypeOrActionTypes: ACTION_TYPE | ACTION_TYPE[] | {[key: number]: ACTION_TYPE} | {[key: string]: ACTION_TYPE}): ACTION_TYPE[] { 25 | return Array.isArray(actionTypeOrActionTypes) 26 | ? actionTypeOrActionTypes 27 | : isPlainObject(actionTypeOrActionTypes) 28 | ? getValues(actionTypeOrActionTypes as object) 29 | : [actionTypeOrActionTypes] 30 | } 31 | -------------------------------------------------------------------------------- /packages/trackable/src/specs/track-enhancer.spec.ts: -------------------------------------------------------------------------------- 1 | import * as Redux from 'redux' 2 | import { 3 | trackEnhancer, 4 | TrackableMap, 5 | TrackableRecord, 6 | } from '../lib' 7 | 8 | test('it works', () => { 9 | const CountRecord = TrackableRecord({ 10 | count: 0, 11 | }) 12 | type CountRecord = TrackableRecord<{ 13 | count: number 14 | }> 15 | type State = TrackableMap 16 | const defaultChildState = CountRecord({ 17 | count: 0, 18 | }) 19 | const defaultState: State = new TrackableMap({ 20 | a: defaultChildState, 21 | }) 22 | 23 | const myReducer = (state: State = defaultState, action: Redux.Action) => { 24 | if (action.type === 'add') { 25 | state.get('a').count++ 26 | } 27 | return state 28 | } 29 | const store = Redux.createStore(myReducer, trackEnhancer) 30 | 31 | store.dispatch({ 32 | type: 'dummy', 33 | }) 34 | 35 | const firstReducedState = store.getState() 36 | expect(firstReducedState.get('a').count).toBe(0) 37 | expect(firstReducedState).toBe(defaultState) 38 | 39 | store.dispatch({ 40 | type: 'add', 41 | }) 42 | 43 | const secondReducedState = store.getState() 44 | expect(secondReducedState.get('a').count).toBe(1) 45 | expect(secondReducedState).not.toBe(defaultState) 46 | }) 47 | -------------------------------------------------------------------------------- /packages/base/src/specs/createActionCreator.spec.ts: -------------------------------------------------------------------------------- 1 | import { 2 | createActionCreator, 3 | PayloadAction, 4 | PureAction, 5 | } from '../lib' 6 | 7 | enum ActionTypes { 8 | Plus = 'Plus', 9 | Set = 'Set', 10 | } 11 | 12 | namespace Actions { 13 | export type PlusAction = PureAction 14 | export type SetAction = PayloadAction 17 | } 18 | 19 | const ActionCreators = { 20 | plus: createActionCreator(ActionTypes.Plus), 21 | set: createActionCreator(ActionTypes.Set), 22 | } 23 | 24 | test('createActionCreator', () => { 25 | const plusAction = ActionCreators.plus() 26 | 27 | // $ExpectError : it doesn't take any payload 28 | // const plusAction = ActionCreators.plus(123) 29 | 30 | expect(plusAction).toEqual({ 31 | type: ActionTypes.Plus, 32 | }) 33 | 34 | const setAction = ActionCreators.set({ 35 | count: 123, 36 | }) 37 | 38 | // $ExpectError : `count` must be a number 39 | // const setAction = ActionCreators.set({ count: '123'}) 40 | // $ExpectError : payload is required 41 | // const setAction = ActionCreators.set() 42 | 43 | expect(setAction).toEqual({ 44 | type: ActionTypes.Set, 45 | payload: { 46 | count: 123, 47 | }, 48 | }) 49 | }) 50 | -------------------------------------------------------------------------------- /packages/trackable/src/lib/trackable.ts: -------------------------------------------------------------------------------- 1 | export interface TrackableProperties { 2 | parent?: Trackable 3 | isChanged: boolean 4 | shallow: boolean 5 | } 6 | 7 | export const isTrackable = (maybeTrackable: any): boolean => { 8 | if (maybeTrackable == null) return false 9 | return !!(maybeTrackable as Trackable).$trackable 10 | } 11 | 12 | export const setParentIfTrackable = (maybeTrackable: any, parent: Trackable) => { 13 | if (isTrackable(maybeTrackable)) { 14 | (maybeTrackable as Trackable).setParent(parent) 15 | } 16 | } 17 | 18 | export const initializeValue = (maybeTrackable: V, parent: Trackable): V => { 19 | if (isTrackable(maybeTrackable)) { 20 | if ((maybeTrackable as any as Trackable).$trackable.isChanged) { 21 | maybeTrackable = (maybeTrackable as any as Trackable).clone() 22 | } 23 | (maybeTrackable as any as Trackable).setParent(parent) 24 | } 25 | return maybeTrackable 26 | } 27 | 28 | export abstract class Trackable { 29 | public $trackable: TrackableProperties = { 30 | isChanged: false, 31 | shallow: false, 32 | } 33 | 34 | public abstract clone (): T 35 | public abstract onChildChange (child: any): void 36 | public abstract toJS (): any 37 | 38 | public markAsChanged () { 39 | this.$trackable.isChanged = true 40 | 41 | if (this.$trackable.parent) { 42 | this.$trackable.parent.onChildChange(this) 43 | } 44 | } 45 | 46 | public setParent (parent: Trackable) { 47 | this.$trackable.parent = parent 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /packages/base/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "typed-redux-kit.base", 3 | "version": "1.0.2", 4 | "main": "node-build/lib/index.js", 5 | "types": "typings/lib/index.d.js", 6 | "module": "build/lib/index.js", 7 | "author": "Junyoung Choi (https://github.com/Rokt33r/)", 8 | "contributors": [ 9 | "Stuart Schechter (https://github.com/UppaJung/)", 10 | "Joseph Stein (https://github.com/josephstein)" 11 | ], 12 | "license": "MIT", 13 | "scripts": { 14 | "build": "npm run clean && npm run build:es && npm run build:node", 15 | "build:es": "tsc -p . -d --declarationDir typings", 16 | "build:node": "tsc -p . -m commonjs --outDir node-build", 17 | "build:watch": "tsc -p . -w", 18 | "test": "jest -c jest.json", 19 | "test:watch": "jest --watch", 20 | "test:quick": "jest", 21 | "lint": "tslint -c ../../tslint.json -p ./tsconfig.json", 22 | "clean": "rimraf build typings node-build", 23 | "prepublishOnly": "npm run lint && npm run build && npm run test" 24 | }, 25 | "repository": { 26 | "type": "git", 27 | "url": "git+https://github.com/Revisolution/typed-redux-kit.git" 28 | }, 29 | "keywords": [ 30 | "typescript", 31 | "redux" 32 | ], 33 | "bugs": { 34 | "url": "https://github.com/Revisolution/typed-redux-kit/issues" 35 | }, 36 | "homepage": "https://github.com/Revisolution/typed-redux-kit#readme", 37 | "devDependencies": { 38 | "@types/jest": "^20.0.2", 39 | "@types/redux": "^3.6.31", 40 | "babel-jest": "^20.0.3", 41 | "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", 42 | "jest": "^20.0.4", 43 | "redux": "^3.7.0", 44 | "rimraf": "^2.6.1", 45 | "source-map-support": "^0.4.15", 46 | "tslint": "^5.5.0", 47 | "typescript": "^2.5.2" 48 | }, 49 | "peerDependencies": { 50 | "redux": "^3.0.0" 51 | }, 52 | "files": [ 53 | "build/lib/*", 54 | "node-build/lib/*", 55 | "typings/lib/*", 56 | "src/lib/*" 57 | ] 58 | } 59 | -------------------------------------------------------------------------------- /packages/trackable/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "typed-redux-kit.trackable", 3 | "version": "1.0.2", 4 | "main": "node-build/lib/index.js", 5 | "types": "typings/lib/index.d.js", 6 | "module": "build/lib/index.js", 7 | "author": "Junyoung Choi (https://github.com/Rokt33r/)", 8 | "contributors": [ 9 | "Stuart Schechter (https://github.com/UppaJung/)", 10 | "Joseph Stein (https://github.com/josephstein)" 11 | ], 12 | "license": "MIT", 13 | "scripts": { 14 | "build": "npm run clean && npm run build:es && npm run build:node", 15 | "build:es": "tsc -p . -d --declarationDir typings", 16 | "build:node": "tsc -p . -m commonjs --outDir node-build", 17 | "build:watch": "tsc -p . -w", 18 | "test": "jest -c jest.json", 19 | "test:watch": "jest --watch", 20 | "test:quick": "jest", 21 | "lint": "tslint -c ../../tslint.json -p ./tsconfig.json", 22 | "clean": "rimraf build typings node-build", 23 | "prepublishOnly": "npm run lint && npm run build && npm run test" 24 | }, 25 | "repository": { 26 | "type": "git", 27 | "url": "git+https://github.com/Revisolution/typed-redux-kit.git" 28 | }, 29 | "keywords": [ 30 | "typescript", 31 | "redux" 32 | ], 33 | "bugs": { 34 | "url": "https://github.com/Revisolution/typed-redux-kit/issues" 35 | }, 36 | "homepage": "https://github.com/Revisolution/typed-redux-kit#readme", 37 | "devDependencies": { 38 | "@types/jest": "^20.0.2", 39 | "@types/redux": "^3.6.31", 40 | "babel-jest": "^20.0.3", 41 | "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", 42 | "jest": "^20.0.4", 43 | "redux": "^3.7.0", 44 | "rimraf": "^2.6.1", 45 | "source-map-support": "^0.4.15", 46 | "tslint": "^5.5.0", 47 | "typescript": "^2.5.2" 48 | }, 49 | "peerDependencies": { 50 | "redux": "^3.0.0" 51 | }, 52 | "files": [ 53 | "build/lib/*", 54 | "node-build/lib/*", 55 | "typings/lib/*", 56 | "src/lib/*" 57 | ] 58 | } 59 | -------------------------------------------------------------------------------- /packages/mapped-reducer/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "typed-redux-kit.mapped-reducer", 3 | "version": "1.0.2", 4 | "main": "node-build/lib/index.js", 5 | "types": "typings/lib/index.d.js", 6 | "module": "build/lib/index.js", 7 | "author": "Junyoung Choi (https://github.com/Rokt33r/)", 8 | "contributors": [ 9 | "Stuart Schechter (https://github.com/UppaJung/)", 10 | "Joseph Stein (https://github.com/josephstein)" 11 | ], 12 | "license": "MIT", 13 | "scripts": { 14 | "build": "npm run clean && npm run build:es && npm run build:node", 15 | "build:es": "tsc -p . -d --declarationDir typings", 16 | "build:node": "tsc -p . -m commonjs --outDir node-build", 17 | "build:watch": "tsc -p . -w", 18 | "test": "jest -c jest.json", 19 | "test:watch": "jest --watch", 20 | "test:quick": "jest", 21 | "lint": "tslint -c ../../tslint.json -p ./tsconfig.json", 22 | "clean": "rimraf build typings node-build", 23 | "prepublishOnly": "npm run lint && npm run build && npm run test" 24 | }, 25 | "repository": { 26 | "type": "git", 27 | "url": "git+https://github.com/Revisolution/typed-redux-kit.git" 28 | }, 29 | "keywords": [ 30 | "typescript", 31 | "redux" 32 | ], 33 | "bugs": { 34 | "url": "https://github.com/Revisolution/typed-redux-kit/issues" 35 | }, 36 | "homepage": "https://github.com/Revisolution/typed-redux-kit#readme", 37 | "devDependencies": { 38 | "@types/jest": "^20.0.2", 39 | "@types/redux": "^3.6.31", 40 | "babel-jest": "^20.0.3", 41 | "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", 42 | "jest": "^20.0.4", 43 | "redux": "^3.7.0", 44 | "rimraf": "^2.6.1", 45 | "source-map-support": "^0.4.15", 46 | "tslint": "^5.5.0", 47 | "typed-redux-kit.base": "^1.0.2", 48 | "typescript": "^2.5.2" 49 | }, 50 | "peerDependencies": { 51 | "redux": "^3.0.0" 52 | }, 53 | "files": [ 54 | "build/lib/*", 55 | "node-build/lib/*", 56 | "typings/lib/*", 57 | "src/lib/*" 58 | ] 59 | } 60 | -------------------------------------------------------------------------------- /packages/batch-enhancer/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "typed-redux-kit.batch-enhancer", 3 | "version": "1.0.2", 4 | "main": "node-build/lib/index.js", 5 | "types": "typings/lib/index.d.js", 6 | "module": "build/lib/index.js", 7 | "author": "Junyoung Choi (https://github.com/Rokt33r/)", 8 | "contributors": [ 9 | "Stuart Schechter (https://github.com/UppaJung/)", 10 | "Joseph Stein (https://github.com/josephstein)" 11 | ], 12 | "license": "MIT", 13 | "scripts": { 14 | "build": "npm run clean && npm run build:es && npm run build:node", 15 | "build:es": "tsc -p . -d --declarationDir typings", 16 | "build:node": "tsc -p . -m commonjs --outDir node-build", 17 | "build:watch": "tsc -p . -w", 18 | "test": "jest -c jest.json", 19 | "test:watch": "jest --watch", 20 | "test:quick": "jest", 21 | "lint": "tslint -c ../../tslint.json -p ./tsconfig.json", 22 | "clean": "rimraf build typings node-build", 23 | "prepublishOnly": "npm run lint && npm run build && npm run test" 24 | }, 25 | "repository": { 26 | "type": "git", 27 | "url": "git+https://github.com/Revisolution/typed-redux-kit.git" 28 | }, 29 | "keywords": [ 30 | "typescript", 31 | "redux" 32 | ], 33 | "bugs": { 34 | "url": "https://github.com/Revisolution/typed-redux-kit/issues" 35 | }, 36 | "homepage": "https://github.com/Revisolution/typed-redux-kit#readme", 37 | "devDependencies": { 38 | "@types/jest": "^20.0.2", 39 | "@types/redux": "^3.6.31", 40 | "babel-jest": "^20.0.3", 41 | "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", 42 | "jest": "^20.0.4", 43 | "redux": "^3.7.0", 44 | "redux-saga": "^0.15.6", 45 | "rimraf": "^2.6.1", 46 | "source-map-support": "^0.4.15", 47 | "tslint": "^5.5.0", 48 | "typescript": "^2.5.2" 49 | }, 50 | "peerDependencies": { 51 | "redux": "^3.0.0", 52 | "redux-saga": "^0.15.6" 53 | }, 54 | "files": [ 55 | "build/lib/*", 56 | "node-build/lib/*", 57 | "typings/lib/*", 58 | "src/lib/*" 59 | ] 60 | } 61 | -------------------------------------------------------------------------------- /packages/typed-redux-kit/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "typed-redux-kit", 3 | "version": "1.0.2", 4 | "main": "node-build/lib/index.js", 5 | "types": "typings/lib/index.d.js", 6 | "module": "build/lib/index.js", 7 | "author": "Junyoung Choi (https://github.com/Rokt33r/)", 8 | "contributors": [ 9 | "Stuart Schechter (https://github.com/UppaJung/)", 10 | "Joseph Stein (https://github.com/josephstein)" 11 | ], 12 | "license": "MIT", 13 | "scripts": { 14 | "build": "npm run clean && npm run build:es && npm run build:node", 15 | "build:es": "tsc -p . -d --declarationDir typings", 16 | "build:node": "tsc -p . -m commonjs --outDir node-build", 17 | "build:watch": "tsc -p . -w", 18 | "test": "jest -c jest.json", 19 | "test:watch": "jest --watch", 20 | "test:quick": "jest", 21 | "lint": "tslint -c ../../tslint.json -p ./tsconfig.json", 22 | "clean": "rimraf build typings node-build", 23 | "prepublishOnly": "npm run lint && npm run build && npm run test" 24 | }, 25 | "repository": { 26 | "type": "git", 27 | "url": "git+https://github.com/Revisolution/typed-redux-kit.git" 28 | }, 29 | "keywords": [ 30 | "typescript", 31 | "redux" 32 | ], 33 | "bugs": { 34 | "url": "https://github.com/Revisolution/typed-redux-kit/issues" 35 | }, 36 | "homepage": "https://github.com/Revisolution/typed-redux-kit#readme", 37 | "devDependencies": { 38 | "@types/jest": "^20.0.2", 39 | "@types/redux": "^3.6.31", 40 | "babel-jest": "^20.0.3", 41 | "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", 42 | "jest": "^20.0.4", 43 | "redux": "^3.7.0", 44 | "redux-saga": "^0.15.6", 45 | "rimraf": "^2.6.1", 46 | "source-map-support": "^0.4.15", 47 | "tslint": "^5.5.0", 48 | "typescript": "^2.5.2" 49 | }, 50 | "peerDependencies": { 51 | "redux": "^3.0.0", 52 | "redux-saga": "^0.15.6" 53 | }, 54 | "files": [ 55 | "build/lib/*", 56 | "node-build/lib/*", 57 | "typings/lib/*", 58 | "src/lib/*" 59 | ], 60 | "dependencies": { 61 | "typed-redux-kit.base": "^1.0.2", 62 | "typed-redux-kit.batch-enhancer": "^1.0.2", 63 | "typed-redux-kit.mapped-reducer": "^1.0.2", 64 | "typed-redux-kit.trackable": "^1.0.2" 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /packages/batch-enhancer/src/lib/batchEnhancer.ts: -------------------------------------------------------------------------------- 1 | import * as Redux from 'redux' 2 | import * as ReduxSaga from 'redux-saga' 3 | import * as ReduxSagaEffects from 'redux-saga/effects' 4 | 5 | declare module 'redux' { 6 | export interface Dispatch { 7 | (asyncAction: A | A[]): A 8 | } 9 | } 10 | 11 | declare module 'redux-saga/effects' { 12 | export interface Put { 13 | (action: A[]): ReduxSagaEffects.PutEffect 14 | resolve(action: A[]): ReduxSagaEffects.PutEffect 15 | } 16 | } 17 | 18 | const BatchActionType = '@@typed-redux/batched-actions' 19 | 20 | interface BatchAction extends Redux.Action { 21 | type: typeof BatchActionType 22 | actions: Redux.Action[] 23 | } 24 | 25 | const batchable = (reducer: (state: S, action: A | BatchAction) => S) => { 26 | return (state: S, action: A | BatchAction) => { 27 | if (action.type === BatchActionType) { 28 | return (action as BatchAction).actions.reduce(reducer, state) 29 | } 30 | return reducer(state, action) 31 | } 32 | } 33 | 34 | export const batchEnhancer = (sagaMiddleware?: ReduxSaga.SagaMiddleware): Redux.GenericStoreEnhancer => (createStore: Redux.StoreEnhancerStoreCreator): Redux.StoreEnhancerStoreCreator => (reducer, preloadedState) => { 35 | const store = createStore(batchable(reducer), preloadedState) 36 | 37 | let sagaDispatcher: Redux.Dispatch = () => { 38 | return 39 | } 40 | 41 | const batchDispatcher: Redux.Dispatch = (actionOrActions: A | A[]) => { 42 | let action: Redux.Action 43 | if (Array.isArray(actionOrActions)) { 44 | actionOrActions.forEach(sagaDispatcher) 45 | action = { 46 | type: BatchActionType, 47 | actions: actionOrActions, 48 | } as BatchAction 49 | } else { 50 | action = actionOrActions as Redux.Action 51 | sagaDispatcher(action) 52 | } 53 | return store.dispatch(action) 54 | } 55 | 56 | if (sagaMiddleware) { 57 | sagaDispatcher = sagaMiddleware({ 58 | getState: store.getState, 59 | // This dispatcher will be used by `put` effect of saga 60 | dispatch: batchDispatcher, 61 | })((a: Redux.Action) => a) 62 | } 63 | 64 | // Replace dispatch with our one 65 | return { 66 | ...store, 67 | dispatch: batchDispatcher, 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /packages/mapped-reducer/src/specs/MappedReducer.spec.ts: -------------------------------------------------------------------------------- 1 | import { createStore } from 'redux' 2 | import { 3 | MappedReducer, 4 | Reducer, 5 | } from '../lib' 6 | 7 | describe('MappedReducer', () => { 8 | describe('set', () => { 9 | it('sets a reducer', () => { 10 | // Given 11 | const reducer = new MappedReducer() 12 | const ActionType = 'random action' 13 | const subReducer = (state: S) => state 14 | 15 | // When 16 | reducer 17 | .set(ActionType, subReducer) 18 | 19 | // Then 20 | expect(reducer.get(ActionType)).toEqual(subReducer) 21 | }) 22 | 23 | it('deletes a reducer', () => { 24 | // Given 25 | const reducer = new MappedReducer() 26 | const ActionType = 'random action' 27 | const subReducer = (state: S) => state 28 | reducer 29 | .set(ActionType, subReducer) 30 | 31 | // When 32 | reducer 33 | .delete(ActionType) 34 | 35 | // Then 36 | expect(reducer.get(ActionType)).toBeUndefined() 37 | }) 38 | 39 | it('replace reducer', () => { 40 | // Given 41 | const reducer = new MappedReducer() 42 | const ActionType = 'random action' 43 | const subReducer = (state: S) => state 44 | const subReducer2 = (state: S) => state 45 | reducer 46 | .set(ActionType, subReducer) 47 | 48 | // When 49 | reducer 50 | .set(ActionType, subReducer2) 51 | 52 | // Then 53 | expect(reducer.get(ActionType)).toEqual(subReducer2) 54 | }) 55 | }) 56 | 57 | describe('reduce', () => { 58 | it('reduces', () => { 59 | // Given 60 | interface State { 61 | count: 0, 62 | } 63 | const initialState: State = { 64 | count: 0, 65 | } 66 | const reducer = new MappedReducer() 67 | const ActionType = 'random action' 68 | const setReducer = (state: State, action: { 69 | type: typeof ActionType 70 | payload: number 71 | }) => ({ 72 | ...state, 73 | count: action.payload, 74 | } as State) 75 | reducer 76 | .set(ActionType, setReducer) 77 | 78 | // When 79 | const newState = reducer.reduce(initialState, { 80 | type: ActionType, 81 | payload: 1, 82 | } as Redux.Action) 83 | 84 | // Then 85 | expect(newState.count).toBe(1) 86 | }) 87 | }) 88 | }) 89 | -------------------------------------------------------------------------------- /packages/mapped-reducer/src/lib/MappedReducer.ts: -------------------------------------------------------------------------------- 1 | import { Action } from 'redux' 2 | import { 3 | MappedReducerOptions, 4 | Reducer, 5 | } from './types' 6 | import { getActionTypes } from './util' 7 | 8 | export class MappedReducer { 9 | private initialState: STATE 10 | 11 | private reducerMap = new Map>() 12 | 13 | /** 14 | * Instantiate MappedReducer 15 | * 16 | * The only option is initialState for now. 17 | * 18 | * @param {MappedReducerOptions} [opts={}] 19 | * @memberof MappedReducer 20 | */ 21 | constructor(opts: MappedReducerOptions = {}) { 22 | this.initialState = opts.initialState 23 | } 24 | 25 | /** 26 | * Set a subreducer for the given action type(s) 27 | * 28 | * It takes a single action type and array/string enum of action types 29 | * 30 | * @memberof MappedReducer 31 | */ 32 | public set = ( 33 | actionTypeOrActionTypes: SETTED_ACTION_TYPE | SETTED_ACTION_TYPE[] | {[key: number]: SETTED_ACTION_TYPE} | {[key: string]: SETTED_ACTION_TYPE}, 34 | reducer: Reducer, 35 | ) => { 36 | const actionTypes: SETTED_ACTION_TYPE[] = getActionTypes(actionTypeOrActionTypes) 37 | actionTypes.forEach((actionType) => { 38 | this.reducerMap.set(actionType, reducer) 39 | }) 40 | return this 41 | } 42 | 43 | /** 44 | * Delete a subreducer for the given action type(s) 45 | * 46 | * It takes a single action type and array/string enum of action types 47 | * 48 | * @memberof MappedReducer 49 | */ 50 | public delete = ( 51 | actionTypeOrActionTypes: SETTED_ACTION_TYPE | SETTED_ACTION_TYPE[] | {[key: number]: SETTED_ACTION_TYPE} | {[key: string]: SETTED_ACTION_TYPE}, 52 | ) => { 53 | const actionTypes: SETTED_ACTION_TYPE[] = getActionTypes(actionTypeOrActionTypes) 54 | actionTypes.forEach((actionType) => { 55 | this.reducerMap.delete(actionType) 56 | }) 57 | return this 58 | } 59 | 60 | public get = (actionType: SETTED_ACTION_TYPE) => this.reducerMap.get(actionType) 61 | 62 | public reduce = (state: STATE = this.initialState, action: ACTION): STATE => { 63 | if (!this.reducerMap.has(action.type)) return state 64 | return this.reducerMap.get(action.type)(state, action) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /packages/typed-redux-kit/src/specs/basic-usage.spec.ts: -------------------------------------------------------------------------------- 1 | import * as Redux from 'redux' 2 | import createSagaMiddleware from 'redux-saga' 3 | import { take, call, put } from 'redux-saga/effects' 4 | import { 5 | trackEnhancer, 6 | batchEnhancer, 7 | TrackableRecord, 8 | MappedPipeReducer, 9 | createActionCreator, 10 | PureAction, 11 | } from '../lib' 12 | 13 | /** 14 | * Actions 15 | */ 16 | 17 | enum ActionTypes { 18 | SayHello = 'SayHello', 19 | SayBye = 'SayBye', 20 | } 21 | 22 | namespace Actions { 23 | export type SayHello = PureAction 24 | export type SayBye = PureAction 25 | } 26 | 27 | const ActionCreators = { 28 | sayHello: createActionCreator(ActionTypes.SayHello), 29 | sayBye: createActionCreator(ActionTypes.SayBye), 30 | } 31 | 32 | interface State { 33 | message: string, 34 | count: number, 35 | } 36 | 37 | /** 38 | * Reducers 39 | */ 40 | 41 | type StateRecord = TrackableRecord 42 | const StateRecord = TrackableRecord({ 43 | message: '', 44 | count: 0, 45 | }) 46 | const initialState = StateRecord() 47 | 48 | const sayHelloReducer = (state: StateRecord, action: Actions.SayHello) => { 49 | state.message = 'hello' 50 | return state 51 | } 52 | 53 | const sayByeReducer = (state: StateRecord, action: Actions.SayBye) => { 54 | state.message = 'bye' 55 | return state 56 | } 57 | 58 | const masterReducer = (state: StateRecord, action: Redux.Action) => { 59 | state.count++ 60 | return state 61 | } 62 | 63 | const reducer = new MappedPipeReducer() 64 | reducer.set(ActionTypes.SayHello, sayHelloReducer) 65 | reducer.set(ActionTypes.SayBye, sayByeReducer) 66 | reducer.append(ActionTypes, masterReducer) 67 | 68 | /** 69 | * Saga 70 | */ 71 | 72 | const dummyFn = jest.fn() 73 | function * saga () { 74 | while (true) { 75 | yield take(ActionTypes.SayHello) 76 | yield call(dummyFn) 77 | yield put([ 78 | ActionCreators.sayBye(), 79 | ActionCreators.sayBye(), 80 | ]) 81 | } 82 | } 83 | 84 | test('Basic usage', () => { 85 | // Given 86 | const sagaMiddleware = createSagaMiddleware() 87 | const enhancer = Redux.compose>(trackEnhancer, batchEnhancer(sagaMiddleware)) 88 | const store = Redux.createStore(reducer.reduce, initialState, enhancer) 89 | sagaMiddleware.run(saga) 90 | 91 | // When 92 | store.dispatch([ 93 | ActionCreators.sayHello(), 94 | ActionCreators.sayHello(), 95 | ]) 96 | 97 | // Then 98 | const state = store.getState() 99 | expect(state.message).toBe('hello') 100 | expect(state.count).toBe(6) 101 | expect(state).not.toBe(initialState) 102 | }) 103 | -------------------------------------------------------------------------------- /packages/base/readme.md: -------------------------------------------------------------------------------- 1 | # Base - Typed Redux Kit 2 | 3 | Tools for basic usage of redux with Typescript 4 | 5 | It provides several convenient interfaces and functions to define `Redux.Action`. 6 | 7 | ## Install 8 | 9 | ```sh 10 | npm i typed-redux-kit.base 11 | 12 | # Or install typed-redux-kit 13 | npm i typed-redux-kit 14 | ``` 15 | 16 | ## Examples 17 | 18 | ```ts 19 | import { 20 | createActionCreator, 21 | PayloadAction, 22 | PureAction, 23 | } from 'typed-redux-kit.base' 24 | 25 | // Define action types with string enum 26 | enum ActionTypes { 27 | Plus = 'Plus', 28 | Set = 'Set', 29 | } 30 | 31 | // Define action interfaces 32 | namespace Actions { 33 | export type PlusAction = PureAction 34 | export type SetAction = PayloadAction 37 | } 38 | 39 | // Define action creators 40 | const ActionCreators = { 41 | plus: createActionCreator(ActionTypes.Plus), 42 | set: createActionCreator(ActionTypes.Set), 43 | } 44 | 45 | test('createActionCreator', () => { 46 | // Create action without any payload 47 | const plusAction = ActionCreators.plus() 48 | 49 | // $ExpectError : it doesn't take any payload 50 | // const plusAction = ActionCreators.plus(123) 51 | 52 | expect(plusAction).toEqual({ 53 | type: ActionTypes.Plus, 54 | }) 55 | 56 | // Crate action with the specific payload 57 | const setAction = ActionCreators.set({ 58 | count: 123, 59 | }) 60 | 61 | // $ExpectError : `count` must be a number 62 | // const setAction = ActionCreators.set({ count: '123'}) 63 | // $ExpectError : payload is required 64 | // const setAction = ActionCreators.set() 65 | 66 | expect(setAction).toEqual({ 67 | type: ActionTypes.Set, 68 | payload: { 69 | count: 123, 70 | }, 71 | }) 72 | }) 73 | ``` 74 | 75 | ## APIs 76 | 77 | ### `PureAction` interface 78 | 79 | `Redux.Action` without any properties. 80 | 81 | ### `PureAction` interface 82 | 83 | `Redux.Action` with `payload` property. 84 | 85 | ### `Action` type 86 | 87 | An union type of `PureAction` and `PureAction` 88 | 89 | ### `createActionCreator(actionType)` 90 | 91 | It returns an action creator, which passes the first argument to the payload property of an `Redux.Action`. 92 | 93 | This is very simple function. The only benefit of this is that you can create strictly typed action creators with less typings. 94 | 95 | ```ts 96 | // With createActionCreator 97 | createActionCreator(ActionTypes.Plus) 98 | 99 | // Same to the above 100 | (payload) => ({ 101 | type: ActionTypes.Plus, 102 | payload, 103 | }) 104 | ``` 105 | 106 | ## Authors 107 | 108 | - [Stuart Schechter](https://github.com/UppaJung) 109 | - [Junyoung Choi](https://github.com/rokt33r) : Maintainer 110 | - [Joseph Stein](https://github.com/josephstein) 111 | 112 | ## License & Copyright 113 | 114 | Licensed under MIT 115 | Copyright 2017 Revisolution 116 | -------------------------------------------------------------------------------- /packages/batch-enhancer/readme.md: -------------------------------------------------------------------------------- 1 | # Batch Enhancer - Typed Redux Kit 2 | 3 | Let's dispatch an array of actions! 4 | 5 | ## Install 6 | 7 | ```sh 8 | npm i typed-redux-kit.batch-enhancer 9 | 10 | # Or install typed-redux-kit 11 | npm i typed-redux-kit 12 | ``` 13 | 14 | ## Example 15 | 16 | ```ts 17 | import { createStore, Action, StoreCreator, Store, StoreEnhancer, compose, applyMiddleware } from 'redux' 18 | import * as Redux from 'redux' 19 | import createSagaMiddleware, { SagaMiddleware } from 'redux-saga' 20 | import { fork, take, put } from 'redux-saga/effects' 21 | import batchEnhancer from 'typed-redux-kit.batch-enhancer' 22 | 23 | const sagaMiddleware = createSagaMiddleware() 24 | const middlewareEnhancer = applyMiddleware(sampleMiddleware) 25 | // Compose enhancer. You probably need this if you're using other middlewares like Redux Logger. 26 | const enhancer = compose>( 27 | middlewareEnhancer, 28 | // If you're using saga, you must provide it to `batchEnhancer` rather than `applyMiddleware` 29 | batchEnhancer(sagaMiddleware), 30 | // Otherwise, just call it without an argument 31 | // batchEnhancer(), 32 | ) 33 | // Apply enhancer when 34 | const store = createStore(myReducer, enhancer) 35 | 36 | // Now you can dispatch an array of actions 37 | store.dispatch([ 38 | { 39 | type: 'SayHello', 40 | }, 41 | { 42 | type: 'SayHello', 43 | }, 44 | { 45 | type: 'SayHello', 46 | }, 47 | ]) 48 | 49 | // You can do it inside of saga generator too 50 | function * saga () { 51 | while (true) { 52 | yield take('SayHello') 53 | yield put([ 54 | { 55 | type: 'SayBye', 56 | }, 57 | { 58 | type: 'SayBye', 59 | }, 60 | { 61 | type: 'SayBye', 62 | }, 63 | ]) 64 | } 65 | } 66 | ``` 67 | 68 | ## Why? 69 | 70 | With every dispatch, all components connected with Redux(`connect`) are re-rendered. 71 | 72 | For reusability, you want to have lots of atomic actions which does one thing well and reliably. This forces you to dispatch a series of actions. 73 | 74 | Here comes the problem. Since each dispatch causes a render, when your app grows bigger, it triggers a bunch of unnecessary renders. 75 | 76 | With Batch Enhancer, you can delay the rendering. If you dispatch an array of actions, BatchEnhancer passes the all actions to the reducer and renders on the final one. 77 | 78 | So, if you dispatch like the example below: 79 | 80 | ```ts 81 | store.dispatch([ 82 | { 83 | type: 'SayHello', 84 | }, 85 | { 86 | type: 'SayHello', 87 | }, 88 | { 89 | type: 'SayHello', 90 | }, 91 | ]) 92 | ``` 93 | 94 | Your state will be reduced 3 times but connected components will be re-rendered only one time. 95 | 96 | ## APIs 97 | 98 | Batch Enhancer has only one API, itself. 99 | 100 | ### `batchEnhancer(sagaMiddleware?: SagaMiddleware): Redux.GenericStoreEnhancer` 101 | 102 | Create batch enhancer with Saga middleware. 103 | 104 | ## Authors 105 | 106 | - [Stuart Schechter](https://github.com/UppaJung) 107 | - [Junyoung Choi](https://github.com/rokt33r) : Maintainer 108 | - [Joseph Stein](https://github.com/josephstein) 109 | 110 | ## License & Copyright 111 | 112 | Licensed under MIT 113 | Copyright 2017 Revisolution 114 | -------------------------------------------------------------------------------- /packages/batch-enhancer/src/specs/batchEnhancer.spec.ts: -------------------------------------------------------------------------------- 1 | import { createStore, Action, StoreCreator, Store, StoreEnhancer, compose, applyMiddleware } from 'redux' 2 | import * as Redux from 'redux' 3 | import createSagaMiddleware, { SagaMiddleware } from 'redux-saga' 4 | import { fork, take, put } from 'redux-saga/effects' 5 | import batchEnhancer from '../lib' 6 | 7 | const sampleMiddleware: Redux.Middleware = () => next => (action: Redux.Action) => { 8 | return next(action) 9 | } 10 | 11 | test('batch', () => { 12 | interface State { 13 | count: number 14 | } 15 | const initialState: State = {count: 0} 16 | 17 | const myReducer = (state: State, action: Redux.Action) => { 18 | if (action.type === 'SayHello') { 19 | return { 20 | count: state.count + 1, 21 | } 22 | } 23 | 24 | return state 25 | } 26 | 27 | const sagaMiddleware = createSagaMiddleware() 28 | const middlewareEnhancer = applyMiddleware(sampleMiddleware) 29 | const enhancer = compose>( 30 | middlewareEnhancer, 31 | batchEnhancer(sagaMiddleware), 32 | ) 33 | // const sagaMiddleware = createSagaMiddleware() 34 | // const middlewareEnhancer: Redux.StoreEnhancer = applyMiddleware(sampleMiddleware) 35 | // const enhancer = compose( 36 | // middlewareEnhancer, 37 | // batchEnhancer(sagaMiddleware), 38 | // ) 39 | const store = createStore(myReducer, initialState, enhancer) 40 | 41 | const output = { 42 | helloSagaCalled: 0, 43 | byeSagaCalled: 0, 44 | listenerCalled: 0, 45 | } 46 | 47 | store.subscribe(() => { 48 | output.listenerCalled++ 49 | }) 50 | 51 | function * sayHello () { 52 | while (true) { 53 | yield take('SayHello') 54 | output.helloSagaCalled++ 55 | 56 | // Inside of saga, you can dispatch batch action 57 | yield put([ 58 | { 59 | type: 'SayBye', 60 | }, 61 | { 62 | type: 'SayBye', 63 | }, 64 | { 65 | type: 'SayBye', 66 | }, 67 | ]) 68 | } 69 | } 70 | 71 | function * sayBye () { 72 | while (true) { 73 | yield take('SayBye') 74 | output.byeSagaCalled++ 75 | } 76 | } 77 | 78 | sagaMiddleware.run(function *() { 79 | yield fork(sayHello) 80 | yield fork(sayBye) 81 | }) 82 | 83 | // Dispath single action 84 | store.dispatch({ 85 | type: 'SayHello', 86 | }) 87 | expect(output).toEqual({ 88 | byeSagaCalled: 3, 89 | helloSagaCalled: 1, 90 | // Litener will be called twice 91 | // One from the above dispatch 92 | // One from saga 93 | listenerCalled: 2, 94 | }) 95 | expect(store.getState().count).toEqual(1) 96 | 97 | // Dispatch batch action 98 | store.dispatch([ 99 | { 100 | type: 'SayHello', 101 | }, 102 | { 103 | type: 'SayHello', 104 | }, 105 | { 106 | type: 'SayHello', 107 | }, 108 | ]) 109 | 110 | // Although our reducer and saga will be called 4 times, 111 | // the listener will be called only 2 times. 112 | expect(output).toEqual({ 113 | // Now byeSaga will be called 12 times because helloSaga is called 4 times and each hello saga dispatch ByeAction 3 times. (4x3) 114 | byeSagaCalled: (1 + 3) * 3, 115 | helloSagaCalled: 4, 116 | // Single dispatch + side effect 117 | // Single Batched dispatch + side effect of each batched action. 118 | listenerCalled: 2 + 4, 119 | }) 120 | expect(store.getState().count).toEqual(4) 121 | }) 122 | -------------------------------------------------------------------------------- /packages/trackable/src/lib/record.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Trackable, 3 | isTrackable, 4 | setParentIfTrackable, 5 | initializeValue, 6 | } from './trackable' 7 | import { 8 | resolveEntryFromIterable, 9 | getEntries, 10 | } from './util' 11 | 12 | export type TrackableRecord = T & TrackableRecordClass 13 | export const TrackableRecord = (defaultValue: T): (object?: Partial) => TrackableRecord => { 14 | class ExtendedTrackableRecord extends TrackableRecordClass { 15 | public clone (): TrackableRecord { 16 | return new ExtendedTrackableRecord(Object.assign({}, defaultValue, this.internalObject)) as TrackableRecord 17 | } 18 | } 19 | 20 | const keys = Object.keys(defaultValue) 21 | keys.forEach(key => { 22 | Object.defineProperty(ExtendedTrackableRecord.prototype, key, { 23 | set (newValue) { 24 | this.set(key, newValue) 25 | }, 26 | get () { 27 | return this.get(key) 28 | }, 29 | }) 30 | }) 31 | 32 | return (object?: Partial) => { 33 | const record = new ExtendedTrackableRecord(Object.assign({}, defaultValue, object)) 34 | return record as TrackableRecord 35 | } 36 | } 37 | 38 | export class TrackableRecordClass extends Trackable> { 39 | protected internalObject: T 40 | 41 | constructor (entryIterableOrObject?: Iterable<[keyof T, T[keyof T]]> | T) { 42 | super() 43 | if (entryIterableOrObject) { 44 | const entryIterable = resolveEntryFromIterable(entryIterableOrObject) 45 | 46 | this.internalObject = {} as T 47 | for (let [key, value] of entryIterable) { 48 | value = initializeValue(value, this) 49 | this.internalObject[key] = value as T[keyof T] 50 | } 51 | } else { 52 | this.internalObject = {} as T 53 | } 54 | } 55 | 56 | public [Symbol.iterator] () { 57 | const entries = getEntries(this.internalObject) 58 | return entries[Symbol.iterator]() 59 | } 60 | 61 | public onChildChange (child: any) { 62 | this.markAsChanged() 63 | } 64 | 65 | public get (key: K, defaultValue?: T[K]): T[K] { 66 | if (this.internalObject[key] === undefined) return defaultValue 67 | return this.internalObject[key] 68 | } 69 | 70 | public set (key: K, newValue: T[K]) { 71 | const previousValue = this.internalObject[key] 72 | if (previousValue !== newValue) { 73 | this.markAsChanged() 74 | this.internalObject[key] = newValue 75 | if (isTrackable(newValue)) { 76 | setParentIfTrackable(newValue, this) 77 | } 78 | } 79 | return this 80 | } 81 | 82 | public delete (key: K) { 83 | if (this.internalObject[key] !== undefined) { 84 | this.markAsChanged() 85 | this.internalObject[key] = undefined 86 | } 87 | return this 88 | } 89 | 90 | public update (key: K, mutator: (value: T[K]) => T[K]) { 91 | const value = this.get(key) 92 | this.set(key, mutator(value)) 93 | return this 94 | } 95 | 96 | public merge (partial: Iterable<[K, T[K]]> | Partial) { 97 | const entries = resolveEntryFromIterable(partial) 98 | for (const [key, value] of entries) { 99 | this.set(key, value) 100 | } 101 | return this 102 | } 103 | 104 | public clone () { 105 | return new TrackableRecordClass(this.internalObject) as TrackableRecord 106 | } 107 | 108 | public toJS (shallow: boolean = false) { 109 | const pureObject: T = {} as T 110 | for (const [key, value] of this) { 111 | pureObject[key as K] = !shallow && isTrackable(value) 112 | ? value.toJS() 113 | : value 114 | } 115 | 116 | return pureObject 117 | } 118 | } 119 | 120 | export default TrackableRecord 121 | -------------------------------------------------------------------------------- /packages/trackable/src/lib/map.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Trackable, 3 | isTrackable, 4 | setParentIfTrackable, 5 | initializeValue, 6 | } from './trackable' 7 | import { 8 | resolveEntryFromIterable, 9 | convertIterableToArray, 10 | } from './util' 11 | 12 | class TrackableMap extends Trackable> { 13 | private internalMap: Map 14 | 15 | public get size (): number { 16 | return this.internalMap.size 17 | } 18 | 19 | constructor (entryIterableOrObject?: Iterable<[K, V]> | {[key: string]: V}) { 20 | super() 21 | if (entryIterableOrObject) { 22 | const entryIterable = resolveEntryFromIterable(entryIterableOrObject) 23 | 24 | this.internalMap = new Map() 25 | for (let [key, value] of entryIterable) { 26 | value = initializeValue(value, this) 27 | this.internalMap.set(key, value) 28 | } 29 | } else { 30 | this.internalMap = new Map() 31 | } 32 | } 33 | 34 | public [Symbol.iterator] () { 35 | return this.internalMap[Symbol.iterator]() 36 | } 37 | 38 | public onChildChange (child: V) { 39 | this.markAsChanged() 40 | } 41 | 42 | public has (key: K) { 43 | return this.internalMap.has(key) 44 | } 45 | 46 | public get (key: K, defaultValue?: V): V { 47 | if (!this.internalMap.has(key)) { 48 | return defaultValue 49 | } 50 | return this.internalMap.get(key) 51 | } 52 | 53 | public set (key: K, newValue: V) { 54 | const previousValue = this.internalMap.get(key) 55 | if (previousValue !== newValue) { 56 | this.markAsChanged() 57 | this.internalMap.set(key, newValue) 58 | setParentIfTrackable(newValue, this) 59 | } 60 | return this 61 | } 62 | 63 | public delete (key: K) { 64 | if (this.internalMap.has(key)) { 65 | this.markAsChanged() 66 | this.internalMap.delete(key) 67 | } 68 | return this 69 | } 70 | 71 | public update (key: K, mutator: (value: V) => V, defaultValue?: V) { 72 | const value = this.get(key, defaultValue) 73 | this.set(key, mutator(value)) 74 | return this 75 | } 76 | 77 | public merge (partial: Iterable<[K, V]> | {[key: string]: V}) { 78 | const entries = resolveEntryFromIterable(partial) 79 | for (const [key, value] of entries) { 80 | this.set(key, value) 81 | } 82 | return this 83 | } 84 | 85 | public clear () { 86 | if (this.internalMap.size > 0) { 87 | this.internalMap = new Map() 88 | this.markAsChanged() 89 | } 90 | } 91 | 92 | public entries () { 93 | return this.internalMap.entries() 94 | } 95 | 96 | public toEntryArray () { 97 | return convertIterableToArray(this.entries()) 98 | } 99 | 100 | public keys () { 101 | return this.internalMap.keys() 102 | } 103 | 104 | public toKeyArray () { 105 | return convertIterableToArray(this.keys()) 106 | } 107 | 108 | public values () { 109 | return this.internalMap.values() 110 | } 111 | 112 | public toValueArray () { 113 | return convertIterableToArray(this.values()) 114 | } 115 | 116 | public mapToArray (callback: (item: V, index: K) => R): R[] { 117 | const array = [] 118 | for (const [key, value] of this.internalMap.entries()) { 119 | array.push(callback(value, key)) 120 | } 121 | return array 122 | } 123 | 124 | public map (callback: (item: V, index: K) => R): TrackableMap { 125 | const newMap: TrackableMap = new TrackableMap() 126 | for (const [key, value] of this.internalMap.entries()) { 127 | newMap.set(key, callback(value, key)) 128 | } 129 | newMap.$trackable.isChanged = false 130 | return newMap 131 | } 132 | 133 | public filter (callback: (item: V, index: K) => boolean): TrackableMap { 134 | const newMap: TrackableMap = new TrackableMap() 135 | for (const [key, value] of this.internalMap.entries()) { 136 | if (callback(value, key)) { 137 | newMap.set(key, value) 138 | } 139 | } 140 | newMap.$trackable.isChanged = false 141 | return newMap 142 | } 143 | 144 | public clone () { 145 | return new TrackableMap(this) 146 | } 147 | 148 | public toJS (shallow: boolean = false) { 149 | const pureObject: {[key: string]: V} = {} 150 | for (const [key, value] of this) { 151 | pureObject[key] = !shallow && isTrackable(value) 152 | ? (value as any as Trackable).toJS() 153 | : value 154 | } 155 | 156 | return pureObject 157 | } 158 | } 159 | 160 | export default TrackableMap 161 | -------------------------------------------------------------------------------- /packages/mapped-reducer/src/lib/MappedPipeReducer.ts: -------------------------------------------------------------------------------- 1 | import { Action } from 'redux' 2 | import { 3 | MappedReducerOptions, 4 | Reducer, 5 | } from './types' 6 | import { getActionTypes } from './util' 7 | 8 | type ReducerArray = Reducer[] 9 | 10 | export class MappedPipeReducer { 11 | private initialState: STATE 12 | 13 | private reducerMap = new Map>() 14 | 15 | constructor(opts: MappedReducerOptions = {}) { 16 | this.initialState = opts.initialState 17 | } 18 | 19 | /** 20 | * Append reducer functions for the given key 21 | */ 22 | public unshift = ( 23 | actionTypeOrActionTypes: SETTED_ACTION_TYPE | SETTED_ACTION_TYPE[] | {[key: number]: SETTED_ACTION_TYPE} | {[key: string]: SETTED_ACTION_TYPE}, 24 | reducerOrReducers: Reducer | ReducerArray, 25 | ) => { 26 | const actionTypes: SETTED_ACTION_TYPE[] = getActionTypes(actionTypeOrActionTypes) 27 | const reducers: ReducerArray = Array.isArray(reducerOrReducers) 28 | ? reducerOrReducers 29 | : [reducerOrReducers] 30 | 31 | actionTypes.forEach((actionType) => { 32 | const reducerArray: ReducerArray = this.reducerMap.has(actionType) 33 | ? this.reducerMap.get(actionType) 34 | : [] 35 | reducerArray.unshift(...reducers) 36 | this.reducerMap.set(actionType, reducerArray) 37 | }) 38 | return this 39 | } 40 | public prepend = this.unshift 41 | 42 | /** 43 | * Append reducer functions for the given key 44 | */ 45 | public push = ( 46 | actionTypeOrActionTypes: SETTED_ACTION_TYPE | SETTED_ACTION_TYPE[] | {[key: number]: SETTED_ACTION_TYPE} | {[key: string]: SETTED_ACTION_TYPE}, 47 | reducerOrReducers: Reducer | ReducerArray, 48 | ) => { 49 | const actionTypes: SETTED_ACTION_TYPE[] = getActionTypes(actionTypeOrActionTypes) 50 | const reducers: ReducerArray = Array.isArray(reducerOrReducers) 51 | ? reducerOrReducers 52 | : [reducerOrReducers] 53 | 54 | actionTypes.forEach((actionType) => { 55 | const reducerArray: ReducerArray = this.reducerMap.has(actionType) 56 | ? this.reducerMap.get(actionType) 57 | : [] 58 | reducerArray.push(...reducers) 59 | this.reducerMap.set(actionType, reducerArray) 60 | }) 61 | return this 62 | } 63 | public append = this.push 64 | 65 | /** 66 | * Replace reducer functions for the given key 67 | */ 68 | public set = ( 69 | actionTypeOrActionTypes: SETTED_ACTION_TYPE | SETTED_ACTION_TYPE[] | {[key: number]: SETTED_ACTION_TYPE} | {[key: string]: SETTED_ACTION_TYPE}, 70 | reducerOrReducers: Reducer | ReducerArray, 71 | ) => { 72 | const actionTypes: SETTED_ACTION_TYPE[] = getActionTypes(actionTypeOrActionTypes) 73 | const reducers: ReducerArray = Array.isArray(reducerOrReducers) 74 | ? reducerOrReducers 75 | : [reducerOrReducers] 76 | 77 | actionTypes.forEach((actionType) => { 78 | this.reducerMap.set(actionType, reducers) 79 | }) 80 | return this 81 | } 82 | 83 | /** 84 | * Replace reducer functions for the given key 85 | */ 86 | public delete = ( 87 | actionTypeOrActionTypes: SETTED_ACTION_TYPE | SETTED_ACTION_TYPE[] | {[key: number]: SETTED_ACTION_TYPE} | {[key: string]: SETTED_ACTION_TYPE}, 88 | ) => { 89 | const actionTypes: SETTED_ACTION_TYPE[] = getActionTypes(actionTypeOrActionTypes) 90 | 91 | actionTypes.forEach((actionType) => { 92 | this.reducerMap.delete(actionType) 93 | }) 94 | return this 95 | } 96 | 97 | public get = (actionType: SETTED_ACTION_TYPE) => this.reducerMap.get(actionType) 98 | 99 | public reduce = (state: STATE = this.initialState, action: ACTION): STATE => { 100 | if (!this.reducerMap.has(action.type)) return state 101 | const reducers = this.reducerMap.get(action.type) 102 | return reducers.reduce((aState, reducer) => reducer(aState, action), state) 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /packages/trackable/readme.md: -------------------------------------------------------------------------------- 1 | # Trackable - Typed Redux Kit 2 | 3 | Modify your state mutably! 4 | 5 | Trackable will track the mess you've done and make sure the modified state stays shiny & new. 6 | 7 | ## Install 8 | 9 | ```sh 10 | npm i typed-redux-kit.trackable 11 | 12 | # Or install typed-redux-kit 13 | npm i typed-redux-kit 14 | ``` 15 | 16 | ## Examples 17 | 18 | ```ts 19 | import * as Redux from 'redux' 20 | import { 21 | trackEnhancer, 22 | TrackableRecord, 23 | TrackableMap, 24 | } from '../lib' 25 | 26 | const CountRecord = TrackableRecord({ 27 | count: 0, 28 | }) 29 | type CountRecord = TrackableRecord<{ 30 | count: number 31 | }> 32 | type State = TrackableMap 33 | const defaultChildState = CountRecord({ 34 | count: 0, 35 | }) 36 | const defaultState: State = new TrackableMap({ 37 | a: defaultChildState, 38 | }) 39 | 40 | const myReducer = (state: State = defaultState, action: Redux.Action) => { 41 | if (action.type === 'add') { 42 | // You can mutate the data directly! 43 | state.get('a').count++ 44 | } 45 | return state 46 | } 47 | // Because track enhancer will renew all tracked changes. 48 | const store = Redux.createStore(myReducer, trackEnhancer) 49 | 50 | store.dispatch({ 51 | type: 'add', 52 | }) 53 | 54 | const reducedState = store.getState() 55 | expect(reducedState.get('a').count).toBe(1) 56 | // We've mutated it directly, but reduced state is a different instance! 57 | expect(reducedState).not.toBe(defaultState) 58 | ``` 59 | 60 | ## Why? 61 | 62 | Handling a state with deep depth is very painful. If you don't use Immutable, you should do like this: 63 | 64 | ```ts 65 | const myReducer = (state, action) => ({ 66 | ...state, 67 | depth1: { 68 | ...state.depth1, 69 | depth2: { 70 | ...state.depth1.depth2, 71 | depth3: { 72 | ...state.depth1.depth2.depth3, 73 | depth4: action.payload 74 | }, 75 | }, 76 | }, 77 | }) 78 | ``` 79 | 80 | This is super verbose and I've seen a lot of people make mistakes when handling this kind of structure. 81 | 82 | In this case, Immutable.js can fix it. 83 | 84 | ```ts 85 | const myReducer = (state, action) => ( 86 | state.setIn(['depth1', 'depth2', 'depth3', 'depth4'], action.payload) 87 | ) 88 | ``` 89 | 90 | But here comes another problem. Its `getIn`, `setIn` and similar `...In` methods take in a string array to resolve keys. So, type inference of typescript doesn't work at all. To keep typeinference working, you have to do like this. 91 | 92 | ```ts 93 | const myReducer = (state, action) => ( 94 | state 95 | .update('depth1', depth1 => depth1 96 | .update('depth2', depth2 => depth2 97 | .update('depth3', depth3 => depth3 98 | .update('depth4', depth4 => action.payload) 99 | ) 100 | ) 101 | ) 102 | ) 103 | ``` 104 | 105 | This is horrible. 106 | 107 | But with Trackable, you can do it like this: 108 | 109 | ```ts 110 | const myReducer = (state, action) => { 111 | state.depth1.depth2.depth3.depth4 = action.payload 112 | return state 113 | } 114 | ``` 115 | 116 | Now you don't have to worry since your state is immutable. Also, type inference against every depth works perfectly. 117 | 118 | ## Todo 119 | 120 | - Set 121 | - HAMT(Hashed Array Map Tree which Immutable.js has) 122 | 123 | ## Polyfill 124 | 125 | Trackable is using Object.values and Object.entries. If you need to support legacy Node.js or browser, use the below polyfill or transpile again with babel: 126 | 127 | ```ts 128 | // Polyfill 129 | const reduce = Function.bind.call(Function.call, Array.prototype.reduce) 130 | const isEnumerable = Function.bind.call(Function.call, Object.prototype.propertyIsEnumerable) 131 | const concat = Function.bind.call(Function.call, Array.prototype.concat) 132 | const keys = Reflect.ownKeys 133 | 134 | if (!Object.values) { 135 | Object.values = function values(O: T) { 136 | return reduce(keys(O), (v: T[K], k: K) => concat(v, typeof k === 'string' && isEnumerable(O, k) ? [O[k]] : []), []) 137 | } 138 | } 139 | 140 | if (!Object.entries) { 141 | Object.entries = function entries(O: T) { 142 | return reduce(keys(O), (e: Array<[K, T]>, k: K) => concat(e, typeof k === 'string' && isEnumerable(O, k) ? [[k, O[k]]] : []), []) 143 | } 144 | } 145 | ``` 146 | 147 | ## Authors 148 | 149 | - [Stuart Schechter](https://github.com/UppaJung) 150 | - [Junyoung Choi](https://github.com/rokt33r) : Maintainer 151 | - [Joseph Stein](https://github.com/josephstein) 152 | 153 | ## License & Copyright 154 | 155 | Licensed under MIT 156 | Copyright 2017 Revisolution 157 | -------------------------------------------------------------------------------- /packages/trackable/src/specs/record.spec.ts: -------------------------------------------------------------------------------- 1 | import { 2 | TrackableRecord, 3 | TrackableMap, 4 | } from '../lib' 5 | 6 | describe('TrackableRecord', () => { 7 | const FamilyRecord = TrackableRecord({ 8 | father: '', 9 | }) 10 | const UserRecord = TrackableRecord({ 11 | name: '', 12 | family: FamilyRecord(), 13 | map: new TrackableMap(), 14 | }) 15 | describe('constructor', () => { 16 | it('returns trackable record', () => { 17 | const user = UserRecord({ 18 | name: 'yolo', 19 | }) 20 | 21 | expect(user.$trackable).toBeDefined() 22 | expect(user.$trackable.isChanged).toBe(false) 23 | expect(user.name).toBe('yolo') 24 | }) 25 | }) 26 | 27 | describe('set', () => { 28 | it('sets data and is marked as changed', () => { 29 | const user = UserRecord({ 30 | name: 'yolo', 31 | }) 32 | 33 | user.name = 'test' 34 | 35 | expect(user.$trackable.isChanged).toBe(true) 36 | expect(user.name).toBe('test') 37 | }) 38 | 39 | it('marks as changed when child trackable map changed', () => { 40 | const user = UserRecord({ 41 | name: 'yolo', 42 | map: new TrackableMap({ 43 | a: 'a', 44 | }), 45 | }) 46 | 47 | user.map.set('a', 'b') 48 | 49 | expect(user.map.$trackable.isChanged).toBe(true) 50 | expect(user.map.get('a')).toBe('b') 51 | expect(user.$trackable.isChanged).toBe(true) 52 | }) 53 | 54 | it('marks as changed when child trackable record changed', () => { 55 | const user = UserRecord({ 56 | name: 'yolo', 57 | family: FamilyRecord({ 58 | father: 'Anakin Skywalker', 59 | }), 60 | }) 61 | 62 | user.family.father = 'Darth Vader' 63 | 64 | expect(user.family.$trackable.isChanged).toBe(true) 65 | expect(user.family.father).toBe('Darth Vader') 66 | expect(user.$trackable.isChanged).toBe(true) 67 | }) 68 | 69 | describe('cloned', () => { 70 | it('sets data and is marked as changed', () => { 71 | const user = UserRecord({ 72 | name: 'yolo', 73 | }) 74 | 75 | const newUser = user.clone() 76 | 77 | newUser.name = 'test' 78 | expect(newUser.$trackable.isChanged).toBe(true) 79 | expect(newUser.name).toBe('test') 80 | expect(user.$trackable.isChanged).toBe(false) 81 | expect(user.name).toBe('yolo') 82 | }) 83 | }) 84 | }) 85 | 86 | describe('update', () => { 87 | const user = UserRecord({ 88 | name: 'yolo', 89 | }) 90 | 91 | user.update('name', (name) => name + 'yolo') 92 | 93 | expect(user.$trackable.isChanged).toBe(true) 94 | expect(user.name).toBe('yoloyolo') 95 | }) 96 | 97 | describe('delete', () => { 98 | const user = UserRecord({ 99 | name: 'yolo', 100 | }) 101 | 102 | user.delete('name') 103 | 104 | expect(user.$trackable.isChanged).toBe(true) 105 | expect(user.name).toBeUndefined() 106 | }) 107 | 108 | describe('merge', () => { 109 | it('merges with partial object', () => { 110 | const user = UserRecord({ 111 | name: 'yolo', 112 | }) 113 | const newFamily = FamilyRecord({ 114 | father: 'Darth Vader', 115 | }) 116 | 117 | user.merge({ 118 | name: 'yoloyolo', 119 | family: newFamily, 120 | }) 121 | 122 | expect(user.$trackable.isChanged).toBe(true) 123 | expect(user.name).toBe('yoloyolo') 124 | expect(user.family).toBe(newFamily) 125 | }) 126 | 127 | it('merges with partial entry iterator', () => { 128 | const user = UserRecord({ 129 | name: 'yolo', 130 | }) 131 | const newFamily = FamilyRecord({ 132 | father: 'Darth Vader', 133 | }) 134 | 135 | user.merge([ 136 | ['name', 'yoloyolo'], 137 | ['family', newFamily], 138 | ]) 139 | 140 | expect(user.$trackable.isChanged).toBe(true) 141 | expect(user.name).toBe('yoloyolo') 142 | expect(user.family).toBe(newFamily) 143 | }) 144 | }) 145 | 146 | describe('clone', () => { 147 | it('clones nested record too', () => { 148 | const familyRecord = FamilyRecord({ 149 | father: 'Anakin Skywalker', 150 | }) 151 | const user = UserRecord({ 152 | name: 'yolo', 153 | family: familyRecord, 154 | }) 155 | user.family.father = 'Darth Vader' 156 | 157 | const newUser = user.clone() 158 | 159 | expect(newUser).not.toBe(user) 160 | expect(newUser.$trackable.isChanged).toBe(false) 161 | expect(newUser.family).not.toBe(familyRecord) 162 | expect(newUser.family.$trackable.isChanged).toBe(false) 163 | expect(newUser.family.father).toBe('Darth Vader') 164 | }) 165 | }) 166 | 167 | describe('toJS', () => { 168 | it('serializes record to pure object', () => { 169 | const user = UserRecord({ 170 | name: 'yolo', 171 | }) 172 | 173 | const serializedUser = user.toJS() 174 | 175 | expect(serializedUser.name).toBe('yolo') 176 | }) 177 | 178 | it('serializes nested record', () => { 179 | const user = UserRecord({ 180 | name: 'yolo', 181 | family: FamilyRecord({ 182 | father: 'Anakin Skywalker', 183 | }), 184 | }) 185 | 186 | const serializedUser = user.toJS() 187 | 188 | expect(serializedUser.name).toBe('yolo') 189 | expect(serializedUser.family.father).toBe('Anakin Skywalker') 190 | }) 191 | }) 192 | }) 193 | -------------------------------------------------------------------------------- /packages/mapped-reducer/src/specs/MappedPipeReducer.spec.ts: -------------------------------------------------------------------------------- 1 | import { createStore } from 'redux' 2 | import { 3 | MappedPipeReducer, 4 | Reducer, 5 | } from '../lib' 6 | 7 | describe('MappedPipeReducer', () => { 8 | describe('set', () => { 9 | it('sets a reducer', () => { 10 | // Given 11 | const reducer = new MappedPipeReducer() 12 | const ActionType = 'random action' 13 | const subReducer = (state: S) => state 14 | 15 | // When 16 | reducer 17 | .set(ActionType, subReducer) 18 | 19 | // Then 20 | expect(reducer.get(ActionType)).toEqual([subReducer]) 21 | }) 22 | 23 | it('sets reducers', () => { 24 | // Given 25 | const reducer = new MappedPipeReducer() 26 | const ActionType = 'random action' 27 | const subReducer = (state: S) => state 28 | const subReducer2 = (state: S) => state 29 | 30 | // When 31 | reducer 32 | .set(ActionType, [subReducer, subReducer2]) 33 | 34 | // Then 35 | expect(reducer.get(ActionType)).toEqual([subReducer, subReducer2]) 36 | }) 37 | 38 | it('replace reducer', () => { 39 | // Given 40 | const reducer = new MappedPipeReducer() 41 | const ActionType = 'random action' 42 | const subReducer = (state: S) => state 43 | const subReducer2 = (state: S) => state 44 | reducer 45 | .set(ActionType, subReducer) 46 | 47 | // When 48 | reducer 49 | .set(ActionType, subReducer2) 50 | 51 | // Then 52 | expect(reducer.get(ActionType)).toEqual([subReducer2]) 53 | }) 54 | }) 55 | 56 | describe('prepend', () => { 57 | it('prepend a reducer', () => { 58 | // Given 59 | const reducer = new MappedPipeReducer() 60 | const ActionType = 'random action' 61 | const subReducer = (state: S) => state 62 | const subReducer2 = (state: S) => state 63 | reducer 64 | .set(ActionType, subReducer) 65 | 66 | // When 67 | reducer 68 | .prepend(ActionType, subReducer2) 69 | 70 | // Then 71 | expect(reducer.get(ActionType)).toEqual([subReducer2, subReducer]) 72 | }) 73 | 74 | it('prepend reducers', () => { 75 | // Given 76 | const reducer = new MappedPipeReducer() 77 | const ActionType = 'random action' 78 | const subReducer = (state: S) => state 79 | const subReducer2 = (state: S) => state 80 | const subReducer3 = (state: S) => state 81 | reducer 82 | .set(ActionType, subReducer) 83 | 84 | // When 85 | reducer 86 | .prepend(ActionType, [subReducer2, subReducer3]) 87 | 88 | // Then 89 | expect(reducer.get(ActionType)).toEqual([subReducer2, subReducer3, subReducer]) 90 | }) 91 | }) 92 | 93 | describe('append', () => { 94 | it('append a reducer', () => { 95 | // Given 96 | const reducer = new MappedPipeReducer() 97 | const ActionType = 'random action' 98 | const subReducer = (state: S) => state 99 | const subReducer2 = (state: S) => state 100 | reducer 101 | .set(ActionType, subReducer) 102 | 103 | // When 104 | reducer 105 | .append(ActionType, subReducer2) 106 | 107 | // Then 108 | expect(reducer.get(ActionType)).toEqual([subReducer, subReducer2]) 109 | }) 110 | 111 | it('append reducers', () => { 112 | // Given 113 | const reducer = new MappedPipeReducer() 114 | const ActionType = 'random action' 115 | const subReducer = (state: S) => state 116 | const subReducer2 = (state: S) => state 117 | const subReducer3 = (state: S) => state 118 | reducer 119 | .set(ActionType, subReducer) 120 | 121 | // When 122 | reducer 123 | .append(ActionType, [subReducer2, subReducer3]) 124 | 125 | // Then 126 | expect(reducer.get(ActionType)).toEqual([subReducer, subReducer2, subReducer3]) 127 | }) 128 | }) 129 | 130 | describe('delete', () => { 131 | it('deletes reducer', () => { 132 | // Given 133 | const reducer = new MappedPipeReducer() 134 | const ActionType = 'random action' 135 | const subReducer = (state: S) => state 136 | reducer 137 | .set(ActionType, subReducer) 138 | 139 | // When 140 | reducer 141 | .delete(ActionType) 142 | 143 | // Then 144 | expect(reducer.get(ActionType)).toBeUndefined() 145 | }) 146 | }) 147 | 148 | describe('reduce', () => { 149 | it('reduces', () => { 150 | // Given 151 | interface State { 152 | count: 0, 153 | } 154 | const initialState: State = { 155 | count: 0, 156 | } 157 | const reducer = new MappedPipeReducer() 158 | const ActionType = 'random action' 159 | const setReducer = (state: State, action: { 160 | type: typeof ActionType 161 | payload: number 162 | }) => ({ 163 | ...state, 164 | count: action.payload, 165 | } as State) 166 | const multiflyReducer = (state: State) => ({ 167 | ...state, 168 | count: state.count * 2, 169 | } as State) 170 | reducer 171 | .set(ActionType, [setReducer, multiflyReducer]) 172 | 173 | // When 174 | const newState = reducer.reduce(initialState, { 175 | type: ActionType, 176 | payload: 1, 177 | } as Redux.Action) 178 | 179 | // Then 180 | // Set count to 1 and multify by 2 = 2 181 | expect(newState.count).toBe(2) 182 | }) 183 | }) 184 | }) 185 | -------------------------------------------------------------------------------- /packages/mapped-reducer/readme.md: -------------------------------------------------------------------------------- 1 | # MappedReducer - Typed Redux Kit 2 | 3 | An efficient reducer exploiting ES6 Map for better lookup! 4 | 5 | ## Install 6 | 7 | ```sh 8 | npm i typed-redux-kit.mapped-reducer 9 | 10 | # Or install typed-redux-kit 11 | npm i typed-redux-kit 12 | ``` 13 | 14 | ## Examples 15 | 16 | ```ts 17 | import { createStore } from 'redux' 18 | import { MappedReducer } from 'typed-redux-kit.mapped-reducer' 19 | import { 20 | PureAction, 21 | PayloadAction, 22 | } from 'typed-redux-kit.base' 23 | 24 | enum ActionTypes { 25 | Plus = 'test_Plus', 26 | Set = 'test_Set', 27 | } 28 | 29 | namespace Actions { 30 | export interface Plus extends PureAction {} 31 | 32 | export interface Set extends PayloadAction {} 35 | } 36 | 37 | interface State { 38 | count: number 39 | } 40 | 41 | const plusReducer = (state: State, action: Actions.PlusAction) => ({ 42 | ...state, 43 | count: state.count + 1, 44 | }) 45 | 46 | const setReducer = (state: State, action: Actions.SetAction) => ({ 47 | ...state, 48 | ...action.payload, 49 | }) 50 | 51 | const combinedReducer = new MappedReducer({ 52 | initialState: { 53 | count: 0, 54 | }, 55 | }) 56 | 57 | combinedReducer 58 | .set(ActionTypes.Plus, plusReducer) 59 | .set(ActionTypes.Set, setReducer) 60 | 61 | const store = createStore(combinedReducer.reduce) 62 | store.dispatch({ 63 | type: ActionTypes.Plus, 64 | } as Actions.Plus) 65 | ``` 66 | 67 | If you want to set multiple reducers for one action, Try `MappedPipeReducer`. 68 | 69 | ```ts 70 | import { MappedPipeReducer } from 'typed-redux-kit.mapped-reducer' 71 | 72 | const combinedReducer = new MappedPipeReducer({ 73 | initialState: { 74 | count: 0, 75 | }, 76 | }) 77 | 78 | combinedReducer 79 | .set(ActionTypes.Plus, plusReducer) 80 | .set(ActionTypes.Set, setReducer) 81 | .set([ 82 | ActionTypes.Plus, 83 | ActionTypes.Set, 84 | ], anotherReducer) 85 | ``` 86 | 87 | Now, the both actions will be passed to `anotherReducer` 88 | 89 | And for more convinence, **it accepts string enum**! 90 | 91 | ```ts 92 | combinedReducer 93 | .set(ActionTypes.Plus, plusReducer) 94 | .set(ActionTypes.Set, setReducer) 95 | .set(ActionTypes, anotherReducer) 96 | ``` 97 | 98 | ## Why is this good? 99 | 100 | `combinedReducer` will pass all actions to every one of its subreducers. When you build a huge app, you probably have lots of reducers, split by domain. Sometimes you want to share actions and this was developed to solve that problem. Even with reducers split by domain, actions can be passed to multiple reducers. 101 | 102 | Also, if you have lots of action types, a lookup with Map is more efficient than one with a `switch` statement. This is because Map keeps a key as a hash. 103 | 104 | ## APIs 105 | 106 | ### `MappedReducer({initialState?: State})` 107 | 108 | Basic mapped reducer. It takes only one option, `initialState`. 109 | 110 | #### `#set(actionTypes: Action | Action[], reducer: Reducer): this` 111 | 112 | Set a subreducer for the given action type(s). 113 | 114 | It takes a single action type and array/string enum of action types. 115 | 116 | > You can set only one subreducer for a single action type. If you want to set more than two, use `MappedPipeReducer`. 117 | 118 | #### `#delete(actionTypes: Action | Action[]): this` 119 | 120 | Delete a subreducer for the given action type(s). 121 | 122 | #### `#get(actionType): Reducer` 123 | 124 | Get a subreducer for the given action type(s). 125 | 126 | #### `#reduce(state: State, action: Action): State` 127 | 128 | This is the actual reducing method. You should pass this to `createStore` or `combineReducers`. 129 | 130 | ```ts 131 | import { 132 | createStore, 133 | combineReducers, 134 | } from 'redux' 135 | 136 | // To store 137 | const store = createStore(reducer.reduce) 138 | 139 | // To combine reducer 140 | const masterReducer = combineReducers({ 141 | slave1: reducer.reduce, 142 | slave22: reducer2.reduce, 143 | }) 144 | ``` 145 | 146 | ### `MappedPipeReducer({initialState?: State})` 147 | 148 | MappedPipeReducer can have multiple subreducers for a given action type(s). 149 | 150 | #### `#unshift(actionTypes: Action | Action[], reducerOrReducers: Reducer | Reducer[])` 151 | 152 | Prepends a subreducer to a subreducer array of a given action type(s). 153 | 154 | ### `#prepend(actionTypes: Action | Action[], reducerOrReducers: Reducer | Reducer[])` 155 | 156 | Alias of `#unshift` 157 | 158 | #### `#push(actionTypes: Action | Action[], reducerOrReducers: Reducer | Reducer[])` 159 | 160 | Appends a subreducer to a subreducer array of a given action type(s). 161 | 162 | ### `#append(actionTypes: Action | Action[], reducerOrReducers: Reducer | Reducer[])` 163 | 164 | Alias of `#push` 165 | 166 | #### `#set(actionTypes: Action | Action[], reducerOrReducers: Reducer | Reducer[])` 167 | 168 | Replaces a subreducer array of a given action type(s). 169 | 170 | #### `#delete(actionTypes: Action | Action[]): this` 171 | 172 | Deletes all subreducers registered of a given action type(s). 173 | 174 | #### `#get(actionType: Action)` 175 | 176 | Almost the same as `MappedReducer#get`, but returns an array of reducers. 177 | 178 | #### `#reduce(state: State, action: Action)` 179 | 180 | Same as `MappedReducer#reduce`. 181 | 182 | ## Polyfill 183 | 184 | MappedReducer is using Object.values. If you need to support legacy Node.js or browser, use the polyfill below or transpile it again with babel 185 | 186 | ```ts 187 | // Polyfill 188 | const reduce = Function.bind.call(Function.call, Array.prototype.reduce) 189 | const isEnumerable = Function.bind.call(Function.call, Object.prototype.propertyIsEnumerable) 190 | const concat = Function.bind.call(Function.call, Array.prototype.concat) 191 | const keys = Reflect.ownKeys 192 | 193 | if (!Object.values) { 194 | Object.values = function values(O: T) { 195 | return reduce(keys(O), (v: T[K], k: K) => concat(v, typeof k === 'string' && isEnumerable(O, k) ? [O[k]] : []), []) 196 | } 197 | } 198 | ``` 199 | 200 | ## Authors 201 | 202 | - [Stuart Schechter](https://github.com/UppaJung) 203 | - [Junyoung Choi](https://github.com/rokt33r) : Maintainer 204 | - [Joseph Stein](https://github.com/josephstein) 205 | 206 | ## License & Copyright 207 | 208 | Licensed under MIT 209 | Copyright 2017 Revisolution 210 | -------------------------------------------------------------------------------- /packages/trackable/src/specs/array.spec.ts: -------------------------------------------------------------------------------- 1 | import { TrackableArray } from '../lib' 2 | 3 | describe('TrackableArray', () => { 4 | describe('constructor', () => { 5 | it('converts from tangoay', () => { 6 | const tango = TrackableArray([1]) 7 | 8 | expect(tango[0]).toBe(1) 9 | expect(tango.$trackable.isChanged).toBe(false) 10 | }) 11 | }) 12 | 13 | describe('length', () => { 14 | it('presents length of array', () => { 15 | const tango = TrackableArray([1]) 16 | 17 | expect(tango.length).toBe(1) 18 | }) 19 | }) 20 | 21 | describe('set', () => { 22 | it('updates data and mark itself as changed', () => { 23 | const tango = TrackableArray([1]) 24 | 25 | tango[0] = 2 26 | 27 | expect(tango[0]).toBe(2) 28 | expect(tango.$trackable.isChanged).toBe(true) 29 | }) 30 | 31 | it('marks parent changed', () => { 32 | const childTango = TrackableArray([1]) 33 | const tango = TrackableArray([ 34 | childTango, 35 | ]) 36 | 37 | childTango[0] = 2 38 | 39 | expect(tango.$trackable.isChanged).toBe(true) 40 | }) 41 | }) 42 | 43 | describe('push', () => { 44 | it('pushes value', () => { 45 | const tango = TrackableArray([1]) 46 | 47 | const length = tango.push(2) 48 | 49 | expect(length).toBe(2) 50 | expect(tango[1]).toBe(2) 51 | expect(tango.$trackable.isChanged).toBe(true) 52 | }) 53 | 54 | it('pushes multiple values', () => { 55 | const tango = TrackableArray([1]) 56 | 57 | const length = tango.push(2, 3) 58 | 59 | expect(length).toBe(3) 60 | expect(tango[1]).toBe(2) 61 | expect(tango[2]).toBe(3) 62 | expect(tango.$trackable.isChanged).toBe(true) 63 | }) 64 | 65 | it('marks parent changed', () => { 66 | const childTango = TrackableArray([1]) 67 | const tango = TrackableArray([ 68 | childTango, 69 | ]) 70 | 71 | childTango.push(2) 72 | 73 | expect(tango.$trackable.isChanged).toBe(true) 74 | }) 75 | }) 76 | 77 | describe('unshift', () => { 78 | it('unshifts value', () => { 79 | const tango = TrackableArray([1]) 80 | 81 | const length = tango.unshift(0) 82 | 83 | expect(length).toBe(2) 84 | expect(tango[0]).toBe(0) 85 | expect(tango.$trackable.isChanged).toBe(true) 86 | }) 87 | 88 | it('unshifts multiple values', () => { 89 | const tango = TrackableArray([1]) 90 | 91 | const length = tango.unshift(-1, 0) 92 | 93 | expect(length).toBe(3) 94 | expect(tango[0]).toBe(-1) 95 | expect(tango[1]).toBe(0) 96 | expect(tango.$trackable.isChanged).toBe(true) 97 | }) 98 | 99 | it('marks parent changed', () => { 100 | const childTango = TrackableArray([1]) 101 | const tango = TrackableArray([ 102 | childTango, 103 | ]) 104 | 105 | childTango.unshift(0) 106 | 107 | expect(tango.$trackable.isChanged).toBe(true) 108 | }) 109 | }) 110 | 111 | describe('pop', () => { 112 | it('pops a value', () => { 113 | const tango = TrackableArray([1, 2]) 114 | 115 | const value = tango.pop() 116 | 117 | expect(value).toBe(2) 118 | expect(tango[0]).toBe(1) 119 | expect(tango.$trackable.isChanged).toBe(true) 120 | }) 121 | 122 | it('marks parent changed', () => { 123 | const childTango = TrackableArray([1]) 124 | const tango = TrackableArray([ 125 | childTango, 126 | ]) 127 | 128 | childTango.pop() 129 | 130 | expect(tango.$trackable.isChanged).toBe(true) 131 | }) 132 | }) 133 | 134 | describe('shift', () => { 135 | it('shifts a value', () => { 136 | const tango = TrackableArray([1, 2]) 137 | 138 | const value = tango.shift() 139 | 140 | expect(value).toBe(1) 141 | expect(tango[0]).toBe(2) 142 | expect(tango.$trackable.isChanged).toBe(true) 143 | }) 144 | 145 | it('marks parent changed', () => { 146 | const childTango = TrackableArray([1]) 147 | const tango = TrackableArray([ 148 | childTango, 149 | ]) 150 | 151 | childTango.shift() 152 | 153 | expect(tango.$trackable.isChanged).toBe(true) 154 | }) 155 | }) 156 | 157 | describe('splice', () => { 158 | it('discards items', () => { 159 | const tango = TrackableArray([1, 2, 3]) 160 | 161 | const deleted = tango.splice(1, 1) 162 | 163 | expect(deleted).toEqual([2]) 164 | expect(tango.$trackable.isChanged).toBe(true) 165 | expect(tango.slice()).toEqual([1, 3]) 166 | }) 167 | 168 | it('inserts items', () => { 169 | const tango = TrackableArray([1, 2, 3]) 170 | 171 | const deleted = tango.splice(1, 0, 1.25, 1.5, 1.75) 172 | 173 | expect(deleted).toEqual([]) 174 | expect(tango.$trackable.isChanged).toBe(true) 175 | expect(tango.slice()).toEqual([1, 1.25, 1.5, 1.75, 2, 3]) 176 | }) 177 | 178 | it('marks parent changed', () => { 179 | const childTango = TrackableArray([1]) 180 | const tango = TrackableArray([ 181 | childTango, 182 | ]) 183 | 184 | childTango.splice(0, 1) 185 | 186 | expect(tango.$trackable.isChanged).toBe(true) 187 | }) 188 | }) 189 | 190 | describe('copyWithin', () => { 191 | it('fills all items with a value', () => { 192 | const tango = TrackableArray([1, 2, 3]) 193 | 194 | tango.copyWithin(0, 1) 195 | 196 | expect(tango.$trackable.isChanged).toBe(true) 197 | expect(tango.slice()).toEqual([2, 3, 3]) 198 | }) 199 | }) 200 | 201 | describe('fill', () => { 202 | it('fills all items with a value', () => { 203 | const tango = TrackableArray([1, 2, 3]) 204 | 205 | tango.fill(1) 206 | 207 | expect(tango.$trackable.isChanged).toBe(true) 208 | expect(tango.slice()).toEqual([1, 1, 1]) 209 | }) 210 | it('sets parent of a trackable value', () => { 211 | const childTango = TrackableArray([1]) 212 | const tango = TrackableArray([ 213 | childTango, 214 | ]) 215 | const newChild = TrackableArray([2]) 216 | 217 | tango.fill(newChild) 218 | 219 | expect(tango.$trackable.isChanged).toBe(true) 220 | expect(newChild.$trackable.parent).toBe(tango) 221 | }) 222 | }) 223 | 224 | describe('reverse', () => { 225 | it('reverses items', () => { 226 | const tango = TrackableArray([1, 2, 3]) 227 | 228 | tango.reverse() 229 | 230 | expect(tango.$trackable.isChanged).toBe(true) 231 | expect(tango.slice()).toEqual([3, 2, 1]) 232 | }) 233 | }) 234 | 235 | describe('slice', () => { 236 | it('returns a clean array', () => { 237 | const tango = TrackableArray([1]) 238 | 239 | const newTango = tango.slice() 240 | 241 | expect(Array.isArray(newTango)).toBe(true) 242 | expect(newTango[0]).toBe(1) 243 | }) 244 | }) 245 | 246 | describe('sort', () => { 247 | it('reverses items', () => { 248 | const tango = TrackableArray([3, 2, 1]) 249 | 250 | tango.sort() 251 | 252 | expect(tango.$trackable.isChanged).toBe(true) 253 | expect(tango.slice()).toEqual([1, 2, 3]) 254 | }) 255 | }) 256 | 257 | describe('clone', () => { 258 | it('returns a clean tangoay', () => { 259 | const tango = TrackableArray([1]) 260 | tango[0] = 2 261 | 262 | const newTango = tango.clone() 263 | 264 | expect(newTango[0]).toBe(2) 265 | expect(newTango.$trackable.isChanged).toBe(false) 266 | }) 267 | }) 268 | 269 | describe('reserveArrayBuffer', () => { 270 | it('reserves more buffer on demand', () => { 271 | const hugeArray = Array.from({length: 1001}).map((v, k) => k) 272 | const tango = TrackableArray(hugeArray) 273 | 274 | expect(tango[1000]).toBe(1000) 275 | }) 276 | }) 277 | }) 278 | -------------------------------------------------------------------------------- /packages/trackable/src/lib/array.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Trackable, 3 | isTrackable, 4 | initializeValue, 5 | setParentIfTrackable, 6 | } from './trackable' 7 | import { 8 | getEntries 9 | } from './util' 10 | 11 | let OBSERVABLE_ARRAY_BUFFER_SIZE = 0 12 | 13 | export type TrackableArray = V[] & TrackableArrayClass 14 | export const TrackableArray = (iterable?: Iterable): TrackableArray => { 15 | const record = new TrackableArrayClass(iterable) 16 | return record as TrackableArray 17 | } 18 | 19 | export class TrackableArrayClass extends Trackable> { 20 | private internalArray: V[] 21 | 22 | public get length (): number { 23 | return this.internalArray.length 24 | } 25 | 26 | constructor (iterable?: Iterable) { 27 | super() 28 | if (iterable && iterable[Symbol.iterator]) { 29 | this.internalArray = [] as V[] 30 | let index = 0 31 | for (let value of iterable) { 32 | value = initializeValue(value, this) 33 | this.internalArray.push(value) 34 | index++ 35 | } 36 | this.reserveArrayBufferOnDemand() 37 | } else { 38 | this.internalArray = [] 39 | } 40 | } 41 | 42 | public [Symbol.iterator] () { 43 | const entries = getEntries(this.internalArray) 44 | return entries[Symbol.iterator]() 45 | } 46 | 47 | /** 48 | * Modifier 49 | */ 50 | 51 | public set (index: number, newValue: V) { 52 | const previousValue = this.internalArray[index] 53 | if (previousValue !== newValue) { 54 | this.markAsChanged() 55 | this.internalArray[index] = newValue 56 | setParentIfTrackable(newValue, this) 57 | this.reserveArrayBufferOnDemand() 58 | } 59 | return this 60 | } 61 | 62 | public push (...newValues: V[]) { 63 | if (newValues.length > 0) { 64 | this.internalArray.push(...newValues) 65 | this.markAsChanged() 66 | for (const newValue of newValues) { 67 | setParentIfTrackable(newValue, this) 68 | } 69 | this.reserveArrayBufferOnDemand() 70 | } 71 | return this.internalArray.length 72 | } 73 | 74 | public pop () { 75 | let value: V 76 | if (this.internalArray.length > 0) { 77 | value = this.internalArray.pop() 78 | this.markAsChanged() 79 | this.reserveArrayBufferOnDemand() 80 | } 81 | return value 82 | } 83 | 84 | public unshift (...newValues: V[]) { 85 | if (newValues.length > 0) { 86 | this.internalArray.unshift(...newValues) 87 | this.markAsChanged() 88 | for (const newValue of newValues) { 89 | setParentIfTrackable(newValue, this) 90 | } 91 | this.reserveArrayBufferOnDemand() 92 | } 93 | return this.internalArray.length 94 | } 95 | 96 | public shift () { 97 | let value: V 98 | if (this.internalArray.length > 0) { 99 | value = this.internalArray.shift() 100 | this.markAsChanged() 101 | this.reserveArrayBufferOnDemand() 102 | } 103 | return value 104 | } 105 | 106 | public splice (start: number, deleteCount?: number, ...items: V[]) { 107 | for (const item of items) { 108 | setParentIfTrackable(item, this) 109 | } 110 | const deleted = this.internalArray.splice(start, deleteCount, ...items) 111 | if (deleteCount > 0 || items.length > 0) { 112 | this.markAsChanged() 113 | this.reserveArrayBufferOnDemand() 114 | } 115 | return deleted 116 | } 117 | 118 | public copyWithin (target: number, start?: number, end?: number) { 119 | if (target !== 0 || start !== 0) { 120 | this.internalArray.copyWithin(target, start, end) 121 | this.markAsChanged() 122 | } 123 | return this 124 | } 125 | 126 | public fill (value: V, start?: number, end?: number) { 127 | if (this.internalArray.length > 0) { 128 | setParentIfTrackable(value, this) 129 | this.internalArray.fill(value, start, end) 130 | this.markAsChanged() 131 | } 132 | return this 133 | } 134 | 135 | public reverse () { 136 | if (this.internalArray.length > 0) { 137 | this.internalArray.reverse() 138 | this.markAsChanged() 139 | } 140 | return this 141 | } 142 | 143 | public sort (compare?: (a: V, b: V) => number) { 144 | if (this.internalArray.length > 0) { 145 | this.internalArray.sort(compare) 146 | this.markAsChanged() 147 | } 148 | return this 149 | } 150 | 151 | /** 152 | * Selectors 153 | */ 154 | 155 | public get (index: number, defaultValue?: V): V { 156 | if (this.internalArray[index] === undefined) return defaultValue 157 | return this.internalArray[index] 158 | } 159 | 160 | public slice (start?: number, end?: number) { 161 | return this.internalArray.slice(start, end) 162 | } 163 | 164 | public concat (...arrays: Array>) { 165 | return this.internalArray.concat(...arrays.map((array) => array.$trackable 166 | ? array.slice() 167 | : array, 168 | )) 169 | } 170 | 171 | public entries (): IterableIterator<[number, V]> { 172 | return this.internalArray.entries() 173 | } 174 | 175 | public every (callback: (value: V, index: number, array: V[]) => boolean, thisArg?: any): boolean { 176 | return this.internalArray.every(callback, thisArg) 177 | } 178 | 179 | public filter (callback: (value: V, index: number, array: V[]) => any, thisArg?: any): V[] { 180 | return this.internalArray.filter(callback, thisArg) 181 | } 182 | 183 | public find (predicate: (this: void, value: V, index: number, obj: Array) => boolean): V | undefined 184 | public find (predicate: (this: Z, value: V, index: number, obj: Array) => boolean, thisArg?: Z): V | undefined { 185 | return this.internalArray.find(predicate, thisArg) 186 | } 187 | 188 | public findIndex (predicate: (this: void, value: V, index: number, obj: Array) => boolean): number 189 | public findIndex (predicate: (this: Z, value: V, index: number, obj: Array) => boolean, thisArg?: Z): number { 190 | return this.internalArray.findIndex(predicate, thisArg) 191 | } 192 | 193 | public includes (searchElement: V, fromIndex?: number): boolean { 194 | return this.internalArray.includes(searchElement, fromIndex) 195 | } 196 | 197 | public indexOf (searchElement: V, fromIndex?: number): number { 198 | return this.internalArray.indexOf(searchElement, fromIndex) 199 | } 200 | 201 | public join (seperator?: string): string { 202 | return this.internalArray.join(seperator) 203 | } 204 | 205 | public keys (): IterableIterator { 206 | return this.internalArray.keys() 207 | } 208 | 209 | public lastIndexOf (searchElement: V, fromIndex?: number): number { 210 | return this.internalArray.lastIndexOf(searchElement, fromIndex) 211 | } 212 | 213 | public map (callback: (value: V, index: number, array: V[]) => U, thisArg?: any): U[] { 214 | return this.internalArray.map(callback, thisArg) 215 | } 216 | 217 | public reduce (callback: (previousValue: U, currentValue: V, currentIndex: number, array: V[]) => U, initialValue?: U): U { 218 | return this.internalArray.reduce(callback, initialValue) 219 | } 220 | 221 | public reduceRight (callback: (previousValue: U, currentValue: V, currentIndex: number, array: V[]) => U, initialValue?: U): U { 222 | return this.internalArray.reduceRight(callback, initialValue) 223 | } 224 | 225 | public some (callback: (value: V, index: number, array: V[]) => boolean, thisArg?: any): boolean { 226 | return this.internalArray.some(callback, thisArg) 227 | } 228 | 229 | public toLocaleString (): string { 230 | return this.internalArray.toLocaleString() 231 | } 232 | 233 | public toString (): string { 234 | return this.internalArray.toString() 235 | } 236 | 237 | public values (): IterableIterator { 238 | return this.internalArray.values() 239 | } 240 | 241 | /** 242 | * Trackable Specifics 243 | */ 244 | 245 | public onChildChange (child: any) { 246 | this.markAsChanged() 247 | } 248 | 249 | public clone () { 250 | return TrackableArray(this.internalArray) 251 | } 252 | 253 | public toJS (shallow: boolean = false) { 254 | const pureArray: V[] = [] 255 | for (let [index, value] of this) { 256 | value = !shallow && isTrackable(value) 257 | ? (value as any as Trackable).toJS() 258 | : value 259 | pureArray.push(value) 260 | } 261 | 262 | return pureArray 263 | } 264 | 265 | private reserveArrayBufferOnDemand () { 266 | if (this.internalArray.length > OBSERVABLE_ARRAY_BUFFER_SIZE) { 267 | reserveArrayBuffer(this.internalArray.length) 268 | } 269 | } 270 | } 271 | 272 | function createArrayBufferItem(index: number) { 273 | Object.defineProperty(TrackableArrayClass.prototype, '' + index, { 274 | enumerable: false, 275 | configurable: false, 276 | get () { 277 | return this.get(index) 278 | }, 279 | set (value) { 280 | this.set(index, value) 281 | }, 282 | }) 283 | } 284 | 285 | function reserveArrayBuffer(max: number) { 286 | for (let index = OBSERVABLE_ARRAY_BUFFER_SIZE; index < max; index++) { 287 | createArrayBufferItem(index) 288 | } 289 | OBSERVABLE_ARRAY_BUFFER_SIZE = max 290 | } 291 | 292 | reserveArrayBuffer(1000) 293 | 294 | export default TrackableArray 295 | -------------------------------------------------------------------------------- /packages/trackable/src/specs/map.spec.ts: -------------------------------------------------------------------------------- 1 | import { TrackableMap } from '../lib' 2 | 3 | describe('TrackedMap', () => { 4 | describe('constructor', () => { 5 | it('constructs with object', () => { 6 | const tango = new TrackableMap({ 7 | a: 1, 8 | }) 9 | 10 | expect(tango.get('a')).toBe(1) 11 | }) 12 | 13 | it('constructs with entry array', () => { 14 | const tango = new TrackableMap([['a', 1]]) 15 | 16 | expect(tango.get('a')).toBe(1) 17 | }) 18 | 19 | it('constructs with entry iterable', () => { 20 | const tango = new TrackableMap(new Map().set('a', 1)) 21 | 22 | expect(tango.get('a')).toBe(1) 23 | }) 24 | 25 | it('set parent to children with tracked interface', () => { 26 | const childTango = new TrackableMap() 27 | const tango = new TrackableMap({ 28 | a: childTango, 29 | }) 30 | 31 | expect(childTango.$trackable.parent).toBe(tango) 32 | }) 33 | }) 34 | 35 | describe('size', () => { 36 | it('presents size of map', () => { 37 | const tango = new TrackableMap([['a', 1]]) 38 | 39 | expect(tango.size).toBe(1) 40 | }) 41 | }) 42 | 43 | describe('has', () => { 44 | it('check if map has a value for key', () => { 45 | const tango = new TrackableMap([['a', 1]]) 46 | 47 | expect(tango.has('a')).toBe(true) 48 | }) 49 | }) 50 | 51 | describe('get', () => { 52 | it('return a value for key', () => { 53 | const tango = new TrackableMap([['a', 1]]) 54 | 55 | expect(tango.get('a')).toBe(1) 56 | }) 57 | }) 58 | 59 | describe('set', () => { 60 | it('sets a new value', () => { 61 | const tango = new TrackableMap() 62 | 63 | tango.set('a', 1) 64 | 65 | expect(tango.get('a')).toBe(1) 66 | }) 67 | 68 | it('sets parent to a new value if the new value is trackable', () => { 69 | const childTango = new TrackableMap() 70 | const tango = new TrackableMap() 71 | 72 | tango.set('a', childTango) 73 | 74 | expect(childTango.$trackable.parent).toBe(tango) 75 | }) 76 | }) 77 | 78 | describe('$trackable.isChanged', () => { 79 | it('is not changed just after instantiate', () => { 80 | const tango = new TrackableMap() 81 | 82 | expect(tango.$trackable.isChanged).toBe(false) 83 | }) 84 | 85 | it('marks as changed itself after data set', () => { 86 | const tango = new TrackableMap() 87 | 88 | tango.set('a', 1) 89 | 90 | expect(tango.$trackable.isChanged).toBe(true) 91 | }) 92 | 93 | it('is marked as changed when its children changed', () => { 94 | const childTango = new TrackableMap({ 95 | b: 2, 96 | }) 97 | const tango = new TrackableMap({ 98 | a: childTango, 99 | }) 100 | 101 | childTango.set('b', 3) 102 | 103 | expect(childTango.get('b')).toBe(3) 104 | expect(childTango.$trackable.isChanged).toBe(true) 105 | expect(tango.$trackable.isChanged).toBe(true) 106 | }) 107 | }) 108 | 109 | describe('delete', () => { 110 | it('deletes a data by key', () => { 111 | const tango = new TrackableMap([['a', 1]]) 112 | 113 | tango.delete('a') 114 | 115 | expect(tango.$trackable.isChanged).toBe(true) 116 | expect(tango.get('a')).toBeUndefined() 117 | }) 118 | }) 119 | 120 | describe('update', () => { 121 | it('updates a data with mutator', () => { 122 | const tango = new TrackableMap([['a', 1]]) 123 | 124 | tango.update('a', (str) => str + str) 125 | 126 | expect(tango.$trackable.isChanged).toBe(true) 127 | expect(tango.get('a')).toBe(2) 128 | }) 129 | }) 130 | 131 | describe('merge', () => { 132 | it('merges with key-value object', () => { 133 | const tango = new TrackableMap([['a', 1]]) 134 | 135 | tango.merge({ 136 | a: 2, 137 | b: 3, 138 | }) 139 | 140 | expect(tango.$trackable.isChanged).toBe(true) 141 | expect(tango.get('a')).toBe(2) 142 | expect(tango.get('b')).toBe(3) 143 | }) 144 | 145 | it('merges with entry array', () => { 146 | const tango = new TrackableMap([['a', 1]]) 147 | 148 | tango.merge([ 149 | ['a', 2], 150 | ['b', 3], 151 | ]) 152 | 153 | expect(tango.$trackable.isChanged).toBe(true) 154 | expect(tango.get('a')).toBe(2) 155 | expect(tango.get('b')).toBe(3) 156 | }) 157 | 158 | it('merges with key-value object', () => { 159 | const tango = new TrackableMap([['a', 1]]) 160 | 161 | tango.merge(new Map([ 162 | ['a', 2], 163 | ['b', 3], 164 | ])) 165 | 166 | expect(tango.$trackable.isChanged).toBe(true) 167 | expect(tango.get('a')).toBe(2) 168 | expect(tango.get('b')).toBe(3) 169 | }) 170 | }) 171 | 172 | describe('clear', () => { 173 | it('clears all value', () => { 174 | const tango = new TrackableMap([['a', 1]]) 175 | 176 | tango.clear() 177 | 178 | expect(tango.$trackable.isChanged).toBe(true) 179 | expect(tango.get('a')).toBeUndefined() 180 | }) 181 | 182 | it('doesnt mark if nothing changed', () => { 183 | const tango = new TrackableMap([]) 184 | 185 | tango.clear() 186 | 187 | expect(tango.$trackable.isChanged).toBe(false) 188 | }) 189 | }) 190 | 191 | describe('entries', () => { 192 | it('returns iterator of entries, which is key/value array', () => { 193 | const tango = new TrackableMap([['a', 1], ['b', 2]]) 194 | 195 | const entries = tango.entries() 196 | 197 | expect(entries.next().value).toEqual(['a', 1]) 198 | expect(entries.next().value).toEqual(['b', 2]) 199 | }) 200 | }) 201 | 202 | describe('keys', () => { 203 | it('returns iterator of keys', () => { 204 | const tango = new TrackableMap([['a', 1], ['b', 2]]) 205 | 206 | const entries = tango.keys() 207 | 208 | expect(entries.next().value).toBe('a') 209 | expect(entries.next().value).toBe('b') 210 | }) 211 | }) 212 | 213 | describe('values', () => { 214 | it('returns iterator of values', () => { 215 | const tango = new TrackableMap([['a', 1], ['b', 2]]) 216 | 217 | const entries = tango.values() 218 | 219 | expect(entries.next().value).toBe(1) 220 | expect(entries.next().value).toBe(2) 221 | }) 222 | }) 223 | 224 | describe('map', () => { 225 | it('returns remapped map', () => { 226 | const tango = new TrackableMap([['a', 1], ['b', 2]]) 227 | 228 | const mappedArray = tango.map((value, key) => key + value) 229 | 230 | expect(mappedArray.get('a')).toBe('a1') 231 | expect(mappedArray.get('b')).toBe('b2') 232 | }) 233 | }) 234 | 235 | describe('mapToArray', () => { 236 | it('returns mapped array', () => { 237 | const tango = new TrackableMap([['a', 1], ['b', 2]]) 238 | 239 | const mappedArray = tango.mapToArray((value, key) => key + value) 240 | 241 | expect(mappedArray[0]).toBe('a1') 242 | expect(mappedArray[1]).toBe('b2') 243 | }) 244 | }) 245 | 246 | describe('filter', () => { 247 | it('returns filtered array', () => { 248 | const tango = new TrackableMap([['a', 1], ['b', 2]]) 249 | 250 | const mappedArray = tango.filter((value) => value === 1) 251 | 252 | expect(mappedArray.get('a')).toBe(1) 253 | expect(mappedArray.get('b')).toBeUndefined() 254 | }) 255 | }) 256 | 257 | describe('clone', () => { 258 | it('clones and return clean instance with same value', () => { 259 | const tango = new TrackableMap() 260 | tango.set('a', 1) 261 | 262 | const clonedTango = tango.clone() 263 | 264 | expect(clonedTango.get('a')).toBe(1) 265 | expect(clonedTango.$trackable.isChanged).toBe(false) 266 | }) 267 | 268 | it('clones and return clean instance with same value', () => { 269 | const childTango = new TrackableMap({ 270 | b: 2, 271 | }) 272 | const tango = new TrackableMap({ 273 | a: childTango, 274 | }) 275 | childTango.set('b', 3) 276 | 277 | const clonedTango = tango.clone() 278 | 279 | expect(clonedTango.$trackable.isChanged).toBe(false) 280 | const childOfClonedTango = clonedTango.get('a') 281 | expect(childOfClonedTango.$trackable.isChanged).toBe(false) 282 | expect(childOfClonedTango.get('b')).toBe(3) 283 | }) 284 | }) 285 | 286 | describe('toJS', () => { 287 | it('returns pure object', () => { 288 | const tango = new TrackableMap({ 289 | a: 1, 290 | }) 291 | 292 | expect(tango.toJS()).toEqual({ 293 | a: 1, 294 | }) 295 | }) 296 | 297 | it('resolves nested tracked too', () => { 298 | const childTango = new TrackableMap({ 299 | b: 2, 300 | }) 301 | const tango = new TrackableMap({ 302 | a: childTango, 303 | }) 304 | 305 | expect(tango.toJS()).toEqual({ 306 | a: { 307 | b: 2, 308 | }, 309 | }) 310 | }) 311 | 312 | it('resolves shallowly if got true', () => { 313 | const childTango = new TrackableMap({ 314 | b: 2, 315 | }) 316 | const tango = new TrackableMap({ 317 | a: childTango, 318 | }) 319 | 320 | expect(tango.toJS(true)).toEqual({ 321 | a: childTango, 322 | }) 323 | }) 324 | }) 325 | }) 326 | -------------------------------------------------------------------------------- /packages/trackable/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "typed-redux-kit.trackable", 3 | "version": "1.0.0-alpha", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@types/jest": { 8 | "version": "20.0.8", 9 | "resolved": "https://registry.npmjs.org/@types/jest/-/jest-20.0.8.tgz", 10 | "integrity": "sha512-+vFMPCwOffrTy685X9Kj+Iz83I56Q8j0JK6xvsm6TA5qxbtPUJZcXtJY05WMGlhCKp/9qbpRCwyOp6GkMuyuLg==", 11 | "dev": true 12 | }, 13 | "@types/redux": { 14 | "version": "3.6.31", 15 | "resolved": "https://registry.npmjs.org/@types/redux/-/redux-3.6.31.tgz", 16 | "integrity": "sha1-QOr6dXXbNrkSzgBZuF3pjCBbBwg=", 17 | "dev": true 18 | }, 19 | "abab": { 20 | "version": "1.0.3", 21 | "resolved": "https://registry.npmjs.org/abab/-/abab-1.0.3.tgz", 22 | "integrity": "sha1-uB3l9ydOxOdW15fNg08wNkJyTl0=", 23 | "dev": true 24 | }, 25 | "acorn": { 26 | "version": "4.0.13", 27 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", 28 | "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=", 29 | "dev": true 30 | }, 31 | "acorn-globals": { 32 | "version": "3.1.0", 33 | "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-3.1.0.tgz", 34 | "integrity": "sha1-/YJw9x+7SZawBPqIDuXUZXOnMb8=", 35 | "dev": true, 36 | "requires": { 37 | "acorn": "4.0.13" 38 | } 39 | }, 40 | "ajv": { 41 | "version": "4.11.8", 42 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", 43 | "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", 44 | "dev": true, 45 | "requires": { 46 | "co": "4.6.0", 47 | "json-stable-stringify": "1.0.1" 48 | } 49 | }, 50 | "align-text": { 51 | "version": "0.1.4", 52 | "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", 53 | "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", 54 | "dev": true, 55 | "requires": { 56 | "kind-of": "3.2.2", 57 | "longest": "1.0.1", 58 | "repeat-string": "1.6.1" 59 | } 60 | }, 61 | "amdefine": { 62 | "version": "1.0.1", 63 | "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", 64 | "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", 65 | "dev": true 66 | }, 67 | "ansi-escapes": { 68 | "version": "1.4.0", 69 | "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", 70 | "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=", 71 | "dev": true 72 | }, 73 | "ansi-regex": { 74 | "version": "2.1.1", 75 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", 76 | "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", 77 | "dev": true 78 | }, 79 | "ansi-styles": { 80 | "version": "2.2.1", 81 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", 82 | "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", 83 | "dev": true 84 | }, 85 | "anymatch": { 86 | "version": "1.3.2", 87 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", 88 | "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", 89 | "dev": true, 90 | "requires": { 91 | "micromatch": "2.3.11", 92 | "normalize-path": "2.1.1" 93 | } 94 | }, 95 | "append-transform": { 96 | "version": "0.4.0", 97 | "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-0.4.0.tgz", 98 | "integrity": "sha1-126/jKlNJ24keja61EpLdKthGZE=", 99 | "dev": true, 100 | "requires": { 101 | "default-require-extensions": "1.0.0" 102 | } 103 | }, 104 | "argparse": { 105 | "version": "1.0.9", 106 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", 107 | "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", 108 | "dev": true, 109 | "requires": { 110 | "sprintf-js": "1.0.3" 111 | } 112 | }, 113 | "arr-diff": { 114 | "version": "2.0.0", 115 | "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", 116 | "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", 117 | "dev": true, 118 | "requires": { 119 | "arr-flatten": "1.1.0" 120 | } 121 | }, 122 | "arr-flatten": { 123 | "version": "1.1.0", 124 | "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", 125 | "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", 126 | "dev": true 127 | }, 128 | "array-equal": { 129 | "version": "1.0.0", 130 | "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", 131 | "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", 132 | "dev": true 133 | }, 134 | "array-unique": { 135 | "version": "0.2.1", 136 | "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", 137 | "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", 138 | "dev": true 139 | }, 140 | "arrify": { 141 | "version": "1.0.1", 142 | "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", 143 | "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", 144 | "dev": true 145 | }, 146 | "asn1": { 147 | "version": "0.2.3", 148 | "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", 149 | "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", 150 | "dev": true 151 | }, 152 | "assert-plus": { 153 | "version": "0.2.0", 154 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", 155 | "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", 156 | "dev": true 157 | }, 158 | "async": { 159 | "version": "2.5.0", 160 | "resolved": "https://registry.npmjs.org/async/-/async-2.5.0.tgz", 161 | "integrity": "sha512-e+lJAJeNWuPCNyxZKOBdaJGyLGHugXVQtrAwtuAe2vhxTYxFTKE73p8JuTmdH0qdQZtDvI4dhJwjZc5zsfIsYw==", 162 | "dev": true, 163 | "requires": { 164 | "lodash": "4.17.4" 165 | } 166 | }, 167 | "asynckit": { 168 | "version": "0.4.0", 169 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 170 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", 171 | "dev": true 172 | }, 173 | "aws-sign2": { 174 | "version": "0.6.0", 175 | "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", 176 | "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", 177 | "dev": true 178 | }, 179 | "aws4": { 180 | "version": "1.6.0", 181 | "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", 182 | "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=", 183 | "dev": true 184 | }, 185 | "babel-code-frame": { 186 | "version": "6.26.0", 187 | "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", 188 | "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", 189 | "dev": true, 190 | "requires": { 191 | "chalk": "1.1.3", 192 | "esutils": "2.0.2", 193 | "js-tokens": "3.0.2" 194 | } 195 | }, 196 | "babel-core": { 197 | "version": "6.26.0", 198 | "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.0.tgz", 199 | "integrity": "sha1-rzL3izGm/O8RnIew/Y2XU/A6C7g=", 200 | "dev": true, 201 | "requires": { 202 | "babel-code-frame": "6.26.0", 203 | "babel-generator": "6.26.0", 204 | "babel-helpers": "6.24.1", 205 | "babel-messages": "6.23.0", 206 | "babel-register": "6.26.0", 207 | "babel-runtime": "6.26.0", 208 | "babel-template": "6.26.0", 209 | "babel-traverse": "6.26.0", 210 | "babel-types": "6.26.0", 211 | "babylon": "6.18.0", 212 | "convert-source-map": "1.5.0", 213 | "debug": "2.6.8", 214 | "json5": "0.5.1", 215 | "lodash": "4.17.4", 216 | "minimatch": "3.0.4", 217 | "path-is-absolute": "1.0.1", 218 | "private": "0.1.7", 219 | "slash": "1.0.0", 220 | "source-map": "0.5.7" 221 | } 222 | }, 223 | "babel-generator": { 224 | "version": "6.26.0", 225 | "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.0.tgz", 226 | "integrity": "sha1-rBriAHC3n248odMmlhMFN3TyDcU=", 227 | "dev": true, 228 | "requires": { 229 | "babel-messages": "6.23.0", 230 | "babel-runtime": "6.26.0", 231 | "babel-types": "6.26.0", 232 | "detect-indent": "4.0.0", 233 | "jsesc": "1.3.0", 234 | "lodash": "4.17.4", 235 | "source-map": "0.5.7", 236 | "trim-right": "1.0.1" 237 | } 238 | }, 239 | "babel-helpers": { 240 | "version": "6.24.1", 241 | "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", 242 | "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", 243 | "dev": true, 244 | "requires": { 245 | "babel-runtime": "6.26.0", 246 | "babel-template": "6.26.0" 247 | } 248 | }, 249 | "babel-jest": { 250 | "version": "20.0.3", 251 | "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-20.0.3.tgz", 252 | "integrity": "sha1-5KA7E9wQOJ4UD8ZF0J/8TO0wFnE=", 253 | "dev": true, 254 | "requires": { 255 | "babel-core": "6.26.0", 256 | "babel-plugin-istanbul": "4.1.4", 257 | "babel-preset-jest": "20.0.3" 258 | } 259 | }, 260 | "babel-messages": { 261 | "version": "6.23.0", 262 | "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", 263 | "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", 264 | "dev": true, 265 | "requires": { 266 | "babel-runtime": "6.26.0" 267 | } 268 | }, 269 | "babel-plugin-istanbul": { 270 | "version": "4.1.4", 271 | "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.4.tgz", 272 | "integrity": "sha1-GN3oS/POMp/d8/QQP66SFFbY5Yc=", 273 | "dev": true, 274 | "requires": { 275 | "find-up": "2.1.0", 276 | "istanbul-lib-instrument": "1.8.0", 277 | "test-exclude": "4.1.1" 278 | } 279 | }, 280 | "babel-plugin-jest-hoist": { 281 | "version": "20.0.3", 282 | "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-20.0.3.tgz", 283 | "integrity": "sha1-r+3IU70/jcNUjqZx++adA8wsF2c=", 284 | "dev": true 285 | }, 286 | "babel-plugin-transform-es2015-modules-commonjs": { 287 | "version": "6.26.0", 288 | "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.0.tgz", 289 | "integrity": "sha1-DYOUApt9xqvhqX7xgeAHWN0uXYo=", 290 | "dev": true, 291 | "requires": { 292 | "babel-plugin-transform-strict-mode": "6.24.1", 293 | "babel-runtime": "6.26.0", 294 | "babel-template": "6.26.0", 295 | "babel-types": "6.26.0" 296 | } 297 | }, 298 | "babel-plugin-transform-strict-mode": { 299 | "version": "6.24.1", 300 | "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", 301 | "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", 302 | "dev": true, 303 | "requires": { 304 | "babel-runtime": "6.26.0", 305 | "babel-types": "6.26.0" 306 | } 307 | }, 308 | "babel-preset-jest": { 309 | "version": "20.0.3", 310 | "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-20.0.3.tgz", 311 | "integrity": "sha1-y6yq3stdaJyh4d4TYOv8ZoYsF4o=", 312 | "dev": true, 313 | "requires": { 314 | "babel-plugin-jest-hoist": "20.0.3" 315 | } 316 | }, 317 | "babel-register": { 318 | "version": "6.26.0", 319 | "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", 320 | "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", 321 | "dev": true, 322 | "requires": { 323 | "babel-core": "6.26.0", 324 | "babel-runtime": "6.26.0", 325 | "core-js": "2.5.1", 326 | "home-or-tmp": "2.0.0", 327 | "lodash": "4.17.4", 328 | "mkdirp": "0.5.1", 329 | "source-map-support": "0.4.17" 330 | } 331 | }, 332 | "babel-runtime": { 333 | "version": "6.26.0", 334 | "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", 335 | "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", 336 | "dev": true, 337 | "requires": { 338 | "core-js": "2.5.1", 339 | "regenerator-runtime": "0.11.0" 340 | } 341 | }, 342 | "babel-template": { 343 | "version": "6.26.0", 344 | "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", 345 | "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", 346 | "dev": true, 347 | "requires": { 348 | "babel-runtime": "6.26.0", 349 | "babel-traverse": "6.26.0", 350 | "babel-types": "6.26.0", 351 | "babylon": "6.18.0", 352 | "lodash": "4.17.4" 353 | } 354 | }, 355 | "babel-traverse": { 356 | "version": "6.26.0", 357 | "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", 358 | "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", 359 | "dev": true, 360 | "requires": { 361 | "babel-code-frame": "6.26.0", 362 | "babel-messages": "6.23.0", 363 | "babel-runtime": "6.26.0", 364 | "babel-types": "6.26.0", 365 | "babylon": "6.18.0", 366 | "debug": "2.6.8", 367 | "globals": "9.18.0", 368 | "invariant": "2.2.2", 369 | "lodash": "4.17.4" 370 | } 371 | }, 372 | "babel-types": { 373 | "version": "6.26.0", 374 | "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", 375 | "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", 376 | "dev": true, 377 | "requires": { 378 | "babel-runtime": "6.26.0", 379 | "esutils": "2.0.2", 380 | "lodash": "4.17.4", 381 | "to-fast-properties": "1.0.3" 382 | } 383 | }, 384 | "babylon": { 385 | "version": "6.18.0", 386 | "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", 387 | "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", 388 | "dev": true 389 | }, 390 | "balanced-match": { 391 | "version": "1.0.0", 392 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 393 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 394 | "dev": true 395 | }, 396 | "bcrypt-pbkdf": { 397 | "version": "1.0.1", 398 | "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", 399 | "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", 400 | "dev": true, 401 | "optional": true, 402 | "requires": { 403 | "tweetnacl": "0.14.5" 404 | } 405 | }, 406 | "boom": { 407 | "version": "2.10.1", 408 | "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", 409 | "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", 410 | "dev": true, 411 | "requires": { 412 | "hoek": "2.16.3" 413 | } 414 | }, 415 | "brace-expansion": { 416 | "version": "1.1.8", 417 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", 418 | "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", 419 | "dev": true, 420 | "requires": { 421 | "balanced-match": "1.0.0", 422 | "concat-map": "0.0.1" 423 | } 424 | }, 425 | "braces": { 426 | "version": "1.8.5", 427 | "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", 428 | "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", 429 | "dev": true, 430 | "requires": { 431 | "expand-range": "1.8.2", 432 | "preserve": "0.2.0", 433 | "repeat-element": "1.1.2" 434 | } 435 | }, 436 | "browser-resolve": { 437 | "version": "1.11.2", 438 | "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.2.tgz", 439 | "integrity": "sha1-j/CbCixCFxihBRwmCzLkj0QpOM4=", 440 | "dev": true, 441 | "requires": { 442 | "resolve": "1.1.7" 443 | }, 444 | "dependencies": { 445 | "resolve": { 446 | "version": "1.1.7", 447 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", 448 | "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", 449 | "dev": true 450 | } 451 | } 452 | }, 453 | "bser": { 454 | "version": "2.0.0", 455 | "resolved": "https://registry.npmjs.org/bser/-/bser-2.0.0.tgz", 456 | "integrity": "sha1-mseNPtXZFYBP2HrLFYvHlxR6Fxk=", 457 | "dev": true, 458 | "requires": { 459 | "node-int64": "0.4.0" 460 | } 461 | }, 462 | "builtin-modules": { 463 | "version": "1.1.1", 464 | "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", 465 | "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", 466 | "dev": true 467 | }, 468 | "callsites": { 469 | "version": "2.0.0", 470 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", 471 | "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", 472 | "dev": true 473 | }, 474 | "camelcase": { 475 | "version": "1.2.1", 476 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", 477 | "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", 478 | "dev": true, 479 | "optional": true 480 | }, 481 | "caseless": { 482 | "version": "0.12.0", 483 | "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", 484 | "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", 485 | "dev": true 486 | }, 487 | "center-align": { 488 | "version": "0.1.3", 489 | "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", 490 | "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", 491 | "dev": true, 492 | "optional": true, 493 | "requires": { 494 | "align-text": "0.1.4", 495 | "lazy-cache": "1.0.4" 496 | } 497 | }, 498 | "chalk": { 499 | "version": "1.1.3", 500 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", 501 | "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", 502 | "dev": true, 503 | "requires": { 504 | "ansi-styles": "2.2.1", 505 | "escape-string-regexp": "1.0.5", 506 | "has-ansi": "2.0.0", 507 | "strip-ansi": "3.0.1", 508 | "supports-color": "2.0.0" 509 | } 510 | }, 511 | "ci-info": { 512 | "version": "1.1.1", 513 | "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.1.1.tgz", 514 | "integrity": "sha512-vHDDF/bP9RYpTWtUhpJRhCFdvvp3iDWvEbuDbWgvjUrNGV1MXJrE0MPcwGtEled04m61iwdBLUIHZtDgzWS4ZQ==", 515 | "dev": true 516 | }, 517 | "cliui": { 518 | "version": "2.1.0", 519 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", 520 | "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", 521 | "dev": true, 522 | "optional": true, 523 | "requires": { 524 | "center-align": "0.1.3", 525 | "right-align": "0.1.3", 526 | "wordwrap": "0.0.2" 527 | }, 528 | "dependencies": { 529 | "wordwrap": { 530 | "version": "0.0.2", 531 | "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", 532 | "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", 533 | "dev": true, 534 | "optional": true 535 | } 536 | } 537 | }, 538 | "co": { 539 | "version": "4.6.0", 540 | "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", 541 | "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", 542 | "dev": true 543 | }, 544 | "code-point-at": { 545 | "version": "1.1.0", 546 | "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", 547 | "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", 548 | "dev": true 549 | }, 550 | "color-convert": { 551 | "version": "1.9.0", 552 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.0.tgz", 553 | "integrity": "sha1-Gsz5fdc5uYO/mU1W/sj5WFNkG3o=", 554 | "dev": true, 555 | "requires": { 556 | "color-name": "1.1.3" 557 | } 558 | }, 559 | "color-name": { 560 | "version": "1.1.3", 561 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 562 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", 563 | "dev": true 564 | }, 565 | "colors": { 566 | "version": "1.1.2", 567 | "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", 568 | "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", 569 | "dev": true 570 | }, 571 | "combined-stream": { 572 | "version": "1.0.5", 573 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", 574 | "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", 575 | "dev": true, 576 | "requires": { 577 | "delayed-stream": "1.0.0" 578 | } 579 | }, 580 | "commander": { 581 | "version": "2.11.0", 582 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", 583 | "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", 584 | "dev": true 585 | }, 586 | "concat-map": { 587 | "version": "0.0.1", 588 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 589 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 590 | "dev": true 591 | }, 592 | "content-type-parser": { 593 | "version": "1.0.1", 594 | "resolved": "https://registry.npmjs.org/content-type-parser/-/content-type-parser-1.0.1.tgz", 595 | "integrity": "sha1-w+VpiMU8ZRJ/tG1AMqOpACRv3JQ=", 596 | "dev": true 597 | }, 598 | "convert-source-map": { 599 | "version": "1.5.0", 600 | "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.0.tgz", 601 | "integrity": "sha1-ms1whRxtXf3ZPZKC5e35SgP/RrU=", 602 | "dev": true 603 | }, 604 | "core-js": { 605 | "version": "2.5.1", 606 | "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.1.tgz", 607 | "integrity": "sha1-rmh03GaTd4m4B1T/VCjfZoGcpQs=", 608 | "dev": true 609 | }, 610 | "core-util-is": { 611 | "version": "1.0.2", 612 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 613 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", 614 | "dev": true 615 | }, 616 | "cryptiles": { 617 | "version": "2.0.5", 618 | "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", 619 | "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", 620 | "dev": true, 621 | "requires": { 622 | "boom": "2.10.1" 623 | } 624 | }, 625 | "cssom": { 626 | "version": "0.3.2", 627 | "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.2.tgz", 628 | "integrity": "sha1-uANhcMefB6kP8vFuIihAJ6JDhIs=", 629 | "dev": true 630 | }, 631 | "cssstyle": { 632 | "version": "0.2.37", 633 | "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-0.2.37.tgz", 634 | "integrity": "sha1-VBCXI0yyUTyDzu06zdwn/yeYfVQ=", 635 | "dev": true, 636 | "requires": { 637 | "cssom": "0.3.2" 638 | } 639 | }, 640 | "dashdash": { 641 | "version": "1.14.1", 642 | "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", 643 | "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", 644 | "dev": true, 645 | "requires": { 646 | "assert-plus": "1.0.0" 647 | }, 648 | "dependencies": { 649 | "assert-plus": { 650 | "version": "1.0.0", 651 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 652 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", 653 | "dev": true 654 | } 655 | } 656 | }, 657 | "debug": { 658 | "version": "2.6.8", 659 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", 660 | "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", 661 | "dev": true, 662 | "requires": { 663 | "ms": "2.0.0" 664 | } 665 | }, 666 | "decamelize": { 667 | "version": "1.2.0", 668 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", 669 | "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", 670 | "dev": true 671 | }, 672 | "deep-is": { 673 | "version": "0.1.3", 674 | "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", 675 | "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", 676 | "dev": true 677 | }, 678 | "default-require-extensions": { 679 | "version": "1.0.0", 680 | "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-1.0.0.tgz", 681 | "integrity": "sha1-836hXT4T/9m0N9M+GnW1+5eHTLg=", 682 | "dev": true, 683 | "requires": { 684 | "strip-bom": "2.0.0" 685 | } 686 | }, 687 | "delayed-stream": { 688 | "version": "1.0.0", 689 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 690 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", 691 | "dev": true 692 | }, 693 | "detect-indent": { 694 | "version": "4.0.0", 695 | "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", 696 | "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", 697 | "dev": true, 698 | "requires": { 699 | "repeating": "2.0.1" 700 | } 701 | }, 702 | "diff": { 703 | "version": "3.3.1", 704 | "resolved": "https://registry.npmjs.org/diff/-/diff-3.3.1.tgz", 705 | "integrity": "sha512-MKPHZDMB0o6yHyDryUOScqZibp914ksXwAMYMTHj6KO8UeKsRYNJD3oNCKjTqZon+V488P7N/HzXF8t7ZR95ww==", 706 | "dev": true 707 | }, 708 | "ecc-jsbn": { 709 | "version": "0.1.1", 710 | "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", 711 | "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", 712 | "dev": true, 713 | "optional": true, 714 | "requires": { 715 | "jsbn": "0.1.1" 716 | } 717 | }, 718 | "errno": { 719 | "version": "0.1.4", 720 | "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.4.tgz", 721 | "integrity": "sha1-uJbiOp5ei6M4cfyZar02NfyaHH0=", 722 | "dev": true, 723 | "requires": { 724 | "prr": "0.0.0" 725 | } 726 | }, 727 | "error-ex": { 728 | "version": "1.3.1", 729 | "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", 730 | "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", 731 | "dev": true, 732 | "requires": { 733 | "is-arrayish": "0.2.1" 734 | } 735 | }, 736 | "escape-string-regexp": { 737 | "version": "1.0.5", 738 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 739 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 740 | "dev": true 741 | }, 742 | "escodegen": { 743 | "version": "1.9.0", 744 | "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.9.0.tgz", 745 | "integrity": "sha512-v0MYvNQ32bzwoG2OSFzWAkuahDQHK92JBN0pTAALJ4RIxEZe766QJPDR8Hqy7XNUy5K3fnVL76OqYAdc4TZEIw==", 746 | "dev": true, 747 | "requires": { 748 | "esprima": "3.1.3", 749 | "estraverse": "4.2.0", 750 | "esutils": "2.0.2", 751 | "optionator": "0.8.2", 752 | "source-map": "0.5.7" 753 | }, 754 | "dependencies": { 755 | "esprima": { 756 | "version": "3.1.3", 757 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", 758 | "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", 759 | "dev": true 760 | } 761 | } 762 | }, 763 | "esprima": { 764 | "version": "4.0.0", 765 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", 766 | "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==", 767 | "dev": true 768 | }, 769 | "estraverse": { 770 | "version": "4.2.0", 771 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", 772 | "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", 773 | "dev": true 774 | }, 775 | "esutils": { 776 | "version": "2.0.2", 777 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", 778 | "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", 779 | "dev": true 780 | }, 781 | "exec-sh": { 782 | "version": "0.2.1", 783 | "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.1.tgz", 784 | "integrity": "sha512-aLt95pexaugVtQerpmE51+4QfWrNc304uez7jvj6fWnN8GeEHpttB8F36n8N7uVhUMbH/1enbxQ9HImZ4w/9qg==", 785 | "dev": true, 786 | "requires": { 787 | "merge": "1.2.0" 788 | } 789 | }, 790 | "expand-brackets": { 791 | "version": "0.1.5", 792 | "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", 793 | "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", 794 | "dev": true, 795 | "requires": { 796 | "is-posix-bracket": "0.1.1" 797 | } 798 | }, 799 | "expand-range": { 800 | "version": "1.8.2", 801 | "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", 802 | "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", 803 | "dev": true, 804 | "requires": { 805 | "fill-range": "2.2.3" 806 | } 807 | }, 808 | "extend": { 809 | "version": "3.0.1", 810 | "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", 811 | "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", 812 | "dev": true 813 | }, 814 | "extglob": { 815 | "version": "0.3.2", 816 | "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", 817 | "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", 818 | "dev": true, 819 | "requires": { 820 | "is-extglob": "1.0.0" 821 | } 822 | }, 823 | "extsprintf": { 824 | "version": "1.3.0", 825 | "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", 826 | "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", 827 | "dev": true 828 | }, 829 | "fast-levenshtein": { 830 | "version": "2.0.6", 831 | "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", 832 | "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", 833 | "dev": true 834 | }, 835 | "fb-watchman": { 836 | "version": "2.0.0", 837 | "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.0.tgz", 838 | "integrity": "sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg=", 839 | "dev": true, 840 | "requires": { 841 | "bser": "2.0.0" 842 | } 843 | }, 844 | "filename-regex": { 845 | "version": "2.0.1", 846 | "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", 847 | "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", 848 | "dev": true 849 | }, 850 | "fileset": { 851 | "version": "2.0.3", 852 | "resolved": "https://registry.npmjs.org/fileset/-/fileset-2.0.3.tgz", 853 | "integrity": "sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA=", 854 | "dev": true, 855 | "requires": { 856 | "glob": "7.1.2", 857 | "minimatch": "3.0.4" 858 | } 859 | }, 860 | "fill-range": { 861 | "version": "2.2.3", 862 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz", 863 | "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=", 864 | "dev": true, 865 | "requires": { 866 | "is-number": "2.1.0", 867 | "isobject": "2.1.0", 868 | "randomatic": "1.1.7", 869 | "repeat-element": "1.1.2", 870 | "repeat-string": "1.6.1" 871 | } 872 | }, 873 | "find-up": { 874 | "version": "2.1.0", 875 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", 876 | "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", 877 | "dev": true, 878 | "requires": { 879 | "locate-path": "2.0.0" 880 | } 881 | }, 882 | "for-in": { 883 | "version": "1.0.2", 884 | "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", 885 | "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", 886 | "dev": true 887 | }, 888 | "for-own": { 889 | "version": "0.1.5", 890 | "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", 891 | "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", 892 | "dev": true, 893 | "requires": { 894 | "for-in": "1.0.2" 895 | } 896 | }, 897 | "forever-agent": { 898 | "version": "0.6.1", 899 | "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", 900 | "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", 901 | "dev": true 902 | }, 903 | "form-data": { 904 | "version": "2.1.4", 905 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", 906 | "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", 907 | "dev": true, 908 | "requires": { 909 | "asynckit": "0.4.0", 910 | "combined-stream": "1.0.5", 911 | "mime-types": "2.1.17" 912 | } 913 | }, 914 | "fs.realpath": { 915 | "version": "1.0.0", 916 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 917 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 918 | "dev": true 919 | }, 920 | "get-caller-file": { 921 | "version": "1.0.2", 922 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", 923 | "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=", 924 | "dev": true 925 | }, 926 | "getpass": { 927 | "version": "0.1.7", 928 | "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", 929 | "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", 930 | "dev": true, 931 | "requires": { 932 | "assert-plus": "1.0.0" 933 | }, 934 | "dependencies": { 935 | "assert-plus": { 936 | "version": "1.0.0", 937 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 938 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", 939 | "dev": true 940 | } 941 | } 942 | }, 943 | "glob": { 944 | "version": "7.1.2", 945 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", 946 | "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", 947 | "dev": true, 948 | "requires": { 949 | "fs.realpath": "1.0.0", 950 | "inflight": "1.0.6", 951 | "inherits": "2.0.3", 952 | "minimatch": "3.0.4", 953 | "once": "1.4.0", 954 | "path-is-absolute": "1.0.1" 955 | } 956 | }, 957 | "glob-base": { 958 | "version": "0.3.0", 959 | "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", 960 | "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", 961 | "dev": true, 962 | "requires": { 963 | "glob-parent": "2.0.0", 964 | "is-glob": "2.0.1" 965 | } 966 | }, 967 | "glob-parent": { 968 | "version": "2.0.0", 969 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", 970 | "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", 971 | "dev": true, 972 | "requires": { 973 | "is-glob": "2.0.1" 974 | } 975 | }, 976 | "globals": { 977 | "version": "9.18.0", 978 | "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", 979 | "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", 980 | "dev": true 981 | }, 982 | "graceful-fs": { 983 | "version": "4.1.11", 984 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", 985 | "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", 986 | "dev": true 987 | }, 988 | "growly": { 989 | "version": "1.3.0", 990 | "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", 991 | "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", 992 | "dev": true 993 | }, 994 | "handlebars": { 995 | "version": "4.0.10", 996 | "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.10.tgz", 997 | "integrity": "sha1-PTDHGLCaPZbyPqTMH0A8TTup/08=", 998 | "dev": true, 999 | "requires": { 1000 | "async": "1.5.2", 1001 | "optimist": "0.6.1", 1002 | "source-map": "0.4.4", 1003 | "uglify-js": "2.8.29" 1004 | }, 1005 | "dependencies": { 1006 | "async": { 1007 | "version": "1.5.2", 1008 | "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", 1009 | "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", 1010 | "dev": true 1011 | }, 1012 | "source-map": { 1013 | "version": "0.4.4", 1014 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", 1015 | "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", 1016 | "dev": true, 1017 | "requires": { 1018 | "amdefine": "1.0.1" 1019 | } 1020 | } 1021 | } 1022 | }, 1023 | "har-schema": { 1024 | "version": "1.0.5", 1025 | "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", 1026 | "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=", 1027 | "dev": true 1028 | }, 1029 | "har-validator": { 1030 | "version": "4.2.1", 1031 | "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", 1032 | "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", 1033 | "dev": true, 1034 | "requires": { 1035 | "ajv": "4.11.8", 1036 | "har-schema": "1.0.5" 1037 | } 1038 | }, 1039 | "has-ansi": { 1040 | "version": "2.0.0", 1041 | "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", 1042 | "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", 1043 | "dev": true, 1044 | "requires": { 1045 | "ansi-regex": "2.1.1" 1046 | } 1047 | }, 1048 | "has-flag": { 1049 | "version": "1.0.0", 1050 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", 1051 | "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", 1052 | "dev": true 1053 | }, 1054 | "hawk": { 1055 | "version": "3.1.3", 1056 | "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", 1057 | "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", 1058 | "dev": true, 1059 | "requires": { 1060 | "boom": "2.10.1", 1061 | "cryptiles": "2.0.5", 1062 | "hoek": "2.16.3", 1063 | "sntp": "1.0.9" 1064 | } 1065 | }, 1066 | "hoek": { 1067 | "version": "2.16.3", 1068 | "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", 1069 | "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", 1070 | "dev": true 1071 | }, 1072 | "home-or-tmp": { 1073 | "version": "2.0.0", 1074 | "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", 1075 | "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", 1076 | "dev": true, 1077 | "requires": { 1078 | "os-homedir": "1.0.2", 1079 | "os-tmpdir": "1.0.2" 1080 | } 1081 | }, 1082 | "hosted-git-info": { 1083 | "version": "2.5.0", 1084 | "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz", 1085 | "integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==", 1086 | "dev": true 1087 | }, 1088 | "html-encoding-sniffer": { 1089 | "version": "1.0.1", 1090 | "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.1.tgz", 1091 | "integrity": "sha1-eb96eF6klf5mFl5zQVPzY/9UN9o=", 1092 | "dev": true, 1093 | "requires": { 1094 | "whatwg-encoding": "1.0.1" 1095 | } 1096 | }, 1097 | "http-signature": { 1098 | "version": "1.1.1", 1099 | "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", 1100 | "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", 1101 | "dev": true, 1102 | "requires": { 1103 | "assert-plus": "0.2.0", 1104 | "jsprim": "1.4.1", 1105 | "sshpk": "1.13.1" 1106 | } 1107 | }, 1108 | "iconv-lite": { 1109 | "version": "0.4.13", 1110 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz", 1111 | "integrity": "sha1-H4irpKsLFQjoMSrMOTRfNumS4vI=", 1112 | "dev": true 1113 | }, 1114 | "inflight": { 1115 | "version": "1.0.6", 1116 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 1117 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 1118 | "dev": true, 1119 | "requires": { 1120 | "once": "1.4.0", 1121 | "wrappy": "1.0.2" 1122 | } 1123 | }, 1124 | "inherits": { 1125 | "version": "2.0.3", 1126 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 1127 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", 1128 | "dev": true 1129 | }, 1130 | "invariant": { 1131 | "version": "2.2.2", 1132 | "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz", 1133 | "integrity": "sha1-nh9WrArNtr8wMwbzOL47IErmA2A=", 1134 | "dev": true, 1135 | "requires": { 1136 | "loose-envify": "1.3.1" 1137 | } 1138 | }, 1139 | "invert-kv": { 1140 | "version": "1.0.0", 1141 | "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", 1142 | "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", 1143 | "dev": true 1144 | }, 1145 | "is-arrayish": { 1146 | "version": "0.2.1", 1147 | "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", 1148 | "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", 1149 | "dev": true 1150 | }, 1151 | "is-buffer": { 1152 | "version": "1.1.5", 1153 | "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.5.tgz", 1154 | "integrity": "sha1-Hzsm72E7IUuIy8ojzGwB2Hlh7sw=", 1155 | "dev": true 1156 | }, 1157 | "is-builtin-module": { 1158 | "version": "1.0.0", 1159 | "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", 1160 | "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", 1161 | "dev": true, 1162 | "requires": { 1163 | "builtin-modules": "1.1.1" 1164 | } 1165 | }, 1166 | "is-ci": { 1167 | "version": "1.0.10", 1168 | "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.0.10.tgz", 1169 | "integrity": "sha1-9zkzayYyNlBhqdSCcM1WrjNpMY4=", 1170 | "dev": true, 1171 | "requires": { 1172 | "ci-info": "1.1.1" 1173 | } 1174 | }, 1175 | "is-dotfile": { 1176 | "version": "1.0.3", 1177 | "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", 1178 | "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", 1179 | "dev": true 1180 | }, 1181 | "is-equal-shallow": { 1182 | "version": "0.1.3", 1183 | "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", 1184 | "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", 1185 | "dev": true, 1186 | "requires": { 1187 | "is-primitive": "2.0.0" 1188 | } 1189 | }, 1190 | "is-extendable": { 1191 | "version": "0.1.1", 1192 | "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", 1193 | "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", 1194 | "dev": true 1195 | }, 1196 | "is-extglob": { 1197 | "version": "1.0.0", 1198 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", 1199 | "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", 1200 | "dev": true 1201 | }, 1202 | "is-finite": { 1203 | "version": "1.0.2", 1204 | "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", 1205 | "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", 1206 | "dev": true, 1207 | "requires": { 1208 | "number-is-nan": "1.0.1" 1209 | } 1210 | }, 1211 | "is-fullwidth-code-point": { 1212 | "version": "1.0.0", 1213 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", 1214 | "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", 1215 | "dev": true, 1216 | "requires": { 1217 | "number-is-nan": "1.0.1" 1218 | } 1219 | }, 1220 | "is-glob": { 1221 | "version": "2.0.1", 1222 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", 1223 | "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", 1224 | "dev": true, 1225 | "requires": { 1226 | "is-extglob": "1.0.0" 1227 | } 1228 | }, 1229 | "is-number": { 1230 | "version": "2.1.0", 1231 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", 1232 | "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", 1233 | "dev": true, 1234 | "requires": { 1235 | "kind-of": "3.2.2" 1236 | } 1237 | }, 1238 | "is-posix-bracket": { 1239 | "version": "0.1.1", 1240 | "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", 1241 | "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", 1242 | "dev": true 1243 | }, 1244 | "is-primitive": { 1245 | "version": "2.0.0", 1246 | "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", 1247 | "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", 1248 | "dev": true 1249 | }, 1250 | "is-typedarray": { 1251 | "version": "1.0.0", 1252 | "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", 1253 | "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", 1254 | "dev": true 1255 | }, 1256 | "is-utf8": { 1257 | "version": "0.2.1", 1258 | "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", 1259 | "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", 1260 | "dev": true 1261 | }, 1262 | "isarray": { 1263 | "version": "1.0.0", 1264 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 1265 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", 1266 | "dev": true 1267 | }, 1268 | "isexe": { 1269 | "version": "2.0.0", 1270 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 1271 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 1272 | "dev": true 1273 | }, 1274 | "isobject": { 1275 | "version": "2.1.0", 1276 | "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", 1277 | "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", 1278 | "dev": true, 1279 | "requires": { 1280 | "isarray": "1.0.0" 1281 | } 1282 | }, 1283 | "isstream": { 1284 | "version": "0.1.2", 1285 | "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", 1286 | "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", 1287 | "dev": true 1288 | }, 1289 | "istanbul-api": { 1290 | "version": "1.1.14", 1291 | "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-1.1.14.tgz", 1292 | "integrity": "sha1-JbxXAffGgMD//5E95G42GaOm5oA=", 1293 | "dev": true, 1294 | "requires": { 1295 | "async": "2.5.0", 1296 | "fileset": "2.0.3", 1297 | "istanbul-lib-coverage": "1.1.1", 1298 | "istanbul-lib-hook": "1.0.7", 1299 | "istanbul-lib-instrument": "1.8.0", 1300 | "istanbul-lib-report": "1.1.1", 1301 | "istanbul-lib-source-maps": "1.2.1", 1302 | "istanbul-reports": "1.1.2", 1303 | "js-yaml": "3.9.1", 1304 | "mkdirp": "0.5.1", 1305 | "once": "1.4.0" 1306 | } 1307 | }, 1308 | "istanbul-lib-coverage": { 1309 | "version": "1.1.1", 1310 | "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.1.1.tgz", 1311 | "integrity": "sha512-0+1vDkmzxqJIn5rcoEqapSB4DmPxE31EtI2dF2aCkV5esN9EWHxZ0dwgDClivMXJqE7zaYQxq30hj5L0nlTN5Q==", 1312 | "dev": true 1313 | }, 1314 | "istanbul-lib-hook": { 1315 | "version": "1.0.7", 1316 | "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-1.0.7.tgz", 1317 | "integrity": "sha512-3U2HB9y1ZV9UmFlE12Fx+nPtFqIymzrqCksrXujm3NVbAZIJg/RfYgO1XiIa0mbmxTjWpVEVlkIZJ25xVIAfkQ==", 1318 | "dev": true, 1319 | "requires": { 1320 | "append-transform": "0.4.0" 1321 | } 1322 | }, 1323 | "istanbul-lib-instrument": { 1324 | "version": "1.8.0", 1325 | "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.8.0.tgz", 1326 | "integrity": "sha1-ZvbJQhzJ7EcE928tsIS6kHiitTI=", 1327 | "dev": true, 1328 | "requires": { 1329 | "babel-generator": "6.26.0", 1330 | "babel-template": "6.26.0", 1331 | "babel-traverse": "6.26.0", 1332 | "babel-types": "6.26.0", 1333 | "babylon": "6.18.0", 1334 | "istanbul-lib-coverage": "1.1.1", 1335 | "semver": "5.4.1" 1336 | } 1337 | }, 1338 | "istanbul-lib-report": { 1339 | "version": "1.1.1", 1340 | "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-1.1.1.tgz", 1341 | "integrity": "sha512-tvF+YmCmH4thnez6JFX06ujIA19WPa9YUiwjc1uALF2cv5dmE3It8b5I8Ob7FHJ70H9Y5yF+TDkVa/mcADuw1Q==", 1342 | "dev": true, 1343 | "requires": { 1344 | "istanbul-lib-coverage": "1.1.1", 1345 | "mkdirp": "0.5.1", 1346 | "path-parse": "1.0.5", 1347 | "supports-color": "3.2.3" 1348 | }, 1349 | "dependencies": { 1350 | "supports-color": { 1351 | "version": "3.2.3", 1352 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", 1353 | "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", 1354 | "dev": true, 1355 | "requires": { 1356 | "has-flag": "1.0.0" 1357 | } 1358 | } 1359 | } 1360 | }, 1361 | "istanbul-lib-source-maps": { 1362 | "version": "1.2.1", 1363 | "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.1.tgz", 1364 | "integrity": "sha512-mukVvSXCn9JQvdJl8wP/iPhqig0MRtuWuD4ZNKo6vB2Ik//AmhAKe3QnPN02dmkRe3lTudFk3rzoHhwU4hb94w==", 1365 | "dev": true, 1366 | "requires": { 1367 | "debug": "2.6.8", 1368 | "istanbul-lib-coverage": "1.1.1", 1369 | "mkdirp": "0.5.1", 1370 | "rimraf": "2.6.1", 1371 | "source-map": "0.5.7" 1372 | } 1373 | }, 1374 | "istanbul-reports": { 1375 | "version": "1.1.2", 1376 | "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-1.1.2.tgz", 1377 | "integrity": "sha1-D7Lj9qqZIr085F0F2KtNXo4HvU8=", 1378 | "dev": true, 1379 | "requires": { 1380 | "handlebars": "4.0.10" 1381 | } 1382 | }, 1383 | "jest": { 1384 | "version": "20.0.4", 1385 | "resolved": "https://registry.npmjs.org/jest/-/jest-20.0.4.tgz", 1386 | "integrity": "sha1-PdJgwpidba1nix6cxNkZRPbWAqw=", 1387 | "dev": true, 1388 | "requires": { 1389 | "jest-cli": "20.0.4" 1390 | }, 1391 | "dependencies": { 1392 | "jest-cli": { 1393 | "version": "20.0.4", 1394 | "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-20.0.4.tgz", 1395 | "integrity": "sha1-5TKxnYiuW8bEF+iwWTpv6VSx3JM=", 1396 | "dev": true, 1397 | "requires": { 1398 | "ansi-escapes": "1.4.0", 1399 | "callsites": "2.0.0", 1400 | "chalk": "1.1.3", 1401 | "graceful-fs": "4.1.11", 1402 | "is-ci": "1.0.10", 1403 | "istanbul-api": "1.1.14", 1404 | "istanbul-lib-coverage": "1.1.1", 1405 | "istanbul-lib-instrument": "1.8.0", 1406 | "istanbul-lib-source-maps": "1.2.1", 1407 | "jest-changed-files": "20.0.3", 1408 | "jest-config": "20.0.4", 1409 | "jest-docblock": "20.0.3", 1410 | "jest-environment-jsdom": "20.0.3", 1411 | "jest-haste-map": "20.0.5", 1412 | "jest-jasmine2": "20.0.4", 1413 | "jest-message-util": "20.0.3", 1414 | "jest-regex-util": "20.0.3", 1415 | "jest-resolve-dependencies": "20.0.3", 1416 | "jest-runtime": "20.0.4", 1417 | "jest-snapshot": "20.0.3", 1418 | "jest-util": "20.0.3", 1419 | "micromatch": "2.3.11", 1420 | "node-notifier": "5.1.2", 1421 | "pify": "2.3.0", 1422 | "slash": "1.0.0", 1423 | "string-length": "1.0.1", 1424 | "throat": "3.2.0", 1425 | "which": "1.3.0", 1426 | "worker-farm": "1.5.0", 1427 | "yargs": "7.1.0" 1428 | } 1429 | } 1430 | } 1431 | }, 1432 | "jest-changed-files": { 1433 | "version": "20.0.3", 1434 | "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-20.0.3.tgz", 1435 | "integrity": "sha1-k5TVzGXEOEBhSb7xv01Sto4D4/g=", 1436 | "dev": true 1437 | }, 1438 | "jest-config": { 1439 | "version": "20.0.4", 1440 | "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-20.0.4.tgz", 1441 | "integrity": "sha1-43kwqyIXyRNgXv8T5712PsSPruo=", 1442 | "dev": true, 1443 | "requires": { 1444 | "chalk": "1.1.3", 1445 | "glob": "7.1.2", 1446 | "jest-environment-jsdom": "20.0.3", 1447 | "jest-environment-node": "20.0.3", 1448 | "jest-jasmine2": "20.0.4", 1449 | "jest-matcher-utils": "20.0.3", 1450 | "jest-regex-util": "20.0.3", 1451 | "jest-resolve": "20.0.4", 1452 | "jest-validate": "20.0.3", 1453 | "pretty-format": "20.0.3" 1454 | } 1455 | }, 1456 | "jest-diff": { 1457 | "version": "20.0.3", 1458 | "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-20.0.3.tgz", 1459 | "integrity": "sha1-gfKI/Z5nXw+yPHXxwrGURf5YZhc=", 1460 | "dev": true, 1461 | "requires": { 1462 | "chalk": "1.1.3", 1463 | "diff": "3.3.1", 1464 | "jest-matcher-utils": "20.0.3", 1465 | "pretty-format": "20.0.3" 1466 | } 1467 | }, 1468 | "jest-docblock": { 1469 | "version": "20.0.3", 1470 | "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-20.0.3.tgz", 1471 | "integrity": "sha1-F76phDQswz2DxQ++FUXqDvqkRxI=", 1472 | "dev": true 1473 | }, 1474 | "jest-environment-jsdom": { 1475 | "version": "20.0.3", 1476 | "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-20.0.3.tgz", 1477 | "integrity": "sha1-BIqKwS7iJfcZBBdxODS7mZeH3pk=", 1478 | "dev": true, 1479 | "requires": { 1480 | "jest-mock": "20.0.3", 1481 | "jest-util": "20.0.3", 1482 | "jsdom": "9.12.0" 1483 | } 1484 | }, 1485 | "jest-environment-node": { 1486 | "version": "20.0.3", 1487 | "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-20.0.3.tgz", 1488 | "integrity": "sha1-1Ii8RhKvLCRumG6K52caCZFj1AM=", 1489 | "dev": true, 1490 | "requires": { 1491 | "jest-mock": "20.0.3", 1492 | "jest-util": "20.0.3" 1493 | } 1494 | }, 1495 | "jest-haste-map": { 1496 | "version": "20.0.5", 1497 | "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-20.0.5.tgz", 1498 | "integrity": "sha512-0IKAQjUvuZjMCNi/0VNQQF74/H9KB67hsHJqGiwTWQC6XO5Azs7kLWm+6Q/dwuhvDUvABDOBMFK2/FwZ3sZ07Q==", 1499 | "dev": true, 1500 | "requires": { 1501 | "fb-watchman": "2.0.0", 1502 | "graceful-fs": "4.1.11", 1503 | "jest-docblock": "20.0.3", 1504 | "micromatch": "2.3.11", 1505 | "sane": "1.6.0", 1506 | "worker-farm": "1.5.0" 1507 | } 1508 | }, 1509 | "jest-jasmine2": { 1510 | "version": "20.0.4", 1511 | "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-20.0.4.tgz", 1512 | "integrity": "sha1-/MWxQReA2RHQQpAu8YWehS5g1eE=", 1513 | "dev": true, 1514 | "requires": { 1515 | "chalk": "1.1.3", 1516 | "graceful-fs": "4.1.11", 1517 | "jest-diff": "20.0.3", 1518 | "jest-matcher-utils": "20.0.3", 1519 | "jest-matchers": "20.0.3", 1520 | "jest-message-util": "20.0.3", 1521 | "jest-snapshot": "20.0.3", 1522 | "once": "1.4.0", 1523 | "p-map": "1.1.1" 1524 | } 1525 | }, 1526 | "jest-matcher-utils": { 1527 | "version": "20.0.3", 1528 | "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-20.0.3.tgz", 1529 | "integrity": "sha1-s6a443yld4A7CDKpixZPRLeBVhI=", 1530 | "dev": true, 1531 | "requires": { 1532 | "chalk": "1.1.3", 1533 | "pretty-format": "20.0.3" 1534 | } 1535 | }, 1536 | "jest-matchers": { 1537 | "version": "20.0.3", 1538 | "resolved": "https://registry.npmjs.org/jest-matchers/-/jest-matchers-20.0.3.tgz", 1539 | "integrity": "sha1-ymnbHDLbWm9wf6XgQBq7VXAN/WA=", 1540 | "dev": true, 1541 | "requires": { 1542 | "jest-diff": "20.0.3", 1543 | "jest-matcher-utils": "20.0.3", 1544 | "jest-message-util": "20.0.3", 1545 | "jest-regex-util": "20.0.3" 1546 | } 1547 | }, 1548 | "jest-message-util": { 1549 | "version": "20.0.3", 1550 | "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-20.0.3.tgz", 1551 | "integrity": "sha1-auwoRDBvyw5udNV5bBAG2W/dgxw=", 1552 | "dev": true, 1553 | "requires": { 1554 | "chalk": "1.1.3", 1555 | "micromatch": "2.3.11", 1556 | "slash": "1.0.0" 1557 | } 1558 | }, 1559 | "jest-mock": { 1560 | "version": "20.0.3", 1561 | "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-20.0.3.tgz", 1562 | "integrity": "sha1-i8Bw6QQUqhVcEajWTIaaDVxx2lk=", 1563 | "dev": true 1564 | }, 1565 | "jest-regex-util": { 1566 | "version": "20.0.3", 1567 | "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-20.0.3.tgz", 1568 | "integrity": "sha1-hburXRM+RGJbGfr4xqpRItCF12I=", 1569 | "dev": true 1570 | }, 1571 | "jest-resolve": { 1572 | "version": "20.0.4", 1573 | "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-20.0.4.tgz", 1574 | "integrity": "sha1-lEiz6La6/BVHlETGSZBFt//ll6U=", 1575 | "dev": true, 1576 | "requires": { 1577 | "browser-resolve": "1.11.2", 1578 | "is-builtin-module": "1.0.0", 1579 | "resolve": "1.4.0" 1580 | } 1581 | }, 1582 | "jest-resolve-dependencies": { 1583 | "version": "20.0.3", 1584 | "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-20.0.3.tgz", 1585 | "integrity": "sha1-bhSntxevDyyzZnxUneQK8Bexcjo=", 1586 | "dev": true, 1587 | "requires": { 1588 | "jest-regex-util": "20.0.3" 1589 | } 1590 | }, 1591 | "jest-runtime": { 1592 | "version": "20.0.4", 1593 | "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-20.0.4.tgz", 1594 | "integrity": "sha1-osgCIZxCA/dU3xQE5JAYYWnRJNg=", 1595 | "dev": true, 1596 | "requires": { 1597 | "babel-core": "6.26.0", 1598 | "babel-jest": "20.0.3", 1599 | "babel-plugin-istanbul": "4.1.4", 1600 | "chalk": "1.1.3", 1601 | "convert-source-map": "1.5.0", 1602 | "graceful-fs": "4.1.11", 1603 | "jest-config": "20.0.4", 1604 | "jest-haste-map": "20.0.5", 1605 | "jest-regex-util": "20.0.3", 1606 | "jest-resolve": "20.0.4", 1607 | "jest-util": "20.0.3", 1608 | "json-stable-stringify": "1.0.1", 1609 | "micromatch": "2.3.11", 1610 | "strip-bom": "3.0.0", 1611 | "yargs": "7.1.0" 1612 | }, 1613 | "dependencies": { 1614 | "strip-bom": { 1615 | "version": "3.0.0", 1616 | "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", 1617 | "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", 1618 | "dev": true 1619 | } 1620 | } 1621 | }, 1622 | "jest-snapshot": { 1623 | "version": "20.0.3", 1624 | "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-20.0.3.tgz", 1625 | "integrity": "sha1-W4R+GtsaTZCFKn+fElCG4YfHZWY=", 1626 | "dev": true, 1627 | "requires": { 1628 | "chalk": "1.1.3", 1629 | "jest-diff": "20.0.3", 1630 | "jest-matcher-utils": "20.0.3", 1631 | "jest-util": "20.0.3", 1632 | "natural-compare": "1.4.0", 1633 | "pretty-format": "20.0.3" 1634 | } 1635 | }, 1636 | "jest-util": { 1637 | "version": "20.0.3", 1638 | "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-20.0.3.tgz", 1639 | "integrity": "sha1-DAf32A2C9OWmfG+LnD/n9lz9Mq0=", 1640 | "dev": true, 1641 | "requires": { 1642 | "chalk": "1.1.3", 1643 | "graceful-fs": "4.1.11", 1644 | "jest-message-util": "20.0.3", 1645 | "jest-mock": "20.0.3", 1646 | "jest-validate": "20.0.3", 1647 | "leven": "2.1.0", 1648 | "mkdirp": "0.5.1" 1649 | } 1650 | }, 1651 | "jest-validate": { 1652 | "version": "20.0.3", 1653 | "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-20.0.3.tgz", 1654 | "integrity": "sha1-0M/R3k9XnymEhJJcKA+PHZTsPKs=", 1655 | "dev": true, 1656 | "requires": { 1657 | "chalk": "1.1.3", 1658 | "jest-matcher-utils": "20.0.3", 1659 | "leven": "2.1.0", 1660 | "pretty-format": "20.0.3" 1661 | } 1662 | }, 1663 | "js-tokens": { 1664 | "version": "3.0.2", 1665 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", 1666 | "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", 1667 | "dev": true 1668 | }, 1669 | "js-yaml": { 1670 | "version": "3.9.1", 1671 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.9.1.tgz", 1672 | "integrity": "sha512-CbcG379L1e+mWBnLvHWWeLs8GyV/EMw862uLI3c+GxVyDHWZcjZinwuBd3iW2pgxgIlksW/1vNJa4to+RvDOww==", 1673 | "dev": true, 1674 | "requires": { 1675 | "argparse": "1.0.9", 1676 | "esprima": "4.0.0" 1677 | } 1678 | }, 1679 | "jsbn": { 1680 | "version": "0.1.1", 1681 | "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", 1682 | "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", 1683 | "dev": true, 1684 | "optional": true 1685 | }, 1686 | "jsdom": { 1687 | "version": "9.12.0", 1688 | "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-9.12.0.tgz", 1689 | "integrity": "sha1-6MVG//ywbADUgzyoRBD+1/igl9Q=", 1690 | "dev": true, 1691 | "requires": { 1692 | "abab": "1.0.3", 1693 | "acorn": "4.0.13", 1694 | "acorn-globals": "3.1.0", 1695 | "array-equal": "1.0.0", 1696 | "content-type-parser": "1.0.1", 1697 | "cssom": "0.3.2", 1698 | "cssstyle": "0.2.37", 1699 | "escodegen": "1.9.0", 1700 | "html-encoding-sniffer": "1.0.1", 1701 | "nwmatcher": "1.4.1", 1702 | "parse5": "1.5.1", 1703 | "request": "2.81.0", 1704 | "sax": "1.2.4", 1705 | "symbol-tree": "3.2.2", 1706 | "tough-cookie": "2.3.2", 1707 | "webidl-conversions": "4.0.2", 1708 | "whatwg-encoding": "1.0.1", 1709 | "whatwg-url": "4.8.0", 1710 | "xml-name-validator": "2.0.1" 1711 | } 1712 | }, 1713 | "jsesc": { 1714 | "version": "1.3.0", 1715 | "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", 1716 | "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", 1717 | "dev": true 1718 | }, 1719 | "json-schema": { 1720 | "version": "0.2.3", 1721 | "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", 1722 | "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", 1723 | "dev": true 1724 | }, 1725 | "json-stable-stringify": { 1726 | "version": "1.0.1", 1727 | "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", 1728 | "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", 1729 | "dev": true, 1730 | "requires": { 1731 | "jsonify": "0.0.0" 1732 | } 1733 | }, 1734 | "json-stringify-safe": { 1735 | "version": "5.0.1", 1736 | "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", 1737 | "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", 1738 | "dev": true 1739 | }, 1740 | "json5": { 1741 | "version": "0.5.1", 1742 | "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", 1743 | "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", 1744 | "dev": true 1745 | }, 1746 | "jsonify": { 1747 | "version": "0.0.0", 1748 | "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", 1749 | "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", 1750 | "dev": true 1751 | }, 1752 | "jsprim": { 1753 | "version": "1.4.1", 1754 | "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", 1755 | "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", 1756 | "dev": true, 1757 | "requires": { 1758 | "assert-plus": "1.0.0", 1759 | "extsprintf": "1.3.0", 1760 | "json-schema": "0.2.3", 1761 | "verror": "1.10.0" 1762 | }, 1763 | "dependencies": { 1764 | "assert-plus": { 1765 | "version": "1.0.0", 1766 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 1767 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", 1768 | "dev": true 1769 | } 1770 | } 1771 | }, 1772 | "kind-of": { 1773 | "version": "3.2.2", 1774 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 1775 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 1776 | "dev": true, 1777 | "requires": { 1778 | "is-buffer": "1.1.5" 1779 | } 1780 | }, 1781 | "lazy-cache": { 1782 | "version": "1.0.4", 1783 | "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", 1784 | "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", 1785 | "dev": true, 1786 | "optional": true 1787 | }, 1788 | "lcid": { 1789 | "version": "1.0.0", 1790 | "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", 1791 | "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", 1792 | "dev": true, 1793 | "requires": { 1794 | "invert-kv": "1.0.0" 1795 | } 1796 | }, 1797 | "leven": { 1798 | "version": "2.1.0", 1799 | "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", 1800 | "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=", 1801 | "dev": true 1802 | }, 1803 | "levn": { 1804 | "version": "0.3.0", 1805 | "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", 1806 | "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", 1807 | "dev": true, 1808 | "requires": { 1809 | "prelude-ls": "1.1.2", 1810 | "type-check": "0.3.2" 1811 | } 1812 | }, 1813 | "load-json-file": { 1814 | "version": "1.1.0", 1815 | "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", 1816 | "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", 1817 | "dev": true, 1818 | "requires": { 1819 | "graceful-fs": "4.1.11", 1820 | "parse-json": "2.2.0", 1821 | "pify": "2.3.0", 1822 | "pinkie-promise": "2.0.1", 1823 | "strip-bom": "2.0.0" 1824 | } 1825 | }, 1826 | "locate-path": { 1827 | "version": "2.0.0", 1828 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", 1829 | "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", 1830 | "dev": true, 1831 | "requires": { 1832 | "p-locate": "2.0.0", 1833 | "path-exists": "3.0.0" 1834 | } 1835 | }, 1836 | "lodash": { 1837 | "version": "4.17.4", 1838 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", 1839 | "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", 1840 | "dev": true 1841 | }, 1842 | "lodash-es": { 1843 | "version": "4.17.4", 1844 | "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.4.tgz", 1845 | "integrity": "sha1-3MHXVS4VCgZABzupyzHXDwMpUOc=", 1846 | "dev": true 1847 | }, 1848 | "longest": { 1849 | "version": "1.0.1", 1850 | "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", 1851 | "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", 1852 | "dev": true 1853 | }, 1854 | "loose-envify": { 1855 | "version": "1.3.1", 1856 | "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", 1857 | "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", 1858 | "dev": true, 1859 | "requires": { 1860 | "js-tokens": "3.0.2" 1861 | } 1862 | }, 1863 | "makeerror": { 1864 | "version": "1.0.11", 1865 | "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", 1866 | "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", 1867 | "dev": true, 1868 | "requires": { 1869 | "tmpl": "1.0.4" 1870 | } 1871 | }, 1872 | "merge": { 1873 | "version": "1.2.0", 1874 | "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.0.tgz", 1875 | "integrity": "sha1-dTHjnUlJwoGma4xabgJl6LBYlNo=", 1876 | "dev": true 1877 | }, 1878 | "micromatch": { 1879 | "version": "2.3.11", 1880 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", 1881 | "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", 1882 | "dev": true, 1883 | "requires": { 1884 | "arr-diff": "2.0.0", 1885 | "array-unique": "0.2.1", 1886 | "braces": "1.8.5", 1887 | "expand-brackets": "0.1.5", 1888 | "extglob": "0.3.2", 1889 | "filename-regex": "2.0.1", 1890 | "is-extglob": "1.0.0", 1891 | "is-glob": "2.0.1", 1892 | "kind-of": "3.2.2", 1893 | "normalize-path": "2.1.1", 1894 | "object.omit": "2.0.1", 1895 | "parse-glob": "3.0.4", 1896 | "regex-cache": "0.4.4" 1897 | } 1898 | }, 1899 | "mime-db": { 1900 | "version": "1.30.0", 1901 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", 1902 | "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=", 1903 | "dev": true 1904 | }, 1905 | "mime-types": { 1906 | "version": "2.1.17", 1907 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", 1908 | "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", 1909 | "dev": true, 1910 | "requires": { 1911 | "mime-db": "1.30.0" 1912 | } 1913 | }, 1914 | "minimatch": { 1915 | "version": "3.0.4", 1916 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 1917 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 1918 | "dev": true, 1919 | "requires": { 1920 | "brace-expansion": "1.1.8" 1921 | } 1922 | }, 1923 | "minimist": { 1924 | "version": "0.0.8", 1925 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 1926 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", 1927 | "dev": true 1928 | }, 1929 | "mkdirp": { 1930 | "version": "0.5.1", 1931 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 1932 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 1933 | "dev": true, 1934 | "requires": { 1935 | "minimist": "0.0.8" 1936 | } 1937 | }, 1938 | "ms": { 1939 | "version": "2.0.0", 1940 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 1941 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", 1942 | "dev": true 1943 | }, 1944 | "natural-compare": { 1945 | "version": "1.4.0", 1946 | "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", 1947 | "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", 1948 | "dev": true 1949 | }, 1950 | "node-int64": { 1951 | "version": "0.4.0", 1952 | "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", 1953 | "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", 1954 | "dev": true 1955 | }, 1956 | "node-notifier": { 1957 | "version": "5.1.2", 1958 | "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.1.2.tgz", 1959 | "integrity": "sha1-L6nhJgX6EACdRFSdb82KY93g5P8=", 1960 | "dev": true, 1961 | "requires": { 1962 | "growly": "1.3.0", 1963 | "semver": "5.4.1", 1964 | "shellwords": "0.1.1", 1965 | "which": "1.3.0" 1966 | } 1967 | }, 1968 | "normalize-package-data": { 1969 | "version": "2.4.0", 1970 | "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", 1971 | "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", 1972 | "dev": true, 1973 | "requires": { 1974 | "hosted-git-info": "2.5.0", 1975 | "is-builtin-module": "1.0.0", 1976 | "semver": "5.4.1", 1977 | "validate-npm-package-license": "3.0.1" 1978 | } 1979 | }, 1980 | "normalize-path": { 1981 | "version": "2.1.1", 1982 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", 1983 | "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", 1984 | "dev": true, 1985 | "requires": { 1986 | "remove-trailing-separator": "1.1.0" 1987 | } 1988 | }, 1989 | "number-is-nan": { 1990 | "version": "1.0.1", 1991 | "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", 1992 | "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", 1993 | "dev": true 1994 | }, 1995 | "nwmatcher": { 1996 | "version": "1.4.1", 1997 | "resolved": "https://registry.npmjs.org/nwmatcher/-/nwmatcher-1.4.1.tgz", 1998 | "integrity": "sha1-eumwew6oBNt+JfBctf5Al9TklJ8=", 1999 | "dev": true 2000 | }, 2001 | "oauth-sign": { 2002 | "version": "0.8.2", 2003 | "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", 2004 | "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", 2005 | "dev": true 2006 | }, 2007 | "object-assign": { 2008 | "version": "4.1.1", 2009 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 2010 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", 2011 | "dev": true 2012 | }, 2013 | "object.omit": { 2014 | "version": "2.0.1", 2015 | "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", 2016 | "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", 2017 | "dev": true, 2018 | "requires": { 2019 | "for-own": "0.1.5", 2020 | "is-extendable": "0.1.1" 2021 | } 2022 | }, 2023 | "once": { 2024 | "version": "1.4.0", 2025 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 2026 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 2027 | "dev": true, 2028 | "requires": { 2029 | "wrappy": "1.0.2" 2030 | } 2031 | }, 2032 | "optimist": { 2033 | "version": "0.6.1", 2034 | "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", 2035 | "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", 2036 | "dev": true, 2037 | "requires": { 2038 | "minimist": "0.0.8", 2039 | "wordwrap": "0.0.3" 2040 | } 2041 | }, 2042 | "optionator": { 2043 | "version": "0.8.2", 2044 | "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", 2045 | "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", 2046 | "dev": true, 2047 | "requires": { 2048 | "deep-is": "0.1.3", 2049 | "fast-levenshtein": "2.0.6", 2050 | "levn": "0.3.0", 2051 | "prelude-ls": "1.1.2", 2052 | "type-check": "0.3.2", 2053 | "wordwrap": "1.0.0" 2054 | }, 2055 | "dependencies": { 2056 | "wordwrap": { 2057 | "version": "1.0.0", 2058 | "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", 2059 | "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", 2060 | "dev": true 2061 | } 2062 | } 2063 | }, 2064 | "os-homedir": { 2065 | "version": "1.0.2", 2066 | "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", 2067 | "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", 2068 | "dev": true 2069 | }, 2070 | "os-locale": { 2071 | "version": "1.4.0", 2072 | "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", 2073 | "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", 2074 | "dev": true, 2075 | "requires": { 2076 | "lcid": "1.0.0" 2077 | } 2078 | }, 2079 | "os-tmpdir": { 2080 | "version": "1.0.2", 2081 | "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", 2082 | "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", 2083 | "dev": true 2084 | }, 2085 | "p-limit": { 2086 | "version": "1.1.0", 2087 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.1.0.tgz", 2088 | "integrity": "sha1-sH/y2aXYi+yAYDWJWiurZqJ5iLw=", 2089 | "dev": true 2090 | }, 2091 | "p-locate": { 2092 | "version": "2.0.0", 2093 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", 2094 | "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", 2095 | "dev": true, 2096 | "requires": { 2097 | "p-limit": "1.1.0" 2098 | } 2099 | }, 2100 | "p-map": { 2101 | "version": "1.1.1", 2102 | "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.1.1.tgz", 2103 | "integrity": "sha1-BfXkrpegaDcbwqXMhr+9vBnErno=", 2104 | "dev": true 2105 | }, 2106 | "parse-glob": { 2107 | "version": "3.0.4", 2108 | "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", 2109 | "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", 2110 | "dev": true, 2111 | "requires": { 2112 | "glob-base": "0.3.0", 2113 | "is-dotfile": "1.0.3", 2114 | "is-extglob": "1.0.0", 2115 | "is-glob": "2.0.1" 2116 | } 2117 | }, 2118 | "parse-json": { 2119 | "version": "2.2.0", 2120 | "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", 2121 | "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", 2122 | "dev": true, 2123 | "requires": { 2124 | "error-ex": "1.3.1" 2125 | } 2126 | }, 2127 | "parse5": { 2128 | "version": "1.5.1", 2129 | "resolved": "https://registry.npmjs.org/parse5/-/parse5-1.5.1.tgz", 2130 | "integrity": "sha1-m387DeMr543CQBsXVzzK8Pb1nZQ=", 2131 | "dev": true 2132 | }, 2133 | "path-exists": { 2134 | "version": "3.0.0", 2135 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", 2136 | "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", 2137 | "dev": true 2138 | }, 2139 | "path-is-absolute": { 2140 | "version": "1.0.1", 2141 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 2142 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 2143 | "dev": true 2144 | }, 2145 | "path-parse": { 2146 | "version": "1.0.5", 2147 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", 2148 | "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", 2149 | "dev": true 2150 | }, 2151 | "path-type": { 2152 | "version": "1.1.0", 2153 | "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", 2154 | "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", 2155 | "dev": true, 2156 | "requires": { 2157 | "graceful-fs": "4.1.11", 2158 | "pify": "2.3.0", 2159 | "pinkie-promise": "2.0.1" 2160 | } 2161 | }, 2162 | "performance-now": { 2163 | "version": "0.2.0", 2164 | "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", 2165 | "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=", 2166 | "dev": true 2167 | }, 2168 | "pify": { 2169 | "version": "2.3.0", 2170 | "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", 2171 | "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", 2172 | "dev": true 2173 | }, 2174 | "pinkie": { 2175 | "version": "2.0.4", 2176 | "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", 2177 | "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", 2178 | "dev": true 2179 | }, 2180 | "pinkie-promise": { 2181 | "version": "2.0.1", 2182 | "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", 2183 | "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", 2184 | "dev": true, 2185 | "requires": { 2186 | "pinkie": "2.0.4" 2187 | } 2188 | }, 2189 | "prelude-ls": { 2190 | "version": "1.1.2", 2191 | "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", 2192 | "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", 2193 | "dev": true 2194 | }, 2195 | "preserve": { 2196 | "version": "0.2.0", 2197 | "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", 2198 | "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", 2199 | "dev": true 2200 | }, 2201 | "pretty-format": { 2202 | "version": "20.0.3", 2203 | "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-20.0.3.tgz", 2204 | "integrity": "sha1-Ag41ClYKH+GpjcO+tsz/s4beixQ=", 2205 | "dev": true, 2206 | "requires": { 2207 | "ansi-regex": "2.1.1", 2208 | "ansi-styles": "3.2.0" 2209 | }, 2210 | "dependencies": { 2211 | "ansi-styles": { 2212 | "version": "3.2.0", 2213 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", 2214 | "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", 2215 | "dev": true, 2216 | "requires": { 2217 | "color-convert": "1.9.0" 2218 | } 2219 | } 2220 | } 2221 | }, 2222 | "private": { 2223 | "version": "0.1.7", 2224 | "resolved": "https://registry.npmjs.org/private/-/private-0.1.7.tgz", 2225 | "integrity": "sha1-aM5eih7woju1cMwoU3tTMqumPvE=", 2226 | "dev": true 2227 | }, 2228 | "prr": { 2229 | "version": "0.0.0", 2230 | "resolved": "https://registry.npmjs.org/prr/-/prr-0.0.0.tgz", 2231 | "integrity": "sha1-GoS4WQgyVQFBGFPQCB7j+obikmo=", 2232 | "dev": true 2233 | }, 2234 | "punycode": { 2235 | "version": "1.4.1", 2236 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", 2237 | "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", 2238 | "dev": true 2239 | }, 2240 | "qs": { 2241 | "version": "6.4.0", 2242 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", 2243 | "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=", 2244 | "dev": true 2245 | }, 2246 | "randomatic": { 2247 | "version": "1.1.7", 2248 | "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz", 2249 | "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==", 2250 | "dev": true, 2251 | "requires": { 2252 | "is-number": "3.0.0", 2253 | "kind-of": "4.0.0" 2254 | }, 2255 | "dependencies": { 2256 | "is-number": { 2257 | "version": "3.0.0", 2258 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", 2259 | "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", 2260 | "dev": true, 2261 | "requires": { 2262 | "kind-of": "3.2.2" 2263 | }, 2264 | "dependencies": { 2265 | "kind-of": { 2266 | "version": "3.2.2", 2267 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 2268 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 2269 | "dev": true, 2270 | "requires": { 2271 | "is-buffer": "1.1.5" 2272 | } 2273 | } 2274 | } 2275 | }, 2276 | "kind-of": { 2277 | "version": "4.0.0", 2278 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", 2279 | "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", 2280 | "dev": true, 2281 | "requires": { 2282 | "is-buffer": "1.1.5" 2283 | } 2284 | } 2285 | } 2286 | }, 2287 | "read-pkg": { 2288 | "version": "1.1.0", 2289 | "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", 2290 | "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", 2291 | "dev": true, 2292 | "requires": { 2293 | "load-json-file": "1.1.0", 2294 | "normalize-package-data": "2.4.0", 2295 | "path-type": "1.1.0" 2296 | } 2297 | }, 2298 | "read-pkg-up": { 2299 | "version": "1.0.1", 2300 | "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", 2301 | "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", 2302 | "dev": true, 2303 | "requires": { 2304 | "find-up": "1.1.2", 2305 | "read-pkg": "1.1.0" 2306 | }, 2307 | "dependencies": { 2308 | "find-up": { 2309 | "version": "1.1.2", 2310 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", 2311 | "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", 2312 | "dev": true, 2313 | "requires": { 2314 | "path-exists": "2.1.0", 2315 | "pinkie-promise": "2.0.1" 2316 | } 2317 | }, 2318 | "path-exists": { 2319 | "version": "2.1.0", 2320 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", 2321 | "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", 2322 | "dev": true, 2323 | "requires": { 2324 | "pinkie-promise": "2.0.1" 2325 | } 2326 | } 2327 | } 2328 | }, 2329 | "redux": { 2330 | "version": "3.7.2", 2331 | "resolved": "https://registry.npmjs.org/redux/-/redux-3.7.2.tgz", 2332 | "integrity": "sha512-pNqnf9q1hI5HHZRBkj3bAngGZW/JMCmexDlOxw4XagXY2o1327nHH54LoTjiPJ0gizoqPDRqWyX/00g0hD6w+A==", 2333 | "dev": true, 2334 | "requires": { 2335 | "lodash": "4.17.4", 2336 | "lodash-es": "4.17.4", 2337 | "loose-envify": "1.3.1", 2338 | "symbol-observable": "1.0.4" 2339 | } 2340 | }, 2341 | "regenerator-runtime": { 2342 | "version": "0.11.0", 2343 | "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz", 2344 | "integrity": "sha512-/aA0kLeRb5N9K0d4fw7ooEbI+xDe+DKD499EQqygGqeS8N3xto15p09uY2xj7ixP81sNPXvRLnAQIqdVStgb1A==", 2345 | "dev": true 2346 | }, 2347 | "regex-cache": { 2348 | "version": "0.4.4", 2349 | "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", 2350 | "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", 2351 | "dev": true, 2352 | "requires": { 2353 | "is-equal-shallow": "0.1.3" 2354 | } 2355 | }, 2356 | "remove-trailing-separator": { 2357 | "version": "1.1.0", 2358 | "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", 2359 | "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", 2360 | "dev": true 2361 | }, 2362 | "repeat-element": { 2363 | "version": "1.1.2", 2364 | "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", 2365 | "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", 2366 | "dev": true 2367 | }, 2368 | "repeat-string": { 2369 | "version": "1.6.1", 2370 | "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", 2371 | "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", 2372 | "dev": true 2373 | }, 2374 | "repeating": { 2375 | "version": "2.0.1", 2376 | "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", 2377 | "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", 2378 | "dev": true, 2379 | "requires": { 2380 | "is-finite": "1.0.2" 2381 | } 2382 | }, 2383 | "request": { 2384 | "version": "2.81.0", 2385 | "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", 2386 | "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", 2387 | "dev": true, 2388 | "requires": { 2389 | "aws-sign2": "0.6.0", 2390 | "aws4": "1.6.0", 2391 | "caseless": "0.12.0", 2392 | "combined-stream": "1.0.5", 2393 | "extend": "3.0.1", 2394 | "forever-agent": "0.6.1", 2395 | "form-data": "2.1.4", 2396 | "har-validator": "4.2.1", 2397 | "hawk": "3.1.3", 2398 | "http-signature": "1.1.1", 2399 | "is-typedarray": "1.0.0", 2400 | "isstream": "0.1.2", 2401 | "json-stringify-safe": "5.0.1", 2402 | "mime-types": "2.1.17", 2403 | "oauth-sign": "0.8.2", 2404 | "performance-now": "0.2.0", 2405 | "qs": "6.4.0", 2406 | "safe-buffer": "5.1.1", 2407 | "stringstream": "0.0.5", 2408 | "tough-cookie": "2.3.2", 2409 | "tunnel-agent": "0.6.0", 2410 | "uuid": "3.1.0" 2411 | } 2412 | }, 2413 | "require-directory": { 2414 | "version": "2.1.1", 2415 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 2416 | "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", 2417 | "dev": true 2418 | }, 2419 | "require-main-filename": { 2420 | "version": "1.0.1", 2421 | "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", 2422 | "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", 2423 | "dev": true 2424 | }, 2425 | "resolve": { 2426 | "version": "1.4.0", 2427 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.4.0.tgz", 2428 | "integrity": "sha512-aW7sVKPufyHqOmyyLzg/J+8606v5nevBgaliIlV7nUpVMsDnoBGV/cbSLNjZAg9q0Cfd/+easKVKQ8vOu8fn1Q==", 2429 | "dev": true, 2430 | "requires": { 2431 | "path-parse": "1.0.5" 2432 | } 2433 | }, 2434 | "right-align": { 2435 | "version": "0.1.3", 2436 | "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", 2437 | "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", 2438 | "dev": true, 2439 | "optional": true, 2440 | "requires": { 2441 | "align-text": "0.1.4" 2442 | } 2443 | }, 2444 | "rimraf": { 2445 | "version": "2.6.1", 2446 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz", 2447 | "integrity": "sha1-wjOOxkPfeht/5cVPqG9XQopV8z0=", 2448 | "dev": true, 2449 | "requires": { 2450 | "glob": "7.1.2" 2451 | } 2452 | }, 2453 | "safe-buffer": { 2454 | "version": "5.1.1", 2455 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", 2456 | "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", 2457 | "dev": true 2458 | }, 2459 | "sane": { 2460 | "version": "1.6.0", 2461 | "resolved": "https://registry.npmjs.org/sane/-/sane-1.6.0.tgz", 2462 | "integrity": "sha1-lhDEUjB6E10pwf3+JUcDQYDEZ3U=", 2463 | "dev": true, 2464 | "requires": { 2465 | "anymatch": "1.3.2", 2466 | "exec-sh": "0.2.1", 2467 | "fb-watchman": "1.9.2", 2468 | "minimatch": "3.0.4", 2469 | "minimist": "1.2.0", 2470 | "walker": "1.0.7", 2471 | "watch": "0.10.0" 2472 | }, 2473 | "dependencies": { 2474 | "bser": { 2475 | "version": "1.0.2", 2476 | "resolved": "https://registry.npmjs.org/bser/-/bser-1.0.2.tgz", 2477 | "integrity": "sha1-OBEWlwsqbe6lZG3RXdcnhES1YWk=", 2478 | "dev": true, 2479 | "requires": { 2480 | "node-int64": "0.4.0" 2481 | } 2482 | }, 2483 | "fb-watchman": { 2484 | "version": "1.9.2", 2485 | "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-1.9.2.tgz", 2486 | "integrity": "sha1-okz0eCf4LTj7Waaa1wt247auc4M=", 2487 | "dev": true, 2488 | "requires": { 2489 | "bser": "1.0.2" 2490 | } 2491 | }, 2492 | "minimist": { 2493 | "version": "1.2.0", 2494 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", 2495 | "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", 2496 | "dev": true 2497 | } 2498 | } 2499 | }, 2500 | "sax": { 2501 | "version": "1.2.4", 2502 | "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", 2503 | "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", 2504 | "dev": true 2505 | }, 2506 | "semver": { 2507 | "version": "5.4.1", 2508 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", 2509 | "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==", 2510 | "dev": true 2511 | }, 2512 | "set-blocking": { 2513 | "version": "2.0.0", 2514 | "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", 2515 | "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", 2516 | "dev": true 2517 | }, 2518 | "shellwords": { 2519 | "version": "0.1.1", 2520 | "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", 2521 | "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", 2522 | "dev": true 2523 | }, 2524 | "slash": { 2525 | "version": "1.0.0", 2526 | "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", 2527 | "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", 2528 | "dev": true 2529 | }, 2530 | "sntp": { 2531 | "version": "1.0.9", 2532 | "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", 2533 | "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", 2534 | "dev": true, 2535 | "requires": { 2536 | "hoek": "2.16.3" 2537 | } 2538 | }, 2539 | "source-map": { 2540 | "version": "0.5.7", 2541 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", 2542 | "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", 2543 | "dev": true 2544 | }, 2545 | "source-map-support": { 2546 | "version": "0.4.17", 2547 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.17.tgz", 2548 | "integrity": "sha512-30c1Ch8FSjV0FwC253iftbbj0dU/OXoSg1LAEGZJUlGgjTNj6cu+DVqJWWIZJY5RXLWV4eFtR+4ouo0VIOYOTg==", 2549 | "dev": true, 2550 | "requires": { 2551 | "source-map": "0.5.7" 2552 | } 2553 | }, 2554 | "spdx-correct": { 2555 | "version": "1.0.2", 2556 | "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", 2557 | "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", 2558 | "dev": true, 2559 | "requires": { 2560 | "spdx-license-ids": "1.2.2" 2561 | } 2562 | }, 2563 | "spdx-expression-parse": { 2564 | "version": "1.0.4", 2565 | "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz", 2566 | "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=", 2567 | "dev": true 2568 | }, 2569 | "spdx-license-ids": { 2570 | "version": "1.2.2", 2571 | "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", 2572 | "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=", 2573 | "dev": true 2574 | }, 2575 | "sprintf-js": { 2576 | "version": "1.0.3", 2577 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 2578 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", 2579 | "dev": true 2580 | }, 2581 | "sshpk": { 2582 | "version": "1.13.1", 2583 | "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", 2584 | "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", 2585 | "dev": true, 2586 | "requires": { 2587 | "asn1": "0.2.3", 2588 | "assert-plus": "1.0.0", 2589 | "bcrypt-pbkdf": "1.0.1", 2590 | "dashdash": "1.14.1", 2591 | "ecc-jsbn": "0.1.1", 2592 | "getpass": "0.1.7", 2593 | "jsbn": "0.1.1", 2594 | "tweetnacl": "0.14.5" 2595 | }, 2596 | "dependencies": { 2597 | "assert-plus": { 2598 | "version": "1.0.0", 2599 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 2600 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", 2601 | "dev": true 2602 | } 2603 | } 2604 | }, 2605 | "string-length": { 2606 | "version": "1.0.1", 2607 | "resolved": "https://registry.npmjs.org/string-length/-/string-length-1.0.1.tgz", 2608 | "integrity": "sha1-VpcPscOFWOnnC3KL894mmsRa36w=", 2609 | "dev": true, 2610 | "requires": { 2611 | "strip-ansi": "3.0.1" 2612 | } 2613 | }, 2614 | "string-width": { 2615 | "version": "1.0.2", 2616 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", 2617 | "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", 2618 | "dev": true, 2619 | "requires": { 2620 | "code-point-at": "1.1.0", 2621 | "is-fullwidth-code-point": "1.0.0", 2622 | "strip-ansi": "3.0.1" 2623 | } 2624 | }, 2625 | "stringstream": { 2626 | "version": "0.0.5", 2627 | "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", 2628 | "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", 2629 | "dev": true 2630 | }, 2631 | "strip-ansi": { 2632 | "version": "3.0.1", 2633 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", 2634 | "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", 2635 | "dev": true, 2636 | "requires": { 2637 | "ansi-regex": "2.1.1" 2638 | } 2639 | }, 2640 | "strip-bom": { 2641 | "version": "2.0.0", 2642 | "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", 2643 | "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", 2644 | "dev": true, 2645 | "requires": { 2646 | "is-utf8": "0.2.1" 2647 | } 2648 | }, 2649 | "supports-color": { 2650 | "version": "2.0.0", 2651 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", 2652 | "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", 2653 | "dev": true 2654 | }, 2655 | "symbol-observable": { 2656 | "version": "1.0.4", 2657 | "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.4.tgz", 2658 | "integrity": "sha1-Kb9hXUqnEhvdiYsi1LP5vE4qoD0=", 2659 | "dev": true 2660 | }, 2661 | "symbol-tree": { 2662 | "version": "3.2.2", 2663 | "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz", 2664 | "integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY=", 2665 | "dev": true 2666 | }, 2667 | "test-exclude": { 2668 | "version": "4.1.1", 2669 | "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-4.1.1.tgz", 2670 | "integrity": "sha512-35+Asrsk3XHJDBgf/VRFexPgh3UyETv8IAn/LRTiZjVy6rjPVqdEk8dJcJYBzl1w0XCJM48lvTy8SfEsCWS4nA==", 2671 | "dev": true, 2672 | "requires": { 2673 | "arrify": "1.0.1", 2674 | "micromatch": "2.3.11", 2675 | "object-assign": "4.1.1", 2676 | "read-pkg-up": "1.0.1", 2677 | "require-main-filename": "1.0.1" 2678 | } 2679 | }, 2680 | "throat": { 2681 | "version": "3.2.0", 2682 | "resolved": "https://registry.npmjs.org/throat/-/throat-3.2.0.tgz", 2683 | "integrity": "sha512-/EY8VpvlqJ+sFtLPeOgc8Pl7kQVOWv0woD87KTXVHPIAE842FGT+rokxIhe8xIUP1cfgrkt0as0vDLjDiMtr8w==", 2684 | "dev": true 2685 | }, 2686 | "tmpl": { 2687 | "version": "1.0.4", 2688 | "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", 2689 | "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=", 2690 | "dev": true 2691 | }, 2692 | "to-fast-properties": { 2693 | "version": "1.0.3", 2694 | "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", 2695 | "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", 2696 | "dev": true 2697 | }, 2698 | "tough-cookie": { 2699 | "version": "2.3.2", 2700 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz", 2701 | "integrity": "sha1-8IH3bkyFcg5sN6X6ztc3FQ2EByo=", 2702 | "dev": true, 2703 | "requires": { 2704 | "punycode": "1.4.1" 2705 | } 2706 | }, 2707 | "tr46": { 2708 | "version": "0.0.3", 2709 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", 2710 | "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", 2711 | "dev": true 2712 | }, 2713 | "trim-right": { 2714 | "version": "1.0.1", 2715 | "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", 2716 | "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", 2717 | "dev": true 2718 | }, 2719 | "tslib": { 2720 | "version": "1.7.1", 2721 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.7.1.tgz", 2722 | "integrity": "sha1-vIAEFkaRkjp5/oN4u+s9ogF1OOw=", 2723 | "dev": true 2724 | }, 2725 | "tslint": { 2726 | "version": "5.7.0", 2727 | "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.7.0.tgz", 2728 | "integrity": "sha1-wl4NDJL6EgHCvDDoROCOaCtPNVI=", 2729 | "dev": true, 2730 | "requires": { 2731 | "babel-code-frame": "6.26.0", 2732 | "colors": "1.1.2", 2733 | "commander": "2.11.0", 2734 | "diff": "3.3.1", 2735 | "glob": "7.1.2", 2736 | "minimatch": "3.0.4", 2737 | "resolve": "1.4.0", 2738 | "semver": "5.4.1", 2739 | "tslib": "1.7.1", 2740 | "tsutils": "2.8.2" 2741 | } 2742 | }, 2743 | "tsutils": { 2744 | "version": "2.8.2", 2745 | "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.8.2.tgz", 2746 | "integrity": "sha1-LBSGukMSYIRbCsb5Aq/Z1wio6mo=", 2747 | "dev": true, 2748 | "requires": { 2749 | "tslib": "1.7.1" 2750 | } 2751 | }, 2752 | "tunnel-agent": { 2753 | "version": "0.6.0", 2754 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", 2755 | "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", 2756 | "dev": true, 2757 | "requires": { 2758 | "safe-buffer": "5.1.1" 2759 | } 2760 | }, 2761 | "tweetnacl": { 2762 | "version": "0.14.5", 2763 | "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", 2764 | "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", 2765 | "dev": true, 2766 | "optional": true 2767 | }, 2768 | "type-check": { 2769 | "version": "0.3.2", 2770 | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", 2771 | "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", 2772 | "dev": true, 2773 | "requires": { 2774 | "prelude-ls": "1.1.2" 2775 | } 2776 | }, 2777 | "typescript": { 2778 | "version": "2.5.2", 2779 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.5.2.tgz", 2780 | "integrity": "sha1-A4qV99m7tCCxvzW6MdTFwd0//jQ=", 2781 | "dev": true 2782 | }, 2783 | "uglify-js": { 2784 | "version": "2.8.29", 2785 | "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", 2786 | "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", 2787 | "dev": true, 2788 | "optional": true, 2789 | "requires": { 2790 | "source-map": "0.5.7", 2791 | "uglify-to-browserify": "1.0.2", 2792 | "yargs": "3.10.0" 2793 | }, 2794 | "dependencies": { 2795 | "yargs": { 2796 | "version": "3.10.0", 2797 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", 2798 | "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", 2799 | "dev": true, 2800 | "optional": true, 2801 | "requires": { 2802 | "camelcase": "1.2.1", 2803 | "cliui": "2.1.0", 2804 | "decamelize": "1.2.0", 2805 | "window-size": "0.1.0" 2806 | } 2807 | } 2808 | } 2809 | }, 2810 | "uglify-to-browserify": { 2811 | "version": "1.0.2", 2812 | "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", 2813 | "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", 2814 | "dev": true, 2815 | "optional": true 2816 | }, 2817 | "uuid": { 2818 | "version": "3.1.0", 2819 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", 2820 | "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==", 2821 | "dev": true 2822 | }, 2823 | "validate-npm-package-license": { 2824 | "version": "3.0.1", 2825 | "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", 2826 | "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", 2827 | "dev": true, 2828 | "requires": { 2829 | "spdx-correct": "1.0.2", 2830 | "spdx-expression-parse": "1.0.4" 2831 | } 2832 | }, 2833 | "verror": { 2834 | "version": "1.10.0", 2835 | "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", 2836 | "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", 2837 | "dev": true, 2838 | "requires": { 2839 | "assert-plus": "1.0.0", 2840 | "core-util-is": "1.0.2", 2841 | "extsprintf": "1.3.0" 2842 | }, 2843 | "dependencies": { 2844 | "assert-plus": { 2845 | "version": "1.0.0", 2846 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 2847 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", 2848 | "dev": true 2849 | } 2850 | } 2851 | }, 2852 | "walker": { 2853 | "version": "1.0.7", 2854 | "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", 2855 | "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", 2856 | "dev": true, 2857 | "requires": { 2858 | "makeerror": "1.0.11" 2859 | } 2860 | }, 2861 | "watch": { 2862 | "version": "0.10.0", 2863 | "resolved": "https://registry.npmjs.org/watch/-/watch-0.10.0.tgz", 2864 | "integrity": "sha1-d3mLLaD5kQ1ZXxrOWwwiWFIfIdw=", 2865 | "dev": true 2866 | }, 2867 | "webidl-conversions": { 2868 | "version": "4.0.2", 2869 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", 2870 | "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", 2871 | "dev": true 2872 | }, 2873 | "whatwg-encoding": { 2874 | "version": "1.0.1", 2875 | "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.1.tgz", 2876 | "integrity": "sha1-PGxFGhmO567FWx7GHQkgxngBpfQ=", 2877 | "dev": true, 2878 | "requires": { 2879 | "iconv-lite": "0.4.13" 2880 | } 2881 | }, 2882 | "whatwg-url": { 2883 | "version": "4.8.0", 2884 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-4.8.0.tgz", 2885 | "integrity": "sha1-0pgaqRSMHgCkHFphMRZqtGg7vMA=", 2886 | "dev": true, 2887 | "requires": { 2888 | "tr46": "0.0.3", 2889 | "webidl-conversions": "3.0.1" 2890 | }, 2891 | "dependencies": { 2892 | "webidl-conversions": { 2893 | "version": "3.0.1", 2894 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", 2895 | "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", 2896 | "dev": true 2897 | } 2898 | } 2899 | }, 2900 | "which": { 2901 | "version": "1.3.0", 2902 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", 2903 | "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", 2904 | "dev": true, 2905 | "requires": { 2906 | "isexe": "2.0.0" 2907 | } 2908 | }, 2909 | "which-module": { 2910 | "version": "1.0.0", 2911 | "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", 2912 | "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", 2913 | "dev": true 2914 | }, 2915 | "window-size": { 2916 | "version": "0.1.0", 2917 | "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", 2918 | "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", 2919 | "dev": true, 2920 | "optional": true 2921 | }, 2922 | "wordwrap": { 2923 | "version": "0.0.3", 2924 | "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", 2925 | "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", 2926 | "dev": true 2927 | }, 2928 | "worker-farm": { 2929 | "version": "1.5.0", 2930 | "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.5.0.tgz", 2931 | "integrity": "sha512-DHRiUggxtbruaTwnLDm2/BRDKZIoOYvrgYUj5Bam4fU6Gtvc0FaEyoswFPBjMXAweGW2H4BDNIpy//1yXXuaqQ==", 2932 | "dev": true, 2933 | "requires": { 2934 | "errno": "0.1.4", 2935 | "xtend": "4.0.1" 2936 | } 2937 | }, 2938 | "wrap-ansi": { 2939 | "version": "2.1.0", 2940 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", 2941 | "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", 2942 | "dev": true, 2943 | "requires": { 2944 | "string-width": "1.0.2", 2945 | "strip-ansi": "3.0.1" 2946 | } 2947 | }, 2948 | "wrappy": { 2949 | "version": "1.0.2", 2950 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 2951 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 2952 | "dev": true 2953 | }, 2954 | "xml-name-validator": { 2955 | "version": "2.0.1", 2956 | "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-2.0.1.tgz", 2957 | "integrity": "sha1-TYuPHszTQZqjYgYb7O9RXh5VljU=", 2958 | "dev": true 2959 | }, 2960 | "xtend": { 2961 | "version": "4.0.1", 2962 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", 2963 | "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", 2964 | "dev": true 2965 | }, 2966 | "y18n": { 2967 | "version": "3.2.1", 2968 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", 2969 | "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", 2970 | "dev": true 2971 | }, 2972 | "yargs": { 2973 | "version": "7.1.0", 2974 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz", 2975 | "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=", 2976 | "dev": true, 2977 | "requires": { 2978 | "camelcase": "3.0.0", 2979 | "cliui": "3.2.0", 2980 | "decamelize": "1.2.0", 2981 | "get-caller-file": "1.0.2", 2982 | "os-locale": "1.4.0", 2983 | "read-pkg-up": "1.0.1", 2984 | "require-directory": "2.1.1", 2985 | "require-main-filename": "1.0.1", 2986 | "set-blocking": "2.0.0", 2987 | "string-width": "1.0.2", 2988 | "which-module": "1.0.0", 2989 | "y18n": "3.2.1", 2990 | "yargs-parser": "5.0.0" 2991 | }, 2992 | "dependencies": { 2993 | "camelcase": { 2994 | "version": "3.0.0", 2995 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", 2996 | "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", 2997 | "dev": true 2998 | }, 2999 | "cliui": { 3000 | "version": "3.2.0", 3001 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", 3002 | "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", 3003 | "dev": true, 3004 | "requires": { 3005 | "string-width": "1.0.2", 3006 | "strip-ansi": "3.0.1", 3007 | "wrap-ansi": "2.1.0" 3008 | } 3009 | } 3010 | } 3011 | }, 3012 | "yargs-parser": { 3013 | "version": "5.0.0", 3014 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz", 3015 | "integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=", 3016 | "dev": true, 3017 | "requires": { 3018 | "camelcase": "3.0.0" 3019 | }, 3020 | "dependencies": { 3021 | "camelcase": { 3022 | "version": "3.0.0", 3023 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", 3024 | "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", 3025 | "dev": true 3026 | } 3027 | } 3028 | } 3029 | } 3030 | } 3031 | --------------------------------------------------------------------------------