1
1
import { MosTypes , getMosTypes , MosType } from '@mos-connection/model'
2
+ import { AnyXMLValue , AnyXMLValueSingular } from './lib'
2
3
3
4
export function getParseMosTypes ( strict : boolean ) : MosParseTypes {
4
5
const mosTypes = getMosTypes ( strict )
5
6
7
+ const specialMosTypes = getSpecialMosTypes ( strict )
6
8
return {
7
9
strict : mosTypes . strict ,
8
10
mosString128 : wrapParseMethods ( mosTypes . mosString128 , strict ) ,
9
11
mosDuration : wrapParseMethods ( mosTypes . mosDuration , strict ) ,
10
12
mosTime : wrapParseMethods ( mosTypes . mosTime , strict ) ,
13
+
14
+ string : wrapParseMethods ( specialMosTypes . string , strict ) ,
15
+ stringEnum : wrapParseMethods ( specialMosTypes . stringEnum , strict ) ,
11
16
}
12
17
}
13
18
type MosParseTypes = {
14
19
[ key in keyof MosTypes ] : MosTypes [ key ] extends MosType < infer Serialized , infer Value , infer CreateValue >
15
20
? MosTypeParse < Serialized , Value , CreateValue >
16
21
: MosTypes [ key ]
22
+ } & {
23
+ string : MosTypeParse < string , string , AnyXMLValue >
24
+ stringEnum : MosTypeParse < any , string , { enum : { [ key : string ] : string } ; value : AnyXMLValue } >
17
25
}
18
26
interface MosTypeParse < Serialized , Value , CreateValue > extends Omit < MosType < Serialized , Value , CreateValue > , 'create' > {
19
27
/**
20
28
* Used to parse data that is optional.
21
29
* If the data is missing, undefined is returned.
22
30
*/
23
- createOptional : ( anyValue : CreateValue ) => Serialized | undefined
31
+ createOptional : ( anyValue : CreateValue | AnyXMLValue ) => Serialized | undefined
24
32
/**
25
33
* Used to parse data that is required.
26
34
* If in strict mode, the data must be present and parsable, otherwise an error is thrown.
27
35
* If not in strict mode, a fallback value will be used.
28
36
*/
29
- createRequired : ( anyValue : CreateValue ) => Serialized
37
+ createRequired : ( anyValue : CreateValue | AnyXMLValue ) => Serialized
30
38
}
31
39
32
40
function wrapParseMethods < Serialized , Value , CreateValue > (
33
41
mosType : MosType < Serialized , Value , CreateValue > ,
34
42
strict : boolean
35
43
) : MosTypeParse < Serialized , Value , CreateValue > {
36
44
return {
37
- createOptional : wrapParseMethodCreateOptional ( mosType ) ,
45
+ createOptional : wrapParseMethodCreateOptional ( mosType , strict ) ,
38
46
createRequired : wrapParseMethodCreateRequired ( mosType , strict ) ,
39
47
validate : mosType . validate ,
40
48
valueOf : mosType . valueOf ,
@@ -43,9 +51,10 @@ function wrapParseMethods<Serialized, Value, CreateValue>(
43
51
} as MosTypeParse < Serialized , Value , CreateValue >
44
52
}
45
53
function wrapParseMethodCreateOptional < Serialized , Value , CreateValue > (
46
- mosType : MosType < Serialized , Value , CreateValue >
54
+ mosType : MosType < Serialized , Value , CreateValue > ,
55
+ strict : boolean
47
56
) : MosTypeParse < Serialized , Value , CreateValue > [ 'createOptional' ] {
48
- return parseOptional ( mosType . create )
57
+ return parseOptional ( mosType . create , strict )
49
58
}
50
59
function wrapParseMethodCreateRequired < Serialized , Value , CreateValue > (
51
60
mosType : MosType < Serialized , Value , CreateValue > ,
@@ -54,24 +63,35 @@ function wrapParseMethodCreateRequired<Serialized, Value, CreateValue>(
54
63
return parseRequired ( mosType . create , mosType . fallback , strict )
55
64
}
56
65
57
- export function parseOptional < V , R > ( parser : ( value : V ) => R ) : ( value : V ) => R | undefined {
66
+ export function parseOptional < V , R > (
67
+ parser : ( value : V ) => R ,
68
+ strict : boolean
69
+ ) : ( value : V | AnyXMLValue ) => R | undefined {
58
70
return ( value : any ) => {
59
71
// handle empty string:
60
72
if ( typeof value === 'string' && ! value . trim ( ) ) value = undefined
61
73
// handle empty object (can happen when parsing an empty xml tag):
62
74
if ( typeof value === 'object' && Object . keys ( value ) . length === 0 ) value = undefined
63
75
76
+ value = ensureSingular ( value , strict )
77
+
64
78
if ( value === undefined ) return undefined
65
79
return parser ( value )
66
80
}
67
81
}
68
- export function parseRequired < V , R > ( parser : ( value : V ) => R , fallback : ( ) => R , strict : boolean ) : ( value : V ) => R {
82
+ export function parseRequired < V , R > (
83
+ parser : ( value : V ) => R ,
84
+ fallback : ( ) => R ,
85
+ strict : boolean
86
+ ) : ( value : V | AnyXMLValue ) => R {
69
87
return ( value : any ) => {
70
88
// handle empty string:
71
89
if ( typeof value === 'string' && ! value . trim ( ) ) value = undefined
72
90
// handle empty object (can happen when parsing an empty xml tag):
73
91
if ( typeof value === 'object' && Object . keys ( value ) . length === 0 ) value = undefined
74
92
93
+ value = ensureSingular ( value , strict )
94
+
75
95
if ( value === undefined ) {
76
96
// Something might be wrong. value is undefined, but should not be (?)
77
97
if ( strict ) {
@@ -85,3 +105,63 @@ export function parseRequired<V, R>(parser: (value: V) => R, fallback: () => R,
85
105
}
86
106
}
87
107
}
108
+
109
+ function ensureSingular ( value : AnyXMLValue , strict : boolean ) : AnyXMLValueSingular {
110
+ if ( typeof value === 'object' ) {
111
+ if ( Array . isArray ( value ) ) {
112
+ if ( value . length === 0 ) return undefined
113
+ if ( value . length > 1 ) {
114
+ if ( strict )
115
+ throw new Error ( `Expected only one value, got ${ value . length } values: ${ JSON . stringify ( value ) } ` )
116
+ else return undefined
117
+ }
118
+
119
+ return ensureSingular ( value [ 0 ] , strict )
120
+ } else {
121
+ if ( strict ) throw new Error ( `Expected only one value, got object: ${ JSON . stringify ( value ) } ` )
122
+ else return undefined
123
+ }
124
+ } else {
125
+ return value
126
+ }
127
+ }
128
+
129
+ function getSpecialMosTypes ( strict : boolean ) {
130
+ const string : MosType < string , string , AnyXMLValue > = {
131
+ create : ( anyValue : AnyXMLValue ) => {
132
+ if ( typeof anyValue !== 'string' ) throw new Error ( `Expected a string, got: "${ anyValue } "` )
133
+ return anyValue
134
+ } ,
135
+ validate : ( _value : string ) => true ,
136
+ valueOf : ( value : string ) => value ,
137
+ stringify : ( value : string ) => value ,
138
+ is : ( value : string | any ) : value is string => typeof value !== 'string' ,
139
+ fallback : ( ) => '' ,
140
+ }
141
+ const stringEnum : MosType < string , string , { enum : { [ key : string ] : string } ; value : AnyXMLValue } > = {
142
+ create : ( createValue ) => {
143
+ if ( ! createValue . enum ) throw new Error ( `Expected an object with an "enum" key, got: "${ createValue } "` )
144
+
145
+ const key = `${ createValue . value } `
146
+ if ( ! key ) throw new Error ( `Expected a value, got: "${ createValue . value } "` )
147
+
148
+ if ( createValue . enum [ key ] === undefined ) {
149
+ if ( strict ) {
150
+ throw new Error ( `Unknown value, got: "${ key } ", possible values: ${ Object . keys ( createValue . enum ) } ` )
151
+ } else return ''
152
+ }
153
+
154
+ return key
155
+ } ,
156
+ validate : ( _value : string ) => true ,
157
+ valueOf : ( value : string ) => value ,
158
+ stringify : ( value : string ) => value ,
159
+ is : ( value : string | any ) : value is string => typeof value !== 'string' ,
160
+ fallback : ( ) => '' ,
161
+ }
162
+
163
+ return {
164
+ string,
165
+ stringEnum,
166
+ }
167
+ }
0 commit comments