From 11c3eb4fb399a8c621327e154121953f632a380f Mon Sep 17 00:00:00 2001 From: Daniel O'Grady Date: Wed, 9 Sep 2026 08:20:04 +0200 Subject: [PATCH 1/4] fix: _servicePath no longer mutates @protocol annotation on CDS service definitions --- CHANGELOG.md | 1 + lib/compile/index.js | 4 ++-- test/lib/compile/openapi.test.js | 13 +++++++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d9ed33..bddce69 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ### Removed ### Fixed - Entities that are transitively autoexposed and should still be considered readonly, do not generate documentation for write endpoints anymore +- `_servicePath` no longer mutates the `@protocol` annotation of the CDS service definition after OpenAPI compilation ### Security ## [1.6.0] - 2026-08-04 diff --git a/lib/compile/index.js b/lib/compile/index.js index 09753f3..36eb247 100644 --- a/lib/compile/index.js +++ b/lib/compile/index.js @@ -198,8 +198,8 @@ function _servicePath(csdl, csn, protocols) { if (Array.isArray(protocols)) { protocols.forEach((protocol) => { - service["@protocol"] = protocol; - path = cds.service.path4?.(service) || cds.serve.path4(service); + const serviceWithProtocol = { ...service, "@protocol": protocol }; + path = cds.service.path4?.(serviceWithProtocol) || cds.serve.path4(serviceWithProtocol); paths[protocol] = path; }); } diff --git a/test/lib/compile/openapi.test.js b/test/lib/compile/openapi.test.js index a74f7be..e21e0b2 100644 --- a/test/lib/compile/openapi.test.js +++ b/test/lib/compile/openapi.test.js @@ -292,6 +292,19 @@ service CatalogService { assert(!openapi.servers[0].url.includes('odata')); }); + test('does not mutate @protocol annotation after compilation', () => { + const csn = cds.compile.to.csn(` + namespace com.sap; + @protocol: ['odata', 'rest'] + service A { entity E { key ID : UUID; }; } + `); + const originalProtocol = csn.definitions['com.sap.A']['@protocol']; + assert(Array.isArray(originalProtocol), '@protocol should be an array before compilation'); + toOpenApi(csn); + assert(Array.isArray(csn.definitions['com.sap.A']['@protocol']), + '@protocol must not be mutated by toOpenApi'); + }); + test('options: Multiple servers', () => { const csn = cds.compile.to.csn(` service A {entity E { key ID : UUID; };};` From 249d54b863b369326fc504b43e89af2c4ca27cf7 Mon Sep 17 00:00:00 2001 From: Daniel O'Grady Date: Wed, 9 Sep 2026 08:20:04 +0200 Subject: [PATCH 2/4] fix: clone CSN in processor to prevent mutation of caller's definition objects --- lib/compile/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/compile/index.js b/lib/compile/index.js index 36eb247..e7195b0 100644 --- a/lib/compile/index.js +++ b/lib/compile/index.js @@ -32,6 +32,7 @@ function compileToOpenAPI(csn, options = {}) { } function processor(csn, options = {}) { + csn = cds.clone(csn); const edmOptions = { odataOpenapiHints: true, // hint to cds-compiler edm4OpenAPI: true, // downgrades certain OData errors to warnings in cds-compiler From 88077e9ef1549fc8db82fe7de090338185e26d60 Mon Sep 17 00:00:00 2001 From: Daniel O'Grady Date: Wed, 9 Sep 2026 08:20:04 +0200 Subject: [PATCH 3/4] fix: clone CSN in processor to prevent mutation of caller's definition objects --- lib/compile/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/compile/index.js b/lib/compile/index.js index e7195b0..a4e3f4a 100644 --- a/lib/compile/index.js +++ b/lib/compile/index.js @@ -199,8 +199,8 @@ function _servicePath(csdl, csn, protocols) { if (Array.isArray(protocols)) { protocols.forEach((protocol) => { - const serviceWithProtocol = { ...service, "@protocol": protocol }; - path = cds.service.path4?.(serviceWithProtocol) || cds.serve.path4(serviceWithProtocol); + service["@protocol"] = protocol; + path = cds.service.path4?.(service) || cds.serve.path4(service); paths[protocol] = path; }); } From b9d5b766f62c22a1a2f3c663941df5df4d77b30f Mon Sep 17 00:00:00 2001 From: Daniel O'Grady Date: Wed, 9 Sep 2026 08:20:04 +0200 Subject: [PATCH 4/4] fix: clone CSN in processor to prevent mutation of caller's definition objects --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bddce69..7c0a768 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/). ### Removed ### Fixed - Entities that are transitively autoexposed and should still be considered readonly, do not generate documentation for write endpoints anymore -- `_servicePath` no longer mutates the `@protocol` annotation of the CDS service definition after OpenAPI compilation +- OpenAPI compilation is now pure: the input CSN is no longer mutated during compilation ### Security ## [1.6.0] - 2026-08-04