1+ import {
2+ ChainItem ,
3+ DefineOriginsAndResolveRefState ,
4+ InternalResolveOptions ,
5+ NormalizationRule ,
6+ OriginsMetaRecord ,
7+ ReferenceHandler ,
8+ RefErrorTypes ,
9+ RichReference ,
10+ } from '../types'
11+ import { CloneState , CrawlHookResponse , CrawlRules , isObject , JsonPath } from '@netcracker/qubership-apihub-json-crawl'
12+ import { OPEN_API_PROPERTY_DESCRIPTION , OPEN_API_PROPERTY_SUMMARY } from '../rules/openapi.const'
13+ import {
14+ evaluateSyntheticTitle ,
15+ getOrReuseOrigin ,
16+ ResolvedRef ,
17+ SyntheticAllOf ,
18+ } from '../define-origins-and-resolve-ref'
19+ import { OpenApiSpecVersion } from '../spec-type'
20+ import { ErrorMessage } from '../errors'
21+ import { JSON_SCHEMA_PROPERTY_ALL_OF } from '../rules/jsonschema.const'
22+ import { setJsoProperty } from '../utils'
23+
24+ export type ReferenceObjectResolverOverrideField =
25+ | typeof OPEN_API_PROPERTY_DESCRIPTION
26+ | typeof OPEN_API_PROPERTY_SUMMARY
27+
28+ export type ReferenceHandlerResponse =
29+ void
30+ | CrawlHookResponse < CloneState < DefineOriginsAndResolveRefState > , NormalizationRule >
31+ export type ResolvedRefWithSiblings = ResolvedRefWithChildrenOrigins | ResolvedRefWithIndex
32+ export type RefAndSiblingResolver = ( context : ResolvedReferenceContext ) => ResolvedRefWithSiblings
33+
34+ export interface ReferenceObjectRuleConfig {
35+ version : OpenApiSpecVersion ,
36+ allowedOverrides ?: ReferenceObjectResolverOverrideField [ ]
37+ }
38+
39+ export interface JsonSchemaReferenceResolverOptions {
40+ richRefAllowed : boolean
41+ }
42+
43+ export interface ReferenceHandlerArgs {
44+ value : unknown ,
45+ safeKey : PropertyKey ,
46+ ref : any ,
47+ path : JsonPath ,
48+ state : CloneState < DefineOriginsAndResolveRefState > ,
49+ options : InternalResolveOptions ,
50+ }
51+
52+ export interface ReferenceHandlerArgsWithResolver extends ReferenceHandlerArgs {
53+ resolveDefaultReference : ( resolver : RefAndSiblingResolver ) => ReferenceHandlerResponse
54+ }
55+
56+ export interface ResolvedRefWithChildrenOrigins extends ResolvedRef {
57+ childrenOrigins : OriginsMetaRecord
58+ }
59+
60+ export interface ResolvedRefWithIndex extends ResolvedRef {
61+ titleIndex : number
62+ refIndex : number
63+ siblingIndex : number
64+ }
65+
66+ export interface ResolvedReferenceContext {
67+ options : InternalResolveOptions
68+ state : CloneState < DefineOriginsAndResolveRefState >
69+ resolvedRef : ResolvedRef
70+ originForObj : ChainItem
71+ sibling : Record < PropertyKey , unknown >
72+ rules : CrawlRules < NormalizationRule > | undefined
73+ syntheticTitleCache : Map < string , Record < PropertyKey , unknown > >
74+ reference : RichReference
75+ }
76+
77+ export function notAllowedReferenceHandler ( {
78+ options,
79+ state,
80+ safeKey,
81+ ref,
82+ path,
83+ value,
84+ } : ReferenceHandlerArgsWithResolver ) : ReferenceHandlerResponse {
85+ options . onRefResolveError ?.( ErrorMessage . referenceNotAllowed ( ref ) , path , ref , RefErrorTypes . REF_NOT_ALLOWED )
86+ state . node [ safeKey ] = value
87+ return { done : true }
88+ }
89+
90+ export function referenceObjectResolver ( overrides ?: ReferenceObjectResolverOverrideField [ ] ) : ReferenceHandler {
91+ return ( { resolveDefaultReference } ) : ReferenceHandlerResponse => {
92+ const overrideFieldsWithSiblings = ( {
93+ options,
94+ state,
95+ resolvedRef,
96+ originForObj,
97+ sibling,
98+ } : ResolvedReferenceContext ) : ResolvedRefWithSiblings => {
99+ const { refValue, origin } = resolvedRef
100+ const referenceValue = refValue as Record < PropertyKey , unknown >
101+
102+ options . originsFlag && getOrReuseOrigin ( referenceValue , originForObj , state . originCache )
103+
104+ const childrenOrigins : OriginsMetaRecord = { }
105+ if ( ! overrides ?. length || ! isObject ( sibling ) || Reflect . ownKeys ( sibling ) . length === 0 ) {
106+ return { refValue : referenceValue , origin, childrenOrigins }
107+ }
108+
109+ const referenceValueWithSibling = { ...referenceValue }
110+ overrides . forEach ( safeKey => {
111+ if ( safeKey in sibling ) {
112+ referenceValueWithSibling [ safeKey ] = sibling [ safeKey ]
113+ childrenOrigins [ safeKey ] = [ {
114+ parent : originForObj ,
115+ value : safeKey ,
116+ } ]
117+ }
118+ } )
119+ options . originsFlag && getOrReuseOrigin ( sibling , originForObj , state . originCache )
120+ return { refValue : referenceValueWithSibling , origin, childrenOrigins }
121+ }
122+ return resolveDefaultReference ( overrideFieldsWithSiblings )
123+ }
124+ }
125+
126+ export function jsonSchemaReferenceResolver ( { richRefAllowed } : JsonSchemaReferenceResolverOptions ) : ReferenceHandler {
127+ return ( { resolveDefaultReference, ref, path } ) : ReferenceHandlerResponse => {
128+ const wrapRefWithAllOfIfNeed = ( {
129+ options,
130+ state,
131+ resolvedRef,
132+ originForObj,
133+ sibling,
134+ rules,
135+ syntheticTitleCache,
136+ reference,
137+ } : ResolvedReferenceContext ) : ResolvedRefWithSiblings => {
138+ const { refValue, origin } = resolvedRef
139+
140+ if ( ! richRefAllowed && Reflect . ownKeys ( sibling ) . length !== 0 ) {
141+ options . onRefResolveError ?.( ErrorMessage . richRefObjectNotAllowed ( ref ) , path , ref , RefErrorTypes . RICH_REF_NOT_ALLOWED )
142+ sibling = { }
143+ }
144+
145+ const referenceValue = refValue as Record < PropertyKey , unknown >
146+
147+ const wrap : SyntheticAllOf & Record < PropertyKey , unknown > = { [ JSON_SCHEMA_PROPERTY_ALL_OF ] : [ ] }
148+ options . originsFlag && getOrReuseOrigin ( wrap , originForObj , state . originCache )
149+ options . originsFlag && getOrReuseOrigin ( wrap [ JSON_SCHEMA_PROPERTY_ALL_OF ] , originForObj , state . originCache )
150+ options . syntheticAllOfFlag && setJsoProperty ( wrap , options . syntheticAllOfFlag , true )
151+ let titleIndex = - 1
152+ let refIndex = 0
153+ let siblingIndex = - 1
154+ if ( options . syntheticTitleFlag && rules ?. resolvedReferenceNamePropertyKey ) {
155+ let syntheticTitle = syntheticTitleCache ?. get ( reference . normalized )
156+ if ( syntheticTitle === undefined ) {
157+ syntheticTitle = evaluateSyntheticTitle ( reference . jsonPath , options . syntheticTitleFlag , rules . resolvedReferenceNamePropertyKey )
158+ syntheticTitleCache . set ( reference . normalized , syntheticTitle )
159+ state . lazySourceOriginCollector . set ( syntheticTitle , { [ rules . resolvedReferenceNamePropertyKey ] : origin ? [ origin ] : [ ] } )
160+ }
161+ wrap . allOf . push ( syntheticTitle )
162+ titleIndex = 0
163+ refIndex ++
164+ }
165+ wrap . allOf . push ( referenceValue )
166+ options . originsFlag && getOrReuseOrigin ( referenceValue , originForObj , state . originCache )
167+ if ( Reflect . ownKeys ( sibling ) . length ) {
168+ wrap . allOf . push ( sibling )
169+ siblingIndex = refIndex + 1
170+ options . originsFlag && getOrReuseOrigin ( sibling , originForObj , state . originCache )
171+ }
172+ return wrap . allOf . length === 1
173+ ? { refValue : referenceValue , origin, childrenOrigins : { } }
174+ : { refValue : wrap , titleIndex, refIndex, siblingIndex, origin }
175+ }
176+
177+ return resolveDefaultReference ( wrapRefWithAllOfIfNeed )
178+ }
179+ }
0 commit comments