@backstage/core-compat-api 0.2.8-next.0 → 0.2.8-next.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # @backstage/core-compat-api
2
2
 
3
+ ## 0.2.8-next.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 72754db: Updated usage of `useRouteRef`, which can now always return `undefined`.
8
+ - 16cf96c: Both `compatWrapper` and `convertLegacyRouteRef` now support converting from the new system to the old.
9
+ - Updated dependencies
10
+ - @backstage/frontend-plugin-api@0.7.0-next.2
11
+ - @backstage/core-plugin-api@1.9.3
12
+ - @backstage/version-bridge@1.0.8
13
+
14
+ ## 0.2.8-next.1
15
+
16
+ ### Patch Changes
17
+
18
+ - 6349099: Added config input type to the extensions
19
+ - Updated dependencies
20
+ - @backstage/frontend-plugin-api@0.6.8-next.1
21
+ - @backstage/core-plugin-api@1.9.3
22
+ - @backstage/version-bridge@1.0.8
23
+
3
24
  ## 0.2.8-next.0
4
25
 
5
26
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"collectLegacyRoutes.esm.js","sources":["../src/collectLegacyRoutes.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n AnyRouteRefParams,\n BackstagePlugin as LegacyBackstagePlugin,\n RouteRef,\n getComponentData,\n} from '@backstage/core-plugin-api';\nimport {\n BackstagePlugin,\n ExtensionDefinition,\n coreExtensionData,\n createApiExtension,\n createExtension,\n createExtensionInput,\n createPageExtension,\n createPlugin,\n} from '@backstage/frontend-plugin-api';\nimport React, { Children, ReactNode, isValidElement } from 'react';\nimport { Route, Routes } from 'react-router-dom';\nimport {\n convertLegacyRouteRef,\n convertLegacyRouteRefs,\n} from './convertLegacyRouteRef';\nimport { compatWrapper } from './compatWrapper';\n\n/*\n\n# Legacy interoperability\n\nUse-cases (prioritized):\n 1. Slowly migrate over an existing app to DI, piece by piece\n 2. Use a legacy plugin in a new DI app\n 3. Use DI in an existing legacy app\n\nStarting point: use-case #1\n\nPotential solutions:\n 1. Codemods (we're not considering this for now)\n 2. Legacy apps are migrated bottom-up, i.e. keep legacy root, replace pages with DI\n 3. Legacy apps are migrated top-down i.e. switch out base to DI, legacy adapter allows for usage of existing app structure\n\nChosen path: #3\n\nExisting tasks:\n - Adopters can migrate their existing app gradually (~4)\n - Example-app uses legacy base with DI adapters\n - Create an API that lets you inject DI into existing apps - working assumption is that this is enough\n - Adopters can use legacy plugins in DI through adapters (~8)\n - App-next uses DI base with legacy adapters\n - Create a legacy adapter that is able to take an existing extension tree\n\n*/\n\n// Creates a shim extension whose purpose is to build up the tree (anchored at\n// the root page) of paths/routeRefs so that the app can bind them properly.\nfunction makeRoutingShimExtension(options: {\n name: string;\n parentExtensionId: string;\n routePath?: string;\n routeRef?: RouteRef;\n}) {\n const { name, parentExtensionId, routePath, routeRef } = options;\n return createExtension({\n kind: 'routing-shim',\n name,\n attachTo: { id: parentExtensionId, input: 'childRoutingShims' },\n inputs: {\n childRoutingShims: createExtensionInput({\n routePath: coreExtensionData.routePath.optional(),\n routeRef: coreExtensionData.routeRef.optional(),\n }),\n },\n output: {\n routePath: coreExtensionData.routePath.optional(),\n routeRef: coreExtensionData.routeRef.optional(),\n },\n factory: () => ({\n routePath,\n routeRef: routeRef ? convertLegacyRouteRef(routeRef) : undefined,\n }),\n });\n}\n\nfunction visitRouteChildren(options: {\n children: ReactNode;\n parentExtensionId: string;\n context: {\n pluginId: string;\n extensions: ExtensionDefinition<unknown>[];\n getUniqueName: () => string;\n discoverPlugin: (plugin: LegacyBackstagePlugin) => void;\n };\n}): void {\n const { children, parentExtensionId, context } = options;\n const { pluginId, extensions, getUniqueName, discoverPlugin } = context;\n\n Children.forEach(children, node => {\n if (!isValidElement(node)) {\n return;\n }\n\n const plugin = getComponentData<LegacyBackstagePlugin>(node, 'core.plugin');\n const routeRef = getComponentData<RouteRef<AnyRouteRefParams>>(\n node,\n 'core.mountPoint',\n );\n const routePath: string | undefined = node.props?.path;\n\n if (plugin) {\n // We just mark the plugin as discovered, but don't change the context\n discoverPlugin(plugin);\n }\n\n let nextParentExtensionId = parentExtensionId;\n if (routeRef || routePath) {\n const nextParentExtensionName = getUniqueName();\n nextParentExtensionId = `routing-shim:${pluginId}/${nextParentExtensionName}`;\n extensions.push(\n makeRoutingShimExtension({\n name: nextParentExtensionName,\n parentExtensionId,\n routePath,\n routeRef,\n }),\n );\n }\n\n visitRouteChildren({\n children: node.props.children,\n parentExtensionId: nextParentExtensionId,\n context,\n });\n });\n}\n\n/** @internal */\nexport function collectLegacyRoutes(\n flatRoutesElement: JSX.Element,\n): BackstagePlugin[] {\n const pluginExtensions = new Map<\n LegacyBackstagePlugin,\n ExtensionDefinition<unknown>[]\n >();\n\n const getUniqueName = (() => {\n let currentIndex = 1;\n return () => String(currentIndex++);\n })();\n\n const getPluginExtensions = (plugin: LegacyBackstagePlugin) => {\n let extensions = pluginExtensions.get(plugin);\n if (!extensions) {\n extensions = [];\n pluginExtensions.set(plugin, extensions);\n }\n return extensions;\n };\n\n React.Children.forEach(\n flatRoutesElement.props.children,\n (route: ReactNode) => {\n // TODO(freben): Handle feature flag and permissions framework wrapper elements\n if (!React.isValidElement(route)) {\n throw new Error(\n `Invalid element inside FlatRoutes, expected Route but found element of type ${typeof route}.`,\n );\n }\n if (route.type !== Route) {\n throw new Error(\n `Invalid element inside FlatRoutes, expected Route but found ${route.type}.`,\n );\n }\n const routeElement = route.props.element;\n const path: string | undefined = route.props.path;\n const plugin = getComponentData<LegacyBackstagePlugin>(\n routeElement,\n 'core.plugin',\n );\n const routeRef = getComponentData<RouteRef>(\n routeElement,\n 'core.mountPoint',\n );\n if (!plugin) {\n throw new Error(\n // TODO(vinzscam): add See <link-to-app-migration-docs> for more info\n `Route with path ${path} has en element that can not be converted as it does not belong to a plugin. Make sure that the top-level React element of the element prop is an extension from a Backstage plugin, or remove the Route completely.`,\n );\n }\n if (path === undefined) {\n throw new Error(\n `Route element inside FlatRoutes had no path prop value given`,\n );\n }\n\n const extensions = getPluginExtensions(plugin);\n const pageExtensionName = extensions.length ? getUniqueName() : undefined;\n const pageExtensionId = `page:${plugin.getId()}${\n pageExtensionName ? `/${pageExtensionName}` : pageExtensionName\n }`;\n\n extensions.push(\n createPageExtension({\n name: pageExtensionName,\n defaultPath: path[0] === '/' ? path.slice(1) : path,\n routeRef: routeRef ? convertLegacyRouteRef(routeRef) : undefined,\n inputs: {\n childRoutingShims: createExtensionInput({\n routePath: coreExtensionData.routePath.optional(),\n routeRef: coreExtensionData.routeRef.optional(),\n }),\n },\n loader: async () =>\n compatWrapper(\n route.props.children ? (\n <Routes>\n <Route path=\"*\" element={routeElement}>\n <Route path=\"*\" element={route.props.children} />\n </Route>\n </Routes>\n ) : (\n routeElement\n ),\n ),\n }),\n );\n\n visitRouteChildren({\n children: route.props.children,\n parentExtensionId: pageExtensionId,\n context: {\n pluginId: plugin.getId(),\n extensions,\n getUniqueName,\n discoverPlugin: getPluginExtensions,\n },\n });\n },\n );\n\n return Array.from(pluginExtensions).map(([plugin, extensions]) =>\n createPlugin({\n id: plugin.getId(),\n extensions: [\n ...extensions,\n ...Array.from(plugin.getApis()).map(factory =>\n createApiExtension({ factory }),\n ),\n ],\n routes: convertLegacyRouteRefs(plugin.routes ?? {}),\n externalRoutes: convertLegacyRouteRefs(plugin.externalRoutes ?? {}),\n }),\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"collectLegacyRoutes.esm.js","sources":["../src/collectLegacyRoutes.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n AnyRouteRefParams,\n BackstagePlugin as LegacyBackstagePlugin,\n RouteRef,\n getComponentData,\n} from '@backstage/core-plugin-api';\nimport {\n BackstagePlugin,\n ExtensionDefinition,\n coreExtensionData,\n createApiExtension,\n createExtension,\n createExtensionInput,\n createPageExtension,\n createPlugin,\n} from '@backstage/frontend-plugin-api';\nimport React, { Children, ReactNode, isValidElement } from 'react';\nimport { Route, Routes } from 'react-router-dom';\nimport {\n convertLegacyRouteRef,\n convertLegacyRouteRefs,\n} from './convertLegacyRouteRef';\nimport { compatWrapper } from './compatWrapper';\n\n/*\n\n# Legacy interoperability\n\nUse-cases (prioritized):\n 1. Slowly migrate over an existing app to DI, piece by piece\n 2. Use a legacy plugin in a new DI app\n 3. Use DI in an existing legacy app\n\nStarting point: use-case #1\n\nPotential solutions:\n 1. Codemods (we're not considering this for now)\n 2. Legacy apps are migrated bottom-up, i.e. keep legacy root, replace pages with DI\n 3. Legacy apps are migrated top-down i.e. switch out base to DI, legacy adapter allows for usage of existing app structure\n\nChosen path: #3\n\nExisting tasks:\n - Adopters can migrate their existing app gradually (~4)\n - Example-app uses legacy base with DI adapters\n - Create an API that lets you inject DI into existing apps - working assumption is that this is enough\n - Adopters can use legacy plugins in DI through adapters (~8)\n - App-next uses DI base with legacy adapters\n - Create a legacy adapter that is able to take an existing extension tree\n\n*/\n\n// Creates a shim extension whose purpose is to build up the tree (anchored at\n// the root page) of paths/routeRefs so that the app can bind them properly.\nfunction makeRoutingShimExtension(options: {\n name: string;\n parentExtensionId: string;\n routePath?: string;\n routeRef?: RouteRef;\n}) {\n const { name, parentExtensionId, routePath, routeRef } = options;\n return createExtension({\n kind: 'routing-shim',\n name,\n attachTo: { id: parentExtensionId, input: 'childRoutingShims' },\n inputs: {\n childRoutingShims: createExtensionInput({\n routePath: coreExtensionData.routePath.optional(),\n routeRef: coreExtensionData.routeRef.optional(),\n }),\n },\n output: {\n routePath: coreExtensionData.routePath.optional(),\n routeRef: coreExtensionData.routeRef.optional(),\n },\n factory: () => ({\n routePath,\n routeRef: routeRef ? convertLegacyRouteRef(routeRef) : undefined,\n }),\n });\n}\n\nfunction visitRouteChildren(options: {\n children: ReactNode;\n parentExtensionId: string;\n context: {\n pluginId: string;\n extensions: ExtensionDefinition<any, any>[];\n getUniqueName: () => string;\n discoverPlugin: (plugin: LegacyBackstagePlugin) => void;\n };\n}): void {\n const { children, parentExtensionId, context } = options;\n const { pluginId, extensions, getUniqueName, discoverPlugin } = context;\n\n Children.forEach(children, node => {\n if (!isValidElement(node)) {\n return;\n }\n\n const plugin = getComponentData<LegacyBackstagePlugin>(node, 'core.plugin');\n const routeRef = getComponentData<RouteRef<AnyRouteRefParams>>(\n node,\n 'core.mountPoint',\n );\n const routePath: string | undefined = node.props?.path;\n\n if (plugin) {\n // We just mark the plugin as discovered, but don't change the context\n discoverPlugin(plugin);\n }\n\n let nextParentExtensionId = parentExtensionId;\n if (routeRef || routePath) {\n const nextParentExtensionName = getUniqueName();\n nextParentExtensionId = `routing-shim:${pluginId}/${nextParentExtensionName}`;\n extensions.push(\n makeRoutingShimExtension({\n name: nextParentExtensionName,\n parentExtensionId,\n routePath,\n routeRef,\n }),\n );\n }\n\n visitRouteChildren({\n children: node.props.children,\n parentExtensionId: nextParentExtensionId,\n context,\n });\n });\n}\n\n/** @internal */\nexport function collectLegacyRoutes(\n flatRoutesElement: JSX.Element,\n): BackstagePlugin[] {\n const pluginExtensions = new Map<\n LegacyBackstagePlugin,\n ExtensionDefinition<any, any>[]\n >();\n\n const getUniqueName = (() => {\n let currentIndex = 1;\n return () => String(currentIndex++);\n })();\n\n const getPluginExtensions = (plugin: LegacyBackstagePlugin) => {\n let extensions = pluginExtensions.get(plugin);\n if (!extensions) {\n extensions = [];\n pluginExtensions.set(plugin, extensions);\n }\n return extensions;\n };\n\n React.Children.forEach(\n flatRoutesElement.props.children,\n (route: ReactNode) => {\n // TODO(freben): Handle feature flag and permissions framework wrapper elements\n if (!React.isValidElement(route)) {\n throw new Error(\n `Invalid element inside FlatRoutes, expected Route but found element of type ${typeof route}.`,\n );\n }\n if (route.type !== Route) {\n throw new Error(\n `Invalid element inside FlatRoutes, expected Route but found ${route.type}.`,\n );\n }\n const routeElement = route.props.element;\n const path: string | undefined = route.props.path;\n const plugin = getComponentData<LegacyBackstagePlugin>(\n routeElement,\n 'core.plugin',\n );\n const routeRef = getComponentData<RouteRef>(\n routeElement,\n 'core.mountPoint',\n );\n if (!plugin) {\n throw new Error(\n // TODO(vinzscam): add See <link-to-app-migration-docs> for more info\n `Route with path ${path} has en element that can not be converted as it does not belong to a plugin. Make sure that the top-level React element of the element prop is an extension from a Backstage plugin, or remove the Route completely.`,\n );\n }\n if (path === undefined) {\n throw new Error(\n `Route element inside FlatRoutes had no path prop value given`,\n );\n }\n\n const extensions = getPluginExtensions(plugin);\n const pageExtensionName = extensions.length ? getUniqueName() : undefined;\n const pageExtensionId = `page:${plugin.getId()}${\n pageExtensionName ? `/${pageExtensionName}` : pageExtensionName\n }`;\n\n extensions.push(\n createPageExtension({\n name: pageExtensionName,\n defaultPath: path[0] === '/' ? path.slice(1) : path,\n routeRef: routeRef ? convertLegacyRouteRef(routeRef) : undefined,\n inputs: {\n childRoutingShims: createExtensionInput({\n routePath: coreExtensionData.routePath.optional(),\n routeRef: coreExtensionData.routeRef.optional(),\n }),\n },\n loader: async () =>\n compatWrapper(\n route.props.children ? (\n <Routes>\n <Route path=\"*\" element={routeElement}>\n <Route path=\"*\" element={route.props.children} />\n </Route>\n </Routes>\n ) : (\n routeElement\n ),\n ),\n }),\n );\n\n visitRouteChildren({\n children: route.props.children,\n parentExtensionId: pageExtensionId,\n context: {\n pluginId: plugin.getId(),\n extensions,\n getUniqueName,\n discoverPlugin: getPluginExtensions,\n },\n });\n },\n );\n\n return Array.from(pluginExtensions).map(([plugin, extensions]) =>\n createPlugin({\n id: plugin.getId(),\n extensions: [\n ...extensions,\n ...Array.from(plugin.getApis()).map(factory =>\n createApiExtension({ factory }),\n ),\n ],\n routes: convertLegacyRouteRefs(plugin.routes ?? {}),\n externalRoutes: convertLegacyRouteRefs(plugin.externalRoutes ?? {}),\n }),\n );\n}\n"],"names":[],"mappings":"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"}
@@ -128,5 +128,5 @@ function BackwardsCompatProvider(props) {
128
128
  return /* @__PURE__ */ React.createElement(LegacyRoutingProvider, null, /* @__PURE__ */ React.createElement(LegacyAppContextProvider, null, props.children));
129
129
  }
