Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.6.0-1.final" />
<PackageReference Include="System.Threading.AccessControl" Version="8.0.0-preview.3.23174.8" />
<PackageReference Include="System.Drawing.Common" Version="8.0.0-preview.2.23128.3" />
<PackageReference Include="JsonSchema.Net" Version="3.3.2" />
<PackageReference Include="JsonSchema.Net" Version="4.1.1" />
</ItemGroup>

</Project>

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@
using System.Management.Automation;
using System.Net.Http;
using System.Security;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Nodes;
using Json.More;
using Json.Schema;
using Markdig.Helpers;
using static System.Management.Automation.PSStyle;

namespace Microsoft.PowerShell.Commands
{
Expand Down Expand Up @@ -118,37 +122,38 @@ protected override void BeginProcessing()
// and automatically fetching referenced URIs is likely the preferred behavior. To do that,
// this property must be set with a method to retrieve and deserialize the content.
// For more information, see https://json-everything.net/json-schema#automatic-resolution
SchemaRegistry.Global.Fetch = static uri =>
SchemaRegistry.Global.Fetch = uri =>
{
try
string text;
switch (uri.Scheme)
{
string text;
switch (uri.Scheme)
{
case "http":
case "https":
{
using var client = new HttpClient();
text = client.GetStringAsync(uri).Result;
break;
}
case "file":
var filename = Uri.UnescapeDataString(uri.AbsolutePath);
text = File.ReadAllText(filename);
case "http":
case "https":
{
using var client = new HttpClient();
text = client.GetStringAsync(uri).Result;
break;
default:
throw new FormatException(string.Format(TestJsonCmdletStrings.InvalidUriScheme, uri.Scheme));
}

return JsonSerializer.Deserialize<JsonSchema>(text);
}
catch (Exception e)
{
throw new JsonSchemaReferenceResolutionException(e);
}
case "file":
var filename = uri.LocalPath;
WriteToConsole($"Fetching: {uri}");
WriteToConsole($"Reading file: {filename}");
if (!File.Exists(filename))
{
WriteToConsole("Cannot find file.");
return null;
}

text = File.ReadAllText(filename);
break;
default:
throw new FormatException(string.Format(TestJsonCmdletStrings.InvalidUriScheme, uri.Scheme));
}

return JsonSerializer.Deserialize<JsonSchema>(text);
};

string resolvedpath = string.Empty;
string resolvedPath = string.Empty;

try
{
Expand All @@ -168,15 +173,18 @@ protected override void BeginProcessing()
{
try
{
resolvedpath = Context.SessionState.Path.GetUnresolvedProviderPathFromPSPath(SchemaFile);
_jschema = JsonSchema.FromFile(resolvedpath);
resolvedPath = Context.SessionState.Path.GetUnresolvedProviderPathFromPSPath(SchemaFile);
_jschema = JsonSchema.FromFile(resolvedPath);
}
catch (JsonException e)
{
Exception exception = new(TestJsonCmdletStrings.InvalidJsonSchema, e);
WriteError(new ErrorRecord(exception, "InvalidJsonSchema", ErrorCategory.InvalidData, SchemaFile));
WriteError(new ErrorRecord(exception, "InvalidJsonSchema", ErrorCategory.InvalidData,
SchemaFile));
}
}

Console.WriteLine("Schema Base URI: {0}", _jschema.BaseUri);
}
catch (Exception e) when (
// Handle exceptions related to file access to provide more specific error message
Expand All @@ -191,14 +199,14 @@ e is SecurityException
string.Format(
CultureInfo.CurrentUICulture,
TestJsonCmdletStrings.JsonSchemaFileOpenFailure,
resolvedpath),
resolvedPath),
e);
ThrowTerminatingError(new ErrorRecord(exception, "JsonSchemaFileOpenFailure", ErrorCategory.OpenError, resolvedpath));
ThrowTerminatingError(new ErrorRecord(exception, "JsonSchemaFileOpenFailure", ErrorCategory.OpenError, resolvedPath));
}
catch (Exception e)
{
Exception exception = new(TestJsonCmdletStrings.InvalidJsonSchema, e);
ThrowTerminatingError(new ErrorRecord(exception, "InvalidJsonSchema", ErrorCategory.InvalidData, resolvedpath));
ThrowTerminatingError(new ErrorRecord(exception, "InvalidJsonSchema", ErrorCategory.InvalidData, resolvedPath));
}
}

Expand Down Expand Up @@ -232,57 +240,95 @@ protected override void ProcessRecord()
jsonToParse = File.ReadAllText(resolvedPath);
}

try
JsonSerializerOptions serializerOptions = new()
{
WriteIndented = true,
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};

