Skip to content

Commit

Permalink
c# improvement: text responses + inlined request body inheritance (#4172
Browse files Browse the repository at this point in the history
)
  • Loading branch information
dcb6 authored Aug 1, 2024
1 parent 4a172e4 commit dc3fabc
Show file tree
Hide file tree
Showing 116 changed files with 4,401 additions and 132 deletions.
12 changes: 6 additions & 6 deletions .pnp.cjs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file not shown.
2 changes: 1 addition & 1 deletion generators/csharp/codegen/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"@fern-api/fs-utils": "workspace:*",
"@fern-api/generator-commons": "workspace:*",
"@fern-api/logging-execa": "workspace:*",
"@fern-fern/ir-sdk": "^53",
"@fern-fern/ir-sdk": "^53.2.0",
"lodash-es": "^4.17.21",
"zod": "^3.22.3"
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
import { RelativeFilePath } from "@fern-api/fs-utils";
import { AbstractGeneratorContext, FernGeneratorExec, GeneratorNotificationService } from "@fern-api/generator-commons";
import {
AliasTypeDeclaration,
DeclaredTypeName,
IntermediateRepresentation,
Name,
ObjectProperty,
ObjectTypeDeclaration,
TypeDeclaration,
TypeId,
TypeReference,
UndiscriminatedUnionTypeDeclaration,
UnionTypeDeclaration
UndiscriminatedUnionTypeDeclaration
} from "@fern-fern/ir-sdk/api";
import { camelCase, upperFirst } from "lodash-es";
import { csharp } from "..";
Expand All @@ -34,7 +29,6 @@ export abstract class AbstractCsharpGeneratorContext<
private namespace: string;
public readonly project: CsharpProject;
public readonly csharpTypeMapper: CsharpTypeMapper;
public readonly flattenedProperties: Map<TypeId, ObjectProperty[]> = new Map();
public publishConfig: FernGeneratorExec.NugetGithubPublishInfo | undefined;

