Skip to content

Commit

Permalink
Optimize type resolving (RicoSuter#1629)
Browse files Browse the repository at this point in the history
* reuse same HashSet for reservedTypeNames instead re-creating on every cache miss
* cleanup csprojs
* remove build configurations for _build project in solution file
* use string interpolation for better optimizations
  • Loading branch information
lahma authored Oct 2, 2023
1 parent c621b17 commit d6f0d01
Show file tree
Hide file tree
Showing 23 changed files with 146 additions and 140 deletions.
11 changes: 6 additions & 5 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,21 @@ jobs:
name: windows-latest
runs-on: windows-latest
steps:
- uses: actions/checkout@v1
- name: Cache .nuke/temp, ~/.nuget/packages
uses: actions/cache@v2
- uses: actions/checkout@v3
- name: 'Cache: .nuke/temp, ~/.nuget/packages'
uses: actions/cache@v3
with:
path: |
.nuke/temp
~/.nuget/packages
key: ${{ runner.os }}-${{ hashFiles('global.json', 'src/**/*.csproj', 'src/**/package.json') }}
- name: Run './build.cmd Compile Test Pack Publish'
- name: 'Run: Compile, Test, Pack, Publish'
run: ./build.cmd Compile Test Pack Publish
env:
NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
MYGET_API_KEY: ${{ secrets.MYGET_API_KEY }}
- uses: actions/upload-artifact@v1
- name: 'Publish: artifacts'
uses: actions/upload-artifact@v3
with:
name: artifacts
path: artifacts
8 changes: 4 additions & 4 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@ jobs:
name: windows-latest
runs-on: windows-latest
steps:
- uses: actions/checkout@v1
- name: Cache .nuke/temp, ~/.nuget/packages
uses: actions/cache@v2
- uses: actions/checkout@v3
- name: 'Cache: .nuke/temp, ~/.nuget/packages'
uses: actions/cache@v3
with:
path: |
.nuke/temp
~/.nuget/packages
key: ${{ runner.os }}-${{ hashFiles('global.json', 'src/**/*.csproj', 'src/**/package.json') }}
- name: Run './build.cmd Compile Test Pack'
- name: 'Run: Compile, Test, Pack'
run: ./build.cmd Compile Test Pack
9 changes: 5 additions & 4 deletions .nuke/build.schema.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Build Schema",
"$ref": "#/definitions/build",
"title": "Build Schema",
"definitions": {
"build": {
"type": "object",
Expand Down Expand Up @@ -29,6 +29,7 @@
"AppVeyor",
"AzurePipelines",
"Bamboo",
"Bitbucket",
"Bitrise",
"GitHubActions",
"GitLab",
Expand All @@ -44,15 +45,15 @@
},
"MyGetApiKey": {
"type": "string",
"default": "Secrets must be entered via 'nuke :secret [profile]'"
"default": "Secrets must be entered via 'nuke :secrets [profile]'"
},
"NoLogo": {
"type": "boolean",
"description": "Disables displaying the NUKE logo"
},
"NuGetApiKey": {
"type": "string",
"default": "Secrets must be entered via 'nuke :secret [profile]'"
"default": "Secrets must be entered via 'nuke :secrets [profile]'"
},
"Partition": {
"type": "string",
Expand Down Expand Up @@ -120,4 +121,4 @@
}
}
}
}
}
9 changes: 7 additions & 2 deletions build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ $TempDirectory = "$PSScriptRoot\\.nuke\temp"

$DotNetGlobalFile = "$PSScriptRoot\\global.json"
$DotNetInstallUrl = "https://dot.net/v1/dotnet-install.ps1"
$DotNetChannel = "Current"
$DotNetChannel = "STS"

$env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE = 1
$env:DOTNET_CLI_TELEMETRY_OPTOUT = 1
Expand Down Expand Up @@ -63,7 +63,12 @@ else {
$env:DOTNET_EXE = "$DotNetDirectory\dotnet.exe"
}

Write-Output "Microsoft (R) .NET Core SDK version $(& $env:DOTNET_EXE --version)"
Write-Output "Microsoft (R) .NET SDK version $(& $env:DOTNET_EXE --version)"

