Skip to content

Commit 2700d84

Browse files
committed
Merge branch 'fix/23535-powershell-dollar-property-names' of https://github.com/gaurav0107/openapi-generator into gaurav0107-fix/23535-powershell-dollar-property-names
2 parents 85aee00 + 4eba061 commit 2700d84

2 files changed

Lines changed: 109 additions & 9 deletions

File tree

modules/openapi-generator/src/main/resources/powershell/model_simple.mustache

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ function Initialize-{{{apiNamePrefix}}}{{{classname}}} {
122122
$PSO = [PSCustomObject]@{
123123
{{=<< >>=}}
124124
<<#allVars>>
125-
"<<baseName>>" = ${<<name>>}
125+
'<<baseName>>' = ${<<name>>}
126126
<</allVars>>
127127
<<={{ }}=>>
128128
}
@@ -184,7 +184,7 @@ function Initialize-{{{apiNamePrefix}}}{{{classname}}} {
184184
{{=<< >>=}}
185185
<<#allVars>>
186186
<<^isReadOnly>>
187-
"<<baseName>>" = ${<<name>>}
187+
'<<baseName>>' = ${<<name>>}
188188
<</isReadOnly>>
189189
<</allVars>>
190190
<<={{ }}=>>
@@ -228,7 +228,7 @@ function ConvertFrom-{{{apiNamePrefix}}}JsonTo{{{classname}}} {
228228
{{/isAdditionalPropertiesTrue}}
229229

230230
# check if Json contains properties not defined in {{{apiNamePrefix}}}{{{classname}}}
231-
$AllProperties = ({{#allVars}}"{{{baseName}}}"{{^-last}}, {{/-last}}{{/allVars}})
231+
$AllProperties = ({{#allVars}}'{{{baseName}}}'{{^-last}}, {{/-last}}{{/allVars}})
232232
foreach ($name in $JsonParameters.PsObject.Properties.Name) {
233233
{{^isAdditionalPropertiesTrue}}
234234
if (!($AllProperties.Contains($name))) {
@@ -250,29 +250,29 @@ function ConvertFrom-{{{apiNamePrefix}}}JsonTo{{{classname}}} {
250250
}
251251

252252
{{/-first}}
253-
if (!([bool]($JsonParameters.PSobject.Properties.name -match "{{{baseName}}}"))) {
253+
if (!([bool]($JsonParameters.PSobject.Properties.name -match '{{{baseName}}}'))) {
254254
throw "Error! JSON cannot be serialized due to the required property '{{{baseName}}}' missing."
255255
} else {
256-
${{name}} = $JsonParameters.PSobject.Properties["{{{baseName}}}"].value
256+
${{name}} = $JsonParameters.PSobject.Properties['{{{baseName}}}'].value
257257
}
258258

259259
{{/requiredVars}}
260260
{{#optionalVars}}
261-
if (!([bool]($JsonParameters.PSobject.Properties.name -match "{{{baseName}}}"))) { #optional property not found
261+
if (!([bool]($JsonParameters.PSobject.Properties.name -match '{{{baseName}}}'))) { #optional property not found
262262
${{name}} = $null
263263
} else {
264-
${{name}} = $JsonParameters.PSobject.Properties["{{{baseName}}}"].value
264+
${{name}} = $JsonParameters.PSobject.Properties['{{{baseName}}}'].value
265265
}
266266

267267
{{/optionalVars}}
268268
$PSO = [PSCustomObject]@{
269269
{{=<< >>=}}
270270
<<#allVars>>
271-
"<<baseName>>" = ${<<name>>}
271+
'<<baseName>>' = ${<<name>>}
272272
<</allVars>>
273273
<<={{ }}=>>
274274
{{#isAdditionalPropertiesTrue}}
275-
"AdditionalProperties" = ${{{apiNamePrefix}}}{{{classname}}}AdditionalProperties
275+
'AdditionalProperties' = ${{{apiNamePrefix}}}{{{classname}}}AdditionalProperties
276276
{{/isAdditionalPropertiesTrue}}
277277
}
278278

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/*
2+
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
3+
* Copyright 2018 SmartBear Software
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* https://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.openapitools.codegen.powershell;
19+
20+
import io.swagger.parser.OpenAPIParser;
21+
import io.swagger.v3.oas.models.OpenAPI;
22+
import io.swagger.v3.parser.core.models.ParseOptions;
23+
import org.openapitools.codegen.ClientOptInput;
24+
import org.openapitools.codegen.CodegenConstants;
25+
import org.openapitools.codegen.DefaultGenerator;
26+
import org.openapitools.codegen.languages.PowerShellClientCodegen;
27+
import org.testng.annotations.Test;
28+
29+
import java.io.File;
30+
import java.io.IOException;
31+
import java.nio.file.Files;
32+
import java.nio.file.Paths;
33+
34+
import static org.openapitools.codegen.TestUtils.assertFileContains;
35+
import static org.openapitools.codegen.TestUtils.assertFileNotContains;
36+
37+
public class PowerShellClientCodegenTest {
38+
39+
/**
40+
* Regression test for <a href="https://github.com/OpenAPITools/openapi-generator/issues/23535">#23535</a>.
41+
*
42+
* PowerShell treats {@code $} inside double-quoted strings as the sigil for
43+
* variable interpolation, so hash-table keys emitted as {@code "$foo"} get
44+
* rewritten at runtime to the value of {@code $foo} (usually empty). This
45+
* produces invalid DTO commandlets whenever an OpenAPI property name starts
46+
* with (or contains) {@code $}. The {@code model_simple.mustache} template
47+
* now emits single-quoted keys so the literal baseName is preserved.
48+
*/
49+
@Test
50+
public void dollarSignPropertyNamesAreSingleQuoted() throws IOException {
51+
File output = Files.createTempDirectory("test-powershell-23535").toFile().getCanonicalFile();
52+
output.deleteOnExit();
53+
String outputPath = output.getAbsolutePath().replace('\\', '/');
54+
55+
OpenAPI openAPI = new OpenAPIParser()
56+
.readLocation("src/test/resources/3_0/dollar-in-names-pull14359.yaml", null, new ParseOptions())
57+
.getOpenAPI();
58+
59+
PowerShellClientCodegen codegen = new PowerShellClientCodegen();
60+
codegen.setOutputDir(output.getAbsolutePath());
61+
62+
ClientOptInput input = new ClientOptInput();
63+
input.openAPI(openAPI);
64+
input.config(codegen);
65+
66+
DefaultGenerator generator = new DefaultGenerator();
67+
generator.setGeneratorPropertyDefault(CodegenConstants.MODELS, "true");
68+
generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_TESTS, "false");
69+
generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_DOCS, "false");
70+
generator.setGeneratorPropertyDefault(CodegenConstants.APIS, "false");
71+
generator.setGeneratorPropertyDefault(CodegenConstants.SUPPORTING_FILES, "false");
72+
generator.opts(input).generate();
73+
74+
// The PowerShell codegen sanitises "$DollarModel$" to "DollarModel",
75+
// so the emitted model lives at src/<package>/Model/DollarModel.ps1.
76+
java.nio.file.Path dollarModelPs1 = Paths.get(outputPath + "/src/PSOpenAPITools/Model/DollarModel.ps1");
77+
78+
// Every site where model_simple.mustache emits a user-supplied baseName
79+
// must use single-quoted PowerShell strings so `$` is treated literally:
80+
//
81+
// 1. The `Initialize-…` hash literal: `'$dollarValue$' = ${DollarValue}`
82+
// 2. The JSON round-trip hash literal in `ConvertFrom-…JsonTo…`
83+
// 3. The property-allowlist array: `$AllProperties = ('$dollarValue$')`
84+
// 4. The property-indexer lookup: `$JsonParameters.PSobject.Properties['$dollarValue$'].value`
85+
// 5. The presence-check regex: `-match '$dollarValue$'`
86+
assertFileContains(dollarModelPs1,
87+
"'$dollarValue$' = ${DollarValue}",
88+
"$AllProperties = ('$dollarValue$')",
89+
"$JsonParameters.PSobject.Properties['$dollarValue$'].value",
90+
"-match '$dollarValue$'");
91+
92+
// The previous double-quoted emissions must no longer appear anywhere in
93+
// the generated model file.
94+
assertFileNotContains(dollarModelPs1,
95+
"\"$dollarValue$\" = ",
96+
"$AllProperties = (\"$dollarValue$\")",
97+
"$JsonParameters.PSobject.Properties[\"$dollarValue$\"]",
98+
"-match \"$dollarValue$\"");
99+
}
100+
}

0 commit comments

Comments
 (0)