66} = require ( '../annotations' ) ;
77const pipeParseResult = require ( '../../pipeParseResult' ) ;
88const {
9- isString, hasKey, getValue,
9+ isArray , isString, hasKey, getValue,
1010} = require ( '../../predicates' ) ;
1111const parseObject = require ( '../parseObject' ) ;
1212const parseArray = require ( '../parseArray' ) ;
@@ -128,10 +128,14 @@ const typeToElementNameMap = {
128128 * Normalises result into an ArrayElement of StringElement
129129 */
130130function parseType ( context ) {
131+ const { namespace } = context ;
132+
131133 let types ;
132134 let isValidType ;
133135
134- if ( context . isOpenAPIVersionMoreThanOrEqual ( 3 , 1 ) ) {
136+ const isOpenAPI31OrHigher = R . always ( context . isOpenAPIVersionMoreThanOrEqual ( 3 , 1 ) ) ;
137+
138+ if ( isOpenAPI31OrHigher ( ) ) {
135139 types = openapi31Types ;
136140 isValidType = isValidOpenAPI31Type ;
137141 } else {
@@ -141,13 +145,71 @@ function parseType(context) {
141145
142146 const ensureValidType = R . unless (
143147 element => isValidType ( element . toValue ( ) ) ,
144- createWarning ( context . namespace , `'${ name } ' 'type' must be either ${ types . join ( ', ' ) } ` )
148+ createWarning ( namespace , `'${ name } ' 'type' must be either ${ types . join ( ', ' ) } ` )
145149 ) ;
146150
147- return pipeParseResult ( context . namespace ,
148- R . unless ( isString , value => createWarning ( context . namespace , `'${ name } ' 'type' is not a string` , value ) ) ,
151+ const parseStringType = pipeParseResult ( namespace ,
149152 ensureValidType ,
150- type => new context . namespace . elements . Array ( [ type ] ) ) ;
153+ type => new namespace . elements . Array ( [ type ] ) ) ;
154+
155+ const ensureValidTypeInArray = R . unless (
156+ element => isValidType ( element . toValue ( ) ) ,
157+ createWarning ( namespace , `'${ name } ' 'type' array must only contain values: ${ types . join ( ', ' ) } ` )
158+ ) ;
159+
160+ const parseArrayTypeItem = pipeParseResult ( namespace ,
161+ R . unless ( isString , createWarning ( namespace , `'${ name } ' 'type' array value is not a string` ) ) ,
162+ ensureValidTypeInArray ) ;
163+
164+ const isEmpty = arrayElement => arrayElement . isEmpty ;
165+
166+ // ArrayElement -> ParseResult<ArrayElement, Annotation>
167+ const ensureTypesAreUnique = ( types ) => {
168+ const inspectedTypes = [ ] ;
169+ const warnings = [ ] ;
170+ const permittedTypes = R . filter ( ( type ) => {
171+ if ( inspectedTypes . includes ( type . toValue ( ) ) ) {
172+ warnings . push ( createWarning ( namespace , `'${ name } ' 'type' array must contain unique items, ${ type . toValue ( ) } is already present` , type ) ) ;
173+ return false ;
174+ }
175+
176+ inspectedTypes . push ( type . toValue ( ) ) ;
177+ return true ;
178+ } , types ) ;
179+
180+ const parseResult = new namespace . elements . ParseResult ( ) ;
181+ parseResult . push ( permittedTypes . elements ) ;
182+
183+ if ( warnings . length > 0 ) {
184+ parseResult . push ( ...warnings ) ;
185+ }
186+ return parseResult ;
187+ } ;
188+
189+ const parseArrayType = pipeParseResult ( namespace ,
190+ R . when ( isEmpty , createWarning ( namespace , `'${ name } ' 'type' array must contain at least one type` ) ) ,
191+ parseArray ( context , `${ name } ' 'type` , parseArrayTypeItem ) ,
192+ ensureTypesAreUnique ,
193+
194+ // FIXME support >1 type
195+ R . when ( e => e . length > 1 , createWarning ( namespace , `'${ name } ' 'type' more than one type is current unsupported` ) ) ) ;
196+
197+ return R . cond ( [
198+ [ isString , parseStringType ] ,
199+ [
200+ R . both ( isArray , isOpenAPI31OrHigher ) ,
201+ parseArrayType ,
202+ ] ,
203+
204+ [
205+ isOpenAPI31OrHigher ,
206+ value => createWarning ( namespace , `'${ name } ' 'type' is not a string or an array` , value ) ,
207+ ] ,
208+ [
209+ R . T ,
210+ value => createWarning ( namespace , `'${ name } ' 'type' is not a string` , value ) ,
211+ ] ,
212+ ] ) ;
151213}
152214
153215// Returns whether the given element value matches the provided schema type
0 commit comments