if (Test-Path env:NUKE_ENTERPRISE_TOKEN) {
& $env:DOTNET_EXE nuget remove source "nuke-enterprise" > $null
& $env:DOTNET_EXE nuget add source "https://f.feedz.io/nuke/enterprise/nuget" --name "nuke-enterprise" --username "PAT" --password $env:NUKE_ENTERPRISE_TOKEN > $null
}

ExecSafe { & $env:DOTNET_EXE build $BuildProjectFile /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet }
ExecSafe { & $env:DOTNET_EXE run --project $BuildProjectFile --no-build -- $BuildArguments }
9 changes: 7 additions & 2 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ TEMP_DIRECTORY="$SCRIPT_DIR//.nuke/temp"

DOTNET_GLOBAL_FILE="$SCRIPT_DIR//global.json"
DOTNET_INSTALL_URL="https://dot.net/v1/dotnet-install.sh"
DOTNET_CHANNEL="Current"
DOTNET_CHANNEL="STS"

export DOTNET_CLI_TELEMETRY_OPTOUT=1
export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
Expand Down Expand Up @@ -56,7 +56,12 @@ else
export DOTNET_EXE="$DOTNET_DIRECTORY/dotnet"
fi

echo "Microsoft (R) .NET Core SDK version $("$DOTNET_EXE" --version)"
echo "Microsoft (R) .NET SDK version $("$DOTNET_EXE" --version)"

if [[ ! -z ${NUKE_ENTERPRISE_TOKEN+x} && "NUKE_ENTERPRISE_TOKEN" != "" ]]; then
"$DOTNET_EXE" nuget remove source "nuke-enterprise" &>/dev/null || true
"$DOTNET_EXE" nuget add source "https://f.feedz.io/nuke/enterprise/nuget" --name "nuke-enterprise" --username "PAT" --password "$NUKE_ENTERPRISE_TOKEN" --store-password-in-clear-text &>/dev/null || true
fi

"$DOTNET_EXE" build "$BUILD_PROJECT_FILE" /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet
"$DOTNET_EXE" run --project "$BUILD_PROJECT_FILE" --no-build -- "$@"
2 changes: 1 addition & 1 deletion build/_build.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Nuke.Common" Version="7.0.2" />
<PackageReference Include="Nuke.Common" Version="7.0.6" />
<PackageDownload Include="NuGet.CommandLine" Version="[5.11.0]" />
</ItemGroup>

Expand Down
30 changes: 30 additions & 0 deletions src/NJsonSchema.Benchmark/CSharpTypeResolverBenchmark.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using BenchmarkDotNet.Attributes;
using NJsonSchema.CodeGeneration.CSharp;

namespace NJsonSchema.Benchmark;

[MemoryDiagnoser]
public class CSharpTypeResolverBenchmark
{
private Dictionary<string, JsonSchema> _definitions;
private CSharpGeneratorSettings _settings;

[GlobalSetup]
public async Task Setup()
{
var json = await JsonSchemaBenchmark.ReadJson();
var schema = await JsonSchema.FromJsonAsync(json);
_definitions = schema.Definitions.ToDictionary(p => p.Key, p => p.Value);
_settings = new CSharpGeneratorSettings();
}

[Benchmark]
public void RegisterSchemaDefinitions()
{
var resolver = new CSharpTypeResolver(_settings, exceptionSchema: null);
resolver.RegisterSchemaDefinitions(_definitions);
}
}
Original file line number Diff line number Diff line change
@@ -1,29 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<IsPackable>false</IsPackable>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>$(NoWarn),1587,1998,1591,618,SYSLIB0012</NoWarn>
<TargetFramework>net6.0</TargetFramework>
<IsPackable>false</IsPackable>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>$(NoWarn),1587,1998,1591,618,SYSLIB0012</NoWarn>
</PropertyGroup>

