-
Notifications
You must be signed in to change notification settings - Fork 8.1k
Test-Json: use JsonSchema.Net instead of NJsonSchema #18023
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
c774a81
a09c2c5
fd12baf
f485dd4
41dcbc9
6858f50
527aab0
ff7384e
7047a32
e98f6ce
dbcdfd9
086d0ed
defd150
cfae3ac
fe74576
e9c179c
80a21b9
7788433
eb6d1d0
af3603c
fc66799
d7fbd12
d56dd1f
b63ab7d
d7502c2
c4d860a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -56,9 +56,6 @@ | |
| <Component Id="cmp31176C5A3BDB4A9F95171A4780D7D4D2"> | ||
| <File Id="fil31176C5A3BDB4A9F95171A4780D7D4D2" KeyPath="yes" Source="$(var.ProductSourcePath)\System.ServiceModel.Syndication.dll" /> | ||
| </Component> | ||
| <Component Id="cmp3CC027D3F160412C9F0044EBED3115DD"> | ||
| <File Id="filFD2EF6BC74AF459D1BB52CA1E8C6E33B" KeyPath="yes" Source="$(var.ProductSourcePath)\NJsonSchema.dll" /> | ||
| </Component> | ||
| <Component Id="cmp3B130879A26D2E954251BB81E8948069"> | ||
| <File Id="filAACDEEE28FEA076C73D082A0AD21B8E0" KeyPath="yes" Source="$(var.ProductSourcePath)\Microsoft.CSharp.dll" /> | ||
| </Component> | ||
|
|
@@ -1587,17 +1584,17 @@ | |
| <Component Id="cmp7C72179331DD48BCB12BF205F34B76AD"> | ||
| <File Id="filF65735DC9B8B4957B27F5B33D2A322F4" KeyPath="yes" Source="$(var.ProductSourcePath)\ref\System.Runtime.InteropServices.JavaScript.dll" /> | ||
| </Component> | ||
| <Component Id="cmpF3EB02BB62A34F509B22CC370C430A20"> | ||
| <File Id="fil489339762CDF41AE97538C020401BEC6" KeyPath="yes" Source="$(var.ProductSourcePath)\ref\System.Net.Quic.dll" /> | ||
| <Component Id="cmpBB2921B987554B68B26862747C3BD398"> | ||
| <File Id="fil1D77B59F22194840A66EFA782AB2BB95" KeyPath="yes" Source="$(var.ProductSourcePath)\ref\System.Text.Encodings.Web.dll" /> | ||
| </Component> | ||
| <Component Id="cmp2BB1C07A912442B0BB6270D7EB3185F3"> | ||
| <File Id="fil2D6E6E560F1743729D90C204D69C369C" KeyPath="yes" Source="$(var.ProductSourcePath)\ref\System.Formats.Asn1.dll" /> | ||
| <Component Id="cmpD182C2F62588471F82252B0038C75327"> | ||
| <File Id="filBD7A930797F148DA8F433C809DC7BFB4" KeyPath="yes" Source="$(var.ProductSourcePath)\ref\System.Formats.Asn1.dll" /> | ||
| </Component> | ||
| <Component Id="cmpF5FD2E392BD94BCD957480F128A38E10"> | ||
| <File Id="fil9C11C1DAFDC94C0588965EA6EAAA7592" KeyPath="yes" Source="$(var.ProductSourcePath)\ref\System.Text.Encoding.CodePages.dll" /> | ||
| <Component Id="cmpF3EB02BB62A34F509B22CC370C430A20"> | ||
| <File Id="fil489339762CDF41AE97538C020401BEC6" KeyPath="yes" Source="$(var.ProductSourcePath)\ref\System.Net.Quic.dll" /> | ||
| </Component> | ||
| <Component Id="cmp28DEAACC47FD4B04A95521A375761643"> | ||
| <File Id="filE0DD0282CF6C440C99209B0B7495422C" KeyPath="yes" Source="$(var.ProductSourcePath)\ref\System.Text.Encodings.Web.dll" /> | ||
| <Component Id="cmp16FC1857F01A4E388616BA7AA8CC5F73"> | ||
| <File Id="fil877D1292F59541DAB6758F5A7A74D20D" KeyPath="yes" Source="$(var.ProductSourcePath)\ref\System.Text.Encoding.CodePages.dll" /> | ||
| </Component> | ||
| </Directory> | ||
| <Directory Id="dirC72EEAF9434D4AD066E0F4D20D8E816C" Name="en-US"> | ||
|
|
@@ -2921,9 +2918,6 @@ | |
| <Component Id="cmp41E9A7E0470540228A69F13F8585089E"> | ||
| <File Id="fil4F7CB5570E86407C94595812662A4F42" KeyPath="yes" Source="$(var.ProductSourcePath)\Microsoft.VisualBasic.Core.dll" /> | ||
| </Component> | ||
| <Component Id="cmp8E8AE88416D44A4CA39F23E9C825A899"> | ||
| <File Id="fil4954FEF58A894EA7B701DFCA7D11AF08" KeyPath="yes" Source="$(var.ProductSourcePath)\Namotion.Reflection.dll" /> | ||
| </Component> | ||
| <Component Id="cmpE5F62B056F174A3E8843DFE8B70E3AA9"> | ||
| <File Id="fil6B276B69CAC64F19A2A3E2A72086EF15" KeyPath="yes" Source="$(var.ProductSourcePath)\Markdig.Signed.dll" /> | ||
| </Component> | ||
|
|
@@ -3150,8 +3144,20 @@ | |
| <Component Id="cmp42A739F2AAC24D729DDBCAA096B8C55A"> | ||
| <File Id="fil48314E2AC49B4E208C5667CEC50CA78C" KeyPath="yes" Source="$(var.ProductSourcePath)\RegisterMicrosoftUpdate.ps1" /> | ||
| </Component> | ||
| <Component Id="cmp76EB2749D0464D41AD1D2BA2C51CF4C9"> | ||
| <File Id="filDC81A93ACA6045E4A22C108F59D69083" KeyPath="yes" Source="$(var.ProductSourcePath)\mscordaccore_$(var.FileArchitecture)_$(var.FileArchitecture)_7.0.22.42610.dll" /> | ||
| <Component Id="cmp5B1AAAB6B46D45EA8A430A766325B0D5"> | ||
| <File Id="filF4983633E7914A1AAD5D02BFDFA7DD63" KeyPath="yes" Source="$(var.ProductSourcePath)\JsonSchema.Net.dll" /> | ||
| </Component> | ||
| <Component Id="cmp61D33FB49B2E4C7D8E9C5EFC3F3A04B2"> | ||
| <File Id="fil78E3FEFE7B0E4FE1993AC9C117B582C5" KeyPath="yes" Source="$(var.ProductSourcePath)\JetBrains.Annotations.dll" /> | ||
| </Component> | ||
| <Component Id="cmpB51390A44A2E4D2EB27C891E4ED3A705"> | ||
| <File Id="fil69092C4DDAE14264A0D1E788993DB43D" KeyPath="yes" Source="$(var.ProductSourcePath)\Json.More.dll" /> | ||
| </Component> | ||
| <Component Id="cmpB5F59B2105D54C0D896C8D7EB3EA82F3"> | ||
| <File Id="filB6F08AEE602D4982A38EB3532F62BCF3" KeyPath="yes" Source="$(var.ProductSourcePath)\JsonPointer.Net.dll" /> | ||
|
||
| </Component> | ||
| <Component Id="cmp9ADAB04764E14F0DA83A54E4CE28319F"> | ||
| <File Id="fil58C3F617C0DE48C0895D80C0FA26CCAB" KeyPath="yes" Source="$(var.ProductSourcePath)\mscordaccore_$(var.FileArchitecture)_$(var.FileArchitecture)_7.0.22.42610.dll" /> | ||
| </Component> | ||
| </DirectoryRef> | ||
| </Fragment> | ||
|
|
@@ -3175,7 +3181,6 @@ | |
| <ComponentRef Id="cmp4477FC97930D452DA018C8F6A3D7D168" /> | ||
| <ComponentRef Id="cmp30C10EC477714A76B2A8D0A957D1D6F3" /> | ||
| <ComponentRef Id="cmp31176C5A3BDB4A9F95171A4780D7D4D2" /> | ||
| <ComponentRef Id="cmp3CC027D3F160412C9F0044EBED3115DD" /> | ||
| <ComponentRef Id="cmp3B130879A26D2E954251BB81E8948069" /> | ||
| <ComponentRef Id="cmp02ABBE4A3EDBEBFD05DC17A009A2B79D" /> | ||
| <ComponentRef Id="cmpAA10498DF244C013CB5043C62E3AA83A" /> | ||
|
|
@@ -4047,7 +4052,6 @@ | |
| <ComponentRef Id="cmpFF8643F8CC97462CAC20815F6071203B" /> | ||
| <ComponentRef Id="cmp0FC1F6198C66492495785315CDEE0B66" /> | ||
| <ComponentRef Id="cmp41E9A7E0470540228A69F13F8585089E" /> | ||
| <ComponentRef Id="cmp8E8AE88416D44A4CA39F23E9C825A899" /> | ||
| <ComponentRef Id="cmpE5F62B056F174A3E8843DFE8B70E3AA9" /> | ||
| <ComponentRef Id="cmp30126C60BD784974B74EA45AE9B04032" /> | ||
| <ComponentRef Id="cmp9EC1507780D247E095EA92A7715B4BAC" /> | ||
|
|
@@ -4159,13 +4163,17 @@ | |
| <ComponentRef Id="cmp97D2E588E938462194C7549B3A0084FE" /> | ||
| <ComponentRef Id="cmp41C949169E9341CC9297641456FEE2CC" /> | ||
| <ComponentRef Id="cmp7C72179331DD48BCB12BF205F34B76AD" /> | ||
| <ComponentRef Id="cmpBB2921B987554B68B26862747C3BD398" /> | ||
| <ComponentRef Id="cmp0721DF55B34849B78C98AE00D863CBFF" /> | ||
| <ComponentRef Id="cmpD182C2F62588471F82252B0038C75327" /> | ||
| <ComponentRef Id="cmpF3EB02BB62A34F509B22CC370C430A20" /> | ||
| <ComponentRef Id="cmp16FC1857F01A4E388616BA7AA8CC5F73" /> | ||
| <ComponentRef Id="cmp42A739F2AAC24D729DDBCAA096B8C55A" /> | ||
| <ComponentRef Id="cmp2BB1C07A912442B0BB6270D7EB3185F3" /> | ||
| <ComponentRef Id="cmp76EB2749D0464D41AD1D2BA2C51CF4C9" /> | ||
| <ComponentRef Id="cmpF5FD2E392BD94BCD957480F128A38E10" /> | ||
| <ComponentRef Id="cmp28DEAACC47FD4B04A95521A375761643" /> | ||
| <ComponentRef Id="cmp5B1AAAB6B46D45EA8A430A766325B0D5" /> | ||
| <ComponentRef Id="cmp61D33FB49B2E4C7D8E9C5EFC3F3A04B2" /> | ||
| <ComponentRef Id="cmpB51390A44A2E4D2EB27C891E4ED3A705" /> | ||
| <ComponentRef Id="cmpB5F59B2105D54C0D896C8D7EB3EA82F3" /> | ||
| <ComponentRef Id="cmp9ADAB04764E14F0DA83A54E4CE28319F" /> | ||
| </ComponentGroup> | ||
| </Fragment> | ||
| </Wix> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT License. | ||
|
|
||
| #nullable enable | ||
|
|
||
| using System; | ||
|
|
||
| namespace Microsoft.PowerShell.Commands; | ||
|
|
||
| /// <summary> | ||
| /// Thrown during evaluation of <see cref="TestJsonCommand"/> when an attempt | ||
| /// to resolve a <code>$ref</code> or <code>$dynamicRef</code> fails. | ||
| /// </summary> | ||
| internal class JsonSchemaReferenceResolutionException : Exception | ||
| { | ||
| /// <summary> | ||
| /// Initializes a new instance of the <see cref="JsonSchemaReferenceResolutionException"/> class. | ||
| /// </summary> | ||
| /// <param name="innerException"> | ||
| /// The exception that is the cause of the current exception, or a null reference | ||
| /// (<code>Nothing</code> in Visual Basic) if no inner exception is specified. | ||
| /// </param> | ||
| public JsonSchemaReferenceResolutionException(Exception innerException) | ||
| : base(message: null, innerException) | ||
| { | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,11 +5,11 @@ | |
| using System.Globalization; | ||
| using System.IO; | ||
| using System.Management.Automation; | ||
| using System.Reflection; | ||
| using System.Runtime.ExceptionServices; | ||
| using System.Net.Http; | ||
| using System.Security; | ||
| using Newtonsoft.Json.Linq; | ||
| using NJsonSchema; | ||
| using System.Text.Json; | ||
| using System.Text.Json.Nodes; | ||
| using Json.Schema; | ||
|
|
||
| namespace Microsoft.PowerShell.Commands | ||
| { | ||
|
|
@@ -52,31 +52,38 @@ public class TestJsonCommand : PSCmdlet | |
| private JsonSchema _jschema; | ||
|
|
||
| /// <summary> | ||
| /// Process all exceptions in the AggregateException. | ||
| /// Unwrap TargetInvocationException if any and | ||
| /// rethrow inner exception without losing the stack trace. | ||
| /// Prepare a JSON schema. | ||
| /// </summary> | ||
| /// <param name="e">AggregateException to be unwrapped.</param> | ||
| /// <returns>Return value is unreachable since we always rethrow.</returns> | ||
| private static bool UnwrapException(Exception e) | ||
| protected override void BeginProcessing() | ||
| { | ||
| if (e.InnerException != null && e is TargetInvocationException) | ||
| { | ||
| ExceptionDispatchInfo.Capture(e.InnerException).Throw(); | ||
| } | ||
| else | ||
| SchemaRegistry.Global.Fetch = static uri => | ||
| { | ||
| ExceptionDispatchInfo.Capture(e).Throw(); | ||
| } | ||
| try | ||
| { | ||
| string text; | ||
| switch (uri.Scheme) | ||
| { | ||
| case "http": | ||
| case "https": | ||
| text = new HttpClient().GetStringAsync(uri).Result; | ||
| break; | ||
| case "file": | ||
| var filename = Uri.UnescapeDataString(uri.AbsolutePath); | ||
| text = File.ReadAllText(filename); | ||
| break; | ||
| default: | ||
| throw new FormatException( | ||
| $"URI scheme '{uri.Scheme}' is not supported. Only HTTP(S) and local file system URIs are allowed."); | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
| return JsonSerializer.Deserialize<JsonSchema>(text); | ||
| } | ||
| catch (Exception e) | ||
| { | ||
| throw new JsonSchemaReferenceResolutionException(e); | ||
| } | ||
| }; | ||
|
|
||
| /// <summary> | ||
| /// Prepare a JSON schema. | ||
| /// </summary> | ||
| protected override void BeginProcessing() | ||
| { | ||
| string resolvedpath = string.Empty; | ||
|
|
||
| try | ||
|
|
@@ -85,25 +92,25 @@ protected override void BeginProcessing() | |
| { | ||
| try | ||
| { | ||
| _jschema = JsonSchema.FromJsonAsync(Schema).Result; | ||
| _jschema = JsonSchema.FromText(Schema); | ||
| } | ||
| catch (AggregateException ae) | ||
| catch (JsonException e) | ||
| { | ||
| // Even if only one exception is thrown, it is still wrapped in an AggregateException exception | ||
| // https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/exception-handling-task-parallel-library | ||
| ae.Handle(UnwrapException); | ||
| Exception exception = new(TestJsonCmdletStrings.InvalidJsonSchema, e); | ||
| WriteError(new ErrorRecord(exception, "InvalidJsonSchema", ErrorCategory.InvalidData, Schema)); | ||
| } | ||
| } | ||
| else if (SchemaFile != null) | ||
| { | ||
| try | ||
| { | ||
| resolvedpath = Context.SessionState.Path.GetUnresolvedProviderPathFromPSPath(SchemaFile); | ||
| _jschema = JsonSchema.FromFileAsync(resolvedpath).Result; | ||
| _jschema = JsonSchema.FromFile(resolvedpath); | ||
| } | ||
| catch (AggregateException ae) | ||
| catch (JsonException e) | ||
| { | ||
| ae.Handle(UnwrapException); | ||
| Exception exception = new(TestJsonCmdletStrings.InvalidJsonSchema, e); | ||
| WriteError(new ErrorRecord(exception, "InvalidJsonSchema", ErrorCategory.InvalidData, SchemaFile)); | ||
| } | ||
| } | ||
| } | ||
|
|
@@ -140,26 +147,49 @@ protected override void ProcessRecord() | |
|
|
||
| try | ||
| { | ||
| var parsedJson = JToken.Parse(Json); | ||
| var parsedJson = JsonNode.Parse(Json); | ||
gregsdennis marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| if (_jschema != null) | ||
| { | ||
| var errorMessages = _jschema.Validate(parsedJson); | ||
| if (errorMessages != null && errorMessages.Count != 0) | ||
| { | ||
| result = false; | ||
|
|
||
| Exception exception = new(TestJsonCmdletStrings.InvalidJsonAgainstSchema); | ||
|
|
||
| foreach (var message in errorMessages) | ||
| var validationResults = _jschema.Validate(parsedJson, new ValidationOptions { OutputFormat = OutputFormat.Basic }); | ||
| result = validationResults.IsValid; | ||
| if (!result) | ||
| { | ||
| ErrorRecord errorRecord = new(exception, "InvalidJsonAgainstSchema", ErrorCategory.InvalidData, null); | ||
| errorRecord.ErrorDetails = new ErrorDetails(message.ToString()); | ||
| WriteError(errorRecord); | ||
| Exception exception = new(TestJsonCmdletStrings.InvalidJsonAgainstSchema); | ||
|
|
||
| if (validationResults.Message != null) | ||
| { | ||
| ErrorRecord errorRecord = new(exception, "InvalidJsonAgainstSchema", ErrorCategory.InvalidData, null); | ||
| var message = $"{validationResults.Message} at {validationResults.InstanceLocation}"; | ||
| errorRecord.ErrorDetails = new ErrorDetails(message); | ||
| WriteError(errorRecord); | ||
| } | ||
|
|
||
| if (validationResults.HasNestedResults) | ||
| { | ||
| foreach (var nestedResult in validationResults.NestedResults) | ||
| { | ||
| if (nestedResult.Message == null) | ||
| { | ||
| continue; | ||
| } | ||
|
|
||
| ErrorRecord errorRecord = new(exception, "InvalidJsonAgainstSchema", ErrorCategory.InvalidData, null); | ||
gregsdennis marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| var message = $"{nestedResult.Message} at {nestedResult.InstanceLocation}"; | ||
| errorRecord.ErrorDetails = new ErrorDetails(message); | ||
| WriteError(errorRecord); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| catch (JsonSchemaReferenceResolutionException jsonExc) | ||
| { | ||
| result = false; | ||
|
|
||
| Exception exception = new(TestJsonCmdletStrings.InvalidJsonSchema, jsonExc); | ||
| WriteError(new ErrorRecord(exception, "InvalidJsonSchema", ErrorCategory.InvalidData, _jschema)); | ||
| } | ||
|
||
| catch (Exception exc) | ||
| { | ||
| result = false; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder we have to include the dependency.
I think that's the problem. I don't think that's what we want to distribute.
And what is official license for the file?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://www.nuget.org/packages/JetBrains.Annotations/
License is MIT.
I've had requests to remove this before. It's actually a dependency. I use
[RegexPattern]in a few of my methods where a Regex string is expected. It provides Regex syntax highlighting in the string literal. If there's a way to get this without the runtime dependency, I'm unaware of it.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could use .Net attribute https://source.dot.net/#System.Text.RegularExpressions/System/Text/RegularExpressions/Regex.cs,59
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will require an update to the library, so I'll have to update the version ref in the .csproj file after I publish. Shouldn't take long.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That attribute is only available in .Net 7 preview. My library is .Net Standard 2.0. I can't use this.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From docs:
So you can remove the dependency from binary package. Or You can also embed attribute declarations
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That removes the attribute from the compilation. That doesn't help my users, which is the entire point of including the attribute. I don't need it for my own development; it's so that the people who use the library get the benefit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use embed attribute declarations