130
130
 
131
- export { BackwardsCompatProvider };
131
+ export { BackwardsCompatProvider, toLegacyPlugin };
132
132
  //# sourceMappingURL=BackwardsCompatProvider.esm.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"BackwardsCompatProvider.esm.js","sources":["../../src/compatWrapper/BackwardsCompatProvider.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { useMemo } from 'react';\nimport { ReactNode } from 'react';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { AppContextProvider } from '../../../core-app-api/src/app/AppContext';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { RouteResolver } from '../../../core-plugin-api/src/routing/useRouteRef';\nimport {\n createPlugin as createNewPlugin,\n BackstagePlugin as NewBackstagePlugin,\n appTreeApiRef,\n componentsApiRef,\n coreComponentRefs,\n iconsApiRef,\n useApi,\n routeResolutionApiRef,\n} from '@backstage/frontend-plugin-api';\nimport {\n AppComponents,\n IconComponent,\n BackstagePlugin as LegacyBackstagePlugin,\n RouteRef,\n} from '@backstage/core-plugin-api';\nimport {\n VersionedValue,\n createVersionedContext,\n createVersionedValueMap,\n getOrCreateGlobalSingleton,\n} from '@backstage/version-bridge';\nimport { convertLegacyRouteRef } from '../convertLegacyRouteRef';\n\n// Make sure that we only convert each new plugin instance to its legacy equivalent once\nconst legacyPluginStore = getOrCreateGlobalSingleton(\n 'legacy-plugin-compatibility-store',\n () => new WeakMap<NewBackstagePlugin, LegacyBackstagePlugin>(),\n);\n\nfunction toLegacyPlugin(plugin: NewBackstagePlugin): LegacyBackstagePlugin {\n let legacy = legacyPluginStore.get(plugin);\n if (legacy) {\n return legacy;\n }\n\n const errorMsg = 'Not implemented in legacy plugin compatibility layer';\n const notImplemented = () => {\n throw new Error(errorMsg);\n };\n\n legacy = {\n getId(): string {\n return plugin.id;\n },\n get routes() {\n return {};\n },\n get externalRoutes() {\n return {};\n },\n getApis: notImplemented,\n getFeatureFlags: notImplemented,\n provide: notImplemented,\n };\n\n legacyPluginStore.set(plugin, legacy);\n return legacy;\n}\n\n// TODO: Currently a very naive implementation, may need some more work\nfunction toNewPlugin(plugin: LegacyBackstagePlugin): NewBackstagePlugin {\n return createNewPlugin({\n id: plugin.getId(),\n });\n}\n\n// Recreates the old AppContext APIs using the various new APIs that replaced it\nfunction LegacyAppContextProvider(props: { children: ReactNode }) {\n const appTreeApi = useApi(appTreeApiRef);\n const componentsApi = useApi(componentsApiRef);\n const iconsApi = useApi(iconsApiRef);\n\n const appContext = useMemo(() => {\n const { tree } = appTreeApi.getTree();\n\n let gatheredPlugins: LegacyBackstagePlugin[] | undefined = undefined;\n\n const ErrorBoundaryFallback = componentsApi.getComponent(\n coreComponentRefs.errorBoundaryFallback,\n );\n const ErrorBoundaryFallbackWrapper: AppComponents['ErrorBoundaryFallback'] =\n ({ plugin, ...rest }) => (\n <ErrorBoundaryFallback\n {...rest}\n plugin={plugin && toNewPlugin(plugin)}\n />\n );\n\n return {\n getPlugins(): LegacyBackstagePlugin[] {\n if (gatheredPlugins) {\n return gatheredPlugins;\n }\n\n const pluginSet = new Set<LegacyBackstagePlugin>();\n for (const node of tree.nodes.values()) {\n const plugin = node.spec.source;\n if (plugin) {\n pluginSet.add(toLegacyPlugin(plugin));\n }\n }\n gatheredPlugins = Array.from(pluginSet);\n\n return gatheredPlugins;\n },\n\n getSystemIcon(key: string): IconComponent | undefined {\n return iconsApi.getIcon(key);\n },\n\n getSystemIcons(): Record<string, IconComponent> {\n return Object.fromEntries(\n iconsApi.listIconKeys().map(key => [key, iconsApi.getIcon(key)!]),\n );\n },\n\n getComponents(): AppComponents {\n return {\n NotFoundErrorPage: componentsApi.getComponent(\n coreComponentRefs.notFoundErrorPage,\n ),\n BootErrorPage() {\n throw new Error(\n 'The BootErrorPage app component should not be accessed by plugins',\n );\n },\n Progress: componentsApi.getComponent(coreComponentRefs.progress),\n Router() {\n throw new Error(\n 'The Router app component should not be accessed by plugins',\n );\n },\n ErrorBoundaryFallback: ErrorBoundaryFallbackWrapper,\n };\n },\n };\n }, [appTreeApi, componentsApi, iconsApi]);\n\n return (\n <AppContextProvider appContext={appContext}>\n {props.children}\n </AppContextProvider>\n );\n}\n\nconst RoutingContext = createVersionedContext<{ 1: RouteResolver }>(\n 'routing-context',\n);\n\nfunction LegacyRoutingProvider(props: { children: ReactNode }) {\n const routeResolutionApi = useApi(routeResolutionApiRef);\n\n const value = useMemo<VersionedValue<{ 1: RouteResolver }>>(() => {\n return createVersionedValueMap({\n 1: {\n resolve(anyRouteRef, location) {\n const sourcePath =\n typeof location === 'string' ? location : location.pathname ?? '';\n\n return routeResolutionApi.resolve(\n // This removes the requirement to use convertLegacyRouteRef inside plugins, but\n // they still need to converted when passed to the plugin instance\n convertLegacyRouteRef(anyRouteRef as RouteRef),\n { sourcePath },\n );\n },\n },\n });\n }, [routeResolutionApi]);\n\n return (\n <RoutingContext.Provider value={value}>\n {props.children}\n </RoutingContext.Provider>\n );\n}\n\nexport function BackwardsCompatProvider(props: { children: ReactNode }) {\n return (\n <LegacyRoutingProvider>\n <LegacyAppContextProvider>{props.children}</LegacyAppContextProvider>\n </LegacyRoutingProvider>\n );\n}\n"],"names":["createNewPlugin"],"mappings":"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"}
