From 333309a584c146ac3cd0206a5f87b7623a42a083 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Heiko=20Thei=C3=9Fen?= Date: Tue, 28 Jan 2025 10:37:53 +0100 Subject: [PATCH 1/6] Parameter aliases conflict with system query options --- lib/csdl2openapi.js | 48 +++++++++++++++++++++++++++++++++--- tools/V4-CSDL-to-OpenAPI.xsl | 19 +++++++++++++- 2 files changed, 62 insertions(+), 5 deletions(-) diff --git a/lib/csdl2openapi.js b/lib/csdl2openapi.js index ae95df27..b7b7f669 100644 --- a/lib/csdl2openapi.js +++ b/lib/csdl2openapi.js @@ -610,8 +610,8 @@ module.exports.csdl2openapi = function ( (byKey ? "entity from " : element.$Collection - ? "entities from " - : "") + + ? "entities from " + : "") + (level > 0 ? "related " : "") + name + (byKey ? " by key" : ""), @@ -1714,7 +1714,27 @@ module.exports.csdl2openapi = function ( type?.$UnderlyingType == "Edm.Stream" ) { param.in = "query"; - if (implicitAliases) { + if ( + implicitAliases && + [ + "compute", + "expand", + "select", + "filter", + "search", + "count", + "orderby", + "skip", + "top", + "format", + "index", + "schemaversion", + "skiptoken", + "apply", + ].includes(p.$Name) + ) { + param.name = "@" + p.$Name; + } else if (implicitAliases) { param.name = p.$Name; } else { pathSegments.push(p.$Name + "=@" + p.$Name); @@ -1740,7 +1760,27 @@ module.exports.csdl2openapi = function ( pathSegments.push(p.$Name + "={" + p.$Name + "}"); param.in = "path"; } - param.name = p.$Name; + if ( + implicitAliases && + [ + "compute", + "expand", + "select", + "filter", + "search", + "count", + "orderby", + "skip", + "top", + "format", + "index", + "schemaversion", + "skiptoken", + "apply", + ].includes(p.$Name) + ) + param.name = "@" + p.$Name; + else param.name = p.$Name; if ( !p.$Type || p.$Type === "Edm.String" || diff --git a/tools/V4-CSDL-to-OpenAPI.xsl b/tools/V4-CSDL-to-OpenAPI.xsl index 0c60fcf8..818c1677 100644 --- a/tools/V4-CSDL-to-OpenAPI.xsl +++ b/tools/V4-CSDL-to-OpenAPI.xsl @@ -4726,12 +4726,29 @@ , {"name":" - + + @ + + ","in":"query", + ","in":"path", From 4769655d9095dd4c957386619207d49103a38cee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Heiko=20Thei=C3=9Fen?= Date: Tue, 28 Jan 2025 10:42:18 +0100 Subject: [PATCH 2/6] DRY --- lib/csdl2openapi.js | 57 +++++++++++++++------------------------------ 1 file changed, 19 insertions(+), 38 deletions(-) diff --git a/lib/csdl2openapi.js b/lib/csdl2openapi.js index b7b7f669..39cd857a 100644 --- a/lib/csdl2openapi.js +++ b/lib/csdl2openapi.js @@ -38,6 +38,23 @@ const TITLE_SUFFIX = { "-update": " (for update)", }; +const SYSTEM_QUERY_OPTIONS = [ + "compute", + "expand", + "select", + "filter", + "search", + "count", + "orderby", + "skip", + "top", + "format", + "index", + "schemaversion", + "skiptoken", + "apply", +]; + /** * Construct an OpenAPI description from a CSDL document * @param {object} csdl CSDL document @@ -1714,25 +1731,7 @@ module.exports.csdl2openapi = function ( type?.$UnderlyingType == "Edm.Stream" ) { param.in = "query"; - if ( - implicitAliases && - [ - "compute", - "expand", - "select", - "filter", - "search", - "count", - "orderby", - "skip", - "top", - "format", - "index", - "schemaversion", - "skiptoken", - "apply", - ].includes(p.$Name) - ) { + if (implicitAliases && SYSTEM_QUERY_OPTIONS.includes(p.$Name)) { param.name = "@" + p.$Name; } else if (implicitAliases) { param.name = p.$Name; @@ -1760,25 +1759,7 @@ module.exports.csdl2openapi = function ( pathSegments.push(p.$Name + "={" + p.$Name + "}"); param.in = "path"; } - if ( - implicitAliases && - [ - "compute", - "expand", - "select", - "filter", - "search", - "count", - "orderby", - "skip", - "top", - "format", - "index", - "schemaversion", - "skiptoken", - "apply", - ].includes(p.$Name) - ) + if (implicitAliases && SYSTEM_QUERY_OPTIONS.includes(p.$Name)) param.name = "@" + p.$Name; else param.name = p.$Name; if ( From e1b949b82188f739b652aced4eaae627dcc4ef0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Heiko=20Thei=C3=9Fen?= Date: Tue, 28 Jan 2025 18:06:08 +0100 Subject: [PATCH 3/6] Only V4 --- tools/V4-CSDL-to-OpenAPI.xsl | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/tools/V4-CSDL-to-OpenAPI.xsl b/tools/V4-CSDL-to-OpenAPI.xsl index 818c1677..0c60fcf8 100644 --- a/tools/V4-CSDL-to-OpenAPI.xsl +++ b/tools/V4-CSDL-to-OpenAPI.xsl @@ -4726,29 +4726,12 @@ , {"name":" + - - @ - - ","in":"query", - ","in":"path", From 0faa27dc4e7be29aef5c3c638a5d3a390a238a32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Heiko=20Thei=C3=9Fen?= Date: Wed, 29 Jan 2025 16:58:25 +0100 Subject: [PATCH 4/6] 100% test coverage --- test/csdl2openapi.test.js | 69 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/test/csdl2openapi.test.js b/test/csdl2openapi.test.js index b485c41f..072bc5f9 100644 --- a/test/csdl2openapi.test.js +++ b/test/csdl2openapi.test.js @@ -929,6 +929,75 @@ describe("Edge cases", function () { ); }); + it("function with @ parameter aliases", function () { + const csdl = { + $Version: "4.01", + $Reference: { + dummy: { + $Include: [{ $Namespace: "Org.OData.Core.V1", $Alias: "Core" }], + }, + }, + $EntityContainer: "model.Container", + model: { + $Alias: "this", + FavoritePhotos: [ + { + $Kind: "Function", + $Parameter: [ + { + $Name: "skip", + $Type: "Edm.Date", + $Collection: true, + "@Core.Description": "Dates to be skipped", + }, + { + $Name: "filter", + "@Core.Description": "Boolean expression to filter the result", + }, + ], + $ReturnType: {}, + }, + ], + Container: { + fav: { $Function: "this.FavoritePhotos" }, + }, + }, + }; + const expected = { + paths: { + "/fav": { + get: { + parameters: [ + { + name: "@skip", + in: "query", + required: true, + description: + "Dates to be skipped \nThis is a URL-encoded JSON array with items of type Edm.Date, see [Complex and Collection Literals](https://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part2-url-conventions.html#sec_ComplexandCollectionLiterals)", + schema: { type: "string" }, + example: "[]", + }, + { + name: "@filter", + in: "query", + required: true, + schema: { type: "string", pattern: "^'([^']|'')*'$" }, + description: + "Boolean expression to filter the result \nString value needs to be enclosed in single quotes", + }, + ], + summary: "Invoke function FavoritePhotos", + tags: ["Service Operations"], + }, + }, + }, + }; + const actual = csdl2openapi(csdl, { diagram: true }); + delete actual.paths["/$batch"]; + delete actual.paths["/fav"].get.responses; + assert.deepStrictEqual(actual.paths, expected.paths); + }); + it("return type with facets", function () { const csdl = { $EntityContainer: "this.Container", From 1db05ea3187ee09f4db75ecdd3f5c258caaded74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Heiko=20Thei=C3=9Fen?= Date: Thu, 30 Jan 2025 09:27:32 +0100 Subject: [PATCH 5/6] No system query option clash in 2.0 --- lib/csdl2openapi.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/csdl2openapi.js b/lib/csdl2openapi.js index 39cd857a..d5bb13d1 100644 --- a/lib/csdl2openapi.js +++ b/lib/csdl2openapi.js @@ -1731,7 +1731,11 @@ module.exports.csdl2openapi = function ( type?.$UnderlyingType == "Edm.Stream" ) { param.in = "query"; - if (implicitAliases && SYSTEM_QUERY_OPTIONS.includes(p.$Name)) { + if ( + implicitAliases && + csdl.$Version !== "2.0" && + SYSTEM_QUERY_OPTIONS.includes(p.$Name) + ) { param.name = "@" + p.$Name; } else if (implicitAliases) { param.name = p.$Name; @@ -1759,7 +1763,11 @@ module.exports.csdl2openapi = function ( pathSegments.push(p.$Name + "={" + p.$Name + "}"); param.in = "path"; } - if (implicitAliases && SYSTEM_QUERY_OPTIONS.includes(p.$Name)) + if ( + implicitAliases && + csdl.$Version !== "2.0" && + SYSTEM_QUERY_OPTIONS.includes(p.$Name) + ) param.name = "@" + p.$Name; else param.name = p.$Name; if ( From 842da6f54ed9225ada8bed2f4d671cab0cf87ab8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Heiko=20Thei=C3=9Fen?= Date: Wed, 5 Feb 2025 18:03:27 +0100 Subject: [PATCH 6/6] system query options case-insensitive --- lib/csdl2openapi.js | 4 ++-- test/csdl2openapi.test.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/csdl2openapi.js b/lib/csdl2openapi.js index 7aa2e947..1a64deea 100644 --- a/lib/csdl2openapi.js +++ b/lib/csdl2openapi.js @@ -1734,7 +1734,7 @@ module.exports.csdl2openapi = function ( if ( implicitAliases && csdl.$Version !== "2.0" && - SYSTEM_QUERY_OPTIONS.includes(p.$Name) + SYSTEM_QUERY_OPTIONS.includes(p.$Name.toLowerCase()) ) { param.name = "@" + p.$Name; } else if (implicitAliases) { @@ -1766,7 +1766,7 @@ module.exports.csdl2openapi = function ( if ( implicitAliases && csdl.$Version !== "2.0" && - SYSTEM_QUERY_OPTIONS.includes(p.$Name) + SYSTEM_QUERY_OPTIONS.includes(p.$Name.toLowerCase()) ) param.name = "@" + p.$Name; else param.name = p.$Name; diff --git a/test/csdl2openapi.test.js b/test/csdl2openapi.test.js index 072bc5f9..2189fc9a 100644 --- a/test/csdl2openapi.test.js +++ b/test/csdl2openapi.test.js @@ -945,7 +945,7 @@ describe("Edge cases", function () { $Kind: "Function", $Parameter: [ { - $Name: "skip", + $Name: "SKIP", $Type: "Edm.Date", $Collection: true, "@Core.Description": "Dates to be skipped", @@ -969,7 +969,7 @@ describe("Edge cases", function () { get: { parameters: [ { - name: "@skip", + name: "@SKIP", in: "query", required: true, description: