Skip to content
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

Added support for projects that do not enable global usings. #518

Merged
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
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,29 @@ Benchmark suites for various components.

The Source Generator which generates types from Json Schema.

## V4.1.2 Updates

Added the `--addExplicitUsings` switch to the code generator (and a corresponding property to the `generator-config.json` schema). If `true`, then
the source generator will emit the standard global usings explicitly into the generated source files. You can then use the generated code in a project that does not have `<ImplicitUsings>enable</ImplicitUsings>`.

```csharp
using global::System;
using global::System.Collections.Generic;
using global::System.IO;
using global::System.Linq;
using global::System.Net.Http;
using global::System.Threading;
using global::System.Threading.Tasks;
```

## V4.1.1 Updates

## Help for people building analyzers and source generators with JSON Schema code generation

We have built a self-contained package called Corvus.Json.SourceGeneratorTools for people looking to build .NET Analyzers or Source Generators that take advantage of JSON Schema code generation.

See the [README](./Solutions/Corvus.Json.SourceGeneratorTools/README.md) for details.

## V4.1 Updates

### YAML support
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,7 @@ public readonly struct Namespace(JsonReference baseUri, string dotnetNamespace)
/// <param name="fileExtension">Gets the file extension to use. Defaults to <c>.cs</c>.</param>
/// <param name="useImplicitOperatorString">If true, then the string conversion will be implicit.</param>
/// <param name="lineEndSequence">The line-end sequence. Defaults to <c>\r\n</c>.</param>
/// <param name="addExplicitUsings">If true, then the generated files will include using statements for the standard implicit usings. You should use this when your project does not use implicit usings.</param>
public class Options(
string defaultNamespace,
NamedType[]? namedTypes = null,
Expand All @@ -604,7 +605,8 @@ public class Options(
string[]? disabledNamingHeuristics = null,
string fileExtension = ".cs",
bool useImplicitOperatorString = false,
string lineEndSequence = "\r\n")
string lineEndSequence = "\r\n",
bool addExplicitUsings = false)
{
private readonly FrozenDictionary<string, NamedType> namedTypeMap = namedTypes?.ToFrozenDictionary(kvp => kvp.Reference, kvp => kvp) ?? FrozenDictionary<string, NamedType>.Empty;
private readonly FrozenDictionary<string, string> namespaceMap = namespaces?.ToFrozenDictionary(kvp => kvp.BaseUri, kvp => kvp.DotnetNamespace) ?? FrozenDictionary<string, string>.Empty;
Expand All @@ -625,7 +627,7 @@ public class Options(
internal bool UseOptionalNameHeuristics { get; } = useOptionalNameHeuristics;

/// <summary>
/// Gets a value indicating whether to always assert the format validation, regardless of the vocabularyy.
/// Gets a value indicating whether to always assert the format validation, regardless of the vocabulary.
/// </summary>
internal bool AlwaysAssertFormat { get; } = alwaysAssertFormat;

Expand All @@ -640,7 +642,7 @@ public class Options(
internal string FileExtension { get; } = fileExtension;

/// <summary>
/// Gets a value indicating whether to generate an implict operator for conversion to <see langword="string"/>.
/// Gets a value indicating whether to generate an implicit operator for conversion to <see langword="string"/>.
/// </summary>
internal bool UseImplicitOperatorString { get; } = useImplicitOperatorString;

Expand All @@ -654,6 +656,14 @@ public class Options(
/// </summary>
internal HashSet<string> DisabledNamingHeuristics { get; } = disabledNamingHeuristics is string[] n ? [.. n] : [];

/// <summary>
/// Gets a value indicating whether to include using statements for the standard implicit usings.
/// </summary>
/// <remarks>
/// You should use this when your project does not use implicit usings.
/// </remarks>
internal bool AddExplicitUsings { get; } = addExplicitUsings;

/// <summary>
/// Gets the namespace for the base URI.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,22 @@ public CodeGenerator EmitFile(CodeGenerator generator, TypeDeclaration typeDecla
{
if ((typeDeclaration.ImpliedCoreTypes() & CoreTypes.Array) != 0)
{
FrameworkType addExplicitUsings = typeDeclaration.AddExplicitUsings() ? FrameworkType.All : FrameworkType.NotEmitted;

generator
.BeginFile(typeDeclaration, "Array")
.AppendAutoGeneratedHeader()
.AppendLine()
.AppendLine("#nullable enable")
.AppendLine()
.AppendUsings(
new("global::System", addExplicitUsings),
new("global::System.Collections.Generic", addExplicitUsings),
new("global::System.IO", addExplicitUsings),
new("global::System.Linq", addExplicitUsings),
new("global::System.Net.Http", addExplicitUsings),
new("global::System.Threading", addExplicitUsings),
new("global::System.Threading.Tasks", addExplicitUsings),
new("System.Buffers", FrameworkType.Net80OrGreater),
"System.Collections",
"System.Collections.Immutable",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,22 @@ public CodeGenerator EmitFile(CodeGenerator generator, TypeDeclaration typeDecla
{
if ((typeDeclaration.ImpliedCoreTypes() & CoreTypes.Boolean) != 0)
{
FrameworkType addExplicitUsings = typeDeclaration.AddExplicitUsings() ? FrameworkType.All : FrameworkType.NotEmitted;

generator
.BeginFile(typeDeclaration, "Boolean")
.AppendAutoGeneratedHeader()
.AppendLine()
.AppendLine("#nullable enable")
.AppendLine()
.AppendUsings(
new("global::System", addExplicitUsings),
new("global::System.Collections.Generic", addExplicitUsings),
new("global::System.IO", addExplicitUsings),
new("global::System.Linq", addExplicitUsings),
new("global::System.Net.Http", addExplicitUsings),
new("global::System.Threading", addExplicitUsings),
new("global::System.Threading.Tasks", addExplicitUsings),
new("System.Collections.Immutable", EmitIfIsObjectOrArray(typeDeclaration)),
"System.Diagnostics.CodeAnalysis",
"System.Text.Json",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,22 @@ private CorePartial()
/// <inheritdoc/>
public CodeGenerator EmitFile(CodeGenerator generator, TypeDeclaration typeDeclaration)
{
FrameworkType addExplicitUsings = typeDeclaration.AddExplicitUsings() ? FrameworkType.All : FrameworkType.NotEmitted;

return generator
.BeginFile(typeDeclaration, string.Empty)
.AppendAutoGeneratedHeader()
.AppendLine()
.AppendLine("#nullable enable")
.AppendLine()
.AppendUsings(
new("global::System", addExplicitUsings),
new("global::System.Collections.Generic", addExplicitUsings),
new("global::System.IO", addExplicitUsings),
new("global::System.Linq", addExplicitUsings),
new("global::System.Net.Http", addExplicitUsings),
new("global::System.Threading", addExplicitUsings),
new("global::System.Threading.Tasks", addExplicitUsings),
"System.Buffers",
RequiresImmutableCollections(typeDeclaration) ? "System.Collections.Immutable" : ConditionalCodeSpecification.DoNotEmit,
"System.Runtime.CompilerServices",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,22 @@ public CodeGenerator EmitFile(CodeGenerator generator, TypeDeclaration typeDecla
{
if ((typeDeclaration.ImpliedCoreTypes() & (CoreTypes.Number | CoreTypes.Integer)) != 0)
{
FrameworkType addExplicitUsings = typeDeclaration.AddExplicitUsings() ? FrameworkType.All : FrameworkType.NotEmitted;

generator
.BeginFile(typeDeclaration, "Number")
.AppendAutoGeneratedHeader()
.AppendLine()
.AppendLine("#nullable enable")
.AppendLine()
.AppendUsings(
new("global::System", addExplicitUsings),
new("global::System.Collections.Generic", addExplicitUsings),
new("global::System.IO", addExplicitUsings),
new("global::System.Linq", addExplicitUsings),
new("global::System.Net.Http", addExplicitUsings),
new("global::System.Threading", addExplicitUsings),
new("global::System.Threading.Tasks", addExplicitUsings),
new("System.Collections.Immutable", EmitIfIsObjectOrArray(typeDeclaration)),
"System.Diagnostics.CodeAnalysis",
new("System.Numerics", FrameworkType.Net80OrGreater),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,22 @@ public CodeGenerator EmitFile(CodeGenerator generator, TypeDeclaration typeDecla
{
if ((typeDeclaration.ImpliedCoreTypes() & CoreTypes.Object) != 0)
{
FrameworkType addExplicitUsings = typeDeclaration.AddExplicitUsings() ? FrameworkType.All : FrameworkType.NotEmitted;

generator
.BeginFile(typeDeclaration, "Object")
.AppendAutoGeneratedHeader()
.AppendLine()
.AppendLine("#nullable enable")
.AppendLine()
.AppendUsings(
new("global::System", addExplicitUsings),
new("global::System.Collections.Generic", addExplicitUsings),
new("global::System.IO", addExplicitUsings),
new("global::System.Linq", addExplicitUsings),
new("global::System.Net.Http", addExplicitUsings),
new("global::System.Threading", addExplicitUsings),
new("global::System.Threading.Tasks", addExplicitUsings),
new("System.Collections", EmitIfIsMapObject(typeDeclaration)),
"System.Collections.Immutable",
new("System.Diagnostics.CodeAnalysis", EmitIfIsMapObject(typeDeclaration)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,22 @@ public CodeGenerator EmitFile(CodeGenerator generator, TypeDeclaration typeDecla
{
if ((typeDeclaration.ImpliedCoreTypes() & CoreTypes.String) != 0)
{
FrameworkType addExplicitUsings = typeDeclaration.AddExplicitUsings() ? FrameworkType.All : FrameworkType.NotEmitted;

generator
.BeginFile(typeDeclaration, "String")
.AppendAutoGeneratedHeader()
.AppendLine()
.AppendLine("#nullable enable")
.AppendLine()
.AppendUsings(
new("global::System", addExplicitUsings),
new("global::System.Collections.Generic", addExplicitUsings),
new("global::System.IO", addExplicitUsings),
new("global::System.Linq", addExplicitUsings),
new("global::System.Net.Http", addExplicitUsings),
new("global::System.Threading", addExplicitUsings),
new("global::System.Threading.Tasks", addExplicitUsings),
"System.Buffers",
new("System.Collections.Immutable", EmitIfIsObjectOrArray(typeDeclaration)),
"System.Diagnostics.CodeAnalysis",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,22 @@ public CodeGenerator EmitFile(CodeGenerator generator, TypeDeclaration typeDecla
// If we have any validation keywords, emit the validation file.
if (typeDeclaration.ValidationKeywords().Count != 0)
{
FrameworkType addExplicitUsings = typeDeclaration.AddExplicitUsings() ? FrameworkType.All : FrameworkType.NotEmitted;

generator
.BeginFile(typeDeclaration, "Validate")
.AppendAutoGeneratedHeader()
.AppendLine()
.AppendLine("#nullable enable")
.AppendLine()
.AppendUsings(
new("global::System", addExplicitUsings),
new("global::System.Collections.Generic", addExplicitUsings),
new("global::System.IO", addExplicitUsings),
new("global::System.Linq", addExplicitUsings),
new("global::System.Net.Http", addExplicitUsings),
new("global::System.Threading", addExplicitUsings),
new("global::System.Threading.Tasks", addExplicitUsings),
"System.Runtime.CompilerServices",
"System.Text.Json",
RequiresRegularExressions(typeDeclaration) ? "System.Text.RegularExpressions" : ConditionalCodeSpecification.DoNotEmit,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public static class TypeDeclarationExtensions
private const string OptionalAsNullableKey = "CSharp_LanguageProvider_OptionalAsNullable";
private const string PreferredBinaryJsonNumberKindKey = "CSharp_LanguageProvider_PreferredBinaryJsonNumberKind";
private const string UseImplicitOperatorStringKey = "CSharp_LanguageProvider_UseImplicitOperatorString";
private const string AddExplicitUsingsKey = "CSharp_LanguageProvider_AddExplicitUsings";

/// <summary>
/// Sets the relevant metadata from the <see cref="CSharpLanguageProvider.Options"/>.
Expand All @@ -34,6 +35,7 @@ public static void SetCSharpOptions(this TypeDeclaration typeDeclaration, CSharp
typeDeclaration.SetMetadata(AlwaysAssertFormatKey, options.AlwaysAssertFormat);
typeDeclaration.SetMetadata(OptionalAsNullableKey, options.OptionalAsNullable);
typeDeclaration.SetMetadata(UseImplicitOperatorStringKey, options.UseImplicitOperatorString);
typeDeclaration.SetMetadata(AddExplicitUsingsKey, options.AddExplicitUsings);
}

/// <summary>
Expand Down Expand Up @@ -180,6 +182,22 @@ public static bool UseImplicitOperatorString(this TypeDeclaration typeDeclaratio
return false;
}

/// <summary>
/// Gets a value indicating whether to generate using statements for the standard implicit usings.
/// </summary>
/// <param name="typeDeclaration">The type declaration to test.</param>
/// <returns><see langword="true"/> if the using statements should be added.</returns>
public static bool AddExplicitUsings(this TypeDeclaration typeDeclaration)
{
if (typeDeclaration.TryGetMetadata(AddExplicitUsingsKey, out bool? addExplicitUsings) &&
addExplicitUsings is bool value)
{
return value;
}

return false;
}

/// <summary>
/// Determines if the given name collides with the parent name.
/// </summary>
Expand Down
8 changes: 7 additions & 1 deletion Solutions/Corvus.Json.CodeGenerator/GenerateCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ public sealed class Settings : CommandSettings
[Description("If true, YAML support is enabled. You may use YAML, JSON or a mixture of such documents.")]
[DefaultValue(false)]
public bool SupportYaml { get; init; }

[CommandOption("--addExplicitUsings")]
[Description("If true, the generate will include using statements for the standard implicit usings.")]
[DefaultValue(false)]
public bool AddExplicitUsings { get; init; }
}

/// <inheritdoc/>
Expand All @@ -109,7 +114,8 @@ public override Task<int> ExecuteAsync(CommandContext context, Settings settings
useSchemaValue: settings.UseSchema != SchemaVariant.NotSpecified ? (GeneratorConfig.UseSchema)settings.UseSchema.ToString() : default(GeneratorConfig.UseSchema?),
useImplicitOperatorString: settings.UseImplicitOperatorString,
useUnixLineEndings: settings.UseUnixLineEndings,
supportYaml: settings.SupportYaml);
supportYaml: settings.SupportYaml,
addExplicitUsings: settings.AddExplicitUsings);

return GenerationDriver.GenerateTypes(config);
}
Expand Down
3 changes: 2 additions & 1 deletion Solutions/Corvus.Json.CodeGenerator/GenerationDriver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,8 @@ private static CSharpLanguageProvider.Options MapGeneratorConfigToOptions(in Gen
optionalAsNullable: (generatorConfig.OptionalAsNullableValue ?? GeneratorConfig.OptionalAsNullable.DefaultInstance).Equals(GeneratorConfig.OptionalAsNullable.EnumValues.NullOrUndefined),
disabledNamingHeuristics: generatorConfig.DisabledNamingHeuristics?.Select(n => (string)n).ToArray(),
useImplicitOperatorString: generatorConfig.UseImplicitOperatorString ?? false,
lineEndSequence: (generatorConfig.UseUnixLineEndings ?? false) ? "\n" : "\r\n");
lineEndSequence: (generatorConfig.UseUnixLineEndings ?? false) ? "\n" : "\r\n",
addExplicitUsings: generatorConfig.AddExplicitUsings ?? false);
}

private static async Task<string?> BeginMapFile(GeneratorConfig generatorConfig, string outputPath)
Expand Down
Loading
Loading