diff --git a/Directory.Packages.props b/Directory.Packages.props index 70e1363ccef..1431be1c0d6 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -40,8 +40,7 @@ - - + @@ -62,7 +61,7 @@ - + diff --git a/src/Microsoft.TemplateEngine.Edge/BuiltInManagedProvider/GlobalSettings.cs b/src/Microsoft.TemplateEngine.Edge/BuiltInManagedProvider/GlobalSettings.cs index 33832329c1e..1b2b18b22cc 100644 --- a/src/Microsoft.TemplateEngine.Edge/BuiltInManagedProvider/GlobalSettings.cs +++ b/src/Microsoft.TemplateEngine.Edge/BuiltInManagedProvider/GlobalSettings.cs @@ -1,12 +1,13 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json; +using System.Text.Json.Nodes; using Microsoft.Extensions.Logging; + using Microsoft.TemplateEngine.Abstractions; using Microsoft.TemplateEngine.Abstractions.Installer; using Microsoft.TemplateEngine.Edge.Settings; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine.Edge.BuiltInManagedProvider { @@ -82,20 +83,20 @@ public async Task> GetInstalledTemplatePackag var jObject = _environmentSettings.Host.FileSystem.ReadObject(_globalSettingsFile); var packages = new List(); - foreach (var package in jObject.Get(nameof(GlobalSettingsData.Packages)) ?? new JArray()) + foreach (var package in jObject.Get(nameof(GlobalSettingsData.Packages)) ?? new JsonArray()) { packages.Add(new TemplatePackageData( - package.ToGuid(nameof(TemplatePackageData.InstallerId)), - package.Value(nameof(TemplatePackageData.MountPointUri)) ?? string.Empty, - ((DateTime?)package[nameof(TemplatePackageData.LastChangeTime)]) ?? default, + package!.ToGuid(nameof(TemplatePackageData.InstallerId)), + package.ToString(nameof(TemplatePackageData.MountPointUri)) ?? string.Empty, + package![nameof(TemplatePackageData.LastChangeTime)]?.GetValue() ?? default, package.ToStringDictionary(propertyName: nameof(TemplatePackageData.Details)))); } return packages; } - catch (JsonReaderException ex) + catch (JsonException ex) { - var wrappedEx = new JsonReaderException(string.Format(LocalizableStrings.GlobalSettings_Error_CorruptedSettings, _globalSettingsFile, ex.Message), ex); + var wrappedEx = new JsonException(string.Format(LocalizableStrings.GlobalSettings_Error_CorruptedSettings, _globalSettingsFile, ex.Message), ex.Path, ex.LineNumber, ex.BytePositionInLine, ex); throw wrappedEx; } catch (Exception) diff --git a/src/Microsoft.TemplateEngine.Edge/BuiltInManagedProvider/GlobalSettingsData.cs b/src/Microsoft.TemplateEngine.Edge/BuiltInManagedProvider/GlobalSettingsData.cs index 6a380483ee0..4e55c4643c0 100644 --- a/src/Microsoft.TemplateEngine.Edge/BuiltInManagedProvider/GlobalSettingsData.cs +++ b/src/Microsoft.TemplateEngine.Edge/BuiltInManagedProvider/GlobalSettingsData.cs @@ -1,8 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json.Serialization; using Microsoft.TemplateEngine.Abstractions.Installer; -using Newtonsoft.Json; namespace Microsoft.TemplateEngine.Edge.BuiltInManagedProvider { @@ -16,7 +16,7 @@ internal GlobalSettingsData(IReadOnlyList packages) Packages = packages; } - [JsonProperty] + [JsonInclude] internal IReadOnlyList Packages { get; } } } diff --git a/src/Microsoft.TemplateEngine.Edge/Constraints/ConstraintsExtensions.cs b/src/Microsoft.TemplateEngine.Edge/Constraints/ConstraintsExtensions.cs index 5f18d34b7ed..308f4813f29 100644 --- a/src/Microsoft.TemplateEngine.Edge/Constraints/ConstraintsExtensions.cs +++ b/src/Microsoft.TemplateEngine.Edge/Constraints/ConstraintsExtensions.cs @@ -1,8 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json; +using System.Text.Json.Nodes; using Microsoft.TemplateEngine.Utils; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine.Edge.Constraints { @@ -16,23 +17,29 @@ internal static class Extensions /// Thrown on unexpected input - not a valid json string or array of string or an empty array. public static IEnumerable ParseArrayOfConstraintStrings(this string? args) { - JToken token = ParseConstraintJToken(args); + JsonNode token = ParseConstraintJsonNode(args); - if (token.Type == JTokenType.String) + if (token.GetValueKind() == JsonValueKind.String) { - return new[] { token.Value() ?? throw new ConfigurationException(string.Format(LocalizableStrings.Constraint_Error_ArgumentHasEmptyString, args)) }; + return new[] { token.GetValue() ?? throw new ConfigurationException(string.Format(LocalizableStrings.Constraint_Error_ArgumentHasEmptyString, args)) }; } - JArray array = token.ToConstraintsJArray(args, true); + JsonArray array = token.ToConstraintsJsonArray(args, true); - return array.Values().Select(value => + return array.Select(value => { - if (string.IsNullOrEmpty(value)) + if (value == null || value.GetValueKind() != JsonValueKind.String) + { + throw new ConfigurationException(string.Format(LocalizableStrings.Constraint_Error_ArgumentHasEmptyString, args)); + } + + string? strValue = value.GetValue(); + if (string.IsNullOrEmpty(strValue)) { throw new ConfigurationException(string.Format(LocalizableStrings.Constraint_Error_ArgumentHasEmptyString, args)); } - return value!; + return strValue!; }); } @@ -42,14 +49,14 @@ public static IEnumerable ParseArrayOfConstraintStrings(this string? arg /// Input configuration string. /// Enumeration of parsed JObject tokens. /// Thrown on unexpected input - not a valid json array or an empty array. - public static IEnumerable ParseArrayOfConstraintJObjects(this string? args) + public static IEnumerable ParseArrayOfConstraintJObjects(this string? args) { - JToken token = ParseConstraintJToken(args); - JArray array = token.ToConstraintsJArray(args, false); + JsonNode token = ParseConstraintJsonNode(args); + JsonArray array = token.ToConstraintsJsonArray(args, false); return array.Select(value => { - if (value is not JObject jObj) + if (value is not JsonObject jObj) { throw new ConfigurationException(string.Format(LocalizableStrings.Constraint_Error_InvalidJsonArray_Objects, args)); } @@ -103,29 +110,29 @@ public static IVersionSpecification ParseVersionSpecification(this string versio return versionInstance; } - private static JToken ParseConstraintJToken(this string? args) + private static JsonNode ParseConstraintJsonNode(this string? args) { if (string.IsNullOrWhiteSpace(args)) { throw new ConfigurationException(LocalizableStrings.Constraint_Error_ArgumentsNotSpecified); } - JToken? token; + JsonNode? token; try { - token = JToken.Parse(args!); + token = JsonNode.Parse(args!); } catch (Exception e) { throw new ConfigurationException(string.Format(LocalizableStrings.Constraint_Error_InvalidJson, args), e); } - return token; + return token ?? throw new ConfigurationException(string.Format(LocalizableStrings.Constraint_Error_InvalidJson, args)); } - private static JArray ToConstraintsJArray(this JToken token, string? args, bool isStringTypeAllowed) + private static JsonArray ToConstraintsJsonArray(this JsonNode token, string? args, bool isStringTypeAllowed) { - if (token is not JArray array) + if (token is not JsonArray array) { throw new ConfigurationException(string.Format( isStringTypeAllowed diff --git a/src/Microsoft.TemplateEngine.Edge/Constraints/HostConstraint.cs b/src/Microsoft.TemplateEngine.Edge/Constraints/HostConstraint.cs index 29741375b44..bdbfb6ea106 100644 --- a/src/Microsoft.TemplateEngine.Edge/Constraints/HostConstraint.cs +++ b/src/Microsoft.TemplateEngine.Edge/Constraints/HostConstraint.cs @@ -1,10 +1,10 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json.Nodes; using Microsoft.TemplateEngine.Abstractions; using Microsoft.TemplateEngine.Abstractions.Constraints; using Microsoft.TemplateEngine.Utils; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine.Edge.Constraints { @@ -71,7 +71,7 @@ private static IEnumerable ParseArgs(string? args) { List hostInformation = new List(); - foreach (JObject jObj in args.ParseArrayOfConstraintJObjects()) + foreach (JsonObject jObj in args.ParseArrayOfConstraintJObjects()) { string? hostName = jObj.ToString("hostname"); string? version = jObj.ToString("version"); diff --git a/src/Microsoft.TemplateEngine.Edge/Microsoft.TemplateEngine.Edge.csproj b/src/Microsoft.TemplateEngine.Edge/Microsoft.TemplateEngine.Edge.csproj index 81945e88fe2..07475cbce22 100644 --- a/src/Microsoft.TemplateEngine.Edge/Microsoft.TemplateEngine.Edge.csproj +++ b/src/Microsoft.TemplateEngine.Edge/Microsoft.TemplateEngine.Edge.csproj @@ -28,7 +28,7 @@ - + diff --git a/src/Microsoft.TemplateEngine.Edge/Settings/SettingsStore.cs b/src/Microsoft.TemplateEngine.Edge/Settings/SettingsStore.cs index dd203f47cd8..688f8d3de9f 100644 --- a/src/Microsoft.TemplateEngine.Edge/Settings/SettingsStore.cs +++ b/src/Microsoft.TemplateEngine.Edge/Settings/SettingsStore.cs @@ -1,66 +1,67 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json; +using System.Text.Json.Nodes; +using System.Text.Json.Serialization; using Microsoft.TemplateEngine.Abstractions; using Microsoft.TemplateEngine.Utils; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine.Edge.Settings { internal class SettingsStore { - internal SettingsStore(JObject? obj) + internal SettingsStore(JsonObject? obj) { if (obj == null) { return; } - if (obj.TryGetValue(nameof(ComponentGuidToAssemblyQualifiedName), StringComparison.OrdinalIgnoreCase, out JToken? componentGuidToAssemblyQualifiedNameToken)) + if (obj.TryGetValueCaseInsensitive(nameof(ComponentGuidToAssemblyQualifiedName), out JsonNode? componentGuidToAssemblyQualifiedNameToken)) { - if (componentGuidToAssemblyQualifiedNameToken is JObject componentGuidToAssemblyQualifiedNameObject) + if (componentGuidToAssemblyQualifiedNameToken is JsonObject componentGuidToAssemblyQualifiedNameObject) { - foreach (JProperty entry in componentGuidToAssemblyQualifiedNameObject.Properties()) + foreach (var entry in componentGuidToAssemblyQualifiedNameObject) { - if (entry.Value is { Type: JTokenType.String }) + if (entry.Value?.GetValueKind() == JsonValueKind.String) { - ComponentGuidToAssemblyQualifiedName[entry.Name] = entry.Value.ToString(); + ComponentGuidToAssemblyQualifiedName[entry.Key] = entry.Value.GetValue(); } } } } - if (obj.TryGetValue(nameof(ProbingPaths), StringComparison.OrdinalIgnoreCase, out JToken? probingPathsToken)) + if (obj.TryGetValueCaseInsensitive(nameof(ProbingPaths), out JsonNode? probingPathsToken)) { - if (probingPathsToken is JArray probingPathsArray) + if (probingPathsToken is JsonArray probingPathsArray) { - foreach (JToken path in probingPathsArray) + foreach (JsonNode? path in probingPathsArray) { - if (path is { Type: JTokenType.String }) + if (path?.GetValueKind() == JsonValueKind.String) { - ProbingPaths.Add(path.ToString()); + ProbingPaths.Add(path.GetValue()); } } } } - if (obj.TryGetValue(nameof(ComponentTypeToGuidList), StringComparison.OrdinalIgnoreCase, out JToken? componentTypeToGuidListToken)) + if (obj.TryGetValueCaseInsensitive(nameof(ComponentTypeToGuidList), out JsonNode? componentTypeToGuidListToken)) { - if (componentTypeToGuidListToken is JObject componentTypeToGuidListObject) + if (componentTypeToGuidListToken is JsonObject componentTypeToGuidListObject) { - foreach (JProperty entry in componentTypeToGuidListObject.Properties()) + foreach (var entry in componentTypeToGuidListObject) { - if (entry.Value is JArray values) + if (entry.Value is JsonArray values) { HashSet set = new HashSet(); - ComponentTypeToGuidList[entry.Name] = set; + ComponentTypeToGuidList[entry.Key] = set; - foreach (JToken value in values) + foreach (JsonNode? value in values) { - if (value is { Type: JTokenType.String }) + if (value?.GetValueKind() == JsonValueKind.String) { - if (Guid.TryParse(value.ToString(), out Guid id)) + if (Guid.TryParse(value.GetValue(), out Guid id)) { set.Add(id); } @@ -72,13 +73,13 @@ internal SettingsStore(JObject? obj) } } - [JsonProperty] + [JsonInclude] internal Dictionary ComponentGuidToAssemblyQualifiedName { get; } = new(); - [JsonProperty] + [JsonInclude] internal HashSet ProbingPaths { get; } = new(); - [JsonProperty] + [JsonInclude] internal Dictionary> ComponentTypeToGuidList { get; } = new(); internal static SettingsStore Load(IEngineEnvironmentSettings engineEnvironmentSettings, SettingsFilePaths paths) @@ -88,7 +89,7 @@ internal static SettingsStore Load(IEngineEnvironmentSettings engineEnvironmentS return new SettingsStore(null); } - JObject parsed; + JsonObject parsed; using (Timing.Over(engineEnvironmentSettings.Host.Logger, "Parse settings")) { try diff --git a/src/Microsoft.TemplateEngine.Edge/Settings/TemplateCache.cs b/src/Microsoft.TemplateEngine.Edge/Settings/TemplateCache.cs index 92462ca29f8..39cde883ea5 100644 --- a/src/Microsoft.TemplateEngine.Edge/Settings/TemplateCache.cs +++ b/src/Microsoft.TemplateEngine.Edge/Settings/TemplateCache.cs @@ -3,13 +3,13 @@ using System.Globalization; using System.Text; +using System.Text.Json.Nodes; +using System.Text.Json.Serialization; using Microsoft.Extensions.Logging; using Microsoft.TemplateEngine.Abstractions; using Microsoft.TemplateEngine.Abstractions.Mount; using Microsoft.TemplateEngine.Abstractions.TemplatePackage; using Microsoft.TemplateEngine.Utils; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine.Edge.Settings { @@ -58,7 +58,7 @@ public TemplateCache(IReadOnlyList allTemplatePackages, ScanRe (IScanTemplateInfo Template, ITemplatePackage TemplatePackage, ILocalizationLocator? Localization, IMountPoint MountPoint) chosenTemplate = duplicatedIdentities.Value.Last(); ILocalizationLocator? loc = GetBestLocalizationLocatorMatch(chosenTemplate.Template); - (string, JObject?)? hostFile = GetBestHostConfigMatch(chosenTemplate.Template, environmentSettings, chosenTemplate.MountPoint); + (string, JsonObject?)? hostFile = GetBestHostConfigMatch(chosenTemplate.Template, environmentSettings, chosenTemplate.MountPoint); templates.Add(new TemplateInfo(chosenTemplate.Template, loc, hostFile)); } @@ -71,11 +71,11 @@ public TemplateCache(IReadOnlyList allTemplatePackages, ScanRe PrintOverlappingIdentityWarning(logger, templateDeduplicationDictionary); } - public TemplateCache(JObject? contentJObject) + public TemplateCache(JsonObject? contentJObject) { - if (contentJObject != null && contentJObject.TryGetValue(nameof(Version), StringComparison.OrdinalIgnoreCase, out JToken? versionToken)) + if (contentJObject != null && contentJObject.TryGetValueCaseInsensitive(nameof(Version), out JsonNode? versionToken)) { - Version = versionToken.ToString(); + Version = versionToken!.ToJsonString().Trim('"'); } else { @@ -86,17 +86,20 @@ public TemplateCache(JObject? contentJObject) return; } - Locale = contentJObject.TryGetValue(nameof(Locale), StringComparison.OrdinalIgnoreCase, out JToken? localeToken) - ? localeToken.ToString() + Locale = contentJObject.TryGetValueCaseInsensitive(nameof(Locale), out JsonNode? localeToken) + ? localeToken!.GetValue() : string.Empty; var mountPointInfo = new Dictionary(); - if (contentJObject.TryGetValue(nameof(MountPointsInfo), StringComparison.OrdinalIgnoreCase, out JToken? mountPointInfoToken) && mountPointInfoToken is IDictionary dict) + if (contentJObject.TryGetValueCaseInsensitive(nameof(MountPointsInfo), out JsonNode? mountPointInfoToken) && mountPointInfoToken is JsonObject mountPointInfoObj) { - foreach (var entry in dict) + foreach (var entry in mountPointInfoObj) { - mountPointInfo.Add(entry.Key, entry.Value.Value()); + if (entry.Value != null) + { + mountPointInfo.Add(entry.Key, entry.Value.GetValue()); + } } } @@ -104,13 +107,13 @@ public TemplateCache(JObject? contentJObject) List templateList = new List(); - if (contentJObject.TryGetValue(nameof(TemplateInfo), StringComparison.OrdinalIgnoreCase, out JToken? templateInfoToken) && templateInfoToken is JArray arr) + if (contentJObject.TryGetValueCaseInsensitive(nameof(TemplateInfo), out JsonNode? templateInfoToken) && templateInfoToken is JsonArray arr) { - foreach (JToken entry in arr) + foreach (JsonNode? entry in arr) { - if (entry != null && entry.Type == JTokenType.Object) + if (entry is JsonObject entryObj) { - templateList.Add(Settings.TemplateInfo.FromJObject((JObject)entry)); + templateList.Add(Settings.TemplateInfo.FromJObject(entryObj)); } } } @@ -118,16 +121,16 @@ public TemplateCache(JObject? contentJObject) TemplateInfo = templateList; } - [JsonProperty] + [JsonPropertyName("Version")] public string? Version { get; } - [JsonProperty] + [JsonPropertyName("Locale")] public string Locale { get; } - [JsonProperty] + [JsonPropertyName("TemplateInfo")] public IReadOnlyList TemplateInfo { get; } - [JsonProperty] + [JsonPropertyName("MountPointsInfo")] public Dictionary MountPointsInfo { get; } private ILocalizationLocator? GetBestLocalizationLocatorMatch(IScanTemplateInfo template) @@ -195,7 +198,7 @@ private void PrintOverlappingIdentityWarning(ILogger logger, IDictionary shortNam /// unlocalized template. /// localization information. /// host config information. - internal TemplateInfo(IScanTemplateInfo template, ILocalizationLocator? localizationInfo, (string Path, JObject? Content)? hostConfig) + internal TemplateInfo(IScanTemplateInfo template, ILocalizationLocator? localizationInfo, (string Path, JsonObject? Content)? hostConfig) { if (template is null) { @@ -97,11 +97,11 @@ internal TemplateInfo(IScanTemplateInfo template, ILocalizationLocator? localiza Name = localizationInfo?.Name ?? template.Name; ParameterDefinitions = LocalizeParameters(template, localizationInfo); - HostData = hostConfig?.Content?.ToString(Formatting.None); + HostData = hostConfig?.Content?.ToJsonString(); } #pragma warning disable CS0618 // Type or member is obsolete - [JsonProperty(nameof(Parameters))] + [JsonPropertyName("Parameters")] #pragma warning restore CS0618 // Type or member is obsolete public IParameterDefinitionSet ParameterDefinitions { get; private set; } = ParameterDefinitionSet.Empty; @@ -109,34 +109,34 @@ internal TemplateInfo(IScanTemplateInfo template, ILocalizationLocator? localiza [Obsolete("Use ParameterDefinitionSet instead.")] public IReadOnlyList Parameters => ParameterDefinitions; - [JsonProperty] + [JsonPropertyName("MountPointUri")] public string MountPointUri { get; } - [JsonProperty] + [JsonPropertyName("Author")] public string? Author { get; private set; } - [JsonProperty] + [JsonPropertyName("Classifications")] public IReadOnlyList Classifications { get; private set; } = new List(); - [JsonProperty] + [JsonPropertyName("DefaultName")] public string? DefaultName { get; private set; } - [JsonProperty] + [JsonPropertyName("Description")] public string? Description { get; private set; } - [JsonProperty] + [JsonPropertyName("Identity")] public string Identity { get; } - [JsonProperty] + [JsonPropertyName("GeneratorId")] public Guid GeneratorId { get; private set; } - [JsonProperty] + [JsonPropertyName("GroupIdentity")] public string? GroupIdentity { get; private set; } - [JsonProperty] + [JsonPropertyName("Precedence")] public int Precedence { get; private set; } - [JsonProperty] + [JsonPropertyName("Name")] public string Name { get; } [JsonIgnore] @@ -156,7 +156,7 @@ string ITemplateInfo.ShortName public IReadOnlyList ShortNameList { get; } = new List(); - [JsonProperty] + [JsonPropertyName("PreferDefaultName")] public bool PreferDefaultName { get; private set; } [JsonIgnore] @@ -210,22 +210,22 @@ IReadOnlyDictionary ITemplateInfo.CacheParameters } } - [JsonProperty] + [JsonPropertyName("ConfigPlace")] public string ConfigPlace { get; } - [JsonProperty] + [JsonPropertyName("LocaleConfigPlace")] public string? LocaleConfigPlace { get; private set; } - [JsonProperty] + [JsonPropertyName("HostConfigPlace")] public string? HostConfigPlace { get; private set; } - [JsonProperty] + [JsonPropertyName("ThirdPartyNotices")] public string? ThirdPartyNotices { get; private set; } - [JsonProperty] + [JsonPropertyName("BaselineInfo")] public IReadOnlyDictionary BaselineInfo { get; private set; } = new Dictionary(); - [JsonProperty] + [JsonPropertyName("TagsCollection")] public IReadOnlyDictionary TagsCollection { get; private set; } = new Dictionary(); [JsonIgnore] @@ -233,13 +233,13 @@ IReadOnlyDictionary ITemplateInfo.CacheParameters public string? HostData { get; private set; } - [JsonProperty] + [JsonPropertyName("PostActions")] public IReadOnlyList PostActions { get; private set; } = []; - [JsonProperty] + [JsonPropertyName("Constraints")] public IReadOnlyList Constraints { get; private set; } = []; - public static TemplateInfo FromJObject(JObject entry) + public static TemplateInfo FromJObject(JsonObject entry) { return TemplateInfoReader.FromJObject(entry); } diff --git a/src/Microsoft.TemplateEngine.Edge/Settings/TemplateInfoReader.cs b/src/Microsoft.TemplateEngine.Edge/Settings/TemplateInfoReader.cs index 264fde02f44..60a2e2b1436 100644 --- a/src/Microsoft.TemplateEngine.Edge/Settings/TemplateInfoReader.cs +++ b/src/Microsoft.TemplateEngine.Edge/Settings/TemplateInfoReader.cs @@ -1,12 +1,12 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json.Nodes; +using System.Text.Json.Serialization; using Microsoft.TemplateEngine.Abstractions; using Microsoft.TemplateEngine.Abstractions.Constraints; using Microsoft.TemplateEngine.Abstractions.Parameters; using Microsoft.TemplateEngine.Utils; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine.Edge.Settings { @@ -14,26 +14,29 @@ internal partial class TemplateInfo { internal class TemplateInfoReader { - internal static TemplateInfo FromJObject(JObject entry) + internal static TemplateInfo FromJObject(JsonObject entry) { string identity = entry.ToString(nameof(Identity)) ?? throw new ArgumentException($"{nameof(entry)} doesn't have {nameof(Identity)} property.", nameof(entry)); string name = entry.ToString(nameof(Name)) ?? throw new ArgumentException($"{nameof(entry)} doesn't have {nameof(Name)} property.", nameof(entry)); string mountPointUri = entry.ToString(nameof(MountPointUri)) ?? throw new ArgumentException($"{nameof(entry)} doesn't have {nameof(MountPointUri)} property.", nameof(entry)); string configPlace = entry.ToString(nameof(ConfigPlace)) ?? throw new ArgumentException($"{nameof(entry)} doesn't have {nameof(ConfigPlace)} property.", nameof(entry)); - JToken? shortNameToken = entry.Get(nameof(ShortNameList)); + JsonNode? shortNameToken = entry.Get(nameof(ShortNameList)); IEnumerable shortNames = shortNameToken.JTokenStringOrArrayToCollection([]); TemplateInfo info = new TemplateInfo(identity, name, shortNames, mountPointUri, configPlace) { Author = entry.ToString(nameof(Author)) }; - JArray? classificationsArray = entry.Get(nameof(Classifications)); + JsonArray? classificationsArray = entry.Get(nameof(Classifications)); if (classificationsArray != null) { List classifications = new List(); - foreach (JToken item in classificationsArray) + foreach (JsonNode? item in classificationsArray) { - classifications.Add(item.ToString()); + if (item != null) + { + classifications.Add(item.GetValue()); + } } info.Classifications = classifications; } @@ -49,34 +52,34 @@ internal static TemplateInfo FromJObject(JObject entry) info.HostConfigPlace = entry.ToString(nameof(HostConfigPlace)); info.ThirdPartyNotices = entry.ToString(nameof(ThirdPartyNotices)); - JObject? baselineJObject = entry.Get(nameof(ITemplateInfo.BaselineInfo)); + JsonObject? baselineJObject = entry.Get(nameof(ITemplateInfo.BaselineInfo)); Dictionary baselineInfo = new Dictionary(); if (baselineJObject != null) { - foreach (JProperty item in baselineJObject.Properties()) + foreach (var item in baselineJObject) { - var defaultOverrides = item.Value.ToStringDictionary(propertyName: nameof(IBaselineInfo.DefaultOverrides)); + var defaultOverrides = item.Value?.ToStringDictionary(propertyName: nameof(IBaselineInfo.DefaultOverrides)); if (defaultOverrides is null) { continue; } IBaselineInfo baseline = new BaselineInfo(defaultOverrides, item.Value.ToString(nameof(IBaselineInfo.Description))); - baselineInfo.Add(item.Name, baseline); + baselineInfo.Add(item.Key, baseline); } info.BaselineInfo = baselineInfo; } //read parameters #pragma warning disable CS0618 // Type or member is obsolete - JArray? parametersArray = entry.Get(nameof(Parameters)); + JsonArray? parametersArray = entry.Get(nameof(Parameters)); #pragma warning restore CS0618 // Type or member is obsolete if (parametersArray != null) { List templateParameters = new List(); - foreach (JToken item in parametersArray) + foreach (JsonNode? item in parametersArray) { - if (item is JObject jObj) + if (item is JsonObject jObj) { templateParameters.Add(ParameterFromJObject(jObj)); } @@ -87,25 +90,25 @@ internal static TemplateInfo FromJObject(JObject entry) //read tags // tags are just "name": "description" // e.g.: "language": "C#" - JObject? tagsObject = entry.Get(nameof(TagsCollection)); + JsonObject? tagsObject = entry.Get(nameof(TagsCollection)); if (tagsObject != null) { Dictionary tags = new Dictionary(); - foreach (JProperty item in tagsObject.Properties()) + foreach (var item in tagsObject) { - tags.Add(item.Name.ToString(), item.Value.ToString()); + tags.Add(item.Key, item.Value?.GetValue() ?? string.Empty); } info.TagsCollection = tags; } info.HostData = entry.ToString(nameof(info.HostData)); - JArray? postActionsArray = entry.Get(nameof(info.PostActions)); + JsonArray? postActionsArray = entry.Get(nameof(info.PostActions)); if (postActionsArray != null) { List postActions = new List(); - foreach (JToken item in postActionsArray) + foreach (JsonNode? item in postActionsArray) { - if (Guid.TryParse(item.ToString(), out Guid id)) + if (item != null && Guid.TryParse(item.GetValue(), out Guid id)) { postActions.Add(id); } @@ -114,11 +117,11 @@ internal static TemplateInfo FromJObject(JObject entry) } //read parameters - JArray? constraintsArray = entry.Get(nameof(info.Constraints)); + JsonArray? constraintsArray = entry.Get(nameof(info.Constraints)); if (constraintsArray != null) { List constraints = new List(); - foreach (JToken item in constraintsArray) + foreach (JsonNode? item in constraintsArray) { string? type = item.ToString(nameof(TemplateConstraintInfo.Type)); if (string.IsNullOrWhiteSpace(type)) @@ -134,10 +137,10 @@ internal static TemplateInfo FromJObject(JObject entry) } /// - /// Parses from . + /// Parses from . /// /// - private static ITemplateParameter ParameterFromJObject(JObject jObject) + private static ITemplateParameter ParameterFromJObject(JsonObject jObject) { string? name = jObject.ToString(nameof(ITemplateParameter.Name)); if (string.IsNullOrWhiteSpace(name)) @@ -160,13 +163,13 @@ private static ITemplateParameter ParameterFromJObject(JObject jObject) if (dataType.Equals("choice", StringComparison.OrdinalIgnoreCase)) { choices = new Dictionary(StringComparer.OrdinalIgnoreCase); - JObject? cdToken = jObject.Get(nameof(ITemplateParameter.Choices)); + JsonObject? cdToken = jObject.Get(nameof(ITemplateParameter.Choices)); if (cdToken != null) { - foreach (JProperty cdPair in cdToken.Properties()) + foreach (var cdPair in cdToken) { choices.Add( - cdPair.Name.ToString(), + cdPair.Key, new ParameterChoice( cdPair.Value.ToString(nameof(ParameterChoice.DisplayName)), cdPair.Value.ToString(nameof(ParameterChoice.Description)))); @@ -205,34 +208,34 @@ internal CacheTemplateParameter(ITemplateParameter parameter) public string? Description => _parameter.Description; - [JsonProperty] + [JsonPropertyName("Name")] public string Name => _parameter.Name; - [JsonProperty] + [JsonPropertyName("Precedence")] public TemplateParameterPrecedence Precedence => _parameter.Precedence; - [JsonProperty] + [JsonPropertyName("Type")] public string Type => _parameter.Type; - [JsonProperty] + [JsonPropertyName("IsName")] public bool IsName => _parameter.IsName; - [JsonProperty] + [JsonPropertyName("DefaultValue")] public string? DefaultValue => _parameter.DefaultValue; - [JsonProperty] + [JsonPropertyName("DefaultIfOptionWithoutValue")] public string? DefaultIfOptionWithoutValue => _parameter.DefaultIfOptionWithoutValue; - [JsonProperty] + [JsonPropertyName("DataType")] public string DataType => _parameter.DataType; - [JsonProperty] + [JsonPropertyName("Choices")] public IReadOnlyDictionary? Choices => _parameter.Choices; - [JsonProperty] + [JsonPropertyName("DisplayName")] public string? DisplayName => _parameter.DisplayName; - [JsonProperty] + [JsonPropertyName("AllowMultipleValues")] public bool AllowMultipleValues => _parameter.AllowMultipleValues; [Obsolete] diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/BaseReplaceSymbol.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/BaseReplaceSymbol.cs index 7f45f022b56..3556d35f850 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/BaseReplaceSymbol.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/BaseReplaceSymbol.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using Newtonsoft.Json.Linq; +using System.Text.Json.Nodes; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ConfigModel { @@ -20,7 +20,7 @@ private protected BaseReplaceSymbol(BaseReplaceSymbol clone) : base(clone) ReplacementContexts = clone.ReplacementContexts; } - private protected BaseReplaceSymbol(JObject jObject, string name) : base(name) + private protected BaseReplaceSymbol(JsonObject jObject, string name) : base(name) { FileRename = jObject.ToString(nameof(FileRename)); Replaces = jObject.ToString(nameof(Replaces)); diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/BaseValueSymbol.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/BaseValueSymbol.cs index 666889bd586..a3a2b0cc7b5 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/BaseValueSymbol.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/BaseValueSymbol.cs @@ -1,7 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using Newtonsoft.Json.Linq; +using System.Text.Json; +using System.Text.Json.Nodes; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ConfigModel { @@ -14,12 +15,12 @@ public abstract class BaseValueSymbol : BaseReplaceSymbol /// /// /// - private protected BaseValueSymbol(string name, JObject jObject, string? defaultOverride, bool symbolConditionsSupported = false) : base(jObject, name) + private protected BaseValueSymbol(string name, JsonObject jObject, string? defaultOverride, bool symbolConditionsSupported = false) : base(jObject, name) { DefaultValue = defaultOverride ?? jObject.ToString(nameof(DefaultValue)); IsRequired = ParseIsRequiredField(jObject, !symbolConditionsSupported); DataType = jObject.ToString(nameof(DataType)); - if (!jObject.TryGetValue(nameof(Forms), StringComparison.OrdinalIgnoreCase, out JToken? formsToken) || formsToken is not JObject formsObject) + if (!jObject.TryGetValue(nameof(Forms), out JsonNode? formsToken) || formsToken is not JsonObject formsObject) { // no value forms explicitly defined, use the default ("identity") Forms = SymbolValueFormsModel.Default; @@ -68,17 +69,18 @@ private protected BaseValueSymbol(string name, string? replaces) : base(name, re /// public string? DataType { get; internal init; } - private protected bool TryGetIsRequiredField(JToken token, out bool result) + private protected bool TryGetIsRequiredField(JsonNode token, out bool result) { result = false; - return (token.Type == JTokenType.Boolean || token.Type == JTokenType.String) + var kind = token.GetValueKind(); + return (kind is JsonValueKind.True or JsonValueKind.False || kind == JsonValueKind.String) && bool.TryParse(token.ToString(), out result); } - private bool ParseIsRequiredField(JToken token, bool throwOnError) + private bool ParseIsRequiredField(JsonNode token, bool throwOnError) { - if (!token.TryGetValue(nameof(IsRequired), out JToken? isRequiredToken)) + if (!token.TryGetValue(nameof(IsRequired), out JsonNode? isRequiredToken)) { return false; } diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/BindSymbol.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/BindSymbol.cs index 880a43d702d..49f8ba92270 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/BindSymbol.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/BindSymbol.cs @@ -1,8 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json.Nodes; using Microsoft.TemplateEngine.Utils; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ConfigModel { @@ -23,7 +23,7 @@ internal BindSymbol(string name, string binding) : base(name, null) Binding = binding; } - internal BindSymbol(string name, JObject jObject) : base(jObject, name) + internal BindSymbol(string name, JsonObject jObject) : base(jObject, name) { string? binding = jObject.ToString(nameof(Binding)); if (string.IsNullOrWhiteSpace(binding)) diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/ComputedSymbol.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/ComputedSymbol.cs index a05df4586f9..59b326f0f6f 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/ComputedSymbol.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/ComputedSymbol.cs @@ -1,8 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json.Nodes; using Microsoft.TemplateEngine.Utils; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ConfigModel { @@ -23,7 +23,7 @@ internal ComputedSymbol(string name, string value) : base(name) Value = value; } - internal ComputedSymbol(string name, JObject jObject) : base(name) + internal ComputedSymbol(string name, JsonObject jObject) : base(name) { string? value = jObject.ToString(nameof(Value)); if (string.IsNullOrWhiteSpace(value)) diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/CustomFileGlobModel.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/CustomFileGlobModel.cs index 91afdfb31bf..002cf601284 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/CustomFileGlobModel.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/CustomFileGlobModel.cs @@ -1,8 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json.Nodes; using Microsoft.TemplateEngine.Core.Contracts; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ConfigModel { @@ -37,15 +37,15 @@ internal CustomFileGlobModel(string glob, IReadOnlyList op /// internal IVariableConfig VariableFormat { get; } = VariableConfig.Default; - internal static CustomFileGlobModel FromJObject(JObject globData, string globName) + internal static CustomFileGlobModel FromJObject(JsonObject globData, string globName) { // setup the custom operations List customOpsForGlob = new List(); - if (globData.TryGetValue(nameof(Operations), StringComparison.OrdinalIgnoreCase, out JToken? operationData)) + if (globData.TryGetValue(nameof(Operations), out JsonNode? operationData)) { - foreach (JToken operationConfig in (JArray)operationData) + foreach (JsonNode? operationConfig in (JsonArray)operationData!) { - if (operationConfig is JObject obj) + if (operationConfig is JsonObject obj) { customOpsForGlob.Add(CustomOperationModel.FromJObject(obj)); } diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/CustomOperationModel.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/CustomOperationModel.cs index 3ed1547ef8c..6fe8f87c4b9 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/CustomOperationModel.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/CustomOperationModel.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using Newtonsoft.Json.Linq; +using System.Text.Json.Nodes; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ConfigModel { @@ -22,13 +22,13 @@ internal CustomOperationModel() { } /// public string? Configuration { get; internal init; } - internal static CustomOperationModel FromJObject(JObject jObject) + internal static CustomOperationModel FromJObject(JsonObject jObject) { CustomOperationModel model = new CustomOperationModel { Type = jObject.ToString(nameof(Type)), Condition = jObject.ToString(nameof(Condition)), - Configuration = jObject.Get(nameof(Configuration))?.ToString(), + Configuration = jObject.Get(nameof(Configuration))?.ToJsonString(), }; return model; diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/DerivedSymbol.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/DerivedSymbol.cs index 09d9e7d4381..31c3bcd4683 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/DerivedSymbol.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/DerivedSymbol.cs @@ -1,8 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json.Nodes; using Microsoft.TemplateEngine.Utils; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ConfigModel { @@ -29,7 +29,7 @@ internal DerivedSymbol(string name, string valueTransform, string valueSource, s ValueSource = valueSource; } - internal DerivedSymbol(string name, JObject jObject, string? defaultOverride) + internal DerivedSymbol(string name, JsonObject jObject, string? defaultOverride) : base(name, jObject, defaultOverride) { string? valueTransform = jObject.ToString(nameof(ValueTransform)); diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/ExtendedFileSource.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/ExtendedFileSource.cs index b48dd82470b..7c80e482031 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/ExtendedFileSource.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/ExtendedFileSource.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using Newtonsoft.Json.Linq; +using System.Text.Json.Nodes; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ConfigModel { @@ -54,7 +54,7 @@ internal ExtendedFileSource() { } /// public IReadOnlyList Modifiers { get; internal init; } = []; - internal static ExtendedFileSource FromJObject(JObject jObject) + internal static ExtendedFileSource FromJObject(JsonObject jObject) { List modifiers = new List(); ExtendedFileSource src = new ExtendedFileSource() @@ -63,13 +63,13 @@ internal static ExtendedFileSource FromJObject(JObject jObject) Exclude = jObject.ToStringReadOnlyList(nameof(Exclude)), Include = jObject.ToStringReadOnlyList(nameof(Include)), Condition = jObject.ToString(nameof(Condition)), - Rename = jObject.Get(nameof(Rename))?.ToStringDictionary().ToDictionary(x => x.Key, x => x.Value) ?? RenameDefaults, + Rename = jObject.Get(nameof(Rename))?.ToStringDictionary().ToDictionary(x => x.Key, x => x.Value) ?? RenameDefaults, Modifiers = modifiers, Source = jObject.ToString(nameof(Source)) ?? "./", Target = jObject.ToString(nameof(Target)) ?? "./" }; - foreach (JObject entry in jObject.Items(nameof(src.Modifiers))) + foreach (JsonObject entry in jObject.Items(nameof(src.Modifiers))) { SourceModifier modifier = new SourceModifier { @@ -77,7 +77,7 @@ internal static ExtendedFileSource FromJObject(JObject jObject) CopyOnly = entry.ToStringReadOnlyList(nameof(CopyOnly)), Exclude = entry.ToStringReadOnlyList(nameof(Exclude)), Include = entry.ToStringReadOnlyList(nameof(Include)), - Rename = entry.Get(nameof(Rename))?.ToStringDictionary().ToDictionary(x => x.Key, x => x.Value) ?? RenameDefaults, + Rename = entry.Get(nameof(Rename))?.ToStringDictionary().ToDictionary(x => x.Key, x => x.Value) ?? RenameDefaults, }; modifiers.Add(modifier); } diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/GeneratedSymbol.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/GeneratedSymbol.cs index 291621f5638..d6ab5bd2e59 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/GeneratedSymbol.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/GeneratedSymbol.cs @@ -1,9 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json.Nodes; using Microsoft.TemplateEngine.Orchestrator.RunnableProjects.Abstractions; using Microsoft.TemplateEngine.Utils; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ConfigModel { @@ -29,7 +29,7 @@ internal GeneratedSymbol(string name, string generator, IReadOnlyDictionary diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/ParameterSymbol.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/ParameterSymbol.cs index 4127cec846a..153ebdd936c 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/ParameterSymbol.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/ParameterSymbol.cs @@ -1,9 +1,10 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json; +using System.Text.Json.Nodes; using Microsoft.TemplateEngine.Abstractions; using Microsoft.TemplateEngine.Utils; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ConfigModel { @@ -25,7 +26,7 @@ public sealed class ParameterSymbol : BaseValueSymbol /// /// JSON to initialize the symbol with. /// - internal ParameterSymbol(string name, JObject jObject, string? defaultOverride) + internal ParameterSymbol(string name, JsonObject jObject, string? defaultOverride) : base(name, jObject, defaultOverride, true) { DefaultIfOptionWithoutValue = jObject.ToString(nameof(DefaultIfOptionWithoutValue)); @@ -38,7 +39,7 @@ internal ParameterSymbol(string name, JObject jObject, string? defaultOverride) { TagName = jObject.ToString(nameof(TagName)); - foreach (JObject choiceObject in jObject.Items(nameof(Choices))) + foreach (JsonObject choiceObject in jObject.Items(nameof(Choices))) { string? choiceName = choiceObject.ToString("choice"); @@ -187,20 +188,20 @@ internal void Localize(IParameterSymbolLocalizationModel locModel) } - private static TemplateParameterPrecedence GetPrecedence(bool isRequired, JObject jObject) + private static TemplateParameterPrecedence GetPrecedence(bool isRequired, JsonObject jObject) { string? isRequiredCondition = ParseIsRequiredConditionField(jObject); // Initialize IsEnabled - as a condition or a constant string? isEnabledCondition = null; bool isEnabled = true; - if (jObject != null && jObject.TryGetValue("IsEnabled", StringComparison.OrdinalIgnoreCase, out JToken? isEnabledToken)) + if (jObject != null && jObject.TryGetValue("IsEnabled", out JsonNode? isEnabledToken)) { if (isEnabledToken!.TryParseBool(out bool enabledConst)) { isEnabled = enabledConst; } - else if (isEnabledToken.Type == JTokenType.String) + else if (isEnabledToken!.GetValueKind() == JsonValueKind.String) { isEnabledCondition = isEnabledToken.ToString(); } @@ -242,9 +243,9 @@ private static TemplateParameterPrecedence GetPrecedence(bool isRequired, bool i return TemplateParameterPrecedence.Default; } - private static string? ParseIsRequiredConditionField(JToken token) + private static string? ParseIsRequiredConditionField(JsonNode token) { - if (!token.TryGetValue(nameof(IsRequired), out JToken? isRequiredToken)) + if (!token.TryGetValue(nameof(IsRequired), out JsonNode? isRequiredToken)) { return null; } @@ -255,7 +256,7 @@ private static TemplateParameterPrecedence GetPrecedence(bool isRequired, bool i return null; } - if (isRequiredToken!.Type != JTokenType.String) + if (isRequiredToken!.GetValueKind() != JsonValueKind.String) { throw new ArgumentException(string.Format(LocalizableStrings.Symbol_Error_IsRequiredNotABoolOrString, isRequiredToken)); } diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/PostActionModel.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/PostActionModel.cs index 958dc603a76..a5842f41f9d 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/PostActionModel.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/PostActionModel.cs @@ -1,10 +1,10 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json.Nodes; using Microsoft.TemplateEngine.Abstractions; using Microsoft.TemplateEngine.Orchestrator.RunnableProjects.Localization; using Microsoft.TemplateEngine.Orchestrator.RunnableProjects.Validation; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ConfigModel { @@ -76,7 +76,7 @@ public string? Description /// public IReadOnlyList ManualInstructionInfo { get; internal init; } = new List(); - internal static IReadOnlyList LoadListFromJArray(JArray? jArray, List validationEntries) + internal static IReadOnlyList LoadListFromJArray(JsonArray? jArray, List validationEntries) { List localizedPostActions = new(); if (jArray == null) @@ -87,10 +87,10 @@ internal static IReadOnlyList LoadListFromJArray(JArray? jArray HashSet postActionIds = new(); for (int postActionIndex = 0; postActionIndex < jArray.Count; postActionIndex++) { - JToken action = jArray[postActionIndex]; + JsonNode? action = jArray[postActionIndex]; string? postActionId = action.ToString(nameof(Id)); string? description = action.ToString(nameof(Description)); - Guid actionId = action.ToGuid(nameof(ActionId)); + Guid actionId = action!.ToGuid(nameof(ActionId)); bool continueOnError = action.ToBool(nameof(ContinueOnError)); string? postActionCondition = action.ToString(nameof(Condition)); bool applyFileRenamesToManualInstructions = action.ToBool(nameof(ApplyFileRenamesToManualInstructions)); @@ -118,9 +118,9 @@ internal static IReadOnlyList LoadListFromJArray(JArray? jArray } Dictionary args = new Dictionary(StringComparer.OrdinalIgnoreCase); - foreach (JProperty argInfo in action.PropertiesOf("Args")) + foreach (var argInfo in action.PropertiesOf("Args")) { - args.Add(argInfo.Name, argInfo.Value.ToString()); + args.Add(argInfo.Key, argInfo.Value?.ToString() ?? string.Empty); } List verifiedApplyFileRenamesToArgs = new(); @@ -141,7 +141,7 @@ internal static IReadOnlyList LoadListFromJArray(JArray? jArray } } - IReadOnlyList manualInstructions = LoadManualInstructionsFromJArray(action.Get("ManualInstructions"), validationEntries); + IReadOnlyList manualInstructions = LoadManualInstructionsFromJArray(action.Get("ManualInstructions"), validationEntries); PostActionModel model = new(args, manualInstructions) { @@ -177,7 +177,7 @@ internal void Localize(PostActionLocalizationModel locModel) } } - private static IReadOnlyList LoadManualInstructionsFromJArray(JArray? jArray, List validationEntries) + private static IReadOnlyList LoadManualInstructionsFromJArray(JsonArray? jArray, List validationEntries) { var results = new List(); if (jArray == null) @@ -188,7 +188,7 @@ private static IReadOnlyList LoadManualInstructionsFromJ HashSet manualInstructionIds = new HashSet(); for (int i = 0; i < jArray.Count; i++) { - JToken jToken = jArray[i]; + JsonNode? jToken = jArray[i]; string? id = jToken.ToString("id"); string text = jToken.ToString("text") ?? string.Empty; string? condition = jToken.ToString("condition"); diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/PrimaryOutputModel.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/PrimaryOutputModel.cs index 3a791151afe..bd2129338e7 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/PrimaryOutputModel.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/PrimaryOutputModel.cs @@ -1,8 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json.Nodes; using Microsoft.TemplateEngine.Utils; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ConfigModel { @@ -27,7 +27,7 @@ internal PrimaryOutputModel(string path) /// public string Path { get; } - internal static IReadOnlyList ListFromJArray(JArray? jsonData) + internal static IReadOnlyList ListFromJArray(JsonArray? jsonData) { List modelList = new List(); @@ -36,7 +36,7 @@ internal static IReadOnlyList ListFromJArray(JArray? jsonDat return modelList; } - foreach (JToken pathInfo in jsonData) + foreach (JsonNode? pathInfo in jsonData) { string? path = pathInfo.ToString(nameof(Path)); if (string.IsNullOrWhiteSpace(path)) diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/ReplacementContext.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/ReplacementContext.cs index be69f3f74a5..e6d430fe6c7 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/ReplacementContext.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/ReplacementContext.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using Newtonsoft.Json.Linq; +using System.Text.Json.Nodes; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ConfigModel { @@ -28,16 +28,16 @@ internal ReplacementContext(string? before, string? after) /// public string? OnlyIfAfter { get; } - internal static IReadOnlyList FromJObject(JObject jObject) + internal static IReadOnlyList FromJObject(JsonObject jObject) { - JArray? onlyIf = jObject.Get("onlyIf"); + JsonArray? onlyIf = jObject.Get("onlyIf"); if (onlyIf != null) { List contexts = new List(); - foreach (JToken entry in onlyIf.Children()) + foreach (JsonNode? entry in onlyIf) { - if (entry is not JObject) + if (entry is not JsonObject) { continue; } diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/SymbolModelConverter.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/SymbolModelConverter.cs index 5f519aaea9e..45f905dd222 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/SymbolModelConverter.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/SymbolModelConverter.cs @@ -1,9 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json.Nodes; using Microsoft.Extensions.Logging; using Microsoft.TemplateEngine.Utils; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ConfigModel { @@ -11,7 +11,7 @@ internal sealed class SymbolModelConverter { // Note: Only ParameterSymbol has a Description property, this it's the only one that gets localization // TODO: change how localization gets merged in, don't do it here. - internal static BaseSymbol? GetModelForObject(string name, JObject jObject, ILogger? logger, string? defaultOverride) + internal static BaseSymbol? GetModelForObject(string name, JsonObject jObject, ILogger? logger, string? defaultOverride) { try { diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/SymbolValueFormsModel.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/SymbolValueFormsModel.cs index 7f8ec6fea4d..a26fa440d64 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/SymbolValueFormsModel.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/SymbolValueFormsModel.cs @@ -1,8 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json; +using System.Text.Json.Nodes; using Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ValueForms; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ConfigModel { @@ -29,42 +30,19 @@ internal SymbolValueFormsModel(IReadOnlyList globalForms) DefaultLowerSafeNamespaceValueFormFactory.FormIdentifier }); - // Sets up the value forms for a symbol, based on configuration from template.json - // There are two acceptable configuration formats for each forms specification. - // - // Note: in the examples below, "global" is used. But we'll be extending this to allow - // conditional forms, which will have other names. - // The same format will be used for other named form definitions. - // - // Simple: - // "forms": { - // "global": [ ] - // } - // - // Detailed: - // "forms" { - // "global": { - // "forms": [ ], - // "addIdentity": , - // // other future extensions, e.g. conditionals - // }, - // - // If the symbol doesn't include an "identity" form and the addIdentity flag isn't false, - // an identity specification is added to the beginning of the symbol's value form list. - // If there is an identity form listed, its position remains intact irrespective of the addIdentity flag. - internal static SymbolValueFormsModel FromJObject(JObject configJson) + internal static SymbolValueFormsModel FromJObject(JsonObject configJson) { - JToken? globalConfig = configJson.Property("global")?.Value; + JsonNode? globalConfig = JExtensions.GetPropertyCaseInsensitive(configJson, "global"); List globalForms; bool addIdentity; - if (globalConfig?.Type == JTokenType.Array) + if (globalConfig?.GetValueKind() == JsonValueKind.Array) { // config is just an array of form names. globalForms = globalConfig.ArrayAsStrings().ToList(); addIdentity = true; // default value } - else if (globalConfig?.Type == JTokenType.Object) + else if (globalConfig?.GetValueKind() == JsonValueKind.Object) { // config is an object. globalForms = globalConfig.ArrayAsStrings("forms").ToList(); diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/TemplateConfigModel.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/TemplateConfigModel.cs index 06a35b816f4..e85bd75a287 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/TemplateConfigModel.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ConfigModel/TemplateConfigModel.cs @@ -2,14 +2,13 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Runtime.InteropServices; +using System.Text.Json.Nodes; using Microsoft.Extensions.Logging; using Microsoft.TemplateEngine.Abstractions; using Microsoft.TemplateEngine.Abstractions.Constraints; using Microsoft.TemplateEngine.Orchestrator.RunnableProjects.Localization; using Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ValueForms; using Microsoft.TemplateEngine.Utils; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ConfigModel { @@ -45,7 +44,7 @@ internal TemplateConfigModel(string identity) Symbols = []; } - private TemplateConfigModel(JObject source, ILogger? logger, string? baselineName = null) + private TemplateConfigModel(JsonObject source, ILogger? logger, string? baselineName = null) { ILogger? logger1 = logger; @@ -78,7 +77,7 @@ private TemplateConfigModel(JObject source, ILogger? logger, string? baselineNam var sources = new List(); Sources = sources; - foreach (JObject item in source.Items(nameof(Sources))) + foreach (JsonObject item in source.Items(nameof(Sources))) { ExtendedFileSource src = ExtendedFileSource.FromJObject(item); sources.Add(src); @@ -107,13 +106,13 @@ private TemplateConfigModel(JObject source, ILogger? logger, string? baselineNam symbols[tagInfo.Key] = ParameterSymbol.FromDeprecatedConfigTag(tagInfo.Key, tagInfo.Value); } } - foreach (JProperty prop in source.PropertiesOf(nameof(Symbols))) + foreach (var prop in source.PropertiesOf(nameof(Symbols))) { - if (prop.Value is not JObject obj) + if (prop.Value is not JsonObject obj) { continue; } - if (string.IsNullOrWhiteSpace(prop.Name)) + if (string.IsNullOrWhiteSpace(prop.Key)) { continue; } @@ -121,26 +120,26 @@ private TemplateConfigModel(JObject source, ILogger? logger, string? baselineNam string? defaultOverride = null; if (baseline?.DefaultOverrides != null) { - baseline.DefaultOverrides.TryGetValue(prop.Name, out defaultOverride); + baseline.DefaultOverrides.TryGetValue(prop.Key, out defaultOverride); } - BaseSymbol? modelForSymbol = SymbolModelConverter.GetModelForObject(prop.Name, obj, logger, defaultOverride); + BaseSymbol? modelForSymbol = SymbolModelConverter.GetModelForObject(prop.Key, obj, logger, defaultOverride); if (modelForSymbol != null) { // The symbols dictionary comparer is Ordinal, making symbol names case-sensitive. - if (string.Equals(prop.Name, NameSymbolName, StringComparison.Ordinal) - && symbols.TryGetValue(prop.Name, out BaseSymbol existingSymbol) + if (string.Equals(prop.Key, NameSymbolName, StringComparison.Ordinal) + && symbols.TryGetValue(prop.Key, out BaseSymbol existingSymbol) && existingSymbol is ParameterSymbol existingParameterSymbol && modelForSymbol is ParameterSymbol modelForParameterSymbol) { // "name" symbol is explicitly defined above. If it's also defined in the template.json, it gets special handling here. - symbols[prop.Name] = new ParameterSymbol(modelForParameterSymbol, existingParameterSymbol.Forms); + symbols[prop.Key] = new ParameterSymbol(modelForParameterSymbol, existingParameterSymbol.Forms); } else { // last in wins (in the odd case where a template.json defined a symbol multiple times) - symbols[prop.Name] = modelForSymbol; + symbols[prop.Key] = modelForSymbol; } } } @@ -152,35 +151,35 @@ private TemplateConfigModel(JObject source, ILogger? logger, string? baselineNam } } _symbols = symbols; - _postActions = PostActionModel.LoadListFromJArray(source.Get("PostActions"), _validationEntries); - PrimaryOutputs = PrimaryOutputModel.ListFromJArray(source.Get(nameof(PrimaryOutputs))); + _postActions = PostActionModel.LoadListFromJArray(source.Get("PostActions"), _validationEntries); + PrimaryOutputs = PrimaryOutputModel.ListFromJArray(source.Get(nameof(PrimaryOutputs))); // Custom operations at the global level - JToken? globalCustomConfigData = source[nameof(GlobalCustomOperations)]; + JsonNode? globalCustomConfigData = JExtensions.GetPropertyCaseInsensitive(source, nameof(GlobalCustomOperations)); if (globalCustomConfigData != null) { - GlobalCustomOperations = CustomFileGlobModel.FromJObject((JObject)globalCustomConfigData, string.Empty); + GlobalCustomOperations = CustomFileGlobModel.FromJObject((JsonObject)globalCustomConfigData, string.Empty); } // Custom operations for specials - IReadOnlyDictionary allSpecialOpsConfig = source.ToJTokenDictionary(StringComparer.OrdinalIgnoreCase, nameof(SpecialCustomOperations)); + IReadOnlyDictionary allSpecialOpsConfig = source.ToJsonNodeDictionary(StringComparer.OrdinalIgnoreCase, nameof(SpecialCustomOperations)); List specialCustomSetup = new(); - foreach (KeyValuePair globConfigKeyValue in allSpecialOpsConfig) + foreach (KeyValuePair globConfigKeyValue in allSpecialOpsConfig) { string globName = globConfigKeyValue.Key; - JToken globData = globConfigKeyValue.Value; + JsonNode globData = globConfigKeyValue.Value; - CustomFileGlobModel globModel = CustomFileGlobModel.FromJObject((JObject)globData, globName); + CustomFileGlobModel globModel = CustomFileGlobModel.FromJObject((JsonObject)globData, globName); specialCustomSetup.Add(globModel); } SpecialCustomOperations = specialCustomSetup; List constraints = new(); - foreach (JProperty prop in source.PropertiesOf(nameof(Constraints))) + foreach (var prop in source.PropertiesOf(nameof(Constraints))) { - if (prop.Value is not JObject obj) + if (prop.Value is not JsonObject obj) { logger1?.LogWarning(LocalizableStrings.SimpleConfigModel_Error_Constraints_InvalidSyntax, nameof(Constraints).ToLowerInvariant()); continue; @@ -189,11 +188,11 @@ private TemplateConfigModel(JObject source, ILogger? logger, string? baselineNam string? type = obj.ToString(nameof(TemplateConstraintInfo.Type)); if (string.IsNullOrWhiteSpace(type)) { - logger1?.LogWarning(LocalizableStrings.SimpleConfigModel_Error_Constraints_MissingType, obj.ToString(), nameof(TemplateConstraintInfo.Type).ToLowerInvariant()); + logger1?.LogWarning(LocalizableStrings.SimpleConfigModel_Error_Constraints_MissingType, obj.ToJsonString(), nameof(TemplateConstraintInfo.Type).ToLowerInvariant()); continue; } - obj.TryGetValue(nameof(TemplateConstraintInfo.Args), StringComparison.OrdinalIgnoreCase, out JToken? args); - constraints.Add(new TemplateConstraintInfo(type!, args?.ToString(Formatting.None))); + obj.TryGetValue(nameof(TemplateConstraintInfo.Args), out JsonNode? args); + constraints.Add(new TemplateConstraintInfo(type!, args?.ToJsonString())); } Constraints = constraints; } @@ -431,11 +430,12 @@ public static TemplateConfigModel FromString(string content, ILogger? logger = n internal static TemplateConfigModel FromTextReader(TextReader content, ILogger? logger = null) { - using JsonReader r = new JsonTextReader(content); - return new TemplateConfigModel(JObject.Load(r), logger, null); + string json = content.ReadToEnd(); + JsonObject source = JExtensions.ParseJsonObject(json); + return new TemplateConfigModel(source, logger, null); } - internal static TemplateConfigModel FromJObject(JObject source, ILogger? logger = null, string? baselineName = null) + internal static TemplateConfigModel FromJObject(JsonObject source, ILogger? logger = null, string? baselineName = null) { return new TemplateConfigModel(source, logger, baselineName); } @@ -520,7 +520,7 @@ private static BaseSymbol SetupDefaultNameSymbol(string? sourceName) }; } - private static Dictionary SetupValueFormMapForTemplate(JObject? source = null) + private static Dictionary SetupValueFormMapForTemplate(JsonObject? source = null) { Dictionary formMap = new(StringComparer.Ordinal); @@ -539,11 +539,11 @@ private static Dictionary SetupValueFormMapForTemplate(JObje // setup the forms defined by the template configuration. // if any have the same name as a default, the default is overridden. - IReadOnlyDictionary templateDefinedForms = source.ToJTokenDictionary(StringComparer.OrdinalIgnoreCase, nameof(Forms)); + IReadOnlyDictionary templateDefinedForms = source.ToJsonNodeDictionary(StringComparer.OrdinalIgnoreCase, nameof(Forms)); - foreach (KeyValuePair form in templateDefinedForms) + foreach (KeyValuePair form in templateDefinedForms) { - if (form.Value is JObject o) + if (form.Value is JsonObject o) { formMap[form.Key] = ValueFormRegistry.GetForm(form.Key, o); } @@ -551,20 +551,20 @@ private static Dictionary SetupValueFormMapForTemplate(JObje return formMap; } - private static IReadOnlyDictionary BaselineInfoFromJObject(IEnumerable baselineJProperties) + private static IReadOnlyDictionary BaselineInfoFromJObject(IEnumerable> baselineProperties) { Dictionary allBaselines = new(); - foreach (JProperty property in baselineJProperties) + foreach (var property in baselineProperties) { - if (property.Value is not JObject obj) + if (property.Value is not JsonObject obj) { continue; } - IReadOnlyDictionary? defaultOverrides = obj.Get(nameof(Utils.BaselineInfo.DefaultOverrides))?.ToStringDictionary() ?? new Dictionary(); + IReadOnlyDictionary? defaultOverrides = obj.Get(nameof(Utils.BaselineInfo.DefaultOverrides))?.ToStringDictionary() ?? new Dictionary(); BaselineInfo baseline = new(defaultOverrides, obj.ToString(nameof(baseline.Description))); - allBaselines[property.Name] = baseline; + allBaselines[property.Key] = baseline; } return allBaselines; diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/DirectoryBasedTemplate.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/DirectoryBasedTemplate.cs index 438575cfe56..e547621644f 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/DirectoryBasedTemplate.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/DirectoryBasedTemplate.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Globalization; +using System.Text.Json.Nodes; using Microsoft.Extensions.Logging; using Microsoft.TemplateEngine.Abstractions; using Microsoft.TemplateEngine.Abstractions.Mount; @@ -9,7 +10,6 @@ using Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ConfigModel; using Microsoft.TemplateEngine.Orchestrator.RunnableProjects.Validation; using Microsoft.TemplateEngine.Utils; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects { @@ -157,7 +157,7 @@ internal Task ValidateAsync(ValidationScope scope, CancellationToken cancellatio /// Additional files must be in the same folder as the template file. /// /// when additional files configuration is invalid. - private static JObject MergeAdditionalConfiguration(JObject primarySource, IFileSystemInfo primarySourceConfig) + private static JsonObject MergeAdditionalConfiguration(JsonObject primarySource, IFileSystemInfo primarySourceConfig) { IReadOnlyList otherFiles = primarySource.ArrayAsStrings(AdditionalConfigFilesIndicator); @@ -166,7 +166,7 @@ private static JObject MergeAdditionalConfiguration(JObject primarySource, IFile return primarySource; } - JObject combinedSource = (JObject)primarySource.DeepClone(); + JsonObject combinedSource = primarySource.DeepCloneObject(); foreach (string partialConfigFileName in otherFiles) { @@ -181,7 +181,7 @@ private static JObject MergeAdditionalConfiguration(JObject primarySource, IFile LocalizableStrings.SimpleConfigModel_AuthoringException_MergeConfiguration_FileNotFound, partialConfigFileName), partialConfigFileName); - JObject partialConfigJson = partialConfigFile.ReadJObjectFromIFile(); + JsonObject partialConfigJson = partialConfigFile.ReadJObjectFromIFile(); combinedSource.Merge(partialConfigJson); } diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/LocalizationModelDeserializer.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/LocalizationModelDeserializer.cs index d9b45444d8c..abaf9937275 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/LocalizationModelDeserializer.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/LocalizationModelDeserializer.cs @@ -1,10 +1,10 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json; using Microsoft.TemplateEngine.Abstractions; using Microsoft.TemplateEngine.Abstractions.Mount; using Microsoft.TemplateEngine.Orchestrator.RunnableProjects.Localization; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects { @@ -26,10 +26,10 @@ public static LocalizationModel Deserialize(IFile file) { _ = file ?? throw new ArgumentNullException(nameof(file)); - JObject srcObject = file.ReadJObjectFromIFile(); + System.Text.Json.Nodes.JsonObject srcObject = file.ReadJObjectFromIFile(); - List<(string Key, string Value)> localizedStrings = srcObject.Properties() - .Select(p => p.Value.Type == JTokenType.String ? (p.Name, p.Value.ToString()) : throw new Exception(LocalizableStrings.Authoring_InvalidJsonElementInLocalizationFile)) + List<(string Key, string Value)> localizedStrings = srcObject + .Select(p => p.Value?.GetValueKind() == JsonValueKind.String ? (p.Key, p.Value.GetValue()) : throw new Exception(LocalizableStrings.Authoring_InvalidJsonElementInLocalizationFile)) .ToList(); var symbols = LoadSymbolModels(localizedStrings); diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/Macros/BaseMacroConfig.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/Macros/BaseMacroConfig.cs index 7dfda10fd30..71ce191c146 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/Macros/BaseMacroConfig.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/Macros/BaseMacroConfig.cs @@ -1,13 +1,14 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json; +using System.Text.Json.Nodes; using System.Text.RegularExpressions; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.TemplateEngine.Core; using Microsoft.TemplateEngine.Core.Expressions.Cpp2; using Microsoft.TemplateEngine.Orchestrator.RunnableProjects.Abstractions; using Microsoft.TemplateEngine.Utils; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.Macros { @@ -84,8 +85,8 @@ protected static bool ConvertJTokenToBool(string token, IGeneratedSymbolConfig c { try { - var jToken = JToken.Parse(token); - if (jToken.TryParseBool(out bool result)) + var jToken = JExtensions.ParseJsonNode(token); + if (jToken != null && jToken.TryParseBool(out bool result)) { return result; } @@ -101,8 +102,8 @@ protected static int ConvertJTokenToInt(string token, IGeneratedSymbolConfig con { try { - var jToken = JToken.Parse(token); - if (jToken.TryParseInt(out int result)) + var jToken = JExtensions.ParseJsonNode(token); + if (jToken != null && jToken.TryParseInt(out int result)) { return result; } @@ -118,12 +119,12 @@ protected static string ConvertJTokenToString(string token, IGeneratedSymbolConf { try { - var jToken = JToken.Parse(token); - if (jToken is not JValue val) + var jToken = JExtensions.ParseJsonNode(token); + if (jToken is not JsonValue val) { throw new TemplateAuthoringException(string.Format(LocalizableStrings.MacroConfig_Exception_ValueShouldBeString, config.VariableName, parameterName), config.VariableName); } - return val.ToString(); + return val.GetValueKind() == JsonValueKind.String ? val.GetValue() : val.ToJsonString(); } catch (Exception ex) when (ex is not TemplateAuthoringException) { @@ -131,16 +132,16 @@ protected static string ConvertJTokenToString(string token, IGeneratedSymbolConf } } - protected static JArray ConvertJTokenToJArray(string token, IGeneratedSymbolConfig config, string parameterName) + protected static JsonArray ConvertJTokenToJArray(string token, IGeneratedSymbolConfig config, string parameterName) { try { - var jToken = JToken.Parse(token); - if (jToken.Type != JTokenType.Array) + var jToken = JExtensions.ParseJsonNode(token); + if (jToken == null || jToken.GetValueKind() != JsonValueKind.Array) { throw new TemplateAuthoringException(string.Format(LocalizableStrings.MacroConfig_Exception_ValueShouldBeArray, config.VariableName, parameterName), config.VariableName); } - return (JArray)jToken; + return (JsonArray)jToken; } catch (Exception ex) when (ex is not TemplateAuthoringException) { @@ -185,7 +186,7 @@ protected TVal GetMandatoryParameterValue(IGeneratedSymbolConfig config, s return converter(token, config, parameterName); } - protected JArray GetMandatoryParameterArray(IGeneratedSymbolConfig config, string parameterName) + protected JsonArray GetMandatoryParameterArray(IGeneratedSymbolConfig config, string parameterName) { if (!config.Parameters.TryGetValue(parameterName, out string token)) { diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/Macros/JoinMacroConfig.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/Macros/JoinMacroConfig.cs index baa2b89d7e0..485b2749c6e 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/Macros/JoinMacroConfig.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/Macros/JoinMacroConfig.cs @@ -1,9 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json.Nodes; using Microsoft.TemplateEngine.Orchestrator.RunnableProjects.Abstractions; using Microsoft.TemplateEngine.Utils; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.Macros { @@ -29,11 +29,11 @@ internal JoinMacroConfig(JoinMacro macro, IGeneratedSymbolConfig generatedSymbol List<(JoinType Type, string Value)> symbolsList = new(); - JArray jArray = GetMandatoryParameterArray(generatedSymbolConfig, SymbolsPropertyName); + JsonArray jArray = GetMandatoryParameterArray(generatedSymbolConfig, SymbolsPropertyName); - foreach (JToken entry in jArray) + foreach (JsonNode? entry in jArray) { - if (entry is not JObject jObj) + if (entry is not JsonObject jObj) { throw new TemplateAuthoringException(string.Format(LocalizableStrings.MacroConfig_Exception_ArrayShouldContainObjects, generatedSymbolConfig.VariableName, SymbolsPropertyName), generatedSymbolConfig.VariableName); } diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/Macros/RegexMacroConfig.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/Macros/RegexMacroConfig.cs index fc8792bacac..5f8d27b14ec 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/Macros/RegexMacroConfig.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/Macros/RegexMacroConfig.cs @@ -1,9 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json.Nodes; using Microsoft.TemplateEngine.Orchestrator.RunnableProjects.Abstractions; using Microsoft.TemplateEngine.Utils; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.Macros { @@ -31,11 +31,11 @@ internal RegexMacroConfig(RegexMacro macro, IGeneratedSymbolConfig generatedSymb Source = GetMandatoryParameterValue(generatedSymbolConfig, "source"); List<(string Type, string Value)> steps = new(); - JArray jArray = GetMandatoryParameterArray(generatedSymbolConfig, StepsPropertyName); + JsonArray jArray = GetMandatoryParameterArray(generatedSymbolConfig, StepsPropertyName); - foreach (JToken entry in jArray) + foreach (JsonNode? entry in jArray) { - if (entry is not JObject jObj) + if (entry is not JsonObject jObj) { throw new TemplateAuthoringException(string.Format(LocalizableStrings.MacroConfig_Exception_ArrayShouldContainObjects, generatedSymbolConfig.VariableName, StepsPropertyName), generatedSymbolConfig.VariableName); } diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/Macros/SwitchMacroConfig.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/Macros/SwitchMacroConfig.cs index df256725ef1..8e82ffe796b 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/Macros/SwitchMacroConfig.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/Macros/SwitchMacroConfig.cs @@ -1,9 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json.Nodes; using Microsoft.TemplateEngine.Orchestrator.RunnableProjects.Abstractions; using Microsoft.TemplateEngine.Utils; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.Macros { @@ -30,11 +30,11 @@ internal SwitchMacroConfig(SwitchMacro macro, IGeneratedSymbolConfig generatedSy Evaluator = EvaluatorSelector.SelectStringEvaluator(EvaluatorSelector.ParseEvaluatorName(evaluator, DefaultEvaluator)); } List<(string? Condition, string Value)> cases = new(); - JArray jArray = GetMandatoryParameterArray(generatedSymbolConfig, CasesPropertyName); + JsonArray jArray = GetMandatoryParameterArray(generatedSymbolConfig, CasesPropertyName); - foreach (JToken entry in jArray) + foreach (JsonNode? entry in jArray) { - if (entry is not JObject jObj) + if (entry is not JsonObject jObj) { throw new TemplateAuthoringException(string.Format(LocalizableStrings.MacroConfig_Exception_ArrayShouldContainObjects, generatedSymbolConfig.VariableName, CasesPropertyName), generatedSymbolConfig.VariableName); } diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.csproj b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.csproj index c85ab5ebc04..79dab3bba05 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.csproj +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.csproj @@ -23,7 +23,7 @@ - + diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/BalancedNestingConfig.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/BalancedNestingConfig.cs index 6aa866e2b6a..d64a25a83d2 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/BalancedNestingConfig.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/BalancedNestingConfig.cs @@ -1,12 +1,12 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json.Nodes; using Microsoft.TemplateEngine.Abstractions.Mount; using Microsoft.TemplateEngine.Core; using Microsoft.TemplateEngine.Core.Contracts; using Microsoft.TemplateEngine.Core.Operations; using Microsoft.TemplateEngine.Orchestrator.RunnableProjects.Abstractions; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.OperationConfig { @@ -18,7 +18,7 @@ internal class BalancedNestingConfig : IOperationConfig public IEnumerable ConfigureFromJson(string configuration, IDirectory templateRoot) { - JObject rawConfiguration = JObject.Parse(configuration); + JsonObject rawConfiguration = JExtensions.ParseJsonObject(configuration); string? startToken = rawConfiguration.ToString("startToken"); string? realEndToken = rawConfiguration.ToString("realEndToken"); string? pseudoEndToken = rawConfiguration.ToString("pseudoEndToken"); @@ -29,9 +29,9 @@ public IEnumerable ConfigureFromJson(string configuration, I yield return new BalancedNesting(startToken.TokenConfig(), realEndToken.TokenConfig(), pseudoEndToken.TokenConfig(), id, resetFlag, onByDefault); } - internal static JObject CreateConfiguration(string startToken, string realEndToken, string pseudoEndToken, string id, string resetFlag) + internal static JsonObject CreateConfiguration(string startToken, string realEndToken, string pseudoEndToken, string id, string resetFlag) { - JObject config = new JObject + JsonObject config = new JsonObject { ["startToken"] = startToken, ["realEndToken"] = realEndToken, diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/ConditionalBlockCommentConfig.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/ConditionalBlockCommentConfig.cs index e7690085e06..31e4f3d2dda 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/ConditionalBlockCommentConfig.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/ConditionalBlockCommentConfig.cs @@ -1,17 +1,17 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json.Nodes; using Microsoft.TemplateEngine.Core; using Microsoft.TemplateEngine.Core.Contracts; using Microsoft.TemplateEngine.Core.Operations; using Microsoft.TemplateEngine.Utils; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.OperationConfig { internal static class ConditionalBlockCommentConfig { - internal static List ConfigureFromJObject(JObject rawConfiguration) + internal static List ConfigureFromJObject(JsonObject rawConfiguration) { string? startToken = rawConfiguration.ToString("startToken"); string? endToken = rawConfiguration.ToString("endToken"); diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/ConditionalConfig.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/ConditionalConfig.cs index cdd90807f15..193519a829a 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/ConditionalConfig.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/ConditionalConfig.cs @@ -1,13 +1,13 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json.Nodes; using Microsoft.TemplateEngine.Abstractions.Mount; using Microsoft.TemplateEngine.Core; using Microsoft.TemplateEngine.Core.Contracts; using Microsoft.TemplateEngine.Core.Operations; using Microsoft.TemplateEngine.Orchestrator.RunnableProjects.Abstractions; using Microsoft.TemplateEngine.Utils; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.OperationConfig { @@ -19,7 +19,7 @@ internal class ConditionalConfig : IOperationConfig public IEnumerable ConfigureFromJson(string configuration, IDirectory templateRoot) { - JObject rawConfiguration = JObject.Parse(configuration); + JsonObject rawConfiguration = JExtensions.ParseJsonObject(configuration); string? commentStyle = rawConfiguration.ToString("style"); IEnumerable operations = string.IsNullOrEmpty(commentStyle) || string.Equals(commentStyle, "custom", StringComparison.OrdinalIgnoreCase) ? ConditionalCustomConfig.ConfigureFromJObject(rawConfiguration) diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/ConditionalCustomConfig.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/ConditionalCustomConfig.cs index e3bc5cbedf5..9926aa08477 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/ConditionalCustomConfig.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/ConditionalCustomConfig.cs @@ -1,16 +1,16 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json.Nodes; using Microsoft.TemplateEngine.Core; using Microsoft.TemplateEngine.Core.Contracts; using Microsoft.TemplateEngine.Core.Operations; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.OperationConfig { internal static class ConditionalCustomConfig { - internal static List ConfigureFromJObject(JObject rawConfiguration) + internal static List ConfigureFromJObject(JsonObject rawConfiguration) { IReadOnlyList ifToken = rawConfiguration.ArrayAsStrings("if"); IReadOnlyList elseToken = rawConfiguration.ArrayAsStrings("else"); diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/ConditionalKeywords.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/ConditionalKeywords.cs index 9989aa22014..cb0ba067129 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/ConditionalKeywords.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/ConditionalKeywords.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using Newtonsoft.Json.Linq; +using System.Text.Json.Nodes; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.OperationConfig { @@ -34,7 +34,7 @@ internal ConditionalKeywords() // TODO: Allow the rawConfiguration elements to be either strings (as-is) or arrays of strings. // The code that consumes instances of this class is already setup to deal with multiple forms of each keyword type. - internal static ConditionalKeywords FromJObject(JObject rawConfiguration) + internal static ConditionalKeywords FromJObject(JsonObject rawConfiguration) { ConditionalKeywords keywords = new ConditionalKeywords(); string? ifKeyword = rawConfiguration.ToString("ifKeyword"); diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/ConditionalLineCommentConfig.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/ConditionalLineCommentConfig.cs index 932874e4f84..88ba8aedd88 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/ConditionalLineCommentConfig.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/ConditionalLineCommentConfig.cs @@ -1,17 +1,17 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json.Nodes; using Microsoft.TemplateEngine.Core; using Microsoft.TemplateEngine.Core.Contracts; using Microsoft.TemplateEngine.Core.Operations; using Microsoft.TemplateEngine.Utils; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.OperationConfig { internal static class ConditionalLineCommentConfig { - internal static List ConfigureFromJObject(JObject rawConfiguration) + internal static List ConfigureFromJObject(JsonObject rawConfiguration) { string? token = rawConfiguration.ToString("token"); diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/ConditionalOperationOptions.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/ConditionalOperationOptions.cs index 3c2886a693c..0033424d020 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/ConditionalOperationOptions.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/ConditionalOperationOptions.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using Newtonsoft.Json.Linq; +using System.Text.Json.Nodes; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.OperationConfig { @@ -28,7 +28,7 @@ internal ConditionalOperationOptions() internal bool OnByDefault { get; set; } - internal static ConditionalOperationOptions FromJObject(JObject rawConfiguration) + internal static ConditionalOperationOptions FromJObject(JsonObject rawConfiguration) { ConditionalOperationOptions options = new ConditionalOperationOptions(); diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/FlagsConfig.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/FlagsConfig.cs index 413acce85d9..f741de589d7 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/FlagsConfig.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/FlagsConfig.cs @@ -1,12 +1,12 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json.Nodes; using Microsoft.TemplateEngine.Abstractions.Mount; using Microsoft.TemplateEngine.Core; using Microsoft.TemplateEngine.Core.Contracts; using Microsoft.TemplateEngine.Core.Operations; using Microsoft.TemplateEngine.Orchestrator.RunnableProjects.Abstractions; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.OperationConfig { @@ -25,7 +25,7 @@ internal class FlagsConfig : IOperationConfig public IEnumerable ConfigureFromJson(string configuration, IDirectory templateRoot) { - JObject rawConfiguration = JObject.Parse(configuration); + JsonObject rawConfiguration = JExtensions.ParseJsonObject(configuration); string? flag = rawConfiguration.ToString("name"); string on = rawConfiguration.ToString("on") ?? string.Empty; string off = rawConfiguration.ToString("off") ?? string.Empty; diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/IncludeConfig.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/IncludeConfig.cs index 09bfbec4e83..1a120f9bea4 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/IncludeConfig.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/IncludeConfig.cs @@ -1,13 +1,13 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json.Nodes; using Microsoft.TemplateEngine.Abstractions.Mount; using Microsoft.TemplateEngine.Core; using Microsoft.TemplateEngine.Core.Contracts; using Microsoft.TemplateEngine.Core.Operations; using Microsoft.TemplateEngine.Orchestrator.RunnableProjects.Abstractions; using Microsoft.TemplateEngine.Utils; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.OperationConfig { @@ -19,7 +19,7 @@ internal class IncludeConfig : IOperationConfig public IEnumerable ConfigureFromJson(string configuration, IDirectory templateRoot) { - JObject rawConfiguration = JObject.Parse(configuration); + JsonObject rawConfiguration = JExtensions.ParseJsonObject(configuration); string? startToken = rawConfiguration.ToString("start"); string? endToken = rawConfiguration.ToString("end"); string? id = rawConfiguration.ToString("id"); diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/RegionConfig.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/RegionConfig.cs index 23ab8774482..18ed46bf2be 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/RegionConfig.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/RegionConfig.cs @@ -1,12 +1,12 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json.Nodes; using Microsoft.TemplateEngine.Abstractions.Mount; using Microsoft.TemplateEngine.Core; using Microsoft.TemplateEngine.Core.Contracts; using Microsoft.TemplateEngine.Core.Operations; using Microsoft.TemplateEngine.Orchestrator.RunnableProjects.Abstractions; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.OperationConfig { @@ -18,7 +18,7 @@ internal class RegionConfig : IOperationConfig public IEnumerable ConfigureFromJson(string configuration, IDirectory templateRoot) { - JObject rawConfiguration = JObject.Parse(configuration); + JsonObject rawConfiguration = JExtensions.ParseJsonObject(configuration); string? id = rawConfiguration.ToString("id"); string? start = rawConfiguration.ToString("start"); string? end = rawConfiguration.ToString("end"); diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/ReplacementConfig.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/ReplacementConfig.cs index 1682d2211ec..0aac579badd 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/ReplacementConfig.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/OperationConfig/ReplacementConfig.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json.Nodes; using Microsoft.Extensions.Logging; using Microsoft.TemplateEngine.Abstractions; using Microsoft.TemplateEngine.Abstractions.Mount; @@ -8,7 +9,6 @@ using Microsoft.TemplateEngine.Core.Contracts; using Microsoft.TemplateEngine.Core.Operations; using Microsoft.TemplateEngine.Orchestrator.RunnableProjects.Abstractions; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.OperationConfig { @@ -20,20 +20,20 @@ internal class ReplacementConfig : IOperationConfig public IEnumerable ConfigureFromJson(string configuration, IDirectory templateRoot) { - JObject rawConfiguration = JObject.Parse(configuration); + JsonObject rawConfiguration = JExtensions.ParseJsonObject(configuration); string? original = rawConfiguration.ToString("original"); string? replacement = rawConfiguration.ToString("replacement"); string? id = rawConfiguration.ToString("id"); bool onByDefault = rawConfiguration.ToBool("onByDefault"); - JArray? onlyIf = rawConfiguration.Get("onlyIf"); + JsonArray? onlyIf = rawConfiguration.Get("onlyIf"); TokenConfig coreConfig = original.TokenConfigBuilder(); if (onlyIf != null) { - foreach (JToken entry in onlyIf.Children()) + foreach (JsonNode? entry in onlyIf) { - if (entry is not JObject) + if (entry is not JsonObject) { continue; } diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ValueFormRegistry.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ValueFormRegistry.cs index 95b9c2e7251..13356b71ff5 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ValueFormRegistry.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ValueFormRegistry.cs @@ -1,8 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json.Nodes; using Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ValueForms; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects { @@ -36,7 +36,7 @@ internal static class ValueFormRegistry internal static IReadOnlyDictionary FormLookup => AllForms.ToDictionary(ff => ff.Identifier, ff => ff, StringComparer.OrdinalIgnoreCase); - internal static IValueForm GetForm(string name, JObject? obj) + internal static IValueForm GetForm(string name, JsonObject? obj) { string? identifier = obj.ToString("identifier"); diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ValueForms/ActionableValueFormFactory.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ValueForms/ActionableValueFormFactory.cs index d88dd60575f..c63f5d440dd 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ValueForms/ActionableValueFormFactory.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ValueForms/ActionableValueFormFactory.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using Newtonsoft.Json.Linq; +using System.Text.Json.Nodes; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ValueForms { @@ -12,7 +12,7 @@ internal abstract class ActionableValueFormFactory : BaseValueFormFactory { protected ActionableValueFormFactory(string identifier) : base(identifier) { } - public override IValueForm FromJObject(string name, JObject? configuration = null) + public override IValueForm FromJObject(string name, JsonObject? configuration = null) { return new ActionableValueForm(name, this); } diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ValueForms/BaseValueFormFactory.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ValueForms/BaseValueFormFactory.cs index ccd721b547a..a0e236ad97b 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ValueForms/BaseValueFormFactory.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ValueForms/BaseValueFormFactory.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using Newtonsoft.Json.Linq; +using System.Text.Json.Nodes; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ValueForms { @@ -24,7 +24,7 @@ protected BaseValueFormFactory(string identifier) public abstract IValueForm Create(string? name = null); - public abstract IValueForm FromJObject(string name, JObject? configuration = null); + public abstract IValueForm FromJObject(string name, JsonObject? configuration = null); protected abstract class BaseValueForm : IValueForm { diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ValueForms/ChainValueFormFactory.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ValueForms/ChainValueFormFactory.cs index 0a6eed43825..eabe5794d6d 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ValueForms/ChainValueFormFactory.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ValueForms/ChainValueFormFactory.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using Newtonsoft.Json.Linq; +using System.Text.Json.Nodes; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ValueForms { @@ -27,7 +27,7 @@ protected override string Process(string value, IReadOnlyList? steps, IR return result; } - protected override IReadOnlyList ReadConfiguration(JObject jObject) + protected override IReadOnlyList ReadConfiguration(JsonObject jObject) { return jObject.ArrayAsStrings("steps"); } diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ValueForms/ConfigurableValueFormFactory.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ValueForms/ConfigurableValueFormFactory.cs index f01570a0256..74a1575a7b4 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ValueForms/ConfigurableValueFormFactory.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ValueForms/ConfigurableValueFormFactory.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using Newtonsoft.Json.Linq; +using System.Text.Json.Nodes; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ValueForms { @@ -12,7 +12,7 @@ internal abstract class ConfigurableValueFormFactory : BaseValueFormFactory w { protected ConfigurableValueFormFactory(string identifier) : base(identifier) { } - public override IValueForm FromJObject(string name, JObject? configuration) + public override IValueForm FromJObject(string name, JsonObject? configuration) { if (configuration != null) { @@ -34,7 +34,7 @@ public override IValueForm Create(string? name = null) }; } - protected abstract T ReadConfiguration(JObject jObject); + protected abstract T ReadConfiguration(JsonObject jObject); protected abstract string Process(string value, T? configuration); diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ValueForms/DependentValueFormFactory.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ValueForms/DependentValueFormFactory.cs index 1ac8da24845..44004dd6f9b 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ValueForms/DependentValueFormFactory.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ValueForms/DependentValueFormFactory.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using Newtonsoft.Json.Linq; +using System.Text.Json.Nodes; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ValueForms { @@ -12,7 +12,7 @@ internal abstract class DependentValueFormFactory : BaseValueFormFactory wher { protected DependentValueFormFactory(string identifier) : base(identifier) { } - public override IValueForm FromJObject(string name, JObject? configuration) + public override IValueForm FromJObject(string name, JsonObject? configuration) { if (configuration != null) { @@ -34,7 +34,7 @@ public override IValueForm Create(string? name = null) }; } - protected abstract T ReadConfiguration(JObject jObject); + protected abstract T ReadConfiguration(JsonObject jObject); protected abstract string Process(string value, T? configuration, IReadOnlyDictionary otherForms); diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ValueForms/IValueForm.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ValueForms/IValueForm.cs index 9366ec4bcdd..7da1e20a63a 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ValueForms/IValueForm.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ValueForms/IValueForm.cs @@ -23,7 +23,7 @@ public interface IValueForm /// /// True is the form is a default implicit form. - /// See for more details. + /// See for more details. /// internal bool IsDefault { get; } diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ValueForms/IValueFormFactory.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ValueForms/IValueFormFactory.cs index 68895ccf1e2..1b48d798fac 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ValueForms/IValueFormFactory.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ValueForms/IValueFormFactory.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using Newtonsoft.Json.Linq; +using System.Text.Json.Nodes; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ValueForms { @@ -20,6 +20,6 @@ internal interface IValueFormFactory /// /// Creates the form from JSON configuration. /// - IValueForm FromJObject(string name, JObject? configuration = null); + IValueForm FromJObject(string name, JsonObject? configuration = null); } } diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ValueForms/JsonEncodeValueFormFactory.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ValueForms/JsonEncodeValueFormFactory.cs index 31661101fd7..95de03692b9 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ValueForms/JsonEncodeValueFormFactory.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ValueForms/JsonEncodeValueFormFactory.cs @@ -1,7 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using Newtonsoft.Json; +using System.Text.Encodings.Web; +using System.Text.Json; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ValueForms { @@ -9,11 +10,16 @@ internal class JsonEncodeValueFormFactory : ActionableValueFormFactory { internal const string FormIdentifier = "jsonEncode"; + private static readonly JsonSerializerOptions JsonEncodeOptions = new() + { + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping + }; + internal JsonEncodeValueFormFactory() : base(FormIdentifier) { } protected override string Process(string value) { - return JsonConvert.SerializeObject(value); + return JsonSerializer.Serialize(value, JsonEncodeOptions); } } } diff --git a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ValueForms/ReplacementValueFormFactory.cs b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ValueForms/ReplacementValueFormFactory.cs index 611a7ffe9b3..9c93ab683ba 100644 --- a/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ValueForms/ReplacementValueFormFactory.cs +++ b/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ValueForms/ReplacementValueFormFactory.cs @@ -1,8 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json.Nodes; using System.Text.RegularExpressions; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ValueForms { @@ -34,7 +34,7 @@ protected override string Process(string value, ReplacementValueFormSettings? co return configuration.Match.Replace(value, configuration.Replacement); } - protected override ReplacementValueFormSettings ReadConfiguration(JObject jObject) + protected override ReplacementValueFormSettings ReadConfiguration(JsonObject jObject) { return new ReplacementValueFormSettings(new Regex(jObject.ToString("pattern")), jObject.ToString("replacement")); } diff --git a/src/Microsoft.TemplateEngine.Utils/Microsoft.TemplateEngine.Utils.csproj b/src/Microsoft.TemplateEngine.Utils/Microsoft.TemplateEngine.Utils.csproj index b87aa437d62..7bfb6cc9f07 100644 --- a/src/Microsoft.TemplateEngine.Utils/Microsoft.TemplateEngine.Utils.csproj +++ b/src/Microsoft.TemplateEngine.Utils/Microsoft.TemplateEngine.Utils.csproj @@ -20,7 +20,7 @@ - + diff --git a/src/Microsoft.TemplateSearch.Common/Microsoft.TemplateSearch.Common.csproj b/src/Microsoft.TemplateSearch.Common/Microsoft.TemplateSearch.Common.csproj index c140fc324a6..80d70443282 100644 --- a/src/Microsoft.TemplateSearch.Common/Microsoft.TemplateSearch.Common.csproj +++ b/src/Microsoft.TemplateSearch.Common/Microsoft.TemplateSearch.Common.csproj @@ -20,7 +20,7 @@ - + diff --git a/src/Microsoft.TemplateSearch.Common/TemplateDiscoveryMetadata/BlobStorageTemplateInfo.cs b/src/Microsoft.TemplateSearch.Common/TemplateDiscoveryMetadata/BlobStorageTemplateInfo.cs index bcd57461605..bdecfd54df4 100644 --- a/src/Microsoft.TemplateSearch.Common/TemplateDiscoveryMetadata/BlobStorageTemplateInfo.cs +++ b/src/Microsoft.TemplateSearch.Common/TemplateDiscoveryMetadata/BlobStorageTemplateInfo.cs @@ -1,16 +1,16 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json; +using System.Text.Json.Nodes; +using System.Text.Json.Serialization; using Microsoft.TemplateEngine; using Microsoft.TemplateEngine.Abstractions; using Microsoft.TemplateEngine.Abstractions.Constraints; using Microsoft.TemplateEngine.Abstractions.Parameters; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateSearch.Common { - [JsonObject(Id = "TemplateInfo")] [Obsolete("The class is deprecated. Use TemplateSearchCache instead to create search cache data. Deserialization code to be moved to TemplateSearchData.Json.")] internal class BlobStorageTemplateInfo : ITemplateInfo { @@ -50,7 +50,7 @@ public BlobStorageTemplateInfo(ITemplateInfo templateInfo) PostActions = templateInfo.PostActions; } - [JsonConstructor] + [System.Text.Json.Serialization.JsonConstructor] private BlobStorageTemplateInfo(string identity, string name, IEnumerable shortNameList) { if (string.IsNullOrWhiteSpace(identity)) @@ -73,7 +73,7 @@ private BlobStorageTemplateInfo(string identity, string name, IEnumerable Parameters => ParameterDefinitions; [JsonIgnore] - string ITemplateLocator.MountPointUri => throw new NotImplementedException(); + string ITemplateLocator.MountPointUri => string.Empty; - [JsonProperty] public string? Author { get; private set; } - [JsonProperty] public IReadOnlyList Classifications { get; private set; } = new List(); [JsonIgnore] - public string DefaultName => throw new NotImplementedException(); + public string DefaultName => string.Empty; - [JsonProperty] public string? Description { get; private set; } - [JsonProperty] public string Identity { get; private set; } [JsonIgnore] - Guid ITemplateLocator.GeneratorId => throw new NotImplementedException(); + Guid ITemplateLocator.GeneratorId => Guid.Empty; - [JsonProperty] public string? GroupIdentity { get; private set; } - [JsonProperty] public int Precedence { get; private set; } - [JsonProperty] public string Name { get; private set; } [JsonIgnore] [Obsolete("Use ShortNameList instead.")] - string ITemplateInfo.ShortName => throw new NotImplementedException(); + string ITemplateInfo.ShortName => ShortNameList.Count > 0 ? ShortNameList[0] : string.Empty; - [JsonProperty] public IReadOnlyList ShortNameList { get; private set; } [JsonIgnore] @@ -130,41 +122,37 @@ private BlobStorageTemplateInfo(string identity, string name, IEnumerable CacheParameters { get; private set; } = new Dictionary(); [JsonIgnore] - string ITemplateLocator.ConfigPlace => throw new NotImplementedException(); + string ITemplateLocator.ConfigPlace => string.Empty; [JsonIgnore] - string IExtendedTemplateLocator.LocaleConfigPlace => throw new NotImplementedException(); + string IExtendedTemplateLocator.LocaleConfigPlace => string.Empty; [JsonIgnore] - string IExtendedTemplateLocator.HostConfigPlace => throw new NotImplementedException(); + string IExtendedTemplateLocator.HostConfigPlace => string.Empty; - [JsonProperty] public string? ThirdPartyNotices { get; private set; } - [JsonProperty] public IReadOnlyDictionary BaselineInfo { get; private set; } = new Dictionary(); [JsonIgnore] [Obsolete("This property is deprecated")] bool ITemplateInfo.HasScriptRunningPostActions { get; set; } - [JsonProperty] public IReadOnlyDictionary TagsCollection { get; private set; } = new Dictionary(); - [JsonProperty] public IReadOnlyList PostActions { get; private set; } = []; [JsonIgnore] - IReadOnlyList ITemplateMetadata.Constraints => throw new NotImplementedException(); + IReadOnlyList ITemplateMetadata.Constraints => []; - public static BlobStorageTemplateInfo FromJObject(JObject entry) + public static BlobStorageTemplateInfo FromJObject(JsonObject entry) { string identity = entry.ToString(nameof(Identity)) ?? throw new ArgumentException($"{nameof(entry)} doesn't have {nameof(Identity)} property.", nameof(entry)); string name = entry.ToString(nameof(Name)) ?? throw new ArgumentException($"{nameof(entry)} doesn't have {nameof(Name)} property.", nameof(entry)); - JToken? shortNameToken = entry.Get(nameof(ShortNameList)); + JsonNode? shortNameToken = entry.Get(nameof(ShortNameList)); IEnumerable shortNames = shortNameToken?.JTokenStringOrArrayToCollection([]) ?? throw new ArgumentException($"{nameof(entry)} doesn't have {nameof(ShortNameList)} property.", nameof(entry)); @@ -172,13 +160,13 @@ public static BlobStorageTemplateInfo FromJObject(JObject entry) { Author = entry.ToString(nameof(Author)) }; - JArray? classificationsArray = entry.Get(nameof(Classifications)); + JsonArray? classificationsArray = entry.Get(nameof(Classifications)); if (classificationsArray != null) { List classifications = new List(); - foreach (JToken item in classificationsArray) + foreach (JsonNode? item in classificationsArray) { - classifications.Add(item.ToString()); + classifications.Add(item?.ToString() ?? string.Empty); } info.Classifications = classifications; } @@ -187,29 +175,29 @@ public static BlobStorageTemplateInfo FromJObject(JObject entry) info.Precedence = entry.ToInt32(nameof(Precedence)); info.ThirdPartyNotices = entry.ToString(nameof(ThirdPartyNotices)); - JObject? baselineJObject = entry.Get(nameof(ITemplateInfo.BaselineInfo)); + JsonObject? baselineJObject = entry.Get(nameof(ITemplateInfo.BaselineInfo)); Dictionary baselineInfo = new Dictionary(); if (baselineJObject != null) { - foreach (JProperty item in baselineJObject.Properties()) + foreach (var item in baselineJObject) { IBaselineInfo baseline = new BaselineCacheInfo() { Description = item.Value.ToString(nameof(IBaselineInfo.Description)), - DefaultOverrides = item.Value.ToStringDictionary(propertyName: nameof(IBaselineInfo.DefaultOverrides)) + DefaultOverrides = item.Value?.ToStringDictionary(propertyName: nameof(IBaselineInfo.DefaultOverrides)) ?? new Dictionary() }; - baselineInfo.Add(item.Name, baseline); + baselineInfo.Add(item.Key, baseline); } info.BaselineInfo = baselineInfo; } - JArray? postActionsArray = entry.Get(nameof(info.PostActions)); + JsonArray? postActionsArray = entry.Get(nameof(info.PostActions)); if (postActionsArray != null) { List postActions = new List(); - foreach (JToken item in postActionsArray) + foreach (JsonNode? item in postActionsArray) { - if (Guid.TryParse(item.ToString(), out Guid id)) + if (Guid.TryParse(item?.ToString(), out Guid id)) { postActions.Add(id); } @@ -220,12 +208,12 @@ public static BlobStorageTemplateInfo FromJObject(JObject entry) //read parameters bool readParameters = false; List templateParameters = new List(); - JArray? parametersArray = entry.Get(nameof(Parameters)); + JsonArray? parametersArray = entry.Get(nameof(Parameters)); if (parametersArray != null) { - foreach (JToken item in parametersArray) + foreach (JsonNode? item in parametersArray) { - if (item is JObject jObj) + if (item is JsonObject jObj) { templateParameters.Add(new BlobTemplateParameter(jObj)); } @@ -233,27 +221,27 @@ public static BlobStorageTemplateInfo FromJObject(JObject entry) readParameters = true; } - JObject? tagsObject = entry.Get(nameof(TagsCollection)); + JsonObject? tagsObject = entry.Get(nameof(TagsCollection)); Dictionary tags = new Dictionary(); if (tagsObject != null) { - foreach (JProperty item in tagsObject.Properties()) + foreach (var item in tagsObject) { - tags.Add(item.Name.ToString(), item.Value.ToString()); + tags.Add(item.Key, item.Value?.ToString() ?? string.Empty); } } //try read tags and parameters - for compatibility reason - tagsObject = entry.Get("tags"); + tagsObject = entry.Get("tags"); if (tagsObject != null) { Dictionary legacyTags = new Dictionary(); - foreach (JProperty item in tagsObject.Properties()) + foreach (var item in tagsObject) { - if (item.Value.Type == JTokenType.String) + if (item.Value is JsonValue jv && jv.GetValueKind() == JsonValueKind.String) { - tags[item.Name.ToString()] = item.Value.ToString(); - legacyTags[item.Name.ToString()] = new BlobLegacyCacheTag( + tags[item.Key] = item.Value.ToString(); + legacyTags[item.Key] = new BlobLegacyCacheTag( description: null, choicesAndDescriptions: new Dictionary() { @@ -262,48 +250,47 @@ public static BlobStorageTemplateInfo FromJObject(JObject entry) defaultValue: item.Value.ToString(), defaultIfOptionWithoutValue: null); } - else if (item.Value is JObject tagObj) + else if (item.Value is JsonObject tagObj) { - JObject? choicesObject = tagObj.Get("ChoicesAndDescriptions"); + JsonObject? choicesObject = tagObj.Get("ChoicesAndDescriptions"); if (choicesObject != null && !readParameters) { Dictionary choicesAndDescriptions = new Dictionary(StringComparer.OrdinalIgnoreCase); Dictionary legacyChoices = new Dictionary(StringComparer.OrdinalIgnoreCase); - foreach (JProperty cdPair in choicesObject.Properties()) + foreach (var cdPair in choicesObject) { - choicesAndDescriptions[cdPair.Name.ToString()] = new ParameterChoice(null, cdPair.Value.ToString()); - legacyChoices[cdPair.Name.ToString()] = cdPair.Value.ToString(); + choicesAndDescriptions[cdPair.Key] = new ParameterChoice(null, cdPair.Value?.ToString() ?? string.Empty); + legacyChoices[cdPair.Key] = cdPair.Value?.ToString() ?? string.Empty; } templateParameters.Add( - new BlobTemplateParameter(item.Name.ToString(), "choice") + new BlobTemplateParameter(item.Key, "choice") { Choices = choicesAndDescriptions }); - legacyTags[item.Name.ToString()] = new BlobLegacyCacheTag( + legacyTags[item.Key] = new BlobLegacyCacheTag( description: tagObj.ToString("description"), choicesAndDescriptions: legacyChoices, defaultValue: tagObj.ToString("defaultValue"), defaultIfOptionWithoutValue: tagObj.ToString("defaultIfOptionWithoutValue")); } - tags[item.Name.ToString()] = tagObj.ToString("defaultValue") ?? string.Empty; + tags[item.Key] = tagObj.ToString("defaultValue") ?? string.Empty; } } info.Tags = legacyTags; } - JObject? cacheParametersObject = entry.Get("cacheParameters"); + JsonObject? cacheParametersObject = entry.Get("cacheParameters"); if (!readParameters && cacheParametersObject != null) { Dictionary legacyParams = new Dictionary(); - foreach (JProperty item in cacheParametersObject.Properties()) + foreach (var item in cacheParametersObject) { - JObject paramObj = (JObject)item.Value; - if (paramObj == null) + if (item.Value is not JsonObject paramObj) { continue; } string dataType = paramObj.ToString(nameof(BlobTemplateParameter.DataType)) ?? "string"; - templateParameters.Add(new BlobTemplateParameter(item.Name.ToString(), dataType)); - legacyParams[item.Name.ToString()] = new BlobLegacyCacheParameter( + templateParameters.Add(new BlobTemplateParameter(item.Key, dataType)); + legacyParams[item.Key] = new BlobLegacyCacheParameter( description: paramObj.ToString("description"), dataType: paramObj.ToString(nameof(BlobTemplateParameter.DataType)) ?? "string", defaultValue: paramObj.ToString("defaultValue"), @@ -320,10 +307,8 @@ public static BlobStorageTemplateInfo FromJObject(JObject entry) private class BaselineCacheInfo : IBaselineInfo { - [JsonProperty] public string? Description { get; set; } - [JsonProperty] public IReadOnlyDictionary DefaultOverrides { get; set; } = new Dictionary(); } @@ -362,7 +347,7 @@ internal BlobTemplateParameter(string name, string dataType) Precedence = TemplateParameterPrecedence.Default; } - internal BlobTemplateParameter(JObject jObject) + internal BlobTemplateParameter(JsonObject jObject) { string? name = jObject.ToString(nameof(Name)); if (string.IsNullOrWhiteSpace(name)) @@ -376,13 +361,13 @@ internal BlobTemplateParameter(JObject jObject) if (DataType.Equals("choice", StringComparison.OrdinalIgnoreCase)) { Dictionary choices = new Dictionary(StringComparer.OrdinalIgnoreCase); - JObject? cdToken = jObject.Get(nameof(Choices)); + JsonObject? cdToken = jObject.Get(nameof(Choices)); if (cdToken != null) { - foreach (JProperty cdPair in cdToken.Properties()) + foreach (var cdPair in cdToken) { choices.Add( - cdPair.Name.ToString(), + cdPair.Key, new ParameterChoice( cdPair.Value.ToString(nameof(ParameterChoice.DisplayName)), cdPair.Value.ToString(nameof(ParameterChoice.Description)))); @@ -399,13 +384,10 @@ internal BlobTemplateParameter(JObject jObject) Precedence = jObject.ToTemplateParameterPrecedence(nameof(Precedence)); } - [JsonProperty] public string Name { get; internal set; } - [JsonProperty] public string DataType { get; internal set; } - [JsonProperty] public IReadOnlyDictionary? Choices { get; internal set; } [JsonIgnore] @@ -422,23 +404,19 @@ internal BlobTemplateParameter(JObject jObject) [JsonIgnore] bool ITemplateParameter.IsName => false; - [JsonProperty] public string? DefaultValue { get; internal set; } [JsonIgnore] - string ITemplateParameter.DisplayName => throw new NotImplementedException(); + string ITemplateParameter.DisplayName => string.Empty; - [JsonProperty] public string? DefaultIfOptionWithoutValue { get; internal set; } - [JsonProperty] public string? Description { get; internal set; } [Obsolete] [JsonIgnore] - string ITemplateParameter.Documentation => throw new NotImplementedException(); + string ITemplateParameter.Documentation => string.Empty; - [JsonProperty] public bool AllowMultipleValues { get; internal set; } public override bool Equals(object obj) @@ -471,23 +449,19 @@ public BlobLegacyCacheTag(string? description, IReadOnlyDictionary ChoicesAndDescriptions { get; } - [JsonProperty] public string? DefaultValue { get; } - [JsonProperty] public string? DefaultIfOptionWithoutValue { get; } [JsonIgnore] - public string DisplayName => throw new NotImplementedException(); + public string DisplayName => string.Empty; [JsonIgnore] - public IReadOnlyDictionary Choices => throw new NotImplementedException(); + public IReadOnlyDictionary Choices => new Dictionary(); } @@ -501,20 +475,16 @@ public BlobLegacyCacheParameter(string? description, string? dataType, string? d DefaultIfOptionWithoutValue = defaultIfOptionWithoutValue; } - [JsonProperty] public string? DataType { get; } - [JsonProperty] public string? DefaultValue { get; } - [JsonProperty] public string? Description { get; } - [JsonProperty] public string? DefaultIfOptionWithoutValue { get; } [JsonIgnore] - public string DisplayName => throw new NotImplementedException(); + public string DisplayName => string.Empty; } } diff --git a/src/Microsoft.TemplateSearch.Common/TemplateDiscoveryMetadata/LegacySearchCacheReader.cs b/src/Microsoft.TemplateSearch.Common/TemplateDiscoveryMetadata/LegacySearchCacheReader.cs index ee6c1acd6c8..78b7f574cfd 100644 --- a/src/Microsoft.TemplateSearch.Common/TemplateDiscoveryMetadata/LegacySearchCacheReader.cs +++ b/src/Microsoft.TemplateSearch.Common/TemplateDiscoveryMetadata/LegacySearchCacheReader.cs @@ -2,9 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections; +using System.Text.Json; +using System.Text.Json.Nodes; using Microsoft.Extensions.Logging; +using Microsoft.TemplateEngine; using Microsoft.TemplateEngine.Abstractions; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateSearch.Common { @@ -56,12 +58,12 @@ internal static bool TryReadDiscoveryMetadata(IEngineEnvironmentSettings environ environmentSettings.Host.Logger.LogDebug($"Reading cache file {pathToConfig}"); string cacheText = environmentSettings.Host.FileSystem.ReadAllText(pathToConfig); - JObject cacheObject = JObject.Parse(cacheText); + JsonObject cacheObject = JExtensions.ParseJsonObject(cacheText); return TryReadDiscoveryMetadata(cacheObject, environmentSettings.Host.Logger, additionalDataReaders, out discoveryMetadata); } - internal static bool TryReadDiscoveryMetadata(JObject cacheObject, ILogger logger, IReadOnlyDictionary>? additionalDataReaders, out TemplateDiscoveryMetadata? discoveryMetadata) + internal static bool TryReadDiscoveryMetadata(JsonObject cacheObject, ILogger logger, IReadOnlyDictionary>? additionalDataReaders, out TemplateDiscoveryMetadata? discoveryMetadata) { // add the reader calls, build the model objects if (TryReadVersion(logger, cacheObject, out string? version) @@ -76,12 +78,12 @@ internal static bool TryReadDiscoveryMetadata(JObject cacheObject, ILogger logge return false; } - private static bool TryReadVersion(ILogger logger, JObject cacheObject, out string? version) + private static bool TryReadVersion(ILogger logger, JsonObject cacheObject, out string? version) { logger.LogDebug($"Reading template metadata version"); - if (cacheObject.TryGetValue(nameof(TemplateDiscoveryMetadata.Version), out JToken? value)) + if (cacheObject.TryGetValueCaseInsensitive(nameof(TemplateDiscoveryMetadata.Version), out JsonNode? value)) { - version = value.Value(); + version = value?.ToString(); logger.LogDebug($"Version: {version}."); return true; } @@ -92,26 +94,26 @@ private static bool TryReadVersion(ILogger logger, JObject cacheObject, out stri private static bool TryReadTemplateList( ILogger logger, - JObject cacheObject, + JsonObject cacheObject, out IReadOnlyList? templateList) { logger.LogDebug($"Reading template list"); try { // This is lifted from TemplateCache.ParseCacheContent - almost identical - if (cacheObject.TryGetValue(nameof(TemplateDiscoveryMetadata.TemplateCache), StringComparison.OrdinalIgnoreCase, out JToken? templateInfoToken)) + if (cacheObject.TryGetValueCaseInsensitive(nameof(TemplateDiscoveryMetadata.TemplateCache), out JsonNode? templateInfoToken)) { List buildingTemplateList = new List(); - if (templateInfoToken is JArray arr) + if (templateInfoToken is JsonArray arr) { - foreach (JToken entry in arr) + foreach (JsonNode? entry in arr) { - if (entry != null && entry.Type == JTokenType.Object) + if (entry is JsonObject entryObj) { try { - buildingTemplateList.Add(BlobStorageTemplateInfo.FromJObject((JObject)entry)); + buildingTemplateList.Add(BlobStorageTemplateInfo.FromJObject(entryObj)); } catch (ArgumentException ex) { @@ -138,13 +140,13 @@ private static bool TryReadTemplateList( } } - private static bool TryReadPackToTemplateMap(ILogger logger, JObject cacheObject, out IReadOnlyDictionary? packToTemplateMap) + private static bool TryReadPackToTemplateMap(ILogger logger, JsonObject cacheObject, out IReadOnlyDictionary? packToTemplateMap) { logger.LogDebug($"Reading package information."); try { - if (!cacheObject.TryGetValue(nameof(TemplateDiscoveryMetadata.PackToTemplateMap), out JToken? packToTemplateMapToken) - || packToTemplateMapToken is not JObject packToTemplateMapObject) + JsonNode? packToTemplateMapToken = JExtensions.GetPropertyCaseInsensitive(cacheObject, nameof(TemplateDiscoveryMetadata.PackToTemplateMap)); + if (packToTemplateMapToken is not JsonObject packToTemplateMapObject) { logger.LogDebug($"Failed to read package info entries. Details: no PackToTemplateMap property found."); packToTemplateMap = null; @@ -153,25 +155,25 @@ private static bool TryReadPackToTemplateMap(ILogger logger, JObject cacheObject Dictionary workingPackToTemplateMap = new(); - foreach (JProperty packEntry in packToTemplateMapObject.Properties()) + foreach (var packEntry in packToTemplateMapObject) { - if (packEntry != null) + if (packEntry.Value != null) { - string packName = packEntry.Name.ToString(); - JObject entryValue = (JObject)packEntry.Value; + string packName = packEntry.Key; + JsonObject entryValue = (JsonObject)packEntry.Value; - if (entryValue.TryGetValue(nameof(PackToTemplateEntry.Version), StringComparison.OrdinalIgnoreCase, out JToken? versionToken) - && versionToken.Type == JTokenType.String - && entryValue.TryGetValue(nameof(PackToTemplateEntry.TemplateIdentificationEntry), StringComparison.OrdinalIgnoreCase, out JToken? identificationToken) - && identificationToken is JArray identificationArray) + JsonNode? versionNode = JExtensions.GetPropertyCaseInsensitive(entryValue, nameof(PackToTemplateEntry.Version)); + JsonNode? identificationNode = JExtensions.GetPropertyCaseInsensitive(entryValue, nameof(PackToTemplateEntry.TemplateIdentificationEntry)); + if (versionNode is JsonValue versionVal && versionVal.GetValueKind() == JsonValueKind.String + && identificationNode is JsonArray identificationArray) { - string? version = versionToken.Value() ?? throw new Exception("Version value is null."); + string? version = versionNode.ToString() ?? throw new Exception("Version value is null."); List templatesInPack = new List(); - foreach (JToken templateIdentityInfo in identificationArray) + foreach (JsonNode? templateIdentityInfo in identificationArray) { - string? identity = templateIdentityInfo.Value(nameof(TemplateIdentificationEntry.Identity)); - string? groupIdentity = templateIdentityInfo.Value(nameof(TemplateIdentificationEntry.GroupIdentity)); + string? identity = templateIdentityInfo?.ToString(nameof(TemplateIdentificationEntry.Identity)); + string? groupIdentity = templateIdentityInfo?.ToString(nameof(TemplateIdentificationEntry.GroupIdentity)); if (identity == null) { @@ -182,8 +184,8 @@ private static bool TryReadPackToTemplateMap(ILogger logger, JObject cacheObject } workingPackToTemplateMap[packName] = new PackToTemplateEntry(version, templatesInPack); - if (entryValue.TryGetValue(nameof(PackToTemplateEntry.TotalDownloads), out JToken? totalDownloadsToken) - && long.TryParse(totalDownloadsToken.Value(), out long totalDownloads)) + if (entryValue.TryGetValueCaseInsensitive(nameof(PackToTemplateEntry.TotalDownloads), out JsonNode? totalDownloadsNode) + && long.TryParse(totalDownloadsNode?.ToString(), out long totalDownloads)) { workingPackToTemplateMap[packName].TotalDownloads = totalDownloads; } @@ -203,7 +205,7 @@ private static bool TryReadPackToTemplateMap(ILogger logger, JObject cacheObject } } - private static bool TryReadAdditionalData(ILogger logger, JObject cacheObject, IReadOnlyDictionary>? additionalDataReaders, out IReadOnlyDictionary? additionalData) + private static bool TryReadAdditionalData(ILogger logger, JsonObject cacheObject, IReadOnlyDictionary>? additionalDataReaders, out IReadOnlyDictionary? additionalData) { if (additionalDataReaders == null) { @@ -212,8 +214,8 @@ private static bool TryReadAdditionalData(ILogger logger, JObject cacheObject, I } logger.LogDebug($"Reading additional information."); // get the additional data section - if (!cacheObject.TryGetValue(nameof(TemplateDiscoveryMetadata.AdditionalData), out JToken? additionalDataToken) - || additionalDataToken is not JObject additionalDataObject) + JsonNode? additionalDataToken = JExtensions.GetPropertyCaseInsensitive(cacheObject, nameof(TemplateDiscoveryMetadata.AdditionalData)); + if (additionalDataToken is not JsonObject additionalDataObject) { logger.LogDebug($"Failed to read package info entries. Details: no AdditionalData property found."); additionalData = null; @@ -227,8 +229,8 @@ private static bool TryReadAdditionalData(ILogger logger, JObject cacheObject, I try { // get the entry for this piece of additional data - if (!additionalDataObject.TryGetValue(dataReadInfo.Key, StringComparison.OrdinalIgnoreCase, out JToken? dataToken) - || dataToken is not JObject dataObject) + JsonNode? dataNode = JExtensions.GetPropertyCaseInsensitive(additionalDataObject, dataReadInfo.Key); + if (dataNode is not JsonObject dataObject) { // this piece of data wasn't found, or wasn't valid. Ignore it. continue; diff --git a/src/Microsoft.TemplateSearch.Common/TemplateDiscoveryMetadata/PackInfo.cs b/src/Microsoft.TemplateSearch.Common/TemplateDiscoveryMetadata/PackInfo.cs index 9d0c1f4d1a5..deb6d88d979 100644 --- a/src/Microsoft.TemplateSearch.Common/TemplateDiscoveryMetadata/PackInfo.cs +++ b/src/Microsoft.TemplateSearch.Common/TemplateDiscoveryMetadata/PackInfo.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.TemplateSearch.Common.Abstractions; -using Newtonsoft.Json; namespace Microsoft.TemplateSearch.Common { @@ -24,19 +23,14 @@ internal PackInfo(string name, string version, long totalDownloads, IEnumerable< Reserved = reserved; } - [JsonProperty] public string Name { get; } - [JsonProperty] public string Version { get; } - [JsonProperty] public long TotalDownloads { get; } - [JsonProperty] public IReadOnlyList Owners { get; } = []; - [JsonProperty] public bool Reserved { get; } //not supported for v1 diff --git a/src/Microsoft.TemplateSearch.Common/TemplateDiscoveryMetadata/PackToTemplateEntry.cs b/src/Microsoft.TemplateSearch.Common/TemplateDiscoveryMetadata/PackToTemplateEntry.cs index 269095a0a45..1bc240a8957 100644 --- a/src/Microsoft.TemplateSearch.Common/TemplateDiscoveryMetadata/PackToTemplateEntry.cs +++ b/src/Microsoft.TemplateSearch.Common/TemplateDiscoveryMetadata/PackToTemplateEntry.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Microsoft.TemplateSearch.Common { @@ -14,19 +14,19 @@ internal PackToTemplateEntry(string version, List t TemplateIdentificationEntry = templateIdentificationEntry; } - [JsonProperty] + [JsonInclude] internal string Version { get; } - [JsonProperty] + [JsonInclude] internal long TotalDownloads { get; set; } - [JsonProperty] + [JsonInclude] internal IReadOnlyList Owners { get; set; } = []; - [JsonProperty] + [JsonInclude] internal bool Reserved { get; set; } - [JsonProperty] + [JsonInclude] internal IReadOnlyList TemplateIdentificationEntry { get; } } } diff --git a/src/Microsoft.TemplateSearch.Common/TemplateDiscoveryMetadata/TemplateDiscoveryMetadata.cs b/src/Microsoft.TemplateSearch.Common/TemplateDiscoveryMetadata/TemplateDiscoveryMetadata.cs index 0fe64655b97..b5e92825580 100644 --- a/src/Microsoft.TemplateSearch.Common/TemplateDiscoveryMetadata/TemplateDiscoveryMetadata.cs +++ b/src/Microsoft.TemplateSearch.Common/TemplateDiscoveryMetadata/TemplateDiscoveryMetadata.cs @@ -1,9 +1,10 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json.Nodes; +using System.Text.Json.Serialization; +using Microsoft.TemplateEngine; using Microsoft.TemplateEngine.Abstractions; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateSearch.Common { @@ -18,21 +19,21 @@ internal TemplateDiscoveryMetadata(string version, IReadOnlyList AdditionalData = additionalData; } - [JsonProperty] + [JsonInclude] internal string Version { get; } - [JsonProperty] + [JsonInclude] internal IReadOnlyList TemplateCache { get; } - [JsonProperty] + [JsonInclude] internal IReadOnlyDictionary PackToTemplateMap { get; } - [JsonProperty] + [JsonInclude] internal IReadOnlyDictionary AdditionalData { get; } - internal JObject ToJObject() + internal JsonObject ToJObject() { - return JObject.FromObject(this); + return JExtensions.FromObject(this); } } } diff --git a/src/Microsoft.TemplateSearch.Common/TemplateDiscoveryMetadata/TemplateIdentificationEntry.cs b/src/Microsoft.TemplateSearch.Common/TemplateDiscoveryMetadata/TemplateIdentificationEntry.cs index c8e54773e18..8a8ccdb4661 100644 --- a/src/Microsoft.TemplateSearch.Common/TemplateDiscoveryMetadata/TemplateIdentificationEntry.cs +++ b/src/Microsoft.TemplateSearch.Common/TemplateDiscoveryMetadata/TemplateIdentificationEntry.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Microsoft.TemplateSearch.Common { @@ -14,10 +14,10 @@ internal TemplateIdentificationEntry(string identity, string? groupIdentity) GroupIdentity = groupIdentity; } - [JsonProperty] + [JsonInclude] internal string Identity { get; } - [JsonProperty] + [JsonInclude] internal string? GroupIdentity { get; } } } diff --git a/src/Microsoft.TemplateSearch.Common/TemplateSearchCache/TemplatePackageSearchData.Json.cs b/src/Microsoft.TemplateSearch.Common/TemplateSearchCache/TemplatePackageSearchData.Json.cs index fb1a956737b..c2f1e14101e 100644 --- a/src/Microsoft.TemplateSearch.Common/TemplateSearchCache/TemplatePackageSearchData.Json.cs +++ b/src/Microsoft.TemplateSearch.Common/TemplateSearchCache/TemplatePackageSearchData.Json.cs @@ -1,17 +1,17 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json; +using System.Text.Json.Nodes; using Microsoft.Extensions.Logging; using Microsoft.TemplateEngine; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateSearch.Common { - [JsonConverter(typeof(TemplatePackageSearchDataJsonConverter))] + [System.Text.Json.Serialization.JsonConverter(typeof(TemplatePackageSearchDataJsonConverter))] public partial class TemplatePackageSearchData { - internal TemplatePackageSearchData(JObject jObject, ILogger logger, IReadOnlyDictionary>? additionalDataReaders = null) + internal TemplatePackageSearchData(JsonObject jObject, ILogger logger, IReadOnlyDictionary>? additionalDataReaders = null) { if (jObject is null) { @@ -27,20 +27,20 @@ internal TemplatePackageSearchData(JObject jObject, ILogger logger, IReadOnlyDic : throw new ArgumentException($"{nameof(jObject)} doesn't have {nameof(Name)} property or it is not a string.", nameof(jObject)); Version = jObject.ToString(nameof(Version)); TotalDownloads = jObject.ToInt32(nameof(TotalDownloads)); - Owners = jObject.Get(nameof(Owners)).JTokenStringOrArrayToCollection([]); + Owners = jObject.Get(nameof(Owners)).JTokenStringOrArrayToCollection([]); Reserved = jObject.ToBool(nameof(Reserved)); Description = jObject.ToString(nameof(Description)); IconUrl = jObject.ToString(nameof(IconUrl)); - JArray? templatesData = jObject.Get(nameof(Templates)) + JsonArray? templatesData = jObject.Get(nameof(Templates)) ?? throw new ArgumentException($"{nameof(jObject)} doesn't have {nameof(Templates)} property or it is not an array.", nameof(jObject)); List templates = new List(); - foreach (JToken template in templatesData) + foreach (JsonNode? template in templatesData) { try { - if (template is JObject templateObj) + if (template is JsonObject templateObj) { templates.Add(new TemplateSearchData(templateObj, logger, additionalDataReaders)); } @@ -62,12 +62,12 @@ internal TemplatePackageSearchData(JObject jObject, ILogger logger, IReadOnlyDic } #region JsonConverter - private class TemplatePackageSearchDataJsonConverter : JsonConverter + private class TemplatePackageSearchDataJsonConverter : System.Text.Json.Serialization.JsonConverter { - public override TemplatePackageSearchData ReadJson(JsonReader reader, Type objectType, TemplatePackageSearchData? existingValue, bool hasExistingValue, JsonSerializer serializer) + public override TemplatePackageSearchData Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => throw new NotImplementedException(); - public override void WriteJson(JsonWriter writer, TemplatePackageSearchData? value, JsonSerializer serializer) + public override void Write(Utf8JsonWriter writer, TemplatePackageSearchData value, JsonSerializerOptions options) { if (value == null) { @@ -75,30 +75,30 @@ public override void WriteJson(JsonWriter writer, TemplatePackageSearchData? val } writer.WriteStartObject(); writer.WritePropertyName(nameof(Name)); - writer.WriteValue(value.Name); + writer.WriteStringValue(value.Name); if (!string.IsNullOrWhiteSpace(value.Version)) { writer.WritePropertyName(nameof(Version)); - writer.WriteValue(value.Version); + writer.WriteStringValue(value.Version); } if (value.TotalDownloads != 0) { writer.WritePropertyName(nameof(TotalDownloads)); - writer.WriteValue(value.TotalDownloads); + writer.WriteNumberValue(value.TotalDownloads); } if (value.Owners.Any()) { writer.WritePropertyName(nameof(Owners)); if (value.Owners.Count == 1) { - writer.WriteValue(value.Owners[0]); + writer.WriteStringValue(value.Owners[0]); } else { writer.WriteStartArray(); foreach (string owner in value.Owners) { - writer.WriteValue(owner); + writer.WriteStringValue(owner); } writer.WriteEndArray(); } @@ -107,28 +107,28 @@ public override void WriteJson(JsonWriter writer, TemplatePackageSearchData? val if (value.Reserved) { writer.WritePropertyName(nameof(Reserved)); - writer.WriteValue(value.Reserved); + writer.WriteBooleanValue(value.Reserved); } if (!string.IsNullOrWhiteSpace(value.Description)) { writer.WritePropertyName(nameof(Description)); - writer.WriteValue(value.Description); + writer.WriteStringValue(value.Description); } if (!string.IsNullOrWhiteSpace(value.IconUrl)) { writer.WritePropertyName(nameof(IconUrl)); - writer.WriteValue(value.IconUrl); + writer.WriteStringValue(value.IconUrl); } writer.WritePropertyName(nameof(Templates)); - serializer.Serialize(writer, value.Templates); + JsonSerializer.Serialize(writer, value.Templates, options); if (value.AdditionalData.Any()) { foreach (var item in value.AdditionalData) { writer.WritePropertyName(item.Key); - serializer.Serialize(writer, item.Value); + JsonSerializer.Serialize(writer, item.Value, options); } } writer.WriteEndObject(); diff --git a/src/Microsoft.TemplateSearch.Common/TemplateSearchCache/TemplateSearchCache.Json.cs b/src/Microsoft.TemplateSearch.Common/TemplateSearchCache/TemplateSearchCache.Json.cs index ffea8ea8fbe..1bb26f57551 100644 --- a/src/Microsoft.TemplateSearch.Common/TemplateSearchCache/TemplateSearchCache.Json.cs +++ b/src/Microsoft.TemplateSearch.Common/TemplateSearchCache/TemplateSearchCache.Json.cs @@ -1,9 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json.Nodes; using Microsoft.Extensions.Logging; using Microsoft.TemplateEngine; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateSearch.Common { @@ -12,7 +12,7 @@ internal partial class TemplateSearchCache private static readonly string[] SupportedVersions = new[] { "1.0.0.0", "1.0.0.3", "2.0" }; internal static TemplateSearchCache FromJObject( - JObject cacheObject, + JsonObject cacheObject, ILogger logger, IReadOnlyDictionary>? additionalDataReaders = null) { @@ -46,14 +46,14 @@ internal static TemplateSearchCache FromJObject( } - JArray? data = cacheObject.Get(nameof(TemplatePackages)) + JsonArray? data = cacheObject.Get(nameof(TemplatePackages)) ?? throw new Exception(LocalizableStrings.TemplateSearchCache_Exception_NotValid); List templatePackages = new(); - foreach (JToken templatePackage in data) + foreach (JsonNode? templatePackage in data) { try { - if (templatePackage is not JObject templatePackageObj) + if (templatePackage is not JsonObject templatePackageObj) { throw new Exception($"Unexpected data in template search cache data, property: {nameof(TemplatePackages)}, value: {templatePackage}"); } @@ -68,15 +68,15 @@ internal static TemplateSearchCache FromJObject( } internal static IDictionary ReadAdditionalData( - JObject cacheObject, + JsonObject cacheObject, IReadOnlyDictionary> additionalDataReaders, ILogger logger) { Dictionary additionalData = new(StringComparer.OrdinalIgnoreCase); foreach (KeyValuePair> dataReadInfo in additionalDataReaders) { - if (!cacheObject.TryGetValue(dataReadInfo.Key, StringComparison.OrdinalIgnoreCase, out JToken? dataToken) - || dataToken is not JObject dataObject) + JsonNode? dataNode = JExtensions.GetPropertyCaseInsensitive(cacheObject, dataReadInfo.Key); + if (dataNode is not JsonObject dataObject) { // this piece of data wasn't found, or wasn't valid. Ignore it. continue; @@ -96,12 +96,12 @@ internal static IDictionary ReadAdditionalData( return additionalData; } - internal JObject ToJObject() + internal JsonObject ToJObject() { - return JObject.FromObject(this); + return JExtensions.FromObject(this); } - private static bool TryReadVersion(ILogger logger, JObject cacheObject, out string? version) + private static bool TryReadVersion(ILogger logger, JsonObject cacheObject, out string? version) { logger.LogDebug($"Reading template search cache version"); version = cacheObject.ToString(nameof(Version)); diff --git a/src/Microsoft.TemplateSearch.Common/TemplateSearchCache/TemplateSearchCache.cs b/src/Microsoft.TemplateSearch.Common/TemplateSearchCache/TemplateSearchCache.cs index 52de55a828c..1c71edb54c3 100644 --- a/src/Microsoft.TemplateSearch.Common/TemplateSearchCache/TemplateSearchCache.cs +++ b/src/Microsoft.TemplateSearch.Common/TemplateSearchCache/TemplateSearchCache.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using Newtonsoft.Json; +using System.Text.Json.Serialization; namespace Microsoft.TemplateSearch.Common { @@ -23,10 +23,10 @@ private TemplateSearchCache(IReadOnlyList data, strin Version = version; } - [JsonProperty] + [JsonInclude] internal IReadOnlyList TemplatePackages { get; } - [JsonProperty] + [JsonInclude] internal string Version { get; private set; } } } diff --git a/src/Microsoft.TemplateSearch.Common/TemplateSearchCache/TemplateSearchData.Json.cs b/src/Microsoft.TemplateSearch.Common/TemplateSearchCache/TemplateSearchData.Json.cs index 1aa8a403e8d..1c9d0a82bea 100644 --- a/src/Microsoft.TemplateSearch.Common/TemplateSearchCache/TemplateSearchData.Json.cs +++ b/src/Microsoft.TemplateSearch.Common/TemplateSearchCache/TemplateSearchData.Json.cs @@ -1,17 +1,17 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json; +using System.Text.Json.Nodes; using Microsoft.Extensions.Logging; using Microsoft.TemplateEngine.Abstractions; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateSearch.Common { - [JsonConverter(typeof(TemplateSearchData.TemplateSearchDataJsonConverter))] + [System.Text.Json.Serialization.JsonConverter(typeof(TemplateSearchData.TemplateSearchDataJsonConverter))] public partial class TemplateSearchData : ITemplateInfo { - internal TemplateSearchData(JObject jObject, ILogger logger, IReadOnlyDictionary>? additionalDataReaders = null) + internal TemplateSearchData(JsonObject jObject, ILogger logger, IReadOnlyDictionary>? additionalDataReaders = null) { if (jObject is null) { @@ -34,13 +34,13 @@ internal TemplateSearchData(JObject jObject, ILogger logger, IReadOnlyDictionary } #region JsonConverter - private class TemplateSearchDataJsonConverter : JsonConverter + private class TemplateSearchDataJsonConverter : System.Text.Json.Serialization.JsonConverter { //falls back to default de-serializer if not implemented - public override TemplateSearchData ReadJson(JsonReader reader, Type objectType, TemplateSearchData? existingValue, bool hasExistingValue, JsonSerializer serializer) + public override TemplateSearchData Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => throw new NotImplementedException(); - public override void WriteJson(JsonWriter writer, TemplateSearchData? value, JsonSerializer serializer) + public override void Write(Utf8JsonWriter writer, TemplateSearchData value, JsonSerializerOptions options) { if (value == null) { @@ -48,43 +48,43 @@ public override void WriteJson(JsonWriter writer, TemplateSearchData? value, Jso } writer.WriteStartObject(); writer.WritePropertyName(nameof(ITemplateInfo.Identity)); - writer.WriteValue(value.TemplateInfo.Identity); + writer.WriteStringValue(value.TemplateInfo.Identity); if (!string.IsNullOrWhiteSpace(value.TemplateInfo.GroupIdentity)) { writer.WritePropertyName(nameof(ITemplateInfo.GroupIdentity)); - writer.WriteValue(value.TemplateInfo.GroupIdentity); + writer.WriteStringValue(value.TemplateInfo.GroupIdentity); } if (value.TemplateInfo.Precedence != 0) { writer.WritePropertyName(nameof(ITemplateInfo.Precedence)); - writer.WriteValue(value.TemplateInfo.Precedence); + writer.WriteNumberValue(value.TemplateInfo.Precedence); } writer.WritePropertyName(nameof(ITemplateInfo.Name)); - writer.WriteValue(value.TemplateInfo.Name); + writer.WriteStringValue(value.TemplateInfo.Name); writer.WritePropertyName(nameof(ITemplateInfo.ShortNameList)); writer.WriteStartArray(); foreach (string shortName in value.TemplateInfo.ShortNameList) { if (!string.IsNullOrWhiteSpace(shortName)) { - writer.WriteValue(shortName); + writer.WriteStringValue(shortName); } } writer.WriteEndArray(); if (!string.IsNullOrWhiteSpace(value.TemplateInfo.Author)) { writer.WritePropertyName(nameof(ITemplateInfo.Author)); - writer.WriteValue(value.TemplateInfo.Author); + writer.WriteStringValue(value.TemplateInfo.Author); } if (!string.IsNullOrWhiteSpace(value.TemplateInfo.Description)) { writer.WritePropertyName(nameof(ITemplateInfo.Description)); - writer.WriteValue(value.TemplateInfo.Description); + writer.WriteStringValue(value.TemplateInfo.Description); } if (!string.IsNullOrWhiteSpace(value.TemplateInfo.ThirdPartyNotices)) { writer.WritePropertyName(nameof(ITemplateInfo.ThirdPartyNotices)); - writer.WriteValue(value.TemplateInfo.ThirdPartyNotices); + writer.WriteStringValue(value.TemplateInfo.ThirdPartyNotices); } if (value.TemplateInfo.Classifications.Any()) @@ -95,7 +95,7 @@ public override void WriteJson(JsonWriter writer, TemplateSearchData? value, Jso { if (!string.IsNullOrWhiteSpace(classification)) { - writer.WriteValue(classification); + writer.WriteStringValue(classification); } } writer.WriteEndArray(); @@ -108,7 +108,7 @@ public override void WriteJson(JsonWriter writer, TemplateSearchData? value, Jso foreach (var tag in value.TemplateInfo.TagsCollection) { writer.WritePropertyName(tag.Key); - writer.WriteValue(tag.Value); + writer.WriteStringValue(tag.Value); } writer.WriteEndObject(); } @@ -123,21 +123,21 @@ public override void WriteJson(JsonWriter writer, TemplateSearchData? value, Jso { writer.WriteStartObject(); writer.WritePropertyName(nameof(ITemplateParameter.Name)); - writer.WriteValue(param.Name); + writer.WriteStringValue(param.Name); if (!string.IsNullOrWhiteSpace(param.DataType)) { writer.WritePropertyName(nameof(ITemplateParameter.DataType)); - writer.WriteValue(param.DataType); + writer.WriteStringValue(param.DataType); } if (!string.IsNullOrWhiteSpace(param.Description)) { writer.WritePropertyName(nameof(ITemplateParameter.Description)); - writer.WriteValue(param.Description); + writer.WriteStringValue(param.Description); } if (!string.IsNullOrWhiteSpace(param.DefaultIfOptionWithoutValue)) { writer.WritePropertyName(nameof(ITemplateParameter.DefaultIfOptionWithoutValue)); - writer.WriteValue(param.DefaultIfOptionWithoutValue); + writer.WriteStringValue(param.DefaultIfOptionWithoutValue); } if (param.Choices != null && param.Choices.Any()) @@ -151,12 +151,12 @@ public override void WriteJson(JsonWriter writer, TemplateSearchData? value, Jso if (!string.IsNullOrWhiteSpace(choice.Value.Description)) { writer.WritePropertyName(nameof(ParameterChoice.Description)); - writer.WriteValue(choice.Value.Description); + writer.WriteStringValue(choice.Value.Description); } if (!string.IsNullOrWhiteSpace(choice.Value.DisplayName)) { writer.WritePropertyName(nameof(ParameterChoice.DisplayName)); - writer.WriteValue(choice.Value.DisplayName); + writer.WriteStringValue(choice.Value.DisplayName); } writer.WriteEndObject(); } @@ -170,7 +170,7 @@ public override void WriteJson(JsonWriter writer, TemplateSearchData? value, Jso if (value.TemplateInfo.BaselineInfo.Any()) { writer.WritePropertyName(nameof(ITemplateInfo.BaselineInfo)); - serializer.Serialize(writer, value.TemplateInfo.BaselineInfo); + JsonSerializer.Serialize(writer, value.TemplateInfo.BaselineInfo, options); } if (value.TemplateInfo.PostActions.Any()) @@ -179,7 +179,7 @@ public override void WriteJson(JsonWriter writer, TemplateSearchData? value, Jso writer.WriteStartArray(); foreach (Guid guid in value.TemplateInfo.PostActions) { - writer.WriteValue(guid.ToString()); + writer.WriteStringValue(guid.ToString()); } writer.WriteEndArray(); } @@ -189,7 +189,7 @@ public override void WriteJson(JsonWriter writer, TemplateSearchData? value, Jso foreach (var item in value.AdditionalData) { writer.WritePropertyName(item.Key); - serializer.Serialize(writer, item.Value); + JsonSerializer.Serialize(writer, item.Value, options); } } diff --git a/src/Shared/JExtensions.cs b/src/Shared/JExtensions.cs index 4d5eff8db3f..4ecbd81a7bc 100644 --- a/src/Shared/JExtensions.cs +++ b/src/Shared/JExtensions.cs @@ -1,42 +1,63 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json; +using System.Text.Json.Nodes; +using System.Text.Json.Serialization; using Microsoft.TemplateEngine.Abstractions; using Microsoft.TemplateEngine.Abstractions.Mount; using Microsoft.TemplateEngine.Abstractions.PhysicalFileSystem; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine { internal static class JExtensions { - internal static string? ToString(this JToken? token, string? key) + private static readonly JsonDocumentOptions DocOptions = new() { CommentHandling = JsonCommentHandling.Skip, AllowTrailingCommas = true }; + private static readonly JsonNodeOptions NodeOptions = new() { PropertyNameCaseInsensitive = true }; + private static readonly JsonSerializerOptions SerializerOptions = new() + { + PropertyNameCaseInsensitive = true, + WriteIndented = false, + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + }; + + internal static string? ToString(this JsonNode? token, string? key) { if (key == null) { - if (token == null || token.Type != JTokenType.String) + if (token == null) { return null; } - return token.ToString(); + if (token is JsonValue val && val.GetValueKind() == JsonValueKind.String) + { + return val.GetValue(); + } + + return null; } - if (token is not JObject obj) + if (token is not JsonObject obj) { return null; } - if (!obj.TryGetValue(key, StringComparison.OrdinalIgnoreCase, out JToken? element) || element.Type == JTokenType.Null) + JsonNode? element = GetPropertyCaseInsensitive(obj, key); + if (element == null || element.GetValueKind() == JsonValueKind.Null) { return null; } - return element.ToString(); + if (element is JsonValue strVal && strVal.GetValueKind() == JsonValueKind.String) + { + return strVal.GetValue(); + } + + return element.ToJsonString(); } - internal static bool TryGetValue(this JToken? token, string? key, out JToken? result) + internal static bool TryGetValue(this JsonNode? token, string? key, out JsonNode? result) { result = null; @@ -49,25 +70,42 @@ internal static bool TryGetValue(this JToken? token, string? key, out JToken? re { result = token; } - else if (!((JObject)token).TryGetValue(key, StringComparison.OrdinalIgnoreCase, out result)) + else { - return false; + result = GetPropertyCaseInsensitive(token.AsObject(), key); + if (result == null) + { + return false; + } } return true; } - internal static bool TryParseBool(this JToken token, out bool result) + internal static bool TryParseBool(this JsonNode token, out bool result) { result = false; - return (token.Type == JTokenType.Boolean || token.Type == JTokenType.String) - && - bool.TryParse(token.ToString(), out result); + var kind = token.GetValueKind(); + if (kind == JsonValueKind.True) + { + result = true; + return true; + } + if (kind == JsonValueKind.False) + { + result = false; + return true; + } + if (kind == JsonValueKind.String) + { + return bool.TryParse(token.GetValue(), out result); + } + return false; } - internal static bool ToBool(this JToken? token, string? key = null, bool defaultValue = false) + internal static bool ToBool(this JsonNode? token, string? key = null, bool defaultValue = false) { - if (!token.TryGetValue(key, out JToken? checkToken)) + if (!token.TryGetValue(key, out JsonNode? checkToken)) { return defaultValue; } @@ -80,20 +118,31 @@ internal static bool ToBool(this JToken? token, string? key = null, bool default return result; } - internal static bool TryParseInt(this JToken token, out int result) + internal static bool TryParseInt(this JsonNode token, out int result) { result = default; - return (token.Type == JTokenType.Integer || token.Type == JTokenType.String) - && - int.TryParse(token.ToString(), out result); + var kind = token.GetValueKind(); + if (kind == JsonValueKind.Number) + { + if (token is JsonValue jv && jv.TryGetValue(out int intVal)) + { + result = intVal; + return true; + } + return int.TryParse(token.ToJsonString(), out result); + } + if (kind == JsonValueKind.String) + { + return int.TryParse(token.GetValue(), out result); + } + return false; } - internal static int ToInt32(this JToken? token, string? key = null, int defaultValue = 0) + internal static int ToInt32(this JsonNode? token, string? key = null, int defaultValue = 0) { - int value; if (key == null) { - if (token == null || token.Type != JTokenType.Integer || !int.TryParse(token.ToString(), out value)) + if (token == null || !token.TryParseInt(out int value)) { return defaultValue; } @@ -101,28 +150,21 @@ internal static int ToInt32(this JToken? token, string? key = null, int defaultV return value; } - if (token is not JObject obj) + if (token is not JsonObject obj) { return defaultValue; } - if (!obj.TryGetValue(key, StringComparison.OrdinalIgnoreCase, out JToken? element)) + JsonNode? element = GetPropertyCaseInsensitive(obj, key); + if (element == null || !element.TryParseInt(out int result)) { return defaultValue; } - else if (element.Type == JTokenType.Integer) - { - return element.ToInt32(); - } - else if (int.TryParse(element.ToString(), out value)) - { - return value; - } - return defaultValue; + return result; } - internal static T ToEnum(this JToken token, string? key = null, T defaultValue = default, bool ignoreCase = false) + internal static T ToEnum(this JsonNode token, string? key = null, T defaultValue = default, bool ignoreCase = false) where T : struct { string? val = token.ToString(key); @@ -134,7 +176,7 @@ internal static T ToEnum(this JToken token, string? key = null, T defaultValu return result; } - internal static Guid ToGuid(this JToken token, string? key = null, Guid defaultValue = default) + internal static Guid ToGuid(this JsonNode token, string? key = null, Guid defaultValue = default) { string? val = token.ToString(key); if (val == null || !Guid.TryParse(val, out Guid result)) @@ -149,10 +191,10 @@ internal static Guid ToGuid(this JToken token, string? key = null, Guid defaultV /// Reads as read only string list/>. /// Property value may be string or array. /// - internal static IReadOnlyList ToStringReadOnlyList(this JObject jObject, string propertyName, IReadOnlyList? defaultValue = null) + internal static IReadOnlyList ToStringReadOnlyList(this JsonObject jObject, string propertyName, IReadOnlyList? defaultValue = null) { defaultValue ??= []; - JToken? token = jObject.Get(propertyName); + JsonNode? token = jObject.Get(propertyName); if (token == null) { return defaultValue; @@ -160,52 +202,49 @@ internal static IReadOnlyList ToStringReadOnlyList(this JObject jObject, return token.JTokenStringOrArrayToCollection(defaultValue) ?? defaultValue; } - internal static IEnumerable PropertiesOf(this JToken? token, string? key = null) + internal static IEnumerable> PropertiesOf(this JsonNode? token, string? key = null) { - if (token is not JObject obj) + if (token is not JsonObject obj) { return []; } if (key != null) { - if (!obj.TryGetValue(key, StringComparison.OrdinalIgnoreCase, out JToken? element)) + JsonNode? element = GetPropertyCaseInsensitive(obj, key); + if (element == null) { return []; } - return element is not JObject jObj ? [] : jObj.Properties(); + return element is not JsonObject jObj ? [] : jObj.ToList(); } - return obj.Properties(); + return obj.ToList(); } - internal static T? Get(this JToken? token, string? key) - where T : JToken + internal static T? Get(this JsonNode? token, string? key) + where T : JsonNode { - if (token is not JObject obj || key == null) - { - return default; - } - - if (!obj.TryGetValue(key, StringComparison.OrdinalIgnoreCase, out JToken? res)) + if (token is not JsonObject obj || key == null) { return default; } + JsonNode? res = GetPropertyCaseInsensitive(obj, key); return res as T; } - internal static IReadOnlyDictionary ToStringDictionary(this JToken token, StringComparer? comparer = null, string? propertyName = null) + internal static IReadOnlyDictionary ToStringDictionary(this JsonNode token, StringComparer? comparer = null, string? propertyName = null) { Dictionary result = new(comparer ?? StringComparer.Ordinal); - foreach (JProperty property in token.PropertiesOf(propertyName)) + foreach (var property in token.PropertiesOf(propertyName)) { - if (property.Value == null || property.Value.Type != JTokenType.String) + if (property.Value == null || property.Value.GetValueKind() != JsonValueKind.String) { continue; } - result[property.Name] = property.Value.ToString(); + result[property.Key] = property.Value.GetValue(); } return result; @@ -213,15 +252,18 @@ internal static IReadOnlyDictionary ToStringDictionary(this JTok /// /// Converts properties of to dictionary. - /// Leaves the values as JToken. + /// Leaves the values as JsonNode. /// - internal static IReadOnlyDictionary ToJTokenDictionary(this JToken token, StringComparer? comparer = null, string? propertyName = null) + internal static IReadOnlyDictionary ToJsonNodeDictionary(this JsonNode token, StringComparer? comparer = null, string? propertyName = null) { - Dictionary result = new(comparer ?? StringComparer.Ordinal); + Dictionary result = new(comparer ?? StringComparer.Ordinal); - foreach (JProperty property in token.PropertiesOf(propertyName)) + foreach (var property in token.PropertiesOf(propertyName)) { - result[property.Name] = property.Value; + if (property.Value != null) + { + result[property.Key] = property.Value; + } } return result; @@ -229,23 +271,26 @@ internal static IReadOnlyDictionary ToJTokenDictionary(this JTok /// /// Converts properties of to dictionary. - /// Values are serialized to string (as JToken). Strings are serialized as , i.e. needs to be parsed prior to be used. + /// Values are serialized to string (as JsonNode). Strings are serialized as JSON, i.e. needs to be parsed prior to be used. /// - internal static IReadOnlyDictionary ToJTokenStringDictionary(this JToken token, StringComparer? comparer = null, string? propertyName = null) + internal static IReadOnlyDictionary ToJsonNodeStringDictionary(this JsonNode token, StringComparer? comparer = null, string? propertyName = null) { Dictionary result = new(comparer ?? StringComparer.Ordinal); - foreach (JProperty property in token.PropertiesOf(propertyName)) + foreach (var property in token.PropertiesOf(propertyName)) { - result[property.Name] = property.Value.ToString(Formatting.None); + if (property.Value != null) + { + result[property.Key] = property.Value.ToJsonString(); + } } return result; } - internal static TemplateParameterPrecedence ToTemplateParameterPrecedence(this JToken jObject, string? key) + internal static TemplateParameterPrecedence ToTemplateParameterPrecedence(this JsonNode jObject, string? key) { - if (!jObject.TryGetValue(key, out JToken? checkToken)) + if (!jObject.TryGetValue(key, out JsonNode? checkToken)) { return TemplateParameterPrecedence.Default; } @@ -258,50 +303,50 @@ internal static TemplateParameterPrecedence ToTemplateParameterPrecedence(this J return new TemplateParameterPrecedence(precedenceDefinition, isRequiredCondition, isEnabledCondition, isRequired); } - internal static IReadOnlyList ArrayAsStrings(this JToken? token, string? propertyName = null) + internal static IReadOnlyList ArrayAsStrings(this JsonNode? token, string? propertyName = null) { if (propertyName != null) { - token = token.Get(propertyName); + token = token.Get(propertyName); } - if (token is not JArray arr) + if (token is not JsonArray arr) { return []; } List values = new(); - foreach (JToken item in arr) + foreach (JsonNode? item in arr) { - if (item != null && item.Type == JTokenType.String) + if (item != null && item.GetValueKind() == JsonValueKind.String) { - values.Add(item.ToString()); + values.Add(item.GetValue()); } } return values; } - internal static IReadOnlyList ArrayAsGuids(this JToken? token, string? propertyName = null) + internal static IReadOnlyList ArrayAsGuids(this JsonNode? token, string? propertyName = null) { if (propertyName != null) { - token = token.Get(propertyName); + token = token.Get(propertyName); } - if (token is not JArray arr) + if (token is not JsonArray arr) { return []; } List values = new(); - foreach (JToken item in arr) + foreach (JsonNode? item in arr) { - if (item != null && item.Type == JTokenType.String) + if (item != null && item.GetValueKind() == JsonValueKind.String) { - if (Guid.TryParse(item.ToString(), out Guid val)) + if (Guid.TryParse(item.GetValue(), out Guid val)) { values.Add(val); } @@ -311,20 +356,20 @@ internal static IReadOnlyList ArrayAsGuids(this JToken? token, string? pro return values; } - internal static IEnumerable Items(this JToken? token, string? propertyName = null) - where T : JToken + internal static IEnumerable Items(this JsonNode? token, string? propertyName = null) + where T : JsonNode { if (propertyName != null) { - token = token.Get(propertyName); + token = token.Get(propertyName); } - if (token is not JArray arr) + if (token is not JsonArray arr) { yield break; } - foreach (JToken item in arr) + foreach (JsonNode? item in arr) { if (item is T res) { @@ -333,47 +378,40 @@ internal static IEnumerable Items(this JToken? token, string? propertyName } } - internal static JObject ReadJObjectFromIFile(this IFile file) + internal static JsonObject ReadJObjectFromIFile(this IFile file) { using Stream s = file.OpenRead(); using TextReader tr = new StreamReader(s, System.Text.Encoding.UTF8, true); - using JsonReader r = new JsonTextReader(tr); - { - return JObject.Load(r); - } + string json = tr.ReadToEnd(); + return (JsonObject?)JsonNode.Parse(json, NodeOptions, DocOptions) + ?? throw new InvalidOperationException("Failed to parse JSON from file."); } - internal static JObject ReadObject(this IPhysicalFileSystem fileSystem, string path) + internal static JsonObject ReadObject(this IPhysicalFileSystem fileSystem, string path) { using Stream fileStream = fileSystem.OpenRead(path); using var textReader = new StreamReader(fileStream, System.Text.Encoding.UTF8, true); - using var jsonReader = new JsonTextReader(textReader); - { - return JObject.Load(jsonReader); - } + string json = textReader.ReadToEnd(); + return (JsonObject?)JsonNode.Parse(json, NodeOptions, DocOptions) + ?? throw new InvalidOperationException($"Failed to parse JSON from '{path}'."); } internal static void WriteObject(this IPhysicalFileSystem fileSystem, string path, object obj) { using Stream fileStream = fileSystem.CreateFile(path); - using var textWriter = new StreamWriter(fileStream, System.Text.Encoding.UTF8); - using var jsonWriter = new JsonTextWriter(textWriter); - { - var serializer = new JsonSerializer(); - serializer.Serialize(jsonWriter, obj); - } + JsonSerializer.Serialize(fileStream, obj, SerializerOptions); } - internal static IReadOnlyList JTokenStringOrArrayToCollection(this JToken? token, IReadOnlyList defaultSet) + internal static IReadOnlyList JTokenStringOrArrayToCollection(this JsonNode? token, IReadOnlyList defaultSet) { if (token == null) { return defaultSet; } - if (token.Type == JTokenType.String) + if (token.GetValueKind() == JsonValueKind.String) { - string tokenValue = token.ToString(); + string tokenValue = token.GetValue(); return new List() { tokenValue }; } @@ -382,11 +420,10 @@ internal static IReadOnlyList JTokenStringOrArrayToCollection(this JToke /// /// Converts to valid JSON string. - /// JToken.ToString() doesn't provide a valid JSON string for JTokenType == String. /// internal static string ToJsonString(object obj) { - return JToken.FromObject(obj).ToString(Formatting.None); + return JsonSerializer.Serialize(obj, SerializerOptions); } internal static string ToCamelCase(this string str) @@ -398,5 +435,111 @@ internal static string ToCamelCase(this string str) }; } + /// + /// Tries to get a property value from a using case-insensitive key matching. + /// + internal static bool TryGetValueCaseInsensitive(this JsonObject obj, string key, out JsonNode? result) + { + result = GetPropertyCaseInsensitive(obj, key); + return result != null; + } + + /// + /// Gets a property from a JsonObject with case-insensitive key matching. + /// + internal static JsonNode? GetPropertyCaseInsensitive(JsonObject obj, string key) + { + // Try exact match first (fast path). + if (obj.TryGetPropertyValue(key, out JsonNode? result)) + { + return result; + } + + // Fall back to case-insensitive search. + foreach (var kvp in obj) + { + if (string.Equals(kvp.Key, key, StringComparison.OrdinalIgnoreCase)) + { + return kvp.Value; + } + } + + return null; + } + + /// + /// Parses a JSON string into a JsonObject (with comment/trailing comma support). + /// + internal static JsonObject ParseJsonObject(string json) + { + return (JsonObject?)JsonNode.Parse(json, NodeOptions, DocOptions) + ?? throw new InvalidOperationException("Failed to parse JSON string as JsonObject."); + } + + /// + /// Parses a JSON string into a JsonNode (with comment/trailing comma support). + /// + internal static JsonNode? ParseJsonNode(string json) + { + return JsonNode.Parse(json, NodeOptions, DocOptions); + } + + /// + /// Serializes an object to a JsonObject via JSON round-trip. + /// Equivalent to Newtonsoft's JObject.FromObject(). + /// + internal static JsonObject FromObject(object obj) + { + string json = JsonSerializer.Serialize(obj, SerializerOptions); + return (JsonObject?)JsonNode.Parse(json, NodeOptions, DocOptions) + ?? throw new InvalidOperationException("Failed to round-trip object to JsonObject."); + } + + /// + /// Creates a deep clone of a by round-tripping through JSON text. + /// + internal static JsonObject DeepCloneObject(this JsonObject source) + { + return (JsonObject?)JsonNode.Parse(source.ToJsonString(), NodeOptions, DocOptions) + ?? throw new InvalidOperationException("Failed to deep clone JsonObject."); + } + + /// + /// Merges properties from into . + /// Equivalent to Newtonsoft's JObject.Merge() with default settings: + /// - Objects are recursively merged + /// - Arrays are concatenated + /// - Other values (including null) from source overwrite target. + /// + internal static void Merge(this JsonObject target, JsonObject source) + { + foreach (var property in source) + { + if (property.Value is JsonObject sourceObj + && target.TryGetPropertyValue(property.Key, out JsonNode? targetNode) + && targetNode is JsonObject targetObj) + { + // Recursively merge nested objects + targetObj.Merge(sourceObj); + } + else if (property.Value is JsonArray sourceArr + && target.TryGetPropertyValue(property.Key, out targetNode) + && targetNode is JsonArray targetArr) + { + // Concatenate arrays + foreach (var item in sourceArr) + { + targetArr.Add(item != null ? JsonNode.Parse(item.ToJsonString()) : null); + } + } + else + { + // Overwrite (or add) the property; clone value to detach from source tree + target[property.Key] = property.Value != null + ? JsonNode.Parse(property.Value.ToJsonString()) + : null; + } + } + } } } diff --git a/test/Microsoft.TemplateEngine.Authoring.CLI.IntegrationTests/ExportCommandTests.cs b/test/Microsoft.TemplateEngine.Authoring.CLI.IntegrationTests/ExportCommandTests.cs index 01039bf238e..4e945be749c 100644 --- a/test/Microsoft.TemplateEngine.Authoring.CLI.IntegrationTests/ExportCommandTests.cs +++ b/test/Microsoft.TemplateEngine.Authoring.CLI.IntegrationTests/ExportCommandTests.cs @@ -1,14 +1,16 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json; +using System.Text.Json.Nodes; using Microsoft.TemplateEngine.TestHelper; using Microsoft.TemplateEngine.Tests; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine.Authoring.CLI.IntegrationTests { public class ExportCommandTests : TestBase, IDisposable { + private static readonly JsonDocumentOptions DocOptions = new() { AllowTrailingCommas = true, CommentHandling = JsonCommentHandling.Skip }; private readonly string _workingDirectory; public ExportCommandTests() @@ -74,26 +76,26 @@ public async Task EnglishLocFilesAreOverwritten() string deLocFile = Path.Combine(expectedExportDirectory, "templatestrings.de.json"); Assert.True(File.Exists(enLocFile)); Assert.True(File.Exists(deLocFile)); - var engJsonContent = JObject.Parse(File.ReadAllText(enLocFile)); - var deJsonContent = JObject.Parse(File.ReadAllText(deLocFile)); - Assert.Equal("Test Asset", engJsonContent.Property("author")?.Value.ToString()); - Assert.Equal("Test Asset", deJsonContent.Property("author")?.Value.ToString()); + var engJsonContent = JsonNode.Parse(File.ReadAllText(enLocFile), documentOptions: DocOptions)!.AsObject(); + var deJsonContent = JsonNode.Parse(File.ReadAllText(deLocFile), documentOptions: DocOptions)!.AsObject(); + Assert.Equal("Test Asset", engJsonContent["author"]?.ToString()); + Assert.Equal("Test Asset", deJsonContent["author"]?.ToString()); //modify author property string baseConfig = Path.Combine(testTemplate, ".template.config", "template.json"); - var templateJsonContent = JObject.Parse(File.ReadAllText(baseConfig)); - Assert.NotNull(templateJsonContent.Property("author")); - templateJsonContent.Property("author")!.Value = "New Author"; - File.WriteAllText(baseConfig, templateJsonContent.ToString()); + var templateJsonContent = JsonNode.Parse(File.ReadAllText(baseConfig), documentOptions: DocOptions)!.AsObject(); + Assert.NotNull(templateJsonContent["author"]); + templateJsonContent["author"] = "New Author"; + File.WriteAllText(baseConfig, templateJsonContent.ToJsonString()); runResult = await Program.Main(new[] { "localize", "export", testTemplate }); Assert.Equal(0, runResult); Assert.True(File.Exists(enLocFile)); Assert.True(File.Exists(deLocFile)); - engJsonContent = JObject.Parse(File.ReadAllText(enLocFile)); - deJsonContent = JObject.Parse(File.ReadAllText(deLocFile)); - Assert.Equal("New Author", engJsonContent.Property("author")?.Value.ToString()); - Assert.Equal("Test Asset", deJsonContent.Property("author")?.Value.ToString()); + engJsonContent = JsonNode.Parse(File.ReadAllText(enLocFile), documentOptions: DocOptions)!.AsObject(); + deJsonContent = JsonNode.Parse(File.ReadAllText(deLocFile), documentOptions: DocOptions)!.AsObject(); + Assert.Equal("New Author", engJsonContent["author"]?.ToString()); + Assert.Equal("Test Asset", deJsonContent["author"]?.ToString()); } [Fact] @@ -101,9 +103,9 @@ public async Task TemplateLanguageLocFilesAreOverwritten() { string testTemplate = GetTestTemplateInTempDir("TemplateWithSourceName"); string baseConfig = Path.Combine(testTemplate, ".template.config", "template.json"); - var templateJsonContent = JObject.Parse(File.ReadAllText(baseConfig)); - templateJsonContent.AddFirst(new JProperty("authoringLanguage", "de")); - File.WriteAllText(baseConfig, templateJsonContent.ToString()); + var templateJsonContent = JsonNode.Parse(File.ReadAllText(baseConfig), documentOptions: DocOptions)!.AsObject(); + templateJsonContent.Insert(0, "authoringLanguage", "de"); + File.WriteAllText(baseConfig, templateJsonContent.ToJsonString()); int runResult = await Program.Main(new[] { "localize", "export", testTemplate }); Assert.Equal(0, runResult); @@ -112,25 +114,25 @@ public async Task TemplateLanguageLocFilesAreOverwritten() string deLocFile = Path.Combine(expectedExportDirectory, "templatestrings.de.json"); Assert.True(File.Exists(enLocFile)); Assert.True(File.Exists(deLocFile)); - var engJsonContent = JObject.Parse(File.ReadAllText(enLocFile)); - var deJsonContent = JObject.Parse(File.ReadAllText(deLocFile)); - Assert.Equal("Test Asset", engJsonContent.Property("author")?.Value.ToString()); - Assert.Equal("Test Asset", deJsonContent.Property("author")?.Value.ToString()); + var engJsonContent = JsonNode.Parse(File.ReadAllText(enLocFile), documentOptions: DocOptions)!.AsObject(); + var deJsonContent = JsonNode.Parse(File.ReadAllText(deLocFile), documentOptions: DocOptions)!.AsObject(); + Assert.Equal("Test Asset", engJsonContent["author"]?.ToString()); + Assert.Equal("Test Asset", deJsonContent["author"]?.ToString()); //modify author property - templateJsonContent = JObject.Parse(File.ReadAllText(baseConfig)); - Assert.NotNull(templateJsonContent.Property("author")); - templateJsonContent.Property("author")!.Value = "New Author"; - File.WriteAllText(baseConfig, templateJsonContent.ToString()); + templateJsonContent = JsonNode.Parse(File.ReadAllText(baseConfig), documentOptions: DocOptions)!.AsObject(); + Assert.NotNull(templateJsonContent["author"]); + templateJsonContent["author"] = "New Author"; + File.WriteAllText(baseConfig, templateJsonContent.ToJsonString()); runResult = await Program.Main(new[] { "localize", "export", testTemplate }); Assert.Equal(0, runResult); Assert.True(File.Exists(enLocFile)); Assert.True(File.Exists(deLocFile)); - engJsonContent = JObject.Parse(File.ReadAllText(enLocFile)); - deJsonContent = JObject.Parse(File.ReadAllText(deLocFile)); - Assert.Equal("New Author", deJsonContent.Property("author")?.Value.ToString()); - Assert.Equal("Test Asset", engJsonContent.Property("author")?.Value.ToString()); + engJsonContent = JsonNode.Parse(File.ReadAllText(enLocFile), documentOptions: DocOptions)!.AsObject(); + deJsonContent = JsonNode.Parse(File.ReadAllText(deLocFile), documentOptions: DocOptions)!.AsObject(); + Assert.Equal("New Author", deJsonContent["author"]?.ToString()); + Assert.Equal("Test Asset", engJsonContent["author"]?.ToString()); } [Fact] diff --git a/test/Microsoft.TemplateEngine.Edge.UnitTests/HostConstraintTests.cs b/test/Microsoft.TemplateEngine.Edge.UnitTests/HostConstraintTests.cs index d36959b3823..9aa38b3d0f5 100644 --- a/test/Microsoft.TemplateEngine.Edge.UnitTests/HostConstraintTests.cs +++ b/test/Microsoft.TemplateEngine.Edge.UnitTests/HostConstraintTests.cs @@ -1,12 +1,13 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json; +using System.Text.Json.Nodes; using FakeItEasy; using Microsoft.TemplateEngine.Abstractions; using Microsoft.TemplateEngine.Abstractions.Constraints; using Microsoft.TemplateEngine.Edge.Constraints; using Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ConfigModel; -using Newtonsoft.Json.Linq; using Xunit; namespace Microsoft.TemplateEngine.Edge.UnitTests @@ -47,7 +48,7 @@ public async Task CanReadConfiguration_WithoutVersion() } }; - var configModel = TemplateConfigModel.FromJObject(JObject.FromObject(config)); + var configModel = TemplateConfigModel.FromJObject(JsonNode.Parse(JsonSerializer.Serialize(config))!.AsObject()); IEngineEnvironmentSettings settings = A.Fake(); A.CallTo(() => settings.Host.HostIdentifier).Returns("host1"); A.CallTo(() => settings.Host.Version).Returns("2.0.0"); @@ -92,7 +93,7 @@ public async Task CanReadConfiguration_ExactVersion() } }; - var configModel = TemplateConfigModel.FromJObject(JObject.FromObject(config)); + var configModel = TemplateConfigModel.FromJObject(JsonNode.Parse(JsonSerializer.Serialize(config))!.AsObject()); IEngineEnvironmentSettings settings = A.Fake(); A.CallTo(() => settings.Host.HostIdentifier).Returns("host2"); A.CallTo(() => settings.Host.Version).Returns("2.0.0"); @@ -140,7 +141,7 @@ public async Task CanReadConfiguration_VersionRange() } }; - var configModel = TemplateConfigModel.FromJObject(JObject.FromObject(config)); + var configModel = TemplateConfigModel.FromJObject(JsonNode.Parse(JsonSerializer.Serialize(config))!.AsObject()); IEngineEnvironmentSettings settings = A.Fake(); A.CallTo(() => settings.Host.HostIdentifier).Returns("host3"); @@ -173,7 +174,7 @@ public async Task FailsOnWrongConfiguration() } }; - var configModel = TemplateConfigModel.FromJObject(JObject.FromObject(config)); + var configModel = TemplateConfigModel.FromJObject(JsonNode.Parse(JsonSerializer.Serialize(config))!.AsObject()); IEngineEnvironmentSettings settings = A.Fake(); A.CallTo(() => settings.Host.HostIdentifier).Returns("host3"); @@ -223,7 +224,7 @@ public async Task CanProcessDifferentVersions(string configuredVersion, string h } }; - var configModel = TemplateConfigModel.FromJObject(JObject.FromObject(config)); + var configModel = TemplateConfigModel.FromJObject(JsonNode.Parse(JsonSerializer.Serialize(config))!.AsObject()); IEngineEnvironmentSettings settings = A.Fake(); A.CallTo(() => settings.Host.HostIdentifier).Returns("host1"); A.CallTo(() => settings.Host.Version).Returns(hostVersion); @@ -273,7 +274,7 @@ public async Task CanProcessDifferentHostNames(string hostName, string fallbackH } }; - var configModel = TemplateConfigModel.FromJObject(JObject.FromObject(config)); + var configModel = TemplateConfigModel.FromJObject(JsonNode.Parse(JsonSerializer.Serialize(config))!.AsObject()); IEngineEnvironmentSettings settings = A.Fake(); A.CallTo(() => settings.Host.HostIdentifier).Returns(hostName); A.CallTo(() => settings.Host.Version).Returns(hostVersion); diff --git a/test/Microsoft.TemplateEngine.Edge.UnitTests/OSConstraintTests.cs b/test/Microsoft.TemplateEngine.Edge.UnitTests/OSConstraintTests.cs index b6538855344..543bc83fe05 100644 --- a/test/Microsoft.TemplateEngine.Edge.UnitTests/OSConstraintTests.cs +++ b/test/Microsoft.TemplateEngine.Edge.UnitTests/OSConstraintTests.cs @@ -2,11 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Runtime.InteropServices; +using System.Text.Json; +using System.Text.Json.Nodes; using Microsoft.TemplateEngine.Abstractions; using Microsoft.TemplateEngine.Abstractions.Constraints; using Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ConfigModel; using Microsoft.TemplateEngine.TestHelper; -using Newtonsoft.Json.Linq; using Xunit; namespace Microsoft.TemplateEngine.Edge.UnitTests @@ -36,7 +37,7 @@ public async Task CanReadStringConfiguration() } }; - var configModel = TemplateConfigModel.FromJObject(JObject.FromObject(config)); + var configModel = TemplateConfigModel.FromJObject(JsonNode.Parse(JsonSerializer.Serialize(config))!.AsObject()); var constraintManager = new TemplateConstraintManager(_sharedSettings); var evaluateResult = await constraintManager.EvaluateConstraintAsync(configModel.Constraints.Single().Type, configModel.Constraints.Single().Args, default); @@ -69,7 +70,7 @@ public async Task CanReadArrayConfiguration() } }; - var configModel = TemplateConfigModel.FromJObject(JObject.FromObject(config)); + var configModel = TemplateConfigModel.FromJObject(JsonNode.Parse(JsonSerializer.Serialize(config))!.AsObject()); var constraintManager = new TemplateConstraintManager(_sharedSettings); var evaluateResult = await constraintManager.EvaluateConstraintAsync(configModel.Constraints.Single().Type, configModel.Constraints.Single().Args, default); diff --git a/test/Microsoft.TemplateEngine.Edge.UnitTests/SdkVersionConstraintTests.cs b/test/Microsoft.TemplateEngine.Edge.UnitTests/SdkVersionConstraintTests.cs index 2adbdf7d973..4434f79d8ee 100644 --- a/test/Microsoft.TemplateEngine.Edge.UnitTests/SdkVersionConstraintTests.cs +++ b/test/Microsoft.TemplateEngine.Edge.UnitTests/SdkVersionConstraintTests.cs @@ -1,13 +1,14 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json; +using System.Text.Json.Nodes; using FakeItEasy; using Microsoft.TemplateEngine.Abstractions; using Microsoft.TemplateEngine.Abstractions.Components; using Microsoft.TemplateEngine.Abstractions.Constraints; using Microsoft.TemplateEngine.Edge.Constraints; using Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ConfigModel; -using Newtonsoft.Json.Linq; using Xunit; namespace Microsoft.TemplateEngine.Edge.UnitTests @@ -37,7 +38,7 @@ public async Task Evaluate_ArrayOfVersions(string sdkVersion, bool allowed) } }; - var configModel = TemplateConfigModel.FromJObject(JObject.FromObject(config)); + var configModel = TemplateConfigModel.FromJObject(JsonNode.Parse(JsonSerializer.Serialize(config))!.AsObject()); ISdkInfoProvider sdkInfoProvider = new SdkInfoProviderMock(sdkVersion); //A.Fake(); IEngineEnvironmentSettings settings = A.Fake(); A.CallTo(() => settings.Components.OfType()).Returns(new[] { sdkInfoProvider }); @@ -76,7 +77,7 @@ public async Task Evaluate_SingleVersionRange(string sdkVersion, bool allowed) } }; - var configModel = TemplateConfigModel.FromJObject(JObject.FromObject(config)); + var configModel = TemplateConfigModel.FromJObject(JsonNode.Parse(JsonSerializer.Serialize(config))!.AsObject()); ISdkInfoProvider sdkInfoProvider = new SdkInfoProviderMock(sdkVersion); //A.Fake(); IEngineEnvironmentSettings settings = A.Fake(); A.CallTo(() => settings.Components.OfType()).Returns(new[] { sdkInfoProvider }); @@ -110,7 +111,7 @@ public async Task Evaluate_AlternativeInstalledVersions(string sdkVersion, IRead } }; - var configModel = TemplateConfigModel.FromJObject(JObject.FromObject(config)); + var configModel = TemplateConfigModel.FromJObject(JsonNode.Parse(JsonSerializer.Serialize(config))!.AsObject()); ISdkInfoProvider sdkInfoProvider = new SdkInfoProviderMock(sdkVersion, installedVersions); //A.Fake(); IEngineEnvironmentSettings settings = A.Fake(); A.CallTo(() => settings.Components.OfType()).Returns(new[] { sdkInfoProvider }); diff --git a/test/Microsoft.TemplateEngine.Edge.UnitTests/TemplateCacheTests.cs b/test/Microsoft.TemplateEngine.Edge.UnitTests/TemplateCacheTests.cs index d4c4fa1af0e..5701de9005b 100644 --- a/test/Microsoft.TemplateEngine.Edge.UnitTests/TemplateCacheTests.cs +++ b/test/Microsoft.TemplateEngine.Edge.UnitTests/TemplateCacheTests.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Globalization; +using System.Text.Json; +using System.Text.Json.Nodes; using FakeItEasy; using Microsoft.Extensions.Logging; using Microsoft.TemplateEngine.Abstractions; @@ -13,8 +15,6 @@ using Microsoft.TemplateEngine.Edge.Settings; using Microsoft.TemplateEngine.TestHelper; using Microsoft.TemplateEngine.Utils; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; using Xunit; namespace Microsoft.TemplateEngine.Edge.UnitTests @@ -330,7 +330,7 @@ public void CanHandleHostData() } """; - string hostFileFormatted = JObject.Parse(hostfile).ToString(Formatting.None); + string hostFileFormatted = JsonNode.Parse(hostfile)!.ToJsonString(); const string hostFileLocation = ".template.config/dotnetcli.host.json"; IDictionary templateSourceFiles = new Dictionary @@ -390,21 +390,18 @@ private ITemplatePackage GetFakedTemplatePackage(string mountPointUri) return managedTemplatePackage; } - private static JObject ReadObject(IPhysicalFileSystem fileSystem, string path) + private static JsonObject ReadObject(IPhysicalFileSystem fileSystem, string path) { using var fileStream = fileSystem.OpenRead(path); using var textReader = new StreamReader(fileStream, System.Text.Encoding.UTF8, true); - using var jsonReader = new JsonTextReader(textReader); - return JObject.Load(jsonReader); + string content = textReader.ReadToEnd(); + return JsonNode.Parse(content)!.AsObject(); } private static void WriteObject(IPhysicalFileSystem fileSystem, string path, object obj) { using var fileStream = fileSystem.CreateFile(path); - using var textWriter = new StreamWriter(fileStream, System.Text.Encoding.UTF8); - using var jsonWriter = new JsonTextWriter(textWriter); - var serializer = new JsonSerializer(); - serializer.Serialize(jsonWriter, obj); + JsonSerializer.Serialize(fileStream, obj); } } } diff --git a/test/Microsoft.TemplateEngine.Edge.UnitTests/WorkloadConstraintTests.cs b/test/Microsoft.TemplateEngine.Edge.UnitTests/WorkloadConstraintTests.cs index fcfff0953c7..d525e67f38e 100644 --- a/test/Microsoft.TemplateEngine.Edge.UnitTests/WorkloadConstraintTests.cs +++ b/test/Microsoft.TemplateEngine.Edge.UnitTests/WorkloadConstraintTests.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json; +using System.Text.Json.Nodes; using FakeItEasy; using Microsoft.Extensions.Logging; using Microsoft.TemplateEngine.Abstractions; @@ -9,7 +11,6 @@ using Microsoft.TemplateEngine.Edge.Constraints; using Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ConfigModel; using Microsoft.TemplateEngine.TestHelper; -using Newtonsoft.Json.Linq; using Xunit; namespace Microsoft.TemplateEngine.Edge.UnitTests @@ -36,7 +37,7 @@ public async Task Evaluate_ArrayOfVersions(IReadOnlyList workloads, bool } }; - var configModel = TemplateConfigModel.FromJObject(JObject.FromObject(config)); + var configModel = TemplateConfigModel.FromJObject(JsonNode.Parse(JsonSerializer.Serialize(config))!.AsObject()); IWorkloadsInfoProvider workloadInfoProvider = new WorkloadsInfoProviderMock(workloads); //A.Fake(); IEngineEnvironmentSettings settings = A.Fake(); A.CallTo(() => settings.Components.OfType()).Returns(new[] { workloadInfoProvider }); @@ -68,7 +69,7 @@ public async Task Evaluate_MultipleConflictingProviders() } }; - var configModel = TemplateConfigModel.FromJObject(JObject.FromObject(config)); + var configModel = TemplateConfigModel.FromJObject(JsonNode.Parse(JsonSerializer.Serialize(config))!.AsObject()); IWorkloadsInfoProvider workloadInfoProviderA = A.Fake(); A.CallTo(() => workloadInfoProviderA .GetInstalledWorkloadsAsync(A._)) @@ -110,7 +111,7 @@ public async Task Evaluate_MultipleDuplicateProviders() } }; - var configModel = TemplateConfigModel.FromJObject(JObject.FromObject(config)); + var configModel = TemplateConfigModel.FromJObject(JsonNode.Parse(JsonSerializer.Serialize(config))!.AsObject()); IWorkloadsInfoProvider workloadInfoProviderA = A.Fake(); A.CallTo(() => workloadInfoProviderA .GetInstalledWorkloadsAsync(A._)) diff --git a/test/Microsoft.TemplateEngine.Mocks/MockTemplateInfo.cs b/test/Microsoft.TemplateEngine.Mocks/MockTemplateInfo.cs index 3f2b35acb2f..073b2f25524 100644 --- a/test/Microsoft.TemplateEngine.Mocks/MockTemplateInfo.cs +++ b/test/Microsoft.TemplateEngine.Mocks/MockTemplateInfo.cs @@ -2,11 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Text; +using System.Text.Json; using Microsoft.TemplateEngine.Abstractions; using Microsoft.TemplateEngine.Abstractions.Constraints; using Microsoft.TemplateEngine.Abstractions.Parameters; using Microsoft.TemplateEngine.Utils; -using Newtonsoft.Json; #if XUNIT_V3 using Xunit.Sdk; #else @@ -246,26 +246,26 @@ public void Deserialize(IXunitSerializationInfo info) Description = info.GetValue("template_description"); Author = info.GetValue("template_author"); #if XUNIT_V3 - _tags = JsonConvert.DeserializeObject>(info.GetValue("template_tags")!) + _tags = JsonSerializer.Deserialize>(info.GetValue("template_tags")!) ?? throw new Exception("Deserialiation failed"); - _parameters = JsonConvert.DeserializeObject>(info.GetValue("template_params")!) + _parameters = JsonSerializer.Deserialize>(info.GetValue("template_params")!) ?? throw new Exception("Deserialiation failed"); - _baselineInfo = JsonConvert.DeserializeObject(info.GetValue("template_baseline")!) + _baselineInfo = JsonSerializer.Deserialize(info.GetValue("template_baseline")!) ?? throw new Exception("Deserialiation failed"); - _classifications = JsonConvert.DeserializeObject(info.GetValue("template_classifications")!) + _classifications = JsonSerializer.Deserialize(info.GetValue("template_classifications")!) ?? throw new Exception("Deserialiation failed"); - _shortNameList = JsonConvert.DeserializeObject(info.GetValue("template_shortname")!) + _shortNameList = JsonSerializer.Deserialize(info.GetValue("template_shortname")!) ?? throw new Exception("Deserialiation failed"); #else - _tags = JsonConvert.DeserializeObject>(info.GetValue("template_tags")) + _tags = JsonSerializer.Deserialize>(info.GetValue("template_tags")) ?? throw new Exception("Deserialiation failed"); - _parameters = JsonConvert.DeserializeObject>(info.GetValue("template_params")) + _parameters = JsonSerializer.Deserialize>(info.GetValue("template_params")) ?? throw new Exception("Deserialiation failed"); - _baselineInfo = JsonConvert.DeserializeObject(info.GetValue("template_baseline")) + _baselineInfo = JsonSerializer.Deserialize(info.GetValue("template_baseline")) ?? throw new Exception("Deserialiation failed"); - _classifications = JsonConvert.DeserializeObject(info.GetValue("template_classifications")) + _classifications = JsonSerializer.Deserialize(info.GetValue("template_classifications")) ?? throw new Exception("Deserialiation failed"); - _shortNameList = JsonConvert.DeserializeObject(info.GetValue("template_shortname")) + _shortNameList = JsonSerializer.Deserialize(info.GetValue("template_shortname")) ?? throw new Exception("Deserialiation failed"); #endif } @@ -273,17 +273,17 @@ public void Deserialize(IXunitSerializationInfo info) public void Serialize(IXunitSerializationInfo info) { info.AddValue("template_name", Name, typeof(string)); - info.AddValue("template_shortname", JsonConvert.SerializeObject(_shortNameList), typeof(string)); + info.AddValue("template_shortname", JsonSerializer.Serialize(_shortNameList), typeof(string)); info.AddValue("template_precedence", Precedence, typeof(int)); info.AddValue("template_identity", Identity, typeof(string)); info.AddValue("template_group", GroupIdentity, typeof(string)); info.AddValue("template_description", Description, typeof(string)); info.AddValue("template_author", Author, typeof(string)); - info.AddValue("template_tags", JsonConvert.SerializeObject(_tags), typeof(string)); - info.AddValue("template_params", JsonConvert.SerializeObject(_parameters), typeof(string)); - info.AddValue("template_baseline", JsonConvert.SerializeObject(_baselineInfo), typeof(string)); - info.AddValue("template_classifications", JsonConvert.SerializeObject(_classifications), typeof(string)); + info.AddValue("template_tags", JsonSerializer.Serialize(_tags), typeof(string)); + info.AddValue("template_params", JsonSerializer.Serialize(_parameters), typeof(string)); + info.AddValue("template_baseline", JsonSerializer.Serialize(_baselineInfo), typeof(string)); + info.AddValue("template_classifications", JsonSerializer.Serialize(_classifications), typeof(string)); } public override string ToString() diff --git a/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/BindSymbolTests.cs b/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/BindSymbolTests.cs index f46004a381e..146e59302d7 100644 --- a/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/BindSymbolTests.cs +++ b/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/BindSymbolTests.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json; +using System.Text.Json.Nodes; using FakeItEasy; using Microsoft.Extensions.Logging; using Microsoft.TemplateEngine.Abstractions; @@ -10,8 +12,6 @@ using Microsoft.TemplateEngine.Edge; using Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ConfigModel; using Microsoft.TemplateEngine.TestHelper; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests { @@ -82,7 +82,7 @@ public async Task CreateAsyncTest_UseBindValuesWithReplace() IDictionary templateSourceFiles = new Dictionary { // template.json - { TestFileSystemUtils.DefaultConfigRelativePath, JsonConvert.SerializeObject(templateConfig, Formatting.Indented) }, + { TestFileSystemUtils.DefaultConfigRelativePath, JsonSerializer.Serialize(templateConfig, new JsonSerializerOptions { WriteIndented = true }) }, { "sourceFile", sourceSnippet } }; @@ -101,7 +101,7 @@ public async Task CreateAsyncTest_UseBindValuesWithReplace() TestFileSystemUtils.WriteTemplateSource(settings, sourceBasePath, templateSourceFiles); using IMountPoint sourceMountPoint = settings.MountPath(sourceBasePath); RunnableProjectGenerator rpg = new RunnableProjectGenerator(); - TemplateConfigModel configModel = TemplateConfigModel.FromJObject(JObject.FromObject(templateConfig)); + TemplateConfigModel configModel = TemplateConfigModel.FromJObject(JsonNode.Parse(JsonSerializer.Serialize(templateConfig))!.AsObject()); using RunnableProjectConfig runnableConfig = new RunnableProjectConfig(settings, rpg, configModel, sourceMountPoint.Root); ParameterSetData parametersData = new ParameterSetData(runnableConfig); @@ -153,7 +153,7 @@ public async Task CreateAsyncTest_UseBindValuesWithFileRename() IDictionary templateSourceFiles = new Dictionary { // template.json - { TestFileSystemUtils.DefaultConfigRelativePath, JsonConvert.SerializeObject(templateConfig, Formatting.Indented) }, + { TestFileSystemUtils.DefaultConfigRelativePath, JsonSerializer.Serialize(templateConfig, new JsonSerializerOptions { WriteIndented = true }) }, //content { "_R1_.cs", string.Empty }, { "_R2_.cs", string.Empty } @@ -174,7 +174,7 @@ public async Task CreateAsyncTest_UseBindValuesWithFileRename() TestFileSystemUtils.WriteTemplateSource(settings, sourceBasePath, templateSourceFiles); using IMountPoint sourceMountPoint = settings.MountPath(sourceBasePath); RunnableProjectGenerator rpg = new RunnableProjectGenerator(); - TemplateConfigModel configModel = TemplateConfigModel.FromJObject(JObject.FromObject(templateConfig)); + TemplateConfigModel configModel = TemplateConfigModel.FromJObject(JsonNode.Parse(JsonSerializer.Serialize(templateConfig))!.AsObject()); using RunnableProjectConfig runnableConfig = new RunnableProjectConfig(settings, rpg, configModel, sourceMountPoint.Root); ParameterSetData parametersData = new ParameterSetData(runnableConfig); IDirectory sourceDir = sourceMountPoint!.DirectoryInfo("/")!; @@ -242,7 +242,7 @@ public async Task CreateAsyncTest_UseBindValuesInMacros() IDictionary templateSourceFiles = new Dictionary { // template.json - { TestFileSystemUtils.DefaultConfigRelativePath, JsonConvert.SerializeObject(templateConfig, Formatting.Indented) }, + { TestFileSystemUtils.DefaultConfigRelativePath, JsonSerializer.Serialize(templateConfig, new JsonSerializerOptions { WriteIndented = true }) }, //content { "sourceFile", sourceSnippet } }; @@ -258,7 +258,7 @@ public async Task CreateAsyncTest_UseBindValuesInMacros() TestFileSystemUtils.WriteTemplateSource(settings, sourceBasePath, templateSourceFiles); using IMountPoint sourceMountPoint = settings.MountPath(sourceBasePath); RunnableProjectGenerator rpg = new RunnableProjectGenerator(); - TemplateConfigModel configModel = TemplateConfigModel.FromJObject(JObject.FromObject(templateConfig)); + TemplateConfigModel configModel = TemplateConfigModel.FromJObject(JsonNode.Parse(JsonSerializer.Serialize(templateConfig))!.AsObject()); using RunnableProjectConfig runnableConfig = new RunnableProjectConfig(settings, rpg, configModel, sourceMountPoint.Root); ParameterSetData parametersData = new ParameterSetData(runnableConfig); IDirectory sourceDir = sourceMountPoint!.DirectoryInfo("/")!; @@ -319,7 +319,7 @@ public async Task CreateAsyncTest_BindingConflict() IDictionary templateSourceFiles = new Dictionary { // template.json - { TestFileSystemUtils.DefaultConfigRelativePath, JsonConvert.SerializeObject(templateConfig, Formatting.Indented) }, + { TestFileSystemUtils.DefaultConfigRelativePath, JsonSerializer.Serialize(templateConfig, new JsonSerializerOptions { WriteIndented = true }) }, //content { "sourceFile", sourceSnippet } }; @@ -344,7 +344,7 @@ public async Task CreateAsyncTest_BindingConflict() TestFileSystemUtils.WriteTemplateSource(settings, sourceBasePath, templateSourceFiles); using IMountPoint sourceMountPoint = settings.MountPath(sourceBasePath); RunnableProjectGenerator rpg = new RunnableProjectGenerator(); - TemplateConfigModel configModel = TemplateConfigModel.FromJObject(JObject.FromObject(templateConfig)); + TemplateConfigModel configModel = TemplateConfigModel.FromJObject(JsonNode.Parse(JsonSerializer.Serialize(templateConfig))!.AsObject()); using RunnableProjectConfig runnableConfig = new RunnableProjectConfig(settings, rpg, configModel, sourceMountPoint.Root); ParameterSetData parametersData = new ParameterSetData(runnableConfig); IDirectory sourceDir = sourceMountPoint!.DirectoryInfo("/")!; @@ -392,7 +392,7 @@ public async Task CreateAsyncTest_ForcedPrefixBinding() IDictionary templateSourceFiles = new Dictionary { // template.json - { TestFileSystemUtils.DefaultConfigRelativePath, JsonConvert.SerializeObject(templateConfig, Formatting.Indented) }, + { TestFileSystemUtils.DefaultConfigRelativePath, JsonSerializer.Serialize(templateConfig, new JsonSerializerOptions { WriteIndented = true }) }, //content { "sourceFile", sourceSnippet } }; @@ -417,7 +417,7 @@ public async Task CreateAsyncTest_ForcedPrefixBinding() TestFileSystemUtils.WriteTemplateSource(settings, sourceBasePath, templateSourceFiles); using IMountPoint sourceMountPoint = settings.MountPath(sourceBasePath); RunnableProjectGenerator rpg = new RunnableProjectGenerator(); - TemplateConfigModel configModel = TemplateConfigModel.FromJObject(JObject.FromObject(templateConfig)); + TemplateConfigModel configModel = TemplateConfigModel.FromJObject(JsonNode.Parse(JsonSerializer.Serialize(templateConfig))!.AsObject()); using RunnableProjectConfig runnableConfig = new RunnableProjectConfig(settings, rpg, configModel, sourceMountPoint.Root); ParameterSetData parametersData = new ParameterSetData(runnableConfig); IDirectory sourceDir = sourceMountPoint!.DirectoryInfo("/")!; @@ -490,7 +490,7 @@ public async Task CreateAsyncTest_CanUseDefaultValue() IDictionary templateSourceFiles = new Dictionary { // template.json - { TestFileSystemUtils.DefaultConfigRelativePath, JsonConvert.SerializeObject(templateConfig, Formatting.Indented) }, + { TestFileSystemUtils.DefaultConfigRelativePath, JsonSerializer.Serialize(templateConfig, new JsonSerializerOptions { WriteIndented = true }) }, //content { "sourceFile", sourceSnippet } }; @@ -510,7 +510,7 @@ public async Task CreateAsyncTest_CanUseDefaultValue() TestFileSystemUtils.WriteTemplateSource(settings, sourceBasePath, templateSourceFiles); using IMountPoint sourceMountPoint = settings.MountPath(sourceBasePath); RunnableProjectGenerator rpg = new RunnableProjectGenerator(); - TemplateConfigModel configModel = TemplateConfigModel.FromJObject(JObject.FromObject(templateConfig)); + TemplateConfigModel configModel = TemplateConfigModel.FromJObject(JsonNode.Parse(JsonSerializer.Serialize(templateConfig))!.AsObject()); using RunnableProjectConfig runnableConfig = new RunnableProjectConfig(settings, rpg, configModel, sourceMountPoint.Root); ParameterSetData parametersData = new ParameterSetData(runnableConfig); IDirectory sourceDir = sourceMountPoint!.DirectoryInfo("/")!; @@ -569,7 +569,7 @@ public async Task CreateAsyncTest_CanConvertValueToDataType() IDictionary templateSourceFiles = new Dictionary { // template.json - { TestFileSystemUtils.DefaultConfigRelativePath, JsonConvert.SerializeObject(templateConfig, Formatting.Indented) }, + { TestFileSystemUtils.DefaultConfigRelativePath, JsonSerializer.Serialize(templateConfig, new JsonSerializerOptions { WriteIndented = true }) }, //content { "sourceFile.cs", sourceSnippet } }; @@ -589,7 +589,7 @@ public async Task CreateAsyncTest_CanConvertValueToDataType() TestFileSystemUtils.WriteTemplateSource(settings, sourceBasePath, templateSourceFiles); using IMountPoint sourceMountPoint = settings.MountPath(sourceBasePath); RunnableProjectGenerator rpg = new RunnableProjectGenerator(); - TemplateConfigModel configModel = TemplateConfigModel.FromJObject(JObject.FromObject(templateConfig)); + TemplateConfigModel configModel = TemplateConfigModel.FromJObject(JsonNode.Parse(JsonSerializer.Serialize(templateConfig))!.AsObject()); RunnableProjectConfig runnableConfig = new RunnableProjectConfig(settings, rpg, configModel, sourceMountPoint.Root); ParameterSetData parametersData = new ParameterSetData(runnableConfig); IDirectory sourceDir = sourceMountPoint!.DirectoryInfo("/")!; @@ -649,7 +649,7 @@ public async Task CreateAsyncTest_NoWarningOnUnknownBindingWithDefaultValue() IDictionary templateSourceFiles = new Dictionary { // template.json - { TestFileSystemUtils.DefaultConfigRelativePath, JsonConvert.SerializeObject(templateConfig, Formatting.Indented) }, + { TestFileSystemUtils.DefaultConfigRelativePath, JsonSerializer.Serialize(templateConfig, new JsonSerializerOptions { WriteIndented = true }) }, //content { "sourceFile", sourceSnippet } }; @@ -669,7 +669,7 @@ public async Task CreateAsyncTest_NoWarningOnUnknownBindingWithDefaultValue() TestFileSystemUtils.WriteTemplateSource(settings, sourceBasePath, templateSourceFiles); using IMountPoint sourceMountPoint = settings.MountPath(sourceBasePath); RunnableProjectGenerator rpg = new RunnableProjectGenerator(); - TemplateConfigModel configModel = TemplateConfigModel.FromJObject(JObject.FromObject(templateConfig)); + TemplateConfigModel configModel = TemplateConfigModel.FromJObject(JsonNode.Parse(JsonSerializer.Serialize(templateConfig))!.AsObject()); RunnableProjectConfig runnableConfig = new RunnableProjectConfig(settings, rpg, configModel, sourceMountPoint.Root); ParameterSetData parametersData = new ParameterSetData(runnableConfig); IDirectory sourceDir = sourceMountPoint!.DirectoryInfo("/")!; diff --git a/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/MacroTests/ConstantMacroTests.cs b/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/MacroTests/ConstantMacroTests.cs index 83d6df9ef53..5fb69c72e42 100644 --- a/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/MacroTests/ConstantMacroTests.cs +++ b/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/MacroTests/ConstantMacroTests.cs @@ -68,7 +68,7 @@ public void GeneratedSymbolTest_Bool() IVariableCollection variables = new VariableCollection(); macro.Evaluate(_engineEnvironmentSettings, variables, symbol); - Assert.Equal("True", variables[variableName]); + Assert.Equal("true", variables[variableName]); } [Fact] diff --git a/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/MacroTests/SwtichMacroTests.cs b/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/MacroTests/SwtichMacroTests.cs index 4d0f51611fc..5a94b3e7962 100644 --- a/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/MacroTests/SwtichMacroTests.cs +++ b/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/MacroTests/SwtichMacroTests.cs @@ -53,20 +53,20 @@ public void GeneratedSymbolTest() string expectedValue = "this one"; string switchCases = @"[ { - 'condition': '(3 > 10)', - 'value': 'three greater than ten' + ""condition"": ""(3 > 10)"", + ""value"": ""three greater than ten"" }, { - 'condition': '(false)', - 'value': 'false value' + ""condition"": ""(false)"", + ""value"": ""false value"" }, { - 'condition': '(10 > 0)', - 'value': '" + expectedValue + @"' + ""condition"": ""(10 > 0)"", + ""value"": """ + expectedValue + @""" }, { - 'condition': '(5 > 4)', - 'value': 'not this one' + ""condition"": ""(5 > 4)"", + ""value"": ""not this one"" } ]"; @@ -136,10 +136,10 @@ public void InvalidConfigurationTest_MissingSymbolValue() string switchCases = /*lang=json*/ @"[ { - 'condition': '(3 > 10)', + ""condition"": ""(3 > 10)"" }, { - 'value': 'default' + ""value"": ""default"" } ]"; @@ -160,11 +160,11 @@ public void DefaultConfigurationTest() string switchCases = /*lang=json*/ @"[ { - 'condition': '(3 > 10)', - 'value': 'v' + ""condition"": ""(3 > 10)"", + ""value"": ""v"" }, { - 'value': 'default' + ""value"": ""default"" } ]"; diff --git a/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests.csproj b/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests.csproj index 68aa13cfed3..73604304db2 100644 --- a/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests.csproj +++ b/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests.csproj @@ -9,7 +9,7 @@ - + diff --git a/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/RunnableProjectConfigTests.cs b/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/RunnableProjectConfigTests.cs index 76a4880bde2..72f63b74e08 100644 --- a/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/RunnableProjectConfigTests.cs +++ b/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/RunnableProjectConfigTests.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json.Nodes; using FakeItEasy; using FluentAssertions; using Microsoft.Extensions.Logging; @@ -13,7 +14,6 @@ using Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests.Serialization; using Microsoft.TemplateEngine.Orchestrator.RunnableProjects.Validation; using Microsoft.TemplateEngine.TestHelper; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests { @@ -111,7 +111,7 @@ public async Task PerformTemplateValidation_ChoiceValuesValidation(string paramD Guid inputTestGuid = new("12aa8f4e-a4aa-4ac1-927c-94cb99485ef1"); string contentFileNamePrefix = "content - "; - JObject choiceParam = JObject.Parse(paramDefinition); + JsonObject choiceParam = JExtensions.ParseJsonObject(paramDefinition); choiceParam["AllowMultipleValues"] = isMultichoice; TemplateConfigModel config = new TemplateConfigModel("test") { @@ -181,8 +181,8 @@ public void VerifyComputedSymbolsParsedCorrectly() ShortNameList = new[] { "shortName" }, Symbols = new[] { - new ComputedSymbol("computed1", JObject.Parse(ValidComputedDefinition)), - new ComputedSymbol("computed2", JObject.Parse(ValidComputedDefinition)) + new ComputedSymbol("computed1", JExtensions.ParseJsonObject(ValidComputedDefinition)), + new ComputedSymbol("computed2", JExtensions.ParseJsonObject(ValidComputedDefinition)) } }; @@ -220,7 +220,7 @@ public void VerifyCustomGeneratedSymbolsParsedCorrectly() ShortNameList = new[] { "shortName" }, Symbols = new[] { - new GeneratedSymbol("fake1", JObject.Parse(ValidCustomMacroDefinition)) + new GeneratedSymbol("fake1", JExtensions.ParseJsonObject(ValidCustomMacroDefinition)) } }; diff --git a/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/RunnableProjectGeneratorTests.cs b/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/RunnableProjectGeneratorTests.cs index 361b26bc723..5f2f2707222 100644 --- a/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/RunnableProjectGeneratorTests.cs +++ b/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/RunnableProjectGeneratorTests.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json; +using System.Text.Json.Nodes; using Microsoft.TemplateEngine.Abstractions; using Microsoft.TemplateEngine.Abstractions.Mount; using Microsoft.TemplateEngine.Abstractions.Parameters; @@ -9,8 +11,6 @@ using Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests.Serialization; using Microsoft.TemplateEngine.TestHelper; using Microsoft.TemplateEngine.Utils; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests { @@ -622,7 +622,7 @@ public async Task Test_CoaleseWithInvalidSetup() IDictionary templateSourceFiles = new Dictionary { // template.json - { TestFileSystemUtils.DefaultConfigRelativePath, JsonConvert.SerializeObject(templateConfig, Formatting.Indented) }, + { TestFileSystemUtils.DefaultConfigRelativePath, JsonSerializer.Serialize(templateConfig, new JsonSerializerOptions { WriteIndented = true }) }, //content { "sourceFile", sourceSnippet } }; @@ -637,7 +637,7 @@ public async Task Test_CoaleseWithInvalidSetup() TestFileSystemUtils.WriteTemplateSource(settings, sourceBasePath, templateSourceFiles); using IMountPoint sourceMountPoint = settings.MountPath(sourceBasePath); RunnableProjectGenerator rpg = new RunnableProjectGenerator(); - TemplateConfigModel configModel = TemplateConfigModel.FromJObject(JObject.FromObject(templateConfig)); + TemplateConfigModel configModel = TemplateConfigModel.FromJObject(JsonNode.Parse(JsonSerializer.Serialize(templateConfig))!.AsObject()); using RunnableProjectConfig runnableConfig = new RunnableProjectConfig(settings, rpg, configModel, sourceMountPoint.Root); ParameterSetData parametersData = new ParameterSetData(runnableConfig); IDirectory sourceDir = sourceMountPoint!.DirectoryInfo("/")!; @@ -705,7 +705,7 @@ This text ensures that buffer is long enough even considering very-very-long env IDictionary templateSourceFiles = new Dictionary { // template.json - { TestFileSystemUtils.DefaultConfigRelativePath, JsonConvert.SerializeObject(templateConfig, Formatting.Indented) }, + { TestFileSystemUtils.DefaultConfigRelativePath, JsonSerializer.Serialize(templateConfig, new JsonSerializerOptions { WriteIndented = true }) }, //content { "sourceFile.md", sourceSnippet } @@ -722,7 +722,7 @@ This text ensures that buffer is long enough even considering very-very-long env using IMountPoint sourceMountPoint = settings.MountPath(sourceBasePath); RunnableProjectGenerator rpg = new(); - TemplateConfigModel configModel = TemplateConfigModel.FromJObject(JObject.FromObject(templateConfig)); + TemplateConfigModel configModel = TemplateConfigModel.FromJObject(JsonNode.Parse(JsonSerializer.Serialize(templateConfig))!.AsObject()); using RunnableProjectConfig runnableConfig = new RunnableProjectConfig(settings, rpg, configModel, sourceMountPoint.Root); ParameterSetData parameters = new( runnableConfig, @@ -791,7 +791,7 @@ This text ensures that buffer is long enough even considering very-very-long env IDictionary templateSourceFiles = new Dictionary { // template.json - { TestFileSystemUtils.DefaultConfigRelativePath, JsonConvert.SerializeObject(templateConfig, Formatting.Indented) }, + { TestFileSystemUtils.DefaultConfigRelativePath, JsonSerializer.Serialize(templateConfig, new JsonSerializerOptions { WriteIndented = true }) }, //content { "sourceFile.yaml", sourceSnippet } @@ -807,7 +807,7 @@ This text ensures that buffer is long enough even considering very-very-long env TestFileSystemUtils.WriteTemplateSource(settings, sourceBasePath, templateSourceFiles); using IMountPoint sourceMountPoint = settings.MountPath(sourceBasePath); RunnableProjectGenerator rpg = new(); - TemplateConfigModel configModel = TemplateConfigModel.FromJObject(JObject.FromObject(templateConfig)); + TemplateConfigModel configModel = TemplateConfigModel.FromJObject(JsonNode.Parse(JsonSerializer.Serialize(templateConfig))!.AsObject()); using RunnableProjectConfig runnableConfig = new RunnableProjectConfig(settings, rpg, configModel, sourceMountPoint.Root); ParameterSetData parameters = new( runnableConfig, diff --git a/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/ScanTests.cs b/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/ScanTests.cs index f4f63ff5bd0..33028c8605d 100644 --- a/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/ScanTests.cs +++ b/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/ScanTests.cs @@ -1,10 +1,10 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json; using Microsoft.TemplateEngine.Abstractions; using Microsoft.TemplateEngine.Abstractions.Mount; using Microsoft.TemplateEngine.TestHelper; -using Newtonsoft.Json; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests { @@ -43,7 +43,7 @@ public async Task CanReadPostActions() string templateConfigDir = Path.Combine(sourceBasePath, RunnableProjectGenerator.TemplateConfigDirectoryName); string filePath = Path.Combine(templateConfigDir, RunnableProjectGenerator.TemplateConfigFileName); environmentSettings.Host.FileSystem.CreateDirectory(templateConfigDir); - environmentSettings.Host.FileSystem.WriteAllText(filePath, JsonConvert.SerializeObject(jsonToBe)); + environmentSettings.Host.FileSystem.WriteAllText(filePath, JsonSerializer.Serialize(jsonToBe)); using IMountPoint mountPoint = environmentSettings.MountPath(sourceBasePath); RunnableProjectGenerator generator = new RunnableProjectGenerator(); diff --git a/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/SchemaTests/JSONSchemaTests.cs b/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/SchemaTests/JSONSchemaTests.cs index 68886b7105a..bae0bdb31a4 100644 --- a/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/SchemaTests/JSONSchemaTests.cs +++ b/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/SchemaTests/JSONSchemaTests.cs @@ -1,10 +1,10 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json; +using System.Text.Json.Nodes; +using Json.Schema; using Microsoft.TemplateEngine.Tests; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using Newtonsoft.Json.Schema; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests.SchemaTests { @@ -21,13 +21,21 @@ public class JSONSchemaTests : TestBase [InlineData(@"SchemaTests/ConditionalParametersTest.json")] public void IsJSONSchemaValid(string testFile) { - using TextReader schemaFileStream = File.OpenText(@"SchemaTests/template.json"); - JSchema schema = JSchema.Load(new JsonTextReader(schemaFileStream)); - using TextReader jsonFileStream = File.OpenText(testFile); - using JsonTextReader jsonReader = new JsonTextReader(jsonFileStream); - JObject templateConfig = (JObject)JToken.ReadFrom(jsonReader); + string schemaContent = File.ReadAllText(@"SchemaTests/template.json"); + var schema = JsonSchema.FromText(schemaContent); + + string jsonContent = File.ReadAllText(testFile); + var jsonNode = JsonNode.Parse(jsonContent, null, new JsonDocumentOptions { CommentHandling = JsonCommentHandling.Skip, AllowTrailingCommas = true }); + + var result = schema.Evaluate(jsonNode, new EvaluationOptions { OutputFormat = OutputFormat.List }); + + var errors = result.Details? + .Where(d => !d.IsValid && d.Errors != null) + .SelectMany(d => d.Errors!.Values) + .ToList() ?? new List(); + Assert.True( - templateConfig.IsValid(schema, out IList errors), + result.IsValid, "The JSON file is not valid against the schema" + Environment.NewLine + string.Join(Environment.NewLine, errors)); diff --git a/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/Serialization/Extensions.cs b/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/Serialization/Extensions.cs index 22f7acc1fc2..bc018d0a122 100644 --- a/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/Serialization/Extensions.cs +++ b/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/Serialization/Extensions.cs @@ -1,8 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json; using Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ConfigModel; -using Newtonsoft.Json; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests.Serialization { @@ -15,6 +15,6 @@ internal static class Extensions /// /// when attempting to serialize model which contains unsupported member. internal static string ToJsonString(this TemplateConfigModel templateConfigModel) - => JsonConvert.SerializeObject(templateConfigModel, Formatting.Indented, TemplateConfigModelJsonConverter.Instance, ParameterSymbolJsonConverter.Instance); + => JsonSerializer.Serialize(templateConfigModel, new JsonSerializerOptions { WriteIndented = true, Converters = { TemplateConfigModelJsonConverter.Instance, ParameterSymbolJsonConverter.Instance } }); } } diff --git a/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/Serialization/ParameterSymbolJsonConverter.cs b/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/Serialization/ParameterSymbolJsonConverter.cs index b61aa0c7a41..7c9170f4602 100644 --- a/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/Serialization/ParameterSymbolJsonConverter.cs +++ b/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/Serialization/ParameterSymbolJsonConverter.cs @@ -1,18 +1,19 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json; +using System.Text.Json.Serialization; using Microsoft.TemplateEngine.Abstractions; using Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ConfigModel; -using Newtonsoft.Json; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests.Serialization { internal class ParameterSymbolJsonConverter : JsonConverter { //falls back to default de-serializer if not implemented - public override ParameterSymbol ReadJson(JsonReader reader, Type objectType, ParameterSymbol? existingValue, bool hasExistingValue, JsonSerializer serializer) => throw new NotImplementedException(); + public override ParameterSymbol Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => throw new NotImplementedException(); - public override void WriteJson(JsonWriter writer, ParameterSymbol? value, JsonSerializer serializer) + public override void Write(Utf8JsonWriter writer, ParameterSymbol value, JsonSerializerOptions options) { if (value == null) { @@ -23,18 +24,18 @@ public override void WriteJson(JsonWriter writer, ParameterSymbol? value, JsonSe writer.WriteStartObject(); writer.WritePropertyName("type"); - writer.WriteValue(value.Type); + writer.WriteStringValue(value.Type); if (!string.IsNullOrEmpty(value.FileRename)) { writer.WritePropertyName("fileRename"); - writer.WriteValue(value.FileRename); + writer.WriteStringValue(value.FileRename); } if (!string.IsNullOrEmpty(value.Replaces)) { writer.WritePropertyName("replaces"); - writer.WriteValue(value.Replaces); + writer.WriteStringValue(value.Replaces); } if (value.ReplacementContexts.Any()) @@ -50,65 +51,65 @@ public override void WriteJson(JsonWriter writer, ParameterSymbol? value, JsonSe if (!string.IsNullOrEmpty(value.DefaultValue)) { writer.WritePropertyName("defaultValue"); - writer.WriteValue(value.DefaultValue); + writer.WriteStringValue(value.DefaultValue); } if (!string.IsNullOrEmpty(value.DataType)) { writer.WritePropertyName("datatype"); - writer.WriteValue(value.DataType); + writer.WriteStringValue(value.DataType); } if (!string.IsNullOrEmpty(value.DisplayName)) { writer.WritePropertyName("displayName"); - writer.WriteValue(value.DisplayName); + writer.WriteStringValue(value.DisplayName); } if (!string.IsNullOrEmpty(value.Description)) { writer.WritePropertyName("description"); - writer.WriteValue(value.Description); + writer.WriteStringValue(value.Description); } if (!string.IsNullOrEmpty(value.DefaultIfOptionWithoutValue) && value.DataType != "bool") { writer.WritePropertyName("defaultIfOptionWithoutValue"); - writer.WriteValue(value.DefaultIfOptionWithoutValue); + writer.WriteStringValue(value.DefaultIfOptionWithoutValue); } if (value.AllowMultipleValues) { writer.WritePropertyName("allowMultipleValues"); - writer.WriteValue(value.AllowMultipleValues); + writer.WriteBooleanValue(value.AllowMultipleValues); } if (value.EnableQuotelessLiterals) { writer.WritePropertyName("enableQuotelessLiterals"); - writer.WriteValue(value.EnableQuotelessLiterals); + writer.WriteBooleanValue(value.EnableQuotelessLiterals); } if (value.IsRequired) { writer.WritePropertyName("isRequired"); - writer.WriteValue(value.IsRequired); + writer.WriteBooleanValue(value.IsRequired); } else if (!string.IsNullOrEmpty(value.IsRequiredCondition)) { writer.WritePropertyName("isRequired"); - writer.WriteValue(value.IsRequiredCondition); + writer.WriteStringValue(value.IsRequiredCondition); } if (value.Precedence.PrecedenceDefinition == PrecedenceDefinition.Disabled) { writer.WritePropertyName("isEnabled"); - writer.WriteValue(false); + writer.WriteBooleanValue(false); } else if (!string.IsNullOrEmpty(value.IsEnabledCondition)) { writer.WritePropertyName("isEnabled"); - writer.WriteValue(value.IsEnabledCondition); + writer.WriteStringValue(value.IsEnabledCondition); } if (value.Choices != null) @@ -119,17 +120,17 @@ public override void WriteJson(JsonWriter writer, ParameterSymbol? value, JsonSe { writer.WriteStartObject(); writer.WritePropertyName("choice"); - writer.WriteValue(choice.Key); + writer.WriteStringValue(choice.Key); if (!string.IsNullOrEmpty(choice.Value.DisplayName)) { writer.WritePropertyName("displayName"); - writer.WriteValue(choice.Value.DisplayName); + writer.WriteStringValue(choice.Value.DisplayName); } if (!string.IsNullOrEmpty(choice.Value.Description)) { writer.WritePropertyName("description"); - writer.WriteValue(choice.Value.Description); + writer.WriteStringValue(choice.Value.Description); } writer.WriteEndObject(); } diff --git a/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/Serialization/TemplateConfigModelJsonConverter.cs b/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/Serialization/TemplateConfigModelJsonConverter.cs index 139938d8594..cc12f1dadaf 100644 --- a/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/Serialization/TemplateConfigModelJsonConverter.cs +++ b/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/Serialization/TemplateConfigModelJsonConverter.cs @@ -1,18 +1,19 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json; +using System.Text.Json.Serialization; using Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ConfigModel; -using Newtonsoft.Json; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests.Serialization { internal class TemplateConfigModelJsonConverter : JsonConverter { //falls back to default de-serializer if not implemented - public override TemplateConfigModel ReadJson(JsonReader reader, Type objectType, TemplateConfigModel? existingValue, bool hasExistingValue, JsonSerializer serializer) + public override TemplateConfigModel Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => throw new NotImplementedException(); - public override void WriteJson(JsonWriter writer, TemplateConfigModel? value, JsonSerializer serializer) + public override void Write(Utf8JsonWriter writer, TemplateConfigModel value, JsonSerializerOptions options) { if (value == null) { @@ -20,9 +21,9 @@ public override void WriteJson(JsonWriter writer, TemplateConfigModel? value, Js } writer.WriteStartObject(); writer.WritePropertyName("identity"); - writer.WriteValue(value.Identity); + writer.WriteStringValue(value.Identity); writer.WritePropertyName("name"); - writer.WriteValue(value.Name); + writer.WriteStringValue(value.Name); writer.WritePropertyName("shortName"); if (value.ShortNameList.Count > 1) @@ -32,74 +33,74 @@ public override void WriteJson(JsonWriter writer, TemplateConfigModel? value, Js { if (!string.IsNullOrEmpty(shortName)) { - writer.WriteValue(shortName); + writer.WriteStringValue(shortName); } } writer.WriteEndArray(); } else if (value.ShortNameList.Count == 1) { - writer.WriteValue(value.ShortNameList[0]); + writer.WriteStringValue(value.ShortNameList[0]); } else { - writer.WriteValue(string.Empty); + writer.WriteStringValue(string.Empty); } if (!string.IsNullOrEmpty(value.GroupIdentity)) { writer.WritePropertyName("groupIdentity"); - writer.WriteValue(value.GroupIdentity); + writer.WriteStringValue(value.GroupIdentity); } if (value.Precedence != 0) { writer.WritePropertyName("precedence"); - writer.WriteValue(value.Precedence); + writer.WriteNumberValue(value.Precedence); } if (!string.IsNullOrEmpty(value.Author)) { writer.WritePropertyName("author"); - writer.WriteValue(value.Author); + writer.WriteStringValue(value.Author); } if (!string.IsNullOrEmpty(value.Description)) { writer.WritePropertyName("description"); - writer.WriteValue(value.Description); + writer.WriteStringValue(value.Description); } if (!string.IsNullOrEmpty(value.ThirdPartyNotices)) { writer.WritePropertyName("thirdPartyNotices"); - writer.WriteValue(value.ThirdPartyNotices); + writer.WriteStringValue(value.ThirdPartyNotices); } if (!string.IsNullOrEmpty(value.DefaultName)) { writer.WritePropertyName("defaultName"); - writer.WriteValue(value.DefaultName); + writer.WriteStringValue(value.DefaultName); } if (!string.IsNullOrEmpty(value.SourceName)) { writer.WritePropertyName("sourceName"); - writer.WriteValue(value.SourceName); + writer.WriteStringValue(value.SourceName); } if (!string.IsNullOrEmpty(value.PlaceholderFilename)) { writer.WritePropertyName("placeholderFilename"); - writer.WriteValue(value.PlaceholderFilename); + writer.WriteStringValue(value.PlaceholderFilename); } if (!string.IsNullOrEmpty(value.GeneratorVersions)) { writer.WritePropertyName("generatorVersions"); - writer.WriteValue(value.GeneratorVersions); + writer.WriteStringValue(value.GeneratorVersions); } if (value.PreferNameDirectory) { writer.WritePropertyName("preferNameDirectory"); - writer.WriteValue(value.PreferNameDirectory); + writer.WriteBooleanValue(value.PreferNameDirectory); } if (value.PreferDefaultName) { writer.WritePropertyName("preferDefaultName"); - writer.WriteValue(value.PreferDefaultName); + writer.WriteBooleanValue(value.PreferDefaultName); } if (value.Classifications.Any()) @@ -110,7 +111,7 @@ public override void WriteJson(JsonWriter writer, TemplateConfigModel? value, Js { if (!string.IsNullOrEmpty(classification)) { - writer.WriteValue(classification); + writer.WriteStringValue(classification); } } writer.WriteEndArray(); @@ -122,7 +123,7 @@ public override void WriteJson(JsonWriter writer, TemplateConfigModel? value, Js writer.WriteStartArray(); foreach (Guid guid in value.Guids) { - writer.WriteValue(guid.ToString()); + writer.WriteStringValue(guid.ToString()); } writer.WriteEndArray(); } @@ -134,7 +135,7 @@ public override void WriteJson(JsonWriter writer, TemplateConfigModel? value, Js foreach (KeyValuePair tag in value.Tags) { writer.WritePropertyName(tag.Key); - writer.WriteValue(tag.Value); + writer.WriteStringValue(tag.Value); } writer.WriteEndObject(); } @@ -148,31 +149,31 @@ public override void WriteJson(JsonWriter writer, TemplateConfigModel? value, Js if (!string.IsNullOrEmpty(source.Source)) { writer.WritePropertyName("source"); - writer.WriteValue(source.Source); + writer.WriteStringValue(source.Source); } if (!string.IsNullOrEmpty(source.Target)) { writer.WritePropertyName("target"); - writer.WriteValue(source.Target); + writer.WriteStringValue(source.Target); } if (!string.IsNullOrEmpty(source.Condition)) { writer.WritePropertyName("condition"); - writer.WriteValue(source.Condition); + writer.WriteStringValue(source.Condition); } if (source.Include.Any()) { writer.WritePropertyName("include"); if (source.Include.Count == 1) { - writer.WriteValue(source.Include[0]); + writer.WriteStringValue(source.Include[0]); } else { writer.WriteStartArray(); foreach (string el in source.Include) { - writer.WriteValue(el); + writer.WriteStringValue(el); } writer.WriteEndArray(); } @@ -182,14 +183,14 @@ public override void WriteJson(JsonWriter writer, TemplateConfigModel? value, Js writer.WritePropertyName("exclude"); if (source.Exclude.Count == 1) { - writer.WriteValue(source.Exclude[0]); + writer.WriteStringValue(source.Exclude[0]); } else { writer.WriteStartArray(); foreach (string el in source.Exclude) { - writer.WriteValue(el); + writer.WriteStringValue(el); } writer.WriteEndArray(); } @@ -199,14 +200,14 @@ public override void WriteJson(JsonWriter writer, TemplateConfigModel? value, Js writer.WritePropertyName("copyOnly"); if (source.CopyOnly.Count == 1) { - writer.WriteValue(source.CopyOnly[0]); + writer.WriteStringValue(source.CopyOnly[0]); } else { writer.WriteStartArray(); foreach (string el in source.CopyOnly) { - writer.WriteValue(el); + writer.WriteStringValue(el); } writer.WriteEndArray(); } @@ -218,7 +219,7 @@ public override void WriteJson(JsonWriter writer, TemplateConfigModel? value, Js { writer.WriteStartObject(); writer.WritePropertyName(el.Key); - writer.WriteValue(el.Value); + writer.WriteStringValue(el.Value); writer.WriteEndObject(); } } @@ -232,21 +233,21 @@ public override void WriteJson(JsonWriter writer, TemplateConfigModel? value, Js if (!string.IsNullOrEmpty(mod.Condition)) { writer.WritePropertyName("condition"); - writer.WriteValue(mod.Condition); + writer.WriteStringValue(mod.Condition); } if (mod.Include.Any()) { writer.WritePropertyName("include"); if (mod.Include.Count == 1) { - writer.WriteValue(mod.Include[0]); + writer.WriteStringValue(mod.Include[0]); } else { writer.WriteStartArray(); foreach (string el in mod.Include) { - writer.WriteValue(el); + writer.WriteStringValue(el); } writer.WriteEndArray(); } @@ -256,14 +257,14 @@ public override void WriteJson(JsonWriter writer, TemplateConfigModel? value, Js writer.WritePropertyName("exclude"); if (mod.Exclude.Count == 1) { - writer.WriteValue(mod.Exclude[0]); + writer.WriteStringValue(mod.Exclude[0]); } else { writer.WriteStartArray(); foreach (string el in mod.Exclude) { - writer.WriteValue(el); + writer.WriteStringValue(el); } writer.WriteEndArray(); } @@ -273,14 +274,14 @@ public override void WriteJson(JsonWriter writer, TemplateConfigModel? value, Js writer.WritePropertyName("copyOnly"); if (mod.CopyOnly.Count == 1) { - writer.WriteValue(mod.CopyOnly[0]); + writer.WriteStringValue(mod.CopyOnly[0]); } else { writer.WriteStartArray(); foreach (string el in mod.CopyOnly) { - writer.WriteValue(el); + writer.WriteStringValue(el); } writer.WriteEndArray(); } @@ -292,7 +293,7 @@ public override void WriteJson(JsonWriter writer, TemplateConfigModel? value, Js { writer.WriteStartObject(); writer.WritePropertyName(el.Key); - writer.WriteValue(el.Value); + writer.WriteStringValue(el.Value); writer.WriteEndObject(); } } @@ -315,17 +316,17 @@ public override void WriteJson(JsonWriter writer, TemplateConfigModel? value, Js if (!string.IsNullOrEmpty(model.Id)) { writer.WritePropertyName("id"); - writer.WriteValue(model.Id); + writer.WriteStringValue(model.Id); } writer.WritePropertyName("actionId"); - writer.WriteValue(model.ActionId); + writer.WriteStringValue(model.ActionId); if (!string.IsNullOrEmpty(model.Description)) { writer.WritePropertyName("description"); - writer.WriteValue(model.Description); + writer.WriteStringValue(model.Description); } writer.WritePropertyName("continueOnError"); - writer.WriteValue(model.ContinueOnError); + writer.WriteBooleanValue(model.ContinueOnError); if (model.Args.Any()) { @@ -334,7 +335,7 @@ public override void WriteJson(JsonWriter writer, TemplateConfigModel? value, Js foreach (KeyValuePair arg in model.Args) { writer.WritePropertyName(arg.Key); - writer.WriteValue(arg.Value); + writer.WriteStringValue(arg.Value); } writer.WriteEndObject(); } @@ -347,16 +348,16 @@ public override void WriteJson(JsonWriter writer, TemplateConfigModel? value, Js { writer.WriteStartObject(); writer.WritePropertyName("text"); - writer.WriteValue(mi.Text); + writer.WriteStringValue(mi.Text); if (!string.IsNullOrEmpty(mi.Condition)) { writer.WritePropertyName("condition"); - writer.WriteValue(mi.Condition); + writer.WriteStringValue(mi.Condition); } if (!string.IsNullOrEmpty(mi.Id)) { writer.WritePropertyName("id"); - writer.WriteValue(mi.Id); + writer.WriteStringValue(mi.Id); } writer.WriteEndObject(); } @@ -387,7 +388,7 @@ public override void WriteJson(JsonWriter writer, TemplateConfigModel? value, Js { continue; } - serializer.Serialize(writer, p); + JsonSerializer.Serialize(writer, p, options); //writer.WriteRaw(JsonConvert.SerializeObject(p, ParameterSymbolJsonConverter.Instance)); } writer.WriteEndObject(); diff --git a/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/TemplateConfigTests/ConstraintsTest.cs b/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/TemplateConfigTests/ConstraintsTest.cs index bdc4c1db626..955d1f9b01f 100644 --- a/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/TemplateConfigTests/ConstraintsTest.cs +++ b/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/TemplateConfigTests/ConstraintsTest.cs @@ -1,10 +1,11 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json; +using System.Text.Json.Nodes; using Microsoft.Extensions.Logging; using Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ConfigModel; using Microsoft.TemplateEngine.TestHelper; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests.TemplateConfigTests { @@ -47,7 +48,7 @@ public void CanReadConstraintDefinition() } }; - var model = TemplateConfigModel.FromJObject(JObject.FromObject(json)); + var model = TemplateConfigModel.FromJObject(JsonNode.Parse(JsonSerializer.Serialize(json))!.AsObject()); Assert.Equal(4, model.Constraints.Count); Assert.Equal("con1", model.Constraints[0].Type); @@ -78,10 +79,10 @@ public void CannotReadConstraint_WhenTypeIsNotSet() List<(LogLevel, string)> loggedMessages = new List<(LogLevel, string)>(); InMemoryLoggerProvider loggerProvider = new InMemoryLoggerProvider(loggedMessages); - var model = TemplateConfigModel.FromJObject(JObject.FromObject(json), loggerProvider.CreateLogger("test")); + var model = TemplateConfigModel.FromJObject(JsonNode.Parse(JsonSerializer.Serialize(json))!.AsObject(), loggerProvider.CreateLogger("test")); Assert.Empty(model.Constraints); Assert.Single(loggedMessages); - Assert.Equal($"Constraint definition '{JObject.FromObject(new { args = "arg" })}' does not contain mandatory property 'type'.", loggedMessages.Single().Item2); + Assert.Equal($"Constraint definition '{JsonNode.Parse(JsonSerializer.Serialize(new { args = "arg" }))!.ToJsonString()}' does not contain mandatory property 'type'.", loggedMessages.Single().Item2); } [Fact] @@ -98,7 +99,7 @@ public void CannotReadConstraint_WhenArrayIsDenfined() List<(LogLevel, string)> loggedMessages = new List<(LogLevel, string)>(); InMemoryLoggerProvider loggerProvider = new InMemoryLoggerProvider(loggedMessages); - var model = TemplateConfigModel.FromJObject(JObject.FromObject(json), loggerProvider.CreateLogger("test")); + var model = TemplateConfigModel.FromJObject(JsonNode.Parse(JsonSerializer.Serialize(json))!.AsObject(), loggerProvider.CreateLogger("test")); Assert.Empty(model.Constraints); Assert.Single(loggedMessages); Assert.Equal("'constraints' should contain objects.", loggedMessages.Single().Item2); diff --git a/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/TemplateConfigTests/CustomConditionalTests.cs b/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/TemplateConfigTests/CustomConditionalTests.cs index 6a8e230ed6a..7aca9a3a587 100644 --- a/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/TemplateConfigTests/CustomConditionalTests.cs +++ b/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/TemplateConfigTests/CustomConditionalTests.cs @@ -1,12 +1,12 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json.Nodes; using FakeItEasy; using Microsoft.TemplateEngine.Abstractions.Mount; using Microsoft.TemplateEngine.Core.Contracts; using Microsoft.TemplateEngine.Core.Operations; using Microsoft.TemplateEngine.Orchestrator.RunnableProjects.OperationConfig; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests.TemplateConfigTests { @@ -14,7 +14,7 @@ public class CustomConditionalTests { // defines a template configuration with a custom conditional configuration. // The style is omitted, which implies custon - private static JObject CustomConditionalSetupNoStyleSpecification + private static JsonObject CustomConditionalSetupNoStyleSpecification { get { @@ -28,11 +28,11 @@ private static JObject CustomConditionalSetupNoStyleSpecification "wholeLine": "true", } """; - return JObject.Parse(configString); + return JExtensions.ParseJsonObject(configString); } } - private static JObject CustomConditionalSetupExplicitStyleSpecification + private static JsonObject CustomConditionalSetupExplicitStyleSpecification { get { @@ -47,11 +47,11 @@ private static JObject CustomConditionalSetupExplicitStyleSpecification "wholeLine": "true", } """; - return JObject.Parse(configString); + return JExtensions.ParseJsonObject(configString); } } - private static JObject LineConditionalSetup + private static JsonObject LineConditionalSetup { get { @@ -61,11 +61,11 @@ private static JObject LineConditionalSetup "token": "//" } """; - return JObject.Parse(configString); + return JExtensions.ParseJsonObject(configString); } } - private static JObject BlockConditionalSetup + private static JsonObject BlockConditionalSetup { get { @@ -77,7 +77,7 @@ private static JObject BlockConditionalSetup "pseudoEndToken": "* /" } """; - return JObject.Parse(configString); + return JExtensions.ParseJsonObject(configString); } } diff --git a/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/TemplateConfigTests/FileRenameTests.cs b/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/TemplateConfigTests/FileRenameTests.cs index dcee0ae64a1..836801538fa 100644 --- a/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/TemplateConfigTests/FileRenameTests.cs +++ b/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/TemplateConfigTests/FileRenameTests.cs @@ -10,7 +10,6 @@ using Microsoft.TemplateEngine.Core.Operations; using Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ConfigModel; using Microsoft.TemplateEngine.TestHelper; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests.TemplateConfigTests { @@ -168,7 +167,7 @@ public void CanReadFilenameReplacementConfig() } } """; - TemplateConfigModel configModel = TemplateConfigModel.FromJObject(JObject.Parse(configContent)); + TemplateConfigModel configModel = TemplateConfigModel.FromJObject(JExtensions.ParseJsonObject(configContent)); IEngineEnvironmentSettings environmentSettings = _environmentSettingsHelper.CreateEnvironment(); string sourceBasePath = environmentSettings.GetTempVirtualizedPath(); @@ -226,7 +225,7 @@ public void CanReadFilenameReplacementConfigWithForms() } } """; - TemplateConfigModel configModel = TemplateConfigModel.FromJObject(JObject.Parse(configContent)); + TemplateConfigModel configModel = TemplateConfigModel.FromJObject(JExtensions.ParseJsonObject(configContent)); IEngineEnvironmentSettings environmentSettings = _environmentSettingsHelper.CreateEnvironment(); string sourceBasePath = environmentSettings.GetTempVirtualizedPath(); diff --git a/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/TemplateConfigTests/LocalizationTests.cs b/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/TemplateConfigTests/LocalizationTests.cs index c6d1df84757..72bb8b8dde0 100644 --- a/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/TemplateConfigTests/LocalizationTests.cs +++ b/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/TemplateConfigTests/LocalizationTests.cs @@ -48,9 +48,9 @@ public void CanReadLocalizationFile(string fileContent, bool errorExpected) } [Theory] - [InlineData(/*lang=json*/ """{ name: "localizedName"}""", false, "localizedName")] - [InlineData(/*lang=json*/ """{ name: ""}""", false, "")] - [InlineData(/*lang=json*/ """{ notName: "localizedName"}""", false, null)] + [InlineData(/*lang=json,strict*/ """{ "name": "localizedName"}""", false, "localizedName")] + [InlineData(/*lang=json,strict*/ """{ "name": ""}""", false, "")] + [InlineData(/*lang=json,strict*/ """{ "notName": "localizedName"}""", false, null)] public void CanReadName(string fileContent, bool errorExpected, string? expectedName) { IEngineEnvironmentSettings environmentSettings = _environmentSettingsHelper.CreateEnvironment(virtualize: true); @@ -72,9 +72,9 @@ public void CanReadName(string fileContent, bool errorExpected, string? expected } [Theory] - [InlineData(/*lang=json*/ """{ description: "localizedDescription"}""", false, "localizedDescription")] - [InlineData(/*lang=json*/ """{ description: ""}""", false, "")] - [InlineData(/*lang=json*/ """{ notdescription: "localizedDescription"}""", false, null)] + [InlineData(/*lang=json,strict*/ """{ "description": "localizedDescription"}""", false, "localizedDescription")] + [InlineData(/*lang=json,strict*/ """{ "description": ""}""", false, "")] + [InlineData(/*lang=json,strict*/ """{ "notdescription": "localizedDescription"}""", false, null)] public void CanReadDescription(string fileContent, bool errorExpected, string? expectedDescription) { IEngineEnvironmentSettings environmentSettings = _environmentSettingsHelper.CreateEnvironment(virtualize: true); @@ -108,7 +108,7 @@ public void CanReadDescription(string fileContent, bool errorExpected, string? e "localizedSymbolDescription1|localizedSymbolDescription2")] [InlineData(/*lang=json,strict*/ """{ "symbols/someSymbol/displayName": "localizedSymbol" }""", false, "someSymbol", "localizedSymbol", "(null)")] [InlineData(/*lang=json,strict*/ """{ "symbols/someSymbol/description": "localizedSymbolDescription" }""", false, "someSymbol", "(null)", "localizedSymbolDescription")] - [InlineData(/*lang=json*/ """{ description: ""}""", false, null, null, null)] + [InlineData(/*lang=json,strict*/ """{ "description": ""}""", false, null, null, null)] // Test case for NullReferenceException fix: malformed symbol key with only "symbols/" prefix [InlineData(/*lang=json,strict*/ """{ "symbols/": "test" }""", false, null, null, null)] public void CanReadNonChoiceSymbol( @@ -171,7 +171,7 @@ public void CanReadNonChoiceSymbol( [InlineData(/*lang=json,strict*/ """{ "symbols/someSymbol/displayName": "localizedSymbol" }""", false, "someSymbol", "localizedSymbol", "(null)", "(null)")] [InlineData(/*lang=json,strict*/ """{ "symbols/someSymbol/description": "localizedSymbolDescription" }""", false, "someSymbol", "(null)", "localizedSymbolDescription", "(null)")] [InlineData(/*lang=json,strict*/ """{ "symbols/someSymbol/choices/one/displayName": "one-localized"}""", false, "someSymbol", "(null)", "(null)", "one*(null)*one-localized")] - [InlineData(/*lang=json*/ "{ description: \"\"}", false, null, null, null, null)] + [InlineData(/*lang=json,strict*/ "{ \"description\": \"\"}", false, null, null, null, null)] public void CanReadChoiceSymbol( string fileContent, bool errorExpected, @@ -243,7 +243,7 @@ public void CanReadChoiceSymbol( "pa0|pa1", "localizedDescription|localizedDescription", "first*firstLocalized%second*secondLocalized|first*firstLocalized")] - [InlineData(/*lang=json*/ """{ description: ""}""", false, null, null, null)] + [InlineData(/*lang=json,strict*/ """{ "description": ""}""", false, null, null, null)] [InlineData(/*lang=json,strict*/ """{ "postActions/pa0/description": "localizedDescription" }""", false, "pa0", "localizedDescription", "(null)")] [InlineData(/*lang=json,strict*/ """{ "postActions/pa0/manualInstructions/first/text": "localizedDescription" }""", false, "pa0", "(null)", "first*localizedDescription")] // Test case for NullReferenceException fix: malformed postAction key with only "postActions/" prefix diff --git a/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/TemplateConfigTests/PostActionTests.cs b/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/TemplateConfigTests/PostActionTests.cs index b6a821bf5e0..3de2f4e46b7 100644 --- a/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/TemplateConfigTests/PostActionTests.cs +++ b/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/TemplateConfigTests/PostActionTests.cs @@ -1,13 +1,13 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json.Nodes; using Microsoft.TemplateEngine.Abstractions; using Microsoft.TemplateEngine.Core; using Microsoft.TemplateEngine.Core.Contracts; using Microsoft.TemplateEngine.Core.Operations; using Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ConfigModel; using Microsoft.TemplateEngine.TestHelper; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests.TemplateConfigTests { @@ -20,7 +20,7 @@ public PostActionTests(EnvironmentSettingsHelper environmentSettingsHelper) _environmentSettings = environmentSettingsHelper.CreateEnvironment(virtualize: true); } - private static JObject TestTemplateJson + private static JsonObject TestTemplateJson { get { @@ -139,7 +139,7 @@ private static JObject TestTemplateJson ] } """; - return JObject.Parse(configString); + return JExtensions.ParseJsonObject(configString); } } @@ -317,7 +317,7 @@ public void CanReadFileRenameSettings() } """; - TemplateConfigModel configModel = TemplateConfigModel.FromJObject(JObject.Parse(configString)); + TemplateConfigModel configModel = TemplateConfigModel.FromJObject(JExtensions.ParseJsonObject(configString)); Assert.Single(configModel.PostActionModels); Assert.True(configModel.PostActionModels.Single().ApplyFileRenamesToManualInstructions); @@ -354,7 +354,7 @@ public void CanAddWarningOnWrongFileRenameConfig() } """; - TemplateConfigModel configModel = TemplateConfigModel.FromJObject(JObject.Parse(configString)); + TemplateConfigModel configModel = TemplateConfigModel.FromJObject(JExtensions.ParseJsonObject(configString)); Assert.Single(configModel.PostActionModels); Assert.True(configModel.PostActionModels.Single().ApplyFileRenamesToManualInstructions); @@ -410,7 +410,7 @@ public void CanApplyFileRenames() } """; - TemplateConfigModel configModel = TemplateConfigModel.FromJObject(JObject.Parse(configString)); + TemplateConfigModel configModel = TemplateConfigModel.FromJObject(JExtensions.ParseJsonObject(configString)); IVariableCollection vc = new VariableCollection { diff --git a/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/TemplateConfigTests/SymbolConfigTests.cs b/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/TemplateConfigTests/SymbolConfigTests.cs index 4ba0f74fae8..e5fcf8c1d08 100644 --- a/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/TemplateConfigTests/SymbolConfigTests.cs +++ b/test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/TemplateConfigTests/SymbolConfigTests.cs @@ -2,15 +2,16 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Runtime.InteropServices; +using System.Text.Json; +using System.Text.Json.Nodes; using Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ConfigModel; using Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ValueForms; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests.TemplateConfigTests { public class SymbolConfigTests { - private static JObject ArrayConfigForSymbolWithFormsButNotIdentity + private static JsonObject ArrayConfigForSymbolWithFormsButNotIdentity { get { @@ -35,11 +36,11 @@ private static JObject ArrayConfigForSymbolWithFormsButNotIdentity } } """; - return JObject.Parse(configString); + return JExtensions.ParseJsonObject(configString); } } - private static JObject ArrayConfigWithNameSymbolAndValueFormsButNotIdentity + private static JsonObject ArrayConfigWithNameSymbolAndValueFormsButNotIdentity { get { @@ -64,11 +65,11 @@ private static JObject ArrayConfigWithNameSymbolAndValueFormsButNotIdentity } } """; - return JObject.Parse(configString); + return JExtensions.ParseJsonObject(configString); } } - private static JObject ArrayConfigWithNameSymbolAndValueFormsWithIdentity + private static JsonObject ArrayConfigWithNameSymbolAndValueFormsWithIdentity { get { @@ -93,11 +94,11 @@ private static JObject ArrayConfigWithNameSymbolAndValueFormsWithIdentity } } """; - return JObject.Parse(configString); + return JExtensions.ParseJsonObject(configString); } } - private static JObject ObjectConfigNameSymbolWithIdentityFormAndAddIdentityFalse + private static JsonObject ObjectConfigNameSymbolWithIdentityFormAndAddIdentityFalse { get { @@ -125,11 +126,11 @@ private static JObject ObjectConfigNameSymbolWithIdentityFormAndAddIdentityFalse } } """; - return JObject.Parse(configString); + return JExtensions.ParseJsonObject(configString); } } - private static JObject ObjectConfigNameSymbolWithIdentityFormAndAddIdentityTrue + private static JsonObject ObjectConfigNameSymbolWithIdentityFormAndAddIdentityTrue { get { @@ -157,11 +158,11 @@ private static JObject ObjectConfigNameSymbolWithIdentityFormAndAddIdentityTrue } } """; - return JObject.Parse(configString); + return JExtensions.ParseJsonObject(configString); } } - private static JObject ConfigWithObjectValueFormDefinitionAddIdentityFalse + private static JsonObject ConfigWithObjectValueFormDefinitionAddIdentityFalse { get { @@ -189,11 +190,11 @@ private static JObject ConfigWithObjectValueFormDefinitionAddIdentityFalse } } """; - return JObject.Parse(configString); + return JExtensions.ParseJsonObject(configString); } } - private static JObject NameConfigWithObjectValueFormDefinitionAddIdentityTrue + private static JsonObject NameConfigWithObjectValueFormDefinitionAddIdentityTrue { get { @@ -221,11 +222,11 @@ private static JObject NameConfigWithObjectValueFormDefinitionAddIdentityTrue } } """; - return JObject.Parse(configString); + return JExtensions.ParseJsonObject(configString); } } - private static JObject NameConfigWithObjectValueFormDefinitionAddIdentityFalse + private static JsonObject NameConfigWithObjectValueFormDefinitionAddIdentityFalse { get { @@ -253,11 +254,11 @@ private static JObject NameConfigWithObjectValueFormDefinitionAddIdentityFalse } } """; - return JObject.Parse(configString); + return JExtensions.ParseJsonObject(configString); } } - private static JObject NameConfigObjectValueFormWithoutIdentityAndAddIdentityUnspecified + private static JsonObject NameConfigObjectValueFormWithoutIdentityAndAddIdentityUnspecified { get { @@ -284,11 +285,11 @@ private static JObject NameConfigObjectValueFormWithoutIdentityAndAddIdentityUns } } """; - return JObject.Parse(configString); + return JExtensions.ParseJsonObject(configString); } } - private static JObject NameConfigObjectValueFormWithIdentityAndAddIdentityUnspecified + private static JsonObject NameConfigObjectValueFormWithIdentityAndAddIdentityUnspecified { get { @@ -315,11 +316,11 @@ private static JObject NameConfigObjectValueFormWithIdentityAndAddIdentityUnspec } } """; - return JObject.Parse(configString); + return JExtensions.ParseJsonObject(configString); } } - private static JObject ConfigForSymbolWithoutValueForms + private static JsonObject ConfigForSymbolWithoutValueForms { get { @@ -341,11 +342,11 @@ private static JObject ConfigForSymbolWithoutValueForms } } """; - return JObject.Parse(configString); + return JExtensions.ParseJsonObject(configString); } } - private static JObject ArrayConfigForSymbolWithValueFormsIncludingIdentity + private static JsonObject ArrayConfigForSymbolWithValueFormsIncludingIdentity { get { @@ -370,11 +371,11 @@ private static JObject ArrayConfigForSymbolWithValueFormsIncludingIdentity } } """; - return JObject.Parse(configString); + return JExtensions.ParseJsonObject(configString); } } - private static JObject ConfigWithObjectValueFormDefinitionAddIdentityTrue + private static JsonObject ConfigWithObjectValueFormDefinitionAddIdentityTrue { get { @@ -402,11 +403,11 @@ private static JObject ConfigWithObjectValueFormDefinitionAddIdentityTrue } } """; - return JObject.Parse(configString); + return JExtensions.ParseJsonObject(configString); } } - private static JObject ObjectConfigParameterSymbolWithIdentityFormAndAddIdentityFalse + private static JsonObject ObjectConfigParameterSymbolWithIdentityFormAndAddIdentityFalse { get { @@ -434,11 +435,11 @@ private static JObject ObjectConfigParameterSymbolWithIdentityFormAndAddIdentity } } """; - return JObject.Parse(configString); + return JExtensions.ParseJsonObject(configString); } } - private static JObject ObjectConfigParameterSymbolWithIdentityFormAndAddIdentityTrue + private static JsonObject ObjectConfigParameterSymbolWithIdentityFormAndAddIdentityTrue { get { @@ -466,11 +467,11 @@ private static JObject ObjectConfigParameterSymbolWithIdentityFormAndAddIdentity } } """; - return JObject.Parse(configString); + return JExtensions.ParseJsonObject(configString); } } - private static JObject ParameterConfigObjectValueFormWithIdentityAndAddIdentityUnspecified + private static JsonObject ParameterConfigObjectValueFormWithIdentityAndAddIdentityUnspecified { get { @@ -497,11 +498,11 @@ private static JObject ParameterConfigObjectValueFormWithIdentityAndAddIdentityU } } """; - return JObject.Parse(configString); + return JExtensions.ParseJsonObject(configString); } } - private static JObject ParameterConfigObjectValueFormWithoutIdentityAndAddIdentityUnspecified + private static JsonObject ParameterConfigObjectValueFormWithoutIdentityAndAddIdentityUnspecified { get { @@ -528,7 +529,7 @@ private static JObject ParameterConfigObjectValueFormWithoutIdentityAndAddIdenti } } """; - return JObject.Parse(configString); + return JExtensions.ParseJsonObject(configString); } } @@ -889,7 +890,7 @@ public void DefaultSymbolsaAreSetup_OnReadingFromJson() }, } }; - TemplateConfigModel configModel = TemplateConfigModel.FromJObject(JObject.FromObject(templateConfig)); + TemplateConfigModel configModel = TemplateConfigModel.FromJObject(JsonNode.Parse(JsonSerializer.Serialize(templateConfig))!.AsObject()); bool isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); Assert.Single(configModel.Symbols, s => s.Name == "name"); Assert.Single(configModel.Symbols, s => s.Name == "other"); @@ -919,7 +920,7 @@ public void DefaultSymbolsaAreSetup_ImplicitBindWillNotOverwrite() }, } }; - TemplateConfigModel configModel = TemplateConfigModel.FromJObject(JObject.FromObject(templateConfig)); + TemplateConfigModel configModel = TemplateConfigModel.FromJObject(JsonNode.Parse(JsonSerializer.Serialize(templateConfig))!.AsObject()); Assert.Equal(2, configModel.Symbols.Count()); Assert.Single(configModel.Symbols, s => s.Name == "name"); Assert.Single(configModel.Symbols, s => s.Name == "OS"); diff --git a/test/Microsoft.TemplateEngine.TestTemplates/test_templates/Invalid/InvalidHostData/.template.config/template.json b/test/Microsoft.TemplateEngine.TestTemplates/test_templates/Invalid/InvalidHostData/.template.config/template.json index a3430682db9..52999f7bcbd 100644 --- a/test/Microsoft.TemplateEngine.TestTemplates/test_templates/Invalid/InvalidHostData/.template.config/template.json +++ b/test/Microsoft.TemplateEngine.TestTemplates/test_templates/Invalid/InvalidHostData/.template.config/template.json @@ -1,6 +1,5 @@ { "$schema": "https://json.schemastore.org/template.json", - "$schema": "http://json.schemastore.org/template", "author": "Test Asset", "classifications": [ "Config" diff --git a/test/Microsoft.TemplateEngine.TestTemplates/test_templates/SourceWithExcludeAndWithout/With/.template.config/template.json b/test/Microsoft.TemplateEngine.TestTemplates/test_templates/SourceWithExcludeAndWithout/With/.template.config/template.json index 0cb81f88c17..d7b3504f76d 100644 --- a/test/Microsoft.TemplateEngine.TestTemplates/test_templates/SourceWithExcludeAndWithout/With/.template.config/template.json +++ b/test/Microsoft.TemplateEngine.TestTemplates/test_templates/SourceWithExcludeAndWithout/With/.template.config/template.json @@ -1,6 +1,5 @@ { "$schema": "https://json.schemastore.org/template.json", - "$schema": "http://json.schemastore.org/template", "name": "Basic Template With Exclude", "identity": "TestAssets.BasicTemplateWithExclude", "shortName": "withexclude", diff --git a/test/Microsoft.TemplateEngine.TestTemplates/test_templates/SourceWithExcludeAndWithout/Without/.template.config/template.json b/test/Microsoft.TemplateEngine.TestTemplates/test_templates/SourceWithExcludeAndWithout/Without/.template.config/template.json index 66ed3815970..46ff60238e7 100644 --- a/test/Microsoft.TemplateEngine.TestTemplates/test_templates/SourceWithExcludeAndWithout/Without/.template.config/template.json +++ b/test/Microsoft.TemplateEngine.TestTemplates/test_templates/SourceWithExcludeAndWithout/Without/.template.config/template.json @@ -1,6 +1,5 @@ { "$schema": "https://json.schemastore.org/template.json", - "$schema": "http://json.schemastore.org/template", "name": "Basic Template Without Exclude", "identity": "TestAssets.BasicTemplateWithoutExclude", "shortName": "withoutexclude", diff --git a/test/Microsoft.TemplateEngine.TestTemplates/test_templates/TemplateConditionalProcessing/.template.config/template.json b/test/Microsoft.TemplateEngine.TestTemplates/test_templates/TemplateConditionalProcessing/.template.config/template.json index 4715586062a..0d8dc0a3952 100644 --- a/test/Microsoft.TemplateEngine.TestTemplates/test_templates/TemplateConditionalProcessing/.template.config/template.json +++ b/test/Microsoft.TemplateEngine.TestTemplates/test_templates/TemplateConditionalProcessing/.template.config/template.json @@ -1,6 +1,5 @@ { "$schema": "https://json.schemastore.org/template.json", - "$schema": "http://json.schemastore.org/template", "author": "Test Asset", "classifications": [ "Test Asset" ], "name": "TemplateConditionalProcessing", diff --git a/test/Microsoft.TemplateSearch.Common.UnitTests/NuGetMetadataSearchProviderTests.cs b/test/Microsoft.TemplateSearch.Common.UnitTests/NuGetMetadataSearchProviderTests.cs index 58311c309b7..b1d5df29871 100644 --- a/test/Microsoft.TemplateSearch.Common.UnitTests/NuGetMetadataSearchProviderTests.cs +++ b/test/Microsoft.TemplateSearch.Common.UnitTests/NuGetMetadataSearchProviderTests.cs @@ -1,12 +1,13 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json; +using System.Text.Json.Nodes; using Microsoft.TemplateEngine.Abstractions; using Microsoft.TemplateEngine.Mocks; using Microsoft.TemplateEngine.TestHelper; using Microsoft.TemplateSearch.Common.Abstractions; using Microsoft.TemplateSearch.Common.Providers; -using Newtonsoft.Json.Linq; using Xunit; namespace Microsoft.TemplateSearch.Common.UnitTests @@ -175,7 +176,7 @@ async Task> Search() [Fact] public async Task SearchReturnsErrorOnIncorrectCache() { - var jsonObject = JObject.FromObject(new { randomField = "smth" }); + var jsonObject = JsonNode.Parse(JsonSerializer.Serialize(new { randomField = "smth" }))!; string searchFilePath = Path.Combine(TestUtils.CreateTemporaryFolder(), "searchCacheV2.json"); File.WriteAllText(searchFilePath, jsonObject.ToString()); @@ -208,7 +209,7 @@ static IReadOnlyList Filter(TemplatePackageSearchData templatePac [Fact] public async Task SearchReturnsErrorOnIncorrectV1Cache() { - var jsonObject = JObject.FromObject(new { version = "1.0.0.0", randomField = "smth" }); + var jsonObject = JsonNode.Parse(JsonSerializer.Serialize(new { version = "1.0.0.0", randomField = "smth" }))!; string searchFilePath = Path.Combine(TestUtils.CreateTemporaryFolder(), "searchCache.json"); File.WriteAllText(searchFilePath, jsonObject.ToString()); @@ -241,7 +242,7 @@ static IReadOnlyList Filter(TemplatePackageSearchData templatePac [Fact] public async Task SearchReturnsErrorOnIncorrectV2Cache() { - var jsonObject = JObject.FromObject(new { version = "2.0", randomField = "smth" }); + var jsonObject = JsonNode.Parse(JsonSerializer.Serialize(new { version = "2.0", randomField = "smth" }))!; string searchFilePath = Path.Combine(TestUtils.CreateTemporaryFolder(), "searchCache.json"); File.WriteAllText(searchFilePath, jsonObject.ToString()); @@ -274,7 +275,7 @@ static IReadOnlyList Filter(TemplatePackageSearchData templatePac [Fact] public async Task SearchReturnsErrorOnIncorrectVersionCache() { - var jsonObject = JObject.FromObject(new { version = "3.0", TemplatePackages = Array.Empty() }); + var jsonObject = JsonNode.Parse(JsonSerializer.Serialize(new { version = "3.0", TemplatePackages = Array.Empty() }))!; string searchFilePath = Path.Combine(TestUtils.CreateTemporaryFolder(), "searchCache.json"); File.WriteAllText(searchFilePath, jsonObject.ToString()); diff --git a/test/Microsoft.TemplateSearch.Common.UnitTests/TemplateSearchCacheReaderTests.cs b/test/Microsoft.TemplateSearch.Common.UnitTests/TemplateSearchCacheReaderTests.cs index c416bca7308..a3b2a164233 100644 --- a/test/Microsoft.TemplateSearch.Common.UnitTests/TemplateSearchCacheReaderTests.cs +++ b/test/Microsoft.TemplateSearch.Common.UnitTests/TemplateSearchCacheReaderTests.cs @@ -1,14 +1,15 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json.Nodes; using FakeItEasy; using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.TemplateEngine; using Microsoft.TemplateEngine.Abstractions; using Microsoft.TemplateEngine.Mocks; using Microsoft.TemplateEngine.TestHelper; using Microsoft.TemplateSearch.Common.Abstractions; using Microsoft.TemplateSearch.Common.Providers; -using Newtonsoft.Json.Linq; using Xunit; namespace Microsoft.TemplateSearch.Common.UnitTests @@ -27,7 +28,7 @@ public void CanReadSearchMetadata() { var environmentSettings = _environmentSettingsHelper.CreateEnvironment(virtualize: true); string content = File.ReadAllText("NuGetTemplateSearchInfo.json"); - JObject cache = JObject.Parse(content); + JsonObject cache = JExtensions.ParseJsonObject(content); var parsedCache = TemplateSearchCache.FromJObject(cache, environmentSettings.Host.Logger); @@ -48,7 +49,7 @@ public void CanReadSearchMetadata_V2() { var environmentSettings = _environmentSettingsHelper.CreateEnvironment(virtualize: true); string content = File.ReadAllText("NuGetTemplateSearchInfo_v2.json"); - JObject cache = JObject.Parse(content); + JsonObject cache = JExtensions.ParseJsonObject(content); var parsedCache = TemplateSearchCache.FromJObject(cache, environmentSettings.Host.Logger); @@ -73,7 +74,7 @@ public void CanSkipInvalidEntriesSearchMetadata() { var environmentSettings = _environmentSettingsHelper.CreateEnvironment(virtualize: true); string content = File.ReadAllText("NuGetTemplateSearchInfoWithInvalidData.json"); - JObject cache = JObject.Parse(content); + JsonObject cache = JExtensions.ParseJsonObject(content); var parsedCache = TemplateSearchCache.FromJObject(cache, environmentSettings.Host.Logger); @@ -95,7 +96,7 @@ public async Task CanReadSearchMetadata_FromBlob() async Task Search() => await sourceFileProvider.GetSearchFileAsync(default); await TestUtils.AttemptSearch(3, TimeSpan.FromSeconds(10), Search); string content = environmentSettings.Host.FileSystem.ReadAllText(Path.Combine(environmentSettings.Paths.HostVersionSettingsDir, "nugetTemplateSearchInfo.json")); - var jObj = JObject.Parse(content); + var jObj = JExtensions.ParseJsonObject(content); Assert.NotNull(TemplateSearchCache.FromJObject(jObj, environmentSettings.Host.Logger, null)); } @@ -111,7 +112,7 @@ public async Task CanReadLegacySearchMetadata_FromBlob() async Task Search() => await sourceFileProvider.GetSearchFileAsync(default); await TestUtils.AttemptSearch(3, TimeSpan.FromSeconds(10), Search); string content = environmentSettings.Host.FileSystem.ReadAllText(Path.Combine(environmentSettings.Paths.HostVersionSettingsDir, "nugetTemplateSearchInfo.json")); - var jObj = JObject.Parse(content); + var jObj = JExtensions.ParseJsonObject(content); #pragma warning disable CS0618 // Type or member is obsolete Assert.True(LegacySearchCacheReader.TryReadDiscoveryMetadata(jObj, environmentSettings.Host.Logger, null, out _)); #pragma warning restore CS0618 // Type or member is obsolete @@ -142,7 +143,7 @@ public void CanReadSearchMetadata_V2_E2E() TemplatePackageSearchData package = new TemplatePackageSearchData(mockPackage, new[] { template }); TemplateSearchCache cache = new TemplateSearchCache(new[] { package }); - JObject jobj = cache.ToJObject(); + JsonObject jobj = cache.ToJObject(); TemplateSearchCache deserializedCache = TemplateSearchCache.FromJObject(jobj, NullLogger.Instance); diff --git a/test/Microsoft.TemplateSearch.TemplateDiscovery.IntegrationTests/NuGetTests.cs b/test/Microsoft.TemplateSearch.TemplateDiscovery.IntegrationTests/NuGetTests.cs index e3f6fcedb2b..785dda51e71 100644 --- a/test/Microsoft.TemplateSearch.TemplateDiscovery.IntegrationTests/NuGetTests.cs +++ b/test/Microsoft.TemplateSearch.TemplateDiscovery.IntegrationTests/NuGetTests.cs @@ -1,9 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json.Nodes; using FluentAssertions; using Microsoft.TemplateSearch.TemplateDiscovery.NuGet; -using Newtonsoft.Json.Linq; using NuGet.Protocol; using NuGet.Protocol.Core.Types; @@ -26,7 +26,7 @@ public async Task CanReadPackageInfo() { string responseText = await response.Content.ReadAsStringAsync(CancellationToken.None); - NuGetPackageSearchResult resultsForPage = NuGetPackageSearchResult.FromJObject(JObject.Parse(responseText)); + NuGetPackageSearchResult resultsForPage = NuGetPackageSearchResult.FromJObject(JsonNode.Parse(responseText)!.AsObject()); Assert.Equal(1, resultsForPage.TotalHits); Assert.Single(resultsForPage.Data); diff --git a/test/Microsoft.TemplateSearch.TemplateDiscovery.IntegrationTests/TemplateDiscoveryTests.cs b/test/Microsoft.TemplateSearch.TemplateDiscovery.IntegrationTests/TemplateDiscoveryTests.cs index 6d92a05affb..f31041934d2 100644 --- a/test/Microsoft.TemplateSearch.TemplateDiscovery.IntegrationTests/TemplateDiscoveryTests.cs +++ b/test/Microsoft.TemplateSearch.TemplateDiscovery.IntegrationTests/TemplateDiscoveryTests.cs @@ -1,10 +1,10 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json.Nodes; using Microsoft.TemplateEngine.CommandUtils; using Microsoft.TemplateEngine.TestHelper; using Microsoft.TemplateEngine.Tests; -using Newtonsoft.Json.Linq; using Xunit.Abstractions; namespace Microsoft.TemplateSearch.TemplateDiscovery.IntegrationTests @@ -113,10 +113,10 @@ public void CanReadAuthor() .Should() .ExitWith(0); - var jObjectV1 = JObject.Parse(File.ReadAllText(Path.Combine(testDir, "SearchCache", "NuGetTemplateSearchInfo.json")))!; - Assert.Equal("TestAuthor", jObjectV1!["PackToTemplateMap"]!.Children().Single(p => p.Name.StartsWith("Microsoft.TemplateEngine.TestTemplates")).Value["Owners"]!.Values().Single()); - var jObjectV2 = JObject.Parse(File.ReadAllText(Path.Combine(testDir, "SearchCache", "NuGetTemplateSearchInfoVer2.json")))!; - Assert.Equal("TestAuthor", jObjectV2!["TemplatePackages"]![0]!["Owners"]!.Value()); + var jObjectV1 = JsonNode.Parse(File.ReadAllText(Path.Combine(testDir, "SearchCache", "NuGetTemplateSearchInfo.json")))!.AsObject(); + Assert.Equal("TestAuthor", jObjectV1!["PackToTemplateMap"]!.AsObject().Single(p => p.Key.StartsWith("Microsoft.TemplateEngine.TestTemplates")).Value!["Owners"]!.AsArray().Select(n => n!.GetValue()).Single()); + var jObjectV2 = JsonNode.Parse(File.ReadAllText(Path.Combine(testDir, "SearchCache", "NuGetTemplateSearchInfoVer2.json")))!.AsObject(); + Assert.Equal("TestAuthor", jObjectV2!["TemplatePackages"]![0]!["Owners"]!.GetValue()); } [Fact] @@ -138,8 +138,8 @@ public void CanReadDescription() .Should() .ExitWith(0); - var jObjectV2 = JObject.Parse(File.ReadAllText(Path.Combine(testDir, "SearchCache", "NuGetTemplateSearchInfoVer2.json")))!; - Assert.Equal("description", jObjectV2!["TemplatePackages"]![0]!["Description"]!.Value()); + var jObjectV2 = JsonNode.Parse(File.ReadAllText(Path.Combine(testDir, "SearchCache", "NuGetTemplateSearchInfoVer2.json")))!.AsObject(); + Assert.Equal("description", jObjectV2!["TemplatePackages"]![0]!["Description"]!.GetValue()); } [Fact] @@ -161,8 +161,8 @@ public void CanReadIconUrl() .Should() .ExitWith(0); - var jObjectV2 = JObject.Parse(File.ReadAllText(Path.Combine(testDir, "SearchCache", "NuGetTemplateSearchInfoVer2.json")))!; - Assert.Equal("https://icon", jObjectV2!["TemplatePackages"]![0]!["IconUrl"]!.Value()); + var jObjectV2 = JsonNode.Parse(File.ReadAllText(Path.Combine(testDir, "SearchCache", "NuGetTemplateSearchInfoVer2.json")))!.AsObject(); + Assert.Equal("https://icon", jObjectV2!["TemplatePackages"]![0]!["IconUrl"]!.GetValue()); } [Fact] @@ -246,10 +246,10 @@ public async Task CanDetectNewPackagesInDiffMode() Assert.True(File.Exists(cacheV2Path)); Assert.True(File.Exists(nonTemplatePackagesList)); - var jObjectV1 = JObject.Parse(File.ReadAllText(cacheV1Path)); - Assert.Equal(2, jObjectV1["PackToTemplateMap"]?.Children().Count()); - var jObjectV2 = JObject.Parse(File.ReadAllText(cacheV2Path)); - Assert.Equal(2, jObjectV2["TemplatePackages"]?.Count()); + var jObjectV1 = JsonNode.Parse(File.ReadAllText(cacheV1Path))!.AsObject(); + Assert.Equal(2, jObjectV1["PackToTemplateMap"]?.AsObject().Count); + var jObjectV2 = JsonNode.Parse(File.ReadAllText(cacheV2Path))!.AsObject(); + Assert.Equal(2, jObjectV2["TemplatePackages"]?.AsArray().Count); } [Fact] @@ -332,11 +332,11 @@ public void CanDetectUpdatedPackagesInDiffMode() Assert.True(File.Exists(cacheV2Path)); Assert.True(File.Exists(nonTemplatePackagesList)); - var jObjectV1 = JObject.Parse(File.ReadAllText(cacheV1Path)); - Assert.Equal(1, jObjectV1["PackToTemplateMap"]?.Children().Count()); - var jObjectV2 = JObject.Parse(File.ReadAllText(cacheV2Path)); - Assert.Equal(1, jObjectV2["TemplatePackages"]?.Count()); - Assert.Equal("1.0.1", jObjectV2["TemplatePackages"]?[0]?["Version"]?.Value()); + var jObjectV1 = JsonNode.Parse(File.ReadAllText(cacheV1Path))!.AsObject(); + Assert.Equal(1, jObjectV1["PackToTemplateMap"]?.AsObject().Count); + var jObjectV2 = JsonNode.Parse(File.ReadAllText(cacheV2Path))!.AsObject(); + Assert.Equal(1, jObjectV2["TemplatePackages"]?.AsArray().Count); + Assert.Equal("1.0.1", jObjectV2["TemplatePackages"]?[0]?["Version"]?.GetValue()); } [Fact] @@ -424,10 +424,10 @@ public void CanDetectRemovedPackagesInDiffMode() Assert.True(File.Exists(cacheV2Path)); Assert.True(File.Exists(nonTemplatePackagesList)); - var jObjectV1 = JObject.Parse(File.ReadAllText(cacheV1Path)); - Assert.Equal(0, jObjectV1["PackToTemplateMap"]?.Children().Count()); - var jObjectV2 = JObject.Parse(File.ReadAllText(cacheV2Path)); - Assert.Equal(0, jObjectV2["TemplatePackages"]?.Count()); + var jObjectV1 = JsonNode.Parse(File.ReadAllText(cacheV1Path))!.AsObject(); + Assert.Equal(0, jObjectV1["PackToTemplateMap"]?.AsObject().Count); + var jObjectV2 = JsonNode.Parse(File.ReadAllText(cacheV2Path))!.AsObject(); + Assert.Equal(0, jObjectV2["TemplatePackages"]?.AsArray().Count); } #pragma warning disable xUnit1004 // Test methods should not be skipped diff --git a/tools/Microsoft.TemplateSearch.TemplateDiscovery/AdditionalData/CliHostSearchCacheData.cs b/tools/Microsoft.TemplateSearch.TemplateDiscovery/AdditionalData/CliHostSearchCacheData.cs index c1b7be0b2bc..ef33279cd73 100644 --- a/tools/Microsoft.TemplateSearch.TemplateDiscovery/AdditionalData/CliHostSearchCacheData.cs +++ b/tools/Microsoft.TemplateSearch.TemplateDiscovery/AdditionalData/CliHostSearchCacheData.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using Newtonsoft.Json.Linq; +using System.Text.Json.Nodes; namespace Microsoft.TemplateSearch.TemplateDiscovery.AdditionalData { @@ -12,28 +12,28 @@ public static class CliHostSearchCacheData public static Func Reader => (obj) => { - if (obj is not JObject cacheObject) + if (obj is not JsonObject cacheObject) { return CliHostTemplateData.Default; } try { - if (HostDataPropertyNames.Contains(cacheObject.Properties().First().Name, StringComparer.OrdinalIgnoreCase)) + if (HostDataPropertyNames.Contains(cacheObject.First().Key, StringComparer.OrdinalIgnoreCase)) { return new CliHostTemplateData(cacheObject); } //fallback to old behavior Dictionary cliData = new Dictionary(); - foreach (JProperty data in cacheObject.Properties()) + foreach (var data in cacheObject) { try { - cliData[data.Name] = new CliHostTemplateData(data.Value as JObject); + cliData[data.Key] = new CliHostTemplateData(data.Value as JsonObject); } catch (Exception ex) { - Console.Error.WriteLine($"Error deserializing the cli host specific template data for template {data.Name}, details:{ex}"); + Console.Error.WriteLine($"Error deserializing the cli host specific template data for template {data.Key}, details:{ex}"); } } return cliData; diff --git a/tools/Microsoft.TemplateSearch.TemplateDiscovery/AdditionalData/CliHostTemplateData.cs b/tools/Microsoft.TemplateSearch.TemplateDiscovery/AdditionalData/CliHostTemplateData.cs index b86573d9149..6c4a78df976 100644 --- a/tools/Microsoft.TemplateSearch.TemplateDiscovery/AdditionalData/CliHostTemplateData.cs +++ b/tools/Microsoft.TemplateSearch.TemplateDiscovery/AdditionalData/CliHostTemplateData.cs @@ -1,12 +1,12 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; +using System.Text.Json; +using System.Text.Json.Nodes; namespace Microsoft.TemplateSearch.TemplateDiscovery.AdditionalData { - [JsonConverter(typeof(CliHostTemplateData.CustomJsonConverter))] + [System.Text.Json.Serialization.JsonConverter(typeof(CliHostTemplateData.CustomJsonConverter))] internal class CliHostTemplateData { private const string IsHiddenKey = "isHidden"; @@ -14,7 +14,7 @@ internal class CliHostTemplateData private const string ShortNameKey = "shortName"; private const string AlwaysShowKey = "alwaysShow"; - internal CliHostTemplateData(JObject? jObject) + internal CliHostTemplateData(JsonObject? jObject) { var symbolsInfo = new Dictionary>(); @@ -24,33 +24,37 @@ internal CliHostTemplateData(JObject? jObject) return; } - if (jObject.GetValue(nameof(UsageExamples), StringComparison.OrdinalIgnoreCase) is JArray usagesArray) + JsonNode? usagesNode = Microsoft.TemplateEngine.JExtensions.GetPropertyCaseInsensitive(jObject, nameof(UsageExamples)); + if (usagesNode is JsonArray usagesArray) { - UsageExamples = new List(usagesArray.Values().Where(v => v != null).OfType()); + UsageExamples = new List(usagesArray.Select(v => v?.ToString()).Where(v => v != null).OfType()); } - if (jObject.GetValue(nameof(SymbolInfo), StringComparison.OrdinalIgnoreCase) is JObject symbols) + JsonNode? symbolsNode = Microsoft.TemplateEngine.JExtensions.GetPropertyCaseInsensitive(jObject, nameof(SymbolInfo)); + if (symbolsNode is JsonObject symbols) { - foreach (var symbolInfo in symbols.Properties()) + foreach (var symbolInfo in symbols) { - if (symbolInfo.Value is not JObject symbol) + if (symbolInfo.Value is not JsonObject symbol) { continue; } var symbolProperties = new Dictionary(); - foreach (var symbolProperty in symbol.Properties()) + foreach (var symbolProperty in symbol) { - symbolProperties[symbolProperty.Name] = symbolProperty.Value.Value() ?? string.Empty; + symbolProperties[symbolProperty.Key] = symbolProperty.Value?.ToString() ?? string.Empty; } - symbolsInfo[symbolInfo.Name] = symbolProperties; + symbolsInfo[symbolInfo.Key] = symbolProperties; } } SymbolInfo = symbolsInfo; - IsHidden = jObject.Value(nameof(IsHidden)); + IsHidden = jObject.TryGetPropertyValue(nameof(IsHidden), out JsonNode? isHiddenNode) + && isHiddenNode is JsonValue isHiddenVal + && isHiddenVal.TryGetValue(out bool boolVal) && boolVal; } @@ -157,11 +161,11 @@ internal string DisplayNameForParameter(string parameterName) return parameterName; } - private class CustomJsonConverter : JsonConverter + private class CustomJsonConverter : System.Text.Json.Serialization.JsonConverter { - public override CliHostTemplateData ReadJson(JsonReader reader, Type objectType, CliHostTemplateData? existingValue, bool hasExistingValue, JsonSerializer serializer) => throw new NotImplementedException(); + public override CliHostTemplateData Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => throw new NotImplementedException(); - public override void WriteJson(JsonWriter writer, CliHostTemplateData? value, JsonSerializer serializer) + public override void Write(Utf8JsonWriter writer, CliHostTemplateData value, JsonSerializerOptions options) { if (value == null) { @@ -171,12 +175,12 @@ public override void WriteJson(JsonWriter writer, CliHostTemplateData? value, Js if (value.IsHidden) { writer.WritePropertyName(nameof(IsHidden)); - writer.WriteValue(value.IsHidden); + writer.WriteBooleanValue(value.IsHidden); } if (value.SymbolInfo.Any()) { writer.WritePropertyName(nameof(SymbolInfo)); - serializer.Serialize(writer, value.SymbolInfo); + JsonSerializer.Serialize(writer, value.SymbolInfo, options); } if (value.UsageExamples != null && value.UsageExamples.Any(e => !string.IsNullOrWhiteSpace(e))) @@ -187,7 +191,7 @@ public override void WriteJson(JsonWriter writer, CliHostTemplateData? value, Js { if (!string.IsNullOrWhiteSpace(example)) { - writer.WriteValue(example); + writer.WriteStringValue(example); } } writer.WriteEndArray(); diff --git a/tools/Microsoft.TemplateSearch.TemplateDiscovery/AdditionalData/CliHostTemplateDataLoader.cs b/tools/Microsoft.TemplateSearch.TemplateDiscovery/AdditionalData/CliHostTemplateDataLoader.cs index 1e047528c2c..3a1f9080a19 100644 --- a/tools/Microsoft.TemplateSearch.TemplateDiscovery/AdditionalData/CliHostTemplateDataLoader.cs +++ b/tools/Microsoft.TemplateSearch.TemplateDiscovery/AdditionalData/CliHostTemplateDataLoader.cs @@ -1,12 +1,12 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json.Nodes; +using Microsoft.TemplateEngine; using Microsoft.TemplateEngine.Abstractions; using Microsoft.TemplateEngine.Abstractions.Mount; using Microsoft.TemplateEngine.Edge.Settings; using Microsoft.TemplateEngine.Utils; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateSearch.TemplateDiscovery.AdditionalData { @@ -29,7 +29,7 @@ internal CliHostTemplateData ReadHostSpecificTemplateData(ITemplateInfo template { if (!string.IsNullOrWhiteSpace(hostData)) { - JObject jObject = JObject.Parse(hostData); + JsonObject jObject = JExtensions.ParseJsonObject(hostData); return new CliHostTemplateData(jObject); } } @@ -52,8 +52,8 @@ internal CliHostTemplateData ReadHostSpecificTemplateData(ITemplateInfo template { using Stream stream = file.OpenRead(); using TextReader textReader = new StreamReader(stream, true); - using JsonReader jsonReader = new JsonTextReader(textReader); - var jsonData = JObject.Load(jsonReader); + string jsonContent = textReader.ReadToEnd(); + var jsonData = JExtensions.ParseJsonObject(jsonContent); return new CliHostTemplateData(jsonData); } diff --git a/tools/Microsoft.TemplateSearch.TemplateDiscovery/Filters/FilterNonMicrosoftAuthors.cs b/tools/Microsoft.TemplateSearch.TemplateDiscovery/Filters/FilterNonMicrosoftAuthors.cs index 95f687bfe4d..d0158060c38 100644 --- a/tools/Microsoft.TemplateSearch.TemplateDiscovery/Filters/FilterNonMicrosoftAuthors.cs +++ b/tools/Microsoft.TemplateSearch.TemplateDiscovery/Filters/FilterNonMicrosoftAuthors.cs @@ -1,12 +1,11 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using Microsoft.TemplateEngine; using Microsoft.TemplateEngine.Abstractions; using Microsoft.TemplateEngine.Abstractions.Mount; using Microsoft.TemplateEngine.Edge; using Microsoft.TemplateSearch.TemplateDiscovery.PackChecking; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateSearch.TemplateDiscovery.Filters; @@ -35,9 +34,8 @@ static PreFilterResult Filter(IDownloadedPackInfo packInfo) try { using var streamReader = new StreamReader(templateJson.OpenRead()); - using var jsonReader = new JsonTextReader(streamReader); - var jObject = JObject.Load(jsonReader); - var author = jObject["author"]?.Value(); + var jObject = JExtensions.ParseJsonObject(streamReader.ReadToEnd()); + var author = jObject.ToString("author"); if (author?.Contains("microsoft", StringComparison.OrdinalIgnoreCase) ?? false) { return new PreFilterResult(FilterId, isFiltered: true, $"{templateJson.FullPath} has Author=Microsoft and package id is {packInfo.Name}"); diff --git a/tools/Microsoft.TemplateSearch.TemplateDiscovery/Microsoft.TemplateSearch.TemplateDiscovery.csproj b/tools/Microsoft.TemplateSearch.TemplateDiscovery/Microsoft.TemplateSearch.TemplateDiscovery.csproj index 1c0b8572ebf..3824b7cbca6 100644 --- a/tools/Microsoft.TemplateSearch.TemplateDiscovery/Microsoft.TemplateSearch.TemplateDiscovery.csproj +++ b/tools/Microsoft.TemplateSearch.TemplateDiscovery/Microsoft.TemplateSearch.TemplateDiscovery.csproj @@ -13,7 +13,6 @@ - diff --git a/tools/Microsoft.TemplateSearch.TemplateDiscovery/NuGet/NuGetPackSourceCheckerFactory.cs b/tools/Microsoft.TemplateSearch.TemplateDiscovery/NuGet/NuGetPackSourceCheckerFactory.cs index 253f4094d6b..bce56e4e1c8 100644 --- a/tools/Microsoft.TemplateSearch.TemplateDiscovery/NuGet/NuGetPackSourceCheckerFactory.cs +++ b/tools/Microsoft.TemplateSearch.TemplateDiscovery/NuGet/NuGetPackSourceCheckerFactory.cs @@ -2,13 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Net; +using System.Text.Json; +using System.Text.Json.Nodes; using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.TemplateEngine; using Microsoft.TemplateSearch.Common; using Microsoft.TemplateSearch.TemplateDiscovery.AdditionalData; using Microsoft.TemplateSearch.TemplateDiscovery.Filters; using Microsoft.TemplateSearch.TemplateDiscovery.PackChecking; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateSearch.TemplateDiscovery.NuGet { @@ -72,9 +73,7 @@ public async Task CreatePackSourceCheckerAsync(CommandArgs co Verbose.WriteLine($"Opening {fileLocation.FullName}"); using var fileStream = fileLocation.OpenRead(); - using var textReader = new StreamReader(fileStream, System.Text.Encoding.UTF8, true); - using var jsonReader = new JsonTextReader(textReader); - return new JsonSerializer().Deserialize>(jsonReader); + return JsonSerializer.Deserialize>(fileStream); } private static async Task LoadExistingCacheAsync(CommandArgs config, CancellationToken cancellationToken) @@ -93,9 +92,8 @@ public async Task CreatePackSourceCheckerAsync(CommandArgs co } Verbose.WriteLine($"Opening {cacheFileLocation.FullName}"); using var fileStream = cacheFileLocation.OpenRead(); - using var textReader = new StreamReader(fileStream, System.Text.Encoding.UTF8, true); - using var jsonReader = new JsonTextReader(textReader); - return TemplateSearchCache.FromJObject(JObject.Load(jsonReader), NullLogger.Instance, new Dictionary>() { { CliHostSearchCacheData.DataName, CliHostSearchCacheData.Reader } }); + JsonObject cacheObject = JExtensions.ParseJsonObject(new StreamReader(fileStream, System.Text.Encoding.UTF8, true).ReadToEnd()); + return TemplateSearchCache.FromJObject(cacheObject, NullLogger.Instance, new Dictionary>() { { CliHostSearchCacheData.DataName, CliHostSearchCacheData.Reader } }); } private static async Task DownloadUriToFileAsync(string uri, string filePath, CancellationToken cancellationToken) diff --git a/tools/Microsoft.TemplateSearch.TemplateDiscovery/NuGet/NugetPackProvider.cs b/tools/Microsoft.TemplateSearch.TemplateDiscovery/NuGet/NugetPackProvider.cs index 51237a8ca04..fe47522b996 100644 --- a/tools/Microsoft.TemplateSearch.TemplateDiscovery/NuGet/NugetPackProvider.cs +++ b/tools/Microsoft.TemplateSearch.TemplateDiscovery/NuGet/NugetPackProvider.cs @@ -2,9 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Runtime.CompilerServices; +using Microsoft.TemplateEngine; using Microsoft.TemplateSearch.Common.Abstractions; using Microsoft.TemplateSearch.TemplateDiscovery.PackChecking; -using Newtonsoft.Json.Linq; using NuGet.Common; using NuGet.Protocol; using NuGet.Protocol.Core.Types; @@ -94,7 +94,7 @@ public async IAsyncEnumerable GetCandidatePacksAsync([Enum { string responseText = await response.Content.ReadAsStringAsync(token).ConfigureAwait(false); - NuGetPackageSearchResult resultsForPage = NuGetPackageSearchResult.FromJObject(JObject.Parse(responseText)); + NuGetPackageSearchResult resultsForPage = NuGetPackageSearchResult.FromJObject(JExtensions.ParseJsonObject(responseText)); totalPackCount = resultsForPage.TotalHits; if (resultsForPage.Data.Count > 0) { @@ -179,7 +179,7 @@ public async Task GetPackageCountAsync(CancellationToken token) using HttpResponseMessage response = await client.GetAsync(queryUri, token).ConfigureAwait(false); response.EnsureSuccessStatusCode(); string responseText = await response.Content.ReadAsStringAsync(token).ConfigureAwait(false); - NuGetPackageSearchResult resultsForPage = NuGetPackageSearchResult.FromJObject(JObject.Parse(responseText)); + NuGetPackageSearchResult resultsForPage = NuGetPackageSearchResult.FromJObject(JExtensions.ParseJsonObject(responseText)); return resultsForPage.TotalHits; } diff --git a/tools/Microsoft.TemplateSearch.TemplateDiscovery/NuGet/NugetPackageSearchResult.cs b/tools/Microsoft.TemplateSearch.TemplateDiscovery/NuGet/NugetPackageSearchResult.cs index 95b84eb2825..021ccc35bcb 100644 --- a/tools/Microsoft.TemplateSearch.TemplateDiscovery/NuGet/NugetPackageSearchResult.cs +++ b/tools/Microsoft.TemplateSearch.TemplateDiscovery/NuGet/NugetPackageSearchResult.cs @@ -1,8 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json.Nodes; using Microsoft.TemplateEngine; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateSearch.TemplateDiscovery.NuGet { @@ -13,18 +13,18 @@ internal class NuGetPackageSearchResult internal List Data { get; } = new List(); //property names are explained here: https://docs.microsoft.com/en-us/nuget/api/search-query-service-resource - internal static NuGetPackageSearchResult FromJObject(JObject entry) + internal static NuGetPackageSearchResult FromJObject(JsonObject entry) { NuGetPackageSearchResult searchResult = new NuGetPackageSearchResult { TotalHits = entry.ToInt32("totalHits") }; - var dataArray = entry.Get("data"); + var dataArray = entry.Get("data"); if (dataArray != null) { - foreach (JToken data in dataArray) + foreach (JsonNode? data in dataArray) { - if (data is JObject dataObj) + if (data is JsonObject dataObj) { searchResult.Data.Add(NuGetPackageSourceInfo.FromJObject(dataObj)); } diff --git a/tools/Microsoft.TemplateSearch.TemplateDiscovery/NuGet/NugetPackageSourceInfo.cs b/tools/Microsoft.TemplateSearch.TemplateDiscovery/NuGet/NugetPackageSourceInfo.cs index 48c3ca03f44..e8834929810 100644 --- a/tools/Microsoft.TemplateSearch.TemplateDiscovery/NuGet/NugetPackageSourceInfo.cs +++ b/tools/Microsoft.TemplateSearch.TemplateDiscovery/NuGet/NugetPackageSourceInfo.cs @@ -1,9 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json.Nodes; using Microsoft.TemplateEngine; using Microsoft.TemplateSearch.Common.Abstractions; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateSearch.TemplateDiscovery.NuGet { @@ -40,14 +40,14 @@ internal NuGetPackageSourceInfo(string id, string version) public string? IconUrl { get; private set; } //property names are explained here: https://docs.microsoft.com/en-us/nuget/api/search-query-service-resource - internal static NuGetPackageSourceInfo FromJObject(JObject entry) + internal static NuGetPackageSourceInfo FromJObject(JsonObject entry) { string id = entry.ToString("id") ?? throw new ArgumentException($"{nameof(entry)} doesn't have \"id\" property.", nameof(entry)); string version = entry.ToString("version") ?? throw new ArgumentException($"{nameof(entry)} doesn't have \"version\" property.", nameof(entry)); NuGetPackageSourceInfo sourceInfo = new NuGetPackageSourceInfo(id, version) { TotalDownloads = entry.ToInt32("totalDownloads"), - Owners = entry.Get("owners").JTokenStringOrArrayToCollection([]), + Owners = entry.Get("owners").JTokenStringOrArrayToCollection([]), Reserved = entry.ToBool("verified"), Description = entry.ToString("description"), IconUrl = entry.ToString("iconUrl") diff --git a/tools/Microsoft.TemplateSearch.TemplateDiscovery/PackChecking/FilteredPackageInfo.cs b/tools/Microsoft.TemplateSearch.TemplateDiscovery/PackChecking/FilteredPackageInfo.cs index 5ea3a2ceaf7..2fe29018900 100644 --- a/tools/Microsoft.TemplateSearch.TemplateDiscovery/PackChecking/FilteredPackageInfo.cs +++ b/tools/Microsoft.TemplateSearch.TemplateDiscovery/PackChecking/FilteredPackageInfo.cs @@ -1,8 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json.Serialization; using Microsoft.TemplateSearch.Common.Abstractions; -using Newtonsoft.Json; namespace Microsoft.TemplateSearch.TemplateDiscovery.PackChecking { @@ -21,29 +21,29 @@ internal FilteredPackageInfo(ITemplatePackageInfo info, string reason) IconUrl = info.IconUrl; } - [JsonConstructor] + [System.Text.Json.Serialization.JsonConstructor] private FilteredPackageInfo(string name, string reason) { Name = name; Reason = reason; } - [JsonProperty] + [JsonInclude] public string Name { get; private set; } - [JsonProperty] + [JsonInclude] public string? Version { get; private set; } - [JsonProperty] + [JsonInclude] public string Reason { get; private set; } - [JsonProperty] + [JsonInclude] public long TotalDownloads { get; private set; } - [JsonProperty] + [JsonInclude] public IReadOnlyList Owners { get; private set; } = []; - [JsonProperty] + [JsonInclude] public bool Reserved { get; private set; } [JsonIgnore] diff --git a/tools/Microsoft.TemplateSearch.TemplateDiscovery/Results/LegacyBlobTemplateInfo.cs b/tools/Microsoft.TemplateSearch.TemplateDiscovery/Results/LegacyBlobTemplateInfo.cs index 1c72bea3627..53cccca10e5 100644 --- a/tools/Microsoft.TemplateSearch.TemplateDiscovery/Results/LegacyBlobTemplateInfo.cs +++ b/tools/Microsoft.TemplateSearch.TemplateDiscovery/Results/LegacyBlobTemplateInfo.cs @@ -1,11 +1,11 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json.Serialization; using Microsoft.TemplateEngine.Abstractions; using Microsoft.TemplateEngine.Abstractions.Constraints; using Microsoft.TemplateEngine.Abstractions.Parameters; using Microsoft.TemplateEngine.Utils; -using Newtonsoft.Json; namespace Microsoft.TemplateSearch.TemplateDiscovery.Results { @@ -72,40 +72,29 @@ public LegacyBlobTemplateInfo(ITemplateInfo templateInfo) } } - [JsonProperty] public Guid ConfigMountPointId => Guid.Empty; - [JsonProperty] public string? Author { get; private set; } - [JsonProperty] public IReadOnlyList Classifications { get; private set; } - [JsonProperty] public string DefaultName => string.Empty; - [JsonProperty] public string? Description { get; private set; } - [JsonProperty] public string Identity { get; private set; } - [JsonProperty] public Guid GeneratorId => Guid.Empty; - [JsonProperty] public string? GroupIdentity { get; private set; } - [JsonProperty] public int Precedence { get; private set; } - [JsonProperty] public string Name { get; private set; } [JsonIgnore] public bool PreferDefaultName { get; } - [JsonProperty] public string ShortName { get @@ -129,34 +118,24 @@ public string ShortName } } - [JsonProperty] public IReadOnlyList ShortNameList { get; private set; } - [JsonProperty] public string ConfigPlace => string.Empty; - [JsonProperty] public Guid LocaleConfigMountPointId => Guid.Empty; - [JsonProperty] public string LocaleConfigPlace => string.Empty; - [JsonProperty] public Guid HostConfigMountPointId => Guid.Empty; - [JsonProperty] public string HostConfigPlace => string.Empty; - [JsonProperty] public string? ThirdPartyNotices { get; private set; } - [JsonProperty] public IReadOnlyDictionary BaselineInfo { get; private set; } - [JsonProperty] public bool HasScriptRunningPostActions { get; set; } - [JsonProperty] public DateTime? ConfigTimestampUtc { get; private set; } [JsonIgnore] @@ -172,17 +151,15 @@ public string ShortName [JsonIgnore] public string MountPointUri => string.Empty; - [JsonProperty] public IReadOnlyDictionary Tags { get; private set; } = new Dictionary(); - [JsonProperty] public IReadOnlyDictionary CacheParameters { get; private set; } = new Dictionary(); [JsonIgnore] public IReadOnlyList PostActions { get; } [JsonIgnore] - IReadOnlyList ITemplateMetadata.Constraints => throw new NotImplementedException(); + IReadOnlyList ITemplateMetadata.Constraints => []; // ShortName should get deserialized when it exists, for backwards compat. // But moving forward, ShortNameList should be the definitive source. @@ -202,23 +179,19 @@ public BlobLegacyCacheTag(string? description, IReadOnlyDictionary ChoicesAndDescriptions { get; } - [JsonProperty] public string? DefaultValue { get; } - [JsonProperty] public string? DefaultIfOptionWithoutValue { get; } [JsonIgnore] - public string? DisplayName => throw new NotImplementedException(); + public string? DisplayName => null; [JsonIgnore] - public IReadOnlyDictionary Choices => throw new NotImplementedException(); + public IReadOnlyDictionary Choices => new Dictionary(); } @@ -232,20 +205,16 @@ public BlobLegacyCacheParameter(string? description, string? dataType, string? d DefaultIfOptionWithoutValue = defaultIfOptionWithoutValue; } - [JsonProperty] public string? DataType { get; } - [JsonProperty] public string? DefaultValue { get; } - [JsonProperty] public string? Description { get; } - [JsonProperty] public string? DefaultIfOptionWithoutValue { get; } [JsonIgnore] - public string DisplayName => throw new NotImplementedException(); + public string DisplayName => string.Empty; } } } diff --git a/tools/Microsoft.TemplateSearch.TemplateDiscovery/Results/LegacyMetadataWriter.cs b/tools/Microsoft.TemplateSearch.TemplateDiscovery/Results/LegacyMetadataWriter.cs index 55f0e9336a8..9752481561d 100644 --- a/tools/Microsoft.TemplateSearch.TemplateDiscovery/Results/LegacyMetadataWriter.cs +++ b/tools/Microsoft.TemplateSearch.TemplateDiscovery/Results/LegacyMetadataWriter.cs @@ -14,7 +14,7 @@ internal partial class LegacyMetadataWriter internal static string WriteLegacySearchMetadata(PackSourceCheckResult packSourceCheckResults, string outputFileName) { var searchMetadata = CreateLegacySearchMetadata(packSourceCheckResults); - File.WriteAllText(outputFileName, searchMetadata.ToJObject().ToString(Newtonsoft.Json.Formatting.None)); + File.WriteAllText(outputFileName, searchMetadata.ToJObject().ToJsonString()); Console.WriteLine($"Legacy search cache file created: {outputFileName}"); return outputFileName; } diff --git a/tools/Microsoft.TemplateSearch.TemplateDiscovery/Results/UnifiedPackCheckResultReportWriter.cs b/tools/Microsoft.TemplateSearch.TemplateDiscovery/Results/UnifiedPackCheckResultReportWriter.cs index c849f42231d..d2c967db607 100644 --- a/tools/Microsoft.TemplateSearch.TemplateDiscovery/Results/UnifiedPackCheckResultReportWriter.cs +++ b/tools/Microsoft.TemplateSearch.TemplateDiscovery/Results/UnifiedPackCheckResultReportWriter.cs @@ -1,9 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json; using Microsoft.TemplateSearch.Common; using Microsoft.TemplateSearch.TemplateDiscovery.PackChecking; -using Newtonsoft.Json; namespace Microsoft.TemplateSearch.TemplateDiscovery.Results { @@ -42,14 +42,14 @@ internal static (string MetadataPath, string LegacyMetadataPath) WriteResults(Di private static void WriteSearchMetadata(PackSourceCheckResult packSourceCheckResults, string outputFileName) { TemplateSearchCache searchMetadata = packSourceCheckResults.SearchCache; - File.WriteAllText(outputFileName, searchMetadata.ToJObject().ToString(Formatting.None)); + File.WriteAllText(outputFileName, searchMetadata.ToJObject().ToJsonString()); Console.WriteLine($"Search cache file created: {outputFileName}"); } private static void WriteNonTemplatePackList(string reportPath, IReadOnlyList packCheckResults) { var orderedFilters = packCheckResults.OrderBy(x => x.Name, StringComparer.OrdinalIgnoreCase).ToArray(); - string serializedContent = JsonConvert.SerializeObject(orderedFilters, Formatting.None); + string serializedContent = JsonSerializer.Serialize(orderedFilters); string outputFileName = Path.Combine(reportPath, NonTemplatePacksFileName); File.WriteAllText(outputFileName, serializedContent); Console.WriteLine($"Non template pack list was created: {outputFileName}"); diff --git a/tools/Microsoft.TemplateSearch.TemplateDiscovery/TestProvider/TestPackCheckerFactory.cs b/tools/Microsoft.TemplateSearch.TemplateDiscovery/TestProvider/TestPackCheckerFactory.cs index 852d9b2f23c..06b6d6fa504 100644 --- a/tools/Microsoft.TemplateSearch.TemplateDiscovery/TestProvider/TestPackCheckerFactory.cs +++ b/tools/Microsoft.TemplateSearch.TemplateDiscovery/TestProvider/TestPackCheckerFactory.cs @@ -1,13 +1,14 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json; +using System.Text.Json.Nodes; using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.TemplateEngine; using Microsoft.TemplateSearch.Common; using Microsoft.TemplateSearch.TemplateDiscovery.AdditionalData; using Microsoft.TemplateSearch.TemplateDiscovery.Filters; using Microsoft.TemplateSearch.TemplateDiscovery.PackChecking; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; namespace Microsoft.TemplateSearch.TemplateDiscovery.Test { @@ -49,9 +50,7 @@ public Task CreatePackSourceCheckerAsync(CommandArgs config, Verbose.WriteLine($"Opening {fileLocation.FullName}"); using var fileStream = fileLocation.OpenRead(); - using var textReader = new StreamReader(fileStream, System.Text.Encoding.UTF8, true); - using var jsonReader = new JsonTextReader(textReader); - return new JsonSerializer().Deserialize>(jsonReader); + return JsonSerializer.Deserialize>(fileStream); } private static TemplateSearchCache? LoadExistingCache(CommandArgs config) @@ -64,9 +63,9 @@ public Task CreatePackSourceCheckerAsync(CommandArgs config, FileInfo? cacheFileLocation = config.DiffOverrideSearchCacheLocation; Verbose.WriteLine($"Opening {cacheFileLocation.FullName}"); using var fileStream = cacheFileLocation.OpenRead(); - using var textReader = new StreamReader(fileStream, System.Text.Encoding.UTF8, true); - using var jsonReader = new JsonTextReader(textReader); - return TemplateSearchCache.FromJObject(JObject.Load(jsonReader), NullLogger.Instance, new Dictionary>() { { CliHostSearchCacheData.DataName, CliHostSearchCacheData.Reader } }); + string content = new StreamReader(fileStream, System.Text.Encoding.UTF8, true).ReadToEnd(); + JsonObject cacheObject = JExtensions.ParseJsonObject(content); + return TemplateSearchCache.FromJObject(cacheObject, NullLogger.Instance, new Dictionary>() { { CliHostSearchCacheData.DataName, CliHostSearchCacheData.Reader } }); } } }