micro-memoize
Advanced tools
| // external dependencies | ||
| import { deepEqual } from 'fast-equals'; | ||
| import memoize from '../src'; | ||
| import { isSameValueZero } from '../src/utils'; | ||
| describe('memoize', () => { | ||
| it('will return the function if already memoized', () => { | ||
| const fn = () => {}; | ||
| fn.isMemoized = true; | ||
| const memoized = memoize(fn); | ||
| expect(memoized).toBe(fn); | ||
| }); | ||
| it('will return the memoized function', () => { | ||
| let callCount = 0; | ||
| const fn = (one: any, two: any) => { | ||
| callCount++; | ||
| return { | ||
| one, | ||
| two, | ||
| }; | ||
| }; | ||
| const memoized = memoize(fn); | ||
| expect(memoized.cache).toEqual({ | ||
| keys: [], | ||
| size: 0, | ||
| values: [], | ||
| }); | ||
| expect(memoized.cacheSnapshot).toEqual({ | ||
| keys: [], | ||
| size: 0, | ||
| values: [], | ||
| }); | ||
| expect(memoized.isMemoized).toEqual(true); | ||
| expect(memoized.options).toEqual({ | ||
| isEqual: isSameValueZero, | ||
| isMatchingKey: undefined, | ||
| isPromise: false, | ||
| maxSize: 1, | ||
| transformKey: undefined, | ||
| }); | ||
| new Array(1000).fill('z').forEach(() => { | ||
| const result = memoized('one', 'two'); | ||
| expect(result).toEqual({ | ||
| one: 'one', | ||
| two: 'two', | ||
| }); | ||
| }); | ||
| expect(callCount).toEqual(1); | ||
| expect(memoized.cache).toEqual({ | ||
| keys: [['one', 'two']], | ||
| size: 1, | ||
| values: [ | ||
| { | ||
| one: 'one', | ||
| two: 'two', | ||
| }, | ||
| ], | ||
| }); | ||
| }); | ||
| it('will return the memoized function that can have multiple cached key => value pairs', () => { | ||
| let callCount = 0; | ||
| const fn = (one: any, two: any) => { | ||
| callCount++; | ||
| return { | ||
| one, | ||
| two, | ||
| }; | ||
| }; | ||
| const maxSize = 3; | ||
| const memoized = memoize(fn, { maxSize }); | ||
| expect(memoized.cache).toEqual({ | ||
| keys: [], | ||
| size: 0, | ||
| values: [], | ||
| }); | ||
| expect(memoized.cacheSnapshot).toEqual({ | ||
| keys: [], | ||
| size: 0, | ||
| values: [], | ||
| }); | ||
| expect(memoized.isMemoized).toEqual(true); | ||
| expect(memoized.options.maxSize).toEqual(maxSize); | ||
| expect(memoized('one', 'two')).toEqual({ | ||
| one: 'one', | ||
| two: 'two', | ||
| }); | ||
| expect(memoized('two', 'three')).toEqual({ | ||
| one: 'two', | ||
| two: 'three', | ||
| }); | ||
| expect(memoized('three', 'four')).toEqual({ | ||
| one: 'three', | ||
| two: 'four', | ||
| }); | ||
| expect(memoized('four', 'five')).toEqual({ | ||
| one: 'four', | ||
| two: 'five', | ||
| }); | ||
| expect(memoized('two', 'three')).toEqual({ | ||
| one: 'two', | ||
| two: 'three', | ||
| }); | ||
| expect(memoized('three', 'four')).toEqual({ | ||
| one: 'three', | ||
| two: 'four', | ||
| }); | ||
| expect(callCount).toEqual(4); | ||
| expect(memoized.cache).toEqual({ | ||
| keys: [['three', 'four'], ['two', 'three'], ['four', 'five']], | ||
| size: 3, | ||
| values: [ | ||
| { | ||
| one: 'three', | ||
| two: 'four', | ||
| }, | ||
| { | ||
| one: 'two', | ||
| two: 'three', | ||
| }, | ||
| { | ||
| one: 'four', | ||
| two: 'five', | ||
| }, | ||
| ], | ||
| }); | ||
| }); | ||
| it('will return the memoized function that will use the custom isEqual method', () => { | ||
| let callCount = 0; | ||
| const fn = (one: any, two: any) => { | ||
| callCount++; | ||
| return { | ||
| one, | ||
| two, | ||
| }; | ||
| }; | ||
| const memoized = memoize(fn, { isEqual: deepEqual }); | ||
| expect(memoized.options.isEqual).toBe(deepEqual); | ||
| expect( | ||
| memoized( | ||
| { deep: { value: 'value' } }, | ||
| { other: { deep: { value: 'value' } } }, | ||
| ), | ||
| ).toEqual({ | ||
| one: { deep: { value: 'value' } }, | ||
| two: { other: { deep: { value: 'value' } } }, | ||
| }); | ||
| expect( | ||
| memoized( | ||
| { deep: { value: 'value' } }, | ||
| { other: { deep: { value: 'value' } } }, | ||
| ), | ||
| ).toEqual({ | ||
| one: { deep: { value: 'value' } }, | ||
| two: { other: { deep: { value: 'value' } } }, | ||
| }); | ||
| expect(callCount).toEqual(1); | ||
| expect(memoized.cache).toEqual({ | ||
| keys: [ | ||
| [{ deep: { value: 'value' } }, { other: { deep: { value: 'value' } } }], | ||
| ], | ||
| size: 1, | ||
| values: [ | ||
| { | ||
| one: { deep: { value: 'value' } }, | ||
| two: { other: { deep: { value: 'value' } } }, | ||
| }, | ||
| ], | ||
| }); | ||
| }); | ||
| it('will return the memoized function that will use the transformKey method', () => { | ||
| let callCount = 0; | ||
| const fn = (one: any, two: any) => { | ||
| callCount++; | ||
| return { | ||
| one, | ||
| two, | ||
| }; | ||
| }; | ||
| const transformKey = function (args: any[]) { | ||
| return [JSON.stringify(args)]; | ||
| }; | ||
| const memoized = memoize(fn, { | ||
| transformKey, | ||
| }); | ||
| expect(memoized.options.transformKey).toBe(transformKey); | ||
| const fnArg1 = () => {}; | ||
| const fnArg2 = () => {}; | ||
| const fnArg3 = () => {}; | ||
| expect(memoized({ one: 'one' }, fnArg1)).toEqual({ | ||
| one: { one: 'one' }, | ||
| two: fnArg1, | ||
| }); | ||
| expect(memoized({ one: 'one' }, fnArg2)).toEqual({ | ||
| one: { one: 'one' }, | ||
| two: fnArg1, | ||
| }); | ||
| expect(memoized({ one: 'one' }, fnArg3)).toEqual({ | ||
| one: { one: 'one' }, | ||
| two: fnArg1, | ||
| }); | ||
| expect(callCount).toEqual(1); | ||
| expect(memoized.cache).toEqual({ | ||
| keys: [['[{"one":"one"},null]']], | ||
| size: 1, | ||
| values: [ | ||
| { | ||
| one: { one: 'one' }, | ||
| two: fnArg1, | ||
| }, | ||
| ], | ||
| }); | ||
| }); | ||
| it('will return the memoized function that will use the transformKey method with a custom isEqual', () => { | ||
| let callCount = 0; | ||
| const fn = (one: any, two: any) => { | ||
| callCount++; | ||
| return { | ||
| one, | ||
| two, | ||
| }; | ||
| }; | ||
| const isEqual = function (key1: any, key2: any) { | ||
| return key1.args === key2.args; | ||
| }; | ||
| const transformKey = function (args: any[]) { | ||
| return [ | ||
| { | ||
| args: JSON.stringify(args), | ||
| }, | ||
| ]; | ||
| }; | ||
| const memoized = memoize(fn, { | ||
| isEqual, | ||
| transformKey, | ||
| }); | ||
| expect(memoized.options.isEqual).toBe(isEqual); | ||
| expect(memoized.options.transformKey).toBe(transformKey); | ||
| const fnArg1 = () => {}; | ||
| const fnArg2 = () => {}; | ||
| const fnArg3 = () => {}; | ||
| expect(memoized({ one: 'one' }, fnArg1)).toEqual({ | ||
| one: { one: 'one' }, | ||
| two: fnArg1, | ||
| }); | ||
| expect(memoized({ one: 'one' }, fnArg2)).toEqual({ | ||
| one: { one: 'one' }, | ||
| two: fnArg1, | ||
| }); | ||
| expect(memoized({ one: 'one' }, fnArg3)).toEqual({ | ||
| one: { one: 'one' }, | ||
| two: fnArg1, | ||
| }); | ||
| expect(callCount).toEqual(1); | ||
| expect(memoized.cache).toEqual({ | ||
| keys: [ | ||
| [ | ||
| { | ||
| args: '[{"one":"one"},null]', | ||
| }, | ||
| ], | ||
| ], | ||
| size: 1, | ||
| values: [ | ||
| { | ||
| one: { one: 'one' }, | ||
| two: fnArg1, | ||
| }, | ||
| ], | ||
| }); | ||
| }); | ||
| it('will return a memoized method that will auto-remove the key from cache if isPromise is true and the promise is rejected', async () => { | ||
| const timeout = 200; | ||
| const error = new Error('boom'); | ||
| const fn = async () => { | ||
| await new Promise((resolve: Function) => { | ||
| setTimeout(resolve, timeout); | ||
| }); | ||
| throw error; | ||
| }; | ||
| const isPromise = true; | ||
| const memoized = memoize(fn, { isPromise }); | ||
| expect(memoized.options.isPromise).toEqual(isPromise); | ||
| const spy = jest.fn(); | ||
| memoized('foo').catch(spy); | ||
| expect(memoized.cacheSnapshot.keys.length).toEqual(1); | ||
| expect(memoized.cacheSnapshot.values.length).toEqual(1); | ||
| await new Promise((resolve: Function) => { | ||
| setTimeout(resolve, timeout + 50); | ||
| }); | ||
| expect(memoized.cacheSnapshot).toEqual({ | ||
| keys: [], | ||
| size: 0, | ||
| values: [], | ||
| }); | ||
| expect(spy).toHaveBeenCalledTimes(1); | ||
| expect(spy).toHaveBeenCalledWith(error); | ||
| }); | ||
| it('will fire the onCacheChange method passed with the cache when it is added to', () => { | ||
| const fn = (one: any, two: any) => ({ | ||
| one, | ||
| two, | ||
| }); | ||
| const onCacheChange = jest.fn(); | ||
| const memoized = memoize(fn, { onCacheChange }); | ||
| expect(memoized.options.onCacheChange).toBe(onCacheChange); | ||
| memoized('foo'); | ||
| expect(onCacheChange).toHaveBeenCalledTimes(1); | ||
| expect(onCacheChange).toHaveBeenCalledWith( | ||
| memoized.cache, | ||
| { | ||
| onCacheChange, | ||
| isEqual: isSameValueZero, | ||
| isMatchingKey: undefined, | ||
| isPromise: false, | ||
| maxSize: 1, | ||
| transformKey: undefined, | ||
| }, | ||
| memoized, | ||
| ); | ||
| }); | ||
| it('will fire the onCacheChange method passed with the cache when it is updated', () => { | ||
| const fn = (one: any, two: any) => ({ | ||
| one, | ||
| two, | ||
| }); | ||
| const onCacheChange = jest.fn(); | ||
| const maxSize = 2; | ||
| const memoized = memoize(fn, { | ||
| maxSize, | ||
| onCacheChange, | ||
| }); | ||
| expect(memoized.options.onCacheChange).toBe(onCacheChange); | ||
| memoized('foo', 'bar'); | ||
| expect(onCacheChange).toHaveBeenCalledTimes(1); | ||
| expect(onCacheChange).toHaveBeenCalledWith( | ||
| { | ||
| keys: [['foo', 'bar']], | ||
| size: 1, | ||
| values: [ | ||
| { | ||
| one: 'foo', | ||
| two: 'bar', | ||
| }, | ||
| ], | ||
| }, | ||
| { | ||
| maxSize, | ||
| onCacheChange, | ||
| isEqual: isSameValueZero, | ||
| isMatchingKey: undefined, | ||
| isPromise: false, | ||
| transformKey: undefined, | ||
| }, | ||
| memoized, | ||
| ); | ||
| onCacheChange.mockReset(); | ||
| memoized('bar', 'foo'); | ||
| expect(onCacheChange).toHaveBeenCalledTimes(1); | ||
| expect(onCacheChange).toHaveBeenCalledWith( | ||
| { | ||
| keys: [['bar', 'foo'], ['foo', 'bar']], | ||
| size: 2, | ||
| values: [ | ||
| { | ||
| one: 'bar', | ||
| two: 'foo', | ||
| }, | ||
| { | ||
| one: 'foo', | ||
| two: 'bar', | ||
| }, | ||
| ], | ||
| }, | ||
| { | ||
| maxSize, | ||
| onCacheChange, | ||
| isEqual: isSameValueZero, | ||
| isMatchingKey: undefined, | ||
| isPromise: false, | ||
| transformKey: undefined, | ||
| }, | ||
| memoized, | ||
| ); | ||
| onCacheChange.mockReset(); | ||
| memoized('bar', 'foo'); | ||
| expect(onCacheChange).toHaveBeenCalledTimes(0); | ||
| onCacheChange.mockReset(); | ||
| memoized('foo', 'bar'); | ||
| expect(onCacheChange).toHaveBeenCalledTimes(1); | ||
| expect(onCacheChange).toHaveBeenCalledWith( | ||
| { | ||
| keys: [['foo', 'bar'], ['bar', 'foo']], | ||
| size: 2, | ||
| values: [ | ||
| { | ||
| one: 'foo', | ||
| two: 'bar', | ||
| }, | ||
| { | ||
| one: 'bar', | ||
| two: 'foo', | ||
| }, | ||
| ], | ||
| }, | ||
| { | ||
| maxSize, | ||
| onCacheChange, | ||
| isEqual: isSameValueZero, | ||
| isMatchingKey: undefined, | ||
| isPromise: false, | ||
| transformKey: undefined, | ||
| }, | ||
| memoized, | ||
| ); | ||
| onCacheChange.mockReset(); | ||
| memoized('foo', 'bar'); | ||
| expect(onCacheChange).toHaveBeenCalledTimes(0); | ||
| }); | ||
| it('will not fire the onCacheHit method passed with the cache when it is added to', () => { | ||
| const fn = (one: any, two: any) => ({ | ||
| one, | ||
| two, | ||
| }); | ||
| const onCacheHit = jest.fn(); | ||
| const memoized = memoize(fn, { onCacheHit }); | ||
| expect(memoized.options.onCacheHit).toBe(onCacheHit); | ||
| memoized('foo'); | ||
| expect(onCacheHit).toHaveBeenCalledTimes(0); | ||
| }); | ||
| it('will fire the onCacheHit method passed with the cache when it is updated', () => { | ||
| const fn = (one: any, two: any) => ({ | ||
| one, | ||
| two, | ||
| }); | ||
| const onCacheHit = jest.fn(); | ||
| const maxSize = 2; | ||
| const memoized = memoize(fn, { | ||
| maxSize, | ||
| onCacheHit, | ||
| }); | ||
| expect(memoized.options.onCacheHit).toBe(onCacheHit); | ||
| memoized('foo', 'bar'); | ||
| expect(onCacheHit).toHaveBeenCalledTimes(0); | ||
| memoized('bar', 'foo'); | ||
| expect(onCacheHit).toHaveBeenCalledTimes(0); | ||
| memoized('bar', 'foo'); | ||
| expect(onCacheHit).toHaveBeenCalledTimes(1); | ||
| expect(onCacheHit).toHaveBeenCalledWith( | ||
| { | ||
| keys: [['bar', 'foo'], ['foo', 'bar']], | ||
| size: 2, | ||
| values: [ | ||
| { | ||
| one: 'bar', | ||
| two: 'foo', | ||
| }, | ||
| { | ||
| one: 'foo', | ||
| two: 'bar', | ||
| }, | ||
| ], | ||
| }, | ||
| { | ||
| maxSize, | ||
| onCacheHit, | ||
| isEqual: isSameValueZero, | ||
| isMatchingKey: undefined, | ||
| isPromise: false, | ||
| transformKey: undefined, | ||
| }, | ||
| memoized, | ||
| ); | ||
| onCacheHit.mockReset(); | ||
| memoized('foo', 'bar'); | ||
| expect(onCacheHit).toHaveBeenCalledTimes(1); | ||
| expect(onCacheHit).toHaveBeenCalledWith( | ||
| { | ||
| keys: [['foo', 'bar'], ['bar', 'foo']], | ||
| size: 2, | ||
| values: [ | ||
| { | ||
| one: 'foo', | ||
| two: 'bar', | ||
| }, | ||
| { | ||
| one: 'bar', | ||
| two: 'foo', | ||
| }, | ||
| ], | ||
| }, | ||
| { | ||
| maxSize, | ||
| onCacheHit, | ||
| isEqual: isSameValueZero, | ||
| isMatchingKey: undefined, | ||
| isPromise: false, | ||
| transformKey: undefined, | ||
| }, | ||
| memoized, | ||
| ); | ||
| onCacheHit.mockReset(); | ||
| memoized('foo', 'bar'); | ||
| expect(onCacheHit).toHaveBeenCalledTimes(1); | ||
| expect(onCacheHit).toHaveBeenCalledWith( | ||
| { | ||
| keys: [['foo', 'bar'], ['bar', 'foo']], | ||
| size: 2, | ||
| values: [ | ||
| { | ||
| one: 'foo', | ||
| two: 'bar', | ||
| }, | ||
| { | ||
| one: 'bar', | ||
| two: 'foo', | ||
| }, | ||
| ], | ||
| }, | ||
| { | ||
| maxSize, | ||
| onCacheHit, | ||
| isEqual: isSameValueZero, | ||
| isMatchingKey: undefined, | ||
| isPromise: false, | ||
| transformKey: undefined, | ||
| }, | ||
| memoized, | ||
| ); | ||
| }); | ||
| it('will fire the onCacheAdd method passed with the cache when it is added but not when hit', () => { | ||
| const fn = (one: any, two: any) => ({ | ||
| one, | ||
| two, | ||
| }); | ||
| const onCacheAdd = jest.fn(); | ||
| const memoized = memoize(fn, { onCacheAdd }); | ||
| expect(memoized.options.onCacheAdd).toBe(onCacheAdd); | ||
| memoized('foo'); | ||
| expect(onCacheAdd).toHaveBeenCalledTimes(1); | ||
| memoized('foo'); | ||
| expect(onCacheAdd).toHaveBeenCalledTimes(1); | ||
| }); | ||
| it('will fire the onCacheAdd method passed with the cache when it is added but never again', () => { | ||
| const fn = (one: any, two: any) => ({ | ||
| one, | ||
| two, | ||
| }); | ||
| const onCacheAdd = jest.fn(); | ||
| const maxSize = 2; | ||
| const memoized = memoize(fn, { | ||
| maxSize, | ||
| onCacheAdd, | ||
| }); | ||
| expect(memoized.options.onCacheAdd).toBe(onCacheAdd); | ||
| memoized('foo', 'bar'); | ||
| expect(onCacheAdd).toHaveBeenCalledTimes(1); | ||
| expect(onCacheAdd).toHaveBeenCalledWith( | ||
| { | ||
| keys: [['foo', 'bar']], | ||
| size: 1, | ||
| values: [ | ||
| { | ||
| one: 'foo', | ||
| two: 'bar', | ||
| }, | ||
| ], | ||
| }, | ||
| { | ||
| maxSize, | ||
| onCacheAdd, | ||
| isEqual: isSameValueZero, | ||
| isMatchingKey: undefined, | ||
| isPromise: false, | ||
| transformKey: undefined, | ||
| }, | ||
| memoized, | ||
| ); | ||
| onCacheAdd.mockReset(); | ||
| memoized('bar', 'foo'); | ||
| expect(onCacheAdd).toHaveBeenCalledTimes(1); | ||
| expect(onCacheAdd).toHaveBeenCalledWith( | ||
| { | ||
| keys: [['bar', 'foo'], ['foo', 'bar']], | ||
| size: 2, | ||
| values: [ | ||
| { | ||
| one: 'bar', | ||
| two: 'foo', | ||
| }, | ||
| { | ||
| one: 'foo', | ||
| two: 'bar', | ||
| }, | ||
| ], | ||
| }, | ||
| { | ||
| maxSize, | ||
| onCacheAdd, | ||
| isEqual: isSameValueZero, | ||
| isMatchingKey: undefined, | ||
| isPromise: false, | ||
| transformKey: undefined, | ||
| }, | ||
| memoized, | ||
| ); | ||
| onCacheAdd.mockReset(); | ||
| memoized('bar', 'foo'); | ||
| expect(onCacheAdd).toHaveBeenCalledTimes(0); | ||
| onCacheAdd.mockReset(); | ||
| memoized('foo', 'bar'); | ||
| expect(onCacheAdd).toHaveBeenCalledTimes(0); | ||
| memoized('foo', 'bar'); | ||
| expect(onCacheAdd).toHaveBeenCalledTimes(0); | ||
| }); | ||
| test('if recursive calls to self will be respected at runtime', () => { | ||
| const calc = memoize( | ||
| (object: { [key: string]: any }, metadata: { c: number }) => | ||
| Object.keys(object).reduce((totals: { [key: string]: number }, key) => { | ||
| if (Array.isArray(object[key])) { | ||
| totals[key] = object[key].map( | ||
| (subObject: { [key: string]: number }) => | ||
| calc(subObject, metadata), | ||
| ); | ||
| } else { | ||
| totals[key] = object[key].a + object[key].b + metadata.c; | ||
| } | ||
| return totals; | ||
| }, {}), | ||
| { | ||
| maxSize: 10, | ||
| }, | ||
| ); | ||
| const data = { | ||
| fifth: { | ||
| a: 4, | ||
| b: 5, | ||
| }, | ||
| first: [ | ||
| { | ||
| second: { | ||
| a: 1, | ||
| b: 2, | ||
| }, | ||
| }, | ||
| { | ||
| third: [ | ||
| { | ||
| fourth: { | ||
| a: 2, | ||
| b: 3, | ||
| }, | ||
| }, | ||
| ], | ||
| }, | ||
| ], | ||
| }; | ||
| const metadata = { | ||
| c: 6, | ||
| }; | ||
| const result1 = calc(data, metadata); | ||
| const result2 = calc(data, metadata); | ||
| expect(result1).toEqual(result2); | ||
| }); | ||
| }); |
| import { | ||
| createAreKeysEqual, | ||
| createGetKeyIndex, | ||
| createUpdateAsyncCache, | ||
| isSameValueZero, | ||
| mergeOptions, | ||
| orderByLru, | ||
| } from '../src/utils'; | ||
| describe('areKeysEqual', () => { | ||
| it('will return false when the length of the keys are different', () => { | ||
| const isEqual = (o1: any, o2: any) => o1 === o2; | ||
| const areKeysEqual = createAreKeysEqual(isEqual); | ||
| const keys1: any[] = []; | ||
| const keys2 = ['key']; | ||
| expect(areKeysEqual(keys1, keys2)).toEqual(false); | ||
| }); | ||
| it('will return false when the keys have different values', () => { | ||
| const isEqual = (o1: any, o2: any) => o1 === o2; | ||
| const areKeysEqual = createAreKeysEqual(isEqual); | ||
| const keys1 = ['key']; | ||
| const keys2 = ['other key']; | ||
| expect(areKeysEqual(keys1, keys2)).toEqual(false); | ||
| }); | ||
| it('will return true when the keys have equal values', () => { | ||
| const isEqual = (o1: any, o2: any) => o1 === o2; | ||
| const areKeysEqual = createAreKeysEqual(isEqual); | ||
| const keys1 = ['key']; | ||
| const keys2 = ['key']; | ||
| expect(areKeysEqual(keys1, keys2)).toEqual(true); | ||
| }); | ||
| }); | ||
| describe('getKeyIndex', () => { | ||
| it('will return the index of the match found', () => { | ||
| const isEqual = (o1: any, o2: any) => o1 === o2; | ||
| const getKeyIndex = createGetKeyIndex({ isEqual, maxSize: 2 }); | ||
| const allKeys = [['key'], ['other key']]; | ||
| const keyToMatch = ['other key']; | ||
| const result = getKeyIndex(allKeys, keyToMatch); | ||
| expect(result).toEqual(1); | ||
| }); | ||
| it('will return -1 of no match found', () => { | ||
| const isEqual = (o1: any, o2: any) => o1 === o2; | ||
| const getKeyIndex = createGetKeyIndex({ isEqual }); | ||
| const allKeys = [['key'], ['other key']]; | ||
| const keyToMatch = ['not present key']; | ||
| const result = getKeyIndex(allKeys, keyToMatch); | ||
| expect(result).toEqual(-1); | ||
| }); | ||
| it('will use the isMatchingKey method if passed', () => { | ||
| const isEqual = (o1: any, o2: any) => o1 === o2; | ||
| const isMatchingKey = (o1: any, o2: any) => { | ||
| const existingKey = o1[0]; | ||
| const key = o2[0]; | ||
| return ( | ||
| existingKey.hasOwnProperty('foo') && | ||
| key.hasOwnProperty('foo') && | ||
| (existingKey.bar === 'bar' || key.bar === 'baz') | ||
| ); | ||
| }; | ||
| const getKeyIndex = createGetKeyIndex({ isEqual, isMatchingKey }); | ||
| const allKeys = [ | ||
| [ | ||
| { | ||
| bar: 'bar', | ||
| foo: 'foo', | ||
| }, | ||
| ], | ||
| ]; | ||
| const keyToMatch = [ | ||
| { | ||
| bar: 'baz', | ||
| foo: 'bar', | ||
| }, | ||
| ]; | ||
| const result = getKeyIndex(allKeys, keyToMatch); | ||
| expect(result).toEqual(0); | ||
| }); | ||
| }); | ||
| describe('isSameValueZero', () => { | ||
| it('will return true when the objects are equal', () => { | ||
| const object1 = {}; | ||
| const object2 = object1; | ||
| expect(isSameValueZero(object1, object2)).toEqual(true); | ||
| }); | ||
| it('will return true when the objects are NaN', () => { | ||
| const object1 = NaN; | ||
| const object2 = NaN; | ||
| expect(isSameValueZero(object1, object2)).toEqual(true); | ||
| }); | ||
| it('will return false when the objects are different', () => { | ||
| const object1 = {}; | ||
| const object2 = {}; | ||
| expect(isSameValueZero(object1, object2)).toEqual(false); | ||
| }); | ||
| }); | ||
| describe('mergeOptions', () => { | ||
| it('will merge the extra and provided options into a new object', () => { | ||
| const extraOptions = { | ||
| extra: 'options', | ||
| }; | ||
| const providedOptions = { | ||
| provided: 'options', | ||
| }; | ||
| const result = mergeOptions(extraOptions, providedOptions); | ||
| expect(result).not.toBe(extraOptions); | ||
| expect(result).not.toBe(providedOptions); | ||
| expect(result).toEqual({ ...extraOptions, ...providedOptions }); | ||
| }); | ||
| }); | ||
| describe('orderByLru', () => { | ||
| it('will do nothing if the itemIndex is 0', () => { | ||
| const cache = { | ||
| keys: [['first'], ['second'], ['third']], | ||
| size: 3, | ||
| values: ['first', 'second', 'third'], | ||
| }; | ||
| const itemIndex = 0; | ||
| const key = cache.keys[itemIndex]; | ||
| const value = cache.values[itemIndex]; | ||
| const maxSize = 3; | ||
| orderByLru(cache, key, value, itemIndex, maxSize); | ||
| expect(cache).toEqual({ | ||
| ...cache, | ||
| keys: [['first'], ['second'], ['third']], | ||
| values: ['first', 'second', 'third'], | ||
| }); | ||
| }); | ||
| it('will place the itemIndex first in order when non-zero', () => { | ||
| const cache = { | ||
| keys: [['first'], ['second'], ['third']], | ||
| size: 3, | ||
| values: ['first', 'second', 'third'], | ||
| }; | ||
| const itemIndex = 1; | ||
| const key = cache.keys[itemIndex]; | ||
| const value = cache.values[itemIndex]; | ||
| const maxSize = 3; | ||
| orderByLru(cache, key, value, itemIndex, maxSize); | ||
| expect(cache).toEqual({ | ||
| ...cache, | ||
| keys: [['second'], ['first'], ['third']], | ||
| values: ['second', 'first', 'third'], | ||
| }); | ||
| }); | ||
| it('will add the new item to the array when the itemIndex is the array length', () => { | ||
| const cache = { | ||
| keys: [['first'], ['second'], ['third']], | ||
| size: 3, | ||
| values: ['first', 'second', 'third'], | ||
| }; | ||
| const itemIndex = cache.keys.length; | ||
| const key = ['key']; | ||
| const value = 'new'; | ||
| const maxSize = 4; | ||
| orderByLru(cache, key, value, itemIndex, maxSize); | ||
| expect(cache).toEqual({ | ||
| ...cache, | ||
| keys: [key, ['first'], ['second'], ['third']], | ||
| values: [value, 'first', 'second', 'third'], | ||
| }); | ||
| }); | ||
| }); | ||
| describe('updateAsyncCache', () => { | ||
| it('will fire cache callbacks if resolved', async () => { | ||
| const timeout = 200; | ||
| const fn = async () => { | ||
| await new Promise((resolve: Function) => { | ||
| setTimeout(resolve, timeout); | ||
| }); | ||
| return 'resolved'; | ||
| }; | ||
| const key = ['foo']; | ||
| const memoized = () => {}; | ||
| const value = fn(); | ||
| const cache = { | ||
| keys: [key], | ||
| size: 1, | ||
| values: [value], | ||
| }; | ||
| const options = { | ||
| isEqual: isSameValueZero, | ||
| onCacheChange: jest.fn(), | ||
| onCacheHit: jest.fn(), | ||
| }; | ||
| createUpdateAsyncCache(options)(cache, memoized); | ||
| // this is just to prevent the unhandled rejection noise | ||
| cache.values[0].catch(() => {}); | ||
| expect(cache.keys.length).toEqual(1); | ||
| expect(cache.values.length).toEqual(1); | ||
| expect(cache.values[0]).toEqual(value); | ||
| await new Promise((resolve: Function) => { | ||
| setTimeout(resolve, timeout + 50); | ||
| }); | ||
| expect(cache.keys.length).toEqual(1); | ||
| expect(cache.values.length).toEqual(1); | ||
| expect(cache.values[0]).toEqual(value); | ||
| expect(options.onCacheHit).toHaveBeenCalledTimes(1); | ||
| expect(options.onCacheHit).toHaveBeenCalledWith(cache, options, memoized); | ||
| expect(options.onCacheChange).toHaveBeenCalledTimes(1); | ||
| expect(options.onCacheChange).toHaveBeenCalledWith( | ||
| cache, | ||
| options, | ||
| memoized, | ||
| ); | ||
| }); | ||
| it('will remove the key from cache when the promise is rejected', async () => { | ||
| const timeout = 200; | ||
| const fn = async () => { | ||
| await new Promise((resolve: Function, reject: Function) => { | ||
| setTimeout(() => reject(new Error('boom')), timeout); | ||
| }); | ||
| }; | ||
| const key = ['foo']; | ||
| const value = fn(); | ||
| const cache = { | ||
| get size() { | ||
| return cache.keys.length; | ||
| }, | ||
| keys: [key], | ||
| values: [value], | ||
| }; | ||
| const options = { | ||
| isEqual: isSameValueZero, | ||
| onCacheChange: jest.fn(), | ||
| onCacheHit: jest.fn(), | ||
| }; | ||
| const memoized = () => {}; | ||
| createUpdateAsyncCache(options)(cache, memoized); | ||
| const catcher = jest.fn(); | ||
| cache.values[0].catch(catcher); | ||
| expect(cache.keys.length).toEqual(1); | ||
| expect(cache.values.length).toEqual(1); | ||
| expect(cache.values[0]).toEqual(value); | ||
| await new Promise((resolve: Function) => { | ||
| setTimeout(resolve, timeout + 50); | ||
| }); | ||
| expect(catcher).toHaveBeenCalledTimes(1); | ||
| expect(cache).toEqual({ | ||
| keys: [], | ||
| size: 0, | ||
| values: [], | ||
| }); | ||
| expect(options.onCacheHit).toHaveBeenCalledTimes(0); | ||
| expect(options.onCacheChange).toHaveBeenCalledTimes(0); | ||
| }); | ||
| it('will not remove the key from cache when the promise is rejected but the key no longer exists', async () => { | ||
| const timeout = 200; | ||
| const fn = async () => { | ||
| await new Promise((resolve: Function, reject: Function) => { | ||
| setTimeout(() => reject(new Error('boom')), timeout); | ||
| }); | ||
| }; | ||
| const key = ['foo']; | ||
| const value = fn(); | ||
| const cache = { | ||
| get size() { | ||
| return cache.keys.length; | ||
| }, | ||
| keys: [key], | ||
| values: [value], | ||
| }; | ||
| const options = { | ||
| isEqual: isSameValueZero, | ||
| onCacheChange: jest.fn(), | ||
| onCacheHit: jest.fn(), | ||
| }; | ||
| const memoized = () => {}; | ||
| createUpdateAsyncCache(options)(cache, memoized); | ||
| const newValue = cache.values[0]; | ||
| const catcher = jest.fn(); | ||
| newValue.catch(catcher); | ||
| expect(cache.keys.length).toEqual(1); | ||
| expect(cache.values.length).toEqual(1); | ||
| expect(cache.values[0]).toEqual(value); | ||
| cache.keys = [['bar']]; | ||
| // @ts-ignore | ||
| cache.values = [Promise.resolve('baz')]; | ||
| await new Promise((resolve: Function) => { | ||
| setTimeout(resolve, timeout + 50); | ||
| }); | ||
| expect(catcher).toHaveBeenCalledTimes(1); | ||
| expect(options.onCacheHit).toHaveBeenCalledTimes(0); | ||
| expect(options.onCacheChange).toHaveBeenCalledTimes(0); | ||
| }); | ||
| }); |
| /* | ||
| * memoize.js | ||
| * by @philogb and @addyosmani | ||
| * with further optimizations by @mathias | ||
| * and @DmitryBaranovsk | ||
| * perf tests: http://bit.ly/q3zpG3 | ||
| * Released under an MIT license. | ||
| */ | ||
| module.exports = function memoize(fn) { | ||
| return function(...args) { | ||
| let index = args.length, | ||
| hash = '', | ||
| currentArg = null; | ||
| currentArg = null; | ||
| while (index--) { | ||
| currentArg = args[index]; | ||
| hash += currentArg === Object(currentArg) ? JSON.stringify(currentArg) : currentArg; | ||
| fn.memoize || (fn.memoize = {}); | ||
| } | ||
| return hash in fn.memoize ? fn.memoize[hash] : (fn.memoize[hash] = fn.apply(this, args)); | ||
| }; | ||
| }; |
| "Name","Overall (average)","Single (average)","Multiple (average)","single primitive","single array","single object","multiple primitive","multiple array","multiple object" | ||
| "micro-memoize","43,702,165","51,789,026","35,615,304","57,637,984","48,611,399","49,117,695","40,849,760","29,961,958","36,034,196" | ||
| "fast-memoize","39,957,140","78,949,201","965,078","233,789,537","1,585,949","1,472,119","1,158,875","946,388","789,972" | ||
| "lodash","14,320,798","27,508,254","1,133,342","32,669,251","24,892,558","24,962,953","1,402,261","1,128,886","868,879" | ||
| "memoizee","9,861,157","11,784,109","7,938,205","16,177,336","9,568,376","9,606,616","9,482,240","7,186,371","7,146,006" | ||
| "ramda","8,678,762","16,102,353","1,255,172","42,919,616","2,907,167","2,480,276","1,550,152","1,222,321","993,044" | ||
| "lru-memoize","7,034,405","7,537,900","6,530,910","8,516,137","7,057,588","7,039,977","6,584,528","6,474,194","6,534,009" | ||
| "mem","6,718,548","11,530,426","1,906,669","30,316,899","2,240,383","2,033,998","2,705,018","1,849,057","1,165,934" | ||
| "underscore","5,014,181","8,820,887","1,207,475","21,489,781","2,673,530","2,299,352","1,479,025","1,183,156","960,246" | ||
| "addy-osmani","4,968,346","7,410,673","2,526,020","17,391,341","2,599,855","2,240,823","5,104,651","1,423,365","1,050,046" | ||
| "memoizerific","4,665,606","5,187,389","4,143,824","5,466,050","5,057,754","5,038,363","4,013,486","4,198,578","4,219,410" |
| const _ = require('lodash'); | ||
| // const fs = require("fs"); | ||
| const React = require('react'); | ||
| const { createSuite } = require('benchee'); | ||
| const Table = require('cli-table2'); | ||
| const resolveArguments = function() { | ||
| return arguments.length > 1 | ||
| ? JSON.stringify(arguments) | ||
| : typeof arguments[0] === 'object' | ||
| ? JSON.stringify(arguments[0]) | ||
| : arguments[0]; | ||
| }; | ||
| const getResults = results => { | ||
| const table = new Table({ | ||
| head: ['Name', 'Ops / sec'], | ||
| }); | ||
| results.forEach(({ name, stats }) => { | ||
| table.push([name, stats.ops.toLocaleString()]); | ||
| }); | ||
| return table.toString(); | ||
| }; | ||
| const addyOsmani = require('./addy-osmani'); | ||
| const fastMemoize = require('fast-memoize'); | ||
| const lodash = _.memoize; | ||
| const lruMemoize = require('lru-memoize').default; | ||
| const mem = require('mem'); | ||
| const memoizee = require('memoizee'); | ||
| const memoizerific = require('memoizerific'); | ||
| const memoize = | ||
| require('../dist/micro-memoize.cjs').default || | ||
| require('../dist/micro-memoize.cjs'); | ||
| const ramda = require('ramda').memoizeWith(resolveArguments); | ||
| const underscore = require('underscore').memoize; | ||
| const deepEqualFastEquals = require('fast-equals').deepEqual; | ||
| const deepEqualLodash = _.isEqual; | ||
| /************* tests *************/ | ||
| const fibonacciSinglePrimitive = number => | ||
| number < 2 | ||
| ? number | ||
| : fibonacciSinglePrimitive(number - 1) + | ||
| fibonacciSinglePrimitive(number - 2); | ||
| const fibonacciSingleArray = array => | ||
| array[0] < 2 | ||
| ? array[0] | ||
| : fibonacciSingleArray([array[0] - 1]) + | ||
| fibonacciSingleArray([array[0] - 2]); | ||
| const fibonacciSingleObject = object => | ||
| object.number < 2 | ||
| ? object.number | ||
| : fibonacciSingleObject({ number: object.number - 1 }) + | ||
| fibonacciSingleObject({ number: object.number - 2 }); | ||
| const fibonacciMultiplePrimitive = (number, isComplete) => { | ||
| if (isComplete) { | ||
| return number; | ||
| } | ||
| const firstValue = number - 1; | ||
| const secondValue = number - 2; | ||
| return ( | ||
| fibonacciMultiplePrimitive(firstValue, firstValue < 2) + | ||
| fibonacciMultiplePrimitive(secondValue, secondValue < 2) | ||
| ); | ||
| }; | ||
| const fibonacciMultipleArray = (array, check) => { | ||
| if (check[0]) { | ||
| return array[0]; | ||
| } | ||
| const firstValue = array[0] - 1; | ||
| const secondValue = array[0] - 2; | ||
| return ( | ||
| fibonacciMultipleArray([firstValue], [firstValue < 2]) + | ||
| fibonacciMultipleArray([secondValue], [secondValue < 2]) | ||
| ); | ||
| }; | ||
| const fibonacciMultipleObject = (object, check) => { | ||
| if (check.isComplete) { | ||
| return object.number; | ||
| } | ||
| const firstValue = object.number - 1; | ||
| const secondValue = object.number - 2; | ||
| return ( | ||
| fibonacciMultipleObject( | ||
| { number: firstValue }, | ||
| { isComplete: firstValue < 2 }, | ||
| ) + | ||
| fibonacciMultipleObject( | ||
| { number: secondValue }, | ||
| { isComplete: secondValue < 2 }, | ||
| ) | ||
| ); | ||
| }; | ||
| /************* benchmarks *************/ | ||
| const singularPrimitive = { | ||
| 'addy osmani': addyOsmani(fibonacciSinglePrimitive), | ||
| 'fast-memoize': fastMemoize(fibonacciSinglePrimitive), | ||
| lodash: lodash(fibonacciSinglePrimitive), | ||
| 'lru-memoize': lruMemoize(1)(fibonacciSinglePrimitive), | ||
| mem: mem(fibonacciSinglePrimitive), | ||
| memoizee: memoizee(fibonacciSinglePrimitive), | ||
| memoizerific: memoizerific(1)(fibonacciSinglePrimitive), | ||
| 'micro-memoize': memoize(fibonacciSinglePrimitive), | ||
| ramda: ramda(fibonacciSinglePrimitive), | ||
| underscore: underscore(fibonacciSinglePrimitive), | ||
| }; | ||
| const singularArray = { | ||
| 'addy osmani': addyOsmani(fibonacciSingleArray), | ||
| 'fast-memoize': fastMemoize(fibonacciSingleArray), | ||
| lodash: lodash(fibonacciSingleArray), | ||
| 'lru-memoize': lruMemoize(1)(fibonacciSingleArray), | ||
| mem: mem(fibonacciSingleArray), | ||
| memoizee: memoizee(fibonacciSingleArray), | ||
| memoizerific: memoizerific(1)(fibonacciSingleArray), | ||
| 'micro-memoize': memoize(fibonacciSingleArray), | ||
| ramda: ramda(fibonacciSingleArray), | ||
| underscore: underscore(fibonacciSingleArray, resolveArguments), | ||
| }; | ||
| const singularObject = { | ||
| 'addy osmani': addyOsmani(fibonacciSingleObject), | ||
| 'fast-memoize': fastMemoize(fibonacciSingleObject), | ||
| lodash: lodash(fibonacciSingleObject), | ||
| 'lru-memoize': lruMemoize(1)(fibonacciSingleObject), | ||
| mem: mem(fibonacciSingleObject), | ||
| memoizee: memoizee(fibonacciSingleObject), | ||
| memoizerific: memoizerific(1)(fibonacciSingleObject), | ||
| 'micro-memoize': memoize(fibonacciSingleObject), | ||
| ramda: ramda(fibonacciSingleObject), | ||
| underscore: underscore(fibonacciSingleObject, resolveArguments), | ||
| }; | ||
| const multiplePrimitive = { | ||
| 'addy osmani': addyOsmani(fibonacciMultiplePrimitive), | ||
| 'fast-memoize': fastMemoize(fibonacciMultiplePrimitive), | ||
| lodash: lodash(fibonacciMultiplePrimitive, resolveArguments), | ||
| 'lru-memoize': lruMemoize(1)(fibonacciMultiplePrimitive), | ||
| mem: mem(fibonacciMultiplePrimitive), | ||
| memoizee: memoizee(fibonacciMultiplePrimitive), | ||
| memoizerific: memoizerific(1)(fibonacciMultiplePrimitive), | ||
| 'micro-memoize': memoize(fibonacciMultiplePrimitive), | ||
| ramda: ramda(fibonacciMultiplePrimitive), | ||
| underscore: underscore(fibonacciMultiplePrimitive, resolveArguments), | ||
| }; | ||
| const multipleArray = { | ||
| 'addy osmani': addyOsmani(fibonacciMultipleArray), | ||
| 'fast-memoize': fastMemoize(fibonacciMultipleArray), | ||
| lodash: lodash(fibonacciMultipleArray, resolveArguments), | ||
| 'lru-memoize': lruMemoize(1)(fibonacciMultipleArray), | ||
| mem: mem(fibonacciMultipleArray), | ||
| memoizee: memoizee(fibonacciMultipleArray), | ||
| memoizerific: memoizerific(1)(fibonacciMultipleArray), | ||
| 'micro-memoize': memoize(fibonacciMultipleArray), | ||
| ramda: ramda(fibonacciMultipleArray), | ||
| underscore: underscore(fibonacciMultipleArray, resolveArguments), | ||
| }; | ||
| const multipleObject = { | ||
| 'addy osmani': addyOsmani(fibonacciMultipleObject), | ||
| 'fast-memoize': fastMemoize(fibonacciMultipleObject), | ||
| lodash: lodash(fibonacciMultipleObject, resolveArguments), | ||
| 'lru-memoize': lruMemoize(1)(fibonacciMultipleObject), | ||
| mem: mem(fibonacciMultipleObject), | ||
| memoizee: memoizee(fibonacciMultipleObject), | ||
| memoizerific: memoizerific(1)(fibonacciMultipleObject), | ||
| 'micro-memoize': memoize(fibonacciMultipleObject), | ||
| ramda: ramda(fibonacciMultipleObject), | ||
| underscore: underscore(fibonacciMultipleObject, resolveArguments), | ||
| }; | ||
| const number = 25; | ||
| const arrayNumber = [number]; | ||
| const objectNumber = { number }; | ||
| const isComplete = false; | ||
| const arrayIsComplete = [isComplete]; | ||
| const objectIsComplete = { isComplete }; | ||
| const suite = createSuite({ | ||
| onComplete(results) { | ||
| const combinedResults = Object.keys(results) | ||
| .reduce((combined, group) => { | ||
| const groupResults = results[group]; | ||
| return groupResults.map(({ name, stats }) => { | ||
| const existingRowIndex = combined.findIndex( | ||
| ({ name: rowName }) => name === rowName, | ||
| ); | ||
| return ~existingRowIndex | ||
| ? { | ||
| ...combined[existingRowIndex], | ||
| stats: { | ||
| elapsed: (combined[existingRowIndex].stats.elapsed += | ||
| stats.elapsed), | ||
| iterations: (combined[existingRowIndex].stats.iterations += | ||
| stats.iterations), | ||
| }, | ||
| } | ||
| : { | ||
| name, | ||
| stats: { | ||
| elapsed: stats.elapsed, | ||
| iterations: stats.iterations, | ||
| }, | ||
| }; | ||
| }); | ||
| }, []) | ||
| .map(({ name, stats }) => ({ | ||
| name, | ||
| stats: { | ||
| ...stats, | ||
| ops: stats.iterations / stats.elapsed, | ||
| }, | ||
| })) | ||
| .sort((a, b) => { | ||
| if (a.stats.ops > b.stats.ops) { | ||
| return -1; | ||
| } | ||
| if (a.stats.ops < b.stats.ops) { | ||
| return 1; | ||
| } | ||
| return 0; | ||
| }); | ||
| console.log(''); | ||
| console.log('Benchmark results complete, overall averages:'); | ||
| console.log(''); | ||
| console.log(getResults(combinedResults)); | ||
| console.log(''); | ||
| }, | ||
| onGroupComplete({ group, results }) { | ||
| console.log(''); | ||
| console.log(`...finished group ${group}.`); | ||
| console.log(''); | ||
| console.log(getResults(results)); | ||
| console.log(''); | ||
| }, | ||
| onGroupStart(group) { | ||
| console.log(''); | ||
| console.log(`Starting benchmarks for group ${group}...`); | ||
| console.log(''); | ||
| }, | ||
| minTime: 3000, | ||
| onResult({ name, stats }) { | ||
| console.log( | ||
| `Benchmark completed for ${name}: ${stats.ops.toLocaleString()} ops/sec`, | ||
| ); | ||
| }, | ||
| }); | ||
| Object.keys(singularPrimitive).forEach(name => { | ||
| const fn = singularPrimitive[name]; | ||
| suite.add(name, 'singular primitive', () => { | ||
| fn(number); | ||
| }); | ||
| }); | ||
| Object.keys(singularArray).forEach(name => { | ||
| const fn = singularArray[name]; | ||
| suite.add(name, 'singular array', () => { | ||
| fn(arrayNumber); | ||
| }); | ||
| }); | ||
| Object.keys(singularObject).forEach(name => { | ||
| const fn = singularObject[name]; | ||
| suite.add(name, 'singular object', () => { | ||
| fn(objectNumber); | ||
| }); | ||
| }); | ||
| Object.keys(multiplePrimitive).forEach(name => { | ||
| const fn = multiplePrimitive[name]; | ||
| suite.add(name, 'multiple primitive', () => { | ||
| fn(number, isComplete); | ||
| }); | ||
| }); | ||
| Object.keys(multipleArray).forEach(name => { | ||
| const fn = multipleArray[name]; | ||
| suite.add(name, 'multiple array', () => { | ||
| fn(arrayNumber, arrayIsComplete); | ||
| }); | ||
| }); | ||
| Object.keys(multipleObject).forEach(name => { | ||
| const fn = multipleObject[name]; | ||
| suite.add(name, 'multiple object', () => { | ||
| fn(objectNumber, objectIsComplete); | ||
| }); | ||
| }); | ||
| suite.run(); |
| 'use strict'; | ||
| const memoize = require('../lib').default; | ||
| const fibonacciSinglePrimitive = (number) => { | ||
| return number < 2 ? number : fibonacciSinglePrimitive(number - 1) + fibonacciSinglePrimitive(number - 2); | ||
| }; | ||
| const fibonacciSingleArray = (array) => { | ||
| return array[0] < 2 ? array[0] : fibonacciSingleArray([array[0] - 1]) + fibonacciSingleArray([array[0] - 2]); | ||
| }; | ||
| const fibonacciSingleObject = (object) => { | ||
| return object.number < 2 | ||
| ? object.number | ||
| : fibonacciSingleObject({number: object.number - 1}) + fibonacciSingleObject({number: object.number - 2}); | ||
| }; | ||
| const fibonacciMultiplePrimitive = (number, isComplete) => { | ||
| if (isComplete) { | ||
| return number; | ||
| } | ||
| const firstValue = number - 1; | ||
| const secondValue = number - 2; | ||
| return ( | ||
| fibonacciMultiplePrimitive(firstValue, firstValue < 2) + fibonacciMultiplePrimitive(secondValue, secondValue < 2) | ||
| ); | ||
| }; | ||
| const fibonacciMultipleArray = (array, check) => { | ||
| if (check[0]) { | ||
| return array[0]; | ||
| } | ||
| const firstValue = array[0] - 1; | ||
| const secondValue = array[0] - 2; | ||
| return ( | ||
| fibonacciMultipleArray([firstValue], [firstValue < 2]) + fibonacciMultipleArray([secondValue], [secondValue < 2]) | ||
| ); | ||
| }; | ||
| const fibonacciMultipleObject = (object, check) => { | ||
| if (check.isComplete) { | ||
| return object.number; | ||
| } | ||
| const firstValue = object.number - 1; | ||
| const secondValue = object.number - 2; | ||
| return ( | ||
| fibonacciMultipleObject({number: firstValue}, {isComplete: firstValue < 2}) + | ||
| fibonacciMultipleObject({number: secondValue}, {isComplete: secondValue < 2}) | ||
| ); | ||
| }; | ||
| const number = 35; | ||
| const array = [number]; | ||
| const object = {number}; | ||
| const isCompleteBoolean = false; | ||
| const isCompleteArray = [false]; | ||
| const isCompleteObject = {isComplete: false}; | ||
| fibonacciSinglePrimitive(number); | ||
| fibonacciSinglePrimitive(number); | ||
| fibonacciSinglePrimitive(number); | ||
| fibonacciSingleArray(array); | ||
| fibonacciSingleArray(array); | ||
| fibonacciSingleArray(array); | ||
| fibonacciSingleObject(object); | ||
| fibonacciSingleObject(object); | ||
| fibonacciSingleObject(object); | ||
| fibonacciMultiplePrimitive(number, isCompleteBoolean); | ||
| fibonacciMultiplePrimitive(number, isCompleteBoolean); | ||
| fibonacciMultiplePrimitive(number, isCompleteBoolean); | ||
| fibonacciMultipleArray(array, isCompleteArray); | ||
| fibonacciMultipleArray(array, isCompleteArray); | ||
| fibonacciMultipleArray(array, isCompleteArray); | ||
| fibonacciMultipleObject(object, isCompleteObject); | ||
| fibonacciMultipleObject(object, isCompleteObject); | ||
| fibonacciMultipleObject(object, isCompleteObject); |
| 'use strict'; | ||
| /*! ***************************************************************************** | ||
| Copyright (c) Microsoft Corporation. All rights reserved. | ||
| Licensed under the Apache License, Version 2.0 (the "License"); you may not use | ||
| this file except in compliance with the License. You may obtain a copy of the | ||
| License at http://www.apache.org/licenses/LICENSE-2.0 | ||
| THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED | ||
| WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, | ||
| MERCHANTABLITY OR NON-INFRINGEMENT. | ||
| See the Apache Version 2.0 License for specific language governing permissions | ||
| and limitations under the License. | ||
| ***************************************************************************** */ | ||
| function __rest(s, e) { | ||
| var t = {}; | ||
| for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) | ||
| t[p] = s[p]; | ||
| if (s != null && typeof Object.getOwnPropertySymbols === "function") | ||
| for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) | ||
| t[p[i]] = s[p[i]]; | ||
| return t; | ||
| } | ||
| function createAreKeysEqual(isEqual) { | ||
| /** | ||
| * @function areKeysEqual | ||
| * | ||
| * @description | ||
| * are the keys shallowly equal to one another | ||
| * | ||
| * @param key1 the keys array to test against | ||
| * @param key2 the keys array to test | ||
| * @returns are the keys shallowly equal | ||
| */ | ||
| return function areKeysEqual(key1, key2) { | ||
| var length = key1.length; | ||
| if (key2.length !== length) { | ||
| return false; | ||
| } | ||
| if (length === 1) { | ||
| return isEqual(key1[0], key2[0]); | ||
| } | ||
| var index = 0; | ||
| while (index < length) { | ||
| if (!isEqual(key1[index], key2[index])) { | ||
| return false; | ||
| } | ||
| index++; | ||
| } | ||
| return true; | ||
| }; | ||
| } | ||
| function createGetKeyIndex(options) { | ||
| var maxSize = options.maxSize; | ||
| var areKeysEqual = typeof options.isMatchingKey === 'function' | ||
| ? options.isMatchingKey | ||
| : createAreKeysEqual(options.isEqual); | ||
| /** | ||
| * @function getKeyIndex | ||
| * | ||
| * @description | ||
| * get the index of the matching key | ||
| * | ||
| * @param allKeys the list of all available keys | ||
| * @param keyToMatch the key to try to match | ||
| * | ||
| * @returns {number} the index of the matching key value, or -1 | ||
| */ | ||
| return function getKeyIndex(allKeys, keyToMatch) { | ||
| if (areKeysEqual(allKeys[0], keyToMatch)) { | ||
| return 0; | ||
| } | ||
| if (maxSize > 1) { | ||
| var length = maxSize > allKeys.length ? allKeys.length : maxSize; | ||
| var index = 1; | ||
| while (index < length) { | ||
| if (areKeysEqual(allKeys[index], keyToMatch)) { | ||
| return index; | ||
| } | ||
| index++; | ||
| } | ||
| } | ||
| return -1; | ||
| }; | ||
| } | ||
| /** | ||
| * @function isSameValueZero | ||
| * | ||
| * @description | ||
| * are the objects equal based on SameValueZero equality | ||
| * | ||
| * @param object1 the first object to compare | ||
| * @param object2 the second object to compare | ||
| * @returns are the two objects equal | ||
| */ | ||
| function isSameValueZero(object1, object2) { | ||
| return object1 === object2 || (object1 !== object1 && object2 !== object2); | ||
| } | ||
| /** | ||
| * @function mergeOptions | ||
| * | ||
| * @description | ||
| * merge the options into the target | ||
| * | ||
| * @param extraOptions the extra options passed | ||
| * @param providedOptions the defaulted options provided | ||
| * @returns the merged options | ||
| */ | ||
| function mergeOptions(extraOptions, providedOptions) { | ||
| var target = {}; | ||
| for (var key in extraOptions) { | ||
| target[key] = extraOptions[key]; | ||
| } | ||
| for (var key in providedOptions) { | ||
| target[key] = providedOptions[key]; | ||
| } | ||
| return target; | ||
| } | ||
| /** | ||
| * @function orderByLru | ||
| * | ||
| * @description | ||
| * order the array based on a Least-Recently-Used basis | ||
| * | ||
| * @param keys the keys to order | ||
| * @param newKey the new key to move to the front | ||
| * @param values the values to order | ||
| * @param newValue the new value to move to the front | ||
| * @param startingIndex the index of the item to move to the front | ||
| */ | ||
| function orderByLru(cache, newKey, newValue, startingIndex, maxSize) { | ||
| var index = startingIndex; | ||
| while (index--) { | ||
| cache.keys[index + 1] = cache.keys[index]; | ||
| cache.values[index + 1] = cache.values[index]; | ||
| } | ||
| cache.keys[0] = newKey; | ||
| cache.values[0] = newValue; | ||
| if (startingIndex >= maxSize) { | ||
| cache.keys.length = maxSize; | ||
| cache.values.length = maxSize; | ||
| } | ||
| } | ||
| function createUpdateAsyncCache(options) { | ||
| var getKeyIndex = createGetKeyIndex(options); | ||
| var onCacheChange = options.onCacheChange, onCacheHit = options.onCacheHit; | ||
| var shouldUpdateOnChange = typeof onCacheChange === 'function'; | ||
| var shouldUpdateOnHit = typeof onCacheHit === 'function'; | ||
| /** | ||
| * @function updateAsyncCache | ||
| * | ||
| * @description | ||
| * update the promise method to auto-remove from cache if rejected, and | ||
| * if resolved then fire cache hit / changed | ||
| * | ||
| * @param cache the memoized function's cache | ||
| * @param memoized the memoized function | ||
| */ | ||
| return function (cache, memoized) { | ||
| var key = cache.keys[0]; | ||
| cache.values[0] = cache.values[0] | ||
| .then(function (value) { | ||
| shouldUpdateOnHit && onCacheHit(cache, options, memoized); | ||
| shouldUpdateOnChange && onCacheChange(cache, options, memoized); | ||
| return value; | ||
| }) | ||
| .catch(function (error) { | ||
| var keyIndex = getKeyIndex(cache.keys, key); | ||
| if (~keyIndex) { | ||
| cache.keys.splice(keyIndex, 1); | ||
| cache.values.splice(keyIndex, 1); | ||
| } | ||
| throw error; | ||
| }); | ||
| }; | ||
| } | ||
| var slice = Array.prototype.slice; | ||
| function createMemoizedFunction(fn, options) { | ||
| if (options === void 0) { options = {}; } | ||
| // @ts-ignore | ||
| if (fn.isMemoized) { | ||
| return fn; | ||
| } | ||
| var _a = options.isEqual, isEqual = _a === void 0 ? isSameValueZero : _a, isMatchingKey = options.isMatchingKey, _b = options.isPromise, isPromise = _b === void 0 ? false : _b, _c = options.maxSize, maxSize = _c === void 0 ? 1 : _c, onCacheAdd = options.onCacheAdd, onCacheChange = options.onCacheChange, onCacheHit = options.onCacheHit, transformKey = options.transformKey, extraOptions = __rest(options, ["isEqual", "isMatchingKey", "isPromise", "maxSize", "onCacheAdd", "onCacheChange", "onCacheHit", "transformKey"]); | ||
| var normalizedOptions = mergeOptions(extraOptions, { | ||
| isEqual: isEqual, | ||
| isMatchingKey: isMatchingKey, | ||
| isPromise: isPromise, | ||
| maxSize: maxSize, | ||
| onCacheAdd: onCacheAdd, | ||
| onCacheChange: onCacheChange, | ||
| onCacheHit: onCacheHit, | ||
| transformKey: transformKey, | ||
| }); | ||
| var getKeyIndex = createGetKeyIndex(normalizedOptions); | ||
| var updateAsyncCache = createUpdateAsyncCache(normalizedOptions); | ||
| var keys = []; | ||
| var values = []; | ||
| var cache = { | ||
| keys: keys, | ||
| get size() { | ||
| return cache.keys.length; | ||
| }, | ||
| values: values, | ||
| }; | ||
| var canTransformKey = typeof transformKey === 'function'; | ||
| var shouldCloneArguments = !!(transformKey || isMatchingKey); | ||
| var shouldUpdateOnAdd = typeof onCacheAdd === 'function'; | ||
| var shouldUpdateOnChange = typeof onCacheChange === 'function'; | ||
| var shouldUpdateOnHit = typeof onCacheHit === 'function'; | ||
| function memoized() { | ||
| var normalizedArgs = shouldCloneArguments | ||
| ? slice.call(arguments, 0) | ||
| : arguments; | ||
| var key = canTransformKey | ||
| ? transformKey(normalizedArgs) | ||
| : normalizedArgs; | ||
| var keyIndex = keys.length ? getKeyIndex(keys, key) : -1; | ||
| if (~keyIndex) { | ||
| shouldUpdateOnHit && onCacheHit(cache, normalizedOptions, memoized); | ||
| if (keyIndex) { | ||
| orderByLru(cache, keys[keyIndex], values[keyIndex], keyIndex, maxSize); | ||
| shouldUpdateOnChange && | ||
| onCacheChange(cache, normalizedOptions, memoized); | ||
| } | ||
| } | ||
| else { | ||
| var newValue = fn.apply(this, arguments); | ||
| var newKey = shouldCloneArguments | ||
| ? key | ||
| : slice.call(normalizedArgs, 0); | ||
| orderByLru(cache, newKey, newValue, keys.length, maxSize); | ||
| isPromise && updateAsyncCache(cache, memoized); | ||
| shouldUpdateOnAdd && onCacheAdd(cache, normalizedOptions, memoized); | ||
| shouldUpdateOnChange && onCacheChange(cache, normalizedOptions, memoized); | ||
| } | ||
| return values[0]; | ||
| } | ||
| Object.defineProperties(memoized, { | ||
| cache: { | ||
| configurable: true, | ||
| value: cache, | ||
| }, | ||
| cacheSnapshot: { | ||
| configurable: true, | ||
| get: function () { | ||
| return { | ||
| keys: slice.call(cache.keys, 0), | ||
| size: cache.size, | ||
| values: slice.call(cache.values, 0), | ||
| }; | ||
| }, | ||
| }, | ||
| isMemoized: { | ||
| configurable: true, | ||
| value: true, | ||
| }, | ||
| options: { | ||
| configurable: true, | ||
| value: normalizedOptions, | ||
| }, | ||
| }); | ||
| return memoized; | ||
| } | ||
| module.exports = createMemoizedFunction; | ||
| //# sourceMappingURL=micro-memoize.cjs.js.map |
| {"version":3,"file":"micro-memoize.cjs.js","sources":["../src/utils.ts","../src/index.ts"],"sourcesContent":["export function createAreKeysEqual(\n isEqual: MicroMemoize.EqualityComparator,\n): MicroMemoize.MatchingKeyComparator {\n /**\n * @function areKeysEqual\n *\n * @description\n * are the keys shallowly equal to one another\n *\n * @param key1 the keys array to test against\n * @param key2 the keys array to test\n * @returns are the keys shallowly equal\n */\n return function areKeysEqual(key1: MicroMemoize.Key, key2: MicroMemoize.Key) {\n const length = key1.length;\n\n if (key2.length !== length) {\n return false;\n }\n\n if (length === 1) {\n return isEqual(key1[0], key2[0]);\n }\n\n let index = 0;\n\n while (index < length) {\n if (!isEqual(key1[index], key2[index])) {\n return false;\n }\n\n index++;\n }\n\n return true;\n };\n}\n\nexport function createGetKeyIndex(\n options: MicroMemoize.Options,\n): MicroMemoize.KeyIndexGetter {\n const { maxSize } = options;\n const areKeysEqual: MicroMemoize.MatchingKeyComparator =\n typeof options.isMatchingKey === 'function'\n ? options.isMatchingKey\n : createAreKeysEqual(options.isEqual);\n\n /**\n * @function getKeyIndex\n *\n * @description\n * get the index of the matching key\n *\n * @param allKeys the list of all available keys\n * @param keyToMatch the key to try to match\n *\n * @returns {number} the index of the matching key value, or -1\n */\n return function getKeyIndex(\n allKeys: MicroMemoize.Keys,\n keyToMatch: MicroMemoize.Key,\n ) {\n if (areKeysEqual(allKeys[0], keyToMatch)) {\n return 0;\n }\n\n if (maxSize > 1) {\n const length = maxSize > allKeys.length ? allKeys.length : maxSize;\n\n let index = 1;\n\n while (index < length) {\n if (areKeysEqual(allKeys[index], keyToMatch)) {\n return index;\n }\n\n index++;\n }\n }\n\n return -1;\n };\n}\n\n/**\n * @function isSameValueZero\n *\n * @description\n * are the objects equal based on SameValueZero equality\n *\n * @param object1 the first object to compare\n * @param object2 the second object to compare\n * @returns are the two objects equal\n */\nexport function isSameValueZero(object1: any, object2: any) {\n return object1 === object2 || (object1 !== object1 && object2 !== object2);\n}\n\n/**\n * @function mergeOptions\n *\n * @description\n * merge the options into the target\n *\n * @param extraOptions the extra options passed\n * @param providedOptions the defaulted options provided\n * @returns the merged options\n */\nexport function mergeOptions(\n extraOptions: PlainObject,\n providedOptions: PlainObject,\n) {\n const target: PlainObject = {};\n\n for (const key in extraOptions) {\n target[key] = extraOptions[key];\n }\n\n for (const key in providedOptions) {\n target[key] = providedOptions[key];\n }\n\n return target;\n}\n\n/**\n * @function orderByLru\n *\n * @description\n * order the array based on a Least-Recently-Used basis\n *\n * @param keys the keys to order\n * @param newKey the new key to move to the front\n * @param values the values to order\n * @param newValue the new value to move to the front\n * @param startingIndex the index of the item to move to the front\n */\nexport function orderByLru(\n cache: MicroMemoize.Cache,\n newKey: MicroMemoize.Key,\n newValue: any,\n startingIndex: number,\n maxSize: number,\n) {\n let index = startingIndex;\n\n while (index--) {\n cache.keys[index + 1] = cache.keys[index];\n cache.values[index + 1] = cache.values[index];\n }\n\n cache.keys[0] = newKey;\n cache.values[0] = newValue;\n\n if (startingIndex >= maxSize) {\n cache.keys.length = maxSize;\n cache.values.length = maxSize;\n }\n}\n\nexport function createUpdateAsyncCache(\n options: MicroMemoize.Options,\n): MicroMemoize.AsyncCacheUpdater {\n const getKeyIndex: MicroMemoize.KeyIndexGetter = createGetKeyIndex(options);\n\n const { onCacheChange, onCacheHit } = options;\n\n const shouldUpdateOnChange = typeof onCacheChange === 'function';\n const shouldUpdateOnHit = typeof onCacheHit === 'function';\n\n /**\n * @function updateAsyncCache\n *\n * @description\n * update the promise method to auto-remove from cache if rejected, and\n * if resolved then fire cache hit / changed\n *\n * @param cache the memoized function's cache\n * @param memoized the memoized function\n */\n return (cache: MicroMemoize.Cache, memoized: MicroMemoize.Memoized): void => {\n const key: any = cache.keys[0];\n\n cache.values[0] = cache.values[0]\n .then((value: any) => {\n shouldUpdateOnHit && onCacheHit(cache, options, memoized);\n shouldUpdateOnChange && onCacheChange(cache, options, memoized);\n\n return value;\n })\n .catch((error: Error) => {\n const keyIndex = getKeyIndex(cache.keys, key);\n\n if (~keyIndex) {\n cache.keys.splice(keyIndex, 1);\n cache.values.splice(keyIndex, 1);\n }\n\n throw error;\n });\n };\n}\n","// utils\nimport {\n createGetKeyIndex,\n createUpdateAsyncCache,\n isSameValueZero,\n mergeOptions,\n orderByLru,\n} from './utils';\n\nconst { slice } = Array.prototype;\n\nfunction createMemoizedFunction(\n fn: Function | MicroMemoize.Memoized,\n options: MicroMemoize.Options = {},\n): MicroMemoize.Memoized {\n // @ts-ignore\n if (fn.isMemoized) {\n return fn;\n }\n\n const {\n isEqual = isSameValueZero,\n isMatchingKey,\n isPromise = false,\n maxSize = 1,\n onCacheAdd,\n onCacheChange,\n onCacheHit,\n transformKey,\n ...extraOptions\n }: MicroMemoize.Options = options;\n\n const normalizedOptions = mergeOptions(extraOptions, {\n isEqual,\n isMatchingKey,\n isPromise,\n maxSize,\n onCacheAdd,\n onCacheChange,\n onCacheHit,\n transformKey,\n });\n\n const getKeyIndex: MicroMemoize.KeyIndexGetter = createGetKeyIndex(\n normalizedOptions,\n );\n const updateAsyncCache: MicroMemoize.AsyncCacheUpdater = createUpdateAsyncCache(\n normalizedOptions,\n );\n\n const keys: MicroMemoize.Keys = [];\n const values: MicroMemoize.Values = [];\n\n const cache: MicroMemoize.Cache = {\n keys,\n get size() {\n return cache.keys.length;\n },\n values,\n };\n\n const canTransformKey = typeof transformKey === 'function';\n\n const shouldCloneArguments = !!(transformKey || isMatchingKey);\n\n const shouldUpdateOnAdd = typeof onCacheAdd === 'function';\n const shouldUpdateOnChange = typeof onCacheChange === 'function';\n const shouldUpdateOnHit = typeof onCacheHit === 'function';\n\n function memoized(): any {\n const normalizedArgs: MicroMemoize.RawKey = shouldCloneArguments\n ? slice.call(arguments, 0)\n : arguments;\n const key: MicroMemoize.RawKey = canTransformKey\n ? transformKey(normalizedArgs)\n : normalizedArgs;\n const keyIndex: number = keys.length ? getKeyIndex(keys, key) : -1;\n\n if (~keyIndex) {\n shouldUpdateOnHit && onCacheHit(cache, normalizedOptions, memoized);\n\n if (keyIndex) {\n orderByLru(cache, keys[keyIndex], values[keyIndex], keyIndex, maxSize);\n\n shouldUpdateOnChange &&\n onCacheChange(cache, normalizedOptions, memoized);\n }\n } else {\n const newValue: any = fn.apply(this, arguments);\n const newKey: MicroMemoize.Key = shouldCloneArguments\n ? key\n : slice.call(normalizedArgs, 0);\n\n orderByLru(cache, newKey, newValue, keys.length, maxSize);\n\n isPromise && updateAsyncCache(cache, memoized);\n\n shouldUpdateOnAdd && onCacheAdd(cache, normalizedOptions, memoized);\n shouldUpdateOnChange && onCacheChange(cache, normalizedOptions, memoized);\n }\n\n return values[0];\n }\n\n Object.defineProperties(memoized, {\n cache: {\n configurable: true,\n value: cache,\n },\n cacheSnapshot: {\n configurable: true,\n get() {\n return {\n keys: slice.call(cache.keys, 0),\n size: cache.size,\n values: slice.call(cache.values, 0),\n };\n },\n },\n isMemoized: {\n configurable: true,\n value: true,\n },\n options: {\n configurable: true,\n value: normalizedOptions,\n },\n });\n\n return memoized;\n}\n\nexport default createMemoizedFunction;\n"],"names":[],"mappings":"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"} |
| /*! ***************************************************************************** | ||
| Copyright (c) Microsoft Corporation. All rights reserved. | ||
| Licensed under the Apache License, Version 2.0 (the "License"); you may not use | ||
| this file except in compliance with the License. You may obtain a copy of the | ||
| License at http://www.apache.org/licenses/LICENSE-2.0 | ||
| THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED | ||
| WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, | ||
| MERCHANTABLITY OR NON-INFRINGEMENT. | ||
| See the Apache Version 2.0 License for specific language governing permissions | ||
| and limitations under the License. | ||
| ***************************************************************************** */ | ||
| function __rest(s, e) { | ||
| var t = {}; | ||
| for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) | ||
| t[p] = s[p]; | ||
| if (s != null && typeof Object.getOwnPropertySymbols === "function") | ||
| for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) | ||
| t[p[i]] = s[p[i]]; | ||
| return t; | ||
| } | ||
| function createAreKeysEqual(isEqual) { | ||
| /** | ||
| * @function areKeysEqual | ||
| * | ||
| * @description | ||
| * are the keys shallowly equal to one another | ||
| * | ||
| * @param key1 the keys array to test against | ||
| * @param key2 the keys array to test | ||
| * @returns are the keys shallowly equal | ||
| */ | ||
| return function areKeysEqual(key1, key2) { | ||
| var length = key1.length; | ||
| if (key2.length !== length) { | ||
| return false; | ||
| } | ||
| if (length === 1) { | ||
| return isEqual(key1[0], key2[0]); | ||
| } | ||
| var index = 0; | ||
| while (index < length) { | ||
| if (!isEqual(key1[index], key2[index])) { | ||
| return false; | ||
| } | ||
| index++; | ||
| } | ||
| return true; | ||
| }; | ||
| } | ||
| function createGetKeyIndex(options) { | ||
| var maxSize = options.maxSize; | ||
| var areKeysEqual = typeof options.isMatchingKey === 'function' | ||
| ? options.isMatchingKey | ||
| : createAreKeysEqual(options.isEqual); | ||
| /** | ||
| * @function getKeyIndex | ||
| * | ||
| * @description | ||
| * get the index of the matching key | ||
| * | ||
| * @param allKeys the list of all available keys | ||
| * @param keyToMatch the key to try to match | ||
| * | ||
| * @returns {number} the index of the matching key value, or -1 | ||
| */ | ||
| return function getKeyIndex(allKeys, keyToMatch) { | ||
| if (areKeysEqual(allKeys[0], keyToMatch)) { | ||
| return 0; | ||
| } | ||
| if (maxSize > 1) { | ||
| var length = maxSize > allKeys.length ? allKeys.length : maxSize; | ||
| var index = 1; | ||
| while (index < length) { | ||
| if (areKeysEqual(allKeys[index], keyToMatch)) { | ||
| return index; | ||
| } | ||
| index++; | ||
| } | ||
| } | ||
| return -1; | ||
| }; | ||
| } | ||
| /** | ||
| * @function isSameValueZero | ||
| * | ||
| * @description | ||
| * are the objects equal based on SameValueZero equality | ||
| * | ||
| * @param object1 the first object to compare | ||
| * @param object2 the second object to compare | ||
| * @returns are the two objects equal | ||
| */ | ||
| function isSameValueZero(object1, object2) { | ||
| return object1 === object2 || (object1 !== object1 && object2 !== object2); | ||
| } | ||
| /** | ||
| * @function mergeOptions | ||
| * | ||
| * @description | ||
| * merge the options into the target | ||
| * | ||
| * @param extraOptions the extra options passed | ||
| * @param providedOptions the defaulted options provided | ||
| * @returns the merged options | ||
| */ | ||
| function mergeOptions(extraOptions, providedOptions) { | ||
| var target = {}; | ||
| for (var key in extraOptions) { | ||
| target[key] = extraOptions[key]; | ||
| } | ||
| for (var key in providedOptions) { | ||
| target[key] = providedOptions[key]; | ||
| } | ||
| return target; | ||
| } | ||
| /** | ||
| * @function orderByLru | ||
| * | ||
| * @description | ||
| * order the array based on a Least-Recently-Used basis | ||
| * | ||
| * @param keys the keys to order | ||
| * @param newKey the new key to move to the front | ||
| * @param values the values to order | ||
| * @param newValue the new value to move to the front | ||
| * @param startingIndex the index of the item to move to the front | ||
| */ | ||
| function orderByLru(cache, newKey, newValue, startingIndex, maxSize) { | ||
| var index = startingIndex; | ||
| while (index--) { | ||
| cache.keys[index + 1] = cache.keys[index]; | ||
| cache.values[index + 1] = cache.values[index]; | ||
| } | ||
| cache.keys[0] = newKey; | ||
| cache.values[0] = newValue; | ||
| if (startingIndex >= maxSize) { | ||
| cache.keys.length = maxSize; | ||
| cache.values.length = maxSize; | ||
| } | ||
| } | ||
| function createUpdateAsyncCache(options) { | ||
| var getKeyIndex = createGetKeyIndex(options); | ||
| var onCacheChange = options.onCacheChange, onCacheHit = options.onCacheHit; | ||
| var shouldUpdateOnChange = typeof onCacheChange === 'function'; | ||
| var shouldUpdateOnHit = typeof onCacheHit === 'function'; | ||
| /** | ||
| * @function updateAsyncCache | ||
| * | ||
| * @description | ||
| * update the promise method to auto-remove from cache if rejected, and | ||
| * if resolved then fire cache hit / changed | ||
| * | ||
| * @param cache the memoized function's cache | ||
| * @param memoized the memoized function | ||
| */ | ||
| return function (cache, memoized) { | ||
| var key = cache.keys[0]; | ||
| cache.values[0] = cache.values[0] | ||
| .then(function (value) { | ||
| shouldUpdateOnHit && onCacheHit(cache, options, memoized); | ||
| shouldUpdateOnChange && onCacheChange(cache, options, memoized); | ||
| return value; | ||
| }) | ||
| .catch(function (error) { | ||
| var keyIndex = getKeyIndex(cache.keys, key); | ||
| if (~keyIndex) { | ||
| cache.keys.splice(keyIndex, 1); | ||
| cache.values.splice(keyIndex, 1); | ||
| } | ||
| throw error; | ||
| }); | ||
| }; | ||
| } | ||
| var slice = Array.prototype.slice; | ||
| function createMemoizedFunction(fn, options) { | ||
| if (options === void 0) { options = {}; } | ||
| // @ts-ignore | ||
| if (fn.isMemoized) { | ||
| return fn; | ||
| } | ||
| var _a = options.isEqual, isEqual = _a === void 0 ? isSameValueZero : _a, isMatchingKey = options.isMatchingKey, _b = options.isPromise, isPromise = _b === void 0 ? false : _b, _c = options.maxSize, maxSize = _c === void 0 ? 1 : _c, onCacheAdd = options.onCacheAdd, onCacheChange = options.onCacheChange, onCacheHit = options.onCacheHit, transformKey = options.transformKey, extraOptions = __rest(options, ["isEqual", "isMatchingKey", "isPromise", "maxSize", "onCacheAdd", "onCacheChange", "onCacheHit", "transformKey"]); | ||
| var normalizedOptions = mergeOptions(extraOptions, { | ||
| isEqual: isEqual, | ||
| isMatchingKey: isMatchingKey, | ||
| isPromise: isPromise, | ||
| maxSize: maxSize, | ||
| onCacheAdd: onCacheAdd, | ||
| onCacheChange: onCacheChange, | ||
| onCacheHit: onCacheHit, | ||
| transformKey: transformKey, | ||
| }); | ||
| var getKeyIndex = createGetKeyIndex(normalizedOptions); | ||
| var updateAsyncCache = createUpdateAsyncCache(normalizedOptions); | ||
| var keys = []; | ||
| var values = []; | ||
| var cache = { | ||
| keys: keys, | ||
| get size() { | ||
| return cache.keys.length; | ||
| }, | ||
| values: values, | ||
| }; | ||
| var canTransformKey = typeof transformKey === 'function'; | ||
| var shouldCloneArguments = !!(transformKey || isMatchingKey); | ||
| var shouldUpdateOnAdd = typeof onCacheAdd === 'function'; | ||
| var shouldUpdateOnChange = typeof onCacheChange === 'function'; | ||
| var shouldUpdateOnHit = typeof onCacheHit === 'function'; | ||
| function memoized() { | ||
| var normalizedArgs = shouldCloneArguments | ||
| ? slice.call(arguments, 0) | ||
| : arguments; | ||
| var key = canTransformKey | ||
| ? transformKey(normalizedArgs) | ||
| : normalizedArgs; | ||
| var keyIndex = keys.length ? getKeyIndex(keys, key) : -1; | ||
| if (~keyIndex) { | ||
| shouldUpdateOnHit && onCacheHit(cache, normalizedOptions, memoized); | ||
| if (keyIndex) { | ||
| orderByLru(cache, keys[keyIndex], values[keyIndex], keyIndex, maxSize); | ||
| shouldUpdateOnChange && | ||
| onCacheChange(cache, normalizedOptions, memoized); | ||
| } | ||
| } | ||
| else { | ||
| var newValue = fn.apply(this, arguments); | ||
| var newKey = shouldCloneArguments | ||
| ? key | ||
| : slice.call(normalizedArgs, 0); | ||
| orderByLru(cache, newKey, newValue, keys.length, maxSize); | ||
| isPromise && updateAsyncCache(cache, memoized); | ||
| shouldUpdateOnAdd && onCacheAdd(cache, normalizedOptions, memoized); | ||
| shouldUpdateOnChange && onCacheChange(cache, normalizedOptions, memoized); | ||
| } | ||
| return values[0]; | ||
| } | ||
| Object.defineProperties(memoized, { | ||
| cache: { | ||
| configurable: true, | ||
| value: cache, | ||
| }, | ||
| cacheSnapshot: { | ||
| configurable: true, | ||
| get: function () { | ||
| return { | ||
| keys: slice.call(cache.keys, 0), | ||
| size: cache.size, | ||
| values: slice.call(cache.values, 0), | ||
| }; | ||
| }, | ||
| }, | ||
| isMemoized: { | ||
| configurable: true, | ||
| value: true, | ||
| }, | ||
| options: { | ||
| configurable: true, | ||
| value: normalizedOptions, | ||
| }, | ||
| }); | ||
| return memoized; | ||
| } | ||
| export default createMemoizedFunction; | ||
| //# sourceMappingURL=micro-memoize.esm.js.map |
| {"version":3,"file":"micro-memoize.esm.js","sources":["../src/utils.ts","../src/index.ts"],"sourcesContent":["export function createAreKeysEqual(\n isEqual: MicroMemoize.EqualityComparator,\n): MicroMemoize.MatchingKeyComparator {\n /**\n * @function areKeysEqual\n *\n * @description\n * are the keys shallowly equal to one another\n *\n * @param key1 the keys array to test against\n * @param key2 the keys array to test\n * @returns are the keys shallowly equal\n */\n return function areKeysEqual(key1: MicroMemoize.Key, key2: MicroMemoize.Key) {\n const length = key1.length;\n\n if (key2.length !== length) {\n return false;\n }\n\n if (length === 1) {\n return isEqual(key1[0], key2[0]);\n }\n\n let index = 0;\n\n while (index < length) {\n if (!isEqual(key1[index], key2[index])) {\n return false;\n }\n\n index++;\n }\n\n return true;\n };\n}\n\nexport function createGetKeyIndex(\n options: MicroMemoize.Options,\n): MicroMemoize.KeyIndexGetter {\n const { maxSize } = options;\n const areKeysEqual: MicroMemoize.MatchingKeyComparator =\n typeof options.isMatchingKey === 'function'\n ? options.isMatchingKey\n : createAreKeysEqual(options.isEqual);\n\n /**\n * @function getKeyIndex\n *\n * @description\n * get the index of the matching key\n *\n * @param allKeys the list of all available keys\n * @param keyToMatch the key to try to match\n *\n * @returns {number} the index of the matching key value, or -1\n */\n return function getKeyIndex(\n allKeys: MicroMemoize.Keys,\n keyToMatch: MicroMemoize.Key,\n ) {\n if (areKeysEqual(allKeys[0], keyToMatch)) {\n return 0;\n }\n\n if (maxSize > 1) {\n const length = maxSize > allKeys.length ? allKeys.length : maxSize;\n\n let index = 1;\n\n while (index < length) {\n if (areKeysEqual(allKeys[index], keyToMatch)) {\n return index;\n }\n\n index++;\n }\n }\n\n return -1;\n };\n}\n\n/**\n * @function isSameValueZero\n *\n * @description\n * are the objects equal based on SameValueZero equality\n *\n * @param object1 the first object to compare\n * @param object2 the second object to compare\n * @returns are the two objects equal\n */\nexport function isSameValueZero(object1: any, object2: any) {\n return object1 === object2 || (object1 !== object1 && object2 !== object2);\n}\n\n/**\n * @function mergeOptions\n *\n * @description\n * merge the options into the target\n *\n * @param extraOptions the extra options passed\n * @param providedOptions the defaulted options provided\n * @returns the merged options\n */\nexport function mergeOptions(\n extraOptions: PlainObject,\n providedOptions: PlainObject,\n) {\n const target: PlainObject = {};\n\n for (const key in extraOptions) {\n target[key] = extraOptions[key];\n }\n\n for (const key in providedOptions) {\n target[key] = providedOptions[key];\n }\n\n return target;\n}\n\n/**\n * @function orderByLru\n *\n * @description\n * order the array based on a Least-Recently-Used basis\n *\n * @param keys the keys to order\n * @param newKey the new key to move to the front\n * @param values the values to order\n * @param newValue the new value to move to the front\n * @param startingIndex the index of the item to move to the front\n */\nexport function orderByLru(\n cache: MicroMemoize.Cache,\n newKey: MicroMemoize.Key,\n newValue: any,\n startingIndex: number,\n maxSize: number,\n) {\n let index = startingIndex;\n\n while (index--) {\n cache.keys[index + 1] = cache.keys[index];\n cache.values[index + 1] = cache.values[index];\n }\n\n cache.keys[0] = newKey;\n cache.values[0] = newValue;\n\n if (startingIndex >= maxSize) {\n cache.keys.length = maxSize;\n cache.values.length = maxSize;\n }\n}\n\nexport function createUpdateAsyncCache(\n options: MicroMemoize.Options,\n): MicroMemoize.AsyncCacheUpdater {\n const getKeyIndex: MicroMemoize.KeyIndexGetter = createGetKeyIndex(options);\n\n const { onCacheChange, onCacheHit } = options;\n\n const shouldUpdateOnChange = typeof onCacheChange === 'function';\n const shouldUpdateOnHit = typeof onCacheHit === 'function';\n\n /**\n * @function updateAsyncCache\n *\n * @description\n * update the promise method to auto-remove from cache if rejected, and\n * if resolved then fire cache hit / changed\n *\n * @param cache the memoized function's cache\n * @param memoized the memoized function\n */\n return (cache: MicroMemoize.Cache, memoized: MicroMemoize.Memoized): void => {\n const key: any = cache.keys[0];\n\n cache.values[0] = cache.values[0]\n .then((value: any) => {\n shouldUpdateOnHit && onCacheHit(cache, options, memoized);\n shouldUpdateOnChange && onCacheChange(cache, options, memoized);\n\n return value;\n })\n .catch((error: Error) => {\n const keyIndex = getKeyIndex(cache.keys, key);\n\n if (~keyIndex) {\n cache.keys.splice(keyIndex, 1);\n cache.values.splice(keyIndex, 1);\n }\n\n throw error;\n });\n };\n}\n","// utils\nimport {\n createGetKeyIndex,\n createUpdateAsyncCache,\n isSameValueZero,\n mergeOptions,\n orderByLru,\n} from './utils';\n\nconst { slice } = Array.prototype;\n\nfunction createMemoizedFunction(\n fn: Function | MicroMemoize.Memoized,\n options: MicroMemoize.Options = {},\n): MicroMemoize.Memoized {\n // @ts-ignore\n if (fn.isMemoized) {\n return fn;\n }\n\n const {\n isEqual = isSameValueZero,\n isMatchingKey,\n isPromise = false,\n maxSize = 1,\n onCacheAdd,\n onCacheChange,\n onCacheHit,\n transformKey,\n ...extraOptions\n }: MicroMemoize.Options = options;\n\n const normalizedOptions = mergeOptions(extraOptions, {\n isEqual,\n isMatchingKey,\n isPromise,\n maxSize,\n onCacheAdd,\n onCacheChange,\n onCacheHit,\n transformKey,\n });\n\n const getKeyIndex: MicroMemoize.KeyIndexGetter = createGetKeyIndex(\n normalizedOptions,\n );\n const updateAsyncCache: MicroMemoize.AsyncCacheUpdater = createUpdateAsyncCache(\n normalizedOptions,\n );\n\n const keys: MicroMemoize.Keys = [];\n const values: MicroMemoize.Values = [];\n\n const cache: MicroMemoize.Cache = {\n keys,\n get size() {\n return cache.keys.length;\n },\n values,\n };\n\n const canTransformKey = typeof transformKey === 'function';\n\n const shouldCloneArguments = !!(transformKey || isMatchingKey);\n\n const shouldUpdateOnAdd = typeof onCacheAdd === 'function';\n const shouldUpdateOnChange = typeof onCacheChange === 'function';\n const shouldUpdateOnHit = typeof onCacheHit === 'function';\n\n function memoized(): any {\n const normalizedArgs: MicroMemoize.RawKey = shouldCloneArguments\n ? slice.call(arguments, 0)\n : arguments;\n const key: MicroMemoize.RawKey = canTransformKey\n ? transformKey(normalizedArgs)\n : normalizedArgs;\n const keyIndex: number = keys.length ? getKeyIndex(keys, key) : -1;\n\n if (~keyIndex) {\n shouldUpdateOnHit && onCacheHit(cache, normalizedOptions, memoized);\n\n if (keyIndex) {\n orderByLru(cache, keys[keyIndex], values[keyIndex], keyIndex, maxSize);\n\n shouldUpdateOnChange &&\n onCacheChange(cache, normalizedOptions, memoized);\n }\n } else {\n const newValue: any = fn.apply(this, arguments);\n const newKey: MicroMemoize.Key = shouldCloneArguments\n ? key\n : slice.call(normalizedArgs, 0);\n\n orderByLru(cache, newKey, newValue, keys.length, maxSize);\n\n isPromise && updateAsyncCache(cache, memoized);\n\n shouldUpdateOnAdd && onCacheAdd(cache, normalizedOptions, memoized);\n shouldUpdateOnChange && onCacheChange(cache, normalizedOptions, memoized);\n }\n\n return values[0];\n }\n\n Object.defineProperties(memoized, {\n cache: {\n configurable: true,\n value: cache,\n },\n cacheSnapshot: {\n configurable: true,\n get() {\n return {\n keys: slice.call(cache.keys, 0),\n size: cache.size,\n values: slice.call(cache.values, 0),\n };\n },\n },\n isMemoized: {\n configurable: true,\n value: true,\n },\n options: {\n configurable: true,\n value: normalizedOptions,\n },\n });\n\n return memoized;\n}\n\nexport default createMemoizedFunction;\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;SAAgB,kBAAkB,CAChC,OAAwC;;;;;;;;;;;IAYxC,OAAO,SAAS,YAAY,CAAC,IAAsB,EAAE,IAAsB;QACzE,IAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAE3B,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM,EAAE;YAC1B,OAAO,KAAK,CAAC;SACd;QAED,IAAI,MAAM,KAAK,CAAC,EAAE;YAChB,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;SAClC;QAED,IAAI,KAAK,GAAG,CAAC,CAAC;QAEd,OAAO,KAAK,GAAG,MAAM,EAAE;YACrB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE;gBACtC,OAAO,KAAK,CAAC;aACd;YAED,KAAK,EAAE,CAAC;SACT;QAED,OAAO,IAAI,CAAC;KACb,CAAC;CACH;AAED,SAAgB,iBAAiB,CAC/B,OAA6B;IAErB,IAAA,yBAAO,CAAa;IAC5B,IAAM,YAAY,GAChB,OAAO,OAAO,CAAC,aAAa,KAAK,UAAU;UACvC,OAAO,CAAC,aAAa;UACrB,kBAAkB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;;;;;;;;;;;;IAa1C,OAAO,SAAS,WAAW,CACzB,OAA0B,EAC1B,UAA4B;QAE5B,IAAI,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE;YACxC,OAAO,CAAC,CAAC;SACV;QAED,IAAI,OAAO,GAAG,CAAC,EAAE;YACf,IAAM,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,OAAO,CAAC;YAEnE,IAAI,KAAK,GAAG,CAAC,CAAC;YAEd,OAAO,KAAK,GAAG,MAAM,EAAE;gBACrB,IAAI,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC,EAAE;oBAC5C,OAAO,KAAK,CAAC;iBACd;gBAED,KAAK,EAAE,CAAC;aACT;SACF;QAED,OAAO,CAAC,CAAC,CAAC;KACX,CAAC;CACH;;;;;;;;;;;AAYD,SAAgB,eAAe,CAAC,OAAY,EAAE,OAAY;IACxD,OAAO,OAAO,KAAK,OAAO,KAAK,OAAO,KAAK,OAAO,IAAI,OAAO,KAAK,OAAO,CAAC,CAAC;CAC5E;;;;;;;;;;;AAYD,SAAgB,YAAY,CAC1B,YAAyB,EACzB,eAA4B;IAE5B,IAAM,MAAM,GAAgB,EAAE,CAAC;IAE/B,KAAK,IAAM,GAAG,IAAI,YAAY,EAAE;QAC9B,MAAM,CAAC,GAAG,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;KACjC;IAED,KAAK,IAAM,GAAG,IAAI,eAAe,EAAE;QACjC,MAAM,CAAC,GAAG,CAAC,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;KACpC;IAED,OAAO,MAAM,CAAC;CACf;;;;;;;;;;;;;AAcD,SAAgB,UAAU,CACxB,KAAyB,EACzB,MAAwB,EACxB,QAAa,EACb,aAAqB,EACrB,OAAe;IAEf,IAAI,KAAK,GAAG,aAAa,CAAC;IAE1B,OAAO,KAAK,EAAE,EAAE;QACd,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1C,KAAK,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;KAC/C;IAED,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC;IACvB,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC;IAE3B,IAAI,aAAa,IAAI,OAAO,EAAE;QAC5B,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC;QAC5B,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,OAAO,CAAC;KAC/B;CACF;AAED,SAAgB,sBAAsB,CACpC,OAA6B;IAE7B,IAAM,WAAW,GAAgC,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAEpE,IAAA,qCAAa,EAAE,+BAAU,CAAa;IAE9C,IAAM,oBAAoB,GAAG,OAAO,aAAa,KAAK,UAAU,CAAC;IACjE,IAAM,iBAAiB,GAAG,OAAO,UAAU,KAAK,UAAU,CAAC;;;;;;;;;;;IAY3D,OAAO,UAAC,KAAyB,EAAE,QAA+B;QAChE,IAAM,GAAG,GAAQ,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAE/B,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;aAC9B,IAAI,CAAC,UAAC,KAAU;YACf,iBAAiB,IAAI,UAAU,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;YAC1D,oBAAoB,IAAI,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;YAEhE,OAAO,KAAK,CAAC;SACd,CAAC;aACD,KAAK,CAAC,UAAC,KAAY;YAClB,IAAM,QAAQ,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;YAE9C,IAAI,CAAC,QAAQ,EAAE;gBACb,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;gBAC/B,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;aAClC;YAED,MAAM,KAAK,CAAC;SACb,CAAC,CAAC;KACN,CAAC;CACH;;AChMO,IAAA,6BAAK,CAAqB;AAElC,SAAS,sBAAsB,CAC7B,EAAoC,EACpC,OAAkC;IAAlC,wBAAA,EAAA,YAAkC;;IAGlC,IAAI,EAAE,CAAC,UAAU,EAAE;QACjB,OAAO,EAAE,CAAC;KACX;IAGC,IAAA,oBAAyB,EAAzB,8CAAyB,EACzB,qCAAa,EACb,sBAAiB,EAAjB,sCAAiB,EACjB,oBAAW,EAAX,gCAAW,EACX,+BAAU,EACV,qCAAa,EACb,+BAAU,EACV,mCAAY,EACZ,iJAAe,CACiB;IAElC,IAAM,iBAAiB,GAAG,YAAY,CAAC,YAAY,EAAE;QACnD,OAAO,SAAA;QACP,aAAa,eAAA;QACb,SAAS,WAAA;QACT,OAAO,SAAA;QACP,UAAU,YAAA;QACV,aAAa,eAAA;QACb,UAAU,YAAA;QACV,YAAY,cAAA;KACb,CAAC,CAAC;IAEH,IAAM,WAAW,GAAgC,iBAAiB,CAChE,iBAAiB,CAClB,CAAC;IACF,IAAM,gBAAgB,GAAmC,sBAAsB,CAC7E,iBAAiB,CAClB,CAAC;IAEF,IAAM,IAAI,GAAsB,EAAE,CAAC;IACnC,IAAM,MAAM,GAAwB,EAAE,CAAC;IAEvC,IAAM,KAAK,GAAuB;QAChC,IAAI,MAAA;QACJ,IAAI,IAAI;YACN,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC;SAC1B;QACD,MAAM,QAAA;KACP,CAAC;IAEF,IAAM,eAAe,GAAG,OAAO,YAAY,KAAK,UAAU,CAAC;IAE3D,IAAM,oBAAoB,GAAG,CAAC,EAAE,YAAY,IAAI,aAAa,CAAC,CAAC;IAE/D,IAAM,iBAAiB,GAAG,OAAO,UAAU,KAAK,UAAU,CAAC;IAC3D,IAAM,oBAAoB,GAAG,OAAO,aAAa,KAAK,UAAU,CAAC;IACjE,IAAM,iBAAiB,GAAG,OAAO,UAAU,KAAK,UAAU,CAAC;IAE3D,SAAS,QAAQ;QACf,IAAM,cAAc,GAAwB,oBAAoB;cAC5D,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;cACxB,SAAS,CAAC;QACd,IAAM,GAAG,GAAwB,eAAe;cAC5C,YAAY,CAAC,cAAc,CAAC;cAC5B,cAAc,CAAC;QACnB,IAAM,QAAQ,GAAW,IAAI,CAAC,MAAM,GAAG,WAAW,CAAC,IAAI,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;QAEnE,IAAI,CAAC,QAAQ,EAAE;YACb,iBAAiB,IAAI,UAAU,CAAC,KAAK,EAAE,iBAAiB,EAAE,QAAQ,CAAC,CAAC;YAEpE,IAAI,QAAQ,EAAE;gBACZ,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;gBAEvE,oBAAoB;oBAClB,aAAa,CAAC,KAAK,EAAE,iBAAiB,EAAE,QAAQ,CAAC,CAAC;aACrD;SACF;aAAM;YACL,IAAM,QAAQ,GAAQ,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;YAChD,IAAM,MAAM,GAAqB,oBAAoB;kBACjD,GAAG;kBACH,KAAK,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC;YAElC,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YAE1D,SAAS,IAAI,gBAAgB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;YAE/C,iBAAiB,IAAI,UAAU,CAAC,KAAK,EAAE,iBAAiB,EAAE,QAAQ,CAAC,CAAC;YACpE,oBAAoB,IAAI,aAAa,CAAC,KAAK,EAAE,iBAAiB,EAAE,QAAQ,CAAC,CAAC;SAC3E;QAED,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC;KAClB;IAED,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE;QAChC,KAAK,EAAE;YACL,YAAY,EAAE,IAAI;YAClB,KAAK,EAAE,KAAK;SACb;QACD,aAAa,EAAE;YACb,YAAY,EAAE,IAAI;YAClB,GAAG;gBACD,OAAO;oBACL,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;oBAC/B,IAAI,EAAE,KAAK,CAAC,IAAI;oBAChB,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;iBACpC,CAAC;aACH;SACF;QACD,UAAU,EAAE;YACV,YAAY,EAAE,IAAI;YAClB,KAAK,EAAE,IAAI;SACZ;QACD,OAAO,EAAE;YACP,YAAY,EAAE,IAAI;YAClB,KAAK,EAAE,iBAAiB;SACzB;KACF,CAAC,CAAC;IAEH,OAAO,QAAQ,CAAC;CACjB;;;;"} |
| /*! ***************************************************************************** | ||
| Copyright (c) Microsoft Corporation. All rights reserved. | ||
| Licensed under the Apache License, Version 2.0 (the "License"); you may not use | ||
| this file except in compliance with the License. You may obtain a copy of the | ||
| License at http://www.apache.org/licenses/LICENSE-2.0 | ||
| THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED | ||
| WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, | ||
| MERCHANTABLITY OR NON-INFRINGEMENT. | ||
| See the Apache Version 2.0 License for specific language governing permissions | ||
| and limitations under the License. | ||
| ***************************************************************************** */ | ||
| function __rest(s, e) { | ||
| var t = {}; | ||
| for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) | ||
| t[p] = s[p]; | ||
| if (s != null && typeof Object.getOwnPropertySymbols === "function") | ||
| for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) | ||
| t[p[i]] = s[p[i]]; | ||
| return t; | ||
| } | ||
| function createAreKeysEqual(isEqual) { | ||
| /** | ||
| * @function areKeysEqual | ||
| * | ||
| * @description | ||
| * are the keys shallowly equal to one another | ||
| * | ||
| * @param key1 the keys array to test against | ||
| * @param key2 the keys array to test | ||
| * @returns are the keys shallowly equal | ||
| */ | ||
| return function areKeysEqual(key1, key2) { | ||
| var length = key1.length; | ||
| if (key2.length !== length) { | ||
| return false; | ||
| } | ||
| if (length === 1) { | ||
| return isEqual(key1[0], key2[0]); | ||
| } | ||
| var index = 0; | ||
| while (index < length) { | ||
| if (!isEqual(key1[index], key2[index])) { | ||
| return false; | ||
| } | ||
| index++; | ||
| } | ||
| return true; | ||
| }; | ||
| } | ||
| function createGetKeyIndex(options) { | ||
| var maxSize = options.maxSize; | ||
| var areKeysEqual = typeof options.isMatchingKey === 'function' | ||
| ? options.isMatchingKey | ||
| : createAreKeysEqual(options.isEqual); | ||
| /** | ||
| * @function getKeyIndex | ||
| * | ||
| * @description | ||
| * get the index of the matching key | ||
| * | ||
| * @param allKeys the list of all available keys | ||
| * @param keyToMatch the key to try to match | ||
| * | ||
| * @returns {number} the index of the matching key value, or -1 | ||
| */ | ||
| return function getKeyIndex(allKeys, keyToMatch) { | ||
| if (areKeysEqual(allKeys[0], keyToMatch)) { | ||
| return 0; | ||
| } | ||
| if (maxSize > 1) { | ||
| var length = maxSize > allKeys.length ? allKeys.length : maxSize; | ||
| var index = 1; | ||
| while (index < length) { | ||
| if (areKeysEqual(allKeys[index], keyToMatch)) { | ||
| return index; | ||
| } | ||
| index++; | ||
| } | ||
| } | ||
| return -1; | ||
| }; | ||
| } | ||
| /** | ||
| * @function isSameValueZero | ||
| * | ||
| * @description | ||
| * are the objects equal based on SameValueZero equality | ||
| * | ||
| * @param object1 the first object to compare | ||
| * @param object2 the second object to compare | ||
| * @returns are the two objects equal | ||
| */ | ||
| function isSameValueZero(object1, object2) { | ||
| return object1 === object2 || (object1 !== object1 && object2 !== object2); | ||
| } | ||
| /** | ||
| * @function mergeOptions | ||
| * | ||
| * @description | ||
| * merge the options into the target | ||
| * | ||
| * @param extraOptions the extra options passed | ||
| * @param providedOptions the defaulted options provided | ||
| * @returns the merged options | ||
| */ | ||
| function mergeOptions(extraOptions, providedOptions) { | ||
| var target = {}; | ||
| for (var key in extraOptions) { | ||
| target[key] = extraOptions[key]; | ||
| } | ||
| for (var key in providedOptions) { | ||
| target[key] = providedOptions[key]; | ||
| } | ||
| return target; | ||
| } | ||
| /** | ||
| * @function orderByLru | ||
| * | ||
| * @description | ||
| * order the array based on a Least-Recently-Used basis | ||
| * | ||
| * @param keys the keys to order | ||
| * @param newKey the new key to move to the front | ||
| * @param values the values to order | ||
| * @param newValue the new value to move to the front | ||
| * @param startingIndex the index of the item to move to the front | ||
| */ | ||
| function orderByLru(cache, newKey, newValue, startingIndex, maxSize) { | ||
| var index = startingIndex; | ||
| while (index--) { | ||
| cache.keys[index + 1] = cache.keys[index]; | ||
| cache.values[index + 1] = cache.values[index]; | ||
| } | ||
| cache.keys[0] = newKey; | ||
| cache.values[0] = newValue; | ||
| if (startingIndex >= maxSize) { | ||
| cache.keys.length = maxSize; | ||
| cache.values.length = maxSize; | ||
| } | ||
| } | ||
| function createUpdateAsyncCache(options) { | ||
| var getKeyIndex = createGetKeyIndex(options); | ||
| var onCacheChange = options.onCacheChange, onCacheHit = options.onCacheHit; | ||
| var shouldUpdateOnChange = typeof onCacheChange === 'function'; | ||
| var shouldUpdateOnHit = typeof onCacheHit === 'function'; | ||
| /** | ||
| * @function updateAsyncCache | ||
| * | ||
| * @description | ||
| * update the promise method to auto-remove from cache if rejected, and | ||
| * if resolved then fire cache hit / changed | ||
| * | ||
| * @param cache the memoized function's cache | ||
| * @param memoized the memoized function | ||
| */ | ||
| return function (cache, memoized) { | ||
| var key = cache.keys[0]; | ||
| cache.values[0] = cache.values[0] | ||
| .then(function (value) { | ||
| shouldUpdateOnHit && onCacheHit(cache, options, memoized); | ||
| shouldUpdateOnChange && onCacheChange(cache, options, memoized); | ||
| return value; | ||
| }) | ||
| .catch(function (error) { | ||
| var keyIndex = getKeyIndex(cache.keys, key); | ||
| if (~keyIndex) { | ||
| cache.keys.splice(keyIndex, 1); | ||
| cache.values.splice(keyIndex, 1); | ||
| } | ||
| throw error; | ||
| }); | ||
| }; | ||
| } | ||
| var slice = Array.prototype.slice; | ||
| function createMemoizedFunction(fn, options) { | ||
| if (options === void 0) { options = {}; } | ||
| // @ts-ignore | ||
| if (fn.isMemoized) { | ||
| return fn; | ||
| } | ||
| var _a = options.isEqual, isEqual = _a === void 0 ? isSameValueZero : _a, isMatchingKey = options.isMatchingKey, _b = options.isPromise, isPromise = _b === void 0 ? false : _b, _c = options.maxSize, maxSize = _c === void 0 ? 1 : _c, onCacheAdd = options.onCacheAdd, onCacheChange = options.onCacheChange, onCacheHit = options.onCacheHit, transformKey = options.transformKey, extraOptions = __rest(options, ["isEqual", "isMatchingKey", "isPromise", "maxSize", "onCacheAdd", "onCacheChange", "onCacheHit", "transformKey"]); | ||
| var normalizedOptions = mergeOptions(extraOptions, { | ||
| isEqual: isEqual, | ||
| isMatchingKey: isMatchingKey, | ||
| isPromise: isPromise, | ||
| maxSize: maxSize, | ||
| onCacheAdd: onCacheAdd, | ||
| onCacheChange: onCacheChange, | ||
| onCacheHit: onCacheHit, | ||
| transformKey: transformKey, | ||
| }); | ||
| var getKeyIndex = createGetKeyIndex(normalizedOptions); | ||
| var updateAsyncCache = createUpdateAsyncCache(normalizedOptions); | ||
| var keys = []; | ||
| var values = []; | ||
| var cache = { | ||
| keys: keys, | ||
| get size() { | ||
| return cache.keys.length; | ||
| }, | ||
| values: values, | ||
| }; | ||
| var canTransformKey = typeof transformKey === 'function'; | ||
| var shouldCloneArguments = !!(transformKey || isMatchingKey); | ||
| var shouldUpdateOnAdd = typeof onCacheAdd === 'function'; | ||
| var shouldUpdateOnChange = typeof onCacheChange === 'function'; | ||
| var shouldUpdateOnHit = typeof onCacheHit === 'function'; | ||
| function memoized() { | ||
| var normalizedArgs = shouldCloneArguments | ||
| ? slice.call(arguments, 0) | ||
| : arguments; | ||
| var key = canTransformKey | ||
| ? transformKey(normalizedArgs) | ||
| : normalizedArgs; | ||
| var keyIndex = keys.length ? getKeyIndex(keys, key) : -1; | ||
| if (~keyIndex) { | ||
| shouldUpdateOnHit && onCacheHit(cache, normalizedOptions, memoized); | ||
| if (keyIndex) { | ||
| orderByLru(cache, keys[keyIndex], values[keyIndex], keyIndex, maxSize); | ||
| shouldUpdateOnChange && | ||
| onCacheChange(cache, normalizedOptions, memoized); | ||
| } | ||
| } | ||
| else { | ||
| var newValue = fn.apply(this, arguments); | ||
| var newKey = shouldCloneArguments | ||
| ? key | ||
| : slice.call(normalizedArgs, 0); | ||
| orderByLru(cache, newKey, newValue, keys.length, maxSize); | ||
| isPromise && updateAsyncCache(cache, memoized); | ||
| shouldUpdateOnAdd && onCacheAdd(cache, normalizedOptions, memoized); | ||
| shouldUpdateOnChange && onCacheChange(cache, normalizedOptions, memoized); | ||
| } | ||
| return values[0]; | ||
| } | ||
| Object.defineProperties(memoized, { | ||
| cache: { | ||
| configurable: true, | ||
| value: cache, | ||
| }, | ||
| cacheSnapshot: { | ||
| configurable: true, | ||
| get: function () { | ||
| return { | ||
| keys: slice.call(cache.keys, 0), | ||
| size: cache.size, | ||
| values: slice.call(cache.values, 0), | ||
| }; | ||
| }, | ||
| }, | ||
| isMemoized: { | ||
| configurable: true, | ||
| value: true, | ||
| }, | ||
| options: { | ||
| configurable: true, | ||
| value: normalizedOptions, | ||
| }, | ||
| }); | ||
| return memoized; | ||
| } | ||
| export default createMemoizedFunction; | ||
| //# sourceMappingURL=micro-memoize.esm.js.map |
| module.exports = { | ||
| moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'], | ||
| roots: ['<rootDir>'], | ||
| transform: { | ||
| '\\.(ts|tsx)$': 'ts-jest', | ||
| }, | ||
| testRegex: '/__tests__/.*\\.(ts|tsx|js)$', | ||
| verbose: true, | ||
| }; |
| { | ||
| "compilerOptions": { | ||
| "allowJs": true, | ||
| "baseUrl": "src", | ||
| "esModuleInterop": true, | ||
| "jsx": "react", | ||
| "lib": ["dom", "es2015"], | ||
| "module": "es2015", | ||
| "moduleResolution": "node", | ||
| "noImplicitAny": true, | ||
| "outDir": "./dist", | ||
| "sourceMap": true, | ||
| "target": "es5" | ||
| }, | ||
| "exclude": ["node_modules"], | ||
| "include": ["src/*", "__tests__/*"] | ||
| } |
| { | ||
| "extends": "tslint-config-airbnb", | ||
| "rules": { | ||
| "import-name": false, | ||
| "no-increment-decrement": false, | ||
| "prefer-array-literal": false | ||
| } | ||
| } |
+246
-317
| (function (global, factory) { | ||
| typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : | ||
| typeof define === 'function' && define.amd ? define(['exports'], factory) : | ||
| (factory((global.memoize = {}))); | ||
| }(this, (function (exports) { 'use strict'; | ||
| typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : | ||
| typeof define === 'function' && define.amd ? define(factory) : | ||
| (global = global || self, global['micro-memoize'] = factory()); | ||
| }(this, function () { 'use strict'; | ||
| function _objectWithoutPropertiesLoose(source, excluded) { | ||
| if (source == null) return {}; | ||
| var target = {}; | ||
| var sourceKeys = Object.keys(source); | ||
| var key, i; | ||
| /*! ***************************************************************************** | ||
| Copyright (c) Microsoft Corporation. All rights reserved. | ||
| Licensed under the Apache License, Version 2.0 (the "License"); you may not use | ||
| this file except in compliance with the License. You may obtain a copy of the | ||
| License at http://www.apache.org/licenses/LICENSE-2.0 | ||
| for (i = 0; i < sourceKeys.length; i++) { | ||
| key = sourceKeys[i]; | ||
| if (excluded.indexOf(key) >= 0) continue; | ||
| target[key] = source[key]; | ||
| } | ||
| THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED | ||
| WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, | ||
| MERCHANTABLITY OR NON-INFRINGEMENT. | ||
| return target; | ||
| } | ||
| See the Apache Version 2.0 License for specific language governing permissions | ||
| and limitations under the License. | ||
| ***************************************************************************** */ | ||
| // types | ||
| var hasOwnProperty = Object.prototype.hasOwnProperty; | ||
| /** | ||
| * @function assign | ||
| * | ||
| * @description | ||
| * merge the sources into the target, as you would with Object.assign() | ||
| * | ||
| * @param {Object} target object to merge into | ||
| * @param {...Array<Object>} sources the sources to merge into the target | ||
| * @returns {Object} the merged object | ||
| */ | ||
| var assign = function assign(target) { | ||
| var source; | ||
| for (var index = 0; index < (arguments.length <= 1 ? 0 : arguments.length - 1); index++) { | ||
| source = index + 1 < 1 || arguments.length <= index + 1 ? undefined : arguments[index + 1]; | ||
| if (source && typeof source === 'object') { | ||
| for (var key in source) { | ||
| if (hasOwnProperty.call(source, key)) { | ||
| target[key] = source[key]; | ||
| } | ||
| } | ||
| } | ||
| function __rest(s, e) { | ||
| var t = {}; | ||
| for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) | ||
| t[p] = s[p]; | ||
| if (s != null && typeof Object.getOwnPropertySymbols === "function") | ||
| for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) | ||
| t[p[i]] = s[p[i]]; | ||
| return t; | ||
| } | ||
| return target; | ||
| }; | ||
| /** | ||
| * @function cloneArray | ||
| * | ||
| * @description | ||
| * clone the array-like object and return the new array | ||
| * | ||
| * @param {Array<any>|Arguments} arrayLike the array-like object to clone | ||
| * @returns {Array<any>} the clone of the array | ||
| */ | ||
| var cloneArray = function cloneArray(arrayLike) { | ||
| var length = arrayLike.length; | ||
| if (!length) { | ||
| return []; | ||
| function createAreKeysEqual(isEqual) { | ||
| /** | ||
| * @function areKeysEqual | ||
| * | ||
| * @description | ||
| * are the keys shallowly equal to one another | ||
| * | ||
| * @param key1 the keys array to test against | ||
| * @param key2 the keys array to test | ||
| * @returns are the keys shallowly equal | ||
| */ | ||
| return function areKeysEqual(key1, key2) { | ||
| var length = key1.length; | ||
| if (key2.length !== length) { | ||
| return false; | ||
| } | ||
| if (length === 1) { | ||
| return isEqual(key1[0], key2[0]); | ||
| } | ||
| var index = 0; | ||
| while (index < length) { | ||
| if (!isEqual(key1[index], key2[index])) { | ||
| return false; | ||
| } | ||
| index++; | ||
| } | ||
| return true; | ||
| }; | ||
| } | ||
| if (length === 1) { | ||
| return [arrayLike[0]]; | ||
| function createGetKeyIndex(options) { | ||
| var maxSize = options.maxSize; | ||
| var areKeysEqual = typeof options.isMatchingKey === 'function' | ||
| ? options.isMatchingKey | ||
| : createAreKeysEqual(options.isEqual); | ||
| /** | ||
| * @function getKeyIndex | ||
| * | ||
| * @description | ||
| * get the index of the matching key | ||
| * | ||
| * @param allKeys the list of all available keys | ||
| * @param keyToMatch the key to try to match | ||
| * | ||
| * @returns {number} the index of the matching key value, or -1 | ||
| */ | ||
| return function getKeyIndex(allKeys, keyToMatch) { | ||
| if (areKeysEqual(allKeys[0], keyToMatch)) { | ||
| return 0; | ||
| } | ||
| if (maxSize > 1) { | ||
| var length = maxSize > allKeys.length ? allKeys.length : maxSize; | ||
| var index = 1; | ||
| while (index < length) { | ||
| if (areKeysEqual(allKeys[index], keyToMatch)) { | ||
| return index; | ||
| } | ||
| index++; | ||
| } | ||
| } | ||
| return -1; | ||
| }; | ||
| } | ||
| if (length === 2) { | ||
| return [arrayLike[0], arrayLike[1]]; | ||
| /** | ||
| * @function isSameValueZero | ||
| * | ||
| * @description | ||
| * are the objects equal based on SameValueZero equality | ||
| * | ||
| * @param object1 the first object to compare | ||
| * @param object2 the second object to compare | ||
| * @returns are the two objects equal | ||
| */ | ||
| function isSameValueZero(object1, object2) { | ||
| return object1 === object2 || (object1 !== object1 && object2 !== object2); | ||
| } | ||
| if (length === 3) { | ||
| return [arrayLike[0], arrayLike[1], arrayLike[2]]; | ||
| } | ||
| var array = new Array(length); | ||
| for (var index = 0; index < length; index++) { | ||
| array[index] = arrayLike[index]; | ||
| } | ||
| return array; | ||
| }; | ||
| var createAreKeysEqual = function createAreKeysEqual(isEqual | ||
| /** | ||
| * @function areKeysEqual | ||
| * | ||
| * @description | ||
| * are the keys shallowly equal to one another | ||
| * | ||
| * @param {Array<any>} keys1 the keys array to test against | ||
| * @param {Array<any>} keys2 the keys array to test | ||
| * @returns {boolean} are the keys shallowly equal | ||
| */ | ||
| ) { | ||
| return function (keys1, keys2) { | ||
| if (keys1.length !== keys2.length) { | ||
| return false; | ||
| } | ||
| for (var index = 0, length = keys1.length; index < length; index++) { | ||
| if (!isEqual(keys1[index], keys2[index])) { | ||
| return false; | ||
| } | ||
| } | ||
| return true; | ||
| }; | ||
| }; | ||
| var createGetKeyIndex = function createGetKeyIndex(isEqual, isMatchingKey) { | ||
| var areKeysEqual = typeof isMatchingKey === 'function' ? isMatchingKey : createAreKeysEqual(isEqual); | ||
| /** | ||
| * @function getKeyIndex | ||
| * @function mergeOptions | ||
| * | ||
| * @description | ||
| * get the index of the matching key | ||
| * merge the options into the target | ||
| * | ||
| * @param {Array<Array<any>>} allKeys the list of all available keys | ||
| * @param {Array<any>} keysToMatch the key to try to match | ||
| * | ||
| * @returns {number} the index of the matching key value, or -1 | ||
| * @param extraOptions the extra options passed | ||
| * @param providedOptions the defaulted options provided | ||
| * @returns the merged options | ||
| */ | ||
| return function (allKeys, keysToMatch) { | ||
| for (var index = 0; index < allKeys.length; index++) { | ||
| if (areKeysEqual(allKeys[index], keysToMatch)) { | ||
| return index; | ||
| function mergeOptions(extraOptions, providedOptions) { | ||
| var target = {}; | ||
| for (var key in extraOptions) { | ||
| target[key] = extraOptions[key]; | ||
| } | ||
| } | ||
| return -1; | ||
| }; | ||
| }; | ||
| /** | ||
| * @function isSameValueZero | ||
| * | ||
| * @description | ||
| * are the objects equal based on SameValueZero | ||
| * | ||
| * @param {any} object1 the first object to compare | ||
| * @param {any} object2 the second object to compare | ||
| * @returns {boolean} are the two objects equal | ||
| */ | ||
| var isSameValueZero = function isSameValueZero(object1, object2) { | ||
| return object1 === object2 || object1 !== object1 && object2 !== object2; | ||
| }; | ||
| var onCacheOperation = function onCacheOperation(cacheIgnored, optionsIgnored, memoizedIgnored) {}; | ||
| /** | ||
| * @function orderByLru | ||
| * | ||
| * @description | ||
| * order the array based on a Least-Recently-Used basis | ||
| * | ||
| * @param {Array<any>} array the array to order | ||
| * @param {any} value the value to assign at the beginning of the array | ||
| * @param {number} startingIndex the index of the item to move to the front | ||
| */ | ||
| var orderByLru = function orderByLru(array, value, startingIndex) { | ||
| var index = startingIndex; | ||
| while (index--) { | ||
| array[index + 1] = array[index]; | ||
| } | ||
| array[0] = value; | ||
| }; | ||
| /** | ||
| * @function createSetPromiseHandler | ||
| * | ||
| * @description | ||
| * update the promise method to auto-remove from cache if rejected, and if resolved then fire cache hit / changed | ||
| * | ||
| * @param {Options} options the options for the memoized function | ||
| * @param {function(Cache, function): function} memoized the memoized function | ||
| */ | ||
| var createSetPromiseHandler = function createSetPromiseHandler(options) { | ||
| var getKeyIndex = createGetKeyIndex(options.isEqual, options.isMatchingKey); | ||
| return function (cache, memoized) { | ||
| var key = cache.keys[0]; | ||
| cache.values[0] = cache.values[0].then(function (value) { | ||
| options.onCacheHit(cache, options, memoized); | ||
| options.onCacheChange(cache, options, memoized); | ||
| return value; | ||
| }).catch(function (error) { | ||
| var keyIndex = getKeyIndex(cache.keys, key); | ||
| if (~keyIndex) { | ||
| cache.keys.splice(keyIndex, 1); | ||
| cache.values.splice(keyIndex, 1); | ||
| for (var key in providedOptions) { | ||
| target[key] = providedOptions[key]; | ||
| } | ||
| throw error; | ||
| }); | ||
| }; | ||
| }; | ||
| /** | ||
| * @function memoize | ||
| * | ||
| * @description | ||
| * get the memoized version of the method passed | ||
| * | ||
| * @param {function} fn the method to memoize | ||
| * @param {Object} [options={}] the options to build the memoizer with | ||
| * @param {boolean} [options.isEqual=isSameValueZero] the method to compare equality of keys with | ||
| * @param {number} [options.maxSize=1] the number of items to store in cache | ||
| * @returns {function} the memoized method | ||
| */ | ||
| function memoize(fn, options) { | ||
| // if it is a memoized method, don't re-memoize it | ||
| if (fn.isMemoized) { | ||
| return fn; | ||
| return target; | ||
| } | ||
| var _ref = options || {}, | ||
| _ref$isEqual = _ref.isEqual, | ||
| isEqual = _ref$isEqual === void 0 ? isSameValueZero : _ref$isEqual, | ||
| isMatchingKey = _ref.isMatchingKey, | ||
| _ref$isPromise = _ref.isPromise, | ||
| isPromise = _ref$isPromise === void 0 ? false : _ref$isPromise, | ||
| _ref$maxSize = _ref.maxSize, | ||
| maxSize = _ref$maxSize === void 0 ? 1 : _ref$maxSize, | ||
| _ref$onCacheAdd = _ref.onCacheAdd, | ||
| onCacheAdd = _ref$onCacheAdd === void 0 ? onCacheOperation : _ref$onCacheAdd, | ||
| _ref$onCacheChange = _ref.onCacheChange, | ||
| onCacheChange = _ref$onCacheChange === void 0 ? onCacheOperation : _ref$onCacheChange, | ||
| _ref$onCacheHit = _ref.onCacheHit, | ||
| onCacheHit = _ref$onCacheHit === void 0 ? onCacheOperation : _ref$onCacheHit, | ||
| transformKey = _ref.transformKey, | ||
| extraOptions = _objectWithoutPropertiesLoose(_ref, ["isEqual", "isMatchingKey", "isPromise", "maxSize", "onCacheAdd", "onCacheChange", "onCacheHit", "transformKey"]); | ||
| var normalizedOptions = assign({}, extraOptions, { | ||
| isEqual: isEqual, | ||
| isMatchingKey: isMatchingKey, | ||
| isPromise: isPromise, | ||
| maxSize: maxSize, | ||
| onCacheAdd: onCacheAdd, | ||
| onCacheChange: onCacheChange, | ||
| onCacheHit: onCacheHit, | ||
| transformKey: transformKey | ||
| }); | ||
| var getKeyIndex = createGetKeyIndex(isEqual, isMatchingKey); | ||
| var setPromiseHandler = createSetPromiseHandler(normalizedOptions); | ||
| var shouldCloneArguments = !!(transformKey || isMatchingKey); | ||
| var cache = { | ||
| keys: [], | ||
| get size() { | ||
| return cache.keys.length; | ||
| }, | ||
| values: [] | ||
| }; | ||
| var keys = cache.keys, | ||
| values = cache.values; | ||
| /** | ||
| * @function memoized | ||
| * @function orderByLru | ||
| * | ||
| * @description | ||
| * the memoized version of the method passed | ||
| * order the array based on a Least-Recently-Used basis | ||
| * | ||
| * @param {...Array<any>} key the arguments passed, which create a unique cache key | ||
| * @returns {any} the value of the method called with the arguments | ||
| * @param keys the keys to order | ||
| * @param newKey the new key to move to the front | ||
| * @param values the values to order | ||
| * @param newValue the new value to move to the front | ||
| * @param startingIndex the index of the item to move to the front | ||
| */ | ||
| function memoized() { | ||
| var args = arguments; | ||
| var normalizedArgs = shouldCloneArguments ? cloneArray(args) : args; | ||
| var key = transformKey ? transformKey(normalizedArgs) : normalizedArgs; | ||
| var keyIndex = getKeyIndex(keys, key); | ||
| if (~keyIndex) { | ||
| onCacheHit(cache, normalizedOptions, memoized); | ||
| if (keyIndex) { | ||
| orderByLru(keys, keys[keyIndex], keyIndex); | ||
| orderByLru(values, values[keyIndex], keyIndex); | ||
| onCacheChange(cache, normalizedOptions, memoized); | ||
| function orderByLru(cache, newKey, newValue, startingIndex, maxSize) { | ||
| var index = startingIndex; | ||
| while (index--) { | ||
| cache.keys[index + 1] = cache.keys[index]; | ||
| cache.values[index + 1] = cache.values[index]; | ||
| } | ||
| } else { | ||
| if (keys.length >= maxSize) { | ||
| keys.pop(); | ||
| values.pop(); | ||
| cache.keys[0] = newKey; | ||
| cache.values[0] = newValue; | ||
| if (startingIndex >= maxSize) { | ||
| cache.keys.length = maxSize; | ||
| cache.values.length = maxSize; | ||
| } | ||
| var newKey = shouldCloneArguments ? key : cloneArray(normalizedArgs); | ||
| var newValue = fn.apply(this, args); | ||
| orderByLru(keys, newKey, keys.length); | ||
| orderByLru(values, newValue, values.length); | ||
| if (isPromise) { | ||
| setPromiseHandler(cache, memoized); | ||
| } | ||
| onCacheAdd(cache, normalizedOptions, memoized); | ||
| onCacheChange(cache, normalizedOptions, memoized); | ||
| } | ||
| return values[0]; | ||
| } | ||
| function createUpdateAsyncCache(options) { | ||
| var getKeyIndex = createGetKeyIndex(options); | ||
| var onCacheChange = options.onCacheChange, onCacheHit = options.onCacheHit; | ||
| var shouldUpdateOnChange = typeof onCacheChange === 'function'; | ||
| var shouldUpdateOnHit = typeof onCacheHit === 'function'; | ||
| /** | ||
| * @function updateAsyncCache | ||
| * | ||
| * @description | ||
| * update the promise method to auto-remove from cache if rejected, and | ||
| * if resolved then fire cache hit / changed | ||
| * | ||
| * @param cache the memoized function's cache | ||
| * @param memoized the memoized function | ||
| */ | ||
| return function (cache, memoized) { | ||
| var key = cache.keys[0]; | ||
| cache.values[0] = cache.values[0] | ||
| .then(function (value) { | ||
| shouldUpdateOnHit && onCacheHit(cache, options, memoized); | ||
| shouldUpdateOnChange && onCacheChange(cache, options, memoized); | ||
| return value; | ||
| }) | ||
| .catch(function (error) { | ||
| var keyIndex = getKeyIndex(cache.keys, key); | ||
| if (~keyIndex) { | ||
| cache.keys.splice(keyIndex, 1); | ||
| cache.values.splice(keyIndex, 1); | ||
| } | ||
| throw error; | ||
| }); | ||
| }; | ||
| } | ||
| Object.defineProperties(memoized, { | ||
| cache: { | ||
| configurable: true, | ||
| get: function get() { | ||
| return cache; | ||
| var slice = Array.prototype.slice; | ||
| function createMemoizedFunction(fn, options) { | ||
| if (options === void 0) { options = {}; } | ||
| // @ts-ignore | ||
| if (fn.isMemoized) { | ||
| return fn; | ||
| } | ||
| }, | ||
| cacheSnapshot: { | ||
| configurable: true, | ||
| get: function get() { | ||
| return { | ||
| keys: cloneArray(cache.keys), | ||
| size: cache.size, | ||
| values: cloneArray(cache.values) | ||
| }; | ||
| var _a = options.isEqual, isEqual = _a === void 0 ? isSameValueZero : _a, isMatchingKey = options.isMatchingKey, _b = options.isPromise, isPromise = _b === void 0 ? false : _b, _c = options.maxSize, maxSize = _c === void 0 ? 1 : _c, onCacheAdd = options.onCacheAdd, onCacheChange = options.onCacheChange, onCacheHit = options.onCacheHit, transformKey = options.transformKey, extraOptions = __rest(options, ["isEqual", "isMatchingKey", "isPromise", "maxSize", "onCacheAdd", "onCacheChange", "onCacheHit", "transformKey"]); | ||
| var normalizedOptions = mergeOptions(extraOptions, { | ||
| isEqual: isEqual, | ||
| isMatchingKey: isMatchingKey, | ||
| isPromise: isPromise, | ||
| maxSize: maxSize, | ||
| onCacheAdd: onCacheAdd, | ||
| onCacheChange: onCacheChange, | ||
| onCacheHit: onCacheHit, | ||
| transformKey: transformKey, | ||
| }); | ||
| var getKeyIndex = createGetKeyIndex(normalizedOptions); | ||
| var updateAsyncCache = createUpdateAsyncCache(normalizedOptions); | ||
| var keys = []; | ||
| var values = []; | ||
| var cache = { | ||
| keys: keys, | ||
| get size() { | ||
| return cache.keys.length; | ||
| }, | ||
| values: values, | ||
| }; | ||
| var canTransformKey = typeof transformKey === 'function'; | ||
| var shouldCloneArguments = !!(transformKey || isMatchingKey); | ||
| var shouldUpdateOnAdd = typeof onCacheAdd === 'function'; | ||
| var shouldUpdateOnChange = typeof onCacheChange === 'function'; | ||
| var shouldUpdateOnHit = typeof onCacheHit === 'function'; | ||
| function memoized() { | ||
| var normalizedArgs = shouldCloneArguments | ||
| ? slice.call(arguments, 0) | ||
| : arguments; | ||
| var key = canTransformKey | ||
| ? transformKey(normalizedArgs) | ||
| : normalizedArgs; | ||
| var keyIndex = keys.length ? getKeyIndex(keys, key) : -1; | ||
| if (~keyIndex) { | ||
| shouldUpdateOnHit && onCacheHit(cache, normalizedOptions, memoized); | ||
| if (keyIndex) { | ||
| orderByLru(cache, keys[keyIndex], values[keyIndex], keyIndex, maxSize); | ||
| shouldUpdateOnChange && | ||
| onCacheChange(cache, normalizedOptions, memoized); | ||
| } | ||
| } | ||
| else { | ||
| var newValue = fn.apply(this, arguments); | ||
| var newKey = shouldCloneArguments | ||
| ? key | ||
| : slice.call(normalizedArgs, 0); | ||
| orderByLru(cache, newKey, newValue, keys.length, maxSize); | ||
| isPromise && updateAsyncCache(cache, memoized); | ||
| shouldUpdateOnAdd && onCacheAdd(cache, normalizedOptions, memoized); | ||
| shouldUpdateOnChange && onCacheChange(cache, normalizedOptions, memoized); | ||
| } | ||
| return values[0]; | ||
| } | ||
| }, | ||
| isMemoized: { | ||
| configurable: true, | ||
| get: function get() { | ||
| return true; | ||
| } | ||
| }, | ||
| options: { | ||
| configurable: true, | ||
| get: function get() { | ||
| return normalizedOptions; | ||
| } | ||
| } | ||
| }); | ||
| return memoized; | ||
| } | ||
| Object.defineProperties(memoized, { | ||
| cache: { | ||
| configurable: true, | ||
| value: cache, | ||
| }, | ||
| cacheSnapshot: { | ||
| configurable: true, | ||
| get: function () { | ||
| return { | ||
| keys: slice.call(cache.keys, 0), | ||
| size: cache.size, | ||
| values: slice.call(cache.values, 0), | ||
| }; | ||
| }, | ||
| }, | ||
| isMemoized: { | ||
| configurable: true, | ||
| value: true, | ||
| }, | ||
| options: { | ||
| configurable: true, | ||
| value: normalizedOptions, | ||
| }, | ||
| }); | ||
| return memoized; | ||
| } | ||
| exports.default = memoize; | ||
| return createMemoizedFunction; | ||
| Object.defineProperty(exports, '__esModule', { value: true }); | ||
| }))); | ||
| })); | ||
| //# sourceMappingURL=micro-memoize.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"micro-memoize.js","sources":["../src/utils.js","../src/index.js"],"sourcesContent":["// @flow\n\n// types\nimport type {\n Cache,\n Options,\n} from './types';\n\nconst hasOwnProperty: Function = Object.prototype.hasOwnProperty;\n\n/**\n * @function assign\n *\n * @description\n * merge the sources into the target, as you would with Object.assign()\n *\n * @param {Object} target object to merge into\n * @param {...Array<Object>} sources the sources to merge into the target\n * @returns {Object} the merged object\n */\nexport const assign = (target: Object, ...sources: Array<Object>): Object => {\n let source;\n\n for (let index = 0; index < sources.length; index++) {\n source = sources[index];\n\n if (source && typeof source === 'object') {\n for (let key in source) {\n if (hasOwnProperty.call(source, key)) {\n target[key] = source[key];\n }\n }\n }\n }\n\n return target;\n};\n\n/**\n * @function cloneArray\n *\n * @description\n * clone the array-like object and return the new array\n *\n * @param {Array<any>|Arguments} arrayLike the array-like object to clone\n * @returns {Array<any>} the clone of the array\n */\nexport const cloneArray = (arrayLike: Array<any> | Object): Array<any> => {\n const length: number = arrayLike.length;\n\n if (!length) {\n return [];\n }\n\n if (length === 1) {\n return [arrayLike[0]];\n }\n\n if (length === 2) {\n return [arrayLike[0], arrayLike[1]];\n }\n\n if (length === 3) {\n return [arrayLike[0], arrayLike[1], arrayLike[2]];\n }\n\n const array: Array<any> = new Array(length);\n\n for (let index: number = 0; index < length; index++) {\n array[index] = arrayLike[index];\n }\n\n return array;\n};\n\nexport const createAreKeysEqual = (isEqual: Function): Function =>\n /**\n * @function areKeysEqual\n *\n * @description\n * are the keys shallowly equal to one another\n *\n * @param {Array<any>} keys1 the keys array to test against\n * @param {Array<any>} keys2 the keys array to test\n * @returns {boolean} are the keys shallowly equal\n */\n (keys1: Array<any>, keys2: Array<any>): boolean => {\n if (keys1.length !== keys2.length) {\n return false;\n }\n\n for (let index: number = 0, length: number = keys1.length; index < length; index++) {\n if (!isEqual(keys1[index], keys2[index])) {\n return false;\n }\n }\n\n return true;\n };\n\nexport const createGetKeyIndex = (isEqual: Function, isMatchingKey: ?Function): Function => {\n const areKeysEqual: Function = typeof isMatchingKey === 'function' ? isMatchingKey : createAreKeysEqual(isEqual);\n\n /**\n * @function getKeyIndex\n *\n * @description\n * get the index of the matching key\n *\n * @param {Array<Array<any>>} allKeys the list of all available keys\n * @param {Array<any>} keysToMatch the key to try to match\n *\n * @returns {number} the index of the matching key value, or -1\n */\n return (allKeys: Array<Array<any>>, keysToMatch: Array<any>): number => {\n for (let index: number = 0; index < allKeys.length; index++) {\n if (areKeysEqual(allKeys[index], keysToMatch)) {\n return index;\n }\n }\n\n return -1;\n };\n};\n\n/**\n * @function isSameValueZero\n *\n * @description\n * are the objects equal based on SameValueZero\n *\n * @param {any} object1 the first object to compare\n * @param {any} object2 the second object to compare\n * @returns {boolean} are the two objects equal\n */\nexport const isSameValueZero = (object1: any, object2: any): boolean =>\n object1 === object2 || (object1 !== object1 && object2 !== object2);\n\nexport const onCacheOperation = (cacheIgnored: Cache, optionsIgnored: Options, memoizedIgnored: Function): void => {};\n\n/**\n * @function orderByLru\n *\n * @description\n * order the array based on a Least-Recently-Used basis\n *\n * @param {Array<any>} array the array to order\n * @param {any} value the value to assign at the beginning of the array\n * @param {number} startingIndex the index of the item to move to the front\n */\nexport const orderByLru = (array: Array<any>, value: any, startingIndex: number) => {\n let index: number = startingIndex;\n\n while (index--) {\n array[index + 1] = array[index];\n }\n\n array[0] = value;\n};\n\n/**\n * @function createSetPromiseHandler\n *\n * @description\n * update the promise method to auto-remove from cache if rejected, and if resolved then fire cache hit / changed\n *\n * @param {Options} options the options for the memoized function\n * @param {function(Cache, function): function} memoized the memoized function\n */\nexport const createSetPromiseHandler = (options: Options): Function => {\n const getKeyIndex = createGetKeyIndex(options.isEqual, options.isMatchingKey);\n\n return (cache: Cache, memoized: Function): void => {\n const key: any = cache.keys[0];\n\n cache.values[0] = cache.values[0]\n .then(\n (value: any): any => {\n options.onCacheHit(cache, options, memoized);\n options.onCacheChange(cache, options, memoized);\n\n return value;\n }\n )\n .catch((error: Error) => {\n const keyIndex: number = getKeyIndex(cache.keys, key);\n\n if (~keyIndex) {\n cache.keys.splice(keyIndex, 1);\n cache.values.splice(keyIndex, 1);\n }\n\n throw error;\n });\n };\n};\n","// @flow\n\n// types\nimport type {\n Cache,\n Options,\n} from './types';\n\n// utils\nimport {\n assign,\n cloneArray,\n createGetKeyIndex,\n createSetPromiseHandler,\n isSameValueZero,\n onCacheOperation,\n orderByLru,\n} from './utils';\n\n/**\n * @function memoize\n *\n * @description\n * get the memoized version of the method passed\n *\n * @param {function} fn the method to memoize\n * @param {Object} [options={}] the options to build the memoizer with\n * @param {boolean} [options.isEqual=isSameValueZero] the method to compare equality of keys with\n * @param {number} [options.maxSize=1] the number of items to store in cache\n * @returns {function} the memoized method\n */\nexport default function memoize(fn: Function, options: Options) {\n // if it is a memoized method, don't re-memoize it\n if (fn.isMemoized) {\n return fn;\n }\n\n const {\n isEqual = isSameValueZero,\n isMatchingKey,\n isPromise = false,\n maxSize = 1,\n onCacheAdd = onCacheOperation,\n onCacheChange = onCacheOperation,\n onCacheHit = onCacheOperation,\n transformKey,\n ...extraOptions\n } = options || {};\n\n const normalizedOptions = assign({}, extraOptions, {\n isEqual,\n isMatchingKey,\n isPromise,\n maxSize,\n onCacheAdd,\n onCacheChange,\n onCacheHit,\n transformKey,\n });\n\n const getKeyIndex: Function = createGetKeyIndex(isEqual, isMatchingKey);\n const setPromiseHandler: Function = createSetPromiseHandler(normalizedOptions);\n const shouldCloneArguments: boolean = !!(transformKey || isMatchingKey);\n\n const cache: Cache = {\n keys: [],\n get size() {\n return cache.keys.length;\n },\n values: [],\n };\n const {keys, values} = cache;\n\n /**\n * @function memoized\n *\n * @description\n * the memoized version of the method passed\n *\n * @param {...Array<any>} key the arguments passed, which create a unique cache key\n * @returns {any} the value of the method called with the arguments\n */\n function memoized(): any {\n const args: Object = arguments;\n const normalizedArgs: Array<any> | Object = shouldCloneArguments ? cloneArray(args) : args;\n const key: Array<any> | Object = transformKey ? transformKey(normalizedArgs) : normalizedArgs;\n const keyIndex: number = getKeyIndex(keys, key);\n\n if (~keyIndex) {\n onCacheHit(cache, normalizedOptions, memoized);\n\n if (keyIndex) {\n orderByLru(keys, keys[keyIndex], keyIndex);\n orderByLru(values, values[keyIndex], keyIndex);\n\n onCacheChange(cache, normalizedOptions, memoized);\n }\n } else {\n if (keys.length >= maxSize) {\n keys.pop();\n values.pop();\n }\n\n const newKey = shouldCloneArguments ? key : cloneArray(normalizedArgs);\n const newValue = fn.apply(this, args);\n\n orderByLru(keys, newKey, keys.length);\n orderByLru(values, newValue, values.length);\n\n if (isPromise) {\n setPromiseHandler(cache, memoized);\n }\n\n onCacheAdd(cache, normalizedOptions, memoized);\n onCacheChange(cache, normalizedOptions, memoized);\n }\n\n return values[0];\n }\n\n Object.defineProperties(\n memoized,\n ({\n cache: {\n configurable: true,\n get() {\n return cache;\n },\n },\n cacheSnapshot: {\n configurable: true,\n get() {\n return {\n keys: cloneArray(cache.keys),\n size: cache.size,\n values: cloneArray(cache.values),\n };\n },\n },\n isMemoized: {\n configurable: true,\n get() {\n return true;\n },\n },\n options: {\n configurable: true,\n get() {\n return normalizedOptions;\n },\n },\n }: Object)\n );\n\n return memoized;\n}\n"],"names":["hasOwnProperty","Object","prototype","assign","target","source","index","key","call","cloneArray","arrayLike","length","array","Array","createAreKeysEqual","isEqual","keys1","keys2","createGetKeyIndex","isMatchingKey","areKeysEqual","allKeys","keysToMatch","isSameValueZero","object1","object2","onCacheOperation","cacheIgnored","optionsIgnored","memoizedIgnored","orderByLru","value","startingIndex","createSetPromiseHandler","options","getKeyIndex","cache","memoized","keys","values","then","onCacheHit","onCacheChange","catch","error","keyIndex","splice","memoize","fn","isMemoized","isPromise","maxSize","onCacheAdd","transformKey","extraOptions","normalizedOptions","setPromiseHandler","shouldCloneArguments","size","args","arguments","normalizedArgs","pop","newKey","newValue","apply","defineProperties","configurable","get","cacheSnapshot"],"mappings":"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"} | ||
| {"version":3,"file":"micro-memoize.js","sources":["../src/utils.ts","../src/index.ts"],"sourcesContent":["export function createAreKeysEqual(\n isEqual: MicroMemoize.EqualityComparator,\n): MicroMemoize.MatchingKeyComparator {\n /**\n * @function areKeysEqual\n *\n * @description\n * are the keys shallowly equal to one another\n *\n * @param key1 the keys array to test against\n * @param key2 the keys array to test\n * @returns are the keys shallowly equal\n */\n return function areKeysEqual(key1: MicroMemoize.Key, key2: MicroMemoize.Key) {\n const length = key1.length;\n\n if (key2.length !== length) {\n return false;\n }\n\n if (length === 1) {\n return isEqual(key1[0], key2[0]);\n }\n\n let index = 0;\n\n while (index < length) {\n if (!isEqual(key1[index], key2[index])) {\n return false;\n }\n\n index++;\n }\n\n return true;\n };\n}\n\nexport function createGetKeyIndex(\n options: MicroMemoize.Options,\n): MicroMemoize.KeyIndexGetter {\n const { maxSize } = options;\n const areKeysEqual: MicroMemoize.MatchingKeyComparator =\n typeof options.isMatchingKey === 'function'\n ? options.isMatchingKey\n : createAreKeysEqual(options.isEqual);\n\n /**\n * @function getKeyIndex\n *\n * @description\n * get the index of the matching key\n *\n * @param allKeys the list of all available keys\n * @param keyToMatch the key to try to match\n *\n * @returns {number} the index of the matching key value, or -1\n */\n return function getKeyIndex(\n allKeys: MicroMemoize.Keys,\n keyToMatch: MicroMemoize.Key,\n ) {\n if (areKeysEqual(allKeys[0], keyToMatch)) {\n return 0;\n }\n\n if (maxSize > 1) {\n const length = maxSize > allKeys.length ? allKeys.length : maxSize;\n\n let index = 1;\n\n while (index < length) {\n if (areKeysEqual(allKeys[index], keyToMatch)) {\n return index;\n }\n\n index++;\n }\n }\n\n return -1;\n };\n}\n\n/**\n * @function isSameValueZero\n *\n * @description\n * are the objects equal based on SameValueZero equality\n *\n * @param object1 the first object to compare\n * @param object2 the second object to compare\n * @returns are the two objects equal\n */\nexport function isSameValueZero(object1: any, object2: any) {\n return object1 === object2 || (object1 !== object1 && object2 !== object2);\n}\n\n/**\n * @function mergeOptions\n *\n * @description\n * merge the options into the target\n *\n * @param extraOptions the extra options passed\n * @param providedOptions the defaulted options provided\n * @returns the merged options\n */\nexport function mergeOptions(\n extraOptions: PlainObject,\n providedOptions: PlainObject,\n) {\n const target: PlainObject = {};\n\n for (const key in extraOptions) {\n target[key] = extraOptions[key];\n }\n\n for (const key in providedOptions) {\n target[key] = providedOptions[key];\n }\n\n return target;\n}\n\n/**\n * @function orderByLru\n *\n * @description\n * order the array based on a Least-Recently-Used basis\n *\n * @param keys the keys to order\n * @param newKey the new key to move to the front\n * @param values the values to order\n * @param newValue the new value to move to the front\n * @param startingIndex the index of the item to move to the front\n */\nexport function orderByLru(\n cache: MicroMemoize.Cache,\n newKey: MicroMemoize.Key,\n newValue: any,\n startingIndex: number,\n maxSize: number,\n) {\n let index = startingIndex;\n\n while (index--) {\n cache.keys[index + 1] = cache.keys[index];\n cache.values[index + 1] = cache.values[index];\n }\n\n cache.keys[0] = newKey;\n cache.values[0] = newValue;\n\n if (startingIndex >= maxSize) {\n cache.keys.length = maxSize;\n cache.values.length = maxSize;\n }\n}\n\nexport function createUpdateAsyncCache(\n options: MicroMemoize.Options,\n): MicroMemoize.AsyncCacheUpdater {\n const getKeyIndex: MicroMemoize.KeyIndexGetter = createGetKeyIndex(options);\n\n const { onCacheChange, onCacheHit } = options;\n\n const shouldUpdateOnChange = typeof onCacheChange === 'function';\n const shouldUpdateOnHit = typeof onCacheHit === 'function';\n\n /**\n * @function updateAsyncCache\n *\n * @description\n * update the promise method to auto-remove from cache if rejected, and\n * if resolved then fire cache hit / changed\n *\n * @param cache the memoized function's cache\n * @param memoized the memoized function\n */\n return (cache: MicroMemoize.Cache, memoized: MicroMemoize.Memoized): void => {\n const key: any = cache.keys[0];\n\n cache.values[0] = cache.values[0]\n .then((value: any) => {\n shouldUpdateOnHit && onCacheHit(cache, options, memoized);\n shouldUpdateOnChange && onCacheChange(cache, options, memoized);\n\n return value;\n })\n .catch((error: Error) => {\n const keyIndex = getKeyIndex(cache.keys, key);\n\n if (~keyIndex) {\n cache.keys.splice(keyIndex, 1);\n cache.values.splice(keyIndex, 1);\n }\n\n throw error;\n });\n };\n}\n","// utils\nimport {\n createGetKeyIndex,\n createUpdateAsyncCache,\n isSameValueZero,\n mergeOptions,\n orderByLru,\n} from './utils';\n\nconst { slice } = Array.prototype;\n\nfunction createMemoizedFunction(\n fn: Function | MicroMemoize.Memoized,\n options: MicroMemoize.Options = {},\n): MicroMemoize.Memoized {\n // @ts-ignore\n if (fn.isMemoized) {\n return fn;\n }\n\n const {\n isEqual = isSameValueZero,\n isMatchingKey,\n isPromise = false,\n maxSize = 1,\n onCacheAdd,\n onCacheChange,\n onCacheHit,\n transformKey,\n ...extraOptions\n }: MicroMemoize.Options = options;\n\n const normalizedOptions = mergeOptions(extraOptions, {\n isEqual,\n isMatchingKey,\n isPromise,\n maxSize,\n onCacheAdd,\n onCacheChange,\n onCacheHit,\n transformKey,\n });\n\n const getKeyIndex: MicroMemoize.KeyIndexGetter = createGetKeyIndex(\n normalizedOptions,\n );\n const updateAsyncCache: MicroMemoize.AsyncCacheUpdater = createUpdateAsyncCache(\n normalizedOptions,\n );\n\n const keys: MicroMemoize.Keys = [];\n const values: MicroMemoize.Values = [];\n\n const cache: MicroMemoize.Cache = {\n keys,\n get size() {\n return cache.keys.length;\n },\n values,\n };\n\n const canTransformKey = typeof transformKey === 'function';\n\n const shouldCloneArguments = !!(transformKey || isMatchingKey);\n\n const shouldUpdateOnAdd = typeof onCacheAdd === 'function';\n const shouldUpdateOnChange = typeof onCacheChange === 'function';\n const shouldUpdateOnHit = typeof onCacheHit === 'function';\n\n function memoized(): any {\n const normalizedArgs: MicroMemoize.RawKey = shouldCloneArguments\n ? slice.call(arguments, 0)\n : arguments;\n const key: MicroMemoize.RawKey = canTransformKey\n ? transformKey(normalizedArgs)\n : normalizedArgs;\n const keyIndex: number = keys.length ? getKeyIndex(keys, key) : -1;\n\n if (~keyIndex) {\n shouldUpdateOnHit && onCacheHit(cache, normalizedOptions, memoized);\n\n if (keyIndex) {\n orderByLru(cache, keys[keyIndex], values[keyIndex], keyIndex, maxSize);\n\n shouldUpdateOnChange &&\n onCacheChange(cache, normalizedOptions, memoized);\n }\n } else {\n const newValue: any = fn.apply(this, arguments);\n const newKey: MicroMemoize.Key = shouldCloneArguments\n ? key\n : slice.call(normalizedArgs, 0);\n\n orderByLru(cache, newKey, newValue, keys.length, maxSize);\n\n isPromise && updateAsyncCache(cache, memoized);\n\n shouldUpdateOnAdd && onCacheAdd(cache, normalizedOptions, memoized);\n shouldUpdateOnChange && onCacheChange(cache, normalizedOptions, memoized);\n }\n\n return values[0];\n }\n\n Object.defineProperties(memoized, {\n cache: {\n configurable: true,\n value: cache,\n },\n cacheSnapshot: {\n configurable: true,\n get() {\n return {\n keys: slice.call(cache.keys, 0),\n size: cache.size,\n values: slice.call(cache.values, 0),\n };\n },\n },\n isMemoized: {\n configurable: true,\n value: true,\n },\n options: {\n configurable: true,\n value: normalizedOptions,\n },\n });\n\n return memoized;\n}\n\nexport default createMemoizedFunction;\n"],"names":[],"mappings":"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"} |
@@ -1,1 +0,1 @@ | ||
| !function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n(e.memoize={})}(this,function(e){"use strict";var O=Object.prototype.hasOwnProperty,P=function(e){var n=e.length;if(!n)return[];if(1===n)return[e[0]];if(2===n)return[e[0],e[1]];if(3===n)return[e[0],e[1],e[2]];for(var t=new Array(n),r=0;r<n;r++)t[r]=e[r];return t},q=function(e,n){var i,r="function"==typeof n?n:(i=e,function(e,n){if(e.length!==n.length)return!1;for(var t=0,r=e.length;t<r;t++)if(!i(e[t],n[t]))return!1;return!0});return function(e,n){for(var t=0;t<e.length;t++)if(r(e[t],n))return t;return-1}},A=function(e,n){return e===n||e!=e&&n!=n},E=function(e,n,t){},H=function(e,n,t){for(var r=t;r--;)e[r+1]=e[r];e[0]=n};e.default=function(u,e){if(u.isMemoized)return u;var i,o,n=e||{},t=n.isEqual,r=void 0===t?A:t,a=n.isMatchingKey,f=n.isPromise,c=void 0!==f&&f,s=n.maxSize,h=void 0===s?1:s,l=n.onCacheAdd,g=void 0===l?E:l,v=n.onCacheChange,d=void 0===v?E:v,y=n.onCacheHit,p=void 0===y?E:y,m=n.transformKey,C=function(e){for(var n,t=0;t<(arguments.length<=1?0:arguments.length-1);t++)if((n=t+1<1||arguments.length<=t+1?void 0:arguments[t+1])&&"object"==typeof n)for(var r in n)O.call(n,r)&&(e[r]=n[r]);return e}({},function(e,n){if(null==e)return{};var t,r,i={},o=Object.keys(e);for(r=0;r<o.length;r++)t=o[r],0<=n.indexOf(t)||(i[t]=e[t]);return i}(n,["isEqual","isMatchingKey","isPromise","maxSize","onCacheAdd","onCacheChange","onCacheHit","transformKey"]),{isEqual:r,isMatchingKey:a,isPromise:c,maxSize:h,onCacheAdd:g,onCacheChange:d,onCacheHit:p,transformKey:m}),b=q(r,a),k=(o=q((i=C).isEqual,i.isMatchingKey),function(t,n){var r=t.keys[0];t.values[0]=t.values[0].then(function(e){return i.onCacheHit(t,i,n),i.onCacheChange(t,i,n),e}).catch(function(e){var n=o(t.keys,r);throw~n&&(t.keys.splice(n,1),t.values.splice(n,1)),e})}),z=!(!m&&!a),x={keys:[],get size(){return x.keys.length},values:[]},K=x.keys,M=x.values;function j(){var e=arguments,n=z?P(e):e,t=m?m(n):n,r=b(K,t);if(~r)p(x,C,j),r&&(H(K,K[r],r),H(M,M[r],r),d(x,C,j));else{K.length>=h&&(K.pop(),M.pop());var i=z?t:P(n),o=u.apply(this,e);H(K,i,K.length),H(M,o,M.length),c&&k(x,j),g(x,C,j),d(x,C,j)}return M[0]}return Object.defineProperties(j,{cache:{configurable:!0,get:function(){return x}},cacheSnapshot:{configurable:!0,get:function(){return{keys:P(x.keys),size:x.size,values:P(x.values)}}},isMemoized:{configurable:!0,get:function(){return!0}},options:{configurable:!0,get:function(){return C}}}),j},Object.defineProperty(e,"__esModule",{value:!0})}); | ||
| !function(e,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):(e=e||self)["micro-memoize"]=n()}(this,function(){"use strict";function w(e){var o,r=e.maxSize,a="function"==typeof e.isMatchingKey?e.isMatchingKey:(o=e.isEqual,function(e,n){var t=e.length;if(n.length!==t)return!1;if(1===t)return o(e[0],n[0]);for(var i=0;i<t;){if(!o(e[i],n[i]))return!1;i++}return!0});return function(e,n){if(a(e[0],n))return 0;if(1<r)for(var t=r>e.length?e.length:r,i=1;i<t;){if(a(e[i],n))return i;i++}return-1}}function A(e,n){return e===n||e!=e&&n!=n}function E(e,n,t,i,o){for(var r=i;r--;)e.keys[r+1]=e.keys[r],e.values[r+1]=e.values[r];e.keys[0]=n,e.values[0]=t,o<=i&&(e.keys.length=o,e.values.length=o)}var H=Array.prototype.slice;return function(r,e){if(void 0===e&&(e={}),r.isMemoized)return r;var o,a,u,f,c,s,n=e.isEqual,t=void 0===n?A:n,i=e.isMatchingKey,l=e.isPromise,h=void 0!==l&&l,y=e.maxSize,v=void 0===y?1:y,g=e.onCacheAdd,p=e.onCacheChange,d=e.onCacheHit,m=e.transformKey,C=function(e,n){var t={};for(var i in e)t[i]=e[i];for(var i in n)t[i]=n[i];return t}(function(e,n){var t={};for(var i in e)Object.prototype.hasOwnProperty.call(e,i)&&n.indexOf(i)<0&&(t[i]=e[i]);if(null!=e&&"function"==typeof Object.getOwnPropertySymbols){var o=0;for(i=Object.getOwnPropertySymbols(e);o<i.length;o++)n.indexOf(i[o])<0&&(t[i[o]]=e[i[o]])}return t}(e,["isEqual","isMatchingKey","isPromise","maxSize","onCacheAdd","onCacheChange","onCacheHit","transformKey"]),{isEqual:t,isMatchingKey:i,isPromise:h,maxSize:v,onCacheAdd:g,onCacheChange:p,onCacheHit:d,transformKey:m}),b=w(C),k=(a=w(o=C),u=o.onCacheChange,f=o.onCacheHit,c="function"==typeof u,s="function"==typeof f,function(t,n){var i=t.keys[0];t.values[0]=t.values[0].then(function(e){return s&&f(t,o,n),c&&u(t,o,n),e}).catch(function(e){var n=a(t.keys,i);throw~n&&(t.keys.splice(n,1),t.values.splice(n,1)),e})}),z=[],O=[],x={keys:z,get size(){return x.keys.length},values:O},K="function"==typeof m,M=!(!m&&!i),P="function"==typeof g,S="function"==typeof p,j="function"==typeof d;function q(){var e=M?H.call(arguments,0):arguments,n=K?m(e):e,t=z.length?b(z,n):-1;if(~t)j&&d(x,C,q),t&&(E(x,z[t],O[t],t,v),S&&p(x,C,q));else{var i=r.apply(this,arguments),o=M?n:H.call(e,0);E(x,o,i,z.length,v),h&&k(x,q),P&&g(x,C,q),S&&p(x,C,q)}return O[0]}return Object.defineProperties(q,{cache:{configurable:!0,value:x},cacheSnapshot:{configurable:!0,get:function(){return{keys:H.call(x.keys,0),size:x.size,values:H.call(x.values,0)}}},isMemoized:{configurable:!0,value:!0},options:{configurable:!0,value:C}}),q}}); |
+15
-8
@@ -1,14 +0,21 @@ | ||
| const fs = require('fs-extra'); | ||
| const fs = require('fs'); | ||
| const path = require('path'); | ||
| const ES_DIRECTORY = path.join(__dirname, 'es'); | ||
| const MJS_DIRECTORY = path.join(__dirname, 'mjs'); | ||
| const pkg = require('./package.json'); | ||
| fs.readdirSync(ES_DIRECTORY).forEach((file) => { | ||
| const fullPathJsFilename = path.resolve(ES_DIRECTORY, file); | ||
| const fullPathMjsFilename = path.resolve(MJS_DIRECTORY, `${file.slice(0, -3)}.mjs`); | ||
| const SOURCE = path.join(__dirname, pkg.module); | ||
| const DESTINATION = path.join(__dirname, pkg.module.replace('esm.js', 'mjs')); | ||
| fs.copySync(fullPathJsFilename, fullPathMjsFilename); | ||
| const getFileName = filename => { | ||
| const split = filename.split('/'); | ||
| console.log(`es/${file} -> mjs/${file.slice(0, -3)}.mjs`); | ||
| return split[split.length - 1]; | ||
| }; | ||
| fs.copyFile(SOURCE, DESTINATION, error => { | ||
| if (error) { | ||
| throw error; | ||
| } | ||
| console.log(`Copied ${getFileName(SOURCE)} to ${getFileName(DESTINATION)}`); | ||
| }); |
+57
-17
@@ -1,20 +0,60 @@ | ||
| interface Cache { | ||
| keys: Array<any>; | ||
| size: number; | ||
| values: Array<any>; | ||
| } | ||
| type PlainObject = { | ||
| [key: string]: any; | ||
| [index: number]: any; | ||
| }; | ||
| interface Options { | ||
| isEqual?: (firstValue: any, secondValue: any) => boolean; | ||
| isMatchingKey?: (cacheKey: Array<any>, key: Array<any>) => boolean; | ||
| isPromise?: boolean; | ||
| maxSize?: number; | ||
| onCacheAdd?: (cache: Cache, options: Options, memoized: Function) => void; | ||
| onCacheChange?: (cache: Cache, options: Options, memoized: Function) => void; | ||
| onCacheHit?: (cache: Cache, options: Options, memoized: Function) => void; | ||
| transformKey?: (args: any[]) => any; | ||
| declare namespace MicroMemoize { | ||
| export type Key = any[]; | ||
| export type RawKey = Key | IArguments; | ||
| export type Keys = Key[]; | ||
| export type Values = any[]; | ||
| export type Cache = { | ||
| keys: Keys; | ||
| size: number; | ||
| values: Values; | ||
| }; | ||
| export type EqualityComparator = (object1: any, object2: any) => boolean; | ||
| export type MatchingKeyComparator = (key1: Key, key2: RawKey) => boolean; | ||
| export type CacheModifiedHandler = ( | ||
| cache: Cache, | ||
| options: Options, | ||
| memoized: Function, | ||
| ) => void; | ||
| export type KeyTransformer = (args: RawKey) => Key; | ||
| export type KeyIndexGetter = (allKeys: Keys, keyToMatch: RawKey) => number; | ||
| export type AsyncCacheUpdater = (cache: Cache, memoized: Memoized) => void; | ||
| export type Options = { | ||
| isEqual?: EqualityComparator; | ||
| isMatchingKey?: MatchingKeyComparator; | ||
| isPromise?: boolean; | ||
| maxSize?: number; | ||
| onCacheAdd?: CacheModifiedHandler; | ||
| onCacheChange?: CacheModifiedHandler; | ||
| onCacheHit?: CacheModifiedHandler; | ||
| transformKey?: KeyTransformer; | ||
| }; | ||
| export interface Memoized extends Function { | ||
| [key: string]: any; | ||
| cache?: Cache; | ||
| cacheSnapshot?: Cache; | ||
| isMemoized?: boolean; | ||
| options?: Options; | ||
| } | ||
| } | ||
| type Fn = (...args: any[]) => any; | ||
| export default function memoize<T extends Fn>(fn: T, options?: Options): T; | ||
| export default function memoize<T extends Function>( | ||
| fn: T, | ||
| options?: MicroMemoize.Options, | ||
| ): MicroMemoize.Memoized; |
+37
-65
| { | ||
| "author": "tony.quetano@planttheidea.com", | ||
| "ava": { | ||
| "failFast": true, | ||
| "files": [ | ||
| "test/*.js" | ||
| ], | ||
| "require": [ | ||
| "@babel/register" | ||
| ], | ||
| "sources": [ | ||
| "src/*.js" | ||
| ], | ||
| "verbose": true | ||
| }, | ||
| "browser": "dist/micro-memoize.js", | ||
| "browserslist": [ | ||
@@ -29,48 +17,35 @@ "defaults", | ||
| "devDependencies": { | ||
| "@babel/cli": "^7.1.2", | ||
| "@babel/core": "^7.1.2", | ||
| "@babel/plugin-syntax-flow": "^7.0.0", | ||
| "@babel/plugin-transform-flow-strip-types": "^7.0.0", | ||
| "@babel/plugin-transform-runtime": "^7.0.0", | ||
| "@babel/preset-env": "^7.0.0", | ||
| "@babel/preset-flow": "^7.0.0", | ||
| "@babel/preset-react": "^7.0.0", | ||
| "@babel/register": "^7.0.0", | ||
| "@babel/runtime": "^7.1.2", | ||
| "ava": "^1.0.0-rc.1", | ||
| "babel-eslint": "^10.0.1", | ||
| "babel-loader": "^8.0.4", | ||
| "@types/bluebird": "^3.5.25", | ||
| "@types/jest": "^24.0.0", | ||
| "@types/react": "^16.7.20", | ||
| "benchee": "^1.0.0", | ||
| "benchmark": "^2.1.4", | ||
| "case-sensitive-paths-webpack-plugin": "^2.1.2", | ||
| "bluebird": "^3.5.2", | ||
| "cli-table2": "^0.2.0", | ||
| "eslint": "^5.7.0", | ||
| "eslint-config-rapid7": "^3.0.4", | ||
| "eslint-friendly-formatter": "^4.0.1", | ||
| "eslint-loader": "^2.1.1", | ||
| "fast-equals": "^1.6.1", | ||
| "fast-memoize": "^2.5.1", | ||
| "flow-babel-webpack-plugin": "^1.1.1", | ||
| "fs-extra": "^7.0.0", | ||
| "hash-it": "^4.0.3", | ||
| "html-webpack-plugin": "^3.2.0", | ||
| "in-publish": "^2.0.0", | ||
| "lodash": "^4.17.10", | ||
| "jest": "^24.1.0", | ||
| "lodash": "^4.17.11", | ||
| "lru-memoize": "^1.0.2", | ||
| "mem": "^4.0.0", | ||
| "memoizee": "^0.4.13", | ||
| "memoizee": "^0.4.14", | ||
| "memoizerific": "^1.11.3", | ||
| "nyc": "^13.1.0", | ||
| "optimize-js-plugin": "^0.0.4", | ||
| "mini-bench": "^1.0.0", | ||
| "ora": "^3.0.0", | ||
| "prop-types": "^15.6.2", | ||
| "ramda": "^0.25.0", | ||
| "react": "^16.4.2", | ||
| "react-dev-utils": "^6.0.5", | ||
| "react-dom": "^16.4.2", | ||
| "react-hot-loader": "^4.3.11", | ||
| "rimraf": "^2.6.2", | ||
| "rollup": "^0.66.6", | ||
| "rollup-plugin-babel": "^4.0.1", | ||
| "performance-now": "^2.1.0", | ||
| "ramda": "^0.26.1", | ||
| "react": "^16.7.0", | ||
| "rollup": "^1.1.2", | ||
| "rollup-plugin-typescript": "^1.0.0", | ||
| "rollup-plugin-uglify": "^6.0.0", | ||
| "sinon": "^7.0.0", | ||
| "rsvp": "^4.8.4", | ||
| "simple-statistics": "^7.0.0", | ||
| "ts-jest": "^23.10.4", | ||
| "ts-loader": "^5.2.2", | ||
| "tslint": "^5.11.0", | ||
| "tslint-config-airbnb": "^5.11.0", | ||
| "tslint-loader": "^3.5.4", | ||
| "typescript": "^3.1.3", | ||
| "underscore": "^1.9.1", | ||
@@ -100,4 +75,4 @@ "webpack": "^4.20.2", | ||
| "license": "MIT", | ||
| "main": "lib/index.js", | ||
| "module": "es/index.js", | ||
| "main": "dist/micro-memoize.cjs.js", | ||
| "module": "dist/micro-memoize.esm.js", | ||
| "name": "micro-memoize", | ||
@@ -109,23 +84,20 @@ "repository": { | ||
| "scripts": { | ||
| "benchmark": "npm run transpile:lib -- --no-comments && node benchmark/index.js", | ||
| "benchmark:trace": "npm run transpile:lib -- --no-comments && node --trace-deopt --trace-opt benchmark/trace-test.js", | ||
| "benchmark:alternative": "npm run transpile:lib -- --no-comments && ALTERNATIVE=true node benchmark/index.js", | ||
| "benchmark": "npm run dist && NODE_ENV=production node ./benchmarks/index.js", | ||
| "build": "NODE_ENV=production rollup -c", | ||
| "clean": "rimraf lib && rimraf es && rimraf mjs && rimraf dist", | ||
| "copy:mjs": "node ./es-to-mjs.js", | ||
| "dev": "NODE_ENV=development webpack-dev-server --progress --colors --config=webpack/webpack.config.js", | ||
| "flow": "flow check src", | ||
| "lint": "eslint --max-warnings 0 src", | ||
| "build:mjs": "node ./es-to-mjs.js", | ||
| "clean": "rimraf dist", | ||
| "dev": "NODE_ENV=development webpack-dev-server --colors --progress --config=webpack/webpack.config.js", | ||
| "dist": "npm run clean && npm run build && npm run build:mjs", | ||
| "lint": "NODE_ENV=test tslint 'src/*.ts'", | ||
| "lint:fix": "npm run lint -- --fix", | ||
| "prepublish": "if in-publish; then npm run prepublish:compile; fi", | ||
| "prepublish:compile": "npm run lint && npm run flow && npm run test:coverage && npm run clean && npm run transpile:lib && npm run transpile:es && npm run copy:mjs && npm run build", | ||
| "prepublish:compile": "npm run lint && npm run test:coverage && npm run dist", | ||
| "start": "npm run dev", | ||
| "test": "NODE_PATH=. NODE_ENV=test ava", | ||
| "test:coverage": "nyc --cache npm test", | ||
| "test:watch": "npm run test -- --watch", | ||
| "transpile:es": "BABEL_ENV=es babel src --out-dir es", | ||
| "transpile:lib": "BABEL_ENV=lib babel src --out-dir lib" | ||
| "test": "NODE_PATH=. jest", | ||
| "test:coverage": "npm run test -- --coverage", | ||
| "test:watch": "npm run test -- --watch" | ||
| }, | ||
| "sideEffects": false, | ||
| "types": "./index.d.ts", | ||
| "version": "2.1.2" | ||
| "version": "3.0.0-beta.0" | ||
| } |
+87
-87
@@ -35,3 +35,3 @@ # micro-memoize | ||
| As the author of [`moize`](https://github.com/planttheidea/moize), I created a consistently fast memoization library, but `moize` has a lot of features to satisfy a large number of edge cases. `micro-memoize` is a simpler approach, focusing on the core feature set with a much smaller footprint (~1.1kB minified+gzipped). Stripping out these edge cases also allows `micro-memoize` to be faster across the board than `moize`. | ||
| As the author of [`moize`](https://github.com/planttheidea/moize), I created a consistently fast memoization library, but `moize` has a lot of features to satisfy a large number of edge cases. `micro-memoize` is a simpler approach, focusing on the core feature set with a much smaller footprint (~1.2kB minified+gzipped). Stripping out these edge cases also allows `micro-memoize` to be faster across the board than `moize`. | ||
@@ -43,3 +43,3 @@ ## Importing | ||
| ```javascript | ||
| import memoize from "micro-memoize"; | ||
| import memoize from 'micro-memoize'; | ||
| ``` | ||
@@ -50,3 +50,3 @@ | ||
| ```javascript | ||
| import memoize from "micro-memoize/mjs"; | ||
| import memoize from 'micro-memoize/mjs'; | ||
| ``` | ||
@@ -57,3 +57,3 @@ | ||
| ```javascript | ||
| const memoize = require("micro-memoize").default; | ||
| const memoize = require('micro-memoize').default; | ||
| ``` | ||
@@ -65,6 +65,6 @@ | ||
| // ES2015+ | ||
| import memoize from "micro-memoize"; | ||
| import memoize from 'micro-memoize'; | ||
| // CommonJS | ||
| const memoize = require("micro-memoize").default; | ||
| const memoize = require('micro-memoize').default; | ||
@@ -80,4 +80,4 @@ // old-school | ||
| console.log(memoized("one", "two")); // {one: 'one', two: 'two'} | ||
| console.log(memoized("one", "two")); // pulled from cache, {one: 'one', two: 'two'} | ||
| console.log(memoized('one', 'two')); // {one: 'one', two: 'two'} | ||
| console.log(memoized('one', 'two')); // pulled from cache, {one: 'one', two: 'two'} | ||
| ``` | ||
@@ -99,3 +99,3 @@ | ||
| ```javascript | ||
| import { deepEqual } from "fast-equals"; | ||
| import { deepEqual } from 'fast-equals'; | ||
@@ -105,3 +105,3 @@ const deepObject = object => { | ||
| foo: object.foo, | ||
| bar: object.bar | ||
| bar: object.bar, | ||
| }; | ||
@@ -115,11 +115,11 @@ }; | ||
| foo: { | ||
| deep: "foo" | ||
| deep: 'foo', | ||
| }, | ||
| bar: { | ||
| deep: "bar" | ||
| deep: 'bar', | ||
| }, | ||
| baz: { | ||
| deep: "baz" | ||
| } | ||
| }) | ||
| deep: 'baz', | ||
| }, | ||
| }), | ||
| ); // {foo: {deep: 'foo'}, bar: {deep: 'bar'}} | ||
@@ -130,11 +130,11 @@ | ||
| foo: { | ||
| deep: "foo" | ||
| deep: 'foo', | ||
| }, | ||
| bar: { | ||
| deep: "bar" | ||
| deep: 'bar', | ||
| }, | ||
| baz: { | ||
| deep: "baz" | ||
| } | ||
| }) | ||
| deep: 'baz', | ||
| }, | ||
| }), | ||
| ); // pulled from cache | ||
@@ -158,3 +158,3 @@ ``` | ||
| ```javascript | ||
| import { deepEqual } from "fast-equals"; | ||
| import { deepEqual } from 'fast-equals'; | ||
@@ -164,3 +164,3 @@ const deepObject = object => { | ||
| foo: object.foo, | ||
| bar: object.bar | ||
| bar: object.bar, | ||
| }; | ||
@@ -172,7 +172,7 @@ }; | ||
| return ( | ||
| object1.hasOwnProperty("foo") && | ||
| object2.hasOwnProperty("foo") && | ||
| object1.hasOwnProperty('foo') && | ||
| object2.hasOwnProperty('foo') && | ||
| object1.bar === object2.bar | ||
| ); | ||
| } | ||
| }, | ||
| }); | ||
@@ -182,6 +182,6 @@ | ||
| memoizedShape({ | ||
| foo: "foo", | ||
| bar: "bar", | ||
| baz: "baz" | ||
| }) | ||
| foo: 'foo', | ||
| bar: 'bar', | ||
| baz: 'baz', | ||
| }), | ||
| ); // {foo: {deep: 'foo'}, bar: {deep: 'bar'}} | ||
@@ -191,6 +191,6 @@ | ||
| memoizedShape({ | ||
| foo: "not foo", | ||
| bar: "bar", | ||
| baz: "baz" | ||
| }) | ||
| foo: 'not foo', | ||
| bar: 'bar', | ||
| baz: 'baz', | ||
| }), | ||
| ); // pulled from cache | ||
@@ -219,3 +219,3 @@ ``` | ||
| memoized("one", "two"); | ||
| memoized('one', 'two'); | ||
@@ -246,11 +246,11 @@ console.log(memoized.cacheSnapshot.keys); // [['one', 'two']] | ||
| console.log(memoized("one", "two")); // ['one', 'two'] | ||
| console.log(memoized("two", "three")); // ['two', 'three'] | ||
| console.log(memoized("three", "four")); // ['three', 'four'] | ||
| console.log(memoized('one', 'two')); // ['one', 'two'] | ||
| console.log(memoized('two', 'three')); // ['two', 'three'] | ||
| console.log(memoized('three', 'four')); // ['three', 'four'] | ||
| console.log(memoized("one", "two")); // pulled from cache | ||
| console.log(memoized("two", "three")); // pulled from cache | ||
| console.log(memoized("three", "four")); // pulled from cache | ||
| console.log(memoized('one', 'two')); // pulled from cache | ||
| console.log(memoized('two', 'three')); // pulled from cache | ||
| console.log(memoized('three', 'four')); // pulled from cache | ||
| console.log(memoized("four", "five")); // ['four', 'five'], drops ['one', 'two'] from cache | ||
| console.log(memoized('four', 'five')); // ['four', 'five'], drops ['one', 'two'] from cache | ||
| ``` | ||
@@ -273,18 +273,18 @@ | ||
| onCacheAdd(cache, options) { | ||
| console.log("cache has been added to: ", cache); | ||
| console.log("memoized method has the following options applied: ", options); | ||
| } | ||
| console.log('cache has been added to: ', cache); | ||
| console.log('memoized method has the following options applied: ', options); | ||
| }, | ||
| }); | ||
| memoized("foo", "bar"); // cache has been added to | ||
| memoized("foo", "bar"); | ||
| memoized("foo", "bar"); | ||
| memoized('foo', 'bar'); // cache has been added to | ||
| memoized('foo', 'bar'); | ||
| memoized('foo', 'bar'); | ||
| memoized("bar", "foo"); // cache has been added to | ||
| memoized("bar", "foo"); | ||
| memoized("bar", "foo"); | ||
| memoized('bar', 'foo'); // cache has been added to | ||
| memoized('bar', 'foo'); | ||
| memoized('bar', 'foo'); | ||
| memoized("foo", "bar"); | ||
| memoized("foo", "bar"); | ||
| memoized("foo", "bar"); | ||
| memoized('foo', 'bar'); | ||
| memoized('foo', 'bar'); | ||
| memoized('foo', 'bar'); | ||
| ``` | ||
@@ -307,18 +307,18 @@ | ||
| onCacheChange(cache, options) { | ||
| console.log("cache has changed: ", cache); | ||
| console.log("memoized method has the following options applied: ", options); | ||
| } | ||
| console.log('cache has changed: ', cache); | ||
| console.log('memoized method has the following options applied: ', options); | ||
| }, | ||
| }); | ||
| memoized("foo", "bar"); // cache has changed | ||
| memoized("foo", "bar"); | ||
| memoized("foo", "bar"); | ||
| memoized('foo', 'bar'); // cache has changed | ||
| memoized('foo', 'bar'); | ||
| memoized('foo', 'bar'); | ||
| memoized("bar", "foo"); // cache has changed | ||
| memoized("bar", "foo"); | ||
| memoized("bar", "foo"); | ||
| memoized('bar', 'foo'); // cache has changed | ||
| memoized('bar', 'foo'); | ||
| memoized('bar', 'foo'); | ||
| memoized("foo", "bar"); // cache has changed | ||
| memoized("foo", "bar"); | ||
| memoized("foo", "bar"); | ||
| memoized('foo', 'bar'); // cache has changed | ||
| memoized('foo', 'bar'); | ||
| memoized('foo', 'bar'); | ||
| ``` | ||
@@ -342,18 +342,18 @@ | ||
| onCacheHit(cache, options) { | ||
| console.log("cache was hit: ", cache); | ||
| console.log("memoized method has the following options applied: ", options); | ||
| } | ||
| console.log('cache was hit: ', cache); | ||
| console.log('memoized method has the following options applied: ', options); | ||
| }, | ||
| }); | ||
| memoized("foo", "bar"); | ||
| memoized("foo", "bar"); // cache was hit | ||
| memoized("foo", "bar"); // cache was hit | ||
| memoized('foo', 'bar'); | ||
| memoized('foo', 'bar'); // cache was hit | ||
| memoized('foo', 'bar'); // cache was hit | ||
| memoized("bar", "foo"); | ||
| memoized("bar", "foo"); // cache was hit | ||
| memoized("bar", "foo"); // cache was hit | ||
| memoized('bar', 'foo'); | ||
| memoized('bar', 'foo'); // cache was hit | ||
| memoized('bar', 'foo'); // cache was hit | ||
| memoized("foo", "bar"); // cache was hit | ||
| memoized("foo", "bar"); // cache was hit | ||
| memoized("foo", "bar"); // cache was hit | ||
| memoized('foo', 'bar'); // cache was hit | ||
| memoized('foo', 'bar'); // cache was hit | ||
| memoized('foo', 'bar'); // cache was hit | ||
| ``` | ||
@@ -375,7 +375,7 @@ | ||
| const memoized = memoize(ignoreFunctionArgs, { | ||
| transformKey: JSON.stringify | ||
| transformKey: JSON.stringify, | ||
| }); | ||
| console.log(memoized("one", () => {})); // ['one', () => {}] | ||
| console.log(memoized("one", () => {})); // pulled from cache, ['one', () => {}] | ||
| console.log(memoized('one', () => {})); // ['one', () => {}] | ||
| console.log(memoized('one', () => {})); // pulled from cache, ['one', () => {}] | ||
| ``` | ||
@@ -396,9 +396,9 @@ | ||
| return { | ||
| args: JSON.stringify(args) | ||
| args: JSON.stringify(args), | ||
| }; | ||
| } | ||
| }, | ||
| }); | ||
| console.log(memoized("one", () => {})); // ['one', () => {}] | ||
| console.log(memoized("one", () => {})); // pulled from cache, ['one', () => {}] | ||
| console.log(memoized('one', () => {})); // ['one', () => {}] | ||
| console.log(memoized('one', () => {})); // pulled from cache, ['one', () => {}] | ||
| ``` | ||
@@ -430,6 +430,6 @@ | ||
| memoized.cache.keys.push(["one", "two"]); | ||
| memoized.cache.values.push("cached"); | ||
| memoized.cache.keys.push(['one', 'two']); | ||
| memoized.cache.values.push('cached'); | ||
| console.log(memoized("one", "two")); // 'cached' | ||
| console.log(memoized('one', 'two')); // 'cached' | ||
| ``` | ||
@@ -436,0 +436,0 @@ |
+41
-33
@@ -1,35 +0,43 @@ | ||
| import babel from 'rollup-plugin-babel'; | ||
| import {uglify} from 'rollup-plugin-uglify'; | ||
| import typescript from 'rollup-plugin-typescript'; | ||
| import { uglify } from 'rollup-plugin-uglify'; | ||
| export default [ | ||
| { | ||
| input: 'src/index.js', | ||
| output: { | ||
| exports: 'named', | ||
| file: 'dist/micro-memoize.js', | ||
| format: 'umd', | ||
| name: 'memoize', | ||
| sourcemap: true, | ||
| }, | ||
| plugins: [ | ||
| babel({ | ||
| exclude: 'node_modules/**', | ||
| }), | ||
| ], | ||
| import pkg from './package.json'; | ||
| const UMD_CONFIG = { | ||
| input: 'src/index.ts', | ||
| output: { | ||
| exports: 'default', | ||
| file: pkg.browser, | ||
| format: 'umd', | ||
| name: pkg.name, | ||
| sourcemap: true, | ||
| }, | ||
| { | ||
| input: 'src/index.js', | ||
| output: { | ||
| exports: 'named', | ||
| file: 'dist/micro-memoize.min.js', | ||
| format: 'umd', | ||
| name: 'memoize', | ||
| }, | ||
| plugins: [ | ||
| babel({ | ||
| exclude: 'node_modules/**', | ||
| }), | ||
| uglify(), | ||
| ], | ||
| }, | ||
| ]; | ||
| plugins: [ | ||
| typescript({ | ||
| typescript: require('typescript'), | ||
| }), | ||
| ], | ||
| }; | ||
| const FORMATTED_CONFIG = Object.assign({}, UMD_CONFIG, { | ||
| output: [ | ||
| Object.assign({}, UMD_CONFIG.output, { | ||
| file: pkg.main, | ||
| format: 'cjs', | ||
| }), | ||
| Object.assign({}, UMD_CONFIG.output, { | ||
| file: pkg.module, | ||
| format: 'es', | ||
| }), | ||
| ], | ||
| }); | ||
| const MINIFIED_CONFIG = Object.assign({}, UMD_CONFIG, { | ||
| output: Object.assign({}, UMD_CONFIG.output, { | ||
| file: pkg.browser.replace('.js', '.min.js'), | ||
| sourcemap: false, | ||
| }), | ||
| plugins: UMD_CONFIG.plugins.concat([uglify()]), | ||
| }); | ||
| export default [UMD_CONFIG, FORMATTED_CONFIG, MINIFIED_CONFIG]; |
Sorry, the diff of this file is not supported yet
| /* | ||
| * memoize.js | ||
| * by @philogb and @addyosmani | ||
| * with further optimizations by @mathias | ||
| * and @DmitryBaranovsk | ||
| * perf tests: http://bit.ly/q3zpG3 | ||
| * Released under an MIT license. | ||
| */ | ||
| module.exports = function memoize(fn) { | ||
| return function(...args) { | ||
| let index = args.length, | ||
| hash = '', | ||
| currentArg = null; | ||
| currentArg = null; | ||
| while (index--) { | ||
| currentArg = args[index]; | ||
| hash += currentArg === Object(currentArg) ? JSON.stringify(currentArg) : currentArg; | ||
| fn.memoize || (fn.memoize = {}); | ||
| } | ||
| return hash in fn.memoize ? fn.memoize[hash] : (fn.memoize[hash] = fn.apply(this, args)); | ||
| }; | ||
| }; |
| "Name","Overall (average)","Single (average)","Multiple (average)","single primitive","single array","single object","multiple primitive","multiple array","multiple object" | ||
| "micro-memoize","43,702,165","51,789,026","35,615,304","57,637,984","48,611,399","49,117,695","40,849,760","29,961,958","36,034,196" | ||
| "fast-memoize","39,957,140","78,949,201","965,078","233,789,537","1,585,949","1,472,119","1,158,875","946,388","789,972" | ||
| "lodash","14,320,798","27,508,254","1,133,342","32,669,251","24,892,558","24,962,953","1,402,261","1,128,886","868,879" | ||
| "memoizee","9,861,157","11,784,109","7,938,205","16,177,336","9,568,376","9,606,616","9,482,240","7,186,371","7,146,006" | ||
| "ramda","8,678,762","16,102,353","1,255,172","42,919,616","2,907,167","2,480,276","1,550,152","1,222,321","993,044" | ||
| "lru-memoize","7,034,405","7,537,900","6,530,910","8,516,137","7,057,588","7,039,977","6,584,528","6,474,194","6,534,009" | ||
| "mem","6,718,548","11,530,426","1,906,669","30,316,899","2,240,383","2,033,998","2,705,018","1,849,057","1,165,934" | ||
| "underscore","5,014,181","8,820,887","1,207,475","21,489,781","2,673,530","2,299,352","1,479,025","1,183,156","960,246" | ||
| "addy-osmani","4,968,346","7,410,673","2,526,020","17,391,341","2,599,855","2,240,823","5,104,651","1,423,365","1,050,046" | ||
| "memoizerific","4,665,606","5,187,389","4,143,824","5,466,050","5,057,754","5,038,363","4,013,486","4,198,578","4,219,410" |
| 'use strict'; | ||
| const _ = require('lodash'); | ||
| const fs = require('fs'); | ||
| const React = require('react'); | ||
| const Benchmark = require('benchmark'); | ||
| const Table = require('cli-table2'); | ||
| const ora = require('ora'); | ||
| const addyOsmani = require('./addy-osmani'); | ||
| const fastMemoize = require('fast-memoize'); | ||
| const lodash = _.memoize; | ||
| const lruMemoize = require('lru-memoize').default; | ||
| const mem = require('mem'); | ||
| const memoizee = require('memoizee'); | ||
| const memoizerific = require('memoizerific'); | ||
| const memoize = require('../lib').default; | ||
| const ramda = require('ramda').memoizeWith; | ||
| const underscore = require('underscore').memoize; | ||
| const deepEqualFastEquals = require('fast-equals').deepEqual; | ||
| const deepEqualLodash = _.isEqual; | ||
| const resolveArguments = function() { | ||
| return arguments.length > 1 | ||
| ? JSON.stringify(arguments) | ||
| : typeof arguments[0] === 'object' ? JSON.stringify(arguments[0]) : arguments[0]; | ||
| }; | ||
| const showResults = (benchmarkResults) => { | ||
| const table = new Table({ | ||
| head: ['Name', 'Ops / sec', 'Relative margin of error', 'Sample size'] | ||
| }); | ||
| benchmarkResults.forEach((result) => { | ||
| const name = result.target.name; | ||
| const opsPerSecond = result.target.hz.toLocaleString('en-US', { | ||
| maximumFractionDigits: 0 | ||
| }); | ||
| const relativeMarginOferror = `± ${result.target.stats.rme.toFixed(2)}%`; | ||
| const sampleSize = result.target.stats.sample.length; | ||
| table.push([name, opsPerSecond, relativeMarginOferror, sampleSize]); | ||
| }); | ||
| console.log(table.toString()); // eslint-disable-line no-console | ||
| }; | ||
| const sortDescResults = (benchmarkResults) => { | ||
| return benchmarkResults.sort((a, b) => { | ||
| return a.target.hz < b.target.hz ? 1 : -1; | ||
| }); | ||
| }; | ||
| const spinner = ora('Running benchmark'); | ||
| let cliResults = [], | ||
| csvResults = {}; | ||
| const onCycle = (event) => { | ||
| cliResults.push(event); | ||
| const {currentTarget, target} = event; | ||
| if (!csvResults[currentTarget.name]) { | ||
| csvResults[currentTarget.name] = {}; | ||
| } | ||
| csvResults[currentTarget.name][target.name] = ~~event.target.hz; | ||
| ora(target.name).succeed(); | ||
| }; | ||
| const onComplete = () => { | ||
| spinner.stop(); | ||
| const orderedBenchmarkResults = sortDescResults(cliResults); | ||
| showResults(orderedBenchmarkResults); | ||
| }; | ||
| const fibonacciSinglePrimitive = (number) => { | ||
| return number < 2 ? number : fibonacciSinglePrimitive(number - 1) + fibonacciSinglePrimitive(number - 2); | ||
| }; | ||
| const fibonacciSingleArray = (array) => { | ||
| return array[0] < 2 ? array[0] : fibonacciSingleArray([array[0] - 1]) + fibonacciSingleArray([array[0] - 2]); | ||
| }; | ||
| const fibonacciSingleObject = (object) => { | ||
| return object.number < 2 | ||
| ? object.number | ||
| : fibonacciSingleObject({number: object.number - 1}) + fibonacciSingleObject({number: object.number - 2}); | ||
| }; | ||
| const fibonacciMultiplePrimitive = (number, isComplete) => { | ||
| if (isComplete) { | ||
| return number; | ||
| } | ||
| const firstValue = number - 1; | ||
| const secondValue = number - 2; | ||
| return ( | ||
| fibonacciMultiplePrimitive(firstValue, firstValue < 2) + fibonacciMultiplePrimitive(secondValue, secondValue < 2) | ||
| ); | ||
| }; | ||
| const fibonacciMultipleArray = (array, check) => { | ||
| if (check[0]) { | ||
| return array[0]; | ||
| } | ||
| const firstValue = array[0] - 1; | ||
| const secondValue = array[0] - 2; | ||
| return ( | ||
| fibonacciMultipleArray([firstValue], [firstValue < 2]) + fibonacciMultipleArray([secondValue], [secondValue < 2]) | ||
| ); | ||
| }; | ||
| const fibonacciMultipleObject = (object, check) => { | ||
| if (check.isComplete) { | ||
| return object.number; | ||
| } | ||
| const firstValue = object.number - 1; | ||
| const secondValue = object.number - 2; | ||
| return ( | ||
| fibonacciMultipleObject({number: firstValue}, {isComplete: firstValue < 2}) + | ||
| fibonacciMultipleObject({number: secondValue}, {isComplete: secondValue < 2}) | ||
| ); | ||
| }; | ||
| const fibonacciMultipleDeepEqual = ({number}) => { | ||
| return number < 2 | ||
| ? number | ||
| : fibonacciMultipleDeepEqual({number: number - 1}) + fibonacciMultipleDeepEqual({number: number - 2}); | ||
| }; | ||
| const getSuiteOptions = (name, resolve) => { | ||
| return { | ||
| name, | ||
| onComplete() { | ||
| onComplete(); | ||
| resolve(); | ||
| }, | ||
| onCycle, | ||
| onStart() { | ||
| console.log(''); // eslint-disable-line no-console | ||
| console.log(`Starting cycles for ${name}...`); // eslint-disable-line no-console | ||
| cliResults = []; | ||
| spinner.start(); | ||
| }, | ||
| queued: true | ||
| }; | ||
| }; | ||
| const runSinglePrimitiveSuite = () => { | ||
| // const fibonacciSuite = new Benchmark.Suite('Single parameter (primitive)'); | ||
| const fibonacciNumber = 35; | ||
| const mAddyOsmani = addyOsmani(fibonacciSinglePrimitive); | ||
| const mFastMemoize = fastMemoize(fibonacciSinglePrimitive); | ||
| const mLodash = lodash(fibonacciSinglePrimitive); | ||
| const mLruMemoize = lruMemoize(Infinity)(fibonacciSinglePrimitive); | ||
| const mMem = mem(fibonacciSinglePrimitive); | ||
| const mMemoizee = memoizee(fibonacciSinglePrimitive); | ||
| const mMemoizerific = memoizerific(Infinity)(fibonacciSinglePrimitive); | ||
| const mMicroMemoize = memoize(fibonacciSinglePrimitive); | ||
| const mRamda = ramda(resolveArguments, fibonacciSinglePrimitive); | ||
| const mUnderscore = underscore(fibonacciSinglePrimitive); | ||
| return new Promise((resolve) => { | ||
| new Benchmark.Suite(getSuiteOptions('single primitive parameter', resolve)) | ||
| .add('addy-osmani', () => { | ||
| mAddyOsmani(fibonacciNumber); | ||
| }) | ||
| .add('fast-memoize', () => { | ||
| mFastMemoize(fibonacciNumber); | ||
| }) | ||
| .add('lodash', () => { | ||
| mLodash(fibonacciNumber); | ||
| }) | ||
| .add('lru-memoize', () => { | ||
| mLruMemoize(fibonacciNumber); | ||
| }) | ||
| .add('mem', () => { | ||
| mMem(fibonacciNumber); | ||
| }) | ||
| .add('memoizee', () => { | ||
| mMemoizee(fibonacciNumber); | ||
| }) | ||
| .add('memoizerific', () => { | ||
| mMemoizerific(fibonacciNumber); | ||
| }) | ||
| .add('micro-memoize', () => { | ||
| mMicroMemoize(fibonacciNumber); | ||
| }) | ||
| .add('ramda', () => { | ||
| mRamda(fibonacciNumber); | ||
| }) | ||
| .add('underscore', () => { | ||
| mUnderscore(fibonacciNumber); | ||
| }) | ||
| .run({async: true}); | ||
| }); | ||
| }; | ||
| const runSingleArraySuite = () => { | ||
| const fibonacciNumber = [35]; | ||
| const mAddyOsmani = addyOsmani(fibonacciSingleArray); | ||
| const mFastMemoize = fastMemoize(fibonacciSingleArray); | ||
| const mLodash = lodash(fibonacciSingleArray); | ||
| const mLruMemoize = lruMemoize(Infinity)(fibonacciSingleArray); | ||
| const mMem = mem(fibonacciSingleArray); | ||
| const mMemoizee = memoizee(fibonacciSingleArray); | ||
| const mMemoizerific = memoizerific(Infinity)(fibonacciSingleArray); | ||
| const mMicroMemoize = memoize(fibonacciSingleArray); | ||
| const mRamda = ramda(resolveArguments, fibonacciSingleArray); | ||
| const mUnderscore = underscore(fibonacciSingleArray, resolveArguments); | ||
| return new Promise((resolve) => { | ||
| new Benchmark.Suite(getSuiteOptions('single array parameter', resolve)) | ||
| .add('addy-osmani', () => { | ||
| mAddyOsmani(fibonacciNumber); | ||
| }) | ||
| .add('fast-memoize', () => { | ||
| mFastMemoize(fibonacciNumber); | ||
| }) | ||
| .add('lodash', () => { | ||
| mLodash(fibonacciNumber); | ||
| }) | ||
| .add('lru-memoize', () => { | ||
| mLruMemoize(fibonacciNumber); | ||
| }) | ||
| .add('mem', () => { | ||
| mMem(fibonacciNumber); | ||
| }) | ||
| .add('memoizee', () => { | ||
| mMemoizee(fibonacciNumber); | ||
| }) | ||
| .add('memoizerific', () => { | ||
| mMemoizerific(fibonacciNumber); | ||
| }) | ||
| .add('micro-memoize', () => { | ||
| mMicroMemoize(fibonacciNumber); | ||
| }) | ||
| .add('ramda', () => { | ||
| mRamda(fibonacciNumber); | ||
| }) | ||
| .add('underscore', () => { | ||
| mUnderscore(fibonacciNumber); | ||
| }) | ||
| .run({ | ||
| async: true, | ||
| queued: true | ||
| }); | ||
| }); | ||
| }; | ||
| const runSingleObjectSuite = () => { | ||
| const fibonacciNumber = { | ||
| number: 35 | ||
| }; | ||
| const mAddyOsmani = addyOsmani(fibonacciSingleObject); | ||
| const mFastMemoize = fastMemoize(fibonacciSingleObject); | ||
| const mLodash = lodash(fibonacciSingleObject); | ||
| const mLruMemoize = lruMemoize(Infinity)(fibonacciSingleObject); | ||
| const mMem = mem(fibonacciSingleObject); | ||
| const mMemoizee = memoizee(fibonacciSingleObject); | ||
| const mMemoizerific = memoizerific(Infinity)(fibonacciSingleObject); | ||
| const mMicroMemoize = memoize(fibonacciSingleObject); | ||
| const mRamda = ramda(resolveArguments, fibonacciSingleObject); | ||
| const mUnderscore = underscore(fibonacciSingleObject, resolveArguments); | ||
| return new Promise((resolve) => { | ||
| new Benchmark.Suite(getSuiteOptions('single object parameter', resolve)) | ||
| .add('addy-osmani', () => { | ||
| mAddyOsmani(fibonacciNumber); | ||
| }) | ||
| .add('fast-memoize', () => { | ||
| mFastMemoize(fibonacciNumber); | ||
| }) | ||
| .add('lodash', () => { | ||
| mLodash(fibonacciNumber); | ||
| }) | ||
| .add('lru-memoize', () => { | ||
| mLruMemoize(fibonacciNumber); | ||
| }) | ||
| .add('mem', () => { | ||
| mMem(fibonacciNumber); | ||
| }) | ||
| .add('memoizee', () => { | ||
| mMemoizee(fibonacciNumber); | ||
| }) | ||
| .add('memoizerific', () => { | ||
| mMemoizerific(fibonacciNumber); | ||
| }) | ||
| .add('micro-memoize', () => { | ||
| mMicroMemoize(fibonacciNumber); | ||
| }) | ||
| .add('ramda', () => { | ||
| mRamda(fibonacciNumber); | ||
| }) | ||
| .add('underscore', () => { | ||
| mUnderscore(fibonacciNumber); | ||
| }) | ||
| .run({ | ||
| async: true, | ||
| queued: true | ||
| }); | ||
| }); | ||
| }; | ||
| const runMultiplePrimitiveSuite = () => { | ||
| const fibonacciNumber = 35; | ||
| const isComplete = false; | ||
| const mAddyOsmani = addyOsmani(fibonacciMultiplePrimitive); | ||
| const mFastMemoize = fastMemoize(fibonacciMultiplePrimitive); | ||
| const mLodash = lodash(fibonacciMultiplePrimitive, resolveArguments); | ||
| const mLruMemoize = lruMemoize(Infinity)(fibonacciMultiplePrimitive); | ||
| const mMem = mem(fibonacciMultiplePrimitive); | ||
| const mMemoizee = memoizee(fibonacciMultiplePrimitive); | ||
| const mMemoizerific = memoizerific(Infinity)(fibonacciMultiplePrimitive); | ||
| const mMicroMemoize = memoize(fibonacciMultiplePrimitive); | ||
| const mRamda = ramda(resolveArguments, fibonacciMultiplePrimitive); | ||
| const mUnderscore = underscore(fibonacciMultiplePrimitive, resolveArguments); | ||
| return new Promise((resolve) => { | ||
| new Benchmark.Suite(getSuiteOptions('multiple primitive parameters', resolve)) | ||
| .add('addy-osmani', () => { | ||
| mAddyOsmani(fibonacciNumber, isComplete); | ||
| }) | ||
| .add('fast-memoize', () => { | ||
| mFastMemoize(fibonacciNumber, isComplete); | ||
| }) | ||
| .add('lodash', () => { | ||
| mLodash(fibonacciNumber, isComplete); | ||
| }) | ||
| .add('lru-memoize', () => { | ||
| mLruMemoize(fibonacciNumber, isComplete); | ||
| }) | ||
| .add('mem', () => { | ||
| mMem(fibonacciNumber, isComplete); | ||
| }) | ||
| .add('memoizee', () => { | ||
| mMemoizee(fibonacciNumber, isComplete); | ||
| }) | ||
| .add('memoizerific', () => { | ||
| mMemoizerific(fibonacciNumber, isComplete); | ||
| }) | ||
| .add('micro-memoize', () => { | ||
| mMicroMemoize(fibonacciNumber, isComplete); | ||
| }) | ||
| .add('ramda', () => { | ||
| mRamda(fibonacciNumber, isComplete); | ||
| }) | ||
| .add('underscore', () => { | ||
| mUnderscore(fibonacciNumber, isComplete); | ||
| }) | ||
| .run({ | ||
| async: true, | ||
| queued: true | ||
| }); | ||
| }); | ||
| }; | ||
| const runMultipleArraySuite = () => { | ||
| const fibonacciNumber = [35]; | ||
| const isComplete = [false]; | ||
| const mAddyOsmani = addyOsmani(fibonacciMultipleArray); | ||
| const mFastMemoize = fastMemoize(fibonacciMultipleArray); | ||
| const mLodash = lodash(fibonacciMultipleArray, resolveArguments); | ||
| const mLruMemoize = lruMemoize(Infinity)(fibonacciMultipleArray); | ||
| const mMem = mem(fibonacciMultipleArray); | ||
| const mMemoizee = memoizee(fibonacciMultipleArray); | ||
| const mMemoizerific = memoizerific(Infinity)(fibonacciMultipleArray); | ||
| const mMicroMemoize = memoize(fibonacciMultipleArray); | ||
| const mRamda = ramda(resolveArguments, fibonacciMultipleArray); | ||
| const mUnderscore = underscore(fibonacciMultipleArray, resolveArguments); | ||
| return new Promise((resolve) => { | ||
| new Benchmark.Suite(getSuiteOptions('multiple array parameters', resolve)) | ||
| .add('addy-osmani', () => { | ||
| mAddyOsmani(fibonacciNumber, isComplete); | ||
| }) | ||
| .add('fast-memoize', () => { | ||
| mFastMemoize(fibonacciNumber, isComplete); | ||
| }) | ||
| .add('lodash', () => { | ||
| mLodash(fibonacciNumber, isComplete); | ||
| }) | ||
| .add('lru-memoize', () => { | ||
| mLruMemoize(fibonacciNumber, isComplete); | ||
| }) | ||
| .add('mem', () => { | ||
| mMem(fibonacciNumber, isComplete); | ||
| }) | ||
| .add('memoizee', () => { | ||
| mMemoizee(fibonacciNumber, isComplete); | ||
| }) | ||
| .add('memoizerific', () => { | ||
| mMemoizerific(fibonacciNumber, isComplete); | ||
| }) | ||
| .add('micro-memoize', () => { | ||
| mMicroMemoize(fibonacciNumber, isComplete); | ||
| }) | ||
| .add('ramda', () => { | ||
| mRamda(fibonacciNumber, isComplete); | ||
| }) | ||
| .add('underscore', () => { | ||
| mUnderscore(fibonacciNumber, isComplete); | ||
| }) | ||
| .run({ | ||
| async: true, | ||
| queued: true | ||
| }); | ||
| }); | ||
| }; | ||
| const runMultipleObjectSuite = () => { | ||
| const fibonacciNumber = {number: 35}; | ||
| const isComplete = {isComplete: false}; | ||
| const mAddyOsmani = addyOsmani(fibonacciMultipleObject); | ||
| const mFastMemoize = fastMemoize(fibonacciMultipleObject); | ||
| const mLodash = lodash(fibonacciMultipleObject, resolveArguments); | ||
| const mLruMemoize = lruMemoize(Infinity)(fibonacciMultipleObject); | ||
| const mMem = mem(fibonacciMultipleObject); | ||
| const mMemoizee = memoizee(fibonacciMultipleObject); | ||
| const mMemoizerific = memoizerific(Infinity)(fibonacciMultipleObject); | ||
| const mMicroMemoize = memoize(fibonacciMultipleObject); | ||
| const mRamda = ramda(resolveArguments, fibonacciMultipleObject); | ||
| const mUnderscore = underscore(fibonacciMultipleObject, resolveArguments); | ||
| return new Promise((resolve) => { | ||
| new Benchmark.Suite(getSuiteOptions('multiple object parameters', resolve)) | ||
| .add('addy-osmani', () => { | ||
| mAddyOsmani(fibonacciNumber, isComplete); | ||
| }) | ||
| .add('fast-memoize', () => { | ||
| mFastMemoize(fibonacciNumber, isComplete); | ||
| }) | ||
| .add('lodash', () => { | ||
| mLodash(fibonacciNumber, isComplete); | ||
| }) | ||
| .add('lru-memoize', () => { | ||
| mLruMemoize(fibonacciNumber, isComplete); | ||
| }) | ||
| .add('mem', () => { | ||
| mMem(fibonacciNumber, isComplete); | ||
| }) | ||
| .add('memoizee', () => { | ||
| mMemoizee(fibonacciNumber, isComplete); | ||
| }) | ||
| .add('memoizerific', () => { | ||
| mMemoizerific(fibonacciNumber, isComplete); | ||
| }) | ||
| .add('micro-memoize', () => { | ||
| mMicroMemoize(fibonacciNumber, isComplete); | ||
| }) | ||
| .add('ramda', () => { | ||
| mRamda(fibonacciNumber, isComplete); | ||
| }) | ||
| .add('underscore', () => { | ||
| mUnderscore(fibonacciNumber, isComplete); | ||
| }) | ||
| .run({ | ||
| async: true, | ||
| queued: true | ||
| }); | ||
| }); | ||
| }; | ||
| const runAlternativeOptionsSuite = () => { | ||
| const mMoizeDeep = memoize(fibonacciMultipleDeepEqual, { | ||
| isMatchingKey: deepEqualFastEquals | ||
| }); | ||
| const mMoizeLodashDeep = memoize(fibonacciMultipleDeepEqual, { | ||
| isMatchingKey: deepEqualLodash | ||
| }); | ||
| const mMoizeSerialize = memoize(fibonacciMultipleDeepEqual, { | ||
| transformKey: JSON.stringify | ||
| }); | ||
| const chooseSpecificArgs = (foo, bar, baz) => { | ||
| return [foo, baz]; | ||
| }; | ||
| const mMoizeSpecificArgs = memoize(chooseSpecificArgs, { | ||
| transformKey(args) { | ||
| let index = args.length, | ||
| newKey = []; | ||
| while (--index) { | ||
| newKey[index - 1] = args[index]; | ||
| } | ||
| return newKey; | ||
| } | ||
| }); | ||
| const mMoizeMaxArgs = memoize( | ||
| (one, two, three) => { | ||
| return [one, two, three]; | ||
| }, | ||
| { | ||
| transformKey(args) { | ||
| return [args[0], args[1]]; | ||
| } | ||
| } | ||
| ); | ||
| const object1 = {foo: 'bar'}; | ||
| const object2 = ['foo']; | ||
| return new Promise((resolve) => { | ||
| new Benchmark.Suite('Alternative options', getSuiteOptions('alternative options', resolve)) | ||
| .add('moize serialized', () => { | ||
| mMoizeSerialize({number: 35}); | ||
| }) | ||
| .add('moize deep equals', () => { | ||
| mMoizeDeep({number: 35}); | ||
| }) | ||
| .add('moize deep equals (lodash isEqual)', () => { | ||
| mMoizeLodashDeep({number: 35}); | ||
| }) | ||
| .add('moize (transform args)', () => { | ||
| mMoizeSpecificArgs('foo', object1, object2); | ||
| }) | ||
| .add('moize (maximum args)', () => { | ||
| mMoizeMaxArgs('foo', object1, object2); | ||
| }) | ||
| .run({ | ||
| async: true, | ||
| queued: true | ||
| }); | ||
| }); | ||
| }; | ||
| const writeCsv = () => { | ||
| let invidualResultsHeaders = ['Name', 'Overall (average)', 'Single (average)', 'Multiple (average)']; | ||
| const individualTableMap = Object.keys(csvResults).reduce((rows, key) => { | ||
| const header = key.replace(/ (parameters|parameter)/, ''); | ||
| if (!~invidualResultsHeaders.indexOf(header)) { | ||
| invidualResultsHeaders.push(header); | ||
| } | ||
| return Object.keys(csvResults[key]).reduce((values, library) => { | ||
| if (!rows[library]) { | ||
| rows[library] = {}; | ||
| } | ||
| rows[library][header] = csvResults[key][library]; | ||
| return rows; | ||
| }, rows); | ||
| }, {}); | ||
| const averages = Object.keys(individualTableMap).reduce((rows, library) => { | ||
| if (!rows[library]) { | ||
| rows[library] = {}; | ||
| } | ||
| const libraryAverages = Object.keys(individualTableMap[library]).reduce( | ||
| ({multiple, single}, header) => { | ||
| if (~header.indexOf('multiple')) { | ||
| multiple.length++; | ||
| multiple.total += ~~individualTableMap[library][header]; | ||
| } else { | ||
| single.length++; | ||
| single.total += ~~individualTableMap[library][header]; | ||
| } | ||
| return { | ||
| multiple, | ||
| single | ||
| }; | ||
| }, | ||
| { | ||
| multiple: { | ||
| length: 0, | ||
| total: 0 | ||
| }, | ||
| single: { | ||
| length: 0, | ||
| total: 0 | ||
| } | ||
| } | ||
| ); | ||
| rows[library] = { | ||
| multiple: libraryAverages.multiple.length | ||
| ? ~~(libraryAverages.multiple.total / libraryAverages.multiple.length) | ||
| : 0, | ||
| overall: libraryAverages.multiple.length | ||
| ? ~~( | ||
| (libraryAverages.multiple.total + libraryAverages.single.total) / | ||
| (libraryAverages.multiple.length + libraryAverages.single.length) | ||
| ) | ||
| : 0, | ||
| single: libraryAverages.single.length ? ~~(libraryAverages.single.total / libraryAverages.single.length) : 0 | ||
| }; | ||
| return rows; | ||
| }, {}); | ||
| const individualRows = _.orderBy( | ||
| Object.keys(individualTableMap).map((key) => { | ||
| const values = invidualResultsHeaders.slice(4).map((header) => { | ||
| return individualTableMap[key][header]; | ||
| }); | ||
| return [key, averages[key].overall, averages[key].single, averages[key].multiple].concat(values); | ||
| }), | ||
| [1, 2], | ||
| ['desc', 'desc'] | ||
| ); | ||
| const individualCsvText = `${invidualResultsHeaders | ||
| .map((header) => { | ||
| return `"${header}"`; | ||
| }) | ||
| .join(',')}\n${individualRows | ||
| .map((row) => { | ||
| return row | ||
| .map((value) => { | ||
| return value ? `"${value.toLocaleString()}"` : '"N/A"'; | ||
| }) | ||
| .join(','); | ||
| }) | ||
| .join('\n')}`; | ||
| // write to file | ||
| if (fs && fs.writeFileSync) { | ||
| fs.writeFileSync('benchmark/benchmark_results.csv', individualCsvText, 'utf8'); | ||
| console.log('Benchmarks done! Results saved to benchmark_results.csv'); | ||
| } else { | ||
| console.log('Benchmarks done!'); | ||
| } | ||
| }; | ||
| if (process.env.ALTERNATIVE) { | ||
| Promise.resolve().then(runAlternativeOptionsSuite); | ||
| } else { | ||
| Promise.resolve() | ||
| .then(runSinglePrimitiveSuite) | ||
| .then(runSingleArraySuite) | ||
| .then(runSingleObjectSuite) | ||
| .then(runMultiplePrimitiveSuite) | ||
| .then(runMultipleArraySuite) | ||
| .then(runMultipleObjectSuite) | ||
| .then(writeCsv); | ||
| } |
| 'use strict'; | ||
| const memoize = require('../lib').default; | ||
| const fibonacciSinglePrimitive = (number) => { | ||
| return number < 2 ? number : fibonacciSinglePrimitive(number - 1) + fibonacciSinglePrimitive(number - 2); | ||
| }; | ||
| const fibonacciSingleArray = (array) => { | ||
| return array[0] < 2 ? array[0] : fibonacciSingleArray([array[0] - 1]) + fibonacciSingleArray([array[0] - 2]); | ||
| }; | ||
| const fibonacciSingleObject = (object) => { | ||
| return object.number < 2 | ||
| ? object.number | ||
| : fibonacciSingleObject({number: object.number - 1}) + fibonacciSingleObject({number: object.number - 2}); | ||
| }; | ||
| const fibonacciMultiplePrimitive = (number, isComplete) => { | ||
| if (isComplete) { | ||
| return number; | ||
| } | ||
| const firstValue = number - 1; | ||
| const secondValue = number - 2; | ||
| return ( | ||
| fibonacciMultiplePrimitive(firstValue, firstValue < 2) + fibonacciMultiplePrimitive(secondValue, secondValue < 2) | ||
| ); | ||
| }; | ||
| const fibonacciMultipleArray = (array, check) => { | ||
| if (check[0]) { | ||
| return array[0]; | ||
| } | ||
| const firstValue = array[0] - 1; | ||
| const secondValue = array[0] - 2; | ||
| return ( | ||
| fibonacciMultipleArray([firstValue], [firstValue < 2]) + fibonacciMultipleArray([secondValue], [secondValue < 2]) | ||
| ); | ||
| }; | ||
| const fibonacciMultipleObject = (object, check) => { | ||
| if (check.isComplete) { | ||
| return object.number; | ||
| } | ||
| const firstValue = object.number - 1; | ||
| const secondValue = object.number - 2; | ||
| return ( | ||
| fibonacciMultipleObject({number: firstValue}, {isComplete: firstValue < 2}) + | ||
| fibonacciMultipleObject({number: secondValue}, {isComplete: secondValue < 2}) | ||
| ); | ||
| }; | ||
| const number = 35; | ||
| const array = [number]; | ||
| const object = {number}; | ||
| const isCompleteBoolean = false; | ||
| const isCompleteArray = [false]; | ||
| const isCompleteObject = {isComplete: false}; | ||
| fibonacciSinglePrimitive(number); | ||
| fibonacciSinglePrimitive(number); | ||
| fibonacciSinglePrimitive(number); | ||
| fibonacciSingleArray(array); | ||
| fibonacciSingleArray(array); | ||
| fibonacciSingleArray(array); | ||
| fibonacciSingleObject(object); | ||
| fibonacciSingleObject(object); | ||
| fibonacciSingleObject(object); | ||
| fibonacciMultiplePrimitive(number, isCompleteBoolean); | ||
| fibonacciMultiplePrimitive(number, isCompleteBoolean); | ||
| fibonacciMultiplePrimitive(number, isCompleteBoolean); | ||
| fibonacciMultipleArray(array, isCompleteArray); | ||
| fibonacciMultipleArray(array, isCompleteArray); | ||
| fibonacciMultipleArray(array, isCompleteArray); | ||
| fibonacciMultipleObject(object, isCompleteObject); | ||
| fibonacciMultipleObject(object, isCompleteObject); | ||
| fibonacciMultipleObject(object, isCompleteObject); |
-143
| function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } | ||
| // types | ||
| // utils | ||
| import { assign, cloneArray, createGetKeyIndex, createSetPromiseHandler, isSameValueZero, onCacheOperation, orderByLru } from './utils'; | ||
| /** | ||
| * @function memoize | ||
| * | ||
| * @description | ||
| * get the memoized version of the method passed | ||
| * | ||
| * @param {function} fn the method to memoize | ||
| * @param {Object} [options={}] the options to build the memoizer with | ||
| * @param {boolean} [options.isEqual=isSameValueZero] the method to compare equality of keys with | ||
| * @param {number} [options.maxSize=1] the number of items to store in cache | ||
| * @returns {function} the memoized method | ||
| */ | ||
| export default function memoize(fn, options) { | ||
| // if it is a memoized method, don't re-memoize it | ||
| if (fn.isMemoized) { | ||
| return fn; | ||
| } | ||
| var _ref = options || {}, | ||
| _ref$isEqual = _ref.isEqual, | ||
| isEqual = _ref$isEqual === void 0 ? isSameValueZero : _ref$isEqual, | ||
| isMatchingKey = _ref.isMatchingKey, | ||
| _ref$isPromise = _ref.isPromise, | ||
| isPromise = _ref$isPromise === void 0 ? false : _ref$isPromise, | ||
| _ref$maxSize = _ref.maxSize, | ||
| maxSize = _ref$maxSize === void 0 ? 1 : _ref$maxSize, | ||
| _ref$onCacheAdd = _ref.onCacheAdd, | ||
| onCacheAdd = _ref$onCacheAdd === void 0 ? onCacheOperation : _ref$onCacheAdd, | ||
| _ref$onCacheChange = _ref.onCacheChange, | ||
| onCacheChange = _ref$onCacheChange === void 0 ? onCacheOperation : _ref$onCacheChange, | ||
| _ref$onCacheHit = _ref.onCacheHit, | ||
| onCacheHit = _ref$onCacheHit === void 0 ? onCacheOperation : _ref$onCacheHit, | ||
| transformKey = _ref.transformKey, | ||
| extraOptions = _objectWithoutPropertiesLoose(_ref, ["isEqual", "isMatchingKey", "isPromise", "maxSize", "onCacheAdd", "onCacheChange", "onCacheHit", "transformKey"]); | ||
| var normalizedOptions = assign({}, extraOptions, { | ||
| isEqual: isEqual, | ||
| isMatchingKey: isMatchingKey, | ||
| isPromise: isPromise, | ||
| maxSize: maxSize, | ||
| onCacheAdd: onCacheAdd, | ||
| onCacheChange: onCacheChange, | ||
| onCacheHit: onCacheHit, | ||
| transformKey: transformKey | ||
| }); | ||
| var getKeyIndex = createGetKeyIndex(isEqual, isMatchingKey); | ||
| var setPromiseHandler = createSetPromiseHandler(normalizedOptions); | ||
| var shouldCloneArguments = !!(transformKey || isMatchingKey); | ||
| var cache = { | ||
| keys: [], | ||
| get size() { | ||
| return cache.keys.length; | ||
| }, | ||
| values: [] | ||
| }; | ||
| var keys = cache.keys, | ||
| values = cache.values; | ||
| /** | ||
| * @function memoized | ||
| * | ||
| * @description | ||
| * the memoized version of the method passed | ||
| * | ||
| * @param {...Array<any>} key the arguments passed, which create a unique cache key | ||
| * @returns {any} the value of the method called with the arguments | ||
| */ | ||
| function memoized() { | ||
| var args = arguments; | ||
| var normalizedArgs = shouldCloneArguments ? cloneArray(args) : args; | ||
| var key = transformKey ? transformKey(normalizedArgs) : normalizedArgs; | ||
| var keyIndex = getKeyIndex(keys, key); | ||
| if (~keyIndex) { | ||
| onCacheHit(cache, normalizedOptions, memoized); | ||
| if (keyIndex) { | ||
| orderByLru(keys, keys[keyIndex], keyIndex); | ||
| orderByLru(values, values[keyIndex], keyIndex); | ||
| onCacheChange(cache, normalizedOptions, memoized); | ||
| } | ||
| } else { | ||
| if (keys.length >= maxSize) { | ||
| keys.pop(); | ||
| values.pop(); | ||
| } | ||
| var newKey = shouldCloneArguments ? key : cloneArray(normalizedArgs); | ||
| var newValue = fn.apply(this, args); | ||
| orderByLru(keys, newKey, keys.length); | ||
| orderByLru(values, newValue, values.length); | ||
| if (isPromise) { | ||
| setPromiseHandler(cache, memoized); | ||
| } | ||
| onCacheAdd(cache, normalizedOptions, memoized); | ||
| onCacheChange(cache, normalizedOptions, memoized); | ||
| } | ||
| return values[0]; | ||
| } | ||
| Object.defineProperties(memoized, { | ||
| cache: { | ||
| configurable: true, | ||
| get: function get() { | ||
| return cache; | ||
| } | ||
| }, | ||
| cacheSnapshot: { | ||
| configurable: true, | ||
| get: function get() { | ||
| return { | ||
| keys: cloneArray(cache.keys), | ||
| size: cache.size, | ||
| values: cloneArray(cache.values) | ||
| }; | ||
| } | ||
| }, | ||
| isMemoized: { | ||
| configurable: true, | ||
| get: function get() { | ||
| return true; | ||
| } | ||
| }, | ||
| options: { | ||
| configurable: true, | ||
| get: function get() { | ||
| return normalizedOptions; | ||
| } | ||
| } | ||
| }); | ||
| return memoized; | ||
| } |
-182
| // types | ||
| var hasOwnProperty = Object.prototype.hasOwnProperty; | ||
| /** | ||
| * @function assign | ||
| * | ||
| * @description | ||
| * merge the sources into the target, as you would with Object.assign() | ||
| * | ||
| * @param {Object} target object to merge into | ||
| * @param {...Array<Object>} sources the sources to merge into the target | ||
| * @returns {Object} the merged object | ||
| */ | ||
| export var assign = function assign(target) { | ||
| var source; | ||
| for (var index = 0; index < (arguments.length <= 1 ? 0 : arguments.length - 1); index++) { | ||
| source = index + 1 < 1 || arguments.length <= index + 1 ? undefined : arguments[index + 1]; | ||
| if (source && typeof source === 'object') { | ||
| for (var key in source) { | ||
| if (hasOwnProperty.call(source, key)) { | ||
| target[key] = source[key]; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| return target; | ||
| }; | ||
| /** | ||
| * @function cloneArray | ||
| * | ||
| * @description | ||
| * clone the array-like object and return the new array | ||
| * | ||
| * @param {Array<any>|Arguments} arrayLike the array-like object to clone | ||
| * @returns {Array<any>} the clone of the array | ||
| */ | ||
| export var cloneArray = function cloneArray(arrayLike) { | ||
| var length = arrayLike.length; | ||
| if (!length) { | ||
| return []; | ||
| } | ||
| if (length === 1) { | ||
| return [arrayLike[0]]; | ||
| } | ||
| if (length === 2) { | ||
| return [arrayLike[0], arrayLike[1]]; | ||
| } | ||
| if (length === 3) { | ||
| return [arrayLike[0], arrayLike[1], arrayLike[2]]; | ||
| } | ||
| var array = new Array(length); | ||
| for (var index = 0; index < length; index++) { | ||
| array[index] = arrayLike[index]; | ||
| } | ||
| return array; | ||
| }; | ||
| export var createAreKeysEqual = function createAreKeysEqual(isEqual | ||
| /** | ||
| * @function areKeysEqual | ||
| * | ||
| * @description | ||
| * are the keys shallowly equal to one another | ||
| * | ||
| * @param {Array<any>} keys1 the keys array to test against | ||
| * @param {Array<any>} keys2 the keys array to test | ||
| * @returns {boolean} are the keys shallowly equal | ||
| */ | ||
| ) { | ||
| return function (keys1, keys2) { | ||
| if (keys1.length !== keys2.length) { | ||
| return false; | ||
| } | ||
| for (var index = 0, length = keys1.length; index < length; index++) { | ||
| if (!isEqual(keys1[index], keys2[index])) { | ||
| return false; | ||
| } | ||
| } | ||
| return true; | ||
| }; | ||
| }; | ||
| export var createGetKeyIndex = function createGetKeyIndex(isEqual, isMatchingKey) { | ||
| var areKeysEqual = typeof isMatchingKey === 'function' ? isMatchingKey : createAreKeysEqual(isEqual); | ||
| /** | ||
| * @function getKeyIndex | ||
| * | ||
| * @description | ||
| * get the index of the matching key | ||
| * | ||
| * @param {Array<Array<any>>} allKeys the list of all available keys | ||
| * @param {Array<any>} keysToMatch the key to try to match | ||
| * | ||
| * @returns {number} the index of the matching key value, or -1 | ||
| */ | ||
| return function (allKeys, keysToMatch) { | ||
| for (var index = 0; index < allKeys.length; index++) { | ||
| if (areKeysEqual(allKeys[index], keysToMatch)) { | ||
| return index; | ||
| } | ||
| } | ||
| return -1; | ||
| }; | ||
| }; | ||
| /** | ||
| * @function isSameValueZero | ||
| * | ||
| * @description | ||
| * are the objects equal based on SameValueZero | ||
| * | ||
| * @param {any} object1 the first object to compare | ||
| * @param {any} object2 the second object to compare | ||
| * @returns {boolean} are the two objects equal | ||
| */ | ||
| export var isSameValueZero = function isSameValueZero(object1, object2) { | ||
| return object1 === object2 || object1 !== object1 && object2 !== object2; | ||
| }; | ||
| export var onCacheOperation = function onCacheOperation(cacheIgnored, optionsIgnored, memoizedIgnored) {}; | ||
| /** | ||
| * @function orderByLru | ||
| * | ||
| * @description | ||
| * order the array based on a Least-Recently-Used basis | ||
| * | ||
| * @param {Array<any>} array the array to order | ||
| * @param {any} value the value to assign at the beginning of the array | ||
| * @param {number} startingIndex the index of the item to move to the front | ||
| */ | ||
| export var orderByLru = function orderByLru(array, value, startingIndex) { | ||
| var index = startingIndex; | ||
| while (index--) { | ||
| array[index + 1] = array[index]; | ||
| } | ||
| array[0] = value; | ||
| }; | ||
| /** | ||
| * @function createSetPromiseHandler | ||
| * | ||
| * @description | ||
| * update the promise method to auto-remove from cache if rejected, and if resolved then fire cache hit / changed | ||
| * | ||
| * @param {Options} options the options for the memoized function | ||
| * @param {function(Cache, function): function} memoized the memoized function | ||
| */ | ||
| export var createSetPromiseHandler = function createSetPromiseHandler(options) { | ||
| var getKeyIndex = createGetKeyIndex(options.isEqual, options.isMatchingKey); | ||
| return function (cache, memoized) { | ||
| var key = cache.keys[0]; | ||
| cache.values[0] = cache.values[0].then(function (value) { | ||
| options.onCacheHit(cache, options, memoized); | ||
| options.onCacheChange(cache, options, memoized); | ||
| return value; | ||
| }).catch(function (error) { | ||
| var keyIndex = getKeyIndex(cache.keys, key); | ||
| if (~keyIndex) { | ||
| cache.keys.splice(keyIndex, 1); | ||
| cache.values.splice(keyIndex, 1); | ||
| } | ||
| throw error; | ||
| }); | ||
| }; | ||
| }; |
| declare module 'micro-memoize' { | ||
| declare type Cache = { | ||
| keys: Array<any>, | ||
| size: number, | ||
| values: Array<any> | ||
| }; | ||
| declare type Options = { | ||
| isEqual?: (firstValue: any, secondValue: any) => boolean, | ||
| isMatchingKey?: (cacheKey: Array<any>, key: Array<any>) => boolean, | ||
| isPromise?: boolean, | ||
| maxSize?: number, | ||
| onCacheAdd?: (cache: Cache, options: Options) => void, | ||
| onCacheChange?: (cache: Cache, options: Options) => void, | ||
| onCacheHit?: (cache: Cache, options: Options) => void, | ||
| transformKey?: (args: any[]) => any | ||
| }; | ||
| declare type Fn = (...args: any[]) => any; | ||
| declare module.exports: { | ||
| (fn: Fn, options?: Options): Fn | ||
| }; | ||
| } |
-146
| "use strict"; | ||
| exports.__esModule = true; | ||
| exports.default = memoize; | ||
| var _utils = require("./utils"); | ||
| function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } | ||
| /** | ||
| * @function memoize | ||
| * | ||
| * @description | ||
| * get the memoized version of the method passed | ||
| * | ||
| * @param {function} fn the method to memoize | ||
| * @param {Object} [options={}] the options to build the memoizer with | ||
| * @param {boolean} [options.isEqual=isSameValueZero] the method to compare equality of keys with | ||
| * @param {number} [options.maxSize=1] the number of items to store in cache | ||
| * @returns {function} the memoized method | ||
| */ | ||
| function memoize(fn, options) { | ||
| // if it is a memoized method, don't re-memoize it | ||
| if (fn.isMemoized) { | ||
| return fn; | ||
| } | ||
| var _ref = options || {}, | ||
| _ref$isEqual = _ref.isEqual, | ||
| isEqual = _ref$isEqual === void 0 ? _utils.isSameValueZero : _ref$isEqual, | ||
| isMatchingKey = _ref.isMatchingKey, | ||
| _ref$isPromise = _ref.isPromise, | ||
| isPromise = _ref$isPromise === void 0 ? false : _ref$isPromise, | ||
| _ref$maxSize = _ref.maxSize, | ||
| maxSize = _ref$maxSize === void 0 ? 1 : _ref$maxSize, | ||
| _ref$onCacheAdd = _ref.onCacheAdd, | ||
| onCacheAdd = _ref$onCacheAdd === void 0 ? _utils.onCacheOperation : _ref$onCacheAdd, | ||
| _ref$onCacheChange = _ref.onCacheChange, | ||
| onCacheChange = _ref$onCacheChange === void 0 ? _utils.onCacheOperation : _ref$onCacheChange, | ||
| _ref$onCacheHit = _ref.onCacheHit, | ||
| onCacheHit = _ref$onCacheHit === void 0 ? _utils.onCacheOperation : _ref$onCacheHit, | ||
| transformKey = _ref.transformKey, | ||
| extraOptions = _objectWithoutPropertiesLoose(_ref, ["isEqual", "isMatchingKey", "isPromise", "maxSize", "onCacheAdd", "onCacheChange", "onCacheHit", "transformKey"]); | ||
| var normalizedOptions = (0, _utils.assign)({}, extraOptions, { | ||
| isEqual: isEqual, | ||
| isMatchingKey: isMatchingKey, | ||
| isPromise: isPromise, | ||
| maxSize: maxSize, | ||
| onCacheAdd: onCacheAdd, | ||
| onCacheChange: onCacheChange, | ||
| onCacheHit: onCacheHit, | ||
| transformKey: transformKey | ||
| }); | ||
| var getKeyIndex = (0, _utils.createGetKeyIndex)(isEqual, isMatchingKey); | ||
| var setPromiseHandler = (0, _utils.createSetPromiseHandler)(normalizedOptions); | ||
| var shouldCloneArguments = !!(transformKey || isMatchingKey); | ||
| var cache = { | ||
| keys: [], | ||
| get size() { | ||
| return cache.keys.length; | ||
| }, | ||
| values: [] | ||
| }; | ||
| var keys = cache.keys, | ||
| values = cache.values; | ||
| /** | ||
| * @function memoized | ||
| * | ||
| * @description | ||
| * the memoized version of the method passed | ||
| * | ||
| * @param {...Array<any>} key the arguments passed, which create a unique cache key | ||
| * @returns {any} the value of the method called with the arguments | ||
| */ | ||
| function memoized() { | ||
| var args = arguments; | ||
| var normalizedArgs = shouldCloneArguments ? (0, _utils.cloneArray)(args) : args; | ||
| var key = transformKey ? transformKey(normalizedArgs) : normalizedArgs; | ||
| var keyIndex = getKeyIndex(keys, key); | ||
| if (~keyIndex) { | ||
| onCacheHit(cache, normalizedOptions, memoized); | ||
| if (keyIndex) { | ||
| (0, _utils.orderByLru)(keys, keys[keyIndex], keyIndex); | ||
| (0, _utils.orderByLru)(values, values[keyIndex], keyIndex); | ||
| onCacheChange(cache, normalizedOptions, memoized); | ||
| } | ||
| } else { | ||
| if (keys.length >= maxSize) { | ||
| keys.pop(); | ||
| values.pop(); | ||
| } | ||
| var newKey = shouldCloneArguments ? key : (0, _utils.cloneArray)(normalizedArgs); | ||
| var newValue = fn.apply(this, args); | ||
| (0, _utils.orderByLru)(keys, newKey, keys.length); | ||
| (0, _utils.orderByLru)(values, newValue, values.length); | ||
| if (isPromise) { | ||
| setPromiseHandler(cache, memoized); | ||
| } | ||
| onCacheAdd(cache, normalizedOptions, memoized); | ||
| onCacheChange(cache, normalizedOptions, memoized); | ||
| } | ||
| return values[0]; | ||
| } | ||
| Object.defineProperties(memoized, { | ||
| cache: { | ||
| configurable: true, | ||
| get: function get() { | ||
| return cache; | ||
| } | ||
| }, | ||
| cacheSnapshot: { | ||
| configurable: true, | ||
| get: function get() { | ||
| return { | ||
| keys: (0, _utils.cloneArray)(cache.keys), | ||
| size: cache.size, | ||
| values: (0, _utils.cloneArray)(cache.values) | ||
| }; | ||
| } | ||
| }, | ||
| isMemoized: { | ||
| configurable: true, | ||
| get: function get() { | ||
| return true; | ||
| } | ||
| }, | ||
| options: { | ||
| configurable: true, | ||
| get: function get() { | ||
| return normalizedOptions; | ||
| } | ||
| } | ||
| }); | ||
| return memoized; | ||
| } |
| "use strict"; |
-209
| "use strict"; | ||
| exports.__esModule = true; | ||
| exports.createSetPromiseHandler = exports.orderByLru = exports.onCacheOperation = exports.isSameValueZero = exports.createGetKeyIndex = exports.createAreKeysEqual = exports.cloneArray = exports.assign = void 0; | ||
| // types | ||
| var hasOwnProperty = Object.prototype.hasOwnProperty; | ||
| /** | ||
| * @function assign | ||
| * | ||
| * @description | ||
| * merge the sources into the target, as you would with Object.assign() | ||
| * | ||
| * @param {Object} target object to merge into | ||
| * @param {...Array<Object>} sources the sources to merge into the target | ||
| * @returns {Object} the merged object | ||
| */ | ||
| var assign = function assign(target) { | ||
| var source; | ||
| for (var index = 0; index < (arguments.length <= 1 ? 0 : arguments.length - 1); index++) { | ||
| source = index + 1 < 1 || arguments.length <= index + 1 ? undefined : arguments[index + 1]; | ||
| if (source && typeof source === 'object') { | ||
| for (var key in source) { | ||
| if (hasOwnProperty.call(source, key)) { | ||
| target[key] = source[key]; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| return target; | ||
| }; | ||
| /** | ||
| * @function cloneArray | ||
| * | ||
| * @description | ||
| * clone the array-like object and return the new array | ||
| * | ||
| * @param {Array<any>|Arguments} arrayLike the array-like object to clone | ||
| * @returns {Array<any>} the clone of the array | ||
| */ | ||
| exports.assign = assign; | ||
| var cloneArray = function cloneArray(arrayLike) { | ||
| var length = arrayLike.length; | ||
| if (!length) { | ||
| return []; | ||
| } | ||
| if (length === 1) { | ||
| return [arrayLike[0]]; | ||
| } | ||
| if (length === 2) { | ||
| return [arrayLike[0], arrayLike[1]]; | ||
| } | ||
| if (length === 3) { | ||
| return [arrayLike[0], arrayLike[1], arrayLike[2]]; | ||
| } | ||
| var array = new Array(length); | ||
| for (var index = 0; index < length; index++) { | ||
| array[index] = arrayLike[index]; | ||
| } | ||
| return array; | ||
| }; | ||
| exports.cloneArray = cloneArray; | ||
| var createAreKeysEqual = function createAreKeysEqual(isEqual | ||
| /** | ||
| * @function areKeysEqual | ||
| * | ||
| * @description | ||
| * are the keys shallowly equal to one another | ||
| * | ||
| * @param {Array<any>} keys1 the keys array to test against | ||
| * @param {Array<any>} keys2 the keys array to test | ||
| * @returns {boolean} are the keys shallowly equal | ||
| */ | ||
| ) { | ||
| return function (keys1, keys2) { | ||
| if (keys1.length !== keys2.length) { | ||
| return false; | ||
| } | ||
| for (var index = 0, length = keys1.length; index < length; index++) { | ||
| if (!isEqual(keys1[index], keys2[index])) { | ||
| return false; | ||
| } | ||
| } | ||
| return true; | ||
| }; | ||
| }; | ||
| exports.createAreKeysEqual = createAreKeysEqual; | ||
| var createGetKeyIndex = function createGetKeyIndex(isEqual, isMatchingKey) { | ||
| var areKeysEqual = typeof isMatchingKey === 'function' ? isMatchingKey : createAreKeysEqual(isEqual); | ||
| /** | ||
| * @function getKeyIndex | ||
| * | ||
| * @description | ||
| * get the index of the matching key | ||
| * | ||
| * @param {Array<Array<any>>} allKeys the list of all available keys | ||
| * @param {Array<any>} keysToMatch the key to try to match | ||
| * | ||
| * @returns {number} the index of the matching key value, or -1 | ||
| */ | ||
| return function (allKeys, keysToMatch) { | ||
| for (var index = 0; index < allKeys.length; index++) { | ||
| if (areKeysEqual(allKeys[index], keysToMatch)) { | ||
| return index; | ||
| } | ||
| } | ||
| return -1; | ||
| }; | ||
| }; | ||
| /** | ||
| * @function isSameValueZero | ||
| * | ||
| * @description | ||
| * are the objects equal based on SameValueZero | ||
| * | ||
| * @param {any} object1 the first object to compare | ||
| * @param {any} object2 the second object to compare | ||
| * @returns {boolean} are the two objects equal | ||
| */ | ||
| exports.createGetKeyIndex = createGetKeyIndex; | ||
| var isSameValueZero = function isSameValueZero(object1, object2) { | ||
| return object1 === object2 || object1 !== object1 && object2 !== object2; | ||
| }; | ||
| exports.isSameValueZero = isSameValueZero; | ||
| var onCacheOperation = function onCacheOperation(cacheIgnored, optionsIgnored, memoizedIgnored) {}; | ||
| /** | ||
| * @function orderByLru | ||
| * | ||
| * @description | ||
| * order the array based on a Least-Recently-Used basis | ||
| * | ||
| * @param {Array<any>} array the array to order | ||
| * @param {any} value the value to assign at the beginning of the array | ||
| * @param {number} startingIndex the index of the item to move to the front | ||
| */ | ||
| exports.onCacheOperation = onCacheOperation; | ||
| var orderByLru = function orderByLru(array, value, startingIndex) { | ||
| var index = startingIndex; | ||
| while (index--) { | ||
| array[index + 1] = array[index]; | ||
| } | ||
| array[0] = value; | ||
| }; | ||
| /** | ||
| * @function createSetPromiseHandler | ||
| * | ||
| * @description | ||
| * update the promise method to auto-remove from cache if rejected, and if resolved then fire cache hit / changed | ||
| * | ||
| * @param {Options} options the options for the memoized function | ||
| * @param {function(Cache, function): function} memoized the memoized function | ||
| */ | ||
| exports.orderByLru = orderByLru; | ||
| var createSetPromiseHandler = function createSetPromiseHandler(options) { | ||
| var getKeyIndex = createGetKeyIndex(options.isEqual, options.isMatchingKey); | ||
| return function (cache, memoized) { | ||
| var key = cache.keys[0]; | ||
| cache.values[0] = cache.values[0].then(function (value) { | ||
| options.onCacheHit(cache, options, memoized); | ||
| options.onCacheChange(cache, options, memoized); | ||
| return value; | ||
| }).catch(function (error) { | ||
| var keyIndex = getKeyIndex(cache.keys, key); | ||
| if (~keyIndex) { | ||
| cache.keys.splice(keyIndex, 1); | ||
| cache.values.splice(keyIndex, 1); | ||
| } | ||
| throw error; | ||
| }); | ||
| }; | ||
| }; | ||
| exports.createSetPromiseHandler = createSetPromiseHandler; |
-143
| function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } | ||
| // types | ||
| // utils | ||
| import { assign, cloneArray, createGetKeyIndex, createSetPromiseHandler, isSameValueZero, onCacheOperation, orderByLru } from './utils'; | ||
| /** | ||
| * @function memoize | ||
| * | ||
| * @description | ||
| * get the memoized version of the method passed | ||
| * | ||
| * @param {function} fn the method to memoize | ||
| * @param {Object} [options={}] the options to build the memoizer with | ||
| * @param {boolean} [options.isEqual=isSameValueZero] the method to compare equality of keys with | ||
| * @param {number} [options.maxSize=1] the number of items to store in cache | ||
| * @returns {function} the memoized method | ||
| */ | ||
| export default function memoize(fn, options) { | ||
| // if it is a memoized method, don't re-memoize it | ||
| if (fn.isMemoized) { | ||
| return fn; | ||
| } | ||
| var _ref = options || {}, | ||
| _ref$isEqual = _ref.isEqual, | ||
| isEqual = _ref$isEqual === void 0 ? isSameValueZero : _ref$isEqual, | ||
| isMatchingKey = _ref.isMatchingKey, | ||
| _ref$isPromise = _ref.isPromise, | ||
| isPromise = _ref$isPromise === void 0 ? false : _ref$isPromise, | ||
| _ref$maxSize = _ref.maxSize, | ||
| maxSize = _ref$maxSize === void 0 ? 1 : _ref$maxSize, | ||
| _ref$onCacheAdd = _ref.onCacheAdd, | ||
| onCacheAdd = _ref$onCacheAdd === void 0 ? onCacheOperation : _ref$onCacheAdd, | ||
| _ref$onCacheChange = _ref.onCacheChange, | ||
| onCacheChange = _ref$onCacheChange === void 0 ? onCacheOperation : _ref$onCacheChange, | ||
| _ref$onCacheHit = _ref.onCacheHit, | ||
| onCacheHit = _ref$onCacheHit === void 0 ? onCacheOperation : _ref$onCacheHit, | ||
| transformKey = _ref.transformKey, | ||
| extraOptions = _objectWithoutPropertiesLoose(_ref, ["isEqual", "isMatchingKey", "isPromise", "maxSize", "onCacheAdd", "onCacheChange", "onCacheHit", "transformKey"]); | ||
| var normalizedOptions = assign({}, extraOptions, { | ||
| isEqual: isEqual, | ||
| isMatchingKey: isMatchingKey, | ||
| isPromise: isPromise, | ||
| maxSize: maxSize, | ||
| onCacheAdd: onCacheAdd, | ||
| onCacheChange: onCacheChange, | ||
| onCacheHit: onCacheHit, | ||
| transformKey: transformKey | ||
| }); | ||
| var getKeyIndex = createGetKeyIndex(isEqual, isMatchingKey); | ||
| var setPromiseHandler = createSetPromiseHandler(normalizedOptions); | ||
| var shouldCloneArguments = !!(transformKey || isMatchingKey); | ||
| var cache = { | ||
| keys: [], | ||
| get size() { | ||
| return cache.keys.length; | ||
| }, | ||
| values: [] | ||
| }; | ||
| var keys = cache.keys, | ||
| values = cache.values; | ||
| /** | ||
| * @function memoized | ||
| * | ||
| * @description | ||
| * the memoized version of the method passed | ||
| * | ||
| * @param {...Array<any>} key the arguments passed, which create a unique cache key | ||
| * @returns {any} the value of the method called with the arguments | ||
| */ | ||
| function memoized() { | ||
| var args = arguments; | ||
| var normalizedArgs = shouldCloneArguments ? cloneArray(args) : args; | ||
| var key = transformKey ? transformKey(normalizedArgs) : normalizedArgs; | ||
| var keyIndex = getKeyIndex(keys, key); | ||
| if (~keyIndex) { | ||
| onCacheHit(cache, normalizedOptions, memoized); | ||
| if (keyIndex) { | ||
| orderByLru(keys, keys[keyIndex], keyIndex); | ||
| orderByLru(values, values[keyIndex], keyIndex); | ||
| onCacheChange(cache, normalizedOptions, memoized); | ||
| } | ||
| } else { | ||
| if (keys.length >= maxSize) { | ||
| keys.pop(); | ||
| values.pop(); | ||
| } | ||
| var newKey = shouldCloneArguments ? key : cloneArray(normalizedArgs); | ||
| var newValue = fn.apply(this, args); | ||
| orderByLru(keys, newKey, keys.length); | ||
| orderByLru(values, newValue, values.length); | ||
| if (isPromise) { | ||
| setPromiseHandler(cache, memoized); | ||
| } | ||
| onCacheAdd(cache, normalizedOptions, memoized); | ||
| onCacheChange(cache, normalizedOptions, memoized); | ||
| } | ||
| return values[0]; | ||
| } | ||
| Object.defineProperties(memoized, { | ||
| cache: { | ||
| configurable: true, | ||
| get: function get() { | ||
| return cache; | ||
| } | ||
| }, | ||
| cacheSnapshot: { | ||
| configurable: true, | ||
| get: function get() { | ||
| return { | ||
| keys: cloneArray(cache.keys), | ||
| size: cache.size, | ||
| values: cloneArray(cache.values) | ||
| }; | ||
| } | ||
| }, | ||
| isMemoized: { | ||
| configurable: true, | ||
| get: function get() { | ||
| return true; | ||
| } | ||
| }, | ||
| options: { | ||
| configurable: true, | ||
| get: function get() { | ||
| return normalizedOptions; | ||
| } | ||
| } | ||
| }); | ||
| return memoized; | ||
| } |
-182
| // types | ||
| var hasOwnProperty = Object.prototype.hasOwnProperty; | ||
| /** | ||
| * @function assign | ||
| * | ||
| * @description | ||
| * merge the sources into the target, as you would with Object.assign() | ||
| * | ||
| * @param {Object} target object to merge into | ||
| * @param {...Array<Object>} sources the sources to merge into the target | ||
| * @returns {Object} the merged object | ||
| */ | ||
| export var assign = function assign(target) { | ||
| var source; | ||
| for (var index = 0; index < (arguments.length <= 1 ? 0 : arguments.length - 1); index++) { | ||
| source = index + 1 < 1 || arguments.length <= index + 1 ? undefined : arguments[index + 1]; | ||
| if (source && typeof source === 'object') { | ||
| for (var key in source) { | ||
| if (hasOwnProperty.call(source, key)) { | ||
| target[key] = source[key]; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| return target; | ||
| }; | ||
| /** | ||
| * @function cloneArray | ||
| * | ||
| * @description | ||
| * clone the array-like object and return the new array | ||
| * | ||
| * @param {Array<any>|Arguments} arrayLike the array-like object to clone | ||
| * @returns {Array<any>} the clone of the array | ||
| */ | ||
| export var cloneArray = function cloneArray(arrayLike) { | ||
| var length = arrayLike.length; | ||
| if (!length) { | ||
| return []; | ||
| } | ||
| if (length === 1) { | ||
| return [arrayLike[0]]; | ||
| } | ||
| if (length === 2) { | ||
| return [arrayLike[0], arrayLike[1]]; | ||
| } | ||
| if (length === 3) { | ||
| return [arrayLike[0], arrayLike[1], arrayLike[2]]; | ||
| } | ||
| var array = new Array(length); | ||
| for (var index = 0; index < length; index++) { | ||
| array[index] = arrayLike[index]; | ||
| } | ||
| return array; | ||
| }; | ||
| export var createAreKeysEqual = function createAreKeysEqual(isEqual | ||
| /** | ||
| * @function areKeysEqual | ||
| * | ||
| * @description | ||
| * are the keys shallowly equal to one another | ||
| * | ||
| * @param {Array<any>} keys1 the keys array to test against | ||
| * @param {Array<any>} keys2 the keys array to test | ||
| * @returns {boolean} are the keys shallowly equal | ||
| */ | ||
| ) { | ||
| return function (keys1, keys2) { | ||
| if (keys1.length !== keys2.length) { | ||
| return false; | ||
| } | ||
| for (var index = 0, length = keys1.length; index < length; index++) { | ||
| if (!isEqual(keys1[index], keys2[index])) { | ||
| return false; | ||
| } | ||
| } | ||
| return true; | ||
| }; | ||
| }; | ||
| export var createGetKeyIndex = function createGetKeyIndex(isEqual, isMatchingKey) { | ||
| var areKeysEqual = typeof isMatchingKey === 'function' ? isMatchingKey : createAreKeysEqual(isEqual); | ||
| /** | ||
| * @function getKeyIndex | ||
| * | ||
| * @description | ||
| * get the index of the matching key | ||
| * | ||
| * @param {Array<Array<any>>} allKeys the list of all available keys | ||
| * @param {Array<any>} keysToMatch the key to try to match | ||
| * | ||
| * @returns {number} the index of the matching key value, or -1 | ||
| */ | ||
| return function (allKeys, keysToMatch) { | ||
| for (var index = 0; index < allKeys.length; index++) { | ||
| if (areKeysEqual(allKeys[index], keysToMatch)) { | ||
| return index; | ||
| } | ||
| } | ||
| return -1; | ||
| }; | ||
| }; | ||
| /** | ||
| * @function isSameValueZero | ||
| * | ||
| * @description | ||
| * are the objects equal based on SameValueZero | ||
| * | ||
| * @param {any} object1 the first object to compare | ||
| * @param {any} object2 the second object to compare | ||
| * @returns {boolean} are the two objects equal | ||
| */ | ||
| export var isSameValueZero = function isSameValueZero(object1, object2) { | ||
| return object1 === object2 || object1 !== object1 && object2 !== object2; | ||
| }; | ||
| export var onCacheOperation = function onCacheOperation(cacheIgnored, optionsIgnored, memoizedIgnored) {}; | ||
| /** | ||
| * @function orderByLru | ||
| * | ||
| * @description | ||
| * order the array based on a Least-Recently-Used basis | ||
| * | ||
| * @param {Array<any>} array the array to order | ||
| * @param {any} value the value to assign at the beginning of the array | ||
| * @param {number} startingIndex the index of the item to move to the front | ||
| */ | ||
| export var orderByLru = function orderByLru(array, value, startingIndex) { | ||
| var index = startingIndex; | ||
| while (index--) { | ||
| array[index + 1] = array[index]; | ||
| } | ||
| array[0] = value; | ||
| }; | ||
| /** | ||
| * @function createSetPromiseHandler | ||
| * | ||
| * @description | ||
| * update the promise method to auto-remove from cache if rejected, and if resolved then fire cache hit / changed | ||
| * | ||
| * @param {Options} options the options for the memoized function | ||
| * @param {function(Cache, function): function} memoized the memoized function | ||
| */ | ||
| export var createSetPromiseHandler = function createSetPromiseHandler(options) { | ||
| var getKeyIndex = createGetKeyIndex(options.isEqual, options.isMatchingKey); | ||
| return function (cache, memoized) { | ||
| var key = cache.keys[0]; | ||
| cache.values[0] = cache.values[0].then(function (value) { | ||
| options.onCacheHit(cache, options, memoized); | ||
| options.onCacheChange(cache, options, memoized); | ||
| return value; | ||
| }).catch(function (error) { | ||
| var keyIndex = getKeyIndex(cache.keys, key); | ||
| if (~keyIndex) { | ||
| cache.keys.splice(keyIndex, 1); | ||
| cache.values.splice(keyIndex, 1); | ||
| } | ||
| throw error; | ||
| }); | ||
| }; | ||
| }; |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Mixed license
LicensePackage contains multiple licenses.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 2 instances in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
37
-26%2523
29.58%420032
-43.6%25
-7.41%1
Infinity%2
100%6
50%1
Infinity%