public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            var jsonObject = SourcePoint.ReadObjectWithSourcePoints(reader, JToken.Load, out var start, out var after);

            if (resourceExplorer.IsRef(jsonObject))
            {
                // We can't do this asynchronously as the Json.NET interface is synchronous
                jsonObject = resourceExplorer.ResolveRefAsync(jsonObject, context).GetAwaiter().GetResult();
            }

            return(jsonObject as JObject);
        }
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            var jsonObject = SourcePoint.ReadObjectWithSourcePoints(reader, JToken.Load, out SourcePoint startPoint, out SourcePoint endPoint);

            if (resourceExplorer.IsRef(jsonObject))
            {
                // We can't do this asynchronously as the Json.NET interface is synchronous
                jsonObject = this.resourceExplorer.ResolveRefAsync(jsonObject).GetAwaiter().GetResult();
            }

            var kind = (string)jsonObject["$kind"];

            if (kind == null)
            {
                throw new ArgumentNullException($"$kind was not found: {JsonConvert.SerializeObject(jsonObject)}");
            }

            // if IdRefResolver made a path available for the JToken, then add it to the path stack
            // this maintains the stack of paths used as the source of json data
            var found = DebugSupport.SourceMap.TryGetValue(jsonObject, out var range);

            if (found)
            {
                paths.Push(range.Path);
            }

            T result = this.resourceExplorer.BuildType <T>(kind, jsonObject, serializer);

            // DeclarativeTypeLoader.LoadAsync only adds FileResource to the paths stack
            if (paths.Count > 0)
            {
                // combine the "path for the most recent JToken from IdRefResolver" or the "top root path"
                // with the line information for this particular json fragment and add it to the sourceMap
                range = new SourceRange()
                {
                    Path = paths.Peek(), StartPoint = startPoint, EndPoint = endPoint
                };
                DebugSupport.SourceMap.Add(result, range);
            }

            if (found)
            {
                paths.Pop();
            }

            return(result);
        }
        /// <summary>
        /// Reads the JSON representation of the object.
        /// </summary>
        /// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
        /// <param name="objectType">Type of the object.</param>
        /// <param name="existingValue">The existing value of object being read.</param>
        /// <param name="serializer">The calling serializer.</param>
        /// <returns>The object value.</returns>
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            var(jToken, range) = SourceScope.ReadTokenRange(reader, sourceContext);

            using (new SourceScope(sourceContext, range))
            {
                string refDialogName = null;

                if (resourceExplorer.IsRef(jToken))
                {
                    refDialogName = jToken.Value <string>();

                    // We can't do this asynchronously as the Json.NET interface is synchronous
                    var reference = resourceExplorer.ResolveRefInternalAsync(jToken, sourceContext).GetAwaiter().GetResult();
                    jToken = reference.token;
                    if (!rangeReferences.ContainsKey(jToken))
                    {
                        rangeReferences.Add(jToken, reference.range);
                    }
                }

                var kind = (string)jToken["$kind"];

                if (kind == null)
                {
                    // see if there is jObject resolver
                    var unKnownResult = ResolveUnknownObject(jToken);
                    if (unKnownResult != null)
                    {
                        return(unKnownResult);
                    }

                    throw new ArgumentNullException($"$kind was not found: {JsonConvert.SerializeObject(jToken)}");
                }

                // if reference resolution made a source context available for the JToken, then add it to the context stack
                var found = rangeReferences.TryGetValue(jToken, out var rangeResolved);
                using (var newScope = found ? new SourceScope(sourceContext, rangeResolved) : null)
                {
                    var passTwo = false;

                    foreach (var observer in this.observers)
                    {
                        if (observer is CycleDetectionObserver cycDetectObserver && cycDetectObserver.CycleDetectionPass == CycleDetectionPasses.PassTwo)
                        {
                            passTwo = true;
                        }

                        if (observer.OnBeforeLoadToken(sourceContext, rangeResolved ?? range, jToken, out T interceptResult))
                        {
                            return(interceptResult);
                        }
                    }

                    var tokenToBuild = TryAssignId(jToken, sourceContext);

                    T result;
                    if (passTwo && refDialogName != null && cachedRefDialogs.ContainsKey(refDialogName))
                    {
                        result = cachedRefDialogs[refDialogName];
                    }
                    else
                    {
                        result = this.resourceExplorer.BuildType <T>(kind, tokenToBuild, serializer);
                        if (passTwo && refDialogName != null)
                        {
                            cachedRefDialogs[refDialogName] = result;
                            this.resourceExplorer.UpdateResourceTokenCache(refDialogName, tokenToBuild, range);
                        }
                    }

                    // Associate the most specific source context information with this item
                    if (sourceContext.CallStack.Count > 0)
                    {
                        range = sourceContext.CallStack.Peek().DeepClone();
                        if (!DebugSupport.SourceMap.TryGetValue(result, out var _))
                        {
                            DebugSupport.SourceMap.Add(result, range);
                        }
                    }

                    foreach (var observer in this.observers)
                    {
                        if (observer.OnAfterLoadToken(sourceContext, range, jToken, result, out T interceptedResult))
                        {
                            return(interceptedResult);
                        }
                    }

                    return(result);
                }
            }
        }