diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/Swift5ClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/Swift5ClientCodegen.java index 7d2a1d9d5154..0ff51c2bd6b5 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/Swift5ClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/Swift5ClientCodegen.java @@ -1264,6 +1264,16 @@ public void postProcessModelProperty(CodegenModel model, CodegenProperty propert } } + @Override + public String toRegularExpression(String pattern) { + // Don't wrap the pattern in "/.../" delimiters: the generated + // Validator hands rule.pattern straight to NSRegularExpression, which + // has no delimiter syntax. Wrapping also escaped every inner "/" as + // "\/", which is not a valid escape sequence in a Swift string + // literal, so any pattern containing "/" failed to compile (#15604). + return escapeText(pattern); + } + @Override public String escapeQuotationMark(String input) { // remove " to avoid code injection diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/Swift6ClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/Swift6ClientCodegen.java index 7cd975547f2c..8c7370751f10 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/Swift6ClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/Swift6ClientCodegen.java @@ -1321,6 +1321,16 @@ public void postProcessModelProperty(CodegenModel model, CodegenProperty propert } } + @Override + public String toRegularExpression(String pattern) { + // Don't wrap the pattern in "/.../" delimiters: the generated + // Validator hands rule.pattern straight to NSRegularExpression, which + // has no delimiter syntax. Wrapping also escaped every inner "/" as + // "\/", which is not a valid escape sequence in a Swift string + // literal, so any pattern containing "/" failed to compile (#15604). + return escapeText(pattern); + } + @Override public String escapeQuotationMark(String input) { // remove " to avoid code injection diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/swift5/Swift5ClientCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/swift5/Swift5ClientCodegenTest.java index ec64a91269d1..2723cad4e698 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/swift5/Swift5ClientCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/swift5/Swift5ClientCodegenTest.java @@ -35,6 +35,22 @@ public class Swift5ClientCodegenTest { Swift5ClientCodegen swiftCodegen = new Swift5ClientCodegen(); + @Test(enabled = true) + public void testToRegularExpressionRemainsValidInSwiftStringLiteral() throws Exception { + // patterns are passed verbatim to NSRegularExpression at runtime, so no + // "/.../" delimiters are added and, in particular, no "\/" escape is + // produced ("\/" is not a valid escape sequence in a Swift string + // literal, see issue #15604) + Assert.assertEquals(swiftCodegen.toRegularExpression("http(s)?://x"), "http(s)?://x"); + Assert.assertEquals(swiftCodegen.toRegularExpression("[a-z/]+"), "[a-z/]+"); + // "\/" in the spec (a JSON-style escaped slash) is normalized to "/" + Assert.assertEquals(swiftCodegen.toRegularExpression("http(s)?:\\/\\/x"), "http(s)?://x"); + // backslashes are escaped for the Swift string literal + Assert.assertEquals(swiftCodegen.toRegularExpression("[a-z0-9\\-]+\\.[a-z]{2,63}"), "[a-z0-9\\\\-]+\\\\.[a-z]{2,63}"); + // a pattern that already carries delimiters is left untouched + Assert.assertEquals(swiftCodegen.toRegularExpression("/[a-z]/i"), "/[a-z]/i"); + } + @Test(enabled = true) public void testCapitalizedReservedWord() throws Exception { Assert.assertEquals(swiftCodegen.toEnumVarName("AS", null), "_as"); diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/swift6/Swift6ClientCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/swift6/Swift6ClientCodegenTest.java index dfd3cd8796ac..4d776f9b2ac6 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/swift6/Swift6ClientCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/swift6/Swift6ClientCodegenTest.java @@ -36,6 +36,22 @@ public class Swift6ClientCodegenTest { Swift6ClientCodegen swiftCodegen = new Swift6ClientCodegen(); + @Test(enabled = true) + public void testToRegularExpressionRemainsValidInSwiftStringLiteral() throws Exception { + // patterns are passed verbatim to NSRegularExpression at runtime, so no + // "/.../" delimiters are added and, in particular, no "\/" escape is + // produced ("\/" is not a valid escape sequence in a Swift string + // literal, see issue #15604) + Assert.assertEquals(swiftCodegen.toRegularExpression("http(s)?://x"), "http(s)?://x"); + Assert.assertEquals(swiftCodegen.toRegularExpression("[a-z/]+"), "[a-z/]+"); + // "\/" in the spec (a JSON-style escaped slash) is normalized to "/" + Assert.assertEquals(swiftCodegen.toRegularExpression("http(s)?:\\/\\/x"), "http(s)?://x"); + // backslashes are escaped for the Swift string literal + Assert.assertEquals(swiftCodegen.toRegularExpression("[a-z0-9\\-]+\\.[a-z]{2,63}"), "[a-z0-9\\\\-]+\\\\.[a-z]{2,63}"); + // a pattern that already carries delimiters is left untouched + Assert.assertEquals(swiftCodegen.toRegularExpression("/[a-z]/i"), "/[a-z]/i"); + } + @Test(enabled = true) public void testCapitalizedReservedWord() throws Exception { Assert.assertEquals(swiftCodegen.toEnumVarName("AS", null), "_as");