Add JSON schema validation to source gen
This commit is contained in:
parent
53f20c9e20
commit
caf8cfe7ef
@ -16,6 +16,9 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Json.More.Net" Version="2.0.1.2" GeneratePathProperty="true" />
|
||||||
|
<PackageReference Include="JsonPointer.Net" Version="5.0.0" GeneratePathProperty="true" />
|
||||||
|
<PackageReference Include="JsonSchema.Net" Version="7.0.4" GeneratePathProperty="true" />
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4">
|
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
@ -29,9 +32,16 @@
|
|||||||
<ProjectReference Include="..\Questionable.Model\Questionable.Model.csproj" />
|
<ProjectReference Include="..\Questionable.Model\Questionable.Model.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<GetTargetPathDependsOn>$(GetTargetPathDependsOn);GetDependencyTargetPaths</GetTargetPathDependsOn>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<Target Name="GetDependencyTargetPaths" AfterTargets="ResolvePackageDependenciesForBuild">
|
<Target Name="GetDependencyTargetPaths" AfterTargets="ResolvePackageDependenciesForBuild">
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<TargetPathWithTargetPlatformMoniker Include="..\Questionable.Model\$(OutputPath)\*.dll" IncludeRuntimeDependency="false" />
|
<TargetPathWithTargetPlatformMoniker Include="..\Questionable.Model\$(OutputPath)\*.dll" IncludeRuntimeDependency="false" />
|
||||||
|
<TargetPathWithTargetPlatformMoniker Include="$(PkgJson_More_Net)\lib\netstandard2.0\Json.More.dll" IncludeRuntimeDependency="false" />
|
||||||
|
<TargetPathWithTargetPlatformMoniker Include="$(PkgJsonPointer_Net)\lib\netstandard2.0\JsonPointer.Net.dll" IncludeRuntimeDependency="false" />
|
||||||
|
<TargetPathWithTargetPlatformMoniker Include="$(PkgJsonSchema_Net)\lib\netstandard2.0\JsonSchema.Net.dll" IncludeRuntimeDependency="false" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Target>
|
</Target>
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Nodes;
|
||||||
|
using Json.Schema;
|
||||||
using Microsoft.CodeAnalysis;
|
using Microsoft.CodeAnalysis;
|
||||||
using Microsoft.CodeAnalysis.CSharp;
|
using Microsoft.CodeAnalysis.CSharp;
|
||||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
@ -17,8 +21,16 @@ namespace Questionable.QuestPathGenerator;
|
|||||||
/// When using a simple text file as a baseline, we can create a non-incremental source generator.
|
/// When using a simple text file as a baseline, we can create a non-incremental source generator.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Generator]
|
[Generator]
|
||||||
|
[SuppressMessage("MicrosoftCodeAnalysisReleaseTracking", "RS2008")]
|
||||||
public class QuestSourceGenerator : ISourceGenerator
|
public class QuestSourceGenerator : ISourceGenerator
|
||||||
{
|
{
|
||||||
|
private static readonly DiagnosticDescriptor InvalidJson = new("QSG0001",
|
||||||
|
"Invalid JSON",
|
||||||
|
"Invalid quest file {0}",
|
||||||
|
nameof(QuestSourceGenerator),
|
||||||
|
DiagnosticSeverity.Error,
|
||||||
|
true);
|
||||||
|
|
||||||
public void Initialize(GeneratorInitializationContext context)
|
public void Initialize(GeneratorInitializationContext context)
|
||||||
{
|
{
|
||||||
// No initialization required for this generator.
|
// No initialization required for this generator.
|
||||||
@ -28,10 +40,15 @@ public class QuestSourceGenerator : ISourceGenerator
|
|||||||
{
|
{
|
||||||
List<(ushort, QuestData)> quests = [];
|
List<(ushort, QuestData)> quests = [];
|
||||||
|
|
||||||
|
// Find schema definition
|
||||||
|
AdditionalText jsonSchemaFile =
|
||||||
|
context.AdditionalFiles.Single(x => Path.GetFileName(x.Path) == "quest-v1.json");
|
||||||
|
var questSchema = JsonSchema.FromText(jsonSchemaFile.GetText()!.ToString());
|
||||||
|
|
||||||
// Go through all files marked as an Additional File in file properties.
|
// Go through all files marked as an Additional File in file properties.
|
||||||
foreach (var additionalFile in context.AdditionalFiles)
|
foreach (var additionalFile in context.AdditionalFiles)
|
||||||
{
|
{
|
||||||
if (additionalFile == null)
|
if (additionalFile == null || additionalFile == jsonSchemaFile)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (Path.GetExtension(additionalFile.Path) != ".json")
|
if (Path.GetExtension(additionalFile.Path) != ".json")
|
||||||
@ -44,7 +61,21 @@ public class QuestSourceGenerator : ISourceGenerator
|
|||||||
if (text == null)
|
if (text == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var quest = JsonSerializer.Deserialize<QuestData>(text.ToString())!;
|
var questNode = JsonNode.Parse(text.ToString());
|
||||||
|
var evaluationResult = questSchema.Evaluate(questNode, new EvaluationOptions()
|
||||||
|
{
|
||||||
|
Culture = CultureInfo.InvariantCulture,
|
||||||
|
OutputFormat = OutputFormat.List
|
||||||
|
});
|
||||||
|
if (!evaluationResult.IsValid)
|
||||||
|
{
|
||||||
|
var error = Diagnostic.Create(InvalidJson,
|
||||||
|
null,
|
||||||
|
Path.GetFileName(additionalFile.Path));
|
||||||
|
context.ReportDiagnostic(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
var quest = questNode.Deserialize<QuestData>()!;
|
||||||
quests.Add((id, quest));
|
quests.Add((id, quest));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,34 @@
|
|||||||
"version": 1,
|
"version": 1,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
".NETStandard,Version=v2.0": {
|
".NETStandard,Version=v2.0": {
|
||||||
|
"Json.More.Net": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[2.0.1.2, )",
|
||||||
|
"resolved": "2.0.1.2",
|
||||||
|
"contentHash": "uF3QeiaXEfH92emz0/BWUiNtMSfxIIvgynuB0Bf1vF4s8eWTcZitBx9l+g/FDaJk5XxqBv9buQXizXKQcXFG1w==",
|
||||||
|
"dependencies": {
|
||||||
|
"System.Text.Json": "8.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"JsonPointer.Net": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[5.0.0, )",
|
||||||
|
"resolved": "5.0.0",
|
||||||
|
"contentHash": "fm4T5w20AY6C+p5/pJr0vrXRNGgtSfHl34I1LxC9zdPwS9S3j0GiR1Mz/CVPWKDXXGDpCt1APHpCq7kn5adCfA==",
|
||||||
|
"dependencies": {
|
||||||
|
"Humanizer.Core": "2.14.1",
|
||||||
|
"Json.More.Net": "2.0.1.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"JsonSchema.Net": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[7.0.4, )",
|
||||||
|
"resolved": "7.0.4",
|
||||||
|
"contentHash": "R0Hk2Tr/np4Q1NO8CBjyQsoiD1iFJyEQP20Sw7JnZCNGJoaSBe+g4b+nZqnBXPQhiqY5LGZ8JZwZkRh/eKZhEQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"JsonPointer.Net": "5.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"Microsoft.CodeAnalysis.Analyzers": {
|
"Microsoft.CodeAnalysis.Analyzers": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
"requested": "[3.3.4, )",
|
"requested": "[3.3.4, )",
|
||||||
|
@ -22,8 +22,10 @@
|
|||||||
<None Remove="ARealmReborn"/>
|
<None Remove="ARealmReborn"/>
|
||||||
<None Remove="Shadowbringers"/>
|
<None Remove="Shadowbringers"/>
|
||||||
<None Remove="Endwalker"/>
|
<None Remove="Endwalker"/>
|
||||||
|
<None Remove="quest-v1.json" />
|
||||||
<AdditionalFiles Include="ARealmReborn\**\*.json" />
|
<AdditionalFiles Include="ARealmReborn\**\*.json" />
|
||||||
<AdditionalFiles Include="Shadowbringers\**\*.json" />
|
<AdditionalFiles Include="Shadowbringers\**\*.json" />
|
||||||
<AdditionalFiles Include="Endwalker\**\*.json" />
|
<AdditionalFiles Include="Endwalker\**\*.json" />
|
||||||
|
<AdditionalFiles Include="quest-v1.json" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -400,7 +400,14 @@
|
|||||||
"if": {
|
"if": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"InteractionType": {
|
"InteractionType": {
|
||||||
"const": "Interact"
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"const": "Interact"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"const": "SinglePlayerDuty"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user