Skip to content

Commit 7c57dba

Browse files
committed
Swap argument order in reduce
Closes #33
1 parent 64b142a commit 7c57dba

14 files changed

+73
-44
lines changed

demos/counter.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ import { state, transition, createMachine, guard, interpret, reduce } from './ma
33
const machine = createMachine({
44
idle: state(
55
transition('inc', 'idle',
6-
reduce((e, {count}) => ({ count: count + 1 })),
6+
reduce(({count}) => ({ count: count + 1 })),
77
guard(({count}) => count < 10)
88
),
99
transition('dec', 'idle',
10-
reduce((e, {count}) => ({ count: count - 1 })),
10+
reduce(({count}) => ({ count: count - 1 })),
1111
guard(({count}) => count > 0)
1212
)
1313
)

demos/fullname.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { guard, state, transition, createMachine, interpret, reduce } from './machine.js';
22

3-
const setFirst = (ev, ctx) => ({ ...ctx, first: ev.target.value });
4-
const setLast = (ev, ctx) => ({ ...ctx, last: ev.target.value });
3+
const setFirst = (ctx, ev) => ({ ...ctx, first: ev.target.value });
4+
const setLast = (ctx, ev) => ({ ...ctx, last: ev.target.value });
55
const nothingEntered = ({ first, last }) => !first && !last;
66
const somethingEntered = (ctx) => !nothingEntered(ctx);
77

demos/login.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ function canSubmit(ctx) {
99
return !!(ctx.login && ctx.password);
1010
}
1111

12-
function updateSubmissionError(ev, ctx) {
12+
function updateSubmissionError(ctx) {
1313
return {
1414
...ctx,
1515
error: 'Missing fields'
@@ -20,18 +20,18 @@ function hasError(ctx) {
2020
return !!ctx.error;
2121
}
2222

23-
function clearError(ev, ctx) {
23+
function clearError(ctx) {
2424
return { ...ctx, error: '' };
2525
}
2626

27-
function setLogin({ event }, ctx) {
27+
function setLogin(ctx, { event }) {
2828
return {
2929
...ctx,
3030
login: event.target.value
3131
};
3232
}
3333

34-
function setPassword({ event }, ctx) {
34+
function setPassword(ctx, { event }) {
3535
return {
3636
...ctx,
3737
password: event.target.value

demos/users.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const machine = createMachine({
2121
),
2222
loading: invoke(loadUsers,
2323
transition('done', 'loaded',
24-
reduce((ev, ctx) => ({ ...ctx, users: ev.data }))
24+
reduce((ctx, ev) => ({ ...ctx, users: ev.data }))
2525
)
2626
),
2727
loaded: state()

docs/api/invoke.md

+5-5
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,10 @@ const machine = createMachine({
3030
),
3131
loading: invoke(loadUsers,
3232
transition('done', 'idle',
33-
reduce((ev, ctx) => ({ ...ctx, user: ev.data }))
33+
reduce((ctx, ev) => ({ ...ctx, user: ev.data }))
3434
),
3535
transition('error', 'error',
36-
reduce((ev, ctx) => ({ ...ctx, error: ev.error }))
36+
reduce((ctx, ev) => ({ ...ctx, error: ev.error }))
3737
)
3838
),
3939
error: state()
@@ -80,7 +80,7 @@ const inputMachine = createMachine({
8080
const wizardMachine = createMachine({
8181
step1: invoke(inputMachine,
8282
transition('done', 'step2',
83-
reduce((ev, ctx) => ({ ...ctx, childContext: ev.data }))
83+
reduce((ctx, ev) => ({ ...ctx, childContext: ev.data }))
8484
)
8585
),
8686
step2: state() // Machine another machine here?
@@ -126,7 +126,7 @@ import { createMachine, invoke, reduce, state, transition } from 'robot3';
126126
const machine = createMachine({
127127
start: invoke(loadTodos,
128128
transition('done', 'loaded',
129-
reduce((ev, ctx) => ({ ...ctx, todo: ev.data }))
129+
reduce((ctx, ev) => ({ ...ctx, todo: ev.data }))
130130
)
131131
),
132132
loaded: state()
@@ -156,7 +156,7 @@ const loadTodos = () => Promise.reject("Sorry but you can't do that");
156156
const machine = createMachine({
157157
start: invoke(loadTodos,
158158
transition('error', 'error',
159-
reduce((ev, ctx) => ({ ...ctx, error: ev.error }))
159+
reduce((ctx, ev) => ({ ...ctx, error: ev.error }))
160160
)
161161
),
162162
error: state()

docs/api/reduce.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ import { createMachine, reduce, state, transition } from 'robot3';
1717
const machine = createMachine({
1818
idle: state(
1919
transition('login', 'idle',
20-
reduce((ev, ctx) => ({ ...ctx, login: ev.target.value }))
20+
reduce((ctx, ev) => ({ ...ctx, login: ev.target.value }))
2121
),
2222
transition('password', 'idle',
23-
reduce((ev, ctx) => ({ ...ctx, password: ev.target.value }))
23+
reduce((ctx, ev) => ({ ...ctx, password: ev.target.value }))
2424
),
2525
transition('submit', 'complete')
2626
),

docs/api/state.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ const machine = createMachine({
2222

2323
input: state(
2424
immediate('idle',
25-
reduce((ev, ctx) => ({ ...ctx, first: ev.target.value }))
25+
reduce((ctx, ev) => ({ ...ctx, first: ev.target.value }))
2626
)
2727
)
2828
});

docs/api/transition.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ const machine = createMachine({
3838
)
3939
loading: invoke(loadUsers,
4040
transition('done', 'show',
41-
reduce((ev, ctx) => ({ ...ctx, users: ev.data })))
41+
reduce((ctx, ev) => ({ ...ctx, users: ev.data })))
4242
)
4343
}, () => ({ users: [] }));
4444
```

docs/guides/comparison-with-xstate.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ import { createMachine, reduce, state, transition } from 'robot3';
9999
const machine = createMachine({
100100
idle: state(
101101
transition('inc', 'idle',
102-
reduce((ev, ctx) => ({ ...ctx, count: ctx.count + 1 }))
102+
reduce(ctx => ({ ...ctx, count: ctx.count + 1 }))
103103
)
104104
)
105105
});

docs/guides/composition.md

+5-5
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ import { createMachine, state, reduce, transition } from 'robot3';
1515
const machine = createMachine(
1616
form: state(
1717
transition('first', 'form',
18-
reduce((ev, ctx) => ({ ...ctx, first: ev.event.target.value }))
18+
reduce((ctx, ev) => ({ ...ctx, first: ev.event.target.value }))
1919
),
2020
transition('last', 'form',
21-
reduce((ev, ctx) => ({ ...ctx, first: ev.event.target.value }))
21+
reduce((ctx, ev) => ({ ...ctx, first: ev.event.target.value }))
2222
)
2323
)
2424
);
@@ -37,7 +37,7 @@ import { createMachine, state, reduce, transition } from 'robot3';
3737

3838
const field = (prop, state) => (
3939
transition(prop, state,
40-
reduce((ev, ctx) => ({ ...ctx, [prop]: ev.event.target.value }))
40+
reduce((ctx, ev) => ({ ...ctx, [prop]: ev.event.target.value }))
4141
)
4242
);
4343

@@ -58,7 +58,7 @@ __transitions.js__
5858
```js
5959
export const field = (prop, state) => (
6060
transition(prop, state,
61-
reduce((ev, ctx) => ({ ...ctx, [prop]: ev.event.target.value }))
61+
reduce((ctx, ev) => ({ ...ctx, [prop]: ev.event.target.value }))
6262
)
6363
);
6464

@@ -84,7 +84,7 @@ You might find that you need a *slight* modification to how one of the transitio
8484
```js
8585
export const field = (prop, state, ...args) => (
8686
transition(prop, state,
87-
reduce((ev, ctx) => ({ ...ctx, [prop]: ev.event.target.value })),
87+
reduce((ctx, ev) => ({ ...ctx, [prop]: ev.event.target.value })),
8888
...args
8989
)
9090
);

docs/index.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ const machine = createMachine({
9494
),
9595
loading: invoke(loadUsers,
9696
transition('done', 'loaded',
97-
reduce((ev, ctx) => ({ ...ctx, users: ev.data }))
97+
reduce((ctx, ev) => ({ ...ctx, users: ev.data }))
9898
)
9999
),
100100
loaded: state()
@@ -199,20 +199,20 @@ const machine = createMachine({
199199
preview: state(
200200
transition('edit', 'editMode'
201201
// Save the current title as oldTitle so we can reset later.
202-
reduce((ev, ctx) => ({ ...ctx, oldTitle: ctx.title }))
202+
reduce(ctx => ({ ...ctx, oldTitle: ctx.title }))
203203
)
204204
),
205205
editMode: state(
206206
transition('input', 'editMode'
207-
reduce((ev, ctx) => ({ ...ctx, title: ev.target.value }))
207+
reduce((ctx, ev) => ({ ...ctx, title: ev.target.value }))
208208
),
209209
transition('cancel', 'cancel'),
210210
transition('save', 'validate')
211211
),
212212
cancel: state(
213213
immediate('preview',
214214
// Reset the title back to oldTitle
215-
reduce((ev, ctx) => ({ ...ctx, title: ctx.oldTitle })
215+
reduce(ctx => ({ ...ctx, title: ctx.oldTitle })
216216
)
217217
),
218218
validate: state(

machine.js

+8-11
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,8 @@ export let d = {};
1010
let truthy = () => true;
1111
let empty = () => ({});
1212
let identity = a => a;
13-
let identity2 = (a, b) => b;
1413
let callBoth = (par, fn, self, args) => par.apply(self, args) && fn.apply(self, args);
15-
let callForward = (par, fn, self, [a, b]) => fn.call(self, a, par.call(self, a, b));
14+
let callForward = (par, fn, self, [a, b]) => fn.call(self, par.call(self, a, b), b);
1615
let create = (a, b) => Object.freeze(Object.create(a, b));
1716

1817
function stack(fns, def, caller) {
@@ -27,9 +26,6 @@ function fnType(fn) {
2726
return create(this, { fn: valueEnumerable(fn) });
2827
}
2928

30-
let actionType = {};
31-
export let action = fnType.bind(actionType);
32-
3329
let reduceType = {};
3430
export let reduce = fnType.bind(reduceType);
3531

@@ -42,7 +38,7 @@ function filter(Type, arr) {
4238

4339
function extractActions(args) {
4440
let guards = stack(filter(guardType, args).map(t => t.fn), truthy, callBoth);
45-
let reducers = stack(filter(reduceType, args).map(t => t.fn), identity2, callForward);
41+
let reducers = stack(filter(reduceType, args).map(t => t.fn), identity, callForward);
4642
return [guards, reducers];
4743
}
4844

@@ -105,7 +101,7 @@ let invokeType = {
105101
};
106102
function machineToPromise(machine) {
107103
return function() {
108-
return new Promise((resolve, reject) => {
104+
return new Promise(resolve => {
109105
this.child = interpret(machine, s => {
110106
this.onChange(s);
111107
if(s.machine.state.value.final) {
@@ -130,11 +126,11 @@ let machine = {
130126
};
131127
}
132128
};
133-
export function createMachine(states, contextFn) {
129+
export function createMachine(states, contextFn = empty) {
134130
if(d._create) d._create(states);
135131
let current = Object.keys(states)[0];
136132
return create(machine, {
137-
context: valueEnumerable(contextFn || empty),
133+
context: valueEnumerable(contextFn),
138134
current: valueEnumerable(current),
139135
states: valueEnumerable(states)
140136
});
@@ -144,7 +140,7 @@ function transitionTo(service, fromEvent, candidates) {
144140
let { machine, context } = service;
145141
for(let { to, guards, reducers } of candidates) {
146142
if(guards(context)) {
147-
service.context = reducers.call(service, fromEvent, context);
143+
service.context = reducers.call(service, context, fromEvent);
148144

149145
let original = machine.original || machine;
150146
let newMachine = create(original, {
@@ -177,6 +173,7 @@ let service = {
177173
this.onChange(this);
178174
}
179175
};
176+
180177
export function interpret(machine, onChange) {
181178
let s = Object.create(service, {
182179
machine: valueEnumerableWritable(machine),
@@ -186,4 +183,4 @@ export function interpret(machine, onChange) {
186183
s.send = s.send.bind(s);
187184
s.machine = s.machine.state.value.enter(s.machine, s, {});
188185
return s;
189-
}
186+
}

test/test-invoke.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ QUnit.module('Invoke', hooks => {
88
one: state(transition('click', 'two')),
99
two: invoke(() => Promise.resolve(13),
1010
transition('done', 'three',
11-
reduce((ev, ctx) => ({ ...ctx, age: ev.data }))
11+
reduce((ctx, ev) => ({ ...ctx, age: ev.data }))
1212
)
1313
),
1414
three: state()
@@ -26,7 +26,7 @@ QUnit.module('Invoke', hooks => {
2626
one: state(transition('click', 'two')),
2727
two: invoke(() => Promise.reject(new Error('oh no')),
2828
transition('error', 'three',
29-
reduce((ev, ctx) => ({ ...ctx, error: ev.error }))
29+
reduce((ctx, ev) => ({ ...ctx, error: ev.error }))
3030
)
3131
),
3232
three: state()
@@ -41,7 +41,7 @@ QUnit.module('Invoke', hooks => {
4141
QUnit.test('The initial state can be an invoke', async assert => {
4242
let machine = createMachine({
4343
one: invoke(() => Promise.resolve(2),
44-
transition('done', 'two', reduce((ev, ctx) => ({...ctx, age: ev.data})))
44+
transition('done', 'two', reduce((ctx, ev) => ({...ctx, age: ev.data})))
4545
),
4646
two: state()
4747
}, () => ({ age: 0 }));

test/test-reduce.js

+34-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ QUnit.module('Reduce', () => {
55
let machine = createMachine({
66
one: state(
77
transition('ping', 'two',
8-
reduce((ev, ctx) => ({ ...ctx, one: 1 })),
9-
reduce((ev, ctx) => ({ ...ctx, two: 2 }))
8+
reduce((ctx) => ({ ...ctx, one: 1 })),
9+
reduce((ctx) => ({ ...ctx, two: 2 }))
1010
)
1111
),
1212
two: state()
@@ -18,4 +18,36 @@ QUnit.module('Reduce', () => {
1818
assert.equal(one, 1, 'first reducer ran');
1919
assert.equal(two, 2, 'second reducer ran');
2020
});
21+
22+
QUnit.test('If no reducers, the context remains', assert => {
23+
let machine = createMachine({
24+
one: state(
25+
transition('go', 'two')
26+
),
27+
two: state()
28+
}, () => ({ one: 1, two: 2 }));
29+
30+
let service = interpret(machine, () => {});
31+
service.send('go');
32+
assert.deepEqual(service.context, { one: 1, two: 2 }, 'context remains');
33+
});
34+
35+
QUnit.test('Event is the second argument', assert => {
36+
assert.expect(2);
37+
38+
let machine = createMachine({
39+
one: state(
40+
transition('go', 'two',
41+
reduce(function(ctx, ev) {
42+
assert.equal(ev, 'go');
43+
return { ...ctx, worked: true };
44+
})
45+
)
46+
),
47+
two: state()
48+
});
49+
let service = interpret(machine, () => {});
50+
service.send('go');
51+
assert.equal(service.context.worked, true, 'changed the context');
52+
});
2153
});

0 commit comments

Comments
 (0)