private void HandleMappingWithWellKnownProperties( DefinitionInfo definition, List <MappingDefinition> mappingDefinitions, MappingToken mapping) { // Check if loose properties are allowed String looseKeyType = null; String looseValueType = null; DefinitionInfo?looseKeyDefinition = null; DefinitionInfo?looseValueDefinition = null; if (!String.IsNullOrEmpty(mappingDefinitions[0].LooseKeyType)) { looseKeyType = mappingDefinitions[0].LooseKeyType; looseValueType = mappingDefinitions[0].LooseValueType; } var keys = new HashSet <String>(StringComparer.OrdinalIgnoreCase); while (m_unraveler.AllowScalar(definition.Expand, out ScalarToken nextKeyScalar)) { // Expression if (nextKeyScalar is ExpressionToken) { var anyDefinition = new DefinitionInfo(definition, TemplateConstants.Any); mapping.Add(nextKeyScalar, Evaluate(anyDefinition)); continue; } // Not a string, convert if (!(nextKeyScalar is StringToken nextKey)) { nextKey = new StringToken(nextKeyScalar.FileId, nextKeyScalar.Line, nextKeyScalar.Column, nextKeyScalar.ToString()); } // Duplicate if (!keys.Add(nextKey.Value)) { m_context.Error(nextKey, TemplateStrings.ValueAlreadyDefined(nextKey.Value)); m_unraveler.SkipMappingValue(); continue; } // Well known if (m_schema.TryMatchKey(mappingDefinitions, nextKey.Value, out String nextValueType)) { var nextValueDefinition = new DefinitionInfo(definition, nextValueType); var nextValue = Evaluate(nextValueDefinition); mapping.Add(nextKey, nextValue); continue; } // Loose if (looseKeyType != null) { if (looseKeyDefinition == null) { looseKeyDefinition = new DefinitionInfo(definition, looseKeyType); looseValueDefinition = new DefinitionInfo(definition, looseValueType); } Validate(nextKey, looseKeyDefinition.Value); var nextValue = Evaluate(looseValueDefinition.Value); mapping.Add(nextKey, nextValue); continue; } // Error m_context.Error(nextKey, TemplateStrings.UnexpectedValue(nextKey.Value)); m_unraveler.SkipMappingValue(); } // Only one if (mappingDefinitions.Count > 1) { var hitCount = new Dictionary <String, Int32>(); foreach (MappingDefinition mapdef in mappingDefinitions) { foreach (String key in mapdef.Properties.Keys) { if (!hitCount.TryGetValue(key, out Int32 value)) { hitCount.Add(key, 1); } else { hitCount[key] = value + 1; } } } List <String> nonDuplicates = new List <String>(); foreach (String key in hitCount.Keys) { if (hitCount[key] == 1) { nonDuplicates.Add(key); } } nonDuplicates.Sort(); String listToDeDuplicate = String.Join(", ", nonDuplicates); m_context.Error(mapping, TemplateStrings.UnableToDetermineOneOf(listToDeDuplicate)); } m_unraveler.ReadMappingEnd(); }
private void HandleMappingWithWellKnownProperties( DefinitionInfo definition, List <MappingDefinition> mappingDefinitions, MappingToken mapping) { // Check if loose properties are allowed String looseKeyType = null; String looseValueType = null; DefinitionInfo?looseKeyDefinition = null; DefinitionInfo?looseValueDefinition = null; if (!String.IsNullOrEmpty(mappingDefinitions[0].LooseKeyType)) { looseKeyType = mappingDefinitions[0].LooseKeyType; looseValueType = mappingDefinitions[0].LooseValueType; } var keys = new HashSet <String>(StringComparer.OrdinalIgnoreCase); var hasExpressionKey = false; while (m_objectReader.AllowLiteral(out LiteralToken rawLiteral)) { var nextKeyScalar = ParseScalar(rawLiteral, definition.AllowedContext); // Expression if (nextKeyScalar is ExpressionToken) { hasExpressionKey = true; // Legal if (definition.AllowedContext.Length > 0) { m_memory.AddBytes(nextKeyScalar); var anyDefinition = new DefinitionInfo(definition, TemplateConstants.Any); mapping.Add(nextKeyScalar, ReadValue(anyDefinition)); } // Illegal else { m_context.Error(nextKeyScalar, TemplateStrings.ExpressionNotAllowed()); SkipValue(); } continue; } // Not a string, convert if (!(nextKeyScalar is StringToken nextKey)) { nextKey = new StringToken(nextKeyScalar.FileId, nextKeyScalar.Line, nextKeyScalar.Column, nextKeyScalar.ToString()); } // Duplicate if (!keys.Add(nextKey.Value)) { m_context.Error(nextKey, TemplateStrings.ValueAlreadyDefined(nextKey.Value)); SkipValue(); continue; } // Well known if (m_schema.TryMatchKey(mappingDefinitions, nextKey.Value, out String nextValueType)) { m_memory.AddBytes(nextKey); var nextValueDefinition = new DefinitionInfo(definition, nextValueType); var nextValue = ReadValue(nextValueDefinition); mapping.Add(nextKey, nextValue); continue; } // Loose if (looseKeyType != null) { if (looseKeyDefinition == null) { looseKeyDefinition = new DefinitionInfo(definition, looseKeyType); looseValueDefinition = new DefinitionInfo(definition, looseValueType); } Validate(nextKey, looseKeyDefinition.Value); m_memory.AddBytes(nextKey); var nextValue = ReadValue(looseValueDefinition.Value); mapping.Add(nextKey, nextValue); continue; } // Error m_context.Error(nextKey, TemplateStrings.UnexpectedValue(nextKey.Value)); SkipValue(); } // Only one if (mappingDefinitions.Count > 1) { var hitCount = new Dictionary <String, Int32>(); foreach (MappingDefinition mapdef in mappingDefinitions) { foreach (String key in mapdef.Properties.Keys) { if (!hitCount.TryGetValue(key, out Int32 value)) { hitCount.Add(key, 1); } else { hitCount[key] = value + 1; } } } List <String> nonDuplicates = new List <String>(); foreach (String key in hitCount.Keys) { if (hitCount[key] == 1) { nonDuplicates.Add(key); } } nonDuplicates.Sort(); String listToDeDuplicate = String.Join(", ", nonDuplicates); m_context.Error(mapping, TemplateStrings.UnableToDetermineOneOf(listToDeDuplicate)); } else if (mappingDefinitions.Count == 1 && !hasExpressionKey) { foreach (var property in mappingDefinitions[0].Properties) { if (property.Value.Required) { if (!keys.Contains(property.Key)) { m_context.Error(mapping, $"Required property is missing: {property.Key}"); } } } } ExpectMappingEnd(); }