try
{
var parsedJson = JsonNode.Parse(jsonToParse);

WriteToConsole("JSON instance:");
WriteToConsole(parsedJson.AsJsonString(serializerOptions));

if (_jschema != null)
{
var validationResults = _jschema.Validate(parsedJson, new ValidationOptions { OutputFormat = OutputFormat.Basic });
result = validationResults.IsValid;
if (!result)
{
if (validationResults.Message != null)
{
Exception exception = new(string.Format(TestJsonCmdletStrings.InvalidJsonAgainstSchemaDetailed, validationResults.Message, validationResults.InstanceLocation));
ErrorRecord errorRecord = new(exception, "InvalidJsonAgainstSchemaDetailed", ErrorCategory.InvalidData, null);
WriteError(errorRecord);
}
WriteToConsole("Schema:");
WriteToConsole(JsonSerializer.Serialize(_jschema, serializerOptions));

EvaluationResults evaluationResults = _jschema.Evaluate(parsedJson, new EvaluationOptions { OutputFormat = OutputFormat.List });

WriteToConsole("Evaluation results:");
WriteToConsole(JsonSerializer.Serialize(evaluationResults, serializerOptions));

if (validationResults.HasNestedResults)
result = evaluationResults.IsValid;
if (!result)
{
HandleValidationErrors(evaluationResults);

if (evaluationResults.HasDetails)
{
foreach (var nestedResult in evaluationResults.Details)
{
foreach (var nestedResult in validationResults.NestedResults)
{
if (nestedResult.Message == null)
{
continue;
}

Exception exception = new(string.Format(TestJsonCmdletStrings.InvalidJsonAgainstSchemaDetailed, nestedResult.Message, nestedResult.InstanceLocation));
ErrorRecord errorRecord = new(exception, "InvalidJsonAgainstSchemaDetailed", ErrorCategory.InvalidData, null);
WriteError(errorRecord);
}
HandleValidationErrors(nestedResult);
}
}
}
}
}
catch (JsonSchemaReferenceResolutionException jsonExc)
catch (JsonSchemaException schemaEx)
{
result = false;

Exception exception = new(TestJsonCmdletStrings.InvalidJsonSchema, jsonExc);
WriteError(new ErrorRecord(exception, "InvalidJsonSchema", ErrorCategory.InvalidData, _jschema));
WriteToConsole(schemaEx.ToString());

Exception exception = new(TestJsonCmdletStrings.JsonSchemaProcessingFailure, schemaEx);
ThrowTerminatingError(new ErrorRecord(exception, "JsonSchemaProcessingFailure", ErrorCategory.InvalidData, _jschema));
}
catch (FormatException formatEx)
{
result = false;

WriteToConsole(formatEx.ToString());

Exception exception = new(TestJsonCmdletStrings.InvalidUriScheme, formatEx);
ThrowTerminatingError(new ErrorRecord(exception, "InvalidUriScheme", ErrorCategory.InvalidData, _jschema));
}
catch (Exception exc)
{
result = false;

WriteToConsole(exc.ToString());

Exception exception = new(TestJsonCmdletStrings.InvalidJson, exc);
WriteError(new ErrorRecord(exception, "InvalidJson", ErrorCategory.InvalidData, Json));
}

WriteObject(result);
}

private void WriteToConsole(string message)
{
HostInformationMessage informationMessage = new() { Message = message };

WriteInformation(informationMessage, new[] { "PSHOST" });
}

private void HandleValidationErrors(EvaluationResults evaluationResult)
{
if (!evaluationResult.HasErrors)
{
return;
}

foreach (var error in evaluationResult.Errors!)
{
Exception exception = new(string.Format(TestJsonCmdletStrings.InvalidJsonAgainstSchemaDetailed, error.Value, evaluationResult.InstanceLocation));
ErrorRecord errorRecord = new(exception, "InvalidJsonAgainstSchemaDetailed", ErrorCategory.InvalidData, null);
WriteError(errorRecord);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -124,12 +124,15 @@
<value>Cannot parse the JSON.</value>
</data>
<data name="InvalidJsonAgainstSchemaDetailed" xml:space="preserve">
<value>The JSON is not valid with the schema: {0} at {1}</value>
<value>The JSON is not valid with the schema: {0} at '{1}'</value>
</data>
<data name="JsonSchemaFileOpenFailure" xml:space="preserve">
<value>Can not open JSON schema file: {0}</value>
</data>
<data name="InvalidUriScheme" xml:space="preserve">
<value>URI scheme '{0}' is not supported. Only HTTP(S) and local file system URIs are allowed.</value>
</data>
<data name="JsonSchemaProcessingFailure" xml:space="preserve">
<value>There was an error processing the schema: </value>
</data>
</root>