Skip to content

Commit 241fdb3

Browse files
Merge pull request cerebral#388 from mfeitoza/master
Svelte plugin
2 parents 6d79e42 + 9948eef commit 241fdb3

File tree

11 files changed

+295
-0
lines changed

11 files changed

+295
-0
lines changed

.cz-config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ module.exports = {
3737
{ name: 'overmind-graphql' },
3838
{ name: 'overmind-statechart' },
3939
{ name: 'overmind-react' },
40+
{ name: 'overmind-svelte' },
4041
{ name: 'overmind-vue' },
4142
{ name: 'overmind-angular' },
4243
{ name: 'action-chain' },

package-lock.json

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
"react-icons": "^3.5.0",
5858
"react-split-pane": "0.1.87",
5959
"styled-components": "3.3.3",
60+
"svelte": "^3.20.1",
6061
"tslib": "1.10.0",
6162
"vscode": "^1.1.36",
6263
"vue": "2.6.10",
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
src
2+
jest.config.js
3+
tsconfig.json
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# overmind-vue
2+
3+
[https://overmindjs.org](https://overmindjs.org)
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
module.exports = {
2+
collectCoverage: true,
3+
collectCoverageFrom: ['src/**/*.{t,j}s?(x)', '!src/**/*.d.ts'],
4+
moduleFileExtensions: ['ts', 'js', 'svelte'],
5+
transform: {
6+
'^.+\\.tsx?$': 'ts-jest',
7+
'^.+\\.svelte$': 'svelte-jester'
8+
},
9+
testRegex: '\\.test\\.ts?$',
10+
testPathIgnorePatterns: [
11+
'/dist/',
12+
'/es/',
13+
'/lib/',
14+
'<rootDir>/node_modules/',
15+
],
16+
transformIgnorePatterns: ['<rootDir>/node_modules/'],
17+
coveragePathIgnorePatterns: ['<rootDir>/node_modules/'],
18+
haste: {
19+
// This option is needed or else globbing ignores <rootDir>/node_modules.
20+
providesModuleNodeModules: ['overmind-svelte'],
21+
},
22+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
{
2+
"name": "overmind-svelte",
3+
"version": "1.0.0-alpha1",
4+
"description": "Functional actions",
5+
"author": "Marcus Feitoza <[email protected]>",
6+
"license": "MIT",
7+
"repository": "git+https://github.com/cerebral/overmind.git",
8+
"main": "lib/index.js",
9+
"module": "es/index.js",
10+
"types": "lib/index.d.ts",
11+
"scripts": {
12+
"build": "npm run build:lib & npm run build:es",
13+
"build:lib": "tsc --outDir lib --module commonjs",
14+
"build:es": "tsc --outDir es --module es2015",
15+
"clean": "rimraf es lib coverage",
16+
"typecheck": "tsc --noEmit",
17+
"test": "jest --runInBand",
18+
"test:watch": "jest --watch --updateSnapshot --coverage false",
19+
"prebuild": "npm run clean",
20+
"postbuild": "rimraf {lib,es}/**/__tests__",
21+
"posttest": "npm run typecheck"
22+
},
23+
"keywords": [
24+
"state",
25+
"sideeffects",
26+
"app",
27+
"framework"
28+
],
29+
"files": [
30+
"lib",
31+
"es",
32+
"react"
33+
],
34+
"dependencies": {
35+
"overmind": "next",
36+
"svelte": "^3.20.1"
37+
},
38+
"devDependencies": {
39+
"@testing-library/jest-dom": "^5.3.0",
40+
"@testing-library/svelte": "^3.0.0",
41+
"@types/node": "^12.11.6",
42+
"svelte-jester": "^1.0.5",
43+
"tslib": "^1.10.0"
44+
},
45+
"setupFilesAfterEnv": [
46+
"@testing-library/jest-dom/extend-expect"
47+
]
48+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<script>
2+
3+
export let store
4+
5+
const state = store.state
6+
7+
$: count = $state.count
8+
let doubled = undefined
9+
store.reaction(
10+
(state) => state.count,
11+
(value) => {
12+
doubled = value * 2
13+
},
14+
{
15+
immediate: true
16+
}
17+
)
18+
19+
</script>
20+
21+
<p>Count: {count}</p>
22+
<p>Doubled: {doubled}</p>
23+
<button id="increase" on:click={() => store.actions.increase()}>Increase</button>
24+
<button id="decrease" on:click={() => store.actions.decrease()}>Increase</button>
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
2+
import '@testing-library/jest-dom/extend-expect'
3+
import { render, fireEvent } from '@testing-library/svelte'
4+
5+
import { Overmind } from 'overmind'
6+
7+
import { createMixin } from './'
8+
import CountTest from './CountTest.svelte'
9+
10+
11+
const app = {
12+
state: {
13+
count: 0
14+
},
15+
actions: {
16+
increase({ state }) {
17+
state.count++;
18+
},
19+
decrease({ state }) {
20+
state.count--;
21+
}
22+
}
23+
}
24+
25+
describe('Svelte', () => {
26+
test('should create mixin', () => {
27+
const overmind = new Overmind(app)
28+
const mixin = createMixin(overmind)
29+
30+
expect('state' in mixin)
31+
})
32+
33+
test('should expose subscribe', () => {
34+
const overmind = new Overmind(app)
35+
const mixin = createMixin(overmind)
36+
37+
expect(typeof mixin.state.subscribe === 'function')
38+
})
39+
40+
test('should display current state', () => {
41+
const overmind = new Overmind(app)
42+
const mixin = createMixin(overmind)
43+
44+
const { getByText, getAllByRole } = render(CountTest, { store: mixin })
45+
expect(getByText('Count: 0')).toBeInTheDocument()
46+
})
47+
48+
test('should update state by button click', async () => {
49+
const overmind = new Overmind(app)
50+
const mixin = createMixin(overmind)
51+
52+
const { getAllByRole } = render(CountTest, { store: mixin })
53+
const [increaseBtn, ] = getAllByRole('button')
54+
55+
await fireEvent.click(increaseBtn)
56+
await fireEvent.click(increaseBtn)
57+
58+
expect(mixin.state.count === 2)
59+
})
60+
61+
test('should update view on state change', async () => {
62+
const overmind = new Overmind(app)
63+
const mixin = createMixin(overmind)
64+
65+
const { getByText, getAllByRole } = render(CountTest, { store: mixin })
66+
const [increaseBtn, decreaseBtn] = getAllByRole('button')
67+
68+
await fireEvent.click(increaseBtn)
69+
70+
expect(getByText('Count: 1')).toBeInTheDocument()
71+
})
72+
73+
test('should update view on reaction', async () => {
74+
const overmind = new Overmind(app)
75+
const mixin = createMixin(overmind)
76+
77+
const { getByText, getAllByRole } = render(CountTest, { store: mixin })
78+
const [increaseBtn, ] = getAllByRole('button')
79+
80+
expect(getByText('Doubled: 0')).toBeInTheDocument()
81+
82+
await fireEvent.click(increaseBtn)
83+
await fireEvent.click(increaseBtn)
84+
85+
expect(getByText('Doubled: 4')).toBeInTheDocument()
86+
})
87+
})
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import { EventType } from 'overmind'
2+
import { onMount, afterUpdate, onDestroy } from 'svelte'
3+
4+
const IS_PRODUCTION = process.env.NODE_ENV === 'production'
5+
6+
let nextComponentId = 0
7+
8+
export function createMixin (overmind) {
9+
const componentId = nextComponentId++
10+
let nextComponentInstanceId = 0
11+
let currentFlushId = 0
12+
13+
const subscribe = listener => {
14+
const tree = overmind.proxyStateTree.getTrackStateTree()
15+
const componentInstanceId = nextComponentInstanceId++
16+
let isUpdating = false
17+
18+
const onUpdate = (mutations, paths, flushId) => {
19+
tree.track(onUpdate)
20+
currentFlushId = flushId
21+
isUpdating = true
22+
listener(tree.state)
23+
}
24+
25+
tree.track(onUpdate)
26+
27+
listener(tree.state)
28+
29+
if (IS_PRODUCTION) {
30+
afterUpdate(() => {
31+
tree.stopTracking()
32+
isUpdating = false
33+
})
34+
} else {
35+
onMount(() => {
36+
overmind.eventHub.emitAsync(EventType.COMPONENT_ADD, {
37+
componentId,
38+
componentInstanceId,
39+
name: '',
40+
paths: Array.from(tree.pathDependencies)
41+
})
42+
})
43+
44+
afterUpdate(() => {
45+
tree.stopTracking()
46+
if (isUpdating) {
47+
overmind.eventHub.emitAsync(EventType.COMPONENT_UPDATE, {
48+
componentId,
49+
componentInstanceId,
50+
name: '',
51+
flushId: currentFlushId,
52+
paths: Array.from(tree.pathDependencies)
53+
})
54+
}
55+
isUpdating = false
56+
})
57+
}
58+
59+
return () => {
60+
overmind.proxyStateTree.disposeTree(tree)
61+
overmind.eventHub.emitAsync(EventType.COMPONENT_REMOVE, {
62+
componentId,
63+
componentInstanceId: componentInstanceId,
64+
name: ''
65+
})
66+
}
67+
}
68+
69+
const reaction = (...args) => {
70+
const dispose = overmind.reaction(...args)
71+
72+
onDestroy(() => {
73+
dispose()
74+
})
75+
}
76+
77+
return {
78+
state: { ...overmind.state, subscribe},
79+
actions: overmind.actions,
80+
effects: overmind.effects,
81+
addMutationListener: overmind.addMutationListener,
82+
reaction: reaction
83+
}
84+
}

0 commit comments

Comments
 (0)