1
+ {"version":3,"file":"BackwardsCompatProvider.esm.js","sources":["../../src/compatWrapper/BackwardsCompatProvider.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { useMemo } from 'react';\nimport { ReactNode } from 'react';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { AppContextProvider } from '../../../core-app-api/src/app/AppContext';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { RouteResolver } from '../../../core-plugin-api/src/routing/useRouteRef';\nimport {\n createPlugin as createNewPlugin,\n BackstagePlugin as NewBackstagePlugin,\n appTreeApiRef,\n componentsApiRef,\n coreComponentRefs,\n iconsApiRef,\n useApi,\n routeResolutionApiRef,\n} from '@backstage/frontend-plugin-api';\nimport {\n AppComponents,\n IconComponent,\n BackstagePlugin as LegacyBackstagePlugin,\n RouteRef,\n} from '@backstage/core-plugin-api';\nimport {\n VersionedValue,\n createVersionedContext,\n createVersionedValueMap,\n getOrCreateGlobalSingleton,\n} from '@backstage/version-bridge';\nimport { convertLegacyRouteRef } from '../convertLegacyRouteRef';\n\n// Make sure that we only convert each new plugin instance to its legacy equivalent once\nconst legacyPluginStore = getOrCreateGlobalSingleton(\n 'legacy-plugin-compatibility-store',\n () => new WeakMap<NewBackstagePlugin, LegacyBackstagePlugin>(),\n);\n\nexport function toLegacyPlugin(\n plugin: NewBackstagePlugin,\n): LegacyBackstagePlugin {\n let legacy = legacyPluginStore.get(plugin);\n if (legacy) {\n return legacy;\n }\n\n const errorMsg = 'Not implemented in legacy plugin compatibility layer';\n const notImplemented = () => {\n throw new Error(errorMsg);\n };\n\n legacy = {\n getId(): string {\n return plugin.id;\n },\n get routes() {\n return {};\n },\n get externalRoutes() {\n return {};\n },\n getApis: notImplemented,\n getFeatureFlags: notImplemented,\n provide: notImplemented,\n };\n\n legacyPluginStore.set(plugin, legacy);\n return legacy;\n}\n\n// TODO: Currently a very naive implementation, may need some more work\nfunction toNewPlugin(plugin: LegacyBackstagePlugin): NewBackstagePlugin {\n return createNewPlugin({\n id: plugin.getId(),\n });\n}\n\n// Recreates the old AppContext APIs using the various new APIs that replaced it\nfunction LegacyAppContextProvider(props: { children: ReactNode }) {\n const appTreeApi = useApi(appTreeApiRef);\n const componentsApi = useApi(componentsApiRef);\n const iconsApi = useApi(iconsApiRef);\n\n const appContext = useMemo(() => {\n const { tree } = appTreeApi.getTree();\n\n let gatheredPlugins: LegacyBackstagePlugin[] | undefined = undefined;\n\n const ErrorBoundaryFallback = componentsApi.getComponent(\n coreComponentRefs.errorBoundaryFallback,\n );\n const ErrorBoundaryFallbackWrapper: AppComponents['ErrorBoundaryFallback'] =\n ({ plugin, ...rest }) => (\n <ErrorBoundaryFallback\n {...rest}\n plugin={plugin && toNewPlugin(plugin)}\n />\n );\n\n return {\n getPlugins(): LegacyBackstagePlugin[] {\n if (gatheredPlugins) {\n return gatheredPlugins;\n }\n\n const pluginSet = new Set<LegacyBackstagePlugin>();\n for (const node of tree.nodes.values()) {\n const plugin = node.spec.source;\n if (plugin) {\n pluginSet.add(toLegacyPlugin(plugin));\n }\n }\n gatheredPlugins = Array.from(pluginSet);\n\n return gatheredPlugins;\n },\n\n getSystemIcon(key: string): IconComponent | undefined {\n return iconsApi.getIcon(key);\n },\n\n getSystemIcons(): Record<string, IconComponent> {\n return Object.fromEntries(\n iconsApi.listIconKeys().map(key => [key, iconsApi.getIcon(key)!]),\n );\n },\n\n getComponents(): AppComponents {\n return {\n NotFoundErrorPage: componentsApi.getComponent(\n coreComponentRefs.notFoundErrorPage,\n ),\n BootErrorPage() {\n throw new Error(\n 'The BootErrorPage app component should not be accessed by plugins',\n );\n },\n Progress: componentsApi.getComponent(coreComponentRefs.progress),\n Router() {\n throw new Error(\n 'The Router app component should not be accessed by plugins',\n );\n },\n ErrorBoundaryFallback: ErrorBoundaryFallbackWrapper,\n };\n },\n };\n }, [appTreeApi, componentsApi, iconsApi]);\n\n return (\n <AppContextProvider appContext={appContext}>\n {props.children}\n </AppContextProvider>\n );\n}\n\nconst RoutingContext = createVersionedContext<{ 1: RouteResolver }>(\n 'routing-context',\n);\n\nfunction LegacyRoutingProvider(props: { children: ReactNode }) {\n const routeResolutionApi = useApi(routeResolutionApiRef);\n\n const value = useMemo<VersionedValue<{ 1: RouteResolver }>>(() => {\n return createVersionedValueMap({\n 1: {\n resolve(anyRouteRef, location) {\n const sourcePath =\n typeof location === 'string' ? location : location.pathname ?? '';\n\n return routeResolutionApi.resolve(\n // This removes the requirement to use convertLegacyRouteRef inside plugins, but\n // they still need to converted when passed to the plugin instance\n convertLegacyRouteRef(anyRouteRef as RouteRef),\n { sourcePath },\n );\n },\n },\n });\n }, [routeResolutionApi]);\n\n return (\n <RoutingContext.Provider value={value}>\n {props.children}\n </RoutingContext.Provider>\n );\n}\n\nexport function BackwardsCompatProvider(props: { children: ReactNode }) {\n return (\n <LegacyRoutingProvider>\n <LegacyAppContextProvider>{props.children}</LegacyAppContextProvider>\n </LegacyRoutingProvider>\n );\n}\n"],"names":["createNewPlugin"],"mappings":"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"}
@@ -1,7 +1,103 @@
1
- import React from 'react';
1
+ import { useApp } from '@backstage/core-plugin-api';
2
+ import { componentsApiRef, iconsApiRef, routeResolutionApiRef, coreComponentRefs } from '@backstage/frontend-plugin-api';
3
+ import React, { useMemo } from 'react';
4
+ import { toLegacyPlugin } from './BackwardsCompatProvider.esm.js';
5
+ import { ApiProvider } from '../core-app-api/src/apis/system/ApiProvider.esm.js';
6
+ import { useVersionedContext } from '@backstage/version-bridge';
7
+ import { convertLegacyRouteRef } from '../convertLegacyRouteRef.esm.js';
2
8
 
