Merge pull request #29190 from backstage/rugvip/norm

core-compat-api: better normalization of discovered route paths
This commit is contained in:
Patrik Oldsberg
2025-03-12 17:25:09 +01:00
committed by GitHub
5 changed files with 77 additions and 2 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/core-compat-api': patch
---
Improved route path normalization when converting existing route elements in `converLegacyApp`, for example handling trailing `/*` in paths.
@@ -25,6 +25,7 @@ import {
EntityCardBlueprint,
EntityContentBlueprint,
} from '@backstage/plugin-catalog-react/alpha';
import { normalizeRoutePath } from './normalizeRoutePath';
const ENTITY_SWITCH_KEY = 'core.backstage.entitySwitch';
const ENTITY_ROUTE_KEY = 'plugin.catalog.entityLayoutRoute';
@@ -114,7 +115,7 @@ export function collectEntityPageContents(
name,
factory(originalFactory, { apis }) {
return originalFactory({
defaultPath: pageNode.path,
defaultPath: normalizeRoutePath(pageNode.path),
defaultTitle: pageNode.title,
filter: mergedIf && (entity => mergedIf(entity, { apis })),
loader: () => Promise.resolve(pageNode.children),
@@ -41,6 +41,7 @@ import {
} from './convertLegacyRouteRef';
import { compatWrapper } from './compatWrapper';
import { collectEntityPageContents } from './collectEntityPageContents';
import { normalizeRoutePath } from './normalizeRoutePath';
/*
@@ -236,7 +237,7 @@ export function collectLegacyRoutes(
factory(originalFactory, { inputs: _inputs }) {
// todo(blam): why do we not use the inputs here?
return originalFactory({
defaultPath: path[0] === '/' ? path.slice(1) : path,
defaultPath: normalizeRoutePath(path),
routeRef: routeRef ? convertLegacyRouteRef(routeRef) : undefined,
loader: async () =>
compatWrapper(
@@ -0,0 +1,36 @@
/*
* Copyright 2025 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { normalizeRoutePath } from './normalizeRoutePath';
describe('normalizeRoutePath', () => {
it('should normalize the path', () => {
expect(normalizeRoutePath('')).toBe('/');
expect(normalizeRoutePath('/')).toBe('/');
expect(normalizeRoutePath('/*')).toBe('/');
expect(normalizeRoutePath('/////')).toBe('/');
expect(normalizeRoutePath('*//*//*')).toBe('/');
expect(normalizeRoutePath('/foo')).toBe('/foo');
expect(normalizeRoutePath('/foo/')).toBe('/foo');
expect(normalizeRoutePath('/foo/*')).toBe('/foo');
expect(normalizeRoutePath('/foo/**')).toBe('/foo');
expect(normalizeRoutePath('/foo//**')).toBe('/foo');
expect(normalizeRoutePath('/foo/*/*')).toBe('/foo');
expect(normalizeRoutePath('//foo/*/*')).toBe('/foo');
expect(normalizeRoutePath('/foo/bar//*/*')).toBe('/foo/bar');
expect(normalizeRoutePath('/foo//bar//*/*')).toBe('/foo//bar');
});
});
@@ -0,0 +1,32 @@
/*
* Copyright 2025 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Normalizes the path to make sure it always starts with a single '/' and do not end with '/' or '*' unless empty
*/
export function normalizeRoutePath(path: string) {
let normalized = path;
while (normalized.endsWith('/') || normalized.endsWith('*')) {
normalized = normalized.slice(0, -1);
}
while (normalized.startsWith('/')) {
normalized = normalized.slice(1);
}
if (!normalized) {
return '/';
}
return `/${normalized}`;
}