Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
C
common
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
npm
common
Commits
6894e538
Commit
6894e538
authored
Feb 04, 2019
by
Vladislav Lagunov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Добавлен алиасы модулей eff http
parent
8cc3cb4a
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
395 additions
and
393 deletions
+395
-393
core/eff.ts
+1
-221
core/http.ts
+1
-172
eff/index.ts
+221
-0
http/index.ts
+172
-0
No files found.
core/eff.ts
View file @
6894e538
import
{
Either
}
from
'../either'
;
import
{
Option
}
from
'../maybe'
;
import
*
as
either
from
'../either'
;
import
{
Observable
}
from
'rxjs'
;
import
*
as
Rx
from
'rxjs'
;
import
{
map
}
from
'rxjs/internal/operators/map'
;
import
{
combineAll
}
from
'rxjs/internal/operators/combineAll'
;
import
{
Expr
}
from
'./internal/expr'
;
/**
* Тайп-алиасы для удобства
*/
export
type
Eff
<
Error
,
Success
>
=
Observable
<
Either
<
Error
,
Success
>>
;
export
type
Cmd
<
Action
>
=
Eff
<
never
,
Action
>
;
declare
module
'rxjs/internal/Observable'
{
export
interface
Observable
<
T
>
{
readonly
_T
:
T
;
map
<
L
,
R
,
R2
>
(
this
:
Eff
<
L
,
R
>
,
f
:
(
x
:
R
)
=>
R2
):
Eff
<
L
,
R2
>
;
mapTo
<
L
,
R
,
R2
>
(
this
:
Eff
<
L
,
R
>
,
x
:
R2
):
Eff
<
L
,
R2
>
;
mapError
<
L
,
R
,
L2
>
(
this
:
Eff
<
L
,
R
>
,
f
:
(
x
:
L
)
=>
L2
):
Eff
<
L2
,
R
>
;
mapErrorTo
<
L
,
R
,
L2
>
(
this
:
Eff
<
L
,
R
>
,
x
:
L2
):
Eff
<
L2
,
R
>
;
perform
<
L
,
R
,
A
>
(
this
:
Eff
<
L
,
R
>
,
onFailure
:
(
x
:
L
)
=>
A
,
onSuccess
:
(
x
:
R
)
=>
A
):
Cmd
<
A
>
;
perform
<
L
,
R
,
A1
,
A2
>
(
this
:
Eff
<
L
,
R
>
,
onFailure
:
(
x
:
L
)
=>
A1
,
onSuccess
:
(
x
:
R
)
=>
A2
):
Cmd
<
A1
|
A2
>
;
performMaybe
<
L
,
R
,
A
>
(
this
:
Eff
<
L
,
R
>
,
onFailure
:
(
x
:
L
)
=>
Option
<
A
>
,
onSuccess
:
(
x
:
R
)
=>
Option
<
A
>
):
Cmd
<
A
>
;
performMaybe
<
L
,
R
,
A1
,
A2
>
(
this
:
Eff
<
L
,
R
>
,
onFailure
:
(
x
:
L
)
=>
Option
<
A1
>
,
onSuccess
:
(
x
:
R
)
=>
Option
<
A2
>
):
Cmd
<
A1
|
A2
>
;
performForget
<
L
,
R
>
(
this
:
Eff
<
L
,
R
>
):
Cmd
<
never
>
;
performSuccess
<
R
,
A
>
(
this
:
Eff
<
never
,
R
>
,
onSuccess
:
(
x
:
R
)
=>
A
):
Cmd
<
A
>
;
onError
<
L
,
R
,
L2
,
R2
>
(
this
:
Eff
<
L
,
R
>
,
onFailure
:
(
x
:
L
)
=>
Eff
<
L2
,
R2
>
):
Eff
<
L2
,
R2
|
R
>
;
chain
<
L
,
R
,
R2
>
(
this
:
Eff
<
L
,
R
>
,
f
:
(
x
:
R
)
=>
Eff
<
L
,
R2
>
):
Eff
<
L
,
R2
>
;
chain
<
L
,
R
,
L2
,
R2
>
(
this
:
Eff
<
L
,
R
>
,
f
:
(
x
:
R
)
=>
Eff
<
L2
,
R2
>
):
Eff
<
L
|
L2
,
R2
>
;
chainTo
<
L
,
R
,
R2
>
(
this
:
Eff
<
L
,
R
>
,
effect
:
Eff
<
L
,
R2
>
):
Eff
<
L
,
R2
>
;
chainTo
<
L
,
R
,
L2
,
R2
>
(
this
:
Eff
<
L
,
R
>
,
effect
:
Eff
<
L2
,
R2
>
):
Eff
<
L
|
L2
,
R2
>
;
// DEPRECATED
chainEff
<
L
,
R
,
R2
>
(
this
:
Eff
<
L
,
R
>
,
f
:
(
x
:
R
)
=>
Eff
<
L
,
R2
>
):
Eff
<
L
,
R2
>
;
chainEff
<
L
,
R
,
L2
,
R2
>
(
this
:
Eff
<
L
,
R
>
,
f
:
(
x
:
R
)
=>
Eff
<
L2
,
R2
>
):
Eff
<
L
|
L2
,
R2
>
;
mapEff
<
L
,
R
,
R2
>
(
this
:
Eff
<
L
,
R
>
,
f
:
(
x
:
R
)
=>
R2
):
Eff
<
L
,
R2
>
;
mapCmd
<
L
,
R
,
R2
>
(
this
:
Eff
<
L
,
R
>
,
f
:
(
x
:
R
)
=>
R2
):
Eff
<
L
,
R2
>
;
}
}
(
Observable
as
any
).
prototype
.
map
=
function
<
L
,
R
,
R2
>
(
this
:
Eff
<
L
,
R
>
,
f
:
(
x
:
R
)
=>
R2
):
Eff
<
L
,
R2
>
{
return
this
.
pipe
(
map
(
ethr
=>
ethr
.
map
(
f
)));
};
(
Observable
as
any
).
prototype
.
mapTo
=
function
<
L
,
R
,
R2
>
(
this
:
Eff
<
L
,
R
>
,
x
:
R2
):
Eff
<
L
,
R2
>
{
return
this
.
pipe
(
map
(
ethr
=>
ethr
.
map
(()
=>
x
)));
};
(
Observable
as
any
).
prototype
.
mapError
=
function
<
L
,
R
,
L2
>
(
this
:
Eff
<
L
,
R
>
,
f
:
(
x
:
L
)
=>
L2
):
Eff
<
L2
,
R
>
{
return
this
.
pipe
(
map
(
ethr
=>
ethr
.
mapLeft
(
f
)));
};
(
Observable
as
any
).
prototype
.
mapErrorTo
=
function
<
L
,
R
,
L2
>
(
this
:
Eff
<
L
,
R
>
,
x
:
L2
):
Eff
<
L2
,
R
>
{
return
this
.
pipe
(
map
(
ethr
=>
ethr
.
mapLeft
(()
=>
x
)));
};
(
Observable
as
any
).
prototype
.
onError
=
function
<
L
,
R
,
L2
,
R2
>
(
this
:
Eff
<
L
,
R
>
,
onFailure
:
(
x
:
L
)
=>
Eff
<
L2
,
R2
>
):
Eff
<
L2
,
R2
|
R
>
{
return
this
.
pipe
(
map
((
ethr
:
Either
<
any
,
any
>
)
=>
ethr
.
tag
===
'Left'
?
onFailure
(
ethr
.
value
)
:
Rx
.
of
(
ethr
)),
combineAll
(
x
=>
x
));
};
(
Observable
as
any
).
prototype
.
chain
=
function
<
L
,
R
,
R2
>
(
this
:
Eff
<
L
,
R
>
,
f
:
(
x
:
R
)
=>
Eff
<
L
,
R2
>
):
Eff
<
L
,
R2
>
{
return
this
.
pipe
(
map
(
ethr
=>
ethr
.
tag
===
'Right'
?
f
(
ethr
.
value
)
:
Rx
.
of
(
ethr
)),
combineAll
(
x
=>
x
as
Either
<
any
,
any
>
));
};
(
Observable
as
any
).
prototype
.
chainTo
=
function
<
L
,
R
,
R2
>
(
this
:
Eff
<
L
,
R
>
,
x
:
Eff
<
L
,
R2
>
):
Eff
<
L
,
R2
>
{
return
this
.
pipe
(
map
(
ethr
=>
ethr
.
tag
===
'Right'
?
x
:
Rx
.
of
(
ethr
)),
combineAll
(
x
=>
x
as
Either
<
any
,
any
>
));
};
(
Observable
as
any
).
prototype
.
perform
=
function
<
L
,
R
,
A
>
(
this
:
Eff
<
L
,
R
>
,
onFailure
:
(
x
:
L
)
=>
A
,
onSuccess
:
(
x
:
R
)
=>
A
):
Cmd
<
A
>
{
return
this
.
pipe
(
map
(
ethr
=>
either
.
success
(
ethr
.
fold
(
onFailure
,
onSuccess
))));
};
(
Observable
as
any
).
prototype
.
performMaybe
=
function
<
L
,
R
,
A
>
(
this
:
Eff
<
L
,
R
>
,
onFailure
:
(
x
:
L
)
=>
Option
<
A
>
,
onSuccess
:
(
x
:
R
)
=>
Option
<
A
>
):
Cmd
<
A
>
{
return
this
.
pipe
(
map
(
projectMaybe
),
combineAll
(
x
=>
x
as
Either
<
never
,
A
>
));
function
projectMaybe
(
ethr
:
Either
<
L
,
R
>
):
Eff
<
never
,
A
>
{
const
maybeMessage
=
ethr
.
fold
(
onFailure
,
onSuccess
);
switch
(
maybeMessage
.
tag
)
{
case
'None'
:
return
Rx
.
NEVER
;
case
'Some'
:
return
Rx
.
of
(
either
.
success
(
maybeMessage
.
value
));
}
}
};
(
Observable
as
any
).
prototype
.
performForget
=
function
<
L
,
R
>
(
this
:
Eff
<
L
,
R
>
):
Cmd
<
never
>
{
return
this
.
pipe
(
map
(
x
=>
Rx
.
NEVER
),
combineAll
(
x
=>
x
));
};
// DEPRECATED
(
Observable
as
any
).
prototype
.
chainEff
=
Observable
.
prototype
.
chain
;
(
Observable
as
any
).
prototype
.
mapEff
=
Observable
.
prototype
.
map
;
(
Observable
as
any
).
prototype
.
mapCmd
=
Observable
.
prototype
.
map
;
export
function
failure
<
L
extends
Expr
>
(
error
:
L
):
Eff
<
L
,
never
>
{
return
Rx
.
of
(
either
.
failure
(
error
));
}
export
function
success
<
R
extends
Expr
>
(
success
:
R
):
Eff
<
never
,
R
>
{
return
Rx
.
of
(
either
.
success
(
success
));
}
export
function
callback
(
run
:
()
=>
void
):
Eff
<
never
,
null
>
{
return
Observable
.
create
(
observer
=>
(
run
(),
observer
.
next
(
either
.
success
(
null
)),
observer
.
complete
(),
void
0
));
}
export
function
fromCallback
<
L
,
R
>
(
run
:
(
cb
:
(
x
:
Either
<
L
,
R
>
)
=>
void
)
=>
void
):
Eff
<
L
,
R
>
{
return
Observable
.
create
(
observer
=>
(
run
(
x
=>
(
observer
.
next
(
x
),
observer
.
complete
())),
void
0
));
}
export
function
promise
<
L
,
R
>
(
func
:
(...
args
:
Array
<
any
>
)
=>
Promise
<
Either
<
L
,
R
>>
,
...
args
:
Array
<
any
>
):
Eff
<
L
,
R
>
{
return
Observable
.
create
(
observer
=>
{
func
.
apply
(
undefined
,
args
).
then
(
x
=>
(
observer
.
next
(
x
),
observer
.
complete
())).
catch
(
e
=>
(
observer
.
error
(
e
),
observer
.
complete
()));
})
}
export
{
success
as
of
};
export
function
lazy
<
A
>
(
f
:
()
=>
A
):
Observable
<
A
>
;
export
function
lazy
<
A
,
B
>
(
f
:
(
a
:
A
)
=>
B
,
a
:
A
):
Observable
<
B
>
;
export
function
lazy
<
A
,
B
,
C
>
(
f
:
(
a
:
A
,
b
:
B
)
=>
C
,
a
:
A
,
b
:
B
):
Observable
<
C
>
;
export
function
lazy
<
A
,
B
,
C
,
D
>
(
f
:
(
a
:
A
,
b
:
B
,
c
:
C
)
=>
D
,
a
:
A
,
b
:
B
,
c
:
C
):
Observable
<
D
>
;
export
function
lazy
()
{
const
_arguments
=
arguments
;
return
Observable
.
create
(
observer
=>
{
const
result
=
_arguments
[
0
].
apply
(
undefined
,
Array
(
_arguments
.
length
-
1
).
map
((
_
,
idx
)
=>
_arguments
[
idx
+
1
]));
observer
.
next
(
result
);
observer
.
complete
();
});
}
export
function
ap
<
L
,
A
,
B
>
(
a
:
Eff
<
L
,
A
>
,
f
:
(
a
:
A
)
=>
B
):
Eff
<
L
,
B
>
;
export
function
ap
<
L
,
A
,
B
,
C
>
(
a
:
Eff
<
L
,
A
>
,
b
:
Eff
<
L
,
B
>
,
f
:
(
a
:
A
,
b
:
B
)
=>
C
):
Eff
<
L
,
C
>
;
export
function
ap
<
L
,
A
,
B
,
C
,
D
>
(
a
:
Eff
<
L
,
A
>
,
b
:
Eff
<
L
,
B
>
,
c
:
Eff
<
L
,
C
>
,
f
:
(
a
:
A
,
b
:
B
,
c
:
C
)
=>
D
):
Eff
<
L
,
D
>
;
export
function
ap
<
L
,
A
,
B
,
C
,
D
,
E
>
(
a
:
Eff
<
L
,
A
>
,
b
:
Eff
<
L
,
B
>
,
c
:
Eff
<
L
,
C
>
,
d
:
Eff
<
L
,
D
>
,
f
:
(
a
:
A
,
b
:
B
,
c
:
C
,
d
:
D
)
=>
E
):
Eff
<
L
,
E
>
;
export
function
ap
<
L
,
A
,
B
,
C
,
D
,
E
,
F
>
(
a
:
Eff
<
L
,
A
>
,
b
:
Eff
<
L
,
B
>
,
c
:
Eff
<
L
,
C
>
,
d
:
Eff
<
L
,
D
>
,
e
:
Eff
<
L
,
E
>
,
f
:
(
a
:
A
,
b
:
B
,
c
:
C
,
d
:
D
,
e
:
E
)
=>
F
):
Eff
<
L
,
F
>
;
export
function
ap
<
L
,
A
,
B
,
C
,
D
,
E
,
F
,
G
>
(
a
:
Eff
<
L
,
A
>
,
b
:
Eff
<
L
,
B
>
,
c
:
Eff
<
L
,
C
>
,
d
:
Eff
<
L
,
D
>
,
e
:
Eff
<
L
,
E
>
,
f_
:
Eff
<
L
,
F
>
,
f
:
(
a
:
A
,
b
:
B
,
c
:
C
,
d
:
D
,
e
:
E
,
f
:
F
)
=>
G
):
Eff
<
L
,
G
>
;
export
function
ap
():
Eff
<
any
,
any
>
{
const
_arguments
=
arguments
;
return
Rx
.
combineLatest
(
Array
.
apply
(
undefined
,
Array
(
arguments
.
length
-
1
)).
map
((
_
,
idx
)
=>
_arguments
[
idx
]),
(...
inputs
)
=>
either
.
traverse
(
inputs
,
x
=>
x
as
any
).
map
(
inputs
=>
_arguments
[
_arguments
.
length
-
1
].
apply
(
undefined
,
inputs
)));
}
/** traverse an array */
export
function
traverse
<
ERR
,
A
,
B
>
(
array
:
A
[],
f
:
(
a
:
A
,
idx
:
number
)
=>
Eff
<
ERR
,
B
>
):
Eff
<
ERR
,
B
[]
>
{
if
(
array
.
length
===
0
)
return
success
([]);
// @ts-ignore
return
ap
(...
array
.
map
(
f
),
(...
args
)
=>
args
);
}
/**
* Объединение нескольких параллельно выполняемых `Cmd`
*/
export
function
batch
<
A
>
(
a
:
Cmd
<
A
>
):
Cmd
<
A
>
;
export
function
batch
<
A
,
B
>
(
a
:
Cmd
<
A
>
,
b
:
Cmd
<
B
>
):
Cmd
<
A
|
B
>
;
export
function
batch
<
A
,
B
,
C
>
(
a
:
Cmd
<
A
>
,
b
:
Cmd
<
B
>
,
c
:
Cmd
<
C
>
):
Cmd
<
A
|
B
|
C
>
;
export
function
batch
<
A
,
B
,
C
,
D
>
(
a
:
Cmd
<
A
>
,
b
:
Cmd
<
B
>
,
c
:
Cmd
<
C
>
,
d
:
Cmd
<
D
>
):
Cmd
<
A
|
B
|
C
|
D
>
;
export
function
batch
<
A
,
B
,
C
,
D
,
E
>
(
a
:
Cmd
<
A
>
,
b
:
Cmd
<
B
>
,
c
:
Cmd
<
C
>
,
d
:
Cmd
<
D
>
,
e
:
Cmd
<
E
>
):
Cmd
<
A
|
B
|
C
|
D
|
E
>
;
export
function
batch
<
A
,
B
,
C
,
D
,
E
,
F
>
(
a
:
Cmd
<
A
>
,
b
:
Cmd
<
B
>
,
c
:
Cmd
<
C
>
,
d
:
Cmd
<
D
>
,
e
:
Cmd
<
E
>
,
f
:
Cmd
<
F
>
):
Cmd
<
A
|
B
|
C
|
D
|
E
|
F
>
;
export
function
batch
<
A
,
B
,
C
,
D
,
E
,
F
,
G
>
(
a
:
Cmd
<
A
>
,
b
:
Cmd
<
B
>
,
c
:
Cmd
<
C
>
,
d
:
Cmd
<
D
>
,
e
:
Cmd
<
E
>
,
f
:
Cmd
<
F
>
,
g
:
Cmd
<
G
>
):
Cmd
<
A
|
B
|
C
|
D
|
E
|
F
|
G
>
;
export
function
batch
<
A
,
B
,
C
,
D
,
E
,
F
,
G
,
H
>
(
a
:
Cmd
<
A
>
,
b
:
Cmd
<
B
>
,
c
:
Cmd
<
C
>
,
d
:
Cmd
<
D
>
,
e
:
Cmd
<
E
>
,
f
:
Cmd
<
F
>
,
g
:
Cmd
<
G
>
,
h
:
Cmd
<
H
>
):
Cmd
<
A
|
B
|
C
|
D
|
E
|
F
|
G
|
H
>
;
export
function
batch
<
A
,
B
,
C
,
D
,
E
,
F
,
G
,
H
,
I
>
(
a
:
Cmd
<
A
>
,
b
:
Cmd
<
B
>
,
c
:
Cmd
<
C
>
,
d
:
Cmd
<
D
>
,
e
:
Cmd
<
E
>
,
f
:
Cmd
<
F
>
,
g
:
Cmd
<
G
>
,
h
:
Cmd
<
H
>
,
i
:
Cmd
<
I
>
):
Cmd
<
A
|
B
|
C
|
D
|
E
|
F
|
G
|
H
|
I
>
;
export
function
batch
<
A
,
B
,
C
,
D
,
E
,
F
,
G
,
H
,
I
,
J
>
(
a
:
Cmd
<
A
>
,
b
:
Cmd
<
B
>
,
c
:
Cmd
<
C
>
,
d
:
Cmd
<
D
>
,
e
:
Cmd
<
E
>
,
f
:
Cmd
<
F
>
,
g
:
Cmd
<
G
>
,
h
:
Cmd
<
H
>
,
i
:
Cmd
<
I
>
,
j
:
Cmd
<
J
>
):
Cmd
<
A
|
B
|
C
|
D
|
E
|
F
|
G
|
H
|
I
|
J
>
;
export
function
batch
<
array
extends
Cmd
<
any
>
[]
>
(
signals
:
array
):
Cmd
<
array
[
number
][
'_T'
][
'_R'
]
>
;
export
function
batch
():
Cmd
<
any
>
{
const
observables
=
Array
.
isArray
(
arguments
[
0
])
?
arguments
[
0
]
:
arguments
;
return
Rx
.
merge
.
apply
(
undefined
,
observables
);
}
/**
* Объединение нескольких `Cmd` в очередь
*/
export
function
concat
<
A
>
(
a
:
Cmd
<
A
>
):
Cmd
<
A
>
;
export
function
concat
<
A
,
B
>
(
a
:
Cmd
<
A
>
,
b
:
Cmd
<
B
>
):
Cmd
<
A
|
B
>
;
export
function
concat
<
A
,
B
,
C
>
(
a
:
Cmd
<
A
>
,
b
:
Cmd
<
B
>
,
c
:
Cmd
<
C
>
):
Cmd
<
A
|
B
|
C
>
;
export
function
concat
<
A
,
B
,
C
,
D
>
(
a
:
Cmd
<
A
>
,
b
:
Cmd
<
B
>
,
c
:
Cmd
<
C
>
,
d
:
Cmd
<
D
>
):
Cmd
<
A
|
B
|
C
|
D
>
;
export
function
concat
<
A
,
B
,
C
,
D
,
E
>
(
a
:
Cmd
<
A
>
,
b
:
Cmd
<
B
>
,
c
:
Cmd
<
C
>
,
d
:
Cmd
<
D
>
,
e
:
Cmd
<
E
>
):
Cmd
<
A
|
B
|
C
|
D
|
E
>
;
export
function
concat
<
A
,
B
,
C
,
D
,
E
,
F
>
(
a
:
Cmd
<
A
>
,
b
:
Cmd
<
B
>
,
c
:
Cmd
<
C
>
,
d
:
Cmd
<
D
>
,
e
:
Cmd
<
E
>
,
f
:
Cmd
<
F
>
):
Cmd
<
A
|
B
|
C
|
D
|
E
|
F
>
;
export
function
concat
<
A
,
B
,
C
,
D
,
E
,
F
,
G
>
(
a
:
Cmd
<
A
>
,
b
:
Cmd
<
B
>
,
c
:
Cmd
<
C
>
,
d
:
Cmd
<
D
>
,
e
:
Cmd
<
E
>
,
f
:
Cmd
<
F
>
,
g
:
Cmd
<
G
>
):
Cmd
<
A
|
B
|
C
|
D
|
E
|
F
|
G
>
;
export
function
concat
<
A
,
B
,
C
,
D
,
E
,
F
,
G
,
H
>
(
a
:
Cmd
<
A
>
,
b
:
Cmd
<
B
>
,
c
:
Cmd
<
C
>
,
d
:
Cmd
<
D
>
,
e
:
Cmd
<
E
>
,
f
:
Cmd
<
F
>
,
g
:
Cmd
<
G
>
,
h
:
Cmd
<
H
>
):
Cmd
<
A
|
B
|
C
|
D
|
E
|
F
|
G
|
H
>
;
export
function
concat
<
A
,
B
,
C
,
D
,
E
,
F
,
G
,
H
,
I
>
(
a
:
Cmd
<
A
>
,
b
:
Cmd
<
B
>
,
c
:
Cmd
<
C
>
,
d
:
Cmd
<
D
>
,
e
:
Cmd
<
E
>
,
f
:
Cmd
<
F
>
,
g
:
Cmd
<
G
>
,
h
:
Cmd
<
H
>
,
i
:
Cmd
<
I
>
):
Cmd
<
A
|
B
|
C
|
D
|
E
|
F
|
G
|
H
|
I
>
;
export
function
concat
<
A
,
B
,
C
,
D
,
E
,
F
,
G
,
H
,
I
,
J
>
(
a
:
Cmd
<
A
>
,
b
:
Cmd
<
B
>
,
c
:
Cmd
<
C
>
,
d
:
Cmd
<
D
>
,
e
:
Cmd
<
E
>
,
f
:
Cmd
<
F
>
,
g
:
Cmd
<
G
>
,
h
:
Cmd
<
H
>
,
i
:
Cmd
<
I
>
,
j
:
Cmd
<
J
>
):
Cmd
<
A
|
B
|
C
|
D
|
E
|
F
|
G
|
H
|
I
|
J
>
;
export
function
concat
<
array
extends
Cmd
<
any
>
[]
>
(
signals
:
array
):
Cmd
<
array
[
number
][
'_T'
][
'_R'
]
>
;
export
function
concat
():
Cmd
<
any
>
{
const
observables
=
Array
.
isArray
(
arguments
[
0
])
?
arguments
[
0
]
:
arguments
;
return
Rx
.
concat
.
apply
(
undefined
,
observables
);
}
/**
* Примитивный `Cmd` не генерирует никаких действий, завершается сразу
* после запуска.
*/
export
const
noop
:
Cmd
<
never
>
=
new
Rx
.
Observable
(
observer
=>
observer
.
complete
());
/**
* Выполнение сайд-еффектов. Observable не генерирует событий, после
* запуска вызывается переданная функция и Observable завершается.
*/
export
function
forget
<
A
>
(
f
:
()
=>
A
):
Cmd
<
never
>
;
export
function
forget
<
A
,
B
>
(
f
:
(
a
:
A
)
=>
B
,
a
:
A
):
Cmd
<
never
>
;
export
function
forget
<
A
,
B
,
C
>
(
f
:
(
a
:
A
,
b
:
B
)
=>
C
,
a
:
A
,
b
:
B
):
Cmd
<
never
>
;
export
function
forget
<
A
,
B
,
C
,
D
>
(
f
:
(
a
:
A
,
b
:
B
,
c
:
C
)
=>
D
,
a
:
A
,
b
:
B
,
c
:
C
):
Cmd
<
never
>
;
export
function
forget
(
f
:
(...
args
:
any
[])
=>
void
,
...
rest
:
any
[]):
Cmd
<
never
>
{
return
Observable
.
create
(
observer
=>
(
f
.
apply
(
undefined
,
rest
),
observer
.
complete
()));
}
export
*
from
'../eff'
;
core/http.ts
View file @
6894e538
import
*
as
Rx
from
'rxjs'
;
import
{
Eff
}
from
'./eff'
;
import
*
as
eff
from
'./eff'
;
import
{
Decoder
,
Problem
}
from
'../decoder'
;
import
{
success
,
failure
}
from
'../either'
;
/** http method */
export
type
Method
=
'GET'
|
'POST'
|
'PUT'
|
'DELETE'
|
'PATCH'
;
/** request */
export
interface
Request
{
url
:
string
;
method
:
Method
;
body
?:
any
;
headers
?:
Record
<
string
,
string
|
number
|
undefined
|
null
>
;
withCredentials
?:
boolean
;
timeout
?:
number
;
}
/** raw error */
export
type
HttpError
=
|
{
tag
:
'BadUrl'
,
desc
:
string
}
|
{
tag
:
'BadPayload'
,
desc
:
string
}
|
{
tag
:
'ValidationProblem'
,
problem
:
Problem
,
url
:
string
}
|
{
tag
:
'BadStatus'
,
status
:
number
,
desc
:
string
}
|
{
tag
:
'Timeout'
}
|
{
tag
:
'NetworkError'
}
/** responce */
export
interface
Response
{
url
:
string
;
status
:
number
;
statusText
:
string
;
headers
:
Record
<
string
,
string
>
;
body
:
string
;
}
/** query params */
export
type
ParamsPrimitive
=
number
|
string
|
undefined
|
null
;
export
type
Params
=
Record
<
string
,
ParamsPrimitive
|
ParamsPrimitive
[]
>
;
/** progress */
export
type
Progress
=
|
{
tag
:
'Computable'
,
total
:
number
,
loaded
:
number
}
|
{
tag
:
'Uncomputable'
}
/** send a request */
export
function
send
(
req
:
Request
):
Eff
<
HttpError
,
Response
>
{
return
Rx
.
Observable
.
create
(
observer
=>
{
const
xhr
=
new
XMLHttpRequest
();
xhr
.
addEventListener
(
'error'
,
()
=>
(
observer
.
next
(
failure
({
tag
:
'NetworkError'
}
as
HttpError
)),
observer
.
complete
()));
xhr
.
addEventListener
(
'timeout'
,
()
=>
(
observer
.
next
(
failure
({
tag
:
'Timeout'
}
as
HttpError
)),
observer
.
complete
()));
xhr
.
addEventListener
(
'load'
,
()
=>
{
observer
.
next
(
success
({
url
:
xhr
.
responseURL
,
status
:
xhr
.
status
,
statusText
:
xhr
.
statusText
,
headers
:
parseHeaders
(
xhr
.
getAllResponseHeaders
()),
body
:
xhr
.
response
||
xhr
.
responseText
,
}));
observer
.
complete
();
});
try
{
xhr
.
open
(
req
.
method
,
req
.
url
,
true
);
}
catch
(
e
)
{
observer
.
next
(
failure
({
tag
:
'BadUrl'
,
desc
:
req
.
url
}
as
HttpError
));
observer
.
complete
();
}
//xhr.addEventListener('progress', e => onResult(success(e.lengthComputable ? { tag: 'Computable', loaded: e.loaded, total: e.total } : { tag: 'Uncomputable' })));
if
(
req
.
timeout
)
xhr
.
timeout
=
req
.
timeout
;
if
(
typeof
(
req
.
withCredentials
)
!==
'undefined'
)
xhr
.
withCredentials
=
req
.
withCredentials
;
if
(
typeof
(
req
.
headers
)
!==
'undefined'
)
{
for
(
let
key
in
req
.
headers
)
{
if
(
!
req
.
headers
.
hasOwnProperty
(
key
))
continue
;
const
value
=
req
.
headers
[
key
];
if
(
typeof
(
value
)
!==
'undefined'
&&
value
!==
null
)
xhr
.
setRequestHeader
(
key
,
String
(
value
));
}
}
const
body
=
Object
.
prototype
.
toString
.
apply
(
req
.
body
)
===
'[object Object]'
?
JSON
.
stringify
(
req
.
body
)
:
req
.
body
;
xhr
.
send
(
body
);
return
()
=>
xhr
.
abort
();
});
}
/** shortcut for GET requests */
export
function
get
(
url
:
string
,
extra
?:
Partial
<
Request
>
):
Eff
<
HttpError
,
Response
>
{
return
send
(
Object
.
assign
({},
extra
,
{
method
:
'GET'
,
url
})
as
any
);
}
/** shortcut for POST requests */
export
function
post
(
url
:
string
,
extra
?:
Partial
<
Request
>
):
Eff
<
HttpError
,
Response
>
{
return
send
(
Object
.
assign
({},
extra
,
{
method
:
'POST'
,
url
})
as
any
);
}
/** parse response as JSON */
export
function
expectJSON
<
A
>
(
decoder
:
Decoder
<
A
>
):
(
resp
:
Response
)
=>
Eff
<
HttpError
,
A
>
{
return
resp
=>
{
if
(
resp
.
body
===
''
)
return
eff
.
failure
({
tag
:
'BadPayload'
,
desc
:
'empty body'
}
as
HttpError
);
let
val
=
null
;
try
{
val
=
JSON
.
parse
(
resp
.
body
);
}
catch
(
e
)
{
return
eff
.
failure
({
tag
:
'BadPayload'
,
desc
:
'invalid json'
}
as
HttpError
);
}
return
Rx
.
of
(
decoder
.
validate
(
val
).
mapLeft
(
problem
=>
({
tag
:
'ValidationProblem'
,
problem
,
url
:
resp
.
url
}
as
HttpError
)));
};
}
/** parse headers from string to dict */
function
parseHeaders
(
rawHeaders
:
string
):
Record
<
string
,
string
>
{
const
output
=
{};
const
lines
=
rawHeaders
.
split
(
'
\
r
\
n'
);
for
(
let
i
in
lines
)
{
const
index
=
lines
[
i
].
indexOf
(
': '
);
if
(
index
<
0
)
continue
;
const
key
=
lines
[
i
].
substring
(
0
,
index
);
const
value
=
lines
[
i
].
substring
(
index
+
2
);
output
[
key
]
=
value
;
}
return
output
;
}
/** join segments of url */
function
joinTwo
(
a
:
string
,
b
:
string
):
string
{
if
(
a
===
''
)
return
b
;
if
(
b
===
''
)
return
a
;
const
trailing
=
a
.
length
&&
a
[
a
.
length
-
1
]
===
'/'
;
const
leading
=
b
.
length
&&
b
[
0
]
===
'/'
;
if
(
trailing
&&
leading
)
return
a
.
substring
(
0
,
a
.
length
-
1
)
+
b
;
if
(
!
trailing
&&
!
leading
)
return
a
+
'/'
+
b
;
return
a
+
b
;
}
/** build an url */
export
function
join
(...
args
:
Array
<
string
|
Params
>
):
string
{
let
path
=
''
;
let
params
=
{}
as
Record
<
string
,
string
>
;
let
query
=
''
;
for
(
let
i
in
args
)
{
const
arg
=
args
[
i
];
if
(
typeof
(
arg
)
===
'string'
)
path
=
joinTwo
(
path
,
arg
);
else
Object
[
'assign'
](
params
,
arg
);
}
for
(
let
key
in
params
)
{
if
(
!
params
.
hasOwnProperty
(
key
)
||
typeof
(
params
[
key
])
===
'undefined'
||
params
[
key
]
===
null
)
continue
;
if
(
Array
.
isArray
(
params
[
key
]))
{
for
(
const
v
of
params
[
key
])
{
if
(
typeof
(
params
[
key
])
===
'undefined'
||
params
[
key
]
===
null
)
continue
;
query
+=
(
query
?
'&'
:
''
)
+
`
${
encodeURIComponent
(
key
)}
=
${
encodeURIComponent
(
v
)}
`
;
}
}
else
{
query
+=
(
query
?
'&'
:
''
)
+
`
${
encodeURIComponent
(
key
)}
=
${
encodeURIComponent
(
params
[
key
])}
`
;
}
}
return
query
?
(
path
+
'?'
+
query
)
:
path
;
}
export
*
from
'../http'
;
eff/index.ts
0 → 100644
View file @
6894e538
import
{
Either
}
from
'../either'
;
import
{
Option
}
from
'../maybe'
;
import
*
as
either
from
'../either'
;
import
{
Observable
}
from
'rxjs'
;
import
*
as
Rx
from
'rxjs'
;
import
{
map
}
from
'rxjs/internal/operators/map'
;
import
{
combineAll
}
from
'rxjs/internal/operators/combineAll'
;
import
{
Expr
}
from
'../types'
;
/**
* Тайп-алиасы для удобства
*/
export
type
Eff
<
Error
,
Success
>
=
Observable
<
Either
<
Error
,
Success
>>
;
export
type
Cmd
<
Action
>
=
Eff
<
never
,
Action
>
;
declare
module
'rxjs/internal/Observable'
{
export
interface
Observable
<
T
>
{
readonly
_T
:
T
;
map
<
L
,
R
,
R2
>
(
this
:
Eff
<
L
,
R
>
,
f
:
(
x
:
R
)
=>
R2
):
Eff
<
L
,
R2
>
;
mapTo
<
L
,
R
,
R2
>
(
this
:
Eff
<
L
,
R
>
,
x
:
R2
):
Eff
<
L
,
R2
>
;
mapError
<
L
,
R
,
L2
>
(
this
:
Eff
<
L
,
R
>
,
f
:
(
x
:
L
)
=>
L2
):
Eff
<
L2
,
R
>
;
mapErrorTo
<
L
,
R
,
L2
>
(
this
:
Eff
<
L
,
R
>
,
x
:
L2
):
Eff
<
L2
,
R
>
;
perform
<
L
,
R
,
A
>
(
this
:
Eff
<
L
,
R
>
,
onFailure
:
(
x
:
L
)
=>
A
,
onSuccess
:
(
x
:
R
)
=>
A
):
Cmd
<
A
>
;
perform
<
L
,
R
,
A1
,
A2
>
(
this
:
Eff
<
L
,
R
>
,
onFailure
:
(
x
:
L
)
=>
A1
,
onSuccess
:
(
x
:
R
)
=>
A2
):
Cmd
<
A1
|
A2
>
;
performMaybe
<
L
,
R
,
A
>
(
this
:
Eff
<
L
,
R
>
,
onFailure
:
(
x
:
L
)
=>
Option
<
A
>
,
onSuccess
:
(
x
:
R
)
=>
Option
<
A
>
):
Cmd
<
A
>
;
performMaybe
<
L
,
R
,
A1
,
A2
>
(
this
:
Eff
<
L
,
R
>
,
onFailure
:
(
x
:
L
)
=>
Option
<
A1
>
,
onSuccess
:
(
x
:
R
)
=>
Option
<
A2
>
):
Cmd
<
A1
|
A2
>
;
performForget
<
L
,
R
>
(
this
:
Eff
<
L
,
R
>
):
Cmd
<
never
>
;
performSuccess
<
R
,
A
>
(
this
:
Eff
<
never
,
R
>
,
onSuccess
:
(
x
:
R
)
=>
A
):
Cmd
<
A
>
;
onError
<
L
,
R
,
L2
,
R2
>
(
this
:
Eff
<
L
,
R
>
,
onFailure
:
(
x
:
L
)
=>
Eff
<
L2
,
R2
>
):
Eff
<
L2
,
R2
|
R
>
;
chain
<
L
,
R
,
R2
>
(
this
:
Eff
<
L
,
R
>
,
f
:
(
x
:
R
)
=>
Eff
<
L
,
R2
>
):
Eff
<
L
,
R2
>
;
chain
<
L
,
R
,
L2
,
R2
>
(
this
:
Eff
<
L
,
R
>
,
f
:
(
x
:
R
)
=>
Eff
<
L2
,
R2
>
):
Eff
<
L
|
L2
,
R2
>
;
chainTo
<
L
,
R
,
R2
>
(
this
:
Eff
<
L
,
R
>
,
effect
:
Eff
<
L
,
R2
>
):
Eff
<
L
,
R2
>
;
chainTo
<
L
,
R
,
L2
,
R2
>
(
this
:
Eff
<
L
,
R
>
,
effect
:
Eff
<
L2
,
R2
>
):
Eff
<
L
|
L2
,
R2
>
;
// DEPRECATED
chainEff
<
L
,
R
,
R2
>
(
this
:
Eff
<
L
,
R
>
,
f
:
(
x
:
R
)
=>
Eff
<
L
,
R2
>
):
Eff
<
L
,
R2
>
;
chainEff
<
L
,
R
,
L2
,
R2
>
(
this
:
Eff
<
L
,
R
>
,
f
:
(
x
:
R
)
=>
Eff
<
L2
,
R2
>
):
Eff
<
L
|
L2
,
R2
>
;
mapEff
<
L
,
R
,
R2
>
(
this
:
Eff
<
L
,
R
>
,
f
:
(
x
:
R
)
=>
R2
):
Eff
<
L
,
R2
>
;
mapCmd
<
L
,
R
,
R2
>
(
this
:
Eff
<
L
,
R
>
,
f
:
(
x
:
R
)
=>
R2
):
Eff
<
L
,
R2
>
;
}
}
(
Observable
as
any
).
prototype
.
map
=
function
<
L
,
R
,
R2
>
(
this
:
Eff
<
L
,
R
>
,
f
:
(
x
:
R
)
=>
R2
):
Eff
<
L
,
R2
>
{
return
this
.
pipe
(
map
(
ethr
=>
ethr
.
map
(
f
)));
};
(
Observable
as
any
).
prototype
.
mapTo
=
function
<
L
,
R
,
R2
>
(
this
:
Eff
<
L
,
R
>
,
x
:
R2
):
Eff
<
L
,
R2
>
{
return
this
.
pipe
(
map
(
ethr
=>
ethr
.
map
(()
=>
x
)));
};
(
Observable
as
any
).
prototype
.
mapError
=
function
<
L
,
R
,
L2
>
(
this
:
Eff
<
L
,
R
>
,
f
:
(
x
:
L
)
=>
L2
):
Eff
<
L2
,
R
>
{
return
this
.
pipe
(
map
(
ethr
=>
ethr
.
mapLeft
(
f
)));
};
(
Observable
as
any
).
prototype
.
mapErrorTo
=
function
<
L
,
R
,
L2
>
(
this
:
Eff
<
L
,
R
>
,
x
:
L2
):
Eff
<
L2
,
R
>
{
return
this
.
pipe
(
map
(
ethr
=>
ethr
.
mapLeft
(()
=>
x
)));
};
(
Observable
as
any
).
prototype
.
onError
=
function
<
L
,
R
,
L2
,
R2
>
(
this
:
Eff
<
L
,
R
>
,
onFailure
:
(
x
:
L
)
=>
Eff
<
L2
,
R2
>
):
Eff
<
L2
,
R2
|
R
>
{
return
this
.
pipe
(
map
((
ethr
:
Either
<
any
,
any
>
)
=>
ethr
.
tag
===
'Left'
?
onFailure
(
ethr
.
value
)
:
Rx
.
of
(
ethr
)),
combineAll
(
x
=>
x
));
};
(
Observable
as
any
).
prototype
.
chain
=
function
<
L
,
R
,
R2
>
(
this
:
Eff
<
L
,
R
>
,
f
:
(
x
:
R
)
=>
Eff
<
L
,
R2
>
):
Eff
<
L
,
R2
>
{
return
this
.
pipe
(
map
(
ethr
=>
ethr
.
tag
===
'Right'
?
f
(
ethr
.
value
)
:
Rx
.
of
(
ethr
)),
combineAll
(
x
=>
x
as
Either
<
any
,
any
>
));
};
(
Observable
as
any
).
prototype
.
chainTo
=
function
<
L
,
R
,
R2
>
(
this
:
Eff
<
L
,
R
>
,
x
:
Eff
<
L
,
R2
>
):
Eff
<
L
,
R2
>
{
return
this
.
pipe
(
map
(
ethr
=>
ethr
.
tag
===
'Right'
?
x
:
Rx
.
of
(
ethr
)),
combineAll
(
x
=>
x
as
Either
<
any
,
any
>
));
};
(
Observable
as
any
).
prototype
.
perform
=
function
<
L
,
R
,
A
>
(
this
:
Eff
<
L
,
R
>
,
onFailure
:
(
x
:
L
)
=>
A
,
onSuccess
:
(
x
:
R
)
=>
A
):
Cmd
<
A
>
{
return
this
.
pipe
(
map
(
ethr
=>
either
.
success
(
ethr
.
fold
(
onFailure
,
onSuccess
))));
};
(
Observable
as
any
).
prototype
.
performMaybe
=
function
<
L
,
R
,
A
>
(
this
:
Eff
<
L
,
R
>
,
onFailure
:
(
x
:
L
)
=>
Option
<
A
>
,
onSuccess
:
(
x
:
R
)
=>
Option
<
A
>
):
Cmd
<
A
>
{
return
this
.
pipe
(
map
(
projectMaybe
),
combineAll
(
x
=>
x
as
Either
<
never
,
A
>
));
function
projectMaybe
(
ethr
:
Either
<
L
,
R
>
):
Eff
<
never
,
A
>
{
const
maybeMessage
=
ethr
.
fold
(
onFailure
,
onSuccess
);
switch
(
maybeMessage
.
tag
)
{
case
'None'
:
return
Rx
.
NEVER
;
case
'Some'
:
return
Rx
.
of
(
either
.
success
(
maybeMessage
.
value
));
}
}
};
(
Observable
as
any
).
prototype
.
performForget
=
function
<
L
,
R
>
(
this
:
Eff
<
L
,
R
>
):
Cmd
<
never
>
{
return
this
.
pipe
(
map
(
x
=>
Rx
.
NEVER
),
combineAll
(
x
=>
x
));
};
// DEPRECATED
(
Observable
as
any
).
prototype
.
chainEff
=
Observable
.
prototype
.
chain
;
(
Observable
as
any
).
prototype
.
mapEff
=
Observable
.
prototype
.
map
;
(
Observable
as
any
).
prototype
.
mapCmd
=
Observable
.
prototype
.
map
;
export
function
failure
<
L
extends
Expr
>
(
error
:
L
):
Eff
<
L
,
never
>
{
return
Rx
.
of
(
either
.
failure
(
error
));
}
export
function
success
<
R
extends
Expr
>
(
success
:
R
):
Eff
<
never
,
R
>
{
return
Rx
.
of
(
either
.
success
(
success
));
}
export
function
callback
(
run
:
()
=>
void
):
Eff
<
never
,
null
>
{
return
Observable
.
create
(
observer
=>
(
run
(),
observer
.
next
(
either
.
success
(
null
)),
observer
.
complete
(),
void
0
));
}
export
function
fromCallback
<
L
,
R
>
(
run
:
(
cb
:
(
x
:
Either
<
L
,
R
>
)
=>
void
)
=>
void
):
Eff
<
L
,
R
>
{
return
Observable
.
create
(
observer
=>
(
run
(
x
=>
(
observer
.
next
(
x
),
observer
.
complete
())),
void
0
));
}
export
function
promise
<
L
,
R
>
(
func
:
(...
args
:
Array
<
any
>
)
=>
Promise
<
Either
<
L
,
R
>>
,
...
args
:
Array
<
any
>
):
Eff
<
L
,
R
>
{
return
Observable
.
create
(
observer
=>
{
func
.
apply
(
undefined
,
args
).
then
(
x
=>
(
observer
.
next
(
x
),
observer
.
complete
())).
catch
(
e
=>
(
observer
.
error
(
e
),
observer
.
complete
()));
})
}
export
{
success
as
of
};
export
function
lazy
<
A
>
(
f
:
()
=>
A
):
Observable
<
A
>
;
export
function
lazy
<
A
,
B
>
(
f
:
(
a
:
A
)
=>
B
,
a
:
A
):
Observable
<
B
>
;
export
function
lazy
<
A
,
B
,
C
>
(
f
:
(
a
:
A
,
b
:
B
)
=>
C
,
a
:
A
,
b
:
B
):
Observable
<
C
>
;
export
function
lazy
<
A
,
B
,
C
,
D
>
(
f
:
(
a
:
A
,
b
:
B
,
c
:
C
)
=>
D
,
a
:
A
,
b
:
B
,
c
:
C
):
Observable
<
D
>
;
export
function
lazy
()
{
const
_arguments
=
arguments
;
return
Observable
.
create
(
observer
=>
{
const
result
=
_arguments
[
0
].
apply
(
undefined
,
Array
(
_arguments
.
length
-
1
).
map
((
_
,
idx
)
=>
_arguments
[
idx
+
1
]));
observer
.
next
(
result
);
observer
.
complete
();
});
}
export
function
ap
<
L
,
A
,
B
>
(
a
:
Eff
<
L
,
A
>
,
f
:
(
a
:
A
)
=>
B
):
Eff
<
L
,
B
>
;
export
function
ap
<
L
,
A
,
B
,
C
>
(
a
:
Eff
<
L
,
A
>
,
b
:
Eff
<
L
,
B
>
,
f
:
(
a
:
A
,
b
:
B
)
=>
C
):
Eff
<
L
,
C
>
;
export
function
ap
<
L
,
A
,
B
,
C
,
D
>
(
a
:
Eff
<
L
,
A
>
,
b
:
Eff
<
L
,
B
>
,
c
:
Eff
<
L
,
C
>
,
f
:
(
a
:
A
,
b
:
B
,
c
:
C
)
=>
D
):
Eff
<
L
,
D
>
;
export
function
ap
<
L
,
A
,
B
,
C
,
D
,
E
>
(
a
:
Eff
<
L
,
A
>
,
b
:
Eff
<
L
,
B
>
,
c
:
Eff
<
L
,
C
>
,
d
:
Eff
<
L
,
D
>
,
f
:
(
a
:
A
,
b
:
B
,
c
:
C
,
d
:
D
)
=>
E
):
Eff
<
L
,
E
>
;
export
function
ap
<
L
,
A
,
B
,
C
,
D
,
E
,
F
>
(
a
:
Eff
<
L
,
A
>
,
b
:
Eff
<
L
,
B
>
,
c
:
Eff
<
L
,
C
>
,
d
:
Eff
<
L
,
D
>
,
e
:
Eff
<
L
,
E
>
,
f
:
(
a
:
A
,
b
:
B
,
c
:
C
,
d
:
D
,
e
:
E
)
=>
F
):
Eff
<
L
,
F
>
;
export
function
ap
<
L
,
A
,
B
,
C
,
D
,
E
,
F
,
G
>
(
a
:
Eff
<
L
,
A
>
,
b
:
Eff
<
L
,
B
>
,
c
:
Eff
<
L
,
C
>
,
d
:
Eff
<
L
,
D
>
,
e
:
Eff
<
L
,
E
>
,
f_
:
Eff
<
L
,
F
>
,
f
:
(
a
:
A
,
b
:
B
,
c
:
C
,
d
:
D
,
e
:
E
,
f
:
F
)
=>
G
):
Eff
<
L
,
G
>
;
export
function
ap
():
Eff
<
any
,
any
>
{
const
_arguments
=
arguments
;
return
Rx
.
combineLatest
(
Array
.
apply
(
undefined
,
Array
(
arguments
.
length
-
1
)).
map
((
_
,
idx
)
=>
_arguments
[
idx
]),
(...
inputs
)
=>
either
.
traverse
(
inputs
,
x
=>
x
as
any
).
map
(
inputs
=>
_arguments
[
_arguments
.
length
-
1
].
apply
(
undefined
,
inputs
)));
}
/** traverse an array */
export
function
traverse
<
ERR
,
A
,
B
>
(
array
:
A
[],
f
:
(
a
:
A
,
idx
:
number
)
=>
Eff
<
ERR
,
B
>
):
Eff
<
ERR
,
B
[]
>
{
if
(
array
.
length
===
0
)
return
success
([]);
// @ts-ignore
return
ap
(...
array
.
map
(
f
),
(...
args
)
=>
args
);
}
/**
* Объединение нескольких параллельно выполняемых `Cmd`
*/
export
function
batch
<
A
>
(
a
:
Cmd
<
A
>
):
Cmd
<
A
>
;
export
function
batch
<
A
,
B
>
(
a
:
Cmd
<
A
>
,
b
:
Cmd
<
B
>
):
Cmd
<
A
|
B
>
;
export
function
batch
<
A
,
B
,
C
>
(
a
:
Cmd
<
A
>
,
b
:
Cmd
<
B
>
,
c
:
Cmd
<
C
>
):
Cmd
<
A
|
B
|
C
>
;
export
function
batch
<
A
,
B
,
C
,
D
>
(
a
:
Cmd
<
A
>
,
b
:
Cmd
<
B
>
,
c
:
Cmd
<
C
>
,
d
:
Cmd
<
D
>
):
Cmd
<
A
|
B
|
C
|
D
>
;
export
function
batch
<
A
,
B
,
C
,
D
,
E
>
(
a
:
Cmd
<
A
>
,
b
:
Cmd
<
B
>
,
c
:
Cmd
<
C
>
,
d
:
Cmd
<
D
>
,
e
:
Cmd
<
E
>
):
Cmd
<
A
|
B
|
C
|
D
|
E
>
;
export
function
batch
<
A
,
B
,
C
,
D
,
E
,
F
>
(
a
:
Cmd
<
A
>
,
b
:
Cmd
<
B
>
,
c
:
Cmd
<
C
>
,
d
:
Cmd
<
D
>
,
e
:
Cmd
<
E
>
,
f
:
Cmd
<
F
>
):
Cmd
<
A
|
B
|
C
|
D
|
E
|
F
>
;
export
function
batch
<
A
,
B
,
C
,
D
,
E
,
F
,
G
>
(
a
:
Cmd
<
A
>
,
b
:
Cmd
<
B
>
,
c
:
Cmd
<
C
>
,
d
:
Cmd
<
D
>
,
e
:
Cmd
<
E
>
,
f
:
Cmd
<
F
>
,
g
:
Cmd
<
G
>
):
Cmd
<
A
|
B
|
C
|
D
|
E
|
F
|
G
>
;
export
function
batch
<
A
,
B
,
C
,
D
,
E
,
F
,
G
,
H
>
(
a
:
Cmd
<
A
>
,
b
:
Cmd
<
B
>
,
c
:
Cmd
<
C
>
,
d
:
Cmd
<
D
>
,
e
:
Cmd
<
E
>
,
f
:
Cmd
<
F
>
,
g
:
Cmd
<
G
>
,
h
:
Cmd
<
H
>
):
Cmd
<
A
|
B
|
C
|
D
|
E
|
F
|
G
|
H
>
;
export
function
batch
<
A
,
B
,
C
,
D
,
E
,
F
,
G
,
H
,
I
>
(
a
:
Cmd
<
A
>
,
b
:
Cmd
<
B
>
,
c
:
Cmd
<
C
>
,
d
:
Cmd
<
D
>
,
e
:
Cmd
<
E
>
,
f
:
Cmd
<
F
>
,
g
:
Cmd
<
G
>
,
h
:
Cmd
<
H
>
,
i
:
Cmd
<
I
>
):
Cmd
<
A
|
B
|
C
|
D
|
E
|
F
|
G
|
H
|
I
>
;
export
function
batch
<
A
,
B
,
C
,
D
,
E
,
F
,
G
,
H
,
I
,
J
>
(
a
:
Cmd
<
A
>
,
b
:
Cmd
<
B
>
,
c
:
Cmd
<
C
>
,
d
:
Cmd
<
D
>
,
e
:
Cmd
<
E
>
,
f
:
Cmd
<
F
>
,
g
:
Cmd
<
G
>
,
h
:
Cmd
<
H
>
,
i
:
Cmd
<
I
>
,
j
:
Cmd
<
J
>
):
Cmd
<
A
|
B
|
C
|
D
|
E
|
F
|
G
|
H
|
I
|
J
>
;
export
function
batch
<
array
extends
Cmd
<
any
>
[]
>
(
signals
:
array
):
Cmd
<
array
[
number
][
'_T'
][
'_R'
]
>
;
export
function
batch
():
Cmd
<
any
>
{
const
observables
=
Array
.
isArray
(
arguments
[
0
])
?
arguments
[
0
]
:
arguments
;
return
Rx
.
merge
.
apply
(
undefined
,
observables
);
}
/**
* Объединение нескольких `Cmd` в очередь
*/
export
function
concat
<
A
>
(
a
:
Cmd
<
A
>
):
Cmd
<
A
>
;
export
function
concat
<
A
,
B
>
(
a
:
Cmd
<
A
>
,
b
:
Cmd
<
B
>
):
Cmd
<
A
|
B
>
;
export
function
concat
<
A
,
B
,
C
>
(
a
:
Cmd
<
A
>
,
b
:
Cmd
<
B
>
,
c
:
Cmd
<
C
>
):
Cmd
<
A
|
B
|
C
>
;
export
function
concat
<
A
,
B
,
C
,
D
>
(
a
:
Cmd
<
A
>
,
b
:
Cmd
<
B
>
,
c
:
Cmd
<
C
>
,
d
:
Cmd
<
D
>
):
Cmd
<
A
|
B
|
C
|
D
>
;
export
function
concat
<
A
,
B
,
C
,
D
,
E
>
(
a
:
Cmd
<
A
>
,
b
:
Cmd
<
B
>
,
c
:
Cmd
<
C
>
,
d
:
Cmd
<
D
>
,
e
:
Cmd
<
E
>
):
Cmd
<
A
|
B
|
C
|
D
|
E
>
;
export
function
concat
<
A
,
B
,
C
,
D
,
E
,
F
>
(
a
:
Cmd
<
A
>
,
b
:
Cmd
<
B
>
,
c
:
Cmd
<
C
>
,
d
:
Cmd
<
D
>
,
e
:
Cmd
<
E
>
,
f
:
Cmd
<
F
>
):
Cmd
<
A
|
B
|
C
|
D
|
E
|
F
>
;
export
function
concat
<
A
,
B
,
C
,
D
,
E
,
F
,
G
>
(
a
:
Cmd
<
A
>
,
b
:
Cmd
<
B
>
,
c
:
Cmd
<
C
>
,
d
:
Cmd
<
D
>
,
e
:
Cmd
<
E
>
,
f
:
Cmd
<
F
>
,
g
:
Cmd
<
G
>
):
Cmd
<
A
|
B
|
C
|
D
|
E
|
F
|
G
>
;
export
function
concat
<
A
,
B
,
C
,
D
,
E
,
F
,
G
,
H
>
(
a
:
Cmd
<
A
>
,
b
:
Cmd
<
B
>
,
c
:
Cmd
<
C
>
,
d
:
Cmd
<
D
>
,
e
:
Cmd
<
E
>
,
f
:
Cmd
<
F
>
,
g
:
Cmd
<
G
>
,
h
:
Cmd
<
H
>
):
Cmd
<
A
|
B
|
C
|
D
|
E
|
F
|
G
|
H
>
;
export
function
concat
<
A
,
B
,
C
,
D
,
E
,
F
,
G
,
H
,
I
>
(
a
:
Cmd
<
A
>
,
b
:
Cmd
<
B
>
,
c
:
Cmd
<
C
>
,
d
:
Cmd
<
D
>
,
e
:
Cmd
<
E
>
,
f
:
Cmd
<
F
>
,
g
:
Cmd
<
G
>
,
h
:
Cmd
<
H
>
,
i
:
Cmd
<
I
>
):
Cmd
<
A
|
B
|
C
|
D
|
E
|
F
|
G
|
H
|
I
>
;
export
function
concat
<
A
,
B
,
C
,
D
,
E
,
F
,
G
,
H
,
I
,
J
>
(
a
:
Cmd
<
A
>
,
b
:
Cmd
<
B
>
,
c
:
Cmd
<
C
>
,
d
:
Cmd
<
D
>
,
e
:
Cmd
<
E
>
,
f
:
Cmd
<
F
>
,
g
:
Cmd
<
G
>
,
h
:
Cmd
<
H
>
,
i
:
Cmd
<
I
>
,
j
:
Cmd
<
J
>
):
Cmd
<
A
|
B
|
C
|
D
|
E
|
F
|
G
|
H
|
I
|
J
>
;
export
function
concat
<
array
extends
Cmd
<
any
>
[]
>
(
signals
:
array
):
Cmd
<
array
[
number
][
'_T'
][
'_R'
]
>
;
export
function
concat
():
Cmd
<
any
>
{
const
observables
=
Array
.
isArray
(
arguments
[
0
])
?
arguments
[
0
]
:
arguments
;
return
Rx
.
concat
.
apply
(
undefined
,
observables
);
}
/**
* Примитивный `Cmd` не генерирует никаких действий, завершается сразу
* после запуска.
*/
export
const
noop
:
Cmd
<
never
>
=
new
Rx
.
Observable
(
observer
=>
observer
.
complete
());
/**
* Выполнение сайд-еффектов. Observable не генерирует событий, после
* запуска вызывается переданная функция и Observable завершается.
*/
export
function
forget
<
A
>
(
f
:
()
=>
A
):
Cmd
<
never
>
;
export
function
forget
<
A
,
B
>
(
f
:
(
a
:
A
)
=>
B
,
a
:
A
):
Cmd
<
never
>
;
export
function
forget
<
A
,
B
,
C
>
(
f
:
(
a
:
A
,
b
:
B
)
=>
C
,
a
:
A
,
b
:
B
):
Cmd
<
never
>
;
export
function
forget
<
A
,
B
,
C
,
D
>
(
f
:
(
a
:
A
,
b
:
B
,
c
:
C
)
=>
D
,
a
:
A
,
b
:
B
,
c
:
C
):
Cmd
<
never
>
;
export
function
forget
(
f
:
(...
args
:
any
[])
=>
void
,
...
rest
:
any
[]):
Cmd
<
never
>
{
return
Observable
.
create
(
observer
=>
(
f
.
apply
(
undefined
,
rest
),
observer
.
complete
()));
}
http/index.ts
0 → 100644
View file @
6894e538
import
*
as
Rx
from
'rxjs'
;
import
{
Eff
}
from
'../eff'
;
import
*
as
eff
from
'../eff'
;
import
{
Decoder
,
Problem
}
from
'../decoder'
;
import
{
success
,
failure
}
from
'../either'
;
/** http method */
export
type
Method
=
'GET'
|
'POST'
|
'PUT'
|
'DELETE'
|
'PATCH'
;
/** request */
export
interface
Request
{
url
:
string
;
method
:
Method
;
body
?:
any
;
headers
?:
Record
<
string
,
string
|
number
|
undefined
|
null
>
;
withCredentials
?:
boolean
;
timeout
?:
number
;
}
/** raw error */
export
type
HttpError
=
|
{
tag
:
'BadUrl'
,
desc
:
string
}
|
{
tag
:
'BadPayload'
,
desc
:
string
}
|
{
tag
:
'ValidationProblem'
,
problem
:
Problem
,
url
:
string
}
|
{
tag
:
'BadStatus'
,
status
:
number
,
desc
:
string
}
|
{
tag
:
'Timeout'
}
|
{
tag
:
'NetworkError'
}
/** responce */
export
interface
Response
{
url
:
string
;
status
:
number
;
statusText
:
string
;
headers
:
Record
<
string
,
string
>
;
body
:
string
;
}
/** query params */
export
type
ParamsPrimitive
=
number
|
string
|
undefined
|
null
;
export
type
Params
=
Record
<
string
,
ParamsPrimitive
|
ParamsPrimitive
[]
>
;
/** progress */
export
type
Progress
=
|
{
tag
:
'Computable'
,
total
:
number
,
loaded
:
number
}
|
{
tag
:
'Uncomputable'
}
/** send a request */
export
function
send
(
req
:
Request
):
Eff
<
HttpError
,
Response
>
{
return
Rx
.
Observable
.
create
(
observer
=>
{
const
xhr
=
new
XMLHttpRequest
();
xhr
.
addEventListener
(
'error'
,
()
=>
(
observer
.
next
(
failure
({
tag
:
'NetworkError'
}
as
HttpError
)),
observer
.
complete
()));
xhr
.
addEventListener
(
'timeout'
,
()
=>
(
observer
.
next
(
failure
({
tag
:
'Timeout'
}
as
HttpError
)),
observer
.
complete
()));
xhr
.
addEventListener
(
'load'
,
()
=>
{
observer
.
next
(
success
({
url
:
xhr
.
responseURL
,
status
:
xhr
.
status
,
statusText
:
xhr
.
statusText
,
headers
:
parseHeaders
(
xhr
.
getAllResponseHeaders
()),
body
:
xhr
.
response
||
xhr
.
responseText
,
}));
observer
.
complete
();
});
try
{
xhr
.
open
(
req
.
method
,
req
.
url
,
true
);
}
catch
(
e
)
{
observer
.
next
(
failure
({
tag
:
'BadUrl'
,
desc
:
req
.
url
}
as
HttpError
));
observer
.
complete
();
}
//xhr.addEventListener('progress', e => onResult(success(e.lengthComputable ? { tag: 'Computable', loaded: e.loaded, total: e.total } : { tag: 'Uncomputable' })));
if
(
req
.
timeout
)
xhr
.
timeout
=
req
.
timeout
;
if
(
typeof
(
req
.
withCredentials
)
!==
'undefined'
)
xhr
.
withCredentials
=
req
.
withCredentials
;
if
(
typeof
(
req
.
headers
)
!==
'undefined'
)
{
for
(
let
key
in
req
.
headers
)
{
if
(
!
req
.
headers
.
hasOwnProperty
(
key
))
continue
;
const
value
=
req
.
headers
[
key
];
if
(
typeof
(
value
)
!==
'undefined'
&&
value
!==
null
)
xhr
.
setRequestHeader
(
key
,
String
(
value
));
}
}
const
body
=
Object
.
prototype
.
toString
.
apply
(
req
.
body
)
===
'[object Object]'
?
JSON
.
stringify
(
req
.
body
)
:
req
.
body
;
xhr
.
send
(
body
);
return
()
=>
xhr
.
abort
();
});
}
/** shortcut for GET requests */
export
function
get
(
url
:
string
,
extra
?:
Partial
<
Request
>
):
Eff
<
HttpError
,
Response
>
{
return
send
(
Object
.
assign
({},
extra
,
{
method
:
'GET'
,
url
})
as
any
);
}
/** shortcut for POST requests */
export
function
post
(
url
:
string
,
extra
?:
Partial
<
Request
>
):
Eff
<
HttpError
,
Response
>
{
return
send
(
Object
.
assign
({},
extra
,
{
method
:
'POST'
,
url
})
as
any
);
}
/** parse response as JSON */
export
function
expectJSON
<
A
>
(
decoder
:
Decoder
<
A
>
):
(
resp
:
Response
)
=>
Eff
<
HttpError
,
A
>
{
return
resp
=>
{
if
(
resp
.
body
===
''
)
return
eff
.
failure
({
tag
:
'BadPayload'
,
desc
:
'empty body'
}
as
HttpError
);
let
val
=
null
;
try
{
val
=
JSON
.
parse
(
resp
.
body
);
}
catch
(
e
)
{
return
eff
.
failure
({
tag
:
'BadPayload'
,
desc
:
'invalid json'
}
as
HttpError
);
}
return
Rx
.
of
(
decoder
.
validate
(
val
).
mapLeft
(
problem
=>
({
tag
:
'ValidationProblem'
,
problem
,
url
:
resp
.
url
}
as
HttpError
)));
};
}
/** parse headers from string to dict */
function
parseHeaders
(
rawHeaders
:
string
):
Record
<
string
,
string
>
{
const
output
=
{};
const
lines
=
rawHeaders
.
split
(
'
\
r
\
n'
);
for
(
let
i
in
lines
)
{
const
index
=
lines
[
i
].
indexOf
(
': '
);
if
(
index
<
0
)
continue
;
const
key
=
lines
[
i
].
substring
(
0
,
index
);
const
value
=
lines
[
i
].
substring
(
index
+
2
);
output
[
key
]
=
value
;
}
return
output
;
}
/** join segments of url */
function
joinTwo
(
a
:
string
,
b
:
string
):
string
{
if
(
a
===
''
)
return
b
;
if
(
b
===
''
)
return
a
;
const
trailing
=
a
.
length
&&
a
[
a
.
length
-
1
]
===
'/'
;
const
leading
=
b
.
length
&&
b
[
0
]
===
'/'
;
if
(
trailing
&&
leading
)
return
a
.
substring
(
0
,
a
.
length
-
1
)
+
b
;
if
(
!
trailing
&&
!
leading
)
return
a
+
'/'
+
b
;
return
a
+
b
;
}
/** build an url */
export
function
join
(...
args
:
Array
<
string
|
Params
>
):
string
{
let
path
=
''
;
let
params
=
{}
as
Record
<
string
,
string
>
;
let
query
=
''
;
for
(
let
i
in
args
)
{
const
arg
=
args
[
i
];
if
(
typeof
(
arg
)
===
'string'
)
path
=
joinTwo
(
path
,
arg
);
else
Object
[
'assign'
](
params
,
arg
);
}
for
(
let
key
in
params
)
{
if
(
!
params
.
hasOwnProperty
(
key
)
||
typeof
(
params
[
key
])
===
'undefined'
||
params
[
key
]
===
null
)
continue
;
if
(
Array
.
isArray
(
params
[
key
]))
{
for
(
const
v
of
params
[
key
])
{
if
(
typeof
(
params
[
key
])
===
'undefined'
||
params
[
key
]
===
null
)
continue
;
query
+=
(
query
?
'&'
:
''
)
+
`
${
encodeURIComponent
(
key
)}
=
${
encodeURIComponent
(
v
)}
`
;
}
}
else
{
query
+=
(
query
?
'&'
:
''
)
+
`
${
encodeURIComponent
(
key
)}
=
${
encodeURIComponent
(
params
[
key
])}
`
;
}
}
return
query
?
(
path
+
'?'
+
query
)
:
path
;
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment