Skip to content

Commit fac60ed

Browse files
wanlwanlalbertxavier100timotheeguerin
authored
Fix bug: Unable to use {service-name} interpolation for filenames with 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>
1 parent 4abea21 commit fac60ed

File tree

7 files changed

+86
-18
lines changed

7 files changed

+86
-18
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
changeKind: breaking
3+
packages:
4+
- "@typespec/openapi3"
5+
---
6+
7+
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

packages/openapi3/README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,11 @@ If the content should be serialized as YAML or JSON. Default 'yaml', it not spec
4848
Name of the output file.
4949
Output file will interpolate the following values:
5050

51-
- service-name: Name of the service if multiple
51+
- service-name: Name of the service
52+
- service-name-if-multiple: Name of the service if multiple
5253
- version: Version of the service if multiple
5354

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

5657
Example Single service no versioning
5758

packages/openapi3/src/lib.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@ export interface OpenAPI3EmitterOptions {
1313
/**
1414
* Name of the output file.
1515
* Output file will interpolate the following values:
16-
* - service-name: Name of the service if multiple
16+
* - service-name: Name of the service
17+
* - service-name-if-multiple: Name of the service if multiple
1718
* - version: Version of the service if multiple
1819
*
19-
* @default `{service-name}.{version}.openapi.yaml` or `.json` if {@link OpenAPI3EmitterOptions["file-type"]} is `"json"`
20+
* @default `{service-name-if-multiple}.{version}.openapi.yaml` or `.json` if {@link OpenAPI3EmitterOptions["file-type"]} is `"json"`
2021
*
2122
* @example Single service no versioning
2223
* - `openapi.yaml`
@@ -99,10 +100,11 @@ const EmitterOptionsSchema: JSONSchemaType<OpenAPI3EmitterOptions> = {
99100
description: [
100101
"Name of the output file.",
101102
" Output file will interpolate the following values:",
102-
" - service-name: Name of the service if multiple",
103+
" - service-name: Name of the service",
104+
" - service-name-if-multiple: Name of the service if multiple",
103105
" - version: Version of the service if multiple",
104106
"",
105-
' Default: `{service-name}.{version}.openapi.yaml` or `.json` if `file-type` is `"json"`',
107+
' Default: `{service-name-if-multiple}.{version}.openapi.yaml` or `.json` if `file-type` is `"json"`',
106108
"",
107109
" Example Single service no versioning",
108110
" - `openapi.yaml`",

packages/openapi3/src/openapi.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ export function resolveOptions(
200200
resolvedOptions["file-type"] ?? findFileTypeFromFilename(resolvedOptions["output-file"]);
201201

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

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

@@ -533,7 +533,8 @@ function createOAPIEmitter(
533533
function resolveOutputFile(service: Service, multipleService: boolean, version?: string): string {
534534
return interpolatePath(options.outputFile, {
535535
"openapi-version": specVersion,
536-
"service-name": multipleService ? getNamespaceFullName(service.type) : undefined,
536+
"service-name-if-multiple": multipleService ? getNamespaceFullName(service.type) : undefined,
537+
"service-name": getNamespaceFullName(service.type),
537538
version,
538539
});
539540
}

packages/openapi3/test/output-file.test.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,4 +134,60 @@ describe("openapi3: output file", () => {
134134
});
135135
});
136136
});
137+
138+
describe("Predefined variable name behavior", () => {
139+
interface ServiceNameCase {
140+
description: string;
141+
code: string;
142+
outputFilePattern: string;
143+
expectedOutputFiles: string[];
144+
}
145+
it.each([
146+
// {service-name} cases
147+
{
148+
description: "{service-name} for one service",
149+
code: "@service namespace AAA { model M {a: string} }",
150+
outputFilePattern: "{service-name}.yaml",
151+
expectedOutputFiles: ["AAA.yaml"],
152+
},
153+
{
154+
description: "{service-name} for multiple services",
155+
code:
156+
"@service namespace AAA { model M {a: string} }" +
157+
"@service namespace BBB { model N {b: string} }",
158+
outputFilePattern: "{service-name}.yaml",
159+
expectedOutputFiles: ["AAA.yaml", "BBB.yaml"],
160+
},
161+
// {service-name-if-multiple} cases
162+
{
163+
description: "{service-name-if-multiple} for one service",
164+
code: "@service namespace AAA { model M {a: string} }",
165+
outputFilePattern: "{service-name-if-multiple}.yaml",
166+
expectedOutputFiles: ["yaml"],
167+
},
168+
{
169+
description: "{service-name-if-multiple} for multiple services",
170+
code:
171+
"@service namespace AAA { model M {a: string} }" +
172+
"@service namespace BBB { model N {b: string} }",
173+
outputFilePattern: "{service-name-if-multiple}.yaml",
174+
expectedOutputFiles: ["AAA.yaml", "BBB.yaml"],
175+
},
176+
// fixed name cases
177+
{
178+
description: "fixed name for one service",
179+
code: "@service namespace AAA { model M {a: string} }",
180+
outputFilePattern: "fixed-name.yaml",
181+
expectedOutputFiles: ["fixed-name.yaml"],
182+
},
183+
])("$description", async (c: ServiceNameCase) => {
184+
await compileOpenAPI(
185+
{
186+
"output-file": c.outputFilePattern,
187+
},
188+
c.code,
189+
);
190+
for (const outputFile of c.expectedOutputFiles) expectHasOutput(outputFile);
191+
});
192+
});
137193
});

website/src/content/docs/docs/emitters/openapi3/reference/emitter.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,11 @@ If the content should be serialized as YAML or JSON. Default 'yaml', it not spec
4242
Name of the output file.
4343
Output file will interpolate the following values:
4444

45-
- service-name: Name of the service if multiple
45+
- service-name: Name of the service
46+
- service-name-if-multiple: Name of the service if multiple
4647
- version: Version of the service if multiple
4748

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

5051
Example Single service no versioning
5152

website/src/content/docs/docs/handbook/configuration/configuration.mdx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -99,17 +99,17 @@ Here's what would be produced:
9999
| ------------------ | ------------- | ------------------------- |
100100
| `"PetStore"` | `"v1"` | `PetStore/output.v1.json` |
101101
| `"PetStore"` | `undefined` | `PetStore/output.json` |
102-
| `undefined` | `"v1"` | `output.v1.json` |
103-
| `undefined` | `undefined` | `output.json` |
104102

105103
#### Built-in variables
106104

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

114114
#### Project Parameters
115115

0 commit comments

Comments
 (0)