New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details
Socket
Book a DemoSign in
Socket

@codeleap/store

Package Overview
Dependencies
Maintainers
2
Versions
67
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@codeleap/store - npm Package Compare versions

Comparing version
6.1.2
to
6.2.3
+2
-2
package.json
{
"name": "@codeleap/store",
"version": "6.1.2",
"version": "6.2.3",
"main": "src/index.ts",

@@ -12,3 +12,3 @@ "license": "UNLICENSED",

"devDependencies": {
"@codeleap/config": "6.1.2",
"@codeleap/config": "6.2.3",
"ts-node-dev": "1.1.8"

@@ -15,0 +15,0 @@ },

import { useStore } from '@nanostores/react'
import { setPersistentEngine, persistentAtom } from '@nanostores/persistent'
import { atom, WritableAtom } from 'nanostores'
import { GlobalState, GlobalStateConfig, StateSelector } from './types'
import { GlobalState, GlobalStateConfig, StateSelector, StateSetter } from './types'
import { stateAssign, useStateSelector } from './utils'

@@ -41,3 +41,3 @@ import { arrayHandler, arrayOps } from './array'

if (prop === 'set') {
return (newValue: Partial<T>) => {
return (newValue: StateSetter<Partial<T>>) => {
const value = stateAssign(newValue, target.get())

@@ -48,14 +48,14 @@ target.set(value)

if(prop == 'reset'){
if (prop == 'reset') {
return Reflect.get(target, 'set', receiver)
}
if(arrayOps.includes(prop as string)){
if (arrayOps.includes(prop as string)) {
const currentValue = target.get()
if(!Array.isArray(currentValue)) {
if (!Array.isArray(currentValue)) {
throw new Error('Cannot call array methods on a non array store')
}
const handle = arrayHandler(target as WritableAtom<any[]>)
const handle = arrayHandler(target as WritableAtom<any[]>)

@@ -66,4 +66,4 @@ return Reflect.get(handle, prop, receiver)

return Reflect.get(target, prop, receiver)
}
},
}) as unknown as GlobalState<T>
}

@@ -14,10 +14,28 @@ import { expect, test, describe } from 'bun:test'

test('store.set with callback function', async () => {
const store = globalState(1)
store.set((x) => x + 1)
expect(store.get()).toBe(2)
const add = Array(10).fill(0).map(() => Math.round(Math.random() * 100))
const totalExpected = store.get() + add.reduce((acc, val) => acc + val)
add.forEach(async n => {
store.set(current => current + n)
})
expect(store.get()).toBe(totalExpected)
})
test('store.set() with object', () => {
const store = globalState({
a: 1,
b: 'Test'
b: 'Test',
})
store.set({
a: 4
a: 4,
})

@@ -27,18 +45,81 @@

})
test('store.set() with object preserves other keys', () => {
const store = globalState({
a: 1,
b: 'Test',
c: true,
})
store.set({ a: 99 })
const val = store.get()
expect(val.a).toBe(99)
expect(val.b).toBe('Test')
expect(val.c).toBe(true)
})
test('store.set() with callback on object', () => {
const store = globalState({
count: 0,
name: 'test',
})
store.set((current) => ({ count: current.count + 5 }))
const val = store.get()
expect(val.count).toBe(5)
expect(val.name).toBe('test')
})
})
test('store.reset() with object', () => {
const store = globalState({
a: 1,
b: 'Test'
describe('reset method', () => {
test('store.reset() with object', () => {
const store = globalState({
a: 1,
b: 'Test',
})
store.reset({
a: 4,
b: 'Changed',
})
const newVal = store.get()
expect(newVal.a).toBe(4)
expect(newVal.b).toBe('Changed')
})
store.reset({
a: 4,
b: 'Changed'
test('store.reset() with primitive', () => {
const store = globalState(100)
store.set(50)
expect(store.get()).toBe(50)
store.reset(100)
expect(store.get()).toBe(100)
})
})
const newVal = store.get()
expect(newVal.a).toBe(4)
expect(newVal.b).toBe('Changed')
describe('get method', () => {
test('store.get() with selector', () => {
const store = globalState({
user: { name: 'John', age: 30 },
settings: { theme: 'dark' },
})
const userName = store.get((s) => s.user.name)
const theme = store.get((s) => s.settings.theme)
expect(userName).toBe('John')
expect(theme).toBe('dark')
})
test('store.get() without selector returns full state', () => {
const store = globalState({ a: 1, b: 2 })
const state = store.get()
expect(state).toEqual({ a: 1, b: 2 })
})
})

@@ -63,14 +144,121 @@

test('store.listen()', () => {
const store = globalState(1)
describe('listen method', () => {
test('store.listen() receives current and previous values', () => {
const store = globalState(1)
store.listen((current, prev) => {
expect(current).toBe(4)
expect(prev).toBe(1)
store.listen((current, prev) => {
expect(current).toBe(4)
expect(prev).toBe(1)
})
store.set(4)
expect(store.get()).toBe(4)
})
store.set(4)
test('store.listen() tracks multiple updates', () => {
const store = globalState(0)
const values: number[] = []
expect(store.get()).toBe(4)
store.listen((current) => {
values.push(current)
})
store.set(1)
store.set(2)
store.set(3)
expect(values).toEqual([1, 2, 3])
})
test('store.listen() unsubscribe stops receiving updates', () => {
const store = globalState(0)
const values: number[] = []
const unsubscribe = store.listen((current) => {
values.push(current)
})
store.set(1)
store.set(2)
unsubscribe()
store.set(3)
store.set(4)
expect(values).toEqual([1, 2])
})
})
describe('array methods', () => {
test('mutating array methods update state', () => {
const store = globalState([] as number[])
store.push(10)
store.unshift(100)
const val = store.get()
expect(val[0]).toBe(100)
expect(val[1]).toBe(10)
})
test('non-mutating array methods return correct values', () => {
const store = globalState([1, 2, 3, 4, 5])
const doubled = store.map((v) => v * 2)
const filtered = store.filter((v) => v > 2)
const found = store.find((v) => v === 3)
const index = store.indexOf(4)
expect(doubled).toEqual([2, 4, 6, 8, 10])
expect(filtered).toEqual([3, 4, 5])
expect(found).toBe(3)
expect(index).toBe(3)
})
test('array methods on non-array store throws error', () => {
const store = globalState({ value: 1 })
expect(() => {
// @ts-expect-error - intentionally testing runtime error
store.push(10)
}).toThrow('Cannot call array methods on a non array store')
})
})
describe('edge cases', () => {
test('store with null initial value', () => {
const store = globalState<string | null>(null)
expect(store.get()).toBe(null)
store.set('value')
expect(store.get()).toBe('value')
store.set(null)
expect(store.get()).toBe(null)
})
test('store with undefined initial value', () => {
const store = globalState<number | undefined>(undefined)
expect(store.get()).toBe(undefined)
store.reset(42)
expect(store.get()).toBe(42)
})
test('store with empty object', () => {
const store = globalState<Record<string, number>>({})
store.set({ a: 1 })
expect(store.get()).toEqual({ a: 1 })
store.set({ b: 2 })
expect(store.get()).toEqual({ a: 1, b: 2 })
})
})
})

@@ -6,6 +6,9 @@ import { WritableAtom } from 'nanostores'

export type StateSetterFunction<In, Out = In> = (current: In) => Out
export type StateSetter<TIn, TOut = TIn> = TOut | StateSetterFunction<TIn, TOut>
export type GlobalState<T> = Omit<WritableAtom<T>, 'set' | 'get'> & {
use: <Selected = T>(selector?: StateSelector<T, Selected>) => Selected
set: (newValue: T extends Record<string, any> ? Partial<T> : T) => void
set: (newValue: T extends Record<string, any> ? StateSetter<T, Partial<T>> : StateSetter<T>) => void

@@ -12,0 +15,0 @@ get: <Selected = T>(selector?: StateSelector<T, Selected>) => Selected extends undefined ? T : Selected

import { useStore } from '@nanostores/react'
import { WritableAtom } from 'nanostores'
import { useMemo } from 'react'
import { StateSetter, StateSetterFunction } from './types'
export function stateAssign<T>(newValue: Partial<T>, stateValue: T): T {
function isFunctionSetter<T>(x: any): x is StateSetterFunction<T> {
return typeof x === 'function'
}
function resolveSetter<T>(setter: StateSetter<T>, currentValue:T):T {
if (isFunctionSetter(setter)) {
return setter(currentValue)
}
return setter
}
export function stateAssign<T>(newValue: StateSetter<Partial<T>>, stateValue: T): T {
const resolvedValue = resolveSetter(newValue, stateValue)
if (
typeof stateValue === "object" && stateValue !== null
typeof stateValue === 'object' && stateValue !== null
) {
return {
...stateValue,
...newValue,
...resolvedValue,
} as T
}
return newValue as T
}
return resolvedValue as T
}

@@ -21,26 +35,26 @@

selector: (state: T) => R,
deselector?: (result: R) => Partial<T>
deselector?: (result: R) => Partial<T>,
) => ({
get: () => selector(store.get()),
listen: (listener: (value: R) => void) => {
return store.listen((state) => {
listener(selector(state))
})
},
set(v: R) {
if(!deselector) {
throw new Error('[createStateSelector] deselector must be implemented to call set on state slices')
}
get: () => selector(store.get()),
listen: (listener: (value: R) => void) => {
return store.listen((state) => {
listener(selector(state))
})
},
set(v: R) {
if (!deselector) {
throw new Error('[createStateSelector] deselector must be implemented to call set on state slices')
}
const parsed = deselector(v)
const newValue = stateAssign(parsed, store.get())
const parsed = deselector(v)
store.set(newValue)
}
} as WritableAtom<R>)
const newValue = stateAssign(parsed, store.get())
store.set(newValue)
},
} as WritableAtom<R>)
export function useStateSelector<T, R, S extends WritableAtom<T>>(
store: S,
selector: (state: T) => R
selector: (state: T) => R,
): R {

@@ -47,0 +61,0 @@ const slice = useMemo(() => createStateSlice(store, selector), [selector])

Sorry, the diff of this file is not supported yet