diff --git a/src/Bicep.Core/Semantics/YamlObjectParser.cs b/src/Bicep.Core/Semantics/YamlObjectParser.cs index 759b7114e88..439be264f8e 100644 --- a/src/Bicep.Core/Semantics/YamlObjectParser.cs +++ b/src/Bicep.Core/Semantics/YamlObjectParser.cs @@ -4,7 +4,7 @@ using Bicep.Core.Diagnostics; using Bicep.Core.Text; using Newtonsoft.Json.Linq; -using SharpYaml.Serialization; +using SharpYaml; namespace Bicep.Core.Semantics; @@ -24,7 +24,7 @@ protected override ResultWithDiagnostic ExtractTokenFromObject(string fi { try { - return new Serializer().Deserialize(fileContent); + return YamlSerializer.Deserialize(fileContent); } catch { diff --git a/src/Bicep.LangServer.IntegrationTests/ImportKubernetesManifestTests.cs b/src/Bicep.LangServer.IntegrationTests/ImportKubernetesManifestTests.cs index 2aec848c7aa..27493bb09d1 100644 --- a/src/Bicep.LangServer.IntegrationTests/ImportKubernetesManifestTests.cs +++ b/src/Bicep.LangServer.IntegrationTests/ImportKubernetesManifestTests.cs @@ -79,7 +79,7 @@ NOT A VALID YAML FILE var message = await messageListener.WaitNext(); message.Should().HaveMessageAndType( - "Failed to deserialize kubernetes manifest YAML: (Lin: 1, Col: 4, Chr: 5) - (Lin: 1, Col: 25, Chr: 26): Expected dictionary node.", + "Failed to deserialize kubernetes manifest YAML: Expected dictionary node.", MessageType.Error); } } diff --git a/src/Bicep.LangServer/Handlers/ImportKubernetesManifestHandler.cs b/src/Bicep.LangServer/Handlers/ImportKubernetesManifestHandler.cs index 207d9229a70..3564b093f13 100644 --- a/src/Bicep.LangServer/Handlers/ImportKubernetesManifestHandler.cs +++ b/src/Bicep.LangServer/Handlers/ImportKubernetesManifestHandler.cs @@ -16,7 +16,7 @@ using OmniSharp.Extensions.JsonRpc; using OmniSharp.Extensions.LanguageServer.Protocol.Server; using SharpYaml; -using SharpYaml.Serialization; +using SharpYaml.Model; namespace Bicep.LanguageServer.Handlers { @@ -79,10 +79,9 @@ private string Decompile(IOUri bicepFileUri, string manifestContents, TelemetryA try { var reader = new StringReader(manifestContents); - var yamlStream = new YamlStream(); - yamlStream.Load(reader); + var yamlStream = YamlStream.Load(reader, null); - foreach (var yamlDocument in yamlStream.Documents) + foreach (var yamlDocument in yamlStream) { var syntax = ProcessResourceYaml(yamlDocument, telemetryHelper); @@ -111,36 +110,38 @@ private string Decompile(IOUri bicepFileUri, string manifestContents, TelemetryA private static ResourceDeclarationSyntax ProcessResourceYaml(YamlDocument yamlDocument, TelemetryAndErrorHandlingHelper telemetryHelper) { - if (yamlDocument.RootNode is not YamlMappingNode rootNode) + if (yamlDocument.Contents is not YamlMapping rootNode) { - throw new YamlException(yamlDocument.RootNode.Start, yamlDocument.RootNode.End, $"Expected dictionary node."); + throw new YamlException("Expected dictionary node."); } - var kindKey = rootNode.Children.Keys.FirstOrDefault(x => x is YamlScalarNode scalar && scalar.Value == "kind"); - var apiVersionKey = rootNode.Children.Keys.FirstOrDefault(x => x is YamlScalarNode scalar && scalar.Value == "apiVersion"); - - if (kindKey is null || apiVersionKey is null) + if (!rootNode.TryGetValue("kind", out var kindNodeElement) || + !rootNode.TryGetValue("apiVersion", out var apiVersionNodeElement)) { - throw new YamlException(rootNode.Start, rootNode.End, $"Failed to find 'kind' and 'apiVersion' keys for resource declaration."); + throw new YamlException("Failed to find 'kind' and 'apiVersion' keys for resource declaration."); } - if (rootNode.Children[kindKey] is not YamlScalarNode kindNode) + if (kindNodeElement is not YamlValue kindNode) { - throw new YamlException(kindKey.Start, kindKey.End, "Unable to process 'kind' for resource declaration."); + throw new YamlException("Unable to process 'kind' for resource declaration."); } - if (rootNode.Children[apiVersionKey] is not YamlScalarNode apiVersionNode) + if (apiVersionNodeElement is not YamlValue apiVersionNode) { - throw new YamlException(apiVersionKey.Start, apiVersionKey.End, "Unable to process 'apiVersion' for resource declaration."); + throw new YamlException("Unable to process 'apiVersion' for resource declaration."); } - var (type, apiVersion) = apiVersionNode.Value.LastIndexOf('/') switch + var kind = kindNode.Scalar.Value; + var apiVersionLiteral = apiVersionNode.Scalar.Value; + var (type, apiVersion) = apiVersionLiteral.LastIndexOf('/') switch { - -1 => ($"core/{kindNode.Value}", apiVersionNode.Value), - int x => ($"{apiVersionNode.Value.Substring(0, x)}/{kindNode.Value}", apiVersionNode.Value.Substring(x + 1)), + -1 => ($"core/{kind}", apiVersionLiteral), + int x => ($"{apiVersionLiteral.Substring(0, x)}/{kind}", apiVersionLiteral.Substring(x + 1)), }; - var filteredChildren = rootNode.Children.Where(x => x.Key != kindKey && x.Key != apiVersionKey); + var filteredChildren = rootNode.Where(x => + x.Key is not YamlValue keyValue || + (keyValue.Scalar.Value != "kind" && keyValue.Scalar.Value != "apiVersion")); var resourceBody = ConvertObjectChildren(filteredChildren); var symbolName = GetResourceSymbolName(type, resourceBody); @@ -193,47 +194,52 @@ private static string GetResourceSymbolName(string type, SyntaxBase resourceBody return identifierBuilder.ToString(); } - private static SyntaxBase ConvertValue(YamlNode value) + private static SyntaxBase ConvertValue(YamlElement? value) { + if (value is null) + { + return SyntaxFactory.CreateNullLiteral(); + } + switch (value) { - case YamlMappingNode dictValue: - return ConvertObjectChildren(dictValue.Children); - case YamlSequenceNode listValue: - var items = listValue.Children.Select(ConvertValue); + case YamlMapping dictValue: + return ConvertObjectChildren(dictValue); + case YamlSequence listValue: + var items = listValue.Select(ConvertValue); return SyntaxFactory.CreateArray(items); - case YamlScalarNode scalarNode: - if (scalarNode.Style == SharpYaml.ScalarStyle.Plain) + case YamlValue scalarNode: + if (scalarNode.Scalar.Style == ScalarStyle.Plain) { // If the user hasn't provided quotes, there's no way to differentiate between strings, ints & bools. We have to guess... - if (bool.TryParse(scalarNode.Value, out var boolVal)) + if (bool.TryParse(scalarNode.Scalar.Value, out var boolVal)) { return SyntaxFactory.CreateBooleanLiteral(boolVal); } - if (long.TryParse(scalarNode.Value, out var longVal)) + if (long.TryParse(scalarNode.Scalar.Value, out var longVal)) { return SyntaxFactory.CreatePositiveOrNegativeInteger(longVal); } } - return SyntaxFactory.CreateStringLiteral(scalarNode.Value); + return SyntaxFactory.CreateStringLiteral(scalarNode.Scalar.Value); default: throw new InvalidOperationException($"Unsupported type {value.GetType()}"); } } - private static ObjectSyntax ConvertObjectChildren(IEnumerable> children) + private static ObjectSyntax ConvertObjectChildren(IEnumerable> children) { var objectProperties = new List(); foreach (var kvp in children) { - if (kvp.Key is not YamlScalarNode keyNode) + if (kvp.Key is not YamlValue keyNode) { throw new InvalidOperationException($"Unsupported object key {kvp.Key.GetType()}"); } - var objectProperty = SyntaxFactory.CreateObjectProperty(keyNode.Value, ConvertValue(kvp.Value)); + var objectProperty = SyntaxFactory.CreateObjectProperty(keyNode.Scalar.Value, ConvertValue(kvp.Value)); objectProperties.Add(objectProperty); } return SyntaxFactory.CreateObject(objectProperties); diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index 3fa9af5ec50..4b022978159 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -91,7 +91,7 @@ - +