Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
### Fixed
- Restore bound actions/functions on containment navigation paths (regression since v1.2.0)
- Function parameters annotated with `@mandatory` no longer lead to "Unexpected mandatory after optional parameter" error
- `GET`, `PATCH`, and `DELETE` endpoints are now exposed as navigation paths for `*_texts` entities
### Security

## [1.4.2] - 2026-05-18
Expand Down
30 changes: 14 additions & 16 deletions lib/compile/csdl2openapi.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@
* @param {{ url?: string, servers?: object, odataVersion?: string, scheme?: string, host?: string, basePath?: string, diagram?: boolean, maxLevels?: number, shortActionPaths?: boolean }} options Optional parameters
* @return {object} OpenAPI description
*/
module.exports.csdl2openapi = function (

Check warning on line 93 in lib/compile/csdl2openapi.js

View workflow job for this annotation

GitHub Actions / Node.js 20

Function has a complexity of 22. Maximum allowed is 15

Check warning on line 93 in lib/compile/csdl2openapi.js

View workflow job for this annotation

GitHub Actions / Node.js 24

Function has a complexity of 22. Maximum allowed is 15

Check warning on line 93 in lib/compile/csdl2openapi.js

View workflow job for this annotation

GitHub Actions / lint

Function has a complexity of 22. Maximum allowed is 15
csdl,
{
url: serviceRoot,
Expand Down Expand Up @@ -468,11 +468,11 @@
* @param {object} options.root Root model element
* @param {string} options.sourceName Name of path source
* @param {string} options.targetName Name of path target
* @param {null | TargetRestrictions[]} options.target Target container child of path
* @param {null | TargetRestrictions} options.target Target container child of path
* @param {number} options.level Number of navigation segments so far
* @param {string} options.navigationPath Path for finding navigation restrictions
*/
function pathItems({ paths, prefix, prefixParameters, element, root, sourceName, targetName, target, level, navigationPath }) {

Check warning on line 475 in lib/compile/csdl2openapi.js

View workflow job for this annotation

GitHub Actions / Node.js 20

Function 'pathItems' has a complexity of 19. Maximum allowed is 15

Check warning on line 475 in lib/compile/csdl2openapi.js

View workflow job for this annotation

GitHub Actions / Node.js 24

Function 'pathItems' has a complexity of 19. Maximum allowed is 15

Check warning on line 475 in lib/compile/csdl2openapi.js

View workflow job for this annotation

GitHub Actions / lint

Function 'pathItems' has a complexity of 19. Maximum allowed is 15
const name = prefix.substring(prefix.lastIndexOf('/') + 1);
const type = meta.modelElement(element.$Type);
const pathItem = {};
Expand All @@ -499,7 +499,8 @@
}
pathItemsForBoundOperations({ paths, prefix, prefixParameters, element, sourceName });

if (element.$ContainsTarget) {
const targetIsTexts = target?.['$cds.autoexpose'] || (target?.$Type && nameParts(target.$Type).name.endsWith('_texts'));
if (element.$ContainsTarget || element.$Collection && targetIsTexts) {
if (element.$Collection) {
if (level < maxLevels)
pathItemsWithKey({
Expand Down Expand Up @@ -669,7 +670,7 @@
* @param {string} options.name Name of navigation segment
* @param {string} options.sourceName Name of path source
* @param {string} options.targetName Name of path target
* @param {null | TargetRestrictions[]} options.target Target container child of path
* @param {null | TargetRestrictions} options.target Target container child of path
* @param {number} options.level Number of navigation segments so far
* @param {object} options.restrictions Navigation property restrictions of navigation segment
*/
Expand Down Expand Up @@ -743,13 +744,13 @@
* @param {string} options.name Name of navigation segment
* @param {string} options.sourceName Name of path source
* @param {string} options.targetName Name of path target
* @param {null | TargetRestrictions[]} options.target Target container child of path
* @param {null | TargetRestrictions} options.target Target container child of path
* @param {number} options.level Number of navigation segments so far
* @param {object} options.restrictions Navigation property restrictions of navigation segment
* @param {boolean} options.byKey Read by key
* @param {array} options.nonExpandable Non-expandable navigation properties
*/
function operationRead({ pathItem, element, name, sourceName, targetName, target, level, restrictions, byKey, nonExpandable }) {

Check warning on line 753 in lib/compile/csdl2openapi.js

View workflow job for this annotation

GitHub Actions / Node.js 20

Function 'operationRead' has a complexity of 31. Maximum allowed is 15

Check warning on line 753 in lib/compile/csdl2openapi.js

View workflow job for this annotation

GitHub Actions / Node.js 24

Function 'operationRead' has a complexity of 31. Maximum allowed is 15

Check warning on line 753 in lib/compile/csdl2openapi.js

View workflow job for this annotation

GitHub Actions / lint

Function 'operationRead' has a complexity of 31. Maximum allowed is 15
const targetRestrictions = target?.[meta.voc.Capabilities.ReadRestrictions];
const readRestrictions = restrictions.ReadRestrictions || targetRestrictions || {};
const readByKeyRestrictions = readRestrictions.ReadByKeyRestrictions;
Expand Down Expand Up @@ -797,12 +798,9 @@
customParameters(operation, byKey ? readByKeyRestrictions || readRestrictions : readRestrictions);

if (collection) {
// @ts-expect-error - see FIXME in optionTop and optionSkip
optionTop(operation.parameters, target, restrictions);
// @ts-expect-error
optionSkip(operation.parameters, target, restrictions);
if (csdl.$Version >= '4.0') optionSearch(operation.parameters, target, restrictions);
// @ts-expect-error
optionFilter(operation.parameters, target, restrictions);
optionCount(operation.parameters, target);
optionOrderBy(operation.parameters, element, target, restrictions);
Expand Down Expand Up @@ -859,7 +857,7 @@
/**
* Add parameter for query option $count
* @param {Array} parameters Array of parameters to augment
* @param {null | TargetRestrictions[]} target Target container child of path
* @param {null | TargetRestrictions} target Target container child of path
*/
function optionCount(parameters, target) {
const targetRestrictions = target?.[meta.voc.Capabilities.CountRestrictions];
Expand All @@ -879,7 +877,7 @@
* Add parameter for query option $expand
* @param {Array} parameters Array of parameters to augment
* @param {object} element Model element of navigation segment
* @param {null | TargetRestrictions[]} target Target container child of path
* @param {null | TargetRestrictions} target Target container child of path
* @param {array} nonExpandable Non-expandable navigation properties
*/
function optionExpand(parameters, element, target, nonExpandable) {
Expand Down Expand Up @@ -966,7 +964,7 @@
* Add parameter for query option $orderby
* @param {Array} parameters Array of parameters to augment
* @param {object} element Model element of navigation segment
* @param {null | TargetRestrictions[]} target Target container child of path
* @param {null | TargetRestrictions} target Target container child of path
* @param {object} restrictions Navigation property restrictions of navigation segment
*/
function optionOrderBy(parameters, element, target, restrictions) {
Expand Down Expand Up @@ -1118,7 +1116,7 @@
/**
* Add parameter for query option $search
* @param {Array} parameters Array of parameters to augment
* @param {null | TargetRestrictions[]} target Target container child of path
* @param {null | TargetRestrictions} target Target container child of path
* @param {object} restrictions Navigation property restrictions of navigation segment
*/
function optionSearch(parameters, target, restrictions) {
Expand All @@ -1142,7 +1140,7 @@
* Add parameter for query option $select
* @param {Array} parameters Array of parameters to augment
* @param {object} element Model element of navigation segment
* @param {null | TargetRestrictions[]} target Target container child of path
* @param {null | TargetRestrictions} target Target container child of path
* @param {object} restrictions Navigation property restrictions of navigation segment
*/
function optionSelect(parameters, element, target, restrictions) {
Expand Down Expand Up @@ -1177,7 +1175,7 @@
/**
* Add parameter for query option $skip
* @param {Array} parameters Array of parameters to augment
* @param {Record<string, boolean>} target Target container child of path FIXME: this seems to be an incorrect use of TargetRestrictions
* @param {null | TargetRestrictions} target Target container child of path
* @param {object} restrictions Navigation property restrictions of navigation segment
*/
function optionSkip(parameters, target, restrictions) {
Expand All @@ -1195,7 +1193,7 @@
/**
* Add parameter for query option $top
* @param {Array} parameters Array of parameters to augment
* @param {Record<string, boolean>} target Target container child of path FIXME: this seems to be an incorrect use of TargetRestrictions
* @param {null | TargetRestrictions} target Target container child of path
* @param {object} restrictions Navigation property restrictions of navigation segment
*/
function optionTop(parameters, target, restrictions) {
Expand All @@ -1217,12 +1215,12 @@
* @param {object} options.element Model element of navigation segment
* @param {string} options.name Name of navigation segment
* @param {string} options.sourceName Name of path source
* @param {null | TargetRestrictions[]} options.target Target container child of path
* @param {null | TargetRestrictions} options.target Target container child of path
* @param {number} options.level Number of navigation segments so far
* @param {object} options.restrictions Navigation property restrictions of navigation segment
* @param {boolean} [options.byKey=false] Update by key
*/
function operationUpdate({ pathItem, element, name, sourceName, target, level, restrictions, byKey = false }) {

Check warning on line 1223 in lib/compile/csdl2openapi.js

View workflow job for this annotation

GitHub Actions / Node.js 20

Function 'operationUpdate' has a complexity of 16. Maximum allowed is 15

Check warning on line 1223 in lib/compile/csdl2openapi.js

View workflow job for this annotation

GitHub Actions / Node.js 24

Function 'operationUpdate' has a complexity of 16. Maximum allowed is 15

Check warning on line 1223 in lib/compile/csdl2openapi.js

View workflow job for this annotation

GitHub Actions / lint

Function 'operationUpdate' has a complexity of 16. Maximum allowed is 15
const updateRestrictions = restrictions.UpdateRestrictions || target?.[meta.voc.Capabilities.UpdateRestrictions] || {};
const countRestrictions = target?.[meta.voc.Capabilities.CountRestrictions]?.Countable === false;
if (updateRestrictions.Updatable !== false && !element[meta.voc.Core.Immutable]) {
Expand Down Expand Up @@ -1269,7 +1267,7 @@
* @param {object} options.element Model element of navigation segment
* @param {string} options.name Name of navigation segment
* @param {string} options.sourceName Name of path source
* @param {null | TargetRestrictions[]} options.target Target container child of path
* @param {null | TargetRestrictions} options.target Target container child of path
* @param {number} options.level Number of navigation segments so far
* @param {object} options.restrictions Navigation property restrictions of navigation segment
* @param {boolean} [options.byKey=false] Delete by key
Expand Down Expand Up @@ -1313,7 +1311,7 @@
*/
function pathItemsForMediaStream({ paths, prefix, prefixParameters, type, name, sourceName }) {
if (type.$HasStream) {
const mediaTypes = type[meta.voc.Core.AcceptableMediaTypes]?.map(t => t['$EnumMember'] ?? t) ?? [];

Check warning on line 1314 in lib/compile/csdl2openapi.js

View workflow job for this annotation

GitHub Actions / Node.js 20

["$EnumMember"] is better written in dot notation

Check warning on line 1314 in lib/compile/csdl2openapi.js

View workflow job for this annotation

GitHub Actions / Node.js 24

["$EnumMember"] is better written in dot notation

Check warning on line 1314 in lib/compile/csdl2openapi.js

View workflow job for this annotation

GitHub Actions / lint

["$EnumMember"] is better written in dot notation
const contentTypes = mediaTypes.length > 0 ? mediaTypes : ['*/*'];
const mediaContent = Object.fromEntries(contentTypes.map(ct => [ct, { schema: { type: 'string', format: 'binary' } }]));
const lname = splitName(name);
Expand Down Expand Up @@ -1643,7 +1641,7 @@
* @param {string} options.sourceName Name of path source
* @param {object} [options.actionImport={}] Action import
*/
function pathItemAction({ paths, prefix, prefixParameters, actionName, overload, sourceName, actionImport = {} }) {

Check warning on line 1644 in lib/compile/csdl2openapi.js

View workflow job for this annotation

GitHub Actions / Node.js 20

Function 'pathItemAction' has a complexity of 18. Maximum allowed is 15

Check warning on line 1644 in lib/compile/csdl2openapi.js

View workflow job for this annotation

GitHub Actions / Node.js 24

Function 'pathItemAction' has a complexity of 18. Maximum allowed is 15

Check warning on line 1644 in lib/compile/csdl2openapi.js

View workflow job for this annotation

GitHub Actions / lint

Function 'pathItemAction' has a complexity of 18. Maximum allowed is 15
const name = actionName.indexOf('.') === -1 ? actionName : nameParts(actionName).name;
const pathItem = {
post: {
Expand Down Expand Up @@ -1733,7 +1731,7 @@
* @param {string} options.sourceName Name of path source
* @param {object} [options.functionImport={}] Function Import
*/
function pathItemFunction({ paths, prefix, prefixParameters, functionName, overload, sourceName, functionImport = {} }) {

Check warning on line 1734 in lib/compile/csdl2openapi.js

View workflow job for this annotation

GitHub Actions / Node.js 20

Function 'pathItemFunction' has a complexity of 16. Maximum allowed is 15

Check warning on line 1734 in lib/compile/csdl2openapi.js

View workflow job for this annotation

GitHub Actions / Node.js 24

Function 'pathItemFunction' has a complexity of 16. Maximum allowed is 15

Check warning on line 1734 in lib/compile/csdl2openapi.js

View workflow job for this annotation

GitHub Actions / lint

Function 'pathItemFunction' has a complexity of 16. Maximum allowed is 15
const name = functionName.indexOf('.') === -1 ? functionName : nameParts(functionName).name;
let parameters = overload.$Parameter || [];
if (overload.$IsBound) parameters = parameters.slice(1);
Expand All @@ -1742,7 +1740,7 @@

const implicitAliases = csdl.$Version > '4.0' || parameters.some(p => p[meta.voc.Core.OptionalParameter]);

parameters.forEach(p => {

Check warning on line 1743 in lib/compile/csdl2openapi.js

View workflow job for this annotation

GitHub Actions / Node.js 20

Arrow function has a complexity of 29. Maximum allowed is 15

Check warning on line 1743 in lib/compile/csdl2openapi.js

View workflow job for this annotation

GitHub Actions / Node.js 24

Arrow function has a complexity of 29. Maximum allowed is 15

Check warning on line 1743 in lib/compile/csdl2openapi.js

View workflow job for this annotation

GitHub Actions / lint

Arrow function has a complexity of 29. Maximum allowed is 15
const description = getDescriptionWithFallback(p);
/** @type {Parameter} */
const param = {
Expand Down Expand Up @@ -2122,7 +2120,7 @@
* @param {string} options.suffix Suffix for read/create/update
* @return {object} Map of Schemas Objects
*/
function schemasForStructuredType({ schemas, qualifier, name, type, suffix }) {

Check warning on line 2123 in lib/compile/csdl2openapi.js

View workflow job for this annotation

GitHub Actions / Node.js 20

Function 'schemasForStructuredType' has a complexity of 18. Maximum allowed is 15

Check warning on line 2123 in lib/compile/csdl2openapi.js

View workflow job for this annotation

GitHub Actions / Node.js 24

Function 'schemasForStructuredType' has a complexity of 18. Maximum allowed is 15

Check warning on line 2123 in lib/compile/csdl2openapi.js

View workflow job for this annotation

GitHub Actions / lint

Function 'schemasForStructuredType' has a complexity of 18. Maximum allowed is 15
const schemaName = `${qualifier}.${name}${suffix}`;
const baseName = `${qualifier}.${name}`;
const isKey = keyMap(type);
Expand All @@ -2138,7 +2136,7 @@
const properties = propertiesOfStructuredType(type);
const expandRestrictions = type[meta.voc.Capabilities.ExpandRestrictions] ?? {};
const nonExpandableProperties = expandRestrictions.NonExpandableProperties ?? [];
Object.keys(properties).forEach(iName => {

Check warning on line 2139 in lib/compile/csdl2openapi.js

View workflow job for this annotation

GitHub Actions / Node.js 20

Arrow function has a complexity of 27. Maximum allowed is 15

Check warning on line 2139 in lib/compile/csdl2openapi.js

View workflow job for this annotation

GitHub Actions / Node.js 24

Arrow function has a complexity of 27. Maximum allowed is 15

Check warning on line 2139 in lib/compile/csdl2openapi.js

View workflow job for this annotation

GitHub Actions / lint

Arrow function has a complexity of 27. Maximum allowed is 15
if (nonExpandableProperties.includes(iName)) {
return;
}
Expand Down
1 change: 1 addition & 0 deletions lib/compile/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export type Schema = (SingleSchema | MultiSchema)
export type TargetRestrictions = {
Countable?: boolean
Expandable?: boolean
$Type?: string
}

// despite how CSDL is defined in the standard,
Expand Down
11 changes: 10 additions & 1 deletion test/lib/compile/data/autoexposed-texts.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@
"$Kind": "EntityContainer",
"Books": {
"$Collection": true,
"$Type": "AdminService.Books"
"$Type": "AdminService.Books",
"$NavigationPropertyBinding": {
"texts": "Books_texts"
}
},
"Books_texts": {
"$Collection": true,
Expand All @@ -20,6 +23,12 @@
"$Key": ["ID"],
"ID": {
"$Type": "Edm.Int32"
},
"texts": {
"$Kind": "NavigationProperty",
"$Type": "AdminService.Books_texts",
"$Collection": true,
"$OnDelete": "Cascade"
}
},
"Books_texts": {
Expand Down
Loading
Loading