From 308ca391c1d4da78327ed53980db3d9393e8294f Mon Sep 17 00:00:00 2001 From: Simon Johansson Date: Thu, 21 May 2026 20:22:58 +0200 Subject: [PATCH] Recognize path variables followed by `:verb` (AIP-136 custom methods) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `findPathVariablesFromPath` required every `{{name}}` placeholder to be followed by `/` or end-of-string. Paths shaped like `/tasks/{{id}}:cancel` — AIP-136 custom methods — fell through to `findCollectionVariablesFromPath` and were demoted to collection variables. Extend the lookahead to also accept `:`; it's the AIP-136 boundary and is not expected inside a path-segment literal in OpenAPI path templates, so it's a safe addition. Co-Authored-By: Claude Opus 4.7 (1M context) --- lib/schemaUtils.js | 5 ++++- test/unit/util.test.js | 7 +++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/schemaUtils.js b/lib/schemaUtils.js index 3ad72128b..2590c8cf4 100644 --- a/lib/schemaUtils.js +++ b/lib/schemaUtils.js @@ -2392,8 +2392,11 @@ module.exports = { findPathVariablesFromPath: function (path) { // /{{path}}/{{file}}.{{format}}/{{hello}} return [ '{{path}}', '{{hello}}' ] + // /tasks/{{id}}:cancel returns [ '/{{id}}' ] — `:` is the boundary used by + // AIP-136 custom methods and is not expected inside a path-segment literal + // in OpenAPI path templates, so it's a safe lookahead. // https://regex101.com/r/XGL4Gh/1 - return path.match(/(\/\{\{[^\/\{\}]+\}\})(?=\/|$)/g); + return path.match(/(\/\{\{[^\/\{\}]+\}\})(?=\/|$|:)/g); }, /** Finds all the possible collection variables in a given path string diff --git a/test/unit/util.test.js b/test/unit/util.test.js index 388f10a58..4f05c7459 100644 --- a/test/unit/util.test.js +++ b/test/unit/util.test.js @@ -2821,6 +2821,13 @@ describe('SCHEMA UTILITY FUNCTION TESTS ', function () { pathVars = SchemaUtils.findPathVariablesFromPath('/send-sms.{{format}}'); expect(pathVars).to.equal(null); + + pathVars = SchemaUtils.findPathVariablesFromPath('/tasks/{{id}}:cancel'); + expect(pathVars[0]).to.equal('/{{id}}'); + + pathVars = SchemaUtils.findPathVariablesFromPath('/users/{{userId}}:archive/items/{{itemId}}'); + expect(pathVars[0]).to.equal('/{{userId}}'); + expect(pathVars[1]).to.equal('/{{itemId}}'); done(); }); });