<ItemGroup>
<Content Include="References\*.json" CopyToOutputDirectory="Always" />
<Content Include="References\*.json" CopyToOutputDirectory="Always" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.11.0" Condition="'$(TargetFramework)' == 'net6.0'" />
<PackageReference Condition="'$(TargetFramework)' == 'net6.0'" Include="System.ComponentModel.Annotations" Version="4.4.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.11.0" Condition="'$(TargetFramework)' == 'net6.0'" />
<PackageReference Condition="'$(TargetFramework)' == 'net6.0'" Include="System.ComponentModel.Annotations" Version="4.4.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\NJsonSchema.CodeGeneration.CSharp\NJsonSchema.CodeGeneration.CSharp.csproj" />
<ProjectReference Include="..\NJsonSchema.CodeGeneration\NJsonSchema.CodeGeneration.csproj" />
<ProjectReference Include="..\NJsonSchema.NewtonsoftJson\NJsonSchema.NewtonsoftJson.csproj" />
<ProjectReference Include="..\NJsonSchema\NJsonSchema.csproj" />
<ProjectReference Include="..\NJsonSchema.CodeGeneration.CSharp\NJsonSchema.CodeGeneration.CSharp.csproj" />
<ProjectReference Include="..\NJsonSchema.NewtonsoftJson\NJsonSchema.NewtonsoftJson.csproj" />
</ItemGroup>

</Project>
6 changes: 3 additions & 3 deletions src/NJsonSchema.CodeGeneration.CSharp/CSharpTypeResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ private string ResolveArrayOrTuple(JsonSchema schema)
{
var itemTypeNameHint = (schema as JsonSchemaProperty)?.Name;
var itemType = Resolve(schema.Item, schema.Item.IsNullable(Settings.SchemaType), itemTypeNameHint);
return string.Format(Settings.ArrayType + "<{0}>", itemType);
return $"{Settings.ArrayType}<{itemType}>";
}

if (schema.Items != null && schema.Items.Count > 0)
Expand All @@ -279,7 +279,7 @@ private string ResolveArrayOrTuple(JsonSchema schema)
.Select(i => Resolve(i, i.IsNullable(Settings.SchemaType), null))
.ToArray();

return string.Format("System.Tuple<" + string.Join(", ", tupleTypes) + ">");
return $"System.Tuple<{string.Join(", ", tupleTypes)}>";
}

return Settings.ArrayType + "<object>";
Expand All @@ -289,7 +289,7 @@ private string ResolveDictionary(JsonSchema schema)
{
var valueType = ResolveDictionaryValueType(schema, "object");
var keyType = ResolveDictionaryKeyType(schema, "string");
return string.Format(Settings.DictionaryType + "<{0}, {1}>", keyType, valueType);
return $"{Settings.DictionaryType}<{keyType}, {valueType}>";
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,8 @@
<EmbeddedResource Include="Templates\*.liquid" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\NJsonSchema.CodeGeneration\NJsonSchema.CodeGeneration.csproj" />
<ProjectReference Include="..\NJsonSchema\NJsonSchema.csproj" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,7 @@
<ItemGroup>
<ProjectReference Include="..\NJsonSchema.CodeGeneration.CSharp\NJsonSchema.CodeGeneration.CSharp.csproj" />
<ProjectReference Include="..\NJsonSchema.CodeGeneration.TypeScript\NJsonSchema.CodeGeneration.TypeScript.csproj" />
<ProjectReference Include="..\NJsonSchema.CodeGeneration\NJsonSchema.CodeGeneration.csproj" />
<ProjectReference Include="..\NJsonSchema.NewtonsoftJson\NJsonSchema.NewtonsoftJson.csproj" />
<ProjectReference Include="..\NJsonSchema\NJsonSchema.csproj" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,7 @@

<ItemGroup>
<ProjectReference Include="..\NJsonSchema.CodeGeneration.TypeScript\NJsonSchema.CodeGeneration.TypeScript.csproj" />
<ProjectReference Include="..\NJsonSchema.CodeGeneration\NJsonSchema.CodeGeneration.csproj" />
<ProjectReference Include="..\NJsonSchema.NewtonsoftJson\NJsonSchema.NewtonsoftJson.csproj" />
<ProjectReference Include="..\NJsonSchema\NJsonSchema.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,8 @@
<EmbeddedResource Include="Templates\File.ParseDateOnly.liquid" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\NJsonSchema.CodeGeneration\NJsonSchema.CodeGeneration.csproj" />
<ProjectReference Include="..\NJsonSchema\NJsonSchema.csproj" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -314,15 +314,15 @@ private string ResolveArrayOrTuple(JsonSchema schema, string typeNameHint, bool
// is TypeUnion
if (itemTypes.Count > 1)
{
itemType = string.Format("({0})", itemType);
itemType = $"({itemType})";
}

return string.Format("{0}[]", itemType);
return $"{itemType}[]";
}
else
{
var itemType = prefix + Resolve(schema.Item, true, typeNameHint);
return string.Format("{0}[]", GetNullableItemType(schema, itemType)); // TODO: Make typeNameHint singular if possible
return $"{GetNullableItemType(schema, itemType)}[]"; // TODO: Make typeNameHint singular if possible
}
}

