Skip to content

Commit

Permalink
feat(overmind): reworked statemachine API once more
Browse files Browse the repository at this point in the history
  • Loading branch information
christianalfoni committed Sep 29, 2020
1 parent fc0f150 commit 142f20c
Show file tree
Hide file tree
Showing 8 changed files with 1,168 additions and 1,135 deletions.
4 changes: 2 additions & 2 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
"overrides": [
{
"files": ["*.ts", "*.tsx"],
"parser": "typescript-eslint-parser",
"plugins": ["typescript"],
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint/eslint-plugin"],
"rules": {
"import/export": "off",
"no-dupe-class-members": "off",
Expand Down
2,013 changes: 1,112 additions & 901 deletions package-lock.json

Large diffs are not rendered by default.

28 changes: 14 additions & 14 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,22 +85,22 @@
"concurrently": "3.6.1",
"cz-customizable": "^5.2.0",
"cz-customizable-ghooks": "^1.5.0",
"eslint": "^5.8.0",
"eslint-config-prettier": "^3.1.0",
"eslint-config-standard": "^12.0.0",
"eslint-config-standard-jsx": "^6.0.2",
"eslint-plugin-import": "^2.14.0",
"eslint-plugin-node": "^8.0.0",
"eslint-plugin-prettier": "^3.0.0",
"eslint-plugin-promise": "^4.0.1",
"eslint-plugin-react": "^7.11.1",
"eslint-plugin-standard": "^4.0.0",
"eslint-plugin-typescript": "^0.14.0",
"eslint": "^7.10.0",
"eslint-config-prettier": "^6.12.0",
"eslint-config-standard": "^14.1.1",
"eslint-config-standard-jsx": "^8.1.0",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^3.1.4",
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-react": "^7.21.2",
"eslint-plugin-standard": "^4.0.1",
"@typescript-eslint/eslint-plugin": "^4.3.0",
"html-webpack-plugin": "3.2.0",
"husky": "^0.14.3",
"jest": "24.9.0",
"jsdom": "11.12.0",
"lint-staged": "^7.2.0",
"lint-staged": "^10.4.0",
"parcel-bundler": "1.11.0",
"prettier": "1.15.2",
"raw-loader": "0.5.1",
Expand All @@ -114,8 +114,8 @@
"ts-loader": "4.4.2",
"tslib": "1.10.0",
"tslint": "5.12.1",
"typescript": "^3.7.5",
"typescript-eslint-parser": "^21.0.1",
"typescript": "^4.0.2",
"@typescript-eslint/parser": "^4.3.0",
"url-loader": "1.0.1",
"vue": "3.0.0-rc.10",
"webpack": "4.35.0",
Expand Down
11 changes: 2 additions & 9 deletions packages/node_modules/overmind/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ import {
IS_PROXY,
ITrackStateTree,
PATH,
PROXY_TREE,
ProxyStateTree,
TTree,
VALUE,
PROXY_TREE,
} from 'proxy-state-tree'

import { Derived, IS_DERIVED, IS_DERIVED_CONSTRUCTOR } from './derived'
Expand Down Expand Up @@ -192,7 +192,6 @@ export class Overmind<ThisConfig extends IConfiguration>
private mode: DefaultMode | TestMode | SSRMode
private reydrateMutationsForHotReloading: IMutation[] = []
private originalConfiguration
private isStrict = false
initialized: Promise<any>
eventHub: EventEmitter<Events>
devtools: Devtools
Expand All @@ -211,7 +210,6 @@ export class Overmind<ThisConfig extends IConfiguration>
const devEnv = options.devEnv || 'development'

this.delimiter = options.delimiter || '.'
this.isStrict = Boolean(options.strict)

if (
(!process.env.NODE_ENV || process.env.NODE_ENV === devEnv) &&
Expand Down Expand Up @@ -578,9 +576,6 @@ export class Overmind<ThisConfig extends IConfiguration>
})
} else {
const mutationTree = execution.getMutationTree()
if (this.isStrict) {
mutationTree.blockMutations()
}
const returnValue = action(
this.createContext(execution, mutationTree),
value
Expand All @@ -603,9 +598,7 @@ export class Overmind<ThisConfig extends IConfiguration>
this.eventHub.emit(EventType.OPERATOR_START, execution)

const mutationTree = execution.getMutationTree()
if (this.isStrict) {
mutationTree.blockMutations()
}

mutationTree.onMutation((mutation) => {
this.eventHub.emit(EventType.MUTATIONS, {
...execution,
Expand Down
3 changes: 1 addition & 2 deletions packages/node_modules/overmind/src/internalTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
ITrackStateTree,
} from 'proxy-state-tree'

import { IAction, IOperator } from './types'
import { IAction, IOperator } from './types'

export type SubType<Base, Condition> = Pick<
Base,
Expand All @@ -24,7 +24,6 @@ export type Options = {
devtools?: string | boolean
logProxies?: boolean
hotReloading?: boolean
strict?: boolean
}

export type DefaultMode = {
Expand Down
174 changes: 18 additions & 156 deletions packages/node_modules/overmind/src/statemachine.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@ describe('Statemachine', () => {

const overmind = createOvermindMock(config)

expect(overmind.state.current).toBe('FOO')
expect(overmind.state.FOO).toBeDefined()
expect(overmind.state.BAR).toBe(null)
})


test('should transition state', () => {
type States = {
FOO: {},
Expand Down Expand Up @@ -53,7 +55,7 @@ describe('Statemachine', () => {


overmind.actions.transition()
expect(overmind.state.current).toBe('BAR')
expect(overmind.state.BAR).toBeDefined()
})

test('should ignore transition to invalid state', () => {
Expand Down Expand Up @@ -82,7 +84,7 @@ describe('Statemachine', () => {

const overmind = createOvermindMock(config)
overmind.actions.transition()
expect(overmind.state.current).toBe('FOO')
expect(overmind.state.FOO).toBeDefined()
})

test('should run entry and exit transition', async () => {
Expand All @@ -99,9 +101,9 @@ describe('Statemachine', () => {

const transition: Action = async ({ state }) => {
if (state.transition('BAR', {})) {
expect(state.current).toBe('BAR')
expect(state.BAR).toBeDefined()
if (state.transition('FOO', {})) {
expect(state.current).toBe('FOO')
expect(state.FOO).toBeDefined()
}
}
}
Expand All @@ -118,7 +120,7 @@ describe('Statemachine', () => {
const overmind = createOvermindMock(config)

await overmind.actions.transition()
expect(overmind.state.current).toBe('FOO')
expect(overmind.state.FOO).toBeDefined()
})

test('should flush changes to transitions', () => {
Expand Down Expand Up @@ -148,90 +150,11 @@ describe('Statemachine', () => {
interface Action extends IAction<typeof config, void, void> {}

const overmind = createOvermind(config)
overmind.reaction((state) => state.current, (value) => {
expect(value).toBe('BAR')
overmind.reaction((state) => state.BAR, (value) => {
expect(value).toEqual({})
})
overmind.actions.transition()
})

test('should error when mutating async in transitions', async () => {
expect.assertions(1)

type States = {
FOO: {},
BAR: {}
}

const state = statemachine<States>({
FOO: ['BAR'],
BAR: ['FOO']
}).create('FOO', {})

const transition: Action = async ({ state }) => {
if (state.transition('BAR', {})) {
await Promise.resolve()
expect(state[PROXY_TREE].master.mutationTree.isBlocking).toBe(true)
}
}

const config = {
state,
actions: {
transition
}
}

interface Action extends IAction<typeof config, void, Promise<void>> {}

const overmind = createOvermind(config)

return overmind.actions.transition()
})

test('should only enable mutations with matches', async () => {
expect.assertions(4)

type States = {
FOO: {},
BAR: {}
}

const state = statemachine<States>({
FOO: ['BAR'],
BAR: ['FOO']
}).create('FOO', {})

const transition: Action = async ({ state }) => {
if (state.transition('BAR', {})) {
await Promise.resolve()
expect(state[PROXY_TREE].master.mutationTree.isBlocking).toBe(true)
if (state.matches('BAR')) {
expect(state[PROXY_TREE].master.mutationTree.isBlocking).toBe(false)
await Promise.resolve()
.then(() => {
expect(state[PROXY_TREE].master.mutationTree.isBlocking).toBe(true)
})
if (state.transition('FOO', {})) {
expect(state[PROXY_TREE].master.mutationTree.isBlocking).toBe(false)
}
}
}
}


const config = {
state,
actions: {
transition
}
}

interface Action extends IAction<typeof config, void, Promise<void>> {}

const overmind = createOvermind(config)

return overmind.actions.transition()
})

test('should make copy of statemachine during tests', () => {

Expand Down Expand Up @@ -270,12 +193,13 @@ describe('Statemachine', () => {

// @ts-ignore
overmind.actions.changeFoo()
expect(overmind.state.FOO.obj.foo).toBe('bar2')

expect(overmind.state.FOO?.obj.foo).toBe('bar2')


const overmind2 = createOvermindMock(config)

expect(overmind2.state.FOO.obj.foo).toBe('bar')
expect(overmind2.state.FOO?.obj.foo).toBe('bar')
})

test('should have base state', () => {
Expand Down Expand Up @@ -349,11 +273,11 @@ describe('Statemachine', () => {
if (state.transition('BAR', {
bar: 123
})) {
expect(state.BAR.bar).toBe(123)
expect(state.BAR?.bar).toBe(123)
await Promise.resolve()
if (state.transition('FOO', { foo: '123'})) {
expect(state.BAR).toBe(null)
expect(state.FOO.foo).toBe('123')
expect(state.FOO?.foo).toBe('123')
await Promise.resolve()
}
}
Expand All @@ -372,68 +296,6 @@ describe('Statemachine', () => {

overmind.actions.transition()
})

test('should not allow mutations in strict mode', () => {
type States = {
FOO: {},
BAR: {}
}

const state = statemachine<States>({
FOO: ['BAR'],
BAR: ['FOO']
}).create('FOO', {})
const transition: Action = ({ state }) => {
state.current = 'BAR'
}

const config = {
state,
actions: {
transition
}
}

interface Action extends IAction<typeof config, void, void> {}

const overmind = createOvermindMock(config)
// @ts-ignore
overmind.isStrict = true


expect(() => overmind.actions.transition()).toThrow()
})

test('should allow mutations using transition', () => {
type States = {
FOO: {}
BAR: {}
}

const state = statemachine<States>({
FOO: ['BAR'],
BAR: ['FOO']
}).create('FOO', {})
const transition: Action = ({ state }) => {
state.transition('BAR', {})
}

const config = {
state,
actions: {
transition
}
}

interface Action extends IAction<typeof config, void, void> {}

const overmind = createOvermindMock(config)
// @ts-ignore
overmind.isStrict = true


expect(() => overmind.actions.transition()).not.toThrow()
})

test('should dispose nested and base machines', async () => {
expect.assertions(3)
Expand Down Expand Up @@ -470,15 +332,15 @@ describe('Statemachine', () => {
})

const transition: Action = ({ state }) => {
if (state.matches('FOO')) {
if (state.FOO) {
const ref = state.FOO
if (state.transition('BAR', {})) {
expect(state.FOO).toBe(null)
ref.transition('BAR', {})
ref.base.transition('BAR', {})

expect(ref.current).toBe('FOO')
expect(ref.base.current).toBe('FOO')
expect(ref.FOO).toBeDefined()
expect(ref.base.FOO).toBeDefined()
}
}
}
Expand Down
Loading

0 comments on commit 142f20c

Please sign in to comment.