Skip to content

Commit

Permalink
[nuget-skip] Improved locking mechanism for header emission
Browse files Browse the repository at this point in the history
  • Loading branch information
Kaoticz committed May 23, 2024
1 parent fe77fbe commit 76e0587
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 37 deletions.
27 changes: 16 additions & 11 deletions Json2SharpLib/Emitters/CSharp/CSharpClassEmitter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,10 @@
namespace Json2SharpLib.Emitters.CSharp;

/// <summary>
/// Parses JSON data into a C# type declaration with the base body of a class definition.
/// Parses JSON data into a C# struct, class, or record with the base body of a class.
/// </summary>
internal sealed class CSharpClassEmitter : CodeEmitter
{
private int _stackCounter;
private readonly string _accessibility;
private readonly CSharpSerializationAttribute _serializationAttributeType;
private readonly string _serializationAttribute;
Expand All @@ -24,7 +23,7 @@ internal sealed class CSharpClassEmitter : CodeEmitter
private readonly string _setterType;

/// <summary>
/// Creates an object that parses JSON data into a C# type declaration with the base body of a class definition.
/// Parses JSON data into a C# struct, class, or record with the base body of a class.
/// </summary>
/// <param name="options">The parsing options.</param>
internal CSharpClassEmitter(Json2SharpCSharpOptions options)
Expand All @@ -42,22 +41,30 @@ internal CSharpClassEmitter(Json2SharpCSharpOptions options)

/// <inheritdoc />
public override string Parse(string objectName, JsonElement jsonElement)
=> InternalParse(objectName, jsonElement, true);

/// <summary>
/// Parse JSON data into a C# struct, class, or record.
/// </summary>
/// <param name="objectName">The name of the type.</param>
/// <param name="jsonElement">The JSON element to be processed.</param>
/// <param name="emitHeaders"><see langword="true"/> to include the "usings" at the beginning, <see langword="false"/> otherwise.</param>
/// <returns>The C# struct, class, or record.</returns>
private string InternalParse(string objectName, JsonElement jsonElement, bool emitHeaders)
{
objectName = objectName.ToPascalCase();
var properties = Json2Sharp.ParseProperties(jsonElement);

if (properties.Count is 0)
return string.Empty;

_stackCounter++;

var extraTypes = new List<string>();
var stringBuilder = new StringBuilder();

// Namespace declaration
if (_stackCounter is 1 && _serializationAttributeType is CSharpSerializationAttribute.SystemTextJson)
if (emitHeaders && _serializationAttributeType is CSharpSerializationAttribute.SystemTextJson)
stringBuilder.AppendLine(Constants.StjUsing + Environment.NewLine);
else if (_stackCounter is 1 && _serializationAttributeType is CSharpSerializationAttribute.NewtonsoftJson)
else if (emitHeaders && _serializationAttributeType is CSharpSerializationAttribute.NewtonsoftJson)
stringBuilder.AppendLine(Constants.NewtonsoftUsing + Environment.NewLine);

// Class declaration
Expand All @@ -71,8 +78,6 @@ public override string Parse(string objectName, JsonElement jsonElement)
// Add extra classes above the root class
AddCustomTypes(stringBuilder, extraTypes);

_stackCounter--;

return stringBuilder.ToStringAndClear();
}

Expand Down Expand Up @@ -189,7 +194,7 @@ private bool HandleCustomType(ParsedJsonProperty property, StringBuilder stringB
{
case JsonValueKind.Object:
var propertyName = property.JsonName ?? property.BclType.Name;
extraTypes.Add(Parse(propertyName, property.JsonElement));
extraTypes.Add(InternalParse(propertyName, property.JsonElement, false));
stringBuilder.AppendLine(ParseCustomType(property));

return true;
Expand All @@ -202,7 +207,7 @@ private bool HandleCustomType(ParsedJsonProperty property, StringBuilder stringB
stringBuilder.AppendLine(ParseArrayType(property, childrenTypes, out var typeName));

if (!typeName.Equals(J2SUtils.GetAliasName(typeof(object), Language.CSharp), StringComparison.Ordinal))
extraTypes.Add(Parse(typeName, childrenTypes[0].JsonElement));
extraTypes.Add(InternalParse(typeName, childrenTypes[0].JsonElement, false));

return true;
default:
Expand Down
27 changes: 16 additions & 11 deletions Json2SharpLib/Emitters/CSharp/CSharpRecordEmitter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,17 @@
namespace Json2SharpLib.Emitters.CSharp;

/// <summary>
/// Parses JSON data into a C# type declaration with the base body of a record definition using a primary constructor.
/// Parses JSON data into a C# record using a primary constructor.
/// </summary>
internal sealed class CSharpRecordEmitter : CodeEmitter
{
private int _stackCounter;
private readonly string _accessibility;
private readonly CSharpSerializationAttribute _serializationAttributeType;
private readonly string _serializationAttribute;
private readonly string _indentationPadding;

/// <summary>
/// Creates an object that parses JSON data into a C# type declaration with the base body of a record definition using a primary constructor.
/// Creates an object that parses JSON data into a C# record using a primary constructor.
/// </summary>
/// <param name="options">The parsing options.</param>
internal CSharpRecordEmitter(Json2SharpCSharpOptions options)
Expand All @@ -40,22 +39,30 @@ internal CSharpRecordEmitter(Json2SharpCSharpOptions options)

/// <inheritdoc />
public override string Parse(string objectName, JsonElement jsonElement)
=> InternalParse(objectName, jsonElement, true);

/// <summary>
/// Parse JSON data into a C# record.
/// </summary>
/// <param name="objectName">The name of the type.</param>
/// <param name="jsonElement">The JSON element to be processed.</param>
/// <param name="emitHeaders"><see langword="true"/> to include the "usings" at the beginning, <see langword="false"/> otherwise.</param>
/// <returns>The C# record.</returns>
private string InternalParse(string objectName, JsonElement jsonElement, bool emitHeaders)
{
objectName = objectName.ToPascalCase();
var properties = Json2Sharp.ParseProperties(jsonElement);

if (properties.Count is 0)
return string.Empty;

_stackCounter++;

var extraTypes = new List<string>();
var stringBuilder = new StringBuilder();

// Namespace declaration
if (_stackCounter is 1 && _serializationAttributeType is CSharpSerializationAttribute.SystemTextJson)
if (emitHeaders && _serializationAttributeType is CSharpSerializationAttribute.SystemTextJson)
stringBuilder.AppendLine(Constants.StjUsing + Environment.NewLine);
else if (_stackCounter is 1 && _serializationAttributeType is CSharpSerializationAttribute.NewtonsoftJson)
else if (emitHeaders && _serializationAttributeType is CSharpSerializationAttribute.NewtonsoftJson)
stringBuilder.AppendLine(Constants.NewtonsoftUsing + Environment.NewLine);

stringBuilder.AppendLine($"{_accessibility} record {objectName}(");
Expand All @@ -67,8 +74,6 @@ public override string Parse(string objectName, JsonElement jsonElement)
// Add extra classes above the root class
AddCustomTypes(stringBuilder, extraTypes);

_stackCounter--;

return stringBuilder.ToStringAndClear();
}

Expand Down Expand Up @@ -175,7 +180,7 @@ private bool HandleCustomType(ParsedJsonProperty property, StringBuilder stringB
{
case JsonValueKind.Object:
var propertyName = property.JsonName ?? property.BclType.Name;
extraTypes.Add(Parse(propertyName, property.JsonElement));
extraTypes.Add(InternalParse(propertyName, property.JsonElement, false));
stringBuilder.AppendLine(ParseCustomType(property));

return true;
Expand All @@ -188,7 +193,7 @@ private bool HandleCustomType(ParsedJsonProperty property, StringBuilder stringB
stringBuilder.AppendLine(ParseArrayType(property, childrenTypes, out var typeName));

if (!typeName.Equals(J2SUtils.GetAliasName(typeof(object), Language.CSharp), StringComparison.Ordinal))
extraTypes.Add(Parse(typeName, childrenTypes[0].JsonElement));
extraTypes.Add(InternalParse(typeName, childrenTypes[0].JsonElement, false));

return true;
default:
Expand Down
23 changes: 15 additions & 8 deletions Json2SharpLib/Emitters/Python/PythonClassEmitter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,15 @@
namespace Json2SharpLib.Emitters.Python;

/// <summary>
/// Parses JSON data into a Python type declaration.
/// Parses JSON data into a Python class.
/// </summary>
internal sealed class PythonClassEmitter : CodeEmitter
{
private int _stackCounter;
private readonly bool _addTypeHint;
private readonly string _indentationPadding;

/// <summary>
/// Creates an object that parses JSON data into a Python type declaration.
/// Creates an object that parses JSON data into a Python class.
/// </summary>
/// <param name="options">The parsing options.</param>
internal PythonClassEmitter(Json2SharpPythonOptions options)
Expand All @@ -33,15 +32,23 @@ internal PythonClassEmitter(Json2SharpPythonOptions options)

/// <inheritdoc />
public override string Parse(string objectName, JsonElement jsonElement)
=> InternalParse(objectName, jsonElement, true);

/// <summary>
/// Parse JSON data into a Python class.
/// </summary>
/// <param name="objectName">The name of the type.</param>
/// <param name="jsonElement">The JSON element to be processed.</param>
/// <param name="emitHeaders"><see langword="true"/> to include the "imports" at the beginning, <see langword="false"/> otherwise.</param>
/// <returns>The Python class.</returns>
private string InternalParse(string objectName, JsonElement jsonElement, bool emitHeaders)
{
objectName = objectName.ToPascalCase();
var properties = Json2Sharp.ParseProperties(jsonElement);

if (properties.Count is 0)
return string.Empty;

_stackCounter++;

var stringBuilder = BuildConstructorSignature(objectName, properties, out var extraTypes);

// Build the body of the constructor
Expand All @@ -55,7 +62,7 @@ public override string Parse(string objectName, JsonElement jsonElement)
AddCustomTypes(stringBuilder, extraTypes);

// Add the imports
if (--_stackCounter == default && _addTypeHint)
if (emitHeaders && _addTypeHint)
{
var hasUuid = stringBuilder.Contains(": uuid");
var hasDatetime = stringBuilder.Contains(": datetime");
Expand Down Expand Up @@ -172,7 +179,7 @@ private bool HandleCustomType(ParsedJsonProperty property, StringBuilder stringB
{
case JsonValueKind.Object:
stringBuilder.AppendIndentedLine(ParseCustomType(property), _indentationPadding, 2);
extraTypes.Add(Parse(property.JsonName!, property.JsonElement));
extraTypes.Add(InternalParse(property.JsonName!, property.JsonElement, false));

return true;
case JsonValueKind.Array:
Expand All @@ -184,7 +191,7 @@ private bool HandleCustomType(ParsedJsonProperty property, StringBuilder stringB
stringBuilder.AppendIndentedLine(ParseArrayType(property, childrenTypes, out var typeName), _indentationPadding, 2);

if (!typeName.Equals(J2SUtils.GetAliasName(typeof(object), Language.Python), StringComparison.Ordinal))
extraTypes.Add(Parse(typeName, childrenTypes[0].JsonElement));
extraTypes.Add(InternalParse(typeName, childrenTypes[0].JsonElement, false));

return true;
default:
Expand Down
25 changes: 18 additions & 7 deletions Json2SharpLib/Emitters/Python/PythonDataClassEmitter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,16 @@
namespace Json2SharpLib.Emitters.Python;

/// <summary>
/// Parses JSON data into a Python data class declaration.
/// Parses JSON data into a Python data class.
/// </summary>
internal sealed class PythonDataClassEmitter : CodeEmitter
{
private int _stackCounter;
private readonly string _indentationPadding;

/// <summary>
/// Creates an object that parses JSON data into a Python data class.
/// </summary>
/// <param name="options">The parsing options.</param>
internal PythonDataClassEmitter(Json2SharpPythonOptions options)
{
_indentationPadding = new string(
Expand All @@ -27,22 +30,30 @@ internal PythonDataClassEmitter(Json2SharpPythonOptions options)

/// <inheritdoc />
public override string Parse(string objectName, JsonElement jsonElement)
=> InternalParse(objectName, jsonElement, true);

/// <summary>
/// Parse JSON data into a Python data class.
/// </summary>
/// <param name="objectName">The name of the type.</param>
/// <param name="jsonElement">The JSON element to be processed.</param>
/// <param name="emitHeaders"><see langword="true"/> to include the "imports" at the beginning, <see langword="false"/> otherwise.</param>
/// <returns>The Python data class.</returns>
private string InternalParse(string objectName, JsonElement jsonElement, bool emitHeaders)
{
objectName = objectName.ToPascalCase();
var properties = Json2Sharp.ParseProperties(jsonElement);

if (properties.Count is 0)
return string.Empty;

_stackCounter++;

var stringBuilder = BuildDataClass(objectName, properties, out var extraTypes);

// Add extra classes above the root class
AddCustomTypes(stringBuilder, extraTypes);

// Add the imports
if (--_stackCounter == default)
if (emitHeaders)
{
stringBuilder.Insert(0, Environment.NewLine + Environment.NewLine);

Expand Down Expand Up @@ -145,7 +156,7 @@ private bool HandleCustomType(ParsedJsonProperty property, StringBuilder stringB
{
case JsonValueKind.Object:
stringBuilder.AppendIndentedLine(ParseCustomType(property), _indentationPadding, 1);
extraTypes.Add(Parse(property.JsonName!, property.JsonElement));
extraTypes.Add(InternalParse(property.JsonName!, property.JsonElement, false));

return true;
case JsonValueKind.Array:
Expand All @@ -157,7 +168,7 @@ private bool HandleCustomType(ParsedJsonProperty property, StringBuilder stringB
stringBuilder.AppendIndentedLine(ParseArrayType(property, childrenTypes, out var typeName), _indentationPadding, 1);

if (!typeName.Equals(J2SUtils.GetAliasName(typeof(object), Language.Python), StringComparison.Ordinal))
extraTypes.Add(Parse(typeName, childrenTypes[0].JsonElement));
extraTypes.Add(InternalParse(typeName, childrenTypes[0].JsonElement, false));

return true;
default:
Expand Down

0 comments on commit 76e0587

Please sign in to comment.