Expand All @@ -332,7 +332,7 @@ private string ResolveArrayOrTuple(JsonSchema schema, string typeNameHint, bool
.Select(s => GetNullableItemType(s, Resolve(s, false, null)))
.ToArray();

return string.Format("[" + string.Join(", ", tupleTypes) + "]");
return $"[{string.Join(", ", tupleTypes)}]";
}

return "any[]";
Expand All @@ -342,7 +342,7 @@ private string GetNullableItemType(JsonSchema schema, string itemType)
{
if (Settings.SupportsStrictNullChecks && schema.Item.IsNullable(Settings.SchemaType))
{
return string.Format("({0} | {1})", itemType, Settings.NullValue.ToString().ToLowerInvariant());
return $"({itemType} | {Settings.NullValue.ToString().ToLowerInvariant()})";
}

return itemType;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@

<ItemGroup>
<PackageReference Include="Fluid.Core" Version="2.4.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>

<ItemGroup>
Expand Down
12 changes: 6 additions & 6 deletions src/NJsonSchema.CodeGeneration/TypeResolverBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public abstract class TypeResolverBase
{
private readonly CodeGeneratorSettingsBase _settings;
internal readonly Dictionary<JsonSchema, string> _generatedTypeNames = new();
private readonly HashSet<string> _reservedTypeNames = new();

/// <summary>Initializes a new instance of the <see cref="TypeResolverBase" /> class.</summary>
/// <param name="settings">The settings.</param>
Expand Down Expand Up @@ -55,9 +56,9 @@ public virtual string GetOrGenerateTypeName(JsonSchema schema, string typeNameHi

if (!_generatedTypeNames.TryGetValue(schema, out var typeNames))
{
var reservedTypeNames = new HashSet<string>(_generatedTypeNames.Values);
typeNames = _settings.TypeNameGenerator.Generate(schema, typeNameHint, reservedTypeNames);
typeNames = _settings.TypeNameGenerator.Generate(schema, typeNameHint, _reservedTypeNames);
_generatedTypeNames[schema] = typeNames;
_reservedTypeNames.Add(typeNames);
}

return typeNames;
Expand Down Expand Up @@ -87,7 +88,7 @@ public void RegisterSchemaDefinitions(IDictionary<string, JsonSchema> definition
public virtual JsonSchema RemoveNullability(JsonSchema schema)
{
// TODO: Method on JsonSchema4?
return schema.OneOf.FirstOrDefault(o => !o.IsNullable(SchemaType.JsonSchema)) ?? schema;
return schema.OneOf.FirstOrDefault(static o => !o.IsNullable(SchemaType.JsonSchema)) ?? schema;
}

/// <summary>Gets the actual schema (i.e. when not referencing a type schema or it is inlined)
Expand Down Expand Up @@ -141,10 +142,9 @@ protected string ResolveDictionaryValueType(JsonSchema schema, string fallbackTy

if (schema.AllowAdditionalProperties == false && schema.PatternProperties.Any())
{
var valueTypes = schema.PatternProperties
var valueTypes = new HashSet<string>(schema.PatternProperties
.Select(p => Resolve(p.Value, p.Value.IsNullable(_settings.SchemaType), null))
.Distinct()
.ToList();
);

if (valueTypes.Count == 1)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@

<ItemGroup>
<ProjectReference Include="..\NJsonSchema.NewtonsoftJson\NJsonSchema.NewtonsoftJson.csproj" />
<ProjectReference Include="..\NJsonSchema\NJsonSchema.csproj" />
</ItemGroup>

</Project>
Loading

0 comments on commit d6f0d01

Please sign in to comment.