diff --git a/examples/spec/twilio_api_v2010.yaml b/examples/spec/twilio_api_v2010.yaml index 3c3f5c80c..745543bb2 100644 --- a/examples/spec/twilio_api_v2010.yaml +++ b/examples/spec/twilio_api_v2010.yaml @@ -447,7 +447,7 @@ paths: parent: /Accounts/{AccountSid}/Calls.json pathType: list /2010-04-01/Accounts/{AccountSid}/Calls/Feedback/Summary/{Sid}.json: - description: A resource that can only be updated + description: A resource that can only be updated and which has a parent path that needs resolution post: operationId: UpdateCallFeedbackSummary parameters: @@ -508,5 +508,5 @@ paths: x-twilio: className: feedback_call_summary mountName: feedback_call_summary - parent: /Accounts/{AccountSid}/Calls.json + parent: /Accounts/{AccountSid}/Calls/{TestInteger}.json pathType: instance diff --git a/src/main/java/com/twilio/oai/PathUtils.java b/src/main/java/com/twilio/oai/PathUtils.java index 6be32e82a..b298a260c 100644 --- a/src/main/java/com/twilio/oai/PathUtils.java +++ b/src/main/java/com/twilio/oai/PathUtils.java @@ -46,8 +46,16 @@ public static String removeTrailingPathParam(final String path) { return path.replaceFirst("/\\{[^}]+}[^/]*$", ""); } + public static boolean isPathPrefix(final String path, final String prefix) { + return removeExtension(removePathParamIds(path)).startsWith(removeExtension(removePathParamIds(prefix))); + } + + public static String removePathParamIds(final String path) { + return path.replaceAll("\\{[^}]+}", "{}"); + } + public static String fetchLastElement(final String path, final String delimiter) { - return path.substring(path.lastIndexOf(delimiter)+1); + return path.substring(path.lastIndexOf(delimiter) + 1); } public static Optional getTwilioExtension(final PathItem pathItem, final String extensionKey) { @@ -64,7 +72,9 @@ public static Optional getTwilioExtension(final Map exte } public static boolean isInstanceOperation(final CodegenOperation operation) { - return operation.vendorExtensions.getOrDefault(PATH_TYPE_EXTENSION_NAME, "").equals(PathType.INSTANCE.getValue()); + return operation.vendorExtensions + .getOrDefault(PATH_TYPE_EXTENSION_NAME, "") + .equals(PathType.INSTANCE.getValue()); } public static boolean isParentParam(final CodegenParameter param) { diff --git a/src/main/java/com/twilio/oai/resource/Resource.java b/src/main/java/com/twilio/oai/resource/Resource.java index 581472890..fa2099056 100644 --- a/src/main/java/com/twilio/oai/resource/Resource.java +++ b/src/main/java/com/twilio/oai/resource/Resource.java @@ -45,9 +45,21 @@ public static class Aliases { } public Optional getParentResource(final IResourceTree resourceTree) { - return PathUtils - .getTwilioExtension(pathItem, "parent") - .flatMap(parent -> resourceTree.findResource(parent, false)); + return PathUtils.getTwilioExtension(pathItem, "parent").flatMap(parent -> { + final String path = PathUtils.removeFirstPart(name); + + // If our parent's path is not a prefix to our own path, attempt to resolve it by removing the trailing + // path param. + if (!PathUtils.isPathPrefix(path, parent)) { + final String parentPrefix = PathUtils.removeTrailingPathParam(parent); + + if (PathUtils.isPathPrefix(path, parentPrefix)) { + parent = parentPrefix; + } + } + + return resourceTree.findResource(parent, false); + }); } public void updateFamily(final IResourceTree resourceTree) { diff --git a/src/test/java/com/twilio/oai/PathUtilsTest.java b/src/test/java/com/twilio/oai/PathUtilsTest.java index 6d9dd0537..fdbb45cd5 100644 --- a/src/test/java/com/twilio/oai/PathUtilsTest.java +++ b/src/test/java/com/twilio/oai/PathUtilsTest.java @@ -31,7 +31,7 @@ public void testGetTwilioExtension() { } @Test - public void testGetFirstPathPart(){ + public void testGetFirstPathPart() { final String path = "/version-v1"; assertEquals("version-v1", PathUtils.getFirstPathPart(path)); @@ -43,7 +43,7 @@ public void testGetFirstPathPart(){ } @Test - public void testCleanPath(){ + public void testCleanPath() { final String pathWithParams = "some/path/{pathParam1}/withPathParams/{pathParam2}.json"; assertEquals("some/path/withPathParams.json", PathUtils.cleanPath(pathWithParams)); @@ -52,39 +52,46 @@ public void testCleanPath(){ } @Test - public void testRemoveExtension(){ + public void testRemoveExtension() { final String pathWithExtension = "some/path/{param1}/with/extension.ext"; assertEquals("some/path/{param1}/with/extension", PathUtils.removeExtension(pathWithExtension)); final String pathWithoutExtension = "some/path"; assertEquals("some/path", PathUtils.removeExtension(pathWithoutExtension)); } + @Test - public void testRemoveFirstPart(){ + public void testRemoveFirstPart() { final String path = "/some/path/{param}"; assertEquals("/path/{param}", PathUtils.removeFirstPart(path)); } @Test - public void testCleanPathAndRemoveFirstElement(){ + public void testCleanPathAndRemoveFirstElement() { final String path = "/some/path/with/{params}/and/extension.ext"; assertEquals("/path/with/and/extension", PathUtils.cleanPathAndRemoveFirstElement(path)); } @Test - public void testRemoveBraces(){ + public void testRemoveBraces() { final String path = "path/with/{braces}/{braces2}/"; assertEquals("path/with/braces/braces2/", PathUtils.removeBraces(path)); } @Test - public void testRemoveTrailingPathParam(){ + public void testRemoveTrailingPathParam() { final String pathWithTrailingParam = "some/path/with/{multiple}/trailing/{param}"; assertEquals("some/path/with/{multiple}/trailing", PathUtils.removeTrailingPathParam(pathWithTrailingParam)); } @Test - public void testFetchLastElement(){ + public void testIsPathPrefix() { + assertTrue(PathUtils.isPathPrefix("path/{abc}/param/dependent.json", "path/{def}/param.json")); + assertFalse(PathUtils.isPathPrefix("path/{abc}/param/dependent", "path/{def}/param/{parent}")); + } + + @Test + public void testFetchLastElement() { final String pathWithDelimiter = "this:is:a:path:wow"; assertEquals("wow", PathUtils.fetchLastElement(pathWithDelimiter, ":")); @@ -93,7 +100,7 @@ public void testFetchLastElement(){ } @Test - public void testIsInstanceOperation(){ + public void testIsInstanceOperation() { CodegenOperation instanceCo = new CodegenOperation(); instanceCo.vendorExtensions.put("x-path-type", "instance"); assertTrue(PathUtils.isInstanceOperation(instanceCo));