public constructor(
Expand All @@ -48,9 +42,6 @@ export abstract class AbstractCsharpGeneratorContext<
this.customConfig.namespace ??
upperFirst(camelCase(`${this.config.organization}_${this.ir.apiName.pascalCase.unsafeName}`));
this.project = new CsharpProject(this, this.namespace);
for (const typeId of Object.keys(ir.types)) {
this.flattenedProperties.set(typeId, this.getFlattenedProperties(typeId));
}
this.csharpTypeMapper = new CsharpTypeMapper(this);
config.output.mode._visit<void>({
github: (github) => {
Expand Down Expand Up @@ -204,55 +195,4 @@ export abstract class AbstractCsharpGeneratorContext<
public abstract getNamespaceForTypeId(typeId: TypeId): string;

public abstract getExtraDependencies(): Record<string, string>;

// STOLEN FROM: ruby/TypesGenerator.ts
// We need a better way to share this sort of ir-processing logic.
//
// We pull all inherited properties onto the object because C#
// does not allow for multiple inheritence of classes, and creating interfaces feels
// heavy-handed + duplicative.
private getFlattenedProperties(typeId: TypeId): ObjectProperty[] {
const td = this.getTypeDeclarationOrThrow(typeId);
return td === undefined
? []
: this.flattenedProperties.get(typeId) ??
td.shape._visit<ObjectProperty[]>({
alias: (atd: AliasTypeDeclaration) => {
return atd.aliasOf._visit<ObjectProperty[]>({
container: () => [],
named: (dtn: DeclaredTypeName) => this.getFlattenedProperties(dtn.typeId),
primitive: () => [],
unknown: () => [],
_other: () => []
});
},
enum: () => {
this.flattenedProperties.set(typeId, []);
return [];
},
object: (otd: ObjectTypeDeclaration) => {
const props = [
...otd.properties,
...otd.extends.flatMap((eo) => this.getFlattenedProperties(eo.typeId))
];
this.flattenedProperties.set(typeId, props);
return props;
},
union: (utd: UnionTypeDeclaration) => {
const props = [
...utd.baseProperties,
...utd.extends.flatMap((eo) => this.getFlattenedProperties(eo.typeId))
];
this.flattenedProperties.set(typeId, props);
return props;
},
undiscriminatedUnion: () => {
this.flattenedProperties.set(typeId, []);
return [];
},
_other: () => {
throw new Error("Attempting to type declaration for an unknown type.");
}
});
}
}
2 changes: 1 addition & 1 deletion generators/csharp/model/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"@fern-api/csharp-codegen": "workspace:*",
"@fern-api/fs-utils": "workspace:*",
"@fern-api/generator-commons": "workspace:*",
"@fern-fern/ir-sdk": "^53",
"@fern-fern/ir-sdk": "^53.2.0",
"zod": "^3.22.3"
},
"devDependencies": {
Expand Down
8 changes: 5 additions & 3 deletions generators/csharp/model/src/object/ObjectGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,17 @@ export class ObjectGenerator extends FileGenerator<CSharpFile, ModelCustomConfig
}

public doGenerate(): CSharpFile {
const typeId = this.typeDeclaration.name.typeId;
const class_ = csharp.class_({
...this.classReference,
partial: false,
access: "public",
record: true
});
const properties = this.context.flattenedProperties.get(typeId) ?? this.objectDeclaration.properties;
properties.forEach((property) => {
const flattenedProperties = [
...this.objectDeclaration.properties,
...(this.objectDeclaration.extendedProperties ?? [])
];
flattenedProperties.forEach((property) => {
const annotations: csharp.Annotation[] = [];
const maybeUndiscriminatedUnion = this.context.getAsUndiscriminatedUnionTypeDeclaration(property.valueType);
if (maybeUndiscriminatedUnion != null) {
Expand Down
5 changes: 5 additions & 0 deletions generators/csharp/sdk/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.8.0 - 2024-07-31]

- Feature: Support text response types.
- Feature: Support inheritance for inlined request bodies.

## [0.7.0 - 2024-07-31]

- Improvement: We now generate Exception types for all errors that are defined in the IR. Generated clients with an
Expand Down
2 changes: 1 addition & 1 deletion generators/csharp/sdk/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.7.0
0.8.0
2 changes: 1 addition & 1 deletion generators/csharp/sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"@fern-api/fs-utils": "workspace:*",
"@fern-api/generator-commons": "workspace:*",
"@fern-fern/generator-exec-sdk": "^0.0.898",
"@fern-fern/ir-sdk": "^53",
"@fern-fern/ir-sdk": "^53.2.0",
"lodash-es": "^4.17.21",
"zod": "^3.22.3"
},
Expand Down
7 changes: 7 additions & 0 deletions generators/csharp/sdk/src/SdkGeneratorContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,13 @@ export class SdkGeneratorContext extends AbstractCsharpGeneratorContext<SdkCusto
);
}

public getJsonExceptionClassReference(): csharp.ClassReference {
return csharp.classReference({
namespace: "System.Text.Json",
name: "JsonException"
});
}

public getSubpackageClassReference(subpackage: Subpackage): csharp.ClassReference {
return csharp.classReference({
name: `${subpackage.name.pascalCase.unsafeName}Client`,
Expand Down
19 changes: 14 additions & 5 deletions generators/csharp/sdk/src/endpoint/EndpointGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ export class EndpointGenerator {
return this.context.csharpTypeMapper.convert({ reference: reference.responseBodyType });
},
streaming: () => undefined,
text: () => undefined,
text: () => csharp.Type.string(),
_other: () => undefined
});
}
Expand Down Expand Up @@ -253,8 +253,8 @@ export class EndpointGenerator {
`var ${RESPONSE_BODY_VARIABLE_NAME} = await ${RESPONSE_VARIABLE_NAME}.Raw.Content.ReadAsStringAsync()`
);
body._visit({
streamParameter: () => undefined,
fileDownload: () => undefined,
streamParameter: () => this.context.logger.error("Stream parameters not supported"),
fileDownload: () => this.context.logger.error("File download not supported"),
json: (reference) => {
const astType = this.context.csharpTypeMapper.convert({ reference: reference.responseBodyType });
writer.writeLine(`if (${RESPONSE_VARIABLE_NAME}.StatusCode is >= 200 and < 400) {`);
Expand Down Expand Up @@ -288,8 +288,17 @@ export class EndpointGenerator {
writer.writeLine("}");
writer.writeLine();
},
streaming: () => undefined,
text: () => undefined,
streaming: () => this.context.logger.error("Streaming not supported"),
text: () => {
writer.writeLine(`if (${RESPONSE_VARIABLE_NAME}.StatusCode is >= 200 and < 400) {`);
writer.writeNewLineIfLastLineNot();

writer.writeTextStatement(`return ${RESPONSE_BODY_VARIABLE_NAME}`);

writer.indent();
writer.writeLine("}");
writer.dedent();
},
_other: () => undefined
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,7 @@ export class WrappedRequestGenerator extends FileGenerator<CSharpFile, SdkCustom
);
},
inlinedRequestBody: (request) => {
// TODO(dsinghvi): handle extends of inlined request bodies
for (const property of request.properties) {
for (const property of [...request.properties, ...(request.extendedProperties ?? [])]) {
const annotations: csharp.Annotation[] = [];
const maybeUndiscriminatedUnion = this.context.getAsUndiscriminatedUnionTypeDeclaration(
property.valueType
Expand Down
Loading

0 comments on commit dc3fabc

Please sign in to comment.