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
f1b9f7f2
Commit
f1b9f7f2
authored
Jan 16, 2019
by
Vladislav Lagunov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Печать названия проблемных полей в printProblem
parent
4c6c4a99
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
68 additions
and
19 deletions
+68
-19
config-reader/index.ts
+7
-9
decoder/index.ts
+61
-10
No files found.
config-reader/index.ts
View file @
f1b9f7f2
...
@@ -84,15 +84,6 @@ export function fromString(d: Decoder<any>, value: string): unknown {
...
@@ -84,15 +84,6 @@ export function fromString(d: Decoder<any>, value: string): unknown {
return
value
.
split
(
', '
).
map
(
x
=>
fromString
(
d
.
_decoder
,
x
));
return
value
.
split
(
', '
).
map
(
x
=>
fromString
(
d
.
_decoder
,
x
));
}
}
// if (d instanceof t.Tuple) {
// return value.split(', ').map((x, idx) => fromString(d._tuple[idx], x));
// }
// if (d instanceof t.Literals) {
// // TODO: проверять значение исходя из типа rep._literals
// return value;
// }
if
(
d
instanceof
t
.
Dict
)
{
if
(
d
instanceof
t
.
Dict
)
{
try
{
try
{
return
JSON
.
parse
(
value
);
return
JSON
.
parse
(
value
);
...
@@ -141,6 +132,9 @@ export function fromString(d: Decoder<any>, value: string): unknown {
...
@@ -141,6 +132,9 @@ export function fromString(d: Decoder<any>, value: string): unknown {
if
(
d
instanceof
WithDefault
)
{
if
(
d
instanceof
WithDefault
)
{
return
fromString
(
d
.
_decoder
,
value
);
return
fromString
(
d
.
_decoder
,
value
);
}
}
if
(
d
instanceof
t
.
Variants
)
{
return
value
;
}
return
fromString
(
d
.
toDecoder
(),
value
);
return
fromString
(
d
.
toDecoder
(),
value
);
}
}
...
@@ -225,6 +219,10 @@ export function configInfo(decoder: RecordDecoder<any>, prefix=''): Record<strin
...
@@ -225,6 +219,10 @@ export function configInfo(decoder: RecordDecoder<any>, prefix=''): Record<strin
info
.
default
=
d
.
_default
;
info
.
default
=
d
.
_default
;
return
info
;
return
info
;
}
}
if
(
d
instanceof
t
.
Variants
)
{
return
{
type
:
d
.
_variants
.
map
(
x
=>
JSON
.
stringify
(
x
)).
join
(
'|'
)
};
}
const
info
=
go
(
d
.
toDecoder
());
const
info
=
go
(
d
.
toDecoder
());
if
(
d
instanceof
ConfigDescription
)
{
if
(
d
instanceof
ConfigDescription
)
{
...
...
decoder/index.ts
View file @
f1b9f7f2
...
@@ -20,6 +20,7 @@ export type Decoder<A> =
...
@@ -20,6 +20,7 @@ export type Decoder<A> =
|
OneOf
<
A
>
|
OneOf
<
A
>
|
Discriminate
<
A
>
|
Discriminate
<
A
>
|
ToDecoder
<
A
>
|
ToDecoder
<
A
>
;
/**
/**
...
@@ -27,6 +28,7 @@ export type Decoder<A> =
...
@@ -27,6 +28,7 @@ export type Decoder<A> =
*/
*/
export
type
Problem
=
{
export
type
Problem
=
{
value
:
any
;
value
:
any
;
path
:
string
[];
rootValue
:
any
;
rootValue
:
any
;
decoder
:
Decoder
<
any
>
;
decoder
:
Decoder
<
any
>
;
rootDecoder
:
Decoder
<
any
>
;
rootDecoder
:
Decoder
<
any
>
;
...
@@ -51,6 +53,7 @@ export class DecoderBase<A> {
...
@@ -51,6 +53,7 @@ export class DecoderBase<A> {
readonly
_A
:
A
;
readonly
_A
:
A
;
static
rootDecoder
:
Decoder
<
any
>|
undefined
=
undefined
;
static
rootDecoder
:
Decoder
<
any
>|
undefined
=
undefined
;
static
rootValue
:
any
=
undefined
;
static
rootValue
:
any
=
undefined
;
static
path
:
string
[]
=
[];
/**
/**
* Печать декодера в виде выражения которым он был создан
* Печать декодера в виде выражения которым он был создан
...
@@ -161,6 +164,15 @@ export class RecordDecoder<A> extends DecoderBase<A> {
...
@@ -161,6 +164,15 @@ export class RecordDecoder<A> extends DecoderBase<A> {
extend
<
F
extends
{
[
K
:
string
]:
Decoder
<
any
>
}
>
(
fields
:
F
):
RecordDecoder
<
A
&
{
[
K
in
keyof
F
]:
F
[
K
][
'_A'
]
}
>
{
extend
<
F
extends
{
[
K
:
string
]:
Decoder
<
any
>
}
>
(
fields
:
F
):
RecordDecoder
<
A
&
{
[
K
in
keyof
F
]:
F
[
K
][
'_A'
]
}
>
{
return
new
RecordDecoder
({
...
this
.
_description
,
...
fields
as
any
});
return
new
RecordDecoder
({
...
this
.
_description
,
...
fields
as
any
});
}
}
pick
<
K
extends
keyof
A
>
(...
keys
:
K
[]):
RecordDecoder
<
Pick
<
A
,
K
>>
{
return
new
RecordDecoder
(
keys
.
reduce
<
any
>
((
acc
,
k
)
=>
(
acc
[
k
]
=
this
.
_description
[
k
as
string
],
acc
),
{}));
}
omit
<
K
extends
keyof
A
>
(...
keys
:
K
[]):
RecordDecoder
<
Omit
<
A
,
K
>>
{
const
description
=
Object
.
keys
(
this
.
_description
).
reduce
((
acc
,
k
)
=>
(
keys
.
indexOf
(
k
as
any
)
===
-
1
&&
(
acc
[
k
]
=
this
.
_description
[
k
]),
acc
),
{});
return
new
RecordDecoder
(
description
);
}
}
}
export
class
AtDecoder
<
A
>
extends
DecoderBase
<
A
>
{
export
class
AtDecoder
<
A
>
extends
DecoderBase
<
A
>
{
...
@@ -221,6 +233,16 @@ export class WithDefault<A> extends ToDecoder<A> {
...
@@ -221,6 +233,16 @@ export class WithDefault<A> extends ToDecoder<A> {
}
}
}
}
export
class
Variants
<
A
>
extends
ToDecoder
<
A
>
{
constructor
(
readonly
_variants
:
A
[],
)
{
super
();
}
toDecoder
()
{
return
new
OneOf
<
A
>
(
this
.
_variants
.
map
(
x
=>
decoder
(
v
=>
v
===
x
?
Either
.
of
(
v
)
:
Either
.
failure
(
`expected
${
x
}
, got
${
fancyTypeOf
(
v
)}
`
))));
}
}
/**
/**
* Результат валидаии
* Результат валидаии
...
@@ -381,13 +403,15 @@ export function optional(key: string|string[], dec: Decoder<any>, def: any): Dec
...
@@ -381,13 +403,15 @@ export function optional(key: string|string[], dec: Decoder<any>, def: any): Dec
/**
/**
* Создание декодера перечислением всех допустимых значений
* Создание декодера перечислением всех допустимых значений
*/
*/
export
function
literals
<
A
extends
Expr
[]
>
(...
array
:
A
):
Decoder
<
A
[
number
]
>
;
export
function
variants
<
A
extends
Expr
[]
>
(...
array
:
A
):
Variants
<
A
[
number
]
>
;
export
function
literals
<
A
extends
Expr
[]
>
(
array
:
A
):
Decoder
<
A
[
number
]
>
;
export
function
variants
<
A
extends
Expr
[]
>
(
array
:
A
):
Variants
<
A
[
number
]
>
;
export
function
literals
():
Decoder
<
any
>
{
export
function
variants
():
Variants
<
any
>
{
const
literals
:
Expr
[]
=
Array
.
isArray
(
arguments
[
0
])
?
arguments
[
0
]
:
Array
.
prototype
.
slice
.
call
(
arguments
);
return
new
Variants
(
Array
.
isArray
(
arguments
[
0
])
?
arguments
[
0
]
:
Array
.
prototype
.
slice
.
call
(
arguments
));
return
new
OneOf
(
literals
.
map
(
x
=>
decoder
(
v
=>
v
===
x
?
Either
.
of
(
v
)
:
Either
.
failure
(
`expected
${
x
}
, got
${
fancyTypeOf
(
v
)}
`
))));
}
}
// @deprecated
export
const
literals
=
variants
;
/**
/**
* Кортежи разных размеров. Проверяемое значение необязательно должно
* Кортежи разных размеров. Проверяемое значение необязательно должно
...
@@ -414,7 +438,7 @@ export function printProblems(problems: Problem): void {
...
@@ -414,7 +438,7 @@ export function printProblems(problems: Problem): void {
console
.
log
(
'%croot decoder:'
,
'font-weight: 600;'
,
problems
.
rootDecoder
.
prettyPrint
());
console
.
log
(
'%croot decoder:'
,
'font-weight: 600;'
,
problems
.
rootDecoder
.
prettyPrint
());
console
.
log
(
'%cfailed value:'
,
'font-weight: 600;'
,
problems
.
value
);
console
.
log
(
'%cfailed value:'
,
'font-weight: 600;'
,
problems
.
value
);
console
.
log
(
'%croot value:'
,
'font-weight: 600;'
,
problems
.
rootValue
);
console
.
log
(
'%croot value:'
,
'font-weight: 600;'
,
problems
.
rootValue
);
//console.log('decoders ', problems.decoders.map(x => x.prettyPrint()
));
console
.
log
(
'%cproblem path:'
,
'font-weight: 600;'
,
[
'_'
,
...
problems
.
path
].
join
(
'.'
));
}
}
...
@@ -428,20 +452,29 @@ function fancyTypeOf(value: any): string {
...
@@ -428,20 +452,29 @@ function fancyTypeOf(value: any): string {
* Выполнение валидации
* Выполнение валидации
*/
*/
export
function
doValidate
<
A
>
(
decoder
:
Decoder
<
A
>
,
value
:
unknown
):
Either
<
Problem
,
A
>
{
export
function
doValidate
<
A
>
(
decoder
:
Decoder
<
A
>
,
value
:
unknown
):
Either
<
Problem
,
A
>
{
const
pathLength
=
DecoderBase
.
path
.
length
;
const
cleanup
=
()
=>
DecoderBase
.
path
.
splice
(
pathLength
);
if
(
decoder
instanceof
Custom
)
{
if
(
decoder
instanceof
Custom
)
{
return
decoder
.
_validate
(
value
).
mapLeft
(
projectProblem
);
DecoderBase
.
path
.
push
(
'<custom>'
);
const
output
=
decoder
.
_validate
(
value
).
mapLeft
(
projectProblem
);
cleanup
();
return
output
;
}
}
if
(
decoder
instanceof
ArrayDecoder
)
{
if
(
decoder
instanceof
ArrayDecoder
)
{
const
output
:
any
[]
=
[];
const
output
:
any
[]
=
[];
if
(
!
Array
.
isArray
(
value
))
return
Either
.
failure
(
projectProblem
(
'not an array'
));
if
(
!
Array
.
isArray
(
value
))
return
Either
.
failure
(
projectProblem
(
'not an array'
));
DecoderBase
.
path
.
push
(
'0'
);
for
(
let
i
=
0
;
i
<
value
.
length
;
i
++
)
{
for
(
let
i
=
0
;
i
<
value
.
length
;
i
++
)
{
DecoderBase
.
path
[
DecoderBase
.
path
.
length
-
1
]
=
String
(
i
);
const
ethr
=
doValidate
(
decoder
.
_decoder
,
value
[
i
]);
const
ethr
=
doValidate
(
decoder
.
_decoder
,
value
[
i
]);
switch
(
ethr
.
tag
)
{
switch
(
ethr
.
tag
)
{
case
'Left'
:
{
return
ethr
;
}
case
'Left'
:
{
return
ethr
;
}
case
'Right'
:
output
.
push
(
ethr
.
value
);
break
;
case
'Right'
:
output
.
push
(
ethr
.
value
);
break
;
}
}
}
}
cleanup
();
return
Either
.
of
(
output
as
any
as
A
);
return
Either
.
of
(
output
as
any
as
A
);
}
}
...
@@ -449,14 +482,17 @@ export function doValidate<A>(decoder: Decoder<A>, value: unknown): Either<Probl
...
@@ -449,14 +482,17 @@ export function doValidate<A>(decoder: Decoder<A>, value: unknown): Either<Probl
if
(
typeof
(
value
)
!==
'object'
)
return
Either
.
failure
(
projectProblem
(
'not an object'
));
if
(
typeof
(
value
)
!==
'object'
)
return
Either
.
failure
(
projectProblem
(
'not an object'
));
if
(
value
===
null
)
return
Either
.
failure
(
projectProblem
(
'found null'
));
if
(
value
===
null
)
return
Either
.
failure
(
projectProblem
(
'found null'
));
const
output
:
{
[
k
:
string
]:
A
}
=
{};
const
output
:
{
[
k
:
string
]:
A
}
=
{};
DecoderBase
.
path
.
push
(
''
);
for
(
let
key
in
value
)
{
for
(
let
key
in
value
)
{
if
(
!
value
.
hasOwnProperty
(
key
))
continue
;
if
(
!
value
.
hasOwnProperty
(
key
))
continue
;
DecoderBase
.
path
[
DecoderBase
.
path
.
length
-
1
]
=
key
;
const
ethr
=
doValidate
(
decoder
.
_decoder
,
value
[
key
]);
const
ethr
=
doValidate
(
decoder
.
_decoder
,
value
[
key
]);
switch
(
ethr
.
tag
)
{
switch
(
ethr
.
tag
)
{
case
'Left'
:
{
return
ethr
;
}
case
'Left'
:
{
return
ethr
;
}
case
'Right'
:
output
[
key
]
=
ethr
.
value
;
break
;
case
'Right'
:
output
[
key
]
=
ethr
.
value
;
break
;
}
}
}
}
cleanup
();
return
Either
.
of
(
output
as
any
as
A
);
return
Either
.
of
(
output
as
any
as
A
);
}
}
...
@@ -464,7 +500,9 @@ export function doValidate<A>(decoder: Decoder<A>, value: unknown): Either<Probl
...
@@ -464,7 +500,9 @@ export function doValidate<A>(decoder: Decoder<A>, value: unknown): Either<Probl
if
(
typeof
(
value
)
!==
'object'
)
return
Either
.
failure
(
projectProblem
(
'not an object'
));
if
(
typeof
(
value
)
!==
'object'
)
return
Either
.
failure
(
projectProblem
(
'not an object'
));
if
(
value
===
null
)
return
Either
.
failure
(
projectProblem
(
'found null'
));
if
(
value
===
null
)
return
Either
.
failure
(
projectProblem
(
'found null'
));
const
output
:
{
[
k
:
string
]:
any
}
=
{};
const
output
:
{
[
k
:
string
]:
any
}
=
{};
DecoderBase
.
path
.
push
(
''
);
for
(
let
key
in
decoder
.
_description
)
{
for
(
let
key
in
decoder
.
_description
)
{
DecoderBase
.
path
[
DecoderBase
.
path
.
length
-
1
]
=
key
;
if
(
!
decoder
.
_description
.
hasOwnProperty
(
key
))
continue
;
if
(
!
decoder
.
_description
.
hasOwnProperty
(
key
))
continue
;
const
ethr
=
doValidate
(
decoder
.
_description
[
key
],
value
[
key
]);
const
ethr
=
doValidate
(
decoder
.
_description
[
key
],
value
[
key
]);
switch
(
ethr
.
tag
)
{
switch
(
ethr
.
tag
)
{
...
@@ -472,11 +510,13 @@ export function doValidate<A>(decoder: Decoder<A>, value: unknown): Either<Probl
...
@@ -472,11 +510,13 @@ export function doValidate<A>(decoder: Decoder<A>, value: unknown): Either<Probl
case
'Right'
:
output
[
key
]
=
ethr
.
value
;
break
;
case
'Right'
:
output
[
key
]
=
ethr
.
value
;
break
;
}
}
}
}
cleanup
();
return
Either
.
of
(
output
as
any
as
A
);
return
Either
.
of
(
output
as
any
as
A
);
}
}
if
(
decoder
instanceof
AtDecoder
)
{
if
(
decoder
instanceof
AtDecoder
)
{
let
iter
=
value
as
any
;
let
iter
=
value
as
any
;
decoder
.
_path
.
forEach
(
k
=>
DecoderBase
.
path
.
push
(
k
+
''
));
for
(
let
i
in
decoder
.
_path
)
{
for
(
let
i
in
decoder
.
_path
)
{
if
(
iter
===
undefined
||
!
iter
.
hasOwnProperty
(
decoder
.
_path
[
i
]))
{
if
(
iter
===
undefined
||
!
iter
.
hasOwnProperty
(
decoder
.
_path
[
i
]))
{
iter
=
undefined
;
iter
=
undefined
;
...
@@ -484,6 +524,7 @@ export function doValidate<A>(decoder: Decoder<A>, value: unknown): Either<Probl
...
@@ -484,6 +524,7 @@ export function doValidate<A>(decoder: Decoder<A>, value: unknown): Either<Probl
}
}
iter
=
iter
[
decoder
.
_path
[
i
]];
iter
=
iter
[
decoder
.
_path
[
i
]];
}
}
cleanup
();
return
doValidate
(
decoder
.
_decoder
,
iter
);
return
doValidate
(
decoder
.
_decoder
,
iter
);
}
}
...
@@ -517,7 +558,10 @@ export function doValidate<A>(decoder: Decoder<A>, value: unknown): Either<Probl
...
@@ -517,7 +558,10 @@ export function doValidate<A>(decoder: Decoder<A>, value: unknown): Either<Probl
}
}
if
(
decoder
instanceof
Chain
)
{
if
(
decoder
instanceof
Chain
)
{
return
doValidate
(
decoder
.
_then
(
doValidate
(
decoder
.
_decoder
,
value
)),
value
);
DecoderBase
.
path
.
push
(
'<chain>'
);
const
output
=
doValidate
(
decoder
.
_then
(
doValidate
(
decoder
.
_decoder
,
value
)),
value
);
cleanup
();
return
output
;
}
}
if
(
decoder
instanceof
Discriminate
)
{
if
(
decoder
instanceof
Discriminate
)
{
...
@@ -526,7 +570,9 @@ export function doValidate<A>(decoder: Decoder<A>, value: unknown): Either<Probl
...
@@ -526,7 +570,9 @@ export function doValidate<A>(decoder: Decoder<A>, value: unknown): Either<Probl
if
(
typeof
(
value
)
!==
'object'
||
!
value
)
return
Either
.
failure
(
projectProblem
(
'expected an object'
));
if
(
typeof
(
value
)
!==
'object'
||
!
value
)
return
Either
.
failure
(
projectProblem
(
'expected an object'
));
if
(
!
value
.
hasOwnProperty
(
key
))
return
Either
.
failure
(
projectProblem
(
`expected input would have key '
${
key
}
'`
));
if
(
!
value
.
hasOwnProperty
(
key
))
return
Either
.
failure
(
projectProblem
(
`expected input would have key '
${
key
}
'`
));
if
(
!
(
value
[
key
]
in
record
))
return
Either
.
failure
(
projectProblem
(
`unknown value of discriminated key
${
value
[
key
]}
`
));
if
(
!
(
value
[
key
]
in
record
))
return
Either
.
failure
(
projectProblem
(
`unknown value of discriminated key
${
value
[
key
]}
`
));
return
record
[
value
[
key
]].
validate
(
value
).
map
(
x
=>
({
...
x
,
[
key
]:
value
[
key
]
}));
const
output
=
record
[
value
[
key
]].
validate
(
value
).
map
(
x
=>
({
...
x
,
[
key
]:
value
[
key
]
}));
cleanup
();
return
output
;
}
}
if
(
decoder
instanceof
ToDecoder
)
{
if
(
decoder
instanceof
ToDecoder
)
{
...
@@ -537,7 +583,7 @@ export function doValidate<A>(decoder: Decoder<A>, value: unknown): Either<Probl
...
@@ -537,7 +583,7 @@ export function doValidate<A>(decoder: Decoder<A>, value: unknown): Either<Probl
function
projectProblem
(
problem
:
Problem
|
string
):
Problem
{
function
projectProblem
(
problem
:
Problem
|
string
):
Problem
{
if
(
typeof
(
problem
)
!==
'string'
)
return
problem
;
if
(
typeof
(
problem
)
!==
'string'
)
return
problem
;
return
{
value
,
rootValue
:
DecoderBase
.
rootValue
,
decoder
,
rootDecoder
:
DecoderBase
.
rootDecoder
||
decoder
,
message
:
problem
,
};
return
{
value
,
rootValue
:
DecoderBase
.
rootValue
,
decoder
,
rootDecoder
:
DecoderBase
.
rootDecoder
||
decoder
,
message
:
problem
,
path
:
DecoderBase
.
path
};
}
}
}
}
...
@@ -559,6 +605,7 @@ export function prettyPrint(decoder: Decoder<any>): string {
...
@@ -559,6 +605,7 @@ export function prettyPrint(decoder: Decoder<any>): string {
if
(
decoder
instanceof
Pure
)
return
`t.of(
${
JSON
.
stringify
(
decoder
.
_value
)}
)`
;
if
(
decoder
instanceof
Pure
)
return
`t.of(
${
JSON
.
stringify
(
decoder
.
_value
)}
)`
;
if
(
decoder
instanceof
Chain
)
return
`
${
decoder
.
prettyPrint
()}
.chain(<func>)`
;
if
(
decoder
instanceof
Chain
)
return
`
${
decoder
.
prettyPrint
()}
.chain(<func>)`
;
if
(
decoder
instanceof
OneOf
)
return
`t.oneOf(
${
decoder
.
_alternatives
.
map
(
x
=>
x
.
prettyPrint
()).
join
(
', '
)}
)`
;
if
(
decoder
instanceof
OneOf
)
return
`t.oneOf(
${
decoder
.
_alternatives
.
map
(
x
=>
x
.
prettyPrint
()).
join
(
', '
)}
)`
;
if
(
decoder
instanceof
Variants
)
return
`t.literals(
${
decoder
.
_variants
.
map
(
x
=>
JSON
.
stringify
(
x
)).
join
(
', '
)}
)`
;
if
(
decoder
instanceof
Discriminate
)
{
if
(
decoder
instanceof
Discriminate
)
{
const
discriminator
=
JSON
.
stringify
(
decoder
.
_discriminator
);
const
discriminator
=
JSON
.
stringify
(
decoder
.
_discriminator
);
const
alternatives
=
Object
.
keys
(
decoder
.
_alternatives
).
map
(
k
=>
JSON
.
stringify
(
k
)
+
": "
+
decoder
.
_alternatives
[
k
].
prettyPrint
()).
join
(
', '
);
const
alternatives
=
Object
.
keys
(
decoder
.
_alternatives
).
map
(
k
=>
JSON
.
stringify
(
k
)
+
": "
+
decoder
.
_alternatives
[
k
].
prettyPrint
()).
join
(
', '
);
...
@@ -570,3 +617,7 @@ export function prettyPrint(decoder: Decoder<any>): string {
...
@@ -570,3 +617,7 @@ export function prettyPrint(decoder: Decoder<any>): string {
return
absurd
(
decoder
);
return
absurd
(
decoder
);
}
}
// Utilies types based on
// https://github.com/Microsoft/TypeScript/issues/12215#issuecomment-307871458
export
type
Omit
<
T
,
K
extends
keyof
any
>
=
Pick
<
T
,
Exclude
<
keyof
T
,
K
>>
;
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