Skip to content

Commit cf6a34b

Browse files
committed
Merge branch 'release/1.5.3'
2 parents 22cab37 + cd7620b commit cf6a34b

12 files changed

Lines changed: 372 additions & 101 deletions

File tree

CHANGELOG.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,22 @@
11
# Changelog
22

3+
## v1.5.2 (14/12/2020)
4+
*No changelog for this release.*
5+
6+
---
7+
8+
## v1.5.1 (14/12/2020)
9+
10+
#### closed
11+
12+
- [**closed**] fix mapObject, create new object for every call [#51](https://github.com/vankeisb/react-tea-cup/pull/51)
13+
14+
#### dependencies
15+
16+
- [**dependencies**] Bump ini from 1.3.5 to 1.3.8 [#52](https://github.com/vankeisb/react-tea-cup/pull/52)
17+
18+
---
19+
320
## v1.5.0 (11/12/2020)
421

522
#### closed

README.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
[![Build Status](https://travis-ci.org/vankeisb/react-tea-cup.svg?branch=develop)](https://travis-ci.org/vankeisb/react-tea-cup) ![](https://img.shields.io/github/tag/vankeisb/react-tea-cup.svg?label=latest&style=flat)
2-
31
Want some TEA in your React ?
42

53
`react-tea-cup` is a very thin library that helps following The Elm Architecture, in React.

core/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "tea-cup-core",
3-
"version": "1.5.2",
3+
"version": "1.5.3",
44
"description": "react-tea-cup core classes and utilities (Maybe etc)",
55
"author": "Rémi Van Keisbelck <remi@rvkb.com>",
66
"license": "MIT",
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* MIT License
3+
*
4+
* Copyright (c) 2019 Rémi Van Keisbelck
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*
24+
*/
25+
26+
import { Cmd } from './Cmd';
27+
import { genericUpdatePiped, updatePiped } from './UpdatePiped';
28+
29+
describe('UpdatePiped', () => {
30+
type MyModel = number;
31+
type MyCmd = readonly string[];
32+
33+
test('generic', () => {
34+
const model0: MyModel = 6;
35+
const [model, cmd] = genericUpdatePiped(
36+
(cmd1: MyCmd, cmd2: MyCmd) => new Array().concat(...cmd1, ...cmd2),
37+
[],
38+
model0,
39+
(model) => [model + 1, ['add 1']],
40+
(model) => [model * 6, ['multiply by 6']],
41+
);
42+
expect(model).toBe(42);
43+
expect(cmd).toEqual(['add 1', 'multiply by 6']);
44+
});
45+
46+
test('example with none handling', () => {
47+
type MyMsg = string;
48+
const model0: MyModel = 6;
49+
const [model, cmd] = updatePiped(
50+
model0,
51+
(model) => [model + 1, Cmd.none()],
52+
(model) => [model * 6, Cmd.none()],
53+
);
54+
expect(model).toBe(42);
55+
expect(cmd).toEqual(Cmd.none());
56+
});
57+
});

core/src/TeaCup/UpdatePiped.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* MIT License
3+
*
4+
* Copyright (c) 2019 Rémi Van Keisbelck
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*
24+
*/
25+
26+
import { Cmd } from './Cmd';
27+
28+
export type UpdateFunction<Model, Msg> = GenericUpdateFunction<Model, Cmd<Msg>>;
29+
30+
/**
31+
* Piped updates.
32+
* Useful for chaining building blocks making up the update loop.
33+
*/
34+
export function updatePiped<Model, Msg>(
35+
model: Model,
36+
...updates: readonly UpdateFunction<Model, Msg>[]
37+
): [Model, Cmd<Msg>] {
38+
const none: Cmd<Msg> = Cmd.none();
39+
const combine = (cmd1: Cmd<Msg>, cmd2: Cmd<Msg>) => {
40+
const none1 = isNone(cmd1);
41+
const none2 = isNone(cmd2);
42+
return none1 && none2 ? cmd1 : none1 ? cmd2 : none2 ? cmd1 : Cmd.batch([cmd1, cmd2]);
43+
};
44+
return genericUpdatePiped(combine, none, model, ...updates);
45+
}
46+
47+
function isNone<Msg>(cmd: Cmd<Msg>): boolean {
48+
return cmd.constructor.name === 'CmdNone';
49+
}
50+
51+
export type GenericUpdateFunction<Model, Cmd> = (model: Model) => [Model, Cmd];
52+
53+
/**
54+
* Generic implementation of chained updates.
55+
* See updatePiped().
56+
*/
57+
export function genericUpdatePiped<Model, Cmd>(
58+
combine: (cmd1: Cmd, cmd2: Cmd) => Cmd,
59+
none: Cmd,
60+
model: Model,
61+
...updates: readonly GenericUpdateFunction<Model, Cmd>[]
62+
): [Model, Cmd] {
63+
return updates.reduce<[Model, Cmd]>(
64+
(acc: [Model, Cmd], update: GenericUpdateFunction<Model, Cmd>) => {
65+
const [model0, cmd0] = acc;
66+
const [model1, cmd1] = update(model0);
67+
return [model1, combine(cmd0, cmd1)];
68+
},
69+
[model, none],
70+
);
71+
}

samples/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"react": "^16.7.0",
1212
"react-dom": "^16.7.0",
1313
"react-scripts": "3.4.3",
14-
"react-tea-cup": "1.5.2"
14+
"react-tea-cup": "^1.5.3"
1515
},
1616
"scripts": {
1717
"start": "react-scripts start",
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { mount, ReactWrapper } from 'enzyme';
2+
import { extendJest, Cmd, Sub, Task, Program, ProgramProps, updateUntilIdle } from "react-tea-cup";
3+
import React, { ReactNode } from 'react';
4+
import { Dispatcher } from 'tea-cup-core';
5+
6+
extendJest(expect);
7+
8+
const init1: () => [number, Cmd<string>] = () => {
9+
return [0, toCmd('go')];
10+
}
11+
12+
const view1: (dispatch: Dispatcher<string>, model: number) => React.ReactNode = (dispatch: Dispatcher<string>, model: number) => {
13+
return (<div className={'count'}>{model}</div>);
14+
}
15+
16+
const update1: (msg: string, model: number) => [number, Cmd<string>] = (msg: string, model: number) => {
17+
return [model + 1, model < 5 ? toCmd('go') : Cmd.none()];
18+
}
19+
20+
// const toCmd = (msg: string) => Task.perform(Time.in(0), () => msg);
21+
const toCmd = (msg: string) => Task.perform(Task.succeed(0), () => msg);
22+
23+
describe('Test Program', () => {
24+
25+
it('expect when program is idle', () => {
26+
const props: ProgramProps<number, string> = {
27+
init: init1,
28+
view: view1,
29+
update: update1,
30+
subscriptions: () => Sub.none<string>()
31+
}
32+
return updateUntilIdle(props, mount).then(([model, wrapper]) => {
33+
expect(model).toEqual(6)
34+
// expect(wrapper).toHaveHTML('')
35+
expect(wrapper.find('.count')).toHaveText('6')
36+
})
37+
})
38+
})

tea-cup/package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-tea-cup",
3-
"version": "1.5.2",
3+
"version": "1.5.3",
44
"description": "Put some TEA in your React.",
55
"author": "Rémi Van Keisbelck <remi@rvkb.com>",
66
"license": "MIT",
@@ -20,7 +20,9 @@
2020
"samples": "tsc --outFile ./dist/Samples/index.js && cp ./src/Samples/index.html ./dist/Samples"
2121
},
2222
"dependencies": {
23-
"tea-cup-core": "1.5.2",
23+
"tea-cup-core": "^1.5.3"
24+
},
25+
"peerDependencies": {
2426
"react": "^16.7.0"
2527
},
2628
"devDependencies": {

tea-cup/src/TeaCup/Program.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ export class Program<Model, Msg> extends Component<ProgramProps<Model, Msg>, nev
7070
this.count++;
7171
const count = this.count;
7272
const currentModel = this.currentModel;
73-
if (currentModel) {
73+
if (currentModel !== undefined) {
7474
const updated = this.props.update(msg, currentModel);
7575
if (this.props.devTools) {
7676
this.fireEvent({

tea-cup/src/TeaCup/Testing.ts

Lines changed: 0 additions & 78 deletions
This file was deleted.

0 commit comments

Comments
 (0)