Skip to content

Commit 3291f6c

Browse files
authored
fix(project-access): guard against undefined URL in uniformUrl (#4498)
The uniformUrl() function in processServices() would throw a TypeError 'Cannot read properties of undefined (reading replace)' when a service endpoint had no path and no urlPath fallback was available. Added an early return for falsy URL values and comprehensive tests for the processServices() function.
1 parent 7928bcf commit 3291f6c

File tree

3 files changed

+97
-0
lines changed

3 files changed

+97
-0
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@sap-ux/project-access': patch
3+
---
4+
5+
Fix: guard against undefined URL in uniformUrl to prevent TypeError when service endpoints have no path

packages/project-access/src/project/cap.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,9 @@ function extractCdsFilesFromMessage(sources: Record<string, { filename?: string
378378
* @returns - uniform url
379379
*/
380380
function uniformUrl(url: string): string {
381+
if (!url) {
382+
return '';
383+
}
381384
return url
382385
.replace(/\\/g, '/')
383386
.replace(/\/\//g, '/')

packages/project-access/test/project/cap.test.ts

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
isCapJavaProject,
2424
getCapModelAndServices,
2525
getCapProjectType,
26+
processServices,
2627
readCapServiceMetadataEdmx,
2728
toReferenceUri,
2829
isCapProject,
@@ -1831,6 +1832,94 @@ describe('Test hasMinCdsVersion()', () => {
18311832
});
18321833
});
18331834

1835+
describe('Test processServices()', () => {
1836+
test('should return empty array for undefined input', () => {
1837+
expect(processServices(undefined)).toEqual([]);
1838+
});
1839+
1840+
test('should return empty array for non-array input', () => {
1841+
expect(processServices({})).toEqual([]);
1842+
});
1843+
1844+
test('should handle services where endpoint path and urlPath are both undefined', () => {
1845+
const services = [
1846+
{
1847+
name: 'TestService',
1848+
endpoints: [
1849+
{
1850+
kind: 'odata',
1851+
path: undefined
1852+
}
1853+
],
1854+
urlPath: undefined
1855+
}
1856+
];
1857+
const result = processServices(services as any);
1858+
expect(result).toEqual([
1859+
{
1860+
name: 'TestService',
1861+
urlPath: '',
1862+
runtime: undefined
1863+
}
1864+
]);
1865+
});
1866+
1867+
test('should use endpoint path when available', () => {
1868+
const services = [
1869+
{
1870+
name: 'TestService',
1871+
endpoints: [
1872+
{
1873+
kind: 'odata',
1874+
path: 'odata/v4/test'
1875+
}
1876+
]
1877+
}
1878+
];
1879+
const result = processServices(services as any);
1880+
expect(result).toEqual([
1881+
{
1882+
name: 'TestService',
1883+
urlPath: 'odata/v4/test',
1884+
runtime: undefined
1885+
}
1886+
]);
1887+
});
1888+
1889+
test('should fall back to urlPath when no odata endpoint path', () => {
1890+
const services = [
1891+
{
1892+
name: 'TestService',
1893+
urlPath: 'service/path'
1894+
}
1895+
];
1896+
const result = processServices(services as any);
1897+
expect(result).toEqual([
1898+
{
1899+
name: 'TestService',
1900+
urlPath: 'service/path',
1901+
runtime: undefined
1902+
}
1903+
]);
1904+
});
1905+
1906+
test('should filter out non-odata services with endpoints', () => {
1907+
const services = [
1908+
{
1909+
name: 'WebSocketService',
1910+
endpoints: [
1911+
{
1912+
kind: 'websocket',
1913+
path: 'ws/test'
1914+
}
1915+
]
1916+
}
1917+
];
1918+
const result = processServices(services as any);
1919+
expect(result).toEqual([]);
1920+
});
1921+
});
1922+
18341923
function fail(message: string) {
18351924
expect(message).toBeFalsy();
18361925
}

0 commit comments

Comments
 (0)