@@ -89,14 +89,20 @@ const plugin = {
8989 }
9090 }
9191 else {
92- promOrVal = extractFromDoc ( basePath , pointer ) . catch ( ( e ) => {
93- throw wrapError ( e , {
94- pointer,
95- $ref : ref ,
96- baseDoc,
97- fullPath,
92+ promOrVal = extractFromDoc ( basePath , pointer )
93+ if ( promOrVal . __value != null ) {
94+ promOrVal = promOrVal . __value
95+ }
96+ else {
97+ promOrVal = promOrVal . catch ( ( e ) => {
98+ throw wrapError ( e , {
99+ pointer,
100+ $ref : ref ,
101+ baseDoc,
102+ fullPath,
103+ } )
98104 } )
99- } )
105+ }
100106 }
101107
102108 if ( promOrVal instanceof Error ) {
@@ -178,7 +184,24 @@ function split(ref) {
178184 * @api public
179185 */
180186function extractFromDoc ( docPath , pointer ) {
181- return getDoc ( docPath ) . then ( doc => extract ( pointer , doc ) )
187+ const doc = docCache [ docPath ]
188+ if ( doc && ! lib . isPromise ( doc ) ) {
189+ // If doc is already available, return __value together with the promise.
190+ // __value is for special handling in cycle check:
191+ // pointerAlreadyInPath() won't work if patch.value is a promise,
192+ // thus when that promise is finally resolved, cycle might happen (because
193+ // `spec` and `docCache[basePath]` refer to the exact same object).
194+ // See test "should resolve a cyclic spec when baseDoc is specified".
195+ try {
196+ const v = extract ( pointer , doc )
197+ return Object . assign ( Promise . resolve ( v ) , { __value : v } )
198+ }
199+ catch ( e ) {
200+ return Promise . reject ( e )
201+ }
202+ }
203+
204+ return getDoc ( docPath ) . then ( _doc => extract ( pointer , _doc ) )
182205}
183206
184207/**
@@ -331,7 +354,7 @@ function pointerAlreadyInPath(pointer, basePath, parent, specmap) {
331354 // Detect by checking that the parent path doesn't start with pointer.
332355 // This only applies if the pointer is internal, i.e. basePath === rootPath (could be null)
333356 const rootDoc = specmap . contextTree . get ( [ ] ) . baseDoc
334- if ( basePath === rootDoc && pointerIsAParent ( parentPointer , pointer ) ) {
357+ if ( basePath == rootDoc && pointerIsAParent ( parentPointer , pointer ) ) { // eslint-disable-line
335358 return true
336359 }
337360
0 commit comments