diff --git a/generators/typescript/sdk/CHANGELOG.md b/generators/typescript/sdk/CHANGELOG.md index 145c3de7020..501906cfac9 100644 --- a/generators/typescript/sdk/CHANGELOG.md +++ b/generators/typescript/sdk/CHANGELOG.md @@ -7,30 +7,40 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [0.12.3-rc1] - 2024-02-27 -- Fix: Previously SDK code snippets would not support generation with undiscriminated - unions. Now, it does. +- Fix: Previously reference.md was just leveraging the function name for the reference, now it leverages the full package-scoped path, mirroring how the function would be used in reality. +```ts +seedExamples.getException(...) + +// is now + +seedExamples.file.notification.service.getException(...) +``` + +## [0.12.3-rc1] - 2024-02-27 + +- Fix: Previously SDK code snippets would not support generation with undiscriminated unions. Now, it does. ## [0.12.2] - 2024-02-27 - Fix: Previously SDK code snippets would not take into account default parameter values - and would always include a `{}`. This was odd and didn't represent how a developer - would use the SDK. Now, the snippets check for default parameter values and omit - if there are no fields specified. + and would always include a `{}`. This was odd and didn't represent how a developer + would use the SDK. Now, the snippets check for default parameter values and omit + if there are no fields specified. ```ts // Before - client.users.list({}) + client.users.list({}); // After - client.users.list() + client.users.list(); ``` ## [0.12.1] - 2024-02-27 -- Fix: Optional objects in deep query parameters were previously being incorrectly +- Fix: Optional objects in deep query parameters were previously being incorrectly serialized. Before this change, optional objects were just being JSON.stringified - which would send the incorrect contents over the wire. + which would send the incorrect contents over the wire. ```ts // Before @@ -38,7 +48,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 _queryParams["foo"] = JSON.stringify(foo); } - // After + // After if (foo != null) { _queryParams["foo"] = foo; } @@ -48,21 +58,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 _queryParams["foo"] = serializers.Foo.jsonOrThrow(foo, { skipValidation: false, breadcrumbs: ["request", "foo"] - }) + }); } ``` ## [0.12.0] - 2024-02-26 -- Feature: support deep object query parameter serialization. If, query parameters are - objects then Fern will support serializing them. +- Feature: support deep object query parameter serialization. If, query parameters are + objects then Fern will support serializing them. ```yaml - MyFoo: - properties: - bar: optional + MyFoo: + properties: + bar: optional - query-parameters: + query-parameters: foo: MyFoo ``` @@ -71,22 +81,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ```ts client.doThing({ foo: { - bar: "...", + bar: "..." } - }) + }); ``` - + ## [0.11.5] - 2024-02-15 -- Fix: Previously `core.Stream` would not work in the Browser. Now the generated Fern SDK - includes a polyfill for `ReadableStream` and uses `TextDecoder` instead of `Buffer`. +- Fix: Previously `core.Stream` would not work in the Browser. Now the generated Fern SDK + includes a polyfill for `ReadableStream` and uses `TextDecoder` instead of `Buffer`. -- Feature: add in a reference markdown file, this shows a quick outline of the available endpoints, +- Feature: add in a reference markdown file, this shows a quick outline of the available endpoints, it's documentation, code snippet, and parameters. - This feature is currently behind a feature flag called `includeApiReference` and can be used + This feature is currently behind a feature flag called `includeApiReference` and can be used + ```yaml - config: + config: includeApiReference: true ``` diff --git a/generators/typescript/sdk/VERSION b/generators/typescript/sdk/VERSION index d294b5831ed..e01e0ddd8e8 100644 --- a/generators/typescript/sdk/VERSION +++ b/generators/typescript/sdk/VERSION @@ -1 +1 @@ -0.12.3-rc1 +0.12.4 diff --git a/generators/typescript/sdk/generator/src/ReferenceGenerator.ts b/generators/typescript/sdk/generator/src/ReferenceGenerator.ts index 66a76df955d..92331651f9e 100644 --- a/generators/typescript/sdk/generator/src/ReferenceGenerator.ts +++ b/generators/typescript/sdk/generator/src/ReferenceGenerator.ts @@ -1,12 +1,11 @@ export declare namespace ReferenceGenerator { export interface Init { - clientName: string; - apiName?: string; + apiName: string; } } export declare namespace ReferenceGeneratorSection { export interface Init { - clientName: string; + apiName: string; // Heading is essentially just the endpoint name in the root package OR heading: string; } @@ -21,6 +20,7 @@ export interface ReferenceParameterDeclaration { export interface EndpointDeclaration { functionPath?: string; functionName: string; + clientPath?: string; returnType: string | undefined; returnTypePath?: string; codeSnippet: string | undefined; @@ -44,12 +44,12 @@ function writeSignature(parameters: ReferenceParameterDeclaration[]): string { } class ReferenceGeneratorSection { - clientName: string; + apiName: string; heading: string; endpoints: EndpointDeclaration[]; constructor(init: ReferenceGeneratorSection.Init) { - this.clientName = init.clientName; + this.apiName = init.apiName; this.heading = init.heading; this.endpoints = []; } @@ -89,9 +89,10 @@ class ReferenceGeneratorSection { : ""; return ` -
${this.clientName}.${wrapInLink(endpoint.functionName, endpoint.functionPath)}${writeSignature( - endpoint.parameters - )} -> ${wrapInLink( +
${endpoint.clientPath ?? this.apiName}.${wrapInLink( + endpoint.functionName, + endpoint.functionPath + )}${writeSignature(endpoint.parameters)} -> ${wrapInLink( endpoint.returnType === undefined ? "void" : endpoint.returnType, endpoint.returnTypePath )} @@ -112,18 +113,17 @@ ${this.endpoints.map((endpoint) => this.writeEndpoint(endpoint)).join("\n")} } export class ReferenceGenerator { - apiName: string | undefined; - clientName: string; + apiName: string; sections: ReferenceGeneratorSection[]; constructor(init: ReferenceGenerator.Init) { - this.clientName = init.clientName; + this.apiName = init.apiName; this.apiName = init.apiName; this.sections = []; } public addSection(heading: string): ReferenceGeneratorSection { - const section = new ReferenceGeneratorSection({ clientName: this.clientName, heading }); + const section = new ReferenceGeneratorSection({ apiName: this.apiName, heading }); this.sections.push(section); return section; } diff --git a/generators/typescript/sdk/generator/src/SdkGenerator.ts b/generators/typescript/sdk/generator/src/SdkGenerator.ts index 3c08c06ef98..907463129dc 100644 --- a/generators/typescript/sdk/generator/src/SdkGenerator.ts +++ b/generators/typescript/sdk/generator/src/SdkGenerator.ts @@ -351,7 +351,6 @@ module.exports = { let refGenerator: ReferenceGenerator | undefined; if (this.config.includeApiReference) { refGenerator = new ReferenceGenerator({ - clientName: this.intermediateRepresentation.apiName.camelCase.safeName, apiName: this.namespaceExport === "api" ? "client" : this.namespaceExport }); } @@ -640,6 +639,7 @@ module.exports = { if (serviceReference !== undefined) { let returnType = undefined; + let endpointClientAccess: ts.Expression | undefined = undefined; const parameters: ReferenceParameterDeclaration[] = []; const referenceSnippet = this.withSnippet({ run: ({ sourceFile, importsManager }): ts.Node[] | undefined => { @@ -662,6 +662,10 @@ module.exports = { }) ?? []) ); + endpointClientAccess = clientClass.accessFromRootClient({ + referenceToRootClient: context.sdkInstanceReferenceForSnippet + }); + return this.runWithSnippet({ sourceFile, importsManager, @@ -675,7 +679,15 @@ module.exports = { includeImports: false }); + let statement = undefined; + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (endpointClientAccess !== undefined) { + statement = getTextOfTsNode(endpointClientAccess); + } + serviceReference.addEndpoint({ + // clientPath: getTextOfTsNode(statement), + clientPath: statement, functionPath: serviceFilepath, functionName: endpoint.name.camelCase.unsafeName, returnType, diff --git a/packages/seed/fern/definition/features.yml b/packages/seed/fern/definition/features.yml index 7e1cb510205..4080c3dc1e5 100644 --- a/packages/seed/fern/definition/features.yml +++ b/packages/seed/fern/definition/features.yml @@ -82,6 +82,11 @@ types: docs: | The SDK should provide a way to access additional properties on the response object. This is useful for when the API adds new fields to the response object and the user wants to grab them without upgrading the SDK. + apiReferenceGeneration: + type: FeatureImplementation + docs: | + The SDK should generate an API reference markdown file (refrence.md at the root level) that shows all the endpoints, their documentation, + their parameters, and their responses. whitelabel: type: FeatureImplementation docs: | diff --git a/seed/ruby-sdk/seed.yml b/seed/ruby-sdk/seed.yml index a24a5fa0bc1..86c6ef8b72c 100644 --- a/seed/ruby-sdk/seed.yml +++ b/seed/ruby-sdk/seed.yml @@ -23,3 +23,4 @@ features: forwardCompatibleEnums: true additionalProperties: true whitelabel: false + apiReferenceGeneration: false diff --git a/seed/ts-sdk/examples/examples-with-api-reference/reference.md b/seed/ts-sdk/examples/examples-with-api-reference/reference.md index 3fb744d5dcc..8b211354aee 100644 --- a/seed/ts-sdk/examples/examples-with-api-reference/reference.md +++ b/seed/ts-sdk/examples/examples-with-api-reference/reference.md @@ -2,7 +2,7 @@ ## Echo -
examples.echo({ ...params }) -> string +
seedExamples.echo({ ...params }) -> string
@@ -77,7 +77,7 @@ await seedExamples.echo("Hello world!"); ## File Notification Service -
examples.getException(notificationId) -> SeedExamples.Exception +
seedExamples.file.notification.service.getException(notificationId) -> SeedExamples.Exception
@@ -152,7 +152,7 @@ await seedExamples.file.notification.service.getException("notification-hsy129x" ## File Service -
examples.getFile(filename, { ...params }) -> SeedExamples.File_ +
seedExamples.file.service.getFile(filename, { ...params }) -> SeedExamples.File_
@@ -261,7 +261,7 @@ await seedExamples.file.service.getFile("file.txt", { ## Health Service -
examples.check(id) -> void +
seedExamples.health.service.check(id) -> void
@@ -351,7 +351,7 @@ await seedExamples.health.service.check("id-2sdx82h");
-
examples.ping() -> boolean +
seedExamples.health.service.ping() -> boolean
@@ -434,7 +434,7 @@ await seedExamples.health.service.ping(); ## Service -
examples.getMovie(movieId) -> SeedExamples.Movie +
seedExamples.service.getMovie(movieId) -> SeedExamples.Movie
@@ -504,7 +504,7 @@ await seedExamples.service.getMovie("movie-c06a4ad7");
-
examples.createMovie({ ...params }) -> SeedExamples.MovieId +
seedExamples.service.createMovie({ ...params }) -> SeedExamples.MovieId
@@ -582,7 +582,7 @@ await seedExamples.service.createMovie({
-
examples.getMetadata({ ...params }) -> SeedExamples.Metadata +
seedExamples.service.getMetadata({ ...params }) -> SeedExamples.Metadata
diff --git a/seed/ts-sdk/seed.yml b/seed/ts-sdk/seed.yml index d05f3f9f9b1..9eef56dcd6b 100644 --- a/seed/ts-sdk/seed.yml +++ b/seed/ts-sdk/seed.yml @@ -108,4 +108,3 @@ allowedFailures: - exhaustive:dev-dependencies - audiences - enum # throws b/c of undiscriminated union examples - - examples:examples-with-api-reference # throws b/c of undiscriminated union examples