Skip to content

Commit

Permalink
rename api to state/computed/effect
Browse files Browse the repository at this point in the history
  • Loading branch information
e7h4n committed Nov 22, 2024
1 parent de6d729 commit 285f7a2
Show file tree
Hide file tree
Showing 11 changed files with 155 additions and 56 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
steps:
- uses: actions/checkout@v4

- uses: pnpm/action-setup@v4
- uses: pnpm/effect-setup@v4
with:
version: 9
run_install: |
Expand All @@ -28,10 +28,10 @@ jobs:
run: pnpm coverage

- name: "Report Coverage"
uses: davelosert/vitest-coverage-report-action@v2
uses: davelosert/vitest-coverage-report-effect@v2

- name: Coveralls
uses: coverallsapp/github-action@v2
uses: coverallsapp/github-effect@v2
with:
file: coverage/cobertura-coverage.xml
format: cobertura
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
id-token: write
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: pnpm/effect-setup@v4
with:
version: 9
run_install: |
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
LIABILITY, WHETHER IN AN EFFECT OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
24 changes: 12 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,43 +10,43 @@

## Core Concepts

### Atom
### State

Atom are the basic stateful units in Rippling. The can be thought of as a simple key-value store.
State are the basic stateful units in Rippling. The can be thought of as a simple key-value store.

For Example:

```typescript
const store = createStore();
const count = atom(0);
const count = state(0);
store.set(count, 1);
console.log(store.get(count)); // 1
```

### Compute
### Computed

Compute are the basic compute units in Rippling. The can read other Atom / Compute / Action.
Computed are the basic compute units in Rippling. The can read other State / Computed / Effect.

For Example:

```typescript
const store = createStore();
const count = atom(0);
const doubleCount = compute((get) => get(count) * 2);
const count = state(0);
const doubleCount = computed((get) => get(count) * 2);
console.log(store.get(doubleCount)); // 0
```

### Action
### Effect

Action are the basic command units in Rippling. The can read other Atom / Compute / Action and write to Atom / Action.
Effect are the basic command units in Rippling. The can read other State / Computed / Effect and write to State / Effect.

For Example:

```typescript
const store = createStore();
const count = atom(0);
const doubleCount = atom(0);
const updateCount = action((get, set, value) => {
const count = state(0);
const doubleCount = state(0);
const updateCount = effect((get, set, value) => {
set(count, value);
set(doubleCount, get(count) * 2);
});
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"@vitest/coverage-v8": "^2.1.1",
"eslint": "^9.10.0",
"eslint-plugin-vitest": "^0.5.4",
"jest-leak-detector": "^29.7.0",
"rollup": "^4.22.0",
"rollup-plugin-dts": "^6.1.1",
"typescript": "^5.6.2",
Expand Down
45 changes: 45 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

53 changes: 53 additions & 0 deletions src/__tests__/memory.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import LeakDetector from 'jest-leak-detector'
import { expect, it } from 'vitest'
import { state, State, Computed, computed, createStore } from '..'


it('should release memory after delete state', async () => {
const store = createStore()
let base: State<object> | undefined = state({})

const detector = new LeakDetector(store.get(base))
base = undefined

expect(await detector.isLeaking()).toBe(false)
})

it('should release memory after base state & derived computed is deleted', async () => {
const store = createStore()
let base: State<object> | undefined = state({})
let derived: Computed<object> | undefined = computed((get) => ({
obj: base && get(base),
}))
const detector1 = new LeakDetector(store.get(base))
const detector2 = new LeakDetector(store.get(derived))

base = undefined
derived = undefined

expect(await detector1.isLeaking()).toBe(false)
expect(await detector2.isLeaking()).toBe(false)
})

it('with a long-lived base state', async () => {
const store = createStore()
const objAtom = state({})

let cmpt: Computed<object> | undefined = computed((get) => ({
obj: get(objAtom),
}))

const detector = new LeakDetector(store.get(cmpt))
cmpt = undefined
expect(await detector.isLeaking()).toBe(false)
})

it.skip('should not hold onto dependent atoms that are not mounted', async () => {
const store = createStore()
const objAtom = state({})
let depAtom: Computed<unknown> | undefined = computed((get) => get(objAtom))
const detector = new LeakDetector(depAtom)
store.get(depAtom)
depAtom = undefined
await expect(detector.isLeaking()).resolves.toBe(false)
})
38 changes: 19 additions & 19 deletions src/__tests__/rippling.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { expect, test, vi } from 'vitest';
import { atom, createStore, Atom, compute, Compute, action } from '../';
import { state, createStore, State, computed, Computed, effect } from '../';

test('should work', () => {
const store = createStore();
const anAtom = atom(1);
const anAtom = state(1);

expect(store.get(anAtom)).toBe(1);

Expand All @@ -14,44 +14,44 @@ test('should work', () => {
expect(store2.get(anAtom)).toBe(1);
});

test('compute atom should work', () => {
test('computed state should work', () => {
const store = createStore();
const anAtom = atom(1);
const computedAtom = compute((get) => {
const anAtom = state(1);
const computedAtom = computed((get) => {
const num = get(anAtom);
return num * 2
});

expect(store.get(computedAtom)).toBe(2);
})

test('compute atom should net set', () => {
test('computed state should net set', () => {
const store = createStore()
const anAtom = atom(1)
const doubleCmpt = compute((get) => {
const anAtom = state(1)
const doubleCmpt = computed((get) => {
return get(anAtom) * 2
})

store.set(doubleCmpt as unknown as Atom<number>, 3)
store.set(doubleCmpt as unknown as State<number>, 3)
expect(store.get(doubleCmpt)).toBe(2)
})

test('async atom should works like sync atom', async () => {
test('async state should works like sync state', async () => {
const store = createStore()
const anAtom = atom(1)
const asyncCmpt: Compute<Promise<number>> = compute(async (get) => {
const anAtom = state(1)
const asyncCmpt: Computed<Promise<number>> = computed(async (get) => {
await Promise.resolve()
return get(anAtom) * 2
})

expect(await store.get(asyncCmpt)).toBe(2)
})

test('action can set other atom', () => {
test('effect can set other state', () => {
const store = createStore()
const anAtom = atom(1)
const doubleAtom = atom(0)
const doubleAction = action((get, set, num) => {
const anAtom = state(1)
const doubleAtom = state(0)
const doubleAction = effect((get, set, num) => {
set(anAtom, num)
set(doubleAtom, get(anAtom) * 2)
})
Expand All @@ -60,16 +60,16 @@ test('action can set other atom', () => {
expect(store.get(doubleAtom)).toBe(4)
})

test('read & write action as an action', async () => {
test('read & write effect as an effect', async () => {
const store = createStore()
const trace = vi.fn()
const actionAction = action(async () => {
const actionAction = effect(async () => {
await Promise.resolve()
trace()
return 2;
})

expect(() => store.get(actionAction)).toThrow('Action is not inited')
expect(() => store.get(actionAction)).toThrow('Effect is not inited')

void store.set(actionAction)
expect(trace).not.toHaveBeenCalled()
Expand Down
4 changes: 2 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export { atom, compute, action, createStore } from './rippling'
export type { Atom, Compute, Action, Store } from './typing'
export { state, computed, effect, createStore } from './rippling'
export type { State, Computed, Effect, Store } from './typing'
Loading

0 comments on commit 285f7a2

Please sign in to comment.