diff --git a/.changeset/ninety-games-lie.md b/.changeset/ninety-games-lie.md new file mode 100644 index 0000000000..e561c2cdec --- /dev/null +++ b/.changeset/ninety-games-lie.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-plugin-api': patch +--- + +Improve compatibility between different versions by defining the route reference type using a string key rather than a unique symbol. This change only applies to type checking and has no effect on the runtime value, where we still use the symbol. diff --git a/packages/core-plugin-api/api-report.md b/packages/core-plugin-api/api-report.md index 39040d1c91..f92dbd44f0 100644 --- a/packages/core-plugin-api/api-report.md +++ b/packages/core-plugin-api/api-report.md @@ -423,7 +423,7 @@ export type ExternalRouteRef< Params extends AnyParams = any, Optional extends boolean = any, > = { - readonly [routeRefType]: 'external'; + $$routeRefType: 'external'; params: ParamKeys; optional?: Optional; }; @@ -720,7 +720,7 @@ export type RoutePath = string; // // @public (undocumented) export type RouteRef = { - readonly [routeRefType]: 'absolute'; + $$routeRefType: 'absolute'; params: ParamKeys; path: string; icon?: OldIconComponent; @@ -811,7 +811,7 @@ export type StorageValueChange = { // // @public (undocumented) export type SubRouteRef = { - readonly [routeRefType]: 'sub'; + $$routeRefType: 'sub'; parent: RouteRef; path: string; params: ParamKeys; @@ -901,6 +901,6 @@ export function withApis(apis: TypesToApiRefs):

( // src/apis/definitions/auth.d.ts:110:16 - (tsdoc-undefined-tag) The TSDoc tag "@IdentityApi" is not defined in this configuration // src/apis/definitions/auth.d.ts:113:68 - (tsdoc-undefined-tag) The TSDoc tag "@AuthRequestOptions" is not defined in this configuration // src/extensions/extensions.d.ts:14:5 - (ae-forgotten-export) The symbol "ComponentLoader" needs to be exported by the entry point index.d.ts -// src/routing/RouteRef.d.ts:34:5 - (ae-forgotten-export) The symbol "OldIconComponent" needs to be exported by the entry point index.d.ts +// src/routing/RouteRef.d.ts:35:5 - (ae-forgotten-export) The symbol "OldIconComponent" needs to be exported by the entry point index.d.ts // src/routing/types.d.ts:30:5 - (ae-forgotten-export) The symbol "ParamKeys" needs to be exported by the entry point index.d.ts ``` diff --git a/packages/core-plugin-api/src/routing/ExternalRouteRef.ts b/packages/core-plugin-api/src/routing/ExternalRouteRef.ts index 401e34773c..c1c17c86df 100644 --- a/packages/core-plugin-api/src/routing/ExternalRouteRef.ts +++ b/packages/core-plugin-api/src/routing/ExternalRouteRef.ts @@ -27,6 +27,8 @@ export class ExternalRouteRefImpl< Optional extends boolean, > implements ExternalRouteRef { + // The marker is used for type checking while the symbol is used at runtime. + declare $$routeRefType: 'external'; readonly [routeRefType] = 'external'; constructor( diff --git a/packages/core-plugin-api/src/routing/RouteRef.ts b/packages/core-plugin-api/src/routing/RouteRef.ts index 31dd9ef518..78211e29c6 100644 --- a/packages/core-plugin-api/src/routing/RouteRef.ts +++ b/packages/core-plugin-api/src/routing/RouteRef.ts @@ -34,6 +34,8 @@ export type RouteRefConfig = { export class RouteRefImpl implements RouteRef { + // The marker is used for type checking while the symbol is used at runtime. + declare $$routeRefType: 'absolute'; readonly [routeRefType] = 'absolute'; constructor( diff --git a/packages/core-plugin-api/src/routing/SubRouteRef.ts b/packages/core-plugin-api/src/routing/SubRouteRef.ts index 6b329dfd42..be30d56096 100644 --- a/packages/core-plugin-api/src/routing/SubRouteRef.ts +++ b/packages/core-plugin-api/src/routing/SubRouteRef.ts @@ -29,6 +29,8 @@ const PARAM_PATTERN = /^\w+$/; export class SubRouteRefImpl implements SubRouteRef { + // The marker is used for type checking while the symbol is used at runtime. + declare $$routeRefType: 'sub'; readonly [routeRefType] = 'sub'; constructor( diff --git a/packages/core-plugin-api/src/routing/types.ts b/packages/core-plugin-api/src/routing/types.ts index 86d469c2cc..7e20d1ff67 100644 --- a/packages/core-plugin-api/src/routing/types.ts +++ b/packages/core-plugin-api/src/routing/types.ts @@ -33,13 +33,18 @@ export type RouteFunc = ( ...[params]: Params extends undefined ? readonly [] : readonly [Params] ) => string; +// This symbol is what we use at runtime to determine whether a given object +// is a type of RouteRef or not. It doesn't work well in TypeScript though since +// the `unique symbol` will refer to different values between package versions. +// For that reason we use the marker $$routeRefType to represent the symbol at +// compile-time instead of using the symbol directly. export const routeRefType: unique symbol = getOrCreateGlobalSingleton( 'route-ref-type', () => Symbol('route-ref-type'), ); export type RouteRef = { - readonly [routeRefType]: 'absolute'; + $$routeRefType: 'absolute'; // See routeRefType above params: ParamKeys; @@ -53,7 +58,7 @@ export type RouteRef = { }; export type SubRouteRef = { - readonly [routeRefType]: 'sub'; + $$routeRefType: 'sub'; // See routeRefType above parent: RouteRef; @@ -66,7 +71,7 @@ export type ExternalRouteRef< Params extends AnyParams = any, Optional extends boolean = any, > = { - readonly [routeRefType]: 'external'; + $$routeRefType: 'external'; // See routeRefType above params: ParamKeys;