1
1
import stampit from 'stampit' ;
2
2
import { propEq } from 'ramda' ;
3
3
import {
4
- cloneDeep ,
5
- cloneShallow ,
6
- Element ,
7
4
isElement ,
8
5
isMemberElement ,
9
6
isPrimitiveElement ,
10
7
isStringElement ,
8
+ IdentityManager ,
9
+ cloneDeep ,
10
+ cloneShallow ,
11
11
visit ,
12
12
toValue ,
13
+ Element ,
13
14
} from '@swagger-api/apidom-core' ;
14
15
import { ApiDOMError } from '@swagger-api/apidom-error' ;
15
16
import { evaluate , uriToPointer } from '@swagger-api/apidom-json-pointer' ;
@@ -19,6 +20,7 @@ import {
19
20
isChannelItemElementExternal ,
20
21
isReferenceElementExternal ,
21
22
isReferenceLikeElement ,
23
+ isBooleanJsonSchemaElement ,
22
24
keyMap ,
23
25
ReferenceElement ,
24
26
} from '@swagger-api/apidom-ns-asyncapi-2' ;
@@ -34,6 +36,21 @@ import Reference from '../../../Reference';
34
36
// @ts -ignore
35
37
const visitAsync = visit [ Symbol . for ( 'nodejs.util.promisify.custom' ) ] ;
36
38
39
+ // initialize element identity manager
40
+ const identityManager = IdentityManager ( ) ;
41
+
42
+ /**
43
+ * Predicate for detecting if element was created by merging referencing
44
+ * element with particular element identity with a referenced element.
45
+ */
46
+ const wasReferencedBy =
47
+ < T extends Element , U extends Element > ( referencingElement : T ) =>
48
+ ( element : U ) =>
49
+ element . meta . hasKey ( 'ref-referencing-element-id' ) &&
50
+ element . meta
51
+ . get ( 'ref-referencing-element-id' )
52
+ . equals ( toValue ( identityManager . identify ( referencingElement ) ) ) ;
53
+
37
54
const AsyncApi2DereferenceVisitor = stampit ( {
38
55
props : {
39
56
indirections : [ ] ,
@@ -55,7 +72,7 @@ const AsyncApi2DereferenceVisitor = stampit({
55
72
* Compute full ancestors lineage.
56
73
* Ancestors are flatten to unwrap all Element instances.
57
74
*/
58
- const directAncestors = new WeakSet ( ancestors . filter ( isElement ) ) ;
75
+ const directAncestors = new Set < Element > ( ancestors . filter ( isElement ) ) ;
59
76
const ancestorsLineage = new AncestorLineage ( ...this . ancestors , directAncestors ) ;
60
77
61
78
return [ ancestorsLineage , directAncestors ] ;
@@ -174,6 +191,24 @@ const AsyncApi2DereferenceVisitor = stampit({
174
191
175
192
this . indirections . pop ( ) ;
176
193
194
+ // Boolean JSON Schemas
195
+ if ( isBooleanJsonSchemaElement ( referencedElement ) ) {
196
+ const booleanJsonSchemaElement = cloneDeep ( referencedElement ) ;
197
+ // annotate referenced element with info about original referencing element
198
+ booleanJsonSchemaElement . setMetaProperty ( 'ref-fields' , {
199
+ $ref : toValue ( referencingElement . $ref ) ,
200
+ } ) ;
201
+ // annotate referenced element with info about origin
202
+ booleanJsonSchemaElement . setMetaProperty ( 'ref-origin' , reference . uri ) ;
203
+ // annotate fragment with info about referencing element
204
+ booleanJsonSchemaElement . setMetaProperty (
205
+ 'ref-referencing-element-id' ,
206
+ cloneDeep ( identityManager . identify ( referencingElement ) ) ,
207
+ ) ;
208
+
209
+ return booleanJsonSchemaElement ;
210
+ }
211
+
177
212
const mergeAndAnnotateReferencedElement = < T extends Element > ( refedElement : T ) : T => {
178
213
const copy = cloneShallow ( refedElement ) ;
179
214
@@ -183,18 +218,28 @@ const AsyncApi2DereferenceVisitor = stampit({
183
218
} ) ;
184
219
// annotate fragment with info about origin
185
220
copy . setMetaProperty ( 'ref-origin' , reference . uri ) ;
221
+ // annotate fragment with info about referencing element
222
+ copy . setMetaProperty (
223
+ 'ref-referencing-element-id' ,
224
+ cloneDeep ( identityManager . identify ( referencingElement ) ) ,
225
+ ) ;
186
226
187
227
return copy ;
188
228
} ;
189
229
190
230
// attempting to create cycle
191
- if ( ancestorsLineage . includes ( referencedElement ) ) {
231
+ if (
232
+ ancestorsLineage . includes ( referencingElement ) ||
233
+ ancestorsLineage . includes ( referencedElement )
234
+ ) {
235
+ const replaceWith =
236
+ ancestorsLineage . findItem ( wasReferencedBy ( referencingElement ) ) ??
237
+ mergeAndAnnotateReferencedElement ( referencedElement ) ;
192
238
if ( isMemberElement ( parent ) ) {
193
- parent . value = mergeAndAnnotateReferencedElement ( referencedElement ) ; // eslint-disable-line no-param-reassign
239
+ parent . value = replaceWith ; // eslint-disable-line no-param-reassign
194
240
} else if ( Array . isArray ( parent ) ) {
195
- parent [ key ] = mergeAndAnnotateReferencedElement ( referencedElement ) ; // eslint-disable-line no-param-reassign
241
+ parent [ key ] = replaceWith ; // eslint-disable-line no-param-reassign
196
242
}
197
-
198
243
return false ;
199
244
}
200
245
@@ -297,18 +342,28 @@ const AsyncApi2DereferenceVisitor = stampit({
297
342
} ) ;
298
343
// annotate referenced with info about origin
299
344
mergedElement . setMetaProperty ( 'ref-origin' , reference . uri ) ;
345
+ // annotate fragment with info about referencing element
346
+ mergedElement . setMetaProperty (
347
+ 'ref-referencing-element-id' ,
348
+ cloneDeep ( identityManager . identify ( referencingElement ) ) ,
349
+ ) ;
300
350
301
351
return mergedElement ;
302
352
} ;
303
353
304
354
// attempting to create cycle
305
- if ( ancestorsLineage . includes ( referencedElement ) ) {
355
+ if (
356
+ ancestorsLineage . includes ( referencingElement ) ||
357
+ ancestorsLineage . includes ( referencedElement )
358
+ ) {
359
+ const replaceWith =
360
+ ancestorsLineage . findItem ( wasReferencedBy ( referencingElement ) ) ??
361
+ mergeAndAnnotateReferencedElement ( referencedElement ) ;
306
362
if ( isMemberElement ( parent ) ) {
307
- parent . value = mergeAndAnnotateReferencedElement ( referencedElement ) ; // eslint-disable-line no-param-reassign
363
+ parent . value = replaceWith ; // eslint-disable-line no-param-reassign
308
364
} else if ( Array . isArray ( parent ) ) {
309
- parent [ key ] = mergeAndAnnotateReferencedElement ( referencedElement ) ; // eslint-disable-line no-param-reassign
365
+ parent [ key ] = replaceWith ; // eslint-disable-line no-param-reassign
310
366
}
311
-
312
367
return false ;
313
368
}
314
369
0 commit comments