9
+ class CompatComponentsApi {
10
+ #Progress;
11
+ #NotFoundErrorPage;
12
+ #ErrorBoundaryFallback;
13
+ constructor(app) {
14
+ const components = app.getComponents();
15
+ const ErrorBoundaryFallback = (props) => /* @__PURE__ */ React.createElement(
16
+ components.ErrorBoundaryFallback,
17
+ {
18
+ ...props,
19
+ plugin: props.plugin && toLegacyPlugin(props.plugin)
20
+ }
21
+ );
22
+ this.#Progress = components.Progress;
23
+ this.#NotFoundErrorPage = components.NotFoundErrorPage;
24
+ this.#ErrorBoundaryFallback = ErrorBoundaryFallback;
25
+ }
26
+ getComponent(ref) {
27
+ switch (ref.id) {
28
+ case coreComponentRefs.progress.id:
29
+ return this.#Progress;
30
+ case coreComponentRefs.notFoundErrorPage.id:
31
+ return this.#NotFoundErrorPage;
32
+ case coreComponentRefs.errorBoundaryFallback.id:
33
+ return this.#ErrorBoundaryFallback;
34
+ default:
35
+ throw new Error(
36
+ `No backwards compatible component is available for ref '${ref.id}'`
37
+ );
38
+ }
39
+ }
40
+ }
41
+ class CompatIconsApi {
42
+ #app;
43
+ constructor(app) {
44
+ this.#app = app;
45
+ }
46
+ getIcon(key) {
47
+ return this.#app.getSystemIcon(key);
48
+ }
49
+ listIconKeys() {
50
+ return Object.keys(this.#app.getSystemIcons());
51
+ }
52
+ }
53
+ class CompatRouteResolutionApi {
54
+ #routeResolver;
55
+ constructor(routeResolver) {
56
+ this.#routeResolver = routeResolver;
57
+ }
58
+ resolve(anyRouteRef, options) {
59
+ const legacyRef = convertLegacyRouteRef(anyRouteRef);
60
+ return this.#routeResolver.resolve(legacyRef, options?.sourcePath ?? "/");
61
+ }
62
+ }
63
+ class ForwardsCompatApis {
64
+ #componentsApi;
65
+ #iconsApi;
66
+ #routeResolutionApi;
67
+ constructor(app, routeResolver) {
68
+ this.#componentsApi = new CompatComponentsApi(app);
69
+ this.#iconsApi = new CompatIconsApi(app);
70
+ this.#routeResolutionApi = new CompatRouteResolutionApi(routeResolver);
71
+ }
72
+ get(ref) {
73
+ if (ref.id === componentsApiRef.id) {
74
+ return this.#componentsApi;
75
+ } else if (ref.id === iconsApiRef.id) {
76
+ return this.#iconsApi;
77
+ } else if (ref.id === routeResolutionApiRef.id) {
78
+ return this.#routeResolutionApi;
79
+ }
80
+ return void 0;
81
+ }
82
+ }
83
+ function NewAppApisProvider(props) {
84
+ const app = useApp();
85
+ const versionedRouteResolverContext = useVersionedContext("routing-context");
86
+ if (!versionedRouteResolverContext) {
87
+ throw new Error("Routing context is not available");
88
+ }
89
+ const routeResolver = versionedRouteResolverContext.atVersion(1);
90
+ if (!routeResolver) {
91
+ throw new Error("RoutingContext v1 not available");
92
+ }
93
+ const appFallbackApis = useMemo(
94
+ () => new ForwardsCompatApis(app, routeResolver),
95
+ [app, routeResolver]
96
+ );
97
+ return /* @__PURE__ */ React.createElement(ApiProvider, { apis: appFallbackApis }, props.children);
98
+ }
3
99
  function ForwardsCompatProvider(props) {
4
- return /* @__PURE__ */ React.createElement(React.Fragment, null, props.children);
100
+ return /* @__PURE__ */ React.createElement(NewAppApisProvider, null, props.children);
5
101
  }
6
102
 
7
103
  export { ForwardsCompatProvider };
@@ -1 +1 @@
1
- {"version":3,"file":"ForwardsCompatProvider.esm.js","sources":["../../src/compatWrapper/ForwardsCompatProvider.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React from 'react';\nimport { ReactNode } from 'react';\n\nexport function ForwardsCompatProvider(props: { children: ReactNode }) {\n // TODO(Rugvip): Implement\n return <>{props.children}</>;\n}\n"],"names":[],"mappings":";;AAmBO,SAAS,uBAAuB,KAAgC,EAAA;AAErE,EAAO,uBAAA,KAAA,CAAA,aAAA,CAAA,KAAA,CAAA,QAAA,EAAA,IAAA,EAAG,MAAM,QAAS,CAAA,CAAA;AAC3B;;;;"}
1
+ {"version":3,"file":"ForwardsCompatProvider.esm.js","sources":["../../src/compatWrapper/ForwardsCompatProvider.tsx"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n ApiHolder,\n ApiRef,\n AppContext,\n useApp,\n} from '@backstage/core-plugin-api';\nimport {\n AnyRouteRefParams,\n ComponentRef,\n ComponentsApi,\n CoreErrorBoundaryFallbackProps,\n CoreNotFoundErrorPageProps,\n CoreProgressProps,\n ExternalRouteRef,\n IconComponent,\n IconsApi,\n RouteFunc,\n RouteRef,\n RouteResolutionApi,\n RouteResolutionApiResolveOptions,\n SubRouteRef,\n componentsApiRef,\n coreComponentRefs,\n iconsApiRef,\n routeResolutionApiRef,\n} from '@backstage/frontend-plugin-api';\nimport React, { ComponentType, useMemo } from 'react';\nimport { ReactNode } from 'react';\nimport { toLegacyPlugin } from './BackwardsCompatProvider';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { ApiProvider } from '../../../core-app-api/src/apis/system/ApiProvider';\nimport { useVersionedContext } from '@backstage/version-bridge';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { type RouteResolver } from '../../../core-plugin-api/src/routing/useRouteRef';\nimport { convertLegacyRouteRef } from '../convertLegacyRouteRef';\n\nclass CompatComponentsApi implements ComponentsApi {\n readonly #Progress: ComponentType<CoreProgressProps>;\n readonly #NotFoundErrorPage: ComponentType<CoreNotFoundErrorPageProps>;\n readonly #ErrorBoundaryFallback: ComponentType<CoreErrorBoundaryFallbackProps>;\n\n constructor(app: AppContext) {\n const components = app.getComponents();\n const ErrorBoundaryFallback = (props: CoreErrorBoundaryFallbackProps) => (\n <components.ErrorBoundaryFallback\n {...props}\n plugin={props.plugin && toLegacyPlugin(props.plugin)}\n />\n );\n this.#Progress = components.Progress;\n this.#NotFoundErrorPage = components.NotFoundErrorPage;\n this.#ErrorBoundaryFallback = ErrorBoundaryFallback;\n }\n\n getComponent<T extends {}>(ref: ComponentRef<T>): ComponentType<T> {\n switch (ref.id) {\n case coreComponentRefs.progress.id:\n return this.#Progress as ComponentType<any>;\n case coreComponentRefs.notFoundErrorPage.id:\n return this.#NotFoundErrorPage as ComponentType<any>;\n case coreComponentRefs.errorBoundaryFallback.id:\n return this.#ErrorBoundaryFallback as ComponentType<any>;\n default:\n throw new Error(\n `No backwards compatible component is available for ref '${ref.id}'`,\n );\n }\n }\n}\n\nclass CompatIconsApi implements IconsApi {\n readonly #app: AppContext;\n\n constructor(app: AppContext) {\n this.#app = app;\n }\n\n getIcon(key: string): IconComponent | undefined {\n return this.#app.getSystemIcon(key);\n }\n\n listIconKeys(): string[] {\n return Object.keys(this.#app.getSystemIcons());\n }\n}\n\nclass CompatRouteResolutionApi implements RouteResolutionApi {\n readonly #routeResolver: RouteResolver;\n\n constructor(routeResolver: RouteResolver) {\n this.#routeResolver = routeResolver;\n }\n\n resolve<TParams extends AnyRouteRefParams>(\n anyRouteRef:\n | RouteRef<TParams>\n | SubRouteRef<TParams>\n | ExternalRouteRef<TParams>,\n options?: RouteResolutionApiResolveOptions | undefined,\n ): RouteFunc<TParams> | undefined {\n const legacyRef = convertLegacyRouteRef(anyRouteRef as RouteRef<TParams>);\n return this.#routeResolver.resolve(legacyRef, options?.sourcePath ?? '/');\n }\n}\n\nclass ForwardsCompatApis implements ApiHolder {\n readonly #componentsApi: ComponentsApi;\n readonly #iconsApi: IconsApi;\n readonly #routeResolutionApi: RouteResolutionApi;\n\n constructor(app: AppContext, routeResolver: RouteResolver) {\n this.#componentsApi = new CompatComponentsApi(app);\n this.#iconsApi = new CompatIconsApi(app);\n this.#routeResolutionApi = new CompatRouteResolutionApi(routeResolver);\n }\n\n get<T>(ref: ApiRef<any>): T | undefined {\n if (ref.id === componentsApiRef.id) {\n return this.#componentsApi as T;\n } else if (ref.id === iconsApiRef.id) {\n return this.#iconsApi as T;\n } else if (ref.id === routeResolutionApiRef.id) {\n return this.#routeResolutionApi as T;\n }\n return undefined;\n }\n}\n\nfunction NewAppApisProvider(props: { children: ReactNode }) {\n const app = useApp();\n const versionedRouteResolverContext = useVersionedContext<{\n 1: RouteResolver;\n }>('routing-context');\n if (!versionedRouteResolverContext) {\n throw new Error('Routing context is not available');\n }\n const routeResolver = versionedRouteResolverContext.atVersion(1);\n if (!routeResolver) {\n throw new Error('RoutingContext v1 not available');\n }\n\n const appFallbackApis = useMemo(\n () => new ForwardsCompatApis(app, routeResolver),\n [app, routeResolver],\n );\n\n return <ApiProvider apis={appFallbackApis}>{props.children}</ApiProvider>;\n}\n\nexport function ForwardsCompatProvider(props: { children: ReactNode }) {\n return <NewAppApisProvider>{props.children}</NewAppApisProvider>;\n}\n"],"names":[],"mappings":"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"}
@@ -13,10 +13,49 @@ function convertLegacyRouteRefs(refs) {
13
13
  );
14
14
  }
15
15
  function convertLegacyRouteRef(ref) {
16
- if ("$$type" in ref) {
16
+ const isNew = "$$type" in ref;
17
+ const oldType = ref[routeRefType];
18
+ if (isNew && oldType) {
17
19
  return ref;
18
20
  }
19
- const type = ref[routeRefType];
21
+ if (isNew) {
22
+ return convertNewToOld(
23
+ ref
24
+ );
25
+ }
26
+ return convertOldToNew(ref, oldType);
27
+ }
28
+ function convertNewToOld(ref) {
29
+ if (ref.$$type === "@backstage/RouteRef") {
30
+ const newRef = toInternalRouteRef(ref);
31
+ return Object.assign(ref, {
32
+ [routeRefType]: "absolute",
33
+ params: newRef.getParams(),
34
+ title: newRef.getDescription()
35
+ });
36
+ }
37
+ if (ref.$$type === "@backstage/SubRouteRef") {
38
+ const newRef = toInternalSubRouteRef(ref);
39
+ return Object.assign(ref, {
40
+ [routeRefType]: "sub",
41
+ parent: convertLegacyRouteRef(newRef.getParent()),
42
+ params: newRef.getParams()
43
+ });
44
+ }
45
+ if (ref.$$type === "@backstage/ExternalRouteRef") {
46
+ const newRef = toInternalExternalRouteRef(ref);
47
+ return Object.assign(ref, {
48
+ [routeRefType]: "external",
49
+ optional: true,
50
+ params: newRef.getParams(),
51
+ defaultTarget: newRef.getDefaultTarget()
52
+ });
53
+ }
54
+ throw new Error(
55
+ `Failed to convert route ref, unknown type '${ref.$$type}'`
56
+ );
57
+ }
58
+ function convertOldToNew(ref, type) {
20
59
  if (type === "absolute") {
21
60
  const legacyRef = ref;
22
61
  const legacyRefStr = String(legacyRef);
@@ -76,7 +115,6 @@ function convertLegacyRouteRef(ref) {
76
115
  const newRef = toInternalExternalRouteRef(
77
116
  createExternalRouteRef({
78
117
  params: legacyRef.params,
79
- optional: legacyRef.optional,
80
118
  defaultTarget: "getDefaultTarget" in legacyRef ? legacyRef.getDefaultTarget() : void 0
81
119
  })
82
120
  );
@@ -84,7 +122,6 @@ function convertLegacyRouteRef(ref) {
84
122
  $$type: "@backstage/ExternalRouteRef",
85
123
  version: "v1",
86
124
  T: newRef.T,
87
- optional: newRef.optional,
88
125
  getParams() {
89
126
  return newRef.getParams();
90
127
  },
@@ -1 +1 @@
1
- {"version":3,"file":"convertLegacyRouteRef.esm.js","sources":["../src/convertLegacyRouteRef.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n RouteRef as LegacyRouteRef,\n SubRouteRef as LegacySubRouteRef,\n ExternalRouteRef as LegacyExternalRouteRef,\n AnyRouteRefParams,\n} from '@backstage/core-plugin-api';\n\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { routeRefType } from '../../core-plugin-api/src/routing/types';\n\nimport {\n RouteRef,\n SubRouteRef,\n ExternalRouteRef,\n createRouteRef,\n createSubRouteRef,\n createExternalRouteRef,\n} from '@backstage/frontend-plugin-api';\n\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { toInternalRouteRef } from '../../frontend-plugin-api/src/routing/RouteRef';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { toInternalSubRouteRef } from '../../frontend-plugin-api/src/routing/SubRouteRef';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { toInternalExternalRouteRef } from '../../frontend-plugin-api/src/routing/ExternalRouteRef';\n\n/**\n * Converts a legacy route ref type to the new system.\n *\n * @public\n */\nexport type ToNewRouteRef<\n T extends LegacyRouteRef | LegacySubRouteRef | LegacyExternalRouteRef,\n> = T extends LegacyRouteRef<infer IParams>\n ? RouteRef<IParams>\n : T extends LegacySubRouteRef<infer IParams>\n ? SubRouteRef<IParams>\n : T extends LegacyExternalRouteRef<infer IParams, infer IOptional>\n ? ExternalRouteRef<IParams, IOptional>\n : never;\n\n/**\n * Converts a collection of legacy route refs to the new system.\n * This is particularly useful when defining plugin `routes` and `externalRoutes`.\n *\n * @public\n */\nexport function convertLegacyRouteRefs<\n TRefs extends {\n [name in string]:\n | LegacyRouteRef\n | LegacySubRouteRef\n | LegacyExternalRouteRef;\n },\n>(refs: TRefs): { [KName in keyof TRefs]: ToNewRouteRef<TRefs[KName]> } {\n return Object.fromEntries(\n Object.entries(refs).map(([name, ref]) => [\n name,\n convertLegacyRouteRef(ref as LegacyRouteRef),\n ]),\n ) as { [KName in keyof TRefs]: ToNewRouteRef<TRefs[KName]> };\n}\n\n/**\n * A temporary helper to convert a legacy route ref to the new system.\n *\n * @public\n * @remarks\n *\n * In the future the legacy createRouteRef will instead create refs compatible with both systems.\n */\nexport function convertLegacyRouteRef<TParams extends AnyRouteRefParams>(\n ref: LegacyRouteRef<TParams>,\n): RouteRef<TParams>;\n\n/**\n * A temporary helper to convert a legacy sub route ref to the new system.\n *\n * @public\n * @remarks\n *\n * In the future the legacy createSubRouteRef will instead create refs compatible with both systems.\n */\nexport function convertLegacyRouteRef<TParams extends AnyRouteRefParams>(\n ref: LegacySubRouteRef<TParams>,\n): SubRouteRef<TParams>;\n\n/**\n * A temporary helper to convert a legacy external route ref to the new system.\n *\n * @public\n * @remarks\n *\n * In the future the legacy createExternalRouteRef will instead create refs compatible with both systems.\n */\nexport function convertLegacyRouteRef<\n TParams extends AnyRouteRefParams,\n TOptional extends boolean,\n>(\n ref: LegacyExternalRouteRef<TParams, TOptional>,\n): ExternalRouteRef<TParams, TOptional>;\n\nexport function convertLegacyRouteRef(\n ref: LegacyRouteRef | LegacySubRouteRef | LegacyExternalRouteRef,\n): RouteRef | SubRouteRef | ExternalRouteRef {\n // Ref has already been converted\n if ('$$type' in ref) {\n return ref as unknown as RouteRef | SubRouteRef | ExternalRouteRef;\n }\n\n const type = (ref as unknown as { [routeRefType]: unknown })[routeRefType];\n\n if (type === 'absolute') {\n const legacyRef = ref as LegacyRouteRef;\n const legacyRefStr = String(legacyRef);\n const newRef = toInternalRouteRef(\n createRouteRef<{ [key in string]: string }>({\n params: legacyRef.params as string[],\n }),\n );\n return Object.assign(legacyRef, {\n $$type: '@backstage/RouteRef' as const,\n version: 'v1',\n T: newRef.T,\n getParams() {\n return newRef.getParams();\n },\n getDescription() {\n return legacyRefStr;\n },\n setId(id: string) {\n newRef.setId(id);\n },\n toString() {\n return legacyRefStr;\n },\n });\n }\n if (type === 'sub') {\n const legacyRef = ref as LegacySubRouteRef;\n const legacyRefStr = String(legacyRef);\n const newRef = toInternalSubRouteRef(\n createSubRouteRef({\n path: legacyRef.path,\n parent: convertLegacyRouteRef(legacyRef.parent),\n }),\n );\n return Object.assign(legacyRef, {\n $$type: '@backstage/SubRouteRef' as const,\n version: 'v1',\n T: newRef.T,\n getParams() {\n return newRef.getParams();\n },\n getParent() {\n return newRef.getParent();\n },\n getDescription() {\n return legacyRefStr;\n },\n toString() {\n return legacyRefStr;\n },\n });\n }\n if (type === 'external') {\n const legacyRef = ref as LegacyExternalRouteRef;\n const legacyRefStr = String(legacyRef);\n const newRef = toInternalExternalRouteRef(\n createExternalRouteRef<{ [key in string]: string }>({\n params: legacyRef.params as string[],\n optional: legacyRef.optional,\n defaultTarget:\n 'getDefaultTarget' in legacyRef\n ? (legacyRef.getDefaultTarget as () => string | undefined)()\n : undefined,\n }),\n );\n return Object.assign(legacyRef, {\n $$type: '@backstage/ExternalRouteRef' as const,\n version: 'v1',\n T: newRef.T,\n optional: newRef.optional,\n getParams() {\n return newRef.getParams();\n },\n getDescription() {\n return legacyRefStr;\n },\n // This might already be implemented in the legacy ref, but we override it just to be sure\n getDefaultTarget() {\n return newRef.getDefaultTarget();\n },\n setId(id: string) {\n newRef.setId(id);\n },\n toString() {\n return legacyRefStr;\n },\n });\n }\n\n throw new Error(`Failed to convert legacy route ref, unknown type '${type}'`);\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"convertLegacyRouteRef.esm.js","sources":["../src/convertLegacyRouteRef.ts"],"sourcesContent":["/*\n * Copyright 2023 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n RouteRef as LegacyRouteRef,\n SubRouteRef as LegacySubRouteRef,\n ExternalRouteRef as LegacyExternalRouteRef,\n AnyRouteRefParams,\n} from '@backstage/core-plugin-api';\n\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { routeRefType } from '../../core-plugin-api/src/routing/types';\n\nimport {\n RouteRef,\n SubRouteRef,\n ExternalRouteRef,\n createRouteRef,\n createSubRouteRef,\n createExternalRouteRef,\n} from '@backstage/frontend-plugin-api';\n\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { toInternalRouteRef } from '../../frontend-plugin-api/src/routing/RouteRef';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { toInternalSubRouteRef } from '../../frontend-plugin-api/src/routing/SubRouteRef';\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport { toInternalExternalRouteRef } from '../../frontend-plugin-api/src/routing/ExternalRouteRef';\n\n/**\n * Converts a legacy route ref type to the new system.\n *\n * @public\n */\nexport type ToNewRouteRef<\n T extends LegacyRouteRef | LegacySubRouteRef | LegacyExternalRouteRef,\n> = T extends LegacyRouteRef<infer IParams>\n ? RouteRef<IParams>\n : T extends LegacySubRouteRef<infer IParams>\n ? SubRouteRef<IParams>\n : T extends LegacyExternalRouteRef<infer IParams>\n ? ExternalRouteRef<IParams>\n : never;\n\n/**\n * Converts a collection of legacy route refs to the new system.\n * This is particularly useful when defining plugin `routes` and `externalRoutes`.\n *\n * @public\n */\nexport function convertLegacyRouteRefs<\n TRefs extends {\n [name in string]:\n | LegacyRouteRef\n | LegacySubRouteRef\n | LegacyExternalRouteRef;\n },\n>(refs: TRefs): { [KName in keyof TRefs]: ToNewRouteRef<TRefs[KName]> } {\n return Object.fromEntries(\n Object.entries(refs).map(([name, ref]) => [\n name,\n convertLegacyRouteRef(ref as LegacyRouteRef),\n ]),\n ) as { [KName in keyof TRefs]: ToNewRouteRef<TRefs[KName]> };\n}\n\n/**\n * A temporary helper to convert a legacy route ref to the new system.\n *\n * @public\n * @remarks\n *\n * In the future the legacy createRouteRef will instead create refs compatible with both systems.\n */\nexport function convertLegacyRouteRef<TParams extends AnyRouteRefParams>(\n ref: LegacyRouteRef<TParams>,\n): RouteRef<TParams>;\n\n/**\n * A temporary helper to convert a legacy sub route ref to the new system.\n *\n * @public\n * @remarks\n *\n * In the future the legacy createSubRouteRef will instead create refs compatible with both systems.\n */\nexport function convertLegacyRouteRef<TParams extends AnyRouteRefParams>(\n ref: LegacySubRouteRef<TParams>,\n): SubRouteRef<TParams>;\n\n/**\n * A temporary helper to convert a legacy external route ref to the new system.\n *\n * @public\n * @remarks\n *\n * In the future the legacy createExternalRouteRef will instead create refs compatible with both systems.\n */\nexport function convertLegacyRouteRef<TParams extends AnyRouteRefParams>(\n ref: LegacyExternalRouteRef<TParams>,\n): ExternalRouteRef<TParams>;\n\n/**\n * A temporary helper to convert a new route ref to the legacy system.\n *\n * @public\n * @remarks\n *\n * In the future the legacy createRouteRef will instead create refs compatible with both systems.\n */\nexport function convertLegacyRouteRef<TParams extends AnyRouteRefParams>(\n ref: RouteRef<TParams>,\n): LegacyRouteRef<TParams>;\n\n/**\n * A temporary helper to convert a new sub route ref to the legacy system.\n *\n * @public\n * @remarks\n *\n * In the future the legacy createSubRouteRef will instead create refs compatible with both systems.\n */\nexport function convertLegacyRouteRef<TParams extends AnyRouteRefParams>(\n ref: SubRouteRef<TParams>,\n): LegacySubRouteRef<TParams>;\n\n/**\n * A temporary helper to convert a new external route ref to the legacy system.\n *\n * @public\n * @remarks\n *\n * In the future the legacy createExternalRouteRef will instead create refs compatible with both systems.\n */\nexport function convertLegacyRouteRef<TParams extends AnyRouteRefParams>(\n ref: ExternalRouteRef<TParams>,\n): LegacyExternalRouteRef<TParams, true>;\nexport function convertLegacyRouteRef(\n ref:\n | LegacyRouteRef\n | LegacySubRouteRef\n | LegacyExternalRouteRef\n | RouteRef\n | SubRouteRef\n | ExternalRouteRef,\n):\n | RouteRef\n | SubRouteRef\n | ExternalRouteRef\n | LegacyRouteRef\n | LegacySubRouteRef\n | LegacyExternalRouteRef {\n const isNew = '$$type' in ref;\n const oldType = (ref as unknown as { [routeRefType]: unknown })[routeRefType];\n\n // Ref has already been converted\n if (isNew && oldType) {\n return ref as any;\n }\n\n if (isNew) {\n return convertNewToOld(\n ref as unknown as RouteRef | SubRouteRef | ExternalRouteRef,\n );\n }\n\n return convertOldToNew(ref, oldType);\n}\n\nfunction convertNewToOld(\n ref: RouteRef | SubRouteRef | ExternalRouteRef,\n): LegacyRouteRef | LegacySubRouteRef | LegacyExternalRouteRef {\n if (ref.$$type === '@backstage/RouteRef') {\n const newRef = toInternalRouteRef(ref);\n return Object.assign(ref, {\n [routeRefType]: 'absolute',\n params: newRef.getParams(),\n title: newRef.getDescription(),\n } as Omit<LegacyRouteRef, '$$routeRefType'>) as unknown as LegacyRouteRef;\n }\n if (ref.$$type === '@backstage/SubRouteRef') {\n const newRef = toInternalSubRouteRef(ref);\n return Object.assign(ref, {\n [routeRefType]: 'sub',\n parent: convertLegacyRouteRef(newRef.getParent()),\n params: newRef.getParams(),\n } as Omit<LegacySubRouteRef, '$$routeRefType' | 'path'>) as unknown as LegacySubRouteRef;\n }\n if (ref.$$type === '@backstage/ExternalRouteRef') {\n const newRef = toInternalExternalRouteRef(ref);\n return Object.assign(ref, {\n [routeRefType]: 'external',\n optional: true,\n params: newRef.getParams(),\n defaultTarget: newRef.getDefaultTarget(),\n } as Omit<LegacyExternalRouteRef, '$$routeRefType' | 'optional'>) as unknown as LegacyExternalRouteRef;\n }\n\n throw new Error(\n `Failed to convert route ref, unknown type '${(ref as any).$$type}'`,\n );\n}\n\nfunction convertOldToNew(\n ref: LegacyRouteRef | LegacySubRouteRef | LegacyExternalRouteRef,\n type: unknown,\n): RouteRef | SubRouteRef | ExternalRouteRef {\n if (type === 'absolute') {\n const legacyRef = ref as LegacyRouteRef;\n const legacyRefStr = String(legacyRef);\n const newRef = toInternalRouteRef(\n createRouteRef<{ [key in string]: string }>({\n params: legacyRef.params as string[],\n }),\n );\n return Object.assign(legacyRef, {\n $$type: '@backstage/RouteRef' as const,\n version: 'v1',\n T: newRef.T,\n getParams() {\n return newRef.getParams();\n },\n getDescription() {\n return legacyRefStr;\n },\n setId(id: string) {\n newRef.setId(id);\n },\n toString() {\n return legacyRefStr;\n },\n });\n }\n if (type === 'sub') {\n const legacyRef = ref as LegacySubRouteRef;\n const legacyRefStr = String(legacyRef);\n const newRef = toInternalSubRouteRef(\n createSubRouteRef({\n path: legacyRef.path,\n parent: convertLegacyRouteRef(legacyRef.parent),\n }),\n );\n return Object.assign(legacyRef, {\n $$type: '@backstage/SubRouteRef' as const,\n version: 'v1',\n T: newRef.T,\n getParams() {\n return newRef.getParams();\n },\n getParent() {\n return newRef.getParent();\n },\n getDescription() {\n return legacyRefStr;\n },\n toString() {\n return legacyRefStr;\n },\n });\n }\n if (type === 'external') {\n const legacyRef = ref as LegacyExternalRouteRef;\n const legacyRefStr = String(legacyRef);\n const newRef = toInternalExternalRouteRef(\n createExternalRouteRef<{ [key in string]: string }>({\n params: legacyRef.params as string[],\n defaultTarget:\n 'getDefaultTarget' in legacyRef\n ? (legacyRef.getDefaultTarget as () => string | undefined)()\n : undefined,\n }),\n );\n return Object.assign(legacyRef, {\n $$type: '@backstage/ExternalRouteRef' as const,\n version: 'v1',\n T: newRef.T,\n getParams() {\n return newRef.getParams();\n },\n getDescription() {\n return legacyRefStr;\n },\n // This might already be implemented in the legacy ref, but we override it just to be sure\n getDefaultTarget() {\n return newRef.getDefaultTarget();\n },\n setId(id: string) {\n newRef.setId(id);\n },\n toString() {\n return legacyRefStr;\n },\n });\n }\n\n throw new Error(`Failed to convert legacy route ref, unknown type '${type}'`);\n}\n"],"names":[],"mappings":";;;;;;AA+DO,SAAS,uBAOd,IAAsE,EAAA;AACtE,EAAA,OAAO,MAAO,CAAA,WAAA;AAAA,IACZ,MAAA,CAAO,QAAQ,IAAI,CAAA,CAAE,IAAI,CAAC,CAAC,IAAM,EAAA,GAAG,CAAM,KAAA;AAAA,MACxC,IAAA;AAAA,MACA,sBAAsB,GAAqB,CAAA;AAAA,KAC5C,CAAA;AAAA,GACH,CAAA;AACF,CAAA;AAyEO,SAAS,sBACd,GAayB,EAAA;AACzB,EAAA,MAAM,QAAQ,QAAY,IAAA,GAAA,CAAA;AAC1B,EAAM,MAAA,OAAA,GAAW,IAA+C,YAAY,CAAA,CAAA;AAG5E,EAAA,IAAI,SAAS,OAAS,EAAA;AACpB,IAAO,OAAA,GAAA,CAAA;AAAA,GACT;AAEA,EAAA,IAAI,KAAO,EAAA;AACT,IAAO,OAAA,eAAA;AAAA,MACL,GAAA;AAAA,KACF,CAAA;AAAA,GACF;AAEA,EAAO,OAAA,eAAA,CAAgB,KAAK,OAAO,CAAA,CAAA;AACrC,CAAA;AAEA,SAAS,gBACP,GAC6D,EAAA;AAC7D,EAAI,IAAA,GAAA,CAAI,WAAW,qBAAuB,EAAA;AACxC,IAAM,MAAA,MAAA,GAAS,mBAAmB,GAAG,CAAA,CAAA;AACrC,IAAO,OAAA,MAAA,CAAO,OAAO,GAAK,EAAA;AAAA,MACxB,CAAC,YAAY,GAAG,UAAA;AAAA,MAChB,MAAA,EAAQ,OAAO,SAAU,EAAA;AAAA,MACzB,KAAA,EAAO,OAAO,cAAe,EAAA;AAAA,KACY,CAAA,CAAA;AAAA,GAC7C;AACA,EAAI,IAAA,GAAA,CAAI,WAAW,wBAA0B,EAAA;AAC3C,IAAM,MAAA,MAAA,GAAS,sBAAsB,GAAG,CAAA,CAAA;AACxC,IAAO,OAAA,MAAA,CAAO,OAAO,GAAK,EAAA;AAAA,MACxB,CAAC,YAAY,GAAG,KAAA;AAAA,MAChB,MAAQ,EAAA,qBAAA,CAAsB,MAAO,CAAA,SAAA,EAAW,CAAA;AAAA,MAChD,MAAA,EAAQ,OAAO,SAAU,EAAA;AAAA,KAC4B,CAAA,CAAA;AAAA,GACzD;AACA,EAAI,IAAA,GAAA,CAAI,WAAW,6BAA+B,EAAA;AAChD,IAAM,MAAA,MAAA,GAAS,2BAA2B,GAAG,CAAA,CAAA;AAC7C,IAAO,OAAA,MAAA,CAAO,OAAO,GAAK,EAAA;AAAA,MACxB,CAAC,YAAY,GAAG,UAAA;AAAA,MAChB,QAAU,EAAA,IAAA;AAAA,MACV,MAAA,EAAQ,OAAO,SAAU,EAAA;AAAA,MACzB,aAAA,EAAe,OAAO,gBAAiB,EAAA;AAAA,KACuB,CAAA,CAAA;AAAA,GAClE;AAEA,EAAA,MAAM,IAAI,KAAA;AAAA,IACR,CAAA,2CAAA,EAA+C,IAAY,MAAM,CAAA,CAAA,CAAA;AAAA,GACnE,CAAA;AACF,CAAA;AAEA,SAAS,eAAA,CACP,KACA,IAC2C,EAAA;AAC3C,EAAA,IAAI,SAAS,UAAY,EAAA;AACvB,IAAA,MAAM,SAAY,GAAA,GAAA,CAAA;AAClB,IAAM,MAAA,YAAA,GAAe,OAAO,SAAS,CAAA,CAAA;AACrC,IAAA,MAAM,MAAS,GAAA,kBAAA;AAAA,MACb,cAA4C,CAAA;AAAA,QAC1C,QAAQ,SAAU,CAAA,MAAA;AAAA,OACnB,CAAA;AAAA,KACH,CAAA;AACA,IAAO,OAAA,MAAA,CAAO,OAAO,SAAW,EAAA;AAAA,MAC9B,MAAQ,EAAA,qBAAA;AAAA,MACR,OAAS,EAAA,IAAA;AAAA,MACT,GAAG,MAAO,CAAA,CAAA;AAAA,MACV,SAAY,GAAA;AACV,QAAA,OAAO,OAAO,SAAU,EAAA,CAAA;AAAA,OAC1B;AAAA,MACA,cAAiB,GAAA;AACf,QAAO,OAAA,YAAA,CAAA;AAAA,OACT;AAAA,MACA,MAAM,EAAY,EAAA;AAChB,QAAA,MAAA,CAAO,MAAM,EAAE,CAAA,CAAA;AAAA,OACjB;AAAA,MACA,QAAW,GAAA;AACT,QAAO,OAAA,YAAA,CAAA;AAAA,OACT;AAAA,KACD,CAAA,CAAA;AAAA,GACH;AACA,EAAA,IAAI,SAAS,KAAO,EAAA;AAClB,IAAA,MAAM,SAAY,GAAA,GAAA,CAAA;AAClB,IAAM,MAAA,YAAA,GAAe,OAAO,SAAS,CAAA,CAAA;AACrC,IAAA,MAAM,MAAS,GAAA,qBAAA;AAAA,MACb,iBAAkB,CAAA;AAAA,QAChB,MAAM,SAAU,CAAA,IAAA;AAAA,QAChB,MAAA,EAAQ,qBAAsB,CAAA,SAAA,CAAU,MAAM,CAAA;AAAA,OAC/C,CAAA;AAAA,KACH,CAAA;AACA,IAAO,OAAA,MAAA,CAAO,OAAO,SAAW,EAAA;AAAA,MAC9B,MAAQ,EAAA,wBAAA;AAAA,MACR,OAAS,EAAA,IAAA;AAAA,MACT,GAAG,MAAO,CAAA,CAAA;AAAA,MACV,SAAY,GAAA;AACV,QAAA,OAAO,OAAO,SAAU,EAAA,CAAA;AAAA,OAC1B;AAAA,MACA,SAAY,GAAA;AACV,QAAA,OAAO,OAAO,SAAU,EAAA,CAAA;AAAA,OAC1B;AAAA,MACA,cAAiB,GAAA;AACf,QAAO,OAAA,YAAA,CAAA;AAAA,OACT;AAAA,MACA,QAAW,GAAA;AACT,QAAO,OAAA,YAAA,CAAA;AAAA,OACT;AAAA,KACD,CAAA,CAAA;AAAA,GACH;AACA,EAAA,IAAI,SAAS,UAAY,EAAA;AACvB,IAAA,MAAM,SAAY,GAAA,GAAA,CAAA;AAClB,IAAM,MAAA,YAAA,GAAe,OAAO,SAAS,CAAA,CAAA;AACrC,IAAA,MAAM,MAAS,GAAA,0BAAA;AAAA,MACb,sBAAoD,CAAA;AAAA,QAClD,QAAQ,SAAU,CAAA,MAAA;AAAA,QAClB,aACE,EAAA,kBAAA,IAAsB,SACjB,GAAA,SAAA,CAAU,kBACX,GAAA,KAAA,CAAA;AAAA,OACP,CAAA;AAAA,KACH,CAAA;AACA,IAAO,OAAA,MAAA,CAAO,OAAO,SAAW,EAAA;AAAA,MAC9B,MAAQ,EAAA,6BAAA;AAAA,MACR,OAAS,EAAA,IAAA;AAAA,MACT,GAAG,MAAO,CAAA,CAAA;AAAA,MACV,SAAY,GAAA;AACV,QAAA,OAAO,OAAO,SAAU,EAAA,CAAA;AAAA,OAC1B;AAAA,MACA,cAAiB,GAAA;AACf,QAAO,OAAA,YAAA,CAAA;AAAA,OACT;AAAA;AAAA,MAEA,gBAAmB,GAAA;AACjB,QAAA,OAAO,OAAO,gBAAiB,EAAA,CAAA;AAAA,OACjC;AAAA,MACA,MAAM,EAAY,EAAA;AAChB,QAAA,MAAA,CAAO,MAAM,EAAE,CAAA,CAAA;AAAA,OACjB;AAAA,MACA,QAAW,GAAA;AACT,QAAO,OAAA,YAAA,CAAA;AAAA,OACT;AAAA,KACD,CAAA,CAAA;AAAA,GACH;AAEA,EAAA,MAAM,IAAI,KAAA,CAAM,CAAqD,kDAAA,EAAA,IAAI,CAAG,CAAA,CAAA,CAAA,CAAA;AAC9E;;;;"}
@@ -0,0 +1,18 @@
1
+ class ApiAggregator {
2
+ holders;
3
+ constructor(...holders) {
4
+ this.holders = holders;
5
+ }
6
+ get(apiRef) {
7
+ for (const holder of this.holders) {
8
+ const api = holder.get(apiRef);
9
+ if (api) {
10
+ return api;
11
+ }
12
+ }
13
+ return void 0;
14
+ }
15
+ }
16
+
17
+ export { ApiAggregator };
18
+ //# sourceMappingURL=ApiAggregator.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ApiAggregator.esm.js","sources":["../../../../../../core-app-api/src/apis/system/ApiAggregator.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ApiRef, ApiHolder } from '@backstage/core-plugin-api';\n\n/**\n * An ApiHolder that queries multiple other holders from for\n * an Api implementation, returning the first one encountered..\n */\nexport class ApiAggregator implements ApiHolder {\n private readonly holders: ApiHolder[];\n\n constructor(...holders: ApiHolder[]) {\n this.holders = holders;\n }\n\n get<T>(apiRef: ApiRef<T>): T | undefined {\n for (const holder of this.holders) {\n const api = holder.get(apiRef);\n if (api) {\n return api;\n }\n }\n return undefined;\n }\n}\n"],"names":[],"mappings":"AAsBO,MAAM,aAAmC,CAAA;AAAA,EAC7B,OAAA,CAAA;AAAA,EAEjB,eAAe,OAAsB,EAAA;AACnC,IAAA,IAAA,CAAK,OAAU,GAAA,OAAA,CAAA;AAAA,GACjB;AAAA,EAEA,IAAO,MAAkC,EAAA;AACvC,IAAW,KAAA,MAAA,MAAA,IAAU,KAAK,OAAS,EAAA;AACjC,MAAM,MAAA,GAAA,GAAM,MAAO,CAAA,GAAA,CAAI,MAAM,CAAA,CAAA;AAC7B,MAAA,IAAI,GAAK,EAAA;AACP,QAAO,OAAA,GAAA,CAAA;AAAA,OACT;AAAA,KACF;AACA,IAAO,OAAA,KAAA,CAAA,CAAA;AAAA,GACT;AACF;;;;"}
@@ -0,0 +1,25 @@
1
+ import React, { useContext } from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { ApiAggregator } from './ApiAggregator.esm.js';
4
+ import { createVersionedContext, createVersionedValueMap } from '@backstage/version-bridge';
5
+
6
+ const ApiContext = createVersionedContext("api-context");
7
+ const ApiProvider = (props) => {
8
+ const { apis, children } = props;
9
+ const parentHolder = useContext(ApiContext)?.atVersion(1);
10
+ const holder = parentHolder ? new ApiAggregator(apis, parentHolder) : apis;
11
+ return /* @__PURE__ */ React.createElement(
12
+ ApiContext.Provider,
13
+ {
14
+ value: createVersionedValueMap({ 1: holder }),
15
+ children
16
+ }
17
+ );
18
+ };
19
+ ApiProvider.propTypes = {
20
+ apis: PropTypes.shape({ get: PropTypes.func.isRequired }).isRequired,
21
+ children: PropTypes.node
22
+ };
23
+
24
+ export { ApiProvider };
25
+ //# sourceMappingURL=ApiProvider.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ApiProvider.esm.js","sources":["../../../../../../core-app-api/src/apis/system/ApiProvider.tsx"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport React, { useContext, ReactNode, PropsWithChildren } from 'react';\nimport PropTypes from 'prop-types';\nimport { ApiHolder } from '@backstage/core-plugin-api';\nimport { ApiAggregator } from './ApiAggregator';\nimport {\n createVersionedValueMap,\n createVersionedContext,\n} from '@backstage/version-bridge';\n\n/**\n * Prop types for the ApiProvider component.\n * @public\n */\nexport type ApiProviderProps = {\n apis: ApiHolder;\n children: ReactNode;\n};\n\nconst ApiContext = createVersionedContext<{ 1: ApiHolder }>('api-context');\n\n/**\n * Provides an {@link @backstage/core-plugin-api#ApiHolder} for consumption in\n * the React tree.\n *\n * @public\n */\nexport const ApiProvider = (props: PropsWithChildren<ApiProviderProps>) => {\n const { apis, children } = props;\n const parentHolder = useContext(ApiContext)?.atVersion(1);\n const holder = parentHolder ? new ApiAggregator(apis, parentHolder) : apis;\n\n return (\n <ApiContext.Provider\n value={createVersionedValueMap({ 1: holder })}\n children={children}\n />\n );\n};\n\nApiProvider.propTypes = {\n apis: PropTypes.shape({ get: PropTypes.func.isRequired }).isRequired,\n children: PropTypes.node,\n};\n"],"names":[],"mappings":";;;;;AAkCA,MAAM,UAAA,GAAa,uBAAyC,aAAa,CAAA,CAAA;AAQ5D,MAAA,WAAA,GAAc,CAAC,KAA+C,KAAA;AACzE,EAAM,MAAA,EAAE,IAAM,EAAA,QAAA,EAAa,GAAA,KAAA,CAAA;AAC3B,EAAA,MAAM,YAAe,GAAA,UAAA,CAAW,UAAU,CAAA,EAAG,UAAU,CAAC,CAAA,CAAA;AACxD,EAAA,MAAM,SAAS,YAAe,GAAA,IAAI,aAAc,CAAA,IAAA,EAAM,YAAY,CAAI,GAAA,IAAA,CAAA;AAEtE,EACE,uBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,UAAW,CAAA,QAAA;AAAA,IAAX;AAAA,MACC,KAAO,EAAA,uBAAA,CAAwB,EAAE,CAAA,EAAG,QAAQ,CAAA;AAAA,MAC5C,QAAA;AAAA,KAAA;AAAA,GACF,CAAA;AAEJ,EAAA;AAEA,WAAA,CAAY,SAAY,GAAA;AAAA,EACtB,IAAA,EAAM,UAAU,KAAM,CAAA,EAAE,KAAK,SAAU,CAAA,IAAA,CAAK,UAAW,EAAC,CAAE,CAAA,UAAA;AAAA,EAC1D,UAAU,SAAU,CAAA,IAAA;AACtB,CAAA;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"ExternalRouteRef.esm.js","sources":["../../../../../frontend-plugin-api/src/routing/ExternalRouteRef.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { RouteRefImpl } from './RouteRef';\nimport { describeParentCallSite } from './describeParentCallSite';\nimport { AnyRouteRefParams } from './types';\n\n/**\n * Route descriptor, to be later bound to a concrete route by the app. Used to implement cross-plugin route references.\n *\n * @remarks\n *\n * See {@link https://backstage.io/docs/plugins/composability#routing-system}.\n *\n * @public\n */\nexport interface ExternalRouteRef<\n TParams extends AnyRouteRefParams = AnyRouteRefParams,\n TOptional extends boolean = boolean,\n> {\n readonly $$type: '@backstage/ExternalRouteRef';\n readonly T: TParams;\n readonly optional: TOptional;\n}\n\n/** @internal */\nexport interface InternalExternalRouteRef<\n TParams extends AnyRouteRefParams = AnyRouteRefParams,\n TOptional extends boolean = boolean,\n> extends ExternalRouteRef<TParams, TOptional> {\n readonly version: 'v1';\n getParams(): string[];\n getDescription(): string;\n getDefaultTarget(): string | undefined;\n\n setId(id: string): void;\n}\n\n/** @internal */\nexport function toInternalExternalRouteRef<\n TParams extends AnyRouteRefParams = AnyRouteRefParams,\n TOptional extends boolean = boolean,\n>(\n resource: ExternalRouteRef<TParams, TOptional>,\n): InternalExternalRouteRef<TParams, TOptional> {\n const r = resource as InternalExternalRouteRef<TParams, TOptional>;\n if (r.$$type !== '@backstage/ExternalRouteRef') {\n throw new Error(`Invalid ExternalRouteRef, bad type '${r.$$type}'`);\n }\n\n return r;\n}\n\n/** @internal */\nexport function isExternalRouteRef(opaque: {\n $$type: string;\n}): opaque is ExternalRouteRef {\n return opaque.$$type === '@backstage/ExternalRouteRef';\n}\n\n/** @internal */\nclass ExternalRouteRefImpl\n extends RouteRefImpl\n implements InternalExternalRouteRef\n{\n readonly $$type = '@backstage/ExternalRouteRef' as any;\n\n constructor(\n readonly optional: boolean,\n readonly params: string[] = [],\n readonly defaultTarget: string | undefined,\n creationSite: string,\n ) {\n super(params, creationSite);\n }\n\n getDefaultTarget() {\n return this.defaultTarget;\n }\n}\n\n/**\n * Creates a route descriptor, to be later bound to a concrete route by the app. Used to implement cross-plugin route references.\n *\n * @remarks\n *\n * See {@link https://backstage.io/docs/plugins/composability#routing-system}.\n *\n * @param options - Description of the route reference to be created.\n * @public\n */\nexport function createExternalRouteRef<\n TParams extends { [param in TParamKeys]: string } | undefined = undefined,\n TOptional extends boolean = false,\n TParamKeys extends string = string,\n>(options?: {\n /**\n * The parameters that will be provided to the external route reference.\n */\n readonly params?: string extends TParamKeys\n ? (keyof TParams)[]\n : TParamKeys[];\n\n /**\n * Whether or not this route is optional, defaults to false.\n *\n * Optional external routes are not required to be bound in the app, and\n * if they aren't, `useExternalRouteRef` will return `undefined`.\n */\n optional?: TOptional;\n\n /**\n * The route (typically in another plugin) that this should map to by default.\n *\n * The string is expected to be on the standard `<plugin id>.<route id>` form,\n * for example `techdocs.docRoot`.\n */\n defaultTarget?: string;\n}): ExternalRouteRef<\n keyof TParams extends never\n ? undefined\n : string extends TParamKeys\n ? TParams\n : { [param in TParamKeys]: string },\n TOptional\n> {\n return new ExternalRouteRefImpl(\n Boolean(options?.optional),\n options?.params as string[] | undefined,\n options?.defaultTarget,\n describeParentCallSite(),\n ) as ExternalRouteRef<any, any>;\n}\n"],"names":[],"mappings":"AAoDO,SAAS,2BAId,QAC8C,EAAA;AAC9C,EAAA,MAAM,CAAI,GAAA,QAAA,CAAA;AACV,EAAI,IAAA,CAAA,CAAE,WAAW,6BAA+B,EAAA;AAC9C,IAAA,MAAM,IAAI,KAAA,CAAM,CAAuC,oCAAA,EAAA,CAAA,CAAE,MAAM,CAAG,CAAA,CAAA,CAAA,CAAA;AAAA,GACpE;AAEA,EAAO,OAAA,CAAA,CAAA;AACT;;;;"}
1
+ {"version":3,"file":"ExternalRouteRef.esm.js","sources":["../../../../../frontend-plugin-api/src/routing/ExternalRouteRef.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { RouteRefImpl } from './RouteRef';\nimport { describeParentCallSite } from './describeParentCallSite';\nimport { AnyRouteRefParams } from './types';\n\n/**\n * Route descriptor, to be later bound to a concrete route by the app. Used to implement cross-plugin route references.\n *\n * @remarks\n *\n * See {@link https://backstage.io/docs/plugins/composability#routing-system}.\n *\n * @public\n */\nexport interface ExternalRouteRef<\n TParams extends AnyRouteRefParams = AnyRouteRefParams,\n> {\n readonly $$type: '@backstage/ExternalRouteRef';\n readonly T: TParams;\n}\n\n/** @internal */\nexport interface InternalExternalRouteRef<\n TParams extends AnyRouteRefParams = AnyRouteRefParams,\n> extends ExternalRouteRef<TParams> {\n readonly version: 'v1';\n getParams(): string[];\n getDescription(): string;\n getDefaultTarget(): string | undefined;\n\n setId(id: string): void;\n}\n\n/** @internal */\nexport function toInternalExternalRouteRef<\n TParams extends AnyRouteRefParams = AnyRouteRefParams,\n>(resource: ExternalRouteRef<TParams>): InternalExternalRouteRef<TParams> {\n const r = resource as InternalExternalRouteRef<TParams>;\n if (r.$$type !== '@backstage/ExternalRouteRef') {\n throw new Error(`Invalid ExternalRouteRef, bad type '${r.$$type}'`);\n }\n\n return r;\n}\n\n/** @internal */\nexport function isExternalRouteRef(opaque: {\n $$type: string;\n}): opaque is ExternalRouteRef {\n return opaque.$$type === '@backstage/ExternalRouteRef';\n}\n\n/** @internal */\nclass ExternalRouteRefImpl\n extends RouteRefImpl\n implements InternalExternalRouteRef\n{\n readonly $$type = '@backstage/ExternalRouteRef' as any;\n\n constructor(\n readonly params: string[] = [],\n readonly defaultTarget: string | undefined,\n creationSite: string,\n ) {\n super(params, creationSite);\n }\n\n getDefaultTarget() {\n return this.defaultTarget;\n }\n}\n\n/**\n * Creates a route descriptor, to be later bound to a concrete route by the app. Used to implement cross-plugin route references.\n *\n * @remarks\n *\n * See {@link https://backstage.io/docs/plugins/composability#routing-system}.\n *\n * @param options - Description of the route reference to be created.\n * @public\n */\nexport function createExternalRouteRef<\n TParams extends { [param in TParamKeys]: string } | undefined = undefined,\n TParamKeys extends string = string,\n>(options?: {\n /**\n * The parameters that will be provided to the external route reference.\n */\n readonly params?: string extends TParamKeys\n ? (keyof TParams)[]\n : TParamKeys[];\n\n /**\n * The route (typically in another plugin) that this should map to by default.\n *\n * The string is expected to be on the standard `<plugin id>.<route id>` form,\n * for example `techdocs.docRoot`.\n */\n defaultTarget?: string;\n}): ExternalRouteRef<\n keyof TParams extends never\n ? undefined\n : string extends TParamKeys\n ? TParams\n : { [param in TParamKeys]: string }\n> {\n return new ExternalRouteRefImpl(\n options?.params as string[] | undefined,\n options?.defaultTarget,\n describeParentCallSite(),\n );\n}\n"],"names":[],"mappings":"AAiDO,SAAS,2BAEd,QAAwE,EAAA;AACxE,EAAA,MAAM,CAAI,GAAA,QAAA,CAAA;AACV,EAAI,IAAA,CAAA,CAAE,WAAW,6BAA+B,EAAA;AAC9C,IAAA,MAAM,IAAI,KAAA,CAAM,CAAuC,oCAAA,EAAA,CAAA,CAAE,MAAM,CAAG,CAAA,CAAA,CAAA,CAAA;AAAA,GACpE;AAEA,EAAO,OAAA,CAAA,CAAA;AACT;;;;"}
package/dist/index.d.ts CHANGED
@@ -71,7 +71,7 @@ declare function convertLegacyApp(rootElement: React.JSX.Element): FrontendFeatu
71
71
  *
72
72
  * @public
73
73
  */
74
- type ToNewRouteRef<T extends RouteRef | SubRouteRef | ExternalRouteRef> = T extends RouteRef<infer IParams> ? RouteRef$1<IParams> : T extends SubRouteRef<infer IParams> ? SubRouteRef$1<IParams> : T extends ExternalRouteRef<infer IParams, infer IOptional> ? ExternalRouteRef$1<IParams, IOptional> : never;
74
+ type ToNewRouteRef<T extends RouteRef | SubRouteRef | ExternalRouteRef> = T extends RouteRef<infer IParams> ? RouteRef$1<IParams> : T extends SubRouteRef<infer IParams> ? SubRouteRef$1<IParams> : T extends ExternalRouteRef<infer IParams> ? ExternalRouteRef$1<IParams> : never;
75
75
  /**
76
76
  * Converts a collection of legacy route refs to the new system.
77
77
  * This is particularly useful when defining plugin `routes` and `externalRoutes`.
@@ -109,6 +109,33 @@ declare function convertLegacyRouteRef<TParams extends AnyRouteRefParams>(ref: S
109
109
  *
110
110
  * In the future the legacy createExternalRouteRef will instead create refs compatible with both systems.
111
111
  */
112
- declare function convertLegacyRouteRef<TParams extends AnyRouteRefParams, TOptional extends boolean>(ref: ExternalRouteRef<TParams, TOptional>): ExternalRouteRef$1<TParams, TOptional>;
112
+ declare function convertLegacyRouteRef<TParams extends AnyRouteRefParams>(ref: ExternalRouteRef<TParams>): ExternalRouteRef$1<TParams>;
113
+ /**
114
+ * A temporary helper to convert a new route ref to the legacy system.
115
+ *
116
+ * @public
117
+ * @remarks
118
+ *
119
+ * In the future the legacy createRouteRef will instead create refs compatible with both systems.
120
+ */
121
+ declare function convertLegacyRouteRef<TParams extends AnyRouteRefParams>(ref: RouteRef$1<TParams>): RouteRef<TParams>;
122
+ /**
123
+ * A temporary helper to convert a new sub route ref to the legacy system.
124
+ *
125
+ * @public
126
+ * @remarks
127
+ *
128
+ * In the future the legacy createSubRouteRef will instead create refs compatible with both systems.
129
+ */
130
+ declare function convertLegacyRouteRef<TParams extends AnyRouteRefParams>(ref: SubRouteRef$1<TParams>): SubRouteRef<TParams>;
131
+ /**
132
+ * A temporary helper to convert a new external route ref to the legacy system.
133
+ *
134
+ * @public
135
+ * @remarks
136
+ *
137
+ * In the future the legacy createExternalRouteRef will instead create refs compatible with both systems.
138
+ */
139
+ declare function convertLegacyRouteRef<TParams extends AnyRouteRefParams>(ref: ExternalRouteRef$1<TParams>): ExternalRouteRef<TParams, true>;
113
140
 
114
141
  export { MultipleAnalyticsApi, NoOpAnalyticsApi, type ToNewRouteRef, compatWrapper, convertLegacyApp, convertLegacyRouteRef, convertLegacyRouteRefs };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/core-compat-api",
3
- "version": "0.2.8-next.0",
3
+ "version": "0.2.8-next.2",
4
4
  "backstage": {
5
5
  "role": "web-library"
6
6
  },
@@ -32,18 +32,19 @@
32
32
  },
33
33
  "dependencies": {
34
34
  "@backstage/core-plugin-api": "^1.9.3",
35
- "@backstage/frontend-plugin-api": "^0.6.8-next.0",
35
+ "@backstage/frontend-plugin-api": "^0.7.0-next.2",
36
36
  "@backstage/version-bridge": "^1.0.8",
37
37
  "@types/react": "^16.13.1 || ^17.0.0"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@backstage-community/plugin-puppetdb": "^0.1.18",
41
41
  "@backstage-community/plugin-stackstorm": "^0.1.16",
42
- "@backstage/cli": "^0.27.0-next.0",
43
- "@backstage/core-app-api": "^1.14.1-next.0",
44
- "@backstage/frontend-app-api": "^0.7.4-next.0",
45
- "@backstage/frontend-test-utils": "^0.1.11-next.0",
46
- "@backstage/plugin-catalog": "^1.21.2-next.0",
42
+ "@backstage/cli": "^0.27.0-next.3",
43
+ "@backstage/core-app-api": "^1.14.2-next.0",
44
+ "@backstage/frontend-app-api": "^0.7.5-next.2",
45
+ "@backstage/frontend-test-utils": "^0.1.12-next.2",
46
+ "@backstage/plugin-catalog": "^1.22.0-next.2",
47
+ "@backstage/test-utils": "^1.5.10-next.2",
47
48
  "@oriflame/backstage-plugin-score-card": "^0.8.0",
48
49
  "@testing-library/jest-dom": "^6.0.0",
49
50
  "@testing-library/react": "^15.0.0"