Skip to content

Commit

Permalink
Fix bug: Unable to use {service-name} interpolation for filenames wit…
Browse files Browse the repository at this point in the history
…h openapi3-emitter when only one service is defined (#6182)

Fix: #5866

---------

Co-authored-by: albertxavier100 <albertxavier001@icloud.com>
Co-authored-by: albertxavier100 <49485679+albertxavier100@users.noreply.github.com>
Co-authored-by: Timothee Guerin <timothee.guerin@outlook.com>
  • Loading branch information
4 people authored Mar 3, 2025
1 parent 4abea21 commit fac60ed
Showing 7 changed files with 86 additions and 18 deletions.
7 changes: 7 additions & 0 deletions .chronus/changes/wanl-service-name-2025-1-27-19-40-32.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
changeKind: breaking
packages:
- "@typespec/openapi3"
---

Using `{service-name}` in `tspconfig.yaml` will always interpolate the current service name. `{service-name-if-multiple}` can be used to get the previous behavior
5 changes: 3 additions & 2 deletions packages/openapi3/README.md
Original file line number Diff line number Diff line change
@@ -48,10 +48,11 @@ If the content should be serialized as YAML or JSON. Default 'yaml', it not spec
Name of the output file.
Output file will interpolate the following values:

- service-name: Name of the service if multiple
- service-name: Name of the service
- service-name-if-multiple: Name of the service if multiple
- version: Version of the service if multiple

Default: `{service-name}.{version}.openapi.yaml` or `.json` if `file-type` is `"json"`
Default: `{service-name-if-multiple}.{version}.openapi.yaml` or `.json` if `file-type` is `"json"`

Example Single service no versioning

10 changes: 6 additions & 4 deletions packages/openapi3/src/lib.ts
Original file line number Diff line number Diff line change
@@ -13,10 +13,11 @@ export interface OpenAPI3EmitterOptions {
/**
* Name of the output file.
* Output file will interpolate the following values:
* - service-name: Name of the service if multiple
* - service-name: Name of the service
* - service-name-if-multiple: Name of the service if multiple
* - version: Version of the service if multiple
*
* @default `{service-name}.{version}.openapi.yaml` or `.json` if {@link OpenAPI3EmitterOptions["file-type"]} is `"json"`
* @default `{service-name-if-multiple}.{version}.openapi.yaml` or `.json` if {@link OpenAPI3EmitterOptions["file-type"]} is `"json"`
*
* @example Single service no versioning
* - `openapi.yaml`
@@ -99,10 +100,11 @@ const EmitterOptionsSchema: JSONSchemaType<OpenAPI3EmitterOptions> = {
description: [
"Name of the output file.",
" Output file will interpolate the following values:",
" - service-name: Name of the service if multiple",
" - service-name: Name of the service",
" - service-name-if-multiple: Name of the service if multiple",
" - version: Version of the service if multiple",
"",
' Default: `{service-name}.{version}.openapi.yaml` or `.json` if `file-type` is `"json"`',
' Default: `{service-name-if-multiple}.{version}.openapi.yaml` or `.json` if `file-type` is `"json"`',
"",
" Example Single service no versioning",
" - `openapi.yaml`",
5 changes: 3 additions & 2 deletions packages/openapi3/src/openapi.ts
Original file line number Diff line number Diff line change
@@ -200,7 +200,7 @@ export function resolveOptions(
resolvedOptions["file-type"] ?? findFileTypeFromFilename(resolvedOptions["output-file"]);

const outputFile =
resolvedOptions["output-file"] ?? `openapi.{service-name}.{version}.${fileType}`;
resolvedOptions["output-file"] ?? `openapi.{service-name-if-multiple}.{version}.${fileType}`;

const openapiVersions = resolvedOptions["openapi-versions"] ?? ["3.0.0"];

@@ -533,7 +533,8 @@ function createOAPIEmitter(
function resolveOutputFile(service: Service, multipleService: boolean, version?: string): string {
return interpolatePath(options.outputFile, {
"openapi-version": specVersion,
"service-name": multipleService ? getNamespaceFullName(service.type) : undefined,
"service-name-if-multiple": multipleService ? getNamespaceFullName(service.type) : undefined,
"service-name": getNamespaceFullName(service.type),
version,
});
}
56 changes: 56 additions & 0 deletions packages/openapi3/test/output-file.test.ts
Original file line number Diff line number Diff line change
@@ -134,4 +134,60 @@ describe("openapi3: output file", () => {
});
});
});

describe("Predefined variable name behavior", () => {
interface ServiceNameCase {
description: string;
code: string;
outputFilePattern: string;
expectedOutputFiles: string[];
}
it.each([
// {service-name} cases
{
description: "{service-name} for one service",
code: "@service namespace AAA { model M {a: string} }",
outputFilePattern: "{service-name}.yaml",
expectedOutputFiles: ["AAA.yaml"],
},
{
description: "{service-name} for multiple services",
code:
"@service namespace AAA { model M {a: string} }" +
"@service namespace BBB { model N {b: string} }",
outputFilePattern: "{service-name}.yaml",
expectedOutputFiles: ["AAA.yaml", "BBB.yaml"],
},
// {service-name-if-multiple} cases
{
description: "{service-name-if-multiple} for one service",
code: "@service namespace AAA { model M {a: string} }",
outputFilePattern: "{service-name-if-multiple}.yaml",
expectedOutputFiles: ["yaml"],
},
{
description: "{service-name-if-multiple} for multiple services",
code:
"@service namespace AAA { model M {a: string} }" +
"@service namespace BBB { model N {b: string} }",
outputFilePattern: "{service-name-if-multiple}.yaml",
expectedOutputFiles: ["AAA.yaml", "BBB.yaml"],
},
// fixed name cases
{
description: "fixed name for one service",
code: "@service namespace AAA { model M {a: string} }",
outputFilePattern: "fixed-name.yaml",
expectedOutputFiles: ["fixed-name.yaml"],
},
])("$description", async (c: ServiceNameCase) => {
await compileOpenAPI(
{
"output-file": c.outputFilePattern,
},
c.code,
);
for (const outputFile of c.expectedOutputFiles) expectHasOutput(outputFile);
});
});
});
Original file line number Diff line number Diff line change
@@ -42,10 +42,11 @@ If the content should be serialized as YAML or JSON. Default 'yaml', it not spec
Name of the output file.
Output file will interpolate the following values:

- service-name: Name of the service if multiple
- service-name: Name of the service
- service-name-if-multiple: Name of the service if multiple
- version: Version of the service if multiple

Default: `{service-name}.{version}.openapi.yaml` or `.json` if `file-type` is `"json"`
Default: `{service-name-if-multiple}.{version}.openapi.yaml` or `.json` if `file-type` is `"json"`

Example Single service no versioning

Original file line number Diff line number Diff line change
@@ -99,17 +99,17 @@ Here's what would be produced:
| ------------------ | ------------- | ------------------------- |
| `"PetStore"` | `"v1"` | `PetStore/output.v1.json` |
| `"PetStore"` | `undefined` | `PetStore/output.json` |
| `undefined` | `"v1"` | `output.v1.json` |
| `undefined` | `undefined` | `output.json` |

#### Built-in variables

| Variable name | Scope | Description |
| -------------- | --------------- | ------------------------------------------------------------------------------------ |
| `cwd` | \* | Points to the current working directory |
| `project-root` | \* | Points to the the tspconfig.yaml file containing folder. |
| `output-dir` | emitter options | Common `output-dir` See [output-dir](#output-dir---configure-the-default-output-dir) |
| `emitter-name` | emitter options | Name of the emitter |
| Variable name | Scope | Description |
| -------------------------- | ------------------------ | ------------------------------------------------------------------------------------ |
| `cwd` | \* | Points to the current working directory |
| `project-root` | \* | Points to the the tspconfig.yaml file containing folder. |
| `output-dir` | emitter options | Common `output-dir` See [output-dir](#output-dir---configure-the-default-output-dir) |
| `emitter-name` | emitter options | Name of the emitter |
| `service-name` | service name | Name of the service |
| `service-name-if-multiple` | service name if multiple | Name of the service if multiple, undefined if one |

#### Project Parameters

0 comments on commit fac60ed

Please sign in to comment.