@@ -30,7 +30,7 @@ class CommentDefinitionParser {
3030 let field = splitLine . shift ( ) ;
3131 line = splitLine . join ( ' ' ) ;
3232 if ( ! field && previous && ( previous . field === 'param' || previous . field === 'returns' ) ) {
33- previous . schema = ( previous . schema || [ ] ) . concat ( line ) ;
33+ previous . textSchema = ( previous . textSchema || [ ] ) . concat ( [ [ line ] ] ) ;
3434 return semanticsList ;
3535 } else if ( DEFINITION_FIELDS . indexOf ( field ) === - 1 ) {
3636 throw new Error ( `Invalid Definition Field: "${ field } "` ) ;
@@ -50,17 +50,14 @@ class CommentDefinitionParser {
5050 values : [ line . trim ( ) ]
5151 } ) ;
5252 } else if ( previous ) {
53- let lastSchemaItem = previous . schema && previous . schema [ previous . schema . length - 1 ] ;
54- let lastSchemaArray = Array . isArray ( lastSchemaItem )
55- ? lastSchemaItem
56- : lastSchemaItem
57- ? [ lastSchemaItem . trim ( ) ]
58- : [ ] ;
59- let isEnum = / ^ { \? ? e n u m } / i. test ( lastSchemaArray [ 0 ] ) ;
53+ let lastSchemaItem = previous . textSchema
54+ ? previous . textSchema [ previous . textSchema . length - 1 ]
55+ : [ '' ] ;
56+ let isEnum = / ^ { \? ? e n u m } / i. test ( lastSchemaItem [ 0 ] . trim ( ) ) ;
6057 // Enums inside schemas need to be collected as a single item
6158 if ( isEnum ) {
62- lastSchemaArray = lastSchemaArray . concat ( line . trim ( ) ) ;
63- previous . schema [ previous . schema . length - 1 ] = lastSchemaArray ;
59+ lastSchemaItem = lastSchemaItem . concat ( line . trim ( ) ) ;
60+ previous . textSchema [ previous . textSchema . length - 1 ] = lastSchemaItem ;
6461 } else {
6562 previous . values = previous . values . concat ( line . trim ( ) ) ;
6663 }
@@ -125,7 +122,8 @@ class CommentDefinitionParser {
125122 return values . join ( ' ' ) . split ( / \s + / ) ;
126123 }
127124
128- getParameter ( values , schema ) {
125+ getParameter ( values , textSchema = [ ] , depth = 0 ) {
126+
129127 if ( ! Array . isArray ( values ) ) {
130128 values = [ values ] ;
131129 }
@@ -168,7 +166,7 @@ class CommentDefinitionParser {
168166 }
169167
170168 if ( type === 'enum' ) {
171- let splitValue = values [ 0 ] . split ( ' ' ) . slice ( 1 ) ;
169+ let splitValue = values [ 0 ] . trim ( ) . split ( ' ' ) . slice ( 1 ) ;
172170 param . name = splitValue . shift ( ) ;
173171 param . description = splitValue . join ( ' ' ) ;
174172 param . members = this . parseEnumMembers ( values . slice ( 1 ) ) ;
@@ -178,11 +176,15 @@ class CommentDefinitionParser {
178176 let splitValue = value . split ( ' ' ) ;
179177 param . name = splitValue . shift ( ) ;
180178 param . description = splitValue . join ( ' ' ) ;
181- if ( schema ) {
179+ if ( textSchema . length ) {
182180 if ( ! [ 'object' , 'array' ] . includes ( type ) ) {
183181 throw new Error ( `Can not provide schema for type: "${ type } "` ) ;
184182 }
185- param . schema = this . parseSchema ( schema , type === 'object' ) ;
183+ let schemas = this . parseSchemas ( textSchema , depth , type === 'object' ) ;
184+ param . schema = schemas . shift ( ) ;
185+ if ( schemas . length ) {
186+ param . alternateSchemas = schemas ;
187+ }
186188 }
187189
188190 if ( defaultMetafield ) {
@@ -197,8 +199,8 @@ class CommentDefinitionParser {
197199 throw new Error ( `Options {?}: Not allowed for type "${ param . type } " for parameter "${ param . name } "` ) ;
198200 }
199201 param . options = { } ;
200- var opt = options . split ( ' ' ) ;
201- var values ;
202+ let opt = options . split ( ' ' ) ;
203+ let values ;
202204 try {
203205 values = JSON . parse ( options ) ;
204206 } catch ( e ) {
@@ -208,7 +210,7 @@ class CommentDefinitionParser {
208210 if ( values . length === 0 ) {
209211 throw new Error ( `Options {?}: Must provide non-zero options length` ) ;
210212 }
211- var paramType = ( param . type === 'object.keyql.query' || param . type === 'object.keyql.order' )
213+ let paramType = ( param . type === 'object.keyql.query' || param . type === 'object.keyql.order' )
212214 ? 'string'
213215 : param . type ;
214216 values . forEach ( v => {
@@ -221,12 +223,12 @@ class CommentDefinitionParser {
221223 if ( ! opt [ 0 ] || opt [ 0 ] . indexOf ( '.' ) === - 1 ) {
222224 throw new Error ( `Options {?}: Invalid API call for "${ param . name } ": "${ opt [ 1 ] } "` ) ;
223225 } else {
224- var call = / ^ ( .+ ?) (?: \( ( .* ) \) ) ? $ / gi. exec ( opt [ 0 ] ) ;
226+ let call = / ^ ( .+ ?) (?: \( ( .* ) \) ) ? $ / gi. exec ( opt [ 0 ] ) ;
225227 param . options . lib = call [ 1 ] ;
226228 if ( call [ 2 ] ) {
227229 param . options . map = ( call [ 2 ] || '' ) . split ( ',' ) . reduce ( ( map , p ) => {
228- var key = p . split ( '=' ) [ 0 ] ;
229- var value = p . split ( '=' ) . slice ( 1 ) . join ( '=' ) ;
230+ let key = p . split ( '=' ) [ 0 ] ;
231+ let value = p . split ( '=' ) . slice ( 1 ) . join ( '=' ) ;
230232 if ( ! key . match ( / ^ [ a - z 0 - 9 \_ ] + $ / i) || ! value . match ( / ^ [ a - z 0 - 9 \_ ] + $ / i) ) {
231233 throw new Error ( `Options {?}: Invalid API call parameters for "${ param . name } ": "${ call [ 2 ] } "` ) ;
232234 }
@@ -261,17 +263,17 @@ class CommentDefinitionParser {
261263
262264 let field = data . field ;
263265 let values = data . values ;
264- let schema = data . schema ;
266+ let textSchema = data . textSchema ;
265267
266268 try {
267269
268270 if ( field === 'description' ) {
269271 definition . description = values . join ( '\n' ) ;
270272 } else if ( field === 'param' ) {
271273 definition . params = definition . params || [ ] ;
272- definition . params . push ( this . getParameter ( values , schema ) ) ;
274+ definition . params . push ( this . getParameter ( values , textSchema ) ) ;
273275 } else if ( field === 'returns' ) {
274- definition . returns = this . getParameter ( values , schema ) ;
276+ definition . returns = this . getParameter ( values , textSchema ) ;
275277 } else if ( field === 'bg' ) {
276278 definition . bg = this . getBg ( values ) ;
277279 } else if ( field === 'acl' ) {
@@ -317,71 +319,57 @@ class CommentDefinitionParser {
317319
318320 }
319321
320- parseSchema ( schema , multipleKeys ) {
321- if ( schema . length && ! Array . isArray ( schema [ 0 ] ) && this . getLineDepth ( schema [ 0 ] ) ) {
322- throw new Error ( `Invalid Schema definition at: "${ schema [ 0 ] } "` ) ;
322+ parseSchemas ( textSchema , depth = 0 , allowMultipleEntries = false ) {
323+ let schemas = [ ] ;
324+ while ( textSchema . length ) {
325+ let line = textSchema [ 0 ] [ 0 ] ;
326+ let params = [ ] ;
327+ let schema = this . _parseSchema ( textSchema , params , depth ) ;
328+ if ( ! allowMultipleEntries && schema . length > 1 ) {
329+ throw new Error ( `Invalid Schema definition at "${ line } ": Schema for "array" can only support one top-level key that maps to every element.` ) ;
330+ }
331+ schemas . push ( schema ) ;
323332 }
324-
325- let parsedSchema = this . _parseSchema ( schema , [ ] , 0 ) ;
326-
327- if ( ! multipleKeys && parsedSchema . length > 1 ) {
328- throw new Error ( 'Schema for "array" can only support one top-level key that maps to every element.' ) ;
333+ if ( ! allowMultipleEntries && schemas . length > 1 ) {
334+ throw new Error ( `Invalid Schema definition at "${ line } ": Schema for "array" does not support OR (alternateSchemas).` ) ;
335+ } else if ( schemas . filter ( params => ! params . length ) . length > 0 ) {
336+ throw new Error ( `Invalid Schema definition at "${ line } ": OR (alternateSchemas) requires all schema lengths to be non-zero` ) ;
329337 }
330-
331- return parsedSchema ;
332-
338+ return schemas ;
333339 }
334340
335- _parseSchema ( schema , params , lastDepth ) {
341+ _parseSchema ( textSchema , params = [ ] , depth = 0 ) {
336342
337- if ( ! schema . length ) {
338- return params ;
343+ let values = textSchema . shift ( ) ;
344+ let line = values [ 0 ] ;
345+ let curDepth = this . getLineDepth ( line ) ;
346+ if ( depth !== curDepth ) {
347+ throw new Error ( `Invalid Schema definition at: "${ line } ", invalid line depth (expecting ${ depth } , found ${ curDepth } )` ) ;
339348 }
340-
341- let line = schema . shift ( ) ;
342- let lastParam = params [ params . length - 1 ] ;
343-
344-
345- // Just call this.getParameter to collect the enum and continue
346- if ( Array . isArray ( line ) ) {
347- let param = this . getParameter ( line ) ;
348-
349- if ( lastParam && ( lastParam . type === 'object' || lastParam . type === 'array' ) ) {
350- lastParam . schema = this . _parseSchema ( schema , [ param ] , lastDepth + 1 ) ;
351- return this . _parseSchema ( schema , params , lastDepth ) ;
349+ if ( line . trim ( ) === 'OR' ) {
350+ if ( ! textSchema . length ) {
351+ throw new Error ( `Invalid Schema definition at "${ line } ": OR (alternateSchemas) can not end a schema definition` ) ;
352352 }
353-
354- params . push ( param ) ;
355- return this . _parseSchema ( schema , params , lastDepth ) ;
356- }
357-
358- let depth = this . getLineDepth ( line ) ;
359- let param = this . getParameter ( line . trim ( ) ) ;
360- let step = depth - lastDepth ;
361-
362- if ( ! lastParam || step === 0 ) {
363- params . push ( param ) ;
364- return this . _parseSchema ( schema , params , depth ) ;
365- }
366-
367- if ( step === 1 ) {
368- if ( lastParam . type !== 'object' && lastParam . type !== 'array' ) {
369- throw new Error ( `Invalid Schema definition at: "${ line } ", can only define schemas for an object or array` ) ;
353+ return params ;
354+ } else {
355+ let subSchemaEnd = textSchema . findIndex ( values => {
356+ let line = values [ 0 ] ;
357+ return this . getLineDepth ( line ) <= curDepth ;
358+ } ) ;
359+ let subSchema ;
360+ if ( subSchemaEnd === - 1 ) {
361+ subSchema = textSchema . splice ( 0 , textSchema . length ) ;
362+ } else if ( subSchemaEnd ) {
363+ subSchema = textSchema . splice ( 0 , subSchemaEnd ) ;
370364 }
371- lastParam . schema = this . _parseSchema ( schema , [ param ] , depth ) ;
372- return this . _parseSchema ( schema , params , lastDepth ) ;
373- }
374-
375- if ( step > 1 ) {
376- throw new Error ( `Invalid Schema definition at: "${ line } ", spacing invalid` ) ;
365+ params . push ( this . getParameter ( values , subSchema , depth + 1 ) ) ;
366+ return textSchema . length
367+ ? this . _parseSchema ( textSchema , params , depth )
368+ : params ;
377369 }
378-
379- schema . unshift ( line ) ;
380- return params ;
381-
382370 }
383371
384- getLineDepth ( line ) {
372+ getLineDepth ( line ) {
385373
386374 let depth = ( line . length - line . replace ( / ^ \s * / , '' ) . length ) / 2 ;
387375
0 commit comments