Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/fern-api/fern into niels/cs…
Browse files Browse the repository at this point in the history
…harp/editorconfig
  • Loading branch information
Swimburger committed Mar 3, 2025
2 parents 3ee2e9a + c747a5f commit 7273051
Show file tree
Hide file tree
Showing 650 changed files with 16,926 additions and 1,285 deletions.
3 changes: 3 additions & 0 deletions fern/pages/changelogs/csharp-model/2025-03-02.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## 0.0.2
**`(internal):`** Upgrade to IR version 56.

11 changes: 7 additions & 4 deletions generators/csharp/codegen/src/AsIs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export const COLLECTION_ITEM_SERIALIZER_CLASS_NAME = "CollectionItemSerializer";
export const DATETIME_SERIALIZER_CLASS_NAME = "DateTimeSerializer";
export const CONSTANTS_CLASS_NAME = "Constants";
export const JSON_UTILS_CLASS_NAME = "JsonUtils";
export const JSON_ACCESS_ATTRIBUTE_NAME = "JsonAccess";

export const AsIsFiles = {
CiYaml: "github-ci.yml",
Expand All @@ -30,10 +31,11 @@ export const AsIsFiles = {
EditorConfig: ".editorconfig.Template",
Json: {
CollectionItemSerializer: "CollectionItemSerializer.Template.cs",
DateTimeSerializer: "DateTimeSerializer.Template.cs",
DateOnlyConverter: "DateOnlyConverter.Template.cs",
DateTimeSerializer: "DateTimeSerializer.Template.cs",
EnumConverter: "EnumConverter.Template.cs",
EnumSerializer: "EnumSerializer.Template.cs",
JsonAccessAttribute: "JsonAccessAttribute.Template.cs",
JsonConfiguration: "JsonConfiguration.Template.cs",
OneOfSerializer: "OneOfSerializer.Template.cs",
StringEnumSerializer: "StringEnumSerializer.Template.cs"
Expand All @@ -54,11 +56,12 @@ export const AsIsFiles = {
"test/Pagination/StringCursorTest.Template.cs"
],
Json: {
OneOfSerializerTests: "test/Json/OneOfSerializerTests.Template.cs",
DateOnlyJsonTests: "test/Json/DateOnlyJsonTests.Template.cs",
DateTimeJsonTests: "test/Json/DateTimeJsonTests.Template.cs",
EnumSerializerTests: "test/Json/EnumSerializerTests.Template.cs",
OneOfSerializerTests: "test/Json/OneOfSerializerTests.Template.cs",
StringEnumSerializerTests: "test/Json/StringEnumSerializerTests.Template.cs",
DateOnlyJsonTests: "test/Json/DateOnlyJsonTests.Template.cs",
DateTimeJsonTests: "test/Json/DateTimeJsonTests.Template.cs"
JsonAccessAttributeTests: "test/Json/JsonAccessAttributeTests.Template.cs"
}
}
};
13 changes: 13 additions & 0 deletions generators/csharp/codegen/src/asIs/JsonAccessAttribute.Template.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace <%= namespace%>;

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
internal class JsonAccessAttribute(JsonAccessType accessType) : Attribute
{
internal JsonAccessType AccessType { get; init; } = accessType;
}

internal enum JsonAccessType
{
ReadOnly,
WriteOnly
}
59 changes: 51 additions & 8 deletions generators/csharp/codegen/src/asIs/JsonConfiguration.Template.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using global::System.Text.Json;
using global::System.Text.Json.Serialization;
using global::System.Text.Json.Serialization.Metadata;

namespace <%= namespace%>;

Expand All @@ -11,15 +12,57 @@ static JsonOptions()
{
var options = new JsonSerializerOptions
{
Converters = {
Converters =
{
new DateTimeSerializer(),
#if USE_PORTABLE_DATE_ONLY
#if USE_PORTABLE_DATE_ONLY
new DateOnlyConverter(),
#endif
new OneOfSerializer()
#endif
new OneOfSerializer(),
},
#if DEBUG
WriteIndented = true,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
#endif
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
TypeInfoResolver = new DefaultJsonTypeInfoResolver
{
Modifiers =
{
static typeInfo =>
{
if (typeInfo.Kind != JsonTypeInfoKind.Object)
return;

foreach (var propertyInfo in typeInfo.Properties)
{
var jsonAccessAttribute = propertyInfo
.AttributeProvider?.GetCustomAttributes(
typeof(JsonAccessAttribute),
true
)
.OfType<JsonAccessAttribute>()
.FirstOrDefault();

if (jsonAccessAttribute != null)
{
propertyInfo.IsRequired = false;
switch (jsonAccessAttribute.AccessType)
{
case JsonAccessType.ReadOnly:
propertyInfo.Get = null;
propertyInfo.ShouldSerialize = (_, _) => false;
break;
case JsonAccessType.WriteOnly:
propertyInfo.Set = null;
break;
default:
throw new ArgumentOutOfRangeException();
}
}
}
},
},
},
};
ConfigureJsonSerializerOptions(options);
JsonSerializerOptions = options;
Expand All @@ -45,4 +88,4 @@ public static T Deserialize<T>(string json)
{
return JsonSerializer.Deserialize<T>(json, JsonOptions.JsonSerializerOptions)!;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using global::System.Text.Json.Serialization;
using NUnit.Framework;
using <%= namespace%>.Core;

namespace <%= namespace%>.Test.Core.Json;

[TestFixture]
public class JsonAccessAttributeTests
{
private class MyClass
{
[JsonPropertyName("read_only_prop")]
[JsonAccess(JsonAccessType.ReadOnly)]
public string? ReadOnlyProp { get; set; }

[JsonPropertyName("write_only_prop")]
[JsonAccess(JsonAccessType.WriteOnly)]
public string? WriteOnlyProp { get; set; }

[JsonPropertyName("normal_prop")]
public string? NormalProp { get; set; }
}

[Test]
public void JsonAccessAttribute_ShouldWorkAsExpected()
{
const string json = """ { "read_only_prop": "read", "write_only_prop": "write", "normal_prop": "normal_prop" } """;
var obj = JsonUtils.Deserialize<MyClass>(json);

Assert.Multiple(() =>
{
Assert.That(obj.ReadOnlyProp, Is.EqualTo("read"));
Assert.That(obj.WriteOnlyProp, Is.Null);
Assert.That(obj.NormalProp, Is.EqualTo("normal_prop"));
});

obj.WriteOnlyProp = "write";
obj.NormalProp = "new_value";

var serializedJson = JsonUtils.Serialize(obj);
const string expectedJson = "{\n \"write_only_prop\": \"write\",\n \"normal_prop\": \"new_value\"\n}";
Assert.That(serializedJson, Is.EqualTo(expectedJson));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
using OneOf;
using <%= namespace%>.Core;

namespace <%= namespace%>.Test.Core;
namespace <%= namespace%>.Test.Core.Json;

[TestFixture]
[Parallelizable(ParallelScope.All)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using NUnit.Framework;
using <%= namespace%>.Core;

namespace <%= namespace%>.Test.Core;
namespace <%= namespace%>.Test.Core.Json;

[TestFixture]
[Parallelizable(ParallelScope.All)]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { camelCase, upperFirst } from "lodash-es";

import { AbstractGeneratorContext, FernGeneratorExec, GeneratorNotificationService } from "@fern-api/base-generator";
import { assertNever } from "@fern-api/core-utils";
import { RelativeFilePath, join } from "@fern-api/fs-utils";

import {
FernFilepath,
HttpHeader,
IntermediateRepresentation,
Name,
ObjectPropertyAccess,
PrimitiveType,
PrimitiveTypeV1,
TypeDeclaration,
Expand All @@ -22,6 +24,7 @@ import {
CONSTANTS_CLASS_NAME,
DATETIME_SERIALIZER_CLASS_NAME,
ENUM_SERIALIZER_CLASS_NAME,
JSON_ACCESS_ATTRIBUTE_NAME,
JSON_UTILS_CLASS_NAME,
ONE_OF_SERIALIZER_CLASS_NAME,
STRING_ENUM_SERIALIZER_CLASS_NAME
Expand Down Expand Up @@ -204,6 +207,27 @@ export abstract class AbstractCsharpGeneratorContext<
});
}

public createJsonAccessAttribute(propertyAccess: ObjectPropertyAccess): csharp.Annotation {
let argument: string;
switch (propertyAccess) {
case "READ_ONLY":
argument = "JsonAccessType.ReadOnly";
break;
case "WRITE_ONLY":
argument = "JsonAccessType.WriteOnly";
break;
default:
assertNever(propertyAccess);
}
return csharp.annotation({
reference: csharp.classReference({
namespace: this.getCoreNamespace(),
name: JSON_ACCESS_ATTRIBUTE_NAME
}),
argument
});
}

public getJsonExceptionClassReference(): csharp.ClassReference {
return csharp.classReference({
namespace: "System.Text.Json",
Expand Down
1 change: 0 additions & 1 deletion generators/csharp/codegen/src/project/CsharpProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -649,7 +649,6 @@ ${this.getAdditionalItemGroups().join(`\n${FOUR_SPACES}`)}

result.push("<PackageReadmeFile>README.md</PackageReadmeFile>");

this.context.logger.debug(`this.license ${JSON.stringify(this.license)}`);
if (this.license) {
result.push(
this.license._visit<string>({
Expand Down
4 changes: 3 additions & 1 deletion generators/csharp/model/src/ModelGeneratorContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export class ModelGeneratorContext extends AbstractCsharpGeneratorContext<ModelC
AsIsFiles.Json.CollectionItemSerializer,
AsIsFiles.Json.DateOnlyConverter,
AsIsFiles.Json.DateTimeSerializer,
AsIsFiles.Json.JsonAccessAttribute,
AsIsFiles.Json.JsonConfiguration,
AsIsFiles.Json.OneOfSerializer
];
Expand All @@ -58,8 +59,9 @@ export class ModelGeneratorContext extends AbstractCsharpGeneratorContext<ModelC

public getCoreTestAsIsFiles(): string[] {
const files = [
AsIsFiles.Test.Json.DateTimeJsonTests,
AsIsFiles.Test.Json.DateOnlyJsonTests,
AsIsFiles.Test.Json.DateTimeJsonTests,
AsIsFiles.Test.Json.JsonAccessAttributeTests,
AsIsFiles.Test.Json.OneOfSerializerTests
];
if (this.customConfig["experimental-enable-forward-compatible-enums"] ?? false) {
Expand Down
8 changes: 7 additions & 1 deletion generators/csharp/model/src/object/ObjectGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ export class ObjectGenerator extends FileGenerator<CSharpFile, ModelCustomConfig
const maybeLiteralInitializer = this.context.getLiteralInitializerFromTypeReference({
typeReference: property.valueType
});
const fieldAttributes = [];
if (property.propertyAccess) {
fieldAttributes.push(this.context.createJsonAccessAttribute(property.propertyAccess));
}

class_.addField(
csharp.field({
name: this.getPropertyName({ className: this.classReference.name, objectProperty: property.name }),
Expand All @@ -54,7 +59,8 @@ export class ObjectGenerator extends FileGenerator<CSharpFile, ModelCustomConfig
summary: property.docs,
jsonPropertyName: property.name.wireValue,
useRequired: true,
initializer: maybeLiteralInitializer
initializer: maybeLiteralInitializer,
annotations: fieldAttributes
})
);
});
Expand Down
7 changes: 7 additions & 0 deletions generators/csharp/model/versions.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
- version: 0.0.2
createdAt: "2025-03-02"
changelogEntry:
- type: internal
summary: Upgrade to IR version 56.
irVersion: 56

- version: 0.0.1
createdAt: "2024-03-31"
changelogEntry:
Expand Down
4 changes: 3 additions & 1 deletion generators/csharp/sdk/src/SdkGeneratorContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ export class SdkGeneratorContext extends AbstractCsharpGeneratorContext<SdkCusto
AsIsFiles.Json.CollectionItemSerializer,
AsIsFiles.Json.DateOnlyConverter,
AsIsFiles.Json.DateTimeSerializer,
AsIsFiles.Json.JsonAccessAttribute,
AsIsFiles.Json.JsonConfiguration,
AsIsFiles.Json.OneOfSerializer,
AsIsFiles.RawClient
Expand Down Expand Up @@ -200,8 +201,9 @@ export class SdkGeneratorContext extends AbstractCsharpGeneratorContext<SdkCusto

public getCoreTestAsIsFiles(): string[] {
const files = [
AsIsFiles.Test.Json.DateTimeJsonTests,
AsIsFiles.Test.Json.DateOnlyJsonTests,
AsIsFiles.Test.Json.DateTimeJsonTests,
AsIsFiles.Test.Json.JsonAccessAttributeTests,
AsIsFiles.Test.Json.OneOfSerializerTests,
AsIsFiles.Test.RawClientTests
];
Expand Down
9 changes: 9 additions & 0 deletions generators/csharp/sdk/versions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@
- type: feat
summary: Add .editorconfig file to the generated SDK.

- version: 1.12.0-rc3
createdAt: "2025-03-02"
irVersion: 56
changelogEntry:
- type: feat
summary: Add support for schema properties with write-only and read-only access.
- type: feat
summary: The JSON serializer will write with indentation during debugging, and without in production.

- version: 1.12.0-rc2
createdAt: "2025-03-02"
irVersion: 56
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export const V56_TO_V55_MIGRATION: IrMigration<
[GeneratorName.GO_SDK]: GeneratorWasNeverUpdatedToConsumeNewIR,
[GeneratorName.RUBY_MODEL]: GeneratorWasNeverUpdatedToConsumeNewIR,
[GeneratorName.RUBY_SDK]: GeneratorWasNeverUpdatedToConsumeNewIR,
[GeneratorName.CSHARP_MODEL]: GeneratorWasNeverUpdatedToConsumeNewIR,
[GeneratorName.CSHARP_MODEL]: "0.0.2",
[GeneratorName.CSHARP_SDK]: "1.12.0",
[GeneratorName.SWIFT_MODEL]: GeneratorWasNeverUpdatedToConsumeNewIR,
[GeneratorName.SWIFT_SDK]: GeneratorWasNotCreatedYet,
Expand Down
Loading

0 comments on commit 7273051

Please sign in to comment.