// ===================[ Interface Methods ]=========================== public JsonValue AppendNew(JsonBuilder valueBuilder) { int currTabbing = JsonHelper.EvaluteBegginningTabOffset(this, valueBuilder.BuilderSettings); int startIndex = this.OffsetInSource + this.StringValue.Length - 1; JsonHelper.FindInsertStart(this.Source.Text, ref startIndex); var trackerBuilder = new IndexTrackingStringBuilder(startIndex); if (this.Count > 0) { trackerBuilder.Write(","); } JsonBuilder.MakeNewline(trackerBuilder, currTabbing, valueBuilder.BuilderSettings); this.Source.BeginPlaceholderMode(trackerBuilder); JsonValue value = valueBuilder.BuildJsonValue(this.Source, trackerBuilder, currTabbing); this.Add(value); this.Source.PlaceholderSetupComplete(); return(value); }
public JsonValue AppendNew(string key, JsonBuilder valueBuilder) { int currTabbing = JsonHelper.EvaluteBegginningTabOffset(this, valueBuilder.BuilderSettings); int startIndex = this.OffsetInSource + this.StringValue.Length - 1; JsonHelper.FindInsertStart(this.Source.Text, ref startIndex); var trackerBuilder = new IndexTrackingStringBuilder(startIndex); if (this.Count > 0) { trackerBuilder.Write(","); } JsonBuilder.MakeNewline(trackerBuilder, currTabbing, valueBuilder.BuilderSettings); // Add the key part. This will actually be invalid until the PlaceholderSetupComplete happens JsonBuilder.WritePropertyHeading(trackerBuilder, key, out int keyStart, valueBuilder.BuilderSettings); if (!valueBuilder.IsValue) { JsonBuilder.MakeNewline(trackerBuilder, currTabbing, valueBuilder.BuilderSettings); } this.Source.BeginPlaceholderMode(trackerBuilder); TrackedString trackedKey = new TrackedString(this.Source, keyStart, key); JsonValue value = valueBuilder.BuildJsonValue(this.Source, trackerBuilder, currTabbing); this.Add(trackedKey, value); this.Source.PlaceholderSetupComplete(); return(value); }
/// <summary> /// The recursive utility that fills out a <see cref="JsonBuilder"/> based off of the passed in source /// </summary> /// <param name="source">The object to pull data from</param> /// <param name="target">The builder to fill out</param> public static void FillOutJsonBuilderForObject(object source, JsonBuilder target) { Type sourceType = source.GetType(); bool isUsuallyQuoted; // If we're elevating one of the properties of this thing, as itself, then we need to // alter the type we're operating on string elevatedPropertyName = sourceType.GetAttributes <JsonPropertyAsSelfAttribute>()?.FirstOrDefault()?.PropertyName; if (elevatedPropertyName != null) { PropertyInfo targetProp = sourceType.GetProperty(elevatedPropertyName, BindingFlags.Public | BindingFlags.Instance); if (targetProp != null) { source = targetProp.GetValue(source); sourceType = source.GetType(); } } // ----------- Handle Simple Values ------------ if (_CheckForSettingsRegisteredSimpleValue(sourceType, source, out isUsuallyQuoted, out string value)) { target.IsValueUsualQuoteTarget = isUsuallyQuoted; _SetValue(value); return; } // ----------- Handle Array ------------ if (typeof(IEnumerable).IsAssignableFrom(sourceType)) { JsonBuilder array = target.StartArray(); IEnumerable enumerableValue = (IEnumerable)source; if (enumerableValue != null) { foreach (object arrayItemObj in enumerableValue) { // =================[ Null Array Item ]=================== if (arrayItemObj == null) { // We've got a null element, but bad news it's an array that means we // *MUST* preserver element order and add an empty element. If it's // not an array, order doesn't matter, so we'll just skip it. if (sourceType.IsArray) { Type elementType = sourceType.GetElementType(); if (typeof(IEnumerable).IsAssignableFrom(elementType)) { var emptyChildArr = array.StartArray(); emptyChildArr.End(); } else if (elementType.IsSimpleType() || target.BuilderSettings.TryGetJsonValueStringMakerFor(elementType) != null) { var item = array.AddArrayItem(String.Empty); item.IsValueUsualQuoteTarget = true; } else { var document = array.StartDocument(); document.End(); } } continue; } // =================[ Normal Array Item ]=================== // Simple array item if (_CheckForSettingsRegisteredSimpleValue(arrayItemObj.GetType(), arrayItemObj, out isUsuallyQuoted, out string stringValue)) { var item = array.AddArrayItem(stringValue); item.IsValueUsualQuoteTarget = isUsuallyQuoted; } // Array of array item else if (arrayItemObj is IEnumerable) { FillOutJsonBuilderForObject(arrayItemObj, array); } // Document array item else { JsonBuilder arrayItem = array.StartDocument(); FillOutJsonBuilderForObject(arrayItemObj, arrayItem); } } } target.End(); return; } // ----------- Handle KeyValuePair special case ----------- if (target.BuilderSettings.HasAnyKVPTypeIdWriteInstructions && sourceType.IsGenericType && typeof(KeyValuePair <,>) == sourceType.GetGenericTypeDefinition()) { // [Special Case] Array item documents get started when they're added if (!target.IsArrayItem) { target = target.StartDocument(); } PropertyInfo keyProp = sourceType.GetProperty("Key"); object keyObj = keyProp.GetValue(source); if (TryGetTypeIdForType(target.BuilderSettings.KeyValuePairKeyTypeIdToWrite, keyObj?.GetType() ?? sourceType.GenericTypeArguments[0], out string keyTypeId)) { target.AddProperty(JsonDocument.kKVPKeyTypeIndicator, keyTypeId); } PropertyInfo valueProp = sourceType.GetProperty("Value"); object valueObj = valueProp.GetValue(source); if (TryGetTypeIdForType(target.BuilderSettings.KeyValuePairValueTypeIdToWrite, valueObj?.GetType() ?? sourceType.GenericTypeArguments[1], out string valueTypeId)) { target.AddProperty(JsonDocument.kKVPValueTypeIndicator, valueTypeId); } _HandleApplyProperty(source, keyProp); _HandleApplyProperty(source, valueProp); return; } // ----------- Handle Document ------------ PropertyInfo[] allProperties = GetPropertiesFrom(source.GetType(), true, false #if WINDOWS_UWP , target.BuilderSettings.UWP_RequireOptInViaDataMemberAttribute #endif ); if (allProperties.Length == 0 && target.Parent != null) { target.Parent.Children.Remove(target); return; } // [Special Case] Array item documents get started when they're added if (!target.IsArrayItem) { target = target.StartDocument(); } // Make sure to write out the type for the instance if requested if (TryGetTypeIdForType(target.BuilderSettings.TypeIdToWrite, sourceType, out string typeId)) { target.AddProperty(JsonDocument.kTypeIndicator, typeId); } foreach (PropertyInfo prop in allProperties) { _HandleApplyProperty(source, prop); } // ----------- Handle Value (Simple Type) ------------ void _HandleApplyProperty(object _propSource, PropertyInfo _propInfo) { object _sourceValue = _propInfo.GetValue(_propSource); if (_sourceValue != null) { var runtimeTypeEval = _propInfo.GetAttributes <JsonRuntimeTypeEvalAttribute>()?.FirstOrDefault(); if (runtimeTypeEval != null && JsonHelper.TryGetTypeIdForType(runtimeTypeEval.TypeWriteTarget, _sourceValue?.GetType(), out string _foundTypeId)) { JsonBuilder propertyObjectBuilder = target.StartProperty(_propInfo.Name).StartDocument(); propertyObjectBuilder.AddProperty(JsonDocument.kTypeIndicator, _foundTypeId); JsonBuilder typedValueObjectBuilder = propertyObjectBuilder.StartProperty(JsonDocument.kRuntimeTypeEvalValue); FillOutJsonBuilderForObject(_sourceValue, typedValueObjectBuilder); } else if (_CheckForSettingsRegisteredSimpleValue(_propInfo.PropertyType, _sourceValue, out isUsuallyQuoted, out string simpleStringValue)) { var created = target.AddProperty(_propInfo.Name, simpleStringValue); created.IsValueUsualQuoteTarget = isUsuallyQuoted; } else { JsonBuilder propertyBuilder = target.StartProperty(_propInfo.Name); FillOutJsonBuilderForObject(_sourceValue, propertyBuilder); } } } bool _CheckForSettingsRegisteredSimpleValue(Type _type, object _instance, out bool _isUsuallyQuoted, out string simplifiedStringValue) { _isUsuallyQuoted = false; var valueBuilder = target.BuilderSettings.TryGetJsonValueStringMakerFor(_type); if (valueBuilder != null) { simplifiedStringValue = valueBuilder(_instance); if (_type == typeof(string) || _type == typeof(char) #if WINDOWS_UWP || _type.IsEnum()) #else || _type.IsEnum) #endif { _isUsuallyQuoted = true; } return(true); } simplifiedStringValue = null; return(false); } void _SetValue(string _value) { if (target.IsValue) { target.Value = _value; } else { target.DocumentKVPValue = new JsonBuilder(target); target.DocumentKVPValue.Value = _value; } } }
internal JsonBuilder(JsonBuilder parent) : this(parent.BuilderSettings) { this.Parent = parent; }