Increasing test coverage

This commit is contained in:
Kai Moseley 2016-12-11 15:50:06 +00:00
parent 5271513b70
commit e4a9eeabfc
36 changed files with 4971 additions and 240 deletions

164
coverage/clover.xml Normal file
View File

@ -0,0 +1,164 @@
<?xml version="1.0" encoding="UTF-8"?>
<coverage generated="1481470770158" clover="3.2.0">
<project timestamp="1481470770158" name="All files">
<metrics statements="124" coveredstatements="95" conditionals="95" coveredconditionals="61" methods="59" coveredmethods="54" elements="278" coveredelements="210" complexity="0" loc="124" ncloc="124" packages="3" files="8" classes="8">
<package name="redux-arg">
<metrics statements="58" coveredstatements="58" conditionals="36" coveredconditionals="36" methods="32" coveredmethods="32"/>
<file name="buildStoreChunk.js" path="F:\GitRepos\redux-arg\src\redux-arg\buildStoreChunk.js">
<metrics statements="12" coveredstatements="12" conditionals="13" coveredconditionals="13" methods="7" coveredmethods="7"/>
<line num="23" count="6" type="stmt"/>
<line num="29" count="7" type="stmt"/>
<line num="30" count="6" type="stmt"/>
<line num="45" count="6" type="stmt"/>
<line num="46" count="4" type="stmt"/>
<line num="53" count="6" type="stmt"/>
<line num="63" count="10" type="stmt"/>
<line num="64" count="10" type="stmt"/>
<line num="70" count="10" type="stmt"/>
<line num="73" count="1" type="stmt"/>
<line num="85" count="10" type="stmt"/>
<line num="97" count="6" type="stmt"/>
</file>
<file name="reducers.js" path="F:\GitRepos\redux-arg\src\redux-arg\reducers.js">
<metrics statements="12" coveredstatements="12" conditionals="7" coveredconditionals="7" methods="6" coveredmethods="6"/>
<line num="45" count="2" type="stmt"/>
<line num="63" count="14" type="stmt"/>
<line num="64" count="14" type="stmt"/>
<line num="66" count="14" type="stmt"/>
<line num="68" count="13" type="stmt"/>
<line num="82" count="9" type="stmt"/>
<line num="94" count="22" type="stmt"/>
<line num="106" count="12" type="stmt"/>
<line num="107" count="12" type="stmt"/>
<line num="109" count="12" type="stmt"/>
<line num="111" count="6" type="stmt"/>
<line num="117" count="2" type="stmt"/>
</file>
<file name="structure.js" path="F:\GitRepos\redux-arg\src\redux-arg\structure.js">
<metrics statements="8" coveredstatements="8" conditionals="4" coveredconditionals="4" methods="12" coveredmethods="12"/>
<line num="49" count="4" type="stmt"/>
<line num="60" count="4" type="stmt"/>
<line num="61" count="59" type="stmt"/>
<line num="66" count="28" type="stmt"/>
<line num="71" count="7" type="stmt"/>
<line num="76" count="15" type="stmt"/>
<line num="81" count="28" type="stmt"/>
<line num="85" count="29" type="stmt"/>
</file>
<file name="validatePayload.js" path="F:\GitRepos\redux-arg\src\redux-arg\validatePayload.js">
<metrics statements="26" coveredstatements="26" conditionals="12" coveredconditionals="12" methods="7" coveredmethods="7"/>
<line num="16" count="11" type="stmt"/>
<line num="17" count="1" type="stmt"/>
<line num="18" count="1" type="stmt"/>
<line num="21" count="10" type="stmt"/>
<line num="22" count="15" type="stmt"/>
<line num="25" count="15" type="stmt"/>
<line num="26" count="1" type="stmt"/>
<line num="28" count="1" type="stmt"/>
<line num="31" count="14" type="stmt"/>
<line num="32" count="14" type="stmt"/>
<line num="33" count="1" type="stmt"/>
<line num="36" count="1" type="stmt"/>
<line num="39" count="13" type="stmt"/>
<line num="48" count="35" type="stmt"/>
<line num="49" count="4" type="stmt"/>
<line num="55" count="7" type="stmt"/>
<line num="56" count="1" type="stmt"/>
<line num="57" count="1" type="stmt"/>
<line num="59" count="6" type="stmt"/>
<line num="60" count="6" type="stmt"/>
<line num="61" count="14" type="stmt"/>
<line num="65" count="29" type="stmt"/>
<line num="72" count="29" type="stmt"/>
<line num="73" count="29" type="stmt"/>
<line num="74" count="1" type="stmt"/>
<line num="77" count="28" type="stmt"/>
</file>
</package>
<package name="redux-arg.reducers">
<metrics statements="60" coveredstatements="31" conditionals="47" coveredconditionals="13" methods="25" coveredmethods="20"/>
<file name="arrayReducer.js" path="F:\GitRepos\redux-arg\src\redux-arg\reducers\arrayReducer.js">
<metrics statements="32" coveredstatements="9" conditionals="29" coveredconditionals="4" methods="9" coveredmethods="6"/>
<line num="48" count="0" type="stmt"/>
<line num="49" count="0" type="stmt"/>
<line num="50" count="0" type="stmt"/>
<line num="52" count="0" type="stmt"/>
<line num="65" count="2" type="stmt"/>
<line num="69" count="0" type="stmt"/>
<line num="70" count="0" type="stmt"/>
<line num="71" count="0" type="stmt"/>
<line num="72" count="0" type="stmt"/>
<line num="77" count="0" type="stmt"/>
<line num="78" count="0" type="stmt"/>
<line num="83" count="0" type="stmt"/>
<line num="84" count="0" type="stmt"/>
<line num="89" count="0" type="stmt"/>
<line num="90" count="0" type="stmt"/>
<line num="91" count="0" type="stmt"/>
<line num="97" count="1" type="stmt"/>
<line num="98" count="1" type="stmt"/>
<line num="101" count="0" type="stmt"/>
<line num="106" count="0" type="stmt"/>
<line num="116" count="1" type="stmt"/>
<line num="128" count="1" type="stmt"/>
<line num="131" count="1" type="stmt"/>
<line num="133" count="15" type="stmt"/>
<line num="137" count="0" type="stmt"/>
<line num="150" count="0" type="stmt"/>
<line num="154" count="0" type="stmt"/>
<line num="155" count="0" type="stmt"/>
<line num="156" count="0" type="stmt"/>
<line num="162" count="6" type="stmt"/>
<line num="164" count="1" type="stmt"/>
<line num="166" count="0" type="stmt"/>
</file>
<file name="objectReducer.js" path="F:\GitRepos\redux-arg\src\redux-arg\reducers\objectReducer.js">
<metrics statements="15" coveredstatements="9" conditionals="10" coveredconditionals="3" methods="9" coveredmethods="7"/>
<line num="53" count="2" type="stmt"/>
<line num="55" count="0" type="stmt"/>
<line num="57" count="0" type="stmt"/>
<line num="62" count="0" type="stmt"/>
<line num="66" count="1" type="stmt"/>
<line num="68" count="0" type="stmt"/>
<line num="78" count="1" type="stmt"/>
<line num="88" count="1" type="stmt"/>
<line num="98" count="1" type="stmt"/>
<line num="99" count="1" type="stmt"/>
<line num="101" count="15" type="stmt"/>
<line num="105" count="0" type="stmt"/>
<line num="112" count="3" type="stmt"/>
<line num="114" count="1" type="stmt"/>
<line num="116" count="0" type="stmt"/>
</file>
<file name="primitiveReducer.js" path="F:\GitRepos\redux-arg\src\redux-arg\reducers\primitiveReducer.js">
<metrics statements="13" coveredstatements="13" conditionals="8" coveredconditionals="6" methods="7" coveredmethods="7"/>
<line num="50" count="2" type="stmt"/>
<line num="52" count="3" type="stmt"/>
<line num="54" count="2" type="stmt"/>
<line num="55" count="2" type="stmt"/>
<line num="60" count="2" type="stmt"/>
<line num="70" count="6" type="stmt"/>
<line num="80" count="6" type="stmt"/>
<line num="81" count="6" type="stmt"/>
<line num="83" count="67" type="stmt"/>
<line num="87" count="4" type="stmt"/>
<line num="94" count="12" type="stmt"/>
<line num="96" count="5" type="stmt"/>
<line num="98" count="2" type="stmt"/>
</file>
</package>
<package name="redux-arg.utils">
<metrics statements="6" coveredstatements="6" conditionals="12" coveredconditionals="12" methods="2" coveredmethods="2"/>
<file name="arrayUtils.js" path="F:\GitRepos\redux-arg\src\redux-arg\utils\arrayUtils.js">
<metrics statements="6" coveredstatements="6" conditionals="12" coveredconditionals="12" methods="2" coveredmethods="2"/>
<line num="3" count="6" type="stmt"/>
<line num="4" count="4" type="stmt"/>
<line num="5" count="3" type="stmt"/>
<line num="13" count="6" type="stmt"/>
<line num="14" count="4" type="stmt"/>
<line num="15" count="3" type="stmt"/>
</file>
</package>
</metrics>
</project>
</coverage>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,212 @@
body, html {
margin:0; padding: 0;
height: 100%;
}
body {
font-family: Helvetica Neue, Helvetica, Arial;
font-size: 14px;
color:#333;
}
.small { font-size: 12px; }
*, *:after, *:before {
-webkit-box-sizing:border-box;
-moz-box-sizing:border-box;
box-sizing:border-box;
}
h1 { font-size: 20px; margin: 0;}
h2 { font-size: 14px; }
pre {
font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace;
margin: 0;
padding: 0;
-moz-tab-size: 2;
-o-tab-size: 2;
tab-size: 2;
}
a { color:#0074D9; text-decoration:none; }
a:hover { text-decoration:underline; }
.strong { font-weight: bold; }
.space-top1 { padding: 10px 0 0 0; }
.pad2y { padding: 20px 0; }
.pad1y { padding: 10px 0; }
.pad2x { padding: 0 20px; }
.pad2 { padding: 20px; }
.pad1 { padding: 10px; }
.space-left2 { padding-left:55px; }
.space-right2 { padding-right:20px; }
.center { text-align:center; }
.clearfix { display:block; }
.clearfix:after {
content:'';
display:block;
height:0;
clear:both;
visibility:hidden;
}
.fl { float: left; }
@media only screen and (max-width:640px) {
.col3 { width:100%; max-width:100%; }
.hide-mobile { display:none!important; }
}
.quiet {
color: #7f7f7f;
color: rgba(0,0,0,0.5);
}
.quiet a { opacity: 0.7; }
.fraction {
font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace;
font-size: 10px;
color: #555;
background: #E8E8E8;
padding: 4px 5px;
border-radius: 3px;
vertical-align: middle;
}
div.path a:link, div.path a:visited { color: #333; }
table.coverage {
border-collapse: collapse;
margin: 10px 0 0 0;
padding: 0;
}
table.coverage td {
margin: 0;
padding: 0;
vertical-align: top;
}
table.coverage td.line-count {
text-align: right;
padding: 0 5px 0 20px;
}
table.coverage td.line-coverage {
text-align: right;
padding-right: 10px;
min-width:20px;
}
table.coverage td span.cline-any {
display: inline-block;
padding: 0 5px;
width: 100%;
}
.missing-if-branch {
display: inline-block;
margin-right: 5px;
border-radius: 3px;
position: relative;
padding: 0 4px;
background: #333;
color: yellow;
}
.skip-if-branch {
display: none;
margin-right: 10px;
position: relative;
padding: 0 4px;
background: #ccc;
color: white;
}
.missing-if-branch .typ, .skip-if-branch .typ {
color: inherit !important;
}
.coverage-summary {
border-collapse: collapse;
width: 100%;
}
.coverage-summary tr { border-bottom: 1px solid #bbb; }
.keyline-all { border: 1px solid #ddd; }
.coverage-summary td, .coverage-summary th { padding: 10px; }
.coverage-summary tbody { border: 1px solid #bbb; }
.coverage-summary td { border-right: 1px solid #bbb; }
.coverage-summary td:last-child { border-right: none; }
.coverage-summary th {
text-align: left;
font-weight: normal;
white-space: nowrap;
}
.coverage-summary th.file { border-right: none !important; }
.coverage-summary th.pct { }
.coverage-summary th.pic,
.coverage-summary th.abs,
.coverage-summary td.pct,
.coverage-summary td.abs { text-align: right; }
.coverage-summary td.file { white-space: nowrap; }
.coverage-summary td.pic { min-width: 120px !important; }
.coverage-summary tfoot td { }
.coverage-summary .sorter {
height: 10px;
width: 7px;
display: inline-block;
margin-left: 0.5em;
background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent;
}
.coverage-summary .sorted .sorter {
background-position: 0 -20px;
}
.coverage-summary .sorted-desc .sorter {
background-position: 0 -10px;
}
.status-line { height: 10px; }
/* dark red */
.red.solid, .status-line.low, .low .cover-fill { background:#C21F39 }
.low .chart { border:1px solid #C21F39 }
/* medium red */
.cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE }
/* light red */
.low, .cline-no { background:#FCE1E5 }
/* light green */
.high, .cline-yes { background:rgb(230,245,208) }
/* medium green */
.cstat-yes { background:rgb(161,215,106) }
/* dark green */
.status-line.high, .high .cover-fill { background:rgb(77,146,33) }
.high .chart { border:1px solid rgb(77,146,33) }
.medium .chart { border:1px solid #666; }
.medium .cover-fill { background: #666; }
.cbranch-no { background: yellow !important; color: #111; }
.cstat-skip { background: #ddd; color: #111; }
.fstat-skip { background: #ddd; color: #111 !important; }
.cbranch-skip { background: #ddd !important; color: #111; }
span.cline-neutral { background: #eaeaea; }
.medium { background: #eaeaea; }
.cover-fill, .cover-empty {
display:inline-block;
height: 12px;
}
.chart {
line-height: 0;
}
.cover-empty {
background: white;
}
.cover-full {
border-right: none !important;
}
pre.prettyprint {
border: none !important;
padding: 0 !important;
margin: 0 !important;
}
.com { color: #999 !important; }
.ignore-none { color: #999; font-weight: normal; }
.wrapper {
min-height: 100%;
height: auto !important;
height: 100%;
margin: 0 auto -48px;
}
.footer, .push {
height: 48px;
}

View File

@ -0,0 +1,119 @@
<!doctype html>
<html lang="en">
<head>
<title>Code coverage report for All files</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="prettify.css" />
<link rel="stylesheet" href="base.css" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<style type='text/css'>
.coverage-summary .sorter {
background-image: url(sort-arrow-sprite.png);
}
</style>
</head>
<body>
<div class='wrapper'>
<div class='pad1'>
<h1>
All files
</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
<span class="strong">76.1% </span>
<span class="quiet">Statements</span>
<span class='fraction'>121/159</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">64.21% </span>
<span class="quiet">Branches</span>
<span class='fraction'>61/95</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">91.53% </span>
<span class="quiet">Functions</span>
<span class='fraction'>54/59</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">76.61% </span>
<span class="quiet">Lines</span>
<span class='fraction'>95/124</span>
</div>
</div>
</div>
<div class='status-line medium'></div>
<div class="pad1">
<table class="coverage-summary">
<thead>
<tr>
<th data-col="file" data-fmt="html" data-html="true" class="file">File</th>
<th data-col="pic" data-type="number" data-fmt="html" data-html="true" class="pic"></th>
<th data-col="statements" data-type="number" data-fmt="pct" class="pct">Statements</th>
<th data-col="statements_raw" data-type="number" data-fmt="html" class="abs"></th>
<th data-col="branches" data-type="number" data-fmt="pct" class="pct">Branches</th>
<th data-col="branches_raw" data-type="number" data-fmt="html" class="abs"></th>
<th data-col="functions" data-type="number" data-fmt="pct" class="pct">Functions</th>
<th data-col="functions_raw" data-type="number" data-fmt="html" class="abs"></th>
<th data-col="lines" data-type="number" data-fmt="pct" class="pct">Lines</th>
<th data-col="lines_raw" data-type="number" data-fmt="html" class="abs"></th>
</tr>
</thead>
<tbody><tr>
<td class="file high" data-value="redux-arg"><a href="redux-arg\index.html">redux-arg</a></td>
<td data-value="100" class="pic high"><div class="chart"><div class="cover-fill cover-full" style="width: 100%;"></div><div class="cover-empty" style="width:0%;"></div></div></td>
<td data-value="100" class="pct high">100%</td>
<td data-value="74" class="abs high">74/74</td>
<td data-value="100" class="pct high">100%</td>
<td data-value="36" class="abs high">36/36</td>
<td data-value="100" class="pct high">100%</td>
<td data-value="32" class="abs high">32/32</td>
<td data-value="100" class="pct high">100%</td>
<td data-value="58" class="abs high">58/58</td>
</tr>
<tr>
<td class="file low" data-value="redux-arg/reducers"><a href="redux-arg\reducers\index.html">redux-arg/reducers</a></td>
<td data-value="49.33" class="pic low"><div class="chart"><div class="cover-fill" style="width: 49%;"></div><div class="cover-empty" style="width:51%;"></div></div></td>
<td data-value="49.33" class="pct low">49.33%</td>
<td data-value="75" class="abs low">37/75</td>
<td data-value="27.66" class="pct low">27.66%</td>
<td data-value="47" class="abs low">13/47</td>
<td data-value="80" class="pct high">80%</td>
<td data-value="25" class="abs high">20/25</td>
<td data-value="51.67" class="pct medium">51.67%</td>
<td data-value="60" class="abs medium">31/60</td>
</tr>
<tr>
<td class="file high" data-value="redux-arg/utils"><a href="redux-arg\utils\index.html">redux-arg/utils</a></td>
<td data-value="100" class="pic high"><div class="chart"><div class="cover-fill cover-full" style="width: 100%;"></div><div class="cover-empty" style="width:0%;"></div></div></td>
<td data-value="100" class="pct high">100%</td>
<td data-value="10" class="abs high">10/10</td>
<td data-value="100" class="pct high">100%</td>
<td data-value="12" class="abs high">12/12</td>
<td data-value="100" class="pct high">100%</td>
<td data-value="2" class="abs high">2/2</td>
<td data-value="100" class="pct high">100%</td>
<td data-value="6" class="abs high">6/6</td>
</tr>
</tbody>
</table>
</div><div class='push'></div><!-- for sticky footer -->
</div><!-- /wrapper -->
<div class='footer quiet pad2 space-top1 center small'>
Code coverage
generated by <a href="http://istanbul-js.org/" target="_blank">istanbul</a> at Sun Dec 11 2016 15:39:29 GMT+0000 (GMT Standard Time)
</div>
</div>
<script src="prettify.js"></script>
<script>
window.onload = function () {
if (typeof prettyPrint === 'function') {
prettyPrint();
}
};
</script>
<script src="sorter.js"></script>
</body>
</html>

View File

@ -0,0 +1 @@
.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,392 @@
<!doctype html>
<html lang="en">
<head>
<title>Code coverage report for redux-arg/buildStoreChunk.js</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="..\prettify.css" />
<link rel="stylesheet" href="..\base.css" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<style type='text/css'>
.coverage-summary .sorter {
background-image: url(..\sort-arrow-sprite.png);
}
</style>
</head>
<body>
<div class='wrapper'>
<div class='pad1'>
<h1>
<a href="..\index.html">All files</a> / <a href="index.html">redux-arg</a> buildStoreChunk.js
</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
<span class="strong">100% </span>
<span class="quiet">Statements</span>
<span class='fraction'>15/15</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">100% </span>
<span class="quiet">Branches</span>
<span class='fraction'>13/13</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">100% </span>
<span class="quiet">Functions</span>
<span class='fraction'>7/7</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">100% </span>
<span class="quiet">Lines</span>
<span class='fraction'>12/12</span>
</div>
</div>
</div>
<div class='status-line high'></div>
<pre><table class="coverage">
<tr><td class="line-count quiet">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110</td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">6x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">7x</span>
<span class="cline-any cline-yes">6x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">6x</span>
<span class="cline-any cline-yes">4x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">6x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">10x</span>
<span class="cline-any cline-yes">10x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">10x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">10x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">6x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">//@flow
//==============================
// Flow imports
//==============================
import type { StructureType, PrimitiveType } from './structure';
import type { PartialStoreChunk } from './reducers';
&nbsp;
//==============================
// JS imports
//==============================
import { combineReducers } from 'redux';
import { reduce, find, omit, isFunction } from 'lodash';
import { compose } from 'ramda';
import { createReducer } from './reducers';
import { PROP_TYPES } from './structure';
&nbsp;
// Build a chunk of the eventual store. The selectors and actions
// generated will specifically operate on the store chunk generated. Selectors will be
// relative to the baseSelector provided or, if not specified, the root of the store, using
// the name of the chunk as the base property.
&nbsp;
export function buildStoreChunk(name: string, structure: any, {
baseSelector = state =&gt; state[name],
locationString = '',
}: {
baseSelector: any,
locationString: string,
} = {}): PartialStoreChunk {
if (!structure) throw new Error(`The structure must be defined for a reducer! LocationString: ${ locationString }`);
const initialMemo: PartialStoreChunk = {
reducers: {
[name]: {},
},
actions: {},
selectors: {},
baseSelector,
locationString,
name,
};
//Build up the reducers, actions, and selectors for this level. Due to recursion,
//these objects will be assigned to a property in the parent object, or simply
//returned to the call site for use in the rest of the application.
&nbsp;
//If the reducer's structure is a function (and, therefore, not nested reducers), we can skip the reduce.
if (isFunction(structure)) return combineStoreChunkReducers(processStructure(initialMemo, structure, name));
return combineStoreChunkReducers(reduce(structure, processStructure, initialMemo));
}
&nbsp;
export function combineStoreChunkReducers(processedStoreChunk: PartialStoreChunk) {
//The Redux 'combineReducers' helper function is used here to save a little bit of boilerplate.
//This helper, if you're not aware, ensures that the correct store properties are passed to the
//reducers assigned to those properties.
return { ...omit(processedStoreChunk, ['baseSelector', 'locationString', 'name']), reducers: {
[processedStoreChunk.name]: combineReducers(processedStoreChunk.reducers)
}};
}
&nbsp;
export function processStructure(memo: PartialStoreChunk, propValue: StructureType | PrimitiveType, propName: string) {
//Get the structure from the propValue. In the case of 'StructureType' properties, this
//will be some form of shape (or primitives in the case of arrays). At this point we
//are only interested in whether or not the structure contains reducers, as that
//has an impact on how we proceed with regards to calls.
const { structure: propStructure } = propValue();
const containsReducers = !!find(propStructure, v =&gt; v().type === PROP_TYPES._reducer);
&nbsp;
//Create the child reducer. Depending on whether or not the current structure level contains
//child reducers, we will either recursively call reducerBuilder, or we will call the
//createReducer function, which will create the correct reducer for the given structure
//(which can be either object, array, or primitive).
let childReducer = containsReducers
? buildStoreChunk(propName, propStructure, {
locationString: memo.locationString ? `${memo.locationString}.${propName}` : propName,
baseSelector: (state: any) =&gt; memo.baseSelector(state)[propName],
})
: createReducer(propValue, {
locationString: `${memo.locationString}.${propName}`,
name: propName,
});
&nbsp;
//As the object is built up, we want to assign the reducers/actions created
//by the child to a location on the reducers/actions object which will match up
//to their location. Selectors are created at this level, as the child does not
//need to know where it is located within the grand scheme of things.
&nbsp;
return {
...memo,
reducers: {
...memo.reducers,
...childReducer.reducers
},
actions: {
...memo.actions,
[propName]: childReducer.actions,
},
selectors: {
...memo.selectors,
[propName]: containsReducers ? childReducer.selectors : state =&gt; memo.baseSelector(state)[propName],
},
};
}
&nbsp;
&nbsp;
&nbsp;
&nbsp;
&nbsp;
&nbsp;
&nbsp;
&nbsp;
&nbsp;
&nbsp;</pre></td></tr>
</table></pre>
<div class='push'></div><!-- for sticky footer -->
</div><!-- /wrapper -->
<div class='footer quiet pad2 space-top1 center small'>
Code coverage
generated by <a href="http://istanbul-js.org/" target="_blank">istanbul</a> at Sun Dec 11 2016 15:39:29 GMT+0000 (GMT Standard Time)
</div>
</div>
<script src="..\prettify.js"></script>
<script>
window.onload = function () {
if (typeof prettyPrint === 'function') {
prettyPrint();
}
};
</script>
<script src="..\sorter.js"></script>
</body>
</html>

View File

@ -0,0 +1,132 @@
<!doctype html>
<html lang="en">
<head>
<title>Code coverage report for redux-arg</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="..\prettify.css" />
<link rel="stylesheet" href="..\base.css" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<style type='text/css'>
.coverage-summary .sorter {
background-image: url(..\sort-arrow-sprite.png);
}
</style>
</head>
<body>
<div class='wrapper'>
<div class='pad1'>
<h1>
<a href="..\index.html">All files</a> redux-arg
</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
<span class="strong">100% </span>
<span class="quiet">Statements</span>
<span class='fraction'>74/74</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">100% </span>
<span class="quiet">Branches</span>
<span class='fraction'>36/36</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">100% </span>
<span class="quiet">Functions</span>
<span class='fraction'>32/32</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">100% </span>
<span class="quiet">Lines</span>
<span class='fraction'>58/58</span>
</div>
</div>
</div>
<div class='status-line high'></div>
<div class="pad1">
<table class="coverage-summary">
<thead>
<tr>
<th data-col="file" data-fmt="html" data-html="true" class="file">File</th>
<th data-col="pic" data-type="number" data-fmt="html" data-html="true" class="pic"></th>
<th data-col="statements" data-type="number" data-fmt="pct" class="pct">Statements</th>
<th data-col="statements_raw" data-type="number" data-fmt="html" class="abs"></th>
<th data-col="branches" data-type="number" data-fmt="pct" class="pct">Branches</th>
<th data-col="branches_raw" data-type="number" data-fmt="html" class="abs"></th>
<th data-col="functions" data-type="number" data-fmt="pct" class="pct">Functions</th>
<th data-col="functions_raw" data-type="number" data-fmt="html" class="abs"></th>
<th data-col="lines" data-type="number" data-fmt="pct" class="pct">Lines</th>
<th data-col="lines_raw" data-type="number" data-fmt="html" class="abs"></th>
</tr>
</thead>
<tbody><tr>
<td class="file high" data-value="buildStoreChunk.js"><a href="buildStoreChunk.js.html">buildStoreChunk.js</a></td>
<td data-value="100" class="pic high"><div class="chart"><div class="cover-fill cover-full" style="width: 100%;"></div><div class="cover-empty" style="width:0%;"></div></div></td>
<td data-value="100" class="pct high">100%</td>
<td data-value="15" class="abs high">15/15</td>
<td data-value="100" class="pct high">100%</td>
<td data-value="13" class="abs high">13/13</td>
<td data-value="100" class="pct high">100%</td>
<td data-value="7" class="abs high">7/7</td>
<td data-value="100" class="pct high">100%</td>
<td data-value="12" class="abs high">12/12</td>
</tr>
<tr>
<td class="file high" data-value="reducers.js"><a href="reducers.js.html">reducers.js</a></td>
<td data-value="100" class="pic high"><div class="chart"><div class="cover-fill cover-full" style="width: 100%;"></div><div class="cover-empty" style="width:0%;"></div></div></td>
<td data-value="100" class="pct high">100%</td>
<td data-value="16" class="abs high">16/16</td>
<td data-value="100" class="pct high">100%</td>
<td data-value="7" class="abs high">7/7</td>
<td data-value="100" class="pct high">100%</td>
<td data-value="6" class="abs high">6/6</td>
<td data-value="100" class="pct high">100%</td>
<td data-value="12" class="abs high">12/12</td>
</tr>
<tr>
<td class="file high" data-value="structure.js"><a href="structure.js.html">structure.js</a></td>
<td data-value="100" class="pic high"><div class="chart"><div class="cover-fill cover-full" style="width: 100%;"></div><div class="cover-empty" style="width:0%;"></div></div></td>
<td data-value="100" class="pct high">100%</td>
<td data-value="14" class="abs high">14/14</td>
<td data-value="100" class="pct high">100%</td>
<td data-value="4" class="abs high">4/4</td>
<td data-value="100" class="pct high">100%</td>
<td data-value="12" class="abs high">12/12</td>
<td data-value="100" class="pct high">100%</td>
<td data-value="8" class="abs high">8/8</td>
</tr>
<tr>
<td class="file high" data-value="validatePayload.js"><a href="validatePayload.js.html">validatePayload.js</a></td>
<td data-value="100" class="pic high"><div class="chart"><div class="cover-fill cover-full" style="width: 100%;"></div><div class="cover-empty" style="width:0%;"></div></div></td>
<td data-value="100" class="pct high">100%</td>
<td data-value="29" class="abs high">29/29</td>
<td data-value="100" class="pct high">100%</td>
<td data-value="12" class="abs high">12/12</td>
<td data-value="100" class="pct high">100%</td>
<td data-value="7" class="abs high">7/7</td>
<td data-value="100" class="pct high">100%</td>
<td data-value="26" class="abs high">26/26</td>
</tr>
</tbody>
</table>
</div><div class='push'></div><!-- for sticky footer -->
</div><!-- /wrapper -->
<div class='footer quiet pad2 space-top1 center small'>
Code coverage
generated by <a href="http://istanbul-js.org/" target="_blank">istanbul</a> at Sun Dec 11 2016 15:39:29 GMT+0000 (GMT Standard Time)
</div>
</div>
<script src="..\prettify.js"></script>
<script>
window.onload = function () {
if (typeof prettyPrint === 'function') {
prettyPrint();
}
};
</script>
<script src="..\sorter.js"></script>
</body>
</html>

View File

@ -0,0 +1,416 @@
<!doctype html>
<html lang="en">
<head>
<title>Code coverage report for redux-arg/reducers.js</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="..\prettify.css" />
<link rel="stylesheet" href="..\base.css" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<style type='text/css'>
.coverage-summary .sorter {
background-image: url(..\sort-arrow-sprite.png);
}
</style>
</head>
<body>
<div class='wrapper'>
<div class='pad1'>
<h1>
<a href="..\index.html">All files</a> / <a href="index.html">redux-arg</a> reducers.js
</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
<span class="strong">100% </span>
<span class="quiet">Statements</span>
<span class='fraction'>16/16</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">100% </span>
<span class="quiet">Branches</span>
<span class='fraction'>7/7</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">100% </span>
<span class="quiet">Functions</span>
<span class='fraction'>6/6</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">100% </span>
<span class="quiet">Lines</span>
<span class='fraction'>12/12</span>
</div>
</div>
</div>
<div class='status-line high'></div>
<pre><table class="coverage">
<tr><td class="line-count quiet">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118</td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">2x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">14x</span>
<span class="cline-any cline-yes">14x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">14x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">13x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">9x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">22x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">12x</span>
<span class="cline-any cline-yes">12x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">12x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">6x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">2x</span>
<span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">//@flow
//==============================
// Flow imports
//==============================
import type {
StructureType,
PrimitiveType,
ReducerType,
PropTypeKeys,
} from './structure';
&nbsp;
//==============================
// Flow types
//==============================
export type PartialStoreChunk = {
reducers: { [key: string]: any },
actions: { [key: string]: any },
selectors: { [key: string]: any },
locationString: string,
baseSelector: () =&gt; {},
name: string,
};
&nbsp;
export type Selector = (state: Object) =&gt; any;
&nbsp;
type CallReducerInterface = {
name: string,
reducerFn: () =&gt; {},
reducerStructureDescriptor: StructureType | PrimitiveType,
locationString: string,
};
&nbsp;
//==============================
// JS imports
//==============================
import {
PROP_TYPES,
} from './structure';
import { compose } from 'ramda';
import { reduce, find } from 'lodash';
import { createShapeReducer } from './reducers/objectReducer';
import { createArrayReducer } from './reducers/arrayReducer';
import { createPrimitiveReducer } from './reducers/primitiveReducer';
&nbsp;
export const REDUCER_CREATOR_MAPPING: { [key: PropTypeKeys]: any } = {
[PROP_TYPES._shape]: createShapeReducer,
[PROP_TYPES._array]: createArrayReducer,
[PROP_TYPES._boolean]: createPrimitiveReducer,
[PROP_TYPES._string]: createPrimitiveReducer,
[PROP_TYPES._number]: createPrimitiveReducer,
};
&nbsp;
export function determineReducerType(reducerDescriptor: ReducerType, {
name,
locationString,
reducerCreatorMapping = REDUCER_CREATOR_MAPPING,
}: {
name: string,
locationString: string,
reducerCreatorMapping: { [key: PropTypeKeys]: any },
}): CallReducerInterface {
&nbsp;
const { structure } = reducerDescriptor();
const { type } = structure();
&nbsp;
if (!reducerCreatorMapping[type]) throw new Error(`Reducer type ${type} does not have a corresponding createReducer function`);
&nbsp;
return {
name,
reducerFn: reducerCreatorMapping[type],
reducerStructureDescriptor: structure,
locationString,
};
}
&nbsp;
export function callReducer({
name,
reducerFn,
reducerStructureDescriptor,
locationString
}: CallReducerInterface) {
return reducerFn(reducerStructureDescriptor, {
locationString,
name,
});
}
&nbsp;
export function createReducerBehaviors(behaviorsConfig: { [key: string]: { reducer: () =&gt; {} } }, locationString: string): any {
//Take a reducer behavior config object, and create the reducer behaviors using the location string.
//This is necessary since all action types are effectively global when Redux processes an action
//(i.e. every reducer will be ran using the action object). Therefore we need to ensure that all
//actions only result in the specific reducer performing a change. Actions are also generated using
//the location string/name combination, so will match up 1:1.
return reduce(behaviorsConfig, (memo, behavior, name) =&gt; ({
...memo,
[`${locationString}.${name}`]: behavior.reducer,
}), {});
}
&nbsp;
export function calculateDefaults(typeDescription: StructureType | PrimitiveType) {
//Using the structure of a type, calculate the default for that type.
//Types can take two forms; a 'StructureType' and a 'PrimitiveType'. The former
//can (and usually does) contain nested type descriptions, so we need to recurse
//through the definition until defaults are found, and build up the corresponding
//structure.
const { type, structure = {}, defaultValue = '' } = typeDescription();
const complex = [PROP_TYPES._array, PROP_TYPES._shape].indexOf(type) &gt; -1;
&nbsp;
if (!complex) return defaultValue;
&nbsp;
return reduce(structure, (memo, propValue, propName) =&gt; ({
...memo,
[propName]: calculateDefaults(propValue),
}), {});
}
&nbsp;
export const createReducer = compose(callReducer, determineReducerType);
&nbsp;</pre></td></tr>
</table></pre>
<div class='push'></div><!-- for sticky footer -->
</div><!-- /wrapper -->
<div class='footer quiet pad2 space-top1 center small'>
Code coverage
generated by <a href="http://istanbul-js.org/" target="_blank">istanbul</a> at Sun Dec 11 2016 15:39:29 GMT+0000 (GMT Standard Time)
</div>
</div>
<script src="..\prettify.js"></script>
<script>
window.onload = function () {
if (typeof prettyPrint === 'function') {
prettyPrint();
}
};
</script>
<script src="..\sorter.js"></script>
</body>
</html>

View File

@ -0,0 +1,575 @@
<!doctype html>
<html lang="en">
<head>
<title>Code coverage report for redux-arg/reducers/arrayReducer.js</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="..\..\prettify.css" />
<link rel="stylesheet" href="..\..\base.css" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<style type='text/css'>
.coverage-summary .sorter {
background-image: url(..\..\sort-arrow-sprite.png);
}
</style>
</head>
<body>
<div class='wrapper'>
<div class='pad1'>
<h1>
<a href="..\..\index.html">All files</a> / <a href="index.html">redux-arg/reducers</a> arrayReducer.js
</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
<span class="strong">26.83% </span>
<span class="quiet">Statements</span>
<span class='fraction'>11/41</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">13.79% </span>
<span class="quiet">Branches</span>
<span class='fraction'>4/29</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">66.67% </span>
<span class="quiet">Functions</span>
<span class='fraction'>6/9</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">28.13% </span>
<span class="quiet">Lines</span>
<span class='fraction'>9/32</span>
</div>
</div>
</div>
<div class='status-line low'></div>
<pre><table class="coverage">
<tr><td class="line-count quiet">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171</td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">2x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">15x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">6x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">//@flow
//==============================
// Flow imports
//==============================
import type { ArrayStructureType } from '../structure';
&nbsp;
//==============================
// Flow types
//==============================
export type ArrayReducerAction = {
type: string,
payload: any,
index: number,
};
export type ArrayReducer = (state: Array&lt;any&gt;, action: ArrayReducerAction) =&gt; Array&lt;any&gt;;
export type ArrayReducerBehavior = (state: Array&lt;any&gt;, payload: any, initialState: Array&lt;any&gt;, index: number | void) =&gt; Array&lt;any&gt;;
export type ArrayReducerBehaviorsConfig = {
[key: string]: {
action?: (value: any) =&gt; any,
reducer: ArrayReducerBehavior,
}
};
export type ArrayReducerBehaviors = {
[key: string]: ArrayReducerBehavior,
};
export type ArrayAction = (value: Array&lt;any&gt;) =&gt; { type: string, payload: any, index?: number };
export type ArrayActions = {
[key: string]: Array&lt;any&gt;
};
export type ArrayReducerOptions = {
behaviorsConfig: ArrayReducerBehaviorsConfig,
locationString: string,
name: string,
};
export type ArraySelector = (state: Object) =&gt; Array&lt;any&gt;;
&nbsp;
//==============================
// JS imports
//==============================
import { reduce, isArray, isNumber, isObject } from 'lodash';
import { validateArray, validateShape, validatePrimitive } from '../validatePayload';
import { createReducerBehaviors } from '../reducers';
import { updateAtIndex, removeAtIndex } from '../utils/arrayUtils';
import { PROP_TYPES } from '../structure';
&nbsp;
&nbsp;
function <span class="fstat-no" title="function not covered" >checkIndex(</span>index: ?number, payload: any, behaviorName: string): boolean {
<span class="cstat-no" title="statement not covered" > if (!isNumber(index) || index === -1) {</span>
<span class="cstat-no" title="statement not covered" > console.warn(`Index not passed to ${behaviorName} for payload ${payload}.`);</span>
<span class="cstat-no" title="statement not covered" > return false;</span>
}
<span class="cstat-no" title="statement not covered" > return true;</span>
}
&nbsp;
&nbsp;
//==============================
// Array behaviors
// ----------------
// Arrays are more complicated than shape or primitive reducers, due to
// the complexities in amending specific elements. Of course, the behaviours
// could still follow and the same pattern as the other reducers and simply
// make the end user replace the correct index themselves. However, it made sense
// to create a few helper behaviors to aid with the most common array operations.
//==============================
const DEFAULT_ARRAY_BEHAVIORS: ArrayReducerBehaviorsConfig = {
//Index specific behaviors.
updateAtIndex: {
reducer(state, payload, initialState, index = <span class="branch-0 cbranch-no" title="branch not covered" >-1)</span> {
<span class="cstat-no" title="statement not covered" > if (!checkIndex(index, payload, 'updateAtIndex')) <span class="cstat-no" title="statement not covered" >return state;</span></span>
<span class="cstat-no" title="statement not covered" > if (payload === undefined) <span class="cstat-no" title="statement not covered" >return console.warn('Undefined was passed when updating index. Update not performed') || state;</span></span>
<span class="cstat-no" title="statement not covered" > if (isArray(payload) || isObject(payload)) <span class="cstat-no" title="statement not covered" >return updateAtIndex(state, { ...state[index], ...payload }, index);</span></span>
<span class="cstat-no" title="statement not covered" > return updateAtIndex(state, payload, index);</span>
}
},
resetAtIndex: {
reducer(state, payload, initialState, index) {
<span class="cstat-no" title="statement not covered" > checkIndex(index, payload, 'resetAtIndex');</span>
<span class="cstat-no" title="statement not covered" > return updateAtIndex(state, initialState, index);</span>
}
},
removeAtIndex: {
reducer(state, payload, initialState, index) {
<span class="cstat-no" title="statement not covered" > checkIndex(index, payload, 'removeAtIndex');</span>
<span class="cstat-no" title="statement not covered" > return removeAtIndex(state, index);</span>
}
},
replaceAtIndex: {
reducer(state, payload, initialState, index) {
<span class="cstat-no" title="statement not covered" > checkIndex(index, payload, 'replaceAtIndex');</span>
<span class="cstat-no" title="statement not covered" > if (payload === undefined) <span class="cstat-no" title="statement not covered" >console.warn('Undefined was passed when updating index. Update not performed');</span></span>
<span class="cstat-no" title="statement not covered" > return updateAtIndex(state, payload, index);</span>
}
},
//Whole array behaviors.
replace: {
action(value) {
<span class="missing-if-branch" title="if path not taken" >I</span>if(!isArray(value)) <span class="cstat-no" title="statement not covered" >throw new Error('An array must be provided when replacing an array');</span>
return value;
},
reducer(state, payload) {
<span class="cstat-no" title="statement not covered" > return payload;</span>
}
},
reset: {
reducer(state, payload, initialState) {
<span class="cstat-no" title="statement not covered" > return initialState;</span>
}
},
};
&nbsp;
&nbsp;
export function createArrayReducer(arrayTypeDescription: ArrayStructureType, {
locationString,
name,
}: ArrayReducerOptions = <span class="branch-0 cbranch-no" title="branch not covered" >{})</span> {
return {
reducers: {
[name]: createReducer(arrayTypeDescription, createReducerBehaviors(DEFAULT_ARRAY_BEHAVIORS, locationString))
},
actions: createActions(DEFAULT_ARRAY_BEHAVIORS, locationString, {}),
};
}
&nbsp;
&nbsp;
function createReducer(arrayTypeDescription: ArrayStructureType, behaviors: ArrayReducerBehaviors): ArrayReducer {
//Take the initial value specified as the default for the array, then apply it, using the validation
//when doing so. The initial value must be an array.
const initialValue = validateArray(arrayTypeDescription, arrayTypeDescription().defaultValue);
&nbsp;
//Return the array reducer.
return (state: Array&lt;any&gt; = initialValue, { type, payload, index }: ArrayReducerAction) =&gt; {
//If the action type does not match any of the specified behaviors, just return the current state.
<span class="missing-if-branch" title="else path not taken" >E</span>if (!behaviors[type]) return state;
//Validating the payload of an array is more tricky, as we do not know ahead of time if the
//payload should be an object, primitive, or an array. However, we can still validate here based on the
//payload type passed.
<span class="cstat-no" title="statement not covered" > return behaviors[type](state, applyValidation(arrayTypeDescription, payload), initialValue, index);</span>
}
}
&nbsp;
&nbsp;
function <span class="fstat-no" title="function not covered" >applyValidation(</span>arrayTypeDescription: ArrayStructureType, payload: any) {
// Array validation is more tricky than object/primitive, as it is possible that the current
// action may involve updating the contents of a specific array element, rather than the
// whole array. As a result, some extra functionality is required to determine which
// form of validation to apply.
&nbsp;
// First case is simple - if the action payload is an array, then we simply validate it against
// the structure of this reducer.
<span class="cstat-no" title="statement not covered" > if (isArray(payload)) <span class="cstat-no" title="statement not covered" >return validateArray(arrayTypeDescription, payload);</span></span>
&nbsp;
// If a non-array payload has been passed in, then we need to check which form of validation
// to use, by checking the structure of the array.
const { structure } = <span class="cstat-no" title="statement not covered" >arrayTypeDescription();</span>
<span class="cstat-no" title="statement not covered" > if (structure().type === PROP_TYPES._shape) <span class="cstat-no" title="statement not covered" >return validateShape(structure, payload);</span></span>
<span class="cstat-no" title="statement not covered" > return validatePrimitive(structure, payload);</span>
}
&nbsp;
&nbsp;
function createActions(behaviorsConfig: ArrayReducerBehaviorsConfig, locationString: string): ArrayActions {
//Take a reducer behavior config object, and create actions using the location string
return reduce(behaviorsConfig, (memo, behavior, name) =&gt; ({
...memo,
[name]: (value: Array&lt;any&gt;, index: ?number) =&gt; ({
type: `${locationString}.${name}`,
payload: (behavior.action || (<span class="fstat-no" title="function not covered" ><span class="branch-1 cbranch-no" title="branch not covered" >()</span> =&gt; <span class="cstat-no" title="statement not covered" >value)</span></span>)(value),
index,
})
}), {});
}
&nbsp;</pre></td></tr>
</table></pre>
<div class='push'></div><!-- for sticky footer -->
</div><!-- /wrapper -->
<div class='footer quiet pad2 space-top1 center small'>
Code coverage
generated by <a href="http://istanbul-js.org/" target="_blank">istanbul</a> at Sun Dec 11 2016 15:39:29 GMT+0000 (GMT Standard Time)
</div>
</div>
<script src="..\..\prettify.js"></script>
<script>
window.onload = function () {
if (typeof prettyPrint === 'function') {
prettyPrint();
}
};
</script>
<script src="..\..\sorter.js"></script>
</body>
</html>

View File

@ -0,0 +1,119 @@
<!doctype html>
<html lang="en">
<head>
<title>Code coverage report for redux-arg/reducers</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="..\..\prettify.css" />
<link rel="stylesheet" href="..\..\base.css" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<style type='text/css'>
.coverage-summary .sorter {
background-image: url(..\..\sort-arrow-sprite.png);
}
</style>
</head>
<body>
<div class='wrapper'>
<div class='pad1'>
<h1>
<a href="..\..\index.html">All files</a> redux-arg/reducers
</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
<span class="strong">49.33% </span>
<span class="quiet">Statements</span>
<span class='fraction'>37/75</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">27.66% </span>
<span class="quiet">Branches</span>
<span class='fraction'>13/47</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">80% </span>
<span class="quiet">Functions</span>
<span class='fraction'>20/25</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">51.67% </span>
<span class="quiet">Lines</span>
<span class='fraction'>31/60</span>
</div>
</div>
</div>
<div class='status-line low'></div>
<div class="pad1">
<table class="coverage-summary">
<thead>
<tr>
<th data-col="file" data-fmt="html" data-html="true" class="file">File</th>
<th data-col="pic" data-type="number" data-fmt="html" data-html="true" class="pic"></th>
<th data-col="statements" data-type="number" data-fmt="pct" class="pct">Statements</th>
<th data-col="statements_raw" data-type="number" data-fmt="html" class="abs"></th>
<th data-col="branches" data-type="number" data-fmt="pct" class="pct">Branches</th>
<th data-col="branches_raw" data-type="number" data-fmt="html" class="abs"></th>
<th data-col="functions" data-type="number" data-fmt="pct" class="pct">Functions</th>
<th data-col="functions_raw" data-type="number" data-fmt="html" class="abs"></th>
<th data-col="lines" data-type="number" data-fmt="pct" class="pct">Lines</th>
<th data-col="lines_raw" data-type="number" data-fmt="html" class="abs"></th>
</tr>
</thead>
<tbody><tr>
<td class="file low" data-value="arrayReducer.js"><a href="arrayReducer.js.html">arrayReducer.js</a></td>
<td data-value="26.83" class="pic low"><div class="chart"><div class="cover-fill" style="width: 26%;"></div><div class="cover-empty" style="width:74%;"></div></div></td>
<td data-value="26.83" class="pct low">26.83%</td>
<td data-value="41" class="abs low">11/41</td>
<td data-value="13.79" class="pct low">13.79%</td>
<td data-value="29" class="abs low">4/29</td>
<td data-value="66.67" class="pct medium">66.67%</td>
<td data-value="9" class="abs medium">6/9</td>
<td data-value="28.13" class="pct low">28.13%</td>
<td data-value="32" class="abs low">9/32</td>
</tr>
<tr>
<td class="file medium" data-value="objectReducer.js"><a href="objectReducer.js.html">objectReducer.js</a></td>
<td data-value="61.11" class="pic medium"><div class="chart"><div class="cover-fill" style="width: 61%;"></div><div class="cover-empty" style="width:39%;"></div></div></td>
<td data-value="61.11" class="pct medium">61.11%</td>
<td data-value="18" class="abs medium">11/18</td>
<td data-value="30" class="pct low">30%</td>
<td data-value="10" class="abs low">3/10</td>
<td data-value="77.78" class="pct medium">77.78%</td>
<td data-value="9" class="abs medium">7/9</td>
<td data-value="60" class="pct medium">60%</td>
<td data-value="15" class="abs medium">9/15</td>
</tr>
<tr>
<td class="file high" data-value="primitiveReducer.js"><a href="primitiveReducer.js.html">primitiveReducer.js</a></td>
<td data-value="93.75" class="pic high"><div class="chart"><div class="cover-fill" style="width: 93%;"></div><div class="cover-empty" style="width:7%;"></div></div></td>
<td data-value="93.75" class="pct high">93.75%</td>
<td data-value="16" class="abs high">15/16</td>
<td data-value="75" class="pct medium">75%</td>
<td data-value="8" class="abs medium">6/8</td>
<td data-value="100" class="pct high">100%</td>
<td data-value="7" class="abs high">7/7</td>
<td data-value="100" class="pct high">100%</td>
<td data-value="13" class="abs high">13/13</td>
</tr>
</tbody>
</table>
</div><div class='push'></div><!-- for sticky footer -->
</div><!-- /wrapper -->
<div class='footer quiet pad2 space-top1 center small'>
Code coverage
generated by <a href="http://istanbul-js.org/" target="_blank">istanbul</a> at Sun Dec 11 2016 15:39:29 GMT+0000 (GMT Standard Time)
</div>
</div>
<script src="..\..\prettify.js"></script>
<script>
window.onload = function () {
if (typeof prettyPrint === 'function') {
prettyPrint();
}
};
</script>
<script src="..\..\sorter.js"></script>
</body>
</html>

View File

@ -0,0 +1,428 @@
<!doctype html>
<html lang="en">
<head>
<title>Code coverage report for redux-arg/reducers/objectReducer.js</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="..\..\prettify.css" />
<link rel="stylesheet" href="..\..\base.css" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<style type='text/css'>
.coverage-summary .sorter {
background-image: url(..\..\sort-arrow-sprite.png);
}
</style>
</head>
<body>
<div class='wrapper'>
<div class='pad1'>
<h1>
<a href="..\..\index.html">All files</a> / <a href="index.html">redux-arg/reducers</a> objectReducer.js
</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
<span class="strong">61.11% </span>
<span class="quiet">Statements</span>
<span class='fraction'>11/18</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">30% </span>
<span class="quiet">Branches</span>
<span class='fraction'>3/10</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">77.78% </span>
<span class="quiet">Functions</span>
<span class='fraction'>7/9</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">60% </span>
<span class="quiet">Lines</span>
<span class='fraction'>9/15</span>
</div>
</div>
</div>
<div class='status-line medium'></div>
<pre><table class="coverage">
<tr><td class="line-count quiet">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122</td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">2x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">15x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-no">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">//@flow
//==============================
// Flow imports
//==============================
import type { StructureType } from '../structure';
&nbsp;
&nbsp;
//==============================
// Flow types
//==============================
export type ShapeReducerAction = {
type: string,
payload: Object,
};
export type ShapeReducer = (state: Object, action: ShapeReducerAction) =&gt; Object;
export type ShapeReducerBehavior = (state: {}, payload: Object | void, initialState: {}) =&gt; Object;
export type ShapeReducerBehaviorsConfig = {
[key: string]: {
action?: (value: Object) =&gt; Object,
reducer: ShapeReducerBehavior,
}
};
export type ShapeReducerBehaviors = {
[key: string]: ShapeReducerBehavior,
};
export type ShapeAction = (value: Object) =&gt; { type: string, payload: Object };
export type ShapeActions = {
[key: string]: ShapeAction
};
export type ShapeReducerOptions = {
behaviorsConfig: ShapeReducerBehaviorsConfig,
locationString: string,
name: string,
};
&nbsp;
&nbsp;
//==============================
// JS imports
//==============================
import { reduce } from 'lodash';
import { validateShape } from '../validatePayload';
import { createReducerBehaviors } from '../reducers';
import { PROP_TYPES } from '../structure';
&nbsp;
&nbsp;
//==============================
// Shape behaviors
// ----------------
// Shapes differ from primitive reducers by allowing an update behavior, merging the
// payload and the previous state in a shallow way. This supplements the replace
// behavior, which still replaces the previous state with the payload.
//==============================
const DEFAULT_SHAPE_BEHAVIORS: ShapeReducerBehaviorsConfig = {
update: {
action(value) { <span class="cstat-no" title="statement not covered" >return value </span>},
reducer(state, payload = <span class="branch-0 cbranch-no" title="branch not covered" >{})</span> {
<span class="cstat-no" title="statement not covered" > return { ...state, ...payload };</span>
}
},
reset: {
reducer(state, payload, initialState) {
<span class="cstat-no" title="statement not covered" > return initialState;</span>
}
},
replace: {
action(value) { return value },
reducer(state, payload = <span class="branch-0 cbranch-no" title="branch not covered" >{})</span> {
<span class="cstat-no" title="statement not covered" > return payload;</span>
}
}
};
&nbsp;
&nbsp;
export function createShapeReducer(reducerShape: StructureType, {
locationString,
name,
}: ShapeReducerOptions = <span class="branch-0 cbranch-no" title="branch not covered" >{})</span> {
return {
reducers: {
[name]: createReducer(reducerShape, createReducerBehaviors(DEFAULT_SHAPE_BEHAVIORS, locationString)),
},
actions: createActions(DEFAULT_SHAPE_BEHAVIORS, locationString, {}),
};
}
&nbsp;
&nbsp;
function calculateDefaults(reducerStructure) {
return reduce(reducerStructure, <span class="fstat-no" title="function not covered" >(m</span>emo, propValue, propName) =&gt; (<span class="cstat-no" title="statement not covered" >{</span>
...memo,
[propName]: propValue().type === PROP_TYPES._shape
? calculateDefaults(propValue().structure)
: propValue().defaultValue,
}), {});
}
&nbsp;
&nbsp;
function createReducer(objectStructure: StructureType, behaviors: ShapeReducerBehaviors): ShapeReducer {
const initialState: Object = validateShape(objectStructure, calculateDefaults(objectStructure().structure));
return (state = initialState, { type, payload }: ShapeReducerAction) =&gt; {
//If the action type does not match any of the specified behaviors, just return the current state.
<span class="missing-if-branch" title="else path not taken" >E</span>if (!behaviors[type]) return state;
&nbsp;
//Sanitize the payload using the reducer shape, then apply the sanitized
//payload to the state using the behavior linked to this action type.
<span class="cstat-no" title="statement not covered" > return behaviors[type](state, validateShape(objectStructure, payload), initialState);</span>
}
}
&nbsp;
&nbsp;
function createActions(behaviorsConfig: ShapeReducerBehaviorsConfig, locationString: string, defaultPayload: any): ShapeActions {
//Take a reducer behavior config object, and create actions using the location string
return reduce(behaviorsConfig, (memo, behavior, name) =&gt; ({
...memo,
[name]: (value: Object) =&gt; ({
type: `${locationString}.${name}`,
payload: (behavior.action || (<span class="fstat-no" title="function not covered" ><span class="branch-1 cbranch-no" title="branch not covered" >()</span> =&gt; <span class="cstat-no" title="statement not covered" >defaultPayload)</span></span>)(value),
})
}), {});
}
&nbsp;
&nbsp;
&nbsp;</pre></td></tr>
</table></pre>
<div class='push'></div><!-- for sticky footer -->
</div><!-- /wrapper -->
<div class='footer quiet pad2 space-top1 center small'>
Code coverage
generated by <a href="http://istanbul-js.org/" target="_blank">istanbul</a> at Sun Dec 11 2016 15:39:29 GMT+0000 (GMT Standard Time)
</div>
</div>
<script src="..\..\prettify.js"></script>
<script>
window.onload = function () {
if (typeof prettyPrint === 'function') {
prettyPrint();
}
};
</script>
<script src="..\..\sorter.js"></script>
</body>
</html>

View File

@ -0,0 +1,377 @@
<!doctype html>
<html lang="en">
<head>
<title>Code coverage report for redux-arg/reducers/primitiveReducer.js</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="..\..\prettify.css" />
<link rel="stylesheet" href="..\..\base.css" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<style type='text/css'>
.coverage-summary .sorter {
background-image: url(..\..\sort-arrow-sprite.png);
}
</style>
</head>
<body>
<div class='wrapper'>
<div class='pad1'>
<h1>
<a href="..\..\index.html">All files</a> / <a href="index.html">redux-arg/reducers</a> primitiveReducer.js
</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
<span class="strong">93.75% </span>
<span class="quiet">Statements</span>
<span class='fraction'>15/16</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">75% </span>
<span class="quiet">Branches</span>
<span class='fraction'>6/8</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">100% </span>
<span class="quiet">Functions</span>
<span class='fraction'>7/7</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">100% </span>
<span class="quiet">Lines</span>
<span class='fraction'>13/13</span>
</div>
</div>
</div>
<div class='status-line high'></div>
<pre><table class="coverage">
<tr><td class="line-count quiet">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105</td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">2x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">2x</span>
<span class="cline-any cline-yes">2x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">2x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">6x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">6x</span>
<span class="cline-any cline-yes">6x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">67x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">4x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">12x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">5x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">2x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">//@flow
//==============================
// Flow imports
//==============================
import type { PrimitiveType } from '../structure';
&nbsp;
//==============================
// Flow types
//==============================
export type PrimitiveReducerAction = {
type: string,
payload: mixed,
};
export type PrimitiveReducer = (state: mixed, action: PrimitiveReducerAction) =&gt; mixed;
export type PrimitiveReducerBehavior = (state: mixed, payload: mixed | void, initialState: mixed) =&gt; mixed;
export type PrimitiveReducerBehaviorsConfig = {
[key: string]: {
action?: (value: mixed) =&gt; mixed,
reducer: PrimitiveReducerBehavior,
}
};
export type PrimitiveReducerBehaviors = {
[key: string]: PrimitiveReducerBehavior,
};
export type PrimitiveAction = (value: mixed) =&gt; { type: string, payload: mixed };
export type PrimitiveActions = {
[key: string]: PrimitiveAction
};
export type PrimitiveReducerOptions = {
behaviorsConfig: PrimitiveReducerBehaviorsConfig,
locationString: string,
name: string,
};
&nbsp;
//==============================
// JS imports
//==============================
import { reduce } from 'lodash';
import { validatePrimitive } from '../validatePayload';
import { createReducerBehaviors } from '../reducers';
&nbsp;
&nbsp;
//==============================
// Primitive behaviors
// ----------------
// Primitives are the most simple case, as they only have the replace and
// reset behaviors by default.
//==============================
&nbsp;
const DEFAULT_PRIMITIVE_BEHAVIORS: PrimitiveReducerBehaviorsConfig = {
replace: {
action(value) { return value },
reducer(state, payload) {
<span class="missing-if-branch" title="if path not taken" >I</span>if (payload === undefined) <span class="cstat-no" title="statement not covered" >return state;</span>
return payload;
}
},
reset: {
reducer(state, payload, initialState) {
return initialState;
}
},
};
&nbsp;
&nbsp;
export function createPrimitiveReducer(primitiveType: PrimitiveType, {
locationString,
name,
}: PrimitiveReducerOptions = <span class="branch-0 cbranch-no" title="branch not covered" >{})</span> {
return {
reducers: {
[name]: createReducer(primitiveType, createReducerBehaviors(DEFAULT_PRIMITIVE_BEHAVIORS, locationString)),
},
actions: createActions(DEFAULT_PRIMITIVE_BEHAVIORS, locationString, {}),
};
}
&nbsp;
&nbsp;
function createReducer(primitiveType: PrimitiveType, behaviors: PrimitiveReducerBehaviors): PrimitiveReducer {
const initialState: mixed = validatePrimitive(primitiveType, primitiveType().defaultValue);
return (state = initialState, { type, payload }: PrimitiveReducerAction) =&gt; {
//If the action type does not match any of the specified behaviors, just return the current state.
if (!behaviors[type]) return state;
&nbsp;
//Sanitize the payload using the reducer shape, then apply the sanitized
//payload to the state using the behavior linked to this action type.
return behaviors[type](state, validatePrimitive(primitiveType, payload), initialState);
}
}
&nbsp;
&nbsp;
function createActions(behaviorsConfig: PrimitiveReducerBehaviorsConfig, locationString: string, defaultPayload: any): PrimitiveActions {
//Take a reducer behavior config object, and create actions using the location string
return reduce(behaviorsConfig, (memo, behavior, name) =&gt; ({
...memo,
[name]: (value: mixed) =&gt; ({
type: `${locationString}.${name}`,
payload: (behavior.action || (() =&gt; defaultPayload))(value),
})
}), {});
}
&nbsp;
&nbsp;
&nbsp;
&nbsp;</pre></td></tr>
</table></pre>
<div class='push'></div><!-- for sticky footer -->
</div><!-- /wrapper -->
<div class='footer quiet pad2 space-top1 center small'>
Code coverage
generated by <a href="http://istanbul-js.org/" target="_blank">istanbul</a> at Sun Dec 11 2016 15:39:29 GMT+0000 (GMT Standard Time)
</div>
</div>
<script src="..\..\prettify.js"></script>
<script>
window.onload = function () {
if (typeof prettyPrint === 'function') {
prettyPrint();
}
};
</script>
<script src="..\..\sorter.js"></script>
</body>
</html>

View File

@ -0,0 +1,332 @@
<!doctype html>
<html lang="en">
<head>
<title>Code coverage report for redux-arg/structure.js</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="..\prettify.css" />
<link rel="stylesheet" href="..\base.css" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<style type='text/css'>
.coverage-summary .sorter {
background-image: url(..\sort-arrow-sprite.png);
}
</style>
</head>
<body>
<div class='wrapper'>
<div class='pad1'>
<h1>
<a href="..\index.html">All files</a> / <a href="index.html">redux-arg</a> structure.js
</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
<span class="strong">100% </span>
<span class="quiet">Statements</span>
<span class='fraction'>14/14</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">100% </span>
<span class="quiet">Branches</span>
<span class='fraction'>4/4</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">100% </span>
<span class="quiet">Functions</span>
<span class='fraction'>12/12</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">100% </span>
<span class="quiet">Lines</span>
<span class='fraction'>8/8</span>
</div>
</div>
</div>
<div class='status-line high'></div>
<pre><table class="coverage">
<tr><td class="line-count quiet">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90</td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">4x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">4x</span>
<span class="cline-any cline-yes">59x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">28x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">7x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">15x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">28x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">29x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">//@flow
&nbsp;
//==============================
// Flow types
//==============================
export type PropTypeKeys = $Keys&lt;typeof PROP_TYPES&gt;;
&nbsp;
export type ShapeStructure = {
[key: string]: StructureType | PrimitiveType | ArrayStructureType,
}
export type StructureType = () =&gt; {
type: PropTypeKeys,
structure: ShapeStructure | StructureType | PrimitiveType,
defaultValue?: any,
};
export type ReducerType = () =&gt; {
type: PropTypeKeys,
structure: StructureType | PrimitiveType,
};
export type ArrayStructureType = () =&gt; {
type: PropTypeKeys,
structure: StructureType | PrimitiveType,
defaultValue: any,
}
export type PrimitiveType = () =&gt; {
type: PropTypeKeys,
defaultValue?: any,
typeofValue: string,
structure?: PrimitiveType,
};
export type TypesObject = {
[key: string]: CreateArrayType | CreateStringType | CreateNumberType | CreateShapeType | CreateBooleanType;
}
&nbsp;
export type TypesObjectDefaults = {
[key: string]: mixed | TypesArrayDefaults,
}
export type TypesArrayDefaults = Array&lt;mixed&gt; | Array&lt;TypesObjectDefaults&gt;;
&nbsp;
type CreateStringType = (defaultValue: string) =&gt; PrimitiveType;
type CreateNumberType = (defaultValue: number) =&gt; PrimitiveType;
type CreateBooleanType = (defaultValue: boolean) =&gt; PrimitiveType;
type CreateArrayType = (structure: StructureType | PrimitiveType, defaultValue: TypesArrayDefaults | TypesObjectDefaults) =&gt; StructureType;
type CreateShapeType = (structure: ShapeStructure, defaultValue: TypesArrayDefaults | TypesObjectDefaults) =&gt; StructureType;
&nbsp;
//==============================
// Structure
//==============================
export const PROP_TYPES = {
_string: '_string',
_number: '_number',
_boolean: '_boolean',
_reducer: '_reducer',
_shape: '_shape',
_array: '_array',
};
&nbsp;
//The types objects are used in order to build up the structure of a store chunk, and provide/accept
//default values whilst doing so.
export const Types: TypesObject = {
string: (defaultValue: string = '') =&gt; () =&gt; ({
type: PROP_TYPES._string,
defaultValue,
typeofValue: 'string',
}),
number: (defaultValue: number = 0) =&gt; () =&gt; ({
type: PROP_TYPES._number,
defaultValue,
typeofValue: 'number',
}),
boolean: (defaultValue: boolean = false) =&gt; () =&gt; ({
type: PROP_TYPES._boolean,
defaultValue,
typeofValue: 'boolean',
}),
arrayOf: (structure: StructureType | PrimitiveType, defaultValue = []) =&gt; () =&gt; ({
type: PROP_TYPES._array,
structure,
defaultValue,
}),
reducer: (structure: ShapeStructure) =&gt; () =&gt; ({
type: PROP_TYPES._reducer,
structure,
}),
shape: (structure: ShapeStructure) =&gt; () =&gt; ({
type: PROP_TYPES._shape,
structure,
}),
};
&nbsp;</pre></td></tr>
</table></pre>
<div class='push'></div><!-- for sticky footer -->
</div><!-- /wrapper -->
<div class='footer quiet pad2 space-top1 center small'>
Code coverage
generated by <a href="http://istanbul-js.org/" target="_blank">istanbul</a> at Sun Dec 11 2016 15:39:29 GMT+0000 (GMT Standard Time)
</div>
</div>
<script src="..\prettify.js"></script>
<script>
window.onload = function () {
if (typeof prettyPrint === 'function') {
prettyPrint();
}
};
</script>
<script src="..\sorter.js"></script>
</body>
</html>

View File

@ -0,0 +1,122 @@
<!doctype html>
<html lang="en">
<head>
<title>Code coverage report for redux-arg/utils/arrayUtils.js</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="..\..\prettify.css" />
<link rel="stylesheet" href="..\..\base.css" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<style type='text/css'>
.coverage-summary .sorter {
background-image: url(..\..\sort-arrow-sprite.png);
}
</style>
</head>
<body>
<div class='wrapper'>
<div class='pad1'>
<h1>
<a href="..\..\index.html">All files</a> / <a href="index.html">redux-arg/utils</a> arrayUtils.js
</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
<span class="strong">100% </span>
<span class="quiet">Statements</span>
<span class='fraction'>10/10</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">100% </span>
<span class="quiet">Branches</span>
<span class='fraction'>12/12</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">100% </span>
<span class="quiet">Functions</span>
<span class='fraction'>2/2</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">100% </span>
<span class="quiet">Lines</span>
<span class='fraction'>6/6</span>
</div>
</div>
</div>
<div class='status-line high'></div>
<pre><table class="coverage">
<tr><td class="line-count quiet">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20</td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">6x</span>
<span class="cline-any cline-yes">4x</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">6x</span>
<span class="cline-any cline-yes">4x</span>
<span class="cline-any cline-yes">3x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">//@flow
export function updateAtIndex(array: Array&lt;any&gt;, value: any, index: number): Array&lt;any&gt; {
if (typeof index !== 'number') throw new Error('Must provide a numeric index to updateAtIndex');
if (index &lt; 0 || index &gt; array.length - 1) throw new Error(`The index ${index} is out of range for the array provided`);
return [
...array.slice(0,index),
value,
...array.slice(index + 1),
];
}
&nbsp;
export function removeAtIndex(array: Array&lt;any&gt;, index: number): Array&lt;any&gt; {
if (typeof index !== 'number') throw new Error('Must provide a numeric index to removeAtIndex');
if (index &lt; 0 || index &gt; array.length - 1) throw new Error(`The index ${index} is out of range for the array provided`);
return [
...array.slice(0, index),
...array.slice(index + 1),
];
}
&nbsp;</pre></td></tr>
</table></pre>
<div class='push'></div><!-- for sticky footer -->
</div><!-- /wrapper -->
<div class='footer quiet pad2 space-top1 center small'>
Code coverage
generated by <a href="http://istanbul-js.org/" target="_blank">istanbul</a> at Sun Dec 11 2016 15:39:29 GMT+0000 (GMT Standard Time)
</div>
</div>
<script src="..\..\prettify.js"></script>
<script>
window.onload = function () {
if (typeof prettyPrint === 'function') {
prettyPrint();
}
};
</script>
<script src="..\..\sorter.js"></script>
</body>
</html>

View File

@ -0,0 +1,93 @@
<!doctype html>
<html lang="en">
<head>
<title>Code coverage report for redux-arg/utils</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="..\..\prettify.css" />
<link rel="stylesheet" href="..\..\base.css" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<style type='text/css'>
.coverage-summary .sorter {
background-image: url(..\..\sort-arrow-sprite.png);
}
</style>
</head>
<body>
<div class='wrapper'>
<div class='pad1'>
<h1>
<a href="..\..\index.html">All files</a> redux-arg/utils
</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
<span class="strong">100% </span>
<span class="quiet">Statements</span>
<span class='fraction'>10/10</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">100% </span>
<span class="quiet">Branches</span>
<span class='fraction'>12/12</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">100% </span>
<span class="quiet">Functions</span>
<span class='fraction'>2/2</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">100% </span>
<span class="quiet">Lines</span>
<span class='fraction'>6/6</span>
</div>
</div>
</div>
<div class='status-line high'></div>
<div class="pad1">
<table class="coverage-summary">
<thead>
<tr>
<th data-col="file" data-fmt="html" data-html="true" class="file">File</th>
<th data-col="pic" data-type="number" data-fmt="html" data-html="true" class="pic"></th>
<th data-col="statements" data-type="number" data-fmt="pct" class="pct">Statements</th>
<th data-col="statements_raw" data-type="number" data-fmt="html" class="abs"></th>
<th data-col="branches" data-type="number" data-fmt="pct" class="pct">Branches</th>
<th data-col="branches_raw" data-type="number" data-fmt="html" class="abs"></th>
<th data-col="functions" data-type="number" data-fmt="pct" class="pct">Functions</th>
<th data-col="functions_raw" data-type="number" data-fmt="html" class="abs"></th>
<th data-col="lines" data-type="number" data-fmt="pct" class="pct">Lines</th>
<th data-col="lines_raw" data-type="number" data-fmt="html" class="abs"></th>
</tr>
</thead>
<tbody><tr>
<td class="file high" data-value="arrayUtils.js"><a href="arrayUtils.js.html">arrayUtils.js</a></td>
<td data-value="100" class="pic high"><div class="chart"><div class="cover-fill cover-full" style="width: 100%;"></div><div class="cover-empty" style="width:0%;"></div></div></td>
<td data-value="100" class="pct high">100%</td>
<td data-value="10" class="abs high">10/10</td>
<td data-value="100" class="pct high">100%</td>
<td data-value="12" class="abs high">12/12</td>
<td data-value="100" class="pct high">100%</td>
<td data-value="2" class="abs high">2/2</td>
<td data-value="100" class="pct high">100%</td>
<td data-value="6" class="abs high">6/6</td>
</tr>
</tbody>
</table>
</div><div class='push'></div><!-- for sticky footer -->
</div><!-- /wrapper -->
<div class='footer quiet pad2 space-top1 center small'>
Code coverage
generated by <a href="http://istanbul-js.org/" target="_blank">istanbul</a> at Sun Dec 11 2016 15:39:29 GMT+0000 (GMT Standard Time)
</div>
</div>
<script src="..\..\prettify.js"></script>
<script>
window.onload = function () {
if (typeof prettyPrint === 'function') {
prettyPrint();
}
};
</script>
<script src="..\..\sorter.js"></script>
</body>
</html>

View File

@ -0,0 +1,296 @@
<!doctype html>
<html lang="en">
<head>
<title>Code coverage report for redux-arg/validatePayload.js</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="..\prettify.css" />
<link rel="stylesheet" href="..\base.css" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<style type='text/css'>
.coverage-summary .sorter {
background-image: url(..\sort-arrow-sprite.png);
}
</style>
</head>
<body>
<div class='wrapper'>
<div class='pad1'>
<h1>
<a href="..\index.html">All files</a> / <a href="index.html">redux-arg</a> validatePayload.js
</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
<span class="strong">100% </span>
<span class="quiet">Statements</span>
<span class='fraction'>29/29</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">100% </span>
<span class="quiet">Branches</span>
<span class='fraction'>12/12</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">100% </span>
<span class="quiet">Functions</span>
<span class='fraction'>7/7</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">100% </span>
<span class="quiet">Lines</span>
<span class='fraction'>26/26</span>
</div>
</div>
</div>
<div class='status-line high'></div>
<pre><table class="coverage">
<tr><td class="line-count quiet">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78</td><td class="line-coverage quiet"><span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">11x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">10x</span>
<span class="cline-any cline-yes">15x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">15x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">14x</span>
<span class="cline-any cline-yes">14x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">13x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">35x</span>
<span class="cline-any cline-yes">4x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">7x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">6x</span>
<span class="cline-any cline-yes">6x</span>
<span class="cline-any cline-yes">14x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">29x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">29x</span>
<span class="cline-any cline-yes">29x</span>
<span class="cline-any cline-yes">1x</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-neutral">&nbsp;</span>
<span class="cline-any cline-yes">28x</span>
<span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">//@flow
//==============================
// Flow imports and types
//==============================
import type { PrimitiveType, StructureType, ShapeStructure } from './structure';
&nbsp;
type validationFunction = (structure: StructureType | PrimitiveType | ShapeStructure, value: any) =&gt; any;
&nbsp;
//==============================
// JS imports
//==============================
import { reduce, isObject } from 'lodash';
import { PROP_TYPES } from './structure';
&nbsp;
export function validateShape(objectStructure: any, value: mixed): Object {
if (!isObject(value)) {
console.error(`The value passed to validateObject() was not an object. Value: `, value);
return {};
}
&nbsp;
return reduce(value, (memo, value, name) =&gt; {
const valueType = objectStructure().structure[name];
//If the value type does not exist in the reducer structure, we don't want to include it in the payload.
//Display a console error for the developer, and skip the inclusion of this property in the payload.
if (!valueType) {
console.warn(`The property, ${name}, was not specified in the structure` +
' and was stripped out of the payload. Structure: ', objectStructure().structure);
return memo;
}
&nbsp;
const validatedValue = getTypeValidation(valueType().type)(valueType, value);
if (validatedValue === undefined) {
console.warn(`The property, ${name}, was populated with a type ${ typeof value } which does not` +
' match that specified in the reducer configuration. It has been stripped from' +
' the payload');
return memo;
}
&nbsp;
return {
...memo,
[name]: validatedValue,
}
}, {});
}
&nbsp;
export function validatePrimitive(primitive: any, value: any): mixed {
//Validate primitives using the typeofValue property of the primitive type definitions.
if (typeof value === primitive().typeofValue ) return value;
return console.warn(`The value, ${value}, did not match the type specified (${primitive().type}).`);
}
&nbsp;
export function validateArray(arrayStructure: any, value: Array&lt;any&gt;): Array&lt;mixed&gt; {
//Validate arrays by performing either of the other validation types to each element of the array,
//based on the provided reducer structure.
if (!Array.isArray(value)) {
console.error(`The value passed to validateArray() was not an array. Value: `, value);
return [];
}
const elementStructure = arrayStructure().structure;
const elementType = elementStructure().type;
return value.map(element =&gt; getTypeValidation(elementType)(elementStructure, element)).filter(e =&gt; e);
}
&nbsp;
export function getTypeValidation(type: string): validationFunction {
const TYPE_VALIDATIONS = {
[PROP_TYPES._string]: validatePrimitive,
[PROP_TYPES._number]: validatePrimitive,
[PROP_TYPES._boolean]: validatePrimitive,
[PROP_TYPES._array]: validateArray,
[PROP_TYPES._shape]: validateShape,
};
const typeValidation = TYPE_VALIDATIONS[type];
if (!typeValidation) {
throw new Error(`The type ${type} does not have a corresponding
validation function!`);
}
return typeValidation;
}</pre></td></tr>
</table></pre>
<div class='push'></div><!-- for sticky footer -->
</div><!-- /wrapper -->
<div class='footer quiet pad2 space-top1 center small'>
Code coverage
generated by <a href="http://istanbul-js.org/" target="_blank">istanbul</a> at Sun Dec 11 2016 15:39:29 GMT+0000 (GMT Standard Time)
</div>
</div>
<script src="..\prettify.js"></script>
<script>
window.onload = function () {
if (typeof prettyPrint === 'function') {
prettyPrint();
}
};
</script>
<script src="..\sorter.js"></script>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 B

View File

@ -0,0 +1,158 @@
var addSorting = (function () {
"use strict";
var cols,
currentSort = {
index: 0,
desc: false
};
// returns the summary table element
function getTable() { return document.querySelector('.coverage-summary'); }
// returns the thead element of the summary table
function getTableHeader() { return getTable().querySelector('thead tr'); }
// returns the tbody element of the summary table
function getTableBody() { return getTable().querySelector('tbody'); }
// returns the th element for nth column
function getNthColumn(n) { return getTableHeader().querySelectorAll('th')[n]; }
// loads all columns
function loadColumns() {
var colNodes = getTableHeader().querySelectorAll('th'),
colNode,
cols = [],
col,
i;
for (i = 0; i < colNodes.length; i += 1) {
colNode = colNodes[i];
col = {
key: colNode.getAttribute('data-col'),
sortable: !colNode.getAttribute('data-nosort'),
type: colNode.getAttribute('data-type') || 'string'
};
cols.push(col);
if (col.sortable) {
col.defaultDescSort = col.type === 'number';
colNode.innerHTML = colNode.innerHTML + '<span class="sorter"></span>';
}
}
return cols;
}
// attaches a data attribute to every tr element with an object
// of data values keyed by column name
function loadRowData(tableRow) {
var tableCols = tableRow.querySelectorAll('td'),
colNode,
col,
data = {},
i,
val;
for (i = 0; i < tableCols.length; i += 1) {
colNode = tableCols[i];
col = cols[i];
val = colNode.getAttribute('data-value');
if (col.type === 'number') {
val = Number(val);
}
data[col.key] = val;
}
return data;
}
// loads all row data
function loadData() {
var rows = getTableBody().querySelectorAll('tr'),
i;
for (i = 0; i < rows.length; i += 1) {
rows[i].data = loadRowData(rows[i]);
}
}
// sorts the table using the data for the ith column
function sortByIndex(index, desc) {
var key = cols[index].key,
sorter = function (a, b) {
a = a.data[key];
b = b.data[key];
return a < b ? -1 : a > b ? 1 : 0;
},
finalSorter = sorter,
tableBody = document.querySelector('.coverage-summary tbody'),
rowNodes = tableBody.querySelectorAll('tr'),
rows = [],
i;
if (desc) {
finalSorter = function (a, b) {
return -1 * sorter(a, b);
};
}
for (i = 0; i < rowNodes.length; i += 1) {
rows.push(rowNodes[i]);
tableBody.removeChild(rowNodes[i]);
}
rows.sort(finalSorter);
for (i = 0; i < rows.length; i += 1) {
tableBody.appendChild(rows[i]);
}
}
// removes sort indicators for current column being sorted
function removeSortIndicators() {
var col = getNthColumn(currentSort.index),
cls = col.className;
cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, '');
col.className = cls;
}
// adds sort indicators for current column being sorted
function addSortIndicators() {
getNthColumn(currentSort.index).className += currentSort.desc ? ' sorted-desc' : ' sorted';
}
// adds event listeners for all sorter widgets
function enableUI() {
var i,
el,
ithSorter = function ithSorter(i) {
var col = cols[i];
return function () {
var desc = col.defaultDescSort;
if (currentSort.index === i) {
desc = !currentSort.desc;
}
sortByIndex(i, desc);
removeSortIndicators();
currentSort.index = i;
currentSort.desc = desc;
addSortIndicators();
};
};
for (i =0 ; i < cols.length; i += 1) {
if (cols[i].sortable) {
// add the click event handler on the th so users
// dont have to click on those tiny arrows
el = getNthColumn(i).querySelector('.sorter').parentElement;
if (el.addEventListener) {
el.addEventListener('click', ithSorter(i));
} else {
el.attachEvent('onclick', ithSorter(i));
}
}
}
}
// adds sorting functionality to the UI
return function () {
if (!getTable()) {
return;
}
cols = loadColumns();
loadData(cols);
addSortIndicators();
enableUI();
};
})();
window.addEventListener('load', addSorting);

409
coverage/lcov.info Normal file
View File

@ -0,0 +1,409 @@
TN:
SF:F:\GitRepos\redux-arg\src\redux-arg\buildStoreChunk.js
FN:22,buildStoreChunk
FN:23,(anonymous_1)
FN:49,combineStoreChunkReducers
FN:58,processStructure
FN:64,(anonymous_4)
FN:73,(anonymous_5)
FN:97,(anonymous_6)
FNF:7
FNH:7
FNDA:7,buildStoreChunk
FNDA:6,(anonymous_1)
FNDA:6,combineStoreChunkReducers
FNDA:10,processStructure
FNDA:2,(anonymous_4)
FNDA:1,(anonymous_5)
FNDA:6,(anonymous_6)
DA:23,6
DA:29,7
DA:30,6
DA:45,6
DA:46,4
DA:53,6
DA:63,10
DA:64,10
DA:70,10
DA:73,1
DA:85,10
DA:97,6
LF:12
LH:12
BRDA:22,0,0,5
BRDA:23,1,0,5
BRDA:24,2,0,5
BRDA:29,3,0,1
BRDA:29,3,1,6
BRDA:45,4,0,2
BRDA:45,4,1,4
BRDA:70,5,0,2
BRDA:70,5,1,8
BRDA:72,6,0,1
BRDA:72,6,1,1
BRDA:97,7,0,2
BRDA:97,7,1,8
BRF:13
BRH:13
end_of_record
TN:
SF:F:\GitRepos\redux-arg\src\redux-arg\reducers.js
FN:53,determineReducerType
FN:76,callReducer
FN:88,createReducerBehaviors
FN:94,(anonymous_3)
FN:100,calculateDefaults
FN:111,(anonymous_5)
FNF:6
FNH:6
FNDA:14,determineReducerType
FNDA:9,callReducer
FNDA:9,createReducerBehaviors
FNDA:22,(anonymous_3)
FNDA:12,calculateDefaults
FNDA:6,(anonymous_5)
DA:45,2
DA:63,14
DA:64,14
DA:66,14
DA:68,13
DA:82,9
DA:94,22
DA:106,12
DA:107,12
DA:109,12
DA:111,6
DA:117,2
LF:12
LH:12
BRDA:56,0,0,13
BRDA:66,1,0,1
BRDA:66,1,1,13
BRDA:106,2,0,9
BRDA:106,3,0,3
BRDA:109,4,0,9
BRDA:109,4,1,3
BRF:7
BRH:7
end_of_record
TN:
SF:F:\GitRepos\redux-arg\src\redux-arg\structure.js
FN:61,(anonymous_0)
FN:61,(anonymous_1)
FN:66,(anonymous_2)
FN:66,(anonymous_3)
FN:71,(anonymous_4)
FN:71,(anonymous_5)
FN:76,(anonymous_6)
FN:76,(anonymous_7)
FN:81,(anonymous_8)
FN:81,(anonymous_9)
FN:85,(anonymous_10)
FN:85,(anonymous_11)
FNF:12
FNH:12
FNDA:24,(anonymous_0)
FNDA:59,(anonymous_1)
FNDA:16,(anonymous_2)
FNDA:28,(anonymous_3)
FNDA:7,(anonymous_4)
FNDA:7,(anonymous_5)
FNDA:11,(anonymous_6)
FNDA:15,(anonymous_7)
FNDA:18,(anonymous_8)
FNDA:28,(anonymous_9)
FNDA:14,(anonymous_10)
FNDA:29,(anonymous_11)
DA:49,4
DA:60,4
DA:61,59
DA:66,28
DA:71,7
DA:76,15
DA:81,28
DA:85,29
LF:8
LH:8
BRDA:61,0,0,17
BRDA:66,1,0,14
BRDA:71,2,0,6
BRDA:76,3,0,10
BRF:4
BRH:4
end_of_record
TN:
SF:F:\GitRepos\redux-arg\src\redux-arg\validatePayload.js
FN:15,validateShape
FN:21,(anonymous_1)
FN:46,validatePrimitive
FN:52,validateArray
FN:61,(anonymous_4)
FN:61,(anonymous_5)
FN:64,getTypeValidation
FNF:7
FNH:7
FNDA:11,validateShape
FNDA:15,(anonymous_1)
FNDA:35,validatePrimitive
FNDA:7,validateArray
FNDA:14,(anonymous_4)
FNDA:14,(anonymous_5)
FNDA:29,getTypeValidation
DA:16,11
DA:17,1
DA:18,1
DA:21,10
DA:22,15
DA:25,15
DA:26,1
DA:28,1
DA:31,14
DA:32,14
DA:33,1
DA:36,1
DA:39,13
DA:48,35
DA:49,4
DA:55,7
DA:56,1
DA:57,1
DA:59,6
DA:60,6
DA:61,14
DA:65,29
DA:72,29
DA:73,29
DA:74,1
DA:77,28
LF:26
LH:26
BRDA:16,0,0,1
BRDA:16,0,1,10
BRDA:25,1,0,1
BRDA:25,1,1,14
BRDA:32,2,0,1
BRDA:32,2,1,13
BRDA:48,3,0,31
BRDA:48,3,1,4
BRDA:55,4,0,1
BRDA:55,4,1,6
BRDA:73,5,0,1
BRDA:73,5,1,28
BRF:12
BRH:12
end_of_record
TN:
SF:F:\GitRepos\redux-arg\src\redux-arg\reducers\arrayReducer.js
FN:47,checkIndex
FN:112,createArrayReducer
FN:125,createReducer
FN:131,(anonymous_3)
FN:142,applyValidation
FN:160,createActions
FN:162,(anonymous_6)
FN:164,(anonymous_7)
FN:166,(anonymous_8)
FNF:9
FNH:6
FNDA:0,checkIndex
FNDA:1,createArrayReducer
FNDA:1,createReducer
FNDA:15,(anonymous_3)
FNDA:0,applyValidation
FNDA:1,createActions
FNDA:6,(anonymous_6)
FNDA:1,(anonymous_7)
FNDA:0,(anonymous_8)
DA:48,0
DA:49,0
DA:50,0
DA:52,0
DA:65,2
DA:69,0
DA:70,0
DA:71,0
DA:72,0
DA:77,0
DA:78,0
DA:83,0
DA:84,0
DA:89,0
DA:90,0
DA:91,0
DA:97,1
DA:98,1
DA:101,0
DA:106,0
DA:116,1
DA:128,1
DA:131,1
DA:133,15
DA:137,0
DA:150,0
DA:154,0
DA:155,0
DA:156,0
DA:162,6
DA:164,1
DA:166,0
LF:32
LH:9
BRDA:48,0,0,0
BRDA:48,0,1,0
BRDA:48,1,0,0
BRDA:48,1,1,0
BRDA:68,2,0,0
BRDA:69,3,0,0
BRDA:69,3,1,0
BRDA:70,4,0,0
BRDA:70,4,1,0
BRDA:70,5,0,0
BRDA:70,5,1,0
BRDA:71,6,0,0
BRDA:71,6,1,0
BRDA:71,7,0,0
BRDA:71,7,1,0
BRDA:90,8,0,0
BRDA:90,8,1,0
BRDA:97,9,0,0
BRDA:97,9,1,1
BRDA:112,10,0,0
BRDA:131,11,0,11
BRDA:133,12,0,15
BRDA:133,12,1,0
BRDA:150,13,0,0
BRDA:150,13,1,0
BRDA:155,14,0,0
BRDA:155,14,1,0
BRDA:166,15,0,1
BRDA:166,15,1,0
BRF:29
BRH:4
end_of_record
TN:
SF:F:\GitRepos\redux-arg\src\redux-arg\reducers\objectReducer.js
FN:74,createShapeReducer
FN:87,calculateDefaults
FN:88,(anonymous_2)
FN:97,createReducer
FN:99,(anonymous_4)
FN:110,createActions
FN:112,(anonymous_6)
FN:114,(anonymous_7)
FN:116,(anonymous_8)
FNF:9
FNH:7
FNDA:1,createShapeReducer
FNDA:1,calculateDefaults
FNDA:0,(anonymous_2)
FNDA:1,createReducer
FNDA:15,(anonymous_4)
FNDA:1,createActions
FNDA:3,(anonymous_6)
FNDA:1,(anonymous_7)
FNDA:0,(anonymous_8)
DA:53,2
DA:55,0
DA:57,0
DA:62,0
DA:66,1
DA:68,0
DA:78,1
DA:88,1
DA:98,1
DA:99,1
DA:101,15
DA:105,0
DA:112,3
DA:114,1
DA:116,0
LF:15
LH:9
BRDA:56,0,0,0
BRDA:67,1,0,0
BRDA:74,2,0,0
BRDA:90,3,0,0
BRDA:90,3,1,0
BRDA:99,4,0,11
BRDA:101,5,0,15
BRDA:101,5,1,0
BRDA:116,6,0,1
BRDA:116,6,1,0
BRF:10
BRH:3
end_of_record
TN:
SF:F:\GitRepos\redux-arg\src\redux-arg\reducers\primitiveReducer.js
FN:66,createPrimitiveReducer
FN:79,createReducer
FN:81,(anonymous_2)
FN:92,createActions
FN:94,(anonymous_4)
FN:96,(anonymous_5)
FN:98,(anonymous_6)
FNF:7
FNH:7
FNDA:6,createPrimitiveReducer
FNDA:6,createReducer
FNDA:67,(anonymous_2)
FNDA:6,createActions
FNDA:12,(anonymous_4)
FNDA:5,(anonymous_5)
FNDA:2,(anonymous_6)
DA:50,2
DA:52,3
DA:54,2
DA:55,2
DA:60,2
DA:70,6
DA:80,6
DA:81,6
DA:83,67
DA:87,4
DA:94,12
DA:96,5
DA:98,2
LF:13
LH:13
BRDA:54,0,0,0
BRDA:54,0,1,2
BRDA:66,1,0,0
BRDA:81,2,0,51
BRDA:83,3,0,63
BRDA:83,3,1,4
BRDA:98,4,0,5
BRDA:98,4,1,2
BRF:8
BRH:6
end_of_record
TN:
SF:F:\GitRepos\redux-arg\src\redux-arg\utils\arrayUtils.js
FN:2,updateAtIndex
FN:12,removeAtIndex
FNF:2
FNH:2
FNDA:6,updateAtIndex
FNDA:6,removeAtIndex
DA:3,6
DA:4,4
DA:5,3
DA:13,6
DA:14,4
DA:15,3
LF:6
LH:6
BRDA:3,0,0,2
BRDA:3,0,1,4
BRDA:4,1,0,1
BRDA:4,1,1,3
BRDA:4,2,0,4
BRDA:4,2,1,4
BRDA:13,3,0,2
BRDA:13,3,1,4
BRDA:14,4,0,1
BRDA:14,4,1,3
BRDA:14,5,0,4
BRDA:14,5,1,4
BRF:12
BRH:12
end_of_record

8
dist/test.bundle.js vendored
View File

@ -10,7 +10,7 @@
/******/ var script = document.createElement("script");
/******/ script.type = "text/javascript";
/******/ script.charset = "utf-8";
/******/ script.src = __webpack_require__.p + "" + chunkId + "." + hotCurrentHash + ".hot-update.js";
/******/ script.src = __webpack_require__.p + "" + chunkId + "." + hotCurrentHash + ".hot-replace.js";
/******/ head.appendChild(script);
/******/ }
@ -19,7 +19,7 @@
/******/ return callback(new Error("No browser support"));
/******/ try {
/******/ var request = new XMLHttpRequest();
/******/ var requestPath = __webpack_require__.p + "" + hotCurrentHash + ".hot-update.json";
/******/ var requestPath = __webpack_require__.p + "" + hotCurrentHash + ".hot-replace.json";
/******/ request.open("GET", requestPath, true);
/******/ request.timeout = 10000;
/******/ request.send(null);
@ -32,7 +32,7 @@
/******/ // timeout
/******/ callback(new Error("Manifest request to " + requestPath + " timed out."));
/******/ } else if(request.status === 404) {
/******/ // no update available
/******/ // no replace available
/******/ callback();
/******/ } else if(request.status !== 200 && request.status !== 304) {
/******/ // other failure
@ -220,7 +220,7 @@
/******/ var hotAvailibleFilesMap = {};
/******/ var hotCallback;
/******/ // The update info
/******/ // The replace info
/******/ var hotUpdate, hotUpdateNewHash;
/******/ function toModuleId(id) {

View File

@ -1,4 +1,4 @@
import { buildStoreChunk } from './redux-arg/buildReducers';
import { buildStoreChunk } from './redux-arg/buildStoreChunk';
import { createStore, compose, combineReducers } from 'redux';
import { Types } from './redux-arg/structure';
@ -44,7 +44,7 @@ const store = createStore(
compose(window.devToolsExtension ? window.devToolsExtension() : f => f)
);
store.dispatch(test.actions.example.form2.update({ lowerLevel: 2, lowerLevel2: 'Rawrg', lowerLevelArray: [3, 'foo'] }));
store.dispatch(test.actions.example.form2.replace({ lowerLevel: 2, lowerLevel2: 'Rawrg', lowerLevelArray: [3, 'foo'] }));
store.dispatch(test.actions.example.form2.reset());
store.dispatch(test.actions.example.form2.replace({ toast: 'nommyNom' }));
store.dispatch(test.actions.example.form2.reset());
@ -58,5 +58,5 @@ store.dispatch(test.actions.example.arrayTest.replace([1,2,3]));
store.dispatch(test.actions.example.arrayTest.updateAtIndex(5, 0));
store.dispatch(test.actions.example.arrayTest.updateAtIndex('foo', 0));
store.dispatch(test.actions.example.primitiveTest.update(5));
store.dispatch(test.actions.example.primitiveTest.replace(5));
store.dispatch(test.actions.example.primitiveTest.reset());

View File

@ -0,0 +1,118 @@
import {
buildStoreChunk,
processStructure,
} from '../buildStoreChunk';
import {
Types,
} from '../structure';
import {
createStore,
combineReducers,
} from 'redux';
describe('buildStoreChunk', () => {
describe('buildStoreChunk', () => {
it('Will throw error if a structure is not defined', () => {
expect(() => buildStoreChunk('toast')).toThrowError(/structure/);
});
it('Will accept a single reducer (no nesting)', () => {
expect(Object.keys(buildStoreChunk('toast', Types.reducer(Types.string()) )) )
.toEqual(['reducers', 'actions', 'selectors']);
});
it('Will return an object containing reducers, actions, and selectors as the result', () => {
expect(Object.keys(buildStoreChunk('toast', {
example: Types.reducer(Types.string()),
}))).toEqual(['reducers', 'actions', 'selectors']);
});
describe('Resulting chunk', () => {
const chunk = buildStoreChunk('example', {
nested1: Types.reducer(Types.string('foo')),
nested2: Types.reducer(Types.shape()),
nested3: Types.reducer(Types.arrayOf(Types.number())),
nested4: Types.reducer({
innerNested1: Types.reducer(Types.string('bar')),
innerNested2: Types.reducer({
innerNested3: Types.reducer(Types.string('baz')),
}),
}),
});
const nonNestedChunk = buildStoreChunk('example2', Types.reducer(Types.string('foo')));
describe('Selectors', () => {
const store = createStore(combineReducers({
...chunk.reducers,
}));
it('Selectors object has the correct top level structure for a nested chunk', () => {
expect(Object.keys(chunk.selectors)).toEqual(['nested1', 'nested2', 'nested3', 'nested4']);
});
it('Selectors object has the correct top level structure for a non nested chunk', () => {
expect(Object.keys(nonNestedChunk.selectors)).toEqual(['example2']);
});
it('Nested selectors object has the correct structure for a defined reducer', () => {
expect(Object.keys(chunk.selectors.nested4)).toEqual(['innerNested1', 'innerNested2']);
});
it('Selector returns correct value', () => {
expect(chunk.selectors.nested1(store.getState())).toEqual('foo');
});
it('Nested selector returns correct value', () => {
expect(chunk.selectors.nested4.innerNested1(store.getState())).toEqual('bar');
});
});
describe('Actions', () => {
it('Actions object has the correct top level structure for a nested chunk', () => {
expect(Object.keys(chunk.actions)).toEqual(['nested1', 'nested2', 'nested3', 'nested4']);
});
it('Actions object has the correct top level structure for a non nested chunk', () => {
expect(Object.keys(nonNestedChunk.actions)).toEqual(['example2']);
});
it('Nested actions object has the correct structure for a chunk', () => {
expect(Object.keys(chunk.actions.nested4)).toEqual(['innerNested1', 'innerNested2']);
});
it('Replace actions return an object that contains a type and payload', () => {
expect(Object.keys(chunk.actions.nested1.replace('bar'))).toEqual(['type', 'payload']);
expect(Object.keys(chunk.actions.nested2.replace({}))).toEqual(['type', 'payload']);
expect(Object.keys(chunk.actions.nested3.replace([]))).toEqual(['type', 'payload', 'index']);
});
});
describe('Combined actions and selectors (nested chunk)', () => {
const store = createStore(combineReducers({
...chunk.reducers,
...nonNestedChunk.reducers,
}));
it('Dispatching an action should correctly update the store', () => {
store.dispatch(chunk.actions.nested1.replace('bar'));
expect(chunk.selectors.nested1(store.getState())).toEqual('bar');
store.dispatch(chunk.actions.nested1.reset());
expect(chunk.selectors.nested1(store.getState())).toEqual('foo');
});
});
describe('Combined actions and selectors (non nested chunk)', () => {
const store = createStore(combineReducers({
...chunk.reducers,
...nonNestedChunk.reducers,
}));
it('Dispatching an action should correctly update the store', () => {
store.dispatch(nonNestedChunk.actions.example2.replace('bar'));
expect(nonNestedChunk.selectors.example2(store.getState())).toEqual('bar');
store.dispatch(nonNestedChunk.actions.example2.reset());
expect(nonNestedChunk.selectors.example2(store.getState())).toEqual('foo');
});
});
});
});
describe('processStructure', () => {
});
});

View File

@ -1,10 +1,20 @@
//@flow
import { Types } from '../structure';
import { calculateDefaults } from '../reducers';
import {
Types,
PROP_TYPES,
} from '../structure';
import {
calculateDefaults,
determineReducerType,
callReducer,
createReducerBehaviors,
REDUCER_CREATOR_MAPPING,
} from '../reducers';
import { forEach, omit } from 'lodash';
describe('reducers', () => {
describe('defaultValues', () => {
describe('calculateDefaults', () => {
it('Should provide correct default values for a given primitive type', () => {
expect(calculateDefaults(Types.string('toast'))).toBe('toast');
expect(calculateDefaults(Types.number(3))).toBe(3);
@ -38,4 +48,62 @@ describe('reducers', () => {
});
});
describe('determineReducerType', () => {
it('should return the correct creator function for the default mapping', () => {
forEach(omit(Types, 'reducer'), structureType => {
const returnVal = determineReducerType(Types.reducer(structureType()), {
name: 'toast',
locationString: 'toasty',
});
expect({
...returnVal,
reducerFn: returnVal.reducerFn.name,
reducerStructureDescriptor: returnVal.reducerStructureDescriptor.name,
}).toEqual({
name: 'toast',
reducerFn: REDUCER_CREATOR_MAPPING[structureType()().type].name,
reducerStructureDescriptor: '', //The internal functions should be anonymous
locationString: 'toasty',
});
});
});
it('should throw an error if the type provided does not match any in the mapping', () => {
expect(() => determineReducerType(Types.reducer(Types.string()), {
name: 'toast',
locationString: 'toasty',
reducerCreatorMapping: omit(REDUCER_CREATOR_MAPPING, PROP_TYPES._string),
})).toThrowError(/createReducer/)
});
});
describe('callReducer', () => {
it('should call the provided reducer with the structure description, location string, and name', () => {
expect(callReducer({
reducerStructureDescriptor: 'foo',
name: 'toast',
locationString: 'toasty',
reducerFn: (reducerStructureDescriptor, { locationString, name }) => ({ reducerStructureDescriptor, locationString, name })
})).toEqual({
reducerStructureDescriptor: 'foo',
locationString: 'toasty',
name: 'toast',
})
});
});
describe('createReducerBehaviors', () => {
it('Should return only the reducers of the behavior config and prepend the locationString', () => {
expect(createReducerBehaviors({
'toast': {
reducer: 'foo',
action: 'bar',
}
}, 'location')).toEqual({
'location.toast': 'foo',
})
});
});
});

View File

@ -0,0 +1,43 @@
import { Types, PROP_TYPES } from '../structure';
function hasType(object, type) {
return object.type === type;
}
describe('Type descriptions', () => {
it('will return a function which subsequently returns an object with the correct type', () => {
expect(hasType(Types.string()(), PROP_TYPES._string)).toBeTruthy();
expect(hasType(Types.number()(), PROP_TYPES._number)).toBeTruthy();
expect(hasType(Types.boolean()(), PROP_TYPES._boolean)).toBeTruthy();
expect(hasType(Types.arrayOf()(), PROP_TYPES._array)).toBeTruthy();
expect(hasType(Types.reducer()(), PROP_TYPES._reducer)).toBeTruthy();
expect(hasType(Types.shape()(), PROP_TYPES._shape)).toBeTruthy();
});
it('will return the standard default values when none provided', () => {
expect(Types.string()().defaultValue).toBe('');
expect(Types.number()().defaultValue).toBe(0);
expect(Types.boolean()().defaultValue).toBe(false);
expect(Types.arrayOf()().defaultValue).toEqual([]);
});
it('will return the default value provided (except for reducer and shape)', () => {
expect(Types.string('foo')().defaultValue).toBe('foo');
expect(Types.number(5)().defaultValue).toBe(5);
expect(Types.boolean(true)().defaultValue).toBe(true);
expect(Types.arrayOf(Types.number(), [1, 2, 3])().defaultValue).toEqual([1, 2, 3]);
});
it('will return the correct typeofValue (for string, number, and boolean)', () => {
expect(Types.string()().typeofValue).toBe('string');
expect(Types.number()().typeofValue).toBe('number');
expect(Types.boolean()().typeofValue).toBe('boolean');
});
it('will return the correct structure (for arrayOf, reducer, and shape)', () => {
const structureTest = Types.string();
expect(Types.shape(structureTest)().structure).toEqual(structureTest);
expect(Types.arrayOf(structureTest)().structure).toEqual(structureTest);
expect(Types.reducer(structureTest)().structure).toEqual(structureTest);
});
});

View File

@ -1,80 +1,99 @@
import { Types } from '../structure';
import { validatePrimitive, validateObject, validateArray } from '../validatePayload';
import {
validatePrimitive,
validateShape,
validateArray,
getTypeValidation
} from '../validatePayload';
describe('Testing validation functionality', () => {
describe('Validation functionality', () => {
//Primitives
it('Number primitive should allow for numbers', () => {
expect(validatePrimitive(Types.number(), 3)).toBe(3);
});
it('String primitive should allow for string', () => {
expect(validatePrimitive(Types.string(), 'toast')).toBe('toast');
});
it('Boolean primitive should allow for string', () => {
expect(validatePrimitive(Types.boolean(), true)).toBe(true);
});
//Arrays
const testArrayStructure = Types.arrayOf(Types.string());
it('Arrays should allow for primitives', () => {
expect(validateArray(testArrayStructure, ['a','b','c','d']))
.toEqual(['a','b','c','d']);
});
it('Arrays should strip values for primitives which fail the test', () => {
expect(validateArray(testArrayStructure, ['a','b',3,'d']))
.toEqual(['a','b','d']);
});
const testArrayStructure2 = Types.arrayOf(Types.shape({
test1: Types.number()
}));
it('Arrays should allow for complex objects', () => {
expect(validateArray(testArrayStructure2, [{test1: 3},{test1: 4}]))
.toEqual([{test1: 3},{test1: 4}]);
});
const testArrayStructure3 = Types.arrayOf(Types.shape({
test1: Types.arrayOf(Types.number())
}));
it('Arrays should allow for complex objects - test 2', () => {
expect(validateArray(testArrayStructure3, [{test1: [3,4,5]}]))
.toEqual([{test1: [3,4,5]}]);
});
//Objects
const testObjectStructure = Types.shape({
test1: Types.string(),
test2: Types.number()
});
it('Object of primitives should allow all props present in the structure', () => {
expect(validateObject(testObjectStructure, { test1: 'toast', test2: 3 }))
.toEqual({ test1: 'toast', test2: 3 });
});
it('Object of primitives should only allow for props with values which match their config', () => {
expect(validateObject(testObjectStructure, { test1: 5, test2: 3 }))
.toEqual({ test2: 3 });
});
it('Object of primitives should strip any properties not part of the config', () => {
expect(validateObject(testObjectStructure, { test1: 'toast', test2: 3, toast: 'bar' }))
.toEqual({ test1: 'toast', test2: 3 });
});
const testObjectStructure2 = Types.shape({
test1: testObjectStructure,
});
it('Objects should allow for arbitrary nesting of objects', () => {
expect(validateObject(testObjectStructure2, { test1: { test1: 'toast', test2: 3 } }))
.toEqual({ test1: { test1: 'toast', test2: 3 } });
});
const testObjectStructure3 = Types.shape({
test1: Types.shape({
test2: Types.string(),
}),
test2: Types.string(),
});
it('Objects containing objects should properly check if an object is provided', () => {
expect(validateObject(testObjectStructure3, { test1: 'foo', test2: 'bar' })).toEqual({
test1: undefined,
test2: 'bar',
describe('Primitives', () => {
it('Number primitive should allow for numbers', () => {
expect(validatePrimitive(Types.number(), 3)).toBe(3);
});
})
it('String primitive should allow for string', () => {
expect(validatePrimitive(Types.string(), 'toast')).toBe('toast');
});
it('Boolean primitive should allow for string', () => {
expect(validatePrimitive(Types.boolean(), true)).toBe(true);
});
});
describe('Arrays', () => {
const testArrayStructure = Types.arrayOf(Types.string());
it('Arrays should allow for primitives', () => {
expect(validateArray(testArrayStructure, ['a','b','c','d']))
.toEqual(['a','b','c','d']);
});
it('Arrays should strip values for primitives which fail the test', () => {
expect(validateArray(testArrayStructure, ['a','b',3,'d']))
.toEqual(['a','b','d']);
});
const testArrayStructure2 = Types.arrayOf(Types.shape({
test1: Types.number()
}));
it('Arrays should allow for complex objects', () => {
expect(validateArray(testArrayStructure2, [{test1: 3},{test1: 4}]))
.toEqual([{test1: 3},{test1: 4}]);
});
const testArrayStructure3 = Types.arrayOf(Types.shape({
test1: Types.arrayOf(Types.number())
}));
it('Arrays should allow for complex objects - test 2', () => {
expect(validateArray(testArrayStructure3, [{test1: [3,4,5]}]))
.toEqual([{test1: [3,4,5]}]);
});
it('Array should return an empty array if a non-array is passed', () => {
expect(validateArray('foo')).toEqual([]);
})
});
describe('Objects', () => {
const testObjectStructure = Types.shape({
test1: Types.string(),
test2: Types.number()
});
it('Object of primitives should allow all props present in the structure', () => {
expect(validateShape(testObjectStructure, { test1: 'toast', test2: 3 }))
.toEqual({ test1: 'toast', test2: 3 });
});
it('Object of primitives should only allow for props with values which match their config', () => {
expect(validateShape(testObjectStructure, { test1: 5, test2: 3 }))
.toEqual({ test2: 3 });
});
it('Object of primitives should strip any properties not part of the config', () => {
expect(validateShape(testObjectStructure, { test1: 'toast', test2: 3, toast: 'bar' }))
.toEqual({ test1: 'toast', test2: 3 });
});
const testObjectStructure2 = Types.shape({
test1: testObjectStructure,
});
it('Objects should allow for arbitrary nesting of objects', () => {
expect(validateShape(testObjectStructure2, { test1: { test1: 'toast', test2: 3 } }))
.toEqual({ test1: { test1: 'toast', test2: 3 } });
});
const testObjectStructure3 = Types.shape({
test1: Types.shape({
test2: Types.string(),
}),
test2: Types.string(),
});
it('Objects containing objects should properly check if an object is provided', () => {
expect(validateShape(testObjectStructure3, { test1: 'foo', test2: 'bar' })).toEqual({
test1: {},
test2: 'bar',
});
})
});
describe('Non covered types', () => {
it('A type with no associated validation should throw an error', () => {
expect(() => getTypeValidation('toast')).toThrowError(/validation/);
});
});
});

View File

@ -1,96 +0,0 @@
//@flow
//==============================
// Flow imports
//==============================
import type { StructureType, PrimitiveType } from './structure';
import type { PartialReducer } from './reducers';
import { combineReducers } from 'redux';
import { reduce, find } from 'lodash';
import { createReducer } from './reducers';
import { PROP_TYPES } from './structure';
// Build a chunk of the eventual store. The selectors and actions
// generated will specifically operate on the store chunk generated. Selectors will be
// relative to the baseSelector provided or, if not specified, the root of the store, using
// the name of the chunk as the base property.
export function buildStoreChunk(name: string, structure: any, {
baseSelector = state => state[name],
locationString = '',
}: {
baseSelector: any,
locationString: string,
} = {}): PartialReducer {
if (structure === undefined) throw new Error(`The structure must be defined for a reducer! LocationString: ${ locationString }`);
//Build up the reducers, actions, and selectors for this level. Due to recursion,
//these objects will be assigned to a property in the parent object, or simply
//returned to the call site for use in the rest of the application.
const temp = reduce(structure, processStructure, {
reducers: {
[name]: {},
},
actions: {},
selectors: {},
});
//The Redux 'combineReducers' helper function is used here to save a little bit of boilerplate.
//This helper, if you're not aware, ensures that the correct store properties are passed to the
//reducers assigned to those properties.
return { ...temp, reducers: {
[name]: combineReducers(temp.reducers)
}};
function processStructure(memo: PartialReducer, propValue: StructureType | PrimitiveType, propName: string) {
//Get the structure from the propValue. In the case of 'StructureType' properties, this
//will be some form of shape (or primitives in the case of arrays). At this point we
//are only interested in whether or not the structure contains reducers, as that
//has an impact on how we proceed with regards to calls.
const { structure: propStructure } = propValue();
const containsReducers = !!find(propStructure, v => v().type === PROP_TYPES._reducer);
//Create the child reducer. Depending on whether or not the current structure level contains
//child reducers, we will either recursively call reducerBuilder, or we will call the
//createReducer function, which will create the correct reducer for the given structure
//(which can be either object, array, or primitive).
let childReducer = containsReducers
? buildStoreChunk(propName, propStructure, {
locationString: locationString ? `${locationString}.${propName}` : propName,
baseSelector: (state: any) => baseSelector(state)[propName],
})
: createReducer(propValue, {
locationString: `${locationString}.${propName}`,
name: propName,
});
//As the object is built up, we want to assign the reducers/actions created
//by the child to a location on the reducers/actions object which will match up
//to their location. Selectors are created at this level, as the child does not
//need to know where it is located within the grand scheme of things.
return {
reducers: {
...memo.reducers,
...childReducer.reducers
},
actions: {
...memo.actions,
[propName]: childReducer.actions,
},
selectors: {
...memo.selectors,
[propName]: containsReducers ? childReducer.selectors : state => baseSelector(state)[propName],
},
};
}
}

View File

@ -0,0 +1,108 @@
//@flow
//==============================
// Flow imports
//==============================
import type { StructureType, PrimitiveType } from './structure';
import type { PartialStoreChunk } from './reducers';
//==============================
// JS imports
//==============================
import { combineReducers } from 'redux';
import { reduce, find, omit, isFunction } from 'lodash';
import { compose } from 'ramda';
import { createReducer } from './reducers';
import { PROP_TYPES } from './structure';
// Build a chunk of the eventual store. The selectors and actions
// generated will specifically operate on the store chunk generated. Selectors will be
// relative to the baseSelector provided or, if not specified, the root of the store, using
// the name of the chunk as the base property.
export function buildStoreChunk(name: string, structure: any, {
baseSelector = state => state[name],
locationString = '',
}: {
baseSelector: any,
locationString: string,
} = {}): PartialStoreChunk {
if (!structure) throw new Error(`The structure must be defined for a reducer! LocationString: ${ locationString }`);
const initialMemo: PartialStoreChunk = {
reducers: {
[name]: {},
},
actions: {},
selectors: {},
baseSelector,
locationString,
name,
};
//Build up the reducers, actions, and selectors for this level. Due to recursion,
//these objects will be assigned to a property in the parent object, or simply
//returned to the call site for use in the rest of the application.
//If the reducer's structure is a function (and, therefore, not nested reducers), we can skip the reduce.
if (isFunction(structure)) return combineStoreChunkReducers(processStructure(initialMemo, structure, name));
return combineStoreChunkReducers(reduce(structure, processStructure, initialMemo));
}
export function combineStoreChunkReducers(processedStoreChunk: PartialStoreChunk) {
//The Redux 'combineReducers' helper function is used here to save a little bit of boilerplate.
//This helper, if you're not aware, ensures that the correct store properties are passed to the
//reducers assigned to those properties.
return { ...omit(processedStoreChunk, ['baseSelector', 'locationString', 'name']), reducers: {
[processedStoreChunk.name]: combineReducers(processedStoreChunk.reducers)
}};
}
export function processStructure(memo: PartialStoreChunk, propValue: StructureType | PrimitiveType, propName: string) {
//Get the structure from the propValue. In the case of 'StructureType' properties, this
//will be some form of shape (or primitives in the case of arrays). At this point we
//are only interested in whether or not the structure contains reducers, as that
//has an impact on how we proceed with regards to calls.
const { structure: propStructure } = propValue();
const containsReducers = !!find(propStructure, v => v().type === PROP_TYPES._reducer);
//Create the child reducer. Depending on whether or not the current structure level contains
//child reducers, we will either recursively call reducerBuilder, or we will call the
//createReducer function, which will create the correct reducer for the given structure
//(which can be either object, array, or primitive).
let childReducer = containsReducers
? buildStoreChunk(propName, propStructure, {
locationString: memo.locationString ? `${memo.locationString}.${propName}` : propName,
baseSelector: (state: any) => memo.baseSelector(state)[propName],
})
: createReducer(propValue, {
locationString: `${memo.locationString}.${propName}`,
name: propName,
});
//As the chunk is built up, we want to assign the reducers/actions created
//by the child to a location on the reducers/actions object which will match up
//to their location. Selectors are created at this level, as the child does not
//need to know where it is located within the grand scheme of things.
return {
...memo,
reducers: {
...memo.reducers,
...childReducer.reducers
},
actions: {
...memo.actions,
[propName]: childReducer.actions,
},
selectors: {
...memo.selectors,
[propName]: containsReducers ? childReducer.selectors : state => memo.baseSelector(state)[propName],
},
};
}

View File

@ -5,19 +5,31 @@
import type {
StructureType,
PrimitiveType,
ReducerType,
PropTypeKeys,
} from './structure';
//==============================
// Flow types
//==============================
export type PartialReducer = {
export type PartialStoreChunk = {
reducers: { [key: string]: any },
actions: { [key: string]: any },
selectors: { [key: string]: any },
locationString: string,
baseSelector: () => {},
name: string,
};
export type Selector = (state: Object) => any;
type CallReducerInterface = {
name: string,
reducerFn: () => {},
reducerStructureDescriptor: StructureType | PrimitiveType,
locationString: string,
};
//==============================
// JS imports
//==============================
@ -25,41 +37,55 @@ import {
PROP_TYPES,
} from './structure';
import { compose } from 'ramda';
import { reduce } from 'lodash';
import { createObjectReducer } from './reducers/objectReducer';
import { reduce, find } from 'lodash';
import { createShapeReducer } from './reducers/objectReducer';
import { createArrayReducer } from './reducers/arrayReducer';
import { createPrimitiveReducer } from './reducers/primitiveReducer';
function determineReducerType(reducerDescriptor, {
export const REDUCER_CREATOR_MAPPING: { [key: PropTypeKeys]: any } = {
[PROP_TYPES._shape]: createShapeReducer,
[PROP_TYPES._array]: createArrayReducer,
[PROP_TYPES._boolean]: createPrimitiveReducer,
[PROP_TYPES._string]: createPrimitiveReducer,
[PROP_TYPES._number]: createPrimitiveReducer,
};
export function determineReducerType(reducerDescriptor: ReducerType, {
name,
locationString,
}) {
const REDUCERS = {
[PROP_TYPES._shape]: createObjectReducer,
[PROP_TYPES._array]: createArrayReducer,
[PROP_TYPES._boolean]: createPrimitiveReducer,
[PROP_TYPES._string]: createPrimitiveReducer,
[PROP_TYPES._number]: createPrimitiveReducer,
};
reducerCreatorMapping = REDUCER_CREATOR_MAPPING,
}: {
name: string,
locationString: string,
reducerCreatorMapping: { [key: PropTypeKeys]: any },
}): CallReducerInterface {
const { structure } = reducerDescriptor();
const { type } = structure();
if (!reducerCreatorMapping[type]) throw new Error(`Reducer type ${type} does not have a corresponding createReducer function`);
return {
name,
reducerFn: REDUCERS[type],
reducerFn: reducerCreatorMapping[type],
reducerStructureDescriptor: structure,
locationString,
};
}
function callReducer({ name, reducerFn, reducerStructureDescriptor, locationString } = {}) {
export function callReducer({
name,
reducerFn,
reducerStructureDescriptor,
locationString
}: CallReducerInterface) {
return reducerFn(reducerStructureDescriptor, {
locationString,
name,
});
}
export function createReducerBehaviors(behaviorsConfig: any, locationString: string): any {
export function createReducerBehaviors(behaviorsConfig: { [key: string]: { reducer: () => {} } }, locationString: string): any {
//Take a reducer behavior config object, and create the reducer behaviors using the location string.
//This is necessary since all action types are effectively global when Redux processes an action
//(i.e. every reducer will be ran using the action object). Therefore we need to ensure that all

View File

@ -38,11 +38,12 @@ export type ArraySelector = (state: Object) => Array<any>;
// JS imports
//==============================
import { reduce, isArray, isNumber, isObject } from 'lodash';
import { validateArray, validateObject, validatePrimitive } from '../validatePayload';
import { validateArray, validateShape, validatePrimitive } from '../validatePayload';
import { createReducerBehaviors } from '../reducers';
import { updateAtIndex, removeAtIndex } from '../utils/arrayUtils';
import { PROP_TYPES } from '../structure';
function checkIndex(index: ?number, payload: any, behaviorName: string): boolean {
if (!isNumber(index) || index === -1) {
console.warn(`Index not passed to ${behaviorName} for payload ${payload}.`);
@ -51,7 +52,18 @@ function checkIndex(index: ?number, payload: any, behaviorName: string): boolean
return true;
}
//==============================
// Array behaviors
// ----------------
// Arrays are more complicated than shape or primitive reducers, due to
// the complexities in amending specific elements. Of course, the behaviours
// could still follow and the same pattern as the other reducers and simply
// make the end user replace the correct index themselves. However, it made sense
// to create a few helper behaviors to aid with the most common array operations.
//==============================
const DEFAULT_ARRAY_BEHAVIORS: ArrayReducerBehaviorsConfig = {
//Index specific behaviors.
updateAtIndex: {
reducer(state, payload, initialState, index = -1) {
if (!checkIndex(index, payload, 'updateAtIndex')) return state;
@ -79,6 +91,7 @@ const DEFAULT_ARRAY_BEHAVIORS: ArrayReducerBehaviorsConfig = {
return updateAtIndex(state, payload, index);
}
},
//Whole array behaviors.
replace: {
action(value) {
if(!isArray(value)) throw new Error('An array must be provided when replacing an array');
@ -135,11 +148,11 @@ function applyValidation(arrayTypeDescription: ArrayStructureType, payload: any)
// First case is simple - if the action payload is an array, then we simply validate it against
// the structure of this reducer.
if (isArray(payload)) return validateArray(arrayTypeDescription, payload);
// If a non-array payload has been passed in, then we need to check which form of validation
// to use, by checking the structure of the array.
const { structure } = arrayTypeDescription();
if (structure().type === PROP_TYPES._shape) return validateObject(structure, payload);
if (structure().type === PROP_TYPES._shape) return validateShape(structure, payload);
return validatePrimitive(structure, payload);
}

View File

@ -4,43 +4,53 @@
//==============================
import type { StructureType } from '../structure';
//==============================
// Flow types
//==============================
export type ObjectReducerAction = {
export type ShapeReducerAction = {
type: string,
payload: Object,
};
export type ObjectReducer = (state: Object, action: ObjectReducerAction) => Object;
export type ObjectReducerBehavior = (state: Object, payload: Object | void, initialState: Object) => Object;
export type ObjectReducerBehaviorsConfig = {
export type ShapeReducer = (state: Object, action: ShapeReducerAction) => Object;
export type ShapeReducerBehavior = (state: {}, payload: Object | void, initialState: {}) => Object;
export type ShapeReducerBehaviorsConfig = {
[key: string]: {
action?: (value: Object) => Object,
reducer: ObjectReducerBehavior,
reducer: ShapeReducerBehavior,
}
};
export type ObjectReducerBehaviors = {
[key: string]: ObjectReducerBehavior,
export type ShapeReducerBehaviors = {
[key: string]: ShapeReducerBehavior,
};
export type ObjectAction = (value: Object) => { type: string, payload: Object };
export type ObjectActions = {
[key: string]: ObjectAction
export type ShapeAction = (value: Object) => { type: string, payload: Object };
export type ShapeActions = {
[key: string]: ShapeAction
};
export type ObjectReducerOptions = {
behaviorsConfig: ObjectReducerBehaviorsConfig,
export type ShapeReducerOptions = {
behaviorsConfig: ShapeReducerBehaviorsConfig,
locationString: string,
name: string,
};
//==============================
// JS imports
//==============================
import { reduce } from 'lodash';
import { validateObject } from '../validatePayload';
import { validateShape } from '../validatePayload';
import { createReducerBehaviors } from '../reducers';
import { PROP_TYPES } from '../structure';
const DEFAULT_OBJECT_BEHAVIORS: ObjectReducerBehaviorsConfig = {
//==============================
// Shape behaviors
// ----------------
// Shapes differ from primitive reducers by allowing an update behavior, merging the
// payload and the previous state in a shallow way. This supplements the replace
// behavior, which still replaces the previous state with the payload.
//==============================
const DEFAULT_SHAPE_BEHAVIORS: ShapeReducerBehaviorsConfig = {
update: {
action(value) { return value },
reducer(state, payload = {}) {
@ -60,15 +70,16 @@ const DEFAULT_OBJECT_BEHAVIORS: ObjectReducerBehaviorsConfig = {
}
};
export function createObjectReducer(reducerShape: StructureType, {
export function createShapeReducer(reducerShape: StructureType, {
locationString,
name,
}: ObjectReducerOptions = {}) {
}: ShapeReducerOptions = {}) {
return {
reducers: {
[name]: createReducer(reducerShape, createReducerBehaviors(DEFAULT_OBJECT_BEHAVIORS, locationString)),
[name]: createReducer(reducerShape, createReducerBehaviors(DEFAULT_SHAPE_BEHAVIORS, locationString)),
},
actions: createActions(DEFAULT_OBJECT_BEHAVIORS, locationString, {}),
actions: createActions(DEFAULT_SHAPE_BEHAVIORS, locationString, {}),
};
}
@ -83,20 +94,20 @@ function calculateDefaults(reducerStructure) {
}
function createReducer(objectStructure: StructureType, behaviors: ObjectReducerBehaviors): ObjectReducer {
const initialState: Object = validateObject(objectStructure, calculateDefaults(objectStructure().structure));
return (state = initialState, { type, payload }: ObjectReducerAction) => {
function createReducer(objectStructure: StructureType, behaviors: ShapeReducerBehaviors): ShapeReducer {
const initialState: Object = validateShape(objectStructure, calculateDefaults(objectStructure().structure));
return (state = initialState, { type, payload }: ShapeReducerAction) => {
//If the action type does not match any of the specified behaviors, just return the current state.
if (!behaviors[type]) return state;
//Sanitize the payload using the reducer shape, then apply the sanitized
//payload to the state using the behavior linked to this action type.
return behaviors[type](state, validateObject(objectStructure, payload), initialState);
return behaviors[type](state, validateShape(objectStructure, payload), initialState);
}
}
function createActions(behaviorsConfig: ObjectReducerBehaviorsConfig, locationString: string, defaultPayload: any): ObjectActions {
function createActions(behaviorsConfig: ShapeReducerBehaviorsConfig, locationString: string, defaultPayload: any): ShapeActions {
//Take a reducer behavior config object, and create actions using the location string
return reduce(behaviorsConfig, (memo, behavior, name) => ({
...memo,

View File

@ -39,8 +39,16 @@ import { reduce } from 'lodash';
import { validatePrimitive } from '../validatePayload';
import { createReducerBehaviors } from '../reducers';
//==============================
// Primitive behaviors
// ----------------
// Primitives are the most simple case, as they only have the replace and
// reset behaviors by default.
//==============================
const DEFAULT_PRIMITIVE_BEHAVIORS: PrimitiveReducerBehaviorsConfig = {
update: {
replace: {
action(value) { return value },
reducer(state, payload) {
if (payload === undefined) return state;

View File

@ -3,27 +3,33 @@
//==============================
// Flow types
//==============================
export type PropTypeKeys = $Keys<typeof PROP_TYPES>;
export type ShapeStructure = {
[key: string]: StructureType | PrimitiveType | ArrayStructureType,
}
export type StructureType = () => {
type: string,
type: PropTypeKeys,
structure: ShapeStructure | StructureType | PrimitiveType,
defaultValue?: any,
};
export type ReducerType = () => {
type: PropTypeKeys,
structure: StructureType | PrimitiveType,
};
export type ArrayStructureType = () => {
type: string,
type: PropTypeKeys,
structure: StructureType | PrimitiveType,
defaultValue: any,
}
export type PrimitiveType = () => {
type: $Keys<typeof PROP_TYPES>,
type: PropTypeKeys,
defaultValue?: any,
typeofValue: string,
structure?: PrimitiveType,
};
export type TypesObject = {
[key: string]: CreateArrayType | CreateStringType | CreateNumberType | CreateObjectType | CreateBooleanType;
[key: string]: CreateArrayType | CreateStringType | CreateNumberType | CreateShapeType | CreateBooleanType;
}
export type TypesObjectDefaults = {
@ -35,7 +41,7 @@ type CreateStringType = (defaultValue: string) => PrimitiveType;
type CreateNumberType = (defaultValue: number) => PrimitiveType;
type CreateBooleanType = (defaultValue: boolean) => PrimitiveType;
type CreateArrayType = (structure: StructureType | PrimitiveType, defaultValue: TypesArrayDefaults | TypesObjectDefaults) => StructureType;
type CreateObjectType = (structure: ShapeStructure, defaultValue: TypesArrayDefaults | TypesObjectDefaults) => StructureType;
type CreateShapeType = (structure: ShapeStructure, defaultValue: TypesArrayDefaults | TypesObjectDefaults) => StructureType;
//==============================
// Structure
@ -49,6 +55,8 @@ export const PROP_TYPES = {
_array: '_array',
};
//The types objects are used in order to build up the structure of a store chunk, and provide/accept
//default values whilst doing so.
export const Types: TypesObject = {
string: (defaultValue: string = '') => () => ({
type: PROP_TYPES._string,
@ -77,5 +85,5 @@ export const Types: TypesObject = {
shape: (structure: ShapeStructure) => () => ({
type: PROP_TYPES._shape,
structure,
})
}),
};

View File

@ -0,0 +1,46 @@
import {
updateAtIndex,
removeAtIndex,
} from '../arrayUtils';
describe('Array utilities', () => {
describe('updateAtIndex', () => {
it('Should throw error if attempting to update without an index', () => {
expect(() => updateAtIndex([1,2,3], 4)).toThrowError(/index/);
});
it('Should throw error if attempting to update with a non numeric index', () => {
expect(() => updateAtIndex([1,2,3], 4, 'toast')).toThrowError(/index/);
});
it('Should throw error if attempting to update with an out of range index', () => {
expect(() => updateAtIndex([1,2,3], 4, 4)).toThrowError(/index/);
});
it('Should update value at the correct index', () => {
expect(updateAtIndex([1,2,3], 4, 0)).toEqual([4,2,3]);
expect(updateAtIndex([1,2,3], 4, 1)).toEqual([1,4,3]);
expect(updateAtIndex([1,2,3], 4, 2)).toEqual([1,2,4]);
});
});
describe('removeAtIndex', () => {
it('Should throw error if attempting to remove without an index', () => {
expect(() => removeAtIndex([1,2,3])).toThrowError(/index/);
});
it('Should throw error if attempting to remove with a non numeric index', () => {
expect(() => removeAtIndex([1,2,3], 'toast')).toThrowError(/index/);
});
it('Should throw error if attempting to remove with an out of range index', () => {
expect(() => removeAtIndex([1,2,3], 4)).toThrowError(/index/);
});
it('Should remove value at the correct index', () => {
expect(removeAtIndex([1,2,3], 0)).toEqual([2,3]);
expect(removeAtIndex([1,2,3], 1)).toEqual([1,3]);
expect(removeAtIndex([1,2,3], 2)).toEqual([1,2]);
});
});
});

View File

@ -1,6 +1,7 @@
//@flow
export function updateAtIndex(array: Array<any>, value: any, index: ?number): Array<any> {
if (index === undefined || index === null) throw new Error('Must provide an index to updateAtIndex');
export function updateAtIndex(array: Array<any>, value: any, index: number): Array<any> {
if (typeof index !== 'number') throw new Error('Must provide a numeric index to updateAtIndex');
if (index < 0 || index > array.length - 1) throw new Error(`The index ${index} is out of range for the array provided`);
return [
...array.slice(0,index),
value,
@ -8,8 +9,9 @@ export function updateAtIndex(array: Array<any>, value: any, index: ?number): Ar
];
}
export function removeAtIndex(array: Array<any>, index: ?number): Array<any> {
if (index === undefined || index === null) throw new Error('Must provide an index to removeAtIndex');
export function removeAtIndex(array: Array<any>, index: number): Array<any> {
if (typeof index !== 'number') throw new Error('Must provide a numeric index to removeAtIndex');
if (index < 0 || index > array.length - 1) throw new Error(`The index ${index} is out of range for the array provided`);
return [
...array.slice(0, index),
...array.slice(index + 1),

View File

@ -12,12 +12,11 @@ type validationFunction = (structure: StructureType | PrimitiveType | ShapeStruc
import { reduce, isObject } from 'lodash';
import { PROP_TYPES } from './structure';
export function validateObject(objectStructure: any, value: mixed): Object {
if (!isObject(value) && !!value) {
export function validateShape(objectStructure: any, value: mixed): Object {
if (!isObject(value)) {
console.error(`The value passed to validateObject() was not an object. Value: `, value);
return {};
}
if (!isObject(value) || !value ) return {};
return reduce(value, (memo, value, name) => {
const valueType = objectStructure().structure[name];
@ -50,22 +49,25 @@ export function validatePrimitive(primitive: any, value: any): mixed {
return console.warn(`The value, ${value}, did not match the type specified (${primitive().type}).`);
}
export function validateArray(arrayStructure: any, value: Array<any> | void): Array<mixed> {
export function validateArray(arrayStructure: any, value: Array<any>): Array<mixed> {
//Validate arrays by performing either of the other validation types to each element of the array,
//based on the provided reducer structure.
if (!Array.isArray(value)) return [];
if (!Array.isArray(value)) {
console.error(`The value passed to validateArray() was not an array. Value: `, value);
return [];
}
const elementStructure = arrayStructure().structure;
const elementType = elementStructure().type;
return value.map(element => getTypeValidation(elementType)(elementStructure, element)).filter(e => e);
}
function getTypeValidation(type): validationFunction {
export function getTypeValidation(type: string): validationFunction {
const TYPE_VALIDATIONS = {
[PROP_TYPES._string]: validatePrimitive,
[PROP_TYPES._number]: validatePrimitive,
[PROP_TYPES._boolean]: validatePrimitive,
[PROP_TYPES._array]: validateArray,
[PROP_TYPES._shape]: validateObject,
[PROP_TYPES._shape]: validateShape,
};
const typeValidation = TYPE_VALIDATIONS[type];
if (!typeValidation) {